From 3627bebf7b119d2f71a8abbcf55fdc633de7d327 Mon Sep 17 00:00:00 2001 From: Roman Stratiienko Date: Tue, 4 Jan 2022 16:02:55 +0200 Subject: [PATCH] drm_hwcomposer: Move HwcDisplay out of DrmHwcTwo class Reduces code complexity. Closes: https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer/-/issues/35 Signed-off-by: Roman Stratiienko --- .ci/Makefile | 2 + Android.bp | 1 + DrmHwcTwo.cpp | 947 +------------------------------------------ DrmHwcTwo.h | 242 +---------- backend/Backend.cpp | 9 +- backend/Backend.h | 9 +- backend/BackendClient.cpp | 4 +- backend/BackendClient.h | 3 +- backend/BackendManager.cpp | 2 +- backend/BackendManager.h | 6 +- backend/BackendRCarDu.cpp | 3 +- backend/BackendRCarDu.h | 2 +- hwc2_device/HwcDisplay.cpp | 958 ++++++++++++++++++++++++++++++++++++++++++++ hwc2_device/HwcDisplay.h | 265 ++++++++++++ hwc2_device/hwc2_device.cpp | 189 ++++----- 15 files changed, 1333 insertions(+), 1309 deletions(-) create mode 100644 hwc2_device/HwcDisplay.cpp create mode 100644 hwc2_device/HwcDisplay.h diff --git a/.ci/Makefile b/.ci/Makefile index c85dd88..ebe534f 100644 --- a/.ci/Makefile +++ b/.ci/Makefile @@ -37,6 +37,8 @@ TIDY_FILES_OVERRIDE := \ drm/DrmProperty.cpp:COARSE \ drm/UEventListener.cpp:COARSE \ drm/VSyncWorker.cpp:COARSE \ + hwc2_device/HwcDisplay.cpp:COARSE \ + hwc2_device/HwcDisplay.h:COARSE \ tests/worker_test.cpp:COARSE \ utils/Worker.h:COARSE \ utils/UniqueFd.h:FINE \ diff --git a/Android.bp b/Android.bp index 0a05376..d72e13a 100644 --- a/Android.bp +++ b/Android.bp @@ -110,6 +110,7 @@ filegroup { "backend/BackendManager.cpp", "backend/BackendRCarDu.cpp", + "hwc2_device/HwcDisplay.cpp", "hwc2_device/HwcLayer.cpp", "hwc2_device/hwc2_device.cpp", ], diff --git a/DrmHwcTwo.cpp b/DrmHwcTwo.cpp index 76fecf9..5bbb48a 100644 --- a/DrmHwcTwo.cpp +++ b/DrmHwcTwo.cpp @@ -14,27 +14,12 @@ * limitations under the License. */ -#define ATRACE_TAG ATRACE_TAG_GRAPHICS #define LOG_TAG "hwc-drm-two" #include "DrmHwcTwo.h" -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "backend/BackendManager.h" -#include "bufferinfo/BufferInfoGetter.h" -#include "compositor/DrmDisplayComposition.h" +#include "backend/Backend.h" #include "utils/log.h" -#include "utils/properties.h" namespace android { @@ -100,60 +85,6 @@ HWC2::Error DrmHwcTwo::DestroyVirtualDisplay(hwc2_display_t /*display*/) { return HWC2::Error::Unsupported; } -std::string DrmHwcTwo::HwcDisplay::DumpDelta( - DrmHwcTwo::HwcDisplay::Stats delta) { - if (delta.total_pixops_ == 0) - return "No stats yet"; - double ratio = 1.0 - double(delta.gpu_pixops_) / double(delta.total_pixops_); - - std::stringstream ss; - ss << " Total frames count: " << delta.total_frames_ << "\n" - << " Failed to test commit frames: " << delta.failed_kms_validate_ << "\n" - << " Failed to commit frames: " << delta.failed_kms_present_ << "\n" - << ((delta.failed_kms_present_ > 0) - ? " !!! Internal failure, FIX it please\n" - : "") - << " Flattened frames: " << delta.frames_flattened_ << "\n" - << " Pixel operations (free units)" - << " : [TOTAL: " << delta.total_pixops_ << " / GPU: " << delta.gpu_pixops_ - << "]\n" - << " Composition efficiency: " << ratio; - - return ss.str(); -} - -std::string DrmHwcTwo::HwcDisplay::Dump() { - std::string flattening_state_str; - switch (flattenning_state_) { - case ClientFlattenningState::Disabled: - flattening_state_str = "Disabled"; - break; - case ClientFlattenningState::NotRequired: - flattening_state_str = "Not needed"; - break; - case ClientFlattenningState::Flattened: - flattening_state_str = "Active"; - break; - case ClientFlattenningState::ClientRefreshRequested: - flattening_state_str = "Refresh requested"; - break; - default: - flattening_state_str = std::to_string(flattenning_state_) + - " VSync remains"; - } - - std::stringstream ss; - ss << "- Display on: " << connector_->name() << "\n" - << " Flattening state: " << flattening_state_str << "\n" - << "Statistics since system boot:\n" - << DumpDelta(total_stats_) << "\n\n" - << "Statistics since last dumpsys request:\n" - << DumpDelta(total_stats_.minus(prev_stats_)) << "\n\n"; - - memcpy(&prev_stats_, &total_stats_, sizeof(Stats)); - return ss.str(); -} - void DrmHwcTwo::Dump(uint32_t *outSize, char *outBuffer) { if (outBuffer != nullptr) { auto copied_bytes = mDumpString.copy(outBuffer, *outSize); @@ -165,7 +96,7 @@ void DrmHwcTwo::Dump(uint32_t *outSize, char *outBuffer) { output << "-- drm_hwcomposer --\n\n"; - for (std::pair &dp : displays_) + for (std::pair &dp : displays_) output << dp.second.Dump(); mDumpString = output.str(); @@ -211,880 +142,6 @@ HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor, return HWC2::Error::None; } -DrmHwcTwo::HwcDisplay::HwcDisplay(ResourceManager *resource_manager, - DrmDevice *drm, hwc2_display_t handle, - HWC2::DisplayType type, DrmHwcTwo *hwc2) - : hwc2_(hwc2), - resource_manager_(resource_manager), - drm_(drm), - handle_(handle), - type_(type), - color_transform_hint_(HAL_COLOR_TRANSFORM_IDENTITY) { - // clang-format off - color_transform_matrix_ = {1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0}; - // clang-format on -} - -void DrmHwcTwo::HwcDisplay::ClearDisplay() { - AtomicCommitArgs a_args = {.clear_active_composition = true}; - compositor_.ExecuteAtomicCommit(a_args); -} - -HWC2::Error DrmHwcTwo::HwcDisplay::Init(std::vector *planes) { - int display = static_cast(handle_); - int ret = compositor_.Init(resource_manager_, display); - if (ret) { - ALOGE("Failed display compositor init for display %d (%d)", display, ret); - return HWC2::Error::NoResources; - } - - // Split up the given display planes into primary and overlay to properly - // interface with the composition - char use_overlay_planes_prop[PROPERTY_VALUE_MAX]; - property_get("vendor.hwc.drm.use_overlay_planes", use_overlay_planes_prop, - "1"); - bool use_overlay_planes = strtol(use_overlay_planes_prop, nullptr, 10); - for (auto &plane : *planes) { - if (plane->GetType() == DRM_PLANE_TYPE_PRIMARY) - primary_planes_.push_back(plane); - else if (use_overlay_planes && (plane)->GetType() == DRM_PLANE_TYPE_OVERLAY) - overlay_planes_.push_back(plane); - } - - crtc_ = drm_->GetCrtcForDisplay(display); - if (!crtc_) { - ALOGE("Failed to get crtc for display %d", display); - return HWC2::Error::BadDisplay; - } - - connector_ = drm_->GetConnectorForDisplay(display); - if (!connector_) { - ALOGE("Failed to get connector for display %d", display); - return HWC2::Error::BadDisplay; - } - - ret = vsync_worker_.Init(drm_, display, [this](int64_t timestamp) { - const std::lock_guard lock(hwc2_->callback_lock_); - /* vsync callback */ -#if PLATFORM_SDK_VERSION > 29 - if (hwc2_->vsync_2_4_callback_.first != nullptr && - hwc2_->vsync_2_4_callback_.second != nullptr) { - hwc2_vsync_period_t period_ns{}; - GetDisplayVsyncPeriod(&period_ns); - hwc2_->vsync_2_4_callback_.first(hwc2_->vsync_2_4_callback_.second, - handle_, timestamp, period_ns); - } else -#endif - if (hwc2_->vsync_callback_.first != nullptr && - hwc2_->vsync_callback_.second != nullptr) { - hwc2_->vsync_callback_.first(hwc2_->vsync_callback_.second, handle_, - timestamp); - } - }); - if (ret) { - ALOGE("Failed to create event worker for d=%d %d\n", display, ret); - return HWC2::Error::BadDisplay; - } - - ret = flattening_vsync_worker_.Init(drm_, display, [this](int64_t /*timestamp*/) { - const std::lock_guard lock(hwc2_->callback_lock_); - /* Frontend flattening */ - if (flattenning_state_ > ClientFlattenningState::ClientRefreshRequested && - --flattenning_state_ == - ClientFlattenningState::ClientRefreshRequested && - hwc2_->refresh_callback_.first != nullptr && - hwc2_->refresh_callback_.second != nullptr) { - hwc2_->refresh_callback_.first(hwc2_->refresh_callback_.second, handle_); - flattening_vsync_worker_.VSyncControl(false); - } - }); - if (ret) { - ALOGE("Failed to create event worker for d=%d %d\n", display, ret); - return HWC2::Error::BadDisplay; - } - - ret = BackendManager::GetInstance().SetBackendForDisplay(this); - if (ret) { - ALOGE("Failed to set backend for d=%d %d\n", display, ret); - return HWC2::Error::BadDisplay; - } - - client_layer_.SetLayerBlendMode(HWC2_BLEND_MODE_PREMULTIPLIED); - - return ChosePreferredConfig(); -} - -HWC2::Error DrmHwcTwo::HwcDisplay::ChosePreferredConfig() { - // Fetch the number of modes from the display - uint32_t num_configs = 0; - HWC2::Error err = GetDisplayConfigs(&num_configs, nullptr); - if (err != HWC2::Error::None || !num_configs) - return HWC2::Error::BadDisplay; - - return SetActiveConfig(preferred_config_id_); -} - -HWC2::Error DrmHwcTwo::HwcDisplay::AcceptDisplayChanges() { - for (std::pair &l : layers_) - l.second.AcceptTypeChange(); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::CreateLayer(hwc2_layer_t *layer) { - layers_.emplace(static_cast(layer_idx_), HwcLayer()); - *layer = static_cast(layer_idx_); - ++layer_idx_; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::DestroyLayer(hwc2_layer_t layer) { - if (!get_layer(layer)) - return HWC2::Error::BadLayer; - - layers_.erase(layer); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetActiveConfig( - hwc2_config_t *config) const { - if (hwc_configs_.count(active_config_id_) == 0) - return HWC2::Error::BadConfig; - - *config = active_config_id_; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetChangedCompositionTypes( - uint32_t *num_elements, hwc2_layer_t *layers, int32_t *types) { - uint32_t num_changes = 0; - for (std::pair &l : layers_) { - if (l.second.IsTypeChanged()) { - if (layers && num_changes < *num_elements) - layers[num_changes] = l.first; - if (types && num_changes < *num_elements) - types[num_changes] = static_cast(l.second.GetValidatedType()); - ++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) { - std::pair min = drm_->min_resolution(); - std::pair 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) - return HWC2::Error::Unsupported; - - // TODO(nobody): 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) { - 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) { - int conf = static_cast(config); - - if (hwc_configs_.count(conf) == 0) { - ALOGE("Could not find active mode for %d", conf); - return HWC2::Error::BadConfig; - } - - auto &hwc_config = hwc_configs_[conf]; - - static const int32_t kUmPerInch = 25400; - uint32_t mm_width = connector_->mm_width(); - uint32_t mm_height = connector_->mm_height(); - auto attribute = static_cast(attribute_in); - switch (attribute) { - case HWC2::Attribute::Width: - *value = static_cast(hwc_config.mode.h_display()); - break; - case HWC2::Attribute::Height: - *value = static_cast(hwc_config.mode.v_display()); - break; - case HWC2::Attribute::VsyncPeriod: - // in nanoseconds - *value = static_cast(1E9 / hwc_config.mode.v_refresh()); - break; - case HWC2::Attribute::DpiX: - // Dots per 1000 inches - *value = mm_width ? static_cast(hwc_config.mode.h_display() * - kUmPerInch / mm_width) - : -1; - break; - case HWC2::Attribute::DpiY: - // Dots per 1000 inches - *value = mm_height ? static_cast(hwc_config.mode.v_display() * - kUmPerInch / mm_height) - : -1; - break; -#if PLATFORM_SDK_VERSION > 29 - case HWC2::Attribute::ConfigGroup: - /* Dispite ConfigGroup is a part of HWC2.4 API, framework - * able to request it even if service @2.1 is used */ - *value = hwc_config.group_id; - break; -#endif - default: - *value = -1; - return HWC2::Error::BadConfig; - } - return HWC2::Error::None; -} - -// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayConfigs(uint32_t *num_configs, - hwc2_config_t *configs) { - // 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) { - int ret = connector_->UpdateModes(); - if (ret) { - ALOGE("Failed to update display modes %d", ret); - return HWC2::Error::BadDisplay; - } - - hwc_configs_.clear(); - preferred_config_id_ = 0; - int preferred_config_group_id_ = 0; - - if (connector_->modes().empty()) { - ALOGE("No modes reported by KMS"); - return HWC2::Error::BadDisplay; - } - - int last_config_id = 1; - int last_group_id = 1; - - /* Group modes */ - for (const auto &mode : connector_->modes()) { - /* Find group for the new mode or create new group */ - int group_found = 0; - for (auto &hwc_config : hwc_configs_) { - if (mode.h_display() == hwc_config.second.mode.h_display() && - mode.v_display() == hwc_config.second.mode.v_display()) { - group_found = hwc_config.second.group_id; - } - } - if (group_found == 0) { - group_found = last_group_id++; - } - - bool disabled = false; - if (mode.flags() & DRM_MODE_FLAG_3D_MASK) { - ALOGI("Disabling display mode %s (Modes with 3D flag aren't supported)", - mode.name().c_str()); - disabled = true; - } - - /* Add config */ - hwc_configs_[last_config_id] = { - .id = last_config_id, - .group_id = group_found, - .mode = mode, - .disabled = disabled, - }; - - /* Chwck if the mode is preferred */ - if ((mode.type() & DRM_MODE_TYPE_PREFERRED) != 0 && - preferred_config_id_ == 0) { - preferred_config_id_ = last_config_id; - preferred_config_group_id_ = group_found; - } - - last_config_id++; - } - - /* We must have preferred mode. Set first mode as preferred - * in case KMS haven't reported anything. */ - if (preferred_config_id_ == 0) { - preferred_config_id_ = 1; - preferred_config_group_id_ = 1; - } - - for (int group = 1; group < last_group_id; group++) { - bool has_interlaced = false; - bool has_progressive = false; - for (auto &hwc_config : hwc_configs_) { - if (hwc_config.second.group_id != group || hwc_config.second.disabled) { - continue; - } - - if (hwc_config.second.IsInterlaced()) { - has_interlaced = true; - } else { - has_progressive = true; - } - } - - bool has_both = has_interlaced && has_progressive; - if (!has_both) { - continue; - } - - bool group_contains_preferred_interlaced = false; - if (group == preferred_config_group_id_ && - hwc_configs_[preferred_config_id_].IsInterlaced()) { - group_contains_preferred_interlaced = true; - } - - for (auto &hwc_config : hwc_configs_) { - if (hwc_config.second.group_id != group || hwc_config.second.disabled) { - continue; - } - - bool disable = group_contains_preferred_interlaced - ? !hwc_config.second.IsInterlaced() - : hwc_config.second.IsInterlaced(); - - if (disable) { - ALOGI( - "Group %i: Disabling display mode %s (This group should consist " - "of %s modes)", - group, hwc_config.second.mode.name().c_str(), - group_contains_preferred_interlaced ? "interlaced" - : "progressive"); - - hwc_config.second.disabled = true; - } - } - } - - /* Group should not contain 2 modes with FPS delta less than ~1HZ - * otherwise android.graphics.cts.SetFrameRateTest CTS will fail - */ - for (int m1 = 1; m1 < last_config_id; m1++) { - for (int m2 = 1; m2 < last_config_id; m2++) { - if (m1 != m2 && - hwc_configs_[m1].group_id == hwc_configs_[m2].group_id && - !hwc_configs_[m1].disabled && !hwc_configs_[m2].disabled && - fabsf(hwc_configs_[m1].mode.v_refresh() - - hwc_configs_[m2].mode.v_refresh()) < 1.0) { - ALOGI( - "Group %i: Disabling display mode %s (Refresh rate value is " - "too close to existing mode %s)", - hwc_configs_[m2].group_id, hwc_configs_[m2].mode.name().c_str(), - hwc_configs_[m1].mode.name().c_str()); - - hwc_configs_[m2].disabled = true; - } - } - } - } - - uint32_t idx = 0; - for (auto &hwc_config : hwc_configs_) { - if (hwc_config.second.disabled) { - continue; - } - - if (configs != nullptr) { - if (idx >= *num_configs) { - break; - } - configs[idx] = hwc_config.second.id; - } - - idx++; - } - *num_configs = idx; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayName(uint32_t *size, char *name) { - 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(static_cast(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*/) { - // TODO(nobody): I think virtual display should request - // HWC2_DISPLAY_REQUEST_WRITE_CLIENT_TARGET_TO_OUTPUT here - *num_elements = 0; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayType(int32_t *type) { - *type = static_cast(type_); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDozeSupport(int32_t *support) { - *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*/) { - *num_types = 0; - return HWC2::Error::None; -} - -/* Find API details at: - * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1767 - */ -HWC2::Error DrmHwcTwo::HwcDisplay::GetReleaseFences(uint32_t *num_elements, - hwc2_layer_t *layers, - int32_t *fences) { - uint32_t num_layers = 0; - - for (std::pair &l : layers_) { - ++num_layers; - if (layers == nullptr || fences == nullptr) - continue; - - 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.GetReleaseFence().Release(); - } - *num_elements = num_layers; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) { - // order the layers by z-order - bool use_client_layer = false; - uint32_t client_z_order = UINT32_MAX; - std::map z_map; - for (std::pair &l : layers_) { - switch (l.second.GetValidatedType()) { - case HWC2::Composition::Device: - z_map.emplace(std::make_pair(l.second.GetZOrder(), &l.second)); - break; - case HWC2::Composition::Client: - // Place it at the z_order of the lowest client layer - use_client_layer = true; - client_z_order = std::min(client_z_order, l.second.GetZOrder()); - break; - default: - continue; - } - } - if (use_client_layer) - z_map.emplace(std::make_pair(client_z_order, &client_layer_)); - - if (z_map.empty()) - return HWC2::Error::BadLayer; - - std::vector composition_layers; - - // now that they're ordered by z, add them to the composition - for (std::pair &l : z_map) { - DrmHwcLayer layer; - l.second->PopulateDrmLayer(&layer); - int ret = layer.ImportBuffer(drm_); - if (ret) { - ALOGE("Failed to import layer, ret=%d", ret); - return HWC2::Error::NoResources; - } - composition_layers.emplace_back(std::move(layer)); - } - - auto composition = std::make_shared(crtc_); - - // TODO(nobody): Don't always assume geometry changed - int ret = composition->SetLayers(composition_layers.data(), - composition_layers.size()); - if (ret) { - ALOGE("Failed to set layers in the composition ret=%d", ret); - return HWC2::Error::BadLayer; - } - - std::vector primary_planes(primary_planes_); - std::vector overlay_planes(overlay_planes_); - ret = composition->Plan(&primary_planes, &overlay_planes); - if (ret) { - ALOGV("Failed to plan the composition ret=%d", ret); - return HWC2::Error::BadConfig; - } - - a_args.composition = composition; - if (staged_mode) { - a_args.display_mode = *staged_mode; - } - ret = compositor_.ExecuteAtomicCommit(a_args); - - if (ret) { - if (!a_args.test_only) - ALOGE("Failed to apply the frame composition ret=%d", ret); - return HWC2::Error::BadParameter; - } - - if (!a_args.test_only) { - staged_mode.reset(); - } - - return HWC2::Error::None; -} - -/* Find API details at: - * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1805 - */ -HWC2::Error DrmHwcTwo::HwcDisplay::PresentDisplay(int32_t *present_fence) { - HWC2::Error ret; - - ++total_stats_.total_frames_; - - AtomicCommitArgs a_args{}; - ret = CreateComposition(a_args); - - if (ret != HWC2::Error::None) - ++total_stats_.failed_kms_present_; - - if (ret == HWC2::Error::BadLayer) { - // Can we really have no client or device layers? - *present_fence = -1; - return HWC2::Error::None; - } - if (ret != HWC2::Error::None) - return ret; - - *present_fence = a_args.out_fence.Release(); - - ++frame_no_; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetActiveConfig(hwc2_config_t config) { - int conf = static_cast(config); - - if (hwc_configs_.count(conf) == 0) { - ALOGE("Could not find active mode for %d", conf); - return HWC2::Error::BadConfig; - } - - auto &mode = hwc_configs_[conf].mode; - - staged_mode = mode; - - active_config_id_ = conf; - - // Setup the client layer's dimensions - hwc_rect_t display_frame = {.left = 0, - .top = 0, - .right = static_cast(mode.h_display()), - .bottom = static_cast(mode.v_display())}; - client_layer_.SetLayerDisplayFrame(display_frame); - - return HWC2::Error::None; -} - -/* Find API details at: - * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1861 - */ -HWC2::Error DrmHwcTwo::HwcDisplay::SetClientTarget(buffer_handle_t target, - int32_t acquire_fence, - int32_t dataspace, - hwc_region_t /*damage*/) { - client_layer_.SetLayerBuffer(target, acquire_fence); - client_layer_.SetLayerDataspace(dataspace); - - /* - * target can be nullptr, this does mean the Composer Service is calling - * cleanDisplayResources() on after receiving HOTPLUG event. See more at: - * https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h;l=350;drc=944b68180b008456ed2eb4d4d329e33b19bd5166 - */ - if (target == nullptr) { - return HWC2::Error::None; - } - - /* TODO: Do not update source_crop every call. - * It makes sense to do it once after every hotplug event. */ - HwcDrmBo bo{}; - BufferInfoGetter::GetInstance()->ConvertBoInfo(target, &bo); - - hwc_frect_t source_crop = {.left = 0.0F, - .top = 0.0F, - .right = static_cast(bo.width), - .bottom = static_cast(bo.height)}; - client_layer_.SetLayerSourceCrop(source_crop); - - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetColorMode(int32_t mode) { - if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_BT2100_HLG) - return HWC2::Error::BadParameter; - - if (mode != HAL_COLOR_MODE_NATIVE) - return HWC2::Error::Unsupported; - - color_mode_ = mode; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetColorTransform(const float *matrix, - int32_t hint) { - if (hint < HAL_COLOR_TRANSFORM_IDENTITY || - hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA) - return HWC2::Error::BadParameter; - - if (!matrix && hint == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX) - return HWC2::Error::BadParameter; - - color_transform_hint_ = static_cast(hint); - if (color_transform_hint_ == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX) - std::copy(matrix, matrix + MATRIX_SIZE, color_transform_matrix_.begin()); - - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetOutputBuffer(buffer_handle_t /*buffer*/, - int32_t /*release_fence*/) { - // TODO(nobody): Need virtual display support - return HWC2::Error::Unsupported; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetPowerMode(int32_t mode_in) { - auto mode = static_cast(mode_in); - AtomicCommitArgs a_args{}; - - switch (mode) { - case HWC2::PowerMode::Off: - a_args.active = false; - break; - case HWC2::PowerMode::On: - /* - * Setting the display to active before we have a composition - * can break some drivers, so skip setting a_args.active to - * true, as the next composition frame will implicitly activate - * the display - */ - return HWC2::Error::None; - break; - case HWC2::PowerMode::Doze: - case HWC2::PowerMode::DozeSuspend: - return HWC2::Error::Unsupported; - default: - ALOGI("Power mode %d is unsupported\n", mode); - return HWC2::Error::BadParameter; - }; - - int err = compositor_.ExecuteAtomicCommit(a_args); - if (err) { - ALOGE("Failed to apply the dpms composition err=%d", err); - return HWC2::Error::BadParameter; - } - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetVsyncEnabled(int32_t enabled) { - vsync_worker_.VSyncControl(HWC2_VSYNC_ENABLE == enabled); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::ValidateDisplay(uint32_t *num_types, - uint32_t *num_requests) { - return backend_->ValidateDisplay(this, num_types, num_requests); -} - -std::vector DrmHwcTwo::HwcDisplay::GetOrderLayersByZPos() { - std::vector ordered_layers; - ordered_layers.reserve(layers_.size()); - - for (auto &[handle, layer] : layers_) { - ordered_layers.emplace_back(&layer); - } - - std::sort(std::begin(ordered_layers), std::end(ordered_layers), - [](const HwcLayer *lhs, const HwcLayer *rhs) { - return lhs->GetZOrder() < rhs->GetZOrder(); - }); - - return ordered_layers; -} - -#if PLATFORM_SDK_VERSION > 29 -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayConnectionType(uint32_t *outType) { - if (connector_->internal()) - *outType = static_cast(HWC2::DisplayConnectionType::Internal); - else if (connector_->external()) - *outType = static_cast(HWC2::DisplayConnectionType::External); - else - return HWC2::Error::BadConfig; - - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayVsyncPeriod( - hwc2_vsync_period_t *outVsyncPeriod /* ns */) { - return GetDisplayAttribute(active_config_id_, HWC2_ATTRIBUTE_VSYNC_PERIOD, - (int32_t *)(outVsyncPeriod)); -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetActiveConfigWithConstraints( - hwc2_config_t /*config*/, - hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints, - hwc_vsync_period_change_timeline_t *outTimeline) { - if (vsyncPeriodChangeConstraints == nullptr || outTimeline == nullptr) { - return HWC2::Error::BadParameter; - } - - return HWC2::Error::BadConfig; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetAutoLowLatencyMode(bool /*on*/) { - return HWC2::Error::Unsupported; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetSupportedContentTypes( - uint32_t *outNumSupportedContentTypes, - const uint32_t *outSupportedContentTypes) { - if (outSupportedContentTypes == nullptr) - *outNumSupportedContentTypes = 0; - - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetContentType(int32_t contentType) { - if (contentType != HWC2_CONTENT_TYPE_NONE) - return HWC2::Error::Unsupported; - - /* TODO: Map to the DRM Connector property: - * https://elixir.bootlin.com/linux/v5.4-rc5/source/drivers/gpu/drm/drm_connector.c#L809 - */ - - return HWC2::Error::None; -} -#endif - -#if PLATFORM_SDK_VERSION > 28 -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayIdentificationData( - uint8_t *outPort, uint32_t *outDataSize, uint8_t *outData) { - auto blob = connector_->GetEdidBlob(); - - if (!blob) { - ALOGE("Failed to get edid property value."); - return HWC2::Error::Unsupported; - } - - if (outData) { - *outDataSize = std::min(*outDataSize, blob->length); - memcpy(outData, blob->data, *outDataSize); - } else { - *outDataSize = blob->length; - } - *outPort = connector_->id(); - - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayCapabilities( - uint32_t *outNumCapabilities, uint32_t * /*outCapabilities*/) { - if (outNumCapabilities == nullptr) { - return HWC2::Error::BadParameter; - } - - *outNumCapabilities = 0; - - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayBrightnessSupport( - bool *supported) { - *supported = false; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetDisplayBrightness( - float /* brightness */) { - return HWC2::Error::Unsupported; -} - -#endif /* PLATFORM_SDK_VERSION > 28 */ - -#if PLATFORM_SDK_VERSION > 27 - -HWC2::Error DrmHwcTwo::HwcDisplay::GetRenderIntents( - int32_t mode, uint32_t *outNumIntents, - int32_t * /*android_render_intent_v1_1_t*/ outIntents) { - if (mode != HAL_COLOR_MODE_NATIVE) { - return HWC2::Error::BadParameter; - } - - if (outIntents == nullptr) { - *outNumIntents = 1; - return HWC2::Error::None; - } - *outNumIntents = 1; - outIntents[0] = HAL_RENDER_INTENT_COLORIMETRIC; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetColorModeWithIntent(int32_t mode, - int32_t intent) { - if (intent < HAL_RENDER_INTENT_COLORIMETRIC || - intent > HAL_RENDER_INTENT_TONE_MAP_ENHANCE) - return HWC2::Error::BadParameter; - - if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_BT2100_HLG) - return HWC2::Error::BadParameter; - - if (mode != HAL_COLOR_MODE_NATIVE) - return HWC2::Error::Unsupported; - - if (intent != HAL_RENDER_INTENT_COLORIMETRIC) - return HWC2::Error::Unsupported; - - color_mode_ = mode; - return HWC2::Error::None; -} - -#endif /* PLATFORM_SDK_VERSION > 27 */ - -const Backend *DrmHwcTwo::HwcDisplay::backend() const { - return backend_.get(); -} - -void DrmHwcTwo::HwcDisplay::set_backend(std::unique_ptr backend) { - backend_ = std::move(backend); -} - void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) { const std::lock_guard lock(callback_lock_); diff --git a/DrmHwcTwo.h b/DrmHwcTwo.h index de70199..d096160 100644 --- a/DrmHwcTwo.h +++ b/DrmHwcTwo.h @@ -19,21 +19,11 @@ #include -#include -#include -#include -#include - -#include "compositor/DrmDisplayCompositor.h" #include "drm/ResourceManager.h" -#include "drm/VSyncWorker.h" -#include "drmhwcomposer.h" -#include "hwc2_device/HwcLayer.h" +#include "hwc2_device/HwcDisplay.h" namespace android { -class Backend; - class DrmHwcTwo { public: DrmHwcTwo(); @@ -49,236 +39,6 @@ class DrmHwcTwo { std::mutex callback_lock_; - class HwcDisplay { - public: - HwcDisplay(ResourceManager *resource_manager, DrmDevice *drm, - hwc2_display_t handle, HWC2::DisplayType type, DrmHwcTwo *hwc2); - HwcDisplay(const HwcDisplay &) = delete; - HWC2::Error Init(std::vector *planes); - - HWC2::Error CreateComposition(AtomicCommitArgs &a_args); - std::vector GetOrderLayersByZPos(); - - void ClearDisplay(); - - std::string Dump(); - - // HWC Hooks - HWC2::Error AcceptDisplayChanges(); - HWC2::Error CreateLayer(hwc2_layer_t *layer); - HWC2::Error DestroyLayer(hwc2_layer_t layer); - HWC2::Error GetActiveConfig(hwc2_config_t *config) const; - HWC2::Error GetChangedCompositionTypes(uint32_t *num_elements, - hwc2_layer_t *layers, - int32_t *types); - HWC2::Error GetClientTargetSupport(uint32_t width, uint32_t height, - int32_t format, int32_t dataspace); - HWC2::Error GetColorModes(uint32_t *num_modes, int32_t *modes); - HWC2::Error GetDisplayAttribute(hwc2_config_t config, int32_t attribute, - int32_t *value); - HWC2::Error GetDisplayConfigs(uint32_t *num_configs, - hwc2_config_t *configs); - HWC2::Error GetDisplayName(uint32_t *size, char *name); - HWC2::Error GetDisplayRequests(int32_t *display_requests, - uint32_t *num_elements, hwc2_layer_t *layers, - int32_t *layer_requests); - HWC2::Error GetDisplayType(int32_t *type); -#if PLATFORM_SDK_VERSION > 27 - HWC2::Error GetRenderIntents(int32_t mode, uint32_t *outNumIntents, - int32_t *outIntents); - HWC2::Error SetColorModeWithIntent(int32_t mode, int32_t intent); -#endif -#if PLATFORM_SDK_VERSION > 28 - HWC2::Error GetDisplayIdentificationData(uint8_t *outPort, - uint32_t *outDataSize, - uint8_t *outData); - HWC2::Error GetDisplayCapabilities(uint32_t *outNumCapabilities, - uint32_t *outCapabilities); - HWC2::Error GetDisplayBrightnessSupport(bool *supported); - HWC2::Error SetDisplayBrightness(float); -#endif -#if PLATFORM_SDK_VERSION > 29 - HWC2::Error GetDisplayConnectionType(uint32_t *outType); - HWC2::Error GetDisplayVsyncPeriod(hwc2_vsync_period_t *outVsyncPeriod); - - HWC2::Error SetActiveConfigWithConstraints( - hwc2_config_t config, - hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints, - hwc_vsync_period_change_timeline_t *outTimeline); - HWC2::Error SetAutoLowLatencyMode(bool on); - HWC2::Error GetSupportedContentTypes( - uint32_t *outNumSupportedContentTypes, - const uint32_t *outSupportedContentTypes); - - HWC2::Error SetContentType(int32_t contentType); -#endif - - HWC2::Error GetDozeSupport(int32_t *support); - HWC2::Error GetHdrCapabilities(uint32_t *num_types, int32_t *types, - float *max_luminance, - float *max_average_luminance, - float *min_luminance); - HWC2::Error GetReleaseFences(uint32_t *num_elements, hwc2_layer_t *layers, - int32_t *fences); - HWC2::Error PresentDisplay(int32_t *present_fence); - HWC2::Error SetActiveConfig(hwc2_config_t config); - HWC2::Error ChosePreferredConfig(); - HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence, - int32_t dataspace, hwc_region_t damage); - HWC2::Error SetColorMode(int32_t mode); - HWC2::Error SetColorTransform(const float *matrix, int32_t hint); - HWC2::Error SetOutputBuffer(buffer_handle_t buffer, int32_t release_fence); - HWC2::Error SetPowerMode(int32_t mode); - HWC2::Error SetVsyncEnabled(int32_t enabled); - HWC2::Error ValidateDisplay(uint32_t *num_types, uint32_t *num_requests); - HwcLayer *get_layer(hwc2_layer_t layer) { - auto it = layers_.find(layer); - if (it == layers_.end()) - return nullptr; - return &it->second; - } - - /* Statistics */ - struct Stats { - Stats minus(Stats b) const { - return {total_frames_ - b.total_frames_, - total_pixops_ - b.total_pixops_, - gpu_pixops_ - b.gpu_pixops_, - failed_kms_validate_ - b.failed_kms_validate_, - failed_kms_present_ - b.failed_kms_present_, - frames_flattened_ - b.frames_flattened_}; - } - - uint32_t total_frames_ = 0; - uint64_t total_pixops_ = 0; - uint64_t gpu_pixops_ = 0; - uint32_t failed_kms_validate_ = 0; - uint32_t failed_kms_present_ = 0; - uint32_t frames_flattened_ = 0; - }; - - struct HwcDisplayConfig { - int id{}; - int group_id{}; - DrmMode mode; - bool disabled{}; - - bool IsInterlaced() const { - return (mode.flags() & DRM_MODE_FLAG_INTERLACE) != 0; - } - }; - - std::map hwc_configs_; - - int active_config_id_ = 0; - int preferred_config_id_ = 0; - - const Backend *backend() const; - void set_backend(std::unique_ptr backend); - - const std::vector &primary_planes() const { - return primary_planes_; - } - - const std::vector &overlay_planes() const { - return overlay_planes_; - } - - std::map &layers() { - return layers_; - } - - const DrmDisplayCompositor &compositor() const { - return compositor_; - } - - const DrmDevice *drm() const { - return drm_; - } - - const DrmConnector *connector() const { - return connector_; - } - - ResourceManager *resource_manager() const { - return resource_manager_; - } - - android_color_transform_t &color_transform_hint() { - return color_transform_hint_; - } - - Stats &total_stats() { - return total_stats_; - } - - /* returns true if composition should be sent to client */ - bool ProcessClientFlatteningState(bool skip) { - int flattenning_state = flattenning_state_; - if (flattenning_state == ClientFlattenningState::Disabled) { - return false; - } - - if (skip) { - flattenning_state_ = ClientFlattenningState::NotRequired; - return false; - } - - if (flattenning_state == ClientFlattenningState::ClientRefreshRequested) { - flattenning_state_ = ClientFlattenningState::Flattened; - return true; - } - - flattening_vsync_worker_.VSyncControl(true); - flattenning_state_ = ClientFlattenningState::VsyncCountdownMax; - return false; - } - - private: - enum ClientFlattenningState : int32_t { - Disabled = -3, - NotRequired = -2, - Flattened = -1, - ClientRefreshRequested = 0, - VsyncCountdownMax = 60, /* 1 sec @ 60FPS */ - }; - - std::atomic_int flattenning_state_{ClientFlattenningState::NotRequired}; - VSyncWorker flattening_vsync_worker_; - - constexpr static size_t MATRIX_SIZE = 16; - - DrmHwcTwo *hwc2_; - - std::optional staged_mode; - - ResourceManager *resource_manager_; - DrmDevice *drm_; - DrmDisplayCompositor compositor_; - - std::vector primary_planes_; - std::vector overlay_planes_; - - std::unique_ptr backend_; - - VSyncWorker vsync_worker_; - DrmConnector *connector_ = nullptr; - DrmCrtc *crtc_ = nullptr; - hwc2_display_t handle_; - HWC2::DisplayType type_; - uint32_t layer_idx_ = 0; - std::map layers_; - HwcLayer client_layer_; - int32_t color_mode_{}; - std::array color_transform_matrix_{}; - android_color_transform_t color_transform_hint_; - - uint32_t frame_no_ = 0; - Stats total_stats_; - Stats prev_stats_; - std::string DumpDelta(DrmHwcTwo::HwcDisplay::Stats delta); - }; - static HwcDisplay *GetDisplay(DrmHwcTwo *hwc, hwc2_display_t display_handle) { auto it = hwc->displays_.find(display_handle); if (it == hwc->displays_.end()) diff --git a/backend/Backend.cpp b/backend/Backend.cpp index 7f87b05..98862ba 100644 --- a/backend/Backend.cpp +++ b/backend/Backend.cpp @@ -23,8 +23,7 @@ namespace android { -HWC2::Error Backend::ValidateDisplay(DrmHwcTwo::HwcDisplay *display, - uint32_t *num_types, +HWC2::Error Backend::ValidateDisplay(HwcDisplay *display, uint32_t *num_types, uint32_t *num_requests) { *num_types = 0; *num_requests = 0; @@ -67,7 +66,7 @@ HWC2::Error Backend::ValidateDisplay(DrmHwcTwo::HwcDisplay *display, } std::tuple Backend::GetClientLayers( - DrmHwcTwo::HwcDisplay *display, const std::vector &layers) { + HwcDisplay *display, const std::vector &layers) { int client_start = -1; size_t client_size = 0; @@ -82,7 +81,7 @@ std::tuple Backend::GetClientLayers( return GetExtraClientRange(display, layers, client_start, client_size); } -bool Backend::IsClientLayer(DrmHwcTwo::HwcDisplay *display, HwcLayer *layer) { +bool Backend::IsClientLayer(HwcDisplay *display, HwcLayer *layer) { return !HardwareSupportsLayerType(layer->GetSfType()) || !BufferInfoGetter::GetInstance()->IsHandleUsable(layer->GetBuffer()) || display->color_transform_hint() != HAL_COLOR_TRANSFORM_IDENTITY || @@ -118,7 +117,7 @@ void Backend::MarkValidated(std::vector &layers, } std::tuple Backend::GetExtraClientRange( - DrmHwcTwo::HwcDisplay *display, const std::vector &layers, + HwcDisplay *display, const std::vector &layers, int client_start, size_t client_size) { size_t avail_planes = display->primary_planes().size() + display->overlay_planes().size(); diff --git a/backend/Backend.h b/backend/Backend.h index 0273570..1a4833e 100644 --- a/backend/Backend.h +++ b/backend/Backend.h @@ -24,12 +24,11 @@ namespace android { class Backend { public: virtual ~Backend() = default; - virtual HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, - uint32_t *num_types, + virtual HWC2::Error ValidateDisplay(HwcDisplay *display, uint32_t *num_types, uint32_t *num_requests); virtual std::tuple GetClientLayers( - DrmHwcTwo::HwcDisplay *display, const std::vector &layers); - virtual bool IsClientLayer(DrmHwcTwo::HwcDisplay *display, HwcLayer *layer); + HwcDisplay *display, const std::vector &layers); + virtual bool IsClientLayer(HwcDisplay *display, HwcLayer *layer); protected: static bool HardwareSupportsLayerType(HWC2::Composition comp_type); @@ -38,7 +37,7 @@ class Backend { static void MarkValidated(std::vector &layers, size_t client_first_z, size_t client_size); static std::tuple GetExtraClientRange( - DrmHwcTwo::HwcDisplay *display, const std::vector &layers, + HwcDisplay *display, const std::vector &layers, int client_start, size_t client_size); }; } // namespace android diff --git a/backend/BackendClient.cpp b/backend/BackendClient.cpp index 73a3b3d..606dca2 100644 --- a/backend/BackendClient.cpp +++ b/backend/BackendClient.cpp @@ -20,10 +20,10 @@ namespace android { -HWC2::Error BackendClient::ValidateDisplay(DrmHwcTwo::HwcDisplay *display, +HWC2::Error BackendClient::ValidateDisplay(HwcDisplay *display, uint32_t *num_types, uint32_t * /*num_requests*/) { - for (auto & [ layer_handle, layer ] : display->layers()) { + for (auto &[layer_handle, layer] : display->layers()) { layer.SetValidatedType(HWC2::Composition::Client); ++*num_types; } diff --git a/backend/BackendClient.h b/backend/BackendClient.h index 13543f1..95abb0f 100644 --- a/backend/BackendClient.h +++ b/backend/BackendClient.h @@ -23,8 +23,7 @@ namespace android { class BackendClient : public Backend { public: - HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, - uint32_t *num_types, + HWC2::Error ValidateDisplay(HwcDisplay *display, uint32_t *num_types, uint32_t *num_requests) override; }; } // namespace android diff --git a/backend/BackendManager.cpp b/backend/BackendManager.cpp index 0577e2f..aadef36 100644 --- a/backend/BackendManager.cpp +++ b/backend/BackendManager.cpp @@ -41,7 +41,7 @@ int BackendManager::RegisterBackend(const std::string &name, return 0; } -int BackendManager::SetBackendForDisplay(DrmHwcTwo::HwcDisplay *display) { +int BackendManager::SetBackendForDisplay(HwcDisplay *display) { std::string driver_name(display->drm()->GetName()); char backend_override[PROPERTY_VALUE_MAX]; property_get("vendor.hwc.backend_override", backend_override, diff --git a/backend/BackendManager.h b/backend/BackendManager.h index 274484c..751cb78 100644 --- a/backend/BackendManager.h +++ b/backend/BackendManager.h @@ -41,10 +41,10 @@ class BackendManager { static BackendManager &GetInstance(); int RegisterBackend(const std::string &name, BackendConstructorT backend_constructor); - int SetBackendForDisplay(DrmHwcTwo::HwcDisplay *display); + int SetBackendForDisplay(HwcDisplay *display); std::unique_ptr GetBackendByName(std::string &name); - HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, - uint32_t *num_types, uint32_t *num_requests); + HWC2::Error ValidateDisplay(HwcDisplay *display, uint32_t *num_types, + uint32_t *num_requests); private: BackendManager() = default; diff --git a/backend/BackendRCarDu.cpp b/backend/BackendRCarDu.cpp index b319d89..0750ee4 100644 --- a/backend/BackendRCarDu.cpp +++ b/backend/BackendRCarDu.cpp @@ -22,8 +22,7 @@ namespace android { -bool BackendRCarDu::IsClientLayer(DrmHwcTwo::HwcDisplay *display, - HwcLayer *layer) { +bool BackendRCarDu::IsClientLayer(HwcDisplay *display, HwcLayer *layer) { hwc_drm_bo_t bo; int ret = BufferInfoGetter::GetInstance()->ConvertBoInfo(layer->GetBuffer(), diff --git a/backend/BackendRCarDu.h b/backend/BackendRCarDu.h index 862bef2..1259c9f 100644 --- a/backend/BackendRCarDu.h +++ b/backend/BackendRCarDu.h @@ -23,7 +23,7 @@ namespace android { class BackendRCarDu : public Backend { public: - bool IsClientLayer(DrmHwcTwo::HwcDisplay *display, HwcLayer *layer) override; + bool IsClientLayer(HwcDisplay *display, HwcLayer *layer) override; }; } // namespace android diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp new file mode 100644 index 0000000..e0a5823 --- /dev/null +++ b/hwc2_device/HwcDisplay.cpp @@ -0,0 +1,958 @@ +/* + * Copyright (C) 2022 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 LOG_TAG "hwc-display" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include "HwcDisplay.h" + +#include "DrmHwcTwo.h" +#include "backend/BackendManager.h" +#include "bufferinfo/BufferInfoGetter.h" +#include "utils/log.h" +#include "utils/properties.h" + +namespace android { + +std::string HwcDisplay::DumpDelta(HwcDisplay::Stats delta) { + if (delta.total_pixops_ == 0) + return "No stats yet"; + double ratio = 1.0 - double(delta.gpu_pixops_) / double(delta.total_pixops_); + + std::stringstream ss; + ss << " Total frames count: " << delta.total_frames_ << "\n" + << " Failed to test commit frames: " << delta.failed_kms_validate_ << "\n" + << " Failed to commit frames: " << delta.failed_kms_present_ << "\n" + << ((delta.failed_kms_present_ > 0) + ? " !!! Internal failure, FIX it please\n" + : "") + << " Flattened frames: " << delta.frames_flattened_ << "\n" + << " Pixel operations (free units)" + << " : [TOTAL: " << delta.total_pixops_ << " / GPU: " << delta.gpu_pixops_ + << "]\n" + << " Composition efficiency: " << ratio; + + return ss.str(); +} + +std::string HwcDisplay::Dump() { + std::string flattening_state_str; + switch (flattenning_state_) { + case ClientFlattenningState::Disabled: + flattening_state_str = "Disabled"; + break; + case ClientFlattenningState::NotRequired: + flattening_state_str = "Not needed"; + break; + case ClientFlattenningState::Flattened: + flattening_state_str = "Active"; + break; + case ClientFlattenningState::ClientRefreshRequested: + flattening_state_str = "Refresh requested"; + break; + default: + flattening_state_str = std::to_string(flattenning_state_) + + " VSync remains"; + } + + std::stringstream ss; + ss << "- Display on: " << connector_->name() << "\n" + << " Flattening state: " << flattening_state_str << "\n" + << "Statistics since system boot:\n" + << DumpDelta(total_stats_) << "\n\n" + << "Statistics since last dumpsys request:\n" + << DumpDelta(total_stats_.minus(prev_stats_)) << "\n\n"; + + memcpy(&prev_stats_, &total_stats_, sizeof(Stats)); + return ss.str(); +} + +HwcDisplay::HwcDisplay(ResourceManager *resource_manager, DrmDevice *drm, + hwc2_display_t handle, HWC2::DisplayType type, + DrmHwcTwo *hwc2) + : hwc2_(hwc2), + resource_manager_(resource_manager), + drm_(drm), + handle_(handle), + type_(type), + color_transform_hint_(HAL_COLOR_TRANSFORM_IDENTITY) { + // clang-format off + color_transform_matrix_ = {1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0}; + // clang-format on +} + +void HwcDisplay::ClearDisplay() { + AtomicCommitArgs a_args = {.clear_active_composition = true}; + compositor_.ExecuteAtomicCommit(a_args); +} + +HWC2::Error HwcDisplay::Init(std::vector *planes) { + int display = static_cast(handle_); + int ret = compositor_.Init(resource_manager_, display); + if (ret) { + ALOGE("Failed display compositor init for display %d (%d)", display, ret); + return HWC2::Error::NoResources; + } + + // Split up the given display planes into primary and overlay to properly + // interface with the composition + char use_overlay_planes_prop[PROPERTY_VALUE_MAX]; + property_get("vendor.hwc.drm.use_overlay_planes", use_overlay_planes_prop, + "1"); + bool use_overlay_planes = strtol(use_overlay_planes_prop, nullptr, 10); + for (auto &plane : *planes) { + if (plane->GetType() == DRM_PLANE_TYPE_PRIMARY) + primary_planes_.push_back(plane); + else if (use_overlay_planes && (plane)->GetType() == DRM_PLANE_TYPE_OVERLAY) + overlay_planes_.push_back(plane); + } + + crtc_ = drm_->GetCrtcForDisplay(display); + if (!crtc_) { + ALOGE("Failed to get crtc for display %d", display); + return HWC2::Error::BadDisplay; + } + + connector_ = drm_->GetConnectorForDisplay(display); + if (!connector_) { + ALOGE("Failed to get connector for display %d", display); + return HWC2::Error::BadDisplay; + } + + ret = vsync_worker_.Init(drm_, display, [this](int64_t timestamp) { + const std::lock_guard lock(hwc2_->callback_lock_); + /* vsync callback */ +#if PLATFORM_SDK_VERSION > 29 + if (hwc2_->vsync_2_4_callback_.first != nullptr && + hwc2_->vsync_2_4_callback_.second != nullptr) { + hwc2_vsync_period_t period_ns{}; + GetDisplayVsyncPeriod(&period_ns); + hwc2_->vsync_2_4_callback_.first(hwc2_->vsync_2_4_callback_.second, + handle_, timestamp, period_ns); + } else +#endif + if (hwc2_->vsync_callback_.first != nullptr && + hwc2_->vsync_callback_.second != nullptr) { + hwc2_->vsync_callback_.first(hwc2_->vsync_callback_.second, handle_, + timestamp); + } + }); + if (ret) { + ALOGE("Failed to create event worker for d=%d %d\n", display, ret); + return HWC2::Error::BadDisplay; + } + + ret = flattening_vsync_worker_ + .Init(drm_, display, [this](int64_t /*timestamp*/) { + const std::lock_guard lock(hwc2_->callback_lock_); + /* Frontend flattening */ + if (flattenning_state_ > + ClientFlattenningState::ClientRefreshRequested && + --flattenning_state_ == + ClientFlattenningState::ClientRefreshRequested && + hwc2_->refresh_callback_.first != nullptr && + hwc2_->refresh_callback_.second != nullptr) { + hwc2_->refresh_callback_.first(hwc2_->refresh_callback_.second, + handle_); + flattening_vsync_worker_.VSyncControl(false); + } + }); + if (ret) { + ALOGE("Failed to create event worker for d=%d %d\n", display, ret); + return HWC2::Error::BadDisplay; + } + + ret = BackendManager::GetInstance().SetBackendForDisplay(this); + if (ret) { + ALOGE("Failed to set backend for d=%d %d\n", display, ret); + return HWC2::Error::BadDisplay; + } + + client_layer_.SetLayerBlendMode(HWC2_BLEND_MODE_PREMULTIPLIED); + + return ChosePreferredConfig(); +} + +HWC2::Error HwcDisplay::ChosePreferredConfig() { + // Fetch the number of modes from the display + uint32_t num_configs = 0; + HWC2::Error err = GetDisplayConfigs(&num_configs, nullptr); + if (err != HWC2::Error::None || !num_configs) + return HWC2::Error::BadDisplay; + + return SetActiveConfig(preferred_config_id_); +} + +HWC2::Error HwcDisplay::AcceptDisplayChanges() { + for (std::pair &l : layers_) + l.second.AcceptTypeChange(); + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::CreateLayer(hwc2_layer_t *layer) { + layers_.emplace(static_cast(layer_idx_), HwcLayer()); + *layer = static_cast(layer_idx_); + ++layer_idx_; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::DestroyLayer(hwc2_layer_t layer) { + if (!get_layer(layer)) + return HWC2::Error::BadLayer; + + layers_.erase(layer); + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetActiveConfig(hwc2_config_t *config) const { + if (hwc_configs_.count(active_config_id_) == 0) + return HWC2::Error::BadConfig; + + *config = active_config_id_; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetChangedCompositionTypes(uint32_t *num_elements, + hwc2_layer_t *layers, + int32_t *types) { + uint32_t num_changes = 0; + for (std::pair &l : layers_) { + if (l.second.IsTypeChanged()) { + if (layers && num_changes < *num_elements) + layers[num_changes] = l.first; + if (types && num_changes < *num_elements) + types[num_changes] = static_cast(l.second.GetValidatedType()); + ++num_changes; + } + } + if (!layers && !types) + *num_elements = num_changes; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetClientTargetSupport(uint32_t width, uint32_t height, + int32_t /*format*/, + int32_t dataspace) { + std::pair min = drm_->min_resolution(); + std::pair 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) + return HWC2::Error::Unsupported; + + // TODO(nobody): Validate format can be handled by either GL or planes + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetColorModes(uint32_t *num_modes, int32_t *modes) { + if (!modes) + *num_modes = 1; + + if (modes) + *modes = HAL_COLOR_MODE_NATIVE; + + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetDisplayAttribute(hwc2_config_t config, + int32_t attribute_in, + int32_t *value) { + int conf = static_cast(config); + + if (hwc_configs_.count(conf) == 0) { + ALOGE("Could not find active mode for %d", conf); + return HWC2::Error::BadConfig; + } + + auto &hwc_config = hwc_configs_[conf]; + + static const int32_t kUmPerInch = 25400; + uint32_t mm_width = connector_->mm_width(); + uint32_t mm_height = connector_->mm_height(); + auto attribute = static_cast(attribute_in); + switch (attribute) { + case HWC2::Attribute::Width: + *value = static_cast(hwc_config.mode.h_display()); + break; + case HWC2::Attribute::Height: + *value = static_cast(hwc_config.mode.v_display()); + break; + case HWC2::Attribute::VsyncPeriod: + // in nanoseconds + *value = static_cast(1E9 / hwc_config.mode.v_refresh()); + break; + case HWC2::Attribute::DpiX: + // Dots per 1000 inches + *value = mm_width ? static_cast(hwc_config.mode.h_display() * + kUmPerInch / mm_width) + : -1; + break; + case HWC2::Attribute::DpiY: + // Dots per 1000 inches + *value = mm_height ? static_cast(hwc_config.mode.v_display() * + kUmPerInch / mm_height) + : -1; + break; +#if PLATFORM_SDK_VERSION > 29 + case HWC2::Attribute::ConfigGroup: + /* Dispite ConfigGroup is a part of HWC2.4 API, framework + * able to request it even if service @2.1 is used */ + *value = hwc_config.group_id; + break; +#endif + default: + *value = -1; + return HWC2::Error::BadConfig; + } + return HWC2::Error::None; +} + +// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme +HWC2::Error HwcDisplay::GetDisplayConfigs(uint32_t *num_configs, + hwc2_config_t *configs) { + // 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) { + int ret = connector_->UpdateModes(); + if (ret) { + ALOGE("Failed to update display modes %d", ret); + return HWC2::Error::BadDisplay; + } + + hwc_configs_.clear(); + preferred_config_id_ = 0; + int preferred_config_group_id_ = 0; + + if (connector_->modes().empty()) { + ALOGE("No modes reported by KMS"); + return HWC2::Error::BadDisplay; + } + + int last_config_id = 1; + int last_group_id = 1; + + /* Group modes */ + for (const auto &mode : connector_->modes()) { + /* Find group for the new mode or create new group */ + int group_found = 0; + for (auto &hwc_config : hwc_configs_) { + if (mode.h_display() == hwc_config.second.mode.h_display() && + mode.v_display() == hwc_config.second.mode.v_display()) { + group_found = hwc_config.second.group_id; + } + } + if (group_found == 0) { + group_found = last_group_id++; + } + + bool disabled = false; + if (mode.flags() & DRM_MODE_FLAG_3D_MASK) { + ALOGI("Disabling display mode %s (Modes with 3D flag aren't supported)", + mode.name().c_str()); + disabled = true; + } + + /* Add config */ + hwc_configs_[last_config_id] = { + .id = last_config_id, + .group_id = group_found, + .mode = mode, + .disabled = disabled, + }; + + /* Chwck if the mode is preferred */ + if ((mode.type() & DRM_MODE_TYPE_PREFERRED) != 0 && + preferred_config_id_ == 0) { + preferred_config_id_ = last_config_id; + preferred_config_group_id_ = group_found; + } + + last_config_id++; + } + + /* We must have preferred mode. Set first mode as preferred + * in case KMS haven't reported anything. */ + if (preferred_config_id_ == 0) { + preferred_config_id_ = 1; + preferred_config_group_id_ = 1; + } + + for (int group = 1; group < last_group_id; group++) { + bool has_interlaced = false; + bool has_progressive = false; + for (auto &hwc_config : hwc_configs_) { + if (hwc_config.second.group_id != group || hwc_config.second.disabled) { + continue; + } + + if (hwc_config.second.IsInterlaced()) { + has_interlaced = true; + } else { + has_progressive = true; + } + } + + bool has_both = has_interlaced && has_progressive; + if (!has_both) { + continue; + } + + bool group_contains_preferred_interlaced = false; + if (group == preferred_config_group_id_ && + hwc_configs_[preferred_config_id_].IsInterlaced()) { + group_contains_preferred_interlaced = true; + } + + for (auto &hwc_config : hwc_configs_) { + if (hwc_config.second.group_id != group || hwc_config.second.disabled) { + continue; + } + + bool disable = group_contains_preferred_interlaced + ? !hwc_config.second.IsInterlaced() + : hwc_config.second.IsInterlaced(); + + if (disable) { + ALOGI( + "Group %i: Disabling display mode %s (This group should consist " + "of %s modes)", + group, hwc_config.second.mode.name().c_str(), + group_contains_preferred_interlaced ? "interlaced" + : "progressive"); + + hwc_config.second.disabled = true; + } + } + } + + /* Group should not contain 2 modes with FPS delta less than ~1HZ + * otherwise android.graphics.cts.SetFrameRateTest CTS will fail + */ + for (int m1 = 1; m1 < last_config_id; m1++) { + for (int m2 = 1; m2 < last_config_id; m2++) { + if (m1 != m2 && + hwc_configs_[m1].group_id == hwc_configs_[m2].group_id && + !hwc_configs_[m1].disabled && !hwc_configs_[m2].disabled && + fabsf(hwc_configs_[m1].mode.v_refresh() - + hwc_configs_[m2].mode.v_refresh()) < 1.0) { + ALOGI( + "Group %i: Disabling display mode %s (Refresh rate value is " + "too close to existing mode %s)", + hwc_configs_[m2].group_id, hwc_configs_[m2].mode.name().c_str(), + hwc_configs_[m1].mode.name().c_str()); + + hwc_configs_[m2].disabled = true; + } + } + } + } + + uint32_t idx = 0; + for (auto &hwc_config : hwc_configs_) { + if (hwc_config.second.disabled) { + continue; + } + + if (configs != nullptr) { + if (idx >= *num_configs) { + break; + } + configs[idx] = hwc_config.second.id; + } + + idx++; + } + *num_configs = idx; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetDisplayName(uint32_t *size, char *name) { + 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(static_cast(length - 1), *size); + strncpy(name, string.c_str(), *size); + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetDisplayRequests(int32_t * /*display_requests*/, + uint32_t *num_elements, + hwc2_layer_t * /*layers*/, + int32_t * /*layer_requests*/) { + // TODO(nobody): I think virtual display should request + // HWC2_DISPLAY_REQUEST_WRITE_CLIENT_TARGET_TO_OUTPUT here + *num_elements = 0; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetDisplayType(int32_t *type) { + *type = static_cast(type_); + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetDozeSupport(int32_t *support) { + *support = 0; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetHdrCapabilities(uint32_t *num_types, + int32_t * /*types*/, + float * /*max_luminance*/, + float * /*max_average_luminance*/, + float * /*min_luminance*/) { + *num_types = 0; + return HWC2::Error::None; +} + +/* Find API details at: + * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1767 + */ +HWC2::Error HwcDisplay::GetReleaseFences(uint32_t *num_elements, + hwc2_layer_t *layers, + int32_t *fences) { + uint32_t num_layers = 0; + + for (std::pair &l : layers_) { + ++num_layers; + if (layers == nullptr || fences == nullptr) + continue; + + 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.GetReleaseFence().Release(); + } + *num_elements = num_layers; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) { + // order the layers by z-order + bool use_client_layer = false; + uint32_t client_z_order = UINT32_MAX; + std::map z_map; + for (std::pair &l : layers_) { + switch (l.second.GetValidatedType()) { + case HWC2::Composition::Device: + z_map.emplace(std::make_pair(l.second.GetZOrder(), &l.second)); + break; + case HWC2::Composition::Client: + // Place it at the z_order of the lowest client layer + use_client_layer = true; + client_z_order = std::min(client_z_order, l.second.GetZOrder()); + break; + default: + continue; + } + } + if (use_client_layer) + z_map.emplace(std::make_pair(client_z_order, &client_layer_)); + + if (z_map.empty()) + return HWC2::Error::BadLayer; + + std::vector composition_layers; + + // now that they're ordered by z, add them to the composition + for (std::pair &l : z_map) { + DrmHwcLayer layer; + l.second->PopulateDrmLayer(&layer); + int ret = layer.ImportBuffer(drm_); + if (ret) { + ALOGE("Failed to import layer, ret=%d", ret); + return HWC2::Error::NoResources; + } + composition_layers.emplace_back(std::move(layer)); + } + + auto composition = std::make_shared(crtc_); + + // TODO(nobody): Don't always assume geometry changed + int ret = composition->SetLayers(composition_layers.data(), + composition_layers.size()); + if (ret) { + ALOGE("Failed to set layers in the composition ret=%d", ret); + return HWC2::Error::BadLayer; + } + + std::vector primary_planes(primary_planes_); + std::vector overlay_planes(overlay_planes_); + ret = composition->Plan(&primary_planes, &overlay_planes); + if (ret) { + ALOGV("Failed to plan the composition ret=%d", ret); + return HWC2::Error::BadConfig; + } + + a_args.composition = composition; + if (staged_mode) { + a_args.display_mode = *staged_mode; + } + ret = compositor_.ExecuteAtomicCommit(a_args); + + if (ret) { + if (!a_args.test_only) + ALOGE("Failed to apply the frame composition ret=%d", ret); + return HWC2::Error::BadParameter; + } + + if (!a_args.test_only) { + staged_mode.reset(); + } + + return HWC2::Error::None; +} + +/* Find API details at: + * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1805 + */ +HWC2::Error HwcDisplay::PresentDisplay(int32_t *present_fence) { + HWC2::Error ret; + + ++total_stats_.total_frames_; + + AtomicCommitArgs a_args{}; + ret = CreateComposition(a_args); + + if (ret != HWC2::Error::None) + ++total_stats_.failed_kms_present_; + + if (ret == HWC2::Error::BadLayer) { + // Can we really have no client or device layers? + *present_fence = -1; + return HWC2::Error::None; + } + if (ret != HWC2::Error::None) + return ret; + + *present_fence = a_args.out_fence.Release(); + + ++frame_no_; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::SetActiveConfig(hwc2_config_t config) { + int conf = static_cast(config); + + if (hwc_configs_.count(conf) == 0) { + ALOGE("Could not find active mode for %d", conf); + return HWC2::Error::BadConfig; + } + + auto &mode = hwc_configs_[conf].mode; + + staged_mode = mode; + + active_config_id_ = conf; + + // Setup the client layer's dimensions + hwc_rect_t display_frame = {.left = 0, + .top = 0, + .right = static_cast(mode.h_display()), + .bottom = static_cast(mode.v_display())}; + client_layer_.SetLayerDisplayFrame(display_frame); + + return HWC2::Error::None; +} + +/* Find API details at: + * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1861 + */ +HWC2::Error HwcDisplay::SetClientTarget(buffer_handle_t target, + int32_t acquire_fence, + int32_t dataspace, + hwc_region_t /*damage*/) { + client_layer_.SetLayerBuffer(target, acquire_fence); + client_layer_.SetLayerDataspace(dataspace); + + /* + * target can be nullptr, this does mean the Composer Service is calling + * cleanDisplayResources() on after receiving HOTPLUG event. See more at: + * https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h;l=350;drc=944b68180b008456ed2eb4d4d329e33b19bd5166 + */ + if (target == nullptr) { + return HWC2::Error::None; + } + + /* TODO: Do not update source_crop every call. + * It makes sense to do it once after every hotplug event. */ + HwcDrmBo bo{}; + BufferInfoGetter::GetInstance()->ConvertBoInfo(target, &bo); + + hwc_frect_t source_crop = {.left = 0.0F, + .top = 0.0F, + .right = static_cast(bo.width), + .bottom = static_cast(bo.height)}; + client_layer_.SetLayerSourceCrop(source_crop); + + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::SetColorMode(int32_t mode) { + if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_BT2100_HLG) + return HWC2::Error::BadParameter; + + if (mode != HAL_COLOR_MODE_NATIVE) + return HWC2::Error::Unsupported; + + color_mode_ = mode; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::SetColorTransform(const float *matrix, int32_t hint) { + if (hint < HAL_COLOR_TRANSFORM_IDENTITY || + hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA) + return HWC2::Error::BadParameter; + + if (!matrix && hint == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX) + return HWC2::Error::BadParameter; + + color_transform_hint_ = static_cast(hint); + if (color_transform_hint_ == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX) + std::copy(matrix, matrix + MATRIX_SIZE, color_transform_matrix_.begin()); + + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::SetOutputBuffer(buffer_handle_t /*buffer*/, + int32_t /*release_fence*/) { + // TODO(nobody): Need virtual display support + return HWC2::Error::Unsupported; +} + +HWC2::Error HwcDisplay::SetPowerMode(int32_t mode_in) { + auto mode = static_cast(mode_in); + AtomicCommitArgs a_args{}; + + switch (mode) { + case HWC2::PowerMode::Off: + a_args.active = false; + break; + case HWC2::PowerMode::On: + /* + * Setting the display to active before we have a composition + * can break some drivers, so skip setting a_args.active to + * true, as the next composition frame will implicitly activate + * the display + */ + return HWC2::Error::None; + break; + case HWC2::PowerMode::Doze: + case HWC2::PowerMode::DozeSuspend: + return HWC2::Error::Unsupported; + default: + ALOGI("Power mode %d is unsupported\n", mode); + return HWC2::Error::BadParameter; + }; + + int err = compositor_.ExecuteAtomicCommit(a_args); + if (err) { + ALOGE("Failed to apply the dpms composition err=%d", err); + return HWC2::Error::BadParameter; + } + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::SetVsyncEnabled(int32_t enabled) { + vsync_worker_.VSyncControl(HWC2_VSYNC_ENABLE == enabled); + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::ValidateDisplay(uint32_t *num_types, + uint32_t *num_requests) { + return backend_->ValidateDisplay(this, num_types, num_requests); +} + +std::vector HwcDisplay::GetOrderLayersByZPos() { + std::vector ordered_layers; + ordered_layers.reserve(layers_.size()); + + for (auto &[handle, layer] : layers_) { + ordered_layers.emplace_back(&layer); + } + + std::sort(std::begin(ordered_layers), std::end(ordered_layers), + [](const HwcLayer *lhs, const HwcLayer *rhs) { + return lhs->GetZOrder() < rhs->GetZOrder(); + }); + + return ordered_layers; +} + +#if PLATFORM_SDK_VERSION > 29 +HWC2::Error HwcDisplay::GetDisplayConnectionType(uint32_t *outType) { + if (connector_->internal()) + *outType = static_cast(HWC2::DisplayConnectionType::Internal); + else if (connector_->external()) + *outType = static_cast(HWC2::DisplayConnectionType::External); + else + return HWC2::Error::BadConfig; + + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetDisplayVsyncPeriod( + hwc2_vsync_period_t *outVsyncPeriod /* ns */) { + return GetDisplayAttribute(active_config_id_, HWC2_ATTRIBUTE_VSYNC_PERIOD, + (int32_t *)(outVsyncPeriod)); +} + +HWC2::Error HwcDisplay::SetActiveConfigWithConstraints( + hwc2_config_t /*config*/, + hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints, + hwc_vsync_period_change_timeline_t *outTimeline) { + if (vsyncPeriodChangeConstraints == nullptr || outTimeline == nullptr) { + return HWC2::Error::BadParameter; + } + + return HWC2::Error::BadConfig; +} + +HWC2::Error HwcDisplay::SetAutoLowLatencyMode(bool /*on*/) { + return HWC2::Error::Unsupported; +} + +HWC2::Error HwcDisplay::GetSupportedContentTypes( + uint32_t *outNumSupportedContentTypes, + const uint32_t *outSupportedContentTypes) { + if (outSupportedContentTypes == nullptr) + *outNumSupportedContentTypes = 0; + + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::SetContentType(int32_t contentType) { + if (contentType != HWC2_CONTENT_TYPE_NONE) + return HWC2::Error::Unsupported; + + /* TODO: Map to the DRM Connector property: + * https://elixir.bootlin.com/linux/v5.4-rc5/source/drivers/gpu/drm/drm_connector.c#L809 + */ + + return HWC2::Error::None; +} +#endif + +#if PLATFORM_SDK_VERSION > 28 +HWC2::Error HwcDisplay::GetDisplayIdentificationData(uint8_t *outPort, + uint32_t *outDataSize, + uint8_t *outData) { + auto blob = connector_->GetEdidBlob(); + + if (!blob) { + ALOGE("Failed to get edid property value."); + return HWC2::Error::Unsupported; + } + + if (outData) { + *outDataSize = std::min(*outDataSize, blob->length); + memcpy(outData, blob->data, *outDataSize); + } else { + *outDataSize = blob->length; + } + *outPort = connector_->id(); + + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetDisplayCapabilities(uint32_t *outNumCapabilities, + uint32_t * /*outCapabilities*/) { + if (outNumCapabilities == nullptr) { + return HWC2::Error::BadParameter; + } + + *outNumCapabilities = 0; + + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetDisplayBrightnessSupport(bool *supported) { + *supported = false; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::SetDisplayBrightness(float /* brightness */) { + return HWC2::Error::Unsupported; +} + +#endif /* PLATFORM_SDK_VERSION > 28 */ + +#if PLATFORM_SDK_VERSION > 27 + +HWC2::Error HwcDisplay::GetRenderIntents( + int32_t mode, uint32_t *outNumIntents, + int32_t * /*android_render_intent_v1_1_t*/ outIntents) { + if (mode != HAL_COLOR_MODE_NATIVE) { + return HWC2::Error::BadParameter; + } + + if (outIntents == nullptr) { + *outNumIntents = 1; + return HWC2::Error::None; + } + *outNumIntents = 1; + outIntents[0] = HAL_RENDER_INTENT_COLORIMETRIC; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::SetColorModeWithIntent(int32_t mode, int32_t intent) { + if (intent < HAL_RENDER_INTENT_COLORIMETRIC || + intent > HAL_RENDER_INTENT_TONE_MAP_ENHANCE) + return HWC2::Error::BadParameter; + + if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_BT2100_HLG) + return HWC2::Error::BadParameter; + + if (mode != HAL_COLOR_MODE_NATIVE) + return HWC2::Error::Unsupported; + + if (intent != HAL_RENDER_INTENT_COLORIMETRIC) + return HWC2::Error::Unsupported; + + color_mode_ = mode; + return HWC2::Error::None; +} + +#endif /* PLATFORM_SDK_VERSION > 27 */ + +const Backend *HwcDisplay::backend() const { + return backend_.get(); +} + +void HwcDisplay::set_backend(std::unique_ptr backend) { + backend_ = std::move(backend); +} + +} // namespace android diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h new file mode 100644 index 0000000..f69ff18 --- /dev/null +++ b/hwc2_device/HwcDisplay.h @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef ANDROID_HWC2_DEVICE_HWC_DISPLAY_H +#define ANDROID_HWC2_DEVICE_HWC_DISPLAY_H + +#include + +#include + +#include "compositor/DrmDisplayCompositor.h" +#include "drm/ResourceManager.h" +#include "drm/VSyncWorker.h" +#include "drmhwcomposer.h" +#include "hwc2_device/HwcLayer.h" + +namespace android { + +class Backend; +class DrmHwcTwo; + +class HwcDisplay { + public: + HwcDisplay(ResourceManager *resource_manager, DrmDevice *drm, + hwc2_display_t handle, HWC2::DisplayType type, DrmHwcTwo *hwc2); + HwcDisplay(const HwcDisplay &) = delete; + HWC2::Error Init(std::vector *planes); + + HWC2::Error CreateComposition(AtomicCommitArgs &a_args); + std::vector GetOrderLayersByZPos(); + + void ClearDisplay(); + + std::string Dump(); + + // HWC Hooks + HWC2::Error AcceptDisplayChanges(); + HWC2::Error CreateLayer(hwc2_layer_t *layer); + HWC2::Error DestroyLayer(hwc2_layer_t layer); + HWC2::Error GetActiveConfig(hwc2_config_t *config) const; + HWC2::Error GetChangedCompositionTypes(uint32_t *num_elements, + hwc2_layer_t *layers, int32_t *types); + HWC2::Error GetClientTargetSupport(uint32_t width, uint32_t height, + int32_t format, int32_t dataspace); + HWC2::Error GetColorModes(uint32_t *num_modes, int32_t *modes); + HWC2::Error GetDisplayAttribute(hwc2_config_t config, int32_t attribute, + int32_t *value); + HWC2::Error GetDisplayConfigs(uint32_t *num_configs, hwc2_config_t *configs); + HWC2::Error GetDisplayName(uint32_t *size, char *name); + HWC2::Error GetDisplayRequests(int32_t *display_requests, + uint32_t *num_elements, hwc2_layer_t *layers, + int32_t *layer_requests); + HWC2::Error GetDisplayType(int32_t *type); +#if PLATFORM_SDK_VERSION > 27 + HWC2::Error GetRenderIntents(int32_t mode, uint32_t *outNumIntents, + int32_t *outIntents); + HWC2::Error SetColorModeWithIntent(int32_t mode, int32_t intent); +#endif +#if PLATFORM_SDK_VERSION > 28 + HWC2::Error GetDisplayIdentificationData(uint8_t *outPort, + uint32_t *outDataSize, + uint8_t *outData); + HWC2::Error GetDisplayCapabilities(uint32_t *outNumCapabilities, + uint32_t *outCapabilities); + HWC2::Error GetDisplayBrightnessSupport(bool *supported); + HWC2::Error SetDisplayBrightness(float); +#endif +#if PLATFORM_SDK_VERSION > 29 + HWC2::Error GetDisplayConnectionType(uint32_t *outType); + HWC2::Error GetDisplayVsyncPeriod(hwc2_vsync_period_t *outVsyncPeriod); + + HWC2::Error SetActiveConfigWithConstraints( + hwc2_config_t config, + hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints, + hwc_vsync_period_change_timeline_t *outTimeline); + HWC2::Error SetAutoLowLatencyMode(bool on); + HWC2::Error GetSupportedContentTypes( + uint32_t *outNumSupportedContentTypes, + const uint32_t *outSupportedContentTypes); + + HWC2::Error SetContentType(int32_t contentType); +#endif + + HWC2::Error GetDozeSupport(int32_t *support); + HWC2::Error GetHdrCapabilities(uint32_t *num_types, int32_t *types, + float *max_luminance, + float *max_average_luminance, + float *min_luminance); + HWC2::Error GetReleaseFences(uint32_t *num_elements, hwc2_layer_t *layers, + int32_t *fences); + HWC2::Error PresentDisplay(int32_t *present_fence); + HWC2::Error SetActiveConfig(hwc2_config_t config); + HWC2::Error ChosePreferredConfig(); + HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence, + int32_t dataspace, hwc_region_t damage); + HWC2::Error SetColorMode(int32_t mode); + HWC2::Error SetColorTransform(const float *matrix, int32_t hint); + HWC2::Error SetOutputBuffer(buffer_handle_t buffer, int32_t release_fence); + HWC2::Error SetPowerMode(int32_t mode); + HWC2::Error SetVsyncEnabled(int32_t enabled); + HWC2::Error ValidateDisplay(uint32_t *num_types, uint32_t *num_requests); + HwcLayer *get_layer(hwc2_layer_t layer) { + auto it = layers_.find(layer); + if (it == layers_.end()) + return nullptr; + return &it->second; + } + + /* Statistics */ + struct Stats { + Stats minus(Stats b) const { + return {total_frames_ - b.total_frames_, + total_pixops_ - b.total_pixops_, + gpu_pixops_ - b.gpu_pixops_, + failed_kms_validate_ - b.failed_kms_validate_, + failed_kms_present_ - b.failed_kms_present_, + frames_flattened_ - b.frames_flattened_}; + } + + uint32_t total_frames_ = 0; + uint64_t total_pixops_ = 0; + uint64_t gpu_pixops_ = 0; + uint32_t failed_kms_validate_ = 0; + uint32_t failed_kms_present_ = 0; + uint32_t frames_flattened_ = 0; + }; + + struct HwcDisplayConfig { + int id{}; + int group_id{}; + DrmMode mode; + bool disabled{}; + + bool IsInterlaced() const { + return (mode.flags() & DRM_MODE_FLAG_INTERLACE) != 0; + } + }; + + std::map hwc_configs_; + + int active_config_id_ = 0; + int preferred_config_id_ = 0; + + const Backend *backend() const; + void set_backend(std::unique_ptr backend); + + const std::vector &primary_planes() const { + return primary_planes_; + } + + const std::vector &overlay_planes() const { + return overlay_planes_; + } + + std::map &layers() { + return layers_; + } + + const DrmDisplayCompositor &compositor() const { + return compositor_; + } + + const DrmDevice *drm() const { + return drm_; + } + + const DrmConnector *connector() const { + return connector_; + } + + ResourceManager *resource_manager() const { + return resource_manager_; + } + + android_color_transform_t &color_transform_hint() { + return color_transform_hint_; + } + + Stats &total_stats() { + return total_stats_; + } + + /* returns true if composition should be sent to client */ + bool ProcessClientFlatteningState(bool skip) { + int flattenning_state = flattenning_state_; + if (flattenning_state == ClientFlattenningState::Disabled) { + return false; + } + + if (skip) { + flattenning_state_ = ClientFlattenningState::NotRequired; + return false; + } + + if (flattenning_state == ClientFlattenningState::ClientRefreshRequested) { + flattenning_state_ = ClientFlattenningState::Flattened; + return true; + } + + flattening_vsync_worker_.VSyncControl(true); + flattenning_state_ = ClientFlattenningState::VsyncCountdownMax; + return false; + } + + private: + enum ClientFlattenningState : int32_t { + Disabled = -3, + NotRequired = -2, + Flattened = -1, + ClientRefreshRequested = 0, + VsyncCountdownMax = 60, /* 1 sec @ 60FPS */ + }; + + std::atomic_int flattenning_state_{ClientFlattenningState::NotRequired}; + VSyncWorker flattening_vsync_worker_; + + constexpr static size_t MATRIX_SIZE = 16; + + DrmHwcTwo *hwc2_; + + std::optional staged_mode; + + ResourceManager *resource_manager_; + DrmDevice *drm_; + DrmDisplayCompositor compositor_; + + std::vector primary_planes_; + std::vector overlay_planes_; + + std::unique_ptr backend_; + + VSyncWorker vsync_worker_; + DrmConnector *connector_ = nullptr; + DrmCrtc *crtc_ = nullptr; + hwc2_display_t handle_; + HWC2::DisplayType type_; + uint32_t layer_idx_ = 0; + std::map layers_; + HwcLayer client_layer_; + int32_t color_mode_{}; + std::array color_transform_matrix_{}; + android_color_transform_t color_transform_hint_; + + uint32_t frame_no_ = 0; + Stats total_stats_; + Stats prev_stats_; + std::string DumpDelta(HwcDisplay::Stats delta); +}; + +} // namespace android + +#endif diff --git a/hwc2_device/hwc2_device.cpp b/hwc2_device/hwc2_device.cpp index 72074ad..22e4589 100644 --- a/hwc2_device/hwc2_device.cpp +++ b/hwc2_device/hwc2_device.cpp @@ -47,8 +47,7 @@ static T DeviceHook(hwc2_device_t *dev, Args... args) { template static int32_t DisplayHook(hwc2_device_t *dev, hwc2_display_t display_handle, Args... args) { - DrmHwcTwo::HwcDisplay *display = DrmHwcTwo::GetDisplay(ToDrmHwcTwo(dev), - display_handle); + HwcDisplay *display = DrmHwcTwo::GetDisplay(ToDrmHwcTwo(dev), display_handle); if (!display) return static_cast(HWC2::Error::BadDisplay); @@ -58,8 +57,7 @@ static int32_t DisplayHook(hwc2_device_t *dev, hwc2_display_t display_handle, template static int32_t LayerHook(hwc2_device_t *dev, hwc2_display_t display_handle, hwc2_layer_t layer_handle, Args... args) { - DrmHwcTwo::HwcDisplay *display = DrmHwcTwo::GetDisplay(ToDrmHwcTwo(dev), - display_handle); + HwcDisplay *display = DrmHwcTwo::GetDisplay(ToDrmHwcTwo(dev), display_handle); if (!display) return static_cast(HWC2::Error::BadDisplay); @@ -113,181 +111,168 @@ static hwc2_function_pointer_t HookDevGetFunction(struct hwc2_device * /*dev*/, // Display functions case HWC2::FunctionDescriptor::AcceptDisplayChanges: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::CreateLayer: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::DestroyLayer: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::GetActiveConfig: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::GetChangedCompositionTypes: return ToHook( - DisplayHook< - decltype(&DrmHwcTwo::HwcDisplay::GetChangedCompositionTypes), - &DrmHwcTwo::HwcDisplay::GetChangedCompositionTypes, uint32_t *, - hwc2_layer_t *, int32_t *>); + DisplayHook); case HWC2::FunctionDescriptor::GetClientTargetSupport: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::GetColorModes: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::GetDisplayAttribute: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::GetDisplayConfigs: return ToHook( - DisplayHook); case HWC2::FunctionDescriptor::GetDisplayName: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::GetDisplayRequests: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::GetDisplayType: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::GetDozeSupport: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::GetHdrCapabilities: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::GetReleaseFences: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::PresentDisplay: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::SetActiveConfig: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::SetClientTarget: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::SetColorMode: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::SetColorTransform: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::SetOutputBuffer: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::SetPowerMode: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::SetVsyncEnabled: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::ValidateDisplay: return ToHook( - DisplayHook); + DisplayHook); #if PLATFORM_SDK_VERSION > 27 case HWC2::FunctionDescriptor::GetRenderIntents: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::SetColorModeWithRenderIntent: return ToHook( - DisplayHook); + DisplayHook); #endif #if PLATFORM_SDK_VERSION > 28 case HWC2::FunctionDescriptor::GetDisplayIdentificationData: return ToHook( - DisplayHook< - decltype(&DrmHwcTwo::HwcDisplay::GetDisplayIdentificationData), - &DrmHwcTwo::HwcDisplay::GetDisplayIdentificationData, uint8_t *, - uint32_t *, uint8_t *>); + DisplayHook); case HWC2::FunctionDescriptor::GetDisplayCapabilities: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::GetDisplayBrightnessSupport: return ToHook( - DisplayHook< - decltype(&DrmHwcTwo::HwcDisplay::GetDisplayBrightnessSupport), - &DrmHwcTwo::HwcDisplay::GetDisplayBrightnessSupport, bool *>); + DisplayHook); case HWC2::FunctionDescriptor::SetDisplayBrightness: return ToHook( - DisplayHook); + DisplayHook); #endif /* PLATFORM_SDK_VERSION > 28 */ #if PLATFORM_SDK_VERSION > 29 case HWC2::FunctionDescriptor::GetDisplayConnectionType: return ToHook( - DisplayHook< - decltype(&DrmHwcTwo::HwcDisplay::GetDisplayConnectionType), - &DrmHwcTwo::HwcDisplay::GetDisplayConnectionType, uint32_t *>); + DisplayHook); case HWC2::FunctionDescriptor::GetDisplayVsyncPeriod: return ToHook( - DisplayHook); case HWC2::FunctionDescriptor::SetActiveConfigWithConstraints: return ToHook( - DisplayHook< - decltype(&DrmHwcTwo::HwcDisplay::SetActiveConfigWithConstraints), - &DrmHwcTwo::HwcDisplay::SetActiveConfigWithConstraints, - hwc2_config_t, hwc_vsync_period_change_constraints_t *, - hwc_vsync_period_change_timeline_t *>); + DisplayHook); case HWC2::FunctionDescriptor::SetAutoLowLatencyMode: return ToHook( - DisplayHook); + DisplayHook); case HWC2::FunctionDescriptor::GetSupportedContentTypes: return ToHook( - DisplayHook< - decltype(&DrmHwcTwo::HwcDisplay::GetSupportedContentTypes), - &DrmHwcTwo::HwcDisplay::GetSupportedContentTypes, uint32_t *, - uint32_t *>); + DisplayHook); case HWC2::FunctionDescriptor::SetContentType: return ToHook( - DisplayHook); + DisplayHook); #endif // Layer functions case HWC2::FunctionDescriptor::SetCursorPosition: -- 2.11.0