drm_hwcomposer: Connect ComposerClient with HwcDisplay
Implements the HWC3 frontend by calling the HWC2 interfaces already
exposed through DrmHwc, HwcDisplay, HwcLayer, and so on.
Convert between hwc2 types and hwc3 types in ComposerClient.
The following changes from !238 were used as a basis for this change,
and squashed together:
(drm_hwcomposer: Connect ComposerClient with HwcDisplay)
(drm_hwcomposer: Implement HWC3 frontend by calling down to HWC2)
The projects [1, 2] were used as a reference for the implementation.
[1]: https://android.googlesource.com/platform/hardware/google/graphics/common/+/refs/heads/main/hwc3/
[2]: https://android.googlesource.com/device/generic/goldfish-opengl/+/refs/heads/master/system/hwc3/
Co-authored-by: Normunds Rieksts <normunds.rieksts@arm.com>
Co-authored-by: Dennis Tsiang <dennis.tsiang@arm.com>
Change-Id: I98c10175d5c5f01aec1e192863238e16aa1537ec
Signed-off-by: Drew Davenport <ddavenport@chromium.org>
Signed-off-by: Drew Davenport <ddavenport@google.com>
diff --git a/Android.bp b/Android.bp
index b25ef36..5620503 100644
--- a/Android.bp
+++ b/Android.bp
@@ -25,6 +25,8 @@
name: "hwcomposer.drm_defaults",
shared_libs: [
+ "android.hardware.graphics.composer@2.1-resources",
+ "android.hardware.graphics.composer@2.2-resources",
"libcutils",
"libdrm",
"libhardware",
@@ -35,7 +37,13 @@
"libutils",
],
- header_libs: ["drm_hwcomposer_headers"],
+ static_libs: [
+ "libaidlcommonsupport",
+ ],
+
+ header_libs: [
+ "drm_hwcomposer_headers",
+ ],
cflags: [
"-Wall",
@@ -99,6 +107,9 @@
srcs: [
"hwc3/Composer.cpp",
"hwc3/ComposerClient.cpp",
+ "hwc3/ComposerResources.cpp",
+ "hwc3/DrmHwcThree.cpp",
+ "hwc3/Utils.cpp",
"hwc3/DrmHwcThree.cpp",
],
}
diff --git a/drm/ResourceManager.h b/drm/ResourceManager.h
index 20e84a9..dea61d6 100644
--- a/drm/ResourceManager.h
+++ b/drm/ResourceManager.h
@@ -34,9 +34,9 @@
class PipelineToFrontendBindingInterface {
public:
virtual ~PipelineToFrontendBindingInterface() = default;
- virtual bool BindDisplay(std::shared_ptr<DrmDisplayPipeline>);
- virtual bool UnbindDisplay(std::shared_ptr<DrmDisplayPipeline>);
- virtual void FinalizeDisplayBinding();
+ virtual bool BindDisplay(std::shared_ptr<DrmDisplayPipeline>) = 0;
+ virtual bool UnbindDisplay(std::shared_ptr<DrmDisplayPipeline>) = 0;
+ virtual void FinalizeDisplayBinding() = 0;
};
class ResourceManager {
diff --git a/hwc3/CommandResultWriter.h b/hwc3/CommandResultWriter.h
new file mode 100644
index 0000000..fa96f33
--- /dev/null
+++ b/hwc3/CommandResultWriter.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2024 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 <unordered_map>
+#include <vector>
+
+#include "Utils.h"
+#include "aidl/android/hardware/graphics/composer3/CommandError.h"
+#include "aidl/android/hardware/graphics/composer3/CommandResultPayload.h"
+#include "aidl/android/hardware/graphics/composer3/PresentFence.h"
+#include "aidl/android/hardware/graphics/composer3/PresentOrValidate.h"
+#include "aidl/android/hardware/graphics/composer3/ReleaseFences.h"
+
+namespace aidl::android::hardware::graphics::composer3 {
+
+struct DisplayChanges {
+ std::optional<ChangedCompositionTypes> composition_changes;
+ std::optional<DisplayRequest> display_request_changes;
+
+ void AddLayerCompositionChange(int64_t display_id, int64_t layer_id,
+ Composition layer_composition) {
+ if (!composition_changes) {
+ composition_changes.emplace();
+ composition_changes->display = display_id;
+ }
+
+ ChangedCompositionLayer composition_change;
+ composition_change.layer = layer_id;
+ composition_change.composition = layer_composition;
+ composition_changes->layers.emplace_back(composition_change);
+ }
+
+ void ClearLayerCompositionChanges() {
+ composition_changes.reset();
+ }
+
+ bool HasAnyChanges() const {
+ return composition_changes.has_value() ||
+ display_request_changes.has_value();
+ }
+
+ void Reset() {
+ composition_changes.reset();
+ display_request_changes.reset();
+ }
+};
+
+class CommandResultWriter {
+ public:
+ explicit CommandResultWriter(std::vector<CommandResultPayload>* results)
+ : results_(results) {
+ }
+
+ bool HasError() const {
+ return has_error_;
+ }
+
+ void IncrementCommand() {
+ index_++;
+ has_error_ = false;
+ }
+
+ void AddError(hwc3::Error error) {
+ CommandError command_error;
+ command_error.errorCode = static_cast<int32_t>(error);
+ command_error.commandIndex = static_cast<int32_t>(index_);
+
+ results_->emplace_back(command_error);
+ has_error_ = true;
+ }
+
+ void AddPresentFence(int64_t display_id, ::android::base::unique_fd fence) {
+ if (!fence.ok()) {
+ return;
+ }
+
+ PresentFence present_fence;
+ present_fence.fence = ::ndk::ScopedFileDescriptor(fence.release());
+ present_fence.display = display_id;
+ results_->emplace_back(std::move(present_fence));
+ }
+
+ void AddReleaseFence(
+ int64_t display_id,
+ std::unordered_map<int64_t, ::android::base::unique_fd>& layer_fences) {
+ ReleaseFences release_fences;
+ release_fences.display = display_id;
+ for (auto& [layer, fence] : layer_fences) {
+ if (!fence.ok()) {
+ continue;
+ }
+
+ ReleaseFences::Layer layer_result;
+ layer_result.layer = layer;
+ layer_result.fence = ::ndk::ScopedFileDescriptor(fence.release());
+
+ release_fences.layers.emplace_back(std::move(layer_result));
+ }
+
+ results_->emplace_back(std::move(release_fences));
+ }
+
+ void AddChanges(const DisplayChanges& changes) {
+ if (changes.composition_changes) {
+ results_->emplace_back(*changes.composition_changes);
+ }
+ if (changes.display_request_changes) {
+ results_->emplace_back(*changes.display_request_changes);
+ }
+ }
+
+ void AddPresentOrValidateResult(int64_t display_id,
+ const PresentOrValidate::Result& pov_result) {
+ PresentOrValidate pov_command;
+ pov_command.display = display_id;
+ pov_command.result = pov_result;
+
+ results_->emplace_back(pov_command);
+ }
+
+ private:
+ size_t index_{0};
+ bool has_error_{false};
+ std::vector<CommandResultPayload>* results_{nullptr};
+};
+}; // namespace aidl::android::hardware::graphics::composer3
\ No newline at end of file
diff --git a/hwc3/Composer.cpp b/hwc3/Composer.cpp
index 5f90797..2494488 100644
--- a/hwc3/Composer.cpp
+++ b/hwc3/Composer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#define LOG_TAG "drmhwc"
#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
#include "Composer.h"
@@ -21,38 +22,51 @@
#include <android-base/logging.h>
#include <android/binder_ibinder_platform.h>
+#include "hwc3/ComposerClient.h"
+#include "hwc3/Utils.h"
#include "utils/log.h"
namespace aidl::android::hardware::graphics::composer3::impl {
-// NOLINTNEXTLINE
-#define DEBUG_FUNC() ALOGV("%s", __func__)
-
ndk::ScopedAStatus Composer::createClient(
std::shared_ptr<IComposerClient>* out_client) {
DEBUG_FUNC();
auto client = ndk::SharedRefBase::make<ComposerClient>();
- if (!client) {
+ if (!client || !client->Init()) {
*out_client = nullptr;
- return ndk::ScopedAStatus::fromServiceSpecificError(EX_NO_RESOURCES);
+ return ToBinderStatus(hwc3::Error::kNoResources);
}
*out_client = client;
+ client_ = client;
return ndk::ScopedAStatus::ok();
}
binder_status_t Composer::dump(int fd, const char** /*args*/,
uint32_t /*numArgs*/) {
- auto output = std::string("hwc3-drm");
- write(fd, output.c_str(), output.size());
+ std::stringstream output;
+ output << "hwc3-drm\n\n";
+
+ auto client_instance = client_.lock();
+ if (!client_instance) {
+ return STATUS_OK;
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast)
+ auto* client = static_cast<ComposerClient*>(client_instance.get());
+ output << client->Dump();
+
+ auto output_str = output.str();
+ write(fd, output_str.c_str(), output_str.size());
return STATUS_OK;
}
-ndk::ScopedAStatus Composer::getCapabilities(
- std::vector<Capability>* /*caps*/) {
+ndk::ScopedAStatus Composer::getCapabilities(std::vector<Capability>* caps) {
DEBUG_FUNC();
+ /* No capabilities advertised */
+ caps->clear();
return ndk::ScopedAStatus::ok();
}
diff --git a/hwc3/Composer.h b/hwc3/Composer.h
index b29d0cf..f6c2536 100644
--- a/hwc3/Composer.h
+++ b/hwc3/Composer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -19,7 +19,7 @@
#include <aidl/android/hardware/graphics/composer3/BnComposer.h>
#include <utils/Mutex.h>
-#include "ComposerClient.h"
+#include <memory>
namespace aidl::android::hardware::graphics::composer3::impl {
@@ -36,6 +36,9 @@
protected:
::ndk::SpAIBinder createBinder() override;
+
+ private:
+ std::weak_ptr<IComposerClient> client_;
};
} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/hwc3/ComposerClient.cpp b/hwc3/ComposerClient.cpp
index 9ebba31..6c03722 100644
--- a/hwc3/ComposerClient.cpp
+++ b/hwc3/ComposerClient.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -14,283 +14,910 @@
* limitations under the License.
*/
+#define LOG_TAG "drmhwc"
#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
#include "ComposerClient.h"
+#include <aidlcommonsupport/NativeHandle.h>
#include <android-base/logging.h>
#include <android/binder_ibinder_platform.h>
+#include <hardware/hwcomposer2.h>
+
+#include <cinttypes>
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "aidl/android/hardware/graphics/common/Transform.h"
+#include "aidl/android/hardware/graphics/composer3/ClientTarget.h"
+#include "aidl/android/hardware/graphics/composer3/Composition.h"
+#include "aidl/android/hardware/graphics/composer3/DisplayRequest.h"
+#include "aidl/android/hardware/graphics/composer3/IComposerClient.h"
+#include "aidl/android/hardware/graphics/composer3/PowerMode.h"
+#include "aidl/android/hardware/graphics/composer3/PresentOrValidate.h"
+#include "aidl/android/hardware/graphics/composer3/RenderIntent.h"
+#include "android/binder_auto_utils.h"
+#include "cutils/native_handle.h"
+#include "hardware/hwcomposer_defs.h"
+#include "hwc2_device/HwcDisplay.h"
+#include "hwc2_device/HwcLayer.h"
+#include "hwc3/DrmHwcThree.h"
+#include "hwc3/Utils.h"
+
+using ::android::HwcDisplay;
#include "utils/log.h"
namespace aidl::android::hardware::graphics::composer3::impl {
+namespace {
-// NOLINTNEXTLINE
-#define DEBUG_FUNC() ALOGV("%s", __func__)
+// clang-format off
+constexpr std::array<float, 16> kIdentityMatrix = {
+ 1.0F, 0.0F, 0.0F, 0.0F,
+ 0.0F, 1.0F, 0.0F, 0.0F,
+ 0.0F, 0.0F, 1.0F, 0.0F,
+ 0.0F, 0.0F, 0.0F, 1.0F,
+};
+// clang-format on
+} // namespace
+
+ComposerClient::ComposerClient() {
+ DEBUG_FUNC();
+}
+
+bool ComposerClient::Init() {
+ DEBUG_FUNC();
+ composer_resources_ = ComposerResources::Create();
+ if (composer_resources_) {
+ hwc_ = std::make_unique<DrmHwcThree>(composer_resources_.get());
+ }
+ return composer_resources_ != nullptr;
+}
+
+// NOLINTNEXTLINE(bugprone-exception-escape)
ComposerClient::~ComposerClient() {
DEBUG_FUNC();
-
LOG(DEBUG) << "removed composer client";
}
-// no need to check nullptr for output parameter, the aidl stub code won't pass
-// nullptr
-ndk::ScopedAStatus ComposerClient::createLayer(int64_t /*display*/,
- int32_t /*bufferSlotCount*/,
- int64_t* /*layer*/) {
+ndk::ScopedAStatus ComposerClient::createLayer(int64_t display_id,
+ int32_t buffer_slot_count,
+ int64_t* layer_id) {
DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ hwc2_layer_t hwc2_layer_id = 0;
+ auto err = Hwc2toHwc3Error(display->CreateLayer(&hwc2_layer_id));
+ if (err != hwc3::Error::kNone) {
+ return ToBinderStatus(err);
+ }
+
+ const int64_t created_layer_id = Hwc2LayerToHwc3(hwc2_layer_id);
+ err = composer_resources_->AddLayer(display_id, created_layer_id,
+ buffer_slot_count);
+ if (err != hwc3::Error::kNone) {
+ destroyLayer(display_id, created_layer_id);
+ return ToBinderStatus(err);
+ }
+
+ *layer_id = created_layer_id;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus ComposerClient::createVirtualDisplay(
- int32_t /*width*/, int32_t /*height*/, AidlPixelFormat /*formatHint*/,
- int32_t /*outputBufferSlotCount*/, VirtualDisplay* /*display*/) {
+ int32_t width, int32_t height, AidlPixelFormat format_hint,
+ int32_t output_buffer_slot_count, VirtualDisplay* out_display) {
DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+
+ hwc2_display_t hwc2_display_id = 0;
+ // TODO: Format is currently not used in drm_hwcomposer.
+ int32_t hwc2_format = 0;
+ auto err = Hwc2toHwc3Error(hwc_->CreateVirtualDisplay(width, height,
+ &hwc2_format,
+ &hwc2_display_id));
+ if (err != hwc3::Error::kNone) {
+ return ToBinderStatus(err);
+ }
+
+ const int64_t created_display_id = Hwc2DisplayToHwc3(hwc2_display_id);
+ err = composer_resources_->AddVirtualDisplay(hwc2_display_id,
+ output_buffer_slot_count);
+ if (err != hwc3::Error::kNone) {
+ hwc_->DestroyVirtualDisplay(hwc2_display_id);
+ return ToBinderStatus(err);
+ }
+
+ out_display->display = created_display_id;
+ out_display->format = format_hint;
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus ComposerClient::destroyLayer(int64_t /*display*/,
- int64_t /*layer*/) {
+ndk::ScopedAStatus ComposerClient::destroyLayer(int64_t display_id,
+ int64_t layer_id) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ auto err = Hwc2toHwc3Error(display->DestroyLayer(Hwc3LayerToHwc2(layer_id)));
+ if (err != hwc3::Error::kNone) {
+ return ToBinderStatus(err);
+ }
+
+ err = composer_resources_->RemoveLayer(display_id, layer_id);
+ return ToBinderStatus(err);
}
-ndk::ScopedAStatus ComposerClient::destroyVirtualDisplay(int64_t /*display*/) {
+ndk::ScopedAStatus ComposerClient::destroyVirtualDisplay(int64_t display_id) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ auto err = Hwc2toHwc3Error(hwc_->DestroyVirtualDisplay(display_id));
+ return ToBinderStatus(err);
+}
+
+hwc3::Error ComposerClient::ValidateDisplayInternal(
+ HwcDisplay& display, std::vector<int64_t>* out_changed_layers,
+ std::vector<Composition>* out_composition_types,
+ int32_t* out_display_request_mask,
+ std::vector<int64_t>* out_requested_layers,
+ std::vector<int32_t>* out_request_masks,
+ ClientTargetProperty* /*out_client_target_property*/,
+ DimmingStage* /*out_dimming_stage*/) {
+ DEBUG_FUNC();
+
+ uint32_t num_types = 0;
+ uint32_t num_requests = 0;
+ const HWC2::Error hwc2_error = display.ValidateDisplay(&num_types,
+ &num_requests);
+
+ /* Check if display has pending changes and no errors */
+ if (hwc2_error != HWC2::Error::None &&
+ hwc2_error != HWC2::Error::HasChanges) {
+ return Hwc2toHwc3Error(hwc2_error);
+ }
+
+ std::vector<hwc2_layer_t> hwc_changed_layers(num_types);
+ std::vector<int32_t> hwc_composition_types(num_types);
+ hwc3::Error error = Hwc2toHwc3Error(
+ display.GetChangedCompositionTypes(&num_types, hwc_changed_layers.data(),
+ hwc_composition_types.data()));
+ if (error != hwc3::Error::kNone) {
+ return error;
+ }
+
+ int32_t display_reqs = 0;
+ out_request_masks->resize(num_requests);
+ std::vector<hwc2_layer_t> hwc_requested_layers(num_requests);
+ error = Hwc2toHwc3Error(
+ display.GetDisplayRequests(&display_reqs, &num_requests,
+ hwc_requested_layers.data(),
+ out_request_masks->data()));
+ if (error != hwc3::Error::kNone) {
+ return error;
+ }
+
+ for (const auto& layer : hwc_changed_layers) {
+ out_changed_layers->emplace_back(Hwc2LayerToHwc3(layer));
+ }
+ for (const auto& type : hwc_composition_types) {
+ out_composition_types->emplace_back(Hwc2CompositionTypeToHwc3(type));
+ }
+ for (const auto& layer : hwc_requested_layers) {
+ out_requested_layers->emplace_back(Hwc2LayerToHwc3(layer));
+ }
+ *out_display_request_mask = display_reqs;
+
+ /* Client target property/dimming stage unsupported */
+ return hwc3::Error::kNone;
+}
+
+hwc3::Error ComposerClient::PresentDisplayInternal(
+ uint64_t display_id, ::android::base::unique_fd& out_display_fence,
+ std::unordered_map<int64_t, ::android::base::unique_fd>&
+ out_release_fences) {
+ DEBUG_FUNC();
+ auto* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return hwc3::Error::kBadDisplay;
+ }
+
+ if (composer_resources_->MustValidateDisplay(display_id)) {
+ return hwc3::Error::kNotValidated;
+ }
+
+ int32_t present_fence = -1;
+ auto error = Hwc2toHwc3Error(display->PresentDisplay(&present_fence));
+ if (error != hwc3::Error::kNone) {
+ return error;
+ }
+ out_display_fence.reset(present_fence);
+
+ uint32_t release_fence_count = 0;
+ error = Hwc2toHwc3Error(
+ display->GetReleaseFences(&release_fence_count, nullptr, nullptr));
+ if (error != hwc3::Error::kNone) {
+ return error;
+ }
+
+ std::vector<hwc2_layer_t> hwc_layers(release_fence_count);
+ std::vector<int32_t> hwc_fences(release_fence_count);
+ error = Hwc2toHwc3Error(display->GetReleaseFences(&release_fence_count,
+ hwc_layers.data(),
+ hwc_fences.data()));
+ if (error != hwc3::Error::kNone) {
+ return error;
+ }
+
+ for (size_t i = 0; i < hwc_layers.size(); i++) {
+ auto layer = Hwc2LayerToHwc3(hwc_layers[i]);
+ out_release_fences[layer] = ::android::base::unique_fd{hwc_fences[i]};
+ }
+
+ return hwc3::Error::kNone;
+}
+
+::android::HwcDisplay* ComposerClient::GetDisplay(uint64_t display_id) {
+ return hwc_->GetDisplay(display_id);
+}
+
+void ComposerClient::DispatchLayerCommand(int64_t display_id,
+ const LayerCommand& command) {
+ auto* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
+ return;
+ }
+
+ auto* layer = display->get_layer(command.layer);
+ if (layer == nullptr) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadLayer);
+ return;
+ }
+
+ HwcLayerWrapper layer_wrapper{command.layer, layer};
+ if (command.buffer) {
+ ExecuteSetLayerBuffer(display_id, layer_wrapper, *command.buffer);
+ }
+ if (command.blendMode) {
+ ExecuteSetLayerBlendMode(display_id, layer_wrapper, *command.blendMode);
+ }
+ if (command.composition) {
+ ExecuteSetLayerComposition(display_id, layer_wrapper, *command.composition);
+ }
+ if (command.dataspace) {
+ ExecuteSetLayerDataspace(display_id, layer_wrapper, *command.dataspace);
+ }
+ if (command.displayFrame) {
+ ExecuteSetLayerDisplayFrame(display_id, layer_wrapper,
+ *command.displayFrame);
+ }
+ if (command.planeAlpha) {
+ ExecuteSetLayerPlaneAlpha(display_id, layer_wrapper, *command.planeAlpha);
+ }
+ if (command.sourceCrop) {
+ ExecuteSetLayerSourceCrop(display_id, layer_wrapper, *command.sourceCrop);
+ }
+ if (command.transform) {
+ ExecuteSetLayerTransform(display_id, layer_wrapper, *command.transform);
+ }
+ if (command.z) {
+ ExecuteSetLayerZOrder(display_id, layer_wrapper, *command.z);
+ }
+ if (command.brightness) {
+ ExecuteSetLayerBrightness(display_id, layer_wrapper, *command.brightness);
+ }
+
+ // Some unsupported functionality returns kUnsupported, and others
+ // are just a no-op.
+ // TODO: Audit whether some of these should actually return kUnsupported
+ // instead.
+ if (command.sidebandStream) {
+ cmd_result_writer_->AddError(hwc3::Error::kUnsupported);
+ }
+ // TODO: Blocking region handling missing.
+ // TODO: Layer surface damage.
+ // TODO: Layer visible region.
+ // TODO: Per-frame metadata.
+ // TODO: Layer color transform.
+ // TODO: Layer cursor position.
+ // TODO: Layer color.
+}
+
+void ComposerClient::ExecuteDisplayCommand(const DisplayCommand& command) {
+ const int64_t display_id = command.display;
+ if (hwc_->GetDisplay(display_id) == nullptr) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
+ return;
+ }
+
+ for (const auto& layer_cmd : command.layers) {
+ DispatchLayerCommand(command.display, layer_cmd);
+ }
+
+ if (command.brightness) {
+ ExecuteSetDisplayBrightness(command.display, *command.brightness);
+ }
+ if (command.colorTransformMatrix) {
+ ExecuteSetDisplayColorTransform(command.display,
+ *command.colorTransformMatrix);
+ }
+ if (command.clientTarget) {
+ ExecuteSetDisplayClientTarget(command.display, *command.clientTarget);
+ }
+ if (command.virtualDisplayOutputBuffer) {
+ ExecuteSetDisplayOutputBuffer(command.display,
+ *command.virtualDisplayOutputBuffer);
+ }
+ if (command.validateDisplay) {
+ ExecuteValidateDisplay(command.display, command.expectedPresentTime);
+ }
+ if (command.acceptDisplayChanges) {
+ ExecuteAcceptDisplayChanges(command.display);
+ }
+ if (command.presentDisplay) {
+ ExecutePresentDisplay(command.display);
+ }
+ if (command.presentOrValidateDisplay) {
+ ExecutePresentOrValidateDisplay(command.display,
+ command.expectedPresentTime);
+ }
}
ndk::ScopedAStatus ComposerClient::executeCommands(
- const std::vector<DisplayCommand>& /*commands*/,
- std::vector<CommandResultPayload>* /*results*/) {
- DEBUG_FUNC();
+ const std::vector<DisplayCommand>& commands,
+ std::vector<CommandResultPayload>* results) {
+ cmd_result_writer_ = std::make_unique<CommandResultWriter>(results);
+ for (const auto& cmd : commands) {
+ ExecuteDisplayCommand(cmd);
+ cmd_result_writer_->IncrementCommand();
+ }
+ cmd_result_writer_.reset();
+
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus ComposerClient::getActiveConfig(int64_t /*display*/,
- int32_t* /*config*/) {
+ndk::ScopedAStatus ComposerClient::getActiveConfig(int64_t display_id,
+ int32_t* config) {
DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ uint32_t hwc2_config = 0;
+ const hwc3::Error error = Hwc2toHwc3Error(
+ display->GetActiveConfig(&hwc2_config));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+ *config = Hwc2ConfigIdToHwc3(hwc2_config);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus ComposerClient::getColorModes(
- int64_t /*display*/, std::vector<ColorMode>* /*colorModes*/) {
+ int64_t display_id, std::vector<ColorMode>* color_modes) {
DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ uint32_t num_modes = 0;
+ auto error = Hwc2toHwc3Error(display->GetColorModes(&num_modes, nullptr));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ std::vector<int32_t> hwc2_color_modes(num_modes);
+ error = Hwc2toHwc3Error(
+ display->GetColorModes(&num_modes, hwc2_color_modes.data()));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ for (const auto& mode : hwc2_color_modes) {
+ color_modes->push_back(Hwc2ColorModeToHwc3(mode));
+ }
+
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus ComposerClient::getDataspaceSaturationMatrix(
- common::Dataspace /*dataspace*/, std::vector<float>* /*matrix*/) {
+ common::Dataspace dataspace, std::vector<float>* matrix) {
DEBUG_FUNC();
+ if (dataspace != common::Dataspace::SRGB_LINEAR) {
+ return ToBinderStatus(hwc3::Error::kBadParameter);
+ }
+
+ matrix->clear();
+ matrix->insert(matrix->begin(), kIdentityMatrix.begin(),
+ kIdentityMatrix.end());
+
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus ComposerClient::getDisplayAttribute(
- int64_t /*display*/, int32_t /*config*/, DisplayAttribute /*attribute*/,
- int32_t* /*value*/) {
+ int64_t display_id, int32_t config, DisplayAttribute attribute,
+ int32_t* value) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ const hwc3::Error error = Hwc2toHwc3Error(
+ display->GetDisplayAttribute(Hwc3ConfigIdToHwc2(config),
+ Hwc3DisplayAttributeToHwc2(attribute),
+ value));
+ return ToBinderStatus(error);
}
ndk::ScopedAStatus ComposerClient::getDisplayCapabilities(
- int64_t /*display*/, std::vector<DisplayCapability>* /*caps*/) {
+ int64_t display_id, std::vector<DisplayCapability>* caps) {
DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+ uint32_t num_capabilities = 0;
+ hwc3::Error error = Hwc2toHwc3Error(
+ display->GetDisplayCapabilities(&num_capabilities, nullptr));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ std::vector<uint32_t> out_caps(num_capabilities);
+ error = Hwc2toHwc3Error(
+ display->GetDisplayCapabilities(&num_capabilities, out_caps.data()));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ caps->reserve(num_capabilities);
+ for (const auto cap : out_caps) {
+ caps->emplace_back(Hwc2DisplayCapabilityToHwc3(cap));
+ }
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus ComposerClient::getDisplayConfigs(
- int64_t /*display*/, std::vector<int32_t>* /*configs*/) {
+ int64_t display_id, std::vector<int32_t>* configs) {
DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ uint32_t num_configs = 0;
+ hwc3::Error error = Hwc2toHwc3Error(
+ display->GetDisplayConfigs(&num_configs, nullptr));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ std::vector<hwc2_config_t> out_configs(num_configs);
+ error = Hwc2toHwc3Error(
+ display->GetDisplayConfigs(&num_configs, out_configs.data()));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ configs->reserve(num_configs);
+ for (const auto config : out_configs) {
+ configs->emplace_back(Hwc2ConfigIdToHwc3(config));
+ }
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus ComposerClient::getDisplayConnectionType(
- int64_t /*display*/, DisplayConnectionType* /*type*/) {
+ int64_t display_id, DisplayConnectionType* type) {
DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ uint32_t out_type = 0;
+ const hwc3::Error error = Hwc2toHwc3Error(
+ display->GetDisplayConnectionType(&out_type));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ *type = Hwc2DisplayConnectionTypeToHwc3(out_type);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus ComposerClient::getDisplayIdentificationData(
- int64_t /*display*/, DisplayIdentification* /*id*/) {
+ int64_t display_id, DisplayIdentification* id) {
DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ uint8_t port = 0;
+ uint32_t data_size = 0;
+ hwc3::Error error = Hwc2toHwc3Error(
+ display->GetDisplayIdentificationData(&port, &data_size, nullptr));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ id->data.resize(data_size);
+ error = Hwc2toHwc3Error(
+ display->GetDisplayIdentificationData(&port, &data_size,
+ id->data.data()));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ id->port = static_cast<int8_t>(port);
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus ComposerClient::getDisplayName(int64_t /*display*/,
- std::string* /*name*/) {
+ndk::ScopedAStatus ComposerClient::getDisplayName(int64_t display_id,
+ std::string* name) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ uint32_t size = 0;
+ auto error = Hwc2toHwc3Error(display->GetDisplayName(&size, nullptr));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ name->resize(size);
+ error = Hwc2toHwc3Error(display->GetDisplayName(&size, name->data()));
+ return ToBinderStatus(error);
}
ndk::ScopedAStatus ComposerClient::getDisplayVsyncPeriod(
- int64_t /*display*/, int32_t* /*vsyncPeriod*/) {
+ int64_t display_id, int32_t* vsync_period) {
DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ uint32_t hwc2_vsync_period = 0;
+ auto error = Hwc2toHwc3Error(
+ display->GetDisplayVsyncPeriod(&hwc2_vsync_period));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ *vsync_period = static_cast<int32_t>(hwc2_vsync_period);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus ComposerClient::getDisplayedContentSample(
- int64_t /*display*/, int64_t /*maxFrames*/, int64_t /*timestamp*/,
+ int64_t /*display_id*/, int64_t /*max_frames*/, int64_t /*timestamp*/,
DisplayContentSample* /*samples*/) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
}
ndk::ScopedAStatus ComposerClient::getDisplayedContentSamplingAttributes(
- int64_t /*display*/, DisplayContentSamplingAttributes* /*attrs*/) {
+ int64_t /*display_id*/, DisplayContentSamplingAttributes* /*attrs*/) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
}
ndk::ScopedAStatus ComposerClient::getDisplayPhysicalOrientation(
- int64_t /*display*/, common::Transform* /*orientation*/) {
+ int64_t display_id, common::Transform* orientation) {
DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ *orientation = common::Transform::NONE;
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus ComposerClient::getHdrCapabilities(
- int64_t /*display*/, HdrCapabilities* /*caps*/) {
+ndk::ScopedAStatus ComposerClient::getHdrCapabilities(int64_t display_id,
+ HdrCapabilities* caps) {
DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ /* No HDR capabilities */
+ caps->types.clear();
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus ComposerClient::getMaxVirtualDisplayCount(
- int32_t* /*count*/) {
+ndk::ScopedAStatus ComposerClient::getMaxVirtualDisplayCount(int32_t* count) {
DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ *count = static_cast<int32_t>(hwc_->GetMaxVirtualDisplayCount());
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus ComposerClient::getPerFrameMetadataKeys(
- int64_t /*display*/, std::vector<PerFrameMetadataKey>* /*keys*/) {
+ int64_t /*display_id*/, std::vector<PerFrameMetadataKey>* /*keys*/) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
}
ndk::ScopedAStatus ComposerClient::getReadbackBufferAttributes(
- int64_t /*display*/, ReadbackBufferAttributes* /*attrs*/) {
+ int64_t /*display_id*/, ReadbackBufferAttributes* /*attrs*/) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
}
ndk::ScopedAStatus ComposerClient::getReadbackBufferFence(
- int64_t /*display*/, ndk::ScopedFileDescriptor* /*acquireFence*/) {
+ int64_t /*display_id*/, ndk::ScopedFileDescriptor* /*acquireFence*/) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
}
ndk::ScopedAStatus ComposerClient::getRenderIntents(
- int64_t /*display*/, ColorMode /*mode*/,
- std::vector<RenderIntent>* /*intents*/) {
+ int64_t display_id, ColorMode mode, std::vector<RenderIntent>* intents) {
DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ const int32_t hwc2_color_mode = Hwc3ColorModeToHwc2(mode);
+ uint32_t out_num_intents = 0;
+ auto error = Hwc2toHwc3Error(
+ display->GetRenderIntents(hwc2_color_mode, &out_num_intents, nullptr));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ std::vector<int32_t> out_intents(out_num_intents);
+ error = Hwc2toHwc3Error(display->GetRenderIntents(hwc2_color_mode,
+ &out_num_intents,
+ out_intents.data()));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ intents->reserve(out_num_intents);
+ for (const auto intent : out_intents) {
+ intents->emplace_back(Hwc2RenderIntentToHwc3(intent));
+ }
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus ComposerClient::getSupportedContentTypes(
- int64_t /*display*/, std::vector<ContentType>* /*types*/) {
+ int64_t display_id, std::vector<ContentType>* types) {
DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ uint32_t out_num_supported_types = 0;
+ auto error = Hwc2toHwc3Error(
+ display->GetSupportedContentTypes(&out_num_supported_types, nullptr));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ std::vector<uint32_t> out_supported_types(out_num_supported_types);
+ error = Hwc2toHwc3Error(
+ display->GetSupportedContentTypes(&out_num_supported_types,
+ out_supported_types.data()));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ for (const auto type : out_supported_types) {
+ types->push_back(Hwc2ContentTypeToHwc3(type));
+ }
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus ComposerClient::getDisplayDecorationSupport(
- int64_t /*display*/,
- std::optional<common::DisplayDecorationSupport>* /*supportStruct*/) {
+ int64_t /*display_id*/,
+ std::optional<common::DisplayDecorationSupport>* /*support_struct*/) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
}
ndk::ScopedAStatus ComposerClient::registerCallback(
- const std::shared_ptr<IComposerCallback>& /*callback*/) {
+ const std::shared_ptr<IComposerCallback>& callback) {
DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ // This function is specified to be called exactly once.
+ hwc_->Init(callback);
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus ComposerClient::setActiveConfig(int64_t /*display*/,
- int32_t /*config*/) {
+ndk::ScopedAStatus ComposerClient::setActiveConfig(int64_t display_id,
+ int32_t config) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ return ToBinderStatus(Hwc2toHwc3Error(display->SetActiveConfig(config)));
}
ndk::ScopedAStatus ComposerClient::setActiveConfigWithConstraints(
- int64_t /*display*/, int32_t /*config*/,
- const VsyncPeriodChangeConstraints& /*constraints*/,
- VsyncPeriodChangeTimeline* /*timeline*/) {
+ int64_t display_id, int32_t config,
+ const VsyncPeriodChangeConstraints& constraints,
+ VsyncPeriodChangeTimeline* timeline) {
DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ hwc_vsync_period_change_constraints_t hwc2_constraints;
+ hwc2_constraints.desiredTimeNanos = constraints.desiredTimeNanos;
+ hwc2_constraints.seamlessRequired = static_cast<uint8_t>(
+ constraints.seamlessRequired);
+
+ hwc_vsync_period_change_timeline_t hwc2_timeline{};
+ auto error = Hwc2toHwc3Error(
+ display->SetActiveConfigWithConstraints(config, &hwc2_constraints,
+ &hwc2_timeline));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ timeline->refreshTimeNanos = hwc2_timeline.refreshTimeNanos;
+ timeline->newVsyncAppliedTimeNanos = hwc2_timeline.newVsyncAppliedTimeNanos;
+ timeline->refreshRequired = static_cast<bool>(hwc2_timeline.refreshRequired);
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus ComposerClient::setBootDisplayConfig(int64_t /*display*/,
+ndk::ScopedAStatus ComposerClient::setBootDisplayConfig(int64_t /*display_id*/,
int32_t /*config*/) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
}
-ndk::ScopedAStatus ComposerClient::clearBootDisplayConfig(int64_t /*display*/) {
+ndk::ScopedAStatus ComposerClient::clearBootDisplayConfig(
+ int64_t /*display_id*/) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
}
ndk::ScopedAStatus ComposerClient::getPreferredBootDisplayConfig(
- int64_t /*display*/, int32_t* /*config*/) {
+ int64_t /*display_id*/, int32_t* /*config*/) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
}
-ndk::ScopedAStatus ComposerClient::setAutoLowLatencyMode(int64_t /*display*/,
- bool /*on*/) {
+ndk::ScopedAStatus ComposerClient::setAutoLowLatencyMode(int64_t display_id,
+ bool on) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ auto error = Hwc2toHwc3Error(display->SetAutoLowLatencyMode(on));
+ return ToBinderStatus(error);
}
-ndk::ScopedAStatus ComposerClient::setClientTargetSlotCount(int64_t /*display*/,
- int32_t /*count*/) {
+ndk::ScopedAStatus ComposerClient::setClientTargetSlotCount(int64_t display_id,
+ int32_t count) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ return ToBinderStatus(
+ composer_resources_->SetDisplayClientTargetCacheSize(display_id, count));
}
-ndk::ScopedAStatus ComposerClient::setColorMode(int64_t /*display*/,
- ColorMode /*mode*/,
- RenderIntent /*intent*/) {
+ndk::ScopedAStatus ComposerClient::setColorMode(int64_t display_id,
+ ColorMode mode,
+ RenderIntent intent) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ auto error = display->SetColorModeWithIntent(Hwc3ColorModeToHwc2(mode),
+ Hwc3RenderIntentToHwc2(intent));
+ return ToBinderStatus(Hwc2toHwc3Error(error));
}
-ndk::ScopedAStatus ComposerClient::setContentType(int64_t /*display*/,
- ContentType /*type*/) {
+ndk::ScopedAStatus ComposerClient::setContentType(int64_t display_id,
+ ContentType type) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ auto error = display->SetContentType(Hwc3ContentTypeToHwc2(type));
+ return ToBinderStatus(Hwc2toHwc3Error(error));
}
ndk::ScopedAStatus ComposerClient::setDisplayedContentSamplingEnabled(
- int64_t /*display*/, bool /*enable*/,
+ int64_t /*display_id*/, bool /*enable*/,
FormatColorComponent /*componentMask*/, int64_t /*maxFrames*/) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
}
-ndk::ScopedAStatus ComposerClient::setPowerMode(int64_t /*display*/,
- PowerMode /*mode*/) {
+ndk::ScopedAStatus ComposerClient::setPowerMode(int64_t display_id,
+ PowerMode mode) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ auto error = display->SetPowerMode(Hwc3PowerModeToHwc2(mode));
+ return ToBinderStatus(Hwc2toHwc3Error(error));
}
ndk::ScopedAStatus ComposerClient::setReadbackBuffer(
- int64_t /*display*/, const AidlNativeHandle& /*aidlBuffer*/,
+ int64_t /*display_id*/, const AidlNativeHandle& /*aidlBuffer*/,
const ndk::ScopedFileDescriptor& /*releaseFence*/) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
}
-ndk::ScopedAStatus ComposerClient::setVsyncEnabled(int64_t /*display*/,
- bool /*enabled*/) {
+ndk::ScopedAStatus ComposerClient::setVsyncEnabled(int64_t display_id,
+ bool enabled) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ auto error = display->SetVsyncEnabled(static_cast<int32_t>(enabled));
+ return ToBinderStatus(Hwc2toHwc3Error(error));
}
-ndk::ScopedAStatus ComposerClient::setIdleTimerEnabled(int64_t /*display*/,
+ndk::ScopedAStatus ComposerClient::setIdleTimerEnabled(int64_t /*display_id*/,
int32_t /*timeout*/) {
DEBUG_FUNC();
- return ndk::ScopedAStatus::ok();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
+std::string ComposerClient::Dump() {
+ uint32_t size = 0;
+ hwc_->Dump(&size, nullptr);
+
+ std::string buffer(size, '\0');
+ hwc_->Dump(&size, &buffer.front());
+ return buffer;
}
::ndk::SpAIBinder ComposerClient::createBinder() {
@@ -299,4 +926,335 @@
return binder;
}
+void ComposerClient::ExecuteSetLayerBuffer(int64_t display_id,
+ HwcLayerWrapper& layer,
+ const Buffer& buffer) {
+ buffer_handle_t imported_buffer = nullptr;
+
+ auto releaser = composer_resources_->CreateResourceReleaser(true);
+ auto err = composer_resources_->GetLayerBuffer(display_id, layer.layer_id,
+ buffer, &imported_buffer,
+ releaser.get());
+ if (err != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(err);
+ return;
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
+ auto fence_fd = const_cast<ndk::ScopedFileDescriptor&>(buffer.fence)
+ .release();
+ err = Hwc2toHwc3Error(layer.layer->SetLayerBuffer(imported_buffer, fence_fd));
+ if (err != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(err);
+ }
+}
+
+void ComposerClient::ExecuteSetLayerBlendMode(
+ int64_t /*display_id*/, HwcLayerWrapper& layer,
+ const ParcelableBlendMode& blend_mode) {
+ auto err = Hwc2toHwc3Error(layer.layer->SetLayerBlendMode(
+ Hwc3BlendModeToHwc2(blend_mode.blendMode)));
+ if (err != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(err);
+ }
+}
+
+void ComposerClient::ExecuteSetLayerComposition(
+ int64_t /*display_id*/, HwcLayerWrapper& layer,
+ const ParcelableComposition& composition) {
+ hwc3::Error error = hwc3::Error::kNone;
+ switch (composition.composition) {
+ // Unsupported composition types should set an error for the current
+ // DisplayCommand.
+ case Composition::DISPLAY_DECORATION:
+ case Composition::SIDEBAND:
+ error = hwc3::Error::kUnsupported;
+ break;
+ default:
+ error = Hwc2toHwc3Error(layer.layer->SetLayerCompositionType(
+ Hwc3CompositionToHwc2(composition.composition)));
+ }
+ if (error != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(error);
+ }
+}
+
+void ComposerClient::ExecuteSetLayerDataspace(
+ int64_t /*display_id*/, HwcLayerWrapper& layer,
+ const ParcelableDataspace& dataspace) {
+ auto err = Hwc2toHwc3Error(
+ layer.layer->SetLayerDataspace(Hwc3DataspaceToHwc2(dataspace.dataspace)));
+ if (err != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(err);
+ }
+}
+
+void ComposerClient::ExecuteSetLayerDisplayFrame(int64_t /*display_id*/,
+ HwcLayerWrapper& layer,
+ const common::Rect& rect) {
+ const hwc_rect_t hwc2_rect{rect.left, rect.top, rect.right, rect.bottom};
+ auto err = Hwc2toHwc3Error(layer.layer->SetLayerDisplayFrame(hwc2_rect));
+ if (err != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(err);
+ }
+}
+void ComposerClient::ExecuteSetLayerPlaneAlpha(int64_t /*display_id*/,
+ HwcLayerWrapper& layer,
+ const PlaneAlpha& plane_alpha) {
+ auto err = Hwc2toHwc3Error(
+ layer.layer->SetLayerPlaneAlpha(plane_alpha.alpha));
+ if (err != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(err);
+ }
+}
+
+void ComposerClient::ExecuteSetLayerSourceCrop(
+ int64_t /*display_id*/, HwcLayerWrapper& layer,
+ const common::FRect& source_crop) {
+ const hwc_frect_t rect{source_crop.left, source_crop.top, source_crop.right,
+ source_crop.bottom};
+ auto err = Hwc2toHwc3Error(layer.layer->SetLayerSourceCrop(rect));
+ if (err != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(err);
+ }
+}
+void ComposerClient::ExecuteSetLayerTransform(
+ int64_t /*display_id*/, HwcLayerWrapper& layer,
+ const ParcelableTransform& transform) {
+ auto err = Hwc2toHwc3Error(
+ layer.layer->SetLayerTransform(Hwc3TransformToHwc2(transform.transform)));
+ if (err != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(err);
+ }
+}
+void ComposerClient::ExecuteSetLayerZOrder(int64_t /*display_id*/,
+ HwcLayerWrapper& layer,
+ const ZOrder& z_order) {
+ auto err = Hwc2toHwc3Error(layer.layer->SetLayerZOrder(z_order.z));
+ if (err != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(err);
+ }
+}
+
+void ComposerClient::ExecuteSetLayerBrightness(
+ int64_t /*display_id*/, HwcLayerWrapper& /*layer*/,
+ const LayerBrightness& brightness) {
+ if (std::signbit(brightness.brightness) ||
+ std::isnan(brightness.brightness)) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadParameter);
+ }
+}
+
+void ComposerClient::ExecuteSetDisplayBrightness(
+ uint64_t display_id, const DisplayBrightness& command) {
+ auto* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
+ return;
+ }
+
+ auto error = Hwc2toHwc3Error(
+ display->SetDisplayBrightness(command.brightness));
+ if (error != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(error);
+ }
+}
+void ComposerClient::ExecuteSetDisplayColorTransform(
+ uint64_t display_id, const std::vector<float>& matrix) {
+ auto* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
+ return;
+ }
+
+ auto almost_equal = [](auto a, auto b) {
+ const float epsilon = 0.001F;
+ return std::abs(a - b) < epsilon;
+ };
+ const bool is_identity = std::equal(matrix.begin(), matrix.end(),
+ kIdentityMatrix.begin(), almost_equal);
+
+ const int32_t hint = is_identity ? HAL_COLOR_TRANSFORM_IDENTITY
+ : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
+
+ auto error = Hwc2toHwc3Error(display->SetColorTransform(matrix.data(), hint));
+ if (error != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(error);
+ }
+}
+void ComposerClient::ExecuteSetDisplayClientTarget(
+ uint64_t display_id, const ClientTarget& command) {
+ auto* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
+ return;
+ }
+
+ hwc_region_t damage_regions;
+ damage_regions.numRects = command.damage.size();
+
+ std::vector<hwc_rect_t> regions(command.damage.size());
+ for (const auto& region : command.damage) {
+ regions.push_back({region.left, region.top, region.right, region.bottom});
+ }
+ damage_regions.rects = regions.data();
+
+ buffer_handle_t imported_buffer = nullptr;
+ auto buf_releaser = composer_resources_->CreateResourceReleaser(true);
+
+ auto error = composer_resources_->GetDisplayClientTarget(display_id,
+ command.buffer,
+ &imported_buffer,
+ buf_releaser.get());
+ if (error != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(error);
+ return;
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
+ auto fence = const_cast<::ndk::ScopedFileDescriptor&>(command.buffer.fence)
+ .release();
+ error = Hwc2toHwc3Error(
+ display->SetClientTarget(imported_buffer, fence,
+ Hwc3DataspaceToHwc2(command.dataspace),
+ damage_regions));
+ if (error != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(error);
+ }
+}
+
+void ComposerClient::ExecuteSetDisplayOutputBuffer(uint64_t display_id,
+ const Buffer& buffer) {
+ auto* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
+ return;
+ }
+
+ buffer_handle_t imported_buffer = nullptr;
+ auto buf_releaser = composer_resources_->CreateResourceReleaser(true);
+
+ auto error = composer_resources_->GetDisplayOutputBuffer(display_id, buffer,
+ &imported_buffer,
+ buf_releaser.get());
+ if (error != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(error);
+ return;
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
+ auto fence = const_cast<::ndk::ScopedFileDescriptor&>(buffer.fence).release();
+ error = Hwc2toHwc3Error(display->SetOutputBuffer(imported_buffer, fence));
+ if (error != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(error);
+ return;
+ }
+}
+void ComposerClient::ExecuteValidateDisplay(
+ int64_t display_id,
+ std::optional<ClockMonotonicTimestamp> /*expected_present_time*/
+) {
+ auto* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
+ return;
+ }
+
+ /* TODO: Handle expectedPresentTime */
+
+ std::vector<int64_t> changed_layers;
+ std::vector<Composition> composition_types;
+ int32_t display_request_mask = 0;
+ std::vector<int64_t> requested_layers;
+ std::vector<int32_t> request_masks;
+
+ const hwc3::Error error = ValidateDisplayInternal(*display, &changed_layers,
+ &composition_types,
+ &display_request_mask,
+ &requested_layers,
+ &request_masks, nullptr,
+ nullptr);
+
+ if (error != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(error);
+ }
+
+ // If a CommandError has been been set for the current DisplayCommand, then
+ // no other results should be returned besides the error.
+ if (cmd_result_writer_->HasError()) {
+ return;
+ }
+
+ DisplayChanges changes{};
+ for (size_t i = 0; i < composition_types.size(); i++) {
+ changes.AddLayerCompositionChange(display_id, changed_layers[i],
+ composition_types[i]);
+ }
+
+ std::vector<DisplayRequest::LayerRequest> layer_requests;
+ for (size_t i = 0; i < requested_layers.size(); i++) {
+ layer_requests.push_back({requested_layers[i], request_masks[i]});
+ }
+
+ const DisplayRequest request_changes{display_id, display_request_mask,
+ layer_requests};
+ changes.display_request_changes = request_changes;
+
+ cmd_result_writer_->AddChanges(changes);
+ composer_resources_->SetDisplayMustValidateState(display_id, false);
+}
+
+void ComposerClient::ExecuteAcceptDisplayChanges(int64_t display_id) {
+ auto* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
+ return;
+ }
+
+ auto error = Hwc2toHwc3Error(display->AcceptDisplayChanges());
+ if (error != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(error);
+ return;
+ }
+}
+
+void ComposerClient::ExecutePresentDisplay(int64_t display_id) {
+ auto* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
+ return;
+ }
+
+ ::android::base::unique_fd display_fence;
+ std::unordered_map<int64_t, ::android::base::unique_fd> release_fences;
+ auto error = PresentDisplayInternal(display_id, display_fence,
+ release_fences);
+ if (error != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(error);
+ }
+ if (cmd_result_writer_->HasError()) {
+ return;
+ }
+
+ cmd_result_writer_->AddPresentFence(display_id, std::move(display_fence));
+ cmd_result_writer_->AddReleaseFence(display_id, release_fences);
+}
+
+void ComposerClient::ExecutePresentOrValidateDisplay(
+ int64_t display_id,
+ std::optional<ClockMonotonicTimestamp> expected_present_time) {
+ auto* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
+ return;
+ }
+
+ /* TODO: Handle expectedPresentTime */
+ /* TODO: Add check if it's possible to skip display validation */
+ ExecuteValidateDisplay(display_id, expected_present_time);
+ cmd_result_writer_
+ ->AddPresentOrValidateResult(display_id,
+ PresentOrValidate::Result::Validated);
+}
+
} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/hwc3/ComposerClient.h b/hwc3/ComposerClient.h
index bdf4b0a..616f8aa 100644
--- a/hwc3/ComposerClient.h
+++ b/hwc3/ComposerClient.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -16,22 +16,42 @@
#pragma once
-#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
-#include <aidl/android/hardware/graphics/composer3/BnComposerClient.h>
-#include <utils/Mutex.h>
-
#include <memory>
+#include "aidl/android/hardware/graphics/composer3/BnComposerClient.h"
+#include "aidl/android/hardware/graphics/composer3/LayerCommand.h"
+#include "hwc3/CommandResultWriter.h"
+#include "hwc3/ComposerResources.h"
+#include "hwc3/Utils.h"
+#include "utils/Mutex.h"
+
using AidlPixelFormat = aidl::android::hardware::graphics::common::PixelFormat;
using AidlNativeHandle = aidl::android::hardware::common::NativeHandle;
+namespace android {
+
+class HwcDisplay;
+class HwcLayer;
+
+} // namespace android
+
namespace aidl::android::hardware::graphics::composer3::impl {
+class DrmHwcThree;
+
+struct HwcLayerWrapper {
+ int64_t layer_id;
+ ::android::HwcLayer* layer;
+};
+
class ComposerClient : public BnComposerClient {
public:
- ComposerClient() = default;
+ ComposerClient();
~ComposerClient() override;
+ bool Init();
+ std::string Dump();
+
// composer3 interface
ndk::ScopedAStatus createLayer(int64_t display, int32_t buffer_slot_count,
int64_t* layer) override;
@@ -119,6 +139,71 @@
protected:
::ndk::SpAIBinder createBinder() override;
+
+ private:
+ // Layer commands
+ void DispatchLayerCommand(int64_t display_id, const LayerCommand& command);
+ void ExecuteSetLayerBuffer(int64_t display_id, HwcLayerWrapper& layer_id,
+ const Buffer& buffer);
+ void ExecuteSetLayerBlendMode(int64_t display_id, HwcLayerWrapper& layer,
+ const ParcelableBlendMode& blend_mode);
+ void ExecuteSetLayerComposition(int64_t display_id, HwcLayerWrapper& layer,
+ const ParcelableComposition& composition);
+ void ExecuteSetLayerDataspace(int64_t display_id, HwcLayerWrapper& layer,
+ const ParcelableDataspace& dataspace);
+ void ExecuteSetLayerDisplayFrame(int64_t display_id, HwcLayerWrapper& layer,
+ const common::Rect& rect);
+ void ExecuteSetLayerPlaneAlpha(int64_t display_id, HwcLayerWrapper& layer,
+ const PlaneAlpha& plane_alpha);
+ void ExecuteSetLayerSourceCrop(int64_t display_id, HwcLayerWrapper& layer,
+ const common::FRect& source_crop);
+ void ExecuteSetLayerTransform(int64_t display_id, HwcLayerWrapper& layer,
+ const ParcelableTransform& transform);
+ void ExecuteSetLayerZOrder(int64_t display_id, HwcLayerWrapper& layer,
+ const ZOrder& z_order);
+ void ExecuteSetLayerBrightness(int64_t display_id, HwcLayerWrapper& layer,
+ const LayerBrightness& brightness);
+
+ // Display commands
+ void ExecuteDisplayCommand(const DisplayCommand& command);
+ void ExecuteSetDisplayBrightness(uint64_t display_id,
+ const DisplayBrightness& command);
+ void ExecuteSetDisplayColorTransform(uint64_t display_id,
+ const std::vector<float>& matrix);
+ void ExecuteSetDisplayClientTarget(uint64_t display_id,
+ const ClientTarget& command);
+ void ExecuteSetDisplayOutputBuffer(uint64_t display_id, const Buffer& buffer);
+ void ExecuteValidateDisplay(
+ int64_t display_id,
+ std::optional<ClockMonotonicTimestamp> expected_present_time);
+ void ExecuteAcceptDisplayChanges(int64_t display_id);
+ void ExecutePresentDisplay(int64_t display_id);
+ void ExecutePresentOrValidateDisplay(
+ int64_t display_id,
+ std::optional<ClockMonotonicTimestamp> expected_present_time);
+
+ static hwc3::Error ValidateDisplayInternal(
+ ::android::HwcDisplay& display, std::vector<int64_t>* out_changed_layers,
+ std::vector<Composition>* out_composition_types,
+ int32_t* out_display_request_mask,
+ std::vector<int64_t>* out_requested_layers,
+ std::vector<int32_t>* out_request_masks,
+ ClientTargetProperty* out_client_target_property,
+ DimmingStage* out_dimming_stage);
+
+ hwc3::Error PresentDisplayInternal(
+ uint64_t display_id, ::android::base::unique_fd& out_display_fence,
+ std::unordered_map<int64_t, ::android::base::unique_fd>&
+ out_release_fences);
+
+ ::android::HwcDisplay* GetDisplay(uint64_t display_id);
+
+ std::unique_ptr<CommandResultWriter> cmd_result_writer_;
+
+ // Manages importing and caching gralloc buffers for displays and layers.
+ std::unique_ptr<ComposerResources> composer_resources_;
+
+ std::unique_ptr<DrmHwcThree> hwc_;
};
} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/hwc3/ComposerResources.cpp b/hwc3/ComposerResources.cpp
new file mode 100644
index 0000000..ae0edf4
--- /dev/null
+++ b/hwc3/ComposerResources.cpp
@@ -0,0 +1,202 @@
+
+/*
+ * Copyright (C) 2024 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 "drmhwc"
+#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
+
+#include "ComposerResources.h"
+
+#include <aidlcommonsupport/NativeHandle.h>
+
+#include "hardware/hwcomposer2.h"
+#include "hwc3/Utils.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+::android::hardware::graphics::composer::V2_1::Display ToHwc2Display(
+ uint64_t display_id) {
+ return static_cast<::android::hardware::graphics::composer::V2_1::Display>(
+ display_id);
+}
+
+::android::hardware::graphics::composer::V2_1::Layer ToHwc2Layer(
+ int64_t layer_id) {
+ return static_cast<::android::hardware::graphics::composer::V2_1::Layer>(
+ layer_id);
+}
+
+std::unique_ptr<ComposerResourceReleaser>
+ComposerResources::CreateResourceReleaser(bool is_buffer) {
+ return std::make_unique<ComposerResourceReleaser>(is_buffer);
+}
+
+std::unique_ptr<ComposerResources> ComposerResources::Create() {
+ auto instance = std::unique_ptr<ComposerResources>(new ComposerResources);
+ if (instance->resources_ == nullptr) {
+ ALOGE("%s: Failed to initialise ComposerResources", __func__);
+ return nullptr;
+ }
+
+ return instance;
+}
+
+hwc3::Error ComposerResources::GetLayerBuffer(
+ uint64_t display_id, int64_t layer_id, const Buffer& buffer,
+ buffer_handle_t* out_buffer_handle,
+ ComposerResourceReleaser* buf_releaser) {
+ auto display = ToHwc2Display(display_id);
+ auto layer = ToHwc2Layer(layer_id);
+
+ const bool use_cache = !buffer.handle.has_value();
+ buffer_handle_t buffer_handle = nullptr;
+ if (buffer.handle.has_value()) {
+ buffer_handle = ::android::makeFromAidl(*buffer.handle);
+ }
+
+ auto err = resources_->getLayerBuffer(display, layer, buffer.slot, use_cache,
+ buffer_handle, out_buffer_handle,
+ buf_releaser->GetReplacedHandle());
+
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+hwc3::Error ComposerResources::GetLayerSidebandStream(
+ uint64_t display_id, int64_t layer_id,
+ const aidl::android::hardware::common::NativeHandle& handle,
+ buffer_handle_t* out_handle, ComposerResourceReleaser* releaser) {
+ auto display = ToHwc2Display(display_id);
+ auto layer = ToHwc2Layer(layer_id);
+
+ auto err = resources_->getLayerSidebandStream(display, layer,
+ ::android::makeFromAidl(handle),
+ out_handle,
+ releaser->GetReplacedHandle());
+
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+hwc3::Error ComposerResources::AddLayer(uint64_t display_id, int64_t layer_id,
+ uint32_t buffer_cache_size) {
+ auto display = ToHwc2Display(display_id);
+ auto layer = ToHwc2Layer(layer_id);
+
+ auto err = resources_->addLayer(display, layer, buffer_cache_size);
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+hwc3::Error ComposerResources::RemoveLayer(uint64_t display_id,
+ int64_t layer_id) {
+ auto display = ToHwc2Display(display_id);
+ auto layer = ToHwc2Layer(layer_id);
+
+ auto err = resources_->removeLayer(display, layer);
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+bool ComposerResources::HasDisplay(uint64_t display_id) {
+ auto display = ToHwc2Display(display_id);
+ return resources_->hasDisplay(display);
+}
+
+hwc3::Error ComposerResources::AddPhysicalDisplay(uint64_t display_id) {
+ auto display = ToHwc2Display(display_id);
+ auto err = resources_->addPhysicalDisplay(display);
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+hwc3::Error ComposerResources::AddVirtualDisplay(
+ uint64_t display, uint32_t output_buffer_cache_size) {
+ auto err = resources_->addVirtualDisplay(display, output_buffer_cache_size);
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+hwc3::Error ComposerResources::RemoveDisplay(uint64_t display_id) {
+ auto display = ToHwc2Display(display_id);
+ auto err = resources_->removeDisplay(display);
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+void ComposerResources::SetDisplayMustValidateState(uint64_t display_id,
+ bool must_validate) {
+ auto display = ToHwc2Display(display_id);
+ resources_->setDisplayMustValidateState(display, must_validate);
+}
+
+bool ComposerResources::MustValidateDisplay(uint64_t display_id) {
+ auto display = ToHwc2Display(display_id);
+ return resources_->mustValidateDisplay(display);
+}
+
+hwc3::Error ComposerResources::GetDisplayClientTarget(
+ uint64_t display_id, const Buffer& buffer, buffer_handle_t* out_handle,
+ ComposerResourceReleaser* releaser) {
+ auto display = ToHwc2Display(display_id);
+
+ const bool use_cache = !buffer.handle.has_value();
+ buffer_handle_t buffer_handle = nullptr;
+ if (buffer.handle.has_value()) {
+ buffer_handle = ::android::makeFromAidl(*buffer.handle);
+ }
+
+ auto err = resources_->getDisplayClientTarget(display, buffer.slot, use_cache,
+ buffer_handle, out_handle,
+ releaser->GetReplacedHandle());
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+hwc3::Error ComposerResources::SetDisplayClientTargetCacheSize(
+ uint64_t display_id, uint32_t client_target_cache_size) {
+ auto display = ToHwc2Display(display_id);
+ auto err = resources_
+ ->setDisplayClientTargetCacheSize(display,
+ client_target_cache_size);
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+hwc3::Error ComposerResources::GetDisplayClientTargetCacheSize(
+ uint64_t display_id, size_t* out_cache_size) {
+ auto display = ToHwc2Display(display_id);
+ auto err = resources_->getDisplayClientTargetCacheSize(display,
+ out_cache_size);
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+hwc3::Error ComposerResources::GetDisplayOutputBufferCacheSize(
+ uint64_t display_id, size_t* out_cache_size) {
+ auto display = ToHwc2Display(display_id);
+ auto err = resources_->getDisplayOutputBufferCacheSize(display,
+ out_cache_size);
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+hwc3::Error ComposerResources::GetDisplayOutputBuffer(
+ uint64_t display_id, const Buffer& buffer, buffer_handle_t* out_handle,
+ ComposerResourceReleaser* releaser) {
+ auto display = ToHwc2Display(display_id);
+ const bool use_cache = !buffer.handle.has_value();
+
+ buffer_handle_t buffer_handle = nullptr;
+ if (buffer.handle.has_value()) {
+ buffer_handle = ::android::makeFromAidl(*buffer.handle);
+ }
+
+ auto err = resources_->getDisplayOutputBuffer(display, buffer.slot, use_cache,
+ buffer_handle, out_handle,
+ releaser->GetReplacedHandle());
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+} // namespace aidl::android::hardware::graphics::composer3::impl
\ No newline at end of file
diff --git a/hwc3/ComposerResources.h b/hwc3/ComposerResources.h
new file mode 100644
index 0000000..6f4eee7
--- /dev/null
+++ b/hwc3/ComposerResources.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "aidl/android/hardware/graphics/composer3/IComposerClient.h"
+#include "composer-resources/2.2/ComposerResources.h"
+#include "cutils/native_handle.h"
+#include "hwc3/Utils.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+class ComposerResourceReleaser {
+ public:
+ explicit ComposerResourceReleaser(bool is_buffer)
+ : replaced_handle_(is_buffer) {
+ }
+ virtual ~ComposerResourceReleaser() = default;
+
+ ::android::hardware::graphics::composer::V2_2::hal::ComposerResources::
+ ReplacedHandle*
+ GetReplacedHandle() {
+ return &replaced_handle_;
+ }
+
+ private:
+ ::android::hardware::graphics::composer::V2_2::hal::ComposerResources::
+ ReplacedHandle replaced_handle_;
+};
+
+class ComposerResources {
+ public:
+ static std::unique_ptr<ComposerResources> Create();
+ ~ComposerResources() = default;
+
+ hwc3::Error GetLayerBuffer(uint64_t display_id, int64_t layer_id,
+ const Buffer& buffer,
+ buffer_handle_t* out_buffer_handle,
+ ComposerResourceReleaser* releaser);
+ hwc3::Error GetLayerSidebandStream(
+ uint64_t display_id, int64_t layer_id,
+ const aidl::android::hardware::common::NativeHandle& handle,
+ buffer_handle_t* out_handle, ComposerResourceReleaser* releaser);
+
+ hwc3::Error AddLayer(uint64_t display, int64_t layer,
+ uint32_t buffer_cache_size);
+ hwc3::Error RemoveLayer(uint64_t display, int64_t layer);
+
+ bool HasDisplay(uint64_t display);
+ hwc3::Error AddPhysicalDisplay(uint64_t display);
+ hwc3::Error AddVirtualDisplay(uint64_t display,
+ uint32_t output_buffer_cache_size);
+ hwc3::Error RemoveDisplay(uint64_t display);
+
+ void SetDisplayMustValidateState(uint64_t display_id, bool must_validate);
+ bool MustValidateDisplay(uint64_t display_id);
+
+ hwc3::Error GetDisplayClientTarget(uint64_t display_id, const Buffer& buffer,
+ buffer_handle_t* out_handle,
+ ComposerResourceReleaser* releaser);
+
+ hwc3::Error SetDisplayClientTargetCacheSize(
+ uint64_t display_id, uint32_t client_target_cache_size);
+ hwc3::Error GetDisplayClientTargetCacheSize(uint64_t display_id,
+ size_t* out_cache_size);
+ hwc3::Error GetDisplayOutputBufferCacheSize(uint64_t display,
+ size_t* out_cache_size);
+ hwc3::Error GetDisplayOutputBuffer(uint64_t display_id, const Buffer& buffer,
+ buffer_handle_t* out_handle,
+ ComposerResourceReleaser* releaser);
+
+ static std::unique_ptr<ComposerResourceReleaser> CreateResourceReleaser(
+ bool is_buffer);
+
+ private:
+ ComposerResources() = default;
+
+ std::unique_ptr<
+ ::android::hardware::graphics::composer::V2_2::hal::ComposerResources>
+ resources_ = ::android::hardware::graphics::composer::V2_2::hal::
+ ComposerResources::create();
+};
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
\ No newline at end of file
diff --git a/hwc3/DrmHwcThree.cpp b/hwc3/DrmHwcThree.cpp
index 62984b4..b39d834 100644
--- a/hwc3/DrmHwcThree.cpp
+++ b/hwc3/DrmHwcThree.cpp
@@ -18,8 +18,26 @@
#include <cinttypes>
+#include "Utils.h"
+#include "aidl/android/hardware/graphics/common/Dataspace.h"
+
namespace aidl::android::hardware::graphics::composer3::impl {
+using ::android::HwcDisplay;
+
+// NOLINTNEXTLINE(bugprone-exception-escape)
+DrmHwcThree::~DrmHwcThree() {
+ std::vector<uint64_t> display_ids;
+ display_ids.reserve(Displays().size());
+ for (auto& [display_id, display] : Displays()) {
+ display_ids.push_back(display_id);
+ }
+
+ for (auto display_id : display_ids) {
+ RemoveAndDestroyDisplay(display_id);
+ }
+}
+
void DrmHwcThree::Init(std::shared_ptr<IComposerCallback> callback) {
composer_callback_ = std::move(callback);
GetResMan().Init();
@@ -38,6 +56,7 @@
}
void DrmHwcThree::SendRefreshEventToClient(uint64_t display_id) {
+ composer_resources_->SetDisplayMustValidateState(display_id, true);
composer_callback_->onRefresh(static_cast<int64_t>(display_id));
}
@@ -49,7 +68,83 @@
void DrmHwcThree::SendHotplugEventToClient(hwc2_display_t display_id,
bool connected) {
+ HandleDisplayHotplugEvent(static_cast<uint64_t>(display_id), connected);
composer_callback_->onHotplug(static_cast<int64_t>(display_id), connected);
}
+void DrmHwcThree::RemoveAndDestroyDisplay(uint64_t display_id) {
+ DEBUG_FUNC();
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return;
+ }
+
+ display->SetPowerMode(static_cast<int32_t>(HWC2::PowerMode::Off));
+ display->Deinit();
+
+ composer_resources_->RemoveDisplay(static_cast<int64_t>(display_id));
+ Displays().erase(display_id);
+}
+
+void DrmHwcThree::CleanDisplayResources(uint64_t display_id) {
+ DEBUG_FUNC();
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return;
+ }
+
+ display->SetPowerMode(static_cast<int32_t>(PowerMode::OFF));
+
+ size_t cache_size = 0;
+ auto err = composer_resources_->GetDisplayClientTargetCacheSize(display_id,
+ &cache_size);
+ if (err != hwc3::Error::kNone) {
+ ALOGE("%s: Could not clear target buffer cache for display: %" PRIu64,
+ __func__, display_id);
+ return;
+ }
+
+ for (size_t slot = 0; slot < cache_size; slot++) {
+ buffer_handle_t buffer_handle = nullptr;
+ auto buf_releaser = ComposerResources::CreateResourceReleaser(true);
+
+ Buffer buf{};
+ buf.slot = static_cast<int32_t>(slot);
+ err = composer_resources_->GetDisplayClientTarget(display_id, buf,
+ &buffer_handle,
+ buf_releaser.get());
+ if (err != hwc3::Error::kNone) {
+ continue;
+ }
+
+ err = Hwc2toHwc3Error(
+ display->SetClientTarget(buffer_handle, -1,
+ static_cast<int32_t>(
+ common::Dataspace::UNKNOWN),
+ {}));
+ if (err != hwc3::Error::kNone) {
+ ALOGE(
+ "%s: Could not clear slot %zu of the target buffer cache for "
+ "display %" PRIu64,
+ __func__, slot, display_id);
+ }
+ }
+}
+
+void DrmHwcThree::HandleDisplayHotplugEvent(uint64_t display_id,
+ bool connected) {
+ DEBUG_FUNC();
+ if (!connected) {
+ composer_resources_->RemoveDisplay(display_id);
+ return;
+ }
+
+ if (composer_resources_->HasDisplay(display_id)) {
+ /* Cleanup existing display resources */
+ CleanDisplayResources(display_id);
+ composer_resources_->RemoveDisplay(display_id);
+ }
+ composer_resources_->AddPhysicalDisplay(display_id);
+}
+
} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/hwc3/DrmHwcThree.h b/hwc3/DrmHwcThree.h
index c2d4119..90e5f32 100644
--- a/hwc3/DrmHwcThree.h
+++ b/hwc3/DrmHwcThree.h
@@ -19,13 +19,16 @@
#include <aidl/android/hardware/graphics/composer3/IComposerCallback.h>
#include "drm/DrmHwc.h"
+#include "hwc3/ComposerResources.h"
namespace aidl::android::hardware::graphics::composer3::impl {
class DrmHwcThree : public ::android::DrmHwc {
public:
- DrmHwcThree() = default;
- ~DrmHwcThree() override = default;
+ explicit DrmHwcThree(ComposerResources* composer_resources)
+ : composer_resources_(composer_resources) {
+ }
+ ~DrmHwcThree() override;
void Init(std::shared_ptr<IComposerCallback> callback);
@@ -39,6 +42,11 @@
bool connected) override;
private:
+ void RemoveAndDestroyDisplay(uint64_t display_id);
+ void CleanDisplayResources(uint64_t display_id);
+ void HandleDisplayHotplugEvent(uint64_t display_id, bool connected);
+
std::shared_ptr<IComposerCallback> composer_callback_;
+ ComposerResources* composer_resources_;
};
} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/hwc3/Utils.cpp b/hwc3/Utils.cpp
new file mode 100644
index 0000000..adbd2fb
--- /dev/null
+++ b/hwc3/Utils.cpp
@@ -0,0 +1,58 @@
+
+/*
+ * Copyright (C) 2024 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 "drmhwc"
+#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
+
+#include "Utils.h"
+
+#include <hardware/hwcomposer2.h>
+
+#include "utils/log.h"
+
+namespace aidl::android::hardware::graphics::composer3 {
+
+hwc3::Error Hwc2toHwc3Error(HWC2::Error error) {
+ switch (error) {
+ case HWC2::Error::None:
+ return hwc3::Error::kNone;
+ case HWC2::Error::BadConfig:
+ return hwc3::Error::kBadConfig;
+ case HWC2::Error::BadDisplay:
+ return hwc3::Error::kBadDisplay;
+ case HWC2::Error::BadLayer:
+ return hwc3::Error::kBadLayer;
+ case HWC2::Error::BadParameter:
+ return hwc3::Error::kBadParameter;
+ case HWC2::Error::NoResources:
+ return hwc3::Error::kNoResources;
+ case HWC2::Error::NotValidated:
+ return hwc3::Error::kNotValidated;
+ case HWC2::Error::Unsupported:
+ return hwc3::Error::kUnsupported;
+ case HWC2::Error::SeamlessNotAllowed:
+ return hwc3::Error::kSeamlessNotAllowed;
+ case HWC2::Error::SeamlessNotPossible:
+ return hwc3::Error::kSeamlessNotPossible;
+ default:
+ ALOGE("Unknown HWC2 error. Could not translate to HWC3 error: %d",
+ static_cast<int32_t>(error));
+ return hwc3::Error::kUnsupported;
+ }
+}
+
+}; // namespace aidl::android::hardware::graphics::composer3
\ No newline at end of file
diff --git a/hwc3/Utils.h b/hwc3/Utils.h
new file mode 100644
index 0000000..23d6bdc
--- /dev/null
+++ b/hwc3/Utils.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/graphics/composer3/IComposerClient.h>
+#include <hardware/hwcomposer2.h>
+
+#include <cstdint>
+
+// NOLINTNEXTLINE
+#define DEBUG_FUNC() ALOGV("%s", __func__)
+
+namespace aidl::android::hardware::graphics::composer3 {
+
+namespace hwc3 {
+enum class Error : int32_t {
+ kNone = 0,
+ kBadConfig = IComposerClient::EX_BAD_CONFIG,
+ kBadDisplay = IComposerClient::EX_BAD_DISPLAY,
+ kBadLayer = IComposerClient::EX_BAD_LAYER,
+ kBadParameter = IComposerClient::EX_BAD_PARAMETER,
+ kNoResources = IComposerClient::EX_NO_RESOURCES,
+ kNotValidated = IComposerClient::EX_NOT_VALIDATED,
+ kUnsupported = IComposerClient::EX_UNSUPPORTED,
+ kSeamlessNotAllowed = IComposerClient::EX_SEAMLESS_NOT_ALLOWED,
+ kSeamlessNotPossible = IComposerClient::EX_SEAMLESS_NOT_POSSIBLE,
+};
+} // namespace hwc3
+
+hwc3::Error Hwc2toHwc3Error(HWC2::Error error);
+
+inline ndk::ScopedAStatus ToBinderStatus(hwc3::Error error) {
+ if (error != hwc3::Error::kNone) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(error));
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+inline ndk::ScopedAStatus ToBinderStatus(HWC2::Error error) {
+ return ToBinderStatus(Hwc2toHwc3Error(error));
+}
+
+// ID conversion. HWC2 uses typedef'd unsigned integer types while HWC3 uses
+// signed integer types. static_cast in between these.
+inline int64_t Hwc2LayerToHwc3(hwc2_layer_t layer) {
+ return static_cast<int64_t>(layer);
+}
+
+inline int64_t Hwc2DisplayToHwc3(hwc2_display_t display) {
+ return static_cast<int64_t>(display);
+}
+
+inline int32_t Hwc2ConfigIdToHwc3(hwc2_config_t config_id) {
+ return static_cast<int32_t>(config_id);
+}
+
+inline hwc2_layer_t Hwc3LayerToHwc2(int64_t layer) {
+ return static_cast<hwc2_layer_t>(layer);
+}
+
+inline hwc2_display_t Hwc3DisplayToHwc2(int64_t display) {
+ return static_cast<hwc2_display_t>(display);
+}
+
+inline hwc2_config_t Hwc3ConfigIdToHwc2(int32_t config_id) {
+ return static_cast<hwc2_config_t>(config_id);
+}
+
+// Values match up to HWC2_COMPOSITION_SIDEBAND, with HWC2 not supporting
+// newer values. static_cast in between shared values.
+// https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/Composition.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/libhardware/include_all/hardware/hwcomposer2.h;drc=d783cabd4d9bddb4b83f2dd38300b7598bb58b24;l=826
+inline Composition Hwc2CompositionTypeToHwc3(int32_t composition_type) {
+ if (composition_type < HWC2_COMPOSITION_INVALID ||
+ composition_type > HWC2_COMPOSITION_SIDEBAND) {
+ return Composition::INVALID;
+ }
+ return static_cast<Composition>(composition_type);
+}
+
+inline int32_t Hwc3CompositionToHwc2(Composition composition_type) {
+ if (composition_type > Composition::SIDEBAND) {
+ return HWC2_COMPOSITION_INVALID;
+ }
+ return static_cast<int32_t>(composition_type);
+}
+
+// Values for color modes match across HWC versions, so static cast is safe:
+// https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/ColorMode.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:system/core/libsystem/include/system/graphics-base-v1.0.h;drc=7d940ae4afa450696afa25e07982f3a95e17e9b2;l=118
+// https://cs.android.com/android/platform/superproject/main/+/main:system/core/libsystem/include/system/graphics-base-v1.1.h;drc=7d940ae4afa450696afa25e07982f3a95e17e9b2;l=35
+inline ColorMode Hwc2ColorModeToHwc3(int32_t color_mode) {
+ return static_cast<ColorMode>(color_mode);
+}
+
+inline int32_t Hwc3ColorModeToHwc2(ColorMode color_mode) {
+ return static_cast<int32_t>(color_mode);
+}
+
+// Capabilities match up to DisplayCapability::AUTO_LOW_LATENCY_MODE, with hwc2
+// not defining capabilities beyond that.
+// https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCapability.aidl#28
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/libhardware/include_all/hardware/hwcomposer2.h;drc=1a0e4a1698c7b080d6763cef9e16592bce75967e;l=418
+inline DisplayCapability Hwc2DisplayCapabilityToHwc3(
+ uint32_t display_capability) {
+ if (display_capability > HWC2_DISPLAY_CAPABILITY_AUTO_LOW_LATENCY_MODE) {
+ return DisplayCapability::INVALID;
+ }
+ return static_cast<DisplayCapability>(display_capability);
+}
+
+// Values match between hwc versions, so static cast is safe.
+// https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayConnectionType.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/libhardware/include_all/hardware/hwcomposer2.h;l=216;drc=d783cabd4d9bddb4b83f2dd38300b7598bb58b24;bpv=0;bpt=1
+inline DisplayConnectionType Hwc2DisplayConnectionTypeToHwc3(uint32_t type) {
+ if (type > HWC2_DISPLAY_CONNECTION_TYPE_EXTERNAL) {
+ // Arbitrarily return EXTERNAL in this case, which shouldn't happen.
+ // TODO: This will be cleaned up once hwc2<->hwc3 conversion is removed.
+ ALOGE("Unknown HWC2 connection type. Could not translate: %d", type);
+ return DisplayConnectionType::EXTERNAL;
+ }
+ return static_cast<DisplayConnectionType>(type);
+}
+
+// Values match, so static_cast is safe.
+// https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/RenderIntent.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:system/core/libsystem/include/system/graphics-base-v1.1.h;drc=7d940ae4afa450696afa25e07982f3a95e17e9b2;l=37
+inline RenderIntent Hwc2RenderIntentToHwc3(int32_t intent) {
+ if (intent < HAL_RENDER_INTENT_COLORIMETRIC ||
+ intent > HAL_RENDER_INTENT_TONE_MAP_ENHANCE) {
+ ALOGE("Unknown HWC2 render intent. Could not translate: %d", intent);
+ return RenderIntent::COLORIMETRIC;
+ }
+ return static_cast<RenderIntent>(intent);
+}
+inline int32_t Hwc3RenderIntentToHwc2(RenderIntent render_intent) {
+ return static_cast<int32_t>(render_intent);
+}
+
+// Content type matches, so static_cast is safe.
+// https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/ContentType.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/libhardware/include_all/hardware/hwcomposer2.h;l=350;drc=1a0e4a1698c7b080d6763cef9e16592bce75967e
+inline ContentType Hwc2ContentTypeToHwc3(uint32_t content_type) {
+ if (content_type > HWC2_CONTENT_TYPE_GAME) {
+ ALOGE("Unknown HWC2 content type. Could not translate: %d", content_type);
+ return ContentType::NONE;
+ }
+ return static_cast<ContentType>(content_type);
+}
+inline int32_t Hwc3ContentTypeToHwc2(ContentType content_type) {
+ return static_cast<int32_t>(content_type);
+}
+
+// Values match, so it's safe to do static_cast.
+// https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayAttribute.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/libhardware/include_all/hardware/hwcomposer2.h;l=58;drc=d783cabd4d9bddb4b83f2dd38300b7598bb58b24
+inline int32_t Hwc3DisplayAttributeToHwc2(DisplayAttribute display_attribute) {
+ return static_cast<int32_t>(display_attribute);
+}
+
+// Values match up to DOZE_SUSPEND.
+// https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/PowerMode.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/libhardware/include_all/hardware/hwcomposer2.h;l=348;drc=d783cabd4d9bddb4b83f2dd38300b7598bb58b24
+inline int32_t Hwc3PowerModeToHwc2(PowerMode power_mode) {
+ if (power_mode > PowerMode::DOZE_SUSPEND) {
+ ALOGE("Unsupported HWC2 power mode. Could not translate: %d", power_mode);
+ return HWC2_POWER_MODE_ON;
+ }
+ return static_cast<int32_t>(power_mode);
+}
+
+// Values match, so static_cast is okay.
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/BlendMode.aidl;drc=bab1ba54ede32520a5042d616a3af46ad4f55d5f;l=25
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/libhardware/include_all/hardware/hwcomposer2.h;l=72;drc=1a0e4a1698c7b080d6763cef9e16592bce75967e
+inline int32_t Hwc3BlendModeToHwc2(common::BlendMode blend_mode) {
+ return static_cast<int32_t>(blend_mode);
+}
+
+// Values appear to match.
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:system/core/libsystem/include/system/graphics-base-v1.0.h;l=43
+// https://cs.android.com/android/platform/superproject/main/+/main:system/core/libsystem/include/system/graphics-base-v1.1.h;l=22;drc=7d940ae4afa450696afa25e07982f3a95e17e9b2
+inline int32_t Hwc3DataspaceToHwc2(common::Dataspace dataspace) {
+ return static_cast<int32_t>(dataspace);
+}
+
+// Values match, so static_cast is okay.
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/Transform.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:system/core/libsystem/include/system/graphics-base-v1.0.h;l=41
+inline int32_t Hwc3TransformToHwc2(common::Transform transform) {
+ return static_cast<int32_t>(transform);
+}
+
+}; // namespace aidl::android::hardware::graphics::composer3
\ No newline at end of file
diff --git a/hwc3/hwc3-drm.rc b/hwc3/hwc3-drm.rc
index ef22730..425dd24 100644
--- a/hwc3/hwc3-drm.rc
+++ b/hwc3/hwc3-drm.rc
@@ -1,5 +1,6 @@
service vendor.hwcomposer-3 /vendor/bin/hw/android.hardware.composer.hwc3-service.drm
class hal animation
+ interface aidl android.hardware.graphics.composer3.IComposer/default
user system
group graphics drmrpc
capabilities SYS_NICE
diff --git a/hwc3/meson.build b/hwc3/meson.build
index b1eb9c3..2486212 100644
--- a/hwc3/meson.build
+++ b/hwc3/meson.build
@@ -4,15 +4,17 @@
'Composer.cpp',
'DrmHwcThree.cpp',
'service.cpp',
+ 'ComposerResources.cpp',
+ 'Utils.cpp',
)
executable(
'android.hardware.composer.hwc3-service.drm',
src_hwc3,
- cpp_args : common_cpp_flags,
+ cpp_args : common_cpp_flags + hwc2_cpp_flags,
dependencies : deps,
install : true,
- link_with: drmhwc_common,
+ link_with: [drmhwc_common, drmhwc_hwc2_common],
install_dir : get_option('bindir') / 'hw',
include_directories: inc_include,
)
diff --git a/hwc3/service.cpp b/hwc3/service.cpp
index f7527b7..920260a 100644
--- a/hwc3/service.cpp
+++ b/hwc3/service.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2022, The Android Open Source Project
+ * Copyright 2024, 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.
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#define LOG_TAG "drmhwc"
+#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
+
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <binder/ProcessState.h>
diff --git a/meson.build b/meson.build
index 113cb50..e9a86ec 100644
--- a/meson.build
+++ b/meson.build
@@ -35,6 +35,9 @@
dependency('sync'),
dependency('ui'),
dependency('utils'),
+ dependency('aidlcommonsupport'),
+ dependency('android.hardware.graphics.composer@2.1-resources'),
+ dependency('android.hardware.graphics.composer@2.2-resources'),
]
common_cpp_flags = [