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