/* * 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 #include #include #include #include #include #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(source.left); target.top = static_cast(source.top); target.right = static_cast(source.right); target.bottom = static_cast(source.bottom); } static std::atomic 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(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(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(const_cast(m_sidebandStream->data)), size, static_cast(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(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(m_layerBuffer.buffer); // gpu and gfx2d are both ok for dim layer and video layer if (IsDimLayer() || ((handle != nullptr) && static_cast(((handle->consumer_usage | handle->producer_usage) & static_cast(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(((handle->consumer_usage | handle->producer_usage) & static_cast(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(m_sourceCrop.right - m_sourceCrop.left); const unsigned int cropHeight = static_cast(m_sourceCrop.bottom - m_sourceCrop.top); const unsigned int dispWidth = static_cast(m_displayFrame.right - m_displayFrame.left); const unsigned int dispHeight = static_cast(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(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(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