sdm: Implement layer stitch.
-- Program buffers to be stitched as part of Commit.
-- Close output fence as there is no client to wait on.
CRs-Fixed: 2568290
Change-Id: Ida80bda0e9648e40e34db098e5563f7ec0c20fc0
diff --git a/composer/hwc_display_builtin.cpp b/composer/hwc_display_builtin.cpp
index 85cdda6..c36fcf6 100644
--- a/composer/hwc_display_builtin.cpp
+++ b/composer/hwc_display_builtin.cpp
@@ -47,6 +47,13 @@
namespace sdm {
+static void SetRect(LayerRect &src_rect, GLRect *target) {
+ target->left = src_rect.left;
+ target->top = src_rect.top;
+ target->right = src_rect.right;
+ target->bottom = src_rect.bottom;
+}
+
int HWCDisplayBuiltIn::Create(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
HWCCallbacks *callbacks, HWCDisplayEventHandler *event_handler,
qService::QService *qservice, hwc2_display_t id, int32_t sdm_id,
@@ -96,7 +103,7 @@
: HWCDisplay(core_intf, buffer_allocator, callbacks, event_handler, qservice, kBuiltIn, id,
sdm_id, DISPLAY_CLASS_BUILTIN),
buffer_allocator_(buffer_allocator),
- cpu_hint_(NULL) {
+ cpu_hint_(NULL), layer_stitch_task_(*this) {
}
int HWCDisplayBuiltIn::Init() {
@@ -129,6 +136,10 @@
is_primary_ = display_intf_->IsPrimaryDisplay();
+ if (!InitLayerStitch()) {
+ DLOGW("Failed to initialize Layer Stitch context");
+ }
+
return status;
}
@@ -150,6 +161,10 @@
// Fill in the remaining blanks in the layers and add them to the SDM layerstack
BuildLayerStack();
+
+ // Add stitch layer to layer stack.
+ AppendStitchLayer();
+
// Checks and replaces layer stack for solid fill
SolidFillPrepare();
@@ -242,13 +257,52 @@
return skip_commit;
}
+HWC2::Error HWCDisplayBuiltIn::CommitStitchLayers() {
+ if (!validated_ || skip_commit_) {
+ return HWC2::Error::None;
+ }
+
+ if (disable_layer_stitch_) {
+ return HWC2::Error::None;
+ }
+
+ for (auto &layer : layer_stack_.layers) {
+ LayerComposition &composition = layer->composition;
+ if (composition != kCompositionStitch) {
+ continue;
+ }
+
+ LayerStitchStitchContext ctx = {};
+ // Stitch target doesn't have an input fence.
+ // Render all layers at specified destination.
+ LayerBuffer &input_buffer = layer->input_buffer;
+ ctx.src_hnd = reinterpret_cast<const private_handle_t *>(input_buffer.buffer_id);
+ Layer *stitch_layer = stitch_target_->GetSDMLayer();
+ LayerBuffer &output_buffer = stitch_layer->input_buffer;
+ ctx.dst_hnd = reinterpret_cast<const private_handle_t *>(output_buffer.buffer_id);
+ SetRect(layer->stitch_dst_rect, &ctx.dst_rect);
+ ctx.src_acquire_fence_fd = input_buffer.acquire_fence_fd;
+
+ layer_stitch_task_.PerformTask(LayerStitchTaskCode::kCodeStitch, &ctx);
+
+ // Merge with current fence and close previous one.
+ int acquire_fence = sync_merge(__CLASS__, output_buffer.acquire_fence_fd, ctx.release_fence_fd);
+ CloseFd(&output_buffer.acquire_fence_fd);
+ CloseFd(&ctx.release_fence_fd);
+
+ output_buffer.acquire_fence_fd = acquire_fence;
+ }
+
+ return HWC2::Error::None;
+}
+
HWC2::Error HWCDisplayBuiltIn::Present(int32_t *out_retire_fence) {
auto status = HWC2::Error::None;
DTRACE_SCOPED();
if (!is_primary_ && active_secure_sessions_[kSecureDisplay]) {
- return status;
+ return status;
} else if (display_paused_) {
DisplayError error = display_intf_->Flush(&layer_stack_);
validated_ = false;
@@ -256,12 +310,26 @@
DLOGE("Flush failed. Error = %d", error);
}
} else {
+ status = CommitStitchLayers();
+ if (status != HWC2::Error::None) {
+ DLOGE("Stitch failed: %d", status);
+ return status;
+ }
+
status = CommitLayerStack();
if (status == HWC2::Error::None) {
HandleFrameOutput();
SolidFillCommit();
status = HWCDisplay::PostCommitLayerStack(out_retire_fence);
}
+
+ if (stitch_target_) {
+ // Close Stitch buffer acquire fence.
+ Layer *stitch_layer = stitch_target_->GetSDMLayer();
+ LayerBuffer &output_buffer = stitch_layer->input_buffer;
+ CloseFd(&output_buffer.acquire_fence_fd);
+ CloseFd(&output_buffer.release_fence_fd);
+ }
}
CloseFd(&output_buffer_.acquire_fence_fd);
@@ -989,4 +1057,141 @@
return false;
}
+int HWCDisplayBuiltIn::Deinit() {
+ // Destory color convert instance. This destroys thread and underlying GL resources.
+ if (gl_layer_stitch_) {
+ layer_stitch_task_.PerformTask(LayerStitchTaskCode::kCodeDestroyInstance, nullptr);
+ }
+
+ return HWCDisplay::Deinit();
+}
+
+void HWCDisplayBuiltIn::OnTask(const LayerStitchTaskCode &task_code,
+ SyncTask<LayerStitchTaskCode>::TaskContext *task_context) {
+ switch (task_code) {
+ case LayerStitchTaskCode::kCodeGetInstance: {
+ gl_layer_stitch_ = GLLayerStitch::GetInstance(false /* Non-secure */);
+ }
+ break;
+ case LayerStitchTaskCode::kCodeStitch: {
+ DTRACE_SCOPED();
+ LayerStitchStitchContext* ctx = reinterpret_cast<LayerStitchStitchContext*>(task_context);
+ gl_layer_stitch_->Blit(ctx->src_hnd, ctx->dst_hnd, ctx->src_rect, ctx->dst_rect,
+ ctx->src_acquire_fence_fd, ctx->dst_acquire_fence_fd,
+ &(ctx->release_fence_fd));
+ }
+ break;
+ case LayerStitchTaskCode::kCodeDestroyInstance: {
+ if (gl_layer_stitch_) {
+ GLLayerStitch::Destroy(gl_layer_stitch_);
+ }
+ }
+ break;
+ }
+}
+
+bool HWCDisplayBuiltIn::InitLayerStitch() {
+ if (!is_primary_) {
+ // Disable on all non-primary builtins.
+ DLOGI("Non-primary builtin.");
+ return true;
+ }
+
+ // Disable by default.
+ int value = 1;
+ Debug::Get()->GetProperty(DISABLE_LAYER_STITCH, &value);
+ disable_layer_stitch_ = (value == 1);
+
+ if (disable_layer_stitch_) {
+ DLOGI("Layer Stitch Disabled !!!");
+ return true;
+ }
+
+ // Initialize stitch context. This will be non-secure.
+ layer_stitch_task_.PerformTask(LayerStitchTaskCode::kCodeGetInstance, nullptr);
+ if (gl_layer_stitch_ == nullptr) {
+ DLOGE("Failed to get LayerStitch Instance");
+ return false;
+ }
+
+ if (!AllocateStitchBuffer()) {
+ return true;
+ }
+
+ stitch_target_ = new HWCLayer(id_, static_cast<HWCBufferAllocator *>(buffer_allocator_));
+
+ // Populate buffer params and pvt handle.
+ InitStitchTarget();
+
+ DLOGI("Created LayerStitch instance: %p", gl_layer_stitch_);
+
+ return true;
+}
+
+bool HWCDisplayBuiltIn::AllocateStitchBuffer() {
+ // Buffer dimensions: FB width * (1.5 * height)
+
+ DisplayError error = display_intf_->GetFrameBufferConfig(&fb_config_);
+ if (error != kErrorNone) {
+ DLOGE("Get frame buffer config failed. Error = %d", error);
+ return false;
+ }
+
+ BufferConfig &config = buffer_info_.buffer_config;
+ config.width = fb_config_.x_pixels;
+ config.height = fb_config_.y_pixels * kBufferHeightFactor;
+
+ // By default UBWC is enabled and below property is global enable/disable for all
+ // buffers allocated through gralloc , including framebuffer targets.
+ int ubwc_disabled = 0;
+ HWCDebugHandler::Get()->GetProperty(DISABLE_UBWC_PROP, &ubwc_disabled);
+ config.format = ubwc_disabled ? kFormatRGBA8888 : kFormatRGBA8888Ubwc;
+
+ config.gfx_client = true;
+
+ // Populate default params.
+ config.secure = false;
+ config.cache = false;
+ config.secure_camera = false;
+
+ error = buffer_allocator_->AllocateBuffer(&buffer_info_);
+
+ if (error != kErrorNone) {
+ DLOGE("Failed to allocate buffer. Error: %d", error);
+ return false;
+ }
+
+ return true;
+}
+
+void HWCDisplayBuiltIn::InitStitchTarget() {
+ LayerBuffer buffer = {};
+ buffer.planes[0].fd = buffer_info_.alloc_buffer_info.fd;
+ buffer.planes[0].offset = 0;
+ buffer.planes[0].stride = buffer_info_.alloc_buffer_info.stride;
+ buffer.size = buffer_info_.alloc_buffer_info.size;
+ buffer.handle_id = buffer_info_.alloc_buffer_info.id;
+ buffer.width = buffer_info_.alloc_buffer_info.aligned_width;
+ buffer.height = buffer_info_.alloc_buffer_info.aligned_height;
+ buffer.unaligned_width = fb_config_.x_pixels;
+ buffer.unaligned_height = fb_config_.y_pixels;
+ buffer.format = buffer_info_.alloc_buffer_info.format;
+
+ Layer *sdm_stitch_target = stitch_target_->GetSDMLayer();
+ sdm_stitch_target->composition = kCompositionStitchTarget;
+ sdm_stitch_target->input_buffer = buffer;
+ sdm_stitch_target->input_buffer.buffer_id = reinterpret_cast<uint64_t>(buffer_info_.private_data);
+}
+
+void HWCDisplayBuiltIn::AppendStitchLayer() {
+ if (disable_layer_stitch_) {
+ return;
+ }
+
+ // Append stitch target buffer to layer stack.
+ Layer *sdm_stitch_target = stitch_target_->GetSDMLayer();
+ sdm_stitch_target->composition = kCompositionStitchTarget;
+ layer_stack_.layers.push_back(sdm_stitch_target);
+}
+
} // namespace sdm