diff options
Diffstat (limited to 'src/util/sec_util.c')
-rwxr-xr-x | src/util/sec_util.c | 2351 |
1 files changed, 2351 insertions, 0 deletions
diff --git a/src/util/sec_util.c b/src/util/sec_util.c new file mode 100755 index 0000000..6f6f747 --- /dev/null +++ b/src/util/sec_util.c @@ -0,0 +1,2351 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: Boram Park <boram1288.park@samsung.com> + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/shm.h> +#include <sys/ipc.h> +#include <sys/ioctl.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <dirent.h> +#include <X11/XWDFile.h> + +#include "sec.h" +#include "sec_util.h" +#include "sec_output.h" +#include "sec_video_fourcc.h" +#include <exynos_drm.h> +#include <list.h> + +#include "fimg2d.h" + +#define DUMP_SCALE_RATIO 2 + +int secUtilDumpBmp (const char * file, const void * data, int width, int height) +{ + int i; + + struct + { + unsigned char magic[2]; + } bmpfile_magic = { {'B', 'M'} }; + + struct + { + unsigned int filesz; + unsigned short creator1; + unsigned short creator2; + unsigned int bmp_offset; + } bmpfile_header = { 0, 0, 0, 0x36 }; + + struct + { + unsigned int header_sz; + unsigned int width; + unsigned int height; + unsigned short nplanes; + unsigned short bitspp; + unsigned int compress_type; + unsigned int bmp_bytesz; + unsigned int hres; + unsigned int vres; + unsigned int ncolors; + unsigned int nimpcolors; + } bmp_dib_v3_header_t = { 0x28, 0, 0, 1, 24, 0, 0, 0, 0, 0, 0 }; + unsigned int * blocks; + + XDBG_RETURN_VAL_IF_FAIL (data != NULL, UTIL_DUMP_ERR_INTERNAL); + XDBG_RETURN_VAL_IF_FAIL (width > 0, UTIL_DUMP_ERR_INTERNAL); + XDBG_RETURN_VAL_IF_FAIL (height > 0, UTIL_DUMP_ERR_INTERNAL); + + XDBG_TRACE (MSEC, "%s : width(%d) height(%d)\n", + __FUNCTION__, width, height); + + FILE * fp = fopen (file, "w+"); + if (fp == NULL) + { + return UTIL_DUMP_ERR_OPENFILE; + } + else + { + bmpfile_header.filesz = sizeof (bmpfile_magic) + sizeof (bmpfile_header) + + sizeof (bmp_dib_v3_header_t) + width * height * 3; + bmp_dib_v3_header_t.header_sz = sizeof (bmp_dib_v3_header_t); + bmp_dib_v3_header_t.width = width; + bmp_dib_v3_header_t.height = -height; + bmp_dib_v3_header_t.nplanes = 1; + bmp_dib_v3_header_t.bmp_bytesz = width * height * 3; + + fwrite (&bmpfile_magic, sizeof (bmpfile_magic), 1, fp); + fwrite (&bmpfile_header, sizeof (bmpfile_header), 1, fp); + fwrite (&bmp_dib_v3_header_t, sizeof (bmp_dib_v3_header_t), 1, fp); + + blocks = (unsigned int*)data; + for (i=0; i<height * width; i++) + fwrite (&blocks[i], 3, 1, fp); + + fclose (fp); + } + + return UTIL_DUMP_OK; +} + +int secUtilDumpShm (int shmid, const void * data, int width, int height) +{ + char * addr; + struct shmid_ds ds; + + addr = shmat (shmid, 0, 0); + if (addr == (void*)-1) + { + return UTIL_DUMP_ERR_SHMATTACH; + } + + if ((shmctl (shmid, IPC_STAT, &ds) < 0) || (ds.shm_segsz < width*height*4)) + { + shmctl (shmid, IPC_RMID, NULL); + shmdt (addr); + + return UTIL_DUMP_ERR_SEGSIZE; + } + + memcpy (addr, data, width*height*4); + + shmctl (shmid, IPC_RMID, NULL); + shmdt (addr); + + return UTIL_DUMP_OK; +} + +int secUtilDumpRaw (const char * file, const void * data, int size) +{ +// int i; + unsigned int * blocks; + + FILE * fp = fopen (file, "w+"); + if (fp == NULL) + { + return UTIL_DUMP_ERR_OPENFILE; + } + else + { + blocks = (unsigned int*)data; + fwrite (blocks, 1, size, fp); + + fclose (fp); + } + + return UTIL_DUMP_OK; +} + +int +secUtilDumpPixmap (const char * file, PixmapPtr pPixmap) +{ + SECPixmapPriv *privPixmap; + Bool need_finish = FALSE; + int ret; + + XDBG_RETURN_VAL_IF_FAIL (pPixmap != NULL, UTIL_DUMP_ERR_INTERNAL); + XDBG_RETURN_VAL_IF_FAIL (file != NULL, UTIL_DUMP_ERR_INTERNAL); + + privPixmap = exaGetPixmapDriverPrivate (pPixmap); + + if (!privPixmap->bo) + { + need_finish = TRUE; + secExaPrepareAccess (pPixmap, EXA_PREPARE_DEST); + XDBG_RETURN_VAL_IF_FAIL (privPixmap->bo != NULL, UTIL_DUMP_ERR_INTERNAL); + } + + ret = secUtilDumpBmp (file, tbm_bo_get_handle (privPixmap->bo, TBM_DEVICE_CPU).ptr, + pPixmap->devKind/(pPixmap->drawable.bitsPerPixel >> 3), + pPixmap->drawable.height); + + if (need_finish) + secExaFinishAccess (pPixmap, EXA_PREPARE_DEST); + + return ret; +} + +typedef struct _DumpBufInfo +{ + int index; + + tbm_bo bo; + int bo_size; + + char file[128]; + Bool dirty; + Bool dump_bmp; + + int width; + int height; + xRectangle rect; + int size; + + struct xorg_list link; +} DumpBufInfo; + +typedef struct _DumpInfo +{ + ScrnInfoPtr pScrn; + + struct xorg_list *cursor; + struct xorg_list bufs; +} DumpInfo; + +static Bool +_calculateSize (int width, int height, xRectangle *crop) +{ + if (crop->x < 0) + { + crop->width += (crop->x); + crop->x = 0; + } + if (crop->y < 0) + { + crop->height += (crop->y); + crop->y = 0; + } + + XDBG_GOTO_IF_FAIL (width > 0 && height > 0, fail_cal); + XDBG_GOTO_IF_FAIL (crop->width > 0 && crop->height > 0, fail_cal); + XDBG_GOTO_IF_FAIL (crop->x >= 0 && crop->x < width, fail_cal); + XDBG_GOTO_IF_FAIL (crop->y >= 0 && crop->y < height, fail_cal); + + if (crop->x + crop->width > width) + crop->width = width - crop->x; + + if (crop->y + crop->height > height) + crop->height = height - crop->y; + + return TRUE; +fail_cal: + XDBG_ERROR (MSEC, "(%dx%d : %d,%d %dx%d)\n", + width, height, crop->x, crop->y, crop->width, crop->height); + + return FALSE; +} + +static void +_secUtilConvertBosG2D (tbm_bo src_bo, int sw, int sh, xRectangle *sr, int sstride, + tbm_bo dst_bo, int dw, int dh, xRectangle *dr, int dstride, + Bool composite, int rotate) +{ + G2dImage *srcImg = NULL, *dstImg = NULL; + tbm_bo_handle src_bo_handle = {0,}; + tbm_bo_handle dst_bo_handle = {0,}; + G2dColorKeyMode mode; + G2dOp op; + + mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + src_bo_handle = tbm_bo_map (src_bo, TBM_DEVICE_2D, TBM_OPTION_READ); + XDBG_GOTO_IF_FAIL (src_bo_handle.s32 > 0, access_done); + + dst_bo_handle = tbm_bo_map (dst_bo, TBM_DEVICE_2D, TBM_OPTION_WRITE); + XDBG_GOTO_IF_FAIL (dst_bo_handle.s32 > 0, access_done); + + srcImg = g2d_image_create_bo (mode, sw, sh, src_bo_handle.s32, sstride); + XDBG_GOTO_IF_FAIL (srcImg != NULL, access_done); + + dstImg = g2d_image_create_bo (mode, dw, dh, dst_bo_handle.s32, dstride); + XDBG_GOTO_IF_FAIL (dstImg != NULL, access_done); + + if (!composite) + op = G2D_OP_SRC; + else + op = G2D_OP_OVER; + + if (rotate == 270) + srcImg->rotate_90 = 1; + else if (rotate == 180) + { + srcImg->xDir = 1; + srcImg->yDir = 1; + } + else if (rotate == 90) + { + srcImg->rotate_90 = 1; + srcImg->xDir = 1; + srcImg->yDir = 1; + } + + util_g2d_blend_with_scale (op, srcImg, dstImg, + (int)sr->x, (int)sr->y, sr->width, sr->height, + (int)dr->x, (int)dr->y, dr->width, dr->height, + FALSE); + g2d_exec (); + +access_done: + if (src_bo_handle.s32) + tbm_bo_unmap (src_bo); + if (dst_bo_handle.s32) + tbm_bo_unmap (dst_bo); + if (srcImg) + g2d_image_free (srcImg); + if (dstImg) + g2d_image_free (dstImg); +} + +static void +_secUtilConvertBosPIXMAN (tbm_bo src_bo, int sw, int sh, xRectangle *sr, int sstride, + tbm_bo dst_bo, int dw, int dh, xRectangle *dr, int dstride, + Bool composite, int rotate) +{ + tbm_bo_handle src_bo_handle = {0,}; + tbm_bo_handle dst_bo_handle = {0,}; + pixman_op_t op; + + src_bo_handle = tbm_bo_map (src_bo, TBM_DEVICE_CPU, TBM_OPTION_READ); + XDBG_GOTO_IF_FAIL (src_bo_handle.ptr != NULL, access_done); + + dst_bo_handle = tbm_bo_map (dst_bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE); + XDBG_GOTO_IF_FAIL (dst_bo_handle.ptr != NULL, access_done); + + if (!composite) + op = PIXMAN_OP_SRC; + else + op = PIXMAN_OP_OVER; + + secUtilConvertImage (op, src_bo_handle.ptr, dst_bo_handle.ptr, + PIXMAN_a8r8g8b8, PIXMAN_a8r8g8b8, + sw, sh, sr, + dw, dh, dr, + NULL, + rotate, FALSE, FALSE); + +access_done: + if (src_bo_handle.ptr) + tbm_bo_unmap (src_bo); + if (dst_bo_handle.ptr) + tbm_bo_unmap (dst_bo); +} + +/* support only RGB */ +void +secUtilConvertBos (ScrnInfoPtr pScrn, + tbm_bo src_bo, int sw, int sh, xRectangle *sr, int sstride, + tbm_bo dst_bo, int dw, int dh, xRectangle *dr, int dstride, + Bool composite, int rotate) +{ + SECPtr pSec = SECPTR (pScrn); + + XDBG_RETURN_IF_FAIL (pScrn != NULL); + XDBG_RETURN_IF_FAIL (src_bo != NULL); + XDBG_RETURN_IF_FAIL (dst_bo != NULL); + XDBG_RETURN_IF_FAIL (sr != NULL); + XDBG_RETURN_IF_FAIL (dr != NULL); + + pSec = SECPTR (pScrn); + XDBG_RETURN_IF_FAIL (pSec != NULL); + + if (!_calculateSize (sw, sh, sr)) + return; + if (!_calculateSize (dw, dh, dr)) + return; + + if (rotate < 0) + rotate += 360; + + XDBG_DEBUG (MVA, "[%dx%d (%d,%d %dx%d) %d] => [%dx%d (%d,%d %dx%d) %d] comp(%d) rot(%d) G2D(%d)\n", + sw, sh, sr->x, sr->y, sr->width, sr->height, sstride, + dw, dh, dr->x, dr->y, dr->width, dr->height, dstride, + composite, rotate, pSec->is_accel_2d); + + if (pSec->is_accel_2d) + _secUtilConvertBosG2D (src_bo, sw, sh, sr, sstride, + dst_bo, dw, dh, dr, dstride, + composite, rotate); + else + { + _secUtilConvertBosPIXMAN (src_bo, sw, sh, sr, sstride, + dst_bo, dw, dh, dr, dstride, + composite, rotate); + tbm_bo_map(src_bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE); + tbm_bo_unmap(src_bo); + } +} + +void* +secUtilPrepareDump (ScrnInfoPtr pScrn, int bo_size, int buf_cnt) +{ + SECPtr pSec = SECPTR (pScrn); + DumpInfo *dump; + int i; + + dump = calloc (1, sizeof (DumpInfo)); + XDBG_RETURN_VAL_IF_FAIL (dump != NULL, NULL); + + bo_size = bo_size / DUMP_SCALE_RATIO; + + dump->pScrn = pScrn; + + xorg_list_init (&dump->bufs); + + for (i = 0; i < buf_cnt; i++) + { + tbm_bo bo = tbm_bo_alloc (pSec->tbm_bufmgr, bo_size, TBM_BO_DEFAULT); + XDBG_GOTO_IF_FAIL (bo != NULL, fail_prepare); + + DumpBufInfo *buf_info = calloc (1, sizeof (DumpBufInfo)); + if (!buf_info) + { + tbm_bo_unref (bo); + XDBG_WARNING_IF_FAIL (buf_info != NULL); + goto fail_prepare; + } + + buf_info->index = i; + buf_info->bo = bo; + buf_info->bo_size = bo_size; + + tbm_bo_handle handle = tbm_bo_map (bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE); + memset (handle.ptr, 0x00, buf_info->bo_size); + tbm_bo_unmap (bo); + + xorg_list_add (&buf_info->link, &dump->bufs); + } + + dump->cursor = &dump->bufs; + + return (void*)dump; + +fail_prepare: + secUtilFinishDump (dump); + return NULL; +} + +void +secUtilDoDumpRaws (void *d, tbm_bo *bo, int *size, int bo_cnt, const char *file) +{ + DumpInfo *dump = (DumpInfo*)d; + DumpBufInfo *next = NULL; + struct xorg_list *next_cursor; + void *src_ptr, *dst_ptr; + int i, remain_size, need_size; + + if (!dump || !bo) + return; + + CARD32 prev = GetTimeInMillis (); + + next_cursor = dump->cursor->next; + XDBG_RETURN_IF_FAIL (next_cursor != NULL); + + if (next_cursor == &dump->bufs) + { + next_cursor = next_cursor->next; + XDBG_RETURN_IF_FAIL (next_cursor != NULL); + } + + next = xorg_list_entry (next_cursor, DumpBufInfo, link); + XDBG_RETURN_IF_FAIL (next != NULL); + + need_size = 0; + for (i = 0; i < bo_cnt; i++) + need_size += size[i]; + if (need_size > next->bo_size) + { + SECPtr pSec = SECPTR (dump->pScrn); + tbm_bo new_bo = tbm_bo_alloc (pSec->tbm_bufmgr, need_size, TBM_BO_DEFAULT); + XDBG_RETURN_IF_FAIL (new_bo != NULL); + tbm_bo_unref (next->bo); + next->bo = new_bo; + next->bo_size = need_size; + } + + dst_ptr = tbm_bo_map (next->bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE).ptr; + XDBG_RETURN_IF_FAIL (dst_ptr != NULL); + + remain_size = next->bo_size; + for (i = 0; i < bo_cnt; i++) + { + XDBG_GOTO_IF_FAIL (size[i] <= remain_size, end_dump_raws); + + src_ptr = tbm_bo_map (bo[i], TBM_DEVICE_CPU, TBM_OPTION_READ).ptr; + XDBG_GOTO_IF_FAIL (src_ptr != NULL, end_dump_raws); + + memcpy (dst_ptr, src_ptr, size[i]); + dst_ptr += size[i]; + + if (i == 0) + next->size = 0; + + next->size += size[i]; + remain_size -= size[i]; + + tbm_bo_unmap (bo[i]); + } + + snprintf (next->file, sizeof (next->file), "%.3f_%s", GetTimeInMillis()/1000.0, file); + memset (&next->rect, 0, sizeof (xRectangle)); + next->dirty = TRUE; + next->dump_bmp = FALSE; + + XDBG_TRACE (MSEC, "DumpRaws: %ld(%d)\n", GetTimeInMillis () - prev, next->index); + + dump->cursor = next_cursor; + +end_dump_raws: + tbm_bo_unmap (next->bo); + + return; +} + +void +secUtilDoDumpBmps (void *d, tbm_bo bo, int w, int h, xRectangle *crop, const char *file) +{ + DumpInfo *dump = (DumpInfo*)d; + DumpBufInfo *next = NULL; + struct xorg_list *next_cursor; + int scale_w = w / DUMP_SCALE_RATIO; + int scale_h = h / DUMP_SCALE_RATIO; + xRectangle temp = {0,}; + + if (!dump || !bo) + return; + + next_cursor = dump->cursor->next; + XDBG_RETURN_IF_FAIL (next_cursor != NULL); + + if (next_cursor == &dump->bufs) + { + next_cursor = next_cursor->next; + XDBG_RETURN_IF_FAIL (next_cursor != NULL); + } + + next = xorg_list_entry (next_cursor, DumpBufInfo, link); + XDBG_RETURN_IF_FAIL (next != NULL); + + tbm_bo_handle src_handle = tbm_bo_get_handle (bo, TBM_DEVICE_CPU); + tbm_bo_handle dst_handle = tbm_bo_get_handle (next->bo, TBM_DEVICE_CPU); + XDBG_RETURN_IF_FAIL (src_handle.ptr != NULL); + XDBG_RETURN_IF_FAIL (dst_handle.ptr != NULL); + XDBG_RETURN_IF_FAIL (scale_w*scale_h*4 <= next->bo_size); + + CARD32 prev = GetTimeInMillis (); + + snprintf (next->file, sizeof (next->file), "%.3f_%s", GetTimeInMillis()/1000.0, file); + + next->dirty = TRUE; + next->dump_bmp = TRUE; + next->size = scale_w*scale_h*4; + + next->width = scale_w; + next->height = scale_h; + next->rect.x = 0; + next->rect.y = 0; + next->rect.width = (crop)?(crop->width/DUMP_SCALE_RATIO):next->width; + next->rect.height = (crop)?(crop->height/DUMP_SCALE_RATIO):next->height; + + temp.width = (crop)?crop->width:w; + temp.height = (crop)?crop->height:h; + + secUtilConvertBos (dump->pScrn, bo, w, h, &temp, w*4, + next->bo, scale_w, scale_h, &next->rect, scale_w*4, + FALSE, 0); + + XDBG_TRACE (MSEC, "DumpBmps: %ld(%d)\n", GetTimeInMillis () - prev, next->index); + + dump->cursor = next_cursor; + + return; +} + +void +secUtilDoDumpPixmaps (void *d, PixmapPtr pPixmap, const char *file) +{ + SECPixmapPriv *privPixmap; + xRectangle rect = {0,}; + Bool need_finish = FALSE; + + XDBG_RETURN_IF_FAIL (d != NULL); + XDBG_RETURN_IF_FAIL (pPixmap != NULL); + XDBG_RETURN_IF_FAIL (file != NULL); + + privPixmap = exaGetPixmapDriverPrivate (pPixmap); + + if (!privPixmap->bo) + { + need_finish = TRUE; + secExaPrepareAccess (pPixmap, EXA_PREPARE_DEST); + XDBG_RETURN_IF_FAIL (privPixmap->bo != NULL); + } + + rect.width = pPixmap->drawable.width; + rect.height = pPixmap->drawable.height; + + secUtilDoDumpBmps (d, privPixmap->bo, + pPixmap->devKind/(pPixmap->drawable.bitsPerPixel >> 3), + pPixmap->drawable.height, &rect, file); + + if (need_finish) + secExaFinishAccess (pPixmap, EXA_PREPARE_DEST); +} + +void +secUtilDoDumpVBuf (void *d, SECVideoBuf *vbuf, const char *file) +{ + XDBG_RETURN_IF_FAIL (d != NULL); + XDBG_RETURN_IF_FAIL (vbuf != NULL); + XDBG_RETURN_IF_FAIL (file != NULL); + XDBG_RETURN_IF_FAIL (vbuf->secure == FALSE); + + if (IS_RGB (vbuf->id)) + secUtilDoDumpBmps (d, vbuf->bo[0], vbuf->width, vbuf->height, &vbuf->crop, file); + else if (vbuf->id == FOURCC_SN12 || vbuf->id == FOURCC_ST12) + secUtilDoDumpRaws (d, vbuf->bo, vbuf->lengths, 2, file); + else + secUtilDoDumpRaws (d, vbuf->bo, &vbuf->size, 1, file); +} + +void +secUtilFlushDump (void *d) +{ + static Bool is_dir = FALSE; + char *dir = DUMP_DIR; + DumpInfo *dump = (DumpInfo*)d; + DumpBufInfo *cur = NULL, *next = NULL; + + if (!dump) + return; + + if (!is_dir) + { + DIR *dp; + mkdir (dir, 0755); + if (!(dp = opendir (dir))) + { + ErrorF ("failed: open'%s'\n", dir); + return; + } + else + closedir (dp); + is_dir = TRUE; + } + + xorg_list_for_each_entry_safe (cur, next, &dump->bufs, link) + { + if (cur->dirty) + { + if (cur->bo) + { + char file[128]; + + snprintf (file, sizeof(file), "%s/%s", dir, cur->file); + + if (cur->dump_bmp) + { + unsigned int *p; + tbm_bo_handle handle = tbm_bo_map (cur->bo, TBM_DEVICE_CPU, TBM_OPTION_READ); + XDBG_GOTO_IF_FAIL (handle.ptr != NULL, reset_dump); + + /* fill magenta color(#FF00FF) for background */ + p = (unsigned int*)handle.ptr; + if (p) + { + int i, j; + for (j = 0; j < cur->height; j++) + for (i = cur->rect.width; i < cur->width ; i++) + p[i + j * cur->width] = 0xFFFF00FF; + } + + secUtilDumpBmp (file, handle.ptr, cur->width, cur->height); + + tbm_bo_unmap (cur->bo); + } + else + { + tbm_bo_handle handle = tbm_bo_map (cur->bo, TBM_DEVICE_CPU, TBM_OPTION_READ); + XDBG_GOTO_IF_FAIL (handle.ptr != NULL, reset_dump); + + secUtilDumpRaw (file, handle.ptr, cur->size); + + tbm_bo_unmap (cur->bo); + } + + XDBG_ERROR (MSEC, "%s saved\n", file); + } + +reset_dump: + { + tbm_bo_handle handle = tbm_bo_map (cur->bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE); + memset (handle.ptr, 0x00, cur->bo_size); + tbm_bo_unmap (cur->bo); + } + cur->width = 0; + cur->height = 0; + cur->size = 0; + memset (&cur->rect, 0, sizeof (xRectangle)); + cur->file[0] = '\0'; + cur->dirty = FALSE; + cur->dump_bmp = FALSE; + } + } +} + +void +secUtilFinishDump (void *d) +{ + DumpInfo *dump = (DumpInfo*)d; + DumpBufInfo *cur = NULL, *next = NULL; + + if (!dump) + return; + + xorg_list_for_each_entry_safe (cur, next, &dump->bufs, link) + { + if (cur->bo) + tbm_bo_unref (cur->bo); + xorg_list_del (&cur->link); + free (cur); + } + free (dump); +} + +#ifndef RR_Rotate_All +#define RR_Rotate_All (RR_Rotate_0|RR_Rotate_90|RR_Rotate_180|RR_Rotate_270) +#endif + +int secUtilDegreeToRotate (int degree) +{ + int rotate; + + switch (degree) + { + case 0: + rotate = RR_Rotate_0; + break; + case 90: + rotate = RR_Rotate_90; + break; + case 180: + rotate = RR_Rotate_180; + break; + case 270: + rotate = RR_Rotate_270; + break; + default: + rotate = 0; /* ERROR */ + break; + } + + return rotate; +} + +int secUtilRotateToDegree (int rotate) +{ + int degree; + + switch (rotate & RR_Rotate_All) + { + case RR_Rotate_0: + degree = 0; + break; + case RR_Rotate_90: + degree = 90; + break; + case RR_Rotate_180: + degree = 180; + break; + case RR_Rotate_270: + degree = 270; + break; + default: + degree = -1; /* ERROR */ + break; + } + + return degree; +} + +static int +_secUtilRotateToInt (int rot) +{ + switch (rot & RR_Rotate_All) + { + case RR_Rotate_0: + return 0; + case RR_Rotate_90: + return 1; + case RR_Rotate_180: + return 2; + case RR_Rotate_270: + return 3; + } + + return 0; +} + +int secUtilRotateAdd (int rot_a, int rot_b) +{ + int a = _secUtilRotateToInt (rot_a); + int b = _secUtilRotateToInt (rot_b); + + return (int) ((1 << ((a+b) %4)) &RR_Rotate_All); +} + +void +secUtilCacheFlush (ScrnInfoPtr scrn) +{ + struct drm_exynos_gem_cache_op cache_op; + SECPtr pSec; + int ret; + + XDBG_RETURN_IF_FAIL (scrn != NULL); + + pSec = SECPTR (scrn); + + CLEAR (cache_op); + cache_op.flags = EXYNOS_DRM_CACHE_FSH_ALL | EXYNOS_DRM_ALL_CACHES_CORES; + cache_op.usr_addr = 0; + cache_op.size = 0; + + ret = drmCommandWriteRead (pSec->drm_fd, DRM_EXYNOS_GEM_CACHE_OP, + &cache_op, sizeof(cache_op)); + if (ret) + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "cache flush failed. (%s)\n", strerror(errno)); +} + +const PropertyPtr +secUtilGetWindowProperty (WindowPtr pWin, const char* prop_name) +{ + int rc; + Mask prop_mode = DixReadAccess; + Atom property; + PropertyPtr pProp; + + if (!prop_name) + return NULL; + + property = MakeAtom (prop_name, strlen (prop_name), FALSE); + if (property == None) + return NULL; + + rc = dixLookupProperty (&pProp, pWin, property, serverClient, prop_mode); + if (rc == Success && pProp->data) + { + return pProp; + } + + return NULL; +} + +static void * +_copy_one_channel (int width, int height, + char *s, int s_size_w, int s_pitches, + char *d, int d_size_w, int d_pitches) +{ + uchar *src = (uchar*)s; + uchar *dst = (uchar*)d; + + if (d_size_w == width && s_size_w == width) + memcpy (dst, src, s_pitches * height); + else + { + int i; + + for (i = 0; i < height; i++) + { + memcpy (dst, src, s_pitches); + src += s_pitches; + dst += d_pitches; + } + } + + return dst; +} + +void* +secUtilCopyImage (int width, int height, + char *s, int s_size_w, int s_size_h, + int *s_pitches, int *s_offsets, int *s_lengths, + char *d, int d_size_w, int d_size_h, + int *d_pitches, int *d_offsets, int *d_lengths, + int channel, int h_sampling, int v_sampling) +{ + int i; + + for (i = 0; i < channel; i++) + { + int c_width = width; + int c_height = height; + + if (i > 0) + { + c_width = c_width / h_sampling; + c_height = c_height / v_sampling; + } + + _copy_one_channel (c_width, c_height, + s, s_size_w, s_pitches[i], + d, d_size_w, d_pitches[i]); + + s = s + s_lengths[i]; + d = d + d_lengths[i]; + } + + return d; +} + +/* + * RR_Rotate_90: Target turns to 90. UI turns to 270. + * RR_Rotate_270: Target turns to 270. UI turns to 90. + * + * [Target] ---------- + * | | + * Top (RR_Rotate_90) | | Top (RR_Rotate_270) + * | | + * ---------- + * [UI,FIMC] ---------- + * | | + * Top (degree: 270) | | Top (degree: 90) + * | | + * ---------- + */ +void +secUtilRotateArea (int *width, int *height, xRectangle *rect, int degree) +{ +// int old_w, old_h; + + XDBG_RETURN_IF_FAIL (width != NULL); + XDBG_RETURN_IF_FAIL (height != NULL); + XDBG_RETURN_IF_FAIL (rect != NULL); + + if (degree == 0) + return; + + secUtilRotateRect (*width, *height, rect, degree); + +// old_w = *width; +// old_h = *height; + + if (degree % 180) + SWAP (*width, *height); + +// ErrorF ("%d: (%dx%d) => (%dx%d)\n", degree, old_w, old_h, *width, *height); +} + +void +secUtilRotateRect2 (int width, int height, xRectangle *rect, int degree, const char *func) +{ + xRectangle new_rect = {0,}; + + XDBG_RETURN_IF_FAIL (rect != NULL); + + if (degree == 0) + return; + + degree = (degree + 360) % 360; + + switch (degree) + { + case 90: + new_rect.x = height - (rect->y + rect->height); + new_rect.y = rect->x; + new_rect.width = rect->height; + new_rect.height = rect->width; + break; + case 180: + new_rect.x = width - (rect->x + rect->width); + new_rect.y = height - (rect->y + rect->height); + new_rect.width = rect->width; + new_rect.height = rect->height; + break; + case 270: + new_rect.x = rect->y; + new_rect.y = width - (rect->x + rect->width); + new_rect.width = rect->height; + new_rect.height = rect->width; + break; + } + +// ErrorF ("%d: %dx%d (%d,%d %dx%d) => (%d,%d %dx%d) %s\n", +// degree, width, height, +// rect->x, rect->y, rect->width, rect->height, +// new_rect.x, new_rect.y, new_rect.width, new_rect.height, func); + + *rect = new_rect; +} + +void +secUtilRotateRegion (int width, int height, RegionPtr region, int degree) +{ + RegionRec new_region; + int nbox; + BoxPtr pBox; + + if (!region) + return; + + nbox = RegionNumRects (region); + pBox = RegionRects (region); + + if (nbox == 0) + return; + + RegionInit (&new_region, NULL, 0); + + while (nbox--) + { + if (pBox) + { + xRectangle temp; + RegionPtr temp_region; + temp.x = pBox->x1; + temp.y = pBox->y1; + temp.width = pBox->x2 - pBox->x1; + temp.height = pBox->y2 - pBox->y1; + secUtilRotateRect (width, height, &temp, degree); + temp_region = RegionFromRects (1, &temp, 0); + RegionUnion (&new_region, &new_region, temp_region); + RegionDestroy (temp_region); + } + + pBox++; + } + + RegionCopy (region, &new_region); + RegionUninit (&new_region); +} + +void +secUtilAlignRect (int src_w, int src_h, int dst_w, int dst_h, xRectangle *fit, Bool hw) +{ + int fit_width; + int fit_height; + float rw, rh, max; + + if (!fit) + return; + + XDBG_RETURN_IF_FAIL (src_w > 0 && src_h > 0); + XDBG_RETURN_IF_FAIL (dst_w > 0 && dst_h > 0); + + rw = (float)src_w / dst_w; + rh = (float)src_h / dst_h; + max = MAX (rw, rh); + + fit_width = src_w / max; + fit_height = src_h / max; + + if (hw) + fit_width &= (~0x3); + + fit->x = (dst_w - fit_width) / 2; + fit->y = (dst_h - fit_height) / 2; + fit->width = fit_width; + fit->height = fit_height; +} + +void +secUtilScaleRect (int src_w, int src_h, int dst_w, int dst_h, xRectangle *scale) +{ + float ratio; + xRectangle fit; + + XDBG_RETURN_IF_FAIL (scale != NULL); + XDBG_RETURN_IF_FAIL (src_w > 0 && src_h > 0); + XDBG_RETURN_IF_FAIL (dst_w > 0 && dst_h > 0); + + if ((src_w == dst_w) && (src_h == dst_h)) + return; + + secUtilAlignRect (src_w, src_h, dst_w, dst_h, &fit, FALSE); + + ratio = (float)fit.width / src_w; + + scale->x = scale->x * ratio + fit.x; + scale->y = scale->y * ratio + fit.y; + scale->width = scale->width * ratio; + scale->height = scale->height * ratio; +} + +/* true iff two Boxes overlap */ +#define EXTENTCHECK(r1, r2) \ + (!( ((r1)->x2 <= (r2)->x1) || \ + ((r1)->x1 >= (r2)->x2) || \ + ((r1)->y2 <= (r2)->y1) || \ + ((r1)->y1 >= (r2)->y2) ) ) + +/* true iff (x,y) is in Box */ +#define INBOX(r, x, y) \ + ( ((r)->x2 > x) && \ + ((r)->x1 <= x) && \ + ((r)->y2 > y) && \ + ((r)->y1 <= y) ) + +/* true iff Box r1 contains Box r2 */ +#define SUBSUMES(r1, r2) \ + ( ((r1)->x1 <= (r2)->x1) && \ + ((r1)->x2 >= (r2)->x2) && \ + ((r1)->y1 <= (r2)->y1) && \ + ((r1)->y2 >= (r2)->y2) ) + +int +secUtilBoxInBox (BoxPtr base, BoxPtr box) +{ + XDBG_RETURN_VAL_IF_FAIL(base != NULL, -1); + XDBG_RETURN_VAL_IF_FAIL(box != NULL, -1); + + if(base->x1 == box->x1 && base->y1 == box->y1 && base->x2 == box->x2 && base->y2 == box->y2) + { + return rgnSAME; + } + else if(SUBSUMES(base, box)) + { + return rgnIN; + } + else if(EXTENTCHECK(base, box)) + { + return rgnPART; + } + else + return rgnOUT; + + return -1; +} + +int +secUtilBoxArea(BoxPtr pBox) +{ + return (int) (pBox->x2 - pBox->x1) *(int) (pBox->y2 -pBox->y1); +} + +int +secUtilBoxIntersect(BoxPtr pDstBox, BoxPtr pBox1, BoxPtr pBox2) +{ + pDstBox->x1 = pBox1->x1 > pBox2->x1 ? pBox1->x1 : pBox2->x1; + pDstBox->x2 = pBox1->x2 < pBox2->x2 ? pBox1->x2 : pBox2->x2; + pDstBox->y1 = pBox1->y1 > pBox2->y1 ? pBox1->y1 : pBox2->y1; + pDstBox->y2 = pBox1->y2 < pBox2->y2 ? pBox1->y2 : pBox2->y2; + + if (pDstBox->x1 >= pDstBox->x2 || pDstBox->y1 >= pDstBox->y2) + { + pDstBox->x1 = 0; + pDstBox->x2 = 0; + pDstBox->y1 = 0; + pDstBox->y2 = 0; + return rgnOUT; + } + + if (pDstBox->x1 == pBox2->x1 && + pDstBox->y1 == pBox2->y1 && + pDstBox->x2 == pBox2->x2 && + pDstBox->y2 == pBox2->y2) + return rgnIN; + + return rgnPART; +} + +void +secUtilBoxMove(BoxPtr pBox, int dx, int dy) +{ + if(dx == 0 && dy == 0) return; + + pBox->x1 += dx; + pBox->x2 += dx; + pBox->y1 += dy; + pBox->y2 += dy; +} + + +Bool +secUtilRectIntersect (xRectanglePtr pDest, xRectanglePtr pRect1, xRectanglePtr pRect2) +{ + int dest_x, dest_y; + int dest_x2, dest_y2; + + if (!pDest) + return FALSE; + + dest_x = MAX (pRect1->x, pRect2->x); + dest_y = MAX (pRect1->y, pRect2->y); + dest_x2 = MIN (pRect1->x + pRect1->width, pRect2->x + pRect2->width); + dest_y2 = MIN (pRect1->y + pRect1->height, pRect2->y + pRect2->height); + + if (dest_x2 > dest_x && dest_y2 > dest_y) + { + pDest->x = dest_x; + pDest->y = dest_y; + pDest->width = dest_x2 - dest_x; + pDest->height = dest_y2 - dest_y; + } + else + { + pDest->width = 0; + pDest->height = 0; + } + + return TRUE; +} + + +void +secUtilSaveImage (pixman_image_t *image, char *path) +{ + void *data; + int width, height; + + XDBG_RETURN_IF_FAIL (image != NULL); + XDBG_RETURN_IF_FAIL (path != NULL); + + width = pixman_image_get_width (image); + height = pixman_image_get_height (image); + + data = pixman_image_get_data (image); + XDBG_RETURN_IF_FAIL (data != NULL); + + secUtilDumpBmp (path, data, width, height); +} + +Bool +secUtilConvertImage (pixman_op_t op, uchar *srcbuf, uchar *dstbuf, + pixman_format_code_t src_format, pixman_format_code_t dst_format, + int sw, int sh, xRectangle *sr, + int dw, int dh, xRectangle *dr, + RegionPtr dst_clip_region, + int rotate, int hflip, int vflip) +{ + pixman_image_t *src_img; + pixman_image_t *dst_img; + int src_stride, dst_stride; + int src_bpp; + int dst_bpp; + double scale_x, scale_y; + int rotate_step; + int ret = FALSE; + pixman_transform_t t; + struct pixman_f_transform ft; + + src_bpp = PIXMAN_FORMAT_BPP (src_format) / 8; + XDBG_RETURN_VAL_IF_FAIL (src_bpp > 0, FALSE); + + dst_bpp = PIXMAN_FORMAT_BPP (dst_format) / 8; + XDBG_RETURN_VAL_IF_FAIL (dst_bpp > 0, FALSE); + + src_stride = sw * src_bpp; + dst_stride = dw * dst_bpp; + + src_img = pixman_image_create_bits (src_format, sw, sh, + (uint32_t*)srcbuf, src_stride); + dst_img = pixman_image_create_bits (dst_format, dw, dh, + (uint32_t*)dstbuf, dst_stride); + + XDBG_GOTO_IF_FAIL (src_img != NULL, CANT_CONVERT); + XDBG_GOTO_IF_FAIL (dst_img != NULL, CANT_CONVERT); + + pixman_f_transform_init_identity (&ft); + + if (hflip) + { + pixman_f_transform_scale (&ft, NULL, -1, 1); + pixman_f_transform_translate (&ft, NULL, dr->width, 0); + } + + if (vflip) + { + pixman_f_transform_scale (&ft, NULL, 1, -1); + pixman_f_transform_translate (&ft, NULL, 0, dr->height); + } + + rotate_step = (rotate + 360) / 90 % 4; + + if (rotate_step > 0) + { + int c, s, tx = 0, ty = 0; + switch (rotate_step) + { + case 1: + /* 90 degrees */ + c = 0; + s = -1; + tx = -dr->width; + break; + case 2: + /* 180 degrees */ + c = -1; + s = 0; + tx = -dr->width; + ty = -dr->height; + break; + case 3: + /* 270 degrees */ + c = 0; + s = 1; + ty = -dr->height; + break; + default: + /* 0 degrees */ + c = 0; + s = 0; + break; + } + + pixman_f_transform_translate (&ft, NULL, tx, ty); + pixman_f_transform_rotate (&ft, NULL, c, s); + } + + if (rotate_step % 2 == 0) + { + scale_x = (double)sr->width / dr->width; + scale_y = (double)sr->height / dr->height; + } + else + { + scale_x = (double)sr->width / dr->height; + scale_y = (double)sr->height / dr->width; + } + + pixman_f_transform_scale (&ft, NULL, scale_x, scale_y); + pixman_f_transform_translate (&ft, NULL, sr->x, sr->y); + + pixman_transform_from_pixman_f_transform (&t, &ft); + pixman_image_set_transform (src_img, &t); + + pixman_image_composite (op, src_img, NULL, dst_img, 0, 0, 0, 0, + dr->x, dr->y, dr->width, dr->height); + + ret = TRUE; + +CANT_CONVERT: + if (src_img) + pixman_image_unref (src_img); + if (dst_img) + pixman_image_unref (dst_img); + + return ret; +} + +void +secUtilFreeHandle (ScrnInfoPtr scrn, unsigned int handle) +{ + struct drm_gem_close close; + SECPtr pSec; + + XDBG_RETURN_IF_FAIL (scrn != NULL); + + pSec = SECPTR (scrn); + + CLEAR (close); + close.handle = handle; + if (drmIoctl (pSec->drm_fd, DRM_IOCTL_GEM_CLOSE, &close)) + { + XDBG_ERRNO (MSEC, "DRM_IOCTL_GEM_CLOSE failed.\n"); + } +} + +Bool +secUtilConvertPhyaddress (ScrnInfoPtr scrn, unsigned int phy_addr, int size, + unsigned int *handle) +{ + struct drm_exynos_gem_phy_imp phy_imp = {0,}; + SECPtr pSec; + + XDBG_RETURN_VAL_IF_FAIL (scrn != NULL, FALSE); + + if (!phy_addr || size <= 0 || !handle) + return FALSE; + + pSec = SECPTR (scrn); + phy_imp.phy_addr = (unsigned long)phy_addr; + phy_imp.size = (unsigned long)size; + + if (pSec->drm_fd) + if (ioctl(pSec->drm_fd, DRM_IOCTL_EXYNOS_GEM_PHY_IMP, &phy_imp) < 0) + { + XDBG_ERRNO (MSEC, "DRM_IOCTL_EXYNOS_GEM_PHY_IMP failed. %p(%d)\n", + (void*)phy_addr, size); + return FALSE; + } + + *handle = phy_imp.gem_handle; + + return TRUE; +} + +Bool +secUtilConvertHandle (ScrnInfoPtr scrn, unsigned int handle, + unsigned int *phy_addr, int *size) +{ + struct drm_exynos_gem_get_phy get_phy; + SECPtr pSec; + + XDBG_RETURN_VAL_IF_FAIL (scrn != NULL, FALSE); + + if (handle == 0 || (!phy_addr && !size)) + return FALSE; + + pSec = SECPTR (scrn); + memset (&get_phy, 0, sizeof (struct drm_exynos_gem_get_phy)); + get_phy.gem_handle = handle; + + if (pSec->drm_fd) + if (ioctl(pSec->drm_fd, DRM_IOCTL_EXYNOS_GEM_GET_PHY, &get_phy) < 0) + { + XDBG_DEBUG (MLYR, "DRM_IOCTL_EXYNOS_GEM_GET_PHY failed. (%d)(%s,%d)\n", + handle, strerror(errno), errno); + return FALSE; + } + + if (phy_addr) + *phy_addr = (unsigned int)get_phy.phy_addr; + + if (size) + *size = (int)((unsigned int)get_phy.size); + + return TRUE; +} + +typedef struct _ListData +{ + void *key; + void *data; + + struct xorg_list link; +} ListData; + +static ListData* +_secUtilListGet (void *list, void *key) +{ + ListData *data = NULL, *next = NULL; + + if (!list) + return NULL; + + xorg_list_for_each_entry_safe (data, next, (struct xorg_list*)list, link) + { + if (data->key == key) + return data; + } + return NULL; +} + +void* +secUtilListAdd (void *list, void *key, void *user_data) +{ + ListData *data; + int list_flag; + + XDBG_RETURN_VAL_IF_FAIL (key != NULL, NULL); + + if (!list) + { + list = calloc (sizeof (struct xorg_list), 1); + XDBG_RETURN_VAL_IF_FAIL (list != NULL, NULL); + xorg_list_init ((struct xorg_list*)list); + list_flag = 1; + } + + if (_secUtilListGet (list, key)) + return list; + + data = malloc (sizeof (ListData)); + XDBG_GOTO_IF_FAIL (data != NULL, fail); + data->key = key; + data->data = user_data; + + xorg_list_add (&data->link, (struct xorg_list*)list); + + return list; + +fail: + if (list_flag && list) + free (list); + + return NULL; +} + +void* +secUtilListRemove (void *list, void *key) +{ + ListData *data; + + XDBG_RETURN_VAL_IF_FAIL (key != NULL, NULL); + + data = _secUtilListGet (list, key); + if (data) + { + xorg_list_del (&data->link); + free (data); + + if (xorg_list_is_empty ((struct xorg_list*)list)) + { + free (list); + return NULL; + } + } + + return list; +} + +void* +secUtilListGetData (void *list, void *key) +{ + ListData *data; + + XDBG_RETURN_VAL_IF_FAIL (key != NULL, NULL); + + data = _secUtilListGet (list, key); + if (data) + return data->data; + + return NULL; +} + +Bool +secUtilListIsEmpty (void *list) +{ + if (!list) + return FALSE; + + return xorg_list_is_empty ((struct xorg_list*)list); +} + +void +secUtilListDestroyData (void *list, DestroyDataFunc func, void *func_data) +{ + ListData *cur = NULL, *next = NULL; + struct xorg_list *l; + + if (!list || !func) + return; + + l = (struct xorg_list*)list; + xorg_list_for_each_entry_safe (cur, next, l, link) + { + func (func_data, cur->data); + } +} + +void +secUtilListDestroy (void *list) +{ + ListData *data = NULL, *next = NULL; + struct xorg_list *l; + + if (!list) + return; + + l = (struct xorg_list*)list; + xorg_list_for_each_entry_safe (data, next, l, link) + { + xorg_list_del (&data->link); + free (data); + } + + free (list); +} + +Bool +secUtilSetDrmProperty (SECModePtr pSecMode, unsigned int obj_id, unsigned int obj_type, + const char *prop_name, unsigned int value) +{ + drmModeObjectPropertiesPtr props; + unsigned int i; + + XDBG_RETURN_VAL_IF_FAIL (pSecMode != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (obj_id > 0, FALSE); + XDBG_RETURN_VAL_IF_FAIL (obj_type > 0, FALSE); + XDBG_RETURN_VAL_IF_FAIL (prop_name != NULL, FALSE); + + props = drmModeObjectGetProperties (pSecMode->fd, obj_id, obj_type); + if (!props) + { + XDBG_ERRNO (MPLN, "fail : drmModeObjectGetProperties.\n"); + return FALSE; + } + + for (i = 0; i < props->count_props; i++) + { + drmModePropertyPtr prop = drmModeGetProperty (pSecMode->fd, props->props[i]); + int ret; + + if (!prop) + { + XDBG_ERRNO (MPLN, "fail : drmModeGetProperty.\n"); + drmModeFreeObjectProperties (props); + return FALSE; + } + + if (!strcmp (prop->name, prop_name)) + { + ret = drmModeObjectSetProperty (pSecMode->fd, obj_id, obj_type, prop->prop_id, value); + if (ret < 0) + { + XDBG_ERRNO (MPLN, "fail : drmModeObjectSetProperty.\n"); + drmModeFreeProperty(prop); + drmModeFreeObjectProperties (props); + return FALSE; + } + + drmModeFreeProperty(prop); + drmModeFreeObjectProperties (props); + + return TRUE; + } + + drmModeFreeProperty(prop); + } + + XDBG_ERROR (MPLN, "fail : drm set property.\n"); + + drmModeFreeObjectProperties (props); + + return FALSE; +} + +Bool +secUtilEnsureExternalCrtc (ScrnInfoPtr scrn) +{ + SECModePtr pSecMode; + SECOutputPrivPtr pOutputPriv = NULL; + + XDBG_RETURN_VAL_IF_FAIL (scrn != NULL, FALSE); + + pSecMode = (SECModePtr) SECPTR (scrn)->pSecMode; + + if (pSecMode->conn_mode == DISPLAY_CONN_MODE_HDMI) + { + pOutputPriv = secOutputGetPrivateForConnType (scrn, DRM_MODE_CONNECTOR_HDMIA); + if (!pOutputPriv) + pOutputPriv = secOutputGetPrivateForConnType (scrn, DRM_MODE_CONNECTOR_HDMIB); + } + else + pOutputPriv = secOutputGetPrivateForConnType (scrn, DRM_MODE_CONNECTOR_VIRTUAL); + + XDBG_RETURN_VAL_IF_FAIL (pOutputPriv != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (pOutputPriv->mode_encoder != NULL, FALSE); + + if (pOutputPriv->mode_encoder->crtc_id > 0) + return TRUE; + + secDisplayDeinitDispMode (scrn); + + return secDisplayInitDispMode (scrn, pSecMode->conn_mode); +} + +typedef struct _VBufFreeFuncInfo +{ + FreeVideoBufFunc func; + void *data; + struct xorg_list link; +} VBufFreeFuncInfo; + +static SECFormatTable format_table[] = +{ + { FOURCC_RGB565, DRM_FORMAT_RGB565, TYPE_RGB }, + { FOURCC_SR16, DRM_FORMAT_RGB565, TYPE_RGB }, + { FOURCC_RGB32, DRM_FORMAT_XRGB8888, TYPE_RGB }, + { FOURCC_SR32, DRM_FORMAT_XRGB8888, TYPE_RGB }, + { FOURCC_YV12, DRM_FORMAT_YVU420, TYPE_YUV420 }, + { FOURCC_I420, DRM_FORMAT_YUV420, TYPE_YUV420 }, + { FOURCC_S420, DRM_FORMAT_YUV420, TYPE_YUV420 }, + { FOURCC_ST12, DRM_FORMAT_NV12MT, TYPE_YUV420 }, + { FOURCC_SN12, DRM_FORMAT_NV12, TYPE_YUV420 }, + { FOURCC_NV12, DRM_FORMAT_NV12, TYPE_YUV420 }, + { FOURCC_SN21, DRM_FORMAT_NV21, TYPE_YUV420 }, + { FOURCC_NV21, DRM_FORMAT_NV21, TYPE_YUV420 }, + { FOURCC_YUY2, DRM_FORMAT_YUYV, TYPE_YUV422 }, + { FOURCC_SUYV, DRM_FORMAT_YUYV, TYPE_YUV422 }, + { FOURCC_UYVY, DRM_FORMAT_UYVY, TYPE_YUV422 }, + { FOURCC_SYVY, DRM_FORMAT_UYVY, TYPE_YUV422 }, + { FOURCC_ITLV, DRM_FORMAT_UYVY, TYPE_YUV422 }, +}; + +static struct xorg_list vbuf_lists; + +#define VBUF_RETURN_IF_FAIL(cond) \ + {if (!(cond)) { XDBG_ERROR (MVBUF, "[%s] : '%s' failed. (%s)\n", __FUNCTION__, #cond, func); return; }} +#define VBUF_RETURN_VAL_IF_FAIL(cond, val) \ + {if (!(cond)) { XDBG_ERROR (MVBUF, "[%s] : '%s' failed. (%s)\n", __FUNCTION__, #cond, func); return val; }} + +static void +_secUtilInitVbuf (void) +{ + static Bool init = FALSE; + if (!init) + { + xorg_list_init (&vbuf_lists); + init = TRUE; + } +} + +static void +_secUtilYUV420BlackFrame (unsigned char *buf, int buf_size, int width, int height) +{ + int i; + int y_len = 0; + int yuv_len = 0; + + y_len = width * height; + yuv_len = (width * height * 3) >> 1; + + if (buf_size < yuv_len) + return; + + if (width % 4) + { + for (i = 0 ; i < y_len ; i++) + buf[i] = 0x10; + + for ( ; i < yuv_len ; i++) + buf[i] = 0x80; + } + else + { + /* faster way */ + int *ibuf = NULL; + short *sbuf = NULL; + ibuf = (int *)buf; + + for (i = 0 ; i < y_len / 4 ; i++) + ibuf[i] = 0x10101010; /* set YYYY */ + + sbuf = (short*)(&buf[y_len]); + + for (i = 0 ; i < (yuv_len - y_len) / 2 ; i++) + sbuf[i] = 0x8080; /* set UV */ + } + + return; +} + +static void +_secUtilYUV422BlackFrame (int id, unsigned char *buf, int buf_size, int width, int height) +{ + /* YUYV */ + int i; + int yuv_len = 0; + int *ibuf = NULL; + + ibuf = (int *)buf; + + yuv_len = (width * height * 2); + + if (buf_size < yuv_len) + return; + + for (i = 0 ; i < yuv_len / 4 ; i++) + if (id == FOURCC_UYVY || id == FOURCC_SYVY || id == FOURCC_ITLV) + ibuf[i] = 0x80108010; /* YUYV -> 0xVYUY */ + else + ibuf[i] = 0x10801080; /* YUYV -> 0xVYUY */ + + return; +} + +static tbm_bo +_secUtilAllocNormalBuffer (ScrnInfoPtr scrn, int size, int flags) +{ + SECPtr pSec = SECPTR (scrn); + + return tbm_bo_alloc (pSec->tbm_bufmgr, size, flags); +} + +static tbm_bo +_secUtilAllocSecureBuffer (ScrnInfoPtr scrn, int size, int flags) +{ + SECPtr pSec = SECPTR (scrn); + struct tzmem_get_region tzmem_get = {0,}; + struct drm_prime_handle arg_handle = {0,}; + struct drm_gem_flink arg_flink = {0,}; + struct drm_gem_close arg_close = {0,}; + tbm_bo bo = NULL; + int tzmem_fd; + + tzmem_fd = -1; + tzmem_get.fd = -1; + + tzmem_fd = open ("/dev/tzmem", O_EXCL); + XDBG_GOTO_IF_FAIL (tzmem_fd >= 0, done_secure_buffer); + + tzmem_get.key = "fimc"; + tzmem_get.size = size; + if (ioctl (tzmem_fd, TZMEM_IOC_GET_TZMEM, &tzmem_get)) + { + XDBG_ERRNO (MVBUF, "failed : create tzmem (%d)\n", size); + goto done_secure_buffer; + } + XDBG_GOTO_IF_FAIL (tzmem_get.fd >= 0, done_secure_buffer); + + arg_handle.fd = (__s32)tzmem_get.fd; + if (drmIoctl (pSec->drm_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &arg_handle)) + { + XDBG_ERRNO (MVBUF, "failed : convert to gem (%d)\n", tzmem_get.fd); + goto done_secure_buffer; + } + XDBG_GOTO_IF_FAIL (arg_handle.handle > 0, done_secure_buffer); + + arg_flink.handle = arg_handle.handle; + if (drmIoctl (pSec->drm_fd, DRM_IOCTL_GEM_FLINK, &arg_flink)) + { + XDBG_ERRNO (MVBUF, "failed : flink gem (%ld)\n", arg_handle.handle); + goto done_secure_buffer; + } + XDBG_GOTO_IF_FAIL (arg_flink.name > 0, done_secure_buffer); + + bo = tbm_bo_import (pSec->tbm_bufmgr, arg_flink.name); + XDBG_GOTO_IF_FAIL (bo != NULL, done_secure_buffer); + +done_secure_buffer: + if (arg_handle.handle > 0) + { + arg_close.handle = arg_handle.handle; + if (drmIoctl (pSec->drm_fd, DRM_IOCTL_GEM_CLOSE, &arg_close)) + XDBG_ERRNO (MVBUF, "failed : close gem (%ld)\n", arg_handle.handle); + } + + if (tzmem_get.fd >= 0) + close (tzmem_get.fd); + + if (tzmem_fd >= 0) + close (tzmem_fd); + + return bo; +} + +/* + * # planar # + * format: YV12 Y/V/U 420 + * format: I420 Y/U/V 420 #YU12, S420 + * format: NV12 Y/UV 420 + * format: NV12M Y/UV 420 #SN12 + * format: NV12MT Y/UV 420 #ST12 + * format: NV21 Y/VU 420 + * format: Y444 YUV 444 + * # packed # + * format: YUY2 YUYV 422 #YUYV, SUYV, SUY2 + * format: YVYU YVYU 422 + * format: UYVY UYVY 422 #SYVY + */ +G2dColorMode +secUtilGetG2dFormat (unsigned int id) +{ + G2dColorMode g2dfmt = 0; + + switch (id) + { + case FOURCC_NV12: + case FOURCC_SN12: + g2dfmt = G2D_COLOR_FMT_YCbCr420 | G2D_YCbCr_2PLANE | G2D_YCbCr_ORDER_CrCb; + break; + case FOURCC_NV21: + case FOURCC_SN21: + g2dfmt = G2D_COLOR_FMT_YCbCr420 | G2D_YCbCr_2PLANE | G2D_YCbCr_ORDER_CbCr; + break; + case FOURCC_SUYV: + case FOURCC_YUY2: + g2dfmt = G2D_COLOR_FMT_YCbCr422 | G2D_YCbCr_ORDER_Y1CbY0Cr; + break; + case FOURCC_SYVY: + case FOURCC_UYVY: + g2dfmt = G2D_COLOR_FMT_YCbCr422 | G2D_YCbCr_ORDER_CbY1CrY0; + break; + case FOURCC_SR16: + case FOURCC_RGB565: + g2dfmt = G2D_COLOR_FMT_RGB565 | G2D_ORDER_AXRGB; + break; + case FOURCC_SR32: + case FOURCC_RGB32: + g2dfmt = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + break; + case FOURCC_YV12: + case FOURCC_I420: + case FOURCC_S420: + case FOURCC_ITLV: + case FOURCC_ST12: + default: + XDBG_NEVER_GET_HERE (MVA); + return 0; + } + + return g2dfmt; +} + +unsigned int +secUtilGetDrmFormat (unsigned int id) +{ + int i, size; + + size = sizeof (format_table) / sizeof (SECFormatTable); + + for (i = 0; i < size; i++) + if (format_table[i].id == id) + return format_table[i].drmfmt; + + return 0; +} + +SECFormatType +secUtilGetColorType (unsigned int id) +{ + int i, size; + + size = sizeof (format_table) / sizeof (SECFormatTable); + + for (i = 0; i < size; i++) + if (format_table[i].id == id) + return format_table[i].type; + + return TYPE_NONE; +} + +static SECVideoBuf* +_findVideoBuffer (CARD32 stamp) +{ + SECVideoBuf *cur = NULL, *next = NULL; + + _secUtilInitVbuf (); + + if (!vbuf_lists.next) + return NULL; + + xorg_list_for_each_entry_safe (cur, next, &vbuf_lists, valid_link) + { + if (cur->stamp == stamp) + return cur; + } + + return NULL; +} + +SECVideoBuf* +_secUtilAllocVideoBuffer (ScrnInfoPtr scrn, int id, int width, int height, + Bool scanout, Bool reset, Bool secure, const char *func) +{ + SECPtr pSec = SECPTR (scrn); + SECVideoBuf *vbuf = NULL; + int flags = 0; + int i; + tbm_bo_handle bo_handle; + CARD32 stamp; + + XDBG_RETURN_VAL_IF_FAIL (scrn != NULL, NULL); + XDBG_RETURN_VAL_IF_FAIL (id > 0, NULL); + XDBG_RETURN_VAL_IF_FAIL (width > 0, NULL); + XDBG_RETURN_VAL_IF_FAIL (height > 0, NULL); + + vbuf = calloc (1, sizeof (SECVideoBuf)); + XDBG_GOTO_IF_FAIL (vbuf != NULL, alloc_fail); + + vbuf->ref_cnt = 1; + + vbuf->pScrn = scrn; + vbuf->id = id; + vbuf->width = width; + vbuf->height = height; + vbuf->crop.width = width; + vbuf->crop.height = height; + + vbuf->size = secVideoQueryImageAttrs (scrn, id, &width, &height, + vbuf->pitches, vbuf->offsets, vbuf->lengths); + XDBG_GOTO_IF_FAIL (vbuf->size > 0, alloc_fail); + + for (i = 0; i < PLANAR_CNT; i++) + { + int alloc_size = 0; + + if (id == FOURCC_SN12 || id == FOURCC_SN21 || id == FOURCC_ST12) + alloc_size = vbuf->lengths[i]; + else if (i == 0) + alloc_size = vbuf->size; + + if (alloc_size <= 0) + continue; + + /* if i > 1, do check. */ + if (id == FOURCC_SN12 || id == FOURCC_SN21 || id == FOURCC_ST12) + { + XDBG_GOTO_IF_FAIL (i <= 1, alloc_fail); + } + else + XDBG_GOTO_IF_FAIL (i == 0, alloc_fail); + + if (scanout) + flags = TBM_BO_SCANOUT|TBM_BO_WC; + else if (!pSec->cachable) + flags = TBM_BO_WC; + else + flags = TBM_BO_DEFAULT; + + if (!secure) + vbuf->bo[i] = _secUtilAllocNormalBuffer (scrn, alloc_size, flags); + else + vbuf->bo[i] = _secUtilAllocSecureBuffer (scrn, alloc_size, flags); + XDBG_GOTO_IF_FAIL (vbuf->bo[i] != NULL, alloc_fail); + + vbuf->keys[i] = tbm_bo_export (vbuf->bo[i]); + XDBG_GOTO_IF_FAIL (vbuf->keys[i] > 0, alloc_fail); + + bo_handle = tbm_bo_get_handle (vbuf->bo[i], TBM_DEVICE_DEFAULT); + vbuf->handles[i] = bo_handle.u32; + XDBG_GOTO_IF_FAIL (vbuf->handles[i] > 0, alloc_fail); + + if (scanout) + secUtilConvertHandle (scrn, vbuf->handles[i], &vbuf->phy_addrs[i], NULL); + + XDBG_DEBUG (MVBUF, "handle(%d) => phy_addrs(%d) \n", vbuf->handles[i], vbuf->phy_addrs[i]); + } + + if (reset) + secUtilClearVideoBuffer (vbuf); + + vbuf->secure = secure; + vbuf->dirty = TRUE; + + xorg_list_init (&vbuf->convert_info); + xorg_list_init (&vbuf->free_funcs); + + _secUtilInitVbuf (); + xorg_list_add (&vbuf->valid_link, &vbuf_lists); + + stamp = GetTimeInMillis (); + while (_findVideoBuffer (stamp)) + stamp++; + vbuf->stamp = stamp; + + vbuf->func = strdup (func); + vbuf->flags = flags; + vbuf->scanout = scanout; + + XDBG_DEBUG (MVBUF, "%ld alloc(flags:%x, scanout:%d): %s\n", vbuf->stamp, flags, scanout, func); + + return vbuf; + +alloc_fail: + if (vbuf) + { + for (i = 0; i < PLANAR_CNT && vbuf->bo[i]; i++) + tbm_bo_unref (vbuf->bo[i]); + + free (vbuf); + } + + return NULL; +} + +SECVideoBuf* +_secUtilCreateVideoBuffer (ScrnInfoPtr scrn, int id, int width, int height, Bool secure, const char *func) +{ + SECVideoBuf *vbuf = NULL; + CARD32 stamp; + + XDBG_RETURN_VAL_IF_FAIL (scrn != NULL, NULL); + XDBG_RETURN_VAL_IF_FAIL (id > 0, NULL); + XDBG_RETURN_VAL_IF_FAIL (width > 0, NULL); + XDBG_RETURN_VAL_IF_FAIL (height > 0, NULL); + + vbuf = calloc (1, sizeof (SECVideoBuf)); + XDBG_GOTO_IF_FAIL (vbuf != NULL, alloc_fail); + + vbuf->ref_cnt = 1; + + vbuf->pScrn = scrn; + vbuf->id = id; + vbuf->width = width; + vbuf->height = height; + vbuf->crop.width = width; + vbuf->crop.height = height; + + vbuf->size = secVideoQueryImageAttrs (scrn, id, &width, &height, + vbuf->pitches, vbuf->offsets, vbuf->lengths); + XDBG_GOTO_IF_FAIL (vbuf->size > 0, alloc_fail); + + vbuf->secure = secure; + + xorg_list_init (&vbuf->convert_info); + xorg_list_init (&vbuf->free_funcs); + + _secUtilInitVbuf (); + xorg_list_add (&vbuf->valid_link, &vbuf_lists); + + stamp = GetTimeInMillis (); + while (_findVideoBuffer (stamp)) + stamp++; + vbuf->stamp = stamp; + + vbuf->func = strdup (func); + vbuf->flags = -1; + + XDBG_DEBUG (MVBUF, "%ld create: %s\n", vbuf->stamp, func); + + return vbuf; + +alloc_fail: + if (vbuf) + secUtilFreeVideoBuffer (vbuf); + + return NULL; +} + +SECVideoBuf* +secUtilVideoBufferRef (SECVideoBuf *vbuf) +{ + if (!vbuf) + return NULL; + + XDBG_RETURN_VAL_IF_FAIL (VBUF_IS_VALID (vbuf), NULL); + + vbuf->ref_cnt++; + + return vbuf; +} + +void +_secUtilVideoBufferUnref (SECVideoBuf *vbuf, const char *func) +{ + if (!vbuf) + return; + + VBUF_RETURN_IF_FAIL (_secUtilIsVbufValid (vbuf, func)); + + vbuf->ref_cnt--; + if (vbuf->ref_cnt == 0) + _secUtilFreeVideoBuffer (vbuf, func); +} + +void +_secUtilFreeVideoBuffer (SECVideoBuf *vbuf, const char *func) +{ + VBufFreeFuncInfo *cur = NULL, *next = NULL; + int i; + + if (!vbuf) + return; + + VBUF_RETURN_IF_FAIL (_secUtilIsVbufValid (vbuf, func)); + VBUF_RETURN_IF_FAIL (!VBUF_IS_CONVERTING (vbuf)); + VBUF_RETURN_IF_FAIL (vbuf->showing == FALSE); + + xorg_list_for_each_entry_safe (cur, next, &vbuf->free_funcs, link) + { + /* call before tmb_bo_unref and drmModeRmFB. */ + if (cur->func) + cur->func (vbuf, cur->data); + xorg_list_del (&cur->link); + free (cur); + } + + for (i = 0; i < PLANAR_CNT; i++) + { + if (vbuf->bo[i]) + tbm_bo_unref (vbuf->bo[i]); + } + + if (vbuf->fb_id > 0) + { + XDBG_DEBUG (MVBUF, "vbuf(%ld) fb_id(%d) removed. \n", vbuf->stamp, vbuf->fb_id); + drmModeRmFB (SECPTR(vbuf->pScrn)->drm_fd, vbuf->fb_id); + } + + xorg_list_del (&vbuf->valid_link); + + XDBG_DEBUG (MVBUF, "%ld freed: %s\n", vbuf->stamp, func); + + vbuf->stamp = 0; + + if (vbuf->func) + free (vbuf->func); + + free (vbuf); +} + +static void +_secUtilClearNormalVideoBuffer (SECVideoBuf *vbuf) +{ + int i; + tbm_bo_handle bo_handle; + + if (!vbuf) + return; + + for (i = 0; i < PLANAR_CNT; i++) + { + int size = 0; + + if (vbuf->id == FOURCC_SN12 || vbuf->id == FOURCC_SN21 || vbuf->id == FOURCC_ST12) + size = vbuf->lengths[i]; + else if (i == 0) + size = vbuf->size; + + if (size <= 0 || !vbuf->bo[i]) + continue; + + bo_handle = tbm_bo_map (vbuf->bo[i], TBM_DEVICE_CPU, TBM_OPTION_WRITE); + XDBG_RETURN_IF_FAIL (bo_handle.ptr != NULL); + + if (vbuf->id == FOURCC_SN12 || vbuf->id == FOURCC_SN21 || vbuf->id == FOURCC_ST12) + { + if (i == 0) + memset (bo_handle.ptr, 0x10, size); + else if (i == 1) + memset (bo_handle.ptr, 0x80, size); + } + else + { + int type = secUtilGetColorType (vbuf->id); + + if (type == TYPE_YUV420) + _secUtilYUV420BlackFrame (bo_handle.ptr, size, vbuf->width, vbuf->height); + else if (type == TYPE_YUV422) + _secUtilYUV422BlackFrame (vbuf->id, bo_handle.ptr, size, vbuf->width, vbuf->height); + else if (type == TYPE_RGB) + memset (bo_handle.ptr, 0, size); + else + XDBG_NEVER_GET_HERE (MSEC); + } + + tbm_bo_unmap (vbuf->bo[i]); + } + + secUtilCacheFlush (vbuf->pScrn); +} + +static void +_secUtilClearSecureVideoBuffer (SECVideoBuf *vbuf) +{ +} + +void +secUtilClearVideoBuffer (SECVideoBuf *vbuf) +{ + if (!vbuf) + return; + + if (!vbuf->secure) + _secUtilClearNormalVideoBuffer (vbuf); + else + _secUtilClearSecureVideoBuffer (vbuf); + + vbuf->dirty = FALSE; + vbuf->need_reset = FALSE; +} + +Bool +_secUtilIsVbufValid (SECVideoBuf *vbuf, const char *func) +{ + SECVideoBuf *cur = NULL, *next = NULL; + + _secUtilInitVbuf (); + + VBUF_RETURN_VAL_IF_FAIL (vbuf != NULL, FALSE); + VBUF_RETURN_VAL_IF_FAIL (vbuf->stamp != 0, FALSE); + + xorg_list_for_each_entry_safe (cur, next, &vbuf_lists, valid_link) + { + if (cur->stamp == vbuf->stamp) + return TRUE; + } + + return FALSE; +} + +static VBufFreeFuncInfo* +_secUtilFindFreeVideoBufferFunc (SECVideoBuf *vbuf, FreeVideoBufFunc func, void *data) +{ + VBufFreeFuncInfo *cur = NULL, *next = NULL; + + xorg_list_for_each_entry_safe (cur, next, &vbuf->free_funcs, link) + { + if (cur->func == func && cur->data == data) + return cur; + } + + return NULL; +} + +void +secUtilAddFreeVideoBufferFunc (SECVideoBuf *vbuf, FreeVideoBufFunc func, void *data) +{ + VBufFreeFuncInfo *info; + + XDBG_RETURN_IF_FAIL (VBUF_IS_VALID (vbuf)); + XDBG_RETURN_IF_FAIL (func != NULL); + + info = _secUtilFindFreeVideoBufferFunc (vbuf, func, data); + if (info) + return; + + info = calloc (1, sizeof (VBufFreeFuncInfo)); + XDBG_RETURN_IF_FAIL (info != NULL); + + info->func = func; + info->data = data; + + xorg_list_add (&info->link, &vbuf->free_funcs); +} + +void +secUtilRemoveFreeVideoBufferFunc (SECVideoBuf *vbuf, FreeVideoBufFunc func, void *data) +{ + VBufFreeFuncInfo *info; + + XDBG_RETURN_IF_FAIL (VBUF_IS_VALID (vbuf)); + XDBG_RETURN_IF_FAIL (func != NULL); + + info = _secUtilFindFreeVideoBufferFunc (vbuf, func, data); + if (!info) + return; + + xorg_list_del (&info->link); + + free (info); +} + +char* +secUtilDumpVideoBuffer (char *reply, int *len) +{ + SECVideoBuf *cur = NULL, *next = NULL; + + _secUtilInitVbuf (); + + if (xorg_list_is_empty (&vbuf_lists)) + return reply; + + XDBG_REPLY ("\nVideo buffers:\n"); + XDBG_REPLY ("id\tsize\t\t\tformat\tflags\trefcnt\tsecure\tstamp\tfunc\n"); + + xorg_list_for_each_entry_safe (cur, next, &vbuf_lists, valid_link) + { + XDBG_REPLY ("%d\t(%dx%d,%d)\t%c%c%c%c\t%d\t%d\t%d\t%ld\t%s\n", + cur->fb_id, cur->width, cur->height, cur->size, + FOURCC_STR (cur->id), + cur->flags, cur->ref_cnt, cur->secure, cur->stamp, cur->func); + } + + return reply; +} + |