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 SkBitmap *tempSkBmp = new SkBitmap(); 322 SkColorType tempSkBmpColor = kUnknown_SkColorType; 323 snprintf(dumpFilename, sizeof(dumpFilename), 324 "%s/sfdump%03d.layer%zu.%s.png", mDumpDirPng, 325 mDumpCntrPng, layerIndex, mDisplayName); 326 327 switch (hnd->format) { 328 case HAL_PIXEL_FORMAT_RGBA_8888: 329 case HAL_PIXEL_FORMAT_RGBX_8888: 330 tempSkBmpColor = kRGBA_8888_SkColorType; 331 break; 332 case HAL_PIXEL_FORMAT_BGRA_8888: 333 tempSkBmpColor = kBGRA_8888_SkColorType; 334 break; 335 case HAL_PIXEL_FORMAT_RGB_565: 336 tempSkBmpColor = kRGB_565_SkColorType; 337 break; 338 case HAL_PIXEL_FORMAT_RGBA_5551: 339 case HAL_PIXEL_FORMAT_RGBA_4444: 340 case HAL_PIXEL_FORMAT_RGB_888: 341 default: 342 tempSkBmpColor = kUnknown_SkColorType; 343 break; 344 } 345 if (kUnknown_SkColorType != tempSkBmpColor) { 346 tempSkBmp->setInfo(SkImageInfo::Make(getWidth(hnd), getHeight(hnd), 347 tempSkBmpColor, kIgnore_SkAlphaType), 0); 348 tempSkBmp->setPixels((void*)hnd->base); 349 bResult = SkImageEncoder::EncodeFile(dumpFilename, 350 *tempSkBmp, SkImageEncoder::kPNG_Type, 100); 351 ALOGI("Display[%s] Layer[%zu] %s Dump to %s: %s", 352 mDisplayName, layerIndex, dumpLogStrPng, 353 dumpFilename, bResult ? "Success" : "Fail"); 354 } else { 355 ALOGI("Display[%s] Layer[%zu] %s Skipping dump: Unsupported layer" 356 " format %s for png encoder", 357 mDisplayName, layerIndex, dumpLogStrPng, pixFormatStr); 358 } 359 delete tempSkBmp; // Calls SkBitmap::freePixels() internally. 360 } 361 #endif 362 if (needDumpRaw && hnd->base) { 363 char dumpFilename[PATH_MAX]; 364 bool bResult = false; 365 snprintf(dumpFilename, sizeof(dumpFilename), 366 "%s/sfdump%03d.layer%zu.%dx%d.%s.%s.raw", 367 mDumpDirRaw, mDumpCntrRaw, 368 layerIndex, getWidth(hnd), getHeight(hnd), 369 pixFormatStr, mDisplayName); 370 FILE* fp = fopen(dumpFilename, "w+"); 371 if (NULL != fp) { 372 bResult = (bool) fwrite((void*)hnd->base, hnd->size, 1, fp); 373 fclose(fp); 374 } 375 ALOGI("Display[%s] Layer[%zu] %s Dump to %s: %s", 376 mDisplayName, layerIndex, dumpLogStrRaw, 377 dumpFilename, bResult ? "Success" : "Fail"); 378 } 379 } 380 381 void HwcDebug::getHalPixelFormatStr(int format, char pixFormatStr[]) 382 { 383 if (!pixFormatStr) 384 return; 385 386 switch(format) { 387 case HAL_PIXEL_FORMAT_RGBA_8888: 388 strlcpy(pixFormatStr, "RGBA_8888", sizeof(pixFormatStr)); 389 break; 390 case HAL_PIXEL_FORMAT_RGBX_8888: 391 strlcpy(pixFormatStr, "RGBX_8888", sizeof(pixFormatStr)); 392 break; 393 case HAL_PIXEL_FORMAT_RGB_888: 394 strlcpy(pixFormatStr, "RGB_888", sizeof(pixFormatStr)); 395 break; 396 case HAL_PIXEL_FORMAT_RGB_565: 397 strlcpy(pixFormatStr, "RGB_565", sizeof(pixFormatStr)); 398 break; 399 case HAL_PIXEL_FORMAT_BGRA_8888: 400 strlcpy(pixFormatStr, "BGRA_8888", sizeof(pixFormatStr)); 401 break; 402 case HAL_PIXEL_FORMAT_RGBA_5551: 403 strlcpy(pixFormatStr, "RGBA_5551", sizeof(pixFormatStr)); 404 break; 405 case HAL_PIXEL_FORMAT_RGBA_4444: 406 strlcpy(pixFormatStr, "RGBA_4444", sizeof(pixFormatStr)); 407 break; 408 case HAL_PIXEL_FORMAT_YV12: 409 strlcpy(pixFormatStr, "YV12", sizeof(pixFormatStr)); 410 break; 411 case HAL_PIXEL_FORMAT_YCbCr_422_SP: 412 strlcpy(pixFormatStr, "YCbCr_422_SP_NV16", sizeof(pixFormatStr)); 413 break; 414 case HAL_PIXEL_FORMAT_YCrCb_420_SP: 415 strlcpy(pixFormatStr, "YCrCb_420_SP_NV21", sizeof(pixFormatStr)); 416 break; 417 case HAL_PIXEL_FORMAT_YCbCr_422_I: 418 strlcpy(pixFormatStr, "YCbCr_422_I_YUY2", sizeof(pixFormatStr)); 419 break; 420 case HAL_PIXEL_FORMAT_YCrCb_422_I: 421 strlcpy(pixFormatStr, "YCrCb_422_I_YVYU", sizeof(pixFormatStr)); 422 break; 423 case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: 424 strlcpy(pixFormatStr, "NV12_ENCODEABLE", sizeof(pixFormatStr)); 425 break; 426 case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: 427 strlcpy(pixFormatStr, "YCbCr_420_SP_TILED_TILE_4x2", 428 sizeof(pixFormatStr)); 429 break; 430 case HAL_PIXEL_FORMAT_YCbCr_420_SP: 431 strlcpy(pixFormatStr, "YCbCr_420_SP", sizeof(pixFormatStr)); 432 break; 433 case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: 434 strlcpy(pixFormatStr, "YCrCb_420_SP_ADRENO", sizeof(pixFormatStr)); 435 break; 436 case HAL_PIXEL_FORMAT_YCrCb_422_SP: 437 strlcpy(pixFormatStr, "YCrCb_422_SP", sizeof(pixFormatStr)); 438 break; 439 case HAL_PIXEL_FORMAT_R_8: 440 strlcpy(pixFormatStr, "R_8", sizeof(pixFormatStr)); 441 break; 442 case HAL_PIXEL_FORMAT_RG_88: 443 strlcpy(pixFormatStr, "RG_88", sizeof(pixFormatStr)); 444 break; 445 case HAL_PIXEL_FORMAT_INTERLACE: 446 strlcpy(pixFormatStr, "INTERLACE", sizeof(pixFormatStr)); 447 break; 448 case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: 449 strlcpy(pixFormatStr, "YCbCr_420_SP_VENUS", sizeof(pixFormatStr)); 450 break; 451 default: 452 size_t len = sizeof(pixFormatStr); 453 snprintf(pixFormatStr, len, "Unknown0x%X", format); 454 break; 455 } 456 } 457 458 } // namespace qhwc 459 460