Adds a ClientFrameComposer which forces client composition
... which is useful for running Cuttlefish on QEMU where we have
accelerated rendering with virglrenderer but do not have the host
setup for HostFrameComposer.
Bug: b/227508739
Test: cvd start --vm_manager=qemu_cli
Change-Id: Ib6d0b335346bd78212a292e36efa6cbab8ed50d4
diff --git a/system/hwc3/Android.mk b/system/hwc3/Android.mk
index a07733d..3d30e89 100644
--- a/system/hwc3/Android.mk
+++ b/system/hwc3/Android.mk
@@ -74,6 +74,7 @@
system/core/libsync/include \
LOCAL_SRC_FILES := \
+ ClientFrameComposer.cpp \
Common.cpp \
Composer.cpp \
ComposerClient.cpp \
diff --git a/system/hwc3/ClientFrameComposer.cpp b/system/hwc3/ClientFrameComposer.cpp
new file mode 100644
index 0000000..d7f8b55
--- /dev/null
+++ b/system/hwc3/ClientFrameComposer.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2022 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 "ClientFrameComposer.h"
+
+#include <android-base/parseint.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <android/hardware/graphics/common/1.0/types.h>
+#include <device_config_shared.h>
+#include <drm_fourcc.h>
+#include <libyuv.h>
+#include <sync/sync.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
+
+#include "Display.h"
+#include "Drm.h"
+#include "Layer.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+HWC3::Error ClientFrameComposer::init() {
+ DEBUG_LOG("%s", __FUNCTION__);
+
+ HWC3::Error error = mDrmPresenter.init();
+ if (error != HWC3::Error::None) {
+ ALOGE("%s: failed to initialize DrmPresenter", __FUNCTION__);
+ return error;
+ }
+
+ return HWC3::Error::None;
+}
+
+HWC3::Error ClientFrameComposer::registerOnHotplugCallback(
+ const HotplugCallback& cb) {
+ return mDrmPresenter.registerOnHotplugCallback(cb);
+ return HWC3::Error::None;
+}
+
+HWC3::Error ClientFrameComposer::unregisterOnHotplugCallback() {
+ return mDrmPresenter.unregisterOnHotplugCallback();
+}
+
+HWC3::Error ClientFrameComposer::onDisplayCreate(Display* display) {
+ const auto displayId = display->getId();
+ DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId);
+
+ // Ensure created.
+ mDisplayInfos.emplace(displayId, DisplayInfo{});
+
+ return HWC3::Error::None;
+}
+
+HWC3::Error ClientFrameComposer::onDisplayDestroy(Display* display) {
+ const auto displayId = display->getId();
+ DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId);
+
+ auto it = mDisplayInfos.find(displayId);
+ if (it == mDisplayInfos.end()) {
+ ALOGE("%s: display:%" PRIu64 " missing display buffers?", __FUNCTION__,
+ displayId);
+ return HWC3::Error::BadDisplay;
+ }
+
+ mDisplayInfos.erase(it);
+
+ return HWC3::Error::None;
+}
+
+HWC3::Error ClientFrameComposer::onDisplayClientTargetSet(Display* display) {
+ const auto displayId = display->getId();
+ DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId);
+
+ auto it = mDisplayInfos.find(displayId);
+ if (it == mDisplayInfos.end()) {
+ ALOGE("%s: display:%" PRIu64 " missing display buffers?", __FUNCTION__,
+ displayId);
+ return HWC3::Error::BadDisplay;
+ }
+
+ DisplayInfo& displayInfo = it->second;
+
+ auto [drmBufferCreateError, drmBuffer] =
+ mDrmPresenter.create(display->getClientTarget().getBuffer());
+ if (drmBufferCreateError != HWC3::Error::None) {
+ ALOGE("%s: display:%" PRIu64 " failed to create client target drm buffer",
+ __FUNCTION__, displayId);
+ return HWC3::Error::NoResources;
+ }
+ displayInfo.clientTargetDrmBuffer = std::move(drmBuffer);
+
+ return HWC3::Error::None;
+}
+
+HWC3::Error ClientFrameComposer::onActiveConfigChange(Display* /*display*/) {
+ return HWC3::Error::None;
+};
+
+HWC3::Error ClientFrameComposer::validateDisplay(Display* display,
+ DisplayChanges* outChanges) {
+ const auto displayId = display->getId();
+ DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId);
+
+ const std::vector<Layer*>& layers = display->getOrderedLayers();
+
+ for (Layer* layer : layers) {
+ const auto layerId = layer->getId();
+ const auto layerCompositionType = layer->getCompositionType();
+
+ if (layerCompositionType != Composition::CLIENT) {
+ outChanges->addLayerCompositionChange(displayId, layerId, Composition::CLIENT);
+ continue;
+ }
+ }
+
+ return HWC3::Error::None;
+}
+
+HWC3::Error ClientFrameComposer::presentDisplay(
+ Display* display, ::android::base::unique_fd* outDisplayFence,
+ std::unordered_map<int64_t,
+ ::android::base::unique_fd>* /*outLayerFences*/) {
+ const auto displayId = display->getId();
+ DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId);
+
+ auto displayInfoIt = mDisplayInfos.find(displayId);
+ if (displayInfoIt == mDisplayInfos.end()) {
+ ALOGE("%s: failed to find display buffers for display:%" PRIu64,
+ __FUNCTION__, displayId);
+ return HWC3::Error::BadDisplay;
+ }
+
+ DisplayInfo& displayInfo = displayInfoIt->second;
+
+ ::android::base::unique_fd fence = display->getClientTarget().getFence();
+
+ auto [flushError, flushCompleteFence] = mDrmPresenter.flushToDisplay(
+ displayId, *displayInfo.clientTargetDrmBuffer, fence);
+ if (flushError != HWC3::Error::None) {
+ ALOGE("%s: display:%" PRIu64 " failed to flush drm buffer" PRIu64,
+ __FUNCTION__, displayId);
+ }
+
+ *outDisplayFence = std::move(flushCompleteFence);
+ return flushError;
+}
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/ClientFrameComposer.h b/system/hwc3/ClientFrameComposer.h
new file mode 100644
index 0000000..3fb0ba8
--- /dev/null
+++ b/system/hwc3/ClientFrameComposer.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2022 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_HWC_CLIENTFRAMECOMPOSER_H
+#define ANDROID_HWC_CLIENTFRAMECOMPOSER_H
+
+#include "Common.h"
+#include "Display.h"
+#include "DrmPresenter.h"
+#include "FrameComposer.h"
+#include "Gralloc.h"
+#include "Layer.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+// A frame composer which always fallsback to client composition
+// (a.k.a make SurfaceFlinger do the composition).
+class ClientFrameComposer : public FrameComposer {
+ public:
+ ClientFrameComposer() = default;
+
+ ClientFrameComposer(const ClientFrameComposer&) = delete;
+ ClientFrameComposer& operator=(const ClientFrameComposer&) = delete;
+
+ ClientFrameComposer(ClientFrameComposer&&) = delete;
+ ClientFrameComposer& operator=(ClientFrameComposer&&) = delete;
+
+ HWC3::Error init() override;
+
+ HWC3::Error registerOnHotplugCallback(const HotplugCallback& cb) override;
+
+ HWC3::Error unregisterOnHotplugCallback() override;
+
+ HWC3::Error onDisplayCreate(Display* display) override;
+
+ HWC3::Error onDisplayDestroy(Display* display) override;
+
+ HWC3::Error onDisplayClientTargetSet(Display* display) override;
+
+ HWC3::Error onActiveConfigChange(Display* display) override;
+
+ // Determines if this composer can compose the given layers on the given
+ // display and requests changes for layers that can't not be composed.
+ HWC3::Error validateDisplay(Display* display,
+ DisplayChanges* outChanges) override;
+
+ // Performs the actual composition of layers and presents the composed result
+ // to the display.
+ HWC3::Error presentDisplay(
+ Display* display, ::android::base::unique_fd* outDisplayFence,
+ std::unordered_map<int64_t, ::android::base::unique_fd>* outLayerFences)
+ override;
+
+ private:
+ struct DisplayInfo {
+ std::unique_ptr<DrmBuffer> clientTargetDrmBuffer;;
+ };
+
+ std::unordered_map<int64_t, DisplayInfo> mDisplayInfos;
+
+ DrmPresenter mDrmPresenter;
+};
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
+
+#endif
diff --git a/system/hwc3/Common.cpp b/system/hwc3/Common.cpp
index 1c7a463..497f764 100644
--- a/system/hwc3/Common.cpp
+++ b/system/hwc3/Common.cpp
@@ -31,8 +31,15 @@
}
bool IsNoOpMode() {
- return ::android::base::GetProperty("ro.vendor.hwcomposer.mode", "") ==
- "noop";
+ const std::string mode = ::android::base::GetProperty("ro.vendor.hwcomposer.mode", "");
+ DEBUG_LOG("%s: sysprop ro.vendor.hwcomposer.mode is %s", __FUNCTION__, mode.c_str());
+ return mode == "noop";
+}
+
+bool IsClientCompositionMode() {
+ const std::string mode = ::android::base::GetProperty("ro.vendor.hwcomposer.mode", "");
+ DEBUG_LOG("%s: sysprop ro.vendor.hwcomposer.mode is %s", __FUNCTION__, mode.c_str());
+ return mode == "client";
}
std::string toString(HWC3::Error error) {
diff --git a/system/hwc3/Common.h b/system/hwc3/Common.h
index fd3d2b7..5b6587e 100644
--- a/system/hwc3/Common.h
+++ b/system/hwc3/Common.h
@@ -45,6 +45,7 @@
bool IsCuttlefish();
bool IsCuttlefishFoldable();
bool IsNoOpMode();
+bool IsClientCompositionMode();
namespace HWC3 {
enum class Error : int32_t {
diff --git a/system/hwc3/Device.cpp b/system/hwc3/Device.cpp
index cad67d5..cf4be42 100644
--- a/system/hwc3/Device.cpp
+++ b/system/hwc3/Device.cpp
@@ -20,6 +20,7 @@
#include <android-base/properties.h>
#include <json/json.h>
+#include "ClientFrameComposer.h"
#include "FrameComposer.h"
#include "GuestFrameComposer.h"
#include "HostFrameComposer.h"
@@ -96,6 +97,9 @@
if (IsNoOpMode()) {
DEBUG_LOG("%s: using NoOpFrameComposer", __FUNCTION__);
mComposer = std::make_unique<NoOpFrameComposer>();
+ } else if (IsClientCompositionMode()) {
+ DEBUG_LOG("%s: using ClientFrameComposer", __FUNCTION__);
+ mComposer = std::make_unique<ClientFrameComposer>();
} else if (shouldUseGuestComposer()) {
DEBUG_LOG("%s: using GuestFrameComposer", __FUNCTION__);
mComposer = std::make_unique<GuestFrameComposer>();