/*
// 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 <HwcTrace.h>
#include <Hwcomposer.h>
#include <DisplayPlane.h>
#include <GraphicBuffer.h>
namespace android {
namespace intel {
DisplayPlane::DisplayPlane(int index, int type, int disp)
: mIndex(index),
mType(type),
mZOrder(-1),
mDevice(disp),
mInitialized(false),
mDataBuffers(),
mActiveBuffers(),
mCacheCapacity(0),
mIsProtectedBuffer(false),
mTransform(0),
mPlaneAlpha(0),
mBlending(HWC_BLENDING_NONE),
mCurrentDataBuffer(0),
mUpdateMasks(0)
{
CTRACE();
memset(&mPosition, 0, sizeof(mPosition));
memset(&mSrcCrop, 0, sizeof(mSrcCrop));
}
DisplayPlane::~DisplayPlane()
{
WARN_IF_NOT_DEINIT();
}
bool DisplayPlane::initialize(uint32_t bufferCount)
{
CTRACE();
if (bufferCount < MIN_DATA_BUFFER_COUNT) {
WTRACE("buffer count %d is too small", bufferCount);
bufferCount = MIN_DATA_BUFFER_COUNT;
}
// create buffer cache, adding few extra slots as buffer rendering is async
// buffer could still be queued in the display pipeline such that they
// can't be unmapped]
mCacheCapacity = bufferCount;
mDataBuffers.setCapacity(bufferCount);
mActiveBuffers.setCapacity(MIN_DATA_BUFFER_COUNT);
mInitialized = true;
return true;
}
void DisplayPlane::deinitialize()
{
// invalidate cached data buffers
if (mDataBuffers.size()) {
// invalidateBufferCache will assert if object is not initialized
// so invoking it only there is buffer to invalidate.
invalidateBufferCache();
}
// invalidate active buffers
if (mActiveBuffers.size()) {
invalidateActiveBuffers();
}
mCurrentDataBuffer = 0;
mInitialized = false;
}
void DisplayPlane::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 DisplayPlane::setPosition(int x, int y, int w, int h)
{
ATRACE("Position = %d, %d - %dx%d", x, y, w, h);
if (mPosition.x != x || mPosition.y != y ||
mPosition.w != w || mPosition.h != h) {
mUpdateMasks |= PLANE_POSITION_CHANGED;
mPosition.x = x;
mPosition.y = y;
mPosition.w = w;
mPosition.h = h;
}
}
void DisplayPlane::setSourceCrop(int x, int y, int w, int h)
{
ATRACE("Source crop = %d, %d - %dx%d", x, y, w, h);
if (mSrcCrop.x != x || mSrcCrop.y != y ||
mSrcCrop.w != w || mSrcCrop.h != h) {
mUpdateMasks |= PLANE_SOURCE_CROP_CHANGED;
mSrcCrop.x = x;
mSrcCrop.y = y;
if (mType == DisplayPlane::PLANE_OVERLAY) {
mSrcCrop.w = w & (~0x01);
mSrcCrop.h = h & (~0x01);
} else {
mSrcCrop.w = w;
mSrcCrop.h = h;
}
}
}
void DisplayPlane::setTransform(int trans)
{
ATRACE("transform = %d", trans);
if (mTransform == trans) {
return;
}
mTransform = trans;
mUpdateMasks |= PLANE_TRANSFORM_CHANGED;
}
void DisplayPlane::setPlaneAlpha(uint8_t alpha, uint32_t blending)
{
ATRACE("plane alpha = 0x%x", alpha);
if (mPlaneAlpha != alpha) {
mPlaneAlpha = alpha;
mUpdateMasks |= PLANE_BUFFER_CHANGED;
}
if (mBlending != blending) {
mBlending = blending;
mUpdateMasks |= PLANE_BUFFER_CHANGED;
}
}
bool DisplayPlane::setDataBuffer(buffer_handle_t handle)
{
DataBuffer *buffer;
BufferMapper *mapper;
ssize_t index;
bool ret;
bool isCompression;
BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
RETURN_FALSE_IF_NOT_INIT();
ATRACE("handle = %#x", handle);
if (!handle) {
WTRACE("invalid buffer handle");
return false;
}
// do not need to update the buffer handle
if (mCurrentDataBuffer != handle)
mUpdateMasks |= PLANE_BUFFER_CHANGED;
// if no update then do Not need set data buffer
if (!mUpdateMasks)
return true;
buffer = bm->lockDataBuffer(handle);
if (!buffer) {
ETRACE("failed to get buffer");
return false;
}
mIsProtectedBuffer = GraphicBuffer::isProtectedBuffer((GraphicBuffer*)buffer);
isCompression = GraphicBuffer::isCompressionBuffer((GraphicBuffer*)buffer);
// map buffer if it's not in cache
index = mDataBuffers.indexOfKey(buffer->getKey());
if (index < 0) {
VTRACE("unmapped buffer, mapping...");
mapper = mapBuffer(buffer);
if (!mapper) {
ETRACE("failed to map buffer %p", handle);
bm->unlockDataBuffer(buffer);
return false;
}
} else {
VTRACE("got mapper in saved data buffers and update source Crop");
mapper = mDataBuffers.valueAt(index);
}
// always update source crop to mapper
mapper->setCrop(mSrcCrop.x, mSrcCrop.y, mSrcCrop.w, mSrcCrop.h);
mapper->setIsCompression(isCompression);
// unlock buffer after getting mapper
bm->unlockDataBuffer(buffer);
buffer = NULL;
ret = setDataBuffer(*mapper);
if (ret) {
mCurrentDataBuffer = handle;
// update active buffers
updateActiveBuffers(mapper);
}
return ret;
}
BufferMapper* DisplayPlane::mapBuffer(DataBuffer *buffer)
{
BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
// invalidate buffer cache if cache is full
if ((int)mDataBuffers.size() >= mCacheCapacity) {
invalidateBufferCache();
}
BufferMapper *mapper = bm->map(*buffer);
if (!mapper) {
ETRACE("failed to map buffer");
return NULL;
}
// add it to data buffers
ssize_t index = mDataBuffers.add(buffer->getKey(), mapper);
if (index < 0) {
ETRACE("failed to add mapper");
bm->unmap(mapper);
return NULL;
}
return mapper;
}
int DisplayPlane::findActiveBuffer(BufferMapper *mapper)
{
for (size_t i = 0; i < mActiveBuffers.size(); i++) {
BufferMapper *activeMapper = mActiveBuffers.itemAt(i);
if (!activeMapper)
continue;
if (activeMapper->getKey() == mapper->getKey())
return i;
}
return -1;
}
void DisplayPlane::updateActiveBuffers(BufferMapper *mapper)
{
BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
int index = findActiveBuffer(mapper);
bool exist = (0 <= index && index < (int)mActiveBuffers.size());
// unmap the first entry (oldest buffer)
if (!exist && mActiveBuffers.size() >= MIN_DATA_BUFFER_COUNT) {
BufferMapper *oldest = mActiveBuffers.itemAt(0);
bm->unmap(oldest);
mActiveBuffers.removeAt(0);
}
// queue it to active buffers
if (!exist) {
mapper->incRef();
} else {
mActiveBuffers.removeAt(index);
}
mActiveBuffers.push_back(mapper);
}
void DisplayPlane::invalidateActiveBuffers()
{
BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
BufferMapper* mapper;
RETURN_VOID_IF_NOT_INIT();
VTRACE("invalidating active buffers");
for (size_t i = 0; i < mActiveBuffers.size(); i++) {
mapper = mActiveBuffers.itemAt(i);
// unmap it
bm->unmap(mapper);
}
// clear recorded data buffers
mActiveBuffers.clear();
}
void DisplayPlane::invalidateBufferCache()
{
BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
BufferMapper* mapper;
RETURN_VOID_IF_NOT_INIT();
for (size_t i = 0; i < mDataBuffers.size(); i++) {
mapper = mDataBuffers.valueAt(i);
bm->unmap(mapper);
}
mDataBuffers.clear();
// reset current buffer
mCurrentDataBuffer = 0;
}
void DisplayPlane::resetCurrentBuffer()
{
// reset current data buffer
mCurrentDataBuffer = 0;
}
bool DisplayPlane::assignToDevice(int disp)
{
RETURN_FALSE_IF_NOT_INIT();
ATRACE("disp = %d", disp);
mDevice = disp;
Drm *drm = Hwcomposer::getInstance().getDrm();
if (!drm->getModeInfo(mDevice, mModeInfo)) {
ETRACE("failed to get mode info");
}
mPanelOrientation = drm->getPanelOrientation(mDevice);
return true;
}
bool DisplayPlane::flip(void *ctx)
{
RETURN_FALSE_IF_NOT_INIT();
// always flip
return true;
}
void DisplayPlane::postFlip()
{
mUpdateMasks = 0;
}
bool DisplayPlane::reset()
{
// reclaim all allocated resources
if (mDataBuffers.size() > 0) {
invalidateBufferCache();
}
if (mActiveBuffers.size() > 0) {
invalidateActiveBuffers();
}
return true;
}
void DisplayPlane::setZOrder(int zorder)
{
mZOrder = zorder;
}
int DisplayPlane::getZOrder() const
{
return mZOrder;
}
} // namespace intel
} // namespace android