diff options
Diffstat (limited to 'DrmHwcTwo.cpp')
-rw-r--r-- | DrmHwcTwo.cpp | 1443 |
1 files changed, 1443 insertions, 0 deletions
diff --git a/DrmHwcTwo.cpp b/DrmHwcTwo.cpp new file mode 100644 index 0000000..65a317c --- /dev/null +++ b/DrmHwcTwo.cpp @@ -0,0 +1,1443 @@ +/* + * 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 <cutils/properties.h> +#include <hardware/hardware.h> +#include <hardware/hwcomposer2.h> +#include <inttypes.h> +#include <log/log.h> + +#include <string> + +#include "backend/BackendManager.h" +#include "compositor/DrmDisplayComposition.h" + +namespace android { + +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_); + hook(data_, display, timestamp); + } + + private: + hwc2_callback_data_t data_; + hwc2_function_pointer_t hook_; +}; + +DrmHwcTwo::DrmHwcTwo() { + 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) { + 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)); + + DrmCrtc *crtc = drm->GetCrtcForDisplay(static_cast<int>(displ)); + if (!crtc) { + ALOGE("Failed to get crtc for display %d", static_cast<int>(displ)); + return HWC2::Error::BadDisplay; + } + std::vector<DrmPlane *> display_planes; + for (auto &plane : drm->planes()) { + if (plane->GetCrtcSupported(*crtc)) + display_planes.push_back(plane.get()); + } + displays_.at(displ).Init(&display_planes); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::Init() { + int rv = resource_manager_.Init(); + if (rv) { + ALOGE("Can't initialize the resource manager %d", rv); + return HWC2::Error::NoResources; + } + + HWC2::Error ret = HWC2::Error::None; + for (int i = 0; i < resource_manager_.getDisplayCount(); i++) { + ret = CreateDisplay(i, HWC2::DisplayType::Physical); + if (ret != HWC2::Error::None) { + ALOGE("Failed to create display %d with error %d", i, ret); + return ret; + } + } + + auto &drmDevices = resource_manager_.getDrmDevices(); + for (auto &device : drmDevices) { + device->RegisterHotplugHandler(new DrmHotplugHandler(this, device.get())); + } + return ret; +} + +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) { + // TODO: Implement virtual display + return unsupported(__func__, width, height, format, display); +} + +HWC2::Error DrmHwcTwo::DestroyVirtualDisplay(hwc2_display_t display) { + // TODO: Implement virtual display + return unsupported(__func__, display); +} + +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_); + + return (std::stringstream() + << " 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) + .str(); +} + +std::string DrmHwcTwo::HwcDisplay::Dump() { + auto out = (std::stringstream() + << "- Display on: " << connector_->name() << "\n" + << " Flattening state: " << compositor_.GetFlatteningState() + << "\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") + .str(); + + memcpy(&prev_stats_, &total_stats_, sizeof(Stats)); + return out; +} + +void DrmHwcTwo::Dump(uint32_t *outSize, char *outBuffer) { + supported(__func__); + + if (outBuffer != nullptr) { + auto copiedBytes = mDumpString.copy(outBuffer, *outSize); + *outSize = static_cast<uint32_t>(copiedBytes); + return; + } + + std::stringstream output; + + output << "-- drm_hwcomposer --\n\n"; + + for (std::pair<const hwc2_display_t, DrmHwcTwo::HwcDisplay> &dp : displays_) + output << dp.second.Dump(); + + mDumpString = output.str(); + *outSize = static_cast<uint32_t>(mDumpString.size()); +} + +uint32_t DrmHwcTwo::GetMaxVirtualDisplayCount() { + // TODO: Implement virtual display + unsupported(__func__); + return 0; +} + +HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor, + hwc2_callback_data_t data, + hwc2_function_pointer_t function) { + supported(__func__); + auto callback = static_cast<HWC2::Callback>(descriptor); + + if (!function) { + callbacks_.erase(callback); + return HWC2::Error::None; + } + + callbacks_.emplace(callback, HwcCallback(data, function)); + + switch (callback) { + case HWC2::Callback::Hotplug: { + auto &drmDevices = resource_manager_.getDrmDevices(); + for (auto &device : drmDevices) + HandleInitialHotplugState(device.get()); + break; + } + case HWC2::Callback::Refresh: { + for (std::pair<const hwc2_display_t, DrmHwcTwo::HwcDisplay> &d : + displays_) + d.second.RegisterRefreshCallback(data, function); + break; + } + case HWC2::Callback::Vsync: { + for (std::pair<const hwc2_display_t, DrmHwcTwo::HwcDisplay> &d : + displays_) + d.second.RegisterVsyncCallback(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), + color_transform_hint_(HAL_COLOR_TRANSFORM_IDENTITY) { + supported(__func__); + + // 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() { + compositor_.ClearDisplay(); +} + +HWC2::Error DrmHwcTwo::HwcDisplay::Init(std::vector<DrmPlane *> *planes) { + supported(__func__); + planner_ = Planner::CreateInstance(drm_); + if (!planner_) { + ALOGE("Failed to create planner instance for composition"); + return HWC2::Error::NoResources; + } + + int display = static_cast<int>(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 = atoi(use_overlay_planes_prop); + for (auto &plane : *planes) { + if (plane->type() == DRM_PLANE_TYPE_PRIMARY) + primary_planes_.push_back(plane); + else if (use_overlay_planes && (plane)->type() == 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); + 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; + } + + return ChosePreferredConfig(); +} + +HWC2::Error DrmHwcTwo::HwcDisplay::ChosePreferredConfig() { + // 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; + + return SetActiveConfig(connector_->get_preferred_mode_id()); +} + +HWC2::Error DrmHwcTwo::HwcDisplay::RegisterVsyncCallback( + hwc2_callback_data_t data, hwc2_function_pointer_t func) { + supported(__func__); + auto callback = std::make_shared<DrmVsyncCallback>(data, func); + vsync_worker_.RegisterCallback(std::move(callback)); + return HWC2::Error::None; +} + +void DrmHwcTwo::HwcDisplay::RegisterRefreshCallback( + hwc2_callback_data_t data, hwc2_function_pointer_t func) { + supported(__func__); + auto hook = reinterpret_cast<HWC2_PFN_REFRESH>(func); + compositor_.SetRefreshCallback([data, hook](int display) { + hook(data, static_cast<hwc2_display_t>(display)); + }); +} + +HWC2::Error DrmHwcTwo::HwcDisplay::AcceptDisplayChanges() { + supported(__func__); + 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) { + supported(__func__); + layers_.emplace(static_cast<hwc2_layer_t>(layer_idx_), HwcLayer()); + *layer = static_cast<hwc2_layer_t>(layer_idx_); + ++layer_idx_; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::DestroyLayer(hwc2_layer_t layer) { + supported(__func__); + if (!get_layer(layer)) + return HWC2::Error::BadLayer; + + layers_.erase(layer); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetActiveConfig(hwc2_config_t *config) { + supported(__func__); + DrmMode const &mode = connector_->active_mode(); + if (mode.id() == 0) + return HWC2::Error::BadConfig; + + *config = mode.id(); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetChangedCompositionTypes( + uint32_t *num_elements, hwc2_layer_t *layers, int32_t *types) { + supported(__func__); + 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) { + supported(__func__); + 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) { + supported(__func__); + 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) { + supported(__func__); + auto mode = std::find_if(connector_->modes().begin(), + connector_->modes().end(), + [config](DrmMode const &m) { + return m.id() == config; + }); + if (mode == connector_->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; + } + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayConfigs(uint32_t *num_configs, + hwc2_config_t *configs) { + supported(__func__); + // 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; + } + } + + // 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 mode = std::find_if(connector_->modes().begin(), + connector_->modes().end(), [&](DrmMode const &m) { + return m.id() == + connector_->get_preferred_mode_id(); + }); + if (mode != connector_->modes().end()) + sel_modes.push_back(*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()); + 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 = idx; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayName(uint32_t *size, char *name) { + supported(__func__); + 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) { + supported(__func__); + // TODO: I think virtual display should request + // HWC2_DISPLAY_REQUEST_WRITE_CLIENT_TARGET_TO_OUTPUT here + unsupported(__func__, display_requests, num_elements, layers, layer_requests); + *num_elements = 0; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayType(int32_t *type) { + supported(__func__); + *type = static_cast<int32_t>(type_); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetDozeSupport(int32_t *support) { + supported(__func__); + *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*/) { + supported(__func__); + *num_types = 0; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetReleaseFences(uint32_t *num_elements, + hwc2_layer_t *layers, + int32_t *fences) { + supported(__func__); + 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.take_release_fence(); + } + *num_elements = num_layers; + return HWC2::Error::None; +} + +void DrmHwcTwo::HwcDisplay::AddFenceToPresentFence(int fd) { + if (fd < 0) + return; + + if (present_fence_.get() >= 0) { + int old_fence = present_fence_.get(); + present_fence_.Set(sync_merge("dc_present", old_fence, fd)); + close(fd); + } else { + present_fence_.Set(fd); + } +} + +bool DrmHwcTwo::HwcDisplay::HardwareSupportsLayerType( + HWC2::Composition comp_type) { + return comp_type == HWC2::Composition::Device || + comp_type == HWC2::Composition::Cursor; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::CreateComposition(bool test) { + std::vector<DrmCompositionDisplayLayersMap> layers_map; + layers_map.emplace_back(); + DrmCompositionDisplayLayersMap &map = layers_map.back(); + + map.display = static_cast<int>(handle_); + map.geometry_changed = true; // TODO: Fix this + + // order the layers by z-order + bool use_client_layer = false; + uint32_t client_z_order = UINT32_MAX; + std::map<uint32_t, DrmHwcTwo::HwcLayer *> z_map; + for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) { + switch (l.second.validated_type()) { + case HWC2::Composition::Device: + z_map.emplace(std::make_pair(l.second.z_order(), &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.z_order()); + 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; + + // now that they're ordered by z, add them to the composition + for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map) { + DrmHwcLayer layer; + l.second->PopulateDrmLayer(&layer); + int ret = layer.ImportBuffer(importer_.get()); + if (ret) { + ALOGE("Failed to import layer, ret=%d", ret); + return HWC2::Error::NoResources; + } + map.layers.emplace_back(std::move(layer)); + } + + std::unique_ptr<DrmDisplayComposition> composition = compositor_ + .CreateComposition(); + composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_); + + // TODO: Don't always assume geometry changed + int 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; + } + + std::vector<DrmPlane *> primary_planes(primary_planes_); + std::vector<DrmPlane *> overlay_planes(overlay_planes_); + ret = composition->Plan(&primary_planes, &overlay_planes); + if (ret) { + ALOGE("Failed to plan the composition ret=%d", ret); + return HWC2::Error::BadConfig; + } + + // Disable the planes we're not using + for (auto i = primary_planes.begin(); i != primary_planes.end();) { + composition->AddPlaneDisable(*i); + i = primary_planes.erase(i); + } + for (auto i = overlay_planes.begin(); i != overlay_planes.end();) { + composition->AddPlaneDisable(*i); + i = overlay_planes.erase(i); + } + + if (test) { + ret = compositor_.TestComposition(composition.get()); + } else { + ret = compositor_.ApplyComposition(std::move(composition)); + AddFenceToPresentFence(compositor_.TakeOutFence()); + } + if (ret) { + if (!test) + ALOGE("Failed to apply the frame composition ret=%d", ret); + return HWC2::Error::BadParameter; + } + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::PresentDisplay(int32_t *present_fence) { + supported(__func__); + HWC2::Error ret; + + ++total_stats_.total_frames_; + + ret = CreateComposition(false); + 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 = present_fence_.Release(); + + ++frame_no_; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::SetActiveConfig(hwc2_config_t config) { + supported(__func__); + auto mode = std::find_if(connector_->modes().begin(), + connector_->modes().end(), + [config](DrmMode const &m) { + return m.id() == config; + }); + if (mode == connector_->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_.ApplyComposition(std::move(composition)); + if (ret) { + ALOGE("Failed to queue dpms composition on %d", ret); + return HWC2::Error::BadConfig; + } + + connector_->set_active_mode(*mode); + + // 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); + + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::SetClientTarget(buffer_handle_t target, + int32_t acquire_fence, + int32_t dataspace, + hwc_region_t /*damage*/) { + supported(__func__); + UniqueFd uf(acquire_fence); + + client_layer_.set_buffer(target); + client_layer_.set_acquire_fence(uf.get()); + client_layer_.SetLayerDataspace(dataspace); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::SetColorMode(int32_t mode) { + supported(__func__); + + 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) { + supported(__func__); + 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<android_color_transform_t>(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) { + supported(__func__); + // TODO: Need virtual display support + return unsupported(__func__, buffer, release_fence); +} + +HWC2::Error DrmHwcTwo::HwcDisplay::SetPowerMode(int32_t mode_in) { + supported(__func__); + uint64_t dpms_value = 0; + auto mode = static_cast<HWC2::PowerMode>(mode_in); + switch (mode) { + 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: + return HWC2::Error::Unsupported; + default: + ALOGI("Power mode %d is unsupported\n", mode); + return HWC2::Error::BadParameter; + }; + + std::unique_ptr<DrmDisplayComposition> composition = compositor_ + .CreateComposition(); + composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_); + composition->SetDpmsMode(dpms_value); + int ret = compositor_.ApplyComposition(std::move(composition)); + if (ret) { + ALOGE("Failed to apply the dpms composition ret=%d", ret); + return HWC2::Error::BadParameter; + } + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::SetVsyncEnabled(int32_t enabled) { + supported(__func__); + vsync_worker_.VSyncControl(HWC2_VSYNC_ENABLE == enabled); + return HWC2::Error::None; +} + +uint32_t DrmHwcTwo::HwcDisplay::CalcPixOps( + std::map<uint32_t, DrmHwcTwo::HwcLayer *> &z_map, size_t first_z, + size_t size) { + uint32_t pixops = 0; + for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map) { + if (l.first >= first_z && l.first < first_z + size) { + hwc_rect_t df = l.second->display_frame(); + pixops += (df.right - df.left) * (df.bottom - df.top); + } + } + return pixops; +} + +void DrmHwcTwo::HwcDisplay::MarkValidated( + std::map<uint32_t, DrmHwcTwo::HwcLayer *> &z_map, size_t client_first_z, + size_t client_size) { + for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map) { + if (l.first >= client_first_z && l.first < client_first_z + client_size) + l.second->set_validated_type(HWC2::Composition::Client); + else + l.second->set_validated_type(HWC2::Composition::Device); + } +} + +HWC2::Error DrmHwcTwo::HwcDisplay::ValidateDisplay(uint32_t *num_types, + uint32_t *num_requests) { + supported(__func__); + + return backend_->ValidateDisplay(this, num_types, num_requests); +} + +#if PLATFORM_SDK_VERSION > 28 +HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayIdentificationData( + uint8_t *outPort, uint32_t *outDataSize, uint8_t *outData) { + supported(__func__); + + drmModePropertyBlobPtr blob; + + if (connector_->GetEdidBlob(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) { + unsupported(__func__, outCapabilities); + + if (outNumCapabilities == NULL) { + 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 (mode != HAL_COLOR_MODE_NATIVE) + return HWC2::Error::BadParameter; + if (intent != HAL_RENDER_INTENT_COLORIMETRIC) + return HWC2::Error::BadParameter; + color_mode_ = mode; + return HWC2::Error::None; +} + +#endif /* PLATFORM_SDK_VERSION > 27 */ + +HWC2::Error DrmHwcTwo::HwcLayer::SetCursorPosition(int32_t x, int32_t y) { + supported(__func__); + cursor_x_ = x; + cursor_y_ = y; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerBlendMode(int32_t mode) { + supported(__func__); + blending_ = static_cast<HWC2::BlendMode>(mode); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerBuffer(buffer_handle_t buffer, + int32_t acquire_fence) { + supported(__func__); + UniqueFd uf(acquire_fence); + + set_buffer(buffer); + set_acquire_fence(uf.get()); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerColor(hwc_color_t color) { + // TODO: Put to client composition here? + supported(__func__); + layer_color_ = color; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerCompositionType(int32_t type) { + sf_type_ = static_cast<HWC2::Composition>(type); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDataspace(int32_t dataspace) { + supported(__func__); + dataspace_ = static_cast<android_dataspace_t>(dataspace); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDisplayFrame(hwc_rect_t frame) { + supported(__func__); + display_frame_ = frame; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerPlaneAlpha(float alpha) { + supported(__func__); + alpha_ = alpha; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSidebandStream( + const native_handle_t *stream) { + supported(__func__); + // TODO: We don't support sideband + return unsupported(__func__, stream); +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSourceCrop(hwc_frect_t crop) { + supported(__func__); + source_crop_ = crop; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSurfaceDamage(hwc_region_t damage) { + supported(__func__); + // 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) { + supported(__func__); + transform_ = static_cast<HWC2::Transform>(transform); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerVisibleRegion(hwc_region_t visible) { + supported(__func__); + // 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) { + supported(__func__); + z_order_ = order; + return HWC2::Error::None; +} + +void DrmHwcTwo::HwcLayer::PopulateDrmLayer(DrmHwcLayer *layer) { + supported(__func__); + switch (blending_) { + case HWC2::BlendMode::None: + layer->blending = DrmHwcBlending::kNone; + break; + case HWC2::BlendMode::Premultiplied: + layer->blending = DrmHwcBlending::kPreMult; + break; + case HWC2::BlendMode::Coverage: + layer->blending = DrmHwcBlending::kCoverage; + break; + default: + ALOGE("Unknown blending mode b=%d", blending_); + layer->blending = DrmHwcBlending::kNone; + break; + } + + OutputFd release_fence = release_fence_output(); + + layer->sf_handle = buffer_; + layer->acquire_fence = acquire_fence_.Release(); + layer->release_fence = std::move(release_fence); + layer->SetDisplayFrame(display_frame_); + layer->alpha = static_cast<uint16_t>(65535.0f * alpha_ + 0.5f); + layer->SetSourceCrop(source_crop_); + layer->SetTransform(static_cast<int32_t>(transform_)); +} + +void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) { + auto cb = callbacks_.find(HWC2::Callback::Hotplug); + if (cb == callbacks_.end()) + 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)); +} + +void DrmHwcTwo::HandleInitialHotplugState(DrmDevice *drmDevice) { + for (auto &conn : drmDevice->connectors()) { + if (conn->state() != DRM_MODE_CONNECTED) + continue; + HandleDisplayHotplug(conn->display(), conn->state()); + } +} + +void DrmHwcTwo::DrmHotplugHandler::HandleEvent(uint64_t timestamp_us) { + for (auto &conn : drm_->connectors()) { + drmModeConnection old_state = conn->state(); + drmModeConnection cur_state = conn->UpdateModes() + ? DRM_MODE_UNKNOWNCONNECTION + : conn->state(); + + if (cur_state == old_state) + continue; + + ALOGI("%s event @%" PRIu64 " for connector %u on display %d", + cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", timestamp_us, + conn->id(), conn->display()); + + int display_id = conn->display(); + if (cur_state == DRM_MODE_CONNECTED) { + auto &display = hwc2_->displays_.at(display_id); + display.ChosePreferredConfig(); + } else { + auto &display = hwc2_->displays_.at(display_id); + display.ClearDisplay(); + } + + hwc2_->HandleDisplayHotplug(display_id, cur_state); + } +} + +// 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*/) { + supported(__func__); + *out_count = 0; +} + +// 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 *>); +#if PLATFORM_SDK_VERSION > 27 + case HWC2::FunctionDescriptor::GetRenderIntents: + return ToHook<HWC2_PFN_GET_RENDER_INTENTS>( + DisplayHook<decltype(&HwcDisplay::GetRenderIntents), + &HwcDisplay::GetRenderIntents, int32_t, uint32_t *, + int32_t *>); + case HWC2::FunctionDescriptor::SetColorModeWithRenderIntent: + return ToHook<HWC2_PFN_SET_COLOR_MODE_WITH_RENDER_INTENT>( + DisplayHook<decltype(&HwcDisplay::SetColorModeWithIntent), + &HwcDisplay::SetColorModeWithIntent, int32_t, int32_t>); +#endif +#if PLATFORM_SDK_VERSION > 28 + case HWC2::FunctionDescriptor::GetDisplayIdentificationData: + return ToHook<HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA>( + DisplayHook<decltype(&HwcDisplay::GetDisplayIdentificationData), + &HwcDisplay::GetDisplayIdentificationData, uint8_t *, + uint32_t *, uint8_t *>); + case HWC2::FunctionDescriptor::GetDisplayCapabilities: + return ToHook<HWC2_PFN_GET_DISPLAY_CAPABILITIES>( + DisplayHook<decltype(&HwcDisplay::GetDisplayCapabilities), + &HwcDisplay::GetDisplayCapabilities, uint32_t *, + uint32_t *>); + case HWC2::FunctionDescriptor::GetDisplayBrightnessSupport: + return ToHook<HWC2_PFN_GET_DISPLAY_BRIGHTNESS_SUPPORT>( + DisplayHook<decltype(&HwcDisplay::GetDisplayBrightnessSupport), + &HwcDisplay::GetDisplayBrightnessSupport, bool *>); + case HWC2::FunctionDescriptor::SetDisplayBrightness: + return ToHook<HWC2_PFN_SET_DISPLAY_BRIGHTNESS>( + DisplayHook<decltype(&HwcDisplay::SetDisplayBrightness), + &HwcDisplay::SetDisplayBrightness, float>); +#endif /* PLATFORM_SDK_VERSION > 28 */ + // 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) { + supported(__func__); + if (strcmp(name, HWC_HARDWARE_COMPOSER)) { + ALOGE("Invalid module name- %s", name); + return -EINVAL; + } + + 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; + } + + 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}, +}; |