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.

6986 lines
262 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 "drmdisplaycomposition.h"
#include "drmlayer.h"
#include "platform.h"
#include "vsyncworker.h"
#include "rockchip/utils/drmdebug.h"
#include "rockchip/drmgralloc.h"
#include <im2d.hpp>
#include <drm_fourcc.h>
#include <rga.h>
#include <inttypes.h>
#include <string>
#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_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE();
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_ALOGE("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
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_ALOGD_IF_VERBOSE("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_ALOGI("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_ALOGD_IF_VERBOSE();
auto virtual_display = displays_.find(display);
if(virtual_display != displays_.end()){
displays_.erase(virtual_display);
resource_manager_->DisableWriteBackMode(resource_manager_->GetWBDisplay());
HWC2_ALOGI("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;
char acVersion[50] = {0};
strcpy(acVersion,GHWC_VERSION);
output.appendFormat("-- HWC2 Version %s by bin.li@rock-chips.com --\n",acVersion);
for(auto &map_disp: displays_){
output.append("\n");
if((map_disp.second.DumpDisplayInfo(output)) < 0)
continue;
}
mDumpString = output;
*size = static_cast<uint32_t>(mDumpString.size());
return;
}
uint32_t DrmHwcTwo::GetMaxVirtualDisplayCount() {
HWC2_ALOGI();
// DSI 固件不支持 HW VirtualDisplay.
if(hwc_get_int_property("ro.vendor.rk_sdk","0") == 0){
HWC2_ALOGI("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;
default: return false;
}
}
HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
hwc2_callback_data_t data,
hwc2_function_pointer_t function) {
HWC2_ALOGD_IF_VERBOSE();
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;
}
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_ALOGE("display=%" PRIu64 " init_success_=%d skip.", handle_, init_success_);
return -1;
}
if(connector_ != NULL){
compositor_->ClearDisplay();
}
HWC2_ALOGD_IF_INFO("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(50*1000);
if(compositor_ != NULL){
compositor_->ClearDisplay();
}
HWC2_ALOGD_IF_INFO("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(50*1000);
if(compositor_ != NULL){
compositor_->ClearDisplay();
}
HWC2_ALOGD_IF_INFO("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_ALOGD_IF_INFO("display-id=%" PRIu64,handle_);
return 0;
}
int DrmHwcTwo::HwcDisplay::ActiveModeChange(bool change) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
bActiveModeChange_ = change;
return 0;
}
bool DrmHwcTwo::HwcDisplay::IsActiveModeChange() {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
return bActiveModeChange_;
}
HWC2::Error DrmHwcTwo::HwcDisplay::Init() {
HWC2_ALOGD_IF_VERBOSE("HwcDisplay::Init display-id=%" PRIu64,handle_);
int display = static_cast<int>(handle_);
if(sync_timeline_.isValid()){
HWC2_ALOGD_IF_INFO("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() && 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_ALOGE("Failed to ReleaseDpyRes for display=%d %d\n", display, ret);
return HWC2::Error::NoResources;
}
return HWC2::Error::None;
}
}
ret = GetCurrentDisplayMode();
if (ret) {
HWC2_ALOGE("Failed to GetCurrentDisplayMode for display=%d %d\n", display, ret);
return HWC2::Error::NoResources;
}
ret = drm_->BindDpyRes(handle_);
if (ret) {
HWC2_ALOGE("Failed to BindDpyRes for display=%d %d\n", display, ret);
return HWC2::Error::NoResources;
}
UpdateDisplayInfo();
ret = drm_->UpdateDisplayGamma(handle_);
if (ret) {
HWC2_ALOGE("Failed to UpdateDisplayGamma for display=%d %d\n", display, ret);
}
ret = drm_->UpdateDisplay3DLut(handle_);
if (ret) {
HWC2_ALOGE("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_ALOGE("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("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_ALOGE("EBookApi init fail check\n");
return HWC2::Error::BadDisplay;
}
EBookError error = EBookError::None;
// 2. 初始化
error = mEBookApi_->Init(EBOOK_VERSION);
if (error != EBookError::None)
{
HWC2_ALOGE("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_ALOGE("EBook Init fail.\n");
return HWC2::Error::BadDisplay;;
}
HWC2_ALOGI(
"EBookInfo: resolution : width=%d height=%d. physical: width=%d mm"
"height=%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_ALOGD_IF_VERBOSE("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_ALOGE("Failed to GetCurrentDisplayMode for display=%d %d\n", display, ret);
return HWC2::Error::NoResources;
}
ret = drm_->BindDpyRes(handle_);
if (ret) {
HWC2_ALOGE("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_ALOGE("Failed to UpdateDisplayGamma for display=%d %d\n", display, ret);
}
ret = drm_->UpdateDisplay3DLut(handle_);
if (ret) {
HWC2_ALOGE("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);;
vsync_worker_.RegisterCallback(NULL);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::UnregisterInvalidateCallback() {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
invalidate_worker_.RegisterCallback(NULL);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::AcceptDisplayChanges() {
HWC2_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("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_ALOGE("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_ALOGD_IF_VERBOSE("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) {
HWC2_ALOGD_IF_DEBUG("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_ALOGI("RK356x primary framebuffer size %dx%d not support AFBC, to disable AFBC\n",
ctx_.framebuffer_width,ctx_.framebuffer_height);
}
}
if(hwc_get_int_property("ro.vendor.rk_sdk","0") == 0){
disable_afbdc = true;
HWC2_ALOGI("Maybe GSI SDK, to disable AFBC\n");
}
if(disable_afbdc){
property_set( "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_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
uint32_t num_request = 0;
if(hwc_get_int_property("ro.vendor.rk_sdk","0") == 0){
HWC2_ALOGD_IF_INFO("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_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
*type = static_cast<int32_t>(type_);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDozeSupport(int32_t *support) {
HWC2_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_DEBUG("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;
}
void DrmHwcTwo::HwcDisplay::AddFenceToRetireFence(int fd) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
char acBuf[32];
int retire_fence_fd = -1;
if (fd < 0){
// Collet all layer releaseFence
const sp<ReleaseFence> client_rf = client_layer_.back_release_fence();
if(client_rf->isValid()){
retire_fence_fd = dup(client_rf->getFd());
sprintf(acBuf,"RTD%" PRIu64 "-FN%d-%d", handle_, frame_no_, 0);
}
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &hwc2layer : layers_) {
if(hwc2layer.second.validated_type() != HWC2::Composition::Device)
continue;
// the new fence semantics for a frame n by returning the fence from frame n-1. For frame 0,
// the adapter returns NO_FENCE.
const sp<ReleaseFence> rf = hwc2layer.second.back_release_fence();
if (rf->isValid()){
// cur_retire_fence is null
if(retire_fence_fd > 0){
sprintf(acBuf,"RTD%" PRIu64 "-FN%d-%" PRIu64,handle_, frame_no_, hwc2layer.first);
int retire_fence_merge = rf->merge(retire_fence_fd, acBuf);
if(retire_fence_merge > 0){
close(retire_fence_fd);
retire_fence_fd = retire_fence_merge;
HWC2_ALOGD_IF_DEBUG("RetireFence(%d) %s frame = %d merge %s sucess!", retire_fence_fd, acBuf, frame_no_, rf->getName().c_str());
}else{
HWC2_ALOGE("RetireFence(%d) %s frame = %d merge %s faile!", retire_fence_fd, acBuf,frame_no_, rf->getName().c_str());
}
}else{
retire_fence_fd = dup(rf->getFd());
continue;
}
}
}
}else{
retire_fence_fd = fd;
}
d_retire_fence_.add(retire_fence_fd, acBuf);
return;
}
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);
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_HWPQ
//only RK3576 VP0 support HWPQ
if(gIsRK3576()){
if(crtc_->get_port_id()==0){
int ret = 0;
ret = client_layer_.DoHwPq(true, &client_target_layer, &ctx_);
if(ret){
HWC2_ALOGE("ClientLayer DoPq fail, ret = %d", ret);
}
}
}else
#endif
#ifdef USE_LIBPQ
if(handle_ == 0){
int ret = 0;
ret = client_layer_.DoSwPq(true, &client_target_layer, &ctx_);
if(ret){
HWC2_ALOGE("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_ALOGD_IF_VERBOSE("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]);
}
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_ALOGD_IF_DEBUG("%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);
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 "]=Device : %s",drm_hwc_layer.uId_,drm_hwc_layer.sLayerName_.c_str());
}
}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_ALOGD_IF_DEBUG("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_;
}
#ifdef USE_LIBPQ_HWPQ
int DrmHwcTwo::HwcDisplay::CollectInfoForHwPqUIMode(){
//HWPQ metadata Should gether here
ctx_.hwpq_meta_fd = -1;
ctx_.hwpq_meta_offset = 0;
ctx_.hwpq_meta_size = 0;
DrmGralloc* gralloc = DrmGralloc::getInstance();
if(gralloc == NULL){
HWC2_ALOGD_IF_INFO("DrmGralloc is null, Can not get PQ Metadata");
}else{
for (auto &layer : drm_hwc_layers_) {
if(layer.bYuv_ && layer.bHasMetadata_){
int64_t iMetaDataOffset_ = gralloc->hwc_get_offset_of_pq_metadata(layer.sf_handle);
if(iMetaDataOffset_>0){
ctx_.hwpq_meta_fd = layer.iFd_;
ctx_.hwpq_meta_offset = iMetaDataOffset_;
ctx_.hwpq_meta_size = layer.iSize_;
HWC2_ALOGD_IF_DEBUG("Pq metadata:fd=%d offset=%" PRIi64" name:%s",ctx_.hwpq_meta_fd,
ctx_.hwpq_meta_offset,layer.sLayerName_.c_str());
break;
}
}
}
}
return 0;
}
#endif
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;
#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_ALOGW("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){
CollectInfoForHwPqUIMode();
ret = client_layer_.DoHwPq(false, &drm_hwc_layer, &ctx_);
}
}else
#endif
if(handle_ == 0){
ret = client_layer_.DoSwPq(false, &drm_hwc_layer, &ctx_);
if(ret){
HWC2_ALOGE("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;
// 执行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::CreateComposition() {
HWC2_ALOGD_IF_VERBOSE("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_ALOGE("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主要用于调试
char value[PROPERTY_VALUE_MAX];
property_get("vendor.hwc.disable_releaseFence", value, "0");
if(atoi(value) == 0){
ret = composition->CreateAndAssignReleaseFences(sync_timeline_);
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_){
if(l.second.validated_type() == HWC2::Composition::Device){
sp<ReleaseFence> rf = composition->GetReleaseFence(l.first);
l.second.set_release_fence(rf);
}else{
l.second.set_release_fence(ReleaseFence::NO_FENCE);
}
}
sp<ReleaseFence> rf = composition->GetReleaseFence(0);
client_layer_.set_release_fence(rf);
AddFenceToRetireFence(composition->take_out_fence());
}
// 配置 HDR mode
composition->SetDisplayHdrMode(ctx_.hdr_mode, ctx_.dataspace);
// 配置丢帧模式
composition->SetDropMode(resource_manager_->IsCompositionDropMode());
ret = compositor_->QueueComposition(std::move(composition));
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::PresentVirtualDisplay(int32_t *retire_fence) {
ATRACE_CALL();
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
*retire_fence = -1;
// 若虚拟屏图层数为0则不做任何处理
if(!layers_.size()){
HWC2_ALOGD_IF_INFO("display %" PRIu64 " layer size is %zu", handle_, layers_.size());
return HWC2::Error::None;
}
if(bUseWriteBack_ &&
resource_manager_->isWBMode() &&
!resource_manager_->IsDisableHwVirtualDisplay()){
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_ALOGD_IF_DEBUG("call im2d reset Success");
mHasResetBufferId_.insert(bufferinfo->uBufferId_);
}else{
HWC2_ALOGE("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_ALOGE("OutputWBBuffer fail!");
}
// 添加调试接口抓打印传递给SurfaceFlinger的 Buffer
char value[PROPERTY_VALUE_MAX];
property_get("debug.wb.dump", value, "0");
if(atoi(value) > 0) {
output_layer_.DumpData();
}
}
}else{
if(client_layer_.acquire_fence() != NULL){
if(client_layer_.acquire_fence()->wait(1500)){
HWC2_ALOGE("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_ALOGE("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;
}
}
++frame_no_;
return HWC2::Error::None;
}
#endif
void DrmHwcTwo::HwcDisplay::CheckForSplitModeTimeline(){
int pipeline_timeline = property_get_int32(DRM_XML_SYS_UPDATE, -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 = property_get_int32(DRM_XML_VENDOR_UPDATE, -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_ALOGD_IF_ERR("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_ALOGD_IF_ERR("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__);
if(ret == HWC2::Error::BadLayer){
ClearDisplay();
}
}else{
ret = CreateComposition();
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(d_retire_fence_.get()->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(d_retire_fence_.get()->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 = d_retire_fence_.get()->isValid() ? dup(d_retire_fence_.get()->getFd()) : -1;
if(LogLevel(DBG_DEBUG)){
HWC2_ALOGD_IF_DEBUG("Return RetireFence(%d) %s frame = %d Info: size=%d act=%d signal=%d err=%d",
d_retire_fence_.get()->isValid(),
d_retire_fence_.get()->getName().c_str(), frame_no_,
d_retire_fence_.get()->getSize(),d_retire_fence_.get()->getActiveCount(),
d_retire_fence_.get()->getSignaledCount(),d_retire_fence_.get()->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_ALOGD_IF_VERBOSE("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_ALOGE("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_){
// VRR
HWC2::Error error = UpdateRefreshRate(config);
if(error != HWC2::Error::None){
return error;
}
}else if(config != 0){
HWC2_ALOGE("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_ALOGD_IF_VERBOSE("display-id=%" PRIu64 " config=%d", handle_, config);
if(!bVrrDisplay_)
return HWC2::Error::None;
const std::vector<int> vrr_mode = connector_->vrr_modes();
if(config <= (vrr_mode.size() - 1)){
int refresh_rate = vrr_mode[config];
int ret = drm_->UpdateVrrRefreshRate(handle_, refresh_rate);
if(ret){
HWC2_ALOGE("display=%" PRIu64 " config=%d refresh_rate=%d UpdateVrrRefreshRate fail!",
handle_, config, refresh_rate);
return HWC2::Error::BadConfig;
}
}else{
HWC2_ALOGE("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_ALOGD_IF_VERBOSE("display-id=%" PRIu64 ", Buffer=%p, acq_fence=%d, dataspace=%x",
handle_,target,acquire_fence,dataspace);
// 动态切换刷新率过程中SurfaceFlinger会出现 SetClientTarget target=null的情况
// 为了避免错误日志打印,故暂时对这种情况进行规避;
if(target == NULL){
HWC2_ALOGW("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_DEBUG("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_ALOGD_IF_VERBOSE("display-id=%" PRIu64 " bNeedSyncPMState_=%d",handle_, bNeedSyncPMState_);
if(!init_success_){
HWC2_ALOGE("init_success_=%d skip.",init_success_);
return HWC2::Error::BadDisplay;
}
if(!bNeedSyncPMState_){
HWC2_ALOGI("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_ALOGE("SetPowerMode fail %d", error);
return error;
}
bNeedSyncPMState_ = false;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetPowerMode(int32_t mode_in) {
HWC2_ALOGD_IF_VERBOSE("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_ALOGI("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_ALOGI("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;
};
if(!init_success_){
bNeedSyncPMState_ = true;
HWC2_ALOGE("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_ALOGE("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_ALOGE("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_ALOGE("Failed to UpdateModes for display=%" PRIu64 " ret=%d\n", handle_, ret);
return HWC2::Error::BadParameter;
}
}
HoplugEventTmeline();
ret = GetCurrentDisplayMode();
if (ret) {
HWC2_ALOGE("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_ALOGE("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_ALOGE("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_ALOGD_IF_VERBOSE("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_ALOGI("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 功能接口
char value[PROPERTY_VALUE_MAX];
property_get("vendor.hwc.only_sideband_use_wb", value, "0");
if(atoi(value) > 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.sf_type() == HWC2::Composition::Sideband){
exist_sideband_stream = true;
}
}
if(exist_sideband_stream){
bUseWriteBack_ = true;
}
}
HWC2_ALOGD_IF_DEBUG("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_ALOGD_IF_DEBUG("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_ALOGD_IF_DEBUG("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_ALOGD_IF_DEBUG("Failed to get crtc for display=%" PRIu64 " wb-display %d frame_no=%d", handle_, WBDisplayId, frame_no_);
bUseWriteBack_ = false;
}
// if(resource_manager_->GetFinishWBBufferSize() == 0){
// HWC2_ALOGD_IF_DEBUG("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_ALOGD_IF_DEBUG("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_ALOGD_IF_DEBUG("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_ALOGI("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_ALOGI("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_ALOGI("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_ERR("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;
}
// update sideband mode
UpdateSidebandMode();
*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;
}
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;
// We can only handle layers of Device type, send everything else to SF
if (layer.validated_type() != HWC2::Composition::Device) {
layer.set_validated_type(HWC2::Composition::Client);
}
//num_types 应该为发生改变的图层不仅仅是Client图层
if(layer.type_changed()){
++*num_types;
}
}
if(!client_layer_.isAfbc()){
++(*num_requests);
}
HWC2_ALOGD_IF_VERBOSE("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
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayConnectionType(uint32_t *outType) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 ,handle_);
if (connector_->internal())
*outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::Internal);
else if (connector_->external())
*outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::External);
else
return HWC2::Error::BadConfig;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayVsyncPeriod(
hwc2_vsync_period_t *outVsyncPeriod /* ns */) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 ,handle_);
supported(__func__);
DrmMode const &mode = connector_->active_mode();
if (mode.id() == 0)
return HWC2::Error::BadConfig;
*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_ALOGD_IF_VERBOSE("display-id=%" PRIu64 ,handle_);
supported(__func__);
if (vsyncPeriodChangeConstraints == nullptr || outTimeline == nullptr) {
return HWC2::Error::BadParameter;
}
//HDMI等接口切换分辨率和帧率会闪黑暂时不支持seamless切换模式
if (vsyncPeriodChangeConstraints->seamlessRequired) {
HWC2_ALOGE("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_ALOGD_IF_VERBOSE("display-id=%" PRIu64 ,handle_);
return HWC2::Error::Unsupported;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetSupportedContentTypes(
uint32_t *outNumSupportedContentTypes,
const uint32_t *outSupportedContentTypes) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 ,handle_);
if (outSupportedContentTypes == nullptr)
*outNumSupportedContentTypes = 0;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetContentType(int32_t contentType) {
HWC2_ALOGD_IF_VERBOSE("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;
}
#endif
// Only Android 14 Support
#if PLATFORM_SDK_VERSION >= 34
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayIdentificationData(
uint8_t *outPort, uint32_t *outDataSize, uint8_t *outData) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 ,handle_);
if(!resource_manager_->GetEnableEdidReport()){
HWC2_ALOGI("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_ALOGD_IF_DEBUG("Failed to get blob, HWC generate one.");
dummyEDID = connector_->MakeFakeEDID();
if(dummyEDID == nullptr){
HWC2_ALOGW("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_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("display-id=%" PRIu64 ,handle_);
*supported = false;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetDisplayBrightness(
float /* brightness */) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 ,handle_);
return HWC2::Error::Unsupported;
}
#endif /* PLATFORM_SDK_VERSION > 28 */
// Only Android 14 Support
#if PLATFORM_SDK_VERSION >= 34
HWC2::Error DrmHwcTwo::HwcDisplay::GetRenderIntents(
int32_t mode, uint32_t *outNumIntents,
int32_t * /*android_render_intent_v1_1_t*/ outIntents) {
HWC2_ALOGD_IF_VERBOSE("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_ALOGD_IF_VERBOSE("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;
}
#endif /* PLATFORM_SDK_VERSION >= 34 */
HWC2::Error DrmHwcTwo::HwcLayer::SetCursorPosition(int32_t x, int32_t y) {
HWC2_ALOGD_IF_VERBOSE("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(" DisplayId=%" PRIu64 ", Connector %u, Type = %s-%u, Connector state = %s\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");
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++;
}
}
output.append(
"------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n"
" id | z | sf-type | hwc-type | handle | transform | blnd | source crop (l,t,r,b) | frame | dataspace | mFps | name \n"
"------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n");
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;
}
}
}
output.append("------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n");
output.append("DrmHwcLayer Dump:\n");
for(auto &drmHwcLayer : drm_hwc_layers_)
drmHwcLayer.DumpInfo(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_);
output.append(
"------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n"
" id | z | req-type | fina-type | handle | transform | blnd | source crop (l,t,r,b) | frame | dataspace | mFps | name \n"
"------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n");
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;
}
}
}
output.append("------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n");
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_);
output.append(
"------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n"
" id | z | sf-type | hwc-type | handle | transform | blnd | source crop (l,t,r,b) | frame | dataspace | mFps | name \n"
"------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n");
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();
output.append("------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n");
ALOGD("%s",output.c_str());
return 0;
}
int DrmHwcTwo::HwcDisplay::DumpAllLayerData(){
char pro_value[PROPERTY_VALUE_MAX];
property_get( PROPERTY_TYPE ".dump",pro_value,0);
if(!strcmp(pro_value,"true")){
for (auto &map_layer : layers_) {
HwcLayer &layer = map_layer.second;
layer.DumpData();
}
if(client_layer_.buffer() != NULL)
client_layer_.DumpData();
for(auto &drm_layer : drm_hwc_layers_){
if(drm_layer.bUseSr_ && drm_layer.pSrBuffer_){
drm_layer.pSrBuffer_->DumpData();
}
}
for(auto &drm_layer : drm_hwc_layers_){
if(drm_layer.bUseRga_ && drm_layer.pRgaBuffer_){
drm_layer.pRgaBuffer_->DumpData();
}
}
}
return 0;
}
int DrmHwcTwo::HwcDisplay::HoplugEventTmeline(){
ctx_.hotplug_timeline++;
return 0;
}
int DrmHwcTwo::HwcDisplay::GetCurrentDisplayMode(){
if(!ctx_.bStandardSwitchResolution){
int timeline;
int display_id = static_cast<int>(handle_);
timeline = property_get_int32("vendor.display.timeline", -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_->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_ALOGW("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_.overscan_value);
return 0;
}
int DrmHwcTwo::HwcDisplay::UpdateHdmiOutputFormat(){
int timeline = 0;
timeline = property_get_int32( "vendor.display.timeline", -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 = property_get_int32("vendor.display.timeline", -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_ALOGD_IF_DEBUG("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_ALOGD_IF_DEBUG("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 = (int)(drmHwcLayer.source_crop.right - drmHwcLayer.source_crop.left);
int src_h = (int)(drmHwcLayer.source_crop.bottom - drmHwcLayer.source_crop.top);
int src_area_size = src_w * src_h;
int dis_w = drmHwcLayer.display_frame.right - drmHwcLayer.display_frame.left;
int dis_h = drmHwcLayer.display_frame.bottom - drmHwcLayer.display_frame.top;
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模式
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模式
char value[PROPERTY_VALUE_MAX];
property_get("persist.vendor.hwc.hdr_force_disable", value, "0");
if(atoi(value) > 0){
if(ctx_.hdr_mode != DRM_HWC_SDR){
HWC2_ALOGD_IF_DEBUG("Exit HDR mode success");
property_set("vendor.hwc.hdr_state","FORCE-NORMAL");
}
HWC2_ALOGD_IF_DEBUG("Fource Disable HDR mode.");
return true;
}
// 存在 HDR图层判断HDR视频的屏幕占比与缩放倍率满足条件则关闭HDR模式
property_get("persist.vendor.hwc.hdr_video_area", value, "6");
if(atoi(value) > hdr_area_ratio){
if(ctx_.hdr_mode != DRM_HWC_SDR){
HWC2_ALOGD_IF_DEBUG("Exit HDR mode success");
property_set("vendor.hwc.hdr_state","FORCE-NORMAL");
}
HWC2_ALOGD_IF_DEBUG("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_ALOGD_IF_INFO("Id=%d Name=%s ", hdrLayer.uId_, hdrLayer.sLayerName_.c_str());
if(ctx_.display_type == DRM_MODE_CONNECTOR_TV){
HWC2_ALOGD_IF_INFO("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_ALOGD_IF_ERR("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_ALOGD_IF_ERR("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_ALOGD_IF_ERR("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_ALOGD_IF_ERR("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 = hwc_get_int_property("persist.sys.vivid.hdr_mode", "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_ALOGD_IF_INFO("Use SDR2SDR mode.");
return -1;
}
DrmGralloc* gralloc = DrmGralloc::getInstance();
if(gralloc == NULL){
HWC2_ALOGD_IF_INFO("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.bHasMetadata_ ? gralloc->hwc_get_offset_of_dynamic_hdr_metadata(hdr_handle):0;
if(offset < 0){
HWC2_ALOGD_IF_ERR("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_ALOGD_IF_INFO("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 = hwc_get_int_property("persist.sys.vivid.max_brightness", "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 = hwc_get_int_property("persist.sys.vivid.max_brightness", "100") * 100;
}
void *cpu_addr = NULL;
if(codec_meta_exist){
// 获取Medata地址
cpu_addr = gralloc->hwc_get_handle_lock(hdr_handle, hdr_width, hdr_height);
if(cpu_addr == NULL){
HWC2_ALOGD_IF_ERR("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 = (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_ALOGD_IF_ERR("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_ALOGD_IF_INFO("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_ALOGD_IF_INFO("Id=%d Name=%s is HLG dynamic, convert to SDR.", hdrLayer.uId_, hdrLayer.sLayerName_.c_str());
}
}
}
}
}
}else{
// Metadata 不存在,则使用 Android Dataspace
hdrLayer.metadataHdrParam_.codec_meta_exist = false;
hdrLayer.metadataHdrParam_.p_hdr_codec_meta = NULL;
// 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 = RANGE_FULL;
break;
case HAL_DATASPACE_RANGE_LIMITED :
hdrLayer.metadataHdrParam_.hdr_dataspace_info.range = RANGE_LIMITED;
break;
default:
hdrLayer.metadataHdrParam_.hdr_dataspace_info.range = 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(hwc_get_int_property("vendor.hwc.vivid_hdr_debug", "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_ALOGD_IF_INFO("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_ALOGD_IF_INFO("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_ALOGD_IF_INFO("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_ALOGD_IF_ERR("Fail to call MetadataHdrParser ret=%d Id=%d Name=%s ",
ret,
hdrLayer.uId_,
hdrLayer.sLayerName_.c_str());
if(cpu_addr != NULL)
gralloc->hwc_get_handle_unlock(hdr_handle);
return ret;
}
if(cpu_addr != NULL)
gralloc->hwc_get_handle_unlock(hdr_handle);
hdrLayer.IsMetadataHdr_ = true;
ctx_.hdr_mode = DRM_HWC_METADATA_HDR;
ctx_.dataspace = hdrLayer.eDataSpace_;
HWC2_ALOGD_IF_INFO("Use HdrParser mode.");
return 0;
}
int DrmHwcTwo::HwcDisplay::EnableHdrMode(DrmHwcLayer& hdrLayer){
HWC2_ALOGD_IF_INFO("Id=%d Name=%s ", hdrLayer.uId_, hdrLayer.sLayerName_.c_str());
if(connector_->is_hdmi_support_hdr()){
if(ctx_.hdr_mode != DRM_HWC_HDR10){
ALOGD_IF(LogLevel(DBG_DEBUG),"Enable HDR mode success");
ctx_.hdr_mode = DRM_HWC_HDR10;
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_ALOGD_IF_ERR("DestoryConnection display=%" PRIu64 " tunnel-id=%d fail ret=%d", handle_, iLastTunnelId_, ret);
}else{
HWC2_ALOGD_IF_INFO("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_ALOGD_IF_ERR("CreateConnection display=%" PRIu64 " fail tunnel-id=%d ret=%d", handle_, tunnel_id, ret);
}else{
dvp->SetProducerFps(tunnel_id,fps);
HWC2_ALOGD_IF_INFO("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_ALOGD_IF_ERR("DestoryConnection display=%" PRIu64 " tunnel-id=%d fail ret=%d", handle_, iLastTunnelId_, ret);
}else{
HWC2_ALOGD_IF_INFO("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_ALOGD_IF_DEBUG("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_ALOGD_IF_DEBUG("Sr Enable SelfRefresh!");
enable_self_refresh = true;
self_fps = 10;
break;
}
// MEMC
if(drmHwcLayer.bUseMemc_){
HWC2_ALOGD_IF_DEBUG("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 = hwc_get_int_property( "vendor.hwc.static_screen_opt_time", "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_ALOGD_IF_VERBOSE("reset timer! interval_value = %d",interval_value);
} else {
static_screen_opt_=false;
tv.it_value.tv_usec = 0;
ALOGD_IF(LogLevel(DBG_DEBUG),"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;
}
// 拼接主屏获取到实际的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_ALOGD_IF_DEBUG("%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_ALOGE("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_ALOGW("SplitMode: invalid transform=%d", transform);
transform = 0;
break;
}
dummy_layer.SetLayerTransform(transform);
HWC2_ALOGI("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_ALOGI("SplitMode: display=%" PRIu64" Destory dummylayer = %" PRIu64, handle_, uCropSplitDummyLayer_);
auto ret = DestroyLayer(uCropSplitDummyLayer_);
uCropSplitDummyLayer_ = 0;
return ret;
}else{
return HWC2::Error::None;
}
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerBlendMode(int32_t mode) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d"", blend=%d" ,id_,mode);
mCurrentState.blending_ = static_cast<HWC2::BlendMode>(mode);
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_ALOGD_IF_VERBOSE("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_ALOGW("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_ALOGD_IF_DEBUG("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;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerColor(hwc_color_t color) {
HWC2_ALOGD_IF_VERBOSE("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;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerCompositionType(int32_t type) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d"", type=0x%x" ,id_,type);
mCurrentState.sf_type_ = static_cast<HWC2::Composition>(type);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDataspace(int32_t dataspace) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d"", dataspace=0x%x" ,id_,dataspace);
mCurrentState.dataspace_ = static_cast<android_dataspace_t>(dataspace);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDisplayFrame(hwc_rect_t frame) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d"", frame=[%d,%d,%d,%d]" ,id_,frame.left,frame.top,frame.right,frame.bottom);
mCurrentState.display_frame_ = frame;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerPlaneAlpha(float alpha) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d"", alpha=%f" ,id_,alpha);
mCurrentState.alpha_ = alpha;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSidebandStream(
const native_handle_t *stream) {
HWC2_ALOGD_IF_VERBOSE("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_ALOGD_IF_DEBUG("SidebandStream: layer-id=%d. version=%d numFds=%d numInts=%d",
id_,
stream->version,
stream->numFds,
stream->numInts);
HWC2_ALOGD_IF_DEBUG("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);
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSourceCrop(hwc_frect_t crop) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d"", frame=[%f,%f,%f,%f]" ,id_,crop.left,crop.top,crop.right,crop.bottom);
mCurrentState.source_crop_ = crop;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSurfaceDamage(hwc_region_t damage) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d",id_);
// TODO: We don't use surface damage, marking as unsupported
unsupported(__func__, damage);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerTransform(int32_t transform) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d" ", transform=%x",id_,transform);
mCurrentState.transform_ = static_cast<HWC2::Transform>(transform);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerVisibleRegion(hwc_region_t visible) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d",id_);
// TODO: We don't use this information, marking as unsupported
unsupported(__func__, visible);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerZOrder(uint32_t order) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d" ", z=%d",id_,order);
mCurrentState.z_order_ = order;
return HWC2::Error::None;
}
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->bSideband2_ = true;
// 通过 Sideband Handle compress_mode 来判断图层是否为AFBC压缩格式
if(mSidebandInfo_.compress_mode > 0){
if(gIsRK3576()){
HWC2_ALOGD_IF_DEBUG("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_;
drmHwcLayer->bHasMetadata_ = pBufferInfo_->bHasMetadata_;
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;
}
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();
#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{
PopulateNormalLayer(drmHwcLayer, ctx);
}
#ifdef RK3528
if(gIsRK3528()){
int enable_prescale_video = hwc_get_int_property("debug.hwc.enable_prescale_video", "0");
if(enable_prescale_video > 0 && drmHwcLayer->bYuv_){
metadata_for_rkvdec_scaling_t* metadata = NULL;
drmGralloc_->lock_rkvdec_scaling_metadata(buffer_, &metadata);
HWC2_ALOGD_IF_INFO("lock_rkvdec_scaling_metadata buffer_=%p metadata=%p", buffer_, metadata);
if(metadata != NULL){
metadata->requestMask = enable_prescale_video;
if(metadata->replyMask > 0){
memcpy(&(drmHwcLayer->mMetadata_), metadata, sizeof(metadata_for_rkvdec_scaling_t));
drmHwcLayer->bNeedPreScale_ = true;
drmHwcLayer->bIsPreScale_ = true;
hwc_frect source_crop;
source_crop.top = metadata->srcTop;
source_crop.left = metadata->srcLeft;
source_crop.right = metadata->srcRight;
source_crop.bottom = metadata->srcBottom;
drmHwcLayer->SetSourceCrop(source_crop);
drmHwcLayer->iWidth_ = metadata->width;
drmHwcLayer->iHeight_ = metadata->height;
drmHwcLayer->iStride_ = metadata->pixel_stride;
drmHwcLayer->iFormat_ = metadata->format;
drmHwcLayer->iUsage = metadata->usage;
drmHwcLayer->iByteStride_ = metadata->byteStride[0];
drmHwcLayer->uModifier_ = metadata->modifier;
drmHwcLayer->uFourccFormat_ = drmGralloc_->hwc_get_fourcc_from_hal_format(metadata->format);
drmHwcLayer->Init();
}
// 打印参数
HWC2_ALOGD_IF_INFO("Name=%s metadata = %p", pBufferInfo_->sLayerName_.c_str(), metadata);
HWC2_ALOGD_IF_INFO("version=0x%" PRIx64 " requestMask=0x%" PRIx64" "
"replyMask=0x%" PRIx64 " BufferId=0x%" PRIx64,
metadata->version,
metadata->requestMask,
metadata->replyMask,
drmHwcLayer->uBufferId_);
HWC2_ALOGD_IF_INFO("w=%d h=%d s=%d f=%d m=0x%" PRIx64 " usage=0x%x ",
metadata->width,
metadata->height,
metadata->pixel_stride,
metadata->format,
metadata->modifier,
metadata->usage);
HWC2_ALOGD_IF_INFO("crop=(%d,%d,%d,%d) ", metadata->srcLeft,
metadata->srcTop,
metadata->srcRight,
metadata->srcBottom);
HWC2_ALOGD_IF_INFO("layer_cnt=%d offset=%d,%d,%d,%d byteStride=%d,%d,%d,%d) ",
metadata->layer_cnt,
metadata->offset[0],
metadata->offset[1],
metadata->offset[2],
metadata->offset[3],
metadata->byteStride[0],
metadata->byteStride[1],
metadata->byteStride[2],
metadata->byteStride[3]);
drmGralloc_->unlock_rkvdec_scaling_metadata(buffer_);
}
}
}
#endif
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;
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){
char value[PROPERTY_VALUE_MAX];
property_get("persist.vendor.tvinput.rkpq.mode", value, "0");
bool pq_mode_enable = atoi(value) > 0;
if(pq_mode_enable == 1){
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_ALOGI("Pq module ready. to enable PqMode.");
}
} else {
bPqReady_ = true;
HWC2_ALOGI("Pq module ready. to enable PqMode.");
}
if(bPqReady_){
// 1. Init Ctx
int ret = swpq_->InitCtx(pqCtx_);
if(ret){
HWC2_ALOGE("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_ALOGI("pq module ready. to enable pqMode.");
}
}
if(bPqReady_){
// 1. Init Ctx
int ret = swpq_->InitCtx(pqCtx_);
if(ret){
HWC2_ALOGE("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;
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_ALOGD_IF_DEBUG("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;
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_ALOGE("wait Fb-Target 1500ms timeout, ret=%d",ret);
drmHwcLayer->bUsePq_ = false;
bufferQueue_->QueueBuffer(dst_buffer);
return ret;
}
}
int output_fence = 0;
ret = swpq_->RunAsync(pqCtx_, &output_fence);
if(ret){
HWC2_ALOGD_IF_DEBUG("RunAsync fail!");
drmHwcLayer->bUsePq_ = false;
bufferQueue_->QueueBuffer(dst_buffer);
return ret;
}
dst_buffer->SetFinishFence(dup(output_fence));
drmHwcLayer->acquire_fence = sp<AcquireFence>(new AcquireFence(output_fence));
property_get("vendor.dump", value, "false");
if(!strcmp(value, "true")){
drmHwcLayer->acquire_fence->wait();
dst_buffer->DumpData();
}
bufferQueue_->QueueBuffer(dst_buffer);
}
}
drmHwcLayer->uFourccFormat_ = DRM_FORMAT_NV24;
} else {
if(bPqReady_) {
swpq_->DeInit();
bPqReady_ = false;
}
}
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
#ifdef USE_LIBPQ_HWPQ
int DrmHwcTwo::HwcLayer::DoHwPq(bool validate, DrmHwcLayer *drmHwcLayer, hwc2_drm_display_t* ctx){
char value[PROPERTY_VALUE_MAX];
property_get("persist.vendor.tvinput.rkpq.mode", value, "0");
bool pq_mode_enable = atoi(value) == 1;
int ret = 0;
if(pq_mode_enable == 1){
if(validate){
ctx->use_pq_fb = false;
if(bufferQueue_ == NULL){
bufferQueue_ = std::make_shared<DrmBufferQueue>();
}
if(hwpq_ == NULL){
hwpq_ = std::make_shared<Pq>();
if(hwpq_ != NULL){
ret = hwpq_->Init(PQ_VERSION);
if(ret != 0){
hwpq_ = NULL;
HWC2_ALOGE("Pq Init Failed, ret = %d", ret);
}else{
bPqReady_ = true;
HWC2_ALOGI("Pq Init Successfully.");
}
}
}
if(hwpq_ == NULL){
HWC2_ALOGE("Pq module not ready.");
} else {
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(hwpq_ != NULL){
// 1. Set buffer Info
HwPqImageInfo 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_.iHeightStride_ = drmHwcLayer->iHeightStride_;
src.mBufferInfo_.uBufferId_ = drmHwcLayer->uBufferId_;
src.mBufferInfo_.uDataSpace_ = (uint64_t)drmHwcLayer->eDataSpace_;
src.mIsFbcdFormat_ = drmHwcLayer->bAfbcd_ || drmHwcLayer->bRfbcd_;
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;
src.iMetaDataFd_ = -1;
src.iMetaDataSize_ = 0;
src.iMetaDataOffset_ = 0;
if(ctx->hwpq_meta_offset > 0){
src.iMetaDataFd_ = ctx->hwpq_meta_fd;
src.iMetaDataSize_ = ctx->hwpq_meta_size;
src.iMetaDataOffset_ = ctx->hwpq_meta_offset;
HWC2_ALOGD_IF_DEBUG("Pq metadata:fd=%d offset=%" PRIi64,src.iMetaDataFd_,
src.iMetaDataOffset_);
}
if(drmHwcLayer->hwPqDisplayStatus){
src.mDisplayStatus_ = drmHwcLayer->hwPqDisplayStatus;
}else{
HWC2_ALOGD_IF_VERBOSE("HWPQ: hwPqDisplayStatus is NULL, Please check TryHwcPolicy!");
}
src.iRotation_ = drmHwcLayer->transform;
src.mIsFbcdFormat_ = drmHwcLayer->bAfbcd_||drmHwcLayer->bRfbcd_;
// 2. Alloc Dst HwPqReg
HwPqImageInfo dst;
std::shared_ptr<DrmBuffer> dst_buffer;
if(drmHwcLayer->hwPqReg_ == NULL){
drmHwcLayer->hwPqReg_ = std::shared_ptr<rk_hwpq_reg>(new rk_hwpq_reg);
if(drmHwcLayer->hwPqReg_ == NULL){
HWC2_ALOGE("rk_hwpq_reg alloc failed");
return -1;
}
}
dst.mBufferInfo_.iFd_ = -1;
dst.mRkHwpqReg_ = drmHwcLayer->hwPqReg_.get();
// 3. Set HwPq Src Image
bool needAllocNewBuffer = false;
ret = hwpq_->SetHwPqSrcImage(src, dst, &needAllocNewBuffer);
if(ret){
if(ret == PqUnInit)
HWC2_ALOGW("Pq SetHwPqSrcImage fail, Pq may still initializing, ret = %d", ret);
else
HWC2_ALOGE("Pq SetHwPqSrcImage fail, ret = %d", ret);
return ret;
}
//如果需要新的buffer宽高format变化
if(needAllocNewBuffer){
HWC2_ALOGD_IF_DEBUG("hwpq use new buffer mode, alloc Buffer!");
dst_buffer = bufferQueue_->DequeueDrmBuffer(dst.mBufferInfo_.iWidth_,
dst.mBufferInfo_.iHeight_,
dst.mBufferInfo_.iFormat_,
// PQ 算法要求 16 对齐
RK_GRALLOC_USAGE_STRIDE_ALIGN_16 |
MALI_GRALLOC_USAGE_NO_AFBC,
"PQ-FB-target");
if(dst_buffer == NULL){
HWC2_ALOGD_IF_DEBUG("DequeueDrmBuffer fail!, skip this policy.");
return -1;
}
// 5. Set buffer Info
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_.iHeightStride_ = dst_buffer->GetHeightStride();
dst.mBufferInfo_.uBufferId_ = dst_buffer->GetBufferId();
}else{
dst.mBufferInfo_ = src.mBufferInfo_;
}
ret = hwpq_->SetHwPqDstImage(dst);
if(ret){
HWC2_ALOGE("Pq SetHwPqDstImage fail ret = %d", ret);
if(dst_buffer != NULL)
bufferQueue_->QueueBuffer(dst_buffer);
return ret;
}
if(dst_buffer != NULL){
hwc_frect_t source_crop;
source_crop.left = dst.mCrop_.iLeft_;
source_crop.top = dst.mCrop_.iTop_;
source_crop.right = dst.mCrop_.iRight_;
source_crop.bottom = dst.mCrop_.iBottom_;
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);
}
int output_fence = -1;
int acquire_fence = -1;
if(drmHwcLayer->acquire_fence->isValid()){
acquire_fence = dup(drmHwcLayer->acquire_fence->getFd());
}
ret = hwpq_->RunHwPqAsync(&output_fence, acquire_fence);
if(ret){
HWC2_ALOGE("RunHwPqAsync fail! ret = %d", ret);
drmHwcLayer->bUsePq_ = false;
if(dst_buffer != NULL)
bufferQueue_->QueueBuffer(dst_buffer);
return ret;
}
//HWPQ output_fence indicate hwpq register is ready
drmHwcLayer->hwPqRegAcquireFence_ = sp<AcquireFence>(new AcquireFence(output_fence));
if(dst_buffer != NULL){
dst_buffer->SetFinishFence(dup(output_fence));
drmHwcLayer->acquire_fence = sp<AcquireFence>(new AcquireFence(dup(output_fence)));
}
property_get("vendor.dump", value, "false");
if(!strcmp(value, "true") && dst_buffer != NULL){
dst_buffer->WaitFinishFence();
dst_buffer->DumpData();
}
if(dst_buffer != NULL)
bufferQueue_->QueueBuffer(dst_buffer);
}
}
} else {
if(bPqReady_) {
drmHwcLayer->hwPqReg_ = NULL;
hwpq_->DeInit();
hwpq_ = NULL;
bPqReady_ = false;
}
}
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() {
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, size;
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);
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;
}
FILE * pfile = NULL;
char data_name[100] ;
system("mkdir /data/dump/ && chmod /data/dump/ 777 ");
sprintf(data_name,"/data/dump/%d_%5.5s_id-%d_%dx%d_z-%d.bin",
frame_cnt++,layer_name_.size() < 5 ? "unset" : layer_name_.c_str(),
id_,stride,height,mCurrentState.z_order_);
pfile = fopen(data_name,"wb");
if(pfile)
{
fwrite((const void *)cpu_addr,(size_t)(size),1,pfile);
fflush(pfile);
fclose(pfile);
ALOGD(" dump surface layer_id=%d ,data_name %s,w:%d,h:%d,stride :%d,size=%d,cpu_addr=%p",
id_,data_name,width,height,byte_stride,size,cpu_addr);
}
else
{
ALOGE("Open %s fail", data_name);
ALOGD(" dump surface layer_id=%d ,data_name %s,w:%d,h:%d,stride :%d,size=%d,cpu_addr=%p",
id_,data_name,width,height,byte_stride,size,cpu_addr);
}
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(ResourceManager::getInstance()->IsSingleDisplayMode() && displayid != HWC_DISPLAY_PRIMARY){
HWC2_ALOGW("IsSingleDisplayMode skip display-id=%" PRIu64 " state=%d hotplug event.",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()){
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_ALOGI("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;
}
}
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())
return;
ResourceManager* rm = ResourceManager::getInstance();
int primary_id = 0;
DrmDevice* drm_ = rm->GetDrmDevice(primary_id);
if(drm_ == NULL){
HWC2_ALOGE("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_ALOGE("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_ALOGI("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_ALOGI("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_ALOGI("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_ALOGD_IF_INFO("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_ALOGI("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_ALOGI("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_ALOGD_IF_INFO("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){
HWC2_ALOGW("hwc_hotplug : receive drm hotplug event but no state change. "
"display's connection maybe have error, timestamp_us=%" PRIu64, timestamp_us);
}
}
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_ALOGE("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_ALOGE("Failed to get DrmConnector for display %d", event.display_id);
return -1;
}
//更新设备的分辨率列表
conn->ResetModesReady();
conn->UpdateModes();
if(!conn->ModesReady()){
HWC2_ALOGE("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_ALOGE("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());
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_ALOGE("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_ALOGI("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);
}
HaneleDisplayPipelineUpdateEvent(DRM_PIPELINE_PRIMARY_CHANGE);
display.SyncPowerMode();
}
}else{
ret |= (int32_t)display.ClearDisplay();
ret |= (int32_t)drm_->ReleaseDpyRes(display_id);
if(ret != 0){
HWC2_ALOGE("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_ALOGI("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());
HaneleDisplayPipelineUpdateEvent(DRM_PIPELINE_PRIMARY_CHANGE);
}
}
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_ALOGE("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_ALOGE("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_ALOGE("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_ALOGE("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_ALOGE("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_ALOGI("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);
}else{
HWC2_ALOGI("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_ALOGE("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_ALOGI("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_ALOGE("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_ALOGI("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_ALOGE("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_ALOGI("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_ALOGI("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_ALOGE("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_ALOGI("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);
}else{
HWC2_ALOGI("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_ALOGE("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_ALOGI("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_ALOGE("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_ALOGI("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_ALOGE("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_ALOGI("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_ALOGE("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_ALOGI("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();
}
int DrmHwcTwo::EventWorker::SendDrmEvent(DrmEvent event){
Lock();
HWC2_ALOGD_IF_INFO("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_ALOGI("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_ALOGI("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_ALOGE("Failed to get DrmDevice for display %d", event.display_id);
return -1;
}
DrmConnector *connector = drm->GetConnectorForDisplay(event.display_id);
if (!connector) {
HWC2_ALOGE("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);
HWC2::Error error = display.ChosePreferredConfig();
if(error != HWC2::Error::None){
HWC2_ALOGE("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_ALOGI("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_ALOGE("Failed to get DrmDevice for display %d", event.display_id);
return -1;
}
DrmConnector *connector = drm->GetConnectorForDisplay(event.display_id);
if (!connector) {
HWC2_ALOGE("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_ALOGE("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_ALOGI("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(uint64_t force_mask_update){
ResourceManager* rm = ResourceManager::getInstance();
int primary_id = 0;
DrmDevice* drm = rm->GetDrmDevice(primary_id);
if(drm == NULL){
HWC2_ALOGE("DisplayPipeChange : Failed to get DrmDevice");
}
// 检查display pipeline更新情况
uint64_t change_mask = 0;
if(drm->GetDisplayPipelineChange(&change_mask) == 0 || force_mask_update > 0){
if(force_mask_update > 0){
change_mask = force_mask_update;
}
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_ALOGE("DisplayPipeChange : HandlePrimaryChange fail.");
return -1;
}
}
if((change_mask & DRM_PIPELINE_SPLIT_MODE_CHANGE) == DRM_PIPELINE_SPLIT_MODE_CHANGE){
if(HandleSplitModeChange()){
HWC2_ALOGE("DisplayPipeChange : SplitMode : HandleSplitModeChange fail.");
return -1;
}
}
// 将所有屏幕设置为连接状态
for(auto &map : hwc2_->displays_){
map.second.ConnectDisplay();
}
}
}
HWC2_ALOGI("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_ALOGE("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_ALOGE("DisplayPipeChange : Failed to ReleaseDpyRes for display=%d %d\n", display_id, ret);
continue;
}
HWC2_ALOGI("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);
}
// 更新主屏信息,可能存在主副屏幕切换行为
drm->UpdatePrimaryInfo();
// 根据新绑定的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_ALOGI("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_ALOGE("DisplayPipeChange : SplitMode: Can not get ResourceManager");
return -1;
}
DrmDevice* drm = rm->GetDrmDevice(0);
if(!drm){
HWC2_ALOGE("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_ALOGI("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_ALOGE("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_ALOGI("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_ALOGI("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_ALOGI("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_ALOGE("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_ALOGI("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(display_id)) == HWC2::Error::None){
HWC2_ALOGI("DisplayPipeChange : SplitMode : %s-%d isHorizontalSplit,, send hotplug to SF.",
drm->connector_type_str(conn->type()),conn->type_id());
hwc2_->HandleDisplayHotplug(display_id, cur_state);
}else{
HWC2_ALOGE("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_){
ret = WaitForSignalOrExitLocked();
Unlock();
return;
}
if(mMapPendingEvent_.empty()){
ret = WaitForSignalOrExitLocked();
if (ret == -EINTR) {
HWC2_ALOGI("EventWorker: WaitForSignalOrExitLocked fail! ret=%d", ret);
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_ALOGE("unknow hotplug event, display-id=%d type=%d connection=%d",
event.display_id, event.type, event.connection);
break;
}
}
if(ret){
HWC2_ALOGE("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__);
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
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::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::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>);
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>);
#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;
}
}
// 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},
};