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