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
51namespace 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
60bool HwcDebug::sDumpEnable = false;
61
62HwcDebug::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
84void 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
96bool 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
184void 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
217void 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
279void 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
381void 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