/* // 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 <common/utils/HwcTrace.h> #include <Hwcomposer.h> #include <DisplayPlane.h> #include <GraphicBuffer.h> #include <DisplayQuery.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), mForceScaling(false), mDisplayWidth(0), mDisplayHeight(0), mScalingSource(0), mScalingTarget(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) { WLOGTRACE("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) { ALOGTRACE("Position = %d, %d - %dx%d", x, y, w, h); if (mForceScaling) { // set in assignToDevice mPosition.x = (int) (((float)x/DEFAULT_DRM_FB_WIDTH)*mDisplayWidth); mPosition.y = (int) (((float)y/DEFAULT_DRM_FB_HEIGHT)*mDisplayHeight); mPosition.w = (int) (((float)w/DEFAULT_DRM_FB_WIDTH)*mDisplayWidth); mPosition.h = (int) (((float)h/DEFAULT_DRM_FB_HEIGHT)*mDisplayHeight); mDisplayCrop.x = 0; mDisplayCrop.y = 0; mDisplayCrop.w = mDisplayWidth; mDisplayCrop.h = mDisplayHeight; return; } 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) { ALOGTRACE("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; mSrcCrop.w = w; mSrcCrop.h = h; } } void DisplayPlane::setTransform(int trans) { ALOGTRACE("transform = %d", trans); if (mTransform == trans) { return; } mTransform = trans; mUpdateMasks |= PLANE_TRANSFORM_CHANGED; } void DisplayPlane::setPlaneAlpha(uint8_t alpha, uint32_t blending) { ALOGTRACE("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(uint32_t handle) { DataBuffer *buffer; BufferMapper *mapper; ssize_t index; bool ret; bool isCompression; BufferManager *bm = Hwcomposer::getInstance().getBufferManager(); RETURN_FALSE_IF_NOT_INIT(); ALOGTRACE("handle = %#x", handle); if (!handle) { WLOGTRACE("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) { ELOGTRACE("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) { VLOGTRACE("unmapped buffer, mapping..."); mapper = mapBuffer(buffer); // Skip the unsupported format in case that a new gralloc buffer was // created and added into the mapped list, triggered by SoftwareRender // with color conversion from known formats to YV12. if (!mapper || mapper->getFormat() == HAL_PIXEL_FORMAT_YV12) { ELOGTRACE("failed to map buffer %#x", handle); bm->unlockDataBuffer(buffer); return false; } } else { VLOGTRACE("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) { ELOGTRACE("failed to map buffer"); return NULL; } // add it to data buffers ssize_t index = mDataBuffers.add(buffer->getKey(), mapper); if (index < 0) { ELOGTRACE("failed to add mapper"); bm->unmap(mapper); return NULL; } return mapper; } bool DisplayPlane::isActiveBuffer(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 true; } return false; } void DisplayPlane::updateActiveBuffers(BufferMapper *mapper) { BufferManager *bm = Hwcomposer::getInstance().getBufferManager(); // unmap the first entry (oldest buffer) if (mActiveBuffers.size() >= MIN_DATA_BUFFER_COUNT) { BufferMapper *oldest = mActiveBuffers.itemAt(0); bm->unmap(oldest); mActiveBuffers.removeAt(0); } // queue it to active buffers if (!isActiveBuffer(mapper)) { mapper->incRef(); mActiveBuffers.push_back(mapper); } } void DisplayPlane::invalidateActiveBuffers() { BufferManager *bm = Hwcomposer::getInstance().getBufferManager(); BufferMapper* mapper; RETURN_VOID_IF_NOT_INIT(); VLOGTRACE("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(); ALOGTRACE("disp = %d", disp); mDevice = disp; Drm *drm = Hwcomposer::getInstance().getDrm(); if (!drm->getModeInfo(mDevice, mModeInfo)) { ELOGTRACE("failed to get mode info"); } mPanelOrientation = drm->getPanelOrientation(mDevice); mForceScaling = DisplayQuery::forceFbScaling(disp); drm->getDisplayResolution(disp, mDisplayWidth, mDisplayHeight); if (mForceScaling) { mModeInfo.hdisplay = mDisplayWidth; mModeInfo.vdisplay = mDisplayHeight; } 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