diff options
author | jk7744.park <jk7744.park@samsung.com> | 2015-09-08 21:31:07 +0900 |
---|---|---|
committer | jk7744.park <jk7744.park@samsung.com> | 2015-09-08 21:31:07 +0900 |
commit | cb41fec8f453fd5dc9fb1d4a92a6d49f043578fc (patch) | |
tree | 5bc62f2394f8b418b20ea103b5afdac3d1427b0b /src | |
parent | dd7d4f2aa2cf93ded1e89c1cb1770654e5f9c1e6 (diff) | |
download | xserver-xorg-video-exynos-tizen_2.3.1.tar.gz xserver-xorg-video-exynos-tizen_2.3.1.tar.bz2 xserver-xorg-video-exynos-tizen_2.3.1.zip |
tizen 2.3.1 releasetizen_2.3.1_releasesubmit/tizen_2.3.1/20150915.072325tizen_2.3.1
Diffstat (limited to 'src')
52 files changed, 36298 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100755 index 0000000..e293a9a --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,71 @@ +AM_CFLAGS = -I@top_srcdir@/src @XORG_CFLAGS@ @EXYNOS_CFLAGS@ +exynos_drv_la_LTLIBRARIES = exynos_drv.la +#exynos_drv_la_LDFLAGS = -module -avoid-version @EXYNOS_LIBS@ +exynos_drv_la_LDFLAGS = -module -avoid-version +exynos_drv_la_LIBADD = @EXYNOS_LIBS@ +exynos_drv_ladir = @moduledir@/drivers + +# common +exynos_drv_la_SOURCES = \ + sec.c + +# crtcconfig +exynos_drv_la_SOURCES += \ + crtcconfig/sec_crtc.c \ + crtcconfig/sec_output.c \ + crtcconfig/sec_plane.c \ + crtcconfig/sec_layer.c \ + crtcconfig/sec_prop.c \ + crtcconfig/sec_xberc.c \ + crtcconfig/sec_display.c +AM_CFLAGS += -I@top_srcdir@/src/crtcconfig + +# accel +exynos_drv_la_SOURCES += \ + accel/sec_exa.c \ + accel/sec_exa_sw.c \ + accel/sec_dri2.c +AM_CFLAGS += -I@top_srcdir@/src/accel + +# xv +exynos_drv_la_SOURCES += \ + xv/sec_video_tvout.c \ + xv/sec_video_virtual.c \ + xv/sec_video_display.c \ + xv/sec_video.c +AM_CFLAGS += -I@top_srcdir@/src/xv + +# util +exynos_drv_la_SOURCES += \ + util/sec_util.c +AM_CFLAGS += -I@top_srcdir@/src/util + +# debug +exynos_drv_la_SOURCES += \ + debug/sec_drmmode_dump.c +AM_CFLAGS += -I@top_srcdir@/src/debug + +# memory flush +#exynos_drv_la_SOURCES += \ +# memory/sec_memory_flush.c +#AM_CFLAGS += -I@top_srcdir@/src/memory + +# neon +exynos_drv_la_SOURCES += \ + neon/memcpy_neon.s \ + neon/copy_area.c +AM_CFLAGS += -I@top_srcdir@/src/neon + +# ipp +exynos_drv_la_SOURCES += \ + ipp/sec_drm_ipp.c \ + ipp/sec_converter.c \ + ipp/sec_wb.c +AM_CFLAGS += -I@top_srcdir@/src/ipp + +# g2d +exynos_drv_la_SOURCES += \ + accel/sec_exa_g2d.c \ + g2d/fimg2d.c \ + g2d/util_g2d.c +AM_CFLAGS += -I@top_srcdir@/src/g2d diff --git a/src/accel/sec_accel.h b/src/accel/sec_accel.h new file mode 100755 index 0000000..f9808a3 --- /dev/null +++ b/src/accel/sec_accel.h @@ -0,0 +1,155 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@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. + +**************************************************************************/ + +#ifndef _SEC_ACCEL_H_ +#define _SEC_ACCEL_H_ 1 + +#include <exa.h> +#include <dri2.h> +#include <list.h> +#include <picture.h> +#include <xf86drm.h> +#include <tbm_bufmgr.h> +#include <damage.h> + +#include "sec_layer.h" + +/* exa driver private infomation */ +typedef struct _secExaPriv SECExaPriv, *SECExaPrivPtr; +#define SECEXAPTR(p) ((SECExaPrivPtr)((p)->pExaPriv)) + +/* pixmap usage hint */ +#define CREATE_PIXMAP_USAGE_DRI2_FLIP_BACK 0x100 +#define CREATE_PIXMAP_USAGE_FB 0x101 +#define CREATE_PIXMAP_USAGE_SUB_FB 0x202 +#define CREATE_PIXMAP_USAGE_DRI2_BACK 0x404 +#define CREATE_PIXMAP_USAGE_XVIDEO 0x808 + +typedef struct +{ + int usage_hint; + long size; + + /* buffer object */ + tbm_bo bo; + pointer pPixData; /*text glyphs or SHM-PutImage*/ + + int isFrameBuffer; + int isSubFramebuffer; + + SECLayer *ovl_layer; + + /* for exa operation */ + void* exaOpInfo; + + /* dump count */ + int dump_cnt; + + /* Last update SBC */ + XID owner; + CARD64 sbc; +} SECPixmapPriv; + +/* exa driver private infomation */ +struct _secExaPriv +{ + ExaDriverPtr pExaDriver; + + int flip_backbufs; +}; + +/* type of the frame event */ +typedef enum _dri2FrameEventType +{ + DRI2_NONE, + DRI2_SWAP, + DRI2_FLIP, + DRI2_BLIT, + DRI2_FB_BLIT, + DRI2_WAITMSC, +} DRI2FrameEventType; + +/* dri2 frame event information */ +typedef struct _dri2FrameEvent +{ + DRI2FrameEventType type; + XID drawable_id; + unsigned int client_idx; + ClientPtr pClient; + int frame; + + /* for swaps & flips only */ + DRI2SwapEventPtr event_complete; + void *event_data; + DRI2BufferPtr pFrontBuf; + DRI2BufferPtr pBackBuf; + + /* pending flip event */ + int crtc_pipe; + void *pCrtc; + struct _dri2FrameEvent *pPendingEvent; + struct xorg_list crtc_pending_link; + + /* for SwapRegion */ + RegionPtr pRegion; +} DRI2FrameEventRec, *DRI2FrameEventPtr; + +/************************************************************************** + * EXA + **************************************************************************/ +/* EXA */ +Bool secExaInit (ScreenPtr pScreen); +void secExaDeinit (ScreenPtr pScreen); +Bool secExaPrepareAccess (PixmapPtr pPix, int index); +void secExaFinishAccess (PixmapPtr pPix, int index); +Bool secExaMigratePixmap (PixmapPtr pPix, tbm_bo bo); +void secExaScreenCountFps (ScreenPtr pScreen); /* count fps */ +void secExaScreenLock (ScreenPtr pScreen, int enable); +int secExaScreenAsyncSwap (ScreenPtr pScreen, int enable); +int secExaScreenSetScrnPixmap (ScreenPtr pScreen); +tbm_bo secExaPixmapGetBo (PixmapPtr pPix); + +/* sw EXA */ +Bool secExaSwInit (ScreenPtr pScreen, ExaDriverPtr pExaDriver); +void secExaSwDeinit (ScreenPtr pScreen); +Bool secExaG2dInit (ScreenPtr pScreen, ExaDriverPtr pExaDriver); +void secExaG2dDeinit (ScreenPtr pScreen); + + +/************************************************************************** + * DRI2 + **************************************************************************/ +/* DRI2 */ +Bool secDri2Init (ScreenPtr pScreen); +void secDri2Deinit (ScreenPtr pScreen); +void secDri2FrameEventHandler (unsigned int frame, unsigned int tv_sec, unsigned int tv_usec, void *event_data); +void secDri2FlipEventHandler (unsigned int frame, unsigned int tv_sec, unsigned int tv_usec, void *event_data, Bool flip_failed); + +#endif /* _SEC_ACCEL_H_ */ diff --git a/src/accel/sec_dri2.c b/src/accel/sec_dri2.c new file mode 100755 index 0000000..1808979 --- /dev/null +++ b/src/accel/sec_dri2.c @@ -0,0 +1,1991 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2001 VA Linux Systems Inc., Fremont, California. +Copyright © 2002 by David Dawes +Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@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. + +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/time.h> +#include <time.h> +#include <errno.h> +#include <poll.h> + +#include "X11/Xatom.h" +#include "xorg-server.h" +#include "xf86.h" +#include "dri2.h" +#include "damage.h" +#include "windowstr.h" +#include "sec.h" +#include "sec_accel.h" +#include "sec_display.h" +#include "sec_crtc.h" +#include "sec_util.h" +#include "sec_crtc.h" +#include "sec_xberc.h" + +#define DRI2_BUFFER_TYPE_WINDOW 0x0 +#define DRI2_BUFFER_TYPE_PIXMAP 0x1 +#define DRI2_BUFFER_TYPE_FB 0x2 + +typedef union{ + unsigned int flags; + struct { + unsigned int type:1; + unsigned int is_framebuffer:1; + unsigned int is_viewable:1; + unsigned int is_reused:1; + unsigned int idx_reuse:3; + }data; +}DRI2BufferFlags; + +#define DRI2_GET_NEXT_IDX(idx, max) (((idx+1) % (max))) + +/* if a window is mapped and realized (viewable) */ +#define IS_VIEWABLE(pDraw) \ + ((pDraw->type == DRAWABLE_PIXMAP)?TRUE:(Bool)(((WindowPtr) pDraw)->viewable)) + +/* dri2 buffer private infomation */ +typedef struct _dri2BufferPriv +{ + int refcnt; + int attachment; + PixmapPtr pPixmap; + ScreenPtr pScreen; + + /* pixmap of the backbuffer */ + int pipe; + Bool canFlip; + int num_buf; + int avail_idx; /* next available index of the back pixmap, -1 means not to be available */ + int cur_idx; /* current index of the back pixmap, -1 means not to be available */ + int free_idx; /* free index of the back pixmap, -1 means not to be available */ + PixmapPtr *pBackPixmaps; + + /* flip buffers */ + ClientPtr pClient; + DRI2FrameEventPtr pFlipEvent; +} DRI2BufferPrivRec, *DRI2BufferPrivPtr; + +/* prototypes */ +static void SECDri2CopyRegion (DrawablePtr pDraw, RegionPtr pRegion, + DRI2BufferPtr pDstBuf, DRI2BufferPtr pSrcBuf); +static void SECDri2DestroyBuffer (DrawablePtr pDraw, DRI2BufferPtr pBuf); + +static PixmapPtr _initBackBufPixmap (DRI2BufferPtr pBackBuf, DrawablePtr pDraw, Bool canFlip); +static void _deinitBackBufPixmap (DRI2BufferPtr pBackBuf, DrawablePtr pDraw, Bool canFlip); +static void _exchangeBackBufPixmap (DRI2BufferPtr pBackBuf); +static PixmapPtr _reuseBackBufPixmap (DRI2BufferPtr pBackBuf, DrawablePtr pDraw, Bool canFlip, int *reues); +static void _disuseBackBufPixmap (DRI2BufferPtr pBackBuf, DRI2FrameEventPtr pEvent); + +static unsigned int +_getName (PixmapPtr pPix) +{ + SECPixmapPriv *pExaPixPriv = NULL; + + if (pPix == NULL) + return 0; + + pExaPixPriv = exaGetPixmapDriverPrivate (pPix); + if (pExaPixPriv == NULL) + return 0; + + if (pExaPixPriv->bo == NULL) + { + if(pExaPixPriv->isFrameBuffer) + return (unsigned int)ROOT_FB_ADDR; + else + return 0; + } + + return tbm_bo_export (pExaPixPriv->bo); +} + +/* initialize the pixmap of the backbuffer */ +static PixmapPtr +_initBackBufPixmap (DRI2BufferPtr pBackBuf, DrawablePtr pDraw, Bool canFlip) +{ + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = SECPTR(pScrn); + SECExaPrivPtr pExaPriv = SECEXAPTR (pSec); + DRI2BufferPrivPtr pBackBufPriv = pBackBuf->driverPrivate; + unsigned int usage_hint = CREATE_PIXMAP_USAGE_DRI2_BACK; + PixmapPtr pPixmap = NULL; + int pipe = -1; + + /* if a drawable can be flip, check whether the flip buffer is available */ + if (canFlip) + { + usage_hint = CREATE_PIXMAP_USAGE_DRI2_FLIP_BACK; + pipe = secDisplayDrawablePipe (pDraw); + if (pipe != -1) + { + /* get the flip pixmap from crtc */ + pPixmap = secCrtcGetFreeFlipPixmap (pScrn, pipe, pDraw, usage_hint); + if (!pPixmap) + { + /* fail to get a flip pixmap from crtc */ + canFlip = FALSE; + XDBG_WARNING(MDRI2, "fail to get a flip pixmap from crtc\n"); + } + } + else + { + /* pipe is -1 */ + canFlip = FALSE; + XDBG_WARNING(MDRI2, "pipe is -1"); + } + } + + /* if canflip is false, get the dri2_back pixmap */ + if (!canFlip) + { + pPixmap = (*pScreen->CreatePixmap) (pScreen, + pDraw->width, + pDraw->height, + pDraw->depth, + usage_hint); + XDBG_RETURN_VAL_IF_FAIL(pPixmap != NULL, NULL); +#if USE_XDBG + xDbgLogPListDrawAddRefPixmap (pDraw, pPixmap); +#endif + } + + if (canFlip) + { + pBackBufPriv->num_buf = pExaPriv->flip_backbufs; + pBackBufPriv->pBackPixmaps = calloc (pBackBufPriv->num_buf, sizeof (void*)); + } + else + { + pBackBufPriv->num_buf = 1; /* num of backbuffer for swap/blit */ + pBackBufPriv->pBackPixmaps = calloc (pBackBufPriv->num_buf, sizeof (void*)); + } + + XDBG_RETURN_VAL_IF_FAIL ((pBackBufPriv->pBackPixmaps != NULL), NULL); + + pBackBufPriv->pBackPixmaps[0] = pPixmap; + pBackBufPriv->canFlip = canFlip; + pBackBufPriv->avail_idx = 0; + pBackBufPriv->free_idx = 0; + pBackBufPriv->cur_idx = 0; + pBackBufPriv->pipe = pipe; + + return pPixmap; +} + +/* deinitialize the pixmap of the backbuffer */ +static void +_deinitBackBufPixmap (DRI2BufferPtr pBackBuf, DrawablePtr pDraw, Bool canFlip) +{ + DRI2BufferPrivPtr pBackBufPriv = pBackBuf->driverPrivate; + ScreenPtr pScreen = pBackBufPriv->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + int i; + int pipe = -1; + + for (i = 0; i < pBackBufPriv->num_buf; i++) + { + if (pBackBufPriv->pBackPixmaps) + { + if(pBackBufPriv->pBackPixmaps[i]) + { + if (canFlip) + { + /* have to release the flip pixmap */ + pipe = pBackBufPriv->pipe; + if (pipe != -1) + secCrtcRelAllFlipPixmap (pScrn, pipe); + else + XDBG_WARNING(MDRI2, "pipe is -1\n"); + } + else + { +#if USE_XDBG + xDbgLogPListDrawRemoveRefPixmap (pDraw, pBackBufPriv->pBackPixmaps[i]); +#endif + (*pScreen->DestroyPixmap) (pBackBufPriv->pBackPixmaps[i]); + } + pBackBufPriv->pBackPixmaps[i] = NULL; + pBackBufPriv->pPixmap = NULL; + } + free(pBackBufPriv->pBackPixmaps); + pBackBufPriv->pBackPixmaps = NULL; + } + } +} + +/* increase the next available index of the backbuffer */ +static void +_exchangeBackBufPixmap (DRI2BufferPtr pBackBuf) +{ + DRI2BufferPrivPtr pBackBufPriv = pBackBuf->driverPrivate; + + /* increase avail_idx when buffers exchange */ + pBackBufPriv->avail_idx = DRI2_GET_NEXT_IDX(pBackBufPriv->avail_idx, pBackBufPriv->num_buf); +} + +/* return the next available pixmap of the backbuffer */ +static PixmapPtr +_reuseBackBufPixmap (DRI2BufferPtr pBackBuf, DrawablePtr pDraw, Bool canFlip, int *reues) +{ + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + DRI2BufferPrivPtr pBackBufPriv = pBackBuf->driverPrivate; + PixmapPtr pPixmap = NULL; + int avail_idx = pBackBufPriv->avail_idx; + unsigned int usage_hint = CREATE_PIXMAP_USAGE_DRI2_BACK; + int pipe = -1; + + if (pBackBufPriv->canFlip != canFlip) + { + /* flip buffer -> swap buffer */ + if (pBackBufPriv->canFlip && !canFlip) + { + /* return the next available pixmap */ + _deinitBackBufPixmap (pBackBuf, pDraw, pBackBufPriv->canFlip); + pPixmap = _initBackBufPixmap(pBackBuf, pDraw, canFlip); + XDBG_RETURN_VAL_IF_FAIL(pPixmap != NULL, NULL); + return pPixmap; + } + + /* swap buffer -> flip buffer */ + if (!pBackBufPriv->canFlip && canFlip) + { + pipe = secDisplayDrawablePipe (pDraw); + if (pipe != -1) + { + /* return the next available pixmap */ + _deinitBackBufPixmap (pBackBuf, pDraw, pBackBufPriv->canFlip); + pPixmap = _initBackBufPixmap(pBackBuf, pDraw, canFlip); + XDBG_RETURN_VAL_IF_FAIL(pPixmap != NULL, NULL); + return pPixmap; + } + else + { + canFlip = FALSE; + XDBG_WARNING (MDRI2, "pipe is -1\n"); + } + } + } + + /* set the next available pixmap */ + /* if pBackPixmap is available, reuse it */ + if (pBackBufPriv->pBackPixmaps[avail_idx]) + { + if (canFlip) + { + usage_hint = CREATE_PIXMAP_USAGE_DRI2_FLIP_BACK; + pipe = secDisplayDrawablePipe (pDraw); + if (pipe != -1) + { + if (avail_idx != pBackBufPriv->cur_idx) + { + /* get the flip pixmap from crtc */ + pBackBufPriv->pBackPixmaps[avail_idx] = secCrtcGetFreeFlipPixmap (pScrn, pipe, pDraw, usage_hint); + if (!pBackBufPriv->pBackPixmaps[avail_idx]) + { + /* fail to get a flip pixmap from crtc */ + XDBG_WARNING(MDRI2, "@@[reuse]: draw(0x%x) fail to get a flip pixmap from crtc to reset the index of pixmap\n", + (unsigned int)pDraw->id); + + _deinitBackBufPixmap (pBackBuf, pDraw, pBackBufPriv->canFlip); + pPixmap = _initBackBufPixmap(pBackBuf, pDraw, FALSE); + XDBG_RETURN_VAL_IF_FAIL(pPixmap != NULL, NULL); + *reues = 0; + return pPixmap; + } + pBackBufPriv->cur_idx = avail_idx; + } + } + else + { + XDBG_WARNING (MDRI2, "pipe is -1(%d)\n", pipe); + return NULL; + } + } + else + { + if (avail_idx != pBackBufPriv->cur_idx) + { + pBackBufPriv->cur_idx = avail_idx; + } + } + + *reues = 1; + } + else + { + if (canFlip) + { + usage_hint = CREATE_PIXMAP_USAGE_DRI2_FLIP_BACK; + pipe = secDisplayDrawablePipe (pDraw); + if (pipe != -1) + { + if (avail_idx != pBackBufPriv->cur_idx) + { + /* get the flip pixmap from crtc */ + pBackBufPriv->pBackPixmaps[avail_idx] = secCrtcGetFreeFlipPixmap (pScrn, pipe, pDraw, usage_hint); + if (!pBackBufPriv->pBackPixmaps[avail_idx]) + { + /* fail to get a flip pixmap from crtc */ + XDBG_WARNING(MDRI2, "@@[initial set]: draw(0x%x) fail to get a flip pixmap from crtc to generate and to set the next available pixmap.\n", + (unsigned int)pDraw->id); + + _deinitBackBufPixmap (pBackBuf, pDraw, TRUE); + pPixmap = _initBackBufPixmap(pBackBuf, pDraw, FALSE); + XDBG_RETURN_VAL_IF_FAIL(pPixmap != NULL, NULL); + *reues = 0; + return pPixmap; + } + pBackBufPriv->cur_idx = avail_idx; + } + } + } + else + { + if (avail_idx != pBackBufPriv->cur_idx) + { + + pBackBufPriv->pBackPixmaps[avail_idx] = (*pScreen->CreatePixmap) (pScreen, + pDraw->width, + pDraw->height, + pDraw->depth, + usage_hint); + XDBG_RETURN_VAL_IF_FAIL(pBackBufPriv->pBackPixmaps[avail_idx] != NULL, NULL); + pBackBufPriv->cur_idx = avail_idx; +#if USE_XDBG + xDbgLogPListDrawAddRefPixmap (pDraw, pPixmap); +#endif + } + } + + *reues = 0; + } + pPixmap = pBackBufPriv->pBackPixmaps[avail_idx]; + + pBackBufPriv->canFlip = canFlip; + + return pPixmap; +} + +static void +_disuseBackBufPixmap (DRI2BufferPtr pBackBuf, DRI2FrameEventPtr pEvent) +{ + DRI2BufferPrivPtr pBackBufPriv = pBackBuf->driverPrivate; + ScreenPtr pScreen = pBackBufPriv->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + if (pEvent->type == DRI2_FLIP) + { + secCrtcRelFlipPixmap (pScrn, pEvent->crtc_pipe, + pBackBufPriv->pBackPixmaps[pBackBufPriv->free_idx]); + + /* increase free_idx when buffers destory or when frame is deleted */ + pBackBufPriv->free_idx = DRI2_GET_NEXT_IDX(pBackBufPriv->free_idx, pBackBufPriv->num_buf); + } +} + +static void +_setDri2Property (DrawablePtr pDraw) +{ + if(pDraw->type == DRAWABLE_WINDOW) + { + static Atom atom_use_dri2= 0; + static int use = 1; + + if(!atom_use_dri2) + { + atom_use_dri2 = MakeAtom ("X_WIN_USE_DRI2", 14, TRUE); + } + + dixChangeWindowProperty (serverClient, + (WindowPtr)pDraw, atom_use_dri2, XA_CARDINAL, 32, + PropModeReplace, 1, &use, TRUE); + } +} + +static unsigned int +_getBufferFlag (DrawablePtr pDraw, Bool canFlip) +{ + DRI2BufferFlags flag; + flag.flags = 0; + + switch (pDraw->type) + { + case DRAWABLE_WINDOW: + flag.data.type = DRI2_BUFFER_TYPE_WINDOW; + break; + case DRAWABLE_PIXMAP: + flag.data.type = DRI2_BUFFER_TYPE_PIXMAP; + break; + } + + if (IS_VIEWABLE(pDraw)) + { + flag.data.is_viewable = 1; + } + + if (canFlip) + { + flag.data.is_framebuffer = 1; + } + + return flag.flags; +} + +static inline PixmapPtr +_getPixmapFromDrawable (DrawablePtr pDraw) +{ + ScreenPtr pScreen = pDraw->pScreen; + PixmapPtr pPix; + + if (pDraw->type == DRAWABLE_WINDOW) + pPix = (*pScreen->GetWindowPixmap) ((WindowPtr) pDraw); + else + pPix = (PixmapPtr) pDraw; + + return pPix; +} + +/* Can this drawable be page flipped? */ +static Bool +_canFlip (DrawablePtr pDraw) +{ + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = SECPTR(pScrn); + WindowPtr pWin, pRoot; + PixmapPtr pWinPixmap, pRootPixmap; + int ret; + + if (pDraw->type == DRAWABLE_PIXMAP) + return FALSE; + + pRoot = pScreen->root; + pRootPixmap = pScreen->GetWindowPixmap (pRoot); + pWin = (WindowPtr) pDraw; + pWinPixmap = pScreen->GetWindowPixmap (pWin); + if (pRootPixmap != pWinPixmap) + return FALSE; + + if (!IS_VIEWABLE(pDraw)) + return FALSE; + + ret = secFbFindBo(pSec->pFb, + pDraw->x, pDraw->y, pDraw->width, pDraw->height, + NULL, NULL); + if (ret != rgnSAME) + return FALSE; + + return TRUE; +} + +static DRI2FrameEventType +_getSwapType (DrawablePtr pDraw, DRI2BufferPtr pFrontBuf, + DRI2BufferPtr pBackBuf) +{ + DRI2BufferPrivPtr pFrontBufPriv; + DRI2BufferPrivPtr pBackBufPriv; + PixmapPtr pFrontPix; + PixmapPtr pBackPix; + SECPixmapPriv *pFrontExaPixPriv = NULL; + SECPixmapPriv *pBackExaPixPriv = NULL; + DRI2FrameEventType swap_type = DRI2_NONE; + + if (!pFrontBuf || !pBackBuf) + return DRI2_NONE; + + /* if a buffer is not viewable at DRI2GetBuffers, return none */ + if (!IS_VIEWABLE(pDraw)) + { + //XDBG_WARNING(MDRI2, "DRI2_NONE: window is not viewable.(%d,%d)\n", pDraw->width, pDraw->height); + return DRI2_NONE; + } + + pFrontBufPriv = pFrontBuf->driverPrivate; + pBackBufPriv = pBackBuf->driverPrivate; + pFrontPix = pFrontBufPriv->pPixmap; + pBackPix = pBackBufPriv->pPixmap; + if (!pFrontPix || !pBackPix) + { + XDBG_WARNING(MDRI2, "Warning: pFrontPix or pBackPix is null.(DRI2_NONE)\n"); + return DRI2_NONE; + } + + pFrontExaPixPriv = exaGetPixmapDriverPrivate (pFrontBufPriv->pPixmap); + pBackExaPixPriv = exaGetPixmapDriverPrivate (pBackBufPriv->pPixmap); + if (!pFrontExaPixPriv || !pBackExaPixPriv) + { + XDBG_WARNING(MDRI2, "Warning: pFrontPixPriv or pBackPixPriv is null.(DRI2_NONE)\n"); + return DRI2_NONE; + } + + + /* Check Exchange */ + if (pFrontBufPriv->canFlip == 1) + { + if(pBackBufPriv->canFlip == 1) + { + swap_type = DRI2_FLIP; + + if (!_canFlip(pDraw)) + { + ErrorF ("@@@ [%10.3f] %lx : flip to blit\n", GetTimeInMillis()/1000.0, pDraw->id); + swap_type = DRI2_BLIT; + } + } + else + { + XDBG_WARNING (MDRI2, "DRI2_FB_BLIT: Front(%d) Back(%d) \n", + pFrontBufPriv->canFlip, pBackBufPriv->canFlip); + swap_type = DRI2_FB_BLIT; + } + } + else + { + if (pFrontExaPixPriv->isFrameBuffer == 1) + { + //XDBG_WARNING (MDRI2, "DRI2_FB_BLIT: Front(%d) Back(%d) : front is framebuffer \n", + // pFrontBufPriv->canFlip, pBackBufPriv->canFlip); + swap_type = DRI2_FB_BLIT; + } + else + { + if (pFrontPix->drawable.width == pBackPix->drawable.width && + pFrontPix->drawable.height == pBackPix->drawable.height && + pFrontPix->drawable.bitsPerPixel == pBackPix->drawable.bitsPerPixel) + { + swap_type = DRI2_SWAP; + } + else + { + swap_type = DRI2_BLIT; + } + } + } + + return swap_type; +} + +static void +_referenceBufferPriv (DRI2BufferPtr pBuf) +{ + if (pBuf) + { + DRI2BufferPrivPtr pBufPriv = pBuf->driverPrivate; + pBufPriv->refcnt++; + } +} + +static void +_unreferenceBufferPriv (DRI2BufferPtr pBuf) +{ + if (pBuf) + { + DRI2BufferPrivPtr pBufPriv = pBuf->driverPrivate; + pBufPriv->refcnt--; + } +} + +static Bool +_resetBufPixmap (DrawablePtr pDraw, DRI2BufferPtr pBuf) +{ + ScreenPtr pScreen = pDraw->pScreen; + DRI2BufferPrivPtr pBufPriv = pBuf->driverPrivate; + PixmapPtr pPix = NULL, pNewPix=NULL, pOldPix=NULL; + Bool canFlip = FALSE; + int reuse = 0; + + canFlip = _canFlip (pDraw); + + if (pBufPriv->attachment == DRI2BufferFrontLeft) + { + pPix = _getPixmapFromDrawable (pDraw); + if (pPix != pBufPriv->pPixmap || + ((DRI2BufferFlags)pBuf->flags).data.is_viewable != IS_VIEWABLE(pDraw)) + { + pOldPix = pBufPriv->pPixmap; + + /* reset the pixmap and the name of the buffer */ + pNewPix = _getPixmapFromDrawable (pDraw); + pPix->refcnt++; + pBufPriv->canFlip = canFlip; + + /* Destroy Old buffer */ + if (pOldPix) + { + (*pScreen->DestroyPixmap) (pOldPix); + } + } + else + { + pBufPriv->canFlip = canFlip; + return FALSE; + } + } + else + { + pNewPix = _reuseBackBufPixmap(pBuf, pDraw, canFlip, &reuse); + if (pNewPix == NULL) + { + XDBG_WARNING (MDRI2, "Error pixmap is null\n", pipe); + return FALSE; + } + + if (reuse) + { + pBufPriv->pPixmap = pNewPix; + return FALSE; + } + } + + pBufPriv->pPixmap = pNewPix; + + pBuf->name = _getName (pNewPix); + pBuf->flags = _getBufferFlag(pDraw, canFlip); + + XDBG_TRACE (MDRI2,"id:0x%x(%d) can_flip:%d attach:%d, name:%d, flags:0x%x geo(%dx%d+%d+%d)\n", + pDraw->id, pDraw->type, + pBufPriv->canFlip, + pBuf->attachment, pBuf->name, pBuf->flags, + pDraw->width, pDraw->height, pDraw->x, pDraw->y); + + return TRUE; +} + +static void +_generateDamage (DrawablePtr pDraw, DRI2FrameEventPtr pFrameEvent) +{ + BoxRec box; + RegionRec region; + + if (pFrameEvent->pRegion) + { + /* translate the regions with drawable */ + BoxPtr pBox = RegionRects(pFrameEvent->pRegion); + int nBox = RegionNumRects(pFrameEvent->pRegion); + + while (nBox--) + { + box.x1 = pBox->x1; + box.y1 = pBox->y1; + box.x2 = pBox->x2; + box.y2 = pBox->y2; + XDBG_DEBUG(MDRI2,"Damage Region[%d]: (x1, y1, x2, y2) = (%d,%d,%d,%d) \n ", + nBox, box.x1, box.x2, box.y1, box.y2); + RegionInit (®ion, &box, 0); + DamageDamageRegion (pDraw, ®ion); + pBox++; + } + } + else + { + + box.x1 = pDraw->x; + box.y1 = pDraw->y; + box.x2 = box.x1 + pDraw->width; + box.y2 = box.y1 + pDraw->height; + RegionInit (®ion, &box, 0); + DamageDamageRegion (pDraw, ®ion); + } +} + +static void +_blitBuffers (DrawablePtr pDraw, DRI2BufferPtr pFrontBuf, DRI2BufferPtr pBackBuf) +{ + BoxRec box; + RegionRec region; + + box.x1 = 0; + box.y1 = 0; + box.x2 = pDraw->width; + box.y2 = pDraw->height; + REGION_INIT (pScreen, ®ion, &box, 0); + + SECDri2CopyRegion (pDraw, ®ion, pFrontBuf, pBackBuf); +} + +static void +_exchangeBuffers (DrawablePtr pDraw, DRI2FrameEventType type, + DRI2BufferPtr pFrontBuf, DRI2BufferPtr pBackBuf) +{ + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = SECPTR (pScrn); + DRI2BufferPrivPtr pFrontBufPriv = pFrontBuf->driverPrivate; + DRI2BufferPrivPtr pBackBufPriv = pBackBuf->driverPrivate; + SECPixmapPriv *pFrontExaPixPriv = exaGetPixmapDriverPrivate (pFrontBufPriv->pPixmap); + SECPixmapPriv *pBackExaPixPriv = exaGetPixmapDriverPrivate (pBackBufPriv->pPixmap); + + if(pFrontBufPriv->canFlip != pBackBufPriv->canFlip) + { + XDBG_WARNING (MDRI2, "Cannot exchange buffer(0x%x): Front(%d, canFlip:%d), Back(%d, canFlip:%d)\n", + (unsigned int)pDraw->id, pFrontBuf->name, pFrontBufPriv->canFlip, + pBackBuf->name, pBackBufPriv->canFlip); + + return; + } + + /* exchange the buffers + * 1. exchange the bo of the exa pixmap private + * 2. get the name of the front buffer (the name of the back buffer will get next DRI2GetBuffers.) + */ + if (pFrontBufPriv->canFlip) + { + XDBG_RETURN_IF_FAIL(NULL != secFbSwapBo(pSec->pFb, pBackExaPixPriv->bo)); + pFrontBuf->name = _getName (pFrontBufPriv->pPixmap); + } + else + { + tbm_bo_swap(pFrontExaPixPriv->bo, pBackExaPixPriv->bo); + pFrontBuf->name = _getName (pFrontBufPriv->pPixmap); + } + + /*Exchange pixmap owner and sbc*/ + { + XID owner; + CARD64 sbc; + + owner = pFrontExaPixPriv->owner; + sbc = pFrontExaPixPriv->sbc; + + pFrontExaPixPriv->owner = pBackExaPixPriv->owner; + pFrontExaPixPriv->sbc = pBackExaPixPriv->sbc; + + pBackExaPixPriv->owner = owner; + pBackExaPixPriv->sbc = sbc; + } + + /* exchange the index of the available buffer*/ + _exchangeBackBufPixmap(pBackBuf); +} + +static DRI2FrameEventPtr +_newFrame (ClientPtr pClient, DrawablePtr pDraw, + DRI2BufferPtr pFrontBuf, DRI2BufferPtr pBackBuf, + DRI2SwapEventPtr swap_func, void *data, RegionPtr pRegion) +{ + DRI2FrameEventPtr pFrameEvent = NULL; + DRI2FrameEventType swap_type = DRI2_NONE; + + /* check and get the swap_type */ + swap_type = _getSwapType (pDraw, pFrontBuf, pBackBuf); + if (swap_type == DRI2_NONE) + return NULL; + + pFrameEvent = calloc (1, sizeof (DRI2FrameEventRec)); + if (!pFrameEvent) + return NULL; + + pFrameEvent->type = swap_type; + pFrameEvent->drawable_id = pDraw->id; + pFrameEvent->client_idx = pClient->index; + pFrameEvent->pClient = pClient; + pFrameEvent->event_complete = swap_func; + pFrameEvent->event_data = data; + pFrameEvent->pFrontBuf = pFrontBuf; + pFrameEvent->pBackBuf = pBackBuf; + + if (pRegion) + { + pFrameEvent->pRegion = RegionCreate(RegionExtents(pRegion), + RegionNumRects(pRegion)); + if (!RegionCopy(pFrameEvent->pRegion, pRegion)) + { + RegionDestroy(pFrameEvent->pRegion); + pFrameEvent->pRegion = NULL; + } + } + else + { + pFrameEvent->pRegion = NULL; + } + + _referenceBufferPriv (pFrontBuf); + _referenceBufferPriv (pBackBuf); + + return pFrameEvent; +} + +static void +_swapFrame (DrawablePtr pDraw, DRI2FrameEventPtr pFrameEvent) +{ + switch (pFrameEvent->type) + { + case DRI2_FLIP: + _generateDamage (pDraw, pFrameEvent); + break; + case DRI2_SWAP: + _exchangeBuffers (pDraw, pFrameEvent->type, + pFrameEvent->pFrontBuf, pFrameEvent->pBackBuf); + _generateDamage (pDraw, pFrameEvent); + break; + case DRI2_BLIT: + case DRI2_FB_BLIT: + /* copy the region from back buffer to front buffer */ + _blitBuffers (pDraw, pFrameEvent->pFrontBuf, pFrameEvent->pBackBuf); + break; + default: + /* Unknown type */ + XDBG_WARNING (MDRI2, "%s: unknown swap_type received\n", __func__); + _generateDamage (pDraw, pFrameEvent); + break; + } +} + +static void +_deleteFrame (DrawablePtr pDraw, DRI2FrameEventPtr pEvent) +{ + /* some special case */ + DRI2BufferPrivPtr pFrontBufPriv; + DRI2BufferPrivPtr pBackBufPriv; + + if (pEvent->pBackBuf && pEvent->pFrontBuf) + { + pFrontBufPriv = pEvent->pFrontBuf->driverPrivate; + pBackBufPriv = pEvent->pBackBuf->driverPrivate; + + /* + * Even though pFrontBufPriv->canFlip and pBackBufPriv->canFlip is 1, pEvent->type can have DRI2_BLIT. + * When it requests SECDri2ScheduleSwapWithRegion(), _canFlip(pDraw) is FALSE. So it has DRI2_BLIT type. + * In this case we should change pEvent->type to DRI2_FLIP. So we can call secCrtcRelFlipPixmap() for pEvent->pBackBuf + */ + if( (pFrontBufPriv->canFlip == 1) && (pBackBufPriv->canFlip == 1) ) + { + pEvent->type = DRI2_FLIP; + } + } + + if (pEvent->pBackBuf) + { + /* disuse the backbuffer */ + _disuseBackBufPixmap(pEvent->pBackBuf, pEvent); + + SECDri2DestroyBuffer (pDraw, pEvent->pBackBuf); + } + + if (pEvent->pFrontBuf) + { + SECDri2DestroyBuffer (pDraw, pEvent->pFrontBuf); + } + + if (pEvent->pRegion) + { + RegionDestroy(pEvent->pRegion); + } + + free (pEvent); + pEvent = NULL; +} + +static void +_asyncSwapBuffers (ClientPtr pClient, DrawablePtr pDraw, DRI2FrameEventPtr pFrameEvent) +{ + XDBG_DEBUG(MDRI2,"id:0x%x(%d) Client:%d Front(attach:%d, name:%d, flag:0x%x), Back(attach:%d, name:%d, flag:0x%x)\n", + (unsigned int)pDraw->id, pDraw->type, + pClient->index, + pFrameEvent->pFrontBuf->attachment, pFrameEvent->pFrontBuf->name, pFrameEvent->pFrontBuf->flags, + pFrameEvent->pBackBuf->attachment, pFrameEvent->pBackBuf->name, pFrameEvent->pBackBuf->flags); + + _swapFrame (pDraw, pFrameEvent); + + switch (pFrameEvent->type) + { + case DRI2_SWAP: + DRI2SwapComplete (pClient, pDraw, 0, 0, 0, + DRI2_EXCHANGE_COMPLETE, + pFrameEvent->event_complete, pFrameEvent->event_data); + break; + case DRI2_FLIP: + _exchangeBuffers (pDraw, pFrameEvent->type, pFrameEvent->pFrontBuf, pFrameEvent->pBackBuf); + DRI2SwapComplete (pClient, pDraw, 0, 0, 0, + DRI2_FLIP_COMPLETE, + pFrameEvent->event_complete, pFrameEvent->event_data); + break; + case DRI2_BLIT: + case DRI2_FB_BLIT: + DRI2SwapComplete (pClient, pDraw, 0, 0, 0, + DRI2_BLIT_COMPLETE, + pFrameEvent->event_complete, pFrameEvent->event_data); + break; + default: + DRI2SwapComplete (pClient, pDraw, 0, 0, 0, + 0, + pFrameEvent->event_complete, pFrameEvent->event_data); + break; + } +} + +static Bool +_doPageFlip (DrawablePtr pDraw, int crtc_pipe, xf86CrtcPtr pCrtc, DRI2FrameEventPtr pEvent) +{ + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + DRI2BufferPrivPtr pBackBufPriv = pEvent->pBackBuf->driverPrivate; + SECPixmapPriv *pBackExaPixPriv = exaGetPixmapDriverPrivate (pBackBufPriv->pPixmap); + + /* Reset buffer position */ + secRenderBoSetPos(pBackExaPixPriv->bo, pDraw->x, pDraw->y); + + if (!secModePageFlip (pScrn, NULL, pEvent, crtc_pipe, pBackExaPixPriv->bo)) + { + XDBG_WARNING (MDRI2, "fail to secModePageFlip\n"); + return FALSE; + } + else + { + XDBG_DEBUG (MDRI2,"doPageFlip id:0x%x(%d) Client:%d pipe:%d Front(attach:%d, name:%d, flag:0x%x), " + "Back(attach:%d, name:%d, flag:0x%x )\n", + (unsigned int)pDraw->id, pDraw->type, + pEvent->pClient->index, crtc_pipe, + pEvent->pFrontBuf->attachment, pEvent->pFrontBuf->name, pEvent->pFrontBuf->flags, + pEvent->pBackBuf->attachment, pEvent->pBackBuf->name, pEvent->pBackBuf->flags); + + _exchangeBuffers (pDraw, pEvent->type, pEvent->pFrontBuf, pEvent->pBackBuf); + } + + return TRUE; +} + + +static Bool +_scheduleFlip (DrawablePtr pDraw, DRI2FrameEventPtr pEvent, Bool bFlipChain) +{ + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcPtr pCrtc = NULL; + SECCrtcPrivPtr pCrtcPriv = NULL; + BoxRec box; + + /* main crtc for this drawable shall finally deliver pageflip event */ + int crtc_pipe = secDisplayDrawablePipe (pDraw); + + box.x1 = pDraw->x; + box.y1 = pDraw->y; + box.x2 = box.x1 + pDraw->width; + box.y2 = box.y1 + pDraw->height; + pCrtc = secModeCoveringCrtc (pScrn, &box, NULL, NULL); + + if (!pCrtc) + { + XDBG_WARNING(MDRI2, "fail to get a crtc from a drawable\n"); + DRI2SwapComplete (pEvent->pClient, pDraw, 0, 0, 0, DRI2_FLIP_COMPLETE, + pEvent->event_complete, pEvent->event_data); + _deleteFrame (pDraw, pEvent); + return FALSE; + } + + pEvent->pCrtc = (void*)pCrtc; + pEvent->crtc_pipe = crtc_pipe; + + pCrtcPriv = pCrtc->driver_private; + + DRI2BufferPrivPtr pBackBufPriv = pEvent->pBackBuf->driverPrivate; + + if (secCrtcIsFlipping(pCrtc) || pBackBufPriv->pFlipEvent) + { + /* Set the pending filp frame_event to the back buffer + * if the previous flip frmae_event is not completed. + */ + if (pBackBufPriv->pFlipEvent) + { + if (pBackBufPriv->pFlipEvent->pPendingEvent) + { + XDBG_WARNING(MDRI2, "waring : pPendingEvent exist.\n"); + return FALSE; + } + pBackBufPriv->pFlipEvent->pPendingEvent = pEvent; + } + + if ( pCrtcPriv->is_fb_blit_flipping || !bFlipChain) + { + secCrtcAddPendingFlip (pCrtc, pEvent); + return TRUE; + } + } + + if (!_doPageFlip (pDraw, crtc_pipe, pCrtc, pEvent)) + XDBG_WARNING (MDRI2, "_doPageflip failed\n"); + else + { + /* set the flip frame_event */ + pBackBufPriv->pFlipEvent = pEvent; + DRI2SwapComplete (pEvent->pClient, pDraw, 0, 0, 0, DRI2_FLIP_COMPLETE, + pEvent->event_complete, pEvent->event_data); + } + + return TRUE; +} + +static void +_saveDrawable (DrawablePtr pDraw, DRI2BufferPtr pBackBuf, DRI2FrameEventType swap_type) +{ + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = SECPTR(pScrn); + char *type[5] = {"none", "swap", "flip", "blit", "fbblit"}; + char file[128]; + PixmapPtr pPix; + DRI2BufferPrivPtr pBackBufPriv; + SECPixmapPriv *pExaPixPriv; + + if (!pSec->dump_info) + return; + + XDBG_RETURN_IF_FAIL (pDraw != NULL); + XDBG_RETURN_IF_FAIL (pBackBuf != NULL); + + pPix = _getPixmapFromDrawable (pDraw); + XDBG_RETURN_IF_FAIL (pPix != NULL); + pBackBufPriv = pBackBuf->driverPrivate; + XDBG_RETURN_IF_FAIL (pBackBufPriv != NULL); + pExaPixPriv = exaGetPixmapDriverPrivate (pPix); + XDBG_RETURN_IF_FAIL (pExaPixPriv != NULL); + + snprintf (file, sizeof(file), "%03d_%s_%lx_%03d.%s", + pSec->flip_cnt, type[swap_type], pDraw->id, pExaPixPriv->dump_cnt, + pSec->dump_type); + + if (!strcmp (pSec->dump_type, "raw")) + { + Bool need_finish = FALSE; + SECPixmapPriv *privPixmap = exaGetPixmapDriverPrivate (pBackBufPriv->pPixmap); + int size; + + if (!privPixmap->bo) + { + need_finish = TRUE; + secExaPrepareAccess (pBackBufPriv->pPixmap, EXA_PREPARE_DEST); + XDBG_RETURN_IF_FAIL (privPixmap->bo != NULL); + } + size = tbm_bo_size (privPixmap->bo); + secUtilDoDumpRaws (pSec->dump_info, &privPixmap->bo, &size, 1, file); + + if (need_finish) + secExaFinishAccess (pBackBufPriv->pPixmap, EXA_PREPARE_DEST); + } + else + secUtilDoDumpPixmaps (pSec->dump_info, pBackBufPriv->pPixmap, file); + + XDBG_DEBUG (MSEC, "dump done\n"); + + pExaPixPriv->dump_cnt++; +} + +static void +_SendSyncDrawDoneMessage(ScreenPtr screen, ClientPtr client, DrawablePtr pDraw) +{ + XDBG_RETURN_IF_FAIL (screen != NULL); + XDBG_RETURN_IF_FAIL (client != NULL); + XDBG_RETURN_IF_FAIL (pDraw != NULL); + + static Atom sync_draw_done = None; + xEvent event; + DeviceIntPtr dev = PickPointer(client); + + XDBG_RETURN_IF_FAIL (dev != NULL); + + if (sync_draw_done == None) + sync_draw_done = MakeAtom ("_E_COMP_SYNC_DRAW_DONE", strlen ("_E_COMP_SYNC_DRAW_DONE"), TRUE); + + memset (&event, 0, sizeof (xEvent)); + event.u.u.type = ClientMessage; + event.u.u.detail = 32; + event.u.clientMessage.u.l.type = sync_draw_done; + event.u.clientMessage.u.l.longs0 = pDraw->id; // window id + event.u.clientMessage.u.l.longs1 = 1; // version + event.u.clientMessage.u.l.longs2 = pDraw->width; // window's width + event.u.clientMessage.u.l.longs3 = pDraw->height; // window's height + + XDBG_DEBUG(MDRI2, "client=%d pDraw->id=%x width=%d height=%d\n", client->index, pDraw->id, pDraw->width, pDraw->height); + + DeliverEventsToWindow(dev, screen->root, &event, 1, SubstructureRedirectMask | SubstructureNotifyMask, NullGrab); +} + +static DRI2BufferPtr +SECDri2CreateBuffer (DrawablePtr pDraw, unsigned int attachment, unsigned int format) +{ + ScreenPtr pScreen = pDraw->pScreen; + DRI2BufferPtr pBuf = NULL; + DRI2BufferPrivPtr pBufPriv = NULL; + PixmapPtr pPix = NULL; + Bool canFlip = FALSE; + + /* create dri2 buffer */ + pBuf = calloc (1, sizeof (DRI2BufferRec)); + if (pBuf == NULL) + goto fail; + + /* create dri2 buffer private */ + pBufPriv = calloc (1, sizeof (DRI2BufferPrivRec)); + if (pBufPriv == NULL) + goto fail; + + /* check canFlip */ + canFlip = _canFlip (pDraw); + + pBuf->driverPrivate = pBufPriv; + pBuf->format = format; + pBuf->flags = _getBufferFlag (pDraw, canFlip); + + /* check the attachments */ + if (attachment == DRI2BufferFrontLeft) + { + pPix = _getPixmapFromDrawable (pDraw); + pPix->refcnt++; + pBufPriv->canFlip = canFlip; + } + else + { + switch (attachment) + { + case DRI2BufferDepth: + case DRI2BufferDepthStencil: + case DRI2BufferFakeFrontLeft: + case DRI2BufferFakeFrontRight: + case DRI2BufferBackRight: + case DRI2BufferBackLeft: + pPix = _initBackBufPixmap (pBuf, pDraw, canFlip); + if (pPix == NULL) + { + goto fail; + } + break; + default: + XDBG_ERROR(MDRI2, "Unsupported attachmemt:%d\n", attachment); + goto fail; + break; + } + + //Set DRI2 property for selective-composite mode + _setDri2Property (pDraw); + } + + pBuf->cpp = pPix->drawable.bitsPerPixel / 8; + pBuf->attachment = attachment; + pBuf->pitch = pPix->devKind; + pBuf->name = _getName (pPix); + if (pBuf->name == 0) + { + goto fail; + } + + pBufPriv->refcnt = 1; + pBufPriv->attachment = attachment; + pBufPriv->pPixmap = pPix; + pBufPriv->pScreen = pScreen; + + XDBG_DEBUG(MDRI2, "id:0x%x(%d) attach:%d, name:%d, flags:0x%x, flip:%d geo(%dx%d+%d+%d)\n", + pDraw->id, pDraw->type, + pBuf->attachment, pBuf->name, pBuf->flags, pBufPriv->canFlip, + pDraw->width, pDraw->height, pDraw->x, pDraw->y); + + return pBuf; +fail: + XDBG_WARNING(MDRI2, "Failed: id:0x%x(%d) attach:%d,geo(%dx%d+%d+%d)\n", + pDraw->id, pDraw->type, attachment, pDraw->width, pDraw->height, pDraw->x, pDraw->y); + if (pPix) + { +#if USE_XDBG + xDbgLogPListDrawRemoveRefPixmap (pDraw, pPix); +#endif + (*pScreen->DestroyPixmap) (pPix); + } + if (pBufPriv) + free (pBufPriv); + if (pBuf) + free (pBuf); + return NULL; +} + +static void +SECDri2DestroyBuffer (DrawablePtr pDraw, DRI2BufferPtr pBuf) +{ + ScreenPtr pScreen = NULL; + DRI2BufferPrivPtr pBufPriv = NULL; + + if (pBuf == NULL) + return; + + pBufPriv = pBuf->driverPrivate; + pScreen = pBufPriv->pScreen; + + _unreferenceBufferPriv(pBuf); + + if (pBufPriv->refcnt == 0) + { + XDBG_DEBUG(MDRI2, "DestroyBuffer(%d:0x%x) name:%d flip:%d\n", + pDraw?pDraw->type:0, + pDraw?(unsigned int)pDraw->id:0, + pBuf->name, + pBufPriv->canFlip); + + if (pBuf->attachment == DRI2BufferFrontLeft) + { + (*pScreen->DestroyPixmap) (pBufPriv->pPixmap); + } + else + { + _deinitBackBufPixmap(pBuf, pDraw, pBufPriv->canFlip); + } + + pBufPriv->pPixmap = NULL; + free (pBufPriv); + free (pBuf); + } +} + +static void +SECDri2CopyRegion (DrawablePtr pDraw, RegionPtr pRegion, + DRI2BufferPtr pDstBuf, DRI2BufferPtr pSrcBuf) +{ + DRI2BufferPrivPtr pSrcBufPriv = pSrcBuf->driverPrivate; + DRI2BufferPrivPtr pDstBufPriv = pDstBuf->driverPrivate; + ScreenPtr pScreen = pDraw->pScreen; + RegionPtr pCopyClip; + GCPtr pGc; + + DrawablePtr pSrcDraw = (pSrcBufPriv->attachment == DRI2BufferFrontLeft) + ? pDraw : &pSrcBufPriv->pPixmap->drawable; + DrawablePtr pDstDraw = (pDstBufPriv->attachment == DRI2BufferFrontLeft) + ? pDraw : &pDstBufPriv->pPixmap->drawable; + + pGc = GetScratchGC (pDstDraw->depth, pScreen); + if (!pGc) + return; + + XDBG_DEBUG(MDRI2,"CopyRegion(%d,0x%x) Dst(attach:%d, name:%d, flag:0x%x), Src(attach:%d, name:%d, flag:0x%x)\n", + pDraw->type, (unsigned int)pDraw->id, + pDstBuf->attachment, pDstBuf->name, pDstBuf->flags, + pSrcBuf->attachment, pSrcBuf->name, pSrcBuf->flags); + + pCopyClip = REGION_CREATE (pScreen, NULL, 0); + REGION_COPY (pScreen, pCopyClip, pRegion); + (*pGc->funcs->ChangeClip) (pGc, CT_REGION, pCopyClip, 0); + ValidateGC (pDstDraw, pGc); + + /* Wait for the scanline to be outside the region to be copied */ + /* [TODO] Something Do ??? */ + + /* It's important that this copy gets submitted before the + * direct rendering client submits rendering for the next + * frame, but we don't actually need to submit right now. The + * client will wait for the DRI2CopyRegion reply or the swap + * buffer event before rendering, and we'll hit the flush + * callback chain before those messages are sent. We submit + * our batch buffers from the flush callback chain so we know + * that will happen before the client tries to render + * again. */ + + (*pGc->ops->CopyArea) (pSrcDraw, pDstDraw, + pGc, + 0, 0, + pDraw->width, pDraw->height, + 0, 0); + (*pGc->funcs->DestroyClip) (pGc); + FreeScratchGC (pGc); +} + + +/* + * ScheduleSwap is responsible for requesting a DRM vblank event for the + * appropriate frame. + * + * In the case of a blit (e.g. for a windowed swap) or buffer exchange, + * the vblank requested can simply be the last queued swap frame + the swap + * interval for the drawable. + * + * In the case of a page flip, we request an event for the last queued swap + * frame + swap interval - 1, since we'll need to queue the flip for the frame + * immediately following the received event. + * + * The client will be blocked if it tries to perform further GL commands + * after queueing a swap, though in the Intel case after queueing a flip, the + * client is free to queue more commands; they'll block in the kernel if + * they access buffers busy with the flip. + * + * When the swap is complete, the driver should call into the server so it + * can send any swap complete events that have been requested. + */ +static int +SECDri2ScheduleSwapWithRegion (ClientPtr pClient, DrawablePtr pDraw, + DRI2BufferPtr pFrontBuf, DRI2BufferPtr pBackBuf, + CARD64 *target_msc, CARD64 divisor, CARD64 remainder, + DRI2SwapEventPtr swap_func, void *data, RegionPtr pRegion) +{ + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = SECPTR (pScrn); + int pipe = 0; /* default */ + int flip = 0; + DRI2FrameEventPtr pFrameEvent = NULL; + DRI2FrameEventType swap_type = DRI2_SWAP; + CARD64 current_msc; + CARD64 ust, msc; + + pFrameEvent = _newFrame (pClient, pDraw, pFrontBuf, pBackBuf, swap_func, data, pRegion); + if (!pFrameEvent) + { + DRI2SwapComplete (pClient, pDraw, 0, 0, 0, 0, swap_func, data); + return TRUE; + } + + /* Set frame count to back*/ + { + PixmapPtr pPix; + SECPixmapPriv *pExaPixPriv = NULL; + DRI2BufferPrivPtr pBufPriv = pBackBuf->driverPrivate; + CARD64 sbc; + unsigned int pending; + + pPix = pBufPriv->pBackPixmaps[pBufPriv->cur_idx]; + pExaPixPriv = exaGetPixmapDriverPrivate (pPix); + DRI2GetSBC(pDraw, &sbc, &pending); + pExaPixPriv->owner = pDraw->id; + pExaPixPriv->sbc = sbc+pending; + } + + + swap_type = pFrameEvent->type; + + XDBG_DEBUG (MSEC, "dump_mode(%x) dump_xid(0x%x:0x%x) swap_type(%d)\n", + pSec->dump_mode, pSec->dump_xid, pDraw->id, swap_type); + + if ((pSec->dump_mode & XBERC_DUMP_MODE_DRAWABLE) && + (swap_type != DRI2_NONE && swap_type != DRI2_WAITMSC) && + (pSec->dump_xid == 0 || pSec->dump_xid == pDraw->id)) + _saveDrawable (pDraw, pBackBuf, swap_type); + + /* If lcd is off status, SwapBuffers do not consider the vblank sync. + * The client that launches after lcd is off wants to render the frame + * on the fly. + */ + if (pSec->isLcdOff == TRUE || + pSec->useAsyncSwap == TRUE) + { + _asyncSwapBuffers (pClient, pDraw, pFrameEvent); + _SendSyncDrawDoneMessage(pScreen, pClient, pDraw); + _deleteFrame (pDraw, pFrameEvent); + return TRUE; + } + + pipe = secDisplayDrawablePipe (pDraw); + + /* check if the pipe is -1 */ + if (pipe == -1) + { + /* if swap_type is DRI2_FLIP, fall into the async swap */ + if (swap_type == DRI2_FLIP) + { + XDBG_WARNING(MDRI2, "Warning: flip pipe is -1 \n"); + _asyncSwapBuffers (pClient, pDraw, pFrameEvent); + _SendSyncDrawDoneMessage(pScreen, pClient, pDraw); + _deleteFrame (pDraw, pFrameEvent); + return TRUE; + } + } + + /* Truncate to match kernel interfaces; means occasional overflow + * misses, but that's generally not a big deal */ + *target_msc &= 0xffffffff; + divisor &= 0xffffffff; + remainder &= 0xffffffff; + + /* Get current count */ + if (!secDisplayGetCurMSC (pScrn, pipe, &ust, &msc)) + { + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, + "fail to get current_msc\n"); + goto blit_fallback; + } + current_msc = msc; + + /* Flips need to be submitted one frame before */ + if (swap_type == DRI2_FLIP) + { + flip = 1; + } + + /* Correct target_msc by 'flip' if swap_type == DRI2_FLIP. + * Do it early, so handling of different timing constraints + * for divisor, remainder and msc vs. target_msc works. + */ + if (*target_msc > 0) + *target_msc -= flip; + + /* + * If divisor is zero, or current_msc is smaller than target_msc + * we just need to make sure target_msc passes before initiating + * the swap. + */ + if (divisor == 0 || current_msc < *target_msc) + { + /* If target_msc already reached or passed, set it to + * current_msc to ensure we return a reasonable value back + * to the caller. This makes swap_interval logic more robust. + */ + if (current_msc >= *target_msc) + *target_msc = current_msc; + + if (!secDisplayVBlank (pScrn, pipe, target_msc, flip, VBLANK_INFO_SWAP, pFrameEvent)) + { + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "fail to Vblank\n"); + goto blit_fallback; + } + + pFrameEvent->frame = (unsigned int )*target_msc; + + XDBG_DEBUG(MDRI2,"id:0x%x(%d) SwapType:%d Client:%d pipe:%d Front(attach:%d, name:%d, flag:0x%x), " + "Back(attach:%d, name:%d, flag:0x%x )\n", + (unsigned int)pDraw->id, pDraw->type, + swap_type, pClient->index, pipe, + pFrontBuf->attachment, pFrontBuf->name, pFrontBuf->flags, + pBackBuf->attachment, pBackBuf->name, pBackBuf->flags); + + if (pFrameEvent->pRegion) + { + BoxPtr pBox = RegionRects(pFrameEvent->pRegion); + int nBox = RegionNumRects(pFrameEvent->pRegion); + + while (nBox--) + { + XDBG_DEBUG(MDRI2,"Region[%d]: (x1, y1, x2, y2) = (%d,%d,%d,%d) \n ", + nBox, pBox->x1, pBox->y1, pBox->x2, pBox->y2); + pBox++; + } + } + + _swapFrame (pDraw, pFrameEvent); + _SendSyncDrawDoneMessage(pScreen, pClient, pDraw); + + return TRUE; + } + + /* + * If we get here, target_msc has already passed or we don't have one, + * and we need to queue an event that will satisfy the divisor/remainder + * equation. + */ + *target_msc = current_msc - (current_msc % divisor) + + remainder; + + /* + * If the calculated deadline vbl.request.sequence is smaller than + * or equal to current_msc, it means we've passed the last point + * when effective onset frame seq could satisfy + * seq % divisor == remainder, so we need to wait for the next time + * this will happen. + + * This comparison takes the 1 frame swap delay in pageflipping mode + * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay + * if we are blitting/exchanging instead of flipping. + */ + if (*target_msc <= current_msc) + *target_msc += divisor; + + /* Account for 1 frame extra pageflip delay if flip > 0 */ + *target_msc -= flip; + + if (!secDisplayVBlank (pScrn, pipe, target_msc, flip, VBLANK_INFO_SWAP, pFrameEvent)) + { + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "fail to Vblank\n"); + goto blit_fallback; + } + + pFrameEvent->frame = *target_msc; + + XDBG_DEBUG(MDRI2,"ScaduleSwap_ex(%d,0x%x) SwapType:%d Client:%d pipe:%d Front(attach:%d, name:%d, flag:0x%x), Back(attach:%d, name:%d, flag:0x%x)\n", + pDraw->type, (unsigned int)pDraw->id, + swap_type, pClient->index, pipe, + pFrontBuf->attachment, pFrontBuf->name, pFrontBuf->flags, + pBackBuf->attachment, pBackBuf->name, pBackBuf->flags); + + _swapFrame (pDraw, pFrameEvent); + _SendSyncDrawDoneMessage(pScreen, pClient, pDraw); + + return TRUE; + +blit_fallback: + XDBG_WARNING(MDRI2,"blit_fallback(%d,0x%x) SwapType:%d Client:%d pipe:%d Front(attach:%d, name:%d, flag:0x%x), Back(attach:%d, name:%d, flag:0x%x)\n", + pDraw->type, (unsigned int)pDraw->id, + swap_type, pClient->index, pipe, + pFrontBuf->attachment, pFrontBuf->name, pFrontBuf->flags, + pBackBuf->attachment, pBackBuf->name, pBackBuf->flags); + + _blitBuffers (pDraw, pFrontBuf, pBackBuf); + + DRI2SwapComplete (pClient, pDraw, 0, 0, 0, DRI2_BLIT_COMPLETE, swap_func, data); + _SendSyncDrawDoneMessage(pScreen, pClient, pDraw); + + if (pFrameEvent) + { + _deleteFrame (pDraw, pFrameEvent); + } + *target_msc = 0; /* offscreen, so zero out target vblank count */ + return TRUE; +} + + +/* + * Get current frame count and frame count timestamp, based on drawable's + * crtc. + */ +static int +SECDri2GetMSC (DrawablePtr pDraw, CARD64 *ust, CARD64 *msc) +{ + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + int pipe; + + pipe = secDisplayDrawablePipe (pDraw); + + /* Get current count */ + if (!secDisplayGetCurMSC (pScrn, pipe, ust, msc)) + { + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, + "fail to get current_msc\n"); + return FALSE; + } + + return TRUE; +} + +/* + * Request a DRM event when the requested conditions will be satisfied. + * + * We need to handle the event and ask the server to wake up the client when + * we receive it. + */ +static int +SECDri2ScheduleWaitMSC (ClientPtr pClient, DrawablePtr pDraw, + CARD64 target_msc, CARD64 divisor, CARD64 remainder) +{ + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + DRI2FrameEventPtr wait_info = NULL; + CARD64 current_msc; + CARD64 ust, msc; + + int pipe = 0; + + /* Truncate to match kernel interfaces; means occasional overflow + * misses, but that's generally not a big deal */ + target_msc &= 0xffffffff; + divisor &= 0xffffffff; + remainder &= 0xffffffff; + + /* Drawable not visible, return immediately */ + pipe = secDisplayDrawablePipe (pDraw); + if (pipe == -1) + goto out_complete; + + wait_info = calloc (1, sizeof (DRI2FrameEventRec)); + if (!wait_info) + goto out_complete; + + wait_info->drawable_id = pDraw->id; + wait_info->pClient = pClient; + wait_info->type = DRI2_WAITMSC; + + /* Get current count */ + if (!secDisplayGetCurMSC (pScrn, pipe, &ust, &msc)) + { + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, + "fail to get current_msc\n"); + goto out_complete; + } + current_msc = msc; + + /* + * If divisor is zero, or current_msc is smaller than target_msc, + * we just need to make sure target_msc passes before waking up the + * client. + */ + if (divisor == 0 || current_msc < target_msc) + { + /* If target_msc already reached or passed, set it to + * current_msc to ensure we return a reasonable value back + * to the caller. This keeps the client from continually + * sending us MSC targets from the past by forcibly updating + * their count on this call. + */ + if (current_msc >= target_msc) + target_msc = current_msc; + + /* flip is 1 to avoid to set DRM_VBLANK_NEXTONMISS */ + if (!secDisplayVBlank (pScrn, pipe, &target_msc, 1, VBLANK_INFO_SWAP, wait_info)) + { + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "fail to Vblank\n"); + goto out_complete; + } + + wait_info->frame = target_msc - 1; /* reply qeuenct is +1 in secDisplayVBlank */ + DRI2BlockClient (pClient, pDraw); + return TRUE; + } + + /* + * If we get here, target_msc has already passed or we don't have one, + * so we queue an event that will satisfy the divisor/remainder equation. + */ + target_msc = current_msc - (current_msc % divisor) + + remainder; + + /* + * If calculated remainder is larger than requested remainder, + * it means we've passed the last point where + * seq % divisor == remainder, so we need to wait for the next time + * that will happen. + */ + if ((current_msc % divisor) >= remainder) + target_msc += divisor; + + /* flip is 1 to avoid to set DRM_VBLANK_NEXTONMISS */ + if (!secDisplayVBlank (pScrn, pipe, &target_msc, 1, VBLANK_INFO_SWAP, wait_info)) + { + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "fail to Vblank\n"); + goto out_complete; + } + + wait_info->frame = target_msc - 1; /* reply qeuenct is +1 in secDisplayVBlank */ + DRI2BlockClient (pClient, pDraw); + + return TRUE; + +out_complete: + free(wait_info); + DRI2WaitMSCComplete (pClient, pDraw, target_msc, 0, 0); + return TRUE; +} + +static int +SECDri2AuthMagic (int fd, uint32_t magic) +{ + int ret; + ret = drmAuthMagic (fd, (drm_magic_t) magic); + + XDBG_TRACE(MDRI2, "AuthMagic: %d\n", ret); + + return ret; +} + +static void +SECDri2ReuseBufferNotify (DrawablePtr pDraw, DRI2BufferPtr pBuf) +{ + DRI2BufferPrivPtr pBufPriv = pBuf->driverPrivate; + + if(!_resetBufPixmap(pDraw, pBuf)) + { + DRI2BufferFlags *flags = (DRI2BufferFlags*)&pBuf->flags; + + pBuf->name = _getName(pBufPriv->pPixmap); + flags->flags = _getBufferFlag(pDraw, pBufPriv->canFlip); + flags->data.is_reused = 1; + + /*Set reuse index*/ + if (pBuf->attachment != DRI2BufferFrontLeft) + { + DRI2BufferPrivPtr pBufPriv = pBuf->driverPrivate; + PixmapPtr pPix; + SECPixmapPriv *pExaPixPriv = NULL; + CARD64 sbc; + unsigned int pending; + + pPix = pBufPriv->pBackPixmaps[pBufPriv->cur_idx]; + pExaPixPriv = exaGetPixmapDriverPrivate (pPix); + + DRI2GetSBC(pDraw, &sbc, &pending); + /*Get current count */ + if(pExaPixPriv->owner == pDraw->id) + { + unsigned int idx_reuse = sbc+pending - pExaPixPriv->sbc + 1; + if(idx_reuse > pBufPriv->num_buf + 1) + { + flags->data.idx_reuse = 0; + } + else + { + flags->data.idx_reuse = idx_reuse; + } + } + else + { + flags->data.idx_reuse = 0; + } + } + else + { + flags->data.idx_reuse = 0; + } + } + + XDBG_DEBUG(MDRI2, "id:0x%x(%d) attach:%d, name:%d, flags:0x%x, flip:%d, geo(%dx%d+%d+%d)\n", + pDraw->id, pDraw->type, + pBuf->attachment, pBuf->name, pBuf->flags, pBufPriv->canFlip, + pDraw->width, pDraw->height, pDraw->x, pDraw->y); +} + +static void +_secDri2ProcessPending (xf86CrtcPtr pCrtc, ScreenPtr pScreen, + unsigned int frame, unsigned int tv_sec, unsigned int tv_usec) +{ + DRI2BufferPrivPtr pBackBufPriv = NULL; + DrawablePtr pCrtcPendingDraw = NULL; + DRI2FrameEventPtr pCrtcPendingFlip = NULL; + + pCrtcPendingFlip = secCrtcGetFirstPendingFlip (pCrtc); + if (pCrtcPendingFlip) + { + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = SECPTR (pScrn); + + secCrtcRemovePendingFlip (pCrtc, pCrtcPendingFlip); + + if (pCrtcPendingFlip->drawable_id) + dixLookupDrawable (&pCrtcPendingDraw, pCrtcPendingFlip->drawable_id, + serverClient, M_ANY, DixWriteAccess); + if (!pCrtcPendingDraw) + { + XDBG_WARNING (MDRI2, "pCrtcPendingDraw is null.\n"); + _deleteFrame (pCrtcPendingDraw, pCrtcPendingFlip); + return; + } + else + { + if(pSec->isLcdOff) + { + XDBG_WARNING (MDRI2, "LCD OFF : Request a pageflip pending even if the lcd is off.\n"); + + _exchangeBuffers(pCrtcPendingDraw, DRI2_FLIP, pCrtcPendingFlip->pFrontBuf, pCrtcPendingFlip->pBackBuf); + + DRI2SwapComplete (pCrtcPendingFlip->pClient, pCrtcPendingDraw, + frame, tv_sec, tv_usec, + 0, pCrtcPendingFlip->event_complete, + pCrtcPendingFlip->event_data); + + pBackBufPriv = pCrtcPendingFlip->pBackBuf->driverPrivate; + pBackBufPriv->pFlipEvent = NULL; + _deleteFrame (pCrtcPendingDraw, pCrtcPendingFlip); + } + else + { + if(!_scheduleFlip (pCrtcPendingDraw, pCrtcPendingFlip, TRUE)) + { + XDBG_WARNING (MDRI2, "fail to _scheduleFlip in secDri2FlipEventHandler\n"); + } + } + } + } + +} + +void +secDri2FlipEventHandler (unsigned int frame, unsigned int tv_sec, + unsigned int tv_usec, void *event_data, Bool flip_failed) +{ + DRI2FrameEventPtr pEvent = event_data; + DRI2BufferPrivPtr pBackBufPriv = pEvent->pBackBuf->driverPrivate; + ScreenPtr pScreen = pBackBufPriv->pScreen; + DrawablePtr pDraw = NULL; + ClientPtr pClient = pEvent->pClient; + xf86CrtcPtr pCrtc = (xf86CrtcPtr) pEvent->pCrtc; + + if (pEvent->drawable_id) + dixLookupDrawable (&pDraw, pEvent->drawable_id, serverClient, M_ANY, DixWriteAccess); + if (!pDraw) + { + XDBG_WARNING (MDRI2,"pDraw is null... Client:%d pipe:%d " + "Front(attach:%d, name:%d, flag:0x%x), Back(attach:%d, name:%d, flag:0x%x)\n", + pClient->index, pBackBufPriv->pipe, + pEvent->pFrontBuf->attachment, pEvent->pFrontBuf->name, pEvent->pFrontBuf->flags, + pEvent->pBackBuf->attachment, pEvent->pBackBuf->name, pEvent->pBackBuf->flags); + _secDri2ProcessPending (pCrtc, pScreen, frame, tv_sec, tv_usec); + _deleteFrame (pDraw, pEvent); + return; + } + + XDBG_TRACE (MDRI2,"FlipEvent(%d,0x%x) Client:%d pipe:%d " + "Front(attach:%d, name:%d, flag:0x%x), Back(attach:%d, name:%d, flag:0x%x)\n", + pDraw->type, (unsigned int)pDraw->id, pClient->index, pBackBufPriv->pipe, + pEvent->pFrontBuf->attachment, pEvent->pFrontBuf->name, pEvent->pFrontBuf->flags, + pEvent->pBackBuf->attachment, pEvent->pBackBuf->name, pEvent->pBackBuf->flags); + + /* check the failure of the pageflip */ + if (flip_failed) + { + _exchangeBuffers(pDraw, DRI2_FLIP, pEvent->pFrontBuf, pEvent->pBackBuf); + + DRI2SwapComplete (pEvent->pClient, pDraw, frame, tv_sec, tv_usec, + 0, pEvent->event_complete, pEvent->event_data); + _deleteFrame (pDraw, pEvent); + return; + } + + assert (pBackBufPriv->pFlipEvent == pEvent); + pBackBufPriv->pFlipEvent = NULL; + _deleteFrame (pDraw, pEvent); + + /* get the next pending flip event */ + _secDri2ProcessPending (pCrtc, pScreen, frame, tv_sec, tv_usec); + +} + +void +secDri2FrameEventHandler (unsigned int frame, unsigned int tv_sec, + unsigned int tv_usec, void *event_data) +{ + DRI2FrameEventPtr pEvent = event_data; + DrawablePtr pDraw = NULL; + int status; + + status = dixLookupDrawable (&pDraw, pEvent->drawable_id, serverClient, + M_ANY, DixWriteAccess); + if (status != Success) + { + XDBG_WARNING(MDRI2,"drawable is not found\n"); + + _deleteFrame (NULL, pEvent); + return; + } + + XDBG_RETURN_IF_FAIL(pEvent->pFrontBuf != NULL); + XDBG_RETURN_IF_FAIL(pEvent->pBackBuf != NULL); + + switch (pEvent->type) + { + case DRI2_FLIP: + if(!_scheduleFlip (pDraw, pEvent, FALSE)) + XDBG_WARNING(MDRI2, "pageflip fails.\n"); + return; + break; + case DRI2_SWAP: + DRI2SwapComplete (pEvent->pClient, pDraw, frame, tv_sec, tv_usec, + DRI2_EXCHANGE_COMPLETE, pEvent->event_complete, pEvent->event_data); + break; + case DRI2_BLIT: + case DRI2_FB_BLIT: + DRI2SwapComplete (pEvent->pClient, pDraw, frame, tv_sec, tv_usec, + DRI2_BLIT_COMPLETE, pEvent->event_complete, pEvent->event_data); + break; + case DRI2_NONE: + DRI2SwapComplete (pEvent->pClient, pDraw, frame, tv_sec, tv_usec, + 0, pEvent->event_complete, pEvent->event_data); + break; + case DRI2_WAITMSC: + DRI2WaitMSCComplete (pEvent->pClient, pDraw, frame, tv_sec, tv_usec); + break; + default: + /* Unknown type */ + break; + } + + XDBG_DEBUG (MDRI2,"FrameEvent(%d,0x%x) SwapType:%d Front(attach:%d, name:%d, flag:0x%x), Back(attach:%d, name:%d, flag:0x%x)\n", + pDraw->type, (unsigned int)pDraw->id, pEvent->type, + pEvent->pFrontBuf->attachment, pEvent->pFrontBuf->name, pEvent->pFrontBuf->flags, + pEvent->pBackBuf->attachment, pEvent->pBackBuf->name, pEvent->pBackBuf->flags); + + + _deleteFrame (pDraw, pEvent); +} + + +Bool secDri2Init (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = SECPTR (pScrn); + SECExaPrivPtr pExaPriv = SECEXAPTR (pSec); + DRI2InfoRec info; + int ret; + const char *driverNames[1]; + + info.driverName = "exynos-drm"; + info.deviceName = pSec->drm_device_name; + info.version = 106; + info.fd = pSec->drm_fd; + info.CreateBuffer = SECDri2CreateBuffer; + info.DestroyBuffer = SECDri2DestroyBuffer; + info.CopyRegion = SECDri2CopyRegion; + info.ScheduleSwap = NULL; + info.GetMSC = SECDri2GetMSC; + info.ScheduleWaitMSC = SECDri2ScheduleWaitMSC; + info.AuthMagic = SECDri2AuthMagic; + info.ReuseBufferNotify = SECDri2ReuseBufferNotify; + info.SwapLimitValidate = NULL; + /* added in version 7 */ + info.GetParam = NULL; + + /* added in version 8 */ + /* AuthMagic callback which passes extra context */ + /* If this is NULL the AuthMagic callback is used */ + /* If this is non-NULL the AuthMagic callback is ignored */ + info.AuthMagic2 = NULL; + + /* added in version 9 */ + info.CreateBuffer2 = NULL; + info.DestroyBuffer2 = NULL; + info.CopyRegion2 = NULL; + + /* add in for Tizen extension */ + info.ScheduleSwapWithRegion = SECDri2ScheduleSwapWithRegion; + + info.Wait = NULL; + info.numDrivers = 1; + info.driverNames = driverNames; + driverNames[0] = info.driverName; + + ret = DRI2ScreenInit (pScreen, &info); + if (ret == FALSE) + { + return FALSE; + } + + /* set the number of the flip back buffers */ + pExaPriv->flip_backbufs = pSec->flip_bufs - 1; + + //xDbgLogSetLevel (MDRI2, 0); + return ret; +} + +void secDri2Deinit (ScreenPtr pScreen) +{ + DRI2CloseScreen (pScreen); +} diff --git a/src/accel/sec_exa.c b/src/accel/sec_exa.c new file mode 100755 index 0000000..c62ede5 --- /dev/null +++ b/src/accel/sec_exa.c @@ -0,0 +1,664 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@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 <fcntl.h> +#include <sys/mman.h> +#include "sec.h" +#include "sec_accel.h" +#include "sec_display.h" +#include "sec_crtc.h" +#include <X11/Xatom.h> +#include "windowstr.h" +#include "fbpict.h" +#include "sec_util.h" +#include "sec_converter.h" + +static void +_setScreenRotationProperty (ScrnInfoPtr pScrn) +{ + SECPtr pSec = SECPTR (pScrn); + ScreenPtr pScreen = pScrn->pScreen; + Atom atom_screen_rotaion; + WindowPtr pWin = pScreen->root; + int rc; + atom_screen_rotaion = MakeAtom ("X_SCREEN_ROTATION", 17, TRUE); + unsigned int rotation = (unsigned int) pSec->rotate; + + rc = dixChangeWindowProperty (serverClient, + pWin, atom_screen_rotaion, XA_CARDINAL, 32, + PropModeReplace, 1, &rotation, FALSE); + if (rc != Success) + XDBG_ERROR (MEXAS, "failed : set X_SCREEN_ROTATION to %d\n", rotation); +} + +static void +_secExaBlockHandler (pointer blockData, OSTimePtr pTimeout, + pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[0]; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + /* add screen rotation property to the root window */ + _setScreenRotationProperty (pScrn); + + RemoveBlockAndWakeupHandlers (_secExaBlockHandler /*blockHandler*/, + (void*)NULL /*wakeupHandler*/, + (void*)NULL /*blockData*/); +} + +static void +SECExaWaitMarker (ScreenPtr pScreen, int marker) +{ +} + +static Bool +SECExaPrepareAccess (PixmapPtr pPix, int index) +{ + ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum]; + SECPtr pSec = SECPTR (pScrn); + SECPixmapPriv *privPixmap = exaGetPixmapDriverPrivate (pPix); + int opt = TBM_OPTION_READ; + tbm_bo_handle bo_handle; + + XDBG_RETURN_VAL_IF_FAIL((privPixmap != NULL), FALSE); + if (pPix->usage_hint == CREATE_PIXMAP_USAGE_FB && + privPixmap->bo == NULL) + { + privPixmap->bo = secRenderBoRef(pSec->pFb->default_bo); + XDBG_RETURN_VAL_IF_FAIL((privPixmap->bo != NULL), FALSE); + XDBG_TRACE(MEXAS, " FRAMEBUFFER\n"); + } + else + { + XDBG_TRACE(MEXAS, "\n"); + } + + if(privPixmap->bo) + { + if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) + opt |= TBM_OPTION_WRITE; + + bo_handle = tbm_bo_map(privPixmap->bo, TBM_DEVICE_CPU, opt); + pPix->devPrivate.ptr = bo_handle.ptr; + } + else + { + if(privPixmap->pPixData) + { + pPix->devPrivate.ptr = privPixmap->pPixData; + } + } + + XDBG_DEBUG (MEXA, "pix:%p index:%d hint:%d ptr:%p\n", + pPix, index, pPix->usage_hint, pPix->devPrivate.ptr); + return TRUE; +} + +static void +SECExaFinishAccess (PixmapPtr pPix, int index) +{ + XDBG_TRACE(MEXAS, "\n"); + if (!pPix) + return; + + SECPixmapPriv *privPixmap = (SECPixmapPriv*)exaGetPixmapDriverPrivate (pPix); + + if(privPixmap == NULL) + return; + + if (privPixmap->bo) + tbm_bo_unmap (privPixmap->bo); + + if (pPix->usage_hint == CREATE_PIXMAP_USAGE_FB) + { + secRenderBoUnref(privPixmap->bo); + privPixmap->bo = NULL; + } + + if (pPix->usage_hint == CREATE_PIXMAP_USAGE_OVERLAY) + secLayerUpdate (secLayerFind (LAYER_OUTPUT_LCD, LAYER_UPPER)); + + pPix->devPrivate.ptr = NULL; + XDBG_DEBUG (MEXA, "pix:%p index:%d hint:%d ptr:%p\n", + pPix, index, pPix->usage_hint, pPix->devPrivate.ptr); +} + +static void * +SECExaCreatePixmap (ScreenPtr pScreen, int size, int align) +{ + SECPixmapPriv *privPixmap = calloc (1, sizeof (SECPixmapPriv)); + + return privPixmap; +} + +static void +SECExaDestroyPixmap (ScreenPtr pScreen, void *driverPriv) +{ + XDBG_RETURN_IF_FAIL (driverPriv != NULL); + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = SECPTR (pScrn); + + SECPixmapPriv *privPixmap = (SECPixmapPriv*)driverPriv; + + XDBG_TRACE (MEXA, "DESTROY_PIXMAP : usage_hint:0x%x\n", privPixmap->usage_hint); + + switch(privPixmap->usage_hint) + { + case CREATE_PIXMAP_USAGE_FB: + pSec->pix_fb = pSec->pix_fb - privPixmap->size; + secRenderBoUnref (privPixmap->bo); + privPixmap->bo = NULL; + break; + case CREATE_PIXMAP_USAGE_DRI2_FLIP_BACK: + pSec->pix_dri2_flip_back = pSec->pix_dri2_flip_back - privPixmap->size; + secRenderBoUnref (privPixmap->bo); + privPixmap->bo = NULL; + break; + case CREATE_PIXMAP_USAGE_SUB_FB: + /* TODO ???? */ + pSec->pix_sub_fb = pSec->pix_sub_fb - privPixmap->size; + privPixmap->bo = NULL; + break; + case CREATE_PIXMAP_USAGE_OVERLAY: + /* TODO ???? */ + pSec->pix_overlay = pSec->pix_overlay - privPixmap->size; + secRenderBoUnref (privPixmap->bo); + privPixmap->bo = NULL; + + if (privPixmap->ovl_layer) + { + secLayerUnref (privPixmap->ovl_layer); + privPixmap->ovl_layer = NULL; + } + + pSec->ovl_drawable = NULL; + + SECModePtr pSecMode = (SECModePtr) SECPTR (pScrn)->pSecMode; + xf86CrtcPtr pCrtc = secCrtcGetAtGeometry (pScrn, 0, 0, + pSecMode->main_lcd_mode.hdisplay, + pSecMode->main_lcd_mode.vdisplay); + secCrtcOverlayRef (pCrtc, FALSE); + + break; + case CREATE_PIXMAP_USAGE_DRI2_BACK: + pSec->pix_dri2_back = pSec->pix_dri2_back - privPixmap->size; + tbm_bo_unref (privPixmap->bo); + privPixmap->bo = NULL; + break; + case CREATE_PIXMAP_USAGE_BACKING_PIXMAP: + pSec->pix_backing_pixmap = pSec->pix_backing_pixmap - privPixmap->size; + tbm_bo_unref (privPixmap->bo); + privPixmap->bo = NULL; + break; + default: + pSec->pix_normal = pSec->pix_normal - privPixmap->size; + tbm_bo_unref (privPixmap->bo); + privPixmap->bo = NULL; + break; + } + + /* free pixmap private */ + free (privPixmap); +} + +static Bool +SECExaModifyPixmapHeader (PixmapPtr pPixmap, int width, int height, + int depth, int bitsPerPixel, int devKind, pointer pPixData) +{ + XDBG_RETURN_VAL_IF_FAIL(pPixmap, FALSE); + + ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; + SECPtr pSec = SECPTR (pScrn); + SECPixmapPriv * privPixmap = (SECPixmapPriv*)exaGetPixmapDriverPrivate (pPixmap); + long lSizeInBytes; + + /* set the default headers of the pixmap */ + miModifyPixmapHeader (pPixmap, width, height, depth, bitsPerPixel, + devKind, pPixData); + + /* screen pixmap : set a framebuffer pixmap */ + if (pPixData == (void*)ROOT_FB_ADDR) + { + lSizeInBytes = pPixmap->drawable.height * pPixmap->devKind; + pSec->pix_fb = pSec->pix_fb + lSizeInBytes; + pPixmap->usage_hint = CREATE_PIXMAP_USAGE_FB; + privPixmap->usage_hint = pPixmap->usage_hint; + privPixmap->isFrameBuffer = TRUE; + privPixmap->bo = NULL; + privPixmap->size = lSizeInBytes; + + XDBG_TRACE (MEXA, "CREATE_PIXMAP_FB(%p) : (x,y,w,h)=(%d,%d,%d,%d)\n", + pPixmap, pPixmap->drawable.x, pPixmap->drawable.y, width, height); + + return TRUE; + } + + if(pPixmap->usage_hint == CREATE_PIXMAP_USAGE_SUB_FB) + { + lSizeInBytes = pPixmap->drawable.height * pPixmap->devKind; + pSec->pix_sub_fb = pSec->pix_sub_fb + lSizeInBytes; + + pPixmap->devPrivate.ptr = NULL; + privPixmap->usage_hint = pPixmap->usage_hint; + privPixmap->isSubFramebuffer = TRUE; + privPixmap->bo = (tbm_bo)pPixData; + privPixmap->size = lSizeInBytes; + + XDBG_TRACE (MEXA, "CREATE_PIXMAP_SUB_FB(%p) : (x,y,w,h)=(%d,%d,%d,%d)\n", + pPixmap, pPixmap->drawable.x, pPixmap->drawable.y, width, height); + + return TRUE; + } + else if(pPixmap->usage_hint == CREATE_PIXMAP_USAGE_OVERLAY) + { + SECModePtr pSecMode = (SECModePtr) SECPTR (pScrn)->pSecMode; + SECLayer *layer; + SECVideoBuf *vbuf; + int width, height; + + lSizeInBytes = pPixmap->drawable.height * pPixmap->devKind; + pSec->pix_overlay = pSec->pix_overlay + lSizeInBytes; + + privPixmap->usage_hint = pPixmap->usage_hint; + privPixmap->size = lSizeInBytes; + + pSec->ovl_drawable = &pPixmap->drawable; + + /* change buffer if needed. */ + xf86CrtcPtr pCrtc = secCrtcGetAtGeometry (pScrn, 0, 0, + pSecMode->main_lcd_mode.hdisplay, + pSecMode->main_lcd_mode.vdisplay); + secCrtcOverlayRef (pCrtc, TRUE); + + layer = secLayerFind (LAYER_OUTPUT_LCD, LAYER_UPPER); + XDBG_RETURN_VAL_IF_FAIL (layer != NULL, FALSE); + + vbuf = secLayerGetBuffer (layer); + XDBG_RETURN_VAL_IF_FAIL (vbuf != NULL, FALSE); + + width = vbuf->width; + height = vbuf->height; + + if (width != pSecMode->main_lcd_mode.hdisplay || height != pSecMode->main_lcd_mode.vdisplay) + { + XDBG_ERROR (MEXA, "layer size(%d,%d) should be (%dx%d). pixmap(%d,%d %dx%d)\n", + width, height, pSecMode->main_lcd_mode.hdisplay, pSecMode->main_lcd_mode.vdisplay, + pPixmap->screen_x, pPixmap->screen_y, pPixmap->drawable.width, pPixmap->drawable.height); + return FALSE; + } + + privPixmap->bo = secRenderBoRef (vbuf->bo[0]); + + privPixmap->ovl_layer = secLayerRef (layer); + + XDBG_TRACE (MEXA, "CREATE_PIXMAP_OVERLAY(%p) : (x,y,w,h)=(%d,%d,%d,%d)\n", + pPixmap, pPixmap->drawable.x, pPixmap->drawable.y, width, height); + + return TRUE; + } + else if(pPixmap->usage_hint == CREATE_PIXMAP_USAGE_XVIDEO) + { + SECCvtProp prop = {0,}; + tbm_bo old_bo = privPixmap->bo; + + prop.id = FOURCC_RGB32; + prop.width = width; + prop.height = height; + prop.crop.width = width; + prop.crop.height = height; + + secCvtEnsureSize (NULL, &prop); + + privPixmap->bo = secRenderBoCreate(pScrn, prop.width, prop.height); + if (!privPixmap->bo) + { + XDBG_ERROR (MEXA, "Error: cannot create a xvideo buffer\n"); + privPixmap->bo = old_bo; + return FALSE; + } + + pPixmap->devKind = prop.width * 4; + + lSizeInBytes = pPixmap->drawable.height * pPixmap->devKind; + pSec->pix_dri2_flip_back = pSec->pix_dri2_flip_back + lSizeInBytes; + + privPixmap->usage_hint = pPixmap->usage_hint; + privPixmap->isFrameBuffer = FALSE; + privPixmap->size = lSizeInBytes; + + XDBG_TRACE (MEXA, "CREATE_PIXMAP_USAGE_XVIDEO(%p) : bo:%p (x,y,w,h)=(%d,%d,%d,%d)\n", + pPixmap, privPixmap->bo, pPixmap->drawable.x, pPixmap->drawable.y, width, height); + + if (old_bo) + tbm_bo_unref (old_bo); + + return TRUE; + } + else if(pPixmap->usage_hint == CREATE_PIXMAP_USAGE_DRI2_FLIP_BACK) + { + privPixmap->bo = secRenderBoCreate(pScrn, width, height); + if (!privPixmap->bo) + { + XDBG_ERROR (MEXA, "Error: cannot create a back flip buffer\n"); + return FALSE; + } + lSizeInBytes = pPixmap->drawable.height * pPixmap->devKind; + pSec->pix_dri2_flip_back = pSec->pix_dri2_flip_back + lSizeInBytes; + + privPixmap->usage_hint = pPixmap->usage_hint; + privPixmap->isFrameBuffer = TRUE; + privPixmap->size = lSizeInBytes; + + XDBG_TRACE (MEXA, "CREATE_PIXMAP_DRI2_FLIP_BACK(%p) : bo:%p (x,y,w,h)=(%d,%d,%d,%d)\n", + pPixmap, privPixmap->bo, pPixmap->drawable.x, pPixmap->drawable.y, width, height); + + return TRUE; + } + else if (pPixmap->usage_hint == CREATE_PIXMAP_USAGE_DRI2_BACK) + { + lSizeInBytes = pPixmap->drawable.height * pPixmap->devKind; + privPixmap->usage_hint = pPixmap->usage_hint; + + privPixmap->bo = tbm_bo_alloc (pSec->tbm_bufmgr, lSizeInBytes, TBM_BO_DEFAULT); + if (privPixmap->bo == NULL) + { + XDBG_ERROR(MEXA, "Error on allocating BufferObject. size:%d\n",lSizeInBytes); + return FALSE; + } + pSec->pix_dri2_back = pSec->pix_dri2_back + lSizeInBytes; + privPixmap->size = lSizeInBytes; + + XDBG_TRACE (MEXA, "CREATE_PIXMAP_USAGE_DRI2_BACK(%p) : bo:%p (x,y,w,h)=(%d,%d,%d,%d)\n", + pPixmap, privPixmap->bo, + pPixmap->drawable.x, pPixmap->drawable.y, width, height); + + return TRUE; + + } + else if (pPixmap->usage_hint == CREATE_PIXMAP_USAGE_BACKING_PIXMAP) + { + lSizeInBytes = pPixmap->drawable.height * pPixmap->devKind; + privPixmap->usage_hint = pPixmap->usage_hint; + + privPixmap->bo = tbm_bo_alloc (pSec->tbm_bufmgr, lSizeInBytes, TBM_BO_DEFAULT); + if (privPixmap->bo == NULL) + { + XDBG_ERROR(MEXA, "Error on allocating BufferObject. size:%d\n",lSizeInBytes); + return FALSE; + } + pSec->pix_backing_pixmap = pSec->pix_backing_pixmap + lSizeInBytes; + privPixmap->size = lSizeInBytes; + + XDBG_TRACE (MEXA, "CREATE_PIXMAP_USAGE_BACKING_PIXMAP(%p) : bo:%p (x,y,w,h)=(%d,%d,%d,%d)\n", + pPixmap, privPixmap->bo, + pPixmap->drawable.x, pPixmap->drawable.y, width, height); + + return TRUE; + + } + + if(privPixmap->bo != NULL) + { + tbm_bo_unref (privPixmap->bo); + privPixmap->bo = NULL; + } + + lSizeInBytes = pPixmap->drawable.height * pPixmap->devKind; + privPixmap->usage_hint = pPixmap->usage_hint; + + /* pPixData is also set for text glyphs or SHM-PutImage */ + if (pPixData) + { + privPixmap->pPixData = pPixData; + /* + privPixmap->bo = tbm_bo_attach(pSec->tbm_bufmgr, + NULL, + TBM_MEM_USERPTR, + lSizeInBytes, (unsigned int)pPixData); + */ + } + else + { + /* create the pixmap private memory */ + if (lSizeInBytes && privPixmap->bo == NULL) + { + privPixmap->bo = tbm_bo_alloc (pSec->tbm_bufmgr, lSizeInBytes, TBM_BO_DEFAULT); + if (privPixmap->bo == NULL) + { + XDBG_ERROR(MEXA, "Error on allocating BufferObject. size:%d\n",lSizeInBytes); + return FALSE; + } + } + pSec->pix_normal = pSec->pix_normal + lSizeInBytes; + } + + XDBG_TRACE (MEXA, "CREATE_PIXMAP_NORMAL(%p) : bo:%p, pPixData:%p (%dx%d+%d+%d)\n", + pPixmap, privPixmap->bo, pPixData, + width, height, + pPixmap->drawable.x, pPixmap->drawable.y); + + return TRUE; +} + +static Bool +SECExaPixmapIsOffscreen (PixmapPtr pPix) +{ + return TRUE; +} + +Bool +secExaInit (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + ExaDriverPtr pExaDriver; + SECPtr pSec = SECPTR (pScrn); + SECExaPrivPtr pExaPriv; + unsigned int cpp = 4; + + /* allocate the pExaPriv private */ + pExaPriv = calloc (1, sizeof (*pExaPriv)); + if (pExaPriv == NULL) + return FALSE; + + /* allocate the EXA driver private */ + pExaDriver = exaDriverAlloc(); + if (pExaDriver == NULL) + { + free (pExaPriv); + return FALSE; + } + + /* version of exa */ + pExaDriver->exa_major = EXA_VERSION_MAJOR; + pExaDriver->exa_minor = EXA_VERSION_MINOR; + + /* setting the memory stuffs */ + pExaDriver->memoryBase = (void*)ROOT_FB_ADDR; + pExaDriver->memorySize = pScrn->videoRam * 1024; + pExaDriver->offScreenBase = pScrn->displayWidth * cpp * pScrn->virtualY; + + pExaDriver->maxX = 1 << 16; + pExaDriver->maxY = 1 << 16; + pExaDriver->pixmapOffsetAlign = 0; + pExaDriver->pixmapPitchAlign = 8; + pExaDriver->flags = (EXA_OFFSCREEN_PIXMAPS | EXA_HANDLES_PIXMAPS + |EXA_SUPPORTS_OFFSCREEN_OVERLAPS + |EXA_SUPPORTS_PREPARE_AUX); + + pExaDriver->WaitMarker = SECExaWaitMarker; + pExaDriver->PrepareAccess = SECExaPrepareAccess; + pExaDriver->FinishAccess = SECExaFinishAccess; + + pExaDriver->CreatePixmap = SECExaCreatePixmap; + pExaDriver->DestroyPixmap = SECExaDestroyPixmap; + pExaDriver->ModifyPixmapHeader = SECExaModifyPixmapHeader; + pExaDriver->PixmapIsOffscreen = SECExaPixmapIsOffscreen; + + /* call init function */ + if (pSec->is_sw_exa) + { + if (secExaSwInit (pScreen, pExaDriver)) + { + XDBG_INFO (MEXA, "Initialized SEC SW_EXA acceleration OK !\n"); + } + else + { + free (pExaPriv); + free (pExaDriver); + FatalError ("Failed to initialize SW_EXA\n"); + return FALSE; + } + } + else + { + if (secExaG2dInit (pScreen, pExaDriver)) + { + XDBG_INFO (MEXA, "Initialized SEC HW_EXA acceleration OK !\n"); + } + else + { + free (pExaPriv); + free (pExaDriver); + FatalError ("Failed to initialize HW_EXA\n"); + return FALSE; + } + } + + /* exa driver init with exa driver private */ + if (exaDriverInit (pScreen, pExaDriver)) + { + pExaPriv->pExaDriver = pExaDriver; + pSec->pExaPriv = pExaPriv; + } + else + { + free (pExaDriver); + free (pExaPriv); + FatalError ("Failed to initialize EXA...exaDriverInit\n"); + return FALSE; + } + + /* block handler */ + RegisterBlockAndWakeupHandlers (_secExaBlockHandler /*blockHandler*/, + NULL /*wakeupHandler*/, + NULL /*blockData*/); + + xf86DrvMsg (pScrn->scrnIndex, X_INFO + , "EXA driver is Loaded successfully\n"); + + return TRUE; +} + +void +secExaDeinit (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = SECPTR (pScrn); + + /* call Fini function */ + if (pSec->is_sw_exa) + { + secExaSwDeinit (pScreen); + XDBG_INFO (MEXA, "Finish SW EXA acceleration.\n"); + } + + xf86DrvMsg (pScrn->scrnIndex, X_INFO + , "EXA driver is UnLoaded successfully\n"); +} + +Bool +secExaPrepareAccess (PixmapPtr pPix, int index) +{ + return SECExaPrepareAccess (pPix, index); +} + +void +secExaFinishAccess (PixmapPtr pPix, int index) +{ + SECExaFinishAccess (pPix, index); +} + +int +secExaScreenAsyncSwap (ScreenPtr pScreen, int enable) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = SECPTR (pScrn); + + if(enable == -1) + return pSec->useAsyncSwap; + + if ( enable == 1) + pSec->useAsyncSwap = TRUE; + else + pSec->useAsyncSwap = FALSE; + + return pSec->useAsyncSwap; +} + +int +secExaScreenSetScrnPixmap (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + PixmapPtr pPix = (*pScreen->GetScreenPixmap) (pScreen); + unsigned int pitch = pScrn->virtualX * 4; + (*pScreen->ModifyPixmapHeader) (pPix, pScrn->virtualX, pScrn->virtualY, + -1, -1, pitch, (void*)ROOT_FB_ADDR); + pScrn->displayWidth = pitch / 4; + return 1; +} + +Bool +secExaMigratePixmap (PixmapPtr pPix, tbm_bo bo) +{ + SECPixmapPriv *privPixmap = exaGetPixmapDriverPrivate (pPix); + + tbm_bo_unref (privPixmap->bo); + privPixmap->bo = tbm_bo_ref(bo); + + return TRUE; +} + +tbm_bo +secExaPixmapGetBo (PixmapPtr pPix) +{ + tbm_bo bo = NULL; + SECPixmapPriv *pExaPixPriv = NULL; + + if (pPix == NULL) + return 0; + + pExaPixPriv = exaGetPixmapDriverPrivate (pPix); + if (pExaPixPriv == NULL) + return 0; + + bo = pExaPixPriv->bo; + + return bo; +} diff --git a/src/accel/sec_exa_g2d.c b/src/accel/sec_exa_g2d.c new file mode 100755 index 0000000..c0e4858 --- /dev/null +++ b/src/accel/sec_exa_g2d.c @@ -0,0 +1,1726 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@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 "sec.h" +#include "sec_accel.h" +#include "sec_util.h" +#include "sec_layer.h" +#include "exa.h" +#include "fbpict.h" +#include "neonmem.h" +#include "g2d/fimg2d.h" + +#define DO(x) ((x.bDo==DO_DRAW_NONE)?"SKIP": \ + ((x.bDo==DO_DRAW_SW)?"SW":"HW")) + +#define PIXINFO(pPixmap) if(pPixmap) { \ + XDBG_TRACE(MEXAH, "%s:%p(0x%x) %dx%d depth:%d(%d) pitch:%d\n", \ + #pPixmap, \ + pPixmap, ID(pPixmap), \ + pPixmap->drawable.width, pPixmap->drawable.height, \ + pPixmap->drawable.depth, \ + pPixmap->drawable.bitsPerPixel, \ + pPixmap->devKind); \ + } + +#define PICINFO(pPic) if(pPic) { \ + XDBG_TRACE(MEXAH, "%s, draw:%p, repeat:%d(%d), ca:%d, srcPict:%p\n", \ + #pPic, \ + pPic->pDrawable, \ + pPic->repeat, pPic->repeatType, \ + pPic->componentAlpha, \ + pPic->pSourcePict); \ + if(pPic->transform) { \ + XDBG_TRACE("EXA2D", "\t0x%08x 0x%08x 0x%08x\n", \ + pPic->transform->matrix[0][0], \ + pPic->transform->matrix[0][1], \ + pPic->transform->matrix[0][2]); \ + XDBG_TRACE("EXA2D", "\t0x%08x 0x%08x 0x%08x\n", \ + pPic->transform->matrix[1][0], \ + pPic->transform->matrix[1][1], \ + pPic->transform->matrix[1][2]); \ + XDBG_TRACE("EXA2D", "\t0x%08x 0x%08x 0x%08x\n", \ + pPic->transform->matrix[1][0], \ + pPic->transform->matrix[1][1], \ + pPic->transform->matrix[1][2]); \ + }\ + } + +typedef struct +{ + BoxRec pos; + PixmapPtr pixmap; + tbm_bo bo; + + unsigned int access_device; /*TBM_DEVICE_XXX*/ + unsigned int access_data; /*pointer or gem*/ + G2dImage* imgG2d; +} ExaOpBuf; + +typedef struct +{ + int refcnt; + int opt; + int num; + int isSame; + + ExaOpBuf buf[5]; +} ExaOpInfo; + +typedef struct +{ + BoxRec box; + int state; /*state of region*/ + + struct xorg_list link; + + ExaOpBuf *pSrc; + ExaOpBuf *pMask; + ExaOpBuf *pDst; +} ExaBox; + +enum{ + DO_DRAW_NONE, + DO_DRAW_SW, + DO_DRAW_HW +}; + +typedef struct +{ + char bDo; + + int alu; + Pixel planemask; + Pixel fg; + PixmapPtr pixmap; + + int x,y,w,h; + GCPtr pGC; + ExaOpInfo* pOpDst; + struct xorg_list opBox; +} OpSolid; + +typedef struct +{ + char bDo; + + Pixel pm; + int alu; + int reverse; + int upsidedown; + PixmapPtr pSrcPix; + PixmapPtr pDstPix; + + /*copy param*/ + int srcX; + int srcY; + int dstX; + int dstY; + int width, height; + + ExaOpInfo* pOpDst; + ExaOpInfo* pOpSrc; + struct xorg_list opBox; +} OpCopy; + +typedef struct +{ + char bDo; + + int op; + PicturePtr pSrcPicture; + PicturePtr pMaskPicture; + PicturePtr pDstPicture; + PixmapPtr pSrcPixmap; + PixmapPtr pMaskPixmap; + PixmapPtr pDstPixmap; + + /*copy param*/ + int srcX, srcY; + int maskX, maskY; + int dstX, dstY; + int width, height; + + char srcRepeat; + char srcRotate; + double srcScaleX; + double srcScaleY; + + char maskRepeat; + char maskRotate; + double maskScaleX; + double maskScaleY; + + ExaOpInfo* pOpSrc; + ExaOpInfo* pOpMask; + ExaOpInfo* pOpDst; + struct xorg_list opBox; +} OpComposite; + +typedef struct +{ + char bDo; + + PixmapPtr pDst; + int x,y,w,h; + char* src; + int src_pitch; + + G2dImage* imgSrc; + ExaOpInfo* pOpDst; + struct xorg_list opBox; +} OpUTS; + +typedef struct +{ + char bDo; + + PixmapPtr pSrc; + int x,y,w,h; + char* dst; + int dst_pitch; + + G2dImage* imgDst; + ExaOpInfo* pOpSrc; + struct xorg_list opBox; +} OpDFS; + +typedef void (* DoDrawProcPtr) (PixmapPtr pPix, Bool isPart, + int x, int y, + int clip_x, int clip_y, + int w, int h, void* data); + +typedef void (* DoDrawProcPtrEx) (ExaBox* box, void* data); + +static ExaOpInfo OpInfo[EXA_NUM_PREPARE_INDICES]; +static OpSolid gOpSolid; +static OpCopy gOpCopy; +static OpComposite gOpComposite; +static OpUTS gOpUTS; +static OpDFS gOpDFS; + +ExaBox* _g2dBoxAdd (struct xorg_list *l, BoxPtr b1, BoxPtr b2) +{ + ExaBox* rgn; + + rgn = calloc (1, sizeof (ExaBox)); + XDBG_RETURN_VAL_IF_FAIL ((rgn != NULL), NULL); + + rgn->state = secUtilBoxIntersect (&rgn->box, b1, b2); + if (rgnOUT == rgn->state) + { + free (rgn); + return NULL; + } + + xorg_list_add (&rgn->link, l); + return rgn; +} + +void _g2dBoxMerge (struct xorg_list *l, struct xorg_list* b, struct xorg_list* t) +{ + ExaBox *b1 = NULL, *b2 = NULL; + ExaBox* r = NULL; + + xorg_list_for_each_entry (b1, b, link) + { + xorg_list_for_each_entry (b2, t, link) + { + r = _g2dBoxAdd (l, &b1->box, &b2->box); + if (r) + { + r->pSrc = b1->pSrc ? b1->pSrc : b2->pSrc; + r->pMask= b1->pMask ? b1->pMask : b2->pMask; + r->pDst = b1->pDst ? b1->pDst : b2->pDst; + } + } + } +} + +void _g2dBoxMove (struct xorg_list* l, int tx, int ty) +{ + ExaBox *b = NULL; + + xorg_list_for_each_entry (b, l, link) + { + secUtilBoxMove (&b->box, tx, ty); + } +} + +void _g2dBoxRemoveAll (struct xorg_list* l) +{ + ExaBox *ref = NULL, *next = NULL; + + xorg_list_for_each_entry_safe (ref, next, l, link) + { + xorg_list_del (&ref->link); + free (ref); + } +} + +int _g2dBoxIsOne (struct xorg_list* l) +{ + if (l->next != l) + { + if (l->next == l->prev) + return 1; + else + return -1; + } + + return 0; +} + +void _g2dBoxPrint (ExaBox* sb1, const char* name) +{ + ExaBox *b = NULL; + + xorg_list_for_each_entry (b, &sb1->link, link) + { + XDBG_DEBUG (MEXAS, "[%s] %d,%d - %d,%d\n", name, + b->box.x1, b->box.y1, b->box.x2, b->box.y2); + } +} + +static pixman_bool_t +_g2d_check_within_epsilon (pixman_fixed_t a, + pixman_fixed_t b, + pixman_fixed_t epsilon) +{ + pixman_fixed_t t = a - b; + + if (t < 0) + t = -t; + + return t <= epsilon; +} + +static Bool +_g2d_check_picture(PicturePtr pPicture, char *rot90, double *scaleX, double *scaleY, char* repeat) +{ + struct pixman_transform* t; + +#define EPSILON (pixman_fixed_t) (2) + +#define IS_SAME(a, b) (_g2d_check_within_epsilon (a, b, EPSILON)) +#define IS_ZERO(a) (_g2d_check_within_epsilon (a, 0, EPSILON)) +#define IS_ONE(a) (_g2d_check_within_epsilon (a, F (1), EPSILON)) +#define IS_UNIT(a) \ + (_g2d_check_within_epsilon (a, F (1), EPSILON) || \ + _g2d_check_within_epsilon (a, F (-1), EPSILON) || \ + IS_ZERO (a)) +#define IS_INT(a) (IS_ZERO (pixman_fixed_frac (a))) + +/*RepeatNormal*/ + + if(pPicture == NULL) + { + return TRUE; + } + + if(pPicture->repeat) + { + switch(pPicture->repeatType) + { + case RepeatNormal: + *repeat = G2D_REPEAT_MODE_REPEAT; + break; + case RepeatPad: + *repeat = G2D_REPEAT_MODE_PAD; + break; + case RepeatReflect: + *repeat = G2D_REPEAT_MODE_REFLECT; + break; + default: + *repeat = G2D_REPEAT_MODE_NONE; + break; + } + } + else + { + *repeat = G2D_REPEAT_MODE_NONE; + } + + if(pPicture->transform == NULL) + { + *rot90 = 0; + *scaleX = 1.0; + *scaleY = 1.0; + return TRUE; + } + + t= pPicture->transform; + + if(!IS_ZERO(t->matrix[0][0]) && IS_ZERO(t->matrix[0][1]) && IS_ZERO(t->matrix[1][0]) && !IS_ZERO(t->matrix[1][1])) + { + *rot90 = FALSE; + *scaleX = pixman_fixed_to_double(t->matrix[0][0]); + *scaleY = pixman_fixed_to_double(t->matrix[1][1]); + } + else if(IS_ZERO(t->matrix[0][0]) && !IS_ZERO(t->matrix[0][1]) && !IS_ZERO(t->matrix[1][0]) && IS_ZERO(t->matrix[1][1])) + { + /* FIMG2D 90 => PIXMAN 270 */ + *rot90 = TRUE; + *scaleX = pixman_fixed_to_double(t->matrix[0][1]); + *scaleY = pixman_fixed_to_double(t->matrix[1][0]*-1); + } + else + { + return FALSE; + } + + return TRUE; +} + +static Bool +_g2dIsSupport(PixmapPtr pPix, Bool forMask) +{ + SECPixmapPriv *privPixmap; + + if(!pPix) return TRUE; + + if(!forMask && pPix->drawable.depth < 8) + return FALSE; + + privPixmap = (SECPixmapPriv*)exaGetPixmapDriverPrivate (pPix); + if(!privPixmap->isFrameBuffer && !privPixmap->bo) + return FALSE; + + return TRUE; +} + +static G2dImage* +_g2dGetImageFromPixmap(PixmapPtr pPix, unsigned int gem) +{ + G2dImage* img; + G2dColorKeyMode mode; + + if(gem == 0) + { + gem = (unsigned int)pPix->devPrivate.ptr; + } + + XDBG_RETURN_VAL_IF_FAIL((pPix != NULL && gem != 0), NULL); + + switch(pPix->drawable.depth) + { + case 32: + mode = G2D_COLOR_FMT_ARGB8888|G2D_ORDER_AXRGB; + break; + case 24: + mode = G2D_COLOR_FMT_XRGB8888|G2D_ORDER_AXRGB; + break; + case 16: + mode = G2D_COLOR_FMT_RGB565|G2D_ORDER_AXRGB; + break; + case 8: + mode = G2D_COLOR_FMT_A8|G2D_ORDER_AXRGB; + break; + case 1: + mode = G2D_COLOR_FMT_A1|G2D_ORDER_AXRGB; + break; + default: + XDBG_ERROR(MEXA, "Unsupport format depth:%d(%d),pitch:%d \n", + pPix->drawable.depth, pPix->drawable.bitsPerPixel, pPix->devKind); + return NULL; + } + + img = g2d_image_create_bo(mode, + pPix->drawable.width, + pPix->drawable.height, + gem, + pPix->devKind); + + return img; +} + +static ExaOpInfo* _g2dPrepareAccess (PixmapPtr pPix, int index, unsigned int device) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = SECPTR (pScrn); + SECPixmapPriv *privPixmap = (SECPixmapPriv*)exaGetPixmapDriverPrivate (pPix); + ExaOpInfo* op = &OpInfo[index]; + int opt = TBM_OPTION_READ; + int i; + tbm_bo *bos = NULL; + tbm_bo_handle bo_handle; + SECFbBoDataPtr bo_data; + int num_bo; + int ret; + + XDBG_RETURN_VAL_IF_FAIL ((privPixmap != NULL), NULL); + + if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) + opt |= TBM_OPTION_WRITE; + + /* Check mapped */ + if (privPixmap->exaOpInfo) + { + op = (ExaOpInfo*)privPixmap->exaOpInfo; + op->refcnt++; + XDBG_TRACE (MEXAH, "pix:%p index:%d hint:%d ptr:%p ref:%d\n", + pPix, index, pPix->usage_hint, pPix->devPrivate.ptr, op->refcnt); + return op; + } + + /*Set buffer info*/ + memset (op, 0x00, sizeof (ExaOpInfo)); + op->refcnt = 1; + op->opt = opt; + op->isSame = 0; + + if (pPix->usage_hint == CREATE_PIXMAP_USAGE_FB) + { + ret = secFbFindBo (pSec->pFb, + pPix->drawable.x, pPix->drawable.y, + pPix->drawable.width, pPix->drawable.height, + &num_bo, &bos); + XDBG_TRACE (MEXAH,"FB ret:%d num_pix:%d, %dx%d+%d+%d\n", + ret, num_bo, + pPix->drawable.width, pPix->drawable.height, + pPix->drawable.x, pPix->drawable.y); + + if (ret == rgnSAME && num_bo == 1) + { + op->num = 1; + op->isSame = 1; + + op->buf[0].pixmap = pPix; + op->buf[0].bo = bos[0]; + op->buf[0].pos.x1 = 0; + op->buf[0].pos.y1 = 0; + op->buf[0].pos.x2 = pPix->drawable.width; + op->buf[0].pos.y2 = pPix->drawable.height; + + op->buf[0].access_device = device; + bo_handle = tbm_bo_map (op->buf[0].bo, device, op->opt); + op->buf[0].access_data = bo_handle.u32; + op->buf[0].pixmap->devPrivate.ptr = (pointer)op->buf[0].access_data; + if(device == TBM_DEVICE_2D) + { + op->buf[0].imgG2d = _g2dGetImageFromPixmap(op->buf[0].pixmap, + op->buf[0].access_data); + } + } + else + { + op->num = num_bo; + op->isSame = 0; + + for (i = 0; i < num_bo; i++) + { + tbm_bo_get_user_data (bos[i], TBM_BO_DATA_FB, (void**)&bo_data); + op->buf[i].pixmap = secRenderBoGetPixmap (pSec->pFb, bos[i]); + op->buf[i].bo = bos[i]; + op->buf[i].pos = bo_data->pos; + + op->buf[i].access_device = device; + bo_handle = tbm_bo_map (op->buf[i].bo, device, op->opt); + op->buf[i].access_data = bo_handle.u32; + op->buf[i].pixmap->devPrivate.ptr = (pointer)op->buf[i].access_data; + if(device == TBM_DEVICE_2D) + { + op->buf[i].imgG2d = _g2dGetImageFromPixmap(op->buf[i].pixmap, + op->buf[i].access_data); + } + } + } + if (bos) + free (bos); + } + else + { + op->num = 1; + op->isSame = 1; + + op->buf[0].pixmap = pPix; + op->buf[0].bo = privPixmap->bo; + op->buf[0].pos.x1 = 0; + op->buf[0].pos.y1 = 0; + op->buf[0].pos.x2 = pPix->drawable.width; + op->buf[0].pos.y2 = pPix->drawable.height; + + op->buf[0].access_device = device; + if (privPixmap->bo) + { + bo_handle = tbm_bo_map (op->buf[0].bo, device, op->opt); + op->buf[0].access_data = bo_handle.u32; + if(device == TBM_DEVICE_2D) + { + op->buf[0].imgG2d = _g2dGetImageFromPixmap(op->buf[0].pixmap, op->buf[0].access_data); + } + } + else + { + op->buf[0].access_data = (unsigned int)privPixmap->pPixData; + op->buf[0].imgG2d = NULL; + } + op->buf[0].pixmap->devPrivate.ptr = (pointer)op->buf[0].access_data; + } + + privPixmap->exaOpInfo = op; + + XDBG_TRACE (MEXAH, "pix:%p index:%d hint:%d ptr:%p ref:%d\n", + pPix, index, pPix->usage_hint, pPix->devPrivate.ptr, op->refcnt); + return op; +} + +static void _g2dFinishAccess (PixmapPtr pPix, int index) +{ + XDBG_RETURN_IF_FAIL (pPix!=NULL); + + SECPixmapPriv *privPixmap = (SECPixmapPriv*)exaGetPixmapDriverPrivate (pPix); + ExaOpInfo* op; + int i; + + XDBG_RETURN_IF_FAIL (privPixmap!=NULL); + XDBG_RETURN_IF_FAIL (privPixmap->exaOpInfo!=NULL); + + op = (ExaOpInfo*)privPixmap->exaOpInfo; + op->refcnt --; + + if (op->refcnt == 0) + { + for (i=0; i<op->num; i++) + { + if(op->buf[i].bo) + { + tbm_bo_unmap(op->buf[i].bo); + op->buf[i].bo = NULL; + } + + if(op->buf[i].pixmap) + { + op->buf[i].pixmap->devPrivate.ptr = NULL; + op->buf[i].pixmap = NULL; + } + + if(op->buf[i].imgG2d) + { + g2d_image_free(op->buf[i].imgG2d); + op->buf[i].imgG2d = NULL; + } + + op->buf[i].access_data = (unsigned int)NULL; + } + + privPixmap->exaOpInfo = NULL; + } + + if (pPix->usage_hint == CREATE_PIXMAP_USAGE_OVERLAY) + secLayerUpdate (secLayerFind (LAYER_OUTPUT_LCD, LAYER_UPPER)); + + XDBG_TRACE (MEXAH, "pix:%p index:%d hint:%d ptr:%p ref:%d\n", + pPix, index, pPix->usage_hint, pPix->devPrivate.ptr, op->refcnt); +} + +void +_g2dDoDraw (struct xorg_list *l, DoDrawProcPtrEx do_draw, void* data) +{ + ExaBox *box = NULL; + xorg_list_for_each_entry (box, l, link) + { + do_draw (box, data); + } +} + +static void +_g2dDoSolid (ExaBox* box, void* data) +{ + XDBG_TRACE (MEXAH, "[%s] (%d,%d), (%d,%d) off(%d,%d)\n", + DO(gOpSolid), + box->box.x1, + box->box.y1, + box->box.x2, + box->box.y2, + gOpSolid.x, + gOpSolid.y); + + if(gOpSolid.bDo == DO_DRAW_SW) + { + fbFill (&box->pDst->pixmap->drawable, + gOpSolid.pGC, + box->box.x1 + gOpSolid.x - box->pDst->pos.x1, + box->box.y1 + gOpSolid.y - box->pDst->pos.y1, + box->box.x2- box->box.x1, + box->box.y2- box->box.y1); + } + else + { + util_g2d_fill_alu(box->pDst->imgG2d, + box->box.x1 + gOpSolid.x - box->pDst->pos.x1, + box->box.y1 + gOpSolid.y - box->pDst->pos.y1, + box->box.x2- box->box.x1, + box->box.y2- box->box.y1, + gOpSolid.fg, + (G2dAlu)gOpSolid.alu); + } +} + +static void +_g2dDoCopy (ExaBox* box, void* data) +{ + CARD8 alu = gOpCopy.alu; + FbBits pm = gOpCopy.pm; + FbBits *src; + FbStride srcStride; + int srcBpp; + FbBits *dst; + FbStride dstStride; + int dstBpp; + _X_UNUSED int srcXoff, srcYoff; + _X_UNUSED int dstXoff, dstYoff; + int srcX, srcY, dstX, dstY, width, height; + + XDBG_TRACE (MEXAH, "[%s] box(%d,%d),(%d,%d) src(%d,%d) dst(%d,%d)\n", + DO(gOpCopy), + box->box.x1, + box->box.y1, + box->box.x2, + box->box.y2, + gOpCopy.srcX, + gOpCopy.srcY); + + srcX = gOpCopy.srcX + box->box.x1 - box->pSrc->pos.x1; + srcY = gOpCopy.srcY + box->box.y1 - box->pSrc->pos.y1; + dstX = gOpCopy.dstX + box->box.x1 - box->pDst->pos.x1; + dstY = gOpCopy.dstY + box->box.y1 - box->pDst->pos.y1; + width = box->box.x2 - box->box.x1; + height = box->box.y2 - box->box.y1; + + if(gOpCopy.bDo == DO_DRAW_SW) + { + fbGetDrawable (&box->pSrc->pixmap->drawable, src, srcStride, srcBpp, srcXoff, srcYoff); + fbGetDrawable (&box->pDst->pixmap->drawable, dst, dstStride, dstBpp, dstXoff, dstYoff); + /* temp fix : do right things later */ + if (!src || !dst) + { + return; + } + + if (pm != FB_ALLONES || + alu != GXcopy || + gOpCopy.reverse || + gOpCopy.upsidedown || + !pixman_blt ((uint32_t *)src, (uint32_t *)dst, + srcStride, + dstStride, + srcBpp, dstBpp, + srcX, srcY, dstX, dstY, width, height)) + { + fbBlt (src + srcY * srcStride, + srcStride, + srcX * srcBpp, + + dst + dstY * dstStride, + dstStride, + dstX * dstBpp, + + width * dstBpp, + height, + + alu, + pm, + dstBpp, + + gOpCopy.reverse, + gOpCopy.upsidedown); + } + } + else + { + util_g2d_copy_alu(box->pSrc->imgG2d, + box->pDst->imgG2d, + srcX, srcY, + dstX, dstY, + width, height, + gOpCopy.alu); + } +} + +static void +_g2dDoComposite (ExaBox* box, void* data) +{ + + if (box->state == rgnPART) + { + XDBG_RETURN_IF_FAIL (gOpComposite.pSrcPicture->transform == NULL); + XDBG_RETURN_IF_FAIL (gOpComposite.pMaskPicture && + gOpComposite.pMaskPicture->transform == NULL); + } + + if (gOpComposite.bDo == DO_DRAW_SW) + { + PicturePtr pDstPicture; + pixman_image_t *src, *mask, *dest; + int src_xoff, src_yoff, msk_xoff, msk_yoff; + FbBits *bits; + FbStride stride; + int bpp; + + pDstPicture = gOpComposite.pDstPicture; + + src = image_from_pict (gOpComposite.pSrcPicture, FALSE, &src_xoff, &src_yoff); + mask = image_from_pict (gOpComposite.pMaskPicture, FALSE, &msk_xoff, &msk_yoff); + + fbGetPixmapBitsData (box->pDst->pixmap, bits, stride, bpp); + dest = pixman_image_create_bits (pDstPicture->format, + box->pDst->pixmap->drawable.width, + box->pDst->pixmap->drawable.height, + (uint32_t *)bits, stride * sizeof (FbStride)); + XDBG_RETURN_IF_FAIL (dest != NULL); + + pixman_image_composite (gOpComposite.op, + src, mask, dest, + gOpComposite.srcX + box->box.x1, + gOpComposite.srcY + box->box.y1, + gOpComposite.maskX + box->box.x1, + gOpComposite.maskY + box->box.y1, + gOpComposite.dstX + box->box.x1 - box->pDst->pos.x1, + gOpComposite.dstY + box->box.y1 - box->pDst->pos.y1, + box->box.x2 - box->box.x1, + box->box.y2 - box->box.y1); + + free_pixman_pict (gOpComposite.pSrcPicture, src); + free_pixman_pict (gOpComposite.pMaskPicture, mask); + pixman_image_unref (dest); + } + else + { + util_g2d_composite (gOpComposite.op, + box->pSrc->imgG2d, + box->pMask ? box->pMask->imgG2d:NULL, + box->pDst->imgG2d, + gOpComposite.srcX + box->box.x1, + gOpComposite.srcY + box->box.y1, + gOpComposite.maskX + box->box.x1, + gOpComposite.maskY + box->box.y1, + gOpComposite.dstX + box->box.x1 - box->pDst->pos.x1, + gOpComposite.dstY + box->box.y1 - box->pDst->pos.y1, + box->box.x2 - box->box.x1, + box->box.y2 - box->box.y1); + } +} + +static void +_g2dDoUploadToScreen (ExaBox* box, void* data) +{ + int dstX, dstY; + int width, height; + + dstX = gOpUTS.x + box->box.x1 - box->pDst->pos.x1; + dstY = gOpUTS.y + box->box.y1 - box->pDst->pos.y1; + width = box->box.x2 - box->box.x1; + height = box->box.y2 - box->box.y1; + + if(gOpUTS.bDo == DO_DRAW_SW) + { + FbBits *dst; + FbStride dstStride; + int dstBpp; + _X_UNUSED int dstXoff, dstYoff; + int srcStride; + + fbGetDrawable (&box->pDst->pixmap->drawable, dst, dstStride, dstBpp, dstXoff, dstYoff); + + srcStride = gOpUTS.src_pitch/sizeof (uint32_t); + + XDBG_TRACE (MEXAH, "src(%p, %d) %d,%d,%d,%d\n", + gOpUTS.src, srcStride, dstX, dstY, width, height); + + if (!pixman_blt ((uint32_t *)gOpUTS.src, + (uint32_t *)dst, + srcStride, + dstStride, + dstBpp, dstBpp, + box->box.x1, box->box.y1, + dstX, dstY, + width, height)) + { + fbBlt ((FbBits*) ((FbBits*)gOpUTS.src), + srcStride, + box->box.x1, + + dst + dstY * dstStride, + dstStride, + dstX, + + width, + height, + + GXcopy, + ~0, + dstBpp, + + 0, + 0); + } + } + else + { + util_g2d_copy(gOpUTS.imgSrc, + box->pDst->imgG2d, + box->box.x1, box->box.y1, + dstX, dstY, + width, height); + } +} + +static void +_g2dDoDownladFromScreen (ExaBox* box, void* data) +{ + int srcX, srcY; + int width, height; + int dstStride; + + dstStride = gOpDFS.dst_pitch/sizeof (uint32_t); + srcX = gOpDFS.x + box->box.x1 - box->pSrc->pos.x1; + srcY = gOpDFS.y + box->box.y1 - box->pSrc->pos.y1; + width = box->box.x2 - box->box.x1; + height = box->box.y2 - box->box.y1; + + XDBG_TRACE (MEXAH, "dst(%p, %d) %d,%d,%d,%d\n", + gOpDFS.dst, dstStride, srcX, srcY, width, height); + + if(gOpDFS.bDo == DO_DRAW_SW) + { + FbBits *src; + FbStride srcStride; + int srcBpp; + _X_UNUSED int srcXoff, srcYoff; + + fbGetDrawable (&box->pSrc->pixmap->drawable, src, srcStride, srcBpp, srcXoff, srcYoff); + + if (!pixman_blt ((uint32_t *)src, + (uint32_t *)gOpDFS.dst, + srcStride, + dstStride, + srcBpp, srcBpp, + srcX, srcY, + box->box.x1, box->box.y1, + width, height)) + { + fbBlt (src + srcY * srcStride, + srcStride, + srcX, + + (FbBits*) ((FbBits*)gOpDFS.dst), + dstStride, + box->box.x1, + + width, + height, + + GXcopy, + ~0, + srcBpp, + + 0, + 0); + } + } + else + { + util_g2d_copy (box->pSrc->imgG2d, + gOpDFS.imgDst, + srcX, srcY, + box->box.x1, box->box.y1, + width, height); + } +} + +static Bool +SECExaG2dPrepareSolid (PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fg) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + ChangeGCVal tmpval[3]; + + XDBG_TRACE (MEXAH, "\n"); + memset (&gOpSolid, 0x00, sizeof (gOpSolid)); + + /* Put ff at the alpha bits when transparency is set to xv */ + if (pPixmap->drawable.depth == 24) + fg = fg | (~ (pScrn->mask.red|pScrn->mask.green|pScrn->mask.blue)); + + gOpSolid.alu = alu; + gOpSolid.fg = fg; + gOpSolid.planemask = planemask; + gOpSolid.pixmap = pPixmap; + + if (!_g2dIsSupport(pPixmap, 0)) + { + gOpSolid.pOpDst = _g2dPrepareAccess (pPixmap, + EXA_PREPARE_DEST, + TBM_DEVICE_CPU); + XDBG_GOTO_IF_FAIL (gOpSolid.pOpDst, bail); + + gOpSolid.pGC = GetScratchGC (pPixmap->drawable.depth, pScreen); + tmpval[0].val = alu; + tmpval[1].val = planemask; + tmpval[2].val = fg; + ChangeGC (NullClient, gOpSolid.pGC, GCFunction|GCPlaneMask|GCForeground, tmpval); + ValidateGC (&pPixmap->drawable, gOpSolid.pGC); + + gOpSolid.bDo = DO_DRAW_SW; + } + else + { + gOpSolid.pOpDst = _g2dPrepareAccess (pPixmap, + EXA_PREPARE_DEST, + TBM_DEVICE_2D); + XDBG_GOTO_IF_FAIL (gOpSolid.pOpDst, bail); + gOpSolid.bDo = DO_DRAW_HW; + } + + return TRUE; + +bail: + XDBG_TRACE (MEXAH, "FAIL: pix:%p hint:%d, num_pix:%d\n", + pPixmap, index, pPixmap->usage_hint, gOpSolid.pOpDst->num); + gOpSolid.bDo = DO_DRAW_NONE; + gOpSolid.pGC = NULL; + + return TRUE; +} + + +static void +SECExaG2dSolid (PixmapPtr pPixmap, int x1, int y1, int x2, int y2) +{ + XDBG_TRACE (MEXAH, " (%d,%d), (%d,%d)\n", x1,y1,x2,y2); + XDBG_TRACE (MEXAH, "%s\n", DO(gOpSolid)); + if (gOpSolid.bDo == DO_DRAW_NONE) return; + + gOpSolid.x = x1; + gOpSolid.y = y1; + gOpSolid.w = x2-x1; + gOpSolid.h = y2-y1; + + if (gOpSolid.pOpDst->isSame) + { + ExaBox box; + + box.state = rgnIN; + box.box.x1 = 0; + box.box.y1 = 0; + box.box.x2 = x2-x1; + box.box.y2 = y2-y1; + box.pDst = &gOpSolid.pOpDst->buf[0]; + _g2dDoSolid (&box, NULL); + } + else + { + int i; + ExaBox *box; + BoxRec b; + + /*Init box list*/ + xorg_list_init (&gOpSolid.opBox); + + b.x1 = x1; + b.y1 = y1; + b.x2 = x2; + b.y2 = y2; + + for (i=0; i<gOpSolid.pOpDst->num; i++) + { + box = _g2dBoxAdd (&gOpSolid.opBox, + &gOpSolid.pOpDst->buf[i].pos, + &b); + if (box) + { + box->pDst = &gOpSolid.pOpDst->buf[i]; + } + } + _g2dBoxMove (&gOpSolid.opBox, -x1, -y1); + + /* Call solid function */ + _g2dDoDraw (&gOpSolid.opBox, + _g2dDoSolid, NULL); + + /*Remove box list*/ + _g2dBoxRemoveAll (&gOpSolid.opBox); + } +} + +static void +SECExaG2dDoneSolid (PixmapPtr pPixmap) +{ + XDBG_TRACE (MEXAH, "\n"); + + if (gOpSolid.bDo) + g2d_exec(); + + if (gOpSolid.pGC) + { + FreeScratchGC (gOpSolid.pGC); + gOpSolid.pGC = NULL; + } + + if (gOpSolid.pixmap) + _g2dFinishAccess (gOpSolid.pixmap, EXA_PREPARE_DEST); +} + +static Bool +SECExaG2dPrepareCopy (PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, + int dx, int dy, int alu, Pixel planemask) +{ + int num_dst_pix = -1; + int num_src_pix = -1; + unsigned int draw_type = DO_DRAW_HW; + unsigned int access_device = TBM_DEVICE_2D; + + XDBG_TRACE (MEXAH, "\n"); + memset (&gOpCopy, 0x00, sizeof (gOpCopy)); + + gOpCopy.alu = alu; + gOpCopy.pm = planemask; + gOpCopy.reverse = (dx == 1)?0:1; + gOpCopy.upsidedown = (dy == 1)?0:1; + gOpCopy.pDstPix = pDstPixmap; + gOpCopy.pSrcPix = pSrcPixmap; + + /* Check capability */ + if(!_g2dIsSupport(pSrcPixmap, 0) || + !_g2dIsSupport(pDstPixmap, 0) || + gOpCopy.reverse || + gOpCopy.upsidedown) + { + draw_type = DO_DRAW_SW; + access_device = TBM_DEVICE_CPU; + } + + gOpCopy.pOpDst = _g2dPrepareAccess (pDstPixmap, EXA_PREPARE_DEST, access_device); + XDBG_GOTO_IF_FAIL (gOpCopy.pOpDst, bail); + gOpCopy.pOpSrc = _g2dPrepareAccess (pSrcPixmap, EXA_PREPARE_SRC, access_device); + XDBG_GOTO_IF_FAIL (gOpCopy.pOpDst, bail); + + gOpCopy.bDo = draw_type; + + return TRUE; + +bail: + XDBG_TRACE (MEXAH, "FAIL\n"); + XDBG_TRACE (MEXAH, " SRC pix:%p, index:%d, hint:%d, num_pix:%d\n", + pSrcPixmap, index, pSrcPixmap->usage_hint, num_src_pix); + XDBG_TRACE (MEXAH, " DST pix:%p, index:%d, hint:%d, num_pix:%d\n", + pDstPixmap, index, pDstPixmap->usage_hint, num_dst_pix); + gOpCopy.bDo = DO_DRAW_NONE; + + return TRUE; +} + + +static void +SECExaG2dCopy (PixmapPtr pDstPixmap, int srcX, int srcY, + int dstX, int dstY, int width, int height) +{ + XDBG_TRACE (MEXAH, "%s\n", DO(gOpCopy)); + XDBG_TRACE (MEXAH, "src(%d,%d) dst(%d,%d) %dx%d\n", + srcX, srcY, dstX, dstY, width, height); + + if (gOpSolid.bDo == FALSE) return; + + gOpCopy.srcX = srcX; + gOpCopy.srcY = srcY; + gOpCopy.dstX = dstX; + gOpCopy.dstY = dstY; + gOpCopy.width = width; + gOpCopy.height = height; + + if (gOpCopy.pOpSrc->isSame && gOpCopy.pOpDst->isSame) + { + ExaBox box; + + box.state = rgnIN; + box.box.x1 = 0; + box.box.y1 = 0; + box.box.x2 = width; + box.box.y2 = height; + box.pDst = &gOpCopy.pOpDst->buf[0]; + box.pSrc = &gOpCopy.pOpSrc->buf[0]; + _g2dDoCopy (&box, NULL); + } + else + { + int i; + struct xorg_list lSrc, lDst; + ExaBox *box; + BoxRec b; + + //Set Dest + b.x1 = dstX; + b.y1 = dstY; + b.x2 = dstX + width; + b.y2 = dstY + height; + xorg_list_init (&lDst); + for (i=0; i<gOpCopy.pOpDst->num; i++) + { + box = _g2dBoxAdd (&lDst, + &gOpCopy.pOpDst->buf[i].pos, + &b); + if (box) + { + box->pDst = &gOpCopy.pOpDst->buf[i]; + } + } + _g2dBoxMove (&lDst, -dstX, -dstY); + + //Set Src + b.x1 = srcX; + b.y1 = srcY; + b.x2 = srcX + width; + b.y2 = srcY + height; + + xorg_list_init (&lSrc); + for (i=0; i<gOpCopy.pOpSrc->num; i++) + { + box = _g2dBoxAdd (&lSrc, + &gOpCopy.pOpSrc->buf[i].pos, + &b); + if (box) + { + box->pSrc = &gOpCopy.pOpSrc->buf[i]; + } + } + _g2dBoxMove (&lSrc, -srcX, -srcY); + + //Merge and call copy + xorg_list_init (&gOpCopy.opBox); + _g2dBoxMerge (&gOpCopy.opBox, &lSrc, &lDst); + _g2dDoDraw (&gOpCopy.opBox, + _g2dDoCopy, NULL); + + //Remove box list + _g2dBoxRemoveAll (&lSrc); + _g2dBoxRemoveAll (&lDst); + _g2dBoxRemoveAll (&gOpCopy.opBox); + } +} + +static void +SECExaG2dDoneCopy (PixmapPtr pDstPixmap) +{ + XDBG_TRACE (MEXAH, "\n"); + if (gOpCopy.bDo == DO_DRAW_HW) + g2d_exec(); + + if (gOpCopy.pDstPix) + _g2dFinishAccess (gOpCopy.pDstPix, EXA_PREPARE_DEST); + if (gOpCopy.pSrcPix) + _g2dFinishAccess (gOpCopy.pSrcPix, EXA_PREPARE_SRC); +} + +static Bool +SECExaG2dCheckComposite (int op, PicturePtr pSrcPicture, + PicturePtr pMaskPicture, PicturePtr pDstPicture) +{ + return TRUE; +} + +static Bool +SECExaG2dPrepareComposite (int op, PicturePtr pSrcPicture, + PicturePtr pMaskPicture, PicturePtr pDstPicture, + PixmapPtr pSrcPixmap, + PixmapPtr pMaskPixmap, PixmapPtr pDstPixmap) +{ + XDBG_GOTO_IF_FAIL (pDstPixmap, bail); + XDBG_GOTO_IF_FAIL (pSrcPicture && pDstPicture, bail); + + unsigned int draw_type = DO_DRAW_HW; + unsigned int access_device = TBM_DEVICE_2D; + + XDBG_TRACE (MEXAH, "\n"); + memset (&gOpComposite, 0x00, sizeof (gOpComposite)); + + gOpComposite.op = op; + gOpComposite.pDstPicture = pDstPicture; + gOpComposite.pSrcPicture = pSrcPicture; + gOpComposite.pMaskPicture = pMaskPicture; + gOpComposite.pSrcPixmap = pSrcPixmap; + gOpComposite.pMaskPixmap = pMaskPixmap; + gOpComposite.pDstPixmap = pDstPixmap; + + if (!_g2dIsSupport(pSrcPixmap, 0) || + !_g2dIsSupport(pDstPixmap, 0) || + !_g2dIsSupport(pMaskPixmap, 1)) + { + draw_type = DO_DRAW_SW; + } + + if (!_g2d_check_picture(pSrcPicture, + &gOpComposite.srcRotate, + &gOpComposite.srcScaleX, + &gOpComposite.srcScaleY, + &gOpComposite.srcRepeat) || + !_g2d_check_picture(pMaskPicture, + &gOpComposite.maskRotate, + &gOpComposite.maskScaleX, + &gOpComposite.maskScaleY, + &gOpComposite.maskRepeat)) + { + draw_type = DO_DRAW_SW; + } + + if(draw_type == DO_DRAW_SW) + { + access_device = TBM_DEVICE_CPU; + } + + gOpComposite.pOpDst = _g2dPrepareAccess (pDstPixmap, + EXA_PREPARE_DEST, + access_device); + + if (pSrcPixmap) + { + gOpComposite.pOpSrc = _g2dPrepareAccess (pSrcPixmap, + EXA_PREPARE_SRC, + access_device); + XDBG_GOTO_IF_FAIL (gOpComposite.pOpSrc->num == 1, bail); + } + + if (pMaskPixmap) + { + gOpComposite.pOpMask = _g2dPrepareAccess (pMaskPixmap, + EXA_PREPARE_MASK, + access_device); + XDBG_GOTO_IF_FAIL (gOpComposite.pOpMask->num == 1, bail); + } + + if(draw_type == DO_DRAW_HW) + { + G2dImage *imgSrc = NULL, *imgMask = NULL; + + if(pSrcPicture) + { + if(gOpComposite.pOpSrc == NULL) + { + gOpComposite.pOpSrc = &OpInfo[EXA_PREPARE_SRC]; + gOpComposite.pOpSrc->buf[0].imgG2d = + g2d_image_create_solid((unsigned int)gOpComposite.pSrcPicture->pSourcePict->solidFill.color); + } + + imgSrc = gOpComposite.pOpSrc->buf[0].imgG2d; + } + + + if(pMaskPicture) + { + if(gOpComposite.pOpMask == NULL) + { + gOpComposite.pOpMask = &OpInfo[EXA_PREPARE_MASK]; + gOpComposite.pOpMask->buf[0].imgG2d = + g2d_image_create_solid((unsigned int)gOpComposite.pSrcPicture->pSourcePict->solidFill.color); + } + + imgMask = gOpComposite.pOpMask->buf[0].imgG2d; + } + + /*Set Repeat*/ + imgSrc->repeat_mode = gOpComposite.srcRepeat; + + /*Set Rotate */ + imgSrc->rotate_90 = gOpComposite.srcRotate; + imgSrc->xDir = (gOpComposite.srcScaleX < 0.0); + imgSrc->yDir = (gOpComposite.srcScaleY < 0.0); + + /*Set Scale*/ + if(((gOpComposite.srcScaleX != 1.0 && gOpComposite.srcScaleX != -1.0) || + (gOpComposite.srcScaleY != 1.0 && gOpComposite.srcScaleY != -1.0))) + { + imgSrc->xscale = G2D_DOUBLE_TO_FIXED(gOpComposite.srcScaleX); + imgSrc->yscale = G2D_DOUBLE_TO_FIXED(gOpComposite.srcScaleY); + imgSrc->scale_mode = G2D_SCALE_MODE_BILINEAR; + } + + if(imgMask) + { + /*Set Repeat*/ + imgMask->repeat_mode = gOpComposite.maskRepeat; + + /*Set Rotate */ + imgMask->rotate_90 = gOpComposite.maskRotate; + imgMask->xDir = (gOpComposite.maskScaleX < 0.0); + imgMask->yDir = (gOpComposite.maskScaleY < 0.0); + + /*Set Scale*/ + if(((gOpComposite.maskScaleX != 1.0 && gOpComposite.maskScaleX != -1.0) || + (gOpComposite.maskScaleY != 1.0 && gOpComposite.maskScaleY != -1.0))) + { + imgMask->xscale = G2D_DOUBLE_TO_FIXED(gOpComposite.maskScaleX); + imgMask->yscale = G2D_DOUBLE_TO_FIXED(gOpComposite.maskScaleY); + imgMask->scale_mode = G2D_SCALE_MODE_BILINEAR; + } + } + } + + gOpComposite.bDo = draw_type; + + return TRUE; + +bail: + XDBG_TRACE (MEXAH, "FAIL: op%d\n", op); + XDBG_TRACE (MEXAH, " SRC picture:%p pix:%p\n", pSrcPicture, pSrcPixmap); + XDBG_TRACE (MEXAH, " MASK picture:%p pix:%p\n", pMaskPicture, pMaskPixmap); + XDBG_TRACE (MEXAH, " DST picture:%p pix:%p\n", pDstPicture, pDstPixmap); + + gOpComposite.bDo = DO_DRAW_NONE; + + return TRUE; +} + +static void +SECExaG2dComposite (PixmapPtr pDstPixmap, int srcX, int srcY, + int maskX, int maskY, int dstX, int dstY, + int width, int height) +{ + XDBG_TRACE (MEXAH, "%s\n", DO(gOpComposite)); + XDBG_TRACE (MEXAH, "s(%d,%d), m(%d,%d) d(%d,%d) %dx%d\n", + srcX, srcY, + maskX, maskY, + dstX, dstY, + width, height); + if (gOpComposite.bDo == DO_DRAW_NONE) return; + + gOpComposite.srcX = srcX; + gOpComposite.srcY = srcY; + gOpComposite.maskX = maskX; + gOpComposite.maskY = maskY; + gOpComposite.dstX = dstX; + gOpComposite.dstY = dstY; + gOpComposite.width = width; + gOpComposite.height = height; + + if (gOpComposite.pOpDst->isSame) + { + ExaBox box; + + box.state = rgnIN; + box.box.x1 = 0; + box.box.y1 = 0; + box.box.x2 = width; + box.box.y2 = height; + box.pDst = &gOpComposite.pOpDst->buf[0]; + box.pSrc = &gOpComposite.pOpSrc->buf[0]; + box.pMask = (gOpComposite.pOpMask)? (&gOpComposite.pOpMask->buf[0]):NULL; + + _g2dDoComposite (&box, NULL); + } + else + { + int i; + ExaBox *box; + BoxRec b; + + /*Init box list*/ + xorg_list_init (&gOpComposite.opBox); + + b.x1 = dstX; + b.y1 = dstY; + b.x2 = dstX+width; + b.y2 = dstY+height; + + for (i=0; i<gOpComposite.pOpDst->num; i++) + { + box = _g2dBoxAdd (&gOpComposite.opBox, + &gOpComposite.pOpDst->buf[i].pos, + &b); + if (box) + { + box->pDst = &gOpComposite.pOpDst->buf[i]; + box->pSrc = &gOpComposite.pOpSrc->buf[0]; + box->pMask= (gOpComposite.pOpMask)? (&gOpComposite.pOpMask->buf[0]):NULL; + } + } + _g2dBoxMove (&gOpComposite.opBox, -dstX, -dstY); + + /* Call solid function */ + _g2dDoDraw (&gOpComposite.opBox, + _g2dDoComposite, NULL); + + /*Remove box list*/ + _g2dBoxRemoveAll (&gOpComposite.opBox); + } +} + +/* done composite : sw done composite, not using pvr2d */ +static void +SECExaG2dDoneComposite (PixmapPtr pDst) +{ + XDBG_TRACE (MEXAH, "\n"); + + if(gOpComposite.bDo == DO_DRAW_HW) + g2d_exec(); + + if (gOpComposite.pDstPixmap != NULL) + _g2dFinishAccess (gOpComposite.pDstPixmap, EXA_PREPARE_DEST); + + if (gOpComposite.pSrcPixmap != NULL) + _g2dFinishAccess (gOpComposite.pSrcPixmap, EXA_PREPARE_SRC); + else if (gOpComposite.pOpSrc) + { + g2d_image_free (gOpComposite.pOpSrc->buf[0].imgG2d); + gOpComposite.pOpSrc->buf[0].imgG2d = NULL; + } + + if (gOpComposite.pMaskPixmap != NULL) + _g2dFinishAccess (gOpComposite.pMaskPixmap, EXA_PREPARE_MASK); + else if (gOpComposite.pOpMask != NULL) + { + g2d_image_free (gOpComposite.pOpMask->buf[0].imgG2d); + gOpComposite.pOpMask->buf[0].imgG2d = NULL; + } +} + +static Bool +SECExaG2dUploadToScreen (PixmapPtr pDst, int x, int y, int w, int h, + char *src, int src_pitch) +{ + XDBG_RETURN_VAL_IF_FAIL (src!=NULL, TRUE); + XDBG_TRACE (MEXAH, "src(%p, %d) %d,%d,%d,%d\n", src, src_pitch, x,y,w,h); + + gOpUTS.pDst = pDst; + gOpUTS.x = x; + gOpUTS.y = y; + gOpUTS.w = w; + gOpUTS.h = h; + gOpUTS.src = src; + gOpUTS.src_pitch = src_pitch; + + if(_g2dIsSupport(pDst, FALSE)) + { + gOpUTS.pOpDst = _g2dPrepareAccess (pDst, + EXA_PREPARE_DEST, + TBM_DEVICE_2D); + gOpUTS.imgSrc = g2d_image_create_data (gOpUTS.pOpDst->buf[0].imgG2d->color_mode, + w, h, (void*)src, src_pitch); + gOpUTS.bDo = DO_DRAW_HW; + } + else + { + gOpUTS.pOpDst = _g2dPrepareAccess (pDst, + EXA_PREPARE_DEST, + TBM_DEVICE_CPU); + gOpUTS.imgSrc = NULL; + gOpUTS.bDo = DO_DRAW_SW; + } + + XDBG_TRACE (MEXAH, "%s\n", DO(gOpUTS)); + if (gOpUTS.pOpDst->isSame) + { + ExaBox box; + + box.box.x1 = 0; + box.box.y1 = 0; + box.box.x2 = w; + box.box.y2 = h; + box.state = rgnIN; + box.pDst = &gOpUTS.pOpDst->buf[0]; + _g2dDoUploadToScreen (&box, NULL); + } + else + { + int i; + ExaBox *box; + BoxRec b; + + /*Init box list*/ + xorg_list_init (&gOpUTS.opBox); + + b.x1 = x; + b.y1 = y; + b.x2 = x+w; + b.y2 = y+h; + + for (i=0; i<gOpUTS.pOpDst->num; i++) + { + box = _g2dBoxAdd (&gOpUTS.opBox, + &gOpUTS.pOpDst->buf[i].pos, + &b); + if (box) + { + box->pDst = &gOpUTS.pOpDst->buf[i]; + } + } + _g2dBoxMove (&gOpUTS.opBox, -x, -y); + + /* Call solid function */ + _g2dDoDraw (&gOpUTS.opBox, + _g2dDoUploadToScreen, NULL); + + /*Remove box list*/ + _g2dBoxRemoveAll (&gOpUTS.opBox); + } + + if(gOpUTS.bDo == DO_DRAW_HW) + g2d_exec(); + + _g2dFinishAccess (pDst, EXA_PREPARE_DEST); + if(gOpUTS.imgSrc) + { + g2d_image_free(gOpUTS.imgSrc); + } + return TRUE; +} + + + +static Bool +SECExaG2dDownloadFromScreen (PixmapPtr pSrc, int x, int y, int w, int h, + char *dst, int dst_pitch) +{ + XDBG_RETURN_VAL_IF_FAIL (dst!=NULL, TRUE); + XDBG_TRACE (MEXAH, "dst(%p, %d) %d,%d,%d,%d\n", dst, dst_pitch, x,y,w,h); + + gOpDFS.pSrc = pSrc; + gOpDFS.x = x; + gOpDFS.y = y; + gOpDFS.w = w; + gOpDFS.h = h; + gOpDFS.dst = dst; + gOpDFS.dst_pitch = dst_pitch; + + if(_g2dIsSupport(pSrc, FALSE)) + { + gOpDFS.pOpSrc = _g2dPrepareAccess (pSrc, + EXA_PREPARE_DEST, + TBM_DEVICE_2D); + gOpDFS.imgDst = g2d_image_create_data (gOpDFS.pOpSrc->buf[0].imgG2d->color_mode, + w, h, (void*)dst, dst_pitch); + gOpDFS.bDo = DO_DRAW_HW; + } + else + { + gOpDFS.pOpSrc = _g2dPrepareAccess (pSrc, + EXA_PREPARE_DEST, + TBM_DEVICE_CPU); + gOpDFS.imgDst = NULL; + gOpDFS.bDo = DO_DRAW_SW; + } + + XDBG_TRACE (MEXAH, "%s\n", DO(gOpDFS)); + if (gOpDFS.pOpSrc->isSame) + { + ExaBox box; + + box.box.x1 = 0; + box.box.y1 = 0; + box.box.x2 = w; + box.box.y2 = h; + box.state = rgnIN; + box.pSrc = &gOpDFS.pOpSrc->buf[0]; + _g2dDoDownladFromScreen (&box, NULL); + } + else + { + int i; + ExaBox *box; + BoxRec b; + + /*Init box list*/ + xorg_list_init (&gOpDFS.opBox); + + b.x1 = x; + b.y1 = y; + b.x2 = x+w; + b.y2 = y+h; + + for (i=0; i<gOpDFS.pOpSrc->num; i++) + { + box = _g2dBoxAdd (&gOpDFS.opBox, + &gOpDFS.pOpSrc->buf[i].pos, + &b); + if (box) + { + box->pSrc = &gOpDFS.pOpSrc->buf[i]; + } + } + _g2dBoxMove (&gOpDFS.opBox, -x, -y); + + /* Call solid function */ + _g2dDoDraw (&gOpDFS.opBox, + _g2dDoDownladFromScreen, NULL); + + /*Remove box list*/ + _g2dBoxRemoveAll (&gOpDFS.opBox); + } + + if(gOpDFS.bDo == DO_DRAW_HW) + g2d_exec(); + + _g2dFinishAccess (pSrc, EXA_PREPARE_SRC); + if(gOpDFS.imgDst) + { + g2d_image_free(gOpDFS.imgDst); + } + return TRUE; +} + +Bool secExaG2dInit (ScreenPtr pScreen, ExaDriverPtr pExaDriver) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = SECPTR (pScrn); + + if(!g2d_init (pSec->drm_fd)) + { + XDBG_WARNING (MEXA, "[EXAG2D] fail to g2d_init(%d)\n", pSec->drm_fd); + } + + pExaDriver->PrepareSolid = SECExaG2dPrepareSolid; + pExaDriver->Solid = SECExaG2dSolid; + pExaDriver->DoneSolid = SECExaG2dDoneSolid; + + pExaDriver->PrepareCopy = SECExaG2dPrepareCopy; + pExaDriver->Copy = SECExaG2dCopy; + pExaDriver->DoneCopy = SECExaG2dDoneCopy; + + pExaDriver->CheckComposite = SECExaG2dCheckComposite; + pExaDriver->PrepareComposite = SECExaG2dPrepareComposite; + pExaDriver->Composite = SECExaG2dComposite; + pExaDriver->DoneComposite = SECExaG2dDoneComposite; + + pExaDriver->UploadToScreen = SECExaG2dUploadToScreen; + pExaDriver->DownloadFromScreen = SECExaG2dDownloadFromScreen; + + xf86DrvMsg (pScrn->scrnIndex, X_INFO + , "Succeed to Initialize G2D EXA\n"); + + return TRUE; +} + +void secExaG2dDeinit (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + xf86DrvMsg (pScrn->scrnIndex, X_INFO + , "Succeed to finish SW EXA\n"); +} diff --git a/src/accel/sec_exa_sw.c b/src/accel/sec_exa_sw.c new file mode 100755 index 0000000..d8c3537 --- /dev/null +++ b/src/accel/sec_exa_sw.c @@ -0,0 +1,1266 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@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 "sec.h" +#include "sec_accel.h" +#include "sec_util.h" +#include "sec_layer.h" +#include "exa.h" +#include "fbpict.h" +#include "neonmem.h" + +typedef struct +{ + BoxRec pos; + PixmapPtr pixmap; + tbm_bo bo; + void* addr; +} ExaOpBuf; + +typedef struct +{ + int refcnt; + int opt; + int num; + int isSame; + + ExaOpBuf buf[5]; +} ExaOpInfo; + +typedef struct +{ + BoxRec box; + int state; /*state of region*/ + + struct xorg_list link; + + ExaOpBuf *pSrc; + ExaOpBuf *pMask; + ExaOpBuf *pDst; +} ExaBox; + +typedef struct +{ + Bool bDo; + + int alu; + Pixel planemask; + Pixel fg; + PixmapPtr pixmap; + + int x,y,w,h; + GCPtr pGC; + ExaOpInfo* pOpDst; + struct xorg_list opBox; +} OpSolid; + +typedef struct +{ + Bool bDo; + Pixel pm; + int alu; + int reverse; + int upsidedown; + PixmapPtr pSrcPix; + PixmapPtr pDstPix; + + /*copy param*/ + int srcX; + int srcY; + int dstX; + int dstY; + int width, height; + + ExaOpInfo* pOpDst; + ExaOpInfo* pOpSrc; + struct xorg_list opBox; +} OpCopy; + +typedef struct +{ + Bool bDo; + int op; + + PicturePtr pSrcPicture; + PicturePtr pMaskPicture; + PicturePtr pDstPicture; + PixmapPtr pSrcPixmap; + PixmapPtr pMaskPixmap; + PixmapPtr pDstPixmap; + + /*copy param*/ + int srcX, srcY; + int maskX, maskY; + int dstX, dstY; + int width, height; + + ExaOpInfo* pOpSrc; + ExaOpInfo* pOpMask; + ExaOpInfo* pOpDst; + struct xorg_list opBox; +} OpComposite; + +typedef struct +{ + Bool bDo; + + PixmapPtr pDst; + int x,y,w,h; + char* src; + int src_pitch; + + ExaOpInfo* pOpDst; + struct xorg_list opBox; +} OpUTS; + +typedef struct +{ + Bool bDo; + + PixmapPtr pSrc; + int x,y,w,h; + char* dst; + int dst_pitch; + + ExaOpInfo* pOpSrc; + struct xorg_list opBox; +} OpDFS; + +typedef void (* DoDrawProcPtr) (PixmapPtr pPix, Bool isPart, + int x, int y, + int clip_x, int clip_y, + int w, int h, void* data); + +typedef void (* DoDrawProcPtrEx) (ExaBox* box, void* data); + +static ExaOpInfo OpInfo[EXA_NUM_PREPARE_INDICES]; +static OpSolid gOpSolid; +static OpCopy gOpCopy; +static OpComposite gOpComposite; +static OpUTS gOpUTS; +static OpDFS gOpDFS; + +ExaBox* _swBoxAdd (struct xorg_list *l, BoxPtr b1, BoxPtr b2) +{ + ExaBox* rgn; + + rgn = calloc (1, sizeof (ExaBox)); + XDBG_RETURN_VAL_IF_FAIL ((rgn != NULL), NULL); + + rgn->state = secUtilBoxIntersect (&rgn->box, b1, b2); + if (rgnOUT == rgn->state) + { + free (rgn); + return NULL; + } + + xorg_list_add (&rgn->link, l); + return rgn; +} + +void _swBoxMerge (struct xorg_list *l, struct xorg_list* b, struct xorg_list* t) +{ + ExaBox *b1 = NULL, *b2 = NULL; + ExaBox* r=NULL; + + xorg_list_for_each_entry (b1, b, link) + { + xorg_list_for_each_entry (b2, t, link) + { + r = _swBoxAdd (l, &b1->box, &b2->box); + if (r) + { + r->pSrc = b1->pSrc ? b1->pSrc : b2->pSrc; + r->pMask= b1->pMask ? b1->pMask : b2->pMask; + r->pDst = b1->pDst ? b1->pDst : b2->pDst; + } + } + } +} + +void _swBoxMove (struct xorg_list* l, int tx, int ty) +{ + ExaBox *b = NULL; + + xorg_list_for_each_entry (b, l, link) + { + secUtilBoxMove (&b->box, tx, ty); + } +} + +void _swBoxRemoveAll (struct xorg_list* l) +{ + ExaBox *ref = NULL, *next = NULL; + + xorg_list_for_each_entry_safe (ref, next, l, link) + { + xorg_list_del (&ref->link); + free (ref); + } +} + +int _swBoxIsOne (struct xorg_list* l) +{ + if (l->next != l) + { + if (l->next == l->prev) + return 1; + else + return -1; + } + + return 0; +} + +void _swBoxPrint (ExaBox* sb1, const char* name) +{ + ExaBox *b = NULL; + + xorg_list_for_each_entry (b, &sb1->link, link) + { + XDBG_DEBUG (MEXA, "[%s] %d,%d - %d,%d\n", name, + b->box.x1, b->box.y1, b->box.x2, b->box.y2); + } +} + +static ExaOpInfo* _swPrepareAccess (PixmapPtr pPix, int index) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = SECPTR (pScrn); + SECPixmapPriv *privPixmap = (SECPixmapPriv*)exaGetPixmapDriverPrivate (pPix); + ExaOpInfo* op = &OpInfo[index]; + int opt = TBM_OPTION_READ; + int i; + tbm_bo *bos; + tbm_bo_handle bo_handle; + SECFbBoDataPtr bo_data; + int num_bo; + int ret; + + XDBG_RETURN_VAL_IF_FAIL ((privPixmap != NULL), NULL); + + if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) + opt |= TBM_OPTION_WRITE; + + /* Check mapped */ + if (privPixmap->exaOpInfo) + { + op = (ExaOpInfo*)privPixmap->exaOpInfo; + op->refcnt++; + XDBG_TRACE (MEXAS, "pix:%p index:%d hint:%d ptr:%p ref:%d\n", + pPix, index, pPix->usage_hint, pPix->devPrivate.ptr, op->refcnt); + return op; + } + + /*Set buffer info*/ + memset (op, 0x00, sizeof (ExaOpInfo)); + op->refcnt = 1; + op->opt = opt; + op->isSame = 0; + + if (pPix->usage_hint == CREATE_PIXMAP_USAGE_FB) + { + ret = secFbFindBo (pSec->pFb, + pPix->drawable.x, pPix->drawable.y, + pPix->drawable.width, pPix->drawable.height, + &num_bo, &bos); + XDBG_TRACE (MEXAS,"FB ret:%d num_pix:%d, %dx%d+%d+%d\n", + ret, num_bo, + pPix->drawable.width, pPix->drawable.height, + pPix->drawable.x, pPix->drawable.y); + + if (ret == rgnSAME && num_bo == 1) + { + op->num = 1; + op->isSame = 1; + + op->buf[0].pixmap = pPix; + op->buf[0].bo = bos[0]; + bo_handle = tbm_bo_map (op->buf[0].bo, TBM_DEVICE_CPU, op->opt); + op->buf[0].addr = bo_handle.ptr; + op->buf[0].pixmap->devPrivate.ptr = op->buf[0].addr; + op->buf[0].pos.x1 = 0; + op->buf[0].pos.y1 = 0; + op->buf[0].pos.x2 = pPix->drawable.width; + op->buf[0].pos.y2 = pPix->drawable.height; + } + else + { + op->num = num_bo; + op->isSame = 0; + + for (i = 0; i < num_bo; i++) + { + tbm_bo_get_user_data (bos[i], TBM_BO_DATA_FB, (void**)&bo_data); + op->buf[i].pixmap = secRenderBoGetPixmap (pSec->pFb, bos[i]); + op->buf[i].bo = bos[i]; + bo_handle = tbm_bo_map (bos[i], TBM_DEVICE_CPU, op->opt); + op->buf[i].addr = bo_handle.ptr; + op->buf[i].pixmap->devPrivate.ptr = op->buf[i].addr; + op->buf[i].pos = bo_data->pos; + } + } + + if (bos) + { + free (bos); + bos=NULL; + } + } + else + { + op->num = 1; + op->isSame = 1; + + op->buf[0].pixmap = pPix; + if (privPixmap->bo) + { + op->buf[0].bo = privPixmap->bo; + bo_handle = tbm_bo_map (op->buf[0].bo, TBM_DEVICE_CPU, op->opt); + op->buf[0].addr = bo_handle.ptr; + } + else + { + op->buf[0].bo = privPixmap->bo; + op->buf[0].addr = privPixmap->pPixData; + } + op->buf[0].pixmap->devPrivate.ptr = op->buf[0].addr; + op->buf[0].pos.x1 = 0; + op->buf[0].pos.y1 = 0; + op->buf[0].pos.x2 = pPix->drawable.width; + op->buf[0].pos.y2 = pPix->drawable.height; + } + + privPixmap->exaOpInfo = op; + + XDBG_TRACE (MEXAS, "pix:%p index:%d hint:%d ptr:%p ref:%d\n", + pPix, index, pPix->usage_hint, pPix->devPrivate.ptr, op->refcnt); + return op; +} + +static void _swFinishAccess (PixmapPtr pPix, int index) +{ + XDBG_RETURN_IF_FAIL (pPix!=NULL); + + SECPixmapPriv *privPixmap = (SECPixmapPriv*)exaGetPixmapDriverPrivate (pPix); + ExaOpInfo* op; + int i; + + XDBG_RETURN_IF_FAIL (privPixmap!=NULL); + XDBG_RETURN_IF_FAIL (privPixmap->exaOpInfo!=NULL); + + op = (ExaOpInfo*)privPixmap->exaOpInfo; + op->refcnt --; + + if (op->refcnt == 0) + { + for (i=0; i < op->num; i++) + { + if (op->buf[i].bo) + { + tbm_bo_unmap (op->buf[i].bo); + + if( index == EXA_PREPARE_DEST && pPix->usage_hint == CREATE_PIXMAP_USAGE_FB ) + { + // In this case, DEST is framebuffer. It is updated by CPU. + // After that LCD will use this buffer. + // So we should call cache op!! + tbm_bo_map(op->buf[i].bo, TBM_DEVICE_3D, TBM_OPTION_READ); + tbm_bo_unmap(op->buf[i].bo); + + ScreenPtr pScreen; + pScreen = pPix->drawable.pScreen; + + if( pScreen != NULL ) + { + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = SECPTR(pScrn); + + pSec->is_fb_touched = TRUE; + } + } + op->buf[i].bo = NULL; + } + + if (op->buf[i].pixmap) + { + op->buf[i].pixmap->devPrivate.ptr = NULL; + op->buf[i].pixmap = NULL; + } + op->buf[i].addr = NULL; + } + + privPixmap->exaOpInfo = NULL; + } + + if (pPix->usage_hint == CREATE_PIXMAP_USAGE_OVERLAY) + secLayerUpdate (secLayerFind (LAYER_OUTPUT_LCD, LAYER_UPPER)); + + XDBG_TRACE (MEXAS, "pix:%p index:%d hint:%d ptr:%p ref:%d\n", + pPix, index, pPix->usage_hint, pPix->devPrivate.ptr, op->refcnt); +} + +void +_swDoDraw (struct xorg_list *l, DoDrawProcPtrEx do_draw, void* data) +{ + ExaBox *box = NULL; + xorg_list_for_each_entry (box, l, link) + { + do_draw (box, data); + } +} + +static void +_swDoSolid (ExaBox* box, void* data) +{ + XDBG_TRACE (MEXAS, "(%d,%d), (%d,%d) off(%d,%d)\n", + box->box.x1, + box->box.y1, + box->box.x2, + box->box.y2, + gOpSolid.x, + gOpSolid.y); + + fbFill (&box->pDst->pixmap->drawable, + gOpSolid.pGC, + box->box.x1 + gOpSolid.x - box->pDst->pos.x1, + box->box.y1 + gOpSolid.y - box->pDst->pos.y1, + box->box.x2- box->box.x1, + box->box.y2- box->box.y1); +} + +static void +_swDoCopy (ExaBox* box, void* data) +{ + CARD8 alu = gOpCopy.alu; + FbBits pm = gOpCopy.pm; + FbBits *src; + FbStride srcStride; + int srcBpp; + FbBits *dst; + FbStride dstStride; + int dstBpp; + _X_UNUSED int srcXoff, srcYoff; + _X_UNUSED int dstXoff, dstYoff; + int srcX, srcY, dstX, dstY, width, height; + + XDBG_TRACE (MEXAS, "box(%d,%d),(%d,%d) src(%d,%d) dst(%d,%d)\n", + box->box.x1, + box->box.y1, + box->box.x2, + box->box.y2, + gOpCopy.srcX, + gOpCopy.srcY); + + srcX = gOpCopy.srcX + box->box.x1 - box->pSrc->pos.x1; + srcY = gOpCopy.srcY + box->box.y1 - box->pSrc->pos.y1; + dstX = gOpCopy.dstX + box->box.x1 - box->pDst->pos.x1; + dstY = gOpCopy.dstY + box->box.y1 - box->pDst->pos.y1; + width = box->box.x2 - box->box.x1; + height = box->box.y2 - box->box.y1; + + fbGetDrawable (&box->pSrc->pixmap->drawable, src, srcStride, srcBpp, srcXoff, srcYoff); + fbGetDrawable (&box->pDst->pixmap->drawable, dst, dstStride, dstBpp, dstXoff, dstYoff); + /* temp fix : do right things later */ + if (!src || !dst) + { + return; + } + + if (pm != FB_ALLONES || + alu != GXcopy || + gOpCopy.reverse || + gOpCopy.upsidedown || + !pixman_blt ((uint32_t *)src, (uint32_t *)dst, + srcStride, + dstStride, + srcBpp, dstBpp, + srcX, srcY, dstX, dstY, width, height)) + { + fbBlt (src + srcY * srcStride, + srcStride, + srcX * srcBpp, + + dst + dstY * dstStride, + dstStride, + dstX * dstBpp, + + width * dstBpp, + height, + + alu, + pm, + dstBpp, + + gOpCopy.reverse, + gOpCopy.upsidedown); + } +} + +static void +_swDoComposite (ExaBox* box, void* data) +{ + PicturePtr pDstPicture; + pixman_image_t *src, *mask, *dest; + int src_xoff, src_yoff, msk_xoff, msk_yoff; + FbBits *bits; + FbStride stride; + int bpp; + + if (box->state == rgnPART) + { + XDBG_RETURN_IF_FAIL (gOpComposite.pSrcPicture->transform == NULL); + XDBG_RETURN_IF_FAIL (gOpComposite.pMaskPicture && + gOpComposite.pMaskPicture->transform == NULL); + } + + pDstPicture = gOpComposite.pDstPicture; + + src = image_from_pict (gOpComposite.pSrcPicture, FALSE, &src_xoff, &src_yoff); + mask = image_from_pict (gOpComposite.pMaskPicture, FALSE, &msk_xoff, &msk_yoff); + + fbGetPixmapBitsData (box->pDst->pixmap, bits, stride, bpp); + dest = pixman_image_create_bits (pDstPicture->format, + box->pDst->pixmap->drawable.width, + box->pDst->pixmap->drawable.height, + (uint32_t *)bits, stride * sizeof (FbStride)); + XDBG_RETURN_IF_FAIL (dest != NULL); + + pixman_image_composite (gOpComposite.op, + src, mask, dest, + gOpComposite.srcX + box->box.x1, + gOpComposite.srcY + box->box.y1, + gOpComposite.maskX + box->box.x1, + gOpComposite.maskY + box->box.y1, + gOpComposite.dstX + box->box.x1 - box->pDst->pos.x1, + gOpComposite.dstY + box->box.y1 - box->pDst->pos.y1, + box->box.x2 - box->box.x1, + box->box.y2 - box->box.y1); + + free_pixman_pict (gOpComposite.pSrcPicture, src); + free_pixman_pict (gOpComposite.pMaskPicture, mask); + pixman_image_unref (dest); +} + +static void +_swDoUploadToScreen (ExaBox* box, void* data) +{ + FbBits *dst; + FbStride dstStride; + int dstBpp; + _X_UNUSED int dstXoff, dstYoff; + int srcStride; + int dstX, dstY; + int width, height; + + fbGetDrawable (&box->pDst->pixmap->drawable, dst, dstStride, dstBpp, dstXoff, dstYoff); + + srcStride = gOpUTS.src_pitch/sizeof (uint32_t); + dstX = gOpUTS.x + box->box.x1 - box->pDst->pos.x1; + dstY = gOpUTS.y + box->box.y1 - box->pDst->pos.y1; + width = box->box.x2 - box->box.x1; + height = box->box.y2 - box->box.y1; + + XDBG_TRACE (MEXAS, "src(%p, %d) %d,%d,%d,%d\n", + gOpUTS.src, srcStride, dstX, dstY, width, height); + + if(dstBpp < 8) + { + XDBG_WARNING(MEXAS, "dstBpp:%d\n", dstBpp); + return; + } + + if (!pixman_blt ((uint32_t *)gOpUTS.src, + (uint32_t *)dst, + srcStride, + dstStride, + dstBpp, dstBpp, + box->box.x1, box->box.y1, + dstX, dstY, + width, height)) + { + unsigned char *pDst, *pSrc; + int dst_pitch, src_pitch, cpp; + + pDst = (unsigned char*)dst; + pSrc = (unsigned char*)gOpUTS.src; + cpp = dstBpp / 8; + src_pitch = gOpUTS.src_pitch; + dst_pitch = box->pDst->pixmap->devKind; + + pSrc += box->box.y1 * src_pitch + box->box.x1 * cpp; + pDst += dstY * dst_pitch + dstX * cpp; + + for (; height > 0; height--) { + memcpy(pDst, pSrc, width * cpp); + pDst += dst_pitch; + pSrc += src_pitch; + } + } +} + +static void +_swDoDownladFromScreen (ExaBox* box, void* data) +{ + FbBits *src; + FbStride srcStride; + int srcBpp; + _X_UNUSED int srcXoff, srcYoff; + int dstStride; + int srcX, srcY; + int width, height; + + fbGetDrawable (&box->pSrc->pixmap->drawable, src, srcStride, srcBpp, srcXoff, srcYoff); + + dstStride = gOpDFS.dst_pitch/sizeof (uint32_t); + srcX = gOpDFS.x + box->box.x1 - box->pSrc->pos.x1; + srcY = gOpDFS.y + box->box.y1 - box->pSrc->pos.y1; + width = box->box.x2 - box->box.x1; + height = box->box.y2 - box->box.y1; + + XDBG_TRACE (MEXAS, "dst(%p, %d) %d,%d,%d,%d\n", + gOpDFS.dst, dstStride, srcX, srcY, width, height); + + if(srcBpp < 8) + { + XDBG_WARNING(MEXAS, "srcBpp:%d\n", srcBpp); + return; + } + + if (!pixman_blt ((uint32_t *)src, + (uint32_t *)gOpDFS.dst, + srcStride, + dstStride, + srcBpp, srcBpp, + srcX, srcY, + box->box.x1, box->box.y1, + width, height)) + { + unsigned char *pDst, *pSrc; + int dst_pitch, src_pitch, cpp; + + pDst = (unsigned char*)gOpDFS.dst; + pSrc = (unsigned char*)src; + cpp = srcBpp / 8; + src_pitch = box->pSrc->pixmap->devKind; + dst_pitch = gOpDFS.dst_pitch; + + pSrc += srcY * src_pitch + srcX * cpp; + pDst += box->box.y1 * dst_pitch + box->box.x1 * cpp; + + for (; height > 0; height--) { + memcpy(pDst, pSrc, width * cpp); + pDst += dst_pitch; + pSrc += src_pitch; + } + } +} + +static Bool +SECExaSwPrepareSolid (PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fg) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + ChangeGCVal tmpval[3]; + + XDBG_TRACE (MEXAS, "\n"); + memset (&gOpSolid, 0x00, sizeof (gOpSolid)); + + /* Put ff at the alpha bits when transparency is set to xv */ + if (pPixmap->drawable.depth == 24) + fg = fg | (~ (pScrn->mask.red|pScrn->mask.green|pScrn->mask.blue)); + gOpSolid.alu = alu; + gOpSolid.fg = fg; + gOpSolid.planemask = planemask; + gOpSolid.pixmap = pPixmap; + + gOpSolid.pOpDst = _swPrepareAccess (pPixmap, EXA_PREPARE_DEST); + XDBG_GOTO_IF_FAIL (gOpSolid.pOpDst, bail); + gOpSolid.pGC = GetScratchGC (pPixmap->drawable.depth, pScreen); + + tmpval[0].val = alu; + tmpval[1].val = planemask; + tmpval[2].val = fg; + ChangeGC (NullClient, gOpSolid.pGC, GCFunction|GCPlaneMask|GCForeground, tmpval); + ValidateGC (&pPixmap->drawable, gOpSolid.pGC); + + gOpSolid.bDo = TRUE; + + return TRUE; + +bail: + XDBG_TRACE (MEXAS, "FAIL: pix:%p hint:%d, num_pix:%d\n", + pPixmap, index, pPixmap->usage_hint, gOpSolid.pOpDst->num); + gOpSolid.bDo = FALSE; + gOpSolid.pGC = NULL; + + return TRUE; +} + + +static void +SECExaSwSolid (PixmapPtr pPixmap, int x1, int y1, int x2, int y2) +{ + XDBG_TRACE (MEXAS, " (%d,%d), (%d,%d)\n", x1,y1,x2,y2); + if (gOpSolid.bDo == FALSE) return; + + gOpSolid.x = x1; + gOpSolid.y = y1; + gOpSolid.w = x2-x1; + gOpSolid.h = y2-y1; + + if (gOpSolid.pOpDst->isSame) + { + ExaBox box; + + box.state = rgnIN; + box.box.x1 = 0; + box.box.y1 = 0; + box.box.x2 = x2-x1; + box.box.y2 = y2-y1; + box.pDst = &gOpSolid.pOpDst->buf[0]; + _swDoSolid (&box, NULL); + } + else + { + int i; + ExaBox *box; + BoxRec b; + + /*Init box list*/ + xorg_list_init (&gOpSolid.opBox); + + b.x1 = x1; + b.y1 = y1; + b.x2 = x2; + b.y2 = y2; + + for (i=0; i<gOpSolid.pOpDst->num; i++) + { + box = _swBoxAdd (&gOpSolid.opBox, + &gOpSolid.pOpDst->buf[i].pos, + &b); + if (box) + { + box->pDst = &gOpSolid.pOpDst->buf[i]; + } + } + _swBoxMove (&gOpSolid.opBox, -x1, -y1); + + /* Call solid function */ + _swDoDraw (&gOpSolid.opBox, + _swDoSolid, NULL); + + /*Remove box list*/ + _swBoxRemoveAll (&gOpSolid.opBox); + } +} + +static void +SECExaSwDoneSolid (PixmapPtr pPixmap) +{ + XDBG_TRACE (MEXAS, "\n"); + if (gOpSolid.pGC) + { + FreeScratchGC (gOpSolid.pGC); + gOpSolid.pGC = NULL; + } + + if (gOpSolid.pixmap) + _swFinishAccess (gOpSolid.pixmap, EXA_PREPARE_DEST); +} + +static Bool +SECExaSwPrepareCopy (PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, + int dx, int dy, int alu, Pixel planemask) +{ + int num_dst_pix = -1; + int num_src_pix = -1; + + XDBG_TRACE (MEXAS, "\n"); + memset (&gOpCopy, 0x00, sizeof (gOpCopy)); + + gOpCopy.alu = alu; + gOpCopy.pm = planemask; + gOpCopy.reverse = (dx == 1)?0:1; + gOpCopy.upsidedown = (dy == 1)?0:1; + gOpCopy.pDstPix = pDstPixmap; + gOpCopy.pSrcPix = pSrcPixmap; + + gOpCopy.pOpDst = _swPrepareAccess (pDstPixmap, EXA_PREPARE_DEST); + XDBG_GOTO_IF_FAIL (gOpCopy.pOpDst, bail); + gOpCopy.pOpSrc = _swPrepareAccess (pSrcPixmap, EXA_PREPARE_SRC); + XDBG_GOTO_IF_FAIL (gOpCopy.pOpDst, bail); + + gOpCopy.bDo = TRUE; + + return TRUE; + +bail: + XDBG_TRACE (MEXAS, "FAIL\n"); + XDBG_TRACE (MEXAS, " SRC pix:%p, index:%d, hint:%d, num_pix:%d\n", + pSrcPixmap, index, pSrcPixmap->usage_hint, num_src_pix); + XDBG_TRACE (MEXAS, " DST pix:%p, index:%d, hint:%d, num_pix:%d\n", + pDstPixmap, index, pDstPixmap->usage_hint, num_dst_pix); + gOpCopy.bDo = FALSE; + + return TRUE; +} + + +static void +SECExaSwCopy (PixmapPtr pDstPixmap, int srcX, int srcY, + int dstX, int dstY, int width, int height) +{ + XDBG_TRACE (MEXAS, "src(%d,%d) dst(%d,%d) %dx%d\n", + srcX, srcY, dstX, dstY, width, height); + + if (gOpSolid.bDo == FALSE) return; + + gOpCopy.srcX = srcX; + gOpCopy.srcY = srcY; + gOpCopy.dstX = dstX; + gOpCopy.dstY = dstY; + gOpCopy.width = width; + gOpCopy.height = height; + + if (gOpCopy.pOpSrc->isSame && gOpCopy.pOpDst->isSame) + { + ExaBox box; + + box.state = rgnIN; + box.box.x1 = 0; + box.box.y1 = 0; + box.box.x2 = width; + box.box.y2 = height; + box.pDst = &gOpCopy.pOpDst->buf[0]; + box.pSrc = &gOpCopy.pOpSrc->buf[0]; + _swDoCopy (&box, NULL); + } + else + { + int i; + struct xorg_list lSrc, lDst; + ExaBox *box; + BoxRec b; + + //Set Dest + b.x1 = dstX; + b.y1 = dstY; + b.x2 = dstX + width; + b.y2 = dstY + height; + xorg_list_init (&lDst); + for (i=0; i<gOpCopy.pOpDst->num; i++) + { + box = _swBoxAdd (&lDst, + &gOpCopy.pOpDst->buf[i].pos, + &b); + if (box) + { + box->pDst = &gOpCopy.pOpDst->buf[i]; + } + } + _swBoxMove (&lDst, -dstX, -dstY); + + //Set Src + b.x1 = srcX; + b.y1 = srcY; + b.x2 = srcX + width; + b.y2 = srcY + height; + + xorg_list_init (&lSrc); + for (i=0; i<gOpCopy.pOpSrc->num; i++) + { + box = _swBoxAdd (&lSrc, + &gOpCopy.pOpSrc->buf[i].pos, + &b); + if (box) + { + box->pSrc = &gOpCopy.pOpSrc->buf[i]; + } + } + _swBoxMove (&lSrc, -srcX, -srcY); + + //Merge and call copy + xorg_list_init (&gOpCopy.opBox); + _swBoxMerge (&gOpCopy.opBox, &lSrc, &lDst); + _swDoDraw (&gOpCopy.opBox, + _swDoCopy, NULL); + + //Remove box list + _swBoxRemoveAll (&lSrc); + _swBoxRemoveAll (&lDst); + _swBoxRemoveAll (&gOpCopy.opBox); + } +} + +static void +SECExaSwDoneCopy (PixmapPtr pDstPixmap) +{ + XDBG_TRACE (MEXAS, "\n"); + + if (gOpCopy.pDstPix) + _swFinishAccess (gOpCopy.pDstPix, EXA_PREPARE_DEST); + if (gOpCopy.pSrcPix) + _swFinishAccess (gOpCopy.pSrcPix, EXA_PREPARE_SRC); +} + +static Bool +SECExaSwCheckComposite (int op, PicturePtr pSrcPicture, + PicturePtr pMaskPicture, PicturePtr pDstPicture) +{ + return TRUE; +} + +static Bool +SECExaSwPrepareComposite (int op, PicturePtr pSrcPicture, + PicturePtr pMaskPicture, PicturePtr pDstPicture, + PixmapPtr pSrcPixmap, + PixmapPtr pMaskPixmap, PixmapPtr pDstPixmap) +{ + XDBG_TRACE (MEXAS, "\n"); + memset (&gOpComposite, 0x00, sizeof (gOpComposite)); + XDBG_GOTO_IF_FAIL (pDstPixmap != NULL, bail); + + gOpComposite.op = op; + gOpComposite.pDstPicture = pDstPicture; + gOpComposite.pSrcPicture = pSrcPicture; + gOpComposite.pMaskPicture = pMaskPicture; + gOpComposite.pSrcPixmap = pSrcPixmap; + gOpComposite.pMaskPixmap = pMaskPixmap; + gOpComposite.pDstPixmap = pDstPixmap; + + gOpComposite.pOpDst = _swPrepareAccess (pDstPixmap, EXA_PREPARE_DEST); + + if (pSrcPixmap) + { + gOpComposite.pOpSrc = _swPrepareAccess (pSrcPixmap, EXA_PREPARE_SRC); + XDBG_GOTO_IF_FAIL (gOpComposite.pOpSrc->num == 1, bail); + } + + if (pMaskPixmap) + { + gOpComposite.pOpMask = _swPrepareAccess (pMaskPixmap, EXA_PREPARE_MASK); + XDBG_GOTO_IF_FAIL (gOpComposite.pOpMask->num == 1, bail); + } + + gOpComposite.bDo = TRUE; + + return TRUE; + +bail: + XDBG_TRACE (MEXAS, "FAIL: op%d\n", op); + XDBG_TRACE (MEXAS, " SRC picture:%p pix:%p\n", pSrcPicture, pSrcPixmap); + XDBG_TRACE (MEXAS, " MASK picture:%p pix:%p\n", pMaskPicture, pMaskPixmap); + XDBG_TRACE (MEXAS, " DST picture:%p pix:%p\n", pDstPicture, pDstPixmap); + + gOpComposite.bDo = FALSE; + + return TRUE; +} + +static void +SECExaSwComposite (PixmapPtr pDstPixmap, int srcX, int srcY, + int maskX, int maskY, int dstX, int dstY, + int width, int height) +{ + XDBG_TRACE (MEXAS, "s(%d,%d), m(%d,%d) d(%d,%d) %dx%d\n", + srcX, srcY, + maskX, maskY, + dstX, dstY, + width, height); + if (!gOpComposite.bDo) return; + + gOpComposite.srcX = srcX; + gOpComposite.srcY = srcY; + gOpComposite.maskX = maskX; + gOpComposite.maskY = maskY; + gOpComposite.dstX = dstX; + gOpComposite.dstY = dstY; + gOpComposite.width = width; + gOpComposite.height = height; + + if (gOpComposite.pOpDst->isSame) + { + ExaBox box; + + box.state = rgnIN; + box.box.x1 = 0; + box.box.y1 = 0; + box.box.x2 = width; + box.box.y2 = height; + box.pDst = &gOpComposite.pOpDst->buf[0]; + box.pSrc = (gOpComposite.pOpSrc)? (&gOpComposite.pOpSrc->buf[0]):NULL; + box.pSrc = (gOpComposite.pOpMask)? (&gOpComposite.pOpMask->buf[0]):NULL; + + _swDoComposite (&box, NULL); + } + else + { + int i; + ExaBox *box; + BoxRec b; + + /*Init box list*/ + xorg_list_init (&gOpComposite.opBox); + + b.x1 = dstX; + b.y1 = dstY; + b.x2 = dstX+width; + b.y2 = dstY+height; + + for (i=0; i<gOpComposite.pOpDst->num; i++) + { + box = _swBoxAdd (&gOpComposite.opBox, + &gOpComposite.pOpDst->buf[i].pos, + &b); + if (box) + { + box->pDst = &gOpComposite.pOpDst->buf[i]; + box->pSrc = (gOpComposite.pOpSrc)? (&gOpComposite.pOpSrc->buf[0]):NULL; + box->pMask= (gOpComposite.pOpMask)? (&gOpComposite.pOpMask->buf[0]):NULL; + } + } + _swBoxMove (&gOpComposite.opBox, -dstX, -dstY); + + /* Call solid function */ + _swDoDraw (&gOpComposite.opBox, + _swDoComposite, NULL); + + /*Remove box list*/ + _swBoxRemoveAll (&gOpComposite.opBox); + } +} + +/* done composite : sw done composite, not using pvr2d */ +static void +SECExaSwDoneComposite (PixmapPtr pDst) +{ + XDBG_TRACE (MEXAS, "\n"); + if (gOpComposite.pDstPixmap != NULL) + _swFinishAccess (gOpComposite.pDstPixmap, EXA_PREPARE_DEST); + if (gOpComposite.pSrcPixmap != NULL) + _swFinishAccess (gOpComposite.pSrcPixmap, EXA_PREPARE_SRC); + if (gOpComposite.pMaskPixmap != NULL) + _swFinishAccess (gOpComposite.pMaskPixmap, EXA_PREPARE_MASK); +} + +static Bool +SECExaSwUploadToScreen (PixmapPtr pDst, int x, int y, int w, int h, + char *src, int src_pitch) +{ + XDBG_RETURN_VAL_IF_FAIL (src!=NULL, TRUE); + XDBG_TRACE (MEXAS, "src(%p, %d) %d,%d,%d,%d\n", src, src_pitch, x,y,w,h); + XDBG_TRACE (MEXAS, "\tdst depth:%d, bpp:%d, pitch:%d, %dx%d\n", + pDst->drawable.depth, pDst->drawable.bitsPerPixel, pDst->devKind, + pDst->drawable.width, pDst->drawable.height); + + gOpUTS.pDst = pDst; + gOpUTS.x = x; + gOpUTS.y = y; + gOpUTS.w = w; + gOpUTS.h = h; + gOpUTS.src = src; + gOpUTS.src_pitch = src_pitch; + gOpUTS.pOpDst = _swPrepareAccess (pDst, EXA_PREPARE_DEST); + + if (gOpUTS.pOpDst->isSame) + { + ExaBox box; + + box.box.x1 = 0; + box.box.y1 = 0; + box.box.x2 = w; + box.box.y2 = h; + box.state = rgnIN; + box.pDst = &gOpUTS.pOpDst->buf[0]; + _swDoUploadToScreen (&box, NULL); + } + else + { + int i; + ExaBox *box; + BoxRec b; + + /*Init box list*/ + xorg_list_init (&gOpUTS.opBox); + + b.x1 = x; + b.y1 = y; + b.x2 = x+w; + b.y2 = y+h; + + for (i=0; i<gOpUTS.pOpDst->num; i++) + { + box = _swBoxAdd (&gOpUTS.opBox, + &gOpUTS.pOpDst->buf[i].pos, + &b); + if (box) + { + box->pDst = &gOpUTS.pOpDst->buf[i]; + } + } + _swBoxMove (&gOpUTS.opBox, -x, -y); + + /* Call solid function */ + _swDoDraw (&gOpUTS.opBox, + _swDoUploadToScreen, NULL); + + /*Remove box list*/ + _swBoxRemoveAll (&gOpUTS.opBox); + } + + _swFinishAccess (pDst, EXA_PREPARE_DEST); + return TRUE; +} + + + +static Bool +SECExaSwDownloadFromScreen (PixmapPtr pSrc, int x, int y, int w, int h, + char *dst, int dst_pitch) +{ + XDBG_RETURN_VAL_IF_FAIL (dst!=NULL, TRUE); + XDBG_TRACE (MEXAS, "dst(%p, %d) %d,%d,%d,%d\n", dst, dst_pitch, x,y,w,h); + + gOpDFS.pSrc = pSrc; + gOpDFS.x = x; + gOpDFS.y = y; + gOpDFS.w = w; + gOpDFS.h = h; + gOpDFS.dst = dst; + gOpDFS.dst_pitch = dst_pitch; + gOpDFS.pOpSrc = _swPrepareAccess (pSrc, EXA_PREPARE_SRC); + + if (gOpDFS.pOpSrc->isSame) + { + ExaBox box; + + box.box.x1 = 0; + box.box.y1 = 0; + box.box.x2 = w; + box.box.y2 = h; + box.state = rgnIN; + box.pSrc = &gOpDFS.pOpSrc->buf[0]; + _swDoDownladFromScreen (&box, NULL); + } + else + { + int i; + ExaBox *box; + BoxRec b; + + /*Init box list*/ + xorg_list_init (&gOpDFS.opBox); + + b.x1 = x; + b.y1 = y; + b.x2 = x+w; + b.y2 = y+h; + + for (i=0; i<gOpDFS.pOpSrc->num; i++) + { + box = _swBoxAdd (&gOpDFS.opBox, + &gOpDFS.pOpSrc->buf[i].pos, + &b); + if (box) + { + box->pSrc = &gOpDFS.pOpSrc->buf[i]; + } + } + _swBoxMove (&gOpDFS.opBox, -x, -y); + + /* Call solid function */ + _swDoDraw (&gOpDFS.opBox, + _swDoDownladFromScreen, NULL); + + /*Remove box list*/ + _swBoxRemoveAll (&gOpDFS.opBox); + } + + _swFinishAccess (pSrc, EXA_PREPARE_SRC); + return TRUE; +} + +int SECExaMarkSync(ScreenPtr pScreen) +{ + XDBG_RETURN_VAL_IF_FAIL (pScreen != NULL, TRUE); + int ret=0; + + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = SECPTR(pScrn); + + if( pSec && pSec->is_fb_touched == TRUE ) + { + XDBG_TRACE(MEXAS, "UpdateRequest to the display!\n"); + + ret = secDisplayUpdateRequest(pScrn); + pSec->is_fb_touched = FALSE; + } + + return ret; +} + +Bool secExaSwInit (ScreenPtr pScreen, ExaDriverPtr pExaDriver) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + pExaDriver->PrepareSolid = SECExaSwPrepareSolid; + pExaDriver->Solid = SECExaSwSolid; + pExaDriver->DoneSolid = SECExaSwDoneSolid; + + pExaDriver->PrepareCopy = SECExaSwPrepareCopy; + pExaDriver->Copy = SECExaSwCopy; + pExaDriver->DoneCopy = SECExaSwDoneCopy; + + pExaDriver->CheckComposite = SECExaSwCheckComposite; + pExaDriver->PrepareComposite = SECExaSwPrepareComposite; + pExaDriver->Composite = SECExaSwComposite; + pExaDriver->DoneComposite = SECExaSwDoneComposite; + + pExaDriver->UploadToScreen = SECExaSwUploadToScreen; + pExaDriver->DownloadFromScreen = SECExaSwDownloadFromScreen; + + pExaDriver->MarkSync = SECExaMarkSync; + + xf86DrvMsg (pScrn->scrnIndex, X_INFO + , "Succeed to Initialize SW EXA\n"); + + return TRUE; +} + +void secExaSwDeinit (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + xf86DrvMsg (pScrn->scrnIndex, X_INFO + , "Succeed to finish SW EXA\n"); +} diff --git a/src/crtcconfig/sec_crtc.c b/src/crtcconfig/sec_crtc.c new file mode 100755 index 0000000..a69cc7b --- /dev/null +++ b/src/crtcconfig/sec_crtc.c @@ -0,0 +1,2768 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2011-2012 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@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. + +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <poll.h> + +#include <xace.h> +#include <xacestr.h> +#include <xorgVersion.h> +#include <tbm_bufmgr.h> +#include <xf86Crtc.h> +#include <xf86DDC.h> +#include <xf86cmap.h> +#include <xf86Xinput.h> +#include <exevents.h> +#include <list.h> +#include <X11/Xatom.h> +#include <X11/extensions/dpmsconst.h> +#include <exynos_drm.h> +#include "sec.h" +#include "sec_util.h" +#include "sec_crtc.h" +#include "sec_output.h" +#include "sec_plane.h" +#include "sec_layer.h" +#include "sec_accel.h" +#include "sec_drm_ipp.h" +#include "fimg2d.h" + +static void _cursorRegisterBlockHandler (xf86CrtcPtr pCrtc); +static void _cursorUnregisterBlockHandler (xf86CrtcPtr pCrtc); +static void _cursorShow (xf86CrtcPtr pCrtc); +static void _cursorMove (xf86CrtcPtr pCrtc, int x, int y); +static void _cursorDrawCursor (xf86CrtcPtr pCrtc); + +static Atom atom_rotate_root_angle; +static Atom atom_relative_device_exist; + +static int +_overlayGetXMoveOffset (xf86CrtcPtr pCrtc, int x) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + SECModePtr pSecMode = (SECModePtr) SECPTR (pCrtc->scrn)->pSecMode; + int offset = 0; + + if (pCrtcPriv->pipe != 0) + return 0; + + offset = x + SEC_CURSOR_W - pSecMode->main_lcd_mode.hdisplay; + + return (offset > 0) ? offset : 0; +} + +static Bool +_overlayEnsureBuffer (xf86CrtcPtr pCrtc, Bool move_layer) +{ + SECModePtr pSecMode = (SECModePtr) SECPTR (pCrtc->scrn)->pSecMode; + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + if (move_layer) + { + if (!pCrtcPriv->ovl_vbuf_cursor) + { + pCrtcPriv->ovl_vbuf_cursor = secUtilAllocVideoBuffer (pCrtc->scrn, FOURCC_RGB32, + SEC_CURSOR_W, SEC_CURSOR_H, + FALSE, TRUE, FALSE); + XDBG_RETURN_VAL_IF_FAIL (pCrtcPriv->ovl_vbuf_cursor != NULL, FALSE); + XDBG_TRACE (MCRS, "[%p] ovl_vbuf_cursor(%p) %dx%d created. \n", pCrtc, + pCrtcPriv->ovl_vbuf_cursor, SEC_CURSOR_W, SEC_CURSOR_H); + } + } + else + { + if (!pCrtcPriv->ovl_vbuf_pixmap) + { + pCrtcPriv->ovl_vbuf_pixmap = secUtilAllocVideoBuffer (pCrtc->scrn, FOURCC_RGB32, + pSecMode->main_lcd_mode.hdisplay, + pSecMode->main_lcd_mode.vdisplay, + FALSE, TRUE, FALSE); + XDBG_RETURN_VAL_IF_FAIL (pCrtcPriv->ovl_vbuf_pixmap != NULL, FALSE); + XDBG_TRACE (MCRS, "[%p] ovl_vbuf_pixmap(%p) %dx%d created. \n", pCrtc, pCrtcPriv->ovl_vbuf_pixmap, + pSecMode->main_lcd_mode.hdisplay, pSecMode->main_lcd_mode.vdisplay); + } + } + + return TRUE; +} + +static Bool +_overlayEnsureLayer (xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + int connector_type; + SECLayerOutput output = LAYER_OUTPUT_LCD; + SECLayer *layer; + + if (pCrtcPriv->ovl_layer) + return TRUE; + + connector_type = secCrtcGetConnectType (pCrtc); + + if (connector_type == DRM_MODE_CONNECTOR_LVDS || + connector_type == DRM_MODE_CONNECTOR_Unknown) + { + output = LAYER_OUTPUT_LCD; + } + else if (connector_type == DRM_MODE_CONNECTOR_HDMIA || + connector_type == DRM_MODE_CONNECTOR_HDMIB || + connector_type == DRM_MODE_CONNECTOR_VIRTUAL) + { + output = LAYER_OUTPUT_EXT; + } + else + { + XDBG_NEVER_GET_HERE (MDISP); + return FALSE; + } + + layer = secLayerFind (output, LAYER_UPPER); + XDBG_RETURN_VAL_IF_FAIL (layer == NULL, FALSE); + + pCrtcPriv->ovl_layer = secLayerCreate (pCrtc->scrn, output, LAYER_UPPER); + XDBG_RETURN_VAL_IF_FAIL (pCrtcPriv->ovl_layer != NULL, FALSE); + + XDBG_TRACE (MCRS, "[%p] ovl_layer(%p) created. \n", pCrtc, pCrtcPriv->ovl_layer); + + return TRUE; +} + +static Bool +_overlaySelectBuffer (xf86CrtcPtr pCrtc, Bool move_layer) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + SECModePtr pSecMode = (SECModePtr) SECPTR (pCrtc->scrn)->pSecMode; + + if (!_overlayEnsureLayer (pCrtc)) + return FALSE; + + if (!_overlayEnsureBuffer (pCrtc, move_layer)) + return FALSE; + + if (move_layer) + { + if (secLayerGetBuffer (pCrtcPriv->ovl_layer) == pCrtcPriv->ovl_vbuf_cursor) + return TRUE; + + secLayerFreezeUpdate (pCrtcPriv->ovl_layer, TRUE); + _cursorDrawCursor (pCrtc); + secLayerSetBuffer (pCrtcPriv->ovl_layer, pCrtcPriv->ovl_vbuf_cursor); + secLayerFreezeUpdate (pCrtcPriv->ovl_layer, FALSE); + + int offset = _overlayGetXMoveOffset (pCrtc, pCrtcPriv->cursor_win_x); + _cursorMove (pCrtc, pCrtcPriv->cursor_win_x - offset, pCrtcPriv->cursor_win_y); + + XDBG_TRACE (MCRS, "[%p] Set ovl_vbuf_cursor. \n", pCrtc); + } + else + { + xRectangle rect = {0,}; + + if (secLayerGetBuffer (pCrtcPriv->ovl_layer) == pCrtcPriv->ovl_vbuf_pixmap) + return TRUE; + + rect.width = pSecMode->main_lcd_mode.hdisplay; + rect.height = pSecMode->main_lcd_mode.vdisplay; + secLayerFreezeUpdate (pCrtcPriv->ovl_layer, TRUE); + secLayerSetBuffer (pCrtcPriv->ovl_layer, pCrtcPriv->ovl_vbuf_pixmap); + secLayerFreezeUpdate (pCrtcPriv->ovl_layer, FALSE); + + secLayerSetRect (pCrtcPriv->ovl_layer, &rect, &rect); + + XDBG_TRACE (MCRS, "[%p] Set ovl_vbuf_pixmap. \n", pCrtc); + } + + return TRUE; +} + +static Bool +_cursorEnsureCursorImage(xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + SECPtr pSec = SECPTR (pCrtc->scrn); + + int x, y, cursor_x, cursor_y; + int win_x, win_y; + int rotate; + int tx = 0, ty = 0; + double c, s; + pixman_transform_t t; + + x = pCrtcPriv->cursor_pos_x; + y = pCrtcPriv->cursor_pos_y; + + //Determine cursor image transform + rotate = secUtilRotateAdd (pSec->rotate, pCrtcPriv->user_rotate); + + //Transform cursor position and screen size + switch (pSec->rotate) + { + case RR_Rotate_0: + default: + cursor_x = x; + cursor_y = y; + break; + case RR_Rotate_90: + cursor_x = y; + cursor_y = pCrtc->scrn->virtualX-1 - x; + break; + case RR_Rotate_180: + cursor_x = pCrtc->scrn->virtualX-1 - x; + cursor_y = pCrtc->scrn->virtualY-1 - y; + break; + case RR_Rotate_270: + cursor_x = pCrtc->scrn->virtualY-1 - y; + cursor_y = x; + break; + } + + switch (rotate) + { + case RR_Rotate_0: + default: + c = 1.0; + s = 0.0; + win_x = cursor_x; + win_y = cursor_y; + break; + case RR_Rotate_90: + c = 0.0; + s = 1.0; + tx = SEC_CURSOR_W; + ty = 0; + + win_x = cursor_x; + win_y = cursor_y - SEC_CURSOR_W; + break; + case RR_Rotate_180: + c = -1.0; + s = 0.0; + tx = SEC_CURSOR_W; + ty = SEC_CURSOR_H; + + win_x = cursor_x - SEC_CURSOR_W; + win_y = cursor_y - SEC_CURSOR_H; + break; + case RR_Rotate_270: + c = 0.0; + s = -1.0; + tx = 0; + ty = SEC_CURSOR_H; + + win_x = cursor_x - SEC_CURSOR_H; + win_y = cursor_y; + break; + } + + pCrtcPriv->cursor_win_x = win_x; + pCrtcPriv->cursor_win_y = win_y; + + if(pCrtcPriv->cursor_image == NULL) + { + XDBG_RETURN_VAL_IF_FAIL (pCrtcPriv->backup_image != NULL, FALSE); + + XDBG_DEBUG (MCRS, "[%p] (%d + %d) => %d \n", pCrtc, + pSec->rotate, pCrtcPriv->user_rotate, rotate); + + if(rotate == RR_Rotate_0) + { + pCrtcPriv->cursor_image = pCrtcPriv->backup_image; + pixman_image_ref(pCrtcPriv->cursor_image); + } + else + { + //Clear cursor image + pCrtcPriv->cursor_image = pixman_image_create_bits (PIXMAN_a8r8g8b8 + , SEC_CURSOR_W, SEC_CURSOR_H + , NULL + , 0); + + //Copy Cursor image + pixman_transform_init_rotate (&t, pixman_double_to_fixed (c), pixman_double_to_fixed (s)); + pixman_transform_translate (&t, NULL, pixman_int_to_fixed (tx), pixman_int_to_fixed (ty)); + pixman_image_set_transform (pCrtcPriv->backup_image, &t); + pixman_image_composite (PIXMAN_OP_SRC + , pCrtcPriv->backup_image + , NULL + , pCrtcPriv->cursor_image + , 0, 0, 0, 0, 0, 0, SEC_CURSOR_W, SEC_CURSOR_H); + pixman_transform_init_rotate (&t, pixman_double_to_fixed (1.0), pixman_double_to_fixed (0.0)); + pixman_image_set_transform (pCrtcPriv->backup_image, &t); + } + } + + return TRUE; +} + +static Bool +_cursorEnsureCanvas (xf86CrtcPtr pCrtc, SECVideoBuf *vbuf, int width, int height) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + tbm_bo_handle bo_handle; + + if (pCrtcPriv->ovl_canvas) + return TRUE; + + if (!_overlayEnsureBuffer (pCrtc, pCrtcPriv->move_layer)) + return FALSE; + + XDBG_RETURN_VAL_IF_FAIL (vbuf != NULL, FALSE); + + bo_handle = tbm_bo_get_handle (vbuf->bo[0], TBM_DEVICE_CPU); + XDBG_RETURN_VAL_IF_FAIL (bo_handle.ptr != NULL, FALSE); + + pCrtcPriv->ovl_canvas = pixman_image_create_bits (PIXMAN_a8r8g8b8, + width, height, + (uint32_t *)bo_handle.ptr, + width * 4); + + XDBG_TRACE (MCRS, "[%p] ovl_canvas(%p) %dx%d created.\n", pCrtc, + pCrtcPriv->ovl_canvas, width, height); + + return TRUE; +} + +static Bool +_cursorEnsureSavedImage (xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + if (pCrtcPriv->saved_image) + return TRUE; + + pCrtcPriv->saved_image = pixman_image_create_bits (PIXMAN_a8r8g8b8, + SEC_CURSOR_W, SEC_CURSOR_H, + NULL, + 0); + XDBG_TRACE (MCRS, "[%p] saved_image(%p) %dx%d created.\n", pCrtc, + pCrtcPriv->saved_image, SEC_CURSOR_W, SEC_CURSOR_H); + + return TRUE; +} + +static void +_cursorSaveImage (xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + SECModePtr pSecMode = (SECModePtr) SECPTR (pCrtc->scrn)->pSecMode; + + XDBG_RETURN_IF_FAIL (pCrtcPriv->move_layer == FALSE); + + _cursorEnsureCanvas (pCrtc, pCrtcPriv->ovl_vbuf_pixmap, + pSecMode->main_lcd_mode.hdisplay, + pSecMode->main_lcd_mode.vdisplay); + + _cursorEnsureSavedImage (pCrtc); + + pixman_image_composite (PIXMAN_OP_SRC, + pCrtcPriv->ovl_canvas, + NULL, + pCrtcPriv->saved_image, + pCrtcPriv->cursor_win_x, pCrtcPriv->cursor_win_y, + 0, 0, + 0, 0, + SEC_CURSOR_W, SEC_CURSOR_H); + + pCrtcPriv->saved_box.x1 = pCrtcPriv->cursor_win_x; + pCrtcPriv->saved_box.y1 = pCrtcPriv->cursor_win_y; + pCrtcPriv->saved_box.x2 = pCrtcPriv->cursor_win_x+SEC_CURSOR_W; + pCrtcPriv->saved_box.y2 = pCrtcPriv->cursor_win_y+SEC_CURSOR_H; + + XDBG_DEBUG (MCRS, "[%p] (%d,%d %dx%d) saved. \n", pCrtc, + pCrtcPriv->cursor_win_x, pCrtcPriv->cursor_win_y, + SEC_CURSOR_W, SEC_CURSOR_H); +} + +static void +_cursorRestoreImage (xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + if (!pCrtcPriv->saved_image || !pCrtcPriv->ovl_canvas) + return; + + pixman_image_composite (PIXMAN_OP_SRC, + pCrtcPriv->saved_image, + NULL, + pCrtcPriv->ovl_canvas, + 0, 0, 0, 0, + pCrtcPriv->saved_box.x1, pCrtcPriv->saved_box.y1, + SEC_CURSOR_W, SEC_CURSOR_H); + + if (pCrtcPriv->ovl_layer && secLayerIsVisible (pCrtcPriv->ovl_layer)) + secLayerUpdate (pCrtcPriv->ovl_layer); + + XDBG_DEBUG (MCRS, "[%p] (%d,%d %dx%d) restored. \n", pCrtc, + pCrtcPriv->saved_box.x1, pCrtcPriv->saved_box.y1, + SEC_CURSOR_W, SEC_CURSOR_H); +} + +static void +_cursorDrawCursor (xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + int x, y; + + XDBG_RETURN_IF_FAIL (pCrtcPriv->ovl_canvas != NULL); + XDBG_RETURN_IF_FAIL (pCrtcPriv->cursor_image != NULL); + + if (pCrtcPriv->move_layer) + { + /* clear */ + pixman_color_t color = {0,}; + pixman_rectangle16_t rect = {0, 0, SEC_CURSOR_W, SEC_CURSOR_H}; + pixman_image_fill_rectangles (PIXMAN_OP_CLEAR, pCrtcPriv->ovl_canvas, + &color, 1, &rect); + + x = _overlayGetXMoveOffset (pCrtc, pCrtcPriv->cursor_win_x); + y = 0; + } + else + { + x = pCrtcPriv->cursor_win_x; + y = pCrtcPriv->cursor_win_y; + } + + pixman_image_composite (PIXMAN_OP_OVER, + pCrtcPriv->cursor_image, + NULL, + pCrtcPriv->ovl_canvas, + 0, 0, 0, 0, x, y, + SEC_CURSOR_W, SEC_CURSOR_H); + + XDBG_DEBUG (MCRS, "[%p] (%d,%d %dx%d) drawn. \n", pCrtc, + x, y, SEC_CURSOR_W, SEC_CURSOR_H); + + secUtilCacheFlush (pCrtc->scrn); + + if (pCrtcPriv->ovl_layer && secLayerIsVisible (pCrtcPriv->ovl_layer)) + secLayerUpdate (pCrtcPriv->ovl_layer); +} + +static void +_cursorReportDamage (DamagePtr pDamage, RegionPtr pRegion, void *closure) +{ + xf86CrtcPtr pCrtc = (xf86CrtcPtr)closure; + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + SECPtr pSec = SECPTR (pCrtc->scrn); + + if (pCrtcPriv->move_layer) + return; + + if(!pSec->enableCursor || !pCrtcPriv->cursor_show) + return; + + if (RegionContainsRect (pRegion, &pCrtcPriv->saved_box) != rgnOUT) + { + XDBG_TRACE (MCRS, "[%p] \n", pCrtc); + pCrtcPriv->need_cursor_update = TRUE; + _cursorRestoreImage(pCrtc); + _cursorRegisterBlockHandler (pCrtc); + } +} + +static void +_cursorDamageDestroy(DamagePtr pDamage, void *closure) +{ + xf86CrtcPtr pCrtc = (xf86CrtcPtr)closure; + SECPtr pSec = SECPTR (pCrtc->scrn); + + if (!pSec->ovl_damage) + return; + + pSec->ovl_damage = NULL; +} + +static void +_cursorBlockHandler(pointer data, OSTimePtr pTimeout, pointer pRead) +{ + xf86CrtcPtr pCrtc = (xf86CrtcPtr)data; + SECPtr pSec = SECPTR (pCrtc->scrn); + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + XDBG_RETURN_IF_FAIL (pCrtcPriv->move_layer == FALSE); + + if(pSec->ovl_drawable) + { + if(pSec->ovl_damage == NULL) + { + pSec->ovl_damage = DamageCreate((DamageReportFunc)_cursorReportDamage, + (DamageDestroyFunc)_cursorDamageDestroy, + DamageReportRawRegion, + TRUE, pCrtc->scrn->pScreen, pCrtc); + XDBG_RETURN_IF_FAIL (pSec->ovl_damage); + DamageRegister(pSec->ovl_drawable, pSec->ovl_damage); + } + } + else + { + if(pSec->ovl_damage) + { + DamageDestroy(pSec->ovl_damage); + pSec->ovl_damage = NULL; + } + } + + XDBG_DEBUG (MCRS, "[%p] enable(%d) cursor_show(%d) need_update(%d) show(%d) \n", pCrtc, + pSec->enableCursor, pCrtcPriv->cursor_show, + pCrtcPriv->need_cursor_update, pCrtcPriv->cursor_show); + + if(pSec->enableCursor && pCrtcPriv->need_cursor_update) + { + SECModePtr pSecMode = (SECModePtr) SECPTR (pCrtc->scrn)->pSecMode; + + _cursorEnsureCursorImage (pCrtc); + _cursorEnsureCanvas (pCrtc, pCrtcPriv->ovl_vbuf_pixmap, + pSecMode->main_lcd_mode.hdisplay, + pSecMode->main_lcd_mode.vdisplay); + + _cursorSaveImage (pCrtc); + + /*Draw Cursor*/ + if(pCrtcPriv->cursor_show) + _cursorDrawCursor (pCrtc); + + _overlaySelectBuffer (pCrtc, pCrtcPriv->move_layer); + _cursorMove (pCrtc, pCrtcPriv->cursor_win_x, pCrtcPriv->cursor_win_y); + + pCrtcPriv->need_cursor_update = FALSE; + } + + if (!secLayerIsVisible (pCrtcPriv->ovl_layer)) + secLayerShow (pCrtcPriv->ovl_layer); + + if(!pSec->enableCursor || !pCrtcPriv->cursor_show || !pCrtcPriv->need_cursor_update) + _cursorUnregisterBlockHandler (pCrtc); +} + +static Bool +_cursorSetPointerDeviceRotate (DeviceIntPtr dev, int rotate) +{ +#define EVDEV_PROP_INVERT_AXES "Evdev Axis Inversion" /* BOOL, 2 values [x, y], 1 inverts axis */ +#define EVDEV_PROP_SWAP_AXES "Evdev Axes Swap" /* BOOL */ + + int swap = 0; + char inv[2]; + + static Atom swap_axes=0; + static Atom invert_axes=0; + int rc; + + if (!dev) return FALSE; + + XDBG_TRACE (MCRS, "device %s (valuator:%p)\n", + dev->name, dev->valuator); + + if (!swap_axes) + swap_axes = MakeAtom (EVDEV_PROP_SWAP_AXES, strlen (EVDEV_PROP_SWAP_AXES), TRUE); + + if (!invert_axes) + invert_axes = MakeAtom (EVDEV_PROP_INVERT_AXES, strlen (EVDEV_PROP_INVERT_AXES), TRUE); + + switch (rotate) + { + case RR_Rotate_0: + swap = 0; + inv[0] = 0; + inv[1] = 0; + break; + case RR_Rotate_90: + swap = 1; + inv[0] = 0; + inv[1] = 1; + break; + case RR_Rotate_180: + swap = 0; + inv[0] = 1; + inv[1] = 1; + break; + case RR_Rotate_270: + swap = 1; + inv[0] = 1; + inv[1] = 0; + break; + default: + XDBG_ERROR (MCRS, "Error.. cursor_rotate:%d\n", rotate); + return FALSE; + } + + XDBG_TRACE (MCRS, "%s change(swap:%d, inv:%d,%d rotate:%d)\n", dev->name, swap, inv[0], inv[1], rotate); + rc = XIChangeDeviceProperty (dev, swap_axes, XA_INTEGER, 8, + PropModeReplace, 1, &swap, TRUE); + if (rc != Success) + { + XDBG_ERROR (MCRS, "Fail change swap(%s , swap:%d)\n", dev->name, swap); + } + + rc = XIChangeDeviceProperty (dev, invert_axes, XA_INTEGER, 8, + PropModeReplace, 2, + inv, TRUE); + if (rc != Success) + { + XDBG_ERROR (MCRS, "Fail change invert(%s , invert:%d,%d)\n", dev->name, inv[0], inv[1]); + } + + return TRUE; +} + +static Bool +_cursorFindRelativeDevice (xf86CrtcPtr pCrtc) +{ + InputInfoPtr localDevices; + DeviceIntPtr dev; + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + XDBG_TRACE (MCRS, "[%p] \n", pCrtc); + + localDevices = xf86FirstLocalDevice(); + while (localDevices) + { + dev= localDevices->dev; + _cursorSetPointerDeviceRotate (dev, pCrtcPriv->user_rotate); + localDevices = localDevices->next; + } + + return TRUE; +} + +static void +_cursorRotateHook (CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + ScrnInfoPtr pScrn = (ScrnInfoPtr) unused; + xf86CrtcPtr pCrtc = xf86CompatCrtc (pScrn); + XacePropertyAccessRec *rec = (XacePropertyAccessRec*)calldata; + PropertyPtr pProp = *rec->ppProp; + Atom name = pProp->propertyName; + + XDBG_RETURN_IF_FAIL (pCrtc != NULL); + + /* Don't care about the new content check */ + if (rec->pWin != pScrn->pScreen->root) //Check Rootwindow + return; + + if (name == atom_rotate_root_angle + && (rec->access_mode & DixWriteAccess)) + { + int rotate_degree = *(int*)pProp->data; + + XDBG_TRACE (MCRS, "[%p] Change root angle(%d)\n", pCrtc, rotate_degree); + secCrtcCursorRotate (pCrtc, secUtilDegreeToRotate (rotate_degree)); + } + + if (name == atom_relative_device_exist + && (rec->access_mode & DixWriteAccess)) + { + int exist = *(int*)pProp->data; + if (exist) + { + _cursorFindRelativeDevice (pCrtc); + XDBG_TRACE (MCRS, "[%p] Change device exist(%d)\n", pCrtc, exist); + } + } + + return; +} + +static void +_cursorRegisterBlockHandler (xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + XDBG_RETURN_IF_FAIL (pCrtcPriv->move_layer == FALSE); + + if (pCrtcPriv->registered_block_handler) + return; + + XDBG_DEBUG (MCRS, "[%p] \n", pCrtc); + + RegisterBlockAndWakeupHandlers (_cursorBlockHandler, + (WakeupHandlerProcPtr)NoopDDA, pCrtc); + + pCrtcPriv->registered_block_handler = TRUE; +} + +static void +_cursorUnregisterBlockHandler (xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + if (!pCrtcPriv->registered_block_handler) + return; + + XDBG_DEBUG (MCRS, "[%p] \n", pCrtc); + + RemoveBlockAndWakeupHandlers (_cursorBlockHandler, + (WakeupHandlerProcPtr)NoopDDA, pCrtc); + + pCrtcPriv->registered_block_handler = FALSE; +} + +static void +_cursorMove (xf86CrtcPtr pCrtc, int x, int y) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + if (!pCrtcPriv->move_layer) + return; + + if (pCrtcPriv->ovl_layer) + { + xRectangle src = {0,}; + xRectangle dst = {0,}; + + src.width = SEC_CURSOR_W; + src.height = SEC_CURSOR_H; + + dst.x = x; + dst.y = y; + dst.width = SEC_CURSOR_W; + dst.height = SEC_CURSOR_H; + + XDBG_DEBUG (MCRS, "[%p] to (%d,%d)\n", pCrtc, x, y); + + secLayerSetRect (pCrtcPriv->ovl_layer, &src, &dst); + } +} + +static void +_cursorInit (xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + XDBG_TRACE (MCRS, "[%p] \n", pCrtc); + + //Damage Create + if (!pCrtcPriv->move_layer) + _cursorRegisterBlockHandler (pCrtc); +} + +static int +_cursorDestroy (xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + XDBG_TRACE (MCRS, "[%p] \n", pCrtc); + + if(pCrtcPriv->saved_image) + { + pixman_image_unref(pCrtcPriv->saved_image); + pCrtcPriv->saved_image = NULL; + } + + if(pCrtcPriv->cursor_image) + { + pixman_image_unref(pCrtcPriv->cursor_image); + pCrtcPriv->cursor_image = NULL; + } + + if(pCrtcPriv->ovl_canvas) + { + XDBG_TRACE (MCRS, "[%p] ovl_canvas(%p) destroy.\n", pCrtc, pCrtcPriv->ovl_canvas); + pixman_image_unref(pCrtcPriv->ovl_canvas); + pCrtcPriv->ovl_canvas = NULL; + pCrtcPriv->need_draw_cursor = TRUE; + } + + if (pCrtcPriv->ovl_layer) + { + XDBG_TRACE (MCRS, "[%p] ovl_layer(%p) destroy.\n", pCrtc, pCrtcPriv->ovl_layer); + secLayerUnref (pCrtcPriv->ovl_layer); + pCrtcPriv->ovl_layer = NULL; + } + + return TRUE; +} + +static void +_cursorShow (xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + SECPtr pSec = SECPTR (pCrtc->scrn); + + if(!pSec->enableCursor) + return; + + if (pCrtcPriv->ovl_layer && !secLayerTurnStatus (pCrtcPriv->ovl_layer)) + secLayerTurn (pCrtcPriv->ovl_layer, TRUE, FALSE); + + XDBG_TRACE (MCRS, "[%p] user_rotate(%d)\n", pCrtc, pCrtcPriv->user_rotate); + + if (pCrtcPriv->move_layer) + { + _overlayEnsureBuffer (pCrtc, pCrtcPriv->move_layer); + _overlayEnsureLayer (pCrtc); + + _cursorEnsureCursorImage (pCrtc); + _cursorEnsureCanvas (pCrtc, pCrtcPriv->ovl_vbuf_cursor, + SEC_CURSOR_W, SEC_CURSOR_H); + _cursorDrawCursor (pCrtc); + + _overlaySelectBuffer (pCrtc, pCrtcPriv->move_layer); + + int offset = _overlayGetXMoveOffset (pCrtc, pCrtcPriv->cursor_win_x); + _cursorMove (pCrtc, pCrtcPriv->cursor_win_x - offset, pCrtcPriv->cursor_win_y); + + if (!secLayerIsVisible (pCrtcPriv->ovl_layer)) + secLayerShow (pCrtcPriv->ovl_layer); + } + else + { + pCrtcPriv->need_cursor_update = TRUE; + _cursorRestoreImage(pCrtc); + _cursorRegisterBlockHandler (pCrtc); + } +} + +static void +_cursorHide (xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + XDBG_TRACE (MCRS, "[%p] \n", pCrtc); + + if (pCrtcPriv->move_layer) + { + if (pCrtcPriv->ovl_layer && secLayerIsVisible (pCrtcPriv->ovl_layer)) + secLayerHide (pCrtcPriv->ovl_layer); + } + else + { + _cursorRestoreImage (pCrtc); + + if (pCrtcPriv->need_off && !pCrtcPriv->cursor_show) + { + if (pCrtcPriv->ovl_layer && secLayerIsVisible (pCrtcPriv->ovl_layer)) + secLayerHide (pCrtcPriv->ovl_layer); + return; + } + } + + if (pCrtcPriv->ovl_layer && secLayerTurnStatus (pCrtcPriv->ovl_layer)) + { + Bool turnoff = FALSE; + + if (pCrtcPriv->ref_overlay && pCrtcPriv->need_off) + turnoff = TRUE; + if (!pCrtcPriv->ref_overlay) + turnoff = TRUE; + + if (turnoff) + _cursorDestroy (pCrtc); + } + + pCrtcPriv->cursor_old_offset = 0; + pCrtcPriv->need_cursor_update = TRUE; +} + +static Bool +_cursorEnable (xf86CrtcPtr pCrtc, Bool enable) +{ + ScrnInfoPtr pScrn = pCrtc->scrn; + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + if (!pCrtcPriv->cursor_show) + return FALSE; + + XDBG_TRACE (MCRS, "[%p] enable(%d) \n", pCrtc, enable); + + if (enable) + { + _cursorShow (pCrtc); + + if (pCrtc == xf86CompatCrtc (pScrn)) + { + PropertyPtr rotate_prop; + + /* Set Current Root Rotation */ + rotate_prop = secUtilGetWindowProperty (pScrn->pScreen->root, + "_E_ILLUME_ROTATE_ROOT_ANGLE"); + if (rotate_prop) + { + int rotate = secUtilDegreeToRotate (*(int*)rotate_prop->data); + pCrtcPriv->user_rotate = rotate; + + //Send swap property to relative input device + _cursorFindRelativeDevice (pCrtc); + } + } + + /* Hook for window rotate */ + atom_rotate_root_angle = MakeAtom ("_E_ILLUME_ROTATE_ROOT_ANGLE" + , strlen ("_E_ILLUME_ROTATE_ROOT_ANGLE"), FALSE); + atom_relative_device_exist = MakeAtom ("X Mouse Exist" + , strlen ("X Mouse Exist"), TRUE); + + if (atom_rotate_root_angle != None) + { + if (!XaceRegisterCallback (XACE_PROPERTY_ACCESS, _cursorRotateHook, pScrn)) + XDBG_ERROR (MCRS, "[%p] Fail XaceRegisterCallback:XACE_PROPERTY_ACCESS\n", pCrtc); + + XDBG_TRACE (MCRS, "[%p] Hook property : _E_ILLUME_ROTATE_ROOT_ANGLE\n", pCrtc); + } + else + XDBG_TRACE (MCRS, "[%p] Cannot find _E_ILLUME_ROTATE_ROOT_ANGLE\n", pCrtc); + } + else + { + XaceDeleteCallback (XACE_PROPERTY_ACCESS, _cursorRotateHook, pScrn); + + _cursorHide (pCrtc); + } + + pCrtcPriv->cursor_old_offset = 0; + + return TRUE; +} + +static Bool +_cursorRotate (xf86CrtcPtr pCrtc, int rotate) +{ + SECPtr pSec = SECPTR (pCrtc->scrn); + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + if (pCrtcPriv->user_rotate == rotate) + return TRUE; + + if (!pCrtcPriv->cursor_show) + return TRUE; + + XDBG_TRACE (MCRS, "[%p] rotate(%d) \n", pCrtc, rotate); + + pCrtcPriv->user_rotate = rotate; + + if (pSec->enableCursor && pCrtcPriv->cursor_show) + { + //Send swap property to relative input device + _cursorFindRelativeDevice (pCrtc); + + if(pCrtcPriv->cursor_image) + { + pixman_image_unref(pCrtcPriv->cursor_image); + pCrtcPriv->cursor_image = NULL; + } + + if (pCrtcPriv->move_layer) + { + _overlayEnsureBuffer (pCrtc, pCrtcPriv->move_layer); + _overlayEnsureLayer (pCrtc); + + _cursorEnsureCursorImage (pCrtc); + _cursorEnsureCanvas (pCrtc, pCrtcPriv->ovl_vbuf_cursor, + SEC_CURSOR_W, SEC_CURSOR_H); + _cursorDrawCursor (pCrtc); + + int offset = _overlayGetXMoveOffset (pCrtc, pCrtcPriv->cursor_win_x); + _cursorMove (pCrtc, pCrtcPriv->cursor_win_x - offset, pCrtcPriv->cursor_win_y); + } + else + { + pCrtcPriv->need_cursor_update = TRUE; + _cursorRestoreImage(pCrtc); + _cursorRegisterBlockHandler (pCrtc); + } + } + + pCrtcPriv->cursor_old_offset = 0; + + return TRUE; +} + +static Bool +_cursorChangeStatus (xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + SECPtr pSec = SECPTR (pCrtc->scrn); + int new_value; + + if (pCrtcPriv->ref_overlay && !pCrtcPriv->need_off) + new_value = FALSE; + else + new_value = TRUE; + + XDBG_TRACE (MCRS, "[%p] ref(%d) off(%d) value(%d=>%d) cursor(%d,%d) \n", pCrtc, + pCrtcPriv->ref_overlay, pCrtcPriv->need_off, pCrtcPriv->move_layer, + new_value, pCrtcPriv->cursor_show, pSec->enableCursor); + + /* layer off if needed */ + if (!pSec->enableCursor && pCrtcPriv->ovl_layer && secLayerTurnStatus (pCrtcPriv->ovl_layer)) + { + Bool turnoff = FALSE; + + if (pCrtcPriv->ref_overlay && pCrtcPriv->need_off) + turnoff = TRUE; + if (!pCrtcPriv->ref_overlay) + turnoff = TRUE; + + if (turnoff) + { + _cursorDestroy (pCrtc); + return TRUE; + } + } + + /* layer on if needed */ + if (pCrtcPriv->ovl_layer && !secLayerTurnStatus (pCrtcPriv->ovl_layer)) + if (pSec->enableCursor || (pCrtcPriv->ref_overlay && !pCrtcPriv->need_off)) + secLayerTurn (pCrtcPriv->ovl_layer, TRUE, FALSE); + + if (pCrtcPriv->move_layer == new_value) + return TRUE; + + pCrtcPriv->move_layer = new_value; + + if(pCrtcPriv->ovl_canvas) + { + XDBG_TRACE (MCRS, "[%p] ovl_canvas(%p) destroy.\n", pCrtc, pCrtcPriv->ovl_canvas); + pixman_image_unref(pCrtcPriv->ovl_canvas); + pCrtcPriv->ovl_canvas = NULL; + pCrtcPriv->need_draw_cursor = TRUE; + } + + if (pCrtcPriv->cursor_show) + _cursorShow (pCrtc); + + if (new_value && pCrtcPriv->ovl_vbuf_pixmap) + { + SECModePtr pSecMode = (SECModePtr) SECPTR (pCrtc->scrn)->pSecMode; + pixman_image_t *old = pCrtcPriv->ovl_canvas; + + pCrtcPriv->ovl_canvas = NULL; + + _cursorEnsureCanvas (pCrtc, pCrtcPriv->ovl_vbuf_pixmap, + pSecMode->main_lcd_mode.hdisplay, + pSecMode->main_lcd_mode.vdisplay); + + _cursorRestoreImage (pCrtc); + + if(pCrtcPriv->ovl_canvas) + pixman_image_unref(pCrtcPriv->ovl_canvas); + + pCrtcPriv->ovl_canvas = old; + } + + if (!pCrtcPriv->ovl_layer) + _overlaySelectBuffer (pCrtc, pCrtcPriv->move_layer); + + if (pCrtcPriv->ovl_layer) + if (!secLayerIsVisible (pCrtcPriv->ovl_layer)) + secLayerShow (pCrtcPriv->ovl_layer); + + return TRUE; +} + +static void +_flipPixmapInit (xf86CrtcPtr pCrtc) +{ + ScrnInfoPtr pScrn = pCrtc->scrn; + SECPtr pSec = SECPTR (pScrn); + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + int flip_backbufs = pSec->flip_bufs - 1; + int i; + + pCrtcPriv->flip_backpixs.lub = -1; + pCrtcPriv->flip_backpixs.num = flip_backbufs; + + pCrtcPriv->flip_backpixs.pix_free = calloc (flip_backbufs, sizeof(void*)); + XDBG_RETURN_IF_FAIL (pCrtcPriv->flip_backpixs.pix_free != NULL); + for (i = 0; i < flip_backbufs; i++) + pCrtcPriv->flip_backpixs.pix_free[i] = TRUE; + pCrtcPriv->flip_backpixs.flip_pixmaps = calloc (flip_backbufs, sizeof(void*)); + pCrtcPriv->flip_backpixs.flip_draws = calloc (flip_backbufs, sizeof(void*)); +} + +static void +_flipPixmapDeinit (xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + ScreenPtr pScreen = pCrtc->scrn->pScreen; + int i; + + for (i = 0; i < pCrtcPriv->flip_backpixs.num; i++) + { + pCrtcPriv->flip_backpixs.pix_free[i] = TRUE; + if (pCrtcPriv->flip_backpixs.flip_pixmaps[i]) + { +#if USE_XDBG + if (pCrtcPriv->flip_backpixs.flip_draws[i]) + xDbgLogPListDrawRemoveRefPixmap (pCrtcPriv->flip_backpixs.flip_draws[i], + pCrtcPriv->flip_backpixs.flip_pixmaps[i]); +#endif + + (*pScreen->DestroyPixmap) (pCrtcPriv->flip_backpixs.flip_pixmaps[i]); + pCrtcPriv->flip_backpixs.flip_pixmaps[i] = NULL; + pCrtcPriv->flip_backpixs.flip_draws[i] = NULL; + } + } + pCrtcPriv->flip_backpixs.lub = -1; +} + +static xf86CrtcPtr +_secCrtcGetFromPipe (ScrnInfoPtr pScrn, int pipe) +{ + xf86CrtcConfigPtr pXf86CrtcConfig; + pXf86CrtcConfig = XF86_CRTC_CONFIG_PTR (pScrn); + xf86CrtcPtr pCrtc = NULL; + SECCrtcPrivPtr pCrtcPriv = NULL; + int i; + + for (i = 0; i < pXf86CrtcConfig->num_output; i++) + { + pCrtc = pXf86CrtcConfig->crtc[i]; + pCrtcPriv = pCrtc->driver_private; + if (pCrtcPriv->pipe == pipe) + { + return pCrtc; + } + } + + return NULL; +} + + +static void +SECCrtcDpms(xf86CrtcPtr pCrtc, int pMode) +{ + +} + +static Bool +SECCrtcSetModeMajor(xf86CrtcPtr pCrtc, DisplayModePtr pMode, + Rotation rotation, int x, int y) +{ + ScrnInfoPtr pScrn = pCrtc->scrn; + SECPtr pSec = SECPTR (pScrn); + SECFbPtr pFb = pSec->pFb; + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + SECModePtr pSecMode = pCrtcPriv->pSecMode; + tbm_bo bo = NULL, old_bo = NULL; + tbm_bo bo_accessibility[2] = {0,}, old_bo_accessibility[2] = {0,}; + int saved_x, saved_y; + Rotation saved_rotation; + DisplayModeRec saved_mode; + Bool ret = FALSE; + + XDBG_DEBUG(MDISP, + "SetModeMajor pMode:%d cur(%dx%d+%d+%d),rot:%d new(%dx%d+%d+%d),refresh(%f)rot:%d\n", + secCrtcID(pCrtcPriv), + pCrtc->mode.HDisplay, pCrtc->mode.VDisplay,pCrtc->x, pCrtc->y, + pCrtc->rotation, + pMode->HDisplay,pMode->VDisplay,x,y,pMode->VRefresh, + rotation); + + memcpy (&saved_mode, &pCrtc->mode, sizeof(DisplayModeRec)); + saved_x = pCrtc->x; + saved_y = pCrtc->y; + saved_rotation = pCrtc->rotation; + + memcpy (&pCrtc->mode, pMode, sizeof(DisplayModeRec)); + pCrtc->x = x; + pCrtc->y = y; + pCrtc->rotation = rotation; + + if (pSec->fake_root) + secDisplaySwapModeToKmode(pCrtc->scrn, &pCrtcPriv->kmode, pMode); + else + secDisplayModeToKmode(pCrtc->scrn, &pCrtcPriv->kmode, pMode); + + /* accessibility */ + if (pCrtcPriv->bAccessibility || pCrtcPriv->screen_rotate_degree > 0) + { + XDBG_GOTO_IF_FAIL (pCrtcPriv->accessibility_front_bo != NULL, fail); + XDBG_GOTO_IF_FAIL (pCrtcPriv->accessibility_back_bo != NULL, fail); + + old_bo_accessibility[0] = pCrtcPriv->accessibility_front_bo; + old_bo_accessibility[1] = pCrtcPriv->accessibility_back_bo; + + bo_accessibility[0] = secRenderBoCreate (pScrn, pMode->HDisplay, pMode->VDisplay); + bo_accessibility[1] = secRenderBoCreate (pScrn, pMode->HDisplay, pMode->VDisplay); + + pCrtcPriv->accessibility_front_bo = bo_accessibility[0]; + pCrtcPriv->accessibility_back_bo = bo_accessibility[1]; + } + + /* find bo which covers the requested mode of crtc */ + old_bo = pCrtcPriv->front_bo; + bo = secFbGetBo(pFb, x, y, pMode->HDisplay, pMode->VDisplay, FALSE); + XDBG_GOTO_IF_FAIL (bo != NULL, fail); + pCrtcPriv->front_bo = bo; + + ret = secCrtcApply(pCrtc); + XDBG_GOTO_IF_FAIL (ret == TRUE, fail); + + /* set the default external mode */ + secDisplayModeToKmode (pCrtc->scrn, &pSecMode->ext_connector_mode, pMode); + + /* accessibility */ + if (pCrtcPriv->bAccessibility || pCrtcPriv->screen_rotate_degree > 0) + { + if (ret) + { + if (old_bo_accessibility[0]) + secRenderBoUnref (old_bo_accessibility[0]); + if (old_bo_accessibility[1]) + secRenderBoUnref (old_bo_accessibility[1]); + } + } + + return ret; +fail: + XDBG_ERROR(MDISP, "Fail crtc apply(crtc_id:%d, rotate:%d, %dx%d+%d+%d\n", + secCrtcID(pCrtcPriv), rotation, x, y, pCrtc->mode.HDisplay, pCrtc->mode.VDisplay); + + pCrtcPriv->front_bo = old_bo; + + /* accessibility */ + if (pCrtcPriv->bAccessibility || pCrtcPriv->screen_rotate_degree > 0) + { + if (bo_accessibility[0]) + secRenderBoUnref (bo_accessibility[0]); + if (bo_accessibility[1]) + secRenderBoUnref (bo_accessibility[1]); + + pCrtcPriv->accessibility_front_bo = old_bo_accessibility[0]; + pCrtcPriv->accessibility_back_bo = old_bo_accessibility[1]; + } + + if (pSec->fake_root) + secDisplaySwapModeToKmode(pCrtc->scrn, &pCrtcPriv->kmode, &saved_mode); + else + secDisplayModeToKmode(pCrtc->scrn, &pCrtcPriv->kmode, &saved_mode); + + memcpy (&pCrtc->mode, &saved_mode, sizeof(DisplayModeRec)); + pCrtc->x = saved_x; + pCrtc->y = saved_y; + pCrtc->rotation = saved_rotation; + + return ret; +} + +static void +SECCrtcSetCursorColors(xf86CrtcPtr pCrtc, int bg, int fg) +{ + XDBG_TRACE (MCRS, "[%p] \n", pCrtc); +} + +static void +SECCrtcSetCursorPosition (xf86CrtcPtr pCrtc, int x, int y) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + SECPtr pSec = SECPTR (pCrtc->scrn); + + pCrtcPriv->cursor_pos_x = x; + pCrtcPriv->cursor_pos_y = y; + + XDBG_DEBUG (MCRS, "[%p] (%d,%d) \n", pCrtc, x, y); + + if (!pSec->enableCursor) + return; + + if (!pCrtcPriv->cursor_show) + return; + + if (pCrtcPriv->move_layer) + { + _cursorEnsureCanvas (pCrtc, pCrtcPriv->ovl_vbuf_cursor, + SEC_CURSOR_W, SEC_CURSOR_H); + _cursorEnsureCursorImage (pCrtc); + + int offset = _overlayGetXMoveOffset (pCrtc, pCrtcPriv->cursor_win_x); + if (pCrtcPriv->cursor_old_offset != offset) + { + _cursorDrawCursor (pCrtc); + pCrtcPriv->cursor_old_offset = offset; + } + + _cursorMove (pCrtc, pCrtcPriv->cursor_win_x - offset, pCrtcPriv->cursor_win_y); + } + else + { + /* Draw cursor in block handler */ + pCrtcPriv->need_cursor_update = TRUE; + _cursorRestoreImage(pCrtc); + _cursorRegisterBlockHandler (pCrtc); + } +} + +static void +SECCrtcShowCursor (xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + XDBG_TRACE (MCRS, "[%p] cursor_show(%d)\n", pCrtc, pCrtcPriv->cursor_show); + + if(pCrtcPriv->cursor_show) + return; + + pCrtcPriv->cursor_show = TRUE; + + _cursorShow (pCrtc); +} + +static void +SECCrtcHideCursor (xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + XDBG_TRACE (MCRS, "[%p] cursor_show(%d)\n", pCrtc, pCrtcPriv->cursor_show); + + if(!pCrtcPriv->cursor_show) + return; + + pCrtcPriv->cursor_show = FALSE; + + _cursorHide (pCrtc); +} + +static void +SECCrtcLoadCursorArgb(xf86CrtcPtr pCrtc, CARD32 *image) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + if (image == NULL) + return; + + XDBG_TRACE (MCRS, "[%p] image(%p) \n", pCrtc, image); + + if (pCrtcPriv->backup_image) + pixman_image_unref (pCrtcPriv->backup_image); + + pCrtcPriv->backup_image = pixman_image_create_bits (PIXMAN_a8r8g8b8 + , SEC_CURSOR_W, SEC_CURSOR_H + , NULL + , 0); + + XDBG_RETURN_IF_FAIL (pCrtcPriv->backup_image != NULL); + + memcpy (pixman_image_get_data(pCrtcPriv->backup_image), image, SEC_CURSOR_W * SEC_CURSOR_H * 4); + + if(pCrtcPriv->cursor_image) + { + pixman_image_unref(pCrtcPriv->cursor_image); + pCrtcPriv->cursor_image = NULL; + } + + pCrtcPriv->need_cursor_update = TRUE; +} + + +static void * +SECCrtcShadowAllocate(xf86CrtcPtr pCrtc, int width, int height) +{ +#if 0 + ScrnInfoPtr scrn = pCrtc->scrn; + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + SECModePtr pSecMode = pCrtcPriv->pSecMode; + unsigned long rotate_pitch; + uint32_t tiling; + int ret; + + pCrtcPriv->rotate_bo = intel_allocate_framebuffer (scrn, + width, height, + pSecMode->cpp, + &rotate_pitch, + &tiling); + + if (!pCrtcPriv->rotate_bo) + { + xf86DrvMsg (pCrtc->scrn->scrnIndex, X_ERROR, + "Couldn't allocate shadow memory for rotated CRTC\n"); + return NULL; + } + + ret = drmModeAddFB (pSecMode->fd, width, height, pCrtc->scrn->depth, + pCrtc->scrn->bitsPerPixel, rotate_pitch, + pCrtcPriv->rotate_bo->handle, + &pCrtcPriv->rotate_fb_id); + if (ret < 0) + { + ErrorF ("failed to add rotate fb\n"); + drm_intel_bo_unreference (pCrtcPriv->rotate_bo); + return NULL; + } + + pCrtcPriv->rotate_pitch = rotate_pitch; + return pCrtcPriv->rotate_bo; +#else + return NULL; +#endif +} + +static PixmapPtr +SECCrtcShadowCreate(xf86CrtcPtr pCrtc, void *data, int width, int height) +{ +#if 0 + ScrnInfoPtr pScrn = pCrtc->scrn; + SECPtr pSEC = SECPtr (pScrn); + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + PixmapPtr rotate_pixmap; + + if (!data) + { + data = SECCrtcShadowAllocate (pCrtc, width, height); + if (!data) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, + "Couldn't allocate shadow pixmap for rotated CRTC\n"); + return NULL; + } + } + if (pCrtcPriv->rotate_bo == NULL) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, + "Couldn't allocate shadow pixmap for rotated CRTC\n"); + return NULL; + } + + rotate_pixmap = GetScratchPixmapHeader (pScrn->pScreen, + width, height, + pScrn->depth, + pScrn->bitsPerPixel, + pCrtcPriv->rotate_pitch, + NULL); + + if (rotate_pixmap == NULL) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, + "Couldn't allocate shadow pixmap for rotated CRTC\n"); + return NULL; + } + +// intel_set_pixmap_bo(rotate_pixmap, pCrtcPriv->rotate_bo); + + pSEC->shadow_present = TRUE; + + return rotate_pixmap; +#else + return NULL; +#endif +} + +static void +SECCrtcShadowDestroy(xf86CrtcPtr pCrtc, PixmapPtr rotate_pixmap, void *data) +{ +#if 0 + ScrnInfoPtr pScrn = pCrtc->scrn; + SECPtr pSEC = SECPtr (pScrn); + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + SECModePtr pSecMode = pCrtcPriv->mode; + + if (rotate_pixmap) + { + intel_set_pixmap_bo (rotate_pixmap, NULL); + FreeScratchPixmapHeader (rotate_pixmap); + } + + if (data) + { + /* Be sure to sync acceleration before the memory gets + * unbound. */ + drmModeRmFB (pSecMode->fd, pCrtcPriv ->rotate_fb_id); + pCrtcPriv ->rotate_fb_id = 0; + + tbm_bo_unreference (pCrtcPriv ->rotate_bo); + pCrtcPriv ->rotate_bo = NULL; + } + + pSEC->shadow_present = pSEC->use_shadow; +#else + return; +#endif +} + +static void +SECCrtcGammaSet(xf86CrtcPtr pCrtc, + CARD16 *red, CARD16 *green, CARD16 *blue, int size) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + SECModePtr pSecMode = pCrtcPriv->pSecMode; + + drmModeCrtcSetGamma(pSecMode->fd, secCrtcID(pCrtcPriv), + size, red, green, blue); +} + +static void +SECCrtcDestroy(xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + DRI2FrameEventPtr event_ref=NULL, event_next=NULL; + xorg_list_for_each_entry_safe (event_ref, event_next, &pCrtcPriv->pending_flips, crtc_pending_link) + { + free (event_ref); + } + + _flipPixmapDeinit (pCrtc); + + _cursorDestroy (pCrtc); + _cursorUnregisterBlockHandler (pCrtc); + +#if 1 + if (pCrtcPriv->pFpsDebug) + { + xDbgLogFpsDebugDestroy (pCrtcPriv->pFpsDebug); + pCrtcPriv->pFpsDebug = NULL; + } +#endif + + if (pCrtcPriv->accessibility_front_bo) + { + secRenderBoUnref (pCrtcPriv->accessibility_front_bo); + pCrtcPriv->accessibility_front_bo = NULL; + } + + if (pCrtcPriv->accessibility_back_bo) + { + secRenderBoUnref (pCrtcPriv->accessibility_back_bo); + pCrtcPriv->accessibility_back_bo = NULL; + } + + if (pCrtcPriv->backup_image) + { + pixman_image_unref(pCrtcPriv->backup_image); + pCrtcPriv->backup_image = NULL; + } + + if (pCrtcPriv->ovl_vbuf_cursor) + { + secUtilVideoBufferUnref (pCrtcPriv->ovl_vbuf_cursor); + pCrtcPriv->ovl_vbuf_cursor = NULL; + } + + if (pCrtcPriv->ovl_vbuf_pixmap) + { + secUtilVideoBufferUnref (pCrtcPriv->ovl_vbuf_pixmap); + pCrtcPriv->ovl_vbuf_pixmap = NULL; + } + + if (pCrtcPriv->ovl_layer) + { + secLayerUnref (pCrtcPriv->ovl_layer); + pCrtcPriv->ovl_layer = NULL; + } + + if (pCrtcPriv->mode_crtc) + drmModeFreeCrtc (pCrtcPriv->mode_crtc); + + if (pCrtcPriv->front_bo) + { + pCrtcPriv->front_bo = NULL; + } + + if (pCrtcPriv->back_bo) + { + secRenderBoUnref(pCrtcPriv->back_bo); + pCrtcPriv->back_bo = NULL; + } + + if( pCrtcPriv->flip_backpixs.pix_free != NULL ) + { + free(pCrtcPriv->flip_backpixs.pix_free); + pCrtcPriv->flip_backpixs.pix_free = NULL; + } + + if( pCrtcPriv->flip_backpixs.flip_pixmaps != NULL ) + { + free(pCrtcPriv->flip_backpixs.flip_pixmaps); + pCrtcPriv->flip_backpixs.flip_pixmaps = NULL; + } + + if( pCrtcPriv->flip_backpixs.flip_draws != NULL ) + { + free(pCrtcPriv->flip_backpixs.flip_draws); + pCrtcPriv->flip_backpixs.flip_draws = NULL; + } + + xorg_list_del (&pCrtcPriv->link); + free (pCrtcPriv); + + pCrtc->driver_private = NULL; +} + +static const xf86CrtcFuncsRec sec_crtc_funcs = +{ + .dpms = SECCrtcDpms, + .set_mode_major = SECCrtcSetModeMajor, + .set_cursor_colors = SECCrtcSetCursorColors, + .set_cursor_position = SECCrtcSetCursorPosition, + .show_cursor = SECCrtcShowCursor, + .hide_cursor = SECCrtcHideCursor, + .load_cursor_argb = SECCrtcLoadCursorArgb, + .shadow_create = SECCrtcShadowCreate, + .shadow_allocate = SECCrtcShadowAllocate, + .shadow_destroy = SECCrtcShadowDestroy, + .gamma_set = SECCrtcGammaSet, + .destroy = SECCrtcDestroy, +}; + +void +secCrtcInit (ScrnInfoPtr pScrn, SECModePtr pSecMode, int num) +{ + xf86CrtcPtr pCrtc; + SECCrtcPrivPtr pCrtcPriv; + SECPtr pSec = SECPTR (pScrn); + +// secLogSetLevel("CRTC", 0); + + pCrtcPriv = calloc (sizeof (SECCrtcPrivRec), 1); + if (pCrtcPriv == NULL) + return; + + pCrtc = xf86CrtcCreate (pScrn, &sec_crtc_funcs); + if (pCrtc == NULL) + { + free (pCrtcPriv); + return; + } + + pCrtcPriv->idx = num; + pCrtcPriv->mode_crtc = drmModeGetCrtc (pSecMode->fd, + pSecMode->mode_res->crtcs[num]); + pCrtcPriv->move_layer = TRUE; + pCrtcPriv->user_rotate = RR_Rotate_0; + + pCrtcPriv->pSecMode = pSecMode; + pCrtc->driver_private = pCrtcPriv; + + pCrtcPriv->pipe = num; + pCrtcPriv->onoff = TRUE; + + xorg_list_init (&pCrtcPriv->pending_flips); + + pCrtcPriv->pCrtc = pCrtc; + +#if 1 + pCrtcPriv->pFpsDebug = xDbgLogFpsDebugCreate (); + if (pCrtcPriv->pFpsDebug == NULL) + { + free (pCrtcPriv); + return; + } +#endif + + if (pSec->enableCursor) + _cursorInit (pCrtc); + + _flipPixmapInit (pCrtc); + + xorg_list_add(&(pCrtcPriv->link), &(pSecMode->crtcs)); +} + +/* check the crtc is on */ +Bool +secCrtcOn(xf86CrtcPtr pCrtc) +{ + ScrnInfoPtr pScrn = pCrtc->scrn; + xf86CrtcConfigPtr pCrtcConfig = XF86_CRTC_CONFIG_PTR (pScrn); + int i; + + if (!pCrtc->enabled) + return FALSE; + + /* Kernel manage CRTC status based out output config */ + for (i = 0; i < pCrtcConfig->num_output; i++) + { + xf86OutputPtr pOutput = pCrtcConfig->output[i]; + if (pOutput->crtc == pCrtc && + secOutputDpmsStatus(pOutput) == DPMSModeOn) + return TRUE; + } + + return TRUE; +} + +Bool +secCrtcApply(xf86CrtcPtr pCrtc) +{ + ScrnInfoPtr pScrn = pCrtc->scrn; + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + SECModePtr pSecMode = pCrtcPriv->pSecMode; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR (pCrtc->scrn); + uint32_t *output_ids; + int output_count = 0; + int fb_id, x, y; + int i; + Bool ret = FALSE; + SECFbBoDataPtr bo_data; + tbm_bo bo; + + output_ids = calloc (sizeof (uint32_t), xf86_config->num_output); + if (!output_ids) + return FALSE; + + for (i = 0; i < xf86_config->num_output; i++) + { + xf86OutputPtr pOutput = xf86_config->output[i]; + SECOutputPrivPtr pOutputPriv; + if (pOutput->crtc != pCrtc) + continue; + + pOutputPriv = pOutput->driver_private; + + /* modify the physical size of monitor */ + if (!strcmp(pOutput->name, "LVDS1")) + { + pOutput->mm_width = pOutputPriv->mode_output->mmWidth; + pOutput->mm_height = pOutputPriv->mode_output->mmHeight; + pOutput->conf_monitor->mon_width = pOutputPriv->mode_output->mmWidth; + pOutput->conf_monitor->mon_height = pOutputPriv->mode_output->mmHeight; + } + + output_ids[output_count] = pOutputPriv->mode_output->connector_id; + output_count++; + } + + if (!xf86CrtcRotate (pCrtc)) + goto done; + + pCrtc->funcs->gamma_set (pCrtc, pCrtc->gamma_red, pCrtc->gamma_green, + pCrtc->gamma_blue, pCrtc->gamma_size); + + /* accessilitity */ + if (pCrtcPriv->bAccessibility || pCrtcPriv->screen_rotate_degree > 0) + { + tbm_bo temp; + bo = pCrtcPriv->accessibility_back_bo; + temp = pCrtcPriv->accessibility_front_bo; + pCrtcPriv->accessibility_front_bo = pCrtcPriv->accessibility_back_bo; + pCrtcPriv->accessibility_back_bo = temp; + } + else + { + bo = pCrtcPriv->front_bo; + } + + tbm_bo_get_user_data(bo, TBM_BO_DATA_FB, (void * *)&bo_data); + x = pCrtc->x-bo_data->pos.x1; + y = pCrtc->y-bo_data->pos.y1; + fb_id = bo_data->fb_id; + + if (pCrtcPriv->rotate_fb_id) + { + fb_id = pCrtcPriv->rotate_fb_id; + x = 0; + y = 0; + } + + XDBG_INFO (MDISP, "fb_id,%d name,%s width,%d height,%d, vrefresh,%d, accessibility,%d\n", + fb_id, pCrtcPriv->kmode.name, pCrtcPriv->kmode.hdisplay, + pCrtcPriv->kmode.vdisplay, pCrtcPriv->kmode.vrefresh, pCrtcPriv->bAccessibility); + + /* turn off the crtc if the same crtc is set already by another display mode + * before the set crtcs + */ + secDisplaySetDispSetMode(pScrn, DISPLAY_SET_MODE_OFF); + + if (!pCrtcPriv->onoff) + secCrtcTurn (pCrtc, TRUE, FALSE, FALSE); + + /* for cache control */ + tbm_bo_map (bo, TBM_DEVICE_2D, TBM_OPTION_READ); + tbm_bo_unmap (bo); + + ret = drmModeSetCrtc(pSecMode->fd, secCrtcID(pCrtcPriv), + fb_id, x, y, output_ids, output_count, + &pCrtcPriv->kmode); + if (ret) + { + XDBG_INFO (MDISP, "failed to set mode: %s\n", strerror (-ret)); + ret = FALSE; + } + else + { + ret = TRUE; + + /* Force DPMS to On for all outputs, which the kernel will have done + * with the mode set. Also, restore the backlight level + */ + for (i = 0; i < xf86_config->num_output; i++) + { + xf86OutputPtr pOutput = xf86_config->output[i]; + SECOutputPrivPtr pOutputPriv; + + if (pOutput->crtc != pCrtc) + continue; + + pOutputPriv = pOutput->driver_private; + + /* TODO :: soolim :: check this out */ + secOutputDpmsSet(pOutput, DPMSModeOn); + pOutputPriv->dpms_mode = DPMSModeOn; + + /* update mode_encoder */ + drmModeFreeEncoder (pOutputPriv->mode_encoder); + pOutputPriv->mode_encoder = + drmModeGetEncoder (pSecMode->fd, pOutputPriv->mode_output->encoders[0]); + + /* set display connector and display set mode */ + if (pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_HDMIA || + pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_HDMIB) + { + secDisplaySetDispConnMode (pScrn, DISPLAY_CONN_MODE_HDMI); + /* TODO : find the display mode */ + secDisplaySetDispSetMode (pScrn, DISPLAY_SET_MODE_EXT); + + /* should be shown again when crtc on. */ + secLayerShowAll (pScrn, LAYER_OUTPUT_EXT); + } + else if (pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_VIRTUAL) + { + secDisplaySetDispConnMode (pScrn, DISPLAY_CONN_MODE_VIRTUAL); + /* TODO : find the display mode */ + secDisplaySetDispSetMode (pScrn, DISPLAY_SET_MODE_EXT); + + /* should be shown again when crtc on. */ + secLayerShowAll (pScrn, LAYER_OUTPUT_EXT); + } + else if (pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_LVDS) + { + /* should be shown again when crtc on. */ + secLayerShowAll (pScrn, LAYER_OUTPUT_LCD); + } + else + XDBG_NEVER_GET_HERE (MDISP); + } + } + + secOutputDrmUpdate (pScrn); + + if (pScrn->pScreen) + xf86_reload_cursors (pScrn->pScreen); + +done: + free (output_ids); + return ret; +} + +Bool +secCrtcOverlayNeedOff (xf86CrtcPtr pCrtc, Bool need_off) +{ + SECCrtcPrivPtr pCrtcPriv; + + XDBG_RETURN_VAL_IF_FAIL (pCrtc != NULL, FALSE); + + pCrtcPriv = pCrtc->driver_private; + XDBG_RETURN_VAL_IF_FAIL (pCrtcPriv != NULL, FALSE); + + pCrtcPriv->need_off = need_off; + + XDBG_TRACE (MCRS, "[%p] need_off(%d) \n", pCrtc, need_off); + + _cursorChangeStatus (pCrtc); + + return TRUE; +} + +Bool +secCrtcOverlayRef (xf86CrtcPtr pCrtc, Bool refer) +{ + SECCrtcPrivPtr pCrtcPriv; + XDBG_RETURN_VAL_IF_FAIL (pCrtc != NULL, FALSE); + + pCrtcPriv = pCrtc->driver_private; + XDBG_RETURN_VAL_IF_FAIL (pCrtcPriv != NULL, FALSE); + + pCrtcPriv->ref_overlay = refer; + + XDBG_TRACE (MCRS, "[%p] refer(%d) \n", pCrtc, refer); + + _cursorChangeStatus (pCrtc); + + return TRUE; +} + +Bool +secCrtcCursorEnable (ScrnInfoPtr pScrn, Bool enable) +{ + SECModePtr pSecMode = (SECModePtr) SECPTR (pScrn)->pSecMode; + SECCrtcPrivPtr pCur = NULL, pNext = NULL; + + xorg_list_for_each_entry_safe (pCur, pNext, &pSecMode->crtcs, link) + { + xf86CrtcPtr pCrtc = pCur->pCrtc; + int connector_type = secCrtcGetConnectType (pCrtc); + if (connector_type != DRM_MODE_CONNECTOR_Unknown) + _cursorEnable (pCrtc, enable); + } + + return TRUE; +} + +Bool +secCrtcCursorRotate (xf86CrtcPtr pCrtc, int rotate) +{ + return _cursorRotate (pCrtc, rotate); +} + +xf86CrtcPtr +secCrtcGetAtGeometry (ScrnInfoPtr pScrn, int x, int y, int width, int height) +{ + BoxRec box; + + XDBG_RETURN_VAL_IF_FAIL (pScrn != NULL, NULL); + + box.x1 = x; + box.y1 = y; + box.x2 = box.x1 + width; + box.y2 = box.y1 + height; + + return secModeCoveringCrtc (pScrn, &box, NULL, NULL); +} + +int +secCrtcGetConnectType (xf86CrtcPtr pCrtc) +{ + xf86CrtcConfigPtr pCrtcConfig; + int i; + + XDBG_RETURN_VAL_IF_FAIL (pCrtc != NULL, DRM_MODE_CONNECTOR_Unknown); + + pCrtcConfig = XF86_CRTC_CONFIG_PTR (pCrtc->scrn); + XDBG_RETURN_VAL_IF_FAIL (pCrtcConfig != NULL, DRM_MODE_CONNECTOR_Unknown); + + for (i = 0; i < pCrtcConfig->num_output; i++) + { + xf86OutputPtr pOutput = pCrtcConfig->output[i]; + SECOutputPrivPtr pOutputPriv = pOutput->driver_private; + + if (pOutput->crtc == pCrtc) + return pOutputPriv->mode_output->connector_type; + } + + return DRM_MODE_CONNECTOR_Unknown; +} + +Bool +secCrtcIsFlipping (xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv; + + XDBG_RETURN_VAL_IF_FAIL (pCrtc != NULL, FALSE); + pCrtcPriv = pCrtc->driver_private; + + /* if isFlipping is true, return true */ + if (pCrtcPriv->is_flipping) + return TRUE; + + /* if there is pending_flips in the list, return true */ + if (!xorg_list_is_empty (&pCrtcPriv->pending_flips)) + return TRUE; + + return FALSE; +} + + +DRI2FrameEventPtr +secCrtcGetPendingFlip (xf86CrtcPtr pCrtc, DRI2FrameEventPtr pEvent) +{ + SECCrtcPrivPtr pCrtcPriv; + DRI2FrameEventPtr item=NULL, tmp=NULL; + + XDBG_RETURN_VAL_IF_FAIL (pCrtc != NULL, NULL); + pCrtcPriv = pCrtc->driver_private; + + if (xorg_list_is_empty (&pCrtcPriv->pending_flips)) + return NULL; + + xorg_list_for_each_entry_safe(item, tmp, &pCrtcPriv->pending_flips, crtc_pending_link) + { + if (item == pEvent) + return item; + } + + return NULL; +} + + + +DRI2FrameEventPtr +secCrtcGetFirstPendingFlip (xf86CrtcPtr pCrtc) +{ + DRI2FrameEventPtr pEvent = NULL; + SECCrtcPrivPtr pCrtcPriv; + DRI2FrameEventPtr item=NULL, tmp=NULL; + + XDBG_RETURN_VAL_IF_FAIL (pCrtc != NULL, NULL); + pCrtcPriv = pCrtc->driver_private; + + if (xorg_list_is_empty (&pCrtcPriv->pending_flips)) + return NULL; + + xorg_list_for_each_entry_safe(item, tmp, &pCrtcPriv->pending_flips, crtc_pending_link) + { + /* get the last item in the circular list ( last item is at last_item.next==head)*/ + if (item->crtc_pending_link.next == &pCrtcPriv->pending_flips) + { + pEvent = item; + break; + } + } + + return pEvent; +} + +void +secCrtcAddPendingFlip (xf86CrtcPtr pCrtc, DRI2FrameEventPtr pEvent) +{ + SECCrtcPrivPtr pCrtcPriv; + + XDBG_RETURN_IF_FAIL (pCrtc != NULL); + + pCrtcPriv = pCrtc->driver_private; + + xorg_list_add(&(pEvent->crtc_pending_link), &(pCrtcPriv->pending_flips)); +} + +void +secCrtcRemovePendingFlip (xf86CrtcPtr pCrtc, DRI2FrameEventPtr pEvent) +{ + SECCrtcPrivPtr pCrtcPriv; + DRI2FrameEventPtr item=NULL, tmp=NULL; + + XDBG_RETURN_IF_FAIL (pCrtc != NULL); + + pCrtcPriv = pCrtc->driver_private; + + if (xorg_list_is_empty (&pCrtcPriv->pending_flips)) + return; + + xorg_list_for_each_entry_safe(item, tmp, &pCrtcPriv->pending_flips, crtc_pending_link) + { + if (item == pEvent) + { + xorg_list_del(&item->crtc_pending_link); + } + } +} + +static Bool +_secCrtcExecAccessibilityScaleNegative (xf86CrtcPtr pCrtc, tbm_bo src_bo, tbm_bo dst_bo) +{ + XDBG_RETURN_VAL_IF_FAIL(pCrtc != NULL, FALSE); + + SECPtr pSec = SECPTR(pCrtc->scrn); + + if (pSec->isLcdOff) + { + XDBG_INFO (MDISP, "Accessibility execute : LCD IS OFF\n"); + return TRUE; + } + + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + XDBG_RETURN_VAL_IF_FAIL(src_bo != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL(dst_bo != NULL, FALSE); + + SECFbBoDataPtr src_bo_data; + SECFbBoDataPtr dst_bo_data; + G2dColorKeyMode mode; + G2dImage *srcImg = NULL, *dstImg = NULL; + unsigned int src_bo_w, src_bo_h, src_bo_stride; + unsigned int dst_bo_w, dst_bo_h, dst_bo_stride; + int src_x, src_y; + unsigned int src_w, src_h; + int negative = 0; + tbm_bo_handle src_bo_handle; + tbm_bo_handle dst_bo_handle; + + tbm_bo_get_user_data (src_bo, TBM_BO_DATA_FB, (void * *)&src_bo_data); + XDBG_RETURN_VAL_IF_FAIL(src_bo_data != NULL, FALSE); + + tbm_bo_get_user_data (dst_bo, TBM_BO_DATA_FB, (void * *)&dst_bo_data); + XDBG_RETURN_VAL_IF_FAIL(dst_bo_data != NULL, FALSE); + + src_bo_w = src_bo_data->pos.x2 - src_bo_data->pos.x1; + src_bo_h = src_bo_data->pos.y2 - src_bo_data->pos.y1; + src_bo_stride = src_bo_w * 4; + + dst_bo_w = dst_bo_data->pos.x2 - dst_bo_data->pos.x1; + dst_bo_h = dst_bo_data->pos.y2 - dst_bo_data->pos.y1; + dst_bo_stride = dst_bo_w * 4; + + mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + src_bo_handle = tbm_bo_map (src_bo, TBM_DEVICE_2D, TBM_OPTION_READ); + dst_bo_handle = tbm_bo_map (dst_bo, TBM_DEVICE_2D, TBM_OPTION_WRITE); + + srcImg = g2d_image_create_bo (mode, src_bo_w, src_bo_h, src_bo_handle.u32, src_bo_stride); + dstImg = g2d_image_create_bo (mode, dst_bo_w, dst_bo_h, dst_bo_handle.u32, dst_bo_stride); + if (!srcImg || !dstImg) + { + XDBG_ERROR (MDISP, "Accessibility : Fail to create g2d_image\n"); + tbm_bo_unmap(src_bo); + tbm_bo_unmap(dst_bo); + + if (srcImg) + g2d_image_free (srcImg); + + if (dstImg) + g2d_image_free (dstImg); + + return FALSE; + } + + if (pCrtcPriv->accessibility_status == ACCESSIBILITY_MODE_NEGATIVE) + { + negative = 1; + } + + if (pCrtcPriv->bScale) + { + src_x = pCrtcPriv->sx; + src_y = pCrtcPriv->sy; + src_w = pCrtcPriv->sw; + src_h = pCrtcPriv->sh; + } + else + { + src_x = 0; + src_y = 0; + src_w = src_bo_w; + src_h = src_bo_h; + } + + util_g2d_copy_with_scale(srcImg, dstImg, + src_x, src_y, src_w, src_h, + 0, 0, dst_bo_w, dst_bo_h, + negative); + g2d_exec (); + + tbm_bo_unmap(src_bo); + tbm_bo_unmap(dst_bo); + + g2d_image_free (srcImg); + g2d_image_free (dstImg); + + return TRUE; +} + +static Bool +_secCrtcExecRotate (xf86CrtcPtr pCrtc, tbm_bo src_bo, tbm_bo dst_bo) +{ + SECPtr pSec; + SECCrtcPrivPtr pCrtcPriv; + struct drm_exynos_ipp_queue_buf buf; + + XDBG_RETURN_VAL_IF_FAIL(pCrtc != NULL, FALSE); + + pCrtcPriv = pCrtc->driver_private; + XDBG_RETURN_VAL_IF_FAIL(pCrtcPriv->screen_rotate_prop_id > 0, FALSE); + + pSec = SECPTR(pCrtc->scrn); + if (pSec->isLcdOff) + { + XDBG_INFO (MDISP, "screen rotate execute : LCD IS OFF\n"); + return TRUE; + } + + CLEAR (buf); + buf.ops_id = EXYNOS_DRM_OPS_SRC; + buf.buf_type = IPP_BUF_ENQUEUE; + buf.prop_id = pCrtcPriv->screen_rotate_prop_id; + buf.handle[0] = (__u32)tbm_bo_get_handle (src_bo, TBM_DEVICE_DEFAULT).u32; + + if (!secDrmIppQueueBuf (pCrtc->scrn, &buf)) + return FALSE; + + CLEAR (buf); + buf.ops_id = EXYNOS_DRM_OPS_DST; + buf.buf_type = IPP_BUF_ENQUEUE; + buf.prop_id = pCrtcPriv->screen_rotate_prop_id; + buf.handle[0] = (__u32)tbm_bo_get_handle (dst_bo, TBM_DEVICE_DEFAULT).u32; + + if (!secDrmIppQueueBuf (pCrtc->scrn, &buf)) + return FALSE; + + if (pCrtcPriv->screen_rotate_ipp_status == IPP_CTRL_STOP) + { + struct drm_exynos_ipp_cmd_ctrl ctrl = {0,}; + ctrl.prop_id = pCrtcPriv->screen_rotate_prop_id; + ctrl.ctrl = IPP_CTRL_PLAY; + secDrmIppCmdCtrl (pCrtc->scrn, &ctrl); + pCrtcPriv->screen_rotate_ipp_status = IPP_CTRL_PLAY; + + XDBG_INFO (MDISP, "screen rotate ipp(id:%d) play\n", + pCrtcPriv->screen_rotate_prop_id); + } + else if (pCrtcPriv->screen_rotate_ipp_status == IPP_CTRL_PAUSE) + { + struct drm_exynos_ipp_cmd_ctrl ctrl = {0,}; + ctrl.prop_id = pCrtcPriv->screen_rotate_prop_id; + ctrl.ctrl = IPP_CTRL_RESUME; + secDrmIppCmdCtrl (pCrtc->scrn, &ctrl); + pCrtcPriv->screen_rotate_ipp_status = IPP_CTRL_RESUME; + + XDBG_INFO (MDISP, "screen rotate ipp(id:%d) resume\n", + pCrtcPriv->screen_rotate_prop_id); + } + + return TRUE; +} + +Bool +secCrtcExecAccessibility (xf86CrtcPtr pCrtc, tbm_bo src_bo, tbm_bo dst_bo) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + Bool ret = FALSE; + CARD32 elapsed = 0; + SECPtr pSec = SECPTR(pCrtc->scrn); + + tbm_bo_map(src_bo, TBM_DEVICE_2D, TBM_OPTION_READ); + tbm_bo_map(dst_bo, TBM_DEVICE_2D, TBM_OPTION_READ); + + if (pSec->xvperf_mode & XBERC_XVPERF_MODE_ACCESS) + elapsed = GetTimeInMillis (); + + if (pCrtcPriv->screen_rotate_degree > 0) + ret = _secCrtcExecRotate (pCrtc, src_bo, dst_bo); + else if (pCrtcPriv->bAccessibility) + ret = _secCrtcExecAccessibilityScaleNegative (pCrtc, src_bo, dst_bo); + else + XDBG_NEVER_GET_HERE (MDISP); + + if (pSec->xvperf_mode & XBERC_XVPERF_MODE_ACCESS) + ErrorF ("Access exec: %3ld ms \n", GetTimeInMillis()-elapsed); + + tbm_bo_unmap(src_bo); + tbm_bo_unmap(dst_bo); + + return ret; +} + +Bool +secCrtcEnableAccessibility (xf86CrtcPtr pCrtc) +{ + XDBG_RETURN_VAL_IF_FAIL (pCrtc != NULL, FALSE); + + ScrnInfoPtr pScrn = pCrtc->scrn; + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + /* accessibility and screen rotate can't be enable at the same time */ + XDBG_RETURN_VAL_IF_FAIL (pCrtcPriv->screen_rotate_degree == 0, FALSE); + + int bAccessibility = (pCrtcPriv->accessibility_status | pCrtcPriv->bScale); + int width = pCrtc->mode.HDisplay; + int height = pCrtc->mode.VDisplay; + + SECLayer *pLayer = NULL; + xf86CrtcConfigPtr pCrtcConfig = XF86_CRTC_CONFIG_PTR (pCrtc->scrn); + xf86OutputPtr pOutput = NULL; + int i; + for (i = 0; i < pCrtcConfig->num_output; i++) + { + xf86OutputPtr pTemp = pCrtcConfig->output[i]; + if (pTemp->crtc == pCrtc) + { + pOutput = pTemp; + break; + } + } + XDBG_RETURN_VAL_IF_FAIL (pOutput != NULL, FALSE); + + SECOutputPrivPtr pOutputPriv = pOutput->driver_private; + SECLayerOutput output = LAYER_OUTPUT_LCD; + + if (pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_LVDS || + pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_Unknown) + { + output = LAYER_OUTPUT_LCD; + } + else if (pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_HDMIA || + pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_HDMIB || + pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_VIRTUAL) + { + output = LAYER_OUTPUT_EXT; + } + else + XDBG_NEVER_GET_HERE (MACCE); + + + if (bAccessibility) + { + if (!pCrtcPriv->accessibility_front_bo) + { + pCrtcPriv->accessibility_front_bo = secRenderBoCreate (pScrn, width, height); + XDBG_RETURN_VAL_IF_FAIL (pCrtcPriv->accessibility_front_bo != NULL, FALSE); + } + + pCrtcPriv->bAccessibility = TRUE; + + /* do accessibility */ + if (!secCrtcExecAccessibility (pCrtc, pCrtcPriv->front_bo, pCrtcPriv->accessibility_front_bo)) + { + XDBG_ERROR (MDISP, "Accessibility : Fail to execute accessibility\n"); + secRenderBoUnref(pCrtcPriv->accessibility_front_bo); + pCrtcPriv->accessibility_front_bo = NULL; + pCrtcPriv->bAccessibility = FALSE; + return FALSE; + } + + XDBG_INFO (MDISP, "accessibility_status(%d), scale(%d):[sx,sy,sw,sh]=[%d,%d,%d,%d]\n", + pCrtcPriv->accessibility_status, + pCrtcPriv->bScale, pCrtcPriv->sx, pCrtcPriv->sy, pCrtcPriv->sw, pCrtcPriv->sh); + + /* layer update */ + pLayer = secLayerFind (output, LAYER_UPPER); + if (pLayer && secLayerIsVisible (pLayer)) + secLayerUpdate (pLayer); + + /* set crtc when accessibility buffer destroy, or drmvlank is error */ + if (!secCrtcApply (pCrtc)) + { + + XDBG_ERROR (MDISP, "Accessibility : Fail to set crtc\n"); + secRenderBoUnref(pCrtcPriv->accessibility_front_bo); + pCrtcPriv->accessibility_front_bo = NULL; + pCrtcPriv->bAccessibility = FALSE; + return FALSE; + } + + } + else + { + pCrtcPriv->bAccessibility = FALSE; + + XDBG_INFO (MDISP, "accessibility_status(%d), scale(%d):[sx,sy,sw,sh]=[%d,%d,%d,%d]\n", + pCrtcPriv->accessibility_status, + pCrtcPriv->bScale, pCrtcPriv->sx, pCrtcPriv->sy, pCrtcPriv->sw, pCrtcPriv->sh); + + if (!secCrtcApply (pCrtc)) + { + XDBG_ERROR (MDISP, "Accessibility : Fail to set crtc\n"); + pCrtcPriv->bAccessibility = TRUE; + return FALSE; + } + + /* layer update */ + pLayer = secLayerFind (output, LAYER_UPPER); + if (pLayer && secLayerIsVisible (pLayer)) + secLayerUpdate (pLayer); + } + + return TRUE; +} + +Bool +secCrtcEnableScreenRotate (xf86CrtcPtr pCrtc, Bool enable) +{ +#ifdef _F_WEARABLE_FEATURE_ + XDBG_RETURN_VAL_IF_FAIL (pCrtc != NULL, FALSE); + + ScrnInfoPtr pScrn = pCrtc->scrn; + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + int width = pCrtc->mode.HDisplay; + int height = pCrtc->mode.VDisplay; + int degree = pCrtcPriv->screen_rotate_degree; + + /* accessibility and screen rotate can't be enable at the same time */ + XDBG_RETURN_VAL_IF_FAIL (pCrtcPriv->bAccessibility == FALSE, FALSE); + + if (enable) + { + struct drm_exynos_ipp_property property; + int prop_id; + + if (!pCrtcPriv->accessibility_front_bo) + { + pCrtcPriv->accessibility_front_bo = secRenderBoCreate (pScrn, width, height); + XDBG_RETURN_VAL_IF_FAIL (pCrtcPriv->accessibility_front_bo != NULL, FALSE); + + pCrtcPriv->accessibility_back_bo = secRenderBoCreate (pScrn, width, height); + XDBG_RETURN_VAL_IF_FAIL (pCrtcPriv->accessibility_back_bo != NULL, FALSE); + } + + prop_id = pCrtcPriv->screen_rotate_prop_id; + if (prop_id != 0) + { + struct drm_exynos_ipp_cmd_ctrl ctrl = {0,}; + ctrl.prop_id = pCrtcPriv->screen_rotate_prop_id; + ctrl.ctrl = IPP_CTRL_PAUSE; + secDrmIppCmdCtrl (pScrn, &ctrl); + pCrtcPriv->screen_rotate_ipp_status = IPP_CTRL_PAUSE; + XDBG_INFO (MDISP, "screen rotate ipp(id:%d) pause\n", + pCrtcPriv->screen_rotate_prop_id); + } + else + pCrtcPriv->screen_rotate_ipp_status = IPP_CTRL_STOP; + + CLEAR (property); + property.config[0].ops_id = EXYNOS_DRM_OPS_SRC; + property.config[0].fmt = DRM_FORMAT_ARGB8888; + property.config[0].sz.hsize = (__u32)width; + property.config[0].sz.vsize = (__u32)height; + property.config[0].pos.x = 0; + property.config[0].pos.y = 0; + property.config[0].pos.w = (__u32)width; + property.config[0].pos.h = (__u32)height; + property.config[1].ops_id = EXYNOS_DRM_OPS_DST; + if (degree % 360 == 90) + property.config[1].degree = EXYNOS_DRM_DEGREE_90; + else if (degree % 360 == 180) + property.config[1].degree = EXYNOS_DRM_DEGREE_180; + else if (degree % 360 == 270) + property.config[1].degree = EXYNOS_DRM_DEGREE_270; + else + property.config[1].degree = EXYNOS_DRM_DEGREE_0; + property.config[1].fmt = DRM_FORMAT_ARGB8888; + property.config[1].sz.hsize = width; + property.config[1].sz.vsize = height; + property.config[1].pos.x = (__u32)0; + property.config[1].pos.y = (__u32)0; + property.config[1].pos.w = (__u32)width; + property.config[1].pos.h = (__u32)height; + + property.cmd = IPP_CMD_M2M; + property.type = IPP_SYNC_WORK; + property.prop_id = prop_id; + + prop_id = secDrmIppSetProperty (pScrn, &property); + XDBG_RETURN_VAL_IF_FAIL (prop_id != 0, FALSE); + pCrtcPriv->screen_rotate_prop_id = prop_id; + + XDBG_INFO (MDISP, "screen rotate ipp(id:%d) start\n", prop_id); + } + else + { + if (pCrtcPriv->screen_rotate_prop_id > 0) + { + struct drm_exynos_ipp_cmd_ctrl ctrl = {0,}; + ctrl.prop_id = pCrtcPriv->screen_rotate_prop_id; + ctrl.ctrl = IPP_CTRL_STOP; + secDrmIppCmdCtrl (pScrn, &ctrl); + pCrtcPriv->screen_rotate_prop_id = 0; + pCrtcPriv->screen_rotate_ipp_status = IPP_CTRL_STOP; + XDBG_INFO (MDISP, "screen rotate ipp(id:%d) stop\n", + pCrtcPriv->screen_rotate_prop_id); + } + } +#endif + return TRUE; +} + +Bool +secCrtcScreenRotate (xf86CrtcPtr pCrtc, int degree) +{ +#ifdef _F_WEARABLE_FEATURE_ + XDBG_RETURN_VAL_IF_FAIL (pCrtc != NULL, FALSE); + + ScrnInfoPtr pScrn = pCrtc->scrn; + SECPtr pSec = SECPTR(pCrtc->scrn); + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + CARD32 elapsed[3] = {0,}; + + if (pCrtcPriv->screen_rotate_degree == degree) + return TRUE; + + /* accessibility and screen rotate can't be enable at the same time */ + XDBG_RETURN_VAL_IF_FAIL (pCrtcPriv->bAccessibility == FALSE, FALSE); + + pCrtcPriv->screen_rotate_degree = degree; + + if (pSec->isLcdOff) + { + XDBG_INFO (MDISP, "screen rotate(degree:%d)\n", degree); + secVideoScreenRotate (pScrn, degree); + return TRUE; + } + + elapsed[0] = GetTimeInMillis (); + + if (degree > 0) + { + secCrtcEnableScreenRotate (pCrtc, TRUE); + + /* do accessibility */ + if (!secCrtcExecAccessibility (pCrtc, pCrtcPriv->front_bo, pCrtcPriv->accessibility_back_bo)) + { + secRenderBoUnref(pCrtcPriv->accessibility_front_bo); + pCrtcPriv->accessibility_front_bo = NULL; + secRenderBoUnref(pCrtcPriv->accessibility_back_bo); + pCrtcPriv->accessibility_back_bo = NULL; + return FALSE; + } + } + else + secCrtcEnableScreenRotate (pCrtc, FALSE); + + elapsed[1] = GetTimeInMillis (); + + secCrtcApply (pCrtc); + + elapsed[2] = GetTimeInMillis (); + + secVideoScreenRotate (pScrn, degree); + + XDBG_INFO (MDISP, "screen rotate done(degree:%d, dur:%ld~%ld~%ld ms)\n", + degree, elapsed[1]-elapsed[0],elapsed[2]-elapsed[1], + GetTimeInMillis()-elapsed[2]); +#endif + return TRUE; +} + +Bool +secCrtcTurn (xf86CrtcPtr pCrtc, Bool onoff, Bool always, Bool user) +{ + SECModePtr pSecMode = SECPTR (pCrtc->scrn)->pSecMode; + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + int crtc_id = secCrtcID(pCrtcPriv); + int mode; + + mode = (onoff > 0) ? 0 : 1; + + if (pCrtcPriv->onoff == onoff) + { + pCrtcPriv->onoff_always = always; + XDBG_ERROR (MDISP, "Crtc(%d) UI layer is '%s'%s\n", + crtc_id, (onoff)?"ON":"OFF", (always)?"(always).":"."); + return TRUE; + } + + if (pCrtcPriv->onoff_always) + if (!always) + { + XDBG_ERROR (MDISP, "Crtc(%d) UI layer can't be '%s'.\n", crtc_id, (onoff)?"ON":"OFF"); + return FALSE; + } + + /* 0 : normal, 1 : blank, 2 : defer */ + if (!secUtilSetDrmProperty (pSecMode, crtc_id, + DRM_MODE_OBJECT_CRTC, "mode", mode)) + { + XDBG_ERROR (MDISP, "SetDrmProperty failed. crtc(%d) onoff(%d) \n", crtc_id, onoff); + return FALSE; + } + + pCrtcPriv->onoff = onoff; + pCrtcPriv->onoff_always = always; + + XDBG_INFO (MDISP, "%s >> crtc(%d) UI layer '%s'%s\n", (user)?"user":"Xorg", + crtc_id, (onoff)?"ON":"OFF", (always)?"(always).":"."); + + return TRUE; +} + +Bool +secCrtcCheckOn (xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + return pCrtcPriv->onoff; +} + +/* return true if there is no flip pixmap available */ +Bool +secCrtcFullFreeFlipPixmap (ScrnInfoPtr pScrn, int crtc_pipe) +{ + xf86CrtcPtr pCrtc = NULL; + SECCrtcPrivPtr pCrtcPriv = NULL; + int i; + + pCrtc = _secCrtcGetFromPipe (pScrn, crtc_pipe); + XDBG_RETURN_VAL_IF_FAIL(pCrtc != NULL, FALSE); + + pCrtcPriv = pCrtc->driver_private; + + /* there is a free flip pixmap, return false */ + for (i = 0; i < pCrtcPriv->flip_backpixs.num; i++) + { + if (pCrtcPriv->flip_backpixs.pix_free[i]) + { + return FALSE; + } + } + + XDBG_WARNING (MFLIP, "no free flip pixmap\n"); + + return TRUE; +} + +#define GET_NEXT_IDX(idx, max) (((idx+1) % (max))) +PixmapPtr +secCrtcGetFreeFlipPixmap (ScrnInfoPtr pScrn, int crtc_pipe, DrawablePtr pDraw, unsigned int usage_hint) +{ + xf86CrtcPtr pCrtc = NULL; + SECCrtcPrivPtr pCrtcPriv = NULL; + PixmapPtr pPixmap = NULL; + ScreenPtr pScreen = pScrn->pScreen; + int i; + int check_release = 0; + + pCrtc = _secCrtcGetFromPipe (pScrn, crtc_pipe); + XDBG_RETURN_VAL_IF_FAIL(pCrtc != NULL, FALSE); + + pCrtcPriv = pCrtc->driver_private; + + /* check if there is free flip pixmaps */ + if (secCrtcFullFreeFlipPixmap(pScrn, crtc_pipe)) + { + /* case : flip pixmap is never release + if flip_count is 0 where there is no uncompleted pageflipping, + release the flip_pixmap which occupied by a drawable. */ + if (pCrtcPriv->flip_count == 0) + { + secCrtcRelAllFlipPixmap (pScrn, crtc_pipe); + check_release = 1; + XDBG_WARNING (MFLIP, "@@ release the drawable pre-occuiped the flip_pixmap\n"); + } + + /* return null, if there is no flip_backpixmap which can release */ + if (!check_release) + return NULL; + } + + /* return flip pixmap */ + for (i = GET_NEXT_IDX(pCrtcPriv->flip_backpixs.lub, pCrtcPriv->flip_backpixs.num) + ; i < pCrtcPriv->flip_backpixs.num + ; i = GET_NEXT_IDX(i, pCrtcPriv->flip_backpixs.num)) + { + if (pCrtcPriv->flip_backpixs.pix_free[i]) + { + if (pCrtcPriv->flip_backpixs.flip_pixmaps[i]) + { + pPixmap = pCrtcPriv->flip_backpixs.flip_pixmaps[i]; + XDBG_DEBUG (MFLIP, "the index(%d, %d) of the flip pixmap in pipe(%d) is set\n", + i, tbm_bo_export(secExaPixmapGetBo(pPixmap)), crtc_pipe); + } + else + { + pPixmap = (*pScreen->CreatePixmap) (pScreen, + pDraw->width, + pDraw->height, + pDraw->depth, + usage_hint); + XDBG_RETURN_VAL_IF_FAIL(pPixmap != NULL, NULL); + pCrtcPriv->flip_backpixs.flip_pixmaps[i] = pPixmap; + + XDBG_DEBUG (MFLIP, + "the index(%d, %d) of the flip pixmap in pipe(%d) is created\n", + i, tbm_bo_export(secExaPixmapGetBo(pPixmap)), crtc_pipe); + } + +#if USE_XDBG + if (pCrtcPriv->flip_backpixs.flip_draws[i] && + (pCrtcPriv->flip_backpixs.flip_draws[i] != pDraw)) + { + xDbgLogPListDrawRemoveRefPixmap (pCrtcPriv->flip_backpixs.flip_draws[i], + pCrtcPriv->flip_backpixs.flip_pixmaps[i]); + } +#endif + + pCrtcPriv->flip_backpixs.pix_free[i] = FALSE; + pCrtcPriv->flip_backpixs.flip_draws[i] = pDraw; + pCrtcPriv->flip_backpixs.lub = i; + +#if USE_XDBG + xDbgLogPListDrawAddRefPixmap (pDraw, pPixmap); +#endif + break; + } + } + + return pPixmap; +} + +void +secCrtcRelFlipPixmap (ScrnInfoPtr pScrn, int crtc_pipe, PixmapPtr pPixmap) +{ + xf86CrtcPtr pCrtc = NULL; + SECCrtcPrivPtr pCrtcPriv = NULL; + int i; + + pCrtc = _secCrtcGetFromPipe (pScrn, crtc_pipe); + XDBG_RETURN_IF_FAIL(pCrtc != NULL); + + pCrtcPriv = pCrtc->driver_private; + + /* release flip pixmap */ + for (i = 0; i < pCrtcPriv->flip_backpixs.num; i++) + { + if (pPixmap == pCrtcPriv->flip_backpixs.flip_pixmaps[i]) + { + pCrtcPriv->flip_backpixs.pix_free[i] = TRUE; + /*pCrtcPriv->flip_backpixs.flip_draws[i] = NULL;*/ + + XDBG_DEBUG (MFLIP, "the index(%d, %d) of the flip pixmap in pipe(%d) is unset\n", + i, tbm_bo_export(secExaPixmapGetBo(pPixmap)), crtc_pipe); + break; + } + } +} + +void +secCrtcRelAllFlipPixmap (ScrnInfoPtr pScrn, int crtc_pipe) +{ + xf86CrtcPtr pCrtc = NULL; + SECCrtcPrivPtr pCrtcPriv = NULL; + int i; + + pCrtc = _secCrtcGetFromPipe (pScrn, crtc_pipe); + XDBG_RETURN_IF_FAIL(pCrtc != NULL); + + pCrtcPriv = pCrtc->driver_private; + + /* release flip pixmap */ + for (i = 0; i < pCrtcPriv->flip_backpixs.num; i++) + { + pCrtcPriv->flip_backpixs.pix_free[i] = TRUE; + /*pCrtcPriv->flip_backpixs.flip_draws[i] = NULL;*/ + + XDBG_DEBUG (MFLIP, + "the index(%d) of the flip draw in pipe(%d) is unset\n", + i, crtc_pipe); + } +} + +void +secCrtcRemoveFlipPixmap (xf86CrtcPtr pCrtc) +{ + _flipPixmapDeinit (pCrtc); +} + +void +secCrtcCountFps(xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = NULL; + int conn_type; + + if (!pCrtc->enabled) + return; + + pCrtcPriv = pCrtc->driver_private; + conn_type = secCrtcGetConnectType (pCrtc); + + xDbgLogFpsDebugCount (pCrtcPriv->pFpsDebug, conn_type); +} diff --git a/src/crtcconfig/sec_crtc.h b/src/crtcconfig/sec_crtc.h new file mode 100755 index 0000000..64d4a44 --- /dev/null +++ b/src/crtcconfig/sec_crtc.h @@ -0,0 +1,170 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@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. + +**************************************************************************/ + +#ifndef __SEC_CRTC_H__ +#define __SEC_CRTC_H__ + +#include "sec_display.h" +#include "sec_layer.h" +#include "sec_util.h" + +typedef enum +{ + ACCESSIBILITY_MODE_NONE, + ACCESSIBILITY_MODE_NEGATIVE, +}ACCESSIBILITY_STATUS; + +typedef struct _secCrtcPriv +{ + SECModePtr pSecMode; + drmModeModeInfo kmode; + drmModeCrtcPtr mode_crtc; + int pipe; + + int idx; + tbm_bo front_bo; + tbm_bo back_bo; + + /* for pageflip */ + unsigned int fe_frame; + unsigned int fe_tv_sec; + unsigned int fe_tv_usec; + DRI2FrameEventPtr flip_info; /* pending flips : flipping must garauntee to do it sequentially */ + struct xorg_list pending_flips; + Bool is_flipping; /* check flipping */ + Bool is_fb_blit_flipping; + int flip_count; /* check flipping completed (check pairs of request_flip and complete_flip */ + struct { + int num; /* number of flip back pixmaps */ + int lub; /* Last used backbuffer */ + Bool *pix_free; /* flags for a flip pixmap to be free */ + DrawablePtr *flip_draws; + PixmapPtr *flip_pixmaps; /* back flip pixmaps in a crtc */ + } flip_backpixs; + +#if 1 + /* for fps debug */ + FpsDebugPtr pFpsDebug; +#endif + + /* overlay(cursor) */ + Bool need_off; + Bool ref_overlay; + Bool move_layer; + Bool cursor_show; + Bool need_draw_cursor; + SECLayer *ovl_layer; + SECVideoBuf *ovl_vbuf_cursor; + SECVideoBuf *ovl_vbuf_pixmap; + Bool need_cursor_update; + Bool registered_block_handler; + int user_rotate; + int cursor_old_offset; + int cursor_pos_x; + int cursor_pos_y; + int cursor_win_x; + int cursor_win_y; + BoxRec saved_box; + pixman_image_t *ovl_canvas; + pixman_image_t *saved_image; + pixman_image_t *cursor_image; + pixman_image_t *backup_image; + + tbm_bo rotate_bo; + uint32_t rotate_pitch; + uint32_t rotate_fb_id; + + /* crtc rotate by display conf */ + Rotation rotate; + + /* Accessibility */ + tbm_bo accessibility_front_bo; + tbm_bo accessibility_back_bo; + Bool bAccessibility; + ACCESSIBILITY_STATUS accessibility_status; + Bool bScale; + int sx, sy, sw, sh; + + /* screen rotate */ + int screen_rotate_degree; + int screen_rotate_prop_id; + int screen_rotate_ipp_status; + + Bool onoff; + Bool onoff_always; + + xf86CrtcPtr pCrtc; + struct xorg_list link; +} SECCrtcPrivRec, *SECCrtcPrivPtr; + +void secCrtcInit (ScrnInfoPtr pScrn, SECModePtr pSecMode, int num); +Bool secCrtcOn (xf86CrtcPtr pCrtc); +Bool secCrtcApply (xf86CrtcPtr pCrtc); + +Bool secCrtcOverlayNeedOff (xf86CrtcPtr pCrtc, Bool need_off); +Bool secCrtcOverlayRef (xf86CrtcPtr pCrtc, Bool refer); +Bool secCrtcCursorEnable (ScrnInfoPtr pScrn, Bool enable); +Bool secCrtcCursorRotate (xf86CrtcPtr pCrtc, int rotate); + +Bool secCrtcScreenRotate (xf86CrtcPtr pCrtc, int degree); +Bool secCrtcEnableScreenRotate (xf86CrtcPtr pCrtc, Bool enable); + +xf86CrtcPtr secCrtcGetAtGeometry (ScrnInfoPtr pScrn, int x, int y, int width, int height); +int secCrtcGetConnectType (xf86CrtcPtr pCrtc); + +Bool secCrtcIsFlipping (xf86CrtcPtr pCrtc); +void secCrtcAddPendingFlip (xf86CrtcPtr pCrtc, DRI2FrameEventPtr pEvent); +void secCrtcRemovePendingFlip (xf86CrtcPtr pCrtc, DRI2FrameEventPtr pEvent); +DRI2FrameEventPtr secCrtcGetPendingFlip (xf86CrtcPtr pCrtc, DRI2FrameEventPtr pEvent); +DRI2FrameEventPtr secCrtcGetFirstPendingFlip (xf86CrtcPtr pCrtc); + +Bool secCrtcEnableAccessibility (xf86CrtcPtr pCrtc); +Bool secCrtcExecAccessibility (xf86CrtcPtr pCrtc, tbm_bo src_bo, tbm_bo dst_bo); + +Bool secCrtcTurn (xf86CrtcPtr pCrtc, Bool onoff, Bool always, Bool user); +Bool secCrtcCheckOn (xf86CrtcPtr pCrtc); + +Bool secCrtcFullFreeFlipPixmap (ScrnInfoPtr pScrn, int crtc_pipe); +PixmapPtr secCrtcGetFreeFlipPixmap (ScrnInfoPtr pScrn, int crtc_pipe, DrawablePtr pDraw, unsigned int usage_hint); +void secCrtcRelFlipPixmap (ScrnInfoPtr pScrn, int crtc_pipe, PixmapPtr pPixmap); +void secCrtcRelAllFlipPixmap (ScrnInfoPtr pScrn, int crtc_pipe); +void secCrtcRemoveFlipPixmap (xf86CrtcPtr pCrtc); + +void secCrtcCountFps(xf86CrtcPtr pCrtc); + +static inline int +secCrtcID(SECCrtcPrivPtr pCrtcPriv) +{ + return pCrtcPriv->mode_crtc->crtc_id; +} + + +#endif /* __SEC_CRTC_H__ */ + diff --git a/src/crtcconfig/sec_display.c b/src/crtcconfig/sec_display.c new file mode 100755 index 0000000..051903e --- /dev/null +++ b/src/crtcconfig/sec_display.c @@ -0,0 +1,1681 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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, sublicense, + * 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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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. + * + * Authors: + * Dave Airlie <airlied@redhat.com> + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <poll.h> +#include <dirent.h> + +#include <X11/extensions/dpmsconst.h> +#include <xorgVersion.h> +#include <X11/Xatom.h> +#include <xf86Crtc.h> +#include <xf86DDC.h> +#include <xf86cmap.h> +#include <sec.h> + +#include "sec_crtc.h" +#include "sec_output.h" +#include "sec_plane.h" +#include "sec_display.h" +#include "sec_video_fourcc.h" +#include "sec_wb.h" +#include "sec_converter.h" +#include "sec_util.h" +#include "sec_xberc.h" + +#include <exynos_drm.h> + +static Bool SECCrtcConfigResize(ScrnInfoPtr pScrn, int width, int height); +static void SECModeVblankHandler(int fd, unsigned int frame, unsigned int tv_sec, + unsigned int tv_usec, void *event); +static void SECModePageFlipHandler(int fd, unsigned int frame, unsigned int tv_sec, + unsigned int tv_usec, void *event_data); +static void SECModeG2dHandler(int fd, unsigned int cmdlist_no, unsigned int tv_sec, + unsigned int tv_usec, void *event_data); +static void SECModeIppHandler(int fd, unsigned int prop_id, unsigned int *buf_idx, unsigned int tv_sec, + unsigned int tv_usec, void *event_data); + +static const xf86CrtcConfigFuncsRec sec_xf86crtc_config_funcs = +{ + SECCrtcConfigResize +}; + +static void +_secDisplaySetDrmEventCtx(SECModePtr pSecMode) +{ + pSecMode->event_context.vblank_handler = SECModeVblankHandler; + pSecMode->event_context.page_flip_handler = SECModePageFlipHandler; + pSecMode->event_context.g2d_handler = SECModeG2dHandler; + pSecMode->event_context.ipp_handler = SECModeIppHandler; +} + +static int +_secSetMainMode (ScrnInfoPtr pScrn, SECModePtr pSecMode) +{ + xf86CrtcConfigPtr pXf86CrtcConfig; + pXf86CrtcConfig = XF86_CRTC_CONFIG_PTR (pScrn); + int i; + + for (i = 0; i < pXf86CrtcConfig->num_output; i++) + { + xf86OutputPtr pOutput = pXf86CrtcConfig->output[i]; + SECOutputPrivPtr pOutputPriv = pOutput->driver_private; + if (pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_LVDS || + pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_Unknown) + { + memcpy (&pSecMode->main_lcd_mode, pOutputPriv->mode_output->modes, sizeof(drmModeModeInfo)); + return 1; + } + } + + return -1; +} + +static void +_secDisplayRemoveFlipPixmaps (ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr pCrtcConfig = XF86_CRTC_CONFIG_PTR (pScrn); + int c; + + for (c = 0; c < pCrtcConfig->num_crtc; c++) + { + xf86CrtcPtr pCrtc = pCrtcConfig->crtc[c]; + int conn_type = secCrtcGetConnectType (pCrtc); + if (conn_type == DRM_MODE_CONNECTOR_Unknown) + secCrtcRemoveFlipPixmap (pCrtc); + } +} + +static void +_saveFrameBuffer (ScrnInfoPtr pScrn, tbm_bo bo, int w, int h) +{ + SECPtr pSec = SECPTR(pScrn); + char file[128]; + SECFbBoDataPtr bo_data; + + if (!pSec->dump_info) + return; + + tbm_bo_get_user_data (bo, TBM_BO_DATA_FB, (void * *)&bo_data); + XDBG_RETURN_IF_FAIL(bo_data != NULL); + + snprintf (file, sizeof(file), "%03d_fb_%d.bmp", pSec->flip_cnt, bo_data->fb_id); + secUtilDoDumpBmps (pSec->dump_info, bo, w, h, NULL, file); + pSec->flip_cnt++; +} + +static int +secHandleEvent (int fd, secDrmEventContextPtr evctx) +{ +#define MAX_BUF_SIZE 1024 + + char buffer[MAX_BUF_SIZE]; + unsigned int len, i; + struct drm_event *e; + + /* The DRM read semantics guarantees that we always get only + * complete events. */ + len = read (fd, buffer, sizeof buffer); + if (len == 0) + { + XDBG_WARNING (MDISP, "warning: the size of the drm_event is 0.\n"); + return 0; + } + if (len < sizeof *e) + { + XDBG_WARNING (MDISP, "warning: the size of the drm_event is less than drm_event structure.\n"); + return -1; + } + if (len > MAX_BUF_SIZE - sizeof (struct drm_exynos_ipp_event)) + { + XDBG_WARNING (MDISP, "warning: the size of the drm_event can be over the maximum size.\n"); + return -1; + } + + i = 0; + while (i < len) + { + e = (struct drm_event *) &buffer[i]; + switch (e->type) + { + case DRM_EVENT_VBLANK: + { + struct drm_event_vblank *vblank; + + if (evctx->vblank_handler == NULL) + break; + + vblank = (struct drm_event_vblank *) e; + evctx->vblank_handler (fd, + vblank->sequence, + vblank->tv_sec, + vblank->tv_usec, + (void *)((unsigned long)vblank->user_data)); + } + break; + case DRM_EVENT_FLIP_COMPLETE: + { + struct drm_event_vblank *vblank; + + if (evctx->page_flip_handler == NULL) + break; + + vblank = (struct drm_event_vblank *) e; + evctx->page_flip_handler (fd, + vblank->sequence, + vblank->tv_sec, + vblank->tv_usec, + (void *)((unsigned long)vblank->user_data)); + } + break; + case DRM_EXYNOS_G2D_EVENT: + { + struct drm_exynos_g2d_event *g2d; + + if (evctx->g2d_handler == NULL) + break; + + g2d = (struct drm_exynos_g2d_event *) e; + evctx->g2d_handler (fd, + g2d->cmdlist_no, + g2d->tv_sec, + g2d->tv_usec, + (void *)((unsigned long)g2d->user_data)); + } + break; + case DRM_EXYNOS_IPP_EVENT: + { + struct drm_exynos_ipp_event *ipp; + + if (evctx->ipp_handler == NULL) + break; + + ipp = (struct drm_exynos_ipp_event *) e; + evctx->ipp_handler (fd, + ipp->prop_id, + ipp->buf_id, + ipp->tv_sec, + ipp->tv_usec, + (void *)((unsigned long)ipp->user_data)); + } + break; + default: + break; + } + i += e->length; + } + + return 0; +} + +static Bool +SECCrtcConfigResize(ScrnInfoPtr pScrn, int width, int height) +{ + ScreenPtr pScreen = pScrn->pScreen; + SECPtr pSec = SECPTR (pScrn); + + XDBG_DEBUG(MDISP, "Resize cur(%dx%d) new(%d,%d)\n", + pScrn->virtualX, + pScrn->virtualY, + width, height); + + if (pScrn->virtualX == width && + pScrn->virtualY == height) + { + return TRUE; + } + + secFbResize(pSec->pFb, width, height); + + /* set the new size of pScrn */ + pScrn->virtualX = width; + pScrn->virtualY = height; + secExaScreenSetScrnPixmap (pScreen); + + secOutputDrmUpdate (pScrn); + + _secDisplayRemoveFlipPixmaps (pScrn); + + return TRUE; +} + +static void +SECModeVblankHandler(int fd, unsigned int frame, unsigned int tv_sec, + unsigned int tv_usec, void *event) +{ + SECVBlankInfoPtr pVblankInfo = event; + SECVBlankInfoType vblank_type; + void *data; + + XDBG_RETURN_IF_FAIL (pVblankInfo != NULL); + + vblank_type = pVblankInfo->type; + data = pVblankInfo->data; + +#if DBG_DRM_EVENT + xDbgLogDrmEventRemoveVblank (pVblankInfo->xdbg_log_vblank); +#endif + + if (vblank_type == VBLANK_INFO_SWAP) + { + XDBG_TRACE (MDISP, "vblank handler (%p, %ld, %ld)\n", + pVblankInfo, pVblankInfo->time, GetTimeInMillis () - pVblankInfo->time); + secDri2FrameEventHandler (frame, tv_sec, tv_usec, data); + } + else if (vblank_type == VBLANK_INFO_PLANE) + secLayerVBlankEventHandler (frame, tv_sec, tv_usec, data); + else + XDBG_ERROR (MDISP, "unknown the vblank type\n"); + + free (pVblankInfo); + pVblankInfo = NULL; +} + +static void +SECModePageFlipHandler(int fd, unsigned int frame, unsigned int tv_sec, + unsigned int tv_usec, void *event_data) +{ + SECPageFlipPtr flip = event_data; + xf86CrtcPtr pCrtc; + SECCrtcPrivPtr pCrtcPriv; + + if (!flip) + { + XDBG_ERROR (MDISP, "flip is null\n"); + return; + } + + XDBG_TRACE (MDISP, "pageflip handler (%p, %ld, %ld)\n", + flip, flip->time, GetTimeInMillis () - flip->time); + + #if DBG_DRM_EVENT + if( flip->xdbg_log_pageflip != NULL ) + xDbgLogDrmEventRemovePageflip (flip->xdbg_log_pageflip); + #endif + + pCrtc = flip->pCrtc; + pCrtcPriv = pCrtc->driver_private; + pCrtcPriv->is_flipping = FALSE; + pCrtcPriv->is_fb_blit_flipping = FALSE; + pCrtcPriv->flip_count--; /* check flipping completed */ + + /* Is this the event whose info shall be delivered to higher level? */ + /* Yes: Cache msc, ust for later delivery. */ + pCrtcPriv->fe_frame = frame; + pCrtcPriv->fe_tv_sec = tv_sec; + pCrtcPriv->fe_tv_usec = tv_usec; + + if (pCrtcPriv->bAccessibility || pCrtcPriv->screen_rotate_degree > 0) + if (pCrtcPriv->accessibility_front_bo && pCrtcPriv->accessibility_back_bo) + { + tbm_bo temp; + temp = pCrtcPriv->accessibility_front_bo; + pCrtcPriv->accessibility_front_bo = pCrtcPriv->accessibility_back_bo; + pCrtcPriv->accessibility_back_bo = temp; + } + + /* accessibility */ + if (flip->accessibility_back_bo) + { + secRenderBoUnref(flip->accessibility_back_bo); + flip->accessibility_back_bo = NULL; + } + + /* if accessibility is diabled, remove the accessibility_bo + when the pageflip is occurred once after the accessibility is disabled */ + if (!pCrtcPriv->bAccessibility && pCrtcPriv->screen_rotate_degree == 0) + { + if (pCrtcPriv->accessibility_front_bo) + { + secRenderBoUnref (pCrtcPriv->accessibility_front_bo); + pCrtcPriv->accessibility_front_bo = NULL; + } + if (pCrtcPriv->accessibility_back_bo) + { + secRenderBoUnref (pCrtcPriv->accessibility_back_bo); + pCrtcPriv->accessibility_back_bo = NULL; + } + } + + /* Release back framebuffer */ + if (flip->back_bo) + { + secRenderBoUnref(flip->back_bo); + flip->back_bo = NULL; + } + + if (pCrtcPriv->flip_info == NULL) + { + /** + * If pCrtcPriv->flip_info is failed and secCrtcGetFirstPendingFlip (pCrtc) has data, + * ModePageFlipHandler is triggered by secDisplayUpdateRequest(). - Maybe FB_BLIT or FB is updated by CPU. + * In this case we should call _secDri2ProcessPending(). + */ + DRI2FrameEventPtr pending_flip; + pending_flip = secCrtcGetFirstPendingFlip (pCrtc); + if( pending_flip != NULL ) + { + XDBG_DEBUG (MDISP, "FB_BLIT or FB is updated by CPU. But there's secCrtcGetFirstPendingFlip(). So trigger it manually\n"); + flip->dispatch_me = TRUE; + pCrtcPriv->flip_info = pending_flip; + } + else + goto fail; + } + + XDBG_DEBUG(MDISP, "ModePageFlipHandler ctrc_id:%d dispatch_me:%d, frame:%d, flip_count=%d is_pending=%p\n", + secCrtcID(pCrtcPriv), flip->dispatch_me, frame, pCrtcPriv->flip_count, secCrtcGetFirstPendingFlip (pCrtc)); + + /* Last crtc completed flip? */ + if (flip->dispatch_me) + { + secCrtcCountFps(pCrtc); + + /* Deliver cached msc, ust from reference crtc to flip event handler */ + secDri2FlipEventHandler (pCrtcPriv->fe_frame, pCrtcPriv->fe_tv_sec, + pCrtcPriv->fe_tv_usec, pCrtcPriv->flip_info, flip->flip_failed); + } + + free (flip); + return; +fail: + if (flip->accessibility_back_bo) + { + secRenderBoUnref(flip->accessibility_back_bo); + flip->accessibility_back_bo = NULL; + } + + if (flip->back_bo) + { + secRenderBoUnref(flip->back_bo); + flip->back_bo = NULL; + } + + free (flip); +} + +static void +SECModeG2dHandler(int fd, unsigned int cmdlist_no, unsigned int tv_sec, + unsigned int tv_usec, void *event_data) +{ +} + +static void +SECModeIppHandler(int fd, unsigned int prop_id, unsigned int *buf_idx, + unsigned int tv_sec, unsigned int tv_usec, void *event_data) +{ + XDBG_DEBUG (MDRM, "wb_prop_id(%d) prop_id(%d), buf_idx(%d, %d) \n", + secWbGetPropID(), prop_id, buf_idx[0], buf_idx[1]); + + if (secWbGetPropID () == prop_id) + secWbHandleIppEvent (fd, buf_idx, event_data); + else + secCvtHandleIppEvent (fd, buf_idx, event_data, FALSE); +} + +static void +SECModeWakeupHanlder(pointer data, int err, pointer p) +{ + SECModePtr pSecMode; + fd_set *read_mask; + + if (data == NULL || err < 0) + return; + + pSecMode = data; + read_mask = p; + if (FD_ISSET (pSecMode->fd, read_mask)) + secHandleEvent (pSecMode->fd, &pSecMode->event_context); +} + +Bool +secModePreInit (ScrnInfoPtr pScrn, int drm_fd) +{ + SECPtr pSec = SECPTR (pScrn); + SECModePtr pSecMode; + unsigned int i; + int cpp; + +// secLogSetLevel(MDISP, 0); + + pSecMode = calloc (1, sizeof *pSecMode); + if (!pSecMode) + return FALSE; + + pSecMode->fd = drm_fd; + xorg_list_init (&pSecMode->crtcs); + xorg_list_init (&pSecMode->outputs); + xorg_list_init (&pSecMode->planes); + + xf86CrtcConfigInit (pScrn, &sec_xf86crtc_config_funcs); + + cpp = pScrn->bitsPerPixel /8; + + pSecMode->cpp = cpp; + pSecMode->mode_res = drmModeGetResources (pSecMode->fd); + if (!pSecMode->mode_res) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, + "failed to get resources: %s\n", strerror (errno)); + free (pSecMode); + return FALSE; + } + + pSecMode->plane_res = drmModeGetPlaneResources (pSecMode->fd); + if (!pSecMode->plane_res) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, + "failed to get plane resources: %s\n", strerror (errno)); + drmModeFreeResources (pSecMode->mode_res); + free (pSecMode); + return FALSE; + } + + xf86CrtcSetSizeRange (pScrn, 320, 200, pSecMode->mode_res->max_width, + pSecMode->mode_res->max_height); + + for (i = 0; i < pSecMode->mode_res->count_crtcs; i++) + secCrtcInit (pScrn, pSecMode, i); + + for (i = 0; i < pSecMode->mode_res->count_connectors; i++) + secOutputInit (pScrn, pSecMode, i); + + for (i = 0; i < pSecMode->plane_res->count_planes; i++) + secPlaneInit (pScrn, pSecMode, i); + + _secSetMainMode (pScrn, pSecMode); + + xf86InitialConfiguration (pScrn, TRUE); + + /* soolim:: + * we assume that kernel always support the pageflipping + * and the drm vblank + */ + /* set the drm event context */ + _secDisplaySetDrmEventCtx(pSecMode); + + pSec->pSecMode = pSecMode; + + /* virtaul x and virtual y of the screen is ones from main lcd mode */ + pScrn->virtualX = pSecMode->main_lcd_mode.hdisplay; + pScrn->virtualY = pSecMode->main_lcd_mode.vdisplay; + +#if DBG_DRM_EVENT + xDbgLogDrmEventInit(); +#endif + + return TRUE; +} + +void +secModeInit (ScrnInfoPtr pScrn) +{ + SECPtr pSec = SECPTR (pScrn); + SECModePtr pSecMode = pSec->pSecMode; + + /* We need to re-register the mode->fd for the synchronisation + * feedback on every server generation, so perform the + * registration within ScreenInit and not PreInit. + */ + //pSecMode->flip_count = 0; + AddGeneralSocket(pSecMode->fd); + RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, + SECModeWakeupHanlder, pSecMode); + +} + +void +secModeDeinit (ScrnInfoPtr pScrn) +{ + SECPtr pSec = SECPTR (pScrn); + SECModePtr pSecMode = (SECModePtr) pSec->pSecMode; + xf86CrtcPtr pCrtc = NULL; + xf86OutputPtr pOutput = NULL; + + secDisplayDeinitDispMode (pScrn); + + SECCrtcPrivPtr crtc_ref = NULL, crtc_next = NULL; + xorg_list_for_each_entry_safe (crtc_ref, crtc_next, &pSecMode->crtcs, link) + { + pCrtc = crtc_ref->pCrtc; + xf86CrtcDestroy (pCrtc); + } + + SECOutputPrivPtr output_ref = NULL, output_next = NULL; + xorg_list_for_each_entry_safe (output_ref, output_next, &pSecMode->outputs, link) + { + pOutput = output_ref->pOutput; + xf86OutputDestroy (pOutput); + } + + SECPlanePrivPtr plane_ref = NULL, plane_next = NULL; + xorg_list_for_each_entry_safe (plane_ref, plane_next, &pSecMode->planes, link) + { + secPlaneDeinit (pScrn, plane_ref); + } + + if (pSecMode->mode_res) + drmModeFreeResources (pSecMode->mode_res); + + if (pSecMode->plane_res) + drmModeFreePlaneResources (pSecMode->plane_res); + + /* mode->rotate_fb_id should have been destroyed already */ + + free (pSecMode); + pSec->pSecMode = NULL; +} + +/* + * Return the crtc covering 'box'. If two crtcs cover a portion of + * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc + * with greater coverage + */ +xf86CrtcPtr +secModeCoveringCrtc (ScrnInfoPtr pScrn, BoxPtr pBox, xf86CrtcPtr pDesiredCrtc, BoxPtr pBoxCrtc) +{ + xf86CrtcConfigPtr pCrtcConfig = XF86_CRTC_CONFIG_PTR (pScrn); + xf86CrtcPtr pCrtc, pBestCrtc; + int coverage, best_coverage; + int c; + BoxRec crtc_box, cover_box; + + XDBG_RETURN_VAL_IF_FAIL (pBox != NULL, NULL); + + pBestCrtc = NULL; + best_coverage = 0; + + if (pBoxCrtc) + { + pBoxCrtc->x1 = 0; + pBoxCrtc->y1 = 0; + pBoxCrtc->x2 = 0; + pBoxCrtc->y2 = 0; + } + + for (c = 0; c < pCrtcConfig->num_crtc; c++) + { + pCrtc = pCrtcConfig->crtc[c]; + + /* If the CRTC is off, treat it as not covering */ + if(!secCrtcOn(pCrtc)) + continue; + + crtc_box.x1 = pCrtc->x; + crtc_box.x2 = pCrtc->x + xf86ModeWidth (&pCrtc->mode, pCrtc->rotation); + crtc_box.y1 = pCrtc->y; + crtc_box.y2 = pCrtc->y + xf86ModeHeight (&pCrtc->mode, pCrtc->rotation); + + secUtilBoxIntersect(&cover_box, &crtc_box, pBox); + coverage = secUtilBoxArea(&cover_box); + + if (coverage && pCrtc == pDesiredCrtc) + { + if (pBoxCrtc) + *pBoxCrtc = crtc_box; + return pCrtc; + } + + if (coverage > best_coverage) + { + if (pBoxCrtc) + *pBoxCrtc = crtc_box; + pBestCrtc = pCrtc; + best_coverage = coverage; + } + } + + return pBestCrtc; +} + +int secModeGetCrtcPipe (xf86CrtcPtr pCrtc) +{ + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + return pCrtcPriv->pipe; +} + +Bool +secModePageFlip (ScrnInfoPtr pScrn, xf86CrtcPtr pCrtc, void* flip_info, int pipe, tbm_bo back_bo) +{ + SECPageFlipPtr pPageFlip = NULL; + SECFbBoDataPtr bo_data; + SECCrtcPrivPtr pCrtcPriv; + SECModePtr pSecMode; + xf86CrtcConfigPtr pCrtcConfig = XF86_CRTC_CONFIG_PTR (pScrn); + xf86CrtcPtr pCurCrtc; + SECPtr pSec = SECPTR(pScrn); + int ret; + int fb_id = 0; + DRI2FrameEventPtr pEvent = (DRI2FrameEventPtr) flip_info; + + BoxRec b1; + int retBox, found=0; + int i; + + tbm_bo_get_user_data (back_bo, TBM_BO_DATA_FB, (void * *)&bo_data); + XDBG_RETURN_VAL_IF_FAIL(bo_data != NULL, FALSE); + + for (i = 0; i < pCrtcConfig->num_crtc; i++) + { + pCurCrtc = pCrtcConfig->crtc[i]; + if (!pCurCrtc->enabled) + continue; + pCrtcPriv = pCurCrtc->driver_private; + pSecMode = pCrtcPriv->pSecMode; + + b1.x1 = pCurCrtc->x; + b1.y1 = pCurCrtc->y; + b1.x2 = pCurCrtc->x + pCurCrtc->mode.HDisplay; + b1.y2 = pCurCrtc->y + pCurCrtc->mode.VDisplay; + + retBox = secUtilBoxInBox(&bo_data->pos, &b1); + if(retBox == rgnSAME || retBox == rgnIN) + { + pPageFlip = calloc (1, sizeof (SECPageFlipRec)); + if (pPageFlip == NULL) + { + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "Page flip alloc failed\n"); + return FALSE; + } + + /* Only the reference crtc will finally deliver its page flip + * completion event. All other crtc's events will be discarded. + */ + pPageFlip->dispatch_me = 0; + pPageFlip->pCrtc = pCurCrtc; + pPageFlip->clone = TRUE; + pPageFlip->back_bo = secRenderBoRef (back_bo); + pPageFlip->data = flip_info; + pPageFlip->flip_failed = FALSE; + + /* accessilitity */ + if (pCrtcPriv->bAccessibility || pCrtcPriv->screen_rotate_degree > 0) + { + tbm_bo accessibility_bo = pCrtcPriv->accessibility_back_bo; + SECFbBoDataPtr accessibility_bo_data; + + tbm_bo_get_user_data (accessibility_bo, TBM_BO_DATA_FB, (void * *)&accessibility_bo_data); + XDBG_GOTO_IF_FAIL (accessibility_bo_data != NULL, fail); + + fb_id = accessibility_bo_data->fb_id; + + /*Buffer is already changed by bo_swap*/ + if (!secCrtcExecAccessibility (pCurCrtc, back_bo, accessibility_bo)) + goto fail; + + pPageFlip->accessibility_back_bo = secRenderBoRef(accessibility_bo); + } + else + { + fb_id = bo_data->fb_id; + + tbm_bo_map(pPageFlip->back_bo, TBM_DEVICE_2D, TBM_OPTION_READ); + tbm_bo_unmap(pPageFlip->back_bo); + } + + pCrtcPriv->is_flipping = TRUE; + + if (!pCrtcPriv->onoff && !pCrtcPriv->onoff_always) + secCrtcTurn (pCrtcPriv->pCrtc, TRUE, FALSE, FALSE); + +#if DBG_DRM_EVENT + pPageFlip->xdbg_log_pageflip = xDbgLogDrmEventAddPageflip (pipe, pEvent->client_idx, pEvent->drawable_id); +#endif + + XDBG_DEBUG (MSEC, "dump_mode(%x)\n", pSec->dump_mode); + + if (pSec->dump_mode & XBERC_DUMP_MODE_FB) + _saveFrameBuffer (pScrn, back_bo, + bo_data->pos.x2 - bo_data->pos.x1, + bo_data->pos.y2 - bo_data->pos.y1); + + pPageFlip->time = GetTimeInMillis (); + + /*Set DirtyFB*/ + if(pSec->use_partial_update && pEvent->pRegion) + { + int nBox; + BoxPtr pBox; + RegionRec new_region; + RegionPtr pRegion = pEvent->pRegion; + + for (nBox = RegionNumRects(pRegion), + pBox = RegionRects(pRegion); nBox--; pBox++) + { + XDBG_DEBUG (MDISP, "dirtfb region(%d): (%d,%d %dx%d)\n", nBox, + pBox->x1, pBox->y1, pBox->x2-pBox->x1, pBox->y2-pBox->y1); + } + + if (pCrtcPriv->screen_rotate_degree > 0) + { + RegionCopy (&new_region, pEvent->pRegion); + secUtilRotateRegion (pCrtc->mode.HDisplay, pCrtc->mode.VDisplay, + &new_region, pCrtcPriv->screen_rotate_degree); + pRegion = &new_region; + + for (nBox = RegionNumRects(pRegion), + pBox = RegionRects(pRegion); nBox--; pBox++) + { + XDBG_DEBUG (MDISP, "(R)dirtfb region(%d): (%d,%d %dx%d)\n", nBox, + pBox->x1, pBox->y1, pBox->x2-pBox->x1, pBox->y2-pBox->y1); + } + } + + drmModeDirtyFB (pSec->drm_fd, fb_id, + (drmModeClipPtr)RegionRects (pRegion), + (uint32_t)RegionNumRects (pRegion)); + } + + + /* DRM Page Flip */ + ret = drmModePageFlip (pSec->drm_fd, secCrtcID(pCrtcPriv), fb_id, + DRM_MODE_PAGE_FLIP_EVENT, pPageFlip); + if (ret) + { + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", strerror (errno)); + goto fail; + } + + XDBG_TRACE (MDISP, "pageflip do (%p, %ld)\n", pPageFlip, pPageFlip->time); + + pCrtcPriv->flip_count++; /* check flipping completed */ + pCrtcPriv->flip_info = (DRI2FrameEventPtr)flip_info; + + found++; + XDBG_DEBUG(MDISP, "ModePageFlip crtc_id:%d, fb_id:%d, back_fb_id:%d, back_name:%d, accessibility:%d\n", + secCrtcID(pCrtcPriv), fb_id, bo_data->fb_id, + tbm_bo_export (back_bo), pCrtcPriv->bAccessibility); + } + } + + if(found==0) + { + XDBG_WARNING(MDISP, "Cannot find CRTC in (%d,%d)-(%d,%d)\n", + bo_data->pos.x1, bo_data->pos.y1, bo_data->pos.x2, bo_data->pos.y2); + return FALSE; + } + + /* Set dispatch_me to last pageflip */ + pPageFlip->dispatch_me = 1; + + return TRUE; + +fail: + pCrtcPriv->flip_count++; /* check flipping completed */ + pCrtcPriv->flip_info = (DRI2FrameEventPtr)flip_info; + pPageFlip->dispatch_me = 1; + pPageFlip->flip_failed = TRUE; + + SECModePageFlipHandler(pSecMode->fd, 0, 0, 0, pPageFlip); + + XDBG_ERROR(MDISP, "drmModePageFlip error(crtc:%d, fb_id:%d, back_fb_id:%d, back_name:%d, accessibility:%d)\n", + secCrtcID(pCrtcPriv), fb_id, bo_data->fb_id, tbm_bo_export (back_bo), pCrtcPriv->bAccessibility); + + return FALSE; +} + +/* load palette per a crtc */ +void +secModeLoadPalette (ScrnInfoPtr pScrn, int numColors, int* indices, + LOCO* colors, VisualPtr pVisual) +{ + xf86CrtcConfigPtr pCrtcConfig = XF86_CRTC_CONFIG_PTR (pScrn); + int i, j, index; + int p; + uint16_t lut_r[256], lut_g[256], lut_b[256]; + + for (p = 0; p < pCrtcConfig->num_crtc; p++) + { + xf86CrtcPtr pCrtc = pCrtcConfig->crtc[p]; + + switch (pScrn->depth) + { + case 16: + for (i = 0; i < numColors; i++) + { + index = indices[i]; + if (index <= 31) + { + for (j = 0; j < 8; j++) + { + lut_r[index * 8 + j] = colors[index].red << 8; + lut_b[index * 8 + j] = colors[index].blue << 8; + } + } + for (j = 0; j < 4; j++) + { + lut_g[index * 4 + j] = colors[index].green << 8; + } + } + break; + default: + for (i = 0; i < numColors; i++) + { + index = indices[i]; + lut_r[index] = colors[index].red << 8; + lut_g[index] = colors[index].green << 8; + lut_b[index] = colors[index].blue << 8; + + } + break; + } + + /* make the change through RandR */ + RRCrtcGammaSet (pCrtc->randr_crtc, lut_r, lut_g, lut_b); + } +} + +void +secDisplaySwapModeFromKmode(ScrnInfoPtr pScrn, + drmModeModeInfoPtr kmode, + DisplayModePtr pMode) +{ + char fake_name[32] = "fake_mode"; + + memset (pMode, 0, sizeof (DisplayModeRec)); + pMode->status = MODE_OK; + + pMode->Clock = kmode->clock; + + pMode->HDisplay = kmode->vdisplay; + pMode->HSyncStart = kmode->vsync_start; + pMode->HSyncEnd = kmode->vsync_end; + pMode->HTotal = kmode->vtotal; + pMode->HSkew = kmode->vscan; + + pMode->VDisplay = kmode->hdisplay; + pMode->VSyncStart = kmode->hsync_start; + pMode->VSyncEnd = kmode->hsync_end; + pMode->VTotal = kmode->htotal; + pMode->VScan = kmode->hskew; + + pMode->Flags = kmode->flags; //& FLAG_BITS; + pMode->name = strdup (fake_name); + + if (kmode->type & DRM_MODE_TYPE_DRIVER) + pMode->type = M_T_DRIVER; + if (kmode->type & DRM_MODE_TYPE_PREFERRED) + pMode->type |= M_T_PREFERRED; + + xf86SetModeCrtc (pMode, pScrn->adjustFlags); +} + + + + +void +secDisplayModeFromKmode(ScrnInfoPtr pScrn, + drmModeModeInfoPtr kmode, + DisplayModePtr pMode) +{ + memset (pMode, 0, sizeof (DisplayModeRec)); + pMode->status = MODE_OK; + + pMode->Clock = kmode->clock; + + pMode->HDisplay = kmode->hdisplay; + pMode->HSyncStart = kmode->hsync_start; + pMode->HSyncEnd = kmode->hsync_end; + pMode->HTotal = kmode->htotal; + pMode->HSkew = kmode->hskew; + + pMode->VDisplay = kmode->vdisplay; + pMode->VSyncStart = kmode->vsync_start; + pMode->VSyncEnd = kmode->vsync_end; + pMode->VTotal = kmode->vtotal; + pMode->VScan = kmode->vscan; + + pMode->Flags = kmode->flags; //& FLAG_BITS; + pMode->name = strdup (kmode->name); + pMode->VRefresh = kmode->vrefresh; + + if (kmode->type & DRM_MODE_TYPE_DRIVER) + pMode->type = M_T_DRIVER; + if (kmode->type & DRM_MODE_TYPE_PREFERRED) + pMode->type |= M_T_PREFERRED; + + xf86SetModeCrtc (pMode, pScrn->adjustFlags); +} + + +void +secDisplaySwapModeToKmode(ScrnInfoPtr pScrn, + drmModeModeInfoPtr kmode, + DisplayModePtr pMode) +{ + memset (kmode, 0, sizeof (*kmode)); + + kmode->clock = pMode->Clock; + kmode->hdisplay = pMode->VDisplay; + kmode->hsync_start = pMode->VSyncStart; + kmode->hsync_end = pMode->VSyncEnd; + kmode->htotal = pMode->VTotal; + kmode->hskew = pMode->VScan; + + kmode->vdisplay = pMode->HDisplay; + kmode->vsync_start = pMode->HSyncStart; + kmode->vsync_end = pMode->HSyncEnd; + kmode->vtotal = pMode->HTotal; + kmode->vscan = pMode->HSkew; + kmode->vrefresh = xf86ModeVRefresh (pMode); + + kmode->flags = pMode->Flags; //& FLAG_BITS; + if (pMode->name) + strncpy (kmode->name, pMode->name, DRM_DISPLAY_MODE_LEN); + kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; +} + + +void +secDisplayModeToKmode(ScrnInfoPtr pScrn, + drmModeModeInfoPtr kmode, + DisplayModePtr pMode) +{ + memset (kmode, 0, sizeof (*kmode)); + + kmode->clock = pMode->Clock; + kmode->hdisplay = pMode->HDisplay; + kmode->hsync_start = pMode->HSyncStart; + kmode->hsync_end = pMode->HSyncEnd; + kmode->htotal = pMode->HTotal; + kmode->hskew = pMode->HSkew; + + kmode->vdisplay = pMode->VDisplay; + kmode->vsync_start = pMode->VSyncStart; + kmode->vsync_end = pMode->VSyncEnd; + kmode->vtotal = pMode->VTotal; + kmode->vscan = pMode->VScan; + kmode->vrefresh = xf86ModeVRefresh (pMode); + + kmode->flags = pMode->Flags; //& FLAG_BITS; + if (pMode->name) + strncpy (kmode->name, pMode->name, DRM_DISPLAY_MODE_LEN); + + kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; +} + + +static uint32_t crtc_id; +static tbm_bo hdmi_bo; + +static Bool connect_crtc; + +static int +_secDisplayGetAvailableCrtcID (ScrnInfoPtr pScrn) +{ + SECModePtr pSecMode = (SECModePtr) SECPTR (pScrn)->pSecMode; + int i; + int crtc_id = 0; + + for (i = 0; i < pSecMode->mode_res->count_crtcs; i++) + { + drmModeCrtcPtr kcrtc = NULL; + kcrtc = drmModeGetCrtc (pSecMode->fd, pSecMode->mode_res->crtcs[i]); + if (!kcrtc) + { + XDBG_ERROR (MSEC, "fail to get kcrtc. \n"); + return 0; + } + + if (kcrtc->buffer_id > 0) + { + drmModeFreeCrtc (kcrtc); + continue; + } + + crtc_id = kcrtc->crtc_id; + drmModeFreeCrtc (kcrtc); + + return crtc_id; + } + + return 0; +} + +static void +_secDisplayWbCloseFunc (SECWb *wb, SECWbNotify noti, void *noti_data, void *user_data) +{ + ScrnInfoPtr pScrn = (ScrnInfoPtr)user_data; + SECPtr pSec; + + if (!pScrn) + return; + + pSec = SECPTR (pScrn); + + pSec->wb_clone = NULL; +} + +Bool +secDisplayInitDispMode (ScrnInfoPtr pScrn, SECDisplayConnMode conn_mode) +{ + SECModePtr pSecMode = (SECModePtr) SECPTR (pScrn)->pSecMode; + Bool ret = FALSE; + uint32_t *output_ids = NULL; + int output_cnt = 1; + uint32_t fb_id; + drmModeModeInfoPtr pKmode = NULL; + drmModeCrtcPtr kcrtc = NULL; + SECFbBoDataPtr bo_data = NULL; + SECOutputPrivPtr pOutputPriv=NULL, pNext=NULL; + int connector_type = -1; + int width, height; + + if (connect_crtc) + return TRUE; + + /* get output ids */ + output_ids = calloc (output_cnt, sizeof (uint32_t)); + XDBG_RETURN_VAL_IF_FAIL (output_ids != NULL, FALSE); + + xorg_list_for_each_entry_safe (pOutputPriv, pNext, &pSecMode->outputs, link) + { + if (conn_mode == DISPLAY_CONN_MODE_HDMI) + { + if (pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_HDMIA || + pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_HDMIB) + { + output_ids[0] = pOutputPriv->mode_output->connector_id; + pKmode = &pSecMode->ext_connector_mode; + connector_type = pOutputPriv->mode_output->connector_type; + break; + } + } + else if (conn_mode == DISPLAY_CONN_MODE_VIRTUAL) + { + if (pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_VIRTUAL) + { + output_ids[0] = pOutputPriv->mode_output->connector_id; + pKmode = &pSecMode->ext_connector_mode; + connector_type = pOutputPriv->mode_output->connector_type; + break; + } + + } + else + { + XDBG_NEVER_GET_HERE (MTVO); + goto fail_to_init; + } + } + XDBG_GOTO_IF_FAIL (output_ids[0] > 0, fail_to_init); + XDBG_GOTO_IF_FAIL (pKmode != NULL, fail_to_init); + + width = pKmode->hdisplay; + height = pKmode->vdisplay; + + pOutputPriv = secOutputGetPrivateForConnType (pScrn, connector_type); + if (pOutputPriv && pOutputPriv->mode_encoder) + XDBG_GOTO_IF_FAIL (pOutputPriv->mode_encoder->crtc_id == 0, fail_to_init); + + crtc_id = _secDisplayGetAvailableCrtcID (pScrn); + XDBG_GOTO_IF_FAIL (crtc_id > 0, fail_to_init); + + /* get crtc_id */ + kcrtc = drmModeGetCrtc (pSecMode->fd, crtc_id); + XDBG_GOTO_IF_FAIL (kcrtc != NULL, fail_to_init); + + if (kcrtc->buffer_id > 0) + { + XDBG_ERROR (MTVO, "crtc(%d) already has buffer(%d) \n", + crtc_id, kcrtc->buffer_id); + goto fail_to_init; + } + + /* get fb_id */ + hdmi_bo = secRenderBoCreate (pScrn, width, height); + XDBG_GOTO_IF_FAIL (hdmi_bo != NULL, fail_to_init); + + tbm_bo_get_user_data(hdmi_bo, TBM_BO_DATA_FB, (void * *)&bo_data); + XDBG_GOTO_IF_FAIL (bo_data != NULL, fail_to_init); + + fb_id = bo_data->fb_id; + + /* set crtc */ + if (drmModeSetCrtc (pSecMode->fd, crtc_id, fb_id, 0, 0, output_ids, output_cnt, pKmode)) + { + XDBG_ERRNO (MTVO, "drmModeSetCrtc failed. \n"); + goto fail_to_init; + } + else + { + ret = TRUE; + } + + secUtilSetDrmProperty (pSecMode, crtc_id, DRM_MODE_OBJECT_CRTC, "mode", 1); + + secOutputDrmUpdate (pScrn); + + XDBG_INFO (MDISP, "** ModeSet : (%dx%d) %dHz !!\n", pKmode->hdisplay, pKmode->vdisplay, pKmode->vrefresh); + + connect_crtc = TRUE; + +fail_to_init: + free (output_ids); + if (kcrtc) + drmModeFreeCrtc (kcrtc); + + return ret; +} + +void +secDisplayDeinitDispMode (ScrnInfoPtr pScrn) +{ + SECModePtr pSecMode = (SECModePtr) SECPTR (pScrn)->pSecMode; + + if (!connect_crtc) + return; + + XDBG_INFO (MDISP, "** ModeUnset. !!\n"); + + secUtilSetDrmProperty (pSecMode, crtc_id, DRM_MODE_OBJECT_CRTC, "mode", 0); + + if (hdmi_bo) + { + secRenderBoUnref (hdmi_bo); + hdmi_bo = NULL; + } + + secOutputDrmUpdate (pScrn); + + crtc_id = 0; + connect_crtc = FALSE; +} + +Bool +secDisplaySetDispSetMode (ScrnInfoPtr pScrn, SECDisplaySetMode set_mode) +{ + SECPtr pSec = SECPTR (pScrn); + SECModePtr pSecMode = pSec->pSecMode; + + if (pSecMode->set_mode == set_mode) + { + XDBG_INFO (MDISP, "set_mode(%d) is already set\n", set_mode); + return TRUE; + } + + if (pSecMode->conn_mode == DISPLAY_CONN_MODE_NONE) + { + XDBG_WARNING (MDISP, "set_mode(%d) is failed : output is not connected yet\n", set_mode); + return FALSE; + } + + switch (set_mode) + { + case DISPLAY_SET_MODE_OFF: + if (secWbIsOpened ()) + { + SECWb *wb = secWbGet (); + secWbClose (wb); + } + secDisplayDeinitDispMode (pScrn); + break; + case DISPLAY_SET_MODE_CLONE: + /* In case of DISPLAY_CONN_MODE_VIRTUAL, we will open writeback + * on GetStill. + */ + if (pSecMode->conn_mode != DISPLAY_CONN_MODE_VIRTUAL) + { + int wb_hz; + + if (pSec->wb_clone) + { + XDBG_ERROR (MWB, "Fail : wb_clone(%p) already exists.\n", pSec->wb_clone); + break; + } + + if (secWbIsOpened ()) + { + XDBG_ERROR (MWB, "Fail : wb(%p) already opened.\n", secWbGet ()); + break; + } + + wb_hz = (pSec->wb_hz > 0)? pSec->wb_hz : pSecMode->ext_connector_mode.vrefresh; + + XDBG_TRACE (MWB, "wb_hz(%d) vrefresh(%d)\n", pSec->wb_hz, pSecMode->ext_connector_mode.vrefresh); + + pSec->wb_clone = secWbOpen (pScrn, FOURCC_SN12, 0, 0, (pSec->scanout)?TRUE:FALSE, wb_hz, TRUE); + if (pSec->wb_clone) + { + secWbAddNotifyFunc (pSec->wb_clone, WB_NOTI_CLOSED, + _secDisplayWbCloseFunc, pScrn); + secWbSetRotate (pSec->wb_clone, pSecMode->rotate); + secWbSetTvout (pSec->wb_clone, TRUE); + if (!secWbStart (pSec->wb_clone)) + { + secWbClose (pSec->wb_clone); + return FALSE; + } + } + } + break; + case DISPLAY_SET_MODE_EXT: + if (secWbIsOpened ()) + { + SECWb *wb = secWbGet (); + secWbClose (wb); + } + secDisplayDeinitDispMode (pScrn); + break; + default: + break; + } + + pSecMode->set_mode = set_mode; + + return TRUE; +} + +SECDisplaySetMode +secDisplayGetDispSetMode (ScrnInfoPtr pScrn) +{ + SECDisplaySetMode set_mode; + SECPtr pSec = SECPTR (pScrn); + SECModePtr pSecMode = pSec->pSecMode; + + set_mode = pSecMode->set_mode; + + return set_mode; +} + +Bool +secDisplaySetDispRotate (ScrnInfoPtr pScrn, int rotate) +{ + SECPtr pSec = SECPTR (pScrn); + SECModePtr pSecMode = pSec->pSecMode; + + if (pSecMode->rotate == rotate) + return TRUE; + + pSecMode->rotate = rotate; + + if (pSec->wb_clone) + secWbSetRotate (pSec->wb_clone, rotate); + + return TRUE; +} + +int +secDisplayGetDispRotate (ScrnInfoPtr pScrn) +{ + int rotate; + SECPtr pSec = SECPTR (pScrn); + SECModePtr pSecMode = pSec->pSecMode; + + rotate = pSecMode->rotate; + + return rotate; +} + +Bool +secDisplaySetDispConnMode (ScrnInfoPtr pScrn, SECDisplayConnMode conn_mode) +{ + SECPtr pSec = SECPTR (pScrn); + SECModePtr pSecMode = pSec->pSecMode; + + if (pSecMode->conn_mode == conn_mode) + { + XDBG_DEBUG (MDISP, "conn_mode(%d) is already set\n", conn_mode); + return TRUE; + } + + switch (conn_mode) + { + case DISPLAY_CONN_MODE_NONE: + break; + case DISPLAY_CONN_MODE_HDMI: + break; + case DISPLAY_CONN_MODE_VIRTUAL: + break; + default: + break; + } + + pSecMode->conn_mode = conn_mode; + + return TRUE; +} + +SECDisplayConnMode +secDisplayGetDispConnMode (ScrnInfoPtr pScrn) +{ + SECDisplayConnMode conn_mode; + + SECPtr pSec = SECPTR (pScrn); + SECModePtr pSecMode = pSec->pSecMode; + + conn_mode = pSecMode->conn_mode; + + return conn_mode; +} + +Bool +secDisplayGetCurMSC (ScrnInfoPtr pScrn, int pipe, CARD64 *ust, CARD64 *msc) +{ + drmVBlank vbl; + int ret; + SECPtr pSec = SECPTR (pScrn); + SECModePtr pSecMode = pSec->pSecMode; + + /* if lcd is off, return true with msc = 0 */ + if (pSec->isLcdOff) + { + *ust = 0; + *msc = 0; + return TRUE; + } + + + /* if pipe is -1, return the current msc of the main crtc */ + if (pipe == -1) + pipe = 0; + + vbl.request.type = DRM_VBLANK_RELATIVE; + + if (pipe > 0) + { + if (pSecMode->conn_mode == DISPLAY_CONN_MODE_VIRTUAL) + vbl.request.type |= _DRM_VBLANK_EXYNOS_VIDI; + else + vbl.request.type |= DRM_VBLANK_SECONDARY; + } + + vbl.request.sequence = 0; + ret = drmWaitVBlank (pSec->drm_fd, &vbl); + if (ret) + { + *ust = 0; + *msc = 0; + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, + "first get vblank counter failed: %s\n", + strerror (errno)); + return FALSE; + } + + *ust = ((CARD64) vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec; + *msc = vbl.reply.sequence; + + return TRUE; +} + +Bool +secDisplayVBlank (ScrnInfoPtr pScrn, int pipe, CARD64 *target_msc, int flip, + SECVBlankInfoType type, void *vblank_info) +{ + drmVBlank vbl; + int ret; + SECPtr pSec = SECPTR (pScrn); + SECVBlankInfoPtr pVblankInfo = NULL; + SECModePtr pSecMode = pSec->pSecMode; + + pVblankInfo = calloc (1, sizeof (SECVBlankInfoRec)); + if (pVblankInfo == NULL) + { + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "vblank_info alloc failed\n"); + return FALSE; + } + + pVblankInfo->type = type; + pVblankInfo->data = vblank_info; + pVblankInfo->time = GetTimeInMillis (); + + vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; + + if (pipe > 0) + { + if (pSecMode->conn_mode == DISPLAY_CONN_MODE_VIRTUAL) + vbl.request.type |= _DRM_VBLANK_EXYNOS_VIDI; + else + vbl.request.type |= DRM_VBLANK_SECONDARY; + } + + /* If non-pageflipping, but blitting/exchanging, we need to use + * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later + * on. + */ + if (flip == 0) + { + if (pSecMode->conn_mode == DISPLAY_CONN_MODE_VIRTUAL && pipe > 0) + ; /* do not set the DRM_VBLANK_NEXTMISS */ + else + vbl.request.type |= DRM_VBLANK_NEXTONMISS; + } + + vbl.request.sequence = *target_msc; + vbl.request.signal = (unsigned long) pVblankInfo; + +#if DBG_DRM_EVENT + DRI2FrameEventPtr pEvent = (DRI2FrameEventPtr) vblank_info; + if (type == VBLANK_INFO_SWAP) + pVblankInfo->xdbg_log_vblank = xDbgLogDrmEventAddVblank (pipe, pEvent->client_idx, pEvent->drawable_id, type); + else + pVblankInfo->xdbg_log_vblank = xDbgLogDrmEventAddVblank (pipe, 0, 0, type); +#endif + ret = drmWaitVBlank (pSec->drm_fd, &vbl); + if (ret) + { +#if DBG_DRM_EVENT + xDbgLogDrmEventRemoveVblank (pVblankInfo->xdbg_log_vblank); +#endif + if (pVblankInfo) + { + free(pVblankInfo); + pVblankInfo = NULL; + } + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, + "divisor 0 get vblank counter failed: %s\n", + strerror (errno)); + return FALSE; + } + + XDBG_TRACE (MDISP, "vblank do (%p, %ld)\n", pVblankInfo, pVblankInfo->time); + + /* Adjust returned value for 1 fame pageflip offset of flip > 0 */ + *target_msc = vbl.reply.sequence + flip; + + return TRUE; +} + +int +secDisplayDrawablePipe (DrawablePtr pDraw) +{ + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + BoxRec box, crtc_box; + xf86CrtcPtr pCrtc; + int pipe = -1; + + box.x1 = pDraw->x; + box.y1 = pDraw->y; + box.x2 = box.x1 + pDraw->width; + box.y2 = box.y1 + pDraw->height; + + pCrtc = secModeCoveringCrtc (pScrn, &box, NULL, &crtc_box); + + if (pCrtc != NULL && !pCrtc->rotatedData) + pipe = secModeGetCrtcPipe (pCrtc); + + return pipe; +} + +int +secDisplayCrtcPipe (ScrnInfoPtr pScrn, int crtc_id) +{ + xf86CrtcConfigPtr pCrtcConfig = XF86_CRTC_CONFIG_PTR (pScrn); + int c; + + for (c = 0; c < pCrtcConfig->num_crtc; c++) + { + xf86CrtcPtr pCrtc = pCrtcConfig->crtc[c]; + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + if (pCrtcPriv->mode_crtc->crtc_id == crtc_id) + return pCrtcPriv->pipe; + } + + XDBG_ERROR (MDISP, "%s(%d): crtc(%d) not found.\n", __func__, __LINE__, crtc_id); + + for (c = 0; c < pCrtcConfig->num_crtc; c++) + { + xf86CrtcPtr pCrtc = pCrtcConfig->crtc[c]; + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + XDBG_ERROR (MDISP, "%s(%d) : crtc(%d) != crtc(%d)\n", __func__, __LINE__, + pCrtcPriv->mode_crtc->crtc_id, crtc_id); + } + + return 0; +} + +Bool secDisplayUpdateRequest(ScrnInfoPtr pScrn) +{ + XDBG_RETURN_VAL_IF_FAIL (pScrn != NULL, FALSE); + + SECPtr pSec = SECPTR(pScrn); + xf86CrtcPtr pCrtc = xf86CompatCrtc (pScrn); + SECCrtcPrivPtr pCrtcPriv; + tbm_bo bo; + Bool ret = FALSE; + SECPageFlipPtr pPageFlip = NULL; + + XDBG_RETURN_VAL_IF_FAIL (pCrtc != NULL, FALSE); + + pCrtcPriv = pCrtc->driver_private; + XDBG_RETURN_VAL_IF_FAIL (pCrtcPriv != NULL, FALSE); + + bo = pCrtcPriv->front_bo; + + if( pCrtcPriv->is_fb_blit_flipping || pCrtcPriv->is_flipping || secCrtcGetFirstPendingFlip (pCrtc) ) + { + XDBG_DEBUG (MDISP, "drmModePageFlip is already requested!\n"); + } + else + { + // Without buffer swap, we need to request drmModePageFlip(). + if( bo != NULL ) + { + SECFbBoDataPtr bo_data; + int fb_id = 0; + + tbm_bo_get_user_data (bo, TBM_BO_DATA_FB, (void * *)&bo_data); + XDBG_RETURN_VAL_IF_FAIL(bo_data != NULL, FALSE); + + fb_id = bo_data->fb_id; + + pPageFlip = calloc (1, sizeof (SECPageFlipRec)); + if (pPageFlip == NULL) + { + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "Page flip alloc failed\n"); + return FALSE; + } + + /* Only the reference crtc will finally deliver its page flip + * completion event. All other crtc's events will be discarded. + */ + pPageFlip->dispatch_me = 0; + pPageFlip->pCrtc = pCrtc; + pPageFlip->clone = TRUE; + pPageFlip->back_bo = secRenderBoRef (bo); + pPageFlip->data = NULL; + pPageFlip->flip_failed = FALSE; + pPageFlip->xdbg_log_pageflip = NULL; + pPageFlip->time = GetTimeInMillis (); + + /* accessilitity */ + if (pCrtcPriv->bAccessibility || pCrtcPriv->screen_rotate_degree > 0) + { + tbm_bo accessibility_bo = pCrtcPriv->accessibility_back_bo; + SECFbBoDataPtr accessibility_bo_data; + + tbm_bo_get_user_data (accessibility_bo, TBM_BO_DATA_FB, (void * *)&accessibility_bo_data); + XDBG_GOTO_IF_FAIL (accessibility_bo_data != NULL, fail); + + fb_id = accessibility_bo_data->fb_id; + + /*Buffer is already changed by bo_swap*/ + if (!secCrtcExecAccessibility (pCrtc, bo, accessibility_bo)) + goto fail; + + pPageFlip->accessibility_back_bo = secRenderBoRef(accessibility_bo); + } + + /* + * DRM Page Flip + * If pPageFlip->dispatch_me is NULL, then in SECModePageFlipHandler, nothing to happen. + * That means only LCD buffer is updated. + * Frame buffer is not swapped. Because these request is only for FB_BLIT case! + */ + if (drmModePageFlip (pSec->drm_fd, secCrtcID(pCrtcPriv), fb_id, + DRM_MODE_PAGE_FLIP_EVENT, pPageFlip)) + { + XDBG_ERRNO (MDISP, "Page flip failed: %s\n", strerror (errno)); + goto fail; + } + + pCrtcPriv->flip_info = NULL; + pCrtcPriv->flip_count++; + pCrtcPriv->is_fb_blit_flipping = TRUE; + } + else + { + XDBG_DEBUG (MDISP, "pCrtcPriv->front_bo is NULL!\n"); + } + } + + ret = TRUE; + + return ret; + +fail : + + if( pPageFlip != NULL ) + { + if (pPageFlip->accessibility_back_bo) + { + secRenderBoUnref(pPageFlip->accessibility_back_bo); + pPageFlip->accessibility_back_bo = NULL; + } + + if (pPageFlip->back_bo) + { + secRenderBoUnref(pPageFlip->back_bo); + pPageFlip->back_bo = NULL; + } + + free(pPageFlip); + } + + return ret; +} + diff --git a/src/crtcconfig/sec_display.h b/src/crtcconfig/sec_display.h new file mode 100755 index 0000000..e45cc05 --- /dev/null +++ b/src/crtcconfig/sec_display.h @@ -0,0 +1,183 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@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. + +**************************************************************************/ + +#ifndef __SEC_DISPLAY_H__ +#define __SEC_DISPLAY_H__ + +#include <xf86drmMode.h> +#include <xf86Crtc.h> +#include <tbm_bufmgr.h> +#include <list.h> + +#define DBG_DRM_EVENT 1 + +typedef enum +{ + DISPLAY_SET_MODE_OFF, + DISPLAY_SET_MODE_CLONE, + DISPLAY_SET_MODE_EXT, +} SECDisplaySetMode; + +typedef enum +{ + DISPLAY_CONN_MODE_NONE, + DISPLAY_CONN_MODE_HDMI, + DISPLAY_CONN_MODE_VIRTUAL, + DISPLAY_CONN_MODE_MAX, +} SECDisplayConnMode; + +typedef enum +{ + VBLNAK_INFO_NONE, + VBLANK_INFO_SWAP, + VBLANK_INFO_PLANE, + VBLANK_INFO_MAX +} SECVBlankInfoType; + +typedef struct _secDrmEventContext { + void (*vblank_handler) (int fd, + unsigned int sequence, + unsigned int tv_sec, + unsigned int tv_usec, + void *user_data); + + void (*page_flip_handler) (int fd, + unsigned int sequence, + unsigned int tv_sec, + unsigned int tv_usec, + void *user_data); + + void (*g2d_handler) (int fd, + unsigned int cmdlist_no, + unsigned int tv_sec, + unsigned int tv_usec, + void *user_data); + + void (*ipp_handler) (int fd, + unsigned int prop_id, + unsigned int *buf_idx, + unsigned int tv_sec, + unsigned int tv_usec, + void *user_data); +} secDrmEventContext, *secDrmEventContextPtr; + +typedef struct _secDrmMode +{ + int type; + int fd; + drmModeResPtr mode_res; + drmModePlaneResPtr plane_res; + int cpp; + drmModeModeInfo main_lcd_mode; + drmModeModeInfo ext_connector_mode; + + secDrmEventContext event_context; + + struct xorg_list outputs; + struct xorg_list crtcs; + struct xorg_list planes; + + SECDisplaySetMode set_mode; + SECDisplayConnMode conn_mode; + int rotate; + + int unset_connector_type; +} SECModeRec, *SECModePtr; + +typedef struct _secPageFlip +{ + xf86CrtcPtr pCrtc; + Bool dispatch_me; + Bool clone; + Bool flip_failed; + + tbm_bo back_bo; + tbm_bo accessibility_back_bo; + + void *data; + CARD32 time; + +#if DBG_DRM_EVENT + void *xdbg_log_pageflip; +#endif +} SECPageFlipRec, *SECPageFlipPtr; + +typedef struct _secVBlankInfo +{ + SECVBlankInfoType type; + void *data; /* request data pointer */ + CARD32 time; + +#if DBG_DRM_EVENT + void *xdbg_log_vblank; +#endif +} SECVBlankInfoRec, *SECVBlankInfoPtr; + +typedef struct _secProperty +{ + drmModePropertyPtr mode_prop; + uint64_t value; + int num_atoms; /* if range prop, num_atoms == 1; if enum prop, num_atoms == num_enums + 1 */ + Atom *atoms; +} SECPropertyRec, *SECPropertyPtr; + +Bool secModePreInit (ScrnInfoPtr pScrn, int drm_fd); +void secModeInit (ScrnInfoPtr pScrn); +void secModeDeinit (ScrnInfoPtr pScrn); +xf86CrtcPtr secModeCoveringCrtc (ScrnInfoPtr pScrn, BoxPtr pBox, xf86CrtcPtr pDesiredCrtc, BoxPtr pBoxCrtc); +int secModeGetCrtcPipe (xf86CrtcPtr pCrtc); +Bool secModePageFlip (ScrnInfoPtr pScrn, xf86CrtcPtr pCrtc, void* flip_info, int pipe, tbm_bo back_bo); +void secModeLoadPalette (ScrnInfoPtr pScrn, int numColors, int* indices, LOCO* colors, VisualPtr pVisual); + +void secDisplaySwapModeFromKmode(ScrnInfoPtr pScrn, drmModeModeInfoPtr kmode, DisplayModePtr pMode); +void secDisplayModeFromKmode(ScrnInfoPtr pScrn, drmModeModeInfoPtr kmode, DisplayModePtr pMode); +void secDisplaySwapModeToKmode(ScrnInfoPtr pScrn, drmModeModeInfoPtr kmode, DisplayModePtr pMode); +void secDisplayModeToKmode(ScrnInfoPtr pScrn, drmModeModeInfoPtr kmode, DisplayModePtr pMode); + +Bool secDisplaySetDispSetMode (ScrnInfoPtr pScrn, SECDisplaySetMode disp_mode); +SECDisplaySetMode secDisplayGetDispSetMode (ScrnInfoPtr pScrn); +Bool secDisplaySetDispRotate (ScrnInfoPtr pScrn, int disp_rotate); +int secDisplayGetDispRotate (ScrnInfoPtr pScrn); +Bool secDisplaySetDispConnMode (ScrnInfoPtr pScrn, SECDisplayConnMode disp_conn); +SECDisplayConnMode secDisplayGetDispConnMode (ScrnInfoPtr pScrn); + +Bool secDisplayInitDispMode (ScrnInfoPtr pScrn, SECDisplayConnMode conn_mode); +void secDisplayDeinitDispMode (ScrnInfoPtr pScrn); + +Bool secDisplayGetCurMSC (ScrnInfoPtr pScrn, int pipe, CARD64 *ust, CARD64 *msc); +Bool secDisplayVBlank (ScrnInfoPtr pScrn, int pipe, CARD64 *target_msc, int flip, SECVBlankInfoType type, void *vblank_info); +int secDisplayDrawablePipe (DrawablePtr pDraw); + +int secDisplayCrtcPipe (ScrnInfoPtr pScrn, int crtc_id); + +Bool secDisplayUpdateRequest(ScrnInfoPtr pScrn); + +#endif /* __SEC_DISPLAY_H__ */ + diff --git a/src/crtcconfig/sec_layer.c b/src/crtcconfig/sec_layer.c new file mode 100755 index 0000000..d91f950 --- /dev/null +++ b/src/crtcconfig/sec_layer.c @@ -0,0 +1,1146 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 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. + +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/ioctl.h> +#include <fcntl.h> +#include <errno.h> +#include <stdlib.h> + +#include "sec.h" +#include "sec_util.h" +#include "sec_crtc.h" +#include "sec_output.h" +#include "sec_plane.h" +#include "sec_layer.h" +#include "sec_video_fourcc.h" +#include "sec_video_tvout.h" +#include "sec_video_virtual.h" + +#include <exynos_drm.h> + +//#define DEBUG_REFCNT + +#ifdef DEBUG_REFCNT +#define SEC_LAYER_PRINT_REFCNT(b) \ + XDBG_TRACE(MLYR, "layer(%p) ref_cnt(%d) \n", b, b->ref_cnt) +#else +#define SEC_LAYER_PRINT_REFCNT(b) +#endif + +typedef struct _NotifyFuncData +{ + NotifyFunc func; + void *user_data; + + struct xorg_list link; +} NotifyFuncData; + +struct _SECLayer +{ + ScrnInfoPtr pScrn; + + SECLayerOutput output; + SECLayerPos lpos; + + int plane_id; + int crtc_id; + + /* for buffer */ + int fb_id; + + int offset_x; + int offset_y; + + xRectangle *src; + xRectangle *dst; + + SECVideoBuf *vbuf; + Bool visible; + + /* vblank */ + Bool enable_vblank; + Bool wait_vblank; + SECVideoBuf *wait_vbuf; + SECVideoBuf *pending_vbuf; + SECVideoBuf *showing_vbuf; + + struct xorg_list noti_data; + struct xorg_list link; + + Bool onoff; + int ref_cnt; + Bool freeze_update; + + /* count */ + unsigned int put_counts; + OsTimerPtr timer; +}; + +static Bool crtc_layers_init; +static struct xorg_list crtc_layers; +static Bool wait_vblank[LAYER_OUTPUT_MAX]; + +#define LAYER_VBLANK_FLAG 0xFFFF + +static CARD32 +_countPrint (OsTimerPtr timer, CARD32 now, pointer arg) +{ + SECLayer *layer = (SECLayer*)arg; + + if (layer->timer) + { + TimerFree (layer->timer); + layer->timer = NULL; + } + + XDBG_DEBUG (MEXA, "crtc(%d) pos(%d) : %d fps. \n", + layer->crtc_id, layer->lpos, layer->put_counts); + + layer->put_counts = 0; + + return 0; +} + +static void +_countFps (SECLayer *layer) +{ + layer->put_counts++; + + if (layer->timer) + return; + + layer->timer = TimerSet (NULL, 0, 1000, _countPrint, layer); +} + +static void +_secLayerInitList (void) +{ + if (!crtc_layers_init) + { + xorg_list_init (&crtc_layers); + crtc_layers_init = TRUE; + } +} + +static void +_secLayerNotify (SECLayer *layer, int type, void *type_data) +{ + NotifyFuncData *data = NULL, *data_next = NULL; + + xorg_list_for_each_entry_safe (data, data_next, &layer->noti_data, link) + { + if (data->func) + data->func (layer, type, type_data, data->user_data); + } +} + +static int +_GetCrtcIdForOutput (ScrnInfoPtr pScrn, SECLayerOutput output) +{ + SECModePtr pSecMode = (SECModePtr) SECPTR (pScrn)->pSecMode; + SECOutputPrivPtr pOutputPriv = NULL; + int crtc_id = 0; + + switch (output) + { + case LAYER_OUTPUT_LCD: + pOutputPriv = secOutputGetPrivateForConnType (pScrn, DRM_MODE_CONNECTOR_LVDS); + if (!pOutputPriv) + pOutputPriv = secOutputGetPrivateForConnType (pScrn, DRM_MODE_CONNECTOR_Unknown); + if (pOutputPriv && pOutputPriv->mode_encoder) + crtc_id = pOutputPriv->mode_encoder->crtc_id; + break; + case LAYER_OUTPUT_EXT: + if (pSecMode->conn_mode == DISPLAY_CONN_MODE_HDMI) + { + pOutputPriv = secOutputGetPrivateForConnType (pScrn, DRM_MODE_CONNECTOR_HDMIA); + if (!pOutputPriv) + pOutputPriv = secOutputGetPrivateForConnType (pScrn, DRM_MODE_CONNECTOR_HDMIB); + if (pOutputPriv && pOutputPriv->mode_encoder) + crtc_id = pOutputPriv->mode_encoder->crtc_id; + } + else if (pSecMode->conn_mode == DISPLAY_CONN_MODE_VIRTUAL) + { + pOutputPriv = secOutputGetPrivateForConnType (pScrn, DRM_MODE_CONNECTOR_VIRTUAL); + if (pOutputPriv && pOutputPriv->mode_encoder) + crtc_id = pOutputPriv->mode_encoder->crtc_id; + } + break; + default: + break; + } + + XDBG_DEBUG (MLYR, "crtc(%d) for output(%d) \n", crtc_id, output); + + if (crtc_id == 0) + XDBG_ERROR (MLYR, "no crtc for output(%d) \n", output); + + return crtc_id; +} + +static int +_GetCrtcID (SECLayer *layer) +{ + if (layer->crtc_id > 0) + return layer->crtc_id; + + layer->crtc_id = _GetCrtcIdForOutput (layer->pScrn, layer->output); + + XDBG_RETURN_VAL_IF_FAIL (layer->crtc_id > 0, 0); + + return layer->crtc_id; +} + +static int +_secLayerGetPlanePos (SECLayer *layer, SECLayerPos lpos) +{ + if (layer->output == LAYER_OUTPUT_LCD) + { + XDBG_DEBUG (MLYR, "lpos(%d) => ppos(%d) (1)\n", lpos, PLANE_POS_3 + lpos); + return PLANE_POS_3 + lpos; + } + else if (layer->output == LAYER_OUTPUT_EXT) + { + if (lpos == -1) + { + XDBG_DEBUG (MLYR, "lpos(%d) => ppos(%d) (2)\n", lpos, PLANE_POS_2); + return PLANE_POS_2; + } + else + { + XDBG_DEBUG (MLYR, "lpos(%d) => ppos(%d) (3)\n", lpos, PLANE_POS_0 + lpos); + return PLANE_POS_0 + lpos; + } + } + else + { + XDBG_NEVER_GET_HERE (MLYR); + } + + return -1; +} + +static void +_secLayerDestroy (SECLayer *layer) +{ + NotifyFuncData *data = NULL, *data_next = NULL; + + XDBG_RETURN_IF_FAIL (layer != NULL); + + xorg_list_del (&layer->link); + + if (layer->src) + free (layer->src); + if (layer->dst) + free (layer->dst); + + if (layer->wait_vbuf) + secUtilVideoBufferUnref (layer->wait_vbuf); + if (layer->pending_vbuf) + secUtilVideoBufferUnref (layer->pending_vbuf); + if (layer->showing_vbuf) + secUtilVideoBufferUnref (layer->showing_vbuf); + if (layer->vbuf) + { + secUtilVideoBufferUnref (layer->vbuf); + layer->vbuf = NULL; + } + + XDBG_TRACE (MLYR, "layer(%p) destroyed. \n", layer); + SEC_LAYER_PRINT_REFCNT (layer); + + _secLayerNotify (layer, LAYER_DESTROYED, NULL); + + xorg_list_for_each_entry_safe (data, data_next, &layer->noti_data, link) + { + xorg_list_del (&data->link); + free (data); + } + + if (layer->plane_id > 0) + secPlaneFreeId (layer->plane_id); + + free (layer); +} + +static void +_secLayerWatchVblank (SECLayer *layer) +{ + CARD64 ust, msc, target_msc; + int pipe, flip = 1; + SECPtr pSec = SECPTR (layer->pScrn); + + /* if lcd is off, do not request vblank information */ + if (pSec->isLcdOff) + return; + + pipe = secDisplayCrtcPipe (layer->pScrn, _GetCrtcID (layer)); + + layer->wait_vblank = TRUE; + + if (wait_vblank[pipe]) + return; + + wait_vblank[pipe] = TRUE; + + if (!secDisplayGetCurMSC (layer->pScrn, pipe, &ust, &msc)) + XDBG_WARNING (MLYR, "fail to get current_msc.\n"); + + target_msc = msc + 1; + + XDBG_TRACE (MLYR, "layer(%p) wait vblank : cur(%lld) target(%lld). \n", + layer, msc, target_msc); + + if (!secDisplayVBlank (layer->pScrn, pipe, &target_msc, flip, VBLANK_INFO_PLANE, (void*)pipe)) + XDBG_WARNING (MLYR, "fail to Vblank.\n"); +} + +static Bool +_secLayerShowInternal (SECLayer *layer, Bool need_update) +{ + int crtc_id, plane_pos; + + XDBG_RETURN_VAL_IF_FAIL (layer->fb_id > 0, FALSE); + + crtc_id = _GetCrtcID (layer); + plane_pos = _secLayerGetPlanePos (layer, layer->lpos); + + if (!secPlaneShow (layer->plane_id, crtc_id, + layer->src->x, layer->src->y, + layer->src->width, layer->src->height, + layer->offset_x + layer->dst->x, + layer->offset_y + layer->dst->y, + layer->dst->width, layer->dst->height, + plane_pos, need_update)) + return FALSE; + + return TRUE; +} + +static void +_secLayerGetBufferID (SECLayer *layer, SECVideoBuf *vbuf) +{ + SECModePtr pSecMode; + unsigned int drmfmt; + unsigned int handles[4] = {0,}; + unsigned int pitches[4] = {0,}; + unsigned int offsets[4] = {0,}; + int i; + + if (vbuf->fb_id > 0) + return; + + pSecMode = (SECModePtr) SECPTR (layer->pScrn)->pSecMode; + drmfmt = secUtilGetDrmFormat (vbuf->id); + + for (i = 0 ; i < PLANAR_CNT; i++) + { + handles[i] = (unsigned int)vbuf->handles[i]; + pitches[i] = (unsigned int)vbuf->pitches[i]; + offsets[i] = (unsigned int)vbuf->offsets[i]; + } + + if (drmModeAddFB2 (pSecMode->fd, vbuf->width, vbuf->height, drmfmt, + handles, pitches, offsets, &vbuf->fb_id, 0)) + { + XDBG_ERRNO (MLYR, "drmModeAddFB2 failed. handles(%d %d %d) pitches(%d %d %d) offsets(%d %d %d) '%c%c%c%c'\n", + handles[0], handles[1], handles[2], + pitches[0], pitches[1], pitches[2], + offsets[0], offsets[1], offsets[2], + FOURCC_STR (drmfmt)); + } + + XDBG_DEBUG (MVBUF, "layer(%p) vbuf(%ld) fb_id(%d) added. \n", layer, vbuf->stamp, vbuf->fb_id); +} + +Bool +secLayerSupport (ScrnInfoPtr pScrn, SECLayerOutput output, SECLayerPos lpos, unsigned int id) +{ + SECModePtr pSecMode; + + XDBG_RETURN_VAL_IF_FAIL (pScrn != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (output < LAYER_OUTPUT_MAX, FALSE); + + pSecMode = (SECModePtr) SECPTR (pScrn)->pSecMode; + + if (output == LAYER_OUTPUT_EXT && lpos == LAYER_LOWER1) + { + if (pSecMode->conn_mode == DISPLAY_CONN_MODE_HDMI) + { + if (id == FOURCC_SN12 || id == FOURCC_ST12) + return TRUE; + else + return FALSE; + } + else if (pSecMode->conn_mode == DISPLAY_CONN_MODE_VIRTUAL) + { + if (id == FOURCC_SN12 || id == FOURCC_RGB32) + return TRUE; + else + return FALSE; + } + } + + return (id == FOURCC_RGB32 || id == FOURCC_SR32) ? TRUE : FALSE; +} + +SECLayer* +secLayerFind (SECLayerOutput output, SECLayerPos lpos) +{ + SECLayer *layer = NULL, *layer_next = NULL; + + XDBG_RETURN_VAL_IF_FAIL (output < LAYER_OUTPUT_MAX, NULL); + + _secLayerInitList (); + + xorg_list_for_each_entry_safe (layer, layer_next, &crtc_layers, link) + { + if (layer->output == output && layer->lpos == lpos) + return layer; + } + + return NULL; +} + +void +secLayerDestroyAll (void) +{ + SECLayer *layer = NULL, *layer_next = NULL; + + _secLayerInitList (); + + xorg_list_for_each_entry_safe (layer, layer_next, &crtc_layers, link) + { + _secLayerDestroy (layer); + } +} + +void +secLayerShowAll (ScrnInfoPtr pScrn, SECLayerOutput output) +{ + int crtc_id = _GetCrtcIdForOutput (pScrn, output); + + secPlaneShowAll (crtc_id); +} + +SECLayer* +secLayerCreate (ScrnInfoPtr pScrn, SECLayerOutput output, SECLayerPos lpos) +{ + SECLayer* layer; + + XDBG_RETURN_VAL_IF_FAIL (pScrn != NULL, NULL); + XDBG_RETURN_VAL_IF_FAIL (output < LAYER_OUTPUT_MAX, NULL); + XDBG_RETURN_VAL_IF_FAIL (lpos != LAYER_DEFAULT, NULL); + + layer = secLayerFind (output, lpos); + if (layer) + { + XDBG_ERROR (MLYR, "layer(%p) already is at output(%d) lpos(%d). \n", + layer, output, lpos); + + return NULL; + } + + layer = calloc (sizeof (SECLayer), 1); + XDBG_RETURN_VAL_IF_FAIL (layer != NULL, NULL); + + layer->pScrn = pScrn; + layer->output = output; + layer->lpos = lpos; + + layer->plane_id = secPlaneGetID (); + if (layer->plane_id < 0) + { + free (layer); + return NULL; + } + + layer->ref_cnt = 1; + + xorg_list_init (&layer->noti_data); + + _secLayerInitList (); + + xorg_list_add(&layer->link, &crtc_layers); + + XDBG_TRACE (MLYR, "layer(%p) output(%d) lpos(%d) created. \n", layer, output, lpos); + SEC_LAYER_PRINT_REFCNT (layer); + + return layer; +} + +SECLayer* +secLayerRef (SECLayer* layer) +{ + XDBG_RETURN_VAL_IF_FAIL (layer != NULL, NULL); + + layer->ref_cnt++; + + SEC_LAYER_PRINT_REFCNT (layer); + + return layer; +} + +void +secLayerUnref (SECLayer* layer) +{ + XDBG_RETURN_IF_FAIL (layer != NULL); + + layer->ref_cnt--; + + SEC_LAYER_PRINT_REFCNT (layer); + + if (layer->ref_cnt == 0) + { + secLayerHide (layer); + _secLayerDestroy (layer); + } +} + +void +secLayerAddNotifyFunc (SECLayer* layer, NotifyFunc func, void *user_data) +{ + NotifyFuncData *data = NULL, *data_next = NULL; + + XDBG_RETURN_IF_FAIL (layer != NULL); + XDBG_RETURN_IF_FAIL (func != NULL); + + xorg_list_for_each_entry_safe (data, data_next, &layer->noti_data, link) + { + if (data->func == func && data->user_data == user_data) + return; + } + + data = calloc (sizeof (NotifyFuncData), 1); + XDBG_RETURN_IF_FAIL (data != NULL); + + data->func = func; + data->user_data = user_data; + + xorg_list_add (&data->link, &layer->noti_data); +} + +void +secLayerRemoveNotifyFunc (SECLayer* layer, NotifyFunc func) +{ + NotifyFuncData *data = NULL, *data_next = NULL; + + XDBG_RETURN_IF_FAIL (layer != NULL); + XDBG_RETURN_IF_FAIL (func != NULL); + + xorg_list_for_each_entry_safe (data, data_next, &layer->noti_data, link) + { + if (data->func == func) + { + xorg_list_del (&data->link); + free (data); + } + } +} + +Bool +secLayerIsVisible (SECLayer *layer) +{ + XDBG_RETURN_VAL_IF_FAIL (layer != NULL, FALSE); + + return layer->visible; +} + +void +secLayerShow (SECLayer *layer) +{ + SECModePtr pSecMode; + + XDBG_RETURN_IF_FAIL (layer != NULL); + XDBG_RETURN_IF_FAIL (layer->fb_id > 0); + + pSecMode = (SECModePtr) SECPTR (layer->pScrn)->pSecMode; + + if (layer->visible) + return; + + if (layer->output == LAYER_OUTPUT_EXT && pSecMode->conn_mode == DISPLAY_CONN_MODE_VIRTUAL) + { + layer->visible = TRUE; + XDBG_TRACE (MLYR, "layer(%p) shown. \n", layer); + return; + } + + if (!_secLayerShowInternal (layer, FALSE)) + return; + + if (layer->enable_vblank) + _secLayerWatchVblank (layer); + + layer->visible = TRUE; + + XDBG_TRACE (MLYR, "layer(%p) shown. \n", layer); + + _secLayerNotify (layer, LAYER_SHOWN, (void*)layer->fb_id); +} + +void +secLayerHide (SECLayer *layer) +{ + SECModePtr pSecMode; + + XDBG_RETURN_IF_FAIL (layer != NULL); + + pSecMode = (SECModePtr) SECPTR (layer->pScrn)->pSecMode; + + if (!layer->visible || layer->ref_cnt > 1) + return; + + if (layer->output == LAYER_OUTPUT_EXT && pSecMode->conn_mode == DISPLAY_CONN_MODE_VIRTUAL) + { + layer->visible = FALSE; + XDBG_TRACE (MLYR, "layer(%p) hidden. \n", layer); + return; + } + + if (!secPlaneHide (layer->plane_id)) + return; + + if (layer->wait_vbuf && VBUF_IS_VALID (layer->wait_vbuf)) + { + layer->wait_vbuf->showing = FALSE; + XDBG_DEBUG (MVBUF, "layer(%p) <-- %s (%ld,%d,%d) \n", layer, + (layer->output==LAYER_OUTPUT_LCD)?"LCD":"TV", + layer->wait_vbuf->stamp, VBUF_IS_CONVERTING (layer->wait_vbuf), + layer->wait_vbuf->showing); + secUtilVideoBufferUnref (layer->wait_vbuf); + } + + if (layer->pending_vbuf && VBUF_IS_VALID (layer->pending_vbuf)) + { + layer->pending_vbuf->showing = FALSE; + secUtilVideoBufferUnref (layer->pending_vbuf); + } + + if (layer->showing_vbuf && VBUF_IS_VALID (layer->showing_vbuf)) + { + layer->showing_vbuf->showing = FALSE; + XDBG_DEBUG (MVBUF, "layer(%p) <-- %s (%ld,%d,%d) \n", layer, + (layer->output==LAYER_OUTPUT_LCD)?"LCD":"TV", + layer->showing_vbuf->stamp, VBUF_IS_CONVERTING (layer->showing_vbuf), + layer->showing_vbuf->showing); + secUtilVideoBufferUnref (layer->showing_vbuf); + } + + layer->showing_vbuf = NULL; + layer->pending_vbuf = NULL; + layer->wait_vbuf = NULL; + layer->wait_vblank = FALSE; + layer->visible = FALSE; + layer->crtc_id = 0; + + XDBG_TRACE (MLYR, "layer(%p) hidden. \n", layer); + + _secLayerNotify (layer, LAYER_HIDDEN, (void*)layer->fb_id); +} + +void +secLayerFreezeUpdate (SECLayer *layer, Bool enable) +{ + XDBG_RETURN_IF_FAIL (layer != NULL); + + layer->freeze_update = enable; + + XDBG_TRACE (MLYR, "layer(%p) freeze %d. \n", layer, enable); + + if (layer->plane_id > 0) + secPlaneFreezeUpdate (layer->plane_id, enable); +} + +void +secLayerUpdate (SECLayer *layer) +{ + SECModePtr pSecMode; + + XDBG_RETURN_IF_FAIL (layer != NULL); + XDBG_RETURN_IF_FAIL (layer->fb_id > 0); + + pSecMode = (SECModePtr) SECPTR (layer->pScrn)->pSecMode; + + if (!layer->visible) + return; + + xf86CrtcConfigPtr pCrtcConfig = XF86_CRTC_CONFIG_PTR (layer->pScrn); + SECCrtcPrivPtr pCrtcPriv = NULL; + int c; + + for (c = 0; c < pCrtcConfig->num_crtc; c++) + { + xf86CrtcPtr pCrtc = pCrtcConfig->crtc[c]; + SECCrtcPrivPtr pTemp = pCrtc->driver_private; + if (pTemp->mode_crtc && pTemp->mode_crtc->crtc_id == layer->crtc_id) + { + pCrtcPriv = pTemp; + break; + } + } + + if (!pCrtcPriv || !pCrtcPriv->bAccessibility) + return; + + if (layer->output == LAYER_OUTPUT_EXT && pSecMode->conn_mode == DISPLAY_CONN_MODE_VIRTUAL) + return; + + if (!_secLayerShowInternal (layer, TRUE)) + return; +} + +void +secLayerTurn (SECLayer *layer, Bool onoff, Bool user) +{ + XDBG_RETURN_IF_FAIL (layer != NULL); + + secPlaneTrun (layer->plane_id, onoff, user); +} + +Bool +secLayerTurnStatus (SECLayer *layer) +{ + XDBG_RETURN_VAL_IF_FAIL (layer != NULL, FALSE); + + return secPlaneTrunStatus (layer->plane_id); +} + +void +secLayerEnableVBlank (SECLayer *layer, Bool enable) +{ + XDBG_RETURN_IF_FAIL (layer != NULL); + + layer->enable_vblank = (enable) ? TRUE : FALSE; +} + +Bool +secLayerSetOffset (SECLayer *layer, int x, int y) +{ + SECModePtr pSecMode; + + XDBG_RETURN_VAL_IF_FAIL (layer != NULL, FALSE); + + pSecMode = (SECModePtr) SECPTR (layer->pScrn)->pSecMode; + + if (layer->offset_x == x && layer->offset_y == y) + return TRUE; + + /* display controller restriction. x+width=2's mutiple */ + XDBG_TRACE (MLYR, "layer(%p) offset(%d,%d => %d,%d).\n", + layer, x, y, x & (~0x1), y); + layer->offset_x = x & (~0x1); + layer->offset_y = y; + + if (layer->output == LAYER_OUTPUT_EXT && pSecMode->conn_mode == DISPLAY_CONN_MODE_VIRTUAL) + return TRUE; + + if (secLayerIsVisible (layer) && !layer->freeze_update) + { + int crtc_id = _GetCrtcID (layer); + int plane_pos = _secLayerGetPlanePos (layer, layer->lpos); + + if (!secPlaneShow (layer->plane_id, crtc_id, + layer->src->x, layer->src->y, + layer->src->width, layer->src->height, + layer->offset_x + layer->dst->x, + layer->offset_y + layer->dst->y, + layer->dst->width, layer->dst->height, + plane_pos, FALSE)) + return FALSE; + } + + return TRUE; +} + +void +secLayerGetOffset (SECLayer *layer, int *x, int *y) +{ + XDBG_RETURN_IF_FAIL (layer != NULL); + + if (x) + *x = layer->offset_x; + if (y) + *y = layer->offset_y; +} + +Bool +secLayerSetPos (SECLayer *layer, SECLayerPos lpos) +{ + SECModePtr pSecMode; + XDBG_RETURN_VAL_IF_FAIL (layer != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (lpos >= LAYER_NONE && lpos < LAYER_MAX, FALSE); + + pSecMode = (SECModePtr) SECPTR (layer->pScrn)->pSecMode; + + if (layer->output == LAYER_OUTPUT_EXT && pSecMode->conn_mode == DISPLAY_CONN_MODE_VIRTUAL) + { + layer->lpos = lpos; + return TRUE; + } + + + if (layer->lpos == lpos) + return TRUE; + + if (secLayerFind (layer->output, lpos)) + return FALSE; + + if (secLayerIsVisible (layer) && !layer->freeze_update) + { + if (lpos == LAYER_NONE) + { + if (!secPlaneHide (layer->plane_id)) + return FALSE; + + layer->visible = FALSE; + layer->crtc_id = 0; + } + else + { + int crtc_id = _GetCrtcID (layer); + int plane_pos = _secLayerGetPlanePos (layer, lpos); + + if (!secPlaneShow (layer->plane_id, crtc_id, + layer->src->x, layer->src->y, + layer->src->width, layer->src->height, + layer->offset_x + layer->dst->x, + layer->offset_y + layer->dst->y, + layer->dst->width, layer->dst->height, + plane_pos, FALSE)) + return FALSE; + } + } + + XDBG_TRACE (MLYR, "layer(%p) lpos(%d). \n", layer, lpos); + + layer->lpos = lpos; + + return TRUE; +} + +Bool +secLayerSwapPos (SECLayer *layer1, SECLayer *layer2) +{ + SECLayer *lower, *upper; + SECLayerPos upper_lpos, lower_lpos; + + XDBG_RETURN_VAL_IF_FAIL (layer1 != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (layer2 != NULL, FALSE); + + XDBG_TRACE (MLYR, "layer1(%p) layer2(%p). \n", layer1, layer2); + + lower = (layer2->lpos < layer1->lpos) ? layer2 : layer1; + upper = (layer2->lpos < layer1->lpos) ? layer1 : layer2; + + upper_lpos = upper->lpos; + lower_lpos = lower->lpos; + + secLayerSetPos (upper, LAYER_NONE); + secLayerSetPos (lower, upper_lpos); + secLayerSetPos (upper, lower_lpos); + + return TRUE; +} + +SECLayerPos +secLayerGetPos (SECLayer *layer) +{ + XDBG_RETURN_VAL_IF_FAIL (layer != NULL, 0); + + return layer->lpos; +} + +Bool +secLayerSetRect (SECLayer *layer, xRectangle *src, xRectangle *dst) +{ + SECModePtr pSecMode; + + XDBG_RETURN_VAL_IF_FAIL (layer != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (src != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (dst != NULL, FALSE); + + pSecMode = (SECModePtr) SECPTR (layer->pScrn)->pSecMode; + + if (!layer->src) + layer->src = calloc (sizeof (xRectangle), 1); + + XDBG_RETURN_VAL_IF_FAIL (layer->src != NULL, FALSE); + + if (!layer->dst) + layer->dst = calloc (sizeof (xRectangle), 1); + + XDBG_RETURN_VAL_IF_FAIL (layer->dst != NULL, FALSE); + + if (!memcmp (layer->src, src, sizeof (xRectangle)) && + !memcmp (layer->dst, dst, sizeof (xRectangle))) + return TRUE; + + *layer->src = *src; + *layer->dst = *dst; + + XDBG_TRACE (MLYR, "layer(%p) src(%d,%d %dx%d) dst(%d,%d %dx%d). \n", + layer, src->x, src->y, src->width, src->height, + dst->x, dst->y, dst->width, dst->height); + if (layer->output == LAYER_OUTPUT_EXT && pSecMode->conn_mode == DISPLAY_CONN_MODE_VIRTUAL) + return TRUE; + + if (layer->pending_vbuf && VBUF_IS_VALID (layer->pending_vbuf)) + { + layer->pending_vbuf->showing = FALSE; + secUtilVideoBufferUnref (layer->pending_vbuf); + layer->pending_vbuf = NULL; + } + + if (secLayerIsVisible (layer) && !layer->freeze_update) + { + int plane_pos = _secLayerGetPlanePos (layer, layer->lpos); + + if (!secPlaneShow (layer->plane_id, _GetCrtcID (layer), + src->x, src->y, src->width, src->height, + layer->offset_x + dst->x, + layer->offset_y + dst->y, + dst->width, dst->height, + plane_pos, FALSE)) + return FALSE; + } + + return TRUE; +} + +void +secLayerGetRect (SECLayer *layer, xRectangle *src, xRectangle *dst) +{ + XDBG_RETURN_IF_FAIL (layer != NULL); + + if (src && layer->src) + *src = *layer->src; + + if (dst && layer->dst) + *dst = *layer->dst; +} + +int +secLayerSetBuffer (SECLayer *layer, SECVideoBuf *vbuf) +{ + SECModePtr pSecMode; + unsigned int fb_id; + + XDBG_RETURN_VAL_IF_FAIL (layer != NULL, 0); + XDBG_RETURN_VAL_IF_FAIL (VBUF_IS_VALID (vbuf), 0); + + if (!secLayerSupport (layer->pScrn, layer->output, layer->lpos, vbuf->id)) + { + XDBG_ERROR (MLYR, "fail : layer(%p) output(%d) lpos(%d) vbuf(%c%c%c%c)\n", + layer, layer->output, layer->lpos, FOURCC_STR (vbuf->id)); + return 0; + } + + pSecMode = (SECModePtr) SECPTR (layer->pScrn)->pSecMode; + + if (layer->output == LAYER_OUTPUT_EXT && pSecMode->conn_mode == DISPLAY_CONN_MODE_VIRTUAL) + { + XDBG_RETURN_VAL_IF_FAIL (layer->enable_vblank == FALSE, 0); + + XDBG_TRACE (MLYR, "layer(%p) vbuf('%c%c%c%c', %dx%d, %d,%d %dx%d)\n", + layer, FOURCC_STR(vbuf->id), vbuf->width, vbuf->height, + vbuf->crop.x, vbuf->crop.y, vbuf->crop.width, vbuf->crop.height); + + if (layer->vbuf) + secUtilVideoBufferUnref (layer->vbuf); + + layer->vbuf = secUtilVideoBufferRef (vbuf); + layer->fb_id = 1; + + _secLayerNotify (layer, LAYER_BUF_CHANGED, vbuf); + + return layer->fb_id; + } + + if (layer->wait_vbuf && layer->pending_vbuf) + { + XDBG_TRACE (MLYR, "pending_vbuf(%ld) exists.\n", layer->pending_vbuf->stamp); + return 0; + } + + _secLayerGetBufferID (layer, vbuf); + XDBG_RETURN_VAL_IF_FAIL (vbuf->fb_id > 0, 0); + + if (layer->wait_vbuf && !layer->pending_vbuf) + { + layer->pending_vbuf = secUtilVideoBufferRef (vbuf); + XDBG_RETURN_VAL_IF_FAIL(layer->pending_vbuf, 0) + layer->pending_vbuf->showing = TRUE; + XDBG_TRACE (MLYR, "pending vbuf(%ld).\n", layer->pending_vbuf->stamp); + return vbuf->fb_id; + } + + fb_id = secPlaneGetBuffer (layer->plane_id, NULL, vbuf); + if (fb_id == 0) + { + fb_id = secPlaneAddBuffer (layer->plane_id, vbuf); + XDBG_RETURN_VAL_IF_FAIL (fb_id > 0, 0); + + layer->fb_id = vbuf->fb_id; + } + + if (vbuf->fb_id != fb_id) + XDBG_WARNING (MLYR, "fb_id (%d != %d) \n", vbuf->fb_id, fb_id); + + layer->fb_id = fb_id; + if (!secPlaneAttach (layer->plane_id, fb_id)) + return 0; + + if (secLayerIsVisible (layer) && !layer->freeze_update) + if (!_secLayerShowInternal (layer, TRUE)) + return 0; + + if (layer->enable_vblank) + { + XDBG_RETURN_VAL_IF_FAIL (layer->wait_vbuf == NULL, 0); + + layer->wait_vbuf = secUtilVideoBufferRef (vbuf); + XDBG_RETURN_VAL_IF_FAIL ((layer->wait_vbuf != NULL), 0); + layer->wait_vbuf->showing = TRUE; + XDBG_DEBUG (MVBUF, "layer(%p) --> %s (%ld,%d,%d) \n", layer, + (layer->output==LAYER_OUTPUT_LCD)?"LCD":"TV", + layer->wait_vbuf->stamp, + VBUF_IS_CONVERTING (layer->wait_vbuf), + layer->wait_vbuf->showing); + + if (secLayerIsVisible (layer)) + { + XDBG_TRACE (MLYR, "layer(%p) fb_id(%d) attached. \n", layer, fb_id); + _secLayerWatchVblank (layer); + } + } + + if (layer->vbuf) + secUtilVideoBufferUnref (layer->vbuf); + layer->vbuf = secUtilVideoBufferRef (vbuf); + + _secLayerNotify (layer, LAYER_BUF_CHANGED, vbuf); + + return fb_id; +} + +SECVideoBuf* +secLayerGetBuffer (SECLayer *layer) +{ + XDBG_RETURN_VAL_IF_FAIL (layer != NULL, NULL); + + if (layer->showing_vbuf && layer->dst && layer->visible) + return layer->showing_vbuf; + else if (layer->vbuf) + return layer->vbuf; + + return NULL; +} + +void +secLayerVBlankEventHandler (unsigned int frame, unsigned int tv_sec, + unsigned int tv_usec, void *event_data) +{ + SECLayer *layer = NULL, *layer_next = NULL; + int pipe = (int)event_data; + + XDBG_RETURN_IF_FAIL (pipe < LAYER_OUTPUT_MAX); + + _secLayerInitList (); + + wait_vblank[pipe] = FALSE; + + XDBG_DEBUG (MLYR, "frame(%d), tv_sec(%d), tv_usec(%d) \n", frame, tv_sec, tv_usec); + + xorg_list_for_each_entry_safe (layer, layer_next, &crtc_layers, link) + { + int crtc_pipe = secDisplayCrtcPipe (layer->pScrn, _GetCrtcID (layer)); + + if (!layer->enable_vblank || !layer->wait_vblank) + continue; + + if (crtc_pipe != pipe) + continue; + + layer->wait_vblank = FALSE; + + if (VBUF_IS_VALID (layer->wait_vbuf)) + { + if (layer->showing_vbuf && VBUF_IS_VALID (layer->showing_vbuf)) + { + layer->showing_vbuf->showing = FALSE; + secUtilVideoBufferUnref (layer->showing_vbuf); + } + + layer->showing_vbuf = layer->wait_vbuf; + layer->wait_vbuf = NULL; + + if (layer->pending_vbuf && VBUF_IS_VALID (layer->pending_vbuf)) + { + int fb_id; + + layer->wait_vbuf = layer->pending_vbuf; + layer->pending_vbuf = NULL; + + fb_id = secPlaneGetBuffer (layer->plane_id, NULL, layer->wait_vbuf); + if (fb_id == 0) + { + fb_id = secPlaneAddBuffer (layer->plane_id, layer->wait_vbuf); + XDBG_RETURN_IF_FAIL (fb_id > 0); + + layer->fb_id = layer->wait_vbuf->fb_id; + } + + if (!secPlaneAttach (layer->plane_id, layer->wait_vbuf->fb_id)) + continue; + + if (secLayerIsVisible (layer) && !layer->freeze_update) + _secLayerShowInternal (layer, TRUE); + + _secLayerWatchVblank (layer); + } + + SECPtr pSec = SECPTR (layer->pScrn); + if (pSec->pVideoPriv->video_fps) + _countFps (layer); + + XDBG_TRACE (MLYR, "layer(%p) fb_id(%d) now showing frame(%d) (%ld,%ld,%ld) => crtc(%d) pos(%d). \n", + layer, layer->fb_id, frame, + VSTMAP(layer->pending_vbuf), VSTMAP(layer->wait_vbuf), VSTMAP(layer->showing_vbuf), + _GetCrtcID (layer), layer->lpos); + + _secLayerNotify (layer, LAYER_VBLANK, (void*)layer->showing_vbuf); + } + } +} diff --git a/src/crtcconfig/sec_layer.h b/src/crtcconfig/sec_layer.h new file mode 100644 index 0000000..e3f0685 --- /dev/null +++ b/src/crtcconfig/sec_layer.h @@ -0,0 +1,105 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 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. + +**************************************************************************/ + +#ifndef __SEC_LAYER_H__ +#define __SEC_LAYER_H__ + +#include "sec_video_types.h" +#include "sec_video_fourcc.h" + +typedef enum +{ + LAYER_OUTPUT_LCD, + LAYER_OUTPUT_EXT, + LAYER_OUTPUT_MAX +} SECLayerOutput; + +typedef enum +{ + LAYER_NONE = -3, + LAYER_LOWER2 = -2, + LAYER_LOWER1 = -1, + LAYER_DEFAULT = 0, + LAYER_UPPER = +1, + LAYER_MAX = +2, +} SECLayerPos; + +#define LAYER_DESTROYED 1 +#define LAYER_SHOWN 2 +#define LAYER_HIDDEN 3 +/* To manage buffer */ +#define LAYER_BUF_CHANGED 4 /* type_data: SECLayerBufInfo */ +#define LAYER_VBLANK 5 /* type_data: SECLayerBufInfo */ + +typedef struct _SECLayer SECLayer; + +typedef void (*NotifyFunc) (SECLayer *layer, int type, void *type_data, void *user_data); + +Bool secLayerSupport (ScrnInfoPtr pScrn, SECLayerOutput output, + SECLayerPos lpos, unsigned int id); + +SECLayer* secLayerFind (SECLayerOutput output, SECLayerPos lpos); +void secLayerDestroyAll (void); +void secLayerShowAll (ScrnInfoPtr pScrn, SECLayerOutput output); + +void secLayerAddNotifyFunc (SECLayer *layer, NotifyFunc func, void *user_data); +void secLayerRemoveNotifyFunc (SECLayer *layer, NotifyFunc func); + +SECLayer* secLayerCreate (ScrnInfoPtr pScrn, SECLayerOutput output, SECLayerPos lpos); +SECLayer* secLayerRef (SECLayer *layer); +void secLayerUnref (SECLayer *layer); + +Bool secLayerIsVisible (SECLayer *layer); +void secLayerShow (SECLayer *layer); +void secLayerHide (SECLayer *layer); +void secLayerFreezeUpdate (SECLayer *layer, Bool enable); +void secLayerUpdate (SECLayer *layer); +void secLayerTurn (SECLayer *layer, Bool onoff, Bool user); +Bool secLayerTurnStatus (SECLayer *layer); + +void secLayerEnableVBlank (SECLayer *layer, Bool enable); + +Bool secLayerSetOffset (SECLayer *layer, int x, int y); +void secLayerGetOffset (SECLayer *layer, int *x, int *y); + +Bool secLayerSetPos (SECLayer *layer, SECLayerPos lpos); +SECLayerPos secLayerGetPos (SECLayer *layer); +Bool secLayerSwapPos (SECLayer *layer1, SECLayer *layer2); + +Bool secLayerSetRect (SECLayer *layer, xRectangle *src, xRectangle *dst); +void secLayerGetRect (SECLayer *layer, xRectangle *src, xRectangle *dst); + +int secLayerSetBuffer (SECLayer *layer, SECVideoBuf *vbuf); +SECVideoBuf* secLayerGetBuffer (SECLayer *layer); + +void secLayerVBlankEventHandler (unsigned int frame, unsigned int tv_sec, + unsigned int tv_usec, void *event_data); + +#endif /* __SEC_LAYER_H__ */ diff --git a/src/crtcconfig/sec_output.c b/src/crtcconfig/sec_output.c new file mode 100755 index 0000000..448c5c8 --- /dev/null +++ b/src/crtcconfig/sec_output.c @@ -0,0 +1,881 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@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. + +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <poll.h> + +#include <xorgVersion.h> +#include <tbm_bufmgr.h> +#include <xf86Crtc.h> +#include <xf86DDC.h> +#include <xf86cmap.h> +#include <list.h> +#include <X11/Xatom.h> +#include <X11/extensions/dpmsconst.h> +#include <sec.h> + +#include "sec_util.h" +#include "sec_crtc.h" +#include "sec_output.h" +#include "sec_prop.h" +#include "sec_xberc.h" +#include "sec_layer.h" +#include "sec_wb.h" +#include "sec_video_virtual.h" + +static const int subpixel_conv_table[7] = +{ + 0, + SubPixelUnknown, + SubPixelHorizontalRGB, + SubPixelHorizontalBGR, + SubPixelVerticalRGB, + SubPixelVerticalBGR, + SubPixelNone +}; + +static const char *output_names[] = +{ + "None", + "VGA", + "DVI", + "DVI", + "DVI", + "Composite", + "TV", + "LVDS", + "CTV", + "DIN", + "DP", + "HDMI", + "HDMI", + "TV", + "eDP", + "Virtual", +}; + +static CARD32 +_secOutputResumeWbTimeout (OsTimerPtr timer, CARD32 now, pointer arg) +{ + XDBG_RETURN_VAL_IF_FAIL(arg, 0); + + xf86OutputPtr pOutput = (xf86OutputPtr)arg; + SECPtr pSec = SECPTR (pOutput->scrn); + + pSec = SECPTR (pOutput->scrn); + + if (pSec->resume_timer) + { + TimerFree (pSec->resume_timer); + pSec->resume_timer = NULL; + } + + secDisplaySetDispSetMode (pOutput->scrn, pSec->set_mode); + pSec->set_mode = DISPLAY_SET_MODE_OFF; + + return 0; +} + +static void +_secOutputAttachEdid(xf86OutputPtr pOutput) +{ + SECOutputPrivPtr pOutputPriv = pOutput->driver_private; + drmModeConnectorPtr koutput = pOutputPriv->mode_output; + SECModePtr pSecMode = pOutputPriv->pSecMode; + drmModePropertyBlobPtr edid_blob = NULL; + xf86MonPtr mon = NULL; + int i; + + /* look for an EDID property */ + for (i = 0; i < koutput->count_props; i++) + { + drmModePropertyPtr props; + + props = drmModeGetProperty (pSecMode->fd, koutput->props[i]); + if (!props) + continue; + + if (!(props->flags & DRM_MODE_PROP_BLOB)) + { + drmModeFreeProperty (props); + continue; + } + + if (!strcmp (props->name, "EDID")) + { + drmModeFreePropertyBlob (edid_blob); + edid_blob = + drmModeGetPropertyBlob (pSecMode->fd, + koutput->prop_values[i]); + } + drmModeFreeProperty (props); + } + + if (edid_blob) + { + mon = xf86InterpretEDID (pOutput->scrn->scrnIndex, + edid_blob->data); + + if (mon && edid_blob->length > 128) + mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; + } + + xf86OutputSetEDID (pOutput, mon); + + if (edid_blob) + drmModeFreePropertyBlob (edid_blob); +} + +static Bool +_secOutputPropertyIgnore(drmModePropertyPtr prop) +{ + if (!prop) + return TRUE; + + /* ignore blob prop */ + if (prop->flags & DRM_MODE_PROP_BLOB) + return TRUE; + + /* ignore standard property */ + if (!strcmp (prop->name, "EDID") || + !strcmp (prop->name, "DPMS")) + return TRUE; + + return FALSE; +} + +static xf86OutputStatus +SECOutputDetect(xf86OutputPtr output) +{ + /* go to the hw and retrieve a new output struct */ + SECOutputPrivPtr pOutputPriv = output->driver_private; + SECModePtr pSecMode = pOutputPriv->pSecMode; + xf86OutputStatus status; +// char *conn_str[] = {"connected", "disconnected", "unknow"}; + + /* update output */ + drmModeFreeConnector (pOutputPriv->mode_output); + pOutputPriv->mode_output = + drmModeGetConnector (pSecMode->fd, pOutputPriv->output_id); + XDBG_RETURN_VAL_IF_FAIL (pOutputPriv->mode_output != NULL, XF86OutputStatusUnknown); + + /* update encoder */ + drmModeFreeEncoder (pOutputPriv->mode_encoder); + pOutputPriv->mode_encoder = + drmModeGetEncoder (pSecMode->fd, pOutputPriv->mode_output->encoders[0]); + XDBG_RETURN_VAL_IF_FAIL (pOutputPriv->mode_encoder != NULL, XF86OutputStatusUnknown); + + if (pSecMode->unset_connector_type == pOutputPriv->mode_output->connector_type) + { + return XF86OutputStatusDisconnected; + } +#if 0 + XDBG_INFO (MSEC, "detect : connect(%d, type:%d, status:%s) encoder(%d) crtc(%d).\n", + pOutputPriv->output_id, pOutputPriv->mode_output->connector_type, + conn_str[pOutputPriv->mode_output->connection-1], + pOutputPriv->mode_encoder->encoder_id, pOutputPriv->mode_encoder->crtc_id); +#endif + switch (pOutputPriv->mode_output->connection) + { + case DRM_MODE_CONNECTED: + status = XF86OutputStatusConnected; + break; + case DRM_MODE_DISCONNECTED: + status = XF86OutputStatusDisconnected; + /* unset write-back clone */ + secPropUnSetDisplayMode (output); + break; + default: + case DRM_MODE_UNKNOWNCONNECTION: + status = XF86OutputStatusUnknown; + break; + } + return status; +} + +static Bool +SECOutputModeValid(xf86OutputPtr pOutput, DisplayModePtr pModes) +{ + SECOutputPrivPtr pOutputPriv = pOutput->driver_private; + drmModeConnectorPtr koutput = pOutputPriv->mode_output; + int i; + + /* driver want to remain available modes which is same as mode + supported from drmmode */ + if (pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_LVDS) + { + for (i = 0; i < koutput->count_modes; i++) + { + if (pModes->HDisplay == koutput->modes[i].hdisplay && + pModes->VDisplay == koutput->modes[i].vdisplay) + return MODE_OK; + } + return MODE_ERROR; + } + + return MODE_OK; +} + +static DisplayModePtr +SECOutputGetModes(xf86OutputPtr pOutput) +{ + SECOutputPrivPtr pOutputPriv = pOutput->driver_private; + drmModeConnectorPtr koutput = pOutputPriv->mode_output; + DisplayModePtr Modes = NULL; + int i; + SECPtr pSec = SECPTR (pOutput->scrn); + DisplayModePtr Mode; + + /* LVDS1 (main LCD) does not provide edid data */ + if (pOutputPriv->mode_output->connector_type != DRM_MODE_CONNECTOR_LVDS) + _secOutputAttachEdid(pOutput); + + /* modes should already be available */ + for (i = 0; i < koutput->count_modes; i++) + { + Mode = calloc (1, sizeof (DisplayModeRec)); + if (Mode) + { + /* generate the fake modes when screen rotation is set */ + if(pSec->fake_root) + secDisplaySwapModeFromKmode(pOutput->scrn, &koutput->modes[i], Mode); + else + secDisplayModeFromKmode(pOutput->scrn, &koutput->modes[i], Mode); + Modes = xf86ModesAdd(Modes, Mode); + } + } + + return Modes; +} + +static void +SECOutputDestory(xf86OutputPtr pOutput) +{ + SECOutputPrivPtr pOutputPriv = pOutput->driver_private; + SECPtr pSec = SECPTR (pOutput->scrn); + int i; + + if (pSec->resume_timer) + { + TimerFree (pSec->resume_timer); + pSec->resume_timer = NULL; + } + pSec->set_mode = DISPLAY_SET_MODE_OFF; + + for (i = 0; i < pOutputPriv->num_props; i++) + { + drmModeFreeProperty (pOutputPriv->props[i].mode_prop); + free (pOutputPriv->props[i].atoms); + } + free (pOutputPriv->props); + + drmModeFreeEncoder (pOutputPriv->mode_encoder); + drmModeFreeConnector (pOutputPriv->mode_output); + xorg_list_del (&pOutputPriv->link); + free (pOutputPriv); + + pOutput->driver_private = NULL; +} + +static void +SECOutputDpms(xf86OutputPtr pOutput, int dpms) +{ + SECOutputPrivPtr pOutputPriv = pOutput->driver_private; + drmModeConnectorPtr koutput = pOutputPriv->mode_output; + SECModePtr pSecMode = pOutputPriv->pSecMode; + SECPtr pSec = SECPTR (pOutput->scrn); + int old_dpms = pOutputPriv->dpms_mode; + int i; + + if (!strcmp(pOutput->name, "HDMI1") || + !strcmp(pOutput->name, "Virtual1")) + return; + + if (dpms == DPMSModeSuspend) + return; + + for (i = 0; i < koutput->count_props; i++) + { + drmModePropertyPtr props; + + props = drmModeGetProperty (pSecMode->fd, koutput->props[i]); + if (!props) + continue; + + if ((old_dpms == DPMSModeStandby && dpms == DPMSModeOn) || + (old_dpms == DPMSModeOn && dpms == DPMSModeStandby)) + { + if (!strcmp (props->name, "panel")) + { + int value = (dpms == DPMSModeStandby)? 1 : 0; + drmModeConnectorSetProperty(pSecMode->fd, + pOutputPriv->output_id, + props->prop_id, + value); + pOutputPriv->dpms_mode = dpms; + drmModeFreeProperty (props); + XDBG_INFO (MDPMS, "panel '%s'\n", (value)?"OFF":"ON"); + return; + } + } + else if (!strcmp (props->name, "DPMS")) + { + int _tmp_dpms = dpms; + switch (dpms) + { + case DPMSModeStandby: + case DPMSModeOn: + if (pOutputPriv->isLcdOff == FALSE) + { + drmModeFreeProperty (props); + return; + } + /* lcd on */ + XDBG_INFO (MDPMS, "\t Reqeust DPMS ON (%s)\n", pOutput->name); + _tmp_dpms = DPMSModeOn; + pOutputPriv->isLcdOff = FALSE; + + if (!strcmp(pOutput->name, "LVDS1")) + { + pSec->isLcdOff = FALSE; + + /* if wb need to be started, start wb after timeout. */ + if (pSec->set_mode == DISPLAY_SET_MODE_CLONE) + { + pSec->resume_timer = TimerSet (pSec->resume_timer, + 0, 30, + _secOutputResumeWbTimeout, + pOutput); + } + + secVideoDpms (pOutput->scrn, TRUE); + secVirtualVideoDpms (pOutput->scrn, TRUE); + } + + /* accessibility */ + SECCrtcPrivPtr pCrtcPriv = pOutput->crtc->driver_private; + if (pCrtcPriv->screen_rotate_degree > 0) + secCrtcEnableScreenRotate (pOutput->crtc, TRUE); + else + secCrtcEnableScreenRotate (pOutput->crtc, FALSE); + if (pCrtcPriv->bAccessibility || pCrtcPriv->screen_rotate_degree > 0) + { + tbm_bo src_bo = pCrtcPriv->front_bo; + tbm_bo dst_bo = pCrtcPriv->accessibility_back_bo; + if (!secCrtcExecAccessibility (pOutput->crtc, src_bo, dst_bo)) + { + XDBG_ERROR(MDPMS, "Fail execute accessibility(output name, %s)\n", + pOutput->name); + } + } + + /* set current fb to crtc */ + if(!secCrtcApply(pOutput->crtc)) + { + XDBG_ERROR(MDPMS, "Fail crtc apply(output name, %s)\n", + pOutput->name); + } + break; + case DPMSModeOff: + if (pOutputPriv->isLcdOff == TRUE) + { + drmModeFreeProperty (props); + return; + } + /* lcd off */ + XDBG_INFO (MDPMS, "\t Reqeust DPMS OFF (%s)\n", pOutput->name); + _tmp_dpms = DPMSModeOff; + pOutputPriv->isLcdOff = TRUE; + + secCrtcEnableScreenRotate (pOutput->crtc, FALSE); + + if (!strcmp(pOutput->name, "LVDS1")) + { + secVideoDpms (pOutput->scrn, FALSE); + secVirtualVideoDpms (pOutput->scrn, FALSE); + + pSec->isLcdOff = TRUE; + + if (pSec->resume_timer) + { + TimerFree (pSec->resume_timer); + drmModeFreeProperty (props); + pSec->resume_timer = NULL; + return; + } + + /* keep previous pSecMode's set_mode. */ + pSec->set_mode = secDisplayGetDispSetMode (pOutput->scrn); + + if (pSec->set_mode == DISPLAY_SET_MODE_CLONE) + { + /* stop wb if wb is working. */ + secDisplaySetDispSetMode (pOutput->scrn, DISPLAY_SET_MODE_OFF); + } + } + break; + default: + drmModeFreeProperty (props); + return; + } + + drmModeConnectorSetProperty(pSecMode->fd, + pOutputPriv->output_id, + props->prop_id, + _tmp_dpms); + + XDBG_INFO (MDPMS, "\t Success DPMS request (%s)\n", pOutput->name); + + pOutputPriv->dpms_mode = _tmp_dpms; + drmModeFreeProperty (props); + return; + } + + drmModeFreeProperty (props); + } +} + +static void +SECOutputCreateReaources(xf86OutputPtr pOutput) +{ + SECOutputPrivPtr pOutputPriv = pOutput->driver_private; + drmModeConnectorPtr mode_output = pOutputPriv->mode_output; + SECModePtr pSecMode = pOutputPriv->pSecMode; + int i, j, err; + + pOutputPriv->props = calloc (mode_output->count_props, sizeof (SECPropertyRec)); + if (!pOutputPriv->props) + return; + + pOutputPriv->num_props = 0; + for (i = j = 0; i < mode_output->count_props; i++) + { + drmModePropertyPtr drmmode_prop; + + drmmode_prop = drmModeGetProperty(pSecMode->fd, + mode_output->props[i]); + if (_secOutputPropertyIgnore(drmmode_prop)) + { + drmModeFreeProperty (drmmode_prop); + continue; + } + + pOutputPriv->props[j].mode_prop = drmmode_prop; + pOutputPriv->props[j].value = mode_output->prop_values[i]; + j++; + } + pOutputPriv->num_props = j; + + for (i = 0; i < pOutputPriv->num_props; i++) + { + SECPropertyPtr p = &pOutputPriv->props[i]; + drmModePropertyPtr drmmode_prop = p->mode_prop; + + if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) + { + INT32 range[2]; + + p->num_atoms = 1; + p->atoms = calloc (p->num_atoms, sizeof (Atom)); + if (!p->atoms) + continue; + + p->atoms[0] = MakeAtom (drmmode_prop->name, strlen (drmmode_prop->name), TRUE); + range[0] = drmmode_prop->values[0]; + range[1] = drmmode_prop->values[1]; + err = RRConfigureOutputProperty (pOutput->randr_output, p->atoms[0], + FALSE, TRUE, + drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, + 2, range); + if (err != 0) + { + xf86DrvMsg (pOutput->scrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + err = RRChangeOutputProperty (pOutput->randr_output, p->atoms[0], + XA_INTEGER, 32, PropModeReplace, 1, &p->value, FALSE, TRUE); + if (err != 0) + { + xf86DrvMsg (pOutput->scrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } + else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) + { + p->num_atoms = drmmode_prop->count_enums + 1; + p->atoms = calloc (p->num_atoms, sizeof (Atom)); + if (!p->atoms) + continue; + + p->atoms[0] = MakeAtom (drmmode_prop->name, strlen (drmmode_prop->name), TRUE); + for (j = 1; j <= drmmode_prop->count_enums; j++) + { + struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; + p->atoms[j] = MakeAtom (e->name, strlen (e->name), TRUE); + } + + err = RRConfigureOutputProperty (pOutput->randr_output, p->atoms[0], + FALSE, FALSE, + drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, + p->num_atoms - 1, (INT32*)&p->atoms[1]); + if (err != 0) + { + xf86DrvMsg (pOutput->scrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + + for (j = 0; j < drmmode_prop->count_enums; j++) + if (drmmode_prop->enums[j].value == p->value) + break; + /* there's always a matching value */ + err = RRChangeOutputProperty (pOutput->randr_output, p->atoms[0], + XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE); + if (err != 0) + { + xf86DrvMsg (pOutput->scrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } + + if (p->atoms) + free (p->atoms); + } +} + +static Bool +SECOutputSetProperty(xf86OutputPtr output, Atom property, + RRPropertyValuePtr value) +{ + SECOutputPrivPtr pOutputPriv = output->driver_private; + SECModePtr pSecMode = pOutputPriv->pSecMode; + int i; + + //SECOutputDpms(output, DPMSModeStandby); + + for (i = 0; i < pOutputPriv->num_props; i++) + { + SECPropertyPtr p = &pOutputPriv->props[i]; + + if (p->atoms[0] != property) + continue; + + if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) + { + uint32_t val; + + if (value->type != XA_INTEGER || value->format != 32 || + value->size != 1) + return FALSE; + val = *(uint32_t*)value->data; + + drmModeConnectorSetProperty (pSecMode->fd, pOutputPriv->output_id, + p->mode_prop->prop_id, (uint64_t) val); + return TRUE; + } + else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) + { + Atom atom; + const char *name; + int j; + + if (value->type != XA_ATOM || value->format != 32 || value->size != 1) + return FALSE; + memcpy (&atom, value->data, 4); + name = NameForAtom (atom); + XDBG_RETURN_VAL_IF_FAIL ((name != NULL), FALSE); + + /* search for matching name string, then set its value down */ + for (j = 0; j < p->mode_prop->count_enums; j++) + { + if (!strcmp (p->mode_prop->enums[j].name, name)) + { + drmModeConnectorSetProperty (pSecMode->fd, pOutputPriv->output_id, + p->mode_prop->prop_id, p->mode_prop->enums[j].value); + return TRUE; + } + } + return FALSE; + } + } + + /* We didn't recognise this property, just report success in order + * to allow the set to continue, otherwise we break setting of + * common properties like EDID. + */ + /* set the hidden properties : features for sec debugging*/ + /* TODO : xberc can works on only LVDS????? */ + if (pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_LVDS) + { + if (secPropSetLvdsFunc (output, property, value)) + return TRUE; + + if (secPropSetFbVisible (output, property, value)) + return TRUE; + + if (secPropSetVideoOffset (output, property, value)) + return TRUE; + + if (secPropSetScreenRotate (output, property, value)) + return TRUE; + + if (secXbercSetProperty (output, property, value)) + return TRUE; + } + /* set the hidden properties : features for driver specific funtions */ + if (pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_HDMIA || + pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_HDMIB || + pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_VIRTUAL) + { + /* set the property for the display mode */ + if (secPropSetDisplayMode(output, property, value)) + return TRUE; + } + + return TRUE; +} + +static Bool +SECOutputGetProperty(xf86OutputPtr pOutput, Atom property) +{ + return FALSE; +} + +static const xf86OutputFuncsRec sec_output_funcs = +{ + .create_resources = SECOutputCreateReaources, +#ifdef RANDR_12_INTERFACE + .set_property = SECOutputSetProperty, + .get_property = SECOutputGetProperty, +#endif + .dpms = SECOutputDpms, +#if 0 + .save = drmmode_crt_save, + .restore = drmmode_crt_restore, + .mode_fixup = drmmode_crt_mode_fixup, + .prepare = sec_output_prepare, + .mode_set = drmmode_crt_mode_set, + .commit = sec_output_commit, +#endif + .detect = SECOutputDetect, + .mode_valid = SECOutputModeValid, + + .get_modes = SECOutputGetModes, + .destroy = SECOutputDestory +}; + +Bool +secOutputDrmUpdate (ScrnInfoPtr pScrn) +{ + SECModePtr pSecMode = (SECModePtr) SECPTR (pScrn)->pSecMode; + Bool ret = TRUE; + int i; + + for (i = 0; i < pSecMode->mode_res->count_connectors; i++) + { + SECOutputPrivPtr pCur = NULL, pNext = NULL, pOutputPriv = NULL; + drmModeConnectorPtr koutput; + drmModeEncoderPtr kencoder; + char *conn_str[] = {"connected", "disconnected", "unknow"}; + + xorg_list_for_each_entry_safe (pCur, pNext, &pSecMode->outputs, link) + { + if (pCur->output_id == pSecMode->mode_res->connectors[i]) + { + pOutputPriv = pCur; + break; + } + } + + if (!pOutputPriv) + { + ret = FALSE; + break; + } + + koutput = drmModeGetConnector (pSecMode->fd, + pSecMode->mode_res->connectors[i]); + if (!koutput) + { + ret = FALSE; + break; + } + + kencoder = drmModeGetEncoder (pSecMode->fd, koutput->encoders[0]); + if (!kencoder) + { + drmModeFreeConnector (koutput); + ret = FALSE; + break; + } + + if (pOutputPriv->mode_output) + { + drmModeFreeConnector (pOutputPriv->mode_output); + pOutputPriv->mode_output = NULL; + } + pOutputPriv->mode_output = koutput; + + if (pOutputPriv->mode_encoder) + { + drmModeFreeEncoder (pOutputPriv->mode_encoder); + pOutputPriv->mode_encoder = NULL; + } + pOutputPriv->mode_encoder = kencoder; + + XDBG_INFO (MSEC, "drm update : connect(%d, type:%d, status:%s) encoder(%d) crtc(%d).\n", + pSecMode->mode_res->connectors[i], koutput->connector_type, + conn_str[pOutputPriv->mode_output->connection-1], + kencoder->encoder_id, kencoder->crtc_id); +#if 0 + /* Does these need to update? */ + pOutput->mm_width = koutput->mmWidth; + pOutput->mm_height = koutput->mmHeight; + + pOutput->possible_crtcs = kencoder->possible_crtcs; + pOutput->possible_clones = kencoder->possible_clones; +#endif + } + + if (!ret) + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "drm(output) update error. (%s)\n", strerror (errno)); + + return ret; +} + +void +secOutputInit (ScrnInfoPtr pScrn, SECModePtr pSecMode, int num) +{ + xf86OutputPtr pOutput; + drmModeConnectorPtr koutput; + drmModeEncoderPtr kencoder; + SECOutputPrivPtr pOutputPriv; + const char *output_name; + char name[32]; + + koutput = drmModeGetConnector (pSecMode->fd, + pSecMode->mode_res->connectors[num]); + if (!koutput) + return; + + kencoder = drmModeGetEncoder (pSecMode->fd, koutput->encoders[0]); + if (!kencoder) + { + drmModeFreeConnector (koutput); + return; + } + + if (koutput->connector_type < ARRAY_SIZE (output_names)) + output_name = output_names[koutput->connector_type]; + else + output_name = "UNKNOWN"; + snprintf (name, 32, "%s%d", output_name, koutput->connector_type_id); + + pOutput = xf86OutputCreate (pScrn, &sec_output_funcs, name); + if (!pOutput) + { + drmModeFreeEncoder (kencoder); + drmModeFreeConnector (koutput); + return; + } + + pOutputPriv = calloc (sizeof (SECOutputPrivRec), 1); + if (!pOutputPriv) + { + xf86OutputDestroy (pOutput); + drmModeFreeConnector (koutput); + drmModeFreeEncoder (kencoder); + return; + } + + pOutputPriv->output_id = pSecMode->mode_res->connectors[num]; + pOutputPriv->mode_output = koutput; + pOutputPriv->mode_encoder = kencoder; + pOutputPriv->pSecMode = pSecMode; + + pOutput->mm_width = koutput->mmWidth; + pOutput->mm_height = koutput->mmHeight; + + pOutput->subpixel_order = subpixel_conv_table[koutput->subpixel]; + pOutput->driver_private = pOutputPriv; + + pOutput->possible_crtcs = kencoder->possible_crtcs; + pOutput->possible_clones = kencoder->possible_clones; + pOutput->interlaceAllowed = TRUE; + + pOutputPriv->pOutput = pOutput; + /* TODO : soolim : management crtc privates */ + xorg_list_add(&pOutputPriv->link, &pSecMode->outputs); +} + +int +secOutputDpmsStatus(xf86OutputPtr pOutput) +{ + SECOutputPrivPtr pOutputPriv = pOutput->driver_private; + return pOutputPriv->dpms_mode; +} + +void +secOutputDpmsSet(xf86OutputPtr pOutput, int mode) +{ + SECOutputDpms(pOutput, mode); +} + +SECOutputPrivPtr +secOutputGetPrivateForConnType (ScrnInfoPtr pScrn, int connect_type) +{ + SECModePtr pSecMode = (SECModePtr) SECPTR (pScrn)->pSecMode; + int i; + + for (i = 0; i < pSecMode->mode_res->count_connectors; i++) + { + SECOutputPrivPtr pCur = NULL, pNext = NULL; + + xorg_list_for_each_entry_safe (pCur, pNext, &pSecMode->outputs, link) + { + drmModeConnectorPtr koutput = pCur->mode_output; + + if (koutput && koutput->connector_type == connect_type) + return pCur; + } + } + + XDBG_ERROR (MSEC, "no output for connect_type(%d) \n", connect_type); + + return NULL; +} diff --git a/src/crtcconfig/sec_output.h b/src/crtcconfig/sec_output.h new file mode 100644 index 0000000..7b9b107 --- /dev/null +++ b/src/crtcconfig/sec_output.h @@ -0,0 +1,65 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@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. + +**************************************************************************/ + +#ifndef __SEC_OUTPUT_H__ +#define __SEC_OUTPUT_H__ + +#include "sec_display.h" + +typedef struct _secOutputPriv +{ + SECModePtr pSecMode; + int output_id; + drmModeConnectorPtr mode_output; + drmModeEncoderPtr mode_encoder; + int num_props; + SECPropertyPtr props; + void *private_data; + + Bool isLcdOff; + int dpms_mode; + + int disp_mode; + + xf86OutputPtr pOutput; + struct xorg_list link; +} SECOutputPrivRec, *SECOutputPrivPtr; + + +void secOutputInit (ScrnInfoPtr pScrn, SECModePtr pSecMode, int num); +int secOutputDpmsStatus (xf86OutputPtr pOutput); +void secOutputDpmsSet (xf86OutputPtr pOutput, int mode); + +Bool secOutputDrmUpdate (ScrnInfoPtr pScrn); + +SECOutputPrivPtr secOutputGetPrivateForConnType (ScrnInfoPtr pScrn, int connect_type); + +#endif /* __SEC_OUTPUT_H__ */ + diff --git a/src/crtcconfig/sec_plane.c b/src/crtcconfig/sec_plane.c new file mode 100644 index 0000000..41384a6 --- /dev/null +++ b/src/crtcconfig/sec_plane.c @@ -0,0 +1,1334 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@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. + +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/ioctl.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <poll.h> + +#include <xorgVersion.h> +#include <tbm_bufmgr.h> +#include <xf86Crtc.h> +#include <xf86DDC.h> +#include <xf86cmap.h> +#include <list.h> +#include <X11/Xatom.h> +#include <X11/extensions/dpmsconst.h> +#include <sec.h> +#include <exynos_drm.h> + +#include "sec_crtc.h" +#include "sec_output.h" +#include "sec_util.h" +#include "sec_video_fourcc.h" +#include "sec_plane.h" +#include "fimg2d.h" + +/* HW restriction */ +#define MIN_WIDTH 32 + +enum +{ + PLANE_FB_TYPE_NONE, + PLANE_FB_TYPE_DEFAULT, + PLANE_FB_TYPE_BO, + PLANE_FB_TYPE_MAX +}; + +typedef struct _SECPlaneAccess +{ + unsigned int fb_id; + + tbm_bo bo; + + int width; + int height; + + xRectangle src; + xRectangle dst; +} SECPlaneAccess; + +/* This is structure to manage a added buffer. */ +typedef struct _SECPlaneFb +{ + unsigned int id; + + int type; + union + { + /* for framebuffer */ + tbm_bo bo; + SECVideoBuf *vbuf; + } buffer; + + int width; + int height; + + Bool buffer_gone; + + struct xorg_list link; +} SECPlaneFb; + +typedef struct _SECPlaneTable +{ + SECPlanePrivPtr pPlanePriv; + int plane_id; + + /* buffers which this plane has */ + struct xorg_list fbs; + SECPlaneFb *cur_fb; + + /* visibilitiy information */ + Bool visible; + int crtc_id; + int zpos; + xRectangle src; + xRectangle dst; + int conn_type; + + Bool onoff; + Bool in_use; + Bool freeze_update; + + /* accessibility */ + SECPlaneAccess *access; +} SECPlaneTable; + +/* table of planes which system has entirely */ +static SECPlaneTable *plane_table; +static int plane_table_size; + +static SECPlaneTable* _secPlaneTableFind (int plane_id); +static SECPlaneFb* _secPlaneTableFindBuffer (SECPlaneTable *table, int fb_id, + tbm_bo bo, SECVideoBuf *vbuf); +static Bool _secPlaneHideInternal (SECPlaneTable *table); + +static void +_secPlaneFreeVbuf (SECVideoBuf *vbuf, void *data) +{ + int plane_id = (int)data; + SECPlaneTable *table; + SECPlaneFb *fb; + + table = _secPlaneTableFind (plane_id); + XDBG_RETURN_IF_FAIL (table != NULL); + + fb = _secPlaneTableFindBuffer (table, vbuf->fb_id, NULL, NULL); + XDBG_RETURN_IF_FAIL (fb != NULL); + + fb->buffer_gone = TRUE; + secPlaneRemoveBuffer (plane_id, vbuf->fb_id); +} + +static SECPlaneTable* +_secPlaneTableFindPos (int crtc_id, int zpos) +{ + int i; + + XDBG_RETURN_VAL_IF_FAIL (crtc_id > 0, NULL); + + for (i = 0; i < plane_table_size; i++) + if (plane_table[i].crtc_id == crtc_id && plane_table[i].zpos == zpos) + return &plane_table[i]; + + return NULL; +} + +static SECPlaneTable* +_secPlaneTableFind (int plane_id) +{ + int i; + + XDBG_RETURN_VAL_IF_FAIL (plane_id > 0, NULL); + + for (i = 0; i < plane_table_size; i++) + if (plane_table[i].plane_id == plane_id) + return &plane_table[i]; + + XDBG_TRACE (MPLN, "plane(%d) not found. \n", plane_id); + + return NULL; +} + +static SECPlaneTable* +_secPlaneTableFindEmpty (void) +{ + int i; + + for (i = 0; i < plane_table_size; i++) + if (!plane_table[i].in_use) + return &plane_table[i]; + + return NULL; +} + +static SECPlaneFb* +_secPlaneTableFindBuffer (SECPlaneTable *table, + int fb_id, + tbm_bo bo, + SECVideoBuf *vbuf) +{ + SECPlaneFb *fb = NULL, *fb_next = NULL; + + xorg_list_for_each_entry_safe (fb, fb_next, &table->fbs, link) + { + if (fb_id > 0) + { + if (fb->id == fb_id) + return fb; + } + else if (bo) + { + if (fb->type == PLANE_FB_TYPE_BO && fb->buffer.bo == bo) + return fb; + } + else if (vbuf) + { + XDBG_RETURN_VAL_IF_FAIL (VBUF_IS_VALID (vbuf), NULL); + + if (fb->type == PLANE_FB_TYPE_DEFAULT) + if (fb->buffer.vbuf == vbuf && fb->buffer.vbuf->stamp == vbuf->stamp) + return fb; + } + } + + return NULL; +} + +static void +_secPlaneTableFreeBuffer (SECPlaneTable *table, SECPlaneFb *fb) +{ + if (table->cur_fb == fb) + return; + + if (fb->type == PLANE_FB_TYPE_BO) + { + if (fb->buffer.bo) + tbm_bo_unref (fb->buffer.bo); + } + else + { + if (!fb->buffer_gone && fb->buffer.vbuf) + secUtilRemoveFreeVideoBufferFunc (fb->buffer.vbuf, _secPlaneFreeVbuf, + (void*)table->plane_id); + } + + xorg_list_del (&fb->link); + + free (fb); +} + +static Bool +_secPlaneTableEnsure (ScrnInfoPtr pScrn, int count_planes) +{ + int i; + + XDBG_RETURN_VAL_IF_FAIL (count_planes > 0, FALSE); + + if (plane_table) + { + if (plane_table_size != count_planes) + XDBG_WARNING (MPLN, "%d != %d, need to re-create! \n", + plane_table_size, count_planes); + return TRUE; + } + + plane_table = calloc (sizeof (SECPlaneTable), count_planes); + XDBG_RETURN_VAL_IF_FAIL (plane_table != NULL, FALSE); + + plane_table_size = count_planes; + + for (i = 0; i < plane_table_size; i++) + { + SECPlaneTable *table = &plane_table[i]; + table->plane_id = -1; + table->onoff = TRUE; + } + + return TRUE; +} + +static void +_secPlaneExecAccessibility (tbm_bo src_bo, int sw, int sh, xRectangle *sr, + tbm_bo dst_bo, int dw, int dh, xRectangle *dr, + Bool bNegative) +{ + G2dImage *srcImg = NULL, *dstImg = NULL; + tbm_bo_handle src_bo_handle = {0,}; + tbm_bo_handle dst_bo_handle = {0,}; + G2dColorKeyMode mode; + + 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, sw * 4); + XDBG_GOTO_IF_FAIL (srcImg != NULL, access_done); + + dstImg = g2d_image_create_bo (mode, dw, dh, dst_bo_handle.s32, dw * 4); + XDBG_GOTO_IF_FAIL (dstImg != NULL, access_done); + + util_g2d_copy_with_scale (srcImg, dstImg, + (int)sr->x, (int)sr->y, sr->width, sr->height, + (int)dr->x, (int)dr->y, dr->width, dr->height, + (int)bNegative); + 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 Bool +_check_hw_restriction (ScrnInfoPtr pScrn, int crtc_id, int buf_w, + int src_x, int src_w, int dst_x, int dst_w, + int *new_src_x, int *new_src_w, + int *new_dst_x, int *new_dst_w) +{ + SECOutputPrivPtr pOutputPriv = secOutputGetPrivateForConnType (pScrn, DRM_MODE_CONNECTOR_LVDS); + SECModePtr pSecMode = (SECModePtr) SECPTR (pScrn)->pSecMode; + int max = pSecMode->main_lcd_mode.hdisplay; + int start, end, diff; + Bool virtual_screen; + + XDBG_RETURN_VAL_IF_FAIL (pOutputPriv != NULL, FALSE); + + if (pOutputPriv->mode_encoder->crtc_id != crtc_id) + return TRUE; + + if (buf_w < MIN_WIDTH || buf_w % 2) + { + XDBG_TRACE (MPLN, "hide: buf_w(%d) not 2's multiple or less than %d\n", + buf_w, MIN_WIDTH); + return FALSE; + } + + if (src_x > dst_x || ((dst_x - src_x) + buf_w) > max) + virtual_screen = TRUE; + else + virtual_screen = FALSE; + + start = (dst_x < 0) ? 0 : dst_x; + end = ((dst_x + dst_w) > max) ? max : (dst_x + dst_w); + + /* check window minimun width */ + if ((end - start) < MIN_WIDTH) + { + XDBG_TRACE (MPLN, "hide: %d than min size: buf_w(%d) src(%d,%d) dst(%d,%d), virt(%d) start(%d) end(%d)\n", + end-start, buf_w, src_x, src_w, dst_x, dst_w, + virtual_screen, start, end); + return FALSE; + } + + XDBG_DEBUG (MPLN, "buf_w(%d) src(%d,%d) dst(%d,%d), virt(%d) start(%d) end(%d)\n", + buf_w, src_x, src_w, dst_x, dst_w, virtual_screen, start, end); + + if (!virtual_screen) + { + /* Pagewidth of window (= 8 byte align / bytes-per-pixel ) */ + if ((end - start) % 2) + end--; + } + else + { + /* You should align the sum of PAGEWIDTH_F and OFFSIZE_F double-word (8 byte) boundary. */ + if (end % 2) + end--; + } + + *new_dst_x = start; + *new_dst_w = end - start; + *new_src_w = *new_dst_w; + diff = start - dst_x; + *new_src_x += diff; + + XDBG_RETURN_VAL_IF_FAIL (*new_src_w > 0, FALSE); + XDBG_RETURN_VAL_IF_FAIL (*new_dst_w > 0, FALSE); + + if (src_x != *new_src_x || src_w != *new_src_w || + dst_x != *new_dst_x || dst_w != *new_dst_w) + XDBG_TRACE (MPLN, " => buf_w(%d) src(%d,%d) dst(%d,%d), virt(%d) start(%d) end(%d)\n", + buf_w, *new_src_x, *new_src_w, *new_dst_x, *new_dst_w, virtual_screen, start, end); + + return TRUE; +} + +static Bool +_secPlaneShowInternal (SECPlaneTable *table, + SECPlaneFb *old_fb, SECPlaneFb *new_fb, + xRectangle *new_src, xRectangle *new_dst, int new_zpos, + Bool need_set_plane) +{ + SECPtr pSec; + SECModePtr pSecMode; + xRectangle old_src = table->src; + xRectangle old_dst = table->dst; + int old_zpos = table->zpos; + Bool change_zpos = FALSE; + tbm_bo_handle bo_handle; + + pSec = SECPTR (table->pPlanePriv->pScrn); + pSecMode = table->pPlanePriv->pSecMode; + + if (pSec->isLcdOff) + { + XDBG_TRACE (MPLN, "lcd off, can't show : plane(%d) crtc(%d) pos(%d). \n", + table->plane_id, table->crtc_id, new_zpos); + return FALSE; + } + + if (!table->onoff) + { + XDBG_TRACE (MPLN, "plane off, can't show : plane(%d) crtc(%d) pos(%d). \n", + table->plane_id, table->crtc_id, new_zpos); + return FALSE; + } + + /* should set zpos before doing drmModeSetPlane */ + if (new_zpos != old_zpos) + { + if (!secUtilSetDrmProperty (pSecMode, table->plane_id, DRM_MODE_OBJECT_PLANE, + "zpos", new_zpos)) + return FALSE; + + table->zpos = new_zpos; + change_zpos = TRUE; + + XDBG_TRACE (MPLN, "plane(%d) => crtc(%d) zpos(%d)\n", + table->plane_id, table->crtc_id, table->zpos); + } + + if (!table->visible || need_set_plane || + change_zpos || + (!old_fb || (old_fb != new_fb)) || + (memcmp (&old_src, new_src, sizeof (xRectangle))) || + (memcmp (&old_dst, new_dst, sizeof (xRectangle)))) + { + xf86CrtcConfigPtr pCrtcConfig = XF86_CRTC_CONFIG_PTR (table->pPlanePriv->pScrn); + SECCrtcPrivPtr pCrtcPriv = NULL; + int c; + + for (c = 0; c < pCrtcConfig->num_crtc; c++) + { + xf86CrtcPtr pCrtc = pCrtcConfig->crtc[c]; + SECCrtcPrivPtr pTemp = pCrtc->driver_private; + if (pTemp->mode_crtc && pTemp->mode_crtc->crtc_id == table->crtc_id) + { + pCrtcPriv = pTemp; + break; + } + } + + XDBG_RETURN_VAL_IF_FAIL (pCrtcPriv != NULL, FALSE); + + XDBG_TRACE (MPLN, "plane(%d) => crtc(%d) fb(%d) (%d,%d %dx%d) => (%d,%d %dx%d) [%d,%d,%c%c%c%c]\n", + table->plane_id, table->crtc_id, new_fb->id, + new_src->x, new_src->y, new_src->width, new_src->height, + new_dst->x, new_dst->y, new_dst->width, new_dst->height, + pCrtcPriv->bAccessibility, new_fb->type, + FOURCC_STR (new_fb->buffer.vbuf->id)); + + if (!pCrtcPriv->bAccessibility || + (new_fb->type == PLANE_FB_TYPE_DEFAULT && new_fb->buffer.vbuf->id != FOURCC_RGB32)) + { + int aligned_src_x = new_src->x; + int aligned_src_w = new_src->width; + int aligned_dst_x = new_dst->x; + int aligned_dst_w = new_dst->width; + + if (!_check_hw_restriction (table->pPlanePriv->pScrn, table->crtc_id, + table->cur_fb->width, + new_src->x, new_src->width, + new_dst->x, new_dst->width, + &aligned_src_x, &aligned_src_w, + &aligned_dst_x, &aligned_dst_w)) + { + XDBG_TRACE (MPLN, "out of range: plane(%d) crtc(%d) pos(%d) crtc(%d,%d %dx%d). \n", + table->plane_id, table->crtc_id, new_zpos, + aligned_dst_x, new_dst->y, aligned_dst_w, new_dst->height); + + _secPlaneHideInternal (table); + + return TRUE; + } + + /* Source values are 16.16 fixed point */ + uint32_t fixed_x = ((unsigned int)aligned_src_x) << 16; + uint32_t fixed_y = ((unsigned int)new_src->y) << 16; + uint32_t fixed_w = ((unsigned int)aligned_src_w) << 16; + uint32_t fixed_h = ((unsigned int)new_src->height) << 16; + + if (drmModeSetPlane (pSecMode->fd, table->plane_id, table->crtc_id, + new_fb->id, 0, + aligned_dst_x, new_dst->y, + aligned_dst_w, new_dst->height, + fixed_x, fixed_y, + fixed_w, fixed_h)) + { + XDBG_ERRNO (MPLN, "drmModeSetPlane failed. plane(%d) crtc(%d) pos(%d) on: fb(%d,%c%c%c%c,%dx%d,[%d,%d %dx%d]=>[%d,%d %dx%d])\n", + table->plane_id, table->crtc_id, table->zpos, + new_fb->id, FOURCC_STR (new_fb->buffer.vbuf->id), + new_fb->buffer.vbuf->width, new_fb->buffer.vbuf->height, + aligned_src_x, new_src->y, aligned_src_w, new_src->height, + aligned_dst_x, new_dst->y, aligned_dst_w, new_dst->height); + + return FALSE; + } + + if (!table->visible) + { + XDBG_SECURE (MPLN, "plane(%d) crtc(%d) pos(%d) on: fb(%d,%c%c%c%c,%dx%d,[%d,%d %dx%d]=>[%d,%d %dx%d])\n", + table->plane_id, table->crtc_id, table->zpos, + new_fb->id, FOURCC_STR (new_fb->buffer.vbuf->id), + new_fb->buffer.vbuf->width, new_fb->buffer.vbuf->height, + aligned_src_x, new_src->y, aligned_src_w, new_src->height, + aligned_dst_x, new_dst->y, aligned_dst_w, new_dst->height); + table->visible = TRUE; + } + } + else + { + SECPlaneAccess *access; + xRectangle fb_src = {0,}; + tbm_bo src_bo; + int old_w = 0, old_h = 0; + + if (!table->access) + { + table->access = calloc (1, sizeof (SECPlaneAccess)); + XDBG_RETURN_VAL_IF_FAIL (table->access != NULL, FALSE); + } + else + { + old_w = table->access->width; + old_h = table->access->height; + } + + access = table->access; + + if (pCrtcPriv->bScale) + { + float h_ratio = 0.0, v_ratio = 0.0; + xRectangle crop; + + h_ratio = (float)pCrtcPriv->kmode.hdisplay / pCrtcPriv->sw; + v_ratio = (float)pCrtcPriv->kmode.vdisplay / pCrtcPriv->sh; + + fb_src.x = new_src->x; + fb_src.y = new_src->y; + fb_src.width = new_src->width; + fb_src.height = new_src->height; + + CLEAR (crop); + crop.x = pCrtcPriv->sx; + crop.y = pCrtcPriv->sy; + crop.width = pCrtcPriv->sw; + crop.height = pCrtcPriv->sh; + + crop.x -= new_dst->x; + crop.y -= new_dst->y; + crop.x += new_src->x; + crop.y += new_src->y; + secUtilRectIntersect (&fb_src, &fb_src, &crop); + + access->dst = *new_dst; + + access->dst.x = new_dst->x; + access->dst.y = new_dst->y; + access->dst.width = new_dst->width; + access->dst.height = new_dst->height; + + CLEAR (crop); + crop.x = pCrtcPriv->sx; + crop.y = pCrtcPriv->sy; + crop.width = pCrtcPriv->sw; + crop.height = pCrtcPriv->sh; + secUtilRectIntersect (&access->dst, &access->dst, &crop); + + access->dst.x -= pCrtcPriv->sx; + access->dst.y -= pCrtcPriv->sy; + + access->dst.x *= h_ratio; + access->dst.y *= v_ratio; + access->dst.width *= h_ratio; + access->dst.height *= v_ratio; + + access->width = pCrtcPriv->kmode.hdisplay; + access->height = pCrtcPriv->kmode.vdisplay; + + access->src.x = 0; + access->src.y = 0; + access->src.width = access->dst.width; + access->src.height = access->dst.height; + } + else + { + fb_src.x = new_src->x; + fb_src.y = new_src->y; + fb_src.width = new_src->width; + fb_src.height = new_src->height; + + /* hw restriction: 8 bytes */ + new_dst->width &= ~1; + + access->dst.x = new_dst->x; + access->dst.y = new_dst->y; + access->dst.width = new_dst->width; + access->dst.height = new_dst->height; + + access->width = access->dst.width; + access->height = access->dst.height; + + access->src.x = 0; + access->src.y = 0; + access->src.width = access->dst.width; + access->src.height = access->dst.height; + } + + XDBG_DEBUG (MPLN, "access : accessibility_status(%d) scale(%d) bo(%p) fb(%d) (%d,%d %dx%d) (%dx%d) (%d,%d %dx%d) (%d,%d %dx%d).\n", + pCrtcPriv->accessibility_status, pCrtcPriv->bScale, + access->bo, access->fb_id, + fb_src.x, fb_src.y, fb_src.width, fb_src.height, + access->width, access->height, + access->src.x, access->src.y, access->src.width, access->src.height, + access->dst.x, access->dst.y, access->dst.width, access->dst.height); + + if (!fb_src.width || !fb_src.height || + !access->width || !access->height || + !access->dst.width || !access->dst.height) + { + _secPlaneHideInternal (table); + + return TRUE; + } + + if (access->bo) + { + if (old_w != access->width || old_h != access->height) + { + if (table->access->fb_id) + { + drmModeRmFB (pSecMode->fd, table->access->fb_id); + table->access->fb_id = 0; + } + + tbm_bo_unref (table->access->bo); + table->access->bo = NULL; + } + } + + if (!access->bo) + { + access->bo = tbm_bo_alloc (pSec->tbm_bufmgr, + access->width * access->height * 4, + TBM_BO_NONCACHABLE); + XDBG_RETURN_VAL_IF_FAIL (access->bo != NULL, FALSE); + + bo_handle = tbm_bo_get_handle (access->bo, TBM_DEVICE_DEFAULT); + if (drmModeAddFB (pSecMode->fd, access->width, access->height, + table->pPlanePriv->pScrn->depth, + table->pPlanePriv->pScrn->bitsPerPixel, + access->width * 4, + bo_handle.u32, + &access->fb_id)) + { + XDBG_ERRNO (MPLN, "drmModeAddFB failed. plane(%d)\n", table->plane_id); + return FALSE; + } + + XDBG_RETURN_VAL_IF_FAIL (access->fb_id > 0, FALSE); + } + + if (new_fb->type == PLANE_FB_TYPE_DEFAULT) + src_bo = new_fb->buffer.vbuf->bo[0]; + else + src_bo = new_fb->buffer.bo; + XDBG_RETURN_VAL_IF_FAIL (src_bo != NULL, FALSE); + + _secPlaneExecAccessibility (src_bo, new_fb->width, new_fb->height, &fb_src, + access->bo, access->width, access->height, &access->src, + pCrtcPriv->accessibility_status); + + int aligned_src_x = access->src.x; + int aligned_src_w = access->src.width; + int aligned_dst_x = access->dst.x; + int aligned_dst_w = access->dst.width; + + if (!_check_hw_restriction (table->pPlanePriv->pScrn, table->crtc_id, + access->width, + access->src.x, access->src.width, + access->dst.x, access->dst.width, + &aligned_src_x, &aligned_src_w, + &aligned_dst_x, &aligned_dst_w)) + { + XDBG_TRACE (MPLN, "out of range: plane(%d) crtc(%d) pos(%d) crtc(%d,%d %dx%d). \n", + table->plane_id, table->crtc_id, new_zpos, + aligned_dst_x, new_dst->y, aligned_dst_w, new_dst->height); + + _secPlaneHideInternal (table); + + return TRUE; + } + + /* Source values are 16.16 fixed point */ + uint32_t fixed_x = ((unsigned int)aligned_src_x) << 16; + uint32_t fixed_y = ((unsigned int)access->src.y) << 16; + uint32_t fixed_w = ((unsigned int)aligned_src_w) << 16; + uint32_t fixed_h = ((unsigned int)access->src.height) << 16; + + if (drmModeSetPlane (pSecMode->fd, table->plane_id, table->crtc_id, + access->fb_id, 0, + aligned_dst_x, access->dst.y, + aligned_dst_w, access->dst.height, + fixed_x, fixed_y, + fixed_w, fixed_h)) + { + XDBG_ERRNO (MPLN, "drmModeSetPlane failed. \n"); + + return FALSE; + } + + if (!table->visible) + { + XDBG_SECURE (MPLN, "plane(%d) crtc(%d) pos(%d) on: access_fb(%d,%dx%d,[%d,%d %dx%d]=>[%d,%d %dx%d])\n", + table->plane_id, table->crtc_id, table->zpos, + access->fb_id, access->width, access->height, + aligned_src_x, access->src.y, aligned_src_w, access->src.height, + aligned_dst_x, access->dst.y, aligned_dst_w, access->dst.height); + + table->visible = TRUE; + } + } + + memcpy (&table->src, new_src, sizeof (xRectangle)); + memcpy (&table->dst, new_dst, sizeof (xRectangle)); + } + + return TRUE; +} + +static Bool +_secPlaneHideInternal (SECPlaneTable *table) +{ + SECPtr pSec; + SECModePtr pSecMode; + + XDBG_RETURN_VAL_IF_FAIL (table != NULL, FALSE); + + if (!table->visible) + return TRUE; + + XDBG_RETURN_VAL_IF_FAIL (table->crtc_id > 0, FALSE); + + pSec = SECPTR (table->pPlanePriv->pScrn); + pSecMode = table->pPlanePriv->pSecMode; + + if (!pSec->isLcdOff && table->onoff) + { + if (drmModeSetPlane (pSecMode->fd, + table->plane_id, + table->crtc_id, + 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0)) + { + XDBG_ERRNO (MPLN, "drmModeSetPlane failed. plane(%d) crtc(%d) zpos(%d) fb(%d)\n", + table->plane_id, table->crtc_id, table->zpos, table->cur_fb->id); + + return FALSE; + } + } + + if (table->visible) + { + XDBG_SECURE (MPLN, "plane(%d) crtc(%d) zpos(%d) off. lcd(%s) onoff(%d)\n", + table->plane_id, table->crtc_id, table->zpos, + (pSec->isLcdOff)?"off":"on", table->onoff); + table->visible = FALSE; + } + + XDBG_TRACE (MPLN, "plane(%d) fb(%d) removed from crtc(%d) zpos(%d). LCD(%s) ONOFF(%s).\n", + table->plane_id, table->cur_fb->id, table->crtc_id, table->zpos, + (pSec->isLcdOff)?"OFF":"ON", (table->onoff)?"ON":"OFF"); + + return TRUE; + +} + +void +secPlaneInit (ScrnInfoPtr pScrn, SECModePtr pSecMode, int num) +{ + SECPlanePrivPtr pPlanePriv; + + XDBG_RETURN_IF_FAIL (pScrn != NULL); + XDBG_RETURN_IF_FAIL (pSecMode != NULL); + XDBG_RETURN_IF_FAIL (pSecMode->plane_res != NULL); + XDBG_RETURN_IF_FAIL (pSecMode->plane_res->count_planes > 0); + + if (!_secPlaneTableEnsure (pScrn, pSecMode->plane_res->count_planes)) + return; + + pPlanePriv = calloc (sizeof (SECPlanePrivRec), 1); + XDBG_RETURN_IF_FAIL (pPlanePriv != NULL); + + pPlanePriv->mode_plane = drmModeGetPlane (pSecMode->fd, + pSecMode->plane_res->planes[num]); + if (!pPlanePriv->mode_plane) + { + XDBG_ERRNO (MPLN, "drmModeGetPlane failed. plane(%d)\n", + pSecMode->plane_res->planes[num]); + + free (pPlanePriv); + return; + } + + pPlanePriv->pScrn = pScrn; + pPlanePriv->pSecMode = pSecMode; + pPlanePriv->plane_id = pPlanePriv->mode_plane->plane_id; + + plane_table[num].plane_id = pPlanePriv->plane_id; + plane_table[num].pPlanePriv = pPlanePriv; + xorg_list_init (&plane_table[num].fbs); + + xorg_list_add(&pPlanePriv->link, &pSecMode->planes); +} + +void +secPlaneDeinit (ScrnInfoPtr pScrn, SECPlanePrivPtr pPlanePriv) +{ + int i; + + XDBG_RETURN_IF_FAIL (pScrn != NULL); + XDBG_RETURN_IF_FAIL (pPlanePriv != NULL); + + secPlaneFreeId (pPlanePriv->plane_id); + drmModeFreePlane (pPlanePriv->mode_plane); + xorg_list_del (&pPlanePriv->link); + + for (i = 0; i < plane_table_size; i++) + if (plane_table[i].plane_id == pPlanePriv->plane_id) + { + plane_table[i].plane_id = -1; + break; + } + + free (pPlanePriv); + + if (plane_table) + { + for (i = 0; i < plane_table_size; i++) + if (plane_table[i].plane_id != -1) + return; + + free (plane_table); + plane_table = NULL; + plane_table_size = 0; + XDBG_TRACE (MPLN, "plane_table destroyed. %d\n", plane_table_size); + } +} + +void +secPlaneShowAll (int crtc_id) +{ + int i; + + XDBG_TRACE (MPLN, "crtc(%d) \n", crtc_id); + + for (i = 0; i < plane_table_size; i++) + { + SECPlaneTable *table = &plane_table[i]; + + if (!table || !table->in_use || !table->visible || !table->onoff) + continue; + + if (table->crtc_id != crtc_id) + continue; + + if (!_secPlaneShowInternal (table, table->cur_fb, table->cur_fb, + &table->src, &table->dst, table->zpos, TRUE)) + + { + XDBG_WARNING (MPLN, "_secPlaneShowInternal failed. \n"); + } + + XDBG_TRACE (MPLN, "plane(%d) crtc(%d) zpos(%d) on.\n", + table->plane_id, table->crtc_id, table->zpos); + } +} + +int +secPlaneGetID (void) +{ + SECPlaneTable *table = _secPlaneTableFindEmpty (); + + if (!table) + { + XDBG_ERROR (MPLN, "No avaliable plane ID. %d\n", -1); + return -1; + } + + table->in_use = TRUE; + table->onoff = TRUE; + + XDBG_TRACE (MPLN, "plane(%d). \n", table->plane_id); + + return table->plane_id; +} + +void +secPlaneFreeId (int plane_id) +{ + SECPlaneTable *table = _secPlaneTableFind (plane_id); + SECPlaneFb *fb = NULL, *fb_next = NULL; + + XDBG_RETURN_IF_FAIL (table != NULL); + + secPlaneHide (table->plane_id); + + table->visible = FALSE; + table->crtc_id = 0; + + table->zpos = 0; + memset (&table->src, 0x00, sizeof (xRectangle)); + memset (&table->dst, 0x00, sizeof (xRectangle)); + + table->cur_fb = NULL; + xorg_list_for_each_entry_safe (fb, fb_next, &table->fbs, link) + { + _secPlaneTableFreeBuffer (table, fb); + } + + if (table->access) + { + if (table->access->fb_id) + { + SECModePtr pSecMode = table->pPlanePriv->pSecMode; + if (pSecMode) + drmModeRmFB (pSecMode->fd, table->access->fb_id); + } + + if (table->access->bo) + tbm_bo_unref (table->access->bo); + + free (table->access); + table->access = NULL; + } + + table->in_use = FALSE; + table->onoff = TRUE; + + XDBG_TRACE (MPLN, "plane(%d).\n", table->plane_id); +} + +Bool +secPlaneTrun (int plane_id, Bool onoff, Bool user) +{ + SECPlaneTable *table = _secPlaneTableFind (plane_id); + SECPtr pSec; + + XDBG_RETURN_VAL_IF_FAIL (table != NULL, FALSE); + + pSec = SECPTR (table->pPlanePriv->pScrn); + + if (pSec->isLcdOff) + return TRUE; + + onoff = (onoff > 0) ? TRUE : FALSE; + + if (table->onoff == onoff) + return TRUE; + + if (onoff) + { + table->onoff = onoff; + + if (!table->visible) + { + if (!_secPlaneShowInternal (table, table->cur_fb, table->cur_fb, + &table->src, &table->dst, table->zpos, TRUE)) + + { + XDBG_WARNING (MPLN, "_secPlaneShowInternal failed. \n"); + } + + XDBG_DEBUG (MPLN, "%s >> plane(%d,%d,%d) '%s'. \n", (user)?"user":"Xorg", + plane_id, table->crtc_id, table->zpos, (onoff)?"ON":"OFF"); + } + } + else + { + if (table->visible) + { + if (!_secPlaneHideInternal (table)) + + { + XDBG_WARNING (MPLN, "_secPlaneHideInternal failed. \n"); + } + + XDBG_DEBUG (MPLN, "%s >> plane(%d,%d,%d) '%s'. \n", (user)?"user":"Xorg", + plane_id, table->crtc_id, table->zpos, (onoff)?"ON":"OFF"); + } + + table->onoff = onoff; + } + + return TRUE; +} + +Bool +secPlaneTrunStatus (int plane_id) +{ + SECPlaneTable *table = _secPlaneTableFind (plane_id); + + XDBG_RETURN_VAL_IF_FAIL (table != NULL, FALSE); + + return table->onoff; +} + +void +secPlaneFreezeUpdate (int plane_id, Bool enable) +{ + SECPlaneTable *table = _secPlaneTableFind (plane_id); + + XDBG_RETURN_IF_FAIL (table != NULL); + + table->freeze_update = enable; +} + +Bool +secPlaneRemoveBuffer (int plane_id, int fb_id) +{ + SECPlaneTable *table; + SECPlaneFb *fb; + + XDBG_RETURN_VAL_IF_FAIL (fb_id > 0, FALSE); + + table = _secPlaneTableFind (plane_id); + XDBG_RETURN_VAL_IF_FAIL (table != NULL, FALSE); + + fb = _secPlaneTableFindBuffer (table, fb_id, NULL, NULL); + XDBG_RETURN_VAL_IF_FAIL (fb != NULL, FALSE); + + _secPlaneTableFreeBuffer (table, fb); + + XDBG_TRACE (MPLN, "plane(%d) fb(%d). \n", plane_id, fb_id); + + return TRUE; +} + +int +secPlaneAddBo (int plane_id, tbm_bo bo) +{ + SECPlaneTable *table; + SECPlaneFb *fb; + int fb_id = 0; + SECFbBoDataPtr bo_data = NULL; + int width, height; + + XDBG_RETURN_VAL_IF_FAIL (bo != NULL, 0); + + table = _secPlaneTableFind (plane_id); + XDBG_RETURN_VAL_IF_FAIL (table != NULL, 0); + + fb = _secPlaneTableFindBuffer (table, 0, bo, NULL); + XDBG_RETURN_VAL_IF_FAIL (fb == NULL, 0); + + tbm_bo_get_user_data (bo, TBM_BO_DATA_FB, (void**)&bo_data); + XDBG_RETURN_VAL_IF_FAIL (bo_data != NULL, 0); + + fb_id = bo_data->fb_id; + width = bo_data->pos.x2 - bo_data->pos.x1; + height = bo_data->pos.y2 - bo_data->pos.y1; + + XDBG_RETURN_VAL_IF_FAIL (fb_id > 0, 0); + XDBG_RETURN_VAL_IF_FAIL (width > 0, 0); + XDBG_RETURN_VAL_IF_FAIL (height > 0, 0); + + fb = calloc (1, sizeof (SECPlaneFb)); + XDBG_RETURN_VAL_IF_FAIL (fb != NULL, 0); + + xorg_list_add(&fb->link, &table->fbs); + + fb->type = PLANE_FB_TYPE_BO; + fb->id = fb_id; + fb->width = width; + fb->height = height; + + fb->buffer.bo = tbm_bo_ref (bo); + + XDBG_TRACE (MPLN, "plane(%d) bo(%d,%dx%d)\n", plane_id, + fb_id, fb->width, fb->height); + + return fb->id; +} + +int +secPlaneAddBuffer (int plane_id, SECVideoBuf *vbuf) +{ + SECPlaneTable *table; + SECPlaneFb *fb; + + XDBG_RETURN_VAL_IF_FAIL (VBUF_IS_VALID (vbuf), 0); + XDBG_RETURN_VAL_IF_FAIL (vbuf->fb_id > 0, 0); + XDBG_RETURN_VAL_IF_FAIL (vbuf->width > 0, 0); + XDBG_RETURN_VAL_IF_FAIL (vbuf->height > 0, 0); + + table = _secPlaneTableFind (plane_id); + XDBG_RETURN_VAL_IF_FAIL (table != NULL, 0); + + fb = _secPlaneTableFindBuffer (table, 0, NULL, vbuf); + XDBG_RETURN_VAL_IF_FAIL (fb == NULL, 0); + + fb = calloc (1, sizeof (SECPlaneFb)); + XDBG_RETURN_VAL_IF_FAIL (fb != NULL, 0); + + xorg_list_add(&fb->link, &table->fbs); + + fb->type = PLANE_FB_TYPE_DEFAULT; + fb->id = vbuf->fb_id; + fb->width = vbuf->width; + fb->height = vbuf->height; + + fb->buffer.vbuf = vbuf; + + secUtilAddFreeVideoBufferFunc (vbuf, _secPlaneFreeVbuf, (void*)plane_id); + + XDBG_TRACE (MPLN, "plane(%d) vbuf(%ld,%d,%dx%d)\n", plane_id, + vbuf->stamp, vbuf->fb_id, vbuf->width, vbuf->height); + + return fb->id; +} + +int +secPlaneGetBuffer (int plane_id, tbm_bo bo, SECVideoBuf *vbuf) +{ + SECPlaneTable *table; + SECPlaneFb *fb; + + table = _secPlaneTableFind (plane_id); + XDBG_RETURN_VAL_IF_FAIL (table != NULL, 0); + + fb = _secPlaneTableFindBuffer (table, 0, bo, vbuf); + if (!fb) + return 0; + + return fb->id; +} + +void +secPlaneGetBufferSize (int plane_id, int fb_id, int *width, int *height) +{ + SECPlaneTable *table; + SECPlaneFb *fb; + + table = _secPlaneTableFind (plane_id); + XDBG_RETURN_IF_FAIL (table != NULL); + + fb = _secPlaneTableFindBuffer (table, fb_id, NULL, NULL); + XDBG_RETURN_IF_FAIL (fb != NULL); + + if (width) + *width = fb->width; + + if (height) + *height = fb->height; +} + +Bool +secPlaneAttach (int plane_id, int fb_id) +{ + SECPlaneTable *table = _secPlaneTableFind (plane_id); + SECPlaneFb *fb; + + XDBG_RETURN_VAL_IF_FAIL (table != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (fb_id > 0, FALSE); + + fb = _secPlaneTableFindBuffer (table, fb_id, NULL, NULL); + XDBG_RETURN_VAL_IF_FAIL (fb != NULL, FALSE); + + table->cur_fb = fb; + + XDBG_DEBUG (MPLN, "plane(%d) fb(%d)\n", plane_id, fb_id); + + return TRUE; +} + +Bool +secPlaneIsVisible (int plane_id) +{ + SECPlaneTable *table = _secPlaneTableFind (plane_id); + + XDBG_RETURN_VAL_IF_FAIL (table != NULL, FALSE); + + return table->visible; +} + +Bool +secPlaneShow (int plane_id, int crtc_id, + int src_x, int src_y, int src_w, int src_h, + int dst_x, int dst_y, int dst_w, int dst_h, + int zpos, Bool need_update) +{ + SECPlaneTable *table = _secPlaneTableFind (plane_id); + SECPlaneTable *temp; + xRectangle src = {src_x, src_y, src_w, src_h}; + xRectangle dst = {dst_x, dst_y, dst_w, dst_h}; + + XDBG_RETURN_VAL_IF_FAIL (table != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (table->cur_fb != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (crtc_id > 0, FALSE); + XDBG_RETURN_VAL_IF_FAIL (zpos >= 0, FALSE); + + temp = _secPlaneTableFindPos (crtc_id, zpos); + + if (temp && temp->plane_id != plane_id) + { + XDBG_ERROR (MPLN, "can't change zpos. plane(%d) is at zpos(%d) crtc(%d) \n", + temp->plane_id, temp->zpos, crtc_id); + return FALSE; + } + + if (!table->visible) + table->crtc_id = crtc_id; + else if (table->crtc_id != crtc_id) + { + XDBG_ERROR (MPLN, "can't change crtc. plane(%d) is on crtc(%d) \n", + table->plane_id, table->zpos); + return FALSE; + } + + if (!_secPlaneShowInternal (table, table->cur_fb, table->cur_fb, + &src, &dst, zpos, need_update)) + { + return FALSE; + } + + return TRUE; +} + +Bool +secPlaneHide (int plane_id) +{ + SECPlaneTable *table = _secPlaneTableFind (plane_id); + + XDBG_RETURN_VAL_IF_FAIL (table != NULL, FALSE); + + if (!table->visible) + return TRUE; + + XDBG_TRACE (MPLN, "plane(%d) crtc(%d)\n", table->plane_id, table->crtc_id); + + _secPlaneHideInternal (table); + + return TRUE; +} + +Bool +secPlaneMove (int plane_id, int x, int y) +{ + SECPlaneTable *table = _secPlaneTableFind (plane_id); + xRectangle dst; + + XDBG_RETURN_VAL_IF_FAIL (table != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (table->cur_fb != NULL, FALSE); + + dst.x = x; + dst.y = y; + dst.width = table->dst.width; + dst.height = table->dst.height; + + if (table->visible && !table->freeze_update) + if (!_secPlaneShowInternal (table, table->cur_fb, table->cur_fb, + &table->src, &dst, table->zpos, FALSE)) + { + return FALSE; + } + + XDBG_TRACE (MPLN, "plane(%d) moved to (%d,%d)\n", table->plane_id, x, y); + + return TRUE; +} + +char* +secPlaneDump (char *reply, int *len) +{ + Bool in_use = FALSE; + int i; + + for (i = 0; i < plane_table_size; i++) + if (plane_table[i].in_use) + { + in_use = TRUE; + break; + } + + if (!in_use) + return reply; + + XDBG_REPLY ("=================================================\n"); + XDBG_REPLY ("plane\tcrtc\tpos\tvisible\tonoff\tfb(w,h)\tsrc\t\tdst\n"); + + for (i = 0; i < plane_table_size; i++) + { + if (plane_table[i].in_use) + XDBG_REPLY ("%d\t%d\t%d\t%d\t%d\t%d(%dx%d)\t%d,%d %dx%d\t%d,%d %dx%d\n", + plane_table[i].plane_id, + plane_table[i].crtc_id, plane_table[i].zpos, + plane_table[i].visible, + plane_table[i].onoff, + (plane_table[i].cur_fb)?plane_table[i].cur_fb->id:0, + (plane_table[i].cur_fb)?plane_table[i].cur_fb->width:0, + (plane_table[i].cur_fb)?plane_table[i].cur_fb->height:0, + plane_table[i].src.x, plane_table[i].src.y, + plane_table[i].src.width, plane_table[i].src.height, + plane_table[i].dst.x, plane_table[i].dst.y, + plane_table[i].dst.width, plane_table[i].dst.height); + } + + XDBG_REPLY ("=================================================\n"); + + return reply; +} diff --git a/src/crtcconfig/sec_plane.h b/src/crtcconfig/sec_plane.h new file mode 100644 index 0000000..5ce2fd1 --- /dev/null +++ b/src/crtcconfig/sec_plane.h @@ -0,0 +1,84 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@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. + +**************************************************************************/ + +#ifndef __SEC_PLANE_H__ +#define __SEC_PLANE_H__ + +#include "sec_display.h" + +#define PLANE_POS_0 0 +#define PLANE_POS_1 1 +#define PLANE_POS_2 2 +#define PLANE_POS_3 3 +#define PLANE_POS_4 4 + +typedef struct _SECPlanePriv +{ + ScrnInfoPtr pScrn; + SECModePtr pSecMode; + drmModePlanePtr mode_plane; + + int plane_id; + + struct xorg_list link; +} SECPlanePrivRec, *SECPlanePrivPtr; + +void secPlaneInit (ScrnInfoPtr pScrn, SECModePtr pSecMode, int num); +void secPlaneDeinit (ScrnInfoPtr pScrn, SECPlanePrivPtr pPlanePriv); + +void secPlaneShowAll (int crtc_id); +int secPlaneGetID (void); +void secPlaneFreeId (int plane_id); +Bool secPlaneTrun (int plane_id, Bool onoff, Bool user); +Bool secPlaneTrunStatus (int plane_id); +void secPlaneFreezeUpdate (int plane_id, Bool enable); + +Bool secPlaneRemoveBuffer (int plane_id, int fb_id); +int secPlaneAddBo (int plane_id, tbm_bo bo); +int secPlaneAddBuffer (int plane_id, SECVideoBuf *vbuf); + +int secPlaneGetBuffer (int plane_id, tbm_bo bo, SECVideoBuf *vbuf); +void secPlaneGetBufferSize (int plane_id, int fb_id, int *width, int *height); + +Bool secPlaneAttach (int plane_id, int fb_id); + +Bool secPlaneIsVisible (int plane_id); +Bool secPlaneHide (int plane_id); +Bool secPlaneShow (int plane_id, int crtc_id, + int src_x, int src_y, int src_w, int src_h, + int dst_x, int dst_y, int dst_w, int dst_h, + int zpos, Bool need_update); + +Bool secPlaneMove (int plane_id, int x, int y); + +/* for debug */ +char* secPlaneDump (char *reply, int *len); + +#endif /* __SEC_PLANE_H__ */ diff --git a/src/crtcconfig/sec_prop.c b/src/crtcconfig/sec_prop.c new file mode 100755 index 0000000..9cf1904 --- /dev/null +++ b/src/crtcconfig/sec_prop.c @@ -0,0 +1,713 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@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. + +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdint.h> +#include <string.h> + +#include "sec.h" +#include "sec_display.h" +#include "sec_output.h" +#include "sec_crtc.h" +#include "sec_prop.h" +#include "sec_util.h" +#include <exynos_drm.h> +#include <sys/ioctl.h> + +#define STR_XRR_DISPLAY_MODE_PROPERTY "XRR_PROPERTY_DISPLAY_MODE" +#define STR_XRR_LVDS_FUNCTION "XRR_PROPERTY_LVDS_FUNCTION" +#define STR_XRR_FB_VISIBLE_PROPERTY "XRR_PROPERTY_FB_VISIBLE" +#define STR_XRR_VIDEO_OFFSET_PROPERTY "XRR_PROPERTY_VIDEO_OFFSET" +#define STR_XRR_PROPERTY_SCREEN_ROTATE "XRR_PROPERTY_SCREEN_ROTATE" + +#define PROP_VERIFY_RR_MODE(id, ptr, a)\ + {\ + int rc = dixLookupResourceByType((pointer *)&(ptr), id,\ + RRModeType, serverClient, a);\ + if (rc != Success) {\ + serverClient->errorValue = id;\ + return 0;\ + }\ + } + + +#define FLAG_BITS (RR_HSyncPositive | \ + RR_HSyncNegative | \ + RR_VSyncPositive | \ + RR_VSyncNegative | \ + RR_Interlace | \ + RR_DoubleScan | \ + RR_CSync | \ + RR_CSyncPositive | \ + RR_CSyncNegative | \ + RR_HSkewPresent | \ + RR_BCast | \ + RR_PixelMultiplex | \ + RR_DoubleClock | \ + RR_ClockDivideBy2) + +static Bool g_display_mode_prop_init = FALSE; +static Bool g_lvds_func_prop_init = FALSE; +static Bool g_fb_visible_prop_init = FALSE; +static Bool g_video_offset_prop_init = FALSE; +static Bool g_screen_rotate_prop_init = FALSE; + +static Atom xrr_property_display_mode_atom; +static Atom xrr_property_lvds_func_atom; +static Atom xrr_property_fb_visible_atom; +static Atom xrr_property_video_offset_atom; +static Atom xrr_property_screen_rotate_atom; + +typedef enum +{ + XRR_OUTPUT_DISPLAY_MODE_NULL, + XRR_OUTPUT_DISPLAY_MODE_WB_CLONE, + XRR_OUTPUT_DISPLAY_MODE_VIDEO_ONLY, +} XRROutputPropDisplayMode; + +typedef enum +{ + XRR_OUTPUT_LVDS_FUNC_NULL, + XRR_OUTPUT_LVDS_FUNC_INIT_VIRTUAL, + XRR_OUTPUT_LVDS_FUNC_HIBERNATION, + XRR_OUTPUT_LVDS_FUNC_ACCESSIBILITY, +} XRROutputPropLvdsFunc; + +/* + * Convert a RandR mode to a DisplayMode + */ +static void +_RRModeConvertToDisplayMode (ScrnInfoPtr scrn, + RRModePtr randr_mode, + DisplayModePtr mode) +{ + memset(mode, 0, sizeof(DisplayModeRec)); + mode->status = MODE_OK; + + mode->Clock = randr_mode->mode.dotClock / 1000; + + mode->HDisplay = randr_mode->mode.width; + mode->HSyncStart = randr_mode->mode.hSyncStart; + mode->HSyncEnd = randr_mode->mode.hSyncEnd; + mode->HTotal = randr_mode->mode.hTotal; + mode->HSkew = randr_mode->mode.hSkew; + + mode->VDisplay = randr_mode->mode.height; + mode->VSyncStart = randr_mode->mode.vSyncStart; + mode->VSyncEnd = randr_mode->mode.vSyncEnd; + mode->VTotal = randr_mode->mode.vTotal; + mode->VScan = 0; + + mode->Flags = randr_mode->mode.modeFlags & FLAG_BITS; + + xf86SetModeCrtc (mode, scrn->adjustFlags); +} + + +static int +_secPropUnsetCrtc (xf86OutputPtr pOutput) +{ + if (!pOutput->crtc) + return 1; + + ScrnInfoPtr pScrn = pOutput->scrn; + SECOutputPrivPtr pOutputPriv = pOutput->driver_private; + SECModePtr pSecMode = pOutputPriv->pSecMode; + + pSecMode->unset_connector_type = pOutputPriv->mode_output->connector_type; + RRGetInfo (pScrn->pScreen, TRUE); + pSecMode->unset_connector_type = 0; + RRGetInfo (pScrn->pScreen, TRUE); + + return 1; +} + +static int +_secPropSetWbClone (xf86OutputPtr pOutput, int mode_xid) +{ + SECOutputPrivPtr pOutputPriv = pOutput->driver_private; + SECModePtr pSecMode = pOutputPriv->pSecMode; + RRModePtr pRRMode; + DisplayModeRec mode; + + /* find kmode and set the external default mode */ + PROP_VERIFY_RR_MODE (mode_xid, pRRMode, DixSetAttrAccess); + _RRModeConvertToDisplayMode (pOutput->scrn, pRRMode, &mode); + secDisplayModeToKmode (pOutput->scrn, &pSecMode->ext_connector_mode, &mode); + + if (pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_HDMIA || + pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_HDMIB) + { + secDisplaySetDispConnMode (pOutput->scrn, DISPLAY_CONN_MODE_HDMI); + _secPropUnsetCrtc (pOutput); + } + else if (pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_VIRTUAL) + { + secDisplaySetDispConnMode (pOutput->scrn, DISPLAY_CONN_MODE_VIRTUAL); + _secPropUnsetCrtc (pOutput); + } + else + { + XDBG_WARNING (MDISP, "(WB_CLONE) Not suuport for this connecotor type\n"); + return 0; + } + + if(!secDisplaySetDispSetMode (pOutput->scrn, DISPLAY_SET_MODE_CLONE)) + { + return 0; + } + + return 1; +} + +static void +_secPropUnSetWbClone (xf86OutputPtr pOutput) +{ + secDisplaySetDispSetMode (pOutput->scrn, DISPLAY_SET_MODE_OFF); + secDisplaySetDispConnMode (pOutput->scrn, DISPLAY_CONN_MODE_NONE); +} + +Bool +secPropSetDisplayMode (xf86OutputPtr pOutput, Atom property, RRPropertyValuePtr value) +{ + XDBG_RETURN_VAL_IF_FAIL(value, FALSE); + XDBG_TRACE (MPROP, "%s\n", __FUNCTION__); + + XRROutputPropDisplayMode disp_mode = XRR_OUTPUT_DISPLAY_MODE_NULL; + SECOutputPrivPtr pOutputPriv; + + if (g_display_mode_prop_init == FALSE) + { + xrr_property_display_mode_atom = MakeAtom (STR_XRR_DISPLAY_MODE_PROPERTY, strlen (STR_XRR_DISPLAY_MODE_PROPERTY), TRUE); + g_display_mode_prop_init = TRUE; + } + + if (xrr_property_display_mode_atom != property) + { + //ErrorF ("[Display_mode]: Unrecognized property name.\n"); + return FALSE; + } + + if (!value->data || value->size == 0) + { + //ErrorF ("[Display_mode]: Unrecognized property value.\n"); + return TRUE; + } + + XDBG_DEBUG (MDISP, "output_name=%s, data=%d size=%ld\n", pOutput->name, *(int *)value->data, value->size); + + disp_mode = *(int *)value->data; + + if (disp_mode == XRR_OUTPUT_DISPLAY_MODE_NULL) + return TRUE; + + XDBG_DEBUG (MDISP, "output_name=%s, disp_mode=%d\n", pOutput->name, disp_mode); + + pOutputPriv = pOutput->driver_private; + + int mode_xid; + switch (disp_mode) + { + case XRR_OUTPUT_DISPLAY_MODE_WB_CLONE: + mode_xid = *((int *)value->data+1); + XDBG_INFO (MDISP, "[DISPLAY_MODE]: Set WriteBack Clone\n"); + _secPropSetWbClone (pOutput, mode_xid); + pOutputPriv->disp_mode = disp_mode; + break; + default: + break; + } + + return TRUE; +} + +void +secPropUnSetDisplayMode (xf86OutputPtr pOutput) +{ + XRROutputPropDisplayMode disp_mode; + SECOutputPrivPtr pOutputPriv; + + pOutputPriv = pOutput->driver_private; + disp_mode = pOutputPriv->disp_mode; + + if (disp_mode == XRR_OUTPUT_DISPLAY_MODE_NULL) + return; + + /* check the private and unset the diplaymode */ + switch (disp_mode) + { + case XRR_OUTPUT_DISPLAY_MODE_WB_CLONE: + XDBG_INFO (MDISP, "[DISPLAY_MODE]: UnSet WriteBack Clone\n"); + _secPropUnSetWbClone (pOutput); + break; + default: + break; + } + + pOutputPriv->disp_mode = XRR_OUTPUT_DISPLAY_MODE_NULL; +} + +static const char fake_edid_info[] = { + /* fill the edid information */ +}; + +static void +_secPropSetVirtual (xf86OutputPtr pOutput, int sc_conn) +{ + SECPtr pSec = SECPTR (pOutput->scrn); + int fd = pSec->drm_fd; + + struct drm_exynos_vidi_connection vidi; + + if (sc_conn == 1) + { + vidi.connection = 1; + vidi.extensions = 1; + vidi.edid = (uint64_t *)fake_edid_info; + } + else if (sc_conn == 2) + { + vidi.connection = 0; + } + else + { + XDBG_WARNING (MDISP, "Warning : wrong virtual connection command\n"); + return; + } + + ioctl (fd, DRM_IOCTL_EXYNOS_VIDI_CONNECTION, &vidi); +} + +Bool +secPropSetLvdsFunc (xf86OutputPtr pOutput, Atom property, RRPropertyValuePtr value) +{ + XDBG_TRACE (MPROP, "%s\n", __FUNCTION__); + XDBG_RETURN_VAL_IF_FAIL(value, FALSE); + + XRROutputPropLvdsFunc lvds_func = XRR_OUTPUT_LVDS_FUNC_NULL; + + if (g_lvds_func_prop_init == FALSE) + { + xrr_property_lvds_func_atom = MakeAtom (STR_XRR_LVDS_FUNCTION, strlen (STR_XRR_LVDS_FUNCTION), TRUE); + g_lvds_func_prop_init = TRUE; + } + + if (xrr_property_lvds_func_atom != property) + { + return FALSE; + } + + if (!value->data || value->size == 0) + { + //ErrorF ("[Display_mode]: Unrecognized property value.\n"); + return TRUE; + } + + XDBG_DEBUG (MDISP, "output_name=%s, data=%d size=%ld\n", pOutput->name, *(int *)value->data, value->size); + + lvds_func = *(int *)value->data; + + if (lvds_func == XRR_OUTPUT_LVDS_FUNC_NULL) + return TRUE; + + XDBG_DEBUG (MDISP, "output_name=%s, lvds_func=%d\n", pOutput->name, lvds_func); + + int sc_conn; + switch (lvds_func) + { + case XRR_OUTPUT_LVDS_FUNC_INIT_VIRTUAL: + sc_conn = *((int *)value->data+1); + XDBG_INFO (MDISP, "[LVDS_FUNC]: set virtual output (%d)\n", sc_conn); + _secPropSetVirtual (pOutput, sc_conn); + break; + case XRR_OUTPUT_LVDS_FUNC_HIBERNATION: + XDBG_INFO (MDISP, "[LVDS_FUNC]: set hibernationn\n"); + break; + case XRR_OUTPUT_LVDS_FUNC_ACCESSIBILITY: + XDBG_INFO (MDISP, "[LVDS_FUNC]: set accessibility\n"); + break; + default: + break; + } + + return TRUE; +} + +void +secPropUnSetLvdsFunc (xf86OutputPtr pOutput) +{ + +} + +static void +_secPropReturnProperty (RRPropertyValuePtr value, const char * f, ...) +{ + int len; + va_list args; + char buf[1024]; + + if (value->data) + { + free (value->data); + value->data = NULL; + } + va_start (args, f); + len = vsnprintf (buf, sizeof(buf), f, args) + 1; + va_end (args); + + value->data = calloc (1, len); + value->format = 8; + value->size = len; + + if (value->data) + strncpy (value->data, buf, len-1); +} + +Bool secPropFbVisible (char *cmd, Bool always, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + int output = 0; + int pos = 0; + Bool onoff = FALSE; + char str[128]; + char *p; + SECLayer *layer; + SECLayerPos lpos; + + XDBG_RETURN_VAL_IF_FAIL (cmd != NULL, FALSE); + + snprintf (str, sizeof(str), "%s", cmd); + + p = strtok (str, ":"); + XDBG_RETURN_VAL_IF_FAIL (p != NULL, FALSE); + output = atoi (p); + + p = strtok (NULL, ":"); + XDBG_RETURN_VAL_IF_FAIL (p != NULL, FALSE); + pos = atoi (p); + + if (output == LAYER_OUTPUT_LCD) + lpos = pos - 3; + else + lpos = pos - 1; + + p = strtok (NULL, ":"); + if (!p) + { + _secPropReturnProperty (value, "%d", 0); + + if (lpos != 0) + { + layer = secLayerFind ((SECLayerOutput)output, lpos); + if (layer) + _secPropReturnProperty (value, "%d", secLayerTurnStatus (layer)); + } + else + { + xf86CrtcConfigPtr pCrtcConfig; + int i; + + pCrtcConfig = XF86_CRTC_CONFIG_PTR (scrn); + if (!pCrtcConfig) + return FALSE; + + for (i = 0; i < pCrtcConfig->num_output; i++) + { + xf86OutputPtr pOutput = pCrtcConfig->output[i]; + SECOutputPrivPtr pOutputPriv = pOutput->driver_private; + + if ((output == LAYER_OUTPUT_LCD && + (pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_LVDS || + pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_Unknown)) || + (output == LAYER_OUTPUT_EXT && + (pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_HDMIA || + pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_HDMIB || + pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_VIRTUAL))) + { + if (pOutput->crtc) + { + SECCrtcPrivPtr pCrtcPriv = pOutput->crtc->driver_private; + _secPropReturnProperty (value, "%d", pCrtcPriv->onoff); + } + break; + } + } + } + + return TRUE; + } + onoff = atoi (p); + + if (lpos != 0) + { + if (!always) + if (output == LAYER_OUTPUT_LCD && lpos == LAYER_UPPER) + { + xf86CrtcPtr pCrtc = xf86CompatCrtc (scrn); + XDBG_RETURN_VAL_IF_FAIL ((pCrtc != NULL), FALSE); + SECCrtcPrivPtr pCrtcPriv = pCrtc->driver_private; + + secCrtcOverlayNeedOff (pCrtc, !onoff); + + if (pCrtcPriv->cursor_show && !onoff) + { + XDBG_TRACE (MCRS, "can't turn upper off.\n"); + return FALSE; + } + } + + layer = secLayerFind ((SECLayerOutput)output, lpos); + if (!layer) + return FALSE; + + if (onoff) + secLayerTurn (layer, TRUE, TRUE); + else + secLayerTurn (layer, FALSE, TRUE); + } + else + { + xf86CrtcConfigPtr pCrtcConfig; + int i; + + pCrtcConfig = XF86_CRTC_CONFIG_PTR (scrn); + if (!pCrtcConfig) + return FALSE; + + for (i = 0; i < pCrtcConfig->num_output; i++) + { + xf86OutputPtr pOutput = pCrtcConfig->output[i]; + SECOutputPrivPtr pOutputPriv = pOutput->driver_private; + + if ((output == LAYER_OUTPUT_LCD && + (pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_LVDS || + pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_Unknown)) || + (output == LAYER_OUTPUT_EXT && + (pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_HDMIA || + pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_HDMIB || + pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_VIRTUAL))) + { + SECCrtcPrivPtr pCrtcPriv; + + if (!pOutput->crtc) + break; + + pCrtcPriv = pOutput->crtc->driver_private; + if (pCrtcPriv->bAccessibility) + { + _secPropReturnProperty (value, "[Xorg] crtc(%d) accessibility ON. \n", + secCrtcID(pCrtcPriv)); + return TRUE; + } + + if (pOutput->crtc && !secCrtcTurn (pOutput->crtc, onoff, always, TRUE)) + { + _secPropReturnProperty (value, "[Xorg] crtc(%d) now %s%s\n", + secCrtcID(pCrtcPriv), + (pCrtcPriv->onoff)?"ON":"OFF", + (pCrtcPriv->onoff_always)?"(always).":"."); + return TRUE; + } + break; + } + } + } + + _secPropReturnProperty (value, "[Xorg] output(%d), zpos(%d) layer %s%s\n", + output, pos, (onoff)?"ON":"OFF", (always)?"(always).":"."); + + return TRUE; +} + +Bool secPropVideoOffset (char *cmd, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + SECPtr pSec = SECPTR (scrn); + int x, y; + char str[128]; + char *p; + SECLayer *layer; + + snprintf (str, sizeof(str), "%s", cmd); + + p = strtok (str, ","); + XDBG_RETURN_VAL_IF_FAIL (p != NULL, FALSE); + x = atoi (p); + + p = strtok (NULL, ","); + XDBG_RETURN_VAL_IF_FAIL (p != NULL, FALSE); + y = atoi (p); + +#if 0 + PropertyPtr rotate_prop; + int rotate = 0; + rotate_prop = secUtilGetWindowProperty (scrn->pScreen->root, "_E_ILLUME_ROTATE_ROOT_ANGLE"); + if (rotate_prop) + rotate = *(int*)rotate_prop->data; +#endif + + pSec->pVideoPriv->video_offset_x = x; + pSec->pVideoPriv->video_offset_y = y; + + layer = secLayerFind (LAYER_OUTPUT_LCD, LAYER_LOWER1); + if (layer) + secLayerSetOffset (layer, x, y); + + layer = secLayerFind (LAYER_OUTPUT_LCD, LAYER_LOWER2); + if (layer) + secLayerSetOffset (layer, x, y); + + _secPropReturnProperty (value, "[Xorg] video_offset : %d,%d.\n", + pSec->pVideoPriv->video_offset_x, + pSec->pVideoPriv->video_offset_y); + + return TRUE; +} + +Bool +secPropSetFbVisible (xf86OutputPtr pOutput, Atom property, RRPropertyValuePtr value) +{ + if (g_fb_visible_prop_init == FALSE) + { + xrr_property_fb_visible_atom = MakeAtom (STR_XRR_FB_VISIBLE_PROPERTY, + strlen (STR_XRR_FB_VISIBLE_PROPERTY), TRUE); + g_fb_visible_prop_init = TRUE; + } + + if (xrr_property_fb_visible_atom != property) + return FALSE; + + if (!value || !value->data || value->size == 0) + return TRUE; + + if (value->format != 8) + return TRUE; + + XDBG_TRACE (MPROP, "%s \n", value->data); + + secPropFbVisible (value->data, FALSE, value, pOutput->scrn); + + return TRUE; +} + +Bool +secPropSetVideoOffset (xf86OutputPtr pOutput, Atom property, RRPropertyValuePtr value) +{ + if (g_video_offset_prop_init == FALSE) + { + xrr_property_video_offset_atom = MakeAtom (STR_XRR_VIDEO_OFFSET_PROPERTY, + strlen (STR_XRR_VIDEO_OFFSET_PROPERTY), TRUE); + g_video_offset_prop_init = TRUE; + } + + if (xrr_property_video_offset_atom != property) + return FALSE; + + if (!value || !value->data || value->size == 0) + return TRUE; + + if (value->format != 8) + return TRUE; + + XDBG_TRACE (MPROP, "%s \n", value->data); + + secPropVideoOffset (value->data, value, pOutput->scrn); + + return TRUE; +} + +Bool secPropScreenRotate (char *cmd, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + xf86CrtcPtr crtc = xf86CompatCrtc (scrn); + int degree; + + if (!crtc) + return TRUE; + + if (!strcmp (cmd, "normal")) + degree = 0; + else if (!strcmp (cmd, "right")) + degree = 90; + else if (!strcmp (cmd, "inverted")) + degree = 180; + else if (!strcmp (cmd, "left")) + degree = 270; + else if (!strcmp (cmd, "0")) + degree = 0; + else if (!strcmp (cmd, "1")) + degree = 270; + else if (!strcmp (cmd, "2")) + degree = 180; + else if (!strcmp (cmd, "3")) + degree = 90; + else + { + _secPropReturnProperty (value, "[Xorg] unknown value: %s\n", cmd); + return TRUE; + } + + if (secCrtcScreenRotate (crtc, degree)) + _secPropReturnProperty (value, "[Xorg] screen rotated %d.\n", degree); + else + { + _secPropReturnProperty (value, "[Xorg] Fail screen rotate %d.\n", degree); + return FALSE; + } + + return TRUE; +} + +Bool +secPropSetScreenRotate (xf86OutputPtr pOutput, Atom property, RRPropertyValuePtr value) +{ + if (g_screen_rotate_prop_init == FALSE) + { + xrr_property_screen_rotate_atom = MakeAtom (STR_XRR_PROPERTY_SCREEN_ROTATE, + strlen (STR_XRR_PROPERTY_SCREEN_ROTATE), TRUE); + g_screen_rotate_prop_init = TRUE; + } + + if (xrr_property_screen_rotate_atom != property) + return FALSE; + + if (!value || !value->data || value->size == 0) + return TRUE; + + if (value->format != 8) + return TRUE; + + XDBG_TRACE (MPROP, "%s \n", value->data); + + secPropScreenRotate (value->data, value, pOutput->scrn); + + return TRUE; +} + diff --git a/src/crtcconfig/sec_prop.h b/src/crtcconfig/sec_prop.h new file mode 100644 index 0000000..79a2135 --- /dev/null +++ b/src/crtcconfig/sec_prop.h @@ -0,0 +1,50 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@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. + +**************************************************************************/ + +#ifndef __SEC_PROP_H__ +#define __SEC_PROP_H__ + +Bool secPropSetLvdsFunc (xf86OutputPtr output, Atom property, RRPropertyValuePtr value); +void secPropUnSetLvdsFunc (xf86OutputPtr pOutput); + +Bool secPropSetDisplayMode (xf86OutputPtr output, Atom property, RRPropertyValuePtr value); +void secPropUnSetDisplayMode (xf86OutputPtr pOutput); + +Bool secPropSetFbVisible (xf86OutputPtr output, Atom property, RRPropertyValuePtr value); +Bool secPropSetVideoOffset (xf86OutputPtr output, Atom property, RRPropertyValuePtr value); +Bool secPropSetScreenRotate (xf86OutputPtr pOutput, Atom property, RRPropertyValuePtr value); + +Bool secPropFbVisible (char *cmd, Bool always, RRPropertyValuePtr value, ScrnInfoPtr scrn); +Bool secPropVideoOffset (char *cmd, RRPropertyValuePtr value, ScrnInfoPtr scrn); +Bool secPropScreenRotate (char *cmd, RRPropertyValuePtr value, ScrnInfoPtr scrn); + + +#endif /* __SEC_PROP_H__ */ + diff --git a/src/crtcconfig/sec_xberc.c b/src/crtcconfig/sec_xberc.c new file mode 100755 index 0000000..3b0936f --- /dev/null +++ b/src/crtcconfig/sec_xberc.c @@ -0,0 +1,1276 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@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. + +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdint.h> +#include <string.h> +#include <strings.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <poll.h> +#include <dirent.h> + +#include <xorgVersion.h> +#include <tbm_bufmgr.h> +#include <xf86Crtc.h> +#include <xf86DDC.h> +#include <xf86cmap.h> +#include <xf86Priv.h> +#include <list.h> +#include <X11/Xatom.h> +#include <X11/extensions/dpmsconst.h> + +#include "sec.h" +#include "sec_util.h" +#include "sec_xberc.h" +#include "sec_output.h" +#include "sec_crtc.h" +#include "sec_layer.h" +#include "sec_wb.h" +#include "sec_plane.h" +#include "sec_prop.h" +#include "sec_drmmode_dump.h" + +#define XRRPROPERTY_ATOM "X_RR_PROPERTY_REMOTE_CONTROLLER" +#define XBERC_BUF_SIZE 8192 + +static Atom rr_property_atom; + +static void _secXbercSetReturnProperty (RRPropertyValuePtr value, const char * f, ...); + +static Bool SECXbercSetTvoutMode (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + SECPtr pSec = SECPTR (scrn); + SECModePtr pSecMode = pSec->pSecMode; + const char * mode_string[] = {"Off", "Clone", "UiClone", "Extension"}; + SECDisplaySetMode mode; + + XDBG_DEBUG (MSEC, "%s value : %d\n", __FUNCTION__, *(unsigned int*)value->data); + + if (argc < 2) + { + _secXbercSetReturnProperty (value, "Error : too few arguments\n"); + return TRUE; + } + + if (argc == 2) + { + _secXbercSetReturnProperty (value, "Current Tv Out mode is %d (%s)\n", + pSecMode->set_mode, mode_string[pSecMode->set_mode]); + return TRUE; + } + + mode = (SECDisplaySetMode)atoi (argv[2]); + + if (mode < DISPLAY_SET_MODE_OFF) + { + _secXbercSetReturnProperty (value, "Error : value(%d) is out of range.\n", mode); + return TRUE; + } + + if (mode == pSecMode->set_mode) + { + _secXbercSetReturnProperty (value, "[Xorg] already tvout : %s.\n", mode_string[mode]); + return TRUE; + } + + if (pSecMode->conn_mode != DISPLAY_CONN_MODE_HDMI && pSecMode->conn_mode != DISPLAY_CONN_MODE_VIRTUAL) + { + _secXbercSetReturnProperty (value, "Error : not connected.\n"); + return TRUE; + } + + secDisplaySetDispSetMode (scrn, mode); + + _secXbercSetReturnProperty (value, "[Xorg] tvout : %s.\n", mode_string[mode]); + + return TRUE; +} + +static Bool SECXbercSetConnectMode (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + SECPtr pSec = SECPTR (scrn); + SECModePtr pSecMode = pSec->pSecMode; + const char * mode_string[] = {"Off", "HDMI", "Virtual"}; + SECDisplayConnMode mode; + + XDBG_DEBUG (MSEC, "%s value : %d\n", __FUNCTION__, *(unsigned int*)value->data); + + if (argc < 2) + { + _secXbercSetReturnProperty (value, "Error : too few arguments\n"); + return TRUE; + } + + if (argc == 2) + { + _secXbercSetReturnProperty (value, "Current connect mode is %d (%s)\n", + pSecMode->conn_mode, mode_string[pSecMode->conn_mode]); + return TRUE; + } + + mode = (SECDisplayConnMode)atoi (argv[2]); + + if (mode < DISPLAY_CONN_MODE_NONE || mode >= DISPLAY_CONN_MODE_MAX) + { + _secXbercSetReturnProperty (value, "Error : value(%d) is out of range.\n", mode); + return TRUE; + } + + if (mode == pSecMode->conn_mode) + { + _secXbercSetReturnProperty (value, "[Xorg] already connect : %s.\n", mode_string[mode]); + return TRUE; + } + + secDisplaySetDispConnMode (scrn, mode); + + _secXbercSetReturnProperty (value, "[Xorg] connect : %s.\n", mode_string[mode]); + + return TRUE; +} + +static Bool SECXbercAsyncSwap (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + ScreenPtr pScreen = scrn->pScreen; + int bEnable; + int status = -1; + + if (argc !=3 ) + { + status = secExaScreenAsyncSwap (pScreen, -1); + if (status < 0) + { + _secXbercSetReturnProperty (value, "%s", "faili to set async swap\n"); + return TRUE; + } + + _secXbercSetReturnProperty (value, "Async swap : %d\n", status); + return TRUE; + } + + bEnable = atoi (argv[2]); + + status = secExaScreenAsyncSwap (pScreen, bEnable); + if (status < 0) + { + _secXbercSetReturnProperty (value, "%s", "faili to set async swap\n"); + return TRUE; + } + + if (status) + _secXbercSetReturnProperty (value, "%s", "Set async swap.\n"); + else + _secXbercSetReturnProperty (value, "%s", "Unset async swap.\n"); + + return TRUE; +} + +static long +_parse_long (char *s) +{ + char *fmt = "%lu"; + long retval = 0L; + int thesign = 1; + + if (s && s[0]) + { + char temp[12]; + snprintf (temp, sizeof (temp), "%s", s); + s = temp; + + if (s[0] == '-') + s++, thesign = -1; + if (s[0] == '0') + s++, fmt = "%lo"; + if (s[0] == 'x' || s[0] == 'X') + s++, fmt = "%lx"; + (void) sscanf (s, fmt, &retval); + } + return (thesign * retval); +} + +static Bool SECXbercDump (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + SECPtr pSec = SECPTR (scrn); + int dump_mode; + Bool flush = TRUE; + char *c; + int buf_cnt = 30; + + if (argc < 3) + goto print_dump; + + pSec->dump_xid = 0; + dump_mode = 0; + + if (pSec->dump_str) + free (pSec->dump_str); + pSec->dump_str = strdup (argv[2]); + + c = strtok (argv[2], ","); + if (!c) + { + _secXbercSetReturnProperty (value, "[Xorg] fail: read option"); + return TRUE; + } + + do + { + if (!strcmp (c, "off")) + { + dump_mode = 0; + break; + } + else if (!strcmp (c, "clear")) + { + dump_mode = 0; + flush = FALSE; + break; + } + else if (!strcmp (c, "drawable")) + { + dump_mode = XBERC_DUMP_MODE_DRAWABLE; + pSec->dump_xid = _parse_long (argv[3]); + } + else if (!strcmp (c, "fb")) + dump_mode |= XBERC_DUMP_MODE_FB; + else if (!strcmp (c, "all")) + dump_mode |= (XBERC_DUMP_MODE_DRAWABLE|XBERC_DUMP_MODE_FB); + else if (!strcmp (c, "ia")) + dump_mode |= XBERC_DUMP_MODE_IA; + else if (!strcmp (c, "ca")) + dump_mode |= XBERC_DUMP_MODE_CA; + else if (!strcmp (c, "ea")) + dump_mode |= XBERC_DUMP_MODE_EA; + else + { + _secXbercSetReturnProperty (value, "[Xorg] fail: unknown option('%s')\n", c); + return TRUE; + } + } while ((c = strtok (NULL, ","))); + + snprintf (pSec->dump_type, sizeof (pSec->dump_type), "bmp"); + if (argc > 3) + { + int i; + for (i = 3; i < argc; i++) + { + c = argv[i]; + if (!strcmp (c, "-count")) + buf_cnt = MIN((argv[i+1])?atoi(argv[i+1]):30,100); + else if (!strcmp (c, "-type")) + { + if (!strcmp (argv[i+1], "bmp") || !strcmp (argv[i+1], "raw")) + snprintf (pSec->dump_type, sizeof (pSec->dump_type), "%s", argv[i+1]); + } + } + } + + if (dump_mode != 0) + { + char *dir = DUMP_DIR; + DIR *dp; + int ret = -1; + + if (!(dp = opendir (dir))) + { + ret = mkdir (dir, 0755); + if (ret < 0) + { + _secXbercSetReturnProperty (value, "[Xorg] fail: mkdir '%s'\n", dir); + return FALSE; + } + } + else + closedir (dp); + } + + if (dump_mode != pSec->dump_mode) + { + pSec->dump_mode = dump_mode; + + if (dump_mode == 0) + { + if (flush) + secUtilFlushDump (pSec->dump_info); + secUtilFinishDump (pSec->dump_info); + pSec->dump_info = NULL; + pSec->flip_cnt = 0; + goto print_dump; + } + else + { + if (pSec->dump_info) + { + secUtilFlushDump (pSec->dump_info); + secUtilFinishDump (pSec->dump_info); + pSec->dump_info = NULL; + pSec->flip_cnt = 0; + } + + pSec->dump_info = secUtilPrepareDump (scrn, + pSec->pSecMode->main_lcd_mode.hdisplay * pSec->pSecMode->main_lcd_mode.vdisplay * 4, + buf_cnt); + if (pSec->dump_info) + { + if (pSec->dump_mode & ~XBERC_DUMP_MODE_DRAWABLE) + _secXbercSetReturnProperty (value, "[Xorg] Dump buffer: %s(cnt:%d)\n", + pSec->dump_str, buf_cnt); + else + _secXbercSetReturnProperty (value, "[Xorg] Dump buffer: %s(xid:0x%x,cnt:%d)\n", + pSec->dump_str, pSec->dump_xid, buf_cnt); + } + else + _secXbercSetReturnProperty (value, "[Xorg] Dump buffer: %s(fail)\n", pSec->dump_str); + } + } + else + goto print_dump; + + return TRUE; +print_dump: + if (pSec->dump_mode & XBERC_DUMP_MODE_DRAWABLE) + _secXbercSetReturnProperty (value, "[Xorg] Dump buffer: %s(0x%x)\n", pSec->dump_str, pSec->dump_xid); + else + _secXbercSetReturnProperty (value, "[Xorg] Dump buffer: %s\n", pSec->dump_str); + + return TRUE; +} + +static Bool SECXbercCursorEnable (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + SECPtr pSec = SECPTR (scrn); + + Bool bEnable; + + if (argc != 3) + { + _secXbercSetReturnProperty (value, "Enable cursor : %d\n", pSec->enableCursor); + return TRUE; + } + + bEnable = atoi (argv[2]); + + if (bEnable!=pSec->enableCursor) + { + pSec->enableCursor = bEnable; + if (secCrtcCursorEnable (scrn, bEnable)) + { + _secXbercSetReturnProperty (value, "[Xorg] cursor %s.\n", bEnable?"enable":"disable"); + } + else + { + _secXbercSetReturnProperty (value, "[Xorg] Fail cursor %s.\n", bEnable?"enable":"disable"); + } + } + else + { + _secXbercSetReturnProperty (value, "[Xorg] already cursor %s.\n", bEnable?"enabled":"disabled"); + } + + return TRUE; +} + +static Bool SECXbercCursorRotate (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + xf86CrtcPtr crtc = xf86CompatCrtc (scrn); + SECCrtcPrivPtr fimd_crtc; + int rotate, RR_rotate; + + if (!crtc) + return TRUE; + + fimd_crtc = crtc->driver_private; + + if (argc != 3) + { + rotate = secUtilRotateToDegree (fimd_crtc->user_rotate); + _secXbercSetReturnProperty (value, "Current cursor rotate value : %d\n", rotate); + return TRUE; + } + + rotate = atoi (argv[2]); + RR_rotate = secUtilDegreeToRotate (rotate); + if (!RR_rotate) + { + _secXbercSetReturnProperty (value, "[Xorg] Not support rotate(0, 90, 180, 270 only)\n"); + return TRUE; + } + + if (secCrtcCursorRotate (crtc, RR_rotate)) + { + _secXbercSetReturnProperty (value, "[Xorg] cursor rotated %d.\n", rotate); + } + else + { + _secXbercSetReturnProperty (value, "[Xorg] Fail cursor rotate %d.\n", rotate); + } + + return TRUE; +} + +static Bool SECXbercVideoPunch (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + SECPtr pSec = SECPTR (scrn); + + Bool video_punch; + + if (argc != 3) + { + _secXbercSetReturnProperty (value, "video_punch : %d\n", pSec->pVideoPriv->video_punch); + return TRUE; + } + + video_punch = atoi (argv[2]); + + if (pSec->pVideoPriv->video_punch != video_punch) + { + pSec->pVideoPriv->video_punch = video_punch; + _secXbercSetReturnProperty (value, "[Xorg] video_punch %s.\n", video_punch?"enabled":"disabled"); + } + else + _secXbercSetReturnProperty (value, "[Xorg] already punch %s.\n", video_punch?"enabled":"disabled"); + + return TRUE; +} + +static Bool SECXbercVideoOffset (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + SECPtr pSec = SECPTR (scrn); + + if (argc != 3) + { + _secXbercSetReturnProperty (value, "video_offset : %d,%d.\n", + pSec->pVideoPriv->video_offset_x, + pSec->pVideoPriv->video_offset_y); + return TRUE; + } + + if (!secPropVideoOffset (argv[2], value, scrn)) + { + _secXbercSetReturnProperty (value, "ex) xberc video_offset 0,100.\n"); + return TRUE; + } + + return TRUE; +} + +static Bool SECXbercVideoFps (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + SECPtr pSec = SECPTR (scrn); + + Bool video_fps; + + if (argc != 3) + { + _secXbercSetReturnProperty (value, "video_fps : %d\n", pSec->pVideoPriv->video_fps); + return TRUE; + } + + video_fps = atoi (argv[2]); + + if (pSec->pVideoPriv->video_fps != video_fps) + { + pSec->pVideoPriv->video_fps = video_fps; + _secXbercSetReturnProperty (value, "[Xorg] video_fps %s.\n", video_fps?"enabled":"disabled"); + } + else + _secXbercSetReturnProperty (value, "[Xorg] already video_fps %s.\n", video_fps?"enabled":"disabled"); + + return TRUE; +} + +static Bool SECXbercVideoSync (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + SECPtr pSec = SECPTR (scrn); + + Bool video_sync; + + if (argc != 3) + { + _secXbercSetReturnProperty (value, "video_sync : %d\n", pSec->pVideoPriv->video_sync); + return TRUE; + } + + video_sync = atoi (argv[2]); + + if (pSec->pVideoPriv->video_sync != video_sync) + { + pSec->pVideoPriv->video_sync = video_sync; + _secXbercSetReturnProperty (value, "[Xorg] video_sync %s.\n", video_sync?"enabled":"disabled"); + } + else + _secXbercSetReturnProperty (value, "[Xorg] already video_sync %s.\n", video_sync?"enabled":"disabled"); + + return TRUE; +} + +static Bool SECXbercVideoNoRetbuf (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + SECPtr pSec = SECPTR (scrn); + + if (argc != 3) + { + _secXbercSetReturnProperty (value, "[Xorg] %s wait retbuf\n", (pSec->pVideoPriv->no_retbuf)?"No":""); + return TRUE; + } + + pSec->pVideoPriv->no_retbuf = atoi (argv[2]); + + _secXbercSetReturnProperty (value, "[Xorg] %s wait retbuf\n", (pSec->pVideoPriv->no_retbuf)?"No":""); + + return TRUE; +} + +static Bool SECXbercVideoOutput (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + SECPtr pSec = SECPTR (scrn); + const char * output_string[] = {"None", "default", "video", "ext_only"}; + int video_output; + + if (argc != 3) + { + _secXbercSetReturnProperty (value, "video_output : %d\n", output_string[pSec->pVideoPriv->video_output]); + return TRUE; + } + + video_output = atoi (argv[2]); + + if (video_output < OUTPUT_MODE_DEFAULT || video_output > OUTPUT_MODE_EXT_ONLY) + { + _secXbercSetReturnProperty (value, "Error : value(%d) is out of range.\n", video_output); + return TRUE; + } + + video_output += 1; + + if (pSec->pVideoPriv->video_output != video_output) + { + pSec->pVideoPriv->video_output = video_output; + _secXbercSetReturnProperty (value, "[Xorg] video_output : %s.\n", output_string[video_output]); + } + else + _secXbercSetReturnProperty (value, "[Xorg] already video_output : %s.\n", output_string[video_output]); + + return TRUE; +} + +static Bool SECXbercWbFps (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + SECPtr pSec = SECPTR (scrn); + + Bool wb_fps; + + if (argc != 3) + { + _secXbercSetReturnProperty (value, "wb_fps : %d\n", pSec->wb_fps); + return TRUE; + } + + wb_fps = atoi (argv[2]); + + if (pSec->wb_fps != wb_fps) + { + pSec->wb_fps = wb_fps; + _secXbercSetReturnProperty (value, "[Xorg] wb_fps %s.\n", wb_fps?"enabled":"disabled"); + } + else + _secXbercSetReturnProperty (value, "[Xorg] already wb_fps %s.\n", wb_fps?"enabled":"disabled"); + + return TRUE; +} + +static Bool SECXbercWbHz (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + SECPtr pSec = SECPTR (scrn); + + Bool wb_hz; + + if (argc != 3) + { + _secXbercSetReturnProperty (value, "wb_hz : %d\n", pSec->wb_hz); + return TRUE; + } + + wb_hz = atoi (argv[2]); + + if (pSec->wb_hz != wb_hz) + { + pSec->wb_hz = wb_hz; + _secXbercSetReturnProperty (value, "[Xorg] wb_hz %d.\n", wb_hz); + } + else + _secXbercSetReturnProperty (value, "[Xorg] already wb_hz %d.\n", wb_hz); + + return TRUE; +} + +static Bool SECXbercXvPerf (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + SECPtr pSec = SECPTR (scrn); + char *c; + + if (argc < 3) + { + _secXbercSetReturnProperty (value, "[Xorg] xvperf: %s\n", + (pSec->xvperf)?pSec->xvperf:"off"); + return TRUE; + } + + if (pSec->xvperf) + free (pSec->xvperf); + pSec->xvperf = strdup (argv[2]); + + c = strtok (argv[2], ","); + if (!c) + { + _secXbercSetReturnProperty (value, "[Xorg] fail: read option\n"); + return TRUE; + } + + do + { + if (!strcmp (c, "off")) + pSec->xvperf_mode = 0; + else if (!strcmp (c, "ia")) + pSec->xvperf_mode |= XBERC_XVPERF_MODE_IA; + else if (!strcmp (c, "ca")) + pSec->xvperf_mode |= XBERC_XVPERF_MODE_CA; + else if (!strcmp (c, "cvt")) + pSec->xvperf_mode |= XBERC_XVPERF_MODE_CVT; + else if (!strcmp (c, "wb")) + pSec->xvperf_mode |= XBERC_XVPERF_MODE_WB; + else if (!strcmp (c, "access")) + pSec->xvperf_mode |= XBERC_XVPERF_MODE_ACCESS; + else + { + _secXbercSetReturnProperty (value, "[Xorg] fail: unknown option('%s')\n", c); + return TRUE; + } + } while ((c = strtok (NULL, ","))); + + _secXbercSetReturnProperty (value, "[Xorg] xvperf: %s\n", + (pSec->xvperf)?pSec->xvperf:"off"); + + return TRUE; +} + +static Bool SECXbercSwap (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + if (argc != 2) + { + _secXbercSetReturnProperty (value, "Error : too few arguments\n"); + return TRUE; + } + + secVideoSwapLayers (scrn->pScreen); + + _secXbercSetReturnProperty (value, "%s", "Video layers swapped.\n"); + + return TRUE; +} + +static Bool SECXbercDrmmodeDump (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + SECPtr pSec = SECPTR (scrn); + char reply[XBERC_BUF_SIZE] = {0,}; + int len = sizeof (reply); + + if (argc != 2) + { + _secXbercSetReturnProperty (value, "Error : too few arguments\n"); + return TRUE; + } + + sec_drmmode_dump (pSec->drm_fd, reply, &len); + _secXbercSetReturnProperty (value, "%s", reply); + + return TRUE; +} + +static Bool SECXbercAccessibility (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + Bool found = FALSE; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR (scrn); + xf86OutputPtr pOutput = NULL; + xf86CrtcPtr pCrtc = NULL; + SECCrtcPrivPtr pCrtcPriv = NULL; + int output_w = 0, output_h = 0; + + char *opt; + char *mode; + int i; + + int accessibility_status; + int bScale; + _X_UNUSED Bool bChange = FALSE; + + char seps[]="x+-"; + char *tr; + int geo[10], g=0; + + for (i = 0; i < xf86_config->num_output; i++) + { + pOutput = xf86_config->output[i]; + if (!pOutput->crtc->enabled) + continue; + + /* modify the physical size of monitor */ + if (!strcmp(pOutput->name, "LVDS1")) + { + found = TRUE; + break; + } + } + + if (!found) + { + _secXbercSetReturnProperty (value, "Error : cannot found LVDS1\n"); + return TRUE; + } + + pCrtc = pOutput->crtc; + pCrtcPriv = pCrtc->driver_private; + + output_w = pCrtc->mode.HDisplay; + output_h = pCrtc->mode.VDisplay; + + for(i=0; i<argc; i++) + { + opt = argv[i]; + if(*opt != '-') continue; + + if(!strcmp(opt, "-n") ) + { + accessibility_status = atoi(argv[++i]); + if(pCrtcPriv->accessibility_status != accessibility_status) + { + pCrtcPriv->accessibility_status = accessibility_status; + bChange = TRUE; + } + } + else if(!strcmp(opt, "-scale")) + { + bScale = atoi(argv[++i]); + + pCrtcPriv->bScale = bScale; + bChange = TRUE; + //ErrorF("[XORG] Set Scale = %d\n", bScale); + + if(bScale) + { + int x,y,w,h; + + mode = argv[++i]; + tr = strtok(mode, seps); + while(tr != NULL) + { + geo[g++] = atoi(tr); + tr=strtok(NULL, seps); + } + + if(g < 4) + { + _secXbercSetReturnProperty (value, "[Xberc] Invalid geometry(%s)\n", mode); + continue; + } + + w = geo[0]; + h = geo[1]; + x = geo[2]; + y = geo[3]; + + /*Check invalidate region */ + if(x<0) x=0; + if(y<0) y=0; + if(x+w > output_w) w = output_w-x; + if(y+h > output_h) h = output_h-y; + + if(pCrtcPriv->rotate == RR_Rotate_90) + { + pCrtcPriv->sx = y; + pCrtcPriv->sy = output_w - (x+w); + pCrtcPriv->sw = h; + pCrtcPriv->sh = w; + } + else if(pCrtcPriv->rotate == RR_Rotate_270) + { + pCrtcPriv->sx = output_h - (y+h); + pCrtcPriv->sy = x; + pCrtcPriv->sw = h; + pCrtcPriv->sh = w; + } + else if(pCrtcPriv->rotate == RR_Rotate_180) + { + pCrtcPriv->sx = output_w - (x+w); + pCrtcPriv->sy = output_h - (y+h); + pCrtcPriv->sw = w; + pCrtcPriv->sh = h; + } + else + { + pCrtcPriv->sx = x; + pCrtcPriv->sy = y; + pCrtcPriv->sw = w; + pCrtcPriv->sh = h; + } + } + } + } + + secCrtcEnableAccessibility (pCrtc); + + return TRUE; +} + +static Bool SECXbercEnableFb (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + Bool always = FALSE; + + if (argc == 2) + { + char ret_buf[XBERC_BUF_SIZE] = {0,}; + char temp[1024] = {0,}; + xf86CrtcConfigPtr pCrtcConfig; + int i, len, remain = XBERC_BUF_SIZE; + char *buf = ret_buf; + + pCrtcConfig = XF86_CRTC_CONFIG_PTR (scrn); + if (!pCrtcConfig) + goto fail_enable_fb; + + for (i = 0; i < pCrtcConfig->num_output; i++) + { + xf86OutputPtr pOutput = pCrtcConfig->output[i]; + if (pOutput->crtc) + { + SECCrtcPrivPtr pCrtcPriv = pOutput->crtc->driver_private; + snprintf (temp, sizeof (temp), "crtc(%d) : %s%s\n", + pCrtcPriv->mode_crtc->crtc_id, + (pCrtcPriv->onoff)?"ON":"OFF", + (pCrtcPriv->onoff_always)?"(always).":"."); + len = MIN (remain, strlen (temp)); + strncpy (buf, temp, len); + buf += len; + remain -= len; + } + } + + secPlaneDump (buf, &remain); + + _secXbercSetReturnProperty (value, "%s", ret_buf); + + return TRUE; + } + + if (argc > 4) + goto fail_enable_fb; + + if (!strcmp ("always", argv[3])) + always = TRUE; + + if (!secPropFbVisible (argv[2], always, value, scrn)) + goto fail_enable_fb; + + return TRUE; + +fail_enable_fb: + _secXbercSetReturnProperty (value, "ex) xberc fb [output]:[zpos]:[onoff] {always}.\n"); + + return TRUE; +} + +static Bool SECXbercScreenRotate (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn) +{ + xf86CrtcPtr crtc = xf86CompatCrtc (scrn); + SECCrtcPrivPtr fimd_crtc; + + if (!crtc) + return TRUE; + + fimd_crtc = crtc->driver_private; + + if (argc != 3) + { + _secXbercSetReturnProperty (value, "Current screen rotate value : %d\n", fimd_crtc->screen_rotate_degree); + return TRUE; + } + + secPropScreenRotate (argv[2], value, scrn); + + return TRUE; +} + +static struct +{ + const char * Cmd; + const char * Description; + const char * Options; + + const char *(*DynamicUsage) (int); + const char * DetailedUsage; + + Bool (*set_property) (int argc, char ** argv, RRPropertyValuePtr value, ScrnInfoPtr scrn); + Bool (*get_property) (RRPropertyValuePtr value); +} xberc_property_proc[] = +{ + { + "tvout", "to set Tv Out Mode", "[0-4]", + NULL, "[Off:0 / Clone:1 / UiClone:2 / Extension:3]", + SECXbercSetTvoutMode, NULL, + }, + + { + "connect", "to set connect mode", "[0-2]", + NULL, "[Off:0 / HDMI:1 / Virtual:2]", + SECXbercSetConnectMode, NULL, + }, + + { + "async_swap", "not block by vsync", "[0 or 1]", + NULL, "[0/1]", + SECXbercAsyncSwap, NULL + }, + + { + "dump", "to dump buffers", "[off,clear,drawable,fb,all]", + NULL, "[off,clear,drawable,fb,all] -count [n] -type [raw|bmp]", + SECXbercDump, NULL + }, + + { + "cursor_enable", "to enable/disable cursor", "[0 or 1]", + NULL, "[Enable:1 / Disable:0]", + SECXbercCursorEnable, NULL + }, + + { + "cursor_rotate", "to set cursor rotate degree", "[0,90,180,270]", + NULL, "[0,90,180,270]", + SECXbercCursorRotate, NULL + }, + + { + "video_punch", "to punch screen when XV put image on screen", "[0 or 1]", + NULL, "[0/1]", + SECXbercVideoPunch, NULL + }, + + { + "video_offset", "to add x,y to the position video", "[x,y]", + NULL, "[x,y]", + SECXbercVideoOffset, NULL + }, + + { + "video_fps", "to print fps of video", "[0 or 1]", + NULL, "[0/1]", + SECXbercVideoFps, NULL + }, + + { + "video_sync", "to sync video", "[0 or 1]", + NULL, "[0/1]", + SECXbercVideoSync, NULL + }, + + { + "video_output", "to set output", "[0,1,2]", + NULL, "[default:0 / video:1 / ext_only:2]", + SECXbercVideoOutput, NULL + }, + + { + "video_no_retbuf", "no wait until buffer returned", "[0,1]", + NULL, "[disable:0 / enable:1]", + SECXbercVideoNoRetbuf, NULL + }, + + { + "wb_fps", "to print fps of writeback", "[0 or 1]", + NULL, "[0/1]", + SECXbercWbFps, NULL + }, + + { + "wb_hz", "to set hz of writeback", "[0, 12, 15, 20, 30, 60]", + NULL, "[0, 12, 15, 20, 30, 60]", + SECXbercWbHz, NULL + }, + + { + "xv_perf", "to print xv elapsed time", "[off,ia,ca,cvt,wb]", + NULL, "[off,ia,ca,cvt,wb]", + SECXbercXvPerf, NULL + }, + + { + "swap", "to swap video layers", "", + NULL, "", + SECXbercSwap, NULL + }, + + { + "drmmode_dump", "to print drmmode resources", "", + NULL, "", + SECXbercDrmmodeDump, NULL + }, + + { + "accessibility", "to set accessibility", "-n [0 or 1] -scale [0 or 1] [{width}x{height}+{x}+{y}]", + NULL, "-n [0 or 1] -scale [0 or 1] [{width}x{height}+{x}+{y}]", + SECXbercAccessibility, NULL + }, + + { + "fb", "to turn framebuffer on/off", "[0~1]:[0~4]:[0~1] {always}", + NULL, "[output : 0(lcd)~1(ext)]:[zpos : 0 ~ 4]:[onoff : 0(on)~1(off)] {always}", + SECXbercEnableFb, NULL + }, + + { + "screen_rotate", "to set screen orientation", "[normal,inverted,left,right,0,1,2,3]", + NULL, "[normal,inverted,left,right,0,1,2,3]", + SECXbercScreenRotate, NULL + }, +}; + +static int _secXbercPrintUsage (char *buf, int size, const char * exec) +{ + char * begin = buf; + char temp[1024]; + int i, len, remain = size; + + int option_cnt = sizeof (xberc_property_proc) / sizeof (xberc_property_proc[0]); + + snprintf (temp, sizeof (temp), "Usage : %s [cmd] [options]\n", exec); + len = MIN (remain, strlen (temp)); + strncpy (buf, temp, len); + buf += len; + remain -= len; + + if (remain <= 0) + return (buf - begin); + + snprintf (temp, sizeof (temp), " ex)\n"); + len = MIN (remain, strlen (temp)); + strncpy (buf, temp, len); + buf += len; + remain -= len; + + if (remain <= 0) + return (buf - begin); + + for (i=0; i<option_cnt; i++) + { + snprintf (temp, sizeof (temp), " %s %s %s\n", exec, xberc_property_proc[i].Cmd, xberc_property_proc[i].Options); + len = MIN (remain, strlen (temp)); + strncpy (buf, temp, len); + buf += len; + remain -= len; + + if (remain <= 0) + return (buf - begin); + } + + snprintf (temp, sizeof (temp), " options :\n"); + len = MIN (remain, strlen (temp)); + strncpy (buf, temp, len); + buf += len; + remain -= len; + + if (remain <= 0) + return (buf - begin); + + for (i=0; i<option_cnt; i++) + { + if (xberc_property_proc[i].Cmd && xberc_property_proc[i].Description) + snprintf (temp, sizeof (temp), " %s (%s)\n", xberc_property_proc[i].Cmd, xberc_property_proc[i].Description); + else + snprintf (temp, sizeof (temp), " Cmd(%p) or Descriptiont(%p).\n", xberc_property_proc[i].Cmd, xberc_property_proc[i].Description); + len = MIN (remain, strlen (temp)); + strncpy (buf, temp, len); + buf += len; + remain -= len; + + if (remain <= 0) + return (buf - begin); + + if (xberc_property_proc[i].DynamicUsage) + { + snprintf (temp, sizeof (temp), " [MODULE:%s]\n", xberc_property_proc[i].DynamicUsage (MODE_NAME_ONLY)); + len = MIN (remain, strlen (temp)); + strncpy (buf, temp, len); + buf += len; + remain -= len; + + if (remain <= 0) + return (buf - begin); + } + + if (xberc_property_proc[i].DetailedUsage) + snprintf (temp, sizeof (temp), " %s\n", xberc_property_proc[i].DetailedUsage); + else + snprintf (temp, sizeof (temp), " DetailedUsage(%p).\n", xberc_property_proc[i].DetailedUsage); + len = MIN (remain, strlen (temp)); + strncpy (buf, temp, len); + buf += len; + remain -= len; + + if (remain <= 0) + return (buf - begin); + } + + return (buf - begin); +} + +static unsigned int _secXbercInit() +{ + XDBG_DEBUG (MSEC, "%s()\n", __FUNCTION__); + + static Bool g_property_init = FALSE; + static unsigned int nProperty = sizeof (xberc_property_proc) / sizeof (xberc_property_proc[0]); + + if (g_property_init == FALSE) + { + rr_property_atom = MakeAtom (XRRPROPERTY_ATOM, strlen (XRRPROPERTY_ATOM), TRUE); + g_property_init = TRUE; + } + + return nProperty; +} + +static int _secXbercParseArg (int * argc, char ** argv, RRPropertyValuePtr value) +{ + int i; + char * data; + + if (argc == NULL || value == NULL || argv == NULL || value->data == NULL) + return FALSE; + + data = value->data; + + if (value->format != 8) + return FALSE; + + if (value->size < 3 || data[value->size - 2] != '\0' || data[value->size - 1] != '\0') + return FALSE; + + for (i=0; *data; i++) + { + argv[i] = data; + data += strlen (data) + 1; + if (data - (char*)value->data > value->size) + return FALSE; + } + argv[i] = data; + *argc = i; + + return TRUE; +} + +static void _secXbercSetReturnProperty (RRPropertyValuePtr value, const char * f, ...) +{ + int len; + va_list args; + char buf[XBERC_BUF_SIZE]; + + if (value->data) + { + free (value->data); + value->data = NULL; + } + va_start (args, f); + len = vsnprintf (buf, sizeof(buf), f, args) + 1; + va_end (args); + + value->data = calloc (1, len); + value->format = 8; + value->size = len; + + if (value->data) + strncpy (value->data, buf, len-1); +} + +int +secXbercSetProperty (xf86OutputPtr output, Atom property, RRPropertyValuePtr value) +{ + XDBG_TRACE (MXBRC, "%s\n", __FUNCTION__); + + unsigned int nProperty = _secXbercInit(); + unsigned int p; + + int argc; + char * argv[1024]; + char buf[XBERC_BUF_SIZE] = {0,}; + + if (rr_property_atom != property) + { + _secXbercSetReturnProperty (value, "[Xberc]: Unrecognized property name.\n"); + return TRUE; + } + + if (_secXbercParseArg (&argc, argv, value) == FALSE || argc < 1) + { + _secXbercSetReturnProperty (value, "[Xberc]: Parse error.\n"); + return TRUE; + } + + if (argc < 2) + { + _secXbercPrintUsage (buf, sizeof (buf), argv[0]); + _secXbercSetReturnProperty (value, buf); + + return TRUE; + } + + for (p=0; p<nProperty; p++) + { + if (!strcmp (argv[1], xberc_property_proc[p].Cmd) || + (argv[1][0] == '-' && !strcmp (1 + argv[1], xberc_property_proc[p].Cmd))) + { + xberc_property_proc[p].set_property (argc, argv, value, output->scrn); + return TRUE; + } + } + + _secXbercPrintUsage (buf, sizeof (buf), argv[0]); + _secXbercSetReturnProperty (value, buf); + + return TRUE; +} diff --git a/src/crtcconfig/sec_xberc.h b/src/crtcconfig/sec_xberc.h new file mode 100644 index 0000000..bf9beaa --- /dev/null +++ b/src/crtcconfig/sec_xberc.h @@ -0,0 +1,51 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@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. + +**************************************************************************/ + +#ifndef __SEC_XBERC_H__ +#define __SEC_XBERC_H__ + +#define XBERC + +#define XBERC_DUMP_MODE_DRAWABLE 0x1 +#define XBERC_DUMP_MODE_FB 0x2 +#define XBERC_DUMP_MODE_IA 0x10 +#define XBERC_DUMP_MODE_CA 0x20 +#define XBERC_DUMP_MODE_EA 0x40 + +#define XBERC_XVPERF_MODE_IA 0x1 +#define XBERC_XVPERF_MODE_CA 0x2 +#define XBERC_XVPERF_MODE_CVT 0x10 +#define XBERC_XVPERF_MODE_WB 0x20 +#define XBERC_XVPERF_MODE_ACCESS 0x40 + +int secXbercSetProperty (xf86OutputPtr output, Atom property, RRPropertyValuePtr value); + +#endif /* __SEC_XBERC_H__ */ + diff --git a/src/debug/sec_drmmode_dump.c b/src/debug/sec_drmmode_dump.c new file mode 100644 index 0000000..f53ebd8 --- /dev/null +++ b/src/debug/sec_drmmode_dump.c @@ -0,0 +1,422 @@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <sys/poll.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/poll.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <time.h> +#include <signal.h> + +#include "libdrm/drm.h" +#include "xf86drm.h" +#include "xf86drmMode.h" +#include "exynos_drm.h" +#include "sec_display.h" +#include "sec_util.h" + +typedef struct _DRMModeTest +{ + int tc_num; + int drm_fd; + + drmModeRes *resources; + drmModePlaneRes *plane_resources; + drmModeEncoder *encoders[3]; + drmModeConnector *connectors[3]; + drmModeCrtc *crtcs[3]; + drmModeFB *fbs[10]; + drmModePlane *planes[10]; + +} DRMModeTest; + +struct type_name +{ + int type; + char *name; +}; + +#define dump_resource(res, reply, len) if (res) reply = dump_##res(reply, len) + +static DRMModeTest test; + +struct type_name encoder_type_names[] = +{ + { DRM_MODE_ENCODER_NONE, "none" }, + { DRM_MODE_ENCODER_DAC, "DAC" }, + { DRM_MODE_ENCODER_TMDS, "TMDS" }, + { DRM_MODE_ENCODER_LVDS, "LVDS" }, + { DRM_MODE_ENCODER_TVDAC, "TVDAC" }, +}; + +struct type_name connector_status_names[] = +{ + { DRM_MODE_CONNECTED, "connected" }, + { DRM_MODE_DISCONNECTED, "disconnected" }, + { DRM_MODE_UNKNOWNCONNECTION, "unknown" }, +}; + +struct type_name connector_type_names[] = +{ + { DRM_MODE_CONNECTOR_Unknown, "unknown" }, + { DRM_MODE_CONNECTOR_VGA, "VGA" }, + { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, + { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, + { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, + { DRM_MODE_CONNECTOR_Composite, "composite" }, + { DRM_MODE_CONNECTOR_SVIDEO, "s-video" }, + { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, + { DRM_MODE_CONNECTOR_Component, "component" }, + { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, + { DRM_MODE_CONNECTOR_DisplayPort, "displayport" }, + { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, + { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, + { DRM_MODE_CONNECTOR_TV, "TV" }, + { DRM_MODE_CONNECTOR_eDP, "embedded displayport" }, +}; + +extern char* secPlaneDump (char *reply, int *len); +extern char* secUtilDumpVideoBuffer (char *reply, int *len); + +static char * encoder_type_str (int type) +{ + int i; + for (i = 0; i < ARRAY_SIZE(encoder_type_names); i++) + { + if (encoder_type_names[i].type == type) + return encoder_type_names[i].name; + } + return "(invalid)"; +} + + +static char * connector_status_str (int type) +{ + int i; + for (i = 0; i < ARRAY_SIZE(connector_status_names); i++) + { + if (connector_status_names[i].type == type) + return connector_status_names[i].name; + } + return "(invalid)"; +} + +static char * connector_type_str (int type) +{ + int i; + for (i = 0; i < ARRAY_SIZE(connector_type_names); i++) + { + if (connector_type_names[i].type == type) + return connector_type_names[i].name; + } + return "(invalid)"; +} + +static char* dump_encoders(char *reply, int *len) +{ + drmModeEncoder *encoder; + drmModeRes *resources = test.resources; + int i; + + XDBG_REPLY ("Encoders:\n"); + XDBG_REPLY ("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n"); + for (i = 0; i < resources->count_encoders; i++) + { + encoder = test.encoders[i];; + + if (!encoder) + { + XDBG_REPLY ("could not get encoder %i\n", i); + continue; + } + XDBG_REPLY ("%d\t%d\t%s\t0x%08x\t0x%08x\n", + encoder->encoder_id, + encoder->crtc_id, + encoder_type_str(encoder->encoder_type), + encoder->possible_crtcs, + encoder->possible_clones); + } + + XDBG_REPLY ("\n"); + + return reply; +} + +static char* dump_mode(drmModeModeInfo *mode, char *reply, int *len) +{ + XDBG_REPLY (" %s %d %d %d %d %d %d %d %d %d\n", + mode->name, + mode->vrefresh, + mode->hdisplay, + mode->hsync_start, + mode->hsync_end, + mode->htotal, + mode->vdisplay, + mode->vsync_start, + mode->vsync_end, + mode->vtotal); + + return reply; +} + +static char* +dump_props(drmModeConnector *connector, char *reply, int *len) +{ + drmModePropertyPtr props; + int i; + + for (i = 0; i < connector->count_props; i++) + { + props = drmModeGetProperty(test.drm_fd, connector->props[i]); + if (props == NULL) + continue; + XDBG_REPLY ("\t%s, flags %d\n", props->name, props->flags); + drmModeFreeProperty(props); + } + + return reply; +} + +static char* dump_connectors(char *reply, int *len) +{ + drmModeConnector *connector; + drmModeRes *resources = test.resources; + int i, j; + + XDBG_REPLY ("Connectors:\n"); + XDBG_REPLY ("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\tencoders\n"); + for (i = 0; i < resources->count_connectors; i++) + { + connector = test.connectors[i]; + + if (!connector) + { + XDBG_REPLY ("could not get connector %i\n", i); + continue; + } + + XDBG_REPLY ("%d\t%d\t%s\t%s\t%dx%d\t\t%d\t", + connector->connector_id, + connector->encoder_id, + connector_status_str(connector->connection), + connector_type_str(connector->connector_type), + connector->mmWidth, connector->mmHeight, + connector->count_modes); + + for (j = 0; j < connector->count_encoders; j++) + XDBG_REPLY ("%s%d", j > 0 ? ", " : "", connector->encoders[j]); + XDBG_REPLY ("\n"); + + if (!connector->count_modes) + continue; + + XDBG_REPLY (" modes:\n"); + XDBG_REPLY (" name refresh (Hz) hdisp hss hse htot vdisp " + "vss vse vtot)\n"); + for (j = 0; j < connector->count_modes; j++) + reply = dump_mode(&connector->modes[j], reply, len); + + XDBG_REPLY (" props:\n"); + reply = dump_props(connector, reply, len); + } + XDBG_REPLY ("\n"); + + return reply; +} + +static char* dump_crtcs(char *reply, int *len) +{ + drmModeCrtc *crtc; + drmModeRes *resources = test.resources; + int i; + + XDBG_REPLY ("CRTCs:\n"); + XDBG_REPLY ("id\tfb\tpos\tsize\n"); + for (i = 0; i < resources->count_crtcs; i++) + { + crtc = test.crtcs[i]; + + if (!crtc) + { + XDBG_REPLY ("could not get crtc %i\n", i); + continue; + } + XDBG_REPLY ("%d\t%d\t(%d,%d)\t(%dx%d)\n", + crtc->crtc_id, + crtc->buffer_id, + crtc->x, crtc->y, + crtc->width, crtc->height); + reply = dump_mode(&crtc->mode, reply, len); + } + XDBG_REPLY ("\n"); + + return reply; +} + +static char* dump_framebuffers(char *reply, int *len) +{ + drmModeFB *fb; + drmModeRes *resources = test.resources; + int i; + + XDBG_REPLY ("Frame buffers:\n"); + XDBG_REPLY ("id\tsize\tpitch\n"); + for (i = 0; i < resources->count_fbs; i++) + { + fb = test.fbs[i]; + + if (!fb) + { + XDBG_REPLY ("could not get fb %i\n", i); + continue; + } + XDBG_REPLY ("%u\t(%ux%u)\t%u\n", + fb->fb_id, + fb->width, fb->height, + fb->pitch); + } + XDBG_REPLY ("\n"); + + return reply; +} + +static char* get_resources_all (char *reply, int *len) +{ + int i; + + /* get drm mode resources */ + test.resources = drmModeGetResources (test.drm_fd); + if (!test.resources) + { + XDBG_REPLY ("drmModeGetResources failed: %s\n", strerror(errno)); + return reply; + } + + /* get drm mode encoder */ + for (i = 0; i < test.resources->count_encoders; i++) + { + test.encoders[i] = drmModeGetEncoder (test.drm_fd, test.resources->encoders[i]); + if (!test.encoders[i]) + { + XDBG_REPLY ("fail to get encoder %i; %s\n", + test.resources->encoders[i], strerror(errno)); + continue; + } + } + + /* get drm mode connector */ + for (i = 0; i < test.resources->count_connectors; i++) + { + test.connectors[i] = drmModeGetConnector (test.drm_fd, test.resources->connectors[i]); + if (!test.connectors[i]) + { + XDBG_REPLY ("fail to get connector %i; %s\n", + test.resources->connectors[i], strerror(errno)); + continue; + } + } + + /* get drm mode crtc */ + for (i = 0; i < test.resources->count_crtcs; i++) + { + test.crtcs[i] = drmModeGetCrtc (test.drm_fd, test.resources->crtcs[i]); + if (!test.crtcs[i]) + { + XDBG_REPLY ("fail to get crtc %i; %s\n", + test.resources->crtcs[i], strerror(errno)); + continue; + } + } + + /* drm mode fb */ + for (i = 0; i < test.resources->count_fbs; i++) + { + test.fbs[i] = drmModeGetFB (test.drm_fd, test.resources->fbs[i]); + if (!test.fbs[i]) + { + XDBG_REPLY ("fail to get fb %i; %s\n", + test.resources->fbs[i], strerror(errno)); + continue; + } + } + + return reply; +} + +static void free_resources_all () +{ + int i; + + if (test.resources) + { + /* free drm mode fbs */ + for (i = 0; i < test.resources->count_fbs; i++) + if (test.fbs[i]) + { + drmModeFreeFB (test.fbs[i]); + test.fbs[i] = NULL; + } + + /* free drm mode crtcs */ + for (i = 0; i < test.resources->count_crtcs; i++) + if (test.crtcs[i]) + { + drmModeFreeCrtc (test.crtcs[i]); + test.crtcs[i] = NULL; + } + + /* free drm mode connectors */ + for (i = 0; i < test.resources->count_connectors; i++) + if (test.connectors[i]) + { + drmModeFreeConnector (test.connectors[i]); + test.connectors[i] = NULL; + } + + /* free drm mode encoders */ + for (i = 0; i < test.resources->count_encoders; i++) + if (test.encoders[i]) + { + drmModeFreeEncoder (test.encoders[i]); + test.encoders[i] = NULL; + } + + /* free drm mode resources */ + drmModeFreeResources (test.resources); + test.resources = NULL; + } +} + +void sec_drmmode_dump (int drm_fd, char *reply, int *len) +{ + int encoders, connectors, crtcs, modes, framebuffers; + + encoders = connectors = crtcs = modes = framebuffers = 1; + + test.drm_fd = drm_fd; + + get_resources_all (reply, len); + dump_resource(encoders, reply, len); + dump_resource(connectors, reply, len); + dump_resource(crtcs, reply, len); + dump_resource(framebuffers, reply, len); + + reply = secPlaneDump (reply, len); + reply = secUtilDumpVideoBuffer (reply, len); + + free_resources_all (); + +} diff --git a/src/debug/sec_drmmode_dump.h b/src/debug/sec_drmmode_dump.h new file mode 100644 index 0000000..b1493a9 --- /dev/null +++ b/src/debug/sec_drmmode_dump.h @@ -0,0 +1,36 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@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. + +**************************************************************************/ + +#ifndef __SEC_DRMMODE_DUMP_H_ +#define __SEC_DRMMODE_DUMP_H_ + +void sec_drmmode_dump (int drm_fd, char *reply, int *len); + +#endif diff --git a/src/g2d/fimg2d.c b/src/g2d/fimg2d.c new file mode 100644 index 0000000..a68347b --- /dev/null +++ b/src/g2d/fimg2d.c @@ -0,0 +1,670 @@ +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/mman.h> + +#include "xf86drm.h" +#include "xf86drmMode.h" +#include "exynos_drm.h" +#include "fimg2d.h" +#include "sec_util.h" + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 1 +#endif + +#define G2D_MAX_CMD 64 +#define G2D_MAX_GEM_CMD 64 +#define G2D_MAX_CMD_LIST 64 + +typedef struct _G2D_CONTEXT { + unsigned int major; + unsigned int minor; + int drm_fd; + + struct drm_exynos_g2d_cmd cmd[G2D_MAX_CMD]; + struct drm_exynos_g2d_cmd cmd_gem[G2D_MAX_GEM_CMD]; + + unsigned int cmd_nr; + unsigned int cmd_gem_nr; + + unsigned int cmdlist_nr; +}G2dContext; + +G2dContext* gCtx=NULL; + +static void +_g2d_clear(void) +{ + gCtx->cmd_nr = 0; + gCtx->cmd_gem_nr = 0; +} + +int +g2d_init (int fd) +{ + int ret; + struct drm_exynos_g2d_get_ver ver; + + if(gCtx) return FALSE; + + gCtx = calloc(1, sizeof(*gCtx)); + gCtx->drm_fd = fd; + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_G2D_GET_VER, &ver); + if (ret < 0) { + XDBG_ERROR (MG2D, "failed to get version: %s\n", strerror(-ret)); + free(gCtx); + gCtx = NULL; + + return FALSE; + } + + gCtx->major = ver.major; + gCtx->minor = ver.minor; + + XDBG_INFO (MG2D, "[G2D] version(%d.%d) init....OK\n", gCtx->major, gCtx->minor); + + return TRUE; +} + +void +g2d_fini (void) +{ + free(gCtx); + gCtx = NULL; +} + +int +g2d_add_cmd (unsigned int cmd, unsigned int value) +{ + switch(cmd) /* Check GEM Command */ + { + case SRC_BASE_ADDR_REG: + case SRC_PLANE2_BASE_ADDR_REG: + case DST_BASE_ADDR_REG: + case DST_PLANE2_BASE_ADDR_REG: + case PAT_BASE_ADDR_REG: + case MASK_BASE_ADDR_REG: + if(gCtx->cmd_gem_nr >= G2D_MAX_GEM_CMD) + { + XDBG_ERROR (MG2D, "Overflow cmd_gem size:%d\n", gCtx->cmd_gem_nr); + return FALSE; + } + + gCtx->cmd_gem[gCtx->cmd_gem_nr].offset = cmd; + gCtx->cmd_gem[gCtx->cmd_gem_nr].data = value; + gCtx->cmd_gem_nr++; + break; + default: + if(gCtx->cmd_nr >= G2D_MAX_CMD) + { + XDBG_ERROR (MG2D, "Overflow cmd size:%d\n", gCtx->cmd_nr); + return FALSE; + } + + gCtx->cmd[gCtx->cmd_nr].offset = cmd; + gCtx->cmd[gCtx->cmd_nr].data = value; + gCtx->cmd_nr++; + break; + } + + return TRUE; +} + +void +g2d_reset (unsigned int clear_reg) +{ + gCtx->cmd_nr = 0; + gCtx->cmd_gem_nr = 0; + + if(clear_reg) + { + g2d_add_cmd(SOFT_RESET_REG, 0x01); + } +} + +int +g2d_exec (void) +{ + struct drm_exynos_g2d_exec exec; + int ret; + + if(gCtx->cmdlist_nr == 0) + return TRUE; + + exec.async = 0; + ret = ioctl(gCtx->drm_fd, DRM_IOCTL_EXYNOS_G2D_EXEC, &exec); + if (ret < 0) { + XDBG_ERROR (MG2D, "failed to execute(%d): %s\n", ret, strerror(-ret)); + return FALSE; + } + + gCtx->cmdlist_nr = 0; + return TRUE; +} + +int +g2d_flush (void) +{ + int ret; + struct drm_exynos_g2d_set_cmdlist cmdlist; + + if (gCtx->cmd_nr == 0 && gCtx->cmd_gem_nr == 0) + return TRUE; + + if(gCtx->cmdlist_nr >= G2D_MAX_CMD_LIST) + { + XDBG_WARNING (MG2D, "Overflow cmdlist:%d\n", gCtx->cmdlist_nr); + g2d_exec(); + } + + memset(&cmdlist, 0, sizeof(struct drm_exynos_g2d_set_cmdlist)); + + cmdlist.cmd = (unsigned long)&gCtx->cmd[0]; + cmdlist.cmd_gem = (unsigned long)&gCtx->cmd_gem[0]; + cmdlist.cmd_nr = gCtx->cmd_nr; + cmdlist.cmd_gem_nr = gCtx->cmd_gem_nr; + cmdlist.event_type = G2D_EVENT_NOT; + cmdlist.user_data = 0; + + gCtx->cmd_nr = 0; + gCtx->cmd_gem_nr = 0; + ret = ioctl(gCtx->drm_fd, DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST, &cmdlist); + if (ret < 0) { + + XDBG_ERROR (MG2D, "numFlush:%d, failed to set cmdlist(%d): %s\n", gCtx->cmdlist_nr, ret, strerror(-ret)); + return FALSE; + } + + gCtx->cmdlist_nr++; + return TRUE; +} + +G2dImage* +g2d_image_new(void) +{ + G2dImage* img; + + img = calloc(1, sizeof(G2dImage)); + if(img == NULL) + { + XDBG_ERROR (MG2D, "Cannot create solid image\n"); + return NULL; + } + + img->repeat_mode = G2D_REPEAT_MODE_NONE; + img->scale_mode = G2D_SCALE_MODE_NONE; + img->xscale = G2D_FIXED_1; + img->yscale = G2D_FIXED_1; + + return img; +} + +G2dImage* +g2d_image_create_solid (unsigned int color) +{ + G2dImage* img; + + img = g2d_image_new(); + if(img == NULL) + { + XDBG_ERROR (MG2D, "Cannot create solid image\n"); + return NULL; + } + + img->select_mode = G2D_SELECT_MODE_FGCOLOR; + img->color_mode = G2D_COLOR_FMT_ARGB8888|G2D_ORDER_AXRGB; + img->data.color = color; + img->width = -1; + img->height = -1; + + return img; +} + +G2dImage* +g2d_image_create_bo (G2dColorMode format, unsigned int width, unsigned int height, + unsigned int bo, unsigned int stride) +{ + G2dImage* img; + + img = g2d_image_new(); + if(img == NULL) + { + XDBG_ERROR (MG2D, "Cannot alloc bo\n"); + return NULL; + } + + img->select_mode = G2D_SELECT_MODE_NORMAL; + img->color_mode = format; + img->width = width; + img->height = height; + + if(bo) + { + img->data.bo[0] = bo; + img->stride = stride; + } + else + { + unsigned int stride; + struct drm_exynos_gem_create arg; + + switch(format&G2D_COLOR_FMT_MASK) + { + case G2D_COLOR_FMT_XRGB8888: + case G2D_COLOR_FMT_ARGB8888: + stride = width*4; + break; + case G2D_COLOR_FMT_A1: + stride = (width+7) / 8; + break; + case G2D_COLOR_FMT_A4: + stride = (width*4+7) /8; + break; + case G2D_COLOR_FMT_A8: + case G2D_COLOR_FMT_L8: + stride = width; + break; + default: + XDBG_ERROR (MG2D, "Unsurpported format(%d)\n", format); + free(img); + return NULL; + } + + /* Allocation gem buffer */ + arg.flags = EXYNOS_BO_CACHABLE; + arg.size = stride*height; + if(drmCommandWriteRead(gCtx->drm_fd, DRM_EXYNOS_GEM_CREATE, &arg, sizeof(arg))) + { + XDBG_ERROR (MG2D, "Cannot create bo image(flag:%x, size:%d)\n", arg.flags, (unsigned int)arg.size); + free(img); + return NULL; + } + + /* Map gembuffer */ + { + struct drm_exynos_gem_mmap arg_map; + + memset(&arg_map, 0, sizeof(arg_map)); + arg_map.handle = arg.handle; + arg_map.size = arg.size; + if(drmCommandWriteRead(gCtx->drm_fd, DRM_EXYNOS_GEM_MMAP, &arg_map, sizeof(arg_map))) + { + XDBG_ERROR (MG2D, "Cannot map offset bo image\n"); + free(img); + return NULL; + } + + img->mapped_ptr[0] = (void*)(unsigned long)arg_map.mapped; + } + + img->stride = stride; + img->data.bo[0] = arg.handle; + img->need_free = 1; + } + + return img; +} + +G2dImage* +g2d_image_create_bo2 (G2dColorMode format, + unsigned int width, unsigned int height, + unsigned int bo1, unsigned int bo2, unsigned int stride) +{ + G2dImage* img; + + if (bo1 == 0) + { + XDBG_ERROR (MG2D, "[G2D] first bo is NULL. \n"); + return NULL; + } + + if (format & G2D_YCbCr_2PLANE) + if (bo2 == 0) + { + XDBG_ERROR (MG2D, "[G2D] second bo is NULL. \n"); + return NULL; + } + + img = g2d_image_new(); + + if(img == NULL) + { + XDBG_ERROR (MG2D, "Cannot alloc bo\n"); + return NULL; + } + + img->select_mode = G2D_SELECT_MODE_NORMAL; + img->color_mode = format; + img->width = width; + img->height = height; + + img->data.bo[0] = bo1; + img->data.bo[1] = bo2; + img->stride = stride; + + return img; +} + +G2dImage* +g2d_image_create_data (G2dColorMode format, unsigned int width, unsigned int height, + void* data, unsigned int stride) +{ + G2dImage* img; + + img = g2d_image_new(); + if(img == NULL) + { + XDBG_ERROR (MG2D, "Cannot alloc bo\n"); + return NULL; + } + + img->select_mode = G2D_SELECT_MODE_NORMAL; + img->color_mode = format; + img->width = width; + img->height = height; + + if(data) + { + struct drm_exynos_gem_userptr userptr; + + memset(&userptr, 0, sizeof(struct drm_exynos_gem_userptr)); + userptr.userptr = (uint64_t)((uint32_t)data); + userptr.size = stride*height; + + img->mapped_ptr[0] = data; + img->stride = stride; + if(drmCommandWriteRead(gCtx->drm_fd, + DRM_EXYNOS_GEM_USERPTR, + &userptr, sizeof(userptr))) + { + XDBG_ERROR (MG2D, "Cannot create userptr(ptr:%p, size:%d)\n", (void*)((uint32_t)userptr.userptr), (uint32_t)userptr.size); + free(img); + return NULL; + } + img->data.bo[0] = userptr.handle; + img->need_free = 1; + } + else + { + unsigned int stride; + struct drm_exynos_gem_create arg; + + switch(format&G2D_COLOR_FMT_MASK) + { + case G2D_COLOR_FMT_XRGB8888: + case G2D_COLOR_FMT_ARGB8888: + stride = width*4; + break; + case G2D_COLOR_FMT_A1: + stride = (width+7) / 8; + break; + case G2D_COLOR_FMT_A4: + stride = (width*4+7) /8; + break; + case G2D_COLOR_FMT_A8: + case G2D_COLOR_FMT_L8: + stride = width; + break; + default: + XDBG_ERROR (MG2D, "Unsurpported format(%d)\n", format); + free(img); + return NULL; + } + + /* Allocation gem buffer */ + arg.flags = EXYNOS_BO_NONCONTIG|EXYNOS_BO_CACHABLE; + arg.size = stride*height; + if(drmCommandWriteRead(gCtx->drm_fd, + DRM_EXYNOS_GEM_CREATE, + &arg, sizeof(arg))) + { + XDBG_ERROR (MG2D, "Cannot create bo image(flag:%x, size:%d)\n", arg.flags, (unsigned int)arg.size); + free(img); + return NULL; + } + + /* Map gembuffer */ + { + struct drm_exynos_gem_mmap arg_map; + + memset(&arg_map, 0, sizeof(arg_map)); + arg_map.handle = arg.handle; + arg_map.size = arg.size; + if(drmCommandWriteRead(gCtx->drm_fd, + DRM_EXYNOS_GEM_MMAP, + &arg_map, sizeof(arg_map))) + { + XDBG_ERROR (MG2D, "Cannot map offset bo image\n"); + free(img); + return NULL; + } + + img->mapped_ptr[0] = (void*)(unsigned long)arg_map.mapped; + } + + img->stride = stride; + img->data.bo[0] = arg.handle; + img->need_free = 1; + } + + return img; +} + +void +g2d_image_free (G2dImage* img) +{ + if(img->need_free) + { + struct drm_gem_close arg; + + /* Free gem buffer */ + memset(&arg, 0, sizeof(arg)); + arg.handle = img->data.bo[0]; + if(drmIoctl(gCtx->drm_fd, DRM_IOCTL_GEM_CLOSE, &arg)) + { + XDBG_ERROR (MG2D, "[G2D] %s:%d error: %d\n",__FUNCTION__, __LINE__, errno); + } + } + + free(img); +} + +int +g2d_set_src(G2dImage* img) +{ + if(img == NULL) return FALSE; + + g2d_add_cmd(SRC_SELECT_REG, img->select_mode); + g2d_add_cmd(SRC_COLOR_MODE_REG, img->color_mode); + + switch(img->select_mode) + { + case G2D_SELECT_MODE_NORMAL: + g2d_add_cmd(SRC_BASE_ADDR_REG, img->data.bo[0]); + if (img->color_mode & G2D_YCbCr_2PLANE) + { + if (img->data.bo[1] > 0) + g2d_add_cmd(SRC_PLANE2_BASE_ADDR_REG, img->data.bo[1]); + else + XDBG_ERROR (MG2D, "[G2D] %s:%d error: second bo is null.\n",__FUNCTION__, __LINE__); + } + g2d_add_cmd(SRC_STRIDE_REG, img->stride); + break; + case G2D_SELECT_MODE_FGCOLOR: + g2d_add_cmd(FG_COLOR_REG, img->data.color); + break; + case G2D_SELECT_MODE_BGCOLOR: + g2d_add_cmd(BG_COLOR_REG, img->data.color); + break; + default: + XDBG_ERROR (MG2D, "Error: set src\n"); + _g2d_clear(); + return FALSE; + } + + return TRUE; +} + +int +g2d_set_mask(G2dImage* img) +{ + G2dMaskModeVal mode; + + if(img == NULL) return FALSE; + if(img->select_mode != G2D_SELECT_MODE_NORMAL) return FALSE; + + g2d_add_cmd(MASK_BASE_ADDR_REG, img->data.bo[0]); + g2d_add_cmd(MASK_STRIDE_REG, img->stride); + + mode.val = 0; + switch(img->color_mode & G2D_COLOR_FMT_MASK) + { + case G2D_COLOR_FMT_A1: + mode.data.maskMode = G2D_MASK_MODE_1BPP; + break; + case G2D_COLOR_FMT_A4: + mode.data.maskMode = G2D_MASK_MODE_4BPP; + break; + case G2D_COLOR_FMT_A8: + mode.data.maskMode = G2D_MASK_MODE_8BPP; + break; + case G2D_COLOR_FMT_ARGB8888: + mode.data.maskMode = G2D_MASK_MODE_32BPP; + mode.data.maskOrder = (img->color_mode&G2D_ORDER_MASK)>>4; + break; + case G2D_COLOR_FMT_RGB565: + mode.data.maskMode = G2D_MASK_MODE_16BPP_565; + mode.data.maskOrder = (img->color_mode&G2D_ORDER_MASK)>>4; + break; + case G2D_COLOR_FMT_ARGB1555: + mode.data.maskMode = G2D_MASK_MODE_16BPP_1555; + mode.data.maskOrder = (img->color_mode&G2D_ORDER_MASK)>>4; + break; + case G2D_COLOR_FMT_ARGB4444: + mode.data.maskMode = G2D_MASK_MODE_16BPP_4444; + mode.data.maskOrder = (img->color_mode&G2D_ORDER_MASK)>>4; + break; + default: + break; + } + g2d_add_cmd(MASK_MODE_REG, mode.val); + + return TRUE; +} + +int +g2d_set_dst(G2dImage* img) +{ + if(img == NULL) return FALSE; + + g2d_add_cmd(DST_SELECT_REG, G2D_SELECT_MODE_FGCOLOR); + g2d_add_cmd(DST_COLOR_MODE_REG, img->color_mode); + + switch(img->select_mode) + { + case G2D_SELECT_MODE_NORMAL: + g2d_add_cmd(DST_BASE_ADDR_REG, img->data.bo[0]); + g2d_add_cmd(DST_STRIDE_REG, img->stride); + break; + case G2D_SELECT_MODE_FGCOLOR: + g2d_add_cmd(FG_COLOR_REG, img->data.color); + break; + case G2D_SELECT_MODE_BGCOLOR: + g2d_add_cmd(BG_COLOR_REG, img->data.color); + break; + default: + XDBG_ERROR (MG2D, "Error: set src\n"); + _g2d_clear(); + return FALSE; + } + + return TRUE; +} + +unsigned int +g2d_get_blend_op(G2dOp op) +{ + G2dBlendFunctionVal val; +#define set_bf(sc, si, scsa, scda, dc, di, dcsa, dcda) \ + val.data.srcCoeff = sc; \ + val.data.invSrcColorCoeff = si; \ + val.data.srcCoeffSrcA = scsa; \ + val.data.srcCoeffDstA = scda; \ + val.data.dstCoeff = dc; \ + val.data.invDstColorCoeff = di; \ + val.data.dstCoeffSrcA = dcsa; \ + val.data.dstCoeffDstA = dcda + + val.val = 0; + switch (op) + { + case G2D_OP_CLEAR: + case G2D_OP_DISJOINT_CLEAR: + case G2D_OP_CONJOINT_CLEAR: + set_bf (G2D_COEFF_MODE_ZERO, 0,0,0, + G2D_COEFF_MODE_ZERO, 0,0,0); + break; + case G2D_OP_SRC: + case G2D_OP_DISJOINT_SRC: + case G2D_OP_CONJOINT_SRC: + set_bf (G2D_COEFF_MODE_ONE, 0,0,0, + G2D_COEFF_MODE_ZERO, 0,0,0); + break; + case G2D_OP_DST: + case G2D_OP_DISJOINT_DST: + case G2D_OP_CONJOINT_DST: + set_bf (G2D_COEFF_MODE_ZERO, 0,0,0, + G2D_COEFF_MODE_ONE, 0,0,0); + break; + case G2D_OP_OVER: + set_bf (G2D_COEFF_MODE_ONE, 0,0,0, + G2D_COEFF_MODE_SRC_ALPHA, 1,0,0); + break; + case G2D_OP_OVER_REVERSE: + case G2D_OP_IN: + case G2D_OP_IN_REVERSE: + case G2D_OP_OUT: + case G2D_OP_OUT_REVERSE: + case G2D_OP_ATOP: + case G2D_OP_ATOP_REVERSE: + case G2D_OP_XOR: + case G2D_OP_ADD: + case G2D_OP_NONE: + default: + XDBG_ERROR (MG2D, "[FIMG2D] Not support op:%d\n", op); + set_bf (G2D_COEFF_MODE_ONE, 0,0,0, + G2D_COEFF_MODE_ZERO, 0,0,0); + break; + } +#undef set_bf + + return val.val; +} + +void +g2d_dump(void) +{ + int i; + XDBG_DEBUG (MG2D, "==================\n"); + XDBG_DEBUG (MG2D, " G2D REG DUMP \n"); + XDBG_DEBUG (MG2D, "==================\n"); + + for(i=0; i<gCtx->cmd_gem_nr; i++) + { + XDBG_DEBUG (MG2D, "[GEM] 0x%08x 0x%08x\n", + gCtx->cmd_gem[i].offset, gCtx->cmd_gem[i].data); + } + + for(i=0; i<gCtx->cmd_nr; i++) + { + XDBG_DEBUG (MG2D, "[CMD] 0x%08x 0x%08x\n", + gCtx->cmd[i].offset, gCtx->cmd[i].data); + } +} diff --git a/src/g2d/fimg2d.h b/src/g2d/fimg2d.h new file mode 100755 index 0000000..ada1c2f --- /dev/null +++ b/src/g2d/fimg2d.h @@ -0,0 +1,670 @@ +#ifndef _FIMG2D_H_ +#define _FIMG2D_H_ + +#include "fimg2d_reg.h" + +typedef unsigned int G2dFixed; + +typedef enum { + G2D_INT_MODE_LEVEL, + G2D_INT_MODE_EDGE, + + G2D_INT_MODE_MAX = G2D_INT_MODE_EDGE +} G2dIntMode; + +typedef enum { + G2D_TRANSPARENT_MODE_OPAQUE, + G2D_TRANSPARENT_MODE_TRANSPARENT, + G2D_TRANSPARENT_MODE_BLUESCREEN, + G2D_TRANSPARENT_MODE_MAX +} G2dTransparentMode; + +typedef enum { + G2D_COLORKEY_MODE_DISABLE = 0, + G2D_COLORKEY_MODE_SRC_RGBA = (1<<0), + G2D_COLORKEY_MODE_DST_RGBA = (1<<1), + G2D_COLORKEY_MODE_SRC_YCbCr = (1<<2), /* VER4.1 */ + G2D_COLORKEY_MODE_DST_YCbCr = (1<<3), /* VER4.1 */ + + G2D_COLORKEY_MODE_MASK = 15, +} G2dColorKeyMode; + +typedef enum { + G2D_ALPHA_BLEND_MODE_DISABLE, + G2D_ALPHA_BLEND_MODE_ENABLE, + G2D_ALPHA_BLEND_MODE_FADING, /* VER3.0 */ + G2D_ALPHA_BLEND_MODE_MAX +} G2dAlphaBlendMode; + +typedef enum { + G2D_SRC_NONPREBLAND_MODE_DISABLE, /* VER3.0 */ + G2D_SRC_NONPREBLAND_MODE_CONSTANT, /* VER3.0 */ + G2D_SRC_NONPREBLAND_MODE_PERPIXEL, /* VER3.0 */ + G2D_SRC_NONPREBLAND_MODE_MAX, /* VER3.0 */ +} G2dSrcNonPreBlendMode; + +typedef enum { + G2D_SELECT_SRC_FOR_ALPHA_BLEND, /* VER4.1 */ + G2D_SELECT_ROP_FOR_ALPHA_BLEND, /* VER4.1 */ +} G2dSelectAlphaSource; + + +typedef enum { /* VER4.1 */ + G2D_COEFF_MODE_ONE, + G2D_COEFF_MODE_ZERO, + G2D_COEFF_MODE_SRC_ALPHA, + G2D_COEFF_MODE_SRC_COLOR, + G2D_COEFF_MODE_DST_ALPHA, + G2D_COEFF_MODE_DST_COLOR, + G2D_COEFF_MODE_GB_ALPHA, /* Global Alpha : Set by ALPHA_REG(0x618) */ + G2D_COEFF_MODE_GB_COLOR, /* Global Alpha : Set by ALPHA_REG(0x618) */ + G2D_COEFF_MODE_DISJOINT_S, /* (1-SRC alpha)/DST Alpha */ + G2D_COEFF_MODE_DISJOINT_D, /* (1-DST alpha)/SRC Alpha */ + G2D_COEFF_MODE_CONJOINT_S, /* SRC alpha/DST alpha */ + G2D_COEFF_MODE_CONJOINT_D, /* DST alpha/SRC alpha */ + G2D_COEFF_MODE_MASK +}G2dCoeffMode; + +typedef enum { + G2D_ACOEFF_MODE_A, /*alpha*/ + G2D_ACOEFF_MODE_APGA, /*alpha + global alpha*/ + G2D_ACOEFF_MODE_AMGA, /*alpha * global alpha*/ + G2D_ACOEFF_MODE_MASK +}G2dACoeffMode; + +typedef enum { + G2D_SELECT_MODE_NORMAL = (0 << 0), + G2D_SELECT_MODE_FGCOLOR = (1 << 0), + G2D_SELECT_MODE_BGCOLOR = (2 << 0), + G2D_SELECT_MODE_MAX = (3 << 0), +} G2dSelectMode; + +typedef enum { + /* COLOR FORMAT */ + G2D_COLOR_FMT_XRGB8888, + G2D_COLOR_FMT_ARGB8888, + G2D_COLOR_FMT_RGB565, + G2D_COLOR_FMT_XRGB1555, + G2D_COLOR_FMT_ARGB1555, + G2D_COLOR_FMT_XRGB4444, + G2D_COLOR_FMT_ARGB4444, + G2D_COLOR_FMT_PRGB888, + G2D_COLOR_FMT_YCbCr444, + G2D_COLOR_FMT_YCbCr422, + G2D_COLOR_FMT_YCbCr420=10, + G2D_COLOR_FMT_A8, /* alpha 8bit */ + G2D_COLOR_FMT_L8, /* Luminance 8bit: gray color */ + G2D_COLOR_FMT_A1, /* alpha 1bit */ + G2D_COLOR_FMT_A4, /* alpha 4bit */ + G2D_COLOR_FMT_MASK = (15 << 0), /* VER4.1 */ + + /* COLOR ORDER */ + G2D_ORDER_AXRGB = (0 << 4), /* VER4.1 */ + G2D_ORDER_RGBAX = (1 << 4), /* VER4.1 */ + G2D_ORDER_AXBGR = (2 << 4), /* VER4.1 */ + G2D_ORDER_BGRAX = (3 << 4), /* VER4.1 */ + G2D_ORDER_MASK = (3 << 4), /* VER4.1 */ + + /* Number of YCbCr plane */ + G2D_YCbCr_1PLANE = (0 << 8), /* VER4.1 */ + G2D_YCbCr_2PLANE = (1 << 8), /* VER4.1 */ + G2D_YCbCr_PLANE_MASK = (3 << 8), /* VER4.1 */ + + /* Order in YCbCr */ + G2D_YCbCr_ORDER_CrY1CbY0 = (0 << 12), /* VER4.1 */ + G2D_YCbCr_ORDER_CbY1CrY0 = (1 << 12), /* VER4.1 */ + G2D_YCbCr_ORDER_Y1CrY0Cb = (2 << 12), /* VER4.1 */ + G2D_YCbCr_ORDER_Y1CbY0Cr = (3 << 12), /* VER4.1 */ + G2D_YCbCr_ORDER_CrCb = G2D_YCbCr_ORDER_CrY1CbY0, /* VER4.1, for 2 plane */ + G2D_YCbCr_ORDER_CbCr = G2D_YCbCr_ORDER_CbY1CrY0, /* VER4.1, for 2 plane */ + G2D_YCbCr_ORDER_MASK = (3 < 12), /* VER4.1 */ + + /* CSC */ + G2D_CSC_601 = (0 << 16), /* VER4.1 */ + G2D_CSC_709 = (1 << 16), /* VER4.1 */ + G2D_CSC_MASK = (1 << 16), /* VER4.1 */ + + /* Valid value range of YCbCr */ + G2D_YCbCr_RANGE_NARROW = (0 << 17), /* VER4.1 */ + G2D_YCbCr_RANGE_WIDE = (1 << 17), /* VER4.1 */ + G2D_YCbCr_RANGE_MASK= (1 << 17), /* VER4.1 */ + + G2D_COLOR_MODE_MASK = 0xFFFFFFFF +}G2dColorMode; + +typedef enum { + G2D_SCALE_MODE_NONE = 0, + G2D_SCALE_MODE_NEAREST, + G2D_SCALE_MODE_BILINEAR, + + G2D_SCALE_MODE_MAX +} G2dScaleMode; + +typedef enum { + G2D_REPEAT_MODE_REPEAT, + G2D_REPEAT_MODE_PAD, + G2D_REPEAT_MODE_REFLECT, + G2D_REPEAT_MODE_CLAMP, + G2D_REPEAT_MODE_NONE, +} G2dRepeatMode; + +typedef enum { + G2D_MASK_OP_ALPHA_ONLY, + G2D_MASK_OP_CMPONENT, + G2D_MASK_OP_CHANNEL, + + G2D_MASK_OP_MAX +} G2dMaskOpType; + +typedef enum { + G2D_MASK_ORDER_AXRGB, + G2D_MASK_ORDER_RGBAX, + G2D_MASK_ORDER_AXBGR, + G2D_MASK_ORDER_BGRAX, + + G2D_MASK_ORDER_MAX +} G2dMaskOrder; + +typedef enum { + G2D_MASK_MODE_1BPP = 0, + G2D_MASK_MODE_4BPP, + G2D_MASK_MODE_8BPP, + G2D_MASK_MODE_16BPP_565, + G2D_MASK_MODE_16BPP_1555, + G2D_MASK_MODE_16BPP_4444, + G2D_MASK_MODE_32BPP, + G2D_MASK_MODE_4BPP_FOR_WINCE, /* ([31:24]bit field of 32bit is used as mask) */ + + G2D_MASK_MODE_MAX +} G2dMaskMode; + +/* +Here are some examples on how to use the ROP3 value to perform the operations: +1) Final Data = Source. Only the Source data matter, so ROP Value = "0xCC". +2) Final Data = Destination. Only the Destination data matter, so ROP Value = "0xAA". +3) Final Data = Pattern. Only the Pattern data matter, so ROP Value = "0xF0". +4) Final Data = Source AND Destination. ROP Value = "0xCC" & "0xAA" = "0x88" +5) Final Data = Source OR Pattern. ROP Value = "0xCC" | "0xF0" = "0xFC". +*/ +typedef enum G2D_ROP3_TYPE { + G2D_ROP3_DST = 0xAA, + G2D_ROP3_SRC = 0xCC, + G2D_ROP3_3RD = 0xF0, + + G2D_ROP3_MASK = 0xFF +} G2dROP3Type; + +typedef enum G2D_ALU { + /*Common alu for x base*/ + G2Dclear = 0x0, /* 0 */ + G2Dand = 0x1, /* src AND dst */ + G2DandReverse = 0x2, /* src AND NOT dst */ + G2Dcopy = 0x3, /* src */ + G2DandInverted = 0x4, /* NOT src AND dst */ + G2Dnoop = 0x5, /* dst */ + G2Dxor = 0x6, /* src XOR dst */ + G2Dor = 0x7, /* src OR dst */ + G2Dnor = 0x8, /* NOT src AND NOT dst */ + G2Dequiv = 0x9, /* NOT src XOR dst */ + G2Dinvert = 0xa, /* NOT dst */ + G2DorReverse = 0xb, /* src OR NOT dst */ + G2DcopyInverted = 0xc, /* NOT src */ + G2DorInverted = 0xd, /* NOT src OR dst */ + G2Dnand = 0xe, /* NOT src OR NOT dst */ + G2Dset = 0xf, /* 1 */ + + /*Special alu*/ + G2Dnegative = 0x20, /*NOT src XOR 0x00FFFFFF*/ +}G2dAlu; + +typedef union _G2D_BITBLT_CMD_VAL { + unsigned int val; + struct { + /* [0:3] */ + unsigned int maskROP4En:1; + unsigned int maskingEn:1; + G2dSelectAlphaSource ROP4AlphaEn:1; + unsigned int ditherEn:1; + /* [4:7] */ + unsigned int resolved1:4; + /* [8:11] */ + unsigned int cwEn:4; + /* [12:15] */ + G2dTransparentMode transparentMode:4; + /* [16:19] */ + G2dColorKeyMode colorKeyMode:4; + /* [20:23] */ + G2dAlphaBlendMode alphaBlendMode:4; + /* [24:27] */ + unsigned int srcPreMultiply:1; + unsigned int patPreMultiply:1; + unsigned int dstPreMultiply:1; + unsigned int dstDepreMultiply:1; + /* [28:31] */ + unsigned int fastSolidColorFillEn:1; + unsigned int reserved:3; + }data; +} G2dBitBltCmdVal; + +typedef union _G2D_BLEND_FUNCTION_VAL { + unsigned int val; + struct { + /* [0:15] */ + G2dCoeffMode srcCoeff:4; + G2dACoeffMode srcCoeffSrcA:2; + G2dACoeffMode srcCoeffDstA:2; + G2dCoeffMode dstCoeff:4; + G2dACoeffMode dstCoeffSrcA:2; + G2dACoeffMode dstCoeffDstA:2; + /* [16:19] */ + unsigned int invSrcColorCoeff:1; + unsigned int resoled1:1; + unsigned int invDstColorCoeff:1; + unsigned int resoled2:1; + /* [20:23] */ + unsigned int lightenEn:1; + unsigned int darkenEn:1; + unsigned int winCESrcOverEn:2; + /* [24:31] */ + unsigned int reserved:8; + }data; +} G2dBlendFunctionVal; + +typedef union _G2D_ROUND_MODE_VAL { + unsigned int val; + struct { + /* + Round Mode in Blending + 2'b00 : + Result = ((A + 1) * B) >>8; + 2'b01 : + Result = ((A+ (A>>7)) * B) >>8; + 2'b10 : + Result_tmp = A * B + 0x80; + Result = (Result_tmp + (Result_tmp>>8))>>8; + 2'b11 : + Result_A = A * B; (16 bpp) + Result_B = C * D; (16 bpp) + Result_tmp = Result_A + Result_B + 0x80; + Result = (Result_tmp + (Result_tmp>>8))>>8; + */ + unsigned int blend:4; + /* + Round Mode in Alpha Premultiply + 2'b00 : + Result = (A * B) >>8; + 2'b01 : + Result = ((A + 1) * B) >>8; + 2'b10 : + Result = ((A+ (A>>7)) * B) >>8; + 2'b11 : + Result_tmp = A * B + 0x80; + Result = (Result_tmp + (Result_tmp>>8))>>8; + */ + unsigned int alphaPremultiply:4; + /* + Round Mode in Alpha Depremultiply + 2'b00 : + Result = ((A + 1) * B) >>8; + 2'b01 : + Result = ((A+ (A>>7)) * B) >>8; + 2'b10 : + Result_tmp = A * B + 0x80; + Result = (Result_tmp + (Result_tmp>>8))>>8; + 2'b11 : Reserved + */ + unsigned int alphaDepremultiply:4; + + unsigned int reserved:20; + }data; +} G2dRoundModeVal; + +typedef union _G2D_ROTATE_VAL { + unsigned int val; + struct { + /* + 0 : No rotation + 1 : 90 degree rotation + */ + unsigned int srcRotate:4; + unsigned int patRotate:4; + unsigned int maskRotate:4; + + unsigned int reserved:20; + }data; +} G2dRotateVal; + +typedef union _G2D_SRC_MASK_DIR_VAL { + unsigned int val; + struct { + unsigned int dirSrcX:1; + unsigned int dirSrcY:1; + unsigned int reserved1:2; + + unsigned int dirMaskX:1; + unsigned int dirMaskY:1; + unsigned int reserved2:2; + + unsigned int reserved:24; + }data; +} G2dSrcMaskDirVal; + +typedef union _G2D_DST_PAT_DIR_VAL { + unsigned int val; + struct { + unsigned int dirDstX:1; + unsigned int dirDstY:1; + unsigned int reserved1:2; + + unsigned int dirPatX:1; + unsigned int dirPatY:1; + unsigned int reserved2:2; + + unsigned int reserved:24; + }data; +} G2dDstPatDirVal; + +typedef union G2D_POINT_VAL { + unsigned int val; + struct { + /* + X Coordinate of Source Image + Range: 0 ~ 8000 (Requirement: SrcLeftX < SrcRightX) + In YCbCr 422 and YCbCr 420 format, this value should be even number. + */ + unsigned int x:16; + /* + Y Coordinate of Source Image + Range: 0 ~ 8000 (Requirement: SrcTopY < SrcBottomY) + In YCbCr 420 format, this value should be even number. + */ + unsigned int y:16; + }data; +} G2dPointVal; + +typedef union G2D_BOX_SIZE_VAL { + unsigned int val; + struct { + /* + Width of box. Range: 1 ~ 8000. + */ + unsigned int width:16; + /* + Height of box. Range: 1 ~ 8000. + */ + unsigned int height:16; + }data; +} G2dBoxSizeVal; + +typedef union _G2D_SELECT_3RD_VAL { + unsigned int val; + struct{ + G2dSelectMode unmasked:4; + G2dSelectMode masked:4; + + unsigned int reserved:24; + }data; +} G2dSelect3rdVal; + +typedef union _G2D_ROP4_VAL { + unsigned int val; + struct{ + G2dROP3Type unmaskedROP3:8; + G2dROP3Type maskedROP3:8; + + unsigned int reserved:16; + }data; +} G2dROP4Val; + +typedef union _G2D_MASK_MODE_VAL { + unsigned int val; + struct{ + /* [0:7] */ + G2dMaskMode maskMode:4; + G2dMaskOrder maskOrder:4; + /* [8:11] */ + G2dMaskOpType maskOp:4; + /* [12:31] */ + unsigned int reserved:20; + }data; +} G2dMaskModeVal; + +typedef union _G2D_GLOBAL_ARGB_VAL { + unsigned int val; + struct{ + unsigned int alpha:8; + unsigned int color:24; + }data; +} G2dGlovalARGBVal; + +typedef union _G2D_COLORKEY_CTL_VAL { + unsigned int val; + struct{ + /* + 0: Stencil Test Off for each RGBA value + 1: Stencil Test On for each RGBA value + */ + unsigned int stencilOnB:4; + unsigned int stencilOnG:4; + unsigned int stencilOnR:4; + unsigned int stencilOnA:4; + unsigned int stencilInv:4; + + unsigned int reserved:12; + }data; +} G2dColorkeyCtlVal; + +typedef union _G2D_COLORKEY_DR_MIN_VAL { + unsigned int val; + struct{ + /* + The color format of source colorkey decision reference register is generally the same as the source color format. + If the color format of source is YCbCr format, the color format of this register is ARGB_8888 format. + But if the source color is selected as the foreground color or the background color, + the source colorkey operation is not activated because the colorkeying for the foreground color + and the background color set by user is meaningless. + */ + unsigned int drMinB:8; + unsigned int drMinG:8; + unsigned int drMinR:8; + unsigned int drMinA:8; + }data; +} G2dColorkeyDrMinVal; + +typedef union _G2D_COLORKEY_DR_MAX_VAL { + unsigned int val; + struct{ + /* + The color format of source colorkey decision reference register is generally the same as the source color format. + If the color format of source is YCbCr format, the color format of this register is ARGB_8888 format. + But if the source color is selected as the foreground color or the background color, + the source colorkey operation is not activated because the colorkeying for the foreground color and + the background color set by user is meaningless. + */ + unsigned int drMaxB:8; + unsigned int drMaxG:8; + unsigned int drMaxR:8; + unsigned int drMaxA:8; + }data; +} G2dColorkeyDrMaxVal; + +typedef union _G2D_COLORKEY_YCBCR_CTL_VAL { + unsigned int val; + struct{ + unsigned int stencilOnCr:4; + unsigned int stencilOnCb:4; + unsigned int stencilOnY:4; + unsigned int stencilInv:4; + + unsigned int reserved:16; + }data; +} G2dColorkeyYCbCrCtlVal; + +typedef union _G2D_COLORKEY_YCBCR_DR_MIN_VAL { + unsigned int val; + struct{ + unsigned int drMinCr:8; + unsigned int drMinCb:8; + unsigned int drMinY:8; + + unsigned int reserved:8; + }data; +} G2dColorkeyYCbCrDrMinVal; + +typedef union _G2D_COLORKEY_YCBCR_DR_MAX_VAL { + unsigned int val; + struct{ + unsigned int drMaxCr:8; + unsigned int drMaxCb:8; + unsigned int drMaxY:8; + + unsigned int reserved:8; + }data; +} G2dColorkeyYCbCrDrMaxVal; + +typedef enum { + G2D_OP_CLEAR = 0x00, + G2D_OP_SRC = 0x01, + G2D_OP_DST = 0x02, + G2D_OP_OVER = 0x03, + G2D_OP_OVER_REVERSE = 0x04, + G2D_OP_IN = 0x05, + G2D_OP_IN_REVERSE = 0x06, + G2D_OP_OUT = 0x07, + G2D_OP_OUT_REVERSE = 0x08, + G2D_OP_ATOP = 0x09, + G2D_OP_ATOP_REVERSE = 0x0a, + G2D_OP_XOR = 0x0b, + G2D_OP_ADD = 0x0c, + G2D_OP_SATURATE = 0x0d, + + G2D_OP_DISJOINT_CLEAR = 0x10, + G2D_OP_DISJOINT_SRC = 0x11, + G2D_OP_DISJOINT_DST = 0x12, + G2D_OP_DISJOINT_OVER = 0x13, + G2D_OP_DISJOINT_OVER_REVERSE = 0x14, + G2D_OP_DISJOINT_IN = 0x15, + G2D_OP_DISJOINT_IN_REVERSE = 0x16, + G2D_OP_DISJOINT_OUT = 0x17, + G2D_OP_DISJOINT_OUT_REVERSE = 0x18, + G2D_OP_DISJOINT_ATOP = 0x19, + G2D_OP_DISJOINT_ATOP_REVERSE = 0x1a, + G2D_OP_DISJOINT_XOR = 0x1b, + + G2D_OP_CONJOINT_CLEAR = 0x20, + G2D_OP_CONJOINT_SRC = 0x21, + G2D_OP_CONJOINT_DST = 0x22, + G2D_OP_CONJOINT_OVER = 0x23, + G2D_OP_CONJOINT_OVER_REVERSE = 0x24, + G2D_OP_CONJOINT_IN = 0x25, + G2D_OP_CONJOINT_IN_REVERSE = 0x26, + G2D_OP_CONJOINT_OUT = 0x27, + G2D_OP_CONJOINT_OUT_REVERSE = 0x28, + G2D_OP_CONJOINT_ATOP = 0x29, + G2D_OP_CONJOINT_ATOP_REVERSE = 0x2a, + G2D_OP_CONJOINT_XOR = 0x2b, + + G2D_N_OPERATORS, + G2D_OP_NONE = G2D_N_OPERATORS +}G2dOp; +#define G2D_OP_DEFAULT G2D_OP_NONE + +#define G2D_PLANE_MAX 2 + +typedef struct _G2D_IMAGE G2dImage; +struct _G2D_IMAGE { + G2dSelectMode select_mode; + G2dColorMode color_mode; + G2dRepeatMode repeat_mode; + + G2dFixed xscale; + G2dFixed yscale; + G2dScaleMode scale_mode; + + unsigned char rotate_90; + unsigned char xDir; + unsigned char yDir; + unsigned char componentAlpha; + + unsigned int width; + unsigned int height; + unsigned int stride; + + unsigned int need_free; + union{ + unsigned int color; + unsigned int bo[G2D_PLANE_MAX]; + }data; + + void *mapped_ptr[G2D_PLANE_MAX]; +}; + +#define G2D_PT(_x, _y) ( (unsigned int)(_y<<16|_x<<0)) + +#define G2D_FIXED_1 (1<<16) +#define G2D_DOUBLE_TO_FIXED(_d) ((G2dFixed)((_d) * 65536.0)) +#define G2D_INT_TO_FIXED(_i) ((G2dFixed)((_i) << 16)) +#define G2D_FIXED_TO_DOUBLE(_f) (double) ((_f) / (double) G2D_FIXED_1) +#define G2D_FIXED_TO_INT(_f) ((int) ((_f) >> 16)) + +int g2d_init(int fd); +void g2d_fini(void); +int g2d_add_cmd(unsigned int cmd, unsigned int value); +void g2d_reset (unsigned int clear_reg); +int g2d_exec(void); +int g2d_flush(void); +void g2d_dump(void); + +G2dImage* g2d_image_create_solid(unsigned int color); +G2dImage* g2d_image_create_bo(G2dColorMode format, + unsigned int width, unsigned int height, + unsigned int bo, unsigned int stride); +G2dImage* g2d_image_create_bo2 (G2dColorMode format, + unsigned int width, unsigned int height, + unsigned int bo1, unsigned int bo2, unsigned int stride); +G2dImage* g2d_image_create_data (G2dColorMode format, + unsigned int width, unsigned int height, + void* data, unsigned int stride); + +void g2d_image_free (G2dImage* img); + +int g2d_set_src(G2dImage* img); +int g2d_set_dst(G2dImage* img); +int g2d_set_mask(G2dImage* img); +unsigned int g2d_get_blend_op(G2dOp op); + +/* UTIL Functions */ +void util_g2d_fill(G2dImage* img, + int x, int y, unsigned int w, unsigned int h, + unsigned int color); +void util_g2d_fill_alu(G2dImage* img, + int x, int y, unsigned int w, unsigned int h, + unsigned int color, G2dAlu alu); +void util_g2d_copy(G2dImage* src, G2dImage* dst, + int src_x, int src_y, + int dst_x, int dst_y, + unsigned int width, unsigned int height); +void util_g2d_copy_alu(G2dImage* src, G2dImage* dst, + int src_x, int src_y, + int dst_x, int dst_y, + unsigned int width, unsigned int height, + G2dAlu alu); +void util_g2d_copy_with_scale(G2dImage* src, G2dImage* dst, + int src_x, int src_y, unsigned int src_w, unsigned int src_h, + int dst_x, int dst_y, unsigned int dst_w, unsigned int dst_h, + int negative); +void util_g2d_blend(G2dOp op, G2dImage* src, G2dImage* dst, + int src_x, int src_y, + int dst_x, int dst_y, + unsigned int width, unsigned int height); +void util_g2d_blend_with_scale(G2dOp op, G2dImage* src, G2dImage* dst, + int src_x, int src_y, unsigned int src_w, unsigned int src_h, + int dst_x, int dst_y, unsigned int dst_w, unsigned int dst_h, + int negative); +void util_g2d_composite(G2dOp op, G2dImage* src, G2dImage* mask, G2dImage* dst, + int src_x, int src_y, + int mask_x, int mask_y, + int dst_x, int dst_y, + unsigned int width, unsigned int height); + +#endif /* _FIMG2D3X_H_ */ diff --git a/src/g2d/fimg2d_reg.h b/src/g2d/fimg2d_reg.h new file mode 100755 index 0000000..97813c8 --- /dev/null +++ b/src/g2d/fimg2d_reg.h @@ -0,0 +1,120 @@ +#ifndef _FIMG2D_HW_H_ +#define _FIMG2D_HW_H_ + +/* Registers */ +/* +* GEBERAL REGISTER +*/ +#define SOFT_RESET_REG (0x0000) +#define INTEN_REG (0x0004) +#define INTC_PEND_REG (0x000c) +#define FIFO_STAT_REG (0x0010) +#define AXI_MODE_REG (0x001C) +#define DMA_SFR_BASE_ADDR_REG (0x0080) +#define DMA_COMMAND_REG (0x0084) +#define DMA_EXE_LIST_NUM_REG (0x0088) +#define DMA_STATUS_REG (0x008C) +#define DMA_HOLD_CMD_REG (0x0090) + +/* +* COMMAND REGISTER +*/ +#define BITBLT_START_REG (0x0100) +#define BITBLT_COMMAND_REG (0x0104) +#define BLEND_FUNCTION_REG (0x0108) /* VER4.1 */ +#define ROUND_MODE_REG (0x010C) /* VER4.1 */ + +/* +* PARAMETER SETTING REGISTER +*/ + +/* ROTATE and DIRECTION*/ +#define ROTATE_REG (0x0200) +#define SRC_MASK_DIRECT_REG (0x0204) +#define DST_PAT_DIRECT_REG (0x0208) + +/* SOURCE */ +#define SRC_SELECT_REG (0x0300) +#define SRC_BASE_ADDR_REG (0x0304) +#define SRC_STRIDE_REG (0x0308) +#define SRC_COLOR_MODE_REG (0x030c) +#define SRC_LEFT_TOP_REG (0x0310) +#define SRC_RIGHT_BOTTOM_REG (0x0314) +#define SRC_PLANE2_BASE_ADDR_REG (0x0318) /* VER4.1 */ +#define SRC_REPEAT_MODE_REG (0x031C) +#define SRC_PAD_VALUE_REG (0x0320) +#define SRC_A8_RGB_EXT_REG (0x0324) +#define SRC_SCALE_CTRL_REG (0x0328) +#define SRC_XSCALE_REG (0x032C) +#define SRC_YSCALE_REG (0x0330) + +/* DESTINATION */ +#define DST_SELECT_REG (0x0400) +#define DST_BASE_ADDR_REG (0x0404) +#define DST_STRIDE_REG (0x0408) +#define DST_COLOR_MODE_REG (0x040C) +#define DST_LEFT_TOP_REG (0x0410) +#define DST_RIGHT_BOTTOM_REG (0x0414) +#define DST_PLANE2_BASE_ADDR_REG (0x0418) /* VER4.1 */ +#define DST_A8_RGB_EXT_REG (0x041C) + +/* PATTERN */ +#define PAT_BASE_ADDR_REG (0x0500) +#define PAT_SIZE_REG (0x0504) +#define PAT_COLOR_MODE_REG (0x0508) +#define PAT_OFFSET_REG (0x050C) +#define PAT_STRIDE_REG (0x0510) + +/* MASK */ +#define MASK_BASE_ADDR_REG (0x0520) +#define MASK_STRIDE_REG (0x0524) +#define MASK_LEFT_TOP_REG (0x0528) /* VER4.1 */ +#define MASK_RIGHT_BOTTOM_REG (0x052C) /* VER4.1 */ +#define MASK_MODE_REG (0x0530) /* VER4.1 */ +#define MASK_REPEAT_MODE_REG (0x0534) +#define MASK_PAD_VALUE_REG (0x0538) +#define MASK_SCALE_CTRL_REG (0x053C) +#define MASK_XSCALE_REG (0x0540) +#define MASK_YSCALE_REG (0x0544) + +/* +* CLIPPING WINDOW +*/ +#define CW_LT_REG (0x0600) +#define CW_RB_REG (0x0604) + +/* +* ROP & ALPHA SETTING +*/ +#define THIRD_OPERAND_REG (0x0610) +#define ROP4_REG (0x0614) +#define ALPHA_REG (0x0618) + +/* +* COLOR SETTING +*/ +#define FG_COLOR_REG (0x0700) +#define BG_COLOR_REG (0x0704) +#define BS_COLOR_REG (0x0708) +#define SF_COLOR_REG (0x070C) /* VER4.1 */ + +/* +* COLOR KEY +*/ +#define SRC_COLORKEY_CTRL_REG (0x0710) +#define SRC_COLORKEY_DR_MIN_REG (0x0714) +#define SRC_COLORKEY_DR_MAX_REG (0x0718) +#define DST_COLORKEY_CTRL_REG (0x071C) +#define DST_COLORKEY_DR_MIN_REG (0x0720) +#define DST_COLORKEY_DR_MAX_REG (0x0724) +/* YCbCr src Color Key */ +#define YCbCr_SRC_COLORKEY_CTRL_REG (0x0728) /* VER4.1 */ +#define YCbCr_SRC_COLORKEY_DR_MIN_REG (0x072C) /* VER4.1 */ +#define YCbCr_SRC_COLORKEY_DR_MAX_REG (0x0730) /* VER4.1 */ +/* YCbCr dst Color Key */ +#define YCbCr_DST_COLORKEY_CTRL_REG (0x0734) /* VER4.1 */ +#define YCbCr_DST_COLORKEY_DR_MIN_REG (0x0738) /* VER4.1 */ +#define YCbCr_DST_COLORKEY_DR_MAX_REG (0x073C) /* VER4.1 */ + +#endif + diff --git a/src/g2d/util_g2d.c b/src/g2d/util_g2d.c new file mode 100644 index 0000000..7c5f2d7 --- /dev/null +++ b/src/g2d/util_g2d.c @@ -0,0 +1,889 @@ +#include <stdio.h> +#include "xf86.h" +#include "fimg2d.h" +#include "sec_util.h" + +static int +_util_get_clip(G2dImage* img, int x, int y, int width, int height, G2dPointVal *lt, G2dPointVal *rb) +{ + if(img->select_mode != G2D_SELECT_MODE_NORMAL) + { + lt->data.x = 0; + lt->data.y = 0; + rb->data.x = 1; + rb->data.y = 1; + return 1; + } + + if(x<0) + { + width += x; + x=0; + } + + if(y<0) + { + height += y; + y=0; + } + + if(x+width > img->width) + { + width = img->width - x; + } + + if(y+height > img->height) + { + height = img->height - y; + } + + if(width <= 0 || height <= 0) + { + if(img->repeat_mode != G2D_REPEAT_MODE_NONE) + { + x=0; + y=0; + width = img->width; + height = img->height; + return 1; + } + + return 0; + } + + lt->data.x = x; + lt->data.y = y; + rb->data.x = x+width; + rb->data.y = y+height; + + return 1; +} + +void +util_g2d_fill(G2dImage* img, + int x, int y, unsigned int w, unsigned int h, + unsigned int color) +{ + G2dBitBltCmdVal bitblt={0,}; + G2dPointVal lt, rb; + + g2d_add_cmd(DST_SELECT_REG, G2D_SELECT_MODE_FGCOLOR); + g2d_add_cmd(DST_COLOR_MODE_REG, img->color_mode); + g2d_add_cmd(DST_BASE_ADDR_REG, img->data.bo[0]); + g2d_add_cmd(DST_STRIDE_REG, img->stride); + + /*Set Geometry*/ + if(!_util_get_clip(img, x, y, w, h, <, &rb)) + { + XDBG_ERROR (MG2D, "[G2D] %s:%d error: invalid geometry\n",__FUNCTION__, __LINE__); + g2d_reset(0); + return; + } + g2d_add_cmd(DST_LEFT_TOP_REG, lt.val); + g2d_add_cmd(DST_RIGHT_BOTTOM_REG, rb.val); + + /*set Src Image*/ + g2d_add_cmd(SF_COLOR_REG, color); + + /*Set G2D Command*/ + bitblt.val = 0; + bitblt.data.fastSolidColorFillEn = 1; + g2d_add_cmd(BITBLT_COMMAND_REG, bitblt.val); + + /* Flush and start */ + g2d_flush(); +} + +void +util_g2d_fill_alu(G2dImage* img, + int x, int y, unsigned int w, unsigned int h, + unsigned int color, G2dAlu alu) +{ + G2dBitBltCmdVal bitblt={0,}; + G2dROP4Val rop4; + G2dPointVal lt, rb; + _X_UNUSED unsigned int bg_color; + unsigned int dst_mode = G2D_SELECT_MODE_BGCOLOR; + G2dROP3Type rop3 = 0; + + switch(alu) + { + case G2Dclear: /* 0 */ + color = 0x00000000; + break; + case G2Dand: /* src AND dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = G2D_ROP3_SRC & G2D_ROP3_DST; + break; + case G2DandReverse: /* src AND NOT dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = G2D_ROP3_SRC & (~G2D_ROP3_DST); + break; + case G2Dcopy: /* src */ + break; + case G2DandInverted: /* NOT src AND dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = (~G2D_ROP3_SRC) & G2D_ROP3_DST; + break; + case G2Dnoop: /* dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = G2D_ROP3_DST; + break; + case G2Dxor: /* src XOR dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = G2D_ROP3_SRC ^ G2D_ROP3_DST; + break; + case G2Dor: /* src OR dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = G2D_ROP3_SRC | G2D_ROP3_DST; + break; + case G2Dnor: /* NOT src AND NOT dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = (~G2D_ROP3_SRC) & (~G2D_ROP3_DST); + break; + case G2Dequiv: /* NOT src XOR dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = (~G2D_ROP3_SRC) ^ G2D_ROP3_DST; + break; + case G2Dinvert: /* NOT dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = ~G2D_ROP3_DST; + break; + case G2DorReverse: /* src OR NOT dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = G2D_ROP3_SRC |( ~G2D_ROP3_DST); + break; + case G2DcopyInverted: /* NOT src */ + rop3 = ~G2D_ROP3_SRC; + break; + case G2DorInverted: /* NOT src OR dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = (~G2D_ROP3_SRC) | G2D_ROP3_DST; + break; + case G2Dnand: /* NOT src OR NOT dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = (~G2D_ROP3_SRC) | (~G2D_ROP3_DST); + break; + case G2Dset: /* 1 */ + color = 0xFFFFFFFF; + break; + case G2Dnegative: + bg_color = 0x00FFFFFF; + rop3 = G2D_ROP3_SRC ^ G2D_ROP3_DST; + break; + default: + break; + } + + /*set Dst Image*/ + g2d_add_cmd(DST_SELECT_REG, dst_mode); + g2d_add_cmd(DST_COLOR_MODE_REG, img->color_mode); + g2d_add_cmd(DST_BASE_ADDR_REG, img->data.bo[0]); + g2d_add_cmd(DST_STRIDE_REG, img->stride); + + /*Set Geometry*/ + if(!_util_get_clip(img, x, y, w, h, <, &rb)) + { + XDBG_ERROR (MG2D, "[G2D] %s:%d error: invalid geometry\n",__FUNCTION__, __LINE__); + g2d_reset(0); + return; + } + g2d_add_cmd(DST_LEFT_TOP_REG, lt.val); + g2d_add_cmd(DST_RIGHT_BOTTOM_REG, rb.val); + + /*set ROP4 val*/ + if(rop3 != 0) + { + /*set Src Image*/ + g2d_add_cmd(SRC_SELECT_REG, G2D_SELECT_MODE_FGCOLOR); + g2d_add_cmd(SRC_COLOR_MODE_REG, G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB); + g2d_add_cmd(FG_COLOR_REG, color); + + rop4.val = 0; + rop4.data.unmaskedROP3 = rop3; + g2d_add_cmd(ROP4_REG, rop4.val); + } + else + { + g2d_add_cmd(SF_COLOR_REG, color); + + /*Set G2D Command*/ + bitblt.val = 0; + bitblt.data.fastSolidColorFillEn = 1; + g2d_add_cmd(BITBLT_COMMAND_REG, bitblt.val); + } + + /* Flush and start */ + g2d_flush(); +} + +void +util_g2d_copy(G2dImage* src, G2dImage* dst, + int src_x, int src_y, + int dst_x, int dst_y, + unsigned int width, unsigned int height) +{ + G2dROP4Val rop4; + G2dPointVal lt, rb; + + /*Set dst*/ + g2d_add_cmd(DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); + g2d_add_cmd(DST_COLOR_MODE_REG, dst->color_mode); + g2d_add_cmd(DST_BASE_ADDR_REG, dst->data.bo[0]); + if (dst->color_mode & G2D_YCbCr_2PLANE) + { + if (dst->data.bo[1] > 0) + g2d_add_cmd(DST_PLANE2_BASE_ADDR_REG, dst->data.bo[1]); + else + XDBG_ERROR (MG2D, "[G2D] %s:%d error: second bo is null.\n",__FUNCTION__, __LINE__); + } + g2d_add_cmd(DST_STRIDE_REG, dst->stride); + + /*Set src*/ + g2d_add_cmd(SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL); + g2d_add_cmd(SRC_COLOR_MODE_REG, src->color_mode); + g2d_add_cmd(SRC_BASE_ADDR_REG, src->data.bo[0]); + if (src->color_mode & G2D_YCbCr_2PLANE) + { + if (src->data.bo[1] > 0) + g2d_add_cmd(DST_PLANE2_BASE_ADDR_REG, src->data.bo[1]); + else + XDBG_ERROR (MG2D, "[G2D] %s:%d error: second bo is null.\n",__FUNCTION__, __LINE__); + } + g2d_add_cmd(SRC_STRIDE_REG, src->stride); + if(src->repeat_mode) + g2d_add_cmd(SRC_REPEAT_MODE_REG, src->repeat_mode); + + /*Set cmd*/ + if(!_util_get_clip(src, src_x, src_y, width, height, <, &rb)) + { + XDBG_ERROR (MG2D, "[G2D] %s:%d error: invalid geometry\n",__FUNCTION__, __LINE__); + g2d_reset(0); + return; + } + g2d_add_cmd(SRC_LEFT_TOP_REG, lt.val); + g2d_add_cmd(SRC_RIGHT_BOTTOM_REG, rb.val); + + if(!_util_get_clip(dst, dst_x, dst_y, width, height, <, &rb)) + { + XDBG_ERROR (MG2D, "[G2D] %s:%d error: invalid geometry\n",__FUNCTION__, __LINE__); + g2d_reset(0); + return; + } + g2d_add_cmd(DST_LEFT_TOP_REG, lt.val); + g2d_add_cmd(DST_RIGHT_BOTTOM_REG, rb.val); + + rop4.val = 0; + rop4.data.unmaskedROP3 = G2D_ROP3_SRC; + g2d_add_cmd(ROP4_REG, rop4.val); + + g2d_flush(); +} + +void +util_g2d_copy_alu(G2dImage* src, G2dImage* dst, + int src_x, int src_y, + int dst_x, int dst_y, + unsigned int width, unsigned int height, + G2dAlu alu) +{ + G2dROP4Val rop4; + G2dPointVal lt, rb; + unsigned int dst_mode = G2D_SELECT_MODE_BGCOLOR; + unsigned int src_mode = G2D_SELECT_MODE_NORMAL; + G2dROP3Type rop3=0; + unsigned int fg_color = 0, bg_color = 0; + + /*Select alu*/ + switch(alu) + { + case G2Dclear: /* 0 */ + src_mode = G2D_SELECT_MODE_FGCOLOR; + fg_color = 0x00000000; + break; + case G2Dand: /* src AND dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = G2D_ROP3_SRC & G2D_ROP3_DST; + break; + case G2DandReverse: /* src AND NOT dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = G2D_ROP3_SRC & (~G2D_ROP3_DST); + break; + case G2Dcopy: /* src */ + rop3 = G2D_ROP3_SRC; + break; + case G2DandInverted: /* NOT src AND dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = (~G2D_ROP3_SRC) & G2D_ROP3_DST; + break; + case G2Dnoop: /* dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = G2D_ROP3_DST; + break; + case G2Dxor: /* src XOR dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = G2D_ROP3_SRC ^ G2D_ROP3_DST; + break; + case G2Dor: /* src OR dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = G2D_ROP3_SRC | G2D_ROP3_DST; + break; + case G2Dnor: /* NOT src AND NOT dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = (~G2D_ROP3_SRC) & (~G2D_ROP3_DST); + break; + case G2Dequiv: /* NOT src XOR dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = (~G2D_ROP3_SRC) ^ G2D_ROP3_DST; + break; + case G2Dinvert: /* NOT dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = ~G2D_ROP3_DST; + break; + case G2DorReverse: /* src OR NOT dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = G2D_ROP3_SRC |( ~G2D_ROP3_DST); + break; + case G2DcopyInverted: /* NOT src */ + rop3 = ~G2D_ROP3_SRC; + break; + case G2DorInverted: /* NOT src OR dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = (~G2D_ROP3_SRC) | G2D_ROP3_DST; + break; + case G2Dnand: /* NOT src OR NOT dst */ + dst_mode = G2D_SELECT_MODE_NORMAL; + rop3 = (~G2D_ROP3_SRC) | (~G2D_ROP3_DST); + break; + case G2Dset: /* 1 */ + src_mode = G2D_SELECT_MODE_FGCOLOR; + fg_color = 0xFFFFFFFF; + rop3 = G2D_ROP3_DST; + break; + case G2Dnegative: + bg_color = 0x00FFFFFF; + rop3 = G2D_ROP3_SRC ^ G2D_ROP3_DST; + break; + default: + break; + } + + /*Set dst*/ + if(dst_mode != G2D_SELECT_MODE_NORMAL) + { + g2d_add_cmd(DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); + g2d_add_cmd(DST_COLOR_MODE_REG, G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB); + g2d_add_cmd(BG_COLOR_REG, bg_color); + } + else + { + g2d_add_cmd(DST_SELECT_REG, G2D_SELECT_MODE_NORMAL); + g2d_add_cmd(DST_COLOR_MODE_REG, dst->color_mode); + } + g2d_add_cmd(DST_BASE_ADDR_REG, dst->data.bo[0]); + g2d_add_cmd(DST_STRIDE_REG, dst->stride); + + /*Set src*/ + if(src_mode != G2D_SELECT_MODE_NORMAL) + { + g2d_add_cmd(SRC_SELECT_REG, G2D_SELECT_MODE_FGCOLOR); + g2d_add_cmd(SRC_COLOR_MODE_REG, G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB); + g2d_add_cmd(FG_COLOR_REG, fg_color); + } + else + { + g2d_add_cmd(SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL); + g2d_add_cmd(SRC_COLOR_MODE_REG, src->color_mode); + g2d_add_cmd(SRC_BASE_ADDR_REG, src->data.bo[0]); + g2d_add_cmd(SRC_STRIDE_REG, src->stride); + if(src->repeat_mode) + g2d_add_cmd(SRC_REPEAT_MODE_REG, src->repeat_mode); + } + + /*Set cmd*/ + if(!_util_get_clip(src, src_x, src_y, width, height, <, &rb)) + { + XDBG_ERROR (MG2D, "[G2D] %s:%d error: invalid geometry\n",__FUNCTION__, __LINE__); + g2d_reset(0); + return; + } + g2d_add_cmd(SRC_LEFT_TOP_REG, lt.val); + g2d_add_cmd(SRC_RIGHT_BOTTOM_REG, rb.val); + + if(!_util_get_clip(dst, dst_x, dst_y, width, height, <, &rb)) + { + XDBG_ERROR (MG2D, "[G2D] %s:%d error: invalid geometry\n",__FUNCTION__, __LINE__); + g2d_reset(0); + return; + } + g2d_add_cmd(DST_LEFT_TOP_REG, lt.val); + g2d_add_cmd(DST_RIGHT_BOTTOM_REG, rb.val); + + rop4.val = 0; + rop4.data.unmaskedROP3 = rop3; + g2d_add_cmd(ROP4_REG, rop4.val); + + g2d_flush(); +} + +void +util_g2d_copy_with_scale(G2dImage* src, G2dImage* dst, + int src_x, int src_y, unsigned int src_w, unsigned int src_h, + int dst_x, int dst_y, unsigned int dst_w, unsigned int dst_h, + int negative) +{ + G2dROP4Val rop4; + G2dPointVal pt; + int bScale; + double scalex=1.0, scaley=1.0; + + /*Set dst*/ + g2d_add_cmd(DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); + g2d_add_cmd(DST_COLOR_MODE_REG, dst->color_mode); + g2d_add_cmd(DST_BASE_ADDR_REG, dst->data.bo[0]); + g2d_add_cmd(DST_STRIDE_REG, dst->stride); + + /*Set src*/ + g2d_add_cmd(SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL); + g2d_add_cmd(SRC_COLOR_MODE_REG, src->color_mode); + g2d_add_cmd(SRC_BASE_ADDR_REG, src->data.bo[0]); + g2d_add_cmd(SRC_STRIDE_REG, src->stride); + + /*Set cmd*/ + if(src_w == dst_w && src_h == dst_h) + bScale = 0; + else + { + bScale = 1; + scalex = (double)src_w/(double)dst_w; + scaley = (double)src_h/(double)dst_h; + } + + if(src_x < 0) + { + src_w += src_x; + src_x = 0; + } + + if(src_y < 0) + { + src_h += src_y; + src_y = 0; + } + if(src_x+src_w > src->width) src_w = src->width - src_x; + if(src_y+src_h > src->height) src_h = src->height - src_y; + + if(dst_x < 0) + { + dst_w += dst_x; + dst_x = 0; + } + + if(dst_y < 0) + { + dst_h += dst_y; + dst_y = 0; + } + if(dst_x+dst_w > dst->width) dst_w = dst->width - dst_x; + if(dst_y+dst_h > dst->height) dst_h = dst->height - dst_y; + + if(src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) + { + XDBG_ERROR (MG2D, "[G2D] error: invalid geometry\n"); + g2d_reset(0); + return; + } + + if(negative) + { + g2d_add_cmd(BG_COLOR_REG, 0x00FFFFFF); + rop4.val = 0; + rop4.data.unmaskedROP3 = G2D_ROP3_SRC^G2D_ROP3_DST; + g2d_add_cmd(ROP4_REG, rop4.val); + } + else + { + rop4.val = 0; + rop4.data.unmaskedROP3 = G2D_ROP3_SRC; + g2d_add_cmd(ROP4_REG, rop4.val); + } + + if(bScale) + { + g2d_add_cmd(SRC_SCALE_CTRL_REG, G2D_SCALE_MODE_BILINEAR); + g2d_add_cmd(SRC_XSCALE_REG, G2D_DOUBLE_TO_FIXED(scalex)); + g2d_add_cmd(SRC_YSCALE_REG, G2D_DOUBLE_TO_FIXED(scaley)); + } + + pt.data.x = src_x; + pt.data.y = src_y; + pt.val = (pt.data.y << 16) | pt.data.x ; + g2d_add_cmd(SRC_LEFT_TOP_REG, pt.val); + pt.data.x = src_x + src_w; + pt.data.y = src_y + src_h; + pt.val = (pt.data.y << 16) | pt.data.x ; + g2d_add_cmd(SRC_RIGHT_BOTTOM_REG, pt.val); + + + pt.data.x = dst_x; + pt.data.y = dst_y; + pt.val = (pt.data.y << 16) | pt.data.x ; + g2d_add_cmd(DST_LEFT_TOP_REG, pt.val); + pt.data.x = dst_x + dst_w; + pt.data.y = dst_y + dst_h; + pt.val = (pt.data.y << 16) | pt.data.x ; + g2d_add_cmd(DST_RIGHT_BOTTOM_REG, pt.val); + + g2d_flush(); +} + +void +util_g2d_blend(G2dOp op, G2dImage* src, G2dImage* dst, + int src_x, int src_y, + int dst_x, int dst_y, + unsigned int width, unsigned int height) +{ + G2dBitBltCmdVal bitblt; + G2dBlendFunctionVal blend; + G2dPointVal pt; + + bitblt.val = 0; + blend.val = 0; + + /*Set dst*/ + if(op == G2D_OP_SRC || op == G2D_OP_CLEAR) + g2d_add_cmd(DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); + else + g2d_add_cmd(DST_SELECT_REG, G2D_SELECT_MODE_NORMAL); + g2d_add_cmd(DST_COLOR_MODE_REG, dst->color_mode); + g2d_add_cmd(DST_BASE_ADDR_REG, dst->data.bo[0]); + g2d_add_cmd(DST_STRIDE_REG, dst->stride); + + /*Set src*/ + g2d_set_src(src); + + /*Set cmd*/ + if(src_x < 0) src_x = 0; + if(src_y < 0) src_y = 0; + if(src_x+width > src->width) width = src->width - src_x; + if(src_y+height > src->height) height = src->height - src_y; + + if(dst_x < 0) dst_x = 0; + if(dst_y < 0) dst_y = 0; + if(dst_x+width > dst->width) width = dst->width - dst_x; + if(dst_y+height > dst->height) height = dst->height - dst_y; + + if(width <= 0 || height <= 0) + { + XDBG_ERROR (MG2D, "[G2D] error: invalid geometry\n"); + g2d_reset(0); + return; + } + + bitblt.data.alphaBlendMode = G2D_ALPHA_BLEND_MODE_ENABLE; + blend.val = g2d_get_blend_op(op); + g2d_add_cmd(BITBLT_COMMAND_REG, bitblt.val); + g2d_add_cmd(BLEND_FUNCTION_REG, blend.val); + + pt.data.x = src_x; + pt.data.y = src_y; + g2d_add_cmd(SRC_LEFT_TOP_REG, pt.val); + pt.data.x = src_x + width; + pt.data.y = src_y + height; + g2d_add_cmd(SRC_RIGHT_BOTTOM_REG, pt.val); + + + pt.data.x = dst_x; + pt.data.y = dst_y; + g2d_add_cmd(DST_LEFT_TOP_REG, pt.val); + pt.data.x = dst_x + width; + pt.data.y = dst_y + height; + g2d_add_cmd(DST_RIGHT_BOTTOM_REG, pt.val); + + g2d_flush(); +} + +void +util_g2d_blend_with_scale(G2dOp op, G2dImage* src, G2dImage* dst, + int src_x, int src_y, unsigned int src_w, unsigned int src_h, + int dst_x, int dst_y, unsigned int dst_w, unsigned int dst_h, + int negative) +{ + G2dROP4Val rop4; + G2dPointVal pt; + int bScale; + double scalex=1.0, scaley=1.0; + G2dRotateVal rotate; + G2dSrcMaskDirVal dir; + int rotate_w, rotate_h; + G2dBitBltCmdVal bitblt; + G2dBlendFunctionVal blend; + + bitblt.val = 0; + blend.val = 0; + rotate.val = 0; + dir.val = 0; + + if(src_x < 0) + { + src_w += src_x; + src_x = 0; + } + + if(src_y < 0) + { + src_h += src_y; + src_y = 0; + } + if(src_x+src_w > src->width) + src_w = src->width - src_x; + if(src_y+src_h > src->height) + src_h = src->height - src_y; + + if(dst_x < 0) + { + dst_w += dst_x; + dst_x = 0; + } + if(dst_y < 0) + { + dst_h += dst_y; + dst_y = 0; + } + if(dst_x+dst_w > dst->width) + dst_w = dst->width - dst_x; + if(dst_y+dst_h > dst->height) + dst_h = dst->height - dst_y; + + if(src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) + { + XDBG_ERROR (MG2D, "[G2D] error: invalid geometry\n"); + g2d_reset(0); + return; + } + + /*Set dst*/ + if(op == G2D_OP_SRC || op == G2D_OP_CLEAR) + g2d_add_cmd(DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); + else + g2d_add_cmd(DST_SELECT_REG, G2D_SELECT_MODE_NORMAL); + g2d_add_cmd(DST_COLOR_MODE_REG, dst->color_mode); + g2d_add_cmd(DST_BASE_ADDR_REG, dst->data.bo[0]); + if (dst->color_mode & G2D_YCbCr_2PLANE) + { + if (dst->data.bo[1] > 0) + g2d_add_cmd(DST_PLANE2_BASE_ADDR_REG, dst->data.bo[1]); + else + fprintf(stderr, "[G2D] %s:%d error: second bo is null.\n",__FUNCTION__, __LINE__); + } + g2d_add_cmd(DST_STRIDE_REG, dst->stride); + + /*Set src*/ + g2d_add_cmd(SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL); + g2d_add_cmd(SRC_COLOR_MODE_REG, src->color_mode); + g2d_add_cmd(SRC_BASE_ADDR_REG, src->data.bo[0]); + if (src->color_mode & G2D_YCbCr_2PLANE) + { + if (src->data.bo[1] > 0) + g2d_add_cmd(SRC_PLANE2_BASE_ADDR_REG, src->data.bo[1]); + else + fprintf(stderr, "[G2D] %s:%d error: second bo is null.\n",__FUNCTION__, __LINE__); + } + g2d_add_cmd(SRC_STRIDE_REG, src->stride); + + /*Set cmd*/ + rotate_w = (src->rotate_90)?dst_h:dst_w; + rotate_h = (src->rotate_90)?dst_w:dst_h; + + if(src_w == rotate_w && src_h == rotate_h) + bScale = 0; + else + { + bScale = 1; + scalex = (double)src_w/(double)rotate_w; + scaley = (double)src_h/(double)rotate_h; + } + + if(negative) + { + g2d_add_cmd(BG_COLOR_REG, 0x00FFFFFF); + rop4.val = 0; + rop4.data.unmaskedROP3 = G2D_ROP3_SRC^G2D_ROP3_DST; + g2d_add_cmd(ROP4_REG, rop4.val); + } + else + { + rop4.val = 0; + rop4.data.unmaskedROP3 = G2D_ROP3_SRC; + g2d_add_cmd(ROP4_REG, rop4.val); + } + + if(bScale) + { + g2d_add_cmd(SRC_SCALE_CTRL_REG, G2D_SCALE_MODE_BILINEAR); + g2d_add_cmd(SRC_XSCALE_REG, G2D_DOUBLE_TO_FIXED(scalex)); + g2d_add_cmd(SRC_YSCALE_REG, G2D_DOUBLE_TO_FIXED(scaley)); + } + + if(src->rotate_90 || src->xDir || src->yDir) + { + rotate.data.srcRotate = src->rotate_90; + dir.data.dirSrcX = src->xDir; + dir.data.dirSrcY = src->yDir; + } + + pt.data.x = src_x; + pt.data.y = src_y; + pt.val = (pt.data.y << 16) | pt.data.x ; + g2d_add_cmd(SRC_LEFT_TOP_REG, pt.val); + pt.data.x = src_x + src_w; + pt.data.y = src_y + src_h; + pt.val = (pt.data.y << 16) | pt.data.x ; + g2d_add_cmd(SRC_RIGHT_BOTTOM_REG, pt.val); + + pt.data.x = dst_x; + pt.data.y = dst_y; + pt.val = (pt.data.y << 16) | pt.data.x ; + g2d_add_cmd(DST_LEFT_TOP_REG, pt.val); + pt.data.x = dst_x + dst_w; + pt.data.y = dst_y + dst_h; + pt.val = (pt.data.y << 16) | pt.data.x ; + g2d_add_cmd(DST_RIGHT_BOTTOM_REG, pt.val); + + if(op != G2D_OP_SRC || op != G2D_OP_CLEAR) + { + bitblt.data.alphaBlendMode = G2D_ALPHA_BLEND_MODE_ENABLE; + blend.val = g2d_get_blend_op(op); + g2d_add_cmd(BITBLT_COMMAND_REG, bitblt.val); + g2d_add_cmd(BLEND_FUNCTION_REG, blend.val); + } + + g2d_add_cmd(ROTATE_REG, rotate.val); + g2d_add_cmd(SRC_MASK_DIRECT_REG, dir.val); + + g2d_flush(); +} + +void +util_g2d_composite(G2dOp op, G2dImage* src, G2dImage* mask, G2dImage* dst, + int src_x, int src_y, + int mask_x, int mask_y, + int dst_x, int dst_y, + unsigned int width, unsigned int height) +{ + G2dBitBltCmdVal bitblt; + G2dBlendFunctionVal blend; + G2dRotateVal rotate; + G2dSrcMaskDirVal dir; + G2dPointVal lt, rb; + + bitblt.val = 0; + blend.val = 0; + rotate.val = 0; + dir.val = 0; + + /*Set dst*/ + if(op == G2D_OP_SRC || op == G2D_OP_CLEAR) + g2d_add_cmd(DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); + else + g2d_add_cmd(DST_SELECT_REG, G2D_SELECT_MODE_NORMAL); + g2d_add_cmd(DST_COLOR_MODE_REG, dst->color_mode); + g2d_add_cmd(DST_BASE_ADDR_REG, dst->data.bo[0]); + + if (dst->color_mode & G2D_YCbCr_2PLANE) + { + if (dst->data.bo[1] > 0) + g2d_add_cmd(DST_PLANE2_BASE_ADDR_REG, dst->data.bo[1]); + else + XDBG_ERROR (MG2D, "[G2D] %s:%d error: second bo is null.\n",__FUNCTION__, __LINE__); + } + + g2d_add_cmd(DST_STRIDE_REG, dst->stride); + + /*Set src*/ + g2d_set_src(src); + if(src->repeat_mode) + { + g2d_add_cmd(SRC_REPEAT_MODE_REG, src->repeat_mode); + } + + if(src->scale_mode) + { + g2d_add_cmd(SRC_XSCALE_REG, src->xscale); + g2d_add_cmd(SRC_YSCALE_REG, src->yscale); + g2d_add_cmd(SRC_SCALE_CTRL_REG, src->scale_mode); + } + + if(src->rotate_90 || src->xDir || src->yDir) + { + rotate.data.srcRotate = src->rotate_90; + dir.data.dirSrcX = src->xDir; + dir.data.dirSrcY = src->yDir; + } + + /*Set Mask*/ + if(mask) + { + bitblt.data.maskingEn = 1; + g2d_set_mask(mask); + + if(mask->repeat_mode) + { + g2d_add_cmd(MASK_REPEAT_MODE_REG, mask->repeat_mode); + } + + if(mask->scale_mode) + { + g2d_add_cmd(MASK_XSCALE_REG, mask->xscale); + g2d_add_cmd(MASK_YSCALE_REG, mask->yscale); + g2d_add_cmd(MASK_SCALE_CTRL_REG, mask->scale_mode); + } + + if(mask->rotate_90 || mask->xDir || mask->yDir) + { + rotate.data.maskRotate = mask->rotate_90; + dir.data.dirMaskX = mask->xDir; + dir.data.dirMaskY = mask->yDir; + } + } + + /*Set Geometry*/ + if(!_util_get_clip(src, src_x, src_y, width, height, <, &rb)) + { + XDBG_ERROR (MG2D, "[G2D] %s:%d error: invalid geometry\n",__FUNCTION__, __LINE__); + g2d_reset(0); + return; + } + g2d_add_cmd(SRC_LEFT_TOP_REG, lt.val); + g2d_add_cmd(SRC_RIGHT_BOTTOM_REG, rb.val); + + if(mask) + { + if(!_util_get_clip(mask, mask_x, mask_y, width, height, <, &rb)) + { + XDBG_ERROR (MG2D, "[G2D] %s:%d error: invalid geometry\n",__FUNCTION__, __LINE__); + g2d_reset(0); + return; + } + g2d_add_cmd(MASK_LEFT_TOP_REG, lt.val); + g2d_add_cmd(MASK_RIGHT_BOTTOM_REG, rb.val); + } + + if(!_util_get_clip(dst, dst_x, dst_y, width, height, <, &rb)) + { + XDBG_ERROR (MG2D, "[G2D] %s:%d error: invalid geometry\n",__FUNCTION__, __LINE__); + g2d_reset(0); + return; + } + g2d_add_cmd(DST_LEFT_TOP_REG, lt.val); + g2d_add_cmd(DST_RIGHT_BOTTOM_REG, rb.val); + + bitblt.data.alphaBlendMode = G2D_ALPHA_BLEND_MODE_ENABLE; + blend.val = g2d_get_blend_op(op); + g2d_add_cmd(BITBLT_COMMAND_REG, bitblt.val); + g2d_add_cmd(BLEND_FUNCTION_REG, blend.val); + g2d_add_cmd(ROTATE_REG, rotate.val); + g2d_add_cmd(SRC_MASK_DIRECT_REG, dir.val); + + g2d_flush(); +} diff --git a/src/ipp/sec_converter.c b/src/ipp/sec_converter.c new file mode 100644 index 0000000..8b4f9bc --- /dev/null +++ b/src/ipp/sec_converter.c @@ -0,0 +1,1021 @@ +/************************************************************************** + +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 <sys/ioctl.h> + +#include "sec.h" +#include "sec_util.h" +#include "sec_video_types.h" +#include "sec_video_fourcc.h" +#include "sec_drm_ipp.h" +#include "sec_converter.h" + +#include <drm_fourcc.h> + +//#define INCREASE_NUM 1 +#define DEQUEUE_FORCE 1 + +#if INCREASE_NUM +#define CVT_BUF_MAX 6 +#endif + +typedef struct _SECCvtFuncData +{ + CvtFunc func; + void *data; + struct xorg_list link; +} SECCvtFuncData; + +typedef struct _SECCvtBuf +{ + SECCvtType type; + int index; + unsigned int handles[EXYNOS_DRM_PLANAR_MAX]; + CARD32 begin; + + SECVideoBuf *vbuf; + + struct xorg_list link; +} SECCvtBuf; + +struct _SECCvt +{ + CARD32 stamp; + + int prop_id; + + ScrnInfoPtr pScrn; + SECCvtOp op; + SECCvtProp props[CVT_TYPE_MAX]; + + struct xorg_list func_datas; + struct xorg_list src_bufs; + struct xorg_list dst_bufs; + +#if INCREASE_NUM + int src_index; + int dst_index; +#endif + + Bool started; + Bool first_event; + + struct xorg_list link; +}; + +static unsigned int formats[] = +{ + FOURCC_RGB565, + FOURCC_SR16, + FOURCC_RGB32, + FOURCC_SR32, + FOURCC_YV12, + FOURCC_I420, + FOURCC_S420, + FOURCC_ST12, + FOURCC_SN12, + FOURCC_NV12, + FOURCC_SN21, + FOURCC_NV21, + FOURCC_YUY2, + FOURCC_SUYV, + FOURCC_UYVY, + FOURCC_SYVY, + FOURCC_ITLV, +}; + +static struct xorg_list cvt_list; + +static void +_initList (void) +{ + static Bool inited = FALSE; + + if (inited) + return; + + xorg_list_init (&cvt_list); + + inited = TRUE; +} + +static SECCvt* +_findCvt (CARD32 stamp) +{ + SECCvt *cur = NULL, *next = NULL; + + _initList (); + + if (cvt_list.next != NULL) + { + xorg_list_for_each_entry_safe (cur, next, &cvt_list, link) + { + if (cur->stamp == stamp) + return cur; + } + } + + return NULL; +} + +static enum drm_exynos_ipp_cmd +_drmCommand (SECCvtOp op) +{ + switch (op) + { + case CVT_OP_OUTPUT: + return IPP_CMD_OUTPUT; + default: + return IPP_CMD_M2M; + } +} + +static enum drm_exynos_degree +_drmDegree (int degree) +{ + switch (degree % 360) + { + case 90: + return EXYNOS_DRM_DEGREE_90; + case 180: + return EXYNOS_DRM_DEGREE_180; + case 270: + return EXYNOS_DRM_DEGREE_270; + default: + return EXYNOS_DRM_DEGREE_0; + } +} + +static void +_FillConfig (SECCvtType type, SECCvtProp *prop, struct drm_exynos_ipp_config *config) +{ + config->ops_id = (type == CVT_TYPE_SRC) ? EXYNOS_DRM_OPS_SRC : EXYNOS_DRM_OPS_DST; + + if (prop->hflip) + config->flip |= EXYNOS_DRM_FLIP_HORIZONTAL; + if (prop->vflip) + config->flip |= EXYNOS_DRM_FLIP_VERTICAL; + + config->degree = _drmDegree (prop->degree); + config->fmt = secUtilGetDrmFormat (prop->id); + config->sz.hsize = (__u32)prop->width; + config->sz.vsize = (__u32)prop->height; + config->pos.x = (__u32)prop->crop.x; + config->pos.y = (__u32)prop->crop.y; + config->pos.w = (__u32)prop->crop.width; + config->pos.h = (__u32)prop->crop.height; +} + +static void +_fillProperty (SECCvt *cvt, SECCvtType type, SECVideoBuf *vbuf, SECCvtProp *prop) +{ + prop->id = vbuf->id; + prop->width = vbuf->width; + prop->height = vbuf->height; + prop->crop = vbuf->crop; + + prop->degree = cvt->props[type].degree; + prop->vflip = cvt->props[type].vflip; + prop->hflip = cvt->props[type].hflip; + prop->secure = cvt->props[type].secure; + prop->csc_range = cvt->props[type].csc_range; +} + +static Bool +_SetVbufConverting (SECVideoBuf *vbuf, SECCvt *cvt, Bool converting) +{ + if (!converting) + { + ConvertInfo *cur = NULL, *next = NULL; + + xorg_list_for_each_entry_safe (cur, next, &vbuf->convert_info, link) + { + if (cur->cvt == (void*)cvt) + { + xorg_list_del (&cur->link); + free (cur); + return TRUE; + } + } + + XDBG_ERROR (MCVT, "failed: %ld not found in %ld.\n", cvt->stamp, vbuf->stamp); + return FALSE; + } + else + { + ConvertInfo *info = NULL, *next = NULL; + + xorg_list_for_each_entry_safe (info, next, &vbuf->convert_info, link) + { + if (info->cvt == (void*)cvt) + { + XDBG_ERROR (MCVT, "failed: %ld already converting %ld.\n", cvt->stamp, vbuf->stamp); + return FALSE; + } + } + + info = calloc (1, sizeof (ConvertInfo)); + XDBG_RETURN_VAL_IF_FAIL (info != NULL, FALSE); + + info->cvt = (void*)cvt; + + xorg_list_add (&info->link, &vbuf->convert_info); + + return TRUE; + } +} + +#if 0 +static void +_printBufIndices (SECCvt *cvt, SECCvtType type, char *str) +{ + struct xorg_list *bufs; + SECCvtBuf *cur, *next; + char nums[128]; + + bufs = (type == CVT_TYPE_SRC) ? &cvt->src_bufs : &cvt->dst_bufs; + + snprintf (nums, 128, "bufs:"); + + list_rev_for_each_entry_safe (cur, next, bufs, link) + { + snprintf (nums, 128, "%s %d", nums, cur->index); + } + + ErrorF ("%s: cvt(%p) %s(%s). \n", str, cvt, + (type == CVT_TYPE_SRC)?"SRC":"DST", nums); +} +#endif + +static int +_secCvtGetEmptyIndex (SECCvt *cvt, SECCvtType type) +{ +#if INCREASE_NUM + int ret; + + if(type == CVT_TYPE_SRC) + { + ret = cvt->src_index++; + if (cvt->src_index >= CVT_BUF_MAX) + cvt->src_index = 0; + } + else + { + ret = cvt->dst_index++; + if (cvt->dst_index >= CVT_BUF_MAX) + cvt->dst_index = 0; + } + + return ret; +#else + struct xorg_list *bufs; + SECCvtBuf *cur = NULL, *next = NULL; + int ret = 0; + + bufs = (type == CVT_TYPE_SRC) ? &cvt->src_bufs : &cvt->dst_bufs; + + while (1) + { + Bool found = FALSE; + + xorg_list_for_each_entry_safe (cur, next, bufs, link) + { + if (ret == cur->index) + { + found = TRUE; + break; + } + } + + if (!found) + break; + + ret++; + } + + return ret; +#endif +} + +static SECCvtBuf* +_secCvtFindBuf (SECCvt *cvt, SECCvtType type, int index) +{ + struct xorg_list *bufs; + SECCvtBuf *cur = NULL, *next = NULL; + + bufs = (type == CVT_TYPE_SRC) ? &cvt->src_bufs : &cvt->dst_bufs; + + xorg_list_for_each_entry_safe (cur, next, bufs, link) + { + if (index == cur->index) + return cur; + } + + XDBG_ERROR (MCVT, "cvt(%p), type(%d), index(%d) not found.\n", cvt, type, index); + + return NULL; +} + +static Bool +_secCvtQueue (SECCvt *cvt, SECCvtBuf *cbuf) +{ + struct drm_exynos_ipp_queue_buf buf = {0,}; + struct xorg_list *bufs; + int i; + int index = _secCvtGetEmptyIndex (cvt, cbuf->type); + + buf.prop_id = cvt->prop_id; + buf.ops_id = (cbuf->type == CVT_TYPE_SRC) ? EXYNOS_DRM_OPS_SRC : EXYNOS_DRM_OPS_DST; + buf.buf_type = IPP_BUF_ENQUEUE; + buf.buf_id = cbuf->index = index; + buf.user_data = (__u64)cvt->stamp; + + for (i = 0; i < EXYNOS_DRM_PLANAR_MAX; i++) + buf.handle[i] = (__u32)cbuf->handles[i]; + + if (!secDrmIppQueueBuf (cvt->pScrn, &buf)) + return FALSE; + + bufs = (cbuf->type == CVT_TYPE_SRC) ? &cvt->src_bufs : &cvt->dst_bufs; + xorg_list_add (&cbuf->link, bufs); + + _SetVbufConverting (cbuf->vbuf, cvt, TRUE); + +#if 0 + if (cbuf->type == CVT_TYPE_SRC) + _printBufIndices (cvt, CVT_TYPE_SRC, "in"); +#endif + + XDBG_DEBUG (MCVT, "cvt(%p), cbuf(%p), type(%d), index(%d) vbuf(%p) converting(%d)\n", + cvt, cbuf, cbuf->type, index, cbuf->vbuf, VBUF_IS_CONVERTING (cbuf->vbuf)); + + return TRUE; +} + +static void +_secCvtDequeue (SECCvt *cvt, SECCvtBuf *cbuf) +{ + struct drm_exynos_ipp_queue_buf buf = {0,}; + int i; + + if (!_secCvtFindBuf (cvt, cbuf->type, cbuf->index)) + { + XDBG_WARNING (MCVT, "cvt(%p) type(%d), index(%d) already dequeued!\n", + cvt, cbuf->type, cbuf->index); + return; + } + + XDBG_RETURN_IF_FAIL (VBUF_IS_VALID (cbuf->vbuf)); + + buf.prop_id = cvt->prop_id; + buf.ops_id = (cbuf->type == CVT_TYPE_SRC) ? EXYNOS_DRM_OPS_SRC : EXYNOS_DRM_OPS_DST; + buf.buf_type = IPP_BUF_DEQUEUE; + buf.buf_id = cbuf->index; + buf.user_data = (__u64)cvt->stamp; + + for (i = 0; i < EXYNOS_DRM_PLANAR_MAX; i++) + buf.handle[i] = (__u32)cbuf->handles[i]; + + if (!secDrmIppQueueBuf (cvt->pScrn, &buf)) + return; +} + +static void +_secCvtDequeued (SECCvt *cvt, SECCvtType type, int index) +{ + SECCvtBuf *cbuf = _secCvtFindBuf (cvt, type, index); + + if (!cbuf) + { + XDBG_WARNING (MCVT, "cvt(%p) type(%d), index(%d) already dequeued!\n", + cvt, type, index); + return; + } + + XDBG_RETURN_IF_FAIL (VBUF_IS_VALID (cbuf->vbuf)); + + _SetVbufConverting (cbuf->vbuf, cvt, FALSE); + + XDBG_DEBUG (MCVT, "cvt(%p) type(%d) index(%d) vbuf(%p) converting(%d)\n", + cvt, type, index, cbuf->vbuf, VBUF_IS_CONVERTING (cbuf->vbuf)); + + xorg_list_del (&cbuf->link); + +#if 0 + if (cbuf->type == CVT_TYPE_SRC) + _printBufIndices (cvt, CVT_TYPE_SRC, "out"); +#endif + + secUtilVideoBufferUnref (cbuf->vbuf); + free (cbuf); +} + +static void +_secCvtDequeueAll (SECCvt *cvt) +{ + SECCvtBuf *cur = NULL, *next = NULL; + + xorg_list_for_each_entry_safe (cur, next, &cvt->src_bufs, link) + { + _secCvtDequeue (cvt, cur); + } + + xorg_list_for_each_entry_safe (cur, next, &cvt->dst_bufs, link) + { + _secCvtDequeue (cvt, cur); + } +} + +static void +_secCvtDequeuedAll (SECCvt *cvt) +{ + SECCvtBuf *cur = NULL, *next = NULL; + + xorg_list_for_each_entry_safe (cur, next, &cvt->src_bufs, link) + { + _secCvtDequeued (cvt, EXYNOS_DRM_OPS_SRC, cur->index); + } + + xorg_list_for_each_entry_safe (cur, next, &cvt->dst_bufs, link) + { + _secCvtDequeued (cvt, EXYNOS_DRM_OPS_DST, cur->index); + } +} + +static void +_secCvtStop (SECCvt *cvt) +{ + struct drm_exynos_ipp_cmd_ctrl ctrl = {0,}; + + XDBG_RETURN_IF_FAIL (cvt != NULL); + + if (!cvt->started) + return; + + _secCvtDequeueAll (cvt); + + ctrl.prop_id = cvt->prop_id; + ctrl.ctrl = IPP_CTRL_STOP; + + secDrmIppCmdCtrl (cvt->pScrn, &ctrl); + + _secCvtDequeuedAll (cvt); + + XDBG_TRACE (MCVT, "cvt(%p)\n", cvt); + + cvt->prop_id = -1; + + memset (cvt->props, 0, sizeof (SECCvtProp) * CVT_TYPE_MAX); + +#if INCREASE_NUM + cvt->src_index = 0; + cvt->dst_index = 0; +#endif + cvt->started = FALSE; + + return; +} + +Bool +secCvtSupportFormat (SECCvtOp op, int id) +{ + unsigned int *drmfmts; + int i, size, num = 0; + unsigned int drmfmt = secUtilGetDrmFormat (id); + + XDBG_RETURN_VAL_IF_FAIL (op >= 0 && op < CVT_OP_MAX, FALSE); + XDBG_RETURN_VAL_IF_FAIL (id > 0, FALSE); + + size = sizeof (formats) / sizeof (unsigned int); + + for (i = 0; i < size; i++) + if (formats[i] == id) + break; + + if (i == size) + { + XDBG_ERROR (MCVT, "converter(op:%d) not support : '%c%c%c%c'.\n", + op, FOURCC_STR (id)); + return FALSE; + } + + drmfmts = secDrmIppGetFormatList (&num); + if (!drmfmts) + { + XDBG_ERROR (MCVT, "no drm format list.\n"); + return FALSE; + } + + for (i = 0; i < num; i++) + if (drmfmts[i] == drmfmt) + { + free (drmfmts); + return TRUE; + } + + XDBG_ERROR (MCVT, "drm ipp not support : '%c%c%c%c'.\n", FOURCC_STR (id)); + + free (drmfmts); + + return FALSE; +} + +Bool +secCvtEnsureSize (SECCvtProp *src, SECCvtProp *dst) +{ + if (src) + { + int type = secUtilGetColorType (src->id); + + XDBG_RETURN_VAL_IF_FAIL (src->width >= 16, FALSE); + XDBG_RETURN_VAL_IF_FAIL (src->height >= 8, FALSE); + XDBG_RETURN_VAL_IF_FAIL (src->crop.width >= 16, FALSE); + XDBG_RETURN_VAL_IF_FAIL (src->crop.height >= 8, FALSE); + + if (src->width % 16) + { + if (!IS_ZEROCOPY (src->id)) + { + int new_width = (src->width + 16) & (~0xF); + XDBG_DEBUG (MCVT, "src's width : %d to %d.\n", src->width, new_width); + src->width = new_width; + } + } + + if (type == TYPE_YUV420 && src->height % 2) + XDBG_WARNING (MCVT, "src's height(%d) is not multiple of 2!!!\n", src->height); + + if (type == TYPE_YUV420 || type == TYPE_YUV422) + { + src->crop.x = src->crop.x & (~0x1); + src->crop.width = src->crop.width & (~0x1); + } + + if (type == TYPE_YUV420) + src->crop.height = src->crop.height & (~0x1); + + if (src->crop.x + src->crop.width > src->width) + src->crop.width = src->width - src->crop.x; + if (src->crop.y + src->crop.height > src->height) + src->crop.height = src->height - src->crop.y; + } + + if (dst) + { + int type = secUtilGetColorType (dst->id); + + XDBG_RETURN_VAL_IF_FAIL (dst->width >= 16, FALSE); + XDBG_RETURN_VAL_IF_FAIL (dst->height >= 8, FALSE); + XDBG_RETURN_VAL_IF_FAIL (dst->crop.width >= 16, FALSE); + XDBG_RETURN_VAL_IF_FAIL (dst->crop.height >= 4, FALSE); + + if (dst->width % 16) + { + int new_width = (dst->width + 16) & (~0xF); + XDBG_DEBUG (MCVT, "dst's width : %d to %d.\n", dst->width, new_width); + dst->width = new_width; + } + + dst->height = dst->height & (~0x1); + + if (type == TYPE_YUV420 && dst->height % 2) + XDBG_WARNING (MCVT, "dst's height(%d) is not multiple of 2!!!\n", dst->height); + + if (type == TYPE_YUV420 || type == TYPE_YUV422) + { + dst->crop.x = dst->crop.x & (~0x1); + dst->crop.width = dst->crop.width & (~0x1); + } + + if (type == TYPE_YUV420) + dst->crop.height = dst->crop.height & (~0x1); + + if (dst->crop.x + dst->crop.width > dst->width) + dst->crop.width = dst->width - dst->crop.x; + if (dst->crop.y + dst->crop.height > dst->height) + dst->crop.height = dst->height - dst->crop.y; + } + + return TRUE; +} + +SECCvt* +secCvtCreate (ScrnInfoPtr pScrn, SECCvtOp op) +{ + SECCvt *cvt; + CARD32 stamp = GetTimeInMillis (); + + _initList (); + + XDBG_RETURN_VAL_IF_FAIL (pScrn != NULL, NULL); + XDBG_RETURN_VAL_IF_FAIL (op >= 0 && op < CVT_OP_MAX, NULL); + + while (_findCvt (stamp)) + stamp++; + + cvt = calloc (1, sizeof (SECCvt)); + XDBG_RETURN_VAL_IF_FAIL (cvt != NULL, NULL); + + cvt->stamp = stamp; + + cvt->pScrn = pScrn; + cvt->op = op; + cvt->prop_id = -1; + + xorg_list_init (&cvt->func_datas); + xorg_list_init (&cvt->src_bufs); + xorg_list_init (&cvt->dst_bufs); + + XDBG_TRACE (MCVT, "op(%d), cvt(%p) stamp(%ld)\n", op, cvt, stamp); + + xorg_list_add (&cvt->link, &cvt_list); + + return cvt; +} + +void +secCvtDestroy (SECCvt *cvt) +{ + SECCvtFuncData *cur = NULL, *next = NULL; + + if (!cvt) + return; + + _secCvtStop (cvt); + + xorg_list_del (&cvt->link); + + xorg_list_for_each_entry_safe (cur, next, &cvt->func_datas, link) + { + xorg_list_del (&cur->link); + free (cur); + } + + XDBG_TRACE (MCVT, "cvt(%p)\n", cvt); + + free (cvt); +} + +SECCvtOp +secCvtGetOp (SECCvt *cvt) +{ + XDBG_RETURN_VAL_IF_FAIL (cvt != NULL, CVT_OP_M2M); + + return cvt->op; +} + +Bool +secCvtSetProperpty (SECCvt *cvt, SECCvtProp *src, SECCvtProp *dst) +{ + if (cvt->started) + return TRUE; + + struct drm_exynos_ipp_property property; + + XDBG_RETURN_VAL_IF_FAIL (cvt != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (src != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (dst != NULL, FALSE); + + if (!secCvtEnsureSize (src, dst)) + return FALSE; + + if (dst->crop.x + dst->crop.width > dst->width) + { + XDBG_ERROR (MCVT, "dst(%d+%d > %d). !\n", dst->crop.x, dst->crop.width, dst->width); + } + + if (!secCvtSupportFormat (cvt->op, src->id)) + { + XDBG_ERROR (MCVT, "cvt(%p) src '%c%c%c%c' not supported.\n", + cvt, FOURCC_STR (src->id)); + return FALSE; + } + + if (!secCvtSupportFormat (cvt->op, dst->id)) + { + XDBG_ERROR (MCVT, "cvt(%p) dst '%c%c%c%c' not supported.\n", + cvt, FOURCC_STR (dst->id)); + return FALSE; + } + + memcpy (&cvt->props[CVT_TYPE_SRC], src, sizeof (SECCvtProp)); + memcpy (&cvt->props[CVT_TYPE_DST], dst, sizeof (SECCvtProp)); + + CLEAR (property); + _FillConfig (CVT_TYPE_SRC, &cvt->props[CVT_TYPE_SRC], &property.config[0]); + _FillConfig (CVT_TYPE_DST, &cvt->props[CVT_TYPE_DST], &property.config[1]); + property.cmd = _drmCommand (cvt->op); +#ifdef _F_WEARABLE_FEATURE_ + property.type = IPP_EVENT_DRIVEN; +#endif + property.prop_id = cvt->prop_id; + property.protect = dst->secure; + property.range = dst->csc_range; + + XDBG_TRACE (MCVT, "cvt(%p) src('%c%c%c%c', '%c%c%c%c', %dx%d, %d,%d %dx%d, %d, %d&%d, %d, %d)\n", + cvt, FOURCC_STR(src->id), FOURCC_STR(secUtilGetDrmFormat(src->id)), + src->width, src->height, + src->crop.x, src->crop.y, src->crop.width, src->crop.height, + src->degree, src->hflip, src->vflip, + src->secure, src->csc_range); + + XDBG_TRACE (MCVT, "cvt(%p) dst('%c%c%c%c', '%c%c%c%c',%dx%d, %d,%d %dx%d, %d, %d&%d, %d, %d)\n", + cvt, FOURCC_STR(dst->id), FOURCC_STR(secUtilGetDrmFormat(dst->id)), + dst->width, dst->height, + dst->crop.x, dst->crop.y, dst->crop.width, dst->crop.height, + dst->degree, dst->hflip, dst->vflip, + dst->secure, dst->csc_range); + + cvt->prop_id = secDrmIppSetProperty (cvt->pScrn, &property); + XDBG_RETURN_VAL_IF_FAIL (cvt->prop_id >= 0, FALSE); + + return TRUE; +} + +void +secCvtGetProperpty (SECCvt *cvt, SECCvtProp *src, SECCvtProp *dst) +{ + XDBG_RETURN_IF_FAIL (cvt != NULL); + + if (src) + *src = cvt->props[CVT_TYPE_SRC]; + + if (dst) + *dst = cvt->props[CVT_TYPE_DST]; +} + +Bool +secCvtConvert (SECCvt *cvt, SECVideoBuf *src, SECVideoBuf *dst) +{ + SECCvtBuf *src_cbuf = NULL, *dst_cbuf = NULL; + SECCvtProp src_prop, dst_prop; + + XDBG_RETURN_VAL_IF_FAIL (cvt != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (cvt->op == CVT_OP_M2M, FALSE); + XDBG_RETURN_VAL_IF_FAIL (src != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (dst != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (VBUF_IS_VALID (src), FALSE); + XDBG_RETURN_VAL_IF_FAIL (VBUF_IS_VALID (dst), FALSE); + + _fillProperty (cvt, CVT_TYPE_SRC, src, &src_prop); + _fillProperty (cvt, CVT_TYPE_DST, dst, &dst_prop); + + if (memcmp (&cvt->props[CVT_TYPE_SRC], &src_prop, sizeof (SECCvtProp)) || + memcmp (&cvt->props[CVT_TYPE_DST], &dst_prop, sizeof (SECCvtProp))) + { + XDBG_ERROR (MCVT, "cvt(%p) prop changed!\n", cvt); + XDBG_TRACE (MCVT, "cvt(%p) src_old('%c%c%c%c', %dx%d, %d,%d %dx%d, %d, %d&%d, %d, %d)\n", + cvt, FOURCC_STR(cvt->props[CVT_TYPE_SRC].id), + cvt->props[CVT_TYPE_SRC].width, cvt->props[CVT_TYPE_SRC].height, + cvt->props[CVT_TYPE_SRC].crop.x, cvt->props[CVT_TYPE_SRC].crop.y, + cvt->props[CVT_TYPE_SRC].crop.width, cvt->props[CVT_TYPE_SRC].crop.height, + cvt->props[CVT_TYPE_SRC].degree, + cvt->props[CVT_TYPE_SRC].hflip, cvt->props[CVT_TYPE_SRC].vflip, + cvt->props[CVT_TYPE_SRC].secure, cvt->props[CVT_TYPE_SRC].csc_range); + XDBG_TRACE (MCVT, "cvt(%p) src_new('%c%c%c%c', %dx%d, %d,%d %dx%d, %d, %d&%d, %d, %d)\n", + cvt, FOURCC_STR(src_prop.id), src_prop.width, src_prop.height, + src_prop.crop.x, src_prop.crop.y, src_prop.crop.width, src_prop.crop.height, + src_prop.degree, src_prop.hflip, src_prop.vflip, + src_prop.secure, src_prop.csc_range); + XDBG_TRACE (MCVT, "cvt(%p) dst_old('%c%c%c%c', %dx%d, %d,%d %dx%d, %d, %d&%d, %d, %d)\n", + cvt, FOURCC_STR(cvt->props[CVT_TYPE_DST].id), + cvt->props[CVT_TYPE_DST].width, cvt->props[CVT_TYPE_DST].height, + cvt->props[CVT_TYPE_DST].crop.x, cvt->props[CVT_TYPE_DST].crop.y, + cvt->props[CVT_TYPE_DST].crop.width, cvt->props[CVT_TYPE_DST].crop.height, + cvt->props[CVT_TYPE_DST].degree, + cvt->props[CVT_TYPE_DST].hflip, cvt->props[CVT_TYPE_DST].vflip, + cvt->props[CVT_TYPE_DST].secure, cvt->props[CVT_TYPE_DST].csc_range); + XDBG_TRACE (MCVT, "cvt(%p) dst_new('%c%c%c%c', %dx%d, %d,%d %dx%d, %d, %d&%d, %d, %d)\n", + cvt, FOURCC_STR(dst_prop.id), dst_prop.width, dst_prop.height, + dst_prop.crop.x, dst_prop.crop.y, dst_prop.crop.width, dst_prop.crop.height, + dst_prop.degree, dst_prop.hflip, dst_prop.vflip, + dst_prop.secure, dst_prop.csc_range); + return FALSE; + } + + XDBG_GOTO_IF_FAIL (cvt->prop_id >= 0, fail_to_convert); + XDBG_GOTO_IF_FAIL (src->handles[0] > 0, fail_to_convert); + XDBG_GOTO_IF_FAIL (dst->handles[0] > 0, fail_to_convert); + + src_cbuf = calloc (1, sizeof (SECCvtBuf)); + XDBG_GOTO_IF_FAIL (src_cbuf != NULL, fail_to_convert); + dst_cbuf = calloc (1, sizeof (SECCvtBuf)); + XDBG_GOTO_IF_FAIL (dst_cbuf != NULL, fail_to_convert); + + src_cbuf->type = CVT_TYPE_SRC; + src_cbuf->vbuf = secUtilVideoBufferRef (src); + XDBG_GOTO_IF_FAIL (src_cbuf->vbuf != NULL, fail_to_convert); + memcpy (src_cbuf->handles, src->handles, sizeof (unsigned int) * EXYNOS_DRM_PLANAR_MAX); + + if (!_secCvtQueue (cvt, src_cbuf)) + { + secUtilVideoBufferUnref (src_cbuf->vbuf); + goto fail_to_convert; + } + + XDBG_DEBUG (MCVT, "cvt(%p) srcbuf(%p) converting(%d)\n", + cvt, src, VBUF_IS_CONVERTING (src)); + + dst_cbuf->type = CVT_TYPE_DST; + dst_cbuf->vbuf = secUtilVideoBufferRef (dst); + memcpy (dst_cbuf->handles, dst->handles, sizeof (unsigned int) * EXYNOS_DRM_PLANAR_MAX); + + if (!_secCvtQueue (cvt, dst_cbuf)) + { + secUtilVideoBufferUnref (dst_cbuf->vbuf); + goto fail_to_convert; + } + + XDBG_DEBUG (MCVT, "cvt(%p) dstbuf(%p) converting(%d)\n", + cvt, dst, VBUF_IS_CONVERTING (dst)); + + XDBG_DEBUG (MVBUF, "==> ipp (%ld,%d,%d : %ld,%d,%d) \n", + src->stamp, VBUF_IS_CONVERTING (src), src->showing, + dst->stamp, VBUF_IS_CONVERTING (dst), dst->showing); + + if (!cvt->started) + { + struct drm_exynos_ipp_cmd_ctrl ctrl = {0,}; + + ctrl.prop_id = cvt->prop_id; + ctrl.ctrl = IPP_CTRL_PLAY; + + if (!secDrmIppCmdCtrl (cvt->pScrn, &ctrl)) + goto fail_to_convert; + + XDBG_TRACE (MCVT, "cvt(%p) start.\n", cvt); + + cvt->started = TRUE; + } + + dst->dirty = TRUE; + + SECPtr pSec = SECPTR (cvt->pScrn); + if (pSec->xvperf_mode & XBERC_XVPERF_MODE_CVT) + src_cbuf->begin = GetTimeInMillis (); + + return TRUE; + +fail_to_convert: + + if (src_cbuf) + free (src_cbuf); + if (dst_cbuf) + free (dst_cbuf); + + _secCvtStop (cvt); + + return FALSE; +} + +Bool +secCvtAddCallback (SECCvt *cvt, CvtFunc func, void *data) +{ + SECCvtFuncData *func_data; + + XDBG_RETURN_VAL_IF_FAIL (cvt != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (func != NULL, FALSE); + + func_data = calloc (1, sizeof (SECCvtFuncData)); + XDBG_RETURN_VAL_IF_FAIL (func_data != NULL, FALSE); + + xorg_list_add (&func_data->link, &cvt->func_datas); + + func_data->func = func; + func_data->data = data; + + return TRUE; +} + +void +secCvtRemoveCallback (SECCvt *cvt, CvtFunc func, void *data) +{ + SECCvtFuncData *cur = NULL, *next = NULL; + + XDBG_RETURN_IF_FAIL (cvt != NULL); + XDBG_RETURN_IF_FAIL (func != NULL); + + xorg_list_for_each_entry_safe (cur, next, &cvt->func_datas, link) + { + if (cur->func == func && cur->data == data) + { + xorg_list_del (&cur->link); + free (cur); + } + } +} + +void +secCvtHandleIppEvent (int fd, unsigned int *buf_idx, void *data, Bool error) +{ + CARD32 stamp = (CARD32)data; + SECCvt *cvt; + SECCvtBuf *src_cbuf, *dst_cbuf; + SECVideoBuf *src_vbuf, *dst_vbuf; + SECCvtFuncData *curr = NULL, *next = NULL; + + XDBG_RETURN_IF_FAIL (buf_idx != NULL); + + cvt = _findCvt (stamp); + if (!cvt) + { + XDBG_DEBUG (MCVT, "invalid cvt's stamp (%ld).\n", stamp); + return; + } + + XDBG_DEBUG (MCVT, "cvt(%p) index(%d, %d)\n", + cvt, buf_idx[EXYNOS_DRM_OPS_SRC], buf_idx[EXYNOS_DRM_OPS_DST]); + +#if 0 + char temp[64]; + snprintf (temp, 64, "%d,%d", buf_idx[EXYNOS_DRM_OPS_SRC], buf_idx[EXYNOS_DRM_OPS_DST]); + _printBufIndices (cvt, CVT_TYPE_SRC, temp); +#endif + +#if DEQUEUE_FORCE + SECCvtBuf *cur = NULL, *prev = NULL; + + list_rev_for_each_entry_safe (cur, prev, &cvt->src_bufs, link) + { + if (buf_idx[EXYNOS_DRM_OPS_SRC] != cur->index) + { + unsigned int indice[EXYNOS_DRM_OPS_MAX] = {cur->index, cur->index}; + + XDBG_WARNING (MCVT, "cvt(%p) event(%d,%d) has been skipped!! \n", + cvt, cur->index, cur->index); + + /* To make sure all events are received, _secCvtDequeued should be called + * for every event. If a event has been skipped, to call _secCvtDequeued + * forcely, we call secCvtHandleIppEvent recursivly. + */ + secCvtHandleIppEvent (0, indice, (void*)cvt->stamp, TRUE); + } + else + break; + } +#endif + + src_cbuf = _secCvtFindBuf (cvt, EXYNOS_DRM_OPS_SRC, buf_idx[EXYNOS_DRM_OPS_SRC]); + XDBG_RETURN_IF_FAIL (src_cbuf != NULL); + + dst_cbuf = _secCvtFindBuf (cvt, EXYNOS_DRM_OPS_DST, buf_idx[EXYNOS_DRM_OPS_DST]); + XDBG_RETURN_IF_FAIL (dst_cbuf != NULL); + + SECPtr pSec = SECPTR (cvt->pScrn); + if (pSec->xvperf_mode & XBERC_XVPERF_MODE_CVT) + { + CARD32 cur, sub; + cur = GetTimeInMillis (); + sub = cur - src_cbuf->begin; + ErrorF ("cvt(%p) ipp interval : %6ld ms\n", cvt, sub); + } + + src_vbuf = src_cbuf->vbuf; + dst_vbuf = dst_cbuf->vbuf; + + XDBG_DEBUG (MVBUF, "<== ipp (%ld,%d,%d : %ld,%d,%d) \n", + src_vbuf->stamp, VBUF_IS_CONVERTING (src_vbuf), src_vbuf->showing, + dst_vbuf->stamp, VBUF_IS_CONVERTING (dst_vbuf), dst_vbuf->showing); + + if (!cvt->first_event) + { + XDBG_DEBUG (MCVT, "cvt(%p) got a IPP event. \n", cvt); + cvt->first_event = TRUE; + } + + xorg_list_for_each_entry_safe (curr, next, &cvt->func_datas, link) + { + if (curr->func) + curr->func (cvt, src_vbuf, dst_vbuf, curr->data, error); + } + + _secCvtDequeued (cvt, EXYNOS_DRM_OPS_SRC, buf_idx[EXYNOS_DRM_OPS_SRC]); + _secCvtDequeued (cvt, EXYNOS_DRM_OPS_DST, buf_idx[EXYNOS_DRM_OPS_DST]); +} diff --git a/src/ipp/sec_converter.h b/src/ipp/sec_converter.h new file mode 100644 index 0000000..b1b147d --- /dev/null +++ b/src/ipp/sec_converter.h @@ -0,0 +1,90 @@ +/************************************************************************** + +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. + +**************************************************************************/ + +#ifndef __SEC_CONVERTER_H__ +#define __SEC_CONVERTER_H__ + +#include <fbdevhw.h> +#include <exynos_drm.h> + +typedef struct _SECCvt SECCvt; + +typedef enum +{ + CVT_OP_M2M, + CVT_OP_OUTPUT, + CVT_OP_MAX, +} SECCvtOp; + +typedef enum +{ + CVT_TYPE_SRC, + CVT_TYPE_DST, + CVT_TYPE_MAX, +} SECCvtType; + +typedef struct _SECCvtProp +{ + unsigned int id; + + int width; + int height; + xRectangle crop; + + int degree; + Bool vflip; + Bool hflip; + Bool secure; + int csc_range; +} SECCvtProp; + +typedef struct _SECCvtFmt +{ + unsigned int id; + +} SECCvtFmt; + +Bool secCvtSupportFormat (SECCvtOp op, int id); +Bool secCvtEnsureSize (SECCvtProp *src, SECCvtProp *dst); + +SECCvt* secCvtCreate (ScrnInfoPtr pScrn, SECCvtOp op); +void secCvtDestroy (SECCvt *cvt); +SECCvtOp secCvtGetOp (SECCvt *cvt); +Bool secCvtSetProperpty (SECCvt *cvt, SECCvtProp *src, SECCvtProp *dst); +void secCvtGetProperpty (SECCvt *cvt, SECCvtProp *src, SECCvtProp *dst); +Bool secCvtConvert (SECCvt *cvt, SECVideoBuf *src, SECVideoBuf *dst); + +typedef void (*CvtFunc) (SECCvt *cvt, SECVideoBuf *src, SECVideoBuf *dst, void *cvt_data, Bool error); +Bool secCvtAddCallback (SECCvt *cvt, CvtFunc func, void *data); +void secCvtRemoveCallback (SECCvt *cvt, CvtFunc func, void *data); + +void secCvtHandleIppEvent (int fd, unsigned int *buf_idx, void *data, Bool error); + +#endif /* __SEC_CONVERTER_H__ */ diff --git a/src/ipp/sec_drm_ipp.c b/src/ipp/sec_drm_ipp.c new file mode 100644 index 0000000..cb50826 --- /dev/null +++ b/src/ipp/sec_drm_ipp.c @@ -0,0 +1,165 @@ +/************************************************************************** + +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 <sys/ioctl.h> + +#include "sec.h" +#include "sec_util.h" +#include "sec_video_types.h" +#include "sec_video_fourcc.h" +#include "sec_drm_ipp.h" + +#include <drm_fourcc.h> + +static unsigned int drmfmt_list[] = +{ + /* packed */ + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_YUYV, + DRM_FORMAT_UYVY, + + /* 2 plane */ + DRM_FORMAT_NV12, + DRM_FORMAT_NV21, + DRM_FORMAT_NV12MT, + + /* 3 plane */ + DRM_FORMAT_YVU420, + DRM_FORMAT_YUV420, + DRM_FORMAT_YUV444, +}; + +/* A drmfmt list newly allocated. should be freed. */ +unsigned int* +secDrmIppGetFormatList (int *num) +{ + unsigned int *drmfmts; + + XDBG_RETURN_VAL_IF_FAIL (num != NULL, NULL); + + drmfmts = malloc (sizeof (drmfmt_list)); + XDBG_RETURN_VAL_IF_FAIL (drmfmts != NULL, NULL); + + memcpy (drmfmts, drmfmt_list, sizeof (drmfmt_list)); + *num = sizeof (drmfmt_list) / sizeof (unsigned int); + + return drmfmts; +} + +int +secDrmIppSetProperty (ScrnInfoPtr pScrn, struct drm_exynos_ipp_property *property) +{ + int ret = 0; + + XDBG_RETURN_VAL_IF_FAIL (pScrn != NULL, -1); + XDBG_RETURN_VAL_IF_FAIL (property != NULL, -1); + + if (property->prop_id == (__u32)-1) + property->prop_id = 0; + + XDBG_DEBUG (MDRM, "src : flip(%x) deg(%d) fmt(%c%c%c%c) sz(%dx%d) pos(%d,%d %dx%d) \n", + property->config[0].flip, property->config[0].degree, FOURCC_STR (property->config[0].fmt), + property->config[0].sz.hsize, property->config[0].sz.vsize, + property->config[0].pos.x, property->config[0].pos.y, property->config[0].pos.w, property->config[0].pos.h); + XDBG_DEBUG (MDRM, "dst : flip(%x) deg(%d) fmt(%c%c%c%c) sz(%dx%d) pos(%d,%d %dx%d) \n", + property->config[1].flip, property->config[1].degree, FOURCC_STR (property->config[1].fmt), + property->config[1].sz.hsize, property->config[1].sz.vsize, + property->config[1].pos.x, property->config[1].pos.y, property->config[1].pos.w, property->config[1].pos.h); + +#ifdef _F_WEARABLE_FEATURE_ + XDBG_DEBUG (MDRM, "cmd(%d) type(%d) ipp_id(%d) prop_id(%d) hz(%d) protect(%d) range(%d) blending(%x)\n", + property->cmd, property->type, property->ipp_id, property->prop_id, property->refresh_rate, + property->protect, property->range, property->blending); +#else + XDBG_DEBUG (MDRM, "cmd(%d) ipp_id(%d) prop_id(%d) hz(%d) protect(%d) range(%d)\n", + property->cmd, property->ipp_id, property->prop_id, property->refresh_rate, + property->protect, property->range); +#endif + + ret = ioctl (SECPTR (pScrn)->drm_fd, DRM_IOCTL_EXYNOS_IPP_SET_PROPERTY, property); + if (ret) + { + XDBG_ERRNO (MDRM, "failed. \n"); + return -1; + } + + XDBG_TRACE (MDRM, "success. prop_id(%d) \n", property->prop_id); + + return property->prop_id; +} + +Bool +secDrmIppQueueBuf (ScrnInfoPtr pScrn, struct drm_exynos_ipp_queue_buf *buf) +{ + int ret = 0; + + XDBG_RETURN_VAL_IF_FAIL (pScrn != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (buf != NULL, FALSE); + + XDBG_DEBUG (MDRM, "prop_id(%d) ops_id(%d) ctrl(%d) id(%d) handles(%x %x %x). \n", + buf->prop_id, buf->ops_id, buf->buf_type, buf->buf_id, + buf->handle[0], buf->handle[1], buf->handle[2]); + + ret = ioctl (SECPTR (pScrn)->drm_fd, DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF, buf); + if (ret) + { + XDBG_ERRNO (MDRM, "failed. prop_id(%d) op(%d) buf(%d) id(%d)\n", + buf->prop_id, buf->ops_id, buf->buf_type, buf->buf_id); + return FALSE; + } + + XDBG_DEBUG (MDRM, "success. prop_id(%d) \n", buf->prop_id); + + return TRUE; +} + +Bool +secDrmIppCmdCtrl (ScrnInfoPtr pScrn, struct drm_exynos_ipp_cmd_ctrl *ctrl) +{ + int ret = 0; + + XDBG_RETURN_VAL_IF_FAIL (pScrn != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (ctrl != NULL, FALSE); + + XDBG_TRACE (MDRM, "prop_id(%d) ctrl(%d). \n", ctrl->prop_id, ctrl->ctrl); + + ret = ioctl (SECPTR (pScrn)->drm_fd, DRM_IOCTL_EXYNOS_IPP_CMD_CTRL, ctrl); + if (ret) + { + XDBG_ERRNO (MDRM, "failed. prop_id(%d) ctrl(%d)\n", + ctrl->prop_id, ctrl->ctrl); + return FALSE; + } + + XDBG_DEBUG (MDRM, "success. prop_id(%d) \n", ctrl->prop_id); + + return TRUE; +} diff --git a/src/ipp/sec_drm_ipp.h b/src/ipp/sec_drm_ipp.h new file mode 100644 index 0000000..e344c4f --- /dev/null +++ b/src/ipp/sec_drm_ipp.h @@ -0,0 +1,44 @@ +/************************************************************************** + +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. + +**************************************************************************/ + +#ifndef __SEC_DRM_IPP_H__ +#define __SEC_DRM_IPP_H__ + +#include <fbdevhw.h> +#include <exynos_drm.h> + +/* A drmfmt list newly allocated. should be freed. */ +unsigned int* secDrmIppGetFormatList (int *num); + +int secDrmIppSetProperty (ScrnInfoPtr pScrn, struct drm_exynos_ipp_property *property); +Bool secDrmIppQueueBuf (ScrnInfoPtr pScrn, struct drm_exynos_ipp_queue_buf *buf); +Bool secDrmIppCmdCtrl (ScrnInfoPtr pScrn, struct drm_exynos_ipp_cmd_ctrl *ctrl); + +#endif /* __SEC_DRM_IPP_H__ */ diff --git a/src/ipp/sec_wb.c b/src/ipp/sec_wb.c new file mode 100644 index 0000000..b1f708e --- /dev/null +++ b/src/ipp/sec_wb.c @@ -0,0 +1,1338 @@ +/* + * xserver-xorg-video-exynos + * + * Copyright 2004 Keith Packard + * Copyright 2005 Eric Anholt + * Copyright 2006 Nokia Corporation + * Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved. + * + * Contact: Boram Park <boram1288.park@samsung.com> + * + * Permission to use, copy, modify, distribute and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the names of the authors and/or copyright holders + * not be used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. The authors and + * copyright holders make no representations about the suitability of this + * software for any purpose. It is provided "as is" without any express + * or implied warranty. + * + * THE AUTHORS AND COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/poll.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#include <sys/time.h> + +#include <X11/Xatom.h> +#include <xace.h> +#include <xacestr.h> + +#include "exynos_drm.h" + +#include "sec.h" +#include "sec_util.h" +#include "sec_crtc.h" +#include "sec_video_fourcc.h" +#include "sec_video_tvout.h" +#include "sec_wb.h" +#include "sec_drm_ipp.h" +#include "sec_converter.h" + +#include <drm_fourcc.h> + +#define WB_BUF_MAX 5 +#define WB_BUF_DEFAULT 3 +#define WB_BUF_MIN 2 + +enum +{ + PENDING_NONE, + PENDING_ROTATE, + PENDING_STOP, + PENDING_CLOSE, +}; + +enum +{ + STATUS_STARTED, + STATUS_STOPPED, +}; + +typedef struct _SECWbNotifyFuncInfo +{ + SECWbNotify noti; + WbNotifyFunc func; + void *user_data; + + struct _SECWbNotifyFuncInfo *next; +} SECWbNotifyFuncInfo; + +struct _SECWb +{ + int prop_id; + + ScrnInfoPtr pScrn; + + unsigned int id; + + int rotate; + + int width; + int height; + xRectangle drm_dst; + xRectangle tv_dst; + + SECVideoBuf *dst_buf[WB_BUF_MAX]; + Bool queued[WB_BUF_MAX]; + int buf_num; + + int wait_show; + int now_showing; + + SECWbNotifyFuncInfo *info_list; + + /* for tvout */ + Bool tvout; + SECVideoTv *tv; + SECLayerPos lpos; + + Bool need_rotate_hook; + OsTimerPtr rotate_timer; + + /* count */ + unsigned int put_counts; + unsigned int last_counts; + OsTimerPtr timer; + + OsTimerPtr event_timer; + OsTimerPtr ipp_timer; + + Bool scanout; + int hz; + + int status; + Bool secure; + CARD32 prev_time; +}; + +static unsigned int formats[] = +{ + FOURCC_RGB32, + FOURCC_ST12, + FOURCC_SN12, +}; + +static SECWb *keep_wb; +static Atom atom_wb_rotate; + +static void _secWbQueue (SECWb *wb, int index); +static Bool _secWbRegisterRotateHook (SECWb *wb, Bool hook); +static void _secWbCloseDrmDstBuffer (SECWb *wb); +static void _secWbCloseDrm (SECWb *wb); + +static CARD32 +_secWbCountPrint (OsTimerPtr timer, CARD32 now, pointer arg) +{ + SECWb *wb = (SECWb*)arg; + + ErrorF ("IppEvent : %d fps. \n", wb->put_counts - wb->last_counts); + + wb->last_counts = wb->put_counts; + + wb->timer = TimerSet (wb->timer, 0, 1000, _secWbCountPrint, arg); + + return 0; +} + +static void +_secWbCountFps (SECWb *wb) +{ + wb->put_counts++; + + if (wb->timer) + return; + + wb->timer = TimerSet (NULL, 0, 1000, _secWbCountPrint, wb); +} + +static void +_secWbCountStop (SECWb *wb) +{ + if (wb->timer) + { + TimerFree (wb->timer); + wb->timer = NULL; + } + + wb->put_counts = 0; + wb->last_counts = 0; +} + +static unsigned int +_secWbSupportFormat (int id) +{ + unsigned int *drmfmts; + int i, size, num = 0; + unsigned int drmfmt = secUtilGetDrmFormat (id); + + size = sizeof (formats) / sizeof (unsigned int); + + for (i = 0; i < size; i++) + if (formats[i] == id) + break; + + if (i == size) + { + XDBG_ERROR (MWB, "wb not support : '%c%c%c%c'.\n", FOURCC_STR (id)); + return 0; + } + + drmfmts = secDrmIppGetFormatList (&num); + if (!drmfmts) + { + XDBG_ERROR (MWB, "no drm format list.\n"); + return 0; + } + + for (i = 0; i < num; i++) + if (drmfmts[i] == drmfmt) + { + free (drmfmts); + return drmfmt; + } + + XDBG_ERROR (MWB, "drm ipp not support : '%c%c%c%c'.\n", FOURCC_STR (id)); + + free (drmfmts); + + return 0; +} + +static void +_secWbCallNotifyFunc (SECWb *wb, SECWbNotify noti, void *noti_data) +{ + SECWbNotifyFuncInfo *info; + + nt_list_for_each_entry (info, wb->info_list, next) + { + if (info->noti == noti && info->func) + info->func (wb, noti, noti_data, info->user_data); + } +} + +static void +_secWbLayerNotifyFunc (SECLayer *layer, int type, void *type_data, void *data) +{ + SECWb *wb = (SECWb*)data; + SECVideoBuf *vbuf = (SECVideoBuf*)type_data; + + if (type != LAYER_VBLANK) + return; + + XDBG_RETURN_IF_FAIL (wb != NULL); + XDBG_RETURN_IF_FAIL (VBUF_IS_VALID (vbuf)); + + if (wb->wait_show >= 0 && wb->dst_buf[wb->wait_show] != vbuf) + XDBG_WARNING (MWB, "wait_show(%d,%p) != showing_vbuf(%p). \n", + wb->wait_show, wb->dst_buf[wb->wait_show], vbuf); + + if (wb->now_showing >= 0) + _secWbQueue (wb, wb->now_showing); + + wb->now_showing = wb->wait_show; + wb->wait_show = -1; + + XDBG_DEBUG (MWB, "now_showing(%d,%p). \n", wb->now_showing, vbuf); +} + +static Bool +_secWbCalTvoutRect (SECWb *wb) +{ + SECModePtr pSecMode = (SECModePtr) SECPTR (wb->pScrn)->pSecMode; + int src_w, src_h, dst_w, dst_h; + + if (!wb->tvout) + { + if (wb->width == 0 || wb->height == 0) + { + wb->width = pSecMode->main_lcd_mode.hdisplay; + wb->height = pSecMode->main_lcd_mode.vdisplay; + } + + src_w = pSecMode->main_lcd_mode.hdisplay; + src_h = pSecMode->main_lcd_mode.vdisplay; + dst_w = wb->width; + dst_h = wb->height; + XDBG_RETURN_VAL_IF_FAIL (src_w > 0 && src_h > 0, FALSE); + XDBG_RETURN_VAL_IF_FAIL (dst_w > 0 && dst_h > 0, FALSE); + + if (wb->rotate % 180) + SWAP (src_w, src_h); + + secUtilAlignRect (src_w, src_h, dst_w, dst_h, &wb->drm_dst, TRUE); + } + else + { + src_w = (int)pSecMode->main_lcd_mode.hdisplay; + src_h = (int)pSecMode->main_lcd_mode.vdisplay; + dst_w = (int)pSecMode->ext_connector_mode.hdisplay; + dst_h = (int)pSecMode->ext_connector_mode.vdisplay; + XDBG_RETURN_VAL_IF_FAIL (src_w > 0 && src_h > 0, FALSE); + XDBG_RETURN_VAL_IF_FAIL (dst_w > 0 && dst_h > 0, FALSE); + + if (wb->rotate % 180) + SWAP (src_w, src_h); + + if (wb->lpos == LAYER_UPPER) + { + /* Mixer can't scale. */ + wb->width = dst_w; + wb->height = dst_h; + wb->tv_dst.width = wb->width; + wb->tv_dst.height = wb->height; + + secUtilAlignRect (src_w, src_h, dst_w, dst_h, &wb->drm_dst, TRUE); + } + else /* LAYER_LOWER1 */ + { + /* VP can scale */ + secUtilAlignRect (src_w, src_h, dst_w, dst_h, &wb->tv_dst, TRUE); + + wb->width = src_w; + wb->height = src_h; + + wb->drm_dst.width = wb->width; + wb->drm_dst.height = wb->height; + } + } + + XDBG_TRACE (MWB, "tvout(%d) lpos(%d) src(%dx%d) drm_dst(%d,%d %dx%d) tv_dst(%d,%d %dx%d).\n", + wb->tvout, wb->lpos, wb->width, wb->height, + wb->drm_dst.x, wb->drm_dst.y, wb->drm_dst.width, wb->drm_dst.height, + wb->tv_dst.x, wb->tv_dst.y, wb->tv_dst.width, wb->tv_dst.height); + + return TRUE; +} + +static void +_secWbQueue (SECWb *wb, int index) +{ + struct drm_exynos_ipp_queue_buf buf; + int j; + + if (index < 0) + return; + + XDBG_RETURN_IF_FAIL (wb->dst_buf[index]->showing == FALSE); + + CLEAR (buf); + buf.ops_id = EXYNOS_DRM_OPS_DST; + buf.buf_type = IPP_BUF_ENQUEUE; + buf.prop_id = wb->prop_id; + buf.buf_id = index; + buf.user_data = (__u64)(unsigned int)wb; + + for (j = 0; j < PLANAR_CNT; j++) + buf.handle[j] = wb->dst_buf[index]->handles[j]; + + if (!secDrmIppQueueBuf (wb->pScrn, &buf)) + return; + + wb->queued[index] = TRUE; + wb->dst_buf[index]->dirty = TRUE; + + XDBG_DEBUG (MWB, "index(%d)\n", index); +} + +static int +_secWbDequeued (SECWb *wb, Bool skip_put, int index) +{ + int i, remain = 0; + + XDBG_RETURN_VAL_IF_FAIL (index < wb->buf_num, -1); + XDBG_WARNING_IF_FAIL (wb->dst_buf[index]->showing == FALSE); + + XDBG_DEBUG (MWB, "skip_put(%d) index(%d)\n", skip_put, index); + + if (!wb->queued[index]) + XDBG_WARNING (MWB, "buf(%d) already dequeued.\n", index); + + wb->queued[index] = FALSE; + + for (i = 0; i< wb->buf_num; i++) + { + if (wb->queued[i]) + remain++; + } + + /* the count of remain buffers should be more than 2. */ + if (remain >= WB_BUF_MIN) + _secWbCallNotifyFunc (wb, WB_NOTI_IPP_EVENT, (void*)wb->dst_buf[index]); + else + XDBG_DEBUG (MWB, "remain buffer count: %d\n", remain); + + if (wb->tvout) + { + if (!wb->tv) + { + if (wb->tv_dst.width > 0 && wb->tv_dst.height > 0) + wb->tv = secVideoTvConnect (wb->pScrn, wb->id, wb->lpos); + + if (wb->tv && !secUtilEnsureExternalCrtc (wb->pScrn)) + { + wb->tvout = FALSE; + secVideoTvDisconnect (wb->tv); + wb->tv = NULL; + } + + if (wb->tv) + { + SECLayer *layer = secVideoTvGetLayer (wb->tv); + secLayerEnableVBlank (layer, TRUE); + secLayerAddNotifyFunc (layer, _secWbLayerNotifyFunc, wb); + } + } + + if (!skip_put && wb->tv) + { + wb->wait_show = index; + secVideoTvPutImage (wb->tv, wb->dst_buf[index], &wb->tv_dst, 0); + } + } + + if (remain == 0) + XDBG_ERROR (MWB, "*** wb's buffer empty!! *** \n"); + + XDBG_DEBUG (MWB, "tv(%p) wait_show(%d) remain(%d)\n", wb->tv, + wb->wait_show, remain); + + return index; +} + +static CARD32 +_secWbIppRetireTimeout (OsTimerPtr timer, CARD32 now, pointer arg) +{ + SECWb *wb = (SECWb*)arg; + + if (wb->ipp_timer) + { + TimerFree (wb->ipp_timer); + wb->ipp_timer = NULL; + } + + XDBG_ERROR (MWB, "failed : +++ WB IPP Retire Timeout!!\n"); + + return 0; +} + +unsigned int +secWbGetPropID (void) +{ + if (!keep_wb) + return -1; + + return keep_wb->prop_id; +} + +void +secWbHandleIppEvent (int fd, unsigned int *buf_idx, void *data) +{ + SECWb *wb = (SECWb*)data; + SECPtr pSec; + int index = buf_idx[EXYNOS_DRM_OPS_DST]; + + if (!wb) + { + XDBG_ERROR (MWB, "data is %p \n", data); + return; + } + + if (keep_wb != wb) + { + XDBG_WARNING (MWB, "Useless ipp event! (%p) \n", wb); + return; + } + + if (wb->event_timer) + { + TimerFree (wb->event_timer); + wb->event_timer = NULL; + } + + if (wb->status == STATUS_STOPPED) + { + XDBG_ERROR (MWB, "stopped. ignore a event.\n", data); + return; + } + + if (wb->ipp_timer) + { + TimerFree (wb->ipp_timer); + wb->ipp_timer = NULL; + } + + wb->ipp_timer = TimerSet (wb->ipp_timer, 0, 2000, _secWbIppRetireTimeout, wb); + + XDBG_DEBUG (MWB, "=============== wb(%p) !\n", wb); + + pSec = SECPTR (wb->pScrn); + + if (pSec->xvperf_mode & XBERC_XVPERF_MODE_WB) + { + CARD32 cur, sub; + cur = GetTimeInMillis (); + sub = cur - wb->prev_time; + wb->prev_time = cur; + ErrorF ("wb evt interval : %6ld ms\n", sub); + } + + if (pSec->wb_fps) + _secWbCountFps (wb); + else + _secWbCountStop (wb); + + if (wb->rotate_timer) + { + _secWbDequeued (wb, TRUE, index); + _secWbQueue (wb, index); + } + else + { + if (wb->wait_show >= 0) + { + _secWbDequeued (wb, TRUE, index); + _secWbQueue (wb, index); + } + else + { + _secWbDequeued (wb, FALSE, index); + + if (wb->wait_show < 0 && !wb->dst_buf[index]->showing) + _secWbQueue (wb, index); + } + } + + _secWbCallNotifyFunc (wb, WB_NOTI_IPP_EVENT_DONE, NULL); + + XDBG_DEBUG (MWB, "=============== !\n"); +} + +static Bool +_secWbEnsureDrmDstBuffer (SECWb *wb) +{ + int i; + + for (i = 0; i < wb->buf_num; i++) + { + if (wb->dst_buf[i]) + { + secUtilClearVideoBuffer (wb->dst_buf[i]); + continue; + } + + wb->dst_buf[i] = secUtilAllocVideoBuffer (wb->pScrn, wb->id, + wb->width, wb->height, + keep_wb->scanout, TRUE, + secVideoIsSecureMode (wb->pScrn)); + XDBG_GOTO_IF_FAIL (wb->dst_buf[i] != NULL, fail_to_ensure); + } + + return TRUE; +fail_to_ensure: + _secWbCloseDrmDstBuffer (wb); + + return FALSE; +} + +static void +_secWbCloseDrmDstBuffer (SECWb *wb) +{ + int i; + + for (i = 0; i < wb->buf_num; i++) + { + if (wb->dst_buf[i]) + { + secUtilVideoBufferUnref (wb->dst_buf[i]); + wb->dst_buf[i] = NULL; + } + } +} + +static void +_secWbClearDrmDstBuffer (SECWb *wb) +{ + int i; + + for (i = 0; i < wb->buf_num; i++) + { + if (wb->dst_buf[i]) + { + if (!wb->dst_buf[i]->showing && wb->dst_buf[i]->need_reset) + secUtilClearVideoBuffer (wb->dst_buf[i]); + else + wb->dst_buf[i]->need_reset = TRUE; + } + } +} + +static CARD32 +_secWbEventTimeout (OsTimerPtr timer, CARD32 now, pointer arg) +{ + SECWb *wb = (SECWb*) arg; + + if (!wb) + return 0; + + if (wb->event_timer) + { + TimerFree (wb->event_timer); + wb->event_timer = NULL; + } + + XDBG_ERROR (MWB, "*** ipp event not happen!! \n"); + + return 0; +} + +static Bool +_secWbOpenDrm (SECWb *wb) +{ + SECPtr pSec = SECPTR (wb->pScrn); + SECModePtr pSecMode = (SECModePtr)pSec->pSecMode; + int i; + unsigned int drmfmt = 0; + struct drm_exynos_ipp_property property; + enum drm_exynos_degree degree; + struct drm_exynos_ipp_cmd_ctrl ctrl; + + if (wb->need_rotate_hook) + _secWbRegisterRotateHook (wb, TRUE); + + if (!_secWbCalTvoutRect (wb)) + goto fail_to_open; + + drmfmt = _secWbSupportFormat (wb->id); + XDBG_GOTO_IF_FAIL (drmfmt > 0, fail_to_open); + + if ((wb->rotate) % 360 == 90) + degree = EXYNOS_DRM_DEGREE_90; + else if ((wb->rotate) % 360 == 180) + degree = EXYNOS_DRM_DEGREE_180; + else if ((wb->rotate) % 360 == 270) + degree = EXYNOS_DRM_DEGREE_270; + else + degree = EXYNOS_DRM_DEGREE_0; + + CLEAR (property); + property.config[0].ops_id = EXYNOS_DRM_OPS_SRC; + property.config[0].fmt = DRM_FORMAT_YUV444; + property.config[0].sz.hsize = (__u32)pSecMode->main_lcd_mode.hdisplay; + property.config[0].sz.vsize = (__u32)pSecMode->main_lcd_mode.vdisplay; + property.config[0].pos.x = 0; + property.config[0].pos.y = 0; + property.config[0].pos.w = (__u32)pSecMode->main_lcd_mode.hdisplay; + property.config[0].pos.h = (__u32)pSecMode->main_lcd_mode.vdisplay; + property.config[1].ops_id = EXYNOS_DRM_OPS_DST; + property.config[1].degree = degree; + property.config[1].fmt = drmfmt; + property.config[1].sz.hsize = wb->width; + property.config[1].sz.vsize = wb->height; + property.config[1].pos.x = (__u32)wb->drm_dst.x; + property.config[1].pos.y = (__u32)wb->drm_dst.y; + property.config[1].pos.w = (__u32)wb->drm_dst.width; + property.config[1].pos.h = (__u32)wb->drm_dst.height; + property.cmd = IPP_CMD_WB; +#ifdef _F_WEARABLE_FEATURE_ + property.type = IPP_EVENT_DRIVEN; +#endif + property.prop_id = wb->prop_id; + property.refresh_rate = wb->hz; + property.protect = wb->secure; + + wb->prop_id = secDrmIppSetProperty (wb->pScrn, &property); + XDBG_GOTO_IF_FAIL (wb->prop_id >= 0, fail_to_open); + + XDBG_TRACE (MWB, "prop_id(%d) drmfmt(%c%c%c%c) size(%dx%d) crop(%d,%d %dx%d) rotate(%d)\n", + wb->prop_id, FOURCC_STR(drmfmt), wb->width, wb->height, + wb->drm_dst.x, wb->drm_dst.y, wb->drm_dst.width, wb->drm_dst.height, + wb->rotate); + + if (!_secWbEnsureDrmDstBuffer (wb)) + goto fail_to_open; + + for (i = 0; i < wb->buf_num; i++) + { + struct drm_exynos_ipp_queue_buf buf; + int j; + + if (wb->dst_buf[i]->showing) + { + XDBG_DEBUG (MWB, "%d. name(%d) is showing\n", i, wb->dst_buf[i]->keys[0]); + continue; + } + + CLEAR (buf); + buf.ops_id = EXYNOS_DRM_OPS_DST; + buf.buf_type = IPP_BUF_ENQUEUE; + buf.prop_id = wb->prop_id; + buf.buf_id = i; + buf.user_data = (__u64)(unsigned int)wb; + + XDBG_GOTO_IF_FAIL (wb->dst_buf[i] != NULL, fail_to_open); + + for (j = 0; j < PLANAR_CNT; j++) + buf.handle[j] = wb->dst_buf[i]->handles[j]; + + if (!secDrmIppQueueBuf (wb->pScrn, &buf)) + goto fail_to_open; + + wb->queued[i] = TRUE; + } + + CLEAR (ctrl); + ctrl.prop_id = wb->prop_id; + ctrl.ctrl = IPP_CTRL_PLAY; + if (!secDrmIppCmdCtrl (wb->pScrn, &ctrl)) + goto fail_to_open; + + wb->event_timer = TimerSet (wb->event_timer, 0, 3000, _secWbEventTimeout, wb); + + return TRUE; + +fail_to_open: + + _secWbCloseDrm (wb); + + _secWbCloseDrmDstBuffer (wb); + + return FALSE; +} + +static void +_secWbCloseDrm (SECWb *wb) +{ + struct drm_exynos_ipp_cmd_ctrl ctrl; + int i; + + _secWbCountStop (wb); + + XDBG_TRACE (MWB, "now_showing(%d) \n", wb->now_showing); + + if (wb->tv) + { + secVideoTvDisconnect (wb->tv); + wb->tv = NULL; + wb->wait_show = -1; + wb->now_showing = -1; + } + + for (i = 0; i < wb->buf_num; i++) + { + struct drm_exynos_ipp_queue_buf buf; + int j; + + CLEAR (buf); + buf.ops_id = EXYNOS_DRM_OPS_DST; + buf.buf_type = IPP_BUF_DEQUEUE; + buf.prop_id = wb->prop_id; + buf.buf_id = i; + + if (wb->dst_buf[i]) + for (j = 0; j < EXYNOS_DRM_PLANAR_MAX && j < PLANAR_CNT; j++) + buf.handle[j] = wb->dst_buf[i]->handles[j]; + + secDrmIppQueueBuf (wb->pScrn, &buf); + + wb->queued[i] = FALSE; + } + + CLEAR (ctrl); + ctrl.prop_id = wb->prop_id; + ctrl.ctrl = IPP_CTRL_STOP; + secDrmIppCmdCtrl (wb->pScrn, &ctrl); + + wb->prop_id = -1; + + if (wb->rotate_timer) + { + TimerFree (wb->rotate_timer); + wb->rotate_timer = NULL; + } + + if (wb->event_timer) + { + TimerFree (wb->event_timer); + wb->event_timer = NULL; + } + + if (wb->ipp_timer) + { + TimerFree (wb->ipp_timer); + wb->ipp_timer = NULL; + } + + if (wb->need_rotate_hook) + _secWbRegisterRotateHook (wb, FALSE); +} + +static CARD32 +_secWbRotateTimeout (OsTimerPtr timer, CARD32 now, pointer arg) +{ + SECWb *wb = (SECWb*) arg; + PropertyPtr rotate_prop; + + if (!wb) + return 0; + + if (wb->rotate_timer) + { + TimerFree (wb->rotate_timer); + wb->rotate_timer = NULL; + } + + rotate_prop = secUtilGetWindowProperty (wb->pScrn->pScreen->root, "_E_ILLUME_ROTATE_ROOT_ANGLE"); + if (rotate_prop) + { + int rotate = *(int*)rotate_prop->data; + + XDBG_TRACE (MWB, "timeout : rotate(%d)\n", rotate); + + if (wb->rotate != rotate) + if (!secWbSetRotate (wb, rotate)) + return 0; + } + + /* make sure streaming is on. */ + secWbStart (wb); + + return 0; +} + +static void +_secWbRotateHook (CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + SECWb *wb = (SECWb*) unused; + ScrnInfoPtr pScrn; + + XDBG_RETURN_IF_FAIL (wb != NULL); + + XacePropertyAccessRec *rec = (XacePropertyAccessRec*)calldata; + PropertyPtr pProp = *rec->ppProp; + Atom name = pProp->propertyName; + + pScrn = wb->pScrn; + + if (rec->pWin != pScrn->pScreen->root) //Check Rootwindow + return; + + if (name == atom_wb_rotate && (rec->access_mode & DixWriteAccess)) + { + int rotate = *(int*)pProp->data; + SECModePtr pSecMode = (SECModePtr) SECPTR (pScrn)->pSecMode; + + if (wb->rotate == rotate) + return; + + XDBG_TRACE (MWB, "Change root angle(%d)\n", rotate); + + if (pSecMode->conn_mode == DISPLAY_CONN_MODE_VIRTUAL) + secWbStop (wb, FALSE); + else + secWbStop (wb, TRUE); + + wb->rotate_timer = TimerSet (wb->rotate_timer, 0, 800, + _secWbRotateTimeout, + wb); + } + + return; +} + +static Bool +_secWbRegisterRotateHook (SECWb *wb, Bool hook) +{ + ScrnInfoPtr pScrn = wb->pScrn; + + XDBG_TRACE (MWB, "hook(%d) \n", hook); + + if (hook) + { + PropertyPtr rotate_prop; + + rotate_prop = secUtilGetWindowProperty (pScrn->pScreen->root, "_E_ILLUME_ROTATE_ROOT_ANGLE"); + if (rotate_prop) + { + int rotate = *(int*)rotate_prop->data; + secWbSetRotate (wb, rotate); + } + + /* Hook for window rotate */ + if (atom_wb_rotate == None) + atom_wb_rotate = MakeAtom ("_E_ILLUME_ROTATE_ROOT_ANGLE", + strlen ("_E_ILLUME_ROTATE_ROOT_ANGLE"), FALSE); + + if (atom_wb_rotate != None) + { + if (!XaceRegisterCallback (XACE_PROPERTY_ACCESS, _secWbRotateHook, wb)) + XDBG_ERROR (MWB, "fail to XaceRegisterCallback.\n"); + } + else + XDBG_WARNING (MWB, "Cannot find _E_ILLUME_ROTATE_ROOT_ANGLE\n"); + } + else + XaceDeleteCallback (XACE_PROPERTY_ACCESS, _secWbRotateHook, wb); + + return TRUE; +} + +Bool +secWbIsOpened (void) +{ + return (keep_wb) ? TRUE : FALSE; +} + +Bool +secWbIsRunning (void) +{ + if (!keep_wb) + return FALSE; + + return (keep_wb->status == STATUS_STARTED) ? TRUE : FALSE; +} + +SECWb* +_secWbOpen (ScrnInfoPtr pScrn, unsigned int id, int width, int height, + Bool scanout, int hz, Bool need_rotate_hook, const char *func) +{ + SECModePtr pSecMode = SECPTR (pScrn)->pSecMode; + + XDBG_RETURN_VAL_IF_FAIL (pScrn != NULL, NULL); + + if (keep_wb) + { + XDBG_ERROR (MWB, "WB already opened. \n"); + return NULL; + } + + if (_secWbSupportFormat (id) == 0) + { + XDBG_ERROR (MWB, "'%c%c%c%c' not supported. \n", FOURCC_STR (id)); + return NULL; + } + + if (SECPTR (pScrn)->isLcdOff) + { + XDBG_ERROR (MWB, "Can't open wb during DPMS off. \n"); + return NULL; + } + + if (!keep_wb) + keep_wb = calloc (sizeof (SECWb), 1); + + XDBG_RETURN_VAL_IF_FAIL (keep_wb != NULL, FALSE); + + keep_wb->prop_id = -1; + keep_wb->pScrn = pScrn; + keep_wb->id = id; + + keep_wb->wait_show = -1; + keep_wb->now_showing = -1; + + keep_wb->width = width; + keep_wb->height = height; + keep_wb->status = STATUS_STOPPED; + + keep_wb->scanout = scanout; + keep_wb->hz = (hz > 0) ? hz : 60; + + if (pSecMode->conn_mode == DISPLAY_CONN_MODE_HDMI && + keep_wb->hz > pSecMode->ext_connector_mode.vrefresh) + keep_wb->buf_num = WB_BUF_MAX; + else + keep_wb->buf_num = WB_BUF_DEFAULT; + + if (id == FOURCC_RGB32) + keep_wb->lpos = LAYER_UPPER; + else + keep_wb->lpos = LAYER_LOWER1; + + keep_wb->need_rotate_hook = need_rotate_hook; + + XDBG_SECURE (MWB, "wb(%p) id(%c%c%c%c) size(%dx%d) scanout(%d) hz(%d) rhoot(%d) buf_num(%d): %s\n", keep_wb, + FOURCC_STR(id), keep_wb->width, keep_wb->height, scanout, hz, + need_rotate_hook, keep_wb->buf_num, func); + + return keep_wb; +} + +void +_secWbClose (SECWb *wb, const char *func) +{ + SECWbNotifyFuncInfo *info, *tmp; + + XDBG_RETURN_IF_FAIL (wb != NULL); + XDBG_RETURN_IF_FAIL (keep_wb == wb); + + secWbStop (wb, TRUE); + + XDBG_SECURE (MWB, "wb(%p): %s \n", wb, func); + + _secWbCallNotifyFunc (wb, WB_NOTI_CLOSED, NULL); + + nt_list_for_each_entry_safe (info, tmp, wb->info_list, next) + { + nt_list_del (info, wb->info_list, SECWbNotifyFuncInfo, next); + free (info); + } + + free (wb); + keep_wb = NULL; +} + +Bool +_secWbStart (SECWb *wb, const char *func) +{ + SECPtr pSec; + + XDBG_RETURN_VAL_IF_FAIL (wb != NULL, FALSE); + + pSec = SECPTR (wb->pScrn); + if (pSec->isLcdOff) + { + XDBG_ERROR (MWB, "Can't start wb(%p) during DPMS off. \n", wb); + return FALSE; + } + + if (wb->status == STATUS_STARTED) + return TRUE; + + if (!_secWbOpenDrm (wb)) + { + XDBG_ERROR (MWB, "open fail. \n"); + return FALSE; + } + + wb->status = STATUS_STARTED; + + _secWbCallNotifyFunc (wb, WB_NOTI_START, NULL); + + XDBG_TRACE (MWB, "start: %s \n", func); + + return TRUE; +} + +void +_secWbStop (SECWb *wb, Bool close_buf,const char *func) +{ + XDBG_RETURN_IF_FAIL (wb != NULL); + + if (wb->status == STATUS_STOPPED) + { + if (wb->rotate_timer) + { + TimerFree (wb->rotate_timer); + wb->rotate_timer = NULL; + } + return; + } + + _secWbCloseDrm (wb); + + if (close_buf) + _secWbCloseDrmDstBuffer (wb); + else + _secWbClearDrmDstBuffer (wb); + + wb->status = STATUS_STOPPED; + + _secWbCallNotifyFunc (wb, WB_NOTI_STOP, NULL); + + XDBG_TRACE (MWB, "stop: %s \n", func); +} + +Bool +secWbSetBuffer (SECWb *wb, SECVideoBuf **vbufs, int bufnum) +{ + int i; + + XDBG_RETURN_VAL_IF_FAIL (wb != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (wb->status != STATUS_STARTED, FALSE); + XDBG_RETURN_VAL_IF_FAIL (vbufs != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (wb->buf_num <= bufnum, FALSE); + XDBG_RETURN_VAL_IF_FAIL (bufnum <= WB_BUF_MAX, FALSE); + + for (i = 0; i < WB_BUF_MAX; i++) + { + if (wb->dst_buf[i]) + { + XDBG_ERROR (MWB, "already has %d buffers\n", wb->buf_num); + return FALSE; + } + } + + for (i = 0; i < bufnum; i++) + { + XDBG_GOTO_IF_FAIL (wb->id == vbufs[i]->id, fail_set_buffer); + XDBG_GOTO_IF_FAIL (wb->width == vbufs[i]->width, fail_set_buffer); + XDBG_GOTO_IF_FAIL (wb->height == vbufs[i]->height, fail_set_buffer); + XDBG_GOTO_IF_FAIL (wb->scanout == vbufs[i]->scanout, fail_set_buffer); + + wb->dst_buf[i] = secUtilVideoBufferRef (vbufs[i]); + XDBG_GOTO_IF_FAIL (wb->dst_buf[i] != NULL, fail_set_buffer); + + if (!wb->dst_buf[i]->showing && wb->dst_buf[i]->need_reset) + secUtilClearVideoBuffer (wb->dst_buf[i]); + else + wb->dst_buf[i]->need_reset = TRUE; + } + + wb->buf_num = bufnum; + + return TRUE; + +fail_set_buffer: + for (i = 0; i < WB_BUF_MAX; i++) + { + if (wb->dst_buf[i]) + { + secUtilVideoBufferUnref (wb->dst_buf[i]); + wb->dst_buf[i] = NULL; + } + } + + return FALSE; +} + +Bool +secWbSetRotate (SECWb *wb, int rotate) +{ + XDBG_RETURN_VAL_IF_FAIL (wb != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL ((rotate % 90) == 0, FALSE); + + if (wb->rotate == rotate) + return TRUE; + + XDBG_DEBUG (MWB, "rotate(%d) \n", rotate); + + wb->rotate = rotate; + + if (wb->status == STATUS_STARTED) + { + SECModePtr pSecMode = (SECModePtr) SECPTR (wb->pScrn)->pSecMode; + + if (pSecMode->conn_mode == DISPLAY_CONN_MODE_VIRTUAL) + secWbStop (wb, FALSE); + else + secWbStop (wb, TRUE); + + if (!secWbStart (wb)) + return FALSE; + } + + return TRUE; +} + +int +secWbGetRotate (SECWb *wb) +{ + XDBG_RETURN_VAL_IF_FAIL (wb != NULL, FALSE); + + return wb->rotate; +} + +void +secWbSetTvout (SECWb *wb, Bool enable) +{ + XDBG_RETURN_IF_FAIL (wb != NULL); + + enable = (enable > 0) ? TRUE : FALSE; + + XDBG_TRACE (MWB, "tvout(%d) \n", enable); + + wb->tvout = enable; + + if (wb->status == STATUS_STARTED) + { + secWbStop (wb, FALSE); + + if (!secWbStart (wb)) + return; + } +} + +Bool +secWbGetTvout (SECWb *wb) +{ + XDBG_RETURN_VAL_IF_FAIL (wb != NULL, FALSE); + + return wb->tvout; +} + +void +secWbSetSecure (SECWb *wb, Bool secure) +{ + XDBG_RETURN_IF_FAIL (wb != NULL); + + secure = (secure > 0) ? TRUE : FALSE; + + if (wb->secure == secure) + return; + + XDBG_TRACE (MWB, "secure(%d) \n", secure); + + wb->secure = secure; + + if (wb->status == STATUS_STARTED) + { + secWbStop (wb, TRUE); + + if (!secWbStart (wb)) + return; + } +} + +Bool +secWbGetSecure (SECWb *wb) +{ + XDBG_RETURN_VAL_IF_FAIL (wb != NULL, FALSE); + + return wb->secure; +} + +void +secWbGetSize (SECWb *wb, int *width, int *height) +{ + XDBG_RETURN_IF_FAIL (wb != NULL); + + if (width) + *width = wb->width; + + if (height) + *height = wb->height; +} + +Bool +secWbCanDequeueBuffer (SECWb *wb) +{ + int i, remain = 0; + + XDBG_RETURN_VAL_IF_FAIL (wb != NULL, FALSE); + + for (i = 0; i< wb->buf_num; i++) + if (wb->queued[i]) + remain++; + + XDBG_DEBUG (MWB, "buf_num(%d) remain(%d)\n", wb->buf_num, remain); + + return (remain > WB_BUF_MIN) ? TRUE : FALSE; +} + +void +secWbQueueBuffer (SECWb *wb, SECVideoBuf *vbuf) +{ + int i; + + XDBG_RETURN_IF_FAIL (wb != NULL); + XDBG_RETURN_IF_FAIL (vbuf != NULL); + XDBG_RETURN_IF_FAIL (vbuf->showing == FALSE); + + if (wb->prop_id == -1) + return; + + for (i = 0; i < wb->buf_num; i++) + if (wb->dst_buf[i] == vbuf) + { + XDBG_DEBUG (MWB, "%d queueing.\n", i); + _secWbQueue (wb, i); + } +} + +void +secWbAddNotifyFunc (SECWb *wb, SECWbNotify noti, WbNotifyFunc func, void *user_data) +{ + SECWbNotifyFuncInfo *info; + + XDBG_RETURN_IF_FAIL (wb != NULL); + + if (!func) + return; + + nt_list_for_each_entry (info, wb->info_list, next) + { + if (info->func == func) + return; + } + + XDBG_DEBUG (MWB, "noti(%d) func(%p) user_data(%p) \n", noti, func, user_data); + + info = calloc (1, sizeof (SECWbNotifyFuncInfo)); + XDBG_RETURN_IF_FAIL (info != NULL); + + info->noti = noti; + info->func = func; + info->user_data = user_data; + + if (wb->info_list) + nt_list_append (info, wb->info_list, SECWbNotifyFuncInfo, next); + else + wb->info_list = info; +} + +void +secWbRemoveNotifyFunc (SECWb *wb, WbNotifyFunc func) +{ + SECWbNotifyFuncInfo *info; + + XDBG_RETURN_IF_FAIL (wb != NULL); + + if (!func) + return; + + nt_list_for_each_entry (info, wb->info_list, next) + { + if (info->func == func) + { + XDBG_DEBUG (MWB, "func(%p) \n", func); + nt_list_del(info, wb->info_list, SECWbNotifyFuncInfo, next); + free (info); + return; + } + } +} + +SECWb* +secWbGet (void) +{ + return keep_wb; +} + +void +secWbDestroy (void) +{ + if (!keep_wb) + return; + + secWbClose (keep_wb); +} diff --git a/src/ipp/sec_wb.h b/src/ipp/sec_wb.h new file mode 100644 index 0000000..38b9752 --- /dev/null +++ b/src/ipp/sec_wb.h @@ -0,0 +1,95 @@ +/************************************************************************** + +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. + +**************************************************************************/ +#ifndef __SEC_WB_H__ +#define __SEC_WB_H__ + +#include <sys/types.h> +#include <xf86str.h> + +#include "sec_video_types.h" + +typedef struct _SECWb SECWb; + +typedef enum +{ + WB_NOTI_INIT, + WB_NOTI_START, + WB_NOTI_IPP_EVENT, + WB_NOTI_IPP_EVENT_DONE, + WB_NOTI_STOP, + WB_NOTI_CLOSED, +} SECWbNotify; + +typedef void (*WbNotifyFunc) (SECWb *wb, SECWbNotify noti, void *noti_data, void *user_data); + +/* Don't close the wb from secWbGet */ +SECWb* secWbGet (void); + +/* If width, height is 0, they will be main display size. */ +SECWb* _secWbOpen (ScrnInfoPtr pScrn, + unsigned int id, int width, int height, + Bool scanout, int hz, Bool need_rotate_hook, + const char *func); +void _secWbClose (SECWb *wb, const char *func); +Bool _secWbStart (SECWb *wb, const char *func); +void _secWbStop (SECWb *wb, Bool close_buf, const char *func); + +#define secWbOpen(s,i,w,h,c,z,n) _secWbOpen(s,i,w,h,c,z,n,__FUNCTION__) +#define secWbClose(w) _secWbClose(w,__FUNCTION__) +#define secWbStart(w) _secWbStart(w,__FUNCTION__) +#define secWbStop(w,c) _secWbStop(w,c,__FUNCTION__) + +Bool secWbSetBuffer (SECWb *wb, SECVideoBuf **vbufs, int bufnum); + +Bool secWbSetRotate (SECWb *wb, int rotate); +int secWbGetRotate (SECWb *wb); + +void secWbSetTvout (SECWb *wb, Bool enable); +Bool secWbGetTvout (SECWb *wb); + +void secWbSetSecure (SECWb *wb, Bool secure); +Bool secWbGetSecure (SECWb *wb); + +void secWbGetSize (SECWb *wb, int *width, int *height); + +Bool secWbCanDequeueBuffer (SECWb *wb); +void secWbQueueBuffer (SECWb *wb, SECVideoBuf *vbuf); + +void secWbAddNotifyFunc (SECWb *wb, SECWbNotify noti, WbNotifyFunc func, void *user_data); +void secWbRemoveNotifyFunc (SECWb *wb, WbNotifyFunc func); + +Bool secWbIsOpened (void); +Bool secWbIsRunning (void); +void secWbDestroy (void); + +unsigned int secWbGetPropID (void); +void secWbHandleIppEvent (int fd, unsigned int *buf_idx, void *data); + +#endif // __SEC_WB_H__ diff --git a/src/memory/sec_memory_flush.c b/src/memory/sec_memory_flush.c new file mode 100644 index 0000000..ad7d631 --- /dev/null +++ b/src/memory/sec_memory_flush.c @@ -0,0 +1,141 @@ +/**************************************************************************
+
+xserver-xorg-video-exynos
+
+Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Contact: SooChan Lim <sc1.lim@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 "sec.h"
+#include <malloc.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <malloc.h>
+
+#include "sec.h"
+#include "xace.h"
+#include "xacestr.h"
+
+#include <X11/extensions/dpmsconst.h>
+#include "sec_util.h"
+#include "sec_dpms.h"
+#include "sec_memory_flush.h"
+
+extern CallbackListPtr DPMSCallback;
+
+static void
+_secMemoryDPMS (CallbackListPtr *list, pointer closure, pointer calldata)
+{
+ SecDPMSPtr pDPMSInfo = (SecDPMSPtr) calldata;
+ ScrnInfoPtr pScrn;
+ //int mode = pDPMSInfo->mode;
+ //int flags = pDPMSInfo->flags;
+
+ if (!pDPMSInfo || !(pScrn = pDPMSInfo->pScrn))
+ {
+ XDBG_ERROR (MMEM, "[X11][%s] DPMS info or screen info is invalid !\n", __FUNCTION__);
+ return;
+ }
+
+ SECPtr pSec = SECPTR (pScrn);
+
+ switch (DPMSPowerLevel)
+ {
+ case DPMSModeOn:
+ case DPMSModeSuspend:
+ break;
+
+ case DPMSModeStandby://LCD on
+ if (pSec->isLcdOff == FALSE) break;
+ break;
+
+ case DPMSModeOff://LCD off
+ if (pSec->isLcdOff == TRUE) break;
+
+ //stack and heap memory trim
+ secMemoryStackTrim();
+ malloc_trim (0);
+
+ XDBG_DEBUG (MMEM, "[X11][%s] Memory flush done !\n", __FUNCTION__);
+ break;
+
+ default:
+ return;
+ }
+}
+
+static void
+_secMemoryClientStateEvent (CallbackListPtr *list, pointer closure, pointer calldata)
+{
+ static int chance = 0;
+ NewClientInfoRec *clientinfo = (NewClientInfoRec*)calldata;
+ ClientPtr pClient = clientinfo->client;
+
+ if (ClientStateGone == pClient->clientState)
+ {
+ int flush;
+
+ //memory flush will be done for every third client gone
+ chance++;
+ flush = !(chance = chance % 3);
+
+ if ( flush )
+ {
+ //stack and heap memory trim
+ secMemoryStackTrim();
+ malloc_trim (0);
+
+ XDBG_DEBUG (MMEM, "[X11][%s] Memory flush done !\n", __FUNCTION__);
+ }
+ }
+}
+
+Bool
+secMemoryInstallHooks (void)
+{
+ int ret = TRUE;
+ ret &= AddCallback (&ClientStateCallback, _secMemoryClientStateEvent, NULL);
+ ret &= AddCallback (&DPMSCallback, _secMemoryDPMS, NULL);
+
+ if (!ret)
+ {
+ XDBG_ERROR (MMEM, "secMemoryInstallHooks: Failed to register one or more callbacks\n");
+ return BadAlloc;
+ }
+
+ return Success;
+}
+
+
+Bool
+secMemoryUninstallHooks (void)
+{
+ DeleteCallback (&ClientStateCallback, _secMemoryClientStateEvent, NULL);
+ DeleteCallback (&DPMSCallback, _secMemoryDPMS, NULL);
+
+ return Success;
+}
diff --git a/src/memory/sec_memory_flush.h b/src/memory/sec_memory_flush.h new file mode 100644 index 0000000..d9c1062 --- /dev/null +++ b/src/memory/sec_memory_flush.h @@ -0,0 +1,85 @@ +/**************************************************************************
+
+xserver-xorg-video-exynos
+
+Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Contact: SooChan Lim <sc1.lim@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.
+
+**************************************************************************/
+
+#ifndef SEC_MEMORY_H
+#define SEC_MEMORY_H
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <X11/Xdefs.h> /* for Bool */
+
+#define GETSP() ({ unsigned int sp; asm volatile ("mov %0,sp " : "=r"(sp)); sp;})
+#define BUF_SIZE 256
+#define _PAGE_SIZE (1 << 12)
+#define _ALIGN_UP(addr,size) (((addr)+((size)-1))&(~((size)-1)))
+#define _ALIGN_DOWN(addr,size) ((addr)&(~((size)-1)))
+#define PAGE_ALIGN(addr) _ALIGN_DOWN(addr, _PAGE_SIZE)
+
+static inline void secMemoryStackTrim (void)
+{
+ unsigned int sp;
+ char buf[BUF_SIZE];
+ FILE* file;
+ unsigned int stacktop;
+ int found = 0;
+
+ sp = GETSP();
+
+ snprintf (buf, BUF_SIZE, "/proc/%d/maps", getpid());
+ file = fopen (buf,"r");
+
+ if (!file)
+ return;
+
+ while (fgets (buf, BUF_SIZE, file) != NULL)
+ {
+ if (strstr (buf, "[stack]"))
+ {
+ found = 1;
+ break;
+ }
+ }
+
+ fclose (file);
+
+ if (found)
+ {
+ sscanf (buf,"%x-",&stacktop);
+ if (madvise ((void*)PAGE_ALIGN (stacktop), PAGE_ALIGN (sp)-stacktop, MADV_DONTNEED) < 0)
+ perror ("stack madvise fail");
+ }
+}
+
+Bool secMemoryInstallHooks (void);
+Bool secMemoryUninstallHooks (void);
+
+#endif/* SEC_MEMORY_H */
diff --git a/src/neon/copy_area.c b/src/neon/copy_area.c new file mode 100644 index 0000000..9bd2c71 --- /dev/null +++ b/src/neon/copy_area.c @@ -0,0 +1,535 @@ +/**************************************************************************
+
+xserver-xorg-video-exynos
+
+Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Contact: SooChan Lim <sc1.lim@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 "neonmem.h"
+
+//#define _USE_LIBC
+//#define _X86_SSE2 // may not work on linux platform
+#define _ARM_NEON
+
+#ifdef _USE_LIBC
+#include <string.h>
+#endif
+
+//////////////////////////////////////////////////////////////////////////
+// General C implementation of copy functions
+//////////////////////////////////////////////////////////////////////////
+static inline void memcpy32 (unsigned long *dst, unsigned long *src, int size)
+{
+ while ( size > 0 )
+ {
+ *dst++ = *src++;
+ size--;
+ }
+}
+
+static inline void memcpy_forward_32 (unsigned long *dst, unsigned long *src, int size)
+{
+ while ( size > 0 )
+ {
+ *dst++ = *src++;
+ size--;
+ }
+}
+
+static inline void memcpy_backward_32 (unsigned long *dst, unsigned long *src, int size)
+{
+ dst = dst + size;
+ src = src + size;
+
+ while ( size > 0 )
+ {
+ *(--dst) = *(--src);
+ size--;
+ }
+}
+
+static inline void memcpy_forward_16 (unsigned short *dst, unsigned short *src, int size)
+{
+ while ( size > 0 )
+ {
+ *dst++ = *src++;
+ size--;
+ }
+}
+
+static inline void memcpy_backward_16 (unsigned short *dst, unsigned short *src, int size)
+{
+ dst = dst + size;
+ src = src + size;
+
+ while ( size > 0 )
+ {
+ *(--dst) = *(--src);
+ size--;
+ }
+}
+
+static inline void memcpy_forward (unsigned char *dst, unsigned char *src, int size)
+{
+ while ( size > 0 && ((unsigned long) dst & 3))
+ {
+ *(unsigned short*)dst = *(unsigned short*)src;
+ dst += 2;
+ src += 2;
+ size -= 2;
+ }
+
+ while ( size >= 4 )
+ {
+ *(unsigned long*)dst = *(unsigned long*)src;
+ dst += 4;
+ src += 4;
+ size -= 4;
+ }
+
+ while ( size > 0 )
+ {
+ *dst++ = *src++;
+ size--;
+ }
+}
+
+static inline void memcpy_backward (unsigned char *dst, unsigned char *src, int size)
+{
+ dst = dst + size;
+ src = src + size;
+
+ while ( size > 0 && ((unsigned long) dst & 3))
+ {
+ *(--dst) = *(--src);
+ size--;
+ }
+
+ while ( size >= 4 )
+ {
+ dst -= 4;
+ src -= 4;
+ size -= 4;
+ *(unsigned long*)dst = *(unsigned long*)src;
+ }
+
+ while ( size > 0 )
+ {
+ *(--dst) = *(--src);
+ size--;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// ARM assembly implementation of copy functions
+//////////////////////////////////////////////////////////////////////////
+#ifdef _ARM_ASM
+static inline void memcpy_forward (unsigned char *dst, unsigned char *src, int size)
+{
+
+}
+
+static inline void memcpy_backward (unsigned char *dst, unsigned char *src, int size)
+{
+
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////
+// ARM NEON implementation of copy functions
+//////////////////////////////////////////////////////////////////////////
+#ifdef _ARM_NEON
+extern void memcpy_forward_32_neon (unsigned long *dst, unsigned long *src, int size);
+extern void memcpy_backward_32_neon (unsigned long *dst, unsigned long *src, int size);
+extern void memcpy_forward_16_neon (unsigned short *dst, unsigned short *src, int size);
+extern void memcpy_backward_16_neon (unsigned short *dst, unsigned short *src, int size);
+#endif
+
+//////////////////////////////////////////////////////////////////////////
+// X86 SSE2 copy functions
+//////////////////////////////////////////////////////////////////////////
+#ifdef _X86_SSE2
+#include <emmintrin.h>
+
+static inline void memcpy_forward_sse2 (unsigned char *dst, unsigned char *src, int size)
+{
+ while ( size > 0 && ((unsigned long) dst & 1))
+ {
+ *dst++ = *src++;
+ size--;
+ }
+
+ while ( size > 0 && ((unsigned long) dst & 3))
+ {
+ *(unsigned short*)dst = *(unsigned short*)src;
+ dst += 2;
+ src += 2;
+ size -= 2;
+ }
+
+ while ( size > 0 && ((unsigned long) dst & 63))
+ {
+ *(unsigned long*)dst = *(unsigned long*)src;
+ dst += 4;
+ src += 4;
+ size -= 4;
+ }
+
+ if ((reinterpret_cast<unsigned long> (src) & 15) == 0 )
+ {
+ while ( size >= 64 )
+ {
+ __m128 xmm0, xmm1, xmm2, xmm3;
+
+ //_mm_prefetch((const char*)(src+320), _MM_HINT_NTA);
+
+ xmm0 = _mm_load_ps ((float*)(src));
+ xmm1 = _mm_load_ps ((float*)(src + 16));
+ xmm2 = _mm_load_ps ((float*)(src + 32));
+ xmm3 = _mm_load_ps ((float*)(src + 48));
+
+ _mm_stream_ps ((float*)(dst), xmm0);
+ _mm_stream_ps ((float*)(dst + 16), xmm1);
+ _mm_stream_ps ((float*)(dst + 32), xmm2);
+ _mm_stream_ps ((float*)(dst + 48), xmm3);
+
+ src += 64;
+ dst += 64;
+ size -= 64;
+ }
+
+ while ( size >= 16 )
+ {
+ _mm_stream_ps ((float*)dst, _mm_load_ps ((float*)src));
+ dst += 16;
+ src += 16;
+ size -= 16;
+ }
+ }
+ else
+ {
+ while ( size >= 64 )
+ {
+ __m128 xmm0, xmm1, xmm2, xmm3;
+
+ //_mm_prefetch((const char*)(src+320), _MM_HINT_NTA);
+
+ xmm0 = _mm_loadu_ps ((float*)(src));
+ xmm1 = _mm_loadu_ps ((float*)(src + 16));
+ xmm2 = _mm_loadu_ps ((float*)(src + 32));
+ xmm3 = _mm_loadu_ps ((float*)(src + 48));
+
+ _mm_stream_ps ((float*)(dst), xmm0);
+ _mm_stream_ps ((float*)(dst + 16), xmm1);
+ _mm_stream_ps ((float*)(dst + 32), xmm2);
+ _mm_stream_ps ((float*)(dst + 48), xmm3);
+
+ src += 64;
+ dst += 64;
+ size -= 64;
+ }
+
+ while ( size >= 16 )
+ {
+ _mm_stream_ps ((float*)dst, _mm_loadu_ps ((float*)src));
+ dst += 16;
+ src += 16;
+ size -= 16;
+ }
+ }
+
+ while ( size >= 4 )
+ {
+ *(unsigned long*)dst = *(unsigned long*)src;
+ dst += 4;
+ src += 4;
+ size -= 4;
+ }
+
+ while ( size > 0 )
+ {
+ *dst++ = *src++;
+ size--;
+ }
+}
+
+static inline void memcpy_backward_sse2 (unsigned char *dst, unsigned char *src, int size)
+{
+ dst = dst + size;
+ src = src + size;
+
+ while ( size > 0 && ((unsigned long) dst & 1))
+ {
+ dst--;
+ src--;
+ size--;
+ *dst = *src;
+ }
+
+ while ( size > 0 && ((unsigned long) dst & 3))
+ {
+ dst -= 2;
+ src -= 2;
+ size -= 2;
+ *(unsigned short*)dst = *(unsigned short*)src;
+ }
+
+ while ( size > 0 && ((unsigned long) dst & 63))
+ {
+ dst -= 4;
+ src -= 4;
+ size -= 4;
+ *(unsigned long*)dst = *(unsigned long*)src;
+ }
+
+ if ((reinterpret_cast<unsigned long> (src) & 15) == 0 )
+ {
+ while ( size >= 64 )
+ {
+ __m128 xmm0, xmm1, xmm2, xmm3;
+
+ src -= 64;
+ dst -= 64;
+ size -= 64;
+
+ //_mm_prefetch((const char*)(src+16), _MM_HINT_NTA);
+
+ xmm0 = _mm_load_ps ((float*)(src));
+ xmm1 = _mm_load_ps ((float*)(src + 16));
+ xmm2 = _mm_load_ps ((float*)(src + 32));
+ xmm3 = _mm_load_ps ((float*)(src + 48));
+
+ _mm_stream_ps ((float*)(dst), xmm0);
+ _mm_stream_ps ((float*)(dst + 16), xmm1);
+ _mm_stream_ps ((float*)(dst + 32), xmm2);
+ _mm_stream_ps ((float*)(dst + 48), xmm3);
+ }
+
+ while ( size >= 16 )
+ {
+ dst -= 16;
+ src -= 16;
+ size -= 16;
+ _mm_stream_ps ((float*)dst, _mm_load_ps ((float*)src));
+ }
+ }
+ else
+ {
+ while ( size >= 64 )
+ {
+ __m128 xmm0, xmm1, xmm2, xmm3;
+
+ src -= 64;
+ dst -= 64;
+ size -= 64;
+
+ //_mm_prefetch((const char*)(src+16), _MM_HINT_NTA);
+
+ xmm0 = _mm_loadu_ps ((float*)(src));
+ xmm1 = _mm_loadu_ps ((float*)(src + 16));
+ xmm2 = _mm_loadu_ps ((float*)(src + 32));
+ xmm3 = _mm_loadu_ps ((float*)(src + 48));
+
+ _mm_stream_ps ((float*)(dst), xmm0);
+ _mm_stream_ps ((float*)(dst + 16), xmm1);
+ _mm_stream_ps ((float*)(dst + 32), xmm2);
+ _mm_stream_ps ((float*)(dst + 48), xmm3);
+ }
+
+ while ( size >= 16 )
+ {
+ dst -= 16;
+ src -= 16;
+ size -= 16;
+ _mm_stream_ps ((float*)dst, _mm_loadu_ps ((float*)src));
+ }
+ }
+
+ while ( size >= 4 )
+ {
+ dst -= 4;
+ src -= 4;
+ size -= 4;
+ *(unsigned long*)dst = *(unsigned long*)src;
+ }
+
+ while ( size > 0 )
+ {
+ dst--;
+ src--;
+ size--;
+ *dst = *src;
+ }
+}
+#endif
+
+static inline void move_memory_32 (unsigned long *dst, unsigned long *src, int size)
+{
+#ifdef _USE_LIBC
+ memmove (dst, src, size*4);
+#elif defined(_ARM_NEON)
+ if ( dst > src && dst < src + size )
+ memcpy_backward_32_neon (dst, src, size);
+ else
+ memcpy_forward_32_neon (dst, src, size);
+#else
+ if ( dst > src && dst < src + size )
+ memcpy_backward_32 (dst, src, size);
+ else
+ memcpy_forward_32 (dst, src, size);
+#endif
+}
+
+static inline void move_memory_16 (unsigned short *dst, unsigned short *src, int size)
+{
+#ifdef _USE_LIBC
+ memmove (dst, src, size*2);
+#elif defined(_ARM_NEON)
+ if ( dst > src && dst < src + size )
+ memcpy_backward_16_neon (dst, src, size);
+ else
+ memcpy_forward_16_neon (dst, src, size);
+#else
+ if ( dst > src && dst < src + size )
+ memcpy_backward_16 (dst, src, size);
+ else
+ memcpy_forward_16 (dst, src, size);
+#endif
+}
+
+/**
+ * @brief Pixel block move function within one image buffer
+ *
+ * @param bits buffer address of top-left corner
+ * @param bpp bits per pixel, must be one of 16 and 32
+ * @param stride number of bytes to go next row (can be negative)
+ * @param img_width entire image width
+ * @param img_height entire image height
+ * @param sx top-left x position of source area
+ * @param sy top-left y position of source area
+ * @param dx top-left x position of destination area
+ * @param dy top-left y position of destination area
+ * @param w width of area to copy
+ * @param h height of area to copy
+ *
+ * @remark This function supports overlapping in source and destination area.
+ * Any source or destination area which is outside given image will be cropped.
+ * Support negative stride.
+ * bits must be word aligned if bpp == 32 and half-word aligned if bpp == 16.
+ */
+int move_pixels (void *bits, int bpp, int stride, int img_width, int img_height,
+ int sx, int sy, int dx, int dy, int w, int h)
+{
+ int bytes_per_pixel;
+ unsigned char *src_row;
+ unsigned char *dst_row;
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // check validity of arguments
+ //////////////////////////////////////////////////////////////////////////
+ if ( !bits || img_width < 0 || img_height < 0 || w < 0 || h < 0 )
+ return 0;
+
+ if ( bpp == 32 )
+ bytes_per_pixel = 4;
+ else if ( bpp == 16 )
+ bytes_per_pixel = 2;
+ else // unsupported bpp
+ return 0;
+
+ if ( bytes_per_pixel*img_width < stride ) // invalid image
+ return 0;
+
+ // Wow thanks, we have nothing to do
+ if ( sx == dx && sy == dy )
+ return 1;
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Bounds check and cropping
+ //////////////////////////////////////////////////////////////////////////
+ while ( sx < 0 || dx < 0 )
+ {
+ sx++;
+ dx++;
+ w--;
+ }
+
+ while ( sy < 0 || dy < 0 )
+ {
+ sy++;
+ dy++;
+ h--;
+ }
+
+ while ( sx + w > img_width || dx + w > img_width )
+ w--;
+
+ while ( sy + h > img_height || dy + h > img_height )
+ h--;
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Check overlap and do copy
+ //////////////////////////////////////////////////////////////////////////
+
+ // No remaining area to copy
+ if ( w <= 0 || h <= 0 )
+ return 1;
+
+ src_row = (unsigned char*)bits + sy*stride + sx*bytes_per_pixel;
+ dst_row = (unsigned char*)bits + dy*stride + dx*bytes_per_pixel;
+
+ // Check if we need to reverse y order
+ if ( dy > sy && dy < sy + h )
+ {
+ src_row += (h - 1) *stride;
+ dst_row += (h - 1) *stride;
+ stride = -stride;
+ }
+
+ if ( bpp == 32 )
+ {
+ while ( h-- )
+ {
+ move_memory_32 ((unsigned long*)dst_row, (unsigned long*)src_row, w);
+ dst_row += stride;
+ src_row += stride;
+ }
+ }
+ else if ( bpp == 16 )
+ {
+ while ( h-- )
+ {
+ move_memory_16 ((unsigned short*)dst_row, (unsigned short*)src_row, w);
+ dst_row += stride;
+ src_row += stride;
+ }
+ }
+
+ return 1;
+}
diff --git a/src/neon/memcpy_neon.s b/src/neon/memcpy_neon.s new file mode 100644 index 0000000..eb3e3b1 --- /dev/null +++ b/src/neon/memcpy_neon.s @@ -0,0 +1,1889 @@ +/* + * Memory copy functions implemented using NEON + * + * NOTICE: + * pld instruction caused no changes in performance. + * Does our processor actually deal with this?? + * Performance was dropped when src and dst pointers are close + * to each other. (I don't know why, this was same for pixman_blt) + * + * TODO: + * Benchmark small block copy and make it better. + * SW pipelining, proper prefetching. + */ + +.fpu neon +.text + +.func memcpy_forward_32_neon +.global memcpy_forward_32_neon + +memcpy_forward_32_neon: + push {r4} + + mov r3, r0 + + cmp r2, #16 + blt 2f + +0: + tst r3, #15 + ldrne r4, [r1], #4 + subne r2, r2, #1 + strne r4, [r3], #4 + bne 0b + +1: + vld1.8 {d0, d1, d2, d3}, [r1]! + sub r2, r2, #8 + cmp r2, #8 + vst1.32 {d0, d1, d2, d3}, [r3, :128]! + bge 1b + +2: + cmp r2, #0 + ble 3f + ldr r4, [r1], #4 + sub r2, r2, #1 + str r4, [r3], #4 + b 2b + +3: + pop {r4} + bx lr +.endfunc + + +.func memcpy_backward_32_neon +.global memcpy_backward_32_neon + +memcpy_backward_32_neon: + push {r4} + + mov r3, r0 + + add r3, r3, r2, asl #2 + add r1, r1, r2, asl #2 + + cmp r2, #16 + blt 2f + +0: + tst r3, #15 + ldrne r4, [r1, #-4]! + subne r2, r2, #1 + strne r4, [r3, #-4]! + bne 0b + +1: + cmp r2, #8 + blt 2f + sub r1, r1, #32 + vld1.8 {d0, d1, d2, d3}, [r1] + sub r3, r3, #32 + sub r2, r2, #8 + vst1.32 {d0, d1, d2, d3}, [r3, :128] + b 1b + +2: + cmp r2, #0 + ble 3f + ldr r4, [r1, #-4]! + sub r2, r2, #1 + str r4, [r3, #-4]! + b 2b + +3: + pop {r4} + bx lr +.endfunc + +.func memcpy_forward_16_neon +.global memcpy_forward_16_neon + +memcpy_forward_16_neon: + push {r4} + + mov r3, r0 + + cmp r2, #16 + blt 2f + +0: + tst r3, #15 + ldrneh r4, [r1], #2 + subne r2, r2, #1 + strneh r4, [r3], #2 + bne 0b + +1: + cmp r2, #8 + blt 2f + vld1.8 {d0, d1}, [r1]! + sub r2, r2, #8 + vst1.32 {d0, d1}, [r3, :128]! + b 1b + +2: + cmp r2, #0 + ble 3f + ldrh r4, [r1], #2 + sub r2, r2, #1 + strh r4, [r3], #2 + b 2b + +3: + pop {r4} + bx lr +.endfunc + + +.func memcpy_backward_16_neon +.global memcpy_backward_16_neon + +memcpy_backward_16_neon: + push {r4} + + mov r3, r0 + + add r3, r3, r2, asl #1 + add r1, r1, r2, asl #1 + + cmp r2, #16 + blt 2f + +0: + tst r3, #15 + ldrneh r4, [r1, #-2]! + subne r2, r2, #1 + strneh r4, [r3, #-2]! + bne 0b + +1: + cmp r2, #8 + blt 2f + sub r1, r1, #16 + vld1.8 {d0, d1}, [r1] + sub r3, r3, #16 + sub r2, r2, #8 + vst1.32 {d0, d1}, [r3, :128] + b 1b + +2: + cmp r2, #0 + ble 3f + ldrh r4, [r1, #-2]! + sub r2, r2, #1 + strh r4, [r3, #-2]! + b 2b + +3: + pop {r4} + bx lr +.endfunc + +/* + * Memory copy functions implemented using NEON + */ + .text + .fpu neon + .align 4 + +memcpy_neon: + MOV ip,r0 + + CMP r2,#0x41 + BCC COPY_UNDER_64B + + CMP r2,#256 + BHI DST_ALIGN + + SUB r2,r2,#0x40 +COPY_BY_64B_s: + VLD1.8 {d0,d1,d2,d3},[r1]! + PLD [r1,#0x60] + SUBS r2,r2,#0x40 + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4,d5,d6,d7},[r1]! + VST1.8 {d4,d5,d6,d7},[ip]! + BGE COPY_BY_64B_s + ANDS r2,r2,#0x3f + BXEQ lr + B COPY_UNDER_64B + +@ SUBS r2,r2,#0x20 +@COPY_BY_32B_s +@ VLD1.8 {d0,d1,d2,d3},[r1]! +@ PLD [r1,#0x40] +@ SUBS r2,r2,#0x20 +@ VST1.8 {d0,d1,d2,d3},[ip]! +@ BGE COPY_BY_32B_s +@ ANDS r2,r2,#0x1f +@ B COPY_UNDER_64B + + +DST_ALIGN: + @ dst memory align to 16-byte + TST r0,#0xf + BEQ BLOCK_COPY +ALIGN_TO_1B: + TST r0,#1 + LDRNEB r3,[r1],#1 + STRNEB r3,[ip],#1 +@ BEQ ALIGN_TO_2B +@ VLD1.8 {d7[0]},[r1]! +@ VST1.8 {d7[0]},[ip]! + SUBNE r2,r2,#1 +ALIGN_TO_2B: + TST ip,#2 + LDRNEH r3,[r1],#2 + STRNEH r3,[ip],#2 +@ BEQ ALIGN_TO_4B +@ VLD2.8 {d5[0],d6[0]},[r1]! +@ VST2.8 {d5[0],d6[0]},[ip@16]! + SUBNE r2,r2,#2 +ALIGN_TO_4B: + TST ip,#4 + LDRNE r3,[r1],#4 + STRNE r3,[ip],#4 +@ BEQ ALIGN_TO_16B@{pc} + 0x10 @ 0x48 +@ VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! +@ VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip,:32]! + SUBNE r2,r2,#4 +ALIGN_TO_16B: + TST ip,#8 + LDRNE r3,[r1],#4 + STRNE r3,[ip],#4 + LDRNE r3,[r1],#4 + STRNE r3,[ip],#4 +@ BEQ BLOCK_COPY_CMP +@ VLD1.8 {d0},[r1]! +@ VST1.8 {d0},[ip@64]! + SUBNE r2,r2,#8 + + @ from here +BLOCK_COPY_CMP: + @ 16-byte align ????64 바이???하??경우? + CMP r2,#0x41 + BCC COPY_UNDER_64B + +BLOCK_COPY: + SUBS r2,r2,#0x40 + MOV r3,#0x40 +COPY_BY_64B: + VLD1.8 {d0,d1,d2,d3},[r1]! + CMP r3,#0x320 + PLD [r1,r3] + ADDLE r3,r3,#0x40 + SUBS r2,r2,#0x40 + VST1.8 {d0,d1,d2,d3},[ip,:128]! + VLD1.8 {d4,d5,d6,d7},[r1]! + VST1.8 {d4,d5,d6,d7},[ip,:128]! + BGE COPY_BY_64B + TST r2,#0x3f + BXEQ lr + TST r2,#0x20 + BEQ COPY_UNDER_16B + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip,:128]! + +@ SUBS r2,r2,#0x20 +@ MOV r3,#0x20 +@COPY_BY_32B +@ VLD1.8 {d0,d1,d2,d3},[r1]! +@ CMP r3,#0x140 +@ PLD [r1,r3] +@ ADDLE r3,r3,#0x20 +@ SUBS r2,r2,#0x20 +@ VST1.8 {d0,d1,d2,d3},[ip,:128]! +@ BGE COPY_BY_32B +@ CMP r2,#0x00 +@ BXEQ lr + + +COPY_UNDER_16B: + TST r2,#0x10 + BEQ COPY_UNDER_15B + VLD1.8 {d0,d1},[r1]! + VST1.8 {d0,d1},[ip,:128]! + +COPY_UNDER_15B: + TST r1,#0x03 + BNE COPY_UNDER_15B_UNALIGN +COPY_UNDER_15B_ALIGN: + @ src가 4-byte align ??경우 + LSLS r3,r2,#29 + LDRCS r3,[r1],#4 + STRCS r3,[ip],#4 + LDRCS r3,[r1],#4 + STRCS r3,[ip],#4 + LDRMI r3,[r1],#4 + STRMI r3,[ip],#4 + LSLS r2,r2,#31 + LDRCSH r3,[r1],#2 + STRCSH r3,[ip],#2 + LDRMIB r3,[r1],#1 + STRMIB r3,[ip],#1 + BX lr +COPY_UNDER_15B_UNALIGN: + @ src가 4-byte align ???닌 경우 + LSLS r3,r2,#29 + BCC COPY_UNDER_15B_UNALIGN_4B + @ neon ??가? + VLD1.8 {d0},[r1]! + VST1.8 {d0},[ip]! +@ LDRBCS r3,[r1],#1 +@ STRBCS r3,[ip],#1 +@ LDRBCS r3,[r1],#1 +@ STRBCS r3,[ip],#1 +@ LDRBCS r3,[r1],#1 +@ STRBCS r3,[ip],#1 +@ LDRBCS r3,[r1],#1 +@ STRBCS r3,[ip],#1 +@ LDRBCS r3,[r1],#1 +@ STRBCS r3,[ip],#1 +@ LDRBCS r3,[r1],#1 +@ STRBCS r3,[ip],#1 +@ LDRBCS r3,[r1],#1 +@ STRBCS r3,[ip],#1 +@ LDRBCS r3,[r1],#1 +@ STRBCS r3,[ip],#1 +COPY_UNDER_15B_UNALIGN_4B: + BPL COPY_UNDER_15B_UNALIGN_2B + LDRMIB r3,[r1],#1 + STRMIB r3,[ip],#1 + LDRMIB r3,[r1],#1 + STRMIB r3,[ip],#1 + LDRMIB r3,[r1],#1 + STRMIB r3,[ip],#1 + LDRMIB r3,[r1],#1 + STRMIB r3,[ip],#1 +COPY_UNDER_15B_UNALIGN_2B: + LSLS r2,r2,#31 + LDRCSB r3,[r1],#1 + STRCSB r3,[ip],#1 + LDRCSB r3,[r1],#1 + STRCSB r3,[ip],#1 + LDRMIB r3,[r1],#1 + STRMIB r3,[ip],#1 + BX lr + +COPY_UNDER_64B: + ADDNE pc,pc,r2,LSL #2 + B MEMCPY_WRAPUP + B MEMCPY_WRAPUP + B COPY_1B + B COPY_2B + B COPY_3B + B COPY_4B + B COPY_5B + B COPY_6B + B COPY_7B + B COPY_8B + B COPY_9B + B COPY_10B + B COPY_11B + B COPY_12B + B COPY_13B + B COPY_14B + B COPY_15B + B COPY_16B + B COPY_17B + B COPY_18B + B COPY_19B + B COPY_20B + B COPY_21B + B COPY_22B + B COPY_23B + B COPY_24B + B COPY_25B + B COPY_26B + B COPY_27B + B COPY_28B + B COPY_29B + B COPY_30B + B COPY_31B + B COPY_32B + B COPY_33B + B COPY_34B + B COPY_35B + B COPY_36B + B COPY_37B + B COPY_38B + B COPY_39B + B COPY_40B + B COPY_41B + B COPY_42B + B COPY_43B + B COPY_44B + B COPY_45B + B COPY_46B + B COPY_47B + B COPY_48B + B COPY_49B + B COPY_50B + B COPY_51B + B COPY_52B + B COPY_53B + B COPY_54B + B COPY_55B + B COPY_56B + B COPY_57B + B COPY_58B + B COPY_59B + B COPY_60B + B COPY_61B + B COPY_62B + B COPY_63B + B COPY_64B + +@ ARM +@ REQUIRE8 +@ PRESERVE8 +@ +@ AREA ||.text||, CODE, READONLY, ALIGN=4 +COPY_1B: + LDRB r2,[r1] + STRB r2,[ip] + BX lr +COPY_1B_: + VLD1.8 {d0[0]},[r1] + VST1.8 {d0[0]},[ip] + BX lr +COPY_2B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_2B_ + LDRH r2,[r1] + STRH r2,[ip] + BXEQ lr +COPY_2B_: + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r3,[r1],#1 + STRB r3,[ip],#1 +@ VLD2.8 {d0[0],d1[0]},[r1] +@ VST2.8 {d0[0],d1[0]},[ip] + BX lr +COPY_3B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_3B_ + LDRH r2,[r1,#0x00] + STRH r2,[ip,#0x00] + LDRB r2,[r1,#0x02] + STRB r2,[ip,#0x02] + BX lr +COPY_3B_: + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r3,[r1],#1 + STRB r3,[ip],#1 +@ VLD3.8 {d0[0],d1[0],d2[0]},[r1] +@ VST3.8 {d0[0],d1[0],d2[0]},[ip] + BX lr +COPY_4B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_4B_ + LDR r2,[r1] + STR r2,[ip] + BX lr +COPY_4B_: + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 +@ VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1] +@ VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip] + BX lr +COPY_5B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_5B_ + LDR r2,[r1],#0x04 + STR r2,[ip],#0x04 + LDRB r2,[r1] + STRB r2,[ip] + BX lr +COPY_5B_: + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD1.8 {d4[0]},[r1]! + VST1.8 {d4[0]},[ip]! + BX lr +COPY_6B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_6B_ + LDR r2,[r1],#0x04 + STR r2,[ip],#0x04 + LDRH r3,[r1] + STRH r3,[ip] + BX lr +COPY_6B_: + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + BX lr +COPY_7B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_7B_ + LDR r2,[r1],#0x04 + STR r2,[ip],#0x04 + LDRH r2,[r1],#0x02 + STRH r2,[ip],#0x02 + LDRB r2,[r1] + STRB r2,[ip] + BX lr +COPY_7B_: + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 +@ VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! +@ VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! +@ VLD3.8 {d4[0],d5[0],d6[0]},[r1]! +@ VST3.8 {d4[0],d5[0],d6[0]},[ip]! + BX lr +COPY_8B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_8B_ + LDMEQ r1!,{r2,r3} + STMEQ ip!,{r2,r3} + BXEQ lr +COPY_8B_: + VLD1.8 {d0},[r1] + VST1.8 {d0},[ip] + BX lr +COPY_9B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_9B_ + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDRB r2,[r1] + STRB r2,[ip] + BX lr +COPY_9B_: + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 +@ VLD1.8 {d0},[r1]! +@ VST1.8 {d0},[ip]! +@ VLD1.8 {d4[0]},[r1] +@ VST1.8 {d4[0]},[ip] + BX lr +COPY_10B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_10B_ + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDRH r2,[r1] + STRH r2,[ip] + BX lr +COPY_10B_: + VLD1.8 {d0},[r1]! + VST1.8 {d0},[ip]! + VLD2.8 {d4[0],d5[0]},[r1] + VST2.8 {d4[0],d5[0]},[ip] + BX lr +COPY_11B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_11B_ + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDRH r2,[r1],#0x02 + STRH r2,[ip],#0x02 + LDRB r2,[r1] + STRB r2,[ip] + BX lr +COPY_11B_: + VLD1.8 {d0},[r1]! + VST1.8 {d0},[ip]! + VLD3.8 {d4[0],d5[0],d6[0]},[r1] + VST3.8 {d4[0],d5[0],d6[0]},[ip] + BX lr +COPY_12B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_12B_ + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDR r2,[r1] + STR r2,[ip] + BX lr +COPY_12B_: + VLD1.8 {d0},[r1]! + VST1.8 {d0},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1] + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip] + BX lr +COPY_13B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_13B_ + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDR r2,[r1],#0x04 + STR r2,[ip],#0x04 + LDRB r3,[r1] + STRB r3,[ip] + BX lr +COPY_13B_: + VLD1.8 {d0},[r1]! + VST1.8 {d0},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD1.8 {d2[0]},[r1] + VST1.8 {d2[0]},[ip] + BX lr +COPY_14B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_14B_ + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDR r2,[r1],#0x04 + STR r2,[ip],#0x04 + LDRH r3,[r1] + STRH r3,[ip] + BX lr +COPY_14B_: + VLD1.8 {d0},[r1]! + VST1.8 {d0},[ip]! + VLD4.8 {d1[0],d2[0],d3[0],d4[0]},[r1]! + VST4.8 {d1[0],d2[0],d3[0],d4[0]},[ip]! + VLD2.8 {d5[0],d6[0]},[r1] + VST2.8 {d5[0],d6[0]},[ip] + BX lr +COPY_15B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_15B_ + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDR r2,[r1],#0x04 + STR r2,[ip],#0x04 + LDRH r3,[r1],#0x02 + STRH r3,[ip],#0x02 + LDRB r2,[r1] + STRB r2,[ip] + BX lr +COPY_15B_: + VLD1.8 {d0},[r1]! + VST1.8 {d0},[ip]! + VLD4.8 {d1[0],d2[0],d3[0],d4[0]},[r1]! + VST4.8 {d1[0],d2[0],d3[0],d4[0]},[ip]! + VLD3.8 {d5[0],d6[0],d7[0]},[r1] + VST3.8 {d5[0],d6[0],d7[0]},[ip] + BX lr +COPY_16B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_16B_ + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + BX lr +COPY_16B_: + VLD1.8 {d0,d1},[r1] + VST1.8 {d0,d1},[ip] + BX lr +COPY_17B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_17B_ + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDRB r2,[r1] + STRB r2,[ip] + BX lr +COPY_17B_: + VLD1.8 {d0,d1},[r1]! + VST1.8 {d0,d1},[ip]! + VLD1.8 {d2[0]},[r1] + VST1.8 {d2[0]},[ip] + BX lr +COPY_18B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_18B_ + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDRH r2,[r1] + STRH r2,[ip] + BX lr +COPY_18B_: + VLD1.8 {d0,d1},[r1]! + VST1.8 {d0,d1},[ip]! + VLD2.8 {d0[0],d1[0]},[r1] + VST2.8 {d0[0],d1[0]},[ip] + BX lr +COPY_19B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_19B_ + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + BX lr +COPY_19B_: + VLD1.8 {d0,d1},[r1]! + VST1.8 {d0,d1},[ip]! + VLD3.8 {d5[0],d6[0],d7[0]},[r1] + VST3.8 {d5[0],d6[0],d7[0]},[ip] + BX lr +COPY_20B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_20B_ + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDR r2,[r1],#4 + STR r2,[ip],#4 + BX lr +COPY_20B_: + VLD1.8 {d0,d1},[r1]! + VST1.8 {d0,d1},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1] + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip] + BX lr +COPY_21B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_21B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDRB r4,[r1],#1 + STRB r4,[ip],#1 + POP {r4} + BX lr +COPY_21B_: + VLD1.8 {d0,d1},[r1]! + VST1.8 {d0,d1},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD1.8 {d3[0]},[r1]! + VST1.8 {d3[0]},[ip]! + BX lr +COPY_22B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_22B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDRH r4,[r1],#2 + STRH r4,[ip],#2 + POP {r4} + BX lr +COPY_22B_: + VLD1.8 {d0,d1},[r1]! + VST1.8 {d0,d1},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD2.8 {d0[0],d1[0]},[r1]! + VST2.8 {d0[0],d1[0]},[ip]! + BX lr +COPY_23B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_23B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDRH r4,[r1],#2 + STRH r4,[ip],#2 + LDRB r4,[r1],#1 + STRB r4,[ip],#1 + POP {r4} + BX lr +COPY_23B_: + VLD1.8 {d0,d1},[r1]! + VST1.8 {d0,d1},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD3.8 {d5[0],d6[0],d7[0]},[r1] + VST3.8 {d5[0],d6[0],d7[0]},[ip] + BX lr +COPY_24B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_24B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + POP {r4} + BX lr +COPY_24B_: + VLD1.8 {d0,d1,d2},[r1] + VST1.8 {d0,d1,d2},[ip] + BX lr +COPY_25B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_25B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_25B_: + VLD1.8 {d0,d1,d2},[r1]! + VST1.8 {d0,d1,d2},[ip]! + VLD1.8 {d3[0]},[r1] + VST1.8 {d3[0]},[ip] + BX lr +COPY_26B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_26B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + POP {r4} + BX lr +COPY_26B_: + VLD1.8 {d0,d1,d2},[r1]! + VST1.8 {d0,d1,d2},[ip]! + VLD2.8 {d0[0],d1[0]},[r1] + VST2.8 {d0[0],d1[0]},[ip] + BX lr +COPY_27B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_27B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_27B_: + VLD1.8 {d0,d1,d2},[r1]! + VST1.8 {d0,d1,d2},[ip]! + VLD3.8 {d5[0],d6[0],d7[0]},[r1] + VST3.8 {d5[0],d6[0],d7[0]},[ip] + BX lr +COPY_28B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_28B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDR r2,[r1],#4 + STR r2,[ip],#4 + POP {r4} + BX lr +COPY_28B_: + VLD1.8 {d0,d1,d2},[r1]! + VST1.8 {d0,d1,d2},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1] + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip] + BX lr +COPY_29B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_29B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDR r2,[r1],#4 + STR r2,[ip],#4 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_29B_: + VLD1.8 {d0,d1,d2},[r1]! + VST1.8 {d0,d1,d2},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD1.8 {d4[0]},[r1] + VST1.8 {d4[0]},[ip] + BX lr +COPY_30B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_30B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDR r2,[r1],#4 + STR r2,[ip],#4 + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + POP {r4} + BX lr +COPY_30B_: + VLD1.8 {d0,d1,d2},[r1]! + VST1.8 {d0,d1,d2},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD2.8 {d0[0],d1[0]},[r1] + VST2.8 {d0[0],d1[0]},[ip] + BX lr +COPY_31B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_31B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDR r2,[r1],#4 + STR r2,[ip],#4 + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_31B_: + VLD1.8 {d0,d1,d2},[r1]! + VST1.8 {d0,d1,d2},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD3.8 {d5[0],d6[0],d7[0]},[r1] + VST3.8 {d5[0],d6[0],d7[0]},[ip] + BX lr +COPY_32B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_32B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + POP {r4} + BX lr +COPY_32B_: + VLD1.8 {d0,d1,d2,d3},[r1] + VST1.8 {d0,d1,d2,d3},[ip] + BX lr +COPY_33B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_33B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_33B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4[0]},[r1] + VST1.8 {d4[0]},[ip] + BX lr +COPY_34B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_34B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + POP {r4} + BX lr +COPY_34B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD2.8 {d0[0],d1[0]},[r1] + VST2.8 {d0[0],d1[0]},[ip] + BX lr +COPY_35B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_35B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_35B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD3.8 {d5[0],d6[0],d7[0]},[r1] + VST3.8 {d5[0],d6[0],d7[0]},[ip] + BX lr +COPY_36B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_36B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + POP {r4} + BX lr +COPY_36B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + BX lr +COPY_37B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_37B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_37B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD1.8 {d5[0]},[r1]! + VST1.8 {d5[0]},[ip]! + BX lr +COPY_38B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_38B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + POP {r4} + BX lr +COPY_38B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD2.8 {d5[0],d6[0]},[r1]! + VST2.8 {d5[0],d6[0]},[ip]! + BX lr +COPY_39B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_39B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_39B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD3.8 {d5[0],d6[0],d7[0]},[r1]! + VST3.8 {d5[0],d6[0],d7[0]},[ip]! + BX lr +COPY_40B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_40B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDR r2,[r1],#4 + STR r2,[ip],#4 + POP {r4} + BX lr +COPY_40B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4},[r1]! + VST1.8 {d4},[ip]! + BX lr +COPY_41B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_41B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDR r2,[r1],#4 + STR r2,[ip],#4 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_41B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4},[r1]! + VST1.8 {d4},[ip]! + VLD1.8 {d5[0]},[r1]! + VST1.8 {d5[0]},[ip]! + BX lr +COPY_42B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_42B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDR r2,[r1],#4 + STR r2,[ip],#4 + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + POP {r4} + BX lr +COPY_42B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4},[r1]! + VST1.8 {d4},[ip]! + VLD2.8 {d0[0],d1[0]},[r1]! + VST2.8 {d0[0],d1[0]},[ip]! + BX lr +COPY_43B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_43B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDR r2,[r1],#4 + STR r2,[ip],#4 + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_43B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4},[r1]! + VST1.8 {d4},[ip]! + VLD3.8 {d5[0],d6[0],d7[0]},[r1]! + VST3.8 {d5[0],d6[0],d7[0]},[ip]! + BX lr +COPY_44B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_44B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + POP {r4} + BX lr +COPY_44B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4},[r1]! + VST1.8 {d4},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + BX lr +COPY_45B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_45B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_45B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4},[r1]! + VST1.8 {d4},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD1.8 {d6[0]},[r1]! + VST1.8 {d6[0]},[ip]! + BX lr +COPY_46B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_46B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + POP {r4} + BX lr +COPY_46B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4},[r1]! + VST1.8 {d4},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD2.8 {d0[0],d1[0]},[r1]! + VST2.8 {d0[0],d1[0]},[ip]! + BX lr +COPY_47B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_47B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_47B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4},[r1]! + VST1.8 {d4},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD3.8 {d5[0],d6[0],d7[0]},[r1]! + VST3.8 {d5[0],d6[0],d7[0]},[ip]! + BX lr +COPY_48B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_48B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + POP {r4} + BX lr +COPY_48B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4,d5},[r1]! + VST1.8 {d4,d5},[ip]! + BX lr +COPY_49B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_49B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_49B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4,d5},[r1]! + VST1.8 {d4,d5},[ip]! + VLD1.8 {d6[0]},[r1]! + VST1.8 {d6[0]},[ip]! + BX lr +COPY_50B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_50B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + POP {r4} + BX lr +COPY_50B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4,d5},[r1]! + VST1.8 {d4,d5},[ip]! + VLD2.8 {d0[0],d1[0]},[r1]! + VST2.8 {d0[0],d1[0]},[ip]! + BX lr +COPY_51B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_51B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_51B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4,d5},[r1]! + VST1.8 {d4,d5},[ip]! + VLD3.8 {d5[0],d6[0],d7[0]},[r1]! + VST3.8 {d5[0],d6[0],d7[0]},[ip]! + BX lr +COPY_52B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_52B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDR r2,[r1],#4 + STR r2,[ip],#4 + POP {r4} + BX lr +COPY_52B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4,d5},[r1]! + VST1.8 {d4,d5},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + BX lr +COPY_53B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_53B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDR r2,[r1],#4 + STR r2,[ip],#4 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_53B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4,d5},[r1]! + VST1.8 {d4,d5},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD1.8 {d7[0]},[r1]! + VST1.8 {d7[0]},[ip]! + BX lr +COPY_54B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_54B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDR r2,[r1],#4 + STR r2,[ip],#4 + LDRH r2,[r1],#1 + STRH r2,[ip],#1 + POP {r4} + BX lr +COPY_54B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4,d5},[r1]! + VST1.8 {d4,d5},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD2.8 {d0[0],d1[0]},[r1]! + VST2.8 {d0[0],d1[0]},[ip]! + BX lr +COPY_55B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_55B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDR r2,[r1],#4 + STR r2,[ip],#4 + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_55B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4,d5},[r1]! + VST1.8 {d4,d5},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD3.8 {d5[0],d6[0],d7[0]},[r1]! + VST3.8 {d5[0],d6[0],d7[0]},[ip]! + BX lr +COPY_56B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_56B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + POP {r4} + BX lr +COPY_56B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4,d5,d6},[r1]! + VST1.8 {d4,d5,d6},[ip]! + BX lr +COPY_57B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_57B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_57B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4,d5,d6},[r1]! + VST1.8 {d4,d5,d6},[ip]! + VLD1.8 {d7[0]},[r1]! + VST1.8 {d7[0]},[ip]! + BX lr +COPY_58B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_58B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + POP {r4} + BX lr +COPY_58B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4,d5,d6},[r1]! + VST1.8 {d4,d5,d6},[ip]! + VLD2.8 {d0[0],d1[0]},[r1]! + VST2.8 {d0[0],d1[0]},[ip]! + BX lr +COPY_59B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_59B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3} + STM ip!,{r2,r3} + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_59B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4,d5,d6},[r1]! + VST1.8 {d4,d5,d6},[ip]! + VLD3.8 {d5[0],d6[0],d7[0]},[r1]! + VST3.8 {d5[0],d6[0],d7[0]},[ip]! + BX lr +COPY_60B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_60B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + POP {r4} + BX lr +COPY_60B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4,d5,d6},[r1]! + VST1.8 {d4,d5,d6},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + BX lr +COPY_61B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_61B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_61B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4,d5,d6},[r1]! + VST1.8 {d4,d5,d6},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD1.8 {d0[0]},[r1]! + VST1.8 {d0[0]},[ip]! + BX lr +COPY_62B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_62B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + POP {r4} + BX lr +COPY_62B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4,d5,d6},[r1]! + VST1.8 {d4,d5,d6},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD2.8 {d0[0],d1[0]},[r1]! + VST2.8 {d0[0],d1[0]},[ip]! + BX lr +COPY_63B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_63B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} + LDRH r2,[r1],#2 + STRH r2,[ip],#2 + LDRB r2,[r1],#1 + STRB r2,[ip],#1 + POP {r4} + BX lr +COPY_63B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VLD1.8 {d4,d5,d6},[r1]! + VST1.8 {d4,d5,d6},[ip]! + VLD4.8 {d0[0],d1[0],d2[0],d3[0]},[r1]! + VST4.8 {d0[0],d1[0],d2[0],d3[0]},[ip]! + VLD3.8 {d5[0],d6[0],d7[0]},[r1]! + VST3.8 {d5[0],d6[0],d7[0]},[ip]! + BX lr +COPY_64B: + ORR r3,ip,r1 + TST r3,#3 + BNE COPY_64B_ + PUSH {r4} + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} @ 12 + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} @ 24 + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} @ 36 + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} @ 48 + LDM r1!,{r2,r3,r4} + STM ip!,{r2,r3,r4} @ 60 + LDR r2,[r1],#4 + STR r2,[ip],#4 + POP {r4} + BX lr +COPY_64B_: + VLD1.8 {d0,d1,d2,d3},[r1]! + VLD1.8 {d4,d5,d6,d7},[r1]! + VST1.8 {d0,d1,d2,d3},[ip]! + VST1.8 {d4,d5,d6,d7},[ip]! + BX lr + +MEMCPY_WRAPUP: + @MOV r0,r5 + @POP {r4-r6,pc} + BX lr + + .global memcpy_neon + diff --git a/src/neon/neonmem.h b/src/neon/neonmem.h new file mode 100644 index 0000000..626abec --- /dev/null +++ b/src/neon/neonmem.h @@ -0,0 +1,49 @@ +/**************************************************************************
+
+xserver-xorg-video-exynos
+
+Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Contact: SooChan Lim <sc1.lim@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.
+
+**************************************************************************/
+
+#ifndef _NEON_MEMCPY_HEADER_
+#define _NEON_MEMCPY_HEADER_
+
+#include <stddef.h>
+
+#ifdef memcpy
+#undef memcpy
+#endif
+
+#define memcpy memcpy_neon
+
+void *
+memcpy_neon (void *dst, const void *src, size_t count);
+
+int
+move_pixels (void *bits, int bpp, int stride, int img_width, int img_height,
+ int sx, int sy, int dx, int dy, int w, int h);
+#endif /* _NEON_MEMCPY_HEADER_ */
+
diff --git a/src/sec.c b/src/sec.c new file mode 100755 index 0000000..256f029 --- /dev/null +++ b/src/sec.c @@ -0,0 +1,1777 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@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. + +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include <sys/stat.h> +#include <fcntl.h> + +/* all driver need this */ +#include "xf86.h" +#include "xf86_OSproc.h" + +#include "fb.h" +#include "mipointer.h" +#include "mibstore.h" +#include "micmap.h" +#include "colormapst.h" +#include "xf86cmap.h" +#include "xf86xv.h" +#include "xf86Crtc.h" +#include "sec.h" +#include "sec_display.h" +#include "sec_plane.h" +#include "sec_accel.h" +#include "sec_xberc.h" +#include "sec_util.h" +#include "sec_wb.h" +#include <tbm_bufmgr.h> +#include "fimg2d.h" + +#define OPTION_FLIP_BUFFERS 0 + +/* prototypes */ +static const OptionInfoRec* SECAvailableOptions (int chipid, int busid); +static void SECIdentify (int flags); +static Bool SECProbe (DriverPtr pDrv, int flags); +static Bool SECPreInit (ScrnInfoPtr pScrn, int flags); +static Bool SECScreenInit (ScreenPtr pScreen, int argc, char **argv); +static Bool SECSwitchMode (ScrnInfoPtr pScrn, DisplayModePtr pMode); +static void SECAdjustFrame (ScrnInfoPtr pScrn, int x, int y); +static Bool SECEnterVT (ScrnInfoPtr pScrn); +static void SECLeaveVT (ScrnInfoPtr pScrn); +static ModeStatus SECValidMode (ScrnInfoPtr pScrn, DisplayModePtr pMode, Bool verbose, int flags); +static Bool SECCloseScreen (ScreenPtr pScreen); +static Bool SECCreateScreenResources (ScreenPtr pScreen); +#if HAVE_UDEV +static void SECUdevEventsHandler (int fd, void *closure); +#endif + +/* This DriverRec must be defined in the driver for Xserver to load this driver */ +_X_EXPORT DriverRec SEC = +{ + SEC_VERSION, + SEC_DRIVER_NAME, + SECIdentify, + SECProbe, + SECAvailableOptions, + NULL, + 0, + NULL, +}; + +/* Supported "chipsets" */ +static SymTabRec SECChipsets[] = +{ + { 0, "exynos" }, + {-1, NULL } +}; + +/* Supported options */ +typedef enum +{ + OPTION_DRI2, + OPTION_EXA, + OPTION_SWEXA, + OPTION_ROTATE, + OPTION_SNAPSHOT, + OPTION_WB, +#if OPTION_FLIP_BUFFERS + OPTION_FLIPBUFS, +#endif + OPTION_CACHABLE, + OPTION_SCANOUT, + OPTION_ACCEL2D, + OPTION_PARTIAL_UPDATE, +} SECOpts; + +static const OptionInfoRec SECOptions[] = +{ + { OPTION_DRI2, "dri2", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_EXA, "exa", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_SWEXA, "sw_exa", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_ROTATE, "rotate", OPTV_STRING, {0}, FALSE }, + { OPTION_SNAPSHOT, "snapshot", OPTV_STRING, {0}, FALSE }, + { OPTION_WB, "wb", OPTV_BOOLEAN, {0}, FALSE }, +#if OPTION_FLIP_BUFFERS + { OPTION_FLIPBUFS, "flip_bufs", OPTV_INTEGER, {0}, 3 }, +#endif + { OPTION_CACHABLE, "cachable", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_SCANOUT, "scanout", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_ACCEL2D, "accel_2d", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_PARTIAL_UPDATE, "partial_update", OPTV_BOOLEAN, {0}, FALSE }, + { -1, NULL, OPTV_NONE, {0}, FALSE } +}; + +/* -------------------------------------------------------------------- */ +#ifdef XFree86LOADER + +MODULESETUPPROTO (SECSetup); + +static XF86ModuleVersionInfo SECVersRec = +{ + "exynos", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + PACKAGE_VERSION_MAJOR, + PACKAGE_VERSION_MINOR, + PACKAGE_VERSION_PATCHLEVEL, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + NULL, + {0,0,0,0} +}; + +_X_EXPORT XF86ModuleData exynosModuleData = { &SECVersRec, SECSetup, NULL }; + +pointer +SECSetup (pointer module, pointer opts, int *errmaj, int *errmin) +{ + static Bool setupDone = FALSE; + + if (!setupDone) + { + setupDone = TRUE; + xf86AddDriver (&SEC, module, HaveDriverFuncs); + return (pointer) 1; + } + else + { + if (errmaj) *errmaj = LDR_ONCEONLY; + return NULL; + } +} + +#endif /* XFree86LOADER */ +/* -------------------------------------------------------------------- */ + +/* TODO:::check the fimd_drm */ +static Bool +_has_drm_mode_setting() +{ + /* TODO:: check the sysfs dri2 device name */ + return TRUE; +} + +/* + * Probing the device with the device node, this probing depend on the specific hw. + * This function just verify whether the display hw is avaliable or not. + */ +static Bool +_secHwProbe (struct pci_device * pPci, char *device,char **namep) +{ + if (!_has_drm_mode_setting()) + return FALSE; + + return TRUE; +} + +static tbm_bufmgr +_secInitBufmgr (int drm_fd, void * arg) +{ + tbm_bufmgr bufmgr = NULL; + + /* get buffer manager */ + setenv("BUFMGR_LOCK_TYPE", "once", 1); + setenv("BUFMGR_MAP_CACHE", "true", 1); + bufmgr = tbm_bufmgr_init (drm_fd); + + if (bufmgr == NULL) + return NULL; + + return bufmgr; +} + +static void +_secDeInitBufmgr (tbm_bufmgr bufmgr) +{ + if (bufmgr) + tbm_bufmgr_deinit (bufmgr); +} + +/* open drm */ +static Bool +_openDrmMaster (ScrnInfoPtr pScrn) +{ + SECPtr pSec = SECPTR (pScrn); + int ret; + + /* open drm */ + pSec->drm_fd = drmOpen ("exynos", NULL); + if (pSec->drm_fd < 0) + { + struct udev *udev; + struct udev_enumerate *e; + struct udev_list_entry *entry; + struct udev_device *device, *drm_device; + const char *path, *device_seat; + const char *filename; + + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "[DRM] Cannot open drm device.. search by udev\n"); + + /* STEP 1: Find drm device */ + udev = udev_new(); + if (udev == NULL) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR,"[DRM] fail to initialize udev context\n"); + goto fail_to_open_drm_master; + } + + e = udev_enumerate_new(udev); + udev_enumerate_add_match_subsystem(e, "drm"); + udev_enumerate_add_match_sysname(e, "card[0-9]*"); + udev_enumerate_scan_devices(e); + + drm_device = NULL; + udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) + { + path = udev_list_entry_get_name(entry); + device = udev_device_new_from_syspath(udev, path); + device_seat = udev_device_get_property_value(device, "ID_SEAT"); + xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "[DRM] drm info: device:%p, patch:%s, seat:%s\n", device, path, device_seat); + + if(!device_seat) + device_seat = "seat0"; + + if(strcmp(device_seat, "seat0") == 0) + { + drm_device = device; + break; + } + udev_device_unref(device); + } + + if(drm_device == NULL) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR,"[DRM] fail to find drm device\n"); + goto fail_to_open_drm_master; + } + + filename = udev_device_get_devnode(drm_device); + + pSec->drm_fd = open(filename, O_RDWR|O_CLOEXEC); + if (pSec->drm_fd < 0) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "[DRM] Cannot open drm device(%s)\n", filename); + + udev_device_unref(drm_device); + udev_enumerate_unref(e); + udev_unref(udev); + + goto fail_to_open_drm_master; + } + else + { + xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "[DRM] Succeed to open drm device(%s)\n", filename); + } + + udev_device_unref(drm_device); + udev_enumerate_unref(e); + udev_unref(udev); + } + else + { + xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "[DRM] Succeed to open drm device\n"); + } + + pSec->drm_device_name = drmGetDeviceNameFromFd (pSec->drm_fd); + xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "[DRM] Succeed get drm device name:%s\n", + pSec->drm_device_name); + + /* enable drm vblank */ + ret = drmCtlInstHandler (pSec->drm_fd, 217); + if (ret) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, + "[DRM] Fail to enable drm VBlank(%d)\n", ret); + goto fail_to_open_drm_master; + } + + xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, + "[DRM] Enable drm VBlank(%d)\n", ret); + + /* initialize drm bufmgr */ + pSec->tbm_bufmgr = _secInitBufmgr (pSec->drm_fd, NULL); + if (pSec->tbm_bufmgr == NULL) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, + "[DRM] Error : bufmgr initialization failed\n"); + goto fail_to_open_drm_master; + } + + xf86DrvMsg (pScrn->scrnIndex, X_CONFIG + , "[DRM] Enable buffer manager\n"); + + return TRUE; + +fail_to_open_drm_master: + + if (pSec->tbm_bufmgr) + { + _secDeInitBufmgr (pSec->tbm_bufmgr); + pSec->tbm_bufmgr = NULL; + } + + if (pSec->drm_device_name) + { + free (pSec->drm_device_name); + pSec->drm_device_name = NULL; + } + + if (pSec->drm_fd >= 0) + { + drmClose (pSec->drm_fd); + pSec->drm_fd = -1; + } + + return FALSE; +} + +/* close drm */ +static void +_closeDrmMaster (ScrnInfoPtr pScrn) +{ + SECPtr pSec = SECPTR (pScrn); + + if (pSec->tbm_bufmgr) + { + _secDeInitBufmgr (pSec->tbm_bufmgr); + pSec->tbm_bufmgr = NULL; + } + + if (pSec->drm_fd >= 0) + { + drmClose (pSec->drm_fd); + pSec->drm_fd = -1; + } + + if (pSec->drm_device_name) + { + free (pSec->drm_device_name); + pSec->drm_device_name = NULL; + } +} + +/* + * Initialize the device Probing the device with the device node, + * this probing depend on the specific hw. + * This function just verify whether the display hw is avaliable or not. + */ +static Bool +_secHwInit (ScrnInfoPtr pScrn, struct pci_device *pPci, char *device) +{ + SECPtr pSec = SECPTR (pScrn); + + /* init drm master */ + if (_openDrmMaster (pScrn) == TRUE) + xf86DrvMsg (pScrn->scrnIndex, X_CONFIG + , "DRM BLANK is enabled\n"); + else + xf86DrvMsg (pScrn->scrnIndex, X_CONFIG + , "DRM BLANK is disabled\n"); + + + if(g2d_init (pSec->drm_fd)) + { + xf86DrvMsg (pScrn->scrnIndex, X_CONFIG + , "G2D is enabled\n"); + pSec->is_accel_2d = TRUE; + } + else + xf86DrvMsg (pScrn->scrnIndex, X_CONFIG + , "G2D is disabled\n"); + + return TRUE; +} + +/* SigHook */ +OsSigWrapperPtr old_sig_wrapper; +int +_secOsSigWrapper (int sig) +{ + XDBG_KLOG(MSEC,"Catch SIG: %d\n", sig); + + return old_sig_wrapper(sig); /*Contiue*/ +} + +/* + * DeInitialize the hw + */ +static void +_secHwDeinit (ScrnInfoPtr pScrn) +{ + g2d_fini (); + + /* deinit drm master */ + _closeDrmMaster (pScrn); + + return; +} + +static Bool +_allocScrnPrivRec (ScrnInfoPtr pScrn) +{ + if (pScrn->driverPrivate != NULL) + return TRUE; + + pScrn->driverPrivate = calloc (sizeof (SECRec), 1); + if (!pScrn->driverPrivate) + return FALSE; + + return TRUE; +} + +static void +_freeScrnPrivRec (ScrnInfoPtr pScrn) +{ + if (pScrn->driverPrivate == NULL) + return; + free (pScrn->driverPrivate); + pScrn->driverPrivate = NULL; +} + +/* + * Check the driver option. + * Set the option flags to the driver private + */ +static void +_checkDriverOptions (ScrnInfoPtr pScrn) +{ + SECPtr pSec = SECPTR (pScrn); + const char *s; + int flip_bufs = 3; + + /* exa */ + if (xf86ReturnOptValBool (pSec->Options, OPTION_EXA, FALSE)) + pSec->is_exa = TRUE; + + /* sw exa */ + if (pSec->is_exa) + { + if (xf86ReturnOptValBool (pSec->Options, OPTION_SWEXA, TRUE)) + pSec->is_sw_exa = TRUE; + } + + /* dri2 */ + if (xf86ReturnOptValBool (pSec->Options, OPTION_DRI2, FALSE)) + { + pSec->is_dri2 = TRUE; + + /* number of the flip buffers */ +#if OPTION_FLIP_BUFFERS + if (xf86GetOptValInteger (pSec->Options, OPTION_FLIPBUFS, &flip_bufs)) + pSec->flip_bufs = flip_bufs; + else +#endif + { + /* default is 3 */ + flip_bufs = 3; + pSec->flip_bufs = flip_bufs; + } + } + + /* rotate */ + pSec->rotate = RR_Rotate_0; + if (( s= xf86GetOptValString (pSec->Options, OPTION_ROTATE))) + { + if (!xf86NameCmp (s, "CW")) + { + pSec->rotate = RR_Rotate_90; + xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "rotating screen clockwise\n"); + } + else if (!xf86NameCmp (s, "CCW")) + { + pSec->rotate = RR_Rotate_270; + xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "rotating screen counter-clockwise\n"); + } + else if (!xf86NameCmp (s, "UD")) + { + pSec->rotate = RR_Rotate_180; + xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "rotating screen upside-down\n"); + } + else + { + xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "\"%s\" is not valid option", s); + } + } + + /* wb */ + if (xf86ReturnOptValBool (pSec->Options, OPTION_WB, FALSE)) + { + if (xf86ReturnOptValBool (pSec->Options, OPTION_WB, TRUE)) + pSec->is_wb_clone = TRUE; + } + + /* cachable */ + if (xf86ReturnOptValBool (pSec->Options, OPTION_CACHABLE, FALSE)) + { + if (xf86ReturnOptValBool (pSec->Options, OPTION_CACHABLE, TRUE)) + { + pSec->cachable = TRUE; + xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "Use cachable buffer.\n"); + } + } + + /* scanout */ + if (xf86ReturnOptValBool (pSec->Options, OPTION_SCANOUT, FALSE)) + { + if (xf86ReturnOptValBool (pSec->Options, OPTION_SCANOUT, TRUE)) + { + pSec->scanout = TRUE; + xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "Use scanout buffer.\n"); + } + } + + /* hw_2d */ + if (xf86ReturnOptValBool (pSec->Options, OPTION_ACCEL2D, FALSE)) + { + if (xf86ReturnOptValBool (pSec->Options, OPTION_ACCEL2D, TRUE)) + { + pSec->is_accel_2d = TRUE; + xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "Use 2d accelerator.\n"); + } + } + + /* use_partial_update */ + if (xf86ReturnOptValBool (pSec->Options, OPTION_PARTIAL_UPDATE, FALSE)) + { + if (xf86ReturnOptValBool (pSec->Options, OPTION_PARTIAL_UPDATE, TRUE)) + { + pSec->use_partial_update = TRUE; + xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "Use partial update.\n"); + } + } +} + +#if HAVE_UDEV +static void +_secUdevInit (ScrnInfoPtr pScrn) +{ + SECPtr pSec = SECPTR (pScrn); + struct udev *u; + struct udev_monitor *mon; + + xf86DrvMsg (pScrn->scrnIndex, X_CONFIG, "hotplug detection\n"); + + u = udev_new(); + if(!u) + return; + + mon = udev_monitor_new_from_netlink(u, "udev"); + if(!mon) + { + udev_unref(u); + return; + } + + if (udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor") > 0 || + udev_monitor_enable_receiving(mon) < 0) + { + udev_monitor_unref(mon); + udev_unref(u); + return; + } + + pSec->uevent_handler = xf86AddGeneralHandler(udev_monitor_get_fd(mon), SECUdevEventsHandler, pScrn); + if (!pSec->uevent_handler) + { + udev_monitor_unref(mon); + udev_unref(u); + return; + } + + pSec->uevent_monitor = mon; +} + +static void +_secUdevDeinit (ScrnInfoPtr pScrn) +{ + SECPtr pSec = SECPTR (pScrn); + + if (pSec->uevent_handler) + { + struct udev *u = udev_monitor_get_udev(pSec->uevent_monitor); + + udev_monitor_unref(pSec->uevent_monitor); + udev_unref(u); + pSec->uevent_handler = NULL; + pSec->uevent_monitor = NULL; + } + +} + +static Bool +SECSaveScreen (ScreenPtr pScreen, int mode) +{ + /* dummpy save screen */ + return TRUE; +} + +static void +SECUdevEventsHandler (int fd, void *closure) +{ + ScrnInfoPtr pScrn = closure; + SECPtr pSec = SECPTR (pScrn); + struct udev_device *dev; + const char *hotplug; + struct stat s; + dev_t udev_devnum; + int ret; + + dev = udev_monitor_receive_device (pSec->uevent_monitor); + if (!dev) + return; + + udev_devnum = udev_device_get_devnum(dev); + + ret = fstat (pSec->drm_fd, &s); + if (ret == -1) + return; + + /* + * Check to make sure this event is directed at our + * device (by comparing dev_t values), then make + * sure it's a hotplug event (HOTPLUG=1) + */ + hotplug = udev_device_get_property_value (dev, "HOTPLUG"); + + if (memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)) == 0 && + hotplug && atoi(hotplug) == 1) + { + XDBG_INFO(MSEC, "SEC-UDEV: HotPlug\n"); + RRGetInfo (screenInfo.screens[pScrn->scrnIndex], TRUE); + } + + udev_device_unref(dev); +} +#endif /* UDEV_HAVE */ + +static const OptionInfoRec * +SECAvailableOptions (int chipid, int busid) +{ + return SECOptions; +} + +static void +SECIdentify (int flags) +{ + xf86PrintChipsets (SEC_NAME, "driver for Exynos Chipsets", SECChipsets); +} + + +/* The purpose of this function is to identify all instances of hardware supported + * by the driver. The probe must find the active device sections that match the driver + * by calling xf86MatchDevice(). + */ +static Bool +SECProbe (DriverPtr pDrv, int flags) +{ + int i; + ScrnInfoPtr pScrn; + GDevPtr *ppDevSections; + int numDevSections; + int entity; + Bool foundScreen = FALSE; + + /* check the drm mode setting */ + if (!_secHwProbe (NULL, NULL, NULL)) + { + return FALSE; + } + + /* For now, just bail out for PROBE_DETECT. */ + if (flags & PROBE_DETECT) + return FALSE; + + if ((numDevSections = xf86MatchDevice (SEC_DRIVER_NAME, &ppDevSections)) <= 0) + { + free (ppDevSections); + return FALSE; + } + + for (i = 0; i < numDevSections; i++) + { + entity = xf86ClaimNoSlot (pDrv, 0, ppDevSections[i], TRUE); + + pScrn = xf86AllocateScreen (pDrv, flags); + xf86AddEntityToScreen (pScrn, entity); + + if (pScrn) + { + foundScreen = TRUE; + + pScrn->driverVersion = SEC_VERSION; + pScrn->driverName = SEC_DRIVER_NAME; + pScrn->name = SEC_NAME; + pScrn->Probe = SECProbe; + pScrn->PreInit = SECPreInit; + pScrn->ScreenInit = SECScreenInit; + pScrn->SwitchMode = SECSwitchMode; + pScrn->AdjustFrame = SECAdjustFrame; + pScrn->EnterVT = SECEnterVT; + pScrn->LeaveVT = SECLeaveVT; + pScrn->ValidMode = SECValidMode; + + xf86DrvMsg (pScrn->scrnIndex, X_INFO, + "using drm mode setting device\n"); + } + } + free (ppDevSections); + + return foundScreen; +} + +/* + * This is called before ScreenInit to probe the screen configuration. + * The main tasks to do in this funtion are probing, module loading, option handling, + * card mapping, and mode setting setup. + */ +static Bool +SECPreInit (ScrnInfoPtr pScrn, int flags) +{ + SECPtr pSec; + Gamma defualt_gamma = {0.0, 0.0, 0.0}; + rgb default_weight = {0, 0, 0}; + int flag24; + + if (flags & PROBE_DETECT) + return FALSE; + + /* allocate private */ + if (!_allocScrnPrivRec (pScrn)) + return FALSE; + pSec = SECPTR (pScrn); + + /* Check the number of entities, and fail if it isn't one. */ + if (pScrn->numEntities != 1) + return FALSE; + + pSec->pEnt = xf86GetEntityInfo (pScrn->entityList[0]); + + /* initialize the hardware specifics */ + if (!_secHwInit (pScrn, NULL, NULL)) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, + "fail to initialize hardware\n"); + goto bail1; + } + + pScrn->displayWidth = 640; /*default width */ + pScrn->monitor = pScrn->confScreen->monitor; + pScrn->progClock = TRUE; + pScrn->rgbBits = 8; + + /* set the depth and the bpp to pScrn */ + flag24 = Support24bppFb | Support32bppFb; + if (!xf86SetDepthBpp (pScrn, 0, 0, 0, flag24)) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, + "fail to find the depth\n"); + goto bail1; + } + xf86PrintDepthBpp (pScrn); /* just print out the depth and the bpp */ + + /* color weight */ + if (!xf86SetWeight (pScrn, default_weight, default_weight)) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR , + "fail to set the color weight of RGB\n"); + goto bail1; + } + + /* visual init, make a TrueColor, -1 */ + if (!xf86SetDefaultVisual (pScrn, -1)) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR , + "fail to initialize the default visual\n"); + goto bail1; + } + + /* Collect all the option flags (fill in pScrn->options) */ + xf86CollectOptions (pScrn, NULL); + + /* + * Process the options based on the information SECOptions. + * The results are written to pSec->Options. If all the options + * processing is done within this fuction a local variable "options" + * can be used instead of pSec->Options + */ + if (!(pSec->Options = malloc (sizeof (SECOptions)))) + goto bail1; + memcpy (pSec->Options, SECOptions, sizeof (SECOptions)); + xf86ProcessOptions (pScrn->scrnIndex, pSec->pEnt->device->options, + pSec->Options); + + /* Check with the driver options */ + _checkDriverOptions (pScrn); + + /* use a fake root pixmap when rotation angle is 90 or 270 */ + pSec->fake_root = ((pSec->rotate &(RR_Rotate_90|RR_Rotate_270)) != 0); + + /* drm mode init:: Set the Crtc, the default Output, and the current Mode */ + if (!secModePreInit (pScrn, pSec->drm_fd)) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR , + "fail to initialize drm mode setting\n"); + goto bail1; + } + + /* set gamma */ + if (!xf86SetGamma (pScrn,defualt_gamma)) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR , + "fail to set the gamma\n"); + goto bail1; + } + + pScrn->currentMode = pScrn->modes; + pScrn->displayWidth = pScrn->virtualX; + xf86PrintModes (pScrn); /* just print the current mode */ + + /* set dpi */ + xf86SetDpi (pScrn, 0, 0); + + /* Load modules */ + if (!xf86LoadSubModule (pScrn, "fb")) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR , + "fail to load fb module\n"); + goto bail1; + } + + if (!xf86LoadSubModule (pScrn, "exa")) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR , + "fail to load exa module\n"); + goto bail1; + } + + if (!xf86LoadSubModule (pScrn, "dri2")) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR , + "fail to load dri2 module\n"); + goto bail1; + } + + old_sig_wrapper = OsRegisterSigWrapper(_secOsSigWrapper); + return TRUE; + +bail1: + _freeScrnPrivRec (pScrn); + _secHwDeinit (pScrn); + return FALSE; +} + + + + +static Bool +SECScreenInit (ScreenPtr pScreen, int argc, char **argv) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = SECPTR (pScrn); + VisualPtr visual; + int init_picture = 0; + SECFbPtr pFb = NULL; + + xf86DrvMsg (pScrn->scrnIndex,X_INFO, + "Infomation of Visual is \n\tbitsPerPixel=%d, depth=%d, defaultVisual=%s\n" + "\tmask: %x,%x,%x, offset: %d,%d,%d\n", + pScrn->bitsPerPixel, + pScrn->depth, + xf86GetVisualName (pScrn->defaultVisual), + (unsigned int) pScrn->mask.red, + (unsigned int) pScrn->mask.green, + (unsigned int) pScrn->mask.blue, + (int) pScrn->offset.red, + (int) pScrn->offset.green, + (int) pScrn->offset.blue); + + /* initialize the framebuffer */ + /* soolim :: think rotations */ + + pFb = secFbAllocate (pScrn, pScrn->virtualX, pScrn->virtualY); + if (!pFb) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "cannot allocate framebuffer\n"); + return FALSE; + } + pSec->pFb = pFb; + + /* mi layer */ + miClearVisualTypes(); + if (!miSetVisualTypes (pScrn->depth, TrueColorMask, pScrn->rgbBits, TrueColor)) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, + "visual type setup failed for %d bits per pixel [1]\n", + pScrn->bitsPerPixel); + return FALSE; + } + + if (!miSetPixmapDepths()) + { + xf86DrvMsg (pScrn->scrnIndex,X_ERROR , + "pixmap depth setup failed\n"); + return FALSE; + } + + switch (pScrn->bitsPerPixel) + { + case 16: + case 24: + case 32: + if (! fbScreenInit (pScreen, (void*)ROOT_FB_ADDR, + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, + pScrn->virtualX, /*Pixel width for framebuffer*/ + pScrn->bitsPerPixel)) + return FALSE; + + init_picture = 1; + + break; + default: + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, + "internal error: invalid number of bits per pixel (%d) encountered\n", + pScrn->bitsPerPixel); + break; + } + + if (pScrn->bitsPerPixel > 8) + { + /* Fixup RGB ordering */ + visual = pScreen->visuals + pScreen->numVisuals; + while (--visual >= pScreen->visuals) + { + if ((visual->class | DynamicClass) == DirectColor) + { + visual->offsetRed = pScrn->offset.red; + visual->offsetGreen = pScrn->offset.green; + visual->offsetBlue = pScrn->offset.blue; + visual->redMask = pScrn->mask.red; + visual->greenMask = pScrn->mask.green; + visual->blueMask = pScrn->mask.blue; + } + } + } + + /* must be after RGB ordering fixed */ + if (init_picture && !fbPictureInit (pScreen, NULL, 0)) + { + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, + "Render extension initialisation failed\n"); + } + + /* init the exa */ + if (pSec->is_exa) + { + if (!secExaInit (pScreen)) + { + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, + "EXA initialization failed\n"); + } + else + { + /* init the dri2 */ + if (pSec->is_dri2) + { + if (!secDri2Init (pScreen)) + { + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, + "DRI2 initialization failed\n"); + } + } + } + } + + /* XVideo Initiailization here */ + if (!secVideoInit (pScreen)) + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, + "XVideo extention initialization failed\n"); + + xf86SetBlackWhitePixels (pScreen); + miInitializeBackingStore (pScreen); + xf86SetBackingStore (pScreen); + + /* use dummy hw_cursro instead of sw_cursor */ + miDCInitialize (pScreen, xf86GetPointerScreenFuncs()); + xf86DrvMsg (pScrn->scrnIndex, X_INFO + , "Initializing HW Cursor\n"); + + if (!xf86_cursors_init (pScreen, SEC_CURSOR_W, SEC_CURSOR_H, + (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | + HARDWARE_CURSOR_BIT_ORDER_MSBFIRST | + HARDWARE_CURSOR_INVERT_MASK | + HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK | + HARDWARE_CURSOR_AND_SOURCE_WITH_MASK | + HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 | + HARDWARE_CURSOR_ARGB))) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR + , "Hardware cursor initialization failed\n"); + } + + /* crtc init */ + if (!xf86CrtcScreenInit (pScreen)) + return FALSE; + + /* set the desire mode : set the mode to xf86crtc here */ + xf86SetDesiredModes (pScrn); + + /* colormap */ + if (!miCreateDefColormap (pScreen)) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR + , "internal error: miCreateDefColormap failed \n"); + return FALSE; + } + + if (!xf86HandleColormaps (pScreen, 256, 8, secModeLoadPalette, NULL, + CMAP_PALETTED_TRUECOLOR)) + return FALSE; + + /* dpms */ + xf86DPMSInit (pScreen, xf86DPMSSet, 0); + + /* screen saver */ + pScreen->SaveScreen = SECSaveScreen; + + secModeInit(pScrn); + + /* Wrap the current CloseScreen function */ + pSec->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = SECCloseScreen; + + /* Wrap the current CloseScreen function */ + pSec->CreateScreenResources = pScreen->CreateScreenResources; + pScreen->CreateScreenResources = SECCreateScreenResources; + +#if HAVE_UDEV + _secUdevInit(pScrn); +#endif + +#if 0 + /* Init Hooks for memory flush */ + secMemoryInstallHooks(); +#endif + +#if USE_XDBG + xDbgLogPListInit (pScreen); +#endif + + XDBG_KLOG(MSEC, "Init Screen\n"); + return TRUE; +} + +static Bool +SECSwitchMode (ScrnInfoPtr pScrn, DisplayModePtr pMode) +{ + return xf86SetSingleMode (pScrn, pMode, RR_Rotate_0); +} + +static void +SECAdjustFrame (ScrnInfoPtr pScrn, int x, int y) +{ +} + +static Bool +SECEnterVT (ScrnInfoPtr pScrn) +{ + xf86DrvMsg (pScrn->scrnIndex, X_INFO + , "EnterVT::Hardware state at EnterVT:\n"); + + return TRUE; +} + +static void +SECLeaveVT (ScrnInfoPtr pScrn) +{ + xf86DrvMsg (pScrn->scrnIndex, X_INFO + , "LeaveVT::Hardware state at LeaveVT:\n"); +} + +static ModeStatus +SECValidMode (ScrnInfoPtr pScrn, DisplayModePtr pMode, Bool verbose, int flags) +{ + return MODE_OK; +} + + +/** + * Adjust the screen pixmap for the current location of the front buffer. + * This is done at EnterVT when buffers are bound as long as the resources + * have already been created, but the first EnterVT happens before + * CreateScreenResources. + */ +static Bool +SECCreateScreenResources (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = SECPTR (pScrn); + + pScreen->CreateScreenResources = pSec->CreateScreenResources; + if (!(*pScreen->CreateScreenResources) (pScreen)) + return FALSE; + + /* + * [TODO]::::: + * create screen resources + * set the bo to the screen pixamp private here + * or create the shadow pixmap for the screen pixamp here + * or set the fake rotated screen infomation here. + */ + + return TRUE; +} + +static Bool +SECCloseScreen (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = SECPTR (pScrn); + + secWbDestroy (); + +#if HAVE_UDEV + _secUdevDeinit(pScrn); +#endif + + secVideoFini (pScreen); + secExaDeinit (pScreen); + secModeDeinit (pScrn); + + if (pSec->pFb) + { + secFbFree (pSec->pFb); + pSec->pFb = NULL; + } + + _secHwDeinit (pScrn); + + pScrn->vtSema = FALSE; + + pScreen->CreateScreenResources = pSec->CreateScreenResources; + pScreen->CloseScreen = pSec->CloseScreen; + + XDBG_KLOG(MSEC, "Close Screen\n"); + return (*pScreen->CloseScreen) (pScreen); +} + + +#define CONV_POINT_TO_KEY(x, y, key) key = (unsigned long)((((unsigned short)(x&0xFFFF)) << 16) | ((unsigned short)(y&0xFFFF ))) +#define CONT_KEY_TO_POINT(key, x, y) x = (unsigned short)((key&0xFFFF0000)>>16); y=(unsigned short)(key&0xFFFF) + +typedef struct{ + tbm_bo bo; + struct xorg_list link; +}SecFbBoItem, *SecFbBoItemPtr; + +static void +_secFbFreeBoData(void* data) +{ + XDBG_RETURN_IF_FAIL(data != NULL); + + ScrnInfoPtr pScrn; + SECPtr pSec; + SECFbBoDataPtr bo_data = (SECFbBoDataPtr)data; + + pScrn = bo_data->pScrn; + pSec = SECPTR (pScrn); + + XDBG_DEBUG (MFB, "FreeRender bo_data gem:%d, fb_id:%d, %dx%d+%d+%d\n", + bo_data->gem_handle, bo_data->fb_id, + bo_data->pos.x2-bo_data->pos.x1, bo_data->pos.y2-bo_data->pos.y1, + bo_data->pos.x1, bo_data->pos.y1); + + if (bo_data->fb_id) + { + drmModeRmFB (pSec->drm_fd, bo_data->fb_id); + bo_data->fb_id = 0; + } + + if (bo_data->pPixmap) + { + pScrn->pScreen->DestroyPixmap (bo_data->pPixmap); + bo_data->pPixmap = NULL; + } + + free (bo_data); + bo_data = NULL; +} + + +static tbm_bo +_secFbCreateBo (SECFbPtr pFb, int x, int y, int width, int height) +{ + XDBG_RETURN_VAL_IF_FAIL ((pFb != NULL), NULL); + XDBG_RETURN_VAL_IF_FAIL ((width > 0), NULL); + XDBG_RETURN_VAL_IF_FAIL ((height > 0), NULL); + + SECPtr pSec = SECPTR (pFb->pScrn); + + tbm_bo bo = NULL; + tbm_bo_handle bo_handle1, bo_handle2; + SECFbBoDataPtr bo_data=NULL; + unsigned int pitch; + unsigned int fb_id = 0; + int ret; + int flag; + + pitch = width * 4; + + if (!pSec->cachable) + flag = TBM_BO_WC; + else + flag = TBM_BO_DEFAULT; + + bo = tbm_bo_alloc (pSec->tbm_bufmgr, pitch*height, flag); + XDBG_GOTO_IF_FAIL (bo != NULL, fail); + + /* memset 0x0 */ + bo_handle1 = tbm_bo_map (bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE); + XDBG_RETURN_VAL_IF_FAIL (bo_handle1.ptr != NULL, NULL); + + memset (bo_handle1.ptr, 0x0, pitch*height); + tbm_bo_unmap (bo); + + bo_handle2 = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT); + + /* Create drm fb */ + ret = drmModeAddFB(pSec->drm_fd + , width, height + , pFb->pScrn->bitsPerPixel + , pFb->pScrn->bitsPerPixel + , pitch + , bo_handle2.u32 + , &fb_id); + XDBG_GOTO_IF_ERRNO(ret == Success, fail, -ret); + + if(x == -1) x = 0; + if(y == -1) y = 0; + + /* Set bo user data */ + bo_data = calloc(1, sizeof(SECFbBoDataRec)); + XDBG_GOTO_IF_FAIL (bo_data != NULL, fail); + bo_data->pFb = pFb; + bo_data->gem_handle = bo_handle2.u32; + bo_data->pitch = pitch; + bo_data->fb_id = fb_id; + bo_data->pos.x1 = x; + bo_data->pos.y1 = y; + bo_data->pos.x2 = x+width; + bo_data->pos.y2 = y+height; + bo_data->size = tbm_bo_size(bo); + bo_data->pScrn = pFb->pScrn; + XDBG_GOTO_IF_FAIL(tbm_bo_add_user_data(bo, TBM_BO_DATA_FB, _secFbFreeBoData), fail); + XDBG_GOTO_IF_FAIL(tbm_bo_set_user_data(bo, TBM_BO_DATA_FB, (void *)bo_data), fail); + + XDBG_DEBUG (MFB, "CreateRender bo(name:%d, gem:%d, fb_id:%d, %dx%d+%d+%d\n", + tbm_bo_export (bo), bo_data->gem_handle, bo_data->fb_id, + bo_data->pos.x2-bo_data->pos.x1, bo_data->pos.y2-bo_data->pos.y1, + bo_data->pos.x1, bo_data->pos.y1); + + return bo; +fail: + if (bo) + { + secRenderBoUnref(bo); + } + + if (fb_id) + { + drmModeRmFB(pSec->drm_fd, fb_id); + } + + if (bo_data) + { + free (bo_data); + bo_data = NULL; + } + + return NULL; +} + +static tbm_bo +_secFbRefBo (tbm_bo bo) +{ + return tbm_bo_ref(bo); +} + +static int +_secFbUnrefBo(tbm_bo bo) +{ + tbm_bo_unref(bo); + bo = NULL; + + return TRUE; +} + +SECFbPtr +secFbAllocate (ScrnInfoPtr pScrn, int width, int height) +{ + //secLogSetLevel(MFB, 0); + + XDBG_RETURN_VAL_IF_FAIL((pScrn != NULL), NULL); + XDBG_RETURN_VAL_IF_FAIL((width > 0), NULL); + XDBG_RETURN_VAL_IF_FAIL((height > 0), NULL); + + SECFbPtr pFb = calloc (1, sizeof(SECFbRec)); + XDBG_GOTO_IF_FAIL ((pFb != NULL), fail); + + pFb->pScrn = pScrn; + pFb->num_bo = 0; + pFb->width = width; + pFb->height = height; + + xorg_list_init(&pFb->list_bo); + + /* Create default buffer */ + pFb->default_bo = _secFbCreateBo(pFb, 0, 0, width, height); + + XDBG_TRACE (MFB,"Allocate %dx%d\n", width, height); + + return pFb; + +fail: + + return NULL; +} + +void +secFbFree (SECFbPtr pFb) +{ + XDBG_RETURN_IF_FAIL(pFb != NULL); + + XDBG_TRACE (MFB,"Free %dx%d, num:%d\n", pFb->width, pFb->height, pFb->num_bo); + + if (!xorg_list_is_empty(&pFb->list_bo)) + { + SecFbBoItemPtr item = NULL, tmp = NULL; + + xorg_list_for_each_entry_safe(item, tmp, &pFb->list_bo, link) + { + xorg_list_del(&item->link); + _secFbUnrefBo(item->bo); + free(item); + item=NULL; + } + } + + if (pFb->default_bo) + { + secRenderBoUnref(pFb->default_bo); + pFb->default_bo = NULL; + } + + free (pFb); + pFb = NULL; +} + +tbm_bo +secFbGetBo (SECFbPtr pFb, int x, int y, int width, int height, Bool onlyIfExists) +{ + SECFbBoDataPtr bo_data=NULL; + tbm_bo bo = NULL; + _X_UNUSED unsigned long key; + BoxRec box; + BoxPtr b1, b2; + int ret = rgnOUT; + + box.x1 = x; + box.y1 = y; + box.x2 = x+width; + box.y2 = y+height; + b2 = &box; + + if(!xorg_list_is_empty(&pFb->list_bo)) + { + SecFbBoItemPtr item = NULL, tmp = NULL; + xorg_list_for_each_entry_safe(item, tmp, &pFb->list_bo, link) + { + bo = item->bo; + + tbm_bo_get_user_data(bo, TBM_BO_DATA_FB, (void * *)&bo_data); + b1 = &bo_data->pos; + + ret = secUtilBoxInBox(b1, b2); + + if(ret == rgnIN || ret == rgnSAME) + { + return bo; + } + else if(ret == rgnPART) + { + if (!onlyIfExists) continue; + + int r2 = secUtilBoxInBox(b2, b1); + if(r2 == rgnIN) + { + xorg_list_del(&item->link); + _secFbUnrefBo(bo); + free(item); + item=NULL; + pFb->num_bo--; + ret = rgnOUT; + break; + } + } + else if(ret == rgnOUT) + { + continue; + } + else + { + return NULL; + } + } + } + + if (ret == rgnOUT && !onlyIfExists) + { + SecFbBoItemPtr item; + CONV_POINT_TO_KEY(x, y, key); + + item = calloc(1, sizeof(SecFbBoItem)); + XDBG_RETURN_VAL_IF_FAIL (item != NULL, NULL); + if(width == pFb->width && + height == pFb->height && + x == 0 && + y == 0) + { + bo = _secFbRefBo(pFb->default_bo); + } + else + { + bo = _secFbCreateBo(pFb, x, y, width, height); + if (!bo) + { + free (item); + item = NULL; + return NULL; + } + } + + item->bo = bo; + xorg_list_add(&item->link, &pFb->list_bo); + pFb->num_bo++; + + XDBG_TRACE (MFB, "GetBO num:%d bo:%p name:%d, %dx%d+%d+%d\n", + pFb->num_bo, bo, tbm_bo_export (bo), width, height, x,y); + return bo; + } + + return NULL; +} + +tbm_bo +secFbSwapBo (SECFbPtr pFb, tbm_bo back_bo) +{ + SECFbBoDataPtr back_bo_data = NULL; + SECFbBoDataPtr bo_data = NULL; + SECFbBoDataRec tmp_bo_data; + tbm_bo bo; + BoxPtr b1, b2; + SecFbBoItemPtr item = NULL, tmp = NULL; + + XDBG_RETURN_VAL_IF_FAIL(pFb != NULL, NULL); + XDBG_RETURN_VAL_IF_FAIL(FALSE == xorg_list_is_empty(&pFb->list_bo), NULL); + XDBG_RETURN_VAL_IF_FAIL(tbm_bo_get_user_data(back_bo, TBM_BO_DATA_FB, (void * *)&back_bo_data), NULL); + XDBG_RETURN_VAL_IF_FAIL(back_bo_data, NULL); + + b2 = &back_bo_data->pos; + + xorg_list_for_each_entry_safe(item, tmp, &pFb->list_bo, link) + { + bo = item->bo; + + tbm_bo_get_user_data(bo, TBM_BO_DATA_FB, (void * *)&bo_data); + b1 = &bo_data->pos; + if(rgnSAME == secUtilBoxInBox(b1, b2)) + { + XDBG_DEBUG(MFB, "SwapBO(Back:%d, Front:%d)\n", + tbm_bo_export (back_bo), tbm_bo_export (bo)); + + if(tbm_bo_swap(bo, back_bo)) + { + memcpy(&tmp_bo_data, bo_data, sizeof(SECFbBoDataRec)); + memcpy(bo_data, back_bo_data, sizeof(SECFbBoDataRec)); + memcpy(back_bo_data, &tmp_bo_data, sizeof(SECFbBoDataRec)); + } + else + return NULL; + + return bo; + } + } + + return NULL; +} + +void +secFbResize (SECFbPtr pFb, int width, int height) +{ + XDBG_RETURN_IF_FAIL(pFb != NULL); + + SECFbBoDataPtr bo_data=NULL; + tbm_bo bo, old_bo; + int ret; + BoxRec box; + BoxPtr b1, b2; + + if (pFb->width == width && pFb->height == height) + return; + + old_bo = pFb->default_bo; + + pFb->width = width; + pFb->height = height; + XDBG_TRACE (MFB,"Resize %dx%d, num:%d\n", pFb->width, pFb->height, pFb->num_bo); + + box.x1=0; + box.y1=0; + box.x2=width; + box.y2=height; + b1 = &box; + + if (!xorg_list_is_empty (&pFb->list_bo)) + { + SecFbBoItemPtr item = NULL, tmp = NULL; + + xorg_list_for_each_entry_safe(item, tmp, &pFb->list_bo, link) + { + bo = item->bo; + + tbm_bo_get_user_data(bo, TBM_BO_DATA_FB, (void * *)&bo_data); + b2 = &bo_data->pos; + ret = secUtilBoxInBox(b1, b2); + + if(ret == rgnIN || ret ==rgnSAME) + continue; + + /* Remove bo */ + XDBG_DEBUG (MFB, "\t unref bo(name:%d, gem:%d, fb_id:%d, %dx%d+%d+%d\n", + tbm_bo_export (bo), bo_data->gem_handle, bo_data->fb_id, + bo_data->pos.x2-bo_data->pos.x1, bo_data->pos.y2-bo_data->pos.y1, + bo_data->pos.x1, bo_data->pos.y1); + + xorg_list_del(&item->link); + secRenderBoUnref(bo); + pFb->num_bo--; + free(item); + item=NULL; + } + } + + pFb->default_bo = _secFbCreateBo(pFb, 0, 0, width, height); + if(old_bo) + secRenderBoUnref(old_bo); +} + +int +secFbFindBo (SECFbPtr pFb, int x, int y, int width, int height, int *num_bo, tbm_bo** bos) +{ + SECFbBoDataPtr bo_data=NULL; + int num=0; + tbm_bo *l=NULL; + tbm_bo bo; + int ret = rgnOUT; + BoxRec box; + BoxPtr b1, b2; + SecFbBoItemPtr item = NULL, tmp = NULL; + + if(xorg_list_is_empty(&pFb->list_bo)) + { + return rgnOUT; + } + + box.x1=x; + box.y1=y; + box.x2=x+width; + box.y2=y+height; + b2 = &box; + + l = calloc(pFb->num_bo, sizeof(tbm_bo)); + + xorg_list_for_each_entry_safe(item, tmp, &pFb->list_bo, link) + { + bo = item->bo; + + tbm_bo_get_user_data(bo, TBM_BO_DATA_FB, (void * *)&bo_data); + if (bo_data == NULL) + { + free (l); + return rgnOUT; + } + + b1 = &bo_data->pos; + ret = secUtilBoxInBox(b1, b2); + XDBG_DEBUG(MFB, "[%d/%d] ret:%d bo(%d,%d,%d,%d) fb(%d,%d,%d,%d)\n", + num+1, pFb->num_bo, ret, + b1->x1,b1->y1,b1->x2,b1->y2, + b2->x1,b2->y1,b2->x2,b2->y2); + + if(ret == rgnSAME || ret == rgnIN) + { + l[num++] = bo; + break; + } + else if(ret == rgnPART) + { + l[num++] = bo; + } + else + { + ; + } + } + + if(num_bo) *num_bo = num; + if(bos) + { + *bos = l; + } + else + { + free(l); + } + + return ret; +} + +tbm_bo +secFbFindBoByPoint (SECFbPtr pFb, int x, int y) +{ + SECFbBoDataPtr bo_data=NULL; + tbm_bo bo; + SecFbBoItemPtr item = NULL, tmp = NULL; + + if(xorg_list_is_empty(&pFb->list_bo)) + { + return NULL; + } + + xorg_list_for_each_entry_safe(item, tmp, &pFb->list_bo, link) + { + bo = item->bo; + tbm_bo_get_user_data(bo, TBM_BO_DATA_FB, (void * *)&bo_data); + if ((x >= bo_data->pos.x1) && + (x < bo_data->pos.x2) && + (y >= bo_data->pos.y1) && + (y < bo_data->pos.y2)) + { + return bo; + } + } + + return NULL; +} + +PixmapPtr +secRenderBoGetPixmap (SECFbPtr pFb, tbm_bo bo) +{ + ScreenPtr pScreen = pFb->pScrn->pScreen; + PixmapPtr pPixmap; + SECFbBoDataPtr bo_data; + int ret; + + XDBG_RETURN_VAL_IF_FAIL(bo != NULL, NULL); + XDBG_RETURN_VAL_IF_FAIL(tbm_bo_get_user_data(bo, TBM_BO_DATA_FB, (void**)&bo_data), NULL); + + if(bo_data->pPixmap == NULL) + { + pPixmap = pScreen->CreatePixmap(pFb->pScrn->pScreen, 0,0, + pFb->pScrn->depth, + CREATE_PIXMAP_USAGE_SUB_FB); + XDBG_GOTO_IF_FAIL(pPixmap != NULL, fail); + + ret = pScreen->ModifyPixmapHeader(pPixmap, + bo_data->pos.x2 - bo_data->pos.x1, + bo_data->pos.y2 - bo_data->pos.y1, + pFb->pScrn->depth, + pFb->pScrn->bitsPerPixel, + bo_data->pitch, (void*)bo); + XDBG_GOTO_IF_FAIL(ret != FALSE, fail); + bo_data->pPixmap = pPixmap; + XDBG_DEBUG(MFB, "CreateRenderPixmap:%p\n", pPixmap); + } + + return bo_data->pPixmap; + +fail: + XDBG_ERROR(MFB, "ERR: CreateRenderPixmap\n"); + if(pPixmap) + { + pScreen->DestroyPixmap(pPixmap); + } + return NULL; +} + +tbm_bo +secRenderBoCreate (ScrnInfoPtr pScrn, int width, int height) +{ + SECPtr pSec = SECPTR (pScrn); + + return _secFbCreateBo(pSec->pFb, -1, -1, width, height); +} + +tbm_bo +secRenderBoRef (tbm_bo bo) +{ + return _secFbRefBo (bo); +} + +void +secRenderBoUnref (tbm_bo bo) +{ + _secFbUnrefBo(bo); +} + +void +secRenderBoSetPos (tbm_bo bo, int x, int y) +{ + SECFbBoDataPtr bo_data; + int width, height; + + XDBG_RETURN_IF_FAIL(bo != NULL); + XDBG_RETURN_IF_FAIL(x >= 0); + XDBG_RETURN_IF_FAIL(y >= 0); + XDBG_RETURN_IF_FAIL(tbm_bo_get_user_data(bo, TBM_BO_DATA_FB, (void**)&bo_data)); + + width = bo_data->pos.x2 - bo_data->pos.x1; + height = bo_data->pos.y2 - bo_data->pos.y1; + + bo_data->pos.x1 = x; + bo_data->pos.y1 = y; + bo_data->pos.x2 = x+width; + bo_data->pos.y2 = y+height; +} diff --git a/src/sec.h b/src/sec.h new file mode 100755 index 0000000..de04a1b --- /dev/null +++ b/src/sec.h @@ -0,0 +1,230 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@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. + +**************************************************************************/ + +#ifndef SEC_H +#define SEC_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdint.h> +#include "xorg-server.h" +#include "xf86.h" +#include "xf86xv.h" +#include "xf86_OSproc.h" +#include "xf86drm.h" +#include "X11/Xatom.h" +#include "tbm_bufmgr.h" +#include "sec_display.h" +#include "sec_accel.h" +#include "sec_video.h" +#include "sec_wb.h" +#include "sec_util.h" +#if HAVE_UDEV +#include <libudev.h> +#endif + +#define USE_XDBG 1 + +/* drm bo data type */ +typedef enum +{ + TBM_BO_DATA_FB = 1, +} TBM_BO_DATA; + +/* framebuffer infomation */ +typedef struct +{ + ScrnInfoPtr pScrn; + + int width; + int height; + + int num_bo; + struct xorg_list list_bo; + void* tbl_bo; /* bo hash table: key=(x,y)position */ + + tbm_bo default_bo; +} SECFbRec, *SECFbPtr; + +/* framebuffer bo data */ +typedef struct +{ + SECFbPtr pFb; + BoxRec pos; + uint32_t gem_handle; + int fb_id; + int pitch; + int size; + PixmapPtr pPixmap; + ScrnInfoPtr pScrn; +} SECFbBoDataRec, *SECFbBoDataPtr; + +/* sec screen private information */ +typedef struct +{ + EntityInfoPtr pEnt; + Bool fake_root; /* screen rotation status */ + + /* driver options */ + OptionInfoPtr Options; + Bool is_exa; + Bool is_dri2; + Bool is_sw_exa; + Bool is_accel_2d; + Bool is_wb_clone; + Bool is_tfb; /* triple flip buffer */ + Bool cachable; /* if use cachable buffer */ + Bool scanout; /* if use scanout buffer */ + int flip_bufs; /* number of the flip buffers */ + Rotation rotate; + Bool use_partial_update; + Bool is_fb_touched; /* whether framebuffer is touched or not */ + + /* drm */ + int drm_fd; + char *drm_device_name; + tbm_bufmgr tbm_bufmgr; + + /* main fb information */ + SECFbPtr pFb; + + /* mode setting info private */ + SECModePtr pSecMode; + + /* exa private */ + SECExaPrivPtr pExaPriv; + + /* video private */ + SECVideoPrivPtr pVideoPriv; + + Bool isLcdOff; /* lvds connector on/off status */ + + /* screen wrapper functions */ + CloseScreenProcPtr CloseScreen; + CreateScreenResourcesProcPtr CreateScreenResources; + +#if HAVE_UDEV + struct udev_monitor *uevent_monitor; + InputHandlerProc uevent_handler; +#endif + + /* DRI2 */ + Atom atom_use_dri2; + Bool useAsyncSwap; + DrawablePtr flipDrawable; + + /* pending flip handler cause of lcd off */ + Bool pending_flip_handler; + unsigned int frame; + unsigned int tv_sec; + unsigned int tv_usec; + void *event_data; + + /* overlay drawable */ + DamagePtr ovl_damage; + DrawablePtr ovl_drawable; + + SECDisplaySetMode set_mode; + OsTimerPtr resume_timer; + + SECWb *wb_clone; + Bool wb_fps; + int wb_hz; + + /* Cursor */ + Bool enableCursor; + + /* dump */ + int dump_mode; + long dump_xid; + void *dump_info; + char *dump_str; + char dump_type[16]; + int xvperf_mode; + char *xvperf; + + int scale; + int cpu; + int flip_cnt; + + /* mem debug + Normal pixmap + CREATE_PIXMAP_USAGE_BACKING_PIXMAP + CREATE_PIXMAP_USAGE_OVERLAY + CREATE_PIXMAP_USAGE_XVIDEO + CREATE_PIXMAP_USAGE_DRI2_FILP_BACK + CREATE_PIXMAP_USAGE_FB + CREATE_PIXMAP_USAGE_SUB_FB + CREATE_PIXMAP_USAGE_DRI2_BACK + */ + int pix_normal; + int pix_backing_pixmap; + int pix_overlay; + int pix_dri2_flip_back; + int pix_fb; + int pix_sub_fb; + int pix_dri2_back; +} SECRec, *SECPtr; + +/* get a private screen of ScrnInfo */ +#define SECPTR(p) ((SECPtr)((p)->driverPrivate)) + +/* the version of the driver */ +#define SEC_VERSION 1000 + +/* the name used to prefix messages */ +#define SEC_NAME "exynos" + +/* the driver name used in display.conf file. exynos_drv.so */ +#define SEC_DRIVER_NAME "exynos" + +#define ROOT_FB_ADDR (~0UL) + +#define SEC_CURSOR_W 64 +#define SEC_CURSOR_H 64 + +/* sec framebuffer */ +SECFbPtr secFbAllocate (ScrnInfoPtr pScrn, int width, int height); +void secFbFree (SECFbPtr pFb); +void secFbResize (SECFbPtr pFb, int width, int height); +tbm_bo secFbGetBo (SECFbPtr pFb, int x, int y, int width, int height, Bool onlyIfExists); +int secFbFindBo (SECFbPtr pFb, int x, int y, int width, int height, int *num_bo, tbm_bo** bos); +tbm_bo secFbFindBoByPoint (SECFbPtr pFb, int x, int y); +tbm_bo secFbSwapBo (SECFbPtr pFb, tbm_bo back_bo); + +tbm_bo secRenderBoCreate (ScrnInfoPtr pScrn, int width, int height); +tbm_bo secRenderBoRef (tbm_bo bo); +void secRenderBoUnref (tbm_bo bo); +void secRenderBoSetPos (tbm_bo bo, int x, int y); +PixmapPtr secRenderBoGetPixmap (SECFbPtr pFb, tbm_bo bo); + +#endif /* SEC_H */ 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; +} + diff --git a/src/util/sec_util.h b/src/util/sec_util.h new file mode 100755 index 0000000..0b0cb8f --- /dev/null +++ b/src/util/sec_util.h @@ -0,0 +1,193 @@ +/************************************************************************** + +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. + +**************************************************************************/ + +#ifndef __SEC_UTIL_H__ +#define __SEC_UTIL_H__ + +#include <fbdevhw.h> +#include <pixman.h> +#include <list.h> +#include <xdbg.h> +#include "fimg2d.h" + +#include "sec.h" +#include "property.h" +#include "sec_display.h" +#include "sec_video_types.h" +#include "sec_xberc.h" + +#define MFB XDBG_M('F','B',0,0) +#define MDISP XDBG_M('D','I','S','P') +#define MLYR XDBG_M('L','Y','R',0) +#define MPLN XDBG_M('P','L','N',0) +#define MSEC XDBG_M('S','E','C',0) +#define MEXA XDBG_M('E','X','A',0) +#define MEXAS XDBG_M('E','X','A','S') +#define MEVT XDBG_M('E','V','T',0) +#define MDRI2 XDBG_M('D','R','I','2') +#define MCRS XDBG_M('C','R','S',0) +#define MFLIP XDBG_M('F','L','I','P') +#define MDPMS XDBG_M('D','P','M','S') +#define MVDO XDBG_M('V','D','O',0) +#define MDA XDBG_M('D','A',0,0) +#define MTVO XDBG_M('T','V','O',0) +#define MWB XDBG_M('W','B',0,0) +#define MVA XDBG_M('V','A',0,0) +#define MPROP XDBG_M('P','R','O','P') +#define MXBRC XDBG_M('X','B','R','C') +#define MVBUF XDBG_M('V','B','U','F') +#define MDRM XDBG_M('D','R','M',0) +#define MACCE XDBG_M('A','C','C','E') +#define MCVT XDBG_M('C','V','T',0) +#define MEXAH XDBG_M('E','X','A','H') +#define MG2D XDBG_M('G','2','D',0) + +#define _XID(win) ((unsigned int)(((WindowPtr)win)->drawable.id)) + +#define UTIL_DUMP_OK 0 +#define UTIL_DUMP_ERR_OPENFILE 1 +#define UTIL_DUMP_ERR_SHMATTACH 2 +#define UTIL_DUMP_ERR_SEGSIZE 3 +#define UTIL_DUMP_ERR_CONFIG 4 +#define UTIL_DUMP_ERR_INTERNAL 5 + +#define rgnSAME 3 + +#define DUMP_DIR "/tmp/xdump" + +int secUtilDumpBmp (const char * file, const void * data, int width, int height); +int secUtilDumpRaw (const char * file, const void * data, int size); +int secUtilDumpShm (int shmid, const void * data, int width, int height); +int secUtilDumpPixmap (const char * file, PixmapPtr pPixmap); + +void* secUtilPrepareDump (ScrnInfoPtr pScrn, int bo_size, int buf_cnt); +void secUtilDoDumpRaws (void *dump, tbm_bo *bo, int *size, int bo_cnt, const char *file); +void secUtilDoDumpBmps (void *d, tbm_bo bo, int w, int h, xRectangle *crop, const char *file); +void secUtilDoDumpPixmaps (void *d, PixmapPtr pPixmap, const char *file); +void secUtilDoDumpVBuf (void *d, SECVideoBuf *vbuf, const char *file); +void secUtilFlushDump (void *dump); +void secUtilFinishDump (void *dump); + +int secUtilDegreeToRotate (int degree); +int secUtilRotateToDegree (int rotate); +int secUtilRotateAdd (int rot_a, int rot_b); + +void secUtilCacheFlush (ScrnInfoPtr scrn); + +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); + +void secUtilRotateArea (int *width, int *height, xRectangle *rect, int degree); +void secUtilRotateRect2 (int width, int height, xRectangle *rect, int degree, const char *func); +#define secUtilRotateRect(w,h,r,d) secUtilRotateRect2(w,h,r,d,__FUNCTION__) +void secUtilRotateRegion (int width, int height, RegionPtr region, int degree); + +void secUtilAlignRect (int src_w, int src_h, int dst_w, int dst_h, xRectangle *fit, Bool hw); +void secUtilScaleRect (int src_w, int src_h, int dst_w, int dst_h, xRectangle *scale); + +const PropertyPtr secUtilGetWindowProperty (WindowPtr pWin, const char* prop_name); + +int secUtilBoxInBox (BoxPtr base, BoxPtr box); +int secUtilBoxArea(BoxPtr pBox); +int secUtilBoxIntersect(BoxPtr pDstBox, BoxPtr pBox1, BoxPtr pBox2); +void secUtilBoxMove(BoxPtr pBox, int dx, int dy); + +Bool secUtilRectIntersect (xRectanglePtr pDest, xRectanglePtr pRect1, xRectanglePtr pRect2); + +void secUtilSaveImage (pixman_image_t *image, char *path); +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); +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); + +void secUtilFreeHandle (ScrnInfoPtr scrn, unsigned int handle); +Bool secUtilConvertPhyaddress (ScrnInfoPtr scrn, unsigned int phy_addr, int size, unsigned int *handle); +Bool secUtilConvertHandle (ScrnInfoPtr scrn, unsigned int handle, unsigned int *phy_addr, int *size); + +typedef void (*DestroyDataFunc) (void *func_data, void *key_data); + +void* secUtilListAdd (void *list, void *key, void *key_data); +void* secUtilListRemove (void *list, void *key); +void* secUtilListGetData (void *list, void *key); +Bool secUtilListIsEmpty (void *list); +void secUtilListDestroyData (void *list, DestroyDataFunc func, void *func_data); +void secUtilListDestroy (void *list); + +Bool secUtilSetDrmProperty (SECModePtr pSecMode, unsigned int obj_id, unsigned int obj_type, + const char *prop_name, unsigned int value); + +Bool secUtilEnsureExternalCrtc (ScrnInfoPtr scrn); + +G2dColorMode secUtilGetG2dFormat (unsigned int id); +unsigned int secUtilGetDrmFormat (unsigned int id); +SECFormatType secUtilGetColorType (unsigned int id); + +SECVideoBuf* _secUtilAllocVideoBuffer (ScrnInfoPtr scrn, int id, int width, int height, + Bool scanout, Bool reset, Bool secure, const char *func); +SECVideoBuf* _secUtilCreateVideoBuffer (ScrnInfoPtr scrn, int id, int width, int height, + Bool secure, const char *func); +SECVideoBuf* secUtilVideoBufferRef (SECVideoBuf *vbuf); +void _secUtilVideoBufferUnref (SECVideoBuf *vbuf, const char *func); +void _secUtilFreeVideoBuffer (SECVideoBuf *vbuf, const char *func); +void secUtilClearVideoBuffer (SECVideoBuf *vbuf); +Bool _secUtilIsVbufValid (SECVideoBuf *vbuf, const char *func); + +typedef void (*FreeVideoBufFunc) (SECVideoBuf *vbuf, void *data); +void secUtilAddFreeVideoBufferFunc (SECVideoBuf *vbuf, FreeVideoBufFunc func, void *data); +void secUtilRemoveFreeVideoBufferFunc (SECVideoBuf *vbuf, FreeVideoBufFunc func, void *data); + +#define secUtilAllocVideoBuffer(s,i,w,h,c,r,d) _secUtilAllocVideoBuffer(s,i,w,h,c,r,d,__FUNCTION__) +#define secUtilCreateVideoBuffer(s,i,w,h,d) _secUtilCreateVideoBuffer(s,i,w,h,d,__FUNCTION__) +#define secUtilVideoBufferUnref(v) _secUtilVideoBufferUnref(v,__FUNCTION__) +#define secUtilFreeVideoBuffer(v) _secUtilFreeVideoBuffer(v,__FUNCTION__) +#define secUtilIsVbufValid(v) _secUtilIsVbufValid(v,__FUNCTION__) +#define VBUF_IS_VALID(v) secUtilIsVbufValid(v) +#define VSTMAP(v) ((v)?(v)->stamp:0) +#define VBUF_IS_CONVERTING(v) (!xorg_list_is_empty (&((v)->convert_info))) + +/* for debug */ +char* secUtilDumpVideoBuffer (char *reply, int *len); + +#define list_rev_for_each_entry_safe(pos, tmp, head, member) \ + for (pos = __container_of((head)->prev, pos, member), tmp = __container_of(pos->member.prev, pos, member);\ + &pos->member != (head);\ + pos = tmp, tmp = __container_of(pos->member.prev, tmp, member)) + +#endif /* __SEC_UTIL_H__ */ diff --git a/src/xv/sec_video.c b/src/xv/sec_video.c new file mode 100644 index 0000000..9eb7d01 --- /dev/null +++ b/src/xv/sec_video.c @@ -0,0 +1,3095 @@ +/* + * xserver-xorg-video-exynos + * + * Copyright 2004 Keith Packard + * Copyright 2005 Eric Anholt + * Copyright 2006 Nokia Corporation + * Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved. + * + * Contact: Boram Park <boram1288.park@samsung.com> + * + * Permission to use, copy, modify, distribute and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the names of the authors and/or copyright holders + * not be used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. The authors and + * copyright holders make no representations about the suitability of this + * software for any purpose. It is provided "as is" without any express + * or implied warranty. + * + * THE AUTHORS AND COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include <errno.h> +#include <sys/time.h> +#include <sys/ioctl.h> + +#include <pixman.h> +#include <X11/Xatom.h> +#include <X11/extensions/Xv.h> +#include <X11/extensions/Xvproto.h> +#include <fourcc.h> + +#include <fb.h> +#include <fbdevhw.h> +#include <damage.h> + +#include <xf86xv.h> + +#include "sec.h" + +#include "sec_accel.h" +#include "sec_display.h" +#include "sec_crtc.h" +#include "sec_output.h" +#include "sec_video.h" +#include "sec_prop.h" +#include "sec_util.h" +#include "sec_wb.h" +#include "sec_video_virtual.h" +#include "sec_video_display.h" +#include "sec_video_tvout.h" +#include "sec_video_fourcc.h" +#include "sec_converter.h" +#include "sec_plane.h" +#include "sec_xberc.h" + +#include "xv_types.h" + +#include <exynos_drm.h> + +#define DONT_FILL_ALPHA -1 +#define SEC_MAX_PORT 16 + +#define INBUF_NUM 6 +#define OUTBUF_NUM 3 +#define NUM_HW_LAYER 2 + +#define OUTPUT_LCD (1 << 0) +#define OUTPUT_EXT (1 << 1) +#define OUTPUT_FULL (1 << 8) + +static XF86VideoEncodingRec dummy_encoding[] = +{ + { 0, "XV_IMAGE", -1, -1, { 1, 1 } }, + { 1, "XV_IMAGE", 4224, 4224, { 1, 1 } }, +}; + +static XF86ImageRec images[] = +{ + XVIMAGE_YUY2, + XVIMAGE_SUYV, + XVIMAGE_UYVY, + XVIMAGE_SYVY, + XVIMAGE_ITLV, + XVIMAGE_YV12, + XVIMAGE_I420, + XVIMAGE_S420, + XVIMAGE_ST12, + XVIMAGE_NV12, + XVIMAGE_SN12, + XVIMAGE_NV21, + XVIMAGE_SN21, + XVIMAGE_RGB32, + XVIMAGE_SR32, + XVIMAGE_RGB565, + XVIMAGE_SR16, +}; + +static XF86VideoFormatRec formats[] = +{ + { 16, TrueColor }, + { 24, TrueColor }, + { 32, TrueColor }, +}; + +static XF86AttributeRec attributes[] = +{ + { 0, 0, 270, "_USER_WM_PORT_ATTRIBUTE_ROTATION" }, + { 0, 0, 1, "_USER_WM_PORT_ATTRIBUTE_HFLIP" }, + { 0, 0, 1, "_USER_WM_PORT_ATTRIBUTE_VFLIP" }, + { 0, -1, 1, "_USER_WM_PORT_ATTRIBUTE_PREEMPTION" }, + { 0, 0, OUTPUT_MODE_EXT_ONLY, "_USER_WM_PORT_ATTRIBUTE_OUTPUT" }, + { 0, 0, 1, "_USER_WM_PORT_ATTRIBUTE_SECURE" }, + { 0, 0, 1, "_USER_WM_PORT_ATTRIBUTE_CSC_RANGE" }, +}; + +typedef enum +{ + PAA_MIN, + PAA_ROTATION, + PAA_HFLIP, + PAA_VFLIP, + PAA_PREEMPTION, + PAA_OUTPUT, + PAA_SECURE, + PAA_CSC_RANGE, + PAA_MAX +} SECPortAttrAtom; + +static struct +{ + SECPortAttrAtom paa; + const char *name; + Atom atom; +} atoms[] = +{ + { PAA_ROTATION, "_USER_WM_PORT_ATTRIBUTE_ROTATION", None }, + { PAA_HFLIP, "_USER_WM_PORT_ATTRIBUTE_HFLIP", None }, + { PAA_VFLIP, "_USER_WM_PORT_ATTRIBUTE_VFLIP", None }, + { PAA_PREEMPTION, "_USER_WM_PORT_ATTRIBUTE_PREEMPTION", None }, + { PAA_OUTPUT, "_USER_WM_PORT_ATTRIBUTE_OUTPUT", None }, + { PAA_SECURE, "_USER_WM_PORT_ATTRIBUTE_SECURE", None }, + { PAA_CSC_RANGE, "_USER_WM_PORT_ATTRIBUTE_CSC_RANGE", None }, +}; + +enum +{ + ON_NONE, + ON_FB, + ON_WINDOW, + ON_PIXMAP +}; + +static char *drawing_type[4] = {"NONE", "FB", "WIN", "PIX"}; + +typedef struct _PutData +{ + unsigned int id; + int width; + int height; + xRectangle src; + xRectangle dst; + void *buf; + Bool sync; + RegionPtr clip_boxes; + void *data; + DrawablePtr pDraw; +} PutData; + +/* SEC port information structure */ +typedef struct +{ + CARD32 prev_time; + int index; + + /* attributes */ + int rotate; + int hflip; + int vflip; + int preemption; /* 1:high, 0:default, -1:low */ + Bool secure; + int csc_range; + + ScrnInfoPtr pScrn; + PutData d; + PutData old_d; + + /* draw inform */ + int drawing; + int hw_rotate; + + int in_width; + int in_height; + xRectangle in_crop; + SECVideoBuf *inbuf[INBUF_NUM]; + Bool inbuf_is_fb; + + /* converter */ + SECCvt *cvt; + + /* layer */ + SECLayer *layer; + int out_width; + int out_height; + xRectangle out_crop; + SECVideoBuf *outbuf[OUTBUF_NUM]; + int outbuf_cvting; + DrawablePtr pDamageDrawable[OUTBUF_NUM]; + + /* tvout */ + int usr_output; + int old_output; + int grab_tvout; + SECVideoTv *tv; + void *gem_list; + Bool skip_tvout; + Bool need_start_wb; + SECVideoBuf *wait_vbuf; + CARD32 tv_prev_time; + + /* count */ + unsigned int put_counts; + OsTimerPtr timer; + + Bool punched; + int stream_cnt; + struct xorg_list link; +} SECPortPriv, *SECPortPrivPtr; + +static RESTYPE event_drawable_type; + +typedef struct _SECVideoResource +{ + XID id; + RESTYPE type; + + SECPortPrivPtr pPort; + ScrnInfoPtr pScrn; +} SECVideoResource; + +typedef struct _SECVideoPortInfo +{ + ClientPtr client; + XvPortPtr pp; +} SECVideoPortInfo; + +static int (*ddPutImage) (ClientPtr, DrawablePtr, struct _XvPortRec *, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16, + XvImagePtr, unsigned char *, Bool, CARD16, CARD16); + +static void _secVideoSendReturnBufferMessage (SECPortPrivPtr pPort, SECVideoBuf *vbuf, unsigned int *keys); +static void SECVideoStop (ScrnInfoPtr pScrn, pointer data, Bool exit); +static void _secVideoCloseInBuffer (SECPortPrivPtr pPort); +static void _secVideoCloseOutBuffer (SECPortPrivPtr pPort, Bool close_layer); +static void _secVideoCloseConverter (SECPortPrivPtr pPort); +static Bool _secVideoSetOutputExternalProperty (DrawablePtr pDraw, Bool tvout); + +static int streaming_ports; +static int registered_handler; +static struct xorg_list layer_owners; + +static DevPrivateKeyRec video_port_key; +#define VideoPortKey (&video_port_key) +#define GetPortInfo(pDraw) ((SECVideoPortInfo*)dixLookupPrivate(&(pDraw)->devPrivates, VideoPortKey)) + +#define NUM_IMAGES (sizeof(images) / sizeof(images[0])) +#define NUM_FORMATS (sizeof(formats) / sizeof(formats[0])) +#define NUM_ATTRIBUTES (sizeof(attributes) / sizeof(attributes[0])) +#define NUM_ATOMS (sizeof(atoms) / sizeof(atoms[0])) + +#define ENSURE_AREA(off, lng, max) (lng = ((off + lng) > max ? (max - off) : lng)) + +static CARD32 +_countPrint (OsTimerPtr timer, CARD32 now, pointer arg) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr)arg; + + if (pPort->timer) + { + TimerFree (pPort->timer); + pPort->timer = NULL; + } + + ErrorF ("PutImage(%d) : %d fps. \n", pPort->index, pPort->put_counts); + + pPort->put_counts = 0; + + return 0; +} + +static void +_countFps (SECPortPrivPtr pPort) +{ + pPort->put_counts++; + + if (pPort->timer) + return; + + pPort->timer = TimerSet (NULL, 0, 1000, _countPrint, pPort); +} + +static SECVideoPortInfo* +_port_info (DrawablePtr pDraw) +{ + if (!pDraw) + return NULL; + + if (pDraw->type == DRAWABLE_WINDOW) + return GetPortInfo ((WindowPtr)pDraw); + else + return GetPortInfo ((PixmapPtr)pDraw); +} + +static PixmapPtr +_getPixmap (DrawablePtr pDraw) +{ + if (pDraw->type == DRAWABLE_WINDOW) + return pDraw->pScreen->GetWindowPixmap ((WindowPtr) pDraw); + else + return (PixmapPtr) pDraw; +} + +static XF86ImagePtr +_get_image_info (int id) +{ + int i; + + for (i = 0; i < NUM_IMAGES; i++) + if (images[i].id == id) + return &images[i]; + + return NULL; +} + +static Atom +_portAtom (SECPortAttrAtom paa) +{ + int i; + + XDBG_RETURN_VAL_IF_FAIL (paa > PAA_MIN && paa < PAA_MAX, None); + + for (i = 0; i < NUM_ATOMS; i++) + { + if (paa == atoms[i].paa) + { + if (atoms[i].atom == None) + atoms[i].atom = MakeAtom (atoms[i].name, + strlen (atoms[i].name), TRUE); + + return atoms[i].atom; + } + } + + XDBG_ERROR (MVDO, "Error: Unknown Port Attribute Name!\n"); + + return None; +} + +static void +_DestroyData (void *port, void *data) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr)port; + unsigned int handle = (unsigned int)data; + + secUtilFreeHandle (pPort->pScrn, handle); +} + +static Bool +_secVideoGrabTvout (SECPortPrivPtr pPort) +{ + SECVideoPrivPtr pVideo = SECPTR(pPort->pScrn)->pVideoPriv; + + if (pPort->grab_tvout) + return TRUE; + + /* other port already grabbed */ + if (pVideo->tvout_in_use) + { + XDBG_WARNING (MVDO, "*** pPort(%p) can't grab tvout. It's in use.\n", pPort); + return FALSE; + } + + if (pPort->tv) + { + XDBG_ERROR (MVDO, "*** wrong handle if you reach here. %p \n", pPort->tv); + return FALSE; + } + + pPort->grab_tvout = TRUE; + pVideo->tvout_in_use = TRUE; + + XDBG_TRACE (MVDO, "pPort(%p) grabs tvout.\n", pPort); + + return TRUE; +} + +static void +_secVideoUngrabTvout (SECPortPrivPtr pPort) +{ + if (pPort->tv) + { + secVideoTvDisconnect (pPort->tv); + pPort->tv = NULL; + } + + /* This port didn't grab tvout */ + if (!pPort->grab_tvout) + return; + + _secVideoSetOutputExternalProperty (pPort->d.pDraw, FALSE); + + if (pPort->need_start_wb) + { + SECWb *wb = secWbGet (); + if (wb) + { + secWbSetSecure (wb, pPort->secure); + secWbStart (wb); + } + pPort->need_start_wb = FALSE; + } + + XDBG_TRACE (MVDO, "pPort(%p) ungrabs tvout.\n", pPort); + + pPort->grab_tvout = FALSE; + + if (pPort->pScrn) + { + SECVideoPrivPtr pVideo; + pVideo = SECPTR(pPort->pScrn)->pVideoPriv; + pVideo->tvout_in_use = FALSE; + } + pPort->wait_vbuf = NULL; +} + +static int +_secVideoGetTvoutMode (SECPortPrivPtr pPort) +{ + SECModePtr pSecMode = (SECModePtr) SECPTR (pPort->pScrn)->pSecMode; + SECVideoPrivPtr pVideo = SECPTR(pPort->pScrn)->pVideoPriv; + SECDisplaySetMode disp_mode = secDisplayGetDispSetMode (pPort->pScrn); + int output = OUTPUT_LCD; + + if (disp_mode == DISPLAY_SET_MODE_CLONE) + { + if (pPort->preemption > -1) + { + if (pVideo->video_output > 0 && streaming_ports == 1) + { + int video_output = pVideo->video_output - 1; + + if (video_output == OUTPUT_MODE_DEFAULT) + output = OUTPUT_LCD; + else if (video_output == OUTPUT_MODE_TVOUT) + output = OUTPUT_LCD|OUTPUT_EXT|OUTPUT_FULL; + else + output = OUTPUT_EXT|OUTPUT_FULL; + } + else if (streaming_ports == 1) + { + output = pPort->usr_output; + if (!(output & OUTPUT_FULL)) + output &= ~(OUTPUT_EXT); + } + else if (streaming_ports > 1) + output = OUTPUT_LCD; + else + XDBG_NEVER_GET_HERE (MVDO); + } + else + output = OUTPUT_LCD; + } + else if (disp_mode == DISPLAY_SET_MODE_EXT) + { + if (pPort->drawing == ON_PIXMAP) + output = OUTPUT_LCD; + else + { + xf86CrtcPtr pCrtc = secCrtcGetAtGeometry (pPort->pScrn, + (int)pPort->d.pDraw->x, (int)pPort->d.pDraw->y, + (int)pPort->d.pDraw->width, (int)pPort->d.pDraw->height); + int c = secCrtcGetConnectType (pCrtc); + + if (c == DRM_MODE_CONNECTOR_LVDS || c == DRM_MODE_CONNECTOR_Unknown) + output = OUTPUT_LCD; + else if (c == DRM_MODE_CONNECTOR_HDMIA || c == DRM_MODE_CONNECTOR_HDMIB) + output = OUTPUT_EXT; + else if (c == DRM_MODE_CONNECTOR_VIRTUAL) + output = OUTPUT_EXT; + else + XDBG_NEVER_GET_HERE (MVDO); + } + } + else /* DISPLAY_SET_MODE_OFF */ + { + output = OUTPUT_LCD; + } + + if (pPort->drawing == ON_PIXMAP) + output = OUTPUT_LCD; + + XDBG_DEBUG (MVDO, "drawing(%d) disp_mode(%d) preemption(%d) streaming_ports(%d) conn_mode(%d) usr_output(%d) video_output(%d) output(%x) skip(%d)\n", + pPort->drawing, disp_mode, pPort->preemption, streaming_ports, pSecMode->conn_mode, + pPort->usr_output, pVideo->video_output, output, pPort->skip_tvout); + + return output; +} + +static int +_secVideodrawingOn (SECPortPrivPtr pPort) +{ + if (pPort->old_d.pDraw != pPort->d.pDraw) + pPort->drawing = ON_NONE; + + if (pPort->drawing != ON_NONE) + return pPort->drawing; + + if (pPort->d.pDraw->type == DRAWABLE_PIXMAP) + return ON_PIXMAP; + else if (pPort->d.pDraw->type == DRAWABLE_WINDOW) + { + PropertyPtr prop = secUtilGetWindowProperty ((WindowPtr)pPort->d.pDraw, + "XV_ON_DRAWABLE"); + if (prop && *(int*)prop->data > 0) + return ON_WINDOW; + } + + return ON_FB; +} + +static void +_secVideoGetRotation (SECPortPrivPtr pPort, int *hw_rotate) +{ + SECVideoPrivPtr pVideo = SECPTR(pPort->pScrn)->pVideoPriv; + + /* + * 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) + * | | + * ---------- + */ + + if (pPort->drawing == ON_FB) + *hw_rotate = (pPort->rotate + pVideo->screen_rotate_degree) % 360; + else + *hw_rotate = pPort->rotate % 360; +} + +static int +_secVideoGetKeys (SECPortPrivPtr pPort, unsigned int *keys, unsigned int *type) +{ + XV_DATA_PTR data = (XV_DATA_PTR) pPort->d.buf; + int valid = XV_VALIDATE_DATA (data); + + if (valid == XV_HEADER_ERROR) + { + XDBG_ERROR (MVDO, "XV_HEADER_ERROR\n"); + return valid; + } + else if (valid == XV_VERSION_MISMATCH) + { + XDBG_ERROR (MVDO, "XV_VERSION_MISMATCH\n"); + return valid; + } + + if (keys) + { + keys[0] = data->YBuf; + keys[1] = data->CbBuf; + keys[2] = data->CrBuf; + } + + if (type) + *type = data->BufType; + + return 0; +} + +static void +_secVideoFreeInbuf (SECVideoBuf *vbuf, void *data) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr)data; + int i; + + XDBG_RETURN_IF_FAIL (pPort->drawing != ON_NONE); + + for (i = 0; i < INBUF_NUM; i++) + if (pPort->inbuf[i] == vbuf) + { + _secVideoSendReturnBufferMessage (pPort, vbuf, NULL); + pPort->inbuf[i] = NULL; + return; + } + + XDBG_NEVER_GET_HERE (MVDO); +} + +static void +_secVideoFreeOutbuf (SECVideoBuf *vbuf, void *data) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr)data; + int i; + + XDBG_RETURN_IF_FAIL (pPort->drawing != ON_NONE); + + for (i = 0; i < OUTBUF_NUM; i++) + if (pPort->outbuf[i] == vbuf) + { + pPort->pDamageDrawable[i] = NULL; + pPort->outbuf[i] = NULL; + return; + } + + XDBG_NEVER_GET_HERE (MVDO); +} + +static SECLayer* +_secVideoCreateLayer (SECPortPrivPtr pPort) +{ + ScrnInfoPtr pScrn = pPort->pScrn; + SECVideoPrivPtr pVideo = SECPTR(pScrn)->pVideoPriv; + DrawablePtr pDraw = pPort->d.pDraw; + xf86CrtcConfigPtr pCrtcConfig; + xf86OutputPtr pOutput = NULL; + int i; + xf86CrtcPtr pCrtc; + SECLayer *layer; + Bool full = TRUE; + xRectangle src, dst; + + pCrtc = secCrtcGetAtGeometry (pScrn, pDraw->x, pDraw->y, pDraw->width, pDraw->height); + XDBG_RETURN_VAL_IF_FAIL (pCrtc != NULL, NULL); + + pCrtcConfig = XF86_CRTC_CONFIG_PTR (pCrtc->scrn); + XDBG_RETURN_VAL_IF_FAIL (pCrtcConfig != NULL, NULL); + + for (i = 0; i < pCrtcConfig->num_output; i++) + { + xf86OutputPtr pTemp = pCrtcConfig->output[i]; + if (pTemp->crtc == pCrtc) + { + pOutput = pTemp; + break; + } + } + XDBG_RETURN_VAL_IF_FAIL (pOutput != NULL, NULL); + + SECOutputPrivPtr pOutputPriv = pOutput->driver_private; + SECLayerOutput output = LAYER_OUTPUT_LCD; + + if (pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_LVDS || + pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_Unknown) + { + output = LAYER_OUTPUT_LCD; + } + else if (pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_HDMIA || + pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_HDMIB || + pOutputPriv->mode_output->connector_type == DRM_MODE_CONNECTOR_VIRTUAL) + { + output = LAYER_OUTPUT_EXT; + } + else + XDBG_NEVER_GET_HERE (MVDO); + + if (!secLayerFind (output, LAYER_LOWER2) || !secLayerFind (output, LAYER_LOWER1)) + full = FALSE; + + if (full) + return NULL; + + layer = secLayerCreate (pScrn, output, LAYER_NONE); + XDBG_RETURN_VAL_IF_FAIL (layer != NULL, NULL); + + src = dst = pPort->out_crop; + dst.x = pPort->d.dst.x; + dst.y = pPort->d.dst.y; + + secLayerSetRect (layer, &src, &dst); + secLayerEnableVBlank (layer, TRUE); + + xorg_list_add (&pPort->link, &layer_owners); + + secLayerSetOffset (layer, pVideo->video_offset_x, pVideo->video_offset_y); + + return layer; +} + +static SECVideoBuf* +_secVideoGetInbufZeroCopy (SECPortPrivPtr pPort, unsigned int *names, unsigned int buf_type) +{ + SECVideoBuf *inbuf = NULL; + int i, empty; + tbm_bo_handle bo_handle; + + for (empty = 0; empty < INBUF_NUM; empty++) + if (!pPort->inbuf[empty]) + break; + + if (empty == INBUF_NUM) + { + XDBG_ERROR (MVDO, "now all inbufs in use!\n"); + return NULL; + } + + /* make sure both widths are same.*/ + XDBG_RETURN_VAL_IF_FAIL (pPort->d.width == pPort->in_width, NULL); + XDBG_RETURN_VAL_IF_FAIL (pPort->d.height == pPort->in_height, NULL); + + inbuf = secUtilCreateVideoBuffer (pPort->pScrn, pPort->d.id, + pPort->in_width, pPort->in_height, + pPort->secure); + XDBG_RETURN_VAL_IF_FAIL (inbuf != NULL, NULL); + + inbuf->crop = pPort->in_crop; + + for (i = 0; i < PLANAR_CNT; i++) + { + if (names[i] > 0) + { + inbuf->keys[i] = names[i]; + + if (buf_type == XV_BUF_TYPE_LEGACY) + { + void *data = secUtilListGetData (pPort->gem_list, (void*)names[i]); + if (!data) + { + secUtilConvertPhyaddress (pPort->pScrn, names[i], inbuf->lengths[i], &inbuf->handles[i]); + + pPort->gem_list = secUtilListAdd (pPort->gem_list, (void*)names[i], + (void*)inbuf->handles[i]); + } + else + inbuf->handles[i] = (unsigned int)data; + + XDBG_DEBUG (MVDO, "%d, %p => %d \n", i, (void*)names[i], inbuf->handles[i]); + } + else + { + XDBG_GOTO_IF_FAIL (inbuf->lengths[i] > 0, fail_dma); + XDBG_GOTO_IF_FAIL (inbuf->bo[i] == NULL, fail_dma); + + inbuf->bo[i] = tbm_bo_import (SECPTR (pPort->pScrn)->tbm_bufmgr, inbuf->keys[i]); + XDBG_GOTO_IF_FAIL (inbuf->bo[i] != NULL, fail_dma); + + bo_handle = tbm_bo_get_handle(inbuf->bo[i], TBM_DEVICE_DEFAULT); + inbuf->handles[i] = bo_handle.u32; + XDBG_GOTO_IF_FAIL (inbuf->handles[i] > 0, fail_dma); + + XDBG_DEBUG (MVDO, "%d, key(%d) => bo(%p) handle(%d)\n", + i, inbuf->keys[i], inbuf->bo[i], inbuf->handles[i]); + } + } + } + + /* not increase ref_cnt to free inbuf when converting/showing is done. */ + pPort->inbuf[empty] = inbuf; + + secUtilAddFreeVideoBufferFunc (inbuf, _secVideoFreeInbuf, pPort); + + return inbuf; + +fail_dma: + if (inbuf) + secUtilFreeVideoBuffer (inbuf); + + return NULL; +} + +static SECVideoBuf* +_secVideoGetInbufRAW (SECPortPrivPtr pPort) +{ + SECVideoBuf *inbuf = NULL; + void *vir_addr = NULL; + int i; + tbm_bo_handle bo_handle; + + /* we can't access virtual pointer. */ + XDBG_RETURN_VAL_IF_FAIL (pPort->secure == FALSE, NULL); + + for (i = 0; i < INBUF_NUM; i++) + { + if (pPort->inbuf[i]) + continue; + + pPort->inbuf[i] = secUtilAllocVideoBuffer (pPort->pScrn, pPort->d.id, + pPort->in_width, pPort->in_height, + FALSE, FALSE, pPort->secure); + XDBG_GOTO_IF_FAIL (pPort->inbuf[i] != NULL, fail_raw_alloc); + } + + for (i = 0; i < INBUF_NUM; i++) + { + XDBG_DEBUG (MVDO, "? inbuf(%d,%p) converting(%d) showing(%d)\n", i, + pPort->inbuf[i], VBUF_IS_CONVERTING (pPort->inbuf[i]), pPort->inbuf[i]->showing); + + if (pPort->inbuf[i] && !VBUF_IS_CONVERTING (pPort->inbuf[i]) && !pPort->inbuf[i]->showing) + { + /* increase ref_cnt to keep inbuf until stream_off. */ + inbuf = secUtilVideoBufferRef (pPort->inbuf[i]); + break; + } + } + + if (!inbuf) + { + XDBG_ERROR (MVDO, "now all inbufs in use!\n"); + return NULL; + } + + inbuf->crop = pPort->in_crop; + + bo_handle = tbm_bo_map (inbuf->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE); + vir_addr = bo_handle.ptr; + XDBG_RETURN_VAL_IF_FAIL (vir_addr != NULL, NULL); + XDBG_RETURN_VAL_IF_FAIL (inbuf->size > 0, NULL); + + if (pPort->d.width != pPort->in_width || pPort->d.height != pPort->in_height) + { + XF86ImagePtr image_info = _get_image_info (pPort->d.id); + XDBG_RETURN_VAL_IF_FAIL (image_info != NULL, NULL); + int pitches[3] = {0,}; + int offsets[3] = {0,}; + int lengths[3] = {0,}; + int width, height; + + width = pPort->d.width; + height = pPort->d.height; + + secVideoQueryImageAttrs (pPort->pScrn, pPort->d.id, + &width, &height, + pitches, offsets, lengths); + + secUtilCopyImage (width, height, + pPort->d.buf, width, height, + pitches, offsets, lengths, + vir_addr, inbuf->width, inbuf->height, + inbuf->pitches, inbuf->offsets, inbuf->lengths, + image_info->num_planes, + image_info->horz_u_period, + image_info->vert_u_period); + } + else + memcpy (vir_addr, pPort->d.buf, inbuf->size); + + tbm_bo_unmap (inbuf->bo[0]); + secUtilCacheFlush (pPort->pScrn); + return inbuf; + +fail_raw_alloc: + _secVideoCloseInBuffer (pPort); + return NULL; +} + +static SECVideoBuf* +_secVideoGetInbuf (SECPortPrivPtr pPort) +{ + unsigned int keys[PLANAR_CNT] = {0,}; + unsigned int buf_type = 0; + SECVideoBuf *inbuf = NULL; + SECPtr pSec = SECPTR (pPort->pScrn); + + if (IS_ZEROCOPY (pPort->d.id)) + { + if (_secVideoGetKeys (pPort, keys, &buf_type)) + return NULL; + + XDBG_RETURN_VAL_IF_FAIL (keys[0] > 0, NULL); + + if (pPort->d.id == FOURCC_SN12 || pPort->d.id == FOURCC_ST12) + XDBG_RETURN_VAL_IF_FAIL (keys[1] > 0, NULL); + + inbuf = _secVideoGetInbufZeroCopy (pPort, keys, buf_type); + + XDBG_RETURN_VAL_IF_FAIL (inbuf != NULL, NULL); + XDBG_TRACE (MVDO, "keys: %d,%d,%d. stamp(%ld)\n", keys[0], keys[1], keys[2], inbuf->stamp); + } + else + inbuf = _secVideoGetInbufRAW (pPort); + + XDBG_RETURN_VAL_IF_FAIL (inbuf != NULL, NULL); + + if ((pSec->dump_mode & XBERC_DUMP_MODE_IA) && pSec->dump_info) + { + char file[128]; + static int i; + snprintf (file, sizeof(file), "xvin_%c%c%c%c_%dx%d_p%d_%03d.%s", + FOURCC_STR(inbuf->id), + inbuf->width, inbuf->height, pPort->index, i++, + IS_RGB(inbuf->id)?"bmp":"yuv"); + secUtilDoDumpVBuf (pSec->dump_info, inbuf, file); + } + + if (pSec->xvperf_mode & XBERC_XVPERF_MODE_IA) + inbuf->put_time = GetTimeInMillis (); + + return inbuf; +} + +static SECVideoBuf* +_secVideoGetOutbufDrawable (SECPortPrivPtr pPort) +{ + ScrnInfoPtr pScrn = pPort->pScrn; + DrawablePtr pDraw = pPort->d.pDraw; + PixmapPtr pPixmap = (PixmapPtr)_getPixmap (pDraw); + SECPixmapPriv *privPixmap = exaGetPixmapDriverPrivate (pPixmap); + Bool need_finish = FALSE; + SECVideoBuf *outbuf = NULL; + int empty; + tbm_bo_handle bo_handle; + + for (empty = 0; empty < OUTBUF_NUM; empty++) + if (!pPort->outbuf[empty]) + break; + + if (empty == OUTBUF_NUM) + { + XDBG_ERROR (MVDO, "now all outbufs in use!\n"); + return NULL; + } + + if ((pDraw->width % 16) && (pPixmap->usage_hint != CREATE_PIXMAP_USAGE_XVIDEO)) + { + ScreenPtr pScreen = pScrn->pScreen; + SECFbBoDataPtr bo_data = NULL; + + pPixmap->usage_hint = CREATE_PIXMAP_USAGE_XVIDEO; + pScreen->ModifyPixmapHeader (pPixmap, + pDraw->width, pDraw->height, + pDraw->depth, + pDraw->bitsPerPixel, + pPixmap->devKind, 0); + XDBG_RETURN_VAL_IF_FAIL (privPixmap->bo != NULL, NULL); + + tbm_bo_get_user_data(privPixmap->bo, TBM_BO_DATA_FB, (void**)&bo_data); + XDBG_RETURN_VAL_IF_FAIL (bo_data != NULL, NULL); + XDBG_RETURN_VAL_IF_FAIL ((bo_data->pos.x2 - bo_data->pos.x1) == pPort->out_width, NULL); + XDBG_RETURN_VAL_IF_FAIL ((bo_data->pos.y2 - bo_data->pos.y1) == pPort->out_height, NULL); + } + + if (!privPixmap->bo) + { + need_finish = TRUE; + secExaPrepareAccess (pPixmap, EXA_PREPARE_DEST); + XDBG_GOTO_IF_FAIL (privPixmap->bo != NULL, fail_drawable); + } + + outbuf = secUtilCreateVideoBuffer (pScrn, FOURCC_RGB32, + pPort->out_width, + pPort->out_height, + pPort->secure); + XDBG_GOTO_IF_FAIL (outbuf != NULL, fail_drawable); + outbuf->crop = pPort->out_crop; + + XDBG_TRACE (MVDO, "outbuf(%p)(%dx%d) created. [%s]\n", + outbuf, pPort->out_width, pPort->out_height, + (pPort->drawing==ON_PIXMAP)?"PIX":"WIN"); + + outbuf->bo[0] = tbm_bo_ref (privPixmap->bo); + + bo_handle = tbm_bo_get_handle (outbuf->bo[0], TBM_DEVICE_DEFAULT); + outbuf->handles[0] = bo_handle.u32; + XDBG_GOTO_IF_FAIL (outbuf->handles[0] > 0, fail_drawable); + + if (need_finish) + secExaFinishAccess (pPixmap, EXA_PREPARE_DEST); + + pPort->pDamageDrawable[empty] = pPort->d.pDraw; + +// RegionTranslate (pPort->d.clip_boxes, -pPort->d.dst.x, -pPort->d.dst.y); + + /* not increase ref_cnt to free outbuf when converting/showing is done. */ + pPort->outbuf[empty] = outbuf; + + secUtilAddFreeVideoBufferFunc (outbuf, _secVideoFreeOutbuf, pPort); + + return outbuf; + +fail_drawable: + if (outbuf) + secUtilFreeVideoBuffer (outbuf); + + return NULL; +} + +static SECVideoBuf* +_secVideoGetOutbufFB (SECPortPrivPtr pPort) +{ + ScrnInfoPtr pScrn = pPort->pScrn; + SECVideoBuf *outbuf = NULL; + int i, next; + + if (!pPort->layer) + { + pPort->layer = _secVideoCreateLayer (pPort); + XDBG_RETURN_VAL_IF_FAIL (pPort->layer != NULL, NULL); + } + else + { + SECVideoBuf *vbuf = secLayerGetBuffer (pPort->layer); + if (vbuf && (vbuf->width == pPort->out_width && vbuf->height == pPort->out_height)) + { + xRectangle src = {0,}, dst = {0,}; + + secLayerGetRect (pPort->layer, &src, &dst); + + /* CHECK */ + if (pPort->d.dst.x != dst.x || pPort->d.dst.y != dst.y) + { + /* x,y can be changed when window is moved. */ + dst.x = pPort->d.dst.x; + dst.y = pPort->d.dst.y; + secLayerSetRect (pPort->layer, &src, &dst); + } + } + } + + for (i = 0; i < OUTBUF_NUM; i++) + { + SECPtr pSec = SECPTR (pPort->pScrn); + + if (pPort->outbuf[i]) + continue; + + pPort->outbuf[i] = secUtilAllocVideoBuffer (pScrn, FOURCC_RGB32, + pPort->out_width, pPort->out_height, + (pSec->scanout)?TRUE:FALSE, + FALSE, pPort->secure); + XDBG_GOTO_IF_FAIL (pPort->outbuf[i] != NULL, fail_fb); + pPort->outbuf[i]->crop = pPort->out_crop; + + XDBG_TRACE (MVDO, "out bo(%p, %d, %dx%d) created. [FB]\n", + pPort->outbuf[i]->bo[0], pPort->outbuf[i]->handles[0], + pPort->out_width, pPort->out_height); + } + + next = ++pPort->outbuf_cvting; + if (next >= OUTBUF_NUM) + next = 0; + + for (i = 0; i < OUTBUF_NUM; i++) + { + XDBG_DEBUG (MVDO, "? outbuf(%d,%p) converting(%d)\n", next, + pPort->outbuf[next], VBUF_IS_CONVERTING (pPort->outbuf[next])); + + if (pPort->outbuf[next] && !VBUF_IS_CONVERTING (pPort->outbuf[next])) + { + /* increase ref_cnt to keep outbuf until stream_off. */ + outbuf = secUtilVideoBufferRef (pPort->outbuf[next]); + break; + } + + next++; + if (next >= OUTBUF_NUM) + next = 0; + } + + if (!outbuf) + { + XDBG_ERROR (MVDO, "now all outbufs in use!\n"); + return NULL; + } + + pPort->outbuf_cvting = next; + + return outbuf; + +fail_fb: + _secVideoCloseConverter (pPort); + _secVideoCloseOutBuffer (pPort, TRUE); + + return NULL; +} + +static SECVideoBuf* +_secVideoGetOutbuf (SECPortPrivPtr pPort) +{ + if (pPort->drawing == ON_PIXMAP || pPort->drawing == ON_WINDOW) + return _secVideoGetOutbufDrawable (pPort); + else /* ON_FB */ + return _secVideoGetOutbufFB (pPort); +} + +static void +_secVideoCloseInBuffer (SECPortPrivPtr pPort) +{ + int i; + + _secVideoUngrabTvout (pPort); + + if (pPort->gem_list) + { + secUtilListDestroyData (pPort->gem_list, _DestroyData, pPort); + secUtilListDestroy (pPort->gem_list); + pPort->gem_list = NULL; + } + + if (!IS_ZEROCOPY (pPort->d.id)) + for (i = 0; i < INBUF_NUM; i++) + { + if (pPort->inbuf[i]) + { + secUtilVideoBufferUnref (pPort->inbuf[i]); + pPort->inbuf[i] = NULL; + } + } + + pPort->in_width = 0; + pPort->in_height = 0; + memset (&pPort->in_crop, 0, sizeof (xRectangle)); + + XDBG_DEBUG (MVDO, "done\n"); +} + +static void +_secVideoCloseOutBuffer (SECPortPrivPtr pPort, Bool close_layer) +{ + int i; + + /* before close outbuf, layer/cvt should be finished. */ + if (close_layer && pPort->layer) + { + secLayerUnref (pPort->layer); + pPort->layer = NULL; + xorg_list_del (&pPort->link); + } + + for (i = 0; i < OUTBUF_NUM; i++) + { + if (pPort->outbuf[i]) + { + if (pPort->drawing == ON_PIXMAP || pPort->drawing == ON_WINDOW) + XDBG_NEVER_GET_HERE (MVDO); + + secUtilVideoBufferUnref (pPort->outbuf[i]); + pPort->outbuf[i] = NULL; + } + } + + pPort->out_width = 0; + pPort->out_height = 0; + memset (&pPort->out_crop, 0, sizeof (xRectangle)); + pPort->outbuf_cvting = -1; + + XDBG_DEBUG (MVDO, "done\n"); +} + +static void +_secVideoSendReturnBufferMessage (SECPortPrivPtr pPort, SECVideoBuf *vbuf, unsigned int *keys) +{ + static Atom return_atom = None; + SECVideoPortInfo *info = _port_info (pPort->d.pDraw); + + if (return_atom == None) + return_atom = MakeAtom ("XV_RETURN_BUFFER", + strlen ("XV_RETURN_BUFFER"), TRUE); + + if (!info) + return; + + xEvent event; + + CLEAR (event); + event.u.u.type = ClientMessage; + event.u.u.detail = 32; + event.u.clientMessage.u.l.type = return_atom; + if (vbuf) + { + event.u.clientMessage.u.l.longs0 = (INT32)vbuf->keys[0]; + event.u.clientMessage.u.l.longs1 = (INT32)vbuf->keys[1]; + event.u.clientMessage.u.l.longs2 = (INT32)vbuf->keys[2]; + + XDBG_TRACE (MVDO, "%ld: %d,%d,%d out. diff(%ld)\n", vbuf->stamp, + vbuf->keys[0], vbuf->keys[1], vbuf->keys[2], GetTimeInMillis()-vbuf->stamp); + } + else if (keys) + { + event.u.clientMessage.u.l.longs0 = (INT32)keys[0]; + event.u.clientMessage.u.l.longs1 = (INT32)keys[1]; + event.u.clientMessage.u.l.longs2 = (INT32)keys[2]; + + XDBG_TRACE (MVDO, "%d,%d,%d out. \n", + keys[0], keys[1], keys[2]); + } + else + XDBG_NEVER_GET_HERE (MVDO); + + WriteEventsToClient(info->client, 1, (xEventPtr) &event); + + SECPtr pSec = SECPTR (pPort->pScrn); + if (pSec->xvperf_mode & XBERC_XVPERF_MODE_IA) + { + if (vbuf) + { + CARD32 cur, sub; + cur = GetTimeInMillis (); + sub = cur - vbuf->put_time; + ErrorF ("vbuf(%d,%d,%d) retbuf : %6ld ms\n", + vbuf->keys[0], vbuf->keys[1], vbuf->keys[2], sub); + } + else if (keys) + ErrorF ("vbuf(%d,%d,%d) retbuf : 0 ms\n", + keys[0], keys[1], keys[2]); + else + XDBG_NEVER_GET_HERE (MVDO); + } +} + +static void +_secVideoCvtCallback (SECCvt *cvt, + SECVideoBuf *src, + SECVideoBuf *dst, + void *cvt_data, + Bool error) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr)cvt_data; + DrawablePtr pDamageDrawable = NULL; + int out_index; + + XDBG_RETURN_IF_FAIL (pPort != NULL); + XDBG_RETURN_IF_FAIL (cvt != NULL); + XDBG_RETURN_IF_FAIL (VBUF_IS_VALID (src)); + XDBG_RETURN_IF_FAIL (VBUF_IS_VALID (dst)); + XDBG_DEBUG (MVDO, "++++++++++++++++++++++++ \n"); + XDBG_DEBUG (MVDO, "cvt(%p) src(%p) dst(%p)\n", cvt, src, dst); + + for (out_index = 0; out_index < OUTBUF_NUM; out_index++) + if (pPort->outbuf[out_index] == dst) + break; + XDBG_RETURN_IF_FAIL (out_index < OUTBUF_NUM); + + if (pPort->drawing == ON_PIXMAP || pPort->drawing == ON_WINDOW) + pDamageDrawable = pPort->pDamageDrawable[out_index]; + else + pDamageDrawable = pPort->d.pDraw; + + XDBG_RETURN_IF_FAIL (pDamageDrawable != NULL); + + if (error) + { + DamageDamageRegion (pDamageDrawable, pPort->d.clip_boxes); + return; + } + + SECPtr pSec = SECPTR (pPort->pScrn); + if ((pSec->dump_mode & XBERC_DUMP_MODE_IA) && pSec->dump_info) + { + char file[128]; + static int i; + snprintf (file, sizeof(file), "xvout_p%d_%03d.bmp", pPort->index, i++); + secUtilDoDumpVBuf (pSec->dump_info, dst, file); + } + + if (pPort->drawing == ON_PIXMAP || pPort->drawing == ON_WINDOW) + { + DamageDamageRegion (pDamageDrawable, pPort->d.clip_boxes); + } + else if (pPort->layer) + { + SECVideoBuf *vbuf = secLayerGetBuffer (pPort->layer); + Bool reset_layer = FALSE; + xRectangle src_rect, dst_rect; + + if (vbuf) + if (vbuf->width != pPort->out_width || vbuf->height != pPort->out_height) + reset_layer = TRUE; + + secLayerGetRect (pPort->layer, &src_rect, &dst_rect); + if (memcmp (&src_rect, &pPort->out_crop, sizeof(xRectangle)) || + dst_rect.x != pPort->d.dst.x || + dst_rect.y != pPort->d.dst.y || + dst_rect.width != pPort->out_crop.width || + dst_rect.height != pPort->out_crop.height) + reset_layer = TRUE; + + if (reset_layer) + { + secLayerFreezeUpdate (pPort->layer, TRUE); + + src_rect = pPort->out_crop; + dst_rect.x = pPort->d.dst.x; + dst_rect.y = pPort->d.dst.y; + dst_rect.width = pPort->out_crop.width; + dst_rect.height = pPort->out_crop.height; + + secLayerSetRect (pPort->layer, &src_rect, &dst_rect); + secLayerFreezeUpdate (pPort->layer, FALSE); + secLayerSetBuffer (pPort->layer, dst); + } + else + secLayerSetBuffer (pPort->layer, dst); + + if (!secLayerIsVisible (pPort->layer)) + secLayerShow (pPort->layer); + } + + XDBG_DEBUG (MVDO, "++++++++++++++++++++++++.. \n"); +} + +static void +_secVideoTvoutCvtCallback (SECCvt *cvt, + SECVideoBuf *src, + SECVideoBuf *dst, + void *cvt_data, + Bool error) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr)cvt_data; + + XDBG_RETURN_IF_FAIL (pPort != NULL); + XDBG_RETURN_IF_FAIL (cvt != NULL); + XDBG_RETURN_IF_FAIL (VBUF_IS_VALID (src)); + XDBG_RETURN_IF_FAIL (VBUF_IS_VALID (dst)); + + XDBG_DEBUG (MVDO, "######################## \n"); + XDBG_DEBUG (MVDO, "cvt(%p) src(%p) dst(%p)\n", cvt, src, dst); + + if (pPort->wait_vbuf != src) + XDBG_WARNING (MVDO, "wait_vbuf(%p) != src(%p). \n", + pPort->wait_vbuf, src); + + pPort->wait_vbuf = NULL; + + XDBG_DEBUG (MVDO, "########################.. \n"); +} + +static void +_secVideoLayerNotifyFunc (SECLayer *layer, int type, void *type_data, void *data) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr)data; + SECVideoBuf *vbuf = (SECVideoBuf*)type_data; + + if (type != LAYER_VBLANK) + return; + + XDBG_RETURN_IF_FAIL (pPort != NULL); + XDBG_RETURN_IF_FAIL (VBUF_IS_VALID (vbuf)); + + if (pPort->wait_vbuf != vbuf) + XDBG_WARNING (MVDO, "wait_vbuf(%p) != vbuf(%p). \n", + pPort->wait_vbuf, vbuf); + + XDBG_DEBUG (MVBUF, "now_showing(%p). \n", vbuf); + + pPort->wait_vbuf = NULL; +} + +static void +_secVideoEnsureConverter (SECPortPrivPtr pPort) +{ + if (pPort->cvt) + return; + + pPort->cvt = secCvtCreate (pPort->pScrn, CVT_OP_M2M); + XDBG_RETURN_IF_FAIL (pPort->cvt != NULL); + + secCvtAddCallback (pPort->cvt, _secVideoCvtCallback, pPort); +} + +static void +_secVideoCloseConverter (SECPortPrivPtr pPort) +{ + if (pPort->cvt) + { + secCvtDestroy (pPort->cvt); + pPort->cvt = NULL; + } + + XDBG_TRACE (MVDO, "done. \n"); +} + +static void +_secVideoStreamOff (SECPortPrivPtr pPort) +{ + _secVideoCloseConverter (pPort); + _secVideoCloseInBuffer (pPort); + _secVideoCloseOutBuffer (pPort, TRUE); + + SECWb *wb = secWbGet (); + if (wb) + { + if (pPort->need_start_wb) + { + secWbSetSecure (wb, FALSE); + secWbStart (wb); + pPort->need_start_wb = FALSE; + } + else + secWbSetSecure (wb, FALSE); + } + + if (pPort->d.clip_boxes) + { + RegionDestroy (pPort->d.clip_boxes); + pPort->d.clip_boxes = NULL; + } + + memset (&pPort->old_d, 0, sizeof (PutData)); + memset (&pPort->d, 0, sizeof (PutData)); + + pPort->need_start_wb = FALSE; + pPort->skip_tvout = FALSE; + pPort->usr_output = OUTPUT_LCD|OUTPUT_EXT; + pPort->outbuf_cvting = -1; + pPort->drawing = 0; + pPort->tv_prev_time = 0; + pPort->secure = FALSE; + pPort->csc_range = 0; + pPort->inbuf_is_fb = FALSE; + + if (pPort->stream_cnt > 0) + { + pPort->stream_cnt = 0; + XDBG_SECURE (MVDO, "pPort(%d) stream off. \n", pPort->index); + + if (pPort->preemption > -1) + streaming_ports--; + + XDBG_WARNING_IF_FAIL (streaming_ports >= 0); + } + + XDBG_TRACE (MVDO, "done. \n"); +} + +static Bool +_secVideoCalculateSize (SECPortPrivPtr pPort) +{ + SECCvtProp src_prop = {0,}, dst_prop = {0,}; + + src_prop.id = pPort->d.id; + src_prop.width = pPort->d.width; + src_prop.height = pPort->d.height; + src_prop.crop = pPort->d.src; + + dst_prop.id = FOURCC_RGB32; + if (pPort->drawing == ON_PIXMAP || pPort->drawing == ON_WINDOW) + { + dst_prop.width = pPort->d.pDraw->width; + dst_prop.height = pPort->d.pDraw->height; + dst_prop.crop = pPort->d.dst; + dst_prop.crop.x -= pPort->d.pDraw->x; + dst_prop.crop.y -= pPort->d.pDraw->y; + } + else + { + dst_prop.width = pPort->d.dst.width; + dst_prop.height = pPort->d.dst.height; + dst_prop.crop = pPort->d.dst; + dst_prop.crop.x = 0; + dst_prop.crop.y = 0; + } + + XDBG_DEBUG (MVDO, "(%dx%d : %d,%d %dx%d) => (%dx%d : %d,%d %dx%d)\n", + src_prop.width, src_prop.height, + src_prop.crop.x, src_prop.crop.y, src_prop.crop.width, src_prop.crop.height, + dst_prop.width, dst_prop.height, + dst_prop.crop.x, dst_prop.crop.y, dst_prop.crop.width, dst_prop.crop.height); + + if (!secCvtEnsureSize (&src_prop, &dst_prop)) + return FALSE; + + XDBG_DEBUG (MVDO, "(%dx%d : %d,%d %dx%d) => (%dx%d : %d,%d %dx%d)\n", + src_prop.width, src_prop.height, + src_prop.crop.x, src_prop.crop.y, src_prop.crop.width, src_prop.crop.height, + dst_prop.width, dst_prop.height, + dst_prop.crop.x, dst_prop.crop.y, dst_prop.crop.width, dst_prop.crop.height); + + XDBG_RETURN_VAL_IF_FAIL (src_prop.width > 0, FALSE); + XDBG_RETURN_VAL_IF_FAIL (src_prop.height > 0, FALSE); + XDBG_RETURN_VAL_IF_FAIL (src_prop.crop.width > 0, FALSE); + XDBG_RETURN_VAL_IF_FAIL (src_prop.crop.height > 0, FALSE); + XDBG_RETURN_VAL_IF_FAIL (dst_prop.width > 0, FALSE); + XDBG_RETURN_VAL_IF_FAIL (dst_prop.height > 0, FALSE); + XDBG_RETURN_VAL_IF_FAIL (dst_prop.crop.width > 0, FALSE); + XDBG_RETURN_VAL_IF_FAIL (dst_prop.crop.height > 0, FALSE); + + pPort->in_width = src_prop.width; + pPort->in_height = src_prop.height; + pPort->in_crop = src_prop.crop; + + pPort->out_width = dst_prop.width; + pPort->out_height = dst_prop.height; + pPort->out_crop = dst_prop.crop; + + return TRUE; +} + +static void +_secVideoPunchDrawable (SECPortPrivPtr pPort) +{ + PixmapPtr pPixmap = _getPixmap (pPort->d.pDraw); + SECPtr pSec = SECPTR (pPort->pScrn); + + if (pPort->drawing != ON_FB || !pSec->pVideoPriv->video_punch) + return; + + if (!pPort->punched) + { + secExaPrepareAccess (pPixmap, EXA_PREPARE_DEST); + if (pPixmap->devPrivate.ptr) + memset (pPixmap->devPrivate.ptr, 0, + pPixmap->drawable.width * pPixmap->drawable.height * 4); + secExaFinishAccess (pPixmap, EXA_PREPARE_DEST); + XDBG_TRACE (MVDO, "Punched (%dx%d) %p. \n", + pPixmap->drawable.width, pPixmap->drawable.height, + pPixmap->devPrivate.ptr); + pPort->punched = TRUE; + DamageDamageRegion (pPort->d.pDraw, pPort->d.clip_boxes); + } +} + +static Bool +_secVideoSupportID (int id) +{ + int i; + + for (i = 0; i < NUM_IMAGES; i++) + if (images[i].id == id) + if (secCvtSupportFormat (CVT_OP_M2M, id)) + return TRUE; + + return FALSE; +} + +static Bool +_secVideoInBranch (WindowPtr p, WindowPtr w) +{ + for (; w; w = w->parent) + if (w == p) + return TRUE; + + return FALSE; +} + +/* Return the child of 'p' which includes 'w'. */ +static WindowPtr +_secVideoGetChild (WindowPtr p, WindowPtr w) +{ + WindowPtr c; + + for (c = w, w = w->parent; w; c = w, w = w->parent) + if (w == p) + return c; + + return NULL; +} + +/* ancestor : Return the parent of 'a' and 'b'. + * ancestor_a : Return the child of 'ancestor' which includes 'a'. + * ancestor_b : Return the child of 'ancestor' which includes 'b'. + */ +static Bool +_secVideoGetAncestors (WindowPtr a, WindowPtr b, + WindowPtr *ancestor, + WindowPtr *ancestor_a, + WindowPtr *ancestor_b) +{ + WindowPtr child_a, child_b; + + if (!ancestor || !ancestor_a || !ancestor_b) + return FALSE; + + for (child_b = b, b = b->parent; b; child_b = b, b = b->parent) + { + child_a = _secVideoGetChild (b, a); + if (child_a) + { + *ancestor = b; + *ancestor_a = child_a; + *ancestor_b = child_b; + return TRUE; + } + } + + return FALSE; +} + +static int +_secVideoCompareWindow (WindowPtr pWin1, WindowPtr pWin2) +{ + WindowPtr a, a1, a2, c; + + if (!pWin1 || !pWin2) + return -2; + + if (pWin1 == pWin2) + return 0; + + if (_secVideoGetChild (pWin1, pWin2)) + return -1; + + if (_secVideoGetChild (pWin2, pWin1)) + return 1; + + if (!_secVideoGetAncestors (pWin1, pWin2, &a, &a1, &a2)) + return -3; + + for (c = a->firstChild; c; c = c->nextSib) + { + if (c == a1) + return 1; + else if (c == a2) + return -1; + } + + return -4; +} + +static void +_secVideoArrangeLayerPos (SECPortPrivPtr pPort, Bool by_notify) +{ + SECPortPrivPtr pCur = NULL, pNext = NULL; + SECPortPrivPtr pAnother = NULL; + int i = 0; + + xorg_list_for_each_entry_safe (pCur, pNext, &layer_owners, link) + { + if (pCur == pPort) + continue; + + i++; + + if (!pAnother) + pAnother = pCur; + else + XDBG_WARNING (MVDO, "There are 3 more V4L2 ports. (%d) \n", i); + } + + if (!pAnother) + { + SECLayerPos lpos = secLayerGetPos (pPort->layer); + + if (lpos == LAYER_NONE) + secLayerSetPos (pPort->layer, LAYER_LOWER2); + } + else + { + SECLayerPos lpos1 = LAYER_NONE; + SECLayerPos lpos2 = LAYER_NONE; + + if (pAnother->layer) + lpos1 = secLayerGetPos (pAnother->layer); + if (pPort->layer) + lpos2 = secLayerGetPos (pPort->layer); + + if (lpos2 == LAYER_NONE) + { + int comp = _secVideoCompareWindow ((WindowPtr)pAnother->d.pDraw, + (WindowPtr)pPort->d.pDraw); + + XDBG_TRACE (MVDO, "0x%08x : 0x%08x => %d \n", + _XID(pAnother->d.pDraw), _XID(pPort->d.pDraw), comp); + + if (comp == 1) + { + if (lpos1 != LAYER_LOWER1) + secLayerSetPos (pAnother->layer, LAYER_LOWER1); + secLayerSetPos (pPort->layer, LAYER_LOWER2); + } + else if (comp == -1) + { + if (lpos1 != LAYER_LOWER2) + secLayerSetPos (pAnother->layer, LAYER_LOWER2); + secLayerSetPos (pPort->layer, LAYER_LOWER1); + } + else + { + if (lpos1 == LAYER_LOWER1) + secLayerSetPos (pPort->layer, LAYER_LOWER2); + else + secLayerSetPos (pPort->layer, LAYER_LOWER1); + } + } + else + { + if (!by_notify) + return; + + int comp = _secVideoCompareWindow ((WindowPtr)pAnother->d.pDraw, + (WindowPtr)pPort->d.pDraw); + + XDBG_TRACE (MVDO, "0x%08x : 0x%08x => %d \n", + _XID(pAnother->d.pDraw), _XID(pPort->d.pDraw), comp); + + if ((comp == 1 && lpos1 != LAYER_LOWER1) || + (comp == -1 && lpos2 != LAYER_LOWER1)) + secLayerSwapPos (pAnother->layer, pPort->layer); + } + } +} + +static void +_secVideoStopTvout (ScrnInfoPtr pScrn) +{ + SECPtr pSec = (SECPtr) pScrn->driverPrivate; + XF86VideoAdaptorPtr pAdaptor = pSec->pVideoPriv->pAdaptor[0]; + int i; + + for (i = 0; i < SEC_MAX_PORT; i++) + { + SECPortPrivPtr pPort = (SECPortPrivPtr) pAdaptor->pPortPrivates[i].ptr; + + if (pPort->grab_tvout) + { + _secVideoUngrabTvout (pPort); + return; + } + } +} + +/* TRUE : current frame will be shown on TV. free after vblank. + * FALSE : current frame won't be shown on TV. + */ +static Bool +_secVideoPutImageTvout (SECPortPrivPtr pPort, int output, SECVideoBuf *inbuf) +{ + ScrnInfoPtr pScrn = pPort->pScrn; + SECModePtr pSecMode = (SECModePtr) SECPTR (pScrn)->pSecMode; + xRectangle tv_rect = {0,}; + Bool first_put = FALSE; + + if (!(output & OUTPUT_EXT)) + return FALSE; + + if (pPort->skip_tvout) + return FALSE; + + if (!_secVideoGrabTvout(pPort)) + goto fail_to_put_tvout; + + if (!pPort->tv) + { + SECCvt *tv_cvt; + SECWb *wb; + + if (!secUtilEnsureExternalCrtc (pScrn)) + { + XDBG_ERROR (MVDO, "failed : pPort(%d) connect external crtc\n", pPort->index); + goto fail_to_put_tvout; + } + + pPort->tv = secVideoTvConnect (pScrn, pPort->d.id, LAYER_LOWER1); + XDBG_GOTO_IF_FAIL (pPort->tv != NULL, fail_to_put_tvout); + + wb = secWbGet (); + if (wb) + { + pPort->need_start_wb = TRUE; + + /* in case of VIRTUAL, wb's buffer is used by tvout. */ + if (pSecMode->conn_mode == DISPLAY_CONN_MODE_VIRTUAL) + secWbStop (wb, FALSE); + else + secWbStop (wb, TRUE); + } + + if (secWbIsRunning ()) + { + XDBG_ERROR (MVDO, "failed: wb still running\n"); + goto fail_to_put_tvout; + } + + tv_cvt = secVideoTvGetConverter (pPort->tv); + if (tv_cvt) + { + /* HDMI : SN12 + * VIRTUAL : SN12 or RGB32 + */ + if (pSecMode->conn_mode == DISPLAY_CONN_MODE_VIRTUAL) + { + if (pSecMode->set_mode == DISPLAY_SET_MODE_CLONE) + { + SECVideoBuf **vbufs = NULL; + int bufnum = 0; + + secVideoTvSetConvertFormat (pPort->tv, FOURCC_SN12); + + /* In case of virtual, we draw video on full-size buffer + * for virtual-adaptor + */ + secVideoTvSetSize (pPort->tv, + pSecMode->ext_connector_mode.hdisplay, + pSecMode->ext_connector_mode.vdisplay); + + secVirtualVideoGetBuffers (pPort->pScrn, FOURCC_SN12, + pSecMode->ext_connector_mode.hdisplay, + pSecMode->ext_connector_mode.vdisplay, + &vbufs, &bufnum); + + XDBG_GOTO_IF_FAIL (vbufs != NULL, fail_to_put_tvout); + XDBG_GOTO_IF_FAIL (bufnum > 0, fail_to_put_tvout); + + secVideoTvSetBuffer (pPort->tv, vbufs, bufnum); + } + else /* desktop */ + secVideoTvSetConvertFormat (pPort->tv, FOURCC_RGB32); + } + else + secVideoTvSetConvertFormat (pPort->tv, FOURCC_SN12); + + secCvtAddCallback (tv_cvt, _secVideoTvoutCvtCallback, pPort); + } + else + { + SECLayer *layer = secVideoTvGetLayer (pPort->tv); + XDBG_GOTO_IF_FAIL (layer != NULL, fail_to_put_tvout); + + secLayerEnableVBlank (layer, TRUE); + secLayerAddNotifyFunc (layer, _secVideoLayerNotifyFunc, pPort); + } + + first_put = TRUE; + } + + SECPtr pSec = SECPTR (pPort->pScrn); + if (pPort->wait_vbuf) + { + if (pSec->pVideoPriv->video_fps) + { + CARD32 cur, sub; + cur = GetTimeInMillis (); + sub = cur - pPort->tv_prev_time; + pPort->tv_prev_time = cur; + + XDBG_DEBUG (MVDO, "tvout skip : sub(%ld) vbuf(%ld:%d,%d,%d) \n", + sub, inbuf->stamp, + inbuf->keys[0], inbuf->keys[1], inbuf->keys[2]); + } + + return FALSE; + } + else if (pSec->pVideoPriv->video_fps) + pPort->tv_prev_time = GetTimeInMillis (); + + if (!(output & OUTPUT_FULL)) + { + tv_rect.x = pPort->d.dst.x + - pSecMode->main_lcd_mode.hdisplay; + tv_rect.y = pPort->d.dst.y; + tv_rect.width = pPort->d.dst.width; + tv_rect.height = pPort->d.dst.height; + } + else + { + secUtilAlignRect (pPort->d.src.width, pPort->d.src.height, + pSecMode->ext_connector_mode.hdisplay, + pSecMode->ext_connector_mode.vdisplay, + &tv_rect, TRUE); + } + + /* if secVideoTvPutImage returns FALSE, it means this frame won't show on TV. */ + if (!secVideoTvPutImage (pPort->tv, inbuf, &tv_rect, pPort->csc_range)) + return FALSE; + + if (first_put && !(output & OUTPUT_LCD)) + _secVideoSetOutputExternalProperty (pPort->d.pDraw, TRUE); + + pPort->wait_vbuf = inbuf; + + return TRUE; + +fail_to_put_tvout: + _secVideoUngrabTvout (pPort); + + pPort->skip_tvout = TRUE; + + XDBG_TRACE (MVDO, "pPort(%d) skip tvout \n", pPort->index); + + return FALSE; +} + +static Bool +_secVideoPutImageInbuf (SECPortPrivPtr pPort, SECVideoBuf *inbuf) +{ + if (!pPort->layer) + { + pPort->layer = _secVideoCreateLayer (pPort); + XDBG_RETURN_VAL_IF_FAIL (pPort->layer != NULL, FALSE); + + _secVideoArrangeLayerPos (pPort, FALSE); + } + + secLayerSetBuffer (pPort->layer, inbuf); + + if (!secLayerIsVisible (pPort->layer)) + secLayerShow (pPort->layer); + + return TRUE; +} + +static Bool +_secVideoPutImageInternal (SECPortPrivPtr pPort, SECVideoBuf *inbuf) +{ + SECPtr pSec = (SECPtr) pPort->pScrn->driverPrivate; + SECCvtProp src_prop = {0,}, dst_prop = {0,}; + SECVideoBuf *outbuf = NULL; + + outbuf = _secVideoGetOutbuf (pPort); + if (!outbuf) + return FALSE; + + /* cacheflush here becasue dst buffer can be created in _secVideoGetOutbuf() */ + if (pPort->stream_cnt == 1) + if (pPort->drawing == ON_PIXMAP || pPort->drawing == ON_WINDOW) + secUtilCacheFlush (pPort->pScrn); + + XDBG_DEBUG (MVDO, "'%c%c%c%c' preem(%d) rot(%d) \n", + FOURCC_STR (pPort->d.id), + pPort->preemption, pPort->hw_rotate); + + if (pPort->layer) + _secVideoArrangeLayerPos (pPort, FALSE); + + _secVideoEnsureConverter (pPort); + XDBG_GOTO_IF_FAIL (pPort->cvt != NULL, fail_to_put); + + src_prop.id = pPort->d.id; + src_prop.width = pPort->in_width; + src_prop.height = pPort->in_height; + src_prop.crop = pPort->in_crop; + + dst_prop.id = FOURCC_RGB32; + dst_prop.width = pPort->out_width; + dst_prop.height = pPort->out_height; + dst_prop.crop = pPort->out_crop; + + dst_prop.degree = pPort->hw_rotate; + dst_prop.hflip = pPort->hflip; + dst_prop.vflip = pPort->vflip; + dst_prop.secure = pPort->secure; + dst_prop.csc_range = pPort->csc_range; + + if (!secCvtEnsureSize (&src_prop, &dst_prop)) + goto fail_to_put; + + if (!secCvtSetProperpty (pPort->cvt, &src_prop, &dst_prop)) + goto fail_to_put; + + if (!secCvtConvert (pPort->cvt, inbuf, outbuf)) + goto fail_to_put; + + if (pSec->pVideoPriv->video_fps) + _countFps (pPort); + + secUtilVideoBufferUnref (outbuf); + + return TRUE; + +fail_to_put: + if (outbuf) + secUtilVideoBufferUnref (outbuf); + + _secVideoCloseConverter (pPort); + _secVideoCloseOutBuffer (pPort, TRUE); + + return FALSE; +} + +static Bool +_secVideoSetHWPortsProperty (ScreenPtr pScreen, int nums) +{ + WindowPtr pWin = pScreen->root; + Atom atom_hw_ports; + + /* With "X_HW_PORTS", an application can know + * how many fimc devices XV uses. + */ + if (!pWin || !serverClient) + return FALSE; + + atom_hw_ports = MakeAtom ("XV_HW_PORTS", strlen ("XV_HW_PORTS"), TRUE); + + dixChangeWindowProperty (serverClient, + pWin, atom_hw_ports, XA_CARDINAL, 32, + PropModeReplace, 1, (unsigned int*)&nums, FALSE); + + return TRUE; +} + +static Bool +_secVideoSetOutputExternalProperty (DrawablePtr pDraw, Bool video_only) +{ + WindowPtr pWin; + Atom atom_external; + + XDBG_RETURN_VAL_IF_FAIL (pDraw != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (pDraw->type == DRAWABLE_WINDOW, FALSE); + + pWin = (WindowPtr)pDraw; + + atom_external = MakeAtom ("XV_OUTPUT_EXTERNAL", strlen ("XV_OUTPUT_EXTERNAL"), TRUE); + + dixChangeWindowProperty (clients[CLIENT_ID(pDraw->id)], + pWin, atom_external, XA_CARDINAL, 32, + PropModeReplace, 1, (unsigned int*)&video_only, TRUE); + + XDBG_TRACE (MVDO, "pDraw(0x%08x) video-only(%s)\n", + pDraw->id, (video_only)?"ON":"OFF"); + + return TRUE; +} + +static void +_secVideoRestackWindow (WindowPtr pWin, WindowPtr pOldNextSib) +{ + ScreenPtr pScreen = ((DrawablePtr)pWin)->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = (SECPtr) pScrn->driverPrivate; + SECVideoPrivPtr pVideo = pSec->pVideoPriv; + + if (pVideo->RestackWindow) + { + pScreen->RestackWindow = pVideo->RestackWindow; + + if (pScreen->RestackWindow) + (*pScreen->RestackWindow)(pWin, pOldNextSib); + + pVideo->RestackWindow = pScreen->RestackWindow; + pScreen->RestackWindow = _secVideoRestackWindow; + } + + if (!xorg_list_is_empty (&layer_owners)) + { + SECPortPrivPtr pCur = NULL, pNext = NULL; + xorg_list_for_each_entry_safe (pCur, pNext, &layer_owners, link) + { + if (_secVideoInBranch (pWin, (WindowPtr)pCur->d.pDraw)) + { + XDBG_TRACE (MVDO, "Do re-arrange. 0x%08x(0x%08x) \n", + _XID(pWin), _XID(pCur->d.pDraw)); + _secVideoArrangeLayerPos (pCur, TRUE); + break; + } + } + } +} + +static void +_secVideoBlockHandler (pointer data, OSTimePtr pTimeout, pointer pRead) +{ + ScreenPtr pScreen = ((ScrnInfoPtr)data)->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = (SECPtr) pScrn->driverPrivate; + SECVideoPrivPtr pVideo = pSec->pVideoPriv; + + pVideo->RestackWindow = pScreen->RestackWindow; + pScreen->RestackWindow = _secVideoRestackWindow; + + if(registered_handler && _secVideoSetHWPortsProperty (pScreen, NUM_HW_LAYER)) + { + RemoveBlockAndWakeupHandlers(_secVideoBlockHandler, + (WakeupHandlerProcPtr)NoopDDA, data); + registered_handler = FALSE; + } +} + +static Bool +_secVideoAddDrawableEvent (SECPortPrivPtr pPort) +{ + SECVideoResource *resource; + void *ptr=NULL; + int ret; + + ret = dixLookupResourceByType (&ptr, pPort->d.pDraw->id, + event_drawable_type, NULL, DixWriteAccess); + if (ret == Success) + { + return TRUE; + } + + resource = malloc (sizeof (SECVideoResource)); + if (resource == NULL) + return FALSE; + + if (!AddResource (pPort->d.pDraw->id, event_drawable_type, resource)) + { + free (resource); + return FALSE; + } + + XDBG_TRACE (MVDO, "id(0x%08lx). \n", pPort->d.pDraw->id); + + resource->id = pPort->d.pDraw->id; + resource->type = event_drawable_type; + resource->pPort = pPort; + resource->pScrn = pPort->pScrn; + + return TRUE; +} + +static int +_secVideoRegisterEventDrawableGone (void *data, XID id) +{ + SECVideoResource *resource = (SECVideoResource*)data; + + XDBG_TRACE (MVDO, "id(0x%08lx). \n", id); + + if (!resource) + return Success; + + if (!resource->pPort || !resource->pScrn) + return Success; + + SECVideoStop (resource->pScrn, (pointer)resource->pPort, 1); + + free(resource); + + return Success; +} + +static Bool +_secVideoRegisterEventResourceTypes (void) +{ + event_drawable_type = CreateNewResourceType (_secVideoRegisterEventDrawableGone, "Sec Video Drawable"); + + if (!event_drawable_type) + return FALSE; + + return TRUE; +} + +int +secVideoQueryImageAttrs (ScrnInfoPtr pScrn, + int id, + int *w, + int *h, + int *pitches, + int *offsets, + int *lengths) +{ + int size = 0, tmp = 0; + + *w = (*w + 1) & ~1; + if (offsets) + offsets[0] = 0; + + switch (id) + { + /* RGB565 */ + case FOURCC_SR16: + case FOURCC_RGB565: + size += (*w << 1); + if (pitches) + pitches[0] = size; + size *= *h; + if (lengths) + lengths[0] = size; + break; + /* RGB32 */ + case FOURCC_SR32: + case FOURCC_RGB32: + size += (*w << 2); + if (pitches) + pitches[0] = size; + size *= *h; + if (lengths) + lengths[0] = size; + break; + /* YUV420, 3 planar */ + case FOURCC_I420: + case FOURCC_S420: + case FOURCC_YV12: + *h = (*h + 1) & ~1; + size = (*w + 3) & ~3; + if (pitches) + pitches[0] = size; + + size *= *h; + if (offsets) + offsets[1] = size; + if (lengths) + lengths[0] = size; + + tmp = ((*w >> 1) + 3) & ~3; + if (pitches) + pitches[1] = pitches[2] = tmp; + + tmp *= (*h >> 1); + size += tmp; + if (offsets) + offsets[2] = size; + if (lengths) + lengths[1] = tmp; + + size += tmp; + if (lengths) + lengths[2] = tmp; + + break; + /* YUV422, packed */ + case FOURCC_UYVY: + case FOURCC_SYVY: + case FOURCC_ITLV: + case FOURCC_SUYV: + case FOURCC_YUY2: + size = *w << 1; + if (pitches) + pitches[0] = size; + + size *= *h; + if (lengths) + lengths[0] = size; + break; + + /* YUV420, 2 planar */ + case FOURCC_SN12: + case FOURCC_NV12: + case FOURCC_SN21: + case FOURCC_NV21: + if (pitches) + pitches[0] = *w; + + size = (*w) * (*h); + if (offsets) + offsets[1] = size; + if (lengths) + lengths[0] = size; + + if (pitches) + pitches[1] = *w >> 1; + + tmp = (*w) * (*h >> 1); + size += tmp; + if (lengths) + lengths[1] = tmp; + break; + + /* YUV420, 2 planar, tiled */ + case FOURCC_ST12: + if (pitches) + pitches[0] = *w; + + size = ALIGN_TO_8KB(ALIGN_TO_128B(*w) * ALIGN_TO_32B(*h)); + if (offsets) + offsets[1] = size; + if (lengths) + lengths[0] = size; + + if (pitches) + pitches[1] = *w >> 1; + + tmp = ALIGN_TO_8KB(ALIGN_TO_128B(*w) * ALIGN_TO_32B(*h >> 1)); + size += tmp; + if (lengths) + lengths[1] = tmp; + break; + default: + return 0; + } + + return size; +} + +static int +SECVideoGetPortAttribute (ScrnInfoPtr pScrn, + Atom attribute, + INT32 *value, + pointer data) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr) data; + + if (attribute == _portAtom (PAA_ROTATION)) + { + *value = pPort->rotate; + return Success; + } + else if (attribute == _portAtom (PAA_HFLIP)) + { + *value = pPort->hflip; + return Success; + } + else if (attribute == _portAtom (PAA_VFLIP)) + { + *value = pPort->vflip; + return Success; + } + else if (attribute == _portAtom (PAA_PREEMPTION)) + { + *value = pPort->preemption; + return Success; + } + else if (attribute == _portAtom (PAA_OUTPUT)) + { + *value = pPort->usr_output; + return Success; + } + else if (attribute == _portAtom (PAA_SECURE)) + { + *value = pPort->secure; + return Success; + } + else if (attribute == _portAtom (PAA_CSC_RANGE)) + { + *value = pPort->csc_range; + return Success; + } + + return BadMatch; +} + +static int +SECVideoSetPortAttribute (ScrnInfoPtr pScrn, + Atom attribute, + INT32 value, + pointer data) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr) data; + + if (attribute == _portAtom (PAA_ROTATION)) + { + pPort->rotate = value; + XDBG_DEBUG (MVDO, "rotate(%d) \n", value); + return Success; + } + else if (attribute == _portAtom (PAA_HFLIP)) + { + pPort->hflip = value; + XDBG_DEBUG (MVDO, "hflip(%d) \n", value); + return Success; + } + else if (attribute == _portAtom (PAA_VFLIP)) + { + pPort->vflip = value; + XDBG_DEBUG (MVDO, "vflip(%d) \n", value); + return Success; + } + else if (attribute == _portAtom (PAA_PREEMPTION)) + { + pPort->preemption = value; + XDBG_DEBUG (MVDO, "preemption(%d) \n", value); + return Success; + } + else if (attribute == _portAtom (PAA_OUTPUT)) + { + if (value == OUTPUT_MODE_TVOUT) + pPort->usr_output = OUTPUT_LCD|OUTPUT_EXT|OUTPUT_FULL; + else if (value == OUTPUT_MODE_EXT_ONLY) + pPort->usr_output = OUTPUT_EXT|OUTPUT_FULL; + else + pPort->usr_output = OUTPUT_LCD|OUTPUT_EXT; + + XDBG_DEBUG (MVDO, "output (%d) \n", value); + + return Success; + } + else if (attribute == _portAtom (PAA_SECURE)) + { + pPort->secure = value; + XDBG_DEBUG (MVDO, "secure(%d) \n", value); + return Success; + } + else if (attribute == _portAtom (PAA_CSC_RANGE)) + { + pPort->csc_range = value; + XDBG_DEBUG (MVDO, "csc_range(%d) \n", value); + return Success; + } + + return Success; +} + +static void +SECVideoQueryBestSize (ScrnInfoPtr pScrn, + Bool motion, + short vid_w, short vid_h, + short dst_w, short dst_h, + uint *p_w, uint *p_h, + pointer data) +{ + SECCvtProp prop = {0,}; + + if (!p_w && !p_h) + return; + + prop.width = dst_w; + prop.height = dst_h; + prop.crop.width = dst_w; + prop.crop.height = dst_h; + + if (secCvtEnsureSize (NULL, &prop)) + { + if (p_w) + *p_w = prop.width; + if (p_h) + *p_h = prop.height; + } + else + { + if (p_w) + *p_w = dst_w; + if (p_h) + *p_h = dst_h; + } +} + +/** + * Give image size and pitches. + */ +static int +SECVideoQueryImageAttributes (ScrnInfoPtr pScrn, + int id, + unsigned short *w, + unsigned short *h, + int *pitches, + int *offsets) +{ + int width, height, size; + + if (!w || !h) + return 0; + + width = (int)*w; + height = (int)*h; + + size = secVideoQueryImageAttrs (pScrn, id, &width, &height, pitches, offsets, NULL); + + *w = (unsigned short)width; + *h = (unsigned short)height; + + return size; +} + +/* coordinates : HW, SCREEN, PORT + * BadRequest : when video can't be shown or drawn. + * Success : A damage event(pixmap) and inbuf should be return. + * If can't return a damage event and inbuf, should be return + * BadRequest. + */ +static int +SECVideoPutImage (ScrnInfoPtr pScrn, + short src_x, short src_y, short dst_x, short dst_y, + short src_w, short src_h, short dst_w, short dst_h, + int id, uchar *buf, short width, short height, + Bool sync, RegionPtr clip_boxes, pointer data, + DrawablePtr pDraw) +{ + SECPtr pSec = SECPTR (pScrn); + SECModePtr pSecMode = (SECModePtr)SECPTR (pScrn)->pSecMode; + SECVideoPrivPtr pVideo = SECPTR (pScrn)->pVideoPriv; + SECPortPrivPtr pPort = (SECPortPrivPtr) data; + int output, ret; + Bool tvout = FALSE, lcdout = FALSE; + SECVideoBuf *inbuf = NULL; + int old_drawing; + + if (!_secVideoSupportID (id)) + { + XDBG_ERROR (MVDO, "'%c%c%c%c' not supported.\n", FOURCC_STR (id)); + return BadRequest; + } + + XDBG_TRACE (MVDO, "======================================= \n"); + + pPort->pScrn = pScrn; + pPort->d.id = id; + pPort->d.buf = buf; + + if (pSec->xvperf_mode & XBERC_XVPERF_MODE_IA) + { + unsigned int keys[PLANAR_CNT] = {0,}; + CARD32 cur, sub; + char temp[64]; + cur = GetTimeInMillis (); + sub = cur - pPort->prev_time; + pPort->prev_time = cur; + temp[0] = '\0'; + if (IS_ZEROCOPY (id)) + { + _secVideoGetKeys (pPort, keys, NULL); + snprintf (temp, sizeof(temp), "%d,%d,%d", keys[0], keys[1], keys[2]); + } + ErrorF ("pPort(%p) put interval(%s) : %6ld ms\n", pPort, temp, sub); + } + + if (IS_ZEROCOPY (pPort->d.id)) + { + unsigned int keys[PLANAR_CNT] = {0,}; + int i; + + if (_secVideoGetKeys (pPort, keys, NULL)) + return BadRequest; + + for (i = 0; i < INBUF_NUM; i++) + if (pPort->inbuf[i] && pPort->inbuf[i]->keys[0] == keys[0]) + { + XDBG_WARNING (MVDO, "got flink_id(%d) twice!\n", keys[0]); + _secVideoSendReturnBufferMessage (pPort, NULL, keys); + return Success; + } + } + + pPort->d.width = width; + pPort->d.height = height; + pPort->d.src.x = src_x; + pPort->d.src.y = src_y; + pPort->d.src.width = src_w; + pPort->d.src.height = src_h; + pPort->d.dst.x = dst_x; /* included pDraw'x */ + pPort->d.dst.y = dst_y; /* included pDraw'y */ + pPort->d.dst.width = dst_w; + pPort->d.dst.height = dst_h; + pPort->d.sync = FALSE; + if (sync) + XDBG_WARNING (MVDO, "not support sync.\n"); + pPort->d.data = data; + pPort->d.pDraw = pDraw; + if (clip_boxes) + { + if (!pPort->d.clip_boxes) + pPort->d.clip_boxes = RegionCreate(NullBox, 0); + RegionCopy (pPort->d.clip_boxes, clip_boxes); + } + + old_drawing = pPort->drawing; + pPort->drawing = _secVideodrawingOn (pPort); + if (old_drawing != pPort->drawing) + { + _secVideoCloseConverter (pPort); + _secVideoCloseOutBuffer (pPort, TRUE); + } + + _secVideoGetRotation (pPort, &pPort->hw_rotate); + + if (pPort->drawing == ON_FB && pVideo->screen_rotate_degree > 0) + secUtilRotateRect (pSecMode->main_lcd_mode.hdisplay, + pSecMode->main_lcd_mode.vdisplay, + &pPort->d.dst, + pVideo->screen_rotate_degree); + + if (pPort->secure) + if (pPort->drawing != ON_FB) + { + XDBG_ERROR (MVDO, "secure video should drawn on FB.\n"); + return BadRequest; + } + + if (pPort->drawing == ON_PIXMAP || pPort->drawing == ON_WINDOW) + if (!_secVideoAddDrawableEvent (pPort)) + return BadRequest; + + if (pPort->stream_cnt == 0) + { + pPort->stream_cnt++; + + if (pPort->preemption > -1) + streaming_ports++; + + XDBG_SECURE (MVDO, "pPort(%d) streams(%d) rotate(%d) flip(%d,%d) secure(%d) range(%d) usr_output(%x) on(%s)\n", + pPort->index, streaming_ports, + pPort->rotate, pPort->hflip, pPort->vflip, pPort->secure, pPort->csc_range, + pPort->usr_output, drawing_type[pPort->drawing]); + XDBG_SECURE (MVDO, "id(%c%c%c%c) sz(%dx%d) src(%d,%d %dx%d) dst(%d,%d %dx%d)\n", + FOURCC_STR (id), width, height, + src_x, src_y, src_w, src_h, dst_x, dst_y, dst_w, dst_h); + + if (streaming_ports > 1) + _secVideoStopTvout (pPort->pScrn); + } + else if (pPort->stream_cnt == 1) + pPort->stream_cnt++; + + if (pPort->cvt) + { + SECCvtProp dst_prop; + + secCvtGetProperpty (pPort->cvt, NULL, &dst_prop); + + if (pPort->d.id != pPort->old_d.id || + pPort->d.width != pPort->old_d.width || + pPort->d.height != pPort->old_d.height || + memcmp (&pPort->d.src, &pPort->old_d.src, sizeof (xRectangle)) || + dst_prop.degree != pPort->hw_rotate || + dst_prop.hflip != pPort->hflip || + dst_prop.vflip != pPort->vflip || + dst_prop.secure != pPort->secure || + dst_prop.csc_range != pPort->csc_range) + { + XDBG_DEBUG (MVDO, "pPort(%d) streams(%d) rotate(%d) flip(%d,%d) secure(%d) range(%d) usr_output(%x) on(%s)\n", + pPort->index, streaming_ports, + pPort->rotate, pPort->hflip, pPort->vflip, pPort->secure, pPort->csc_range, + pPort->usr_output, drawing_type[pPort->drawing]); + XDBG_DEBUG (MVDO, "pPort(%d) old_src(%dx%d %d,%d %dx%d) : new_src(%dx%d %d,%d %dx%d)\n", + pPort->index, pPort->old_d.width, pPort->old_d.height, + pPort->old_d.src.x, pPort->old_d.src.y, + pPort->old_d.src.width, pPort->old_d.src.height, + pPort->d.width, pPort->d.height, + pPort->d.src.x, pPort->d.src.y, + pPort->d.src.width, pPort->d.src.height); + _secVideoCloseConverter (pPort); + _secVideoCloseInBuffer (pPort); + pPort->inbuf_is_fb = FALSE; + } + } + + if (memcmp (&pPort->d.dst, &pPort->old_d.dst, sizeof (xRectangle))) + { + XDBG_DEBUG (MVDO, "pPort(%d) old_dst(%d,%d %dx%d) : new_dst(%dx%d %dx%d)\n", + pPort->index, + pPort->old_d.dst.x, pPort->old_d.dst.y, + pPort->old_d.dst.width, pPort->old_d.dst.height, + pPort->d.dst.x, pPort->d.dst.y, + pPort->d.dst.width, pPort->d.dst.height); + _secVideoCloseConverter (pPort); + _secVideoCloseOutBuffer (pPort, FALSE); + pPort->inbuf_is_fb = FALSE; + } + + if (!_secVideoCalculateSize (pPort)) + return BadRequest; + + output = _secVideoGetTvoutMode (pPort); + if (!(output & OUTPUT_LCD) && pPort->old_output & OUTPUT_LCD) + { + /* If the video of LCD becomes off, we also turn off LCD layer. */ + if (pPort->drawing == ON_PIXMAP || pPort->drawing == ON_WINDOW) + { + PixmapPtr pPixmap = _getPixmap (pPort->d.pDraw); + SECPixmapPriv *privPixmap = exaGetPixmapDriverPrivate (pPixmap); + + secExaPrepareAccess (pPixmap, EXA_PREPARE_DEST); + if (pPixmap->devPrivate.ptr && privPixmap->size > 0) + memset (pPixmap->devPrivate.ptr, 0, privPixmap->size); + secExaFinishAccess (pPixmap, EXA_PREPARE_DEST); + + DamageDamageRegion (pPort->d.pDraw, pPort->d.clip_boxes); + } + else + { + _secVideoCloseConverter (pPort); + _secVideoCloseOutBuffer (pPort, TRUE); + } + } + + if (pPort->d.id == FOURCC_SR32 && + pPort->in_crop.width == pPort->out_crop.width && + pPort->in_crop.height == pPort->out_crop.height && + pPort->hw_rotate == 0) + pPort->inbuf_is_fb = TRUE; + else + pPort->inbuf_is_fb = FALSE; + + inbuf = _secVideoGetInbuf (pPort); + if (!inbuf) + return BadRequest; + + /* punch here not only LCD but also HDMI. */ + if (pPort->drawing == ON_FB) + _secVideoPunchDrawable (pPort); + + /* HDMI */ + if (output & OUTPUT_EXT) + tvout = _secVideoPutImageTvout (pPort, output, inbuf); + else + { + _secVideoUngrabTvout (pPort); + + SECWb *wb = secWbGet (); + if (wb) + secWbSetSecure (wb, pPort->secure); + } + + /* LCD */ + if (output & OUTPUT_LCD) + { + SECPtr pSec = SECPTR (pScrn); + + if (pSec->isLcdOff) + XDBG_TRACE (MVDO, "port(%d) put image after dpms off.\n", pPort->index); + else if (pPort->inbuf_is_fb) + lcdout = _secVideoPutImageInbuf (pPort, inbuf); + else + lcdout = _secVideoPutImageInternal (pPort, inbuf); + } + + if (lcdout || tvout) + { + ret = Success; + } + else + { + if (IS_ZEROCOPY (pPort->d.id)) + { + int i; + + for (i = 0; i < INBUF_NUM; i++) + if (pPort->inbuf[i] == inbuf) + { + pPort->inbuf[i] = NULL; + secUtilRemoveFreeVideoBufferFunc (inbuf, _secVideoFreeInbuf, pPort); + break; + } + XDBG_WARNING_IF_FAIL (inbuf->ref_cnt == 1); + } + else + XDBG_WARNING_IF_FAIL (inbuf->ref_cnt == 2); + + ret = BadRequest; + } + + /* decrease ref_cnt here to pass ownership of inbuf to converter or tvout. + * in case of zero-copy, it will be really freed + * when converting is finished or tvout is finished. + */ + secUtilVideoBufferUnref (inbuf); + + pPort->old_d = pPort->d; + pPort->old_output = output; + + XDBG_TRACE (MVDO, "=======================================.. \n"); + + return ret; +} + +static int +SECVideoDDPutImage (ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 src_x, INT16 src_y, + CARD16 src_w, CARD16 src_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h, + XvImagePtr format, + unsigned char *data, Bool sync, CARD16 width, CARD16 height) +{ + SECVideoPortInfo *info = _port_info (pDraw); + int ret; + + if (info) + { + info->client = client; + info->pp = pPort; + } + + ret = ddPutImage (client, pDraw, pPort, pGC, + src_x, src_y, src_w, src_h, + drw_x, drw_y, drw_w, drw_h, + format, data, sync, width, height); + + return ret; +} + +static void +SECVideoStop (ScrnInfoPtr pScrn, pointer data, Bool exit) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr) data; + + if (!exit) + return; + + XDBG_DEBUG (MVDO, "exit (%d) \n", exit); + + _secVideoStreamOff (pPort); + + pPort->preemption = 0; + pPort->rotate = 0; + pPort->hflip = 0; + pPort->vflip = 0; + pPort->punched = FALSE; +} + +/** + * Set up all our internal structures. + */ +static XF86VideoAdaptorPtr +secVideoSetupImageVideo (ScreenPtr pScreen) +{ + XF86VideoAdaptorPtr pAdaptor; + SECPortPrivPtr pPort; + int i; + + pAdaptor = calloc (1, sizeof (XF86VideoAdaptorRec) + + (sizeof (DevUnion) + sizeof (SECPortPriv)) * SEC_MAX_PORT); + if (!pAdaptor) + return NULL; + + dummy_encoding[0].width = pScreen->width; + dummy_encoding[0].height = pScreen->height; + + pAdaptor->type = XvWindowMask | XvPixmapMask | XvInputMask | XvImageMask; + pAdaptor->flags = VIDEO_OVERLAID_IMAGES; + pAdaptor->name = "SEC supporting Software Video Conversions"; + pAdaptor->nEncodings = sizeof (dummy_encoding) / sizeof (XF86VideoEncodingRec); + pAdaptor->pEncodings = dummy_encoding; + pAdaptor->nFormats = NUM_FORMATS; + pAdaptor->pFormats = formats; + pAdaptor->nPorts = SEC_MAX_PORT; + pAdaptor->pPortPrivates = (DevUnion*)(&pAdaptor[1]); + + pPort = + (SECPortPrivPtr) (&pAdaptor->pPortPrivates[SEC_MAX_PORT]); + + for (i = 0; i < SEC_MAX_PORT; i++) + { + pAdaptor->pPortPrivates[i].ptr = &pPort[i]; + pPort[i].index = i; + pPort[i].usr_output = OUTPUT_LCD|OUTPUT_EXT; + pPort[i].outbuf_cvting = -1; + } + + pAdaptor->nAttributes = NUM_ATTRIBUTES; + pAdaptor->pAttributes = attributes; + pAdaptor->nImages = NUM_IMAGES; + pAdaptor->pImages = images; + + pAdaptor->GetPortAttribute = SECVideoGetPortAttribute; + pAdaptor->SetPortAttribute = SECVideoSetPortAttribute; + pAdaptor->QueryBestSize = SECVideoQueryBestSize; + pAdaptor->QueryImageAttributes = SECVideoQueryImageAttributes; + pAdaptor->PutImage = SECVideoPutImage; + pAdaptor->StopVideo = SECVideoStop; + + if (!_secVideoRegisterEventResourceTypes ()) + { + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "Failed to register EventResourceTypes. \n"); + return FALSE; + } + + return pAdaptor; +} + +static void +SECVideoReplacePutImageFunc (ScreenPtr pScreen) +{ + int i; + + XvScreenPtr xvsp = dixLookupPrivate (&pScreen->devPrivates, + XvGetScreenKey()); + if (!xvsp) + return; + + for (i = 0; i < xvsp->nAdaptors; i++) + { + XvAdaptorPtr pAdapt = xvsp->pAdaptors + i; + if (pAdapt->ddPutImage) + { + ddPutImage = pAdapt->ddPutImage; + pAdapt->ddPutImage = SECVideoDDPutImage; + break; + } + } + + if (!dixRegisterPrivateKey (VideoPortKey, PRIVATE_WINDOW, sizeof (SECVideoPortInfo))) + return; + if (!dixRegisterPrivateKey (VideoPortKey, PRIVATE_PIXMAP, sizeof (SECVideoPortInfo))) + return; +} + +#ifdef XV +/** + * Set up everything we need for Xv. + */ +Bool secVideoInit (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = (SECPtr) pScrn->driverPrivate; + SECVideoPrivPtr pVideo; + + pVideo = (SECVideoPrivPtr)calloc (sizeof (SECVideoPriv), 1); + if (!pVideo) + return FALSE; + + pVideo->pAdaptor[0] = secVideoSetupImageVideo (pScreen); + if (!pVideo->pAdaptor[0]) + { + free (pVideo); + return FALSE; + } + + pVideo->pAdaptor[1] = secVideoSetupVirtualVideo (pScreen); + if (!pVideo->pAdaptor[1]) + { + free (pVideo->pAdaptor[0]); + free (pVideo); + return FALSE; + } + + pVideo->pAdaptor[2] = secVideoSetupDisplayVideo (pScreen); + if (!pVideo->pAdaptor[2]) + { + free (pVideo->pAdaptor[1]); + free (pVideo->pAdaptor[0]); + free (pVideo); + return FALSE; + } + + xf86XVScreenInit (pScreen, pVideo->pAdaptor, ADAPTOR_NUM); + + SECVideoReplacePutImageFunc (pScreen); + secVirtualVideoReplacePutStillFunc (pScreen); + + if(registered_handler == FALSE) + { + RegisterBlockAndWakeupHandlers(_secVideoBlockHandler, + (WakeupHandlerProcPtr)NoopDDA, pScrn); + registered_handler = TRUE; + } + + pSec->pVideoPriv = pVideo; + xorg_list_init (&layer_owners); + + return TRUE; +} + +/** + * Shut down Xv, used on regeneration. + */ +void secVideoFini (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SECPtr pSec = (SECPtr) pScrn->driverPrivate; + SECVideoPrivPtr pVideo = pSec->pVideoPriv; + SECPortPrivPtr pCur = NULL, pNext = NULL; + int i; + + xorg_list_for_each_entry_safe (pCur, pNext, &layer_owners, link) + { + if (pCur->tv) + { + secVideoTvDisconnect (pCur->tv); + pCur->tv = NULL; + } + + if (pCur->d.clip_boxes) + { + RegionDestroy (pCur->d.clip_boxes); + pCur->d.clip_boxes = NULL; + } + } + + for (i = 0; i < ADAPTOR_NUM; i++) + if (pVideo->pAdaptor[i]) + free (pVideo->pAdaptor[i]); + + free (pVideo); + pSec->pVideoPriv= NULL; +} + +#endif + +void +secVideoDpms (ScrnInfoPtr pScrn, Bool on) +{ + if (!on) + { + SECPtr pSec = (SECPtr) pScrn->driverPrivate; + XF86VideoAdaptorPtr pAdaptor = pSec->pVideoPriv->pAdaptor[0]; + int i; + + for (i = 0; i < SEC_MAX_PORT; i++) + { + SECPortPrivPtr pPort = (SECPortPrivPtr) pAdaptor->pPortPrivates[i].ptr; + if (pPort->stream_cnt == 0) + continue; + XDBG_TRACE (MVDO, "port(%d) cvt stop.\n", pPort->index); + _secVideoCloseConverter (pPort); + _secVideoCloseInBuffer (pPort); + } + } +} + +void +secVideoScreenRotate (ScrnInfoPtr pScrn, int degree) +{ + SECPtr pSec = SECPTR(pScrn); + SECVideoPrivPtr pVideo = pSec->pVideoPriv; + int old_degree; + + if (pVideo->screen_rotate_degree == degree) + return; + + old_degree = pVideo->screen_rotate_degree; + pVideo->screen_rotate_degree = degree; + XDBG_DEBUG (MVDO, "screen rotate degree: %d\n", degree); + + if (pSec->isLcdOff) + return; + + SECPortPrivPtr pCur = NULL, pNext = NULL; + xorg_list_for_each_entry_safe (pCur, pNext, &layer_owners, link) + { + SECModePtr pSecMode = pSec->pSecMode; + SECVideoBuf *old_vbuf, *rot_vbuf; + xRectangle rot_rect, dst_rect; + int rot_width, rot_height; + int scn_width, scn_height; + int degree_diff = degree - old_degree; + + if (!pCur->layer) + continue; + + old_vbuf = secLayerGetBuffer (pCur->layer); + XDBG_RETURN_IF_FAIL (old_vbuf != NULL); + + rot_width = old_vbuf->width; + rot_height = old_vbuf->height; + rot_rect = old_vbuf->crop; + secUtilRotateArea (&rot_width, &rot_height, &rot_rect, degree_diff); + + rot_vbuf = secUtilAllocVideoBuffer (pScrn, FOURCC_RGB32, rot_width, rot_height, + (pSec->scanout)?TRUE:FALSE, FALSE, pCur->secure); + XDBG_RETURN_IF_FAIL (rot_vbuf != NULL); + rot_vbuf->crop = rot_rect; + + secUtilConvertBos (pScrn, + old_vbuf->bo[0], old_vbuf->width, old_vbuf->height, &old_vbuf->crop, old_vbuf->width*4, + rot_vbuf->bo[0], rot_vbuf->width, rot_vbuf->height, &rot_vbuf->crop, rot_vbuf->width*4, + FALSE, degree_diff); + + tbm_bo_map (rot_vbuf->bo[0], TBM_DEVICE_2D, TBM_OPTION_READ); + tbm_bo_unmap (rot_vbuf->bo[0]); + + secLayerGetRect (pCur->layer, NULL, &dst_rect); + + scn_width = (old_degree % 180)?pSecMode->main_lcd_mode.vdisplay:pSecMode->main_lcd_mode.hdisplay; + scn_height = (old_degree % 180)?pSecMode->main_lcd_mode.hdisplay:pSecMode->main_lcd_mode.vdisplay; + + secUtilRotateRect (scn_width, scn_height, &dst_rect, degree_diff); + + secLayerFreezeUpdate (pCur->layer, TRUE); + secLayerSetRect (pCur->layer, &rot_vbuf->crop, &dst_rect); + secLayerFreezeUpdate (pCur->layer, FALSE); + secLayerSetBuffer (pCur->layer, rot_vbuf); + + secUtilVideoBufferUnref (rot_vbuf); + + _secVideoCloseConverter (pCur); + } +} + +void +secVideoSwapLayers (ScreenPtr pScreen) +{ + SECPortPrivPtr pCur = NULL, pNext = NULL; + SECPortPrivPtr pPort1 = NULL, pPort2 = NULL; + + xorg_list_for_each_entry_safe (pCur, pNext, &layer_owners, link) + { + if (!pPort1) + pPort1 = pCur; + else if (!pPort2) + pPort2 = pCur; + } + + if (pPort1 && pPort2) + { + secLayerSwapPos (pPort1->layer, pPort2->layer); + XDBG_TRACE (MVDO, "%p : %p \n", pPort1->layer, pPort2->layer); + } +} + +Bool +secVideoIsSecureMode (ScrnInfoPtr pScrn) +{ + SECPtr pSec = (SECPtr) pScrn->driverPrivate; + XF86VideoAdaptorPtr pAdaptor = pSec->pVideoPriv->pAdaptor[0]; + int i; + + for (i = 0; i < SEC_MAX_PORT; i++) + { + SECPortPrivPtr pPort = (SECPortPrivPtr) pAdaptor->pPortPrivates[i].ptr; + if (pPort->secure) + { + XDBG_TRACE (MVDO, "pPort(%d) is secure.\n", pPort->index); + return TRUE; + } + } + + XDBG_TRACE (MVDO, "no secure port.\n"); + + return FALSE; +} diff --git a/src/xv/sec_video.h b/src/xv/sec_video.h new file mode 100644 index 0000000..54888bc --- /dev/null +++ b/src/xv/sec_video.h @@ -0,0 +1,86 @@ +/************************************************************************** + +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. + +**************************************************************************/ +#ifndef SEC_VIDEO_H +#define SEC_VIDEO_H + +#define ADAPTOR_NUM 3 + +enum +{ + OUTPUT_MODE_DEFAULT, + OUTPUT_MODE_TVOUT, + OUTPUT_MODE_EXT_ONLY, +}; + +typedef struct +{ +#ifdef XV + XF86VideoAdaptorPtr pAdaptor[ADAPTOR_NUM]; +#endif + + int video_punch; + int video_fps; + int video_sync; + int video_fimc; + int video_output; + + int video_offset_x; + int video_offset_y; + + /* extension */ + int tvout_in_use; + + Bool no_retbuf; + + int screen_rotate_degree; + + /* for configure notify */ + RestackWindowProcPtr RestackWindow; + +} SECVideoPriv, *SECVideoPrivPtr; + +Bool secVideoInit (ScreenPtr pScreen); +void secVideoFini (ScreenPtr pScreen); + +void secVideoDpms (ScrnInfoPtr pScrn, Bool on); +void secVideoScreenRotate (ScrnInfoPtr pScrn, int degree); +void secVideoSwapLayers (ScreenPtr pScreen); + +int secVideoQueryImageAttrs (ScrnInfoPtr pScrn, + int id, + int *w, + int *h, + int *pitches, + int *offsets, + int *lengths); + +Bool secVideoIsSecureMode (ScrnInfoPtr pScrn); + +#endif // SEC_VIDEO_H diff --git a/src/xv/sec_video_display.c b/src/xv/sec_video_display.c new file mode 100644 index 0000000..e1f50c8 --- /dev/null +++ b/src/xv/sec_video_display.c @@ -0,0 +1,618 @@ +/* + * xserver-xorg-video-exynos + * + * Copyright 2004 Keith Packard + * Copyright 2005 Eric Anholt + * Copyright 2006 Nokia Corporation + * Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved. + * + * Contact: Boram Park <boram1288.park@samsung.com> + * + * Permission to use, copy, modify, distribute and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the names of the authors and/or copyright holders + * not be used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. The authors and + * copyright holders make no representations about the suitability of this + * software for any purpose. It is provided "as is" without any express + * or implied warranty. + * + * THE AUTHORS AND COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include <errno.h> +#include <sys/time.h> +#include <sys/ioctl.h> + +#include <pixman.h> +#include <X11/Xatom.h> +#include <X11/extensions/Xv.h> +#include <X11/extensions/Xvproto.h> +#include <fourcc.h> + +#include <xf86xv.h> + +#include "sec.h" +#include "sec_util.h" +#include "sec_video_display.h" +#include "sec_video_fourcc.h" +#include "sec_layer.h" + +#include "fimg2d.h" + +#define SEC_MAX_PORT 1 +#define LAYER_BUF_CNT 3 + +static XF86VideoEncodingRec dummy_encoding[] = +{ + { 0, "XV_IMAGE", -1, -1, { 1, 1 } }, + { 1, "XV_IMAGE", 4224, 4224, { 1, 1 } }, +}; + +static XF86VideoFormatRec formats[] = +{ + { 16, TrueColor }, + { 24, TrueColor }, + { 32, TrueColor }, +}; + +static XF86AttributeRec attributes[] = +{ + { 0, 0, 1, "_USER_WM_PORT_ATTRIBUTE_OVERLAY" }, +}; + +typedef enum +{ + PAA_MIN, + PAA_OVERLAY, + PAA_MAX +} SECPortAttrAtom; + +static struct +{ + SECPortAttrAtom paa; + const char *name; + Atom atom; +} atoms[] = +{ + { PAA_OVERLAY, "_USER_WM_PORT_ATTRIBUTE_OVERLAY", None }, +}; + +typedef struct _GetData +{ + int width; + int height; + xRectangle src; + xRectangle dst; + DrawablePtr pDraw; +} GetData; + +/* SEC port information structure */ +typedef struct +{ + int index; + + /* attributes */ + Bool overlay; + + ScrnInfoPtr pScrn; + GetData d; + GetData old_d; + + /* layer */ + SECLayer *layer; + SECVideoBuf *outbuf[LAYER_BUF_CNT]; + + int stream_cnt; + struct xorg_list link; +} SECPortPriv, *SECPortPrivPtr; + +static RESTYPE event_drawable_type; + +typedef struct _SECDisplayVideoResource +{ + XID id; + RESTYPE type; + + SECPortPrivPtr pPort; + ScrnInfoPtr pScrn; +} SECDisplayVideoResource; + +static void _secDisplayVideoCloseBuffers (SECPortPrivPtr pPort); +static void SECDisplayVideoStop (ScrnInfoPtr pScrn, pointer data, Bool exit); + +#define NUM_FORMATS (sizeof(formats) / sizeof(formats[0])) +#define NUM_ATTRIBUTES (sizeof(attributes) / sizeof(attributes[0])) +#define NUM_ATOMS (sizeof(atoms) / sizeof(atoms[0])) + +static PixmapPtr +_getPixmap (DrawablePtr pDraw) +{ + if (pDraw->type == DRAWABLE_WINDOW) + return pDraw->pScreen->GetWindowPixmap ((WindowPtr) pDraw); + else + return (PixmapPtr) pDraw; +} + +static Atom +_portAtom (SECPortAttrAtom paa) +{ + int i; + + XDBG_RETURN_VAL_IF_FAIL (paa > PAA_MIN && paa < PAA_MAX, None); + + for (i = 0; i < NUM_ATOMS; i++) + { + if (paa == atoms[i].paa) + { + if (atoms[i].atom == None) + atoms[i].atom = MakeAtom (atoms[i].name, + strlen (atoms[i].name), TRUE); + + return atoms[i].atom; + } + } + + XDBG_ERROR (MDA, "Error: Unknown Port Attribute Name!\n"); + + return None; +} + +static void +_copyBuffer (DrawablePtr pDraw, SECVideoBuf *vbuf) +{ + PixmapPtr pPixmap = (PixmapPtr)_getPixmap (pDraw); + SECPixmapPriv *privPixmap = exaGetPixmapDriverPrivate (pPixmap); + Bool need_finish = FALSE; + tbm_bo_handle bo_handle_src, bo_handle_dst; + G2dImage *src_image = NULL, *dst_image = NULL; + + if (!privPixmap->bo) + { + need_finish = TRUE; + secExaPrepareAccess (pPixmap, EXA_PREPARE_DEST); + XDBG_GOTO_IF_FAIL (privPixmap->bo != NULL, done_copy_buf); + } + + bo_handle_src = tbm_bo_get_handle (privPixmap->bo, TBM_DEVICE_DEFAULT); + XDBG_GOTO_IF_FAIL (bo_handle_src.u32 > 0, done_copy_buf); + + bo_handle_dst = tbm_bo_get_handle (vbuf->bo[0], TBM_DEVICE_DEFAULT); + XDBG_GOTO_IF_FAIL (bo_handle_dst.u32 > 0, done_copy_buf); + + src_image = g2d_image_create_bo2 (G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB, + (unsigned int)pDraw->width, + (unsigned int)pDraw->height, + (unsigned int)bo_handle_src.u32, + (unsigned int)0, + (unsigned int)pDraw->width * 4); + XDBG_GOTO_IF_FAIL (src_image != NULL, done_copy_buf); + + dst_image = g2d_image_create_bo2 (G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB, + (unsigned int)vbuf->width, + (unsigned int)vbuf->height, + (unsigned int)vbuf->handles[0], + (unsigned int)vbuf->handles[1], + (unsigned int)vbuf->pitches[0]); + XDBG_GOTO_IF_FAIL (dst_image != NULL, done_copy_buf); + + tbm_bo_map (privPixmap->bo, TBM_DEVICE_MM, TBM_OPTION_READ); + tbm_bo_map (vbuf->bo[0], TBM_DEVICE_MM, TBM_OPTION_READ); + + util_g2d_blend_with_scale (G2D_OP_SRC, src_image, dst_image, + (int)vbuf->crop.x, (int)vbuf->crop.y, + (unsigned int)vbuf->crop.width, + (unsigned int)vbuf->crop.height, + (int)vbuf->crop.x, (int)vbuf->crop.y, + (unsigned int)vbuf->crop.width, + (unsigned int)vbuf->crop.height, + FALSE); + g2d_exec(); + + tbm_bo_unmap (privPixmap->bo); + tbm_bo_unmap (vbuf->bo[0]); + +done_copy_buf: + if (src_image) + g2d_image_free (src_image); + if (dst_image) + g2d_image_free (dst_image); + if (need_finish) + secExaFinishAccess (pPixmap, EXA_PREPARE_DEST); +} + +static Bool +_secDisplayVideoShowLayer (SECPortPrivPtr pPort, SECVideoBuf *vbuf, + SECLayerOutput output, SECLayerPos lpos) +{ + xRectangle src_rect, dst_rect; + + if (!pPort->layer) + { + SECModePtr pSecMode = (SECModePtr) SECPTR (pPort->pScrn)->pSecMode; + + if (!secUtilEnsureExternalCrtc (pPort->pScrn)) + { + XDBG_ERROR (MDA, "failed : pPort(%d) connect external crtc\n", pPort->index); + return FALSE; + } + + pPort->layer = secLayerCreate (pPort->pScrn, output, lpos); + XDBG_RETURN_VAL_IF_FAIL (pPort->layer != NULL, FALSE); + + if (output == LAYER_OUTPUT_EXT && pSecMode->conn_mode != DISPLAY_CONN_MODE_VIRTUAL) + secLayerEnableVBlank (pPort->layer, TRUE); + } + + secLayerGetRect (pPort->layer, &src_rect, &dst_rect); + + if (memcmp (&pPort->d.src, &src_rect, sizeof (xRectangle)) || + memcmp (&pPort->d.dst, &dst_rect, sizeof (xRectangle))) + { + secLayerFreezeUpdate (pPort->layer, TRUE); + secLayerSetRect (pPort->layer, &pPort->d.src, &pPort->d.dst); + secLayerFreezeUpdate (pPort->layer, FALSE); + } + + secLayerSetBuffer (pPort->layer, vbuf); + if (!secLayerIsVisible (pPort->layer)) + secLayerShow (pPort->layer); + + XDBG_DEBUG (MDA, "pDraw(0x%lx), fb_id(%d), (%d,%d %dx%d) (%d,%d %dx%d)\n", + pPort->d.pDraw->id, vbuf->fb_id, + pPort->d.src.x, pPort->d.src.y, pPort->d.src.width, pPort->d.src.height, + pPort->d.dst.x, pPort->d.dst.y, pPort->d.dst.width, pPort->d.dst.height); + + return TRUE; +} + +static void +_secDisplayVideoHideLayer (SECPortPrivPtr pPort) +{ + if (!pPort->layer) + return; + + secLayerUnref (pPort->layer); + pPort->layer = NULL; +} + +static SECVideoBuf* +_secDisplayVideoGetBuffer (SECPortPrivPtr pPort) +{ + int i; + + for (i = 0; i < LAYER_BUF_CNT; i++) + { + if (!pPort->outbuf[i]) + { + SECPtr pSec = SECPTR (pPort->pScrn); + + pPort->outbuf[i] = secUtilAllocVideoBuffer (pPort->pScrn, FOURCC_RGB32, + pPort->d.pDraw->width, + pPort->d.pDraw->height, + (pSec->scanout)?TRUE:FALSE, + FALSE, FALSE); + XDBG_GOTO_IF_FAIL (pPort->outbuf[i] != NULL, fail_get_buf); + break; + } + else if (!pPort->outbuf[i]->showing) + break; + } + + if (i == LAYER_BUF_CNT) + { + XDBG_ERROR (MDA, "now all outbufs in use!\n"); + return NULL; + } + + XDBG_DEBUG (MDA, "outbuf: stamp(%ld) index(%d) h(%d,%d,%d)\n", + pPort->outbuf[i]->stamp, i, + pPort->outbuf[i]->handles[0], + pPort->outbuf[i]->handles[1], + pPort->outbuf[i]->handles[2]); + + pPort->outbuf[i]->crop = pPort->d.src; + + _copyBuffer (pPort->d.pDraw, pPort->outbuf[i]); + + return pPort->outbuf[i]; + +fail_get_buf: + _secDisplayVideoCloseBuffers (pPort); + return NULL; +} + +static void +_secDisplayVideoCloseBuffers (SECPortPrivPtr pPort) +{ + int i; + + for (i = 0; i < LAYER_BUF_CNT; i++) + if (pPort->outbuf[i]) + { + secUtilVideoBufferUnref (pPort->outbuf[i]); + pPort->outbuf[i] = NULL; + } +} + +static void +_secDisplayVideoStreamOff (SECPortPrivPtr pPort) +{ + _secDisplayVideoHideLayer (pPort); + _secDisplayVideoCloseBuffers (pPort); + + memset (&pPort->old_d, 0, sizeof (GetData)); + memset (&pPort->d, 0, sizeof (GetData)); + + if (pPort->stream_cnt > 0) + { + pPort->stream_cnt = 0; + XDBG_SECURE (MDA, "pPort(%d) stream off. \n", pPort->index); + } + + XDBG_TRACE (MDA, "done. \n"); +} + +static Bool +_secDisplayVideoAddDrawableEvent (SECPortPrivPtr pPort) +{ + SECDisplayVideoResource *resource; + void *ptr=NULL; + int ret; + + ret = dixLookupResourceByType (&ptr, pPort->d.pDraw->id, + event_drawable_type, NULL, DixWriteAccess); + if (ret == Success) + { + return TRUE; + } + + resource = malloc (sizeof (SECDisplayVideoResource)); + if (resource == NULL) + return FALSE; + + if (!AddResource (pPort->d.pDraw->id, event_drawable_type, resource)) + { + free (resource); + return FALSE; + } + + XDBG_TRACE (MDA, "id(0x%08lx). \n", pPort->d.pDraw->id); + + resource->id = pPort->d.pDraw->id; + resource->type = event_drawable_type; + resource->pPort = pPort; + resource->pScrn = pPort->pScrn; + + return TRUE; +} + +static int +_secDisplayVideoRegisterEventDrawableGone (void *data, XID id) +{ + SECDisplayVideoResource *resource = (SECDisplayVideoResource*)data; + + XDBG_TRACE (MDA, "id(0x%08lx). \n", id); + + if (!resource) + return Success; + + if (!resource->pPort || !resource->pScrn) + return Success; + + SECDisplayVideoStop (resource->pScrn, (pointer)resource->pPort, 1); + + free(resource); + + return Success; +} + +static Bool +_secDisplayVideoRegisterEventResourceTypes (void) +{ + event_drawable_type = CreateNewResourceType (_secDisplayVideoRegisterEventDrawableGone, "Sec Video Drawable"); + + if (!event_drawable_type) + return FALSE; + + return TRUE; +} + +static int +SECDisplayVideoGetPortAttribute (ScrnInfoPtr pScrn, + Atom attribute, + INT32 *value, + pointer data) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr) data; + + if (attribute == _portAtom (PAA_OVERLAY)) + { + *value = pPort->overlay; + return Success; + } + + return BadMatch; +} + +static int +SECDisplayVideoSetPortAttribute (ScrnInfoPtr pScrn, + Atom attribute, + INT32 value, + pointer data) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr) data; + + if (attribute == _portAtom (PAA_OVERLAY)) + { + pPort->overlay = value; + XDBG_DEBUG (MDA, "overlay(%d) \n", value); + return Success; + } + + return BadMatch; +} + +static int +SECDisplayVideoGetStill (ScrnInfoPtr pScrn, + short vid_x, short vid_y, short drw_x, short drw_y, + short vid_w, short vid_h, short drw_w, short drw_h, + RegionPtr clipBoxes, pointer data, + DrawablePtr pDraw) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr) data; + SECVideoBuf *vbuf; + SECLayerOutput output; + SECLayerPos lpos; + + XDBG_RETURN_VAL_IF_FAIL (pDraw->type == DRAWABLE_PIXMAP, BadRequest); + + pPort->pScrn = pScrn; + + pPort->d.width = pDraw->width; + pPort->d.height = pDraw->height; + pPort->d.src.x = drw_x; + pPort->d.src.y = drw_y; + pPort->d.src.width = drw_w; + pPort->d.src.height = drw_h; + pPort->d.dst.x = vid_x; + pPort->d.dst.y = vid_y; + pPort->d.dst.width = drw_w; + pPort->d.dst.height = drw_h; + pPort->d.pDraw = pDraw; + + if (pPort->old_d.width != pPort->d.width || + pPort->old_d.height != pPort->d.height) + { + _secDisplayVideoHideLayer (pPort); + _secDisplayVideoCloseBuffers (pPort); + } + + if (!_secDisplayVideoAddDrawableEvent (pPort)) + return BadRequest; + + if (pPort->stream_cnt == 0) + { + pPort->stream_cnt++; + + XDBG_SECURE (MDA, "pPort(%d) sz(%dx%d) src(%d,%d %dx%d) dst(%d,%d %dx%d)\n", + pPort->index, pDraw->width, pDraw->height, + drw_x, drw_y, drw_w, drw_h, vid_x, vid_y, vid_w, vid_h); + } + + vbuf = _secDisplayVideoGetBuffer (pPort); + XDBG_RETURN_VAL_IF_FAIL (vbuf != NULL, BadRequest); + + if (pPort->overlay) + { + output = LAYER_OUTPUT_EXT; + lpos = LAYER_UPPER; + } + else + { + XDBG_ERROR (MDA, "pPort(%d) implemented for only overlay\n", pPort->index); + return BadRequest; + } + + if (!_secDisplayVideoShowLayer (pPort, vbuf, output, lpos)) + return BadRequest; + + pPort->old_d = pPort->d; + + return Success; +} + +static void +SECDisplayVideoStop (ScrnInfoPtr pScrn, pointer data, Bool exit) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr) data; + + XDBG_TRACE (MDA, "exit (%d) \n", exit); + + if (!exit) + return; + + _secDisplayVideoStreamOff (pPort); + + pPort->overlay = FALSE; +} + +static void +SECDisplayVideoQueryBestSize (ScrnInfoPtr pScrn, + Bool motion, + short vid_w, short vid_h, + short dst_w, short dst_h, + unsigned int *p_w, unsigned int *p_h, + pointer data) +{ + if (p_w) + *p_w = (unsigned int)dst_w & ~1; + if (p_h) + *p_h = (unsigned int)dst_h; +} + +XF86VideoAdaptorPtr +secVideoSetupDisplayVideo (ScreenPtr pScreen) +{ + XF86VideoAdaptorPtr pAdaptor; + SECPortPrivPtr pPort; + int i; + + pAdaptor = calloc (1, sizeof (XF86VideoAdaptorRec) + + (sizeof (DevUnion) + sizeof (SECPortPriv)) * SEC_MAX_PORT); + if (!pAdaptor) + return NULL; + + dummy_encoding[0].width = pScreen->width; + dummy_encoding[0].height = pScreen->height; + + pAdaptor->type = XvPixmapMask | XvOutputMask | XvStillMask; + pAdaptor->flags = VIDEO_OVERLAID_IMAGES; + pAdaptor->name = "SEC External Overlay Video"; + pAdaptor->nEncodings = sizeof (dummy_encoding) / sizeof (XF86VideoEncodingRec); + pAdaptor->pEncodings = dummy_encoding; + pAdaptor->nFormats = NUM_FORMATS; + pAdaptor->pFormats = formats; + pAdaptor->nPorts = SEC_MAX_PORT; + pAdaptor->pPortPrivates = (DevUnion*)(&pAdaptor[1]); + + pPort = (SECPortPrivPtr) (&pAdaptor->pPortPrivates[SEC_MAX_PORT]); + + for (i = 0; i < SEC_MAX_PORT; i++) + { + pAdaptor->pPortPrivates[i].ptr = &pPort[i]; + pPort[i].index = i; + } + + pAdaptor->nAttributes = NUM_ATTRIBUTES; + pAdaptor->pAttributes = attributes; + + pAdaptor->GetPortAttribute = SECDisplayVideoGetPortAttribute; + pAdaptor->SetPortAttribute = SECDisplayVideoSetPortAttribute; + pAdaptor->GetStill = SECDisplayVideoGetStill; + pAdaptor->StopVideo = SECDisplayVideoStop; + pAdaptor->QueryBestSize = SECDisplayVideoQueryBestSize; + + if (!_secDisplayVideoRegisterEventResourceTypes ()) + { + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "Failed to register EventResourceTypes. \n"); + return FALSE; + } + + return pAdaptor; +} diff --git a/src/xv/sec_video_display.h b/src/xv/sec_video_display.h new file mode 100644 index 0000000..96bb952 --- /dev/null +++ b/src/xv/sec_video_display.h @@ -0,0 +1,36 @@ +/************************************************************************** + +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. + +**************************************************************************/ +#ifndef __SEC_VIDEO_DISPLAY_H__ +#define __SEC_VIDEO_DISPLAY_H__ + +/* setup display adaptor */ +XF86VideoAdaptorPtr secVideoSetupDisplayVideo (ScreenPtr pScreen); + +#endif
\ No newline at end of file diff --git a/src/xv/sec_video_fourcc.h b/src/xv/sec_video_fourcc.h new file mode 100644 index 0000000..2023e49 --- /dev/null +++ b/src/xv/sec_video_fourcc.h @@ -0,0 +1,326 @@ +/************************************************************************** + +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. + +**************************************************************************/ + +#ifndef __SEC_VIDEO_FOURCC_H__ +#define __SEC_VIDEO_FOURCC_H__ + +#include <fourcc.h> +#include <drm_fourcc.h> + +#define C(b,m) (((b) >> (m)) & 0xFF) +#define B(c,s) ((((unsigned int)(c)) & 0xff) << (s)) +#define FOURCC(a,b,c,d) (B(d,24) | B(c,16) | B(b,8) | B(a,0)) +#define FOURCC_STR(id) C(id,0), C(id,8), C(id,16), C(id,24) +#define FOURCC_ID(str) FOURCC(((char*)str)[0],((char*)str)[1],((char*)str)[2],((char*)str)[3]) +#define IS_ZEROCOPY(id) ((C(id,0) == 'S') || id == FOURCC_ITLV) +#define IS_RGB(id) (id == FOURCC_RGB565 || id == FOURCC_RGB32 || \ + id == FOURCC_SR16 || id == FOURCC_SR32) + +/* Specific format for S.LSI + * 2x2 subsampled Cr:Cb plane 64x32 macroblocks + */ +#define DRM_FORMAT_NV12MT fourcc_code('T', 'M', '1', '2') + +/* http://www.fourcc.org/yuv.php + * http://en.wikipedia.org/wiki/YUV + */ +#define FOURCC_RGB565 FOURCC('R','G','B','P') +#define XVIMAGE_RGB565 \ + { \ + FOURCC_RGB565, \ + XvRGB, \ + LSBFirst, \ + {'R','G','B','P', \ + 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \ + 16, \ + XvPacked, \ + 1, \ + 16, 0x0000F800, 0x000007E0, 0x0000001F, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + {'R','G','B',0, \ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \ + XvTopToBottom \ + } + +#define FOURCC_SR16 FOURCC('S','R','1','6') +#define XVIMAGE_SR16 \ + { \ + FOURCC_SR16, \ + XvRGB, \ + LSBFirst, \ + {'S','R','1','6', \ + 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \ + 16, \ + XvPacked, \ + 1, \ + 16, 0x0000F800, 0x000007E0, 0x0000001F, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + {'R','G','B',0, \ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \ + XvTopToBottom \ + } + +#define FOURCC_RGB24 FOURCC('R','G','B','3') +#define XVIMAGE_RGB24 \ + { \ + FOURCC_RGB24, \ + XvRGB, \ + LSBFirst, \ + {'R','G','B','3', \ + 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \ + 24, \ + XvPacked, \ + 1, \ + 24, 0x00FF0000, 0x0000FF00, 0x000000FF, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + {'R','G','B',0, \ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \ + XvTopToBottom \ + } + +#define FOURCC_RGB32 FOURCC('R','G','B','4') +#define XVIMAGE_RGB32 \ + { \ + FOURCC_RGB32, \ + XvRGB, \ + LSBFirst, \ + {'R','G','B','4', \ + 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \ + 32, \ + XvPacked, \ + 1, \ + 24, 0x00FF0000, 0x0000FF00, 0x000000FF, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + {'X','R','G','B', \ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \ + XvTopToBottom \ + } + +#define FOURCC_SR32 FOURCC('S','R','3','2') +#define XVIMAGE_SR32 \ + { \ + FOURCC_SR32, \ + XvRGB, \ + LSBFirst, \ + {'S','R','3','2', \ + 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \ + 32, \ + XvPacked, \ + 1, \ + 24, 0x00FF0000, 0x0000FF00, 0x000000FF, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + {'X','R','G','B', \ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \ + XvTopToBottom \ + } + +#define FOURCC_ST12 FOURCC('S','T','1','2') +#define XVIMAGE_ST12 \ + { \ + FOURCC_ST12, \ + XvYUV, \ + LSBFirst, \ + {'S','T','1','2', \ + 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \ + 12, \ + XvPlanar, \ + 2, \ + 0, 0, 0, 0, \ + 8, 8, 8, \ + 1, 2, 2, \ + 1, 2, 2, \ + {'Y','U','V', \ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \ + XvTopToBottom \ + } + +#define FOURCC_SN12 FOURCC('S','N','1','2') +#define XVIMAGE_SN12 \ + { \ + FOURCC_SN12, \ + XvYUV, \ + LSBFirst, \ + {'S','N','1','2', \ + 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \ + 12, \ + XvPlanar, \ + 2, \ + 0, 0, 0, 0, \ + 8, 8, 8, \ + 1, 2, 2, \ + 1, 2, 2, \ + {'Y','U','V', \ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \ + XvTopToBottom \ + } + +#define FOURCC_NV12 FOURCC('N','V','1','2') +#define XVIMAGE_NV12 \ + { \ + FOURCC_NV12, \ + XvYUV, \ + LSBFirst, \ + {'N','V','1','2', \ + 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \ + 12, \ + XvPlanar, \ + 2, \ + 0, 0, 0, 0, \ + 8, 8, 8, \ + 1, 2, 2, \ + 1, 2, 2, \ + {'Y','U','V', \ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \ + XvTopToBottom \ + } + +#define FOURCC_SN21 FOURCC('S','N','2','1') +#define XVIMAGE_SN21 \ + { \ + FOURCC_SN21, \ + XvYUV, \ + LSBFirst, \ + {'S','N','2','1', \ + 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \ + 12, \ + XvPlanar, \ + 2, \ + 0, 0, 0, 0, \ + 8, 8, 8, \ + 1, 2, 2, \ + 1, 2, 2, \ + {'Y','V','U', \ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \ + XvTopToBottom \ + } + +#define FOURCC_NV21 FOURCC('N','V','2','1') +#define XVIMAGE_NV21 \ + { \ + FOURCC_NV21, \ + XvYUV, \ + LSBFirst, \ + {'N','V','2','1', \ + 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \ + 12, \ + XvPlanar, \ + 2, \ + 0, 0, 0, 0, \ + 8, 8, 8, \ + 1, 2, 2, \ + 1, 2, 2, \ + {'Y','V','U', \ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \ + XvTopToBottom \ + } + +#define FOURCC_S420 FOURCC('S','4','2','0') +#define XVIMAGE_S420 \ + { \ + FOURCC_S420, \ + XvYUV, \ + LSBFirst, \ + {'S','4','2','0', \ + 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \ + 12, \ + XvPlanar, \ + 3, \ + 0, 0, 0, 0, \ + 8, 8, 8, \ + 1, 2, 2, \ + 1, 2, 2, \ + {'Y','U','V', \ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \ + XvTopToBottom \ + } +#define FOURCC_SUYV FOURCC('S','U','Y','V') +#define XVIMAGE_SUYV \ + { \ + FOURCC_SUYV, \ + XvYUV, \ + LSBFirst, \ + {'S','U','Y','V', \ + 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \ + 16, \ + XvPacked, \ + 1, \ + 0, 0, 0, 0, \ + 8, 8, 8, \ + 1, 2, 2, \ + 1, 1, 1, \ + {'Y','U','Y','V', \ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \ + XvTopToBottom \ + } + +#define FOURCC_SYVY FOURCC('S','Y','V','Y') +#define XVIMAGE_SYVY \ + { \ + FOURCC_SYVY, \ + XvYUV, \ + LSBFirst, \ + {'S','Y','V','Y', \ + 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \ + 16, \ + XvPacked, \ + 1, \ + 0, 0, 0, 0, \ + 8, 8, 8, \ + 1, 2, 2, \ + 1, 1, 1, \ + {'U','Y','V','Y', \ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \ + XvTopToBottom \ + } + +#define FOURCC_ITLV FOURCC('I','T','L','V') +#define XVIMAGE_ITLV \ + { \ + FOURCC_ITLV, \ + XvYUV, \ + LSBFirst, \ + {'I','T','L','V', \ + 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \ + 16, \ + XvPacked, \ + 1, \ + 0, 0, 0, 0, \ + 8, 8, 8, \ + 1, 2, 2, \ + 1, 1, 1, \ + {'U','Y','V','Y', \ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \ + XvTopToBottom \ + } + +#define FOURCC_Y444 FOURCC('Y','4','4','4') + + +#endif // __SEC_VIDEO_FOURCC_H__ diff --git a/src/xv/sec_video_tvout.c b/src/xv/sec_video_tvout.c new file mode 100644 index 0000000..20492ce --- /dev/null +++ b/src/xv/sec_video_tvout.c @@ -0,0 +1,529 @@ +/************************************************************************** + +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 "sec.h" +#include "sec_display.h" +#include "sec_crtc.h" +#include "sec_output.h" +#include "sec_accel.h" +#include "sec_util.h" +#include "sec_converter.h" +#include "sec_video_tvout.h" +#include "sec_video_virtual.h" +#include "sec_video_fourcc.h" +#include "sec_drm_ipp.h" +#include "sec_layer.h" +#include "sec_prop.h" + +#include <sys/ioctl.h> +#include <exynos_drm.h> +#include <drm_fourcc.h> + +#define TVBUF_NUM 3 + +/* HW restriction (VP) */ +#define MIN_WIDTH 32 +#define MIN_HEIGHT 4 +#define MAX_WIDTH 1920 +#define MAX_HEIGHT 1080 +#define MIN_SCALE 0.25 +#define MAX_SCALE 16.0 + +/* private structure */ +struct _SECVideoTv +{ + ScrnInfoPtr pScrn; + + SECLayer *layer; + SECLayerPos lpos; + + /* used if id is not supported in case of lpos == LAYER_LOWER1. */ + SECCvt *cvt; + SECVideoBuf **outbuf; + int outbuf_index; + int outbuf_num; + + int tv_width; + int tv_height; + + xRectangle tv_rect; + + unsigned int convert_id; +}; + +static Bool +_secVieoTvCalSize (SECVideoTv* tv, int src_w, int src_h, int dst_w, int dst_h) +{ + float r; + + if (src_w < MIN_WIDTH || src_h < MIN_HEIGHT) + { + XDBG_WARNING (MTVO, "size(%dx%d) must be more than (%dx%d).\n", + src_w, src_h, MIN_WIDTH, MAX_WIDTH); + } + + r = (float)dst_w / src_w; + if (r < MIN_SCALE || r > MAX_SCALE) + { + XDBG_WARNING (MTVO, "ratio_w(%f) is out of range(%f~%f).\n", + r, MIN_SCALE, MAX_SCALE); + } + + r = (float)dst_h / src_h; + if (r < MIN_SCALE || r > MAX_SCALE) + { + XDBG_WARNING (MTVO, "ratio_h(%d) is out of range(%f~%f).\n", + r, MIN_SCALE, MAX_SCALE); + } + + return TRUE; +} + +static SECVideoBuf* +_secVideoTvGetOutBuffer (SECVideoTv* tv, int width, int height, Bool secure) +{ + int i = tv->outbuf_index, j; + + if (!tv->outbuf) + { + tv->outbuf = (SECVideoBuf**)calloc (tv->outbuf_num, sizeof (SECVideoBuf*)); + XDBG_RETURN_VAL_IF_FAIL (tv->outbuf != NULL, NULL); + } + + i++; + if (i >= tv->outbuf_num) + i = 0; + + for (j = 0; j < tv->outbuf_num; j++) + { + if (tv->outbuf[i]) + { + XDBG_DEBUG (MTVO, "outbuf(%p) converting(%d) showing(%d)\n", + tv->outbuf[i], VBUF_IS_CONVERTING (tv->outbuf[i]), tv->outbuf[i]->showing); + + if (tv->outbuf[i] && !VBUF_IS_CONVERTING (tv->outbuf[i]) && !tv->outbuf[i]->showing) + { + tv->outbuf_index = i; + return tv->outbuf[i]; + } + } + else + { + SECPtr pSec = SECPTR (tv->pScrn); + + tv->outbuf[i] = secUtilAllocVideoBuffer (tv->pScrn, tv->convert_id, width, height, + (pSec->scanout)?TRUE:FALSE, TRUE, secure); + XDBG_RETURN_VAL_IF_FAIL (tv->outbuf[i] != NULL, NULL); + + XDBG_DEBUG (MTVO, "outbuf(%p, %c%c%c%c)\n", tv->outbuf[i], FOURCC_STR (tv->convert_id)); + + tv->outbuf_index = i; + return tv->outbuf[i]; + } + + i++; + if (i >= tv->outbuf_num) + i = 0; + } + +#if 0 + char buffers[1024]; + CLEAR (buffers); + for (j = 0; j < tv->outbuf_num; j++) + { + if (tv->outbuf[j]) + snprintf (buffers, 1024, "%s %d(%d,%d) ", buffers, tv->outbuf[j]->keys[0], + VBUF_IS_CONVERTING (tv->outbuf[j]), tv->outbuf[j]->showing); + } + + XDBG_ERROR (MTVO, "now all outbufs in use! %s\n", buffers); +#else + XDBG_ERROR (MTVO, "now all outbufs in use!\n"); +#endif + + return NULL; +} + +static Bool +_secVideoTvLayerEnsure (SECVideoTv* tv) +{ + SECLayer *layer; + + if (tv->layer) + return TRUE; + + XDBG_RETURN_VAL_IF_FAIL (tv->lpos != LAYER_NONE, FALSE); + + layer = secLayerCreate (tv->pScrn, LAYER_OUTPUT_EXT, tv->lpos); + XDBG_RETURN_VAL_IF_FAIL (layer != NULL, FALSE); + + tv->layer = layer; + + return TRUE; +} + +static void +_secVideoTvLayerDestroy (SECVideoTv* tv) +{ + if (tv->layer) + { + secLayerUnref (tv->layer); + tv->layer = NULL; + } +} + +static int +_secVideoTvPutImageInternal (SECVideoTv *tv, SECVideoBuf *vbuf, xRectangle *rect) +{ + int ret = 0; + + XDBG_DEBUG (MTVO, "rect (%d,%d %dx%d) \n", + rect->x, rect->y, rect->width, rect->height); + + secLayerSetRect (tv->layer, &vbuf->crop, rect); + + if (tv->lpos == LAYER_LOWER1) + if (!_secVieoTvCalSize (tv, vbuf->width, vbuf->height, + rect->width, rect->height)) + return 0; + + ret = secLayerSetBuffer (tv->layer, vbuf); + + if (ret == 0) + return 0; + + secLayerShow (tv->layer); + + return ret; +} + +static void +_secVideoTvCvtCallback (SECCvt *cvt, + SECVideoBuf *src, + SECVideoBuf *dst, + void *cvt_data, + Bool error) +{ + SECVideoTv *tv = (SECVideoTv*)cvt_data; + int i; + + XDBG_RETURN_IF_FAIL (tv != NULL); + XDBG_RETURN_IF_FAIL (cvt != NULL); + XDBG_RETURN_IF_FAIL (VBUF_IS_VALID (dst)); + + XDBG_DEBUG (MTVO, "++++++++++++++++++++++++ \n"); + + for (i = 0; i < tv->outbuf_num; i++) + if (tv->outbuf[i] == dst) + break; + XDBG_RETURN_IF_FAIL (i < tv->outbuf_num); + + _secVideoTvPutImageInternal (tv, dst, &tv->tv_rect); + + XDBG_DEBUG (MTVO, "++++++++++++++++++++++++.. \n"); +} + +SECVideoTv* +secVideoTvConnect (ScrnInfoPtr pScrn, unsigned int id, SECLayerPos lpos) +{ + SECVideoTv* tv = NULL; + SECModePtr pSecMode; + + XDBG_RETURN_VAL_IF_FAIL (pScrn != NULL, NULL); + XDBG_RETURN_VAL_IF_FAIL (lpos >= LAYER_LOWER1 && lpos <= LAYER_UPPER, NULL); + XDBG_RETURN_VAL_IF_FAIL (id > 0, NULL); + + tv = calloc (sizeof (SECVideoTv), 1); + XDBG_RETURN_VAL_IF_FAIL (tv != NULL, NULL); + + pSecMode = (SECModePtr) SECPTR (pScrn)->pSecMode; + + if (lpos == LAYER_LOWER1 && pSecMode->conn_mode == DISPLAY_CONN_MODE_VIRTUAL) + { + /* In case of video-only(virtual), we always use converter. */ + tv->cvt = secCvtCreate (pScrn, CVT_OP_M2M); + XDBG_GOTO_IF_FAIL (tv->cvt != NULL, fail_connect); + + secCvtAddCallback (tv->cvt, _secVideoTvCvtCallback, tv); + } + else if (lpos == LAYER_LOWER1 && pSecMode->conn_mode == DISPLAY_CONN_MODE_HDMI) + { + if (!secLayerSupport (pScrn, LAYER_OUTPUT_EXT, lpos, id)) + { + /* used if id is not supported in case of lpos == LAYER_LOWER1. */ + tv->cvt = secCvtCreate (pScrn, CVT_OP_M2M); + XDBG_GOTO_IF_FAIL (tv->cvt != NULL, fail_connect); + + secCvtAddCallback (tv->cvt, _secVideoTvCvtCallback, tv); + } + } + + XDBG_DEBUG (MTVO, "id(%c%c%c%c), lpos(%d)!\n", FOURCC_STR (id), lpos); + + tv->pScrn = pScrn; + tv->lpos = lpos; + tv->outbuf_index = -1; + tv->convert_id = FOURCC_RGB32; + tv->outbuf_num = TVBUF_NUM; + + return tv; + +fail_connect: + if (tv) + { + if (tv->cvt) + secCvtDestroy (tv->cvt); + free (tv); + } + return NULL; +} + +void +secVideoTvDisconnect (SECVideoTv* tv) +{ + int i; + + XDBG_RETURN_IF_FAIL (tv != NULL); + + XDBG_DEBUG (MTVO, "!\n"); + + if (tv->cvt) + secCvtDestroy (tv->cvt); + + _secVideoTvLayerDestroy (tv); + + if (tv->outbuf) + { + for (i = 0; i < tv->outbuf_num; i++) + if (tv->outbuf[i]) + secUtilVideoBufferUnref (tv->outbuf[i]); + + free (tv->outbuf); + } + + free (tv); +} + +Bool +secVideoTvSetBuffer (SECVideoTv* tv, SECVideoBuf **vbufs, int bufnum) +{ + int i; + + XDBG_RETURN_VAL_IF_FAIL (tv != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (vbufs != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (bufnum >= TVBUF_NUM, FALSE); + + if (tv->outbuf) + { + XDBG_ERROR (MTVO, "already has buffers.\n"); + return FALSE; + } + + tv->outbuf_num = bufnum; + tv->outbuf = (SECVideoBuf**)calloc (bufnum, sizeof (SECVideoBuf*)); + XDBG_RETURN_VAL_IF_FAIL (tv->outbuf != NULL, FALSE); + + for (i = 0; i < tv->outbuf_num; i++) + { + XDBG_GOTO_IF_FAIL (tv->convert_id == vbufs[i]->id, fail_set_buffer); + XDBG_GOTO_IF_FAIL (tv->tv_width == vbufs[i]->width, fail_set_buffer); + XDBG_GOTO_IF_FAIL (tv->tv_height == vbufs[i]->height, fail_set_buffer); + + tv->outbuf[i] = secUtilVideoBufferRef (vbufs[i]); + XDBG_GOTO_IF_FAIL (tv->outbuf[i] != NULL, fail_set_buffer); + + if (!tv->outbuf[i]->showing && tv->outbuf[i]->need_reset) + secUtilClearVideoBuffer (tv->outbuf[i]); + else + tv->outbuf[i]->need_reset = TRUE; + } + + return TRUE; + +fail_set_buffer: + if (tv->outbuf) + { + for (i = 0; i < tv->outbuf_num; i++) + { + if (tv->outbuf[i]) + { + secUtilVideoBufferUnref (tv->outbuf[i]); + tv->outbuf[i] = NULL; + } + } + + free (tv->outbuf); + tv->outbuf = NULL; + } + + return FALSE; +} +SECLayerPos +secVideoTvGetPos (SECVideoTv *tv) +{ + XDBG_RETURN_VAL_IF_FAIL (tv != NULL, LAYER_NONE); + + return tv->lpos; +} + +SECLayer* +secVideoTvGetLayer (SECVideoTv *tv) +{ + XDBG_RETURN_VAL_IF_FAIL (tv != NULL, NULL); + + _secVideoTvLayerEnsure (tv); + + return tv->layer; +} + +/* HDMI : 'handles' is "gem handle" + * VIRTUAL : 'handles' is "physical address" + * 'data' is "raw data" + * only one of 'handles' and 'data' has value. + */ +int +secVideoTvPutImage (SECVideoTv *tv, SECVideoBuf *vbuf, xRectangle *rect, int csc_range) +{ + XDBG_RETURN_VAL_IF_FAIL (tv != NULL, 0); + XDBG_RETURN_VAL_IF_FAIL (VBUF_IS_VALID (vbuf), 0); + XDBG_RETURN_VAL_IF_FAIL (vbuf->id > 0, 0); + XDBG_RETURN_VAL_IF_FAIL (rect != NULL, 0); + + XDBG_RETURN_VAL_IF_FAIL (vbuf->handles[0] > 0, 0); + XDBG_RETURN_VAL_IF_FAIL (vbuf->pitches[0] > 0, 0); + + _secVideoTvLayerEnsure (tv); + XDBG_RETURN_VAL_IF_FAIL (tv->layer != NULL, 0); + + if (tv->cvt) + { + /* can't show buffer to HDMI at now. */ + SECModePtr pSecMode = (SECModePtr) SECPTR (tv->pScrn)->pSecMode; + SECCvtProp src_prop = {0,}, dst_prop = {0,}; + SECVideoBuf *outbuf; + int dst_width, dst_height; + xRectangle dst_crop; + + + /* CHECK */ + if (pSecMode->conn_mode == DISPLAY_CONN_MODE_VIRTUAL) + { + XDBG_RETURN_VAL_IF_FAIL (tv->tv_width > 0, 0); + XDBG_RETURN_VAL_IF_FAIL (tv->tv_height > 0, 0); + dst_width = tv->tv_width; + dst_height = tv->tv_height; + dst_crop = *rect; + + tv->tv_rect.x = 0; + tv->tv_rect.y = 0; + tv->tv_rect.width = tv->tv_width; + tv->tv_rect.height = tv->tv_height; + } + else + { + dst_width = rect->width; + dst_height = rect->height; + dst_crop = *rect; + dst_crop.x = 0; + dst_crop.y = 0; + + tv->tv_rect = *rect; + } + + src_prop.id = vbuf->id; + src_prop.width = vbuf->width; + src_prop.height = vbuf->height; + src_prop.crop = vbuf->crop; + + dst_prop.id = tv->convert_id; + dst_prop.width = dst_width; + dst_prop.height = dst_height; + dst_prop.crop = dst_crop; + dst_prop.secure = vbuf->secure; + dst_prop.csc_range = csc_range; + + if (!secCvtEnsureSize (&src_prop, &dst_prop)) + return 0; + + outbuf = _secVideoTvGetOutBuffer (tv, dst_prop.width, dst_prop.height, vbuf->secure); + if (!outbuf) + return 0; + outbuf->crop = dst_prop.crop; + + if (!secCvtSetProperpty (tv->cvt, &src_prop, &dst_prop)) + return 0; + + if (!secCvtConvert (tv->cvt, vbuf, outbuf)) + return 0; + + XDBG_TRACE (MTVO, "'%c%c%c%c' %dx%d (%d,%d %dx%d) => '%c%c%c%c' %dx%d (%d,%d %dx%d) convert. rect(%d,%d %dx%d)\n", + FOURCC_STR (vbuf->id), vbuf->width, vbuf->height, + vbuf->crop.x, vbuf->crop.y, vbuf->crop.width, vbuf->crop.height, + FOURCC_STR (outbuf->id), outbuf->width, outbuf->height, + outbuf->crop.x, outbuf->crop.y, outbuf->crop.width, outbuf->crop.height, + rect->x, rect->y, rect->width, rect->height); + + return 1; + } + + /* can show buffer to HDMI at now. */ + + return _secVideoTvPutImageInternal (tv, vbuf, rect); +} + +void +secVideoTvSetSize (SECVideoTv *tv, int width, int height) +{ + XDBG_RETURN_IF_FAIL (tv != NULL); + + tv->tv_width = width; + tv->tv_height = height; + + XDBG_TRACE (MTVO, "size(%dx%d) \n", width, height); +} + +SECCvt* +secVideoTvGetConverter (SECVideoTv *tv) +{ + XDBG_RETURN_VAL_IF_FAIL (tv != NULL, NULL); + + return tv->cvt; +} + +void +secVideoTvSetConvertFormat (SECVideoTv *tv, unsigned int convert_id) +{ + XDBG_RETURN_IF_FAIL (tv != NULL); + XDBG_RETURN_IF_FAIL (convert_id > 0); + + tv->convert_id = convert_id; + + XDBG_TRACE (MTVO, "convert_id(%c%c%c%c) \n", FOURCC_STR (convert_id)); +} diff --git a/src/xv/sec_video_tvout.h b/src/xv/sec_video_tvout.h new file mode 100644 index 0000000..9c88dc4 --- /dev/null +++ b/src/xv/sec_video_tvout.h @@ -0,0 +1,56 @@ +/************************************************************************** + +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. + +**************************************************************************/ + +#ifndef __SEC_VIDEO_TVOUT_H__ +#define __SEC_VIDEO_TVOUT_H__ + +#include <xf86str.h> +#include <X11/Xdefs.h> +#include "sec_layer.h" +#include "sec_converter.h" +#include "sec_video_types.h" + +typedef struct _SECVideoTv SECVideoTv; + +SECVideoTv* secVideoTvConnect (ScrnInfoPtr pScrn, unsigned int id, SECLayerPos lpos); +void secVideoTvDisconnect (SECVideoTv *tv); + +Bool secVideoTvSetBuffer (SECVideoTv* tv, SECVideoBuf **vbufs, int bufnum); + +SECLayerPos secVideoTvGetPos (SECVideoTv *tv); +SECLayer* secVideoTvGetLayer (SECVideoTv *tv); + +void secVideoTvSetSize (SECVideoTv *tv, int width, int height); +int secVideoTvPutImage (SECVideoTv *tv, SECVideoBuf *vbuf, xRectangle *dst, int csc_range); + +SECCvt* secVideoTvGetConverter (SECVideoTv *tv); +void secVideoTvSetConvertFormat (SECVideoTv *tv, unsigned int convert_id); + +#endif /* __SEC_VIDEO_TVOUT_H__ */ diff --git a/src/xv/sec_video_types.h b/src/xv/sec_video_types.h new file mode 100644 index 0000000..1afe0fb --- /dev/null +++ b/src/xv/sec_video_types.h @@ -0,0 +1,168 @@ +/************************************************************************** + +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. + +**************************************************************************/ + +#ifndef __SEC_V4L2_TYPES_H__ +#define __SEC_V4L2_TYPES_H__ + +#include <sys/types.h> +#include <fbdevhw.h> +#include <X11/Xdefs.h> +#include <tbm_bufmgr.h> +#include <exynos_drm.h> + +/* securezone memory */ +#define TZMEM_IOC_GET_TZMEM 0xC00C5402 +struct tzmem_get_region +{ + const char *key; + unsigned int size; + int fd; +}; + +/************************************************************ + * DEFINITION + ************************************************************/ +#ifndef CLEAR +#define CLEAR(x) memset(&(x), 0, sizeof (x)) +#endif + +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef SWAP +#define SWAP(a, b) ({int t; t = a; a = b; b = t;}) +#endif + +#ifndef ROUNDUP +#define ROUNDUP(x) (ceil (floor ((float)(height) / 4))) +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +enum fimc_overlay_mode { + FIMC_OVLY_NOT_FIXED = 0, + FIMC_OVLY_FIFO, + FIMC_OVLY_DMA_AUTO, + FIMC_OVLY_DMA_MANUAL, + FIMC_OVLY_NONE_SINGLE_BUF, + FIMC_OVLY_NONE_MULTI_BUF, +}; + +#define ALIGN_TO_16B(x) ((((x) + (1 << 4) - 1) >> 4) << 4) +#define ALIGN_TO_32B(x) ((((x) + (1 << 5) - 1) >> 5) << 5) +#define ALIGN_TO_128B(x) ((((x) + (1 << 7) - 1) >> 7) << 7) +#define ALIGN_TO_2KB(x) ((((x) + (1 << 11) - 1) >> 11) << 11) +#define ALIGN_TO_8KB(x) ((((x) + (1 << 13) - 1) >> 13) << 13) +#define ALIGN_TO_64KB(x) ((((x) + (1 << 16) - 1) >> 16) << 16) + +#define PLANAR_CNT EXYNOS_DRM_PLANAR_MAX + +/************************************************************ + * TYPE DEFINITION + ************************************************************/ + +#ifndef uchar +typedef unsigned char uchar; +#endif + +typedef enum +{ + TYPE_NONE, + TYPE_RGB, + TYPE_YUV444, + TYPE_YUV422, + TYPE_YUV420, +} SECFormatType; + +typedef struct _SECFormatTable +{ + unsigned int id; + unsigned int drmfmt; + SECFormatType type; +} SECFormatTable; + +typedef struct _ConvertInfo +{ + void *cvt; + struct xorg_list link; +} ConvertInfo; + +typedef struct _SECVideoBuf +{ + ScrnInfoPtr pScrn; + int id; + + int width; + int height; + xRectangle crop; + + int pitches[PLANAR_CNT]; + int offsets[PLANAR_CNT]; + int lengths[PLANAR_CNT]; + int size; + + tbm_bo bo[PLANAR_CNT]; + unsigned int keys[PLANAR_CNT]; + unsigned int phy_addrs[PLANAR_CNT]; + unsigned int handles[PLANAR_CNT]; + + struct xorg_list convert_info; + Bool showing; /* now showing or now waiting to show. */ + Bool dirty; + Bool need_reset; + + unsigned int fb_id; /* fb_id of vbuf */ + + struct xorg_list free_funcs; + + Bool secure; + int csc_range; + + struct xorg_list valid_link; /* to check valid */ + CARD32 stamp; + unsigned int ref_cnt; + char *func; + int flags; + Bool scanout; + + CARD32 put_time; +} SECVideoBuf; + +#endif diff --git a/src/xv/sec_video_virtual.c b/src/xv/sec_video_virtual.c new file mode 100644 index 0000000..fac74b8 --- /dev/null +++ b/src/xv/sec_video_virtual.c @@ -0,0 +1,2066 @@ +/* + * xserver-xorg-video-exynos + * + * Copyright 2004 Keith Packard + * Copyright 2005 Eric Anholt + * Copyright 2006 Nokia Corporation + * Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved. + * + * Contact: Boram Park <boram1288.park@samsung.com> + * + * Permission to use, copy, modify, distribute and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the names of the authors and/or copyright holders + * not be used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. The authors and + * copyright holders make no representations about the suitability of this + * software for any purpose. It is provided "as is" without any express + * or implied warranty. + * + * THE AUTHORS AND COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pixman.h> +#include <X11/Xatom.h> +#include <X11/extensions/Xv.h> + +#include "sec.h" +#include "sec_util.h" +#include "sec_wb.h" +#include "sec_crtc.h" +#include "sec_converter.h" +#include "sec_output.h" +#include "sec_video.h" +#include "sec_video_fourcc.h" +#include "sec_video_virtual.h" +#include "sec_video_tvout.h" +#include "sec_display.h" +#include "sec_xberc.h" + +#include "xv_types.h" + +#define DEV_INDEX 2 +#define BUF_NUM_EXTERNAL 5 +#define BUF_NUM_STREAM 3 + +enum +{ + CAPTURE_MODE_NONE, + CAPTURE_MODE_STILL, + CAPTURE_MODE_STREAM, + CAPTURE_MODE_MAX, +}; + +enum +{ + DISPLAY_LCD, + DISPLAY_EXTERNAL, +}; + +enum +{ + DATA_TYPE_UI, + DATA_TYPE_VIDEO, + DATA_TYPE_MAX, +}; + +static unsigned int support_formats[] = +{ + FOURCC_RGB32, + FOURCC_ST12, + FOURCC_SN12, +}; + +static XF86VideoEncodingRec dummy_encoding[] = +{ + { 0, "XV_IMAGE", -1, -1, { 1, 1 } }, + { 1, "XV_IMAGE", 2560, 2560, { 1, 1 } }, +}; + +static XF86ImageRec images[] = +{ + XVIMAGE_RGB32, + XVIMAGE_SN12, + XVIMAGE_ST12, +}; + +static XF86VideoFormatRec formats[] = +{ + { 16, TrueColor }, + { 24, TrueColor }, + { 32, TrueColor }, +}; + +static XF86AttributeRec attributes[] = +{ + { 0, 0, 0x7fffffff, "_USER_WM_PORT_ATTRIBUTE_FORMAT" }, + { 0, 0, CAPTURE_MODE_MAX, "_USER_WM_PORT_ATTRIBUTE_CAPTURE" }, + { 0, 0, 1, "_USER_WM_PORT_ATTRIBUTE_DISPLAY" }, + { 0, 0, 1, "_USER_WM_PORT_ATTRIBUTE_ROTATE_OFF" }, + { 0, 0, DATA_TYPE_MAX, "_USER_WM_PORT_ATTRIBUTE_DATA_TYPE" }, + { 0, 0, 1, "_USER_WM_PORT_ATTRIBUTE_SECURE" }, + { 0, 0, 0x7fffffff, "_USER_WM_PORT_ATTRIBUTE_RETURN_BUFFER" }, +}; + +typedef enum +{ + PAA_MIN, + PAA_FORMAT, + PAA_CAPTURE, + PAA_DISPLAY, + PAA_ROTATE_OFF, + PAA_DATA_TYPE, + PAA_SECURE, + PAA_RETBUF, + PAA_MAX +} SECPortAttrAtom; + +static struct +{ + SECPortAttrAtom paa; + const char *name; + Atom atom; +} atoms[] = +{ + { PAA_FORMAT, "_USER_WM_PORT_ATTRIBUTE_FORMAT", None }, + { PAA_CAPTURE, "_USER_WM_PORT_ATTRIBUTE_CAPTURE", None }, + { PAA_DISPLAY, "_USER_WM_PORT_ATTRIBUTE_DISPLAY", None }, + { PAA_ROTATE_OFF, "_USER_WM_PORT_ATTRIBUTE_ROTATE_OFF", None }, + { PAA_DATA_TYPE, "_USER_WM_PORT_ATTRIBUTE_DATA_TYPE", None }, + { PAA_SECURE, "_USER_WM_PORT_ATTRIBUTE_SECURE", None }, + { PAA_RETBUF, "_USER_WM_PORT_ATTRIBUTE_RETURN_BUFFER", None }, +}; + +typedef struct _RetBufInfo +{ + SECVideoBuf *vbuf; + int type; + struct xorg_list link; +} RetBufInfo; + +/* SEC port information structure */ +typedef struct +{ + /* index */ + int index; + + /* port attribute */ + int id; + int capture; + int display; + Bool secure; + Bool data_type; + Bool rotate_off; + + /* information from outside */ + ScrnInfoPtr pScrn; + DrawablePtr pDraw; + RegionPtr clipBoxes; + + /* writeback */ + SECWb *wb; + + /* video */ + SECCvt *cvt; + + SECVideoBuf *dstbuf; + SECVideoBuf **outbuf; + int outbuf_num; + int outbuf_index; + + struct xorg_list retbuf_info; + Bool need_damage; + + OsTimerPtr retire_timer; + Bool putstill_on; + + unsigned int status; + CARD32 retire_time; + CARD32 prev_time; + + struct xorg_list link; +} SECPortPriv, *SECPortPrivPtr; + +static RESTYPE event_drawable_type; + +typedef struct _SECVideoResource +{ + XID id; + RESTYPE type; + SECPortPrivPtr pPort; + ScrnInfoPtr pScrn; +} SECVideoResource; + +#define SEC_MAX_PORT 1 + +#define NUM_IMAGES (sizeof(images) / sizeof(images[0])) +#define NUM_FORMATS (sizeof(formats) / sizeof(formats[0])) +#define NUM_ATTRIBUTES (sizeof(attributes) / sizeof(attributes[0])) +#define NUM_ATOMS (sizeof(atoms) / sizeof(atoms[0])) + +static DevPrivateKeyRec video_virtual_port_key; +#define VideoVirtualPortKey (&video_virtual_port_key) +#define GetPortInfo(pDraw) ((SECVideoPortInfo*)dixLookupPrivate(&(pDraw)->devPrivates, VideoVirtualPortKey)) + +typedef struct _SECVideoPortInfo +{ + ClientPtr client; + XvPortPtr pp; +} SECVideoPortInfo; + +static int (*ddPutStill) (ClientPtr, DrawablePtr, struct _XvPortRec *, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); + +static void SECVirtualVideoStop (ScrnInfoPtr pScrn, pointer data, Bool exit); +static void _secVirtualVideoCloseOutBuffer (SECPortPrivPtr pPort); +static void _secVirtualVideoLayerNotifyFunc (SECLayer *layer, int type, void *type_data, void *data); +static void _secVirtualVideoWbDumpFunc (SECWb *wb, SECWbNotify noti, void *noti_data, void *user_data); +static void _secVirtualVideoWbStopFunc (SECWb *wb, SECWbNotify noti, void *noti_data, void *user_data); +static SECVideoBuf* _secVirtualVideoGetBlackBuffer (SECPortPrivPtr pPort); +static Bool _secVirtualVideoEnsureOutBuffers (ScrnInfoPtr pScrn, SECPortPrivPtr pPort, int id, int width, int height); +static void _secVirtualVideoWbCloseFunc (SECWb *wb, SECWbNotify noti, void *noti_data, void *user_data); + +static SECVideoPortInfo* +_port_info (DrawablePtr pDraw) +{ + if (!pDraw) + return NULL; + + if (pDraw->type == DRAWABLE_WINDOW) + return GetPortInfo ((WindowPtr)pDraw); + else + return GetPortInfo ((PixmapPtr)pDraw); +} + +static Atom +_secVideoGetPortAtom (SECPortAttrAtom paa) +{ + int i; + + XDBG_RETURN_VAL_IF_FAIL (paa > PAA_MIN && paa < PAA_MAX, None); + + for (i = 0; i < NUM_ATOMS; i++) + { + if (paa == atoms[i].paa) + { + if (atoms[i].atom == None) + atoms[i].atom = MakeAtom (atoms[i].name, + strlen (atoms[i].name), TRUE); + + return atoms[i].atom; + } + } + + XDBG_ERROR (MVA, "Error: Unknown Port Attribute Name!\n"); + + return None; +} + +static void +_secVirtualVideoSetSecure (SECPortPrivPtr pPort, Bool secure) +{ + SECVideoPortInfo *info; + + secure = (secure > 0) ? TRUE : FALSE; + + if (pPort->secure == secure) + return; + + pPort->secure = secure; + + XDBG_TRACE (MVA, "secure(%d) \n", secure); + + info = _port_info (pPort->pDraw); + if (!info || !info->pp) + return; + + XvdiSendPortNotify (info->pp, _secVideoGetPortAtom (PAA_SECURE), secure); +} + +static PixmapPtr +_secVirtualVideoGetPixmap (DrawablePtr pDraw) +{ + if (pDraw->type == DRAWABLE_WINDOW) + return pDraw->pScreen->GetWindowPixmap ((WindowPtr) pDraw); + else + return (PixmapPtr) pDraw; +} + +static Bool +_secVirtualVideoIsSupport (unsigned int id) +{ + int i; + + for (i = 0; i < sizeof (support_formats) / sizeof (unsigned int); i++) + if (support_formats[i] == id) + return TRUE; + + return FALSE; +} + +#if 0 +static char buffers[1024]; + +static void +_buffers (SECPortPrivPtr pPort) +{ + RetBufInfo *cur = NULL, *next = NULL; + + CLEAR (buffers); + xorg_list_for_each_entry_safe (cur, next, &pPort->retbuf_info, link) + { + if (cur->vbuf) + snprintf (buffers, 1024, "%s %d", buffers, cur->vbuf->keys[0]); + } +} +#endif + +static RetBufInfo* +_secVirtualVideoFindReturnBuf (SECPortPrivPtr pPort, unsigned int key) +{ + RetBufInfo *cur = NULL, *next = NULL; + + XDBG_RETURN_VAL_IF_FAIL (pPort->capture != CAPTURE_MODE_STILL, NULL); + + xorg_list_for_each_entry_safe (cur, next, &pPort->retbuf_info, link) + { + if (cur->vbuf && cur->vbuf->keys[0] == key) + return cur; + } + + return NULL; +} + +static Bool +_secVirtualVideoAddReturnBuf (SECPortPrivPtr pPort, SECVideoBuf *vbuf) +{ + RetBufInfo *info; + + XDBG_RETURN_VAL_IF_FAIL (pPort->capture != CAPTURE_MODE_STILL, FALSE); + + info = _secVirtualVideoFindReturnBuf (pPort, vbuf->keys[0]); + XDBG_RETURN_VAL_IF_FAIL (info == NULL, FALSE); + + info = calloc (1, sizeof (RetBufInfo)); + XDBG_RETURN_VAL_IF_FAIL (info != NULL, FALSE); + + info->vbuf = secUtilVideoBufferRef (vbuf); + XDBG_GOTO_IF_FAIL (info->vbuf != NULL, fail); + info->vbuf->showing = TRUE; + + XDBG_DEBUG (MVA, "retbuf (%ld,%d,%d,%d) added.\n", vbuf->stamp, + vbuf->keys[0], vbuf->keys[1], vbuf->keys[2]); + + xorg_list_add (&info->link, &pPort->retbuf_info); + + return TRUE; + +fail : + if (info) + free (info); + + return FALSE; +} + +static void +_secVirtualVideoRemoveReturnBuf (SECPortPrivPtr pPort, RetBufInfo *info) +{ + XDBG_RETURN_IF_FAIL (pPort->capture != CAPTURE_MODE_STILL); + XDBG_RETURN_IF_FAIL (info != NULL); + XDBG_RETURN_IF_FAIL (info->vbuf != NULL); + + info->vbuf->showing = FALSE; + + XDBG_DEBUG (MVA, "retbuf (%ld,%d,%d,%d) removed.\n", info->vbuf->stamp, + info->vbuf->keys[0], info->vbuf->keys[1], info->vbuf->keys[2]); + + if (pPort->wb) + secWbQueueBuffer (pPort->wb, info->vbuf); + + secUtilVideoBufferUnref (info->vbuf); + xorg_list_del (&info->link); + free (info); +} + +static void +_secVirtualVideoRemoveReturnBufAll (SECPortPrivPtr pPort) +{ + RetBufInfo *cur = NULL, *next = NULL; + + XDBG_RETURN_IF_FAIL (pPort->capture != CAPTURE_MODE_STILL); + + xorg_list_for_each_entry_safe (cur, next, &pPort->retbuf_info, link) + { + _secVirtualVideoRemoveReturnBuf (pPort, cur); + } +} + +static void +_secVirtualVideoDraw (SECPortPrivPtr pPort, SECVideoBuf *buf) +{ + if (pPort->retire_timer) + { + TimerFree (pPort->retire_timer); + pPort->retire_timer = NULL; + } + + if (!pPort->pDraw) + { + XDBG_TRACE (MVA, "drawable gone!\n"); + return; + } + + XDBG_RETURN_IF_FAIL (pPort->need_damage == TRUE); + XDBG_GOTO_IF_FAIL (VBUF_IS_VALID (buf), draw_done); + + XDBG_TRACE (MVA, "%c%c%c%c, %dx%d. \n", + FOURCC_STR (buf->id), buf->width, buf->height); + + if (pPort->id == FOURCC_RGB32) + { + PixmapPtr pPixmap = _secVirtualVideoGetPixmap (pPort->pDraw); + tbm_bo_handle bo_handle; + + XDBG_GOTO_IF_FAIL (buf->secure == FALSE, draw_done); + + if (pPort->pDraw->width != buf->width || pPort->pDraw->height != buf->height) + { + XDBG_ERROR (MVA, "not matched. (%dx%d != %dx%d) \n", + pPort->pDraw->width, pPort->pDraw->height, + buf->width, buf->height); + goto draw_done; + } + + bo_handle = tbm_bo_map (buf->bo[0], TBM_DEVICE_CPU, TBM_OPTION_READ); + XDBG_GOTO_IF_FAIL (bo_handle.ptr != NULL, draw_done); + XDBG_GOTO_IF_FAIL (buf->size > 0, draw_done); + + secExaPrepareAccess (pPixmap, EXA_PREPARE_DEST); + + if (pPixmap->devPrivate.ptr) + { + XDBG_DEBUG (MVA, "vir(%p) size(%d) => pixmap(%p)\n", + bo_handle.ptr, buf->size, pPixmap->devPrivate.ptr); + + memcpy (pPixmap->devPrivate.ptr, bo_handle.ptr, buf->size); + } + + secExaFinishAccess (pPixmap, EXA_PREPARE_DEST); + + tbm_bo_unmap (buf->bo[0]); + } + else /* FOURCC_ST12 */ + { + PixmapPtr pPixmap = _secVirtualVideoGetPixmap (pPort->pDraw); + XV_DATA xv_data = {0,}; + + _secVirtualVideoSetSecure (pPort, buf->secure); + + XV_INIT_DATA (&xv_data); + + if (buf->phy_addrs[0] > 0) + { + xv_data.YBuf = buf->phy_addrs[0]; + xv_data.CbBuf = buf->phy_addrs[1]; + xv_data.CrBuf = buf->phy_addrs[2]; + + xv_data.BufType = XV_BUF_TYPE_LEGACY; + } + else + { + xv_data.YBuf = buf->keys[0]; + xv_data.CbBuf = buf->keys[1]; + xv_data.CrBuf = buf->keys[2]; + + xv_data.BufType = XV_BUF_TYPE_DMABUF; + } + +#if 0 + _buffers (pPort); + ErrorF ("[Xorg] send : %d (%s)\n", xv_data.YBuf, buffers); +#endif + + XDBG_DEBUG (MVA, "still_data(%d,%d,%d) type(%d) \n", + xv_data.YBuf, xv_data.CbBuf, xv_data.CrBuf, + xv_data.BufType); + + secExaPrepareAccess (pPixmap, EXA_PREPARE_DEST); + + if (pPixmap->devPrivate.ptr) + memcpy (pPixmap->devPrivate.ptr, &xv_data, sizeof (XV_DATA)); + + secExaFinishAccess (pPixmap, EXA_PREPARE_DEST); + + _secVirtualVideoAddReturnBuf (pPort, buf); + } + +draw_done: + DamageDamageRegion (pPort->pDraw, pPort->clipBoxes); + pPort->need_damage = FALSE; + + SECPtr pSec = SECPTR (pPort->pScrn); + if ((pSec->dump_mode & XBERC_DUMP_MODE_CA) && pSec->dump_info) + { + char file[128]; + static int i; + snprintf (file, sizeof(file), "capout_stream_%c%c%c%c_%dx%d_%03d.%s", + FOURCC_STR(buf->id), buf->width, buf->height, i++, + IS_RGB (buf->id)?"bmp":"yuv"); + secUtilDoDumpVBuf (pSec->dump_info, buf, file); + } + + if (pSec->xvperf_mode & XBERC_XVPERF_MODE_CA) + { + CARD32 cur, sub; + cur = GetTimeInMillis (); + sub = cur - pPort->prev_time; + ErrorF ("damage send : %6ld ms\n", sub); + } +} + +static void +_secVirtualVideoWbDumpFunc (SECWb *wb, SECWbNotify noti, void *noti_data, void *user_data) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr)user_data; + SECVideoBuf *vbuf = (SECVideoBuf*)noti_data; + + XDBG_RETURN_IF_FAIL (pPort != NULL); + XDBG_RETURN_IF_FAIL (VBUF_IS_VALID (vbuf)); + XDBG_RETURN_IF_FAIL (vbuf->showing == FALSE); + + XDBG_TRACE (MVA, "dump (%ld,%d,%d,%d)\n", vbuf->stamp, + vbuf->keys[0], vbuf->keys[1], vbuf->keys[2]); + + if (pPort->need_damage) + { + _secVirtualVideoDraw (pPort, vbuf); + } + + return; +} + +static void +_secVirtualVideoWbDumpDoneFunc (SECWb *wb, SECWbNotify noti, void *noti_data, void *user_data) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr)user_data; + + if (!pPort) + return; + + XDBG_DEBUG (MVA, "close wb after ipp event done\n"); + + XDBG_RETURN_IF_FAIL (pPort->wb != NULL); + + secWbRemoveNotifyFunc (pPort->wb, _secVirtualVideoWbStopFunc); + secWbRemoveNotifyFunc (pPort->wb, _secVirtualVideoWbDumpFunc); + secWbRemoveNotifyFunc (pPort->wb, _secVirtualVideoWbDumpDoneFunc); + secWbRemoveNotifyFunc (pPort->wb, _secVirtualVideoWbCloseFunc); + + secWbClose (pPort->wb); + pPort->wb = NULL; +} + +static void +_secVirtualVideoWbStopFunc (SECWb *wb, SECWbNotify noti, void *noti_data, void *user_data) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr)user_data; + + if (!pPort) + return; + + if (pPort->need_damage) + { + SECVideoBuf *black = _secVirtualVideoGetBlackBuffer (pPort); + XDBG_TRACE (MVA, "black buffer(%d) return: wb stop\n", (black)?black->keys[0]:0); + _secVirtualVideoDraw (pPort, black); + } +} + +static void +_secVirtualVideoWbCloseFunc (SECWb *wb, SECWbNotify noti, void *noti_data, void *user_data) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr)user_data; + + if (!pPort) + return; + + pPort->wb = NULL; +} + +static void +_secVirtualVideoStreamOff (SECPortPrivPtr pPort) +{ + SECLayer *layer; + + XDBG_TRACE (MVA, "STREAM_OFF!\n"); + + if (pPort->retire_timer) + { + TimerFree (pPort->retire_timer); + pPort->retire_timer = NULL; + } + + if (pPort->wb) + { + secWbRemoveNotifyFunc (pPort->wb, _secVirtualVideoWbStopFunc); + secWbRemoveNotifyFunc (pPort->wb, _secVirtualVideoWbDumpFunc); + secWbRemoveNotifyFunc (pPort->wb, _secVirtualVideoWbDumpDoneFunc); + secWbRemoveNotifyFunc (pPort->wb, _secVirtualVideoWbCloseFunc); + + secWbClose (pPort->wb); + pPort->wb = NULL; + } + + if (pPort->id != FOURCC_RGB32) + _secVirtualVideoRemoveReturnBufAll (pPort); + + layer = secLayerFind (LAYER_OUTPUT_EXT, LAYER_LOWER1); + if (layer) + secLayerRemoveNotifyFunc (layer, _secVirtualVideoLayerNotifyFunc); + + if (pPort->need_damage) + { + /* all callbacks has been removed from wb/layer. We can't expect + * any event. So we send black image at the end. + */ + SECVideoBuf *black = _secVirtualVideoGetBlackBuffer (pPort); + XDBG_TRACE (MVA, "black buffer(%d) return: stream off\n", (black)?black->keys[0]:0); + _secVirtualVideoDraw (pPort, black); + } + + _secVirtualVideoCloseOutBuffer (pPort); + + if (pPort->clipBoxes) + { + RegionDestroy (pPort->clipBoxes); + pPort->clipBoxes = NULL; + } + + pPort->pDraw = NULL; + pPort->capture = CAPTURE_MODE_NONE; + pPort->id = FOURCC_RGB32; + pPort->secure = FALSE; + pPort->data_type = DATA_TYPE_UI; + pPort->need_damage = FALSE; + + if (pPort->putstill_on) + { + pPort->putstill_on = FALSE; + XDBG_SECURE (MVA, "pPort(%d) putstill off. \n", pPort->index); + } +} + +static int +_secVirtualVideoAddDrawableEvent (SECPortPrivPtr pPort) +{ + SECVideoResource *resource; + void *ptr; + int ret = 0; + + XDBG_RETURN_VAL_IF_FAIL (pPort->pScrn != NULL, BadImplementation); + XDBG_RETURN_VAL_IF_FAIL (pPort->pDraw != NULL, BadImplementation); + + ptr = NULL; + ret = dixLookupResourceByType (&ptr, pPort->pDraw->id, + event_drawable_type, NULL, DixWriteAccess); + if (ret == Success) + return Success; + + resource = malloc (sizeof (SECVideoResource)); + if (resource == NULL) + return BadAlloc; + + if (!AddResource (pPort->pDraw->id, event_drawable_type, resource)) + { + free (resource); + return BadAlloc; + } + + XDBG_TRACE (MVA, "id(0x%08lx). \n", pPort->pDraw->id); + + resource->id = pPort->pDraw->id; + resource->type = event_drawable_type; + resource->pPort = pPort; + resource->pScrn = pPort->pScrn; + + return Success; +} + +static int +_secVirtualVideoRegisterEventDrawableGone (void *data, XID id) +{ + SECVideoResource *resource = (SECVideoResource*)data; + + XDBG_TRACE (MVA, "id(0x%08lx). \n", id); + + if (!resource) + return Success; + + if (!resource->pPort || !resource->pScrn) + return Success; + + resource->pPort->pDraw = NULL; + + SECVirtualVideoStop (resource->pScrn, (pointer)resource->pPort, 1); + + free(resource); + + return Success; +} + +static Bool +_secVirtualVideoRegisterEventResourceTypes (void) +{ + event_drawable_type = CreateNewResourceType (_secVirtualVideoRegisterEventDrawableGone, + "Sec Virtual Video Drawable"); + + if (!event_drawable_type) + return FALSE; + + return TRUE; +} + +static tbm_bo +_secVirtualVideoGetFrontBo (SECPortPrivPtr pPort, int connector_type) +{ + xf86CrtcConfigPtr pCrtcConfig; + int i; + + pCrtcConfig = XF86_CRTC_CONFIG_PTR (pPort->pScrn); + XDBG_RETURN_VAL_IF_FAIL (pCrtcConfig != NULL, NULL); + + for (i = 0; i < pCrtcConfig->num_output; i++) + { + xf86OutputPtr pOutput = pCrtcConfig->output[i]; + SECOutputPrivPtr pOutputPriv = pOutput->driver_private; + + if (pOutputPriv->mode_output->connector_type == connector_type) + { + if (pOutput->crtc) + { + SECCrtcPrivPtr pCrtcPriv = pOutput->crtc->driver_private; + return pCrtcPriv->front_bo; + } + else + XDBG_ERROR (MVA, "no crtc.\n"); + } + } + + return NULL; +} + +static SECVideoBuf* +_secVirtualVideoGetBlackBuffer (SECPortPrivPtr pPort) +{ + int i; + + if (!pPort->outbuf[0]) + { + XDBG_RETURN_VAL_IF_FAIL (pPort->pDraw != NULL, NULL); + _secVirtualVideoEnsureOutBuffers (pPort->pScrn, pPort, pPort->id, + pPort->pDraw->width, pPort->pDraw->height); + } + + for (i = 0; i < pPort->outbuf_num; i++) + { + if (pPort->outbuf[i] && !pPort->outbuf[i]->showing) + { + if (pPort->outbuf[i]->dirty) + secUtilClearVideoBuffer (pPort->outbuf[i]); + + return pPort->outbuf[i]; + } + } + + XDBG_ERROR (MVA, "now all buffers are in showing\n"); + + return NULL; +} + +static Bool +_secVirtualVideoEnsureOutBuffers (ScrnInfoPtr pScrn, SECPortPrivPtr pPort, int id, int width, int height) +{ + SECPtr pSec = SECPTR (pScrn); + int i; + + if (pPort->display == DISPLAY_EXTERNAL) + pPort->outbuf_num = BUF_NUM_EXTERNAL; + else + pPort->outbuf_num = BUF_NUM_STREAM; + + if (!pPort->outbuf) + { + pPort->outbuf = (SECVideoBuf**)calloc(pPort->outbuf_num, sizeof (SECVideoBuf*)); + XDBG_RETURN_VAL_IF_FAIL (pPort->outbuf != NULL, FALSE); + } + + for (i = 0; i < pPort->outbuf_num; i++) + { + int scanout; + + if (pPort->outbuf[i]) + continue; + + XDBG_RETURN_VAL_IF_FAIL (width > 0, FALSE); + XDBG_RETURN_VAL_IF_FAIL (height > 0, FALSE); + + if (pPort->display == DISPLAY_LCD) + scanout = FALSE; + else + scanout = pSec->scanout; + + /* pPort->pScrn can be NULL if XvPutStill isn't called. */ + pPort->outbuf[i] = secUtilAllocVideoBuffer (pScrn, id, + width, height, + scanout, TRUE, pPort->secure); + + XDBG_GOTO_IF_FAIL (pPort->outbuf[i] != NULL, ensure_buffer_fail); + } + + return TRUE; + +ensure_buffer_fail: + _secVirtualVideoCloseOutBuffer (pPort); + + return FALSE; +} + +static Bool +_secVirtualVideoEnsureDstBuffer (SECPortPrivPtr pPort) +{ + if (pPort->dstbuf) + { + secUtilClearVideoBuffer (pPort->dstbuf); + return TRUE; + } + + pPort->dstbuf = secUtilAllocVideoBuffer (pPort->pScrn, FOURCC_RGB32, + pPort->pDraw->width, + pPort->pDraw->height, + FALSE, FALSE, pPort->secure); + XDBG_RETURN_VAL_IF_FAIL (pPort->dstbuf != NULL, FALSE); + + return TRUE; +} + +static SECVideoBuf* +_secVirtualVideoGetUIBuffer (SECPortPrivPtr pPort, int connector_type) +{ + SECVideoBuf *uibuf = NULL; + tbm_bo bo[PLANAR_CNT] = {0,}; + SECFbBoDataPtr bo_data = NULL; + tbm_bo_handle bo_handle; + + bo[0] = _secVirtualVideoGetFrontBo (pPort, connector_type); + XDBG_RETURN_VAL_IF_FAIL (bo[0] != NULL, NULL); + + tbm_bo_get_user_data (bo[0], TBM_BO_DATA_FB, (void**)&bo_data); + XDBG_RETURN_VAL_IF_FAIL (bo_data != NULL, NULL); + + uibuf = secUtilCreateVideoBuffer (pPort->pScrn, FOURCC_RGB32, + bo_data->pos.x2 - bo_data->pos.x1, + bo_data->pos.y2 - bo_data->pos.y1, + FALSE); + XDBG_RETURN_VAL_IF_FAIL (uibuf != NULL, NULL); + + uibuf->bo[0] = tbm_bo_ref (bo[0]); + XDBG_GOTO_IF_FAIL (uibuf->bo[0] != NULL, fail_get); + + bo_handle = tbm_bo_get_handle (bo[0], TBM_DEVICE_DEFAULT); + uibuf->handles[0] = bo_handle.u32; + + XDBG_GOTO_IF_FAIL (uibuf->handles[0] > 0, fail_get); + + return uibuf; + +fail_get: + if (uibuf) + secUtilVideoBufferUnref (uibuf); + + return NULL; +} + +static SECVideoBuf* +_secVirtualVideoGetDrawableBuffer (SECPortPrivPtr pPort) +{ + SECVideoBuf *vbuf = NULL; + PixmapPtr pPixmap = NULL; + tbm_bo_handle bo_handle; + SECPixmapPriv *privPixmap; + Bool need_finish = FALSE; + + XDBG_GOTO_IF_FAIL (pPort->secure == FALSE, fail_get); + XDBG_GOTO_IF_FAIL (pPort->pDraw != NULL, fail_get); + + pPixmap = _secVirtualVideoGetPixmap (pPort->pDraw); + XDBG_GOTO_IF_FAIL (pPixmap != NULL, fail_get); + + privPixmap = exaGetPixmapDriverPrivate (pPixmap); + XDBG_GOTO_IF_FAIL (privPixmap != NULL, fail_get); + + if (!privPixmap->bo) + { + need_finish = TRUE; + secExaPrepareAccess (pPixmap, EXA_PREPARE_DEST); + XDBG_GOTO_IF_FAIL (privPixmap->bo != NULL, fail_get); + } + + vbuf = secUtilCreateVideoBuffer (pPort->pScrn, FOURCC_RGB32, + pPort->pDraw->width, + pPort->pDraw->height, + FALSE); + XDBG_GOTO_IF_FAIL (vbuf != NULL, fail_get); + + vbuf->bo[0] = tbm_bo_ref (privPixmap->bo); + bo_handle = tbm_bo_get_handle (privPixmap->bo, TBM_DEVICE_DEFAULT); + vbuf->handles[0] = bo_handle.u32; + + XDBG_GOTO_IF_FAIL (vbuf->handles[0] > 0, fail_get); + + return vbuf; + +fail_get: + if (pPixmap && need_finish) + secExaFinishAccess (pPixmap, EXA_PREPARE_DEST); + + if (vbuf) + secUtilVideoBufferUnref (vbuf); + + return NULL; +} + +static void +_secVirtualVideoCloseOutBuffer (SECPortPrivPtr pPort) +{ + int i; + + if (pPort->outbuf) + { + for (i = 0; i < pPort->outbuf_num; i++) + { + if (pPort->outbuf[i]) + secUtilVideoBufferUnref (pPort->outbuf[i]); + pPort->outbuf[i] = NULL; + } + + free (pPort->outbuf); + pPort->outbuf = NULL; + } + + if (pPort->dstbuf) + { + secUtilVideoBufferUnref (pPort->dstbuf); + pPort->dstbuf = NULL; + } + + pPort->outbuf_index = -1; +} + +static int +_secVirtualVideoDataType (SECPortPrivPtr pPort) +{ + SECLayer *video_layer = secLayerFind (LAYER_OUTPUT_EXT, LAYER_LOWER1); + + return (video_layer) ? DATA_TYPE_VIDEO : DATA_TYPE_UI; +} + +static int +_secVirtualVideoPreProcess (ScrnInfoPtr pScrn, SECPortPrivPtr pPort, + RegionPtr clipBoxes, DrawablePtr pDraw) +{ + if (pPort->pScrn == pScrn && pPort->pDraw == pDraw && + pPort->clipBoxes && clipBoxes && RegionEqual (pPort->clipBoxes, clipBoxes)) + return Success; + + pPort->pScrn = pScrn; + pPort->pDraw = pDraw; + + if (clipBoxes) + { + if (!pPort->clipBoxes) + pPort->clipBoxes = RegionCreate (NULL, 1); + + XDBG_RETURN_VAL_IF_FAIL (pPort->clipBoxes != NULL, BadAlloc); + + RegionCopy (pPort->clipBoxes, clipBoxes); + } + + XDBG_TRACE (MVA, "pDraw(0x%x, %dx%d). \n", pDraw->id, pDraw->width, pDraw->height); + + return Success; +} + +static int +_secVirtualVideoGetOutBufferIndex (SECPortPrivPtr pPort) +{ + if (!pPort->outbuf) + return -1; + + pPort->outbuf_index++; + if (pPort->outbuf_index >= pPort->outbuf_num) + pPort->outbuf_index = 0; + + return pPort->outbuf_index; +} + +static int +_secVirtualVideoSendPortNotify (SECPortPrivPtr pPort, SECPortAttrAtom paa, INT32 value) +{ + SECVideoPortInfo *info; + Atom atom = None; + + XDBG_RETURN_VAL_IF_FAIL (pPort->pDraw != NULL, BadValue); + + info = _port_info (pPort->pDraw); + XDBG_RETURN_VAL_IF_FAIL (info != NULL, BadValue); + XDBG_RETURN_VAL_IF_FAIL (info->pp != NULL, BadValue); + + atom = _secVideoGetPortAtom (paa); + XDBG_RETURN_VAL_IF_FAIL (atom != None, BadValue); + + XDBG_TRACE (MVA, "paa(%d), value(%d)\n", paa, value); + + return XvdiSendPortNotify (info->pp, atom, value); +} + +static Bool +_secVirtualVideoComposite (SECVideoBuf *src, SECVideoBuf *dst, + int src_x, int src_y, int src_w, int src_h, + int dst_x, int dst_y, int dst_w, int dst_h, + Bool composite, int rotate) +{ + xRectangle src_rect = {0,}, dst_rect = {0,}; + + XDBG_RETURN_VAL_IF_FAIL (src != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (dst != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (src->bo[0] != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (dst->bo[0] != NULL, FALSE); + XDBG_RETURN_VAL_IF_FAIL (src->pitches[0] > 0, FALSE); + XDBG_RETURN_VAL_IF_FAIL (dst->pitches[0] > 0, FALSE); + XDBG_RETURN_VAL_IF_FAIL (IS_RGB (src->id), FALSE); + XDBG_RETURN_VAL_IF_FAIL (IS_RGB (dst->id), FALSE); + + XDBG_DEBUG (MVA, "comp(%d) src : %ld %c%c%c%c %dx%d (%d,%d %dx%d) => dst : %ld %c%c%c%c %dx%d (%d,%d %dx%d)\n", + composite, src->stamp, FOURCC_STR (src->id), src->width, src->height, + src_x, src_y, src_w, src_h, + dst->stamp, FOURCC_STR (dst->id), dst->width, dst->height, + dst_x, dst_y, dst_w, dst_h); + + src_rect.x = src_x; + src_rect.y = src_y; + src_rect.width = src_w; + src_rect.height = src_h; + dst_rect.x = dst_x; + dst_rect.y = dst_y; + dst_rect.width = dst_w; + dst_rect.height = dst_h; + + secUtilConvertBos (src->pScrn, + src->bo[0], src->width, src->height, &src_rect, src->pitches[0], + dst->bo[0], dst->width, dst->height, &dst_rect, dst->pitches[0], + composite, rotate); + + return TRUE; +} + +static int +_secVirtualVideoCompositeExtLayers (SECPortPrivPtr pPort) +{ + SECVideoBuf *dst_buf = NULL; + SECLayer *lower_layer = NULL; + SECLayer *upper_layer = NULL; + SECVideoBuf *ui_buf = NULL; + xRectangle rect = {0,}; + int index; + Bool comp = FALSE; + + index = _secVirtualVideoGetOutBufferIndex (pPort); + if (index < 0) + { + XDBG_WARNING (MVA, "all out buffers are in use.\n"); + return FALSE; + } + + lower_layer = secLayerFind (LAYER_OUTPUT_EXT, LAYER_LOWER1); + if (lower_layer) + { + SECVideoBuf *lower_buf = secLayerGetBuffer (lower_layer); + + if (lower_buf && !lower_buf->secure && VBUF_IS_VALID (lower_buf)) + { + /* In case of virtual, lower layer already has full-size. */ + dst_buf = lower_buf; + comp = TRUE; + } + } + + if (!dst_buf) + { + if (!_secVirtualVideoEnsureDstBuffer (pPort)) + return FALSE; + + dst_buf = pPort->dstbuf; + } + + /* before compositing, flush all */ + secUtilCacheFlush (pPort->pScrn); + + ui_buf = _secVirtualVideoGetUIBuffer (pPort, DRM_MODE_CONNECTOR_VIRTUAL); + if (ui_buf) + { + XDBG_DEBUG (MVA, "ui : %c%c%c%c %dx%d (%d,%d %dx%d) => dst : %c%c%c%c %dx%d (%d,%d %dx%d)\n", + FOURCC_STR (ui_buf->id), + ui_buf->width, ui_buf->height, + ui_buf->crop.x, ui_buf->crop.y, + ui_buf->crop.width, ui_buf->crop.height, + FOURCC_STR (dst_buf->id), + dst_buf->width, dst_buf->height, + 0, 0, + dst_buf->width, dst_buf->height); + + if (!_secVirtualVideoComposite (ui_buf, dst_buf, + ui_buf->crop.x, ui_buf->crop.y, + ui_buf->crop.width, ui_buf->crop.height, + 0, 0, + dst_buf->width, dst_buf->height, + comp, 0)) + { + secUtilVideoBufferUnref (ui_buf); + return FALSE; + } + + comp = TRUE; + } + + upper_layer = secLayerFind (LAYER_OUTPUT_EXT, LAYER_UPPER); + if (upper_layer) + { + SECVideoBuf *upper_buf = secLayerGetBuffer (upper_layer); + + if (upper_buf && VBUF_IS_VALID (upper_buf)) + { + secLayerGetRect (upper_layer, &upper_buf->crop, &rect); + + XDBG_DEBUG (MVA, "upper : %c%c%c%c %dx%d (%d,%d %dx%d) => dst : %c%c%c%c %dx%d (%d,%d %dx%d)\n", + FOURCC_STR (upper_buf->id), + upper_buf->width, upper_buf->height, + upper_buf->crop.x, upper_buf->crop.y, + upper_buf->crop.width, upper_buf->crop.height, + FOURCC_STR (dst_buf->id), + dst_buf->width, dst_buf->height, + rect.x, rect.y, rect.width, rect.height); + + _secVirtualVideoComposite (upper_buf, dst_buf, + upper_buf->crop.x, upper_buf->crop.y, + upper_buf->crop.width, upper_buf->crop.height, + rect.x, rect.y, rect.width, rect.height, + comp, 0); + } + } + + dst_buf->crop.x = 0; + dst_buf->crop.y = 0; + dst_buf->crop.width = dst_buf->width; + dst_buf->crop.height = dst_buf->height; + + XDBG_RETURN_VAL_IF_FAIL (pPort->outbuf[index] != NULL, FALSE); + + pPort->outbuf[index]->crop.x = 0; + pPort->outbuf[index]->crop.y = 0; + pPort->outbuf[index]->crop.width = pPort->outbuf[index]->width; + pPort->outbuf[index]->crop.height = pPort->outbuf[index]->height; + _secVirtualVideoComposite (dst_buf, pPort->outbuf[index], + 0, 0, dst_buf->width, dst_buf->height, + 0, 0, pPort->outbuf[index]->width, pPort->outbuf[index]->height, + FALSE, 0); + + _secVirtualVideoDraw (pPort, pPort->outbuf[index]); + + if (ui_buf) + secUtilVideoBufferUnref (ui_buf); + + return TRUE; +} + +static void +_secVirtualVideoCompositeSubtitle (SECPortPrivPtr pPort, SECVideoBuf *vbuf) +{ + SECLayer *subtitle_layer; + SECVideoBuf *subtitle_vbuf; + xRectangle src_rect; + xRectangle dst_rect; + + subtitle_layer = secLayerFind (LAYER_OUTPUT_EXT, LAYER_UPPER); + if (!subtitle_layer) + return; + + subtitle_vbuf = secLayerGetBuffer (subtitle_layer); + if (!subtitle_vbuf || !VBUF_IS_VALID (subtitle_vbuf)) + return; + + CLEAR (src_rect); + CLEAR (dst_rect); + secLayerGetRect (subtitle_layer, &src_rect, &dst_rect); + + XDBG_DEBUG (MVA, "subtitle : %dx%d (%d,%d %dx%d) => %dx%d (%d,%d %dx%d)\n", + subtitle_vbuf->width, subtitle_vbuf->height, + src_rect.x, src_rect.y, src_rect.width, src_rect.height, + vbuf->width, vbuf->height, + dst_rect.x, dst_rect.y, dst_rect.width, dst_rect.height); + + _secVirtualVideoComposite (subtitle_vbuf, vbuf, + src_rect.x, src_rect.y, src_rect.width, src_rect.height, + dst_rect.x, dst_rect.y, dst_rect.width, dst_rect.height, + TRUE, 0); +} + +static CARD32 +_secVirtualVideoRetireTimeout (OsTimerPtr timer, CARD32 now, pointer arg) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr) arg; + SECModePtr pSecMode; + int diff; + + if (!pPort) + return 0; + + pSecMode = (SECModePtr)SECPTR (pPort->pScrn)->pSecMode; + + if (pPort->retire_timer) + { + TimerFree (pPort->retire_timer); + pPort->retire_timer = NULL; + } + + XDBG_ERROR (MVA, "capture(%d) mode(%d) conn(%d) type(%d) status(%x). \n", + pPort->capture, pSecMode->set_mode, pSecMode->conn_mode, + pPort->data_type, pPort->status); + + diff = GetTimeInMillis () - pPort->retire_time; + XDBG_ERROR (MVA, "failed : +++ Retire Timeout!! diff(%d)\n", diff); + + return 0; +} + +static void +_secVirtualVideoLayerNotifyFunc (SECLayer *layer, int type, void *type_data, void *data) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr)data; + SECVideoBuf *vbuf = (SECVideoBuf*)type_data; + SECVideoBuf *black; + + secLayerRemoveNotifyFunc (layer, _secVirtualVideoLayerNotifyFunc); + + if (type == LAYER_DESTROYED || type != LAYER_BUF_CHANGED || !vbuf) + goto fail_layer_noti; + + XDBG_GOTO_IF_FAIL (VBUF_IS_VALID (vbuf), fail_layer_noti); + XDBG_GOTO_IF_FAIL (vbuf->showing == FALSE, fail_layer_noti); + + XDBG_DEBUG (MVA, "------------------------------\n"); + + _secVirtualVideoCompositeSubtitle (pPort, vbuf); + _secVirtualVideoDraw (pPort, vbuf); + XDBG_DEBUG (MVA, "------------------------------...\n"); + + return; + +fail_layer_noti: + black = _secVirtualVideoGetBlackBuffer (pPort); + XDBG_TRACE (MVA, "black buffer(%d) return: layer noti. type(%d), vbuf(%p)\n", + (black)?black->keys[0]:0, type, vbuf); + _secVirtualVideoDraw (pPort, black); +} + +static int +_secVirtualVideoPutStill (SECPortPrivPtr pPort) +{ + SECModePtr pSecMode = (SECModePtr)SECPTR (pPort->pScrn)->pSecMode; + SECVideoBuf *pix_buf = NULL; + SECVideoBuf *ui_buf = NULL; + Bool comp; + int i; + CARD32 start = GetTimeInMillis (); + + XDBG_GOTO_IF_FAIL (pPort->secure == FALSE, done_still); + + if (pPort->retire_timer) + { + TimerFree (pPort->retire_timer); + pPort->retire_timer = NULL; + } + + comp = FALSE; + + pix_buf = _secVirtualVideoGetDrawableBuffer (pPort); + XDBG_GOTO_IF_FAIL (pix_buf != NULL, done_still); + + ui_buf = _secVirtualVideoGetUIBuffer (pPort, DRM_MODE_CONNECTOR_LVDS); + XDBG_GOTO_IF_FAIL (ui_buf != NULL, done_still); + + tbm_bo_map (pix_buf->bo[0], TBM_DEVICE_2D, TBM_OPTION_WRITE); + + for (i = LAYER_LOWER2; i < LAYER_MAX; i++) + { + SECVideoBuf *upper = NULL; + xRectangle src_rect, dst_rect; + int vwidth = pSecMode->main_lcd_mode.hdisplay; + int vheight = pSecMode->main_lcd_mode.vdisplay; + int rotate; + + if (i == LAYER_DEFAULT) + { + upper = secUtilVideoBufferRef (ui_buf); + tbm_bo_map (upper->bo[0], TBM_DEVICE_2D, TBM_OPTION_READ); + + src_rect.x = src_rect.y = 0; + src_rect.width = ui_buf->width; + src_rect.height = ui_buf->height; + + dst_rect.x = dst_rect.y = 0; + dst_rect.width = ui_buf->width; + dst_rect.height = ui_buf->height; + + rotate = 0; + } + else + { + SECLayer *layer = secLayerFind (LAYER_OUTPUT_LCD, (SECLayerPos)i); + int off_x = 0, off_y = 0; + SECVideoPrivPtr pVideo = SECPTR(pPort->pScrn)->pVideoPriv; + + if (!layer) + continue; + + upper = secUtilVideoBufferRef (secLayerGetBuffer (layer)); + if (!upper || !VBUF_IS_VALID (upper)) + continue; + + secLayerGetRect (layer, &src_rect, &dst_rect); + secLayerGetOffset (layer, &off_x, &off_y); + dst_rect.x += off_x; + dst_rect.y += off_y; + + rotate = (360 - pVideo->screen_rotate_degree) % 360; + + /* rotate upper_rect */ + secUtilRotateArea (&vwidth, &vheight, &dst_rect, rotate); + } + + /* scale upper_rect */ + secUtilScaleRect (vwidth, vheight, pix_buf->width, pix_buf->height, &dst_rect); + + XDBG_DEBUG (MVA, "%dx%d(%d,%d, %dx%d) => %dx%d(%d,%d, %dx%d) :comp(%d) r(%d)\n", + upper->width, upper->height, + src_rect.x, src_rect.y, src_rect.width, src_rect.height, + pix_buf->width, pix_buf->height, + dst_rect.x, dst_rect.y, dst_rect.width, dst_rect.height, + comp, rotate); + + if (!_secVirtualVideoComposite (upper, pix_buf, + src_rect.x, src_rect.y, + src_rect.width, src_rect.height, + dst_rect.x, dst_rect.y, + dst_rect.width, dst_rect.height, + comp, rotate)) + { + if (i == LAYER_DEFAULT) + tbm_bo_unmap (upper->bo[0]); + tbm_bo_unmap (pix_buf->bo[0]); + goto done_still; + } + + if (i == LAYER_DEFAULT) + tbm_bo_unmap (upper->bo[0]); + + secUtilVideoBufferUnref (upper); + + comp = TRUE; + } + + XDBG_TRACE (MVA, "make still: %ldms\n", GetTimeInMillis() - start); + + tbm_bo_unmap (pix_buf->bo[0]); + +done_still: + + secUtilCacheFlush (pPort->pScrn); + + if (pix_buf) + secUtilVideoBufferUnref (pix_buf); + if (ui_buf) + secUtilVideoBufferUnref (ui_buf); + + DamageDamageRegion (pPort->pDraw, pPort->clipBoxes); + pPort->need_damage = FALSE; + + SECPtr pSec = SECPTR (pPort->pScrn); + if ((pSec->dump_mode & XBERC_DUMP_MODE_CA) && pSec->dump_info) + { + PixmapPtr pPixmap = _secVirtualVideoGetPixmap (pPort->pDraw); + char file[128]; + static int i; + snprintf (file, sizeof(file), "capout_still_%03d.bmp", i++); + secUtilDoDumpPixmaps (pSec->dump_info, pPixmap, file); + } + + return Success; +} + +static int +_secVirtualVideoPutWB (SECPortPrivPtr pPort) +{ + SECPtr pSec = SECPTR (pPort->pScrn); + + XDBG_RETURN_VAL_IF_FAIL (pPort->pScrn != NULL, BadImplementation); + XDBG_RETURN_VAL_IF_FAIL (pPort->pDraw != NULL, BadImplementation); + + if (!_secVirtualVideoEnsureOutBuffers (pPort->pScrn, pPort, pPort->id, pPort->pDraw->width, pPort->pDraw->height)) + return BadAlloc; + + if (!pPort->wb) + { + int scanout; + + if (secWbIsOpened ()) + { + XDBG_ERROR (MVA, "Fail : wb open. \n"); + return BadRequest; + } + + if (pPort->display == DISPLAY_LCD) + scanout = FALSE; + else + scanout = pSec->scanout; + + /* For capture mode, we don't need to create contiguous buffer. + * Rotation should be considered when wb begins. + */ + pPort->wb = secWbOpen (pPort->pScrn, pPort->id, + pPort->pDraw->width, pPort->pDraw->height, + scanout, 60, + (pPort->rotate_off)?FALSE:TRUE); + XDBG_RETURN_VAL_IF_FAIL (pPort->wb != NULL, BadAlloc); + + secWbSetBuffer (pPort->wb, pPort->outbuf, pPort->outbuf_num); + + XDBG_TRACE (MVA, "wb(%p) start. \n", pPort->wb); + + if (!secWbStart (pPort->wb)) + { + secWbClose (pPort->wb); + pPort->wb = NULL; + return BadAlloc; + } + secWbAddNotifyFunc (pPort->wb, WB_NOTI_STOP, + _secVirtualVideoWbStopFunc, pPort); + secWbAddNotifyFunc (pPort->wb, WB_NOTI_IPP_EVENT, + _secVirtualVideoWbDumpFunc, pPort); + if (pPort->capture == CAPTURE_MODE_STILL) + secWbAddNotifyFunc (pPort->wb, WB_NOTI_IPP_EVENT_DONE, + _secVirtualVideoWbDumpDoneFunc, pPort); + secWbAddNotifyFunc (pPort->wb, WB_NOTI_CLOSED, + _secVirtualVideoWbCloseFunc, pPort); + } + + /* no available buffer, need to return buffer by client. */ + if (!secWbIsRunning ()) + { + XDBG_WARNING (MVA, "wb is stopped.\n"); + return BadRequest; + } + + /* no available buffer, need to return buffer by client. */ + if (!secWbCanDequeueBuffer (pPort->wb)) + { + XDBG_TRACE (MVA, "no available buffer\n"); + return BadRequest; + } + + XDBG_TRACE (MVA, "wb(%p), running(%d). \n", pPort->wb, secWbIsRunning ()); + + return Success; +} + +static int +_secVirtualVideoPutVideoOnly (SECPortPrivPtr pPort) +{ + SECLayer *layer; + SECVideoBuf *vbuf; + int i; + + XDBG_RETURN_VAL_IF_FAIL (pPort->display == DISPLAY_EXTERNAL, BadRequest); + XDBG_RETURN_VAL_IF_FAIL (pPort->capture == CAPTURE_MODE_STREAM, BadRequest); + + layer = secLayerFind (LAYER_OUTPUT_EXT, LAYER_LOWER1); + if (!layer) + return BadRequest; + + for (i = 0; i < pPort->outbuf_num; i++) + { + if (!pPort->outbuf[i]->showing) + break; + } + + if (i == pPort->outbuf_num) + { + XDBG_ERROR (MVA, "now all buffers are in showing\n"); + return BadRequest; + } + + vbuf = secLayerGetBuffer (layer); + /* if layer is just created, vbuf can't be null. */ + if (!vbuf || !VBUF_IS_VALID (vbuf)) + { + SECVideoBuf *black = _secVirtualVideoGetBlackBuffer (pPort); + XDBG_RETURN_VAL_IF_FAIL (black != NULL, BadRequest); + + XDBG_TRACE (MVA, "black buffer(%d) return: vbuf invalid\n", black->keys[0]); + _secVirtualVideoDraw (pPort, black); + return Success; + } + + /* Wait the next frame if it's same as previous one */ + if (_secVirtualVideoFindReturnBuf (pPort, vbuf->keys[0])) + { + secLayerAddNotifyFunc (layer, _secVirtualVideoLayerNotifyFunc, pPort); + XDBG_DEBUG (MVA, "wait notify.\n"); + return Success; + } + + _secVirtualVideoCompositeSubtitle (pPort, vbuf); + _secVirtualVideoDraw (pPort, vbuf); + + return Success; +} + +static int +_secVirtualVideoPutExt (SECPortPrivPtr pPort) +{ + if (_secVirtualVideoCompositeExtLayers (pPort)) + return Success; + + return BadRequest; +} + +static int +SECVirtualVideoGetPortAttribute (ScrnInfoPtr pScrn, + Atom attribute, + INT32 *value, + pointer data) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr) data; + + if (attribute == _secVideoGetPortAtom (PAA_FORMAT)) + { + *value = pPort->id; + return Success; + } + else if (attribute == _secVideoGetPortAtom (PAA_CAPTURE)) + { + *value = pPort->capture; + return Success; + } + else if (attribute == _secVideoGetPortAtom (PAA_DISPLAY)) + { + *value = pPort->display; + return Success; + } + else if (attribute == _secVideoGetPortAtom (PAA_ROTATE_OFF)) + { + *value = pPort->rotate_off; + return Success; + } + else if (attribute == _secVideoGetPortAtom (PAA_DATA_TYPE)) + { + *value = pPort->data_type; + return Success; + } + else if (attribute == _secVideoGetPortAtom (PAA_SECURE)) + { + *value = pPort->secure; + return Success; + } + return BadMatch; +} + +static int +SECVirtualVideoSetPortAttribute (ScrnInfoPtr pScrn, + Atom attribute, + INT32 value, + pointer data) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr) data; + + if (attribute == _secVideoGetPortAtom (PAA_FORMAT)) + { + if (!_secVirtualVideoIsSupport ((unsigned int)value)) + { + XDBG_ERROR (MVA, "id(%c%c%c%c) not supported.\n", FOURCC_STR (value)); + return BadRequest; + } + + pPort->id = (unsigned int)value; + XDBG_DEBUG (MVA, "id(%d) \n", value); + return Success; + } + else if (attribute == _secVideoGetPortAtom (PAA_CAPTURE)) + { + if (value < CAPTURE_MODE_NONE || value >= CAPTURE_MODE_MAX) + { + XDBG_ERROR (MVA, "capture value(%d) is out of range\n", value); + return BadRequest; + } + + pPort->capture = value; + XDBG_DEBUG (MVA, "capture(%d) \n", pPort->capture); + return Success; + } + else if (attribute == _secVideoGetPortAtom (PAA_DISPLAY)) + { + XDBG_DEBUG (MVA, "display: %d \n", pPort->display); + pPort->display = value; + return Success; + } + else if (attribute == _secVideoGetPortAtom (PAA_ROTATE_OFF)) + { + XDBG_DEBUG (MVA, "ROTATE_OFF: %d! \n", pPort->rotate_off); + pPort->rotate_off = value; + return Success; + } + else if (attribute == _secVideoGetPortAtom (PAA_SECURE)) + { + XDBG_TRACE (MVA, "not implemented 'secure' attr. (%d) \n", pPort->secure); +// pPort->secure = value; + return Success; + } + else if (attribute == _secVideoGetPortAtom (PAA_RETBUF)) + { + RetBufInfo *info; + + if (!pPort->pDraw) + return Success; + + info = _secVirtualVideoFindReturnBuf (pPort, value); + if (!info) + { + XDBG_WARNING (MVA, "wrong gem name(%d) returned\n", value); + return Success; + } + + if (info->vbuf && info->vbuf->need_reset) + secUtilClearVideoBuffer (info->vbuf); + + _secVirtualVideoRemoveReturnBuf (pPort, info); +#if 0 + _buffers (pPort); + ErrorF ("[Xorg] retbuf : %ld (%s)\n", value, buffers); +#endif + + return Success; + } + + return Success; +} + +/* vid_w, vid_h : no meaning for us. not using. + * dst_w, dst_h : size to hope for PutStill. + * p_w, p_h : real size for PutStill. + */ +static void +SECVirtualVideoQueryBestSize (ScrnInfoPtr pScrn, + Bool motion, + short vid_w, short vid_h, + short dst_w, short dst_h, + unsigned int *p_w, unsigned int *p_h, + pointer data) +{ + SECModePtr pSecMode = (SECModePtr)SECPTR (pScrn)->pSecMode; + SECPortPrivPtr pPort = (SECPortPrivPtr) data; + + if (pPort->display == DISPLAY_EXTERNAL) + { + if (p_w) + *p_w = pSecMode->ext_connector_mode.hdisplay; + if (p_h) + *p_h = pSecMode->ext_connector_mode.vdisplay; + } + else + { + if (p_w) + *p_w = (unsigned int)dst_w; + if (p_h) + *p_h = (unsigned int)dst_h; + } +} + +/* vid_x, vid_y, vid_w, vid_h : no meaning for us. not using. + * drw_x, drw_y, dst_w, dst_h : no meaning for us. not using. + * Only pDraw's size is used. + */ +static int +SECVirtualVideoPutStill (ScrnInfoPtr pScrn, + short vid_x, short vid_y, short drw_x, short drw_y, + short vid_w, short vid_h, short drw_w, short drw_h, + RegionPtr clipBoxes, pointer data, DrawablePtr pDraw ) +{ + SECPtr pSec = SECPTR (pScrn); + SECModePtr pSecMode = (SECModePtr)SECPTR (pScrn)->pSecMode; + SECPortPrivPtr pPort = (SECPortPrivPtr) data; + int ret = BadRequest; + + XDBG_GOTO_IF_FAIL (pPort->need_damage == FALSE, put_still_fail); + + if (pPort->capture == CAPTURE_MODE_STILL && pPort->display == DISPLAY_EXTERNAL) + { + XDBG_ERROR (MVA, "not implemented to capture still of external display. \n"); + return BadImplementation; + } + + if (pPort->display == DISPLAY_EXTERNAL && pSecMode->conn_mode != DISPLAY_CONN_MODE_VIRTUAL) + { + XDBG_ERROR (MVA, "virtual display not connected!. \n"); + return BadRequest; + } + +#if 0 + ErrorF ("[Xorg] PutStill\n"); +#endif + + XDBG_DEBUG (MVA, "*************************************** \n"); + + if (pSec->xvperf_mode & XBERC_XVPERF_MODE_CA) + { + CARD32 cur, sub; + cur = GetTimeInMillis (); + sub = cur - pPort->prev_time; + pPort->prev_time = cur; + ErrorF ("getstill interval : %6ld ms\n", sub); + } + + if (pPort->retire_timer) + { + TimerFree (pPort->retire_timer); + pPort->retire_timer = NULL; + } + + if (pSec->pVideoPriv->no_retbuf) + _secVirtualVideoRemoveReturnBufAll (pPort); + + pPort->retire_timer = TimerSet (pPort->retire_timer, 0, 4000, + _secVirtualVideoRetireTimeout, + pPort); + XDBG_GOTO_IF_FAIL (pPort->id > 0, put_still_fail); + + pPort->status = 0; + pPort->retire_time = GetTimeInMillis (); + + ret = _secVirtualVideoPreProcess (pScrn, pPort, clipBoxes, pDraw); + XDBG_GOTO_IF_FAIL (ret == Success, put_still_fail); + + ret = _secVirtualVideoAddDrawableEvent (pPort); + XDBG_GOTO_IF_FAIL (ret == Success, put_still_fail); + + /* check drawable */ + XDBG_RETURN_VAL_IF_FAIL (pDraw->type == DRAWABLE_PIXMAP, BadPixmap); + + if (!pPort->putstill_on) + { + pPort->putstill_on = TRUE; + XDBG_SECURE (MVA, "pPort(%d) putstill on. secure(%d), capture(%d), format(%c%c%c%c)\n", + pPort->index, pPort->secure, pPort->capture, FOURCC_STR (pPort->id), 60); + } + + pPort->need_damage = TRUE; + + if (pPort->capture == CAPTURE_MODE_STILL && pPort->display == DISPLAY_LCD) + { + XDBG_DEBUG (MVA, "still mode.\n"); + + if (1) + ret = _secVirtualVideoPutStill (pPort); + else + /* camera buffer can't be mapped. we should use WB to capture screen */ + ret = _secVirtualVideoPutWB (pPort); + + XDBG_GOTO_IF_FAIL (ret == Success, put_still_fail); + } + else if (pPort->capture == CAPTURE_MODE_STREAM && pPort->display == DISPLAY_LCD) + { + XDBG_DEBUG (MVA, "stream mode.\n"); + if (SECPTR (pScrn)->isLcdOff) + { + XDBG_TRACE (MVA, "DPMS status: off. \n"); + ret = BadRequest; + goto put_still_fail; + } + + ret = _secVirtualVideoPutWB (pPort); + if (ret != Success) + goto put_still_fail; + } + else if (pPort->capture == CAPTURE_MODE_STREAM && pPort->display == DISPLAY_EXTERNAL) + { + int old_data_type = pPort->data_type; + SECVideoBuf *black; + + switch (pSecMode->set_mode) + { + case DISPLAY_SET_MODE_OFF: + XDBG_DEBUG (MVA, "display mode is off. \n"); + black = _secVirtualVideoGetBlackBuffer (pPort); + XDBG_RETURN_VAL_IF_FAIL (black != NULL, BadRequest); + XDBG_DEBUG (MVA, "black buffer(%d) return: lcd off\n", black->keys[0]); + _secVirtualVideoDraw (pPort, black); + ret = Success; + goto put_still_fail; + + case DISPLAY_SET_MODE_CLONE: + pPort->data_type = _secVirtualVideoDataType (pPort); + + if (pPort->data_type != old_data_type) + _secVirtualVideoSendPortNotify (pPort, PAA_DATA_TYPE, pPort->data_type); + + if (pPort->data_type == DATA_TYPE_UI) + { + XDBG_DEBUG (MVA, "clone mode.\n"); + + ret = _secVirtualVideoPutWB (pPort); + if (ret != Success) + goto put_still_fail; + } + else + { + XDBG_DEBUG (MVA, "video only mode.\n"); + ret = _secVirtualVideoPutVideoOnly (pPort); + if (ret != Success) + goto put_still_fail; + } + break; + + case DISPLAY_SET_MODE_EXT: + XDBG_DEBUG (MVA, "desktop mode.\n"); + + if (pSecMode->ext_connector_mode.hdisplay != pDraw->width || + pSecMode->ext_connector_mode.vdisplay != pDraw->height) + { + XDBG_ERROR (MVA, "drawble should have %dx%d size. mode(%d), conn(%d)\n", + pSecMode->ext_connector_mode.hdisplay, + pSecMode->ext_connector_mode.vdisplay, + pSecMode->set_mode, pSecMode->conn_mode); + ret = BadRequest; + goto put_still_fail; + } + + ret = _secVirtualVideoPutExt (pPort); + if (ret != Success) + goto put_still_fail; + break; + + default: + break; + } + } + else + { + XDBG_NEVER_GET_HERE (MVA); + ret = BadRequest; + goto put_still_fail; + } + + XDBG_DEBUG (MVA, "***************************************.. \n"); + return Success; + +put_still_fail: + pPort->need_damage = FALSE; + + if (pPort->retire_timer) + { + TimerFree (pPort->retire_timer); + pPort->retire_timer = NULL; + } + + XDBG_DEBUG (MVA, "***************************************.. \n"); + + return ret; +} + +static void +SECVirtualVideoStop (ScrnInfoPtr pScrn, pointer data, Bool exit) +{ + SECPortPrivPtr pPort = (SECPortPrivPtr) data; + + _secVirtualVideoStreamOff (pPort); +} + +static int +SECVirtualVideoDDPutStill (ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, CARD16 drw_w, CARD16 drw_h) +{ + SECVideoPortInfo *info = _port_info (pDraw); + int ret; + + if (info) + { + info->client = client; + info->pp = pPort; + } + + ret = ddPutStill (client, pDraw, pPort, pGC, + vid_x, vid_y, vid_w, vid_h, + drw_x, drw_y, drw_w, drw_h); + + return ret; +} + +XF86VideoAdaptorPtr +secVideoSetupVirtualVideo (ScreenPtr pScreen) +{ + XF86VideoAdaptorPtr pAdaptor; + SECPortPrivPtr pPort; + int i; + + pAdaptor = calloc (1, sizeof (XF86VideoAdaptorRec) + + (sizeof (DevUnion) + sizeof (SECPortPriv)) * SEC_MAX_PORT); + if (!pAdaptor) + return NULL; + + dummy_encoding[0].width = pScreen->width; + dummy_encoding[0].height = pScreen->height; + + pAdaptor->type = XvWindowMask | XvPixmapMask | XvInputMask | XvStillMask; + pAdaptor->flags = 0; + pAdaptor->name = "SEC Virtual Video"; + pAdaptor->nEncodings = sizeof (dummy_encoding) / sizeof (XF86VideoEncodingRec); + pAdaptor->pEncodings = dummy_encoding; + pAdaptor->nFormats = NUM_FORMATS; + pAdaptor->pFormats = formats; + pAdaptor->nPorts = SEC_MAX_PORT; + pAdaptor->pPortPrivates = (DevUnion*)(&pAdaptor[1]); + + pPort = (SECPortPrivPtr) (&pAdaptor->pPortPrivates[SEC_MAX_PORT]); + + for (i = 0; i < SEC_MAX_PORT; i++) + { + pAdaptor->pPortPrivates[i].ptr = &pPort[i]; + pPort[i].index = i; + pPort[i].id = FOURCC_RGB32; + pPort[i].outbuf_index = -1; + + xorg_list_init (&pPort[i].retbuf_info); + } + + pAdaptor->nAttributes = NUM_ATTRIBUTES; + pAdaptor->pAttributes = attributes; + pAdaptor->nImages = NUM_IMAGES; + pAdaptor->pImages = images; + + pAdaptor->GetPortAttribute = SECVirtualVideoGetPortAttribute; + pAdaptor->SetPortAttribute = SECVirtualVideoSetPortAttribute; + pAdaptor->QueryBestSize = SECVirtualVideoQueryBestSize; + pAdaptor->PutStill = SECVirtualVideoPutStill; + pAdaptor->StopVideo = SECVirtualVideoStop; + + if (!_secVirtualVideoRegisterEventResourceTypes ()) + { + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "Failed to register EventResourceTypes. \n"); + return NULL; + } + + return pAdaptor; +} + +void +secVirtualVideoDpms (ScrnInfoPtr pScrn, Bool on) +{ + SECPtr pSec = (SECPtr) pScrn->driverPrivate; + XF86VideoAdaptorPtr pAdaptor = pSec->pVideoPriv->pAdaptor[1]; + int i; + + if (on) + return; + + for (i = 0; i < SEC_MAX_PORT; i++) + { + SECPortPrivPtr pPort = (SECPortPrivPtr) pAdaptor->pPortPrivates[i].ptr; + + if (pPort->wb) + { + secWbClose (pPort->wb); + pPort->wb = NULL; + } + } +} + +void +secVirtualVideoReplacePutStillFunc (ScreenPtr pScreen) +{ + int i; + + XvScreenPtr xvsp = dixLookupPrivate (&pScreen->devPrivates, + XvGetScreenKey()); + if (!xvsp) + return; + + for (i = 1; i < xvsp->nAdaptors; i++) + { + XvAdaptorPtr pAdapt = xvsp->pAdaptors + i; + if (pAdapt->ddPutStill) + { + ddPutStill = pAdapt->ddPutStill; + pAdapt->ddPutStill = SECVirtualVideoDDPutStill; + break; + } + } + + if (!dixRegisterPrivateKey (VideoVirtualPortKey, PRIVATE_WINDOW, sizeof (SECVideoPortInfo))) + return; + if (!dixRegisterPrivateKey (VideoVirtualPortKey, PRIVATE_PIXMAP, sizeof (SECVideoPortInfo))) + return; +} + +void +secVirtualVideoGetBuffers (ScrnInfoPtr pScrn, int id, int width, int height, SECVideoBuf ***vbufs, int *bufnum) +{ + SECPtr pSec = (SECPtr) pScrn->driverPrivate; + XF86VideoAdaptorPtr pAdaptor = pSec->pVideoPriv->pAdaptor[1]; + int i; + + for (i = 0; i < SEC_MAX_PORT; i++) + { + SECPortPrivPtr pPort = (SECPortPrivPtr) pAdaptor->pPortPrivates[i].ptr; + + if (pPort->pDraw) + { + XDBG_RETURN_IF_FAIL (pPort->id == id); + XDBG_RETURN_IF_FAIL (pPort->pDraw->width == width); + XDBG_RETURN_IF_FAIL (pPort->pDraw->height == height); + } + + if (!_secVirtualVideoEnsureOutBuffers (pScrn, pPort, id, width, height)) + return; + + *vbufs = pPort->outbuf; + *bufnum = pPort->outbuf_num; + } +} diff --git a/src/xv/sec_video_virtual.h b/src/xv/sec_video_virtual.h new file mode 100644 index 0000000..a3400b4 --- /dev/null +++ b/src/xv/sec_video_virtual.h @@ -0,0 +1,40 @@ +/************************************************************************** + +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. + +**************************************************************************/ +#ifndef __SEC_VIDEO_VIRTUAL_H__ +#define __SEC_VIDEO_VIRTUAL_H__ + +/* setup virtual adaptor */ +XF86VideoAdaptorPtr secVideoSetupVirtualVideo (ScreenPtr pScreen); +void secVirtualVideoReplacePutStillFunc (ScreenPtr pScreen); + +void secVirtualVideoDpms (ScrnInfoPtr pScrn, Bool on); +void secVirtualVideoGetBuffers (ScrnInfoPtr pScrn, int id, int width, int height, SECVideoBuf ***vbufs, int *bufnum); + +#endif // __SEC_VIDEO_VIRTUAL_H__ diff --git a/src/xv/xv_types.h b/src/xv/xv_types.h new file mode 100644 index 0000000..e82b4e4 --- /dev/null +++ b/src/xv/xv_types.h @@ -0,0 +1,88 @@ +/************************************************************************** + +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. + +**************************************************************************/ + +/* */ +/* File name : xv_types.h */ +/* Author : Boram Park (boram1288.park@samsung.com) */ +/* Protocol Version : 1.0.1 (Dec 16th 2009) */ +/* This file is for describing Xv APIs' buffer encoding method. */ +/* */ + +#ifndef __XV_TYPE_H__ +#define __XV_TYPE_H__ + +#define XV_DATA_HEADER 0xDEADCD01 +#define XV_DATA_VERSION 0x00010001 + +/* Return Values */ +#define XV_OK 0 +#define XV_HEADER_ERROR -1 +#define XV_VERSION_MISMATCH -2 + +#define XV_BUF_TYPE_DMABUF 0 +#define XV_BUF_TYPE_LEGACY 1 + +/* Data structure for XvPutImage / XvShmPutImage */ +typedef struct +{ + unsigned int _header; /* for internal use only */ + unsigned int _version; /* for internal use only */ + + unsigned int YBuf; + unsigned int CbBuf; + unsigned int CrBuf; + + unsigned int BufType; +} XV_DATA, * XV_DATA_PTR; + +static void +#ifdef __GNUC__ +__attribute__ ((unused)) +#endif +XV_INIT_DATA (XV_DATA_PTR data) +{ + data->_header = XV_DATA_HEADER; + data->_version = XV_DATA_VERSION; +} + +static int +#ifdef __GNUC__ +__attribute__ ((unused)) +#endif +XV_VALIDATE_DATA (XV_DATA_PTR data) +{ + if (data->_header != XV_DATA_HEADER) + return XV_HEADER_ERROR; + if (data->_version != XV_DATA_VERSION) + return XV_VERSION_MISMATCH; + return XV_OK; +} + +#endif |