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