diff options
author | Sean Paul <seanpaul@chromium.org> | 2017-04-25 15:42:17 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2017-04-25 15:42:17 +0000 |
commit | 09db4a4721840702d3db81b2dcfb0f09bb046909 (patch) | |
tree | 290054237e5b83232482a87d52bf27ea9ed71850 | |
parent | 255f3a387a67c1024e0438c789eaf67a8f5c6b2c (diff) | |
parent | 982615eba7fba6cd205045032d564bacaee8b3ad (diff) | |
download | drm_hwcomposer-09db4a4721840702d3db81b2dcfb0f09bb046909.tar.gz |
drm_hwcomposer: Partially implement HWC2 API am: ac8741504b am: 46a1916dbf am: c2044d3ab8 am: fcc69d22ee
am: 982615eba7
Change-Id: I21e9b2ffe60884759f9ff7868676e1aa95c9c8ed
-rw-r--r-- | drmhwctwo.cpp | 764 | ||||
-rw-r--r-- | drmhwctwo.h | 127 |
2 files changed, 831 insertions, 60 deletions
diff --git a/drmhwctwo.cpp b/drmhwctwo.cpp index e7fecb8..138f5fa 100644 --- a/drmhwctwo.cpp +++ b/drmhwctwo.cpp @@ -17,218 +17,815 @@ #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 <inttypes.h> +#include <string> #include <cutils/log.h> +#include <cutils/properties.h> +#include <hardware/hardware.h> #include <hardware/hwcomposer2.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::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<int>(HWC_DISPLAY_PRIMARY)); + if (!crtc) { + ALOGE("Failed to get crtc for display %d", + static_cast<int>(HWC_DISPLAY_PRIMARY)); + 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(HWC_DISPLAY_PRIMARY).Init(&display_planes); + return HWC2::Error::None; +} + 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, 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) { - return unsupported(__func__, descriptor, data, function); + hwc2_callback_data_t data, + hwc2_function_pointer_t function) { + supported(__func__); + auto callback = static_cast<HWC2::Callback>(descriptor); + callbacks_.emplace(callback, HwcCallback(data, function)); + + switch (callback) { + case HWC2::Callback::Hotplug: { + auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(function); + hotplug(data, HWC_DISPLAY_PRIMARY, + static_cast<int32_t>(HWC2::Connection::Connected)); + 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(DrmResources *drm, + std::shared_ptr<Importer> 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<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(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<DrmVsyncCallback>(data, func); + int ret = vsync_worker_.RegisterCallback(std::move(callback)); + if (ret) { + ALOGE("Failed to register callback d=%" PRIu64 " ret=%d", handle_, ret); + return HWC2::Error::BadDisplay; + } + return HWC2::Error::None; } HWC2::Error DrmHwcTwo::HwcDisplay::AcceptDisplayChanges() { - return unsupported(__func__); + supported(__func__); + uint32_t num_changes = 0; + 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) { - return unsupported(__func__, 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) { - return unsupported(__func__, layer); + supported(__func__); + layers_.erase(layer); + return HWC2::Error::None; } HWC2::Error DrmHwcTwo::HwcDisplay::GetActiveConfig(hwc2_config_t *config) { - return unsupported(__func__, 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) { - return unsupported(__func__, num_elements, layers, 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) { - return unsupported(__func__, width, height, format, dataspace); + 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) { + 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, - int32_t *value) { - return unsupported(__func__, config, attribute, value); + 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) { - return unsupported(__func__, num_configs, 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<uint32_t>(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) { - return unsupported(__func__, size, 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) { - return unsupported(__func__, display_requests, num_elements, layers, - layer_requests); +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) { - return unsupported(__func__, type); + supported(__func__); + *type = static_cast<int32_t>(type_); + return HWC2::Error::None; } HWC2::Error DrmHwcTwo::HwcDisplay::GetDozeSupport(int32_t *support) { - return unsupported(__func__, 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) { - return unsupported(__func__, num_elements, layers, fences); + 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::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) { - return unsupported(__func__, retire_fence); + supported(__func__); + 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 = 0; + 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 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<const uint32_t, DrmHwcTwo::HwcLayer *> &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<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(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<const uint32_t, DrmHwcTwo::HwcLayer *> &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) { - return unsupported(__func__, 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_.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<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) { - return unsupported(__func__, target, acquire_fence, dataspace, 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) { + 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) { + 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) { - return unsupported(__func__, mode); +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; + default: + ALOGI("Power mode %d is unsupported\n", mode); + return HWC2::Error::Unsupported; + }; + + std::unique_ptr<DrmDisplayComposition> 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) { - return unsupported(__func__, enabled); + supported(__func__); + vsync_worker_.VSyncControl(enabled); + return HWC2::Error::None; } HWC2::Error DrmHwcTwo::HwcDisplay::ValidateDisplay(uint32_t *num_types, - uint32_t *num_requests) { - return unsupported(__func__, num_types, num_requests); + uint32_t *num_requests) { + supported(__func__); + *num_types = 0; + *num_requests = 0; + for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &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) { - return unsupported(__func__, 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) { - return unsupported(__func__, buffer, acquire_fence); + 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) { - return unsupported(__func__, type); + sf_type_ = static_cast<HWC2::Composition>(type); + return HWC2::Error::None; } HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDataspace(int32_t dataspace) { - return unsupported(__func__, dataspace); + supported(__func__); + dataspace_ = static_cast<android_dataspace_t>(dataspace); + return HWC2::Error::None; } HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDisplayFrame(hwc_rect_t frame) { - return unsupported(__func__, frame); + supported(__func__); + display_frame_ = frame; + return HWC2::Error::None; } HWC2::Error DrmHwcTwo::HwcLayer::SetLayerPlaneAlpha(float alpha) { - return unsupported(__func__, 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) { - return unsupported(__func__, crop); + supported(__func__); + source_crop_ = crop; + return HWC2::Error::None; } HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSurfaceDamage(hwc_region_t damage) { - return unsupported(__func__, 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) { - return unsupported(__func__, transform); + supported(__func__); + transform_ = static_cast<HWC2::Transform>(transform); + return HWC2::Error::None; } HWC2::Error DrmHwcTwo::HwcLayer::SetLayerVisibleRegion(hwc_region_t visible) { - return unsupported(__func__, 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 z) { - return unsupported(__func__, z); +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<uint8_t>(255.0f * alpha_ + 0.5f); + layer->SetSourceCrop(source_crop_); + layer->SetTransform(static_cast<int32_t>(transform_)); } // static @@ -239,18 +836,17 @@ int DrmHwcTwo::HookDevClose(hw_device_t * /*dev*/) { // static void DrmHwcTwo::HookDevGetCapabilities(hwc2_device_t * /*dev*/, - uint32_t *out_count, - int32_t * /*out_capabilities*/) { - unsupported(__func__); + 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) { - DrmHwcTwo *hwc = toDrmHwcTwo(dev); - HWC2::FunctionDescriptor func = (HWC2::FunctionDescriptor)descriptor; - +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: @@ -332,6 +928,11 @@ hwc2_function_pointer_t DrmHwcTwo::HookDevGetFunction(struct hwc2_device *dev, 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), @@ -431,8 +1032,51 @@ hwc2_function_pointer_t DrmHwcTwo::HookDevGetFunction(struct hwc2_device *dev, 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; } +} + +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}, +}; diff --git a/drmhwctwo.h b/drmhwctwo.h index 8bc5ce9..038412d 100644 --- a/drmhwctwo.h +++ b/drmhwctwo.h @@ -14,6 +14,12 @@ * limitations under the License. */ +#include "drmdisplaycompositor.h" +#include "drmhwcomposer.h" +#include "drmresources.h" +#include "platform.h" +#include "vsyncworker.h" + #include <hardware/hwcomposer2.h> #include <map> @@ -22,11 +28,67 @@ namespace android { class DrmHwcTwo : public hwc2_device_t { public: + static int HookDevOpen(const struct hw_module_t *module, const char *name, + struct hw_device_t **dev); + DrmHwcTwo(); + HWC2::Error Init(); + private: class HwcLayer { public: + HWC2::Composition sf_type() const { + return sf_type_; + } + HWC2::Composition validated_type() const { + return validated_type_; + } + void accept_type_change() { + sf_type_ = validated_type_; + } + void set_validated_type(HWC2::Composition type) { + validated_type_ = type; + } + bool type_changed() const { + return sf_type_ != validated_type_; + } + + uint32_t z_order() const { + return z_order_; + } + + buffer_handle_t buffer() { + return buffer_; + } + void set_buffer(buffer_handle_t buffer) { + buffer_ = buffer; + } + + int take_acquire_fence() { + return acquire_fence_.Release(); + } + void set_acquire_fence(int acquire_fence) { + acquire_fence_.Set(dup(acquire_fence)); + } + + int release_fence() { + return release_fence_.get(); + } + int take_release_fence() { + return release_fence_.Release(); + } + void manage_release_fence() { + release_fence_.Set(release_fence_raw_); + release_fence_raw_ = -1; + } + OutputFd release_fence_output() { + return OutputFd(&release_fence_raw_); + } + + void PopulateDrmLayer(DrmHwcLayer *layer); + + // Layer hooks HWC2::Error SetCursorPosition(int32_t x, int32_t y); HWC2::Error SetLayerBlendMode(int32_t mode); HWC2::Error SetLayerBuffer(buffer_handle_t buffer, int32_t acquire_fence); @@ -41,10 +103,45 @@ class DrmHwcTwo : public hwc2_device_t { HWC2::Error SetLayerTransform(int32_t transform); HWC2::Error SetLayerVisibleRegion(hwc_region_t visible); HWC2::Error SetLayerZOrder(uint32_t z); + + private: + // sf_type_ stores the initial type given to us by surfaceflinger, + // validated_type_ stores the type after running ValidateDisplay + HWC2::Composition sf_type_ = HWC2::Composition::Invalid; + HWC2::Composition validated_type_ = HWC2::Composition::Invalid; + + HWC2::BlendMode blending_ = HWC2::BlendMode::None; + buffer_handle_t buffer_; + UniqueFd acquire_fence_; + int release_fence_raw_ = -1; + UniqueFd release_fence_; + hwc_rect_t display_frame_; + float alpha_ = 1.0f; + hwc_frect_t source_crop_; + HWC2::Transform transform_ = HWC2::Transform::None; + uint32_t z_order_ = 0; + android_dataspace_t dataspace_ = HAL_DATASPACE_UNKNOWN; + }; + + struct HwcCallback { + HwcCallback(hwc2_callback_data_t d, hwc2_function_pointer_t f) + : data(d), func(f) { + } + hwc2_callback_data_t data; + hwc2_function_pointer_t func; }; class HwcDisplay { public: + HwcDisplay(DrmResources *drm, std::shared_ptr<Importer> importer, + const gralloc_module_t *gralloc, hwc2_display_t handle, + HWC2::DisplayType type); + HwcDisplay(const HwcDisplay &) = delete; + HWC2::Error Init(std::vector<DrmPlane *> *planes); + + HWC2::Error RegisterVsyncCallback(hwc2_callback_data_t data, + hwc2_function_pointer_t func); + // HWC Hooks HWC2::Error AcceptDisplayChanges(); HWC2::Error CreateLayer(hwc2_layer_t *layer); @@ -66,6 +163,10 @@ class DrmHwcTwo : public hwc2_device_t { int32_t *layer_requests); HWC2::Error GetDisplayType(int32_t *type); 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 *retire_fence); @@ -83,7 +184,29 @@ class DrmHwcTwo : public hwc2_device_t { } private: + void AddFenceToRetireFence(int fd); + + DrmResources *drm_; + DrmDisplayCompositor compositor_; + std::shared_ptr<Importer> importer_; + std::unique_ptr<Planner> planner_; + const gralloc_module_t *gralloc_; + + std::vector<DrmPlane *> primary_planes_; + std::vector<DrmPlane *> overlay_planes_; + + VSyncWorker vsync_worker_; + DrmConnector *connector_ = NULL; + DrmCrtc *crtc_ = NULL; + hwc2_display_t handle_; + HWC2::DisplayType type_; + uint32_t layer_idx_ = 0; std::map<hwc2_layer_t, HwcLayer> layers_; + HwcLayer client_layer_; + UniqueFd retire_fence_; + UniqueFd next_retire_fence_; + + uint32_t frame_no_ = 0; }; static DrmHwcTwo *toDrmHwcTwo(hwc2_device_t *dev) { @@ -136,6 +259,10 @@ class DrmHwcTwo : public hwc2_device_t { HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data, hwc2_function_pointer_t function); + DrmResources drm_; + std::shared_ptr<Importer> importer_; // Shared with HwcDisplay + const gralloc_module_t *gralloc_; std::map<hwc2_display_t, HwcDisplay> displays_; + std::map<HWC2::Callback, HwcCallback> callbacks_; }; } |