aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Macnak <natsu@google.com>2022-10-07 11:06:41 -0700
committerJason Macnak <natsu@google.com>2022-10-11 10:33:05 -0700
commitda49cb770d1a06f145b110827d685df7d3f24ac3 (patch)
treee1a5f74f42af60f7fe0c43418de44f11c3b39b5f
parentad3b3de56f49d50180a47535243e245ce4ea8226 (diff)
downloadgoldfish-opengl-da49cb770d1a06f145b110827d685df7d3f24ac3.tar.gz
Handle display hotplug (connect/disconnect)
Adds classes for many of the DRM objects for easier handling. Updates display disconnect (see DrmDisplay::onDisconnect()) to disconnect any existing framebuffer from its configured plane so that the virtio-gpu kernel module will send a command to disable the scanout on the host. Updates the frontend (ComposerClient::destroyDisplayLocked()) to also set the PowerMode to OFF before destroying the frontend display object. Bug: b/163864461 Test: cvd start Test: cvd display list Test: cvd display add --width=600 --height=600 Test: cvd display add --width=500 --height=400 Test: cvd display list Test: cvd display remove 1 Test: cvd display remove 2 Change-Id: Icf82a013e9919da13ce75e27c663ee3b88202ed5
-rw-r--r--system/hwc3/Android.mk10
-rw-r--r--system/hwc3/ClientFrameComposer.cpp14
-rw-r--r--system/hwc3/ClientFrameComposer.h8
-rw-r--r--system/hwc3/ComposerClient.cpp6
-rw-r--r--system/hwc3/DisplayFinder.cpp8
-rw-r--r--system/hwc3/DisplayFinder.h4
-rw-r--r--system/hwc3/Drm.cpp288
-rw-r--r--system/hwc3/DrmAtomicRequest.cpp58
-rw-r--r--system/hwc3/DrmAtomicRequest.h50
-rw-r--r--system/hwc3/DrmBuffer.cpp27
-rw-r--r--system/hwc3/DrmBuffer.h62
-rw-r--r--system/hwc3/DrmClient.cpp310
-rw-r--r--system/hwc3/DrmClient.h109
-rw-r--r--system/hwc3/DrmConnector.cpp122
-rw-r--r--system/hwc3/DrmConnector.h85
-rw-r--r--system/hwc3/DrmCrtc.cpp34
-rw-r--r--system/hwc3/DrmCrtc.h70
-rw-r--r--system/hwc3/DrmDisplay.cpp214
-rw-r--r--system/hwc3/DrmDisplay.h90
-rw-r--r--system/hwc3/DrmEventListener.cpp103
-rw-r--r--system/hwc3/DrmEventListener.h55
-rw-r--r--system/hwc3/DrmMode.cpp38
-rw-r--r--system/hwc3/DrmMode.h78
-rw-r--r--system/hwc3/DrmPlane.cpp46
-rw-r--r--system/hwc3/DrmPlane.h100
-rw-r--r--system/hwc3/DrmPresenter.cpp750
-rw-r--r--system/hwc3/DrmPresenter.h202
-rw-r--r--system/hwc3/DrmProperty.h97
-rw-r--r--system/hwc3/FrameComposer.h4
-rw-r--r--system/hwc3/GuestFrameComposer.cpp20
-rw-r--r--system/hwc3/GuestFrameComposer.h8
-rw-r--r--system/hwc3/HostFrameComposer.cpp36
-rw-r--r--system/hwc3/HostFrameComposer.h10
-rw-r--r--system/hwc3/NoOpFrameComposer.h2
34 files changed, 1964 insertions, 1154 deletions
diff --git a/system/hwc3/Android.mk b/system/hwc3/Android.mk
index 3d30e89b..a0d08437 100644
--- a/system/hwc3/Android.mk
+++ b/system/hwc3/Android.mk
@@ -84,7 +84,15 @@ LOCAL_SRC_FILES := \
DisplayConfig.cpp \
DisplayFinder.cpp \
Drm.cpp \
- DrmPresenter.cpp \
+ DrmAtomicRequest.cpp \
+ DrmBuffer.cpp \
+ DrmClient.cpp \
+ DrmConnector.cpp \
+ DrmCrtc.cpp \
+ DrmDisplay.cpp \
+ DrmEventListener.cpp \
+ DrmMode.cpp \
+ DrmPlane.cpp \
Gralloc.cpp \
GuestFrameComposer.cpp \
HostFrameComposer.cpp \
diff --git a/system/hwc3/ClientFrameComposer.cpp b/system/hwc3/ClientFrameComposer.cpp
index 284a46f9..85ba90f6 100644
--- a/system/hwc3/ClientFrameComposer.cpp
+++ b/system/hwc3/ClientFrameComposer.cpp
@@ -37,9 +37,9 @@ namespace aidl::android::hardware::graphics::composer3::impl {
HWC3::Error ClientFrameComposer::init() {
DEBUG_LOG("%s", __FUNCTION__);
- HWC3::Error error = mDrmPresenter.init();
+ HWC3::Error error = mDrmClient.init();
if (error != HWC3::Error::None) {
- ALOGE("%s: failed to initialize DrmPresenter", __FUNCTION__);
+ ALOGE("%s: failed to initialize DrmClient", __FUNCTION__);
return error;
}
@@ -48,12 +48,12 @@ HWC3::Error ClientFrameComposer::init() {
HWC3::Error ClientFrameComposer::registerOnHotplugCallback(
const HotplugCallback& cb) {
- return mDrmPresenter.registerOnHotplugCallback(cb);
+ return mDrmClient.registerOnHotplugCallback(cb);
return HWC3::Error::None;
}
HWC3::Error ClientFrameComposer::unregisterOnHotplugCallback() {
- return mDrmPresenter.unregisterOnHotplugCallback();
+ return mDrmClient.unregisterOnHotplugCallback();
}
HWC3::Error ClientFrameComposer::onDisplayCreate(Display* display) {
@@ -96,7 +96,7 @@ HWC3::Error ClientFrameComposer::onDisplayClientTargetSet(Display* display) {
DisplayInfo& displayInfo = it->second;
auto [drmBufferCreateError, drmBuffer] =
- mDrmPresenter.create(display->getClientTarget().getBuffer());
+ mDrmClient.create(display->getClientTarget().getBuffer());
if (drmBufferCreateError != HWC3::Error::None) {
ALOGE("%s: display:%" PRIu64 " failed to create client target drm buffer",
__FUNCTION__, displayId);
@@ -154,8 +154,8 @@ HWC3::Error ClientFrameComposer::presentDisplay(
::android::base::unique_fd fence = display->getClientTarget().getFence();
- auto [flushError, flushCompleteFence] = mDrmPresenter.flushToDisplay(
- displayId, *displayInfo.clientTargetDrmBuffer, fence);
+ auto [flushError, flushCompleteFence] = mDrmClient.flushToDisplay(
+ displayId, displayInfo.clientTargetDrmBuffer, fence);
if (flushError != HWC3::Error::None) {
ALOGE("%s: display:%" PRIu64 " failed to flush drm buffer" PRIu64,
__FUNCTION__, displayId);
diff --git a/system/hwc3/ClientFrameComposer.h b/system/hwc3/ClientFrameComposer.h
index 28199b3d..87988072 100644
--- a/system/hwc3/ClientFrameComposer.h
+++ b/system/hwc3/ClientFrameComposer.h
@@ -19,7 +19,7 @@
#include "Common.h"
#include "Display.h"
-#include "DrmPresenter.h"
+#include "DrmClient.h"
#include "FrameComposer.h"
#include "Gralloc.h"
#include "Layer.h"
@@ -64,8 +64,8 @@ class ClientFrameComposer : public FrameComposer {
std::unordered_map<int64_t, ::android::base::unique_fd>* outLayerFences)
override;
- const DrmPresenter* getDrmPresenter() const override {
- return &mDrmPresenter;
+ const DrmClient* getDrmPresenter() const override {
+ return &mDrmClient;
}
private:
@@ -75,7 +75,7 @@ class ClientFrameComposer : public FrameComposer {
std::unordered_map<int64_t, DisplayInfo> mDisplayInfos;
- DrmPresenter mDrmPresenter;
+ DrmClient mDrmClient;
};
} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/ComposerClient.cpp b/system/hwc3/ComposerClient.cpp
index 20984350..f7ba42e0 100644
--- a/system/hwc3/ComposerClient.cpp
+++ b/system/hwc3/ComposerClient.cpp
@@ -1284,6 +1284,8 @@ HWC3::Error ComposerClient::createDisplayLocked(
return error;
}
+ display->setPowerMode(PowerMode::ON);
+
DEBUG_LOG("%s: adding display:%" PRIu64, __FUNCTION__, displayId);
mDisplays.emplace(displayId, std::move(display));
@@ -1320,6 +1322,10 @@ HWC3::Error ComposerClient::destroyDisplayLocked(int64_t displayId) {
return HWC3::Error::BadDisplay;
}
+ Display* display = it->second.get();
+
+ display->setPowerMode(PowerMode::OFF);
+
HWC3::Error error = mComposer->onDisplayDestroy(it->second.get());
if (error != HWC3::Error::None) {
ALOGE("%s: display:%" PRId64 " failed to destroy with frame composer",
diff --git a/system/hwc3/DisplayFinder.cpp b/system/hwc3/DisplayFinder.cpp
index 10bd5fdb..1b45d0af 100644
--- a/system/hwc3/DisplayFinder.cpp
+++ b/system/hwc3/DisplayFinder.cpp
@@ -213,11 +213,11 @@ HWC3::Error findNoOpDisplays(std::vector<DisplayMultiConfigs>* outDisplays) {
return HWC3::Error::None;
}
-HWC3::Error findDrmDisplays(const DrmPresenter& drm,
+HWC3::Error findDrmDisplays(const DrmClient& drm,
std::vector<DisplayMultiConfigs>* outDisplays) {
outDisplays->clear();
- std::vector<DrmPresenter::DisplayConfig> drmDisplayConfigs;
+ std::vector<DrmClient::DisplayConfig> drmDisplayConfigs;
HWC3::Error error = drm.getDisplayConfigs(&drmDisplayConfigs);
if (error != HWC3::Error::None) {
@@ -225,7 +225,7 @@ HWC3::Error findDrmDisplays(const DrmPresenter& drm,
return error;
}
- for (const DrmPresenter::DisplayConfig drmDisplayConfig : drmDisplayConfigs) {
+ for (const DrmClient::DisplayConfig drmDisplayConfig : drmDisplayConfigs) {
outDisplays->push_back(DisplayMultiConfigs{
.displayId = drmDisplayConfig.id,
.activeConfigId = static_cast<int32_t>(drmDisplayConfig.id),
@@ -245,7 +245,7 @@ HWC3::Error findDrmDisplays(const DrmPresenter& drm,
} // namespace
-HWC3::Error findDisplays(const DrmPresenter* drm,
+HWC3::Error findDisplays(const DrmClient* drm,
std::vector<DisplayMultiConfigs>* outDisplays) {
HWC3::Error error = HWC3::Error::None;
if (IsInNoOpCompositionMode()) {
diff --git a/system/hwc3/DisplayFinder.h b/system/hwc3/DisplayFinder.h
index 171d2048..963e4c17 100644
--- a/system/hwc3/DisplayFinder.h
+++ b/system/hwc3/DisplayFinder.h
@@ -22,7 +22,7 @@
#include "Common.h"
#include "DisplayConfig.h"
-#include "DrmPresenter.h"
+#include "DrmClient.h"
namespace aidl::android::hardware::graphics::composer3::impl {
@@ -33,7 +33,7 @@ struct DisplayMultiConfigs {
std::vector<DisplayConfig> configs;
};
-HWC3::Error findDisplays(const DrmPresenter* drm,
+HWC3::Error findDisplays(const DrmClient* drm,
std::vector<DisplayMultiConfigs>* outDisplays);
} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/Drm.cpp b/system/hwc3/Drm.cpp
index 6872eb4d..d5cf1d7c 100644
--- a/system/hwc3/Drm.cpp
+++ b/system/hwc3/Drm.cpp
@@ -23,158 +23,158 @@
namespace aidl::android::hardware::graphics::composer3::impl {
const char* GetDrmFormatString(uint32_t drm_format) {
- switch (drm_format) {
- case DRM_FORMAT_ABGR1555:
- return "DRM_FORMAT_ABGR1555";
- case DRM_FORMAT_ABGR2101010:
- return "DRM_FORMAT_ABGR2101010";
- case DRM_FORMAT_ABGR4444:
- return "DRM_FORMAT_ABGR4444";
- case DRM_FORMAT_ABGR8888:
- return "DRM_FORMAT_ABGR8888";
- case DRM_FORMAT_ARGB1555:
- return "DRM_FORMAT_ARGB1555";
- case DRM_FORMAT_ARGB2101010:
- return "DRM_FORMAT_ARGB2101010";
- case DRM_FORMAT_ARGB4444:
- return "DRM_FORMAT_ARGB4444";
- case DRM_FORMAT_ARGB8888:
- return "DRM_FORMAT_ARGB8888";
- case DRM_FORMAT_AYUV:
- return "DRM_FORMAT_AYUV";
- case DRM_FORMAT_BGR233:
- return "DRM_FORMAT_BGR233";
- case DRM_FORMAT_BGR565:
- return "DRM_FORMAT_BGR565";
- case DRM_FORMAT_BGR888:
- return "DRM_FORMAT_BGR888";
- case DRM_FORMAT_BGRA1010102:
- return "DRM_FORMAT_BGRA1010102";
- case DRM_FORMAT_BGRA4444:
- return "DRM_FORMAT_BGRA4444";
- case DRM_FORMAT_BGRA5551:
- return "DRM_FORMAT_BGRA5551";
- case DRM_FORMAT_BGRA8888:
- return "DRM_FORMAT_BGRA8888";
- case DRM_FORMAT_BGRX1010102:
- return "DRM_FORMAT_BGRX1010102";
- case DRM_FORMAT_BGRX4444:
- return "DRM_FORMAT_BGRX4444";
- case DRM_FORMAT_BGRX5551:
- return "DRM_FORMAT_BGRX5551";
- case DRM_FORMAT_BGRX8888:
- return "DRM_FORMAT_BGRX8888";
- case DRM_FORMAT_C8:
- return "DRM_FORMAT_C8";
- case DRM_FORMAT_GR88:
- return "DRM_FORMAT_GR88";
- case DRM_FORMAT_NV12:
- return "DRM_FORMAT_NV12";
- case DRM_FORMAT_NV21:
- return "DRM_FORMAT_NV21";
- case DRM_FORMAT_R8:
- return "DRM_FORMAT_R8";
- case DRM_FORMAT_RG88:
- return "DRM_FORMAT_RG88";
- case DRM_FORMAT_RGB332:
- return "DRM_FORMAT_RGB332";
- case DRM_FORMAT_RGB565:
- return "DRM_FORMAT_RGB565";
- case DRM_FORMAT_RGB888:
- return "DRM_FORMAT_RGB888";
- case DRM_FORMAT_RGBA1010102:
- return "DRM_FORMAT_RGBA1010102";
- case DRM_FORMAT_RGBA4444:
- return "DRM_FORMAT_RGBA4444";
- case DRM_FORMAT_RGBA5551:
- return "DRM_FORMAT_RGBA5551";
- case DRM_FORMAT_RGBA8888:
- return "DRM_FORMAT_RGBA8888";
- case DRM_FORMAT_RGBX1010102:
- return "DRM_FORMAT_RGBX1010102";
- case DRM_FORMAT_RGBX4444:
- return "DRM_FORMAT_RGBX4444";
- case DRM_FORMAT_RGBX5551:
- return "DRM_FORMAT_RGBX5551";
- case DRM_FORMAT_RGBX8888:
- return "DRM_FORMAT_RGBX8888";
- case DRM_FORMAT_UYVY:
- return "DRM_FORMAT_UYVY";
- case DRM_FORMAT_VYUY:
- return "DRM_FORMAT_VYUY";
- case DRM_FORMAT_XBGR1555:
- return "DRM_FORMAT_XBGR1555";
- case DRM_FORMAT_XBGR2101010:
- return "DRM_FORMAT_XBGR2101010";
- case DRM_FORMAT_XBGR4444:
- return "DRM_FORMAT_XBGR4444";
- case DRM_FORMAT_XBGR8888:
- return "DRM_FORMAT_XBGR8888";
- case DRM_FORMAT_XRGB1555:
- return "DRM_FORMAT_XRGB1555";
- case DRM_FORMAT_XRGB2101010:
- return "DRM_FORMAT_XRGB2101010";
- case DRM_FORMAT_XRGB4444:
- return "DRM_FORMAT_XRGB4444";
- case DRM_FORMAT_XRGB8888:
- return "DRM_FORMAT_XRGB8888";
- case DRM_FORMAT_YUYV:
- return "DRM_FORMAT_YUYV";
- case DRM_FORMAT_YVU420:
- return "DRM_FORMAT_YVU420";
- case DRM_FORMAT_YVYU:
- return "DRM_FORMAT_YVYU";
- }
- return "Unknown";
+ switch (drm_format) {
+ case DRM_FORMAT_ABGR1555:
+ return "DRM_FORMAT_ABGR1555";
+ case DRM_FORMAT_ABGR2101010:
+ return "DRM_FORMAT_ABGR2101010";
+ case DRM_FORMAT_ABGR4444:
+ return "DRM_FORMAT_ABGR4444";
+ case DRM_FORMAT_ABGR8888:
+ return "DRM_FORMAT_ABGR8888";
+ case DRM_FORMAT_ARGB1555:
+ return "DRM_FORMAT_ARGB1555";
+ case DRM_FORMAT_ARGB2101010:
+ return "DRM_FORMAT_ARGB2101010";
+ case DRM_FORMAT_ARGB4444:
+ return "DRM_FORMAT_ARGB4444";
+ case DRM_FORMAT_ARGB8888:
+ return "DRM_FORMAT_ARGB8888";
+ case DRM_FORMAT_AYUV:
+ return "DRM_FORMAT_AYUV";
+ case DRM_FORMAT_BGR233:
+ return "DRM_FORMAT_BGR233";
+ case DRM_FORMAT_BGR565:
+ return "DRM_FORMAT_BGR565";
+ case DRM_FORMAT_BGR888:
+ return "DRM_FORMAT_BGR888";
+ case DRM_FORMAT_BGRA1010102:
+ return "DRM_FORMAT_BGRA1010102";
+ case DRM_FORMAT_BGRA4444:
+ return "DRM_FORMAT_BGRA4444";
+ case DRM_FORMAT_BGRA5551:
+ return "DRM_FORMAT_BGRA5551";
+ case DRM_FORMAT_BGRA8888:
+ return "DRM_FORMAT_BGRA8888";
+ case DRM_FORMAT_BGRX1010102:
+ return "DRM_FORMAT_BGRX1010102";
+ case DRM_FORMAT_BGRX4444:
+ return "DRM_FORMAT_BGRX4444";
+ case DRM_FORMAT_BGRX5551:
+ return "DRM_FORMAT_BGRX5551";
+ case DRM_FORMAT_BGRX8888:
+ return "DRM_FORMAT_BGRX8888";
+ case DRM_FORMAT_C8:
+ return "DRM_FORMAT_C8";
+ case DRM_FORMAT_GR88:
+ return "DRM_FORMAT_GR88";
+ case DRM_FORMAT_NV12:
+ return "DRM_FORMAT_NV12";
+ case DRM_FORMAT_NV21:
+ return "DRM_FORMAT_NV21";
+ case DRM_FORMAT_R8:
+ return "DRM_FORMAT_R8";
+ case DRM_FORMAT_RG88:
+ return "DRM_FORMAT_RG88";
+ case DRM_FORMAT_RGB332:
+ return "DRM_FORMAT_RGB332";
+ case DRM_FORMAT_RGB565:
+ return "DRM_FORMAT_RGB565";
+ case DRM_FORMAT_RGB888:
+ return "DRM_FORMAT_RGB888";
+ case DRM_FORMAT_RGBA1010102:
+ return "DRM_FORMAT_RGBA1010102";
+ case DRM_FORMAT_RGBA4444:
+ return "DRM_FORMAT_RGBA4444";
+ case DRM_FORMAT_RGBA5551:
+ return "DRM_FORMAT_RGBA5551";
+ case DRM_FORMAT_RGBA8888:
+ return "DRM_FORMAT_RGBA8888";
+ case DRM_FORMAT_RGBX1010102:
+ return "DRM_FORMAT_RGBX1010102";
+ case DRM_FORMAT_RGBX4444:
+ return "DRM_FORMAT_RGBX4444";
+ case DRM_FORMAT_RGBX5551:
+ return "DRM_FORMAT_RGBX5551";
+ case DRM_FORMAT_RGBX8888:
+ return "DRM_FORMAT_RGBX8888";
+ case DRM_FORMAT_UYVY:
+ return "DRM_FORMAT_UYVY";
+ case DRM_FORMAT_VYUY:
+ return "DRM_FORMAT_VYUY";
+ case DRM_FORMAT_XBGR1555:
+ return "DRM_FORMAT_XBGR1555";
+ case DRM_FORMAT_XBGR2101010:
+ return "DRM_FORMAT_XBGR2101010";
+ case DRM_FORMAT_XBGR4444:
+ return "DRM_FORMAT_XBGR4444";
+ case DRM_FORMAT_XBGR8888:
+ return "DRM_FORMAT_XBGR8888";
+ case DRM_FORMAT_XRGB1555:
+ return "DRM_FORMAT_XRGB1555";
+ case DRM_FORMAT_XRGB2101010:
+ return "DRM_FORMAT_XRGB2101010";
+ case DRM_FORMAT_XRGB4444:
+ return "DRM_FORMAT_XRGB4444";
+ case DRM_FORMAT_XRGB8888:
+ return "DRM_FORMAT_XRGB8888";
+ case DRM_FORMAT_YUYV:
+ return "DRM_FORMAT_YUYV";
+ case DRM_FORMAT_YVU420:
+ return "DRM_FORMAT_YVU420";
+ case DRM_FORMAT_YVYU:
+ return "DRM_FORMAT_YVYU";
+ }
+ return "Unknown";
}
int GetDrmFormatBytesPerPixel(uint32_t drm_format) {
- switch (drm_format) {
- case DRM_FORMAT_ABGR8888:
- case DRM_FORMAT_ARGB8888:
- case DRM_FORMAT_XBGR8888:
- return 4;
- case DRM_FORMAT_BGR888:
- return 3;
- case DRM_FORMAT_RGB565:
- case DRM_FORMAT_YVU420:
+ switch (drm_format) {
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XBGR8888:
+ return 4;
+ case DRM_FORMAT_BGR888:
+ return 3;
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_YVU420:
#ifdef GRALLOC_MODULE_API_VERSION_0_2
- case DRM_FORMAT_FLEX_YCbCr_420_888:
+ case DRM_FORMAT_FLEX_YCbCr_420_888:
#endif
- return 2;
- case DRM_FORMAT_R8:
- return 1;
- }
- ALOGE("%s: format size unknown %d(%s)", __FUNCTION__, drm_format,
- GetDrmFormatString(drm_format));
- return 8;
+ return 2;
+ case DRM_FORMAT_R8:
+ return 1;
+ }
+ ALOGE("%s: format size unknown %d(%s)", __FUNCTION__, drm_format,
+ GetDrmFormatString(drm_format));
+ return 8;
}
int GetDrmFormatFromHalFormat(int hal_format) {
- switch (hal_format) {
- case HAL_PIXEL_FORMAT_RGBA_FP16:
- return DRM_FORMAT_ABGR16161616F;
- case HAL_PIXEL_FORMAT_RGBA_8888:
- return DRM_FORMAT_ABGR8888;
- case HAL_PIXEL_FORMAT_RGBX_8888:
- return DRM_FORMAT_XBGR8888;
- case HAL_PIXEL_FORMAT_BGRA_8888:
- return DRM_FORMAT_ARGB8888;
- case HAL_PIXEL_FORMAT_RGB_888:
- return DRM_FORMAT_BGR888;
- case HAL_PIXEL_FORMAT_RGB_565:
- return DRM_FORMAT_BGR565;
- case HAL_PIXEL_FORMAT_YV12:
- return DRM_FORMAT_YVU420;
- case HAL_PIXEL_FORMAT_YCbCr_420_888:
- return DRM_FORMAT_YVU420;
- case HAL_PIXEL_FORMAT_BLOB:
- return DRM_FORMAT_R8;
- default:
- break;
- }
- ALOGE("%s unhandled hal format: %d", __FUNCTION__, hal_format);
- return 0;
+ switch (hal_format) {
+ case HAL_PIXEL_FORMAT_RGBA_FP16:
+ return DRM_FORMAT_ABGR16161616F;
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ return DRM_FORMAT_ABGR8888;
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ return DRM_FORMAT_XBGR8888;
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ return DRM_FORMAT_ARGB8888;
+ case HAL_PIXEL_FORMAT_RGB_888:
+ return DRM_FORMAT_BGR888;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ return DRM_FORMAT_BGR565;
+ case HAL_PIXEL_FORMAT_YV12:
+ return DRM_FORMAT_YVU420;
+ case HAL_PIXEL_FORMAT_YCbCr_420_888:
+ return DRM_FORMAT_YVU420;
+ case HAL_PIXEL_FORMAT_BLOB:
+ return DRM_FORMAT_R8;
+ default:
+ break;
+ }
+ ALOGE("%s unhandled hal format: %d", __FUNCTION__, hal_format);
+ return 0;
}
} // namespace aidl::android::hardware::graphics::composer3::impl \ No newline at end of file
diff --git a/system/hwc3/DrmAtomicRequest.cpp b/system/hwc3/DrmAtomicRequest.cpp
new file mode 100644
index 00000000..63e5c10a
--- /dev/null
+++ b/system/hwc3/DrmAtomicRequest.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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 "DrmAtomicRequest.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+std::unique_ptr<DrmAtomicRequest> DrmAtomicRequest::create() {
+ drmModeAtomicReqPtr request = drmModeAtomicAlloc();
+ if (!request) {
+ return nullptr;
+ }
+
+ return std::unique_ptr<DrmAtomicRequest>(new DrmAtomicRequest(request));
+}
+
+DrmAtomicRequest::~DrmAtomicRequest() {
+ if (mRequest) {
+ drmModeAtomicFree(mRequest);
+ }
+}
+
+bool DrmAtomicRequest::Set(uint32_t objectId, const DrmProperty& prop, uint64_t value) {
+ int ret = drmModeAtomicAddProperty(mRequest, objectId, prop.getId(), value);
+ if (ret < 0) {
+ ALOGE("%s: failed to set atomic request property %s to %" PRIu64 ": %s", __FUNCTION__,
+ prop.getName().c_str(), value, strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+bool DrmAtomicRequest::Commit(::android::base::borrowed_fd drmFd) {
+ constexpr const uint32_t kCommitFlags = DRM_MODE_ATOMIC_ALLOW_MODESET;
+
+ int ret = drmModeAtomicCommit(drmFd.get(), mRequest, kCommitFlags, 0);
+ if (ret) {
+ ALOGE("%s:%d: atomic commit failed: %s\n", __FUNCTION__, __LINE__, strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmAtomicRequest.h b/system/hwc3/DrmAtomicRequest.h
new file mode 100644
index 00000000..862ea2f2
--- /dev/null
+++ b/system/hwc3/DrmAtomicRequest.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "Common.h"
+#include "DrmMode.h"
+#include "DrmProperty.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+class DrmAtomicRequest {
+ public:
+ static std::unique_ptr<DrmAtomicRequest> create();
+ ~DrmAtomicRequest();
+
+ bool Set(uint32_t objectId, const DrmProperty& prop, uint64_t value);
+
+ bool Commit(::android::base::borrowed_fd drmFd);
+
+ private:
+ DrmAtomicRequest(drmModeAtomicReqPtr request) : mRequest(request) {}
+
+ drmModeAtomicReqPtr mRequest;
+};
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmBuffer.cpp b/system/hwc3/DrmBuffer.cpp
new file mode 100644
index 00000000..68b5457a
--- /dev/null
+++ b/system/hwc3/DrmBuffer.cpp
@@ -0,0 +1,27 @@
+/*
+ * 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 "DrmBuffer.h"
+
+#include "DrmClient.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+DrmBuffer::DrmBuffer(DrmClient& DrmClient) : mDrmClient(DrmClient) {}
+
+DrmBuffer::~DrmBuffer() { mDrmClient.destroyDrmFramebuffer(this); }
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmBuffer.h b/system/hwc3/DrmBuffer.h
new file mode 100644
index 00000000..1d5e30af
--- /dev/null
+++ b/system/hwc3/DrmBuffer.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include <cstdint>
+#include <optional>
+#include <unordered_map>
+
+#include "Common.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+class DrmClient;
+
+// A RAII object that will clear a drm framebuffer upon destruction.
+class DrmBuffer {
+ public:
+ ~DrmBuffer();
+
+ DrmBuffer(const DrmBuffer&) = delete;
+ DrmBuffer& operator=(const DrmBuffer&) = delete;
+
+ DrmBuffer(DrmBuffer&&) = delete;
+ DrmBuffer& operator=(DrmBuffer&&) = delete;
+
+ private:
+ friend class DrmClient;
+ friend class DrmDisplay;
+ DrmBuffer(DrmClient& drmClient);
+
+ DrmClient& mDrmClient;
+
+ uint32_t mWidth = 0;
+ uint32_t mHeight = 0;
+ uint32_t mDrmFormat = 0;
+ uint32_t mPlaneFds[4] = {0, 0, 0, 0};
+ uint32_t mPlaneHandles[4] = {0, 0, 0, 0};
+ uint32_t mPlanePitches[4] = {0, 0, 0, 0};
+ uint32_t mPlaneOffsets[4] = {0, 0, 0, 0};
+ std::optional<uint32_t> mDrmFramebuffer;
+};
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmClient.cpp b/system/hwc3/DrmClient.cpp
new file mode 100644
index 00000000..581544f5
--- /dev/null
+++ b/system/hwc3/DrmClient.cpp
@@ -0,0 +1,310 @@
+/*
+ * 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 "DrmClient.h"
+
+#include <cros_gralloc_handle.h>
+
+using ::android::base::guest::AutoReadLock;
+using ::android::base::guest::AutoWriteLock;
+using ::android::base::guest::ReadWriteLock;
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+DrmClient::~DrmClient() {
+ if (mFd > 0) {
+ drmDropMaster(mFd.get());
+ }
+}
+
+HWC3::Error DrmClient::init() {
+ DEBUG_LOG("%s", __FUNCTION__);
+
+ mFd = ::android::base::unique_fd(open("/dev/dri/card0", O_RDWR | O_CLOEXEC));
+ if (mFd < 0) {
+ ALOGE("%s: failed to open drm device: %s", __FUNCTION__, strerror(errno));
+ return HWC3::Error::NoResources;
+ }
+
+ int ret = drmSetClientCap(mFd.get(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+ if (ret) {
+ ALOGE("%s: failed to set cap universal plane %s\n", __FUNCTION__, strerror(errno));
+ return HWC3::Error::NoResources;
+ }
+
+ ret = drmSetClientCap(mFd.get(), DRM_CLIENT_CAP_ATOMIC, 1);
+ if (ret) {
+ ALOGE("%s: failed to set cap atomic %s\n", __FUNCTION__, strerror(errno));
+ return HWC3::Error::NoResources;
+ }
+
+ drmSetMaster(mFd.get());
+
+ if (!drmIsMaster(mFd.get())) {
+ ALOGE("%s: failed to get master drm device", __FUNCTION__);
+ return HWC3::Error::NoResources;
+ }
+
+ {
+ AutoWriteLock lock(mDisplaysMutex);
+ bool success = loadDrmDisplays();
+ if (success) {
+ DEBUG_LOG("%s: Successfully initialized DRM backend", __FUNCTION__);
+ } else {
+ ALOGE("%s: Failed to initialize DRM backend", __FUNCTION__);
+ return HWC3::Error::NoResources;
+ }
+ }
+
+ mDrmEventListener = DrmEventListener::create(mFd, [this]() { handleHotplug(); });
+ if (!mDrmEventListener) {
+ ALOGE("%s: Failed to initialize DRM event listener", __FUNCTION__);
+ } else {
+ DEBUG_LOG("%s: Successfully initialized DRM event listener", __FUNCTION__);
+ }
+
+ DEBUG_LOG("%s: Successfully initialized.", __FUNCTION__);
+ return HWC3::Error::None;
+}
+
+HWC3::Error DrmClient::getDisplayConfigs(std::vector<DisplayConfig>* configs) const {
+ AutoReadLock lock(mDisplaysMutex);
+
+ configs->clear();
+
+ for (uint32_t i = 0; i < mDisplays.size(); i++) {
+ const auto& display = mDisplays[i];
+
+ configs->emplace_back(DisplayConfig{
+ .id = i,
+ .width = display->getWidth(),
+ .height = display->getHeight(),
+ .dpiX = 160, // static_cast<uint32_t>(connector.dpiX),
+ .dpiY = 160, // static_cast<uint32_t>(connector.dpiY),
+ .refreshRateHz = display->getRefreshRateUint(),
+ });
+ }
+
+ return HWC3::Error::None;
+}
+
+HWC3::Error DrmClient::registerOnHotplugCallback(const HotplugCallback& cb) {
+ mHotplugCallback = cb;
+ return HWC3::Error::None;
+}
+
+HWC3::Error DrmClient::unregisterOnHotplugCallback() {
+ mHotplugCallback.reset();
+ return HWC3::Error::None;
+}
+
+bool DrmClient::loadDrmDisplays() {
+ DEBUG_LOG("%s", __FUNCTION__);
+
+ std::vector<std::unique_ptr<DrmCrtc>> crtcs;
+ std::vector<std::unique_ptr<DrmConnector>> connectors;
+ std::vector<std::unique_ptr<DrmPlane>> planes;
+
+ drmModePlaneResPtr drmPlaneResources = drmModeGetPlaneResources(mFd.get());
+ for (uint32_t i = 0; i < drmPlaneResources->count_planes; ++i) {
+ const uint32_t planeId = drmPlaneResources->planes[i];
+
+ auto crtc = DrmPlane::create(mFd, planeId);
+ if (!crtc) {
+ ALOGE("%s: Failed to create DRM CRTC.", __FUNCTION__);
+ return false;
+ }
+
+ planes.emplace_back(std::move(crtc));
+ }
+ drmModeFreePlaneResources(drmPlaneResources);
+
+ drmModeRes* drmResources = drmModeGetResources(mFd.get());
+ for (uint32_t crtcIndex = 0; crtcIndex < drmResources->count_crtcs; crtcIndex++) {
+ const uint32_t crtcId = drmResources->crtcs[crtcIndex];
+
+ auto crtc = DrmCrtc::create(mFd, crtcId, crtcIndex);
+ if (!crtc) {
+ ALOGE("%s: Failed to create DRM CRTC.", __FUNCTION__);
+ return false;
+ }
+
+ crtcs.emplace_back(std::move(crtc));
+ }
+
+ for (uint32_t i = 0; i < drmResources->count_connectors; ++i) {
+ const uint32_t connectorId = drmResources->connectors[i];
+
+ auto connector = DrmConnector::create(mFd, connectorId);
+ if (!connector) {
+ ALOGE("%s: Failed to create DRM CRTC.", __FUNCTION__);
+ return false;
+ }
+
+ connectors.emplace_back(std::move(connector));
+ }
+
+ drmModeFreeResources(drmResources);
+
+ if (crtcs.size() != connectors.size()) {
+ ALOGE("%s: Failed assumption mCrtcs.size():%zu equals mConnectors.size():%zu", __FUNCTION__,
+ crtcs.size(), connectors.size());
+ return false;
+ }
+
+ for (uint32_t i = 0; i < crtcs.size(); i++) {
+ std::unique_ptr<DrmCrtc> crtc = std::move(crtcs[i]);
+ std::unique_ptr<DrmConnector> connector = std::move(connectors[i]);
+
+ auto planeIt =
+ std::find_if(planes.begin(), planes.end(), [&](const std::unique_ptr<DrmPlane>& plane) {
+ if (!plane->isOverlay() && !plane->isPrimary()) {
+ return false;
+ }
+ return plane->isCompatibleWith(*crtc);
+ });
+ if (planeIt == planes.end()) {
+ ALOGE("%s: Failed to find plane for display:%" PRIu32, __FUNCTION__, i);
+ return false;
+ }
+
+ std::unique_ptr<DrmPlane> plane = std::move(*planeIt);
+ planes.erase(planeIt);
+
+ auto display =
+ DrmDisplay::create(i, std::move(connector), std::move(crtc), std::move(plane), mFd);
+ if (!display) {
+ return false;
+ }
+ mDisplays.push_back(std::move(display));
+ }
+
+ return true;
+}
+
+std::tuple<HWC3::Error, std::shared_ptr<DrmBuffer>> DrmClient::create(
+ const native_handle_t* handle) {
+ cros_gralloc_handle* crosHandle = (cros_gralloc_handle*)handle;
+ if (crosHandle == nullptr) {
+ ALOGE("%s: invalid cros_gralloc_handle", __FUNCTION__);
+ return std::make_tuple(HWC3::Error::NoResources, nullptr);
+ }
+
+ DrmPrimeBufferHandle primeHandle = 0;
+ int ret = drmPrimeFDToHandle(mFd.get(), crosHandle->fds[0], &primeHandle);
+ if (ret) {
+ ALOGE("%s: drmPrimeFDToHandle failed: %s (errno %d)", __FUNCTION__, strerror(errno), errno);
+ return std::make_tuple(HWC3::Error::NoResources, nullptr);
+ }
+
+ auto buffer = std::shared_ptr<DrmBuffer>(new DrmBuffer(*this));
+ buffer->mWidth = crosHandle->width;
+ buffer->mHeight = crosHandle->height;
+ buffer->mDrmFormat = crosHandle->format;
+ buffer->mPlaneFds[0] = crosHandle->fds[0];
+ buffer->mPlaneHandles[0] = primeHandle;
+ buffer->mPlanePitches[0] = crosHandle->strides[0];
+ buffer->mPlaneOffsets[0] = crosHandle->offsets[0];
+
+ uint32_t framebuffer = 0;
+ ret = drmModeAddFB2(mFd.get(), buffer->mWidth, buffer->mHeight, buffer->mDrmFormat,
+ buffer->mPlaneHandles, buffer->mPlanePitches, buffer->mPlaneOffsets,
+ &framebuffer, 0);
+ if (ret) {
+ ALOGE("%s: drmModeAddFB2 failed: %s (errno %d)", __FUNCTION__, strerror(errno), errno);
+ return std::make_tuple(HWC3::Error::NoResources, nullptr);
+ }
+ DEBUG_LOG("%s: created framebuffer:%" PRIu32, __FUNCTION__, framebuffer);
+ buffer->mDrmFramebuffer = framebuffer;
+
+ return std::make_tuple(HWC3::Error::None, std::shared_ptr<DrmBuffer>(buffer));
+}
+
+HWC3::Error DrmClient::destroyDrmFramebuffer(DrmBuffer* buffer) {
+ if (buffer->mDrmFramebuffer) {
+ uint32_t framebuffer = *buffer->mDrmFramebuffer;
+ if (drmModeRmFB(mFd.get(), framebuffer)) {
+ ALOGE("%s: drmModeRmFB failed: %s (errno %d)", __FUNCTION__, strerror(errno), errno);
+ return HWC3::Error::NoResources;
+ }
+ DEBUG_LOG("%s: destroyed framebuffer:%" PRIu32, __FUNCTION__, framebuffer);
+ buffer->mDrmFramebuffer.reset();
+ }
+ if (buffer->mPlaneHandles[0]) {
+ struct drm_gem_close gem_close = {};
+ gem_close.handle = buffer->mPlaneHandles[0];
+ if (drmIoctl(mFd.get(), DRM_IOCTL_GEM_CLOSE, &gem_close)) {
+ ALOGE("%s: DRM_IOCTL_GEM_CLOSE failed: %s (errno %d)", __FUNCTION__, strerror(errno),
+ errno);
+ return HWC3::Error::NoResources;
+ }
+ }
+
+ return HWC3::Error::None;
+}
+
+bool DrmClient::handleHotplug() {
+ DEBUG_LOG("%s", __FUNCTION__);
+
+ AutoWriteLock lock(mDisplaysMutex);
+
+ for (auto& display : mDisplays) {
+ auto change = display->checkAndHandleHotplug(mFd);
+ if (change == DrmHotplugChange::kNoChange) {
+ continue;
+ }
+
+ if (mHotplugCallback) {
+ const bool connected = (change == DrmHotplugChange::kConnected);
+ (*mHotplugCallback)(connected, //
+ display->getId(), //
+ display->getWidth(), //
+ display->getHeight(), //
+ display->getDpiX(), //
+ display->getDpiY(), //
+ display->getRefreshRateUint());
+ }
+ }
+
+ return true;
+}
+
+std::tuple<HWC3::Error, ::android::base::unique_fd> DrmClient::flushToDisplay(
+ int displayId, const std::shared_ptr<DrmBuffer>& buffer,
+ ::android::base::borrowed_fd inSyncFd) {
+ ATRACE_CALL();
+
+ if (!buffer->mDrmFramebuffer) {
+ ALOGE("%s: failed, no framebuffer created.", __FUNCTION__);
+ return std::make_tuple(HWC3::Error::NoResources, ::android::base::unique_fd());
+ }
+
+ AutoReadLock lock(mDisplaysMutex);
+ return mDisplays[displayId]->flush(mFd, inSyncFd, buffer);
+}
+
+std::optional<std::vector<uint8_t>> DrmClient::getEdid(uint32_t displayId) {
+ AutoReadLock lock(mDisplaysMutex);
+
+ if (displayId >= mDisplays.size()) {
+ DEBUG_LOG("%s: invalid display:%" PRIu32, __FUNCTION__, displayId);
+ return std::nullopt;
+ }
+
+ return mDisplays[displayId]->getEdid(mFd);
+}
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmClient.h b/system/hwc3/DrmClient.h
new file mode 100644
index 00000000..0f0dafd3
--- /dev/null
+++ b/system/hwc3/DrmClient.h
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <cutils/native_handle.h>
+
+#include <memory>
+#include <tuple>
+#include <vector>
+
+#include "Common.h"
+#include "DrmAtomicRequest.h"
+#include "DrmBuffer.h"
+#include "DrmConnector.h"
+#include "DrmCrtc.h"
+#include "DrmDisplay.h"
+#include "DrmEventListener.h"
+#include "DrmMode.h"
+#include "DrmPlane.h"
+#include "DrmProperty.h"
+#include "LruCache.h"
+#include "android/base/synchronization/AndroidLock.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+class DrmClient {
+ public:
+ DrmClient() = default;
+ ~DrmClient();
+
+ DrmClient(const DrmClient&) = delete;
+ DrmClient& operator=(const DrmClient&) = delete;
+
+ DrmClient(DrmClient&&) = delete;
+ DrmClient& operator=(DrmClient&&) = delete;
+
+ HWC3::Error init();
+
+ struct DisplayConfig {
+ uint32_t id;
+ uint32_t width;
+ uint32_t height;
+ uint32_t dpiX;
+ uint32_t dpiY;
+ uint32_t refreshRateHz;
+ };
+
+ HWC3::Error getDisplayConfigs(std::vector<DisplayConfig>* configs) const;
+
+ using HotplugCallback = std::function<void(bool /*connected*/, //
+ uint32_t /*id*/, //
+ uint32_t /*width*/, //
+ uint32_t /*height*/, //
+ uint32_t /*dpiX*/, //
+ uint32_t /*dpiY*/, //
+ uint32_t /*refreshRate*/)>;
+
+ HWC3::Error registerOnHotplugCallback(const HotplugCallback& cb);
+ HWC3::Error unregisterOnHotplugCallback();
+
+ uint32_t refreshRate() const { return mDisplays[0]->getRefreshRateUint(); }
+
+ std::tuple<HWC3::Error, std::shared_ptr<DrmBuffer>> create(const native_handle_t* handle);
+
+ std::tuple<HWC3::Error, ::android::base::unique_fd> flushToDisplay(
+ int display, const std::shared_ptr<DrmBuffer>& buffer,
+ ::android::base::borrowed_fd inWaitSyncFd);
+
+ std::optional<std::vector<uint8_t>> getEdid(uint32_t id);
+
+ private:
+ using DrmPrimeBufferHandle = uint32_t;
+
+ // Grant visibility to destroyDrmFramebuffer to DrmBuffer.
+ friend class DrmBuffer;
+ HWC3::Error destroyDrmFramebuffer(DrmBuffer* buffer);
+
+ // Grant visibility for handleHotplug to DrmEventListener.
+ bool handleHotplug();
+
+ bool loadDrmDisplays();
+
+ // Drm device.
+ ::android::base::unique_fd mFd;
+
+ mutable ::android::base::guest::ReadWriteLock mDisplaysMutex;
+ std::vector<std::unique_ptr<DrmDisplay>> mDisplays;
+
+ std::optional<HotplugCallback> mHotplugCallback;
+
+ std::unique_ptr<DrmEventListener> mDrmEventListener;
+};
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmConnector.cpp b/system/hwc3/DrmConnector.cpp
new file mode 100644
index 00000000..2481beb1
--- /dev/null
+++ b/system/hwc3/DrmConnector.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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 "DrmConnector.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+namespace {
+
+static constexpr const int32_t kUmPerInch = 25400;
+
+} // namespace
+
+std::unique_ptr<DrmConnector> DrmConnector::create(::android::base::borrowed_fd drmFd,
+ uint32_t connectorId) {
+ std::unique_ptr<DrmConnector> connector(new DrmConnector(connectorId));
+
+ if (!LoadDrmProperties(drmFd, connectorId, DRM_MODE_OBJECT_CONNECTOR, GetPropertiesMap(),
+ connector.get())) {
+ ALOGE("%s: Failed to load connector properties.", __FUNCTION__);
+ return nullptr;
+ }
+
+ if (!connector->update(drmFd)) {
+ return nullptr;
+ }
+
+ return connector;
+}
+
+bool DrmConnector::update(::android::base::borrowed_fd drmFd) {
+ DEBUG_LOG("%s: Loading properties for connector:%" PRIu32, __FUNCTION__, mId);
+
+ drmModeConnector* drmConnector = drmModeGetConnector(drmFd.get(), mId);
+ if (!drmConnector) {
+ ALOGE("%s: Failed to load connector.", __FUNCTION__);
+ return false;
+ }
+
+ mStatus = drmConnector->connection;
+
+ mModes.clear();
+ for (uint32_t i = 0; i < drmConnector->count_modes; i++) {
+ auto mode = DrmMode::create(drmFd, drmConnector->modes[i]);
+ if (!mode) {
+ ALOGE("%s: Failed to create mode for connector.", __FUNCTION__);
+ return false;
+ }
+
+ mModes.push_back(std::move(mode));
+ }
+
+ mWidthMillimeters = drmConnector->mmWidth;
+ mHeightMillimeters = drmConnector->mmHeight;
+
+ drmModeFreeConnector(drmConnector);
+
+ return true;
+}
+
+uint32_t DrmConnector::getWidth() const {
+ if (mModes.empty()) {
+ return 0;
+ }
+ return mModes[0]->hdisplay;
+}
+
+uint32_t DrmConnector::getHeight() const {
+ if (mModes.empty()) {
+ return 0;
+ }
+ return mModes[0]->vdisplay;
+}
+
+int32_t DrmConnector::getDpiX() const {
+ if (mModes.empty()) {
+ return -1;
+ }
+
+ const auto& mode = mModes[0];
+ if (mWidthMillimeters) {
+ return (mode->hdisplay * kUmPerInch) / mWidthMillimeters;
+ }
+
+ return -1;
+}
+
+int32_t DrmConnector::getDpiY() const {
+ if (mModes.empty()) {
+ return -1;
+ }
+
+ const auto& mode = mModes[0];
+ if (mHeightMillimeters) {
+ return (mode->hdisplay * kUmPerInch) / mHeightMillimeters;
+ }
+
+ return -1;
+}
+
+float DrmConnector::getRefreshRate() const {
+ if (!mModes.empty()) {
+ const auto& mode = mModes[0];
+ return 1000.0f * mode->clock / ((float)mode->vtotal * (float)mode->htotal);
+ }
+
+ return -1.0f;
+}
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmConnector.h b/system/hwc3/DrmConnector.h
new file mode 100644
index 00000000..58087b58
--- /dev/null
+++ b/system/hwc3/DrmConnector.h
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "Common.h"
+#include "DrmMode.h"
+#include "DrmProperty.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+// A "cable" to the display (HDMI, DisplayPort, etc).
+class DrmConnector {
+ public:
+ static std::unique_ptr<DrmConnector> create(::android::base::borrowed_fd drmFd,
+ uint32_t connectorId);
+ ~DrmConnector(){};
+
+ uint32_t getId() const { return mId; }
+
+ uint32_t getWidth() const;
+ uint32_t getHeight() const;
+
+ int32_t getDpiX() const;
+ int32_t getDpiY() const;
+
+ float getRefreshRate() const;
+ uint32_t getRefreshRateUint() const { return (uint32_t)(getRefreshRate() + 0.5f); }
+
+ bool isConnected() const { return mStatus == DRM_MODE_CONNECTED; }
+
+ const DrmProperty& getCrtcProperty() const { return mCrtc; }
+ const DrmProperty& getEdidProperty() const { return mEdid; }
+ const DrmMode* getDefaultMode() const { return mModes[0].get(); }
+
+ bool update(::android::base::borrowed_fd drmFd);
+
+ private:
+ DrmConnector(uint32_t id) : mId(id) {}
+
+ const uint32_t mId;
+
+ drmModeConnection mStatus = DRM_MODE_UNKNOWNCONNECTION;
+ uint32_t mWidthMillimeters = -1;
+ uint32_t mHeightMillimeters = -1;
+ std::vector<std::unique_ptr<DrmMode>> mModes;
+
+ DrmProperty mCrtc;
+ DrmProperty mEdid;
+
+ static const auto& GetPropertiesMap() {
+ static const auto* sMap = []() {
+ return new DrmPropertyMemberMap<DrmConnector>{
+ {"CRTC_ID", &DrmConnector::mCrtc},
+ {"EDID", &DrmConnector::mEdid},
+ };
+ }();
+ return *sMap;
+ }
+};
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmCrtc.cpp b/system/hwc3/DrmCrtc.cpp
new file mode 100644
index 00000000..4648a9fb
--- /dev/null
+++ b/system/hwc3/DrmCrtc.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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 "DrmCrtc.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+std::unique_ptr<DrmCrtc> DrmCrtc::create(::android::base::borrowed_fd drmFd, uint32_t crtcId,
+ uint32_t crtcIndexInResourcesArray) {
+ std::unique_ptr<DrmCrtc> crtc(new DrmCrtc(crtcId, crtcIndexInResourcesArray));
+
+ DEBUG_LOG("%s: Loading properties for crtc:%" PRIu32, __FUNCTION__, crtcId);
+ if (!LoadDrmProperties(drmFd, crtcId, DRM_MODE_OBJECT_CRTC, GetPropertiesMap(), crtc.get())) {
+ ALOGE("%s: Failed to load crtc properties.", __FUNCTION__);
+ return nullptr;
+ }
+
+ return crtc;
+}
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmCrtc.h b/system/hwc3/DrmCrtc.h
new file mode 100644
index 00000000..947ff517
--- /dev/null
+++ b/system/hwc3/DrmCrtc.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "Common.h"
+#include "DrmProperty.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+class DrmCrtc {
+ public:
+ static std::unique_ptr<DrmCrtc> create(::android::base::borrowed_fd drmFd, uint32_t crtcId,
+ uint32_t crtcIndexInResourcesArray);
+ ~DrmCrtc() {}
+
+ uint32_t getId() const { return mId; }
+
+ const DrmProperty& getActiveProperty() const { return mActive; }
+ const DrmProperty& getModeProperty() const { return mMode; }
+ const DrmProperty& getOutFenceProperty() const { return mOutFence; }
+
+ private:
+ DrmCrtc(uint32_t id, uint32_t index) : mId(id), mIndexInResourcesArray(index) {}
+
+ friend class DrmPlane;
+
+ const uint32_t mId = -1;
+ const uint32_t mIndexInResourcesArray = -1;
+
+ DrmProperty mActive;
+ DrmProperty mMode;
+ DrmProperty mOutFence;
+
+ static const auto& GetPropertiesMap() {
+ static const auto* sMap = []() {
+ return new DrmPropertyMemberMap<DrmCrtc>{
+ {"ACTIVE", &DrmCrtc::mActive},
+ {"MODE_ID", &DrmCrtc::mMode},
+ {"OUT_FENCE_PTR", &DrmCrtc::mOutFence},
+ };
+ }();
+ return *sMap;
+ }
+};
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmDisplay.cpp b/system/hwc3/DrmDisplay.cpp
new file mode 100644
index 00000000..ac9dc214
--- /dev/null
+++ b/system/hwc3/DrmDisplay.cpp
@@ -0,0 +1,214 @@
+/*
+ * 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 "DrmDisplay.h"
+
+#include "DrmAtomicRequest.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+namespace {
+
+template <typename T>
+uint64_t addressAsUint(T* pointer) {
+ return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(pointer));
+}
+
+} // namespace
+
+std::unique_ptr<DrmDisplay> DrmDisplay::create(uint32_t id, std::unique_ptr<DrmConnector> connector,
+ std::unique_ptr<DrmCrtc> crtc,
+ std::unique_ptr<DrmPlane> plane,
+ ::android::base::borrowed_fd drmFd) {
+ if (!crtc) {
+ ALOGE("%s: invalid crtc.", __FUNCTION__);
+ return nullptr;
+ }
+ if (!connector) {
+ ALOGE("%s: invalid connector.", __FUNCTION__);
+ return nullptr;
+ }
+ if (!plane) {
+ ALOGE("%s: invalid plane.", __FUNCTION__);
+ return nullptr;
+ }
+
+ if (connector->isConnected()) {
+ auto request = DrmAtomicRequest::create();
+ if (!request) {
+ ALOGE("%s: failed to create atomic request.", __FUNCTION__);
+ return nullptr;
+ }
+
+ bool okay = true;
+ okay &= request->Set(connector->getId(), connector->getCrtcProperty(), crtc->getId());
+ okay &= request->Set(crtc->getId(), crtc->getActiveProperty(), 1);
+ okay &= request->Set(crtc->getId(), crtc->getModeProperty(),
+ connector->getDefaultMode()->getBlobId());
+ okay &= request->Commit(drmFd);
+ if (!okay) {
+ ALOGE("%s: failed to set display mode.", __FUNCTION__);
+ return nullptr;
+ }
+ }
+
+ return std::unique_ptr<DrmDisplay>(
+ new DrmDisplay(id, std::move(connector), std::move(crtc), std::move(plane)));
+}
+
+std::optional<std::vector<uint8_t>> DrmDisplay::getEdid(::android::base::borrowed_fd drmFd) const {
+ DEBUG_LOG("%s: display:%" PRIu32, __FUNCTION__, mId);
+
+ if (!mConnector) {
+ ALOGE("%s: display:%" PRIu32 " is missing connector.", __FUNCTION__, mId);
+ return std::nullopt;
+ }
+
+ const DrmProperty& edidProp = mConnector->getEdidProperty();
+ if (edidProp.getId() == -1) {
+ ALOGW("%s: display:%" PRIu32 " does not have EDID.", __FUNCTION__, mId);
+ return std::nullopt;
+ }
+
+ const uint64_t edidBlobId = edidProp.getValue();
+
+ auto blob = drmModeGetPropertyBlob(drmFd.get(), edidBlobId);
+ if (!blob) {
+ ALOGE("%s: display:%" PRIu32 " failed to read EDID blob (%" PRIu64 "): %s", __FUNCTION__,
+ mId, edidBlobId, strerror(errno));
+ return std::nullopt;
+ }
+
+ std::vector<uint8_t> edid;
+ uint8_t* start = static_cast<uint8_t*>(blob->data);
+ edid.insert(edid.begin(), start, start + blob->length);
+
+ drmModeFreePropertyBlob(blob);
+
+ return edid;
+}
+
+std::tuple<HWC3::Error, ::android::base::unique_fd> DrmDisplay::flush(
+ ::android::base::borrowed_fd drmFd, ::android::base::borrowed_fd inSyncFd,
+ const std::shared_ptr<DrmBuffer>& buffer) {
+ std::unique_ptr<DrmAtomicRequest> request = DrmAtomicRequest::create();
+ if (!request) {
+ ALOGE("%s: failed to create atomic request.", __FUNCTION__);
+ return std::make_tuple(HWC3::Error::NoResources, ::android::base::unique_fd());
+ }
+
+ int flushFenceFd = -1;
+
+ bool okay = true;
+ okay &=
+ request->Set(mCrtc->getId(), mCrtc->getOutFenceProperty(), addressAsUint(&flushFenceFd));
+ okay &= request->Set(mPlane->getId(), mPlane->getCrtcProperty(), mCrtc->getId());
+ okay &= request->Set(mPlane->getId(), mPlane->getInFenceProperty(), inSyncFd.get());
+ okay &= request->Set(mPlane->getId(), mPlane->getFbProperty(), *buffer->mDrmFramebuffer);
+ okay &= request->Set(mPlane->getId(), mPlane->getCrtcXProperty(), 0);
+ okay &= request->Set(mPlane->getId(), mPlane->getCrtcYProperty(), 0);
+ okay &= request->Set(mPlane->getId(), mPlane->getCrtcWProperty(), buffer->mWidth);
+ okay &= request->Set(mPlane->getId(), mPlane->getCrtcHProperty(), buffer->mHeight);
+ okay &= request->Set(mPlane->getId(), mPlane->getSrcXProperty(), 0);
+ okay &= request->Set(mPlane->getId(), mPlane->getSrcYProperty(), 0);
+ okay &= request->Set(mPlane->getId(), mPlane->getSrcWProperty(), buffer->mWidth << 16);
+ okay &= request->Set(mPlane->getId(), mPlane->getSrcHProperty(), buffer->mHeight << 16);
+
+ okay &= request->Commit(drmFd);
+ if (!okay) {
+ ALOGE("%s: failed to flush to display.", __FUNCTION__);
+ return std::make_tuple(HWC3::Error::NoResources, ::android::base::unique_fd());
+ }
+
+ mPreviousBuffer = buffer;
+
+ DEBUG_LOG("%s: submitted atomic update, flush fence:%d\n", __FUNCTION__, flushFenceFd);
+ return std::make_tuple(HWC3::Error::None, ::android::base::unique_fd(flushFenceFd));
+}
+
+bool DrmDisplay::onConnect(::android::base::borrowed_fd drmFd) {
+ DEBUG_LOG("%s: display:%" PRIu32, __FUNCTION__, mId);
+
+ auto request = DrmAtomicRequest::create();
+ if (!request) {
+ ALOGE("%s: display:%" PRIu32 " failed to create atomic request.", __FUNCTION__, mId);
+ return false;
+ }
+
+ bool okay = true;
+ okay &= request->Set(mConnector->getId(), mConnector->getCrtcProperty(), mCrtc->getId());
+ okay &= request->Set(mCrtc->getId(), mCrtc->getActiveProperty(), 1);
+ okay &= request->Set(mCrtc->getId(), mCrtc->getModeProperty(),
+ mConnector->getDefaultMode()->getBlobId());
+
+ okay &= request->Commit(drmFd);
+ if (!okay) {
+ ALOGE("%s: display:%" PRIu32 " failed to set mode.", __FUNCTION__, mId);
+ return false;
+ }
+
+ return true;
+}
+
+bool DrmDisplay::onDisconnect(::android::base::borrowed_fd drmFd) {
+ DEBUG_LOG("%s: display:%" PRIu32, __FUNCTION__, mId);
+
+ auto request = DrmAtomicRequest::create();
+ if (!request) {
+ ALOGE("%s: display:%" PRIu32 " failed to create atomic request.", __FUNCTION__, mId);
+ return false;
+ }
+
+ bool okay = true;
+ okay &= request->Set(mPlane->getId(), mPlane->getCrtcProperty(), 0);
+ okay &= request->Set(mPlane->getId(), mPlane->getFbProperty(), 0);
+
+ okay &= request->Commit(drmFd);
+ if (!okay) {
+ ALOGE("%s: display:%" PRIu32 " failed to set mode", __FUNCTION__, mId);
+ }
+
+ mPreviousBuffer.reset();
+
+ return okay;
+}
+
+DrmHotplugChange DrmDisplay::checkAndHandleHotplug(::android::base::borrowed_fd drmFd) {
+ DEBUG_LOG("%s: display:%" PRIu32, __FUNCTION__, mId);
+
+ const bool oldConnected = mConnector->isConnected();
+ mConnector->update(drmFd);
+ const bool newConnected = mConnector->isConnected();
+
+ if (oldConnected == newConnected) {
+ return DrmHotplugChange::kNoChange;
+ }
+
+ if (newConnected) {
+ ALOGI("%s: display:%" PRIu32 " was connected.", __FUNCTION__, mId);
+ if (!onConnect(drmFd)) {
+ ALOGE("%s: display:%" PRIu32 " failed to connect.", __FUNCTION__, mId);
+ }
+ return DrmHotplugChange::kConnected;
+ } else {
+ ALOGI("%s: display:%" PRIu32 " was disconnected.", __FUNCTION__, mId);
+ if (!onDisconnect(drmFd)) {
+ ALOGE("%s: display:%" PRIu32 " failed to disconnect.", __FUNCTION__, mId);
+ }
+ return DrmHotplugChange::kDisconnected;
+ }
+}
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmDisplay.h b/system/hwc3/DrmDisplay.h
new file mode 100644
index 00000000..af3e9772
--- /dev/null
+++ b/system/hwc3/DrmDisplay.h
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "Common.h"
+#include "DrmBuffer.h"
+#include "DrmConnector.h"
+#include "DrmCrtc.h"
+#include "DrmPlane.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+enum class DrmHotplugChange {
+ kNoChange,
+ kConnected,
+ kDisconnected,
+};
+
+class DrmDisplay {
+ public:
+ static std::unique_ptr<DrmDisplay> create(uint32_t id, std::unique_ptr<DrmConnector> connector,
+ std::unique_ptr<DrmCrtc> crtc,
+ std::unique_ptr<DrmPlane> plane,
+ ::android::base::borrowed_fd drmFd);
+
+ uint32_t getId() const { return mId; }
+
+ uint32_t getWidth() const { return mConnector->getWidth(); }
+ uint32_t getHeight() const { return mConnector->getHeight(); }
+
+ uint32_t getDpiX() const { return mConnector->getDpiX(); }
+ uint32_t getDpiY() const { return mConnector->getDpiY(); }
+
+ uint32_t getRefreshRateUint() const { return mConnector->getRefreshRateUint(); }
+
+ std::optional<std::vector<uint8_t>> getEdid(::android::base::borrowed_fd drmFd) const;
+
+ std::tuple<HWC3::Error, ::android::base::unique_fd> flush(
+ ::android::base::borrowed_fd drmFd, ::android::base::borrowed_fd inWaitSyncFd,
+ const std::shared_ptr<DrmBuffer>& buffer);
+
+ DrmHotplugChange checkAndHandleHotplug(::android::base::borrowed_fd drmFd);
+
+ private:
+ DrmDisplay(uint32_t id, std::unique_ptr<DrmConnector> connector, std::unique_ptr<DrmCrtc> crtc,
+ std::unique_ptr<DrmPlane> plane)
+ : mId(id),
+ mConnector(std::move(connector)),
+ mCrtc(std::move(crtc)),
+ mPlane(std::move(plane)) {}
+
+ bool onConnect(::android::base::borrowed_fd drmFd);
+
+ bool onDisconnect(::android::base::borrowed_fd drmFd);
+
+ const uint32_t mId;
+ std::unique_ptr<DrmConnector> mConnector;
+ std::unique_ptr<DrmCrtc> mCrtc;
+ std::unique_ptr<DrmPlane> mPlane;
+
+ // The last presented buffer / DRM framebuffer is cached until
+ // the next present to avoid toggling the display on and off.
+ std::shared_ptr<DrmBuffer> mPreviousBuffer;
+};
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmEventListener.cpp b/system/hwc3/DrmEventListener.cpp
new file mode 100644
index 00000000..208824bc
--- /dev/null
+++ b/system/hwc3/DrmEventListener.cpp
@@ -0,0 +1,103 @@
+/*
+ * 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 "DrmEventListener.h"
+
+#include <linux/netlink.h>
+#include <sys/socket.h>
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+std::unique_ptr<DrmEventListener> DrmEventListener::create(::android::base::borrowed_fd drmFd,
+ std::function<void()> callback) {
+ std::unique_ptr<DrmEventListener> listener(new DrmEventListener(std::move(callback)));
+
+ if (!listener->init(drmFd)) {
+ return nullptr;
+ }
+
+ return listener;
+}
+
+bool DrmEventListener::init(::android::base::borrowed_fd drmFd) {
+ mEventFd = ::android::base::unique_fd(socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT));
+ if (!mEventFd.ok()) {
+ ALOGE("Failed to open uevent socket: %s", strerror(errno));
+ return false;
+ }
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ addr.nl_pid = 0;
+ addr.nl_groups = 0xFFFFFFFF;
+
+ int ret = bind(mEventFd, (struct sockaddr*)&addr, sizeof(addr));
+ if (ret) {
+ ALOGE("Failed to bind uevent socket: %s", strerror(errno));
+ return false;
+ }
+
+ FD_ZERO(&mMonitoredFds);
+ FD_SET(drmFd.get(), &mMonitoredFds);
+ FD_SET(mEventFd.get(), &mMonitoredFds);
+ mMaxMonitoredFd = std::max(drmFd.get(), mEventFd.get());
+
+ mThread = std::thread([this]() { threadLoop(); });
+
+ return true;
+}
+
+void DrmEventListener::threadLoop() {
+ int ret;
+ do {
+ ret = select(mMaxMonitoredFd + 1, &mMonitoredFds, NULL, NULL, NULL);
+ } while (ret == -1 && errno == EINTR);
+
+ if (!FD_ISSET(mEventFd.get(), &mMonitoredFds)) {
+ ALOGE("%s: DrmEventListevener event fd unset?", __FUNCTION__);
+ return;
+ }
+
+ char buffer[1024];
+ while (true) {
+ ret = read(mEventFd.get(), &buffer, sizeof(buffer));
+ if (ret == 0) {
+ return;
+ } else if (ret < 0) {
+ ALOGE("Got error reading uevent %d", ret);
+ return;
+ }
+
+ bool drmEvent = false, hotplugEvent = false;
+ for (int i = 0; i < ret;) {
+ char* event = buffer + i;
+ if (strcmp(event, "DEVTYPE=drm_minor")) {
+ drmEvent = true;
+ } else if (strcmp(event, "HOTPLUG=1")) {
+ hotplugEvent = true;
+ }
+
+ i += strlen(event) + 1;
+ }
+
+ if (drmEvent && hotplugEvent) {
+ DEBUG_LOG("DrmEventListener detected hotplug event .");
+ mOnEventCallback();
+ }
+ }
+}
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmEventListener.h b/system/hwc3/DrmEventListener.h
new file mode 100644
index 00000000..4ab29b61
--- /dev/null
+++ b/system/hwc3/DrmEventListener.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include <cstdint>
+#include <functional>
+#include <optional>
+#include <thread>
+#include <unordered_map>
+
+#include "Common.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+class DrmEventListener {
+ public:
+ static std::unique_ptr<DrmEventListener> create(::android::base::borrowed_fd drmFd,
+ std::function<void()> callback);
+
+ ~DrmEventListener() {}
+
+ private:
+ DrmEventListener(std::function<void()> callback) : mOnEventCallback(std::move(callback)) {}
+
+ bool init(::android::base::borrowed_fd drmFd);
+
+ void threadLoop();
+
+ std::thread mThread;
+ std::function<void()> mOnEventCallback;
+ ::android::base::unique_fd mEventFd;
+ fd_set mMonitoredFds;
+ int mMaxMonitoredFd = 0;
+};
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmMode.cpp b/system/hwc3/DrmMode.cpp
new file mode 100644
index 00000000..d65f0cc9
--- /dev/null
+++ b/system/hwc3/DrmMode.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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 "DrmMode.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+std::unique_ptr<DrmMode> DrmMode::create(::android::base::borrowed_fd drmFd,
+ const drmModeModeInfo& info) {
+ uint32_t blobId = 0;
+
+ int ret = drmModeCreatePropertyBlob(drmFd.get(), &info, sizeof(info), &blobId);
+ if (ret != 0) {
+ ALOGE("%s: Failed to create mode blob: %s.", __FUNCTION__, strerror(errno));
+ return nullptr;
+ }
+
+ return std::unique_ptr<DrmMode>(new DrmMode(info, blobId));
+}
+
+DrmMode::~DrmMode() {
+ // TODO: don't leak the blob.
+}
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmMode.h b/system/hwc3/DrmMode.h
new file mode 100644
index 00000000..23b170de
--- /dev/null
+++ b/system/hwc3/DrmMode.h
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include <cstdint>
+#include <memory>
+
+#include "Common.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+class DrmMode {
+ public:
+ static std::unique_ptr<DrmMode> create(::android::base::borrowed_fd drmFd,
+ const drmModeModeInfo& info);
+
+ ~DrmMode();
+
+ const uint32_t clock;
+ const uint16_t hdisplay;
+ const uint16_t hsync_start;
+ const uint16_t hsync_end;
+ const uint16_t htotal;
+ const uint16_t hskew;
+ const uint16_t vdisplay;
+ const uint16_t vsync_start;
+ const uint16_t vsync_end;
+ const uint16_t vtotal;
+ const uint16_t vscan;
+ const uint32_t vrefresh;
+ const uint32_t flags;
+ const uint32_t type;
+ const std::string name;
+
+ uint32_t getBlobId() const { return mBlobId; }
+
+ private:
+ DrmMode(const drmModeModeInfo& info, uint32_t blobId)
+ : clock(info.clock),
+ hdisplay(info.hdisplay),
+ hsync_start(info.hsync_start),
+ hsync_end(info.hsync_end),
+ htotal(info.htotal),
+ hskew(info.hskew),
+ vdisplay(info.vdisplay),
+ vsync_start(info.vsync_start),
+ vsync_end(info.vsync_end),
+ vtotal(info.vtotal),
+ vscan(info.vscan),
+ vrefresh(info.vrefresh),
+ flags(info.flags),
+ type(info.type),
+ name(info.name),
+ mBlobId(blobId) {}
+
+ const uint32_t mBlobId;
+};
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmPlane.cpp b/system/hwc3/DrmPlane.cpp
new file mode 100644
index 00000000..f2027ee2
--- /dev/null
+++ b/system/hwc3/DrmPlane.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 "DrmPlane.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+std::unique_ptr<DrmPlane> DrmPlane::create(::android::base::borrowed_fd drmFd, uint32_t planeId) {
+ std::unique_ptr<DrmPlane> plane(new DrmPlane(planeId));
+
+ DEBUG_LOG("%s: Loading properties for DRM plane:%" PRIu32, __FUNCTION__, planeId);
+ if (!LoadDrmProperties(drmFd, planeId, DRM_MODE_OBJECT_PLANE, GetPropertiesMap(),
+ plane.get())) {
+ ALOGE("%s: Failed to load plane properties.", __FUNCTION__);
+ return nullptr;
+ }
+
+ drmModePlanePtr drmPlane = drmModeGetPlane(drmFd.get(), planeId);
+ plane->mPossibleCrtcsMask = drmPlane->possible_crtcs;
+ drmModeFreePlane(drmPlane);
+
+ return plane;
+}
+
+bool DrmPlane::isPrimary() const { return mType.getValue() == DRM_PLANE_TYPE_PRIMARY; }
+
+bool DrmPlane::isOverlay() const { return mType.getValue() == DRM_PLANE_TYPE_OVERLAY; }
+
+bool DrmPlane::isCompatibleWith(const DrmCrtc& crtc) {
+ return ((0x1 << crtc.mIndexInResourcesArray) & mPossibleCrtcsMask);
+}
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmPlane.h b/system/hwc3/DrmPlane.h
new file mode 100644
index 00000000..b2447566
--- /dev/null
+++ b/system/hwc3/DrmPlane.h
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "Common.h"
+#include "DrmCrtc.h"
+#include "DrmProperty.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+class DrmPlane {
+ public:
+ static std::unique_ptr<DrmPlane> create(::android::base::borrowed_fd drmFd, uint32_t planeId);
+ ~DrmPlane(){};
+
+ uint32_t getId() const { return mId; }
+
+ bool isPrimary() const;
+ bool isOverlay() const;
+
+ bool isCompatibleWith(const DrmCrtc& crtc);
+
+ const DrmProperty& getCrtcProperty() const { return mCrtc; }
+ const DrmProperty& getInFenceProperty() const { return mInFenceFd; }
+ const DrmProperty& getFbProperty() const { return mFb; }
+ const DrmProperty& getCrtcXProperty() const { return mCrtcX; }
+ const DrmProperty& getCrtcYProperty() const { return mCrtcY; }
+ const DrmProperty& getCrtcWProperty() const { return mCrtcW; }
+ const DrmProperty& getCrtcHProperty() const { return mCrtcH; }
+ const DrmProperty& getSrcXProperty() const { return mSrcX; }
+ const DrmProperty& getSrcYProperty() const { return mSrcY; }
+ const DrmProperty& getSrcWProperty() const { return mSrcW; }
+ const DrmProperty& getSrcHProperty() const { return mSrcH; }
+
+ private:
+ DrmPlane(uint32_t id) : mId(id){};
+
+ const uint32_t mId;
+
+ uint32_t mPossibleCrtcsMask = 0;
+
+ DrmProperty mCrtc;
+ DrmProperty mInFenceFd;
+ DrmProperty mFb;
+ DrmProperty mCrtcX;
+ DrmProperty mCrtcY;
+ DrmProperty mCrtcW;
+ DrmProperty mCrtcH;
+ DrmProperty mSrcX;
+ DrmProperty mSrcY;
+ DrmProperty mSrcW;
+ DrmProperty mSrcH;
+ DrmProperty mType;
+
+ static const auto& GetPropertiesMap() {
+ static const auto* sMap = []() {
+ return new DrmPropertyMemberMap<DrmPlane>{
+ {"CRTC_ID", &DrmPlane::mCrtc},
+ {"CRTC_X", &DrmPlane::mCrtcX},
+ {"CRTC_Y", &DrmPlane::mCrtcY},
+ {"CRTC_W", &DrmPlane::mCrtcW},
+ {"CRTC_H", &DrmPlane::mCrtcH},
+ {"FB_ID", &DrmPlane::mFb},
+ {"IN_FENCE_FD", &DrmPlane::mInFenceFd},
+ {"SRC_X", &DrmPlane::mSrcX},
+ {"SRC_Y", &DrmPlane::mSrcY},
+ {"SRC_W", &DrmPlane::mSrcW},
+ {"SRC_H", &DrmPlane::mSrcH},
+ {"type", &DrmPlane::mType},
+ };
+ }();
+ return *sMap;
+ }
+};
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmPresenter.cpp b/system/hwc3/DrmPresenter.cpp
deleted file mode 100644
index b5122778..00000000
--- a/system/hwc3/DrmPresenter.cpp
+++ /dev/null
@@ -1,750 +0,0 @@
-/*
- * 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 "DrmPresenter.h"
-
-#include <cros_gralloc_handle.h>
-#include <linux/netlink.h>
-#include <sys/socket.h>
-
-#include <chrono>
-#include <thread>
-
-using ::android::base::guest::AutoReadLock;
-using ::android::base::guest::AutoWriteLock;
-using ::android::base::guest::ReadWriteLock;
-
-namespace aidl::android::hardware::graphics::composer3::impl {
-namespace {
-
-uint64_t addressAsUint(int* pointer) {
- return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(pointer));
-}
-
-} // namespace
-
-DrmPresenter::~DrmPresenter() {
- if (mFd > 0) {
- drmDropMaster(mFd.get());
- }
-}
-
-HWC3::Error DrmPresenter::init() {
- DEBUG_LOG("%s", __FUNCTION__);
-
- mFd = ::android::base::unique_fd(open("/dev/dri/card0", O_RDWR | O_CLOEXEC));
- if (mFd < 0) {
- ALOGE("%s: failed to open drm device: %s", __FUNCTION__, strerror(errno));
- return HWC3::Error::NoResources;
- }
-
- int ret = drmSetClientCap(mFd.get(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
- if (ret) {
- ALOGE("%s: failed to set cap universal plane %s\n", __FUNCTION__,
- strerror(errno));
- return HWC3::Error::NoResources;
- }
-
- ret = drmSetClientCap(mFd.get(), DRM_CLIENT_CAP_ATOMIC, 1);
- if (ret) {
- ALOGE("%s: failed to set cap atomic %s\n", __FUNCTION__, strerror(errno));
- return HWC3::Error::NoResources;
- }
-
- drmSetMaster(mFd.get());
-
- if (!drmIsMaster(mFd.get())) {
- ALOGE("%s: failed to get master drm device", __FUNCTION__);
- return HWC3::Error::NoResources;
- }
-
- {
- AutoWriteLock lock(mStateMutex);
- bool initDrmRet = initDrmElementsLocked();
- if (initDrmRet) {
- DEBUG_LOG("%s: Successfully initialized DRM backend", __FUNCTION__);
- } else {
- ALOGE("%s: Failed to initialize DRM backend", __FUNCTION__);
- return HWC3::Error::NoResources;
- }
-
- constexpr const std::size_t kCachedBuffersPerDisplay = 3;
- std::size_t numDisplays = 0;
- for (const DrmConnector& connector : mConnectors) {
- if (connector.connection == DRM_MODE_CONNECTED) {
- ++numDisplays;
- }
- }
- const std::size_t bufferCacheSize = kCachedBuffersPerDisplay * numDisplays;
- DEBUG_LOG("%s: initializing DRM buffer cache to size %zu",
- __FUNCTION__, bufferCacheSize);
- mBufferCache = std::make_unique<DrmBufferCache>(bufferCacheSize);
- }
-
- mDrmEventListener = ::android::sp<DrmEventListener>::make(*this);
- if (mDrmEventListener->init()) {
- DEBUG_LOG("%s: Successfully initialized DRM event listener", __FUNCTION__);
- } else {
- ALOGE("%s: Failed to initialize DRM event listener", __FUNCTION__);
- }
- mDrmEventListener->run("", ANDROID_PRIORITY_URGENT_DISPLAY);
-
- return HWC3::Error::None;
-}
-
-HWC3::Error DrmPresenter::getDisplayConfigs(std::vector<DisplayConfig>* configs) const {
- AutoReadLock lock(mStateMutex);
-
- configs->clear();
-
- for (uint32_t i = 0; i < mConnectors.size(); i++) {
- const auto& connector = mConnectors[i];
-
- if (connector.connection != DRM_MODE_CONNECTED) {
- continue;
- }
-
- configs->emplace_back(DisplayConfig{
- .id = i,
- .width = connector.mMode.hdisplay,
- .height = connector.mMode.vdisplay,
- .dpiX = 160, //static_cast<uint32_t>(connector.dpiX),
- .dpiY = 160, //static_cast<uint32_t>(connector.dpiY),
- .refreshRateHz = connector.mRefreshRateAsInteger,
- });
- }
-
- return HWC3::Error::None;
-}
-
-HWC3::Error DrmPresenter::registerOnHotplugCallback(const HotplugCallback& cb) {
- mHotplugCallback = cb;
- return HWC3::Error::None;
-}
-
-HWC3::Error DrmPresenter::unregisterOnHotplugCallback() {
- mHotplugCallback.reset();
- return HWC3::Error::None;
-}
-
-bool DrmPresenter::initDrmElementsLocked() {
- drmModeRes* res;
- static const int32_t kUmPerInch = 25400;
-
- res = drmModeGetResources(mFd.get());
- if (res == nullptr) {
- ALOGE("%s HWC3::Error reading drm resources: %d", __FUNCTION__, errno);
- mFd.reset();
- return false;
- }
-
- DEBUG_LOG(
- "drmModeRes count fbs %d crtc %d connector %d encoder %d min w %d max w "
- "%d min h %d max h %d",
- res->count_fbs, res->count_crtcs, res->count_connectors,
- res->count_encoders, res->min_width, res->max_width, res->min_height,
- res->max_height);
-
- for (uint32_t i = 0; i < res->count_crtcs; i++) {
- DrmCrtc crtc = {};
-
- drmModeCrtcPtr c = drmModeGetCrtc(mFd.get(), res->crtcs[i]);
- crtc.mId = c->crtc_id;
-
- drmModeObjectPropertiesPtr crtcProps =
- drmModeObjectGetProperties(mFd.get(), c->crtc_id, DRM_MODE_OBJECT_CRTC);
-
- for (uint32_t crtcPropsIndex = 0; crtcPropsIndex < crtcProps->count_props;
- crtcPropsIndex++) {
- drmModePropertyPtr crtcProp =
- drmModeGetProperty(mFd.get(), crtcProps->props[crtcPropsIndex]);
-
- if (!strcmp(crtcProp->name, "OUT_FENCE_PTR")) {
- crtc.mOutFencePtrPropertyId = crtcProp->prop_id;
- } else if (!strcmp(crtcProp->name, "ACTIVE")) {
- crtc.mActivePropertyId = crtcProp->prop_id;
- } else if (!strcmp(crtcProp->name, "MODE_ID")) {
- crtc.mModePropertyId = crtcProp->prop_id;
- }
-
- drmModeFreeProperty(crtcProp);
- }
-
- drmModeFreeObjectProperties(crtcProps);
-
- mCrtcs.push_back(crtc);
- }
-
- drmModePlaneResPtr planeRes = drmModeGetPlaneResources(mFd.get());
- for (uint32_t i = 0; i < planeRes->count_planes; ++i) {
- DrmPlane plane = {};
-
- drmModePlanePtr p = drmModeGetPlane(mFd.get(), planeRes->planes[i]);
- plane.mId = p->plane_id;
-
- DEBUG_LOG(
- "%s: plane id: %u crtcid %u fbid %u crtc xy %d %d xy %d %d "
- "possible ctrcs 0x%x",
- __FUNCTION__, p->plane_id, p->crtc_id, p->fb_id, p->crtc_x, p->crtc_y,
- p->x, p->y, p->possible_crtcs);
-
- drmModeObjectPropertiesPtr planeProps =
- drmModeObjectGetProperties(mFd.get(), plane.mId, DRM_MODE_OBJECT_PLANE);
-
- for (uint32_t planePropIndex = 0; planePropIndex < planeProps->count_props;
- ++planePropIndex) {
- drmModePropertyPtr planeProp =
- drmModeGetProperty(mFd.get(), planeProps->props[planePropIndex]);
-
- if (!strcmp(planeProp->name, "CRTC_ID")) {
- plane.mCrtcPropertyId = planeProp->prop_id;
- } else if (!strcmp(planeProp->name, "IN_FENCE_FD")) {
- plane.mInFenceFdPropertyId = planeProp->prop_id;
- } else if (!strcmp(planeProp->name, "FB_ID")) {
- plane.mFbPropertyId = planeProp->prop_id;
- } else if (!strcmp(planeProp->name, "CRTC_X")) {
- plane.mCrtcXPropertyId = planeProp->prop_id;
- } else if (!strcmp(planeProp->name, "CRTC_Y")) {
- plane.mCrtcYPropertyId = planeProp->prop_id;
- } else if (!strcmp(planeProp->name, "CRTC_W")) {
- plane.mCrtcWPropertyId = planeProp->prop_id;
- } else if (!strcmp(planeProp->name, "CRTC_H")) {
- plane.mCrtcHPropertyId = planeProp->prop_id;
- } else if (!strcmp(planeProp->name, "SRC_X")) {
- plane.mSrcXPropertyId = planeProp->prop_id;
- } else if (!strcmp(planeProp->name, "SRC_Y")) {
- plane.mSrcYPropertyId = planeProp->prop_id;
- } else if (!strcmp(planeProp->name, "SRC_W")) {
- plane.mSrcWPropertyId = planeProp->prop_id;
- } else if (!strcmp(planeProp->name, "SRC_H")) {
- plane.mSrcHPropertyId = planeProp->prop_id;
- } else if (!strcmp(planeProp->name, "type")) {
- plane.mTypePropertyId = planeProp->prop_id;
- uint64_t type = planeProp->values[0];
- switch (type) {
- case DRM_PLANE_TYPE_OVERLAY:
- plane.mType = type;
- DEBUG_LOG("%s: plane %" PRIu32 " is DRM_PLANE_TYPE_OVERLAY",
- __FUNCTION__, plane.mId);
- break;
- case DRM_PLANE_TYPE_PRIMARY:
- plane.mType = type;
- DEBUG_LOG("%s: plane %" PRIu32 " is DRM_PLANE_TYPE_PRIMARY",
- __FUNCTION__, plane.mId);
- break;
- default:
- break;
- }
- }
-
- drmModeFreeProperty(planeProp);
- }
-
- drmModeFreeObjectProperties(planeProps);
-
- bool isPrimaryOrOverlay = plane.mType == DRM_PLANE_TYPE_OVERLAY ||
- plane.mType == DRM_PLANE_TYPE_PRIMARY;
- if (isPrimaryOrOverlay) {
- for (uint32_t j = 0; j < mCrtcs.size(); j++) {
- if ((0x1 << j) & p->possible_crtcs) {
- DEBUG_LOG("%s: plane %" PRIu32 " compatible with crtc mask %" PRIu32,
- __FUNCTION__, plane.mId, p->possible_crtcs);
- if (mCrtcs[j].mPlaneId == -1) {
- mCrtcs[j].mPlaneId = plane.mId;
- DEBUG_LOG("%s: plane %" PRIu32 " associated with crtc %" PRIu32,
- __FUNCTION__, plane.mId, j);
- break;
- }
- }
- }
- }
-
- drmModeFreePlane(p);
- mPlanes[plane.mId] = plane;
- }
- drmModeFreePlaneResources(planeRes);
-
- for (uint32_t i = 0; i < res->count_connectors; ++i) {
- DrmConnector connector = {};
- connector.mId = res->connectors[i];
-
- {
- drmModeObjectPropertiesPtr connectorProps = drmModeObjectGetProperties(
- mFd.get(), connector.mId, DRM_MODE_OBJECT_CONNECTOR);
-
- for (uint32_t connectorPropIndex = 0;
- connectorPropIndex < connectorProps->count_props;
- ++connectorPropIndex) {
- drmModePropertyPtr connectorProp = drmModeGetProperty(
- mFd.get(), connectorProps->props[connectorPropIndex]);
- if (!strcmp(connectorProp->name, "CRTC_ID")) {
- connector.mCrtcPropertyId = connectorProp->prop_id;
- } else if (!strcmp(connectorProp->name, "EDID")) {
- connector.mEdidBlobId =
- connectorProps->prop_values[connectorPropIndex];
- }
- drmModeFreeProperty(connectorProp);
- }
-
- drmModeFreeObjectProperties(connectorProps);
- }
- {
- drmModeConnector* c = drmModeGetConnector(mFd.get(), connector.mId);
- if (c == nullptr) {
- ALOGE("%s: Failed to get connector %" PRIu32 ": %d", __FUNCTION__,
- connector.mId, errno);
- return false;
- }
- connector.connection = c->connection;
- if (c->count_modes > 0) {
- memcpy(&connector.mMode, &c->modes[0], sizeof(drmModeModeInfo));
- drmModeCreatePropertyBlob(mFd.get(), &connector.mMode,
- sizeof(connector.mMode),
- &connector.mModeBlobId);
-
- // Dots per 1000 inches
- connector.dpiX =
- c->mmWidth ? (c->modes[0].hdisplay * kUmPerInch) / (c->mmWidth)
- : -1;
- // Dots per 1000 inches
- connector.dpiY =
- c->mmHeight ? (c->modes[0].vdisplay * kUmPerInch) / (c->mmHeight)
- : -1;
- }
- DEBUG_LOG("%s connector %" PRIu32 " dpiX %" PRIi32 " dpiY %" PRIi32
- " connection %d",
- __FUNCTION__, connector.mId, connector.dpiX, connector.dpiY,
- connector.connection);
-
- drmModeFreeConnector(c);
-
- connector.mRefreshRateAsFloat =
- 1000.0f * connector.mMode.clock /
- ((float)connector.mMode.vtotal * (float)connector.mMode.htotal);
- connector.mRefreshRateAsInteger =
- (uint32_t)(connector.mRefreshRateAsFloat + 0.5f);
- }
-
- mConnectors.push_back(connector);
- }
-
- drmModeFreeResources(res);
- return true;
-}
-
-void DrmPresenter::resetDrmElementsLocked() {
- for (auto& c : mConnectors) {
- if (c.mModeBlobId) {
- if (drmModeDestroyPropertyBlob(mFd.get(), c.mModeBlobId)) {
- ALOGE("%s: Error destroy PropertyBlob %" PRIu32, __func__,
- c.mModeBlobId);
- }
- }
- }
- mConnectors.clear();
- mCrtcs.clear();
- mPlanes.clear();
-}
-
-std::tuple<HWC3::Error, std::shared_ptr<DrmBuffer>> DrmPresenter::create(
- const native_handle_t* handle) {
- cros_gralloc_handle* crosHandle = (cros_gralloc_handle*)handle;
- if (crosHandle == nullptr) {
- ALOGE("%s: invalid cros_gralloc_handle", __FUNCTION__);
- return std::make_tuple(HWC3::Error::NoResources, nullptr);
- }
-
- DrmPrimeBufferHandle primeHandle = 0;
- int ret = drmPrimeFDToHandle(mFd.get(), crosHandle->fds[0], &primeHandle);
- if (ret) {
- ALOGE("%s: drmPrimeFDToHandle failed: %s (errno %d)", __FUNCTION__,
- strerror(errno), errno);
- return std::make_tuple(HWC3::Error::NoResources, nullptr);
- }
-
- auto drmBufferPtr = mBufferCache->get(primeHandle);
- if (drmBufferPtr != nullptr) {
- return std::make_tuple(HWC3::Error::None,
- std::shared_ptr<DrmBuffer>(*drmBufferPtr));
- }
-
- auto buffer = std::shared_ptr<DrmBuffer>(new DrmBuffer(*this));
- buffer->mWidth = crosHandle->width;
- buffer->mHeight = crosHandle->height;
- buffer->mDrmFormat = crosHandle->format;
- buffer->mPlaneFds[0] = crosHandle->fds[0];
- buffer->mPlaneHandles[0] = primeHandle;
- buffer->mPlanePitches[0] = crosHandle->strides[0];
- buffer->mPlaneOffsets[0] = crosHandle->offsets[0];
-
- uint32_t framebuffer = 0;
- ret = drmModeAddFB2(mFd.get(),
- buffer->mWidth,
- buffer->mHeight,
- buffer->mDrmFormat,
- buffer->mPlaneHandles,
- buffer->mPlanePitches,
- buffer->mPlaneOffsets,
- &framebuffer,
- 0);
- if (ret) {
- ALOGE("%s: drmModeAddFB2 failed: %s (errno %d)", __FUNCTION__,
- strerror(errno), errno);
- return std::make_tuple(HWC3::Error::NoResources, nullptr);
- }
- DEBUG_LOG("%s: created framebuffer:%" PRIu32, __FUNCTION__, framebuffer);
- buffer->mDrmFramebuffer = framebuffer;
-
- mBufferCache->set(primeHandle, std::shared_ptr<DrmBuffer>(buffer));
-
- return std::make_tuple(HWC3::Error::None,
- std::shared_ptr<DrmBuffer>(buffer));
-}
-
-HWC3::Error DrmPresenter::destroyDrmFramebuffer(DrmBuffer* buffer) {
- if (buffer->mDrmFramebuffer) {
- uint32_t framebuffer = *buffer->mDrmFramebuffer;
- if (drmModeRmFB(mFd.get(), framebuffer)) {
- ALOGE("%s: drmModeRmFB failed: %s (errno %d)", __FUNCTION__,
- strerror(errno), errno);
- return HWC3::Error::NoResources;
- }
- DEBUG_LOG("%s: destroyed framebuffer:%" PRIu32, __FUNCTION__, framebuffer);
- buffer->mDrmFramebuffer.reset();
- }
- if (buffer->mPlaneHandles[0]) {
- struct drm_gem_close gem_close = {};
- gem_close.handle = buffer->mPlaneHandles[0];
- if (drmIoctl(mFd.get(), DRM_IOCTL_GEM_CLOSE, &gem_close)) {
- ALOGE("%s: DRM_IOCTL_GEM_CLOSE failed: %s (errno %d)", __FUNCTION__,
- strerror(errno), errno);
- return HWC3::Error::NoResources;
- }
-
- mBufferCache->remove(buffer->mPlaneHandles[0]);
- }
-
- return HWC3::Error::None;
-}
-
-bool DrmPresenter::handleHotplug() {
- std::vector<DrmConnector> oldConnectors(mConnectors);
- {
- AutoReadLock lock(mStateMutex);
- oldConnectors.assign(mConnectors.begin(), mConnectors.end());
- }
- {
- AutoWriteLock lock(mStateMutex);
- resetDrmElementsLocked();
- if (!initDrmElementsLocked()) {
- ALOGE(
- "%s: failed to initialize drm elements during hotplug. Displays may "
- "not function correctly!",
- __FUNCTION__);
- return false;
- }
- }
-
- AutoReadLock lock(mStateMutex);
- for (int i = 0; i < mConnectors.size(); i++) {
- bool changed =
- oldConnectors[i].dpiX != mConnectors[i].dpiX ||
- oldConnectors[i].dpiY != mConnectors[i].dpiY ||
- oldConnectors[i].connection != mConnectors[i].connection ||
- oldConnectors[i].mMode.hdisplay != mConnectors[i].mMode.hdisplay ||
- oldConnectors[i].mMode.vdisplay != mConnectors[i].mMode.vdisplay;
- if (changed) {
- if (i == 0) {
- ALOGE(
- "%s: Ignoring changes to display:0 which is not configurable by "
- "multi-display interface.",
- __FUNCTION__);
- continue;
- }
-
- const bool connected =
- mConnectors[i].connection == DRM_MODE_CONNECTED ? true : false;
- if (mHotplugCallback) {
- (*mHotplugCallback)(connected, //
- i, //
- mConnectors[i].mMode.hdisplay, //
- mConnectors[i].mMode.vdisplay, //
- mConnectors[i].dpiX, //
- mConnectors[i].dpiY, //
- mConnectors[i].mRefreshRateAsInteger);
- }
- }
- }
- return true;
-}
-
-std::tuple<HWC3::Error, ::android::base::unique_fd>
-DrmPresenter::flushToDisplay(int display, const DrmBuffer& buffer,
- ::android::base::borrowed_fd inSyncFd) {
- ATRACE_CALL();
-
- if (!buffer.mDrmFramebuffer) {
- ALOGE("%s: failed, no framebuffer created.", __FUNCTION__);
- return std::make_tuple(HWC3::Error::NoResources,
- ::android::base::unique_fd());
- }
-
- AutoReadLock lock(mStateMutex);
-
- DrmConnector& connector = mConnectors[display];
- DrmCrtc& crtc = mCrtcs[display];
-
- HWC3::Error error = HWC3::Error::None;
-
- drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
-
- int ret;
-
- if (!crtc.mDidSetCrtc) {
- DEBUG_LOG("%s: Setting crtc.\n", __FUNCTION__);
- ret = drmModeAtomicAddProperty(pset, crtc.mId, crtc.mActivePropertyId, 1);
- if (ret < 0) {
- ALOGE("%s:%d: failed: %s\n", __FUNCTION__, __LINE__, strerror(errno));
- }
- ret = drmModeAtomicAddProperty(pset, crtc.mId, crtc.mModePropertyId,
- connector.mModeBlobId);
- if (ret < 0) {
- ALOGE("%s:%d: failed: %s\n", __FUNCTION__, __LINE__, strerror(errno));
- }
- ret = drmModeAtomicAddProperty(pset, connector.mId,
- connector.mCrtcPropertyId, crtc.mId);
- if (ret < 0) {
- ALOGE("%s:%d: failed: %s\n", __FUNCTION__, __LINE__, strerror(errno));
- }
-
- crtc.mDidSetCrtc = true;
- } else {
- DEBUG_LOG("%s: Already set crtc\n", __FUNCTION__);
- }
-
- int flushFenceFd = -1;
- ret = drmModeAtomicAddProperty(pset, crtc.mId, crtc.mOutFencePtrPropertyId,
- addressAsUint(&flushFenceFd));
- if (ret < 0) {
- ALOGE("%s:%d: set OUT_FENCE_PTR failed %d errno %d\n", __FUNCTION__,
- __LINE__, ret, errno);
- }
-
- if (crtc.mPlaneId == -1) {
- ALOGE("%s:%d: no plane available for crtc id %" PRIu32, __FUNCTION__,
- __LINE__, crtc.mId);
- return std::make_tuple(HWC3::Error::NoResources,
- ::android::base::unique_fd());
- }
-
- DrmPlane& plane = mPlanes[crtc.mPlaneId];
-
- DEBUG_LOG("%s: set plane: plane id %d crtc id %d fbid %d bo w h %d %d\n",
- __FUNCTION__, plane.mId, crtc.mId, *buffer.mDrmFramebuffer,
- buffer.mWidth, buffer.mHeight);
-
- ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcPropertyId,
- crtc.mId);
- if (ret < 0) {
- ALOGE("%s:%d: failed: %s\n", __FUNCTION__, __LINE__, strerror(errno));
- }
- ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mInFenceFdPropertyId,
- inSyncFd.get());
- if (ret < 0) {
- ALOGE("%s:%d: failed: %s\n", __FUNCTION__, __LINE__, strerror(errno));
- }
- ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mFbPropertyId,
- *buffer.mDrmFramebuffer);
- if (ret < 0) {
- ALOGE("%s:%d: failed: %s\n", __FUNCTION__, __LINE__, strerror(errno));
- }
- ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcXPropertyId, 0);
- if (ret < 0) {
- ALOGE("%s:%d: failed: %s\n", __FUNCTION__, __LINE__, strerror(errno));
- }
- ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcYPropertyId, 0);
- if (ret < 0) {
- ALOGE("%s:%d: failed: %s\n", __FUNCTION__, __LINE__, strerror(errno));
- }
- ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcWPropertyId,
- buffer.mWidth);
- if (ret < 0) {
- ALOGE("%s:%d: failed: %s\n", __FUNCTION__, __LINE__, strerror(errno));
- }
- ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcHPropertyId,
- buffer.mHeight);
- if (ret < 0) {
- ALOGE("%s:%d: failed: %s\n", __FUNCTION__, __LINE__, strerror(errno));
- }
- ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mSrcXPropertyId, 0);
- if (ret < 0) {
- ALOGE("%s:%d: failed: %s\n", __FUNCTION__, __LINE__, strerror(errno));
- }
- ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mSrcYPropertyId, 0);
- if (ret < 0) {
- ALOGE("%s:%d: failed: %s\n", __FUNCTION__, __LINE__, strerror(errno));
- }
- ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mSrcWPropertyId,
- buffer.mWidth << 16);
- if (ret < 0) {
- ALOGE("%s:%d: failed: %s\n", __FUNCTION__, __LINE__, strerror(errno));
- }
- ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mSrcHPropertyId,
- buffer.mHeight << 16);
- if (ret < 0) {
- ALOGE("%s:%d: failed: %s\n", __FUNCTION__, __LINE__, strerror(errno));
- }
-
- constexpr const uint32_t kCommitFlags = DRM_MODE_ATOMIC_ALLOW_MODESET;
- ret = drmModeAtomicCommit(mFd.get(), pset, kCommitFlags, 0);
-
- if (ret) {
- ALOGE("%s:%d: atomic commit failed: %s\n", __FUNCTION__, __LINE__,
- strerror(errno));
- error = HWC3::Error::NoResources;
- flushFenceFd = -1;
- }
-
- if (pset) {
- drmModeAtomicFree(pset);
- }
-
- DEBUG_LOG("%s: flush fence:%d\n", __FUNCTION__, flushFenceFd);
- return std::make_tuple(error, ::android::base::unique_fd(flushFenceFd));
-}
-
-std::optional<std::vector<uint8_t>> DrmPresenter::getEdid(uint32_t id) {
- AutoReadLock lock(mStateMutex);
-
- if (mConnectors[id].mEdidBlobId == -1) {
- DEBUG_LOG("%s: EDID not supported", __func__);
- return std::nullopt;
- }
- drmModePropertyBlobPtr blob =
- drmModeGetPropertyBlob(mFd.get(), mConnectors[id].mEdidBlobId);
- if (!blob) {
- ALOGE("%s: fail to read EDID from DRM", __func__);
- return std::nullopt;
- }
-
- std::vector<uint8_t> edid;
- uint8_t* start = static_cast<uint8_t*>(blob->data);
- edid.insert(edid.begin(), start, start + blob->length);
-
- drmModeFreePropertyBlob(blob);
-
- return edid;
-}
-
-DrmBuffer::DrmBuffer(DrmPresenter& DrmPresenter)
- : mDrmPresenter(DrmPresenter) {}
-
-DrmBuffer::~DrmBuffer() { mDrmPresenter.destroyDrmFramebuffer(this); }
-
-DrmPresenter::DrmEventListener::DrmEventListener(DrmPresenter& presenter)
- : mPresenter(presenter) {}
-
-DrmPresenter::DrmEventListener::~DrmEventListener() {}
-
-bool DrmPresenter::DrmEventListener::init() {
- mEventFd = ::android::base::unique_fd(
- socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT));
- if (!mEventFd.ok()) {
- ALOGE("Failed to open uevent socket: %s", strerror(errno));
- return false;
- }
- struct sockaddr_nl addr;
- memset(&addr, 0, sizeof(addr));
- addr.nl_family = AF_NETLINK;
- addr.nl_pid = 0;
- addr.nl_groups = 0xFFFFFFFF;
-
- int ret = bind(mEventFd, (struct sockaddr*)&addr, sizeof(addr));
- if (ret) {
- ALOGE("Failed to bind uevent socket: %s", strerror(errno));
- return false;
- }
-
- FD_ZERO(&mMonitoredFds);
- FD_SET(mPresenter.mFd.get(), &mMonitoredFds);
- FD_SET(mEventFd.get(), &mMonitoredFds);
- mMaxFd = std::max(mPresenter.mFd.get(), mEventFd.get());
-
- return true;
-}
-
-bool DrmPresenter::DrmEventListener::threadLoop() {
- int ret;
- do {
- ret = select(mMaxFd + 1, &mMonitoredFds, NULL, NULL, NULL);
- } while (ret == -1 && errno == EINTR);
-
- // if (FD_ISSET(mPresenter.mFd, &mFds)) {
- // TODO: handle drm related events
- // }
-
- if (FD_ISSET(mEventFd.get(), &mMonitoredFds)) {
- eventThreadLoop();
- }
- return true;
-}
-
-void DrmPresenter::DrmEventListener::eventThreadLoop() {
- char buffer[1024];
- int ret;
-
- struct timespec ts;
- uint64_t timestamp = 0;
- ret = clock_gettime(CLOCK_MONOTONIC, &ts);
- if (!ret) {
- timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
- } else {
- ALOGE("Failed to get monotonic clock on hotplug %d", ret);
- }
-
- while (true) {
- ret = read(mEventFd.get(), &buffer, sizeof(buffer));
- if (ret == 0) {
- return;
- } else if (ret < 0) {
- ALOGE("Got error reading uevent %d", ret);
- return;
- }
-
- bool drmEvent = false, hotplugEvent = false;
- for (int i = 0; i < ret;) {
- char* event = buffer + i;
- if (strcmp(event, "DEVTYPE=drm_minor")) {
- drmEvent = true;
- } else if (strcmp(event, "HOTPLUG=1")) {
- hotplugEvent = true;
- }
-
- i += strlen(event) + 1;
- }
-
- if (drmEvent && hotplugEvent) {
- processHotplug(timestamp);
- }
- }
-}
-
-void DrmPresenter::DrmEventListener::processHotplug(uint64_t timestamp) {
- ALOGD("DrmEventListener detected hotplug event %" PRIu64, timestamp);
- mPresenter.handleHotplug();
-}
-
-} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmPresenter.h b/system/hwc3/DrmPresenter.h
deleted file mode 100644
index 72e3f5a5..00000000
--- a/system/hwc3/DrmPresenter.h
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * 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_DRMPRESENTER_H
-#define ANDROID_HWC_DRMPRESENTER_H
-
-#include <android-base/unique_fd.h>
-#include <cutils/native_handle.h>
-#include <utils/Thread.h>
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-
-#include <map>
-#include <memory>
-#include <tuple>
-#include <vector>
-
-#include "Common.h"
-#include "LruCache.h"
-#include "android/base/synchronization/AndroidLock.h"
-
-namespace aidl::android::hardware::graphics::composer3::impl {
-
-class DrmBuffer;
-class DrmPresenter;
-
-// A RAII object that will clear a drm framebuffer upon destruction.
-class DrmBuffer {
- public:
- ~DrmBuffer();
-
- DrmBuffer(const DrmBuffer&) = delete;
- DrmBuffer& operator=(const DrmBuffer&) = delete;
-
- DrmBuffer(DrmBuffer&&) = delete;
- DrmBuffer& operator=(DrmBuffer&&) = delete;
-
- private:
- friend class DrmPresenter;
- DrmBuffer(DrmPresenter& drmPresenter);
-
- DrmPresenter& mDrmPresenter;
-
- uint32_t mWidth = 0;
- uint32_t mHeight = 0;
- uint32_t mDrmFormat = 0;
- uint32_t mPlaneFds[4] = {0, 0, 0, 0};
- uint32_t mPlaneHandles[4] = {0, 0, 0, 0};
- uint32_t mPlanePitches[4] = {0, 0, 0, 0};
- uint32_t mPlaneOffsets[4] = {0, 0, 0, 0};
- std::optional<uint32_t> mDrmFramebuffer;
-};
-
-class DrmPresenter {
- public:
- DrmPresenter() = default;
- ~DrmPresenter();
-
- DrmPresenter(const DrmPresenter&) = delete;
- DrmPresenter& operator=(const DrmPresenter&) = delete;
-
- DrmPresenter(DrmPresenter&&) = delete;
- DrmPresenter& operator=(DrmPresenter&&) = delete;
-
- HWC3::Error init();
-
- struct DisplayConfig {
- uint32_t id;
- uint32_t width;
- uint32_t height;
- uint32_t dpiX;
- uint32_t dpiY;
- uint32_t refreshRateHz;
- };
-
- HWC3::Error getDisplayConfigs(std::vector<DisplayConfig>* configs) const;
-
- using HotplugCallback = std::function<void(bool /*connected*/, //
- uint32_t /*id*/, //
- uint32_t /*width*/, //
- uint32_t /*height*/, //
- uint32_t /*dpiX*/, //
- uint32_t /*dpiY*/, //
- uint32_t /*refreshRate*/)>;
-
- HWC3::Error registerOnHotplugCallback(const HotplugCallback& cb);
- HWC3::Error unregisterOnHotplugCallback();
-
- uint32_t refreshRate() const { return mConnectors[0].mRefreshRateAsInteger; }
-
- std::tuple<HWC3::Error, std::shared_ptr<DrmBuffer>> create(
- const native_handle_t* handle);
-
- std::tuple<HWC3::Error, ::android::base::unique_fd> flushToDisplay(
- int display, const DrmBuffer& buffer,
- ::android::base::borrowed_fd inWaitSyncFd);
-
- std::optional<std::vector<uint8_t>> getEdid(uint32_t id);
-
- private:
- // TODO: make this cache per display when enabling hotplug support.
- using DrmPrimeBufferHandle = uint32_t;
- using DrmBufferCache = LruCache<DrmPrimeBufferHandle, std::shared_ptr<DrmBuffer>>;
- std::unique_ptr<DrmBufferCache> mBufferCache;
-
- // Grant visibility to destroyDrmFramebuffer to DrmBuffer.
- friend class DrmBuffer;
- HWC3::Error destroyDrmFramebuffer(DrmBuffer* buffer);
-
- // Grant visibility for handleHotplug to DrmEventListener.
- bool handleHotplug();
-
- bool initDrmElementsLocked();
- void resetDrmElementsLocked();
-
- // Drm device.
- ::android::base::unique_fd mFd;
-
- std::optional<HotplugCallback> mHotplugCallback;
-
- // Protects access to the below drm structs.
- mutable ::android::base::guest::ReadWriteLock mStateMutex;
-
- struct DrmPlane {
- uint32_t mId = -1;
- uint32_t mCrtcPropertyId = -1;
- uint32_t mInFenceFdPropertyId = -1;
- uint32_t mFbPropertyId = -1;
- uint32_t mCrtcXPropertyId = -1;
- uint32_t mCrtcYPropertyId = -1;
- uint32_t mCrtcWPropertyId = -1;
- uint32_t mCrtcHPropertyId = -1;
- uint32_t mSrcXPropertyId = -1;
- uint32_t mSrcYPropertyId = -1;
- uint32_t mSrcWPropertyId = -1;
- uint32_t mSrcHPropertyId = -1;
- uint32_t mTypePropertyId = -1;
- uint64_t mType = -1;
- };
- std::map<uint32_t, DrmPlane> mPlanes;
-
- struct DrmCrtc {
- uint32_t mId = -1;
- uint32_t mActivePropertyId = -1;
- uint32_t mModePropertyId = -1;
- uint32_t mOutFencePtrPropertyId = -1;
- uint32_t mPlaneId = -1;
-
- bool mDidSetCrtc = false;
- };
- std::vector<DrmCrtc> mCrtcs;
-
- struct DrmConnector {
- uint32_t mId = -1;
- uint32_t mCrtcPropertyId = -1;
- drmModeModeInfo mMode;
- int32_t dpiX;
- int32_t dpiY;
- drmModeConnection connection;
- uint32_t mModeBlobId = 0;
- float mRefreshRateAsFloat;
- uint32_t mRefreshRateAsInteger;
- uint64_t mEdidBlobId = -1;
- };
- std::vector<DrmConnector> mConnectors;
-
- class DrmEventListener : public ::android::Thread {
- public:
- DrmEventListener(DrmPresenter& presenter);
- virtual ~DrmEventListener();
-
- bool init();
-
- private:
- bool threadLoop() final;
- void eventThreadLoop();
- void processHotplug(uint64_t timestamp);
-
- DrmPresenter& mPresenter;
- ::android::base::unique_fd mEventFd;
- int mMaxFd;
- fd_set mMonitoredFds;
- };
- ::android::sp<DrmEventListener> mDrmEventListener;
-};
-
-} // namespace aidl::android::hardware::graphics::composer3::impl
-
-#endif
diff --git a/system/hwc3/DrmProperty.h b/system/hwc3/DrmProperty.h
new file mode 100644
index 00000000..9e7b7984
--- /dev/null
+++ b/system/hwc3/DrmProperty.h
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include <cstdint>
+#include <string>
+#include <unordered_map>
+
+#include "Common.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+class DrmProperty {
+ public:
+ DrmProperty() {}
+ DrmProperty(uint32_t id, uint64_t value, std::string name)
+ : mId(id), mValue(value), mName(name) {}
+
+ ~DrmProperty() {}
+
+ uint32_t getId() const { return mId; }
+
+ uint64_t getValue() const { return mValue; }
+
+ const std::string& getName() const { return mName; }
+
+ private:
+ uint32_t mId = -1;
+ uint64_t mValue = -1;
+ std::string mName;
+};
+
+template <typename T>
+using DrmPropertyMember = DrmProperty T::*;
+
+template <typename T>
+using DrmPropertyMemberMap = std::unordered_map<std::string, DrmPropertyMember<T>>;
+
+// Helper to many DrmProperty members for DrmCrtc, DrmConnector, and DrmPlane.
+template <typename T>
+bool LoadDrmProperties(::android::base::borrowed_fd drmFd, uint32_t objectId, uint32_t objectType,
+ const DrmPropertyMemberMap<T>& objectPropertyMap, T* object) {
+ auto drmProperties = drmModeObjectGetProperties(drmFd.get(), objectId, objectType);
+ if (!drmProperties) {
+ ALOGE("%s: Failed to get properties: %s", __FUNCTION__, strerror(errno));
+ return false;
+ }
+
+ for (uint32_t i = 0; i < drmProperties->count_props; ++i) {
+ const auto propertyId = drmProperties->props[i];
+
+ auto drmProperty = drmModeGetProperty(drmFd.get(), propertyId);
+ if (!drmProperty) {
+ ALOGE("%s: Failed to get property: %s", __FUNCTION__, strerror(errno));
+ continue;
+ }
+
+ const auto propertyName = drmProperty->name;
+ const auto propertyValue = drmProperties->prop_values[i];
+
+ auto it = objectPropertyMap.find(propertyName);
+ if (it != objectPropertyMap.end()) {
+ DEBUG_LOG("%s: Loaded property:%" PRIu32 " (%s) val:%" PRIu64, __FUNCTION__, propertyId,
+ propertyName, propertyValue);
+
+ auto& objectPointerToMember = it->second;
+ object->*objectPointerToMember = DrmProperty(propertyId, propertyValue, propertyName);
+ }
+
+ drmModeFreeProperty(drmProperty);
+ }
+
+ drmModeFreeObjectProperties(drmProperties);
+
+ return true;
+}
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/FrameComposer.h b/system/hwc3/FrameComposer.h
index 794855b8..70e0f00a 100644
--- a/system/hwc3/FrameComposer.h
+++ b/system/hwc3/FrameComposer.h
@@ -26,7 +26,7 @@
#include "Common.h"
#include "DisplayChanges.h"
-#include "DrmPresenter.h"
+#include "DrmClient.h"
namespace aidl::android::hardware::graphics::composer3::impl {
@@ -70,7 +70,7 @@ class FrameComposer {
virtual HWC3::Error onActiveConfigChange(Display* display) = 0;
- virtual const DrmPresenter* getDrmPresenter() const {
+ virtual const DrmClient* getDrmPresenter() const {
return nullptr;
}
};
diff --git a/system/hwc3/GuestFrameComposer.cpp b/system/hwc3/GuestFrameComposer.cpp
index 7d4b0dcd..d28f57ca 100644
--- a/system/hwc3/GuestFrameComposer.cpp
+++ b/system/hwc3/GuestFrameComposer.cpp
@@ -410,9 +410,9 @@ std::optional<BufferSpec> GetBufferSpec(GrallocBuffer& buffer,
HWC3::Error GuestFrameComposer::init() {
DEBUG_LOG("%s", __FUNCTION__);
- HWC3::Error error = mDrmPresenter.init();
+ HWC3::Error error = mDrmClient.init();
if (error != HWC3::Error::None) {
- ALOGE("%s: failed to initialize DrmPresenter", __FUNCTION__);
+ ALOGE("%s: failed to initialize DrmClient", __FUNCTION__);
return error;
}
@@ -421,12 +421,12 @@ HWC3::Error GuestFrameComposer::init() {
HWC3::Error GuestFrameComposer::registerOnHotplugCallback(
const HotplugCallback& cb) {
- return mDrmPresenter.registerOnHotplugCallback(cb);
+ return mDrmClient.registerOnHotplugCallback(cb);
return HWC3::Error::None;
}
HWC3::Error GuestFrameComposer::unregisterOnHotplugCallback() {
- return mDrmPresenter.unregisterOnHotplugCallback();
+ return mDrmClient.unregisterOnHotplugCallback();
}
HWC3::Error GuestFrameComposer::onDisplayCreate(Display* display) {
@@ -487,7 +487,7 @@ HWC3::Error GuestFrameComposer::onDisplayCreate(Display* display) {
displayInfo.compositionResultBuffer = bufferHandle;
- auto [drmBufferCreateError, drmBuffer] = mDrmPresenter.create(bufferHandle);
+ auto [drmBufferCreateError, drmBuffer] = mDrmClient.create(bufferHandle);
if (drmBufferCreateError != HWC3::Error::None) {
ALOGE("%s: failed to create drm buffer for display:%" PRIu64, __FUNCTION__,
displayId);
@@ -496,8 +496,8 @@ HWC3::Error GuestFrameComposer::onDisplayCreate(Display* display) {
displayInfo.compositionResultDrmBuffer = std::move(drmBuffer);
if (displayId == 0) {
- auto [flushError, flushSyncFd] = mDrmPresenter.flushToDisplay(
- displayId, *displayInfo.compositionResultDrmBuffer, -1);
+ auto [flushError, flushSyncFd] = mDrmClient.flushToDisplay(
+ displayId, displayInfo.compositionResultDrmBuffer, -1);
if (flushError != HWC3::Error::None) {
ALOGW(
"%s: Initial display flush failed. HWComposer assuming that we are "
@@ -507,7 +507,7 @@ HWC3::Error GuestFrameComposer::onDisplayCreate(Display* display) {
}
}
- std::optional<std::vector<uint8_t>> edid = mDrmPresenter.getEdid(displayId);
+ std::optional<std::vector<uint8_t>> edid = mDrmClient.getEdid(displayId);
if (edid) {
display->setEdid(*edid);
}
@@ -888,8 +888,8 @@ HWC3::Error GuestFrameComposer::presentDisplay(
DEBUG_LOG("%s display:%" PRIu64 " flushing drm buffer", __FUNCTION__,
displayId);
- auto [error, fence] = mDrmPresenter.flushToDisplay(
- displayId, *displayInfo.compositionResultDrmBuffer, -1);
+ auto [error, fence] = mDrmClient.flushToDisplay(
+ displayId, displayInfo.compositionResultDrmBuffer, -1);
if (error != HWC3::Error::None) {
ALOGE("%s: display:%" PRIu64 " failed to flush drm buffer" PRIu64,
__FUNCTION__, displayId);
diff --git a/system/hwc3/GuestFrameComposer.h b/system/hwc3/GuestFrameComposer.h
index e37ff875..2df2f32b 100644
--- a/system/hwc3/GuestFrameComposer.h
+++ b/system/hwc3/GuestFrameComposer.h
@@ -19,7 +19,7 @@
#include "Common.h"
#include "Display.h"
-#include "DrmPresenter.h"
+#include "DrmClient.h"
#include "FrameComposer.h"
#include "Gralloc.h"
#include "Layer.h"
@@ -62,8 +62,8 @@ class GuestFrameComposer : public FrameComposer {
HWC3::Error onActiveConfigChange(Display* /*display*/) override;
- const DrmPresenter* getDrmPresenter() const override {
- return &mDrmPresenter;
+ const DrmClient* getDrmPresenter() const override {
+ return &mDrmClient;
}
private:
@@ -102,7 +102,7 @@ class GuestFrameComposer : public FrameComposer {
Gralloc mGralloc;
- DrmPresenter mDrmPresenter;
+ DrmClient mDrmClient;
// Cuttlefish on QEMU does not have a display. Disable presenting to avoid
// spamming logcat with DRM commit failures.
diff --git a/system/hwc3/HostFrameComposer.cpp b/system/hwc3/HostFrameComposer.cpp
index 7b090c2d..bcaaf59c 100644
--- a/system/hwc3/HostFrameComposer.cpp
+++ b/system/hwc3/HostFrameComposer.cpp
@@ -204,11 +204,11 @@ HWC3::Error HostFrameComposer::init() {
mUseAngle = useAngleFromProperty();
if (mIsMinigbm) {
- mDrmPresenter.emplace();
+ mDrmClient.emplace();
- HWC3::Error error = mDrmPresenter->init();
+ HWC3::Error error = mDrmClient->init();
if (error != HWC3::Error::None) {
- ALOGE("%s: failed to initialize DrmPresenter", __FUNCTION__);
+ ALOGE("%s: failed to initialize DrmClient", __FUNCTION__);
return error;
}
} else {
@@ -220,15 +220,15 @@ HWC3::Error HostFrameComposer::init() {
HWC3::Error HostFrameComposer::registerOnHotplugCallback(
const HotplugCallback& cb) {
- if (mDrmPresenter) {
- mDrmPresenter->registerOnHotplugCallback(cb);
+ if (mDrmClient) {
+ mDrmClient->registerOnHotplugCallback(cb);
}
return HWC3::Error::None;
}
HWC3::Error HostFrameComposer::unregisterOnHotplugCallback() {
- if (mDrmPresenter) {
- mDrmPresenter->unregisterOnHotplugCallback();
+ if (mDrmClient) {
+ mDrmClient->unregisterOnHotplugCallback();
}
return HWC3::Error::None;
}
@@ -280,9 +280,9 @@ HWC3::Error HostFrameComposer::createHostComposerDisplayInfo(
return HWC3::Error::NoResources;
}
- if (mDrmPresenter) {
+ if (mDrmClient) {
auto [drmBufferCreateError, drmBuffer] =
- mDrmPresenter->create(displayInfo.compositionResultBuffer);
+ mDrmClient->create(displayInfo.compositionResultBuffer);
if (drmBufferCreateError != HWC3::Error::None) {
ALOGE("%s: display:%" PRIu64 " failed to create target drm buffer",
__FUNCTION__, displayId);
@@ -384,8 +384,8 @@ HWC3::Error HostFrameComposer::onDisplayCreate(Display* display) {
}
std::optional<std::vector<uint8_t>> edid;
- if (mDrmPresenter) {
- edid = mDrmPresenter->getEdid(displayId);
+ if (mDrmClient) {
+ edid = mDrmClient->getEdid(displayId);
if (edid) {
display->setEdid(*edid);
}
@@ -436,7 +436,7 @@ HWC3::Error HostFrameComposer::onDisplayClientTargetSet(Display* display) {
FencedBuffer& clientTargetFencedBuffer = display->getClientTarget();
auto [drmBufferCreateError, drmBuffer] =
- mDrmPresenter->create(clientTargetFencedBuffer.getBuffer());
+ mDrmClient->create(clientTargetFencedBuffer.getBuffer());
if (drmBufferCreateError != HWC3::Error::None) {
ALOGE("%s: display:%" PRIu64 " failed to create client target drm buffer",
__FUNCTION__, displayId);
@@ -586,8 +586,8 @@ HWC3::Error HostFrameComposer::presentDisplay(
if (displayClientTarget.getBuffer() != nullptr) {
::android::base::unique_fd fence = displayClientTarget.getFence();
if (mIsMinigbm) {
- auto [_, flushCompleteFence] = mDrmPresenter->flushToDisplay(
- displayId, *displayInfo.clientTargetDrmBuffer, fence);
+ auto [_, flushCompleteFence] = mDrmClient->flushToDisplay(
+ displayId, displayInfo.clientTargetDrmBuffer, fence);
*outDisplayFence = std::move(flushCompleteFence);
} else {
@@ -730,8 +730,8 @@ HWC3::Error HostFrameComposer::presentDisplay(
}
if (mIsMinigbm) {
- auto [_, fence] = mDrmPresenter->flushToDisplay(
- displayId, *displayInfo.compositionResultDrmBuffer, -1);
+ auto [_, fence] = mDrmClient->flushToDisplay(
+ displayId, displayInfo.compositionResultDrmBuffer, -1);
retire_fd = std::move(fence);
} else {
int fd;
@@ -761,8 +761,8 @@ HWC3::Error HostFrameComposer::presentDisplay(
::android::base::unique_fd displayClientTargetFence =
displayClientTarget.getFence();
if (mIsMinigbm) {
- auto [_, flushFence] = mDrmPresenter->flushToDisplay(
- displayId, *displayInfo.compositionResultDrmBuffer,
+ auto [_, flushFence] = mDrmClient->flushToDisplay(
+ displayId, displayInfo.compositionResultDrmBuffer,
displayClientTargetFence);
*outDisplayFence = std::move(flushFence);
} else {
diff --git a/system/hwc3/HostFrameComposer.h b/system/hwc3/HostFrameComposer.h
index 42eb43a6..aebf7160 100644
--- a/system/hwc3/HostFrameComposer.h
+++ b/system/hwc3/HostFrameComposer.h
@@ -23,7 +23,7 @@
#include <tuple>
#include "Common.h"
-#include "DrmPresenter.h"
+#include "DrmClient.h"
#include "FrameComposer.h"
#include "HostConnection.h"
@@ -65,9 +65,9 @@ class HostFrameComposer : public FrameComposer {
HWC3::Error onActiveConfigChange(Display* display) override;
- const DrmPresenter* getDrmPresenter() const override {
- if (mDrmPresenter) {
- return &*mDrmPresenter;
+ const DrmClient* getDrmPresenter() const override {
+ if (mDrmClient) {
+ return &*mDrmClient;
}
return nullptr;
}
@@ -100,7 +100,7 @@ class HostFrameComposer : public FrameComposer {
std::unordered_map<int64_t, HostComposerDisplayInfo> mDisplayInfos;
- std::optional<DrmPresenter> mDrmPresenter;
+ std::optional<DrmClient> mDrmClient;
};
} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/NoOpFrameComposer.h b/system/hwc3/NoOpFrameComposer.h
index 4722477a..b773a3e5 100644
--- a/system/hwc3/NoOpFrameComposer.h
+++ b/system/hwc3/NoOpFrameComposer.h
@@ -19,7 +19,7 @@
#include "Common.h"
#include "Display.h"
-#include "DrmPresenter.h"
+#include "DrmClient.h"
#include "FrameComposer.h"
#include "Gralloc.h"
#include "Layer.h"