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