/* * 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 "drmdisplaycomposition.h" #include "drmhwcomposer.h" #include "drmhwctwo.h" #include "platform.h" #include "vsyncworker.h" #include #include #include #include #include #include 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(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::Init() { int ret = drm_.Init(); if (ret) { ALOGE("Can't initialize drm object %d", ret); return HWC2::Error::NoResources; } importer_.reset(Importer::CreateInstance(&drm_)); if (!importer_) { ALOGE("Failed to create importer instance"); return HWC2::Error::NoResources; } ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (const hw_module_t **)&gralloc_); if (ret) { ALOGE("Failed to open gralloc module %d", ret); return HWC2::Error::NoResources; } displays_.emplace(std::piecewise_construct, std::forward_as_tuple(HWC_DISPLAY_PRIMARY), std::forward_as_tuple(&drm_, importer_, gralloc_, HWC_DISPLAY_PRIMARY, HWC2::DisplayType::Physical)); DrmCrtc *crtc = drm_.GetCrtcForDisplay(static_cast(HWC_DISPLAY_PRIMARY)); if (!crtc) { ALOGE("Failed to get crtc for display %d", static_cast(HWC_DISPLAY_PRIMARY)); return HWC2::Error::BadDisplay; } std::vector display_planes; for (auto &plane : drm_.planes()) { if (plane->GetCrtcSupported(*crtc)) display_planes.push_back(plane.get()); } displays_.at(HWC_DISPLAY_PRIMARY).Init(&display_planes); return HWC2::Error::None; } template 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); } void DrmHwcTwo::Dump(uint32_t *size, char *buffer) { // TODO: Implement dump unsupported(__func__, size, buffer); } 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(descriptor); callbacks_.emplace(callback, HwcCallback(data, function)); switch (callback) { case HWC2::Callback::Hotplug: { auto hotplug = reinterpret_cast(function); hotplug(data, HWC_DISPLAY_PRIMARY, static_cast(HWC2::Connection::Connected)); break; } case HWC2::Callback::Vsync: { for (std::pair &d : displays_) d.second.RegisterVsyncCallback(data, function); break; } default: break; } return HWC2::Error::None; } DrmHwcTwo::HwcDisplay::HwcDisplay(DrmResources *drm, std::shared_ptr importer, const gralloc_module_t *gralloc, hwc2_display_t handle, HWC2::DisplayType type) : drm_(drm), importer_(importer), gralloc_(gralloc), handle_(handle), type_(type) { supported(__func__); } HWC2::Error DrmHwcTwo::HwcDisplay::Init(std::vector *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(handle_); int ret = compositor_.Init(drm_, 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("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; } // 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; // Grab the first mode, we'll choose this as the active mode // TODO: Should choose the preferred mode here hwc2_config_t default_config; num_configs = 1; err = GetDisplayConfigs(&num_configs, &default_config); if (err != HWC2::Error::None) return err; 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; } return SetActiveConfig(default_config); } HWC2::Error DrmHwcTwo::HwcDisplay::RegisterVsyncCallback( hwc2_callback_data_t data, hwc2_function_pointer_t func) { supported(__func__); auto callback = std::make_shared(data, func); vsync_worker_.RegisterCallback(std::move(callback)); return HWC2::Error::None; } HWC2::Error DrmHwcTwo::HwcDisplay::AcceptDisplayChanges() { supported(__func__); uint32_t num_changes = 0; for (std::pair &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(layer_idx_), HwcLayer()); *layer = static_cast(layer_idx_); ++layer_idx_; return HWC2::Error::None; } HWC2::Error DrmHwcTwo::HwcDisplay::DestroyLayer(hwc2_layer_t layer) { supported(__func__); 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 &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(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 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 && 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__); // TODO: android_color_mode_t isn't defined yet! return unsupported(__func__, num_modes, modes); } 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(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; } } auto num_modes = static_cast(connector_->modes().size()); if (!configs) { *num_configs = num_modes; return HWC2::Error::None; } uint32_t idx = 0; for (const DrmMode &mode : connector_->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(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) { 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(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 &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::AddFenceToRetireFence(int fd) { supported(__func__); if (fd < 0) return; if (next_retire_fence_.get() >= 0) { int old_fence = next_retire_fence_.get(); next_retire_fence_.Set(sync_merge("dc_retire", old_fence, fd)); } else { next_retire_fence_.Set(dup(fd)); } } HWC2::Error DrmHwcTwo::HwcDisplay::PresentDisplay(int32_t *retire_fence) { supported(__func__); std::vector layers_map; layers_map.emplace_back(); DrmCompositionDisplayLayersMap &map = layers_map.back(); map.display = static_cast(handle_); map.geometry_changed = true; // TODO: Fix this // order the layers by z-order bool use_client_layer = false; uint32_t client_z_order = 0; std::map z_map; for (std::pair &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 highest client layer use_client_layer = true; client_z_order = std::max(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_)); // 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(importer_.get(), gralloc_); if (ret) { ALOGE("Failed to import layer, ret=%d", ret); return HWC2::Error::NoResources; } map.layers.emplace_back(std::move(layer)); } if (map.layers.empty()) { *retire_fence = -1; return HWC2::Error::None; } std::unique_ptr 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 primary_planes(primary_planes_); std::vector overlay_planes(overlay_planes_); ret = composition->Plan(compositor_.squash_state(), &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); } ret = compositor_.QueueComposition(std::move(composition)); if (ret) { ALOGE("Failed to apply the frame composition ret=%d", ret); return HWC2::Error::BadParameter; } // Now that the release fences have been generated by the compositor, make // sure they're managed properly for (std::pair &l : z_map) { l.second->manage_release_fence(); AddFenceToRetireFence(l.second->release_fence()); } // The retire fence returned here is for the last frame, so return it and // promote the next retire fence *retire_fence = retire_fence_.Release(); retire_fence_ = std::move(next_retire_fence_); ++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 composition = compositor_.CreateComposition(); composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_); int ret = composition->SetDisplayMode(*mode); ret = compositor_.QueueComposition(std::move(composition)); if (ret) { ALOGE("Failed to queue dpms composition on %d", ret); return HWC2::Error::BadConfig; } if (connector_->active_mode().id() == 0) connector_->set_active_mode(*mode); // 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); 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__); // TODO: android_color_mode_t isn't defined yet! return unsupported(__func__, mode); } HWC2::Error DrmHwcTwo::HwcDisplay::SetColorTransform(const float *matrix, int32_t hint) { supported(__func__); // TODO: Force client composition if we get this return unsupported(__func__, matrix, hint); } 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(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; default: ALOGI("Power mode %d is unsupported\n", mode); return HWC2::Error::Unsupported; }; std::unique_ptr composition = compositor_.CreateComposition(); composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_); composition->SetDpmsMode(dpms_value); int ret = compositor_.QueueComposition(std::move(composition)); if (ret) { ALOGE("Failed to apply the dpms composition ret=%d", ret); return HWC2::Error::BadParameter; } return HWC2::Error::None; } HWC2::Error DrmHwcTwo::HwcDisplay::SetVsyncEnabled(int32_t enabled) { supported(__func__); vsync_worker_.VSyncControl(enabled); return HWC2::Error::None; } HWC2::Error DrmHwcTwo::HwcDisplay::ValidateDisplay(uint32_t *num_types, uint32_t *num_requests) { supported(__func__); *num_types = 0; *num_requests = 0; for (std::pair &l : layers_) { DrmHwcTwo::HwcLayer &layer = l.second; switch (layer.sf_type()) { case HWC2::Composition::SolidColor: case HWC2::Composition::Cursor: case HWC2::Composition::Sideband: layer.set_validated_type(HWC2::Composition::Client); ++*num_types; break; default: layer.set_validated_type(layer.sf_type()); break; } } return HWC2::Error::None; } HWC2::Error DrmHwcTwo::HwcLayer::SetCursorPosition(int32_t x, int32_t y) { supported(__func__); // TODO: Implement proper cursor support return unsupported(__func__, x, y); } HWC2::Error DrmHwcTwo::HwcLayer::SetLayerBlendMode(int32_t mode) { supported(__func__); blending_ = static_cast(mode); return HWC2::Error::None; } HWC2::Error DrmHwcTwo::HwcLayer::SetLayerBuffer(buffer_handle_t buffer, int32_t acquire_fence) { supported(__func__); UniqueFd uf(acquire_fence); // The buffer and acquire_fence are handled elsewhere if (sf_type_ == HWC2::Composition::Client || sf_type_ == HWC2::Composition::Sideband || sf_type_ == HWC2::Composition::SolidColor) return HWC2::Error::None; set_buffer(buffer); set_acquire_fence(uf.get()); return HWC2::Error::None; } HWC2::Error DrmHwcTwo::HwcLayer::SetLayerColor(hwc_color_t color) { // TODO: Punt to client composition here? return unsupported(__func__, color); } HWC2::Error DrmHwcTwo::HwcLayer::SetLayerCompositionType(int32_t type) { sf_type_ = static_cast(type); return HWC2::Error::None; } HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDataspace(int32_t dataspace) { supported(__func__); dataspace_ = static_cast(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(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(255.0f * alpha_ + 0.5f); layer->SetSourceCrop(source_crop_); layer->SetTransform(static_cast(transform_)); } // 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(descriptor); switch (func) { // Device functions case HWC2::FunctionDescriptor::CreateVirtualDisplay: return ToHook( DeviceHook); case HWC2::FunctionDescriptor::DestroyVirtualDisplay: return ToHook( DeviceHook); case HWC2::FunctionDescriptor::Dump: return ToHook( DeviceHook); case HWC2::FunctionDescriptor::GetMaxVirtualDisplayCount: return ToHook( DeviceHook); case HWC2::FunctionDescriptor::RegisterCallback: return ToHook( DeviceHook); // Display functions case HWC2::FunctionDescriptor::AcceptDisplayChanges: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::CreateLayer: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::DestroyLayer: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetActiveConfig: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetChangedCompositionTypes: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetClientTargetSupport: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetColorModes: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetDisplayAttribute: return ToHook(DisplayHook< decltype(&HwcDisplay::GetDisplayAttribute), &HwcDisplay::GetDisplayAttribute, hwc2_config_t, int32_t, int32_t *>); case HWC2::FunctionDescriptor::GetDisplayConfigs: return ToHook(DisplayHook< decltype(&HwcDisplay::GetDisplayConfigs), &HwcDisplay::GetDisplayConfigs, uint32_t *, hwc2_config_t *>); case HWC2::FunctionDescriptor::GetDisplayName: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetDisplayRequests: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetDisplayType: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetDozeSupport: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetHdrCapabilities: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetReleaseFences: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::PresentDisplay: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::SetActiveConfig: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::SetClientTarget: return ToHook(DisplayHook< decltype(&HwcDisplay::SetClientTarget), &HwcDisplay::SetClientTarget, buffer_handle_t, int32_t, int32_t, hwc_region_t>); case HWC2::FunctionDescriptor::SetColorMode: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::SetColorTransform: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::SetOutputBuffer: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::SetPowerMode: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::SetVsyncEnabled: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::ValidateDisplay: return ToHook( DisplayHook); // Layer functions case HWC2::FunctionDescriptor::SetCursorPosition: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerBlendMode: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerBuffer: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerColor: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerCompositionType: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerDataspace: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerDisplayFrame: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerPlaneAlpha: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerSidebandStream: return ToHook(LayerHook< decltype(&HwcLayer::SetLayerSidebandStream), &HwcLayer::SetLayerSidebandStream, const native_handle_t *>); case HWC2::FunctionDescriptor::SetLayerSourceCrop: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerSurfaceDamage: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerTransform: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerVisibleRegion: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerZOrder: return ToHook( LayerHook); 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 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(module); *dev = &ctx->common; ctx.release(); return 0; } } 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}, };