libQcomUI/libhwcomposer: Log and dump layers of screen frames.

Log a frame-by-frame succession of HWComposer layers' data and write
their buffers, if any, into raw or png files based on system property
values.

CRs-fixed: 339748

Change-Id: I171a9891a0867548b34d45c0561f25f66cf0580c
(cherry picked from commit 8166b062df4765af0b0d9f95d55fa14dd4b75b8d)
This commit is contained in:
Mathew Karimpanal 2012-02-29 12:57:31 -08:00 committed by Andrew Sutherland
parent 43afc2743e
commit 0f6ca9f6c9
4 changed files with 323 additions and 2 deletions

View File

@ -1495,7 +1495,10 @@ static int hwc_set(hwc_composer_device_t *dev,
int ret = 0;
if (list) {
bool bDumpLayers = needToDumpLayers(); // Check need for debugging dumps
for (size_t i=0; i<list->numHwLayers; i++) {
if (bDumpLayers)
dumpLayer(hwcModule->compositionType, list->flags, i, list->hwLayers);
if (list->hwLayers[i].flags & HWC_SKIP_LAYER) {
continue;
#ifdef COMPOSITION_BYPASS

View File

@ -14,9 +14,14 @@ LOCAL_SHARED_LIBRARIES := \
libcutils \
libmemalloc \
libui \
libEGL
libEGL \
libskia
LOCAL_C_INCLUDES := $(TOP)/hardware/qcom/display/libgralloc \
$(TOP)/frameworks/base/services/surfaceflinger \
$(TOP)/external/skia/include/core \
$(TOP)/external/skia/include/images
LOCAL_CFLAGS := -DLOG_TAG=\"libQcomUI\"
LOCAL_CFLAGS += -DQCOM_HARDWARE
LOCAL_CFLAGS += -DDEBUG_CALC_FPS

View File

@ -34,8 +34,11 @@
#include <alloc_controller.h>
#include <memalloc.h>
#include <errno.h>
#include <cutils/properties.h>
#include <EGL/eglext.h>
#include <sys/stat.h>
#include <SkBitmap.h>
#include <SkImageEncoder.h>
#include <Transform.h>
#include <EGL/egl.h>
#include <GLES2/gl2.h>
@ -536,6 +539,281 @@ external_display handleEventHDMI(external_display newState, external_display
}
return retState;
}
// Using global variables for layer dumping since "property_set("debug.sf.dump",
// property)" does not work.
int sfdump_countlimit_raw = 0;
int sfdump_counter_raw = 1;
char sfdump_propstr_persist_raw[PROPERTY_VALUE_MAX] = "";
char sfdumpdir_raw[256] = "";
int sfdump_countlimit_png = 0;
int sfdump_counter_png = 1;
char sfdump_propstr_persist_png[PROPERTY_VALUE_MAX] = "";
char sfdumpdir_png[256] = "";
bool needToDumpLayers()
{
bool bDumpLayer = false;
char sfdump_propstr[PROPERTY_VALUE_MAX];
time_t timenow;
tm sfdump_time;
time(&timenow);
localtime_r(&timenow, &sfdump_time);
if ((property_get("debug.sf.dump.png", sfdump_propstr, NULL) > 0) &&
(strncmp(sfdump_propstr, sfdump_propstr_persist_png,
PROPERTY_VALUE_MAX - 1))) {
// Strings exist & not equal implies it has changed, so trigger a dump
strncpy(sfdump_propstr_persist_png, sfdump_propstr,
PROPERTY_VALUE_MAX - 1);
sfdump_countlimit_png = atoi(sfdump_propstr);
sfdump_countlimit_png = (sfdump_countlimit_png < 0) ? 0:
(sfdump_countlimit_png >= LONG_MAX) ? (LONG_MAX - 1):
sfdump_countlimit_png;
if (sfdump_countlimit_png) {
sprintf(sfdumpdir_png,"/data/sfdump.png%04d%02d%02d.%02d%02d%02d",
sfdump_time.tm_year + 1900, sfdump_time.tm_mon + 1,
sfdump_time.tm_mday, sfdump_time.tm_hour,
sfdump_time.tm_min, sfdump_time.tm_sec);
if (0 == mkdir(sfdumpdir_png, 0777))
sfdump_counter_png = 0;
else
LOGE("sfdump: Error: %s. Failed to create sfdump directory"
": %s", strerror(errno), sfdumpdir_png);
}
}
if (sfdump_counter_png <= sfdump_countlimit_png)
sfdump_counter_png++;
if ((property_get("debug.sf.dump", sfdump_propstr, NULL) > 0) &&
(strncmp(sfdump_propstr, sfdump_propstr_persist_raw,
PROPERTY_VALUE_MAX - 1))) {
// Strings exist & not equal implies it has changed, so trigger a dump
strncpy(sfdump_propstr_persist_raw, sfdump_propstr,
PROPERTY_VALUE_MAX - 1);
sfdump_countlimit_raw = atoi(sfdump_propstr);
sfdump_countlimit_raw = (sfdump_countlimit_raw < 0) ? 0:
(sfdump_countlimit_raw >= LONG_MAX) ? (LONG_MAX - 1):
sfdump_countlimit_raw;
if (sfdump_countlimit_raw) {
sprintf(sfdumpdir_raw,"/data/sfdump.raw%04d%02d%02d.%02d%02d%02d",
sfdump_time.tm_year + 1900, sfdump_time.tm_mon + 1,
sfdump_time.tm_mday, sfdump_time.tm_hour,
sfdump_time.tm_min, sfdump_time.tm_sec);
if (0 == mkdir(sfdumpdir_raw, 0777))
sfdump_counter_raw = 0;
else
LOGE("sfdump: Error: %s. Failed to create sfdump directory"
": %s", strerror(errno), sfdumpdir_raw);
}
}
if (sfdump_counter_raw <= sfdump_countlimit_raw)
sfdump_counter_raw++;
bDumpLayer = (sfdump_countlimit_png || sfdump_countlimit_raw)? true : false;
return bDumpLayer;
}
inline void getHalPixelFormatStr(int format, char pixelformatstr[])
{
if (!pixelformatstr)
return;
switch(format) {
case HAL_PIXEL_FORMAT_RGBA_8888:
strcpy(pixelformatstr, "RGBA_8888");
break;
case HAL_PIXEL_FORMAT_RGBX_8888:
strcpy(pixelformatstr, "RGBX_8888");
break;
case HAL_PIXEL_FORMAT_RGB_888:
strcpy(pixelformatstr, "RGB_888");
break;
case HAL_PIXEL_FORMAT_RGB_565:
strcpy(pixelformatstr, "RGB_565");
break;
case HAL_PIXEL_FORMAT_BGRA_8888:
strcpy(pixelformatstr, "BGRA_8888");
break;
case HAL_PIXEL_FORMAT_RGBA_5551:
strcpy(pixelformatstr, "RGBA_5551");
break;
case HAL_PIXEL_FORMAT_RGBA_4444:
strcpy(pixelformatstr, "RGBA_4444");
break;
case HAL_PIXEL_FORMAT_YV12:
strcpy(pixelformatstr, "YV12");
break;
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
strcpy(pixelformatstr, "YCbCr_422_SP_NV16");
break;
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
strcpy(pixelformatstr, "YCrCb_420_SP_NV21");
break;
case HAL_PIXEL_FORMAT_YCbCr_422_I:
strcpy(pixelformatstr, "YCbCr_422_I_YUY2");
break;
case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
strcpy(pixelformatstr, "NV12_ENCODEABLE");
break;
case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
strcpy(pixelformatstr, "YCbCr_420_SP_TILED_TILE_4x2");
break;
case HAL_PIXEL_FORMAT_YCbCr_420_SP:
strcpy(pixelformatstr, "YCbCr_420_SP");
break;
case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
strcpy(pixelformatstr, "YCrCb_420_SP_ADRENO");
break;
case HAL_PIXEL_FORMAT_YCrCb_422_SP:
strcpy(pixelformatstr, "YCrCb_422_SP");
break;
case HAL_PIXEL_FORMAT_R_8:
strcpy(pixelformatstr, "R_8");
break;
case HAL_PIXEL_FORMAT_RG_88:
strcpy(pixelformatstr, "RG_88");
break;
case HAL_PIXEL_FORMAT_INTERLACE:
strcpy(pixelformatstr, "INTERLACE");
break;
default:
sprintf(pixelformatstr, "Unknown0x%X", format);
break;
}
}
void dumpLayer(int moduleCompositionType, int listFlags, size_t layerIndex,
hwc_layer_t hwLayers[])
{
char dumplogstr_png[128] = "";
char dumplogstr_raw[128] = "";
if (sfdump_counter_png <= sfdump_countlimit_png) {
sprintf(dumplogstr_png, "[png-dump-frame: %03d of %03d] ",
sfdump_counter_png, sfdump_countlimit_png);
}
if (sfdump_counter_raw <= sfdump_countlimit_raw) {
sprintf(dumplogstr_raw, "[raw-dump-frame: %03d of %03d]",
sfdump_counter_raw, sfdump_countlimit_raw);
}
if (NULL == hwLayers) {
LOGE("sfdump: Error.%s%sLayer[%d] No hwLayers to dump.",
dumplogstr_raw, dumplogstr_png, layerIndex);
return;
}
hwc_layer *layer = &hwLayers[layerIndex];
hwc_rect_t sourceCrop = layer->sourceCrop;
hwc_rect_t displayFrame = layer->displayFrame;
private_handle_t *hnd = (private_handle_t *)layer->handle;
char pixelformatstr[32] = "None";
if (hnd)
getHalPixelFormatStr(hnd->format, pixelformatstr);
LOGE("sfdump: %s%s[%s]-Composition, Layer[%d] SrcBuff[%dx%d] "
"SrcCrop[%dl, %dt, %dr, %db] "
"DispFrame[%dl, %dt, %dr, %db] Composition-type = %s, Format = %s, "
"Orientation = %s, Flags = %s%s%s%s%s%s%s%s%s%s",
dumplogstr_raw, dumplogstr_png,
(moduleCompositionType == COMPOSITION_TYPE_GPU)? "GPU":
(moduleCompositionType == COMPOSITION_TYPE_MDP)? "MDP":
(moduleCompositionType == COMPOSITION_TYPE_C2D)? "C2D":
(moduleCompositionType == COMPOSITION_TYPE_CPU)? "CPU":
(moduleCompositionType == COMPOSITION_TYPE_DYN)? "DYN": "???",
layerIndex,
(hnd)? hnd->width : -1, (hnd)? hnd->height : -1,
sourceCrop.left, sourceCrop.top,
sourceCrop.right, sourceCrop.bottom,
displayFrame.left, displayFrame.top,
displayFrame.right, displayFrame.bottom,
(layer->compositionType == HWC_FRAMEBUFFER)? "Framebuffer (OpenGL ES)":
(layer->compositionType == HWC_OVERLAY)? "Overlay":
(layer->compositionType == HWC_USE_COPYBIT)? "Copybit": "???",
pixelformatstr,
(layer->transform == Transform::ROT_0)? "ROT_0":
(layer->transform == Transform::FLIP_H)? "FLIP_H":
(layer->transform == Transform::FLIP_V)? "FLIP_V":
(layer->transform == Transform::ROT_90)? "ROT_90":
(layer->transform == Transform::ROT_180)? "ROT_180":
(layer->transform == Transform::ROT_270)? "ROT_270":
(layer->transform == Transform::ROT_INVALID)? "ROT_INVALID":"???",
(layer->flags == 0)? "[None]":"",
(layer->flags & HWC_SKIP_LAYER)? "[Skip layer]":"",
(layer->flags & HWC_LAYER_NOT_UPDATING)? "[Layer not updating]":"",
(layer->flags & HWC_USE_ORIGINAL_RESOLUTION)? "[Original Resolution]":"",
(layer->flags & HWC_DO_NOT_USE_OVERLAY)? "[Do not use Overlay]":"",
(layer->flags & HWC_COMP_BYPASS)? "[Bypass]":"",
(layer->flags & HWC_BYPASS_RESERVE_0)? "[Bypass Reserve 0]":"",
(layer->flags & HWC_BYPASS_RESERVE_1)? "[Bypass Reserve 1]":"",
(listFlags & HWC_GEOMETRY_CHANGED)? "[List: Geometry Changed]":"",
(listFlags & HWC_SKIP_COMPOSITION)? "[List: Skip Composition]":"");
if (NULL == hnd) {
LOGE("sfdump: %s%sLayer[%d] private-handle is invalid.",
dumplogstr_raw, dumplogstr_png, layerIndex);
return;
}
if ((sfdump_counter_png <= sfdump_countlimit_png) && hnd->base) {
bool bResult = false;
char sfdumpfile_name[256];
SkBitmap *tempSkBmp = new SkBitmap();
SkBitmap::Config tempSkBmpConfig = SkBitmap::kNo_Config;
sprintf(sfdumpfile_name, "%s/sfdump%03d_layer%d.png", sfdumpdir_png,
sfdump_counter_png, layerIndex);
switch (hnd->format) {
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_RGBX_8888:
case HAL_PIXEL_FORMAT_BGRA_8888:
tempSkBmpConfig = SkBitmap::kARGB_8888_Config;
break;
case HAL_PIXEL_FORMAT_RGB_565:
case HAL_PIXEL_FORMAT_RGBA_5551:
case HAL_PIXEL_FORMAT_RGBA_4444:
tempSkBmpConfig = SkBitmap::kRGB_565_Config;
break;
case HAL_PIXEL_FORMAT_RGB_888:
default:
tempSkBmpConfig = SkBitmap::kNo_Config;
break;
}
if (SkBitmap::kNo_Config != tempSkBmpConfig) {
tempSkBmp->setConfig(tempSkBmpConfig, hnd->width, hnd->height);
tempSkBmp->setPixels((void*)hnd->base);
bResult = SkImageEncoder::EncodeFile(sfdumpfile_name,
*tempSkBmp, SkImageEncoder::kPNG_Type, 100);
LOGE("sfdump: %sDumped Layer[%d] to %s: %s", dumplogstr_png,
layerIndex, sfdumpfile_name, bResult ? "Success" : "Fail");
}
else {
LOGE("sfdump: %sSkipping Layer[%d] dump: Unsupported layer "
"format %s for png encoder.", dumplogstr_png, layerIndex,
pixelformatstr);
}
delete tempSkBmp; // Calls SkBitmap::freePixels() internally.
}
if ((sfdump_counter_raw <= sfdump_countlimit_raw) && hnd->base) {
char sfdumpfile_name[256];
bool bResult = false;
sprintf(sfdumpfile_name, "%s/sfdump%03d_layer%d_%dx%d_%s.raw",
sfdumpdir_raw,
sfdump_counter_raw, layerIndex, hnd->width, hnd->height,
pixelformatstr);
FILE* fp = fopen(sfdumpfile_name, "w+");
if (fp != NULL) {
bResult = (bool) fwrite((void*)hnd->base, hnd->size, 1, fp);
fclose(fp);
}
LOGE("sfdump: %s Dumped Layer[%d] to %s: %s", dumplogstr_raw,
layerIndex, sfdumpfile_name, bResult ? "Success" : "Fail");
}
}
#ifdef DEBUG_CALC_FPS
ANDROID_SINGLETON_STATIC_INSTANCE(CalcFps) ;

View File

@ -36,6 +36,7 @@
#include <ui/Region.h>
#include <EGL/egl.h>
#include <utils/Singleton.h>
#include <cutils/properties.h>
#include "../libgralloc/gralloc_priv.h"
using namespace android;
@ -364,4 +365,38 @@ int qcomuiClearRegion(Region region, EGLDisplay dpy, EGLSurface sur);
*/
external_display handleEventHDMI(external_display newEvent, external_display
currEvent);
/*
* Checks if layers need to be dumped based on system property "debug.sf.dump"
* for raw dumps and "debug.sf.dump.png" for png dumps.
*
* For example, to dump 25 frames in raw format, do,
* adb shell setprop debug.sf.dump 25
* Layers are dumped in a time-stamped location: /data/sfdump*.
*
* To dump 10 frames in png format, do,
* adb shell setprop debug.sf.dump.png 10
* To dump another 25 or so frames in raw format, do,
* adb shell setprop debug.sf.dump 26
*
* To turn off logcat logging of layer-info, set both properties to 0,
* adb shell setprop debug.sf.dump.png 0
* adb shell setprop debug.sf.dump 0
*
* @return: true if layers need to be dumped (or logcat-ed).
*/
bool needToDumpLayers();
/*
* Dumps a layer's info into logcat and its buffer into raw/png files.
*
* @param: moduleCompositionType - Composition type set in hwcomposer module.
* @param: listFlags - Flags used in hwcomposer's list.
* @param: layerIndex - Index of layer being dumped.
* @param: hwLayers - Address of hwc_layer_t to log and dump.
*
*/
void dumpLayer(int moduleCompositionType, int listFlags, size_t layerIndex,
hwc_layer_t hwLayers[]);
#endif // INCLUDE_LIBQCOM_UI