Home | History | Annotate | Download | only in libhwcomposer
      1 /*
      2  * Copyright (c) 2012-2014, Linux Foundation. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *   * Redistributions of source code must retain the above copyright
      8  *     notice, this list of conditions and the following disclaimer.
      9  *   * Redistributions in binary form must reproduce the above
     10  *     copyright notice, this list of conditions and the following
     11  *     disclaimer in the documentation and/or other materials provided
     12  *     with the distribution.
     13  *   * Neither the name of Linux Foundation nor the names of its
     14  *     contributors may be used to endorse or promote products derived
     15  *     from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     24  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     26  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #ifndef LOG_TAG
     31 #define LOG_TAG "qsfdump"
     32 #endif
     33 #define LOG_NDEBUG 0
     34 #include <hwc_utils.h>
     35 #include <hwc_dump_layers.h>
     36 #include <cutils/log.h>
     37 #include <sys/stat.h>
     38 #include <comptype.h>
     39 #ifdef QCOM_BSP
     40 #include <SkBitmap.h>
     41 #include <SkImageEncoder.h>
     42 #endif
     43 #ifdef STDC_FORMAT_MACROS
     44 #include <inttypes.h>
     45 #endif
     46 
     47 namespace qhwc {
     48 
     49 // MAX_ALLOWED_FRAMEDUMPS must be capped to (LONG_MAX - 1)
     50 // 60fps => 216000 frames per hour
     51 // Below setting of 216000 * 24 * 7 => 1 week or 168 hours of capture.
     52   enum {
     53     MAX_ALLOWED_FRAMEDUMPS = (216000 * 24 * 7)
     54   };
     55 
     56 bool HwcDebug::sDumpEnable = false;
     57 
     58 HwcDebug::HwcDebug(uint32_t dpy):
     59   mDumpCntLimRaw(0),
     60   mDumpCntrRaw(1),
     61   mDumpCntLimPng(0),
     62   mDumpCntrPng(1),
     63   mDpy(dpy) {
     64     char dumpPropStr[PROPERTY_VALUE_MAX];
     65     if(mDpy) {
     66         strlcpy(mDisplayName, "external", sizeof(mDisplayName));
     67     } else {
     68         strlcpy(mDisplayName, "primary", sizeof(mDisplayName));
     69     }
     70     snprintf(mDumpPropKeyDisplayType, sizeof(mDumpPropKeyDisplayType),
     71              "debug.sf.dump.%s", (char *)mDisplayName);
     72 
     73     if ((property_get("debug.sf.dump.enable", dumpPropStr, NULL) > 0)) {
     74         if(!strncmp(dumpPropStr, "true", strlen("true"))) {
     75             sDumpEnable = true;
     76         }
     77     }
     78 }
     79 
     80 void HwcDebug::dumpLayers(hwc_display_contents_1_t* list)
     81 {
     82     // Check need for dumping layers for debugging.
     83     if (UNLIKELY(sDumpEnable) && UNLIKELY(needToDumpLayers()) && LIKELY(list)) {
     84         logHwcProps(list->flags);
     85         for (size_t i = 0; i < list->numHwLayers; i++) {
     86             logLayer(i, list->hwLayers);
     87             dumpLayer(i, list->hwLayers);
     88         }
     89     }
     90 }
     91 
     92 bool HwcDebug::needToDumpLayers()
     93 {
     94     bool bDumpLayer = false;
     95     char dumpPropStr[PROPERTY_VALUE_MAX];
     96     // Enable primary dump and disable external dump by default.
     97     bool bDumpEnable = !mDpy;
     98     time_t timeNow;
     99     tm dumpTime;
    100 
    101     // Override the bDumpEnable based on the property value, if the property
    102     // is present in the build.prop file.
    103     if ((property_get(mDumpPropKeyDisplayType, dumpPropStr, NULL) > 0)) {
    104         if(!strncmp(dumpPropStr, "true", strlen("true")))
    105             bDumpEnable = true;
    106         else
    107             bDumpEnable = false;
    108     }
    109 
    110     if (false == bDumpEnable)
    111         return false;
    112 
    113     time(&timeNow);
    114     localtime_r(&timeNow, &dumpTime);
    115 
    116     if ((property_get("debug.sf.dump.png", dumpPropStr, NULL) > 0) &&
    117             (strncmp(dumpPropStr, mDumpPropStrPng, PROPERTY_VALUE_MAX - 1))) {
    118         // Strings exist & not equal implies it has changed, so trigger a dump
    119         strlcpy(mDumpPropStrPng, dumpPropStr, sizeof(mDumpPropStrPng));
    120         mDumpCntLimPng = atoi(dumpPropStr);
    121         if (mDumpCntLimPng > MAX_ALLOWED_FRAMEDUMPS) {
    122             ALOGW("Warning: Using debug.sf.dump.png %d (= max)",
    123                 MAX_ALLOWED_FRAMEDUMPS);
    124             mDumpCntLimPng = MAX_ALLOWED_FRAMEDUMPS;
    125         }
    126         mDumpCntLimPng = (mDumpCntLimPng < 0) ? 0: mDumpCntLimPng;
    127         if (mDumpCntLimPng) {
    128             snprintf(mDumpDirPng, sizeof(mDumpDirPng),
    129                     "/data/sfdump.png.%04d.%02d.%02d.%02d.%02d.%02d",
    130                     dumpTime.tm_year + 1900, dumpTime.tm_mon + 1,
    131                     dumpTime.tm_mday, dumpTime.tm_hour,
    132                     dumpTime.tm_min, dumpTime.tm_sec);
    133             if (0 == mkdir(mDumpDirPng, 0777))
    134                 mDumpCntrPng = 0;
    135             else {
    136                 ALOGE("Error: %s. Failed to create sfdump directory: %s",
    137                     strerror(errno), mDumpDirPng);
    138                 mDumpCntrPng = mDumpCntLimPng + 1;
    139             }
    140         }
    141     }
    142 
    143     if (mDumpCntrPng <= mDumpCntLimPng)
    144         mDumpCntrPng++;
    145 
    146     if ((property_get("debug.sf.dump", dumpPropStr, NULL) > 0) &&
    147             (strncmp(dumpPropStr, mDumpPropStrRaw, PROPERTY_VALUE_MAX - 1))) {
    148         // Strings exist & not equal implies it has changed, so trigger a dump
    149         strlcpy(mDumpPropStrRaw, dumpPropStr, sizeof(mDumpPropStrRaw));
    150         mDumpCntLimRaw = atoi(dumpPropStr);
    151         if (mDumpCntLimRaw > MAX_ALLOWED_FRAMEDUMPS) {
    152             ALOGW("Warning: Using debug.sf.dump %d (= max)",
    153                 MAX_ALLOWED_FRAMEDUMPS);
    154             mDumpCntLimRaw = MAX_ALLOWED_FRAMEDUMPS;
    155         }
    156         mDumpCntLimRaw = (mDumpCntLimRaw < 0) ? 0: mDumpCntLimRaw;
    157         if (mDumpCntLimRaw) {
    158             snprintf(mDumpDirRaw, sizeof(mDumpDirRaw),
    159                     "/data/sfdump.raw.%04d.%02d.%02d.%02d.%02d.%02d",
    160                     dumpTime.tm_year + 1900, dumpTime.tm_mon + 1,
    161                     dumpTime.tm_mday, dumpTime.tm_hour,
    162                     dumpTime.tm_min, dumpTime.tm_sec);
    163             if (0 == mkdir(mDumpDirRaw, 0777))
    164                 mDumpCntrRaw = 0;
    165             else {
    166                 ALOGE("Error: %s. Failed to create sfdump directory: %s",
    167                     strerror(errno), mDumpDirRaw);
    168                 mDumpCntrRaw = mDumpCntLimRaw + 1;
    169             }
    170         }
    171     }
    172 
    173     if (mDumpCntrRaw <= mDumpCntLimRaw)
    174         mDumpCntrRaw++;
    175 
    176     bDumpLayer = (mDumpCntLimPng || mDumpCntLimRaw)? true : false;
    177     return bDumpLayer;
    178 }
    179 
    180 void HwcDebug::logHwcProps(uint32_t listFlags)
    181 {
    182     static int hwcModuleCompType = -1;
    183     static int sMdpCompMaxLayers = 0;
    184     static String8 hwcModuleCompTypeLog("");
    185     if (-1 == hwcModuleCompType) {
    186         // One time stuff
    187         char mdpCompPropStr[PROPERTY_VALUE_MAX];
    188         if (property_get("debug.mdpcomp.maxlayer", mdpCompPropStr, NULL) > 0) {
    189             sMdpCompMaxLayers = atoi(mdpCompPropStr);
    190         }
    191         hwcModuleCompType =
    192             qdutils::QCCompositionType::getInstance().getCompositionType();
    193         hwcModuleCompTypeLog.appendFormat("%s%s%s%s%s%s",
    194             // Is hwc module composition type now a bit-field?!
    195             (hwcModuleCompType == qdutils::COMPOSITION_TYPE_GPU)?
    196                 "[GPU]": "",
    197             (hwcModuleCompType & qdutils::COMPOSITION_TYPE_MDP)?
    198                 "[MDP]": "",
    199             (hwcModuleCompType & qdutils::COMPOSITION_TYPE_C2D)?
    200                 "[C2D]": "",
    201             (hwcModuleCompType & qdutils::COMPOSITION_TYPE_CPU)?
    202                 "[CPU]": "",
    203             (hwcModuleCompType & qdutils::COMPOSITION_TYPE_DYN)?
    204                 "[DYN]": "",
    205             (hwcModuleCompType >= (qdutils::COMPOSITION_TYPE_DYN << 1))?
    206                 "[???]": "");
    207     }
    208     ALOGI("Display[%s] Layer[*] %s-HwcModuleCompType, %d-layer MdpComp %s",
    209          mDisplayName, hwcModuleCompTypeLog.string(), sMdpCompMaxLayers,
    210         (listFlags & HWC_GEOMETRY_CHANGED)? "[HwcList Geometry Changed]": "");
    211 }
    212 
    213 void HwcDebug::logLayer(size_t layerIndex, hwc_layer_1_t hwLayers[])
    214 {
    215     if (NULL == hwLayers) {
    216         ALOGE("Display[%s] Layer[%zu] Error. No hwc layers to log.",
    217             mDisplayName, layerIndex);
    218         return;
    219     }
    220 
    221     hwc_layer_1_t *layer = &hwLayers[layerIndex];
    222     hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
    223     hwc_rect_t displayFrame = layer->displayFrame;
    224     size_t numHwcRects = layer->visibleRegionScreen.numRects;
    225     hwc_rect_t const *hwcRects = layer->visibleRegionScreen.rects;
    226     private_handle_t *hnd = (private_handle_t *)layer->handle;
    227 
    228     char pixFormatStr[32] = "None";
    229     String8 hwcVisRegsScrLog("[None]");
    230 
    231     for (size_t i = 0 ; (hwcRects && (i < numHwcRects)); i++) {
    232         if (0 == i)
    233             hwcVisRegsScrLog.clear();
    234         hwcVisRegsScrLog.appendFormat("[%dl, %dt, %dr, %db]",
    235                                         hwcRects[i].left, hwcRects[i].top,
    236                                         hwcRects[i].right, hwcRects[i].bottom);
    237     }
    238 
    239     if (hnd)
    240         getHalPixelFormatStr(hnd->format, pixFormatStr);
    241 
    242     // Log Line 1
    243     ALOGI("Display[%s] Layer[%zu] SrcBuff[%dx%d] SrcCrop[%dl, %dt, %dr, %db] "
    244         "DispFrame[%dl, %dt, %dr, %db] VisRegsScr%s", mDisplayName, layerIndex,
    245         (hnd)? getWidth(hnd) : -1, (hnd)? getHeight(hnd) : -1,
    246         sourceCrop.left, sourceCrop.top,
    247         sourceCrop.right, sourceCrop.bottom,
    248         displayFrame.left, displayFrame.top,
    249         displayFrame.right, displayFrame.bottom,
    250         hwcVisRegsScrLog.string());
    251     // Log Line 2
    252     ALOGI("Display[%s] Layer[%zu] LayerCompType = %s, Format = %s, "
    253         "Orientation = %s, Flags = %s%s%s, Hints = %s%s%s, "
    254         "Blending = %s%s%s", mDisplayName, layerIndex,
    255         (layer->compositionType == HWC_FRAMEBUFFER)? "Framebuffer(GPU)":
    256             (layer->compositionType == HWC_OVERLAY)? "Overlay":
    257             (layer->compositionType == HWC_BACKGROUND)? "Background":"???",
    258          pixFormatStr,
    259          (layer->transform == 0)? "ROT_0":
    260              (layer->transform == HWC_TRANSFORM_FLIP_H)? "FLIP_H":
    261              (layer->transform == HWC_TRANSFORM_FLIP_V)? "FLIP_V":
    262              (layer->transform == HWC_TRANSFORM_ROT_90)? "ROT_90":
    263                                                         "ROT_INVALID",
    264          (layer->flags)? "": "[None]",
    265          (layer->flags & HWC_SKIP_LAYER)? "[Skip layer]":"",
    266          (layer->flags & qhwc::HWC_MDPCOMP)? "[MDP Comp]":"",
    267          (layer->hints)? "":"[None]",
    268          (layer->hints & HWC_HINT_TRIPLE_BUFFER)? "[Triple Buffer]":"",
    269          (layer->hints & HWC_HINT_CLEAR_FB)? "[Clear FB]":"",
    270          (layer->blending == HWC_BLENDING_NONE)? "[None]":"",
    271          (layer->blending == HWC_BLENDING_PREMULT)? "[PreMult]":"",
    272          (layer->blending == HWC_BLENDING_COVERAGE)? "[Coverage]":"");
    273 }
    274 
    275 void HwcDebug::dumpLayer(size_t layerIndex, hwc_layer_1_t hwLayers[])
    276 {
    277     char dumpLogStrPng[128] = "";
    278     char dumpLogStrRaw[128] = "";
    279     bool needDumpPng = (mDumpCntrPng <= mDumpCntLimPng)? true:false;
    280     bool needDumpRaw = (mDumpCntrRaw <= mDumpCntLimRaw)? true:false;
    281 
    282     if (needDumpPng) {
    283         snprintf(dumpLogStrPng, sizeof(dumpLogStrPng),
    284             "[png-dump-frame: %03d of %03d]", mDumpCntrPng,
    285             mDumpCntLimPng);
    286     }
    287     if (needDumpRaw) {
    288         snprintf(dumpLogStrRaw, sizeof(dumpLogStrRaw),
    289             "[raw-dump-frame: %03d of %03d]", mDumpCntrRaw,
    290             mDumpCntLimRaw);
    291     }
    292 
    293     if (!(needDumpPng || needDumpRaw))
    294         return;
    295 
    296     if (NULL == hwLayers) {
    297         ALOGE("Display[%s] Layer[%zu] %s%s Error: No hwc layers to dump.",
    298             mDisplayName, layerIndex, dumpLogStrRaw, dumpLogStrPng);
    299         return;
    300     }
    301 
    302     hwc_layer_1_t *layer = &hwLayers[layerIndex];
    303     private_handle_t *hnd = (private_handle_t *)layer->handle;
    304     char pixFormatStr[32] = "None";
    305 
    306     if (NULL == hnd) {
    307         ALOGI("Display[%s] Layer[%zu] %s%s Skipping dump: Bufferless layer.",
    308             mDisplayName, layerIndex, dumpLogStrRaw, dumpLogStrPng);
    309         return;
    310     }
    311 
    312     getHalPixelFormatStr(hnd->format, pixFormatStr);
    313 #ifdef QCOM_BSP
    314     if (needDumpPng && hnd->base) {
    315         bool bResult = false;
    316         char dumpFilename[PATH_MAX];
    317         SkBitmap::Config tempSkBmpConfig = SkBitmap::kNo_Config;
    318         snprintf(dumpFilename, sizeof(dumpFilename),
    319             "%s/sfdump%03d.layer%zu.%s.png", mDumpDirPng,
    320             mDumpCntrPng, layerIndex, mDisplayName);
    321 
    322         switch (hnd->format) {
    323             case HAL_PIXEL_FORMAT_RGBA_8888:
    324             case HAL_PIXEL_FORMAT_RGBX_8888:
    325             case HAL_PIXEL_FORMAT_BGRA_8888:
    326                 tempSkBmpConfig = SkBitmap::kARGB_8888_Config;
    327                 break;
    328             case HAL_PIXEL_FORMAT_RGB_565:
    329                 tempSkBmpConfig = SkBitmap::kRGB_565_Config;
    330                 break;
    331             case HAL_PIXEL_FORMAT_RGB_888:
    332             default:
    333                 tempSkBmpConfig = SkBitmap::kNo_Config;
    334                 break;
    335         }
    336         if (SkBitmap::kNo_Config != tempSkBmpConfig) {
    337             SkImageInfo info = SkImageInfo::Make(getWidth(hnd), getHeight(hnd),
    338                                                  tempSkBmpColor, kIgnore_SkAlphaType);
    339             SkPixmap pixmap(info, (const void*)hnd->base, info.minRowBytes());
    340             SkFILEWStream file(dumpFilename);
    341             bResult = SkEncodeImage(&file, pixmap, SkEncodedImageFormat::kPNG, 100);
    342             ALOGI("Display[%s] Layer[%zu] %s Dump to %s: %s",
    343                 mDisplayName, layerIndex, dumpLogStrPng,
    344                 dumpFilename, bResult ? "Success" : "Fail");
    345         } else {
    346             ALOGI("Display[%s] Layer[%zu] %s Skipping dump: Unsupported layer"
    347                 " format %s for png encoder",
    348                 mDisplayName, layerIndex, dumpLogStrPng, pixFormatStr);
    349         }
    350     }
    351 #endif
    352     if (needDumpRaw && hnd->base) {
    353         char dumpFilename[PATH_MAX];
    354         bool bResult = false;
    355         snprintf(dumpFilename, sizeof(dumpFilename),
    356             "%s/sfdump%03d.layer%zu.%dx%d.%s.%s.raw",
    357             mDumpDirRaw, mDumpCntrRaw,
    358             layerIndex, getWidth(hnd), getHeight(hnd),
    359             pixFormatStr, mDisplayName);
    360         FILE* fp = fopen(dumpFilename, "w+");
    361         if (NULL != fp) {
    362             bResult = (bool) fwrite((void*)hnd->base, hnd->size, 1, fp);
    363             fclose(fp);
    364         }
    365         ALOGI("Display[%s] Layer[%zu] %s Dump to %s: %s",
    366             mDisplayName, layerIndex, dumpLogStrRaw,
    367             dumpFilename, bResult ? "Success" : "Fail");
    368     }
    369 }
    370 
    371 void HwcDebug::getHalPixelFormatStr(int format, char pixFormatStr[])
    372 {
    373     if (!pixFormatStr)
    374         return;
    375 
    376     switch(format) {
    377         case HAL_PIXEL_FORMAT_RGBA_8888:
    378             strlcpy(pixFormatStr, "RGBA_8888", sizeof(pixFormatStr));
    379             break;
    380         case HAL_PIXEL_FORMAT_RGBX_8888:
    381             strlcpy(pixFormatStr, "RGBX_8888", sizeof(pixFormatStr));
    382             break;
    383         case HAL_PIXEL_FORMAT_RGB_888:
    384             strlcpy(pixFormatStr, "RGB_888", sizeof(pixFormatStr));
    385             break;
    386         case HAL_PIXEL_FORMAT_RGB_565:
    387             strlcpy(pixFormatStr, "RGB_565", sizeof(pixFormatStr));
    388             break;
    389         case HAL_PIXEL_FORMAT_BGRA_8888:
    390             strlcpy(pixFormatStr, "BGRA_8888", sizeof(pixFormatStr));
    391             break;
    392         case HAL_PIXEL_FORMAT_YV12:
    393             strlcpy(pixFormatStr, "YV12", sizeof(pixFormatStr));
    394             break;
    395         case HAL_PIXEL_FORMAT_YCbCr_422_SP:
    396             strlcpy(pixFormatStr, "YCbCr_422_SP_NV16", sizeof(pixFormatStr));
    397             break;
    398         case HAL_PIXEL_FORMAT_YCrCb_420_SP:
    399             strlcpy(pixFormatStr, "YCrCb_420_SP_NV21", sizeof(pixFormatStr));
    400             break;
    401         case HAL_PIXEL_FORMAT_YCbCr_422_I:
    402             strlcpy(pixFormatStr, "YCbCr_422_I_YUY2", sizeof(pixFormatStr));
    403             break;
    404         case HAL_PIXEL_FORMAT_YCrCb_422_I:
    405             strlcpy(pixFormatStr, "YCrCb_422_I_YVYU", sizeof(pixFormatStr));
    406             break;
    407         case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
    408             strlcpy(pixFormatStr, "NV12_ENCODEABLE", sizeof(pixFormatStr));
    409             break;
    410         case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
    411             strlcpy(pixFormatStr, "YCbCr_420_SP_TILED_TILE_4x2",
    412                    sizeof(pixFormatStr));
    413             break;
    414         case HAL_PIXEL_FORMAT_YCbCr_420_SP:
    415             strlcpy(pixFormatStr, "YCbCr_420_SP", sizeof(pixFormatStr));
    416             break;
    417         case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
    418             strlcpy(pixFormatStr, "YCrCb_420_SP_ADRENO", sizeof(pixFormatStr));
    419             break;
    420         case HAL_PIXEL_FORMAT_YCrCb_422_SP:
    421             strlcpy(pixFormatStr, "YCrCb_422_SP", sizeof(pixFormatStr));
    422             break;
    423         case HAL_PIXEL_FORMAT_R_8:
    424             strlcpy(pixFormatStr, "R_8", sizeof(pixFormatStr));
    425             break;
    426         case HAL_PIXEL_FORMAT_RG_88:
    427             strlcpy(pixFormatStr, "RG_88", sizeof(pixFormatStr));
    428             break;
    429         case HAL_PIXEL_FORMAT_INTERLACE:
    430             strlcpy(pixFormatStr, "INTERLACE", sizeof(pixFormatStr));
    431             break;
    432         case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
    433             strlcpy(pixFormatStr, "YCbCr_420_SP_VENUS", sizeof(pixFormatStr));
    434             break;
    435         default:
    436             size_t len = sizeof(pixFormatStr);
    437             snprintf(pixFormatStr, len, "Unknown0x%X", format);
    438             break;
    439     }
    440 }
    441 
    442 } // namespace qhwc
    443 
    444