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