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.

7106 lines
303 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* Copyright (C) 2016 The Android Open Source Project
*
* 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.
*/
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#define LOG_TAG "hwc-drm-two"
#include "drmhwctwo.h"
#include <drm_fourcc.h>
#include <rga.h>
#include <im2d.hpp>
#include "drmdisplaycomposition.h"
#include "drmlayer.h"
#include "hwc3/hwc3adapterhwc2.h"
#include "platform.h"
#include "rockchip/drmgralloc.h"
#include "rockchip/utils/drmdebug.h"
#include "utils/hwc2_dumper.h"
#include "vsyncworker.h"
#include <inttypes.h>
#include <iomanip>
#include <cutils/properties.h>
#include <hardware/hardware.h>
#include <hardware/hwcomposer2.h>
#include <log/log.h>
#include <utils/Trace.h>
#include <linux/fb.h>
#ifdef USE_LIBEBOOK
#include "EBookApi.h"
#endif
#define hwcMIN(x, y) (((x) <= (y)) ? (x) : (y))
#define hwcMAX(x, y) (((x) >= (y)) ? (x) : (y))
#ifndef IS_ALIGN
#define IS_ALIGN(val, align) (((val) & (align - 1)) == 0)
#endif
#ifndef ALIGN
#define ALIGN(value, base) (((value) + ((base) - 1)) & ~((base) - 1))
#endif
#ifndef ALIGN_DOWN
#define ALIGN_DOWN(value, base) (value & (~(base - 1)))
#endif
#ifndef RK_GRALLOC_USAGE_STRIDE_ALIGN_64
#define RK_GRALLOC_USAGE_STRIDE_ALIGN_64 (1ULL << 60)
#endif
#ifndef MALI_GRALLOC_USAGE_NO_AFBC
#define MALI_GRALLOC_USAGE_NO_AFBC (1ULL << 29)
#endif
#ifndef RK_GRALLOC_USAGE_WITHIN_4G
#define RK_GRALLOC_USAGE_WITHIN_4G (1ULL << 56)
#endif
namespace android {
static inline long __currentTime() {
struct timeval tp;
gettimeofday(&tp, NULL);
return static_cast<long>(tp.tv_sec) * 1000000 + tp.tv_usec;
}
#define ALOGD_HWC2_DRM_LAYER_INFO(log_level, drmHwcLayers) \
if (LogLevel(log_level)) { \
String8 output; \
for (auto& drmHwcLayer : drmHwcLayers) { \
drmHwcLayer.DumpInfo(output); \
ALOGD_IF(LogLevel(log_level), "%s", output.c_str()); \
output.clear(); \
} \
}
class DrmVsyncCallback : public VsyncCallback {
public:
DrmVsyncCallback(hwc2_callback_data_t data, hwc2_function_pointer_t hook) : data_(data), hook_(hook) {}
void Callback(int display, int64_t timestamp) {
auto hook = reinterpret_cast<HWC2_PFN_VSYNC>(hook_);
if (hook) {
hook(data_, display, timestamp);
}
}
#if PLATFORM_SDK_VERSION >= 34
void Callback(int display, int64_t timestamp, hwc2_vsync_period_t vsyncPeriodNanos) {
auto hook = reinterpret_cast<HWC2_PFN_VSYNC_2_4>(hook_);
if (hook) {
hook(data_, display, timestamp, vsyncPeriodNanos);
}
}
#endif
private:
hwc2_callback_data_t data_;
hwc2_function_pointer_t hook_;
};
class DrmInvalidateCallback : public InvalidateCallback {
public:
DrmInvalidateCallback(hwc2_callback_data_t data, hwc2_function_pointer_t hook) : data_(data), hook_(hook) {}
void Callback(int display) {
auto hook = reinterpret_cast<HWC2_PFN_REFRESH>(hook_);
if (hook) {
hook(data_, display);
}
}
private:
hwc2_callback_data_t data_;
hwc2_function_pointer_t hook_;
};
DrmHwcTwo::DrmHwcTwo() : resource_manager_(ResourceManager::getInstance()) {
common.tag = HARDWARE_DEVICE_TAG;
common.version = HWC_DEVICE_API_VERSION_2_0;
common.close = HookDevClose;
getCapabilities = HookDevGetCapabilities;
getFunction = HookDevGetFunction;
#ifdef USE_LIBEBOOK
EBookDisplayId_ = -1;
#endif
}
HWC2::Error DrmHwcTwo::CreateDisplay(hwc2_display_t displ, HWC2::DisplayType type) {
HWC2_LOGV_IF("display-id=%" PRIu64 " type=%s", displ,
(type == HWC2::DisplayType::Physical ? "Physical" : "Virtual"));
DrmDevice* drm = resource_manager_->GetDrmDevice(displ);
std::shared_ptr<Importer> importer = resource_manager_->GetImporter(displ);
if (!drm || !importer) {
ALOGE("Failed to get a valid drmresource and importer");
return HWC2::Error::NoResources;
}
displays_.emplace(std::piecewise_construct, std::forward_as_tuple(displ),
std::forward_as_tuple(resource_manager_, drm, importer, displ, type));
displays_.at(displ).Init();
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::Init() {
HWC2_LOGV_IF();
int rv = resource_manager_->Init(this);
if (rv) {
ALOGE("Can't initialize the resource manager %d", rv);
return HWC2::Error::NoResources;
}
HWC2::Error ret = HWC2::Error::None;
for (auto& map_display : resource_manager_->getDisplays()) {
ret = CreateDisplay(map_display.second, HWC2::DisplayType::Physical);
if (ret != HWC2::Error::None) {
ALOGE("Failed to create display %d with error %d", map_display.second, ret);
return ret;
}
}
auto& drmDevices = resource_manager_->GetDrmDevices();
for (auto& device : drmDevices) {
device->RegisterHotplugHandler(new DrmHotplugHandler(this, device.get()));
}
// drm event 异步消息处理线程
if (eventWorker_.Init(this)) {
HWC2_LOGE("EventWorker init fail.");
}
#ifdef USE_LIBEBOOK
// 初始化EBook显示设备
int physical_display_num = resource_manager_->getDisplayCount();
int ebook_display_id = physical_display_num + mVirtualDisplayCount_;
if (!displays_.count(ebook_display_id)) {
int virtual_display_id = 0;
DrmDevice* drm = resource_manager_->GetDrmDevice(virtual_display_id);
std::shared_ptr<Importer> importer = resource_manager_->GetImporter(virtual_display_id);
if (!drm || !importer) {
ALOGE("Failed to get a valid drmresource and importer");
return HWC2::Error::NoResources;
}
displays_.emplace(
std::piecewise_construct, std::forward_as_tuple(ebook_display_id),
std::forward_as_tuple(resource_manager_, drm, importer, ebook_display_id, HWC2::DisplayType::Physical));
displays_.at(ebook_display_id).InitEBook();
mVirtualDisplayCount_++;
EBookDisplayId_ = ebook_display_id;
}
#endif
//Ensure all display except primary are disabled in SingleDisplay mode
if (resource_manager_->IsSingleDisplayMode()) {
auto drm = resource_manager_->GetDrmDevice(0);
if (drm) {
for (auto& conn : drm->connectors()) {
if (conn->display() != 0) {
HWC2_LOGI("SingleDisplayMode disable display %d (%s-%d).", conn->display(),
drm->connector_type_str(conn->type()), conn->type_id());
int ret = drm->ReleaseDpyRes(conn->display());
if (ret) {
HWC2_LOGE("Failed to disable Display %d, ret=%d", conn->display(), ret);
}
}
}
} else {
HWC2_LOGE("Failed to get DrmDevice for Display 0");
}
}
return ret;
}
hwc2_drm_display_t* DrmHwcTwo::GetDisplayCtxPtr(hwc2_display_t display_id) {
if (displays_.count(display_id)) {
auto& display = displays_.at(display_id);
return display.GetDisplayCtxPtr();
}
return NULL;
}
template <typename... Args>
static inline HWC2::Error unsupported(char const* func, Args... /*args*/) {
ALOGV("Unsupported function: %s", func);
return HWC2::Error::Unsupported;
}
static inline void supported(char const* func) {
ALOGV("Supported function: %s", func);
}
HWC2::Error DrmHwcTwo::CreateVirtualDisplay(uint32_t width, uint32_t height, int32_t* format, hwc2_display_t* display) {
HWC2_LOGV_IF("w=%u,h=%u,f=%d", width, height, *format);
HWC2::Error ret = HWC2::Error::None;
int physical_display_num = resource_manager_->getDisplayCount();
int virtual_display_id = physical_display_num + mVirtualDisplayCount_;
if (!displays_.count(virtual_display_id)) {
char value[PROPERTY_VALUE_MAX];
property_get("vendor.hwc.virtual_display_write_back_id", value, "0");
int write_back_id = atoi(value);
DrmDevice* drm = resource_manager_->GetDrmDevice(write_back_id);
std::shared_ptr<Importer> importer = resource_manager_->GetImporter(write_back_id);
if (!drm || !importer) {
ALOGE("Failed to get a valid drmresource and importer");
return HWC2::Error::NoResources;
}
displays_.emplace(std::piecewise_construct, std::forward_as_tuple(virtual_display_id),
std::forward_as_tuple(resource_manager_, drm, importer, virtual_display_id,
HWC2::DisplayType::Virtual));
displays_.at(virtual_display_id).InitVirtual();
*display = virtual_display_id;
*format = HAL_PIXEL_FORMAT_RGBA_8888;
mVirtualDisplayCount_++;
resource_manager_->EnableWriteBackMode(write_back_id);
HWC2_LOGI("Support VDS: w=%u,h=%u,f=%d display-id=%d", width, height, *format, virtual_display_id);
auto& display = resource_manager_->GetHwc2()->displays_.at(0);
display.InvalidateControl(30, -1);
return HWC2::Error::None;
}
return HWC2::Error::NoResources;
}
HWC2::Error DrmHwcTwo::DestroyVirtualDisplay(hwc2_display_t display) {
HWC2_LOGV_IF();
auto virtual_display = displays_.find(display);
if (virtual_display != displays_.end()) {
displays_.erase(virtual_display);
resource_manager_->DisableWriteBackMode(resource_manager_->GetWBDisplay());
HWC2_LOGI("VDS: display-id=%" PRIu64, display);
mVirtualDisplayCount_--;
auto& display = resource_manager_->GetHwc2()->displays_.at(0);
display.InvalidateControl(30, 0);
return HWC2::Error::None;
}
return HWC2::Error::BadDisplay;
}
void DrmHwcTwo::Dump(uint32_t* size, char* buffer) {
if (buffer != nullptr) {
auto copiedBytes = mDumpString.copy(buffer, *size);
*size = static_cast<uint32_t>(copiedBytes);
return;
}
String8 output;
output.appendFormat("HWC2 Version %s-%s by bin.li@rock-chips.com\n", GHWC_VERSION, GHWC_VERSION_NOTES);
for (auto& map_disp : displays_) {
if ((map_disp.second.DumpDisplayInfo(output)) < 0) continue;
}
DrmVideoProducer* dvp = DrmVideoProducer::getInstance();
if (dvp != NULL) {
dvp->Dump(output);
}
mDumpString = output;
*size = static_cast<uint32_t>(mDumpString.size());
return;
}
uint32_t DrmHwcTwo::GetMaxVirtualDisplayCount() {
HWC2_LOGI();
// DSI 固件不支持 HW VirtualDisplay.
if (hwc_get_int_property("ro.vendor.rk_sdk", "0") == 0) {
HWC2_LOGI("Maybe GSI SDK, to disable HW VirtualDisplay\n");
return 0;
}
char value[PROPERTY_VALUE_MAX];
property_get("vendor.hwc.max_virtual_display_count", value, "5");
return atoi(value);
}
static bool isValid(HWC2::Callback descriptor) {
switch (descriptor) {
case HWC2::Callback::Hotplug: // Fall-through
case HWC2::Callback::Refresh: // Fall-through
#if PLATFORM_SDK_VERSION >= 34
case HWC2::Callback::Vsync_2_4:
#endif
case HWC2::Callback::Vsync:
return true;
#if PLATFORM_SDK_VERSION >= 34
case HWC2::Callback::VsyncPeriodTimingChanged:
case HWC2::Callback::SeamlessPossible:
return false;
#endif
default:
return false;
}
}
HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor, hwc2_callback_data_t data,
hwc2_function_pointer_t function) {
HWC2_LOGV_IF();
auto callback = static_cast<HWC2::Callback>(descriptor);
if (!isValid(callback)) {
return HWC2::Error::BadParameter;
}
if (!function) {
callbacks_.erase(callback);
switch (callback) {
#if PLATFORM_SDK_VERSION >= 34
case HWC2::Callback::Vsync_2_4:
#endif
case HWC2::Callback::Vsync: {
for (std::pair<const hwc2_display_t, DrmHwcTwo::HwcDisplay>& d : displays_)
d.second.UnregisterVsyncCallback();
break;
}
case HWC2::Callback::Refresh: {
for (std::pair<const hwc2_display_t, DrmHwcTwo::HwcDisplay>& d : displays_)
d.second.UnregisterInvalidateCallback();
break;
}
default:
break;
}
return HWC2::Error::None;
}
callbacks_.emplace(callback, HwcCallback(data, function));
switch (callback) {
case HWC2::Callback::Hotplug: {
auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(function);
hotplug(data, HWC_DISPLAY_PRIMARY,
static_cast<int32_t>(HWC2::Connection::Connected));
#ifdef USE_LIBEBOOK
if (EBookDisplayId_ > 0) {
hotplug(data, EBookDisplayId_, static_cast<int32_t>(HWC2::Connection::Connected));
}
#endif
// 主屏已经向SurfaceFlinger注册
mHasRegisterDisplay_.insert(HWC_DISPLAY_PRIMARY);
auto& drmDevices = resource_manager_->GetDrmDevices();
for (auto& device : drmDevices) HandleInitialHotplugState(device.get());
// 热插拔事件处理线程启动
eventWorker_.Start();
break;
}
#if PLATFORM_SDK_VERSION >= 34
case HWC2::Callback::Vsync_2_4:
#endif
case HWC2::Callback::Vsync: {
for (std::pair<const hwc2_display_t, DrmHwcTwo::HwcDisplay>& d : displays_)
d.second.RegisterVsyncCallback(data, function);
break;
}
case HWC2::Callback::Refresh: {
for (std::pair<const hwc2_display_t, DrmHwcTwo::HwcDisplay>& d : displays_)
d.second.RegisterInvalidateCallback(data, function);
break;
}
default:
break;
}
return HWC2::Error::None;
}
#if PLATFORM_SDK_VERSION >= 34
HWC2::Error DrmHwcTwo::GetLayerGenericMetadataKey(uint32_t keyIndex, uint32_t* outKeyLength, char* outKey,
bool* outMandatory) {
HWC2_LOGV_IF();
return unsupported(__func__, keyIndex, outKeyLength, outKey, outMandatory);
}
#endif
DrmHwcTwo::HwcDisplay::HwcDisplay(ResourceManager* resource_manager, DrmDevice* drm, std::shared_ptr<Importer> importer,
hwc2_display_t handle, HWC2::DisplayType type)
: resource_manager_(resource_manager),
drm_(drm),
importer_(importer),
handle_(handle),
type_(type),
client_layer_(UINT32_MAX, drm),
output_layer_(UINT32_MAX, drm),
init_success_(false) {}
int DrmHwcTwo::HwcDisplay::ClearDisplay() {
// 虚拟屏不执行此逻辑
if (isVirtual()) {
return 0;
}
#ifdef USE_LIBEBOOK
// 电子书不执行此逻辑
if (isEBook()) {
return 0;
}
#endif
if (!init_success_) {
HWC2_LOGE("display=%" PRIu64 " init_success_=%d skip.", handle_, init_success_);
return -1;
}
if (connector_ != NULL) {
compositor_->ClearDisplay();
}
HWC2_LOGI_IF("display-id=%" PRIu64, handle_);
return 0;
}
int DrmHwcTwo::HwcDisplay::ResetDisplay() {
// 虚拟屏不执行此逻辑
if (isVirtual()) {
return 0;
}
#ifdef USE_LIBEBOOK
// 电子书不执行此逻辑
if (isEBook()) {
return 0;
}
#endif
init_success_ = false;
// 等待一段时间display处理完当前帧
usleep(20 * 1000);
if (compositor_ != NULL) {
compositor_->ClearDisplay();
}
HWC2_LOGI_IF("display-id=%" PRIu64, handle_);
return 0;
};
int DrmHwcTwo::HwcDisplay::DisconnectDisplay() {
// 虚拟屏不执行此逻辑
if (isVirtual()) {
return 0;
}
#ifdef USE_LIBEBOOK
// 电子书不执行此逻辑
if (isEBook()) {
return 0;
}
#endif
force_disconneted_ = true;
// 等待一段时间display处理完当前帧
usleep(20 * 1000);
if (compositor_ != NULL) {
compositor_->ClearDisplay();
}
HWC2_LOGI_IF("display-id=%" PRIu64, handle_);
return 0;
}
int DrmHwcTwo::HwcDisplay::ConnectDisplay() {
// 虚拟屏不执行此逻辑
if (isVirtual()) {
return 0;
}
#ifdef USE_LIBEBOOK
// 电子书不执行此逻辑
if (isEBook()) {
return 0;
}
#endif
force_disconneted_ = false;
HWC2_LOGI_IF("display-id=%" PRIu64, handle_);
return 0;
}
int DrmHwcTwo::HwcDisplay::ActiveModeChange(bool change) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
bActiveModeChange_ = change;
return 0;
}
bool DrmHwcTwo::HwcDisplay::IsActiveModeChange() {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
return bActiveModeChange_;
}
HWC2::Error DrmHwcTwo::HwcDisplay::Init() {
HWC2_LOGV_IF("HwcDisplay::Init display-id=%" PRIu64, handle_);
int display = static_cast<int>(handle_);
if (sync_timeline_.isValid()) {
HWC2_LOGI_IF("sync_timeline_ fd = %d isValid", sync_timeline_.getFd());
}
connector_ = drm_->GetConnectorForDisplay(display);
if (!connector_) {
ALOGE("Failed to get connector for display %d", display);
return HWC2::Error::BadDisplay;
}
int ret = vsync_worker_.Init(drm_, display);
if (ret) {
ALOGE("Failed to create event worker for d=%d %d\n", display, ret);
return HWC2::Error::BadDisplay;
}
ret = invalidate_worker_.Init(display);
if (ret) {
ALOGE("Failed to create invalidate worker for d=%d %d\n", display, ret);
return HWC2::Error::BadDisplay;
}
if (connector_->state() != DRM_MODE_CONNECTED) {
ALOGI("Connector %u type=%s, type_id=%d, state is DRM_MODE_DISCONNECTED, skip init.\n", connector_->id(),
drm_->connector_type_str(connector_->type()), connector_->type_id());
return HWC2::Error::NoResources;
}
// RK3528 HDMI/TV互斥模式要求若HDMI已连接则 TV不注册
if (gIsRK3528() && !ResourceManager::getInstance()->IsSingleDisplayMode() &&
connector_->type() == DRM_MODE_CONNECTOR_TV) {
DrmConnector* primary = drm_->GetConnectorForDisplay(HWC_DISPLAY_PRIMARY);
if (primary && primary->state() == DRM_MODE_CONNECTED) {
ret = drm_->ReleaseDpyRes(handle_);
if (ret) {
HWC2_LOGE("Failed to ReleaseDpyRes for display=%d %d\n", display, ret);
return HWC2::Error::NoResources;
}
return HWC2::Error::None;
}
}
ret = GetCurrentDisplayMode();
if (ret) {
HWC2_LOGE("Failed to GetCurrentDisplayMode for display=%d %d\n", display, ret);
return HWC2::Error::NoResources;
}
ret = drm_->BindDpyRes(handle_);
if (ret) {
HWC2_LOGE("Failed to BindDpyRes for display=%d %d\n", display, ret);
return HWC2::Error::NoResources;
}
UpdateDisplayInfo();
ret = drm_->UpdateDisplayGamma(handle_);
if (ret) {
HWC2_LOGE("Failed to UpdateDisplayGamma for display=%d %d\n", display, ret);
}
ret = drm_->UpdateDisplay3DLut(handle_);
if (ret) {
HWC2_LOGE("Failed to UpdateDisplay3DLut for display=%d %d\n", display, ret);
}
crtc_ = drm_->GetCrtcForDisplay(display);
if (!crtc_) {
ALOGE("Failed to get crtc for display %d", display);
return HWC2::Error::BadDisplay;
}
// VRR
ret = connector_->UpdateModes();
if (ret) {
ALOGE("Failed to update display modes %d", ret);
return HWC2::Error::BadDisplay;
}
bVrrDisplay_ = crtc_->is_vrr();
// 更新 hotplug 状态
connector_->update_hotplug_state();
planner_ = Planner::CreateInstance(drm_);
if (!planner_) {
ALOGE("Failed to create planner instance for composition");
return HWC2::Error::NoResources;
}
compositor_ = resource_manager_->GetDrmDisplayCompositor(crtc_);
ret = compositor_->Init(resource_manager_, display);
if (ret) {
ALOGE("Failed display compositor init for display %d (%d)", display, ret);
return HWC2::Error::NoResources;
}
// CropSplit must to
if (connector_->isCropSplit()) {
std::unique_ptr<DrmDisplayComposition> composition = compositor_->CreateComposition();
composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_, handle_);
composition->SetDpmsMode(DRM_MODE_DPMS_ON);
ret = compositor_->QueueComposition(std::move(composition));
if (ret) {
HWC2_LOGE("Failed to apply the dpms composition ret=%d", ret);
}
}
// soc_id
ctx_.soc_id = resource_manager_->getSocId();
// display_id
ctx_.display_id = display;
// display-type
ctx_.display_type = connector_->type();
// vop aclk
ctx_.aclk = crtc_->get_aclk();
// Baseparameter Info
ctx_.baseparameter_info = connector_->baseparameter_info();
// Standard Switch Resolution Mode
ctx_.bStandardSwitchResolution = hwc_get_bool_property("vendor.hwc.enable_display_configs", "false");
HWC2::Error error = ChosePreferredConfig();
if (error != HWC2::Error::None) {
ALOGE("Failed to chose prefererd config for display %d (%d)", display, error);
return error;
}
// 非主屏的拼接屏幕需要创建 DummyLayer
if (connector_->isCropSplit() && !connector_->IsSplitPrimary()) {
GetOrCreateDummyLayer();
}
init_success_ = true;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::InitVirtual() {
HWC2_LOGV_IF("display-id=%" PRIu64 " type=%s", handle_,
(type_ == HWC2::DisplayType::Physical ? "Physical" : "Virtual"));
int display = static_cast<int>(handle_);
connector_ = drm_->GetWritebackConnectorForDisplay(0);
if (!connector_) {
ALOGE("Failed to get connector for display %d", display);
return HWC2::Error::BadDisplay;
}
init_success_ = true;
force_disconneted_ = false;
frame_no_ = 0;
wb_frame_no_ = 0;
return HWC2::Error::None;
}
#ifdef USE_LIBEBOOK
HWC2::Error DrmHwcTwo::HwcDisplay::InitEBook() {
HWC2_LOGV_IF("display-id=%" PRIu64 " type=%s", handle_,
(type_ == HWC2::DisplayType::Physical ? "Physical" : "Ebook"));
int display = static_cast<int>(handle_);
mEBookApi_ = std::shared_ptr<EBookApi>(new EBookApi());
if (mEBookApi_ == NULL) {
HWC2_LOGE("EBookApi init fail check\n");
return HWC2::Error::BadDisplay;
}
EBookError error = EBookError::None;
// 2. 初始化
error = mEBookApi_->Init(EBOOK_VERSION);
if (error != EBookError::None) {
HWC2_LOGE("EBook Init fail.\n");
return HWC2::Error::BadDisplay;
}
error = mEBookApi_->GetEBookInfo(&ebook_framebuffer_width, &ebook_framebuffer_height, &ebook_framebuffer_mmwidth,
&ebook_framebuffer_mmheight);
if (error != EBookError::None) {
HWC2_LOGE("EBook Init fail.\n");
return HWC2::Error::BadDisplay;
;
}
HWC2_LOGI("EBookInfo: resolution : width=%d height=%d. physical: width=%d mmheight=%d mm\n",
ebook_framebuffer_width, ebook_framebuffer_height, ebook_framebuffer_mmwidth, ebook_framebuffer_mmheight);
connector_ = drm_->GetWritebackConnectorForDisplay(0);
if (!connector_) {
ALOGE("Failed to get connector for display %d", display);
return HWC2::Error::BadDisplay;
}
init_success_ = true;
force_disconneted_ = false;
frame_no_ = 0;
wb_frame_no_ = 0;
return HWC2::Error::None;
}
#endif
HWC2::Error DrmHwcTwo::HwcDisplay::CheckStateAndReinit(bool clear_layer) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
// 虚拟屏不执行此逻辑
if (isVirtual()) {
return HWC2::Error::BadConfig;
}
#ifdef USE_LIBEBOOK
// 电子书不执行此逻辑
if (isEBook()) {
return HWC2::Error::BadConfig;
}
#endif
int display = static_cast<int>(handle_);
connector_ = drm_->GetConnectorForDisplay(display);
if (!connector_) {
ALOGE("Failed to get connector for display %d", display);
return HWC2::Error::BadDisplay;
}
if (connector_->state() != DRM_MODE_CONNECTED) {
ALOGI("Connector %u type=%s, type_id=%d, state is DRM_MODE_DISCONNECTED, skip init.\n", connector_->id(),
drm_->connector_type_str(connector_->type()), connector_->type_id());
return HWC2::Error::NoResources;
}
int ret = GetCurrentDisplayMode();
if (ret) {
HWC2_LOGE("Failed to GetCurrentDisplayMode for display=%d %d\n", display, ret);
return HWC2::Error::NoResources;
}
ret = drm_->BindDpyRes(handle_);
if (ret) {
HWC2_LOGE("Failed to BindDpyRes for display=%d %d\n", display, ret);
return HWC2::Error::NoResources;
}
UpdateDisplayInfo();
crtc_ = drm_->GetCrtcForDisplay(display);
if (!crtc_) {
ALOGE("Failed to get crtc for display %d", display);
return HWC2::Error::BadDisplay;
}
bVrrDisplay_ = crtc_->is_vrr();
ret = drm_->UpdateDisplayGamma(handle_);
if (ret) {
HWC2_LOGE("Failed to UpdateDisplayGamma for display=%d %d\n", display, ret);
}
ret = drm_->UpdateDisplay3DLut(handle_);
if (ret) {
HWC2_LOGE("Failed to UpdateDisplay3DLut for display=%d %d\n", display, ret);
}
// Reset HwcLayer resource
if (clear_layer && handle_ != HWC_DISPLAY_PRIMARY && !connector_->isCropSplit()) {
// Clear Layers
for (auto& map_layer : layers_) {
map_layer.second.clear();
}
// Bug: #359894
// layers_ not clear may cause error log:
// "E hwc-platform-drm-generic: ImportBuffer fail fd=7,w=-1,h=-1,bo->format=AB24 ..."
layers_.clear();
// Clear Client Target Layer
client_layer_.clear();
}
compositor_ = resource_manager_->GetDrmDisplayCompositor(crtc_);
ret = compositor_->Init(resource_manager_, display);
if (ret) {
ALOGE("Failed display compositor init for display %d (%d)", display, ret);
return HWC2::Error::NoResources;
}
if (init_success_) {
return HWC2::Error::None;
}
planner_ = Planner::CreateInstance(drm_);
if (!planner_) {
ALOGE("Failed to create planner instance for composition");
return HWC2::Error::NoResources;
}
// soc_id
ctx_.soc_id = resource_manager_->getSocId();
// display_id
ctx_.display_id = display;
// display-type
ctx_.display_type = connector_->type();
// vop aclk
ctx_.aclk = crtc_->get_aclk();
// Baseparameter Info
ctx_.baseparameter_info = connector_->baseparameter_info();
// Standard Switch Resolution Mode
ctx_.bStandardSwitchResolution = hwc_get_bool_property("vendor.hwc.enable_display_configs", "false");
HWC2::Error error = ChosePreferredConfig();
if (error != HWC2::Error::None) {
ALOGE("Failed to chose prefererd config for display %d (%d)", display, error);
return error;
}
init_success_ = true;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::CheckDisplayState() {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
int display = static_cast<int>(handle_);
if (!init_success_) {
ALOGE_IF(LogLevel(DBG_ERROR), "Display %d not init success! %s,line=%d", display, __FUNCTION__, __LINE__);
return HWC2::Error::BadDisplay;
}
connector_ = drm_->GetConnectorForDisplay(display);
if (!connector_) {
ALOGE_IF(LogLevel(DBG_ERROR), "Failed to get connector for display %d, %s,line=%d", display, __FUNCTION__,
__LINE__);
return HWC2::Error::BadDisplay;
}
if (connector_->state() != DRM_MODE_CONNECTED) {
// Mirror Primary Display 允许主屏disconnect状态下送显因为Mirror Display连接状态还是正常的
if (connector_->is_connector_mirror_primary() == false) {
ALOGE_IF(LogLevel(DBG_ERROR),
"Connector %u type=%s, type_id=%d, state is DRM_MODE_DISCONNECTED, skip init, %s,line=%d\n",
connector_->id(), drm_->connector_type_str(connector_->type()), connector_->type_id(),
__FUNCTION__, __LINE__);
return HWC2::Error::NoResources;
}
}
crtc_ = drm_->GetCrtcForDisplay(display);
if (!crtc_) {
ALOGE_IF(LogLevel(DBG_ERROR), "Failed to get crtc for display %d, %s,line=%d", display, __FUNCTION__, __LINE__);
return HWC2::Error::BadDisplay;
}
if (!layers_.size()) {
ALOGE_IF(LogLevel(DBG_ERROR), "display %d layer size is %zu, %s,line=%d", display, layers_.size(), __FUNCTION__,
__LINE__);
return HWC2::Error::BadLayer;
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::ChosePreferredConfig() {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
// Fetch the number of modes from the display
uint32_t num_configs;
HWC2::Error err = GetDisplayConfigs(&num_configs, NULL);
if (err != HWC2::Error::None || !num_configs) return err;
if (ctx_.bStandardSwitchResolution) {
err = SetActiveConfig(connector_->active_mode().id());
} else {
err = SetActiveConfig(0);
}
return err;
}
HWC2::Error DrmHwcTwo::HwcDisplay::RegisterVsyncCallback(hwc2_callback_data_t data, hwc2_function_pointer_t func) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
auto callback = std::make_shared<DrmVsyncCallback>(data, func);
vsync_worker_.RegisterCallback(std::move(callback));
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::RegisterInvalidateCallback(hwc2_callback_data_t data, hwc2_function_pointer_t func) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
auto callback = std::make_shared<DrmInvalidateCallback>(data, func);
invalidate_worker_.RegisterCallback(std::move(callback));
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::UnregisterVsyncCallback() {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
;
vsync_worker_.RegisterCallback(NULL);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::UnregisterInvalidateCallback() {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
invalidate_worker_.RegisterCallback(NULL);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::AcceptDisplayChanges() {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) l.second.accept_type_change();
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::CreateLayer(hwc2_layer_t* layer) {
std::unique_lock<std::recursive_mutex> lock(mDisplayMutex_);
layers_.emplace(static_cast<hwc2_layer_t>(layer_idx_), HwcLayer(layer_idx_, drm_));
*layer = static_cast<hwc2_layer_t>(layer_idx_);
++layer_idx_;
HWC2_LOGV_IF("display-id=%" PRIu64 ", layer-id=%" PRIu64, handle_, *layer);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::DestroyLayer(hwc2_layer_t layer) {
std::unique_lock<std::recursive_mutex> lock(mDisplayMutex_);
HWC2_LOGV_IF("display-id=%" PRIu64 ", layer-id=%" PRIu64, handle_, layer);
auto map_layer = layers_.find(layer);
if (map_layer != layers_.end()) {
map_layer->second.clear();
layers_.erase(layer);
return HWC2::Error::None;
} else {
return HWC2::Error::BadLayer;
}
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetActiveConfig(hwc2_config_t* config) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
if (ctx_.bStandardSwitchResolution) {
DrmMode const& mode = connector_->active_mode();
if (mode.id() == 0) return HWC2::Error::BadConfig;
DrmMode const& best_mode = connector_->best_mode();
if (connector_->isHorizontalSplit()) {
ctx_.framebuffer_width = best_mode.h_display() / 2;
ctx_.framebuffer_height = best_mode.v_display();
} else {
ctx_.framebuffer_width = best_mode.h_display();
ctx_.framebuffer_height = best_mode.v_display();
}
*config = mode.id();
} else {
*config = 0;
}
//如果Surfaceflinger查询到当前的ActiveConfig与Surfaceflinger内部保存的一致
//将不会再调用SetActiveConfig,因此需要在这里设置 client_layer_ 参数
if (connector_->isCropSplit()) {
int32_t srcX, srcY, srcW, srcH;
connector_->getCropInfo(&srcX, &srcY, &srcW, &srcH);
hwc_rect_t display_frame = {.left = 0,
.top = 0,
.right = static_cast<int>(ctx_.framebuffer_width),
.bottom = static_cast<int>(ctx_.framebuffer_height)};
client_layer_.SetLayerDisplayFrame(display_frame);
hwc_frect_t source_crop = {
.left = srcX + 0.0f, .top = srcY + 0.0f, .right = srcX + srcW + 0.0f, .bottom = srcY + srcH + 0.0f};
client_layer_.SetLayerSourceCrop(source_crop);
} else {
// Setup the client layer's dimensions
hwc_rect_t display_frame = {.left = 0,
.top = 0,
.right = static_cast<int>(ctx_.framebuffer_width),
.bottom = static_cast<int>(ctx_.framebuffer_height)};
client_layer_.SetLayerDisplayFrame(display_frame);
hwc_frect_t source_crop = {.left = 0.0f,
.top = 0.0f,
.right = ctx_.framebuffer_width + 0.0f,
.bottom = ctx_.framebuffer_height + 0.0f};
client_layer_.SetLayerSourceCrop(source_crop);
}
HWC2_LOGV_IF("display-id=%" PRIu64 " config-id=%d", handle_, *config);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetChangedCompositionTypes(uint32_t* num_elements, hwc2_layer_t* layers,
int32_t* types) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
uint32_t num_changes = 0;
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) {
if (l.second.type_changed()) {
if (layers && num_changes < *num_elements) layers[num_changes] = l.first;
if (types && num_changes < *num_elements)
types[num_changes] = static_cast<int32_t>(l.second.validated_type());
++num_changes;
}
}
if (!layers && !types) *num_elements = num_changes;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetClientTargetSupport(uint32_t width, uint32_t height, int32_t /*format*/,
int32_t dataspace) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
std::pair<uint32_t, uint32_t> min = drm_->min_resolution();
std::pair<uint32_t, uint32_t> max = drm_->max_resolution();
if (width < min.first || height < min.second) return HWC2::Error::Unsupported;
if (width > max.first || height > max.second) return HWC2::Error::Unsupported;
if (dataspace != HAL_DATASPACE_UNKNOWN && dataspace != HAL_DATASPACE_STANDARD_UNSPECIFIED)
return HWC2::Error::Unsupported;
// TODO: Validate format can be handled by either GL or planes
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetColorModes(uint32_t* num_modes, int32_t* modes) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
if (!modes) *num_modes = 1;
if (modes) *modes = HAL_COLOR_MODE_NATIVE;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayAttribute(hwc2_config_t config, int32_t attribute_in, int32_t* value) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
if (ctx_.bStandardSwitchResolution) {
auto mode = std::find_if(sf_modes_.begin(), sf_modes_.end(),
[config](DrmMode const& m) { return m.id() == config; });
if (mode == sf_modes_.end()) {
HWC2_LOGE("Could not find active mode for %d", config);
return HWC2::Error::BadConfig;
}
static const int32_t kUmPerInch = 25400;
uint32_t mm_width = connector_->mm_width();
uint32_t mm_height = connector_->mm_height();
auto attribute = static_cast<HWC2::Attribute>(attribute_in);
switch (attribute) {
case HWC2::Attribute::Width:
*value = mode->h_display();
break;
case HWC2::Attribute::Height:
*value = mode->v_display();
break;
case HWC2::Attribute::VsyncPeriod:
// in nanoseconds
*value = 1000 * 1000 * 1000 / mode->v_refresh();
break;
case HWC2::Attribute::DpiX:
// Dots per 1000 inches
*value = mm_width ? (mode->h_display() * kUmPerInch) / mm_width : -1;
break;
case HWC2::Attribute::DpiY:
// Dots per 1000 inches
*value = mm_height ? (mode->v_display() * kUmPerInch) / mm_height : -1;
break;
// Only Android 14 Support
#if PLATFORM_SDK_VERSION >= 34
case HWC2::Attribute::ConfigGroup:
*value = 0; /* TODO: Add support for config groups */
break;
#endif
default:
*value = -1;
return HWC2::Error::BadConfig;
}
} else {
static const int32_t kUmPerInch = 25400;
uint32_t mm_width = 0;
uint32_t mm_height = 0;
int w = 0;
int h = 0;
int vrefresh = 0;
#ifdef USE_LIBEBOOK
if (isEBook()) {
mm_width = ebook_framebuffer_mmwidth;
mm_height = ebook_framebuffer_mmheight;
w = ctx_.framebuffer_width;
h = ctx_.framebuffer_height;
vrefresh = 10;
auto attribute = static_cast<HWC2::Attribute>(attribute_in);
switch (attribute) {
case HWC2::Attribute::Width:
*value = w;
break;
case HWC2::Attribute::Height:
*value = h;
break;
case HWC2::Attribute::VsyncPeriod:
// in nanoseconds
*value = 1000 * 1000 * 1000 / vrefresh;
break;
case HWC2::Attribute::DpiX:
// Dots per 1000 inches
*value = mm_width ? (w * kUmPerInch) / mm_width : -1;
break;
case HWC2::Attribute::DpiY:
// Dots per 1000 inches
*value = mm_height ? (h * kUmPerInch) / mm_height : -1;
break;
// Only Android 14 Support
#if PLATFORM_SDK_VERSION >= 34
case HWC2::Attribute::ConfigGroup:
*value = 0; /* TODO: Add support for config groups */
break;
#endif
default:
*value = -1;
return HWC2::Error::BadConfig;
}
} else
#endif
{
mm_width = connector_->mm_width();
mm_height = connector_->mm_height();
w = ctx_.framebuffer_width;
h = ctx_.framebuffer_height;
vrefresh = ctx_.vrefresh;
// VRR
const std::vector<int> vrr_mode = connector_->vrr_modes();
if (bVrrDisplay_ && vrr_mode.size() > 1 && config < vrr_mode.size()) {
vrefresh = vrr_mode[config];
}
auto attribute = static_cast<HWC2::Attribute>(attribute_in);
switch (attribute) {
case HWC2::Attribute::Width:
*value = w;
break;
case HWC2::Attribute::Height:
*value = h;
break;
case HWC2::Attribute::VsyncPeriod:
// in nanoseconds
*value = 1000 * 1000 * 1000 / vrefresh;
break;
case HWC2::Attribute::DpiX:
// Dots per 1000 inches
*value = mm_width ? (w * kUmPerInch) / mm_width : -1;
break;
case HWC2::Attribute::DpiY:
// Dots per 1000 inches
*value = mm_height ? (h * kUmPerInch) / mm_height : -1;
break;
// Only Android 14 Support
#if PLATFORM_SDK_VERSION >= 34
case HWC2::Attribute::ConfigGroup:
*value = 0; /* TODO: Add support for config groups */
break;
#endif
default:
*value = -1;
return HWC2::Error::BadConfig;
}
}
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayConfigs(uint32_t* num_configs, hwc2_config_t* configs) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
// Since this callback is normally invoked twice (once to get the count, and
// once to populate configs), we don't really want to read the edid
// redundantly. Instead, only update the modes on the first invocation. While
// it's possible this will result in stale modes, it'll all come out in the
// wash when we try to set the active config later.
if (!configs) {
if (!connector_->ModesReady()) {
int ret = connector_->UpdateModes();
if (ret) {
ALOGE("Failed to update display modes %d", ret);
return HWC2::Error::BadDisplay;
}
}
}
if (ctx_.bStandardSwitchResolution) {
// Since the upper layers only look at vactive/hactive/refresh, height and
// width, it doesn't differentiate interlaced from progressive and other
// similar modes. Depending on the order of modes we return to SF, it could
// end up choosing a suboptimal configuration and dropping the preferred
// mode. To workaround this, don't offer interlaced modes to SF if there is
// at least one non-interlaced alternative and only offer a single WxH@R
// mode with at least the prefered mode from in DrmConnector::UpdateModes()
// TODO: Remove the following block of code until AOSP handles all modes
std::vector<DrmMode> sel_modes;
// Add the preferred mode first to be sure it's not dropped
auto preferred_mode =
std::find_if(connector_->modes().begin(), connector_->modes().end(),
[&](DrmMode const& m) { return m.id() == connector_->get_preferred_mode_id(); });
if (preferred_mode != connector_->modes().end()) sel_modes.push_back(*preferred_mode);
// Add the active mode if different from preferred mode
if (connector_->active_mode().id() != connector_->get_preferred_mode_id())
sel_modes.push_back(connector_->active_mode());
// Cycle over the modes and filter out "similar" modes, keeping only the
// first ones in the order given by DRM (from CEA ids and timings order)
for (const DrmMode& mode : connector_->modes()) {
// TODO: Remove this when 3D Attributes are in AOSP
if (mode.flags() & DRM_MODE_FLAG_3D_MASK) continue;
// TODO: Remove this when the Interlaced attribute is in AOSP
if (mode.flags() & DRM_MODE_FLAG_INTERLACE) {
auto m =
std::find_if(connector_->modes().begin(), connector_->modes().end(), [&mode](DrmMode const& m) {
return !(m.flags() & DRM_MODE_FLAG_INTERLACE) && m.h_display() == mode.h_display() &&
m.v_display() == mode.v_display();
});
if (m == connector_->modes().end()) sel_modes.push_back(mode);
continue;
}
// Search for a similar WxH@R mode in the filtered list and drop it if
// another mode with the same WxH@R has already been selected
// TODO: Remove this when AOSP handles duplicates modes
auto m = std::find_if(sel_modes.begin(), sel_modes.end(), [&mode](DrmMode const& m) {
return m.h_display() == mode.h_display() && m.v_display() == mode.v_display() &&
m.v_refresh() == mode.v_refresh();
});
if (m == sel_modes.end()) sel_modes.push_back(mode);
}
auto num_modes = static_cast<uint32_t>(sel_modes.size());
sf_modes_.swap(sel_modes);
if (!configs) {
*num_configs = num_modes;
return HWC2::Error::None;
}
uint32_t idx = 0;
for (const DrmMode& mode : sel_modes) {
if (idx >= *num_configs) break;
configs[idx++] = mode.id();
}
*num_configs = sf_modes_.size();
#ifdef USE_LIBEBOOK
} else if (isEBook()) {
ctx_.framebuffer_width = ebook_framebuffer_width;
ctx_.framebuffer_height = ebook_framebuffer_height;
ctx_.vrefresh = 10;
if (!configs) {
*num_configs = 1;
return HWC2::Error::None;
}
*num_configs = 1;
configs[0] = 0;
return HWC2::Error::None;
#endif
} else {
UpdateDisplayInfo();
const DrmMode best_mode = connector_->active_mode();
char framebuffer_size[PROPERTY_VALUE_MAX];
uint32_t width = 0, height = 0, vrefresh = 0;
connector_->GetFramebufferInfo(handle_, &width, &height, &vrefresh);
if (width && height) {
ctx_.framebuffer_width = width;
ctx_.framebuffer_height = height;
ctx_.vrefresh = vrefresh ? vrefresh : 60;
} else if (best_mode.h_display() && best_mode.v_display() && best_mode.v_refresh()) {
ctx_.framebuffer_width = best_mode.h_display();
ctx_.framebuffer_height = best_mode.v_display();
ctx_.vrefresh = best_mode.v_refresh();
/*
* RK3588/RK3576Limit to 4096x2160 if large than 2160p
* Other: Limit to 1920x1080 if large than 2160p
*/
bool low_ram_device = property_get_bool("ro.boot.low_ram", false);
if (low_ram_device) {
if (ctx_.framebuffer_height >= 2160 && ctx_.framebuffer_width >= ctx_.framebuffer_height) {
ALOGD("Limit framebuffer for low-ram device");
ctx_.framebuffer_width >>= 1;
ctx_.framebuffer_height >>= 1;
}
} else if (isRK3588(resource_manager_->getSocId()) || isRK3576(resource_manager_->getSocId())) {
if (ctx_.framebuffer_height >= 2160 && ctx_.framebuffer_width >= ctx_.framebuffer_height) {
ctx_.framebuffer_width = ctx_.framebuffer_width * (2160.0 / ctx_.framebuffer_height);
ctx_.framebuffer_height = 2160;
}
} else {
if (ctx_.framebuffer_height >= 2160 && ctx_.framebuffer_width >= ctx_.framebuffer_height) {
ctx_.framebuffer_width = ctx_.framebuffer_width * (1080.0 / ctx_.framebuffer_height);
ctx_.framebuffer_height = 1080;
}
}
} else {
ctx_.framebuffer_width = 1920;
ctx_.framebuffer_height = 1080;
ctx_.vrefresh = 60;
ALOGE("Failed to find available display mode for display %" PRIu64 "\n", handle_);
}
if (connector_->isHorizontalSplit()) {
ctx_.rel_xres = best_mode.h_display() / DRM_CONNECTOR_SPLIT_RATIO;
ctx_.rel_yres = best_mode.v_display();
ctx_.framebuffer_width = ctx_.framebuffer_width / DRM_CONNECTOR_SPLIT_RATIO;
if (handle_ >= DRM_CONNECTOR_SPLIT_MODE_MASK) {
ctx_.rel_xoffset = best_mode.h_display() / DRM_CONNECTOR_SPLIT_RATIO;
ctx_.rel_yoffset = 0; //best_mode.v_display() / 2;
}
} else if (connector_->isCropSplit()) {
int32_t fb_w = 0, fb_h = 0;
connector_->getCropSplitFb(&fb_w, &fb_h);
ctx_.framebuffer_width = fb_w;
ctx_.framebuffer_height = fb_h;
ctx_.rel_xres = best_mode.h_display();
ctx_.rel_yres = best_mode.v_display();
} else {
ctx_.rel_xres = best_mode.h_display();
ctx_.rel_yres = best_mode.v_display();
}
// 动态可变刷新率要求将刷新率上报
if (best_mode.v_refresh() > 0) {
ctx_.vrefresh = best_mode.v_refresh();
}
// AFBC limit
if (handle_ == HWC_DISPLAY_PRIMARY) {
bool disable_afbdc = false;
if (isRK356x(resource_manager_->getSocId())) {
if (ctx_.framebuffer_width % 4 != 0) {
disable_afbdc = true;
HWC2_LOGI("RK356x primary framebuffer size %dx%d not support AFBC, to disable AFBC\n",
ctx_.framebuffer_width, ctx_.framebuffer_height);
}
}
if (ResourceManager::getInstance()->IsGsiSDK()) {
disable_afbdc = true;
HWC2_LOGI("Maybe GSI SDK, to disable AFBC\n");
}
if (disable_afbdc) {
HwcAProperty::getInstance().setProperty("vendor.gralloc.no_afbc_for_fb_target_layer", "1");
}
}
// set display orientation for camera
if (handle_ == HWC_DISPLAY_PRIMARY && ctx_.rel_xres < ctx_.rel_yres)
property_set(PROPERTY_TYPE ".hwc.orient.main", "270");
const std::vector<int> vrr_mode = connector_->vrr_modes();
if (bVrrDisplay_ && vrr_mode.size() > 1) {
if (!configs) {
*num_configs = vrr_mode.size();
return HWC2::Error::None;
}
*num_configs = vrr_mode.size();
for (int index = 0; index <= vrr_mode.size(); index++) {
configs[index] = index;
}
} else {
if (!configs) {
*num_configs = 1;
return HWC2::Error::None;
}
*num_configs = 1;
configs[0] = 0;
}
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayName(uint32_t* size, char* name) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
std::ostringstream stream;
stream << "display-" << connector_->id();
std::string string = stream.str();
size_t length = string.length();
if (!name) {
*size = length;
return HWC2::Error::None;
}
*size = std::min<uint32_t>(static_cast<uint32_t>(length - 1), *size);
strncpy(name, string.c_str(), *size);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayRequests(int32_t* display_requests, uint32_t* num_elements,
hwc2_layer_t* layers, int32_t* layer_requests) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
uint32_t num_request = 0;
if (ResourceManager::getInstance()->IsGsiSDK()) {
HWC2_LOGI_IF("Maybe GSI SDK, to disable AFBC\n");
if (!layers || !layer_requests) {
*num_elements = num_request;
return HWC2::Error::None;
} else {
*display_requests = 0;
return HWC2::Error::None;
}
}
// RK3528 Mali 不支持AFBC
if (gIsRK3528()) {
if (!layers || !layer_requests) {
*num_elements = num_request;
return HWC2::Error::None;
} else {
*display_requests = 0;
return HWC2::Error::None;
}
}
// TODO: I think virtual display should request
// HWC2_DISPLAY_REQUEST_WRITE_CLIENT_TARGET_TO_OUTPUT here
uint32_t client_layer_id = false;
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) {
if (l.second.validated_type() == HWC2::Composition::Client) {
client_layer_id = l.first;
break;
}
}
#if (PLATFORM_SDK_VERSION > 28)
if (client_layer_id > 0 && validate_success_ && !client_layer_.isAfbc()) {
num_request++;
if (display_requests) {
// RK: Reuse HWC2_DISPLAY_REQUEST_FLIP_CLIENT_TARGET definition to
// implement ClientTarget feature.
*display_requests = HWC2_DISPLAY_REQUEST_FLIP_CLIENT_TARGET;
}
} else {
*display_requests = 0;
}
#endif
if (!layers || !layer_requests)
*num_elements = num_request;
else {
layers[0] = client_layer_id;
layer_requests[0] = 0;
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayType(int32_t* type) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
*type = static_cast<int32_t>(type_);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDozeSupport(int32_t* support) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
*support = 0;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetHdrCapabilities(uint32_t* num_types, int32_t* types, float* max_luminance,
float* max_average_luminance, float* min_luminance) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
int display = static_cast<int>(handle_);
int HdrIndex = 0;
if (!connector_) {
ALOGE("%s:Failed to get connector for display %d line=%d", __FUNCTION__, display, __LINE__);
return HWC2::Error::None;
}
if (!connector_->ModesReady()) {
int ret = connector_->UpdateModes();
if (ret) {
ALOGE("Failed to update display modes %d", ret);
return HWC2::Error::None;
}
}
const std::vector<DrmHdr> hdr_support_list = connector_->get_hdr_support_list();
if (types == NULL) {
*num_types = hdr_support_list.size();
return HWC2::Error::None;
}
for (const DrmHdr& hdr_mode : hdr_support_list) {
types[HdrIndex] = hdr_mode.drmHdrType;
*max_luminance = hdr_mode.outMaxLuminance;
*max_average_luminance = hdr_mode.outMaxAverageLuminance;
*min_luminance = hdr_mode.outMinLuminance;
HdrIndex++;
}
*num_types = hdr_support_list.size();
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetReleaseFences(uint32_t* num_elements, hwc2_layer_t* layers, int32_t* fences) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
uint32_t num_layers = 0;
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) {
++num_layers;
if (layers == NULL || fences == NULL) {
continue;
} else if (num_layers > *num_elements) {
ALOGW("Overflow num_elements %d/%d", num_layers, *num_elements);
return HWC2::Error::None;
}
layers[num_layers - 1] = l.first;
fences[num_layers - 1] = l.second.release_fence()->isValid() ? dup(l.second.release_fence()->getFd()) : -1;
if (LogLevel(DBG_VERBOSE))
HWC2_LOGV_IF("Check Layer %" PRIu64 " Release(%d) %s Info: size=%d act=%d signal=%d err=%d", l.first,
l.second.release_fence()->isValid(), l.second.release_fence()->getName().c_str(),
l.second.release_fence()->getSize(), l.second.release_fence()->getActiveCount(),
l.second.release_fence()->getSignaledCount(), l.second.release_fence()->getErrorCount());
// HWC2_LOGD_IF("GetReleaseFences [%" PRIu64 "][%d]",layers[num_layers - 1],fences[num_layers - 1]);
// the new fence semantics for a frame n by returning the fence from frame n-1. For frame 0,
// the adapter returns NO_FENCE.
}
*num_elements = num_layers;
return HWC2::Error::None;
}
bool SortByZpos(const DrmHwcLayer& drmHwcLayer1, const DrmHwcLayer& drmHwcLayer2) {
return drmHwcLayer1.iZpos_ < drmHwcLayer2.iZpos_;
}
HWC2::Error DrmHwcTwo::HwcDisplay::ModifyHwcLayerDisplayFrame(bool only_fb_scale) {
bool need_overscan_by_scale = false;
// RK3588 RK3576不支持Overscan
if (gIsRK3588() || gIsRK3576()) {
need_overscan_by_scale = true;
}
// 隔行扫描分辨率overscan效果比较差
if (connector_ && connector_->current_mode().id() > 0 && connector_->current_mode().interlaced() > 0) {
need_overscan_by_scale = true;
}
// 使能 scale
if (need_overscan_by_scale) {
for (auto& drmLayer : drm_hwc_layers_) {
if (only_fb_scale && !drmLayer.bFbTarget_) continue;
drmLayer.ModifyDisplayFrameForOverscan(&ctx_);
}
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::InitDrmHwcLayer() {
drm_hwc_layers_.clear();
// now that they're ordered by z, add them to the composition
for (auto& hwc2layer : layers_) {
drm_hwc_layers_.emplace_back();
DrmHwcLayer& drmHwclayer = drm_hwc_layers_.back();
hwc2layer.second.PopulateDrmLayer(hwc2layer.first, &drmHwclayer, &ctx_, frame_no_);
}
std::sort(drm_hwc_layers_.begin(), drm_hwc_layers_.end(), SortByZpos);
// 找到可删除的底层黑色的背景图层
int have_skip_layer_zpos = 0;
for (auto& drm_hwc_layer : drm_hwc_layers_) {
for (auto& hwc2layer : layers_) {
if (hwc2layer.first == drm_hwc_layer.uId_) {
// 如果图层是纯色图层并且zpos=0,则跳过该图层使用CRTC的background作为背景色
if (hwc2layer.second.CanSkipSolidColorLayer(have_skip_layer_zpos)) {
have_skip_layer_zpos++;
drm_hwc_layer.bBackgroundSkip_ = true;
if (hwc2layer.second.sf_type() != HWC2::Composition::SolidColor) {
hwc2layer.second.set_validated_type(HWC2::Composition::SolidColor);
}
break;
}
}
}
}
// 遍历所有删除 bBackgroundSkip_ = true 的图层,并重新排序
auto it = std::remove_if(drm_hwc_layers_.begin(), drm_hwc_layers_.end(), [](const DrmHwcLayer& layer) {
if (layer.bBackgroundSkip_) {
// HWC2_LOGI("Delete Background Skip Layer, id=%d, z_order=%d", layer.uId_, layer.iZpos_);
return true;
}
return false;
});
drm_hwc_layers_.erase(it, drm_hwc_layers_.end());
uint32_t client_id = 0;
drm_hwc_layers_.emplace_back();
DrmHwcLayer& client_target_layer = drm_hwc_layers_.back();
client_layer_.PopulateFB(client_id, &client_target_layer, &ctx_, frame_no_, true);
#ifdef USE_LIBPQ
if (gIsRK3576() == 0) {
if (handle_ == 0) {
int ret = 0;
ret = client_layer_.DoSwPq(true, &client_target_layer, &ctx_);
if (ret) {
HWC2_LOGE("ClientLayer DoPq fail, ret = %d", ret);
}
}
}
#endif
ALOGD_HWC2_DRM_LAYER_INFO((DBG_INFO), drm_hwc_layers_);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::ValidatePlanes() {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
int ret;
InitDrmHwcLayer();
// 需要修改 HwcLayer display frame 的情况列举:
// 1. RK3588 RK3576不支持Overscan
// 2. 隔行扫描分辨率 overscan 效果较差
// 3. RK3528 运营商版本需要提供视频显示区域修改接口
ModifyHwcLayerDisplayFrame(false);
std::vector<DrmHwcLayer*> layers;
layers.reserve(drm_hwc_layers_.size());
for (size_t i = 0; i < drm_hwc_layers_.size(); ++i) {
layers.push_back(&drm_hwc_layers_[i]);
if (drm_hwc_layers_[i].bUpdate_) {
// 如果存在图层更新,则关闭静态桌面优化
static_screen_opt_ = false;
}
}
std::vector<PlaneGroup*> plane_groups;
DrmDevice* drm = crtc_->getDrmDevice();
plane_groups.clear();
std::vector<PlaneGroup*> all_plane_groups = drm->GetPlaneGroups();
for (auto& plane_group : all_plane_groups) {
if (plane_group->acquire(1 << crtc_->pipe(), handle_)) {
// RK3576平台动态迁移功能如果需要disable的图层则不进行策略匹配
if (plane_group->is_will_disable() == false) {
plane_groups.push_back(plane_group);
} else {
HWC2_LOGD_IF("%s will disable, display-id(%" PRIi64 "->%" PRIi64 ") crtc_mask(0x%" PRIx32
" -> 0x%" PRIx32 ")",
plane_group->planes[0]->name(), plane_group->possible_display_,
plane_group->next_possible_display_, plane_group->current_crtc_, plane_group->next_crtc_);
continue;
}
}
}
std::tie(ret, composition_planes_) =
planner_->TryHwcPolicy(layers, plane_groups, crtc_, static_screen_opt_ || force_gles_);
if (ret) {
ALOGE("First, GLES policy fail ret=%d", ret);
return HWC2::Error::BadConfig;
}
for (auto& drm_hwc_layer : drm_hwc_layers_) {
if (drm_hwc_layer.bFbTarget_) {
if (drm_hwc_layer.bAfbcd_)
client_layer_.EnableAfbc();
else
client_layer_.DisableAfbc();
continue;
}
if (drm_hwc_layer.bMatch_) {
auto map_hwc2layer = layers_.find(drm_hwc_layer.uId_);
map_hwc2layer->second.set_validated_type(HWC2::Composition::Device);
switch (map_hwc2layer->second.sf_type()) {
case HWC2::Composition::Device:
case HWC2::Composition::Sideband:
case HWC2::Composition::SolidColor:
case HWC2::Composition::Cursor:
map_hwc2layer->second.set_validated_type(map_hwc2layer->second.sf_type());
if (drm_hwc_layer.bUseSr_) {
ALOGD_IF(LogLevel(DBG_INFO), "[%.4" PRIu32 "]=Device-Sr : %s", drm_hwc_layer.uId_,
drm_hwc_layer.sLayerName_.c_str());
} else if (drm_hwc_layer.bUseMemc_) {
ALOGD_IF(LogLevel(DBG_INFO), "[%.4" PRIu32 "]=Device-Memc : %s", drm_hwc_layer.uId_,
drm_hwc_layer.sLayerName_.c_str());
} else {
ALOGD_IF(LogLevel(DBG_INFO), "[%.4" PRIu32 "]=%s : %s", drm_hwc_layer.uId_,
to_string(map_hwc2layer->second.validated_type()).c_str(),
drm_hwc_layer.sLayerName_.c_str());
}
break;
case HWC2::Composition::Client:
map_hwc2layer->second.set_validated_type(HWC2::Composition::Device);
ALOGD_IF(LogLevel(DBG_INFO), "[%.4" PRIu32 "]=%s : %s", drm_hwc_layer.uId_,
to_string(map_hwc2layer->second.validated_type()).c_str(),
drm_hwc_layer.sLayerName_.c_str());
break;
default:
HWC2_LOGE("invalid Composition =%d", map_hwc2layer->second.sf_type());
}
} else {
auto map_hwc2layer = layers_.find(drm_hwc_layer.uId_);
map_hwc2layer->second.set_validated_type(HWC2::Composition::Client);
ALOGD_IF(LogLevel(DBG_INFO), "[%.4" PRIu32 "]=Client : %s", drm_hwc_layer.uId_,
drm_hwc_layer.sLayerName_.c_str());
}
}
#if (defined USE_LIBSR) || (defined USE_LIBSVEP_MEMC)
// Update svep state.
UpdateSvepState();
#endif
return HWC2::Error::None;
}
void DrmHwcTwo::HwcDisplay::UpdateSvepState() {
// 只有主屏可以开启SVEP模式其他屏幕不需要更新SVEP状态
if (handle_ > 0) return;
bool exist_svep_layer = std::any_of(drm_hwc_layers_.begin(), drm_hwc_layers_.end(), [](const auto& drm_hwc_layer) {
return drm_hwc_layer.bUseSr_ || drm_hwc_layer.bUseMemc_;
});
if (exist_svep_layer != bLastSvepState_) {
// story last_svep_state
bLastSvepState_ = exist_svep_layer;
if (exist_svep_layer) {
property_set("vendor.hwc.svep_state", "1");
} else {
property_set("vendor.hwc.svep_state", "0");
}
// update ddr state
int fd_ddr_state = open("/sys/class/devfreq/dmc/system_status", O_WRONLY);
if (fd_ddr_state < 0) {
HWC2_LOGD_IF("failed to open /sys/class/devfreq/dmc/system_status ret =%d", fd_ddr_state);
} else {
if (exist_svep_layer) {
// S 状态是专门提供给SVEP的场景变频, 进入SVEP场景变频
write(fd_ddr_state, "S", sizeof(char));
} else {
// s 状态是专门提供给SVEP的场景变频, 退出SVEP场景变频
write(fd_ddr_state, "s", sizeof(char));
}
close(fd_ddr_state);
}
}
return;
}
hwc2_drm_display_t* DrmHwcTwo::HwcDisplay::GetDisplayCtxPtr() {
return &ctx_;
}
int DrmHwcTwo::HwcDisplay::ImportBuffers() {
int ret = 0;
// 匹配 DrmPlane 图层,请求获取 GemHandle
bool use_client_layer = false;
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) {
if (l.second.validated_type() == HWC2::Composition::Client) {
use_client_layer = true;
}
for (auto& drm_hwc_layer : drm_hwc_layers_) {
// 如果图层没有采用Overlay,则不需要获取GemHandle
if (!drm_hwc_layer.bMatch_) continue;
#if (defined USE_LIBSR) || (defined USE_LIBSVEP_MEMC)
// 如果是超分处理后的图层已经更新了GemHandle参数则不再获取GemHandle
if (drm_hwc_layer.bUseSr_) continue;
// 如果是超分处理后的图层已经更新了GemHandle参数则不再获取GemHandle
if (drm_hwc_layer.bUseMemc_) continue;
#endif
// 如果是RGA处理后的图层已经更新了GemHandle参数则不再获取GemHandle
if (drm_hwc_layer.bUseRga_) continue;
// 如果是RGA处理后的图层已经更新了GemHandle参数则不再获取GemHandle
if (drm_hwc_layer.bBackgraoundLayer_) continue;
#ifdef USE_LIBPQ_HWPQ
// 如果是HWPQ处理后的图层已经更新了GemHandle参数则不再获取GemHandle
if (drm_hwc_layer.bUseHwpqScale_) continue;
#endif
#ifdef RK3528
// 当前状态为启用预缩小,但是解码端数据还没准备号,需要用本地的黑帧临时送显
if (drm_hwc_layer.bNeedPreScale_ && drm_hwc_layer.bIsPreScale_ == false && drm_hwc_layer.bUseBlackBuffer_)
continue;
#endif
// SidebandStream 不需要获取GemHandle
if (drm_hwc_layer.bSidebandStreamLayer_) continue;
if (drm_hwc_layer.uId_ == l.first) {
ret = l.second.initOrGetGemhanleFromCache(&drm_hwc_layer);
if (ret) {
ALOGE("Failed to get_gemhanle layer-id=%" PRIu64 ", ret=%d", l.first, ret);
return ret;
}
}
}
}
// 若存在 GPU 合成, 则 ClientLayer 请求获取 GemHandle
if (use_client_layer) {
for (auto& drm_hwc_layer : drm_hwc_layers_) {
if (drm_hwc_layer.bFbTarget_) {
// 如果是RGA处理后的图层已经更新了GemHandle参数则不再获取GemHandle
if (drm_hwc_layer.bUseRga_) continue;
uint32_t client_id = 0;
client_layer_.PopulateFB(client_id, &drm_hwc_layer, &ctx_, frame_no_, false);
ret = client_layer_.initOrGetGemhanleFromCache(&drm_hwc_layer);
if (ret) {
ALOGE("Failed to get_gemhanle client_layer, ret=%d", ret);
return ret;
}
if (client_layer_.isAfbc() != fourcc_mod_is_vendor(drm_hwc_layer.uModifier_, ARM)) {
//如果AFBC状态与匹配的状态不一致说明Client layer可能下发失败
//此状态一般热插拔后第一帧复现,由于热插拔有强制刷新,后续必然存在正常下发的帧,丢弃第一帧影响不大。
HWC2_LOGW("Client Layer AFBC %s not match client buffer modifier 0x%" PRIx64 " skip frame.",
client_layer_.isAfbc() ? "[Enabled]" : "[Disabled]", drm_hwc_layer.uModifier_);
return -1;
}
#ifdef USE_LIBPQ
#ifdef USE_LIBPQ_HWPQ
if (gIsRK3576()) {
if (drm_hwc_layer.uWinType_ == PLANE_RK3576_CLUSTER0_WIN0 && crtc_->get_port_id() == 0) {
int pq_mode = HwcAProperty::getInstance().getIntWithInterval("persist.vendor.tvinput.rkpq.mode",
500, 0);
if (pq_mode == 1) {
ctx_.use_pq_fb = true;
ResourceManager::getInstance()->GetDrmPq()->RunHwPqUiMode(drm_hwc_layers_);
} else {
ctx_.use_pq_fb = false;
// 如果关闭了HWPQ则清除缓存
if (pq_mode == 0) {
ResourceManager::getInstance()->GetDrmPq()->ClearCache();
}
drm_hwc_layer.hwPqReg_ = NULL;
}
}
} else
#endif
{
if (handle_ == 0) {
ret = client_layer_.DoSwPq(false, &drm_hwc_layer, &ctx_);
if (ret) {
HWC2_LOGE("ClientLayer DoPq fail, ret = %d", ret);
}
}
}
#endif
}
}
ModifyHwcLayerDisplayFrame(true);
}
// 所有匹配 DrmPlane 图层,请求 Import 获取 FbId
for (auto& drm_hwc_layer : drm_hwc_layers_) {
if (!use_client_layer && drm_hwc_layer.bFbTarget_) continue;
// 若不是Overlay图层则不进行ImportBuffer
if (!drm_hwc_layer.bMatch_) continue;
// SidebandStream 图层不需要执行 import 操作
if (drm_hwc_layer.bSidebandStreamLayer_) continue;
// Memc 图层不需要执行 import 操作
if (drm_hwc_layer.bUseMemc_) continue;
// 执行ImportBuffer,获取FbId
ret = drm_hwc_layer.ImportBuffer(importer_.get());
if (ret) {
ALOGE("Failed to import layer, ret=%d", ret);
return ret;
}
}
return ret;
}
HWC2::Error DrmHwcTwo::HwcDisplay::CreateEmptyComposition() {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
int ret;
std::unique_ptr<DrmDisplayComposition> composition = compositor_->CreateComposition();
composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_, handle_);
// 利用 vendor.hwc.disable_releaseFence 属性强制关闭ReleaseFence主要用于调试
int disable_releaseFence =
HwcAProperty::getInstance().getIntWithInterval("vendor.hwc.disable_releaseFence", 1000, 0);
sp<ReleaseFence> rf = ReleaseFence::NO_FENCE;
if (disable_releaseFence == 0) {
rf = composition->CreateReleaseFence(sync_timeline_);
}
// 配置 ReleaseFence
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) {
l.second.set_release_fence(rf);
}
// 配置 RetireFence, client_layer_::ReleaseFence 作为 RetireFence
client_layer_.set_release_fence(rf);
// 配置 HDR mode
composition->SetDisplayHdrMode(ctx_.hdr_mode, ctx_.dataspace);
// 配置丢帧模式
composition->SetDropMode(resource_manager_->IsCompositionDropMode());
// 配置Overscan信息
composition->SetOverscan(ctx_.left_margin, ctx_.top_margin, ctx_.right_margin, ctx_.bottom_margin);
ret = compositor_->QueueComposition(std::move(composition));
if (ret) {
HWC2_LOGE("display_id=%" PRIu64 " frame_no=%d QueueComposition fail ret=%d", handle_, frame_no_, ret);
return HWC2::Error::BadParameter;
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::CreateFrameComposition() {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
int ret;
std::vector<DrmCompositionDisplayLayersMap> layers_map;
layers_map.emplace_back();
DrmCompositionDisplayLayersMap& map = layers_map.back();
map.display = static_cast<int>(handle_);
map.geometry_changed = true;
ret = ImportBuffers();
if (ret) {
HWC2_LOGE("Failed to ImportBuffers, ret=%d", ret);
return HWC2::Error::NoResources;
}
for (auto& drm_hwc_layer : drm_hwc_layers_) {
if (drm_hwc_layer.bMatch_) map.layers.emplace_back(std::move(drm_hwc_layer));
}
std::unique_ptr<DrmDisplayComposition> composition = compositor_->CreateComposition();
composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_, handle_);
// TODO: Don't always assume geometry changed
ret = composition->SetLayers(map.layers.data(), map.layers.size(), true);
if (ret) {
ALOGE("Failed to set layers in the composition ret=%d", ret);
return HWC2::Error::BadLayer;
}
for (auto& composition_plane : composition_planes_)
ret = composition->AddPlaneComposition(std::move(composition_plane));
ret = composition->DisableUnusedPlanes();
if (ret) {
ALOGE("Failed to plan the composition ret=%d", ret);
return HWC2::Error::BadConfig;
}
// 利用 vendor.hwc.disable_releaseFence 属性强制关闭ReleaseFence主要用于调试
int disable_releaseFence =
HwcAProperty::getInstance().getIntWithInterval("vendor.hwc.disable_releaseFence", 1000, 0);
sp<ReleaseFence> rf = ReleaseFence::NO_FENCE;
if (disable_releaseFence == 0) {
rf = composition->CreateReleaseFence(sync_timeline_);
}
// 配置 ReleaseFence
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) {
l.second.set_release_fence(rf);
}
// 配置 RetireFence, client_layer_::ReleaseFence 作为 RetireFence
client_layer_.set_release_fence(rf);
// 配置 HDR mode
composition->SetDisplayHdrMode(ctx_.hdr_mode, ctx_.dataspace);
// 配置丢帧模式
composition->SetDropMode(resource_manager_->IsCompositionDropMode());
// 配置Overscan信息
composition->SetOverscan(ctx_.left_margin, ctx_.top_margin, ctx_.right_margin, ctx_.bottom_margin);
// 配置 ExpectedPresentTime
composition->SetExpectedPresentTime(iExpectedPresentTime_);
ret = compositor_->QueueComposition(std::move(composition));
if (ret) {
HWC2_LOGE("display_id=%" PRIu64 " frame_no=%d QueueComposition fail ret=%d", handle_, frame_no_, ret);
return HWC2::Error::BadParameter;
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::PresentVirtualDisplay(int32_t* retire_fence) {
ATRACE_CALL();
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
*retire_fence = -1;
// 若虚拟屏图层数为0则不做任何处理
if (!layers_.size()) {
HWC2_LOGI_IF("display %" PRIu64 " layer size is %zu", handle_, layers_.size());
return HWC2::Error::None;
}
if (bUseWriteBack_ && resource_manager_->isWBMode() && !resource_manager_->IsDisableHwVirtualDisplay() &&
output_layer_.GetBufferInfo() != NULL) {
if (resource_manager_->isWBMode()) {
const std::shared_ptr<LayerInfoCache> bufferinfo = output_layer_.GetBufferInfo();
// 每个目标的Buffer都需要初始化YUV数据
if (!mHasResetBufferId_.count(bufferinfo->uBufferId_)) {
rga_buffer_t src;
rga_buffer_t dst;
rga_buffer_t pat;
im_rect src_rect;
im_rect dst_rect;
im_rect pat_rect;
memset(&src, 0x0, sizeof(rga_buffer_t));
memset(&dst, 0x0, sizeof(rga_buffer_t));
memset(&pat, 0x0, sizeof(rga_buffer_t));
memset(&src_rect, 0x0, sizeof(im_rect));
memset(&dst_rect, 0x0, sizeof(im_rect));
memset(&pat_rect, 0x0, sizeof(im_rect));
std::shared_ptr<DrmBuffer> resetBuffer = resource_manager_->GetResetWBBuffer();
// Set src buffer info
src.fd = resetBuffer->GetFd();
src.width = resetBuffer->GetWidth();
src.height = resetBuffer->GetHeight();
src.wstride = resetBuffer->GetStride();
src.hstride = resetBuffer->GetHeightStride();
src.format = resetBuffer->GetFormat();
// Set src rect info
src_rect.x = 0;
src_rect.y = 0;
src_rect.width = resetBuffer->GetWidth();
src_rect.height = resetBuffer->GetHeight();
// Set dst buffer info
dst.fd = bufferinfo->uniqueFd_.get();
dst.width = bufferinfo->iWidth_;
dst.height = bufferinfo->iHeight_;
dst.wstride = bufferinfo->iStride_;
dst.hstride = bufferinfo->iHeightStride_;
// 虚拟屏的格式通常为 HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED
// 由 Gralloc 决定具体格式,对应格式需要查询 uFourccFormat_ 才能确定
// 实际申请格式由于RGA不支持Fourcc格式所以要做个转换。
switch (bufferinfo->uFourccFormat_) {
case DRM_FORMAT_BGR888:
dst.format = HAL_PIXEL_FORMAT_RGB_888;
break;
case DRM_FORMAT_ARGB8888:
dst.format = HAL_PIXEL_FORMAT_BGRA_8888;
break;
case DRM_FORMAT_XBGR8888:
// dst.format = HAL_PIXEL_FORMAT_RGBX_8888;
dst.format = HAL_PIXEL_FORMAT_BGRA_8888;
break;
case DRM_FORMAT_ABGR8888:
dst.format = HAL_PIXEL_FORMAT_RGBA_8888;
break;
case DRM_FORMAT_ABGR2101010:
dst.format = HAL_PIXEL_FORMAT_RGBA_1010102;
break;
//Fix color error in NenaMark2 and Taiji
case DRM_FORMAT_BGR565:
dst.format = HAL_PIXEL_FORMAT_RGB_565;
break;
case DRM_FORMAT_YVU420:
dst.format = HAL_PIXEL_FORMAT_YV12;
break;
case DRM_FORMAT_NV12:
dst.format = HAL_PIXEL_FORMAT_YCrCb_NV12;
break;
case DRM_FORMAT_NV12_10:
dst.format = HAL_PIXEL_FORMAT_YCrCb_NV12_10;
break;
default:
ALOGE("Cannot convert uFourccFormat_=%c%c%c%c to hal format, use default format nv12.",
bufferinfo->uFourccFormat_, bufferinfo->uFourccFormat_ >> 8,
bufferinfo->uFourccFormat_ >> 16, bufferinfo->uFourccFormat_ >> 24);
dst.format = HAL_PIXEL_FORMAT_YCrCb_NV12;
}
dst_rect.x = 0;
dst_rect.y = 0;
dst_rect.width = bufferinfo->iWidth_;
dst_rect.height = bufferinfo->iHeight_;
dst_rect.x = ALIGN_DOWN(dst_rect.x, 2);
dst_rect.y = ALIGN_DOWN(dst_rect.y, 2);
dst_rect.width = ALIGN_DOWN(dst_rect.width, 2);
dst_rect.height = ALIGN_DOWN(dst_rect.height, 2);
if (AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 == (bufferinfo->uModifier_ & AFBC_FORMAT_MOD_BLOCK_SIZE_16x16)) {
dst.rd_mode = IM_FBC_MODE;
}
IM_STATUS im_state = IM_STATUS_NOERROR;
;
im_opt_t imOpt;
memset(&imOpt, 0x00, sizeof(im_opt_t));
// 只有RK3588需要指定RGA3核心因为RGA3支持4G以上地址以及由于RGA2/RGA3放大算法差异
// 所以需要指定RGA3完成后级放大处理
if (gIsRK3588()) {
imOpt.core = IM_SCHEDULER_RGA3_CORE0 | IM_SCHEDULER_RGA3_CORE1;
}
// Call Im2d 格式转换
im_state = improcess(src, dst, pat, src_rect, dst_rect, pat_rect, 0, NULL, &imOpt, 0);
if (im_state == IM_STATUS_SUCCESS) {
HWC2_LOGD_IF("call im2d reset Success");
mHasResetBufferId_.insert(bufferinfo->uBufferId_);
} else {
HWC2_LOGE("call im2d reset fail, ret=%d Error=%s", im_state, imStrError(im_state));
}
}
rga_buffer_t dst;
im_rect dst_rect;
memset(&dst, 0x00, sizeof(rga_buffer_t));
memset(&dst_rect, 0x00, sizeof(im_rect));
// Set dst buffer info
dst.fd = bufferinfo->uniqueFd_.get();
dst.width = bufferinfo->iWidth_;
dst.height = bufferinfo->iHeight_;
dst.wstride = bufferinfo->iStride_;
dst.hstride = bufferinfo->iHeightStride_;
// 虚拟屏的格式通常为 HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED
// 由 Gralloc 决定具体格式,对应格式需要查询 uFourccFormat_ 才能确定
// 实际申请格式由于RGA不支持Fourcc格式所以垚做个转换。
switch (bufferinfo->uFourccFormat_) {
case DRM_FORMAT_BGR888:
dst.format = HAL_PIXEL_FORMAT_RGB_888;
break;
case DRM_FORMAT_ARGB8888:
dst.format = HAL_PIXEL_FORMAT_BGRA_8888;
break;
case DRM_FORMAT_XBGR8888:
// dst.format = HAL_PIXEL_FORMAT_RGBX_8888;
dst.format = HAL_PIXEL_FORMAT_BGRA_8888;
break;
case DRM_FORMAT_ABGR8888:
dst.format = HAL_PIXEL_FORMAT_RGBA_8888;
break;
case DRM_FORMAT_ABGR2101010:
dst.format = HAL_PIXEL_FORMAT_RGBA_1010102;
break;
//Fix color error in NenaMark2 and Taiji
case DRM_FORMAT_BGR565:
dst.format = HAL_PIXEL_FORMAT_RGB_565;
break;
case DRM_FORMAT_YVU420:
dst.format = HAL_PIXEL_FORMAT_YV12;
break;
case DRM_FORMAT_NV12:
dst.format = HAL_PIXEL_FORMAT_YCrCb_NV12;
break;
case DRM_FORMAT_NV12_10:
dst.format = HAL_PIXEL_FORMAT_YCrCb_NV12_10;
break;
default:
ALOGE("Cannot convert uFourccFormat_=%c%c%c%c to hal format, use default format nv12.",
bufferinfo->uFourccFormat_, bufferinfo->uFourccFormat_ >> 8, bufferinfo->uFourccFormat_ >> 16,
bufferinfo->uFourccFormat_ >> 24);
dst.format = HAL_PIXEL_FORMAT_YCrCb_NV12;
}
// 为了确保录屏数据宽高比一致,故需要对目标的区域做修正
DrmMode wbMode = resource_manager_->GetWBMode();
if (wbMode.width() != bufferinfo->iWidth_ || wbMode.height() != bufferinfo->iHeight_) {
if ((wbMode.width() * 1.0 / bufferinfo->iWidth_) > (wbMode.height() * 1.0 / bufferinfo->iHeight_)) {
dst_rect.width = bufferinfo->iWidth_;
dst_rect.height = (int)(bufferinfo->iWidth_ * wbMode.height() / (wbMode.width() * 1.0));
dst_rect.x = 0;
dst_rect.y = (bufferinfo->iHeight_ - dst_rect.height) / 2;
} else {
dst_rect.width = (int)((bufferinfo->iHeight_) * wbMode.width() / (wbMode.height() * 1.0));
dst_rect.height = bufferinfo->iHeight_;
dst_rect.x = (bufferinfo->iWidth_ - dst_rect.width) / 2;
dst_rect.y = 0;
}
} else {
dst_rect.x = 0;
dst_rect.y = 0;
dst_rect.width = bufferinfo->iWidth_;
dst_rect.height = bufferinfo->iHeight_;
}
dst_rect.x = ALIGN_DOWN(dst_rect.x, 2);
dst_rect.y = ALIGN_DOWN(dst_rect.y, 2);
dst_rect.width = ALIGN_DOWN(dst_rect.width, 2);
dst_rect.height = ALIGN_DOWN(dst_rect.height, 2);
if (AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 == (bufferinfo->uModifier_ & AFBC_FORMAT_MOD_BLOCK_SIZE_16x16)) {
dst.rd_mode = IM_FBC_MODE;
}
int ret = resource_manager_->OutputWBBuffer((int)handle_, dst, dst_rect, retire_fence, &wb_frame_no_);
if (ret) {
HWC2_LOGE("OutputWBBuffer fail!");
}
// 添加调试接口抓打印传递给SurfaceFlinger的 Buffer
if (HwcAProperty::getInstance().getBoolWithInterval("vendor.dump", 500, false)) {
output_layer_.DumpData(frame_no_, "W");
}
}
} else {
if (client_layer_.acquire_fence() != NULL) {
if (client_layer_.acquire_fence()->wait(1500)) {
HWC2_LOGE("WB client layer wait acquirefence 1500ms timeout!");
}
}
}
++frame_no_;
return HWC2::Error::None;
}
#ifdef USE_LIBEBOOK
HWC2::Error DrmHwcTwo::HwcDisplay::PresentEBookDisplay(int32_t* retire_fence) {
ATRACE_CALL();
*retire_fence = -1;
// 如果电源模式是PowerOff则不送显
if (mPowerMode_ != HWC2::PowerMode::On) {
++frame_no_;
return HWC2::Error::None;
}
const std::shared_ptr<LayerInfoCache> info = client_layer_.GetBufferInfo();
if (info != NULL) {
// 5. 设置源图像参数
EBookImageInfo src;
src.mBufferInfo_.iFd_ = info->uniqueFd_.get();
src.mBufferInfo_.iWidth_ = info->iWidth_;
src.mBufferInfo_.iHeight_ = info->iHeight_;
src.mBufferInfo_.iFormat_ = info->uFourccFormat_;
src.mBufferInfo_.iStride_ = info->iStride_;
src.mBufferInfo_.iHeightStride_ = info->iHeightStride_;
src.mBufferInfo_.uBufferId_ = info->uBufferId_;
src.mBufferInfo_.iSize_ = info->iSize_;
src.mAcquireFence_.Set(dup(client_layer_.acquire_fence()->getFd()));
src.mCrop_.iLeft_ = 0;
src.mCrop_.iTop_ = 0;
src.mCrop_.iRight_ = ebook_framebuffer_width;
src.mCrop_.iBottom_ = ebook_framebuffer_height;
if (info->uModifier_) {
src.mBufferInfo_.uMask_ = EBookBufferMask::EB_AFBC_FORMATE;
}
if (validate_success_) {
// 6. Commit
int finish_fence = -1;
EBookError error = mEBookApi_->Commit(&src, current_mode_, &finish_fence);
if (error != EBookError::None) {
HWC2_LOGE("EBook RunAsync fail\n");
return HWC2::Error::BadDisplay;
}
last_mode_ = current_mode_;
if (finish_fence > 0) {
*retire_fence = finish_fence;
}
}
// 应用在休眠模式与PowerOff模式会传递名为“EBOOK_STANDBY”或者“EBOOK_POWEROFF”图层
// HWC 需要在检测到目标图层后将当前帧作为最后一帧提交至EBook驱动直到PowerOn请求
// 再恢复正常显示
if (ebook_commit_last_frame_and_stop_) {
ebook_stop_commit_util_power_on_ = true;
// 通常PowerOff后系统会清空所有图层故需要提交完成后将 ebook_commit_last_frame_and_stop_ 置为false
// 否则会干扰下次提交
ebook_commit_last_frame_and_stop_ = false;
}
}
++frame_no_;
return HWC2::Error::None;
}
#endif
void DrmHwcTwo::HwcDisplay::CheckForSplitModeTimeline() {
int pipeline_timeline = HwcAProperty::getInstance().getIntWithInterval(DRM_XML_SYS_UPDATE, 1000, -1);
//Only Primary display check for cropsplit mode update
if (handle_ == 0 && pipeline_timeline > 0 && drm_->IsCheckDisplayPipeline(pipeline_timeline)) {
DrmEvent event;
event.type = DISPLAY_PIPELINE_UPDATE_EVENT;
g_ctx->eventWorker_.SendDrmEvent(event);
return;
}
pipeline_timeline = HwcAProperty::getInstance().getIntWithInterval(DRM_XML_VENDOR_UPDATE, 1000, -1);
//Only Primary display check for cropsplit mode update
if (handle_ == 0 && pipeline_timeline > 0 && drm_->IsCheckDisplayPipeline(pipeline_timeline)) {
DrmEvent event;
event.type = DISPLAY_PIPELINE_UPDATE_EVENT;
g_ctx->eventWorker_.SendDrmEvent(event);
return;
}
}
HWC2::Error DrmHwcTwo::HwcDisplay::PresentDisplay(int32_t* retire_fence) {
ATRACE_CALL();
if (isVirtual()) {
return PresentVirtualDisplay(retire_fence);
}
#ifdef USE_LIBEBOOK
if (isEBook()) {
return PresentEBookDisplay(retire_fence);
}
#endif
DestructExecutor<DrmHwcTwo::HwcDisplay> check_split_timeline(this, &HwcDisplay::CheckForSplitModeTimeline);
int32_t merge_retire_fence = -1;
// 强制断开的屏幕不处理任何逻辑
if (force_disconneted_) {
HWC2_LOGE_IF("force_disconneted_=%d skip.", force_disconneted_);
*retire_fence = merge_retire_fence;
return HWC2::Error::None;
}
// 拼接主屏需要遍历其他拼接子屏幕
if (connector_->IsSplitPrimary()) {
DoMirrorDisplay(&merge_retire_fence);
}
if (!init_success_) {
HWC2_LOGE_IF("init_success_=%d skip.", init_success_);
*retire_fence = merge_retire_fence;
return HWC2::Error::None;
}
DumpAllLayerData();
HWC2::Error ret;
ret = CheckDisplayState();
if (ret != HWC2::Error::None || !validate_success_ || connector_->type() == DRM_MODE_CONNECTOR_VIRTUAL) {
ALOGE_IF(LogLevel(DBG_ERROR), "Check display %" PRIu64 " state fail %s, %s,line=%d", handle_,
validate_success_ ? "" : "or validate fail.", __FUNCTION__, __LINE__);
ClearDisplay();
// 创建 empty composition更新 ReleaseFence / RetireFence 并立即 Signal
// Bug: #566932 / #489238 并发对 sp<ReleaseFence> 修改(赋值)操作低概率会引起内存异常问题
// 故将对 sp<ReleaseFence> 的操作移动到主线程进行处理
CreateEmptyComposition();
} else {
ret = CreateFrameComposition();
if (ret == HWC2::Error::BadLayer) {
// Can we really have no client or device layers?
*retire_fence = merge_retire_fence;
return HWC2::Error::None;
}
}
if (merge_retire_fence > 0) {
if (client_layer_.release_fence()->isValid()) {
char acBuf[32];
sprintf(acBuf, "RTD%" PRIu64 "M-FN%d-%d", handle_, frame_no_, 0);
sp<ReleaseFence> rt = sp<ReleaseFence>(new ReleaseFence(merge_retire_fence, acBuf));
*retire_fence = rt->merge(client_layer_.release_fence()->getFd(), acBuf);
} else {
*retire_fence = merge_retire_fence;
}
} else {
// The retire fence returned here is for the last frame, so return it and
// promote the next retire fence
*retire_fence = client_layer_.release_fence()->isValid() ? dup(client_layer_.release_fence()->getFd()) : -1;
if (LogLevel(DBG_DEBUG)) {
HWC2_LOGD_IF("Return RetireFence(%d) %s frame = %d Info: size=%d act=%d signal=%d err=%d",
client_layer_.release_fence()->isValid(), client_layer_.release_fence()->getName().c_str(),
frame_no_, client_layer_.release_fence()->getSize(),
client_layer_.release_fence()->getActiveCount(),
client_layer_.release_fence()->getSignaledCount(),
client_layer_.release_fence()->getErrorCount());
}
}
++frame_no_;
UpdateTimerState(!static_screen_opt_);
/* 解决 DynamicDisplayMode 导致SurfaceFlinger奔溃问题, Crash Log如下:
F DEBUG : id: 2873, tid: 2873, name: surfaceflinger >>> /system/bin/surfaceflinger
F DEBUG : backtrace:
F DEBUG : #00 pc 00000000000c1848 /system/lib64/libsurfaceflinger.so (android::sp<android::Fence>::operator=(android::Fence*)+68) (BuildId: cf81f72dadf878a95979872a8edad889)
F DEBUG : #01 pc 00000000000c17d4 /system/lib64/libsurfaceflinger.so (android::HWC2::impl::Display::present(android::sp<android::Fence>*)+104) (BuildId: cf81f72dadf878a95979872a8edad889)
F DEBUG : #02 pc 00000000000ca2fc /system/lib64/libsurfaceflinger.so (android::impl::HWComposer::presentAndGetReleaseFences(android::DisplayId)+568) (BuildId: cf81f72dadf878a95979872a8edad889)
F DEBUG : #03 pc 0000000000141330 /system/lib64/libsurfaceflinger.so (android::compositionengine::impl::Display::presentAndGetFrameFences()+132) (BuildId: cf81f72dadf878a95979872a8edad889)
问题主要原因在于原方案,会导致 main_thread callback 回 SurfaceFlinger直接将当前Display资源删除
导致PresentDisplay接口返回后相关资源被删除引发空指针crash.
解决方案为单独创建 eventWorker_ 线程调用SurfaceFlinger callback不使用 main_thread 则不会删除 display 资源
*/
if (IsActiveModeChange()) {
DrmEvent event;
event.type = DISPLAY_MODE_UPDATE_EVENT;
event.display_id = (int)handle_;
event.connection = DRM_MODE_CONNECTED;
g_ctx->eventWorker_.SendDrmEvent(event);
ActiveModeChange(false);
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetActiveConfig(hwc2_config_t config) {
HWC2_LOGV_IF("display-id=%" PRIu64 " config=%d", handle_, config);
if (ctx_.bStandardSwitchResolution) {
auto mode = std::find_if(sf_modes_.begin(), sf_modes_.end(),
[config](DrmMode const& m) { return m.id() == config; });
if (mode == sf_modes_.end()) {
HWC2_LOGE("Could not find active mode for %d", config);
return HWC2::Error::BadConfig;
}
// std::unique_ptr<DrmDisplayComposition> composition = compositor_
// .CreateComposition();
// composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_);
// int ret = composition->SetDisplayMode(*mode);
// ret = compositor_.QueueComposition(std::move(composition));
// if (ret) {
// ALOGE("Failed to queue dpms composition on %d", ret);
// return HWC2::Error::BadConfig;
// }
connector_->set_best_mode(*mode);
connector_->set_current_mode(*mode);
ctx_.rel_xres = (*mode).h_display();
ctx_.rel_yres = (*mode).v_display();
// Setup the client layer's dimensions
hwc_rect_t display_frame = {.left = 0,
.top = 0,
.right = static_cast<int>(mode->h_display()),
.bottom = static_cast<int>(mode->v_display())};
client_layer_.SetLayerDisplayFrame(display_frame);
hwc_frect_t source_crop = {
.left = 0.0f, .top = 0.0f, .right = mode->h_display() + 0.0f, .bottom = mode->v_display() + 0.0f};
client_layer_.SetLayerSourceCrop(source_crop);
drm_->UpdateDisplayMode(handle_);
// SetDisplayModeInfo cost 2.5ms - 5ms, a A few cases cost 10ms - 20ms
connector_->SetDisplayModeInfo(handle_);
} else {
if (connector_->isCropSplit()) {
int32_t srcX, srcY, srcW, srcH;
connector_->getCropInfo(&srcX, &srcY, &srcW, &srcH);
hwc_rect_t display_frame = {.left = 0,
.top = 0,
.right = static_cast<int>(ctx_.framebuffer_width),
.bottom = static_cast<int>(ctx_.framebuffer_height)};
client_layer_.SetLayerDisplayFrame(display_frame);
hwc_frect_t source_crop = {
.left = srcX + 0.0f, .top = srcY + 0.0f, .right = srcX + srcW + 0.0f, .bottom = srcY + srcH + 0.0f};
client_layer_.SetLayerSourceCrop(source_crop);
} else {
if (bVrrDisplay_ && connector_->vrr_modes().size() > 1) {
// VRR
HWC2::Error error = UpdateRefreshRate(config);
if (error != HWC2::Error::None) {
return error;
}
} else if (config != 0) {
HWC2_LOGE("Could not find active mode for %d", config);
return HWC2::Error::BadConfig;
}
// Setup the client layer's dimensions
hwc_rect_t display_frame = {.left = 0,
.top = 0,
.right = static_cast<int>(ctx_.framebuffer_width),
.bottom = static_cast<int>(ctx_.framebuffer_height)};
client_layer_.SetLayerDisplayFrame(display_frame);
hwc_frect_t source_crop = {.left = 0.0f,
.top = 0.0f,
.right = ctx_.framebuffer_width + 0.0f,
.bottom = ctx_.framebuffer_height + 0.0f};
client_layer_.SetLayerSourceCrop(source_crop);
}
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::UpdateRefreshRate(hwc2_config_t config) {
HWC2_LOGV_IF("display-id=%" PRIu64 " config=%d", handle_, config);
if (!bVrrDisplay_) return HWC2::Error::None;
const std::vector<int> vrr_mode = connector_->vrr_modes();
if(vrr_mode.size() <= 0) return HWC2::Error::None;
if (config <= (vrr_mode.size() - 1)) {
int refresh_rate = vrr_mode[config];
int ret = drm_->UpdateVrrRefreshRate(handle_, refresh_rate);
if (ret) {
HWC2_LOGE("display=%" PRIu64 " config=%d refresh_rate=%d UpdateVrrRefreshRate fail!", handle_, config,
refresh_rate);
return HWC2::Error::BadConfig;
}
} else {
HWC2_LOGE("Could not find active mode for %d", config);
return HWC2::Error::BadConfig;
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetClientTarget(buffer_handle_t target, int32_t acquire_fence, int32_t dataspace,
hwc_region_t /*damage*/) {
HWC2_LOGV_IF("display-id=%" PRIu64 ", Buffer=%p, acq_fence=%d, dataspace=%x", handle_, target, acquire_fence,
dataspace);
// 动态切换刷新率过程中SurfaceFlinger会出现 SetClientTarget target=null的情况
// 为了避免错误日志打印,故暂时对这种情况进行规避;
if (target == NULL) {
HWC2_LOGW("Buffer is NULL, skip SetClientTarget");
return HWC2::Error::None;
}
client_layer_.CacheBufferInfo(target);
client_layer_.set_acquire_fence(sp<AcquireFence>(new AcquireFence(acquire_fence)));
client_layer_.SetLayerDataspace(dataspace);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetColorMode(int32_t mode) {
HWC2_LOGV_IF("display-id=%" PRIu64 ", mode=%x", handle_, mode);
if (mode != HAL_COLOR_MODE_NATIVE) return HWC2::Error::BadParameter;
color_mode_ = mode;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetColorTransform(const float* matrix, int32_t hint) {
HWC2_LOGV_IF("display-id=%" PRIu64 ", hint=%x", handle_, hint);
// TODO: Force client composition if we get this
// hint definition from android_color_transform_t in system/core/libsystem/include/system/graphics-base-v1.0.h
force_gles_ = (hint > 0);
unsupported(__func__, matrix, hint);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetOutputBuffer(buffer_handle_t buffer, int32_t release_fence) {
HWC2_LOGV_IF("display-id=%" PRIu64 ", buffer=%p, rel_fence=%d", handle_, buffer, release_fence);
// TODO: Need virtual display support
output_layer_.set_output_buffer(buffer);
if (release_fence > 0) {
/* release_fence will be close in this file hardware/interfaces/
* graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcHal.h+319
* int32_t err = mDispatch.setOutputBuffer(mDevice, display, buffer, releaseFence);
* // unlike in setClientTarget, releaseFence is owned by us
* if (err == HWC2_ERROR_NONE && releaseFence >= 0) {
* close(releaseFence);
* }
*/
int32_t new_release_fence = dup(release_fence);
String8 output;
output.appendFormat("%s-F%" PRIu32 "-Fd%d", __FUNCTION__, frame_no_, new_release_fence);
sp<ReleaseFence> release = sp<ReleaseFence>(new ReleaseFence(new_release_fence, output.c_str()));
output_layer_.set_release_fence(release);
HWC2_LOGD_IF("Release=%d(%d) %s Info: size=%d act=%d signal=%d err=%d", release->getFd(), release->isValid(),
release->getName().c_str(), release->getSize(), release->getActiveCount(),
release->getSignaledCount(), release->getErrorCount());
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SyncPowerMode() {
HWC2_LOGV_IF("display-id=%" PRIu64 " bNeedSyncPMState_=%d", handle_, bNeedSyncPMState_);
if (!init_success_) {
HWC2_LOGE("init_success_=%d skip.", init_success_);
return HWC2::Error::BadDisplay;
}
if (!bNeedSyncPMState_) {
HWC2_LOGI("bNeedSyncPMState_=%d don't need to sync PowerMode state.", bNeedSyncPMState_);
return HWC2::Error::None;
}
HWC2::Error error = SetPowerMode((int32_t)mPowerMode_);
if (error != HWC2::Error::None) {
HWC2_LOGE("SetPowerMode fail %d", error);
return error;
}
bNeedSyncPMState_ = false;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetPowerMode(int32_t mode_in) {
HWC2_LOGV_IF("display-id=%" PRIu64 ", mode_in=%d", handle_, mode_in);
#ifdef USE_LIBEBOOK
if (isEBook()) {
HWC2::PowerMode old_mode = mPowerMode_;
mPowerMode_ = static_cast<HWC2::PowerMode>(mode_in);
if (mPowerMode_ == HWC2::PowerMode::On) {
HWC2_LOGI("EBook PowerOn, enable force update frame.");
ebook_stop_commit_util_power_on_ = false;
// 如果电源模式切换为 PowerOn则设置强制刷新帧率为10fps刷新10帧
InvalidateControl(10, 10);
// 如果电源模式从PowerOff切换为PowerOn则第一帧要全刷
if (old_mode == HWC2::PowerMode::Off) {
HWC2_LOGI("EBOOK RESUME");
force_full_once_ = true;
}
}
return HWC2::Error::None;
}
#endif
// 拼接屏幕主屏需要更新拼接副屏的电源状态
if (connector_->IsSplitPrimary()) {
for (auto& conn : drm_->connectors()) {
if (!conn->isCropSplit()) {
continue;
}
int display_id = conn->display();
if (!conn->IsSplitPrimary()) {
auto& display = resource_manager_->GetHwc2()->displays_.at(display_id);
display.SetPowerMode(mode_in);
}
}
}
uint64_t dpms_value = 0;
mPowerMode_ = static_cast<HWC2::PowerMode>(mode_in);
switch (mPowerMode_) {
case HWC2::PowerMode::Off:
dpms_value = DRM_MODE_DPMS_OFF;
break;
case HWC2::PowerMode::On:
dpms_value = DRM_MODE_DPMS_ON;
break;
case HWC2::PowerMode::Doze:
case HWC2::PowerMode::DozeSuspend:
ALOGI("Power mode %d is unsupported\n", mPowerMode_);
return HWC2::Error::Unsupported;
default:
ALOGI("Power mode %d is BadParameter\n", mPowerMode_);
return HWC2::Error::BadParameter;
};
//这里使用析构函数确保eventWorker_恢复event处理的操作在SetPowerMode流程执行完成后执行
struct signalScope_t {
~signalScope_t() {
g_ctx->eventWorker_.SetEventBlockState(false, "Display 0 Powered on");
g_ctx->eventWorker_.Signal();
}
};
std::shared_ptr<signalScope_t> signalScope = nullptr;
ResourceManager* rm = ResourceManager::getInstance();
if (!rm) {
HWC2_LOGE("EventWorker::Routine: Can not get ResourceManager");
} else {
//Check if hotplug need to block in sleep
if (rm->GetBlockHotplugInPowerOff() && handle_ == 0) {
if (mPowerMode_ == HWC2::PowerMode::Off) {
g_ctx->eventWorker_.SetEventBlockState(true, "Display 0 Powered off");
}
if (mPowerMode_ == HWC2::PowerMode::On) {
signalScope = std::make_shared<signalScope_t>();
}
}
}
if (!init_success_) {
bNeedSyncPMState_ = true;
HWC2_LOGE("init_success_=%d skip.", init_success_);
return HWC2::Error::BadDisplay;
}
std::unique_ptr<DrmDisplayComposition> composition = compositor_->CreateComposition();
composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_, handle_);
composition->SetDpmsMode(dpms_value);
int ret = compositor_->QueueComposition(std::move(composition));
if (ret) {
ALOGE("Failed to apply the dpms composition ret=%d", ret);
return HWC2::Error::BadParameter;
}
int fb0_fd = resource_manager_->getFb0Fd();
if (fb0_fd <= 0)
ALOGE_IF(LogLevel(DBG_ERROR), "%s,line=%d fb0_fd = %d can't operation /dev/graphics/fb0 node.", __FUNCTION__,
__LINE__, fb0_fd);
int fb_blank = 0;
if (dpms_value == DRM_MODE_DPMS_OFF)
fb_blank = FB_BLANK_POWERDOWN;
else if (dpms_value == DRM_MODE_DPMS_ON)
fb_blank = FB_BLANK_UNBLANK;
else
ALOGE("dpmsValue is invalid value= %" PRIu64 "", dpms_value);
if (fb_blank != fb_blanked && fb0_fd > 0) {
int err = ioctl(fb0_fd, FBIOBLANK, fb_blank);
ALOGD_IF(LogLevel(DBG_DEBUG), "%s Notice fb_blank to fb=%d", __FUNCTION__, fb_blank);
if (err < 0) {
ALOGE("fb_blank ioctl failed(%d) display=%" PRIu64 ",fb_blank=%d,dpmsValue=%" PRIu64 "", errno, handle_,
fb_blank, dpms_value);
}
}
fb_blanked = fb_blank;
if (dpms_value == DRM_MODE_DPMS_OFF) {
ClearDisplay();
ret = drm_->SetPowerMode(handle_, DRM_MODE_DPMS_OFF);
if (ret) {
HWC2_LOGE("Failed to ReleaseDpyRes for display=%" PRIu64 " %d\n", handle_, ret);
return HWC2::Error::BadParameter;
}
if (isRK3566(resource_manager_->getSocId())) {
int display_id = drm_->GetCommitMirrorDisplayId();
DrmConnector* extend = drm_->GetConnectorForDisplay(display_id);
if (extend != NULL) {
int extend_display_id = extend->display();
auto& display = resource_manager_->GetHwc2()->displays_.at(extend_display_id);
display.ClearDisplay();
ret = drm_->SetPowerMode(extend_display_id, DRM_MODE_DPMS_OFF);
if (ret) {
HWC2_LOGE("Failed to ReleaseDpyRes for display=%d %d\n", extend_display_id, ret);
return HWC2::Error::BadParameter;
}
}
}
} else {
if (connector_->hotplug()) {
ret = connector_->UpdateModes();
if (ret) {
HWC2_LOGE("Failed to UpdateModes for display=%" PRIu64 " ret=%d\n", handle_, ret);
return HWC2::Error::BadParameter;
}
}
HoplugEventTmeline();
ret = GetCurrentDisplayMode();
if (ret) {
HWC2_LOGE("Failed to GetCurrentDisplayMode for display=%" PRIu64 " ret=%d\n", handle_, ret);
return HWC2::Error::BadParameter;
}
ret = drm_->SetPowerMode(handle_, DRM_MODE_DPMS_ON);
if (ret) {
HWC2_LOGE("Failed to BindDpyRes for display=%" PRIu64 " ret=%d\n", handle_, ret);
return HWC2::Error::BadParameter;
}
UpdateDisplayInfo();
if (isRK3566(resource_manager_->getSocId())) {
ALOGD_IF(LogLevel(DBG_DEBUG), "SetPowerMode display-id=%" PRIu64 ",soc is rk3566", handle_);
int display_id = drm_->GetCommitMirrorDisplayId();
DrmConnector* extend = drm_->GetConnectorForDisplay(display_id);
if (extend != NULL) {
int extend_display_id = extend->display();
ret = drm_->SetPowerMode(extend_display_id, DRM_MODE_DPMS_ON);
if (ret) {
HWC2_LOGE("Failed to BindDpyRes for display=%d ret=%d\n", extend_display_id, ret);
}
}
}
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetVsyncEnabled(int32_t enabled) {
HWC2_LOGV_IF("display-id=%" PRIu64 ", enable=%d", handle_, enabled);
vsync_worker_.VSyncControl(HWC2_VSYNC_ENABLE == enabled);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::ValidateVirtualDisplay(uint32_t* num_types, uint32_t* num_requests) {
if (LogLevel(DBG_INFO)) {
DumpDisplayLayersInfo();
}
if (!layers_.size()) {
HWC2_LOGI("display %" PRIu64 " layer size is %zu, %s,line=%d", handle_, layers_.size(), __FUNCTION__, __LINE__);
return HWC2::Error::None;
}
// 强制设置系统刷新为30帧
InvalidateControl(30, -1);
bUseWriteBack_ = true;
// 提供仅 Sideband 模式下开启 hw Virtual Display 功能接口
if (HwcAProperty::getInstance().getIntWithInterval("vendor.hwc.only_sideband_use_wb", 1000, 0) > 0) {
bUseWriteBack_ = false;
bool exist_sideband_stream = false;
// 只有存在 SidebandStream 的录屏才会使用 WriteBack;
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) {
DrmHwcTwo::HwcLayer& layer = l.second;
if (layer.isSidebandLayer()) {
exist_sideband_stream = true;
}
}
if (exist_sideband_stream) {
bUseWriteBack_ = true;
}
}
HWC2_LOGD_IF("frame_no_ = %d", frame_no_);
// 获取 WriteBack id
int WBDisplayId = resource_manager_->GetWBDisplay();
// 检查是否正确使能 Hw Virtual Display 功能
if (WBDisplayId >= 0 && resource_manager_->isWBMode() && !resource_manager_->IsDisableHwVirtualDisplay()) {
DrmConnector* connector = drm_->GetConnectorForDisplay(WBDisplayId);
if (!connector) {
HWC2_LOGD_IF("Failed to get WB connector for display=%" PRIu64 " wb-display %d frame_no=%d", handle_,
WBDisplayId, frame_no_);
bUseWriteBack_ = false;
} else {
if (connector->state() != DRM_MODE_CONNECTED) {
HWC2_LOGD_IF(
"WB Connector %u type=%s, type_id=%d, state is DRM_MODE_DISCONNECTED, skip init. "
"display=%" PRIu64 " wb-display %d frame_no=%d",
connector->id(), drm_->connector_type_str(connector->type()), connector->type_id(), handle_,
WBDisplayId, frame_no_);
;
bUseWriteBack_ = false;
}
DrmCrtc* crtc = drm_->GetCrtcForDisplay(WBDisplayId);
if (!crtc) {
HWC2_LOGD_IF("Failed to get crtc for display=%" PRIu64 " wb-display %d frame_no=%d", handle_,
WBDisplayId, frame_no_);
bUseWriteBack_ = false;
}
if (resource_manager_->GetWriteBackRunningState() == false) {
HWC2_LOGD_IF("WB: Current display=%" PRIu64 " WBDisplay=%d runing state=%d. disable VDS. frame_no=%d",
handle_, WBDisplayId, resource_manager_->GetWriteBackRunningState(), frame_no_);
bUseWriteBack_ = false;
}
// if(resource_manager_->GetFinishWBBufferSize() == 0){
// HWC2_LOGD_IF("WB buffer not ready, display=%" PRIu64 " wb-display %d frame_no=%d", handle_, WBDisplayId, frame_no_);
// bUseWriteBack_ = false;
// }
// 逐层匹配图层确认是否支持从WriteBack获取图像
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) {
DrmHwcTwo::HwcLayer& layer = l.second;
uint64_t buffer_id = 0;
const std::shared_ptr<LayerInfoCache> layer_info_cache = layer.GetBufferInfo();
if (layer_info_cache != NULL) {
buffer_id = layer_info_cache->uBufferId_;
}
// 判断信息当前仅需要 BufferId 与 图层名字
MirrorDisplayInfo_t info;
info.buffer_id = buffer_id;
info.name = layer.name();
if (!resource_manager_->IsWBMirrorDisplay(handle_, layer.z_order(), info)) {
HWC2_LOGD_IF("WB: Current display=%" PRIu64
" is not wb-display %d mirror display. disable VDS. frame_no=%d",
handle_, WBDisplayId, frame_no_);
bUseWriteBack_ = false;
}
}
}
} else {
bUseWriteBack_ = false;
HWC2_LOGD_IF("WB display %d is invalid, disable HW VDS.", WBDisplayId);
}
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) {
DrmHwcTwo::HwcLayer& layer = l.second;
if (bUseWriteBack_) {
if (layer.sf_type() == HWC2::Composition::Sideband) {
layer.set_validated_type(HWC2::Composition::Sideband);
} else {
layer.set_validated_type(HWC2::Composition::Device);
}
} else {
layer.set_validated_type(HWC2::Composition::Client);
}
//num_types 应该为发生改变的图层不仅仅是Client图层
if (layer.type_changed()) {
++*num_types;
}
}
*num_requests = 0;
return HWC2::Error::None;
}
#ifdef USE_LIBEBOOK
HWC2::Error DrmHwcTwo::HwcDisplay::ValidateEBookDisplay(uint32_t* num_types, uint32_t* num_requests) {
if (LogLevel(DBG_INFO)) {
DumpDisplayLayersInfo();
}
if (!layers_.size()) {
HWC2_LOGI("display %" PRIu64 " layer size is %zu, %s,line=%d", handle_, layers_.size(), __FUNCTION__, __LINE__);
return HWC2::Error::None;
}
// 若存在图像更新,则认为 validate 成功否则不送显。主要目的为了降低EBook功耗
validate_success_ = false;
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) {
DrmHwcTwo::HwcLayer& layer = l.second;
if (layer.isUpdate()) {
validate_success_ = true;
break;
}
}
char value[PROPERTY_VALUE_MAX];
property_get("sys.eink.mode", value, "9");
current_mode_ = static_cast<EBookMode>(atoi(value));
// 如果模式发生切换则需要更新当前帧
if (current_mode_ != last_mode_) {
validate_success_ = true;
}
// 应用在休眠模式与PowerOff模式会传递名为“EBOOK_STANDBY”或者“EBOOK_POWEROFF”图层
// HWC 需要在检测到目标图层后将当前帧作为最后一帧提交至EBook驱动直到PowerOn请求
// 再恢复正常显示
ebook_commit_last_frame_and_stop_ = false;
// EBook特殊的电源模式切换,找到特殊的命名图层
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) {
DrmHwcTwo::HwcLayer& layer = l.second;
const std::shared_ptr<LayerInfoCache> bufferinfo = layer.GetBufferInfo();
if (bufferinfo != NULL && bufferinfo->sLayerName_.empty() == false) {
if (strstr(bufferinfo->sLayerName_.c_str(), "EBOOK_STANDBY")) {
HWC2_LOGI("EBOOK STANDBY\n");
current_mode_ = EBOOK_FORCE_FULL;
ebook_commit_last_frame_and_stop_ = true;
} else if (strstr(bufferinfo->sLayerName_.c_str(), "EBOOK_POWEROFF")) {
HWC2_LOGI("EBOOK POWEROFF\n");
current_mode_ = EBOOK_FORCE_FULL;
ebook_commit_last_frame_and_stop_ = true;
}
}
}
// 如果 EBook 停止送显则关闭SurfaceFlinger GPU合成目的是为了降低功耗
if (ebook_stop_commit_util_power_on_) {
validate_success_ = false;
}
if (force_full_once_) {
current_mode_ = EBOOK_FORCE_FULL;
force_full_once_ = false;
}
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) {
DrmHwcTwo::HwcLayer& layer = l.second;
if (layer.sf_type() == HWC2::Composition::Sideband) {
layer.set_validated_type(HWC2::Composition::Sideband);
} else if (layer.sf_type() != HWC2::Composition::Device) {
layer.set_validated_type(layer.sf_type());
} else {
if (validate_success_) {
layer.set_validated_type(HWC2::Composition::Client);
} else {
layer.set_validated_type(HWC2::Composition::Device);
}
}
layer.resetUpdate();
//num_types 应该为发生改变的图层不仅仅是Client图层
if (layer.type_changed()) {
++*num_types;
}
}
*num_requests = 0;
return HWC2::Error::None;
}
#endif
HWC2::Error DrmHwcTwo::HwcDisplay::ValidateDisplay(uint32_t* num_types, uint32_t* num_requests) {
ATRACE_CALL();
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
// Enable/disable debug log
UpdateLogLevel();
// 虚拟屏
if (isVirtual()) {
return ValidateVirtualDisplay(num_types, num_requests);
}
#ifdef USE_LIBEBOOK
// 虚拟屏
if (isEBook()) {
return ValidateEBookDisplay(num_types, num_requests);
}
#endif
if (LogLevel(DBG_DEBUG)) DumpDisplayLayersInfo();
if (!init_success_ || force_disconneted_) {
HWC2_LOGE_IF("init_success_=%d force_disconneted_=%d skip.", init_success_, force_disconneted_);
if (connector_->IsSplitPrimary()) {
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) {
l.second.set_validated_type(HWC2::Composition::Client);
//num_types 应该为发生改变的图层不仅仅是Client图层
if (l.second.type_changed()) {
++*num_types;
}
}
} else {
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) {
l.second.set_validated_type(l.second.sf_type());
}
}
validate_success_ = false;
return *num_types ? HWC2::Error::HasChanges : HWC2::Error::None;
}
UpdateBCSH();
UpdateHdmiOutputFormat();
UpdateOverscan();
UpdateDisplayMode();
// 虚拟屏幕
if (connector_->type() == DRM_MODE_CONNECTOR_VIRTUAL) {
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) {
l.second.set_validated_type(l.second.sf_type());
}
return HWC2::Error::None;
}
*num_types = 0;
*num_requests = 0;
HWC2::Error ret;
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) {
if (gIsRK3528()) {
l.second.set_validated_type(HWC2::Composition::Device);
} else {
l.second.set_validated_type(HWC2::Composition::Client);
}
}
ret = CheckDisplayState();
if (ret != HWC2::Error::None) {
ALOGE_IF(LogLevel(DBG_ERROR), "Check display %" PRIu64 " state fail, %s,line=%d", handle_, __FUNCTION__,
__LINE__);
composition_planes_.clear();
validate_success_ = false;
return HWC2::Error::None;
}
ret = ValidatePlanes();
if (ret != HWC2::Error::None) {
ALOGE("%s fail , ret = %d,line = %d", __FUNCTION__, ret, __LINE__);
validate_success_ = false;
return HWC2::Error::BadConfig;
}
// update sideband mode
UpdateSidebandMode();
// update hdr states
SwitchHdrMode();
// Static screen opt
UpdateTimerEnable();
// Enable Self-refresh mode.
SelfRefreshEnable();
// 更新使能WriteBack的Display当前提交的图层信息
if (resource_manager_->isWBMode() && resource_manager_->GetWBDisplay() == handle_) {
std::map<uint32_t, MirrorDisplayInfo_t> wbd_info;
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) {
DrmHwcTwo::HwcLayer& layer = l.second;
uint64_t buffer_id = 0;
const std::shared_ptr<LayerInfoCache> layer_info_cache = layer.GetBufferInfo();
if (layer_info_cache != NULL) {
buffer_id = layer_info_cache->uBufferId_;
}
// 目前判断信息仅需要BufferId与图层名称
MirrorDisplayInfo_t info;
info.buffer_id = buffer_id;
info.name = layer.name();
wbd_info[layer.z_order()] = info;
}
// 保存当前帧信息到 resource_manager
resource_manager_->AddWBDisplayLayerInfo(wbd_info);
}
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) {
DrmHwcTwo::HwcLayer& layer = l.second;
//num_types 应该为发生改变的图层不仅仅是Client图层
if (layer.type_changed() && (layer.hwc3_sf_type() != HWC3_COMPOSITION_DISPLAY_DECORATION)) {
++*num_types;
}
layer.resetUpdate();
}
if (!client_layer_.isAfbc()) {
++(*num_requests);
}
client_layer_.resetUpdate();
HWC2_LOGV_IF("num_requests=%" PRIu32 ",num_types=%" PRIu32, *num_requests, *num_types);
validate_success_ = true;
return *num_types ? HWC2::Error::HasChanges : HWC2::Error::None;
}
// Only Android 14 Support
#if PLATFORM_SDK_VERSION >= 34
// Composer 2.4
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayConnectionType(uint32_t* outType) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
if (handle_ == 0) {
*outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::Internal);
} else {
*outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::External);
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayVsyncPeriod(hwc2_vsync_period_t* outVsyncPeriod /* ns */) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
supported(__func__);
DrmMode const& mode = connector_->active_mode();
if (mode.id() == 0) {
// 如果屏幕没有接则直接上报60帧的默认刷新
*outVsyncPeriod = 1E9 / 60;
return HWC2::Error::None;
}
*outVsyncPeriod = 1E9 / mode.v_refresh();
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetActiveConfigWithConstraints(
hwc2_config_t config, hwc_vsync_period_change_constraints_t* vsyncPeriodChangeConstraints,
hwc_vsync_period_change_timeline_t* outTimeline) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
supported(__func__);
if (vsyncPeriodChangeConstraints == nullptr || outTimeline == nullptr) {
return HWC2::Error::BadParameter;
}
//HDMI等接口切换分辨率和帧率会闪黑暂时不支持seamless切换模式
if (vsyncPeriodChangeConstraints->seamlessRequired) {
HWC2_LOGE("Not Support change seamlessly, configi= %u ", config);
return HWC2::Error::SeamlessNotAllowed;
}
//设置分辨率
HWC2::Error err = SetActiveConfig(config);
if (err != HWC2::Error::None) {
return HWC2::Error::BadConfig;
}
//获取新的单帧时长
DrmMode const& mode = connector_->current_mode();
if (mode.id() == 0) return HWC2::Error::BadConfig;
hwc2_vsync_period_t currentVsyncPeriod = 1E9 / mode.v_refresh();
//上报帧率切换时间,
//这里刷新时间设定为当前时刻后一帧应用时间为当前时刻后60帧
//屏幕应该在这个时间里面可以同步好时序显示出画面
const auto now = systemTime(SYSTEM_TIME_MONOTONIC);
auto delta = (vsyncPeriodChangeConstraints->desiredTimeNanos - now) % currentVsyncPeriod;
outTimeline->refreshTimeNanos = now + delta;
outTimeline->newVsyncAppliedTimeNanos = now + delta + 60 * currentVsyncPeriod;
if (outTimeline->newVsyncAppliedTimeNanos < vsyncPeriodChangeConstraints->desiredTimeNanos)
outTimeline->newVsyncAppliedTimeNanos = vsyncPeriodChangeConstraints->desiredTimeNanos;
outTimeline->refreshRequired = true;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetAutoLowLatencyMode(bool /*on*/) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
return HWC2::Error::Unsupported;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetSupportedContentTypes(uint32_t* outNumSupportedContentTypes,
const uint32_t* outSupportedContentTypes) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
if (outSupportedContentTypes == nullptr) *outNumSupportedContentTypes = 0;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetContentType(int32_t contentType) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
supported(__func__);
if (contentType != HWC2_CONTENT_TYPE_NONE) return HWC2::Error::Unsupported;
/* TODO: Map to the DRM Connector property:
* https://elixir.bootlin.com/linux/v5.4-rc5/source/drivers/gpu/drm/drm_connector.c#L809
*/
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetClientTargetProperty(hwc_client_target_property_t* outClientTargetProperty) {
if (outClientTargetProperty) {
auto pixelFormat = HAL_PIXEL_FORMAT_RGBA_8888;
#ifdef USE_LIBPQ_HWPQ
// If HWPQ is enabled, use RGB_888 instead of RGBA_8888 for better quality.
if (gIsRK3576()) {
if (crtc_ && crtc_->get_port_id() == 0) {
if (ctx_.use_pq_fb) pixelFormat = HAL_PIXEL_FORMAT_RGB_888;
}
}
#endif
outClientTargetProperty->pixelFormat = pixelFormat;
outClientTargetProperty->dataspace = HAL_DATASPACE_SRGB;
HWC2_LOGV_IF("display-id=%" PRIu64 "pixel format = %d dataspace =%" PRIx32, handle_,
outClientTargetProperty->pixelFormat, outClientTargetProperty->dataspace);
} else {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetExpectedPresentTime(int64_t expected_present_time) {
HWC2_LOGV_IF("display-id=%" PRIu64 " expected_present_time=%" PRIi64, handle_, expected_present_time);
iExpectedPresentTime_ = expected_present_time;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayIdentificationData(uint8_t* outPort, uint32_t* outDataSize,
uint8_t* outData) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
if (!resource_manager_->GetEnableEdidReport()) {
HWC2_LOGI("vendor.hwc.enable_edid_report = 0, disable GetDisplayIdentificationData support.");
return HWC2::Error::Unsupported;
}
supported(__func__);
auto blob = connector_->GetEdidBlob();
uint8_t* dummyEDID = NULL;
uint32_t dummySize = 0;
if (blob == nullptr) {
HWC2_LOGD_IF("Failed to get blob, HWC generate one.");
dummyEDID = connector_->MakeFakeEDID();
if (dummyEDID == nullptr) {
HWC2_LOGW("Failed to get blob, HWC generate Failed.");
return HWC2::Error::Unsupported;
}
dummySize = 128;
}
*outPort = connector_->id();
if (!blob && !dummyEDID) {
if (outData == nullptr) {
*outDataSize = 0;
}
return HWC2::Error::None;
}
if (outData) {
if (blob) {
*outDataSize = std::min(*outDataSize, blob->length);
memcpy(outData, blob->data, *outDataSize);
} else {
*outDataSize = std::min(*outDataSize, dummySize);
memcpy(outData, dummyEDID, *outDataSize);
}
} else {
if (blob) {
*outDataSize = blob->length;
} else {
*outDataSize = dummySize;
}
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayCapabilities(uint32_t* outNumCapabilities, uint32_t* outCapabilities) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
uint32_t capabilityNum = 0;
if (outCapabilities == NULL) {
*outNumCapabilities = capabilityNum;
return HWC2::Error::None;
}
if (capabilityNum != *outNumCapabilities) {
ALOGE("%s:: invalid outNumCapabilities(%d), should be(%d)", __func__, *outNumCapabilities, capabilityNum);
return HWC2::Error::BadParameter;
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayBrightnessSupport(bool* supported) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
*supported = false;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetDisplayBrightness(float /* brightness */) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
return HWC2::Error::Unsupported;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayedContentSamplingAttributes(
int32_t* /* android_pixel_format_t */ format, int32_t* /* android_dataspace_t */ dataspace,
uint8_t* /* mask of android_component_t */ supported_components) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
return HWC2::Error::Unsupported;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetDisplayedContentSamplingEnabled(
int32_t /*hwc2_displayed_content_sampling_t*/ enabled, uint8_t /* mask of android_component_t */ component_mask,
uint64_t max_frames) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
return HWC2::Error::Unsupported;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayedContentSample(uint64_t max_frames, uint64_t timestamp,
uint64_t* frame_count, int32_t samples_size[4],
uint64_t* samples[4]) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
return HWC2::Error::Unsupported;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetRenderIntents(int32_t mode, uint32_t* outNumIntents,
int32_t* /*android_render_intent_v1_1_t*/ outIntents) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
if (mode != HAL_COLOR_MODE_NATIVE) {
return HWC2::Error::BadParameter;
}
if (outIntents == nullptr) {
*outNumIntents = 1;
return HWC2::Error::None;
}
*outNumIntents = 1;
outIntents[0] = HAL_RENDER_INTENT_COLORIMETRIC;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetColorModeWithIntent(int32_t mode, int32_t intent) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
if (intent < HAL_RENDER_INTENT_COLORIMETRIC || intent > HAL_RENDER_INTENT_TONE_MAP_ENHANCE)
return HWC2::Error::BadParameter;
if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_BT2100_HLG) return HWC2::Error::BadParameter;
if (mode != HAL_COLOR_MODE_NATIVE) return HWC2::Error::Unsupported;
if (intent != HAL_RENDER_INTENT_COLORIMETRIC) return HWC2::Error::Unsupported;
color_mode_ = mode;
return HWC2::Error::None;
}
// TODO:
HWC2::Error DrmHwcTwo::HwcDisplay::GetPerFrameMetadataKeys(uint32_t* outNumKeys,
int32_t* /*hwc2_per_frame_metadata_key_t*/ outKeys) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
return unsupported(__func__, outNumKeys, outKeys);
}
// TODO:
HWC2::Error DrmHwcTwo::HwcDisplay::GetReadbackBufferFence(int32_t* outFence) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
return unsupported(__func__, outFence);
}
// TODO:
HWC2::Error DrmHwcTwo::HwcDisplay::SetReadbackBuffer(buffer_handle_t buffer, int32_t releaseFence) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
if (releaseFence > 0) {
close(releaseFence);
releaseFence = -1;
}
return unsupported(__func__, buffer);
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetReadbackBufferAttributes(int32_t* /*android_pixel_format_t*/ outFormat,
int32_t* /*android_dataspace_t*/ outDataspace) {
HWC2_LOGV_IF("display-id=%" PRIu64, handle_);
return unsupported(__func__, outFormat, outDataspace);
}
#endif /* PLATFORM_SDK_VERSION >= 34 */
HWC2::Error DrmHwcTwo::HwcLayer::SetCursorPosition(int32_t x, int32_t y) {
HWC2_LOGV_IF("layer-id=%d, x=%d, y=%d", id_, x, y);
mCurrentState.cursor_x_ = x;
mCurrentState.cursor_y_ = y;
return HWC2::Error::None;
}
int DrmHwcTwo::HwcDisplay::DumpDisplayInfo(String8& output) {
output.appendFormat(
"\nDisplayId=%" PRIu64 ", Connector %u, Type = %s-%u, Connector state = %s frame_no =%" PRIu32 "\n",
handle_, connector_->id(), isVirtual() ? "Virtual" : drm_->connector_type_str(connector_->type()),
connector_->type_id(),
connector_->state() == DRM_MODE_CONNECTED ? "DRM_MODE_CONNECTED" : "DRM_MODE_DISCONNECTED", frame_no_);
if (connector_->state() != DRM_MODE_CONNECTED) return -1;
DrmMode const& active_mode = connector_->active_mode();
if (active_mode.id() == 0) {
return -1;
}
output.appendFormat(" NumHwLayers=%zu, activeModeId=%u, %s%c%.2f, colorMode = %d, bStandardSwitchResolution=%d\n",
get_layers().size(), active_mode.id(), active_mode.name().c_str(), 'p', active_mode.v_refresh(),
color_mode_, ctx_.bStandardSwitchResolution);
if (sf_modes_.size() > 0) {
uint32_t idx = 0;
for (const DrmMode& mode : sf_modes_) {
if (active_mode.id() == mode.id())
output.appendFormat(" Config[%2u] = %s%c%.2f mode-id=%d (active)\n", idx, mode.name().c_str(), 'p',
mode.v_refresh(), mode.id());
else
output.appendFormat(" Config[%2u] = %s%c%.2f mode-id=%d \n", idx, mode.name().c_str(), 'p',
mode.v_refresh(), mode.id());
idx++;
}
}
// clang-format off
output.append(
"------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n"
" id | z | sf-type | hwc-type | handle | transform | blnd | source crop (l,t,r,b) | frame | dataspace | mFps | name \n"
"------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n");
// clang-format on
for (uint32_t z_order = 0; z_order <= layers_.size(); z_order++) {
for (auto& map_layer : layers_) {
HwcLayer& layer = map_layer.second;
if (layer.z_order() == z_order) {
layer.DumpLayerInfo(output);
break;
}
}
}
// clang-format off
output.append("------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n");
output.append("DrmHwcLayer Dump:\n");
// clang-format on
for (auto& drmHwcLayer : drm_hwc_layers_) drmHwcLayer.DumpInfo(output);
if (compositor_ != NULL) {
compositor_->Dump(output);
}
return 0;
}
int DrmHwcTwo::HwcDisplay::DumpDisplayLayersInfo(String8& output) {
output.appendFormat(" DisplayId=%" PRIu64 ", Connector %u, Type = %s-%u, Connector state = %s , frame_no = %d\n",
handle_, connector_->id(),
isVirtual() ? "Virtual" : drm_->connector_type_str(connector_->type()), connector_->type_id(),
connector_->state() == DRM_MODE_CONNECTED ? "DRM_MODE_CONNECTED" : "DRM_MODE_DISCONNECTED",
frame_no_);
// clang-format off
output.append(
"------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n"
" id | z | req-type | fina-type | handle | transform | blnd | source crop (l,t,r,b) | frame | dataspace | mFps | name \n"
"------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n");
// clang-format on
for (uint32_t z_order = 0; z_order <= layers_.size(); z_order++) {
for (auto& map_layer : layers_) {
HwcLayer& layer = map_layer.second;
if (layer.z_order() == z_order) {
layer.DumpLayerInfo(output);
break;
}
}
}
// clang-format off
output.append("------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n");
// clang-format on
return 0;
}
int DrmHwcTwo::HwcDisplay::DumpDisplayLayersInfo() {
String8 output;
output.appendFormat(" DisplayId=%" PRIu64 ", Connector %u, Type = %s-%u, Connector state = %s , frame_no = %d\n",
handle_, connector_->id(),
isVirtual() ? "Virtual" : drm_->connector_type_str(connector_->type()), connector_->type_id(),
connector_->state() == DRM_MODE_CONNECTED ? "DRM_MODE_CONNECTED" : "DRM_MODE_DISCONNECTED",
frame_no_);
// clang-format off
output.append(
"------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n"
" id | z | sf-type | hwc-type | handle | transform | blnd | source crop (l,t,r,b) | frame | dataspace | mFps | name \n"
"------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n");
// clang-format on
ALOGD("%s", output.c_str());
for (uint32_t z_order = 0; z_order <= layers_.size(); z_order++) {
for (auto& map_layer : layers_) {
HwcLayer& layer = map_layer.second;
if (layer.z_order() == z_order) {
output.clear();
layer.DumpLayerInfo(output);
ALOGD("%s", output.c_str());
break;
}
}
}
output.clear();
// clang-format off
output.append("------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n");
// clang-format on
ALOGD("%s", output.c_str());
return 0;
}
int DrmHwcTwo::HwcDisplay::DumpAllLayerData() {
bool need_dump = HwcAProperty::getInstance().getBoolWithInterval("vendor.dump", 500, false);
if (need_dump) {
bool use_client_layer = false;
for (auto& map_layer : layers_) {
HwcLayer& layer = map_layer.second;
layer.DumpData(frame_no_, "M");
if (layer.validated_type() == HWC2::Composition::Client) {
use_client_layer = true;
}
}
if (use_client_layer && client_layer_.buffer() != NULL) client_layer_.DumpData(frame_no_, "M");
for (auto& drm_layer : drm_hwc_layers_) {
if (drm_layer.bUseSr_ && drm_layer.pSrBuffer_) {
drm_layer.pSrBuffer_->DumpData(frame_no_, drm_layer.iZpos_, "M");
}
}
for (auto& drm_layer : drm_hwc_layers_) {
if (drm_layer.bUseRga_ && drm_layer.pRgaBuffer_) {
drm_layer.pRgaBuffer_->DumpData(frame_no_, drm_layer.iZpos_, "M");
}
}
for (auto& drm_layer : drm_hwc_layers_) {
if (drm_layer.bBackgraoundLayer_) {
drm_layer.DumpData("M");
}
}
bool disable_dump_with_wb =
HwcAProperty::getInstance().getBoolWithInterval("vendor.dump.disable_wb", 500, false);
if (disable_dump_with_wb) {
DisableDumpWithWB();
} else {
EnableDumpWithWB();
}
if (iDumpCnt <= 0) {
int framecnt = HwcAProperty::getInstance().getInt("vendor.dump.cnt", -1);
if (framecnt > 0) {
iDumpCnt = framecnt;
}
}
if (iDumpCnt > 0) {
iDumpCnt--;
if (iDumpCnt == 0) {
HwcAProperty::getInstance().setPropertyAsync("vendor.dump", "false");
}
}
} else {
DisableDumpWithWB();
iDumpCnt = -1;
}
return 0;
}
int DrmHwcTwo::HwcDisplay::HoplugEventTmeline() {
ctx_.hotplug_timeline++;
return 0;
}
int DrmHwcTwo::HwcDisplay::GetCurrentDisplayMode() {
if (!ctx_.bStandardSwitchResolution) {
int display_id = static_cast<int>(handle_);
int timeline = HwcAProperty::getInstance().getIntWithInterval("vendor.display.timeline", 100, -1);
if (timeline && timeline == ctx_.display_timeline && ctx_.hotplug_timeline == drm_->timeline()) return 0;
ctx_.display_timeline = timeline;
ctx_.hotplug_timeline = drm_->timeline();
int ret = connector_->GetBestDisplayMode(display_id, timeline);
if (!ret) {
const DrmMode best_mode = connector_->best_mode();
connector_->set_current_mode(best_mode);
// will change display resolution, to clear all display.
if (connector_->state() == DRM_MODE_CONNECTED && connector_->power_state() == DRM_MODE_DPMS_ON &&
connector_->current_mode().id() > 0 && connector_->active_mode().id() > 0 &&
!(connector_->current_mode() == connector_->active_mode())) {
ClearDisplay();
// 标识 Display mode 发生改变
ActiveModeChange(true);
}
}
// RK3566 使用的DisplayMirror模式需要从Primary更新副屏幕的分辨率信息
if (isRK3566(resource_manager_->getSocId())) {
bool mirror_mode = true;
display_id = drm_->GetCommitMirrorDisplayId();
DrmConnector* conn_mirror = drm_->GetConnectorForDisplay(display_id);
if (!conn_mirror || conn_mirror->state() != DRM_MODE_CONNECTED) {
ALOGI_IF(LogLevel(DBG_DEBUG), "%s,line=%d disable bCommitMirrorMode", __FUNCTION__, __LINE__);
mirror_mode = false;
}
if (mirror_mode) {
ret = conn_mirror->GetBestDisplayMode(display_id, timeline);
if (!ret) {
const DrmMode best_mode = conn_mirror->best_mode();
conn_mirror->set_current_mode(best_mode);
}
}
}
// MirrorExternal分辨率切换需要从MirrorPrimary流程中触发
if (connector_->is_connector_mirror_primary()) {
for (int mirror_display_id : connector_->get_connector_mirror_display_id()) {
DrmConnector* conn_mirror = drm_->GetConnectorForDisplay(mirror_display_id);
if (conn_mirror != NULL) {
ret = conn_mirror->GetBestDisplayMode(mirror_display_id, timeline);
if (!ret) {
const DrmMode best_mode = conn_mirror->best_mode();
conn_mirror->set_current_mode(best_mode);
}
}
}
}
}
return 0;
}
int DrmHwcTwo::HwcDisplay::UpdateDisplayMode() {
// 获取当前最新设置的分辨率
GetCurrentDisplayMode();
if (!ctx_.bStandardSwitchResolution) {
// 记录当前的Mirror状态
bool old_is_mirror_state = connector_->is_connector_mirror_mode();
bool old_is_mirror_primary = connector_->is_connector_mirror_primary();
int old_mirror_primary_id = connector_->get_connector_mirror_primary_id();
std::set<int> old_mirror_set;
if (old_is_mirror_primary) {
old_mirror_set = connector_->get_connector_mirror_display_id();
}
drm_->UpdateDisplayMode(handle_);
UpdateDisplayInfo();
// RK3566 MirrorConn 分辨率切换流程需要从MirrorPrimary触发
if (isRK3566(resource_manager_->getSocId())) {
int display_id = drm_->GetCommitMirrorDisplayId();
drm_->UpdateDisplayMode(display_id);
}
// 再次确认更新分辨率后的Mirror状态
// MirrorPrimary 需要确认挂载在底下的所有MirrorExternal是否更新了Mirror状态如果更新并且正常获取DRM资源的需要注册到SurfaceFlinger;
// ConnectorMirror分辨率切换需要从MirrorPrimary流程中触发
if (old_is_mirror_primary) {
if (old_mirror_set.size() > 0) {
for (int old_mirror_display_id : old_mirror_set) {
DrmConnector* conn_mirror = drm_->GetConnectorForDisplay(old_mirror_display_id);
drm_->UpdateDisplayMode(old_mirror_display_id);
// 如果经过分辨率切换后,当前的 MirrorPrimary 退出了Mirror模式则需要注册副屏幕才行
if (conn_mirror->is_connector_mirror_mode() == false) {
if (conn_mirror->state() == DRM_MODE_CONNECTED &&
drm_->GetCrtcForDisplay(old_mirror_display_id) != NULL) {
// 发送热插拔注册事件
DrmEvent event;
event.type = HOTPLUG_USER_EVENT;
event.display_id = old_mirror_display_id;
event.connection = DRM_MODE_CONNECTED;
g_ctx->eventWorker_.SendDrmEvent(event);
} else {
HWC2_LOGW("MirrorDisplay: mirror_conn=%d, connection=%d crtc=%p state is error.",
conn_mirror->display(), conn_mirror->state(),
drm_->GetCrtcForDisplay(old_mirror_display_id));
}
}
}
}
} else { // 之前不是Mirror但是切换分辨率后进入了Mirror模式则需要销毁当前注册的屏幕
if (old_is_mirror_state == false && connector_->is_connector_mirror_mode() == true) {
// 发送热插拔注册事件
DrmEvent event;
event.type = HOTPLUG_USER_EVENT;
event.display_id = connector_->display();
event.connection = DRM_MODE_DISCONNECTED;
g_ctx->eventWorker_.SendDrmEvent(event);
}
}
}
return 0;
}
int DrmHwcTwo::HwcDisplay::UpdateDisplayInfo() {
if (!ctx_.bStandardSwitchResolution) {
const DrmMode active_mode = connector_->active_mode();
if (connector_->isHorizontalSplit()) {
ctx_.rel_xres = active_mode.h_display() / DRM_CONNECTOR_SPLIT_RATIO;
ctx_.rel_yres = active_mode.v_display();
if (handle_ >= DRM_CONNECTOR_SPLIT_MODE_MASK) {
ctx_.rel_xoffset = active_mode.h_display() / DRM_CONNECTOR_SPLIT_RATIO;
ctx_.rel_yoffset = 0; //best_mode.v_display() / 2;
}
} else if (connector_->isCropSplit()) {
ctx_.rel_xres = active_mode.h_display();
ctx_.rel_yres = active_mode.v_display();
} else {
ctx_.rel_xres = active_mode.h_display();
ctx_.rel_yres = active_mode.v_display();
}
ctx_.dclk = active_mode.clock();
}
return 0;
}
int DrmHwcTwo::HwcDisplay::UpdateOverscan() {
connector_->UpdateOverscan(handle_, &ctx_.left_margin, &ctx_.top_margin, &ctx_.right_margin, &ctx_.bottom_margin);
return 0;
}
int DrmHwcTwo::HwcDisplay::UpdateHdmiOutputFormat() {
int timeline = HwcAProperty::getInstance().getIntWithInterval("vendor.display.timeline", 100, -1);
/*
* force update propetry when timeline is zero or not exist.
*/
if (timeline && timeline == ctx_.display_timeline && ctx_.hotplug_timeline == drm_->timeline()) return 0;
connector_->UpdateOutputFormat(handle_, timeline);
if (isRK3566(resource_manager_->getSocId())) {
bool mirror_mode = true;
int display_id = drm_->GetCommitMirrorDisplayId();
DrmConnector* conn_mirror = drm_->GetConnectorForDisplay(display_id);
if (!conn_mirror || conn_mirror->state() != DRM_MODE_CONNECTED) {
ALOGI_IF(LogLevel(DBG_DEBUG), "%s,line=%d disable bCommitMirrorMode", __FUNCTION__, __LINE__);
mirror_mode = false;
}
if (mirror_mode) {
conn_mirror->UpdateOutputFormat(display_id, timeline);
}
}
return 0;
}
int DrmHwcTwo::HwcDisplay::UpdateBCSH() {
int timeline = HwcAProperty::getInstance().getIntWithInterval("vendor.display.timeline", 100, -1);
/*
* force update propetry when timeline is zero or not exist.
*/
if (timeline && timeline == ctx_.bcsh_timeline) return 0;
connector_->UpdateBCSH(handle_, timeline);
if (isRK3566(resource_manager_->getSocId())) {
bool mirror_mode = true;
int display_id = drm_->GetCommitMirrorDisplayId();
DrmConnector* conn_mirror = drm_->GetConnectorForDisplay(display_id);
if (!conn_mirror || conn_mirror->state() != DRM_MODE_CONNECTED) {
ALOGI_IF(LogLevel(DBG_DEBUG), "%s,line=%d disable bCommitMirrorMode", __FUNCTION__, __LINE__);
mirror_mode = false;
}
if (mirror_mode) {
conn_mirror->UpdateBCSH(display_id, timeline);
}
}
ctx_.bcsh_timeline = timeline;
return 0;
}
bool DrmHwcTwo::HwcDisplay::DisableHdrModeRK3588() {
DrmMode active_mode = connector_->active_mode();
// 如果是8K分辨率模式HDR片源没有走 overlay 策略则关闭HDR
// 主要原因是VOP硬件限制要求最底层为 HDR dataspaceGPU合成输出为SDR
// 不满足条件则需要关闭HDR模式
if (active_mode.id() > 0 && active_mode.is_8k_mode()) {
for (auto& drmHwcLayer : drm_hwc_layers_) {
if (drmHwcLayer.bHdr_) {
// 没有被硬件图层匹配则说明使用GPU合成
if (!drmHwcLayer.bMatch_) {
HWC2_LOGD_IF("HDR video compose by GLES on 8k resolution, Fource Disable HDR mode.");
return true;
}
}
}
}
return false;
}
bool DrmHwcTwo::HwcDisplay::DisableHdrMode() {
// 判断 当前屏幕的 crtc 是否支持 HDR
if (connector_ != NULL && connector_->encoder() != NULL && connector_->encoder()->crtc() != NULL) {
DrmCrtc* crtc = connector_->encoder()->crtc();
// 不支持则关闭HDR
if (crtc != NULL && crtc->get_hdr() == false) {
HWC2_LOGD_IF("crtc-id=%d port-id=%d unsupport hdr.", crtc->id(), crtc->get_port_id());
return true;
}
}
bool exist_hdr_layer = false;
int hdr_area_ratio = 0;
for (auto& drmHwcLayer : drm_hwc_layers_) {
if (drmHwcLayer.bHdr_) {
exist_hdr_layer = true;
int src_w, src_h, dis_w, dis_h;
// 如果使用RGA策略则使用原大小进行计算
if (drmHwcLayer.bUseRga_) {
src_w = (int)(drmHwcLayer.storeLayerInfo_.source_crop.right -
drmHwcLayer.storeLayerInfo_.source_crop.left);
src_h = (int)(drmHwcLayer.storeLayerInfo_.source_crop.bottom -
drmHwcLayer.storeLayerInfo_.source_crop.top);
dis_w = drmHwcLayer.storeLayerInfo_.display_frame.right -
drmHwcLayer.storeLayerInfo_.display_frame.left;
dis_h = drmHwcLayer.storeLayerInfo_.display_frame.bottom -
drmHwcLayer.storeLayerInfo_.display_frame.top;
} else {
src_w = (int)(drmHwcLayer.source_crop.right - drmHwcLayer.source_crop.left);
src_h = (int)(drmHwcLayer.source_crop.bottom - drmHwcLayer.source_crop.top);
dis_w = drmHwcLayer.display_frame.right - drmHwcLayer.display_frame.left;
dis_h = drmHwcLayer.display_frame.bottom - drmHwcLayer.display_frame.top;
}
int src_area_size = src_w * src_h;
int dis_area_size = dis_w * dis_h;
// 视频缩小倍数*10*10的原因是 vendor.hwc.hdr_video_area 为整型,不支持浮点数
hdr_area_ratio = dis_area_size * 10 / src_area_size;
int screen_size = ctx_.rel_xres * ctx_.rel_yres;
// 视频占屏幕面积*10取缩小倍数与视频占用屏幕面积较大值实现与操作
// 即需要同时满足视频缩小60%屏占60%才关闭HDR模式
// 缩放值判断可避免将如219比例的存在大黑边全屏视频播放场景误判屏占比不足而关闭HDR
if (hdr_area_ratio < (dis_area_size * 10 / screen_size)) hdr_area_ratio = dis_area_size * 10 / screen_size;
}
}
if (exist_hdr_layer) {
// 存在 HDR图层判断是否存在强制关闭HDR属性若存在则关闭HDR模式
if (HwcAProperty::getInstance().getIntWithInterval("persist.vendor.hwc.hdr_force_disable", 500, 0) > 0) {
if (ctx_.hdr_mode != DRM_HWC_SDR) {
HWC2_LOGD_IF("Exit HDR mode success");
property_set("vendor.hwc.hdr_state", "FORCE-NORMAL");
}
HWC2_LOGD_IF("Fource Disable HDR mode.");
return true;
}
// 存在 HDR图层判断HDR视频的屏幕占比与缩放倍率满足条件则关闭HDR模式
if (HwcAProperty::getInstance().getIntWithInterval("persist.vendor.hwc.hdr_video_area", 500, 6) >
hdr_area_ratio) {
if (ctx_.hdr_mode != DRM_HWC_SDR) {
HWC2_LOGD_IF("Exit HDR mode success");
property_set("vendor.hwc.hdr_state", "FORCE-NORMAL");
}
HWC2_LOGD_IF("Force Disable HDR mode.");
return true;
}
}
if (!exist_hdr_layer && ctx_.hdr_mode != DRM_HWC_SDR) {
ALOGD_IF(LogLevel(DBG_DEBUG), "Exit HDR mode success");
property_set("vendor.hwc.hdr_state", "NORMAL");
return true;
}
// 如果当前屏幕处于MirrorDisplay状态则需要检查其Mirror屏幕是否支持HDR
// 只要存在一个不支持HDR则采用SDR模式
if (connector_->is_connector_mirror_primary()) {
for (int mirror_display_id : connector_->get_connector_mirror_display_id()) {
DrmConnector* conn_mirror = drm_->GetConnectorForDisplay(mirror_display_id);
// 存在一路不支持HDR则关闭HDR模式
if (conn_mirror != NULL && conn_mirror->is_hdmi_support_hdr() == false) {
return true;
}
}
}
return false;
}
int DrmHwcTwo::HwcDisplay::EnableMetadataHdrMode(DrmHwcLayer& hdrLayer) {
HWC2_LOGI_IF("Id=%d Name=%s ", hdrLayer.uId_, hdrLayer.sLayerName_.c_str());
if (ctx_.display_type == DRM_MODE_CONNECTOR_TV) {
HWC2_LOGI_IF("RK3528 TV unsupport HDR2SDR, Id=%d Name=%s eDataSpace_=0x%x eotf=%d", hdrLayer.uId_,
hdrLayer.sLayerName_.c_str(), hdrLayer.eDataSpace_, hdrLayer.uEOTF);
return -1;
}
if (hdrLayer.bSideband2_) {
HWC2_LOGE_IF("Sideband2 layer skip, Id=%d Name=%s zpos=%d match=%d", hdrLayer.uId_,
hdrLayer.sLayerName_.c_str(), hdrLayer.iZpos_, hdrLayer.bMatch_);
return -1;
}
// Next hdr zpos must be 0
if (hdrLayer.iZpos_ > 0) {
HWC2_LOGE_IF("Next hdr zpos must be 0, Id=%d Name=%s zpos=%d", hdrLayer.uId_, hdrLayer.sLayerName_.c_str(),
hdrLayer.iZpos_);
return -1;
}
if (!hdrLayer.bMatch_) {
HWC2_LOGE_IF("Next hdr not overlay, Id=%d Name=%s zpos=%d match=%d", hdrLayer.uId_,
hdrLayer.sLayerName_.c_str(), hdrLayer.iZpos_, hdrLayer.bMatch_);
return -1;
}
// 算法解析库是否存在
DrmHdrParser* dhp = DrmHdrParser::Get();
if (dhp == NULL) {
HWC2_LOGE_IF("Fail to get DrmHdrParser, use SDR mode, Id=%d Name=%s ", hdrLayer.uId_,
hdrLayer.sLayerName_.c_str());
return -1;
}
// 显示器是否支持HDR
bool is_hdr_display = connector_->is_hdmi_support_hdr();
// 如果当前屏幕处于MirrorDisplay状态则需要检查其Mirror屏幕是否支持HDR
// 只要存在一个不支持HDR则采用SDR模式
if (connector_->is_connector_mirror_primary()) {
for (int mirror_display_id : connector_->get_connector_mirror_display_id()) {
DrmConnector* conn_mirror = drm_->GetConnectorForDisplay(mirror_display_id);
// 存在一路不支持HDR则关闭HDR模式
if (conn_mirror != NULL && conn_mirror->is_hdmi_support_hdr() == false) {
is_hdr_display = false;
break;
}
}
}
// 是否为 HDR 片源
bool is_input_hdr = hdrLayer.bHdr_;
// 2:自动模式: 电视支持 HDR模式播放HDR视频则切换HDR模式否则使用SDR模式
// 1:HDR模式: 等同自动模式
// 0:SDR模式: 电视强制使用SDR模式HDR片源也采用SDR显示
int user_hdr_mode = HwcAProperty::getInstance().getIntWithInterval("persist.sys.vivid.hdr_mode", 100, 2);
// 可能存在模式SDR2SDR,HDR2SDR,SDR2HDR,HDR2HDR
bool is_output_hdr = false;
// 2:自动模式: 电视支持 HDR模式播放HDR视频则切换HDR模式否则使用SDR模式
// 1:HDR模式: 电视支持 HDR模式则强制使用HDR模式SDR片源也采用HDR模式输出
if ((user_hdr_mode == 2 && is_hdr_display && is_input_hdr) ||
(user_hdr_mode == 1 && is_hdr_display && is_input_hdr)) {
is_output_hdr = true;
} else {
is_output_hdr = false;
}
// 如果输入是 SDR 且输出为SDR,则不需要进行任何处理
if (is_input_hdr == false && is_output_hdr == false) {
HWC2_LOGI_IF("Use SDR2SDR mode.");
return -1;
}
DrmGralloc* gralloc = DrmGralloc::getInstance();
if (gralloc == NULL) {
HWC2_LOGI_IF("DrmGralloc is null, Use SDR2SDR mode.");
return -1;
}
// debug 打印耗时
long t0 = __currentTime();
// 用于判断是否存在 metadata 信息
bool codec_meta_exist = false;
buffer_handle_t hdr_handle = NULL;
int hdr_width = 0;
int hdr_height = 0;
// 如果使用了RGA预缩小则需要从旧的 handle 中获取 metadata 信息
if (hdrLayer.bUseRga_) {
hdr_handle = hdrLayer.storeLayerInfo_.sf_handle;
hdr_width = hdrLayer.storeLayerInfo_.iWidth_;
hdr_height = hdrLayer.storeLayerInfo_.iHeight_;
} else {
hdr_handle = hdrLayer.sf_handle;
hdr_width = hdrLayer.iWidth_;
hdr_height = hdrLayer.iHeight_;
}
// 获取存储 metadata 信息的offset
int64_t offset = hdrLayer.bHasHdrMetadata_ ? hdrLayer.iHdrMetadataOffset_ : 0;
if (offset < 0) {
HWC2_LOGE_IF("Fail to get hdr metadata offset, Id=%d Name=%s ", hdrLayer.uId_, hdrLayer.sLayerName_.c_str());
}
// offset > 0 则认为存在 Metadata
codec_meta_exist = offset > 0;
HWC2_LOGI_IF("dynamic_hdr_metadata offset=%" PRIi64, offset);
// 初始化参数
memset(&hdrLayer.metadataHdrParam_, 0x00, sizeof(rk_hdr_parser_params_t));
// 如果输出模式为HDR
if (is_output_hdr) {
// Android bt2020 or bt709
switch (hdrLayer.eDataSpace_ & HAL_DATASPACE_STANDARD_MASK) {
case HAL_DATASPACE_STANDARD_BT2020:
case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.color_prim = COLOR_PRIM_BT2020;
break;
default:
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.color_prim = COLOR_PRIM_BT709;
break;
}
// 片源为 HLG且电视支持 HLG ,则选择 HLG bypass 模式
if (hdrLayer.uEOTF == HLG && connector_->isSupportHLG()) {
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf = SINK_EOTF_HLG;
// 片源为 HDR10且电视支持 HDR10 ,则选择 HDR10 bypass 模式
} else if (hdrLayer.uEOTF == SMPTE_ST2084 && connector_->isSupportSt2084()) {
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf = SINK_EOTF_ST2084;
// 若没有匹配的 HDR 模式,则优先使用 HDR10 输出
} else {
if (connector_->isSupportSt2084()) {
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf = SINK_EOTF_ST2084;
} else if (connector_->isSupportHLG()) {
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf = SINK_EOTF_HLG;
}
}
// hdr10 最小亮度应该是0.05,算法提供接口是要求外部数值 0.05*100=5
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.dst_min = 5;
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.dst_max =
HwcAProperty::getInstance().getIntWithInterval("persist.sys.vivid.max_brightness", 100, 1000) * 100;
} else {
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.color_prim = COLOR_PRIM_BT709;
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf = SINK_EOTF_GAMMA_SDR;
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.dst_min = 10;
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.dst_max =
HwcAProperty::getInstance().getIntWithInterval("persist.sys.vivid.max_brightness", 100, 100) * 100;
}
bool usemmap = false;
int fd = -1;
void* cpu_addr = NULL;
if (codec_meta_exist) {
// 获取Metadata地址优先使用mmap
if (hdrLayer.pBufferInfo_ != NULL) {
fd = hdrLayer.pBufferInfo_->uniqueFd_.get();
cpu_addr = hdrLayer.pBufferInfo_->pHdrMetadataVir_;
int ret = gralloc->hwc_buf_flush_read_cache_start(fd);
if (ret) {
HWC2_LOGE("hwc_buf_flush_read_cache_start fail ret=%d. name=%s", ret, hdrLayer.sLayerName_.c_str());
}
usemmap = true;
} else {
fd = gralloc->hwc_get_handle_primefd(hdr_handle);
cpu_addr = gralloc->hwc_get_handle_lock(hdr_handle, hdr_width, hdr_height);
}
if (cpu_addr == NULL) {
HWC2_LOGE_IF("Fail to lock dma buffer, Id=%d Name=%s ", hdrLayer.uId_, hdrLayer.sLayerName_.c_str());
hdrLayer.metadataHdrParam_.codec_meta_exist = false;
hdrLayer.metadataHdrParam_.p_hdr_codec_meta = NULL;
} else {
uint16_t* u16_cpu_metadata;
if (usemmap)
u16_cpu_metadata = (uint16_t*)((uint8_t*)cpu_addr);
else
u16_cpu_metadata = (uint16_t*)((uint8_t*)cpu_addr + offset);
hdrLayer.metadataHdrParam_.codec_meta_exist = codec_meta_exist;
hdrLayer.metadataHdrParam_.p_hdr_codec_meta = (RkMetaHdrHeader*)u16_cpu_metadata;
// 如果当前设置 hdr 显示模式为 HLG bypass则需要检测 HLG 片源是否为 dynamic Hdr
// 若为 dynamic Hdr则需要将输出模式修改为 Hdr10,若不支持Hdr10,则输出SDR
// 原因是目前 VOP3 是参考 VividHdr标准实现标准内部没有支持 dynamic hlg hdr 直出模式
if (hdrLayer.uEOTF == HLG && hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf == SINK_EOTF_HLG) {
int ret = dhp->MetadataHdrparserFormat(&hdrLayer.metadataHdrParam_, &hdrLayer.metadataHdrFmtInfo_);
if (ret) {
HWC2_LOGE_IF("MetadataHdrparserFormat, Id=%d Name=%s ", hdrLayer.uId_,
hdrLayer.sLayerName_.c_str());
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf = SINK_EOTF_ST2084;
} else {
if (hdrLayer.metadataHdrFmtInfo_.hdr_format == HDRVIVID) {
if (connector_->isSupportSt2084()) {
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf = SINK_EOTF_ST2084;
HWC2_LOGI_IF("Id=%d Name=%s is HLG dynamic, convert to HDR10.", hdrLayer.uId_,
hdrLayer.sLayerName_.c_str());
} else {
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf = SINK_EOTF_GAMMA_SDR;
HWC2_LOGI_IF("Id=%d Name=%s is HLG dynamic, convert to SDR.", hdrLayer.uId_,
hdrLayer.sLayerName_.c_str());
}
}
}
}
}
} else {
hdrLayer.metadataHdrParam_.codec_meta_exist = false;
hdrLayer.metadataHdrParam_.p_hdr_codec_meta = NULL;
}
// 为了处理杜比兼容 Hdr10 的情况,此时存在动态 metaHdr 解析库需要根据 Android Dataspace 修正参数
// 因此无论是否存在 metadata, 都需要将 Android Dataspace 信息传递给 Hdr 解析库
// Android bt2020 or bt709
switch (hdrLayer.eDataSpace_ & HAL_DATASPACE_STANDARD_MASK) {
case HAL_DATASPACE_STANDARD_BT2020:
case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
hdrLayer.metadataHdrParam_.hdr_dataspace_info.color_prim = COLOR_PRIM_BT2020;
break;
default:
hdrLayer.metadataHdrParam_.hdr_dataspace_info.color_prim = COLOR_PRIM_BT709;
break;
}
// Android st2084 / HLG / SDR
switch (hdrLayer.eDataSpace_ & HAL_DATASPACE_TRANSFER_MASK) {
case HAL_DATASPACE_TRANSFER_ST2084:
hdrLayer.metadataHdrParam_.hdr_dataspace_info.eotf = SINK_EOTF_ST2084;
break;
case HAL_DATASPACE_TRANSFER_HLG:
hdrLayer.metadataHdrParam_.hdr_dataspace_info.eotf = SINK_EOTF_HLG;
break;
default:
hdrLayer.metadataHdrParam_.hdr_dataspace_info.eotf = SINK_EOTF_GAMMA_SDR;
break;
}
// Android full / limit range
switch (hdrLayer.eDataSpace_ & HAL_DATASPACE_RANGE_MASK) {
case HAL_DATASPACE_RANGE_FULL:
hdrLayer.metadataHdrParam_.hdr_dataspace_info.range = HWC_HDR_RANGE_FULL;
break;
case HAL_DATASPACE_RANGE_LIMITED:
hdrLayer.metadataHdrParam_.hdr_dataspace_info.range = HWC_HDR_RANGE_LIMITED;
break;
default:
hdrLayer.metadataHdrParam_.hdr_dataspace_info.range = HWC_HDR_RANGE_LIMITED;
break;
}
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_pq_max_y_mode = 0;
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_dst_gamma = 2.2;
hdrLayer.metadataHdrParam_.hdr_user_cfg.s2h_sm_ratio = 1.0;
hdrLayer.metadataHdrParam_.hdr_user_cfg.s2h_scale_ratio = 1.0;
hdrLayer.metadataHdrParam_.hdr_user_cfg.s2h_sdr_color_space = 2;
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_debug_cfg.print_input_meta = 0;
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_debug_cfg.hdr_log_level = 0;
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_prop_set[0] = HDR_PLAT_DEFAULT;
if (isRK3528(ctx_.soc_id)) hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_prop_set[0] = HDR_PLAT_DEFAULT;
if (isRK356x(ctx_.soc_id)) hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_prop_set[0] = HDR_PLAT_RK356x;
if (isRK3576(ctx_.soc_id)) hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_prop_set[0] = HDR_PLAT_RK3576;
if (HwcAProperty::getInstance().getIntWithInterval("vendor.hwc.vivid_hdr_debug", 1000, 0) > 0) {
hdrLayer.uEOTF = hwc_get_int_property("vendor.hwc.vivid_layer_eotf", "0");
hdrLayer.metadataHdrParam_.codec_meta_exist =
hwc_get_bool_property("vendor.hwc.vivid_codec_meta_exist", "true");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.color_prim = hwc_get_int_property("vendor.hwc.vivid_color_prim", "0");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf = hwc_get_int_property("vendor.hwc.vivid_eotf", "0");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.red_x = hwc_get_int_property("vendor.hwc.vivid_red_x", "0");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.red_y = hwc_get_int_property("vendor.hwc.vivid_red_y", "0");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.green_x = hwc_get_int_property("vendor.hwc.vivid_green_x", "0");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.green_y = hwc_get_int_property("vendor.hwc.vivid_green_y", "0");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.white_point_x =
hwc_get_int_property("vendor.hwc.vivid_white_point_x", "0");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.white_point_y =
hwc_get_int_property("vendor.hwc.vivid_white_point_y", "0");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.dst_min = hwc_get_int_property("vendor.hwc.vivid_dst_min", "10");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.dst_max = hwc_get_int_property("vendor.hwc.vivid_dst_max", "10000");
hdrLayer.metadataHdrParam_.hdr_dataspace_info.color_prim =
hwc_get_int_property("vendor.hwc.vivid_dataspace_pri", "0");
hdrLayer.metadataHdrParam_.hdr_dataspace_info.eotf =
hwc_get_int_property("vendor.hwc.vivid_dataspace_eotf", "0");
hdrLayer.metadataHdrParam_.hdr_dataspace_info.range =
hwc_get_int_property("vendor.hwc.vivid_dataspace_range", "0");
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_pq_max_y_mode =
hwc_get_int_property("vendor.hwc.vivid_hdr_pq_max_y_mode", "0");
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_dst_gamma =
(hwc_get_int_property("vendor.hwc.vivid_hdr_dst_gamma", "22") * 1.0 / 10);
hdrLayer.metadataHdrParam_.hdr_user_cfg.s2h_sm_ratio =
hwc_get_int_property("vendor.hwc.vivid_s2h_sm_ratio", "10") * 1.0 / 10;
hdrLayer.metadataHdrParam_.hdr_user_cfg.s2h_scale_ratio =
hwc_get_int_property("vendor.hwc.vivid_s2h_scale_ratio", "10") * 1.0 / 10;
hdrLayer.metadataHdrParam_.hdr_user_cfg.s2h_sdr_color_space =
hwc_get_int_property("vendor.hwc.vivid_s2h_sdr_color_space", "2");
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_debug_cfg.print_input_meta =
hwc_get_int_property("vendor.hwc.vivid_print_input_meta", "1");
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_debug_cfg.hdr_log_level =
hwc_get_int_property("vendor.hwc.vivid_hdr_log_level", "7");
}
HWC2_LOGI_IF(
"hdr_hdmi_meta: user_hdr_mode(%d) layer eDataSpace=0x%x eotf=%d => codec_meta_exist(%d) "
"hdr_dataspace_info: color_prim=%d eotf=%d range=%d",
user_hdr_mode, hdrLayer.eDataSpace_, hdrLayer.uEOTF, hdrLayer.metadataHdrParam_.codec_meta_exist,
hdrLayer.metadataHdrParam_.hdr_dataspace_info.color_prim,
hdrLayer.metadataHdrParam_.hdr_dataspace_info.eotf, hdrLayer.metadataHdrParam_.hdr_dataspace_info.range);
HWC2_LOGI_IF(
"hdr_hdmi_meta: color_prim=%d eotf=%d red_x=%d red_y=%d green_x=%d green_y=%d white_point_x=%d "
"white_point_y=%d dst_min=%d dst_max=%d",
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.color_prim, hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf,
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.red_x, hdrLayer.metadataHdrParam_.hdr_hdmi_meta.red_y,
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.green_x, hdrLayer.metadataHdrParam_.hdr_hdmi_meta.green_y,
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.white_point_x,
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.white_point_y, hdrLayer.metadataHdrParam_.hdr_hdmi_meta.dst_min,
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.dst_max);
HWC2_LOGI_IF(
"hdr_user_cfg: hdr_pq_max_y_mode=%d hdr_dst_gamma=%f s2h_sm_ratio=%f s2h_scale_ratio=%f "
"s2h_sdr_color_space=%d print_input_meta=%d hdr_log_level=%d",
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_pq_max_y_mode,
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_dst_gamma, hdrLayer.metadataHdrParam_.hdr_user_cfg.s2h_sm_ratio,
hdrLayer.metadataHdrParam_.hdr_user_cfg.s2h_scale_ratio,
hdrLayer.metadataHdrParam_.hdr_user_cfg.s2h_sdr_color_space,
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_debug_cfg.print_input_meta,
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_debug_cfg.hdr_log_level);
int ret = dhp->MetadataHdrParser(&hdrLayer.metadataHdrParam_);
if (ret) {
HWC2_LOGE_IF("Fail to call MetadataHdrParser ret=%d Id=%d Name=%s ", ret, hdrLayer.uId_,
hdrLayer.sLayerName_.c_str());
if (cpu_addr != NULL) {
if (usemmap) {
gralloc->hwc_buf_flush_read_cache_end(fd);
} else {
gralloc->hwc_get_handle_unlock(hdr_handle);
}
}
return ret;
}
if (cpu_addr != NULL) {
if (usemmap) {
gralloc->hwc_buf_flush_read_cache_end(fd);
} else {
gralloc->hwc_get_handle_unlock(hdr_handle);
}
}
hdrLayer.IsMetadataHdr_ = true;
ctx_.hdr_mode = DRM_HWC_METADATA_HDR;
ctx_.dataspace = hdrLayer.eDataSpace_;
HWC2_LOGI_IF("Use HdrParser mode.");
return 0;
}
int DrmHwcTwo::HwcDisplay::EnableHdrMode(DrmHwcLayer& hdrLayer) {
HWC2_LOGI_IF("Id=%d Name=%s ", hdrLayer.uId_, hdrLayer.sLayerName_.c_str());
if (connector_->is_hdmi_support_hdr()) {
//Default to HDR10
DrmHdrType hdr_mode = DRM_HWC_HDR10;
if ((hdrLayer.eDataSpace_ & HAL_DATASPACE_TRANSFER_ST2084) == HAL_DATASPACE_TRANSFER_ST2084) {
hdr_mode = DRM_HWC_HDR10;
} else if ((hdrLayer.eDataSpace_ & HAL_DATASPACE_TRANSFER_HLG) == HAL_DATASPACE_TRANSFER_HLG) {
hdr_mode = DRM_HWC_HLG;
}
if (ctx_.hdr_mode != hdr_mode) {
ALOGD_IF(LogLevel(DBG_DEBUG), "Enable HDR mode success");
ctx_.hdr_mode = hdr_mode;
ctx_.dataspace = hdrLayer.eDataSpace_;
property_set("vendor.hwc.hdr_state", "HDR");
}
return 0;
}
return -1;
}
int DrmHwcTwo::HwcDisplay::UpdateSidebandMode() {
if (handle_ > 0) {
return 0;
}
// UpdateSideband state
DrmVideoProducer* dvp = DrmVideoProducer::getInstance();
if (!dvp->IsValid()) {
return -1;
}
// 判断是否存在Sideband图层并保存tunnel_id信息
int tunnel_id = 0;
uint64_t fps = 0;
android_dataspace_t dataspace;
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer>& l : layers_) {
if (l.second.isSidebandLayer()) {
tunnel_id = l.second.getTunnelId();
fps = l.second.GetSidebandLayerFps();
dataspace = (android_dataspace_t)l.second.GetSidebandLayerDataspace();
}
}
// 若存在合法 tunnel_id
if (tunnel_id > 0) {
if (tunnel_id != iLastTunnelId_) {
if (iLastTunnelId_ > 0) {
// tunnel id 不一致则先断开连接旧连接
int ret = dvp->DestoryConnection((int(handle_) + 1000), iLastTunnelId_);
if (ret) {
HWC2_LOGE_IF("DestoryConnection display=%" PRIu64 " tunnel-id=%d fail ret=%d", handle_,
iLastTunnelId_, ret);
} else {
HWC2_LOGI_IF("DestoryConnection display=%" PRIu64 " tunnel-id=%d success ret=%d", handle_,
iLastTunnelId_, ret);
}
}
// 创建新连接
int ret = dvp->CreateConnection((int(handle_) + 1000), tunnel_id, dataspace, DRM_MODE_ROTATE_0);
if (ret) {
HWC2_LOGE_IF("CreateConnection display=%" PRIu64 " fail tunnel-id=%d ret=%d", handle_, tunnel_id, ret);
} else {
dvp->SetProducerFps(tunnel_id, fps);
HWC2_LOGI_IF("CreateConnection display=%" PRIu64 " tunnel-id=%d success ret=%d", handle_, tunnel_id,
ret);
}
iLastTunnelId_ = tunnel_id;
}
} else {
if (iLastTunnelId_ > 0) {
// tunnel id 不一致则先断开连接旧连接
int ret = dvp->DestoryConnection((int(handle_) + 1000), iLastTunnelId_);
if (ret) {
HWC2_LOGE_IF("DestoryConnection display=%" PRIu64 " tunnel-id=%d fail ret=%d", handle_, iLastTunnelId_,
ret);
} else {
HWC2_LOGI_IF("DestoryConnection display=%" PRIu64 " tunnel-id=%d success ret=%d", handle_,
iLastTunnelId_, ret);
iLastTunnelId_ = 0;
}
}
}
return 0;
}
int DrmHwcTwo::HwcDisplay::SwitchHdrMode() {
// 需要HDR模式,找到 HDR layer,判断当前采用HDR模式
for (auto& drmHwcLayer : drm_hwc_layers_) {
if (drmHwcLayer.bYuv_) {
// MetadataHdr 模式特殊处理
#if defined(USE_VIVID_HDR) && USE_VIVID_HDR
if (crtc_ && crtc_->hdr_ext_data().id() > 0) {
if (EnableMetadataHdrMode(drmHwcLayer) == 0) {
return 0;
}
}
#endif
// 其他平台的 HDR 模式处理
if (drmHwcLayer.bHdr_) {
// 其他平台通用的判断是否需要进入HDR模式逻辑
if (DisableHdrMode()) {
ctx_.hdr_mode = DRM_HWC_SDR;
ctx_.dataspace = HAL_DATASPACE_UNKNOWN;
return 0;
}
// RK3588 平台特殊的判断逻辑
if (DisableHdrModeRK3588()) {
ctx_.hdr_mode = DRM_HWC_SDR;
ctx_.dataspace = HAL_DATASPACE_UNKNOWN;
return 0;
}
if (!EnableHdrMode(drmHwcLayer)) {
return 0;
}
}
}
}
ctx_.hdr_mode = DRM_HWC_SDR;
ctx_.dataspace = HAL_DATASPACE_UNKNOWN;
return 0;
}
int DrmHwcTwo::HwcDisplay::UpdateTimerEnable() {
bool enable_timer = true;
for (auto& drmHwcLayer : drm_hwc_layers_) {
// Video
if (drmHwcLayer.bYuv_) {
ALOGD_IF(LogLevel(DBG_DEBUG), "Yuv %s timer!", static_screen_timer_enable_ ? "Enable" : "Disable");
enable_timer = false;
break;
}
#if (defined USE_LIBSR) || (defined USE_LIBSVEP_MEMC)
// Sr
if (drmHwcLayer.bUseSr_) {
ALOGD_IF(LogLevel(DBG_DEBUG), "Sr %s timer!", static_screen_timer_enable_ ? "Enable" : "Disable");
enable_timer = false;
break;
}
// Memc
if (drmHwcLayer.bUseMemc_) {
ALOGD_IF(LogLevel(DBG_DEBUG), "Sr %s timer!", static_screen_timer_enable_ ? "Enable" : "Disable");
enable_timer = false;
break;
}
#endif
// Sideband
if (drmHwcLayer.bSidebandStreamLayer_) {
enable_timer = false;
break;
}
// Surface w/h is larger than FB
int crop_w = static_cast<int>(drmHwcLayer.source_crop.right - drmHwcLayer.source_crop.left);
int crop_h = static_cast<int>(drmHwcLayer.source_crop.bottom - drmHwcLayer.source_crop.top);
if (crop_w * crop_h > ctx_.framebuffer_width * ctx_.framebuffer_height) {
ALOGD_IF(LogLevel(DBG_DEBUG), "LargeSurface %s timer!", static_screen_timer_enable_ ? "Enable" : "Disable");
enable_timer = false;
break;
}
#ifdef USE_LIBPQ_HWPQ
if (drmHwcLayer.hwPqReg_ != NULL) {
HWC2_LOGD_IF("drmHwcLayer.hwPqReg_ != NULL , Disable Timer.");
enable_timer = false;
}
#endif
}
static_screen_timer_enable_ = enable_timer;
return 0;
}
int DrmHwcTwo::HwcDisplay::SelfRefreshEnable() {
bool enable_self_refresh = false;
int self_fps = 10;
for (auto& drmHwcLayer : drm_hwc_layers_) {
#if (defined USE_LIBSR) || (defined USE_LIBSVEP_MEMC)
// Sr
if (drmHwcLayer.bUseSr_) {
HWC2_LOGD_IF("Sr Enable SelfRefresh!");
enable_self_refresh = true;
self_fps = 10;
break;
}
// MEMC
// if(drmHwcLayer.bUseMemc_){
// HWC2_LOGD_IF("Memc Enable SelfRefresh!");
// enable_self_refresh = true;
// self_fps = 60;
// break;
// }
#endif
if (drmHwcLayer.bAccelerateLayer_ && !drmHwcLayer.bMatch_) {
enable_self_refresh = true;
self_fps = 30;
break;
}
}
if (resource_manager_->isWBMode()) {
enable_self_refresh = true;
if (self_fps < 30) self_fps = 30;
}
if (enable_self_refresh) {
InvalidateControl(self_fps, -1);
}
return 0;
}
int DrmHwcTwo::HwcDisplay::UpdateTimerState(bool gles_comp) {
struct itimerval tv = {{0, 0}, {0, 0}};
if (static_screen_timer_enable_ && gles_comp) {
int interval_value =
HwcAProperty::getInstance().getIntWithInterval("vendor.hwc.static_screen_opt_time", 1000, 2500);
interval_value = interval_value > 5000 ? 5000 : interval_value;
interval_value = interval_value < 250 ? 250 : interval_value;
tv.it_value.tv_sec = interval_value / 1000;
tv.it_value.tv_usec = (interval_value % 1000) * 1000;
HWC2_LOGV_IF("reset timer! interval_value = %d", interval_value);
} else {
static_screen_opt_ = false;
tv.it_value.tv_usec = 0;
HWC2_LOGV_IF("close timer!");
}
setitimer(ITIMER_REAL, &tv, NULL);
return 0;
}
int DrmHwcTwo::HwcDisplay::EntreStaticScreen(uint64_t refresh, int refresh_cnt) {
static_screen_opt_ = true;
invalidate_worker_.InvalidateControl(refresh, refresh_cnt);
return 0;
}
int DrmHwcTwo::HwcDisplay::InvalidateControl(uint64_t refresh, int refresh_cnt) {
invalidate_worker_.InvalidateControl(refresh, refresh_cnt);
return 0;
}
int DrmHwcTwo::HwcDisplay::DoMirrorDisplay(int32_t* retire_fence) {
if (!connector_->isCropSplit()) {
return 0;
}
if (!connector_->IsSplitPrimary()) {
return 0;
}
if (CheckDisplayState() == HWC2::Error::None) {
// 拼接主屏获取到实际的ClientBuffer后需要重新调用 TryHwcPolicy 执行策略匹配
int ret = 0;
std::vector<DrmHwcLayer*> layers;
layers.reserve(drm_hwc_layers_.size());
for (size_t i = 0; i < drm_hwc_layers_.size(); ++i) {
layers.push_back(&drm_hwc_layers_[i]);
}
for (auto& drm_hwc_layer : drm_hwc_layers_) {
if (drm_hwc_layer.bFbTarget_) {
uint32_t client_id = 0;
client_layer_.PopulateFB(client_id, &drm_hwc_layer, &ctx_, frame_no_, false);
ret = client_layer_.initOrGetGemhanleFromCache(&drm_hwc_layer);
if (ret) {
ALOGE("Failed to get_gemhanle client_layer, ret=%d", ret);
return ret;
}
}
}
std::vector<PlaneGroup*> plane_groups;
DrmDevice* drm = crtc_->getDrmDevice();
plane_groups.clear();
std::vector<PlaneGroup*> all_plane_groups = drm->GetPlaneGroups();
for (auto& plane_group : all_plane_groups) {
if (plane_group->acquire(1 << crtc_->pipe(), handle_)) {
// RK3576平台动态迁移功能如果需要disable的图层则不进行策略匹配
if (plane_group->is_will_disable() == false) {
plane_groups.push_back(plane_group);
} else {
HWC2_LOGD_IF("%s will disable, display-id(%" PRIi64 "->%" PRIi64 ") crtc_mask(0x%" PRIx32
" -> 0x%" PRIx32 ")",
plane_group->planes[0]->name(), plane_group->possible_display_,
plane_group->next_possible_display_, plane_group->current_crtc_,
plane_group->next_crtc_);
continue;
}
}
}
std::tie(ret, composition_planes_) =
planner_->TryHwcPolicy(layers, plane_groups, crtc_, static_screen_opt_ || force_gles_);
if (ret) {
ALOGE("First, GLES policy fail ret=%d", ret);
return -1;
}
}
int32_t merge_rt_fence = -1;
int32_t display_cnt = 1;
for (auto& conn : drm_->connectors()) {
if (!conn->isCropSplit()) {
continue;
}
int display_id = conn->display();
// 非拼接主屏需要将主屏幕ClientBuffer作为一般Buffer传入
if (!conn->IsSplitPrimary()) {
auto& display = resource_manager_->GetHwc2()->displays_.at(display_id);
if (conn->state() == DRM_MODE_CONNECTED) {
if (display.GetSplitDummyLayer() > 0 && display.has_layer(display.GetSplitDummyLayer())) {
// 获取SplitLayer并设置拼接屏幕的BufferHandle
HwcLayer& split_layer = display.get_layer(display.GetSplitDummyLayer());
split_layer.SetLayerBuffer(client_layer_.buffer(), dup(client_layer_.acquire_fence()->getFd()));
uint32_t num_types;
uint32_t num_requests;
display.ValidateDisplay(&num_types, &num_requests);
display.AcceptDisplayChanges();
int32_t rt_fence = -1;
display.PresentDisplay(&rt_fence);
if (merge_rt_fence > 0) {
char acBuf[32];
sprintf(acBuf, "RTD%" PRIu64 "M-FN%d-%d", handle_, frame_no_, display_cnt++);
sp<ReleaseFence> rt = sp<ReleaseFence>(new ReleaseFence(rt_fence, acBuf));
if (rt->isValid()) {
sprintf(acBuf, "RTD%" PRIu64 "M-FN%d-%d", handle_, frame_no_, display_cnt++);
int32_t merge_rt_fence_temp = merge_rt_fence;
merge_rt_fence = rt->merge(merge_rt_fence, acBuf);
close(merge_rt_fence_temp);
} else {
HWC2_LOGE("connector %u type=%s, type_id=%d is MirrorDisplay get retireFence fail.\n",
conn->id(), drm_->connector_type_str(conn->type()), conn->type_id());
}
} else {
merge_rt_fence = rt_fence;
}
}
}
}
}
*retire_fence = merge_rt_fence;
return 0;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetOrCreateDummyLayer() {
std::unique_lock<std::recursive_mutex> lock(mDisplayMutex_);
if (uCropSplitDummyLayer_ > 0 && has_layer(uCropSplitDummyLayer_)) {
return HWC2::Error::None;
} else {
CreateLayer(&uCropSplitDummyLayer_);
HwcLayer& dummy_layer = get_layer(uCropSplitDummyLayer_);
// 设置 frame 信息
hwc_rect_t frame = {0, 0, ctx_.framebuffer_width, ctx_.framebuffer_height};
dummy_layer.SetLayerDisplayFrame(frame);
// 设置 crop信息
int32_t srcX = 0, srcY = 0, srcW = 0, srcH = 0;
connector_->getCropInfo(&srcX, &srcY, &srcW, &srcH);
hwc_frect_t crop = {static_cast<float>(srcX), static_cast<float>(srcY), static_cast<float>(srcX + srcW),
static_cast<float>(srcY + srcH)};
dummy_layer.SetLayerSourceCrop(crop);
dummy_layer.SetLayerZOrder(0);
dummy_layer.SetLayerBlendMode(HWC2_BLEND_MODE_NONE);
dummy_layer.SetLayerPlaneAlpha(1.0);
dummy_layer.SetLayerCompositionType(HWC2_COMPOSITION_DEVICE);
// 设置旋转信息
int32_t transform = connector_->getCropSplitTransform();
switch (transform) {
case static_cast<int32_t>(HWC2::Transform::None):
case static_cast<int32_t>(HWC2::Transform::FlipH):
case static_cast<int32_t>(HWC2::Transform::FlipV):
case static_cast<int32_t>(HWC2::Transform::Rotate90):
case static_cast<int32_t>(HWC2::Transform::Rotate180):
case static_cast<int32_t>(HWC2::Transform::Rotate270):
case static_cast<int32_t>(HWC2::Transform::FlipHRotate90):
case static_cast<int32_t>(HWC2::Transform::FlipVRotate90):
break;
default:
HWC2_LOGW("SplitMode: invalid transform=%d", transform);
transform = 0;
break;
}
dummy_layer.SetLayerTransform(transform);
HWC2_LOGI("SplitMode: display=%" PRIu64 " Create dummylayer = %" PRIu64
" crop=[%f,%f,%f,%f] frame=[%d,%d,%d,%d] transform=%s",
handle_, uCropSplitDummyLayer_, crop.left, crop.top, crop.right, crop.bottom, frame.left, frame.top,
frame.right, frame.bottom, getTransformName(static_cast<hwc_transform_t>(transform)));
return HWC2::Error::None;
}
}
HWC2::Error DrmHwcTwo::HwcDisplay::DestoryDummyLayer() {
std::unique_lock<std::recursive_mutex> lock(mDisplayMutex_);
if (uCropSplitDummyLayer_ > 0 && has_layer(uCropSplitDummyLayer_)) {
HWC2_LOGI("SplitMode: display=%" PRIu64 " Destory dummylayer = %" PRIu64, handle_, uCropSplitDummyLayer_);
auto ret = DestroyLayer(uCropSplitDummyLayer_);
uCropSplitDummyLayer_ = 0;
return ret;
} else {
return HWC2::Error::None;
}
}
int DrmHwcTwo::HwcDisplay::EnableDumpWithWB() {
//如果已经使能,不重复使能
if (bDumpWbEnabled_) {
HWC2_LOGD_IF("dump: Dump WriteBack is enabled, not enable again.");
return 0;
}
//检查当前屏幕是否为Writeback屏幕
int write_back_id = property_get_int32("vendor.hwc.virtual_display_write_back_id", 0);
if (write_back_id != handle_) {
HWC2_LOGD_IF("dump: writeback id =%d not match display=%" PRIu64 ", skip", write_back_id, handle_);
return 0;
}
iDumpWbDisplayId_ = write_back_id;
//注册Writeback回调
auto writeback_callback = [](std::shared_ptr<DrmBuffer> buffer, void* argument) {
buffer->DumpData(/*z-pos*/ 0, "M");
};
if (iDumpWBCallbackId_ >= 0) resource_manager_->UnregisterWBCallback(iDumpWbDisplayId_, iDumpWBCallbackId_);
iDumpWBCallbackId_ = resource_manager_->RegisterWBCallback(iDumpWbDisplayId_, writeback_callback, &frame_no_);
if (iDumpWBCallbackId_ < 0) {
//this should never happend
HWC2_LOGE("dump: Failed to register WB callback");
return -1;
}
//启用Writeback
int ret = resource_manager_->EnableWriteBackMode(iDumpWbDisplayId_);
HWC2_LOGI("dump: Enable WriteBack for Dispaly %" PRIu64 " %s, ret=%d", handle_, ret ? "Failed" : "OK", ret);
bDumpWbEnabled_ = (ret == 0);
return ret;
}
int DrmHwcTwo::HwcDisplay::DisableDumpWithWB() {
if (bDumpWbEnabled_) {
if (iDumpWBCallbackId_ >= 0) {
resource_manager_->UnregisterWBCallback(iDumpWbDisplayId_, iDumpWBCallbackId_);
iDumpWBCallbackId_ = -1;
}
HWC2_LOGI("dump: Disable WriteBack for Dispaly %" PRIu64 ", WBDisplay=%d", handle_, iDumpWbDisplayId_);
resource_manager_->DisableWriteBackMode(iDumpWbDisplayId_);
bDumpWbEnabled_ = false;
}
return 0;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerBlendMode(int32_t mode) {
HWC2_LOGV_IF("layer-id=%d, blend=%d", id_, mode);
mCurrentState.blending_ = static_cast<HWC2::BlendMode>(mode);
bUpdate_ = true;
return HWC2::Error::None;
}
// 此定义位于 hardware/interfaces/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h
#define RK_BUFFER_SLOT_SHIFT 8
#define RK_BUFFER_CACHE_SHIFT 16
#define RK_BUFFER_USE_CACHE_FLAG 1
#define RK_BUFFER_USE_UNCACHE_FLAG (1 << 1)
#define RK_DECODING_CALCULATION(value, shift) (((value * (-1)) >> shift) & 0xff)
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerBuffer(buffer_handle_t buffer, int32_t acquire_fence) {
HWC2_LOGV_IF("layer-id=%d, buffer=%p, acq_fence=%d", id_, buffer, acquire_fence);
//Deleting the following logic may cause the problem that the handle cannot be updated
// The buffer and acquire_fence are handled elsewhere
// if (sf_type_ == HWC2::Composition::Client ||
// sf_type_ == HWC2::Composition::Sideband ||
// sf_type_ == HWC2::Composition::SolidColor)
// return HWC2::Error::None;
if (mCurrentState.sf_type_ == HWC2::Composition::Sideband) {
return HWC2::Error::None;
}
// 动态切换刷新率过程中SurfaceFlinger会出现 SetLayerBuffer target=null的情况
// 为了避免错误日志打印,故暂时对这种情况进行规避;
if (buffer == NULL) {
HWC2_LOGW("Buffer is NULL, skip SetLayerBuffer");
if (acquire_fence > 0) {
close(acquire_fence);
}
return HWC2::Error::None;
}
// 应用端可能会不销毁 Surface 直接将Sideband图层修改为一般图层故需要重置Sideband相关配置
bSideband2_ = false;
bSideband2Valid_ = false;
sidebandStreamHandle_ = NULL;
/* RK 内部实现 cache 方法:
* acquire_fence 原则上是只会出现 -1 或者 > 0 的数值,目前 RK 利用 < -1 的值范围
* 传递 cache 信息,具体方法如下:
* 1. 如果 acquire_fence 出现 小于 -1 的值,则说明 RK 内部实现的cache方法生效
* 2. acquire_fence 通过如下方法构造:
* 2.1. acquire_fence |= CACHE_SLOT << RK_BUFFER_SLOT_SHIFT
* 2.2. acquire_fence |= (USE_CACHE or USE_UNCACHE) << RK_BUFFER_CACHE_SHIFT
* 2.3 acquire_fence = acquire_fence * (-1)
*
* on Android14,
* slot is counting form 0 to 64,
* on pervious Android version,
* slot is counting form 64 to 0.
*/
if (acquire_fence < -1) {
bUseSlotCache = RK_DECODING_CALCULATION(acquire_fence, RK_BUFFER_CACHE_SHIFT) == RK_BUFFER_USE_CACHE_FLAG;
uCacheSlot = RK_DECODING_CALCULATION(acquire_fence, RK_BUFFER_SLOT_SHIFT);
if (uCacheSlot >= 0) {
HWC2_LOGD_IF("use_cache=%d cache_slot=%d", bUseSlotCache, uCacheSlot);
return HWC2::Error::None;
}
}
// 部分video不希望使用cache逻辑因为可能会导致oom问题
bool need_cache = true;
ResourceManager* rm = ResourceManager::getInstance();
int buffer_limit_size = rm->GetCacheBufferLimitSize();
if (buffer_limit_size > 0) {
int format = drmGralloc_->hwc_get_handle_attibute(buffer, ATT_FORMAT);
uint32_t fourcc = drmGralloc_->hwc_get_handle_fourcc_format(buffer);
if (drmGralloc_->is_yuv_format(format, fourcc)) {
int width = drmGralloc_->hwc_get_handle_attibute(buffer_, ATT_WIDTH);
int height = drmGralloc_->hwc_get_handle_attibute(buffer_, ATT_HEIGHT);
if (width * height > buffer_limit_size) {
need_cache = false;
}
}
}
if (need_cache) {
if (uCacheSlot >= 0) {
CacheBufferInfoBySlot(buffer, bUseSlotCache, uCacheSlot);
} else {
CacheBufferInfo(buffer);
}
} else {
NoCacheBufferInfo(buffer);
}
acquire_fence_ = sp<AcquireFence>(new AcquireFence(acquire_fence));
bUseSlotCache = false;
uCacheSlot = -1;
bUpdate_ = true;
// #564052 , 存在 SolidColor layer转换为 Normal Layer的可能
// 故当Layer存在有效的BufferHandle时需要将 SolidColor 标志重置
mCurrentState.solid_color_buffer_ = NULL;
mCurrentState.is_solid_color_ = false;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerColor(hwc_color_t color) {
HWC2_LOGV_IF("layer-id=%d, color [r,g,b,a]=[%d,%d,%d,%d]", id_, color.r, color.g, color.b, color.a);
// TODO: Punt to client composition here?
mCurrentState.color_ = color;
ResourceManager* rm = ResourceManager::getInstance();
if (rm != NULL && rm->IsSupportSolidColor()) {
// 将 argb值转换为 uint32_t, 由于填充格式为 AB24需要根据[31:0] A:B:G:R 8:8:8:8 little endian 构造 uint32_t值
uint32_t value_rgba = (mCurrentState.color_.a << 24) | (mCurrentState.color_.b << 16) |
(mCurrentState.color_.g << 8) | (mCurrentState.color_.r);
// TODO: 暂时先用 1920x1080 size实现后续查看是否用哪个参数
mCurrentState.solid_color_buffer_ = rm->GetSolidColorBuffer(value_rgba, 960, 544);
if (mCurrentState.solid_color_buffer_ != NULL) {
mCurrentState.is_solid_color_ = true;
}
}
bUpdate_ = true;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerCompositionType(int32_t type) {
HWC2_LOGV_IF("layer-id=%d, type=0x%x", id_, type);
#if PLATFORM_SDK_VERSION >= 34
mCurrentState.hwc3_sf_type_ = type;
if (mCurrentState.hwc3_sf_type_ == HWC3_COMPOSITION_DISPLAY_DECORATION) return HWC2::Error::Unsupported;
#endif
mCurrentState.sf_type_ = static_cast<HWC2::Composition>(type);
bUpdate_ = true;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDataspace(int32_t dataspace) {
HWC2_LOGV_IF("layer-id=%d, dataspace=0x%x", id_, dataspace);
mCurrentState.dataspace_ = static_cast<android_dataspace_t>(dataspace);
bUpdate_ = true;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDisplayFrame(hwc_rect_t frame) {
HWC2_LOGV_IF("layer-id=%d, frame=[%d,%d,%d,%d]", id_, frame.left, frame.top, frame.right, frame.bottom);
mCurrentState.display_frame_ = frame;
bUpdate_ = true;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerPlaneAlpha(float alpha) {
HWC2_LOGV_IF("layer-id=%d, alpha=%f", id_, alpha);
mCurrentState.alpha_ = alpha;
bUpdate_ = true;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSidebandStream(const native_handle_t* stream) {
HWC2_LOGV_IF("layer-id=%d stream=%p", id_, stream);
ResourceManager* rm = ResourceManager::getInstance();
if (rm->IsSidebandStream2Mode()) {
if (stream != NULL) {
vt_sideband_data_t* sbi = (vt_sideband_data_t*)(stream->data);
// 如果 Tunnel Id 有效,并且是未连接状态,则创建连接
if (sbi->tunnel_id != mSidebandInfo_.tunnel_id) {
HWC2_LOGD_IF("SidebandStream: layer-id=%d. version=%d numFds=%d numInts=%d", id_, stream->version,
stream->numFds, stream->numInts);
HWC2_LOGD_IF("SidebandStream: version=%d sizeof=%zu tunnel-id=%d session-id=%" PRIu64
" crop[%d,%d,%d,%d] w=%d h=%d ws=%d hs=%d bs=%d f=%d transform=%d size=%d "
"modifier=%d usage=0x%" PRIx64 " dataSpace=0x%" PRIx64 " afbc=%d fps=%" PRIu64 "",
stream->data[0], sizeof(vt_sideband_data_t), sbi->tunnel_id, sbi->session_id,
sbi->crop.left, sbi->crop.top, sbi->crop.right, sbi->crop.bottom, sbi->width, sbi->height,
sbi->hor_stride, sbi->ver_stride, sbi->byte_stride, sbi->format, sbi->transform, sbi->size,
sbi->modifier, sbi->usage, sbi->data_space, sbi->compress_mode, sbi->fps);
bSideband2Valid_ = true;
memcpy(&mSidebandInfo_, sbi, sizeof(vt_sideband_data_t));
}
// sbi->tunnel_id 不等于0才认为是有效的Sideband 2.0 handle
if (sbi->tunnel_id != 0) {
sidebandStreamHandle_ = stream;
} else { // 否则设置为NULL
sidebandStreamHandle_ = NULL;
}
}
bSideband2_ = true;
} else {
setSidebandStream(stream);
}
// #564052 , 存在 SolidColor layer转换为 Normal Layer的可能
// 故当Layer存在有效的BufferHandle时需要将 SolidColor 标志重置
mCurrentState.solid_color_buffer_ = NULL;
mCurrentState.is_solid_color_ = false;
bUpdate_ = true;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSourceCrop(hwc_frect_t crop) {
HWC2_LOGV_IF("layer-id=%d, frame=[%f,%f,%f,%f]", id_, crop.left, crop.top, crop.right, crop.bottom);
mCurrentState.source_crop_ = crop;
bUpdate_ = true;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSurfaceDamage(hwc_region_t damage) {
HWC2_LOGV_IF("layer-id=%d", id_);
// TODO: We don't use surface damage, marking as unsupported
unsupported(__func__, damage);
bUpdate_ = true;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerTransform(int32_t transform) {
HWC2_LOGV_IF("layer-id=%d, transform=%x", id_, transform);
mCurrentState.transform_ = static_cast<HWC2::Transform>(transform);
bUpdate_ = true;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerVisibleRegion(hwc_region_t visible) {
HWC2_LOGV_IF("layer-id=%d", id_);
// TODO: We don't use this information, marking as unsupported
unsupported(__func__, visible);
bUpdate_ = true;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerZOrder(uint32_t order) {
HWC2_LOGV_IF("layer-id=%d, z=%d", id_, order);
mCurrentState.z_order_ = order;
bUpdate_ = true;
return HWC2::Error::None;
}
#if PLATFORM_SDK_VERSION >= 34
// Composer 2.2 : TODO:
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerPerFrameMetadata(uint32_t numElements,
const int32_t* /*hw2_per_frame_metadata_key_t*/ keys,
const float* metadata) {
HWC2_LOGV_IF("layer-id=%d", id_);
return HWC2::Error::None;
}
// TODO:
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerFloatColor(hwc_float_color_t color) {
HWC2_LOGV_IF("layer-id=%d", id_);
return HWC2::Error::None;
}
// Composer 2.3 TODO:
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerPerFrameMetadataBlobs(uint32_t numElements,
const int32_t* /*hw2_per_frame_metadata_key_t*/ keys,
const uint32_t* sizes, const uint8_t* metadata) {
HWC2_LOGV_IF("layer-id=%d", id_);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerColorTransform(const float* matrix) {
HWC2_LOGV_IF("layer-id=%d", id_);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerGenericMetadata(uint32_t keyLength, const char* key, bool mandatory,
uint32_t valueLength, const uint8_t* value) {
HWC2_LOGV_IF("layer-id=%d", id_);
return HWC2::Error::None;
}
#endif
void DrmHwcTwo::HwcLayer::PopulateSidebandLayer(DrmHwcLayer* drmHwcLayer, hwc2_drm_display_t* ctx) {
// sideband layer
if (bSideband2_) {
if (bSideband2Valid_) {
drmHwcLayer->iTunnelId_ = mSidebandInfo_.tunnel_id;
drmHwcLayer->bSidebandStreamLayer_ = true;
drmHwcLayer->sf_handle = NULL;
drmHwcLayer->SetDisplayFrame(mCurrentState.display_frame_, ctx);
hwc_frect source_crop;
source_crop.left = mSidebandInfo_.crop.left;
source_crop.top = mSidebandInfo_.crop.top;
source_crop.right = mSidebandInfo_.crop.right;
source_crop.bottom = mSidebandInfo_.crop.bottom;
drmHwcLayer->SetSourceCrop(source_crop);
drmHwcLayer->SetTransform(mCurrentState.transform_);
// Commit mirror function
drmHwcLayer->SetDisplayFrameMirror(mCurrentState.display_frame_);
drmHwcLayer->iFd_ = -1;
drmHwcLayer->iWidth_ = mSidebandInfo_.crop.right - mSidebandInfo_.crop.left;
drmHwcLayer->iHeight_ = mSidebandInfo_.crop.bottom - mSidebandInfo_.crop.top;
drmHwcLayer->iStride_ = mSidebandInfo_.crop.right - mSidebandInfo_.crop.left;
drmHwcLayer->iFormat_ = mSidebandInfo_.format;
drmHwcLayer->iUsage = mSidebandInfo_.usage;
drmHwcLayer->iHeightStride_ = mSidebandInfo_.crop.bottom - mSidebandInfo_.crop.top;
drmHwcLayer->uFourccFormat_ = drmGralloc_->hwc_get_fourcc_from_hal_format(mSidebandInfo_.format);
drmHwcLayer->fFps_ = mSidebandInfo_.fps;
drmHwcLayer->bSideband2_ = true;
// 通过 Sideband Handle compress_mode 来判断图层是否为AFBC压缩格式
if (mSidebandInfo_.compress_mode > 0) {
if (gIsRK3576()) {
HWC2_LOGD_IF("TODO: AFBC/RFBC Need to be updated for RK3576!!!");
drmHwcLayer->uModifier_ = AFBC_FORMAT_MOD_BLOCK_SIZE_32x8;
} else {
drmHwcLayer->uModifier_ = AFBC_FORMAT_MOD_BLOCK_SIZE_16x16;
}
} else {
drmHwcLayer->uModifier_ = 0;
}
drmHwcLayer->uGemHandle_ = 0;
drmHwcLayer->sLayerName_ = std::string("SidebandStream-2.0");
drmHwcLayer->eDataSpace_ = (android_dataspace_t)mSidebandInfo_.data_space;
} else {
drmHwcLayer->iFd_ = -1;
drmHwcLayer->iWidth_ = -1;
drmHwcLayer->iHeight_ = -1;
drmHwcLayer->iStride_ = -1;
drmHwcLayer->iFormat_ = -1;
drmHwcLayer->iUsage = 0;
drmHwcLayer->iHeightStride_ = -1;
drmHwcLayer->uFourccFormat_ = 0x20202020; //0x20 is space
drmHwcLayer->uModifier_ = 0;
drmHwcLayer->uGemHandle_ = 0;
drmHwcLayer->sLayerName_.clear();
}
} else {
drmHwcLayer->bSidebandStreamLayer_ = true;
drmHwcLayer->sf_handle = mCurrentState.sidebandStreamHandle_;
drmHwcLayer->SetDisplayFrame(mCurrentState.display_frame_, ctx);
hwc_frect source_crop;
source_crop.top = 0;
source_crop.left = 0;
source_crop.right = pBufferInfo_->iWidth_;
source_crop.bottom = pBufferInfo_->iHeight_;
drmHwcLayer->SetSourceCrop(source_crop);
drmHwcLayer->SetTransform(mCurrentState.transform_);
// Commit mirror function
drmHwcLayer->SetDisplayFrameMirror(mCurrentState.display_frame_);
if (mCurrentState.sidebandStreamHandle_) {
drmHwcLayer->iFd_ = pBufferInfo_->uniqueFd_.get();
drmHwcLayer->iWidth_ = pBufferInfo_->iWidth_;
drmHwcLayer->iHeight_ = pBufferInfo_->iHeight_;
drmHwcLayer->iStride_ = pBufferInfo_->iStride_;
drmHwcLayer->iFormat_ = pBufferInfo_->iFormat_;
drmHwcLayer->iUsage = pBufferInfo_->iUsage_;
drmHwcLayer->iHeightStride_ = pBufferInfo_->iHeightStride_;
drmHwcLayer->iByteStride_ = pBufferInfo_->iByteStride_;
drmHwcLayer->uFourccFormat_ = pBufferInfo_->uFourccFormat_;
drmHwcLayer->uModifier_ = pBufferInfo_->uModifier_;
drmHwcLayer->sLayerName_ = pBufferInfo_->sLayerName_;
} else {
drmHwcLayer->iFd_ = -1;
drmHwcLayer->iWidth_ = -1;
drmHwcLayer->iHeight_ = -1;
drmHwcLayer->iStride_ = -1;
drmHwcLayer->iFormat_ = -1;
drmHwcLayer->iUsage = 0;
drmHwcLayer->iHeightStride_ = -1;
drmHwcLayer->uFourccFormat_ = 0x20202020; //0x20 is space
drmHwcLayer->uModifier_ = 0;
drmHwcLayer->uGemHandle_ = 0;
drmHwcLayer->sLayerName_.clear();
}
}
drmHwcLayer->Init();
return;
}
void DrmHwcTwo::HwcLayer::PopulateNormalLayer(DrmHwcLayer* drmHwcLayer, hwc2_drm_display_t* ctx) {
drmHwcLayer->SetDisplayFrame(mCurrentState.display_frame_, ctx);
drmHwcLayer->SetSourceCrop(mCurrentState.source_crop_);
drmHwcLayer->SetTransform(mCurrentState.transform_);
// Commit mirror function
drmHwcLayer->SetDisplayFrameMirror(mCurrentState.display_frame_);
if (buffer_ && pBufferInfo_ != NULL) {
drmHwcLayer->sf_handle = buffer_;
drmHwcLayer->uBufferId_ = pBufferInfo_->uBufferId_;
// 利用 dup dma-buffer-fd 来增加对 dma-buffer 的引用计数
// 避免 dma-buffer 被提前释放
drmHwcLayer->iFd_ = pBufferInfo_->uniqueFd_.get();
drmHwcLayer->iWidth_ = pBufferInfo_->iWidth_;
drmHwcLayer->iHeight_ = pBufferInfo_->iHeight_;
drmHwcLayer->iStride_ = pBufferInfo_->iStride_;
drmHwcLayer->iSize_ = pBufferInfo_->iSize_;
drmHwcLayer->iFormat_ = pBufferInfo_->iFormat_;
drmHwcLayer->iUsage = pBufferInfo_->iUsage_;
drmHwcLayer->iHeightStride_ = pBufferInfo_->iHeightStride_;
drmHwcLayer->iByteStride_ = pBufferInfo_->iByteStride_;
drmHwcLayer->uFourccFormat_ = pBufferInfo_->uFourccFormat_;
drmHwcLayer->uModifier_ = pBufferInfo_->uModifier_;
drmHwcLayer->sLayerName_ = pBufferInfo_->sLayerName_;
drmHwcLayer->uByteStridePlanes_ = pBufferInfo_->uByteStridePlanes_;
// 同步 PQ metadata 与 offset
drmHwcLayer->bHasPqMetadata_ = pBufferInfo_->bHasPqMetadata_;
drmHwcLayer->iPqMetadataOffset_ = pBufferInfo_->iPqMetadataOffset_;
// 同步 HDR metadata 与 offset
drmHwcLayer->bHasHdrMetadata_ = pBufferInfo_->bHasHdrMetadata_;
drmHwcLayer->iHdrMetadataOffset_ = pBufferInfo_->iHdrMetadataOffset_;
drmHwcLayer->fVideoFps_ = pBufferInfo_->fVideoFps_;
drmHwcLayer->pBufferInfo_ = pBufferInfo_;
} else {
drmHwcLayer->iFd_ = -1;
drmHwcLayer->iWidth_ = -1;
drmHwcLayer->iHeight_ = -1;
drmHwcLayer->iStride_ = -1;
drmHwcLayer->iSize_ = -1;
drmHwcLayer->iFormat_ = -1;
drmHwcLayer->iUsage = 0;
drmHwcLayer->iHeightStride_ = -1;
drmHwcLayer->uFourccFormat_ = 0x20202020; //0x20 is space
drmHwcLayer->uModifier_ = 0;
drmHwcLayer->uGemHandle_ = 0;
drmHwcLayer->sLayerName_.clear();
drmHwcLayer->uByteStridePlanes_.clear();
drmHwcLayer->pBufferInfo_ = nullptr;
}
drmHwcLayer->Init();
return;
}
bool DrmHwcTwo::HwcLayer::CanSkipSolidColorLayer(int have_skip_layer_zpos) {
if (mCurrentState.is_solid_color_) {
if (HwcAProperty::getInstance().getIntWithInterval("vendor.hwc.disable_background_opt", 1000, 0)) {
return false;
}
if (mCurrentState.z_order_ == have_skip_layer_zpos && mCurrentState.color_.r == 0 &&
mCurrentState.color_.g == 0 && mCurrentState.color_.b == 0) {
HWC2_LOGD_IF("Skip Solid Color Layer, z_order=%d, color=(%d,%d,%d)", mCurrentState.z_order_,
mCurrentState.color_.r, mCurrentState.color_.g, mCurrentState.color_.b);
set_validated_type(sf_type());
return true;
}
}
return false;
}
void DrmHwcTwo::HwcLayer::PopulateSolidColorLayer(DrmHwcLayer* drmHwcLayer, hwc2_drm_display_t* ctx) {
drmHwcLayer->SetDisplayFrame(mCurrentState.display_frame_, ctx);
drmHwcLayer->SetTransform(mCurrentState.transform_);
// Commit mirror function
drmHwcLayer->SetDisplayFrameMirror(mCurrentState.display_frame_);
android::DrmBuffer* solid_buffer = mCurrentState.solid_color_buffer_->getDrmBuffer();
if (solid_buffer != NULL) {
drmHwcLayer->sf_handle = solid_buffer->GetHandle();
drmHwcLayer->uBufferId_ = solid_buffer->GetBufferId();
drmHwcLayer->iFd_ = solid_buffer->GetFd();
drmHwcLayer->iWidth_ = solid_buffer->GetWidth();
drmHwcLayer->iHeight_ = solid_buffer->GetHeight();
drmHwcLayer->iStride_ = solid_buffer->GetStride();
drmHwcLayer->iSize_ = solid_buffer->GetSize();
drmHwcLayer->iFormat_ = solid_buffer->GetFormat();
drmHwcLayer->iUsage = solid_buffer->GetUsage();
drmHwcLayer->iHeightStride_ = solid_buffer->GetHeightStride();
drmHwcLayer->iByteStride_ = solid_buffer->GetByteStride();
drmHwcLayer->uFourccFormat_ = solid_buffer->GetFourccFormat();
drmHwcLayer->uModifier_ = solid_buffer->GetModifier();
drmHwcLayer->sLayerName_ = solid_buffer->GetName();
drmHwcLayer->uByteStridePlanes_ = solid_buffer->GetByteStridePlanes();
drmHwcLayer->uGemHandle_ = solid_buffer->GetGemHandle();
drmHwcLayer->bHasPqMetadata_ = false;
drmHwcLayer->bHasHdrMetadata_ = false;
drmHwcLayer->pBufferInfo_ = NULL;
mCurrentState.source_crop_.left = 0;
mCurrentState.source_crop_.top = 0;
//如果目标区域比buffer小使用目标区域大小避免缩放
mCurrentState.source_crop_.right =
std::min(solid_buffer->GetWidth(), drmHwcLayer->display_frame.right - drmHwcLayer->display_frame.left);
mCurrentState.source_crop_.bottom =
std::min(solid_buffer->GetHeight(), drmHwcLayer->display_frame.bottom - drmHwcLayer->display_frame.top);
drmHwcLayer->SetSourceCrop(mCurrentState.source_crop_);
} else {
drmHwcLayer->iFd_ = -1;
drmHwcLayer->iWidth_ = -1;
drmHwcLayer->iHeight_ = -1;
drmHwcLayer->iStride_ = -1;
drmHwcLayer->iSize_ = -1;
drmHwcLayer->iFormat_ = -1;
drmHwcLayer->iUsage = 0;
drmHwcLayer->iHeightStride_ = -1;
drmHwcLayer->uFourccFormat_ = 0x20202020; //0x20 is space
drmHwcLayer->uModifier_ = 0;
drmHwcLayer->uGemHandle_ = 0;
drmHwcLayer->sLayerName_.clear();
drmHwcLayer->uByteStridePlanes_.clear();
drmHwcLayer->pBufferInfo_ = nullptr;
}
drmHwcLayer->Init();
return;
}
void DrmHwcTwo::HwcLayer::PopulateDrmLayer(hwc2_layer_t layer_id, DrmHwcLayer* drmHwcLayer, hwc2_drm_display_t* ctx,
uint32_t frame_no) {
drmHwcLayer->uId_ = layer_id;
drmHwcLayer->iZpos_ = mCurrentState.z_order_;
drmHwcLayer->uFrameNo_ = frame_no;
drmHwcLayer->bFbTarget_ = false;
drmHwcLayer->bSkipLayer_ = false;
drmHwcLayer->bUse_ = true;
drmHwcLayer->eDataSpace_ = mCurrentState.dataspace_;
drmHwcLayer->alpha = static_cast<uint16_t>(255.0f * mCurrentState.alpha_ + 0.5f);
drmHwcLayer->sf_composition = sf_type();
drmHwcLayer->iBestPlaneType = 0;
drmHwcLayer->bSidebandStreamLayer_ = false;
drmHwcLayer->bMatch_ = false;
drmHwcLayer->IsMetadataHdr_ = false;
drmHwcLayer->bSideband2_ = false;
drmHwcLayer->fFps_ = GetActiveFps();
drmHwcLayer->bUpdate_ = isUpdate();
drmHwcLayer->bBackgroundSkip_ = false;
drmHwcLayer->bBackgraoundLayer_ = false;
drmHwcLayer->pSolidColorBuffer_ = NULL;
drmHwcLayer->uArgbValue_ = 0;
if (mCurrentState.is_solid_color_) {
drmHwcLayer->bBackgraoundLayer_ = mCurrentState.is_solid_color_;
drmHwcLayer->pSolidColorBuffer_ = mCurrentState.solid_color_buffer_;
// (1 << 31) 为 drm 驱动要求传递的使能标志
drmHwcLayer->uArgbValue_ =
(1 << 31) | (mCurrentState.color_.r << 16) | mCurrentState.color_.g << 8 | mCurrentState.color_.b;
}
#ifdef RK3528
// RK3528 仅 VOP支持AFBC格式如果遇到以下两个问题需要启用解码预缩小功能
// 1. AFBC格式无法Overlay需要启用预缩小关闭AFBC并缩小;
// 2. 视频缩放倍率超过VOP硬件限制需要启用预缩小减少后端缩小倍数
drmHwcLayer->bNeedPreScale_ = false;
drmHwcLayer->bIsPreScale_ = false;
#endif
drmHwcLayer->acquire_fence = acquire_fence_;
drmHwcLayer->iFbWidth_ = ctx->framebuffer_width;
drmHwcLayer->iFbHeight_ = ctx->framebuffer_height;
drmHwcLayer->uAclk_ = ctx->aclk;
drmHwcLayer->uDclk_ = ctx->dclk;
drmHwcLayer->SetBlend(mCurrentState.blending_);
// SidebandStream layer
if (sidebandStreamHandle_ != NULL) {
PopulateSidebandLayer(drmHwcLayer, ctx);
} else if (mCurrentState.is_solid_color_) {
PopulateSolidColorLayer(drmHwcLayer, ctx);
} else {
PopulateNormalLayer(drmHwcLayer, ctx);
}
return;
}
void DrmHwcTwo::HwcLayer::PopulateFB(hwc2_layer_t layer_id, DrmHwcLayer* drmHwcLayer, hwc2_drm_display_t* ctx,
uint32_t frame_no, bool validate) {
drmHwcLayer->uId_ = layer_id;
drmHwcLayer->uFrameNo_ = frame_no;
drmHwcLayer->bFbTarget_ = true;
drmHwcLayer->bUse_ = true;
drmHwcLayer->bSkipLayer_ = false;
drmHwcLayer->blending = DrmHwcBlending::kPreMult;
drmHwcLayer->iZpos_ = mCurrentState.z_order_;
drmHwcLayer->alpha = static_cast<uint16_t>(255.0f * mCurrentState.alpha_ + 0.5f);
drmHwcLayer->iBestPlaneType = 0;
drmHwcLayer->bSidebandStreamLayer_ = false;
drmHwcLayer->IsMetadataHdr_ = false;
drmHwcLayer->bSideband2_ = false;
drmHwcLayer->fFps_ = GetActiveFps();
drmHwcLayer->bUpdate_ = isUpdate();
drmHwcLayer->bBackgroundSkip_ = false;
drmHwcLayer->bBackgraoundLayer_ = false;
drmHwcLayer->pSolidColorBuffer_ = NULL;
drmHwcLayer->uArgbValue_ = 0;
if (!validate) {
drmHwcLayer->sf_handle = buffer_;
drmHwcLayer->acquire_fence = acquire_fence_;
} else {
// Commit mirror function
drmHwcLayer->SetDisplayFrameMirror(mCurrentState.display_frame_);
drmHwcLayer->bMatch_ = false;
}
drmHwcLayer->iFbWidth_ = ctx->framebuffer_width;
drmHwcLayer->iFbHeight_ = ctx->framebuffer_height;
drmHwcLayer->uAclk_ = ctx->aclk;
drmHwcLayer->uDclk_ = ctx->dclk;
drmHwcLayer->SetDisplayFrame(mCurrentState.display_frame_, ctx);
drmHwcLayer->SetSourceCrop(mCurrentState.source_crop_);
drmHwcLayer->SetTransform(mCurrentState.transform_);
if (buffer_ && !validate && pBufferInfo_ != NULL) {
// 利用 dup dma-buffer-fd 来增加对 dma-buffer 的引用计数
// 避免 dma-buffer 被提前释放
drmHwcLayer->uBufferId_ = pBufferInfo_->uBufferId_;
drmHwcLayer->iFd_ = pBufferInfo_->uniqueFd_.get();
drmHwcLayer->iWidth_ = pBufferInfo_->iWidth_;
drmHwcLayer->iHeight_ = pBufferInfo_->iHeight_;
drmHwcLayer->iStride_ = pBufferInfo_->iStride_;
drmHwcLayer->iSize_ = pBufferInfo_->iSize_;
drmHwcLayer->iFormat_ = pBufferInfo_->iFormat_;
drmHwcLayer->iUsage = pBufferInfo_->iUsage_;
drmHwcLayer->iHeightStride_ = pBufferInfo_->iHeightStride_;
drmHwcLayer->iByteStride_ = pBufferInfo_->iByteStride_;
drmHwcLayer->uFourccFormat_ = pBufferInfo_->uFourccFormat_;
drmHwcLayer->uModifier_ = pBufferInfo_->uModifier_;
drmHwcLayer->sLayerName_ = pBufferInfo_->sLayerName_;
drmHwcLayer->pBufferInfo_ = pBufferInfo_;
} else {
drmHwcLayer->iFd_ = -1;
drmHwcLayer->iWidth_ = (mCurrentState.source_crop_.right - mCurrentState.source_crop_.left);
drmHwcLayer->iHeight_ = (mCurrentState.source_crop_.bottom - mCurrentState.source_crop_.top);
drmHwcLayer->iStride_ = (mCurrentState.source_crop_.right - mCurrentState.source_crop_.left);
// 由于 validate 没有实际的handle, 故此处的size通过crop信息预估,格式为 RGBA
drmHwcLayer->iSize_ = (mCurrentState.source_crop_.right - mCurrentState.source_crop_.left) *
(mCurrentState.source_crop_.bottom - mCurrentState.source_crop_.top) * 4;
drmHwcLayer->iFormat_ = -1;
drmHwcLayer->iUsage = 0;
drmHwcLayer->iHeightStride_ = -1;
drmHwcLayer->uFourccFormat_ = DRM_FORMAT_ABGR8888; // fb target default DRM_FORMAT_ABGR8888
drmHwcLayer->uModifier_ = 0;
drmHwcLayer->uGemHandle_ = 0;
drmHwcLayer->sLayerName_ = std::string("FramebufferSurface");
drmHwcLayer->pBufferInfo_ = NULL;
}
drmHwcLayer->Init();
return;
}
#ifdef USE_LIBPQ
int DrmHwcTwo::HwcLayer::DoSwPq(bool validate, DrmHwcLayer* drmHwcLayer, hwc2_drm_display_t* ctx) {
bool pq_mode_enable =
HwcAProperty::getInstance().getIntWithInterval("persist.vendor.tvinput.rkpq.mode", 500, 0) > 0;
if (pq_mode_enable == 1) {
std::lock_guard<std::recursive_mutex> pq_lock(ResourceManager::getInstance()->GetSwpqMutex());
if (ResourceManager::getInstance()->NeedReinitSwpqForMode(ResourceManager::SWPQ_MODE_PQ)) {
if (swpq_ == NULL) {
swpq_ = Pq::Get();
}
if (swpq_) {
HWC2_LOGI("SWPQ: Swap form LD mode to PQ mode! Deinit swpq!");
swpq_->DeInit();
swpq_ = NULL;
bPqReady_ = false;
}
}
if (validate) {
ctx->use_pq_fb = false;
if (bufferQueue_ == NULL) {
bufferQueue_ = std::make_shared<DrmBufferQueue>();
}
if (swpq_ == NULL) {
swpq_ = Pq::Get();
if (swpq_ != NULL) {
bPqReady_ = true;
HWC2_LOGI("Pq module ready. to enable PqMode.");
}
} else {
bPqReady_ = true;
HWC2_LOGI("Pq module ready. to enable PqMode.");
}
if (bPqReady_) {
// 1. Init Ctx
int ret = swpq_->InitCtx(pqCtx_);
if (ret) {
HWC2_LOGE("Pq ctx init fail");
return ret;
}
// 2. Set buffer Info
PqImageInfo src;
src.mBufferInfo_.iFd_ = 1;
src.mBufferInfo_.iWidth_ = drmHwcLayer->iFbWidth_;
src.mBufferInfo_.iHeight_ = drmHwcLayer->iFbHeight_;
src.mBufferInfo_.iFormat_ = HAL_PIXEL_FORMAT_RGBA_8888;
// src.mBufferInfo_.iSize_ = drmHwcLayer->iFbWidth_ * drmHwcLayer->iFbHeight_ * 4;
src.mBufferInfo_.iStride_ = drmHwcLayer->iFbWidth_;
src.mBufferInfo_.uBufferId_ = 0x1;
src.mCrop_.iLeft_ = (int)drmHwcLayer->source_crop.left;
src.mCrop_.iTop_ = (int)drmHwcLayer->source_crop.top;
src.mCrop_.iRight_ = (int)drmHwcLayer->source_crop.right;
src.mCrop_.iBottom_ = (int)drmHwcLayer->source_crop.bottom;
ret = swpq_->SetSrcImage(pqCtx_, src);
if (ret) {
printf("pq SetSrcImage fail\n");
return ret;
}
ctx->use_pq_fb = true;
}
} else if (ctx->use_pq_fb) {
ctx->use_pq_fb = false;
if (bufferQueue_ == NULL) {
bufferQueue_ = std::make_shared<DrmBufferQueue>();
}
if (swpq_ == NULL) {
swpq_ = Pq::Get();
if (swpq_ != NULL) {
bPqReady_ = true;
HWC2_LOGI("pq module ready. to enable pqMode.");
}
}
if (bPqReady_) {
// 1. Init Ctx
int ret = swpq_->InitCtx(pqCtx_);
if (ret) {
HWC2_LOGE("Pq ctx init fail");
return ret;
}
// 2. Set buffer Info
PqImageInfo src;
src.mBufferInfo_.iFd_ = drmHwcLayer->iFd_;
src.mBufferInfo_.iWidth_ = drmHwcLayer->iWidth_;
src.mBufferInfo_.iHeight_ = drmHwcLayer->iHeight_;
src.mBufferInfo_.iFormat_ = drmHwcLayer->iFormat_;
src.mBufferInfo_.iStride_ = drmHwcLayer->iStride_;
// src.mBufferInfo_.iSize_ = drmHwcLayer->iSize_;
src.mBufferInfo_.uBufferId_ = drmHwcLayer->uBufferId_;
src.mBufferInfo_.uDataSpace_ = (uint64_t)drmHwcLayer->eDataSpace_;
src.mCrop_.iLeft_ = (int)drmHwcLayer->source_crop.left;
src.mCrop_.iTop_ = (int)drmHwcLayer->source_crop.top;
src.mCrop_.iRight_ = (int)drmHwcLayer->source_crop.right;
src.mCrop_.iBottom_ = (int)drmHwcLayer->source_crop.bottom;
#ifdef USE_LIBPQ_LD
//local dimming
DrmCrtc* crtc = drm_->GetCrtcForDisplay(ctx->display_id);
std::shared_ptr<std::vector<uint32_t>> pDimmingBufferSize = NULL;
std::shared_ptr<std::vector<uint8_t>> pDimmingBuffer = NULL;
//使用crtc是否存在dimming_data作为启用dimming的标记
bool use_local_dimming = crtc && crtc->dimming_data().id();
if (crtc) src.uCrtcId = crtc->id();
if (use_local_dimming) {
pDimmingBufferSize = std::make_shared<std::vector<uint32_t>>(1);
src.uSpiProtLength = pDimmingBufferSize->data();
} else {
src.uSpiProtLength = nullptr;
}
#endif
ret = swpq_->SetSrcImage(pqCtx_, src);
if (ret) {
printf("Pq SetSrcImage fail\n");
return ret;
}
// 4. Alloc Dst buffer
std::shared_ptr<DrmBuffer> dst_buffer;
dst_buffer = bufferQueue_->DequeueDrmBuffer(
ctx->framebuffer_width, ctx->framebuffer_height, HAL_PIXEL_FORMAT_YCBCR_444_888,
// PQ 算法要求 256 对齐Gralloc可用的只有256奇数倍对齐
// 暂时按照 256 奇数倍对齐,后续查看情况
// TODO: 最终PQ库内部修改为64对齐即可
RK_GRALLOC_USAGE_STRIDE_ALIGN_64 | MALI_GRALLOC_USAGE_NO_AFBC, "PQ-FB-target");
if (dst_buffer == NULL) {
HWC2_LOGD_IF("DequeueDrmBuffer fail!, skip this policy.");
return -1;
}
// 5. Set buffer Info
PqImageInfo dst;
dst.mBufferInfo_.iFd_ = dst_buffer->GetFd();
dst.mBufferInfo_.iWidth_ = dst_buffer->GetWidth();
dst.mBufferInfo_.iHeight_ = dst_buffer->GetHeight();
dst.mBufferInfo_.iFormat_ = dst_buffer->GetFormat();
dst.mBufferInfo_.iStride_ = dst_buffer->GetStride();
dst.mBufferInfo_.uBufferId_ = dst_buffer->GetBufferId();
dst.mCrop_.iLeft_ = (int)drmHwcLayer->source_crop.left;
dst.mCrop_.iTop_ = (int)drmHwcLayer->source_crop.top;
dst.mCrop_.iRight_ = (int)drmHwcLayer->source_crop.right;
dst.mCrop_.iBottom_ = (int)drmHwcLayer->source_crop.bottom;
dst.mCrop_.iLeft_ = 0;
dst.mCrop_.iTop_ = 0;
dst.mCrop_.iRight_ = ctx->framebuffer_width;
dst.mCrop_.iBottom_ = ctx->framebuffer_height;
#ifdef USE_LIBPQ_LD
//LocalDimming 申请和配置LocalDimming buffer
if (crtc) dst.uCrtcId = crtc->id();
if (use_local_dimming) {
uint32_t dimm_size = swpq_->getDimmingSize(crtc->id());
HWC2_LOGV_IF("local_dimm: DimmingBufferSize = %" PRIu32, dimm_size);
pDimmingBuffer = std::make_shared<std::vector<uint8_t>>(dimm_size);
dst.uSpiProtLength = pDimmingBufferSize->data();
dst.uSpiBuffAddr = pDimmingBuffer->data();
} else {
dst.uSpiProtLength = nullptr;
dst.uSpiBuffAddr = nullptr;
}
#endif
ret = swpq_->SetDstImage(pqCtx_, dst);
if (ret) {
printf("Pq SetSrcImage fail\n");
bufferQueue_->QueueBuffer(dst_buffer);
return ret;
}
hwc_frect_t source_crop;
source_crop.left = 0;
source_crop.top = 0;
source_crop.right = ctx->framebuffer_width;
source_crop.bottom = ctx->framebuffer_height;
drmHwcLayer->UpdateAndStoreInfoFromDrmBuffer(
dst_buffer->GetHandle(), dst_buffer->GetFd(), dst_buffer->GetFormat(), dst_buffer->GetWidth(),
dst_buffer->GetHeight(), dst_buffer->GetStride(), dst_buffer->GetHeightStride(),
dst_buffer->GetByteStride(), dst_buffer->GetSize(), dst_buffer->GetUsage(),
dst_buffer->GetFourccFormat(), dst_buffer->GetModifier(), dst_buffer->GetByteStridePlanes(),
dst_buffer->GetName(), source_crop, dst_buffer->GetBufferId(), dst_buffer->GetGemHandle(),
drmHwcLayer->transform);
if (drmHwcLayer->acquire_fence->isValid()) {
ret = drmHwcLayer->acquire_fence->wait(1500);
if (ret) {
HWC2_LOGE("wait Fb-Target 1500ms timeout, ret=%d", ret);
drmHwcLayer->bUsePq_ = false;
bufferQueue_->QueueBuffer(dst_buffer);
return ret;
}
}
int output_fence = -1;
ret = swpq_->RunAsync(pqCtx_, &output_fence);
if (ret) {
HWC2_LOGD_IF("RunAsync fail!");
drmHwcLayer->bUsePq_ = false;
bufferQueue_->QueueBuffer(dst_buffer);
return ret;
}
#ifdef USE_LIBPQ_LD
if (use_local_dimming) {
drmHwcLayer->pDimmingBuffer_ = pDimmingBuffer;
drmHwcLayer->pDimmingBufferSize_ = pDimmingBufferSize;
}
#endif
dst_buffer->SetFinishFence(dup(output_fence));
drmHwcLayer->acquire_fence = sp<AcquireFence>(new AcquireFence(output_fence));
if (HwcAProperty::getInstance().getBoolWithInterval("vendor.dump", 500, false)) {
drmHwcLayer->acquire_fence->wait();
dst_buffer->DumpData(drmHwcLayer->uFrameNo_, drmHwcLayer->iZpos_, "M");
}
bufferQueue_->QueueBuffer(dst_buffer);
}
}
drmHwcLayer->uFourccFormat_ = DRM_FORMAT_NV24;
} else {
#ifndef USE_LIBPQ_LD
//local dimming下swpq与HDMI-in通路是复用的不进行deinit避免冲突
if (bPqReady_) {
swpq_->DeInit();
bPqReady_ = false;
}
#endif
}
drmHwcLayer->Init();
if (gIsDrmVerison6_1()) {
drmHwcLayer->uColorSpace.colorspace_kernel_6_1_.color_encoding_ = DRM_COLOR_YCBCR_BT601;
drmHwcLayer->uColorSpace.colorspace_kernel_6_1_.color_range_ = DRM_COLOR_YCBCR_FULL_RANGE;
} else {
drmHwcLayer->uColorSpace.colorspace_kernel_510_ = V4L2_COLORSPACE_JPEG;
}
return 0;
}
#endif
void DrmHwcTwo::HwcLayer::DumpLayerInfo(String8& output) {
output.appendFormat(
" %04" PRIu32 " | %03" PRIu32 " | %9s | %9s | %-18.18" PRIxPTR
" | %-11.11s | %-10.10s |%7.1f,%7.1f,%7.1f,%7.1f |%5d,%5d,%5d,%5d | %10x | %5.1f | %s | 0x%" PRIx64 "\n",
id_, mCurrentState.z_order_, to_string(mCurrentState.sf_type_).c_str(),
to_string(mCurrentState.validated_type_).c_str(), intptr_t(buffer_),
to_string(mCurrentState.transform_).c_str(), to_string(mCurrentState.blending_).c_str(),
mCurrentState.source_crop_.left, mCurrentState.source_crop_.top, mCurrentState.source_crop_.right,
mCurrentState.source_crop_.bottom, mCurrentState.display_frame_.left, mCurrentState.display_frame_.top,
mCurrentState.display_frame_.right, mCurrentState.display_frame_.bottom, mCurrentState.dataspace_, GetFps(),
layer_name_.c_str(), pBufferInfo_ != NULL ? pBufferInfo_->uBufferId_ : -1);
return;
}
int DrmHwcTwo::HwcLayer::DumpData(int frame_no, const char* tag) {
ATRACE_CALL();
if (!buffer_) ALOGI_IF(LogLevel(DBG_INFO), "%s,line=%d LayerId=%u Buffer is null.", __FUNCTION__, __LINE__, id_);
void* cpu_addr = NULL;
static int frame_cnt = 0;
int width, height, stride, byte_stride, height_stride, size;
uint32_t fourcc_format;
uint64_t modifier;
uint64_t buffer_id = 0;
int ret = 0;
width = drmGralloc_->hwc_get_handle_attibute(buffer_, ATT_WIDTH);
height = drmGralloc_->hwc_get_handle_attibute(buffer_, ATT_HEIGHT);
stride = drmGralloc_->hwc_get_handle_attibute(buffer_, ATT_STRIDE);
size = drmGralloc_->hwc_get_handle_attibute(buffer_, ATT_SIZE);
byte_stride = drmGralloc_->hwc_get_handle_attibute(buffer_, ATT_BYTE_STRIDE);
height_stride = drmGralloc_->hwc_get_handle_attibute(buffer_, ATT_HEIGHT_STRIDE);
fourcc_format = drmGralloc_->hwc_get_handle_fourcc_format(buffer_);
modifier = drmGralloc_->hwc_get_handle_format_modifier(buffer_);
ret = drmGralloc_->hwc_get_handle_buffer_id(buffer_, &buffer_id);
cpu_addr = drmGralloc_->hwc_get_handle_lock(buffer_, width, height);
if (cpu_addr == NULL) {
ALOGE("%s, line = %d, LayerId = %u, lock fail", __FUNCTION__, __LINE__, id_);
return -1;
}
std::string dump_file_name = HwcDumper::GetInstance()->GetDumpName(
tag, frame_no, mCurrentState.z_order_, mCurrentState.validated_type_, stride,
height_stride > 0 ? height_stride : height, byte_stride, fourcc_format, modifier, layer_name_, buffer_id);
HwcDumper::GetInstance()->DumpData(cpu_addr, size, dump_file_name.c_str());
ret = drmGralloc_->hwc_get_handle_unlock(buffer_);
if (ret) {
ALOGE("%s,line=%d, LayerId=%u, unlock fail ret = %d ", __FUNCTION__, __LINE__, id_, ret);
return ret;
}
return ret;
}
bool DrmHwcTwo::IsHasRegisterDisplayId(hwc2_display_t displayid) {
return mHasRegisterDisplay_.count(displayid) > 0;
}
void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) {
auto cb = callbacks_.find(HWC2::Callback::Hotplug);
if (cb == callbacks_.end()) return;
if (isRK3566(resource_manager_->getSocId())) {
if (displayid != HWC_DISPLAY_PRIMARY) {
auto& drmDevices = resource_manager_->GetDrmDevices();
for (auto& device : drmDevices) {
if (state == DRM_MODE_CONNECTED)
device->SetCommitMirrorDisplayId(displayid);
else
device->SetCommitMirrorDisplayId(-1);
}
ALOGD_IF(LogLevel(DBG_DEBUG), "HandleDisplayHotplug skip display-id=%" PRIu64 " state=%d", displayid,
state);
return;
}
}
if (displayid == HWC_DISPLAY_PRIMARY && state == HWC2_CONNECTION_DISCONNECTED) return;
auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(cb->second.func);
hotplug(cb->second.data, displayid,
(state == DRM_MODE_CONNECTED ? HWC2_CONNECTION_CONNECTED : HWC2_CONNECTION_DISCONNECTED));
// 通过 mHasRegisterDisplay_ 记录已经向 SurfaceFlinger 注册的 display-id
if (state == DRM_MODE_CONNECTED)
mHasRegisterDisplay_.insert(displayid);
else {
mHasRegisterDisplay_.erase(displayid);
}
// 休眠100ms,等待上层处理
usleep(100 * 1000);
}
void DrmHwcTwo::HandleInitialHotplugState(DrmDevice* drmDevice) {
// RK3528 HDMI/TV互斥模式要求若HDMI已连接则 TV 不注册
if (gIsRK3528() && !ResourceManager::getInstance()->IsSingleDisplayMode()) {
drmDevice->FlipHotplugEventForInit();
return;
}
for (auto& conn : drmDevice->connectors()) {
if (conn->state() != DRM_MODE_CONNECTED) continue;
for (auto& crtc : drmDevice->crtc()) {
if (conn->display() != crtc->display()) continue;
// HWC_DISPLAY_PRIMARY display have been hotplug
if (conn->display() == HWC_DISPLAY_PRIMARY) {
// SplitDisplay Hotplug
if (conn->isHorizontalSplit()) {
HandleDisplayHotplug((conn->GetSplitModeId()), conn->state());
ALOGI("HWC2 Init: SF register connector %u type=%s, type_id=%d SplitDisplay=%d\n", conn->id(),
drmDevice->connector_type_str(conn->type()), conn->type_id(), conn->GetSplitModeId());
}
continue;
}
// SplitDisplay Hotplug
if (conn->isCropSplit()) {
if (conn->IsSplitPrimary()) {
HandleDisplayHotplug(conn->display(), conn->state());
ALOGI("HWC2 Init: SF register connector %u type=%s, type_id=%d display-id=%d\n", conn->id(),
drmDevice->connector_type_str(conn->type()), conn->type_id(), conn->display());
continue;
} else {
// CropSplit
HWC2_LOGI("HWC2 Init: not to register connector %u type=%s, type_id=%d isCropSplit=%d\n",
conn->id(), drmDevice->connector_type_str(conn->type()), conn->type_id(),
conn->isCropSplit());
continue;
}
}
if (ResourceManager::getInstance()->IsSingleDisplayMode() && conn->display() > 0) {
HWC2_LOGI("HWC2 Init: SingleDisplayMode not to register connector %u type=%s, type_id=%d \n",
conn->id(), drmDevice->connector_type_str(conn->type()), conn->type_id());
continue;
}
ALOGI("HWC2 Init: SF register connector %u type=%s, type_id=%d \n", conn->id(),
drmDevice->connector_type_str(conn->type()), conn->type_id());
HandleDisplayHotplug(conn->display(), conn->state());
// SplitDisplay Hotplug
if (conn->isHorizontalSplit()) {
HandleDisplayHotplug((conn->GetSplitModeId()), conn->state());
ALOGI("HWC2 Init: SF register connector %u type=%s, type_id=%d SplitDisplay=%d\n", conn->id(),
drmDevice->connector_type_str(conn->type()), conn->type_id(), conn->GetSplitModeId());
}
}
}
}
void DrmHwcTwo::EventWorker::HdmiTvOnlyOne(PLUG_EVENT_TYPE hdmi_hotplug_state) {
if (!gIsRK3528() || ResourceManager::getInstance()->IsSingleDisplayMode()) return;
ResourceManager* rm = ResourceManager::getInstance();
int primary_id = 0;
DrmDevice* drm_ = rm->GetDrmDevice(primary_id);
if (drm_ == NULL) {
HWC2_LOGE("Failed to get DrmDevice for display 0");
return;
}
// RK3528 HDMI拔出则需要注册 TV 到 SurfaceFlinger
if (hdmi_hotplug_state == DRM_HOTPLUG_UNPLUG_EVENT) {
for (auto& conn : drm_->connectors()) {
if (conn->type() == DRM_MODE_CONNECTOR_TV) {
drmModeConnection cur_state = conn->state();
if (cur_state == DRM_MODE_CONNECTED) {
int display_id = conn->display();
auto& display = hwc2_->displays_.at(display_id);
int ret = (int32_t)display.HoplugEventTmeline();
ret |= (int32_t)display.CheckStateAndReinit(!hwc2_->IsHasRegisterDisplayId(display_id));
ret |= (int32_t)display.ChosePreferredConfig();
if (ret != 0) {
HWC2_LOGE("hwc_hotplug: %s connector %u type=%s type_id=%d state is error, skip hotplug.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
} else {
HWC2_LOGI("hwc_hotplug: %s connector %u type=%s type_id=%d send hotplug event to SF.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
hwc2_->HandleDisplayHotplug(display_id, cur_state);
display.SyncPowerMode();
}
}
}
}
// RK3528 HDMI接入则需要销毁 TV 到 SurfaceFlinger
} else {
// 检查HDMI连接状态
bool hdmi_conneted = false;
for (auto& conn : drm_->connectors()) {
if (conn->type() == DRM_MODE_CONNECTOR_HDMIA) {
hdmi_conneted = (conn->state() == DRM_MODE_CONNECTED);
}
}
// 若HDMI已连接则需要销毁 TV display
if (hdmi_conneted) {
for (auto& conn : drm_->connectors()) {
if (conn->type() == DRM_MODE_CONNECTOR_TV) {
int display_id = conn->display();
auto& display = hwc2_->displays_.at(display_id);
display.SetPowerMode(HWC2_POWER_MODE_OFF);
HWC2_LOGI("hwc_hotplug: Unplug connector %u type=%s type_id=%d send unhotplug event to SF.",
conn->id(), drm_->connector_type_str(conn->type()), conn->type_id());
hwc2_->HandleDisplayHotplug(display_id, DRM_MODE_DISCONNECTED);
}
}
}
}
return;
}
void DrmHwcTwo::DrmHotplugHandler::HandleEvent(uint64_t timestamp_us) {
std::unique_lock<std::recursive_mutex> lock(mRecursiveMutex);
int changed_conn_cnt = 0;
for (auto& conn : drm_->connectors()) {
drmModeConnection old_state = conn->hotplug_state();
//update hotplug state by fast mode
conn->UpdateHotplugState(true);
drmModeConnection cur_state = conn->hotplug_state();
if (cur_state != old_state) {
DrmEvent event;
event.display_id = conn->display();
event.connection = cur_state;
event.type = HOTPLUG_DRM_EVENT;
event.timestamp = timestamp_us;
hwc2_->eventWorker_.SendDrmEvent(event);
changed_conn_cnt++;
HWC2_LOGI("hwc_hotplug : %s-%d state is changed! %s -> %s, timestamp_us=%" PRIu64,
drm_->connector_type_str(conn->type()), conn->type_id(),
old_state == DRM_MODE_CONNECTED ? "Connected" : "Disconnected",
cur_state == DRM_MODE_CONNECTED ? "Connected" : "Disconnected", timestamp_us);
} else {
HWC2_LOGI_IF("hwc_hotplug : %s-%d state is no changed! %s -> %s, timestamp_us=%" PRIu64,
drm_->connector_type_str(conn->type()), conn->type_id(),
old_state == DRM_MODE_CONNECTED ? "Connected" : "Disconnected",
cur_state == DRM_MODE_CONNECTED ? "Connected" : "Disconnected", timestamp_us);
}
}
if (changed_conn_cnt == 0) {
HWC2_LOGI("hwc_hotplug : receive drm hotplug event but no state change. check by slow mode.");
for (auto& conn : drm_->connectors()) {
drmModeConnection old_state = conn->hotplug_state();
//update hotplug state by slow mode
conn->UpdateHotplugState(false);
drmModeConnection cur_state = conn->hotplug_state();
if (cur_state != old_state) {
DrmEvent event;
event.display_id = conn->display();
event.connection = cur_state;
event.type = HOTPLUG_DRM_EVENT;
event.timestamp = timestamp_us;
hwc2_->eventWorker_.SendDrmEvent(event);
changed_conn_cnt++;
HWC2_LOGI("hwc_hotplug : connector %s-%d state is changed! %s -> %s, timestamp_us=%" PRIu64,
drm_->connector_type_str(conn->type()), conn->type_id(),
old_state == DRM_MODE_CONNECTED ? "Connected" : "Disconnected",
cur_state == DRM_MODE_CONNECTED ? "Connected" : "Disconnected", timestamp_us);
} else {
HWC2_LOGI_IF("hwc_hotplug : connector %s-%d state is no changed! %s -> %s, timestamp_us=%" PRIu64,
drm_->connector_type_str(conn->type()), conn->type_id(),
old_state == DRM_MODE_CONNECTED ? "Connected" : "Disconnected",
cur_state == DRM_MODE_CONNECTED ? "Connected" : "Disconnected", timestamp_us);
}
}
}
if (changed_conn_cnt == 0) {
if (gIsRK3528() && timestamp_us == 0) {
HWC2_LOGW("hwc_hotplug : RK3528 process first hotplug, timestamp_us=%" PRIu64, timestamp_us);
for (auto& conn : drm_->connectors()) {
DrmEvent event;
event.display_id = conn->display();
event.connection = conn->hotplug_state();
event.type = HOTPLUG_DRM_EVENT;
event.timestamp = timestamp_us;
hwc2_->eventWorker_.SendDrmEvent(event);
HWC2_LOGI("hwc_hotplug : rk3528 send first hotplug, connector %s-%d , timestamp_us=%" PRIu64,
drm_->connector_type_str(conn->type()), conn->type_id(), timestamp_us);
}
} else {
HWC2_LOGW(
"hwc_hotplug : receive drm hotplug event but no state change. display's connection maybe have "
"error, timestamp_us=%" PRIu64,
timestamp_us);
}
}
}
// 处理单屏热插拔事件,处理主要分为这几步:
// 1. 如果主屏没有变化,则不做任何处理
// 2. 如果主屏有变化:
// a. 针对新的PrimaryDisplay需要重新初始化并且需要更新SF的Display信息
// b. 针对旧的PrimaryDisplay需要PowerOff对应屏幕以及释放资源
int DrmHwcTwo::EventWorker::HandleSingleDisplayEvent(DrmEvent event) {
uint64_t timestamp_us = event.timestamp;
ResourceManager* rm = ResourceManager::getInstance();
DrmDevice* drm_ = rm->GetDrmDevice(event.display_id);
if (drm_ == NULL) {
HWC2_LOGE("Failed to get DrmDevice for display %d", event.display_id);
return -1;
}
int32_t ret = 0;
DrmConnector* conn = drm_->GetConnectorForDisplay(event.display_id);
if (!conn) {
HWC2_LOGE("Failed to get DrmConnector for display %d", event.display_id);
return -1;
}
//更新设备的分辨率列表
conn->ResetModesReady();
conn->UpdateModes();
if (!conn->ModesReady()) {
HWC2_LOGE("hwc_hotplug : display-id=%d %s-%d DrmMode is not ready.", event.display_id,
drm_->connector_type_str(conn->type()), conn->type_id());
return -1;
}
drmModeConnection cur_state = conn->state();
if (event.connection != cur_state) {
HWC2_LOGE("hwc_hotplug : display-id=%d %s-%d cur_state=%s event.connection=%s skip hotplug.", event.display_id,
drm_->connector_type_str(conn->type()), conn->type_id(),
cur_state == DRM_MODE_CONNECTED ? "Connected" : "Disconnected",
event.connection == DRM_MODE_CONNECTED ? "Connected" : "Disconnected");
return -1;
}
HWC2_LOGI("hwc_hotplug: %s event %" PRIu64 " for connector %u type=%s, type_id=%d\n",
event.connection == DRM_MODE_CONNECTED ? "Plug" : "Unplug", event.timestamp, conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
// 1. 更新主屏信息,可能存在主副屏幕切换行为
bool primaryChange = false;
// true: Check only
// false: Check and Update
// 检查主屏信息是否发生变化
drm_->UpdatePrimaryInfo(true /*checkonly*/);
DrmConnector* old_primary = NULL;
DrmConnector* new_primary = NULL;
for (auto& conn : drm_->connectors()) {
if (conn->display() == 0 && conn->display_next() != 0) {
// 获取旧主屏信息
old_primary = conn.get();
} else if (conn->display() != 0 && conn->display_next() == 0) {
// 获取新主屏信息
new_primary = conn.get();
}
}
// 主屏发生变化,则需要更新主屏信息
if (old_primary != NULL && new_primary != NULL) {
primaryChange = true;
HWC2_LOGI("hwc_hotplug: primaryChange, old_primary=%d %s-%d, new_primary=%d %s-%d", old_primary->display(),
drm_->connector_type_str(old_primary->type()), old_primary->type_id(), new_primary->display(),
drm_->connector_type_str(new_primary->type()), new_primary->type_id());
// 将所有屏幕设置为断开模式并清黑屏幕
for (auto& map : hwc2_->displays_) {
map.second.DisconnectDisplay();
}
// 释放旧主屏的资源
drm_->ReleaseDpyRes(0);
// 更新主屏信息,主屏已切换
drm_->UpdatePrimaryInfo(false);
// 初始化新主屏
auto& display = hwc2_->displays_.at(0);
ret = 0;
ret |= (int32_t)display.HoplugEventTmeline();
ret |= (int32_t)display.CheckStateAndReinit(!hwc2_->IsHasRegisterDisplayId(0));
ret |= (int32_t)display.ChosePreferredConfig();
if (ret != 0) {
HWC2_LOGE("hwc_hotplug: %s connector %u type=%s type_id=%d state is error, skip hotplug.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
} else {
HWC2_LOGI("hwc_hotplug: %s connector %u type=%s type_id=%d to switch primary config.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
if (event.state_change_panding) {
display.SetNeedPowerModeSync(event.state_change_panding);
}
display.SyncPowerMode();
hwc2_->HandleDisplayHotplug(0, DRM_MODE_CONNECTED);
}
// 将所有屏幕设置为连接状态
for (auto& map : hwc2_->displays_) {
map.second.ConnectDisplay();
}
} else {
HWC2_LOGI(
"hwc_hotplug : primaryChange is not change. display-id=%d %s-%d cur_state=%s event.connection=%s skip "
"hotplug.",
event.display_id, drm_->connector_type_str(conn->type()), conn->type_id(),
cur_state == DRM_MODE_CONNECTED ? "Connected" : "Disconnected",
event.connection == DRM_MODE_CONNECTED ? "Connected" : "Disconnected");
}
auto& primary = hwc2_->displays_.at(0);
primary.InvalidateControl(5, 20);
return 0;
}
int DrmHwcTwo::EventWorker::HandleDrmHotplugEvent(DrmEvent event) {
uint64_t timestamp_us = event.timestamp;
ResourceManager* rm = ResourceManager::getInstance();
DrmDevice* drm_ = rm->GetDrmDevice(event.display_id);
if (drm_ == NULL) {
HWC2_LOGE("Failed to get DrmDevice for display %d", event.display_id);
return -1;
}
int32_t ret = 0;
PLUG_EVENT_TYPE event_type = DRM_HOTPLUG_NONE;
DrmConnector* conn = drm_->GetConnectorForDisplay(event.display_id);
if (!conn) {
HWC2_LOGE("Failed to get DrmConnector for display %d", event.display_id);
return -1;
}
// RK3528 TV 不需要处理TV的热插拔事件
if (gIsRK3528() && conn->type() == DRM_MODE_CONNECTOR_TV) {
ALOGI("hwc_hotplug: RK3528 not handle type=%s-%d hotplug event.\n", drm_->connector_type_str(conn->type()),
conn->type_id());
return -1;
}
//更新设备的分辨率列表
conn->ResetModesReady();
conn->UpdateModes();
if (!conn->ModesReady()) {
HWC2_LOGE("hwc_hotplug : display-id=%d %s-%d DrmMode is not ready.", event.display_id,
drm_->connector_type_str(conn->type()), conn->type_id());
return -1;
}
drmModeConnection cur_state = conn->state();
if (event.connection != cur_state) {
HWC2_LOGE("hwc_hotplug : display-id=%d %s-%d cur_state=%s event.connection=%s skip hotplug.", event.display_id,
drm_->connector_type_str(conn->type()), conn->type_id(),
cur_state == DRM_MODE_CONNECTED ? "Connected" : "Disconnected",
event.connection == DRM_MODE_CONNECTED ? "Connected" : "Disconnected");
return -1;
}
ALOGI("hwc_hotplug: %s event %" PRIu64 " for connector %u type=%s, type_id=%d\n",
event.connection == DRM_MODE_CONNECTED ? "Plug" : "Unplug", event.timestamp, conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
// 当前状态为未连接,则为拔出事件
if (cur_state == DRM_MODE_DISCONNECTED) {
event_type = DRM_HOTPLUG_UNPLUG_EVENT;
} else {
event_type = DRM_HOTPLUG_PLUG_EVENT;
}
// RK3528 HDMI/TV 互斥功能需要提前处理 TV display
if (gIsRK3528() && conn->type() == DRM_MODE_CONNECTOR_HDMIA) HdmiTvOnlyOne(event_type);
int display_id = conn->display();
auto& display = hwc2_->displays_.at(display_id);
if (cur_state == DRM_MODE_CONNECTED) {
ret |= (int32_t)display.HoplugEventTmeline();
ret |= (int32_t)display.CheckStateAndReinit(!hwc2_->IsHasRegisterDisplayId(display_id));
ret |= (int32_t)display.ChosePreferredConfig();
if (ret != 0) {
HWC2_LOGE("hwc_hotplug: %s connector %u type=%s type_id=%d state is error, skip hotplug.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
} else if (conn->isCropSplit()) {
HWC2_LOGI("hwc_hotplug: %s connector %u type=%s type_id=%d isCropSplit skip hotplug.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
display.SetPowerMode(HWC2_POWER_MODE_ON);
// 非主屏的拼接屏幕需要创建 DummyLayer
if (!conn->IsSplitPrimary()) {
display.GetOrCreateDummyLayer();
}
} else {
HWC2_LOGI("hwc_hotplug: %s connector %u type=%s type_id=%d send hotplug event to SF.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
if (event.state_change_panding) {
display.SetNeedPowerModeSync(event.state_change_panding);
}
hwc2_->HandleDisplayHotplug(display_id, cur_state);
//如果前后状态一致但是中间出现一次快速热插拔驱动的powermode可能和HWC不同步强制sync
display.SyncPowerMode();
}
} else {
// 当前拔出的设备是Mirror的主屏
if (conn->is_connector_mirror_mode()) {
// 如果是MirrorPrimary,说明还存在MirrorExternal屏幕故仅执行断开drm资源操作不上报拔出事件
if (conn->is_connector_mirror_primary()) {
ret = (int32_t)drm_->ReleaseDpyRes(display_id);
if (ret) {
HWC2_LOGE("hwc_hotplug: MirrorDisplayPrimary %s connector %u type=%s type_id=%d state is error.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
return ret;
}
HWC2_LOGI("hwc_hotplug: MirrorDisplayPrimary %s connector %u type=%s type_id=%d, skip hotplug.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
return ret;
} else { // 非MirrorPrimary设备故仅执行断开drm资源操作
int mirror_primary_id = conn->get_connector_mirror_primary_id();
ret = (int32_t)drm_->ReleaseDpyRes(display_id);
if (ret) {
HWC2_LOGE("hwc_hotplug: MirrorDisplayExternal %s connector %u type=%s type_id=%d state is error.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
return ret;
}
HWC2_LOGI("hwc_hotplug: MirrorDisplayExternal %s connector %u type=%s type_id=%d, skip hotplug.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
// 检查MirrorPrimary的连接状态如果此MirrorPrimary设备已断开且没有其他MirrorExternal则需要上报拔出事件销毁对应的SF Display
if (mirror_primary_id > 0) {
auto& mirror_primary_display = hwc2_->displays_.at(mirror_primary_id);
DrmConnector* mirror_primary = drm_->GetConnectorForDisplay(mirror_primary_id);
// MirrorPrimary 变为非MirrorMode状态说明所有MirrorExternal都已经断开
// 如果此时 MirrorPrimary 也是断开就需要上报拔出事件销毁对应的SF Display
if (mirror_primary != NULL && mirror_primary->hotplug_state() == DRM_MODE_DISCONNECTED &&
mirror_primary->is_connector_mirror_mode() == false) {
ret |= (int32_t)mirror_primary_display.ClearDisplay();
ret |= (int32_t)drm_->ReleaseDpyRes(mirror_primary_id);
if (ret != 0) {
HWC2_LOGE(
"hwc_hotplug: MirrorDisplay Unplug primary-display-id=%d connector %u type=%s "
"type_id=%d state is error, skip hotplug.",
mirror_primary_id, mirror_primary->id(),
drm_->connector_type_str(mirror_primary->type()), mirror_primary->type_id());
} else if (conn->isCropSplit()) {
HWC2_LOGI(
"hwc_hotplug: MirrorDisplay Unplug primary-display-id=%d connector %u type=%s "
"type_id=%d isCropSplit skip hotplug.",
mirror_primary_id, mirror_primary->id(),
drm_->connector_type_str(mirror_primary->type()), mirror_primary->type_id());
// display.SetPowerMode(HWC2_POWER_MODE_OFF);
} else {
HWC2_LOGI(
"hwc_hotplug: MirrorDisplay Unplug primary-display-id=%d connector %u type=%s "
"type_id=%d send hotplug event to SF.",
mirror_primary_id, mirror_primary->id(),
drm_->connector_type_str(mirror_primary->type()), mirror_primary->type_id());
hwc2_->HandleDisplayHotplug(mirror_primary_id, DRM_MODE_DISCONNECTED);
}
}
}
return ret;
}
} else {
ret |= (int32_t)display.ClearDisplay();
ret |= (int32_t)drm_->ReleaseDpyRes(display_id);
if (ret != 0) {
HWC2_LOGE("hwc_hotplug: %s connector %u type=%s type_id=%d state is error, skip hotplug.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
} else if (conn->isCropSplit()) {
HWC2_LOGI("hwc_hotplug: %s connector %u type=%s type_id=%d isCropSplit skip hotplug.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
// display.SetPowerMode(HWC2_POWER_MODE_OFF);
// 非主屏的拼接屏幕需销毁DummyLayer
if (!conn->IsSplitPrimary()) {
display.DestoryDummyLayer();
}
} else {
HWC2_LOGI("hwc_hotplug: %s connector %u type=%s type_id=%d send hotplug event to SF.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
hwc2_->HandleDisplayHotplug(display_id, cur_state);
}
}
}
// SplitDisplay Hoplug.
ret = 0;
if (conn->isHorizontalSplit()) {
display_id = conn->GetSplitModeId();
auto& split_display = hwc2_->displays_.at(display_id);
if (cur_state == DRM_MODE_CONNECTED) {
ret |= (int32_t)split_display.HoplugEventTmeline();
ret |= (int32_t)split_display.CheckStateAndReinit(!hwc2_->IsHasRegisterDisplayId(display_id));
ret |= (int32_t)split_display.ChosePreferredConfig();
if (ret != 0) {
HWC2_LOGE("hwc_hotplug: %s connector %u type=%s type_id=%d state is error, skip hotplug.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
} else {
HWC2_LOGI("hwc_hotplug: %s connector %u type=%s type_id=%d send hotplug event to SF.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
hwc2_->HandleDisplayHotplug(display_id, cur_state);
split_display.SyncPowerMode();
}
} else {
ret |= (int32_t)split_display.ClearDisplay();
ret |= (int32_t)drm_->ReleaseDpyRes(display_id);
if (ret != 0) {
HWC2_LOGE("hwc_hotplug: %s connector %u type=%s type_id=%d state is error, skip hotplug.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
} else {
HWC2_LOGI("hwc_hotplug: %s connector %u type=%s type_id=%d send hotplug event to SF.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
hwc2_->HandleDisplayHotplug(display_id, cur_state);
}
}
}
// 拔出事件说明存在crtc资源释放
if (event_type == DRM_HOTPLUG_UNPLUG_EVENT) {
for (auto& conn : drm_->connectors()) {
// 多屏拼接不需要重新注册屏幕
if (conn->isCropSplit()) {
return ret;
}
ret = 0;
drmModeConnection cur_state = conn->state();
if (cur_state == DRM_MODE_CONNECTED) {
if (conn->hwc_state_change_and_plug()) {
int display_id = conn->display();
auto& display = hwc2_->displays_.at(display_id);
ret |= (int32_t)display.HoplugEventTmeline();
ret |= (int32_t)display.CheckStateAndReinit(!hwc2_->IsHasRegisterDisplayId(display_id));
ret |= (int32_t)display.ChosePreferredConfig();
if (ret != 0) {
HWC2_LOGE("hwc_hotplug: %s connector %u type=%s type_id=%d state is error, skip hotplug.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
} else {
HWC2_LOGI("hwc_hotplug: %s connector %u type=%s type_id=%d send hotplug event to SF.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
drm_->connector_type_str(conn->type()), conn->type_id());
hwc2_->HandleDisplayHotplug(display_id, cur_state);
display.SyncPowerMode();
}
}
}
}
}
auto& primary = hwc2_->displays_.at(0);
primary.InvalidateControl(5, 20);
return 0;
}
void DrmHwcTwo::DrmHotplugHandler::HandleResolutionSwitchEvent(int display_id) {
// 若系统没有设置为动态更新模式的话,则不进行分辨率更新
ResourceManager* rm = ResourceManager::getInstance();
if (!rm->IsDynamicDisplayMode()) {
return;
}
DrmConnector* connector = drm_->GetConnectorForDisplay(display_id);
if (!connector) {
ALOGE("Failed to get connector for display %d", display_id);
return;
}
auto& display = hwc2_->displays_.at(display_id);
HWC2::Error error = display.ChosePreferredConfig();
if (error != HWC2::Error::None) {
HWC2_LOGE("hwc_resolution_switch: connector %u type=%s, type_id=%d ChosePreferredConfig fail.\n",
connector->id(), drm_->connector_type_str(connector->type()), connector->type_id());
return;
}
if (display.IsActiveModeChange()) {
HWC2_LOGI("hwc_resolution_switch: connector %u type=%s, type_id=%d\n", connector->id(),
drm_->connector_type_str(connector->type()), connector->type_id());
if (!connector->isCropSplit() || (connector->isCropSplit() && connector->IsSplitPrimary()))
hwc2_->HandleDisplayHotplug(display_id, DRM_MODE_CONNECTED);
auto& primary = hwc2_->displays_.at(0);
primary.InvalidateControl(5, 20);
display.ActiveModeChange(false);
}
return;
}
DrmHwcTwo::EventWorker::EventWorker() : Worker("hwc2-event", HAL_PRIORITY_URGENT_DISPLAY), hwc2_(NULL) {}
DrmHwcTwo::EventWorker::~EventWorker() {}
int DrmHwcTwo::EventWorker::Init(DrmHwcTwo* hwc2) {
hwc2_ = hwc2;
return InitWorker();
}
void DrmHwcTwo::EventWorker::Start() {
Lock();
bCanHotplugCallBack_ = true;
Unlock();
Signal();
}
//this function cannot be locked or it may dead lock.
void DrmHwcTwo::EventWorker::SetEventBlockState(bool isBlock, std::string reason) {
bBlockHotplugCallBack_ = isBlock;
HWC2_LOGD_IF("%s EventWorker for %s", isBlock ? "Block" : "Resume", reason.c_str());
}
int DrmHwcTwo::EventWorker::SendDrmEvent(DrmEvent event) {
Lock();
HWC2_LOGI_IF("hwc_hotplug : add event display-id=%d type=%d connection=%s timestamp=%" PRIu64, event.display_id,
event.type, event.connection == DRM_MODE_CONNECTED ? "connected" : "disconnected", event.timestamp);
if (mMapPendingEvent_.count(event.display_id) > 0) {
// 外层 map 中存在 id
if (mMapPendingEvent_[event.display_id].count(event.type) > 0) {
if (mMapPendingEvent_[event.display_id][event.type].connection != event.connection) {
HWC2_LOGI(
"hwc_hotplug : Duplicate hotplug events display-id=%d type=%d connection %s -> %s, "
"pending_handle set true.",
event.display_id, event.type,
mMapPendingEvent_[event.display_id][event.type].connection == DRM_MODE_CONNECTED
? "connected"
: "disconnected",
event.connection == DRM_MODE_CONNECTED ? "connected" : "disconnected");
event.state_change_panding = true;
} else {
HWC2_LOGI(
"hwc_hotplug : Duplicate hotplug events display-id=%d type=%d %s event, use lastest event "
"%" PRIu64 " -> %" PRIu64 ".",
event.display_id, event.type,
event.connection == DRM_MODE_CONNECTED ? "connected" : "disconnected",
mMapPendingEvent_[event.display_id][event.type].timestamp, event.timestamp);
}
}
}
mMapPendingEvent_[event.display_id][event.type] = event;
Unlock();
Signal();
return 0;
}
int DrmHwcTwo::EventWorker::HandleDisplayModeUpdateEvent(DrmEvent event) {
// 若系统没有设置为动态更新模式的话,则不进行分辨率更新
ResourceManager* rm = ResourceManager::getInstance();
if (!rm->IsDynamicDisplayMode()) {
return 0;
}
int primary_id = 0;
DrmDevice* drm = rm->GetDrmDevice(primary_id);
if (drm == NULL) {
HWC2_LOGE("Failed to get DrmDevice for display %d", event.display_id);
return -1;
}
DrmConnector* connector = drm->GetConnectorForDisplay(event.display_id);
if (!connector) {
HWC2_LOGE("Failed to get connector for display %d", event.display_id);
return -1;
}
if (connector->state() != DRM_MODE_CONNECTED) {
HWC2_LOGW("hwc_fb_switch: connector %u type=%s, type_id=%d is DRM_MODE_DISCONNECTED skip!\n", connector->id(),
drm->connector_type_str(connector->type()), connector->type_id());
return -1;
}
if (hwc2_->displays_.count(event.display_id)) {
auto& display = hwc2_->displays_.at(event.display_id);
HWC2::Error error = display.ChosePreferredConfig();
if (error != HWC2::Error::None) {
HWC2_LOGE("hwc_fb_switch: connector %u type=%s, type_id=%d ChosePreferredConfig fail.\n", connector->id(),
drm->connector_type_str(connector->type()), connector->type_id());
return -1;
}
HWC2_LOGI("hwc_fb_switch: display_id=%d connector %u type=%s, type_id=%d\n", event.display_id, connector->id(),
drm->connector_type_str(connector->type()), connector->type_id());
if (!connector->isCropSplit() || (connector->isCropSplit() && connector->IsSplitPrimary()))
hwc2_->HandleDisplayHotplug(event.display_id, DRM_MODE_CONNECTED);
}
if (hwc2_->displays_.count(primary_id)) {
auto& primary = hwc2_->displays_.at(primary_id);
primary.InvalidateControl(5, 20);
}
return 0;
}
int DrmHwcTwo::EventWorker::HandleUserHotplugEvent(DrmEvent event) {
// 若系统没有设置为动态更新模式的话,则不进行分辨率更新
ResourceManager* rm = ResourceManager::getInstance();
int primary_id = 0;
DrmDevice* drm = rm->GetDrmDevice(primary_id);
if (drm == NULL) {
HWC2_LOGE("Failed to get DrmDevice for display %d", event.display_id);
return -1;
}
DrmConnector* connector = drm->GetConnectorForDisplay(event.display_id);
if (!connector) {
HWC2_LOGE("Failed to get connector for display %d", event.display_id);
return -1;
}
if (hwc2_->displays_.count(event.display_id)) {
auto& display = hwc2_->displays_.at(event.display_id);
if (event.connection == DRM_MODE_CONNECTED) {
int ret = (int32_t)display.HoplugEventTmeline();
ret |= (int32_t)display.UpdateDisplayMode();
ret |= (int32_t)display.CheckStateAndReinit(!hwc2_->IsHasRegisterDisplayId(event.display_id));
ret |= (int32_t)display.ChosePreferredConfig();
if (ret != 0) {
HWC2_LOGE("hwc_hotplug: %s for connector %u type=%s, type_id=%d CheckStateAndReinit fail.\n",
event.connection == DRM_MODE_CONNECTED ? "Plug" : "Unplug", connector->id(),
drm->connector_type_str(connector->type()), connector->type_id());
return -1;
}
}
HWC2_LOGI("hwc_hotplug: %s for display_id=%d connector %u type=%s, type_id=%d \n",
event.connection == DRM_MODE_CONNECTED ? "Plug" : "Unplug", event.display_id, connector->id(),
drm->connector_type_str(connector->type()), connector->type_id());
hwc2_->HandleDisplayHotplug(event.display_id, event.connection);
}
if (hwc2_->displays_.count(primary_id)) {
auto& primary = hwc2_->displays_.at(primary_id);
primary.InvalidateControl(5, 20);
}
return 0;
}
int DrmHwcTwo::EventWorker::HaneleDisplayPipelineUpdateEvent() {
ResourceManager* rm = ResourceManager::getInstance();
int primary_id = 0;
DrmDevice* drm = rm->GetDrmDevice(primary_id);
if (drm == NULL) {
HWC2_LOGE("DisplayPipeChange : Failed to get DrmDevice");
}
// 检查display pipeline更新情况
uint64_t change_mask = 0;
if (drm->GetDisplayPipelineChange(&change_mask) == 0) {
if (change_mask > 0) {
// 将所有屏幕设置为断开模式并清黑屏幕
for (auto& map : hwc2_->displays_) {
map.second.DisconnectDisplay();
}
if ((change_mask & DRM_PIPELINE_PRIMARY_CHANGE) == DRM_PIPELINE_PRIMARY_CHANGE) {
if (HandlePrimaryChange()) {
HWC2_LOGE("DisplayPipeChange : HandlePrimaryChange fail.");
return -1;
}
}
if ((change_mask & DRM_PIPELINE_SPLIT_MODE_CHANGE) == DRM_PIPELINE_SPLIT_MODE_CHANGE) {
if (HandleSplitModeChange()) {
HWC2_LOGE("DisplayPipeChange : SplitMode : HandleSplitModeChange fail.");
return -1;
}
}
// 将所有屏幕设置为连接状态
for (auto& map : hwc2_->displays_) {
map.second.ConnectDisplay();
}
}
}
HWC2_LOGI("DisplayPipeChange : handle Success!");
return 0;
}
int DrmHwcTwo::EventWorker::HandlePrimaryChange() {
ResourceManager* rm = ResourceManager::getInstance();
int primary_id = 0;
DrmDevice* drm = rm->GetDrmDevice(primary_id);
if (drm == NULL) {
HWC2_LOGE("DisplayPipeChange: Failed to get DrmDevice");
}
// 将所有屏幕设置为断开模式并清黑屏幕
for (auto& map : hwc2_->displays_) {
map.second.ResetDisplay();
}
// 删除所有状态是已连接的屏幕
for (auto& connector : drm->connectors()) {
if (connector->hotplug_state() == DRM_MODE_DISCONNECTED) {
continue;
}
int display_id = connector->display();
// 释放当前display的 drm resource 资源
int ret = drm->ReleaseDpyRes(display_id);
if (ret) {
HWC2_LOGE("DisplayPipeChange : Failed to ReleaseDpyRes for display=%d %d\n", display_id, ret);
continue;
}
HWC2_LOGI("DisplayPipeChange : hwc_hotplug: Unplug for display_id=%d connector %u type=%s, type_id=%d \n",
display_id, connector->id(), drm->connector_type_str(connector->type()), connector->type_id());
// 上报拔出事件通知SurfaceFlinger删除屏幕
hwc2_->HandleDisplayHotplug(display_id, DRM_MODE_DISCONNECTED);
}
// 更新主屏信息,可能存在主副屏幕切换行为
// true: Check only
// false: Check and Update
drm->UpdatePrimaryInfo(false);
// 根据新绑定的display-id信息进行重新初始化
for (auto& map : hwc2_->displays_) {
map.second.CheckStateAndReinit();
}
// 根据设备的连接状态重新上报插入事件
for (auto& connector : drm->connectors()) {
if (connector->hotplug_state() == DRM_MODE_CONNECTED) {
int display_id = connector->display();
HWC2_LOGI("DisplayPipeChange : hwc_hotplug: Plug for display_id=%d connector %u type=%s, type_id=%d \n",
display_id, connector->id(), drm->connector_type_str(connector->type()), connector->type_id());
hwc2_->HandleDisplayHotplug(display_id, DRM_MODE_CONNECTED);
}
}
if (hwc2_->displays_.count(primary_id)) {
auto& primary = hwc2_->displays_.at(primary_id);
primary.InvalidateControl(5, 20);
}
usleep(200 * 1000);
return 0;
}
int DrmHwcTwo::EventWorker::HandleSplitModeChange() {
int32_t ret = 0;
ResourceManager* rm = ResourceManager::getInstance();
if (!rm) {
HWC2_LOGE("DisplayPipeChange : SplitMode: Can not get ResourceManager");
return -1;
}
DrmDevice* drm = rm->GetDrmDevice(0);
if (!drm) {
HWC2_LOGE("DisplayPipeChange : SplitMode: can not get drm device");
return -1;
}
// 更新SplitMode配置信息
drm->UpdateSplitModeInfo();
// 遍历所有 connector 检查存在xml前后更新的差异
for (auto& conn : drm->connectors()) {
ret = 0;
// 如果当前屏幕未连接,且不是拼接主屏幕(拼接主屏不连接也需要更新信息)
drmModeConnection cur_state = conn->hotplug_state();
if (cur_state != DRM_MODE_CONNECTED && !conn->IsSplitPrimary()) {
continue;
}
int display_id = conn->display();
auto& display = hwc2_->displays_.at(display_id);
// 所有屏幕都删除 SplitDummyLayer
display.DestoryDummyLayer();
// 如果是拼接模式的屏幕
if (conn->isCropSplit()) {
if (conn->IsSplitPrimary()) {
if (display.CheckStateAndReinit(!hwc2_->IsHasRegisterDisplayId(display_id)) == HWC2::Error::None) {
HWC2_LOGI("DisplayPipeChange : SplitMode : %s-%d IsSplitPrimary, send hotplug to SF.",
drm->connector_type_str(conn->type()), conn->type_id());
hwc2_->HandleDisplayHotplug(display_id, DRM_MODE_CONNECTED);
} else {
HWC2_LOGE(
"DisplayPipeChange : SplitMode : %s-%d IsSplitPrimary CheckStateAndReinit fail, skip "
"hotplug.",
drm->connector_type_str(conn->type()), conn->type_id());
}
} else {
if (hwc2_->IsHasRegisterDisplayId(display_id)) {
HWC2_LOGI("DisplayPipeChange : SplitMode: %s-%d isCropSplit, send unplug to SF.",
drm->connector_type_str(conn->type()), conn->type_id());
hwc2_->HandleDisplayHotplug(display_id, DRM_MODE_DISCONNECTED);
}
// 更新拼接屏幕的屏幕信息
display.ChosePreferredConfig();
// 只有拼接副屏创建 DummyLayer
display.GetOrCreateDummyLayer();
}
} else {
HWC2_LOGI("DisplayPipeChange : SplitMode: %s-%d Exit CropSplit, send plug event to SF.",
drm->connector_type_str(conn->type()), conn->type_id());
// 更新拼接屏幕的屏幕信息
display.ChosePreferredConfig();
if (display.CheckStateAndReinit(!hwc2_->IsHasRegisterDisplayId(display_id)) == HWC2::Error::None) {
HWC2_LOGI("DisplayPipeChange : SplitMode : %s-%d Exit CropSplit,, send hotplug to SF.",
drm->connector_type_str(conn->type()), conn->type_id());
hwc2_->HandleDisplayHotplug(display_id, cur_state);
} else {
HWC2_LOGE(
"DisplayPipeChange : SplitMode : %s-%d Exit CropSplit, CheckStateAndReinit fail, skip hotplug.",
drm->connector_type_str(conn->type()), conn->type_id());
}
display.SyncPowerMode();
}
if (conn->isHorizontalSplit()) {
HWC2_LOGI("DisplayPipeChange : SplitMode: %s-%d isHorizontalSplit, send unplug to SF.",
drm->connector_type_str(conn->type()), conn->type_id());
if (hwc2_->displays_.count(conn->GetSplitModeId()) == 0) {
hwc2_->CreateDisplay(conn->GetSplitModeId(), HWC2::DisplayType::Physical);
}
display.ChosePreferredConfig();
if (display.CheckStateAndReinit(!hwc2_->IsHasRegisterDisplayId(conn->GetSplitModeId())) ==
HWC2::Error::None) {
HWC2_LOGI("DisplayPipeChange : SplitMode : %s-%d isHorizontalSplit,, send hotplug to SF.",
drm->connector_type_str(conn->type()), conn->type_id());
hwc2_->HandleDisplayHotplug(conn->GetSplitModeId(), cur_state);
} else {
HWC2_LOGE(
"DisplayPipeChange : SplitMode : %s-%d isHorizontalSplit, CheckStateAndReinit fail, skip "
"hotplug.",
drm->connector_type_str(conn->type()), conn->type_id());
}
} else {
if (hwc2_->IsHasRegisterDisplayId(conn->GetSplitModeId())) {
hwc2_->HandleDisplayHotplug(conn->GetSplitModeId(), DRM_MODE_DISCONNECTED);
}
}
}
auto& display = hwc2_->displays_.at(0);
display.InvalidateControl(30, 120);
usleep(200 * 1000);
return 0;
}
void DrmHwcTwo::EventWorker::Routine() {
ATRACE_CALL();
Lock();
int ret = 0;
if (!bCanHotplugCallBack_ || bBlockHotplugCallBack_) {
ret = WaitForSignalOrExitLocked();
Unlock();
return;
}
if (mMapPendingEvent_.empty()) {
ret = WaitForSignalOrExitLocked();
if (ret == -EINTR) {
HWC2_LOGI("EventWorker: WaitForSignalOrExitLocked fail! ret=%d", ret);
Unlock();
return;
}
}
if (bBlockHotplugCallBack_) {
Unlock();
return;
}
//将 Pending 的事件打包成 queue 队列进行处理
std::queue<DrmEvent> local_pending_event;
for (const auto& outerPair : mMapPendingEvent_) {
const auto& innerMap = outerPair.second;
for (const auto& innerPair : innerMap) {
local_pending_event.push(innerPair.second);
}
}
mMapPendingEvent_.clear();
Unlock();
// 处理实际的热插拔事件请求
while (!local_pending_event.empty()) {
DrmEvent event = local_pending_event.front();
local_pending_event.pop();
// 单主屏模式忽略其他所有热插拔处理流程仅处理DRM热插拔事件
if (ResourceManager::getInstance()->IsSingleDisplayMode()) {
ret = HandleSingleDisplayEvent(event);
} else {
switch (event.type) {
case HOTPLUG_DRM_EVENT:
ret = HandleDrmHotplugEvent(event);
break;
case HOTPLUG_USER_EVENT:
ret = HandleUserHotplugEvent(event);
break;
case DISPLAY_MODE_UPDATE_EVENT:
ret = HandleDisplayModeUpdateEvent(event);
break;
case DISPLAY_PIPELINE_UPDATE_EVENT:
ret = HaneleDisplayPipelineUpdateEvent();
break;
default:
ret = -1;
HWC2_LOGE("unknow hotplug event, display-id=%d type=%d connection=%d", event.display_id, event.type,
event.connection);
break;
}
}
if (ret) {
HWC2_LOGE("send hotplug event fail ret=%d , display-id=%d type=%d connection=%d", ret, event.display_id,
event.type, event.connection);
}
}
return;
}
// static
int DrmHwcTwo::HookDevClose(hw_device_t* /*dev*/) {
unsupported(__func__);
return 0;
}
// static
void DrmHwcTwo::HookDevGetCapabilities(hwc2_device_t* /*dev*/, uint32_t* out_count, int32_t* out_capabilities) {
if (out_capabilities == NULL) {
*out_count = 1;
return;
}
out_capabilities[0] = static_cast<int32_t>(HWC2::Capability::SidebandStream);
}
// static
hwc2_function_pointer_t DrmHwcTwo::HookDevGetFunction(struct hwc2_device* /*dev*/, int32_t descriptor) {
supported(__func__);
if (descriptor < HWC2_RK_FUNCTION_SET_EXPECTED_PRESENT_TIME) {
auto func = static_cast<HWC2::FunctionDescriptor>(descriptor);
switch (func) {
// Device functions
case HWC2::FunctionDescriptor::CreateVirtualDisplay:
return ToHook<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(
DeviceHook<int32_t, decltype(&DrmHwcTwo::CreateVirtualDisplay),
&DrmHwcTwo::CreateVirtualDisplay, uint32_t, uint32_t, int32_t*, hwc2_display_t*>);
case HWC2::FunctionDescriptor::DestroyVirtualDisplay:
return ToHook<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(
DeviceHook<int32_t, decltype(&DrmHwcTwo::DestroyVirtualDisplay),
&DrmHwcTwo::DestroyVirtualDisplay, hwc2_display_t>);
case HWC2::FunctionDescriptor::Dump:
return ToHook<HWC2_PFN_DUMP>(
DeviceHook<void, decltype(&DrmHwcTwo::Dump), &DrmHwcTwo::Dump, uint32_t*, char*>);
case HWC2::FunctionDescriptor::GetMaxVirtualDisplayCount:
return ToHook<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>(
DeviceHook<uint32_t, decltype(&DrmHwcTwo::GetMaxVirtualDisplayCount),
&DrmHwcTwo::GetMaxVirtualDisplayCount>);
case HWC2::FunctionDescriptor::RegisterCallback:
return ToHook<HWC2_PFN_REGISTER_CALLBACK>(
DeviceHook<int32_t, decltype(&DrmHwcTwo::RegisterCallback), &DrmHwcTwo::RegisterCallback,
int32_t, hwc2_callback_data_t, hwc2_function_pointer_t>);
// Display functions
case HWC2::FunctionDescriptor::AcceptDisplayChanges:
return ToHook<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(
DisplayHook<decltype(&HwcDisplay::AcceptDisplayChanges), &HwcDisplay::AcceptDisplayChanges>);
case HWC2::FunctionDescriptor::CreateLayer:
return ToHook<HWC2_PFN_CREATE_LAYER>(
DisplayHook<decltype(&HwcDisplay::CreateLayer), &HwcDisplay::CreateLayer, hwc2_layer_t*>);
case HWC2::FunctionDescriptor::DestroyLayer:
return ToHook<HWC2_PFN_DESTROY_LAYER>(
DisplayHook<decltype(&HwcDisplay::DestroyLayer), &HwcDisplay::DestroyLayer, hwc2_layer_t>);
case HWC2::FunctionDescriptor::GetActiveConfig:
return ToHook<HWC2_PFN_GET_ACTIVE_CONFIG>(DisplayHook<decltype(&HwcDisplay::GetActiveConfig),
&HwcDisplay::GetActiveConfig, hwc2_config_t*>);
case HWC2::FunctionDescriptor::GetChangedCompositionTypes:
return ToHook<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(
DisplayHook<decltype(&HwcDisplay::GetChangedCompositionTypes),
&HwcDisplay::GetChangedCompositionTypes, uint32_t*, hwc2_layer_t*, int32_t*>);
case HWC2::FunctionDescriptor::GetClientTargetSupport:
return ToHook<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(
DisplayHook<decltype(&HwcDisplay::GetClientTargetSupport), &HwcDisplay::GetClientTargetSupport,
uint32_t, uint32_t, int32_t, int32_t>);
case HWC2::FunctionDescriptor::GetColorModes:
return ToHook<HWC2_PFN_GET_COLOR_MODES>(DisplayHook<decltype(&HwcDisplay::GetColorModes),
&HwcDisplay::GetColorModes, uint32_t*, int32_t*>);
case HWC2::FunctionDescriptor::GetDisplayAttribute:
return ToHook<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(
DisplayHook<decltype(&HwcDisplay::GetDisplayAttribute), &HwcDisplay::GetDisplayAttribute,
hwc2_config_t, int32_t, int32_t*>);
case HWC2::FunctionDescriptor::GetDisplayConfigs:
return ToHook<HWC2_PFN_GET_DISPLAY_CONFIGS>(
DisplayHook<decltype(&HwcDisplay::GetDisplayConfigs), &HwcDisplay::GetDisplayConfigs, uint32_t*,
hwc2_config_t*>);
case HWC2::FunctionDescriptor::GetDisplayName:
return ToHook<HWC2_PFN_GET_DISPLAY_NAME>(DisplayHook<decltype(&HwcDisplay::GetDisplayName),
&HwcDisplay::GetDisplayName, uint32_t*, char*>);
case HWC2::FunctionDescriptor::GetDisplayRequests:
return ToHook<HWC2_PFN_GET_DISPLAY_REQUESTS>(
DisplayHook<decltype(&HwcDisplay::GetDisplayRequests), &HwcDisplay::GetDisplayRequests,
int32_t*, uint32_t*, hwc2_layer_t*, int32_t*>);
case HWC2::FunctionDescriptor::GetDisplayType:
return ToHook<HWC2_PFN_GET_DISPLAY_TYPE>(
DisplayHook<decltype(&HwcDisplay::GetDisplayType), &HwcDisplay::GetDisplayType, int32_t*>);
case HWC2::FunctionDescriptor::GetDozeSupport:
return ToHook<HWC2_PFN_GET_DOZE_SUPPORT>(
DisplayHook<decltype(&HwcDisplay::GetDozeSupport), &HwcDisplay::GetDozeSupport, int32_t*>);
case HWC2::FunctionDescriptor::GetHdrCapabilities:
return ToHook<HWC2_PFN_GET_HDR_CAPABILITIES>(
DisplayHook<decltype(&HwcDisplay::GetHdrCapabilities), &HwcDisplay::GetHdrCapabilities,
uint32_t*, int32_t*, float*, float*, float*>);
case HWC2::FunctionDescriptor::GetReleaseFences:
return ToHook<HWC2_PFN_GET_RELEASE_FENCES>(
DisplayHook<decltype(&HwcDisplay::GetReleaseFences), &HwcDisplay::GetReleaseFences, uint32_t*,
hwc2_layer_t*, int32_t*>);
case HWC2::FunctionDescriptor::PresentDisplay:
return ToHook<HWC2_PFN_PRESENT_DISPLAY>(
DisplayHook<decltype(&HwcDisplay::PresentDisplay), &HwcDisplay::PresentDisplay, int32_t*>);
case HWC2::FunctionDescriptor::SetActiveConfig:
return ToHook<HWC2_PFN_SET_ACTIVE_CONFIG>(DisplayHook<decltype(&HwcDisplay::SetActiveConfig),
&HwcDisplay::SetActiveConfig, hwc2_config_t>);
case HWC2::FunctionDescriptor::SetClientTarget:
return ToHook<HWC2_PFN_SET_CLIENT_TARGET>(
DisplayHook<decltype(&HwcDisplay::SetClientTarget), &HwcDisplay::SetClientTarget,
buffer_handle_t, int32_t, int32_t, hwc_region_t>);
case HWC2::FunctionDescriptor::SetColorMode:
return ToHook<HWC2_PFN_SET_COLOR_MODE>(
DisplayHook<decltype(&HwcDisplay::SetColorMode), &HwcDisplay::SetColorMode, int32_t>);
case HWC2::FunctionDescriptor::SetColorTransform:
return ToHook<HWC2_PFN_SET_COLOR_TRANSFORM>(
DisplayHook<decltype(&HwcDisplay::SetColorTransform), &HwcDisplay::SetColorTransform,
const float*, int32_t>);
case HWC2::FunctionDescriptor::SetOutputBuffer:
return ToHook<HWC2_PFN_SET_OUTPUT_BUFFER>(
DisplayHook<decltype(&HwcDisplay::SetOutputBuffer), &HwcDisplay::SetOutputBuffer,
buffer_handle_t, int32_t>);
case HWC2::FunctionDescriptor::SetPowerMode:
return ToHook<HWC2_PFN_SET_POWER_MODE>(
DisplayHook<decltype(&HwcDisplay::SetPowerMode), &HwcDisplay::SetPowerMode, int32_t>);
case HWC2::FunctionDescriptor::SetVsyncEnabled:
return ToHook<HWC2_PFN_SET_VSYNC_ENABLED>(
DisplayHook<decltype(&HwcDisplay::SetVsyncEnabled), &HwcDisplay::SetVsyncEnabled, int32_t>);
case HWC2::FunctionDescriptor::ValidateDisplay:
return ToHook<HWC2_PFN_VALIDATE_DISPLAY>(
DisplayHook<decltype(&HwcDisplay::ValidateDisplay), &HwcDisplay::ValidateDisplay, uint32_t*,
uint32_t*>);
// Only Android 14 Support
#if PLATFORM_SDK_VERSION >= 34
// Composer 2.2 Display
case HWC2::FunctionDescriptor::GetRenderIntents:
return ToHook<HWC2_PFN_GET_RENDER_INTENTS>(
DisplayHook<decltype(&HwcDisplay::GetRenderIntents), &HwcDisplay::GetRenderIntents, int32_t,
uint32_t*, int32_t*>);
case HWC2::FunctionDescriptor::SetColorModeWithRenderIntent:
return ToHook<HWC2_PFN_SET_COLOR_MODE_WITH_RENDER_INTENT>(
DisplayHook<decltype(&HwcDisplay::SetColorModeWithIntent), &HwcDisplay::SetColorModeWithIntent,
int32_t, int32_t>);
case HWC2::FunctionDescriptor::GetPerFrameMetadataKeys:
return ToHook<HWC2_PFN_GET_PER_FRAME_METADATA_KEYS>(
DisplayHook<decltype(&HwcDisplay::GetPerFrameMetadataKeys),
&HwcDisplay::GetPerFrameMetadataKeys, uint32_t*, int32_t*>);
case HWC2::FunctionDescriptor::GetReadbackBufferFence:
return ToHook<HWC2_PFN_GET_READBACK_BUFFER_FENCE>(
DisplayHook<decltype(&HwcDisplay::GetReadbackBufferFence), &HwcDisplay::GetReadbackBufferFence,
int32_t*>);
case HWC2::FunctionDescriptor::SetReadbackBuffer:
return ToHook<HWC2_PFN_SET_READBACK_BUFFER>(
DisplayHook<decltype(&HwcDisplay::SetReadbackBuffer), &HwcDisplay::SetReadbackBuffer,
buffer_handle_t, int32_t>);
case HWC2::FunctionDescriptor::GetReadbackBufferAttributes:
return ToHook<HWC2_PFN_GET_READBACK_BUFFER_ATTRIBUTES>(
DisplayHook<decltype(&HwcDisplay::GetReadbackBufferAttributes),
&HwcDisplay::GetReadbackBufferAttributes, int32_t*, int32_t*>);
// Composer 2.2 Layer
case HWC2::FunctionDescriptor::SetLayerPerFrameMetadata:
return ToHook<HWC2_PFN_SET_LAYER_PER_FRAME_METADATA>(
LayerHook<decltype(&HwcLayer::SetLayerPerFrameMetadata), &HwcLayer::SetLayerPerFrameMetadata,
uint32_t, const int32_t*, const float*>);
case HWC2::FunctionDescriptor::SetLayerFloatColor:
return ToHook<HWC2_PFN_SET_LAYER_FLOAT_COLOR>(
LayerHook<decltype(&HwcLayer::SetLayerFloatColor), &HwcLayer::SetLayerFloatColor,
hwc_float_color_t>);
// Composer 2.3 Display
case HWC2::FunctionDescriptor::GetDisplayIdentificationData:
return ToHook<HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA>(
DisplayHook<decltype(&HwcDisplay::GetDisplayIdentificationData),
&HwcDisplay::GetDisplayIdentificationData, uint8_t*, uint32_t*, uint8_t*>);
case HWC2::FunctionDescriptor::GetDisplayCapabilities:
return ToHook<HWC2_PFN_GET_DISPLAY_CAPABILITIES>(
DisplayHook<decltype(&HwcDisplay::GetDisplayCapabilities), &HwcDisplay::GetDisplayCapabilities,
uint32_t*, uint32_t*>);
case HWC2::FunctionDescriptor::GetDisplayedContentSamplingAttributes:
return ToHook<HWC2_PFN_GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES>(
DisplayHook<decltype(&HwcDisplay::GetDisplayedContentSamplingAttributes),
&HwcDisplay::GetDisplayedContentSamplingAttributes, int32_t*, int32_t*, uint8_t*>);
case HWC2::FunctionDescriptor::SetDisplayedContentSamplingEnabled:
return ToHook<HWC2_PFN_SET_DISPLAYED_CONTENT_SAMPLING_ENABLED>(
DisplayHook<decltype(&HwcDisplay::SetDisplayedContentSamplingEnabled),
&HwcDisplay::SetDisplayedContentSamplingEnabled, int32_t, uint8_t, uint64_t>);
case HWC2::FunctionDescriptor::GetDisplayedContentSample:
return ToHook<HWC2_PFN_GET_DISPLAYED_CONTENT_SAMPLE>(
DisplayHook<decltype(&HwcDisplay::GetDisplayedContentSample),
&HwcDisplay::GetDisplayedContentSample, uint64_t, uint64_t, uint64_t*, int32_t*,
uint64_t**>);
case HWC2::FunctionDescriptor::GetDisplayBrightnessSupport:
return ToHook<HWC2_PFN_GET_DISPLAY_BRIGHTNESS_SUPPORT>(
DisplayHook<decltype(&HwcDisplay::GetDisplayBrightnessSupport),
&HwcDisplay::GetDisplayBrightnessSupport, bool*>);
case HWC2::FunctionDescriptor::SetDisplayBrightness:
return ToHook<HWC2_PFN_SET_DISPLAY_BRIGHTNESS>(DisplayHook<decltype(&HwcDisplay::SetDisplayBrightness),
&HwcDisplay::SetDisplayBrightness, float>);
// Composer 2.3 layer
case HWC2::FunctionDescriptor::SetLayerPerFrameMetadataBlobs:
return ToHook<HWC2_PFN_SET_LAYER_PER_FRAME_METADATA_BLOBS>(
LayerHook<decltype(&HwcLayer::SetLayerPerFrameMetadataBlobs),
&HwcLayer::SetLayerPerFrameMetadataBlobs, uint32_t, const int32_t*, const uint32_t*,
const uint8_t*>);
case HWC2::FunctionDescriptor::SetLayerColorTransform:
return ToHook<HWC2_PFN_SET_LAYER_COLOR_TRANSFORM>(
LayerHook<decltype(&HwcLayer::SetLayerColorTransform), &HwcLayer::SetLayerColorTransform,
const float*>);
// Composer 2.4 display
case HWC2::FunctionDescriptor::GetDisplayConnectionType:
return ToHook<HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE>(
DisplayHook<decltype(&HwcDisplay::GetDisplayConnectionType),
&HwcDisplay::GetDisplayConnectionType, uint32_t*>);
case HWC2::FunctionDescriptor::GetDisplayVsyncPeriod:
return ToHook<HWC2_PFN_GET_DISPLAY_VSYNC_PERIOD>(
DisplayHook<decltype(&HwcDisplay::GetDisplayVsyncPeriod), &HwcDisplay::GetDisplayVsyncPeriod,
hwc2_vsync_period_t*>);
case HWC2::FunctionDescriptor::SetActiveConfigWithConstraints:
return ToHook<HWC2_PFN_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS>(
DisplayHook<decltype(&HwcDisplay::SetActiveConfigWithConstraints),
&HwcDisplay::SetActiveConfigWithConstraints, hwc2_config_t,
hwc_vsync_period_change_constraints_t*, hwc_vsync_period_change_timeline_t*>);
case HWC2::FunctionDescriptor::SetAutoLowLatencyMode:
return ToHook<HWC2_PFN_SET_AUTO_LOW_LATENCY_MODE>(
DisplayHook<decltype(&HwcDisplay::SetAutoLowLatencyMode), &HwcDisplay::SetAutoLowLatencyMode,
bool>);
case HWC2::FunctionDescriptor::GetSupportedContentTypes:
return ToHook<HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES>(
DisplayHook<decltype(&HwcDisplay::GetSupportedContentTypes),
&HwcDisplay::GetSupportedContentTypes, uint32_t*, uint32_t*>);
case HWC2::FunctionDescriptor::SetContentType:
return ToHook<HWC2_PFN_SET_CONTENT_TYPE>(
DisplayHook<decltype(&HwcDisplay::SetContentType), &HwcDisplay::SetContentType, int32_t>);
case HWC2::FunctionDescriptor::GetClientTargetProperty:
return ToHook<HWC2_PFN_GET_CLIENT_TARGET_PROPERTY>(
DisplayHook<decltype(&HwcDisplay::GetClientTargetProperty),
&HwcDisplay::GetClientTargetProperty, hwc_client_target_property_t*>);
// Composer 2.4 layer
case HWC2::FunctionDescriptor::SetLayerGenericMetadata:
return ToHook<HWC2_PFN_SET_LAYER_GENERIC_METADATA>(
LayerHook<decltype(&HwcLayer::SetLayerGenericMetadata), &HwcLayer::SetLayerGenericMetadata,
uint32_t, const char*, bool, uint32_t, const uint8_t*>);
// Composer 2.4 Device
case HWC2::FunctionDescriptor::GetLayerGenericMetadataKey:
return ToHook<HWC2_PFN_GET_LAYER_GENERIC_METADATA_KEY>(
DeviceHook<void, decltype(&DrmHwcTwo::GetLayerGenericMetadataKey),
&DrmHwcTwo::GetLayerGenericMetadataKey, uint32_t, uint32_t*, char*, bool*>);
#endif
// Layer functions
case HWC2::FunctionDescriptor::SetCursorPosition:
return ToHook<HWC2_PFN_SET_CURSOR_POSITION>(LayerHook<decltype(&HwcLayer::SetCursorPosition),
&HwcLayer::SetCursorPosition, int32_t, int32_t>);
case HWC2::FunctionDescriptor::SetLayerBlendMode:
return ToHook<HWC2_PFN_SET_LAYER_BLEND_MODE>(
LayerHook<decltype(&HwcLayer::SetLayerBlendMode), &HwcLayer::SetLayerBlendMode, int32_t>);
case HWC2::FunctionDescriptor::SetLayerBuffer:
return ToHook<HWC2_PFN_SET_LAYER_BUFFER>(
LayerHook<decltype(&HwcLayer::SetLayerBuffer), &HwcLayer::SetLayerBuffer, buffer_handle_t,
int32_t>);
case HWC2::FunctionDescriptor::SetLayerColor:
return ToHook<HWC2_PFN_SET_LAYER_COLOR>(
LayerHook<decltype(&HwcLayer::SetLayerColor), &HwcLayer::SetLayerColor, hwc_color_t>);
case HWC2::FunctionDescriptor::SetLayerCompositionType:
return ToHook<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(
LayerHook<decltype(&HwcLayer::SetLayerCompositionType), &HwcLayer::SetLayerCompositionType,
int32_t>);
case HWC2::FunctionDescriptor::SetLayerDataspace:
return ToHook<HWC2_PFN_SET_LAYER_DATASPACE>(
LayerHook<decltype(&HwcLayer::SetLayerDataspace), &HwcLayer::SetLayerDataspace, int32_t>);
case HWC2::FunctionDescriptor::SetLayerDisplayFrame:
return ToHook<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(LayerHook<decltype(&HwcLayer::SetLayerDisplayFrame),
&HwcLayer::SetLayerDisplayFrame, hwc_rect_t>);
case HWC2::FunctionDescriptor::SetLayerPlaneAlpha:
return ToHook<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(
LayerHook<decltype(&HwcLayer::SetLayerPlaneAlpha), &HwcLayer::SetLayerPlaneAlpha, float>);
case HWC2::FunctionDescriptor::SetLayerSidebandStream:
return ToHook<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>(
LayerHook<decltype(&HwcLayer::SetLayerSidebandStream), &HwcLayer::SetLayerSidebandStream,
const native_handle_t*>);
case HWC2::FunctionDescriptor::SetLayerSourceCrop:
return ToHook<HWC2_PFN_SET_LAYER_SOURCE_CROP>(
LayerHook<decltype(&HwcLayer::SetLayerSourceCrop), &HwcLayer::SetLayerSourceCrop, hwc_frect_t>);
case HWC2::FunctionDescriptor::SetLayerSurfaceDamage:
return ToHook<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(
LayerHook<decltype(&HwcLayer::SetLayerSurfaceDamage), &HwcLayer::SetLayerSurfaceDamage,
hwc_region_t>);
case HWC2::FunctionDescriptor::SetLayerTransform:
return ToHook<HWC2_PFN_SET_LAYER_TRANSFORM>(
LayerHook<decltype(&HwcLayer::SetLayerTransform), &HwcLayer::SetLayerTransform, int32_t>);
case HWC2::FunctionDescriptor::SetLayerVisibleRegion:
return ToHook<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(
LayerHook<decltype(&HwcLayer::SetLayerVisibleRegion), &HwcLayer::SetLayerVisibleRegion,
hwc_region_t>);
case HWC2::FunctionDescriptor::SetLayerZOrder:
return ToHook<HWC2_PFN_SET_LAYER_Z_ORDER>(
LayerHook<decltype(&HwcLayer::SetLayerZOrder), &HwcLayer::SetLayerZOrder, uint32_t>);
case HWC2::FunctionDescriptor::Invalid:
default:
return NULL;
}
}
// Only Android 14 Support
#if PLATFORM_SDK_VERSION >= 34
else {
auto func = static_cast<RkExtensionFunctionDescriptor>(descriptor);
switch (func) {
case RkExtensionFunctionDescriptor::SetExpectedPresentTime:
return ToHook<HWC2_PFN_RK_SET_EXPECTED_PRESENT_TIME>(
DisplayHook<decltype(&HwcDisplay::SetExpectedPresentTime), &HwcDisplay::SetExpectedPresentTime,
int64_t>);
default:
return NULL;
}
}
#endif
return NULL;
}
// static
int DrmHwcTwo::HookDevOpen(const struct hw_module_t* module, const char* name, struct hw_device_t** dev) {
if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
ALOGE("Invalid module name- %s", name);
return -EINVAL;
}
InitDebugModule();
std::unique_ptr<DrmHwcTwo> ctx(new DrmHwcTwo());
if (!ctx) {
ALOGE("Failed to allocate DrmHwcTwo");
return -ENOMEM;
}
HWC2::Error err = ctx->Init();
if (err != HWC2::Error::None) {
ALOGE("Failed to initialize DrmHwcTwo err=%d\n", err);
return -EINVAL;
}
g_ctx = ctx.get();
signal(SIGALRM, StaticScreenOptHandler);
property_set("vendor.hwc.hdr_state", "NORMAL");
ctx->common.module = const_cast<hw_module_t*>(module);
*dev = &ctx->common;
ctx.release();
return 0;
}
} // namespace android
static struct hw_module_methods_t hwc2_module_methods = {
.open = android::DrmHwcTwo::HookDevOpen,
};
hw_module_t HAL_MODULE_INFO_SYM = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = HARDWARE_MODULE_API_VERSION(2, 0),
.id = HWC_HARDWARE_MODULE_ID,
.name = "DrmHwcTwo module",
.author = "The Android Open Source Project",
.methods = &hwc2_module_methods,
.dso = NULL,
.reserved = {0},
};