blob: 04fd1bbfa19ba08cbf731d5fd8c0b48528c1445a [file] [log] [blame]
/*
// 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