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