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
HwcDebug(uint32_t dpy)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
dumpLayers(hwc_display_contents_1_t * list)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
needToDumpLayers()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
logHwcProps(uint32_t listFlags)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
logLayer(size_t layerIndex,hwc_layer_1_t hwLayers[])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
dumpLayer(size_t layerIndex,hwc_layer_1_t hwLayers[])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 *tempSkBmp = new SkBitmap();
318 SkBitmap::Config tempSkBmpConfig = SkBitmap::kNo_Config;
319 snprintf(dumpFilename, sizeof(dumpFilename),
320 "%s/sfdump%03d.layer%zu.%s.png", mDumpDirPng,
321 mDumpCntrPng, layerIndex, mDisplayName);
322
323 switch (hnd->format) {
324 case HAL_PIXEL_FORMAT_RGBA_8888:
325 case HAL_PIXEL_FORMAT_RGBX_8888:
326 case HAL_PIXEL_FORMAT_BGRA_8888:
327 tempSkBmpConfig = SkBitmap::kARGB_8888_Config;
328 break;
329 case HAL_PIXEL_FORMAT_RGB_565:
330 tempSkBmpConfig = SkBitmap::kRGB_565_Config;
331 break;
332 case HAL_PIXEL_FORMAT_RGB_888:
333 default:
334 tempSkBmpConfig = SkBitmap::kNo_Config;
335 break;
336 }
337 if (SkBitmap::kNo_Config != tempSkBmpConfig) {
338 tempSkBmp->setConfig(tempSkBmpConfig, getWidth(hnd), getHeight(hnd));
339 tempSkBmp->setPixels((void*)hnd->base);
340 SkFILEWStream file(dumpFilename);
341 bResult = SkEncodeImage(&file, *tempSkBmp, 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 delete tempSkBmp; // Calls SkBitmap::freePixels() internally.
351 }
352 #endif
353 if (needDumpRaw && hnd->base) {
354 char dumpFilename[PATH_MAX];
355 bool bResult = false;
356 snprintf(dumpFilename, sizeof(dumpFilename),
357 "%s/sfdump%03d.layer%zu.%dx%d.%s.%s.raw",
358 mDumpDirRaw, mDumpCntrRaw,
359 layerIndex, getWidth(hnd), getHeight(hnd),
360 pixFormatStr, mDisplayName);
361 FILE* fp = fopen(dumpFilename, "w+");
362 if (NULL != fp) {
363 bResult = (bool) fwrite((void*)hnd->base, hnd->size, 1, fp);
364 fclose(fp);
365 }
366 ALOGI("Display[%s] Layer[%zu] %s Dump to %s: %s",
367 mDisplayName, layerIndex, dumpLogStrRaw,
368 dumpFilename, bResult ? "Success" : "Fail");
369 }
370 }
371
getHalPixelFormatStr(int format,char pixFormatStr[])372 void HwcDebug::getHalPixelFormatStr(int format, char pixFormatStr[])
373 {
374 if (!pixFormatStr)
375 return;
376
377 switch(format) {
378 case HAL_PIXEL_FORMAT_RGBA_8888:
379 strlcpy(pixFormatStr, "RGBA_8888", sizeof(pixFormatStr));
380 break;
381 case HAL_PIXEL_FORMAT_RGBX_8888:
382 strlcpy(pixFormatStr, "RGBX_8888", sizeof(pixFormatStr));
383 break;
384 case HAL_PIXEL_FORMAT_RGB_888:
385 strlcpy(pixFormatStr, "RGB_888", sizeof(pixFormatStr));
386 break;
387 case HAL_PIXEL_FORMAT_RGB_565:
388 strlcpy(pixFormatStr, "RGB_565", sizeof(pixFormatStr));
389 break;
390 case HAL_PIXEL_FORMAT_BGRA_8888:
391 strlcpy(pixFormatStr, "BGRA_8888", sizeof(pixFormatStr));
392 break;
393 case HAL_PIXEL_FORMAT_YV12:
394 strlcpy(pixFormatStr, "YV12", sizeof(pixFormatStr));
395 break;
396 case HAL_PIXEL_FORMAT_YCbCr_422_SP:
397 strlcpy(pixFormatStr, "YCbCr_422_SP_NV16", sizeof(pixFormatStr));
398 break;
399 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
400 strlcpy(pixFormatStr, "YCrCb_420_SP_NV21", sizeof(pixFormatStr));
401 break;
402 case HAL_PIXEL_FORMAT_YCbCr_422_I:
403 strlcpy(pixFormatStr, "YCbCr_422_I_YUY2", sizeof(pixFormatStr));
404 break;
405 case HAL_PIXEL_FORMAT_YCrCb_422_I:
406 strlcpy(pixFormatStr, "YCrCb_422_I_YVYU", sizeof(pixFormatStr));
407 break;
408 case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
409 strlcpy(pixFormatStr, "NV12_ENCODEABLE", sizeof(pixFormatStr));
410 break;
411 case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
412 strlcpy(pixFormatStr, "YCbCr_420_SP_TILED_TILE_4x2",
413 sizeof(pixFormatStr));
414 break;
415 case HAL_PIXEL_FORMAT_YCbCr_420_SP:
416 strlcpy(pixFormatStr, "YCbCr_420_SP", sizeof(pixFormatStr));
417 break;
418 case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
419 strlcpy(pixFormatStr, "YCrCb_420_SP_ADRENO", sizeof(pixFormatStr));
420 break;
421 case HAL_PIXEL_FORMAT_YCrCb_422_SP:
422 strlcpy(pixFormatStr, "YCrCb_422_SP", sizeof(pixFormatStr));
423 break;
424 case HAL_PIXEL_FORMAT_R_8:
425 strlcpy(pixFormatStr, "R_8", sizeof(pixFormatStr));
426 break;
427 case HAL_PIXEL_FORMAT_RG_88:
428 strlcpy(pixFormatStr, "RG_88", sizeof(pixFormatStr));
429 break;
430 case HAL_PIXEL_FORMAT_INTERLACE:
431 strlcpy(pixFormatStr, "INTERLACE", sizeof(pixFormatStr));
432 break;
433 case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
434 strlcpy(pixFormatStr, "YCbCr_420_SP_VENUS", sizeof(pixFormatStr));
435 break;
436 default:
437 size_t len = sizeof(pixFormatStr);
438 snprintf(pixFormatStr, len, "Unknown0x%X", format);
439 break;
440 }
441 }
442
443 } // namespace qhwc
444
445