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.
1447 lines
56 KiB
1447 lines
56 KiB
/*
|
|
* Copyright (c) Hisilicon Technologies Co., Ltd.. 2016-2019. All rights reserved.
|
|
* Description: On behalf of a display device, hwcomposer is called for composition and sent for display
|
|
* Author: Hisilicon
|
|
* Created: 2016.08.12
|
|
*/
|
|
#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
|
|
#include "HWCDisplay.h"
|
|
#include <cerrno>
|
|
#include <cstdlib>
|
|
#include <sstream>
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/stat.h>
|
|
#include <log/log.h>
|
|
#include <utils/Errors.h>
|
|
#include <utils/threads.h>
|
|
#include <utils/Trace.h>
|
|
#include <cutils/properties.h>
|
|
#include <securec.h>
|
|
#include <linux/fb.h>
|
|
#include "uapi_disp.h"
|
|
|
|
#include "HWCIapiAdapter.h"
|
|
#include "VsyncLoopThread.h"
|
|
namespace android {
|
|
using std::fstream;
|
|
using std::string;
|
|
using std::to_string;
|
|
|
|
static int SyncWait(int fd, int timeout)
|
|
{
|
|
__s32 to = timeout;
|
|
return ioctl(fd, SYNC_IOC_WAIT, &to);
|
|
}
|
|
|
|
static bool IsValidPowerMode(const HWC2::PowerMode mode)
|
|
{
|
|
switch (mode) {
|
|
case HWC2::PowerMode::Off: // Fall-through
|
|
case HWC2::PowerMode::DozeSuspend: // Fall-through
|
|
case HWC2::PowerMode::Doze: // Fall-through
|
|
case HWC2::PowerMode::On:
|
|
ALOGI("get valid power Mode =%d", mode);
|
|
return true;
|
|
default:
|
|
ALOGI("get invalid power Mode =%d", mode);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#ifdef EXT_GFX2D_SUPPORT
|
|
void HWCDisplay::QueryFbReleaseFence(const unsigned int phyAddr, int &fbReleaseFd)
|
|
{
|
|
for (size_t i = 0; i < FENCE_MAP_SIZE; i++) {
|
|
if (phyAddr == m_fbReleaseFenceMap[i].phyAddr) {
|
|
fbReleaseFd = m_fbReleaseFenceMap[i].releaseFenceid;
|
|
// clear fence_map releaseFenceid
|
|
m_fbReleaseFenceMap[i].releaseFenceid = HWC_INVALID_FENCE_ID;
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
void HWCDisplay::AddFbReleaseFence(const unsigned int phyAddr, const int fbReleaseFd)
|
|
{
|
|
for (size_t i = 0; i < FENCE_MAP_SIZE; i++) {
|
|
if (phyAddr == m_fbReleaseFenceMap[i].phyAddr) {
|
|
if (m_fbReleaseFenceMap[i].releaseFenceid != HWC_INVALID_FENCE_ID) {
|
|
ALOGI("last release fence for addr:0X%x maybe not closed", phyAddr);
|
|
}
|
|
m_fbReleaseFenceMap[i].releaseFenceid = fbReleaseFd;
|
|
// must return do not change break
|
|
return;
|
|
}
|
|
}
|
|
|
|
for (size_t i = 0; i < FENCE_MAP_SIZE; i++) {
|
|
if (m_fbReleaseFenceMap[i].phyAddr == HWC_INVALID_PHY_ADDR) {
|
|
m_fbReleaseFenceMap[i].phyAddr = phyAddr;
|
|
m_fbReleaseFenceMap[i].releaseFenceid = fbReleaseFd;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
HWCDisplay::HWCDisplay(const DisplayType type, const hwc2_display_t displayId, const framebuffer_device_t *fbDevice,
|
|
const bool gfx2dCompose, const HWCCallbacks* callback)
|
|
: m_displayType(type),
|
|
m_displayFbDevice(fbDevice),
|
|
m_layerChanges(),
|
|
m_layerRequests(),
|
|
m_displayRequests(static_cast<HWC2::DisplayRequest>(0)),
|
|
m_displayId(displayId),
|
|
m_colorModes(),
|
|
m_displayName(),
|
|
m_powerMode(HWC2::PowerMode::On),
|
|
m_vsyncEnabled(HWC2::Vsync::Invalid),
|
|
m_clientTarget({nullptr, -1, -1}),
|
|
m_outputBuffer({nullptr, -1, -1}),
|
|
m_retireFenceId(-1),
|
|
m_lastRetireFenceId(-1),
|
|
m_layers(),
|
|
m_layerMap(),
|
|
m_hwcCallbacks(callback),
|
|
m_validated(false),
|
|
m_stateMutex(),
|
|
m_displayConfigs(),
|
|
m_activeConfig(0),
|
|
m_activeDisplayConfig({0, 0, 0, 0, 0}),
|
|
m_hwcCompose(gfx2dCompose),
|
|
m_hwcCompress(false),
|
|
m_hwcAsyncCompose(false),
|
|
m_lastIonPhyAddr(0),
|
|
m_composeType(-1),
|
|
m_codeStateFlag(false),
|
|
m_frameBufferFd(-1),
|
|
m_vsyncMutex(),
|
|
m_vsyncCondition(),
|
|
m_freshRate(0),
|
|
m_vsyncCount(0),
|
|
m_supportdirectPresent(false)
|
|
{
|
|
#ifdef EXT_GFX2D_SUPPORT
|
|
for (int i = 0; i < FENCE_MAP_SIZE; i++) {
|
|
m_fbReleaseFenceMap[i].phyAddr = HWC_INVALID_PHY_ADDR;
|
|
m_fbReleaseFenceMap[i].releaseFenceid = HWC_INVALID_FENCE_ID;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
HWCDisplay::HWCDisplay(const DisplayType type, const hwc2_display_t displayId, DisplayConfigInfo& displayConfigInfo)
|
|
: m_displayType(type),
|
|
m_displayFbDevice(nullptr),
|
|
m_layerChanges(),
|
|
m_layerRequests(),
|
|
m_displayRequests(static_cast<HWC2::DisplayRequest>(0)),
|
|
m_displayId(displayId),
|
|
m_colorModes(),
|
|
m_displayName(),
|
|
m_powerMode(HWC2::PowerMode::On),
|
|
m_vsyncEnabled(HWC2::Vsync::Invalid),
|
|
m_clientTarget({nullptr, -1, -1}),
|
|
m_outputBuffer({nullptr, -1, -1}),
|
|
m_retireFenceId(-1),
|
|
m_lastRetireFenceId(-1),
|
|
m_layers(),
|
|
m_layerMap(),
|
|
m_hwcCallbacks(nullptr),
|
|
m_validated(false),
|
|
m_stateMutex(),
|
|
m_displayConfigs(),
|
|
m_activeConfig(0),
|
|
m_activeDisplayConfig(displayConfigInfo),
|
|
m_hwcCompose(true),
|
|
m_hwcCompress(false),
|
|
m_hwcAsyncCompose(false),
|
|
fbCapabilityInfo({}),
|
|
m_lastIonPhyAddr(0),
|
|
m_composeType(-1),
|
|
m_codeStateFlag(false),
|
|
m_frameBufferFd(-1),
|
|
m_vsyncMutex(),
|
|
m_vsyncCondition(),
|
|
m_freshRate(0),
|
|
m_vsyncCount(0),
|
|
m_supportdirectPresent(false)
|
|
{
|
|
m_displayConfigs.emplace(0, displayConfigInfo);
|
|
#ifdef EXT_GFX2D_SUPPORT
|
|
for (int i = 0; i < FENCE_MAP_SIZE; i++) {
|
|
m_fbReleaseFenceMap[i].phyAddr = HWC_INVALID_PHY_ADDR;
|
|
m_fbReleaseFenceMap[i].releaseFenceid = HWC_INVALID_FENCE_ID;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void HWCDisplay::Init()
|
|
{
|
|
if (m_displayFbDevice == nullptr) {
|
|
ALOGE("frame buffer device was not initialized");
|
|
return;
|
|
}
|
|
|
|
HWCIapiAdapter::GetInstance().InitDisplayConfigs(m_displayId, m_displayConfigs, *m_displayFbDevice,
|
|
m_activeConfig);
|
|
m_activeDisplayConfig = m_displayConfigs[m_activeConfig];
|
|
UpdateVirtualScreenByConfig();
|
|
|
|
m_hwcCompress = m_hwcCompose && property_get_bool("ro.vendor.gfx.gfx2d.compress", true);
|
|
|
|
m_supportdirectPresent = property_get_bool("persist.vendor.gfx.hwc.direct_present", false) &&
|
|
m_displayType != DisplayType::DISPLAY_EXTERNAL;
|
|
|
|
if (m_displayType == DisplayType::DISPLAY_PRIMARY || m_displayType == DisplayType::DISPLAY_EXTERNAL) {
|
|
private_module_t *module = reinterpret_cast<private_module_t *>(m_displayFbDevice->common.module);
|
|
if (module == nullptr) {
|
|
ALOGE("fb module was not initialized");
|
|
return;
|
|
}
|
|
int fbDeviceId = HWCIapiAdapter::GetInstance().GetFbDevId(m_displayId);
|
|
m_frameBufferFd = module->framebuffer[fbDeviceId]->fd;
|
|
ALOGI("fbDeviceId:%d, m_displayId:%" PRIu64 ", m_frameBufferFd:%d", fbDeviceId, m_displayId, m_frameBufferFd);
|
|
}
|
|
|
|
// read the ability of fb
|
|
ioctl(m_frameBufferFd, GFBGIOGET_CAPABILITY, &fbCapabilityInfo);
|
|
// only support Hardware Vsync for primary display currently
|
|
if (m_displayType == DisplayType::DISPLAY_PRIMARY) {
|
|
sp<VsyncLoopThread> thread = new VsyncLoopThread(*this);
|
|
thread->run("VsyncLoopThread",
|
|
static_cast<int>(PRIORITY_URGENT_DISPLAY) + static_cast<int>(PRIORITY_MORE_FAVORABLE));
|
|
}
|
|
// get debug property
|
|
m_fenceMonitorDebug = property_get_bool("vendor.gfx.hwc.debug.fence_monitor", false);
|
|
m_fbPixelDebug = property_get_bool("vendor.gfx.hwc.debug.fbbuffer", false);
|
|
|
|
// the below code is about fb1 attach disp1
|
|
if (m_displayType == DisplayType::DISPLAY_PRIMARY) {
|
|
return;
|
|
}
|
|
if (property_get_int32("persist.vendor.disp1.attach.fb", FB_EXTERNAL_ID) != FB_EXTERNAL_CURSOR_ID) {
|
|
return;
|
|
}
|
|
ALOGI("fb1 attach disp1");
|
|
gfbg_disp_channel dispChannelTmp = GFBG_DISP_CHN1;
|
|
if (ioctl(m_frameBufferFd, GFBGIOSET_CURSOR_ATTACH_CHANNEL, &dispChannelTmp) < 0) {
|
|
ALOGE("ioctl GFBGIOSET_CURSOR_ATTACH_CHANNEL failed");
|
|
}
|
|
}
|
|
|
|
HWCDisplay::~HWCDisplay()
|
|
{
|
|
if (m_fbAddr != nullptr) {
|
|
const private_handle_t *fbHandle = static_cast<const private_handle_t *>(m_clientTarget.buffer);
|
|
// framebuffer count
|
|
const size_t fbNum = 3;
|
|
const size_t unmapSize = fbHandle->size * fbNum;
|
|
munmap(m_fbAddr, unmapSize);
|
|
m_fbAddr = nullptr;
|
|
}
|
|
}
|
|
|
|
bool HWCDisplay::CanPresentDirectly() const
|
|
{
|
|
// present layer buffer directly only when ther is only one layer
|
|
if (m_supportdirectPresent && (m_layers.size() == 1)) {
|
|
const HWCLayer* layer = *m_layers.begin();
|
|
const private_handle_t *handle = static_cast<const private_handle_t *>(layer->GetLayerBuffer().buffer);
|
|
// read the compression status of buffer
|
|
int bufferCompressionFlag = -1;
|
|
gralloc_buffer_attr_read(handle, GRALLOC_BUFFER_ATTR_COMPRESSION, &bufferCompressionFlag);
|
|
bool support = ((layer->GetLayerSourceCrop().left == 0) &&
|
|
(layer->GetLayerSourceCrop().top == 0) &&
|
|
(layer->GetLayerSourceCrop().right == static_cast<int>(m_activeDisplayConfig.width)) &&
|
|
(layer->GetLayerSourceCrop().bottom == static_cast<int>(m_activeDisplayConfig.height)) &&
|
|
(layer->GetDisplayFrame().left == 0) &&
|
|
(layer->GetDisplayFrame().top == 0) &&
|
|
(layer->GetDisplayFrame().right == static_cast<int>(m_activeDisplayConfig.width)) &&
|
|
(layer->GetDisplayFrame().bottom == static_cast<int>(m_activeDisplayConfig.height)) &&
|
|
(handle != nullptr) &&
|
|
(handle->format == HAL_PIXEL_FORMAT_RGBA_8888) &&
|
|
(layer->GetClientRequested() != HWC2::Composition::Sideband) &&
|
|
!static_cast<bool>((handle->consumer_usage | handle->producer_usage) &
|
|
static_cast<unsigned long long>(GRALLOC_USAGE_PRI_VDP))) &&
|
|
(bufferCompressionFlag != COMPRESSION_FLAG_AFBC || fbCapabilityInfo.compression.is_support_afbc);
|
|
if (support) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int HWCDisplay::GetComposeType() const
|
|
{
|
|
HWC_CHK_RETURN((m_displayId == HWC_DISPLAY_VIRTUAL), (int)HWC_COMPOSE::HWC_GPU_COMPOSE);
|
|
HWC_CHK_RETURN(property_get_bool(m_lockFb.c_str(), false), (int)HWC_COMPOSE::HWC_GFX2D_COMPOSE);
|
|
HWC_CHK_RETURN((CanPresentDirectly()), (int)HWC_COMPOSE::HWC_DIRECT_PRESENT);
|
|
HWC_CHK_RETURN(!m_hwcCompose, (int)HWC_COMPOSE::HWC_GPU_COMPOSE);
|
|
// num > 7 || num == 0 not support
|
|
if (HWCIapiAdapter::GetInstance().CheckLayerNum(m_layers.size())) {
|
|
ALOGI("force gpu compose because the number of layers is %zu", m_layers.size());
|
|
return (int)HWC_COMPOSE::HWC_GPU_COMPOSE;
|
|
}
|
|
|
|
int resizeNum = 0;
|
|
int videoNum = 0;
|
|
bool allLayerSideband = true;
|
|
for (auto layer = m_layers.cbegin(); layer != m_layers.cend(); ++layer) {
|
|
allLayerSideband = allLayerSideband && (*layer)->GetClientRequested() == HWC2::Composition::Sideband;
|
|
if ((*layer)->ForceGpuCompose(resizeNum, videoNum)) {
|
|
return (int)HWC_COMPOSE::HWC_GPU_COMPOSE;
|
|
}
|
|
}
|
|
|
|
if (allLayerSideband) {
|
|
ALOGI("force gpu compose because all layers are composed with sideband");
|
|
return (int)HWC_COMPOSE::HWC_GPU_COMPOSE;
|
|
}
|
|
return (int)HWC_COMPOSE::HWC_GFX2D_COMPOSE;
|
|
}
|
|
|
|
static string ConvertFormat(int fmt)
|
|
{
|
|
switch (fmt) {
|
|
case HAL_PIXEL_FORMAT_RGBA_8888:
|
|
return "RGBA_8888";
|
|
case HAL_PIXEL_FORMAT_RGBX_8888:
|
|
return "RGBX_8888";
|
|
case HAL_PIXEL_FORMAT_BGRA_8888:
|
|
return "RGBA_8888";
|
|
case HAL_PIXEL_FORMAT_RGB_888:
|
|
return "RGB_888";
|
|
case HAL_PIXEL_FORMAT_RGB_565:
|
|
return "RGB_565";
|
|
case HAL_PIXEL_FORMAT_RGBA_1010102:
|
|
return "RGB_1010102";
|
|
case HAL_PIXEL_FORMAT_RGBA_FP16:
|
|
return "RGB_FP16";
|
|
case HAL_PIXEL_FORMAT_YCbCr_422_I:
|
|
return "YCbCr_422_I";
|
|
case HAL_PIXEL_FORMAT_YV12:
|
|
return "YV12";
|
|
case HAL_PIXEL_FORMAT_YCbCr_420_888:
|
|
return "YCbCr_420_888";
|
|
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
|
|
return "YCrCb_420_SP";
|
|
case HAL_PIXEL_FORMAT_BLOB:
|
|
return "BLOB";
|
|
default:
|
|
return "Unkonwn";
|
|
}
|
|
}
|
|
|
|
void HWCDisplay::CaptureLayerIfNecessary() const
|
|
{
|
|
static int frame = 0;
|
|
const int maxFileNameLen = 100;
|
|
// zero values means that capture all layers, otherwize, capture layer with special id
|
|
int layerId = property_get_int32("vendor.gfx.hwc.capture.layer", -1);
|
|
HWC_CHK_RETURN_NOT_VALUE((layerId < 0));
|
|
|
|
// capture once default
|
|
int frames = property_get_int32("vendor.gfx.hwc.capture.frames", 1);
|
|
// set frame to be zero again after finish capture
|
|
if (++frame > frames) {
|
|
frame = 0;
|
|
property_set("vendor.gfx.hwc.capture.layer", "-1");
|
|
return;
|
|
}
|
|
|
|
void *virAddr = nullptr;
|
|
for (auto layer = m_layers.cbegin(); layer != m_layers.cend(); ++layer) {
|
|
if (layerId != 0 && layerId != static_cast<int>((*layer)->GetId())) {
|
|
continue;
|
|
}
|
|
const private_handle_t *handle = static_cast<const private_handle_t *>((*layer)->GetLayerBuffer().buffer);
|
|
if (handle == nullptr) {
|
|
ALOGI("Layer%02" PRIu64 " has nullptr handle", (*layer)->GetId());
|
|
continue;
|
|
}
|
|
virAddr = handle->base;
|
|
if (virAddr == nullptr) {
|
|
ALOGE("Layer%02" PRIu64 " base has nullptr", (*layer)->GetId());
|
|
continue;
|
|
}
|
|
|
|
char fname[maxFileNameLen] = {0};
|
|
int ret = snprintf_s(fname, maxFileNameLen, maxFileNameLen - 1,
|
|
"/data/hwc_frame%02d_Layer%02" PRIu64 "_%dx%d_%s", frame, (*layer)->GetId(), handle->width,
|
|
handle->height, ConvertFormat(handle->format).c_str());
|
|
HWC_CHK_RETURN_NOT_VALUE((ret < 0), ALOGE("snprintf_s fname failed(0x%x)", ret));
|
|
|
|
FILE *fp = fopen(fname, "wb");
|
|
HWC_CHK_RETURN_NOT_VALUE((fp == nullptr), ALOGE("fopen %s failed", fname));
|
|
|
|
if (fchmod(fileno(fp), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) != 0) {
|
|
ALOGE("fchmod %s failed", fname);
|
|
fclose(fp);
|
|
fp = nullptr;
|
|
return;
|
|
}
|
|
if ((*layer)->GetLayerBuffer().fenceId != HWC_INVALID_FENCE_ID) {
|
|
int err = SyncWait((*layer)->GetLayerBuffer().fenceId, HWC_FENCE_TIMEOUT);
|
|
if (err < 0 && errno == ETIME) {
|
|
ALOGE("HWC sync_wait for over 3s %s,%d", __FUNCTION__, __LINE__);
|
|
}
|
|
}
|
|
size_t hasWriten = fwrite(virAddr, sizeof(unsigned char), handle->size, fp);
|
|
|
|
ALOGI("fwrite %zu bytes from virtual addr into %s with bytes_stride:%d",
|
|
hasWriten, fname, handle->bytes_stride);
|
|
fclose(fp);
|
|
}
|
|
}
|
|
|
|
void HWCDisplay::WaitIfNecessary() const
|
|
{
|
|
if (property_get_bool("vendor.gfx.hwc.wait.fence", false)) {
|
|
int64_t start = systemTime(SYSTEM_TIME_MONOTONIC) / 1000LL;
|
|
SyncWait(m_clientTarget.fenceId, HWC_FENCE_TIMEOUT);
|
|
ALOGE("sync_wait clientTarget fence:%d for %" PRId64 " us", m_clientTarget.fenceId,
|
|
systemTime(SYSTEM_TIME_MONOTONIC) / 1000 - start);
|
|
}
|
|
|
|
int32_t moreTime = property_get_int32("vendor.gfx.hwc.wait", 0);
|
|
if (moreTime > 0) {
|
|
usleep(moreTime);
|
|
ALOGE("wait moreTime %d", moreTime);
|
|
}
|
|
}
|
|
|
|
void HWCDisplay::HwcMediaFresh()
|
|
{
|
|
// Set Sideband Position
|
|
int zorder;
|
|
if (HWCIapiAdapter::GetInstance().GetFbDevId(m_displayId) == FB_PRIMARY_ID) {
|
|
zorder = 0;
|
|
} else {
|
|
zorder = INT_MIN; // don't support zorder for UAPI_DISPLAY1
|
|
}
|
|
for (auto layer = m_layers.cbegin(); layer != m_layers.cend(); ++layer) {
|
|
// set sideband window position
|
|
if ((*layer)->GetDeviceSelected() == HWC2::Composition::Sideband) {
|
|
const native_handle_t *sideband = (*layer)->GetLayerSidebandStream();
|
|
const uint16_t absZorderOffset = 1;
|
|
if (sideband != nullptr) {
|
|
HWCIapiAdapter::GetInstance().SetVoWindowPosition(*sideband, (*layer)->GetDisplayFrame(),
|
|
zorder, (*layer)->GetLayerZOrder() + absZorderOffset);
|
|
zorder++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int HWCDisplay::HwcDirectFresh()
|
|
{
|
|
HWCLayer* layer = *m_layers.begin();
|
|
// record last fb lease fence;
|
|
m_lastRetireFenceId = m_retireFenceId;
|
|
m_retireFenceId = HWC_INVALID_FENCE_ID;
|
|
HWC_CHK_RETURN((layer == nullptr), HWC_FAILURE, ALOGE("HwcDirectFresh layer is null"));
|
|
HWCBuffer &buffer = const_cast<HWCBuffer &>(layer->GetLayerBuffer());
|
|
AddFenceToMonitor(buffer.fenceId, FENCE_TYPE_ENUM::FENCE_DIRECT_ACQUIRE, layer->GetId());
|
|
HWCIapiAdapter::GetInstance().FreshDirect(m_frameBufferFd, buffer);
|
|
AddFenceToMonitor(buffer.releaseFenceFd, FENCE_TYPE_ENUM::FENCE_DIRECT_RELEASE, layer->GetId());
|
|
return HWC_SUCCESS;
|
|
}
|
|
|
|
int HWCDisplay::HwcFbFresh()
|
|
{
|
|
HWC_CHK_RETURN((m_frameBufferFd < 0), HWC_FAILURE, ALOGE("HwcFbFresh fb fd is invalid: %d", m_frameBufferFd));
|
|
const private_handle_t *fbHandle = static_cast<const private_handle_t *>(m_clientTarget.buffer);
|
|
HWC_CHK_RETURN((fbHandle == nullptr), HWC_FAILURE, ALOGE("HwcFbFreshfbHandle is null"));
|
|
|
|
// capture layer buffer or wait for debug
|
|
CaptureLayerIfNecessary();
|
|
WaitIfNecessary();
|
|
|
|
if (m_composeType != (int)HWC_COMPOSE::HWC_GPU_COMPOSE) {
|
|
// if gfx2d compose, mark it. so gpu will know the compose switch and do global switch
|
|
int val = 1;
|
|
gralloc_buffer_attr_write(const_cast<private_handle_t *>(fbHandle), GRALLOC_BUFFER_ATTR_COMPOSE, &val);
|
|
}
|
|
|
|
// don't fresh fb when no swap buffer
|
|
if (m_lastIonPhyAddr == fbHandle->addr) {
|
|
if (m_clientTarget.fenceId != HWC_INVALID_FENCE_ID) {
|
|
ALOGE("repeat frame should not have valid acquire fence");
|
|
}
|
|
ALOGI("repeat frame ion_phy=0x%x composeType=%d", fbHandle->addr, m_composeType);
|
|
m_lastRetireFenceId = HWC_INVALID_FENCE_ID;
|
|
return HWC_SUCCESS;
|
|
}
|
|
|
|
if (m_composeType == (int)HWC_COMPOSE::HWC_GFX2D_COMPOSE) {
|
|
// close frame buffer acquire fence for gfx compose
|
|
if (m_clientTarget.fenceId != HWC_INVALID_FENCE_ID) {
|
|
close(m_clientTarget.fenceId);
|
|
}
|
|
// switch frame buffer release fence of gfx compose to be acquire fence of fresh fb
|
|
if (m_hwcAsyncCompose) {
|
|
m_clientTarget.fenceId = m_clientTarget.releaseFenceFd;
|
|
} else {
|
|
m_clientTarget.fenceId = HWC_INVALID_FENCE_ID;
|
|
}
|
|
}
|
|
m_clientTarget.releaseFenceFd = HWC_INVALID_FENCE_ID;
|
|
AddFenceToMonitor(m_clientTarget.fenceId, FENCE_TYPE_ENUM::FENCE_FB_ACQUIRE, 0);
|
|
HWCIapiAdapter::GetInstance().FreshFb(m_frameBufferFd, m_clientTarget, m_composeType, m_hwcCompress,
|
|
m_displayType != DisplayType::DISPLAY_PRIMARY);
|
|
m_lastIonPhyAddr = fbHandle->addr;
|
|
m_lastRetireFenceId = m_retireFenceId;
|
|
if (m_clientTarget.releaseFenceFd != HWC_INVALID_FENCE_ID) {
|
|
m_retireFenceId = m_clientTarget.releaseFenceFd;
|
|
#ifdef EXT_GFX2D_SUPPORT
|
|
int s32HWCReleaseFenceFd = dup(m_clientTarget.releaseFenceFd);
|
|
AddFbReleaseFence(fbHandle->addr, s32HWCReleaseFenceFd);
|
|
#endif
|
|
m_clientTarget.releaseFenceFd = HWC_INVALID_FENCE_ID;
|
|
} else {
|
|
m_retireFenceId = HWC_INVALID_FENCE_ID;
|
|
#ifdef EXT_GFX2D_SUPPORT
|
|
AddFbReleaseFence(fbHandle->addr, HWC_INVALID_FENCE_ID);
|
|
#endif
|
|
}
|
|
return HWC_SUCCESS;
|
|
}
|
|
|
|
uint32_t HWCDisplay::ReadFbPixel(private_handle_t &fbHandle, const int x, const int y)
|
|
{
|
|
const int fbNum = 3;
|
|
const int pixelBytes = 4;
|
|
int stride = fbHandle.bytes_stride;
|
|
if (m_fbAddr == nullptr) {
|
|
m_fbAddr = mmap(nullptr, fbHandle.size * fbNum, PROT_READ, MAP_SHARED, m_frameBufferFd, 0);
|
|
}
|
|
HWC_CHK_RETURN((m_fbAddr == nullptr), HWC_SUCCESS, ALOGD("ReadFbPixel m_fbAddr null"));
|
|
unsigned char *addr = static_cast<unsigned char *>(m_fbAddr) + fbHandle.offset;
|
|
int pixelPostion = y * stride + x * pixelBytes;
|
|
if ((pixelPostion + pixelBytes) > fbHandle.size) {
|
|
ALOGE("the pixel is outside");
|
|
return 0;
|
|
}
|
|
auto data = reinterpret_cast<uint32_t *>(addr + pixelPostion);
|
|
return *data;
|
|
}
|
|
|
|
void HWCDisplay::SaveFbRgbFile(const std::string &filename, const private_handle_t &fbHandle)
|
|
{
|
|
const int fbNum = 3;
|
|
if (m_fbAddr == nullptr) {
|
|
m_fbAddr = mmap(nullptr, fbHandle.size * fbNum, PROT_READ, MAP_SHARED, m_frameBufferFd, 0);
|
|
}
|
|
HWC_CHK_RETURN_NOT_VALUE((m_fbAddr == nullptr), ALOGE("SaveFbRgbFile m_fbAddr null"));
|
|
unsigned char *addr = static_cast<unsigned char *>(m_fbAddr) + fbHandle.offset;
|
|
int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
|
if (fd < 0) {
|
|
ALOGE("saveRgbFile fopen %s failed errno:%d ", filename.c_str(), errno);
|
|
return;
|
|
}
|
|
int hasWriten = write(fd, addr, fbHandle.size);
|
|
ALOGI("saveRgbFile %s has write %d size %d", filename.c_str(), hasWriten, fbHandle.size);
|
|
close(fd);
|
|
}
|
|
|
|
void HWCDisplay::CheckFbPresentPixel()
|
|
{
|
|
static uint32_t testCount = 0;
|
|
HWC_CHK_RETURN_NOT_VALUE((m_frameBufferFd < 0), ALOGE("chk pixel fb fd is invalid: %d", m_frameBufferFd));
|
|
struct private_handle_t *fbHandle = (struct private_handle_t *)(m_clientTarget.buffer);
|
|
HWC_CHK_RETURN_NOT_VALUE((fbHandle == nullptr), ALOGE("HwcFbFreshfbHandle is null"));
|
|
const int x = property_get_int32("vendor.gfx.hwc.debug.fbbuffer.x", -1);
|
|
const int y = property_get_int32("vendor.gfx.hwc.debug.fbbuffer.y", -1);
|
|
if ((x < 0) || (y < 0) || (x >= static_cast<int>(m_displayFbDevice->width)) ||
|
|
(y >= static_cast<int>(m_displayFbDevice->height))) {
|
|
return;
|
|
}
|
|
SyncWait(m_clientTarget.fenceId, HWC_FENCE_TIMEOUT);
|
|
char value[PROPERTY_VALUE_MAX] = {0};
|
|
property_get("vendor.gfx.hwc.debug.fbbuffer.color", value, nullptr);
|
|
uint32_t color = strtoul(value, nullptr, HWC_HEX);
|
|
uint32_t fbColor = ReadFbPixel(*fbHandle, x, y);
|
|
ALOGI("testCount %d x: %d y: %d wantColor %x, fbColor %x offset: %lu fbHandle->bytes_stride %d",
|
|
testCount, x, y, color, fbColor, fbHandle->offset, fbHandle->bytes_stride);
|
|
// check the pixel
|
|
if (fbColor != color) {
|
|
ALOGE("has detect the unnormal pixel testCount %d", testCount);
|
|
testCount++;
|
|
// save fb buffer
|
|
std::stringstream os;
|
|
os << "/data/hwc_fbbuffer_" << testCount << ".bmp";
|
|
const std::string fname = os.str();
|
|
SaveFbRgbFile(fname, *fbHandle);
|
|
ALOGE("has detect the abnormal pixel sleep 3");
|
|
sleep(HWC_PIXEL_CHECK_TIMEOUT);
|
|
}
|
|
}
|
|
|
|
void HWCDisplay::WaitFenceBeforeSyncCompose() const
|
|
{
|
|
for (auto layer = m_layers.cbegin(); layer != m_layers.cend(); ++layer) {
|
|
if ((*layer)->GetLayerBuffer().fenceId >= 0) {
|
|
int64_t syncWaitStart = systemTime(SYSTEM_TIME_MONOTONIC) / TIME_CONVERSION_LEVEL;
|
|
int err = SyncWait((*layer)->GetLayerBuffer().fenceId, HWC_FENCE_TIMEOUT);
|
|
if (err < 0 && errno == ETIME) {
|
|
ALOGE("sync_wait layer(%" PRIu64 ") for over 3s", (*layer)->GetId());
|
|
}
|
|
if (m_codeStateFlag) {
|
|
ALOGD("sync_wait layer(%" PRIu64 ") fence for %" PRId64 "us", (*layer)->GetId(),
|
|
systemTime(SYSTEM_TIME_MONOTONIC) / TIME_CONVERSION_LEVEL - syncWaitStart);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_clientTarget.fenceId != HWC_INVALID_FENCE_ID) {
|
|
int64_t syncWaitStart = systemTime(SYSTEM_TIME_MONOTONIC) / TIME_CONVERSION_LEVEL;
|
|
int err = SyncWait(m_clientTarget.fenceId, HWC_FENCE_TIMEOUT);
|
|
if (err < 0 && errno == ETIME) {
|
|
ALOGE("sync_wait fb fence for over 3 seconds");
|
|
}
|
|
if (m_codeStateFlag) {
|
|
ALOGD("sync_wait fb fence for %" PRId64 "us",
|
|
systemTime(SYSTEM_TIME_MONOTONIC) / TIME_CONVERSION_LEVEL - syncWaitStart);
|
|
}
|
|
} else {
|
|
// framebuffer handle
|
|
const private_handle_t *handle = static_cast<const private_handle_t *>(m_clientTarget.buffer);
|
|
if (handle != nullptr) {
|
|
ALOGE("invalide fence fb(-1) (addr=0x%x) , do not wait", handle->addr);
|
|
}
|
|
}
|
|
}
|
|
|
|
int HWCDisplay::HwcGfx2DComposer()
|
|
{
|
|
ATRACE_CALL();
|
|
const unsigned int layerNum = m_layers.size();
|
|
HWC_CHK_RETURN((m_displayId == HWC_DISPLAY_VIRTUAL), HWC_FAILURE, ALOGD("virtual screen not hwc"));
|
|
HWC_CHK_RETURN((m_frameBufferFd < 0), HWC_FAILURE, ALOGE("HwcGfx2DComposer fb fd is invalid:%d", m_frameBufferFd));
|
|
HWC_CHK_RETURN((layerNum <= 0), HWC_FAILURE, ALOGE("HWC hwcGfx2DComposer have no layer to compose"));
|
|
int layerReleaseFences[layerNum];
|
|
errno_t eok = memset_s(layerReleaseFences, layerNum * sizeof(int), 0, layerNum * sizeof(int));
|
|
HWC_CHK_RETURN((eok != EOK), HWC_FAILURE, ALOGE("layerReleaseFences memset_s failed"));
|
|
HWC_CHK_RETURN(m_powerMode != HWC2::PowerMode::On, HWC_FAILURE,
|
|
ALOGD("powermode is not on"));
|
|
int fbRealeaseFence;
|
|
unsigned int i = 0;
|
|
|
|
if (m_hwcCompress) {
|
|
char displayMode[PROPERTY_VALUE_MAX] = { 0 };
|
|
string displayMode2D = "2D";
|
|
property_get("vendor.display.format.mode", displayMode, "2D");
|
|
if (strncmp(displayMode, displayMode2D.c_str(), displayMode2D.length()) != 0) {
|
|
m_hwcCompress = false; // the frame compress
|
|
}
|
|
}
|
|
// Step 1. prepare to allocate memory which is used to record the gfx2d compose info
|
|
int ret = HWCIapiAdapter::GetInstance().PrepareGfx2dBasicArg(layerNum);
|
|
if (ret != HWC_SUCCESS) {
|
|
HWCIapiAdapter::GetInstance().PostGfx2dCompose();
|
|
return ret;
|
|
}
|
|
// Step 2. prepare input(layer info) for gfx2d compose
|
|
for (auto layer = m_layers.cbegin(); layer != m_layers.cend(); ++layer) {
|
|
if ((*layer)->GetDeviceSelected() == HWC2::Composition::Client) {
|
|
ALOGE("Error: gfx2dCompose have gpu layer ");
|
|
HWCIapiAdapter::GetInstance().PostGfx2dCompose();
|
|
return ret;
|
|
}
|
|
ret = HWCIapiAdapter::GetInstance().PrepareGfx2dLayerArg(*(*layer), i, m_displayFbDevice->width,
|
|
m_displayFbDevice->height, m_hwcAsyncCompose);
|
|
if (ret != HWC_SUCCESS) {
|
|
HWCIapiAdapter::GetInstance().PostGfx2dCompose();
|
|
return ret;
|
|
}
|
|
i++;
|
|
}
|
|
// Step 3. prepare ouput(framebuffer info) for gfx2d compose
|
|
ret = HWCIapiAdapter::GetInstance().PrepareGfx2dDestArg(m_frameBufferFd, m_clientTarget, m_hwcCompress);
|
|
if (ret != HWC_SUCCESS) {
|
|
HWCIapiAdapter::GetInstance().PostGfx2dCompose();
|
|
return ret;
|
|
}
|
|
// Step 4. wait fb and layer acquire fence for async compose, and close them later to avoid fd leak
|
|
if (!m_hwcAsyncCompose) {
|
|
WaitFenceBeforeSyncCompose();
|
|
}
|
|
// Step 5. process gfx2d compose
|
|
ret = HWCIapiAdapter::GetInstance().Gfx2dCompose(layerReleaseFences, layerNum, fbRealeaseFence, m_hwcAsyncCompose);
|
|
if (ret != HWC_SUCCESS) {
|
|
HWCIapiAdapter::GetInstance().PostGfx2dCompose();
|
|
return ret;
|
|
}
|
|
i = 0;
|
|
for (auto layer = m_layers.cbegin(); layer != m_layers.cend(); ++layer) {
|
|
if ((*layer)->GetDeviceSelected() != HWC2::Composition::Device) {
|
|
if (layerReleaseFences[i] != HWC_INVALID_FENCE_ID) {
|
|
close(layerReleaseFences[i]);
|
|
}
|
|
layerReleaseFences[i] = HWC_INVALID_FENCE_ID;
|
|
}
|
|
(*layer)->SetLayerBufferReleaseFence(layerReleaseFences[i]);
|
|
AddFenceToMonitor((*layer)->GetLayerBuffer().fenceId, FENCE_TYPE_ENUM::FENCE_FB_ACQUIRE, (*layer)->GetId());
|
|
AddFenceToMonitor(layerReleaseFences[i], FENCE_TYPE_ENUM::FENCE_FB_ACQUIRE, (*layer)->GetId());
|
|
i++;
|
|
}
|
|
m_clientTarget.releaseFenceFd = fbRealeaseFence;
|
|
// Step 6. free the memory allocated in the step 1.
|
|
HWCIapiAdapter::GetInstance().PostGfx2dCompose();
|
|
return ret;
|
|
}
|
|
|
|
HWCLayer* HWCDisplay::GetHWCLayer(hwc2_layer_t layer)
|
|
{
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
const auto mapLayer = m_layerMap.find(layer);
|
|
if (mapLayer == m_layerMap.end()) {
|
|
ALOGE("[%" PRIu64 "] getLayer(%" PRIu64 ") failed: no such layer", m_displayId, layer);
|
|
return nullptr;
|
|
} else {
|
|
return mapLayer->second;
|
|
}
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::AcceptDisplayChanges(void)
|
|
{
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
HWC_CHK_RETURN((!m_validated && !m_layers.empty()), HWC2::Error::NotValidated,
|
|
ALOGD("hwc accept display changes validate=%d", m_validated));
|
|
|
|
HWC_CHK_RETURN(m_layerChanges.empty(), HWC2::Error::None);
|
|
for (auto change = m_layerChanges.cbegin(); change != m_layerChanges.cend(); ++change) {
|
|
auto hwcLayer = m_layerMap[(*change).first];
|
|
auto composition = (*change).second;
|
|
|
|
if (hwcLayer == nullptr) {
|
|
ALOGI("Null layer in HWCDisplay::AcceptDisplayChanges.");
|
|
} else {
|
|
hwcLayer->UpdateClientCompositionType(composition);
|
|
}
|
|
}
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::CreateLayer(hwc2_layer_t *outLayerId)
|
|
{
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
HWC_CHK_RETURN((outLayerId == nullptr), HWC2::Error::BadParameter,
|
|
ALOGE("HWC:createLayer get null input"));
|
|
|
|
const auto layer = *m_layers.emplace(new HWCLayer(m_displayId));
|
|
m_layerMap.emplace(std::make_pair(layer->GetId(), layer));
|
|
*outLayerId = layer->GetId();
|
|
ALOGV("[%" PRIu64 "] created layer %" PRIu64, m_displayId, *outLayerId);
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::DestroyLayer(hwc2_layer_t layerId)
|
|
{
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
const auto mapLayer = m_layerMap.find(layerId);
|
|
HWC_CHK_RETURN((mapLayer == m_layerMap.end()), HWC2::Error::BadLayer,
|
|
ALOGE("[%" PRIu64 "] destroyLayer(%" PRIu64 ") failed: no such layer", m_displayId, layerId));
|
|
|
|
auto layer = mapLayer->second;
|
|
m_layerMap.erase(mapLayer);
|
|
auto zRange = m_layers.equal_range(layer);
|
|
for (auto current = zRange.first; current != zRange.second; ++current) {
|
|
if (*current == layer) {
|
|
current = m_layers.erase(current);
|
|
delete layer;
|
|
break;
|
|
}
|
|
}
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::GetActiveConfig(hwc2_config_t *outConfig)
|
|
{
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
HWC_CHK_RETURN((outConfig == nullptr), HWC2::Error::BadParameter,
|
|
ALOGE("getActiveConfig outConfig is null"));
|
|
|
|
*outConfig = m_activeConfig;
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::GetChangedCompositionTypes(uint32_t *outNumElements, hwc2_layer_t *outLayers,
|
|
int32_t *outTypes)
|
|
{
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
HWC_CHK_RETURN((m_layers.empty()), HWC2::Error::None, ALOGI("GetChangedCompositionTypes with no layer"));
|
|
HWC_CHK_RETURN((outNumElements == nullptr), HWC2::Error::BadParameter,
|
|
ALOGE("HWC:getChangedCompositionTypes get null input"));
|
|
HWC_CHK_RETURN(!m_validated, HWC2::Error::NotValidated, ALOGW("Display is not validated"));
|
|
|
|
*outNumElements = uint32_t(m_layerChanges.size());
|
|
HWC_CHK_RETURN(m_layerChanges.empty(), HWC2::Error::None);
|
|
if (outLayers != nullptr && outTypes != nullptr) {
|
|
uint32_t i = 0;
|
|
for (auto change = m_layerChanges.cbegin(); change != m_layerChanges.cend(); ++change) {
|
|
if (i < *outNumElements) {
|
|
outLayers[i] = (*change).first;
|
|
outTypes[i] = int32_t((*change).second);
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::GetClientTargetSupport(uint32_t width, uint32_t height, int32_t format,
|
|
int32_t dataSpace)
|
|
{
|
|
UNUSED(width);
|
|
UNUSED(height);
|
|
UNUSED(format);
|
|
UNUSED(dataSpace);
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::GetColorModes(uint32_t *outNumModes, int32_t *outModes)
|
|
{
|
|
HWC_CHK_RETURN((outNumModes == nullptr), HWC2::Error::BadParameter, ALOGE("GetColorModes outNumModes is nullptr"));
|
|
*outNumModes = 0;
|
|
if (outModes != nullptr) {
|
|
*outModes = 0;
|
|
}
|
|
return HWC2::Error::Unsupported;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::GetDisplayAttribute(hwc2_config_t config, HWC2::Attribute attribute, int32_t *outValue)
|
|
{
|
|
UNUSED(config);
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
HWC_CHK_RETURN((outValue == nullptr), HWC2::Error::BadParameter,
|
|
ALOGE("GetDisplayAttribute with null input"));
|
|
|
|
const auto configInfo = m_displayConfigs.find(config);
|
|
HWC_CHK_RETURN((configInfo == m_displayConfigs.end()), HWC2::Error::BadParameter,
|
|
ALOGE("GetDisplayAttribute failed for config:%d", config));
|
|
DisplayConfigInfo displayConfig = configInfo->second;
|
|
|
|
const uint32_t yDpiUnit = 1000;
|
|
switch (attribute) {
|
|
case HWC2::Attribute::VsyncPeriod:
|
|
*outValue = int32_t(1e9 / displayConfig.fps);
|
|
ALOGI("GetDisplayAttribute *outValue:%d", *outValue);
|
|
break;
|
|
|
|
case HWC2::Attribute::Width:
|
|
*outValue = displayConfig.width;
|
|
ALOGI("GetDisplayAttribute Width *outValue:%d", *outValue);
|
|
break;
|
|
|
|
case HWC2::Attribute::Height:
|
|
*outValue = displayConfig.height;
|
|
ALOGI("GetDisplayAttribute Height *outValue:%d", *outValue);
|
|
break;
|
|
|
|
case HWC2::Attribute::DpiX:
|
|
*outValue = int32_t(displayConfig.xDpi * yDpiUnit);
|
|
ALOGI("GetDisplayAttribute DpiX *outValue:%d", *outValue);
|
|
break;
|
|
|
|
case HWC2::Attribute::DpiY:
|
|
*outValue = int32_t(displayConfig.yDpi * yDpiUnit);
|
|
ALOGI("GetDisplayAttribute DpiY *outValue:%d", *outValue);
|
|
break;
|
|
|
|
default:
|
|
ALOGE("Unknown display attribute %u", attribute);
|
|
break;
|
|
}
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::GetDisplayConfigs(uint32_t *outNumConfigs, hwc2_config_t *outConfigs)
|
|
{
|
|
HWC_CHK_RETURN((outNumConfigs == nullptr), HWC2::Error::BadParameter,
|
|
ALOGE("HWC:getDisplayConfigs get null input"));
|
|
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
if (outConfigs == nullptr) {
|
|
*outNumConfigs = m_displayConfigs.size();
|
|
ALOGI("GetDisplayConfigs outNumConfigs:%d", *outNumConfigs);
|
|
} else {
|
|
uint32_t i = 0;
|
|
for (auto config = m_displayConfigs.cbegin(); config != m_displayConfigs.cend(); ++config) {
|
|
if (i < *outNumConfigs) {
|
|
outConfigs[i] = (*config).first;
|
|
ALOGI("GetDisplayConfigs config:%d", outConfigs[i]);
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::GetDisplayName(uint32_t *outSize, char *outName)
|
|
{
|
|
HWC_CHK_RETURN((outSize == nullptr), HWC2::Error::BadParameter, ALOGE("GetDisplayName outSize is null"));
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
const uint32_t oSize = 32;
|
|
if (outName == nullptr) {
|
|
*outSize = oSize;
|
|
} else {
|
|
std::string name;
|
|
switch (m_displayId) {
|
|
case HWC_DISPLAY_PRIMARY:
|
|
name = "Primary Display";
|
|
break;
|
|
case HWC_DISPLAY_EXTERNAL:
|
|
name = "External Display";
|
|
break;
|
|
case HWC_DISPLAY_VIRTUAL:
|
|
name = "Virtual Display";
|
|
break;
|
|
default:
|
|
name = "Unknown";
|
|
break;
|
|
}
|
|
errno_t ret = strncpy_s(outName, oSize + 1, name.c_str(), name.size());
|
|
HWC_CHK_RETURN((ret != EOK), HWC2::Error::NotValidated,
|
|
ALOGE("ERR :%s LINE %d | GetDisplayName strncpy_s ret(%x)", __FUNCTION__, __LINE__, ret));
|
|
*outSize = uint32_t(name.size());
|
|
}
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::GetDisplayRequests(int32_t *outDisplayRequests, uint32_t *outNumElements,
|
|
hwc2_layer_t *outLayers, int32_t *outLayerRequests)
|
|
{
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
HWC_CHK_RETURN(m_layers.empty(), HWC2::Error::None);
|
|
HWC_CHK_RETURN((outDisplayRequests == nullptr || outNumElements == nullptr), HWC2::Error::BadParameter,
|
|
ALOGE("HWC:getDisplayRequests get null input"));
|
|
HWC_CHK_RETURN(!m_validated, HWC2::Error::NotValidated, ALOGW("Display is not validated"));
|
|
|
|
*outDisplayRequests = int32_t(m_displayRequests);
|
|
*outNumElements = uint32_t(m_layerRequests.size());
|
|
HWC_CHK_RETURN(m_layerRequests.empty(), HWC2::Error::None);
|
|
if (outLayers != nullptr && outLayerRequests != nullptr) {
|
|
uint32_t i = 0;
|
|
for (auto request = m_layerRequests.cbegin(); request != m_layerRequests.cend(); ++request) {
|
|
if (i < *outNumElements) {
|
|
outLayers[i] = (*request).first;
|
|
outLayerRequests[i] = int32_t((*request).second);
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::GetDisplayType(int32_t *outType)
|
|
{
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
HWC_CHK_RETURN((outType == nullptr), HWC2::Error::BadParameter, ALOGE("GetDisplayType outType is null"));
|
|
if (m_displayId == HWC_DISPLAY_VIRTUAL) {
|
|
*outType = HWC2_DISPLAY_TYPE_VIRTUAL;
|
|
} else {
|
|
*outType = HWC2_DISPLAY_TYPE_PHYSICAL;
|
|
}
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::GetReleaseFences(uint32_t *outNumElements, hwc2_layer_t *outLayers, int32_t *outFences)
|
|
{
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
HWC_CHK_RETURN(m_layers.empty(), HWC2::Error::None);
|
|
HWC_CHK_RETURN((outNumElements == nullptr), HWC2::Error::BadParameter,
|
|
ALOGE("HWC:GetReleaseFences get null input"));
|
|
*outNumElements = uint32_t(m_layers.size());
|
|
if (outLayers != nullptr && outFences != nullptr) {
|
|
uint32_t i = 0;
|
|
for (auto layer = m_layers.cbegin(); layer != m_layers.cend(); ++layer) {
|
|
if (i < *outNumElements) {
|
|
outLayers[i] = (*layer)->GetId();
|
|
outFences[i] = (*layer)->PopReleaseFence();
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
int HWCDisplay::GetFrameBufferFd() const
|
|
{
|
|
return m_frameBufferFd;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::SetLayerZOrder(hwc2_layer_t layerId, uint32_t z)
|
|
{
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
const auto mapLayer = m_layerMap.find(layerId);
|
|
HWC_CHK_RETURN((mapLayer == m_layerMap.end()), HWC2::Error::BadLayer,
|
|
ALOGE("[%" PRIu64 "] updateLayerZ failed to find layer", m_displayId));
|
|
|
|
auto layer = mapLayer->second;
|
|
auto zRange = m_layers.equal_range(layer);
|
|
bool layerOnDisplay = false;
|
|
for (auto current = zRange.first; current != zRange.second; ++current) {
|
|
if (*current == layer) {
|
|
if ((*current)->GetLayerZOrder() == z) {
|
|
// Don't change anything if the Z hasn't changed
|
|
return HWC2::Error::None;
|
|
}
|
|
current = m_layers.erase(current);
|
|
layerOnDisplay = true;
|
|
break;
|
|
}
|
|
}
|
|
HWC_CHK_RETURN((!layerOnDisplay), HWC2::Error::BadLayer,
|
|
ALOGE("[%" PRIu64 "] updateLayerZ failed to find layer on display", m_displayId));
|
|
|
|
layer->SetLayerZOrder(z);
|
|
m_layers.emplace(layer);
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::SetOutputBuffer(buffer_handle_t buf, int32_t releaseFence)
|
|
{
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
ALOGV("[%" PRIu64 "] setOutputBuffer(%p, %d)", m_displayId, buf, releaseFence);
|
|
m_outputBuffer.buffer = buf;
|
|
m_outputBuffer.fenceId = releaseFence;
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::SetPowerMode(HWC2::PowerMode mode)
|
|
{
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
HWC_CHK_RETURN((!IsValidPowerMode(mode)), HWC2::Error::BadParameter);
|
|
HWC_CHK_RETURN((mode == m_powerMode && mode != HWC2::PowerMode::On), HWC2::Error::None);
|
|
|
|
// Required only for battery products
|
|
string tabletProduct = "tablet";
|
|
string xrProduct = "xr";
|
|
char value[PROPERTY_VALUE_MAX] = {0};
|
|
property_get("ro.build.product", value, "");
|
|
if ((strncmp(value, tabletProduct.c_str(), tabletProduct.length()) == 0) ||
|
|
(strncmp(value, xrProduct.c_str(), xrProduct.length()) == 0)) {
|
|
ALOGI("need set disp power state, power mode is %d ", mode);
|
|
HWCIapiAdapter::GetInstance().SetDispPowerState(m_displayId, mode);
|
|
}
|
|
|
|
m_powerMode = mode;
|
|
// when change attach/detach, SF will set powerMode to stop/start draw on external display,
|
|
// set fb alpha to 0 prevent the last frame cover up external attach or
|
|
// set fb alpha recover normal.
|
|
if (m_displayType == DisplayType::DISPLAY_EXTERNAL) {
|
|
RefreshFb(m_powerMode);
|
|
}
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
void HWCDisplay::RefreshFb(const HWC2::PowerMode mode)
|
|
{
|
|
if (mode == HWC2::PowerMode::Off) {
|
|
m_couldDisplay = false;
|
|
} else if (mode == HWC2::PowerMode::On) {
|
|
uapi_disp_state dispStatus = {};
|
|
int ret = HWCIapiAdapter::GetInstance().GetExternalDisplayStatus(&dispStatus);
|
|
if (ret != HWC_SUCCESS) {
|
|
ALOGE("GetExternalDisplayStatus fail");
|
|
return;
|
|
}
|
|
ALOGI("external display is slaved: %s", dispStatus.is_slave ? "true" : "false");
|
|
|
|
// if external display is slave with primary display, we close external display.
|
|
if (dispStatus.is_slave) {
|
|
m_couldDisplay = false;
|
|
} else {
|
|
m_couldDisplay = true;
|
|
}
|
|
} else {
|
|
ALOGI("Refresh fb show status ignore! unknow powermode, %d", static_cast<int>(mode));
|
|
return;
|
|
}
|
|
|
|
ALOGI("external display is showable: %s", m_couldDisplay ? "true" : "false");
|
|
if (ioctl(m_frameBufferFd, GFBGIOPUT_SHOW, &m_couldDisplay) != 0) {
|
|
ALOGE("GFBGIOPUT_SHOW Error!");
|
|
}
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::SetVsyncEnabled(HWC2::Vsync enabled)
|
|
{
|
|
std::unique_lock<std::mutex> lock(m_vsyncMutex);
|
|
m_vsyncEnabled = enabled;
|
|
if (m_vsyncEnabled == HWC2::Vsync::Enable) {
|
|
m_vsyncCondition.notify_one();
|
|
}
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
bool HWCDisplay::Vsync(int64_t timestamp, unsigned int freshRate)
|
|
{
|
|
// m_freshRate is activeMode's fresh_rate, freshRate is vsync freshRate
|
|
int gap = 1;
|
|
if (m_freshRate <= freshRate) {
|
|
gap = freshRate / m_freshRate;
|
|
} else {
|
|
ALOGE("vsync warnning! m_freshRate is %d, freshRate is %d", m_freshRate, freshRate);
|
|
}
|
|
|
|
std::unique_lock<std::mutex> lock(m_vsyncMutex);
|
|
if (m_vsyncEnabled != HWC2::Vsync::Enable) {
|
|
m_vsyncCount = 0;
|
|
m_vsyncCondition.wait(lock);
|
|
} else {
|
|
if (m_hwcCallbacks == nullptr) {
|
|
return false;
|
|
}
|
|
if (((m_vsyncCount++) % gap) == 0) {
|
|
m_hwcCallbacks->Vsync(m_displayId, timestamp);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
inline void HWCDisplay::AddFenceToMonitor(int fd, FENCE_TYPE type, hwc2_layer_t layerId)
|
|
{
|
|
if (m_fenceMonitorDebug || CC_UNLIKELY((atrace_is_tag_enabled(ATRACE_TAG_GRAPHICS) != 0))) {
|
|
if (m_fenceMonitorMng == nullptr) {
|
|
m_fenceMonitorMng = std::make_unique<FenceMonitorMng>();
|
|
}
|
|
m_fenceMonitorMng->AddFence(fd, type, layerId, m_seq);
|
|
}
|
|
}
|
|
|
|
void HWCDisplay::UpdateRequestAndComposeType()
|
|
{
|
|
m_layerRequests.clear();
|
|
m_displayRequests = static_cast<HWC2::DisplayRequest>(0);
|
|
|
|
if (m_layers.empty()) {
|
|
return;
|
|
}
|
|
HWCLayer* firstLayer = *m_layers.begin();
|
|
switch (m_composeType) {
|
|
case (int)HWC_COMPOSE::HWC_GPU_COMPOSE:
|
|
// any layer not supported by hwc, all layers will be added to GPU
|
|
for (auto layer = m_layers.cbegin(); layer != m_layers.cend(); ++layer) {
|
|
PrivHandle handle = static_cast<PrivHandle>((*layer)->GetLayerBuffer().buffer);
|
|
if (((*layer)->GetClientRequested() == HWC2::Composition::Sideband) || ((handle != nullptr) &&
|
|
static_cast<bool>((handle->consumer_usage | handle->producer_usage) &
|
|
static_cast<unsigned long long>(GRALLOC_USAGE_PRI_VDP)))) {
|
|
(*layer)->UpdateDeviceCompositionType(HWC2::Composition::Sideband);
|
|
m_layerRequests[(*layer)->GetId()] = HWC2::LayerRequest::ClearClientTarget;
|
|
} else {
|
|
(*layer)->UpdateDeviceCompositionType(HWC2::Composition::Client);
|
|
}
|
|
}
|
|
break;
|
|
case (int)HWC_COMPOSE::HWC_GFX2D_COMPOSE:
|
|
for (auto layer = m_layers.cbegin(); layer != m_layers.cend(); ++layer) {
|
|
PrivHandle handle = static_cast<PrivHandle>((*layer)->GetLayerBuffer().buffer);
|
|
if (((*layer)->GetClientRequested() == HWC2::Composition::Sideband) || ((handle != nullptr) &&
|
|
static_cast<bool>((handle->consumer_usage | handle->producer_usage) &
|
|
static_cast<unsigned long long>(GRALLOC_USAGE_PRI_VDP)))) {
|
|
(*layer)->UpdateDeviceCompositionType(HWC2::Composition::Sideband);
|
|
} else {
|
|
(*layer)->UpdateDeviceCompositionType(HWC2::Composition::Device);
|
|
// need to sed layer requests, otherwise, surfaceflinger can't get display request.
|
|
// sideband should avoid digging holes twice both by GPU and gfx2d
|
|
m_layerRequests[(*layer)->GetId()] = HWC2::LayerRequest::ClearClientTarget;
|
|
}
|
|
}
|
|
if (!static_cast<bool>(property_get_bool(m_lockFb.c_str(), false))) {
|
|
m_displayRequests = HWC2::DisplayRequest::FlipClientTarget;
|
|
}
|
|
break;
|
|
case (int)HWC_COMPOSE::HWC_DIRECT_PRESENT:
|
|
// Select device compostion to avoid GPU Composition in surfaceflinger
|
|
// and don't set FlipClientTarget to ensure that frame buffer was not udpated
|
|
firstLayer->UpdateDeviceCompositionType(HWC2::Composition::Device);
|
|
break;
|
|
default:
|
|
ALOGE("wrong compose type:%d", m_composeType);
|
|
break;
|
|
}
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::ValidateDisplay(uint32_t *outNumTypes, uint32_t *outNumRequests)
|
|
{
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
// if screen off , not composer and send fb
|
|
HWC_CHK_RETURN((m_powerMode != HWC2::PowerMode::On), HWC2::Error::None, ALOGD("HWC power mode not On"));
|
|
HWC_CHK_RETURN((outNumTypes == nullptr || outNumRequests == nullptr), HWC2::Error::BadParameter,
|
|
ALOGE("HWC:validateDisplay get null input"));
|
|
|
|
m_codeStateFlag = property_get_bool("vendor.gfx.hwc.stat", false);
|
|
m_hwcAsyncCompose = property_get_bool("persist.vendor.gfx.gfx2d.async", true);
|
|
m_layerChanges.clear();
|
|
m_composeType = GetComposeType();
|
|
UpdateRequestAndComposeType();
|
|
|
|
for (auto layer = m_layers.cbegin(); layer != m_layers.cend(); ++layer) {
|
|
if ((*layer)->GetDeviceSelected() != (*layer)->GetClientRequested()) {
|
|
m_layerChanges[(*layer)->GetId()] = (*layer)->GetDeviceSelected();
|
|
}
|
|
}
|
|
|
|
*outNumTypes = uint32_t(m_layerChanges.size());
|
|
*outNumRequests = uint32_t(m_layerRequests.size());
|
|
m_validated = true;
|
|
HWC_CHK_RETURN((*outNumTypes > 0), HWC2::Error::HasChanges);
|
|
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::PresentDisplay(int32_t *outRetireFence)
|
|
{
|
|
ATRACE_CALL();
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
// if screen off , not composer and send fb.
|
|
HWC_CHK_RETURN((m_powerMode != HWC2::PowerMode::On), HWC2::Error::None, ALOGD("powermode is off"));
|
|
HWC_CHK_RETURN((!m_couldDisplay), HWC2::Error::None, ALOGD("couldn't display, because display is close"));
|
|
|
|
HWC_CHK_RETURN((outRetireFence == nullptr), HWC2::Error::BadParameter,
|
|
ALOGE("presentDisplay get null input"));
|
|
|
|
HWC_CHK_RETURN((m_displayId == HWC_DISPLAY_VIRTUAL), HWC2::Error::None);
|
|
|
|
if (static_cast<bool>(property_get_bool(m_lockFb.c_str(), false))) {
|
|
WaitFenceBeforeSyncCompose();
|
|
return HWC2::Error::None;
|
|
}
|
|
// whether gfx2d compress graphic data
|
|
if (m_hwcCompose && (m_composeType == (int)HWC_COMPOSE::HWC_GFX2D_COMPOSE)) {
|
|
(void)HwcGfx2DComposer();
|
|
}
|
|
|
|
HwcMediaFresh();
|
|
if (m_composeType != (int)HWC_COMPOSE::HWC_DIRECT_PRESENT) {
|
|
HwcFbFresh();
|
|
if (m_fbPixelDebug) {
|
|
CheckFbPresentPixel();
|
|
}
|
|
} else {
|
|
HwcDirectFresh();
|
|
}
|
|
AddFenceToMonitor(m_retireFenceId, FENCE_TYPE_ENUM::FENCE_FB_ACQUIRE, 0);
|
|
m_seq++;
|
|
bool enableDebug = property_get_bool("vendor.gfx.hwc.debug", false);
|
|
// Close layer acquire fence to avoid fd leak and push release fence
|
|
for (auto layer = m_layers.cbegin(); layer != m_layers.cend(); ++layer) {
|
|
if (enableDebug) {
|
|
(*layer)->Dump();
|
|
}
|
|
(*layer)->CloseAcquireFence();
|
|
(*layer)->PushReleaseFence();
|
|
}
|
|
|
|
// close frame buffer acquire fence to avoid fd leak
|
|
if (m_clientTarget.fenceId != HWC_INVALID_FENCE_ID) {
|
|
// here only for gpu compose ,we don't need to wait fence only close it or else fd will be leaked
|
|
close(m_clientTarget.fenceId);
|
|
m_clientTarget.fenceId = HWC_INVALID_FENCE_ID;
|
|
}
|
|
|
|
*outRetireFence = m_lastRetireFenceId;
|
|
if (enableDebug) {
|
|
ALOGI("PresentDisplay return with fence:%d", m_lastRetireFenceId);
|
|
}
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
void HWCDisplay::UpdateVirtualScreenByConfig()
|
|
{
|
|
#ifdef EXT_XR
|
|
// for XR special scene, virtual screen only should be 3840 x 1080 or 2560 x 720,
|
|
// which is not completely equal to curren resolution, such as 1920 x 1080, 1280 x 720.
|
|
if ((m_displayFbDevice->width == HWC_XR_3D_WIDTH) && (m_displayFbDevice->height == HWC_XR_3D_HEIGHT)) {
|
|
if (m_activeDisplayConfig.height == HWC_XR_3D_HEIGHT) {
|
|
HWCIapiAdapter::GetInstance().UpdateVirtualScreen(m_displayId, HWC_XR_3D_WIDTH, HWC_XR_3D_HEIGHT);
|
|
} else if (m_activeDisplayConfig.height == HWC_XR_3D_OLD_HEIGHT) {
|
|
HWCIapiAdapter::GetInstance().UpdateVirtualScreen(m_displayId, HWC_XR_3D_OLD_WIDTH, HWC_XR_3D_OLD_HEIGHT);
|
|
}
|
|
return;
|
|
}
|
|
#endif
|
|
HWCIapiAdapter::GetInstance().UpdateVirtualScreen(m_displayId, m_activeDisplayConfig.width,
|
|
m_activeDisplayConfig.height);
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::SetActiveConfig(hwc2_config_t config)
|
|
{
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
m_activeConfig = config;
|
|
ALOGI("SetActiveConfig %d", m_activeConfig);
|
|
m_activeDisplayConfig = m_displayConfigs[config];
|
|
UpdateVirtualScreenByConfig();
|
|
m_freshRate = m_activeDisplayConfig.fps;
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::SetClientTarget(buffer_handle_t target, int32_t acquireFence, int32_t dataSpace,
|
|
hwc_region_t damage)
|
|
{
|
|
// dataspace and damage can't be used now, so ignore them
|
|
UNUSED(dataSpace);
|
|
UNUSED(damage);
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
ALOGV("[%" PRIu64 "] setClientTarget(%p, %d)", m_displayId, target, acquireFence);
|
|
m_clientTarget.buffer = target;
|
|
#ifdef EXT_GFX2D_SUPPORT
|
|
int fbReleaseFd = HWC_INVALID_FENCE_ID;
|
|
const private_handle_t *fbHandle = static_cast<const private_handle_t *>(target);
|
|
if (fbHandle != nullptr) {
|
|
QueryFbReleaseFence(fbHandle->addr, fbReleaseFd);
|
|
}
|
|
if (m_composeType == (int)HWC_COMPOSE::HWC_GFX2D_COMPOSE) {
|
|
// for gfx2d compose, init the value of clientTrage.fenceId using stored value
|
|
if (acquireFence != HWC_INVALID_FENCE_ID) {
|
|
// to avoid fd leak
|
|
close(acquireFence);
|
|
acquireFence = HWC_INVALID_FENCE_ID;
|
|
}
|
|
m_clientTarget.fenceId = fbReleaseFd;
|
|
} else {
|
|
if (fbReleaseFd != HWC_INVALID_FENCE_ID) {
|
|
// to avoid fd leak
|
|
close(fbReleaseFd);
|
|
fbReleaseFd = HWC_INVALID_FENCE_ID;
|
|
}
|
|
m_clientTarget.fenceId = acquireFence;
|
|
}
|
|
#else
|
|
m_clientTarget.fenceId = acquireFence;
|
|
#endif
|
|
m_clientTarget.releaseFenceFd = HWC_INVALID_FENCE_ID;
|
|
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::SetColorMode(int32_t mode)
|
|
{
|
|
UNUSED(mode);
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::SetCursorPosition(hwc2_layer_t layer, int x, int y)
|
|
{
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
ALOGV("[%" PRIu64 "] setCursorPosition(%d, %d)", layer, x, y);
|
|
return HWC2::Error::Unsupported;
|
|
}
|
|
|
|
HWC2::Error HWCDisplay::GetHdrCapabilities(uint32_t *outNumTypes, int32_t *outTypes, float *outMaxLuminance,
|
|
float *outMaxAverageLuminance, float *outMinLuminance)
|
|
{
|
|
UNUSED(outTypes);
|
|
HWC_CHK_RETURN((outNumTypes == nullptr || outMaxLuminance == nullptr || outMaxAverageLuminance == nullptr ||
|
|
outMinLuminance == nullptr), HWC2::Error::BadParameter, ALOGE("getHdrCapabilities get null input"));
|
|
|
|
if (property_get_bool("vendor.gfx.hwc.debug.hdr", false)) {
|
|
if (outTypes == nullptr) {
|
|
*outNumTypes = MAX_HDR_TYPES;
|
|
return HWC2::Error::None;
|
|
}
|
|
outTypes[HDR_ARRAY_INDEX_0] = HAL_HDR_DOLBY_VISION;
|
|
outTypes[HDR_ARRAY_INDEX_1] = HAL_HDR_HDR10;
|
|
outTypes[HDR_ARRAY_INDEX_2] = HAL_HDR_HLG;
|
|
*outMaxLuminance = 0;
|
|
*outMaxAverageLuminance = 0;
|
|
*outMinLuminance = 0;
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
#ifdef EXT_HDMI_SUPPORT
|
|
HdrCap cap;
|
|
errno_t eok = memset_s(&cap, sizeof(HdrCap), 0, sizeof(HdrCap));
|
|
HWC_CHK_RETURN((eok != EOK), HWC2::Error::NotValidated, ALOGE("HdrCap memset_s failed"));
|
|
|
|
int ret = HWCIapiAdapter::GetInstance().GetHdrInfo(m_displayId, cap);
|
|
HWC_CHK_RETURN((ret == HWC_FAILURE), HWC2::Error::NotValidated);
|
|
|
|
if (outTypes == nullptr) {
|
|
*outNumTypes = cap.num;
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
unsigned int i = 0;
|
|
if (cap.dolby) {
|
|
outTypes[i++] = HAL_HDR_DOLBY_VISION;
|
|
}
|
|
if (cap.hdr10) {
|
|
outTypes[i++] = HAL_HDR_HDR10;
|
|
}
|
|
if (cap.hlg) {
|
|
outTypes[i++] = HAL_HDR_HLG;
|
|
}
|
|
if (i != cap.num) {
|
|
ALOGE("GetHdrInfo return illegal values i=%d num=%d", i, cap.num);
|
|
}
|
|
|
|
*outNumTypes = cap.num;
|
|
*outMaxLuminance = cap.maxLuminance;
|
|
*outMaxAverageLuminance = cap.maxAverageLuminance;
|
|
*outMinLuminance = cap.minLuminance;
|
|
#endif
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
std::string HWCDisplay::Dump()
|
|
{
|
|
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
|
|
std::stringstream os;
|
|
os << "-----------------------------------------------" << std::endl;
|
|
os << "HWC2 Display: " << m_displayId << std::endl;
|
|
const private_handle_t *fbHandle = static_cast<const private_handle_t *>(m_clientTarget.buffer);
|
|
os << " composeType: " << m_composeType << std::endl;
|
|
os << " framebuffer: " << std::hex << fbHandle << std::dec << std::endl;
|
|
os << " couldDisplay: " << m_couldDisplay << std::endl;
|
|
if (fbHandle != nullptr) {
|
|
os << " framebuffer size: " << fbHandle->width << " x " << fbHandle->height << std::endl;
|
|
}
|
|
os << " m_activeConfig: " << m_activeConfig << std::endl;
|
|
os << " m_displayConfigs: " << std::endl;
|
|
for (auto config = m_displayConfigs.cbegin(); config != m_displayConfigs.cend(); ++config) {
|
|
os << " config id:" << (*config).first << " DisplayConfigInfo:"
|
|
<< "{" << (*config).second.width << ", " << (*config).second.height << ", "
|
|
<< (*config).second.xDpi << ", " << (*config).second.yDpi << ", "
|
|
<< (*config).second.fps << "}" << std::endl;
|
|
}
|
|
for (auto layer = m_layers.cbegin(); layer != m_layers.cend(); ++layer) {
|
|
os << "-------------" << std::endl;
|
|
os << "layer_id: " << (*layer)->GetId() << std::endl;
|
|
os << "\tz: " << (*layer)->GetLayerZOrder() << std::endl;
|
|
const private_handle_t *pHandle = static_cast<const private_handle_t *>((*layer)->GetLayerBuffer().buffer);
|
|
if (((pHandle != nullptr) &&
|
|
static_cast<bool>((pHandle->consumer_usage | pHandle->producer_usage) &
|
|
static_cast<unsigned long long>(GRALLOC_USAGE_PRI_VDP)))) {
|
|
os << "\tclient(SF) composition: Overlay" << std::endl;
|
|
os << "\tdevice(HWC) composition: Overlay" << std::endl;
|
|
} else {
|
|
os << "\tclient(SF) composition: " << to_string((*layer)->GetClientRequested()) << std::endl;
|
|
os << "\tdevice(HWC) composition: " << to_string((*layer)->GetDeviceSelected()) << std::endl;
|
|
}
|
|
os << "\tplane_alpha: " << std::to_string((*layer)->GetPlaneAlpha()).c_str() << std::endl;
|
|
os << "\tbuffer: " << std::hex << pHandle << std::dec << std::endl;
|
|
if (pHandle != nullptr) {
|
|
os << "\tformat: " << std::hex << pHandle->format << std::dec << std::endl;
|
|
}
|
|
os << "\tm_sidebandStream: " << std::hex << (*layer)->GetLayerSidebandStream() << std::dec << std::endl;
|
|
os << "\tsourceCrop:[" << (*layer)->GetLayerSourceCrop().left << "," << (*layer)->GetLayerSourceCrop().top <<
|
|
"," << (*layer)->GetLayerSourceCrop().right << "," << (*layer)->GetLayerSourceCrop().bottom << "]" <<
|
|
std::endl;
|
|
os << "\tm_displayFrame:[" << (*layer)->GetDisplayFrame().left << "," << (*layer)->GetDisplayFrame().top <<
|
|
"," << (*layer)->GetDisplayFrame().right << "," << (*layer)->GetDisplayFrame().bottom << "]" <<
|
|
std::endl;
|
|
}
|
|
if (m_fenceMonitorDebug && (m_fenceMonitorMng != nullptr)) {
|
|
os << "-------------" << std::endl;
|
|
os << m_fenceMonitorMng->Dump();
|
|
}
|
|
return os.str();
|
|
}
|
|
} // namespace android
|