/*
// 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 <tangier/TngOverlayPlane.h>
#include <tangier/TngGrallocBuffer.h>
namespace android {
namespace intel {
TngOverlayPlane::TngOverlayPlane(int index, int disp)
: OverlayPlaneBase(index, disp),
mRotationBufProvider(NULL)
{
CTRACE();
memset(&mContext, 0, sizeof(mContext));
}
TngOverlayPlane::~TngOverlayPlane()
{
CTRACE();
}
bool TngOverlayPlane::flip(void *ctx)
{
RETURN_FALSE_IF_NOT_INIT();
if (!DisplayPlane::flip(ctx))
return false;
mContext.type = DC_OVERLAY_PLANE;
mContext.ctx.ov_ctx.ovadd = 0x0;
mContext.ctx.ov_ctx.ovadd = (mBackBuffer[mCurrent]->gttOffsetInPage << 12);
mContext.ctx.ov_ctx.index = mIndex;
mContext.ctx.ov_ctx.pipe = mDevice;
mContext.ctx.ov_ctx.ovadd |= mPipeConfig;
mContext.ctx.ov_ctx.ovadd |= 0x1;
// 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;
}
bool TngOverlayPlane::reset()
{
OverlayPlaneBase::reset();
if (mRotationBufProvider)
mRotationBufProvider->reset();
return true;
}
void* TngOverlayPlane::getContext() const
{
CTRACE();
return (void *)&mContext;
}
bool TngOverlayPlane::setDataBuffer(BufferMapper& mapper)
{
if (OverlayPlaneBase::setDataBuffer(mapper) == false) {
return false;
}
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 = (uint64_t)mapper.getCpuAddress(0);
return true;
}
bool TngOverlayPlane::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 TngOverlayPlane::deinitialize()
{
DEINIT_AND_DELETE_OBJ(mRotationBufProvider);
OverlayPlaneBase::deinitialize();
}
bool TngOverlayPlane::rotatedBufferReady(BufferMapper& mapper, BufferMapper* &rotatedMapper)
{
struct VideoPayloadBuffer *payload;
VideoPayloadBuffer buffer_info;
uint32_t format;
// only NV12_VED has rotated buffer
format = mapper.getFormat();
if (format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar &&
format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled &&
format != HAL_PIXEL_FORMAT_NV12) {
ETRACE("Invalid video format %#x", format);
return false;
}
payload = (struct VideoPayloadBuffer *)mapper.getCpuAddress(SUB_BUFFER1);
if (payload == NULL && format == HAL_PIXEL_FORMAT_NV12) {
// need to populate buffer_info
void *p = mapper.getCpuAddress(SUB_BUFFER0);
if (!p) {
ETRACE("failed to get buffer user pointer");
return false;
}
bool ret = mRotationBufProvider->prepareBufferInfo(mapper.getWidth(),
mapper.getHeight(),
mapper.getStride().yuv.yStride,
&buffer_info, p);
if (ret == false) {
ETRACE("failed to prepare buffer info");
return false;
}
payload = &buffer_info;
}
// 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) {
payload->hwc_timestamp = systemTime();
payload->layer_transform = mTransform;
if (!mRotationBufProvider->setupRotationBuffer(payload, mTransform)) {
ETRACE("failed to setup rotation buffer");
return false;
}
}
rotatedMapper = getTTMMapper(mapper, payload);
return true;
}
bool TngOverlayPlane::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))
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 = (mBackBuffer[mCurrent]->gttOffsetInPage << 12);
// pipe select
arg.plane.ctx |= mPipeConfig;
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