| /* |
| * 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; |
| } |