From 0ddc329b2585584806951705319461aa05ef9d49 Mon Sep 17 00:00:00 2001 From: Matvii Zorin Date: Mon, 27 Jul 2020 18:29:15 +0300 Subject: drm_hwcomposer: Add include guard into drmhwctwo.h Include guard was missed for the file. Signed-off-by: Matvii Zorin --- include/drmhwctwo.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/drmhwctwo.h b/include/drmhwctwo.h index 1f226bc..62ee85a 100644 --- a/include/drmhwctwo.h +++ b/include/drmhwctwo.h @@ -14,6 +14,9 @@ * limitations under the License. */ +#ifndef ANDROID_DRM_HWC_TWO_H_ +#define ANDROID_DRM_HWC_TWO_H_ + #include "drmdisplaycompositor.h" #include "drmhwcomposer.h" #include "platform.h" @@ -370,3 +373,5 @@ class DrmHwcTwo : public hwc2_device_t { std::string mDumpString; }; } // namespace android + +#endif -- cgit v1.2.3 From e0e7c5cf7f300ce66c556b68c7a03b7d5d66b420 Mon Sep 17 00:00:00 2001 From: Matvii Zorin Date: Mon, 27 Jul 2020 18:35:39 +0300 Subject: drm_hwcomposer: Move DrmHwcTwo internal classes outside private section Making backend-validation for HwcDisplay is required access to the internal class outside DrmHwcTwo. There is no need to keep other internal classes in the private section in this case. Signed-off-by: Matvii Zorin --- include/drmhwctwo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/drmhwctwo.h b/include/drmhwctwo.h index 62ee85a..5f9f6c5 100644 --- a/include/drmhwctwo.h +++ b/include/drmhwctwo.h @@ -40,7 +40,6 @@ class DrmHwcTwo : public hwc2_device_t { HWC2::Error Init(); - private: class HwcLayer { public: HWC2::Composition sf_type() const { @@ -299,6 +298,7 @@ class DrmHwcTwo : public hwc2_device_t { DrmDevice *drm_; }; + private: static DrmHwcTwo *toDrmHwcTwo(hwc2_device_t *dev) { return static_cast(dev); } -- cgit v1.2.3 From 373de710a96450cb1bfcb678fcab0bee1078941d Mon Sep 17 00:00:00 2001 From: Matvii Zorin Date: Tue, 11 Aug 2020 14:05:12 +0300 Subject: drm_hwcomposer: Expand access to HwcDisplay class members Move the private methods and Stats structure into the public section to have access outside the class. Create get functions for private members. Access changing is needed to move display validation to the Backend class. Signed-off-by: Matvii Zorin --- include/drmhwctwo.h | 91 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 24 deletions(-) diff --git a/include/drmhwctwo.h b/include/drmhwctwo.h index 5f9f6c5..df75c41 100644 --- a/include/drmhwctwo.h +++ b/include/drmhwctwo.h @@ -167,6 +167,12 @@ class DrmHwcTwo : public hwc2_device_t { hwc2_function_pointer_t func); void RegisterRefreshCallback(hwc2_callback_data_t data, hwc2_function_pointer_t func); + HWC2::Error CreateComposition(bool test); + bool HardwareSupportsLayerType(HWC2::Composition comp_type); + uint32_t CalcPixOps(std::map &z_map, + size_t first_z, size_t size); + void MarkValidated(std::map &z_map, + size_t client_first_z, size_t client_size); void ClearDisplay(); @@ -231,14 +237,67 @@ class DrmHwcTwo : public hwc2_device_t { return &it->second; } + /* Statistics */ + struct Stats { + Stats minus(Stats b) { + return {total_frames_ - b.total_frames_, + total_pixops_ - b.total_pixops_, + gpu_pixops_ - b.gpu_pixops_, + failed_kms_validate_ - b.failed_kms_validate_, + failed_kms_present_ - b.failed_kms_present_, + frames_flattened_ - b.frames_flattened_}; + } + + uint32_t total_frames_ = 0; + uint64_t total_pixops_ = 0; + uint64_t gpu_pixops_ = 0; + uint32_t failed_kms_validate_ = 0; + uint32_t failed_kms_present_ = 0; + uint32_t frames_flattened_ = 0; + }; + + const std::vector &primary_planes() const { + return primary_planes_; + } + + const std::vector &overlay_planes() const { + return overlay_planes_; + } + + std::map &layers() { + return layers_; + } + + const DrmDisplayCompositor &compositor() const { + return compositor_; + } + + const DrmDevice *drm() const { + return drm_; + } + + const DrmConnector *connector() const { + return connector_; + } + + const std::shared_ptr &importer() const { + return importer_; + } + + ResourceManager *resource_manager() const { + return resource_manager_; + } + + android_color_transform_t &color_transform_hint() { + return color_transform_hint_; + } + + Stats &total_stats() { + return total_stats_; + } + private: - HWC2::Error CreateComposition(bool test); void AddFenceToPresentFence(int fd); - bool HardwareSupportsLayerType(HWC2::Composition comp_type); - uint32_t CalcPixOps(std::map &z_map, - size_t first_z, size_t size); - void MarkValidated(std::map &z_map, - size_t client_first_z, size_t client_size); constexpr static size_t MATRIX_SIZE = 16; @@ -265,24 +324,8 @@ class DrmHwcTwo : public hwc2_device_t { android_color_transform_t color_transform_hint_; uint32_t frame_no_ = 0; - /* Statistics */ - struct Stats { - Stats minus(Stats b) { - return {total_frames_ - b.total_frames_, - total_pixops_ - b.total_pixops_, - gpu_pixops_ - b.gpu_pixops_, - failed_kms_validate_ - b.failed_kms_validate_, - failed_kms_present_ - b.failed_kms_present_, - frames_flattened_ - b.frames_flattened_}; - } - - uint32_t total_frames_ = 0; - uint64_t total_pixops_ = 0; - uint64_t gpu_pixops_ = 0; - uint32_t failed_kms_validate_ = 0; - uint32_t failed_kms_present_ = 0; - uint32_t frames_flattened_ = 0; - } total_stats_, prev_stats_; + Stats total_stats_; + Stats prev_stats_; std::string DumpDelta(DrmHwcTwo::HwcDisplay::Stats delta); }; -- cgit v1.2.3 From ef3c797daff14f3df798fe78f2843c41f549c6c5 Mon Sep 17 00:00:00 2001 From: Matvii Zorin Date: Tue, 11 Aug 2020 15:15:44 +0300 Subject: drm_hwcomposer: Add backend-dependent validation for HwcDisplay class Different DRM/KMS backends have a variable set of limitations, which is not always exposed via DRM ioctls. This implementation of backend-dependent validation provides a register of platform-specific inherited backend class to the map by BackendManager class. ValidateDisplay function is moved to generic backend implementantion and separated into 2 additional methods. The map key is a string that contains the corresponding DRM driver name. During DrmHwcTwo class initialization the vendor.hwc.backend_override system property and driver name will be checked and a backend will be set for the appropriate display. If the map does not have any backend for the named driver, the generic backend will be used. Signed-off-by: Matvii Zorin --- Android.bp | 3 + backend/backend.cpp | 136 +++++++++++++++++++++++++++++++++++++++++++++ backend/backendmanager.cpp | 80 ++++++++++++++++++++++++++ drm/drmdevice.cpp | 12 ++++ drmhwctwo.cpp | 93 +++---------------------------- include/backend.h | 38 +++++++++++++ include/backendmanager.h | 58 +++++++++++++++++++ include/drmdevice.h | 2 + include/drmhwctwo.h | 11 ++++ 9 files changed, 348 insertions(+), 85 deletions(-) create mode 100644 backend/backend.cpp create mode 100644 backend/backendmanager.cpp create mode 100644 include/backend.h create mode 100644 include/backendmanager.h diff --git a/Android.bp b/Android.bp index 8bcd1aa..b4bf8e0 100644 --- a/Android.bp +++ b/Android.bp @@ -94,6 +94,9 @@ cc_library_static { "utils/autolock.cpp", "utils/hwcutils.cpp", + + "backend/backendmanager.cpp", + "backend/backend.cpp", ], } diff --git a/backend/backend.cpp b/backend/backend.cpp new file mode 100644 index 0000000..08ee5a7 --- /dev/null +++ b/backend/backend.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2020 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 "backend.h" +#include "backendmanager.h" +#include "drmhwctwo.h" + +namespace android { + +HWC2::Error Backend::ValidateDisplay(DrmHwcTwo::HwcDisplay *display, + uint32_t *num_types, + uint32_t *num_requests) { + *num_types = 0; + *num_requests = 0; + size_t avail_planes = display->primary_planes().size() + + display->overlay_planes().size(); + + /* + * If more layers then planes, save one plane + * for client composited layers + */ + if (avail_planes < display->layers().size()) + avail_planes--; + + std::map z_map, z_map_tmp; + uint32_t z_index = 0; + // First create a map of layers and z_order values + for (std::pair &l : + display->layers()) + z_map_tmp.emplace(std::make_pair(l.second.z_order(), &l.second)); + // normalise the map so that the lowest z_order layer has key 0 + for (std::pair &l : z_map_tmp) + z_map.emplace(std::make_pair(z_index++, l.second)); + + uint32_t total_pixops = display->CalcPixOps(z_map, 0, z_map.size()); + uint32_t gpu_pixops = 0; + + int client_start = -1, client_size = 0; + + if (display->compositor().ShouldFlattenOnClient()) { + client_start = 0; + client_size = z_map.size(); + display->MarkValidated(z_map, client_start, client_size); + } else { + std::tie(client_start, client_size) = GetClientLayers(display, z_map); + + int extra_client = (z_map.size() - client_size) - avail_planes; + if (extra_client > 0) { + int start = 0, steps; + if (client_size != 0) { + int prepend = std::min(client_start, extra_client); + int append = std::min(int(z_map.size() - (client_start + client_size)), + extra_client); + start = client_start - prepend; + client_size += extra_client; + steps = 1 + std::min(std::min(append, prepend), + int(z_map.size()) - (start + client_size)); + } else { + client_size = extra_client; + steps = 1 + z_map.size() - extra_client; + } + + gpu_pixops = INT_MAX; + for (int i = 0; i < steps; i++) { + uint32_t po = display->CalcPixOps(z_map, start + i, client_size); + if (po < gpu_pixops) { + gpu_pixops = po; + client_start = start + i; + } + } + } + + display->MarkValidated(z_map, client_start, client_size); + + bool testing_needed = !(client_start == 0 && client_size == z_map.size()); + + if (testing_needed && + display->CreateComposition(true) != HWC2::Error::None) { + ++display->total_stats().failed_kms_validate_; + gpu_pixops = total_pixops; + client_size = z_map.size(); + display->MarkValidated(z_map, 0, client_size); + } + } + + *num_types = client_size; + + display->total_stats().frames_flattened_ = display->compositor() + .GetFlattenedFramesCount(); + display->total_stats().gpu_pixops_ += gpu_pixops; + display->total_stats().total_pixops_ += total_pixops; + + return *num_types ? HWC2::Error::HasChanges : HWC2::Error::None; +} + +std::tuple Backend::GetClientLayers( + DrmHwcTwo::HwcDisplay *display, + const std::map &z_map) { + int client_start = -1, client_size = 0; + + for (auto & [ z_order, layer ] : z_map) { + if (IsClientLayer(display, layer)) { + if (client_start < 0) + client_start = z_order; + client_size = (z_order - client_start) + 1; + } + } + + return std::make_tuple(client_start, client_size); +} + +bool Backend::IsClientLayer(DrmHwcTwo::HwcDisplay *display, + DrmHwcTwo::HwcLayer *layer) { + return !display->HardwareSupportsLayerType(layer->sf_type()) || + !display->importer()->CanImportBuffer(layer->buffer()) || + display->color_transform_hint() != HAL_COLOR_TRANSFORM_IDENTITY || + (layer->RequireScalingOrPhasing() && + display->resource_manager()->ForcedScalingWithGpu()); +} + +REGISTER_BACKEND("generic", Backend); + +} // namespace android diff --git a/backend/backendmanager.cpp b/backend/backendmanager.cpp new file mode 100644 index 0000000..80ec827 --- /dev/null +++ b/backend/backendmanager.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "hwc-backend" + +#include "backendmanager.h" +#include "backend.h" +#include "drmhwctwo.h" + +#include +#include + +namespace android { + +const std::vector BackendManager::client_devices_ = { + "kirin", +}; + +BackendManager &BackendManager::GetInstance() { + static BackendManager backend_manager; + + return backend_manager; +} + +int BackendManager::RegisterBackend(const std::string &name, + backend_constructor_t backend_constructor) { + available_backends_[name] = std::move(backend_constructor); + return 0; +} + +int BackendManager::SetBackendForDisplay(DrmHwcTwo::HwcDisplay *display) { + std::string driver_name(display->drm()->GetName()); + char backend_override[PROPERTY_VALUE_MAX]; + property_get("vendor.hwc.backend_override", backend_override, + driver_name.c_str()); + std::string backend_name(std::move(backend_override)); + + display->set_backend(GetBackendByName(backend_name)); + if (!display->backend()) { + ALOGE("Failed to set backend '%s' for '%s' and driver '%s'", + backend_name.c_str(), display->connector()->name().c_str(), + driver_name.c_str()); + return -EINVAL; + } + + ALOGI("Backend '%s' for '%s' and driver '%s' was successfully set", + backend_name.c_str(), display->connector()->name().c_str(), + driver_name.c_str()); + + return 0; +} + +std::unique_ptr BackendManager::GetBackendByName(std::string &name) { + if (!available_backends_.size()) { + ALOGE("No backends are specified"); + return nullptr; + } + + auto it = available_backends_.find(name); + if (it == available_backends_.end()) { + auto it = std::find(client_devices_.begin(), client_devices_.end(), name); + name = it == client_devices_.end() ? "generic" : "client"; + } + + return available_backends_[name](); +} +} // namespace android diff --git a/drm/drmdevice.cpp b/drm/drmdevice.cpp index d7fd2f2..91fe158 100644 --- a/drm/drmdevice.cpp +++ b/drm/drmdevice.cpp @@ -570,4 +570,16 @@ int DrmDevice::GetConnectorProperty(const DrmConnector &connector, return GetProperty(connector.id(), DRM_MODE_OBJECT_CONNECTOR, prop_name, property); } + +const std::string DrmDevice::GetName() const { + auto ver = drmGetVersion(fd_.get()); + if (!ver) { + ALOGW("Failed to get drm version for fd=%d", fd_.get()); + return "generic"; + } + + std::string name(ver->name); + drmFreeVersion(ver); + return name; +} } // namespace android diff --git a/drmhwctwo.cpp b/drmhwctwo.cpp index a847c35..ffc45ef 100644 --- a/drmhwctwo.cpp +++ b/drmhwctwo.cpp @@ -18,6 +18,7 @@ #define LOG_TAG "hwc-drm-two" #include "drmhwctwo.h" +#include "backendmanager.h" #include "drmdisplaycomposition.h" #include "drmhwcomposer.h" #include "platform.h" @@ -299,6 +300,12 @@ HWC2::Error DrmHwcTwo::HwcDisplay::Init(std::vector *planes) { return HWC2::Error::BadDisplay; } + ret = BackendManager::GetInstance().SetBackendForDisplay(this); + if (ret) { + ALOGE("Failed to set backend for d=%d %d\n", display, ret); + return HWC2::Error::BadDisplay; + } + return ChosePreferredConfig(); } @@ -900,92 +907,8 @@ void DrmHwcTwo::HwcDisplay::MarkValidated( HWC2::Error DrmHwcTwo::HwcDisplay::ValidateDisplay(uint32_t *num_types, uint32_t *num_requests) { supported(__func__); - *num_types = 0; - *num_requests = 0; - size_t avail_planes = primary_planes_.size() + overlay_planes_.size(); - - /* - * If more layers then planes, save one plane - * for client composited layers - */ - if (avail_planes < layers_.size()) - avail_planes--; - - std::map z_map, z_map_tmp; - uint32_t z_index = 0; - // First create a map of layers and z_order values - for (std::pair &l : layers_) - z_map_tmp.emplace(std::make_pair(l.second.z_order(), &l.second)); - // normalise the map so that the lowest z_order layer has key 0 - for (std::pair &l : z_map_tmp) - z_map.emplace(std::make_pair(z_index++, l.second)); - - uint32_t total_pixops = CalcPixOps(z_map, 0, z_map.size()), gpu_pixops = 0; - - int client_start = -1, client_size = 0; - - if (compositor_.ShouldFlattenOnClient()) { - client_start = 0; - client_size = z_map.size(); - MarkValidated(z_map, client_start, client_size); - } else { - for (std::pair &l : z_map) { - if (!HardwareSupportsLayerType(l.second->sf_type()) || - !importer_->CanImportBuffer(l.second->buffer()) || - color_transform_hint_ != HAL_COLOR_TRANSFORM_IDENTITY || - (l.second->RequireScalingOrPhasing() && - resource_manager_->ForcedScalingWithGpu())) { - if (client_start < 0) - client_start = l.first; - client_size = (l.first - client_start) + 1; - } - } - - int extra_client = (z_map.size() - client_size) - avail_planes; - if (extra_client > 0) { - int start = 0, steps; - if (client_size != 0) { - int prepend = std::min(client_start, extra_client); - int append = std::min(int(z_map.size() - (client_start + client_size)), - extra_client); - start = client_start - prepend; - client_size += extra_client; - steps = 1 + std::min(std::min(append, prepend), - int(z_map.size()) - (start + client_size)); - } else { - client_size = extra_client; - steps = 1 + z_map.size() - extra_client; - } - - gpu_pixops = INT_MAX; - for (int i = 0; i < steps; i++) { - uint32_t po = CalcPixOps(z_map, start + i, client_size); - if (po < gpu_pixops) { - gpu_pixops = po; - client_start = start + i; - } - } - } - - MarkValidated(z_map, client_start, client_size); - - bool testing_needed = !(client_start == 0 && client_size == z_map.size()); - - if (testing_needed && CreateComposition(true) != HWC2::Error::None) { - ++total_stats_.failed_kms_validate_; - gpu_pixops = total_pixops; - client_size = z_map.size(); - MarkValidated(z_map, 0, client_size); - } - } - - *num_types = client_size; - - total_stats_.frames_flattened_ = compositor_.GetFlattenedFramesCount(); - total_stats_.gpu_pixops_ += gpu_pixops; - total_stats_.total_pixops_ += total_pixops; - return *num_types ? HWC2::Error::HasChanges : HWC2::Error::None; + return backend_->ValidateDisplay(this, num_types, num_requests); } #if PLATFORM_SDK_VERSION > 28 diff --git a/include/backend.h b/include/backend.h new file mode 100644 index 0000000..cd9d8cd --- /dev/null +++ b/include/backend.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_BACKEND_H +#define ANDROID_BACKEND_H + +#include "drmhwctwo.h" + +namespace android { + +class Backend { + public: + virtual ~Backend() = default; + virtual HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, + uint32_t *num_types, + uint32_t *num_requests); + virtual std::tuple GetClientLayers( + DrmHwcTwo::HwcDisplay *display, + const std::map &z_map); + virtual bool IsClientLayer(DrmHwcTwo::HwcDisplay *display, + DrmHwcTwo::HwcLayer *layer); +}; +} // namespace android + +#endif diff --git a/include/backendmanager.h b/include/backendmanager.h new file mode 100644 index 0000000..d141652 --- /dev/null +++ b/include/backendmanager.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_BACKEND_MANAGER_H +#define ANDROID_BACKEND_MANAGER_H + +#include "backend.h" +#include "drmhwctwo.h" + +#include +#include +#include +#include + +#define REGISTER_BACKEND(name_str_, backend_) \ + static int \ + backend = BackendManager::GetInstance() \ + .RegisterBackend(name_str_, \ + []() -> std::unique_ptr { \ + return std::make_unique(); \ + }); + +namespace android { + +class BackendManager { + public: + using backend_constructor_t = std::function()>; + static BackendManager &GetInstance(); + int RegisterBackend(const std::string &name, + backend_constructor_t backend_constructor); + int SetBackendForDisplay(DrmHwcTwo::HwcDisplay *display); + std::unique_ptr GetBackendByName(std::string &name); + HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, + uint32_t *num_types, uint32_t *num_requests); + + private: + BackendManager() = default; + + static const std::vector client_devices_; + + std::map available_backends_; +}; +} // namespace android + +#endif diff --git a/include/drmdevice.h b/include/drmdevice.h index 91dd38b..1f08f20 100644 --- a/include/drmdevice.h +++ b/include/drmdevice.h @@ -70,6 +70,8 @@ class DrmDevice { int GetConnectorProperty(const DrmConnector &connector, const char *prop_name, DrmProperty *property); + const std::string GetName() const; + const std::vector> &crtcs() const; uint32_t next_mode_id(); diff --git a/include/drmhwctwo.h b/include/drmhwctwo.h index df75c41..8b1be4b 100644 --- a/include/drmhwctwo.h +++ b/include/drmhwctwo.h @@ -31,6 +31,8 @@ namespace android { +class Backend; + class DrmHwcTwo : public hwc2_device_t { public: static int HookDevOpen(const struct hw_module_t *module, const char *name, @@ -256,6 +258,13 @@ class DrmHwcTwo : public hwc2_device_t { uint32_t frames_flattened_ = 0; }; + const Backend *backend() const { + return backend_.get(); + } + void set_backend(std::unique_ptr backend) { + backend_ = std::move(backend); + } + const std::vector &primary_planes() const { return primary_planes_; } @@ -310,6 +319,8 @@ class DrmHwcTwo : public hwc2_device_t { std::vector primary_planes_; std::vector overlay_planes_; + std::unique_ptr backend_; + VSyncWorker vsync_worker_; DrmConnector *connector_ = NULL; DrmCrtc *crtc_ = NULL; -- cgit v1.2.3 From 7f7efd80b5c4d1f970be0991a9b6dcf5f3230636 Mon Sep 17 00:00:00 2001 From: Matvii Zorin Date: Tue, 11 Aug 2020 15:29:21 +0300 Subject: drm_hwcomposer: Add composition skipping backend This display backend may be chosen by setting the hwc.backend_override system property to the "client" value. Suggested-by: Andrii Chepurnyi Signed-off-by: Matvii Zorin --- Android.bp | 1 + backend/backendclient.cpp | 35 +++++++++++++++++++++++++++++++++++ include/backendclient.h | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 backend/backendclient.cpp create mode 100644 include/backendclient.h diff --git a/Android.bp b/Android.bp index b4bf8e0..e6b767e 100644 --- a/Android.bp +++ b/Android.bp @@ -97,6 +97,7 @@ cc_library_static { "backend/backendmanager.cpp", "backend/backend.cpp", + "backend/backendclient.cpp", ], } diff --git a/backend/backendclient.cpp b/backend/backendclient.cpp new file mode 100644 index 0000000..3f3cd44 --- /dev/null +++ b/backend/backendclient.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2020 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 "backendclient.h" +#include "backendmanager.h" +#include "drmhwctwo.h" + +namespace android { + +HWC2::Error BackendClient::ValidateDisplay(DrmHwcTwo::HwcDisplay *display, + uint32_t *num_types, + uint32_t * /*num_requests*/) { + for (auto & [ layer_handle, layer ] : display->layers()) { + layer.set_validated_type(HWC2::Composition::Client); + ++*num_types; + } + return HWC2::Error::HasChanges; +} + +REGISTER_BACKEND("client", BackendClient); + +} // namespace android diff --git a/include/backendclient.h b/include/backendclient.h new file mode 100644 index 0000000..361160f --- /dev/null +++ b/include/backendclient.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_BACKEND_CLIENT_H +#define ANDROID_BACKEND_CLIENT_H + +#include "backend.h" +#include "drmhwctwo.h" + +namespace android { + +class BackendClient : public Backend { + public: + HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, + uint32_t *num_types, + uint32_t *num_requests) override; +}; +} // namespace android + +#endif -- cgit v1.2.3 From 51a0e0d30cfbcbf869c44650b33da08585bb6fab Mon Sep 17 00:00:00 2001 From: Matvii Zorin Date: Tue, 11 Aug 2020 15:33:03 +0300 Subject: drm_hwcomposer: Add rcar-du display backend ABGR8888 pixel format and layer scaling are unsupported for rcar-du platform. Handle and filter out the layers by overriding the IsClientLayer method for additional checks. That will force layers that require scaling or have the unsupported pixel format to be merged by GPU, and allow other layers to be merged by DRM. Signed-off-by: Matvii Zorin --- Android.bp | 1 + backend/backendrcardu.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ include/backendrcardu.h | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 backend/backendrcardu.cpp create mode 100644 include/backendrcardu.h diff --git a/Android.bp b/Android.bp index e6b767e..7046837 100644 --- a/Android.bp +++ b/Android.bp @@ -98,6 +98,7 @@ cc_library_static { "backend/backendmanager.cpp", "backend/backend.cpp", "backend/backendclient.cpp", + "backend/backendrcardu.cpp", ], } diff --git a/backend/backendrcardu.cpp b/backend/backendrcardu.cpp new file mode 100644 index 0000000..d6fe7bf --- /dev/null +++ b/backend/backendrcardu.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2020 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 "backendrcardu.h" +#include "backendmanager.h" +#include "drm_fourcc.h" + +namespace android { + +bool BackendRCarDu::IsClientLayer(DrmHwcTwo::HwcDisplay *display, + DrmHwcTwo::HwcLayer *layer) { + hwc_drm_bo_t bo; + + int ret = display->importer()->ConvertBoInfo(layer->buffer(), &bo); + if (ret) + return true; + + if (bo.format == DRM_FORMAT_ABGR8888) + return true; + + if (layer->RequireScalingOrPhasing()) + return true; + + return Backend::IsClientLayer(display, layer); +} + +REGISTER_BACKEND("rcar-du", BackendRCarDu); + +} // namespace android \ No newline at end of file diff --git a/include/backendrcardu.h b/include/backendrcardu.h new file mode 100644 index 0000000..29ccea9 --- /dev/null +++ b/include/backendrcardu.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HWC_DISPLAY_BACKEND_RCAR_DU_H +#define HWC_DISPLAY_BACKEND_RCAR_DU_H + +#include "backend.h" +#include "drmhwctwo.h" + +namespace android { + +class BackendRCarDu : public Backend { + public: + bool IsClientLayer(DrmHwcTwo::HwcDisplay *display, + DrmHwcTwo::HwcLayer *layer) override; +}; +} // namespace android + +#endif -- cgit v1.2.3 From cfc2b2e60267fb4140e99c0049598752c7d8749a Mon Sep 17 00:00:00 2001 From: Roman Stratiienko Date: Tue, 1 Sep 2020 13:39:17 +0300 Subject: drm_hwcomposer: fix incorrect layer_count usage According to [1] DRM YCrCb planes is not the same as gralloc layers. DRMHWC2 has no information about number of layers used in the buffer. Also supplying value other than 1 will allways fail validation on passthrough MapperHal@2.1 and probably other passthrough implementations [2]. [1] - https://cs.android.com/android/platform/superproject/+/master:hardware/libhardware/include/hardware/gralloc1.h;l=467;drc=1155c41d016a118801fe97b55af9918e531f7f84 [2] - https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc0Hal.h;l=40;drc=e308ceb1e9940d1d90a11177782a7cfe8630bb95 Signed-off-by: Roman Stratiienko Change-Id: Idbfea8eaa74a557b98ecdff728e6c67aeea9cea6 --- utils/hwcutils.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/utils/hwcutils.cpp b/utils/hwcutils.cpp index 87e3c42..324d855 100644 --- a/utils/hwcutils.cpp +++ b/utils/hwcutils.cpp @@ -114,13 +114,9 @@ int DrmHwcLayer::ImportBuffer(Importer *importer) { const hwc_drm_bo *bo = buffer.operator->(); - unsigned int layer_count; - for (layer_count = 0; layer_count < HWC_DRM_BO_MAX_PLANES; ++layer_count) - if (bo->gem_handles[layer_count] == 0) - break; - - ret = handle.CopyBufferHandle(sf_handle, bo->width, bo->height, layer_count, - bo->hal_format, bo->usage, bo->pixel_stride); + ret = handle.CopyBufferHandle(sf_handle, bo->width, bo->height, + 1 /*layer_count*/, bo->hal_format, bo->usage, + bo->pixel_stride); if (ret) return ret; -- cgit v1.2.3 From fbf5c0ca45b3c4dd1d9621eb5198c3d43f1afbf6 Mon Sep 17 00:00:00 2001 From: Roman Stratiienko Date: Mon, 24 Aug 2020 11:27:48 +0300 Subject: drm_hwcomposer: libdrm gralloc_handle: modifiers and YUV support 1. Import DRM modifier field from libdrm's gralloc_habdle. 2. Recently lock_ycrcb() was added to gbm_gralloc() [1], mesa3d uses this function to obtain CrCb plane data (offsets, strides). Use the same alhorythm in drm_hwcomposer. This allows GPU offloading during video playback. (Tested using Gallery app and SkyTube). [1] - https://github.com/robherring/gbm_gralloc/pull/15 [2] - https://gitlab.freedesktop.org/mesa/mesa/-/blob/68957a82562d13b3f0d21a04ce633ffd236e6036/src/egl/drivers/dri2/platform_android.c#L202 Signed-off-by: Roman Stratiienko Change-Id: I8ec177ac782f27174443cebcb6e773070c1505cc --- platform/platformdrmgeneric.cpp | 153 ++++++++++++++++++++++++++++++++++++++-- platform/platformdrmgeneric.h | 1 + 2 files changed, 148 insertions(+), 6 deletions(-) diff --git a/platform/platformdrmgeneric.cpp b/platform/platformdrmgeneric.cpp index bc28dd5..b9dafb3 100644 --- a/platform/platformdrmgeneric.cpp +++ b/platform/platformdrmgeneric.cpp @@ -73,6 +73,130 @@ int DrmGenericImporter::Init() { return 0; } +enum chroma_order { + YCbCr, + YCrCb, +}; + +struct droid_yuv_format { + /* Lookup keys */ + int native; /* HAL_PIXEL_FORMAT_ */ + enum chroma_order chroma_order; /* chroma order is {Cb, Cr} or {Cr, Cb} */ + int chroma_step; /* Distance in bytes between subsequent chroma pixels. */ + + /* Result */ + int fourcc; /* DRM_FORMAT_ */ +}; + +/* The following table is used to look up a DRI image FourCC based + * on native format and information contained in android_ycbcr struct. */ +static const struct droid_yuv_format droid_yuv_formats[] = { + /* Native format, YCrCb, Chroma step, DRI image FourCC */ + {HAL_PIXEL_FORMAT_YCbCr_420_888, YCbCr, 2, DRM_FORMAT_NV12}, + {HAL_PIXEL_FORMAT_YCbCr_420_888, YCbCr, 1, DRM_FORMAT_YUV420}, + {HAL_PIXEL_FORMAT_YCbCr_420_888, YCrCb, 1, DRM_FORMAT_YVU420}, + {HAL_PIXEL_FORMAT_YV12, YCrCb, 1, DRM_FORMAT_YVU420}, + /* HACK: See droid_create_image_from_prime_fds() and + * https://issuetracker.google.com/32077885. */ + {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCbCr, 2, DRM_FORMAT_NV12}, + {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCbCr, 1, DRM_FORMAT_YUV420}, + {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCrCb, 1, DRM_FORMAT_YVU420}, + {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCrCb, 1, DRM_FORMAT_AYUV}, + {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCrCb, 1, DRM_FORMAT_XYUV8888}, +}; + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +static int get_fourcc_yuv(int native, enum chroma_order chroma_order, + int chroma_step) { + for (int i = 0; i < ARRAY_SIZE(droid_yuv_formats); ++i) + if (droid_yuv_formats[i].native == native && + droid_yuv_formats[i].chroma_order == chroma_order && + droid_yuv_formats[i].chroma_step == chroma_step) + return droid_yuv_formats[i].fourcc; + + return -1; +} + +static bool is_yuv(int native) { + for (int i = 0; i < ARRAY_SIZE(droid_yuv_formats); ++i) + if (droid_yuv_formats[i].native == native) + return true; + + return false; +} + +bool DrmGenericImporter::GetYuvPlaneInfo(int num_fds, buffer_handle_t handle, + hwc_drm_bo_t *bo) { + struct android_ycbcr ycbcr; + enum chroma_order chroma_order; + int ret; + + if (!gralloc_->lock_ycbcr) { + static std::once_flag once; + std::call_once(once, + []() { ALOGW("Gralloc does not support lock_ycbcr()"); }); + return false; + } + + memset(&ycbcr, 0, sizeof(ycbcr)); + ret = gralloc_->lock_ycbcr(gralloc_, handle, 0, 0, 0, 0, 0, &ycbcr); + if (ret) { + ALOGW("gralloc->lock_ycbcr failed: %d", ret); + return false; + } + gralloc_->unlock(gralloc_, handle); + + /* When lock_ycbcr's usage argument contains no SW_READ/WRITE flags + * it will return the .y/.cb/.cr pointers based on a NULL pointer, + * so they can be interpreted as offsets. */ + bo->offsets[0] = (size_t)ycbcr.y; + /* We assume here that all the planes are located in one DMA-buf. */ + if ((size_t)ycbcr.cr < (size_t)ycbcr.cb) { + chroma_order = YCrCb; + bo->offsets[1] = (size_t)ycbcr.cr; + bo->offsets[2] = (size_t)ycbcr.cb; + } else { + chroma_order = YCbCr; + bo->offsets[1] = (size_t)ycbcr.cb; + bo->offsets[2] = (size_t)ycbcr.cr; + } + + /* .ystride is the line length (in bytes) of the Y plane, + * .cstride is the line length (in bytes) of any of the remaining + * Cb/Cr/CbCr planes, assumed to be the same for Cb and Cr for fully + * planar formats. */ + bo->pitches[0] = ycbcr.ystride; + bo->pitches[1] = bo->pitches[2] = ycbcr.cstride; + + /* .chroma_step is the byte distance between the same chroma channel + * values of subsequent pixels, assumed to be the same for Cb and Cr. */ + bo->format = get_fourcc_yuv(bo->hal_format, chroma_order, ycbcr.chroma_step); + if (bo->format == -1) { + ALOGW( + "unsupported YUV format, native = %x, chroma_order = %s, chroma_step = " + "%d", + bo->hal_format, chroma_order == YCbCr ? "YCbCr" : "YCrCb", + (int)ycbcr.chroma_step); + return false; + } + + /* + * Since this is EGL_NATIVE_BUFFER_ANDROID don't assume that + * the single-fd case cannot happen. So handle eithe single + * fd or fd-per-plane case: + */ + if (num_fds == 1) { + bo->prime_fds[2] = bo->prime_fds[1] = bo->prime_fds[0]; + } else { + int expected_planes = (ycbcr.chroma_step == 2) ? 2 : 3; + if (num_fds != expected_planes) + return false; + } + + return true; +} + uint32_t DrmGenericImporter::ConvertHalFormatToDrm(uint32_t hal_format) { switch (hal_format) { case HAL_PIXEL_FORMAT_RGB_888: @@ -120,15 +244,32 @@ int DrmGenericImporter::ConvertBoInfo(buffer_handle_t handle, bo->width = gr_handle->width; bo->height = gr_handle->height; bo->hal_format = gr_handle->format; - bo->format = ConvertHalFormatToDrm(gr_handle->format); - if (bo->format == DRM_FORMAT_INVALID) - return -EINVAL; + +#if GRALLOC_HANDLE_VERSION < 4 +#warning libdrm >= v2.4.97 is required to support modifiers +#endif +#if GRALLOC_HANDLE_VERSION == 4 + bo->modifiers[0] = gr_handle->modifier; + bo->with_modifiers = gr_handle->modifier != DRM_FORMAT_MOD_NONE && + gr_handle->modifier != DRM_FORMAT_MOD_INVALID; +#endif + bo->usage = gr_handle->usage; + bo->prime_fds[0] = gr_handle->prime_fd; + + if (is_yuv(gr_handle->format)) { + if (!GetYuvPlaneInfo(handle->numFds, handle, bo)) + return -EINVAL; + } else { + bo->pitches[0] = gr_handle->stride; + bo->offsets[0] = 0; + bo->format = ConvertHalFormatToDrm(gr_handle->format); + if (bo->format == DRM_FORMAT_INVALID) + return -EINVAL; + } + bo->pixel_stride = (gr_handle->stride * 8) / DrmFormatToBitsPerPixel(bo->format); - bo->prime_fds[0] = gr_handle->prime_fd; - bo->pitches[0] = gr_handle->stride; - bo->offsets[0] = 0; return 0; } diff --git a/platform/platformdrmgeneric.h b/platform/platformdrmgeneric.h index f9d923f..ad74de4 100644 --- a/platform/platformdrmgeneric.h +++ b/platform/platformdrmgeneric.h @@ -48,6 +48,7 @@ class DrmGenericImporter : public Importer { uint32_t ConvertHalFormatToDrm(uint32_t hal_format); uint32_t DrmFormatToBitsPerPixel(uint32_t drm_format); + bool GetYuvPlaneInfo(int num_fds, buffer_handle_t handle, hwc_drm_bo_t *bo); protected: DrmDevice *drm_; -- cgit v1.2.3 From aa3cd5456293a2a30a142824e58fd8dd92e628c6 Mon Sep 17 00:00:00 2001 From: Roman Stratiienko Date: Sat, 29 Aug 2020 11:26:16 +0300 Subject: drm_hwcomposer: move header files into source directory ... to improve navigation between source/header file. Unnecessary dependencies also removed. Signed-off-by: Roman Stratiienko Change-Id: I2c3bf993b8c5f356490433fd94e90011487a1276 --- Android.bp | 10 +- backend/backend.cpp | 1 - backend/backend.h | 38 +++ backend/backendclient.cpp | 1 - backend/backendclient.h | 33 +++ backend/backendmanager.cpp | 2 - backend/backendmanager.h | 58 +++++ backend/backendrcardu.h | 32 +++ compositor/drmdisplaycomposition.cpp | 14 +- compositor/drmdisplaycomposition.h | 198 ++++++++++++++++ compositor/drmdisplaycompositor.cpp | 18 +- compositor/drmdisplaycompositor.h | 161 +++++++++++++ drm/drmconnector.h | 116 ++++++++++ drm/drmcrtc.h | 65 ++++++ drm/drmdevice.cpp | 5 - drm/drmdevice.h | 110 +++++++++ drm/drmencoder.cpp | 1 - drm/drmencoder.h | 60 +++++ drm/drmeventlistener.h | 65 ++++++ drm/drmmode.cpp | 4 - drm/drmmode.h | 83 +++++++ drm/drmplane.cpp | 1 - drm/drmplane.h | 88 +++++++ drm/drmproperty.h | 79 +++++++ drm/resourcemanager.cpp | 1 - drm/resourcemanager.h | 60 +++++ drm/vsyncworker.cpp | 4 - drm/vsyncworker.h | 68 ++++++ drmhwctwo.cpp | 14 +- drmhwctwo.h | 431 +++++++++++++++++++++++++++++++++++ include/autolock.h | 42 ---- include/backend.h | 38 --- include/backendclient.h | 33 --- include/backendmanager.h | 58 ----- include/backendrcardu.h | 32 --- include/drmconnector.h | 115 ---------- include/drmcrtc.h | 65 ------ include/drmdevice.h | 109 --------- include/drmdisplaycomposition.h | 198 ---------------- include/drmdisplaycompositor.h | 161 ------------- include/drmencoder.h | 59 ----- include/drmeventlistener.h | 65 ------ include/drmhwctwo.h | 431 ----------------------------------- include/drmmode.h | 82 ------- include/drmplane.h | 87 ------- include/drmproperty.h | 78 ------- include/platform.h | 161 ------------- include/resourcemanager.h | 60 ----- include/vsyncworker.h | 68 ------ include/worker.h | 81 ------- platform/platform.cpp | 3 +- platform/platform.h | 161 +++++++++++++ platform/platformdrmgeneric.cpp | 2 - platform/platformdrmgeneric.h | 8 +- platform/platformhisi.cpp | 4 - platform/platformhisi.h | 1 - platform/platformimagination.cpp | 1 + platform/platformimagination.h | 1 - platform/platformmeson.cpp | 4 - platform/platformmeson.h | 1 - platform/platformminigbm.cpp | 3 - platform/platformminigbm.h | 1 - tests/Android.bp | 5 +- tests/worker_test.cpp | 4 +- utils/autolock.h | 42 ++++ utils/hwcutils.cpp | 6 +- utils/worker.h | 81 +++++++ 67 files changed, 2074 insertions(+), 2098 deletions(-) create mode 100644 backend/backend.h create mode 100644 backend/backendclient.h create mode 100644 backend/backendmanager.h create mode 100644 backend/backendrcardu.h create mode 100644 compositor/drmdisplaycomposition.h create mode 100644 compositor/drmdisplaycompositor.h create mode 100644 drm/drmconnector.h create mode 100644 drm/drmcrtc.h create mode 100644 drm/drmdevice.h create mode 100644 drm/drmencoder.h create mode 100644 drm/drmeventlistener.h create mode 100644 drm/drmmode.h create mode 100644 drm/drmplane.h create mode 100644 drm/drmproperty.h create mode 100644 drm/resourcemanager.h create mode 100644 drm/vsyncworker.h create mode 100644 drmhwctwo.h delete mode 100644 include/autolock.h delete mode 100644 include/backend.h delete mode 100644 include/backendclient.h delete mode 100644 include/backendmanager.h delete mode 100644 include/backendrcardu.h delete mode 100644 include/drmconnector.h delete mode 100644 include/drmcrtc.h delete mode 100644 include/drmdevice.h delete mode 100644 include/drmdisplaycomposition.h delete mode 100644 include/drmdisplaycompositor.h delete mode 100644 include/drmencoder.h delete mode 100644 include/drmeventlistener.h delete mode 100644 include/drmhwctwo.h delete mode 100644 include/drmmode.h delete mode 100644 include/drmplane.h delete mode 100644 include/drmproperty.h delete mode 100644 include/platform.h delete mode 100644 include/resourcemanager.h delete mode 100644 include/vsyncworker.h delete mode 100644 include/worker.h create mode 100644 platform/platform.h create mode 100644 utils/autolock.h create mode 100644 utils/worker.h diff --git a/Android.bp b/Android.bp index 7046837..ef8af52 100644 --- a/Android.bp +++ b/Android.bp @@ -20,7 +20,10 @@ cc_library_static { srcs: ["utils/worker.cpp"], - include_dirs: ["external/drm_hwcomposer/include"], + include_dirs: [ + "external/drm_hwcomposer/include", + "external/drm_hwcomposer", + ], cflags: [ "-Wall", @@ -47,7 +50,10 @@ cc_defaults { "libutils", ], - include_dirs: ["external/drm_hwcomposer/include"], + include_dirs: [ + "external/drm_hwcomposer/include", + "external/drm_hwcomposer", + ], static_libs: ["libdrmhwc_utils"], diff --git a/backend/backend.cpp b/backend/backend.cpp index 08ee5a7..e36c47e 100644 --- a/backend/backend.cpp +++ b/backend/backend.cpp @@ -16,7 +16,6 @@ #include "backend.h" #include "backendmanager.h" -#include "drmhwctwo.h" namespace android { diff --git a/backend/backend.h b/backend/backend.h new file mode 100644 index 0000000..cd9d8cd --- /dev/null +++ b/backend/backend.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_BACKEND_H +#define ANDROID_BACKEND_H + +#include "drmhwctwo.h" + +namespace android { + +class Backend { + public: + virtual ~Backend() = default; + virtual HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, + uint32_t *num_types, + uint32_t *num_requests); + virtual std::tuple GetClientLayers( + DrmHwcTwo::HwcDisplay *display, + const std::map &z_map); + virtual bool IsClientLayer(DrmHwcTwo::HwcDisplay *display, + DrmHwcTwo::HwcLayer *layer); +}; +} // namespace android + +#endif diff --git a/backend/backendclient.cpp b/backend/backendclient.cpp index 3f3cd44..a9418da 100644 --- a/backend/backendclient.cpp +++ b/backend/backendclient.cpp @@ -16,7 +16,6 @@ #include "backendclient.h" #include "backendmanager.h" -#include "drmhwctwo.h" namespace android { diff --git a/backend/backendclient.h b/backend/backendclient.h new file mode 100644 index 0000000..361160f --- /dev/null +++ b/backend/backendclient.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_BACKEND_CLIENT_H +#define ANDROID_BACKEND_CLIENT_H + +#include "backend.h" +#include "drmhwctwo.h" + +namespace android { + +class BackendClient : public Backend { + public: + HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, + uint32_t *num_types, + uint32_t *num_requests) override; +}; +} // namespace android + +#endif diff --git a/backend/backendmanager.cpp b/backend/backendmanager.cpp index 80ec827..03ad704 100644 --- a/backend/backendmanager.cpp +++ b/backend/backendmanager.cpp @@ -17,8 +17,6 @@ #define LOG_TAG "hwc-backend" #include "backendmanager.h" -#include "backend.h" -#include "drmhwctwo.h" #include #include diff --git a/backend/backendmanager.h b/backend/backendmanager.h new file mode 100644 index 0000000..f18637d --- /dev/null +++ b/backend/backendmanager.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_BACKEND_MANAGER_H +#define ANDROID_BACKEND_MANAGER_H + +#include +#include +#include +#include + +#include "backend.h" +#include "drmhwctwo.h" + +#define REGISTER_BACKEND(name_str_, backend_) \ + static int \ + backend = BackendManager::GetInstance() \ + .RegisterBackend(name_str_, \ + []() -> std::unique_ptr { \ + return std::make_unique(); \ + }); + +namespace android { + +class BackendManager { + public: + using backend_constructor_t = std::function()>; + static BackendManager &GetInstance(); + int RegisterBackend(const std::string &name, + backend_constructor_t backend_constructor); + int SetBackendForDisplay(DrmHwcTwo::HwcDisplay *display); + std::unique_ptr GetBackendByName(std::string &name); + HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, + uint32_t *num_types, uint32_t *num_requests); + + private: + BackendManager() = default; + + static const std::vector client_devices_; + + std::map available_backends_; +}; +} // namespace android + +#endif diff --git a/backend/backendrcardu.h b/backend/backendrcardu.h new file mode 100644 index 0000000..29ccea9 --- /dev/null +++ b/backend/backendrcardu.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HWC_DISPLAY_BACKEND_RCAR_DU_H +#define HWC_DISPLAY_BACKEND_RCAR_DU_H + +#include "backend.h" +#include "drmhwctwo.h" + +namespace android { + +class BackendRCarDu : public Backend { + public: + bool IsClientLayer(DrmHwcTwo::HwcDisplay *display, + DrmHwcTwo::HwcLayer *layer) override; +}; +} // namespace android + +#endif diff --git a/compositor/drmdisplaycomposition.cpp b/compositor/drmdisplaycomposition.cpp index b710fe1..82d7194 100644 --- a/compositor/drmdisplaycomposition.cpp +++ b/compositor/drmdisplaycomposition.cpp @@ -17,20 +17,18 @@ #define LOG_TAG "hwc-drm-display-composition" #include "drmdisplaycomposition.h" -#include "drmcrtc.h" -#include "drmdevice.h" -#include "drmdisplaycompositor.h" -#include "drmplane.h" -#include "platform.h" +#include #include +#include +#include #include #include -#include -#include -#include +#include "drm/drmdevice.h" +#include "drmdisplaycompositor.h" +#include "platform/platform.h" namespace android { diff --git a/compositor/drmdisplaycomposition.h b/compositor/drmdisplaycomposition.h new file mode 100644 index 0000000..d8a668c --- /dev/null +++ b/compositor/drmdisplaycomposition.h @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_DISPLAY_COMPOSITION_H_ +#define ANDROID_DRM_DISPLAY_COMPOSITION_H_ + +#include +#include + +#include +#include + +#include "drm/drmcrtc.h" +#include "drm/drmplane.h" +#include "drmhwcomposer.h" + +namespace android { + +class Importer; +class Planner; +class SquashState; + +enum DrmCompositionType { + DRM_COMPOSITION_TYPE_EMPTY, + DRM_COMPOSITION_TYPE_FRAME, + DRM_COMPOSITION_TYPE_DPMS, + DRM_COMPOSITION_TYPE_MODESET, +}; + +struct DrmCompositionDisplayLayersMap { + int display; + bool geometry_changed = true; + std::vector layers; + + DrmCompositionDisplayLayersMap() = default; + DrmCompositionDisplayLayersMap(DrmCompositionDisplayLayersMap &&rhs) = + default; +}; + +struct DrmCompositionRegion { + std::vector source_layers; +}; + +class DrmCompositionPlane { + public: + enum class Type : int32_t { + kDisable, + kLayer, + }; + + DrmCompositionPlane() = default; + DrmCompositionPlane(DrmCompositionPlane &&rhs) = default; + DrmCompositionPlane &operator=(DrmCompositionPlane &&other) = default; + DrmCompositionPlane(Type type, DrmPlane *plane, DrmCrtc *crtc) + : type_(type), plane_(plane), crtc_(crtc) { + } + DrmCompositionPlane(Type type, DrmPlane *plane, DrmCrtc *crtc, + size_t source_layer) + : type_(type), + plane_(plane), + crtc_(crtc), + source_layers_(1, source_layer) { + } + + Type type() const { + return type_; + } + + DrmPlane *plane() const { + return plane_; + } + void set_plane(DrmPlane *plane) { + plane_ = plane; + } + + DrmCrtc *crtc() const { + return crtc_; + } + + std::vector &source_layers() { + return source_layers_; + } + + const std::vector &source_layers() const { + return source_layers_; + } + + private: + Type type_ = Type::kDisable; + DrmPlane *plane_ = NULL; + DrmCrtc *crtc_ = NULL; + std::vector source_layers_; +}; + +class DrmDisplayComposition { + public: + DrmDisplayComposition() = default; + DrmDisplayComposition(const DrmDisplayComposition &) = delete; + ~DrmDisplayComposition(); + + int Init(DrmDevice *drm, DrmCrtc *crtc, Importer *importer, Planner *planner, + uint64_t frame_no); + + int SetLayers(DrmHwcLayer *layers, size_t num_layers, bool geometry_changed); + int AddPlaneComposition(DrmCompositionPlane plane); + int AddPlaneDisable(DrmPlane *plane); + int SetDpmsMode(uint32_t dpms_mode); + int SetDisplayMode(const DrmMode &display_mode); + + int Plan(std::vector *primary_planes, + std::vector *overlay_planes); + + std::vector &layers() { + return layers_; + } + + std::vector &composition_planes() { + return composition_planes_; + } + + bool geometry_changed() const { + return geometry_changed_; + } + + uint64_t frame_no() const { + return frame_no_; + } + + DrmCompositionType type() const { + return type_; + } + + uint32_t dpms_mode() const { + return dpms_mode_; + } + + const DrmMode &display_mode() const { + return display_mode_; + } + + DrmCrtc *crtc() const { + return crtc_; + } + + Importer *importer() const { + return importer_; + } + + Planner *planner() const { + return planner_; + } + + int take_out_fence() { + return out_fence_.Release(); + } + + void set_out_fence(int out_fence) { + out_fence_.Set(out_fence); + } + + void Dump(std::ostringstream *out) const; + + private: + bool validate_composition_type(DrmCompositionType desired); + + DrmDevice *drm_ = NULL; + DrmCrtc *crtc_ = NULL; + Importer *importer_ = NULL; + Planner *planner_ = NULL; + + DrmCompositionType type_ = DRM_COMPOSITION_TYPE_EMPTY; + uint32_t dpms_mode_ = DRM_MODE_DPMS_ON; + DrmMode display_mode_; + + UniqueFd out_fence_ = -1; + + bool geometry_changed_; + std::vector layers_; + std::vector composition_planes_; + + uint64_t frame_no_ = 0; +}; +} // namespace android + +#endif // ANDROID_DRM_DISPLAY_COMPOSITION_H_ diff --git a/compositor/drmdisplaycompositor.cpp b/compositor/drmdisplaycompositor.cpp index 1519736..aed090a 100644 --- a/compositor/drmdisplaycompositor.cpp +++ b/compositor/drmdisplaycompositor.cpp @@ -19,23 +19,23 @@ #include "drmdisplaycompositor.h" +#include +#include #include #include #include +#include #include +#include + #include #include #include -#include -#include -#include -#include - -#include "autolock.h" -#include "drmcrtc.h" -#include "drmdevice.h" -#include "drmplane.h" +#include "drm/drmcrtc.h" +#include "drm/drmdevice.h" +#include "drm/drmplane.h" +#include "utils/autolock.h" static const uint32_t kWaitWritebackFence = 100; // ms diff --git a/compositor/drmdisplaycompositor.h b/compositor/drmdisplaycompositor.h new file mode 100644 index 0000000..62dd04e --- /dev/null +++ b/compositor/drmdisplaycompositor.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_DISPLAY_COMPOSITOR_H_ +#define ANDROID_DRM_DISPLAY_COMPOSITOR_H_ + +#include +#include +#include + +#include +#include +#include + +#include "drm/resourcemanager.h" +#include "drm/vsyncworker.h" +#include "drmdisplaycomposition.h" +#include "drmframebuffer.h" +#include "drmhwcomposer.h" + +// One for the front, one for the back, and one for cases where we need to +// squash a frame that the hw can't display with hw overlays. +#define DRM_DISPLAY_BUFFERS 3 + +// If a scene is still for this number of vblanks flatten it to reduce power +// consumption. +#define FLATTEN_COUNTDOWN_INIT 60 + +namespace android { + +enum class FlatteningState { + kNone, + kNotNeeded, + kClientRequested, + kClientDone, + kSerial, + kConcurrent +}; + +std::ostream &operator<<(std::ostream &str, FlatteningState state); + +class DrmDisplayCompositor { + public: + DrmDisplayCompositor(); + ~DrmDisplayCompositor(); + + int Init(ResourceManager *resource_manager, int display); + + template + void SetRefreshCallback(Fn &&refresh_cb) { + refresh_display_cb_ = std::forward(refresh_cb); + } + + std::unique_ptr CreateComposition() const; + std::unique_ptr CreateInitializedComposition() const; + int ApplyComposition(std::unique_ptr composition); + int TestComposition(DrmDisplayComposition *composition); + int Composite(); + void Dump(std::ostringstream *out) const; + void Vsync(int display, int64_t timestamp); + void ClearDisplay(); + int TakeOutFence() { + if (!active_composition_) + return -1; + return active_composition_->take_out_fence(); + } + + FlatteningState GetFlatteningState() const; + uint32_t GetFlattenedFramesCount() const; + bool ShouldFlattenOnClient() const; + + std::tuple GetActiveModeResolution(); + + private: + struct ModeState { + bool needs_modeset = false; + DrmMode mode; + uint32_t blob_id = 0; + uint32_t old_blob_id = 0; + }; + + DrmDisplayCompositor(const DrmDisplayCompositor &) = delete; + + // We'll wait for acquire fences to fire for kAcquireWaitTimeoutMs, + // kAcquireWaitTries times, logging a warning in between. + static const int kAcquireWaitTries = 5; + static const int kAcquireWaitTimeoutMs = 100; + + int CommitFrame(DrmDisplayComposition *display_comp, bool test_only, + DrmConnector *writeback_conn = NULL, + DrmHwcBuffer *writeback_buffer = NULL); + int SetupWritebackCommit(drmModeAtomicReqPtr pset, uint32_t crtc_id, + DrmConnector *writeback_conn, + DrmHwcBuffer *writeback_buffer); + int ApplyDpms(DrmDisplayComposition *display_comp); + int DisablePlanes(DrmDisplayComposition *display_comp); + + void ApplyFrame(std::unique_ptr composition, + int status, bool writeback = false); + + void SetFlattening(FlatteningState new_state); + bool IsFlatteningNeeded() const; + int FlattenActiveComposition(); + int FlattenOnClient(); + int FlattenSerial(DrmConnector *writeback_conn); + int FlattenConcurrent(DrmConnector *writeback_conn); + int FlattenOnDisplay(std::unique_ptr &src, + DrmConnector *writeback_conn, DrmMode &src_mode, + DrmHwcLayer *writeback_layer); + + bool CountdownExpired() const; + + std::tuple CreateModeBlob(const DrmMode &mode); + + ResourceManager *resource_manager_; + int display_; + + std::unique_ptr active_composition_; + + bool initialized_; + bool active_; + bool use_hw_overlays_; + + ModeState mode_; + + int framebuffer_index_; + DrmFramebuffer framebuffers_[DRM_DISPLAY_BUFFERS]; + + // mutable since we need to acquire in Dump() + mutable pthread_mutex_t lock_; + + // State tracking progress since our last Dump(). These are mutable since + // we need to reset them on every Dump() call. + mutable uint64_t dump_frames_composited_; + mutable uint64_t dump_last_timestamp_ns_; + VSyncWorker vsync_worker_; + int64_t flatten_countdown_; + std::unique_ptr planner_; + int writeback_fence_; + + FlatteningState flattening_state_; + uint32_t frames_flattened_; + + std::function refresh_display_cb_; +}; +} // namespace android + +#endif // ANDROID_DRM_DISPLAY_COMPOSITOR_H_ diff --git a/drm/drmconnector.h b/drm/drmconnector.h new file mode 100644 index 0000000..0c19c55 --- /dev/null +++ b/drm/drmconnector.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_CONNECTOR_H_ +#define ANDROID_DRM_CONNECTOR_H_ + +#include +#include + +#include +#include + +#include "drmencoder.h" +#include "drmmode.h" +#include "drmproperty.h" + +namespace android { + +class DrmDevice; + +class DrmConnector { + public: + DrmConnector(DrmDevice *drm, drmModeConnectorPtr c, + DrmEncoder *current_encoder, + std::vector &possible_encoders); + DrmConnector(const DrmProperty &) = delete; + DrmConnector &operator=(const DrmProperty &) = delete; + + int Init(); + + uint32_t id() const; + + int display() const; + void set_display(int display); + + bool internal() const; + bool external() const; + bool writeback() const; + bool valid_type() const; + + std::string name() const; + + int UpdateModes(); + + const std::vector &modes() const { + return modes_; + } + const DrmMode &active_mode() const; + void set_active_mode(const DrmMode &mode); + + const DrmProperty &dpms_property() const; + const DrmProperty &crtc_id_property() const; + const DrmProperty &edid_property() const; + const DrmProperty &writeback_pixel_formats() const; + const DrmProperty &writeback_fb_id() const; + const DrmProperty &writeback_out_fence() const; + + const std::vector &possible_encoders() const { + return possible_encoders_; + } + DrmEncoder *encoder() const; + void set_encoder(DrmEncoder *encoder); + + drmModeConnection state() const; + + uint32_t mm_width() const; + uint32_t mm_height() const; + + uint32_t get_preferred_mode_id() const { + return preferred_mode_id_; + } + + private: + DrmDevice *drm_; + + uint32_t id_; + DrmEncoder *encoder_; + int display_; + + uint32_t type_; + uint32_t type_id_; + drmModeConnection state_; + + uint32_t mm_width_; + uint32_t mm_height_; + + DrmMode active_mode_; + std::vector modes_; + + DrmProperty dpms_property_; + DrmProperty crtc_id_property_; + DrmProperty edid_property_; + DrmProperty writeback_pixel_formats_; + DrmProperty writeback_fb_id_; + DrmProperty writeback_out_fence_; + + std::vector possible_encoders_; + + uint32_t preferred_mode_id_; +}; +} // namespace android + +#endif // ANDROID_DRM_PLANE_H_ diff --git a/drm/drmcrtc.h b/drm/drmcrtc.h new file mode 100644 index 0000000..132c2d3 --- /dev/null +++ b/drm/drmcrtc.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_CRTC_H_ +#define ANDROID_DRM_CRTC_H_ + +#include +#include + +#include "drmmode.h" +#include "drmproperty.h" + +namespace android { + +class DrmDevice; + +class DrmCrtc { + public: + DrmCrtc(DrmDevice *drm, drmModeCrtcPtr c, unsigned pipe); + DrmCrtc(const DrmCrtc &) = delete; + DrmCrtc &operator=(const DrmCrtc &) = delete; + + int Init(); + + uint32_t id() const; + unsigned pipe() const; + + int display() const; + void set_display(int display); + + bool can_bind(int display) const; + + const DrmProperty &active_property() const; + const DrmProperty &mode_property() const; + const DrmProperty &out_fence_ptr_property() const; + + private: + DrmDevice *drm_; + + uint32_t id_; + unsigned pipe_; + int display_; + + DrmMode mode_; + + DrmProperty active_property_; + DrmProperty mode_property_; + DrmProperty out_fence_ptr_property_; +}; +} // namespace android + +#endif // ANDROID_DRM_CRTC_H_ diff --git a/drm/drmdevice.cpp b/drm/drmdevice.cpp index 91fe158..18b5b62 100644 --- a/drm/drmdevice.cpp +++ b/drm/drmdevice.cpp @@ -17,11 +17,6 @@ #define LOG_TAG "hwc-drm-device" #include "drmdevice.h" -#include "drmconnector.h" -#include "drmcrtc.h" -#include "drmencoder.h" -#include "drmeventlistener.h" -#include "drmplane.h" #include #include diff --git a/drm/drmdevice.h b/drm/drmdevice.h new file mode 100644 index 0000000..6a8de47 --- /dev/null +++ b/drm/drmdevice.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_H_ +#define ANDROID_DRM_H_ + +#include + +#include + +#include "drmconnector.h" +#include "drmcrtc.h" +#include "drmencoder.h" +#include "drmeventlistener.h" +#include "drmplane.h" +#include "platform/platform.h" + +namespace android { + +class DrmDevice { + public: + DrmDevice(); + ~DrmDevice(); + + std::tuple Init(const char *path, int num_displays); + + int fd() const { + return fd_.get(); + } + + const std::vector> &connectors() const { + return connectors_; + } + + const std::vector> &planes() const { + return planes_; + } + + std::pair min_resolution() const { + return min_resolution_; + } + + std::pair max_resolution() const { + return max_resolution_; + } + + DrmConnector *GetConnectorForDisplay(int display) const; + DrmConnector *GetWritebackConnectorForDisplay(int display) const; + DrmConnector *AvailableWritebackConnector(int display) const; + DrmCrtc *GetCrtcForDisplay(int display) const; + DrmPlane *GetPlane(uint32_t id) const; + DrmEventListener *event_listener(); + + int GetPlaneProperty(const DrmPlane &plane, const char *prop_name, + DrmProperty *property); + int GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name, + DrmProperty *property); + int GetConnectorProperty(const DrmConnector &connector, const char *prop_name, + DrmProperty *property); + + const std::string GetName() const; + + const std::vector> &crtcs() const; + uint32_t next_mode_id(); + + int CreatePropertyBlob(void *data, size_t length, uint32_t *blob_id); + int DestroyPropertyBlob(uint32_t blob_id); + bool HandlesDisplay(int display) const; + void RegisterHotplugHandler(DrmEventHandler *handler) { + event_listener_.RegisterHotplugHandler(handler); + } + + private: + int TryEncoderForDisplay(int display, DrmEncoder *enc); + int GetProperty(uint32_t obj_id, uint32_t obj_type, const char *prop_name, + DrmProperty *property); + + int CreateDisplayPipe(DrmConnector *connector); + int AttachWriteback(DrmConnector *display_conn); + + UniqueFd fd_; + uint32_t mode_id_ = 0; + + std::vector> connectors_; + std::vector> writeback_connectors_; + std::vector> encoders_; + std::vector> crtcs_; + std::vector> planes_; + DrmEventListener event_listener_; + + std::pair min_resolution_; + std::pair max_resolution_; + std::map displays_; +}; +} // namespace android + +#endif // ANDROID_DRM_H_ diff --git a/drm/drmencoder.cpp b/drm/drmencoder.cpp index c36fca1..9aa6805 100644 --- a/drm/drmencoder.cpp +++ b/drm/drmencoder.cpp @@ -15,7 +15,6 @@ */ #include "drmencoder.h" -#include "drmcrtc.h" #include "drmdevice.h" #include diff --git a/drm/drmencoder.h b/drm/drmencoder.h new file mode 100644 index 0000000..4403d9f --- /dev/null +++ b/drm/drmencoder.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_ENCODER_H_ +#define ANDROID_DRM_ENCODER_H_ + +#include +#include + +#include +#include + +#include "drmcrtc.h" + +namespace android { + +class DrmEncoder { + public: + DrmEncoder(drmModeEncoderPtr e, DrmCrtc *current_crtc, + const std::vector &possible_crtcs); + DrmEncoder(const DrmEncoder &) = delete; + DrmEncoder &operator=(const DrmEncoder &) = delete; + + uint32_t id() const; + + DrmCrtc *crtc() const; + void set_crtc(DrmCrtc *crtc); + bool can_bind(int display) const; + int display() const; + + const std::vector &possible_crtcs() const { + return possible_crtcs_; + } + bool CanClone(DrmEncoder *encoder); + void AddPossibleClone(DrmEncoder *possible_clone); + + private: + uint32_t id_; + DrmCrtc *crtc_; + int display_; + + std::vector possible_crtcs_; + std::set possible_clones_; +}; +} // namespace android + +#endif // ANDROID_DRM_ENCODER_H_ diff --git a/drm/drmeventlistener.h b/drm/drmeventlistener.h new file mode 100644 index 0000000..ff3b8e5 --- /dev/null +++ b/drm/drmeventlistener.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#ifndef ANDROID_DRM_EVENT_LISTENER_H_ +#define ANDROID_DRM_EVENT_LISTENER_H_ + +#include "autofd.h" +#include "utils/worker.h" + +namespace android { + +class DrmDevice; + +class DrmEventHandler { + public: + DrmEventHandler() { + } + virtual ~DrmEventHandler() { + } + + virtual void HandleEvent(uint64_t timestamp_us) = 0; +}; + +class DrmEventListener : public Worker { + public: + DrmEventListener(DrmDevice *drm); + virtual ~DrmEventListener() { + } + + int Init(); + + void RegisterHotplugHandler(DrmEventHandler *handler); + + static void FlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, + unsigned int tv_usec, void *user_data); + + protected: + virtual void Routine(); + + private: + void UEventHandler(); + + fd_set fds_; + UniqueFd uevent_fd_; + int max_fd_ = -1; + + DrmDevice *drm_; + std::unique_ptr hotplug_handler_; +}; +} // namespace android + +#endif diff --git a/drm/drmmode.cpp b/drm/drmmode.cpp index c3ab385..c1398ef 100644 --- a/drm/drmmode.cpp +++ b/drm/drmmode.cpp @@ -17,10 +17,6 @@ #include "drmmode.h" #include "drmdevice.h" -#include -#include -#include - namespace android { DrmMode::DrmMode(drmModeModeInfoPtr m) diff --git a/drm/drmmode.h b/drm/drmmode.h new file mode 100644 index 0000000..313a8ea --- /dev/null +++ b/drm/drmmode.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_MODE_H_ +#define ANDROID_DRM_MODE_H_ + +#include +#include + +#include + +namespace android { + +class DrmMode { + public: + DrmMode() = default; + DrmMode(drmModeModeInfoPtr m); + + bool operator==(const drmModeModeInfo &m) const; + void ToDrmModeModeInfo(drm_mode_modeinfo *m) const; + + uint32_t id() const; + void set_id(uint32_t id); + + uint32_t clock() const; + + uint32_t h_display() const; + uint32_t h_sync_start() const; + uint32_t h_sync_end() const; + uint32_t h_total() const; + uint32_t h_skew() const; + + uint32_t v_display() const; + uint32_t v_sync_start() const; + uint32_t v_sync_end() const; + uint32_t v_total() const; + uint32_t v_scan() const; + float v_refresh() const; + + uint32_t flags() const; + uint32_t type() const; + + std::string name() const; + + private: + uint32_t id_ = 0; + + uint32_t clock_ = 0; + + uint32_t h_display_ = 0; + uint32_t h_sync_start_ = 0; + uint32_t h_sync_end_ = 0; + uint32_t h_total_ = 0; + uint32_t h_skew_ = 0; + + uint32_t v_display_ = 0; + uint32_t v_sync_start_ = 0; + uint32_t v_sync_end_ = 0; + uint32_t v_total_ = 0; + uint32_t v_scan_ = 0; + uint32_t v_refresh_ = 0; + + uint32_t flags_ = 0; + uint32_t type_ = 0; + + std::string name_; +}; +} // namespace android + +#endif // ANDROID_DRM_MODE_H_ diff --git a/drm/drmplane.cpp b/drm/drmplane.cpp index 6f1bf9b..f0c7559 100644 --- a/drm/drmplane.cpp +++ b/drm/drmplane.cpp @@ -24,7 +24,6 @@ #include #include -#include namespace android { diff --git a/drm/drmplane.h b/drm/drmplane.h new file mode 100644 index 0000000..1a4dc91 --- /dev/null +++ b/drm/drmplane.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_PLANE_H_ +#define ANDROID_DRM_PLANE_H_ + +#include +#include + +#include + +#include "drmcrtc.h" +#include "drmproperty.h" + +namespace android { + +class DrmDevice; + +class DrmPlane { + public: + DrmPlane(DrmDevice *drm, drmModePlanePtr p); + DrmPlane(const DrmPlane &) = delete; + DrmPlane &operator=(const DrmPlane &) = delete; + + int Init(); + + uint32_t id() const; + + bool GetCrtcSupported(const DrmCrtc &crtc) const; + + uint32_t type() const; + + const DrmProperty &crtc_property() const; + const DrmProperty &fb_property() const; + const DrmProperty &crtc_x_property() const; + const DrmProperty &crtc_y_property() const; + const DrmProperty &crtc_w_property() const; + const DrmProperty &crtc_h_property() const; + const DrmProperty &src_x_property() const; + const DrmProperty &src_y_property() const; + const DrmProperty &src_w_property() const; + const DrmProperty &src_h_property() const; + const DrmProperty &zpos_property() const; + const DrmProperty &rotation_property() const; + const DrmProperty &alpha_property() const; + const DrmProperty &blend_property() const; + const DrmProperty &in_fence_fd_property() const; + + private: + DrmDevice *drm_; + uint32_t id_; + + uint32_t possible_crtc_mask_; + + uint32_t type_; + + DrmProperty crtc_property_; + DrmProperty fb_property_; + DrmProperty crtc_x_property_; + DrmProperty crtc_y_property_; + DrmProperty crtc_w_property_; + DrmProperty crtc_h_property_; + DrmProperty src_x_property_; + DrmProperty src_y_property_; + DrmProperty src_w_property_; + DrmProperty src_h_property_; + DrmProperty zpos_property_; + DrmProperty rotation_property_; + DrmProperty alpha_property_; + DrmProperty blend_property_; + DrmProperty in_fence_fd_property_; +}; +} // namespace android + +#endif // ANDROID_DRM_PLANE_H_ diff --git a/drm/drmproperty.h b/drm/drmproperty.h new file mode 100644 index 0000000..d293da3 --- /dev/null +++ b/drm/drmproperty.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_PROPERTY_H_ +#define ANDROID_DRM_PROPERTY_H_ + +#include +#include + +#include +#include + +namespace android { + +enum DrmPropertyType { + DRM_PROPERTY_TYPE_INT, + DRM_PROPERTY_TYPE_ENUM, + DRM_PROPERTY_TYPE_OBJECT, + DRM_PROPERTY_TYPE_BLOB, + DRM_PROPERTY_TYPE_INVALID, +}; + +class DrmProperty { + public: + DrmProperty() = default; + DrmProperty(drmModePropertyPtr p, uint64_t value); + DrmProperty(const DrmProperty &) = delete; + DrmProperty &operator=(const DrmProperty &) = delete; + + void Init(drmModePropertyPtr p, uint64_t value); + std::tuple GetEnumValueWithName(std::string name) const; + + uint32_t id() const; + std::string name() const; + + std::tuple value() const; + bool is_immutable() const; + + bool is_range() const; + std::tuple range_min() const; + std::tuple range_max() const; + + private: + class DrmPropertyEnum { + public: + DrmPropertyEnum(drm_mode_property_enum *e); + ~DrmPropertyEnum(); + + uint64_t value_; + std::string name_; + }; + + uint32_t id_ = 0; + + DrmPropertyType type_ = DRM_PROPERTY_TYPE_INVALID; + uint32_t flags_ = 0; + std::string name_; + uint64_t value_ = 0; + + std::vector values_; + std::vector enums_; + std::vector blob_ids_; +}; +} // namespace android + +#endif // ANDROID_DRM_PROPERTY_H_ diff --git a/drm/resourcemanager.cpp b/drm/resourcemanager.cpp index 986d4ab..45fa818 100644 --- a/drm/resourcemanager.cpp +++ b/drm/resourcemanager.cpp @@ -22,7 +22,6 @@ #include #include #include -#include namespace android { diff --git a/drm/resourcemanager.h b/drm/resourcemanager.h new file mode 100644 index 0000000..4afa842 --- /dev/null +++ b/drm/resourcemanager.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RESOURCEMANAGER_H +#define RESOURCEMANAGER_H + +#include + +#include "drmdevice.h" +#include "platform/platform.h" + +namespace android { + +class ResourceManager { + public: + ResourceManager(); + ResourceManager(const ResourceManager &) = delete; + ResourceManager &operator=(const ResourceManager &) = delete; + int Init(); + DrmDevice *GetDrmDevice(int display); + std::shared_ptr GetImporter(int display); + const gralloc_module_t *gralloc(); + DrmConnector *AvailableWritebackConnector(int display); + const std::vector> &getDrmDevices() const { + return drms_; + } + int getDisplayCount() const { + return num_displays_; + } + bool ForcedScalingWithGpu() { + return scale_with_gpu_; + } + + private: + int AddDrmDevice(std::string path); + static bool IsKMSDev(const char *path); + + int num_displays_; + std::vector> drms_; + std::vector> importers_; + const gralloc_module_t *gralloc_; + + bool scale_with_gpu_; +}; +} // namespace android + +#endif // RESOURCEMANAGER_H diff --git a/drm/vsyncworker.cpp b/drm/vsyncworker.cpp index 08ab301..55dbd26 100644 --- a/drm/vsyncworker.cpp +++ b/drm/vsyncworker.cpp @@ -17,16 +17,12 @@ #define LOG_TAG "hwc-vsync-worker" #include "vsyncworker.h" -#include "drmdevice.h" -#include "worker.h" #include #include #include #include -#include -#include #include namespace android { diff --git a/drm/vsyncworker.h b/drm/vsyncworker.h new file mode 100644 index 0000000..cbf4ffa --- /dev/null +++ b/drm/vsyncworker.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_EVENT_WORKER_H_ +#define ANDROID_EVENT_WORKER_H_ + +#include +#include +#include + +#include + +#include "drmdevice.h" +#include "utils/worker.h" + +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(DrmDevice *drm, int display); + void RegisterCallback(std::shared_ptr callback); + + void VSyncControl(bool enabled); + + protected: + void Routine() override; + + private: + int64_t GetPhasedVSync(int64_t frame_ns, int64_t current); + int SyntheticWaitVBlank(int64_t *timestamp); + + DrmDevice *drm_; + + // 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 callback_ = NULL; + + int display_; + std::atomic_bool enabled_; + int64_t last_timestamp_; +}; +} // namespace android + +#endif diff --git a/drmhwctwo.cpp b/drmhwctwo.cpp index ffc45ef..c771022 100644 --- a/drmhwctwo.cpp +++ b/drmhwctwo.cpp @@ -18,20 +18,18 @@ #define LOG_TAG "hwc-drm-two" #include "drmhwctwo.h" -#include "backendmanager.h" -#include "drmdisplaycomposition.h" -#include "drmhwcomposer.h" -#include "platform.h" -#include "vsyncworker.h" - -#include -#include #include #include #include +#include #include +#include + +#include "backend/backendmanager.h" +#include "compositor/drmdisplaycomposition.h" + namespace android { class DrmVsyncCallback : public VsyncCallback { diff --git a/drmhwctwo.h b/drmhwctwo.h new file mode 100644 index 0000000..94b13fc --- /dev/null +++ b/drmhwctwo.h @@ -0,0 +1,431 @@ +/* + * 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. + */ + +#ifndef ANDROID_DRM_HWC_TWO_H_ +#define ANDROID_DRM_HWC_TWO_H_ + +#include +#include + +#include +#include + +#include "compositor/drmdisplaycompositor.h" +#include "drm/resourcemanager.h" +#include "drm/vsyncworker.h" +#include "drmhwcomposer.h" +#include "platform/platform.h" + +namespace android { + +class Backend; + +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(); + + 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_); + } + + hwc_rect_t display_frame() { + return display_frame_; + } + + void PopulateDrmLayer(DrmHwcLayer *layer); + + bool RequireScalingOrPhasing() { + float src_width = source_crop_.right - source_crop_.left; + float src_height = source_crop_.bottom - source_crop_.top; + + float dest_width = display_frame_.right - display_frame_.left; + float dest_height = display_frame_.bottom - display_frame_.top; + + bool scaling = src_width != dest_width || src_height != dest_height; + bool phasing = (source_crop_.left - floor(source_crop_.left) != 0) || + (source_crop_.top - floor(source_crop_.top) != 0); + return scaling || phasing; + } + + // 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_ = NULL; + 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_; + hwc_color_t layer_color_; + 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(ResourceManager *resource_manager, DrmDevice *drm, + std::shared_ptr importer, hwc2_display_t handle, + HWC2::DisplayType type); + HwcDisplay(const HwcDisplay &) = delete; + HWC2::Error Init(std::vector *planes); + + HWC2::Error RegisterVsyncCallback(hwc2_callback_data_t data, + hwc2_function_pointer_t func); + void RegisterRefreshCallback(hwc2_callback_data_t data, + hwc2_function_pointer_t func); + HWC2::Error CreateComposition(bool test); + bool HardwareSupportsLayerType(HWC2::Composition comp_type); + uint32_t CalcPixOps(std::map &z_map, + size_t first_z, size_t size); + void MarkValidated(std::map &z_map, + size_t client_first_z, size_t client_size); + + void ClearDisplay(); + + std::string Dump(); + + // HWC Hooks + HWC2::Error AcceptDisplayChanges(); + HWC2::Error CreateLayer(hwc2_layer_t *layer); + HWC2::Error DestroyLayer(hwc2_layer_t layer); + HWC2::Error GetActiveConfig(hwc2_config_t *config); + HWC2::Error GetChangedCompositionTypes(uint32_t *num_elements, + hwc2_layer_t *layers, + int32_t *types); + HWC2::Error GetClientTargetSupport(uint32_t width, uint32_t height, + int32_t format, int32_t dataspace); + HWC2::Error GetColorModes(uint32_t *num_modes, int32_t *modes); + HWC2::Error GetDisplayAttribute(hwc2_config_t config, int32_t attribute, + int32_t *value); + HWC2::Error GetDisplayConfigs(uint32_t *num_configs, + hwc2_config_t *configs); + HWC2::Error GetDisplayName(uint32_t *size, char *name); + HWC2::Error GetDisplayRequests(int32_t *display_requests, + uint32_t *num_elements, hwc2_layer_t *layers, + int32_t *layer_requests); + HWC2::Error GetDisplayType(int32_t *type); +#if PLATFORM_SDK_VERSION > 27 + HWC2::Error GetRenderIntents(int32_t mode, uint32_t *outNumIntents, + int32_t *outIntents); + HWC2::Error SetColorModeWithIntent(int32_t mode, int32_t intent); +#endif +#if PLATFORM_SDK_VERSION > 28 + HWC2::Error GetDisplayIdentificationData(uint8_t *outPort, + uint32_t *outDataSize, + uint8_t *outData); + HWC2::Error GetDisplayCapabilities(uint32_t *outNumCapabilities, + uint32_t *outCapabilities); + HWC2::Error GetDisplayBrightnessSupport(bool *supported); + HWC2::Error SetDisplayBrightness(float); +#endif + HWC2::Error GetDozeSupport(int32_t *support); + HWC2::Error GetHdrCapabilities(uint32_t *num_types, int32_t *types, + float *max_luminance, + float *max_average_luminance, + float *min_luminance); + HWC2::Error GetReleaseFences(uint32_t *num_elements, hwc2_layer_t *layers, + int32_t *fences); + HWC2::Error PresentDisplay(int32_t *present_fence); + HWC2::Error SetActiveConfig(hwc2_config_t config); + HWC2::Error ChosePreferredConfig(); + HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence, + int32_t dataspace, hwc_region_t damage); + HWC2::Error SetColorMode(int32_t mode); + HWC2::Error SetColorTransform(const float *matrix, int32_t hint); + HWC2::Error SetOutputBuffer(buffer_handle_t buffer, int32_t release_fence); + HWC2::Error SetPowerMode(int32_t mode); + HWC2::Error SetVsyncEnabled(int32_t enabled); + HWC2::Error ValidateDisplay(uint32_t *num_types, uint32_t *num_requests); + HwcLayer *get_layer(hwc2_layer_t layer) { + auto it = layers_.find(layer); + if (it == layers_.end()) + return nullptr; + return &it->second; + } + + /* Statistics */ + struct Stats { + Stats minus(Stats b) { + return {total_frames_ - b.total_frames_, + total_pixops_ - b.total_pixops_, + gpu_pixops_ - b.gpu_pixops_, + failed_kms_validate_ - b.failed_kms_validate_, + failed_kms_present_ - b.failed_kms_present_, + frames_flattened_ - b.frames_flattened_}; + } + + uint32_t total_frames_ = 0; + uint64_t total_pixops_ = 0; + uint64_t gpu_pixops_ = 0; + uint32_t failed_kms_validate_ = 0; + uint32_t failed_kms_present_ = 0; + uint32_t frames_flattened_ = 0; + }; + + const Backend *backend() const { + return backend_.get(); + } + void set_backend(std::unique_ptr backend) { + backend_ = std::move(backend); + } + + const std::vector &primary_planes() const { + return primary_planes_; + } + + const std::vector &overlay_planes() const { + return overlay_planes_; + } + + std::map &layers() { + return layers_; + } + + const DrmDisplayCompositor &compositor() const { + return compositor_; + } + + const DrmDevice *drm() const { + return drm_; + } + + const DrmConnector *connector() const { + return connector_; + } + + const std::shared_ptr &importer() const { + return importer_; + } + + ResourceManager *resource_manager() const { + return resource_manager_; + } + + android_color_transform_t &color_transform_hint() { + return color_transform_hint_; + } + + Stats &total_stats() { + return total_stats_; + } + + private: + void AddFenceToPresentFence(int fd); + + constexpr static size_t MATRIX_SIZE = 16; + + ResourceManager *resource_manager_; + DrmDevice *drm_; + DrmDisplayCompositor compositor_; + std::shared_ptr importer_; + std::unique_ptr planner_; + + std::vector primary_planes_; + std::vector overlay_planes_; + + std::unique_ptr backend_; + + VSyncWorker vsync_worker_; + DrmConnector *connector_ = NULL; + DrmCrtc *crtc_ = NULL; + hwc2_display_t handle_; + HWC2::DisplayType type_; + uint32_t layer_idx_ = 0; + std::map layers_; + HwcLayer client_layer_; + UniqueFd present_fence_; + int32_t color_mode_; + std::array color_transform_matrix_; + android_color_transform_t color_transform_hint_; + + uint32_t frame_no_ = 0; + Stats total_stats_; + Stats prev_stats_; + std::string DumpDelta(DrmHwcTwo::HwcDisplay::Stats delta); + }; + + class DrmHotplugHandler : public DrmEventHandler { + public: + DrmHotplugHandler(DrmHwcTwo *hwc2, DrmDevice *drm) + : hwc2_(hwc2), drm_(drm) { + } + void HandleEvent(uint64_t timestamp_us); + + private: + DrmHwcTwo *hwc2_; + DrmDevice *drm_; + }; + + private: + static DrmHwcTwo *toDrmHwcTwo(hwc2_device_t *dev) { + return static_cast(dev); + } + + template + static hwc2_function_pointer_t ToHook(T function) { + static_assert(std::is_same::value, "Incompatible fn pointer"); + return reinterpret_cast(function); + } + + template + static T DeviceHook(hwc2_device_t *dev, Args... args) { + DrmHwcTwo *hwc = toDrmHwcTwo(dev); + return static_cast(((*hwc).*func)(std::forward(args)...)); + } + + static HwcDisplay *GetDisplay(DrmHwcTwo *hwc, hwc2_display_t display_handle) { + auto it = hwc->displays_.find(display_handle); + if (it == hwc->displays_.end()) + return nullptr; + + return &it->second; + } + + template + static int32_t DisplayHook(hwc2_device_t *dev, hwc2_display_t display_handle, + Args... args) { + HwcDisplay *display = GetDisplay(toDrmHwcTwo(dev), display_handle); + if (!display) + return static_cast(HWC2::Error::BadDisplay); + + return static_cast((display->*func)(std::forward(args)...)); + } + + template + static int32_t LayerHook(hwc2_device_t *dev, hwc2_display_t display_handle, + hwc2_layer_t layer_handle, Args... args) { + HwcDisplay *display = GetDisplay(toDrmHwcTwo(dev), display_handle); + if (!display) + return static_cast(HWC2::Error::BadDisplay); + + HwcLayer *layer = display->get_layer(layer_handle); + if (!layer) + return static_cast(HWC2::Error::BadLayer); + + return static_cast((layer->*func)(std::forward(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 *outSize, char *outBuffer); + uint32_t GetMaxVirtualDisplayCount(); + HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data, + hwc2_function_pointer_t function); + HWC2::Error CreateDisplay(hwc2_display_t displ, HWC2::DisplayType type); + void HandleDisplayHotplug(hwc2_display_t displayid, int state); + void HandleInitialHotplugState(DrmDevice *drmDevice); + + ResourceManager resource_manager_; + std::map displays_; + std::map callbacks_; + + std::string mDumpString; +}; +} // namespace android + +#endif diff --git a/include/autolock.h b/include/autolock.h deleted file mode 100644 index 006406a..0000000 --- a/include/autolock.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2015 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 - -namespace android { - -class AutoLock { - public: - AutoLock(pthread_mutex_t *mutex, const char *const name) - : mutex_(mutex), name_(name) { - } - ~AutoLock() { - if (locked_) - Unlock(); - } - - AutoLock(const AutoLock &rhs) = delete; - AutoLock &operator=(const AutoLock &rhs) = delete; - - int Lock(); - int Unlock(); - - private: - pthread_mutex_t *const mutex_; - bool locked_ = false; - const char *const name_; -}; -} // namespace android diff --git a/include/backend.h b/include/backend.h deleted file mode 100644 index cd9d8cd..0000000 --- a/include/backend.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_BACKEND_H -#define ANDROID_BACKEND_H - -#include "drmhwctwo.h" - -namespace android { - -class Backend { - public: - virtual ~Backend() = default; - virtual HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, - uint32_t *num_types, - uint32_t *num_requests); - virtual std::tuple GetClientLayers( - DrmHwcTwo::HwcDisplay *display, - const std::map &z_map); - virtual bool IsClientLayer(DrmHwcTwo::HwcDisplay *display, - DrmHwcTwo::HwcLayer *layer); -}; -} // namespace android - -#endif diff --git a/include/backendclient.h b/include/backendclient.h deleted file mode 100644 index 361160f..0000000 --- a/include/backendclient.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_BACKEND_CLIENT_H -#define ANDROID_BACKEND_CLIENT_H - -#include "backend.h" -#include "drmhwctwo.h" - -namespace android { - -class BackendClient : public Backend { - public: - HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, - uint32_t *num_types, - uint32_t *num_requests) override; -}; -} // namespace android - -#endif diff --git a/include/backendmanager.h b/include/backendmanager.h deleted file mode 100644 index d141652..0000000 --- a/include/backendmanager.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_BACKEND_MANAGER_H -#define ANDROID_BACKEND_MANAGER_H - -#include "backend.h" -#include "drmhwctwo.h" - -#include -#include -#include -#include - -#define REGISTER_BACKEND(name_str_, backend_) \ - static int \ - backend = BackendManager::GetInstance() \ - .RegisterBackend(name_str_, \ - []() -> std::unique_ptr { \ - return std::make_unique(); \ - }); - -namespace android { - -class BackendManager { - public: - using backend_constructor_t = std::function()>; - static BackendManager &GetInstance(); - int RegisterBackend(const std::string &name, - backend_constructor_t backend_constructor); - int SetBackendForDisplay(DrmHwcTwo::HwcDisplay *display); - std::unique_ptr GetBackendByName(std::string &name); - HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, - uint32_t *num_types, uint32_t *num_requests); - - private: - BackendManager() = default; - - static const std::vector client_devices_; - - std::map available_backends_; -}; -} // namespace android - -#endif diff --git a/include/backendrcardu.h b/include/backendrcardu.h deleted file mode 100644 index 29ccea9..0000000 --- a/include/backendrcardu.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef HWC_DISPLAY_BACKEND_RCAR_DU_H -#define HWC_DISPLAY_BACKEND_RCAR_DU_H - -#include "backend.h" -#include "drmhwctwo.h" - -namespace android { - -class BackendRCarDu : public Backend { - public: - bool IsClientLayer(DrmHwcTwo::HwcDisplay *display, - DrmHwcTwo::HwcLayer *layer) override; -}; -} // namespace android - -#endif diff --git a/include/drmconnector.h b/include/drmconnector.h deleted file mode 100644 index dc64b38..0000000 --- a/include/drmconnector.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_CONNECTOR_H_ -#define ANDROID_DRM_CONNECTOR_H_ - -#include "drmencoder.h" -#include "drmmode.h" -#include "drmproperty.h" - -#include -#include -#include -#include - -namespace android { - -class DrmDevice; - -class DrmConnector { - public: - DrmConnector(DrmDevice *drm, drmModeConnectorPtr c, - DrmEncoder *current_encoder, - std::vector &possible_encoders); - DrmConnector(const DrmProperty &) = delete; - DrmConnector &operator=(const DrmProperty &) = delete; - - int Init(); - - uint32_t id() const; - - int display() const; - void set_display(int display); - - bool internal() const; - bool external() const; - bool writeback() const; - bool valid_type() const; - - std::string name() const; - - int UpdateModes(); - - const std::vector &modes() const { - return modes_; - } - const DrmMode &active_mode() const; - void set_active_mode(const DrmMode &mode); - - const DrmProperty &dpms_property() const; - const DrmProperty &crtc_id_property() const; - const DrmProperty &edid_property() const; - const DrmProperty &writeback_pixel_formats() const; - const DrmProperty &writeback_fb_id() const; - const DrmProperty &writeback_out_fence() const; - - const std::vector &possible_encoders() const { - return possible_encoders_; - } - DrmEncoder *encoder() const; - void set_encoder(DrmEncoder *encoder); - - drmModeConnection state() const; - - uint32_t mm_width() const; - uint32_t mm_height() const; - - uint32_t get_preferred_mode_id() const { - return preferred_mode_id_; - } - - private: - DrmDevice *drm_; - - uint32_t id_; - DrmEncoder *encoder_; - int display_; - - uint32_t type_; - uint32_t type_id_; - drmModeConnection state_; - - uint32_t mm_width_; - uint32_t mm_height_; - - DrmMode active_mode_; - std::vector modes_; - - DrmProperty dpms_property_; - DrmProperty crtc_id_property_; - DrmProperty edid_property_; - DrmProperty writeback_pixel_formats_; - DrmProperty writeback_fb_id_; - DrmProperty writeback_out_fence_; - - std::vector possible_encoders_; - - uint32_t preferred_mode_id_; -}; -} // namespace android - -#endif // ANDROID_DRM_PLANE_H_ diff --git a/include/drmcrtc.h b/include/drmcrtc.h deleted file mode 100644 index 3075f9b..0000000 --- a/include/drmcrtc.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_CRTC_H_ -#define ANDROID_DRM_CRTC_H_ - -#include "drmmode.h" -#include "drmproperty.h" - -#include -#include - -namespace android { - -class DrmDevice; - -class DrmCrtc { - public: - DrmCrtc(DrmDevice *drm, drmModeCrtcPtr c, unsigned pipe); - DrmCrtc(const DrmCrtc &) = delete; - DrmCrtc &operator=(const DrmCrtc &) = delete; - - int Init(); - - uint32_t id() const; - unsigned pipe() const; - - int display() const; - void set_display(int display); - - bool can_bind(int display) const; - - const DrmProperty &active_property() const; - const DrmProperty &mode_property() const; - const DrmProperty &out_fence_ptr_property() const; - - private: - DrmDevice *drm_; - - uint32_t id_; - unsigned pipe_; - int display_; - - DrmMode mode_; - - DrmProperty active_property_; - DrmProperty mode_property_; - DrmProperty out_fence_ptr_property_; -}; -} // namespace android - -#endif // ANDROID_DRM_CRTC_H_ diff --git a/include/drmdevice.h b/include/drmdevice.h deleted file mode 100644 index 1f08f20..0000000 --- a/include/drmdevice.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_H_ -#define ANDROID_DRM_H_ - -#include "drmconnector.h" -#include "drmcrtc.h" -#include "drmencoder.h" -#include "drmeventlistener.h" -#include "drmplane.h" -#include "platform.h" - -#include -#include - -namespace android { - -class DrmDevice { - public: - DrmDevice(); - ~DrmDevice(); - - std::tuple Init(const char *path, int num_displays); - - int fd() const { - return fd_.get(); - } - - const std::vector> &connectors() const { - return connectors_; - } - - const std::vector> &planes() const { - return planes_; - } - - std::pair min_resolution() const { - return min_resolution_; - } - - std::pair max_resolution() const { - return max_resolution_; - } - - DrmConnector *GetConnectorForDisplay(int display) const; - DrmConnector *GetWritebackConnectorForDisplay(int display) const; - DrmConnector *AvailableWritebackConnector(int display) const; - DrmCrtc *GetCrtcForDisplay(int display) const; - DrmPlane *GetPlane(uint32_t id) const; - DrmEventListener *event_listener(); - - int GetPlaneProperty(const DrmPlane &plane, const char *prop_name, - DrmProperty *property); - int GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name, - DrmProperty *property); - int GetConnectorProperty(const DrmConnector &connector, const char *prop_name, - DrmProperty *property); - - const std::string GetName() const; - - const std::vector> &crtcs() const; - uint32_t next_mode_id(); - - int CreatePropertyBlob(void *data, size_t length, uint32_t *blob_id); - int DestroyPropertyBlob(uint32_t blob_id); - bool HandlesDisplay(int display) const; - void RegisterHotplugHandler(DrmEventHandler *handler) { - event_listener_.RegisterHotplugHandler(handler); - } - - private: - int TryEncoderForDisplay(int display, DrmEncoder *enc); - int GetProperty(uint32_t obj_id, uint32_t obj_type, const char *prop_name, - DrmProperty *property); - - int CreateDisplayPipe(DrmConnector *connector); - int AttachWriteback(DrmConnector *display_conn); - - UniqueFd fd_; - uint32_t mode_id_ = 0; - - std::vector> connectors_; - std::vector> writeback_connectors_; - std::vector> encoders_; - std::vector> crtcs_; - std::vector> planes_; - DrmEventListener event_listener_; - - std::pair min_resolution_; - std::pair max_resolution_; - std::map displays_; -}; -} // namespace android - -#endif // ANDROID_DRM_H_ diff --git a/include/drmdisplaycomposition.h b/include/drmdisplaycomposition.h deleted file mode 100644 index 2a5b1a4..0000000 --- a/include/drmdisplaycomposition.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_DISPLAY_COMPOSITION_H_ -#define ANDROID_DRM_DISPLAY_COMPOSITION_H_ - -#include "drmcrtc.h" -#include "drmhwcomposer.h" -#include "drmplane.h" - -#include -#include - -#include -#include - -namespace android { - -class Importer; -class Planner; -class SquashState; - -enum DrmCompositionType { - DRM_COMPOSITION_TYPE_EMPTY, - DRM_COMPOSITION_TYPE_FRAME, - DRM_COMPOSITION_TYPE_DPMS, - DRM_COMPOSITION_TYPE_MODESET, -}; - -struct DrmCompositionDisplayLayersMap { - int display; - bool geometry_changed = true; - std::vector layers; - - DrmCompositionDisplayLayersMap() = default; - DrmCompositionDisplayLayersMap(DrmCompositionDisplayLayersMap &&rhs) = - default; -}; - -struct DrmCompositionRegion { - std::vector source_layers; -}; - -class DrmCompositionPlane { - public: - enum class Type : int32_t { - kDisable, - kLayer, - }; - - DrmCompositionPlane() = default; - DrmCompositionPlane(DrmCompositionPlane &&rhs) = default; - DrmCompositionPlane &operator=(DrmCompositionPlane &&other) = default; - DrmCompositionPlane(Type type, DrmPlane *plane, DrmCrtc *crtc) - : type_(type), plane_(plane), crtc_(crtc) { - } - DrmCompositionPlane(Type type, DrmPlane *plane, DrmCrtc *crtc, - size_t source_layer) - : type_(type), - plane_(plane), - crtc_(crtc), - source_layers_(1, source_layer) { - } - - Type type() const { - return type_; - } - - DrmPlane *plane() const { - return plane_; - } - void set_plane(DrmPlane *plane) { - plane_ = plane; - } - - DrmCrtc *crtc() const { - return crtc_; - } - - std::vector &source_layers() { - return source_layers_; - } - - const std::vector &source_layers() const { - return source_layers_; - } - - private: - Type type_ = Type::kDisable; - DrmPlane *plane_ = NULL; - DrmCrtc *crtc_ = NULL; - std::vector source_layers_; -}; - -class DrmDisplayComposition { - public: - DrmDisplayComposition() = default; - DrmDisplayComposition(const DrmDisplayComposition &) = delete; - ~DrmDisplayComposition(); - - int Init(DrmDevice *drm, DrmCrtc *crtc, Importer *importer, Planner *planner, - uint64_t frame_no); - - int SetLayers(DrmHwcLayer *layers, size_t num_layers, bool geometry_changed); - int AddPlaneComposition(DrmCompositionPlane plane); - int AddPlaneDisable(DrmPlane *plane); - int SetDpmsMode(uint32_t dpms_mode); - int SetDisplayMode(const DrmMode &display_mode); - - int Plan(std::vector *primary_planes, - std::vector *overlay_planes); - - std::vector &layers() { - return layers_; - } - - std::vector &composition_planes() { - return composition_planes_; - } - - bool geometry_changed() const { - return geometry_changed_; - } - - uint64_t frame_no() const { - return frame_no_; - } - - DrmCompositionType type() const { - return type_; - } - - uint32_t dpms_mode() const { - return dpms_mode_; - } - - const DrmMode &display_mode() const { - return display_mode_; - } - - DrmCrtc *crtc() const { - return crtc_; - } - - Importer *importer() const { - return importer_; - } - - Planner *planner() const { - return planner_; - } - - int take_out_fence() { - return out_fence_.Release(); - } - - void set_out_fence(int out_fence) { - out_fence_.Set(out_fence); - } - - void Dump(std::ostringstream *out) const; - - private: - bool validate_composition_type(DrmCompositionType desired); - - DrmDevice *drm_ = NULL; - DrmCrtc *crtc_ = NULL; - Importer *importer_ = NULL; - Planner *planner_ = NULL; - - DrmCompositionType type_ = DRM_COMPOSITION_TYPE_EMPTY; - uint32_t dpms_mode_ = DRM_MODE_DPMS_ON; - DrmMode display_mode_; - - UniqueFd out_fence_ = -1; - - bool geometry_changed_; - std::vector layers_; - std::vector composition_planes_; - - uint64_t frame_no_ = 0; -}; -} // namespace android - -#endif // ANDROID_DRM_DISPLAY_COMPOSITION_H_ diff --git a/include/drmdisplaycompositor.h b/include/drmdisplaycompositor.h deleted file mode 100644 index 26e2572..0000000 --- a/include/drmdisplaycompositor.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_DISPLAY_COMPOSITOR_H_ -#define ANDROID_DRM_DISPLAY_COMPOSITOR_H_ - -#include "drmdisplaycomposition.h" -#include "drmframebuffer.h" -#include "drmhwcomposer.h" -#include "resourcemanager.h" -#include "vsyncworker.h" - -#include -#include -#include -#include - -#include -#include - -// One for the front, one for the back, and one for cases where we need to -// squash a frame that the hw can't display with hw overlays. -#define DRM_DISPLAY_BUFFERS 3 - -// If a scene is still for this number of vblanks flatten it to reduce power -// consumption. -#define FLATTEN_COUNTDOWN_INIT 60 - -namespace android { - -enum class FlatteningState { - kNone, - kNotNeeded, - kClientRequested, - kClientDone, - kSerial, - kConcurrent -}; - -std::ostream &operator<<(std::ostream &str, FlatteningState state); - -class DrmDisplayCompositor { - public: - DrmDisplayCompositor(); - ~DrmDisplayCompositor(); - - int Init(ResourceManager *resource_manager, int display); - - template - void SetRefreshCallback(Fn &&refresh_cb) { - refresh_display_cb_ = std::forward(refresh_cb); - } - - std::unique_ptr CreateComposition() const; - std::unique_ptr CreateInitializedComposition() const; - int ApplyComposition(std::unique_ptr composition); - int TestComposition(DrmDisplayComposition *composition); - int Composite(); - void Dump(std::ostringstream *out) const; - void Vsync(int display, int64_t timestamp); - void ClearDisplay(); - int TakeOutFence() { - if (!active_composition_) - return -1; - return active_composition_->take_out_fence(); - } - - FlatteningState GetFlatteningState() const; - uint32_t GetFlattenedFramesCount() const; - bool ShouldFlattenOnClient() const; - - std::tuple GetActiveModeResolution(); - - private: - struct ModeState { - bool needs_modeset = false; - DrmMode mode; - uint32_t blob_id = 0; - uint32_t old_blob_id = 0; - }; - - DrmDisplayCompositor(const DrmDisplayCompositor &) = delete; - - // We'll wait for acquire fences to fire for kAcquireWaitTimeoutMs, - // kAcquireWaitTries times, logging a warning in between. - static const int kAcquireWaitTries = 5; - static const int kAcquireWaitTimeoutMs = 100; - - int CommitFrame(DrmDisplayComposition *display_comp, bool test_only, - DrmConnector *writeback_conn = NULL, - DrmHwcBuffer *writeback_buffer = NULL); - int SetupWritebackCommit(drmModeAtomicReqPtr pset, uint32_t crtc_id, - DrmConnector *writeback_conn, - DrmHwcBuffer *writeback_buffer); - int ApplyDpms(DrmDisplayComposition *display_comp); - int DisablePlanes(DrmDisplayComposition *display_comp); - - void ApplyFrame(std::unique_ptr composition, - int status, bool writeback = false); - - void SetFlattening(FlatteningState new_state); - bool IsFlatteningNeeded() const; - int FlattenActiveComposition(); - int FlattenOnClient(); - int FlattenSerial(DrmConnector *writeback_conn); - int FlattenConcurrent(DrmConnector *writeback_conn); - int FlattenOnDisplay(std::unique_ptr &src, - DrmConnector *writeback_conn, DrmMode &src_mode, - DrmHwcLayer *writeback_layer); - - bool CountdownExpired() const; - - std::tuple CreateModeBlob(const DrmMode &mode); - - ResourceManager *resource_manager_; - int display_; - - std::unique_ptr active_composition_; - - bool initialized_; - bool active_; - bool use_hw_overlays_; - - ModeState mode_; - - int framebuffer_index_; - DrmFramebuffer framebuffers_[DRM_DISPLAY_BUFFERS]; - - // mutable since we need to acquire in Dump() - mutable pthread_mutex_t lock_; - - // State tracking progress since our last Dump(). These are mutable since - // we need to reset them on every Dump() call. - mutable uint64_t dump_frames_composited_; - mutable uint64_t dump_last_timestamp_ns_; - VSyncWorker vsync_worker_; - int64_t flatten_countdown_; - std::unique_ptr planner_; - int writeback_fence_; - - FlatteningState flattening_state_; - uint32_t frames_flattened_; - - std::function refresh_display_cb_; -}; -} // namespace android - -#endif // ANDROID_DRM_DISPLAY_COMPOSITOR_H_ diff --git a/include/drmencoder.h b/include/drmencoder.h deleted file mode 100644 index 8a7f682..0000000 --- a/include/drmencoder.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_ENCODER_H_ -#define ANDROID_DRM_ENCODER_H_ - -#include "drmcrtc.h" - -#include -#include -#include -#include - -namespace android { - -class DrmEncoder { - public: - DrmEncoder(drmModeEncoderPtr e, DrmCrtc *current_crtc, - const std::vector &possible_crtcs); - DrmEncoder(const DrmEncoder &) = delete; - DrmEncoder &operator=(const DrmEncoder &) = delete; - - uint32_t id() const; - - DrmCrtc *crtc() const; - void set_crtc(DrmCrtc *crtc); - bool can_bind(int display) const; - int display() const; - - const std::vector &possible_crtcs() const { - return possible_crtcs_; - } - bool CanClone(DrmEncoder *encoder); - void AddPossibleClone(DrmEncoder *possible_clone); - - private: - uint32_t id_; - DrmCrtc *crtc_; - int display_; - - std::vector possible_crtcs_; - std::set possible_clones_; -}; -} // namespace android - -#endif // ANDROID_DRM_ENCODER_H_ diff --git a/include/drmeventlistener.h b/include/drmeventlistener.h deleted file mode 100644 index 95672ee..0000000 --- a/include/drmeventlistener.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_DRM_EVENT_LISTENER_H_ -#define ANDROID_DRM_EVENT_LISTENER_H_ - -#include "autofd.h" -#include "worker.h" - -namespace android { - -class DrmDevice; - -class DrmEventHandler { - public: - DrmEventHandler() { - } - virtual ~DrmEventHandler() { - } - - virtual void HandleEvent(uint64_t timestamp_us) = 0; -}; - -class DrmEventListener : public Worker { - public: - DrmEventListener(DrmDevice *drm); - virtual ~DrmEventListener() { - } - - int Init(); - - void RegisterHotplugHandler(DrmEventHandler *handler); - - static void FlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, - unsigned int tv_usec, void *user_data); - - protected: - virtual void Routine(); - - private: - void UEventHandler(); - - fd_set fds_; - UniqueFd uevent_fd_; - int max_fd_ = -1; - - DrmDevice *drm_; - std::unique_ptr hotplug_handler_; -}; -} // namespace android - -#endif diff --git a/include/drmhwctwo.h b/include/drmhwctwo.h deleted file mode 100644 index 8b1be4b..0000000 --- a/include/drmhwctwo.h +++ /dev/null @@ -1,431 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_DRM_HWC_TWO_H_ -#define ANDROID_DRM_HWC_TWO_H_ - -#include "drmdisplaycompositor.h" -#include "drmhwcomposer.h" -#include "platform.h" -#include "resourcemanager.h" -#include "vsyncworker.h" - -#include - -#include -#include -#include - -namespace android { - -class Backend; - -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(); - - 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_); - } - - hwc_rect_t display_frame() { - return display_frame_; - } - - void PopulateDrmLayer(DrmHwcLayer *layer); - - bool RequireScalingOrPhasing() { - float src_width = source_crop_.right - source_crop_.left; - float src_height = source_crop_.bottom - source_crop_.top; - - float dest_width = display_frame_.right - display_frame_.left; - float dest_height = display_frame_.bottom - display_frame_.top; - - bool scaling = src_width != dest_width || src_height != dest_height; - bool phasing = (source_crop_.left - floor(source_crop_.left) != 0) || - (source_crop_.top - floor(source_crop_.top) != 0); - return scaling || phasing; - } - - // 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_ = NULL; - 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_; - hwc_color_t layer_color_; - 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(ResourceManager *resource_manager, DrmDevice *drm, - std::shared_ptr importer, hwc2_display_t handle, - HWC2::DisplayType type); - HwcDisplay(const HwcDisplay &) = delete; - HWC2::Error Init(std::vector *planes); - - HWC2::Error RegisterVsyncCallback(hwc2_callback_data_t data, - hwc2_function_pointer_t func); - void RegisterRefreshCallback(hwc2_callback_data_t data, - hwc2_function_pointer_t func); - HWC2::Error CreateComposition(bool test); - bool HardwareSupportsLayerType(HWC2::Composition comp_type); - uint32_t CalcPixOps(std::map &z_map, - size_t first_z, size_t size); - void MarkValidated(std::map &z_map, - size_t client_first_z, size_t client_size); - - void ClearDisplay(); - - std::string Dump(); - - // HWC Hooks - HWC2::Error AcceptDisplayChanges(); - HWC2::Error CreateLayer(hwc2_layer_t *layer); - HWC2::Error DestroyLayer(hwc2_layer_t layer); - HWC2::Error GetActiveConfig(hwc2_config_t *config); - HWC2::Error GetChangedCompositionTypes(uint32_t *num_elements, - hwc2_layer_t *layers, - int32_t *types); - HWC2::Error GetClientTargetSupport(uint32_t width, uint32_t height, - int32_t format, int32_t dataspace); - HWC2::Error GetColorModes(uint32_t *num_modes, int32_t *modes); - HWC2::Error GetDisplayAttribute(hwc2_config_t config, int32_t attribute, - int32_t *value); - HWC2::Error GetDisplayConfigs(uint32_t *num_configs, - hwc2_config_t *configs); - HWC2::Error GetDisplayName(uint32_t *size, char *name); - HWC2::Error GetDisplayRequests(int32_t *display_requests, - uint32_t *num_elements, hwc2_layer_t *layers, - int32_t *layer_requests); - HWC2::Error GetDisplayType(int32_t *type); -#if PLATFORM_SDK_VERSION > 27 - HWC2::Error GetRenderIntents(int32_t mode, uint32_t *outNumIntents, - int32_t *outIntents); - HWC2::Error SetColorModeWithIntent(int32_t mode, int32_t intent); -#endif -#if PLATFORM_SDK_VERSION > 28 - HWC2::Error GetDisplayIdentificationData(uint8_t *outPort, - uint32_t *outDataSize, - uint8_t *outData); - HWC2::Error GetDisplayCapabilities(uint32_t *outNumCapabilities, - uint32_t *outCapabilities); - HWC2::Error GetDisplayBrightnessSupport(bool *supported); - HWC2::Error SetDisplayBrightness(float); -#endif - HWC2::Error GetDozeSupport(int32_t *support); - HWC2::Error GetHdrCapabilities(uint32_t *num_types, int32_t *types, - float *max_luminance, - float *max_average_luminance, - float *min_luminance); - HWC2::Error GetReleaseFences(uint32_t *num_elements, hwc2_layer_t *layers, - int32_t *fences); - HWC2::Error PresentDisplay(int32_t *present_fence); - HWC2::Error SetActiveConfig(hwc2_config_t config); - HWC2::Error ChosePreferredConfig(); - HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence, - int32_t dataspace, hwc_region_t damage); - HWC2::Error SetColorMode(int32_t mode); - HWC2::Error SetColorTransform(const float *matrix, int32_t hint); - HWC2::Error SetOutputBuffer(buffer_handle_t buffer, int32_t release_fence); - HWC2::Error SetPowerMode(int32_t mode); - HWC2::Error SetVsyncEnabled(int32_t enabled); - HWC2::Error ValidateDisplay(uint32_t *num_types, uint32_t *num_requests); - HwcLayer *get_layer(hwc2_layer_t layer) { - auto it = layers_.find(layer); - if (it == layers_.end()) - return nullptr; - return &it->second; - } - - /* Statistics */ - struct Stats { - Stats minus(Stats b) { - return {total_frames_ - b.total_frames_, - total_pixops_ - b.total_pixops_, - gpu_pixops_ - b.gpu_pixops_, - failed_kms_validate_ - b.failed_kms_validate_, - failed_kms_present_ - b.failed_kms_present_, - frames_flattened_ - b.frames_flattened_}; - } - - uint32_t total_frames_ = 0; - uint64_t total_pixops_ = 0; - uint64_t gpu_pixops_ = 0; - uint32_t failed_kms_validate_ = 0; - uint32_t failed_kms_present_ = 0; - uint32_t frames_flattened_ = 0; - }; - - const Backend *backend() const { - return backend_.get(); - } - void set_backend(std::unique_ptr backend) { - backend_ = std::move(backend); - } - - const std::vector &primary_planes() const { - return primary_planes_; - } - - const std::vector &overlay_planes() const { - return overlay_planes_; - } - - std::map &layers() { - return layers_; - } - - const DrmDisplayCompositor &compositor() const { - return compositor_; - } - - const DrmDevice *drm() const { - return drm_; - } - - const DrmConnector *connector() const { - return connector_; - } - - const std::shared_ptr &importer() const { - return importer_; - } - - ResourceManager *resource_manager() const { - return resource_manager_; - } - - android_color_transform_t &color_transform_hint() { - return color_transform_hint_; - } - - Stats &total_stats() { - return total_stats_; - } - - private: - void AddFenceToPresentFence(int fd); - - constexpr static size_t MATRIX_SIZE = 16; - - ResourceManager *resource_manager_; - DrmDevice *drm_; - DrmDisplayCompositor compositor_; - std::shared_ptr importer_; - std::unique_ptr planner_; - - std::vector primary_planes_; - std::vector overlay_planes_; - - std::unique_ptr backend_; - - VSyncWorker vsync_worker_; - DrmConnector *connector_ = NULL; - DrmCrtc *crtc_ = NULL; - hwc2_display_t handle_; - HWC2::DisplayType type_; - uint32_t layer_idx_ = 0; - std::map layers_; - HwcLayer client_layer_; - UniqueFd present_fence_; - int32_t color_mode_; - std::array color_transform_matrix_; - android_color_transform_t color_transform_hint_; - - uint32_t frame_no_ = 0; - Stats total_stats_; - Stats prev_stats_; - std::string DumpDelta(DrmHwcTwo::HwcDisplay::Stats delta); - }; - - class DrmHotplugHandler : public DrmEventHandler { - public: - DrmHotplugHandler(DrmHwcTwo *hwc2, DrmDevice *drm) - : hwc2_(hwc2), drm_(drm) { - } - void HandleEvent(uint64_t timestamp_us); - - private: - DrmHwcTwo *hwc2_; - DrmDevice *drm_; - }; - - private: - static DrmHwcTwo *toDrmHwcTwo(hwc2_device_t *dev) { - return static_cast(dev); - } - - template - static hwc2_function_pointer_t ToHook(T function) { - static_assert(std::is_same::value, "Incompatible fn pointer"); - return reinterpret_cast(function); - } - - template - static T DeviceHook(hwc2_device_t *dev, Args... args) { - DrmHwcTwo *hwc = toDrmHwcTwo(dev); - return static_cast(((*hwc).*func)(std::forward(args)...)); - } - - static HwcDisplay *GetDisplay(DrmHwcTwo *hwc, hwc2_display_t display_handle) { - auto it = hwc->displays_.find(display_handle); - if (it == hwc->displays_.end()) - return nullptr; - - return &it->second; - } - - template - static int32_t DisplayHook(hwc2_device_t *dev, hwc2_display_t display_handle, - Args... args) { - HwcDisplay *display = GetDisplay(toDrmHwcTwo(dev), display_handle); - if (!display) - return static_cast(HWC2::Error::BadDisplay); - - return static_cast((display->*func)(std::forward(args)...)); - } - - template - static int32_t LayerHook(hwc2_device_t *dev, hwc2_display_t display_handle, - hwc2_layer_t layer_handle, Args... args) { - HwcDisplay *display = GetDisplay(toDrmHwcTwo(dev), display_handle); - if (!display) - return static_cast(HWC2::Error::BadDisplay); - - HwcLayer *layer = display->get_layer(layer_handle); - if (!layer) - return static_cast(HWC2::Error::BadLayer); - - return static_cast((layer->*func)(std::forward(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 *outSize, char *outBuffer); - uint32_t GetMaxVirtualDisplayCount(); - HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data, - hwc2_function_pointer_t function); - HWC2::Error CreateDisplay(hwc2_display_t displ, HWC2::DisplayType type); - void HandleDisplayHotplug(hwc2_display_t displayid, int state); - void HandleInitialHotplugState(DrmDevice *drmDevice); - - ResourceManager resource_manager_; - std::map displays_; - std::map callbacks_; - - std::string mDumpString; -}; -} // namespace android - -#endif diff --git a/include/drmmode.h b/include/drmmode.h deleted file mode 100644 index 4cc06b1..0000000 --- a/include/drmmode.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_MODE_H_ -#define ANDROID_DRM_MODE_H_ - -#include -#include -#include - -namespace android { - -class DrmMode { - public: - DrmMode() = default; - DrmMode(drmModeModeInfoPtr m); - - bool operator==(const drmModeModeInfo &m) const; - void ToDrmModeModeInfo(drm_mode_modeinfo *m) const; - - uint32_t id() const; - void set_id(uint32_t id); - - uint32_t clock() const; - - uint32_t h_display() const; - uint32_t h_sync_start() const; - uint32_t h_sync_end() const; - uint32_t h_total() const; - uint32_t h_skew() const; - - uint32_t v_display() const; - uint32_t v_sync_start() const; - uint32_t v_sync_end() const; - uint32_t v_total() const; - uint32_t v_scan() const; - float v_refresh() const; - - uint32_t flags() const; - uint32_t type() const; - - std::string name() const; - - private: - uint32_t id_ = 0; - - uint32_t clock_ = 0; - - uint32_t h_display_ = 0; - uint32_t h_sync_start_ = 0; - uint32_t h_sync_end_ = 0; - uint32_t h_total_ = 0; - uint32_t h_skew_ = 0; - - uint32_t v_display_ = 0; - uint32_t v_sync_start_ = 0; - uint32_t v_sync_end_ = 0; - uint32_t v_total_ = 0; - uint32_t v_scan_ = 0; - uint32_t v_refresh_ = 0; - - uint32_t flags_ = 0; - uint32_t type_ = 0; - - std::string name_; -}; -} // namespace android - -#endif // ANDROID_DRM_MODE_H_ diff --git a/include/drmplane.h b/include/drmplane.h deleted file mode 100644 index 43e0e8a..0000000 --- a/include/drmplane.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_PLANE_H_ -#define ANDROID_DRM_PLANE_H_ - -#include "drmcrtc.h" -#include "drmproperty.h" - -#include -#include -#include - -namespace android { - -class DrmDevice; - -class DrmPlane { - public: - DrmPlane(DrmDevice *drm, drmModePlanePtr p); - DrmPlane(const DrmPlane &) = delete; - DrmPlane &operator=(const DrmPlane &) = delete; - - int Init(); - - uint32_t id() const; - - bool GetCrtcSupported(const DrmCrtc &crtc) const; - - uint32_t type() const; - - const DrmProperty &crtc_property() const; - const DrmProperty &fb_property() const; - const DrmProperty &crtc_x_property() const; - const DrmProperty &crtc_y_property() const; - const DrmProperty &crtc_w_property() const; - const DrmProperty &crtc_h_property() const; - const DrmProperty &src_x_property() const; - const DrmProperty &src_y_property() const; - const DrmProperty &src_w_property() const; - const DrmProperty &src_h_property() const; - const DrmProperty &zpos_property() const; - const DrmProperty &rotation_property() const; - const DrmProperty &alpha_property() const; - const DrmProperty &blend_property() const; - const DrmProperty &in_fence_fd_property() const; - - private: - DrmDevice *drm_; - uint32_t id_; - - uint32_t possible_crtc_mask_; - - uint32_t type_; - - DrmProperty crtc_property_; - DrmProperty fb_property_; - DrmProperty crtc_x_property_; - DrmProperty crtc_y_property_; - DrmProperty crtc_w_property_; - DrmProperty crtc_h_property_; - DrmProperty src_x_property_; - DrmProperty src_y_property_; - DrmProperty src_w_property_; - DrmProperty src_h_property_; - DrmProperty zpos_property_; - DrmProperty rotation_property_; - DrmProperty alpha_property_; - DrmProperty blend_property_; - DrmProperty in_fence_fd_property_; -}; -} // namespace android - -#endif // ANDROID_DRM_PLANE_H_ diff --git a/include/drmproperty.h b/include/drmproperty.h deleted file mode 100644 index 2d92ca1..0000000 --- a/include/drmproperty.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_PROPERTY_H_ -#define ANDROID_DRM_PROPERTY_H_ - -#include -#include -#include -#include - -namespace android { - -enum DrmPropertyType { - DRM_PROPERTY_TYPE_INT, - DRM_PROPERTY_TYPE_ENUM, - DRM_PROPERTY_TYPE_OBJECT, - DRM_PROPERTY_TYPE_BLOB, - DRM_PROPERTY_TYPE_INVALID, -}; - -class DrmProperty { - public: - DrmProperty() = default; - DrmProperty(drmModePropertyPtr p, uint64_t value); - DrmProperty(const DrmProperty &) = delete; - DrmProperty &operator=(const DrmProperty &) = delete; - - void Init(drmModePropertyPtr p, uint64_t value); - std::tuple GetEnumValueWithName(std::string name) const; - - uint32_t id() const; - std::string name() const; - - std::tuple value() const; - bool is_immutable() const; - - bool is_range() const; - std::tuple range_min() const; - std::tuple range_max() const; - - private: - class DrmPropertyEnum { - public: - DrmPropertyEnum(drm_mode_property_enum *e); - ~DrmPropertyEnum(); - - uint64_t value_; - std::string name_; - }; - - uint32_t id_ = 0; - - DrmPropertyType type_ = DRM_PROPERTY_TYPE_INVALID; - uint32_t flags_ = 0; - std::string name_; - uint64_t value_ = 0; - - std::vector values_; - std::vector enums_; - std::vector blob_ids_; -}; -} // namespace android - -#endif // ANDROID_DRM_PROPERTY_H_ diff --git a/include/platform.h b/include/platform.h deleted file mode 100644 index 6775e29..0000000 --- a/include/platform.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_PLATFORM_H_ -#define ANDROID_DRM_PLATFORM_H_ - -#include "drmdisplaycomposition.h" -#include "drmhwcomposer.h" - -#include -#include - -#include -#include - -namespace android { - -class DrmDevice; - -class Importer { - public: - virtual ~Importer() { - } - - // Creates a platform-specific importer instance - static Importer *CreateInstance(DrmDevice *drm); - - // Imports the buffer referred to by handle into bo. - // - // Note: This can be called from a different thread than ReleaseBuffer. The - // implementation is responsible for ensuring thread safety. - virtual int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) = 0; - - // Releases the buffer object (ie: does the inverse of ImportBuffer) - // - // Note: This can be called from a different thread than ImportBuffer. The - // implementation is responsible for ensuring thread safety. - virtual int ReleaseBuffer(hwc_drm_bo_t *bo) = 0; - - // Checks if importer can import the buffer. - virtual bool CanImportBuffer(buffer_handle_t handle) = 0; - - // Convert platform-dependent buffer format to drm_hwc internal format. - virtual int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) = 0; -}; - -class Planner { - public: - class PlanStage { - public: - virtual ~PlanStage() { - } - - virtual int ProvisionPlanes(std::vector *composition, - std::map &layers, - DrmCrtc *crtc, - std::vector *planes) = 0; - - protected: - // Removes and returns the next available plane from planes - static DrmPlane *PopPlane(std::vector *planes) { - if (planes->empty()) - return NULL; - DrmPlane *plane = planes->front(); - planes->erase(planes->begin()); - return plane; - } - - static int ValidatePlane(DrmPlane *plane, DrmHwcLayer *layer); - - // Inserts the given layer:plane in the composition at the back - static int Emplace(std::vector *composition, - std::vector *planes, - DrmCompositionPlane::Type type, DrmCrtc *crtc, - std::pair layer) { - DrmPlane *plane = PopPlane(planes); - std::vector unused_planes; - int ret = -ENOENT; - while (plane) { - ret = ValidatePlane(plane, layer.second); - if (!ret) - break; - if (!plane->zpos_property().is_immutable()) - unused_planes.push_back(plane); - plane = PopPlane(planes); - } - - if (!ret) { - composition->emplace_back(type, plane, crtc, layer.first); - planes->insert(planes->begin(), unused_planes.begin(), - unused_planes.end()); - } - - return ret; - } - }; - - // Creates a planner instance with platform-specific planning stages - static std::unique_ptr CreateInstance(DrmDevice *drm); - - // Takes a stack of layers and provisions hardware planes for them. If the - // entire stack can't fit in hardware, FIXME - // - // @layers: a map of index:layer of layers to composite - // @primary_planes: a vector of primary planes available for this frame - // @overlay_planes: a vector of overlay planes available for this frame - // - // Returns: A tuple with the status of the operation (0 for success) and - // a vector of the resulting plan (ie: layer->plane mapping). - std::tuple> ProvisionPlanes( - std::map &layers, DrmCrtc *crtc, - std::vector *primary_planes, - std::vector *overlay_planes); - - template - void AddStage(A &&... args) { - stages_.emplace_back( - std::unique_ptr(new T(std::forward(args)...))); - } - - private: - std::vector GetUsablePlanes( - DrmCrtc *crtc, std::vector *primary_planes, - std::vector *overlay_planes); - - std::vector> stages_; -}; - -// This plan stage extracts all protected layers and places them on dedicated -// planes. -class PlanStageProtected : public Planner::PlanStage { - public: - int ProvisionPlanes(std::vector *composition, - std::map &layers, DrmCrtc *crtc, - std::vector *planes); -}; - -// This plan stage places as many layers on dedicated planes as possible (first -// come first serve), and then sticks the rest in a precomposition plane (if -// needed). -class PlanStageGreedy : public Planner::PlanStage { - public: - int ProvisionPlanes(std::vector *composition, - std::map &layers, DrmCrtc *crtc, - std::vector *planes); -}; -} // namespace android -#endif diff --git a/include/resourcemanager.h b/include/resourcemanager.h deleted file mode 100644 index 9fefb46..0000000 --- a/include/resourcemanager.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef RESOURCEMANAGER_H -#define RESOURCEMANAGER_H - -#include "drmdevice.h" -#include "platform.h" - -#include - -namespace android { - -class ResourceManager { - public: - ResourceManager(); - ResourceManager(const ResourceManager &) = delete; - ResourceManager &operator=(const ResourceManager &) = delete; - int Init(); - DrmDevice *GetDrmDevice(int display); - std::shared_ptr GetImporter(int display); - const gralloc_module_t *gralloc(); - DrmConnector *AvailableWritebackConnector(int display); - const std::vector> &getDrmDevices() const { - return drms_; - } - int getDisplayCount() const { - return num_displays_; - } - bool ForcedScalingWithGpu() { - return scale_with_gpu_; - } - - private: - int AddDrmDevice(std::string path); - static bool IsKMSDev(const char *path); - - int num_displays_; - std::vector> drms_; - std::vector> importers_; - const gralloc_module_t *gralloc_; - - bool scale_with_gpu_; -}; -} // namespace android - -#endif // RESOURCEMANAGER_H diff --git a/include/vsyncworker.h b/include/vsyncworker.h deleted file mode 100644 index 96f7432..0000000 --- a/include/vsyncworker.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_EVENT_WORKER_H_ -#define ANDROID_EVENT_WORKER_H_ - -#include "drmdevice.h" -#include "worker.h" - -#include -#include - -#include -#include - -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(DrmDevice *drm, int display); - void RegisterCallback(std::shared_ptr callback); - - void VSyncControl(bool enabled); - - protected: - void Routine() override; - - private: - int64_t GetPhasedVSync(int64_t frame_ns, int64_t current); - int SyntheticWaitVBlank(int64_t *timestamp); - - DrmDevice *drm_; - - // 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 callback_ = NULL; - - int display_; - std::atomic_bool enabled_; - int64_t last_timestamp_; -}; -} // namespace android - -#endif diff --git a/include/worker.h b/include/worker.h deleted file mode 100644 index 7909038..0000000 --- a/include/worker.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2015-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. - */ - -#ifndef ANDROID_WORKER_H_ -#define ANDROID_WORKER_H_ - -#include -#include -#include - -#include -#include -#include - -namespace android { - -class Worker { - public: - void Lock() { - mutex_.lock(); - } - void Unlock() { - mutex_.unlock(); - } - - void Signal() { - cond_.notify_all(); - } - void Exit(); - - bool initialized() const { - return initialized_; - } - - protected: - Worker(const char *name, int priority); - virtual ~Worker(); - - int InitWorker(); - virtual void Routine() = 0; - - /* - * Must be called with the lock acquired. max_nanoseconds may be negative to - * indicate infinite timeout, otherwise it indicates the maximum time span to - * wait for a signal before returning. - * Returns -EINTR if interrupted by exit request, or -ETIMEDOUT if timed out - */ - int WaitForSignalOrExitLocked(int64_t max_nanoseconds = -1); - - bool should_exit() const { - return exit_; - } - - std::mutex mutex_; - std::condition_variable cond_; - - private: - void InternalRoutine(); - - std::string name_; - int priority_; - - std::unique_ptr thread_; - bool exit_; - bool initialized_; -}; -} // namespace android -#endif diff --git a/platform/platform.cpp b/platform/platform.cpp index b7a47c7..9fb91e7 100644 --- a/platform/platform.cpp +++ b/platform/platform.cpp @@ -17,10 +17,11 @@ #define LOG_TAG "hwc-platform" #include "platform.h" -#include "drmdevice.h" #include +#include "drm/drmdevice.h" + namespace android { std::vector Planner::GetUsablePlanes( diff --git a/platform/platform.h b/platform/platform.h new file mode 100644 index 0000000..e0befdb --- /dev/null +++ b/platform/platform.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_PLATFORM_H_ +#define ANDROID_DRM_PLATFORM_H_ + +#include +#include + +#include +#include + +#include "compositor/drmdisplaycomposition.h" +#include "drmhwcomposer.h" + +namespace android { + +class DrmDevice; + +class Importer { + public: + virtual ~Importer() { + } + + // Creates a platform-specific importer instance + static Importer *CreateInstance(DrmDevice *drm); + + // Imports the buffer referred to by handle into bo. + // + // Note: This can be called from a different thread than ReleaseBuffer. The + // implementation is responsible for ensuring thread safety. + virtual int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) = 0; + + // Releases the buffer object (ie: does the inverse of ImportBuffer) + // + // Note: This can be called from a different thread than ImportBuffer. The + // implementation is responsible for ensuring thread safety. + virtual int ReleaseBuffer(hwc_drm_bo_t *bo) = 0; + + // Checks if importer can import the buffer. + virtual bool CanImportBuffer(buffer_handle_t handle) = 0; + + // Convert platform-dependent buffer format to drm_hwc internal format. + virtual int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) = 0; +}; + +class Planner { + public: + class PlanStage { + public: + virtual ~PlanStage() { + } + + virtual int ProvisionPlanes(std::vector *composition, + std::map &layers, + DrmCrtc *crtc, + std::vector *planes) = 0; + + protected: + // Removes and returns the next available plane from planes + static DrmPlane *PopPlane(std::vector *planes) { + if (planes->empty()) + return NULL; + DrmPlane *plane = planes->front(); + planes->erase(planes->begin()); + return plane; + } + + static int ValidatePlane(DrmPlane *plane, DrmHwcLayer *layer); + + // Inserts the given layer:plane in the composition at the back + static int Emplace(std::vector *composition, + std::vector *planes, + DrmCompositionPlane::Type type, DrmCrtc *crtc, + std::pair layer) { + DrmPlane *plane = PopPlane(planes); + std::vector unused_planes; + int ret = -ENOENT; + while (plane) { + ret = ValidatePlane(plane, layer.second); + if (!ret) + break; + if (!plane->zpos_property().is_immutable()) + unused_planes.push_back(plane); + plane = PopPlane(planes); + } + + if (!ret) { + composition->emplace_back(type, plane, crtc, layer.first); + planes->insert(planes->begin(), unused_planes.begin(), + unused_planes.end()); + } + + return ret; + } + }; + + // Creates a planner instance with platform-specific planning stages + static std::unique_ptr CreateInstance(DrmDevice *drm); + + // Takes a stack of layers and provisions hardware planes for them. If the + // entire stack can't fit in hardware, FIXME + // + // @layers: a map of index:layer of layers to composite + // @primary_planes: a vector of primary planes available for this frame + // @overlay_planes: a vector of overlay planes available for this frame + // + // Returns: A tuple with the status of the operation (0 for success) and + // a vector of the resulting plan (ie: layer->plane mapping). + std::tuple> ProvisionPlanes( + std::map &layers, DrmCrtc *crtc, + std::vector *primary_planes, + std::vector *overlay_planes); + + template + void AddStage(A &&... args) { + stages_.emplace_back( + std::unique_ptr(new T(std::forward(args)...))); + } + + private: + std::vector GetUsablePlanes( + DrmCrtc *crtc, std::vector *primary_planes, + std::vector *overlay_planes); + + std::vector> stages_; +}; + +// This plan stage extracts all protected layers and places them on dedicated +// planes. +class PlanStageProtected : public Planner::PlanStage { + public: + int ProvisionPlanes(std::vector *composition, + std::map &layers, DrmCrtc *crtc, + std::vector *planes); +}; + +// This plan stage places as many layers on dedicated planes as possible (first +// come first serve), and then sticks the rest in a precomposition plane (if +// needed). +class PlanStageGreedy : public Planner::PlanStage { + public: + int ProvisionPlanes(std::vector *composition, + std::map &layers, DrmCrtc *crtc, + std::vector *planes); +}; +} // namespace android +#endif diff --git a/platform/platformdrmgeneric.cpp b/platform/platformdrmgeneric.cpp index b9dafb3..d903031 100644 --- a/platform/platformdrmgeneric.cpp +++ b/platform/platformdrmgeneric.cpp @@ -17,8 +17,6 @@ #define LOG_TAG "hwc-platform-drm-generic" #include "platformdrmgeneric.h" -#include "drmdevice.h" -#include "platform.h" #include #include diff --git a/platform/platformdrmgeneric.h b/platform/platformdrmgeneric.h index ad74de4..4284093 100644 --- a/platform/platformdrmgeneric.h +++ b/platform/platformdrmgeneric.h @@ -17,13 +17,13 @@ #ifndef ANDROID_PLATFORM_DRM_GENERIC_H_ #define ANDROID_PLATFORM_DRM_GENERIC_H_ -#include "drmdevice.h" -#include "platform.h" - +#include #include + #include -#include +#include "drm/drmdevice.h" +#include "platform.h" #ifndef DRM_FORMAT_INVALID #define DRM_FORMAT_INVALID 0 diff --git a/platform/platformhisi.cpp b/platform/platformhisi.cpp index 1f1478f..8c10e34 100644 --- a/platform/platformhisi.cpp +++ b/platform/platformhisi.cpp @@ -17,15 +17,11 @@ #define LOG_TAG "hwc-platform-hisi" #include "platformhisi.h" -#include "drmdevice.h" -#include "platform.h" -#include #include #include #include -#include #include #include "gralloc_priv.h" diff --git a/platform/platformhisi.h b/platform/platformhisi.h index f127bdb..272e547 100644 --- a/platform/platformhisi.h +++ b/platform/platformhisi.h @@ -17,7 +17,6 @@ #ifndef ANDROID_PLATFORM_HISI_H_ #define ANDROID_PLATFORM_HISI_H_ -#include "drmdevice.h" #include "platform.h" #include "platformdrmgeneric.h" diff --git a/platform/platformimagination.cpp b/platform/platformimagination.cpp index bd4a4c3..83cebf3 100644 --- a/platform/platformimagination.cpp +++ b/platform/platformimagination.cpp @@ -1,6 +1,7 @@ #define LOG_TAG "hwc-platform-imagination" #include "platformimagination.h" + #include #include diff --git a/platform/platformimagination.h b/platform/platformimagination.h index f2a7cb7..4eec698 100644 --- a/platform/platformimagination.h +++ b/platform/platformimagination.h @@ -1,7 +1,6 @@ #ifndef PLATFORMIMAGINATION_H #define PLATFORMIMAGINATION_H -#include "drmdevice.h" #include "platform.h" #include "platformdrmgeneric.h" diff --git a/platform/platformmeson.cpp b/platform/platformmeson.cpp index ad3aff1..ecace29 100644 --- a/platform/platformmeson.cpp +++ b/platform/platformmeson.cpp @@ -17,15 +17,11 @@ #define LOG_TAG "hwc-platform-meson" #include "platformmeson.h" -#include "drmdevice.h" -#include "platform.h" -#include #include #include #include -#include #include #include "gralloc_priv.h" diff --git a/platform/platformmeson.h b/platform/platformmeson.h index f29b796..1b428a4 100644 --- a/platform/platformmeson.h +++ b/platform/platformmeson.h @@ -17,7 +17,6 @@ #ifndef ANDROID_PLATFORM_HISI_H_ #define ANDROID_PLATFORM_HISI_H_ -#include "drmdevice.h" #include "platform.h" #include "platformdrmgeneric.h" diff --git a/platform/platformminigbm.cpp b/platform/platformminigbm.cpp index df195d3..39decab 100644 --- a/platform/platformminigbm.cpp +++ b/platform/platformminigbm.cpp @@ -17,13 +17,10 @@ #define LOG_TAG "hwc-platform-drm-minigbm" #include "platformminigbm.h" -#include "drmdevice.h" -#include "platform.h" #include #include -#include #include #include "cros_gralloc_handle.h" diff --git a/platform/platformminigbm.h b/platform/platformminigbm.h index 053b2aa..1eea6ca 100644 --- a/platform/platformminigbm.h +++ b/platform/platformminigbm.h @@ -17,7 +17,6 @@ #ifndef ANDROID_PLATFORM_DRM_MINIGBM_H_ #define ANDROID_PLATFORM_DRM_MINIGBM_H_ -#include "drmdevice.h" #include "platform.h" #include "platformdrmgeneric.h" diff --git a/tests/Android.bp b/tests/Android.bp index 7e550ff..282e71c 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -9,5 +9,8 @@ cc_test { header_libs: ["libhardware_headers"], static_libs: ["libdrmhwc_utils"], shared_libs: ["hwcomposer.drm"], - include_dirs: ["external/drm_hwcomposer/include"], + include_dirs: [ + "external/drm_hwcomposer/include", + "external/drm_hwcomposer", + ], } diff --git a/tests/worker_test.cpp b/tests/worker_test.cpp index 82523f0..ba89b6f 100644 --- a/tests/worker_test.cpp +++ b/tests/worker_test.cpp @@ -1,10 +1,10 @@ +#include "utils/worker.h" + #include #include #include -#include "worker.h" - using android::Worker; struct TestWorker : public Worker { diff --git a/utils/autolock.h b/utils/autolock.h new file mode 100644 index 0000000..006406a --- /dev/null +++ b/utils/autolock.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2015 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 + +namespace android { + +class AutoLock { + public: + AutoLock(pthread_mutex_t *mutex, const char *const name) + : mutex_(mutex), name_(name) { + } + ~AutoLock() { + if (locked_) + Unlock(); + } + + AutoLock(const AutoLock &rhs) = delete; + AutoLock &operator=(const AutoLock &rhs) = delete; + + int Lock(); + int Unlock(); + + private: + pthread_mutex_t *const mutex_; + bool locked_ = false; + const char *const name_; +}; +} // namespace android diff --git a/utils/hwcutils.cpp b/utils/hwcutils.cpp index 324d855..2dc7e7b 100644 --- a/utils/hwcutils.cpp +++ b/utils/hwcutils.cpp @@ -17,12 +17,12 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #define LOG_TAG "hwc-drm-utils" -#include "drmhwcomposer.h" -#include "platform.h" - #include #include +#include "drmhwcomposer.h" +#include "platform/platform.h" + #define UNUSED(x) (void)(x) namespace android { diff --git a/utils/worker.h b/utils/worker.h new file mode 100644 index 0000000..73a80da --- /dev/null +++ b/utils/worker.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2015-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. + */ + +#ifndef ANDROID_WORKER_H_ +#define ANDROID_WORKER_H_ + +#include +#include + +#include +#include +#include +#include + +namespace android { + +class Worker { + public: + void Lock() { + mutex_.lock(); + } + void Unlock() { + mutex_.unlock(); + } + + void Signal() { + cond_.notify_all(); + } + void Exit(); + + bool initialized() const { + return initialized_; + } + + protected: + Worker(const char *name, int priority); + virtual ~Worker(); + + int InitWorker(); + virtual void Routine() = 0; + + /* + * Must be called with the lock acquired. max_nanoseconds may be negative to + * indicate infinite timeout, otherwise it indicates the maximum time span to + * wait for a signal before returning. + * Returns -EINTR if interrupted by exit request, or -ETIMEDOUT if timed out + */ + int WaitForSignalOrExitLocked(int64_t max_nanoseconds = -1); + + bool should_exit() const { + return exit_; + } + + std::mutex mutex_; + std::condition_variable cond_; + + private: + void InternalRoutine(); + + std::string name_; + int priority_; + + std::unique_ptr thread_; + bool exit_; + bool initialized_; +}; +} // namespace android +#endif -- cgit v1.2.3 From 13cc3666c63010a4fc12568d645703bf365ccfc7 Mon Sep 17 00:00:00 2001 From: Roman Stratiienko Date: Sat, 29 Aug 2020 21:35:39 +0300 Subject: drm_hwcomposer: use CamelCase in source/header files related to class Main goal is to increase readability of file names. AOSP uses camelcase for files in many projects. Lets do the same for drm_hwcomposer. Keep platform/ directory as is, since class names is different from file names. Signed-off-by: Roman Stratiienko Change-Id: I7e992357851c2a86711f4da1241c4d507359e56b --- Android.bp | 40 +- DrmHwcTwo.cpp | 1448 ++++++++++++++++++++++++++++++++++ DrmHwcTwo.h | 431 ++++++++++ backend/Backend.cpp | 136 ++++ backend/Backend.h | 38 + backend/BackendClient.cpp | 35 + backend/BackendClient.h | 32 + backend/BackendManager.cpp | 78 ++ backend/BackendManager.h | 57 ++ backend/BackendRCarDu.cpp | 43 + backend/BackendRCarDu.h | 31 + backend/backend.cpp | 135 ---- backend/backend.h | 38 - backend/backendclient.cpp | 34 - backend/backendclient.h | 33 - backend/backendmanager.cpp | 78 -- backend/backendmanager.h | 58 -- backend/backendrcardu.cpp | 42 - backend/backendrcardu.h | 32 - compositor/DrmDisplayComposition.cpp | 297 +++++++ compositor/DrmDisplayComposition.h | 198 +++++ compositor/DrmDisplayCompositor.cpp | 1097 ++++++++++++++++++++++++++ compositor/DrmDisplayCompositor.h | 161 ++++ compositor/drmdisplaycomposition.cpp | 297 ------- compositor/drmdisplaycomposition.h | 198 ----- compositor/drmdisplaycompositor.cpp | 1097 -------------------------- compositor/drmdisplaycompositor.h | 161 ---- drm/DrmConnector.cpp | 233 ++++++ drm/DrmConnector.h | 116 +++ drm/DrmCrtc.cpp | 85 ++ drm/DrmCrtc.h | 65 ++ drm/DrmDevice.cpp | 579 ++++++++++++++ drm/DrmDevice.h | 110 +++ drm/DrmEncoder.cpp | 62 ++ drm/DrmEncoder.h | 60 ++ drm/DrmEventListener.cpp | 138 ++++ drm/DrmEventListener.h | 65 ++ drm/DrmMode.cpp | 137 ++++ drm/DrmMode.h | 83 ++ drm/DrmPlane.cpp | 215 +++++ drm/DrmPlane.h | 88 +++ drm/DrmProperty.cpp | 135 ++++ drm/DrmProperty.h | 79 ++ drm/ResourceManager.cpp | 144 ++++ drm/ResourceManager.h | 60 ++ drm/VSyncWorker.cpp | 187 +++++ drm/VSyncWorker.h | 68 ++ drm/drmconnector.cpp | 233 ------ drm/drmconnector.h | 116 --- drm/drmcrtc.cpp | 85 -- drm/drmcrtc.h | 65 -- drm/drmdevice.cpp | 580 -------------- drm/drmdevice.h | 110 --- drm/drmencoder.cpp | 61 -- drm/drmencoder.h | 60 -- drm/drmeventlistener.cpp | 138 ---- drm/drmeventlistener.h | 65 -- drm/drmmode.cpp | 136 ---- drm/drmmode.h | 83 -- drm/drmplane.cpp | 214 ----- drm/drmplane.h | 88 --- drm/drmproperty.cpp | 134 ---- drm/drmproperty.h | 79 -- drm/resourcemanager.cpp | 143 ---- drm/resourcemanager.h | 60 -- drm/vsyncworker.cpp | 188 ----- drm/vsyncworker.h | 68 -- drmhwctwo.cpp | 1448 ---------------------------------- drmhwctwo.h | 431 ---------- include/DrmFramebuffer.h | 105 +++ include/drmframebuffer.h | 107 --- platform/platform.cpp | 2 +- platform/platform.h | 2 +- platform/platformdrmgeneric.h | 2 +- tests/worker_test.cpp | 2 +- utils/Worker.cpp | 94 +++ utils/Worker.h | 81 ++ utils/worker.cpp | 94 --- utils/worker.h | 81 -- 79 files changed, 7095 insertions(+), 7094 deletions(-) create mode 100644 DrmHwcTwo.cpp create mode 100644 DrmHwcTwo.h create mode 100644 backend/Backend.cpp create mode 100644 backend/Backend.h create mode 100644 backend/BackendClient.cpp create mode 100644 backend/BackendClient.h create mode 100644 backend/BackendManager.cpp create mode 100644 backend/BackendManager.h create mode 100644 backend/BackendRCarDu.cpp create mode 100644 backend/BackendRCarDu.h delete mode 100644 backend/backend.cpp delete mode 100644 backend/backend.h delete mode 100644 backend/backendclient.cpp delete mode 100644 backend/backendclient.h delete mode 100644 backend/backendmanager.cpp delete mode 100644 backend/backendmanager.h delete mode 100644 backend/backendrcardu.cpp delete mode 100644 backend/backendrcardu.h create mode 100644 compositor/DrmDisplayComposition.cpp create mode 100644 compositor/DrmDisplayComposition.h create mode 100644 compositor/DrmDisplayCompositor.cpp create mode 100644 compositor/DrmDisplayCompositor.h delete mode 100644 compositor/drmdisplaycomposition.cpp delete mode 100644 compositor/drmdisplaycomposition.h delete mode 100644 compositor/drmdisplaycompositor.cpp delete mode 100644 compositor/drmdisplaycompositor.h create mode 100644 drm/DrmConnector.cpp create mode 100644 drm/DrmConnector.h create mode 100644 drm/DrmCrtc.cpp create mode 100644 drm/DrmCrtc.h create mode 100644 drm/DrmDevice.cpp create mode 100644 drm/DrmDevice.h create mode 100644 drm/DrmEncoder.cpp create mode 100644 drm/DrmEncoder.h create mode 100644 drm/DrmEventListener.cpp create mode 100644 drm/DrmEventListener.h create mode 100644 drm/DrmMode.cpp create mode 100644 drm/DrmMode.h create mode 100644 drm/DrmPlane.cpp create mode 100644 drm/DrmPlane.h create mode 100644 drm/DrmProperty.cpp create mode 100644 drm/DrmProperty.h create mode 100644 drm/ResourceManager.cpp create mode 100644 drm/ResourceManager.h create mode 100644 drm/VSyncWorker.cpp create mode 100644 drm/VSyncWorker.h delete mode 100644 drm/drmconnector.cpp delete mode 100644 drm/drmconnector.h delete mode 100644 drm/drmcrtc.cpp delete mode 100644 drm/drmcrtc.h delete mode 100644 drm/drmdevice.cpp delete mode 100644 drm/drmdevice.h delete mode 100644 drm/drmencoder.cpp delete mode 100644 drm/drmencoder.h delete mode 100644 drm/drmeventlistener.cpp delete mode 100644 drm/drmeventlistener.h delete mode 100644 drm/drmmode.cpp delete mode 100644 drm/drmmode.h delete mode 100644 drm/drmplane.cpp delete mode 100644 drm/drmplane.h delete mode 100644 drm/drmproperty.cpp delete mode 100644 drm/drmproperty.h delete mode 100644 drm/resourcemanager.cpp delete mode 100644 drm/resourcemanager.h delete mode 100644 drm/vsyncworker.cpp delete mode 100644 drm/vsyncworker.h delete mode 100644 drmhwctwo.cpp delete mode 100644 drmhwctwo.h create mode 100644 include/DrmFramebuffer.h delete mode 100644 include/drmframebuffer.h create mode 100644 utils/Worker.cpp create mode 100644 utils/Worker.h delete mode 100644 utils/worker.cpp delete mode 100644 utils/worker.h diff --git a/Android.bp b/Android.bp index ef8af52..4bd4586 100644 --- a/Android.bp +++ b/Android.bp @@ -18,7 +18,7 @@ cc_library_static { name: "libdrmhwc_utils", - srcs: ["utils/worker.cpp"], + srcs: ["utils/Worker.cpp"], include_dirs: [ "external/drm_hwcomposer/include", @@ -80,31 +80,31 @@ cc_library_static { name: "drm_hwcomposer", defaults: ["hwcomposer.drm_defaults"], srcs: [ - "drmhwctwo.cpp", - - "compositor/drmdisplaycomposition.cpp", - "compositor/drmdisplaycompositor.cpp", - - "drm/drmconnector.cpp", - "drm/drmcrtc.cpp", - "drm/drmdevice.cpp", - "drm/drmencoder.cpp", - "drm/drmeventlistener.cpp", - "drm/drmmode.cpp", - "drm/drmplane.cpp", - "drm/drmproperty.cpp", - "drm/resourcemanager.cpp", - "drm/vsyncworker.cpp", + "DrmHwcTwo.cpp", + + "compositor/DrmDisplayComposition.cpp", + "compositor/DrmDisplayCompositor.cpp", + + "drm/DrmConnector.cpp", + "drm/DrmCrtc.cpp", + "drm/DrmDevice.cpp", + "drm/DrmEncoder.cpp", + "drm/DrmEventListener.cpp", + "drm/DrmMode.cpp", + "drm/DrmPlane.cpp", + "drm/DrmProperty.cpp", + "drm/ResourceManager.cpp", + "drm/VSyncWorker.cpp", "platform/platform.cpp", "utils/autolock.cpp", "utils/hwcutils.cpp", - "backend/backendmanager.cpp", - "backend/backend.cpp", - "backend/backendclient.cpp", - "backend/backendrcardu.cpp", + "backend/BackendManager.cpp", + "backend/Backend.cpp", + "backend/BackendClient.cpp", + "backend/BackendRCarDu.cpp", ], } diff --git a/DrmHwcTwo.cpp b/DrmHwcTwo.cpp new file mode 100644 index 0000000..15fa324 --- /dev/null +++ b/DrmHwcTwo.cpp @@ -0,0 +1,1448 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +#define LOG_TAG "hwc-drm-two" + +#include "DrmHwcTwo.h" + +#include +#include +#include +#include +#include + +#include + +#include "backend/BackendManager.h" +#include "compositor/DrmDisplayComposition.h" + +namespace android { + +class DrmVsyncCallback : public VsyncCallback { + public: + DrmVsyncCallback(hwc2_callback_data_t data, hwc2_function_pointer_t hook) + : data_(data), hook_(hook) { + } + + void Callback(int display, int64_t timestamp) { + auto hook = reinterpret_cast(hook_); + hook(data_, display, timestamp); + } + + private: + hwc2_callback_data_t data_; + hwc2_function_pointer_t hook_; +}; + +DrmHwcTwo::DrmHwcTwo() { + common.tag = HARDWARE_DEVICE_TAG; + common.version = HWC_DEVICE_API_VERSION_2_0; + common.close = HookDevClose; + getCapabilities = HookDevGetCapabilities; + getFunction = HookDevGetFunction; +} + +HWC2::Error DrmHwcTwo::CreateDisplay(hwc2_display_t displ, + HWC2::DisplayType type) { + DrmDevice *drm = resource_manager_.GetDrmDevice(displ); + std::shared_ptr importer = resource_manager_.GetImporter(displ); + if (!drm || !importer) { + ALOGE("Failed to get a valid drmresource and importer"); + return HWC2::Error::NoResources; + } + displays_.emplace(std::piecewise_construct, std::forward_as_tuple(displ), + std::forward_as_tuple(&resource_manager_, drm, importer, + displ, type)); + + DrmCrtc *crtc = drm->GetCrtcForDisplay(static_cast(displ)); + if (!crtc) { + ALOGE("Failed to get crtc for display %d", static_cast(displ)); + return HWC2::Error::BadDisplay; + } + std::vector display_planes; + for (auto &plane : drm->planes()) { + if (plane->GetCrtcSupported(*crtc)) + display_planes.push_back(plane.get()); + } + displays_.at(displ).Init(&display_planes); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::Init() { + int rv = resource_manager_.Init(); + if (rv) { + ALOGE("Can't initialize the resource manager %d", rv); + return HWC2::Error::NoResources; + } + + HWC2::Error ret = HWC2::Error::None; + for (int i = 0; i < resource_manager_.getDisplayCount(); i++) { + ret = CreateDisplay(i, HWC2::DisplayType::Physical); + if (ret != HWC2::Error::None) { + ALOGE("Failed to create display %d with error %d", i, ret); + return ret; + } + } + + auto &drmDevices = resource_manager_.getDrmDevices(); + for (auto &device : drmDevices) { + device->RegisterHotplugHandler(new DrmHotplugHandler(this, device.get())); + } + return ret; +} + +template +static inline HWC2::Error unsupported(char const *func, Args... /*args*/) { + ALOGV("Unsupported function: %s", func); + return HWC2::Error::Unsupported; +} + +static inline void supported(char const *func) { + ALOGV("Supported function: %s", func); +} + +HWC2::Error DrmHwcTwo::CreateVirtualDisplay(uint32_t width, uint32_t height, + int32_t *format, + hwc2_display_t *display) { + // TODO: Implement virtual display + return unsupported(__func__, width, height, format, display); +} + +HWC2::Error DrmHwcTwo::DestroyVirtualDisplay(hwc2_display_t display) { + // TODO: Implement virtual display + return unsupported(__func__, display); +} + +std::string DrmHwcTwo::HwcDisplay::DumpDelta( + DrmHwcTwo::HwcDisplay::Stats delta) { + if (delta.total_pixops_ == 0) + return "No stats yet"; + double Ratio = 1.0 - double(delta.gpu_pixops_) / double(delta.total_pixops_); + + return (std::stringstream() + << " Total frames count: " << delta.total_frames_ << "\n" + << " Failed to test commit frames: " << delta.failed_kms_validate_ + << "\n" + << " Failed to commit frames: " << delta.failed_kms_present_ << "\n" + << ((delta.failed_kms_present_ > 0) + ? " !!! Internal failure, FIX it please\n" + : "") + << " Flattened frames: " << delta.frames_flattened_ << "\n" + << " Pixel operations (free units)" + << " : [TOTAL: " << delta.total_pixops_ + << " / GPU: " << delta.gpu_pixops_ << "]\n" + << " Composition efficiency: " << Ratio) + .str(); +} + +std::string DrmHwcTwo::HwcDisplay::Dump() { + auto out = (std::stringstream() + << "- Display on: " << connector_->name() << "\n" + << " Flattening state: " << compositor_.GetFlatteningState() + << "\n" + << "Statistics since system boot:\n" + << DumpDelta(total_stats_) << "\n\n" + << "Statistics since last dumpsys request:\n" + << DumpDelta(total_stats_.minus(prev_stats_)) << "\n\n") + .str(); + + memcpy(&prev_stats_, &total_stats_, sizeof(Stats)); + return out; +} + +void DrmHwcTwo::Dump(uint32_t *outSize, char *outBuffer) { + supported(__func__); + + if (outBuffer != nullptr) { + auto copiedBytes = mDumpString.copy(outBuffer, *outSize); + *outSize = static_cast(copiedBytes); + return; + } + + std::stringstream output; + + output << "-- drm_hwcomposer --\n\n"; + + for (std::pair &dp : displays_) + output << dp.second.Dump(); + + mDumpString = output.str(); + *outSize = static_cast(mDumpString.size()); +} + +uint32_t DrmHwcTwo::GetMaxVirtualDisplayCount() { + // TODO: Implement virtual display + unsupported(__func__); + return 0; +} + +HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor, + hwc2_callback_data_t data, + hwc2_function_pointer_t function) { + supported(__func__); + auto callback = static_cast(descriptor); + + if (!function) { + callbacks_.erase(callback); + return HWC2::Error::None; + } + + callbacks_.emplace(callback, HwcCallback(data, function)); + + switch (callback) { + case HWC2::Callback::Hotplug: { + auto &drmDevices = resource_manager_.getDrmDevices(); + for (auto &device : drmDevices) + HandleInitialHotplugState(device.get()); + break; + } + case HWC2::Callback::Refresh: { + for (std::pair &d : + displays_) + d.second.RegisterRefreshCallback(data, function); + break; + } + case HWC2::Callback::Vsync: { + for (std::pair &d : + displays_) + d.second.RegisterVsyncCallback(data, function); + break; + } + default: + break; + } + return HWC2::Error::None; +} + +DrmHwcTwo::HwcDisplay::HwcDisplay(ResourceManager *resource_manager, + DrmDevice *drm, + std::shared_ptr importer, + hwc2_display_t handle, HWC2::DisplayType type) + : resource_manager_(resource_manager), + drm_(drm), + importer_(importer), + handle_(handle), + type_(type), + color_transform_hint_(HAL_COLOR_TRANSFORM_IDENTITY) { + supported(__func__); + + // clang-format off + color_transform_matrix_ = {1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0}; + // clang-format on +} + +void DrmHwcTwo::HwcDisplay::ClearDisplay() { + compositor_.ClearDisplay(); +} + +HWC2::Error DrmHwcTwo::HwcDisplay::Init(std::vector *planes) { + supported(__func__); + planner_ = Planner::CreateInstance(drm_); + if (!planner_) { + ALOGE("Failed to create planner instance for composition"); + return HWC2::Error::NoResources; + } + + int display = static_cast(handle_); + int ret = compositor_.Init(resource_manager_, display); + if (ret) { + ALOGE("Failed display compositor init for display %d (%d)", display, ret); + return HWC2::Error::NoResources; + } + + // Split up the given display planes into primary and overlay to properly + // interface with the composition + char use_overlay_planes_prop[PROPERTY_VALUE_MAX]; + property_get("vendor.hwc.drm.use_overlay_planes", use_overlay_planes_prop, + "1"); + bool use_overlay_planes = atoi(use_overlay_planes_prop); + for (auto &plane : *planes) { + if (plane->type() == DRM_PLANE_TYPE_PRIMARY) + primary_planes_.push_back(plane); + else if (use_overlay_planes && (plane)->type() == DRM_PLANE_TYPE_OVERLAY) + overlay_planes_.push_back(plane); + } + + crtc_ = drm_->GetCrtcForDisplay(display); + if (!crtc_) { + ALOGE("Failed to get crtc for display %d", display); + return HWC2::Error::BadDisplay; + } + + connector_ = drm_->GetConnectorForDisplay(display); + if (!connector_) { + ALOGE("Failed to get connector for display %d", display); + return HWC2::Error::BadDisplay; + } + + ret = vsync_worker_.Init(drm_, display); + if (ret) { + ALOGE("Failed to create event worker for d=%d %d\n", display, ret); + return HWC2::Error::BadDisplay; + } + + ret = BackendManager::GetInstance().SetBackendForDisplay(this); + if (ret) { + ALOGE("Failed to set backend for d=%d %d\n", display, ret); + return HWC2::Error::BadDisplay; + } + + return ChosePreferredConfig(); +} + +HWC2::Error DrmHwcTwo::HwcDisplay::ChosePreferredConfig() { + // Fetch the number of modes from the display + uint32_t num_configs; + HWC2::Error err = GetDisplayConfigs(&num_configs, NULL); + if (err != HWC2::Error::None || !num_configs) + return err; + + return SetActiveConfig(connector_->get_preferred_mode_id()); +} + +HWC2::Error DrmHwcTwo::HwcDisplay::RegisterVsyncCallback( + hwc2_callback_data_t data, hwc2_function_pointer_t func) { + supported(__func__); + auto callback = std::make_shared(data, func); + vsync_worker_.RegisterCallback(std::move(callback)); + return HWC2::Error::None; +} + +void DrmHwcTwo::HwcDisplay::RegisterRefreshCallback( + hwc2_callback_data_t data, hwc2_function_pointer_t func) { + supported(__func__); + auto hook = reinterpret_cast(func); + compositor_.SetRefreshCallback([data, hook](int display) { + hook(data, static_cast(display)); + }); +} + +HWC2::Error DrmHwcTwo::HwcDisplay::AcceptDisplayChanges() { + supported(__func__); + for (std::pair &l : layers_) + l.second.accept_type_change(); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::CreateLayer(hwc2_layer_t *layer) { + supported(__func__); + layers_.emplace(static_cast(layer_idx_), HwcLayer()); + *layer = static_cast(layer_idx_); + ++layer_idx_; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::DestroyLayer(hwc2_layer_t layer) { + supported(__func__); + if (!get_layer(layer)) + return HWC2::Error::BadLayer; + + layers_.erase(layer); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetActiveConfig(hwc2_config_t *config) { + supported(__func__); + DrmMode const &mode = connector_->active_mode(); + if (mode.id() == 0) + return HWC2::Error::BadConfig; + + *config = mode.id(); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetChangedCompositionTypes( + uint32_t *num_elements, hwc2_layer_t *layers, int32_t *types) { + supported(__func__); + uint32_t num_changes = 0; + for (std::pair &l : layers_) { + if (l.second.type_changed()) { + if (layers && num_changes < *num_elements) + layers[num_changes] = l.first; + if (types && num_changes < *num_elements) + types[num_changes] = static_cast(l.second.validated_type()); + ++num_changes; + } + } + if (!layers && !types) + *num_elements = num_changes; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetClientTargetSupport(uint32_t width, + uint32_t height, + int32_t /*format*/, + int32_t dataspace) { + supported(__func__); + std::pair min = drm_->min_resolution(); + std::pair max = drm_->max_resolution(); + + if (width < min.first || height < min.second) + return HWC2::Error::Unsupported; + + if (width > max.first || height > max.second) + return HWC2::Error::Unsupported; + + if (dataspace != HAL_DATASPACE_UNKNOWN && + dataspace != HAL_DATASPACE_STANDARD_UNSPECIFIED) + return HWC2::Error::Unsupported; + + // TODO: Validate format can be handled by either GL or planes + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetColorModes(uint32_t *num_modes, + int32_t *modes) { + supported(__func__); + 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(attribute_in); + switch (attribute) { + case HWC2::Attribute::Width: + *value = mode->h_display(); + break; + case HWC2::Attribute::Height: + *value = mode->v_display(); + break; + case HWC2::Attribute::VsyncPeriod: + // in nanoseconds + *value = 1000 * 1000 * 1000 / mode->v_refresh(); + break; + case HWC2::Attribute::DpiX: + // Dots per 1000 inches + *value = mm_width ? (mode->h_display() * kUmPerInch) / mm_width : -1; + break; + case HWC2::Attribute::DpiY: + // Dots per 1000 inches + *value = mm_height ? (mode->v_display() * kUmPerInch) / mm_height : -1; + break; + default: + *value = -1; + return HWC2::Error::BadConfig; + } + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayConfigs(uint32_t *num_configs, + hwc2_config_t *configs) { + supported(__func__); + // Since this callback is normally invoked twice (once to get the count, and + // once to populate configs), we don't really want to read the edid + // redundantly. Instead, only update the modes on the first invocation. While + // it's possible this will result in stale modes, it'll all come out in the + // wash when we try to set the active config later. + if (!configs) { + int ret = connector_->UpdateModes(); + if (ret) { + ALOGE("Failed to update display modes %d", ret); + return HWC2::Error::BadDisplay; + } + } + + // Since the upper layers only look at vactive/hactive/refresh, height and + // width, it doesn't differentiate interlaced from progressive and other + // similar modes. Depending on the order of modes we return to SF, it could + // end up choosing a suboptimal configuration and dropping the preferred + // mode. To workaround this, don't offer interlaced modes to SF if there is + // at least one non-interlaced alternative and only offer a single WxH@R + // mode with at least the prefered mode from in DrmConnector::UpdateModes() + + // TODO: Remove the following block of code until AOSP handles all modes + std::vector sel_modes; + + // Add the preferred mode first to be sure it's not dropped + auto mode = std::find_if(connector_->modes().begin(), + connector_->modes().end(), [&](DrmMode const &m) { + return m.id() == + connector_->get_preferred_mode_id(); + }); + if (mode != connector_->modes().end()) + sel_modes.push_back(*mode); + + // Add the active mode if different from preferred mode + if (connector_->active_mode().id() != connector_->get_preferred_mode_id()) + sel_modes.push_back(connector_->active_mode()); + + // Cycle over the modes and filter out "similar" modes, keeping only the + // first ones in the order given by DRM (from CEA ids and timings order) + for (const DrmMode &mode : connector_->modes()) { + // TODO: Remove this when 3D Attributes are in AOSP + if (mode.flags() & DRM_MODE_FLAG_3D_MASK) + continue; + + // TODO: Remove this when the Interlaced attribute is in AOSP + if (mode.flags() & DRM_MODE_FLAG_INTERLACE) { + auto m = std::find_if(connector_->modes().begin(), + connector_->modes().end(), + [&mode](DrmMode const &m) { + return !(m.flags() & DRM_MODE_FLAG_INTERLACE) && + m.h_display() == mode.h_display() && + m.v_display() == mode.v_display(); + }); + if (m == connector_->modes().end()) + sel_modes.push_back(mode); + + continue; + } + + // Search for a similar WxH@R mode in the filtered list and drop it if + // another mode with the same WxH@R has already been selected + // TODO: Remove this when AOSP handles duplicates modes + auto m = std::find_if(sel_modes.begin(), sel_modes.end(), + [&mode](DrmMode const &m) { + return m.h_display() == mode.h_display() && + m.v_display() == mode.v_display() && + m.v_refresh() == mode.v_refresh(); + }); + if (m == sel_modes.end()) + sel_modes.push_back(mode); + } + + auto num_modes = static_cast(sel_modes.size()); + if (!configs) { + *num_configs = num_modes; + return HWC2::Error::None; + } + + uint32_t idx = 0; + for (const DrmMode &mode : sel_modes) { + if (idx >= *num_configs) + break; + configs[idx++] = mode.id(); + } + *num_configs = idx; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayName(uint32_t *size, char *name) { + supported(__func__); + std::ostringstream stream; + stream << "display-" << connector_->id(); + std::string string = stream.str(); + size_t length = string.length(); + if (!name) { + *size = length; + return HWC2::Error::None; + } + + *size = std::min(static_cast(length - 1), *size); + strncpy(name, string.c_str(), *size); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayRequests(int32_t *display_requests, + uint32_t *num_elements, + hwc2_layer_t *layers, + int32_t *layer_requests) { + supported(__func__); + // TODO: I think virtual display should request + // HWC2_DISPLAY_REQUEST_WRITE_CLIENT_TARGET_TO_OUTPUT here + unsupported(__func__, display_requests, num_elements, layers, layer_requests); + *num_elements = 0; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayType(int32_t *type) { + supported(__func__); + *type = static_cast(type_); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetDozeSupport(int32_t *support) { + supported(__func__); + *support = 0; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetHdrCapabilities( + uint32_t *num_types, int32_t * /*types*/, float * /*max_luminance*/, + float * /*max_average_luminance*/, float * /*min_luminance*/) { + supported(__func__); + *num_types = 0; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetReleaseFences(uint32_t *num_elements, + hwc2_layer_t *layers, + int32_t *fences) { + supported(__func__); + uint32_t num_layers = 0; + + for (std::pair &l : layers_) { + ++num_layers; + if (layers == NULL || fences == NULL) { + continue; + } else if (num_layers > *num_elements) { + ALOGW("Overflow num_elements %d/%d", num_layers, *num_elements); + return HWC2::Error::None; + } + + layers[num_layers - 1] = l.first; + fences[num_layers - 1] = l.second.take_release_fence(); + } + *num_elements = num_layers; + return HWC2::Error::None; +} + +void DrmHwcTwo::HwcDisplay::AddFenceToPresentFence(int fd) { + if (fd < 0) + return; + + if (present_fence_.get() >= 0) { + int old_fence = present_fence_.get(); + present_fence_.Set(sync_merge("dc_present", old_fence, fd)); + close(fd); + } else { + present_fence_.Set(fd); + } +} + +bool DrmHwcTwo::HwcDisplay::HardwareSupportsLayerType( + HWC2::Composition comp_type) { + return comp_type == HWC2::Composition::Device || + comp_type == HWC2::Composition::Cursor; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::CreateComposition(bool test) { + std::vector layers_map; + layers_map.emplace_back(); + DrmCompositionDisplayLayersMap &map = layers_map.back(); + + map.display = static_cast(handle_); + map.geometry_changed = true; // TODO: Fix this + + // order the layers by z-order + bool use_client_layer = false; + uint32_t client_z_order = UINT32_MAX; + std::map z_map; + for (std::pair &l : layers_) { + switch (l.second.validated_type()) { + case HWC2::Composition::Device: + z_map.emplace(std::make_pair(l.second.z_order(), &l.second)); + break; + case HWC2::Composition::Client: + // Place it at the z_order of the lowest client layer + use_client_layer = true; + client_z_order = std::min(client_z_order, l.second.z_order()); + break; + default: + continue; + } + } + if (use_client_layer) + z_map.emplace(std::make_pair(client_z_order, &client_layer_)); + + if (z_map.empty()) + return HWC2::Error::BadLayer; + + // now that they're ordered by z, add them to the composition + for (std::pair &l : z_map) { + DrmHwcLayer layer; + l.second->PopulateDrmLayer(&layer); + int ret = layer.ImportBuffer(importer_.get()); + if (ret) { + ALOGE("Failed to import layer, ret=%d", ret); + return HWC2::Error::NoResources; + } + map.layers.emplace_back(std::move(layer)); + } + + std::unique_ptr composition = compositor_ + .CreateComposition(); + composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_); + + // TODO: Don't always assume geometry changed + int ret = composition->SetLayers(map.layers.data(), map.layers.size(), true); + if (ret) { + ALOGE("Failed to set layers in the composition ret=%d", ret); + return HWC2::Error::BadLayer; + } + + std::vector primary_planes(primary_planes_); + std::vector overlay_planes(overlay_planes_); + ret = composition->Plan(&primary_planes, &overlay_planes); + if (ret) { + ALOGE("Failed to plan the composition ret=%d", ret); + return HWC2::Error::BadConfig; + } + + // Disable the planes we're not using + for (auto i = primary_planes.begin(); i != primary_planes.end();) { + composition->AddPlaneDisable(*i); + i = primary_planes.erase(i); + } + for (auto i = overlay_planes.begin(); i != overlay_planes.end();) { + composition->AddPlaneDisable(*i); + i = overlay_planes.erase(i); + } + + if (test) { + ret = compositor_.TestComposition(composition.get()); + } else { + ret = compositor_.ApplyComposition(std::move(composition)); + AddFenceToPresentFence(compositor_.TakeOutFence()); + } + if (ret) { + if (!test) + ALOGE("Failed to apply the frame composition ret=%d", ret); + return HWC2::Error::BadParameter; + } + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::PresentDisplay(int32_t *present_fence) { + supported(__func__); + HWC2::Error ret; + + ++total_stats_.total_frames_; + + ret = CreateComposition(false); + if (ret != HWC2::Error::None) + ++total_stats_.failed_kms_present_; + + if (ret == HWC2::Error::BadLayer) { + // Can we really have no client or device layers? + *present_fence = -1; + return HWC2::Error::None; + } + if (ret != HWC2::Error::None) + return ret; + + *present_fence = present_fence_.Release(); + + ++frame_no_; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::SetActiveConfig(hwc2_config_t config) { + supported(__func__); + auto mode = std::find_if(connector_->modes().begin(), + connector_->modes().end(), + [config](DrmMode const &m) { + return m.id() == config; + }); + if (mode == connector_->modes().end()) { + ALOGE("Could not find active mode for %d", config); + return HWC2::Error::BadConfig; + } + + std::unique_ptr composition = compositor_ + .CreateComposition(); + composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_); + int ret = composition->SetDisplayMode(*mode); + ret = compositor_.ApplyComposition(std::move(composition)); + if (ret) { + ALOGE("Failed to queue dpms composition on %d", ret); + return HWC2::Error::BadConfig; + } + + connector_->set_active_mode(*mode); + + // Setup the client layer's dimensions + hwc_rect_t display_frame = {.left = 0, + .top = 0, + .right = static_cast(mode->h_display()), + .bottom = static_cast(mode->v_display())}; + client_layer_.SetLayerDisplayFrame(display_frame); + hwc_frect_t source_crop = {.left = 0.0f, + .top = 0.0f, + .right = mode->h_display() + 0.0f, + .bottom = mode->v_display() + 0.0f}; + client_layer_.SetLayerSourceCrop(source_crop); + + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::SetClientTarget(buffer_handle_t target, + int32_t acquire_fence, + int32_t dataspace, + hwc_region_t /*damage*/) { + supported(__func__); + UniqueFd uf(acquire_fence); + + client_layer_.set_buffer(target); + client_layer_.set_acquire_fence(uf.get()); + client_layer_.SetLayerDataspace(dataspace); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::SetColorMode(int32_t mode) { + supported(__func__); + + if (mode != HAL_COLOR_MODE_NATIVE) + return HWC2::Error::BadParameter; + + color_mode_ = mode; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::SetColorTransform(const float *matrix, + int32_t hint) { + supported(__func__); + if (hint < HAL_COLOR_TRANSFORM_IDENTITY || + hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA) + return HWC2::Error::BadParameter; + + if (!matrix && hint == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX) + return HWC2::Error::BadParameter; + + color_transform_hint_ = static_cast(hint); + if (color_transform_hint_ == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX) + std::copy(matrix, matrix + MATRIX_SIZE, color_transform_matrix_.begin()); + + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::SetOutputBuffer(buffer_handle_t buffer, + int32_t release_fence) { + supported(__func__); + // TODO: Need virtual display support + return unsupported(__func__, buffer, release_fence); +} + +HWC2::Error DrmHwcTwo::HwcDisplay::SetPowerMode(int32_t mode_in) { + supported(__func__); + uint64_t dpms_value = 0; + auto mode = static_cast(mode_in); + switch (mode) { + case HWC2::PowerMode::Off: + dpms_value = DRM_MODE_DPMS_OFF; + break; + case HWC2::PowerMode::On: + dpms_value = DRM_MODE_DPMS_ON; + break; + case HWC2::PowerMode::Doze: + case HWC2::PowerMode::DozeSuspend: + return HWC2::Error::Unsupported; + default: + ALOGI("Power mode %d is unsupported\n", mode); + return HWC2::Error::BadParameter; + }; + + std::unique_ptr composition = compositor_ + .CreateComposition(); + composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_); + composition->SetDpmsMode(dpms_value); + int ret = compositor_.ApplyComposition(std::move(composition)); + if (ret) { + ALOGE("Failed to apply the dpms composition ret=%d", ret); + return HWC2::Error::BadParameter; + } + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::SetVsyncEnabled(int32_t enabled) { + supported(__func__); + vsync_worker_.VSyncControl(HWC2_VSYNC_ENABLE == enabled); + return HWC2::Error::None; +} + +uint32_t DrmHwcTwo::HwcDisplay::CalcPixOps( + std::map &z_map, size_t first_z, + size_t size) { + uint32_t pixops = 0; + for (std::pair &l : z_map) { + if (l.first >= first_z && l.first < first_z + size) { + hwc_rect_t df = l.second->display_frame(); + pixops += (df.right - df.left) * (df.bottom - df.top); + } + } + return pixops; +} + +void DrmHwcTwo::HwcDisplay::MarkValidated( + std::map &z_map, size_t client_first_z, + size_t client_size) { + for (std::pair &l : z_map) { + if (l.first >= client_first_z && l.first < client_first_z + client_size) + l.second->set_validated_type(HWC2::Composition::Client); + else + l.second->set_validated_type(HWC2::Composition::Device); + } +} + +HWC2::Error DrmHwcTwo::HwcDisplay::ValidateDisplay(uint32_t *num_types, + uint32_t *num_requests) { + supported(__func__); + + return backend_->ValidateDisplay(this, num_types, num_requests); +} + +#if PLATFORM_SDK_VERSION > 28 +HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayIdentificationData( + uint8_t *outPort, uint32_t *outDataSize, uint8_t *outData) { + supported(__func__); + + drmModePropertyBlobPtr blob; + int ret; + uint64_t blob_id; + + std::tie(ret, blob_id) = connector_->edid_property().value(); + if (ret) { + ALOGE("Failed to get edid property value."); + return HWC2::Error::Unsupported; + } + + blob = drmModeGetPropertyBlob(drm_->fd(), blob_id); + + if (outData) { + *outDataSize = std::min(*outDataSize, blob->length); + memcpy(outData, blob->data, *outDataSize); + } else { + *outDataSize = blob->length; + } + *outPort = connector_->id(); + + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayCapabilities( + uint32_t *outNumCapabilities, uint32_t *outCapabilities) { + unsupported(__func__, outCapabilities); + + if (outNumCapabilities == NULL) { + return HWC2::Error::BadParameter; + } + + *outNumCapabilities = 0; + + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayBrightnessSupport( + bool *supported) { + *supported = false; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::SetDisplayBrightness( + float /* brightness */) { + return HWC2::Error::Unsupported; +} + +#endif /* PLATFORM_SDK_VERSION > 28 */ + +#if PLATFORM_SDK_VERSION > 27 + +HWC2::Error DrmHwcTwo::HwcDisplay::GetRenderIntents( + int32_t mode, uint32_t *outNumIntents, + int32_t * /*android_render_intent_v1_1_t*/ outIntents) { + if (mode != HAL_COLOR_MODE_NATIVE) { + return HWC2::Error::BadParameter; + } + + if (outIntents == nullptr) { + *outNumIntents = 1; + return HWC2::Error::None; + } + *outNumIntents = 1; + outIntents[0] = HAL_RENDER_INTENT_COLORIMETRIC; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::SetColorModeWithIntent(int32_t mode, + int32_t intent) { + if (mode != HAL_COLOR_MODE_NATIVE) + return HWC2::Error::BadParameter; + if (intent != HAL_RENDER_INTENT_COLORIMETRIC) + return HWC2::Error::BadParameter; + color_mode_ = mode; + return HWC2::Error::None; +} + +#endif /* PLATFORM_SDK_VERSION > 27 */ + +HWC2::Error DrmHwcTwo::HwcLayer::SetCursorPosition(int32_t x, int32_t y) { + supported(__func__); + cursor_x_ = x; + cursor_y_ = y; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerBlendMode(int32_t mode) { + supported(__func__); + blending_ = static_cast(mode); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerBuffer(buffer_handle_t buffer, + int32_t acquire_fence) { + supported(__func__); + UniqueFd uf(acquire_fence); + + set_buffer(buffer); + set_acquire_fence(uf.get()); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerColor(hwc_color_t color) { + // TODO: Put to client composition here? + supported(__func__); + layer_color_ = color; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerCompositionType(int32_t type) { + sf_type_ = static_cast(type); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDataspace(int32_t dataspace) { + supported(__func__); + dataspace_ = static_cast(dataspace); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDisplayFrame(hwc_rect_t frame) { + supported(__func__); + display_frame_ = frame; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerPlaneAlpha(float alpha) { + supported(__func__); + alpha_ = alpha; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSidebandStream( + const native_handle_t *stream) { + supported(__func__); + // TODO: We don't support sideband + return unsupported(__func__, stream); +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSourceCrop(hwc_frect_t crop) { + supported(__func__); + source_crop_ = crop; + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSurfaceDamage(hwc_region_t damage) { + supported(__func__); + // TODO: We don't use surface damage, marking as unsupported + unsupported(__func__, damage); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerTransform(int32_t transform) { + supported(__func__); + transform_ = static_cast(transform); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerVisibleRegion(hwc_region_t visible) { + supported(__func__); + // TODO: We don't use this information, marking as unsupported + unsupported(__func__, visible); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcLayer::SetLayerZOrder(uint32_t order) { + supported(__func__); + z_order_ = order; + return HWC2::Error::None; +} + +void DrmHwcTwo::HwcLayer::PopulateDrmLayer(DrmHwcLayer *layer) { + supported(__func__); + switch (blending_) { + case HWC2::BlendMode::None: + layer->blending = DrmHwcBlending::kNone; + break; + case HWC2::BlendMode::Premultiplied: + layer->blending = DrmHwcBlending::kPreMult; + break; + case HWC2::BlendMode::Coverage: + layer->blending = DrmHwcBlending::kCoverage; + break; + default: + ALOGE("Unknown blending mode b=%d", blending_); + layer->blending = DrmHwcBlending::kNone; + break; + } + + OutputFd release_fence = release_fence_output(); + + layer->sf_handle = buffer_; + layer->acquire_fence = acquire_fence_.Release(); + layer->release_fence = std::move(release_fence); + layer->SetDisplayFrame(display_frame_); + layer->alpha = static_cast(65535.0f * alpha_ + 0.5f); + layer->SetSourceCrop(source_crop_); + layer->SetTransform(static_cast(transform_)); +} + +void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) { + auto cb = callbacks_.find(HWC2::Callback::Hotplug); + if (cb == callbacks_.end()) + return; + + auto hotplug = reinterpret_cast(cb->second.func); + hotplug(cb->second.data, displayid, + (state == DRM_MODE_CONNECTED ? HWC2_CONNECTION_CONNECTED + : HWC2_CONNECTION_DISCONNECTED)); +} + +void DrmHwcTwo::HandleInitialHotplugState(DrmDevice *drmDevice) { + for (auto &conn : drmDevice->connectors()) { + if (conn->state() != DRM_MODE_CONNECTED) + continue; + HandleDisplayHotplug(conn->display(), conn->state()); + } +} + +void DrmHwcTwo::DrmHotplugHandler::HandleEvent(uint64_t timestamp_us) { + for (auto &conn : drm_->connectors()) { + drmModeConnection old_state = conn->state(); + drmModeConnection cur_state = conn->UpdateModes() + ? DRM_MODE_UNKNOWNCONNECTION + : conn->state(); + + if (cur_state == old_state) + continue; + + ALOGI("%s event @%" PRIu64 " for connector %u on display %d", + cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", timestamp_us, + conn->id(), conn->display()); + + int display_id = conn->display(); + if (cur_state == DRM_MODE_CONNECTED) { + auto &display = hwc2_->displays_.at(display_id); + display.ChosePreferredConfig(); + } else { + auto &display = hwc2_->displays_.at(display_id); + display.ClearDisplay(); + } + + hwc2_->HandleDisplayHotplug(display_id, cur_state); + } +} + +// static +int DrmHwcTwo::HookDevClose(hw_device_t * /*dev*/) { + unsupported(__func__); + return 0; +} + +// static +void DrmHwcTwo::HookDevGetCapabilities(hwc2_device_t * /*dev*/, + uint32_t *out_count, + int32_t * /*out_capabilities*/) { + supported(__func__); + *out_count = 0; +} + +// static +hwc2_function_pointer_t DrmHwcTwo::HookDevGetFunction( + struct hwc2_device * /*dev*/, int32_t descriptor) { + supported(__func__); + auto func = static_cast(descriptor); + switch (func) { + // Device functions + case HWC2::FunctionDescriptor::CreateVirtualDisplay: + return ToHook( + DeviceHook); + case HWC2::FunctionDescriptor::DestroyVirtualDisplay: + return ToHook( + DeviceHook); + case HWC2::FunctionDescriptor::Dump: + return ToHook( + DeviceHook); + case HWC2::FunctionDescriptor::GetMaxVirtualDisplayCount: + return ToHook( + DeviceHook); + case HWC2::FunctionDescriptor::RegisterCallback: + return ToHook( + DeviceHook); + + // Display functions + case HWC2::FunctionDescriptor::AcceptDisplayChanges: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::CreateLayer: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::DestroyLayer: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::GetActiveConfig: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::GetChangedCompositionTypes: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::GetClientTargetSupport: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::GetColorModes: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::GetDisplayAttribute: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::GetDisplayConfigs: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::GetDisplayName: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::GetDisplayRequests: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::GetDisplayType: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::GetDozeSupport: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::GetHdrCapabilities: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::GetReleaseFences: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::PresentDisplay: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::SetActiveConfig: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::SetClientTarget: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::SetColorMode: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::SetColorTransform: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::SetOutputBuffer: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::SetPowerMode: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::SetVsyncEnabled: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::ValidateDisplay: + return ToHook( + DisplayHook); +#if PLATFORM_SDK_VERSION > 27 + case HWC2::FunctionDescriptor::GetRenderIntents: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::SetColorModeWithRenderIntent: + return ToHook( + DisplayHook); +#endif +#if PLATFORM_SDK_VERSION > 28 + case HWC2::FunctionDescriptor::GetDisplayIdentificationData: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::GetDisplayCapabilities: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::GetDisplayBrightnessSupport: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::SetDisplayBrightness: + return ToHook( + DisplayHook); +#endif /* PLATFORM_SDK_VERSION > 28 */ + // Layer functions + case HWC2::FunctionDescriptor::SetCursorPosition: + return ToHook( + LayerHook); + case HWC2::FunctionDescriptor::SetLayerBlendMode: + return ToHook( + LayerHook); + case HWC2::FunctionDescriptor::SetLayerBuffer: + return ToHook( + LayerHook); + case HWC2::FunctionDescriptor::SetLayerColor: + return ToHook( + LayerHook); + case HWC2::FunctionDescriptor::SetLayerCompositionType: + return ToHook( + LayerHook); + case HWC2::FunctionDescriptor::SetLayerDataspace: + return ToHook( + LayerHook); + case HWC2::FunctionDescriptor::SetLayerDisplayFrame: + return ToHook( + LayerHook); + case HWC2::FunctionDescriptor::SetLayerPlaneAlpha: + return ToHook( + LayerHook); + case HWC2::FunctionDescriptor::SetLayerSidebandStream: + return ToHook( + LayerHook); + case HWC2::FunctionDescriptor::SetLayerSourceCrop: + return ToHook( + LayerHook); + case HWC2::FunctionDescriptor::SetLayerSurfaceDamage: + return ToHook( + LayerHook); + case HWC2::FunctionDescriptor::SetLayerTransform: + return ToHook( + LayerHook); + case HWC2::FunctionDescriptor::SetLayerVisibleRegion: + return ToHook( + LayerHook); + case HWC2::FunctionDescriptor::SetLayerZOrder: + return ToHook( + LayerHook); + case HWC2::FunctionDescriptor::Invalid: + default: + return NULL; + } +} + +// static +int DrmHwcTwo::HookDevOpen(const struct hw_module_t *module, const char *name, + struct hw_device_t **dev) { + supported(__func__); + if (strcmp(name, HWC_HARDWARE_COMPOSER)) { + ALOGE("Invalid module name- %s", name); + return -EINVAL; + } + + std::unique_ptr ctx(new DrmHwcTwo()); + if (!ctx) { + ALOGE("Failed to allocate DrmHwcTwo"); + return -ENOMEM; + } + + HWC2::Error err = ctx->Init(); + if (err != HWC2::Error::None) { + ALOGE("Failed to initialize DrmHwcTwo err=%d\n", err); + return -EINVAL; + } + + ctx->common.module = const_cast(module); + *dev = &ctx->common; + ctx.release(); + return 0; +} +} // namespace android + +static struct hw_module_methods_t hwc2_module_methods = { + .open = android::DrmHwcTwo::HookDevOpen, +}; + +hw_module_t HAL_MODULE_INFO_SYM = { + .tag = HARDWARE_MODULE_TAG, + .module_api_version = HARDWARE_MODULE_API_VERSION(2, 0), + .id = HWC_HARDWARE_MODULE_ID, + .name = "DrmHwcTwo module", + .author = "The Android Open Source Project", + .methods = &hwc2_module_methods, + .dso = NULL, + .reserved = {0}, +}; diff --git a/DrmHwcTwo.h b/DrmHwcTwo.h new file mode 100644 index 0000000..ca7a00b --- /dev/null +++ b/DrmHwcTwo.h @@ -0,0 +1,431 @@ +/* + * 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. + */ + +#ifndef ANDROID_DRM_HWC_TWO_H_ +#define ANDROID_DRM_HWC_TWO_H_ + +#include +#include + +#include +#include + +#include "compositor/DrmDisplayCompositor.h" +#include "drm/ResourceManager.h" +#include "drm/VSyncWorker.h" +#include "drmhwcomposer.h" +#include "platform/platform.h" + +namespace android { + +class Backend; + +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(); + + 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_); + } + + hwc_rect_t display_frame() { + return display_frame_; + } + + void PopulateDrmLayer(DrmHwcLayer *layer); + + bool RequireScalingOrPhasing() { + float src_width = source_crop_.right - source_crop_.left; + float src_height = source_crop_.bottom - source_crop_.top; + + float dest_width = display_frame_.right - display_frame_.left; + float dest_height = display_frame_.bottom - display_frame_.top; + + bool scaling = src_width != dest_width || src_height != dest_height; + bool phasing = (source_crop_.left - floor(source_crop_.left) != 0) || + (source_crop_.top - floor(source_crop_.top) != 0); + return scaling || phasing; + } + + // 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_ = NULL; + 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_; + hwc_color_t layer_color_; + 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(ResourceManager *resource_manager, DrmDevice *drm, + std::shared_ptr importer, hwc2_display_t handle, + HWC2::DisplayType type); + HwcDisplay(const HwcDisplay &) = delete; + HWC2::Error Init(std::vector *planes); + + HWC2::Error RegisterVsyncCallback(hwc2_callback_data_t data, + hwc2_function_pointer_t func); + void RegisterRefreshCallback(hwc2_callback_data_t data, + hwc2_function_pointer_t func); + HWC2::Error CreateComposition(bool test); + bool HardwareSupportsLayerType(HWC2::Composition comp_type); + uint32_t CalcPixOps(std::map &z_map, + size_t first_z, size_t size); + void MarkValidated(std::map &z_map, + size_t client_first_z, size_t client_size); + + void ClearDisplay(); + + std::string Dump(); + + // HWC Hooks + HWC2::Error AcceptDisplayChanges(); + HWC2::Error CreateLayer(hwc2_layer_t *layer); + HWC2::Error DestroyLayer(hwc2_layer_t layer); + HWC2::Error GetActiveConfig(hwc2_config_t *config); + HWC2::Error GetChangedCompositionTypes(uint32_t *num_elements, + hwc2_layer_t *layers, + int32_t *types); + HWC2::Error GetClientTargetSupport(uint32_t width, uint32_t height, + int32_t format, int32_t dataspace); + HWC2::Error GetColorModes(uint32_t *num_modes, int32_t *modes); + HWC2::Error GetDisplayAttribute(hwc2_config_t config, int32_t attribute, + int32_t *value); + HWC2::Error GetDisplayConfigs(uint32_t *num_configs, + hwc2_config_t *configs); + HWC2::Error GetDisplayName(uint32_t *size, char *name); + HWC2::Error GetDisplayRequests(int32_t *display_requests, + uint32_t *num_elements, hwc2_layer_t *layers, + int32_t *layer_requests); + HWC2::Error GetDisplayType(int32_t *type); +#if PLATFORM_SDK_VERSION > 27 + HWC2::Error GetRenderIntents(int32_t mode, uint32_t *outNumIntents, + int32_t *outIntents); + HWC2::Error SetColorModeWithIntent(int32_t mode, int32_t intent); +#endif +#if PLATFORM_SDK_VERSION > 28 + HWC2::Error GetDisplayIdentificationData(uint8_t *outPort, + uint32_t *outDataSize, + uint8_t *outData); + HWC2::Error GetDisplayCapabilities(uint32_t *outNumCapabilities, + uint32_t *outCapabilities); + HWC2::Error GetDisplayBrightnessSupport(bool *supported); + HWC2::Error SetDisplayBrightness(float); +#endif + HWC2::Error GetDozeSupport(int32_t *support); + HWC2::Error GetHdrCapabilities(uint32_t *num_types, int32_t *types, + float *max_luminance, + float *max_average_luminance, + float *min_luminance); + HWC2::Error GetReleaseFences(uint32_t *num_elements, hwc2_layer_t *layers, + int32_t *fences); + HWC2::Error PresentDisplay(int32_t *present_fence); + HWC2::Error SetActiveConfig(hwc2_config_t config); + HWC2::Error ChosePreferredConfig(); + HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence, + int32_t dataspace, hwc_region_t damage); + HWC2::Error SetColorMode(int32_t mode); + HWC2::Error SetColorTransform(const float *matrix, int32_t hint); + HWC2::Error SetOutputBuffer(buffer_handle_t buffer, int32_t release_fence); + HWC2::Error SetPowerMode(int32_t mode); + HWC2::Error SetVsyncEnabled(int32_t enabled); + HWC2::Error ValidateDisplay(uint32_t *num_types, uint32_t *num_requests); + HwcLayer *get_layer(hwc2_layer_t layer) { + auto it = layers_.find(layer); + if (it == layers_.end()) + return nullptr; + return &it->second; + } + + /* Statistics */ + struct Stats { + Stats minus(Stats b) { + return {total_frames_ - b.total_frames_, + total_pixops_ - b.total_pixops_, + gpu_pixops_ - b.gpu_pixops_, + failed_kms_validate_ - b.failed_kms_validate_, + failed_kms_present_ - b.failed_kms_present_, + frames_flattened_ - b.frames_flattened_}; + } + + uint32_t total_frames_ = 0; + uint64_t total_pixops_ = 0; + uint64_t gpu_pixops_ = 0; + uint32_t failed_kms_validate_ = 0; + uint32_t failed_kms_present_ = 0; + uint32_t frames_flattened_ = 0; + }; + + const Backend *backend() const { + return backend_.get(); + } + void set_backend(std::unique_ptr backend) { + backend_ = std::move(backend); + } + + const std::vector &primary_planes() const { + return primary_planes_; + } + + const std::vector &overlay_planes() const { + return overlay_planes_; + } + + std::map &layers() { + return layers_; + } + + const DrmDisplayCompositor &compositor() const { + return compositor_; + } + + const DrmDevice *drm() const { + return drm_; + } + + const DrmConnector *connector() const { + return connector_; + } + + const std::shared_ptr &importer() const { + return importer_; + } + + ResourceManager *resource_manager() const { + return resource_manager_; + } + + android_color_transform_t &color_transform_hint() { + return color_transform_hint_; + } + + Stats &total_stats() { + return total_stats_; + } + + private: + void AddFenceToPresentFence(int fd); + + constexpr static size_t MATRIX_SIZE = 16; + + ResourceManager *resource_manager_; + DrmDevice *drm_; + DrmDisplayCompositor compositor_; + std::shared_ptr importer_; + std::unique_ptr planner_; + + std::vector primary_planes_; + std::vector overlay_planes_; + + std::unique_ptr backend_; + + VSyncWorker vsync_worker_; + DrmConnector *connector_ = NULL; + DrmCrtc *crtc_ = NULL; + hwc2_display_t handle_; + HWC2::DisplayType type_; + uint32_t layer_idx_ = 0; + std::map layers_; + HwcLayer client_layer_; + UniqueFd present_fence_; + int32_t color_mode_; + std::array color_transform_matrix_; + android_color_transform_t color_transform_hint_; + + uint32_t frame_no_ = 0; + Stats total_stats_; + Stats prev_stats_; + std::string DumpDelta(DrmHwcTwo::HwcDisplay::Stats delta); + }; + + class DrmHotplugHandler : public DrmEventHandler { + public: + DrmHotplugHandler(DrmHwcTwo *hwc2, DrmDevice *drm) + : hwc2_(hwc2), drm_(drm) { + } + void HandleEvent(uint64_t timestamp_us); + + private: + DrmHwcTwo *hwc2_; + DrmDevice *drm_; + }; + + private: + static DrmHwcTwo *toDrmHwcTwo(hwc2_device_t *dev) { + return static_cast(dev); + } + + template + static hwc2_function_pointer_t ToHook(T function) { + static_assert(std::is_same::value, "Incompatible fn pointer"); + return reinterpret_cast(function); + } + + template + static T DeviceHook(hwc2_device_t *dev, Args... args) { + DrmHwcTwo *hwc = toDrmHwcTwo(dev); + return static_cast(((*hwc).*func)(std::forward(args)...)); + } + + static HwcDisplay *GetDisplay(DrmHwcTwo *hwc, hwc2_display_t display_handle) { + auto it = hwc->displays_.find(display_handle); + if (it == hwc->displays_.end()) + return nullptr; + + return &it->second; + } + + template + static int32_t DisplayHook(hwc2_device_t *dev, hwc2_display_t display_handle, + Args... args) { + HwcDisplay *display = GetDisplay(toDrmHwcTwo(dev), display_handle); + if (!display) + return static_cast(HWC2::Error::BadDisplay); + + return static_cast((display->*func)(std::forward(args)...)); + } + + template + static int32_t LayerHook(hwc2_device_t *dev, hwc2_display_t display_handle, + hwc2_layer_t layer_handle, Args... args) { + HwcDisplay *display = GetDisplay(toDrmHwcTwo(dev), display_handle); + if (!display) + return static_cast(HWC2::Error::BadDisplay); + + HwcLayer *layer = display->get_layer(layer_handle); + if (!layer) + return static_cast(HWC2::Error::BadLayer); + + return static_cast((layer->*func)(std::forward(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 *outSize, char *outBuffer); + uint32_t GetMaxVirtualDisplayCount(); + HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data, + hwc2_function_pointer_t function); + HWC2::Error CreateDisplay(hwc2_display_t displ, HWC2::DisplayType type); + void HandleDisplayHotplug(hwc2_display_t displayid, int state); + void HandleInitialHotplugState(DrmDevice *drmDevice); + + ResourceManager resource_manager_; + std::map displays_; + std::map callbacks_; + + std::string mDumpString; +}; +} // namespace android + +#endif diff --git a/backend/Backend.cpp b/backend/Backend.cpp new file mode 100644 index 0000000..50ef900 --- /dev/null +++ b/backend/Backend.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2020 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 "Backend.h" + +#include "BackendManager.h" + +namespace android { + +HWC2::Error Backend::ValidateDisplay(DrmHwcTwo::HwcDisplay *display, + uint32_t *num_types, + uint32_t *num_requests) { + *num_types = 0; + *num_requests = 0; + size_t avail_planes = display->primary_planes().size() + + display->overlay_planes().size(); + + /* + * If more layers then planes, save one plane + * for client composited layers + */ + if (avail_planes < display->layers().size()) + avail_planes--; + + std::map z_map, z_map_tmp; + uint32_t z_index = 0; + // First create a map of layers and z_order values + for (std::pair &l : + display->layers()) + z_map_tmp.emplace(std::make_pair(l.second.z_order(), &l.second)); + // normalise the map so that the lowest z_order layer has key 0 + for (std::pair &l : z_map_tmp) + z_map.emplace(std::make_pair(z_index++, l.second)); + + uint32_t total_pixops = display->CalcPixOps(z_map, 0, z_map.size()); + uint32_t gpu_pixops = 0; + + int client_start = -1, client_size = 0; + + if (display->compositor().ShouldFlattenOnClient()) { + client_start = 0; + client_size = z_map.size(); + display->MarkValidated(z_map, client_start, client_size); + } else { + std::tie(client_start, client_size) = GetClientLayers(display, z_map); + + int extra_client = (z_map.size() - client_size) - avail_planes; + if (extra_client > 0) { + int start = 0, steps; + if (client_size != 0) { + int prepend = std::min(client_start, extra_client); + int append = std::min(int(z_map.size() - (client_start + client_size)), + extra_client); + start = client_start - prepend; + client_size += extra_client; + steps = 1 + std::min(std::min(append, prepend), + int(z_map.size()) - (start + client_size)); + } else { + client_size = extra_client; + steps = 1 + z_map.size() - extra_client; + } + + gpu_pixops = INT_MAX; + for (int i = 0; i < steps; i++) { + uint32_t po = display->CalcPixOps(z_map, start + i, client_size); + if (po < gpu_pixops) { + gpu_pixops = po; + client_start = start + i; + } + } + } + + display->MarkValidated(z_map, client_start, client_size); + + bool testing_needed = !(client_start == 0 && client_size == z_map.size()); + + if (testing_needed && + display->CreateComposition(true) != HWC2::Error::None) { + ++display->total_stats().failed_kms_validate_; + gpu_pixops = total_pixops; + client_size = z_map.size(); + display->MarkValidated(z_map, 0, client_size); + } + } + + *num_types = client_size; + + display->total_stats().frames_flattened_ = display->compositor() + .GetFlattenedFramesCount(); + display->total_stats().gpu_pixops_ += gpu_pixops; + display->total_stats().total_pixops_ += total_pixops; + + return *num_types ? HWC2::Error::HasChanges : HWC2::Error::None; +} + +std::tuple Backend::GetClientLayers( + DrmHwcTwo::HwcDisplay *display, + const std::map &z_map) { + int client_start = -1, client_size = 0; + + for (auto & [ z_order, layer ] : z_map) { + if (IsClientLayer(display, layer)) { + if (client_start < 0) + client_start = z_order; + client_size = (z_order - client_start) + 1; + } + } + + return std::make_tuple(client_start, client_size); +} + +bool Backend::IsClientLayer(DrmHwcTwo::HwcDisplay *display, + DrmHwcTwo::HwcLayer *layer) { + return !display->HardwareSupportsLayerType(layer->sf_type()) || + !display->importer()->CanImportBuffer(layer->buffer()) || + display->color_transform_hint() != HAL_COLOR_TRANSFORM_IDENTITY || + (layer->RequireScalingOrPhasing() && + display->resource_manager()->ForcedScalingWithGpu()); +} + +REGISTER_BACKEND("generic", Backend); + +} // namespace android diff --git a/backend/Backend.h b/backend/Backend.h new file mode 100644 index 0000000..898fece --- /dev/null +++ b/backend/Backend.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_BACKEND_H +#define ANDROID_BACKEND_H + +#include "DrmHwcTwo.h" + +namespace android { + +class Backend { + public: + virtual ~Backend() = default; + virtual HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, + uint32_t *num_types, + uint32_t *num_requests); + virtual std::tuple GetClientLayers( + DrmHwcTwo::HwcDisplay *display, + const std::map &z_map); + virtual bool IsClientLayer(DrmHwcTwo::HwcDisplay *display, + DrmHwcTwo::HwcLayer *layer); +}; +} // namespace android + +#endif diff --git a/backend/BackendClient.cpp b/backend/BackendClient.cpp new file mode 100644 index 0000000..033a35c --- /dev/null +++ b/backend/BackendClient.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2020 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 "BackendClient.h" + +#include "BackendManager.h" + +namespace android { + +HWC2::Error BackendClient::ValidateDisplay(DrmHwcTwo::HwcDisplay *display, + uint32_t *num_types, + uint32_t * /*num_requests*/) { + for (auto & [ layer_handle, layer ] : display->layers()) { + layer.set_validated_type(HWC2::Composition::Client); + ++*num_types; + } + return HWC2::Error::HasChanges; +} + +REGISTER_BACKEND("client", BackendClient); + +} // namespace android diff --git a/backend/BackendClient.h b/backend/BackendClient.h new file mode 100644 index 0000000..13543f1 --- /dev/null +++ b/backend/BackendClient.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_BACKEND_CLIENT_H +#define ANDROID_BACKEND_CLIENT_H + +#include "Backend.h" + +namespace android { + +class BackendClient : public Backend { + public: + HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, + uint32_t *num_types, + uint32_t *num_requests) override; +}; +} // namespace android + +#endif diff --git a/backend/BackendManager.cpp b/backend/BackendManager.cpp new file mode 100644 index 0000000..b7601ee --- /dev/null +++ b/backend/BackendManager.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "hwc-backend" + +#include "BackendManager.h" + +#include +#include + +namespace android { + +const std::vector BackendManager::client_devices_ = { + "kirin", +}; + +BackendManager &BackendManager::GetInstance() { + static BackendManager backend_manager; + + return backend_manager; +} + +int BackendManager::RegisterBackend(const std::string &name, + backend_constructor_t backend_constructor) { + available_backends_[name] = std::move(backend_constructor); + return 0; +} + +int BackendManager::SetBackendForDisplay(DrmHwcTwo::HwcDisplay *display) { + std::string driver_name(display->drm()->GetName()); + char backend_override[PROPERTY_VALUE_MAX]; + property_get("vendor.hwc.backend_override", backend_override, + driver_name.c_str()); + std::string backend_name(std::move(backend_override)); + + display->set_backend(GetBackendByName(backend_name)); + if (!display->backend()) { + ALOGE("Failed to set backend '%s' for '%s' and driver '%s'", + backend_name.c_str(), display->connector()->name().c_str(), + driver_name.c_str()); + return -EINVAL; + } + + ALOGI("Backend '%s' for '%s' and driver '%s' was successfully set", + backend_name.c_str(), display->connector()->name().c_str(), + driver_name.c_str()); + + return 0; +} + +std::unique_ptr BackendManager::GetBackendByName(std::string &name) { + if (!available_backends_.size()) { + ALOGE("No backends are specified"); + return nullptr; + } + + auto it = available_backends_.find(name); + if (it == available_backends_.end()) { + auto it = std::find(client_devices_.begin(), client_devices_.end(), name); + name = it == client_devices_.end() ? "generic" : "client"; + } + + return available_backends_[name](); +} +} // namespace android diff --git a/backend/BackendManager.h b/backend/BackendManager.h new file mode 100644 index 0000000..e86c098 --- /dev/null +++ b/backend/BackendManager.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_BACKEND_MANAGER_H +#define ANDROID_BACKEND_MANAGER_H + +#include +#include +#include +#include + +#include "Backend.h" + +#define REGISTER_BACKEND(name_str_, backend_) \ + static int \ + backend = BackendManager::GetInstance() \ + .RegisterBackend(name_str_, \ + []() -> std::unique_ptr { \ + return std::make_unique(); \ + }); + +namespace android { + +class BackendManager { + public: + using backend_constructor_t = std::function()>; + static BackendManager &GetInstance(); + int RegisterBackend(const std::string &name, + backend_constructor_t backend_constructor); + int SetBackendForDisplay(DrmHwcTwo::HwcDisplay *display); + std::unique_ptr GetBackendByName(std::string &name); + HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, + uint32_t *num_types, uint32_t *num_requests); + + private: + BackendManager() = default; + + static const std::vector client_devices_; + + std::map available_backends_; +}; +} // namespace android + +#endif diff --git a/backend/BackendRCarDu.cpp b/backend/BackendRCarDu.cpp new file mode 100644 index 0000000..d52f0c3 --- /dev/null +++ b/backend/BackendRCarDu.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2020 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 "BackendRCarDu.h" + +#include "BackendManager.h" +#include "drm_fourcc.h" + +namespace android { + +bool BackendRCarDu::IsClientLayer(DrmHwcTwo::HwcDisplay *display, + DrmHwcTwo::HwcLayer *layer) { + hwc_drm_bo_t bo; + + int ret = display->importer()->ConvertBoInfo(layer->buffer(), &bo); + if (ret) + return true; + + if (bo.format == DRM_FORMAT_ABGR8888) + return true; + + if (layer->RequireScalingOrPhasing()) + return true; + + return Backend::IsClientLayer(display, layer); +} + +REGISTER_BACKEND("rcar-du", BackendRCarDu); + +} // namespace android \ No newline at end of file diff --git a/backend/BackendRCarDu.h b/backend/BackendRCarDu.h new file mode 100644 index 0000000..8a1011a --- /dev/null +++ b/backend/BackendRCarDu.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HWC_DISPLAY_BACKEND_RCAR_DU_H +#define HWC_DISPLAY_BACKEND_RCAR_DU_H + +#include "Backend.h" + +namespace android { + +class BackendRCarDu : public Backend { + public: + bool IsClientLayer(DrmHwcTwo::HwcDisplay *display, + DrmHwcTwo::HwcLayer *layer) override; +}; +} // namespace android + +#endif diff --git a/backend/backend.cpp b/backend/backend.cpp deleted file mode 100644 index e36c47e..0000000 --- a/backend/backend.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2020 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 "backend.h" -#include "backendmanager.h" - -namespace android { - -HWC2::Error Backend::ValidateDisplay(DrmHwcTwo::HwcDisplay *display, - uint32_t *num_types, - uint32_t *num_requests) { - *num_types = 0; - *num_requests = 0; - size_t avail_planes = display->primary_planes().size() + - display->overlay_planes().size(); - - /* - * If more layers then planes, save one plane - * for client composited layers - */ - if (avail_planes < display->layers().size()) - avail_planes--; - - std::map z_map, z_map_tmp; - uint32_t z_index = 0; - // First create a map of layers and z_order values - for (std::pair &l : - display->layers()) - z_map_tmp.emplace(std::make_pair(l.second.z_order(), &l.second)); - // normalise the map so that the lowest z_order layer has key 0 - for (std::pair &l : z_map_tmp) - z_map.emplace(std::make_pair(z_index++, l.second)); - - uint32_t total_pixops = display->CalcPixOps(z_map, 0, z_map.size()); - uint32_t gpu_pixops = 0; - - int client_start = -1, client_size = 0; - - if (display->compositor().ShouldFlattenOnClient()) { - client_start = 0; - client_size = z_map.size(); - display->MarkValidated(z_map, client_start, client_size); - } else { - std::tie(client_start, client_size) = GetClientLayers(display, z_map); - - int extra_client = (z_map.size() - client_size) - avail_planes; - if (extra_client > 0) { - int start = 0, steps; - if (client_size != 0) { - int prepend = std::min(client_start, extra_client); - int append = std::min(int(z_map.size() - (client_start + client_size)), - extra_client); - start = client_start - prepend; - client_size += extra_client; - steps = 1 + std::min(std::min(append, prepend), - int(z_map.size()) - (start + client_size)); - } else { - client_size = extra_client; - steps = 1 + z_map.size() - extra_client; - } - - gpu_pixops = INT_MAX; - for (int i = 0; i < steps; i++) { - uint32_t po = display->CalcPixOps(z_map, start + i, client_size); - if (po < gpu_pixops) { - gpu_pixops = po; - client_start = start + i; - } - } - } - - display->MarkValidated(z_map, client_start, client_size); - - bool testing_needed = !(client_start == 0 && client_size == z_map.size()); - - if (testing_needed && - display->CreateComposition(true) != HWC2::Error::None) { - ++display->total_stats().failed_kms_validate_; - gpu_pixops = total_pixops; - client_size = z_map.size(); - display->MarkValidated(z_map, 0, client_size); - } - } - - *num_types = client_size; - - display->total_stats().frames_flattened_ = display->compositor() - .GetFlattenedFramesCount(); - display->total_stats().gpu_pixops_ += gpu_pixops; - display->total_stats().total_pixops_ += total_pixops; - - return *num_types ? HWC2::Error::HasChanges : HWC2::Error::None; -} - -std::tuple Backend::GetClientLayers( - DrmHwcTwo::HwcDisplay *display, - const std::map &z_map) { - int client_start = -1, client_size = 0; - - for (auto & [ z_order, layer ] : z_map) { - if (IsClientLayer(display, layer)) { - if (client_start < 0) - client_start = z_order; - client_size = (z_order - client_start) + 1; - } - } - - return std::make_tuple(client_start, client_size); -} - -bool Backend::IsClientLayer(DrmHwcTwo::HwcDisplay *display, - DrmHwcTwo::HwcLayer *layer) { - return !display->HardwareSupportsLayerType(layer->sf_type()) || - !display->importer()->CanImportBuffer(layer->buffer()) || - display->color_transform_hint() != HAL_COLOR_TRANSFORM_IDENTITY || - (layer->RequireScalingOrPhasing() && - display->resource_manager()->ForcedScalingWithGpu()); -} - -REGISTER_BACKEND("generic", Backend); - -} // namespace android diff --git a/backend/backend.h b/backend/backend.h deleted file mode 100644 index cd9d8cd..0000000 --- a/backend/backend.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_BACKEND_H -#define ANDROID_BACKEND_H - -#include "drmhwctwo.h" - -namespace android { - -class Backend { - public: - virtual ~Backend() = default; - virtual HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, - uint32_t *num_types, - uint32_t *num_requests); - virtual std::tuple GetClientLayers( - DrmHwcTwo::HwcDisplay *display, - const std::map &z_map); - virtual bool IsClientLayer(DrmHwcTwo::HwcDisplay *display, - DrmHwcTwo::HwcLayer *layer); -}; -} // namespace android - -#endif diff --git a/backend/backendclient.cpp b/backend/backendclient.cpp deleted file mode 100644 index a9418da..0000000 --- a/backend/backendclient.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2020 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 "backendclient.h" -#include "backendmanager.h" - -namespace android { - -HWC2::Error BackendClient::ValidateDisplay(DrmHwcTwo::HwcDisplay *display, - uint32_t *num_types, - uint32_t * /*num_requests*/) { - for (auto & [ layer_handle, layer ] : display->layers()) { - layer.set_validated_type(HWC2::Composition::Client); - ++*num_types; - } - return HWC2::Error::HasChanges; -} - -REGISTER_BACKEND("client", BackendClient); - -} // namespace android diff --git a/backend/backendclient.h b/backend/backendclient.h deleted file mode 100644 index 361160f..0000000 --- a/backend/backendclient.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_BACKEND_CLIENT_H -#define ANDROID_BACKEND_CLIENT_H - -#include "backend.h" -#include "drmhwctwo.h" - -namespace android { - -class BackendClient : public Backend { - public: - HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, - uint32_t *num_types, - uint32_t *num_requests) override; -}; -} // namespace android - -#endif diff --git a/backend/backendmanager.cpp b/backend/backendmanager.cpp deleted file mode 100644 index 03ad704..0000000 --- a/backend/backendmanager.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "hwc-backend" - -#include "backendmanager.h" - -#include -#include - -namespace android { - -const std::vector BackendManager::client_devices_ = { - "kirin", -}; - -BackendManager &BackendManager::GetInstance() { - static BackendManager backend_manager; - - return backend_manager; -} - -int BackendManager::RegisterBackend(const std::string &name, - backend_constructor_t backend_constructor) { - available_backends_[name] = std::move(backend_constructor); - return 0; -} - -int BackendManager::SetBackendForDisplay(DrmHwcTwo::HwcDisplay *display) { - std::string driver_name(display->drm()->GetName()); - char backend_override[PROPERTY_VALUE_MAX]; - property_get("vendor.hwc.backend_override", backend_override, - driver_name.c_str()); - std::string backend_name(std::move(backend_override)); - - display->set_backend(GetBackendByName(backend_name)); - if (!display->backend()) { - ALOGE("Failed to set backend '%s' for '%s' and driver '%s'", - backend_name.c_str(), display->connector()->name().c_str(), - driver_name.c_str()); - return -EINVAL; - } - - ALOGI("Backend '%s' for '%s' and driver '%s' was successfully set", - backend_name.c_str(), display->connector()->name().c_str(), - driver_name.c_str()); - - return 0; -} - -std::unique_ptr BackendManager::GetBackendByName(std::string &name) { - if (!available_backends_.size()) { - ALOGE("No backends are specified"); - return nullptr; - } - - auto it = available_backends_.find(name); - if (it == available_backends_.end()) { - auto it = std::find(client_devices_.begin(), client_devices_.end(), name); - name = it == client_devices_.end() ? "generic" : "client"; - } - - return available_backends_[name](); -} -} // namespace android diff --git a/backend/backendmanager.h b/backend/backendmanager.h deleted file mode 100644 index f18637d..0000000 --- a/backend/backendmanager.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_BACKEND_MANAGER_H -#define ANDROID_BACKEND_MANAGER_H - -#include -#include -#include -#include - -#include "backend.h" -#include "drmhwctwo.h" - -#define REGISTER_BACKEND(name_str_, backend_) \ - static int \ - backend = BackendManager::GetInstance() \ - .RegisterBackend(name_str_, \ - []() -> std::unique_ptr { \ - return std::make_unique(); \ - }); - -namespace android { - -class BackendManager { - public: - using backend_constructor_t = std::function()>; - static BackendManager &GetInstance(); - int RegisterBackend(const std::string &name, - backend_constructor_t backend_constructor); - int SetBackendForDisplay(DrmHwcTwo::HwcDisplay *display); - std::unique_ptr GetBackendByName(std::string &name); - HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, - uint32_t *num_types, uint32_t *num_requests); - - private: - BackendManager() = default; - - static const std::vector client_devices_; - - std::map available_backends_; -}; -} // namespace android - -#endif diff --git a/backend/backendrcardu.cpp b/backend/backendrcardu.cpp deleted file mode 100644 index d6fe7bf..0000000 --- a/backend/backendrcardu.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2020 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 "backendrcardu.h" -#include "backendmanager.h" -#include "drm_fourcc.h" - -namespace android { - -bool BackendRCarDu::IsClientLayer(DrmHwcTwo::HwcDisplay *display, - DrmHwcTwo::HwcLayer *layer) { - hwc_drm_bo_t bo; - - int ret = display->importer()->ConvertBoInfo(layer->buffer(), &bo); - if (ret) - return true; - - if (bo.format == DRM_FORMAT_ABGR8888) - return true; - - if (layer->RequireScalingOrPhasing()) - return true; - - return Backend::IsClientLayer(display, layer); -} - -REGISTER_BACKEND("rcar-du", BackendRCarDu); - -} // namespace android \ No newline at end of file diff --git a/backend/backendrcardu.h b/backend/backendrcardu.h deleted file mode 100644 index 29ccea9..0000000 --- a/backend/backendrcardu.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef HWC_DISPLAY_BACKEND_RCAR_DU_H -#define HWC_DISPLAY_BACKEND_RCAR_DU_H - -#include "backend.h" -#include "drmhwctwo.h" - -namespace android { - -class BackendRCarDu : public Backend { - public: - bool IsClientLayer(DrmHwcTwo::HwcDisplay *display, - DrmHwcTwo::HwcLayer *layer) override; -}; -} // namespace android - -#endif diff --git a/compositor/DrmDisplayComposition.cpp b/compositor/DrmDisplayComposition.cpp new file mode 100644 index 0000000..79dd470 --- /dev/null +++ b/compositor/DrmDisplayComposition.cpp @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "hwc-drm-display-composition" + +#include "DrmDisplayComposition.h" + +#include +#include +#include +#include + +#include +#include + +#include "DrmDisplayCompositor.h" +#include "drm/DrmDevice.h" +#include "platform/platform.h" + +namespace android { + +DrmDisplayComposition::~DrmDisplayComposition() { +} + +int DrmDisplayComposition::Init(DrmDevice *drm, DrmCrtc *crtc, + Importer *importer, Planner *planner, + uint64_t frame_no) { + drm_ = drm; + crtc_ = crtc; // Can be NULL if we haven't modeset yet + importer_ = importer; + planner_ = planner; + frame_no_ = frame_no; + + return 0; +} + +bool DrmDisplayComposition::validate_composition_type(DrmCompositionType des) { + return type_ == DRM_COMPOSITION_TYPE_EMPTY || type_ == des; +} + +int DrmDisplayComposition::SetLayers(DrmHwcLayer *layers, size_t num_layers, + bool geometry_changed) { + if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME)) + return -EINVAL; + + geometry_changed_ = geometry_changed; + + for (size_t layer_index = 0; layer_index < num_layers; layer_index++) { + layers_.emplace_back(std::move(layers[layer_index])); + } + + type_ = DRM_COMPOSITION_TYPE_FRAME; + return 0; +} + +int DrmDisplayComposition::SetDpmsMode(uint32_t dpms_mode) { + if (!validate_composition_type(DRM_COMPOSITION_TYPE_DPMS)) + return -EINVAL; + dpms_mode_ = dpms_mode; + type_ = DRM_COMPOSITION_TYPE_DPMS; + return 0; +} + +int DrmDisplayComposition::SetDisplayMode(const DrmMode &display_mode) { + if (!validate_composition_type(DRM_COMPOSITION_TYPE_MODESET)) + return -EINVAL; + display_mode_ = display_mode; + dpms_mode_ = DRM_MODE_DPMS_ON; + type_ = DRM_COMPOSITION_TYPE_MODESET; + return 0; +} + +int DrmDisplayComposition::AddPlaneDisable(DrmPlane *plane) { + composition_planes_.emplace_back(DrmCompositionPlane::Type::kDisable, plane, + crtc_); + return 0; +} + +int DrmDisplayComposition::AddPlaneComposition(DrmCompositionPlane plane) { + composition_planes_.emplace_back(std::move(plane)); + return 0; +} + +int DrmDisplayComposition::Plan(std::vector *primary_planes, + std::vector *overlay_planes) { + if (type_ != DRM_COMPOSITION_TYPE_FRAME) + return 0; + + std::map to_composite; + + for (size_t i = 0; i < layers_.size(); ++i) + to_composite.emplace(std::make_pair(i, &layers_[i])); + + int ret; + std::tie(ret, + composition_planes_) = planner_->ProvisionPlanes(to_composite, crtc_, + primary_planes, + overlay_planes); + if (ret) { + ALOGE("Planner failed provisioning planes ret=%d", ret); + return ret; + } + + // Remove the planes we used from the pool before returning. This ensures they + // won't be reused by another display in the composition. + for (auto &i : composition_planes_) { + if (!i.plane()) + continue; + + // make sure that source layers are ordered based on zorder + std::sort(i.source_layers().begin(), i.source_layers().end()); + + std::vector *container; + if (i.plane()->type() == DRM_PLANE_TYPE_PRIMARY) + container = primary_planes; + else + container = overlay_planes; + for (auto j = container->begin(); j != container->end(); ++j) { + if (*j == i.plane()) { + container->erase(j); + break; + } + } + } + + return 0; +} + +static const char *DrmCompositionTypeToString(DrmCompositionType type) { + switch (type) { + case DRM_COMPOSITION_TYPE_EMPTY: + return "EMPTY"; + case DRM_COMPOSITION_TYPE_FRAME: + return "FRAME"; + case DRM_COMPOSITION_TYPE_DPMS: + return "DPMS"; + case DRM_COMPOSITION_TYPE_MODESET: + return "MODESET"; + default: + return ""; + } +} + +static const char *DPMSModeToString(int dpms_mode) { + switch (dpms_mode) { + case DRM_MODE_DPMS_ON: + return "ON"; + case DRM_MODE_DPMS_OFF: + return "OFF"; + default: + return ""; + } +} + +static void DumpBuffer(const DrmHwcBuffer &buffer, std::ostringstream *out) { + if (!buffer) { + *out << "buffer="; + return; + } + + *out << "buffer[w/h/format]="; + *out << buffer->width << "/" << buffer->height << "/" << buffer->format; +} + +static void DumpTransform(uint32_t transform, std::ostringstream *out) { + *out << "["; + + if (transform == 0) + *out << "IDENTITY"; + + bool separator = false; + if (transform & DrmHwcTransform::kFlipH) { + *out << "FLIPH"; + separator = true; + } + if (transform & DrmHwcTransform::kFlipV) { + if (separator) + *out << "|"; + *out << "FLIPV"; + separator = true; + } + if (transform & DrmHwcTransform::kRotate90) { + if (separator) + *out << "|"; + *out << "ROTATE90"; + separator = true; + } + if (transform & DrmHwcTransform::kRotate180) { + if (separator) + *out << "|"; + *out << "ROTATE180"; + separator = true; + } + if (transform & DrmHwcTransform::kRotate270) { + if (separator) + *out << "|"; + *out << "ROTATE270"; + separator = true; + } + + uint32_t valid_bits = DrmHwcTransform::kFlipH | DrmHwcTransform::kFlipH | + DrmHwcTransform::kRotate90 | + DrmHwcTransform::kRotate180 | + DrmHwcTransform::kRotate270; + if (transform & ~valid_bits) { + if (separator) + *out << "|"; + *out << "INVALID"; + } + *out << "]"; +} + +static const char *BlendingToString(DrmHwcBlending blending) { + switch (blending) { + case DrmHwcBlending::kNone: + return "NONE"; + case DrmHwcBlending::kPreMult: + return "PREMULT"; + case DrmHwcBlending::kCoverage: + return "COVERAGE"; + default: + return ""; + } +} + +void DrmDisplayComposition::Dump(std::ostringstream *out) const { + *out << "----DrmDisplayComposition" + << " crtc=" << (crtc_ ? crtc_->id() : -1) + << " type=" << DrmCompositionTypeToString(type_); + + switch (type_) { + case DRM_COMPOSITION_TYPE_DPMS: + *out << " dpms_mode=" << DPMSModeToString(dpms_mode_); + break; + case DRM_COMPOSITION_TYPE_MODESET: + *out << " display_mode=" << display_mode_.h_display() << "x" + << display_mode_.v_display(); + break; + default: + break; + } + + *out << " Layers: count=" << layers_.size() << "\n"; + for (size_t i = 0; i < layers_.size(); i++) { + const DrmHwcLayer &layer = layers_[i]; + *out << " [" << i << "] "; + + DumpBuffer(layer.buffer, out); + + if (layer.protected_usage()) + *out << " protected"; + + *out << " transform="; + DumpTransform(layer.transform, out); + *out << " blending[a=" << (int)layer.alpha + << "]=" << BlendingToString(layer.blending) << "\n"; + } + + *out << " Planes: count=" << composition_planes_.size() << "\n"; + for (size_t i = 0; i < composition_planes_.size(); i++) { + const DrmCompositionPlane &comp_plane = composition_planes_[i]; + *out << " [" << i << "]" + << " plane=" << (comp_plane.plane() ? comp_plane.plane()->id() : -1) + << " type="; + switch (comp_plane.type()) { + case DrmCompositionPlane::Type::kDisable: + *out << "DISABLE"; + break; + case DrmCompositionPlane::Type::kLayer: + *out << "LAYER"; + break; + default: + *out << ""; + break; + } + + *out << " source_layer="; + for (auto i : comp_plane.source_layers()) { + *out << i << " "; + } + *out << "\n"; + } +} +} // namespace android diff --git a/compositor/DrmDisplayComposition.h b/compositor/DrmDisplayComposition.h new file mode 100644 index 0000000..73a9024 --- /dev/null +++ b/compositor/DrmDisplayComposition.h @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_DISPLAY_COMPOSITION_H_ +#define ANDROID_DRM_DISPLAY_COMPOSITION_H_ + +#include +#include + +#include +#include + +#include "drm/DrmCrtc.h" +#include "drm/DrmPlane.h" +#include "drmhwcomposer.h" + +namespace android { + +class Importer; +class Planner; +class SquashState; + +enum DrmCompositionType { + DRM_COMPOSITION_TYPE_EMPTY, + DRM_COMPOSITION_TYPE_FRAME, + DRM_COMPOSITION_TYPE_DPMS, + DRM_COMPOSITION_TYPE_MODESET, +}; + +struct DrmCompositionDisplayLayersMap { + int display; + bool geometry_changed = true; + std::vector layers; + + DrmCompositionDisplayLayersMap() = default; + DrmCompositionDisplayLayersMap(DrmCompositionDisplayLayersMap &&rhs) = + default; +}; + +struct DrmCompositionRegion { + std::vector source_layers; +}; + +class DrmCompositionPlane { + public: + enum class Type : int32_t { + kDisable, + kLayer, + }; + + DrmCompositionPlane() = default; + DrmCompositionPlane(DrmCompositionPlane &&rhs) = default; + DrmCompositionPlane &operator=(DrmCompositionPlane &&other) = default; + DrmCompositionPlane(Type type, DrmPlane *plane, DrmCrtc *crtc) + : type_(type), plane_(plane), crtc_(crtc) { + } + DrmCompositionPlane(Type type, DrmPlane *plane, DrmCrtc *crtc, + size_t source_layer) + : type_(type), + plane_(plane), + crtc_(crtc), + source_layers_(1, source_layer) { + } + + Type type() const { + return type_; + } + + DrmPlane *plane() const { + return plane_; + } + void set_plane(DrmPlane *plane) { + plane_ = plane; + } + + DrmCrtc *crtc() const { + return crtc_; + } + + std::vector &source_layers() { + return source_layers_; + } + + const std::vector &source_layers() const { + return source_layers_; + } + + private: + Type type_ = Type::kDisable; + DrmPlane *plane_ = NULL; + DrmCrtc *crtc_ = NULL; + std::vector source_layers_; +}; + +class DrmDisplayComposition { + public: + DrmDisplayComposition() = default; + DrmDisplayComposition(const DrmDisplayComposition &) = delete; + ~DrmDisplayComposition(); + + int Init(DrmDevice *drm, DrmCrtc *crtc, Importer *importer, Planner *planner, + uint64_t frame_no); + + int SetLayers(DrmHwcLayer *layers, size_t num_layers, bool geometry_changed); + int AddPlaneComposition(DrmCompositionPlane plane); + int AddPlaneDisable(DrmPlane *plane); + int SetDpmsMode(uint32_t dpms_mode); + int SetDisplayMode(const DrmMode &display_mode); + + int Plan(std::vector *primary_planes, + std::vector *overlay_planes); + + std::vector &layers() { + return layers_; + } + + std::vector &composition_planes() { + return composition_planes_; + } + + bool geometry_changed() const { + return geometry_changed_; + } + + uint64_t frame_no() const { + return frame_no_; + } + + DrmCompositionType type() const { + return type_; + } + + uint32_t dpms_mode() const { + return dpms_mode_; + } + + const DrmMode &display_mode() const { + return display_mode_; + } + + DrmCrtc *crtc() const { + return crtc_; + } + + Importer *importer() const { + return importer_; + } + + Planner *planner() const { + return planner_; + } + + int take_out_fence() { + return out_fence_.Release(); + } + + void set_out_fence(int out_fence) { + out_fence_.Set(out_fence); + } + + void Dump(std::ostringstream *out) const; + + private: + bool validate_composition_type(DrmCompositionType desired); + + DrmDevice *drm_ = NULL; + DrmCrtc *crtc_ = NULL; + Importer *importer_ = NULL; + Planner *planner_ = NULL; + + DrmCompositionType type_ = DRM_COMPOSITION_TYPE_EMPTY; + uint32_t dpms_mode_ = DRM_MODE_DPMS_ON; + DrmMode display_mode_; + + UniqueFd out_fence_ = -1; + + bool geometry_changed_; + std::vector layers_; + std::vector composition_planes_; + + uint64_t frame_no_ = 0; +}; +} // namespace android + +#endif // ANDROID_DRM_DISPLAY_COMPOSITION_H_ diff --git a/compositor/DrmDisplayCompositor.cpp b/compositor/DrmDisplayCompositor.cpp new file mode 100644 index 0000000..467f8ba --- /dev/null +++ b/compositor/DrmDisplayCompositor.cpp @@ -0,0 +1,1097 @@ +/* + * Copyright (C) 2015 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-display-compositor" + +#include "DrmDisplayCompositor.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "drm/DrmCrtc.h" +#include "drm/DrmDevice.h" +#include "drm/DrmPlane.h" +#include "utils/autolock.h" + +static const uint32_t kWaitWritebackFence = 100; // ms + +namespace android { + +std::ostream &operator<<(std::ostream &str, FlatteningState state) { + std::array flattenting_state_str = { + "None", "Not needed", "SF Requested", "Squashed by GPU", + "Serial", "Concurrent", + }; + + return str << flattenting_state_str[static_cast(state)]; +} + +class CompositorVsyncCallback : public VsyncCallback { + public: + CompositorVsyncCallback(DrmDisplayCompositor *compositor) + : compositor_(compositor) { + } + + void Callback(int display, int64_t timestamp) { + compositor_->Vsync(display, timestamp); + } + + private: + DrmDisplayCompositor *compositor_; +}; + +DrmDisplayCompositor::DrmDisplayCompositor() + : resource_manager_(NULL), + display_(-1), + initialized_(false), + active_(false), + use_hw_overlays_(true), + dump_frames_composited_(0), + dump_last_timestamp_ns_(0), + flatten_countdown_(FLATTEN_COUNTDOWN_INIT), + writeback_fence_(-1), + flattening_state_(FlatteningState::kNone), + frames_flattened_(0) { + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts)) + return; + dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; +} + +DrmDisplayCompositor::~DrmDisplayCompositor() { + if (!initialized_) + return; + + vsync_worker_.Exit(); + int ret = pthread_mutex_lock(&lock_); + if (ret) + ALOGE("Failed to acquire compositor lock %d", ret); + DrmDevice *drm = resource_manager_->GetDrmDevice(display_); + if (mode_.blob_id) + drm->DestroyPropertyBlob(mode_.blob_id); + if (mode_.old_blob_id) + drm->DestroyPropertyBlob(mode_.old_blob_id); + + active_composition_.reset(); + + ret = pthread_mutex_unlock(&lock_); + if (ret) + ALOGE("Failed to acquire compositor lock %d", ret); + + pthread_mutex_destroy(&lock_); +} + +int DrmDisplayCompositor::Init(ResourceManager *resource_manager, int display) { + resource_manager_ = resource_manager; + display_ = display; + DrmDevice *drm = resource_manager_->GetDrmDevice(display); + if (!drm) { + ALOGE("Could not find drmdevice for display"); + return -EINVAL; + } + int ret = pthread_mutex_init(&lock_, NULL); + if (ret) { + ALOGE("Failed to initialize drm compositor lock %d\n", ret); + return ret; + } + planner_ = Planner::CreateInstance(drm); + + vsync_worker_.Init(drm, display_); + auto callback = std::make_shared(this); + vsync_worker_.RegisterCallback(callback); + + initialized_ = true; + return 0; +} + +std::unique_ptr DrmDisplayCompositor::CreateComposition() + const { + return std::unique_ptr(new DrmDisplayComposition()); +} + +std::unique_ptr +DrmDisplayCompositor::CreateInitializedComposition() const { + DrmDevice *drm = resource_manager_->GetDrmDevice(display_); + DrmCrtc *crtc = drm->GetCrtcForDisplay(display_); + if (!crtc) { + ALOGE("Failed to find crtc for display = %d", display_); + return std::unique_ptr(); + } + std::unique_ptr comp = CreateComposition(); + std::shared_ptr importer = resource_manager_->GetImporter(display_); + if (!importer) { + ALOGE("Failed to find resources for display = %d", display_); + return std::unique_ptr(); + } + int ret = comp->Init(drm, crtc, importer.get(), planner_.get(), 0); + if (ret) { + ALOGE("Failed to init composition for display = %d", display_); + return std::unique_ptr(); + } + return comp; +} + +FlatteningState DrmDisplayCompositor::GetFlatteningState() const { + return flattening_state_; +} + +uint32_t DrmDisplayCompositor::GetFlattenedFramesCount() const { + return frames_flattened_; +} + +bool DrmDisplayCompositor::ShouldFlattenOnClient() const { + return flattening_state_ == FlatteningState::kClientRequested || + flattening_state_ == FlatteningState::kClientDone; +} + +std::tuple +DrmDisplayCompositor::GetActiveModeResolution() { + DrmDevice *drm = resource_manager_->GetDrmDevice(display_); + DrmConnector *connector = drm->GetConnectorForDisplay(display_); + if (connector == NULL) { + ALOGE("Failed to determine display mode: no connector for display %d", + display_); + return std::make_tuple(0, 0, -ENODEV); + } + + const DrmMode &mode = connector->active_mode(); + return std::make_tuple(mode.h_display(), mode.v_display(), 0); +} + +int DrmDisplayCompositor::DisablePlanes(DrmDisplayComposition *display_comp) { + drmModeAtomicReqPtr pset = drmModeAtomicAlloc(); + if (!pset) { + ALOGE("Failed to allocate property set"); + return -ENOMEM; + } + + int ret; + std::vector &comp_planes = display_comp + ->composition_planes(); + for (DrmCompositionPlane &comp_plane : comp_planes) { + DrmPlane *plane = comp_plane.plane(); + ret = drmModeAtomicAddProperty(pset, plane->id(), + plane->crtc_property().id(), 0) < 0 || + drmModeAtomicAddProperty(pset, plane->id(), plane->fb_property().id(), + 0) < 0; + if (ret) { + ALOGE("Failed to add plane %d disable to pset", plane->id()); + drmModeAtomicFree(pset); + return ret; + } + } + DrmDevice *drm = resource_manager_->GetDrmDevice(display_); + ret = drmModeAtomicCommit(drm->fd(), pset, 0, drm); + if (ret) { + ALOGE("Failed to commit pset ret=%d\n", ret); + drmModeAtomicFree(pset); + return ret; + } + + drmModeAtomicFree(pset); + return 0; +} + +int DrmDisplayCompositor::SetupWritebackCommit(drmModeAtomicReqPtr pset, + uint32_t crtc_id, + DrmConnector *writeback_conn, + DrmHwcBuffer *writeback_buffer) { + int ret = 0; + if (writeback_conn->writeback_fb_id().id() == 0 || + writeback_conn->writeback_out_fence().id() == 0) { + ALOGE("Writeback properties don't exit"); + return -EINVAL; + } + if ((*writeback_buffer)->fb_id == 0) { + ALOGE("Invalid writeback buffer"); + return -EINVAL; + } + ret = drmModeAtomicAddProperty(pset, writeback_conn->id(), + writeback_conn->writeback_fb_id().id(), + (*writeback_buffer)->fb_id); + if (ret < 0) { + ALOGE("Failed to add writeback_fb_id"); + return ret; + } + ret = drmModeAtomicAddProperty(pset, writeback_conn->id(), + writeback_conn->writeback_out_fence().id(), + (uint64_t)&writeback_fence_); + if (ret < 0) { + ALOGE("Failed to add writeback_out_fence"); + return ret; + } + + ret = drmModeAtomicAddProperty(pset, writeback_conn->id(), + writeback_conn->crtc_id_property().id(), + crtc_id); + if (ret < 0) { + ALOGE("Failed to attach writeback"); + return ret; + } + return 0; +} + +int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp, + bool test_only, + DrmConnector *writeback_conn, + DrmHwcBuffer *writeback_buffer) { + ATRACE_CALL(); + + int ret = 0; + + std::vector &layers = display_comp->layers(); + std::vector &comp_planes = display_comp + ->composition_planes(); + DrmDevice *drm = resource_manager_->GetDrmDevice(display_); + uint64_t out_fences[drm->crtcs().size()]; + + DrmConnector *connector = drm->GetConnectorForDisplay(display_); + if (!connector) { + ALOGE("Could not locate connector for display %d", display_); + return -ENODEV; + } + DrmCrtc *crtc = drm->GetCrtcForDisplay(display_); + if (!crtc) { + ALOGE("Could not locate crtc for display %d", display_); + return -ENODEV; + } + + drmModeAtomicReqPtr pset = drmModeAtomicAlloc(); + if (!pset) { + ALOGE("Failed to allocate property set"); + return -ENOMEM; + } + + if (writeback_buffer != NULL) { + if (writeback_conn == NULL) { + ALOGE("Invalid arguments requested writeback without writeback conn"); + return -EINVAL; + } + ret = SetupWritebackCommit(pset, crtc->id(), writeback_conn, + writeback_buffer); + if (ret < 0) { + ALOGE("Failed to Setup Writeback Commit ret = %d", ret); + return ret; + } + } + if (crtc->out_fence_ptr_property().id() != 0) { + ret = drmModeAtomicAddProperty(pset, crtc->id(), + crtc->out_fence_ptr_property().id(), + (uint64_t)&out_fences[crtc->pipe()]); + if (ret < 0) { + ALOGE("Failed to add OUT_FENCE_PTR property to pset: %d", ret); + drmModeAtomicFree(pset); + return ret; + } + } + + if (mode_.needs_modeset) { + ret = drmModeAtomicAddProperty(pset, crtc->id(), + crtc->active_property().id(), 1); + if (ret < 0) { + ALOGE("Failed to add crtc active to pset\n"); + drmModeAtomicFree(pset); + return ret; + } + + ret = drmModeAtomicAddProperty(pset, crtc->id(), crtc->mode_property().id(), + mode_.blob_id) < 0 || + drmModeAtomicAddProperty(pset, connector->id(), + connector->crtc_id_property().id(), + crtc->id()) < 0; + if (ret) { + ALOGE("Failed to add blob %d to pset", mode_.blob_id); + drmModeAtomicFree(pset); + return ret; + } + } + + for (DrmCompositionPlane &comp_plane : comp_planes) { + DrmPlane *plane = comp_plane.plane(); + DrmCrtc *crtc = comp_plane.crtc(); + std::vector &source_layers = comp_plane.source_layers(); + + int fb_id = -1; + int fence_fd = -1; + hwc_rect_t display_frame; + hwc_frect_t source_crop; + uint64_t rotation = 0; + uint64_t alpha = 0xFFFF; + uint64_t blend; + + if (comp_plane.type() != DrmCompositionPlane::Type::kDisable) { + if (source_layers.size() > 1) { + ALOGE("Can't handle more than one source layer sz=%zu type=%d", + source_layers.size(), comp_plane.type()); + continue; + } + + if (source_layers.empty() || source_layers.front() >= layers.size()) { + ALOGE("Source layer index %zu out of bounds %zu type=%d", + source_layers.front(), layers.size(), comp_plane.type()); + break; + } + DrmHwcLayer &layer = layers[source_layers.front()]; + if (!layer.buffer) { + ALOGE("Expected a valid framebuffer for pset"); + break; + } + fb_id = layer.buffer->fb_id; + fence_fd = layer.acquire_fence.get(); + display_frame = layer.display_frame; + source_crop = layer.source_crop; + alpha = layer.alpha; + + if (plane->blend_property().id()) { + switch (layer.blending) { + case DrmHwcBlending::kPreMult: + std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName( + "Pre-multiplied"); + break; + case DrmHwcBlending::kCoverage: + std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName( + "Coverage"); + break; + case DrmHwcBlending::kNone: + default: + std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName( + "None"); + break; + } + } + + if (plane->zpos_property().id() && + !plane->zpos_property().is_immutable()) { + uint64_t min_zpos = 0; + + // Ignore ret and use min_zpos as 0 by default + std::tie(std::ignore, min_zpos) = plane->zpos_property().range_min(); + + ret = drmModeAtomicAddProperty(pset, plane->id(), + plane->zpos_property().id(), + source_layers.front() + min_zpos) < 0; + if (ret) { + ALOGE("Failed to add zpos property %d to plane %d", + plane->zpos_property().id(), plane->id()); + break; + } + } + + rotation = 0; + if (layer.transform & DrmHwcTransform::kFlipH) + rotation |= DRM_MODE_REFLECT_X; + if (layer.transform & DrmHwcTransform::kFlipV) + rotation |= DRM_MODE_REFLECT_Y; + if (layer.transform & DrmHwcTransform::kRotate90) + rotation |= DRM_MODE_ROTATE_90; + else if (layer.transform & DrmHwcTransform::kRotate180) + rotation |= DRM_MODE_ROTATE_180; + else if (layer.transform & DrmHwcTransform::kRotate270) + rotation |= DRM_MODE_ROTATE_270; + else + rotation |= DRM_MODE_ROTATE_0; + + if (fence_fd >= 0) { + int prop_id = plane->in_fence_fd_property().id(); + if (prop_id == 0) { + ALOGE("Failed to get IN_FENCE_FD property id"); + break; + } + ret = drmModeAtomicAddProperty(pset, plane->id(), prop_id, fence_fd); + if (ret < 0) { + ALOGE("Failed to add IN_FENCE_FD property to pset: %d", ret); + break; + } + } + } + + // Disable the plane if there's no framebuffer + if (fb_id < 0) { + ret = drmModeAtomicAddProperty(pset, plane->id(), + plane->crtc_property().id(), 0) < 0 || + drmModeAtomicAddProperty(pset, plane->id(), + plane->fb_property().id(), 0) < 0; + if (ret) { + ALOGE("Failed to add plane %d disable to pset", plane->id()); + break; + } + continue; + } + + ret = drmModeAtomicAddProperty(pset, plane->id(), + plane->crtc_property().id(), crtc->id()) < 0; + ret |= drmModeAtomicAddProperty(pset, plane->id(), + plane->fb_property().id(), fb_id) < 0; + ret |= drmModeAtomicAddProperty(pset, plane->id(), + plane->crtc_x_property().id(), + display_frame.left) < 0; + ret |= drmModeAtomicAddProperty(pset, plane->id(), + plane->crtc_y_property().id(), + display_frame.top) < 0; + ret |= drmModeAtomicAddProperty(pset, plane->id(), + plane->crtc_w_property().id(), + display_frame.right - display_frame.left) < + 0; + ret |= drmModeAtomicAddProperty(pset, plane->id(), + plane->crtc_h_property().id(), + display_frame.bottom - display_frame.top) < + 0; + ret |= drmModeAtomicAddProperty(pset, plane->id(), + plane->src_x_property().id(), + (int)(source_crop.left) << 16) < 0; + ret |= drmModeAtomicAddProperty(pset, plane->id(), + plane->src_y_property().id(), + (int)(source_crop.top) << 16) < 0; + ret |= drmModeAtomicAddProperty(pset, plane->id(), + plane->src_w_property().id(), + (int)(source_crop.right - source_crop.left) + << 16) < 0; + ret |= drmModeAtomicAddProperty(pset, plane->id(), + plane->src_h_property().id(), + (int)(source_crop.bottom - source_crop.top) + << 16) < 0; + if (ret) { + ALOGE("Failed to add plane %d to set", plane->id()); + break; + } + + if (plane->rotation_property().id()) { + ret = drmModeAtomicAddProperty(pset, plane->id(), + plane->rotation_property().id(), + rotation) < 0; + if (ret) { + ALOGE("Failed to add rotation property %d to plane %d", + plane->rotation_property().id(), plane->id()); + break; + } + } + + if (plane->alpha_property().id()) { + ret = drmModeAtomicAddProperty(pset, plane->id(), + plane->alpha_property().id(), alpha) < 0; + if (ret) { + ALOGE("Failed to add alpha property %d to plane %d", + plane->alpha_property().id(), plane->id()); + break; + } + } + + if (plane->blend_property().id()) { + ret = drmModeAtomicAddProperty(pset, plane->id(), + plane->blend_property().id(), blend) < 0; + if (ret) { + ALOGE("Failed to add pixel blend mode property %d to plane %d", + plane->blend_property().id(), plane->id()); + break; + } + } + } + + if (!ret) { + uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET; + if (test_only) + flags |= DRM_MODE_ATOMIC_TEST_ONLY; + + ret = drmModeAtomicCommit(drm->fd(), pset, flags, drm); + if (ret) { + if (!test_only) + ALOGE("Failed to commit pset ret=%d\n", ret); + drmModeAtomicFree(pset); + return ret; + } + } + if (pset) + drmModeAtomicFree(pset); + + if (!test_only && mode_.needs_modeset) { + ret = drm->DestroyPropertyBlob(mode_.old_blob_id); + if (ret) { + ALOGE("Failed to destroy old mode property blob %" PRIu32 "/%d", + mode_.old_blob_id, ret); + return ret; + } + + /* TODO: Add dpms to the pset when the kernel supports it */ + ret = ApplyDpms(display_comp); + if (ret) { + ALOGE("Failed to apply DPMS after modeset %d\n", ret); + return ret; + } + + connector->set_active_mode(mode_.mode); + mode_.old_blob_id = mode_.blob_id; + mode_.blob_id = 0; + mode_.needs_modeset = false; + } + + if (crtc->out_fence_ptr_property().id()) { + display_comp->set_out_fence((int)out_fences[crtc->pipe()]); + } + + return ret; +} + +int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) { + DrmDevice *drm = resource_manager_->GetDrmDevice(display_); + DrmConnector *conn = drm->GetConnectorForDisplay(display_); + if (!conn) { + ALOGE("Failed to get DrmConnector for display %d", display_); + return -ENODEV; + } + + const DrmProperty &prop = conn->dpms_property(); + int ret = drmModeConnectorSetProperty(drm->fd(), conn->id(), prop.id(), + display_comp->dpms_mode()); + if (ret) { + ALOGE("Failed to set DPMS property for connector %d", conn->id()); + return ret; + } + return 0; +} + +std::tuple DrmDisplayCompositor::CreateModeBlob( + const DrmMode &mode) { + struct drm_mode_modeinfo drm_mode; + memset(&drm_mode, 0, sizeof(drm_mode)); + mode.ToDrmModeModeInfo(&drm_mode); + + uint32_t id = 0; + DrmDevice *drm = resource_manager_->GetDrmDevice(display_); + int ret = drm->CreatePropertyBlob(&drm_mode, sizeof(struct drm_mode_modeinfo), + &id); + if (ret) { + ALOGE("Failed to create mode property blob %d", ret); + return std::make_tuple(ret, 0); + } + ALOGE("Create blob_id %" PRIu32 "\n", id); + return std::make_tuple(ret, id); +} + +void DrmDisplayCompositor::ClearDisplay() { + if (!active_composition_) + return; + + if (DisablePlanes(active_composition_.get())) + return; + + active_composition_.reset(NULL); + vsync_worker_.VSyncControl(false); +} + +void DrmDisplayCompositor::ApplyFrame( + std::unique_ptr composition, int status, + bool writeback) { + AutoLock lock(&lock_, __func__); + if (lock.Lock()) + return; + int ret = status; + + if (!ret) { + if (writeback && !CountdownExpired()) { + ALOGE("Abort playing back scene"); + return; + } + ret = CommitFrame(composition.get(), false); + } + + if (ret) { + ALOGE("Composite failed for display %d", display_); + // Disable the hw used by the last active composition. This allows us to + // signal the release fences from that composition to avoid hanging. + ClearDisplay(); + return; + } + ++dump_frames_composited_; + + active_composition_.swap(composition); + + flatten_countdown_ = FLATTEN_COUNTDOWN_INIT; + if (flattening_state_ != FlatteningState::kClientRequested) { + SetFlattening(FlatteningState::kNone); + } else { + SetFlattening(FlatteningState::kClientDone); + } + vsync_worker_.VSyncControl(!writeback); +} + +int DrmDisplayCompositor::ApplyComposition( + std::unique_ptr composition) { + int ret = 0; + switch (composition->type()) { + case DRM_COMPOSITION_TYPE_FRAME: + if (composition->geometry_changed()) { + // Send the composition to the kernel to ensure we can commit it. This + // is just a test, it won't actually commit the frame. + ret = CommitFrame(composition.get(), true); + if (ret) { + ALOGE("Commit test failed for display %d, FIXME", display_); + return ret; + } + } + + ApplyFrame(std::move(composition), ret); + break; + case DRM_COMPOSITION_TYPE_DPMS: + active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON); + ret = ApplyDpms(composition.get()); + if (ret) + ALOGE("Failed to apply dpms for display %d", display_); + return ret; + case DRM_COMPOSITION_TYPE_MODESET: + mode_.mode = composition->display_mode(); + if (mode_.blob_id) + resource_manager_->GetDrmDevice(display_)->DestroyPropertyBlob( + mode_.blob_id); + std::tie(ret, mode_.blob_id) = CreateModeBlob(mode_.mode); + if (ret) { + ALOGE("Failed to create mode blob for display %d", display_); + return ret; + } + mode_.needs_modeset = true; + return 0; + default: + ALOGE("Unknown composition type %d", composition->type()); + return -EINVAL; + } + + return ret; +} + +int DrmDisplayCompositor::TestComposition(DrmDisplayComposition *composition) { + return CommitFrame(composition, true); +} + +// Flatten a scene on the display by using a writeback connector +// and returns the composition result as a DrmHwcLayer. +int DrmDisplayCompositor::FlattenOnDisplay( + std::unique_ptr &src, DrmConnector *writeback_conn, + DrmMode &src_mode, DrmHwcLayer *writeback_layer) { + int ret = 0; + DrmDevice *drm = resource_manager_->GetDrmDevice(display_); + ret = writeback_conn->UpdateModes(); + if (ret) { + ALOGE("Failed to update modes %d", ret); + return ret; + } + for (const DrmMode &mode : writeback_conn->modes()) { + if (mode.h_display() == src_mode.h_display() && + mode.v_display() == src_mode.v_display()) { + mode_.mode = mode; + if (mode_.blob_id) + drm->DestroyPropertyBlob(mode_.blob_id); + std::tie(ret, mode_.blob_id) = CreateModeBlob(mode_.mode); + if (ret) { + ALOGE("Failed to create mode blob for display %d", display_); + return ret; + } + mode_.needs_modeset = true; + break; + } + } + if (mode_.blob_id <= 0) { + ALOGE("Failed to find similar mode"); + return -EINVAL; + } + + DrmCrtc *crtc = drm->GetCrtcForDisplay(display_); + if (!crtc) { + ALOGE("Failed to find crtc for display %d", display_); + return -EINVAL; + } + // TODO what happens if planes could go to both CRTCs, I don't think it's + // handled anywhere + std::vector primary_planes; + std::vector overlay_planes; + for (auto &plane : drm->planes()) { + if (!plane->GetCrtcSupported(*crtc)) + continue; + if (plane->type() == DRM_PLANE_TYPE_PRIMARY) + primary_planes.push_back(plane.get()); + else if (plane->type() == DRM_PLANE_TYPE_OVERLAY) + overlay_planes.push_back(plane.get()); + } + + ret = src->Plan(&primary_planes, &overlay_planes); + if (ret) { + ALOGE("Failed to plan the composition ret = %d", ret); + return ret; + } + + // Disable the planes we're not using + for (auto i = primary_planes.begin(); i != primary_planes.end();) { + src->AddPlaneDisable(*i); + i = primary_planes.erase(i); + } + for (auto i = overlay_planes.begin(); i != overlay_planes.end();) { + src->AddPlaneDisable(*i); + i = overlay_planes.erase(i); + } + + AutoLock lock(&lock_, __func__); + ret = lock.Lock(); + if (ret) + return ret; + DrmFramebuffer *writeback_fb = &framebuffers_[framebuffer_index_]; + framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS; + if (!writeback_fb->Allocate(mode_.mode.h_display(), mode_.mode.v_display())) { + ALOGE("Failed to allocate writeback buffer"); + return -ENOMEM; + } + DrmHwcBuffer *writeback_buffer = &writeback_layer->buffer; + writeback_layer->sf_handle = writeback_fb->buffer()->handle; + ret = writeback_layer->ImportBuffer( + resource_manager_->GetImporter(display_).get()); + if (ret) { + ALOGE("Failed to import writeback buffer"); + return ret; + } + + ret = CommitFrame(src.get(), true, writeback_conn, writeback_buffer); + if (ret) { + ALOGE("Atomic check failed"); + return ret; + } + ret = CommitFrame(src.get(), false, writeback_conn, writeback_buffer); + if (ret) { + ALOGE("Atomic commit failed"); + return ret; + } + + ret = sync_wait(writeback_fence_, kWaitWritebackFence); + writeback_layer->acquire_fence.Set(writeback_fence_); + writeback_fence_ = -1; + if (ret) { + ALOGE("Failed to wait on writeback fence"); + return ret; + } + return 0; +} + +void DrmDisplayCompositor::SetFlattening(FlatteningState new_state) { + if (flattening_state_ != new_state) { + switch (flattening_state_) { + case FlatteningState::kClientDone: + case FlatteningState::kConcurrent: + case FlatteningState::kSerial: + ++frames_flattened_; + break; + case FlatteningState::kClientRequested: + case FlatteningState::kNone: + case FlatteningState::kNotNeeded: + break; + } + } + flattening_state_ = new_state; +} + +bool DrmDisplayCompositor::IsFlatteningNeeded() const { + return CountdownExpired() && active_composition_->layers().size() >= 2; +} + +int DrmDisplayCompositor::FlattenOnClient() { + if (refresh_display_cb_) { + { + AutoLock lock(&lock_, __func__); + if (!IsFlatteningNeeded()) { + if (flattening_state_ != FlatteningState::kClientDone) { + ALOGV("Flattening is not needed"); + SetFlattening(FlatteningState::kNotNeeded); + } + return -EALREADY; + } + } + + ALOGV( + "No writeback connector available, " + "falling back to client composition"); + SetFlattening(FlatteningState::kClientRequested); + refresh_display_cb_(display_); + return 0; + } else { + ALOGV("No writeback connector available"); + return -EINVAL; + } +} + +// Flatten a scene by enabling the writeback connector attached +// to the same CRTC as the one driving the display. +int DrmDisplayCompositor::FlattenSerial(DrmConnector *writeback_conn) { + ALOGV("FlattenSerial by enabling writeback connector to the same crtc"); + // Flattened composition with only one layer that is obtained + // using the writeback connector + std::unique_ptr + writeback_comp = CreateInitializedComposition(); + if (!writeback_comp) + return -EINVAL; + + AutoLock lock(&lock_, __func__); + int ret = lock.Lock(); + if (ret) + return ret; + if (!IsFlatteningNeeded()) { + ALOGV("Flattening is not needed"); + SetFlattening(FlatteningState::kNotNeeded); + return -EALREADY; + } + + DrmFramebuffer *writeback_fb = &framebuffers_[framebuffer_index_]; + framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS; + lock.Unlock(); + + if (!writeback_fb->Allocate(mode_.mode.h_display(), mode_.mode.v_display())) { + ALOGE("Failed to allocate writeback buffer"); + return -ENOMEM; + } + writeback_comp->layers().emplace_back(); + + DrmHwcLayer &writeback_layer = writeback_comp->layers().back(); + writeback_layer.sf_handle = writeback_fb->buffer()->handle; + writeback_layer.source_crop = {0, 0, (float)mode_.mode.h_display(), + (float)mode_.mode.v_display()}; + writeback_layer.display_frame = {0, 0, (int)mode_.mode.h_display(), + (int)mode_.mode.v_display()}; + ret = writeback_layer.ImportBuffer( + resource_manager_->GetImporter(display_).get()); + if (ret || writeback_comp->layers().size() != 1) { + ALOGE("Failed to import writeback buffer"); + return ret; + } + + drmModeAtomicReqPtr pset = drmModeAtomicAlloc(); + if (!pset) { + ALOGE("Failed to allocate property set"); + return -ENOMEM; + } + DrmDevice *drm = resource_manager_->GetDrmDevice(display_); + DrmCrtc *crtc = drm->GetCrtcForDisplay(display_); + if (!crtc) { + ALOGE("Failed to find crtc for display %d", display_); + return -EINVAL; + } + ret = SetupWritebackCommit(pset, crtc->id(), writeback_conn, + &writeback_layer.buffer); + if (ret < 0) { + ALOGE("Failed to Setup Writeback Commit"); + return ret; + } + ret = drmModeAtomicCommit(drm->fd(), pset, 0, drm); + if (ret) { + ALOGE("Failed to enable writeback %d", ret); + return ret; + } + ret = sync_wait(writeback_fence_, kWaitWritebackFence); + writeback_layer.acquire_fence.Set(writeback_fence_); + writeback_fence_ = -1; + if (ret) { + ALOGE("Failed to wait on writeback fence"); + return ret; + } + + DrmCompositionPlane squashed_comp(DrmCompositionPlane::Type::kLayer, NULL, + crtc); + for (auto &drmplane : drm->planes()) { + if (!drmplane->GetCrtcSupported(*crtc)) + continue; + if (!squashed_comp.plane() && drmplane->type() == DRM_PLANE_TYPE_PRIMARY) + squashed_comp.set_plane(drmplane.get()); + else + writeback_comp->AddPlaneDisable(drmplane.get()); + } + squashed_comp.source_layers().push_back(0); + ret = writeback_comp->AddPlaneComposition(std::move(squashed_comp)); + if (ret) { + ALOGE("Failed to add flatten scene"); + return ret; + } + + ApplyFrame(std::move(writeback_comp), 0, true); + return 0; +} + +// Flatten a scene by using a crtc which works concurrent with +// the one driving the display. +int DrmDisplayCompositor::FlattenConcurrent(DrmConnector *writeback_conn) { + ALOGV("FlattenConcurrent by using an unused crtc/display"); + int ret = 0; + DrmDisplayCompositor drmdisplaycompositor; + ret = drmdisplaycompositor.Init(resource_manager_, writeback_conn->display()); + if (ret) { + ALOGE("Failed to init drmdisplaycompositor = %d", ret); + return ret; + } + // Copy of the active_composition, needed because of two things: + // 1) Not to hold the lock for the whole time we are accessing + // active_composition + // 2) It will be committed on a crtc that might not be on the same + // dri node, so buffers need to be imported on the right node. + std::unique_ptr + copy_comp = drmdisplaycompositor.CreateInitializedComposition(); + + // Writeback composition that will be committed to the display. + std::unique_ptr + writeback_comp = CreateInitializedComposition(); + + if (!copy_comp || !writeback_comp) + return -EINVAL; + AutoLock lock(&lock_, __func__); + ret = lock.Lock(); + if (ret) + return ret; + if (!IsFlatteningNeeded()) { + ALOGV("Flattening is not needed"); + SetFlattening(FlatteningState::kNotNeeded); + return -EALREADY; + } + DrmCrtc *crtc = active_composition_->crtc(); + + std::vector copy_layers; + for (DrmHwcLayer &src_layer : active_composition_->layers()) { + DrmHwcLayer copy; + ret = copy.InitFromDrmHwcLayer(&src_layer, + resource_manager_ + ->GetImporter(writeback_conn->display()) + .get()); + if (ret) { + ALOGE("Failed to import buffer ret = %d", ret); + return -EINVAL; + } + copy_layers.emplace_back(std::move(copy)); + } + ret = copy_comp->SetLayers(copy_layers.data(), copy_layers.size(), true); + if (ret) { + ALOGE("Failed to set copy_comp layers"); + return ret; + } + + lock.Unlock(); + DrmHwcLayer writeback_layer; + ret = drmdisplaycompositor.FlattenOnDisplay(copy_comp, writeback_conn, + mode_.mode, &writeback_layer); + if (ret) { + ALOGE("Failed to flatten on display ret = %d", ret); + return ret; + } + + DrmCompositionPlane squashed_comp(DrmCompositionPlane::Type::kLayer, NULL, + crtc); + for (auto &drmplane : resource_manager_->GetDrmDevice(display_)->planes()) { + if (!drmplane->GetCrtcSupported(*crtc)) + continue; + if (drmplane->type() == DRM_PLANE_TYPE_PRIMARY) + squashed_comp.set_plane(drmplane.get()); + else + writeback_comp->AddPlaneDisable(drmplane.get()); + } + writeback_comp->layers().emplace_back(); + DrmHwcLayer &next_layer = writeback_comp->layers().back(); + next_layer.sf_handle = writeback_layer.get_usable_handle(); + next_layer.blending = DrmHwcBlending::kPreMult; + next_layer.source_crop = {0, 0, (float)mode_.mode.h_display(), + (float)mode_.mode.v_display()}; + next_layer.display_frame = {0, 0, (int)mode_.mode.h_display(), + (int)mode_.mode.v_display()}; + ret = next_layer.ImportBuffer(resource_manager_->GetImporter(display_).get()); + if (ret) { + ALOGE("Failed to import framebuffer for display %d", ret); + return ret; + } + squashed_comp.source_layers().push_back(0); + ret = writeback_comp->AddPlaneComposition(std::move(squashed_comp)); + if (ret) { + ALOGE("Failed to add plane composition %d", ret); + return ret; + } + ApplyFrame(std::move(writeback_comp), 0, true); + return ret; +} + +int DrmDisplayCompositor::FlattenActiveComposition() { + DrmConnector *writeback_conn = resource_manager_->AvailableWritebackConnector( + display_); + if (!active_composition_ || !writeback_conn) { + // Try to fallback to GPU composition on client, since it is more + // power-efficient than composition on device side + return FlattenOnClient(); + } + + if (writeback_conn->display() != display_) { + SetFlattening(FlatteningState::kConcurrent); + return FlattenConcurrent(writeback_conn); + } else { + SetFlattening(FlatteningState::kSerial); + return FlattenSerial(writeback_conn); + } + + return 0; +} + +bool DrmDisplayCompositor::CountdownExpired() const { + return flatten_countdown_ <= 0; +} + +void DrmDisplayCompositor::Vsync(int display, int64_t timestamp) { + AutoLock lock(&lock_, __func__); + if (lock.Lock()) + return; + flatten_countdown_--; + if (!CountdownExpired()) + return; + lock.Unlock(); + int ret = FlattenActiveComposition(); + ALOGV("scene flattening triggered for display %d at timestamp %" PRIu64 + " result = %d \n", + display, timestamp, ret); +} + +void DrmDisplayCompositor::Dump(std::ostringstream *out) const { + int ret = pthread_mutex_lock(&lock_); + if (ret) + return; + + uint64_t num_frames = dump_frames_composited_; + dump_frames_composited_ = 0; + + struct timespec ts; + ret = clock_gettime(CLOCK_MONOTONIC, &ts); + if (ret) { + pthread_mutex_unlock(&lock_); + return; + } + + uint64_t cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; + uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000); + float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f; + + *out << "--DrmDisplayCompositor[" << display_ + << "]: num_frames=" << num_frames << " num_ms=" << num_ms + << " fps=" << fps << "\n"; + + dump_last_timestamp_ns_ = cur_ts; + + pthread_mutex_unlock(&lock_); +} +} // namespace android diff --git a/compositor/DrmDisplayCompositor.h b/compositor/DrmDisplayCompositor.h new file mode 100644 index 0000000..e500c9e --- /dev/null +++ b/compositor/DrmDisplayCompositor.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_DISPLAY_COMPOSITOR_H_ +#define ANDROID_DRM_DISPLAY_COMPOSITOR_H_ + +#include +#include +#include + +#include +#include +#include + +#include "DrmDisplayComposition.h" +#include "DrmFramebuffer.h" +#include "drm/ResourceManager.h" +#include "drm/VSyncWorker.h" +#include "drmhwcomposer.h" + +// One for the front, one for the back, and one for cases where we need to +// squash a frame that the hw can't display with hw overlays. +#define DRM_DISPLAY_BUFFERS 3 + +// If a scene is still for this number of vblanks flatten it to reduce power +// consumption. +#define FLATTEN_COUNTDOWN_INIT 60 + +namespace android { + +enum class FlatteningState { + kNone, + kNotNeeded, + kClientRequested, + kClientDone, + kSerial, + kConcurrent +}; + +std::ostream &operator<<(std::ostream &str, FlatteningState state); + +class DrmDisplayCompositor { + public: + DrmDisplayCompositor(); + ~DrmDisplayCompositor(); + + int Init(ResourceManager *resource_manager, int display); + + template + void SetRefreshCallback(Fn &&refresh_cb) { + refresh_display_cb_ = std::forward(refresh_cb); + } + + std::unique_ptr CreateComposition() const; + std::unique_ptr CreateInitializedComposition() const; + int ApplyComposition(std::unique_ptr composition); + int TestComposition(DrmDisplayComposition *composition); + int Composite(); + void Dump(std::ostringstream *out) const; + void Vsync(int display, int64_t timestamp); + void ClearDisplay(); + int TakeOutFence() { + if (!active_composition_) + return -1; + return active_composition_->take_out_fence(); + } + + FlatteningState GetFlatteningState() const; + uint32_t GetFlattenedFramesCount() const; + bool ShouldFlattenOnClient() const; + + std::tuple GetActiveModeResolution(); + + private: + struct ModeState { + bool needs_modeset = false; + DrmMode mode; + uint32_t blob_id = 0; + uint32_t old_blob_id = 0; + }; + + DrmDisplayCompositor(const DrmDisplayCompositor &) = delete; + + // We'll wait for acquire fences to fire for kAcquireWaitTimeoutMs, + // kAcquireWaitTries times, logging a warning in between. + static const int kAcquireWaitTries = 5; + static const int kAcquireWaitTimeoutMs = 100; + + int CommitFrame(DrmDisplayComposition *display_comp, bool test_only, + DrmConnector *writeback_conn = NULL, + DrmHwcBuffer *writeback_buffer = NULL); + int SetupWritebackCommit(drmModeAtomicReqPtr pset, uint32_t crtc_id, + DrmConnector *writeback_conn, + DrmHwcBuffer *writeback_buffer); + int ApplyDpms(DrmDisplayComposition *display_comp); + int DisablePlanes(DrmDisplayComposition *display_comp); + + void ApplyFrame(std::unique_ptr composition, + int status, bool writeback = false); + + void SetFlattening(FlatteningState new_state); + bool IsFlatteningNeeded() const; + int FlattenActiveComposition(); + int FlattenOnClient(); + int FlattenSerial(DrmConnector *writeback_conn); + int FlattenConcurrent(DrmConnector *writeback_conn); + int FlattenOnDisplay(std::unique_ptr &src, + DrmConnector *writeback_conn, DrmMode &src_mode, + DrmHwcLayer *writeback_layer); + + bool CountdownExpired() const; + + std::tuple CreateModeBlob(const DrmMode &mode); + + ResourceManager *resource_manager_; + int display_; + + std::unique_ptr active_composition_; + + bool initialized_; + bool active_; + bool use_hw_overlays_; + + ModeState mode_; + + int framebuffer_index_; + DrmFramebuffer framebuffers_[DRM_DISPLAY_BUFFERS]; + + // mutable since we need to acquire in Dump() + mutable pthread_mutex_t lock_; + + // State tracking progress since our last Dump(). These are mutable since + // we need to reset them on every Dump() call. + mutable uint64_t dump_frames_composited_; + mutable uint64_t dump_last_timestamp_ns_; + VSyncWorker vsync_worker_; + int64_t flatten_countdown_; + std::unique_ptr planner_; + int writeback_fence_; + + FlatteningState flattening_state_; + uint32_t frames_flattened_; + + std::function refresh_display_cb_; +}; +} // namespace android + +#endif // ANDROID_DRM_DISPLAY_COMPOSITOR_H_ diff --git a/compositor/drmdisplaycomposition.cpp b/compositor/drmdisplaycomposition.cpp deleted file mode 100644 index 82d7194..0000000 --- a/compositor/drmdisplaycomposition.cpp +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "hwc-drm-display-composition" - -#include "drmdisplaycomposition.h" - -#include -#include -#include -#include - -#include -#include - -#include "drm/drmdevice.h" -#include "drmdisplaycompositor.h" -#include "platform/platform.h" - -namespace android { - -DrmDisplayComposition::~DrmDisplayComposition() { -} - -int DrmDisplayComposition::Init(DrmDevice *drm, DrmCrtc *crtc, - Importer *importer, Planner *planner, - uint64_t frame_no) { - drm_ = drm; - crtc_ = crtc; // Can be NULL if we haven't modeset yet - importer_ = importer; - planner_ = planner; - frame_no_ = frame_no; - - return 0; -} - -bool DrmDisplayComposition::validate_composition_type(DrmCompositionType des) { - return type_ == DRM_COMPOSITION_TYPE_EMPTY || type_ == des; -} - -int DrmDisplayComposition::SetLayers(DrmHwcLayer *layers, size_t num_layers, - bool geometry_changed) { - if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME)) - return -EINVAL; - - geometry_changed_ = geometry_changed; - - for (size_t layer_index = 0; layer_index < num_layers; layer_index++) { - layers_.emplace_back(std::move(layers[layer_index])); - } - - type_ = DRM_COMPOSITION_TYPE_FRAME; - return 0; -} - -int DrmDisplayComposition::SetDpmsMode(uint32_t dpms_mode) { - if (!validate_composition_type(DRM_COMPOSITION_TYPE_DPMS)) - return -EINVAL; - dpms_mode_ = dpms_mode; - type_ = DRM_COMPOSITION_TYPE_DPMS; - return 0; -} - -int DrmDisplayComposition::SetDisplayMode(const DrmMode &display_mode) { - if (!validate_composition_type(DRM_COMPOSITION_TYPE_MODESET)) - return -EINVAL; - display_mode_ = display_mode; - dpms_mode_ = DRM_MODE_DPMS_ON; - type_ = DRM_COMPOSITION_TYPE_MODESET; - return 0; -} - -int DrmDisplayComposition::AddPlaneDisable(DrmPlane *plane) { - composition_planes_.emplace_back(DrmCompositionPlane::Type::kDisable, plane, - crtc_); - return 0; -} - -int DrmDisplayComposition::AddPlaneComposition(DrmCompositionPlane plane) { - composition_planes_.emplace_back(std::move(plane)); - return 0; -} - -int DrmDisplayComposition::Plan(std::vector *primary_planes, - std::vector *overlay_planes) { - if (type_ != DRM_COMPOSITION_TYPE_FRAME) - return 0; - - std::map to_composite; - - for (size_t i = 0; i < layers_.size(); ++i) - to_composite.emplace(std::make_pair(i, &layers_[i])); - - int ret; - std::tie(ret, - composition_planes_) = planner_->ProvisionPlanes(to_composite, crtc_, - primary_planes, - overlay_planes); - if (ret) { - ALOGE("Planner failed provisioning planes ret=%d", ret); - return ret; - } - - // Remove the planes we used from the pool before returning. This ensures they - // won't be reused by another display in the composition. - for (auto &i : composition_planes_) { - if (!i.plane()) - continue; - - // make sure that source layers are ordered based on zorder - std::sort(i.source_layers().begin(), i.source_layers().end()); - - std::vector *container; - if (i.plane()->type() == DRM_PLANE_TYPE_PRIMARY) - container = primary_planes; - else - container = overlay_planes; - for (auto j = container->begin(); j != container->end(); ++j) { - if (*j == i.plane()) { - container->erase(j); - break; - } - } - } - - return 0; -} - -static const char *DrmCompositionTypeToString(DrmCompositionType type) { - switch (type) { - case DRM_COMPOSITION_TYPE_EMPTY: - return "EMPTY"; - case DRM_COMPOSITION_TYPE_FRAME: - return "FRAME"; - case DRM_COMPOSITION_TYPE_DPMS: - return "DPMS"; - case DRM_COMPOSITION_TYPE_MODESET: - return "MODESET"; - default: - return ""; - } -} - -static const char *DPMSModeToString(int dpms_mode) { - switch (dpms_mode) { - case DRM_MODE_DPMS_ON: - return "ON"; - case DRM_MODE_DPMS_OFF: - return "OFF"; - default: - return ""; - } -} - -static void DumpBuffer(const DrmHwcBuffer &buffer, std::ostringstream *out) { - if (!buffer) { - *out << "buffer="; - return; - } - - *out << "buffer[w/h/format]="; - *out << buffer->width << "/" << buffer->height << "/" << buffer->format; -} - -static void DumpTransform(uint32_t transform, std::ostringstream *out) { - *out << "["; - - if (transform == 0) - *out << "IDENTITY"; - - bool separator = false; - if (transform & DrmHwcTransform::kFlipH) { - *out << "FLIPH"; - separator = true; - } - if (transform & DrmHwcTransform::kFlipV) { - if (separator) - *out << "|"; - *out << "FLIPV"; - separator = true; - } - if (transform & DrmHwcTransform::kRotate90) { - if (separator) - *out << "|"; - *out << "ROTATE90"; - separator = true; - } - if (transform & DrmHwcTransform::kRotate180) { - if (separator) - *out << "|"; - *out << "ROTATE180"; - separator = true; - } - if (transform & DrmHwcTransform::kRotate270) { - if (separator) - *out << "|"; - *out << "ROTATE270"; - separator = true; - } - - uint32_t valid_bits = DrmHwcTransform::kFlipH | DrmHwcTransform::kFlipH | - DrmHwcTransform::kRotate90 | - DrmHwcTransform::kRotate180 | - DrmHwcTransform::kRotate270; - if (transform & ~valid_bits) { - if (separator) - *out << "|"; - *out << "INVALID"; - } - *out << "]"; -} - -static const char *BlendingToString(DrmHwcBlending blending) { - switch (blending) { - case DrmHwcBlending::kNone: - return "NONE"; - case DrmHwcBlending::kPreMult: - return "PREMULT"; - case DrmHwcBlending::kCoverage: - return "COVERAGE"; - default: - return ""; - } -} - -void DrmDisplayComposition::Dump(std::ostringstream *out) const { - *out << "----DrmDisplayComposition" - << " crtc=" << (crtc_ ? crtc_->id() : -1) - << " type=" << DrmCompositionTypeToString(type_); - - switch (type_) { - case DRM_COMPOSITION_TYPE_DPMS: - *out << " dpms_mode=" << DPMSModeToString(dpms_mode_); - break; - case DRM_COMPOSITION_TYPE_MODESET: - *out << " display_mode=" << display_mode_.h_display() << "x" - << display_mode_.v_display(); - break; - default: - break; - } - - *out << " Layers: count=" << layers_.size() << "\n"; - for (size_t i = 0; i < layers_.size(); i++) { - const DrmHwcLayer &layer = layers_[i]; - *out << " [" << i << "] "; - - DumpBuffer(layer.buffer, out); - - if (layer.protected_usage()) - *out << " protected"; - - *out << " transform="; - DumpTransform(layer.transform, out); - *out << " blending[a=" << (int)layer.alpha - << "]=" << BlendingToString(layer.blending) << "\n"; - } - - *out << " Planes: count=" << composition_planes_.size() << "\n"; - for (size_t i = 0; i < composition_planes_.size(); i++) { - const DrmCompositionPlane &comp_plane = composition_planes_[i]; - *out << " [" << i << "]" - << " plane=" << (comp_plane.plane() ? comp_plane.plane()->id() : -1) - << " type="; - switch (comp_plane.type()) { - case DrmCompositionPlane::Type::kDisable: - *out << "DISABLE"; - break; - case DrmCompositionPlane::Type::kLayer: - *out << "LAYER"; - break; - default: - *out << ""; - break; - } - - *out << " source_layer="; - for (auto i : comp_plane.source_layers()) { - *out << i << " "; - } - *out << "\n"; - } -} -} // namespace android diff --git a/compositor/drmdisplaycomposition.h b/compositor/drmdisplaycomposition.h deleted file mode 100644 index d8a668c..0000000 --- a/compositor/drmdisplaycomposition.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_DISPLAY_COMPOSITION_H_ -#define ANDROID_DRM_DISPLAY_COMPOSITION_H_ - -#include -#include - -#include -#include - -#include "drm/drmcrtc.h" -#include "drm/drmplane.h" -#include "drmhwcomposer.h" - -namespace android { - -class Importer; -class Planner; -class SquashState; - -enum DrmCompositionType { - DRM_COMPOSITION_TYPE_EMPTY, - DRM_COMPOSITION_TYPE_FRAME, - DRM_COMPOSITION_TYPE_DPMS, - DRM_COMPOSITION_TYPE_MODESET, -}; - -struct DrmCompositionDisplayLayersMap { - int display; - bool geometry_changed = true; - std::vector layers; - - DrmCompositionDisplayLayersMap() = default; - DrmCompositionDisplayLayersMap(DrmCompositionDisplayLayersMap &&rhs) = - default; -}; - -struct DrmCompositionRegion { - std::vector source_layers; -}; - -class DrmCompositionPlane { - public: - enum class Type : int32_t { - kDisable, - kLayer, - }; - - DrmCompositionPlane() = default; - DrmCompositionPlane(DrmCompositionPlane &&rhs) = default; - DrmCompositionPlane &operator=(DrmCompositionPlane &&other) = default; - DrmCompositionPlane(Type type, DrmPlane *plane, DrmCrtc *crtc) - : type_(type), plane_(plane), crtc_(crtc) { - } - DrmCompositionPlane(Type type, DrmPlane *plane, DrmCrtc *crtc, - size_t source_layer) - : type_(type), - plane_(plane), - crtc_(crtc), - source_layers_(1, source_layer) { - } - - Type type() const { - return type_; - } - - DrmPlane *plane() const { - return plane_; - } - void set_plane(DrmPlane *plane) { - plane_ = plane; - } - - DrmCrtc *crtc() const { - return crtc_; - } - - std::vector &source_layers() { - return source_layers_; - } - - const std::vector &source_layers() const { - return source_layers_; - } - - private: - Type type_ = Type::kDisable; - DrmPlane *plane_ = NULL; - DrmCrtc *crtc_ = NULL; - std::vector source_layers_; -}; - -class DrmDisplayComposition { - public: - DrmDisplayComposition() = default; - DrmDisplayComposition(const DrmDisplayComposition &) = delete; - ~DrmDisplayComposition(); - - int Init(DrmDevice *drm, DrmCrtc *crtc, Importer *importer, Planner *planner, - uint64_t frame_no); - - int SetLayers(DrmHwcLayer *layers, size_t num_layers, bool geometry_changed); - int AddPlaneComposition(DrmCompositionPlane plane); - int AddPlaneDisable(DrmPlane *plane); - int SetDpmsMode(uint32_t dpms_mode); - int SetDisplayMode(const DrmMode &display_mode); - - int Plan(std::vector *primary_planes, - std::vector *overlay_planes); - - std::vector &layers() { - return layers_; - } - - std::vector &composition_planes() { - return composition_planes_; - } - - bool geometry_changed() const { - return geometry_changed_; - } - - uint64_t frame_no() const { - return frame_no_; - } - - DrmCompositionType type() const { - return type_; - } - - uint32_t dpms_mode() const { - return dpms_mode_; - } - - const DrmMode &display_mode() const { - return display_mode_; - } - - DrmCrtc *crtc() const { - return crtc_; - } - - Importer *importer() const { - return importer_; - } - - Planner *planner() const { - return planner_; - } - - int take_out_fence() { - return out_fence_.Release(); - } - - void set_out_fence(int out_fence) { - out_fence_.Set(out_fence); - } - - void Dump(std::ostringstream *out) const; - - private: - bool validate_composition_type(DrmCompositionType desired); - - DrmDevice *drm_ = NULL; - DrmCrtc *crtc_ = NULL; - Importer *importer_ = NULL; - Planner *planner_ = NULL; - - DrmCompositionType type_ = DRM_COMPOSITION_TYPE_EMPTY; - uint32_t dpms_mode_ = DRM_MODE_DPMS_ON; - DrmMode display_mode_; - - UniqueFd out_fence_ = -1; - - bool geometry_changed_; - std::vector layers_; - std::vector composition_planes_; - - uint64_t frame_no_ = 0; -}; -} // namespace android - -#endif // ANDROID_DRM_DISPLAY_COMPOSITION_H_ diff --git a/compositor/drmdisplaycompositor.cpp b/compositor/drmdisplaycompositor.cpp deleted file mode 100644 index aed090a..0000000 --- a/compositor/drmdisplaycompositor.cpp +++ /dev/null @@ -1,1097 +0,0 @@ -/* - * Copyright (C) 2015 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-display-compositor" - -#include "drmdisplaycompositor.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "drm/drmcrtc.h" -#include "drm/drmdevice.h" -#include "drm/drmplane.h" -#include "utils/autolock.h" - -static const uint32_t kWaitWritebackFence = 100; // ms - -namespace android { - -std::ostream &operator<<(std::ostream &str, FlatteningState state) { - std::array flattenting_state_str = { - "None", "Not needed", "SF Requested", "Squashed by GPU", - "Serial", "Concurrent", - }; - - return str << flattenting_state_str[static_cast(state)]; -} - -class CompositorVsyncCallback : public VsyncCallback { - public: - CompositorVsyncCallback(DrmDisplayCompositor *compositor) - : compositor_(compositor) { - } - - void Callback(int display, int64_t timestamp) { - compositor_->Vsync(display, timestamp); - } - - private: - DrmDisplayCompositor *compositor_; -}; - -DrmDisplayCompositor::DrmDisplayCompositor() - : resource_manager_(NULL), - display_(-1), - initialized_(false), - active_(false), - use_hw_overlays_(true), - dump_frames_composited_(0), - dump_last_timestamp_ns_(0), - flatten_countdown_(FLATTEN_COUNTDOWN_INIT), - writeback_fence_(-1), - flattening_state_(FlatteningState::kNone), - frames_flattened_(0) { - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts)) - return; - dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; -} - -DrmDisplayCompositor::~DrmDisplayCompositor() { - if (!initialized_) - return; - - vsync_worker_.Exit(); - int ret = pthread_mutex_lock(&lock_); - if (ret) - ALOGE("Failed to acquire compositor lock %d", ret); - DrmDevice *drm = resource_manager_->GetDrmDevice(display_); - if (mode_.blob_id) - drm->DestroyPropertyBlob(mode_.blob_id); - if (mode_.old_blob_id) - drm->DestroyPropertyBlob(mode_.old_blob_id); - - active_composition_.reset(); - - ret = pthread_mutex_unlock(&lock_); - if (ret) - ALOGE("Failed to acquire compositor lock %d", ret); - - pthread_mutex_destroy(&lock_); -} - -int DrmDisplayCompositor::Init(ResourceManager *resource_manager, int display) { - resource_manager_ = resource_manager; - display_ = display; - DrmDevice *drm = resource_manager_->GetDrmDevice(display); - if (!drm) { - ALOGE("Could not find drmdevice for display"); - return -EINVAL; - } - int ret = pthread_mutex_init(&lock_, NULL); - if (ret) { - ALOGE("Failed to initialize drm compositor lock %d\n", ret); - return ret; - } - planner_ = Planner::CreateInstance(drm); - - vsync_worker_.Init(drm, display_); - auto callback = std::make_shared(this); - vsync_worker_.RegisterCallback(callback); - - initialized_ = true; - return 0; -} - -std::unique_ptr DrmDisplayCompositor::CreateComposition() - const { - return std::unique_ptr(new DrmDisplayComposition()); -} - -std::unique_ptr -DrmDisplayCompositor::CreateInitializedComposition() const { - DrmDevice *drm = resource_manager_->GetDrmDevice(display_); - DrmCrtc *crtc = drm->GetCrtcForDisplay(display_); - if (!crtc) { - ALOGE("Failed to find crtc for display = %d", display_); - return std::unique_ptr(); - } - std::unique_ptr comp = CreateComposition(); - std::shared_ptr importer = resource_manager_->GetImporter(display_); - if (!importer) { - ALOGE("Failed to find resources for display = %d", display_); - return std::unique_ptr(); - } - int ret = comp->Init(drm, crtc, importer.get(), planner_.get(), 0); - if (ret) { - ALOGE("Failed to init composition for display = %d", display_); - return std::unique_ptr(); - } - return comp; -} - -FlatteningState DrmDisplayCompositor::GetFlatteningState() const { - return flattening_state_; -} - -uint32_t DrmDisplayCompositor::GetFlattenedFramesCount() const { - return frames_flattened_; -} - -bool DrmDisplayCompositor::ShouldFlattenOnClient() const { - return flattening_state_ == FlatteningState::kClientRequested || - flattening_state_ == FlatteningState::kClientDone; -} - -std::tuple -DrmDisplayCompositor::GetActiveModeResolution() { - DrmDevice *drm = resource_manager_->GetDrmDevice(display_); - DrmConnector *connector = drm->GetConnectorForDisplay(display_); - if (connector == NULL) { - ALOGE("Failed to determine display mode: no connector for display %d", - display_); - return std::make_tuple(0, 0, -ENODEV); - } - - const DrmMode &mode = connector->active_mode(); - return std::make_tuple(mode.h_display(), mode.v_display(), 0); -} - -int DrmDisplayCompositor::DisablePlanes(DrmDisplayComposition *display_comp) { - drmModeAtomicReqPtr pset = drmModeAtomicAlloc(); - if (!pset) { - ALOGE("Failed to allocate property set"); - return -ENOMEM; - } - - int ret; - std::vector &comp_planes = display_comp - ->composition_planes(); - for (DrmCompositionPlane &comp_plane : comp_planes) { - DrmPlane *plane = comp_plane.plane(); - ret = drmModeAtomicAddProperty(pset, plane->id(), - plane->crtc_property().id(), 0) < 0 || - drmModeAtomicAddProperty(pset, plane->id(), plane->fb_property().id(), - 0) < 0; - if (ret) { - ALOGE("Failed to add plane %d disable to pset", plane->id()); - drmModeAtomicFree(pset); - return ret; - } - } - DrmDevice *drm = resource_manager_->GetDrmDevice(display_); - ret = drmModeAtomicCommit(drm->fd(), pset, 0, drm); - if (ret) { - ALOGE("Failed to commit pset ret=%d\n", ret); - drmModeAtomicFree(pset); - return ret; - } - - drmModeAtomicFree(pset); - return 0; -} - -int DrmDisplayCompositor::SetupWritebackCommit(drmModeAtomicReqPtr pset, - uint32_t crtc_id, - DrmConnector *writeback_conn, - DrmHwcBuffer *writeback_buffer) { - int ret = 0; - if (writeback_conn->writeback_fb_id().id() == 0 || - writeback_conn->writeback_out_fence().id() == 0) { - ALOGE("Writeback properties don't exit"); - return -EINVAL; - } - if ((*writeback_buffer)->fb_id == 0) { - ALOGE("Invalid writeback buffer"); - return -EINVAL; - } - ret = drmModeAtomicAddProperty(pset, writeback_conn->id(), - writeback_conn->writeback_fb_id().id(), - (*writeback_buffer)->fb_id); - if (ret < 0) { - ALOGE("Failed to add writeback_fb_id"); - return ret; - } - ret = drmModeAtomicAddProperty(pset, writeback_conn->id(), - writeback_conn->writeback_out_fence().id(), - (uint64_t)&writeback_fence_); - if (ret < 0) { - ALOGE("Failed to add writeback_out_fence"); - return ret; - } - - ret = drmModeAtomicAddProperty(pset, writeback_conn->id(), - writeback_conn->crtc_id_property().id(), - crtc_id); - if (ret < 0) { - ALOGE("Failed to attach writeback"); - return ret; - } - return 0; -} - -int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp, - bool test_only, - DrmConnector *writeback_conn, - DrmHwcBuffer *writeback_buffer) { - ATRACE_CALL(); - - int ret = 0; - - std::vector &layers = display_comp->layers(); - std::vector &comp_planes = display_comp - ->composition_planes(); - DrmDevice *drm = resource_manager_->GetDrmDevice(display_); - uint64_t out_fences[drm->crtcs().size()]; - - DrmConnector *connector = drm->GetConnectorForDisplay(display_); - if (!connector) { - ALOGE("Could not locate connector for display %d", display_); - return -ENODEV; - } - DrmCrtc *crtc = drm->GetCrtcForDisplay(display_); - if (!crtc) { - ALOGE("Could not locate crtc for display %d", display_); - return -ENODEV; - } - - drmModeAtomicReqPtr pset = drmModeAtomicAlloc(); - if (!pset) { - ALOGE("Failed to allocate property set"); - return -ENOMEM; - } - - if (writeback_buffer != NULL) { - if (writeback_conn == NULL) { - ALOGE("Invalid arguments requested writeback without writeback conn"); - return -EINVAL; - } - ret = SetupWritebackCommit(pset, crtc->id(), writeback_conn, - writeback_buffer); - if (ret < 0) { - ALOGE("Failed to Setup Writeback Commit ret = %d", ret); - return ret; - } - } - if (crtc->out_fence_ptr_property().id() != 0) { - ret = drmModeAtomicAddProperty(pset, crtc->id(), - crtc->out_fence_ptr_property().id(), - (uint64_t)&out_fences[crtc->pipe()]); - if (ret < 0) { - ALOGE("Failed to add OUT_FENCE_PTR property to pset: %d", ret); - drmModeAtomicFree(pset); - return ret; - } - } - - if (mode_.needs_modeset) { - ret = drmModeAtomicAddProperty(pset, crtc->id(), - crtc->active_property().id(), 1); - if (ret < 0) { - ALOGE("Failed to add crtc active to pset\n"); - drmModeAtomicFree(pset); - return ret; - } - - ret = drmModeAtomicAddProperty(pset, crtc->id(), crtc->mode_property().id(), - mode_.blob_id) < 0 || - drmModeAtomicAddProperty(pset, connector->id(), - connector->crtc_id_property().id(), - crtc->id()) < 0; - if (ret) { - ALOGE("Failed to add blob %d to pset", mode_.blob_id); - drmModeAtomicFree(pset); - return ret; - } - } - - for (DrmCompositionPlane &comp_plane : comp_planes) { - DrmPlane *plane = comp_plane.plane(); - DrmCrtc *crtc = comp_plane.crtc(); - std::vector &source_layers = comp_plane.source_layers(); - - int fb_id = -1; - int fence_fd = -1; - hwc_rect_t display_frame; - hwc_frect_t source_crop; - uint64_t rotation = 0; - uint64_t alpha = 0xFFFF; - uint64_t blend; - - if (comp_plane.type() != DrmCompositionPlane::Type::kDisable) { - if (source_layers.size() > 1) { - ALOGE("Can't handle more than one source layer sz=%zu type=%d", - source_layers.size(), comp_plane.type()); - continue; - } - - if (source_layers.empty() || source_layers.front() >= layers.size()) { - ALOGE("Source layer index %zu out of bounds %zu type=%d", - source_layers.front(), layers.size(), comp_plane.type()); - break; - } - DrmHwcLayer &layer = layers[source_layers.front()]; - if (!layer.buffer) { - ALOGE("Expected a valid framebuffer for pset"); - break; - } - fb_id = layer.buffer->fb_id; - fence_fd = layer.acquire_fence.get(); - display_frame = layer.display_frame; - source_crop = layer.source_crop; - alpha = layer.alpha; - - if (plane->blend_property().id()) { - switch (layer.blending) { - case DrmHwcBlending::kPreMult: - std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName( - "Pre-multiplied"); - break; - case DrmHwcBlending::kCoverage: - std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName( - "Coverage"); - break; - case DrmHwcBlending::kNone: - default: - std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName( - "None"); - break; - } - } - - if (plane->zpos_property().id() && - !plane->zpos_property().is_immutable()) { - uint64_t min_zpos = 0; - - // Ignore ret and use min_zpos as 0 by default - std::tie(std::ignore, min_zpos) = plane->zpos_property().range_min(); - - ret = drmModeAtomicAddProperty(pset, plane->id(), - plane->zpos_property().id(), - source_layers.front() + min_zpos) < 0; - if (ret) { - ALOGE("Failed to add zpos property %d to plane %d", - plane->zpos_property().id(), plane->id()); - break; - } - } - - rotation = 0; - if (layer.transform & DrmHwcTransform::kFlipH) - rotation |= DRM_MODE_REFLECT_X; - if (layer.transform & DrmHwcTransform::kFlipV) - rotation |= DRM_MODE_REFLECT_Y; - if (layer.transform & DrmHwcTransform::kRotate90) - rotation |= DRM_MODE_ROTATE_90; - else if (layer.transform & DrmHwcTransform::kRotate180) - rotation |= DRM_MODE_ROTATE_180; - else if (layer.transform & DrmHwcTransform::kRotate270) - rotation |= DRM_MODE_ROTATE_270; - else - rotation |= DRM_MODE_ROTATE_0; - - if (fence_fd >= 0) { - int prop_id = plane->in_fence_fd_property().id(); - if (prop_id == 0) { - ALOGE("Failed to get IN_FENCE_FD property id"); - break; - } - ret = drmModeAtomicAddProperty(pset, plane->id(), prop_id, fence_fd); - if (ret < 0) { - ALOGE("Failed to add IN_FENCE_FD property to pset: %d", ret); - break; - } - } - } - - // Disable the plane if there's no framebuffer - if (fb_id < 0) { - ret = drmModeAtomicAddProperty(pset, plane->id(), - plane->crtc_property().id(), 0) < 0 || - drmModeAtomicAddProperty(pset, plane->id(), - plane->fb_property().id(), 0) < 0; - if (ret) { - ALOGE("Failed to add plane %d disable to pset", plane->id()); - break; - } - continue; - } - - ret = drmModeAtomicAddProperty(pset, plane->id(), - plane->crtc_property().id(), crtc->id()) < 0; - ret |= drmModeAtomicAddProperty(pset, plane->id(), - plane->fb_property().id(), fb_id) < 0; - ret |= drmModeAtomicAddProperty(pset, plane->id(), - plane->crtc_x_property().id(), - display_frame.left) < 0; - ret |= drmModeAtomicAddProperty(pset, plane->id(), - plane->crtc_y_property().id(), - display_frame.top) < 0; - ret |= drmModeAtomicAddProperty(pset, plane->id(), - plane->crtc_w_property().id(), - display_frame.right - display_frame.left) < - 0; - ret |= drmModeAtomicAddProperty(pset, plane->id(), - plane->crtc_h_property().id(), - display_frame.bottom - display_frame.top) < - 0; - ret |= drmModeAtomicAddProperty(pset, plane->id(), - plane->src_x_property().id(), - (int)(source_crop.left) << 16) < 0; - ret |= drmModeAtomicAddProperty(pset, plane->id(), - plane->src_y_property().id(), - (int)(source_crop.top) << 16) < 0; - ret |= drmModeAtomicAddProperty(pset, plane->id(), - plane->src_w_property().id(), - (int)(source_crop.right - source_crop.left) - << 16) < 0; - ret |= drmModeAtomicAddProperty(pset, plane->id(), - plane->src_h_property().id(), - (int)(source_crop.bottom - source_crop.top) - << 16) < 0; - if (ret) { - ALOGE("Failed to add plane %d to set", plane->id()); - break; - } - - if (plane->rotation_property().id()) { - ret = drmModeAtomicAddProperty(pset, plane->id(), - plane->rotation_property().id(), - rotation) < 0; - if (ret) { - ALOGE("Failed to add rotation property %d to plane %d", - plane->rotation_property().id(), plane->id()); - break; - } - } - - if (plane->alpha_property().id()) { - ret = drmModeAtomicAddProperty(pset, plane->id(), - plane->alpha_property().id(), alpha) < 0; - if (ret) { - ALOGE("Failed to add alpha property %d to plane %d", - plane->alpha_property().id(), plane->id()); - break; - } - } - - if (plane->blend_property().id()) { - ret = drmModeAtomicAddProperty(pset, plane->id(), - plane->blend_property().id(), blend) < 0; - if (ret) { - ALOGE("Failed to add pixel blend mode property %d to plane %d", - plane->blend_property().id(), plane->id()); - break; - } - } - } - - if (!ret) { - uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET; - if (test_only) - flags |= DRM_MODE_ATOMIC_TEST_ONLY; - - ret = drmModeAtomicCommit(drm->fd(), pset, flags, drm); - if (ret) { - if (!test_only) - ALOGE("Failed to commit pset ret=%d\n", ret); - drmModeAtomicFree(pset); - return ret; - } - } - if (pset) - drmModeAtomicFree(pset); - - if (!test_only && mode_.needs_modeset) { - ret = drm->DestroyPropertyBlob(mode_.old_blob_id); - if (ret) { - ALOGE("Failed to destroy old mode property blob %" PRIu32 "/%d", - mode_.old_blob_id, ret); - return ret; - } - - /* TODO: Add dpms to the pset when the kernel supports it */ - ret = ApplyDpms(display_comp); - if (ret) { - ALOGE("Failed to apply DPMS after modeset %d\n", ret); - return ret; - } - - connector->set_active_mode(mode_.mode); - mode_.old_blob_id = mode_.blob_id; - mode_.blob_id = 0; - mode_.needs_modeset = false; - } - - if (crtc->out_fence_ptr_property().id()) { - display_comp->set_out_fence((int)out_fences[crtc->pipe()]); - } - - return ret; -} - -int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) { - DrmDevice *drm = resource_manager_->GetDrmDevice(display_); - DrmConnector *conn = drm->GetConnectorForDisplay(display_); - if (!conn) { - ALOGE("Failed to get DrmConnector for display %d", display_); - return -ENODEV; - } - - const DrmProperty &prop = conn->dpms_property(); - int ret = drmModeConnectorSetProperty(drm->fd(), conn->id(), prop.id(), - display_comp->dpms_mode()); - if (ret) { - ALOGE("Failed to set DPMS property for connector %d", conn->id()); - return ret; - } - return 0; -} - -std::tuple DrmDisplayCompositor::CreateModeBlob( - const DrmMode &mode) { - struct drm_mode_modeinfo drm_mode; - memset(&drm_mode, 0, sizeof(drm_mode)); - mode.ToDrmModeModeInfo(&drm_mode); - - uint32_t id = 0; - DrmDevice *drm = resource_manager_->GetDrmDevice(display_); - int ret = drm->CreatePropertyBlob(&drm_mode, sizeof(struct drm_mode_modeinfo), - &id); - if (ret) { - ALOGE("Failed to create mode property blob %d", ret); - return std::make_tuple(ret, 0); - } - ALOGE("Create blob_id %" PRIu32 "\n", id); - return std::make_tuple(ret, id); -} - -void DrmDisplayCompositor::ClearDisplay() { - if (!active_composition_) - return; - - if (DisablePlanes(active_composition_.get())) - return; - - active_composition_.reset(NULL); - vsync_worker_.VSyncControl(false); -} - -void DrmDisplayCompositor::ApplyFrame( - std::unique_ptr composition, int status, - bool writeback) { - AutoLock lock(&lock_, __func__); - if (lock.Lock()) - return; - int ret = status; - - if (!ret) { - if (writeback && !CountdownExpired()) { - ALOGE("Abort playing back scene"); - return; - } - ret = CommitFrame(composition.get(), false); - } - - if (ret) { - ALOGE("Composite failed for display %d", display_); - // Disable the hw used by the last active composition. This allows us to - // signal the release fences from that composition to avoid hanging. - ClearDisplay(); - return; - } - ++dump_frames_composited_; - - active_composition_.swap(composition); - - flatten_countdown_ = FLATTEN_COUNTDOWN_INIT; - if (flattening_state_ != FlatteningState::kClientRequested) { - SetFlattening(FlatteningState::kNone); - } else { - SetFlattening(FlatteningState::kClientDone); - } - vsync_worker_.VSyncControl(!writeback); -} - -int DrmDisplayCompositor::ApplyComposition( - std::unique_ptr composition) { - int ret = 0; - switch (composition->type()) { - case DRM_COMPOSITION_TYPE_FRAME: - if (composition->geometry_changed()) { - // Send the composition to the kernel to ensure we can commit it. This - // is just a test, it won't actually commit the frame. - ret = CommitFrame(composition.get(), true); - if (ret) { - ALOGE("Commit test failed for display %d, FIXME", display_); - return ret; - } - } - - ApplyFrame(std::move(composition), ret); - break; - case DRM_COMPOSITION_TYPE_DPMS: - active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON); - ret = ApplyDpms(composition.get()); - if (ret) - ALOGE("Failed to apply dpms for display %d", display_); - return ret; - case DRM_COMPOSITION_TYPE_MODESET: - mode_.mode = composition->display_mode(); - if (mode_.blob_id) - resource_manager_->GetDrmDevice(display_)->DestroyPropertyBlob( - mode_.blob_id); - std::tie(ret, mode_.blob_id) = CreateModeBlob(mode_.mode); - if (ret) { - ALOGE("Failed to create mode blob for display %d", display_); - return ret; - } - mode_.needs_modeset = true; - return 0; - default: - ALOGE("Unknown composition type %d", composition->type()); - return -EINVAL; - } - - return ret; -} - -int DrmDisplayCompositor::TestComposition(DrmDisplayComposition *composition) { - return CommitFrame(composition, true); -} - -// Flatten a scene on the display by using a writeback connector -// and returns the composition result as a DrmHwcLayer. -int DrmDisplayCompositor::FlattenOnDisplay( - std::unique_ptr &src, DrmConnector *writeback_conn, - DrmMode &src_mode, DrmHwcLayer *writeback_layer) { - int ret = 0; - DrmDevice *drm = resource_manager_->GetDrmDevice(display_); - ret = writeback_conn->UpdateModes(); - if (ret) { - ALOGE("Failed to update modes %d", ret); - return ret; - } - for (const DrmMode &mode : writeback_conn->modes()) { - if (mode.h_display() == src_mode.h_display() && - mode.v_display() == src_mode.v_display()) { - mode_.mode = mode; - if (mode_.blob_id) - drm->DestroyPropertyBlob(mode_.blob_id); - std::tie(ret, mode_.blob_id) = CreateModeBlob(mode_.mode); - if (ret) { - ALOGE("Failed to create mode blob for display %d", display_); - return ret; - } - mode_.needs_modeset = true; - break; - } - } - if (mode_.blob_id <= 0) { - ALOGE("Failed to find similar mode"); - return -EINVAL; - } - - DrmCrtc *crtc = drm->GetCrtcForDisplay(display_); - if (!crtc) { - ALOGE("Failed to find crtc for display %d", display_); - return -EINVAL; - } - // TODO what happens if planes could go to both CRTCs, I don't think it's - // handled anywhere - std::vector primary_planes; - std::vector overlay_planes; - for (auto &plane : drm->planes()) { - if (!plane->GetCrtcSupported(*crtc)) - continue; - if (plane->type() == DRM_PLANE_TYPE_PRIMARY) - primary_planes.push_back(plane.get()); - else if (plane->type() == DRM_PLANE_TYPE_OVERLAY) - overlay_planes.push_back(plane.get()); - } - - ret = src->Plan(&primary_planes, &overlay_planes); - if (ret) { - ALOGE("Failed to plan the composition ret = %d", ret); - return ret; - } - - // Disable the planes we're not using - for (auto i = primary_planes.begin(); i != primary_planes.end();) { - src->AddPlaneDisable(*i); - i = primary_planes.erase(i); - } - for (auto i = overlay_planes.begin(); i != overlay_planes.end();) { - src->AddPlaneDisable(*i); - i = overlay_planes.erase(i); - } - - AutoLock lock(&lock_, __func__); - ret = lock.Lock(); - if (ret) - return ret; - DrmFramebuffer *writeback_fb = &framebuffers_[framebuffer_index_]; - framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS; - if (!writeback_fb->Allocate(mode_.mode.h_display(), mode_.mode.v_display())) { - ALOGE("Failed to allocate writeback buffer"); - return -ENOMEM; - } - DrmHwcBuffer *writeback_buffer = &writeback_layer->buffer; - writeback_layer->sf_handle = writeback_fb->buffer()->handle; - ret = writeback_layer->ImportBuffer( - resource_manager_->GetImporter(display_).get()); - if (ret) { - ALOGE("Failed to import writeback buffer"); - return ret; - } - - ret = CommitFrame(src.get(), true, writeback_conn, writeback_buffer); - if (ret) { - ALOGE("Atomic check failed"); - return ret; - } - ret = CommitFrame(src.get(), false, writeback_conn, writeback_buffer); - if (ret) { - ALOGE("Atomic commit failed"); - return ret; - } - - ret = sync_wait(writeback_fence_, kWaitWritebackFence); - writeback_layer->acquire_fence.Set(writeback_fence_); - writeback_fence_ = -1; - if (ret) { - ALOGE("Failed to wait on writeback fence"); - return ret; - } - return 0; -} - -void DrmDisplayCompositor::SetFlattening(FlatteningState new_state) { - if (flattening_state_ != new_state) { - switch (flattening_state_) { - case FlatteningState::kClientDone: - case FlatteningState::kConcurrent: - case FlatteningState::kSerial: - ++frames_flattened_; - break; - case FlatteningState::kClientRequested: - case FlatteningState::kNone: - case FlatteningState::kNotNeeded: - break; - } - } - flattening_state_ = new_state; -} - -bool DrmDisplayCompositor::IsFlatteningNeeded() const { - return CountdownExpired() && active_composition_->layers().size() >= 2; -} - -int DrmDisplayCompositor::FlattenOnClient() { - if (refresh_display_cb_) { - { - AutoLock lock(&lock_, __func__); - if (!IsFlatteningNeeded()) { - if (flattening_state_ != FlatteningState::kClientDone) { - ALOGV("Flattening is not needed"); - SetFlattening(FlatteningState::kNotNeeded); - } - return -EALREADY; - } - } - - ALOGV( - "No writeback connector available, " - "falling back to client composition"); - SetFlattening(FlatteningState::kClientRequested); - refresh_display_cb_(display_); - return 0; - } else { - ALOGV("No writeback connector available"); - return -EINVAL; - } -} - -// Flatten a scene by enabling the writeback connector attached -// to the same CRTC as the one driving the display. -int DrmDisplayCompositor::FlattenSerial(DrmConnector *writeback_conn) { - ALOGV("FlattenSerial by enabling writeback connector to the same crtc"); - // Flattened composition with only one layer that is obtained - // using the writeback connector - std::unique_ptr - writeback_comp = CreateInitializedComposition(); - if (!writeback_comp) - return -EINVAL; - - AutoLock lock(&lock_, __func__); - int ret = lock.Lock(); - if (ret) - return ret; - if (!IsFlatteningNeeded()) { - ALOGV("Flattening is not needed"); - SetFlattening(FlatteningState::kNotNeeded); - return -EALREADY; - } - - DrmFramebuffer *writeback_fb = &framebuffers_[framebuffer_index_]; - framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS; - lock.Unlock(); - - if (!writeback_fb->Allocate(mode_.mode.h_display(), mode_.mode.v_display())) { - ALOGE("Failed to allocate writeback buffer"); - return -ENOMEM; - } - writeback_comp->layers().emplace_back(); - - DrmHwcLayer &writeback_layer = writeback_comp->layers().back(); - writeback_layer.sf_handle = writeback_fb->buffer()->handle; - writeback_layer.source_crop = {0, 0, (float)mode_.mode.h_display(), - (float)mode_.mode.v_display()}; - writeback_layer.display_frame = {0, 0, (int)mode_.mode.h_display(), - (int)mode_.mode.v_display()}; - ret = writeback_layer.ImportBuffer( - resource_manager_->GetImporter(display_).get()); - if (ret || writeback_comp->layers().size() != 1) { - ALOGE("Failed to import writeback buffer"); - return ret; - } - - drmModeAtomicReqPtr pset = drmModeAtomicAlloc(); - if (!pset) { - ALOGE("Failed to allocate property set"); - return -ENOMEM; - } - DrmDevice *drm = resource_manager_->GetDrmDevice(display_); - DrmCrtc *crtc = drm->GetCrtcForDisplay(display_); - if (!crtc) { - ALOGE("Failed to find crtc for display %d", display_); - return -EINVAL; - } - ret = SetupWritebackCommit(pset, crtc->id(), writeback_conn, - &writeback_layer.buffer); - if (ret < 0) { - ALOGE("Failed to Setup Writeback Commit"); - return ret; - } - ret = drmModeAtomicCommit(drm->fd(), pset, 0, drm); - if (ret) { - ALOGE("Failed to enable writeback %d", ret); - return ret; - } - ret = sync_wait(writeback_fence_, kWaitWritebackFence); - writeback_layer.acquire_fence.Set(writeback_fence_); - writeback_fence_ = -1; - if (ret) { - ALOGE("Failed to wait on writeback fence"); - return ret; - } - - DrmCompositionPlane squashed_comp(DrmCompositionPlane::Type::kLayer, NULL, - crtc); - for (auto &drmplane : drm->planes()) { - if (!drmplane->GetCrtcSupported(*crtc)) - continue; - if (!squashed_comp.plane() && drmplane->type() == DRM_PLANE_TYPE_PRIMARY) - squashed_comp.set_plane(drmplane.get()); - else - writeback_comp->AddPlaneDisable(drmplane.get()); - } - squashed_comp.source_layers().push_back(0); - ret = writeback_comp->AddPlaneComposition(std::move(squashed_comp)); - if (ret) { - ALOGE("Failed to add flatten scene"); - return ret; - } - - ApplyFrame(std::move(writeback_comp), 0, true); - return 0; -} - -// Flatten a scene by using a crtc which works concurrent with -// the one driving the display. -int DrmDisplayCompositor::FlattenConcurrent(DrmConnector *writeback_conn) { - ALOGV("FlattenConcurrent by using an unused crtc/display"); - int ret = 0; - DrmDisplayCompositor drmdisplaycompositor; - ret = drmdisplaycompositor.Init(resource_manager_, writeback_conn->display()); - if (ret) { - ALOGE("Failed to init drmdisplaycompositor = %d", ret); - return ret; - } - // Copy of the active_composition, needed because of two things: - // 1) Not to hold the lock for the whole time we are accessing - // active_composition - // 2) It will be committed on a crtc that might not be on the same - // dri node, so buffers need to be imported on the right node. - std::unique_ptr - copy_comp = drmdisplaycompositor.CreateInitializedComposition(); - - // Writeback composition that will be committed to the display. - std::unique_ptr - writeback_comp = CreateInitializedComposition(); - - if (!copy_comp || !writeback_comp) - return -EINVAL; - AutoLock lock(&lock_, __func__); - ret = lock.Lock(); - if (ret) - return ret; - if (!IsFlatteningNeeded()) { - ALOGV("Flattening is not needed"); - SetFlattening(FlatteningState::kNotNeeded); - return -EALREADY; - } - DrmCrtc *crtc = active_composition_->crtc(); - - std::vector copy_layers; - for (DrmHwcLayer &src_layer : active_composition_->layers()) { - DrmHwcLayer copy; - ret = copy.InitFromDrmHwcLayer(&src_layer, - resource_manager_ - ->GetImporter(writeback_conn->display()) - .get()); - if (ret) { - ALOGE("Failed to import buffer ret = %d", ret); - return -EINVAL; - } - copy_layers.emplace_back(std::move(copy)); - } - ret = copy_comp->SetLayers(copy_layers.data(), copy_layers.size(), true); - if (ret) { - ALOGE("Failed to set copy_comp layers"); - return ret; - } - - lock.Unlock(); - DrmHwcLayer writeback_layer; - ret = drmdisplaycompositor.FlattenOnDisplay(copy_comp, writeback_conn, - mode_.mode, &writeback_layer); - if (ret) { - ALOGE("Failed to flatten on display ret = %d", ret); - return ret; - } - - DrmCompositionPlane squashed_comp(DrmCompositionPlane::Type::kLayer, NULL, - crtc); - for (auto &drmplane : resource_manager_->GetDrmDevice(display_)->planes()) { - if (!drmplane->GetCrtcSupported(*crtc)) - continue; - if (drmplane->type() == DRM_PLANE_TYPE_PRIMARY) - squashed_comp.set_plane(drmplane.get()); - else - writeback_comp->AddPlaneDisable(drmplane.get()); - } - writeback_comp->layers().emplace_back(); - DrmHwcLayer &next_layer = writeback_comp->layers().back(); - next_layer.sf_handle = writeback_layer.get_usable_handle(); - next_layer.blending = DrmHwcBlending::kPreMult; - next_layer.source_crop = {0, 0, (float)mode_.mode.h_display(), - (float)mode_.mode.v_display()}; - next_layer.display_frame = {0, 0, (int)mode_.mode.h_display(), - (int)mode_.mode.v_display()}; - ret = next_layer.ImportBuffer(resource_manager_->GetImporter(display_).get()); - if (ret) { - ALOGE("Failed to import framebuffer for display %d", ret); - return ret; - } - squashed_comp.source_layers().push_back(0); - ret = writeback_comp->AddPlaneComposition(std::move(squashed_comp)); - if (ret) { - ALOGE("Failed to add plane composition %d", ret); - return ret; - } - ApplyFrame(std::move(writeback_comp), 0, true); - return ret; -} - -int DrmDisplayCompositor::FlattenActiveComposition() { - DrmConnector *writeback_conn = resource_manager_->AvailableWritebackConnector( - display_); - if (!active_composition_ || !writeback_conn) { - // Try to fallback to GPU composition on client, since it is more - // power-efficient than composition on device side - return FlattenOnClient(); - } - - if (writeback_conn->display() != display_) { - SetFlattening(FlatteningState::kConcurrent); - return FlattenConcurrent(writeback_conn); - } else { - SetFlattening(FlatteningState::kSerial); - return FlattenSerial(writeback_conn); - } - - return 0; -} - -bool DrmDisplayCompositor::CountdownExpired() const { - return flatten_countdown_ <= 0; -} - -void DrmDisplayCompositor::Vsync(int display, int64_t timestamp) { - AutoLock lock(&lock_, __func__); - if (lock.Lock()) - return; - flatten_countdown_--; - if (!CountdownExpired()) - return; - lock.Unlock(); - int ret = FlattenActiveComposition(); - ALOGV("scene flattening triggered for display %d at timestamp %" PRIu64 - " result = %d \n", - display, timestamp, ret); -} - -void DrmDisplayCompositor::Dump(std::ostringstream *out) const { - int ret = pthread_mutex_lock(&lock_); - if (ret) - return; - - uint64_t num_frames = dump_frames_composited_; - dump_frames_composited_ = 0; - - struct timespec ts; - ret = clock_gettime(CLOCK_MONOTONIC, &ts); - if (ret) { - pthread_mutex_unlock(&lock_); - return; - } - - uint64_t cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; - uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000); - float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f; - - *out << "--DrmDisplayCompositor[" << display_ - << "]: num_frames=" << num_frames << " num_ms=" << num_ms - << " fps=" << fps << "\n"; - - dump_last_timestamp_ns_ = cur_ts; - - pthread_mutex_unlock(&lock_); -} -} // namespace android diff --git a/compositor/drmdisplaycompositor.h b/compositor/drmdisplaycompositor.h deleted file mode 100644 index 62dd04e..0000000 --- a/compositor/drmdisplaycompositor.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_DISPLAY_COMPOSITOR_H_ -#define ANDROID_DRM_DISPLAY_COMPOSITOR_H_ - -#include -#include -#include - -#include -#include -#include - -#include "drm/resourcemanager.h" -#include "drm/vsyncworker.h" -#include "drmdisplaycomposition.h" -#include "drmframebuffer.h" -#include "drmhwcomposer.h" - -// One for the front, one for the back, and one for cases where we need to -// squash a frame that the hw can't display with hw overlays. -#define DRM_DISPLAY_BUFFERS 3 - -// If a scene is still for this number of vblanks flatten it to reduce power -// consumption. -#define FLATTEN_COUNTDOWN_INIT 60 - -namespace android { - -enum class FlatteningState { - kNone, - kNotNeeded, - kClientRequested, - kClientDone, - kSerial, - kConcurrent -}; - -std::ostream &operator<<(std::ostream &str, FlatteningState state); - -class DrmDisplayCompositor { - public: - DrmDisplayCompositor(); - ~DrmDisplayCompositor(); - - int Init(ResourceManager *resource_manager, int display); - - template - void SetRefreshCallback(Fn &&refresh_cb) { - refresh_display_cb_ = std::forward(refresh_cb); - } - - std::unique_ptr CreateComposition() const; - std::unique_ptr CreateInitializedComposition() const; - int ApplyComposition(std::unique_ptr composition); - int TestComposition(DrmDisplayComposition *composition); - int Composite(); - void Dump(std::ostringstream *out) const; - void Vsync(int display, int64_t timestamp); - void ClearDisplay(); - int TakeOutFence() { - if (!active_composition_) - return -1; - return active_composition_->take_out_fence(); - } - - FlatteningState GetFlatteningState() const; - uint32_t GetFlattenedFramesCount() const; - bool ShouldFlattenOnClient() const; - - std::tuple GetActiveModeResolution(); - - private: - struct ModeState { - bool needs_modeset = false; - DrmMode mode; - uint32_t blob_id = 0; - uint32_t old_blob_id = 0; - }; - - DrmDisplayCompositor(const DrmDisplayCompositor &) = delete; - - // We'll wait for acquire fences to fire for kAcquireWaitTimeoutMs, - // kAcquireWaitTries times, logging a warning in between. - static const int kAcquireWaitTries = 5; - static const int kAcquireWaitTimeoutMs = 100; - - int CommitFrame(DrmDisplayComposition *display_comp, bool test_only, - DrmConnector *writeback_conn = NULL, - DrmHwcBuffer *writeback_buffer = NULL); - int SetupWritebackCommit(drmModeAtomicReqPtr pset, uint32_t crtc_id, - DrmConnector *writeback_conn, - DrmHwcBuffer *writeback_buffer); - int ApplyDpms(DrmDisplayComposition *display_comp); - int DisablePlanes(DrmDisplayComposition *display_comp); - - void ApplyFrame(std::unique_ptr composition, - int status, bool writeback = false); - - void SetFlattening(FlatteningState new_state); - bool IsFlatteningNeeded() const; - int FlattenActiveComposition(); - int FlattenOnClient(); - int FlattenSerial(DrmConnector *writeback_conn); - int FlattenConcurrent(DrmConnector *writeback_conn); - int FlattenOnDisplay(std::unique_ptr &src, - DrmConnector *writeback_conn, DrmMode &src_mode, - DrmHwcLayer *writeback_layer); - - bool CountdownExpired() const; - - std::tuple CreateModeBlob(const DrmMode &mode); - - ResourceManager *resource_manager_; - int display_; - - std::unique_ptr active_composition_; - - bool initialized_; - bool active_; - bool use_hw_overlays_; - - ModeState mode_; - - int framebuffer_index_; - DrmFramebuffer framebuffers_[DRM_DISPLAY_BUFFERS]; - - // mutable since we need to acquire in Dump() - mutable pthread_mutex_t lock_; - - // State tracking progress since our last Dump(). These are mutable since - // we need to reset them on every Dump() call. - mutable uint64_t dump_frames_composited_; - mutable uint64_t dump_last_timestamp_ns_; - VSyncWorker vsync_worker_; - int64_t flatten_countdown_; - std::unique_ptr planner_; - int writeback_fence_; - - FlatteningState flattening_state_; - uint32_t frames_flattened_; - - std::function refresh_display_cb_; -}; -} // namespace android - -#endif // ANDROID_DRM_DISPLAY_COMPOSITOR_H_ diff --git a/drm/DrmConnector.cpp b/drm/DrmConnector.cpp new file mode 100644 index 0000000..8fa47f5 --- /dev/null +++ b/drm/DrmConnector.cpp @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "hwc-drm-connector" + +#include "DrmConnector.h" + +#include +#include +#include +#include + +#include +#include + +#include "DrmDevice.h" + +namespace android { + +constexpr size_t TYPES_COUNT = 17; + +DrmConnector::DrmConnector(DrmDevice *drm, drmModeConnectorPtr c, + DrmEncoder *current_encoder, + std::vector &possible_encoders) + : drm_(drm), + id_(c->connector_id), + encoder_(current_encoder), + display_(-1), + type_(c->connector_type), + type_id_(c->connector_type_id), + state_(c->connection), + mm_width_(c->mmWidth), + mm_height_(c->mmHeight), + possible_encoders_(possible_encoders) { +} + +int DrmConnector::Init() { + int ret = drm_->GetConnectorProperty(*this, "DPMS", &dpms_property_); + if (ret) { + ALOGE("Could not get DPMS property\n"); + return ret; + } + ret = drm_->GetConnectorProperty(*this, "CRTC_ID", &crtc_id_property_); + if (ret) { + ALOGE("Could not get CRTC_ID property\n"); + return ret; + } + ret = drm_->GetConnectorProperty(*this, "EDID", &edid_property_); + if (ret) { + ALOGW("Could not get EDID property\n"); + } + if (writeback()) { + ret = drm_->GetConnectorProperty(*this, "WRITEBACK_PIXEL_FORMATS", + &writeback_pixel_formats_); + if (ret) { + ALOGE("Could not get WRITEBACK_PIXEL_FORMATS connector_id = %d\n", id_); + return ret; + } + ret = drm_->GetConnectorProperty(*this, "WRITEBACK_FB_ID", + &writeback_fb_id_); + if (ret) { + ALOGE("Could not get WRITEBACK_FB_ID connector_id = %d\n", id_); + return ret; + } + ret = drm_->GetConnectorProperty(*this, "WRITEBACK_OUT_FENCE_PTR", + &writeback_out_fence_); + if (ret) { + ALOGE("Could not get WRITEBACK_OUT_FENCE_PTR connector_id = %d\n", id_); + return ret; + } + } + return 0; +} + +uint32_t DrmConnector::id() const { + return id_; +} + +int DrmConnector::display() const { + return display_; +} + +void DrmConnector::set_display(int display) { + display_ = display; +} + +bool DrmConnector::internal() const { + return type_ == DRM_MODE_CONNECTOR_LVDS || type_ == DRM_MODE_CONNECTOR_eDP || + type_ == DRM_MODE_CONNECTOR_DSI || + type_ == DRM_MODE_CONNECTOR_VIRTUAL || type_ == DRM_MODE_CONNECTOR_DPI; +} + +bool DrmConnector::external() const { + return type_ == DRM_MODE_CONNECTOR_HDMIA || + type_ == DRM_MODE_CONNECTOR_DisplayPort || + type_ == DRM_MODE_CONNECTOR_DVID || type_ == DRM_MODE_CONNECTOR_DVII || + type_ == DRM_MODE_CONNECTOR_VGA; +} + +bool DrmConnector::writeback() const { +#ifdef DRM_MODE_CONNECTOR_WRITEBACK + return type_ == DRM_MODE_CONNECTOR_WRITEBACK; +#else + return false; +#endif +} + +bool DrmConnector::valid_type() const { + return internal() || external() || writeback(); +} + +std::string DrmConnector::name() const { + constexpr std::array names = + {"None", "VGA", "DVI-I", "DVI-D", "DVI-A", "Composite", + "SVIDEO", "LVDS", "Component", "DIN", "DP", "HDMI-A", + "HDMI-B", "TV", "eDP", "Virtual", "DSI"}; + + if (type_ < TYPES_COUNT) { + std::ostringstream name_buf; + name_buf << names[type_] << "-" << type_id_; + return name_buf.str(); + } else { + ALOGE("Unknown type in connector %d, could not make his name", id_); + return "None"; + } +} + +int DrmConnector::UpdateModes() { + int fd = drm_->fd(); + + drmModeConnectorPtr c = drmModeGetConnector(fd, id_); + if (!c) { + ALOGE("Failed to get connector %d", id_); + return -ENODEV; + } + + state_ = c->connection; + + bool preferred_mode_found = false; + std::vector new_modes; + for (int i = 0; i < c->count_modes; ++i) { + bool exists = false; + for (const DrmMode &mode : modes_) { + if (mode == c->modes[i]) { + new_modes.push_back(mode); + exists = true; + break; + } + } + if (!exists) { + DrmMode m(&c->modes[i]); + m.set_id(drm_->next_mode_id()); + new_modes.push_back(m); + } + // Use only the first DRM_MODE_TYPE_PREFERRED mode found + if (!preferred_mode_found && + (new_modes.back().type() & DRM_MODE_TYPE_PREFERRED)) { + preferred_mode_id_ = new_modes.back().id(); + preferred_mode_found = true; + } + } + modes_.swap(new_modes); + if (!preferred_mode_found && modes_.size() != 0) { + preferred_mode_id_ = modes_[0].id(); + } + return 0; +} + +const DrmMode &DrmConnector::active_mode() const { + return active_mode_; +} + +void DrmConnector::set_active_mode(const DrmMode &mode) { + active_mode_ = mode; +} + +const DrmProperty &DrmConnector::dpms_property() const { + return dpms_property_; +} + +const DrmProperty &DrmConnector::crtc_id_property() const { + return crtc_id_property_; +} + +const DrmProperty &DrmConnector::edid_property() const { + return edid_property_; +} + +const DrmProperty &DrmConnector::writeback_pixel_formats() const { + return writeback_pixel_formats_; +} + +const DrmProperty &DrmConnector::writeback_fb_id() const { + return writeback_fb_id_; +} + +const DrmProperty &DrmConnector::writeback_out_fence() const { + return writeback_out_fence_; +} + +DrmEncoder *DrmConnector::encoder() const { + return encoder_; +} + +void DrmConnector::set_encoder(DrmEncoder *encoder) { + encoder_ = encoder; +} + +drmModeConnection DrmConnector::state() const { + return state_; +} + +uint32_t DrmConnector::mm_width() const { + return mm_width_; +} + +uint32_t DrmConnector::mm_height() const { + return mm_height_; +} +} // namespace android diff --git a/drm/DrmConnector.h b/drm/DrmConnector.h new file mode 100644 index 0000000..3fdf146 --- /dev/null +++ b/drm/DrmConnector.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_CONNECTOR_H_ +#define ANDROID_DRM_CONNECTOR_H_ + +#include +#include + +#include +#include + +#include "DrmEncoder.h" +#include "DrmMode.h" +#include "DrmProperty.h" + +namespace android { + +class DrmDevice; + +class DrmConnector { + public: + DrmConnector(DrmDevice *drm, drmModeConnectorPtr c, + DrmEncoder *current_encoder, + std::vector &possible_encoders); + DrmConnector(const DrmProperty &) = delete; + DrmConnector &operator=(const DrmProperty &) = delete; + + int Init(); + + uint32_t id() const; + + int display() const; + void set_display(int display); + + bool internal() const; + bool external() const; + bool writeback() const; + bool valid_type() const; + + std::string name() const; + + int UpdateModes(); + + const std::vector &modes() const { + return modes_; + } + const DrmMode &active_mode() const; + void set_active_mode(const DrmMode &mode); + + const DrmProperty &dpms_property() const; + const DrmProperty &crtc_id_property() const; + const DrmProperty &edid_property() const; + const DrmProperty &writeback_pixel_formats() const; + const DrmProperty &writeback_fb_id() const; + const DrmProperty &writeback_out_fence() const; + + const std::vector &possible_encoders() const { + return possible_encoders_; + } + DrmEncoder *encoder() const; + void set_encoder(DrmEncoder *encoder); + + drmModeConnection state() const; + + uint32_t mm_width() const; + uint32_t mm_height() const; + + uint32_t get_preferred_mode_id() const { + return preferred_mode_id_; + } + + private: + DrmDevice *drm_; + + uint32_t id_; + DrmEncoder *encoder_; + int display_; + + uint32_t type_; + uint32_t type_id_; + drmModeConnection state_; + + uint32_t mm_width_; + uint32_t mm_height_; + + DrmMode active_mode_; + std::vector modes_; + + DrmProperty dpms_property_; + DrmProperty crtc_id_property_; + DrmProperty edid_property_; + DrmProperty writeback_pixel_formats_; + DrmProperty writeback_fb_id_; + DrmProperty writeback_out_fence_; + + std::vector possible_encoders_; + + uint32_t preferred_mode_id_; +}; +} // namespace android + +#endif // ANDROID_DRM_PLANE_H_ diff --git a/drm/DrmCrtc.cpp b/drm/DrmCrtc.cpp new file mode 100644 index 0000000..4ce8cfc --- /dev/null +++ b/drm/DrmCrtc.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "hwc-drm-crtc" + +#include "DrmCrtc.h" + +#include +#include +#include + +#include "DrmDevice.h" + +namespace android { + +DrmCrtc::DrmCrtc(DrmDevice *drm, drmModeCrtcPtr c, unsigned pipe) + : drm_(drm), id_(c->crtc_id), pipe_(pipe), display_(-1), mode_(&c->mode) { +} + +int DrmCrtc::Init() { + int ret = drm_->GetCrtcProperty(*this, "ACTIVE", &active_property_); + if (ret) { + ALOGE("Failed to get ACTIVE property"); + return ret; + } + + ret = drm_->GetCrtcProperty(*this, "MODE_ID", &mode_property_); + if (ret) { + ALOGE("Failed to get MODE_ID property"); + return ret; + } + + ret = drm_->GetCrtcProperty(*this, "OUT_FENCE_PTR", &out_fence_ptr_property_); + if (ret) { + ALOGE("Failed to get OUT_FENCE_PTR property"); + return ret; + } + return 0; +} + +uint32_t DrmCrtc::id() const { + return id_; +} + +unsigned DrmCrtc::pipe() const { + return pipe_; +} + +int DrmCrtc::display() const { + return display_; +} + +void DrmCrtc::set_display(int display) { + display_ = display; +} + +bool DrmCrtc::can_bind(int display) const { + return display_ == -1 || display_ == display; +} + +const DrmProperty &DrmCrtc::active_property() const { + return active_property_; +} + +const DrmProperty &DrmCrtc::mode_property() const { + return mode_property_; +} + +const DrmProperty &DrmCrtc::out_fence_ptr_property() const { + return out_fence_ptr_property_; +} +} // namespace android diff --git a/drm/DrmCrtc.h b/drm/DrmCrtc.h new file mode 100644 index 0000000..7972bef --- /dev/null +++ b/drm/DrmCrtc.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_CRTC_H_ +#define ANDROID_DRM_CRTC_H_ + +#include +#include + +#include "DrmMode.h" +#include "DrmProperty.h" + +namespace android { + +class DrmDevice; + +class DrmCrtc { + public: + DrmCrtc(DrmDevice *drm, drmModeCrtcPtr c, unsigned pipe); + DrmCrtc(const DrmCrtc &) = delete; + DrmCrtc &operator=(const DrmCrtc &) = delete; + + int Init(); + + uint32_t id() const; + unsigned pipe() const; + + int display() const; + void set_display(int display); + + bool can_bind(int display) const; + + const DrmProperty &active_property() const; + const DrmProperty &mode_property() const; + const DrmProperty &out_fence_ptr_property() const; + + private: + DrmDevice *drm_; + + uint32_t id_; + unsigned pipe_; + int display_; + + DrmMode mode_; + + DrmProperty active_property_; + DrmProperty mode_property_; + DrmProperty out_fence_ptr_property_; +}; +} // namespace android + +#endif // ANDROID_DRM_CRTC_H_ diff --git a/drm/DrmDevice.cpp b/drm/DrmDevice.cpp new file mode 100644 index 0000000..28ecfda --- /dev/null +++ b/drm/DrmDevice.cpp @@ -0,0 +1,579 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "hwc-drm-device" + +#include "DrmDevice.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static void trim_left(std::string &str) { + str.erase(std::begin(str), + std::find_if(std::begin(str), std::end(str), + [](int ch) { return !std::isspace(ch); })); +} + +static void trim_right(std::string &str) { + str.erase(std::find_if(std::rbegin(str), std::rend(str), + [](int ch) { return !std::isspace(ch); }) + .base(), + std::end(str)); +} + +static void trim(std::string &str) { + trim_left(str); + trim_right(str); +} + +namespace android { + +static std::vector read_primary_display_order_prop() { + std::array display_order_buf; + property_get("vendor.hwc.drm.primary_display_order", display_order_buf.data(), + "..."); + + std::vector display_order; + std::istringstream str(display_order_buf.data()); + for (std::string conn_name = ""; std::getline(str, conn_name, ',');) { + trim(conn_name); + display_order.push_back(std::move(conn_name)); + } + return display_order; +} + +static std::vector make_primary_display_candidates( + std::vector> &connectors) { + std::vector primary_candidates; + std::transform(std::begin(connectors), std::end(connectors), + std::back_inserter(primary_candidates), + [](std::unique_ptr &conn) { + return conn.get(); + }); + primary_candidates.erase(std::remove_if(std::begin(primary_candidates), + std::end(primary_candidates), + [](const DrmConnector *conn) { + return conn->state() != + DRM_MODE_CONNECTED; + }), + std::end(primary_candidates)); + + std::vector display_order = read_primary_display_order_prop(); + bool use_other = display_order.back() == "..."; + + // putting connectors from primary_display_order first + auto curr_connector = std::begin(primary_candidates); + for (const std::string &display_name : display_order) { + auto it = std::find_if(std::begin(primary_candidates), + std::end(primary_candidates), + [&display_name](const DrmConnector *conn) { + return conn->name() == display_name; + }); + if (it != std::end(primary_candidates)) { + std::iter_swap(it, curr_connector); + ++curr_connector; + } + } + + if (use_other) { + // then putting internal connectors second, everything else afterwards + std::partition(curr_connector, std::end(primary_candidates), + [](const DrmConnector *conn) { return conn->internal(); }); + } else { + primary_candidates.erase(curr_connector, std::end(primary_candidates)); + } + + return primary_candidates; +} + +DrmDevice::DrmDevice() : event_listener_(this) { +} + +DrmDevice::~DrmDevice() { + event_listener_.Exit(); +} + +std::tuple DrmDevice::Init(const char *path, int num_displays) { + /* TODO: Use drmOpenControl here instead */ + fd_.Set(open(path, O_RDWR)); + if (fd() < 0) { + ALOGE("Failed to open dri %s: %s", path, strerror(errno)); + return std::make_tuple(-ENODEV, 0); + } + + int ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); + if (ret) { + ALOGE("Failed to set universal plane cap %d", ret); + return std::make_tuple(ret, 0); + } + + ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_ATOMIC, 1); + if (ret) { + ALOGE("Failed to set atomic cap %d", ret); + return std::make_tuple(ret, 0); + } + +#ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS + ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1); + if (ret) { + ALOGI("Failed to set writeback cap %d", ret); + ret = 0; + } +#endif + + drmModeResPtr res = drmModeGetResources(fd()); + if (!res) { + ALOGE("Failed to get DrmDevice resources"); + return std::make_tuple(-ENODEV, 0); + } + + min_resolution_ = std::pair(res->min_width, + res->min_height); + max_resolution_ = std::pair(res->max_width, + res->max_height); + + // Assumes that the primary display will always be in the first + // drm_device opened. + bool found_primary = num_displays != 0; + + for (int i = 0; !ret && i < res->count_crtcs; ++i) { + drmModeCrtcPtr c = drmModeGetCrtc(fd(), res->crtcs[i]); + if (!c) { + ALOGE("Failed to get crtc %d", res->crtcs[i]); + ret = -ENODEV; + break; + } + + std::unique_ptr crtc(new DrmCrtc(this, c, i)); + drmModeFreeCrtc(c); + + ret = crtc->Init(); + if (ret) { + ALOGE("Failed to initialize crtc %d", res->crtcs[i]); + break; + } + crtcs_.emplace_back(std::move(crtc)); + } + + std::vector possible_clones; + for (int i = 0; !ret && i < res->count_encoders; ++i) { + drmModeEncoderPtr e = drmModeGetEncoder(fd(), res->encoders[i]); + if (!e) { + ALOGE("Failed to get encoder %d", res->encoders[i]); + ret = -ENODEV; + break; + } + + std::vector possible_crtcs; + DrmCrtc *current_crtc = NULL; + for (auto &crtc : crtcs_) { + if ((1 << crtc->pipe()) & e->possible_crtcs) + possible_crtcs.push_back(crtc.get()); + + if (crtc->id() == e->crtc_id) + current_crtc = crtc.get(); + } + + std::unique_ptr enc( + new DrmEncoder(e, current_crtc, possible_crtcs)); + possible_clones.push_back(e->possible_clones); + drmModeFreeEncoder(e); + + encoders_.emplace_back(std::move(enc)); + } + + for (unsigned int i = 0; i < encoders_.size(); i++) { + for (unsigned int j = 0; j < encoders_.size(); j++) + if (possible_clones[i] & (1 << j)) + encoders_[i]->AddPossibleClone(encoders_[j].get()); + } + + for (int i = 0; !ret && i < res->count_connectors; ++i) { + drmModeConnectorPtr c = drmModeGetConnector(fd(), res->connectors[i]); + if (!c) { + ALOGE("Failed to get connector %d", res->connectors[i]); + ret = -ENODEV; + break; + } + + std::vector possible_encoders; + DrmEncoder *current_encoder = NULL; + for (int j = 0; j < c->count_encoders; ++j) { + for (auto &encoder : encoders_) { + if (encoder->id() == c->encoders[j]) + possible_encoders.push_back(encoder.get()); + if (encoder->id() == c->encoder_id) + current_encoder = encoder.get(); + } + } + + std::unique_ptr conn( + new DrmConnector(this, c, current_encoder, possible_encoders)); + + drmModeFreeConnector(c); + + ret = conn->Init(); + if (ret) { + ALOGE("Init connector %d failed", res->connectors[i]); + break; + } + + if (conn->writeback()) + writeback_connectors_.emplace_back(std::move(conn)); + else + connectors_.emplace_back(std::move(conn)); + } + + // Primary display priority: + // 1) vendor.hwc.drm.primary_display_order property + // 2) internal connectors + // 3) anything else + std::vector + primary_candidates = make_primary_display_candidates(connectors_); + if (!primary_candidates.empty() && !found_primary) { + DrmConnector &conn = **std::begin(primary_candidates); + conn.set_display(num_displays); + displays_[num_displays] = num_displays; + ++num_displays; + found_primary = true; + } else { + ALOGE( + "Failed to find primary display from " + "\"vendor.hwc.drm.primary_display_order\" property"); + } + + // If no priority display were found then pick first available as primary and + // for the others assign consecutive display_numbers. + for (auto &conn : connectors_) { + if (conn->external() || conn->internal()) { + if (!found_primary) { + conn->set_display(num_displays); + displays_[num_displays] = num_displays; + found_primary = true; + ++num_displays; + } else if (conn->display() < 0) { + conn->set_display(num_displays); + displays_[num_displays] = num_displays; + ++num_displays; + } + } + } + + if (res) + drmModeFreeResources(res); + + // Catch-all for the above loops + if (ret) + return std::make_tuple(ret, 0); + + drmModePlaneResPtr plane_res = drmModeGetPlaneResources(fd()); + if (!plane_res) { + ALOGE("Failed to get plane resources"); + return std::make_tuple(-ENOENT, 0); + } + + for (uint32_t i = 0; i < plane_res->count_planes; ++i) { + drmModePlanePtr p = drmModeGetPlane(fd(), plane_res->planes[i]); + if (!p) { + ALOGE("Failed to get plane %d", plane_res->planes[i]); + ret = -ENODEV; + break; + } + + std::unique_ptr plane(new DrmPlane(this, p)); + + drmModeFreePlane(p); + + ret = plane->Init(); + if (ret) { + ALOGE("Init plane %d failed", plane_res->planes[i]); + break; + } + + planes_.emplace_back(std::move(plane)); + } + drmModeFreePlaneResources(plane_res); + if (ret) + return std::make_tuple(ret, 0); + + ret = event_listener_.Init(); + if (ret) { + ALOGE("Can't initialize event listener %d", ret); + return std::make_tuple(ret, 0); + } + + for (auto &conn : connectors_) { + ret = CreateDisplayPipe(conn.get()); + if (ret) { + ALOGE("Failed CreateDisplayPipe %d with %d", conn->id(), ret); + return std::make_tuple(ret, 0); + } + if (!AttachWriteback(conn.get())) { + ALOGI("Display %d has writeback attach to it", conn->display()); + } + } + return std::make_tuple(ret, displays_.size()); +} + +bool DrmDevice::HandlesDisplay(int display) const { + return displays_.find(display) != displays_.end(); +} + +DrmConnector *DrmDevice::GetConnectorForDisplay(int display) const { + for (auto &conn : connectors_) { + if (conn->display() == display) + return conn.get(); + } + return NULL; +} + +DrmConnector *DrmDevice::GetWritebackConnectorForDisplay(int display) const { + for (auto &conn : writeback_connectors_) { + if (conn->display() == display) + return conn.get(); + } + return NULL; +} + +// TODO what happens when hotplugging +DrmConnector *DrmDevice::AvailableWritebackConnector(int display) const { + DrmConnector *writeback_conn = GetWritebackConnectorForDisplay(display); + DrmConnector *display_conn = GetConnectorForDisplay(display); + // If we have a writeback already attached to the same CRTC just use that, + // if possible. + if (display_conn && writeback_conn && + writeback_conn->encoder()->CanClone(display_conn->encoder())) + return writeback_conn; + + // Use another CRTC if available and doesn't have any connector + for (auto &crtc : crtcs_) { + if (crtc->display() == display) + continue; + display_conn = GetConnectorForDisplay(crtc->display()); + // If we have a display connected don't use it for writeback + if (display_conn && display_conn->state() == DRM_MODE_CONNECTED) + continue; + writeback_conn = GetWritebackConnectorForDisplay(crtc->display()); + if (writeback_conn) + return writeback_conn; + } + return NULL; +} + +DrmCrtc *DrmDevice::GetCrtcForDisplay(int display) const { + for (auto &crtc : crtcs_) { + if (crtc->display() == display) + return crtc.get(); + } + return NULL; +} + +DrmPlane *DrmDevice::GetPlane(uint32_t id) const { + for (auto &plane : planes_) { + if (plane->id() == id) + return plane.get(); + } + return NULL; +} + +const std::vector> &DrmDevice::crtcs() const { + return crtcs_; +} + +uint32_t DrmDevice::next_mode_id() { + return ++mode_id_; +} + +int DrmDevice::TryEncoderForDisplay(int display, DrmEncoder *enc) { + /* First try to use the currently-bound crtc */ + DrmCrtc *crtc = enc->crtc(); + if (crtc && crtc->can_bind(display)) { + crtc->set_display(display); + enc->set_crtc(crtc); + return 0; + } + + /* Try to find a possible crtc which will work */ + for (DrmCrtc *crtc : enc->possible_crtcs()) { + /* We've already tried this earlier */ + if (crtc == enc->crtc()) + continue; + + if (crtc->can_bind(display)) { + crtc->set_display(display); + enc->set_crtc(crtc); + return 0; + } + } + + /* We can't use the encoder, but nothing went wrong, try another one */ + return -EAGAIN; +} + +int DrmDevice::CreateDisplayPipe(DrmConnector *connector) { + int display = connector->display(); + /* Try to use current setup first */ + if (connector->encoder()) { + int ret = TryEncoderForDisplay(display, connector->encoder()); + if (!ret) { + return 0; + } else if (ret != -EAGAIN) { + ALOGE("Could not set mode %d/%d", display, ret); + return ret; + } + } + + for (DrmEncoder *enc : connector->possible_encoders()) { + int ret = TryEncoderForDisplay(display, enc); + if (!ret) { + connector->set_encoder(enc); + return 0; + } else if (ret != -EAGAIN) { + ALOGE("Could not set mode %d/%d", display, ret); + return ret; + } + } + ALOGE("Could not find a suitable encoder/crtc for display %d", + connector->display()); + return -ENODEV; +} + +// Attach writeback connector to the CRTC linked to the display_conn +int DrmDevice::AttachWriteback(DrmConnector *display_conn) { + DrmCrtc *display_crtc = display_conn->encoder()->crtc(); + if (GetWritebackConnectorForDisplay(display_crtc->display()) != NULL) { + ALOGE("Display already has writeback attach to it"); + return -EINVAL; + } + for (auto &writeback_conn : writeback_connectors_) { + if (writeback_conn->display() >= 0) + continue; + for (DrmEncoder *writeback_enc : writeback_conn->possible_encoders()) { + for (DrmCrtc *possible_crtc : writeback_enc->possible_crtcs()) { + if (possible_crtc != display_crtc) + continue; + // Use just encoders which had not been bound already + if (writeback_enc->can_bind(display_crtc->display())) { + writeback_enc->set_crtc(display_crtc); + writeback_conn->set_encoder(writeback_enc); + writeback_conn->set_display(display_crtc->display()); + writeback_conn->UpdateModes(); + return 0; + } + } + } + } + return -EINVAL; +} + +int DrmDevice::CreatePropertyBlob(void *data, size_t length, + uint32_t *blob_id) { + struct drm_mode_create_blob create_blob; + memset(&create_blob, 0, sizeof(create_blob)); + create_blob.length = length; + create_blob.data = (__u64)data; + + int ret = drmIoctl(fd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob); + if (ret) { + ALOGE("Failed to create mode property blob %d", ret); + return ret; + } + *blob_id = create_blob.blob_id; + return 0; +} + +int DrmDevice::DestroyPropertyBlob(uint32_t blob_id) { + if (!blob_id) + return 0; + + struct drm_mode_destroy_blob destroy_blob; + memset(&destroy_blob, 0, sizeof(destroy_blob)); + destroy_blob.blob_id = (__u32)blob_id; + int ret = drmIoctl(fd(), DRM_IOCTL_MODE_DESTROYPROPBLOB, &destroy_blob); + if (ret) { + ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", blob_id, ret); + return ret; + } + return 0; +} + +DrmEventListener *DrmDevice::event_listener() { + return &event_listener_; +} + +int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type, + const char *prop_name, DrmProperty *property) { + drmModeObjectPropertiesPtr props; + + props = drmModeObjectGetProperties(fd(), obj_id, obj_type); + if (!props) { + ALOGE("Failed to get properties for %d/%x", obj_id, obj_type); + return -ENODEV; + } + + bool found = false; + for (int i = 0; !found && (size_t)i < props->count_props; ++i) { + drmModePropertyPtr p = drmModeGetProperty(fd(), props->props[i]); + if (!strcmp(p->name, prop_name)) { + property->Init(p, props->prop_values[i]); + found = true; + } + drmModeFreeProperty(p); + } + + drmModeFreeObjectProperties(props); + return found ? 0 : -ENOENT; +} + +int DrmDevice::GetPlaneProperty(const DrmPlane &plane, const char *prop_name, + DrmProperty *property) { + return GetProperty(plane.id(), DRM_MODE_OBJECT_PLANE, prop_name, property); +} + +int DrmDevice::GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name, + DrmProperty *property) { + return GetProperty(crtc.id(), DRM_MODE_OBJECT_CRTC, prop_name, property); +} + +int DrmDevice::GetConnectorProperty(const DrmConnector &connector, + const char *prop_name, + DrmProperty *property) { + return GetProperty(connector.id(), DRM_MODE_OBJECT_CONNECTOR, prop_name, + property); +} + +const std::string DrmDevice::GetName() const { + auto ver = drmGetVersion(fd_.get()); + if (!ver) { + ALOGW("Failed to get drm version for fd=%d", fd_.get()); + return "generic"; + } + + std::string name(ver->name); + drmFreeVersion(ver); + return name; +} +} // namespace android diff --git a/drm/DrmDevice.h b/drm/DrmDevice.h new file mode 100644 index 0000000..d7ea359 --- /dev/null +++ b/drm/DrmDevice.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_H_ +#define ANDROID_DRM_H_ + +#include + +#include + +#include "DrmConnector.h" +#include "DrmCrtc.h" +#include "DrmEncoder.h" +#include "DrmEventListener.h" +#include "DrmPlane.h" +#include "platform/platform.h" + +namespace android { + +class DrmDevice { + public: + DrmDevice(); + ~DrmDevice(); + + std::tuple Init(const char *path, int num_displays); + + int fd() const { + return fd_.get(); + } + + const std::vector> &connectors() const { + return connectors_; + } + + const std::vector> &planes() const { + return planes_; + } + + std::pair min_resolution() const { + return min_resolution_; + } + + std::pair max_resolution() const { + return max_resolution_; + } + + DrmConnector *GetConnectorForDisplay(int display) const; + DrmConnector *GetWritebackConnectorForDisplay(int display) const; + DrmConnector *AvailableWritebackConnector(int display) const; + DrmCrtc *GetCrtcForDisplay(int display) const; + DrmPlane *GetPlane(uint32_t id) const; + DrmEventListener *event_listener(); + + int GetPlaneProperty(const DrmPlane &plane, const char *prop_name, + DrmProperty *property); + int GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name, + DrmProperty *property); + int GetConnectorProperty(const DrmConnector &connector, const char *prop_name, + DrmProperty *property); + + const std::string GetName() const; + + const std::vector> &crtcs() const; + uint32_t next_mode_id(); + + int CreatePropertyBlob(void *data, size_t length, uint32_t *blob_id); + int DestroyPropertyBlob(uint32_t blob_id); + bool HandlesDisplay(int display) const; + void RegisterHotplugHandler(DrmEventHandler *handler) { + event_listener_.RegisterHotplugHandler(handler); + } + + private: + int TryEncoderForDisplay(int display, DrmEncoder *enc); + int GetProperty(uint32_t obj_id, uint32_t obj_type, const char *prop_name, + DrmProperty *property); + + int CreateDisplayPipe(DrmConnector *connector); + int AttachWriteback(DrmConnector *display_conn); + + UniqueFd fd_; + uint32_t mode_id_ = 0; + + std::vector> connectors_; + std::vector> writeback_connectors_; + std::vector> encoders_; + std::vector> crtcs_; + std::vector> planes_; + DrmEventListener event_listener_; + + std::pair min_resolution_; + std::pair max_resolution_; + std::map displays_; +}; +} // namespace android + +#endif // ANDROID_DRM_H_ diff --git a/drm/DrmEncoder.cpp b/drm/DrmEncoder.cpp new file mode 100644 index 0000000..bcf0926 --- /dev/null +++ b/drm/DrmEncoder.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015 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 "DrmEncoder.h" + +#include +#include + +#include "DrmDevice.h" + +namespace android { + +DrmEncoder::DrmEncoder(drmModeEncoderPtr e, DrmCrtc *current_crtc, + const std::vector &possible_crtcs) + : id_(e->encoder_id), + crtc_(current_crtc), + display_(-1), + possible_crtcs_(possible_crtcs) { +} + +uint32_t DrmEncoder::id() const { + return id_; +} + +DrmCrtc *DrmEncoder::crtc() const { + return crtc_; +} + +bool DrmEncoder::CanClone(DrmEncoder *possible_clone) { + return possible_clones_.find(possible_clone) != possible_clones_.end(); +} + +void DrmEncoder::AddPossibleClone(DrmEncoder *possible_clone) { + possible_clones_.insert(possible_clone); +} + +void DrmEncoder::set_crtc(DrmCrtc *crtc) { + crtc_ = crtc; + display_ = crtc->display(); +} + +int DrmEncoder::display() const { + return display_; +} + +bool DrmEncoder::can_bind(int display) const { + return display_ == -1 || display_ == display; +} +} // namespace android diff --git a/drm/DrmEncoder.h b/drm/DrmEncoder.h new file mode 100644 index 0000000..f4464d0 --- /dev/null +++ b/drm/DrmEncoder.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_ENCODER_H_ +#define ANDROID_DRM_ENCODER_H_ + +#include +#include + +#include +#include + +#include "DrmCrtc.h" + +namespace android { + +class DrmEncoder { + public: + DrmEncoder(drmModeEncoderPtr e, DrmCrtc *current_crtc, + const std::vector &possible_crtcs); + DrmEncoder(const DrmEncoder &) = delete; + DrmEncoder &operator=(const DrmEncoder &) = delete; + + uint32_t id() const; + + DrmCrtc *crtc() const; + void set_crtc(DrmCrtc *crtc); + bool can_bind(int display) const; + int display() const; + + const std::vector &possible_crtcs() const { + return possible_crtcs_; + } + bool CanClone(DrmEncoder *encoder); + void AddPossibleClone(DrmEncoder *possible_clone); + + private: + uint32_t id_; + DrmCrtc *crtc_; + int display_; + + std::vector possible_crtcs_; + std::set possible_clones_; +}; +} // namespace android + +#endif // ANDROID_DRM_ENCODER_H_ diff --git a/drm/DrmEventListener.cpp b/drm/DrmEventListener.cpp new file mode 100644 index 0000000..3d95e28 --- /dev/null +++ b/drm/DrmEventListener.cpp @@ -0,0 +1,138 @@ +/* + * 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 LOG_TAG "hwc-drm-event-listener" + +#include "DrmEventListener.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DrmDevice.h" + +namespace android { + +DrmEventListener::DrmEventListener(DrmDevice *drm) + : Worker("drm-event-listener", HAL_PRIORITY_URGENT_DISPLAY), drm_(drm) { +} + +int DrmEventListener::Init() { + uevent_fd_.Set(socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT)); + if (uevent_fd_.get() < 0) { + ALOGE("Failed to open uevent socket: %s", strerror(errno)); + return uevent_fd_.get(); + } + + struct sockaddr_nl addr; + memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + addr.nl_pid = 0; + addr.nl_groups = 0xFFFFFFFF; + + int ret = bind(uevent_fd_.get(), (struct sockaddr *)&addr, sizeof(addr)); + if (ret) { + ALOGE("Failed to bind uevent socket: %s", strerror(errno)); + return -errno; + } + + FD_ZERO(&fds_); + FD_SET(drm_->fd(), &fds_); + FD_SET(uevent_fd_.get(), &fds_); + max_fd_ = std::max(drm_->fd(), uevent_fd_.get()); + + return InitWorker(); +} + +void DrmEventListener::RegisterHotplugHandler(DrmEventHandler *handler) { + assert(!hotplug_handler_); + hotplug_handler_.reset(handler); +} + +void DrmEventListener::FlipHandler(int /* fd */, unsigned int /* sequence */, + unsigned int tv_sec, unsigned int tv_usec, + void *user_data) { + DrmEventHandler *handler = (DrmEventHandler *)user_data; + if (!handler) + return; + + handler->HandleEvent((uint64_t)tv_sec * 1000 * 1000 + tv_usec); + delete handler; +} + +void DrmEventListener::UEventHandler() { + char buffer[1024]; + int ret; + + struct timespec ts; + uint64_t timestamp = 0; + ret = clock_gettime(CLOCK_MONOTONIC, &ts); + if (!ret) + timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; + else + ALOGE("Failed to get monotonic clock on hotplug %d", ret); + + while (true) { + ret = read(uevent_fd_.get(), &buffer, sizeof(buffer)); + if (ret == 0) { + return; + } else if (ret < 0) { + ALOGE("Got error reading uevent %d", ret); + return; + } + + if (!hotplug_handler_) + continue; + + bool drm_event = false, hotplug_event = false; + for (int i = 0; i < ret;) { + char *event = buffer + i; + if (strcmp(event, "DEVTYPE=drm_minor")) + drm_event = true; + else if (strcmp(event, "HOTPLUG=1")) + hotplug_event = true; + + i += strlen(event) + 1; + } + + if (drm_event && hotplug_event) + hotplug_handler_->HandleEvent(timestamp); + } +} + +void DrmEventListener::Routine() { + int ret; + do { + ret = select(max_fd_ + 1, &fds_, NULL, NULL, NULL); + } while (ret == -1 && errno == EINTR); + + if (FD_ISSET(drm_->fd(), &fds_)) { + drmEventContext event_context = + {.version = 2, + .vblank_handler = NULL, + .page_flip_handler = DrmEventListener::FlipHandler}; + drmHandleEvent(drm_->fd(), &event_context); + } + + if (FD_ISSET(uevent_fd_.get(), &fds_)) + UEventHandler(); +} +} // namespace android diff --git a/drm/DrmEventListener.h b/drm/DrmEventListener.h new file mode 100644 index 0000000..9f9a4ba --- /dev/null +++ b/drm/DrmEventListener.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#ifndef ANDROID_DRM_EVENT_LISTENER_H_ +#define ANDROID_DRM_EVENT_LISTENER_H_ + +#include "autofd.h" +#include "utils/Worker.h" + +namespace android { + +class DrmDevice; + +class DrmEventHandler { + public: + DrmEventHandler() { + } + virtual ~DrmEventHandler() { + } + + virtual void HandleEvent(uint64_t timestamp_us) = 0; +}; + +class DrmEventListener : public Worker { + public: + DrmEventListener(DrmDevice *drm); + virtual ~DrmEventListener() { + } + + int Init(); + + void RegisterHotplugHandler(DrmEventHandler *handler); + + static void FlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, + unsigned int tv_usec, void *user_data); + + protected: + virtual void Routine(); + + private: + void UEventHandler(); + + fd_set fds_; + UniqueFd uevent_fd_; + int max_fd_ = -1; + + DrmDevice *drm_; + std::unique_ptr hotplug_handler_; +}; +} // namespace android + +#endif diff --git a/drm/DrmMode.cpp b/drm/DrmMode.cpp new file mode 100644 index 0000000..6de671a --- /dev/null +++ b/drm/DrmMode.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2015 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 "DrmMode.h" + +#include "DrmDevice.h" + +namespace android { + +DrmMode::DrmMode(drmModeModeInfoPtr m) + : id_(0), + clock_(m->clock), + h_display_(m->hdisplay), + h_sync_start_(m->hsync_start), + h_sync_end_(m->hsync_end), + h_total_(m->htotal), + h_skew_(m->hskew), + v_display_(m->vdisplay), + v_sync_start_(m->vsync_start), + v_sync_end_(m->vsync_end), + v_total_(m->vtotal), + v_scan_(m->vscan), + v_refresh_(m->vrefresh), + flags_(m->flags), + type_(m->type), + name_(m->name) { +} + +bool DrmMode::operator==(const drmModeModeInfo &m) const { + return clock_ == m.clock && h_display_ == m.hdisplay && + h_sync_start_ == m.hsync_start && h_sync_end_ == m.hsync_end && + h_total_ == m.htotal && h_skew_ == m.hskew && + v_display_ == m.vdisplay && v_sync_start_ == m.vsync_start && + v_sync_end_ == m.vsync_end && v_total_ == m.vtotal && + v_scan_ == m.vscan && flags_ == m.flags && type_ == m.type; +} + +void DrmMode::ToDrmModeModeInfo(drm_mode_modeinfo *m) const { + m->clock = clock_; + m->hdisplay = h_display_; + m->hsync_start = h_sync_start_; + m->hsync_end = h_sync_end_; + m->htotal = h_total_; + m->hskew = h_skew_; + m->vdisplay = v_display_; + m->vsync_start = v_sync_start_; + m->vsync_end = v_sync_end_; + m->vtotal = v_total_; + m->vscan = v_scan_; + m->vrefresh = v_refresh_; + m->flags = flags_; + m->type = type_; + strncpy(m->name, name_.c_str(), DRM_DISPLAY_MODE_LEN); +} + +uint32_t DrmMode::id() const { + return id_; +} + +void DrmMode::set_id(uint32_t id) { + id_ = id; +} + +uint32_t DrmMode::clock() const { + return clock_; +} + +uint32_t DrmMode::h_display() const { + return h_display_; +} + +uint32_t DrmMode::h_sync_start() const { + return h_sync_start_; +} + +uint32_t DrmMode::h_sync_end() const { + return h_sync_end_; +} + +uint32_t DrmMode::h_total() const { + return h_total_; +} + +uint32_t DrmMode::h_skew() const { + return h_skew_; +} + +uint32_t DrmMode::v_display() const { + return v_display_; +} + +uint32_t DrmMode::v_sync_start() const { + return v_sync_start_; +} + +uint32_t DrmMode::v_sync_end() const { + return v_sync_end_; +} + +uint32_t DrmMode::v_total() const { + return v_total_; +} + +uint32_t DrmMode::v_scan() const { + return v_scan_; +} + +float DrmMode::v_refresh() const { + // Always recalculate refresh to report correct float rate + return clock_ / (float)(v_total_ * h_total_) * 1000.0f; +} + +uint32_t DrmMode::flags() const { + return flags_; +} + +uint32_t DrmMode::type() const { + return type_; +} + +std::string DrmMode::name() const { + return name_; +} +} // namespace android diff --git a/drm/DrmMode.h b/drm/DrmMode.h new file mode 100644 index 0000000..313a8ea --- /dev/null +++ b/drm/DrmMode.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_MODE_H_ +#define ANDROID_DRM_MODE_H_ + +#include +#include + +#include + +namespace android { + +class DrmMode { + public: + DrmMode() = default; + DrmMode(drmModeModeInfoPtr m); + + bool operator==(const drmModeModeInfo &m) const; + void ToDrmModeModeInfo(drm_mode_modeinfo *m) const; + + uint32_t id() const; + void set_id(uint32_t id); + + uint32_t clock() const; + + uint32_t h_display() const; + uint32_t h_sync_start() const; + uint32_t h_sync_end() const; + uint32_t h_total() const; + uint32_t h_skew() const; + + uint32_t v_display() const; + uint32_t v_sync_start() const; + uint32_t v_sync_end() const; + uint32_t v_total() const; + uint32_t v_scan() const; + float v_refresh() const; + + uint32_t flags() const; + uint32_t type() const; + + std::string name() const; + + private: + uint32_t id_ = 0; + + uint32_t clock_ = 0; + + uint32_t h_display_ = 0; + uint32_t h_sync_start_ = 0; + uint32_t h_sync_end_ = 0; + uint32_t h_total_ = 0; + uint32_t h_skew_ = 0; + + uint32_t v_display_ = 0; + uint32_t v_sync_start_ = 0; + uint32_t v_sync_end_ = 0; + uint32_t v_total_ = 0; + uint32_t v_scan_ = 0; + uint32_t v_refresh_ = 0; + + uint32_t flags_ = 0; + uint32_t type_ = 0; + + std::string name_; +}; +} // namespace android + +#endif // ANDROID_DRM_MODE_H_ diff --git a/drm/DrmPlane.cpp b/drm/DrmPlane.cpp new file mode 100644 index 0000000..1fb1316 --- /dev/null +++ b/drm/DrmPlane.cpp @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "hwc-drm-plane" + +#include "DrmPlane.h" + +#include +#include +#include + +#include + +#include "DrmDevice.h" + +namespace android { + +DrmPlane::DrmPlane(DrmDevice *drm, drmModePlanePtr p) + : drm_(drm), id_(p->plane_id), possible_crtc_mask_(p->possible_crtcs) { +} + +int DrmPlane::Init() { + DrmProperty p; + + int ret = drm_->GetPlaneProperty(*this, "type", &p); + if (ret) { + ALOGE("Could not get plane type property"); + return ret; + } + + uint64_t type; + std::tie(ret, type) = p.value(); + if (ret) { + ALOGE("Failed to get plane type property value"); + return ret; + } + switch (type) { + case DRM_PLANE_TYPE_OVERLAY: + case DRM_PLANE_TYPE_PRIMARY: + case DRM_PLANE_TYPE_CURSOR: + type_ = (uint32_t)type; + break; + default: + ALOGE("Invalid plane type %" PRIu64, type); + return -EINVAL; + } + + ret = drm_->GetPlaneProperty(*this, "CRTC_ID", &crtc_property_); + if (ret) { + ALOGE("Could not get CRTC_ID property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "FB_ID", &fb_property_); + if (ret) { + ALOGE("Could not get FB_ID property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "CRTC_X", &crtc_x_property_); + if (ret) { + ALOGE("Could not get CRTC_X property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "CRTC_Y", &crtc_y_property_); + if (ret) { + ALOGE("Could not get CRTC_Y property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "CRTC_W", &crtc_w_property_); + if (ret) { + ALOGE("Could not get CRTC_W property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "CRTC_H", &crtc_h_property_); + if (ret) { + ALOGE("Could not get CRTC_H property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "SRC_X", &src_x_property_); + if (ret) { + ALOGE("Could not get SRC_X property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "SRC_Y", &src_y_property_); + if (ret) { + ALOGE("Could not get SRC_Y property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "SRC_W", &src_w_property_); + if (ret) { + ALOGE("Could not get SRC_W property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "SRC_H", &src_h_property_); + if (ret) { + ALOGE("Could not get SRC_H property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "zpos", &zpos_property_); + if (ret) + ALOGE("Could not get zpos property for plane %u", id()); + + ret = drm_->GetPlaneProperty(*this, "rotation", &rotation_property_); + if (ret) + ALOGE("Could not get rotation property"); + + ret = drm_->GetPlaneProperty(*this, "alpha", &alpha_property_); + if (ret) + ALOGI("Could not get alpha property"); + + ret = drm_->GetPlaneProperty(*this, "pixel blend mode", &blend_property_); + if (ret) + ALOGI("Could not get pixel blend mode property"); + + ret = drm_->GetPlaneProperty(*this, "IN_FENCE_FD", &in_fence_fd_property_); + if (ret) + ALOGI("Could not get IN_FENCE_FD property"); + + return 0; +} + +uint32_t DrmPlane::id() const { + return id_; +} + +bool DrmPlane::GetCrtcSupported(const DrmCrtc &crtc) const { + return !!((1 << crtc.pipe()) & possible_crtc_mask_); +} + +uint32_t DrmPlane::type() const { + return type_; +} + +const DrmProperty &DrmPlane::crtc_property() const { + return crtc_property_; +} + +const DrmProperty &DrmPlane::fb_property() const { + return fb_property_; +} + +const DrmProperty &DrmPlane::crtc_x_property() const { + return crtc_x_property_; +} + +const DrmProperty &DrmPlane::crtc_y_property() const { + return crtc_y_property_; +} + +const DrmProperty &DrmPlane::crtc_w_property() const { + return crtc_w_property_; +} + +const DrmProperty &DrmPlane::crtc_h_property() const { + return crtc_h_property_; +} + +const DrmProperty &DrmPlane::src_x_property() const { + return src_x_property_; +} + +const DrmProperty &DrmPlane::src_y_property() const { + return src_y_property_; +} + +const DrmProperty &DrmPlane::src_w_property() const { + return src_w_property_; +} + +const DrmProperty &DrmPlane::src_h_property() const { + return src_h_property_; +} + +const DrmProperty &DrmPlane::zpos_property() const { + return zpos_property_; +} + +const DrmProperty &DrmPlane::rotation_property() const { + return rotation_property_; +} + +const DrmProperty &DrmPlane::alpha_property() const { + return alpha_property_; +} + +const DrmProperty &DrmPlane::blend_property() const { + return blend_property_; +} + +const DrmProperty &DrmPlane::in_fence_fd_property() const { + return in_fence_fd_property_; +} +} // namespace android diff --git a/drm/DrmPlane.h b/drm/DrmPlane.h new file mode 100644 index 0000000..d2f0601 --- /dev/null +++ b/drm/DrmPlane.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_PLANE_H_ +#define ANDROID_DRM_PLANE_H_ + +#include +#include + +#include + +#include "DrmCrtc.h" +#include "DrmProperty.h" + +namespace android { + +class DrmDevice; + +class DrmPlane { + public: + DrmPlane(DrmDevice *drm, drmModePlanePtr p); + DrmPlane(const DrmPlane &) = delete; + DrmPlane &operator=(const DrmPlane &) = delete; + + int Init(); + + uint32_t id() const; + + bool GetCrtcSupported(const DrmCrtc &crtc) const; + + uint32_t type() const; + + const DrmProperty &crtc_property() const; + const DrmProperty &fb_property() const; + const DrmProperty &crtc_x_property() const; + const DrmProperty &crtc_y_property() const; + const DrmProperty &crtc_w_property() const; + const DrmProperty &crtc_h_property() const; + const DrmProperty &src_x_property() const; + const DrmProperty &src_y_property() const; + const DrmProperty &src_w_property() const; + const DrmProperty &src_h_property() const; + const DrmProperty &zpos_property() const; + const DrmProperty &rotation_property() const; + const DrmProperty &alpha_property() const; + const DrmProperty &blend_property() const; + const DrmProperty &in_fence_fd_property() const; + + private: + DrmDevice *drm_; + uint32_t id_; + + uint32_t possible_crtc_mask_; + + uint32_t type_; + + DrmProperty crtc_property_; + DrmProperty fb_property_; + DrmProperty crtc_x_property_; + DrmProperty crtc_y_property_; + DrmProperty crtc_w_property_; + DrmProperty crtc_h_property_; + DrmProperty src_x_property_; + DrmProperty src_y_property_; + DrmProperty src_w_property_; + DrmProperty src_h_property_; + DrmProperty zpos_property_; + DrmProperty rotation_property_; + DrmProperty alpha_property_; + DrmProperty blend_property_; + DrmProperty in_fence_fd_property_; +}; +} // namespace android + +#endif // ANDROID_DRM_PLANE_H_ diff --git a/drm/DrmProperty.cpp b/drm/DrmProperty.cpp new file mode 100644 index 0000000..b60a76e --- /dev/null +++ b/drm/DrmProperty.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2015 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 "DrmProperty.h" + +#include +#include +#include + +#include + +#include "DrmDevice.h" + +namespace android { + +DrmProperty::DrmPropertyEnum::DrmPropertyEnum(drm_mode_property_enum *e) + : value_(e->value), name_(e->name) { +} + +DrmProperty::DrmPropertyEnum::~DrmPropertyEnum() { +} + +DrmProperty::DrmProperty(drmModePropertyPtr p, uint64_t value) + : id_(0), type_(DRM_PROPERTY_TYPE_INVALID), flags_(0), name_("") { + Init(p, value); +} + +void DrmProperty::Init(drmModePropertyPtr p, uint64_t value) { + id_ = p->prop_id; + flags_ = p->flags; + name_ = p->name; + value_ = value; + + for (int i = 0; i < p->count_values; ++i) + values_.push_back(p->values[i]); + + for (int i = 0; i < p->count_enums; ++i) + enums_.push_back(DrmPropertyEnum(&p->enums[i])); + + for (int i = 0; i < p->count_blobs; ++i) + blob_ids_.push_back(p->blob_ids[i]); + + if (flags_ & DRM_MODE_PROP_RANGE) + type_ = DRM_PROPERTY_TYPE_INT; + else if (flags_ & DRM_MODE_PROP_ENUM) + type_ = DRM_PROPERTY_TYPE_ENUM; + else if (flags_ & DRM_MODE_PROP_OBJECT) + type_ = DRM_PROPERTY_TYPE_OBJECT; + else if (flags_ & DRM_MODE_PROP_BLOB) + type_ = DRM_PROPERTY_TYPE_BLOB; +} + +uint32_t DrmProperty::id() const { + return id_; +} + +std::string DrmProperty::name() const { + return name_; +} + +std::tuple DrmProperty::value() const { + if (type_ == DRM_PROPERTY_TYPE_BLOB) + return std::make_tuple(0, value_); + + if (values_.size() == 0) + return std::make_tuple(-ENOENT, 0); + + switch (type_) { + case DRM_PROPERTY_TYPE_INT: + return std::make_tuple(0, value_); + + case DRM_PROPERTY_TYPE_ENUM: + if (value_ >= enums_.size()) + return std::make_tuple(-ENOENT, 0); + + return std::make_tuple(0, enums_[value_].value_); + + case DRM_PROPERTY_TYPE_OBJECT: + return std::make_tuple(0, value_); + + default: + return std::make_tuple(-EINVAL, 0); + } +} + +bool DrmProperty::is_immutable() const { + return id_ && (flags_ & DRM_MODE_PROP_IMMUTABLE); +} + +bool DrmProperty::is_range() const { + return id_ && (flags_ & DRM_MODE_PROP_RANGE); +} + +std::tuple DrmProperty::range_min() const { + if (!is_range()) + return std::make_tuple(-EINVAL, 0); + if (values_.size() < 1) + return std::make_tuple(-ENOENT, 0); + + return std::make_tuple(0, values_[0]); +} + +std::tuple DrmProperty::range_max() const { + if (!is_range()) + return std::make_tuple(-EINVAL, 0); + if (values_.size() < 2) + return std::make_tuple(-ENOENT, 0); + + return std::make_tuple(0, values_[1]); +} + +std::tuple DrmProperty::GetEnumValueWithName( + std::string name) const { + for (auto it : enums_) { + if (it.name_.compare(name) == 0) { + return std::make_tuple(it.value_, 0); + } + } + + return std::make_tuple(UINT64_MAX, -EINVAL); +} +} // namespace android diff --git a/drm/DrmProperty.h b/drm/DrmProperty.h new file mode 100644 index 0000000..d293da3 --- /dev/null +++ b/drm/DrmProperty.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_PROPERTY_H_ +#define ANDROID_DRM_PROPERTY_H_ + +#include +#include + +#include +#include + +namespace android { + +enum DrmPropertyType { + DRM_PROPERTY_TYPE_INT, + DRM_PROPERTY_TYPE_ENUM, + DRM_PROPERTY_TYPE_OBJECT, + DRM_PROPERTY_TYPE_BLOB, + DRM_PROPERTY_TYPE_INVALID, +}; + +class DrmProperty { + public: + DrmProperty() = default; + DrmProperty(drmModePropertyPtr p, uint64_t value); + DrmProperty(const DrmProperty &) = delete; + DrmProperty &operator=(const DrmProperty &) = delete; + + void Init(drmModePropertyPtr p, uint64_t value); + std::tuple GetEnumValueWithName(std::string name) const; + + uint32_t id() const; + std::string name() const; + + std::tuple value() const; + bool is_immutable() const; + + bool is_range() const; + std::tuple range_min() const; + std::tuple range_max() const; + + private: + class DrmPropertyEnum { + public: + DrmPropertyEnum(drm_mode_property_enum *e); + ~DrmPropertyEnum(); + + uint64_t value_; + std::string name_; + }; + + uint32_t id_ = 0; + + DrmPropertyType type_ = DRM_PROPERTY_TYPE_INVALID; + uint32_t flags_ = 0; + std::string name_; + uint64_t value_ = 0; + + std::vector values_; + std::vector enums_; + std::vector blob_ids_; +}; +} // namespace android + +#endif // ANDROID_DRM_PROPERTY_H_ diff --git a/drm/ResourceManager.cpp b/drm/ResourceManager.cpp new file mode 100644 index 0000000..67ef7f8 --- /dev/null +++ b/drm/ResourceManager.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "hwc-resource-manager" + +#include "ResourceManager.h" + +#include +#include +#include + +#include + +namespace android { + +ResourceManager::ResourceManager() : num_displays_(0), gralloc_(NULL) { +} + +int ResourceManager::Init() { + char path_pattern[PROPERTY_VALUE_MAX]; + // Could be a valid path or it can have at the end of it the wildcard % + // which means that it will try open all devices until an error is met. + int path_len = property_get("vendor.hwc.drm.device", path_pattern, + "/dev/dri/card%"); + int ret = 0; + if (path_pattern[path_len - 1] != '%') { + ret = AddDrmDevice(std::string(path_pattern)); + } else { + path_pattern[path_len - 1] = '\0'; + for (int idx = 0; !ret; ++idx) { + std::ostringstream path; + path << path_pattern << idx; + + struct stat buf; + if (stat(path.str().c_str(), &buf)) { + break; + } else if (IsKMSDev(path.str().c_str())) { + ret = AddDrmDevice(path.str()); + } + } + } + + if (!num_displays_) { + ALOGE("Failed to initialize any displays"); + return ret ? -EINVAL : ret; + } + + char scale_with_gpu[PROPERTY_VALUE_MAX]; + property_get("vendor.hwc.drm.scale_with_gpu", scale_with_gpu, "0"); + scale_with_gpu_ = bool(strncmp(scale_with_gpu, "0", 1)); + + return hw_get_module(GRALLOC_HARDWARE_MODULE_ID, + (const hw_module_t **)&gralloc_); +} + +int ResourceManager::AddDrmDevice(std::string path) { + std::unique_ptr drm = std::make_unique(); + int displays_added, ret; + std::tie(ret, displays_added) = drm->Init(path.c_str(), num_displays_); + if (ret) + return ret; + std::shared_ptr importer; + importer.reset(Importer::CreateInstance(drm.get())); + if (!importer) { + ALOGE("Failed to create importer instance"); + return -ENODEV; + } + importers_.push_back(importer); + drms_.push_back(std::move(drm)); + num_displays_ += displays_added; + return ret; +} + +DrmConnector *ResourceManager::AvailableWritebackConnector(int display) { + DrmDevice *drm_device = GetDrmDevice(display); + DrmConnector *writeback_conn = NULL; + if (drm_device) { + writeback_conn = drm_device->AvailableWritebackConnector(display); + if (writeback_conn) + return writeback_conn; + } + for (auto &drm : drms_) { + if (drm.get() == drm_device) + continue; + writeback_conn = drm->AvailableWritebackConnector(display); + if (writeback_conn) + return writeback_conn; + } + return writeback_conn; +} + +bool ResourceManager::IsKMSDev(const char *path) { + int fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) + return false; + + auto res = drmModeGetResources(fd); + if (!res) { + close(fd); + return false; + } + + bool is_kms = res->count_crtcs > 0 && res->count_connectors > 0 && + res->count_encoders > 0; + + drmModeFreeResources(res); + close(fd); + + return is_kms; +} + +DrmDevice *ResourceManager::GetDrmDevice(int display) { + for (auto &drm : drms_) { + if (drm->HandlesDisplay(display)) + return drm.get(); + } + return NULL; +} + +std::shared_ptr ResourceManager::GetImporter(int display) { + for (unsigned int i = 0; i < drms_.size(); i++) { + if (drms_[i]->HandlesDisplay(display)) + return importers_[i]; + } + return NULL; +} + +const gralloc_module_t *ResourceManager::gralloc() { + return gralloc_; +} +} // namespace android diff --git a/drm/ResourceManager.h b/drm/ResourceManager.h new file mode 100644 index 0000000..94ba43e --- /dev/null +++ b/drm/ResourceManager.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RESOURCEMANAGER_H +#define RESOURCEMANAGER_H + +#include + +#include "DrmDevice.h" +#include "platform/platform.h" + +namespace android { + +class ResourceManager { + public: + ResourceManager(); + ResourceManager(const ResourceManager &) = delete; + ResourceManager &operator=(const ResourceManager &) = delete; + int Init(); + DrmDevice *GetDrmDevice(int display); + std::shared_ptr GetImporter(int display); + const gralloc_module_t *gralloc(); + DrmConnector *AvailableWritebackConnector(int display); + const std::vector> &getDrmDevices() const { + return drms_; + } + int getDisplayCount() const { + return num_displays_; + } + bool ForcedScalingWithGpu() { + return scale_with_gpu_; + } + + private: + int AddDrmDevice(std::string path); + static bool IsKMSDev(const char *path); + + int num_displays_; + std::vector> drms_; + std::vector> importers_; + const gralloc_module_t *gralloc_; + + bool scale_with_gpu_; +}; +} // namespace android + +#endif // RESOURCEMANAGER_H diff --git a/drm/VSyncWorker.cpp b/drm/VSyncWorker.cpp new file mode 100644 index 0000000..dfbf8ce --- /dev/null +++ b/drm/VSyncWorker.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "hwc-vsync-worker" + +#include "VSyncWorker.h" + +#include +#include +#include +#include +#include + +namespace android { + +VSyncWorker::VSyncWorker() + : Worker("vsync", HAL_PRIORITY_URGENT_DISPLAY), + drm_(NULL), + display_(-1), + enabled_(false), + last_timestamp_(-1) { +} + +VSyncWorker::~VSyncWorker() { +} + +int VSyncWorker::Init(DrmDevice *drm, int display) { + drm_ = drm; + display_ = display; + + return InitWorker(); +} + +void VSyncWorker::RegisterCallback(std::shared_ptr callback) { + Lock(); + callback_ = callback; + Unlock(); +} + +void VSyncWorker::VSyncControl(bool enabled) { + Lock(); + enabled_ = enabled; + last_timestamp_ = -1; + Unlock(); + + Signal(); +} + +/* + * Returns the timestamp of the next vsync in phase with last_timestamp_. + * For example: + * last_timestamp_ = 137 + * frame_ns = 50 + * current = 683 + * + * ret = (50 * ((683 - 137)/50 + 1)) + 137 + * ret = 687 + * + * Thus, we must sleep until timestamp 687 to maintain phase with the last + * timestamp. + */ +int64_t VSyncWorker::GetPhasedVSync(int64_t frame_ns, int64_t current) { + if (last_timestamp_ < 0) + return current + frame_ns; + + return frame_ns * ((current - last_timestamp_) / frame_ns + 1) + + last_timestamp_; +} + +static const int64_t kOneSecondNs = 1 * 1000 * 1000 * 1000; + +int VSyncWorker::SyntheticWaitVBlank(int64_t *timestamp) { + struct timespec vsync; + int ret = clock_gettime(CLOCK_MONOTONIC, &vsync); + + float refresh = 60.0f; // Default to 60Hz refresh rate + DrmConnector *conn = drm_->GetConnectorForDisplay(display_); + if (conn && conn->active_mode().v_refresh() != 0.0f) + refresh = conn->active_mode().v_refresh(); + else + ALOGW("Vsync worker active with conn=%p refresh=%f\n", conn, + conn ? conn->active_mode().v_refresh() : 0.0f); + + int64_t phased_timestamp = GetPhasedVSync(kOneSecondNs / refresh, + vsync.tv_sec * kOneSecondNs + + vsync.tv_nsec); + vsync.tv_sec = phased_timestamp / kOneSecondNs; + vsync.tv_nsec = phased_timestamp - (vsync.tv_sec * kOneSecondNs); + do { + ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &vsync, NULL); + } while (ret == -1 && errno == EINTR); + if (ret) + return ret; + + *timestamp = (int64_t)vsync.tv_sec * kOneSecondNs + (int64_t)vsync.tv_nsec; + return 0; +} + +void VSyncWorker::Routine() { + int ret; + + Lock(); + if (!enabled_) { + ret = WaitForSignalOrExitLocked(); + if (ret == -EINTR) { + Unlock(); + return; + } + } + + int display = display_; + std::shared_ptr callback(callback_); + Unlock(); + + DrmCrtc *crtc = drm_->GetCrtcForDisplay(display); + if (!crtc) { + ALOGE("Failed to get crtc for display"); + return; + } + uint32_t high_crtc = (crtc->pipe() << DRM_VBLANK_HIGH_CRTC_SHIFT); + + drmVBlank vblank; + memset(&vblank, 0, sizeof(vblank)); + vblank.request.type = (drmVBlankSeqType)( + DRM_VBLANK_RELATIVE | (high_crtc & DRM_VBLANK_HIGH_CRTC_MASK)); + vblank.request.sequence = 1; + + int64_t timestamp; + ret = drmWaitVBlank(drm_->fd(), &vblank); + if (ret == -EINTR) { + return; + } else if (ret) { + ret = SyntheticWaitVBlank(×tamp); + if (ret) + return; + } else { + timestamp = (int64_t)vblank.reply.tval_sec * kOneSecondNs + + (int64_t)vblank.reply.tval_usec * 1000; + } + + /* + * VSync could be disabled during routine execution so it could potentially + * lead to crash since callback's inner hook could be invalid anymore. We have + * no control over lifetime of this hook, therefore we can't rely that it'll + * be valid after vsync disabling. + * + * Blocking VSyncControl to wait until routine + * will finish execution is logically correct way to fix this issue, but it + * creates visible lags and stutters, so we have to resort to other ways of + * mitigating this issue. + * + * Doing check before attempt to invoke callback drastically shortens the + * window when such situation could happen and that allows us to practically + * avoid this issue. + * + * Please note that issue described below is different one and it is related + * to RegisterCallback, not to disabling vsync via VSyncControl. + */ + if (!enabled_) + return; + /* + * 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 callback_ right before calling + * the hook. However, in practice, callback_ is only updated once, so it's not + * worth the overhead. + */ + if (callback) + callback->Callback(display, timestamp); + last_timestamp_ = timestamp; +} +} // namespace android diff --git a/drm/VSyncWorker.h b/drm/VSyncWorker.h new file mode 100644 index 0000000..0121a6c --- /dev/null +++ b/drm/VSyncWorker.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_EVENT_WORKER_H_ +#define ANDROID_EVENT_WORKER_H_ + +#include +#include +#include + +#include + +#include "DrmDevice.h" +#include "utils/Worker.h" + +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(DrmDevice *drm, int display); + void RegisterCallback(std::shared_ptr callback); + + void VSyncControl(bool enabled); + + protected: + void Routine() override; + + private: + int64_t GetPhasedVSync(int64_t frame_ns, int64_t current); + int SyntheticWaitVBlank(int64_t *timestamp); + + DrmDevice *drm_; + + // 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 callback_ = NULL; + + int display_; + std::atomic_bool enabled_; + int64_t last_timestamp_; +}; +} // namespace android + +#endif diff --git a/drm/drmconnector.cpp b/drm/drmconnector.cpp deleted file mode 100644 index 81c2b98..0000000 --- a/drm/drmconnector.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "hwc-drm-connector" - -#include "drmconnector.h" -#include "drmdevice.h" - -#include -#include - -#include -#include - -#include -#include - -namespace android { - -constexpr size_t TYPES_COUNT = 17; - -DrmConnector::DrmConnector(DrmDevice *drm, drmModeConnectorPtr c, - DrmEncoder *current_encoder, - std::vector &possible_encoders) - : drm_(drm), - id_(c->connector_id), - encoder_(current_encoder), - display_(-1), - type_(c->connector_type), - type_id_(c->connector_type_id), - state_(c->connection), - mm_width_(c->mmWidth), - mm_height_(c->mmHeight), - possible_encoders_(possible_encoders) { -} - -int DrmConnector::Init() { - int ret = drm_->GetConnectorProperty(*this, "DPMS", &dpms_property_); - if (ret) { - ALOGE("Could not get DPMS property\n"); - return ret; - } - ret = drm_->GetConnectorProperty(*this, "CRTC_ID", &crtc_id_property_); - if (ret) { - ALOGE("Could not get CRTC_ID property\n"); - return ret; - } - ret = drm_->GetConnectorProperty(*this, "EDID", &edid_property_); - if (ret) { - ALOGW("Could not get EDID property\n"); - } - if (writeback()) { - ret = drm_->GetConnectorProperty(*this, "WRITEBACK_PIXEL_FORMATS", - &writeback_pixel_formats_); - if (ret) { - ALOGE("Could not get WRITEBACK_PIXEL_FORMATS connector_id = %d\n", id_); - return ret; - } - ret = drm_->GetConnectorProperty(*this, "WRITEBACK_FB_ID", - &writeback_fb_id_); - if (ret) { - ALOGE("Could not get WRITEBACK_FB_ID connector_id = %d\n", id_); - return ret; - } - ret = drm_->GetConnectorProperty(*this, "WRITEBACK_OUT_FENCE_PTR", - &writeback_out_fence_); - if (ret) { - ALOGE("Could not get WRITEBACK_OUT_FENCE_PTR connector_id = %d\n", id_); - return ret; - } - } - return 0; -} - -uint32_t DrmConnector::id() const { - return id_; -} - -int DrmConnector::display() const { - return display_; -} - -void DrmConnector::set_display(int display) { - display_ = display; -} - -bool DrmConnector::internal() const { - return type_ == DRM_MODE_CONNECTOR_LVDS || type_ == DRM_MODE_CONNECTOR_eDP || - type_ == DRM_MODE_CONNECTOR_DSI || - type_ == DRM_MODE_CONNECTOR_VIRTUAL || type_ == DRM_MODE_CONNECTOR_DPI; -} - -bool DrmConnector::external() const { - return type_ == DRM_MODE_CONNECTOR_HDMIA || - type_ == DRM_MODE_CONNECTOR_DisplayPort || - type_ == DRM_MODE_CONNECTOR_DVID || type_ == DRM_MODE_CONNECTOR_DVII || - type_ == DRM_MODE_CONNECTOR_VGA; -} - -bool DrmConnector::writeback() const { -#ifdef DRM_MODE_CONNECTOR_WRITEBACK - return type_ == DRM_MODE_CONNECTOR_WRITEBACK; -#else - return false; -#endif -} - -bool DrmConnector::valid_type() const { - return internal() || external() || writeback(); -} - -std::string DrmConnector::name() const { - constexpr std::array names = - {"None", "VGA", "DVI-I", "DVI-D", "DVI-A", "Composite", - "SVIDEO", "LVDS", "Component", "DIN", "DP", "HDMI-A", - "HDMI-B", "TV", "eDP", "Virtual", "DSI"}; - - if (type_ < TYPES_COUNT) { - std::ostringstream name_buf; - name_buf << names[type_] << "-" << type_id_; - return name_buf.str(); - } else { - ALOGE("Unknown type in connector %d, could not make his name", id_); - return "None"; - } -} - -int DrmConnector::UpdateModes() { - int fd = drm_->fd(); - - drmModeConnectorPtr c = drmModeGetConnector(fd, id_); - if (!c) { - ALOGE("Failed to get connector %d", id_); - return -ENODEV; - } - - state_ = c->connection; - - bool preferred_mode_found = false; - std::vector new_modes; - for (int i = 0; i < c->count_modes; ++i) { - bool exists = false; - for (const DrmMode &mode : modes_) { - if (mode == c->modes[i]) { - new_modes.push_back(mode); - exists = true; - break; - } - } - if (!exists) { - DrmMode m(&c->modes[i]); - m.set_id(drm_->next_mode_id()); - new_modes.push_back(m); - } - // Use only the first DRM_MODE_TYPE_PREFERRED mode found - if (!preferred_mode_found && - (new_modes.back().type() & DRM_MODE_TYPE_PREFERRED)) { - preferred_mode_id_ = new_modes.back().id(); - preferred_mode_found = true; - } - } - modes_.swap(new_modes); - if (!preferred_mode_found && modes_.size() != 0) { - preferred_mode_id_ = modes_[0].id(); - } - return 0; -} - -const DrmMode &DrmConnector::active_mode() const { - return active_mode_; -} - -void DrmConnector::set_active_mode(const DrmMode &mode) { - active_mode_ = mode; -} - -const DrmProperty &DrmConnector::dpms_property() const { - return dpms_property_; -} - -const DrmProperty &DrmConnector::crtc_id_property() const { - return crtc_id_property_; -} - -const DrmProperty &DrmConnector::edid_property() const { - return edid_property_; -} - -const DrmProperty &DrmConnector::writeback_pixel_formats() const { - return writeback_pixel_formats_; -} - -const DrmProperty &DrmConnector::writeback_fb_id() const { - return writeback_fb_id_; -} - -const DrmProperty &DrmConnector::writeback_out_fence() const { - return writeback_out_fence_; -} - -DrmEncoder *DrmConnector::encoder() const { - return encoder_; -} - -void DrmConnector::set_encoder(DrmEncoder *encoder) { - encoder_ = encoder; -} - -drmModeConnection DrmConnector::state() const { - return state_; -} - -uint32_t DrmConnector::mm_width() const { - return mm_width_; -} - -uint32_t DrmConnector::mm_height() const { - return mm_height_; -} -} // namespace android diff --git a/drm/drmconnector.h b/drm/drmconnector.h deleted file mode 100644 index 0c19c55..0000000 --- a/drm/drmconnector.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_CONNECTOR_H_ -#define ANDROID_DRM_CONNECTOR_H_ - -#include -#include - -#include -#include - -#include "drmencoder.h" -#include "drmmode.h" -#include "drmproperty.h" - -namespace android { - -class DrmDevice; - -class DrmConnector { - public: - DrmConnector(DrmDevice *drm, drmModeConnectorPtr c, - DrmEncoder *current_encoder, - std::vector &possible_encoders); - DrmConnector(const DrmProperty &) = delete; - DrmConnector &operator=(const DrmProperty &) = delete; - - int Init(); - - uint32_t id() const; - - int display() const; - void set_display(int display); - - bool internal() const; - bool external() const; - bool writeback() const; - bool valid_type() const; - - std::string name() const; - - int UpdateModes(); - - const std::vector &modes() const { - return modes_; - } - const DrmMode &active_mode() const; - void set_active_mode(const DrmMode &mode); - - const DrmProperty &dpms_property() const; - const DrmProperty &crtc_id_property() const; - const DrmProperty &edid_property() const; - const DrmProperty &writeback_pixel_formats() const; - const DrmProperty &writeback_fb_id() const; - const DrmProperty &writeback_out_fence() const; - - const std::vector &possible_encoders() const { - return possible_encoders_; - } - DrmEncoder *encoder() const; - void set_encoder(DrmEncoder *encoder); - - drmModeConnection state() const; - - uint32_t mm_width() const; - uint32_t mm_height() const; - - uint32_t get_preferred_mode_id() const { - return preferred_mode_id_; - } - - private: - DrmDevice *drm_; - - uint32_t id_; - DrmEncoder *encoder_; - int display_; - - uint32_t type_; - uint32_t type_id_; - drmModeConnection state_; - - uint32_t mm_width_; - uint32_t mm_height_; - - DrmMode active_mode_; - std::vector modes_; - - DrmProperty dpms_property_; - DrmProperty crtc_id_property_; - DrmProperty edid_property_; - DrmProperty writeback_pixel_formats_; - DrmProperty writeback_fb_id_; - DrmProperty writeback_out_fence_; - - std::vector possible_encoders_; - - uint32_t preferred_mode_id_; -}; -} // namespace android - -#endif // ANDROID_DRM_PLANE_H_ diff --git a/drm/drmcrtc.cpp b/drm/drmcrtc.cpp deleted file mode 100644 index b627291..0000000 --- a/drm/drmcrtc.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "hwc-drm-crtc" - -#include "drmcrtc.h" -#include "drmdevice.h" - -#include -#include - -#include - -namespace android { - -DrmCrtc::DrmCrtc(DrmDevice *drm, drmModeCrtcPtr c, unsigned pipe) - : drm_(drm), id_(c->crtc_id), pipe_(pipe), display_(-1), mode_(&c->mode) { -} - -int DrmCrtc::Init() { - int ret = drm_->GetCrtcProperty(*this, "ACTIVE", &active_property_); - if (ret) { - ALOGE("Failed to get ACTIVE property"); - return ret; - } - - ret = drm_->GetCrtcProperty(*this, "MODE_ID", &mode_property_); - if (ret) { - ALOGE("Failed to get MODE_ID property"); - return ret; - } - - ret = drm_->GetCrtcProperty(*this, "OUT_FENCE_PTR", &out_fence_ptr_property_); - if (ret) { - ALOGE("Failed to get OUT_FENCE_PTR property"); - return ret; - } - return 0; -} - -uint32_t DrmCrtc::id() const { - return id_; -} - -unsigned DrmCrtc::pipe() const { - return pipe_; -} - -int DrmCrtc::display() const { - return display_; -} - -void DrmCrtc::set_display(int display) { - display_ = display; -} - -bool DrmCrtc::can_bind(int display) const { - return display_ == -1 || display_ == display; -} - -const DrmProperty &DrmCrtc::active_property() const { - return active_property_; -} - -const DrmProperty &DrmCrtc::mode_property() const { - return mode_property_; -} - -const DrmProperty &DrmCrtc::out_fence_ptr_property() const { - return out_fence_ptr_property_; -} -} // namespace android diff --git a/drm/drmcrtc.h b/drm/drmcrtc.h deleted file mode 100644 index 132c2d3..0000000 --- a/drm/drmcrtc.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_CRTC_H_ -#define ANDROID_DRM_CRTC_H_ - -#include -#include - -#include "drmmode.h" -#include "drmproperty.h" - -namespace android { - -class DrmDevice; - -class DrmCrtc { - public: - DrmCrtc(DrmDevice *drm, drmModeCrtcPtr c, unsigned pipe); - DrmCrtc(const DrmCrtc &) = delete; - DrmCrtc &operator=(const DrmCrtc &) = delete; - - int Init(); - - uint32_t id() const; - unsigned pipe() const; - - int display() const; - void set_display(int display); - - bool can_bind(int display) const; - - const DrmProperty &active_property() const; - const DrmProperty &mode_property() const; - const DrmProperty &out_fence_ptr_property() const; - - private: - DrmDevice *drm_; - - uint32_t id_; - unsigned pipe_; - int display_; - - DrmMode mode_; - - DrmProperty active_property_; - DrmProperty mode_property_; - DrmProperty out_fence_ptr_property_; -}; -} // namespace android - -#endif // ANDROID_DRM_CRTC_H_ diff --git a/drm/drmdevice.cpp b/drm/drmdevice.cpp deleted file mode 100644 index 18b5b62..0000000 --- a/drm/drmdevice.cpp +++ /dev/null @@ -1,580 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "hwc-drm-device" - -#include "drmdevice.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -static void trim_left(std::string &str) { - str.erase(std::begin(str), - std::find_if(std::begin(str), std::end(str), - [](int ch) { return !std::isspace(ch); })); -} - -static void trim_right(std::string &str) { - str.erase(std::find_if(std::rbegin(str), std::rend(str), - [](int ch) { return !std::isspace(ch); }) - .base(), - std::end(str)); -} - -static void trim(std::string &str) { - trim_left(str); - trim_right(str); -} - -namespace android { - -static std::vector read_primary_display_order_prop() { - std::array display_order_buf; - property_get("vendor.hwc.drm.primary_display_order", display_order_buf.data(), - "..."); - - std::vector display_order; - std::istringstream str(display_order_buf.data()); - for (std::string conn_name = ""; std::getline(str, conn_name, ',');) { - trim(conn_name); - display_order.push_back(std::move(conn_name)); - } - return display_order; -} - -static std::vector make_primary_display_candidates( - std::vector> &connectors) { - std::vector primary_candidates; - std::transform(std::begin(connectors), std::end(connectors), - std::back_inserter(primary_candidates), - [](std::unique_ptr &conn) { - return conn.get(); - }); - primary_candidates.erase(std::remove_if(std::begin(primary_candidates), - std::end(primary_candidates), - [](const DrmConnector *conn) { - return conn->state() != - DRM_MODE_CONNECTED; - }), - std::end(primary_candidates)); - - std::vector display_order = read_primary_display_order_prop(); - bool use_other = display_order.back() == "..."; - - // putting connectors from primary_display_order first - auto curr_connector = std::begin(primary_candidates); - for (const std::string &display_name : display_order) { - auto it = std::find_if(std::begin(primary_candidates), - std::end(primary_candidates), - [&display_name](const DrmConnector *conn) { - return conn->name() == display_name; - }); - if (it != std::end(primary_candidates)) { - std::iter_swap(it, curr_connector); - ++curr_connector; - } - } - - if (use_other) { - // then putting internal connectors second, everything else afterwards - std::partition(curr_connector, std::end(primary_candidates), - [](const DrmConnector *conn) { return conn->internal(); }); - } else { - primary_candidates.erase(curr_connector, std::end(primary_candidates)); - } - - return primary_candidates; -} - -DrmDevice::DrmDevice() : event_listener_(this) { -} - -DrmDevice::~DrmDevice() { - event_listener_.Exit(); -} - -std::tuple DrmDevice::Init(const char *path, int num_displays) { - /* TODO: Use drmOpenControl here instead */ - fd_.Set(open(path, O_RDWR)); - if (fd() < 0) { - ALOGE("Failed to open dri %s: %s", path, strerror(errno)); - return std::make_tuple(-ENODEV, 0); - } - - int ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); - if (ret) { - ALOGE("Failed to set universal plane cap %d", ret); - return std::make_tuple(ret, 0); - } - - ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_ATOMIC, 1); - if (ret) { - ALOGE("Failed to set atomic cap %d", ret); - return std::make_tuple(ret, 0); - } - -#ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS - ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1); - if (ret) { - ALOGI("Failed to set writeback cap %d", ret); - ret = 0; - } -#endif - - drmModeResPtr res = drmModeGetResources(fd()); - if (!res) { - ALOGE("Failed to get DrmDevice resources"); - return std::make_tuple(-ENODEV, 0); - } - - min_resolution_ = std::pair(res->min_width, - res->min_height); - max_resolution_ = std::pair(res->max_width, - res->max_height); - - // Assumes that the primary display will always be in the first - // drm_device opened. - bool found_primary = num_displays != 0; - - for (int i = 0; !ret && i < res->count_crtcs; ++i) { - drmModeCrtcPtr c = drmModeGetCrtc(fd(), res->crtcs[i]); - if (!c) { - ALOGE("Failed to get crtc %d", res->crtcs[i]); - ret = -ENODEV; - break; - } - - std::unique_ptr crtc(new DrmCrtc(this, c, i)); - drmModeFreeCrtc(c); - - ret = crtc->Init(); - if (ret) { - ALOGE("Failed to initialize crtc %d", res->crtcs[i]); - break; - } - crtcs_.emplace_back(std::move(crtc)); - } - - std::vector possible_clones; - for (int i = 0; !ret && i < res->count_encoders; ++i) { - drmModeEncoderPtr e = drmModeGetEncoder(fd(), res->encoders[i]); - if (!e) { - ALOGE("Failed to get encoder %d", res->encoders[i]); - ret = -ENODEV; - break; - } - - std::vector possible_crtcs; - DrmCrtc *current_crtc = NULL; - for (auto &crtc : crtcs_) { - if ((1 << crtc->pipe()) & e->possible_crtcs) - possible_crtcs.push_back(crtc.get()); - - if (crtc->id() == e->crtc_id) - current_crtc = crtc.get(); - } - - std::unique_ptr enc( - new DrmEncoder(e, current_crtc, possible_crtcs)); - possible_clones.push_back(e->possible_clones); - drmModeFreeEncoder(e); - - encoders_.emplace_back(std::move(enc)); - } - - for (unsigned int i = 0; i < encoders_.size(); i++) { - for (unsigned int j = 0; j < encoders_.size(); j++) - if (possible_clones[i] & (1 << j)) - encoders_[i]->AddPossibleClone(encoders_[j].get()); - } - - for (int i = 0; !ret && i < res->count_connectors; ++i) { - drmModeConnectorPtr c = drmModeGetConnector(fd(), res->connectors[i]); - if (!c) { - ALOGE("Failed to get connector %d", res->connectors[i]); - ret = -ENODEV; - break; - } - - std::vector possible_encoders; - DrmEncoder *current_encoder = NULL; - for (int j = 0; j < c->count_encoders; ++j) { - for (auto &encoder : encoders_) { - if (encoder->id() == c->encoders[j]) - possible_encoders.push_back(encoder.get()); - if (encoder->id() == c->encoder_id) - current_encoder = encoder.get(); - } - } - - std::unique_ptr conn( - new DrmConnector(this, c, current_encoder, possible_encoders)); - - drmModeFreeConnector(c); - - ret = conn->Init(); - if (ret) { - ALOGE("Init connector %d failed", res->connectors[i]); - break; - } - - if (conn->writeback()) - writeback_connectors_.emplace_back(std::move(conn)); - else - connectors_.emplace_back(std::move(conn)); - } - - // Primary display priority: - // 1) vendor.hwc.drm.primary_display_order property - // 2) internal connectors - // 3) anything else - std::vector - primary_candidates = make_primary_display_candidates(connectors_); - if (!primary_candidates.empty() && !found_primary) { - DrmConnector &conn = **std::begin(primary_candidates); - conn.set_display(num_displays); - displays_[num_displays] = num_displays; - ++num_displays; - found_primary = true; - } else { - ALOGE( - "Failed to find primary display from " - "\"vendor.hwc.drm.primary_display_order\" property"); - } - - // If no priority display were found then pick first available as primary and - // for the others assign consecutive display_numbers. - for (auto &conn : connectors_) { - if (conn->external() || conn->internal()) { - if (!found_primary) { - conn->set_display(num_displays); - displays_[num_displays] = num_displays; - found_primary = true; - ++num_displays; - } else if (conn->display() < 0) { - conn->set_display(num_displays); - displays_[num_displays] = num_displays; - ++num_displays; - } - } - } - - if (res) - drmModeFreeResources(res); - - // Catch-all for the above loops - if (ret) - return std::make_tuple(ret, 0); - - drmModePlaneResPtr plane_res = drmModeGetPlaneResources(fd()); - if (!plane_res) { - ALOGE("Failed to get plane resources"); - return std::make_tuple(-ENOENT, 0); - } - - for (uint32_t i = 0; i < plane_res->count_planes; ++i) { - drmModePlanePtr p = drmModeGetPlane(fd(), plane_res->planes[i]); - if (!p) { - ALOGE("Failed to get plane %d", plane_res->planes[i]); - ret = -ENODEV; - break; - } - - std::unique_ptr plane(new DrmPlane(this, p)); - - drmModeFreePlane(p); - - ret = plane->Init(); - if (ret) { - ALOGE("Init plane %d failed", plane_res->planes[i]); - break; - } - - planes_.emplace_back(std::move(plane)); - } - drmModeFreePlaneResources(plane_res); - if (ret) - return std::make_tuple(ret, 0); - - ret = event_listener_.Init(); - if (ret) { - ALOGE("Can't initialize event listener %d", ret); - return std::make_tuple(ret, 0); - } - - for (auto &conn : connectors_) { - ret = CreateDisplayPipe(conn.get()); - if (ret) { - ALOGE("Failed CreateDisplayPipe %d with %d", conn->id(), ret); - return std::make_tuple(ret, 0); - } - if (!AttachWriteback(conn.get())) { - ALOGI("Display %d has writeback attach to it", conn->display()); - } - } - return std::make_tuple(ret, displays_.size()); -} - -bool DrmDevice::HandlesDisplay(int display) const { - return displays_.find(display) != displays_.end(); -} - -DrmConnector *DrmDevice::GetConnectorForDisplay(int display) const { - for (auto &conn : connectors_) { - if (conn->display() == display) - return conn.get(); - } - return NULL; -} - -DrmConnector *DrmDevice::GetWritebackConnectorForDisplay(int display) const { - for (auto &conn : writeback_connectors_) { - if (conn->display() == display) - return conn.get(); - } - return NULL; -} - -// TODO what happens when hotplugging -DrmConnector *DrmDevice::AvailableWritebackConnector(int display) const { - DrmConnector *writeback_conn = GetWritebackConnectorForDisplay(display); - DrmConnector *display_conn = GetConnectorForDisplay(display); - // If we have a writeback already attached to the same CRTC just use that, - // if possible. - if (display_conn && writeback_conn && - writeback_conn->encoder()->CanClone(display_conn->encoder())) - return writeback_conn; - - // Use another CRTC if available and doesn't have any connector - for (auto &crtc : crtcs_) { - if (crtc->display() == display) - continue; - display_conn = GetConnectorForDisplay(crtc->display()); - // If we have a display connected don't use it for writeback - if (display_conn && display_conn->state() == DRM_MODE_CONNECTED) - continue; - writeback_conn = GetWritebackConnectorForDisplay(crtc->display()); - if (writeback_conn) - return writeback_conn; - } - return NULL; -} - -DrmCrtc *DrmDevice::GetCrtcForDisplay(int display) const { - for (auto &crtc : crtcs_) { - if (crtc->display() == display) - return crtc.get(); - } - return NULL; -} - -DrmPlane *DrmDevice::GetPlane(uint32_t id) const { - for (auto &plane : planes_) { - if (plane->id() == id) - return plane.get(); - } - return NULL; -} - -const std::vector> &DrmDevice::crtcs() const { - return crtcs_; -} - -uint32_t DrmDevice::next_mode_id() { - return ++mode_id_; -} - -int DrmDevice::TryEncoderForDisplay(int display, DrmEncoder *enc) { - /* First try to use the currently-bound crtc */ - DrmCrtc *crtc = enc->crtc(); - if (crtc && crtc->can_bind(display)) { - crtc->set_display(display); - enc->set_crtc(crtc); - return 0; - } - - /* Try to find a possible crtc which will work */ - for (DrmCrtc *crtc : enc->possible_crtcs()) { - /* We've already tried this earlier */ - if (crtc == enc->crtc()) - continue; - - if (crtc->can_bind(display)) { - crtc->set_display(display); - enc->set_crtc(crtc); - return 0; - } - } - - /* We can't use the encoder, but nothing went wrong, try another one */ - return -EAGAIN; -} - -int DrmDevice::CreateDisplayPipe(DrmConnector *connector) { - int display = connector->display(); - /* Try to use current setup first */ - if (connector->encoder()) { - int ret = TryEncoderForDisplay(display, connector->encoder()); - if (!ret) { - return 0; - } else if (ret != -EAGAIN) { - ALOGE("Could not set mode %d/%d", display, ret); - return ret; - } - } - - for (DrmEncoder *enc : connector->possible_encoders()) { - int ret = TryEncoderForDisplay(display, enc); - if (!ret) { - connector->set_encoder(enc); - return 0; - } else if (ret != -EAGAIN) { - ALOGE("Could not set mode %d/%d", display, ret); - return ret; - } - } - ALOGE("Could not find a suitable encoder/crtc for display %d", - connector->display()); - return -ENODEV; -} - -// Attach writeback connector to the CRTC linked to the display_conn -int DrmDevice::AttachWriteback(DrmConnector *display_conn) { - DrmCrtc *display_crtc = display_conn->encoder()->crtc(); - if (GetWritebackConnectorForDisplay(display_crtc->display()) != NULL) { - ALOGE("Display already has writeback attach to it"); - return -EINVAL; - } - for (auto &writeback_conn : writeback_connectors_) { - if (writeback_conn->display() >= 0) - continue; - for (DrmEncoder *writeback_enc : writeback_conn->possible_encoders()) { - for (DrmCrtc *possible_crtc : writeback_enc->possible_crtcs()) { - if (possible_crtc != display_crtc) - continue; - // Use just encoders which had not been bound already - if (writeback_enc->can_bind(display_crtc->display())) { - writeback_enc->set_crtc(display_crtc); - writeback_conn->set_encoder(writeback_enc); - writeback_conn->set_display(display_crtc->display()); - writeback_conn->UpdateModes(); - return 0; - } - } - } - } - return -EINVAL; -} - -int DrmDevice::CreatePropertyBlob(void *data, size_t length, - uint32_t *blob_id) { - struct drm_mode_create_blob create_blob; - memset(&create_blob, 0, sizeof(create_blob)); - create_blob.length = length; - create_blob.data = (__u64)data; - - int ret = drmIoctl(fd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob); - if (ret) { - ALOGE("Failed to create mode property blob %d", ret); - return ret; - } - *blob_id = create_blob.blob_id; - return 0; -} - -int DrmDevice::DestroyPropertyBlob(uint32_t blob_id) { - if (!blob_id) - return 0; - - struct drm_mode_destroy_blob destroy_blob; - memset(&destroy_blob, 0, sizeof(destroy_blob)); - destroy_blob.blob_id = (__u32)blob_id; - int ret = drmIoctl(fd(), DRM_IOCTL_MODE_DESTROYPROPBLOB, &destroy_blob); - if (ret) { - ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", blob_id, ret); - return ret; - } - return 0; -} - -DrmEventListener *DrmDevice::event_listener() { - return &event_listener_; -} - -int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type, - const char *prop_name, DrmProperty *property) { - drmModeObjectPropertiesPtr props; - - props = drmModeObjectGetProperties(fd(), obj_id, obj_type); - if (!props) { - ALOGE("Failed to get properties for %d/%x", obj_id, obj_type); - return -ENODEV; - } - - bool found = false; - for (int i = 0; !found && (size_t)i < props->count_props; ++i) { - drmModePropertyPtr p = drmModeGetProperty(fd(), props->props[i]); - if (!strcmp(p->name, prop_name)) { - property->Init(p, props->prop_values[i]); - found = true; - } - drmModeFreeProperty(p); - } - - drmModeFreeObjectProperties(props); - return found ? 0 : -ENOENT; -} - -int DrmDevice::GetPlaneProperty(const DrmPlane &plane, const char *prop_name, - DrmProperty *property) { - return GetProperty(plane.id(), DRM_MODE_OBJECT_PLANE, prop_name, property); -} - -int DrmDevice::GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name, - DrmProperty *property) { - return GetProperty(crtc.id(), DRM_MODE_OBJECT_CRTC, prop_name, property); -} - -int DrmDevice::GetConnectorProperty(const DrmConnector &connector, - const char *prop_name, - DrmProperty *property) { - return GetProperty(connector.id(), DRM_MODE_OBJECT_CONNECTOR, prop_name, - property); -} - -const std::string DrmDevice::GetName() const { - auto ver = drmGetVersion(fd_.get()); - if (!ver) { - ALOGW("Failed to get drm version for fd=%d", fd_.get()); - return "generic"; - } - - std::string name(ver->name); - drmFreeVersion(ver); - return name; -} -} // namespace android diff --git a/drm/drmdevice.h b/drm/drmdevice.h deleted file mode 100644 index 6a8de47..0000000 --- a/drm/drmdevice.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_H_ -#define ANDROID_DRM_H_ - -#include - -#include - -#include "drmconnector.h" -#include "drmcrtc.h" -#include "drmencoder.h" -#include "drmeventlistener.h" -#include "drmplane.h" -#include "platform/platform.h" - -namespace android { - -class DrmDevice { - public: - DrmDevice(); - ~DrmDevice(); - - std::tuple Init(const char *path, int num_displays); - - int fd() const { - return fd_.get(); - } - - const std::vector> &connectors() const { - return connectors_; - } - - const std::vector> &planes() const { - return planes_; - } - - std::pair min_resolution() const { - return min_resolution_; - } - - std::pair max_resolution() const { - return max_resolution_; - } - - DrmConnector *GetConnectorForDisplay(int display) const; - DrmConnector *GetWritebackConnectorForDisplay(int display) const; - DrmConnector *AvailableWritebackConnector(int display) const; - DrmCrtc *GetCrtcForDisplay(int display) const; - DrmPlane *GetPlane(uint32_t id) const; - DrmEventListener *event_listener(); - - int GetPlaneProperty(const DrmPlane &plane, const char *prop_name, - DrmProperty *property); - int GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name, - DrmProperty *property); - int GetConnectorProperty(const DrmConnector &connector, const char *prop_name, - DrmProperty *property); - - const std::string GetName() const; - - const std::vector> &crtcs() const; - uint32_t next_mode_id(); - - int CreatePropertyBlob(void *data, size_t length, uint32_t *blob_id); - int DestroyPropertyBlob(uint32_t blob_id); - bool HandlesDisplay(int display) const; - void RegisterHotplugHandler(DrmEventHandler *handler) { - event_listener_.RegisterHotplugHandler(handler); - } - - private: - int TryEncoderForDisplay(int display, DrmEncoder *enc); - int GetProperty(uint32_t obj_id, uint32_t obj_type, const char *prop_name, - DrmProperty *property); - - int CreateDisplayPipe(DrmConnector *connector); - int AttachWriteback(DrmConnector *display_conn); - - UniqueFd fd_; - uint32_t mode_id_ = 0; - - std::vector> connectors_; - std::vector> writeback_connectors_; - std::vector> encoders_; - std::vector> crtcs_; - std::vector> planes_; - DrmEventListener event_listener_; - - std::pair min_resolution_; - std::pair max_resolution_; - std::map displays_; -}; -} // namespace android - -#endif // ANDROID_DRM_H_ diff --git a/drm/drmencoder.cpp b/drm/drmencoder.cpp deleted file mode 100644 index 9aa6805..0000000 --- a/drm/drmencoder.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2015 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 "drmencoder.h" -#include "drmdevice.h" - -#include -#include - -namespace android { - -DrmEncoder::DrmEncoder(drmModeEncoderPtr e, DrmCrtc *current_crtc, - const std::vector &possible_crtcs) - : id_(e->encoder_id), - crtc_(current_crtc), - display_(-1), - possible_crtcs_(possible_crtcs) { -} - -uint32_t DrmEncoder::id() const { - return id_; -} - -DrmCrtc *DrmEncoder::crtc() const { - return crtc_; -} - -bool DrmEncoder::CanClone(DrmEncoder *possible_clone) { - return possible_clones_.find(possible_clone) != possible_clones_.end(); -} - -void DrmEncoder::AddPossibleClone(DrmEncoder *possible_clone) { - possible_clones_.insert(possible_clone); -} - -void DrmEncoder::set_crtc(DrmCrtc *crtc) { - crtc_ = crtc; - display_ = crtc->display(); -} - -int DrmEncoder::display() const { - return display_; -} - -bool DrmEncoder::can_bind(int display) const { - return display_ == -1 || display_ == display; -} -} // namespace android diff --git a/drm/drmencoder.h b/drm/drmencoder.h deleted file mode 100644 index 4403d9f..0000000 --- a/drm/drmencoder.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_ENCODER_H_ -#define ANDROID_DRM_ENCODER_H_ - -#include -#include - -#include -#include - -#include "drmcrtc.h" - -namespace android { - -class DrmEncoder { - public: - DrmEncoder(drmModeEncoderPtr e, DrmCrtc *current_crtc, - const std::vector &possible_crtcs); - DrmEncoder(const DrmEncoder &) = delete; - DrmEncoder &operator=(const DrmEncoder &) = delete; - - uint32_t id() const; - - DrmCrtc *crtc() const; - void set_crtc(DrmCrtc *crtc); - bool can_bind(int display) const; - int display() const; - - const std::vector &possible_crtcs() const { - return possible_crtcs_; - } - bool CanClone(DrmEncoder *encoder); - void AddPossibleClone(DrmEncoder *possible_clone); - - private: - uint32_t id_; - DrmCrtc *crtc_; - int display_; - - std::vector possible_crtcs_; - std::set possible_clones_; -}; -} // namespace android - -#endif // ANDROID_DRM_ENCODER_H_ diff --git a/drm/drmeventlistener.cpp b/drm/drmeventlistener.cpp deleted file mode 100644 index ccee0d6..0000000 --- a/drm/drmeventlistener.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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 LOG_TAG "hwc-drm-event-listener" - -#include "drmeventlistener.h" -#include "drmdevice.h" - -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace android { - -DrmEventListener::DrmEventListener(DrmDevice *drm) - : Worker("drm-event-listener", HAL_PRIORITY_URGENT_DISPLAY), drm_(drm) { -} - -int DrmEventListener::Init() { - uevent_fd_.Set(socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT)); - if (uevent_fd_.get() < 0) { - ALOGE("Failed to open uevent socket: %s", strerror(errno)); - return uevent_fd_.get(); - } - - struct sockaddr_nl addr; - memset(&addr, 0, sizeof(addr)); - addr.nl_family = AF_NETLINK; - addr.nl_pid = 0; - addr.nl_groups = 0xFFFFFFFF; - - int ret = bind(uevent_fd_.get(), (struct sockaddr *)&addr, sizeof(addr)); - if (ret) { - ALOGE("Failed to bind uevent socket: %s", strerror(errno)); - return -errno; - } - - FD_ZERO(&fds_); - FD_SET(drm_->fd(), &fds_); - FD_SET(uevent_fd_.get(), &fds_); - max_fd_ = std::max(drm_->fd(), uevent_fd_.get()); - - return InitWorker(); -} - -void DrmEventListener::RegisterHotplugHandler(DrmEventHandler *handler) { - assert(!hotplug_handler_); - hotplug_handler_.reset(handler); -} - -void DrmEventListener::FlipHandler(int /* fd */, unsigned int /* sequence */, - unsigned int tv_sec, unsigned int tv_usec, - void *user_data) { - DrmEventHandler *handler = (DrmEventHandler *)user_data; - if (!handler) - return; - - handler->HandleEvent((uint64_t)tv_sec * 1000 * 1000 + tv_usec); - delete handler; -} - -void DrmEventListener::UEventHandler() { - char buffer[1024]; - int ret; - - struct timespec ts; - uint64_t timestamp = 0; - ret = clock_gettime(CLOCK_MONOTONIC, &ts); - if (!ret) - timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; - else - ALOGE("Failed to get monotonic clock on hotplug %d", ret); - - while (true) { - ret = read(uevent_fd_.get(), &buffer, sizeof(buffer)); - if (ret == 0) { - return; - } else if (ret < 0) { - ALOGE("Got error reading uevent %d", ret); - return; - } - - if (!hotplug_handler_) - continue; - - bool drm_event = false, hotplug_event = false; - for (int i = 0; i < ret;) { - char *event = buffer + i; - if (strcmp(event, "DEVTYPE=drm_minor")) - drm_event = true; - else if (strcmp(event, "HOTPLUG=1")) - hotplug_event = true; - - i += strlen(event) + 1; - } - - if (drm_event && hotplug_event) - hotplug_handler_->HandleEvent(timestamp); - } -} - -void DrmEventListener::Routine() { - int ret; - do { - ret = select(max_fd_ + 1, &fds_, NULL, NULL, NULL); - } while (ret == -1 && errno == EINTR); - - if (FD_ISSET(drm_->fd(), &fds_)) { - drmEventContext event_context = - {.version = 2, - .vblank_handler = NULL, - .page_flip_handler = DrmEventListener::FlipHandler}; - drmHandleEvent(drm_->fd(), &event_context); - } - - if (FD_ISSET(uevent_fd_.get(), &fds_)) - UEventHandler(); -} -} // namespace android diff --git a/drm/drmeventlistener.h b/drm/drmeventlistener.h deleted file mode 100644 index ff3b8e5..0000000 --- a/drm/drmeventlistener.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_DRM_EVENT_LISTENER_H_ -#define ANDROID_DRM_EVENT_LISTENER_H_ - -#include "autofd.h" -#include "utils/worker.h" - -namespace android { - -class DrmDevice; - -class DrmEventHandler { - public: - DrmEventHandler() { - } - virtual ~DrmEventHandler() { - } - - virtual void HandleEvent(uint64_t timestamp_us) = 0; -}; - -class DrmEventListener : public Worker { - public: - DrmEventListener(DrmDevice *drm); - virtual ~DrmEventListener() { - } - - int Init(); - - void RegisterHotplugHandler(DrmEventHandler *handler); - - static void FlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, - unsigned int tv_usec, void *user_data); - - protected: - virtual void Routine(); - - private: - void UEventHandler(); - - fd_set fds_; - UniqueFd uevent_fd_; - int max_fd_ = -1; - - DrmDevice *drm_; - std::unique_ptr hotplug_handler_; -}; -} // namespace android - -#endif diff --git a/drm/drmmode.cpp b/drm/drmmode.cpp deleted file mode 100644 index c1398ef..0000000 --- a/drm/drmmode.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2015 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 "drmmode.h" -#include "drmdevice.h" - -namespace android { - -DrmMode::DrmMode(drmModeModeInfoPtr m) - : id_(0), - clock_(m->clock), - h_display_(m->hdisplay), - h_sync_start_(m->hsync_start), - h_sync_end_(m->hsync_end), - h_total_(m->htotal), - h_skew_(m->hskew), - v_display_(m->vdisplay), - v_sync_start_(m->vsync_start), - v_sync_end_(m->vsync_end), - v_total_(m->vtotal), - v_scan_(m->vscan), - v_refresh_(m->vrefresh), - flags_(m->flags), - type_(m->type), - name_(m->name) { -} - -bool DrmMode::operator==(const drmModeModeInfo &m) const { - return clock_ == m.clock && h_display_ == m.hdisplay && - h_sync_start_ == m.hsync_start && h_sync_end_ == m.hsync_end && - h_total_ == m.htotal && h_skew_ == m.hskew && - v_display_ == m.vdisplay && v_sync_start_ == m.vsync_start && - v_sync_end_ == m.vsync_end && v_total_ == m.vtotal && - v_scan_ == m.vscan && flags_ == m.flags && type_ == m.type; -} - -void DrmMode::ToDrmModeModeInfo(drm_mode_modeinfo *m) const { - m->clock = clock_; - m->hdisplay = h_display_; - m->hsync_start = h_sync_start_; - m->hsync_end = h_sync_end_; - m->htotal = h_total_; - m->hskew = h_skew_; - m->vdisplay = v_display_; - m->vsync_start = v_sync_start_; - m->vsync_end = v_sync_end_; - m->vtotal = v_total_; - m->vscan = v_scan_; - m->vrefresh = v_refresh_; - m->flags = flags_; - m->type = type_; - strncpy(m->name, name_.c_str(), DRM_DISPLAY_MODE_LEN); -} - -uint32_t DrmMode::id() const { - return id_; -} - -void DrmMode::set_id(uint32_t id) { - id_ = id; -} - -uint32_t DrmMode::clock() const { - return clock_; -} - -uint32_t DrmMode::h_display() const { - return h_display_; -} - -uint32_t DrmMode::h_sync_start() const { - return h_sync_start_; -} - -uint32_t DrmMode::h_sync_end() const { - return h_sync_end_; -} - -uint32_t DrmMode::h_total() const { - return h_total_; -} - -uint32_t DrmMode::h_skew() const { - return h_skew_; -} - -uint32_t DrmMode::v_display() const { - return v_display_; -} - -uint32_t DrmMode::v_sync_start() const { - return v_sync_start_; -} - -uint32_t DrmMode::v_sync_end() const { - return v_sync_end_; -} - -uint32_t DrmMode::v_total() const { - return v_total_; -} - -uint32_t DrmMode::v_scan() const { - return v_scan_; -} - -float DrmMode::v_refresh() const { - // Always recalculate refresh to report correct float rate - return clock_ / (float)(v_total_ * h_total_) * 1000.0f; -} - -uint32_t DrmMode::flags() const { - return flags_; -} - -uint32_t DrmMode::type() const { - return type_; -} - -std::string DrmMode::name() const { - return name_; -} -} // namespace android diff --git a/drm/drmmode.h b/drm/drmmode.h deleted file mode 100644 index 313a8ea..0000000 --- a/drm/drmmode.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_MODE_H_ -#define ANDROID_DRM_MODE_H_ - -#include -#include - -#include - -namespace android { - -class DrmMode { - public: - DrmMode() = default; - DrmMode(drmModeModeInfoPtr m); - - bool operator==(const drmModeModeInfo &m) const; - void ToDrmModeModeInfo(drm_mode_modeinfo *m) const; - - uint32_t id() const; - void set_id(uint32_t id); - - uint32_t clock() const; - - uint32_t h_display() const; - uint32_t h_sync_start() const; - uint32_t h_sync_end() const; - uint32_t h_total() const; - uint32_t h_skew() const; - - uint32_t v_display() const; - uint32_t v_sync_start() const; - uint32_t v_sync_end() const; - uint32_t v_total() const; - uint32_t v_scan() const; - float v_refresh() const; - - uint32_t flags() const; - uint32_t type() const; - - std::string name() const; - - private: - uint32_t id_ = 0; - - uint32_t clock_ = 0; - - uint32_t h_display_ = 0; - uint32_t h_sync_start_ = 0; - uint32_t h_sync_end_ = 0; - uint32_t h_total_ = 0; - uint32_t h_skew_ = 0; - - uint32_t v_display_ = 0; - uint32_t v_sync_start_ = 0; - uint32_t v_sync_end_ = 0; - uint32_t v_total_ = 0; - uint32_t v_scan_ = 0; - uint32_t v_refresh_ = 0; - - uint32_t flags_ = 0; - uint32_t type_ = 0; - - std::string name_; -}; -} // namespace android - -#endif // ANDROID_DRM_MODE_H_ diff --git a/drm/drmplane.cpp b/drm/drmplane.cpp deleted file mode 100644 index f0c7559..0000000 --- a/drm/drmplane.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "hwc-drm-plane" - -#include "drmplane.h" -#include "drmdevice.h" - -#include -#include -#include - -#include - -namespace android { - -DrmPlane::DrmPlane(DrmDevice *drm, drmModePlanePtr p) - : drm_(drm), id_(p->plane_id), possible_crtc_mask_(p->possible_crtcs) { -} - -int DrmPlane::Init() { - DrmProperty p; - - int ret = drm_->GetPlaneProperty(*this, "type", &p); - if (ret) { - ALOGE("Could not get plane type property"); - return ret; - } - - uint64_t type; - std::tie(ret, type) = p.value(); - if (ret) { - ALOGE("Failed to get plane type property value"); - return ret; - } - switch (type) { - case DRM_PLANE_TYPE_OVERLAY: - case DRM_PLANE_TYPE_PRIMARY: - case DRM_PLANE_TYPE_CURSOR: - type_ = (uint32_t)type; - break; - default: - ALOGE("Invalid plane type %" PRIu64, type); - return -EINVAL; - } - - ret = drm_->GetPlaneProperty(*this, "CRTC_ID", &crtc_property_); - if (ret) { - ALOGE("Could not get CRTC_ID property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "FB_ID", &fb_property_); - if (ret) { - ALOGE("Could not get FB_ID property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "CRTC_X", &crtc_x_property_); - if (ret) { - ALOGE("Could not get CRTC_X property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "CRTC_Y", &crtc_y_property_); - if (ret) { - ALOGE("Could not get CRTC_Y property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "CRTC_W", &crtc_w_property_); - if (ret) { - ALOGE("Could not get CRTC_W property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "CRTC_H", &crtc_h_property_); - if (ret) { - ALOGE("Could not get CRTC_H property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "SRC_X", &src_x_property_); - if (ret) { - ALOGE("Could not get SRC_X property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "SRC_Y", &src_y_property_); - if (ret) { - ALOGE("Could not get SRC_Y property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "SRC_W", &src_w_property_); - if (ret) { - ALOGE("Could not get SRC_W property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "SRC_H", &src_h_property_); - if (ret) { - ALOGE("Could not get SRC_H property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "zpos", &zpos_property_); - if (ret) - ALOGE("Could not get zpos property for plane %u", id()); - - ret = drm_->GetPlaneProperty(*this, "rotation", &rotation_property_); - if (ret) - ALOGE("Could not get rotation property"); - - ret = drm_->GetPlaneProperty(*this, "alpha", &alpha_property_); - if (ret) - ALOGI("Could not get alpha property"); - - ret = drm_->GetPlaneProperty(*this, "pixel blend mode", &blend_property_); - if (ret) - ALOGI("Could not get pixel blend mode property"); - - ret = drm_->GetPlaneProperty(*this, "IN_FENCE_FD", &in_fence_fd_property_); - if (ret) - ALOGI("Could not get IN_FENCE_FD property"); - - return 0; -} - -uint32_t DrmPlane::id() const { - return id_; -} - -bool DrmPlane::GetCrtcSupported(const DrmCrtc &crtc) const { - return !!((1 << crtc.pipe()) & possible_crtc_mask_); -} - -uint32_t DrmPlane::type() const { - return type_; -} - -const DrmProperty &DrmPlane::crtc_property() const { - return crtc_property_; -} - -const DrmProperty &DrmPlane::fb_property() const { - return fb_property_; -} - -const DrmProperty &DrmPlane::crtc_x_property() const { - return crtc_x_property_; -} - -const DrmProperty &DrmPlane::crtc_y_property() const { - return crtc_y_property_; -} - -const DrmProperty &DrmPlane::crtc_w_property() const { - return crtc_w_property_; -} - -const DrmProperty &DrmPlane::crtc_h_property() const { - return crtc_h_property_; -} - -const DrmProperty &DrmPlane::src_x_property() const { - return src_x_property_; -} - -const DrmProperty &DrmPlane::src_y_property() const { - return src_y_property_; -} - -const DrmProperty &DrmPlane::src_w_property() const { - return src_w_property_; -} - -const DrmProperty &DrmPlane::src_h_property() const { - return src_h_property_; -} - -const DrmProperty &DrmPlane::zpos_property() const { - return zpos_property_; -} - -const DrmProperty &DrmPlane::rotation_property() const { - return rotation_property_; -} - -const DrmProperty &DrmPlane::alpha_property() const { - return alpha_property_; -} - -const DrmProperty &DrmPlane::blend_property() const { - return blend_property_; -} - -const DrmProperty &DrmPlane::in_fence_fd_property() const { - return in_fence_fd_property_; -} -} // namespace android diff --git a/drm/drmplane.h b/drm/drmplane.h deleted file mode 100644 index 1a4dc91..0000000 --- a/drm/drmplane.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_PLANE_H_ -#define ANDROID_DRM_PLANE_H_ - -#include -#include - -#include - -#include "drmcrtc.h" -#include "drmproperty.h" - -namespace android { - -class DrmDevice; - -class DrmPlane { - public: - DrmPlane(DrmDevice *drm, drmModePlanePtr p); - DrmPlane(const DrmPlane &) = delete; - DrmPlane &operator=(const DrmPlane &) = delete; - - int Init(); - - uint32_t id() const; - - bool GetCrtcSupported(const DrmCrtc &crtc) const; - - uint32_t type() const; - - const DrmProperty &crtc_property() const; - const DrmProperty &fb_property() const; - const DrmProperty &crtc_x_property() const; - const DrmProperty &crtc_y_property() const; - const DrmProperty &crtc_w_property() const; - const DrmProperty &crtc_h_property() const; - const DrmProperty &src_x_property() const; - const DrmProperty &src_y_property() const; - const DrmProperty &src_w_property() const; - const DrmProperty &src_h_property() const; - const DrmProperty &zpos_property() const; - const DrmProperty &rotation_property() const; - const DrmProperty &alpha_property() const; - const DrmProperty &blend_property() const; - const DrmProperty &in_fence_fd_property() const; - - private: - DrmDevice *drm_; - uint32_t id_; - - uint32_t possible_crtc_mask_; - - uint32_t type_; - - DrmProperty crtc_property_; - DrmProperty fb_property_; - DrmProperty crtc_x_property_; - DrmProperty crtc_y_property_; - DrmProperty crtc_w_property_; - DrmProperty crtc_h_property_; - DrmProperty src_x_property_; - DrmProperty src_y_property_; - DrmProperty src_w_property_; - DrmProperty src_h_property_; - DrmProperty zpos_property_; - DrmProperty rotation_property_; - DrmProperty alpha_property_; - DrmProperty blend_property_; - DrmProperty in_fence_fd_property_; -}; -} // namespace android - -#endif // ANDROID_DRM_PLANE_H_ diff --git a/drm/drmproperty.cpp b/drm/drmproperty.cpp deleted file mode 100644 index 3aeed13..0000000 --- a/drm/drmproperty.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2015 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 "drmproperty.h" -#include "drmdevice.h" - -#include -#include -#include - -#include - -namespace android { - -DrmProperty::DrmPropertyEnum::DrmPropertyEnum(drm_mode_property_enum *e) - : value_(e->value), name_(e->name) { -} - -DrmProperty::DrmPropertyEnum::~DrmPropertyEnum() { -} - -DrmProperty::DrmProperty(drmModePropertyPtr p, uint64_t value) - : id_(0), type_(DRM_PROPERTY_TYPE_INVALID), flags_(0), name_("") { - Init(p, value); -} - -void DrmProperty::Init(drmModePropertyPtr p, uint64_t value) { - id_ = p->prop_id; - flags_ = p->flags; - name_ = p->name; - value_ = value; - - for (int i = 0; i < p->count_values; ++i) - values_.push_back(p->values[i]); - - for (int i = 0; i < p->count_enums; ++i) - enums_.push_back(DrmPropertyEnum(&p->enums[i])); - - for (int i = 0; i < p->count_blobs; ++i) - blob_ids_.push_back(p->blob_ids[i]); - - if (flags_ & DRM_MODE_PROP_RANGE) - type_ = DRM_PROPERTY_TYPE_INT; - else if (flags_ & DRM_MODE_PROP_ENUM) - type_ = DRM_PROPERTY_TYPE_ENUM; - else if (flags_ & DRM_MODE_PROP_OBJECT) - type_ = DRM_PROPERTY_TYPE_OBJECT; - else if (flags_ & DRM_MODE_PROP_BLOB) - type_ = DRM_PROPERTY_TYPE_BLOB; -} - -uint32_t DrmProperty::id() const { - return id_; -} - -std::string DrmProperty::name() const { - return name_; -} - -std::tuple DrmProperty::value() const { - if (type_ == DRM_PROPERTY_TYPE_BLOB) - return std::make_tuple(0, value_); - - if (values_.size() == 0) - return std::make_tuple(-ENOENT, 0); - - switch (type_) { - case DRM_PROPERTY_TYPE_INT: - return std::make_tuple(0, value_); - - case DRM_PROPERTY_TYPE_ENUM: - if (value_ >= enums_.size()) - return std::make_tuple(-ENOENT, 0); - - return std::make_tuple(0, enums_[value_].value_); - - case DRM_PROPERTY_TYPE_OBJECT: - return std::make_tuple(0, value_); - - default: - return std::make_tuple(-EINVAL, 0); - } -} - -bool DrmProperty::is_immutable() const { - return id_ && (flags_ & DRM_MODE_PROP_IMMUTABLE); -} - -bool DrmProperty::is_range() const { - return id_ && (flags_ & DRM_MODE_PROP_RANGE); -} - -std::tuple DrmProperty::range_min() const { - if (!is_range()) - return std::make_tuple(-EINVAL, 0); - if (values_.size() < 1) - return std::make_tuple(-ENOENT, 0); - - return std::make_tuple(0, values_[0]); -} - -std::tuple DrmProperty::range_max() const { - if (!is_range()) - return std::make_tuple(-EINVAL, 0); - if (values_.size() < 2) - return std::make_tuple(-ENOENT, 0); - - return std::make_tuple(0, values_[1]); -} - -std::tuple DrmProperty::GetEnumValueWithName( - std::string name) const { - for (auto it : enums_) { - if (it.name_.compare(name) == 0) { - return std::make_tuple(it.value_, 0); - } - } - - return std::make_tuple(UINT64_MAX, -EINVAL); -} -} // namespace android diff --git a/drm/drmproperty.h b/drm/drmproperty.h deleted file mode 100644 index d293da3..0000000 --- a/drm/drmproperty.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_PROPERTY_H_ -#define ANDROID_DRM_PROPERTY_H_ - -#include -#include - -#include -#include - -namespace android { - -enum DrmPropertyType { - DRM_PROPERTY_TYPE_INT, - DRM_PROPERTY_TYPE_ENUM, - DRM_PROPERTY_TYPE_OBJECT, - DRM_PROPERTY_TYPE_BLOB, - DRM_PROPERTY_TYPE_INVALID, -}; - -class DrmProperty { - public: - DrmProperty() = default; - DrmProperty(drmModePropertyPtr p, uint64_t value); - DrmProperty(const DrmProperty &) = delete; - DrmProperty &operator=(const DrmProperty &) = delete; - - void Init(drmModePropertyPtr p, uint64_t value); - std::tuple GetEnumValueWithName(std::string name) const; - - uint32_t id() const; - std::string name() const; - - std::tuple value() const; - bool is_immutable() const; - - bool is_range() const; - std::tuple range_min() const; - std::tuple range_max() const; - - private: - class DrmPropertyEnum { - public: - DrmPropertyEnum(drm_mode_property_enum *e); - ~DrmPropertyEnum(); - - uint64_t value_; - std::string name_; - }; - - uint32_t id_ = 0; - - DrmPropertyType type_ = DRM_PROPERTY_TYPE_INVALID; - uint32_t flags_ = 0; - std::string name_; - uint64_t value_ = 0; - - std::vector values_; - std::vector enums_; - std::vector blob_ids_; -}; -} // namespace android - -#endif // ANDROID_DRM_PROPERTY_H_ diff --git a/drm/resourcemanager.cpp b/drm/resourcemanager.cpp deleted file mode 100644 index 45fa818..0000000 --- a/drm/resourcemanager.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "hwc-resource-manager" - -#include "resourcemanager.h" - -#include -#include -#include -#include - -namespace android { - -ResourceManager::ResourceManager() : num_displays_(0), gralloc_(NULL) { -} - -int ResourceManager::Init() { - char path_pattern[PROPERTY_VALUE_MAX]; - // Could be a valid path or it can have at the end of it the wildcard % - // which means that it will try open all devices until an error is met. - int path_len = property_get("vendor.hwc.drm.device", path_pattern, - "/dev/dri/card%"); - int ret = 0; - if (path_pattern[path_len - 1] != '%') { - ret = AddDrmDevice(std::string(path_pattern)); - } else { - path_pattern[path_len - 1] = '\0'; - for (int idx = 0; !ret; ++idx) { - std::ostringstream path; - path << path_pattern << idx; - - struct stat buf; - if (stat(path.str().c_str(), &buf)) { - break; - } else if (IsKMSDev(path.str().c_str())) { - ret = AddDrmDevice(path.str()); - } - } - } - - if (!num_displays_) { - ALOGE("Failed to initialize any displays"); - return ret ? -EINVAL : ret; - } - - char scale_with_gpu[PROPERTY_VALUE_MAX]; - property_get("vendor.hwc.drm.scale_with_gpu", scale_with_gpu, "0"); - scale_with_gpu_ = bool(strncmp(scale_with_gpu, "0", 1)); - - return hw_get_module(GRALLOC_HARDWARE_MODULE_ID, - (const hw_module_t **)&gralloc_); -} - -int ResourceManager::AddDrmDevice(std::string path) { - std::unique_ptr drm = std::make_unique(); - int displays_added, ret; - std::tie(ret, displays_added) = drm->Init(path.c_str(), num_displays_); - if (ret) - return ret; - std::shared_ptr importer; - importer.reset(Importer::CreateInstance(drm.get())); - if (!importer) { - ALOGE("Failed to create importer instance"); - return -ENODEV; - } - importers_.push_back(importer); - drms_.push_back(std::move(drm)); - num_displays_ += displays_added; - return ret; -} - -DrmConnector *ResourceManager::AvailableWritebackConnector(int display) { - DrmDevice *drm_device = GetDrmDevice(display); - DrmConnector *writeback_conn = NULL; - if (drm_device) { - writeback_conn = drm_device->AvailableWritebackConnector(display); - if (writeback_conn) - return writeback_conn; - } - for (auto &drm : drms_) { - if (drm.get() == drm_device) - continue; - writeback_conn = drm->AvailableWritebackConnector(display); - if (writeback_conn) - return writeback_conn; - } - return writeback_conn; -} - -bool ResourceManager::IsKMSDev(const char *path) { - int fd = open(path, O_RDWR | O_CLOEXEC); - if (fd < 0) - return false; - - auto res = drmModeGetResources(fd); - if (!res) { - close(fd); - return false; - } - - bool is_kms = res->count_crtcs > 0 && res->count_connectors > 0 && - res->count_encoders > 0; - - drmModeFreeResources(res); - close(fd); - - return is_kms; -} - -DrmDevice *ResourceManager::GetDrmDevice(int display) { - for (auto &drm : drms_) { - if (drm->HandlesDisplay(display)) - return drm.get(); - } - return NULL; -} - -std::shared_ptr ResourceManager::GetImporter(int display) { - for (unsigned int i = 0; i < drms_.size(); i++) { - if (drms_[i]->HandlesDisplay(display)) - return importers_[i]; - } - return NULL; -} - -const gralloc_module_t *ResourceManager::gralloc() { - return gralloc_; -} -} // namespace android diff --git a/drm/resourcemanager.h b/drm/resourcemanager.h deleted file mode 100644 index 4afa842..0000000 --- a/drm/resourcemanager.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef RESOURCEMANAGER_H -#define RESOURCEMANAGER_H - -#include - -#include "drmdevice.h" -#include "platform/platform.h" - -namespace android { - -class ResourceManager { - public: - ResourceManager(); - ResourceManager(const ResourceManager &) = delete; - ResourceManager &operator=(const ResourceManager &) = delete; - int Init(); - DrmDevice *GetDrmDevice(int display); - std::shared_ptr GetImporter(int display); - const gralloc_module_t *gralloc(); - DrmConnector *AvailableWritebackConnector(int display); - const std::vector> &getDrmDevices() const { - return drms_; - } - int getDisplayCount() const { - return num_displays_; - } - bool ForcedScalingWithGpu() { - return scale_with_gpu_; - } - - private: - int AddDrmDevice(std::string path); - static bool IsKMSDev(const char *path); - - int num_displays_; - std::vector> drms_; - std::vector> importers_; - const gralloc_module_t *gralloc_; - - bool scale_with_gpu_; -}; -} // namespace android - -#endif // RESOURCEMANAGER_H diff --git a/drm/vsyncworker.cpp b/drm/vsyncworker.cpp deleted file mode 100644 index 55dbd26..0000000 --- a/drm/vsyncworker.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "hwc-vsync-worker" - -#include "vsyncworker.h" - -#include -#include -#include -#include - -#include - -namespace android { - -VSyncWorker::VSyncWorker() - : Worker("vsync", HAL_PRIORITY_URGENT_DISPLAY), - drm_(NULL), - display_(-1), - enabled_(false), - last_timestamp_(-1) { -} - -VSyncWorker::~VSyncWorker() { -} - -int VSyncWorker::Init(DrmDevice *drm, int display) { - drm_ = drm; - display_ = display; - - return InitWorker(); -} - -void VSyncWorker::RegisterCallback(std::shared_ptr callback) { - Lock(); - callback_ = callback; - Unlock(); -} - -void VSyncWorker::VSyncControl(bool enabled) { - Lock(); - enabled_ = enabled; - last_timestamp_ = -1; - Unlock(); - - Signal(); -} - -/* - * Returns the timestamp of the next vsync in phase with last_timestamp_. - * For example: - * last_timestamp_ = 137 - * frame_ns = 50 - * current = 683 - * - * ret = (50 * ((683 - 137)/50 + 1)) + 137 - * ret = 687 - * - * Thus, we must sleep until timestamp 687 to maintain phase with the last - * timestamp. - */ -int64_t VSyncWorker::GetPhasedVSync(int64_t frame_ns, int64_t current) { - if (last_timestamp_ < 0) - return current + frame_ns; - - return frame_ns * ((current - last_timestamp_) / frame_ns + 1) + - last_timestamp_; -} - -static const int64_t kOneSecondNs = 1 * 1000 * 1000 * 1000; - -int VSyncWorker::SyntheticWaitVBlank(int64_t *timestamp) { - struct timespec vsync; - int ret = clock_gettime(CLOCK_MONOTONIC, &vsync); - - float refresh = 60.0f; // Default to 60Hz refresh rate - DrmConnector *conn = drm_->GetConnectorForDisplay(display_); - if (conn && conn->active_mode().v_refresh() != 0.0f) - refresh = conn->active_mode().v_refresh(); - else - ALOGW("Vsync worker active with conn=%p refresh=%f\n", conn, - conn ? conn->active_mode().v_refresh() : 0.0f); - - int64_t phased_timestamp = GetPhasedVSync(kOneSecondNs / refresh, - vsync.tv_sec * kOneSecondNs + - vsync.tv_nsec); - vsync.tv_sec = phased_timestamp / kOneSecondNs; - vsync.tv_nsec = phased_timestamp - (vsync.tv_sec * kOneSecondNs); - do { - ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &vsync, NULL); - } while (ret == -1 && errno == EINTR); - if (ret) - return ret; - - *timestamp = (int64_t)vsync.tv_sec * kOneSecondNs + (int64_t)vsync.tv_nsec; - return 0; -} - -void VSyncWorker::Routine() { - int ret; - - Lock(); - if (!enabled_) { - ret = WaitForSignalOrExitLocked(); - if (ret == -EINTR) { - Unlock(); - return; - } - } - - int display = display_; - std::shared_ptr callback(callback_); - Unlock(); - - DrmCrtc *crtc = drm_->GetCrtcForDisplay(display); - if (!crtc) { - ALOGE("Failed to get crtc for display"); - return; - } - uint32_t high_crtc = (crtc->pipe() << DRM_VBLANK_HIGH_CRTC_SHIFT); - - drmVBlank vblank; - memset(&vblank, 0, sizeof(vblank)); - vblank.request.type = (drmVBlankSeqType)( - DRM_VBLANK_RELATIVE | (high_crtc & DRM_VBLANK_HIGH_CRTC_MASK)); - vblank.request.sequence = 1; - - int64_t timestamp; - ret = drmWaitVBlank(drm_->fd(), &vblank); - if (ret == -EINTR) { - return; - } else if (ret) { - ret = SyntheticWaitVBlank(×tamp); - if (ret) - return; - } else { - timestamp = (int64_t)vblank.reply.tval_sec * kOneSecondNs + - (int64_t)vblank.reply.tval_usec * 1000; - } - - /* - * VSync could be disabled during routine execution so it could potentially - * lead to crash since callback's inner hook could be invalid anymore. We have - * no control over lifetime of this hook, therefore we can't rely that it'll - * be valid after vsync disabling. - * - * Blocking VSyncControl to wait until routine - * will finish execution is logically correct way to fix this issue, but it - * creates visible lags and stutters, so we have to resort to other ways of - * mitigating this issue. - * - * Doing check before attempt to invoke callback drastically shortens the - * window when such situation could happen and that allows us to practically - * avoid this issue. - * - * Please note that issue described below is different one and it is related - * to RegisterCallback, not to disabling vsync via VSyncControl. - */ - if (!enabled_) - return; - /* - * 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 callback_ right before calling - * the hook. However, in practice, callback_ is only updated once, so it's not - * worth the overhead. - */ - if (callback) - callback->Callback(display, timestamp); - last_timestamp_ = timestamp; -} -} // namespace android diff --git a/drm/vsyncworker.h b/drm/vsyncworker.h deleted file mode 100644 index cbf4ffa..0000000 --- a/drm/vsyncworker.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_EVENT_WORKER_H_ -#define ANDROID_EVENT_WORKER_H_ - -#include -#include -#include - -#include - -#include "drmdevice.h" -#include "utils/worker.h" - -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(DrmDevice *drm, int display); - void RegisterCallback(std::shared_ptr callback); - - void VSyncControl(bool enabled); - - protected: - void Routine() override; - - private: - int64_t GetPhasedVSync(int64_t frame_ns, int64_t current); - int SyntheticWaitVBlank(int64_t *timestamp); - - DrmDevice *drm_; - - // 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 callback_ = NULL; - - int display_; - std::atomic_bool enabled_; - int64_t last_timestamp_; -}; -} // namespace android - -#endif diff --git a/drmhwctwo.cpp b/drmhwctwo.cpp deleted file mode 100644 index c771022..0000000 --- a/drmhwctwo.cpp +++ /dev/null @@ -1,1448 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#define LOG_TAG "hwc-drm-two" - -#include "drmhwctwo.h" - -#include -#include -#include -#include -#include - -#include - -#include "backend/backendmanager.h" -#include "compositor/drmdisplaycomposition.h" - -namespace android { - -class DrmVsyncCallback : public VsyncCallback { - public: - DrmVsyncCallback(hwc2_callback_data_t data, hwc2_function_pointer_t hook) - : data_(data), hook_(hook) { - } - - void Callback(int display, int64_t timestamp) { - auto hook = reinterpret_cast(hook_); - hook(data_, display, timestamp); - } - - private: - hwc2_callback_data_t data_; - hwc2_function_pointer_t hook_; -}; - -DrmHwcTwo::DrmHwcTwo() { - common.tag = HARDWARE_DEVICE_TAG; - common.version = HWC_DEVICE_API_VERSION_2_0; - common.close = HookDevClose; - getCapabilities = HookDevGetCapabilities; - getFunction = HookDevGetFunction; -} - -HWC2::Error DrmHwcTwo::CreateDisplay(hwc2_display_t displ, - HWC2::DisplayType type) { - DrmDevice *drm = resource_manager_.GetDrmDevice(displ); - std::shared_ptr importer = resource_manager_.GetImporter(displ); - if (!drm || !importer) { - ALOGE("Failed to get a valid drmresource and importer"); - return HWC2::Error::NoResources; - } - displays_.emplace(std::piecewise_construct, std::forward_as_tuple(displ), - std::forward_as_tuple(&resource_manager_, drm, importer, - displ, type)); - - DrmCrtc *crtc = drm->GetCrtcForDisplay(static_cast(displ)); - if (!crtc) { - ALOGE("Failed to get crtc for display %d", static_cast(displ)); - return HWC2::Error::BadDisplay; - } - std::vector display_planes; - for (auto &plane : drm->planes()) { - if (plane->GetCrtcSupported(*crtc)) - display_planes.push_back(plane.get()); - } - displays_.at(displ).Init(&display_planes); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::Init() { - int rv = resource_manager_.Init(); - if (rv) { - ALOGE("Can't initialize the resource manager %d", rv); - return HWC2::Error::NoResources; - } - - HWC2::Error ret = HWC2::Error::None; - for (int i = 0; i < resource_manager_.getDisplayCount(); i++) { - ret = CreateDisplay(i, HWC2::DisplayType::Physical); - if (ret != HWC2::Error::None) { - ALOGE("Failed to create display %d with error %d", i, ret); - return ret; - } - } - - auto &drmDevices = resource_manager_.getDrmDevices(); - for (auto &device : drmDevices) { - device->RegisterHotplugHandler(new DrmHotplugHandler(this, device.get())); - } - return ret; -} - -template -static inline HWC2::Error unsupported(char const *func, Args... /*args*/) { - ALOGV("Unsupported function: %s", func); - return HWC2::Error::Unsupported; -} - -static inline void supported(char const *func) { - ALOGV("Supported function: %s", func); -} - -HWC2::Error DrmHwcTwo::CreateVirtualDisplay(uint32_t width, uint32_t height, - int32_t *format, - hwc2_display_t *display) { - // TODO: Implement virtual display - return unsupported(__func__, width, height, format, display); -} - -HWC2::Error DrmHwcTwo::DestroyVirtualDisplay(hwc2_display_t display) { - // TODO: Implement virtual display - return unsupported(__func__, display); -} - -std::string DrmHwcTwo::HwcDisplay::DumpDelta( - DrmHwcTwo::HwcDisplay::Stats delta) { - if (delta.total_pixops_ == 0) - return "No stats yet"; - double Ratio = 1.0 - double(delta.gpu_pixops_) / double(delta.total_pixops_); - - return (std::stringstream() - << " Total frames count: " << delta.total_frames_ << "\n" - << " Failed to test commit frames: " << delta.failed_kms_validate_ - << "\n" - << " Failed to commit frames: " << delta.failed_kms_present_ << "\n" - << ((delta.failed_kms_present_ > 0) - ? " !!! Internal failure, FIX it please\n" - : "") - << " Flattened frames: " << delta.frames_flattened_ << "\n" - << " Pixel operations (free units)" - << " : [TOTAL: " << delta.total_pixops_ - << " / GPU: " << delta.gpu_pixops_ << "]\n" - << " Composition efficiency: " << Ratio) - .str(); -} - -std::string DrmHwcTwo::HwcDisplay::Dump() { - auto out = (std::stringstream() - << "- Display on: " << connector_->name() << "\n" - << " Flattening state: " << compositor_.GetFlatteningState() - << "\n" - << "Statistics since system boot:\n" - << DumpDelta(total_stats_) << "\n\n" - << "Statistics since last dumpsys request:\n" - << DumpDelta(total_stats_.minus(prev_stats_)) << "\n\n") - .str(); - - memcpy(&prev_stats_, &total_stats_, sizeof(Stats)); - return out; -} - -void DrmHwcTwo::Dump(uint32_t *outSize, char *outBuffer) { - supported(__func__); - - if (outBuffer != nullptr) { - auto copiedBytes = mDumpString.copy(outBuffer, *outSize); - *outSize = static_cast(copiedBytes); - return; - } - - std::stringstream output; - - output << "-- drm_hwcomposer --\n\n"; - - for (std::pair &dp : displays_) - output << dp.second.Dump(); - - mDumpString = output.str(); - *outSize = static_cast(mDumpString.size()); -} - -uint32_t DrmHwcTwo::GetMaxVirtualDisplayCount() { - // TODO: Implement virtual display - unsupported(__func__); - return 0; -} - -HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor, - hwc2_callback_data_t data, - hwc2_function_pointer_t function) { - supported(__func__); - auto callback = static_cast(descriptor); - - if (!function) { - callbacks_.erase(callback); - return HWC2::Error::None; - } - - callbacks_.emplace(callback, HwcCallback(data, function)); - - switch (callback) { - case HWC2::Callback::Hotplug: { - auto &drmDevices = resource_manager_.getDrmDevices(); - for (auto &device : drmDevices) - HandleInitialHotplugState(device.get()); - break; - } - case HWC2::Callback::Refresh: { - for (std::pair &d : - displays_) - d.second.RegisterRefreshCallback(data, function); - break; - } - case HWC2::Callback::Vsync: { - for (std::pair &d : - displays_) - d.second.RegisterVsyncCallback(data, function); - break; - } - default: - break; - } - return HWC2::Error::None; -} - -DrmHwcTwo::HwcDisplay::HwcDisplay(ResourceManager *resource_manager, - DrmDevice *drm, - std::shared_ptr importer, - hwc2_display_t handle, HWC2::DisplayType type) - : resource_manager_(resource_manager), - drm_(drm), - importer_(importer), - handle_(handle), - type_(type), - color_transform_hint_(HAL_COLOR_TRANSFORM_IDENTITY) { - supported(__func__); - - // clang-format off - color_transform_matrix_ = {1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0}; - // clang-format on -} - -void DrmHwcTwo::HwcDisplay::ClearDisplay() { - compositor_.ClearDisplay(); -} - -HWC2::Error DrmHwcTwo::HwcDisplay::Init(std::vector *planes) { - supported(__func__); - planner_ = Planner::CreateInstance(drm_); - if (!planner_) { - ALOGE("Failed to create planner instance for composition"); - return HWC2::Error::NoResources; - } - - int display = static_cast(handle_); - int ret = compositor_.Init(resource_manager_, display); - if (ret) { - ALOGE("Failed display compositor init for display %d (%d)", display, ret); - return HWC2::Error::NoResources; - } - - // Split up the given display planes into primary and overlay to properly - // interface with the composition - char use_overlay_planes_prop[PROPERTY_VALUE_MAX]; - property_get("vendor.hwc.drm.use_overlay_planes", use_overlay_planes_prop, - "1"); - bool use_overlay_planes = atoi(use_overlay_planes_prop); - for (auto &plane : *planes) { - if (plane->type() == DRM_PLANE_TYPE_PRIMARY) - primary_planes_.push_back(plane); - else if (use_overlay_planes && (plane)->type() == DRM_PLANE_TYPE_OVERLAY) - overlay_planes_.push_back(plane); - } - - crtc_ = drm_->GetCrtcForDisplay(display); - if (!crtc_) { - ALOGE("Failed to get crtc for display %d", display); - return HWC2::Error::BadDisplay; - } - - connector_ = drm_->GetConnectorForDisplay(display); - if (!connector_) { - ALOGE("Failed to get connector for display %d", display); - return HWC2::Error::BadDisplay; - } - - ret = vsync_worker_.Init(drm_, display); - if (ret) { - ALOGE("Failed to create event worker for d=%d %d\n", display, ret); - return HWC2::Error::BadDisplay; - } - - ret = BackendManager::GetInstance().SetBackendForDisplay(this); - if (ret) { - ALOGE("Failed to set backend for d=%d %d\n", display, ret); - return HWC2::Error::BadDisplay; - } - - return ChosePreferredConfig(); -} - -HWC2::Error DrmHwcTwo::HwcDisplay::ChosePreferredConfig() { - // Fetch the number of modes from the display - uint32_t num_configs; - HWC2::Error err = GetDisplayConfigs(&num_configs, NULL); - if (err != HWC2::Error::None || !num_configs) - return err; - - return SetActiveConfig(connector_->get_preferred_mode_id()); -} - -HWC2::Error DrmHwcTwo::HwcDisplay::RegisterVsyncCallback( - hwc2_callback_data_t data, hwc2_function_pointer_t func) { - supported(__func__); - auto callback = std::make_shared(data, func); - vsync_worker_.RegisterCallback(std::move(callback)); - return HWC2::Error::None; -} - -void DrmHwcTwo::HwcDisplay::RegisterRefreshCallback( - hwc2_callback_data_t data, hwc2_function_pointer_t func) { - supported(__func__); - auto hook = reinterpret_cast(func); - compositor_.SetRefreshCallback([data, hook](int display) { - hook(data, static_cast(display)); - }); -} - -HWC2::Error DrmHwcTwo::HwcDisplay::AcceptDisplayChanges() { - supported(__func__); - for (std::pair &l : layers_) - l.second.accept_type_change(); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::CreateLayer(hwc2_layer_t *layer) { - supported(__func__); - layers_.emplace(static_cast(layer_idx_), HwcLayer()); - *layer = static_cast(layer_idx_); - ++layer_idx_; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::DestroyLayer(hwc2_layer_t layer) { - supported(__func__); - if (!get_layer(layer)) - return HWC2::Error::BadLayer; - - layers_.erase(layer); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetActiveConfig(hwc2_config_t *config) { - supported(__func__); - DrmMode const &mode = connector_->active_mode(); - if (mode.id() == 0) - return HWC2::Error::BadConfig; - - *config = mode.id(); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetChangedCompositionTypes( - uint32_t *num_elements, hwc2_layer_t *layers, int32_t *types) { - supported(__func__); - uint32_t num_changes = 0; - for (std::pair &l : layers_) { - if (l.second.type_changed()) { - if (layers && num_changes < *num_elements) - layers[num_changes] = l.first; - if (types && num_changes < *num_elements) - types[num_changes] = static_cast(l.second.validated_type()); - ++num_changes; - } - } - if (!layers && !types) - *num_elements = num_changes; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetClientTargetSupport(uint32_t width, - uint32_t height, - int32_t /*format*/, - int32_t dataspace) { - supported(__func__); - std::pair min = drm_->min_resolution(); - std::pair max = drm_->max_resolution(); - - if (width < min.first || height < min.second) - return HWC2::Error::Unsupported; - - if (width > max.first || height > max.second) - return HWC2::Error::Unsupported; - - if (dataspace != HAL_DATASPACE_UNKNOWN && - dataspace != HAL_DATASPACE_STANDARD_UNSPECIFIED) - return HWC2::Error::Unsupported; - - // TODO: Validate format can be handled by either GL or planes - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetColorModes(uint32_t *num_modes, - int32_t *modes) { - supported(__func__); - 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(attribute_in); - switch (attribute) { - case HWC2::Attribute::Width: - *value = mode->h_display(); - break; - case HWC2::Attribute::Height: - *value = mode->v_display(); - break; - case HWC2::Attribute::VsyncPeriod: - // in nanoseconds - *value = 1000 * 1000 * 1000 / mode->v_refresh(); - break; - case HWC2::Attribute::DpiX: - // Dots per 1000 inches - *value = mm_width ? (mode->h_display() * kUmPerInch) / mm_width : -1; - break; - case HWC2::Attribute::DpiY: - // Dots per 1000 inches - *value = mm_height ? (mode->v_display() * kUmPerInch) / mm_height : -1; - break; - default: - *value = -1; - return HWC2::Error::BadConfig; - } - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayConfigs(uint32_t *num_configs, - hwc2_config_t *configs) { - supported(__func__); - // Since this callback is normally invoked twice (once to get the count, and - // once to populate configs), we don't really want to read the edid - // redundantly. Instead, only update the modes on the first invocation. While - // it's possible this will result in stale modes, it'll all come out in the - // wash when we try to set the active config later. - if (!configs) { - int ret = connector_->UpdateModes(); - if (ret) { - ALOGE("Failed to update display modes %d", ret); - return HWC2::Error::BadDisplay; - } - } - - // Since the upper layers only look at vactive/hactive/refresh, height and - // width, it doesn't differentiate interlaced from progressive and other - // similar modes. Depending on the order of modes we return to SF, it could - // end up choosing a suboptimal configuration and dropping the preferred - // mode. To workaround this, don't offer interlaced modes to SF if there is - // at least one non-interlaced alternative and only offer a single WxH@R - // mode with at least the prefered mode from in DrmConnector::UpdateModes() - - // TODO: Remove the following block of code until AOSP handles all modes - std::vector sel_modes; - - // Add the preferred mode first to be sure it's not dropped - auto mode = std::find_if(connector_->modes().begin(), - connector_->modes().end(), [&](DrmMode const &m) { - return m.id() == - connector_->get_preferred_mode_id(); - }); - if (mode != connector_->modes().end()) - sel_modes.push_back(*mode); - - // Add the active mode if different from preferred mode - if (connector_->active_mode().id() != connector_->get_preferred_mode_id()) - sel_modes.push_back(connector_->active_mode()); - - // Cycle over the modes and filter out "similar" modes, keeping only the - // first ones in the order given by DRM (from CEA ids and timings order) - for (const DrmMode &mode : connector_->modes()) { - // TODO: Remove this when 3D Attributes are in AOSP - if (mode.flags() & DRM_MODE_FLAG_3D_MASK) - continue; - - // TODO: Remove this when the Interlaced attribute is in AOSP - if (mode.flags() & DRM_MODE_FLAG_INTERLACE) { - auto m = std::find_if(connector_->modes().begin(), - connector_->modes().end(), - [&mode](DrmMode const &m) { - return !(m.flags() & DRM_MODE_FLAG_INTERLACE) && - m.h_display() == mode.h_display() && - m.v_display() == mode.v_display(); - }); - if (m == connector_->modes().end()) - sel_modes.push_back(mode); - - continue; - } - - // Search for a similar WxH@R mode in the filtered list and drop it if - // another mode with the same WxH@R has already been selected - // TODO: Remove this when AOSP handles duplicates modes - auto m = std::find_if(sel_modes.begin(), sel_modes.end(), - [&mode](DrmMode const &m) { - return m.h_display() == mode.h_display() && - m.v_display() == mode.v_display() && - m.v_refresh() == mode.v_refresh(); - }); - if (m == sel_modes.end()) - sel_modes.push_back(mode); - } - - auto num_modes = static_cast(sel_modes.size()); - if (!configs) { - *num_configs = num_modes; - return HWC2::Error::None; - } - - uint32_t idx = 0; - for (const DrmMode &mode : sel_modes) { - if (idx >= *num_configs) - break; - configs[idx++] = mode.id(); - } - *num_configs = idx; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayName(uint32_t *size, char *name) { - supported(__func__); - std::ostringstream stream; - stream << "display-" << connector_->id(); - std::string string = stream.str(); - size_t length = string.length(); - if (!name) { - *size = length; - return HWC2::Error::None; - } - - *size = std::min(static_cast(length - 1), *size); - strncpy(name, string.c_str(), *size); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayRequests(int32_t *display_requests, - uint32_t *num_elements, - hwc2_layer_t *layers, - int32_t *layer_requests) { - supported(__func__); - // TODO: I think virtual display should request - // HWC2_DISPLAY_REQUEST_WRITE_CLIENT_TARGET_TO_OUTPUT here - unsupported(__func__, display_requests, num_elements, layers, layer_requests); - *num_elements = 0; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayType(int32_t *type) { - supported(__func__); - *type = static_cast(type_); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDozeSupport(int32_t *support) { - supported(__func__); - *support = 0; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetHdrCapabilities( - uint32_t *num_types, int32_t * /*types*/, float * /*max_luminance*/, - float * /*max_average_luminance*/, float * /*min_luminance*/) { - supported(__func__); - *num_types = 0; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetReleaseFences(uint32_t *num_elements, - hwc2_layer_t *layers, - int32_t *fences) { - supported(__func__); - uint32_t num_layers = 0; - - for (std::pair &l : layers_) { - ++num_layers; - if (layers == NULL || fences == NULL) { - continue; - } else if (num_layers > *num_elements) { - ALOGW("Overflow num_elements %d/%d", num_layers, *num_elements); - return HWC2::Error::None; - } - - layers[num_layers - 1] = l.first; - fences[num_layers - 1] = l.second.take_release_fence(); - } - *num_elements = num_layers; - return HWC2::Error::None; -} - -void DrmHwcTwo::HwcDisplay::AddFenceToPresentFence(int fd) { - if (fd < 0) - return; - - if (present_fence_.get() >= 0) { - int old_fence = present_fence_.get(); - present_fence_.Set(sync_merge("dc_present", old_fence, fd)); - close(fd); - } else { - present_fence_.Set(fd); - } -} - -bool DrmHwcTwo::HwcDisplay::HardwareSupportsLayerType( - HWC2::Composition comp_type) { - return comp_type == HWC2::Composition::Device || - comp_type == HWC2::Composition::Cursor; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::CreateComposition(bool test) { - std::vector layers_map; - layers_map.emplace_back(); - DrmCompositionDisplayLayersMap &map = layers_map.back(); - - map.display = static_cast(handle_); - map.geometry_changed = true; // TODO: Fix this - - // order the layers by z-order - bool use_client_layer = false; - uint32_t client_z_order = UINT32_MAX; - std::map z_map; - for (std::pair &l : layers_) { - switch (l.second.validated_type()) { - case HWC2::Composition::Device: - z_map.emplace(std::make_pair(l.second.z_order(), &l.second)); - break; - case HWC2::Composition::Client: - // Place it at the z_order of the lowest client layer - use_client_layer = true; - client_z_order = std::min(client_z_order, l.second.z_order()); - break; - default: - continue; - } - } - if (use_client_layer) - z_map.emplace(std::make_pair(client_z_order, &client_layer_)); - - if (z_map.empty()) - return HWC2::Error::BadLayer; - - // now that they're ordered by z, add them to the composition - for (std::pair &l : z_map) { - DrmHwcLayer layer; - l.second->PopulateDrmLayer(&layer); - int ret = layer.ImportBuffer(importer_.get()); - if (ret) { - ALOGE("Failed to import layer, ret=%d", ret); - return HWC2::Error::NoResources; - } - map.layers.emplace_back(std::move(layer)); - } - - std::unique_ptr composition = compositor_ - .CreateComposition(); - composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_); - - // TODO: Don't always assume geometry changed - int ret = composition->SetLayers(map.layers.data(), map.layers.size(), true); - if (ret) { - ALOGE("Failed to set layers in the composition ret=%d", ret); - return HWC2::Error::BadLayer; - } - - std::vector primary_planes(primary_planes_); - std::vector overlay_planes(overlay_planes_); - ret = composition->Plan(&primary_planes, &overlay_planes); - if (ret) { - ALOGE("Failed to plan the composition ret=%d", ret); - return HWC2::Error::BadConfig; - } - - // Disable the planes we're not using - for (auto i = primary_planes.begin(); i != primary_planes.end();) { - composition->AddPlaneDisable(*i); - i = primary_planes.erase(i); - } - for (auto i = overlay_planes.begin(); i != overlay_planes.end();) { - composition->AddPlaneDisable(*i); - i = overlay_planes.erase(i); - } - - if (test) { - ret = compositor_.TestComposition(composition.get()); - } else { - ret = compositor_.ApplyComposition(std::move(composition)); - AddFenceToPresentFence(compositor_.TakeOutFence()); - } - if (ret) { - if (!test) - ALOGE("Failed to apply the frame composition ret=%d", ret); - return HWC2::Error::BadParameter; - } - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::PresentDisplay(int32_t *present_fence) { - supported(__func__); - HWC2::Error ret; - - ++total_stats_.total_frames_; - - ret = CreateComposition(false); - if (ret != HWC2::Error::None) - ++total_stats_.failed_kms_present_; - - if (ret == HWC2::Error::BadLayer) { - // Can we really have no client or device layers? - *present_fence = -1; - return HWC2::Error::None; - } - if (ret != HWC2::Error::None) - return ret; - - *present_fence = present_fence_.Release(); - - ++frame_no_; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetActiveConfig(hwc2_config_t config) { - supported(__func__); - auto mode = std::find_if(connector_->modes().begin(), - connector_->modes().end(), - [config](DrmMode const &m) { - return m.id() == config; - }); - if (mode == connector_->modes().end()) { - ALOGE("Could not find active mode for %d", config); - return HWC2::Error::BadConfig; - } - - std::unique_ptr composition = compositor_ - .CreateComposition(); - composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_); - int ret = composition->SetDisplayMode(*mode); - ret = compositor_.ApplyComposition(std::move(composition)); - if (ret) { - ALOGE("Failed to queue dpms composition on %d", ret); - return HWC2::Error::BadConfig; - } - - connector_->set_active_mode(*mode); - - // Setup the client layer's dimensions - hwc_rect_t display_frame = {.left = 0, - .top = 0, - .right = static_cast(mode->h_display()), - .bottom = static_cast(mode->v_display())}; - client_layer_.SetLayerDisplayFrame(display_frame); - hwc_frect_t source_crop = {.left = 0.0f, - .top = 0.0f, - .right = mode->h_display() + 0.0f, - .bottom = mode->v_display() + 0.0f}; - client_layer_.SetLayerSourceCrop(source_crop); - - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetClientTarget(buffer_handle_t target, - int32_t acquire_fence, - int32_t dataspace, - hwc_region_t /*damage*/) { - supported(__func__); - UniqueFd uf(acquire_fence); - - client_layer_.set_buffer(target); - client_layer_.set_acquire_fence(uf.get()); - client_layer_.SetLayerDataspace(dataspace); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetColorMode(int32_t mode) { - supported(__func__); - - if (mode != HAL_COLOR_MODE_NATIVE) - return HWC2::Error::BadParameter; - - color_mode_ = mode; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetColorTransform(const float *matrix, - int32_t hint) { - supported(__func__); - if (hint < HAL_COLOR_TRANSFORM_IDENTITY || - hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA) - return HWC2::Error::BadParameter; - - if (!matrix && hint == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX) - return HWC2::Error::BadParameter; - - color_transform_hint_ = static_cast(hint); - if (color_transform_hint_ == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX) - std::copy(matrix, matrix + MATRIX_SIZE, color_transform_matrix_.begin()); - - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetOutputBuffer(buffer_handle_t buffer, - int32_t release_fence) { - supported(__func__); - // TODO: Need virtual display support - return unsupported(__func__, buffer, release_fence); -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetPowerMode(int32_t mode_in) { - supported(__func__); - uint64_t dpms_value = 0; - auto mode = static_cast(mode_in); - switch (mode) { - case HWC2::PowerMode::Off: - dpms_value = DRM_MODE_DPMS_OFF; - break; - case HWC2::PowerMode::On: - dpms_value = DRM_MODE_DPMS_ON; - break; - case HWC2::PowerMode::Doze: - case HWC2::PowerMode::DozeSuspend: - return HWC2::Error::Unsupported; - default: - ALOGI("Power mode %d is unsupported\n", mode); - return HWC2::Error::BadParameter; - }; - - std::unique_ptr composition = compositor_ - .CreateComposition(); - composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_); - composition->SetDpmsMode(dpms_value); - int ret = compositor_.ApplyComposition(std::move(composition)); - if (ret) { - ALOGE("Failed to apply the dpms composition ret=%d", ret); - return HWC2::Error::BadParameter; - } - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetVsyncEnabled(int32_t enabled) { - supported(__func__); - vsync_worker_.VSyncControl(HWC2_VSYNC_ENABLE == enabled); - return HWC2::Error::None; -} - -uint32_t DrmHwcTwo::HwcDisplay::CalcPixOps( - std::map &z_map, size_t first_z, - size_t size) { - uint32_t pixops = 0; - for (std::pair &l : z_map) { - if (l.first >= first_z && l.first < first_z + size) { - hwc_rect_t df = l.second->display_frame(); - pixops += (df.right - df.left) * (df.bottom - df.top); - } - } - return pixops; -} - -void DrmHwcTwo::HwcDisplay::MarkValidated( - std::map &z_map, size_t client_first_z, - size_t client_size) { - for (std::pair &l : z_map) { - if (l.first >= client_first_z && l.first < client_first_z + client_size) - l.second->set_validated_type(HWC2::Composition::Client); - else - l.second->set_validated_type(HWC2::Composition::Device); - } -} - -HWC2::Error DrmHwcTwo::HwcDisplay::ValidateDisplay(uint32_t *num_types, - uint32_t *num_requests) { - supported(__func__); - - return backend_->ValidateDisplay(this, num_types, num_requests); -} - -#if PLATFORM_SDK_VERSION > 28 -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayIdentificationData( - uint8_t *outPort, uint32_t *outDataSize, uint8_t *outData) { - supported(__func__); - - drmModePropertyBlobPtr blob; - int ret; - uint64_t blob_id; - - std::tie(ret, blob_id) = connector_->edid_property().value(); - if (ret) { - ALOGE("Failed to get edid property value."); - return HWC2::Error::Unsupported; - } - - blob = drmModeGetPropertyBlob(drm_->fd(), blob_id); - - if (outData) { - *outDataSize = std::min(*outDataSize, blob->length); - memcpy(outData, blob->data, *outDataSize); - } else { - *outDataSize = blob->length; - } - *outPort = connector_->id(); - - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayCapabilities( - uint32_t *outNumCapabilities, uint32_t *outCapabilities) { - unsupported(__func__, outCapabilities); - - if (outNumCapabilities == NULL) { - return HWC2::Error::BadParameter; - } - - *outNumCapabilities = 0; - - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayBrightnessSupport( - bool *supported) { - *supported = false; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetDisplayBrightness( - float /* brightness */) { - return HWC2::Error::Unsupported; -} - -#endif /* PLATFORM_SDK_VERSION > 28 */ - -#if PLATFORM_SDK_VERSION > 27 - -HWC2::Error DrmHwcTwo::HwcDisplay::GetRenderIntents( - int32_t mode, uint32_t *outNumIntents, - int32_t * /*android_render_intent_v1_1_t*/ outIntents) { - if (mode != HAL_COLOR_MODE_NATIVE) { - return HWC2::Error::BadParameter; - } - - if (outIntents == nullptr) { - *outNumIntents = 1; - return HWC2::Error::None; - } - *outNumIntents = 1; - outIntents[0] = HAL_RENDER_INTENT_COLORIMETRIC; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetColorModeWithIntent(int32_t mode, - int32_t intent) { - if (mode != HAL_COLOR_MODE_NATIVE) - return HWC2::Error::BadParameter; - if (intent != HAL_RENDER_INTENT_COLORIMETRIC) - return HWC2::Error::BadParameter; - color_mode_ = mode; - return HWC2::Error::None; -} - -#endif /* PLATFORM_SDK_VERSION > 27 */ - -HWC2::Error DrmHwcTwo::HwcLayer::SetCursorPosition(int32_t x, int32_t y) { - supported(__func__); - cursor_x_ = x; - cursor_y_ = y; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerBlendMode(int32_t mode) { - supported(__func__); - blending_ = static_cast(mode); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerBuffer(buffer_handle_t buffer, - int32_t acquire_fence) { - supported(__func__); - UniqueFd uf(acquire_fence); - - set_buffer(buffer); - set_acquire_fence(uf.get()); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerColor(hwc_color_t color) { - // TODO: Put to client composition here? - supported(__func__); - layer_color_ = color; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerCompositionType(int32_t type) { - sf_type_ = static_cast(type); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDataspace(int32_t dataspace) { - supported(__func__); - dataspace_ = static_cast(dataspace); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDisplayFrame(hwc_rect_t frame) { - supported(__func__); - display_frame_ = frame; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerPlaneAlpha(float alpha) { - supported(__func__); - alpha_ = alpha; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSidebandStream( - const native_handle_t *stream) { - supported(__func__); - // TODO: We don't support sideband - return unsupported(__func__, stream); -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSourceCrop(hwc_frect_t crop) { - supported(__func__); - source_crop_ = crop; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSurfaceDamage(hwc_region_t damage) { - supported(__func__); - // TODO: We don't use surface damage, marking as unsupported - unsupported(__func__, damage); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerTransform(int32_t transform) { - supported(__func__); - transform_ = static_cast(transform); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerVisibleRegion(hwc_region_t visible) { - supported(__func__); - // TODO: We don't use this information, marking as unsupported - unsupported(__func__, visible); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerZOrder(uint32_t order) { - supported(__func__); - z_order_ = order; - return HWC2::Error::None; -} - -void DrmHwcTwo::HwcLayer::PopulateDrmLayer(DrmHwcLayer *layer) { - supported(__func__); - switch (blending_) { - case HWC2::BlendMode::None: - layer->blending = DrmHwcBlending::kNone; - break; - case HWC2::BlendMode::Premultiplied: - layer->blending = DrmHwcBlending::kPreMult; - break; - case HWC2::BlendMode::Coverage: - layer->blending = DrmHwcBlending::kCoverage; - break; - default: - ALOGE("Unknown blending mode b=%d", blending_); - layer->blending = DrmHwcBlending::kNone; - break; - } - - OutputFd release_fence = release_fence_output(); - - layer->sf_handle = buffer_; - layer->acquire_fence = acquire_fence_.Release(); - layer->release_fence = std::move(release_fence); - layer->SetDisplayFrame(display_frame_); - layer->alpha = static_cast(65535.0f * alpha_ + 0.5f); - layer->SetSourceCrop(source_crop_); - layer->SetTransform(static_cast(transform_)); -} - -void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) { - auto cb = callbacks_.find(HWC2::Callback::Hotplug); - if (cb == callbacks_.end()) - return; - - auto hotplug = reinterpret_cast(cb->second.func); - hotplug(cb->second.data, displayid, - (state == DRM_MODE_CONNECTED ? HWC2_CONNECTION_CONNECTED - : HWC2_CONNECTION_DISCONNECTED)); -} - -void DrmHwcTwo::HandleInitialHotplugState(DrmDevice *drmDevice) { - for (auto &conn : drmDevice->connectors()) { - if (conn->state() != DRM_MODE_CONNECTED) - continue; - HandleDisplayHotplug(conn->display(), conn->state()); - } -} - -void DrmHwcTwo::DrmHotplugHandler::HandleEvent(uint64_t timestamp_us) { - for (auto &conn : drm_->connectors()) { - drmModeConnection old_state = conn->state(); - drmModeConnection cur_state = conn->UpdateModes() - ? DRM_MODE_UNKNOWNCONNECTION - : conn->state(); - - if (cur_state == old_state) - continue; - - ALOGI("%s event @%" PRIu64 " for connector %u on display %d", - cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", timestamp_us, - conn->id(), conn->display()); - - int display_id = conn->display(); - if (cur_state == DRM_MODE_CONNECTED) { - auto &display = hwc2_->displays_.at(display_id); - display.ChosePreferredConfig(); - } else { - auto &display = hwc2_->displays_.at(display_id); - display.ClearDisplay(); - } - - hwc2_->HandleDisplayHotplug(display_id, cur_state); - } -} - -// static -int DrmHwcTwo::HookDevClose(hw_device_t * /*dev*/) { - unsupported(__func__); - return 0; -} - -// static -void DrmHwcTwo::HookDevGetCapabilities(hwc2_device_t * /*dev*/, - uint32_t *out_count, - int32_t * /*out_capabilities*/) { - supported(__func__); - *out_count = 0; -} - -// static -hwc2_function_pointer_t DrmHwcTwo::HookDevGetFunction( - struct hwc2_device * /*dev*/, int32_t descriptor) { - supported(__func__); - auto func = static_cast(descriptor); - switch (func) { - // Device functions - case HWC2::FunctionDescriptor::CreateVirtualDisplay: - return ToHook( - DeviceHook); - case HWC2::FunctionDescriptor::DestroyVirtualDisplay: - return ToHook( - DeviceHook); - case HWC2::FunctionDescriptor::Dump: - return ToHook( - DeviceHook); - case HWC2::FunctionDescriptor::GetMaxVirtualDisplayCount: - return ToHook( - DeviceHook); - case HWC2::FunctionDescriptor::RegisterCallback: - return ToHook( - DeviceHook); - - // Display functions - case HWC2::FunctionDescriptor::AcceptDisplayChanges: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::CreateLayer: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::DestroyLayer: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::GetActiveConfig: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::GetChangedCompositionTypes: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::GetClientTargetSupport: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::GetColorModes: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::GetDisplayAttribute: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::GetDisplayConfigs: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::GetDisplayName: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::GetDisplayRequests: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::GetDisplayType: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::GetDozeSupport: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::GetHdrCapabilities: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::GetReleaseFences: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::PresentDisplay: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::SetActiveConfig: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::SetClientTarget: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::SetColorMode: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::SetColorTransform: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::SetOutputBuffer: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::SetPowerMode: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::SetVsyncEnabled: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::ValidateDisplay: - return ToHook( - DisplayHook); -#if PLATFORM_SDK_VERSION > 27 - case HWC2::FunctionDescriptor::GetRenderIntents: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::SetColorModeWithRenderIntent: - return ToHook( - DisplayHook); -#endif -#if PLATFORM_SDK_VERSION > 28 - case HWC2::FunctionDescriptor::GetDisplayIdentificationData: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::GetDisplayCapabilities: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::GetDisplayBrightnessSupport: - return ToHook( - DisplayHook); - case HWC2::FunctionDescriptor::SetDisplayBrightness: - return ToHook( - DisplayHook); -#endif /* PLATFORM_SDK_VERSION > 28 */ - // Layer functions - case HWC2::FunctionDescriptor::SetCursorPosition: - return ToHook( - LayerHook); - case HWC2::FunctionDescriptor::SetLayerBlendMode: - return ToHook( - LayerHook); - case HWC2::FunctionDescriptor::SetLayerBuffer: - return ToHook( - LayerHook); - case HWC2::FunctionDescriptor::SetLayerColor: - return ToHook( - LayerHook); - case HWC2::FunctionDescriptor::SetLayerCompositionType: - return ToHook( - LayerHook); - case HWC2::FunctionDescriptor::SetLayerDataspace: - return ToHook( - LayerHook); - case HWC2::FunctionDescriptor::SetLayerDisplayFrame: - return ToHook( - LayerHook); - case HWC2::FunctionDescriptor::SetLayerPlaneAlpha: - return ToHook( - LayerHook); - case HWC2::FunctionDescriptor::SetLayerSidebandStream: - return ToHook( - LayerHook); - case HWC2::FunctionDescriptor::SetLayerSourceCrop: - return ToHook( - LayerHook); - case HWC2::FunctionDescriptor::SetLayerSurfaceDamage: - return ToHook( - LayerHook); - case HWC2::FunctionDescriptor::SetLayerTransform: - return ToHook( - LayerHook); - case HWC2::FunctionDescriptor::SetLayerVisibleRegion: - return ToHook( - LayerHook); - case HWC2::FunctionDescriptor::SetLayerZOrder: - return ToHook( - LayerHook); - case HWC2::FunctionDescriptor::Invalid: - default: - return NULL; - } -} - -// static -int DrmHwcTwo::HookDevOpen(const struct hw_module_t *module, const char *name, - struct hw_device_t **dev) { - supported(__func__); - if (strcmp(name, HWC_HARDWARE_COMPOSER)) { - ALOGE("Invalid module name- %s", name); - return -EINVAL; - } - - std::unique_ptr ctx(new DrmHwcTwo()); - if (!ctx) { - ALOGE("Failed to allocate DrmHwcTwo"); - return -ENOMEM; - } - - HWC2::Error err = ctx->Init(); - if (err != HWC2::Error::None) { - ALOGE("Failed to initialize DrmHwcTwo err=%d\n", err); - return -EINVAL; - } - - ctx->common.module = const_cast(module); - *dev = &ctx->common; - ctx.release(); - return 0; -} -} // namespace android - -static struct hw_module_methods_t hwc2_module_methods = { - .open = android::DrmHwcTwo::HookDevOpen, -}; - -hw_module_t HAL_MODULE_INFO_SYM = { - .tag = HARDWARE_MODULE_TAG, - .module_api_version = HARDWARE_MODULE_API_VERSION(2, 0), - .id = HWC_HARDWARE_MODULE_ID, - .name = "DrmHwcTwo module", - .author = "The Android Open Source Project", - .methods = &hwc2_module_methods, - .dso = NULL, - .reserved = {0}, -}; diff --git a/drmhwctwo.h b/drmhwctwo.h deleted file mode 100644 index 94b13fc..0000000 --- a/drmhwctwo.h +++ /dev/null @@ -1,431 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_DRM_HWC_TWO_H_ -#define ANDROID_DRM_HWC_TWO_H_ - -#include -#include - -#include -#include - -#include "compositor/drmdisplaycompositor.h" -#include "drm/resourcemanager.h" -#include "drm/vsyncworker.h" -#include "drmhwcomposer.h" -#include "platform/platform.h" - -namespace android { - -class Backend; - -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(); - - 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_); - } - - hwc_rect_t display_frame() { - return display_frame_; - } - - void PopulateDrmLayer(DrmHwcLayer *layer); - - bool RequireScalingOrPhasing() { - float src_width = source_crop_.right - source_crop_.left; - float src_height = source_crop_.bottom - source_crop_.top; - - float dest_width = display_frame_.right - display_frame_.left; - float dest_height = display_frame_.bottom - display_frame_.top; - - bool scaling = src_width != dest_width || src_height != dest_height; - bool phasing = (source_crop_.left - floor(source_crop_.left) != 0) || - (source_crop_.top - floor(source_crop_.top) != 0); - return scaling || phasing; - } - - // 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_ = NULL; - 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_; - hwc_color_t layer_color_; - 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(ResourceManager *resource_manager, DrmDevice *drm, - std::shared_ptr importer, hwc2_display_t handle, - HWC2::DisplayType type); - HwcDisplay(const HwcDisplay &) = delete; - HWC2::Error Init(std::vector *planes); - - HWC2::Error RegisterVsyncCallback(hwc2_callback_data_t data, - hwc2_function_pointer_t func); - void RegisterRefreshCallback(hwc2_callback_data_t data, - hwc2_function_pointer_t func); - HWC2::Error CreateComposition(bool test); - bool HardwareSupportsLayerType(HWC2::Composition comp_type); - uint32_t CalcPixOps(std::map &z_map, - size_t first_z, size_t size); - void MarkValidated(std::map &z_map, - size_t client_first_z, size_t client_size); - - void ClearDisplay(); - - std::string Dump(); - - // HWC Hooks - HWC2::Error AcceptDisplayChanges(); - HWC2::Error CreateLayer(hwc2_layer_t *layer); - HWC2::Error DestroyLayer(hwc2_layer_t layer); - HWC2::Error GetActiveConfig(hwc2_config_t *config); - HWC2::Error GetChangedCompositionTypes(uint32_t *num_elements, - hwc2_layer_t *layers, - int32_t *types); - HWC2::Error GetClientTargetSupport(uint32_t width, uint32_t height, - int32_t format, int32_t dataspace); - HWC2::Error GetColorModes(uint32_t *num_modes, int32_t *modes); - HWC2::Error GetDisplayAttribute(hwc2_config_t config, int32_t attribute, - int32_t *value); - HWC2::Error GetDisplayConfigs(uint32_t *num_configs, - hwc2_config_t *configs); - HWC2::Error GetDisplayName(uint32_t *size, char *name); - HWC2::Error GetDisplayRequests(int32_t *display_requests, - uint32_t *num_elements, hwc2_layer_t *layers, - int32_t *layer_requests); - HWC2::Error GetDisplayType(int32_t *type); -#if PLATFORM_SDK_VERSION > 27 - HWC2::Error GetRenderIntents(int32_t mode, uint32_t *outNumIntents, - int32_t *outIntents); - HWC2::Error SetColorModeWithIntent(int32_t mode, int32_t intent); -#endif -#if PLATFORM_SDK_VERSION > 28 - HWC2::Error GetDisplayIdentificationData(uint8_t *outPort, - uint32_t *outDataSize, - uint8_t *outData); - HWC2::Error GetDisplayCapabilities(uint32_t *outNumCapabilities, - uint32_t *outCapabilities); - HWC2::Error GetDisplayBrightnessSupport(bool *supported); - HWC2::Error SetDisplayBrightness(float); -#endif - HWC2::Error GetDozeSupport(int32_t *support); - HWC2::Error GetHdrCapabilities(uint32_t *num_types, int32_t *types, - float *max_luminance, - float *max_average_luminance, - float *min_luminance); - HWC2::Error GetReleaseFences(uint32_t *num_elements, hwc2_layer_t *layers, - int32_t *fences); - HWC2::Error PresentDisplay(int32_t *present_fence); - HWC2::Error SetActiveConfig(hwc2_config_t config); - HWC2::Error ChosePreferredConfig(); - HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence, - int32_t dataspace, hwc_region_t damage); - HWC2::Error SetColorMode(int32_t mode); - HWC2::Error SetColorTransform(const float *matrix, int32_t hint); - HWC2::Error SetOutputBuffer(buffer_handle_t buffer, int32_t release_fence); - HWC2::Error SetPowerMode(int32_t mode); - HWC2::Error SetVsyncEnabled(int32_t enabled); - HWC2::Error ValidateDisplay(uint32_t *num_types, uint32_t *num_requests); - HwcLayer *get_layer(hwc2_layer_t layer) { - auto it = layers_.find(layer); - if (it == layers_.end()) - return nullptr; - return &it->second; - } - - /* Statistics */ - struct Stats { - Stats minus(Stats b) { - return {total_frames_ - b.total_frames_, - total_pixops_ - b.total_pixops_, - gpu_pixops_ - b.gpu_pixops_, - failed_kms_validate_ - b.failed_kms_validate_, - failed_kms_present_ - b.failed_kms_present_, - frames_flattened_ - b.frames_flattened_}; - } - - uint32_t total_frames_ = 0; - uint64_t total_pixops_ = 0; - uint64_t gpu_pixops_ = 0; - uint32_t failed_kms_validate_ = 0; - uint32_t failed_kms_present_ = 0; - uint32_t frames_flattened_ = 0; - }; - - const Backend *backend() const { - return backend_.get(); - } - void set_backend(std::unique_ptr backend) { - backend_ = std::move(backend); - } - - const std::vector &primary_planes() const { - return primary_planes_; - } - - const std::vector &overlay_planes() const { - return overlay_planes_; - } - - std::map &layers() { - return layers_; - } - - const DrmDisplayCompositor &compositor() const { - return compositor_; - } - - const DrmDevice *drm() const { - return drm_; - } - - const DrmConnector *connector() const { - return connector_; - } - - const std::shared_ptr &importer() const { - return importer_; - } - - ResourceManager *resource_manager() const { - return resource_manager_; - } - - android_color_transform_t &color_transform_hint() { - return color_transform_hint_; - } - - Stats &total_stats() { - return total_stats_; - } - - private: - void AddFenceToPresentFence(int fd); - - constexpr static size_t MATRIX_SIZE = 16; - - ResourceManager *resource_manager_; - DrmDevice *drm_; - DrmDisplayCompositor compositor_; - std::shared_ptr importer_; - std::unique_ptr planner_; - - std::vector primary_planes_; - std::vector overlay_planes_; - - std::unique_ptr backend_; - - VSyncWorker vsync_worker_; - DrmConnector *connector_ = NULL; - DrmCrtc *crtc_ = NULL; - hwc2_display_t handle_; - HWC2::DisplayType type_; - uint32_t layer_idx_ = 0; - std::map layers_; - HwcLayer client_layer_; - UniqueFd present_fence_; - int32_t color_mode_; - std::array color_transform_matrix_; - android_color_transform_t color_transform_hint_; - - uint32_t frame_no_ = 0; - Stats total_stats_; - Stats prev_stats_; - std::string DumpDelta(DrmHwcTwo::HwcDisplay::Stats delta); - }; - - class DrmHotplugHandler : public DrmEventHandler { - public: - DrmHotplugHandler(DrmHwcTwo *hwc2, DrmDevice *drm) - : hwc2_(hwc2), drm_(drm) { - } - void HandleEvent(uint64_t timestamp_us); - - private: - DrmHwcTwo *hwc2_; - DrmDevice *drm_; - }; - - private: - static DrmHwcTwo *toDrmHwcTwo(hwc2_device_t *dev) { - return static_cast(dev); - } - - template - static hwc2_function_pointer_t ToHook(T function) { - static_assert(std::is_same::value, "Incompatible fn pointer"); - return reinterpret_cast(function); - } - - template - static T DeviceHook(hwc2_device_t *dev, Args... args) { - DrmHwcTwo *hwc = toDrmHwcTwo(dev); - return static_cast(((*hwc).*func)(std::forward(args)...)); - } - - static HwcDisplay *GetDisplay(DrmHwcTwo *hwc, hwc2_display_t display_handle) { - auto it = hwc->displays_.find(display_handle); - if (it == hwc->displays_.end()) - return nullptr; - - return &it->second; - } - - template - static int32_t DisplayHook(hwc2_device_t *dev, hwc2_display_t display_handle, - Args... args) { - HwcDisplay *display = GetDisplay(toDrmHwcTwo(dev), display_handle); - if (!display) - return static_cast(HWC2::Error::BadDisplay); - - return static_cast((display->*func)(std::forward(args)...)); - } - - template - static int32_t LayerHook(hwc2_device_t *dev, hwc2_display_t display_handle, - hwc2_layer_t layer_handle, Args... args) { - HwcDisplay *display = GetDisplay(toDrmHwcTwo(dev), display_handle); - if (!display) - return static_cast(HWC2::Error::BadDisplay); - - HwcLayer *layer = display->get_layer(layer_handle); - if (!layer) - return static_cast(HWC2::Error::BadLayer); - - return static_cast((layer->*func)(std::forward(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 *outSize, char *outBuffer); - uint32_t GetMaxVirtualDisplayCount(); - HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data, - hwc2_function_pointer_t function); - HWC2::Error CreateDisplay(hwc2_display_t displ, HWC2::DisplayType type); - void HandleDisplayHotplug(hwc2_display_t displayid, int state); - void HandleInitialHotplugState(DrmDevice *drmDevice); - - ResourceManager resource_manager_; - std::map displays_; - std::map callbacks_; - - std::string mDumpString; -}; -} // namespace android - -#endif diff --git a/include/DrmFramebuffer.h b/include/DrmFramebuffer.h new file mode 100644 index 0000000..33ca0db --- /dev/null +++ b/include/DrmFramebuffer.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DRM_FRAMEBUFFER_ +#define ANDROID_DRM_FRAMEBUFFER_ + +#include +#include +#include + +namespace android { + +struct DrmFramebuffer { + DrmFramebuffer() : release_fence_fd_(-1) { + } + + ~DrmFramebuffer() { + if (release_fence_fd() >= 0) + close(release_fence_fd()); + } + + bool is_valid() { + return buffer_ != NULL; + } + + sp buffer() { + return buffer_; + } + + int release_fence_fd() { + return release_fence_fd_; + } + + void set_release_fence_fd(int fd) { + if (release_fence_fd_ >= 0) + close(release_fence_fd_); + release_fence_fd_ = fd; + } + + bool Allocate(uint32_t w, uint32_t h) { + if (is_valid()) { + if (buffer_->getWidth() == w && buffer_->getHeight() == h) + return true; + + if (release_fence_fd_ >= 0) { + if (sync_wait(release_fence_fd_, kReleaseWaitTimeoutMs) != 0) { + ALOGE("Wait for release fence failed\n"); + return false; + } + } + Clear(); + } + buffer_ = new GraphicBuffer(w, h, PIXEL_FORMAT_RGB_888, + GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER | + GRALLOC_USAGE_HW_COMPOSER); + release_fence_fd_ = -1; + return is_valid(); + } + + void Clear() { + if (!is_valid()) + return; + + if (release_fence_fd_ >= 0) { + close(release_fence_fd_); + release_fence_fd_ = -1; + } + + buffer_.clear(); + } + + int WaitReleased(int timeout_milliseconds) { + if (!is_valid()) + return 0; + if (release_fence_fd_ < 0) + return 0; + + int ret = sync_wait(release_fence_fd_, timeout_milliseconds); + return ret; + } + + // Somewhat arbitrarily chosen, but wanted to stay below 3000ms, which is the + // system timeout + static const int kReleaseWaitTimeoutMs = 1500; + + private: + sp buffer_; + int release_fence_fd_; +}; +} // namespace android + +#endif // ANDROID_DRM_FRAMEBUFFER_ diff --git a/include/drmframebuffer.h b/include/drmframebuffer.h deleted file mode 100644 index 9032d3a..0000000 --- a/include/drmframebuffer.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DRM_FRAMEBUFFER_ -#define ANDROID_DRM_FRAMEBUFFER_ - -#include - -#include - -#include - -namespace android { - -struct DrmFramebuffer { - DrmFramebuffer() : release_fence_fd_(-1) { - } - - ~DrmFramebuffer() { - if (release_fence_fd() >= 0) - close(release_fence_fd()); - } - - bool is_valid() { - return buffer_ != NULL; - } - - sp buffer() { - return buffer_; - } - - int release_fence_fd() { - return release_fence_fd_; - } - - void set_release_fence_fd(int fd) { - if (release_fence_fd_ >= 0) - close(release_fence_fd_); - release_fence_fd_ = fd; - } - - bool Allocate(uint32_t w, uint32_t h) { - if (is_valid()) { - if (buffer_->getWidth() == w && buffer_->getHeight() == h) - return true; - - if (release_fence_fd_ >= 0) { - if (sync_wait(release_fence_fd_, kReleaseWaitTimeoutMs) != 0) { - ALOGE("Wait for release fence failed\n"); - return false; - } - } - Clear(); - } - buffer_ = new GraphicBuffer(w, h, PIXEL_FORMAT_RGB_888, - GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER | - GRALLOC_USAGE_HW_COMPOSER); - release_fence_fd_ = -1; - return is_valid(); - } - - void Clear() { - if (!is_valid()) - return; - - if (release_fence_fd_ >= 0) { - close(release_fence_fd_); - release_fence_fd_ = -1; - } - - buffer_.clear(); - } - - int WaitReleased(int timeout_milliseconds) { - if (!is_valid()) - return 0; - if (release_fence_fd_ < 0) - return 0; - - int ret = sync_wait(release_fence_fd_, timeout_milliseconds); - return ret; - } - - // Somewhat arbitrarily chosen, but wanted to stay below 3000ms, which is the - // system timeout - static const int kReleaseWaitTimeoutMs = 1500; - - private: - sp buffer_; - int release_fence_fd_; -}; -} // namespace android - -#endif // ANDROID_DRM_FRAMEBUFFER_ diff --git a/platform/platform.cpp b/platform/platform.cpp index 9fb91e7..479e79e 100644 --- a/platform/platform.cpp +++ b/platform/platform.cpp @@ -20,7 +20,7 @@ #include -#include "drm/drmdevice.h" +#include "drm/DrmDevice.h" namespace android { diff --git a/platform/platform.h b/platform/platform.h index e0befdb..13dc360 100644 --- a/platform/platform.h +++ b/platform/platform.h @@ -23,7 +23,7 @@ #include #include -#include "compositor/drmdisplaycomposition.h" +#include "compositor/DrmDisplayComposition.h" #include "drmhwcomposer.h" namespace android { diff --git a/platform/platformdrmgeneric.h b/platform/platformdrmgeneric.h index 4284093..bb78c28 100644 --- a/platform/platformdrmgeneric.h +++ b/platform/platformdrmgeneric.h @@ -22,7 +22,7 @@ #include -#include "drm/drmdevice.h" +#include "drm/DrmDevice.h" #include "platform.h" #ifndef DRM_FORMAT_INVALID diff --git a/tests/worker_test.cpp b/tests/worker_test.cpp index ba89b6f..cb6275e 100644 --- a/tests/worker_test.cpp +++ b/tests/worker_test.cpp @@ -1,4 +1,4 @@ -#include "utils/worker.h" +#include "utils/Worker.h" #include #include diff --git a/utils/Worker.cpp b/utils/Worker.cpp new file mode 100644 index 0000000..1f30588 --- /dev/null +++ b/utils/Worker.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2015-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 "Worker.h" + +#include +#include + +namespace android { + +Worker::Worker(const char *name, int priority) + : name_(name), priority_(priority), exit_(false), initialized_(false) { +} + +Worker::~Worker() { + Exit(); +} + +int Worker::InitWorker() { + std::lock_guard lk(mutex_); + if (initialized()) + return -EALREADY; + + thread_ = std::unique_ptr( + new std::thread(&Worker::InternalRoutine, this)); + initialized_ = true; + exit_ = false; + + return 0; +} + +void Worker::Exit() { + std::unique_lock lk(mutex_); + exit_ = true; + if (initialized()) { + lk.unlock(); + cond_.notify_all(); + thread_->join(); + initialized_ = false; + } +} + +int Worker::WaitForSignalOrExitLocked(int64_t max_nanoseconds) { + int ret = 0; + if (should_exit()) + return -EINTR; + + std::unique_lock lk(mutex_, std::adopt_lock); + if (max_nanoseconds < 0) { + cond_.wait(lk); + } else if (std::cv_status::timeout == + cond_.wait_for(lk, std::chrono::nanoseconds(max_nanoseconds))) { + ret = -ETIMEDOUT; + } + + // exit takes precedence on timeout + if (should_exit()) + ret = -EINTR; + + // release leaves mutex locked when going out of scope + lk.release(); + + return ret; +} + +void Worker::InternalRoutine() { + setpriority(PRIO_PROCESS, 0, priority_); + prctl(PR_SET_NAME, name_.c_str()); + + std::unique_lock lk(mutex_, std::defer_lock); + + while (true) { + lk.lock(); + if (should_exit()) + return; + lk.unlock(); + + Routine(); + } +} +} // namespace android diff --git a/utils/Worker.h b/utils/Worker.h new file mode 100644 index 0000000..73a80da --- /dev/null +++ b/utils/Worker.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2015-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. + */ + +#ifndef ANDROID_WORKER_H_ +#define ANDROID_WORKER_H_ + +#include +#include + +#include +#include +#include +#include + +namespace android { + +class Worker { + public: + void Lock() { + mutex_.lock(); + } + void Unlock() { + mutex_.unlock(); + } + + void Signal() { + cond_.notify_all(); + } + void Exit(); + + bool initialized() const { + return initialized_; + } + + protected: + Worker(const char *name, int priority); + virtual ~Worker(); + + int InitWorker(); + virtual void Routine() = 0; + + /* + * Must be called with the lock acquired. max_nanoseconds may be negative to + * indicate infinite timeout, otherwise it indicates the maximum time span to + * wait for a signal before returning. + * Returns -EINTR if interrupted by exit request, or -ETIMEDOUT if timed out + */ + int WaitForSignalOrExitLocked(int64_t max_nanoseconds = -1); + + bool should_exit() const { + return exit_; + } + + std::mutex mutex_; + std::condition_variable cond_; + + private: + void InternalRoutine(); + + std::string name_; + int priority_; + + std::unique_ptr thread_; + bool exit_; + bool initialized_; +}; +} // namespace android +#endif diff --git a/utils/worker.cpp b/utils/worker.cpp deleted file mode 100644 index 0dceb16..0000000 --- a/utils/worker.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2015-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 "worker.h" - -#include -#include - -namespace android { - -Worker::Worker(const char *name, int priority) - : name_(name), priority_(priority), exit_(false), initialized_(false) { -} - -Worker::~Worker() { - Exit(); -} - -int Worker::InitWorker() { - std::lock_guard lk(mutex_); - if (initialized()) - return -EALREADY; - - thread_ = std::unique_ptr( - new std::thread(&Worker::InternalRoutine, this)); - initialized_ = true; - exit_ = false; - - return 0; -} - -void Worker::Exit() { - std::unique_lock lk(mutex_); - exit_ = true; - if (initialized()) { - lk.unlock(); - cond_.notify_all(); - thread_->join(); - initialized_ = false; - } -} - -int Worker::WaitForSignalOrExitLocked(int64_t max_nanoseconds) { - int ret = 0; - if (should_exit()) - return -EINTR; - - std::unique_lock lk(mutex_, std::adopt_lock); - if (max_nanoseconds < 0) { - cond_.wait(lk); - } else if (std::cv_status::timeout == - cond_.wait_for(lk, std::chrono::nanoseconds(max_nanoseconds))) { - ret = -ETIMEDOUT; - } - - // exit takes precedence on timeout - if (should_exit()) - ret = -EINTR; - - // release leaves mutex locked when going out of scope - lk.release(); - - return ret; -} - -void Worker::InternalRoutine() { - setpriority(PRIO_PROCESS, 0, priority_); - prctl(PR_SET_NAME, name_.c_str()); - - std::unique_lock lk(mutex_, std::defer_lock); - - while (true) { - lk.lock(); - if (should_exit()) - return; - lk.unlock(); - - Routine(); - } -} -} // namespace android diff --git a/utils/worker.h b/utils/worker.h deleted file mode 100644 index 73a80da..0000000 --- a/utils/worker.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2015-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. - */ - -#ifndef ANDROID_WORKER_H_ -#define ANDROID_WORKER_H_ - -#include -#include - -#include -#include -#include -#include - -namespace android { - -class Worker { - public: - void Lock() { - mutex_.lock(); - } - void Unlock() { - mutex_.unlock(); - } - - void Signal() { - cond_.notify_all(); - } - void Exit(); - - bool initialized() const { - return initialized_; - } - - protected: - Worker(const char *name, int priority); - virtual ~Worker(); - - int InitWorker(); - virtual void Routine() = 0; - - /* - * Must be called with the lock acquired. max_nanoseconds may be negative to - * indicate infinite timeout, otherwise it indicates the maximum time span to - * wait for a signal before returning. - * Returns -EINTR if interrupted by exit request, or -ETIMEDOUT if timed out - */ - int WaitForSignalOrExitLocked(int64_t max_nanoseconds = -1); - - bool should_exit() const { - return exit_; - } - - std::mutex mutex_; - std::condition_variable cond_; - - private: - void InternalRoutine(); - - std::string name_; - int priority_; - - std::unique_ptr thread_; - bool exit_; - bool initialized_; -}; -} // namespace android -#endif -- cgit v1.2.3 From adc5d8229b9ce25f1bf0e4d02bb838eae62b89fc Mon Sep 17 00:00:00 2001 From: Andrii Chepurnyi Date: Fri, 10 Jul 2020 16:07:03 +0300 Subject: drm_hwcomposer: Fix EDID fetch from DRM EDID fetch procedure consist of two steps: 1) get appropriate blob_id 2) fetch EDID blob using blob_id Those steps should be done sequentially, in other case drivers can update EDID and blob_id won't be actual. Signed-off-by: Andrii Chepurnyi --- DrmHwcTwo.cpp | 7 +------ drm/DrmConnector.cpp | 29 +++++++++++++++++++++++++---- drm/DrmConnector.h | 2 ++ 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/DrmHwcTwo.cpp b/DrmHwcTwo.cpp index 15fa324..65a317c 100644 --- a/DrmHwcTwo.cpp +++ b/DrmHwcTwo.cpp @@ -915,17 +915,12 @@ HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayIdentificationData( supported(__func__); drmModePropertyBlobPtr blob; - int ret; - uint64_t blob_id; - std::tie(ret, blob_id) = connector_->edid_property().value(); - if (ret) { + if (connector_->GetEdidBlob(blob)) { ALOGE("Failed to get edid property value."); return HWC2::Error::Unsupported; } - blob = drmModeGetPropertyBlob(drm_->fd(), blob_id); - if (outData) { *outDataSize = std::min(*outDataSize, blob->length); memcpy(outData, blob->data, *outDataSize); diff --git a/drm/DrmConnector.cpp b/drm/DrmConnector.cpp index 8fa47f5..0de0f91 100644 --- a/drm/DrmConnector.cpp +++ b/drm/DrmConnector.cpp @@ -58,10 +58,7 @@ int DrmConnector::Init() { ALOGE("Could not get CRTC_ID property\n"); return ret; } - ret = drm_->GetConnectorProperty(*this, "EDID", &edid_property_); - if (ret) { - ALOGW("Could not get EDID property\n"); - } + ret = UpdateEdidProperty(); if (writeback()) { ret = drm_->GetConnectorProperty(*this, "WRITEBACK_PIXEL_FORMATS", &writeback_pixel_formats_); @@ -85,6 +82,30 @@ int DrmConnector::Init() { return 0; } +int DrmConnector::UpdateEdidProperty() { + int ret = drm_->GetConnectorProperty(*this, "EDID", &edid_property_); + if (ret) { + ALOGW("Could not get EDID property\n"); + } + return ret; +} + +int DrmConnector::GetEdidBlob(drmModePropertyBlobPtr &blob) { + uint64_t blob_id; + int ret = UpdateEdidProperty(); + if (ret) { + return ret; + } + + std::tie(ret, blob_id) = edid_property().value(); + if (ret) { + return ret; + } + + blob = drmModeGetPropertyBlob(drm_->fd(), blob_id); + return 0; +} + uint32_t DrmConnector::id() const { return id_; } diff --git a/drm/DrmConnector.h b/drm/DrmConnector.h index 3fdf146..8533af8 100644 --- a/drm/DrmConnector.h +++ b/drm/DrmConnector.h @@ -40,6 +40,8 @@ class DrmConnector { DrmConnector &operator=(const DrmProperty &) = delete; int Init(); + int UpdateEdidProperty(); + int GetEdidBlob(drmModePropertyBlobPtr &blob); uint32_t id() const; -- cgit v1.2.3 From f2393a48d10d792b79b5ac498f28f77d886910df Mon Sep 17 00:00:00 2001 From: Roman Stratiienko Date: Sat, 29 Aug 2020 22:16:21 +0300 Subject: drm_hwcomposer: always use PlanStageGreedy Only PlatformHisi has custom planner. It doesn't makes much sense since for HISI all composition is done on client side and planner should never get buffers with usage flag other than GRALLOC_USAGE_HW_FB. Signed-off-by: Roman Stratiienko Change-Id: I3db3f96165f4c3aacb8bc43c8ee3ebc877163e1b --- platform/platformdrmgeneric.cpp | 2 -- platform/platformhisi.cpp | 38 -------------------------------------- platform/platformimagination.cpp | 5 ----- platform/platformmeson.cpp | 5 ----- platform/platformminigbm.cpp | 6 ------ 5 files changed, 56 deletions(-) diff --git a/platform/platformdrmgeneric.cpp b/platform/platformdrmgeneric.cpp index d903031..deac477 100644 --- a/platform/platformdrmgeneric.cpp +++ b/platform/platformdrmgeneric.cpp @@ -354,13 +354,11 @@ bool DrmGenericImporter::CanImportBuffer(buffer_handle_t handle) { return true; } -#ifdef USE_DRM_GENERIC_IMPORTER std::unique_ptr Planner::CreateInstance(DrmDevice *) { std::unique_ptr planner(new Planner); planner->AddStage(); return planner; } -#endif int DrmGenericImporter::ImportHandle(uint32_t gem_handle) { gem_refcount_[gem_handle]++; diff --git a/platform/platformhisi.cpp b/platform/platformhisi.cpp index 8c10e34..67793db 100644 --- a/platform/platformhisi.cpp +++ b/platform/platformhisi.cpp @@ -152,42 +152,4 @@ int HisiImporter::ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) { return 0; } -class PlanStageHiSi : public Planner::PlanStage { - public: - int ProvisionPlanes(std::vector *composition, - std::map &layers, DrmCrtc *crtc, - std::vector *planes) { - int layers_added = 0; - // Fill up as many DRM planes as we can with buffers that have HW_FB usage. - // Buffers without HW_FB should have been filtered out with - // CanImportBuffer(), if we meet one here, just skip it. - for (auto i = layers.begin(); i != layers.end(); i = layers.erase(i)) { - if (!(i->second->gralloc_buffer_usage & GRALLOC_USAGE_HW_FB)) - continue; - - int ret = Emplace(composition, planes, DrmCompositionPlane::Type::kLayer, - crtc, std::make_pair(i->first, i->second)); - layers_added++; - // We don't have any planes left - if (ret == -ENOENT) - break; - else if (ret) { - ALOGE("Failed to emplace layer %zu, dropping it", i->first); - return ret; - } - } - // If we didn't emplace anything, return an error to ensure we force client - // compositing. - if (!layers_added) - return -EINVAL; - - return 0; - } -}; - -std::unique_ptr Planner::CreateInstance(DrmDevice *) { - std::unique_ptr planner(new Planner); - planner->AddStage(); - return planner; -} } // namespace android diff --git a/platform/platformimagination.cpp b/platform/platformimagination.cpp index 83cebf3..7001d64 100644 --- a/platform/platformimagination.cpp +++ b/platform/platformimagination.cpp @@ -60,9 +60,4 @@ int ImaginationImporter::ConvertBoInfo(buffer_handle_t handle, return 0; } -std::unique_ptr Planner::CreateInstance(DrmDevice *) { - std::unique_ptr planner(new Planner); - planner->AddStage(); - return planner; -} } // namespace android diff --git a/platform/platformmeson.cpp b/platform/platformmeson.cpp index ecace29..278eac5 100644 --- a/platform/platformmeson.cpp +++ b/platform/platformmeson.cpp @@ -102,9 +102,4 @@ int MesonImporter::ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) { return 0; } -std::unique_ptr Planner::CreateInstance(DrmDevice *) { - std::unique_ptr planner(new Planner); - planner->AddStage(); - return planner; -} } // namespace android diff --git a/platform/platformminigbm.cpp b/platform/platformminigbm.cpp index 39decab..4360b0a 100644 --- a/platform/platformminigbm.cpp +++ b/platform/platformminigbm.cpp @@ -60,10 +60,4 @@ int DrmMinigbmImporter::ConvertBoInfo(buffer_handle_t handle, return 0; } -std::unique_ptr Planner::CreateInstance(DrmDevice *) { - std::unique_ptr planner(new Planner); - planner->AddStage(); - return planner; -} - } // namespace android -- cgit v1.2.3 From 42c7f0c1b52fdda20ca142c8d3ef911b10783313 Mon Sep 17 00:00:00 2001 From: Roman Stratiienko Date: Sat, 29 Aug 2020 22:28:07 +0300 Subject: drm_hwcomposer: remove vendor.hwc.drm.exclude_non_hwfb_imports property This property was used to force composition on 'client' side. After adding Backends support, it can be replaced with more straightforward property definition: 'vendor.hwc.backend_override=client'. Signed-off-by: Roman Stratiienko Change-Id: I896da41abe8b777166a485c06a11c163ceaeb3f0 --- platform/platformdrmgeneric.cpp | 11 +---------- platform/platformdrmgeneric.h | 1 - 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/platform/platformdrmgeneric.cpp b/platform/platformdrmgeneric.cpp index deac477..ed3a68c 100644 --- a/platform/platformdrmgeneric.cpp +++ b/platform/platformdrmgeneric.cpp @@ -45,8 +45,7 @@ Importer *Importer::CreateInstance(DrmDevice *drm) { } #endif -DrmGenericImporter::DrmGenericImporter(DrmDevice *drm) - : drm_(drm), exclude_non_hwfb_(false) { +DrmGenericImporter::DrmGenericImporter(DrmDevice *drm) : drm_(drm) { } DrmGenericImporter::~DrmGenericImporter() { @@ -63,11 +62,6 @@ int DrmGenericImporter::Init() { ALOGI("Using %s gralloc module: %s\n", gralloc_->common.name, gralloc_->common.author); - char exclude_non_hwfb_prop[PROPERTY_VALUE_MAX]; - property_get("vendor.hwc.drm.exclude_non_hwfb_imports", exclude_non_hwfb_prop, - "0"); - exclude_non_hwfb_ = static_cast(strncmp(exclude_non_hwfb_prop, "0", 1)); - return 0; } @@ -348,9 +342,6 @@ bool DrmGenericImporter::CanImportBuffer(buffer_handle_t handle) { if (bo.prime_fds[0] == 0) return false; - if (exclude_non_hwfb_ && !(bo.usage & GRALLOC_USAGE_HW_FB)) - return false; - return true; } diff --git a/platform/platformdrmgeneric.h b/platform/platformdrmgeneric.h index bb78c28..1bdaa09 100644 --- a/platform/platformdrmgeneric.h +++ b/platform/platformdrmgeneric.h @@ -55,7 +55,6 @@ class DrmGenericImporter : public Importer { private: const gralloc_module_t *gralloc_; - bool exclude_non_hwfb_; int CloseHandle(uint32_t gem_handle); std::map gem_refcount_; -- cgit v1.2.3 From 5284c7e970a25dd6f80991672e51047c79811075 Mon Sep 17 00:00:00 2001 From: Mattijs Korpershoek Date: Mon, 21 Sep 2020 11:03:35 +0000 Subject: drm_hwcomposer: Add MediaTek platform support This platform handler is dedicated for the i500 MediaTek SoC [1]. i500 has a Mali-G72 MP3 GPU. OpenGL/Mali integration is based on ARM Gralloc module, version BX304L01B-SW-99005-r20p0-01rel0, without additional patches. This platformmediatek is based on platformmeson, without the additional usage flag in the private_handle_t. AFBC support has also been removed as it's unsupported. External Android.bp file should be created in order to build this module: ``` cc_library_shared { name: "hwcomposer.drm_mediatek", defaults: ["hwcomposer.drm_defaults"], srcs: [":drm_hwcomposer_platformmediatek"], whole_static_libs: ["drm_hwcomposer"], } ``` [1] https://www.mediatek.com/products/AIoT/i500 Change-Id: I3ea7a980d76ba5c5ff583b5d4f21e1989875bafb Signed-off-by: Mattijs Korpershoek --- Android.bp | 9 ++++++ platform/platformmediatek.cpp | 71 +++++++++++++++++++++++++++++++++++++++++++ platform/platformmediatek.h | 36 ++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 platform/platformmediatek.cpp create mode 100644 platform/platformmediatek.h diff --git a/Android.bp b/Android.bp index 4bd4586..fef3ed6 100644 --- a/Android.bp +++ b/Android.bp @@ -153,3 +153,12 @@ filegroup { "platform/platformmeson.cpp", ], } + +// Used by hwcomposer.drm_mediatek +filegroup { + name: "drm_hwcomposer_platformmediatek", + srcs: [ + "platform/platformdrmgeneric.cpp", + "platform/platformmediatek.cpp", + ], +} diff --git a/platform/platformmediatek.cpp b/platform/platformmediatek.cpp new file mode 100644 index 0000000..bbf76ea --- /dev/null +++ b/platform/platformmediatek.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "hwc-platform-mediatek" + +#include "platformmediatek.h" + +#include +#include +#include +#include +#include + +#include + +#include "gralloc_priv.h" +#include "platform.h" + +namespace android { + +Importer *Importer::CreateInstance(DrmDevice *drm) { + MediatekImporter *importer = new MediatekImporter(drm); + if (!importer) + return NULL; + + int ret = importer->Init(); + if (ret) { + ALOGE("Failed to initialize the mediatek importer %d", ret); + delete importer; + return NULL; + } + return importer; +} + +int MediatekImporter::ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) { + private_handle_t const *hnd = reinterpret_cast( + handle); + if (!hnd) + return -EINVAL; + + uint32_t fmt = ConvertHalFormatToDrm(hnd->req_format); + if (fmt == DRM_FORMAT_INVALID) + return -EINVAL; + + bo->width = hnd->width; + bo->height = hnd->height; + bo->hal_format = hnd->req_format; + bo->format = fmt; + bo->usage = hnd->consumer_usage | hnd->producer_usage; + bo->pixel_stride = hnd->stride; + bo->prime_fds[0] = hnd->share_fd; + bo->pitches[0] = hnd->byte_stride; + bo->offsets[0] = 0; + + return 0; +} + +} // namespace android diff --git a/platform/platformmediatek.h b/platform/platformmediatek.h new file mode 100644 index 0000000..61fcf47 --- /dev/null +++ b/platform/platformmediatek.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_PLATFORM_MTK_H_ +#define ANDROID_PLATFORM_MTK_H_ + +#include +#include + +#include "platform.h" +#include "platformdrmgeneric.h" + +namespace android { + +class MediatekImporter : public DrmGenericImporter { + public: + using DrmGenericImporter::DrmGenericImporter; + + int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) override; +}; +} // namespace android + +#endif -- cgit v1.2.3 From bbf28bb8d10abdcbc278e4e3e73faca650e92b16 Mon Sep 17 00:00:00 2001 From: Mattijs Korpershoek Date: Tue, 22 Sep 2020 17:52:06 +0200 Subject: drm_hwcomposer: add drm-mediatek to client-backend list Since mediatek-drm has no support for premultiplied alpha buffers, we can have issues with transparency. Disable off-loading by adding "mediatek-drm" to the client-backend list. Change-Id: I12b034ecd5ae961264d01b6effaa4f4010036ac9 Suggested-by: Roman Stratiienko Signed-off-by: Mattijs Korpershoek --- backend/BackendManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/BackendManager.cpp b/backend/BackendManager.cpp index b7601ee..0bacdcd 100644 --- a/backend/BackendManager.cpp +++ b/backend/BackendManager.cpp @@ -25,6 +25,7 @@ namespace android { const std::vector BackendManager::client_devices_ = { "kirin", + "mediatek-drm", }; BackendManager &BackendManager::GetInstance() { -- cgit v1.2.3 From 859b6074d795e3f43dfc43af62a019042a4a014f Mon Sep 17 00:00:00 2001 From: Roman Kovalivskyi Date: Thu, 26 Mar 2020 05:03:39 +0200 Subject: drm_hwcomposer: Add supported formats list to DrmPlane There are some use-cases for checking formats supported by given plane. drmModePlane already contains reqired data, so it simply could be saved into DrmPlane, no need to query any additional stuff. Signed-off-by: Roman Kovalivskyi --- drm/DrmPlane.cpp | 10 +++++++++- drm/DrmPlane.h | 4 ++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drm/DrmPlane.cpp b/drm/DrmPlane.cpp index 1fb1316..f994252 100644 --- a/drm/DrmPlane.cpp +++ b/drm/DrmPlane.cpp @@ -29,7 +29,10 @@ namespace android { DrmPlane::DrmPlane(DrmDevice *drm, drmModePlanePtr p) - : drm_(drm), id_(p->plane_id), possible_crtc_mask_(p->possible_crtcs) { + : drm_(drm), + id_(p->plane_id), + possible_crtc_mask_(p->possible_crtcs), + formats_(p->formats, p->formats + p->count_formats) { } int DrmPlane::Init() { @@ -153,6 +156,11 @@ uint32_t DrmPlane::type() const { return type_; } +bool DrmPlane::IsFormatSupported(uint32_t format) const { + return std::find(std::begin(formats_), std::end(formats_), format) != + std::end(formats_); +} + const DrmProperty &DrmPlane::crtc_property() const { return crtc_property_; } diff --git a/drm/DrmPlane.h b/drm/DrmPlane.h index d2f0601..16731a8 100644 --- a/drm/DrmPlane.h +++ b/drm/DrmPlane.h @@ -43,6 +43,8 @@ class DrmPlane { uint32_t type() const; + bool IsFormatSupported(uint32_t format) const; + const DrmProperty &crtc_property() const; const DrmProperty &fb_property() const; const DrmProperty &crtc_x_property() const; @@ -67,6 +69,8 @@ class DrmPlane { uint32_t type_; + std::vector formats_; + DrmProperty crtc_property_; DrmProperty fb_property_; DrmProperty crtc_x_property_; -- cgit v1.2.3 From 15a453aae5294567e0609f63e35f767c06773219 Mon Sep 17 00:00:00 2001 From: Roman Kovalivskyi Date: Thu, 10 Sep 2020 12:07:37 +0300 Subject: drm_hwcomposer: Add check for format support during plane validation Some layers have pixel format that aren't supported by a hardware. In such case it is better to reject plane that doesn't supports such format, so we could handle it in future, rather than accepting it, passing to the kernel side and failing whole composition. Signed-off-by: Roman Kovalivskyi --- platform/platform.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/platform/platform.cpp b/platform/platform.cpp index 479e79e..a500398 100644 --- a/platform/platform.cpp +++ b/platform/platform.cpp @@ -78,6 +78,13 @@ int Planner::PlanStage::ValidatePlane(DrmPlane *plane, DrmHwcLayer *layer) { ALOGE("Expected a valid blend mode on plane %d", plane->id()); } + uint32_t format = layer->buffer->format; + if (!plane->IsFormatSupported(format)) { + ALOGE("Plane %d does not supports %c%c%c%c format", plane->id(), format, + format >> 8, format >> 16, format >> 24); + return -EINVAL; + } + return ret; } -- cgit v1.2.3 From acdea8cf93b1e91e48fd1788c220e483310a53bd Mon Sep 17 00:00:00 2001 From: Roman Stratiienko Date: Wed, 23 Sep 2020 11:51:12 +0300 Subject: drm_hwcomposer: fix build error after fbf5c0ca45b3 'warning' preprocessor directive is interpreted as build error. Replace it with ALOGW. Fixes: fbf5c0ca45b3 ("drm_hwcomposer: libdrm gralloc_handle: modifiers and YUV support") Signed-off-by: Roman Stratiienko --- platform/platformdrmgeneric.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/platform/platformdrmgeneric.cpp b/platform/platformdrmgeneric.cpp index ed3a68c..95a1eac 100644 --- a/platform/platformdrmgeneric.cpp +++ b/platform/platformdrmgeneric.cpp @@ -238,7 +238,11 @@ int DrmGenericImporter::ConvertBoInfo(buffer_handle_t handle, bo->hal_format = gr_handle->format; #if GRALLOC_HANDLE_VERSION < 4 -#warning libdrm >= v2.4.97 is required to support modifiers + static std::once_flag once; + std::call_once(once, []() { + ALOGE( + "libdrm < v2.4.97 has broken gralloc_handle structure. Please update."); + }); #endif #if GRALLOC_HANDLE_VERSION == 4 bo->modifiers[0] = gr_handle->modifier; -- cgit v1.2.3 From 25ddbc44acfbe6d53439deb68e0f92b5809b5738 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Sat, 19 Sep 2020 12:12:03 +0200 Subject: drm_hwcomposer: Return error from GetEdidBlob if blob is null drmModeGetPropertyBlob can return NULL blobs resulting in a segfault in GetDisplayIdentificationData which expects blob to be set to a valid pointer when GetEdidBlob returns 0. Fixes: adc5d8229b9ce25f1bf0e4d02bb838eae62b89fc Signed-off-by: Marijn Suijten --- drm/DrmConnector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drm/DrmConnector.cpp b/drm/DrmConnector.cpp index 0de0f91..f1b6c1b 100644 --- a/drm/DrmConnector.cpp +++ b/drm/DrmConnector.cpp @@ -103,7 +103,7 @@ int DrmConnector::GetEdidBlob(drmModePropertyBlobPtr &blob) { } blob = drmModeGetPropertyBlob(drm_->fd(), blob_id); - return 0; + return !blob; } uint32_t DrmConnector::id() const { -- cgit v1.2.3