diff options
author | Jason Macnak <natsu@google.com> | 2022-10-07 11:06:41 -0700 |
---|---|---|
committer | Jason Macnak <natsu@google.com> | 2022-10-11 10:33:05 -0700 |
commit | da49cb770d1a06f145b110827d685df7d3f24ac3 (patch) | |
tree | e1a5f74f42af60f7fe0c43418de44f11c3b39b5f | |
parent | ad3b3de56f49d50180a47535243e245ce4ea8226 (diff) | |
download | goldfish-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
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" |