7 #include "flutter/fml/trace_event.h"
44 const std::weak_ptr<Context>& context,
45 std::weak_ptr<android::SurfaceControl> surface_control,
48 size_t swapchain_image_count) {
49 auto impl = std::shared_ptr<AHBSwapchainImplVK>(
51 enable_msaa, swapchain_image_count));
52 return impl->IsValid() ? impl :
nullptr;
56 const std::weak_ptr<Context>& context,
57 std::weak_ptr<android::SurfaceControl> surface_control,
60 size_t swapchain_image_count)
61 : surface_control_(
std::move(surface_control)),
65 std::make_shared<AHBTexturePoolVK>(context, desc_, swapchain_image_count);
66 if (!pool_->IsValid()) {
69 transients_ = std::make_shared<SwapchainTransientsVK>(
91 TRACE_EVENT0(
"impeller",
"CompositorPendingWait");
92 if (!pending_presents_->Wait()) {
97 AutoSemaSignaler auto_sema_signaler =
98 std::make_shared<fml::ScopedCleanupClosure>(
99 [sema = pending_presents_]() { sema->Signal(); });
105 auto pool_entry = pool_->Pop();
107 if (!pool_entry.IsValid()) {
112 auto context = transients_->GetContext().lock();
119 if (!SubmitWaitForRenderReady(pool_entry.render_ready_fence,
120 pool_entry.texture)) {
121 VALIDATION_LOG <<
"Could not submit a command to the GPU to wait on render "
127 transients_, pool_entry.texture,
128 [signaler = auto_sema_signaler, weak = weak_from_this(),
129 texture = pool_entry.texture]() {
130 auto thiz = weak.lock();
132 VALIDATION_LOG <<
"Swapchain died before image could be presented.";
135 return thiz->Present(signaler, texture);
145 bool AHBSwapchainImplVK::Present(
146 const AutoSemaSignaler& signaler,
147 const std::shared_ptr<AHBTextureSourceVK>& texture) {
148 auto control = surface_control_.lock();
149 if (!control || !control->IsValid()) {
150 VALIDATION_LOG <<
"Surface control died before swapchain image could be "
155 auto context = transients_->GetContext().lock();
157 ContextVK::Cast(*context).GetGPUTracer()->MarkFrameEnd();
164 auto fence = SubmitSignalForPresentReady(texture);
171 android::SurfaceTransaction transaction;
172 if (!transaction.SetContents(control.get(),
173 texture->GetBackingStore(),
176 VALIDATION_LOG <<
"Could not set swapchain image contents on the surface "
180 return transaction.Apply([signaler, texture, weak = weak_from_this()](
181 ASurfaceTransactionStats* stats) {
182 auto thiz = weak.lock();
186 thiz->OnTextureUpdatedOnSurfaceControl(signaler, texture, stats);
190 std::shared_ptr<ExternalFenceVK>
191 AHBSwapchainImplVK::SubmitSignalForPresentReady(
192 const std::shared_ptr<AHBTextureSourceVK>& texture)
const {
193 auto context = transients_->GetContext().lock();
197 auto fence = std::make_shared<ExternalFenceVK>(context);
198 if (!fence || !fence->IsValid()) {
202 auto command_buffer = context->CreateCommandBuffer();
203 if (!command_buffer) {
206 command_buffer->SetLabel(
"AHBSubmitSignalForPresentReadyCB");
207 const auto& encoder = CommandBufferVK::Cast(*command_buffer).GetEncoder();
209 const auto command_encoder_vk = encoder->GetCommandBuffer();
212 barrier.cmd_buffer = command_encoder_vk;
213 barrier.new_layout = vk::ImageLayout::eGeneral;
214 barrier.src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput;
215 barrier.src_access = vk::AccessFlagBits::eColorAttachmentWrite;
216 barrier.dst_stage = vk::PipelineStageFlagBits::eBottomOfPipe;
217 barrier.dst_access = {};
219 if (!texture->SetLayout(barrier).ok()) {
223 encoder->Track(fence->GetSharedHandle());
225 if (!encoder->EndCommandBuffer()) {
229 vk::SubmitInfo submit_info;
230 submit_info.setCommandBuffers(command_encoder_vk);
232 auto result = ContextVK::Cast(*context).GetGraphicsQueue()->Submit(
233 submit_info, fence->GetHandle());
234 if (result != vk::Result::eSuccess) {
240 vk::UniqueSemaphore AHBSwapchainImplVK::CreateRenderReadySemaphore(
241 const std::shared_ptr<fml::UniqueFD>& fd)
const {
242 if (!fd->is_valid()) {
246 auto context = transients_->GetContext().lock();
251 const auto& context_vk = ContextVK::Cast(*context);
252 const auto& device = context_vk.GetDevice();
254 auto signal_wait = device.createSemaphoreUnique({});
256 if (signal_wait.result != vk::Result::eSuccess) {
260 context_vk.SetDebugName(*signal_wait.value,
"AHBRenderReadySemaphore");
262 vk::ImportSemaphoreFdInfoKHR import_info;
263 import_info.semaphore = *signal_wait.value;
264 import_info.fd = fd->get();
265 import_info.handleType = vk::ExternalSemaphoreHandleTypeFlagBits::eSyncFd;
267 import_info.flags = vk::SemaphoreImportFlagBitsKHR::eTemporary;
269 const auto import_result = device.importSemaphoreFdKHR(import_info);
271 if (import_result != vk::Result::eSuccess) {
273 << vk::to_string(import_result);
281 [[maybe_unused]]
auto released = fd->release();
283 return std::move(signal_wait.value);
286 bool AHBSwapchainImplVK::SubmitWaitForRenderReady(
287 const std::shared_ptr<fml::UniqueFD>& render_ready_fence,
288 const std::shared_ptr<AHBTextureSourceVK>& texture)
const {
291 if (!render_ready_fence || !render_ready_fence->is_valid()) {
295 auto context = transients_->GetContext().lock();
300 auto completion_fence =
301 ContextVK::Cast(*context).GetDevice().createFenceUnique({}).value;
302 if (!completion_fence) {
306 auto command_buffer = context->CreateCommandBuffer();
307 if (!command_buffer) {
310 command_buffer->SetLabel(
"AHBSubmitWaitForRenderReadyCB");
311 const auto& encoder = CommandBufferVK::Cast(*command_buffer).GetEncoder();
313 const auto command_buffer_vk = encoder->GetCommandBuffer();
316 barrier.cmd_buffer = command_buffer_vk;
317 barrier.new_layout = vk::ImageLayout::eColorAttachmentOptimal;
318 barrier.src_stage = vk::PipelineStageFlagBits::eBottomOfPipe;
319 barrier.src_access = {};
320 barrier.dst_stage = vk::PipelineStageFlagBits::eTopOfPipe;
321 barrier.dst_access = {};
323 if (!texture->SetLayout(barrier).ok()) {
327 auto render_ready_semaphore =
328 MakeSharedVK(CreateRenderReadySemaphore(render_ready_fence));
329 encoder->Track(render_ready_semaphore);
331 if (!encoder->EndCommandBuffer()) {
335 vk::SubmitInfo submit_info;
337 if (render_ready_semaphore) {
338 static constexpr
const auto kWaitStages =
339 vk::PipelineStageFlagBits::eColorAttachmentOutput |
340 vk::PipelineStageFlagBits::eFragmentShader |
341 vk::PipelineStageFlagBits::eTransfer;
342 submit_info.setWaitSemaphores(render_ready_semaphore->Get());
343 submit_info.setWaitDstStageMask(kWaitStages);
346 submit_info.setCommandBuffers(command_buffer_vk);
348 auto result = ContextVK::Cast(*context).GetGraphicsQueue()->Submit(
349 submit_info, *completion_fence);
350 if (result != vk::Result::eSuccess) {
354 ContextVK::Cast(*context).GetFenceWaiter()->AddFence(
355 std::move(completion_fence), [encoder]() {});
360 void AHBSwapchainImplVK::OnTextureUpdatedOnSurfaceControl(
361 const AutoSemaSignaler& signaler,
362 std::shared_ptr<AHBTextureSourceVK> texture,
363 ASurfaceTransactionStats* stats) {
364 auto control = surface_control_.lock();
371 auto render_ready_fence =
377 Lock lock(currently_displayed_texture_mutex_);
378 auto old_texture = currently_displayed_texture_;
379 currently_displayed_texture_ = std::move(texture);
380 pool_->Push(std::move(old_texture), std::move(render_ready_fence));