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