|
|
/* |
|
|
// 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 <PhysicalDevice.h> |
|
|
#include <common/OverlayPlaneBase.h> |
|
|
#include <common/TTMBufferMapper.h> |
|
|
#include <common/GrallocSubBuffer.h> |
|
|
#include <DisplayQuery.h> |
|
|
|
|
|
|
|
|
// FIXME: remove it |
|
|
#include <OMX_IVCommon.h> |
|
|
#include <OMX_IntelVideoExt.h> |
|
|
|
|
|
namespace android { |
|
|
namespace intel { |
|
|
|
|
|
OverlayPlaneBase::OverlayPlaneBase(int index, int disp) |
|
|
: DisplayPlane(index, PLANE_OVERLAY, disp), |
|
|
mTTMBuffers(), |
|
|
mActiveTTMBuffers(), |
|
|
mCurrent(0), |
|
|
mWsbm(0), |
|
|
mPipeConfig(0), |
|
|
mBobDeinterlace(0), |
|
|
mUseScaledBuffer(0) |
|
|
{ |
|
|
CTRACE(); |
|
|
for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { |
|
|
mBackBuffer[i] = 0; |
|
|
} |
|
|
} |
|
|
|
|
|
OverlayPlaneBase::~OverlayPlaneBase() |
|
|
{ |
|
|
CTRACE(); |
|
|
} |
|
|
|
|
|
bool OverlayPlaneBase::initialize(uint32_t bufferCount) |
|
|
{ |
|
|
Drm *drm = Hwcomposer::getInstance().getDrm(); |
|
|
CTRACE(); |
|
|
|
|
|
// NOTE: use overlay's data buffer count for the overlay plane |
|
|
if (bufferCount < OVERLAY_DATA_BUFFER_COUNT) { |
|
|
ITRACE("override overlay buffer count from %d to %d", |
|
|
bufferCount, OVERLAY_DATA_BUFFER_COUNT); |
|
|
bufferCount = OVERLAY_DATA_BUFFER_COUNT; |
|
|
} |
|
|
if (!DisplayPlane::initialize(bufferCount)) { |
|
|
DEINIT_AND_RETURN_FALSE("failed to initialize display plane"); |
|
|
} |
|
|
|
|
|
mTTMBuffers.setCapacity(bufferCount); |
|
|
mActiveTTMBuffers.setCapacity(MIN_DATA_BUFFER_COUNT); |
|
|
|
|
|
// init wsbm |
|
|
mWsbm = new Wsbm(drm->getDrmFd()); |
|
|
if (!mWsbm || !mWsbm->initialize()) { |
|
|
DEINIT_AND_RETURN_FALSE("failed to create wsbm"); |
|
|
} |
|
|
|
|
|
// create overlay back buffer |
|
|
for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { |
|
|
mBackBuffer[i] = createBackBuffer(); |
|
|
if (!mBackBuffer[i]) { |
|
|
DEINIT_AND_RETURN_FALSE("failed to create overlay back buffer"); |
|
|
} |
|
|
// reset back buffer |
|
|
resetBackBuffer(i); |
|
|
} |
|
|
|
|
|
// disable overlay when created |
|
|
flush(PLANE_DISABLE); |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
bool OverlayPlaneBase::isDisabled() |
|
|
{ |
|
|
RETURN_FALSE_IF_NOT_INIT(); |
|
|
|
|
|
struct drm_psb_register_rw_arg arg; |
|
|
memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg)); |
|
|
|
|
|
arg.get_plane_state_mask = 1; |
|
|
arg.plane.type = DC_OVERLAY_PLANE; |
|
|
arg.plane.index = mIndex; |
|
|
// pass the pipe index to check its enabled status |
|
|
// now we can pass the device id directly since |
|
|
// their values are just equal |
|
|
arg.plane.ctx = mDevice; // not used in kernel |
|
|
|
|
|
Drm *drm = Hwcomposer::getInstance().getDrm(); |
|
|
bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg)); |
|
|
if (ret == false) { |
|
|
WTRACE("overlay plane query failed with error code %d", ret); |
|
|
return false; |
|
|
} |
|
|
|
|
|
DTRACE("overlay %d status %s on device %d, current device %d", |
|
|
mIndex, arg.plane.ctx ? "DISABLED" : "ENABLED", mDevice, mDevice); |
|
|
|
|
|
return arg.plane.ctx == PSB_DC_PLANE_DISABLED; |
|
|
} |
|
|
|
|
|
void OverlayPlaneBase::deinitialize() |
|
|
{ |
|
|
if (mTTMBuffers.size()) { |
|
|
invalidateBufferCache(); |
|
|
} |
|
|
|
|
|
if (mActiveTTMBuffers.size() > 0) { |
|
|
invalidateActiveTTMBuffers(); |
|
|
} |
|
|
|
|
|
// delete back buffer |
|
|
for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { |
|
|
if (mBackBuffer[i]) { |
|
|
deleteBackBuffer(i); |
|
|
mBackBuffer[i] = NULL; |
|
|
} |
|
|
} |
|
|
DEINIT_AND_DELETE_OBJ(mWsbm); |
|
|
|
|
|
DisplayPlane::deinitialize(); |
|
|
} |
|
|
|
|
|
void OverlayPlaneBase::invalidateBufferCache() |
|
|
{ |
|
|
// clear plane buffer cache |
|
|
DisplayPlane::invalidateBufferCache(); |
|
|
invalidateTTMBuffers(); |
|
|
} |
|
|
|
|
|
bool OverlayPlaneBase::assignToDevice(int disp) |
|
|
{ |
|
|
uint32_t pipeConfig = 0; |
|
|
|
|
|
RETURN_FALSE_IF_NOT_INIT(); |
|
|
VTRACE("overlay %d assigned to disp %d", mIndex, disp); |
|
|
|
|
|
switch (disp) { |
|
|
case IDisplayDevice::DEVICE_EXTERNAL: |
|
|
pipeConfig = (0x2 << 6); |
|
|
break; |
|
|
case IDisplayDevice::DEVICE_PRIMARY: |
|
|
default: |
|
|
pipeConfig = 0; |
|
|
break; |
|
|
} |
|
|
|
|
|
// if pipe switching happened, then disable overlay first |
|
|
if (mPipeConfig != pipeConfig) { |
|
|
DTRACE("overlay %d switched from %d to %d", mIndex, mDevice, disp); |
|
|
disable(); |
|
|
} |
|
|
|
|
|
mPipeConfig = pipeConfig; |
|
|
DisplayPlane::assignToDevice(disp); |
|
|
|
|
|
enable(); |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
void OverlayPlaneBase::setZOrderConfig(ZOrderConfig& zorderConfig, |
|
|
void *nativeConfig) |
|
|
{ |
|
|
CTRACE(); |
|
|
|
|
|
// setup overlay z order |
|
|
int ovaZOrder = -1; |
|
|
int ovcZOrder = -1; |
|
|
for (size_t i = 0; i < zorderConfig.size(); i++) { |
|
|
DisplayPlane *plane = zorderConfig[i]->plane; |
|
|
if (plane->getType() == DisplayPlane::PLANE_OVERLAY) { |
|
|
if (plane->getIndex() == 0) { |
|
|
ovaZOrder = i; |
|
|
} else if (plane->getIndex() == 1) { |
|
|
ovcZOrder = i; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { |
|
|
OverlayBackBufferBlk *backBuffer = mBackBuffer[i]->buf; |
|
|
if (!backBuffer) |
|
|
return; |
|
|
|
|
|
// force overlay c above overlay a |
|
|
if ((ovaZOrder >= 0) && (ovaZOrder < ovcZOrder)) { |
|
|
backBuffer->OCONFIG |= (1 << 15); |
|
|
} else { |
|
|
backBuffer->OCONFIG &= ~(1 << 15); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
bool OverlayPlaneBase::reset() |
|
|
{ |
|
|
RETURN_FALSE_IF_NOT_INIT(); |
|
|
|
|
|
DisplayPlane::reset(); |
|
|
|
|
|
// invalidate active TTM buffers |
|
|
if (mActiveTTMBuffers.size() > 0) { |
|
|
invalidateActiveTTMBuffers(); |
|
|
} |
|
|
|
|
|
// reset back buffers |
|
|
for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { |
|
|
resetBackBuffer(i); |
|
|
} |
|
|
return true; |
|
|
} |
|
|
|
|
|
bool OverlayPlaneBase::enable() |
|
|
{ |
|
|
RETURN_FALSE_IF_NOT_INIT(); |
|
|
for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { |
|
|
OverlayBackBufferBlk *backBuffer = mBackBuffer[i]->buf; |
|
|
if (!backBuffer) |
|
|
return false; |
|
|
|
|
|
if (backBuffer->OCMD & 0x1) |
|
|
return true; |
|
|
|
|
|
backBuffer->OCMD |= 0x1; |
|
|
} |
|
|
|
|
|
// flush |
|
|
flush(PLANE_ENABLE); |
|
|
return true; |
|
|
} |
|
|
|
|
|
bool OverlayPlaneBase::disable() |
|
|
{ |
|
|
RETURN_FALSE_IF_NOT_INIT(); |
|
|
for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { |
|
|
OverlayBackBufferBlk *backBuffer = mBackBuffer[i]->buf; |
|
|
if (!backBuffer) |
|
|
return false; |
|
|
|
|
|
if (!(backBuffer->OCMD & 0x1)) |
|
|
return true; |
|
|
|
|
|
backBuffer->OCMD &= ~0x1; |
|
|
} |
|
|
|
|
|
// flush |
|
|
flush(PLANE_DISABLE); |
|
|
return true; |
|
|
} |
|
|
|
|
|
OverlayBackBuffer* OverlayPlaneBase::createBackBuffer() |
|
|
{ |
|
|
CTRACE(); |
|
|
|
|
|
// create back buffer |
|
|
OverlayBackBuffer *backBuffer = (OverlayBackBuffer *)malloc(sizeof(OverlayBackBuffer)); |
|
|
if (!backBuffer) { |
|
|
ETRACE("failed to allocate back buffer"); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
|
|
|
int size = sizeof(OverlayBackBufferBlk); |
|
|
int alignment = 64 * 1024; |
|
|
void *wsbmBufferObject = 0; |
|
|
bool ret = mWsbm->allocateTTMBuffer(size, alignment, &wsbmBufferObject); |
|
|
if (ret == false) { |
|
|
ETRACE("failed to allocate TTM buffer"); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
void *virtAddr = mWsbm->getCPUAddress(wsbmBufferObject); |
|
|
uint32_t gttOffsetInPage = mWsbm->getGttOffset(wsbmBufferObject); |
|
|
|
|
|
backBuffer->buf = (OverlayBackBufferBlk *)virtAddr; |
|
|
backBuffer->gttOffsetInPage = gttOffsetInPage; |
|
|
backBuffer->bufObject = wsbmBufferObject; |
|
|
|
|
|
VTRACE("cpu %p, gtt %d", virtAddr, gttOffsetInPage); |
|
|
|
|
|
return backBuffer; |
|
|
} |
|
|
|
|
|
void OverlayPlaneBase::deleteBackBuffer(int buf) |
|
|
{ |
|
|
if (!mBackBuffer[buf]) |
|
|
return; |
|
|
|
|
|
void *wsbmBufferObject = mBackBuffer[buf]->bufObject; |
|
|
bool ret = mWsbm->destroyTTMBuffer(wsbmBufferObject); |
|
|
if (ret == false) { |
|
|
WTRACE("failed to destroy TTM buffer"); |
|
|
} |
|
|
// free back buffer |
|
|
free(mBackBuffer[buf]); |
|
|
mBackBuffer[buf] = 0; |
|
|
} |
|
|
|
|
|
void OverlayPlaneBase::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 << 3); |
|
|
backBuffer->OCONFIG |= (0x1 << 27); |
|
|
backBuffer->SCHRKEN &= ~(0x7 << 24); |
|
|
backBuffer->SCHRKEN |= 0xff; |
|
|
} |
|
|
|
|
|
BufferMapper* OverlayPlaneBase::getTTMMapper(BufferMapper& grallocMapper, struct VideoPayloadBuffer *payload) |
|
|
{ |
|
|
buffer_handle_t khandle; |
|
|
uint32_t w, h; |
|
|
uint32_t yStride, uvStride; |
|
|
stride_t stride; |
|
|
int srcX, srcY, srcW, srcH; |
|
|
int tmp; |
|
|
|
|
|
DataBuffer *buf; |
|
|
ssize_t index; |
|
|
TTMBufferMapper *mapper; |
|
|
bool ret; |
|
|
|
|
|
if (!payload) { |
|
|
ETRACE("invalid payload buffer"); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
srcX = grallocMapper.getCrop().x; |
|
|
srcY = grallocMapper.getCrop().y; |
|
|
srcW = grallocMapper.getCrop().w; |
|
|
srcH = grallocMapper.getCrop().h; |
|
|
|
|
|
// init ttm buffer |
|
|
if (mUseScaledBuffer) { |
|
|
khandle = payload->scaling_khandle; |
|
|
} else { |
|
|
khandle = payload->rotated_buffer_handle; |
|
|
} |
|
|
index = mTTMBuffers.indexOfKey(khandle); |
|
|
if (index < 0) { |
|
|
VTRACE("unmapped TTM buffer, will map it"); |
|
|
|
|
|
if (mUseScaledBuffer) { |
|
|
w = payload->scaling_width; |
|
|
h = payload->scaling_height; |
|
|
} else { |
|
|
w = payload->rotated_width; |
|
|
h = payload->rotated_height; |
|
|
|
|
|
checkCrop(srcX, srcY, srcW, srcH, payload->coded_width, payload->coded_height); |
|
|
} |
|
|
|
|
|
uint32_t format = grallocMapper.getFormat(); |
|
|
// this is for sw decode with tiled buffer in landscape mode |
|
|
if (payload->tiling) |
|
|
format = OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled; |
|
|
|
|
|
// calculate stride |
|
|
switch (format) { |
|
|
case HAL_PIXEL_FORMAT_YV12: |
|
|
case HAL_PIXEL_FORMAT_I420: |
|
|
uint32_t yStride_align; |
|
|
yStride_align = DisplayQuery::getOverlayLumaStrideAlignment(grallocMapper.getFormat()); |
|
|
if (yStride_align > 0) |
|
|
{ |
|
|
yStride = align_to(align_to(w, 32), yStride_align); |
|
|
} |
|
|
else |
|
|
{ |
|
|
yStride = align_to(align_to(w, 32), 64); |
|
|
} |
|
|
uvStride = align_to(yStride >> 1, 64); |
|
|
stride.yuv.yStride = yStride; |
|
|
stride.yuv.uvStride = uvStride; |
|
|
break; |
|
|
case HAL_PIXEL_FORMAT_NV12: |
|
|
yStride = align_to(align_to(w, 32), 64); |
|
|
uvStride = yStride; |
|
|
stride.yuv.yStride = yStride; |
|
|
stride.yuv.uvStride = uvStride; |
|
|
break; |
|
|
case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar: |
|
|
case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled: |
|
|
if (mUseScaledBuffer) { |
|
|
stride.yuv.yStride = payload->scaling_luma_stride; |
|
|
stride.yuv.uvStride = payload->scaling_chroma_u_stride; |
|
|
} else { |
|
|
yStride = align_to(align_to(w, 32), 64); |
|
|
uvStride = yStride; |
|
|
stride.yuv.yStride = yStride; |
|
|
stride.yuv.uvStride = uvStride; |
|
|
} |
|
|
break; |
|
|
case HAL_PIXEL_FORMAT_YUY2: |
|
|
case HAL_PIXEL_FORMAT_UYVY: |
|
|
yStride = align_to((align_to(w, 32) << 1), 64); |
|
|
uvStride = 0; |
|
|
stride.yuv.yStride = yStride; |
|
|
stride.yuv.uvStride = uvStride; |
|
|
break; |
|
|
} |
|
|
|
|
|
DataBuffer buf(khandle); |
|
|
// update buffer |
|
|
buf.setStride(stride); |
|
|
buf.setWidth(w); |
|
|
buf.setHeight(h); |
|
|
buf.setCrop(srcX, srcY, srcW, srcH); |
|
|
buf.setFormat(format); |
|
|
|
|
|
// create buffer mapper |
|
|
bool res = false; |
|
|
do { |
|
|
mapper = new TTMBufferMapper(*mWsbm, buf); |
|
|
if (!mapper) { |
|
|
ETRACE("failed to allocate mapper"); |
|
|
break; |
|
|
} |
|
|
// map ttm buffer |
|
|
ret = mapper->map(); |
|
|
if (!ret) { |
|
|
ETRACE("failed to map"); |
|
|
invalidateTTMBuffers(); |
|
|
ret = mapper->map(); |
|
|
if (!ret) { |
|
|
ETRACE("failed to remap"); |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
if (mTTMBuffers.size() >= OVERLAY_DATA_BUFFER_COUNT) { |
|
|
invalidateTTMBuffers(); |
|
|
} |
|
|
|
|
|
// add mapper |
|
|
index = mTTMBuffers.add(khandle, mapper); |
|
|
if (index < 0) { |
|
|
ETRACE("failed to add TTMMapper"); |
|
|
break; |
|
|
} |
|
|
|
|
|
// increase mapper refCount since it is added to mTTMBuffers |
|
|
mapper->incRef(); |
|
|
res = true; |
|
|
} while (0); |
|
|
|
|
|
if (!res) { |
|
|
// error handling |
|
|
if (mapper) { |
|
|
mapper->unmap(); |
|
|
delete mapper; |
|
|
mapper = NULL; |
|
|
} |
|
|
return 0; |
|
|
} |
|
|
} else { |
|
|
VTRACE("got mapper in saved ttm buffers"); |
|
|
mapper = reinterpret_cast<TTMBufferMapper *>(mTTMBuffers.valueAt(index)); |
|
|
if (mapper->getCrop().x != srcX || mapper->getCrop().y != srcY || |
|
|
mapper->getCrop().w != srcW || mapper->getCrop().h != srcH) { |
|
|
if(!mUseScaledBuffer) |
|
|
checkCrop(srcX, srcY, srcW, srcH, payload->coded_width, payload->coded_height); |
|
|
mapper->setCrop(srcX, srcY, srcW, srcH); |
|
|
} |
|
|
} |
|
|
|
|
|
XTRACE(); |
|
|
return mapper; |
|
|
} |
|
|
|
|
|
void OverlayPlaneBase::putTTMMapper(BufferMapper* mapper) |
|
|
{ |
|
|
if (!mapper) |
|
|
return; |
|
|
|
|
|
if (!mapper->decRef()) { |
|
|
// unmap it |
|
|
mapper->unmap(); |
|
|
|
|
|
// destroy this mapper |
|
|
delete mapper; |
|
|
} |
|
|
} |
|
|
|
|
|
bool OverlayPlaneBase::isActiveTTMBuffer(BufferMapper *mapper) |
|
|
{ |
|
|
for (size_t i = 0; i < mActiveTTMBuffers.size(); i++) { |
|
|
BufferMapper *activeMapper = mActiveTTMBuffers.itemAt(i); |
|
|
if (!activeMapper) |
|
|
continue; |
|
|
if (activeMapper->getKey() == mapper->getKey()) |
|
|
return true; |
|
|
} |
|
|
|
|
|
return false; |
|
|
} |
|
|
|
|
|
void OverlayPlaneBase::updateActiveTTMBuffers(BufferMapper *mapper) |
|
|
{ |
|
|
// unmap the first entry (oldest buffer) |
|
|
if (mActiveTTMBuffers.size() >= MAX_ACTIVE_TTM_BUFFERS) { |
|
|
BufferMapper *oldest = mActiveTTMBuffers.itemAt(0); |
|
|
putTTMMapper(oldest); |
|
|
mActiveTTMBuffers.removeAt(0); |
|
|
} |
|
|
|
|
|
// queue it to cached buffers |
|
|
if (!isActiveTTMBuffer(mapper)) { |
|
|
mapper->incRef(); |
|
|
mActiveTTMBuffers.push_back(mapper); |
|
|
} |
|
|
} |
|
|
|
|
|
void OverlayPlaneBase::invalidateActiveTTMBuffers() |
|
|
{ |
|
|
BufferMapper* mapper; |
|
|
|
|
|
RETURN_VOID_IF_NOT_INIT(); |
|
|
|
|
|
for (size_t i = 0; i < mActiveTTMBuffers.size(); i++) { |
|
|
mapper = mActiveTTMBuffers.itemAt(i); |
|
|
// unmap it |
|
|
putTTMMapper(mapper); |
|
|
} |
|
|
|
|
|
// clear recorded data buffers |
|
|
mActiveTTMBuffers.clear(); |
|
|
} |
|
|
|
|
|
void OverlayPlaneBase::invalidateTTMBuffers() |
|
|
{ |
|
|
BufferMapper* mapper; |
|
|
for (size_t i = 0; i < mTTMBuffers.size(); i++) { |
|
|
mapper = mTTMBuffers.valueAt(i); |
|
|
// putTTMMapper removes mapper from cache |
|
|
putTTMMapper(mapper); |
|
|
} |
|
|
mTTMBuffers.clear(); |
|
|
} |
|
|
|
|
|
|
|
|
bool OverlayPlaneBase::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) |
|
|
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) |
|
|
return false; |
|
|
|
|
|
if (payload->client_transform != mTransform) { |
|
|
if (payload->surface_protected) { |
|
|
payload->hwc_timestamp = systemTime(); |
|
|
payload->layer_transform = mTransform; |
|
|
} |
|
|
WTRACE("client is not ready"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
rotatedMapper = getTTMMapper(mapper, payload); |
|
|
return true; |
|
|
} |
|
|
|
|
|
|
|
|
bool OverlayPlaneBase::useOverlayRotation(BufferMapper& mapper) |
|
|
{ |
|
|
// by default overlay plane does not support rotation. |
|
|
return false; |
|
|
} |
|
|
|
|
|
bool OverlayPlaneBase::scaledBufferReady(BufferMapper& mapper, BufferMapper* &scaledMapper, VideoPayloadBuffer *payload) |
|
|
{ |
|
|
return false; |
|
|
} |
|
|
|
|
|
void OverlayPlaneBase::checkPosition(int& x, int& y, int& w, int& h) |
|
|
{ |
|
|
drmModeModeInfoPtr mode = &mModeInfo; |
|
|
|
|
|
if (mode->hdisplay == 0 || mode->vdisplay == 0) |
|
|
return; |
|
|
|
|
|
if (x < 0) |
|
|
x = 0; |
|
|
if (y < 0) |
|
|
y = 0; |
|
|
if ((x + w) > mode->hdisplay) |
|
|
w = mode->hdisplay - x; |
|
|
if ((y + h) > mode->vdisplay) |
|
|
h = mode->vdisplay - y; |
|
|
} |
|
|
|
|
|
void OverlayPlaneBase::checkCrop(int& srcX, int& srcY, int& srcW, int& srcH, |
|
|
int coded_width, int coded_height) |
|
|
{ |
|
|
int tmp; |
|
|
|
|
|
if (mTransform) |
|
|
srcH >>= mBobDeinterlace; |
|
|
|
|
|
if (mTransform == HWC_TRANSFORM_ROT_90 || mTransform == HWC_TRANSFORM_ROT_270) { |
|
|
tmp = srcH; |
|
|
srcH = srcW; |
|
|
srcW = tmp; |
|
|
|
|
|
tmp = srcX; |
|
|
srcX = srcY; |
|
|
srcY = tmp; |
|
|
|
|
|
tmp = coded_width; |
|
|
coded_width = coded_height; |
|
|
coded_height = tmp; |
|
|
} |
|
|
|
|
|
// skip pading bytes in rotate buffer |
|
|
switch(mTransform) { |
|
|
case HWC_TRANSFORM_ROT_90: |
|
|
srcX = (coded_width >> mBobDeinterlace) - srcW - srcX; |
|
|
break; |
|
|
case HWC_TRANSFORM_ROT_180: |
|
|
srcX = coded_width - srcW - srcX; |
|
|
srcY = (coded_height >> mBobDeinterlace) - srcH - srcY; |
|
|
break; |
|
|
case HWC_TRANSFORM_ROT_270: |
|
|
srcY = coded_height - srcH - srcY; |
|
|
break; |
|
|
default: |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
bool OverlayPlaneBase::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; |
|
|
|
|
|
// clear original format setting |
|
|
backBuffer->OCMD &= ~(0xf << 10); |
|
|
backBuffer->OCMD &= ~OVERLAY_MEMORY_LAYOUT_TILED; |
|
|
|
|
|
// Y/U/V plane must be 4k bytes aligned. |
|
|
backBuffer->OSTART_0Y = 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 |
|
|
backBuffer->OSTART_0Y |= 0x01; |
|
|
} |
|
|
|
|
|
backBuffer->OSTART_0U = gttOffsetInBytes; |
|
|
backBuffer->OSTART_0V = gttOffsetInBytes; |
|
|
|
|
|
backBuffer->OSTART_1Y = backBuffer->OSTART_0Y; |
|
|
backBuffer->OSTART_1U = backBuffer->OSTART_0U; |
|
|
backBuffer->OSTART_1V = backBuffer->OSTART_0V; |
|
|
|
|
|
switch(format) { |
|
|
case HAL_PIXEL_FORMAT_YV12: // YV12 |
|
|
backBuffer->OBUF_0Y = 0; |
|
|
backBuffer->OBUF_0V = yStride * h; |
|
|
backBuffer->OBUF_0U = backBuffer->OBUF_0V + (uvStride * (h / 2)); |
|
|
backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_YUV420; |
|
|
break; |
|
|
case HAL_PIXEL_FORMAT_I420: // I420 |
|
|
backBuffer->OBUF_0Y = 0; |
|
|
backBuffer->OBUF_0U = yStride * h; |
|
|
backBuffer->OBUF_0V = backBuffer->OBUF_0U + (uvStride * (h / 2)); |
|
|
backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_YUV420; |
|
|
break; |
|
|
case HAL_PIXEL_FORMAT_NV12: // NV12 |
|
|
backBuffer->OBUF_0Y = 0; |
|
|
backBuffer->OBUF_0U = yStride * h; |
|
|
backBuffer->OBUF_0V = 0; |
|
|
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: // Intel codec NV12 |
|
|
backBuffer->OBUF_0Y = 0; |
|
|
backBuffer->OBUF_0U = yStride * align_to(h, 32); |
|
|
backBuffer->OBUF_0V = 0; |
|
|
backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2; |
|
|
break; |
|
|
case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled: //NV12_tiled |
|
|
backBuffer->OBUF_0Y = 0; |
|
|
backBuffer->OBUF_0U = yStride * align_to(h, 32); |
|
|
backBuffer->OBUF_0V = 0; |
|
|
backBuffer->OSTART_0U += yStride * align_to(h, 32); |
|
|
backBuffer->OSTART_0V += yStride * align_to(h, 32); |
|
|
backBuffer->OSTART_1U = backBuffer->OSTART_0U; |
|
|
backBuffer->OSTART_1V = backBuffer->OSTART_0V; |
|
|
backBuffer->OTILEOFF_0Y = srcX + (srcY << 16); |
|
|
backBuffer->OTILEOFF_1Y = backBuffer->OTILEOFF_0Y; |
|
|
backBuffer->OTILEOFF_0U = srcX + ((srcY / 2) << 16); |
|
|
backBuffer->OTILEOFF_1U = backBuffer->OTILEOFF_0U; |
|
|
backBuffer->OTILEOFF_0V = backBuffer->OTILEOFF_0U; |
|
|
backBuffer->OTILEOFF_1V = backBuffer->OTILEOFF_0U; |
|
|
backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2; |
|
|
backBuffer->OCMD |= OVERLAY_MEMORY_LAYOUT_TILED; |
|
|
break; |
|
|
case HAL_PIXEL_FORMAT_YUY2: // YUY2 |
|
|
backBuffer->OBUF_0Y = 0; |
|
|
backBuffer->OBUF_0U = 0; |
|
|
backBuffer->OBUF_0V = 0; |
|
|
backBuffer->OCMD |= OVERLAY_FORMAT_PACKED_YUV422; |
|
|
backBuffer->OCMD |= OVERLAY_PACKED_ORDER_YUY2; |
|
|
break; |
|
|
case HAL_PIXEL_FORMAT_UYVY: // UYVY |
|
|
backBuffer->OBUF_0Y = 0; |
|
|
backBuffer->OBUF_0U = 0; |
|
|
backBuffer->OBUF_0V = 0; |
|
|
backBuffer->OCMD |= OVERLAY_FORMAT_PACKED_YUV422; |
|
|
backBuffer->OCMD |= OVERLAY_PACKED_ORDER_UYVY; |
|
|
break; |
|
|
default: |
|
|
ETRACE("unsupported format %d", format); |
|
|
return false; |
|
|
} |
|
|
|
|
|
backBuffer->OBUF_0Y += srcY * yStride + srcX; |
|
|
backBuffer->OBUF_0V += (srcY / 2) * uvStride + srcX; |
|
|
backBuffer->OBUF_0U += (srcY / 2) * uvStride + srcX; |
|
|
backBuffer->OBUF_1Y = backBuffer->OBUF_0Y; |
|
|
backBuffer->OBUF_1U = backBuffer->OBUF_0U; |
|
|
backBuffer->OBUF_1V = backBuffer->OBUF_0V; |
|
|
|
|
|
VTRACE("done. offset (%d, %d, %d)", |
|
|
backBuffer->OBUF_0Y, |
|
|
backBuffer->OBUF_0U, |
|
|
backBuffer->OBUF_0V); |
|
|
return true; |
|
|
} |
|
|
|
|
|
uint32_t OverlayPlaneBase::calculateSWidthSW(uint32_t offset, uint32_t width) |
|
|
{ |
|
|
ATRACE("offset = %d, width = %d", offset, width); |
|
|
|
|
|
uint32_t swidth = ((offset + width + 0x3F) >> 6) - (offset >> 6); |
|
|
|
|
|
swidth <<= 1; |
|
|
swidth -= 1; |
|
|
|
|
|
return swidth; |
|
|
} |
|
|
|
|
|
bool OverlayPlaneBase::coordinateSetup(BufferMapper& mapper) |
|
|
{ |
|
|
CTRACE(); |
|
|
|
|
|
OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf; |
|
|
if (!backBuffer) { |
|
|
ETRACE("invalid back buffer"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
uint32_t swidthy = 0; |
|
|
uint32_t swidthuv = 0; |
|
|
uint32_t format = mapper.getFormat(); |
|
|
uint32_t width = mapper.getCrop().w; |
|
|
uint32_t height = mapper.getCrop().h; |
|
|
uint32_t yStride = mapper.getStride().yuv.yStride; |
|
|
uint32_t uvStride = mapper.getStride().yuv.uvStride; |
|
|
uint32_t offsety = backBuffer->OBUF_0Y; |
|
|
uint32_t offsetu = backBuffer->OBUF_0U; |
|
|
|
|
|
switch (format) { |
|
|
case HAL_PIXEL_FORMAT_YV12: // YV12 |
|
|
case HAL_PIXEL_FORMAT_I420: // I420 |
|
|
case HAL_PIXEL_FORMAT_NV12: // NV12 |
|
|
case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar: // NV12 |
|
|
case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled: // NV12_tiled |
|
|
break; |
|
|
case HAL_PIXEL_FORMAT_YUY2: // YUY2 |
|
|
case HAL_PIXEL_FORMAT_UYVY: // UYVY |
|
|
width <<= 1; |
|
|
break; |
|
|
default: |
|
|
ETRACE("unsupported format %d", format); |
|
|
return false; |
|
|
} |
|
|
|
|
|
if (width <= 0 || height <= 0) { |
|
|
ETRACE("invalid src dim"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
if (yStride <=0 && uvStride <= 0) { |
|
|
ETRACE("invalid source stride"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
backBuffer->SWIDTH = width | ((width / 2) << 16); |
|
|
swidthy = calculateSWidthSW(offsety, width); |
|
|
swidthuv = calculateSWidthSW(offsetu, width / 2); |
|
|
backBuffer->SWIDTHSW = (swidthy << 2) | (swidthuv << 18); |
|
|
backBuffer->SHEIGHT = height | ((height / 2) << 16); |
|
|
backBuffer->OSTRIDE = (yStride & (~0x3f)) | ((uvStride & (~0x3f)) << 16); |
|
|
|
|
|
XTRACE(); |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
bool OverlayPlaneBase::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; |
|
|
} |
|
|
|
|
|
void OverlayPlaneBase::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.54 - 0.46 * cos(2 * i * pi / (2 * num - 1))); |
|
|
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; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
bool OverlayPlaneBase::scalingSetup(BufferMapper& mapper) |
|
|
{ |
|
|
int xscaleInt, xscaleFract, yscaleInt, yscaleFract; |
|
|
int xscaleIntUV, xscaleFractUV; |
|
|
int yscaleIntUV, yscaleFractUV; |
|
|
int deinterlace_factor = 1; |
|
|
// 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; |
|
|
bool scaleChanged = false; |
|
|
int x, y, w, h; |
|
|
|
|
|
OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf; |
|
|
if (!backBuffer) { |
|
|
ETRACE("invalid back buffer"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
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)", |
|
|
srcWidth, srcHeight, |
|
|
dstWidth, dstHeight); |
|
|
|
|
|
// 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 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; |
|
|
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); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
XTRACE(); |
|
|
return true; |
|
|
} |
|
|
|
|
|
bool OverlayPlaneBase::colorSetup(BufferMapper& mapper) |
|
|
{ |
|
|
CTRACE(); |
|
|
|
|
|
OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf; |
|
|
if (!backBuffer) { |
|
|
ETRACE("invalid back buffer"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
uint32_t format = mapper.getFormat(); |
|
|
if (format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar && |
|
|
format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled) { |
|
|
|
|
|
VTRACE("Not video layer, use default color setting"); |
|
|
backBuffer->OCLRC0 = (OVERLAY_INIT_CONTRAST << 18) | |
|
|
(OVERLAY_INIT_BRIGHTNESS & 0xff); |
|
|
backBuffer->OCLRC1 = OVERLAY_INIT_SATURATION; |
|
|
backBuffer->OCONFIG &= ~(1 << 5); |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
struct VideoPayloadBuffer *payload; |
|
|
payload = (struct VideoPayloadBuffer *)mapper.getCpuAddress(SUB_BUFFER1); |
|
|
// check payload |
|
|
if (!payload) { |
|
|
ETRACE("no payload found"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
// BT.601 or BT.709 |
|
|
backBuffer->OCONFIG &= ~(1 << 5); |
|
|
backBuffer->OCONFIG |= ((payload->csc_mode & 1) << 5); |
|
|
|
|
|
// no level expansion for video on HDMI |
|
|
if (payload->video_range || mPipeConfig == (0x2 << 6)) { |
|
|
// full range, no need to do level expansion |
|
|
backBuffer->OCLRC0 = 0x1000000; |
|
|
backBuffer->OCLRC1 = 0x80; |
|
|
} else { |
|
|
// level expansion for limited range |
|
|
backBuffer->OCLRC0 = (OVERLAY_INIT_CONTRAST << 18) | |
|
|
(OVERLAY_INIT_BRIGHTNESS & 0xff); |
|
|
backBuffer->OCLRC1 = OVERLAY_INIT_SATURATION; |
|
|
} |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
bool OverlayPlaneBase::setDataBuffer(BufferMapper& grallocMapper) |
|
|
{ |
|
|
BufferMapper *mapper; |
|
|
BufferMapper *videoBufferMapper = 0; |
|
|
bool ret; |
|
|
uint32_t format; |
|
|
|
|
|
RETURN_FALSE_IF_NOT_INIT(); |
|
|
|
|
|
// get gralloc mapper |
|
|
mapper = &grallocMapper; |
|
|
format = grallocMapper.getFormat(); |
|
|
if (format == OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar || |
|
|
format == OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled) { |
|
|
struct VideoPayloadBuffer *payload; |
|
|
payload = (struct VideoPayloadBuffer *)grallocMapper.getCpuAddress(SUB_BUFFER1); |
|
|
if (!payload) { |
|
|
ETRACE("invalid payload buffer"); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
mBobDeinterlace = payload->bob_deinterlace; |
|
|
|
|
|
int srcW, srcH; |
|
|
srcW = grallocMapper.getCrop().w - grallocMapper.getCrop().x; |
|
|
srcH = grallocMapper.getCrop().h - grallocMapper.getCrop().y; |
|
|
if ((srcW > INTEL_OVERLAY_MAX_WIDTH - 1) || (srcH > INTEL_OVERLAY_MAX_HEIGHT - 1)) { |
|
|
if (mTransform) { |
|
|
int x, y, w, h; |
|
|
x = mSrcCrop.x; |
|
|
y = mSrcCrop.y; |
|
|
w = mSrcCrop.w; |
|
|
h = mSrcCrop.h; |
|
|
setSourceCrop(0, 0, payload->scaling_width, payload->scaling_height); |
|
|
if (!useOverlayRotation(grallocMapper)) { |
|
|
DTRACE("The scaled buffer will hit overlay rotation limitation, fall back to GLES"); |
|
|
setSourceCrop(x, y, w, h); |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
if (!scaledBufferReady(grallocMapper, videoBufferMapper, payload)) { |
|
|
DTRACE("scaled buffer is not ready, fall back to GLES"); |
|
|
return false; |
|
|
} else { |
|
|
videoBufferMapper->setFormat(OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar); |
|
|
mapper = videoBufferMapper; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
if (!mUseScaledBuffer && mTransform && !useOverlayRotation(grallocMapper)) { |
|
|
if (!rotatedBufferReady(grallocMapper, videoBufferMapper)) { |
|
|
DTRACE("rotated buffer is not ready"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
if (!videoBufferMapper) { |
|
|
ETRACE("failed to get rotated buffer"); |
|
|
return false; |
|
|
} |
|
|
mapper = videoBufferMapper; |
|
|
} |
|
|
|
|
|
OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf; |
|
|
if (!backBuffer) { |
|
|
ETRACE("invalid back buffer"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
ret = bufferOffsetSetup(*mapper); |
|
|
if (ret == false) { |
|
|
ETRACE("failed to set up buffer offsets"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
ret = coordinateSetup(*mapper); |
|
|
if (ret == false) { |
|
|
ETRACE("failed to set up overlay coordinates"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
ret = scalingSetup(*mapper); |
|
|
if (ret == false) { |
|
|
ETRACE("failed to set up scaling parameters"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
backBuffer->OCMD |= 0x1; |
|
|
|
|
|
ret = colorSetup(grallocMapper); |
|
|
if (ret == false) { |
|
|
ETRACE("failed to set up color parameters"); |
|
|
return false; |
|
|
} |
|
|
if (mBobDeinterlace && !mTransform) { |
|
|
backBuffer->OCMD |= BUF_TYPE_FIELD; |
|
|
backBuffer->OCMD &= ~FIELD_SELECT; |
|
|
backBuffer->OCMD |= FIELD0; |
|
|
backBuffer->OCMD &= ~(BUFFER_SELECT); |
|
|
backBuffer->OCMD |= BUFFER0; |
|
|
} |
|
|
|
|
|
// add to active ttm buffers if it's a rotated buffer |
|
|
if (videoBufferMapper) { |
|
|
updateActiveTTMBuffers(mapper); |
|
|
} |
|
|
|
|
|
mUseScaledBuffer = 0; |
|
|
return true; |
|
|
} |
|
|
|
|
|
} // namespace intel |
|
|
} // namespace android |
|
|
|
|
|
|