From 3d1b94d07f1e5a309ac0dcbb838773f06604941b Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Wed, 27 Apr 2016 11:50:33 +0900 Subject: [PATCH] 1st implementation of tbm surface dump Change-Id: I2834e0957e96253f56eee234e8e4b861bcc53665 --- configure.ac | 5 +- packaging/libtbm.spec | 1 + src/tbm_bufmgr_int.h | 6 + src/tbm_surface_internal.c | 314 +++++++++++++++++++++++++++++++++++++++++++++ src/tbm_surface_internal.h | 36 ++++++ 5 files changed, 360 insertions(+), 2 deletions(-) mode change 100644 => 100755 src/tbm_bufmgr_int.h mode change 100644 => 100755 src/tbm_surface_internal.c mode change 100644 => 100755 src/tbm_surface_internal.h diff --git a/configure.ac b/configure.ac index 2257156..f726daa 100644 --- a/configure.ac +++ b/configure.ac @@ -73,9 +73,10 @@ PKG_CHECK_MODULES(PTHREADSTUBS, pthread-stubs) PKG_CHECK_MODULES(WL_CLIENT, wayland-client) PKG_CHECK_MODULES(WL_SERVER, wayland-server) PKG_CHECK_MODULES(WL_SCANNER, wayland-scanner) +PKG_CHECK_MODULES(LIBPNG, libpng) -LIBTBM_CFLAGS+="$LIBTBM_CFALGS $LIBDRM_CFLAGS $PTHREADSTUBS_CFLAGS $CAPI_CFLAGS $WL_CLIENT_CFLAGS $WL_SERVER_CFLAGS" -LIBTBM_LIBS+="$LIBTBM_LIBS $LIBDRM_LIBS $PTHREADSTUBS_LIBS $CAPI_LIBS $WL_CLIENT_LIBS $WL_SERVER_LIBS" +LIBTBM_CFLAGS+="$LIBTBM_CFALGS $LIBDRM_CFLAGS $PTHREADSTUBS_CFLAGS $CAPI_CFLAGS $WL_CLIENT_CFLAGS $WL_SERVER_CFLAGS $LIBPNG_CFLAGS" +LIBTBM_LIBS+="$LIBTBM_LIBS $LIBDRM_LIBS $PTHREADSTUBS_LIBS $CAPI_LIBS $WL_CLIENT_LIBS $WL_SERVER_LIBS $LIBPNG_LIBS" AC_SUBST(LIBTBM_CFLAGS) AC_SUBST(LIBTBM_LIBS) diff --git a/packaging/libtbm.spec b/packaging/libtbm.spec index 5217c24..03f0f62 100644 --- a/packaging/libtbm.spec +++ b/packaging/libtbm.spec @@ -15,6 +15,7 @@ BuildRequires: pkgconfig(wayland-server) BuildRequires: pkgconfig(wayland-client) BuildRequires: pkgconfig(pthread-stubs) BuildRequires: pkgconfig(capi-base-common) +BuildRequires: pkgconfig(libpng) %description Description: %{summary} diff --git a/src/tbm_bufmgr_int.h b/src/tbm_bufmgr_int.h old mode 100644 new mode 100755 index 36fc796..f0e116a --- a/src/tbm_bufmgr_int.h +++ b/src/tbm_bufmgr_int.h @@ -64,6 +64,12 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. return val;\ } \ } +#define TBM_GOTO_VAL_IF_FAIL(cond, val) {\ + if (!(cond)) {\ + TBM_LOG("[%s] : '%s' failed.\n", __func__, #cond);\ + goto val;\ + } \ +} /* check flags */ #define RETURN_CHECK_FLAG(cond) {\ diff --git a/src/tbm_surface_internal.c b/src/tbm_surface_internal.c old mode 100644 new mode 100755 index 6aa6c31..de7c2a3 --- a/src/tbm_surface_internal.c +++ b/src/tbm_surface_internal.c @@ -34,6 +34,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "tbm_bufmgr_int.h" #include "tbm_surface_internal.h" #include "list.h" +#include static tbm_bufmgr g_surface_bufmgr; static pthread_mutex_t tbm_surface_lock; @@ -1137,3 +1138,316 @@ tbm_surface_internal_delete_user_data(tbm_surface_h surface, return 1; } +typedef struct _tbm_surface_dump_info tbm_surface_dump_info; +typedef struct _tbm_surface_dump_buf_info tbm_surface_dump_buf_info; + +struct _tbm_surface_dump_buf_info +{ + int index; + tbm_bo bo; + int size; + int dirty; + char name[1024]; + + tbm_surface_info_s info; + + struct list_head link; +}; + +struct _tbm_surface_dump_info +{ + char *path; // copy??? + struct list_head *link; + struct list_head surface_list; /* link of surface */ +}; + +static tbm_surface_dump_info *g_dump_info = NULL; +static const char *dump_postfix[2] = {"png", "yuv"}; + +#if 0 +static void +_tbm_surface_internal_dump_file_raw(const char *file, void *data1, int size1, void *data2, + int size2, void *data3, int size3) +{ + unsigned int *blocks; + FILE *fp = fopen(file, "w+"); + TBM_RETURN_IF_FAIL(fp != NULL); + + blocks = (unsigned int *)data1; + fwrite(blocks, 1, size1, fp); + + if (size2 > 0) { + blocks = (unsigned int *)data2; + fwrite(blocks, 1, size2, fp); + } + + if (size3 > 0) { + blocks = (unsigned int *)data3; + fwrite(blocks, 1, size3, fp); + } + + fclose(fp); +} +#endif + +static void +_tbm_surface_internal_dump_file_png(const char *file, const void *data, int width, + int height) +{ + FILE *fp = fopen(file, "wb"); + TBM_RETURN_IF_FAIL(fp != NULL); + int depth = 8; + + png_structp pPngStruct = + png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!pPngStruct) { + fclose(fp); + return; + } + + png_infop pPngInfo = png_create_info_struct(pPngStruct); + if (!pPngInfo) { + png_destroy_write_struct(&pPngStruct, NULL); + fclose(fp); + return; + } + + png_init_io(pPngStruct, fp); + png_set_IHDR(pPngStruct, + pPngInfo, + width, + height, + depth, + PNG_COLOR_TYPE_RGBA, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + png_set_bgr(pPngStruct); + png_write_info(pPngStruct, pPngInfo); + + const int pixel_size = 4; // RGBA + png_bytep *row_pointers = + png_malloc(pPngStruct, height * sizeof(png_byte *)); + + unsigned int *blocks = (unsigned int *)data; + int y = 0; + int x = 0; + + for (; y < height; ++y) { + png_bytep row = + png_malloc(pPngStruct, sizeof(png_byte) * width * pixel_size); + row_pointers[y] = (png_bytep)row; + for (x = 0; x < width; ++x) { + unsigned int curBlock = blocks[y * width + x]; + row[x * pixel_size] = (curBlock & 0xFF); + row[1 + x * pixel_size] = (curBlock >> 8) & 0xFF; + row[2 + x * pixel_size] = (curBlock >> 16) & 0xFF; + row[3 + x * pixel_size] = (curBlock >> 24) & 0xFF; + } + } + + png_write_image(pPngStruct, row_pointers); + png_write_end(pPngStruct, pPngInfo); + + for (y = 0; y < height; y++) + png_free(pPngStruct, row_pointers[y]); + png_free(pPngStruct, row_pointers); + + png_destroy_write_struct(&pPngStruct, &pPngInfo); + + fclose(fp); +} + +void +tbm_surface_internal_dump_start(char *path, int buffer_size, int count) +{ + TBM_RETURN_IF_FAIL(path != NULL); + TBM_RETURN_IF_FAIL(buffer_size > 0); + TBM_RETURN_IF_FAIL(count > 0); + + tbm_surface_dump_buf_info *buf_info = NULL; + tbm_bo bo = NULL; + tbm_bo_handle bo_handle; + int i; + + /* check running */ + if (g_dump_info) { + TBM_LOG("[libtbm:%d] " + "waring: %s:%d already running the tbm_surface_internal_dump.\n", + getpid(), __func__, __LINE__); + return; + } + + g_dump_info = calloc(1, sizeof (buffer_size *count)); + TBM_RETURN_IF_FAIL(g_dump_info); + + LIST_INITHEAD(&g_dump_info->surface_list); + + for (i = 0; i < count; i++) { + buf_info = calloc(1, sizeof (tbm_surface_dump_buf_info)); + TBM_GOTO_VAL_IF_FAIL(buf_info, fail); + bo = tbm_bo_alloc(g_surface_bufmgr, buffer_size, TBM_BO_DEFAULT); + TBM_GOTO_VAL_IF_FAIL(bo, fail); + + bo_handle = tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE); + memset(bo_handle.ptr, 0x00, buffer_size); + tbm_bo_unmap(bo); + + buf_info->index = i; + buf_info->bo = bo; + buf_info->size = buffer_size; + + LIST_ADDTAIL(&buf_info->link, &g_dump_info->surface_list); + } + + g_dump_info->path = path; + g_dump_info->link = &g_dump_info->surface_list; + + TBM_LOG("Dump Start.. path:%s\n", g_dump_info->path); + + return; +fail: +// TODO: + return; +} + +void +tbm_surface_internal_dump_end(void) +{ + tbm_surface_dump_buf_info *buf_info, *tmp; + char file[2048] = {0, }; + tbm_bo_handle bo_handle; + + if (!g_dump_info) + return; + + /* make files */ + if (!LIST_IS_EMPTY(&g_dump_info->surface_list)) { + LIST_FOR_EACH_ENTRY_SAFE(buf_info, tmp, &g_dump_info->surface_list, link) { + if (buf_info->dirty) { + switch (buf_info->info.format) { + case TBM_FORMAT_ARGB8888: + case TBM_FORMAT_XRGB8888: + bo_handle = tbm_bo_map(buf_info->bo, TBM_DEVICE_CPU, TBM_OPTION_READ); + if (bo_handle.ptr == NULL) + continue; + snprintf(file, sizeof(file), "%s/%s", g_dump_info->path, buf_info->name); + TBM_LOG("Dump File.. %s generated.\n", file); + _tbm_surface_internal_dump_file_png(file, bo_handle.ptr, + buf_info->info.planes[0].stride >> 2, buf_info->info.height); + break; + case TBM_FORMAT_YVU420: + case TBM_FORMAT_YUV420: + // TODO: + break; + case TBM_FORMAT_NV12: + case TBM_FORMAT_NV21: + // TODO: + break; + case TBM_FORMAT_YUYV: + case TBM_FORMAT_UYVY: + // TODO: + break; + default: + //TDM_ERR("can't dump %c%c%c%c buffer", FOURCC_STR (info.format)); + TBM_LOG("can't dump\n"); + tbm_bo_unmap(buf_info->bo); + return; + } + } + } + } + + + /* free resources */ + if (!LIST_IS_EMPTY(&g_dump_info->surface_list)) { + LIST_FOR_EACH_ENTRY_SAFE(buf_info, tmp, &g_dump_info->surface_list, link) { + tbm_bo_unref(buf_info->bo); + free(buf_info); + } + } + + free(g_dump_info); + g_dump_info = NULL; + + TBM_LOG("Dump End..\n"); +} + +void +tbm_internal_surface_dump_buffer(tbm_surface_h surface, const char *type) +{ + TBM_RETURN_IF_FAIL(surface != NULL); + TBM_RETURN_IF_FAIL(type != NULL); + + tbm_surface_dump_buf_info *buf_info; + tbm_surface_info_s info; + struct list_head *next_link; + tbm_bo_handle bo_handle; + int ret; + const char *postfix; + + if (!g_dump_info) + return; + + next_link = g_dump_info->link->next; + TBM_RETURN_IF_FAIL(next_link != NULL); + + if (next_link == &g_dump_info->surface_list) + { + next_link = next_link->next; + TBM_RETURN_IF_FAIL(next_link != NULL); + } + + buf_info = LIST_ENTRY(tbm_surface_dump_buf_info, next_link, link); + TBM_RETURN_IF_FAIL(buf_info != NULL); + + ret = tbm_surface_map(surface, TBM_SURF_OPTION_READ|TBM_SURF_OPTION_WRITE, &info); + TBM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE); + + if (info.format == TBM_FORMAT_ARGB8888 || info.format == TBM_FORMAT_XRGB8888) + postfix = dump_postfix[0]; + else + postfix = dump_postfix[1]; + + /* make the file information */ + snprintf(buf_info->name, sizeof(buf_info->name), "%d-%s.%s", buf_info->index, type, postfix); + memcpy(&buf_info->info, &info, sizeof(tbm_surface_info_s)); + + /* dump */ + bo_handle = tbm_bo_map(buf_info->bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE); + TBM_RETURN_IF_FAIL(bo_handle.ptr != NULL); + + switch (info.format) { + case TBM_FORMAT_ARGB8888: + case TBM_FORMAT_XRGB8888: + memcpy(bo_handle.ptr, info.planes[0].ptr, info.size); + break; + case TBM_FORMAT_YVU420: + case TBM_FORMAT_YUV420: + // TODO: + break; + case TBM_FORMAT_NV12: + case TBM_FORMAT_NV21: + // TODO: + break; + case TBM_FORMAT_YUYV: + case TBM_FORMAT_UYVY: + // TODO: + break; + default: + //TDM_ERR("can't dump %c%c%c%c buffer", FOURCC_STR (info.format)); + TBM_LOG("can't dump\n"); + tbm_bo_unmap(buf_info->bo); + return; + } + + tbm_bo_unmap(buf_info->bo); + + tbm_surface_unmap(surface); + + buf_info->dirty = 1; + g_dump_info->link = next_link; + + TBM_LOG("Dump %s \n", buf_info->name); +} + diff --git a/src/tbm_surface_internal.h b/src/tbm_surface_internal.h old mode 100644 new mode 100755 index dc08067..083ef36 --- a/src/tbm_surface_internal.h +++ b/src/tbm_surface_internal.h @@ -397,6 +397,42 @@ int tbm_surface_internal_get_user_data(tbm_surface_h surface, unsigned long key, int tbm_surface_internal_delete_user_data(tbm_surface_h surface, unsigned long key); +/** + * @brief Start the dump debugging. + * @since_tizen 3.0 + * @param[in] path The given dump path + * @param[in] buffer_size the buffer size of a dump image + * @param[in] count The dump count number + * @see #tdm_helper_dump_stop() + */ +void tbm_surface_internal_dump_start(char *path, int buffer_size, int count); + +/** + * @brief End the dump debugging. + * @since_tizen 3.0 + * @see #tdm_helper_dump_start() + */ +void tbm_surface_internal_dump_end(void); + +/** + * @brief Dump a buffer + * @details + * This function supports only if a buffer has below formats. + * - TBM_FORMAT_ARGB8888 + * - TBM_FORMAT_XRGB8888 + * - TBM_FORMAT_YVU420 + * - TBM_FORMAT_YUV420 + * - TBM_FORMAT_NV12 + * - TBM_FORMAT_NV21 + * - TBM_FORMAT_YUYV + * - TBM_FORMAT_UYVY + * The filename extension should be "png" for TBM_FORMAT_ARGB8888 and TBM_FORMAT_XRGB8888 + * or "yuv" for YUV formats. + * @param[in] surface a tbm surface + * @param[in] type a string used by a file name. + */ +void tbm_internal_surface_dump_buffer(tbm_surface_h surface, const char *type); + #ifdef __cplusplus } #endif -- 2.7.4