drm_hwcomposer: Rework HWC frontends buffer management
Change summary:
- Use BufferInfo instead of native_buffer to configure the HwcLayer.
- Extend buffer properties with slot info.
- Provide fence and active slot ID separate from the buffer.
- Move swapchain tracking into HWC2. HWC3 doesn't need that.
Why:
- Support more flexible resource management control from the frontend
side, which is required by HWC3 API.
- Move more Android-specific data types to the frontend module.
Change-Id: Idaa4c552f600f78d6f0ad21997cfa7f3a6c6cbd8
Signed-off-by: Roman Stratiienko <r.stratiienko@gmail.com>
diff --git a/hwc2_device/hwc2_device.cpp b/hwc2_device/hwc2_device.cpp
index ac25cf6..10e1608 100644
--- a/hwc2_device/hwc2_device.cpp
+++ b/hwc2_device/hwc2_device.cpp
@@ -19,10 +19,16 @@
#define LOG_TAG "drmhwc"
+#include <cassert>
#include <cinttypes>
+#include <memory>
+#include <optional>
+
+#include <cutils/native_handle.h>
#include "DrmHwcTwo.h"
#include "backend/Backend.h"
+#include "hwc2_device/HwcLayer.h"
#include "utils/log.h"
namespace android {
@@ -43,6 +49,110 @@
return str.substr(p1, p2 - p1);
}
+class Hwc2DeviceLayer : public FrontendLayerBase {
+ public:
+ auto HandleNextBuffer(buffer_handle_t buffer_handle, int32_t fence_fd)
+ -> std::pair<std::optional<HwcLayer::LayerProperties>,
+ bool /* not a swapchain */> {
+ auto slot = GetSlotNumber(buffer_handle);
+
+ if (invalid_) {
+ return std::make_pair(std::nullopt, true);
+ }
+
+ bool buffer_provided = false;
+ bool not_a_swapchain = true;
+ int32_t slot_id = 0;
+
+ if (slot.has_value()) {
+ buffer_provided = swchain_slots_[slot.value()];
+ slot_id = slot.value();
+ not_a_swapchain = true;
+ }
+
+ HwcLayer::LayerProperties lp;
+ if (!buffer_provided) {
+ auto bo_info = BufferInfoGetter::GetInstance()->GetBoInfo(buffer_handle);
+ if (!bo_info) {
+ invalid_ = true;
+ return std::make_pair(std::nullopt, true);
+ }
+
+ lp.slot_buffer = {
+ .slot_id = slot_id,
+ .bi = bo_info,
+ };
+ }
+ lp.active_slot = {
+ .slot_id = slot_id,
+ .fence = MakeSharedFd(fence_fd),
+ };
+
+ return std::make_pair(lp, not_a_swapchain);
+ }
+
+ void SwChainClearCache() {
+ swchain_lookup_table_.clear();
+ swchain_slots_.clear();
+ swchain_reassembled_ = false;
+ }
+
+ private:
+ auto GetSlotNumber(buffer_handle_t buffer_handle) -> std::optional<int32_t> {
+ auto unique_id = BufferInfoGetter::GetInstance()->GetUniqueId(
+ buffer_handle);
+ if (!unique_id) {
+ ALOGE("Failed to get unique id for buffer handle %p", buffer_handle);
+ return std::nullopt;
+ }
+
+ if (swchain_lookup_table_.count(*unique_id) == 0) {
+ SwChainReassemble(*unique_id);
+ return std::nullopt;
+ }
+
+ if (!swchain_reassembled_) {
+ return std::nullopt;
+ }
+
+ return swchain_lookup_table_[*unique_id];
+ }
+
+ void SwChainReassemble(BufferUniqueId unique_id) {
+ if (swchain_lookup_table_.count(unique_id) != 0) {
+ if (swchain_lookup_table_[unique_id] ==
+ int(swchain_lookup_table_.size()) - 1) {
+ /* Skip same buffer */
+ return;
+ }
+ if (swchain_lookup_table_[unique_id] == 0) {
+ swchain_reassembled_ = true;
+ return;
+ }
+ /* Tracking error */
+ SwChainClearCache();
+ return;
+ }
+
+ swchain_lookup_table_[unique_id] = int(swchain_lookup_table_.size());
+ }
+
+ bool invalid_{}; /* Layer is invalid and should be skipped */
+ std::map<BufferUniqueId, int /*slot*/> swchain_lookup_table_;
+ std::map<int /*slot*/, bool /*buffer_provided*/> swchain_slots_;
+ bool swchain_reassembled_{};
+};
+
+static auto GetHwc2DeviceLayer(HwcLayer &layer)
+ -> std::shared_ptr<Hwc2DeviceLayer> {
+ auto frontend_private_data = layer.GetFrontendPrivateData();
+ if (!frontend_private_data) {
+ frontend_private_data = std::make_shared<Hwc2DeviceLayer>();
+ layer.SetFrontendPrivateData(frontend_private_data);
+ }
+ return std::static_pointer_cast<Hwc2DeviceLayer>(frontend_private_data);
+}
+
struct Drmhwc2Device : hwc2_device {
DrmHwcTwo drmhwctwo;
};
@@ -149,20 +259,33 @@
LOCK_COMPOSER(device);
GET_DISPLAY(display);
+ auto &client_layer = idisplay->GetClientLayer();
+ auto h2l = GetHwc2DeviceLayer(client_layer);
+ if (!h2l) {
+ client_layer.SetFrontendPrivateData(std::make_shared<Hwc2DeviceLayer>());
+ }
+
if (target == nullptr) {
- idisplay->GetClientLayer().SwChainClearCache();
+ client_layer.ClearSlots();
+ h2l->SwChainClearCache();
+
return 0;
}
- HwcLayer::LayerProperties lp;
- lp.buffer = {
- .buffer_handle = target,
- .acquire_fence = MakeSharedFd(acquire_fence),
- };
- lp.color_space = Hwc2ToColorSpace(dataspace);
- lp.sample_range = Hwc2ToSampleRange(dataspace);
+ auto [lp, not_a_swapchain] = h2l->HandleNextBuffer(target, acquire_fence);
+ if (!lp) {
+ ALOGE("Failed to process client target");
+ return static_cast<int32_t>(HWC2::Error::BadLayer);
+ }
- idisplay->GetClientLayer().SetLayerProperties(lp);
+ if (not_a_swapchain) {
+ client_layer.ClearSlots();
+ }
+
+ lp->color_space = Hwc2ToColorSpace(dataspace);
+ lp->sample_range = Hwc2ToSampleRange(dataspace);
+
+ idisplay->GetClientLayer().SetLayerProperties(lp.value());
return 0;
}
@@ -179,12 +302,23 @@
return static_cast<int32_t>(HWC2::Error::BadLayer);
}
- HwcLayer::LayerProperties lp;
- lp.buffer = {
- .buffer_handle = buffer,
- .acquire_fence = MakeSharedFd(release_fence),
- };
- writeback_layer->SetLayerProperties(lp);
+ auto h2l = GetHwc2DeviceLayer(*writeback_layer);
+ if (!h2l) {
+ writeback_layer->SetFrontendPrivateData(
+ std::make_shared<Hwc2DeviceLayer>());
+ }
+
+ auto [lp, not_a_swapchain] = h2l->HandleNextBuffer(buffer, release_fence);
+ if (!lp) {
+ ALOGE("Failed to process output buffer");
+ return static_cast<int32_t>(HWC2::Error::BadLayer);
+ }
+
+ if (not_a_swapchain) {
+ writeback_layer->ClearSlots();
+ }
+
+ writeback_layer->SetLayerProperties(lp.value());
return 0;
}
@@ -232,10 +366,19 @@
GET_DISPLAY(display);
GET_LAYER(layer);
- HwcLayer::LayerProperties layer_properties;
- layer_properties.buffer = {.buffer_handle = buffer,
- .acquire_fence = MakeSharedFd(acquire_fence)};
- ilayer->SetLayerProperties(layer_properties);
+ auto h2l = GetHwc2DeviceLayer(*ilayer);
+
+ auto [lp, not_a_swapchain] = h2l->HandleNextBuffer(buffer, acquire_fence);
+ if (!lp) {
+ ALOGV("Failed to process layer buffer");
+ return static_cast<int32_t>(HWC2::Error::BadLayer);
+ }
+
+ if (not_a_swapchain) {
+ ilayer->ClearSlots();
+ }
+
+ ilayer->SetLayerProperties(lp.value());
return 0;
}