|
|
/* |
|
|
// Copyright (c) 2014 Intel Corporation |
|
|
// |
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
// you may not use this file except in compliance with the License. |
|
|
// You may obtain a copy of the License at |
|
|
// |
|
|
// http://www.apache.org/licenses/LICENSE-2.0 |
|
|
// |
|
|
// Unless required by applicable law or agreed to in writing, software |
|
|
// distributed under the License is distributed on an "AS IS" BASIS, |
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
|
// See the License for the specific language governing permissions and |
|
|
// limitations under the License. |
|
|
*/ |
|
|
|
|
|
#include <math.h> |
|
|
#include <HwcTrace.h> |
|
|
#include <Drm.h> |
|
|
#include <Hwcomposer.h> |
|
|
#include <anniedale/AnnOverlayPlane.h> |
|
|
#include <tangier/TngGrallocBuffer.h> |
|
|
|
|
|
// FIXME: remove it |
|
|
#include <OMX_IVCommon.h> |
|
|
#include <OMX_IntelVideoExt.h> |
|
|
|
|
|
namespace android { |
|
|
namespace intel { |
|
|
|
|
|
AnnOverlayPlane::AnnOverlayPlane(int index, int disp) |
|
|
: OverlayPlaneBase(index, disp), |
|
|
mRotationBufProvider(NULL), |
|
|
mRotationConfig(0), |
|
|
mZOrderConfig(0), |
|
|
mUseOverlayRotation(true) |
|
|
{ |
|
|
CTRACE(); |
|
|
|
|
|
memset(&mContext, 0, sizeof(mContext)); |
|
|
} |
|
|
|
|
|
AnnOverlayPlane::~AnnOverlayPlane() |
|
|
{ |
|
|
CTRACE(); |
|
|
} |
|
|
|
|
|
void AnnOverlayPlane::setZOrderConfig(ZOrderConfig& zorderConfig, |
|
|
void *nativeConfig) |
|
|
{ |
|
|
long slot = (long)nativeConfig; |
|
|
|
|
|
CTRACE(); |
|
|
|
|
|
switch (slot) { |
|
|
case 0: |
|
|
mZOrderConfig = 0; |
|
|
break; |
|
|
case 1: |
|
|
mZOrderConfig = (1 << 8); |
|
|
break; |
|
|
case 2: |
|
|
mZOrderConfig = (2 << 8); |
|
|
break; |
|
|
case 3: |
|
|
mZOrderConfig = (3 << 8); |
|
|
break; |
|
|
default: |
|
|
ETRACE("Invalid overlay plane zorder %ld", slot); |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
bool AnnOverlayPlane::reset() |
|
|
{ |
|
|
OverlayPlaneBase::reset(); |
|
|
if (mRotationBufProvider) { |
|
|
mRotationBufProvider->reset(); |
|
|
} |
|
|
return true; |
|
|
} |
|
|
|
|
|
bool AnnOverlayPlane::enable() |
|
|
{ |
|
|
RETURN_FALSE_IF_NOT_INIT(); |
|
|
|
|
|
// by default always use overlay rotation |
|
|
mUseOverlayRotation = true; |
|
|
|
|
|
if (mContext.ctx.ov_ctx.ovadd & (0x1 << 15)) |
|
|
return true; |
|
|
|
|
|
mContext.ctx.ov_ctx.ovadd |= (0x1 << 15); |
|
|
|
|
|
// flush |
|
|
flush(PLANE_ENABLE); |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
bool AnnOverlayPlane::disable() |
|
|
{ |
|
|
RETURN_FALSE_IF_NOT_INIT(); |
|
|
|
|
|
if (!(mContext.ctx.ov_ctx.ovadd & (0x1 << 15))) |
|
|
return true; |
|
|
|
|
|
mContext.ctx.ov_ctx.ovadd &= ~(0x1 << 15); |
|
|
|
|
|
mContext.ctx.ov_ctx.ovadd &= ~(0x300); |
|
|
|
|
|
mContext.ctx.ov_ctx.ovadd |= mPipeConfig; |
|
|
|
|
|
// flush |
|
|
flush(PLANE_DISABLE); |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
void AnnOverlayPlane::postFlip() |
|
|
{ |
|
|
// when using AnnOverlayPlane through AnnDisplayPlane as proxy, postFlip is never |
|
|
// called so mUpdateMasks is never reset. |
|
|
// When using AnnOverlayPlane directly, postFlip is invoked and mUpdateMasks is reset |
|
|
// post-flip. |
|
|
|
|
|
// need to check why mUpdateMasks = 0 causes video freeze. |
|
|
|
|
|
//DisplayPlane::postFlip(); |
|
|
} |
|
|
|
|
|
|
|
|
void AnnOverlayPlane::resetBackBuffer(int buf) |
|
|
{ |
|
|
CTRACE(); |
|
|
|
|
|
if (!mBackBuffer[buf] || !mBackBuffer[buf]->buf) |
|
|
return; |
|
|
|
|
|
OverlayBackBufferBlk *backBuffer = mBackBuffer[buf]->buf; |
|
|
|
|
|
memset(backBuffer, 0, sizeof(OverlayBackBufferBlk)); |
|
|
|
|
|
// reset overlay |
|
|
backBuffer->OCLRC0 = (OVERLAY_INIT_CONTRAST << 18) | |
|
|
(OVERLAY_INIT_BRIGHTNESS & 0xff); |
|
|
backBuffer->OCLRC1 = OVERLAY_INIT_SATURATION; |
|
|
backBuffer->DCLRKV = OVERLAY_INIT_COLORKEY; |
|
|
backBuffer->DCLRKM = OVERLAY_INIT_COLORKEYMASK; |
|
|
backBuffer->OCONFIG = 0; |
|
|
backBuffer->OCONFIG |= (0x1 << 27); |
|
|
// use 3 line buffers |
|
|
backBuffer->OCONFIG |= 0x1; |
|
|
backBuffer->SCHRKEN &= ~(0x7 << 24); |
|
|
backBuffer->SCHRKEN |= 0xff; |
|
|
} |
|
|
|
|
|
bool AnnOverlayPlane::bufferOffsetSetup(BufferMapper& mapper) |
|
|
{ |
|
|
CTRACE(); |
|
|
|
|
|
OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf; |
|
|
if (!backBuffer) { |
|
|
ETRACE("invalid back buffer"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
uint32_t format = mapper.getFormat(); |
|
|
uint32_t gttOffsetInBytes = (mapper.getGttOffsetInPage(0) << 12); |
|
|
uint32_t yStride = mapper.getStride().yuv.yStride; |
|
|
uint32_t uvStride = mapper.getStride().yuv.uvStride; |
|
|
uint32_t w = mapper.getWidth(); |
|
|
uint32_t h = mapper.getHeight(); |
|
|
uint32_t srcX= mapper.getCrop().x; |
|
|
uint32_t srcY= mapper.getCrop().y; |
|
|
uint32_t ySurface, uSurface, vSurface; |
|
|
uint32_t yTileOffsetX, yTileOffsetY; |
|
|
uint32_t uTileOffsetX, uTileOffsetY; |
|
|
uint32_t vTileOffsetX, vTileOffsetY; |
|
|
|
|
|
// clear original format setting |
|
|
backBuffer->OCMD &= ~(0xf << 10); |
|
|
backBuffer->OCMD &= ~OVERLAY_MEMORY_LAYOUT_TILED; |
|
|
|
|
|
backBuffer->OBUF_0Y = 0; |
|
|
backBuffer->OBUF_0V = 0; |
|
|
backBuffer->OBUF_0U = 0; |
|
|
// Y/U/V plane must be 4k bytes aligned. |
|
|
ySurface = gttOffsetInBytes; |
|
|
if (mIsProtectedBuffer) { |
|
|
// temporary workaround until vsync event logic is corrected. |
|
|
// it seems that overlay buffer update and renderring can be overlapped, |
|
|
// as such encryption bit may be cleared during HW rendering |
|
|
ySurface |= 0x01; |
|
|
} |
|
|
|
|
|
switch(format) { |
|
|
case HAL_PIXEL_FORMAT_YV12: // YV12 |
|
|
vSurface = ySurface + yStride * h; |
|
|
uSurface = vSurface + uvStride * (h / 2); |
|
|
yTileOffsetX = srcX; |
|
|
yTileOffsetY = srcY; |
|
|
uTileOffsetX = srcX / 2; |
|
|
uTileOffsetY = srcY / 2; |
|
|
vTileOffsetX = uTileOffsetX; |
|
|
vTileOffsetY = uTileOffsetY; |
|
|
backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_YUV420; |
|
|
break; |
|
|
case HAL_PIXEL_FORMAT_I420: // I420 |
|
|
uSurface = ySurface + yStride * h; |
|
|
vSurface = uSurface + uvStride * (h / 2); |
|
|
yTileOffsetX = srcX; |
|
|
yTileOffsetY = srcY; |
|
|
uTileOffsetX = srcX / 2; |
|
|
uTileOffsetY = srcY / 2; |
|
|
vTileOffsetX = uTileOffsetX; |
|
|
vTileOffsetY = uTileOffsetY; |
|
|
backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_YUV420; |
|
|
break; |
|
|
case HAL_PIXEL_FORMAT_NV12: // NV12 |
|
|
uSurface = ySurface; |
|
|
vSurface = ySurface; |
|
|
backBuffer->OBUF_0U = yStride * h; |
|
|
yTileOffsetX = srcX; |
|
|
yTileOffsetY = srcY; |
|
|
uTileOffsetX = srcX / 2; |
|
|
uTileOffsetY = srcY / 2 + h; |
|
|
vTileOffsetX = uTileOffsetX; |
|
|
vTileOffsetY = uTileOffsetY; |
|
|
backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2; |
|
|
break; |
|
|
// NOTE: this is the decoded video format, align the height to 32B |
|
|
//as it's defined by video driver |
|
|
case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar: // NV12 |
|
|
uSurface = ySurface + yStride * align_to(h, 32); |
|
|
vSurface = ySurface + yStride * align_to(h, 32); |
|
|
yTileOffsetX = srcX; |
|
|
yTileOffsetY = srcY; |
|
|
uTileOffsetX = srcX; |
|
|
uTileOffsetY = srcY / 2; |
|
|
vTileOffsetX = uTileOffsetX; |
|
|
vTileOffsetY = uTileOffsetY; |
|
|
backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2; |
|
|
break; |
|
|
case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled: //NV12_tiled |
|
|
uSurface = ySurface + yStride * align_to(h, 32); |
|
|
vSurface = ySurface + yStride * align_to(h, 32); |
|
|
yTileOffsetX = srcX; |
|
|
yTileOffsetY = srcY; |
|
|
uTileOffsetX = srcX; |
|
|
uTileOffsetY = srcY / 2; |
|
|
vTileOffsetX = uTileOffsetX; |
|
|
vTileOffsetY = uTileOffsetY; |
|
|
backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2; |
|
|
backBuffer->OCMD |= OVERLAY_MEMORY_LAYOUT_TILED; |
|
|
break; |
|
|
case HAL_PIXEL_FORMAT_YUY2: // YUY2 |
|
|
uSurface = ySurface; |
|
|
vSurface = ySurface; |
|
|
yTileOffsetX = srcX; |
|
|
yTileOffsetY = srcY; |
|
|
uTileOffsetX = yTileOffsetX; |
|
|
uTileOffsetY = yTileOffsetY; |
|
|
vTileOffsetX = yTileOffsetX; |
|
|
vTileOffsetY = yTileOffsetY; |
|
|
backBuffer->OCMD |= OVERLAY_FORMAT_PACKED_YUV422; |
|
|
backBuffer->OCMD |= OVERLAY_PACKED_ORDER_YUY2; |
|
|
break; |
|
|
case HAL_PIXEL_FORMAT_UYVY: // UYVY |
|
|
uSurface = ySurface; |
|
|
vSurface = ySurface; |
|
|
yTileOffsetX = srcX; |
|
|
yTileOffsetY = srcY; |
|
|
uTileOffsetX = yTileOffsetX; |
|
|
uTileOffsetY = yTileOffsetY; |
|
|
vTileOffsetX = yTileOffsetX; |
|
|
vTileOffsetY = yTileOffsetY; |
|
|
backBuffer->OCMD |= OVERLAY_FORMAT_PACKED_YUV422; |
|
|
backBuffer->OCMD |= OVERLAY_PACKED_ORDER_UYVY; |
|
|
break; |
|
|
default: |
|
|
ETRACE("unsupported format %d", format); |
|
|
return false; |
|
|
} |
|
|
|
|
|
backBuffer->OSTART_0Y = ySurface; |
|
|
backBuffer->OSTART_0U = uSurface; |
|
|
backBuffer->OSTART_0V = vSurface; |
|
|
backBuffer->OBUF_0Y += srcY * yStride + srcX; |
|
|
backBuffer->OBUF_0V += (srcY / 2) * uvStride + srcX; |
|
|
backBuffer->OBUF_0U += (srcY / 2) * uvStride + srcX; |
|
|
backBuffer->OTILEOFF_0Y = yTileOffsetY << 16 | yTileOffsetX; |
|
|
backBuffer->OTILEOFF_0U = uTileOffsetY << 16 | uTileOffsetX; |
|
|
backBuffer->OTILEOFF_0V = vTileOffsetY << 16 | vTileOffsetX; |
|
|
|
|
|
VTRACE("done. offset (%d, %d, %d)", |
|
|
backBuffer->OBUF_0Y, |
|
|
backBuffer->OBUF_0U, |
|
|
backBuffer->OBUF_0V); |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
bool AnnOverlayPlane::scalingSetup(BufferMapper& mapper) |
|
|
{ |
|
|
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]; |
|
|
coeffRec ycoeffY[N_VERT_Y_TAPS * N_PHASES]; |
|
|
coeffRec ycoeffUV[N_VERT_UV_TAPS * N_PHASES]; |
|
|
int i, j, pos; |
|
|
bool scaleChanged = false; |
|
|
int x, y, w, h; |
|
|
int deinterlace_factor = 1; |
|
|
drmModeModeInfoPtr mode = &mModeInfo; |
|
|
|
|
|
OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf; |
|
|
if (!backBuffer) { |
|
|
ETRACE("invalid back buffer"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
if (mPanelOrientation == PANEL_ORIENTATION_180) { |
|
|
if (mode->hdisplay) |
|
|
x = mode->hdisplay - mPosition.x - mPosition.w; |
|
|
else |
|
|
x = mPosition.x; |
|
|
if (mode->vdisplay) |
|
|
y = mode->vdisplay - mPosition.y - mPosition.h; |
|
|
else |
|
|
y = mPosition.y; |
|
|
} else { |
|
|
x = mPosition.x; |
|
|
y = mPosition.y; |
|
|
} |
|
|
|
|
|
w = mPosition.w; |
|
|
h = mPosition.h; |
|
|
|
|
|
// check position |
|
|
checkPosition(x, y, w, h); |
|
|
VTRACE("final position (%d, %d, %d, %d)", x, y, w, h); |
|
|
|
|
|
if ((w <= 0) || (h <= 0)) { |
|
|
ETRACE("invalid dst width/height"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
// setup dst position |
|
|
backBuffer->DWINPOS = (y << 16) | x; |
|
|
backBuffer->DWINSZ = (h << 16) | w; |
|
|
|
|
|
uint32_t srcWidth = mapper.getCrop().w; |
|
|
uint32_t srcHeight = mapper.getCrop().h; |
|
|
uint32_t dstWidth = w; |
|
|
uint32_t dstHeight = h; |
|
|
|
|
|
if (mBobDeinterlace && !mTransform) |
|
|
deinterlace_factor = 2; |
|
|
|
|
|
VTRACE("src (%dx%d), dst (%dx%d), transform %d", |
|
|
srcWidth, srcHeight, |
|
|
dstWidth, dstHeight, |
|
|
mTransform); |
|
|
|
|
|
// switch destination width/height for scale factor calculation |
|
|
// for 90/270 transformation |
|
|
if (mUseOverlayRotation && ((mTransform == HWC_TRANSFORM_ROT_90) || |
|
|
(mTransform == HWC_TRANSFORM_ROT_270))) { |
|
|
uint32_t tmp = srcHeight; |
|
|
srcHeight = srcWidth; |
|
|
srcWidth = tmp; |
|
|
} |
|
|
|
|
|
// Y down-scale factor as a multiple of 4096 |
|
|
if (srcWidth == dstWidth && srcHeight == dstHeight) { |
|
|
xscaleFract = (1 << 12); |
|
|
yscaleFract = (1 << 12) / deinterlace_factor; |
|
|
} else { |
|
|
xscaleFract = ((srcWidth - 1) << 12) / dstWidth; |
|
|
yscaleFract = ((srcHeight - 1) << 12) / (dstHeight * deinterlace_factor); |
|
|
} |
|
|
|
|
|
// 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; |
|
|
|
|
|
// Check scaling ratio |
|
|
if (xscaleInt > INTEL_OVERLAY_MAX_SCALING_RATIO) { |
|
|
ETRACE("xscaleInt > %d", INTEL_OVERLAY_MAX_SCALING_RATIO); |
|
|
return false; |
|
|
} |
|
|
|
|
|
// shouldn't get here |
|
|
if (xscaleIntUV > INTEL_OVERLAY_MAX_SCALING_RATIO) { |
|
|
ETRACE("xscaleIntUV > %d", INTEL_OVERLAY_MAX_SCALING_RATIO); |
|
|
return false; |
|
|
} |
|
|
|
|
|
newval = (xscaleInt << 15) | |
|
|
((xscaleFract & 0xFFF) << 3) | ((yscaleFract & 0xFFF) << 20); |
|
|
if (newval != backBuffer->YRGBSCALE) { |
|
|
scaleChanged = true; |
|
|
backBuffer->YRGBSCALE = newval; |
|
|
} |
|
|
|
|
|
newval = (xscaleIntUV << 15) | ((xscaleFractUV & 0xFFF) << 3) | |
|
|
((yscaleFractUV & 0xFFF) << 20); |
|
|
if (newval != backBuffer->UVSCALE) { |
|
|
scaleChanged = true; |
|
|
backBuffer->UVSCALE = newval; |
|
|
} |
|
|
|
|
|
newval = yscaleInt << 16 | yscaleIntUV; |
|
|
if (newval != backBuffer->UVSCALEV) { |
|
|
scaleChanged = true; |
|
|
backBuffer->UVSCALEV = newval; |
|
|
} |
|
|
|
|
|
// Recalculate coefficients if the scaling changed |
|
|
// Only Horizontal coefficients so far. |
|
|
if (scaleChanged) { |
|
|
double fHCutoffY; |
|
|
double fHCutoffUV; |
|
|
double fVCutoffY; |
|
|
double fVCutoffUV; |
|
|
|
|
|
fHCutoffY = xscaleFract / 4096.0; |
|
|
fHCutoffUV = xscaleFractUV / 4096.0; |
|
|
fVCutoffY = yscaleFract / 4096.0; |
|
|
fVCutoffUV = yscaleFractUV / 4096.0; |
|
|
|
|
|
// Limit to between 1.0 and 3.0 |
|
|
if (fHCutoffY < MIN_CUTOFF_FREQ) |
|
|
fHCutoffY = MIN_CUTOFF_FREQ; |
|
|
if (fHCutoffY > MAX_CUTOFF_FREQ) |
|
|
fHCutoffY = MAX_CUTOFF_FREQ; |
|
|
if (fHCutoffUV < MIN_CUTOFF_FREQ) |
|
|
fHCutoffUV = MIN_CUTOFF_FREQ; |
|
|
if (fHCutoffUV > MAX_CUTOFF_FREQ) |
|
|
fHCutoffUV = MAX_CUTOFF_FREQ; |
|
|
|
|
|
if (fVCutoffY < MIN_CUTOFF_FREQ) |
|
|
fVCutoffY = MIN_CUTOFF_FREQ; |
|
|
if (fVCutoffY > MAX_CUTOFF_FREQ) |
|
|
fVCutoffY = MAX_CUTOFF_FREQ; |
|
|
if (fVCutoffUV < MIN_CUTOFF_FREQ) |
|
|
fVCutoffUV = MIN_CUTOFF_FREQ; |
|
|
if (fVCutoffUV > MAX_CUTOFF_FREQ) |
|
|
fVCutoffUV = MAX_CUTOFF_FREQ; |
|
|
|
|
|
updateCoeff(N_HORIZ_Y_TAPS, fHCutoffY, true, true, xcoeffY); |
|
|
updateCoeff(N_HORIZ_UV_TAPS, fHCutoffUV, true, false, xcoeffUV); |
|
|
updateCoeff(N_VERT_Y_TAPS, fVCutoffY, false, true, ycoeffY); |
|
|
updateCoeff(N_VERT_UV_TAPS, fVCutoffUV, false, false, ycoeffUV); |
|
|
|
|
|
for (i = 0; i < N_PHASES; i++) { |
|
|
for (j = 0; j < N_HORIZ_Y_TAPS; j++) { |
|
|
pos = i * N_HORIZ_Y_TAPS + j; |
|
|
backBuffer->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; |
|
|
backBuffer->UV_HCOEFS[pos] = |
|
|
(xcoeffUV[pos].sign << 15 | |
|
|
xcoeffUV[pos].exponent << 12 | |
|
|
xcoeffUV[pos].mantissa); |
|
|
} |
|
|
} |
|
|
|
|
|
for (i = 0; i < N_PHASES; i++) { |
|
|
for (j = 0; j < N_VERT_Y_TAPS; j++) { |
|
|
pos = i * N_VERT_Y_TAPS + j; |
|
|
backBuffer->Y_VCOEFS[pos] = |
|
|
(ycoeffY[pos].sign << 15 | |
|
|
ycoeffY[pos].exponent << 12 | |
|
|
ycoeffY[pos].mantissa); |
|
|
} |
|
|
} |
|
|
for (i = 0; i < N_PHASES; i++) { |
|
|
for (j = 0; j < N_VERT_UV_TAPS; j++) { |
|
|
pos = i * N_VERT_UV_TAPS + j; |
|
|
backBuffer->UV_VCOEFS[pos] = |
|
|
(ycoeffUV[pos].sign << 15 | |
|
|
ycoeffUV[pos].exponent << 12 | |
|
|
ycoeffUV[pos].mantissa); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
XTRACE(); |
|
|
return true; |
|
|
} |
|
|
|
|
|
void AnnOverlayPlane::setTransform(int transform) |
|
|
{ |
|
|
RETURN_VOID_IF_NOT_INIT(); |
|
|
|
|
|
if (mPanelOrientation == PANEL_ORIENTATION_180) |
|
|
transform ^= HWC_TRANSFORM_ROT_180; |
|
|
|
|
|
DisplayPlane::setTransform(transform); |
|
|
|
|
|
// setup transform config |
|
|
switch (mTransform) { |
|
|
case HWC_TRANSFORM_ROT_90: |
|
|
mRotationConfig = (0x1 << 10); |
|
|
break; |
|
|
case HWC_TRANSFORM_ROT_180: |
|
|
mRotationConfig = (0x2 << 10); |
|
|
break; |
|
|
case HWC_TRANSFORM_ROT_270: |
|
|
mRotationConfig = (0x3 << 10); |
|
|
break; |
|
|
case 0: |
|
|
mRotationConfig = 0; |
|
|
break; |
|
|
default: |
|
|
ETRACE("Invalid transform %d", mTransform); |
|
|
mRotationConfig = 0; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
// HSD 4645510: |
|
|
// This is a SOC limition, that when source buffer width range is |
|
|
// in (960, 1024] - one cache line length, and rotation bit is set |
|
|
// in portrait mode, video will show distortion. |
|
|
bool AnnOverlayPlane::isSettingRotBitAllowed() |
|
|
{ |
|
|
uint32_t width = mSrcCrop.w; |
|
|
|
|
|
if ((width > 960 && width <= 1024) && |
|
|
(mTransform == 0 || mTransform == HAL_TRANSFORM_ROT_180)) |
|
|
return false; |
|
|
return true; |
|
|
} |
|
|
|
|
|
bool AnnOverlayPlane::flip(void *ctx) |
|
|
{ |
|
|
uint32_t ovadd = 0; |
|
|
|
|
|
RETURN_FALSE_IF_NOT_INIT(); |
|
|
|
|
|
if (!DisplayPlane::flip(ctx)) { |
|
|
ETRACE("failed to flip display plane."); |
|
|
return false; |
|
|
} |
|
|
|
|
|
// update back buffer address |
|
|
ovadd = (mBackBuffer[mCurrent]->gttOffsetInPage << 12); |
|
|
|
|
|
// enable rotation mode and setup rotation config |
|
|
// if video is interlaced, cannot use overlay rotation |
|
|
if (mIndex == 0 && !mBobDeinterlace) { |
|
|
if (isSettingRotBitAllowed()) |
|
|
ovadd |= (1 << 12); |
|
|
ovadd |= mRotationConfig; |
|
|
} |
|
|
|
|
|
// setup z-order config |
|
|
ovadd |= mZOrderConfig; |
|
|
|
|
|
// load coefficients |
|
|
ovadd |= 0x1; |
|
|
|
|
|
// enable overlay |
|
|
ovadd |= (1 << 15); |
|
|
|
|
|
mContext.type = DC_OVERLAY_PLANE; |
|
|
mContext.ctx.ov_ctx.ovadd = ovadd; |
|
|
mContext.ctx.ov_ctx.index = mIndex; |
|
|
mContext.ctx.ov_ctx.pipe = mDevice; |
|
|
mContext.ctx.ov_ctx.ovadd |= mPipeConfig; |
|
|
|
|
|
// move to next back buffer |
|
|
mCurrent = (mCurrent + 1) % OVERLAY_BACK_BUFFER_COUNT; |
|
|
|
|
|
VTRACE("ovadd = %#x, index = %d, device = %d", |
|
|
mContext.ctx.ov_ctx.ovadd, |
|
|
mIndex, |
|
|
mDevice); |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
void* AnnOverlayPlane::getContext() const |
|
|
{ |
|
|
CTRACE(); |
|
|
return (void *)&mContext; |
|
|
} |
|
|
|
|
|
bool AnnOverlayPlane::setDataBuffer(BufferMapper& mapper) |
|
|
{ |
|
|
if (OverlayPlaneBase::setDataBuffer(mapper) == false) { |
|
|
return false; |
|
|
} |
|
|
|
|
|
signalVideoRotation(mapper); |
|
|
|
|
|
if (mIsProtectedBuffer) { |
|
|
// Bit 0: Decryption request, only allowed to change on a synchronous flip |
|
|
// This request will be qualified with the separate decryption enable bit for OV |
|
|
mBackBuffer[mCurrent]->buf->OSTART_0Y |= 0x1; |
|
|
mBackBuffer[mCurrent]->buf->OSTART_1Y |= 0x1; |
|
|
} |
|
|
|
|
|
mContext.gtt_key = (unsigned long)mapper.getCpuAddress(0); |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
bool AnnOverlayPlane::initialize(uint32_t bufferCount) |
|
|
{ |
|
|
if (!OverlayPlaneBase::initialize(bufferCount)) { |
|
|
ETRACE("failed to initialize OverlayPlaneBase"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
// setup rotation buffer |
|
|
mRotationBufProvider = new RotationBufferProvider(mWsbm); |
|
|
if (!mRotationBufProvider || !mRotationBufProvider->initialize()) { |
|
|
DEINIT_AND_RETURN_FALSE("failed to initialize RotationBufferProvider"); |
|
|
} |
|
|
return true; |
|
|
} |
|
|
|
|
|
void AnnOverlayPlane::deinitialize() |
|
|
{ |
|
|
DEINIT_AND_DELETE_OBJ(mRotationBufProvider); |
|
|
OverlayPlaneBase::deinitialize(); |
|
|
} |
|
|
|
|
|
bool AnnOverlayPlane::rotatedBufferReady(BufferMapper& mapper, BufferMapper* &rotatedMapper) |
|
|
{ |
|
|
struct VideoPayloadBuffer *payload; |
|
|
uint32_t format; |
|
|
// only NV12_VED has rotated buffer |
|
|
format = mapper.getFormat(); |
|
|
if (format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar && |
|
|
format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled) { |
|
|
ETRACE("invalid video format %#x", format); |
|
|
return false; |
|
|
} |
|
|
|
|
|
payload = (struct VideoPayloadBuffer *)mapper.getCpuAddress(SUB_BUFFER1); |
|
|
// check payload |
|
|
if (!payload) { |
|
|
ETRACE("no payload found"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
if (payload->force_output_method == FORCE_OUTPUT_GPU) { |
|
|
ETRACE("Output method is not supported!"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
if (payload->client_transform != mTransform || |
|
|
mBobDeinterlace) { |
|
|
if (!mRotationBufProvider->setupRotationBuffer(payload, mTransform)) { |
|
|
DTRACE("failed to setup rotation buffer"); |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
rotatedMapper = getTTMMapper(mapper, payload); |
|
|
return true; |
|
|
} |
|
|
|
|
|
void AnnOverlayPlane::signalVideoRotation(BufferMapper& mapper) |
|
|
{ |
|
|
struct VideoPayloadBuffer *payload; |
|
|
uint32_t format; |
|
|
|
|
|
// check if it's video layer |
|
|
format = mapper.getFormat(); |
|
|
if (format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar && |
|
|
format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled) { |
|
|
return; |
|
|
} |
|
|
|
|
|
payload = (struct VideoPayloadBuffer *)mapper.getCpuAddress(SUB_BUFFER1); |
|
|
if (!payload) { |
|
|
ETRACE("no payload found"); |
|
|
return; |
|
|
} |
|
|
|
|
|
/* if use overlay rotation, signal decoder to stop rotation */ |
|
|
if (mUseOverlayRotation) { |
|
|
if (payload->client_transform) { |
|
|
WTRACE("signal decoder to stop generate rotation buffer"); |
|
|
payload->hwc_timestamp = systemTime(); |
|
|
payload->layer_transform = 0; |
|
|
} |
|
|
} else { |
|
|
/* if overlay rotation cannot be used, signal decoder to start rotation */ |
|
|
if (payload->client_transform != mTransform) { |
|
|
WTRACE("signal decoder to generate rotation buffer with transform %d", mTransform); |
|
|
payload->hwc_timestamp = systemTime(); |
|
|
payload->layer_transform = mTransform; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
bool AnnOverlayPlane::useOverlayRotation(BufferMapper& mapper) |
|
|
{ |
|
|
if (mTransform == 0) |
|
|
return true; |
|
|
|
|
|
if (!isSettingRotBitAllowed()) { |
|
|
mUseOverlayRotation = false; |
|
|
mRotationConfig = 0; |
|
|
return false; |
|
|
} |
|
|
|
|
|
// workaround limitation of overlay rotation by falling back to use VA rotated buffer |
|
|
bool fallback = false; |
|
|
float scaleX = (float)mSrcCrop.w / mPosition.w; |
|
|
float scaleY = (float)mSrcCrop.h / mPosition.h; |
|
|
if (mTransform == HAL_TRANSFORM_ROT_270 || mTransform == HAL_TRANSFORM_ROT_90) { |
|
|
scaleX = (float)mSrcCrop.w / mPosition.h; |
|
|
scaleY = (float)mSrcCrop.h / mPosition.w; |
|
|
} |
|
|
if (scaleX >= 3 || scaleY >= 3) { |
|
|
if (mUseOverlayRotation) { |
|
|
DTRACE("overlay rotation with scaling >= 3, use VA rotated buffer"); |
|
|
} |
|
|
fallback = true; |
|
|
} else if ((int)mSrcCrop.x & 63) { |
|
|
if (mUseOverlayRotation) { |
|
|
DTRACE("offset is not 64 bytes aligned, use VA rotated buffer"); |
|
|
} |
|
|
fallback = true; |
|
|
} |
|
|
#if 0 |
|
|
else if (mTransform != HAL_TRANSFORM_ROT_180 && scaleX != scaleY) { |
|
|
if (mUseOverlayRotation) { |
|
|
DTRACE("overlay rotation with uneven scaling, use VA rotated buffer"); |
|
|
} |
|
|
fallback = true; |
|
|
} |
|
|
#endif |
|
|
|
|
|
// per DC spec, if video is 1080(H)x1920(V), the buffer |
|
|
// need 1920 of 64-pixel strip if using hw rotation. |
|
|
// fallback to video ration buffer in such case. |
|
|
if (mSrcCrop.w == 1080 && mSrcCrop.h == 1920 && mTransform != 0) { |
|
|
DTRACE("1080(H)x1920(V) cannot use hw rotation, use VA rotated buffer"); |
|
|
fallback = true; |
|
|
} |
|
|
|
|
|
if (fallback || mBobDeinterlace) { |
|
|
mUseOverlayRotation = false; |
|
|
mRotationConfig = 0; |
|
|
} else { |
|
|
mUseOverlayRotation = true; |
|
|
} |
|
|
return mUseOverlayRotation; |
|
|
} |
|
|
|
|
|
bool AnnOverlayPlane::scaledBufferReady(BufferMapper& mapper, BufferMapper* &scaledMapper, VideoPayloadBuffer *payload) |
|
|
{ |
|
|
mUseScaledBuffer = (payload->scaling_khandle != 0); |
|
|
|
|
|
if (mUseScaledBuffer) { |
|
|
mapper.setCrop(mapper.getCrop().x, mapper.getCrop().y, payload->scaling_width, payload->scaling_height); |
|
|
scaledMapper = getTTMMapper(mapper, payload); |
|
|
return (scaledMapper != 0); |
|
|
} |
|
|
|
|
|
return mUseScaledBuffer; |
|
|
} |
|
|
|
|
|
bool AnnOverlayPlane::flush(uint32_t flags) |
|
|
{ |
|
|
RETURN_FALSE_IF_NOT_INIT(); |
|
|
ATRACE("flags = %#x, type = %d, index = %d", flags, mType, mIndex); |
|
|
|
|
|
if (!(flags & PLANE_ENABLE) && !(flags & PLANE_DISABLE)) { |
|
|
ETRACE("invalid flush flags."); |
|
|
return false; |
|
|
} |
|
|
|
|
|
struct drm_psb_register_rw_arg arg; |
|
|
memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg)); |
|
|
|
|
|
if (flags & PLANE_DISABLE) |
|
|
arg.plane_disable_mask = 1; |
|
|
else if (flags & PLANE_ENABLE) |
|
|
arg.plane_enable_mask = 1; |
|
|
|
|
|
arg.plane.type = DC_OVERLAY_PLANE; |
|
|
arg.plane.index = mIndex; |
|
|
arg.plane.ctx = mContext.ctx.ov_ctx.ovadd; |
|
|
if (flags & PLANE_DISABLE) { |
|
|
DTRACE("disabling overlay %d on device %d", mIndex, mDevice); |
|
|
} |
|
|
|
|
|
// issue ioctl |
|
|
Drm *drm = Hwcomposer::getInstance().getDrm(); |
|
|
bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg)); |
|
|
if (ret == false) { |
|
|
WTRACE("overlay update failed with error code %d", ret); |
|
|
return false; |
|
|
} |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
} // namespace intel |
|
|
} // namespace android
|
|
|
|