diff options
Diffstat (limited to 'src/xv/sec_video.c')
-rw-r--r-- | src/xv/sec_video.c | 3095 |
1 files changed, 3095 insertions, 0 deletions
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; +} |