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