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