• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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