• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
HwcDebug(uint32_t dpy)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 
dumpLayers(hwc_display_contents_1_t * list)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 
needToDumpLayers()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 
logHwcProps(uint32_t listFlags)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 
logLayer(size_t layerIndex,hwc_layer_1_t hwLayers[])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 
dumpLayer(size_t layerIndex,hwc_layer_1_t hwLayers[])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 
getHalPixelFormatStr(int format,char pixFormatStr[])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