sdm: hwc2: Add support for HWC Readback feature
Add support for HWC Readback feature in HWC2 and SDM.
CRs-Fixed: 2217822
Change-Id: If2df64dc0bdea7a9ca4c2b0498f1cd3f3dc9de9d
diff --git a/sdm/libs/hwc2/hwc_display_primary.cpp b/sdm/libs/hwc2/hwc_display_primary.cpp
index c68081a..4751c98 100644
--- a/sdm/libs/hwc2/hwc_display_primary.cpp
+++ b/sdm/libs/hwc2/hwc_display_primary.cpp
@@ -31,6 +31,7 @@
#include <sync/sync.h>
#include <utils/constants.h>
#include <utils/debug.h>
+#include <utils/utils.h>
#include <stdarg.h>
#include <sys/mman.h>
@@ -185,11 +186,15 @@
bool pending_output_dump = dump_frame_count_ && dump_output_to_file_;
- if (frame_capture_buffer_queued_ || pending_output_dump) {
+ if (readback_buffer_queued_ || pending_output_dump) {
+ CloseFd(&output_buffer_.release_fence_fd);
// RHS values were set in FrameCaptureAsync() called from a binder thread. They are picked up
- // here in a subsequent draw round.
- layer_stack_.output_buffer = &output_buffer_;
- layer_stack_.flags.post_processed_output = post_processed_output_;
+ // here in a subsequent draw round. Readback is not allowed for any secure use case.
+ readback_configured_ = !layer_stack_.flags.secure_present;
+ if (readback_configured_) {
+ layer_stack_.output_buffer = &output_buffer_;
+ layer_stack_.flags.post_processed_output = post_processed_output_;
+ }
}
uint32_t num_updating_layers = GetUpdatingLayersCount();
@@ -234,6 +239,7 @@
}
}
+ CloseFd(&output_buffer_.acquire_fence_fd);
return status;
}
@@ -306,6 +312,52 @@
return status;
}
+HWC2::Error HWCDisplayPrimary::SetReadbackBuffer(const native_handle_t *buffer,
+ int32_t acquire_fence,
+ bool post_processed_output) {
+ const private_handle_t *handle = reinterpret_cast<const private_handle_t *>(buffer);
+ if (!handle || (handle->fd < 0)) {
+ return HWC2::Error::BadParameter;
+ }
+
+ // Configure the output buffer as Readback buffer
+ output_buffer_.width = UINT32(handle->width);
+ output_buffer_.height = UINT32(handle->height);
+ output_buffer_.unaligned_width = UINT32(handle->unaligned_width);
+ output_buffer_.unaligned_height = UINT32(handle->unaligned_height);
+ output_buffer_.format = HWCLayer::GetSDMFormat(handle->format, handle->flags);
+ output_buffer_.planes[0].fd = handle->fd;
+ output_buffer_.planes[0].stride = UINT32(handle->width);
+ output_buffer_.acquire_fence_fd = dup(acquire_fence);
+ output_buffer_.release_fence_fd = -1;
+
+ post_processed_output_ = post_processed_output;
+ readback_buffer_queued_ = true;
+ readback_configured_ = false;
+ validated_ = false;
+
+ DisablePartialUpdateOneFrame();
+ return HWC2::Error::None;
+}
+
+HWC2::Error HWCDisplayPrimary::GetReadbackBufferFence(int32_t *release_fence) {
+ auto status = HWC2::Error::None;
+
+ if (readback_configured_ && (output_buffer_.release_fence_fd >= 0)) {
+ *release_fence = output_buffer_.release_fence_fd;
+ } else {
+ status = HWC2::Error::Unsupported;
+ *release_fence = -1;
+ }
+
+ post_processed_output_ = false;
+ readback_buffer_queued_ = false;
+ readback_configured_ = false;
+ output_buffer_ = {};
+
+ return status;
+}
+
int HWCDisplayPrimary::Perform(uint32_t operation, ...) {
va_list args;
va_start(args, operation);
@@ -447,52 +499,30 @@
validated_ = false;
}
-static void SetLayerBuffer(const BufferInfo &output_buffer_info, LayerBuffer *output_buffer) {
- const BufferConfig& buffer_config = output_buffer_info.buffer_config;
- const AllocatedBufferInfo &alloc_buffer_info = output_buffer_info.alloc_buffer_info;
-
- output_buffer->width = alloc_buffer_info.aligned_width;
- output_buffer->height = alloc_buffer_info.aligned_height;
- output_buffer->unaligned_width = buffer_config.width;
- output_buffer->unaligned_height = buffer_config.height;
- output_buffer->format = buffer_config.format;
- output_buffer->planes[0].fd = alloc_buffer_info.fd;
- output_buffer->planes[0].stride = alloc_buffer_info.stride;
-}
-
void HWCDisplayPrimary::HandleFrameOutput() {
- if (frame_capture_buffer_queued_) {
- HandleFrameCapture();
- } else if (dump_output_to_file_) {
+ if (readback_buffer_queued_) {
+ validated_ = false;
+ }
+
+ if (dump_output_to_file_) {
HandleFrameDump();
}
}
-void HWCDisplayPrimary::HandleFrameCapture() {
- if (output_buffer_.release_fence_fd >= 0) {
- frame_capture_status_ = sync_wait(output_buffer_.release_fence_fd, 1000);
- ::close(output_buffer_.release_fence_fd);
- output_buffer_.release_fence_fd = -1;
+void HWCDisplayPrimary::HandleFrameDump() {
+ if (!readback_configured_) {
+ dump_frame_count_ = 0;
}
- frame_capture_buffer_queued_ = false;
- post_processed_output_ = false;
- output_buffer_ = {};
-}
-
-void HWCDisplayPrimary::HandleFrameDump() {
- if (dump_frame_count_) {
- int ret = 0;
- if (output_buffer_.release_fence_fd >= 0) {
- ret = sync_wait(output_buffer_.release_fence_fd, 1000);
- ::close(output_buffer_.release_fence_fd);
- output_buffer_.release_fence_fd = -1;
- if (ret < 0) {
- DLOGE("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
- }
- }
- if (ret >= 0) {
+ if (dump_frame_count_ && output_buffer_.release_fence_fd >= 0) {
+ int ret = sync_wait(output_buffer_.release_fence_fd, 1000);
+ ::close(output_buffer_.release_fence_fd);
+ output_buffer_.release_fence_fd = -1;
+ if (ret < 0) {
+ DLOGE("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
+ } else {
DumpOutputBuffer(output_buffer_info_, output_buffer_base_, layer_stack_.retire_fence_fd);
+ readback_buffer_queued_ = false;
}
}
@@ -506,7 +536,10 @@
DLOGE("FreeBuffer failed");
}
+ readback_buffer_queued_ = false;
post_processed_output_ = false;
+ readback_configured_ = false;
+
output_buffer_ = {};
output_buffer_info_ = {};
output_buffer_base_ = nullptr;
@@ -546,9 +579,9 @@
}
output_buffer_base_ = buffer;
- post_processed_output_ = true;
- DisablePartialUpdateOneFrame();
- validated_ = false;
+ const native_handle_t *handle = static_cast<native_handle_t *>(output_buffer_info_.private_data);
+ SetReadbackBuffer(handle, -1, true);
+
return HWC2::Error::None;
}
@@ -578,16 +611,16 @@
return -1;
}
- SetLayerBuffer(output_buffer_info, &output_buffer_);
- post_processed_output_ = post_processed_output;
- frame_capture_buffer_queued_ = true;
- // Status is only cleared on a new call to dump and remains valid otherwise
- frame_capture_status_ = -EAGAIN;
- DisablePartialUpdateOneFrame();
+ const native_handle_t *buffer = static_cast<native_handle_t *>(output_buffer_info.private_data);
+ SetReadbackBuffer(buffer, -1, post_processed_output);
return 0;
}
+bool HWCDisplayPrimary::GetFrameCaptureFence(int32_t *release_fence) {
+ return (GetReadbackBufferFence(release_fence) == HWC2::Error::None);
+}
+
DisplayError HWCDisplayPrimary::SetDetailEnhancerConfig
(const DisplayDetailEnhancerData &de_data) {
DisplayError error = kErrorNotSupported;