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             bResult = SkImageEncoder::EncodeFile(dumpFilename,
341                                     *tempSkBmp, SkImageEncoder::kPNG_Type, 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