android13/hardware/rockchip/hwcomposer/drmhwc2/drmhwctwo.cpp

4825 lines
181 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#define LOG_TAG "hwc-drm-two"
#include "drmhwctwo.h"
#include "drmdisplaycomposition.h"
#include "drmlayer.h"
#include "platform.h"
#include "vsyncworker.h"
#include "rockchip/utils/drmdebug.h"
#include "rockchip/drmgralloc.h"
#include <im2d.hpp>
#include <drm_fourcc.h>
#include <rga.h>
#include <inttypes.h>
#include <string>
#include <cutils/properties.h>
#include <hardware/hardware.h>
#include <hardware/hwcomposer2.h>
#include <log/log.h>
#include <utils/Trace.h>
#include <linux/fb.h>
#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
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.string()); \
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);
}
}
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;
}
HWC2::Error DrmHwcTwo::CreateDisplay(hwc2_display_t displ,
HWC2::DisplayType type) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 " type=%s" , displ,
(type == HWC2::DisplayType::Physical ? "Physical" : "Virtual"));
DrmDevice *drm = resource_manager_->GetDrmDevice(displ);
std::shared_ptr<Importer> importer = resource_manager_->GetImporter(displ);
if (!drm || !importer) {
ALOGE("Failed to get a valid drmresource and importer");
return HWC2::Error::NoResources;
}
displays_.emplace(std::piecewise_construct, std::forward_as_tuple(displ),
std::forward_as_tuple(resource_manager_, drm, importer,
displ, type));
displays_.at(displ).Init();
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::Init() {
HWC2_ALOGD_IF_VERBOSE();
int rv = resource_manager_->Init(this);
if (rv) {
ALOGE("Can't initialize the resource manager %d", rv);
return HWC2::Error::NoResources;
}
HWC2::Error ret = HWC2::Error::None;
for (auto &map_display : resource_manager_->getDisplays()) {
ret = CreateDisplay(map_display.second, HWC2::DisplayType::Physical);
if (ret != HWC2::Error::None) {
ALOGE("Failed to create display %d with error %d", map_display.second, ret);
return ret;
}
}
auto &drmDevices = resource_manager_->GetDrmDevices();
for (auto &device : drmDevices) {
device->RegisterHotplugHandler(new DrmHotplugHandler(this, device.get()));
}
return ret;
}
hwc2_drm_display_t* DrmHwcTwo::GetDisplayCtxPtr(hwc2_display_t display_id){
if(displays_.count(display_id)){
auto &display = displays_.at(display_id);
return display.GetDisplayCtxPtr();
}
return NULL;
}
template <typename... Args>
static inline HWC2::Error unsupported(char const *func, Args... /*args*/) {
ALOGV("Unsupported function: %s", func);
return HWC2::Error::Unsupported;
}
static inline void supported(char const *func) {
ALOGV("Supported function: %s", func);
}
HWC2::Error DrmHwcTwo::CreateVirtualDisplay(uint32_t width, uint32_t height,
int32_t *format,
hwc2_display_t *display) {
HWC2_ALOGD_IF_VERBOSE("w=%u,h=%u,f=%d",width,height,*format);
HWC2::Error ret = HWC2::Error::None;
int physical_display_num = resource_manager_->getDisplayCount();
int virtual_display_id = physical_display_num + mVirtualDisplayCount_;
if(!displays_.count(virtual_display_id)){
char value[PROPERTY_VALUE_MAX];
property_get("vendor.hwc.virtual_display_write_back_id", value, "0");
int write_back_id = atoi(value);
DrmDevice *drm = resource_manager_->GetDrmDevice(write_back_id);
std::shared_ptr<Importer> importer = resource_manager_->GetImporter(write_back_id);
if (!drm || !importer) {
ALOGE("Failed to get a valid drmresource and importer");
return HWC2::Error::NoResources;
}
displays_.emplace(std::piecewise_construct, std::forward_as_tuple(virtual_display_id),
std::forward_as_tuple(resource_manager_, drm, importer,
virtual_display_id,
HWC2::DisplayType::Virtual));
displays_.at(virtual_display_id).InitVirtual();
*display = virtual_display_id;
*format = HAL_PIXEL_FORMAT_RGBA_8888;
mVirtualDisplayCount_++;
resource_manager_->EnableWriteBackMode(write_back_id);
HWC2_ALOGI("Support VDS: w=%u,h=%u,f=%d display-id=%d",width,height,*format,virtual_display_id);
auto &display = resource_manager_->GetHwc2()->displays_.at(0);
display.InvalidateControl(30,-1);
return HWC2::Error::None;
}
return HWC2::Error::NoResources;
}
HWC2::Error DrmHwcTwo::DestroyVirtualDisplay(hwc2_display_t display) {
HWC2_ALOGD_IF_VERBOSE();
auto virtual_display = displays_.find(display);
if(virtual_display != displays_.end()){
displays_.erase(virtual_display);
resource_manager_->DisableWriteBackMode(resource_manager_->GetWBDisplay());
HWC2_ALOGI("VDS: display-id=%" PRIu64 , display);
mVirtualDisplayCount_--;
auto &display = resource_manager_->GetHwc2()->displays_.at(0);
display.InvalidateControl(30,0);
return HWC2::Error::None;
}
return HWC2::Error::BadDisplay;
}
void DrmHwcTwo::Dump(uint32_t *size, char *buffer) {
if (buffer != nullptr) {
auto copiedBytes = mDumpString.copy(buffer, *size);
*size = static_cast<uint32_t>(copiedBytes);
return;
}
String8 output;
char acVersion[50] = {0};
strcpy(acVersion,GHWC_VERSION);
output.appendFormat("-- HWC2 Version %s by bin.li@rock-chips.com --\n",acVersion);
for(auto &map_disp: displays_){
output.append("\n");
if((map_disp.second.DumpDisplayInfo(output)) < 0)
continue;
}
mDumpString = output.string();
*size = static_cast<uint32_t>(mDumpString.size());
return;
}
uint32_t DrmHwcTwo::GetMaxVirtualDisplayCount() {
HWC2_ALOGI();
// DSI 固件不支持 HW VirtualDisplay.
if(hwc_get_int_property("ro.vendor.rk_sdk","0") == 0){
HWC2_ALOGI("Maybe GSI SDK, to disable HW VirtualDisplay\n");
return 0;
}
char value[PROPERTY_VALUE_MAX];
property_get("vendor.hwc.max_virtual_display_count", value, "5");
return atoi(value);
}
static bool isValid(HWC2::Callback descriptor) {
switch (descriptor) {
case HWC2::Callback::Hotplug: // Fall-through
case HWC2::Callback::Refresh: // Fall-through
case HWC2::Callback::Vsync: return true;
default: return false;
}
}
HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
hwc2_callback_data_t data,
hwc2_function_pointer_t function) {
HWC2_ALOGD_IF_VERBOSE();
auto callback = static_cast<HWC2::Callback>(descriptor);
if (!isValid(callback)) {
return HWC2::Error::BadParameter;
}
if (!function) {
callbacks_.erase(callback);
switch (callback) {
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));
// 主屏已经向SurfaceFlinger注册
mHasRegisterDisplay_.insert(HWC_DISPLAY_PRIMARY);
auto &drmDevices = resource_manager_->GetDrmDevices();
for (auto &device : drmDevices)
HandleInitialHotplugState(device.get());
break;
}
case HWC2::Callback::Vsync: {
for (std::pair<const hwc2_display_t, DrmHwcTwo::HwcDisplay> &d :
displays_)
d.second.RegisterVsyncCallback(data, function);
break;
}
case HWC2::Callback::Refresh: {
for (std::pair<const hwc2_display_t, DrmHwcTwo::HwcDisplay> &d :
displays_)
d.second.RegisterInvalidateCallback(data, function);
break;
}
default:
break;
}
return HWC2::Error::None;
}
DrmHwcTwo::HwcDisplay::HwcDisplay(ResourceManager *resource_manager,
DrmDevice *drm,
std::shared_ptr<Importer> importer,
hwc2_display_t handle, HWC2::DisplayType type)
: resource_manager_(resource_manager),
drm_(drm),
importer_(importer),
handle_(handle),
type_(type),
client_layer_(UINT32_MAX,drm),
output_layer_(UINT32_MAX,drm),
init_success_(false){
}
int DrmHwcTwo::HwcDisplay::ClearDisplay() {
if(!init_success_){
HWC2_ALOGE("display=%" PRIu64 " init_success_=%d skip.", handle_, init_success_);
return -1;
}
if(connector_ != NULL &&
connector_->hwc_state() != HwcConnnectorStete::RELEASE_CRTC){
compositor_->ClearDisplay();
}
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
return 0;
}
int DrmHwcTwo::HwcDisplay::ActiveModeChange(bool change) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
bActiveModeChange_ = change;
return 0;
}
bool DrmHwcTwo::HwcDisplay::IsActiveModeChange() {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
return bActiveModeChange_;
}
HWC2::Error DrmHwcTwo::HwcDisplay::Init() {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
int display = static_cast<int>(handle_);
if(sync_timeline_.isValid()){
HWC2_ALOGD_IF_INFO("sync_timeline_ fd = %d isValid", sync_timeline_.getFd());
}
connector_ = drm_->GetConnectorForDisplay(display);
if (!connector_) {
ALOGE("Failed to get connector for display %d", display);
return HWC2::Error::BadDisplay;
}
int ret = vsync_worker_.Init(drm_, display);
if (ret) {
ALOGE("Failed to create event worker for d=%d %d\n", display, ret);
return HWC2::Error::BadDisplay;
}
ret = invalidate_worker_.Init(display);
if (ret) {
ALOGE("Failed to create invalidate worker for d=%d %d\n", display, ret);
return HWC2::Error::BadDisplay;
}
if(connector_->state() != DRM_MODE_CONNECTED){
ALOGI("Connector %u type=%s, type_id=%d, state is DRM_MODE_DISCONNECTED, skip init.\n",
connector_->id(),
drm_->connector_type_str(connector_->type()),
connector_->type_id());
return HWC2::Error::NoResources;
}
// RK3528 HDMI/TV互斥模式要求若HDMI已连接则 TV不注册
if(gIsRK3528() && connector_->type() == DRM_MODE_CONNECTOR_TV){
DrmConnector* primary = drm_->GetConnectorForDisplay(HWC_DISPLAY_PRIMARY);
if(primary && primary->state() == DRM_MODE_CONNECTED){
ret = drm_->ReleaseDpyRes(handle_);
if (ret) {
HWC2_ALOGE("Failed to ReleaseDpyRes for display=%d %d\n", display, ret);
return HWC2::Error::NoResources;
}
return HWC2::Error::None;
}
}
UpdateDisplayMode();
ret = drm_->BindDpyRes(handle_);
if (ret) {
HWC2_ALOGE("Failed to BindDpyRes for display=%d %d\n", display, ret);
return HWC2::Error::NoResources;
}
UpdateDisplayInfo();
ret = drm_->UpdateDisplayGamma(handle_);
if (ret) {
HWC2_ALOGE("Failed to UpdateDisplayGamma for display=%d %d\n", display, ret);
}
ret = drm_->UpdateDisplay3DLut(handle_);
if (ret) {
HWC2_ALOGE("Failed to UpdateDisplay3DLut for display=%d %d\n", display, ret);
}
crtc_ = drm_->GetCrtcForDisplay(display);
if (!crtc_) {
ALOGE("Failed to get crtc for display %d", display);
return HWC2::Error::BadDisplay;
}
// VRR
ret = connector_->UpdateModes();
if(ret){
ALOGE("Failed to update display modes %d", ret);
return HWC2::Error::BadDisplay;
}
bVrrDisplay_ = crtc_->is_vrr();
// 更新 hotplug 状态
connector_->update_hotplug_state();
planner_ = Planner::CreateInstance(drm_);
if (!planner_) {
ALOGE("Failed to create planner instance for composition");
return HWC2::Error::NoResources;
}
compositor_ = resource_manager_->GetDrmDisplayCompositor(crtc_);
ret = compositor_->Init(resource_manager_, display);
if (ret) {
ALOGE("Failed display compositor init for display %d (%d)", display, ret);
return HWC2::Error::NoResources;
}
// CropSpilt must to
if(connector_->isCropSpilt()){
std::unique_ptr<DrmDisplayComposition> composition = compositor_->CreateComposition();
composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_, handle_);
composition->SetDpmsMode(DRM_MODE_DPMS_ON);
ret = compositor_->QueueComposition(std::move(composition));
if (ret) {
HWC2_ALOGE("Failed to apply the dpms composition ret=%d", ret);
}
}
// soc_id
ctx_.soc_id = resource_manager_->getSocId();
// display_id
ctx_.display_id = display;
// display-type
ctx_.display_type = connector_->type();
// vop aclk
ctx_.aclk = crtc_->get_aclk();
// Baseparameter Info
ctx_.baseparameter_info = connector_->baseparameter_info();
// Standard Switch Resolution Mode
ctx_.bStandardSwitchResolution = hwc_get_bool_property("vendor.hwc.enable_display_configs","false");
HWC2::Error error = ChosePreferredConfig();
if(error != HWC2::Error::None){
ALOGE("Failed to chose prefererd config for display %d (%d)", display, error);
return error;
}
init_success_ = true;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::InitVirtual() {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 " type=%s",handle_,
(type_ == HWC2::DisplayType::Physical ? "Physical" : "Virtual"));
int display = static_cast<int>(handle_);
connector_ = drm_->GetWritebackConnectorForDisplay(0);
if (!connector_) {
ALOGE("Failed to get connector for display %d", display);
return HWC2::Error::BadDisplay;
}
init_success_ = true;
frame_no_ = 0;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::CheckStateAndReinit(bool clear_layer) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
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;
}
UpdateDisplayMode();
int ret = drm_->BindDpyRes(handle_);
if (ret) {
HWC2_ALOGE("Failed to BindDpyRes for display=%d %d\n", display, ret);
return HWC2::Error::NoResources;
}
UpdateDisplayInfo();
crtc_ = drm_->GetCrtcForDisplay(display);
if (!crtc_) {
ALOGE("Failed to get crtc for display %d", display);
return HWC2::Error::BadDisplay;
}
bVrrDisplay_ = crtc_->is_vrr();
ret = drm_->UpdateDisplayGamma(handle_);
if (ret) {
HWC2_ALOGE("Failed to UpdateDisplayGamma for display=%d %d\n", display, ret);
}
ret = drm_->UpdateDisplay3DLut(handle_);
if (ret) {
HWC2_ALOGE("Failed to UpdateDisplay3DLut for display=%d %d\n", display, ret);
}
// Reset HwcLayer resource
if(clear_layer && handle_ != HWC_DISPLAY_PRIMARY){
// Clear Layers
for(auto &map_layer : layers_){
map_layer.second.clear();
}
// Bug: #359894
// layers_ not clear may cause error log:
// "E hwc-platform-drm-generic: ImportBuffer fail fd=7,w=-1,h=-1,bo->format=AB24 ..."
layers_.clear();
// Clear Client Target Layer
client_layer_.clear();
}
compositor_ = resource_manager_->GetDrmDisplayCompositor(crtc_);
ret = compositor_->Init(resource_manager_, display);
if (ret) {
ALOGE("Failed display compositor init for display %d (%d)", display, ret);
return HWC2::Error::NoResources;
}
if(init_success_){
return HWC2::Error::None;
}
planner_ = Planner::CreateInstance(drm_);
if (!planner_) {
ALOGE("Failed to create planner instance for composition");
return HWC2::Error::NoResources;
}
// soc_id
ctx_.soc_id = resource_manager_->getSocId();
// display_id
ctx_.display_id = display;
// display-type
ctx_.display_type = connector_->type();
// vop aclk
ctx_.aclk = crtc_->get_aclk();
// Baseparameter Info
ctx_.baseparameter_info = connector_->baseparameter_info();
// Standard Switch Resolution Mode
ctx_.bStandardSwitchResolution = hwc_get_bool_property("vendor.hwc.enable_display_configs","false");
HWC2::Error error = ChosePreferredConfig();
if(error != HWC2::Error::None){
ALOGE("Failed to chose prefererd config for display %d (%d)", display, error);
return error;
}
init_success_ = true;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::CheckDisplayState(){
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
int display = static_cast<int>(handle_);
if(!init_success_){
ALOGE_IF(LogLevel(DBG_ERROR),"Display %d not init success! %s,line=%d", display,
__FUNCTION__, __LINE__);
return HWC2::Error::BadDisplay;
}
connector_ = drm_->GetConnectorForDisplay(display);
if (!connector_) {
ALOGE_IF(LogLevel(DBG_ERROR),"Failed to get connector for display %d, %s,line=%d",
display, __FUNCTION__, __LINE__);
return HWC2::Error::BadDisplay;
}
if(connector_->state() != DRM_MODE_CONNECTED){
ALOGE_IF(LogLevel(DBG_ERROR),"Connector %u type=%s, type_id=%d, state is DRM_MODE_DISCONNECTED, skip init, %s,line=%d\n",
connector_->id(),drm_->connector_type_str(connector_->type()),connector_->type_id(),
__FUNCTION__, __LINE__);
return HWC2::Error::NoResources;
}
crtc_ = drm_->GetCrtcForDisplay(display);
if (!crtc_) {
ALOGE_IF(LogLevel(DBG_ERROR),"Failed to get crtc for display %d, %s,line=%d", display,
__FUNCTION__, __LINE__);
return HWC2::Error::BadDisplay;
}
if(!layers_.size()){
ALOGE_IF(LogLevel(DBG_ERROR),"display %d layer size is %zu, %s,line=%d", display, layers_.size(),
__FUNCTION__, __LINE__);
return HWC2::Error::BadLayer;
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::ChosePreferredConfig() {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
// Fetch the number of modes from the display
uint32_t num_configs;
HWC2::Error err = GetDisplayConfigs(&num_configs, NULL);
if (err != HWC2::Error::None || !num_configs)
return err;
err = SetActiveConfig(connector_->active_mode().id());
return err;
}
HWC2::Error DrmHwcTwo::HwcDisplay::RegisterVsyncCallback(
hwc2_callback_data_t data, hwc2_function_pointer_t func) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
auto callback = std::make_shared<DrmVsyncCallback>(data, func);
vsync_worker_.RegisterCallback(std::move(callback));
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::RegisterInvalidateCallback(
hwc2_callback_data_t data, hwc2_function_pointer_t func) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
auto callback = std::make_shared<DrmInvalidateCallback>(data, func);
invalidate_worker_.RegisterCallback(std::move(callback));
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::UnregisterVsyncCallback() {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);;
vsync_worker_.RegisterCallback(NULL);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::UnregisterInvalidateCallback() {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
invalidate_worker_.RegisterCallback(NULL);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::AcceptDisplayChanges() {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_)
l.second.accept_type_change();
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::CreateLayer(hwc2_layer_t *layer) {
layers_.emplace(static_cast<hwc2_layer_t>(layer_idx_), HwcLayer(layer_idx_, drm_));
*layer = static_cast<hwc2_layer_t>(layer_idx_);
++layer_idx_;
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 ", layer-id=%" PRIu64,handle_,*layer);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::DestroyLayer(hwc2_layer_t layer) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 ", layer-id=%" PRIu64,handle_,layer);
auto map_layer = layers_.find(layer);
if (map_layer != layers_.end()){
map_layer->second.clear();
layers_.erase(layer);
return HWC2::Error::None;
}else{
return HWC2::Error::BadLayer;
}
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetActiveConfig(hwc2_config_t *config) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 ,handle_);
if(ctx_.bStandardSwitchResolution){
DrmMode const &mode = connector_->active_mode();
if (mode.id() == 0)
return HWC2::Error::BadConfig;
DrmMode const &best_mode = connector_->best_mode();
if(connector_->isHorizontalSpilt()){
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;
}
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 " config-id=%d" ,handle_,*config);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetChangedCompositionTypes(
uint32_t *num_elements, hwc2_layer_t *layers, int32_t *types) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
uint32_t num_changes = 0;
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) {
if (l.second.type_changed()) {
if (layers && num_changes < *num_elements)
layers[num_changes] = l.first;
if (types && num_changes < *num_elements)
types[num_changes] = static_cast<int32_t>(l.second.validated_type());
++num_changes;
}
}
if (!layers && !types)
*num_elements = num_changes;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetClientTargetSupport(uint32_t width,
uint32_t height,
int32_t /*format*/,
int32_t dataspace) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
std::pair<uint32_t, uint32_t> min = drm_->min_resolution();
std::pair<uint32_t, uint32_t> max = drm_->max_resolution();
if (width < min.first || height < min.second)
return HWC2::Error::Unsupported;
if (width > max.first || height > max.second)
return HWC2::Error::Unsupported;
if (dataspace != HAL_DATASPACE_UNKNOWN &&
dataspace != HAL_DATASPACE_STANDARD_UNSPECIFIED)
return HWC2::Error::Unsupported;
// TODO: Validate format can be handled by either GL or planes
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetColorModes(uint32_t *num_modes,
int32_t *modes) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
if (!modes)
*num_modes = 1;
if (modes)
*modes = HAL_COLOR_MODE_NATIVE;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayAttribute(hwc2_config_t config,
int32_t attribute_in,
int32_t *value) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
if(ctx_.bStandardSwitchResolution){
auto mode = std::find_if(sf_modes_.begin(),
sf_modes_.end(),
[config](DrmMode const &m) {
return m.id() == config;
});
if (mode == sf_modes_.end()) {
ALOGE("Could not find active mode for %d", config);
return HWC2::Error::BadConfig;
}
static const int32_t kUmPerInch = 25400;
uint32_t mm_width = connector_->mm_width();
uint32_t mm_height = connector_->mm_height();
auto attribute = static_cast<HWC2::Attribute>(attribute_in);
switch (attribute) {
case HWC2::Attribute::Width:
*value = mode->h_display();
break;
case HWC2::Attribute::Height:
*value = mode->v_display();
break;
case HWC2::Attribute::VsyncPeriod:
// in nanoseconds
*value = 1000 * 1000 * 1000 / mode->v_refresh();
break;
case HWC2::Attribute::DpiX:
// Dots per 1000 inches
*value = mm_width ? (mode->h_display() * kUmPerInch) / mm_width : -1;
break;
case HWC2::Attribute::DpiY:
// Dots per 1000 inches
*value = mm_height ? (mode->v_display() * kUmPerInch) / mm_height : -1;
break;
default:
*value = -1;
return HWC2::Error::BadConfig;
}
}else{
static const int32_t kUmPerInch = 25400;
uint32_t mm_width = connector_->mm_width();
uint32_t mm_height = connector_->mm_height();
int w = ctx_.framebuffer_width;
int h = ctx_.framebuffer_height;
int 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;
default:
*value = -1;
return HWC2::Error::BadConfig;
}
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayConfigs(uint32_t *num_configs,
hwc2_config_t *configs) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
// Since this callback is normally invoked twice (once to get the count, and
// once to populate configs), we don't really want to read the edid
// redundantly. Instead, only update the modes on the first invocation. While
// it's possible this will result in stale modes, it'll all come out in the
// wash when we try to set the active config later.
if (!configs) {
if (!connector_->ModesReady()) {
int ret = connector_->UpdateModes();
if(ret){
ALOGE("Failed to update display modes %d", ret);
return HWC2::Error::BadDisplay;
}
}
}
if(ctx_.bStandardSwitchResolution){
// Since the upper layers only look at vactive/hactive/refresh, height and
// width, it doesn't differentiate interlaced from progressive and other
// similar modes. Depending on the order of modes we return to SF, it could
// end up choosing a suboptimal configuration and dropping the preferred
// mode. To workaround this, don't offer interlaced modes to SF if there is
// at least one non-interlaced alternative and only offer a single WxH@R
// mode with at least the prefered mode from in DrmConnector::UpdateModes()
// TODO: Remove the following block of code until AOSP handles all modes
std::vector<DrmMode> sel_modes;
// Add the preferred mode first to be sure it's not dropped
auto preferred_mode = std::find_if(connector_->modes().begin(),
connector_->modes().end(), [&](DrmMode const &m) {
return m.id() ==
connector_->get_preferred_mode_id();
});
if (preferred_mode != connector_->modes().end())
sel_modes.push_back(*preferred_mode);
// Add the active mode if different from preferred mode
if (connector_->active_mode().id() != connector_->get_preferred_mode_id())
sel_modes.push_back(connector_->active_mode());
// Cycle over the modes and filter out "similar" modes, keeping only the
// first ones in the order given by DRM (from CEA ids and timings order)
for (const DrmMode &mode : connector_->modes()) {
// TODO: Remove this when 3D Attributes are in AOSP
if (mode.flags() & DRM_MODE_FLAG_3D_MASK)
continue;
// TODO: Remove this when the Interlaced attribute is in AOSP
if (mode.flags() & DRM_MODE_FLAG_INTERLACE) {
auto m = std::find_if(connector_->modes().begin(),
connector_->modes().end(),
[&mode](DrmMode const &m) {
return !(m.flags() & DRM_MODE_FLAG_INTERLACE) &&
m.h_display() == mode.h_display() &&
m.v_display() == mode.v_display();
});
if (m == connector_->modes().end())
sel_modes.push_back(mode);
continue;
}
// Search for a similar WxH@R mode in the filtered list and drop it if
// another mode with the same WxH@R has already been selected
// TODO: Remove this when AOSP handles duplicates modes
auto m = std::find_if(sel_modes.begin(), sel_modes.end(),
[&mode](DrmMode const &m) {
return m.h_display() == mode.h_display() &&
m.v_display() == mode.v_display() &&
m.v_refresh() == mode.v_refresh();
});
if (m == sel_modes.end())
sel_modes.push_back(mode);
}
auto num_modes = static_cast<uint32_t>(sel_modes.size());
sf_modes_.swap(sel_modes);
if (!configs) {
*num_configs = num_modes;
return HWC2::Error::None;
}
uint32_t idx = 0;
for (const DrmMode &mode : sel_modes) {
if (idx >= *num_configs)
break;
configs[idx++] = mode.id();
}
*num_configs = sf_modes_.size();
}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();
/*
* RK3588Limit to 4096x2160 if large than 2160p
* Other: Limit to 1920x1080 if large than 2160p
*/
if(isRK3588(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_->isHorizontalSpilt()){
ctx_.rel_xres = best_mode.h_display() / DRM_CONNECTOR_SPILT_RATIO;
ctx_.rel_yres = best_mode.v_display();
ctx_.framebuffer_width = ctx_.framebuffer_width / DRM_CONNECTOR_SPILT_RATIO;
if(handle_ >= DRM_CONNECTOR_SPILT_MODE_MASK){
ctx_.rel_xoffset = best_mode.h_display() / DRM_CONNECTOR_SPILT_RATIO;
ctx_.rel_yoffset = 0;//best_mode.v_display() / 2;
}
}else if(connector_->isCropSpilt()){
int32_t fb_w = 0, fb_h = 0;
connector_->getCropSpiltFb(&fb_w, &fb_h);
ctx_.framebuffer_width = fb_w;
ctx_.framebuffer_height = fb_h;
ctx_.rel_xres = best_mode.h_display();
ctx_.rel_yres = best_mode.v_display();
}else{
ctx_.rel_xres = best_mode.h_display();
ctx_.rel_yres = best_mode.v_display();
}
// 动态可变刷新率要求将刷新率上报
if(best_mode.v_refresh() > 0){
ctx_.vrefresh = best_mode.v_refresh();
}
// AFBC limit
if(handle_ == HWC_DISPLAY_PRIMARY){
bool disable_afbdc = false;
if(isRK356x(resource_manager_->getSocId())){
if(ctx_.framebuffer_width % 4 != 0){
disable_afbdc = true;
HWC2_ALOGI("RK356x primary framebuffer size %dx%d not support AFBC, to disable AFBC\n",
ctx_.framebuffer_width,ctx_.framebuffer_height);
}
}
if(hwc_get_int_property("ro.vendor.rk_sdk","0") == 0){
disable_afbdc = true;
HWC2_ALOGI("Maybe GSI SDK, to disable AFBC\n");
}
if(disable_afbdc){
property_set( "vendor.gralloc.no_afbc_for_fb_target_layer", "1");
}
}
const std::vector<int> vrr_mode = connector_->vrr_modes();
if(bVrrDisplay_ && vrr_mode.size() > 1){
if (!configs) {
*num_configs = vrr_mode.size();
return HWC2::Error::None;
}
*num_configs = vrr_mode.size();
for(int index = 0 ; index <= vrr_mode.size(); index++){
configs[index] = index;
}
}else{
if (!configs) {
*num_configs = 1;
return HWC2::Error::None;
}
*num_configs = 1;
configs[0] = 0;
}
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayName(uint32_t *size, char *name) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
std::ostringstream stream;
stream << "display-" << connector_->id();
std::string string = stream.str();
size_t length = string.length();
if (!name) {
*size = length;
return HWC2::Error::None;
}
*size = std::min<uint32_t>(static_cast<uint32_t>(length - 1), *size);
strncpy(name, string.c_str(), *size);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayRequests(int32_t *display_requests,
uint32_t *num_elements,
hwc2_layer_t *layers,
int32_t *layer_requests) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
uint32_t num_request = 0;
if(hwc_get_int_property("ro.vendor.rk_sdk","0") == 0){
HWC2_ALOGD_IF_INFO("Maybe GSI SDK, to disable AFBC\n");
if (!layers || !layer_requests){
*num_elements = num_request;
return HWC2::Error::None;
}else{
*display_requests = 0;
return HWC2::Error::None;
}
}
// RK3528 Mali 不支持AFBC
if(gIsRK3528()){
if (!layers || !layer_requests){
*num_elements = num_request;
return HWC2::Error::None;
}else{
*display_requests = 0;
return HWC2::Error::None;
}
}
// TODO: I think virtual display should request
// HWC2_DISPLAY_REQUEST_WRITE_CLIENT_TARGET_TO_OUTPUT here
uint32_t client_layer_id = false;
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) {
if (l.second.validated_type() == HWC2::Composition::Client) {
client_layer_id = l.first;
break;
}
}
if(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;
}
if (!layers || !layer_requests)
*num_elements = num_request;
else{
layers[0] = client_layer_id;
layer_requests[0] = 0;
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayType(int32_t *type) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
*type = static_cast<int32_t>(type_);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDozeSupport(int32_t *support) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
*support = 0;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetHdrCapabilities(
uint32_t *num_types, int32_t *types, float * max_luminance,
float *max_average_luminance, float * min_luminance) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
int display = static_cast<int>(handle_);
int HdrIndex = 0;
if (!connector_) {
ALOGE("%s:Failed to get connector for display %d line=%d", __FUNCTION__,display,__LINE__);
return HWC2::Error::None;
}
if(!connector_->ModesReady()){
int ret = connector_->UpdateModes();
if (ret) {
ALOGE("Failed to update display modes %d", ret);
return HWC2::Error::None;
}
}
const std::vector<DrmHdr> hdr_support_list = connector_->get_hdr_support_list();
if(types == NULL){
*num_types = hdr_support_list.size();
return HWC2::Error::None;
}
for(const DrmHdr &hdr_mode : hdr_support_list){
types[HdrIndex] = hdr_mode.drmHdrType;
*max_luminance = hdr_mode.outMaxLuminance;
*max_average_luminance = hdr_mode.outMaxAverageLuminance;
*min_luminance = hdr_mode.outMinLuminance;
HdrIndex++;
}
*num_types = hdr_support_list.size();
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetReleaseFences(uint32_t *num_elements,
hwc2_layer_t *layers,
int32_t *fences) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
uint32_t num_layers = 0;
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) {
++num_layers;
if (layers == NULL || fences == NULL) {
continue;
} else if (num_layers > *num_elements) {
ALOGW("Overflow num_elements %d/%d", num_layers, *num_elements);
return HWC2::Error::None;
}
layers[num_layers - 1] = l.first;
fences[num_layers - 1] = l.second.release_fence()->isValid() ? dup(l.second.release_fence()->getFd()) : -1;
if(LogLevel(DBG_VERBOSE))
HWC2_ALOGD_IF_VERBOSE("Check Layer %" PRIu64 " Release(%d) %s Info: size=%d act=%d signal=%d err=%d",
l.first,l.second.release_fence()->isValid(),l.second.release_fence()->getName().c_str(),
l.second.release_fence()->getSize(), l.second.release_fence()->getActiveCount(),
l.second.release_fence()->getSignaledCount(), l.second.release_fence()->getErrorCount());
// HWC2_ALOGD_IF_DEBUG("GetReleaseFences [%" PRIu64 "][%d]",layers[num_layers - 1],fences[num_layers - 1]);
// the new fence semantics for a frame n by returning the fence from frame n-1. For frame 0,
// the adapter returns NO_FENCE.
}
*num_elements = num_layers;
return HWC2::Error::None;
}
void DrmHwcTwo::HwcDisplay::AddFenceToRetireFence(int fd) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
char acBuf[32];
int retire_fence_fd = -1;
if (fd < 0){
// Collet all layer releaseFence
const sp<ReleaseFence> client_rf = client_layer_.back_release_fence();
if(client_rf->isValid()){
retire_fence_fd = dup(client_rf->getFd());
sprintf(acBuf,"RTD%" PRIu64 "-FN%d-%d", handle_, frame_no_, 0);
}
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &hwc2layer : layers_) {
if(hwc2layer.second.validated_type() != HWC2::Composition::Device)
continue;
// the new fence semantics for a frame n by returning the fence from frame n-1. For frame 0,
// the adapter returns NO_FENCE.
const sp<ReleaseFence> rf = hwc2layer.second.back_release_fence();
if (rf->isValid()){
// cur_retire_fence is null
if(retire_fence_fd > 0){
sprintf(acBuf,"RTD%" PRIu64 "-FN%d-%" PRIu64,handle_, frame_no_, hwc2layer.first);
int retire_fence_merge = rf->merge(retire_fence_fd, acBuf);
if(retire_fence_merge > 0){
close(retire_fence_fd);
retire_fence_fd = retire_fence_merge;
HWC2_ALOGD_IF_DEBUG("RetireFence(%d) %s frame = %d merge %s sucess!", retire_fence_fd, acBuf, frame_no_, rf->getName().c_str());
}else{
HWC2_ALOGE("RetireFence(%d) %s frame = %d merge %s faile!", retire_fence_fd, acBuf,frame_no_, rf->getName().c_str());
}
}else{
retire_fence_fd = dup(rf->getFd());
continue;
}
}
}
}else{
retire_fence_fd = fd;
}
d_retire_fence_.add(retire_fence_fd, acBuf);
return;
}
bool SortByZpos(const DrmHwcLayer &drmHwcLayer1, const DrmHwcLayer &drmHwcLayer2){
return drmHwcLayer1.iZpos_ < drmHwcLayer2.iZpos_;
}
HWC2::Error DrmHwcTwo::HwcDisplay::ModifyHwcLayerDisplayFrame(bool only_fb_scale) {
bool need_overscan_by_scale = false;
// RK3588 不支持Overscan
if(gIsRK3588()){
need_overscan_by_scale = true;
}
// 隔行扫描分辨率overscan效果比较差
if(connector_ &&
connector_->current_mode().id() > 0 &&
connector_->current_mode().interlaced() > 0){
need_overscan_by_scale = true;
}
// 使能 scale
if(need_overscan_by_scale){
for(auto &drmLayer : drm_hwc_layers_){
if(only_fb_scale && !drmLayer.bFbTarget_)
continue;
drmLayer.ModifyDisplayFrameForOverscan(&ctx_);
}
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::InitDrmHwcLayer() {
drm_hwc_layers_.clear();
// now that they're ordered by z, add them to the composition
for (auto &hwc2layer : layers_) {
drm_hwc_layers_.emplace_back();
DrmHwcLayer &drmHwclayer = drm_hwc_layers_.back();
hwc2layer.second.PopulateDrmLayer(hwc2layer.first, &drmHwclayer, &ctx_, frame_no_);
}
std::sort(drm_hwc_layers_.begin(),drm_hwc_layers_.end(),SortByZpos);
uint32_t client_id = 0;
drm_hwc_layers_.emplace_back();
DrmHwcLayer &client_target_layer = drm_hwc_layers_.back();
client_layer_.PopulateFB(client_id, &client_target_layer, &ctx_, frame_no_, true);
#ifdef USE_LIBPQ
if(handle_ == 0){
int ret = client_layer_.DoPq(true, &client_target_layer, &ctx_);
if(ret){
HWC2_ALOGE("ClientLayer DoPq fail, ret = %d", ret);
}
}
#endif
ALOGD_HWC2_DRM_LAYER_INFO((DBG_INFO),drm_hwc_layers_);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::ValidatePlanes() {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
int ret;
InitDrmHwcLayer();
// 需要修改 HwcLayer display frame 的情况列举:
// 1. RK3588 不支持Overscan
// 2. 隔行扫描分辨率 overscan 效果较差
// 3. RK3528 运营商版本需要提供视频显示区域修改接口
ModifyHwcLayerDisplayFrame(false);
std::vector<DrmHwcLayer *> layers;
layers.reserve(drm_hwc_layers_.size());
for(size_t i = 0; i < drm_hwc_layers_.size(); ++i){
layers.push_back(&drm_hwc_layers_[i]);
}
std::vector<PlaneGroup *> plane_groups;
DrmDevice *drm = crtc_->getDrmDevice();
plane_groups.clear();
std::vector<PlaneGroup *> all_plane_groups = drm->GetPlaneGroups();
for(auto &plane_group : all_plane_groups){
if(plane_group->acquire(1 << crtc_->pipe(), handle_)){
plane_groups.push_back(plane_group);
}
}
std::tie(ret,
composition_planes_) = planner_->TryHwcPolicy(layers, plane_groups, crtc_,
static_screen_opt_ ||
force_gles_ ||
connector_->isCropSpilt());
if (ret){
ALOGE("First, GLES policy fail ret=%d", ret);
return HWC2::Error::BadConfig;
}
for (auto &drm_hwc_layer : drm_hwc_layers_) {
if(drm_hwc_layer.bFbTarget_){
if(drm_hwc_layer.bAfbcd_)
client_layer_.EnableAfbc();
else
client_layer_.DisableAfbc();
continue;
}
if(drm_hwc_layer.bMatch_){
auto map_hwc2layer = layers_.find(drm_hwc_layer.uId_);
map_hwc2layer->second.set_validated_type(HWC2::Composition::Device);
if(drm_hwc_layer.bUseSr_){
ALOGD_IF(LogLevel(DBG_INFO),"[%.4" PRIu32 "]=Device-Sr : %s",drm_hwc_layer.uId_,drm_hwc_layer.sLayerName_.c_str());
}else if(drm_hwc_layer.bUseMemc_){
ALOGD_IF(LogLevel(DBG_INFO),"[%.4" PRIu32 "]=Device-Memc : %s",drm_hwc_layer.uId_,drm_hwc_layer.sLayerName_.c_str());
}else{
ALOGD_IF(LogLevel(DBG_INFO),"[%.4" PRIu32 "]=Device : %s",drm_hwc_layer.uId_,drm_hwc_layer.sLayerName_.c_str());
}
}else{
auto map_hwc2layer = layers_.find(drm_hwc_layer.uId_);
map_hwc2layer->second.set_validated_type(HWC2::Composition::Client);
ALOGD_IF(LogLevel(DBG_INFO),"[%.4" PRIu32 "]=Client : %s",drm_hwc_layer.uId_,drm_hwc_layer.sLayerName_.c_str());
}
}
#if (defined USE_LIBSR) || (defined USE_LIBSVEP_MEMC)
// Update svep state.
UpdateSvepState();
#endif
return HWC2::Error::None;
}
void DrmHwcTwo::HwcDisplay::UpdateSvepState() {
// 只有主屏可以开启SVEP模式其他屏幕不需要更新SVEP状态
if(handle_ > 0)
return;
bool exist_svep_layer = std::any_of(drm_hwc_layers_.begin(), drm_hwc_layers_.end(),
[](const auto& drm_hwc_layer) {
return drm_hwc_layer.bUseSr_ || drm_hwc_layer.bUseMemc_;
});
if(exist_svep_layer != bLastSvepState_){
// story last_svep_state
bLastSvepState_ = exist_svep_layer;
if(exist_svep_layer){
property_set("vendor.hwc.svep_state","1");
}else{
property_set("vendor.hwc.svep_state","0");
}
// update ddr state
int fd_ddr_state = open("/sys/class/devfreq/dmc/system_status", O_WRONLY);
if (fd_ddr_state < 0) {
HWC2_ALOGD_IF_DEBUG("failed to open /sys/class/devfreq/dmc/system_status ret =%d", fd_ddr_state);
}else{
if(exist_svep_layer){
// S 状态是专门提供给SVEP的场景变频, 进入SVEP场景变频
write(fd_ddr_state, "S", sizeof(char));
}else{
// s 状态是专门提供给SVEP的场景变频, 退出SVEP场景变频
write(fd_ddr_state, "s", sizeof(char));
}
close(fd_ddr_state);
}
}
return ;
}
hwc2_drm_display_t* DrmHwcTwo::HwcDisplay::GetDisplayCtxPtr(){
return &ctx_;
}
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.sf_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
// 如果是超分处理后的图层已经更新了GemHandle参数则不再获取GemHandle
if(drm_hwc_layer.bUseRga_)
continue;
// 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_){
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;
}
#ifdef USE_LIBPQ
if(handle_ == 0){
ret = client_layer_.DoPq(false, &drm_hwc_layer, &ctx_);
if(ret){
HWC2_ALOGE("ClientLayer DoPq fail, ret = %d", ret);
}
}
#endif
}
}
ModifyHwcLayerDisplayFrame(true);
}
// 所有匹配 DrmPlane 图层,请求 Import 获取 FbId
for (auto &drm_hwc_layer : drm_hwc_layers_) {
if(!use_client_layer && drm_hwc_layer.bFbTarget_)
continue;
// 若不是Overlay图层则不进行ImportBuffer
if(!drm_hwc_layer.bMatch_)
continue;
// SidebandStream 图层不需要执行 import 操作
if(drm_hwc_layer.bSidebandStreamLayer_)
continue;
// 执行ImportBuffer,获取FbId
ret = drm_hwc_layer.ImportBuffer(importer_.get());
if (ret) {
ALOGE("Failed to import layer, ret=%d", ret);
return ret;
}
}
return ret;
}
HWC2::Error DrmHwcTwo::HwcDisplay::CreateComposition() {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
int ret;
std::vector<DrmCompositionDisplayLayersMap> layers_map;
layers_map.emplace_back();
DrmCompositionDisplayLayersMap &map = layers_map.back();
map.display = static_cast<int>(handle_);
map.geometry_changed = true;
ret = ImportBuffers();
if(ret){
HWC2_ALOGE("Failed to ImportBuffers, ret=%d", ret);
return HWC2::Error::NoResources;
}
for (auto &drm_hwc_layer : drm_hwc_layers_) {
if(drm_hwc_layer.bMatch_)
map.layers.emplace_back(std::move(drm_hwc_layer));
}
std::unique_ptr<DrmDisplayComposition> composition = compositor_->CreateComposition();
composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_, handle_);
// TODO: Don't always assume geometry changed
ret = composition->SetLayers(map.layers.data(), map.layers.size(), true);
if (ret) {
ALOGE("Failed to set layers in the composition ret=%d", ret);
return HWC2::Error::BadLayer;
}
for(auto &composition_plane :composition_planes_)
ret = composition->AddPlaneComposition(std::move(composition_plane));
ret = composition->DisableUnusedPlanes();
if (ret) {
ALOGE("Failed to plan the composition ret=%d", ret);
return HWC2::Error::BadConfig;
}
// 利用 vendor.hwc.disable_releaseFence 属性强制关闭ReleaseFence主要用于调试
char value[PROPERTY_VALUE_MAX];
property_get("vendor.hwc.disable_releaseFence", value, "0");
if(atoi(value) == 0){
ret = composition->CreateAndAssignReleaseFences(sync_timeline_);
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_){
if(l.second.sf_type() == HWC2::Composition::Device){
sp<ReleaseFence> rf = composition->GetReleaseFence(l.first);
l.second.set_release_fence(rf);
}else{
l.second.set_release_fence(ReleaseFence::NO_FENCE);
}
}
sp<ReleaseFence> rf = composition->GetReleaseFence(0);
client_layer_.set_release_fence(rf);
AddFenceToRetireFence(composition->take_out_fence());
}
// 配置 HDR mode
composition->SetDisplayHdrMode(ctx_.hdr_mode, ctx_.dataspace);
// 配置丢帧模式
composition->SetDropMode(resource_manager_->IsCompositionDropMode());
ret = compositor_->QueueComposition(std::move(composition));
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::PresentVirtualDisplay(int32_t *retire_fence) {
ATRACE_CALL();
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64,handle_);
*retire_fence = -1;
// 若虚拟屏图层数为0则不做任何处理
if(!layers_.size()){
HWC2_ALOGD_IF_INFO("display %" PRIu64 " layer size is %zu", handle_, layers_.size());
return HWC2::Error::None;
}
if(bUseWriteBack_ &&
resource_manager_->isWBMode() &&
!resource_manager_->IsDisableHwVirtualDisplay()){
if(resource_manager_->isWBMode()){
const std::shared_ptr<LayerInfoCache>
bufferinfo = output_layer_.GetBufferInfo();
// 每个目标的Buffer都需要初始化YUV数据
if(!mHasResetBufferId_.count(bufferinfo->uBufferId_)){
rga_buffer_t src;
rga_buffer_t dst;
rga_buffer_t pat;
im_rect src_rect;
im_rect dst_rect;
im_rect pat_rect;
memset(&src, 0x0, sizeof(rga_buffer_t));
memset(&dst, 0x0, sizeof(rga_buffer_t));
memset(&pat, 0x0, sizeof(rga_buffer_t));
memset(&src_rect, 0x0, sizeof(im_rect));
memset(&dst_rect, 0x0, sizeof(im_rect));
memset(&pat_rect, 0x0, sizeof(im_rect));
std::shared_ptr<DrmBuffer> resetBuffer = resource_manager_->GetResetWBBuffer();
// Set src buffer info
src.fd = resetBuffer->GetFd();
src.width = resetBuffer->GetWidth();
src.height = resetBuffer->GetHeight();
src.wstride = resetBuffer->GetStride();
src.hstride = resetBuffer->GetHeightStride();
src.format = resetBuffer->GetFormat();
// Set src rect info
src_rect.x = 0;
src_rect.y = 0;
src_rect.width = resetBuffer->GetWidth();
src_rect.height = resetBuffer->GetHeight();
// Set dst buffer info
dst.fd = bufferinfo->iFd_;
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));
imOpt.core = IM_SCHEDULER_RGA3_CORE0 | IM_SCHEDULER_RGA3_CORE1;
// Call Im2d 格式转换
im_state = improcess(src, dst, pat, src_rect, dst_rect, pat_rect, 0, NULL, &imOpt, 0);
if(im_state == IM_STATUS_SUCCESS){
HWC2_ALOGD_IF_DEBUG("call im2d reset Success");
mHasResetBufferId_.insert(bufferinfo->uBufferId_);
}else{
HWC2_ALOGE("call im2d reset fail, ret=%d Error=%s", im_state, imStrError(im_state));
}
}
rga_buffer_t dst;
im_rect dst_rect;
memset(&dst, 0x00, sizeof(rga_buffer_t));
memset(&dst_rect, 0x00, sizeof(im_rect));
// Set dst buffer info
dst.fd = bufferinfo->iFd_;
dst.width = bufferinfo->iWidth_;
dst.height = bufferinfo->iHeight_;
dst.wstride = bufferinfo->iStride_;
dst.hstride = bufferinfo->iHeightStride_;
// 虚拟屏的格式通常为 HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED
// 由 Gralloc 决定具体格式,对应格式需要查询 uFourccFormat_ 才能确定
// 实际申请格式由于RGA不支持Fourcc格式所以垚做个转换。
switch (bufferinfo->uFourccFormat_) {
case DRM_FORMAT_BGR888:
dst.format = HAL_PIXEL_FORMAT_RGB_888;
break;
case DRM_FORMAT_ARGB8888:
dst.format = HAL_PIXEL_FORMAT_BGRA_8888;
break;
case DRM_FORMAT_XBGR8888:
// dst.format = HAL_PIXEL_FORMAT_RGBX_8888;
dst.format = HAL_PIXEL_FORMAT_BGRA_8888;
break;
case DRM_FORMAT_ABGR8888:
dst.format = HAL_PIXEL_FORMAT_RGBA_8888;
break;
case DRM_FORMAT_ABGR2101010:
dst.format = HAL_PIXEL_FORMAT_RGBA_1010102;
break;
//Fix color error in NenaMark2 and Taiji
case DRM_FORMAT_BGR565:
dst.format = HAL_PIXEL_FORMAT_RGB_565;
break;
case DRM_FORMAT_YVU420:
dst.format = HAL_PIXEL_FORMAT_YV12;
break;
case DRM_FORMAT_NV12:
dst.format = HAL_PIXEL_FORMAT_YCrCb_NV12;
break;
case DRM_FORMAT_NV12_10:
dst.format = HAL_PIXEL_FORMAT_YCrCb_NV12_10;
break;
default:
ALOGE("Cannot convert uFourccFormat_=%c%c%c%c to hal format, use default format nv12.",
bufferinfo->uFourccFormat_, bufferinfo->uFourccFormat_ >> 8,
bufferinfo->uFourccFormat_ >> 16, bufferinfo->uFourccFormat_ >> 24);
dst.format = HAL_PIXEL_FORMAT_YCrCb_NV12;
}
// 为了确保录屏数据宽高比一致,故需要对目标的区域做修正
DrmMode wbMode = resource_manager_->GetWBMode();
if(wbMode.width() != bufferinfo->iWidth_ ||
wbMode.height() != bufferinfo->iHeight_){
if((wbMode.width() * 1.0 / bufferinfo->iWidth_) >
(wbMode.height() * 1.0 / bufferinfo->iHeight_)){
dst_rect.width = bufferinfo->iWidth_;
dst_rect.height = (int)(bufferinfo->iWidth_ * wbMode.height() / (wbMode.width() * 1.0));
dst_rect.x = 0;
dst_rect.y = (bufferinfo->iHeight_ - dst_rect.height) / 2;
}else{
dst_rect.width = (int)((bufferinfo->iHeight_) * wbMode.width() / (wbMode.height() * 1.0));
dst_rect.height = bufferinfo->iHeight_;
dst_rect.x = (bufferinfo->iWidth_ - dst_rect.width) / 2;
dst_rect.y = 0;
}
}else{
dst_rect.x = 0;
dst_rect.y = 0;
dst_rect.width = bufferinfo->iWidth_;
dst_rect.height = bufferinfo->iHeight_;
}
dst_rect.x = ALIGN_DOWN( dst_rect.x, 2);
dst_rect.y = ALIGN_DOWN( dst_rect.y, 2);
dst_rect.width = ALIGN_DOWN( dst_rect.width, 2);
dst_rect.height = ALIGN_DOWN( dst_rect.height, 2);
if(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 == (bufferinfo->uModifier_ & AFBC_FORMAT_MOD_BLOCK_SIZE_16x16)){
dst.rd_mode = IM_FBC_MODE;
}
int ret = resource_manager_->OutputWBBuffer((int)handle_, dst, dst_rect, retire_fence, &wb_frame_no_);
if(ret){
HWC2_ALOGE("OutputWBBuffer fail!");
}
// 添加调试接口抓打印传递给SurfaceFlinger的 Buffer
char value[PROPERTY_VALUE_MAX];
property_get("debug.wb.dump", value, "0");
if(atoi(value) > 0) {
output_layer_.DumpData();
}
}
}else{
if(client_layer_.acquire_fence() != NULL){
if(client_layer_.acquire_fence()->wait(1500)){
HWC2_ALOGE("WB client layer wait acquirefence 1500ms timeout!");
}
}
}
++frame_no_;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::PresentDisplay(int32_t *retire_fence) {
ATRACE_CALL();
if(isVirtual()){
return PresentVirtualDisplay(retire_fence);;
}
int32_t merge_retire_fence = -1;
// 拼接主屏需要遍历其他拼接子屏幕
if(connector_->IsSpiltPrimary()){
DoMirrorDisplay(&merge_retire_fence);
}
if(!init_success_){
HWC2_ALOGD_IF_ERR("init_success_=%d skip.",init_success_);
*retire_fence = merge_retire_fence;
return HWC2::Error::None;
}
DumpAllLayerData();
HWC2::Error ret;
ret = CheckDisplayState();
if(ret != HWC2::Error::None ||
!validate_success_ ||
connector_->type() == DRM_MODE_CONNECTOR_VIRTUAL){
ALOGE_IF(LogLevel(DBG_ERROR),"Check display %" PRIu64 " state fail %s, %s,line=%d", handle_,
validate_success_? "" : "or validate fail.",__FUNCTION__, __LINE__);
if(ret == HWC2::Error::BadLayer){
ClearDisplay();
}
}else{
ret = CreateComposition();
if (ret == HWC2::Error::BadLayer) {
// Can we really have no client or device layers?
*retire_fence = merge_retire_fence;
return HWC2::Error::None;
}
}
if(merge_retire_fence > 0){
if(d_retire_fence_.get()->isValid()){
char acBuf[32];
sprintf(acBuf,"RTD%" PRIu64 "M-FN%d-%d", handle_, frame_no_, 0);
sp<ReleaseFence> rt = sp<ReleaseFence>(new ReleaseFence(merge_retire_fence, acBuf));
*retire_fence = rt->merge(d_retire_fence_.get()->getFd(), acBuf);
}else{
*retire_fence = merge_retire_fence;
}
}else{
// The retire fence returned here is for the last frame, so return it and
// promote the next retire fence
*retire_fence = d_retire_fence_.get()->isValid() ? dup(d_retire_fence_.get()->getFd()) : -1;
if(LogLevel(DBG_DEBUG)){
HWC2_ALOGD_IF_DEBUG("Return RetireFence(%d) %s frame = %d Info: size=%d act=%d signal=%d err=%d",
d_retire_fence_.get()->isValid(),
d_retire_fence_.get()->getName().c_str(), frame_no_,
d_retire_fence_.get()->getSize(),d_retire_fence_.get()->getActiveCount(),
d_retire_fence_.get()->getSignaledCount(),d_retire_fence_.get()->getErrorCount());
}
}
++frame_no_;
UpdateTimerState(!static_screen_opt_);
if(IsActiveModeChange())
drm_->FlipResolutionSwitchHandler((int)handle_);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetActiveConfig(hwc2_config_t config) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 " config=%d",handle_,config);
if(ctx_.bStandardSwitchResolution){
auto mode = std::find_if(sf_modes_.begin(),
sf_modes_.end(),
[config](DrmMode const &m) {
return m.id() == config;
});
if (mode == sf_modes_.end()) {
ALOGE("Could not find active mode for %d", config);
return HWC2::Error::BadConfig;
}
// std::unique_ptr<DrmDisplayComposition> composition = compositor_
// .CreateComposition();
// composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_);
// int ret = composition->SetDisplayMode(*mode);
// ret = compositor_.QueueComposition(std::move(composition));
// if (ret) {
// ALOGE("Failed to queue dpms composition on %d", ret);
// return HWC2::Error::BadConfig;
// }
connector_->set_best_mode(*mode);
connector_->set_current_mode(*mode);
ctx_.rel_xres = (*mode).h_display();
ctx_.rel_yres = (*mode).v_display();
// Setup the client layer's dimensions
hwc_rect_t display_frame = {.left = 0,
.top = 0,
.right = static_cast<int>(mode->h_display()),
.bottom = static_cast<int>(mode->v_display())};
client_layer_.SetLayerDisplayFrame(display_frame);
hwc_frect_t source_crop = {.left = 0.0f,
.top = 0.0f,
.right = mode->h_display() + 0.0f,
.bottom = mode->v_display() + 0.0f};
client_layer_.SetLayerSourceCrop(source_crop);
drm_->UpdateDisplayMode(handle_);
// SetDisplayModeInfo cost 2.5ms - 5ms, a A few cases cost 10ms - 20ms
connector_->SetDisplayModeInfo(handle_);
}else{
if(connector_->isCropSpilt()){
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);
}
// VRR
UpdateRefreshRate(config);
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::UpdateRefreshRate(hwc2_config_t config) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 " config=%d", handle_, config);
if(!bVrrDisplay_)
return HWC2::Error::None;
const std::vector<int> vrr_mode = connector_->vrr_modes();
if(config < vrr_mode.size()){
int refresh_rate = vrr_mode[config];
int ret = drm_->UpdateVrrRefreshRate(handle_, refresh_rate);
if(ret){
HWC2_ALOGE("display=%" PRIu64 " config=%d refresh_rate=%d UpdateVrrRefreshRate fail!",
handle_, config, refresh_rate);
return HWC2::Error::BadConfig;
}
}
return HWC2::Error::BadConfig;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetClientTarget(buffer_handle_t target,
int32_t acquire_fence,
int32_t dataspace,
hwc_region_t /*damage*/) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 ", Buffer=%p, acq_fence=%d, dataspace=%x",
handle_,target,acquire_fence,dataspace);
// 动态切换刷新率过程中SurfaceFlinger会出现 SetClientTarget target=null的情况
// 为了避免错误日志打印,故暂时对这种情况进行规避;
if(target == NULL){
HWC2_ALOGW("Buffer is NULL, skip SetClientTarget");
return HWC2::Error::None;
}
client_layer_.CacheBufferInfo(target);
client_layer_.set_acquire_fence(sp<AcquireFence>(new AcquireFence(acquire_fence)));
client_layer_.SetLayerDataspace(dataspace);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetColorMode(int32_t mode) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 ", mode=%x",handle_,mode);
if (mode != HAL_COLOR_MODE_NATIVE)
return HWC2::Error::BadParameter;
color_mode_ = mode;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetColorTransform(const float *matrix,
int32_t hint) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 ", hint=%x",handle_,hint);
// TODO: Force client composition if we get this
// hint definition from android_color_transform_t in system/core/libsystem/include/system/graphics-base-v1.0.h
force_gles_ = (hint > 0);
unsupported(__func__, matrix, hint);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetOutputBuffer(buffer_handle_t buffer,
int32_t release_fence) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 ", buffer=%p, rel_fence=%d",handle_,buffer,release_fence);
// TODO: Need virtual display support
output_layer_.set_output_buffer(buffer);
if(release_fence > 0){
/* release_fence will be close in this file hardware/interfaces/
* graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcHal.h+319
* int32_t err = mDispatch.setOutputBuffer(mDevice, display, buffer, releaseFence);
* // unlike in setClientTarget, releaseFence is owned by us
* if (err == HWC2_ERROR_NONE && releaseFence >= 0) {
* close(releaseFence);
* }
*/
int32_t new_release_fence = dup(release_fence);
String8 output;
output.appendFormat("%s-F%" PRIu32 "-Fd%d",__FUNCTION__,frame_no_,new_release_fence);
sp<ReleaseFence> release = sp<ReleaseFence>(new ReleaseFence(new_release_fence, output.c_str()));
output_layer_.set_release_fence(release);
HWC2_ALOGD_IF_DEBUG("Release=%d(%d) %s Info: size=%d act=%d signal=%d err=%d",
release->getFd(),release->isValid(),release->getName().c_str(),
release->getSize(), release->getActiveCount(),
release->getSignaledCount(), release->getErrorCount());
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SyncPowerMode() {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 " bNeedSyncPMState_=%d",handle_, bNeedSyncPMState_);
if(!init_success_){
HWC2_ALOGE("init_success_=%d skip.",init_success_);
return HWC2::Error::BadDisplay;
}
if(!bNeedSyncPMState_){
HWC2_ALOGI("bNeedSyncPMState_=%d don't need to sync PowerMode state.",bNeedSyncPMState_);
return HWC2::Error::None;
}
HWC2::Error error = SetPowerMode((int32_t)mPowerMode_);
if(error != HWC2::Error::None){
HWC2_ALOGE("SetPowerMode fail %d", error);
return error;
}
bNeedSyncPMState_ = false;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetPowerMode(int32_t mode_in) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 ", mode_in=%d",handle_,mode_in);
// 拼接屏幕主屏需要更新拼接副屏的电源状态
if(connector_->IsSpiltPrimary()){
for (auto &conn : drm_->connectors()) {
if(!conn->isCropSpilt()){
continue;
}
int display_id = conn->display();
if(!conn->IsSpiltPrimary()){
auto &display = resource_manager_->GetHwc2()->displays_.at(display_id);
display.SetPowerMode(mode_in);
}
}
}
uint64_t dpms_value = 0;
mPowerMode_ = static_cast<HWC2::PowerMode>(mode_in);
switch (mPowerMode_) {
case HWC2::PowerMode::Off:
dpms_value = DRM_MODE_DPMS_OFF;
break;
case HWC2::PowerMode::On:
dpms_value = DRM_MODE_DPMS_ON;
break;
case HWC2::PowerMode::Doze:
case HWC2::PowerMode::DozeSuspend:
ALOGI("Power mode %d is unsupported\n", mPowerMode_);
return HWC2::Error::Unsupported;
default:
ALOGI("Power mode %d is BadParameter\n", mPowerMode_);
return HWC2::Error::BadParameter;
};
if(!init_success_){
bNeedSyncPMState_ = true;
HWC2_ALOGE("init_success_=%d skip.",init_success_);
return HWC2::Error::BadDisplay;
}
std::unique_ptr<DrmDisplayComposition> composition = compositor_->CreateComposition();
composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_, handle_);
composition->SetDpmsMode(dpms_value);
int ret = compositor_->QueueComposition(std::move(composition));
if (ret) {
ALOGE("Failed to apply the dpms composition ret=%d", ret);
return HWC2::Error::BadParameter;
}
int fb0_fd = resource_manager_->getFb0Fd();
if(fb0_fd<=0)
ALOGE_IF(LogLevel(DBG_ERROR),"%s,line=%d fb0_fd = %d can't operation /dev/graphics/fb0 node.",
__FUNCTION__,__LINE__,fb0_fd);
int fb_blank = 0;
if(dpms_value == DRM_MODE_DPMS_OFF)
fb_blank = FB_BLANK_POWERDOWN;
else if(dpms_value == DRM_MODE_DPMS_ON)
fb_blank = FB_BLANK_UNBLANK;
else
ALOGE("dpmsValue is invalid value= %" PRIu64 "",dpms_value);
if(fb_blank != fb_blanked && fb0_fd > 0){
int err = ioctl(fb0_fd, FBIOBLANK, fb_blank);
ALOGD_IF(LogLevel(DBG_DEBUG),"%s Notice fb_blank to fb=%d", __FUNCTION__, fb_blank);
if (err < 0) {
ALOGE("fb_blank ioctl failed(%d) display=%" PRIu64 ",fb_blank=%d,dpmsValue=%" PRIu64 "",
errno,handle_,fb_blank,dpms_value);
}
}
fb_blanked = fb_blank;
if(dpms_value == DRM_MODE_DPMS_OFF){
ClearDisplay();
ret = drm_->ReleaseDpyRes(handle_, DmcuReleaseByPowerMode);
if (ret) {
HWC2_ALOGE("Failed to ReleaseDpyRes for display=%" PRIu64 " %d\n", handle_, ret);
}
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_->ReleaseDpyRes(extend_display_id);
if (ret) {
HWC2_ALOGE("Failed to ReleaseDpyRes for display=%d %d\n", extend_display_id, ret);
}
}
}
}else{
if(connector_->hotplug()){
ret = connector_->UpdateModes();
if (ret) {
HWC2_ALOGE("Failed to UpdateModes for display=%" PRIu64 " ret=%d\n", handle_, ret);
}
}
HoplugEventTmeline();
ret = UpdateDisplayMode();
if (ret) {
HWC2_ALOGE("Failed to UpdateDisplayMode for display=%" PRIu64 " ret=%d\n", handle_, ret);
}
ret = drm_->BindDpyRes(handle_);
if (ret) {
HWC2_ALOGE("Failed to BindDpyRes for display=%" PRIu64 " ret=%d\n", handle_, ret);
}
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_->BindDpyRes(extend_display_id);
if (ret) {
HWC2_ALOGE("Failed to BindDpyRes for display=%d ret=%d\n", extend_display_id, ret);
}
}
}
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::SetVsyncEnabled(int32_t enabled) {
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 ", enable=%d",handle_,enabled);
vsync_worker_.VSyncControl(HWC2_VSYNC_ENABLE == enabled);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::ValidateVirtualDisplay(uint32_t *num_types,
uint32_t *num_requests) {
if(LogLevel(DBG_INFO)){
DumpDisplayLayersInfo();
}
if(!layers_.size()){
HWC2_ALOGI("display %" PRIu64 " layer size is %zu, %s,line=%d", handle_, layers_.size(),
__FUNCTION__, __LINE__);
return HWC2::Error::None;
}
// 强制设置系统刷新为30帧
InvalidateControl(30,-1);
bUseWriteBack_ = true;
// 提供仅 Sideband 模式下开启 hw Virtual Display 功能接口
char value[PROPERTY_VALUE_MAX];
property_get("vendor.hwc.only_sideband_use_wb", value, "0");
if(atoi(value) > 0){
bUseWriteBack_ = false;
bool exist_sideband_stream = false;
// 只有存在 SidebandStream 的录屏才会使用 WriteBack;
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) {
DrmHwcTwo::HwcLayer &layer = l.second;
if(layer.sf_type() == HWC2::Composition::Sideband){
exist_sideband_stream = true;
}
}
if(exist_sideband_stream){
bUseWriteBack_ = true;
}
}
HWC2_ALOGI("frame_no_ = %d", frame_no_);
// 获取 WriteBack id
int WBDisplayId = resource_manager_->GetWBDisplay();
// 检查是否正确使能 Hw Virtual Display 功能
if(WBDisplayId >= 0 &&
resource_manager_->isWBMode() &&
!resource_manager_->IsDisableHwVirtualDisplay()){
DrmConnector *connector = drm_->GetConnectorForDisplay(WBDisplayId);
if (!connector) {
HWC2_ALOGD_IF_DEBUG("Failed to get WB connector for display=%" PRIu64 " wb-display %d frame_no=%d", handle_, WBDisplayId, frame_no_);
bUseWriteBack_ = false;
}else{
if(connector->state() != DRM_MODE_CONNECTED){
HWC2_ALOGD_IF_DEBUG("WB Connector %u type=%s, type_id=%d, state is DRM_MODE_DISCONNECTED,"
" skip init. display=%" PRIu64 " wb-display %d frame_no=%d",
connector->id(),drm_->connector_type_str(connector->type()),connector->type_id(),
handle_, WBDisplayId, frame_no_);;
bUseWriteBack_ = false;
}
DrmCrtc *crtc = drm_->GetCrtcForDisplay(WBDisplayId);
if (!crtc) {
HWC2_ALOGD_IF_DEBUG("Failed to get crtc for display=%" PRIu64 " wb-display %d frame_no=%d", handle_, WBDisplayId, frame_no_);
bUseWriteBack_ = false;
}
if(resource_manager_->GetFinishWBBufferSize() == 0){
HWC2_ALOGD_IF_DEBUG("WB buffer not ready, display=%" PRIu64 " wb-display %d frame_no=%d", handle_, WBDisplayId, frame_no_);
bUseWriteBack_ = false;
}
}
}else{
bUseWriteBack_ = false;
HWC2_ALOGD_IF_DEBUG("WB display %d is invalid, disable HW VDS.", WBDisplayId);
}
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) {
DrmHwcTwo::HwcLayer &layer = l.second;
if(bUseWriteBack_){
layer.set_validated_type(HWC2::Composition::Device);
}else{
layer.set_validated_type(HWC2::Composition::Client);
}
++*num_types;
}
*num_requests = 0;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::ValidateDisplay(uint32_t *num_types,
uint32_t *num_requests) {
ATRACE_CALL();
HWC2_ALOGD_IF_VERBOSE("display-id=%" PRIu64 ,handle_);
// 虚拟屏
if(isVirtual()){
return ValidateVirtualDisplay(num_types, num_requests);;
}
if(LogLevel(DBG_DEBUG))
DumpDisplayLayersInfo();
if(!init_success_){
HWC2_ALOGD_IF_ERR("init_success_=%d skip.",init_success_);
if(connector_->IsSpiltPrimary()){
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_){
l.second.set_validated_type(HWC2::Composition::Client);
}
}else{
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_){
l.second.set_validated_type(l.second.sf_type());
}
}
return HWC2::Error::None;
}
// Enable/disable debug log
UpdateLogLevel();
UpdateBCSH();
UpdateHdmiOutputFormat();
UpdateOverscan();
if(!ctx_.bStandardSwitchResolution){
UpdateDisplayMode();
drm_->UpdateDisplayMode(handle_);
if(isRK3566(resource_manager_->getSocId())){
int display_id = drm_->GetCommitMirrorDisplayId();
drm_->UpdateDisplayMode(display_id);
}
UpdateDisplayInfo();
}
// 虚拟屏幕
if(connector_->type() == DRM_MODE_CONNECTOR_VIRTUAL){
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_){
l.second.set_validated_type(l.second.sf_type());
}
return HWC2::Error::None;
}
// update sideband mode
UpdateSidebandMode();
*num_types = 0;
*num_requests = 0;
HWC2::Error ret;
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_){
if(gIsRK3528()){
l.second.set_validated_type(HWC2::Composition::Device);
}else{
l.second.set_validated_type(HWC2::Composition::Client);
}
}
ret = CheckDisplayState();
if(ret != HWC2::Error::None){
ALOGE_IF(LogLevel(DBG_ERROR),"Check display %" PRIu64 " state fail, %s,line=%d", handle_,
__FUNCTION__, __LINE__);
composition_planes_.clear();
validate_success_ = false;
return HWC2::Error::None;
}
ret = ValidatePlanes();
if (ret != HWC2::Error::None){
ALOGE("%s fail , ret = %d,line = %d",__FUNCTION__,ret,__LINE__);
validate_success_ = false;
return HWC2::Error::BadConfig;
}
SwitchHdrMode();
// Static screen opt
UpdateTimerEnable();
// Enable Self-refresh mode.
SelfRefreshEnable();
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) {
DrmHwcTwo::HwcLayer &layer = l.second;
// We can only handle layers of Device type, send everything else to SF
if (layer.validated_type() != HWC2::Composition::Device) {
layer.set_validated_type(HWC2::Composition::Client);
++*num_types;
}
}
if(!client_layer_.isAfbc()){
++(*num_requests);
}
validate_success_ = true;
return *num_types ? HWC2::Error::HasChanges : HWC2::Error::None;
}
#ifdef ANDROID_S
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayConnectionType(uint32_t *outType) {
if (connector_->internal())
*outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::Internal);
else if (connector_->external())
*outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::External);
else
return HWC2::Error::BadConfig;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayVsyncPeriod(
hwc2_vsync_period_t *outVsyncPeriod /* ns */) {
supported(__func__);
DrmMode const &mode = connector_->active_mode();
if (mode.id() == 0)
return HWC2::Error::BadConfig;
*outVsyncPeriod = 1E9 / mode.v_refresh();
return HWC2::Error::None;
}
#endif //ANDROID_S
HWC2::Error DrmHwcTwo::HwcLayer::SetCursorPosition(int32_t x, int32_t y) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d"", x=%d, y=%d" ,id_,x,y);
mCurrentState.cursor_x_ = x;
mCurrentState.cursor_y_ = y;
return HWC2::Error::None;
}
int DrmHwcTwo::HwcDisplay::DumpDisplayInfo(String8 &output){
output.appendFormat(" DisplayId=%" PRIu64 ", Connector %u, Type = %s-%u, Connector state = %s\n",handle_,
connector_->id(),
isVirtual() ? "Virtual" : drm_->connector_type_str(connector_->type()),
connector_->type_id(),
connector_->state() == DRM_MODE_CONNECTED ? "DRM_MODE_CONNECTED" : "DRM_MODE_DISCONNECTED");
if(connector_->state() != DRM_MODE_CONNECTED)
return -1;
DrmMode const &active_mode = connector_->active_mode();
if (active_mode.id() == 0){
return -1;
}
output.appendFormat(" NumHwLayers=%zu, activeModeId=%u, %s%c%.2f, colorMode = %d, bStandardSwitchResolution=%d\n",
get_layers().size(),
active_mode.id(), active_mode.name().c_str(),'p' ,active_mode.v_refresh(),
color_mode_,ctx_.bStandardSwitchResolution);
if(sf_modes_.size() > 0){
uint32_t idx = 0;
for (const DrmMode &mode : sf_modes_) {
if(active_mode.id() == mode.id())
output.appendFormat(" Config[%2u] = %s%c%.2f mode-id=%d (active)\n",idx, mode.name().c_str(), 'p' , mode.v_refresh(),mode.id());
else
output.appendFormat(" Config[%2u] = %s%c%.2f mode-id=%d \n",idx, mode.name().c_str(), 'p' , mode.v_refresh(),mode.id());
idx++;
}
}
output.append(
"------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n"
" id | z | sf-type | hwc-type | handle | transform | blnd | source crop (l,t,r,b) | frame | dataspace | mFps | name \n"
"------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n");
for (uint32_t z_order = 0; z_order <= layers_.size(); z_order++) {
for (auto &map_layer : layers_) {
HwcLayer &layer = map_layer.second;
if(layer.z_order() == z_order){
layer.DumpLayerInfo(output);
break;
}
}
}
output.append("------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n");
output.append("DrmHwcLayer Dump:\n");
for(auto &drmHwcLayer : drm_hwc_layers_)
drmHwcLayer.DumpInfo(output);
return 0;
}
int DrmHwcTwo::HwcDisplay::DumpDisplayLayersInfo(String8 &output){
output.appendFormat(" DisplayId=%" PRIu64 ", Connector %u, Type = %s-%u, Connector state = %s , frame_no = %d\n",handle_,
connector_->id(),
isVirtual() ? "Virtual" : drm_->connector_type_str(connector_->type()),
connector_->type_id(),
connector_->state() == DRM_MODE_CONNECTED ? "DRM_MODE_CONNECTED" : "DRM_MODE_DISCONNECTED",
frame_no_);
output.append(
"------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n"
" id | z | req-type | fina-type | handle | transform | blnd | source crop (l,t,r,b) | frame | dataspace | mFps | name \n"
"------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n");
for (uint32_t z_order = 0; z_order <= layers_.size(); z_order++) {
for (auto &map_layer : layers_) {
HwcLayer &layer = map_layer.second;
if(layer.z_order() == z_order){
layer.DumpLayerInfo(output);
break;
}
}
}
output.append("------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n");
return 0;
}
int DrmHwcTwo::HwcDisplay::DumpDisplayLayersInfo(){
String8 output;
output.appendFormat(" DisplayId=%" PRIu64 ", Connector %u, Type = %s-%u, Connector state = %s , frame_no = %d\n",handle_,
connector_->id(),
isVirtual() ? "Virtual" : drm_->connector_type_str(connector_->type()),
connector_->type_id(),
connector_->state() == DRM_MODE_CONNECTED ? "DRM_MODE_CONNECTED" : "DRM_MODE_DISCONNECTED",
frame_no_);
output.append(
"------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n"
" id | z | sf-type | hwc-type | handle | transform | blnd | source crop (l,t,r,b) | frame | dataspace | mFps | name \n"
"------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n");
ALOGD("%s",output.string());
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.string());
break;
}
}
}
output.clear();
output.append("------+-----+-----------+-----------+--------------------+-------------+------------+--------------------------------+------------------------+------------+--------+------------\n");
ALOGD("%s",output.string());
return 0;
}
int DrmHwcTwo::HwcDisplay::DumpAllLayerData(){
char pro_value[PROPERTY_VALUE_MAX];
property_get( PROPERTY_TYPE ".dump",pro_value,0);
if(!strcmp(pro_value,"true")){
for (auto &map_layer : layers_) {
HwcLayer &layer = map_layer.second;
layer.DumpData();
}
if(client_layer_.buffer() != NULL)
client_layer_.DumpData();
for(auto &drm_layer : drm_hwc_layers_){
if(drm_layer.bUseSr_ && drm_layer.pSrBuffer_){
drm_layer.pSrBuffer_->DumpData();
}
}
for(auto &drm_layer : drm_hwc_layers_){
if(drm_layer.bUseRga_ && drm_layer.pRgaBuffer_){
drm_layer.pRgaBuffer_->DumpData();
}
}
}
return 0;
}
int DrmHwcTwo::HwcDisplay::HoplugEventTmeline(){
ctx_.hotplug_timeline++;
return 0;
}
int DrmHwcTwo::HwcDisplay::UpdateDisplayMode(){
if(!ctx_.bStandardSwitchResolution){
int timeline;
int display_id = static_cast<int>(handle_);
timeline = property_get_int32("vendor.display.timeline", -1);
if(timeline && timeline == ctx_.display_timeline && ctx_.hotplug_timeline == drm_->timeline())
return 0;
ctx_.display_timeline = timeline;
ctx_.hotplug_timeline = drm_->timeline();
int ret = connector_->UpdateDisplayMode(display_id, timeline);
if(!ret){
const DrmMode best_mode = connector_->best_mode();
connector_->set_current_mode(best_mode);
// will change display resolution, to clear all display.
if(!(connector_->current_mode() == connector_->active_mode())){
ClearDisplay();
// 标识 Display mode 发生改变
ActiveModeChange(true);
}
}
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->UpdateDisplayMode(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::UpdateDisplayInfo(){
if(!ctx_.bStandardSwitchResolution){
const DrmMode active_mode = connector_->active_mode();
if(connector_->isHorizontalSpilt()){
ctx_.rel_xres = active_mode.h_display() / DRM_CONNECTOR_SPILT_RATIO;
ctx_.rel_yres = active_mode.v_display();
if(handle_ >= DRM_CONNECTOR_SPILT_MODE_MASK){
ctx_.rel_xoffset = active_mode.h_display() / DRM_CONNECTOR_SPILT_RATIO;
ctx_.rel_yoffset = 0;//best_mode.v_display() / 2;
}
}else if(connector_->isCropSpilt()){
ctx_.rel_xres = active_mode.h_display();
ctx_.rel_yres = active_mode.v_display();
}else{
ctx_.rel_xres = active_mode.h_display();
ctx_.rel_yres = active_mode.v_display();
}
ctx_.dclk = active_mode.clock();
}
return 0;
}
int DrmHwcTwo::HwcDisplay::UpdateOverscan(){
connector_->UpdateOverscan(handle_, ctx_.overscan_value);
return 0;
}
int DrmHwcTwo::HwcDisplay::UpdateHdmiOutputFormat(){
int timeline = 0;
timeline = property_get_int32( "vendor.display.timeline", -1);
/*
* force update propetry when timeline is zero or not exist.
*/
if (timeline && timeline == ctx_.display_timeline && ctx_.hotplug_timeline == drm_->timeline())
return 0;
connector_->UpdateOutputFormat(handle_, timeline);
if(isRK3566(resource_manager_->getSocId())){
bool mirror_mode = true;
int display_id = drm_->GetCommitMirrorDisplayId();
DrmConnector *conn_mirror = drm_->GetConnectorForDisplay(display_id);
if(!conn_mirror || conn_mirror->state() != DRM_MODE_CONNECTED){
ALOGI_IF(LogLevel(DBG_DEBUG),"%s,line=%d disable bCommitMirrorMode",__FUNCTION__,__LINE__);
mirror_mode = false;
}
if(mirror_mode){
conn_mirror->UpdateOutputFormat(display_id, timeline);
}
}
return 0;
}
int DrmHwcTwo::HwcDisplay::UpdateBCSH(){
int timeline = property_get_int32("vendor.display.timeline", -1);
/*
* force update propetry when timeline is zero or not exist.
*/
if (timeline && timeline == ctx_.bcsh_timeline)
return 0;
connector_->UpdateBCSH(handle_,timeline);
if(isRK3566(resource_manager_->getSocId())){
bool mirror_mode = true;
int display_id = drm_->GetCommitMirrorDisplayId();
DrmConnector *conn_mirror = drm_->GetConnectorForDisplay(display_id);
if(!conn_mirror || conn_mirror->state() != DRM_MODE_CONNECTED){
ALOGI_IF(LogLevel(DBG_DEBUG),"%s,line=%d disable bCommitMirrorMode",__FUNCTION__,__LINE__);
mirror_mode = false;
}
if(mirror_mode){
conn_mirror->UpdateBCSH(display_id,timeline);
}
}
ctx_.bcsh_timeline = timeline;
return 0;
}
bool DrmHwcTwo::HwcDisplay::DisableHdrModeRK3588(){
DrmMode active_mode = connector_->active_mode();
// 如果是8K分辨率模式HDR片源没有走 overlay 策略则关闭HDR
// 主要原因是VOP硬件限制要求最底层为 HDR dataspaceGPU合成输出为SDR
// 不满足条件则需要关闭HDR模式
if(active_mode.id() > 0 && active_mode.is_8k_mode()){
for(auto &drmHwcLayer : drm_hwc_layers_){
if(drmHwcLayer.bHdr_){
// 没有被硬件图层匹配则说明使用GPU合成
if(!drmHwcLayer.bMatch_){
HWC2_ALOGD_IF_DEBUG("HDR video compose by GLES on 8k resolution, Fource Disable HDR mode.");
return true;
}
}
}
}
return false;
}
bool DrmHwcTwo::HwcDisplay::DisableHdrMode(){
bool exist_hdr_layer = false;
int hdr_area_ratio = 0;
for(auto &drmHwcLayer : drm_hwc_layers_){
if(drmHwcLayer.bHdr_){
exist_hdr_layer = true;
int src_w = (int)(drmHwcLayer.source_crop.right - drmHwcLayer.source_crop.left);
int src_h = (int)(drmHwcLayer.source_crop.bottom - drmHwcLayer.source_crop.top);
int src_area_size = src_w * src_h;
int dis_w = drmHwcLayer.display_frame.right - drmHwcLayer.display_frame.left;
int dis_h = drmHwcLayer.display_frame.bottom - drmHwcLayer.display_frame.top;
int dis_area_size = dis_w * dis_h;
// 视频缩小倍数*10*10的原因是 vendor.hwc.hdr_video_area 为整型,不支持浮点数
hdr_area_ratio = dis_area_size * 10 / src_area_size;
int screen_size = ctx_.rel_xres * ctx_.rel_yres;
// 视频占屏幕面积*10取缩小倍数与视频占用屏幕面积较大值实现与操作
// 即需要同时满足视频缩小60%屏占60%才关闭HDR模式
if(hdr_area_ratio < (dis_area_size * 10 / screen_size))
hdr_area_ratio = dis_area_size * 10 / screen_size;
}
}
if(exist_hdr_layer){
// 存在 HDR图层判断是否存在强制关闭HDR属性若存在则关闭HDR模式
char value[PROPERTY_VALUE_MAX];
property_get("persist.vendor.hwc.hdr_force_disable", value, "0");
if(atoi(value) > 0){
if(ctx_.hdr_mode != DRM_HWC_SDR){
HWC2_ALOGD_IF_DEBUG("Exit HDR mode success");
property_set("vendor.hwc.hdr_state","FORCE-NORMAL");
}
HWC2_ALOGD_IF_DEBUG("Fource Disable HDR mode.");
return true;
}
// 存在 HDR图层判断HDR视频的屏幕占比与缩放倍率满足条件则关闭HDR模式
property_get("persist.vendor.hwc.hdr_video_area", value, "6");
if(atoi(value) > hdr_area_ratio){
if(ctx_.hdr_mode != DRM_HWC_SDR){
HWC2_ALOGD_IF_DEBUG("Exit HDR mode success");
property_set("vendor.hwc.hdr_state","FORCE-NORMAL");
}
HWC2_ALOGD_IF_DEBUG("Force Disable HDR mode.");
return true;
}
}
if(!exist_hdr_layer && ctx_.hdr_mode != DRM_HWC_SDR){
ALOGD_IF(LogLevel(DBG_DEBUG),"Exit HDR mode success");
property_set("vendor.hwc.hdr_state","NORMAL");
return true;
}
return false;
}
int DrmHwcTwo::HwcDisplay::EnableMetadataHdrMode(DrmHwcLayer& hdrLayer){
HWC2_ALOGD_IF_INFO("Id=%d Name=%s ", hdrLayer.uId_, hdrLayer.sLayerName_.c_str());
if(ctx_.display_type == DRM_MODE_CONNECTOR_TV){
HWC2_ALOGD_IF_INFO("RK3528 TV unsupport HDR2SDR, Id=%d Name=%s eDataSpace_=0x%x eotf=%d",
hdrLayer.uId_, hdrLayer.sLayerName_.c_str(),
hdrLayer.eDataSpace_,
hdrLayer.uEOTF);
return -1;
}
if(hdrLayer.bSideband2_){
HWC2_ALOGD_IF_ERR("Sideband2 layer skip, Id=%d Name=%s zpos=%d match=%d",
hdrLayer.uId_, hdrLayer.sLayerName_.c_str(), hdrLayer.iZpos_, hdrLayer.bMatch_);
return -1;
}
// Next hdr zpos must be 0
if(hdrLayer.iZpos_ > 0){
HWC2_ALOGD_IF_ERR("Next hdr zpos must be 0, Id=%d Name=%s zpos=%d",
hdrLayer.uId_, hdrLayer.sLayerName_.c_str(), hdrLayer.iZpos_);
return -1;
}
if(!hdrLayer.bMatch_){
HWC2_ALOGD_IF_ERR("Next hdr not overlay, Id=%d Name=%s zpos=%d match=%d",
hdrLayer.uId_, hdrLayer.sLayerName_.c_str(), hdrLayer.iZpos_, hdrLayer.bMatch_);
return -1;
}
// 算法解析库是否存在
DrmHdrParser* dhp = DrmHdrParser::Get();
if(dhp == NULL){
HWC2_ALOGD_IF_ERR("Fail to get DrmHdrParser, use SDR mode, Id=%d Name=%s ", hdrLayer.uId_, hdrLayer.sLayerName_.c_str());
return -1;
}
// 显示器是否支持HDR
bool is_hdr_display = connector_->is_hdmi_support_hdr();
// 是否为 HDR 片源
bool is_input_hdr = hdrLayer.bHdr_;
// 2:自动模式: 电视支持 HDR模式播放HDR视频则切换HDR模式否则使用SDR模式
// 1:HDR模式: 等同自动模式
// 0:SDR模式: 电视强制使用SDR模式HDR片源也采用SDR显示
int user_hdr_mode = hwc_get_int_property("persist.sys.vivid.hdr_mode", "2");
// 可能存在模式SDR2SDR,HDR2SDR,SDR2HDR,HDR2HDR
bool is_output_hdr = false;
// 2:自动模式: 电视支持 HDR模式播放HDR视频则切换HDR模式否则使用SDR模式
// 1:HDR模式: 电视支持 HDR模式则强制使用HDR模式SDR片源也采用HDR模式输出
if((user_hdr_mode == 2 && is_hdr_display && is_input_hdr) ||
(user_hdr_mode == 1 && is_hdr_display && is_input_hdr)){
is_output_hdr = true;
}else{
is_output_hdr = false;
}
// 如果输入是 SDR 且输出为SDR,则不需要进行任何处理
if(is_input_hdr == false && is_output_hdr == false){
HWC2_ALOGD_IF_INFO("Use SDR2SDR mode.");
return -1;
}
DrmGralloc* gralloc = DrmGralloc::getInstance();
if(gralloc == NULL){
HWC2_ALOGD_IF_INFO("DrmGralloc is null, Use SDR2SDR mode.");
return -1;
}
// debug 打印耗时
long t0 = __currentTime();
// 用于判断是否存在 metadata 信息
bool codec_meta_exist = false;
// 获取存储 metadata 信息的offset
int64_t offset = gralloc->hwc_get_offset_of_dynamic_hdr_metadata(hdrLayer.sf_handle);
if(offset < 0){
HWC2_ALOGD_IF_ERR("Fail to get hdr metadata offset, Id=%d Name=%s ", hdrLayer.uId_, hdrLayer.sLayerName_.c_str());
}
// offset > 0 则认为存在 Metadata
codec_meta_exist = offset > 0;
HWC2_ALOGD_IF_INFO("dynamic_hdr_metadata offset=%" PRIi64, offset);
// 初始化参数
memset(&hdrLayer.metadataHdrParam_, 0x00, sizeof(rk_hdr_parser_params_t));
// 如果输出模式为HDR
if(is_output_hdr){
// Android bt2020 or bt709
switch(hdrLayer.eDataSpace_ & HAL_DATASPACE_STANDARD_MASK){
case HAL_DATASPACE_STANDARD_BT2020:
case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE :
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.color_prim = COLOR_PRIM_BT2020;
break;
default:
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.color_prim = COLOR_PRIM_BT709;
break;
}
// 片源为 HLG且电视支持 HLG ,则选择 HLG bypass 模式
if(hdrLayer.uEOTF == HLG && connector_->isSupportHLG()){
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf = SINK_EOTF_HLG;
// 片源为 HDR10且电视支持 HDR10 ,则选择 HDR10 bypass 模式
}else if(hdrLayer.uEOTF == SMPTE_ST2084 && connector_->isSupportSt2084()){
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf = SINK_EOTF_ST2084;
// 若没有匹配的 HDR 模式,则优先使用 HDR10 输出
}else{
if(connector_->isSupportSt2084()){
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf = SINK_EOTF_ST2084;
}else if(connector_->isSupportHLG()){
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf = SINK_EOTF_HLG;
}
}
// hdr10 最小亮度应该是0.05,算法提供接口是要求外部数值 0.05*100=5
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.dst_min = 5;
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.dst_max = hwc_get_int_property("persist.sys.vivid.max_brightness", "1000") * 100;
}else{
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.color_prim = COLOR_PRIM_BT709;
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf = SINK_EOTF_GAMMA_SDR;
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.dst_min = 10;
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.dst_max = hwc_get_int_property("persist.sys.vivid.max_brightness", "100") * 100;
}
void *cpu_addr = NULL;
if(codec_meta_exist){
// 获取Medata地址
cpu_addr = gralloc->hwc_get_handle_lock(hdrLayer.sf_handle, hdrLayer.iWidth_, hdrLayer.iHeight_);
if(cpu_addr == NULL){
HWC2_ALOGD_IF_ERR("Fail to lock dma buffer, Id=%d Name=%s ", hdrLayer.uId_, hdrLayer.sLayerName_.c_str());
hdrLayer.metadataHdrParam_.codec_meta_exist = false;
hdrLayer.metadataHdrParam_.p_hdr_codec_meta = NULL;
}else{
uint16_t *u16_cpu_metadata = (uint16_t *)((uint8_t *)cpu_addr + offset);
hdrLayer.metadataHdrParam_.codec_meta_exist = codec_meta_exist;
hdrLayer.metadataHdrParam_.p_hdr_codec_meta = (RkMetaHdrHeader*)u16_cpu_metadata;
// 如果当前设置 hdr 显示模式为 HLG bypass则需要检测 HLG 片源是否为 dynamic Hdr
// 若为 dynamic Hdr则需要将输出模式修改为 Hdr10,若不支持Hdr10,则输出SDR
// 原因是目前 VOP3 是参考 VividHdr标准实现标准内部没有支持 dynamic hlg hdr 直出模式
if(hdrLayer.uEOTF == HLG &&
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf == SINK_EOTF_HLG){
int ret = dhp->MetadataHdrparserFormat(&hdrLayer.metadataHdrParam_,
&hdrLayer.metadataHdrFmtInfo_);
if(ret){
HWC2_ALOGD_IF_ERR("MetadataHdrparserFormat, Id=%d Name=%s ", hdrLayer.uId_, hdrLayer.sLayerName_.c_str());
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf = SINK_EOTF_ST2084;
}else{
if(hdrLayer.metadataHdrFmtInfo_.hdr_format == HDRVIVID){
if(connector_->isSupportSt2084()){
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf = SINK_EOTF_ST2084;
HWC2_ALOGD_IF_INFO("Id=%d Name=%s is HLG dynamic, convert to HDR10.", hdrLayer.uId_, hdrLayer.sLayerName_.c_str());
}else{
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf = SINK_EOTF_GAMMA_SDR;
HWC2_ALOGD_IF_INFO("Id=%d Name=%s is HLG dynamic, convert to SDR.", hdrLayer.uId_, hdrLayer.sLayerName_.c_str());
}
}
}
}
}
}else{
// Metadata 不存在,则使用 Android Dataspace
hdrLayer.metadataHdrParam_.codec_meta_exist = false;
hdrLayer.metadataHdrParam_.p_hdr_codec_meta = NULL;
// Android bt2020 or bt709
switch(hdrLayer.eDataSpace_ & HAL_DATASPACE_STANDARD_MASK){
case HAL_DATASPACE_STANDARD_BT2020:
case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE :
hdrLayer.metadataHdrParam_.hdr_dataspace_info.color_prim = COLOR_PRIM_BT2020;
break;
default:
hdrLayer.metadataHdrParam_.hdr_dataspace_info.color_prim = COLOR_PRIM_BT709;
break;
}
// Android st2084 / HLG / SDR
switch(hdrLayer.eDataSpace_ & HAL_DATASPACE_TRANSFER_MASK){
case HAL_DATASPACE_TRANSFER_ST2084:
hdrLayer.metadataHdrParam_.hdr_dataspace_info.eotf = SINK_EOTF_ST2084;
break;
case HAL_DATASPACE_TRANSFER_HLG :
hdrLayer.metadataHdrParam_.hdr_dataspace_info.eotf = SINK_EOTF_HLG;
break;
default:
hdrLayer.metadataHdrParam_.hdr_dataspace_info.eotf = SINK_EOTF_GAMMA_SDR;
break;
}
// Android full / limit range
switch(hdrLayer.eDataSpace_ & HAL_DATASPACE_RANGE_MASK){
case HAL_DATASPACE_RANGE_FULL:
hdrLayer.metadataHdrParam_.hdr_dataspace_info.range = RANGE_FULL;
break;
case HAL_DATASPACE_RANGE_LIMITED :
hdrLayer.metadataHdrParam_.hdr_dataspace_info.range = RANGE_LIMITED;
break;
default:
hdrLayer.metadataHdrParam_.hdr_dataspace_info.range = RANGE_LIMITED;
break;
}
}
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_pq_max_y_mode = 0;
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_dst_gamma = 2.2;
hdrLayer.metadataHdrParam_.hdr_user_cfg.s2h_sm_ratio = 1.0;
hdrLayer.metadataHdrParam_.hdr_user_cfg.s2h_scale_ratio = 1.0;
hdrLayer.metadataHdrParam_.hdr_user_cfg.s2h_sdr_color_space = 2;
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_debug_cfg.print_input_meta = 0;
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_debug_cfg.hdr_log_level = 0;
if(hwc_get_int_property("vendor.hwc.vivid_hdr_debug", "0") > 0){
hdrLayer.uEOTF = hwc_get_int_property("vendor.hwc.vivid_layer_eotf", "0");
hdrLayer.metadataHdrParam_.codec_meta_exist = hwc_get_bool_property("vendor.hwc.vivid_codec_meta_exist", "true");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.color_prim = hwc_get_int_property("vendor.hwc.vivid_color_prim", "0");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf = hwc_get_int_property("vendor.hwc.vivid_eotf", "0");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.red_x = hwc_get_int_property("vendor.hwc.vivid_red_x", "0");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.red_y = hwc_get_int_property("vendor.hwc.vivid_red_y", "0");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.green_x = hwc_get_int_property("vendor.hwc.vivid_green_x", "0");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.green_y = hwc_get_int_property("vendor.hwc.vivid_green_y", "0");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.white_point_x = hwc_get_int_property("vendor.hwc.vivid_white_point_x", "0");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.white_point_y = hwc_get_int_property("vendor.hwc.vivid_white_point_y", "0");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.dst_min = hwc_get_int_property("vendor.hwc.vivid_dst_min", "10");
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.dst_max = hwc_get_int_property("vendor.hwc.vivid_dst_max", "10000");
hdrLayer.metadataHdrParam_.hdr_dataspace_info.color_prim = hwc_get_int_property("vendor.hwc.vivid_dataspace_pri", "0");
hdrLayer.metadataHdrParam_.hdr_dataspace_info.eotf = hwc_get_int_property("vendor.hwc.vivid_dataspace_eotf", "0");
hdrLayer.metadataHdrParam_.hdr_dataspace_info.range = hwc_get_int_property("vendor.hwc.vivid_dataspace_range", "0");
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_pq_max_y_mode = hwc_get_int_property("vendor.hwc.vivid_hdr_pq_max_y_mode", "0");
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_dst_gamma = (hwc_get_int_property("vendor.hwc.vivid_hdr_dst_gamma", "22") * 1.0 / 10);
hdrLayer.metadataHdrParam_.hdr_user_cfg.s2h_sm_ratio = hwc_get_int_property("vendor.hwc.vivid_s2h_sm_ratio", "10") * 1.0 / 10;
hdrLayer.metadataHdrParam_.hdr_user_cfg.s2h_scale_ratio = hwc_get_int_property("vendor.hwc.vivid_s2h_scale_ratio", "10") * 1.0 / 10;
hdrLayer.metadataHdrParam_.hdr_user_cfg.s2h_sdr_color_space = hwc_get_int_property("vendor.hwc.vivid_s2h_sdr_color_space", "2");
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_debug_cfg.print_input_meta = hwc_get_int_property("vendor.hwc.vivid_print_input_meta", "1");
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_debug_cfg.hdr_log_level = hwc_get_int_property("vendor.hwc.vivid_hdr_log_level", "7");
}
HWC2_ALOGD_IF_INFO("hdr_hdmi_meta: user_hdr_mode(%d) layer eDataSpace=0x%x eotf=%d => codec_meta_exist(%d) hdr_dataspace_info: color_prim=%d eotf=%d range=%d",
user_hdr_mode,
hdrLayer.eDataSpace_,
hdrLayer.uEOTF,
hdrLayer.metadataHdrParam_.codec_meta_exist,
hdrLayer.metadataHdrParam_.hdr_dataspace_info.color_prim,
hdrLayer.metadataHdrParam_.hdr_dataspace_info.eotf,
hdrLayer.metadataHdrParam_.hdr_dataspace_info.range);
HWC2_ALOGD_IF_INFO("hdr_hdmi_meta: color_prim=%d eotf=%d red_x=%d red_y=%d green_x=%d green_y=%d white_point_x=%d white_point_y=%d dst_min=%d dst_max=%d",
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.color_prim,
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.eotf,
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.red_x,
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.red_y,
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.green_x,
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.green_y,
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.white_point_x,
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.white_point_y,
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.dst_min,
hdrLayer.metadataHdrParam_.hdr_hdmi_meta.dst_max);
HWC2_ALOGD_IF_INFO("hdr_user_cfg: hdr_pq_max_y_mode=%d hdr_dst_gamma=%f s2h_sm_ratio=%f s2h_scale_ratio=%f s2h_sdr_color_space=%d print_input_meta=%d hdr_log_level=%d",
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_pq_max_y_mode,
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_dst_gamma,
hdrLayer.metadataHdrParam_.hdr_user_cfg.s2h_sm_ratio,
hdrLayer.metadataHdrParam_.hdr_user_cfg.s2h_scale_ratio,
hdrLayer.metadataHdrParam_.hdr_user_cfg.s2h_sdr_color_space,
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_debug_cfg.print_input_meta,
hdrLayer.metadataHdrParam_.hdr_user_cfg.hdr_debug_cfg.hdr_log_level);
int ret = dhp->MetadataHdrParser(&hdrLayer.metadataHdrParam_);
if(ret){
HWC2_ALOGD_IF_ERR("Fail to call MetadataHdrParser ret=%d Id=%d Name=%s ",
ret,
hdrLayer.uId_,
hdrLayer.sLayerName_.c_str());
if(cpu_addr != NULL)
gralloc->hwc_get_handle_unlock(hdrLayer.sf_handle);
return ret;
}
if(cpu_addr != NULL)
gralloc->hwc_get_handle_unlock(hdrLayer.sf_handle);
hdrLayer.IsMetadataHdr_ = true;
ctx_.hdr_mode = DRM_HWC_METADATA_HDR;
ctx_.dataspace = hdrLayer.eDataSpace_;
HWC2_ALOGD_IF_INFO("Use HdrParser mode.");
return 0;
}
int DrmHwcTwo::HwcDisplay::EnableHdrMode(DrmHwcLayer& hdrLayer){
HWC2_ALOGD_IF_INFO("Id=%d Name=%s ", hdrLayer.uId_, hdrLayer.sLayerName_.c_str());
if(connector_->is_hdmi_support_hdr()){
if(ctx_.hdr_mode != DRM_HWC_HDR10){
ALOGD_IF(LogLevel(DBG_DEBUG),"Enable HDR mode success");
ctx_.hdr_mode = DRM_HWC_HDR10;
ctx_.dataspace = hdrLayer.eDataSpace_;
property_set("vendor.hwc.hdr_state","HDR");
}
return 0;
}
return -1;
}
int DrmHwcTwo::HwcDisplay::UpdateSidebandMode(){
if(handle_ > 0){
return 0;
}
// UpdateSideband state
DrmVideoProducer* dvp = DrmVideoProducer::getInstance();
if(!dvp->IsValid()){
return -1;
}
// 判断是否存在Sideband图层并保存tunnel_id信息
int tunnel_id = 0;
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_){
if(l.second.isSidebandLayer()){
tunnel_id = l.second.getTunnelId();
}
}
// 若存在合法 tunnel_id
if(tunnel_id > 0){
if(tunnel_id != iLastTunnelId_){
if(iLastTunnelId_ > 0){
// tunnel id 不一致则先断开连接旧连接
int ret = dvp->DestoryConnection((int(handle_) + 1000), iLastTunnelId_);
if(ret){
HWC2_ALOGD_IF_ERR("DestoryConnection display=%" PRIu64 " tunnel-id=%d fail ret=%d", handle_, iLastTunnelId_, ret);
}else{
HWC2_ALOGD_IF_INFO("DestoryConnection display=%" PRIu64 " tunnel-id=%d success ret=%d", handle_, iLastTunnelId_, ret);
}
}
// 创建新连接
int ret = dvp->CreateConnection((int(handle_) + 1000), tunnel_id);
if(ret){
HWC2_ALOGD_IF_ERR("CreateConnection display=%" PRIu64 " fail tunnel-id=%d ret=%d", handle_, tunnel_id, ret);
}else{
HWC2_ALOGD_IF_INFO("CreateConnection display=%" PRIu64 " tunnel-id=%d success ret=%d", handle_, tunnel_id, ret);
}
iLastTunnelId_ = tunnel_id;
}
}else{
if(iLastTunnelId_ > 0){
// tunnel id 不一致则先断开连接旧连接
int ret = dvp->DestoryConnection((int(handle_) + 1000), iLastTunnelId_);
if(ret){
HWC2_ALOGD_IF_ERR("DestoryConnection display=%" PRIu64 " tunnel-id=%d fail ret=%d", handle_, iLastTunnelId_, ret);
}else{
HWC2_ALOGD_IF_INFO("DestoryConnection display=%" PRIu64 " tunnel-id=%d success ret=%d", handle_, iLastTunnelId_, ret);
iLastTunnelId_ = 0;
}
}
}
return 0;
}
int DrmHwcTwo::HwcDisplay::SwitchHdrMode(){
// 需要HDR模式,找到 HDR layer,判断当前采用HDR模式
for(auto &drmHwcLayer : drm_hwc_layers_){
if(drmHwcLayer.bYuv_){
// RK3528 HDR 模式特殊处理
if(gIsRK3528()){
if(EnableMetadataHdrMode(drmHwcLayer) == 0){
return 0;
}
// 其他平台的 HDR 模式处理
}else{
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;
}
}
static_screen_timer_enable_ = enable_timer;
return 0;
}
int DrmHwcTwo::HwcDisplay::SelfRefreshEnable(){
bool enable_self_refresh = false;
int self_fps = 10;
for(auto &drmHwcLayer : drm_hwc_layers_){
#if (defined USE_LIBSR) || (defined USE_LIBSVEP_MEMC)
// Sr
if(drmHwcLayer.bUseSr_){
HWC2_ALOGD_IF_DEBUG("Sr Enable SelfRefresh!");
enable_self_refresh = true;
self_fps = 10;
break;
}
// MEMC
if(drmHwcLayer.bUseMemc_){
HWC2_ALOGD_IF_DEBUG("Memc Enable SelfRefresh!");
enable_self_refresh = true;
self_fps = 60;
break;
}
#endif
if(drmHwcLayer.bAccelerateLayer_ && !drmHwcLayer.bMatch_){
enable_self_refresh = true;
self_fps = 30;
break;
}
}
if(resource_manager_->isWBMode()){
if(self_fps < 30)
self_fps = 30;
}
if(enable_self_refresh){
InvalidateControl(self_fps,-1);
}
return 0 ;
}
int DrmHwcTwo::HwcDisplay::UpdateTimerState(bool gles_comp){
struct itimerval tv = {{0,0},{0,0}};
if (static_screen_timer_enable_ && gles_comp) {
int interval_value = hwc_get_int_property( "vendor.hwc.static_screen_opt_time", "2500");
interval_value = interval_value > 5000? 5000:interval_value;
interval_value = interval_value < 250? 250:interval_value;
tv.it_value.tv_sec = interval_value / 1000;
tv.it_value.tv_usec=( interval_value % 1000) * 1000;
HWC2_ALOGD_IF_VERBOSE("reset timer! interval_value = %d",interval_value);
} else {
static_screen_opt_=false;
tv.it_value.tv_usec = 0;
ALOGD_IF(LogLevel(DBG_DEBUG),"close timer!");
}
setitimer(ITIMER_REAL, &tv, NULL);
return 0;
}
int DrmHwcTwo::HwcDisplay::EntreStaticScreen(uint64_t refresh, int refresh_cnt){
static_screen_opt_=true;
invalidate_worker_.InvalidateControl(refresh, refresh_cnt);
return 0;
}
int DrmHwcTwo::HwcDisplay::InvalidateControl(uint64_t refresh, int refresh_cnt){
invalidate_worker_.InvalidateControl(refresh, refresh_cnt);
return 0;
}
int DrmHwcTwo::HwcDisplay::DoMirrorDisplay(int32_t *retire_fence){
if(!connector_->isCropSpilt()){
return 0;
}
if(!connector_->IsSpiltPrimary()){
return 0;
}
int32_t merge_rt_fence = -1;
int32_t display_cnt = 1;
for (auto &conn : drm_->connectors()) {
if(!conn->isCropSpilt()){
continue;
}
int display_id = conn->display();
if(!conn->IsSpiltPrimary()){
auto &display = resource_manager_->GetHwc2()->displays_.at(display_id);
if (conn->state() == DRM_MODE_CONNECTED) {
static hwc2_layer_t layer_id = 0;
if(display.has_layer(layer_id)){
}else{
display.CreateLayer(&layer_id);
}
HwcLayer &layer = display.get_layer(layer_id);
hwc_rect_t frame = {0,0,1920,1080};
layer.SetLayerDisplayFrame(frame);
hwc_frect_t crop = {0.0, 0.0, 1920.0, 1080.0};
layer.SetLayerSourceCrop(crop);
layer.SetLayerZOrder(0);
layer.SetLayerBlendMode(HWC2_BLEND_MODE_NONE);
layer.SetLayerPlaneAlpha(1.0);
layer.SetLayerCompositionType(HWC2_COMPOSITION_DEVICE);
// layer.SetLayerBuffer(NULL,-1);
layer.SetLayerTransform(0);
uint32_t num_types;
uint32_t num_requests;
display.ValidateDisplay(&num_types,&num_requests);
// display.GetChangedCompositionTypes();
// display.GetDisplayRequests();
display.AcceptDisplayChanges();
hwc_region_t damage;
display.SetClientTarget(client_layer_.buffer(),
dup(client_layer_.acquire_fence()->getFd()),
0,
damage);
int32_t rt_fence;
display.PresentDisplay(&rt_fence);
if(merge_rt_fence > 0){
char acBuf[32];
sprintf(acBuf,"RTD%" PRIu64 "M-FN%d-%d", handle_, frame_no_, display_cnt++);
sp<ReleaseFence> rt = sp<ReleaseFence>(new ReleaseFence(rt_fence, acBuf));
if(rt->isValid()){
sprintf(acBuf,"RTD%" PRIu64 "M-FN%d-%d",handle_, frame_no_, display_cnt++);
int32_t merge_rt_fence_temp = merge_rt_fence;
merge_rt_fence = rt->merge(merge_rt_fence, acBuf);
close(merge_rt_fence_temp);
}else{
HWC2_ALOGE("connector %u type=%s, type_id=%d is MirrorDisplay get retireFence fail.\n",
conn->id(),
drm_->connector_type_str(conn->type()),
conn->type_id());
}
}else{
merge_rt_fence = rt_fence;
}
}
}
}
*retire_fence = merge_rt_fence;
return 0;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerBlendMode(int32_t mode) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d"", blend=%d" ,id_,mode);
mCurrentState.blending_ = static_cast<HWC2::BlendMode>(mode);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerBuffer(buffer_handle_t buffer,
int32_t acquire_fence) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d"", buffer=%p, acq_fence=%d" ,id_,buffer,acquire_fence);
//Deleting the following logic may cause the problem that the handle cannot be updated
// The buffer and acquire_fence are handled elsewhere
// if (sf_type_ == HWC2::Composition::Client ||
// sf_type_ == HWC2::Composition::Sideband ||
// sf_type_ == HWC2::Composition::SolidColor)
// return HWC2::Error::None;
if (mCurrentState.sf_type_ == HWC2::Composition::Sideband){
return HWC2::Error::None;
}
// 应用端可能会不销毁 Surface 直接将Sideband图层修改为一般图层故需要重置Sideband相关配置
bSideband2_ = false;
bSideband2Valid_ = false;
sidebandStreamHandle_ = NULL;
// 部分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){
CacheBufferInfo(buffer);
}else{
NoCacheBufferInfo(buffer);
}
acquire_fence_ = sp<AcquireFence>(new AcquireFence(acquire_fence));
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerColor(hwc_color_t color) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d"", color [r,g,b,a]=[%d,%d,%d,%d]" ,id_,color.r,color.g,color.b,color.a);
// TODO: Punt to client composition here?
mCurrentState.color_ = color;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerCompositionType(int32_t type) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d"", type=0x%x" ,id_,type);
mCurrentState.sf_type_ = static_cast<HWC2::Composition>(type);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDataspace(int32_t dataspace) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d"", dataspace=0x%x" ,id_,dataspace);
mCurrentState.dataspace_ = static_cast<android_dataspace_t>(dataspace);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDisplayFrame(hwc_rect_t frame) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d"", frame=[%d,%d,%d,%d]" ,id_,frame.left,frame.top,frame.right,frame.bottom);
mCurrentState.display_frame_ = frame;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerPlaneAlpha(float alpha) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d"", alpha=%f" ,id_,alpha);
mCurrentState.alpha_ = alpha;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSidebandStream(
const native_handle_t *stream) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d stream=%p",id_, stream);
ResourceManager* rm = ResourceManager::getInstance();
if(rm->IsSidebandStream2Mode()){
if(stream != NULL){
vt_sideband_data_t *sbi = (vt_sideband_data_t *)(stream->data);
// 如果 Tunnel Id 有效,并且是未连接状态,则创建连接
if(sbi->tunnel_id != mSidebandInfo_.tunnel_id){
HWC2_ALOGD_IF_DEBUG("SidebandStream: layer-id=%d. version=%d numFds=%d numInts=%d",
id_,
stream->version,
stream->numFds,
stream->numInts);
HWC2_ALOGD_IF_DEBUG("SidebandStream: version=%d sizeof=%zu tunnel-id=%d session-id=%" PRIu64 " crop[%d,%d,%d,%d] "
" w=%d h=%d ws=%d hs=%d bs=%d f=%d transform=%d size=%d modifier=%d"
" usage=0x%" PRIx64 " dataSpace=0x%" PRIx64 " afbc=%d fps=%" PRIu64 "",
stream->data[0],
sizeof(vt_sideband_data_t),
sbi->tunnel_id,
sbi->session_id,
sbi->crop.left,
sbi->crop.top,
sbi->crop.right,
sbi->crop.bottom,
sbi->width,
sbi->height,
sbi->hor_stride,
sbi->ver_stride,
sbi->byte_stride,
sbi->format,
sbi->transform,
sbi->size,
sbi->modifier,
sbi->usage,
sbi->data_space,
sbi->is_afbc,
sbi->fps);
bSideband2Valid_=true;
memcpy(&mSidebandInfo_, sbi, sizeof(vt_sideband_data_t));
}
// sbi->tunnel_id 不等于0才认为是有效的Sideband 2.0 handle
if(sbi->tunnel_id != 0){
sidebandStreamHandle_ = stream;
}else{// 否则设置为NULL
sidebandStreamHandle_ = NULL;
}
}
bSideband2_ = true;
}else{
setSidebandStream(stream);
}
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSourceCrop(hwc_frect_t crop) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d"", frame=[%f,%f,%f,%f]" ,id_,crop.left,crop.top,crop.right,crop.bottom);
mCurrentState.source_crop_ = crop;
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSurfaceDamage(hwc_region_t damage) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d",id_);
// TODO: We don't use surface damage, marking as unsupported
unsupported(__func__, damage);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerTransform(int32_t transform) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d" ", transform=%x",id_,transform);
mCurrentState.transform_ = static_cast<HWC2::Transform>(transform);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerVisibleRegion(hwc_region_t visible) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d",id_);
// TODO: We don't use this information, marking as unsupported
unsupported(__func__, visible);
return HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetLayerZOrder(uint32_t order) {
HWC2_ALOGD_IF_VERBOSE("layer-id=%d" ", z=%d",id_,order);
mCurrentState.z_order_ = order;
return HWC2::Error::None;
}
void DrmHwcTwo::HwcLayer::PopulateSidebandLayer(DrmHwcLayer *drmHwcLayer,
hwc2_drm_display_t* ctx) {
// sideband layer
if(bSideband2_){
if(bSideband2Valid_){
drmHwcLayer->iTunnelId_ = mSidebandInfo_.tunnel_id;
drmHwcLayer->bSidebandStreamLayer_ = true;
drmHwcLayer->sf_handle = NULL;
drmHwcLayer->SetDisplayFrame(mCurrentState.display_frame_, ctx);
hwc_frect source_crop;
source_crop.left = mSidebandInfo_.crop.left;
source_crop.top = mSidebandInfo_.crop.top;
source_crop.right = mSidebandInfo_.crop.right;
source_crop.bottom = mSidebandInfo_.crop.bottom;
drmHwcLayer->SetSourceCrop(source_crop);
drmHwcLayer->SetTransform(mCurrentState.transform_);
// Commit mirror function
drmHwcLayer->SetDisplayFrameMirror(mCurrentState.display_frame_);
drmHwcLayer->iFd_ = -1;
drmHwcLayer->iWidth_ = mSidebandInfo_.crop.right - mSidebandInfo_.crop.left;
drmHwcLayer->iHeight_ = mSidebandInfo_.crop.bottom - mSidebandInfo_.crop.top;
drmHwcLayer->iStride_ = mSidebandInfo_.crop.right - mSidebandInfo_.crop.left;;
drmHwcLayer->iFormat_ = mSidebandInfo_.format;
drmHwcLayer->iUsage = mSidebandInfo_.usage;
drmHwcLayer->iHeightStride_ = mSidebandInfo_.crop.bottom - mSidebandInfo_.crop.top;
drmHwcLayer->uFourccFormat_ = drmGralloc_->hwc_get_fourcc_from_hal_format(mSidebandInfo_.format);
drmHwcLayer->bSideband2_ = true;
// 通过 Sideband Handle is_afbc 来判断图层是否为AFBC压缩格式
drmHwcLayer->uModifier_ = (mSidebandInfo_.is_afbc > 0) ? AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 : 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_->iFd_.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_){
drmHwcLayer->sf_handle = pBufferInfo_->native_buffer_;
drmHwcLayer->uBufferId_ = pBufferInfo_->uBufferId_;
drmHwcLayer->iFd_ = pBufferInfo_->iFd_.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_;
}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->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->fRealFps_ = GetRealFps();
drmHwcLayer->fRealMaxFps_ = GetRealMaxFps();
#ifdef RK3528
// RK3528 仅 VOP支持AFBC格式如果遇到以下两个问题需要启用解码预缩小功能
// 1. AFBC格式无法Overlay需要启用预缩小关闭AFBC并缩小;
// 2. 视频缩放倍率超过VOP硬件限制需要启用预缩小减少后端缩小倍数
drmHwcLayer->bNeedPreScale_ = false;
drmHwcLayer->bIsPreScale_ = false;
#endif
drmHwcLayer->acquire_fence = acquire_fence_;
drmHwcLayer->iFbWidth_ = ctx->framebuffer_width;
drmHwcLayer->iFbHeight_ = ctx->framebuffer_height;
drmHwcLayer->uAclk_ = ctx->aclk;
drmHwcLayer->uDclk_ = ctx->dclk;
drmHwcLayer->SetBlend(mCurrentState.blending_);
// SidebandStream layer
if(sidebandStreamHandle_ != NULL){
PopulateSidebandLayer(drmHwcLayer, ctx);
}else{
PopulateNormalLayer(drmHwcLayer, ctx);
}
#ifdef RK3528
if(gIsRK3528()){
// 调试命令
int enable_prescale_video = hwc_get_int_property("debug.hwc.enable_prescale_video", "0");
if(enable_prescale_video > 0 && drmHwcLayer->bYuv_){
metadata_for_rkvdec_scaling_t* metadata = NULL;
drmGralloc_->lock_rkvdec_scaling_metadata(buffer_, &metadata);
HWC2_ALOGD_IF_INFO("lock_rkvdec_scaling_metadata buffer_=%p metadata=%p", buffer_, metadata);
if(metadata != NULL){
metadata->requestMask = enable_prescale_video;
if(metadata->replyMask > 0){
memcpy(&(drmHwcLayer->mMetadata_), metadata, sizeof(metadata_for_rkvdec_scaling_t));
drmHwcLayer->bNeedPreScale_ = true;
drmHwcLayer->bIsPreScale_ = true;
hwc_frect source_crop;
source_crop.top = metadata->srcTop;
source_crop.left = metadata->srcLeft;
source_crop.right = metadata->srcRight;
source_crop.bottom = metadata->srcBottom;
drmHwcLayer->SetSourceCrop(source_crop);
drmHwcLayer->iWidth_ = metadata->width;
drmHwcLayer->iHeight_ = metadata->height;
drmHwcLayer->iStride_ = metadata->pixel_stride;
drmHwcLayer->iFormat_ = metadata->format;
drmHwcLayer->iUsage = metadata->usage;
drmHwcLayer->iByteStride_ = metadata->byteStride[0];
drmHwcLayer->uModifier_ = metadata->modifier;
drmHwcLayer->uFourccFormat_ = drmGralloc_->hwc_get_fourcc_from_hal_format(metadata->format);
drmHwcLayer->Init();
}
// 打印参数
HWC2_ALOGD_IF_INFO("Name=%s metadata = %p", pBufferInfo_->sLayerName_.c_str(), metadata);
HWC2_ALOGD_IF_INFO("version=0x%" PRIx64 " requestMask=0x%" PRIx64" "
"replyMask=0x%" PRIx64 " BufferId=0x%" PRIx64,
metadata->version,
metadata->requestMask,
metadata->replyMask,
drmHwcLayer->uBufferId_);
HWC2_ALOGD_IF_INFO("w=%d h=%d s=%d f=%d m=0x%" PRIx64 " usage=0x%x ",
metadata->width,
metadata->height,
metadata->pixel_stride,
metadata->format,
metadata->modifier,
metadata->usage);
HWC2_ALOGD_IF_INFO("crop=(%d,%d,%d,%d) ", metadata->srcLeft,
metadata->srcTop,
metadata->srcRight,
metadata->srcBottom);
HWC2_ALOGD_IF_INFO("layer_cnt=%d offset=%d,%d,%d,%d byteStride=%d,%d,%d,%d) ",
metadata->layer_cnt,
metadata->offset[0],
metadata->offset[1],
metadata->offset[2],
metadata->offset[3],
metadata->byteStride[0],
metadata->byteStride[1],
metadata->byteStride[2],
metadata->byteStride[3]);
drmGralloc_->unlock_rkvdec_scaling_metadata(buffer_);
}
}
}
#endif
return;
}
void DrmHwcTwo::HwcLayer::PopulateFB(hwc2_layer_t layer_id, DrmHwcLayer *drmHwcLayer,
hwc2_drm_display_t* ctx, uint32_t frame_no, bool validate) {
drmHwcLayer->uId_ = layer_id;
drmHwcLayer->uFrameNo_ = frame_no;
drmHwcLayer->bFbTarget_ = true;
drmHwcLayer->bUse_ = true;
drmHwcLayer->bSkipLayer_ = false;
drmHwcLayer->blending = DrmHwcBlending::kPreMult;
drmHwcLayer->iZpos_ = mCurrentState.z_order_;
drmHwcLayer->alpha = static_cast<uint16_t>(255.0f * mCurrentState.alpha_ + 0.5f);
drmHwcLayer->iBestPlaneType = 0;
if(!validate){
drmHwcLayer->sf_handle = buffer_;
drmHwcLayer->acquire_fence = acquire_fence_;
}else{
// Commit mirror function
drmHwcLayer->SetDisplayFrameMirror(mCurrentState.display_frame_);
drmHwcLayer->bMatch_ = false;
}
drmHwcLayer->iFbWidth_ = ctx->framebuffer_width;
drmHwcLayer->iFbHeight_ = ctx->framebuffer_height;
drmHwcLayer->uAclk_ = ctx->aclk;
drmHwcLayer->uDclk_ = ctx->dclk;
drmHwcLayer->SetDisplayFrame(mCurrentState.display_frame_, ctx);
drmHwcLayer->SetSourceCrop(mCurrentState.source_crop_);
drmHwcLayer->SetTransform(mCurrentState.transform_);
if(buffer_ && !validate){
drmHwcLayer->iFd_ = pBufferInfo_->iFd_.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_;
}else{
drmHwcLayer->iFd_ = -1;
drmHwcLayer->iWidth_ = -1;
drmHwcLayer->iHeight_ = -1;
drmHwcLayer->iStride_ = -1;
// 由于 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->Init();
return;
}
#ifdef USE_LIBPQ
int DrmHwcTwo::HwcLayer::DoPq(bool validate, DrmHwcLayer *drmHwcLayer, hwc2_drm_display_t* ctx){
char value[PROPERTY_VALUE_MAX];
property_get("persist.vendor.tvinput.rkpq.mode", value, "0");
bool pq_mode_enable = atoi(value) > 0;
if(pq_mode_enable == 1){
static bool use_pq_fb = false;
if(validate){
if(bufferQueue_ == NULL){
bufferQueue_ = std::make_shared<DrmBufferQueue>();
}
if(pq_ == NULL){
pq_ = Pq::Get();
if(pq_ != NULL){
bPqReady_ = true;
HWC2_ALOGI("Pq module ready. to enable PqMode.");
}
} else {
bPqReady_ = true;
HWC2_ALOGI("Pq module ready. to enable PqMode.");
}
if(bPqReady_){
// 1. Init Ctx
int ret = pq_->InitCtx(pqCtx_);
if(ret){
HWC2_ALOGE("Pq ctx init fail");
return ret;
}
// 2. Set buffer Info
PqImageInfo src;
src.mBufferInfo_.iFd_ = 1;
src.mBufferInfo_.iWidth_ = drmHwcLayer->iFbWidth_;
src.mBufferInfo_.iHeight_ = drmHwcLayer->iFbHeight_;
src.mBufferInfo_.iFormat_ = HAL_PIXEL_FORMAT_RGBA_8888;
// src.mBufferInfo_.iSize_ = drmHwcLayer->iFbWidth_ * drmHwcLayer->iFbHeight_ * 4;
src.mBufferInfo_.iStride_ = drmHwcLayer->iFbWidth_;
src.mBufferInfo_.uBufferId_ = 0x1;
src.mCrop_.iLeft_ = (int)drmHwcLayer->source_crop.left;
src.mCrop_.iTop_ = (int)drmHwcLayer->source_crop.top;
src.mCrop_.iRight_ = (int)drmHwcLayer->source_crop.right;
src.mCrop_.iBottom_= (int)drmHwcLayer->source_crop.bottom;
ret = pq_->SetSrcImage(pqCtx_, src);
if(ret){
printf("pq SetSrcImage fail\n");
return ret;
}
use_pq_fb = true;
}
}else if(use_pq_fb){
use_pq_fb = false;
if(bufferQueue_ == NULL){
bufferQueue_ = std::make_shared<DrmBufferQueue>();
}
if(pq_ == NULL){
pq_ = Pq::Get();
if(pq_ != NULL){
bPqReady_ = true;
HWC2_ALOGI("pq module ready. to enable pqMode.");
}
}
if(bPqReady_){
// 1. Init Ctx
int ret = pq_->InitCtx(pqCtx_);
if(ret){
HWC2_ALOGE("Pq ctx init fail");
return ret;
}
// 2. Set buffer Info
PqImageInfo src;
src.mBufferInfo_.iFd_ = drmHwcLayer->iFd_;
src.mBufferInfo_.iWidth_ = drmHwcLayer->iWidth_;
src.mBufferInfo_.iHeight_ = drmHwcLayer->iHeight_;
src.mBufferInfo_.iFormat_ = drmHwcLayer->iFormat_;
src.mBufferInfo_.iStride_ = drmHwcLayer->iStride_;
// src.mBufferInfo_.iSize_ = drmHwcLayer->iSize_;
src.mBufferInfo_.uBufferId_ = drmHwcLayer->uBufferId_;
src.mBufferInfo_.uDataSpace_ = (uint64_t)drmHwcLayer->eDataSpace_;
src.mCrop_.iLeft_ = (int)drmHwcLayer->source_crop.left;
src.mCrop_.iTop_ = (int)drmHwcLayer->source_crop.top;
src.mCrop_.iRight_ = (int)drmHwcLayer->source_crop.right;
src.mCrop_.iBottom_= (int)drmHwcLayer->source_crop.bottom;
ret = pq_->SetSrcImage(pqCtx_, src);
if(ret){
printf("Pq SetSrcImage fail\n");
return ret;
}
// 4. Alloc Dst buffer
std::shared_ptr<DrmBuffer> dst_buffer;
dst_buffer = bufferQueue_->DequeueDrmBuffer(ctx->framebuffer_width,
ctx->framebuffer_height,
HAL_PIXEL_FORMAT_YCBCR_444_888,
// PQ 算法要求 256 对齐Gralloc可用的只有256奇数倍对齐
// 暂时按照 256 奇数倍对齐,后续查看情况
// TODO: 最终PQ库内部修改为64对齐即可
RK_GRALLOC_USAGE_STRIDE_ALIGN_64 |
MALI_GRALLOC_USAGE_NO_AFBC,
"PQ-FB-target");
if(dst_buffer == NULL){
HWC2_ALOGD_IF_DEBUG("DequeueDrmBuffer fail!, skip this policy.");
return -1;
}
// 5. Set buffer Info
PqImageInfo dst;
dst.mBufferInfo_.iFd_ = dst_buffer->GetFd();
dst.mBufferInfo_.iWidth_ = dst_buffer->GetWidth();
dst.mBufferInfo_.iHeight_ = dst_buffer->GetHeight();
dst.mBufferInfo_.iFormat_ = dst_buffer->GetFormat();
dst.mBufferInfo_.iStride_ = dst_buffer->GetStride();
dst.mBufferInfo_.uBufferId_ = dst_buffer->GetBufferId();
dst.mCrop_.iLeft_ = (int)drmHwcLayer->source_crop.left;
dst.mCrop_.iTop_ = (int)drmHwcLayer->source_crop.top;
dst.mCrop_.iRight_ = (int)drmHwcLayer->source_crop.right;
dst.mCrop_.iBottom_= (int)drmHwcLayer->source_crop.bottom;
dst.mCrop_.iLeft_ = 0;
dst.mCrop_.iTop_ = 0;
dst.mCrop_.iRight_ = ctx->framebuffer_width;
dst.mCrop_.iBottom_= ctx->framebuffer_height;
ret = pq_->SetDstImage(pqCtx_, dst);
if(ret){
printf("Pq SetSrcImage fail\n");
bufferQueue_->QueueBuffer(dst_buffer);
return ret;
}
hwc_frect_t source_crop;
source_crop.left = 0;
source_crop.top = 0;
source_crop.right = ctx->framebuffer_width;
source_crop.bottom = ctx->framebuffer_height;
drmHwcLayer->UpdateAndStoreInfoFromDrmBuffer(dst_buffer->GetHandle(),
dst_buffer->GetFd(),
dst_buffer->GetFormat(),
dst_buffer->GetWidth(),
dst_buffer->GetHeight(),
dst_buffer->GetStride(),
dst_buffer->GetHeightStride(),
dst_buffer->GetByteStride(),
dst_buffer->GetSize(),
dst_buffer->GetUsage(),
dst_buffer->GetFourccFormat(),
dst_buffer->GetModifier(),
dst_buffer->GetByteStridePlanes(),
dst_buffer->GetName(),
source_crop,
dst_buffer->GetBufferId(),
dst_buffer->GetGemHandle(),
drmHwcLayer->transform);
if(drmHwcLayer->acquire_fence->isValid()){
ret = drmHwcLayer->acquire_fence->wait(1500);
if(ret){
HWC2_ALOGE("wait Fb-Target 1500ms timeout, ret=%d",ret);
drmHwcLayer->bUsePq_ = false;
bufferQueue_->QueueBuffer(dst_buffer);
return ret;
}
}
int output_fence = 0;
ret = pq_->RunAsync(pqCtx_, &output_fence);
if(ret){
HWC2_ALOGD_IF_DEBUG("RunAsync fail!");
drmHwcLayer->bUsePq_ = false;
bufferQueue_->QueueBuffer(dst_buffer);
return ret;
}
dst_buffer->SetFinishFence(dup(output_fence));
drmHwcLayer->acquire_fence = sp<AcquireFence>(new AcquireFence(output_fence));
property_get("vendor.dump", value, "false");
if(!strcmp(value, "true")){
drmHwcLayer->acquire_fence->wait();
dst_buffer->DumpData();
}
bufferQueue_->QueueBuffer(dst_buffer);
}
}
drmHwcLayer->uFourccFormat_ = DRM_FORMAT_NV24;
} else {
if(bPqReady_) {
pq_->DeInit();
bPqReady_ = false;
}
}
drmHwcLayer->Init();
if(gIsDrmVerison6_1()){
drmHwcLayer->uColorSpace.colorspace_kernel_6_1_.color_encoding_ = DRM_COLOR_YCBCR_BT601;
drmHwcLayer->uColorSpace.colorspace_kernel_6_1_.color_range_ = DRM_COLOR_YCBCR_FULL_RANGE;
}else{
drmHwcLayer->uColorSpace.colorspace_kernel_510_ = V4L2_COLORSPACE_JPEG;
}
return 0;
}
#endif
void DrmHwcTwo::HwcLayer::DumpLayerInfo(String8 &output) {
output.appendFormat( " %04" PRIu32 " | %03" PRIu32 " | %9s | %9s | %-18.18" PRIxPTR " |"
" %-11.11s | %-10.10s |%7.1f,%7.1f,%7.1f,%7.1f |%5d,%5d,%5d,%5d |"
" %10x | %5.1f | %s | 0x%" PRIx64 "\n",
id_,
mCurrentState.z_order_,
to_string(mCurrentState.sf_type_).c_str(),
to_string(mCurrentState.validated_type_).c_str(),
intptr_t(buffer_),
to_string(mCurrentState.transform_).c_str(),
to_string(mCurrentState.blending_).c_str(),
mCurrentState.source_crop_.left,
mCurrentState.source_crop_.top,
mCurrentState.source_crop_.right,
mCurrentState.source_crop_.bottom,
mCurrentState.display_frame_.left,
mCurrentState.display_frame_.top,
mCurrentState.display_frame_.right,
mCurrentState.display_frame_.bottom,
mCurrentState.dataspace_,
GetFps(),
layer_name_.c_str(),
pBufferInfo_ != NULL ? pBufferInfo_->uBufferId_ : -1);
return;
}
int DrmHwcTwo::HwcLayer::DumpData() {
if(!buffer_)
ALOGI_IF(LogLevel(DBG_INFO),"%s,line=%d LayerId=%u Buffer is null.",__FUNCTION__,__LINE__,id_);
void* cpu_addr = NULL;
static int frame_cnt =0;
int width, height, stride, byte_stride, size;
int ret = 0;
width = drmGralloc_->hwc_get_handle_attibute(buffer_,ATT_WIDTH);
height = drmGralloc_->hwc_get_handle_attibute(buffer_,ATT_HEIGHT);
stride = drmGralloc_->hwc_get_handle_attibute(buffer_,ATT_STRIDE);
size = drmGralloc_->hwc_get_handle_attibute(buffer_,ATT_SIZE);
byte_stride = drmGralloc_->hwc_get_handle_attibute(buffer_,ATT_BYTE_STRIDE);
cpu_addr = drmGralloc_->hwc_get_handle_lock(buffer_,width,height);
if(cpu_addr == NULL) {
ALOGE("%s, line = %d, LayerId = %u, lock fail", __FUNCTION__, __LINE__, id_);
return -1;
}
FILE * pfile = NULL;
char data_name[100] ;
system("mkdir /data/dump/ && chmod /data/dump/ 777 ");
sprintf(data_name,"/data/dump/%d_%5.5s_id-%d_%dx%d_z-%d.bin",
frame_cnt++,layer_name_.size() < 5 ? "unset" : layer_name_.c_str(),
id_,stride,height,mCurrentState.z_order_);
pfile = fopen(data_name,"wb");
if(pfile)
{
fwrite((const void *)cpu_addr,(size_t)(size),1,pfile);
fflush(pfile);
fclose(pfile);
ALOGD(" dump surface layer_id=%d ,data_name %s,w:%d,h:%d,stride :%d,size=%d,cpu_addr=%p",
id_,data_name,width,height,byte_stride,size,cpu_addr);
}
else
{
ALOGE("Open %s fail", data_name);
ALOGD(" dump surface layer_id=%d ,data_name %s,w:%d,h:%d,stride :%d,size=%d,cpu_addr=%p",
id_,data_name,width,height,byte_stride,size,cpu_addr);
}
ret = drmGralloc_->hwc_get_handle_unlock(buffer_);
if(ret){
ALOGE("%s,line=%d, LayerId=%u, unlock fail ret = %d ",__FUNCTION__,__LINE__,id_,ret);
return ret;
}
return ret;
}
bool DrmHwcTwo::IsHasRegisterDisplayId(hwc2_display_t displayid){
return mHasRegisterDisplay_.count(displayid) > 0;
}
void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) {
auto cb = callbacks_.find(HWC2::Callback::Hotplug);
if (cb == callbacks_.end())
return;
if(isRK3566(resource_manager_->getSocId())){
if(displayid != HWC_DISPLAY_PRIMARY){
auto &drmDevices = resource_manager_->GetDrmDevices();
for (auto &device : drmDevices) {
if(state==DRM_MODE_CONNECTED)
device->SetCommitMirrorDisplayId(displayid);
else
device->SetCommitMirrorDisplayId(-1);
}
ALOGD_IF(LogLevel(DBG_DEBUG),"HandleDisplayHotplug skip display-id=%" PRIu64 " state=%d",displayid,state);
return;
}
}
if(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);
}
}
void DrmHwcTwo::HandleInitialHotplugState(DrmDevice *drmDevice) {
// RK3528 HDMI/TV互斥模式要求若HDMI已连接则 TV不注册
if(gIsRK3528()){
drmDevice->FlipHotplugEventForInit();
return;
}
for (auto &conn : drmDevice->connectors()) {
if (conn->state() != DRM_MODE_CONNECTED)
continue;
for (auto &crtc : drmDevice->crtc()) {
if(conn->display() != crtc->display())
continue;
// HWC_DISPLAY_PRIMARY display have been hotplug
if(conn->display() == HWC_DISPLAY_PRIMARY){
// SpiltDisplay Hotplug
if(conn->isHorizontalSpilt()){
HandleDisplayHotplug((conn->GetSpiltModeId()), conn->state());
ALOGI("HWC2 Init: SF register connector %u type=%s, type_id=%d SpiltDisplay=%d\n",
conn->id(),drmDevice->connector_type_str(conn->type()),conn->type_id(),conn->GetSpiltModeId());
}
continue;
}
// SpiltDisplay Hotplug
if(conn->isCropSpilt()){
if(conn->IsSpiltPrimary()){
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{
// CropSpilt
HWC2_ALOGI("HWC2 Init: not to register connector %u type=%s, type_id=%d isCropSpilt=%d\n",
conn->id(),drmDevice->connector_type_str(conn->type()),
conn->type_id(),
conn->isCropSpilt());
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());
// SpiltDisplay Hotplug
if(conn->isHorizontalSpilt()){
HandleDisplayHotplug((conn->GetSpiltModeId()), conn->state());
ALOGI("HWC2 Init: SF register connector %u type=%s, type_id=%d SpiltDisplay=%d\n",
conn->id(),drmDevice->connector_type_str(conn->type()),conn->type_id(),conn->GetSpiltModeId());
}
}
}
}
void DrmHwcTwo::DrmHotplugHandler::HdmiTvOnlyOne(PLUG_EVENT_TYPE hdmi_hotplug_state){
if(!gIsRK3528())
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.UpdateDisplayMode();
ret |= (int32_t)display.CheckStateAndReinit(!hwc2_->IsHasRegisterDisplayId(display_id));
ret |= (int32_t)display.ChosePreferredConfig();
if(ret != 0){
HWC2_ALOGE("hwc_hotplug: %s connector %u type=%s type_id=%d state is error, skip hotplug.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug",
conn->id(),drm_->connector_type_str(conn->type()), conn->type_id());
}else{
HWC2_ALOGI("hwc_hotplug: %s connector %u type=%s type_id=%d send hotplug event to SF.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug",
conn->id(),drm_->connector_type_str(conn->type()),conn->type_id());
hwc2_->HandleDisplayHotplug(display_id, cur_state);
display.SyncPowerMode();
}
}
}
}
// RK3528 HDMI接入则需要销毁 TV 到 SurfaceFlinger
}else{
// 检查HDMI连接状态
bool hdmi_conneted = false;
for (auto &conn : drm_->connectors()) {
if(conn->type() == DRM_MODE_CONNECTOR_HDMIA){
hdmi_conneted = (conn->state() == DRM_MODE_CONNECTED);
}
}
// 若HDMI已连接则需要销毁 TV display
if(hdmi_conneted){
for (auto &conn : drm_->connectors()) {
if(conn->type() == DRM_MODE_CONNECTOR_TV){
int display_id = conn->display();
auto &display = hwc2_->displays_.at(display_id);
display.SetPowerMode(HWC2_POWER_MODE_OFF);
HWC2_ALOGI("hwc_hotplug: Unplug connector %u type=%s type_id=%d send unhotplug event to SF.",
conn->id(),drm_->connector_type_str(conn->type()),conn->type_id());
hwc2_->HandleDisplayHotplug(display_id, DRM_MODE_DISCONNECTED);
}
}
}
}
return ;
}
void DrmHwcTwo::DrmHotplugHandler::HandleEvent(uint64_t timestamp_us) {
int32_t ret = 0;
bool primary_change = true;
PLUG_EVENT_TYPE event_type = DRM_HOTPLUG_NONE;
for (auto &conn : drm_->connectors()) {
ret = 0;
// 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());
continue;
}
drmModeConnection old_state = conn->hotplug_state();
conn->ResetModesReady();
conn->UpdateModes();
conn->update_hotplug_state();
drmModeConnection cur_state = conn->hotplug_state();
if(!conn->ModesReady())
continue;
if (cur_state == old_state)
continue;
// 当前状态为未连接,则为拔出事件
if(cur_state == DRM_MODE_DISCONNECTED){
event_type = DRM_HOTPLUG_UNPLUG_EVENT;
}else{
event_type = DRM_HOTPLUG_PLUG_EVENT;
}
ALOGI("hwc_hotplug: %s event @%" PRIu64 " for connector %u type=%s, type_id=%d\n",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", timestamp_us, conn->id(),
drm_->connector_type_str(conn->type()),conn->type_id());
// RK3528 HDMI/TV 互斥功能需要提前处理 TV display
if(gIsRK3528() && conn->type() == DRM_MODE_CONNECTOR_HDMIA)
HdmiTvOnlyOne(event_type);
int display_id = conn->display();
primary_change = (display_id == 0);
auto &display = hwc2_->displays_.at(display_id);
if (cur_state == DRM_MODE_CONNECTED) {
ret |= (int32_t)display.HoplugEventTmeline();
ret |= (int32_t)display.UpdateDisplayMode();
ret |= (int32_t)display.CheckStateAndReinit(!hwc2_->IsHasRegisterDisplayId(display_id));
ret |= (int32_t)display.ChosePreferredConfig();
if(ret != 0){
HWC2_ALOGE("hwc_hotplug: %s connector %u type=%s type_id=%d state is error, skip hotplug.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug",
conn->id(),drm_->connector_type_str(conn->type()),conn->type_id());
}else if(conn->isCropSpilt()){
HWC2_ALOGI("hwc_hotplug: %s connector %u type=%s type_id=%d isCropSpilt skip hotplug.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug",
conn->id(),drm_->connector_type_str(conn->type()),conn->type_id());
display.SetPowerMode(HWC2_POWER_MODE_ON);
}else{
HWC2_ALOGI("hwc_hotplug: %s connector %u type=%s type_id=%d send hotplug event to SF.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug",
conn->id(),drm_->connector_type_str(conn->type()),conn->type_id());
hwc2_->HandleDisplayHotplug(display_id, cur_state);
display.SyncPowerMode();
}
}else{
ret |= (int32_t)display.ClearDisplay();
ret |= (int32_t)drm_->ReleaseDpyRes(display_id);
if(ret != 0){
HWC2_ALOGE("hwc_hotplug: %s connector %u type=%s type_id=%d state is error, skip hotplug.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug",
conn->id(),drm_->connector_type_str(conn->type()),conn->type_id());
}else if(conn->isCropSpilt()){
HWC2_ALOGI("hwc_hotplug: %s connector %u type=%s type_id=%d isCropSpilt skip hotplug.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug",
conn->id(),drm_->connector_type_str(conn->type()),conn->type_id());
// display.SetPowerMode(HWC2_POWER_MODE_OFF);
}else{
HWC2_ALOGI("hwc_hotplug: %s connector %u type=%s type_id=%d send hotplug event to SF.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug",
conn->id(),drm_->connector_type_str(conn->type()),conn->type_id());
hwc2_->HandleDisplayHotplug(display_id, cur_state);
}
}
// SpiltDisplay Hoplug.
ret = 0;
if(conn->isHorizontalSpilt()){
display_id = conn->GetSpiltModeId();
auto &spilt_display = hwc2_->displays_.at(display_id);
if (cur_state == DRM_MODE_CONNECTED) {
ret |= (int32_t)spilt_display.HoplugEventTmeline();
ret |= (int32_t)spilt_display.UpdateDisplayMode();
ret |= (int32_t)spilt_display.CheckStateAndReinit(!hwc2_->IsHasRegisterDisplayId(display_id));
ret |= (int32_t)spilt_display.ChosePreferredConfig();
if(ret != 0){
HWC2_ALOGE("hwc_hotplug: %s connector %u type=%s type_id=%d state is error, skip hotplug.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug",
conn->id(),drm_->connector_type_str(conn->type()),conn->type_id());
}else{
HWC2_ALOGI("hwc_hotplug: %s connector %u type=%s type_id=%d send hotplug event to SF.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug",
conn->id(),drm_->connector_type_str(conn->type()),conn->type_id());
hwc2_->HandleDisplayHotplug(display_id, cur_state);
spilt_display.SyncPowerMode();
}
}else{
ret |= (int32_t)spilt_display.ClearDisplay();
ret |= (int32_t)drm_->ReleaseDpyRes(display_id);
if(ret != 0){
HWC2_ALOGE("hwc_hotplug: %s connector %u type=%s type_id=%d state is error, skip hotplug.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug",
conn->id(),drm_->connector_type_str(conn->type()),conn->type_id());
}else{
HWC2_ALOGI("hwc_hotplug: %s connector %u type=%s type_id=%d send hotplug event to SF.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug",
conn->id(),drm_->connector_type_str(conn->type()),conn->type_id());
hwc2_->HandleDisplayHotplug(display_id, cur_state);
}
}
}
}
if(primary_change){
for (auto &conn : drm_->connectors()) {
// RK3528 不需要此功能
if(gIsRK3528()){
continue;
}
// 多屏拼接不需要重新注册屏幕
if(conn->isCropSpilt()){
continue;
}
int display_id = conn->display();
drmModeConnection state = conn->state();
if (display_id != 0 && state == DRM_MODE_CONNECTED) {
HWC2_ALOGI("hwc_hotplug: primary_change Plug connector %u type=%s type_id=%d send hotplug event to SF.",
conn->id(),drm_->connector_type_str(conn->type()),conn->type_id());
hwc2_->HandleDisplayHotplug(display_id, state);
}
}
}
// 拔出事件说明存在crtc资源释放
if(event_type == DRM_HOTPLUG_UNPLUG_EVENT){
for (auto &conn : drm_->connectors()) {
// 多屏拼接不需要重新注册屏幕
if(conn->isCropSpilt()){
continue;
}
ret = 0;
drmModeConnection cur_state = conn->state();
HwcConnnectorStete cur_hwc_state = conn->hwc_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.UpdateDisplayMode();
ret |= (int32_t)display.CheckStateAndReinit(!hwc2_->IsHasRegisterDisplayId(display_id));
ret |= (int32_t)display.ChosePreferredConfig();
if(ret != 0){
HWC2_ALOGE("hwc_hotplug: %s connector %u type=%s type_id=%d state is error, skip hotplug.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug",
conn->id(),drm_->connector_type_str(conn->type()), conn->type_id());
}else{
HWC2_ALOGI("hwc_hotplug: %s connector %u type=%s type_id=%d send hotplug event to SF.",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug",
conn->id(),drm_->connector_type_str(conn->type()),conn->type_id());
hwc2_->HandleDisplayHotplug(display_id, cur_state);
display.SyncPowerMode();
}
}
}
}
}
auto &display = hwc2_->displays_.at(0);
display.InvalidateControl(5,20);
return;
}
void DrmHwcTwo::DrmHotplugHandler::HandleResolutionSwitchEvent(int display_id) {
// 若系统没有设置为动态更新模式的话,则不进行分辨率更新
ResourceManager* rm = ResourceManager::getInstance();
if(!rm->IsDynamicDisplayMode()){
return;
}
DrmConnector *connector = drm_->GetConnectorForDisplay(display_id);
if (!connector) {
ALOGE("Failed to get connector for display %d", display_id);
return;
}
auto &display = hwc2_->displays_.at(display_id);
HWC2::Error error = display.ChosePreferredConfig();
if(error != HWC2::Error::None){
HWC2_ALOGE("hwc_resolution_switch: connector %u type=%s, type_id=%d ChosePreferredConfig fail.\n",
connector->id(),
drm_->connector_type_str(connector->type()),
connector->type_id());
return;
}
if(display.IsActiveModeChange()){
HWC2_ALOGI("hwc_resolution_switch: connector %u type=%s, type_id=%d\n",
connector->id(),
drm_->connector_type_str(connector->type()),
connector->type_id());
hwc2_->HandleDisplayHotplug(display_id, DRM_MODE_CONNECTED);
auto &primary = hwc2_->displays_.at(0);
primary.InvalidateControl(5,20);
display.ActiveModeChange(false);
}
return;
}
// static
int DrmHwcTwo::HookDevClose(hw_device_t * /*dev*/) {
unsupported(__func__);
return 0;
}
// static
void DrmHwcTwo::HookDevGetCapabilities(hwc2_device_t * /*dev*/,
uint32_t *out_count,
int32_t * out_capabilities) {
if(out_capabilities == NULL){
*out_count = 1;
return;
}
out_capabilities[0] = static_cast<int32_t>(HWC2::Capability::SidebandStream);
}
// static
hwc2_function_pointer_t DrmHwcTwo::HookDevGetFunction(
struct hwc2_device * /*dev*/, int32_t descriptor) {
supported(__func__);
auto func = static_cast<HWC2::FunctionDescriptor>(descriptor);
switch (func) {
// Device functions
case HWC2::FunctionDescriptor::CreateVirtualDisplay:
return ToHook<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(
DeviceHook<int32_t, decltype(&DrmHwcTwo::CreateVirtualDisplay),
&DrmHwcTwo::CreateVirtualDisplay, uint32_t, uint32_t,
int32_t *, hwc2_display_t *>);
case HWC2::FunctionDescriptor::DestroyVirtualDisplay:
return ToHook<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(
DeviceHook<int32_t, decltype(&DrmHwcTwo::DestroyVirtualDisplay),
&DrmHwcTwo::DestroyVirtualDisplay, hwc2_display_t>);
case HWC2::FunctionDescriptor::Dump:
return ToHook<HWC2_PFN_DUMP>(
DeviceHook<void, decltype(&DrmHwcTwo::Dump), &DrmHwcTwo::Dump,
uint32_t *, char *>);
case HWC2::FunctionDescriptor::GetMaxVirtualDisplayCount:
return ToHook<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>(
DeviceHook<uint32_t, decltype(&DrmHwcTwo::GetMaxVirtualDisplayCount),
&DrmHwcTwo::GetMaxVirtualDisplayCount>);
case HWC2::FunctionDescriptor::RegisterCallback:
return ToHook<HWC2_PFN_REGISTER_CALLBACK>(
DeviceHook<int32_t, decltype(&DrmHwcTwo::RegisterCallback),
&DrmHwcTwo::RegisterCallback, int32_t,
hwc2_callback_data_t, hwc2_function_pointer_t>);
// Display functions
case HWC2::FunctionDescriptor::AcceptDisplayChanges:
return ToHook<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(
DisplayHook<decltype(&HwcDisplay::AcceptDisplayChanges),
&HwcDisplay::AcceptDisplayChanges>);
case HWC2::FunctionDescriptor::CreateLayer:
return ToHook<HWC2_PFN_CREATE_LAYER>(
DisplayHook<decltype(&HwcDisplay::CreateLayer),
&HwcDisplay::CreateLayer, hwc2_layer_t *>);
case HWC2::FunctionDescriptor::DestroyLayer:
return ToHook<HWC2_PFN_DESTROY_LAYER>(
DisplayHook<decltype(&HwcDisplay::DestroyLayer),
&HwcDisplay::DestroyLayer, hwc2_layer_t>);
case HWC2::FunctionDescriptor::GetActiveConfig:
return ToHook<HWC2_PFN_GET_ACTIVE_CONFIG>(
DisplayHook<decltype(&HwcDisplay::GetActiveConfig),
&HwcDisplay::GetActiveConfig, hwc2_config_t *>);
case HWC2::FunctionDescriptor::GetChangedCompositionTypes:
return ToHook<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(
DisplayHook<decltype(&HwcDisplay::GetChangedCompositionTypes),
&HwcDisplay::GetChangedCompositionTypes, uint32_t *,
hwc2_layer_t *, int32_t *>);
case HWC2::FunctionDescriptor::GetClientTargetSupport:
return ToHook<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(
DisplayHook<decltype(&HwcDisplay::GetClientTargetSupport),
&HwcDisplay::GetClientTargetSupport, uint32_t, uint32_t,
int32_t, int32_t>);
case HWC2::FunctionDescriptor::GetColorModes:
return ToHook<HWC2_PFN_GET_COLOR_MODES>(
DisplayHook<decltype(&HwcDisplay::GetColorModes),
&HwcDisplay::GetColorModes, uint32_t *, int32_t *>);
case HWC2::FunctionDescriptor::GetDisplayAttribute:
return ToHook<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(
DisplayHook<decltype(&HwcDisplay::GetDisplayAttribute),
&HwcDisplay::GetDisplayAttribute, hwc2_config_t, int32_t,
int32_t *>);
case HWC2::FunctionDescriptor::GetDisplayConfigs:
return ToHook<HWC2_PFN_GET_DISPLAY_CONFIGS>(
DisplayHook<decltype(&HwcDisplay::GetDisplayConfigs),
&HwcDisplay::GetDisplayConfigs, uint32_t *,
hwc2_config_t *>);
case HWC2::FunctionDescriptor::GetDisplayName:
return ToHook<HWC2_PFN_GET_DISPLAY_NAME>(
DisplayHook<decltype(&HwcDisplay::GetDisplayName),
&HwcDisplay::GetDisplayName, uint32_t *, char *>);
case HWC2::FunctionDescriptor::GetDisplayRequests:
return ToHook<HWC2_PFN_GET_DISPLAY_REQUESTS>(
DisplayHook<decltype(&HwcDisplay::GetDisplayRequests),
&HwcDisplay::GetDisplayRequests, int32_t *, uint32_t *,
hwc2_layer_t *, int32_t *>);
case HWC2::FunctionDescriptor::GetDisplayType:
return ToHook<HWC2_PFN_GET_DISPLAY_TYPE>(
DisplayHook<decltype(&HwcDisplay::GetDisplayType),
&HwcDisplay::GetDisplayType, int32_t *>);
case HWC2::FunctionDescriptor::GetDozeSupport:
return ToHook<HWC2_PFN_GET_DOZE_SUPPORT>(
DisplayHook<decltype(&HwcDisplay::GetDozeSupport),
&HwcDisplay::GetDozeSupport, int32_t *>);
case HWC2::FunctionDescriptor::GetHdrCapabilities:
return ToHook<HWC2_PFN_GET_HDR_CAPABILITIES>(
DisplayHook<decltype(&HwcDisplay::GetHdrCapabilities),
&HwcDisplay::GetHdrCapabilities, uint32_t *, int32_t *,
float *, float *, float *>);
case HWC2::FunctionDescriptor::GetReleaseFences:
return ToHook<HWC2_PFN_GET_RELEASE_FENCES>(
DisplayHook<decltype(&HwcDisplay::GetReleaseFences),
&HwcDisplay::GetReleaseFences, uint32_t *, hwc2_layer_t *,
int32_t *>);
case HWC2::FunctionDescriptor::PresentDisplay:
return ToHook<HWC2_PFN_PRESENT_DISPLAY>(
DisplayHook<decltype(&HwcDisplay::PresentDisplay),
&HwcDisplay::PresentDisplay, int32_t *>);
case HWC2::FunctionDescriptor::SetActiveConfig:
return ToHook<HWC2_PFN_SET_ACTIVE_CONFIG>(
DisplayHook<decltype(&HwcDisplay::SetActiveConfig),
&HwcDisplay::SetActiveConfig, hwc2_config_t>);
case HWC2::FunctionDescriptor::SetClientTarget:
return ToHook<HWC2_PFN_SET_CLIENT_TARGET>(
DisplayHook<decltype(&HwcDisplay::SetClientTarget),
&HwcDisplay::SetClientTarget, buffer_handle_t, int32_t,
int32_t, hwc_region_t>);
case HWC2::FunctionDescriptor::SetColorMode:
return ToHook<HWC2_PFN_SET_COLOR_MODE>(
DisplayHook<decltype(&HwcDisplay::SetColorMode),
&HwcDisplay::SetColorMode, int32_t>);
case HWC2::FunctionDescriptor::SetColorTransform:
return ToHook<HWC2_PFN_SET_COLOR_TRANSFORM>(
DisplayHook<decltype(&HwcDisplay::SetColorTransform),
&HwcDisplay::SetColorTransform, const float *, int32_t>);
case HWC2::FunctionDescriptor::SetOutputBuffer:
return ToHook<HWC2_PFN_SET_OUTPUT_BUFFER>(
DisplayHook<decltype(&HwcDisplay::SetOutputBuffer),
&HwcDisplay::SetOutputBuffer, buffer_handle_t, int32_t>);
case HWC2::FunctionDescriptor::SetPowerMode:
return ToHook<HWC2_PFN_SET_POWER_MODE>(
DisplayHook<decltype(&HwcDisplay::SetPowerMode),
&HwcDisplay::SetPowerMode, int32_t>);
case HWC2::FunctionDescriptor::SetVsyncEnabled:
return ToHook<HWC2_PFN_SET_VSYNC_ENABLED>(
DisplayHook<decltype(&HwcDisplay::SetVsyncEnabled),
&HwcDisplay::SetVsyncEnabled, int32_t>);
case HWC2::FunctionDescriptor::ValidateDisplay:
return ToHook<HWC2_PFN_VALIDATE_DISPLAY>(
DisplayHook<decltype(&HwcDisplay::ValidateDisplay),
&HwcDisplay::ValidateDisplay, uint32_t *, uint32_t *>);
#ifdef ANDROID_S
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 *>);
#endif //ANDROID_S
// Layer functions
case HWC2::FunctionDescriptor::SetCursorPosition:
return ToHook<HWC2_PFN_SET_CURSOR_POSITION>(
LayerHook<decltype(&HwcLayer::SetCursorPosition),
&HwcLayer::SetCursorPosition, int32_t, int32_t>);
case HWC2::FunctionDescriptor::SetLayerBlendMode:
return ToHook<HWC2_PFN_SET_LAYER_BLEND_MODE>(
LayerHook<decltype(&HwcLayer::SetLayerBlendMode),
&HwcLayer::SetLayerBlendMode, int32_t>);
case HWC2::FunctionDescriptor::SetLayerBuffer:
return ToHook<HWC2_PFN_SET_LAYER_BUFFER>(
LayerHook<decltype(&HwcLayer::SetLayerBuffer),
&HwcLayer::SetLayerBuffer, buffer_handle_t, int32_t>);
case HWC2::FunctionDescriptor::SetLayerColor:
return ToHook<HWC2_PFN_SET_LAYER_COLOR>(
LayerHook<decltype(&HwcLayer::SetLayerColor),
&HwcLayer::SetLayerColor, hwc_color_t>);
case HWC2::FunctionDescriptor::SetLayerCompositionType:
return ToHook<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(
LayerHook<decltype(&HwcLayer::SetLayerCompositionType),
&HwcLayer::SetLayerCompositionType, int32_t>);
case HWC2::FunctionDescriptor::SetLayerDataspace:
return ToHook<HWC2_PFN_SET_LAYER_DATASPACE>(
LayerHook<decltype(&HwcLayer::SetLayerDataspace),
&HwcLayer::SetLayerDataspace, int32_t>);
case HWC2::FunctionDescriptor::SetLayerDisplayFrame:
return ToHook<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(
LayerHook<decltype(&HwcLayer::SetLayerDisplayFrame),
&HwcLayer::SetLayerDisplayFrame, hwc_rect_t>);
case HWC2::FunctionDescriptor::SetLayerPlaneAlpha:
return ToHook<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(
LayerHook<decltype(&HwcLayer::SetLayerPlaneAlpha),
&HwcLayer::SetLayerPlaneAlpha, float>);
case HWC2::FunctionDescriptor::SetLayerSidebandStream:
return ToHook<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>(
LayerHook<decltype(&HwcLayer::SetLayerSidebandStream),
&HwcLayer::SetLayerSidebandStream,
const native_handle_t *>);
case HWC2::FunctionDescriptor::SetLayerSourceCrop:
return ToHook<HWC2_PFN_SET_LAYER_SOURCE_CROP>(
LayerHook<decltype(&HwcLayer::SetLayerSourceCrop),
&HwcLayer::SetLayerSourceCrop, hwc_frect_t>);
case HWC2::FunctionDescriptor::SetLayerSurfaceDamage:
return ToHook<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(
LayerHook<decltype(&HwcLayer::SetLayerSurfaceDamage),
&HwcLayer::SetLayerSurfaceDamage, hwc_region_t>);
case HWC2::FunctionDescriptor::SetLayerTransform:
return ToHook<HWC2_PFN_SET_LAYER_TRANSFORM>(
LayerHook<decltype(&HwcLayer::SetLayerTransform),
&HwcLayer::SetLayerTransform, int32_t>);
case HWC2::FunctionDescriptor::SetLayerVisibleRegion:
return ToHook<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(
LayerHook<decltype(&HwcLayer::SetLayerVisibleRegion),
&HwcLayer::SetLayerVisibleRegion, hwc_region_t>);
case HWC2::FunctionDescriptor::SetLayerZOrder:
return ToHook<HWC2_PFN_SET_LAYER_Z_ORDER>(
LayerHook<decltype(&HwcLayer::SetLayerZOrder),
&HwcLayer::SetLayerZOrder, uint32_t>);
case HWC2::FunctionDescriptor::Invalid:
default:
return NULL;
}
}
// static
int DrmHwcTwo::HookDevOpen(const struct hw_module_t *module, const char *name,
struct hw_device_t **dev) {
if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
ALOGE("Invalid module name- %s", name);
return -EINVAL;
}
InitDebugModule();
std::unique_ptr<DrmHwcTwo> ctx(new DrmHwcTwo());
if (!ctx) {
ALOGE("Failed to allocate DrmHwcTwo");
return -ENOMEM;
}
HWC2::Error err = ctx->Init();
if (err != HWC2::Error::None) {
ALOGE("Failed to initialize DrmHwcTwo err=%d\n", err);
return -EINVAL;
}
g_ctx = ctx.get();
signal(SIGALRM, StaticScreenOptHandler);
property_set("vendor.hwc.hdr_state","NORMAL");
ctx->common.module = const_cast<hw_module_t *>(module);
*dev = &ctx->common;
ctx.release();
return 0;
}
} // namespace android
static struct hw_module_methods_t hwc2_module_methods = {
.open = android::DrmHwcTwo::HookDevOpen,
};
hw_module_t HAL_MODULE_INFO_SYM = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = HARDWARE_MODULE_API_VERSION(2, 0),
.id = HWC_HARDWARE_MODULE_ID,
.name = "DrmHwcTwo module",
.author = "The Android Open Source Project",
.methods = &hwc2_module_methods,
.dso = NULL,
.reserved = {0},
};