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