/* * Copyright (c) 2011 Intel Corporation. All Rights Reserved. * * 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. * * Authors: * Shengquan Yuan <shengquan.yuan@intel.com> * Binglin Chen <binglin.chen@intel.com> * Jason Hu <jason.hu@intel.com> * Zeng Li <zeng.li@intel.com> */ /* * Most of rendering codes are ported from xf86-video-i810/src/i810_overlay.c */ #include <errno.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <math.h> #include <va/va_backend.h> #include <wsbm/wsbm_manager.h> #include "psb_drv_video.h" #include "psb_output.h" #include "psb_overlay.h" #include "psb_drv_debug.h" #ifdef ANDROID #define psb_xrandr_single_mode() 0 #else int psb_xrandr_single_mode(); #endif #define INIT_DRIVER_DATA psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData #define SURFACE(id) ((object_surface_p) object_heap_lookup( &driver_data->surface_heap, id )) #define CONTEXT(id) ((object_context_p) object_heap_lookup( &driver_data->context_heap, id )) //#define GET_SURFACE_INFO_rotate(psb_surface) ((int) (psb_surface)->extra_info[5]) #ifndef VA_FOURCC_I420 #define VA_FOURCC_I420 0x30323449 #endif /********************************************************************************************** * I830ResetVideo * * Description: Use this function to reset the overlay register back buffer to its default * values. Note that this function does not actually apply these values. To do so, please * write to OVADD. **********************************************************************************************/ static void I830ResetVideo(VADriverContextP ctx, PsbPortPrivPtr pPriv) { INIT_DRIVER_DATA; I830OverlayRegPtr overlayA = (I830OverlayRegPtr)(pPriv->regmap[0]); I830OverlayRegPtr overlayC = (I830OverlayRegPtr)(pPriv->regmap[1]); memset(overlayA, 0, sizeof(*overlayA)); memset(overlayC, 0, sizeof(*overlayC)); overlayA->OCLRC0 = (pPriv->contrast.Value << 18) | (pPriv->brightness.Value & 0xff); overlayA->OCLRC1 = pPriv->saturation.Value; overlayC->OCLRC0 = (pPriv->contrast.Value << 18) | (pPriv->brightness.Value & 0xff); overlayC->OCLRC1 = pPriv->saturation.Value; #if USE_DCLRK /* case bit depth 16 */ overlayA->DCLRKV = pPriv->colorKey; overlayA->DCLRKM |= DEST_KEY_ENABLE; overlayA->DCLRKM &= ~CONST_ALPHA_ENABLE; overlayC->DCLRKV = pPriv->colorKey; overlayC->DCLRKM |= DEST_KEY_ENABLE; overlayC->DCLRKM &= ~CONST_ALPHA_ENABLE; #else overlayA->DCLRKM &= ~DEST_KEY_ENABLE; overlayC->DCLRKM &= ~DEST_KEY_ENABLE; #endif overlayA->DWINSZ = 0x00000000; overlayA->OCONFIG = CC_OUT_8BIT; overlayC->DWINSZ = 0x00000000; overlayC->OCONFIG = CC_OUT_8BIT; } static uint32_t I830BoundGammaElt(uint32_t elt, uint32_t eltPrev) { elt &= 0xff; eltPrev &= 0xff; if (elt < eltPrev) elt = eltPrev; else if ((elt - eltPrev) > 0x7e) elt = eltPrev + 0x7e; return elt; } static uint32_t I830BoundGamma(uint32_t gamma, uint32_t gammaPrev) { return (I830BoundGammaElt(gamma >> 24, gammaPrev >> 24) << 24 | I830BoundGammaElt(gamma >> 16, gammaPrev >> 16) << 16 | I830BoundGammaElt(gamma >> 8, gammaPrev >> 8) << 8 | I830BoundGammaElt(gamma , gammaPrev)); } static void I830UpdateGamma(VADriverContextP ctx, PsbPortPrivPtr pPriv) { #ifndef BAYTRAIL INIT_DRIVER_DATA; uint32_t gamma0 = pPriv->gamma0; uint32_t gamma1 = pPriv->gamma1; uint32_t gamma2 = pPriv->gamma2; uint32_t gamma3 = pPriv->gamma3; uint32_t gamma4 = pPriv->gamma4; uint32_t gamma5 = pPriv->gamma5; struct drm_psb_register_rw_arg regs; gamma1 = I830BoundGamma(gamma1, gamma0); gamma2 = I830BoundGamma(gamma2, gamma1); gamma3 = I830BoundGamma(gamma3, gamma2); gamma4 = I830BoundGamma(gamma4, gamma3); gamma5 = I830BoundGamma(gamma5, gamma4); memset(®s, 0, sizeof(regs)); if (pPriv->is_mfld) regs.overlay_write_mask |= OV_REGRWBITS_OGAM_ALL | OVC_REGRWBITS_OGAM_ALL; else regs.overlay_write_mask |= OV_REGRWBITS_OGAM_ALL; regs.overlay.OGAMC0 = gamma0; regs.overlay.OGAMC1 = gamma1; regs.overlay.OGAMC2 = gamma2; regs.overlay.OGAMC3 = gamma3; regs.overlay.OGAMC4 = gamma4; regs.overlay.OGAMC5 = gamma5; drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, ®s, sizeof(regs)); #endif } static void I830StopVideo(VADriverContextP ctx) { #ifndef BAYTRAIL INIT_DRIVER_DATA; PsbPortPrivPtr pPriv = (PsbPortPrivPtr)(&driver_data->coverlay_priv); I830OverlayRegPtr overlayA, overlayC; struct drm_psb_register_rw_arg regs; if (!pPriv->overlayA_enabled && !pPriv->overlayC_enabled) { drv_debug_msg(VIDEO_DEBUG_GENERAL, "I830StopVideo : no overlay has been enabled, do nothing.\n"); return; } overlayA = (I830OverlayRegPtr)(pPriv->regmap[0]); overlayC = (I830OverlayRegPtr)(pPriv->regmap[1]); #if 0 REGION_EMPTY(pScrn->pScreen, &pPriv->clip); #endif memset(®s, 0, sizeof(regs)); if (pPriv->subpicture_enabled) { regs.subpicture_disable_mask = pPriv->subpicture_enable_mask; pPriv->subpicture_enabled = 0; drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, ®s, sizeof(regs)); } memset(®s, 0, sizeof(regs)); if (pPriv->is_mfld && psb_xrandr_single_mode() == 0) { if (pPriv->overlayC_enabled) { regs.overlay_read_mask = OVC_REGRWBITS_OVADD; drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, ®s, sizeof(regs)); overlayC->DWINSZ = 0x00000000; overlayC->OCMD &= ~OVERLAY_ENABLE; regs.overlay_read_mask = 0; regs.overlay_write_mask = OVC_REGRWBITS_OVADD; regs.overlay.b_wait_vblank = 1; drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, ®s, sizeof(regs)); memset(®s, 0, sizeof(regs)); pPriv->overlayC_enabled = 0; } if (pPriv->overlayA_enabled) { regs.overlay_read_mask = OV_REGRWBITS_OVADD; drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, ®s, sizeof(regs)); overlayA->DWINSZ = 0x00000000; overlayA->OCMD &= ~OVERLAY_ENABLE; regs.overlay_read_mask = 0; regs.overlay_write_mask = OV_REGRWBITS_OVADD; regs.overlay.b_wait_vblank = 1; drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, ®s, sizeof(regs)); pPriv->overlayA_enabled = 0; } } else { regs.overlay_read_mask = OV_REGRWBITS_OVADD; drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, ®s, sizeof(regs)); overlayA->DWINSZ = 0x00000000; overlayA->OCMD &= ~OVERLAY_ENABLE; regs.overlay_read_mask = 0; regs.overlay_write_mask = OV_REGRWBITS_OVADD; regs.overlay.b_wait_vblank = 1; drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, ®s, sizeof(regs)); pPriv->overlayA_enabled = 0; } #endif } #if 0 static void I830SwitchPipe(VADriverContextP ctx , int overlayId, int pipeId) { INIT_DRIVER_DATA; PsbPortPrivPtr pPriv = (PsbPortPrivPtr)(&driver_data->coverlay_priv); I830OverlayRegPtr overlay = (I830OverlayRegPtr)(pPriv->regmap[overlayId]); struct drm_psb_register_rw_arg regs; uint32_t overlay_mask; if ((overlayId == OVERLAY_A) && pPriv->overlayA_enabled) overlay_mask = OV_REGRWBITS_OVADD; else if ((overlayId == OVERLAY_C) && pPriv->overlayC_enabled) overlay_mask = OVC_REGRWBITS_OVADD; else return; /*No overlay enabled, do nothing.*/ drv_debug_msg(VIDEO_DEBUG_GENERAL, "Overlay %d switch to pipe %d\n", overlayId, pipeId); memset(®s, 0, sizeof(regs)); memset(overlay, 0, sizeof(*overlay)); overlay->OCLRC0 = (pPriv->contrast.Value << 18) | (pPriv->brightness.Value & 0xff); overlay->OCLRC1 = pPriv->saturation.Value; /* case bit depth 16 */ overlay->DCLRKV = pPriv->colorKey; overlay->DCLRKM |= DEST_KEY_ENABLE; overlay->DCLRKM &= ~CONST_ALPHA_ENABLE; overlay->DWINSZ = 0x00000000; overlay->OCONFIG = CC_OUT_8BIT; regs.overlay_read_mask = overlay_mask; drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, ®s, sizeof(regs)); switch (pipeId) { case PIPEA: overlay->OCONFIG |= OVERLAY_C_PIPE_A; break; case PIPEB: overlay->OCONFIG |= OVERLAY_C_PIPE_B; break; case PIPEC: overlay->OCONFIG |= OVERLAY_C_PIPE_C; break; } regs.overlay_read_mask = 0; regs.overlay_write_mask = overlay_mask; regs.overlay.b_wait_vblank = 1; drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, ®s, sizeof(regs)); } #endif static int i830_swidth(unsigned int offset, unsigned int width, unsigned int mask, int shift) { int swidth = ((offset + width + mask) >> shift) - (offset >> shift); swidth <<= 1; swidth -= 1; return swidth << 2; } static Bool SetCoeffRegs(double *coeff, int mantSize, coeffPtr pCoeff, int pos) { int maxVal, icoeff, res; int sign; double c; sign = 0; maxVal = 1 << mantSize; c = *coeff; if (c < 0.0) { sign = 1; c = -c; } res = 12 - mantSize; if ((icoeff = (int)(c * 4 * maxVal + 0.5)) < maxVal) { pCoeff[pos].exponent = 3; pCoeff[pos].mantissa = icoeff << res; *coeff = (double)icoeff / (double)(4 * maxVal); } else if ((icoeff = (int)(c * 2 * maxVal + 0.5)) < maxVal) { pCoeff[pos].exponent = 2; pCoeff[pos].mantissa = icoeff << res; *coeff = (double)icoeff / (double)(2 * maxVal); } else if ((icoeff = (int)(c * maxVal + 0.5)) < maxVal) { pCoeff[pos].exponent = 1; pCoeff[pos].mantissa = icoeff << res; *coeff = (double)icoeff / (double)(maxVal); } else if ((icoeff = (int)(c * maxVal * 0.5 + 0.5)) < maxVal) { pCoeff[pos].exponent = 0; pCoeff[pos].mantissa = icoeff << res; *coeff = (double)icoeff / (double)(maxVal / 2); } else { /* Coeff out of range */ return FALSE; } pCoeff[pos].sign = sign; if (sign) *coeff = -(*coeff); return TRUE; } static void UpdateCoeff(int taps, double fCutoff, Bool isHoriz, Bool isY, coeffPtr pCoeff) { int i, j, j1, num, pos, mantSize; double pi = 3.1415926535, val, sinc, window, sum; double rawCoeff[MAX_TAPS * 32], coeffs[N_PHASES][MAX_TAPS]; double diff; int tapAdjust[MAX_TAPS], tap2Fix; Bool isVertAndUV; if (isHoriz) mantSize = 7; else mantSize = 6; isVertAndUV = !isHoriz && !isY; num = taps * 16; for (i = 0; i < num * 2; i++) { val = (1.0 / fCutoff) * taps * pi * (i - num) / (2 * num); if (val == 0.0) sinc = 1.0; else sinc = sin(val) / val; /* Hamming window */ window = (0.5 - 0.5 * cos(i * pi / num)); rawCoeff[i] = sinc * window; } for (i = 0; i < N_PHASES; i++) { /* Normalise the coefficients. */ sum = 0.0; for (j = 0; j < taps; j++) { pos = i + j * 32; sum += rawCoeff[pos]; } for (j = 0; j < taps; j++) { pos = i + j * 32; coeffs[i][j] = rawCoeff[pos] / sum; } /* Set the register values. */ for (j = 0; j < taps; j++) { pos = j + i * taps; if ((j == (taps - 1) / 2) && !isVertAndUV) SetCoeffRegs(&coeffs[i][j], mantSize + 2, pCoeff, pos); else SetCoeffRegs(&coeffs[i][j], mantSize, pCoeff, pos); } tapAdjust[0] = (taps - 1) / 2; for (j = 1, j1 = 1; j <= tapAdjust[0]; j++, j1++) { tapAdjust[j1] = tapAdjust[0] - j; tapAdjust[++j1] = tapAdjust[0] + j; } /* Adjust the coefficients. */ sum = 0.0; for (j = 0; j < taps; j++) sum += coeffs[i][j]; if (sum != 1.0) { for (j1 = 0; j1 < taps; j1++) { tap2Fix = tapAdjust[j1]; diff = 1.0 - sum; coeffs[i][tap2Fix] += diff; pos = tap2Fix + i * taps; if ((tap2Fix == (taps - 1) / 2) && !isVertAndUV) SetCoeffRegs(&coeffs[i][tap2Fix], mantSize + 2, pCoeff, pos); else SetCoeffRegs(&coeffs[i][tap2Fix], mantSize, pCoeff, pos); sum = 0.0; for (j = 0; j < taps; j++) sum += coeffs[i][j]; if (sum == 1.0) break; } } } } static void i830_display_video( VADriverContextP ctx, PsbPortPrivPtr pPriv, VASurfaceID __maybe_unused surface, int id, short width, short height, int dstPitch, int srcPitch, int __maybe_unused x1, int __maybe_unused y1, int __maybe_unused x2, int __maybe_unused y2, BoxPtr dstBox, short src_w, short src_h, short drw_w, short drw_h, unsigned int flags, int overlayId, int pipeId) { #ifndef BAYTRAIL INIT_DRIVER_DATA; unsigned int swidth, swidthy, swidthuv; unsigned int mask, shift, offsety, offsetu; int tmp; uint32_t OCMD; Bool scaleChanged = FALSE; unsigned int offset = wsbmBOOffsetHint(pPriv->wsbo[overlayId]) & 0x0FFFFFFF; I830OverlayRegPtr overlay = (I830OverlayRegPtr)(pPriv->regmap[overlayId]); struct drm_psb_register_rw_arg regs; int i32EnableIEP = 0; int i32EnableIEPBLE = 0; /*before enabling overlay, make sure overlay is disabled first.*/ if ((overlayId == OVERLAY_A) && !pPriv->overlayA_enabled) { memset(®s, 0, sizeof(regs)); regs.overlay_read_mask = OV_REGRWBITS_OVADD; drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, ®s, sizeof(regs)); overlay->OCMD &= ~OVERLAY_ENABLE; regs.overlay_read_mask = 0; regs.overlay_write_mask = OV_REGRWBITS_OVADD; drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, ®s, sizeof(regs)); } /* FIXME: don't know who and why add this * comment it for full screen scale issue * any concern contact qiang.miao@intel.com */ #if 0 if (drw_w >= 800) { x2 = x2 / 4; y2 = y2 / 4; dstBox->x2 = dstBox->x2 / 4; dstBox->y2 = dstBox->y2 / 4; drw_w = drw_w / 4; drw_h = drw_h / 4; } #endif #if USE_DCLRK overlay->DCLRKM &= ~CONST_ALPHA_ENABLE; if (pPriv->subpicture_enabled) overlay->DCLRKM &= ~DEST_KEY_ENABLE; else overlay->DCLRKM |= DEST_KEY_ENABLE; overlay->DCLRKV = pPriv->colorKey; overlay->DCLRKM |= 0xffffff; #else /* disable overlay destination color key didn't work, * it seems z-order of overlay has been bellow display pipe. */ overlay->DCLRKM &= ~DEST_KEY_ENABLE; #endif #if USE_ROTATION_FUNC if (((pipeId == PIPEA) && (driver_data->mipi0_rotation != VA_ROTATION_NONE)) || ((pipeId == PIPEB) && (driver_data->hdmi_rotation != VA_ROTATION_NONE))) { switch (pPriv->rotation) { case VA_ROTATION_NONE: break; case VA_ROTATION_270: tmp = dstBox->x1; dstBox->x1 = dstBox->y1; dstBox->y1 = pPriv->height_save - tmp; tmp = dstBox->x2; dstBox->x2 = dstBox->y2; dstBox->y2 = pPriv->height_save - tmp; tmp = dstBox->y1; dstBox->y1 = dstBox->y2; dstBox->y2 = tmp; tmp = drw_w; drw_w = drw_h; drw_h = tmp; break; case VA_ROTATION_180: tmp = dstBox->x1; dstBox->x1 = pPriv->width_save - dstBox->x2; dstBox->x2 = pPriv->width_save - tmp; tmp = dstBox->y1; dstBox->y1 = pPriv->height_save - dstBox->y2; dstBox->y2 = pPriv->height_save - tmp; break; case VA_ROTATION_90: tmp = dstBox->x1; dstBox->x1 = pPriv->width_save - dstBox->y1; dstBox->y1 = tmp; tmp = dstBox->x2; dstBox->x2 = pPriv->width_save - dstBox->y2; dstBox->y2 = tmp; tmp = dstBox->x1; dstBox->x1 = dstBox->x2; dstBox->x2 = tmp; tmp = drw_w; drw_w = drw_h; drw_h = tmp; break; } } #endif if (pPriv->oneLineMode) { /* change the coordinates with panel fitting active */ dstBox->y1 = (((dstBox->y1 - 1) * pPriv->scaleRatio) >> 16) + 1; dstBox->y2 = ((dstBox->y2 * pPriv->scaleRatio) >> 16) + 1; /* Now, alter the height, so we scale to the correct size */ drw_h = ((drw_h * pPriv->scaleRatio) >> 16) + 1; } shift = 6; mask = 0x3f; if (pPriv->curBuf == 0) { offsety = pPriv->YBuf0offset; offsetu = pPriv->UBuf0offset; } else { offsety = pPriv->YBuf1offset; offsetu = pPriv->UBuf1offset; } switch (id) { case VA_FOURCC_NV12: overlay->SWIDTH = width | ((width / 2 & 0x7ff) << 16); swidthy = i830_swidth(offsety, width, mask, shift); swidthuv = i830_swidth(offsetu, width / 2, mask, shift); overlay->SWIDTHSW = (swidthy) | (swidthuv << 16); overlay->SHEIGHT = height | ((height / 2) << 16); break; case VA_FOURCC_YV12: case VA_FOURCC_I420: overlay->SWIDTH = width | ((width / 2 & 0x7ff) << 16); swidthy = i830_swidth(offsety, width, mask, shift); swidthuv = i830_swidth(offsetu, width / 2, mask, shift); overlay->SWIDTHSW = (swidthy) | (swidthuv << 16); overlay->SHEIGHT = height | ((height / 2) << 16); break; case VA_FOURCC_UYVY: case VA_FOURCC_YUY2: default: overlay->SWIDTH = width; swidth = ((offsety + (width << 1) + mask) >> shift) - (offsety >> shift); swidth <<= 1; swidth -= 1; swidth <<= 2; overlay->SWIDTHSW = swidth; overlay->SHEIGHT = height; break; } overlay->DWINPOS = (dstBox->y1 << 16) | dstBox->x1; overlay->DWINSZ = (((dstBox->y2 - dstBox->y1) << 16) | (dstBox->x2 - dstBox->x1)); /* buffer locations */ overlay->OBUF_0Y = pPriv->YBuf0offset; overlay->OBUF_0U = pPriv->UBuf0offset; overlay->OBUF_0V = pPriv->VBuf0offset; overlay->OBUF_1Y = pPriv->YBuf1offset; overlay->OBUF_1U = pPriv->UBuf1offset; overlay->OBUF_1V = pPriv->VBuf1offset; /* * Calculate horizontal and vertical scaling factors and polyphase * coefficients. */ if (1) { int xscaleInt, xscaleFract, yscaleInt, yscaleFract; int xscaleIntUV, xscaleFractUV; int yscaleIntUV, yscaleFractUV; /* UV is half the size of Y -- YUV420 */ int uvratio = 2; uint32_t newval; coeffRec xcoeffY[N_HORIZ_Y_TAPS * N_PHASES]; coeffRec xcoeffUV[N_HORIZ_UV_TAPS * N_PHASES]; int i, j, pos; int deinterlace_factor; /* * Y down-scale factor as a multiple of 4096. */ if ((id == VA_FOURCC_NV12) && (0 != (flags & (VA_TOP_FIELD | VA_BOTTOM_FIELD)))) deinterlace_factor = 2; else deinterlace_factor = 1; /* deinterlace requires twice of VSCALE setting*/ if (src_w == drw_w && src_h == drw_h) { xscaleFract = 1 << 12; yscaleFract = (1 << 12) / deinterlace_factor; } else { xscaleFract = ((src_w - 1) << 12) / drw_w; yscaleFract = ((src_h - 1) << 12) / (deinterlace_factor * drw_h); } /* Calculate the UV scaling factor. */ xscaleFractUV = xscaleFract / uvratio; yscaleFractUV = yscaleFract / uvratio; /* * To keep the relative Y and UV ratios exact, round the Y scales * to a multiple of the Y/UV ratio. */ xscaleFract = xscaleFractUV * uvratio; yscaleFract = yscaleFractUV * uvratio; /* Integer (un-multiplied) values. */ xscaleInt = xscaleFract >> 12; yscaleInt = yscaleFract >> 12; xscaleIntUV = xscaleFractUV >> 12; yscaleIntUV = yscaleFractUV >> 12; /* shouldn't get here */ if (xscaleInt > 7) { return; } /* shouldn't get here */ if (xscaleIntUV > 7) { return; } if (pPriv->is_mfld) newval = (xscaleInt << 15) | ((xscaleFract & 0xFFF) << 3) | ((yscaleFract & 0xFFF) << 20); else newval = (xscaleInt << 16) | ((xscaleFract & 0xFFF) << 3) | ((yscaleFract & 0xFFF) << 20); if (newval != overlay->YRGBSCALE) { scaleChanged = TRUE; overlay->YRGBSCALE = newval; } if (pPriv->is_mfld) newval = (xscaleIntUV << 15) | ((xscaleFractUV & 0xFFF) << 3) | ((yscaleFractUV & 0xFFF) << 20); else newval = (xscaleIntUV << 16) | ((xscaleFractUV & 0xFFF) << 3) | ((yscaleFractUV & 0xFFF) << 20); if (newval != overlay->UVSCALE) { scaleChanged = TRUE; overlay->UVSCALE = newval; } newval = yscaleInt << 16 | yscaleIntUV; if (newval != overlay->UVSCALEV) { scaleChanged = TRUE; overlay->UVSCALEV = newval; } /* Recalculate coefficients if the scaling changed. */ /* * Only Horizontal coefficients so far. */ if (scaleChanged) { double fCutoffY; double fCutoffUV; fCutoffY = xscaleFract / 4096.0; fCutoffUV = xscaleFractUV / 4096.0; /* Limit to between 1.0 and 3.0. */ if (fCutoffY < MIN_CUTOFF_FREQ) fCutoffY = MIN_CUTOFF_FREQ; if (fCutoffY > MAX_CUTOFF_FREQ) fCutoffY = MAX_CUTOFF_FREQ; if (fCutoffUV < MIN_CUTOFF_FREQ) fCutoffUV = MIN_CUTOFF_FREQ; if (fCutoffUV > MAX_CUTOFF_FREQ) fCutoffUV = MAX_CUTOFF_FREQ; UpdateCoeff(N_HORIZ_Y_TAPS, fCutoffY, TRUE, TRUE, xcoeffY); UpdateCoeff(N_HORIZ_UV_TAPS, fCutoffUV, TRUE, FALSE, xcoeffUV); for (i = 0; i < N_PHASES; i++) { for (j = 0; j < N_HORIZ_Y_TAPS; j++) { pos = i * N_HORIZ_Y_TAPS + j; overlay->Y_HCOEFS[pos] = (xcoeffY[pos].sign << 15 | xcoeffY[pos].exponent << 12 | xcoeffY[pos].mantissa); } } for (i = 0; i < N_PHASES; i++) { for (j = 0; j < N_HORIZ_UV_TAPS; j++) { pos = i * N_HORIZ_UV_TAPS + j; overlay->UV_HCOEFS[pos] = (xcoeffUV[pos].sign << 15 | xcoeffUV[pos].exponent << 12 | xcoeffUV[pos].mantissa); } } } } OCMD = OVERLAY_ENABLE; switch (id) { case VA_FOURCC_NV12: overlay->OSTRIDE = dstPitch | (dstPitch << 16); OCMD &= ~SOURCE_FORMAT; OCMD &= ~OV_BYTE_ORDER; OCMD |= NV12;//in the spec, there are two NV12, which to use? break; case VA_FOURCC_YV12: case VA_FOURCC_I420: /* set UV vertical phase to -0.25 */ /* overlay->UV_VPH = 0x30003000; */ overlay->OSTRIDE = (dstPitch * 2) | (dstPitch << 16); OCMD &= ~SOURCE_FORMAT; OCMD &= ~OV_BYTE_ORDER; OCMD |= YUV_420; break; case VA_FOURCC_UYVY: case VA_FOURCC_YUY2: overlay->OSTRIDE = dstPitch; OCMD &= ~SOURCE_FORMAT; OCMD |= YUV_422; OCMD &= ~OV_BYTE_ORDER; if (id == VA_FOURCC_UYVY) OCMD |= Y_SWAP; break; } if (flags & (VA_TOP_FIELD | VA_BOTTOM_FIELD)) { OCMD |= BUF_TYPE_FIELD; OCMD &= ~FIELD_SELECT; if (flags & VA_BOTTOM_FIELD) { OCMD |= FIELD1; overlay->OBUF_0Y = pPriv->YBuf0offset - srcPitch; overlay->OBUF_0U = pPriv->UBuf0offset - srcPitch; overlay->OBUF_0V = pPriv->VBuf0offset - srcPitch; overlay->OBUF_1Y = pPriv->YBuf1offset - srcPitch; overlay->OBUF_1U = pPriv->UBuf1offset - srcPitch; overlay->OBUF_1V = pPriv->VBuf1offset - srcPitch; } else OCMD |= FIELD0; } else { OCMD &= ~(FIELD_SELECT); OCMD &= ~BUF_TYPE_FIELD; } OCMD &= ~(BUFFER_SELECT); if (pPriv->curBuf == 0) OCMD |= BUFFER0; else OCMD |= BUFFER1; overlay->OCMD = OCMD; memset(®s, 0, sizeof(regs)); switch (overlayId) { case OVERLAY_A: pPriv->overlayA_enabled = 1; regs.overlay_write_mask = OV_REGRWBITS_OVADD; break; case OVERLAY_C: pPriv->overlayC_enabled = 1; regs.overlay_write_mask = OVC_REGRWBITS_OVADD; break; } if (pPriv->is_mfld) { i32EnableIEP = 0; i32EnableIEPBLE = 0; if (i32EnableIEP == 0) { overlay->OCONFIG = CC_OUT_8BIT; overlay->OCONFIG &= OVERLAY_C_PIPE_A | (~OVERLAY_C_PIPE_MASK); overlay->OCONFIG |= IEP_LITE_BYPASS; regs.overlay.OVADD = offset | 1; regs.overlay.IEP_ENABLED = 0; regs.overlay.buffer_handle = wsbmKBufHandle(wsbmKBuf(pPriv->wsbo[overlayId])); } } else { overlay->OCONFIG = CC_OUT_8BIT; overlay->OCONFIG |= IEP_LITE_BYPASS; regs.overlay.OVADD = offset | 1; } if (pPriv->is_mfld) { switch (pipeId) { case PIPEA: overlay->OCONFIG |= OVERLAY_C_PIPE_A; overlay->OCONFIG |= ZORDER_TOP; break; case PIPEB: overlay->OCONFIG |= OVERLAY_C_PIPE_B; overlay->OCONFIG |= ZORDER_TOP; regs.overlay.OVADD |= 0x80; break; case PIPEC: overlay->OCONFIG |= OVERLAY_C_PIPE_C; overlay->OCONFIG |= ZORDER_TOP; regs.overlay.OVADD |= 0x40; break; } overlay->OCONFIG |= ZORDER_TOP; } else overlay->OCONFIG |= pipeId << 18; /* mrst */ if (IS_CTP(driver_data) || IS_MRFL(driver_data) ) regs.overlay.b_wms = 1; drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, ®s, sizeof(regs)); if (pPriv->is_mfld) { if (regs.overlay.IEP_ENABLED) { #if 0 printf("regs.overlay BLE minmax 0x%x, BSSCC control 0x%x\n", regs.overlay.IEP_BLE_MINMAX, regs.overlay.IEP_BSSCC_CONTROL); #endif *(unsigned int *)((unsigned int)&(overlay->IEP_SPACE[0]) + 0x804) = regs.overlay.IEP_BLE_MINMAX; } } #endif } static void I830PutImageFlipRotateSurface( VADriverContextP ctx, object_surface_p obj_surface, int *src_w_new, int *src_h_new, int *width_new, int *height_new, psb_surface_p *psb_surface_new, int pipeId) { int src_w = *src_w_new, src_h = *src_h_new; int width = *width_new, height = *height_new; int tmp = 0; psb_surface_p psb_surface = NULL; INIT_DRIVER_DATA; PsbPortPrivPtr pPriv; /* local/extend display doesn't have render rotation */ if (((pipeId == PIPEA) && (driver_data->local_rotation == VA_ROTATION_NONE)) || ((pipeId == PIPEB) && (driver_data->extend_rotation == VA_ROTATION_NONE))) return; pPriv = (PsbPortPrivPtr)(&driver_data->coverlay_priv); if (pipeId == PIPEA) { if (driver_data->local_rotation != VA_ROTATION_NONE) { psb_surface = obj_surface->out_loop_surface; width = obj_surface->width_r; height = obj_surface->height_r; if (driver_data->local_rotation != VA_ROTATION_180) { tmp = src_w; src_w = src_h; src_h = tmp; } } if ((driver_data->local_rotation == VA_ROTATION_NONE) || (driver_data->local_rotation == VA_ROTATION_180)) { pPriv->width_save = pPriv->display_width; pPriv->height_save = pPriv->display_height; } else { pPriv->width_save = pPriv->display_height; pPriv->height_save = pPriv->display_width; } if (driver_data->is_android == 0) pPriv->rotation = driver_data->local_rotation; else pPriv->rotation = 0; } else if (pipeId == PIPEB) { if (driver_data->extend_rotation != VA_ROTATION_NONE) { psb_surface = obj_surface->out_loop_surface; width = obj_surface->width_r; height = obj_surface->height_r; if (driver_data->extend_rotation != VA_ROTATION_180) { tmp = src_w; src_w = src_h; src_h = tmp; } } if ((driver_data->extend_rotation == VA_ROTATION_NONE) || (driver_data->extend_rotation == VA_ROTATION_180)) { pPriv->width_save = pPriv->extend_display_width; pPriv->height_save = pPriv->extend_display_height; } else { pPriv->width_save = pPriv->extend_display_height; pPriv->height_save = pPriv->extend_display_width; } if (driver_data->is_android == 0) pPriv->rotation = driver_data->extend_rotation; else pPriv->rotation = 0; } *src_w_new = src_w; *src_h_new = src_h; *width_new = width; *height_new = height; *psb_surface_new = psb_surface; } static int I830PutImageFlipRotateDebug( VADriverContextP ctx, VASurfaceID surface, short __maybe_unused src_x, short __maybe_unused src_y, short __maybe_unused src_w, short __maybe_unused src_h, short __maybe_unused drw_x, short __maybe_unused drw_y, short __maybe_unused drw_w, short __maybe_unused drw_h, int __maybe_unused fourcc, int __maybe_unused flags, int __maybe_unused overlayId, int pipeId) { INIT_DRIVER_DATA; object_surface_p obj_surface; psb_surface_p psb_surface = NULL; VAStatus vaStatus = VA_STATUS_SUCCESS; obj_surface = SURFACE(surface); CHECK_SURFACE(obj_surface); if (pipeId != 0) return -1; psb_surface = obj_surface->out_loop_surface; psb_buffer_p buf = &psb_surface->buf; unsigned char *data, *chroma, *buffer, *header; static FILE *pf = NULL; int ret, i; if (!psb_surface) goto dump_out; if (pf == NULL) if ((pf = fopen("/home/dump.yuv", "w+")) == NULL) { printf("Open yuv file fails\n"); return -1; } ret = psb_buffer_map(buf, &data); if (ret) { printf("Map buffer fail\n"); return -1; } for (i = 0; i < obj_surface->height_r; i++) { fwrite(data, 1, obj_surface->width_r, pf); data += psb_surface->stride; } buffer = malloc(obj_surface->height_r * obj_surface->width_r); if (!buffer) { printf("Alloc chroma buffer fail\n"); return -1; } header = buffer; chroma = data; for (i = 0; i < obj_surface->height_r / 2; i++) { int j; for (j = 0; j < obj_surface->width_r / 2; j++) { *buffer++ = data[j*2]; } data += psb_surface->stride; } data = chroma; for (i = 0; i < obj_surface->height_r / 2; i++) { int j; for (j = 0; j < obj_surface->width_r / 2; j++) { *buffer++ = data[j*2 + 1]; } data += psb_surface->stride; } fwrite(header, obj_surface->height_r / 2, obj_surface->width_r, pf); free(header); psb_buffer_unmap(buf); return 0; dump_out: return -1; } /* * The source rectangle of the video is defined by (src_x, src_y, src_w, src_h). * The dest rectangle of the video is defined by (drw_x, drw_y, drw_w, drw_h). * id is a fourcc code for the format of the video. * buf is the pointer to the source data in system memory. * width and height are the w/h of the source data. * If "sync" is TRUE, then we must be finished with *buf at the point of return * (which we always are). * clipBoxes is the clipping region in screen space. * data is a pointer to our port private. * pDraw is a Drawable, which might not be the screen in the case of * compositing. It's a new argument to the function in the 1.1 server. */ static int I830PutImage( VADriverContextP ctx, VASurfaceID surface, int src_x, int src_y, int src_w, int src_h, int drw_x, int drw_y, int drw_w, int drw_h, int fourcc, int flags, int overlayId, int pipeId) { INIT_DRIVER_DATA; int x1, x2, y1, y2; int width, height; int top, left, npixels; int pitch = 0, pitch2 = 0; unsigned int pre_add; unsigned int gtt_ofs; struct _WsbmBufferObject *drm_buf; BoxRec dstBox; PsbPortPrivPtr pPriv; object_surface_p obj_surface = SURFACE(surface); psb_surface_p psb_surface = NULL; /* silent kw */ if (NULL == obj_surface) return 1; pPriv = (PsbPortPrivPtr)(&driver_data->coverlay_priv); switch (fourcc) { case VA_FOURCC_NV12: width = obj_surface->width; height = obj_surface->height; break; default: width = obj_surface->width; height = obj_surface->height; break; } /* rotate support here: more check? * and for oold also? */ psb_surface = obj_surface->psb_surface; I830PutImageFlipRotateSurface(ctx, obj_surface, &src_w, &src_h, &width, &height, &psb_surface, pipeId); if (NULL == psb_surface) { /*Rotate surface may not be ready, so we have to discard this frame.*/ drv_debug_msg(VIDEO_DEBUG_GENERAL, "Discard this frame if rotate surface hasn't be ready.\n"); return 1; } width = (width <= 1920) ? width : 1920; /* If dst width and height are less than 1/8th the src size, the * src/dst scale factor becomes larger than 8 and doesn't fit in * the scale register. */ if (src_w >= (drw_w * 8)) drw_w = src_w / 7; if (src_h >= (drw_h * 8)) drw_h = src_h / 7; /* Clip */ x1 = src_x; x2 = src_x + src_w; y1 = src_y; y2 = src_y + src_h; dstBox.x1 = drw_x; dstBox.x2 = drw_x + drw_w; dstBox.y1 = drw_y; dstBox.y2 = drw_y + drw_h; #if USE_CLIP_FUNC if (!i830_get_crtc(pScrn, &crtc, &dstBox)) return Success; /* *Update drw_* and 'clipBoxes' according to current downscale/upscale state * Make sure the area determined by drw_* is in 'clipBoxes' */ if (crtc->rotation & (RR_Rotate_90 | RR_Rotate_270)) { h_ratio = (float)pScrn->pScreen->height / pPriv->width_save; v_ratio = (float)pScrn->pScreen->width / pPriv->height_save; } else { h_ratio = (float)pScrn->pScreen->width / pPriv->width_save; v_ratio = (float)pScrn->pScreen->height / pPriv->height_save; } /* Horizontal downscale/upscale */ if ((int)h_ratio) clipBoxes->extents.x1 /= h_ratio; else if (!(int)h_ratio) clipBoxes->extents.x2 /= h_ratio; /* Vertical downscale/upscale */ if ((int)v_ratio) clipBoxes->extents.y1 /= v_ratio; else if (!(int)v_ratio) clipBoxes->extents.y2 /= v_ratio; drw_x /= h_ratio; drw_y /= v_ratio; drw_w /= h_ratio; drw_h /= v_ratio; dstBox.x1 = drw_x; dstBox.x2 = drw_x + drw_w; dstBox.y1 = drw_y; dstBox.y2 = drw_y + drw_h; /* Count in client supplied clipboxes */ clipRegion = clipBoxes; psb_perform_clip(pScrn, vaPtr->clipbox, vaPtr->num_clipbox, clipBoxes, clipRegion, pDraw); if (!i830_clip_video_helper(pScrn, &crtc, &dstBox, &x1, &x2, &y1, &y2, clipRegion, width, height)) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "%s: Fail to clip video to any crtc!\n", __FUNCTION__); return 0; } #endif switch (fourcc) { case VA_FOURCC_NV12: pitch = (width + 0x3) & ~0x3; pitch2 = psb_surface->stride; break; case VA_FOURCC_YV12: case VA_FOURCC_I420: pitch = (width + 0x3) & ~0x3; break; #if USE_DISPLAY_C_SPRITE case FOURCC_RGBA: pitch = width << 2; break; #endif case VA_FOURCC_UYVY: case VA_FOURCC_YUY2: default: pitch = width << 1; break; } top = (y1) & ~1; left = (x1) & ~1; npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left; if (fourcc == VA_FOURCC_NV12) { pre_add = psb_surface->buf.buffer_ofs; drm_buf = psb_surface->buf.drm_buf; gtt_ofs = wsbmBOOffsetHint(drm_buf) & 0x0FFFFFFF; /*skip pad bytes.*/ if (driver_data->local_rotation == VA_ROTATION_90) { left += ((src_w + 0xf) & ~0xf) - src_w; } else if (driver_data->local_rotation == VA_ROTATION_270) { top += ((src_h + 0xf) & ~0xf) - src_h; } else if (driver_data->local_rotation == VA_ROTATION_180) { left += ((src_w + 0xf) & ~0xf) - src_w; top += ((src_h + 0xf) & ~0xf) - src_h; } pPriv->YBuf0offset = pre_add + gtt_ofs + top * pitch2 + left; pPriv->YBuf1offset = pPriv->YBuf0offset; pPriv->UBuf0offset = pre_add + gtt_ofs + (pitch2 * height) + top * (pitch2 / 2) + left; pPriv->VBuf0offset = pPriv->UBuf0offset; pPriv->UBuf1offset = pPriv->UBuf0offset; pPriv->VBuf1offset = pPriv->UBuf0offset; } else { //TBD //pPriv->YBuf0offset = pPriv->videoBuf0_gtt_offset << PAGE_SHIFT; //pPriv->YBuf1offset = pPriv->videoBuf1_gtt_offset << PAGE_SHIFT; if (pPriv->rotation & (RR_Rotate_90 | RR_Rotate_270)) { pPriv->UBuf0offset = pPriv->YBuf0offset + (pitch2 * width); pPriv->VBuf0offset = pPriv->UBuf0offset + (pitch2 * width / 2); pPriv->UBuf1offset = pPriv->YBuf1offset + (pitch2 * width); pPriv->VBuf1offset = pPriv->UBuf1offset + (pitch2 * width / 2); } else { pPriv->UBuf0offset = pPriv->YBuf0offset + (pitch2 * height); pPriv->VBuf0offset = pPriv->UBuf0offset + (pitch2 * height / 2); pPriv->UBuf1offset = pPriv->YBuf1offset + (pitch2 * height); pPriv->VBuf1offset = pPriv->UBuf1offset + (pitch2 * height / 2); } } #if USE_DISPLAY_C_SPRITE if (fourcc == FOURCC_RGBA \ || (fourcc == FOURCC_XVVA \ && (pPriv->rotation != RR_Rotate_0) \ && (vaPtr->dst_srf.fourcc == VA_FOURCC_RGBA))) i830_display_video_sprite(pScrn, crtc, width, height, dstPitch, &dstBox, sprite_offset); else #endif i830_display_video(ctx, pPriv, surface, fourcc, src_w, src_h, pitch2, pitch, x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h, flags, overlayId, pipeId); // FIXME : do I use two buffers here really? // pPriv->curBuf = (pPriv->curBuf + 1) & 1; return Success; } static void psbPortPrivCreate(PsbPortPrivPtr pPriv) { #if 0 REGION_NULL(pScreen, &pPriv->clip); #endif /* coeffs defaut value */ pPriv->brightness.Value = OV_BRIGHTNESS_DEFAULT_VALUE; pPriv->brightness.Fraction = 0; pPriv->contrast.Value = OV_CONTRAST_DEFAULT_VALUE; pPriv->contrast.Fraction = 0; pPriv->hue.Value = OV_HUE_DEFAULT_VALUE; pPriv->hue.Fraction = 0; pPriv->saturation.Value = OV_SATURATION_DEFAULT_VALUE; pPriv->saturation.Fraction = 0; pPriv->subpicture_enabled = 0; pPriv->subpicture_enable_mask = 0; pPriv->overlayA_enabled = 0; pPriv->overlayC_enabled = 0; pPriv->overlayA_pipeId = PIPEA; pPriv->overlayC_pipeId = PIPEB; /* FIXME: is this right? set up to current screen size */ #if 1 pPriv->width_save = 1024; pPriv->height_save = 600; #endif } static void psbPortPrivDestroy(VADriverContextP ctx, PsbPortPrivPtr pPriv) { I830StopVideo(ctx); wsbmBOUnmap(pPriv->wsbo[0]); wsbmBOUnreference(&pPriv->wsbo[0]); wsbmBOUnmap(pPriv->wsbo[1]); wsbmBOUnreference(&pPriv->wsbo[1]); if (pPriv->is_mfld) { if (pPriv->p_iep_lite_context) free(pPriv->p_iep_lite_context); } pPriv->p_iep_lite_context = NULL; } static int psbSetupImageVideoOverlay(VADriverContextP ctx, PsbPortPrivPtr pPriv) { INIT_DRIVER_DATA; I830OverlayRegPtr overlayA = NULL; I830OverlayRegPtr overlayC = NULL; int ret; psbPortPrivCreate(pPriv); /* use green as color key by default for android media player */ pPriv->colorKey = driver_data->color_key/*0x0440*/; /*Bypass color correction. Because these color correction can be done in pipe color correction in future.*/ pPriv->brightness.Value = 0; /*-19*/ pPriv->contrast.Value = 0x40; /*75*/ pPriv->saturation.Value = 0x80; /*146*/ pPriv->gamma5 = 0xc0c0c0; pPriv->gamma4 = 0x808080; pPriv->gamma3 = 0x404040; pPriv->gamma2 = 0x202020; pPriv->gamma1 = 0x101010; pPriv->gamma0 = 0x080808; pPriv->rotation = VA_ROTATION_NONE; pPriv->subpic_clear_flag = 1; #if 0 /* gotta uninit this someplace */ REGION_NULL(pScreen, &pPriv->clip); #endif /* With LFP's we need to detect whether we're in One Line Mode, which * essentially means a resolution greater than 1024x768, and fix up * the scaler accordingly. */ pPriv->scaleRatio = 0x10000; pPriv->oneLineMode = FALSE; ret = wsbmGenBuffers(driver_data->main_pool, 2, &pPriv->wsbo[0], 64 * 1024, /* 64k alignment */ WSBM_PL_FLAG_TT); if (ret) goto out_err; ret = wsbmBOData(pPriv->wsbo[0], 5 * 4096, NULL, NULL, WSBM_PL_FLAG_TT); if (ret) goto out_err_bo0; pPriv->regmap[0] = wsbmBOMap(pPriv->wsbo[0], WSBM_ACCESS_READ | WSBM_ACCESS_WRITE); if (!pPriv->regmap[0]) { goto out_err_bo0; } ret = wsbmBOData(pPriv->wsbo[1], 5 * 4096, NULL, NULL, WSBM_PL_FLAG_TT); if (ret) goto out_err_bo1; pPriv->regmap[1] = wsbmBOMap(pPriv->wsbo[1], WSBM_ACCESS_READ | WSBM_ACCESS_WRITE); if (!pPriv->regmap[1]) { goto out_err_bo1; } overlayA = (I830OverlayRegPtr)(pPriv->regmap[0]); overlayC = (I830OverlayRegPtr)(pPriv->regmap[1]); if (pPriv->is_mfld) { driver_data->ble_black_mode.value = 1; driver_data->ble_white_mode.value = 3; driver_data->blueStretch_gain.value = 200; driver_data->skinColorCorrection_gain.value = 100; driver_data->hue.value = (5.25f * (1 << 25)); driver_data->saturation.value = (1.07f * (1 << 25)); driver_data->brightness.value = (-10.1f * (1 << 10)); driver_data->contrast.value = (0.99f * (1 << 25)); } return 0; out_err_bo1: wsbmBOUnreference(&pPriv->wsbo[1]); out_err_bo0: wsbmBOUnreference(&pPriv->wsbo[0]); out_err: return -1; } int psb_coverlay_init(VADriverContextP ctx) { #ifndef BAYTRAIL INIT_DRIVER_DATA; PsbPortPrivPtr pPriv = &driver_data->coverlay_priv; struct drm_psb_register_rw_arg regs; int ret; memset(pPriv, 0, sizeof(PsbPortPrivRec)); pPriv->is_mfld = (IS_MFLD(driver_data) || IS_MRFL(driver_data)); ret = psbSetupImageVideoOverlay(ctx, pPriv); if (ret != 0) { drv_debug_msg(VIDEO_DEBUG_ERROR, "psb_coverlay_init : Create overlay cmd buffer failed.\n"); return -1; } if (pPriv->is_mfld && driver_data->is_android) { drv_debug_msg(VIDEO_DEBUG_GENERAL, "Android ExtVideo: set PIPEB(HDMI)display plane on the bottom.\n"); memset(®s, 0, sizeof(regs)); regs.display_read_mask = REGRWBITS_DSPBCNTR; drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, ®s, sizeof(regs)); regs.display.dspcntr_b |= DISPPLANE_BOTTOM; regs.display_write_mask = REGRWBITS_DSPBCNTR; drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, ®s, sizeof(regs)); } I830ResetVideo(ctx, pPriv); I830UpdateGamma(ctx, pPriv); #endif return 0; } int psb_coverlay_stop(VADriverContextP ctx) { I830StopVideo(ctx); return 0; } int psb_coverlay_deinit(VADriverContextP ctx) { #ifndef BAYTRAIL INIT_DRIVER_DATA; PsbPortPrivPtr pPriv = &driver_data->coverlay_priv; struct drm_psb_register_rw_arg regs; if (pPriv->is_mfld && driver_data->is_android) { drv_debug_msg(VIDEO_DEBUG_GENERAL, "Android ExtVideo: set PIPEB(HDMI)display plane normal.\n"); memset(®s, 0, sizeof(regs)); regs.display_read_mask = REGRWBITS_DSPBCNTR; drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, ®s, sizeof(regs)); regs.display.dspcntr_b &= ~DISPPLANE_BOTTOM; regs.display_write_mask = REGRWBITS_DSPBCNTR; drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, ®s, sizeof(regs)); } psbPortPrivDestroy(ctx, pPriv); #endif return 0; } VAStatus psb_putsurface_overlay( VADriverContextP ctx, VASurfaceID surface, short srcx, short srcy, unsigned short srcw, unsigned short srch, short destx, short desty, unsigned short destw, unsigned short desth, unsigned int flags, /* de-interlacing flags */ int overlayId, int pipeId ) { INIT_DRIVER_DATA; object_surface_p obj_surface = SURFACE(surface); PsbPortPrivPtr pPriv = (PsbPortPrivPtr)(&driver_data->coverlay_priv); #if 0 if ((overlayId == OVERLAY_A) && (pPriv->overlayA_pipeId != pipeId)) { pPriv->overlayA_pipeId = pipeId; I830SwitchPipe(ctx, OVERLAY_A, pipeId); drv_debug_msg(VIDEO_DEBUG_GENERAL, "OverlayA switch pipe to %d, stop overlayA first.\n", pipeId); } else if ((overlayId == OVERLAY_C) && (pPriv->overlayC_pipeId != pipeId)) { pPriv->overlayC_pipeId = pipeId; I830SwitchPipe(ctx, OVERLAY_C, pipeId); drv_debug_msg(VIDEO_DEBUG_GENERAL, "OverlayC switch pipe to %d, stop overlayC first.\n", pipeId); } #endif I830PutImage(ctx, surface, srcx, srcy, srcw, srch, destx, desty, destw, desth, VA_FOURCC_NV12, flags, overlayId, pipeId); /* current surface is being displayed */ if (driver_data->cur_displaying_surface != VA_INVALID_SURFACE) driver_data->last_displaying_surface = driver_data->cur_displaying_surface; if (obj_surface == NULL) { drv_debug_msg(VIDEO_DEBUG_ERROR, "Invalid surface ID: 0x%08x\n", surface); return VA_STATUS_ERROR_INVALID_SURFACE; } obj_surface->display_timestamp = GetTickCount(); driver_data->cur_displaying_surface = surface; return VA_STATUS_SUCCESS; }