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