You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

371 lines
12 KiB

/*
* Copyright (c) Hisilicon Technologies Co., Ltd.. 2016-2019. All rights reserved.
* Description: The smallest unit of hwc composition mainly realizes the attribute change of some individual layers
* Author: Hisilicon
* Created: 2016.08.12
*/
#include "HWCLayer.h"
#include <cstdlib>
#include <fcntl.h>
#include <log/log.h>
#include <utils/Errors.h>
#include <hardware/hardware.h>
#include <securec.h>
#include "gfbg.h"
#include "HWCCommon.h"
#include "HWCIapiAdapter.h"
namespace android {
static void SetRect(const hwc_frect_t &source, hwc_rect_t &target)
{
target.left = static_cast<int>(source.left);
target.top = static_cast<int>(source.top);
target.right = static_cast<int>(source.right);
target.bottom = static_cast<int>(source.bottom);
}
static std::atomic<hwc2_layer_t> g_nextHwcLayerId(1); // initialization static g_nextLayerId
HWCLayer::HWCLayer(hwc2_display_t displayId)
: m_zOrder(0),
m_id(g_nextHwcLayerId++),
m_layerBuffer({nullptr, -1, -1}),
m_blendMode(HWC2::BlendMode::None),
m_planeAlpha(0.0f),
m_displayFrame({ 0, 0, 0, 0 }),
m_clientRequested(HWC2::Composition::Device),
m_deviceSelected(HWC2::Composition::Device),
m_sourceCrop({ 0, 0, 0, 0 }),
m_sidebandStream(nullptr),
m_visibleRegion(),
m_visible(false),
m_transform(HWC2::Transform::None),
m_displayId(displayId),
m_surfaceDamage(),
#ifdef OVERLAY
m_lastOverlayBuffer(nullptr),
m_overlay(nullptr),
#endif
m_color({ 0, 0, 0, 0 })
{
m_releaseFences.push(-1);
}
HWCLayer::~HWCLayer()
{
if (m_sidebandStream != nullptr) {
HWCIapiAdapter::GetInstance().DisableVoWindow(*m_sidebandStream);
native_handle_close(m_sidebandStream);
native_handle_delete(const_cast<native_handle_t *>(m_sidebandStream));
m_sidebandStream = nullptr;
}
// Close any fences left for this layer
while (!m_releaseFences.empty()) {
close(m_releaseFences.front());
m_releaseFences.pop();
}
#ifdef OVERLAY
if (m_overlay != nullptr) {
m_overlay.reset(); // release memory
m_overlay = nullptr;
}
#endif
}
HWC2::Error HWCLayer::SetLayerBlendMode(HWC2::BlendMode mode)
{
m_blendMode = mode;
return HWC2::Error::None;
}
bool HWCLayer::IsDimLayer() const
{
HWC_CHK_RETURN((m_layerBuffer.buffer == nullptr) && (GetClientRequested() != HWC2::Composition::Sideband), true);
return false;
}
HWC2::Error HWCLayer::SetLayerBuffer(buffer_handle_t buffer, int32_t acquireFence)
{
ALOGV("Setting acquireFence to %d for layer %" PRIu64, acquireFence, m_id);
m_layerBuffer.buffer = buffer;
m_layerBuffer.fenceId = acquireFence;
m_layerBuffer.releaseFenceFd = HWC_INVALID_FENCE_ID;
return HWC2::Error::None;
}
HWC2::Error HWCLayer::SetLayerBufferReleaseFence(int32_t releaseFence)
{
if (m_layerBuffer.releaseFenceFd != HWC_INVALID_FENCE_ID) {
ALOGI("releaseFenceFd was not init before SetLayerBufferReleaseFence");
}
m_layerBuffer.releaseFenceFd = releaseFence;
return HWC2::Error::None;
}
const HWCBuffer& HWCLayer::GetLayerBuffer() const
{
return m_layerBuffer;
}
HWC2::Error HWCLayer::SetLayerColor(hwc_color_t color)
{
m_color = color;
return HWC2::Error::None;
}
HWC2::Error HWCLayer::SetLayerCompositionType(HWC2::Composition type)
{
m_clientRequested = type;
switch (m_clientRequested) {
case HWC2::Composition::Client:
break;
case HWC2::Composition::Device:
break;
case HWC2::Composition::SolidColor:
break;
case HWC2::Composition::Cursor:
break;
case HWC2::Composition::Invalid:
return HWC2::Error::BadParameter;
default:
return HWC2::Error::Unsupported;
}
return HWC2::Error::None;
}
HWC2::Error HWCLayer::SetLayerDataspace(android_dataspace_t dataspace)
{
UNUSED(dataspace);
return HWC2::Error::None;
}
HWC2::Error HWCLayer::SetLayerDisplayFrame(hwc_rect_t frame)
{
m_displayFrame = frame;
return HWC2::Error::None;
}
const hwc_rect_t& HWCLayer::GetDisplayFrame() const
{
return m_displayFrame;
}
HWC2::Error HWCLayer::SetLayerPlaneAlpha(float alpha)
{
m_planeAlpha = static_cast<uint8_t>(std::round(255.0f * alpha));
return HWC2::Error::None;
}
HWC2::Error HWCLayer::SetLayerSourceCrop(hwc_frect_t crop)
{
SetRect(crop, m_sourceCrop);
return HWC2::Error::None;
}
const hwc_rect_t& HWCLayer::GetLayerSourceCrop() const
{
return m_sourceCrop;
}
HWC2::Error HWCLayer::SetLayerSidebandStream(const native_handle_t *stream)
{
// sideband stream which type is native_handle_t has no fd
// only has integers
HWC_CHK_RETURN((stream == nullptr), HWC2::Error::BadParameter, ALOGE("SetLayerSidebandStream stream is null"));
if (m_sidebandStream != nullptr) {
if ((stream->numFds == m_sidebandStream->numFds) &&
(stream->numInts == m_sidebandStream->numInts)) {
// native handle has the same fields, just copy data
if (stream->numFds > NATIVE_HANDLE_MAX_FDS || stream->numInts > NATIVE_HANDLE_MAX_INTS) {
ALOGE("numFds:%d or numInts:%d is too large", stream->numFds, stream->numInts);
return HWC2::Error::BadParameter;
}
size_t size = (stream->numFds + stream->numInts) * sizeof(int);
errno_t ret = memcpy_s(static_cast<void *>(const_cast<int *>(m_sidebandStream->data)), size,
static_cast<const void *>(stream->data), size);
HWC_CHK_RETURN((ret != EOK), HWC2::Error::NotValidated, ALOGE("memcpy SetLayerSidebandStream failed"));
return HWC2::Error::None;
} else {
// delete prev handle to recreate native handle
native_handle_close(m_sidebandStream);
native_handle_delete(const_cast<native_handle_t *>(m_sidebandStream));
}
}
m_sidebandStream = native_handle_clone(stream);
return HWC2::Error::None;
}
const native_handle_t* HWCLayer::GetLayerSidebandStream() const
{
return m_sidebandStream;
}
HWC2::Error HWCLayer::SetLayerSurfaceDamage(hwc_region_t damage)
{
UNUSED(damage);
return HWC2::Error::None;
}
HWC2::Error HWCLayer::SetLayerTransform(HWC2::Transform transform)
{
m_transform = transform;
return HWC2::Error::None;
}
HWC2::Error HWCLayer::SetLayerVisibleRegion(hwc_region_t visibleReg)
{
m_visibleRegion.clear();
for (size_t i = 0; i < visibleReg.numRects; i++) {
hwc_rect_t rect = visibleReg.rects[i];
if ((rect.bottom > 0) || (rect.left > 0) || (rect.right > 0) || (rect.top > 0)) {
m_visible = true;
break;
}
m_visibleRegion.push_back(rect);
}
return HWC2::Error::None;
}
bool HWCLayer::ForceGpuCompose(int &resizeNum, int &videoNum)
{
if (m_clientRequested == HWC2::Composition::Client) {
ALOGI("force gpu compose for request client layer %" PRIu64, m_id);
return true;
}
const private_handle_t *handle = static_cast<const private_handle_t *>(m_layerBuffer.buffer);
// gpu and gfx2d are both ok for dim layer and video layer
if (IsDimLayer() ||
((handle != nullptr) &&
static_cast<bool>(((handle->consumer_usage | handle->producer_usage) &
static_cast<unsigned long long>(GRALLOC_USAGE_PRI_VDP)))) ||
(m_clientRequested == HWC2::Composition::Sideband)) {
return false;
}
if (m_transform != HWC2::Transform::None) {
ALOGI("force gpu compose for unsupport transform %d for layer %" PRIu64, m_transform, m_id);
return true;
}
if ((handle != nullptr) &&
static_cast<bool>(((handle->consumer_usage | handle->producer_usage) &
static_cast<unsigned long long>(GRALLOC_USAGE_PRI_HFBC)))) {
ALOGI("force gpu compose due to unsupport YUV tile for layer %" PRIu64, m_id);
return true;
}
if ((handle != nullptr) && (handle->format == HAL_PIXEL_FORMAT_YV12)) {
ALOGI("force gpu compose due to unsupport format HAL_PIXEL_FORMAT_YV12 for layer %" PRIu64, m_id);
return true;
}
if (UnsupportSizeByGfx2d(resizeNum, videoNum)) {
return true;
}
return false;
}
bool HWCLayer::UnsupportSizeByGfx2d(int &resizeNum, int &videoNum) const
{
const unsigned int cropWidth = static_cast<unsigned int>(m_sourceCrop.right - m_sourceCrop.left);
const unsigned int cropHeight = static_cast<unsigned int>(m_sourceCrop.bottom - m_sourceCrop.top);
const unsigned int dispWidth = static_cast<unsigned int>(m_displayFrame.right - m_displayFrame.left);
const unsigned int dispHeight = static_cast<unsigned int>(m_displayFrame.bottom - m_displayFrame.top);
if (HWCIapiAdapter::GetInstance().CheckLayerSize(cropWidth, cropHeight, dispWidth, dispHeight)) {
ALOGI("force gpu compose due to unsupport size: crop %dx%d, disp %dx%d for layer %" PRIu64,
cropWidth, cropHeight, dispWidth, dispHeight, m_id);
return true;
}
const private_handle_t *handle = static_cast<const private_handle_t *>(m_layerBuffer.buffer);
int32_t val;
bool isAfbc = false;
if (handle != nullptr) {
int ret = gralloc_buffer_attr_read(handle, GRALLOC_BUFFER_ATTR_COMPRESSION, &val);
if (ret != GRALLOC_SUCCESS) {
ALOGE("gralloc_buffer_attr_read failed :%d", ret);
}
isAfbc = (val == COMPRESSION_FLAG_AFBC);
// if layer is compress as afbc, hwc only support format ABGR8888、BGR888、ABGR2101010.
if (isAfbc && handle->format != HAL_PIXEL_FORMAT_RGBA_8888 && handle->format != HAL_PIXEL_FORMAT_RGB_888 &&
handle->format != HAL_PIXEL_FORMAT_RGBA_1010102) {
ALOGI("force gpu compose because it contains afbc Layer with UnExcepted buffer format.");
return true;
}
}
if (((cropWidth != dispWidth) || (cropHeight != dispHeight)) && isAfbc) {
// if this afbc layer should be scaled.
return true;
}
// calculate resize number and video number
if ((handle != nullptr) && (handle->format == HAL_PIXEL_FORMAT_YCrCb_420_SP)) {
// 420SP layer should be considered as a resize layer as well as video layer
resizeNum++;
videoNum++;
} else if ((cropWidth != dispWidth) || (cropHeight != dispHeight) || isAfbc) {
resizeNum++;
}
if ((resizeNum == GFX2D_MAX_RESIZE_NUM) &&
(handle != nullptr) && (handle->format == HAL_PIXEL_FORMAT_RGBA_1010102)) {
ALOGI("force gpu compose because the third resize layer %" PRIu64 " has unsupport format(RGBA1010102)", m_id);
return true;
}
if (HWCIapiAdapter::GetInstance().CheckResizeNum(resizeNum, videoNum)) {
ALOGI("force gpu compose because the number of resize(%d)/video(%d) layers is too many", resizeNum, videoNum);
return true;
}
return false;
}
void HWCLayer::CloseAcquireFence()
{
if (m_layerBuffer.fenceId != HWC_INVALID_FENCE_ID) {
close(m_layerBuffer.fenceId);
m_layerBuffer.fenceId = HWC_INVALID_FENCE_ID;
}
}
void HWCLayer::PushReleaseFence()
{
m_releaseFences.push(m_layerBuffer.releaseFenceFd);
m_layerBuffer.releaseFenceFd = HWC_INVALID_FENCE_ID;
}
int32_t HWCLayer::PopReleaseFence()
{
HWC_CHK_RETURN(m_releaseFences.empty(), HWC_INVALID_FENCE_ID);
auto fence = m_releaseFences.front();
m_releaseFences.pop();
return fence;
}
HWC2::Error HWCLayer::SetLayerZOrder(uint32_t z)
{
if (m_zOrder != z) {
m_zOrder = z;
}
return HWC2::Error::None;
}
void HWCLayer::Dump()
{
const private_handle_t *handle = static_cast<const private_handle_t *>(m_layerBuffer.buffer);
if (handle != nullptr) {
ALOGI("dump layer:%" PRIu64 ", fd=%d, offset=%ld, addr=0x%x, fence=%d, releaseFence=%d popFence:%d",
m_id, handle->fd, handle->offset, handle->addr, m_layerBuffer.fenceId, m_layerBuffer.releaseFenceFd,
m_releaseFences.front());
} else {
ALOGI("dump layer:%" PRIu64 ", handle=nullptr, fence=%d, releaseFence=%d popFence:%d",
m_id, m_layerBuffer.fenceId, m_layerBuffer.releaseFenceFd, m_releaseFences.front());
}
ALOGI(" clientRequested=%d, deviceSelected=%d, alpha=%u, Crop=[%d, %d, %d, %d], display=[%d, %d, %d, %d]",
m_clientRequested, m_deviceSelected, m_planeAlpha,
m_sourceCrop.left, m_sourceCrop.top, m_sourceCrop.right, m_sourceCrop.bottom,
m_displayFrame.left, m_displayFrame.top, m_displayFrame.right, m_displayFrame.bottom);
return;
}
} // namespace android