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 // Ignore Wconversion errors for external headers 41 #pragma GCC diagnostic push 42 #pragma GCC diagnostic ignored "-Wconversion" 43 #include <SkBitmap.h> 44 #include <SkImageEncoder.h> 45 #pragma GCC diagnostic pop 46 #endif 47 #ifdef STDC_FORMAT_MACROS 48 #include <inttypes.h> 49 #endif 50 51 namespace qhwc { 52 53 // MAX_ALLOWED_FRAMEDUMPS must be capped to (LONG_MAX - 1) 54 // 60fps => 216000 frames per hour 55 // Below setting of 216000 * 24 * 7 => 1 week or 168 hours of capture. 56 enum { 57 MAX_ALLOWED_FRAMEDUMPS = (216000 * 24 * 7) 58 }; 59 60 bool HwcDebug::sDumpEnable = false; 61 62 HwcDebug::HwcDebug(uint32_t dpy): 63 mDumpCntLimRaw(0), 64 mDumpCntrRaw(1), 65 mDumpCntLimPng(0), 66 mDumpCntrPng(1), 67 mDpy(dpy) { 68 char dumpPropStr[PROPERTY_VALUE_MAX]; 69 if(mDpy) { 70 strlcpy(mDisplayName, "external", sizeof(mDisplayName)); 71 } else { 72 strlcpy(mDisplayName, "primary", sizeof(mDisplayName)); 73 } 74 snprintf(mDumpPropKeyDisplayType, sizeof(mDumpPropKeyDisplayType), 75 "debug.sf.dump.%s", (char *)mDisplayName); 76 77 if ((property_get("debug.sf.dump.enable", dumpPropStr, NULL) > 0)) { 78 if(!strncmp(dumpPropStr, "true", strlen("true"))) { 79 sDumpEnable = true; 80 } 81 } 82 } 83 84 void HwcDebug::dumpLayers(hwc_display_contents_1_t* list) 85 { 86 // Check need for dumping layers for debugging. 87 if (UNLIKELY(sDumpEnable) && UNLIKELY(needToDumpLayers()) && LIKELY(list)) { 88 logHwcProps(list->flags); 89 for (size_t i = 0; i < list->numHwLayers; i++) { 90 logLayer(i, list->hwLayers); 91 dumpLayer(i, list->hwLayers); 92 } 93 } 94 } 95 96 bool HwcDebug::needToDumpLayers() 97 { 98 bool bDumpLayer = false; 99 char dumpPropStr[PROPERTY_VALUE_MAX]; 100 // Enable primary dump and disable external dump by default. 101 bool bDumpEnable = !mDpy; 102 time_t timeNow; 103 tm dumpTime; 104 105 // Override the bDumpEnable based on the property value, if the property 106 // is present in the build.prop file. 107 if ((property_get(mDumpPropKeyDisplayType, dumpPropStr, NULL) > 0)) { 108 if(!strncmp(dumpPropStr, "true", strlen("true"))) 109 bDumpEnable = true; 110 else 111 bDumpEnable = false; 112 } 113 114 if (false == bDumpEnable) 115 return false; 116 117 time(&timeNow); 118 localtime_r(&timeNow, &dumpTime); 119 120 if ((property_get("debug.sf.dump.png", dumpPropStr, NULL) > 0) && 121 (strncmp(dumpPropStr, mDumpPropStrPng, PROPERTY_VALUE_MAX - 1))) { 122 // Strings exist & not equal implies it has changed, so trigger a dump 123 strlcpy(mDumpPropStrPng, dumpPropStr, sizeof(mDumpPropStrPng)); 124 mDumpCntLimPng = atoi(dumpPropStr); 125 if (mDumpCntLimPng > MAX_ALLOWED_FRAMEDUMPS) { 126 ALOGW("Warning: Using debug.sf.dump.png %d (= max)", 127 MAX_ALLOWED_FRAMEDUMPS); 128 mDumpCntLimPng = MAX_ALLOWED_FRAMEDUMPS; 129 } 130 mDumpCntLimPng = (mDumpCntLimPng < 0) ? 0: mDumpCntLimPng; 131 if (mDumpCntLimPng) { 132 snprintf(mDumpDirPng, sizeof(mDumpDirPng), 133 "/data/sfdump.png.%04d.%02d.%02d.%02d.%02d.%02d", 134 dumpTime.tm_year + 1900, dumpTime.tm_mon + 1, 135 dumpTime.tm_mday, dumpTime.tm_hour, 136 dumpTime.tm_min, dumpTime.tm_sec); 137 if (0 == mkdir(mDumpDirPng, 0777)) 138 mDumpCntrPng = 0; 139 else { 140 ALOGE("Error: %s. Failed to create sfdump directory: %s", 141 strerror(errno), mDumpDirPng); 142 mDumpCntrPng = mDumpCntLimPng + 1; 143 } 144 } 145 } 146 147 if (mDumpCntrPng <= mDumpCntLimPng) 148 mDumpCntrPng++; 149 150 if ((property_get("debug.sf.dump", dumpPropStr, NULL) > 0) && 151 (strncmp(dumpPropStr, mDumpPropStrRaw, PROPERTY_VALUE_MAX - 1))) { 152 // Strings exist & not equal implies it has changed, so trigger a dump 153 strlcpy(mDumpPropStrRaw, dumpPropStr, sizeof(mDumpPropStrRaw)); 154 mDumpCntLimRaw = atoi(dumpPropStr); 155 if (mDumpCntLimRaw > MAX_ALLOWED_FRAMEDUMPS) { 156 ALOGW("Warning: Using debug.sf.dump %d (= max)", 157 MAX_ALLOWED_FRAMEDUMPS); 158 mDumpCntLimRaw = MAX_ALLOWED_FRAMEDUMPS; 159 } 160 mDumpCntLimRaw = (mDumpCntLimRaw < 0) ? 0: mDumpCntLimRaw; 161 if (mDumpCntLimRaw) { 162 snprintf(mDumpDirRaw, sizeof(mDumpDirRaw), 163 "/data/sfdump.raw.%04d.%02d.%02d.%02d.%02d.%02d", 164 dumpTime.tm_year + 1900, dumpTime.tm_mon + 1, 165 dumpTime.tm_mday, dumpTime.tm_hour, 166 dumpTime.tm_min, dumpTime.tm_sec); 167 if (0 == mkdir(mDumpDirRaw, 0777)) 168 mDumpCntrRaw = 0; 169 else { 170 ALOGE("Error: %s. Failed to create sfdump directory: %s", 171 strerror(errno), mDumpDirRaw); 172 mDumpCntrRaw = mDumpCntLimRaw + 1; 173 } 174 } 175 } 176 177 if (mDumpCntrRaw <= mDumpCntLimRaw) 178 mDumpCntrRaw++; 179 180 bDumpLayer = (mDumpCntLimPng || mDumpCntLimRaw)? true : false; 181 return bDumpLayer; 182 } 183 184 void HwcDebug::logHwcProps(uint32_t listFlags) 185 { 186 static int hwcModuleCompType = -1; 187 static int sMdpCompMaxLayers = 0; 188 static String8 hwcModuleCompTypeLog(""); 189 if (-1 == hwcModuleCompType) { 190 // One time stuff 191 char mdpCompPropStr[PROPERTY_VALUE_MAX]; 192 if (property_get("debug.mdpcomp.maxlayer", mdpCompPropStr, NULL) > 0) { 193 sMdpCompMaxLayers = atoi(mdpCompPropStr); 194 } 195 hwcModuleCompType = 196 qdutils::QCCompositionType::getInstance().getCompositionType(); 197 hwcModuleCompTypeLog.appendFormat("%s%s%s%s%s%s", 198 // Is hwc module composition type now a bit-field?! 199 (hwcModuleCompType == qdutils::COMPOSITION_TYPE_GPU)? 200 "[GPU]": "", 201 (hwcModuleCompType & qdutils::COMPOSITION_TYPE_MDP)? 202 "[MDP]": "", 203 (hwcModuleCompType & qdutils::COMPOSITION_TYPE_C2D)? 204 "[C2D]": "", 205 (hwcModuleCompType & qdutils::COMPOSITION_TYPE_CPU)? 206 "[CPU]": "", 207 (hwcModuleCompType & qdutils::COMPOSITION_TYPE_DYN)? 208 "[DYN]": "", 209 (hwcModuleCompType >= (qdutils::COMPOSITION_TYPE_DYN << 1))? 210 "[???]": ""); 211 } 212 ALOGI("Display[%s] Layer[*] %s-HwcModuleCompType, %d-layer MdpComp %s", 213 mDisplayName, hwcModuleCompTypeLog.string(), sMdpCompMaxLayers, 214 (listFlags & HWC_GEOMETRY_CHANGED)? "[HwcList Geometry Changed]": ""); 215 } 216 217 void HwcDebug::logLayer(size_t layerIndex, hwc_layer_1_t hwLayers[]) 218 { 219 if (NULL == hwLayers) { 220 ALOGE("Display[%s] Layer[%zu] Error. No hwc layers to log.", 221 mDisplayName, layerIndex); 222 return; 223 } 224 225 hwc_layer_1_t *layer = &hwLayers[layerIndex]; 226 hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf); 227 hwc_rect_t displayFrame = layer->displayFrame; 228 size_t numHwcRects = layer->visibleRegionScreen.numRects; 229 hwc_rect_t const *hwcRects = layer->visibleRegionScreen.rects; 230 private_handle_t *hnd = (private_handle_t *)layer->handle; 231 232 char pixFormatStr[32] = "None"; 233 String8 hwcVisRegsScrLog("[None]"); 234 235 for (size_t i = 0 ; (hwcRects && (i < numHwcRects)); i++) { 236 if (0 == i) 237 hwcVisRegsScrLog.clear(); 238 hwcVisRegsScrLog.appendFormat("[%dl, %dt, %dr, %db]", 239 hwcRects[i].left, hwcRects[i].top, 240 hwcRects[i].right, hwcRects[i].bottom); 241 } 242 243 if (hnd) 244 getHalPixelFormatStr(hnd->format, pixFormatStr); 245 246 // Log Line 1 247 ALOGI("Display[%s] Layer[%zu] SrcBuff[%dx%d] SrcCrop[%dl, %dt, %dr, %db] " 248 "DispFrame[%dl, %dt, %dr, %db] VisRegsScr%s", mDisplayName, layerIndex, 249 (hnd)? getWidth(hnd) : -1, (hnd)? getHeight(hnd) : -1, 250 sourceCrop.left, sourceCrop.top, 251 sourceCrop.right, sourceCrop.bottom, 252 displayFrame.left, displayFrame.top, 253 displayFrame.right, displayFrame.bottom, 254 hwcVisRegsScrLog.string()); 255 // Log Line 2 256 ALOGI("Display[%s] Layer[%zu] LayerCompType = %s, Format = %s, " 257 "Orientation = %s, Flags = %s%s%s, Hints = %s%s%s, " 258 "Blending = %s%s%s", mDisplayName, layerIndex, 259 (layer->compositionType == HWC_FRAMEBUFFER)? "Framebuffer(GPU)": 260 (layer->compositionType == HWC_OVERLAY)? "Overlay": 261 (layer->compositionType == HWC_BACKGROUND)? "Background":"???", 262 pixFormatStr, 263 (layer->transform == 0)? "ROT_0": 264 (layer->transform == HWC_TRANSFORM_FLIP_H)? "FLIP_H": 265 (layer->transform == HWC_TRANSFORM_FLIP_V)? "FLIP_V": 266 (layer->transform == HWC_TRANSFORM_ROT_90)? "ROT_90": 267 "ROT_INVALID", 268 (layer->flags)? "": "[None]", 269 (layer->flags & HWC_SKIP_LAYER)? "[Skip layer]":"", 270 (layer->flags & qhwc::HWC_MDPCOMP)? "[MDP Comp]":"", 271 (layer->hints)? "":"[None]", 272 (layer->hints & HWC_HINT_TRIPLE_BUFFER)? "[Triple Buffer]":"", 273 (layer->hints & HWC_HINT_CLEAR_FB)? "[Clear FB]":"", 274 (layer->blending == HWC_BLENDING_NONE)? "[None]":"", 275 (layer->blending == HWC_BLENDING_PREMULT)? "[PreMult]":"", 276 (layer->blending == HWC_BLENDING_COVERAGE)? "[Coverage]":""); 277 } 278 279 void HwcDebug::dumpLayer(size_t layerIndex, hwc_layer_1_t hwLayers[]) 280 { 281 char dumpLogStrPng[128] = ""; 282 char dumpLogStrRaw[128] = ""; 283 bool needDumpPng = (mDumpCntrPng <= mDumpCntLimPng)? true:false; 284 bool needDumpRaw = (mDumpCntrRaw <= mDumpCntLimRaw)? true:false; 285 286 if (needDumpPng) { 287 snprintf(dumpLogStrPng, sizeof(dumpLogStrPng), 288 "[png-dump-frame: %03d of %03d]", mDumpCntrPng, 289 mDumpCntLimPng); 290 } 291 if (needDumpRaw) { 292 snprintf(dumpLogStrRaw, sizeof(dumpLogStrRaw), 293 "[raw-dump-frame: %03d of %03d]", mDumpCntrRaw, 294 mDumpCntLimRaw); 295 } 296 297 if (!(needDumpPng || needDumpRaw)) 298 return; 299 300 if (NULL == hwLayers) { 301 ALOGE("Display[%s] Layer[%zu] %s%s Error: No hwc layers to dump.", 302 mDisplayName, layerIndex, dumpLogStrRaw, dumpLogStrPng); 303 return; 304 } 305 306 hwc_layer_1_t *layer = &hwLayers[layerIndex]; 307 private_handle_t *hnd = (private_handle_t *)layer->handle; 308 char pixFormatStr[32] = "None"; 309 310 if (NULL == hnd) { 311 ALOGI("Display[%s] Layer[%zu] %s%s Skipping dump: Bufferless layer.", 312 mDisplayName, layerIndex, dumpLogStrRaw, dumpLogStrPng); 313 return; 314 } 315 316 getHalPixelFormatStr(hnd->format, pixFormatStr); 317 #ifdef QCOM_BSP 318 if (needDumpPng && hnd->base) { 319 bool bResult = false; 320 char dumpFilename[PATH_MAX]; 321 SkColorType tempSkBmpColor = kUnknown_SkColorType; 322 snprintf(dumpFilename, sizeof(dumpFilename), 323 "%s/sfdump%03d.layer%zu.%s.png", mDumpDirPng, 324 mDumpCntrPng, layerIndex, mDisplayName); 325 326 switch (hnd->format) { 327 case HAL_PIXEL_FORMAT_RGBA_8888: 328 case HAL_PIXEL_FORMAT_RGBX_8888: 329 tempSkBmpColor = kRGBA_8888_SkColorType; 330 break; 331 case HAL_PIXEL_FORMAT_BGRA_8888: 332 tempSkBmpColor = kBGRA_8888_SkColorType; 333 break; 334 case HAL_PIXEL_FORMAT_RGB_565: 335 tempSkBmpColor = kRGB_565_SkColorType; 336 break; 337 case HAL_PIXEL_FORMAT_RGBA_5551: 338 case HAL_PIXEL_FORMAT_RGBA_4444: 339 case HAL_PIXEL_FORMAT_RGB_888: 340 default: 341 tempSkBmpColor = kUnknown_SkColorType; 342 break; 343 } 344 if (kUnknown_SkColorType != tempSkBmpColor) { 345 SkImageInfo info = SkImageInfo::Make(getWidth(hnd), getHeight(hnd), 346 tempSkBmpColor, kIgnore_SkAlphaType); 347 SkPixmap pixmap(info, (const void*)hnd->base, info.minRowBytes()); 348 SkFILEWStream file(dumpFilename); 349 bResult = SkEncodeImage(&file, pixmap, SkEncodedImageFormat::kPNG, 100); 350 ALOGI("Display[%s] Layer[%zu] %s Dump to %s: %s", 351 mDisplayName, layerIndex, dumpLogStrPng, 352 dumpFilename, bResult ? "Success" : "Fail"); 353 } else { 354 ALOGI("Display[%s] Layer[%zu] %s Skipping dump: Unsupported layer" 355 " format %s for png encoder", 356 mDisplayName, layerIndex, dumpLogStrPng, pixFormatStr); 357 } 358 } 359 #endif 360 if (needDumpRaw && hnd->base) { 361 char dumpFilename[PATH_MAX]; 362 bool bResult = false; 363 snprintf(dumpFilename, sizeof(dumpFilename), 364 "%s/sfdump%03d.layer%zu.%dx%d.%s.%s.raw", 365 mDumpDirRaw, mDumpCntrRaw, 366 layerIndex, getWidth(hnd), getHeight(hnd), 367 pixFormatStr, mDisplayName); 368 FILE* fp = fopen(dumpFilename, "w+"); 369 if (NULL != fp) { 370 bResult = (bool) fwrite((void*)hnd->base, hnd->size, 1, fp); 371 fclose(fp); 372 } 373 ALOGI("Display[%s] Layer[%zu] %s Dump to %s: %s", 374 mDisplayName, layerIndex, dumpLogStrRaw, 375 dumpFilename, bResult ? "Success" : "Fail"); 376 } 377 } 378 379 void HwcDebug::getHalPixelFormatStr(int format, char pixFormatStr[]) 380 { 381 if (!pixFormatStr) 382 return; 383 384 switch(format) { 385 case HAL_PIXEL_FORMAT_RGBA_8888: 386 strlcpy(pixFormatStr, "RGBA_8888", sizeof(pixFormatStr)); 387 break; 388 case HAL_PIXEL_FORMAT_RGBX_8888: 389 strlcpy(pixFormatStr, "RGBX_8888", sizeof(pixFormatStr)); 390 break; 391 case HAL_PIXEL_FORMAT_RGB_888: 392 strlcpy(pixFormatStr, "RGB_888", sizeof(pixFormatStr)); 393 break; 394 case HAL_PIXEL_FORMAT_RGB_565: 395 strlcpy(pixFormatStr, "RGB_565", sizeof(pixFormatStr)); 396 break; 397 case HAL_PIXEL_FORMAT_BGRA_8888: 398 strlcpy(pixFormatStr, "BGRA_8888", sizeof(pixFormatStr)); 399 break; 400 case HAL_PIXEL_FORMAT_RGBA_5551: 401 strlcpy(pixFormatStr, "RGBA_5551", sizeof(pixFormatStr)); 402 break; 403 case HAL_PIXEL_FORMAT_RGBA_4444: 404 strlcpy(pixFormatStr, "RGBA_4444", sizeof(pixFormatStr)); 405 break; 406 case HAL_PIXEL_FORMAT_YV12: 407 strlcpy(pixFormatStr, "YV12", sizeof(pixFormatStr)); 408 break; 409 case HAL_PIXEL_FORMAT_YCbCr_422_SP: 410 strlcpy(pixFormatStr, "YCbCr_422_SP_NV16", sizeof(pixFormatStr)); 411 break; 412 case HAL_PIXEL_FORMAT_YCrCb_420_SP: 413 strlcpy(pixFormatStr, "YCrCb_420_SP_NV21", sizeof(pixFormatStr)); 414 break; 415 case HAL_PIXEL_FORMAT_YCbCr_422_I: 416 strlcpy(pixFormatStr, "YCbCr_422_I_YUY2", sizeof(pixFormatStr)); 417 break; 418 case HAL_PIXEL_FORMAT_YCrCb_422_I: 419 strlcpy(pixFormatStr, "YCrCb_422_I_YVYU", sizeof(pixFormatStr)); 420 break; 421 case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: 422 strlcpy(pixFormatStr, "NV12_ENCODEABLE", sizeof(pixFormatStr)); 423 break; 424 case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: 425 strlcpy(pixFormatStr, "YCbCr_420_SP_TILED_TILE_4x2", 426 sizeof(pixFormatStr)); 427 break; 428 case HAL_PIXEL_FORMAT_YCbCr_420_SP: 429 strlcpy(pixFormatStr, "YCbCr_420_SP", sizeof(pixFormatStr)); 430 break; 431 case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: 432 strlcpy(pixFormatStr, "YCrCb_420_SP_ADRENO", sizeof(pixFormatStr)); 433 break; 434 case HAL_PIXEL_FORMAT_YCrCb_422_SP: 435 strlcpy(pixFormatStr, "YCrCb_422_SP", sizeof(pixFormatStr)); 436 break; 437 case HAL_PIXEL_FORMAT_R_8: 438 strlcpy(pixFormatStr, "R_8", sizeof(pixFormatStr)); 439 break; 440 case HAL_PIXEL_FORMAT_RG_88: 441 strlcpy(pixFormatStr, "RG_88", sizeof(pixFormatStr)); 442 break; 443 case HAL_PIXEL_FORMAT_INTERLACE: 444 strlcpy(pixFormatStr, "INTERLACE", sizeof(pixFormatStr)); 445 break; 446 case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: 447 strlcpy(pixFormatStr, "YCbCr_420_SP_VENUS", sizeof(pixFormatStr)); 448 break; 449 default: 450 size_t len = sizeof(pixFormatStr); 451 snprintf(pixFormatStr, len, "Unknown0x%X", format); 452 break; 453 } 454 } 455 456 } // namespace qhwc 457 458