/* // 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 <Drm.h> #include <HwcLayer.h> #include <Hwcomposer.h> #include <GraphicBuffer.h> #include <IDisplayDevice.h> #include <DisplayQuery.h> #include <PlaneCapabilities.h> #include <cutils/properties.h> namespace android { namespace intel { inline bool operator==(const hwc_rect_t& x, const hwc_rect_t& y) { return (x.top == y.top && x.bottom == y.bottom && x.left == y.left && x.right == y.right); } inline bool operator !=(const hwc_rect_t& x, const hwc_rect_t& y) { return !operator==(x, y); } inline bool operator ==(const hwc_frect_t& x, const hwc_frect_t& y) { return (x.top == y.top && x.bottom == y.bottom && x.left == y.left && x.right == y.right); } inline bool operator !=(const hwc_frect_t& x, const hwc_frect_t& y) { return !operator==(x, y); } HwcLayer::HwcLayer(int index, hwc_layer_1_t *layer) : mIndex(index), mZOrder(index + 1), // 0 is reserved for frame buffer target mDevice(0), mLayer(layer), mPlane(0), mFormat(DataBuffer::FORMAT_INVALID), mWidth(0), mHeight(0), mUsage(0), mHandle(0), mIsProtected(false), mType(LAYER_FB), mPriority(0), mTransform(0), mStaticCount(0), mUpdated(false) { memset(&mSourceCropf, 0, sizeof(mSourceCropf)); memset(&mDisplayFrame, 0, sizeof(mDisplayFrame)); memset(&mStride, 0, sizeof(mStride)); mPlaneCandidate = false; setupAttributes(); #ifdef HWC_TRACE_FPS mTraceFps = false; char prop[PROPERTY_VALUE_MAX]; if (property_get("debug.hwc.fps_trace.enable", prop, "0") > 0) { mTraceFps = atoi(prop); } mLastHandle = NULL; if (mTraceFps) { // holding up to 6 seconds of samples at 60Hz mFrames.setCapacity(6 * 60); } #endif } HwcLayer::~HwcLayer() { if (mPlane) { WTRACE("HwcLayer is not cleaned up"); } mLayer = NULL; mPlane = NULL; #ifdef HWC_TRACE_FPS mFrames.clear(); #endif } bool HwcLayer::attachPlane(DisplayPlane* plane, int device) { if (mPlane) { ETRACE("failed to attach plane, plane exists"); return false; } if (!plane) { ETRACE("Invalid plane"); return false; } mDevice = device; //plane->setZOrder(mIndex); plane->assignToDevice(device); mPlane = plane; return true; } DisplayPlane* HwcLayer::detachPlane() { // reset plane's z order if (mPlane) mPlane->setZOrder(-1); DisplayPlane *plane = mPlane; mPlane = 0; mDevice = 0; return plane; } void HwcLayer::setType(uint32_t type) { if (!mLayer) return; switch (type) { case LAYER_OVERLAY: case LAYER_SKIPPED: mLayer->compositionType = HWC_OVERLAY; mLayer->hints |= HWC_HINT_CLEAR_FB; break; // NOTE: set compositionType to HWC_FRAMEBUFFER here so that we have // a chance to submit the primary changes to HW. // Upper layer HWComposer will reset the compositionType automatically. case LAYER_FB: case LAYER_FORCE_FB: mLayer->compositionType = HWC_FRAMEBUFFER; break; case LAYER_SIDEBAND: mLayer->compositionType = HWC_SIDEBAND; break; case LAYER_CURSOR_OVERLAY: mLayer->compositionType = HWC_CURSOR_OVERLAY; break; default: break; } mType = type; } uint32_t HwcLayer::getType() const { return mType; } void HwcLayer::setCompositionType(int32_t type) { mLayer->compositionType = type; } int32_t HwcLayer::getCompositionType() const { return mLayer->compositionType; } int HwcLayer::getIndex() const { return mIndex; } int HwcLayer::getZOrder() const { return mZOrder; } uint32_t HwcLayer::getFormat() const { return mFormat; } uint32_t HwcLayer::getBufferWidth() const { return mWidth; } uint32_t HwcLayer::getBufferHeight() const { return mHeight; } const stride_t& HwcLayer::getBufferStride() const { return mStride; } uint32_t HwcLayer::getUsage() const { return mUsage; } buffer_handle_t HwcLayer::getHandle() const { return mHandle; } uint32_t HwcLayer::getTransform() const { return mTransform; } bool HwcLayer::isProtected() const { return mIsProtected; } hwc_layer_1_t* HwcLayer::getLayer() const { return mLayer; } DisplayPlane* HwcLayer::getPlane() const { return mPlane; } void HwcLayer::setPriority(uint32_t priority) { mPriority = priority; } uint32_t HwcLayer::getPriority() const { return mPriority; } bool HwcLayer::update(hwc_layer_1_t *layer) { // update layer mLayer = layer; setupAttributes(); #ifdef HWC_TRACE_FPS if (mTraceFps && mLayer && mLayer->compositionType != HWC_FRAMEBUFFER_TARGET ) { // 1 second = 1000000000 nano seconds uint64_t now = systemTime(CLOCK_MONOTONIC); if (mLastHandle != mHandle) { mLastHandle = mHandle; mFrames.push(now); } // calculate fps in 5-second time window int frames = mFrames.size(); while (frames && now - mFrames[0] > 5000000000LL) { mFrames.removeItemsAt(0); frames--; } double fps = 0; if (frames > 1) { fps = frames * 1000000000.0/ (now - mFrames[0]); } ITRACE("fps of layer %d is %.1f", mIndex, fps); } #endif // if not a FB layer & a plane was attached update plane's data buffer if (mPlane) { mPlane->setPosition(layer->displayFrame.left, layer->displayFrame.top, layer->displayFrame.right - layer->displayFrame.left, layer->displayFrame.bottom - layer->displayFrame.top); mPlane->setSourceCrop(layer->sourceCropf.left, layer->sourceCropf.top, layer->sourceCropf.right - layer->sourceCropf.left, layer->sourceCropf.bottom - layer->sourceCropf.top); mPlane->setTransform(layer->transform); mPlane->setPlaneAlpha(layer->planeAlpha, layer->blending); bool ret = mPlane->setDataBuffer(layer->handle); if (ret == true) { return true; } DTRACE("failed to set data buffer, reset handle to 0!!"); mHandle = 0; if (!mIsProtected) { // typical case: rotated buffer is not ready or handle is null return false; } else { // protected video has to be rendered using overlay. // if buffer is not ready overlay will still be attached to this layer // but rendering needs to be skipped. WTRACE("ignoring result of data buffer setting for protected video"); return true; } } return true; } bool HwcLayer::isUpdated() { return mUpdated; } uint32_t HwcLayer::getStaticCount() { return mStaticCount; } void HwcLayer::postFlip() { mUpdated = false; if (mPlane) { mPlane->postFlip(); // flip frame buffer target once in video extended mode to refresh screen, // then mark type as LAYER_SKIPPED so it will not be flipped again. // by doing this pipe for primary device can enter idle state if (mDevice == IDisplayDevice::DEVICE_PRIMARY && mType == LAYER_FRAMEBUFFER_TARGET && Hwcomposer::getInstance().getDisplayAnalyzer()->isVideoExtModeActive()) { DTRACE("Skipping frame buffer target..."); mType = LAYER_SKIPPED; } } } void HwcLayer::setupAttributes() { if ((mLayer->flags & HWC_SKIP_LAYER) || mTransform != mLayer->transform || mSourceCropf != mLayer->sourceCropf || mDisplayFrame != mLayer->displayFrame || mHandle != mLayer->handle || DisplayQuery::isVideoFormat(mFormat)) { // TODO: same handle does not mean there is always no update mUpdated = true; mStaticCount = 0; } else { // protect it from exceeding its max if (++mStaticCount > 1000) mStaticCount = LAYER_STATIC_THRESHOLD + 1; } // update handle always as it can become "NULL" // if the given layer is not ready mTransform = mLayer->transform; mSourceCropf = mLayer->sourceCropf; mDisplayFrame = mLayer->displayFrame; mHandle = mLayer->handle; if (mFormat != DataBuffer::FORMAT_INVALID) { // other attributes have been set. return; } if (mLayer->handle == NULL) { VTRACE("invalid handle"); return; } BufferManager *bm = Hwcomposer::getInstance().getBufferManager(); if (bm == NULL) { // TODO: this check is redundant return; } DataBuffer *buffer = bm->lockDataBuffer(mLayer->handle); if (!buffer) { ETRACE("failed to get buffer"); } else { mFormat = buffer->getFormat(); mWidth = buffer->getWidth(); mHeight = buffer->getHeight(); mStride = buffer->getStride(); mPriority = (mSourceCropf.right - mSourceCropf.left) * (mSourceCropf.bottom - mSourceCropf.top); mPriority <<= LAYER_PRIORITY_SIZE_OFFSET; mPriority |= mIndex; GraphicBuffer *gBuffer = (GraphicBuffer*)buffer; mUsage = gBuffer->getUsage(); mIsProtected = GraphicBuffer::isProtectedBuffer((GraphicBuffer*)buffer); if (mIsProtected) { mPriority |= LAYER_PRIORITY_PROTECTED; } else if (PlaneCapabilities::isFormatSupported(DisplayPlane::PLANE_OVERLAY, this)) { mPriority |= LAYER_PRIORITY_OVERLAY; } bm->unlockDataBuffer(buffer); } } } // namespace intel } // namespace android