diff options
-rw-r--r-- | Android.mk | 7 | ||||
-rw-r--r-- | drmdisplaycomposition.cpp | 8 | ||||
-rw-r--r-- | drmdisplaycompositor.cpp | 8 | ||||
-rw-r--r-- | drmeventlistener.cpp | 2 | ||||
-rw-r--r-- | drmhwcomposer.h | 6 | ||||
-rw-r--r-- | drmhwctwo.cpp | 1088 | ||||
-rw-r--r-- | drmhwctwo.h | 271 | ||||
-rw-r--r-- | drmresources.cpp | 5 | ||||
-rw-r--r-- | drmresources.h | 11 | ||||
-rw-r--r-- | glworker.cpp | 16 | ||||
-rw-r--r-- | glworker.h | 3 | ||||
-rw-r--r-- | hwcomposer.cpp | 170 | ||||
-rw-r--r-- | hwcutils.cpp | 199 | ||||
-rw-r--r-- | platform.h | 4 | ||||
-rw-r--r-- | platformdrmgeneric.cpp | 17 | ||||
-rw-r--r-- | platformdrmgeneric.h | 1 | ||||
-rw-r--r-- | platformnv.cpp | 11 | ||||
-rw-r--r-- | platformnv.h | 1 | ||||
-rw-r--r-- | vsyncworker.cpp | 18 | ||||
-rw-r--r-- | vsyncworker.h | 15 |
20 files changed, 1674 insertions, 187 deletions
@@ -75,11 +75,12 @@ LOCAL_SRC_FILES := \ drmdisplaycompositor.cpp \ drmencoder.cpp \ drmeventlistener.cpp \ + drmhwctwo.cpp \ drmmode.cpp \ drmplane.cpp \ drmproperty.cpp \ glworker.cpp \ - hwcomposer.cpp \ + hwcutils.cpp \ platform.cpp \ separate_rects.cpp \ virtualcompositorworker.cpp \ @@ -87,6 +88,10 @@ LOCAL_SRC_FILES := \ LOCAL_CFLAGS := $(common_drm_hwcomposer_cflags) +LOCAL_CPPFLAGS += \ + -DHWC2_USE_CPP11 \ + -DHWC2_INCLUDE_STRINGIFICATION + ifeq ($(strip $(BOARD_DRM_HWCOMPOSER_BUFFER_IMPORTER)),nvidia-gralloc) LOCAL_CPPFLAGS += -DUSE_NVIDIA_IMPORTER LOCAL_SRC_FILES += platformnv.cpp diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp index b7f8d1a..0f8084b 100644 --- a/drmdisplaycomposition.cpp +++ b/drmdisplaycomposition.cpp @@ -258,8 +258,10 @@ int DrmDisplayComposition::CreateAndAssignReleaseFences() { if (!layer->release_fence) continue; int ret = layer->release_fence.Set(CreateNextTimelineFence()); - if (ret < 0) + if (ret < 0) { + ALOGE("Failed to set the release fence (squash) %d", ret); return ret; + } } timeline_squash_done_ = timeline_; @@ -276,8 +278,10 @@ int DrmDisplayComposition::CreateAndAssignReleaseFences() { if (!layer->release_fence) continue; int ret = layer->release_fence.Set(CreateNextTimelineFence()); - if (ret < 0) + if (ret < 0) { + ALOGE("Failed to set the release fence (comp) %d", ret); return ret; + } } return 0; diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp index 14b87aa..b3cfb6d 100644 --- a/drmdisplaycompositor.cpp +++ b/drmdisplaycompositor.cpp @@ -375,7 +375,8 @@ int DrmDisplayCompositor::ApplySquash(DrmDisplayComposition *display_comp) { std::vector<DrmCompositionRegion> ®ions = display_comp->squash_regions(); ret = pre_compositor_->Composite(display_comp->layers().data(), - regions.data(), regions.size(), fb.buffer()); + regions.data(), regions.size(), fb.buffer(), + display_comp->importer()); pre_compositor_->Finish(); if (ret) { @@ -408,7 +409,8 @@ int DrmDisplayCompositor::ApplyPreComposite( std::vector<DrmCompositionRegion> ®ions = display_comp->pre_comp_regions(); ret = pre_compositor_->Composite(display_comp->layers().data(), - regions.data(), regions.size(), fb.buffer()); + regions.data(), regions.size(), fb.buffer(), + display_comp->importer()); pre_compositor_->Finish(); if (ret) { @@ -626,6 +628,8 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp, if (ret) ALOGW("Acquire fence %d wait %d failed (%d). Total time %d", acquire_fence, i, ret, total_fence_timeout); + else + break; } if (ret) { ALOGE("Failed to wait for acquire %d/%d", acquire_fence, ret); diff --git a/drmeventlistener.cpp b/drmeventlistener.cpp index a07bd89..7a21980 100644 --- a/drmeventlistener.cpp +++ b/drmeventlistener.cpp @@ -126,7 +126,7 @@ void DrmEventListener::Routine() { if (FD_ISSET(drm_->fd(), &fds_)) { drmEventContext event_context = { - .version = DRM_EVENT_CONTEXT_VERSION, + .version = 2, .vblank_handler = NULL, .page_flip_handler = DrmEventListener::FlipHandler}; drmHandleEvent(drm_->fd(), &event_context); diff --git a/drmhwcomposer.h b/drmhwcomposer.h index d087873..f8440fb 100644 --- a/drmhwcomposer.h +++ b/drmhwcomposer.h @@ -144,13 +144,17 @@ struct DrmHwcLayer { uint8_t alpha = 0xff; DrmHwcRect<float> source_crop; DrmHwcRect<int> display_frame; - std::vector<DrmHwcRect<int>> source_damage; UniqueFd acquire_fence; OutputFd release_fence; int InitFromHwcLayer(hwc_layer_1_t *sf_layer, Importer *importer, const gralloc_module_t *gralloc); + int ImportBuffer(Importer *importer, const gralloc_module_t *gralloc); + + void SetTransform(int32_t sf_transform); + void SetSourceCrop(hwc_frect_t const &crop); + void SetDisplayFrame(hwc_rect_t const &frame); buffer_handle_t get_usable_handle() const { return handle.get() != NULL ? handle.get() : sf_handle; diff --git a/drmhwctwo.cpp b/drmhwctwo.cpp new file mode 100644 index 0000000..8c853f4 --- /dev/null +++ b/drmhwctwo.cpp @@ -0,0 +1,1088 @@ +/* + * 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 <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, 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<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); + 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<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__); + 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; + } + } + + 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) { + 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::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<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) { + 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) { + 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::Unsupported; + + color_mode_ = mode; + return HWC2::Error::None; +} + +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<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) { + 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<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__); + 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); + + // 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<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<uint8_t>(255.0f * alpha_ + 0.5f); + layer->SetSourceCrop(source_crop_); + layer->SetTransform(static_cast<int32_t>(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<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 *>); + + // 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; +} +} + +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 new file mode 100644 index 0000000..0490e2a --- /dev/null +++ b/drmhwctwo.h @@ -0,0 +1,271 @@ +/* + * 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. + */ + +#include "drmdisplaycompositor.h" +#include "drmhwcomposer.h" +#include "drmresources.h" +#include "platform.h" +#include "vsyncworker.h" + +#include <hardware/hwcomposer2.h> + +#include <map> + +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); + HWC2::Error SetLayerColor(hwc_color_t color); + HWC2::Error SetLayerCompositionType(int32_t type); + HWC2::Error SetLayerDataspace(int32_t dataspace); + HWC2::Error SetLayerDisplayFrame(hwc_rect_t frame); + HWC2::Error SetLayerPlaneAlpha(float alpha); + HWC2::Error SetLayerSidebandStream(const native_handle_t *stream); + HWC2::Error SetLayerSourceCrop(hwc_frect_t crop); + HWC2::Error SetLayerSurfaceDamage(hwc_region_t damage); + 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_; + int32_t cursor_x_; + int32_t cursor_y_; + 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); + HWC2::Error DestroyLayer(hwc2_layer_t layer); + HWC2::Error GetActiveConfig(hwc2_config_t *config); + HWC2::Error GetChangedCompositionTypes(uint32_t *num_elements, + hwc2_layer_t *layers, + int32_t *types); + HWC2::Error GetClientTargetSupport(uint32_t width, uint32_t height, + int32_t format, int32_t dataspace); + HWC2::Error GetColorModes(uint32_t *num_modes, int32_t *modes); + HWC2::Error GetDisplayAttribute(hwc2_config_t config, int32_t attribute, + int32_t *value); + HWC2::Error GetDisplayConfigs(uint32_t *num_configs, + hwc2_config_t *configs); + HWC2::Error GetDisplayName(uint32_t *size, char *name); + HWC2::Error GetDisplayRequests(int32_t *display_requests, + uint32_t *num_elements, hwc2_layer_t *layers, + int32_t *layer_requests); + HWC2::Error GetDisplayType(int32_t *type); + 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); + HWC2::Error SetActiveConfig(hwc2_config_t config); + HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence, + int32_t dataspace, hwc_region_t damage); + HWC2::Error SetColorMode(int32_t mode); + HWC2::Error SetColorTransform(const float *matrix, int32_t hint); + HWC2::Error SetOutputBuffer(buffer_handle_t buffer, int32_t release_fence); + HWC2::Error SetPowerMode(int32_t mode); + HWC2::Error SetVsyncEnabled(int32_t enabled); + HWC2::Error ValidateDisplay(uint32_t *num_types, uint32_t *num_requests); + HwcLayer &get_layer(hwc2_layer_t layer) { + return layers_.at(layer); + } + + 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_; + int32_t color_mode_; + + uint32_t frame_no_ = 0; + }; + + static DrmHwcTwo *toDrmHwcTwo(hwc2_device_t *dev) { + return static_cast<DrmHwcTwo *>(dev); + } + + template <typename PFN, typename T> + static hwc2_function_pointer_t ToHook(T function) { + static_assert(std::is_same<PFN, T>::value, "Incompatible fn pointer"); + return reinterpret_cast<hwc2_function_pointer_t>(function); + } + + template <typename T, typename HookType, HookType func, typename... Args> + static T DeviceHook(hwc2_device_t *dev, Args... args) { + DrmHwcTwo *hwc = toDrmHwcTwo(dev); + return static_cast<T>(((*hwc).*func)(std::forward<Args>(args)...)); + } + + template <typename HookType, HookType func, typename... Args> + static int32_t DisplayHook(hwc2_device_t *dev, hwc2_display_t display_handle, + Args... args) { + DrmHwcTwo *hwc = toDrmHwcTwo(dev); + HwcDisplay &display = hwc->displays_.at(display_handle); + return static_cast<int32_t>((display.*func)(std::forward<Args>(args)...)); + } + + template <typename HookType, HookType func, typename... Args> + static int32_t LayerHook(hwc2_device_t *dev, hwc2_display_t display_handle, + hwc2_layer_t layer_handle, Args... args) { + DrmHwcTwo *hwc = toDrmHwcTwo(dev); + HwcDisplay &display = hwc->displays_.at(display_handle); + HwcLayer &layer = display.get_layer(layer_handle); + return static_cast<int32_t>((layer.*func)(std::forward<Args>(args)...)); + } + + // hwc2_device_t hooks + static int HookDevClose(hw_device_t *dev); + static void HookDevGetCapabilities(hwc2_device_t *dev, uint32_t *out_count, + int32_t *out_capabilities); + static hwc2_function_pointer_t HookDevGetFunction(struct hwc2_device *device, + int32_t descriptor); + + // Device functions + HWC2::Error CreateVirtualDisplay(uint32_t width, uint32_t height, + int32_t *format, + hwc2_display_t *display); + HWC2::Error DestroyVirtualDisplay(hwc2_display_t display); + void Dump(uint32_t *size, char *buffer); + uint32_t GetMaxVirtualDisplayCount(); + 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_; +}; +} diff --git a/drmresources.cpp b/drmresources.cpp index e433239..6b8ed03 100644 --- a/drmresources.cpp +++ b/drmresources.cpp @@ -71,6 +71,11 @@ int DrmResources::Init() { return -ENODEV; } + min_resolution_ = + std::pair<uint32_t, uint32_t>(res->min_width, res->min_height); + max_resolution_ = + std::pair<uint32_t, uint32_t>(res->max_width, res->max_height); + bool found_primary = false; int display_num = 1; diff --git a/drmresources.h b/drmresources.h index 64e6b57..011f87e 100644 --- a/drmresources.h +++ b/drmresources.h @@ -47,6 +47,14 @@ class DrmResources { return planes_; } + std::pair<uint32_t, uint32_t> min_resolution() const { + return min_resolution_; + } + + std::pair<uint32_t, uint32_t> max_resolution() const { + return max_resolution_; + } + DrmConnector *GetConnectorForDisplay(int display) const; DrmCrtc *GetCrtcForDisplay(int display) const; DrmPlane *GetPlane(uint32_t id) const; @@ -83,6 +91,9 @@ class DrmResources { std::vector<std::unique_ptr<DrmPlane>> planes_; DrmCompositor compositor_; DrmEventListener event_listener_; + + std::pair<uint32_t, uint32_t> min_resolution_; + std::pair<uint32_t, uint32_t> max_resolution_; }; } diff --git a/glworker.cpp b/glworker.cpp index 6ce2de3..e12995e 100644 --- a/glworker.cpp +++ b/glworker.cpp @@ -35,14 +35,10 @@ #include <utils/Trace.h> #include "drmdisplaycomposition.h" +#include "platform.h" #include "glworker.h" -// TODO(zachr): use hwc_drm_bo to turn buffer handles into textures -#ifndef EGL_NATIVE_HANDLE_ANDROID_NVX -#define EGL_NATIVE_HANDLE_ANDROID_NVX 0x322A -#endif - #define MAX_OVERLAPPING_LAYERS 64 namespace android { @@ -416,10 +412,9 @@ static int EGLFenceWait(EGLDisplay egl_display, int acquireFenceFd) { static int CreateTextureFromHandle(EGLDisplay egl_display, buffer_handle_t handle, + Importer *importer, AutoEGLImageAndGLTexture *out) { - EGLImageKHR image = eglCreateImageKHR( - egl_display, EGL_NO_CONTEXT, EGL_NATIVE_HANDLE_ANDROID_NVX, - (EGLClientBuffer)handle, NULL /* no attribs */); + EGLImageKHR image = importer->ImportImage(egl_display, handle); if (image == EGL_NO_IMAGE_KHR) { ALOGE("Failed to make image %s %p", GetEGLError(), handle); @@ -552,7 +547,8 @@ GLWorkerCompositor::~GLWorkerCompositor() { int GLWorkerCompositor::Composite(DrmHwcLayer *layers, DrmCompositionRegion *regions, size_t num_regions, - const sp<GraphicBuffer> &framebuffer) { + const sp<GraphicBuffer> &framebuffer, + Importer *importer) { ATRACE_CALL(); int ret = 0; std::vector<AutoEGLImageAndGLTexture> layer_textures; @@ -590,7 +586,7 @@ int GLWorkerCompositor::Composite(DrmHwcLayer *layers, continue; ret = CreateTextureFromHandle(egl_display_, layer->get_usable_handle(), - &layer_textures.back()); + importer, &layer_textures.back()); if (!ret) { ret = EGLFenceWait(egl_display_, layer->acquire_fence.Release()); @@ -43,7 +43,8 @@ class GLWorkerCompositor { int Init(); int Composite(DrmHwcLayer *layers, DrmCompositionRegion *regions, - size_t num_regions, const sp<GraphicBuffer> &framebuffer); + size_t num_regions, const sp<GraphicBuffer> &framebuffer, + Importer *importer); void Finish(); private: diff --git a/hwcomposer.cpp b/hwcomposer.cpp index 8d8e1d0..875056d 100644 --- a/hwcomposer.cpp +++ b/hwcomposer.cpp @@ -201,165 +201,17 @@ struct hwc_context_t { DrmHotplugHandler hotplug_handler; }; -static native_handle_t *dup_buffer_handle(buffer_handle_t handle) { - native_handle_t *new_handle = - native_handle_create(handle->numFds, handle->numInts); - if (new_handle == NULL) - return NULL; - - const int *old_data = handle->data; - int *new_data = new_handle->data; - for (int i = 0; i < handle->numFds; i++) { - *new_data = dup(*old_data); - old_data++; - new_data++; - } - memcpy(new_data, old_data, sizeof(int) * handle->numInts); - - return new_handle; -} - -static void free_buffer_handle(native_handle_t *handle) { - int ret = native_handle_close(handle); - if (ret) - ALOGE("Failed to close native handle %d", ret); - ret = native_handle_delete(handle); - if (ret) - ALOGE("Failed to delete native handle %d", ret); -} - -const hwc_drm_bo *DrmHwcBuffer::operator->() const { - if (importer_ == NULL) { - ALOGE("Access of non-existent BO"); - exit(1); - return NULL; - } - return &bo_; -} - -void DrmHwcBuffer::Clear() { - if (importer_ != NULL) { - importer_->ReleaseBuffer(&bo_); - importer_ = NULL; - } -} - -int DrmHwcBuffer::ImportBuffer(buffer_handle_t handle, Importer *importer) { - hwc_drm_bo tmp_bo; - - int ret = importer->ImportBuffer(handle, &tmp_bo); - if (ret) - return ret; - - if (importer_ != NULL) { - importer_->ReleaseBuffer(&bo_); - } - - importer_ = importer; - - bo_ = tmp_bo; - - return 0; -} - -int DrmHwcNativeHandle::CopyBufferHandle(buffer_handle_t handle, - const gralloc_module_t *gralloc) { - native_handle_t *handle_copy = dup_buffer_handle(handle); - if (handle_copy == NULL) { - ALOGE("Failed to duplicate handle"); - return -ENOMEM; - } - - int ret = gralloc->registerBuffer(gralloc, handle_copy); - if (ret) { - ALOGE("Failed to register buffer handle %d", ret); - free_buffer_handle(handle_copy); - return ret; - } - - Clear(); - - gralloc_ = gralloc; - handle_ = handle_copy; - - return 0; -} - -DrmHwcNativeHandle::~DrmHwcNativeHandle() { - Clear(); -} - -void DrmHwcNativeHandle::Clear() { - if (gralloc_ != NULL && handle_ != NULL) { - gralloc_->unregisterBuffer(gralloc_, handle_); - free_buffer_handle(handle_); - gralloc_ = NULL; - handle_ = NULL; - } -} - -int DrmHwcLayer::InitFromHwcLayer(hwc_layer_1_t *sf_layer, Importer *importer, - const gralloc_module_t *gralloc) { - sf_handle = sf_layer->handle; - alpha = sf_layer->planeAlpha; - - source_crop = DrmHwcRect<float>( - sf_layer->sourceCropf.left, sf_layer->sourceCropf.top, - sf_layer->sourceCropf.right, sf_layer->sourceCropf.bottom); - display_frame = DrmHwcRect<int>( - sf_layer->displayFrame.left, sf_layer->displayFrame.top, - sf_layer->displayFrame.right, sf_layer->displayFrame.bottom); - - transform = 0; - // 270* and 180* cannot be combined with flips. More specifically, they - // already contain both horizontal and vertical flips, so those fields are - // redundant in this case. 90* rotation can be combined with either horizontal - // flip or vertical flip, so treat it differently - if (sf_layer->transform == HWC_TRANSFORM_ROT_270) { - transform = DrmHwcTransform::kRotate270; - } else if (sf_layer->transform == HWC_TRANSFORM_ROT_180) { - transform = DrmHwcTransform::kRotate180; - } else { - if (sf_layer->transform & HWC_TRANSFORM_FLIP_H) - transform |= DrmHwcTransform::kFlipH; - if (sf_layer->transform & HWC_TRANSFORM_FLIP_V) - transform |= DrmHwcTransform::kFlipV; - if (sf_layer->transform & HWC_TRANSFORM_ROT_90) - transform |= DrmHwcTransform::kRotate90; - } - - switch (sf_layer->blending) { - case HWC_BLENDING_NONE: - blending = DrmHwcBlending::kNone; - break; - case HWC_BLENDING_PREMULT: - blending = DrmHwcBlending::kPreMult; - break; - case HWC_BLENDING_COVERAGE: - blending = DrmHwcBlending::kCoverage; - break; - default: - ALOGE("Invalid blending in hwc_layer_1_t %d", sf_layer->blending); - return -EINVAL; +class DrmVsyncCallback : public VsyncCallback { + public: + DrmVsyncCallback(hwc_procs_t const *procs) : procs_(procs) { } - int ret = buffer.ImportBuffer(sf_layer->handle, importer); - if (ret) - return ret; - - ret = handle.CopyBufferHandle(sf_layer->handle, gralloc); - if (ret) - return ret; - - ret = gralloc->perform(gralloc, GRALLOC_MODULE_PERFORM_GET_USAGE, - handle.get(), &gralloc_buffer_usage); - if (ret) { - ALOGE("Failed to get usage for buffer %p (%d)", handle.get(), ret); - return ret; + void Callback(int display, int64_t timestamp) { + procs_->vsync(procs_, display, timestamp); } - - return 0; -} + private: + hwc_procs_t const *procs_; +}; static void hwc_dump(struct hwc_composer_device_1 *dev, char *buff, int buff_len) { @@ -683,8 +535,10 @@ static void hwc_register_procs(struct hwc_composer_device_1 *dev, ctx->procs = procs; - for (std::pair<const int, hwc_drm_display> &display_entry : ctx->displays) - display_entry.second.vsync_worker.SetProcs(procs); + for (std::pair<const int, hwc_drm_display> &display_entry : ctx->displays) { + auto callback = std::make_shared<DrmVsyncCallback>(procs); + display_entry.second.vsync_worker.RegisterCallback(std::move(callback)); + } ctx->hotplug_handler.Init(&ctx->drm, procs); ctx->drm.event_listener()->RegisterHotplugHandler(&ctx->hotplug_handler); diff --git a/hwcutils.cpp b/hwcutils.cpp new file mode 100644 index 0000000..0091575 --- /dev/null +++ b/hwcutils.cpp @@ -0,0 +1,199 @@ +/* + * 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-utils" + +#include "drmhwcomposer.h" +#include "platform.h" + +#include <cutils/log.h> + +namespace android { + +const hwc_drm_bo *DrmHwcBuffer::operator->() const { + if (importer_ == NULL) { + ALOGE("Access of non-existent BO"); + exit(1); + return NULL; + } + return &bo_; +} + +void DrmHwcBuffer::Clear() { + if (importer_ != NULL) { + importer_->ReleaseBuffer(&bo_); + importer_ = NULL; + } +} + +int DrmHwcBuffer::ImportBuffer(buffer_handle_t handle, Importer *importer) { + hwc_drm_bo tmp_bo; + + int ret = importer->ImportBuffer(handle, &tmp_bo); + if (ret) + return ret; + + if (importer_ != NULL) { + importer_->ReleaseBuffer(&bo_); + } + + importer_ = importer; + + bo_ = tmp_bo; + + return 0; +} + +static native_handle_t *dup_buffer_handle(buffer_handle_t handle) { + native_handle_t *new_handle = + native_handle_create(handle->numFds, handle->numInts); + if (new_handle == NULL) + return NULL; + + const int *old_data = handle->data; + int *new_data = new_handle->data; + for (int i = 0; i < handle->numFds; i++) { + *new_data = dup(*old_data); + old_data++; + new_data++; + } + memcpy(new_data, old_data, sizeof(int) * handle->numInts); + + return new_handle; +} + +static void free_buffer_handle(native_handle_t *handle) { + int ret = native_handle_close(handle); + if (ret) + ALOGE("Failed to close native handle %d", ret); + ret = native_handle_delete(handle); + if (ret) + ALOGE("Failed to delete native handle %d", ret); +} + +int DrmHwcNativeHandle::CopyBufferHandle(buffer_handle_t handle, + const gralloc_module_t *gralloc) { + native_handle_t *handle_copy = dup_buffer_handle(handle); + if (handle_copy == NULL) { + ALOGE("Failed to duplicate handle"); + return -ENOMEM; + } + + int ret = gralloc->registerBuffer(gralloc, handle_copy); + if (ret) { + ALOGE("Failed to register buffer handle %d", ret); + free_buffer_handle(handle_copy); + return ret; + } + + Clear(); + + gralloc_ = gralloc; + handle_ = handle_copy; + + return 0; +} + +DrmHwcNativeHandle::~DrmHwcNativeHandle() { + Clear(); +} + +void DrmHwcNativeHandle::Clear() { + if (gralloc_ != NULL && handle_ != NULL) { + gralloc_->unregisterBuffer(gralloc_, handle_); + free_buffer_handle(handle_); + gralloc_ = NULL; + handle_ = NULL; + } +} + +int DrmHwcLayer::InitFromHwcLayer(hwc_layer_1_t *sf_layer, Importer *importer, + const gralloc_module_t *gralloc) { + alpha = sf_layer->planeAlpha; + + SetSourceCrop(sf_layer->sourceCropf); + SetDisplayFrame(sf_layer->displayFrame); + SetTransform(sf_layer->transform); + + switch (sf_layer->blending) { + case HWC_BLENDING_NONE: + blending = DrmHwcBlending::kNone; + break; + case HWC_BLENDING_PREMULT: + blending = DrmHwcBlending::kPreMult; + break; + case HWC_BLENDING_COVERAGE: + blending = DrmHwcBlending::kCoverage; + break; + default: + ALOGE("Invalid blending in hwc_layer_1_t %d", sf_layer->blending); + return -EINVAL; + } + + sf_handle = sf_layer->handle; + + return ImportBuffer(importer, gralloc); +} + +int DrmHwcLayer::ImportBuffer(Importer *importer, + const gralloc_module_t *gralloc) { + int ret = buffer.ImportBuffer(sf_handle, importer); + if (ret) + return ret; + + ret = handle.CopyBufferHandle(sf_handle, gralloc); + if (ret) + return ret; + + ret = gralloc->perform(gralloc, GRALLOC_MODULE_PERFORM_GET_USAGE, + handle.get(), &gralloc_buffer_usage); + if (ret) { + ALOGE("Failed to get usage for buffer %p (%d)", handle.get(), ret); + return ret; + } + return 0; +} + +void DrmHwcLayer::SetSourceCrop(hwc_frect_t const &crop) { + source_crop = DrmHwcRect<float>(crop.left, crop.top, crop.right, crop.bottom); +} + +void DrmHwcLayer::SetDisplayFrame(hwc_rect_t const &frame) { + display_frame = + DrmHwcRect<int>(frame.left, frame.top, frame.right, frame.bottom); +} + +void DrmHwcLayer::SetTransform(int32_t sf_transform) { + transform = 0; + // 270* and 180* cannot be combined with flips. More specifically, they + // already contain both horizontal and vertical flips, so those fields are + // redundant in this case. 90* rotation can be combined with either horizontal + // flip or vertical flip, so treat it differently + if (sf_transform == HWC_TRANSFORM_ROT_270) { + transform = DrmHwcTransform::kRotate270; + } else if (sf_transform == HWC_TRANSFORM_ROT_180) { + transform = DrmHwcTransform::kRotate180; + } else { + if (sf_transform & HWC_TRANSFORM_FLIP_H) + transform |= DrmHwcTransform::kFlipH; + if (sf_transform & HWC_TRANSFORM_FLIP_V) + transform |= DrmHwcTransform::kFlipV; + if (sf_transform & HWC_TRANSFORM_ROT_90) + transform |= DrmHwcTransform::kRotate90; + } +} +} @@ -38,6 +38,10 @@ class Importer { // Creates a platform-specific importer instance static Importer *CreateInstance(DrmResources *drm); + // Imports EGLImage for glcompositor, since NV handles this in non-standard + // way, and fishing out the details is specific to the gralloc used. + virtual EGLImageKHR ImportImage(EGLDisplay egl_display, buffer_handle_t handle) = 0; + // Imports the buffer referred to by handle into bo. // // Note: This can be called from a different thread than ReleaseBuffer. The diff --git a/platformdrmgeneric.cpp b/platformdrmgeneric.cpp index 90ba0e2..aa3d0fa 100644 --- a/platformdrmgeneric.cpp +++ b/platformdrmgeneric.cpp @@ -27,6 +27,7 @@ #include <cutils/log.h> #include <gralloc_drm_handle.h> #include <hardware/gralloc.h> +#include <EGL/eglext.h> namespace android { @@ -83,6 +84,22 @@ uint32_t DrmGenericImporter::ConvertHalFormatToDrm(uint32_t hal_format) { } } +EGLImageKHR DrmGenericImporter::ImportImage(EGLDisplay egl_display, buffer_handle_t handle) { + gralloc_drm_handle_t *gr_handle = gralloc_drm_handle(handle); + if (!gr_handle) + return NULL; + EGLint attr[] = { + EGL_WIDTH, gr_handle->width, + EGL_HEIGHT, gr_handle->height, + EGL_LINUX_DRM_FOURCC_EXT, (EGLint)ConvertHalFormatToDrm(gr_handle->format), + EGL_DMA_BUF_PLANE0_FD_EXT, gr_handle->prime_fd, + EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, + EGL_DMA_BUF_PLANE0_PITCH_EXT, gr_handle->stride, + EGL_NONE, + }; + return eglCreateImageKHR(egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attr); +} + int DrmGenericImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) { gralloc_drm_handle_t *gr_handle = gralloc_drm_handle(handle); if (!gr_handle) diff --git a/platformdrmgeneric.h b/platformdrmgeneric.h index 3400876..8376580 100644 --- a/platformdrmgeneric.h +++ b/platformdrmgeneric.h @@ -31,6 +31,7 @@ class DrmGenericImporter : public Importer { int Init(); + EGLImageKHR ImportImage(EGLDisplay egl_display, buffer_handle_t handle) override; int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) override; int ReleaseBuffer(hwc_drm_bo_t *bo) override; diff --git a/platformnv.cpp b/platformnv.cpp index e05d1bb..e7b6be3 100644 --- a/platformnv.cpp +++ b/platformnv.cpp @@ -29,6 +29,10 @@ #include <cutils/log.h> #include <hardware/gralloc.h> +#ifndef EGL_NATIVE_HANDLE_ANDROID_NVX +#define EGL_NATIVE_HANDLE_ANDROID_NVX 0x322A +#endif + namespace android { #ifdef USE_NVIDIA_IMPORTER @@ -69,6 +73,13 @@ int NvImporter::Init() { return 0; } + +EGLImageKHR NvImporter::ImportImage(EGLDisplay egl_display, buffer_handle_t handle) { + return eglCreateImageKHR( + egl_display, EGL_NO_CONTEXT, EGL_NATIVE_HANDLE_ANDROID_NVX, + (EGLClientBuffer)handle, NULL /* no attribs */); +} + int NvImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) { memset(bo, 0, sizeof(hwc_drm_bo_t)); NvBuffer_t *buf = GrallocGetNvBuffer(handle); diff --git a/platformnv.h b/platformnv.h index e379ea9..7e2784f 100644 --- a/platformnv.h +++ b/platformnv.h @@ -34,6 +34,7 @@ class NvImporter : public Importer { int Init(); + EGLImageKHR ImportImage(EGLDisplay egl_display, buffer_handle_t handle) override; int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) override; int ReleaseBuffer(hwc_drm_bo_t *bo) override; diff --git a/vsyncworker.cpp b/vsyncworker.cpp index ee140cb..2177521 100644 --- a/vsyncworker.cpp +++ b/vsyncworker.cpp @@ -34,7 +34,6 @@ namespace android { VSyncWorker::VSyncWorker() : Worker("vsync", HAL_PRIORITY_URGENT_DISPLAY), drm_(NULL), - procs_(NULL), display_(-1), last_timestamp_(-1) { } @@ -49,9 +48,9 @@ int VSyncWorker::Init(DrmResources *drm, int display) { return InitWorker(); } -void VSyncWorker::SetProcs(hwc_procs_t const *procs) { +void VSyncWorker::RegisterCallback(std::shared_ptr<VsyncCallback> callback) { Lock(); - procs_ = procs; + callback_ = callback; Unlock(); } @@ -126,7 +125,8 @@ void VSyncWorker::Routine() { bool enabled = enabled_; int display = display_; - hwc_procs_t const *procs = procs_; + std::shared_ptr<VsyncCallback> callback(callback_); + Unlock(); if (!enabled) @@ -159,16 +159,16 @@ void VSyncWorker::Routine() { } /* - * There's a race here where a change in procs_ will not take effect until + * There's a race here where a change in callback_ will not take effect until * the next subsequent requested vsync. This is unavoidable since we can't * call the vsync hook while holding the thread lock. * - * We could shorten the race window by caching procs_ right before calling - * the hook. However, in practice, procs_ is only updated once, so it's not + * We could shorten the race window by caching callback_ right before calling + * the hook. However, in practice, callback_ is only updated once, so it's not * worth the overhead. */ - if (procs && procs->vsync) - procs->vsync(procs, display, timestamp); + if (callback) + callback->Callback(display, timestamp); last_timestamp_ = timestamp; } } diff --git a/vsyncworker.h b/vsyncworker.h index 3e1f814..787152e 100644 --- a/vsyncworker.h +++ b/vsyncworker.h @@ -28,13 +28,20 @@ namespace android { +class VsyncCallback { + public: + virtual ~VsyncCallback() { + } + virtual void Callback(int display, int64_t timestamp) = 0; +}; + class VSyncWorker : public Worker { public: VSyncWorker(); ~VSyncWorker() override; int Init(DrmResources *drm, int display); - void SetProcs(hwc_procs_t const *procs); + void RegisterCallback(std::shared_ptr<VsyncCallback> callback); void VSyncControl(bool enabled); @@ -46,7 +53,11 @@ class VSyncWorker : public Worker { int SyntheticWaitVBlank(int64_t *timestamp); DrmResources *drm_; - hwc_procs_t const *procs_; + + // shared_ptr since we need to use this outside of the thread lock (to + // actually call the hook) and we don't want the memory freed until we're + // done + std::shared_ptr<VsyncCallback> callback_ = NULL; int display_; bool enabled_; |