7 #include "flutter/fml/trace_event.h"
17 #include "vulkan/vulkan_to_string.hpp"
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>(
72 auto control = surface_control_.lock();
73 is_valid_ = control && control->IsValid();
93 TRACE_EVENT0(
"impeller",
"CompositorPendingWait");
94 if (!pending_presents_->Wait()) {
99 AutoSemaSignaler auto_sema_signaler =
100 std::make_shared<fml::ScopedCleanupClosure>(
101 [sema = pending_presents_]() { sema->Signal(); });
107 auto pool_entry = pool_->Pop();
109 if (!pool_entry.IsValid()) {
116 if (!SubmitWaitForRenderReady(pool_entry.render_ready_fence,
117 pool_entry.texture)) {
123 auto context = transients_->GetContext().lock();
127 #endif // IMPELLER_DEBUG
130 transients_, pool_entry.texture,
131 [signaler = auto_sema_signaler, weak = weak_from_this(),
132 texture = pool_entry.texture]() {
133 auto thiz = weak.lock();
135 VALIDATION_LOG <<
"Swapchain died before image could be presented.";
138 return thiz->Present(signaler, texture);
148 bool AHBSwapchainImplVK::Present(
149 const AutoSemaSignaler& signaler,
150 const std::shared_ptr<AHBTextureSourceVK>& texture) {
151 auto control = surface_control_.lock();
152 if (!control || !control->IsValid()) {
153 VALIDATION_LOG <<
"Surface control died before swapchain image could be "
159 auto context = transients_->GetContext().lock();
161 ContextVK::Cast(*context).GetGPUTracer()->MarkFrameEnd();
163 #endif // IMPELLER_DEBUG
169 auto fence = SubmitSignalForPresentReady(texture);
176 android::SurfaceTransaction transaction;
177 if (!transaction.SetContents(control.get(),
178 texture->GetBackingStore(),
181 VALIDATION_LOG <<
"Could not set swapchain image contents on the surface "
185 return transaction.Apply([signaler, texture, weak = weak_from_this()](
186 ASurfaceTransactionStats* stats) {
187 auto thiz = weak.lock();
191 thiz->OnTextureUpdatedOnSurfaceControl(signaler, texture, stats);
195 std::shared_ptr<ExternalFenceVK>
196 AHBSwapchainImplVK::SubmitSignalForPresentReady(
197 const std::shared_ptr<AHBTextureSourceVK>& texture)
const {
198 auto context = transients_->GetContext().lock();
202 auto fence = std::make_shared<ExternalFenceVK>(context);
203 if (!fence || !fence->IsValid()) {
207 auto command_buffer = context->CreateCommandBuffer();
208 if (!command_buffer) {
211 command_buffer->SetLabel(
"AHBSubmitSignalForPresentReadyCB");
212 CommandBufferVK& command_buffer_vk = CommandBufferVK::Cast(*command_buffer);
214 const auto command_encoder_vk = command_buffer_vk.GetCommandBuffer();
217 barrier.cmd_buffer = command_encoder_vk;
218 barrier.new_layout = vk::ImageLayout::eGeneral;
219 barrier.src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput;
220 barrier.src_access = vk::AccessFlagBits::eColorAttachmentWrite;
221 barrier.dst_stage = vk::PipelineStageFlagBits::eBottomOfPipe;
222 barrier.dst_access = {};
224 if (!texture->SetLayout(barrier).ok()) {
228 command_buffer_vk.Track(fence->GetSharedHandle());
230 if (!command_buffer_vk.EndCommandBuffer()) {
234 vk::SubmitInfo submit_info;
235 submit_info.setCommandBuffers(command_encoder_vk);
237 auto result = ContextVK::Cast(*context).GetGraphicsQueue()->Submit(
238 submit_info, fence->GetHandle());
239 if (result != vk::Result::eSuccess) {
245 vk::UniqueFence AHBSwapchainImplVK::CreateRenderReadyFence(
246 const std::shared_ptr<fml::UniqueFD>& fd)
const {
247 if (!fd->is_valid()) {
251 auto context = transients_->GetContext().lock();
256 const auto& context_vk = ContextVK::Cast(*context);
257 const auto& device = context_vk.GetDevice();
259 auto signal_wait = device.createFenceUnique({});
261 if (signal_wait.result != vk::Result::eSuccess) {
265 context_vk.SetDebugName(*signal_wait.value,
"AHBRenderReadyFence");
267 vk::ImportFenceFdInfoKHR import_info;
268 import_info.fence = *signal_wait.value;
269 import_info.fd = fd->get();
270 import_info.handleType = vk::ExternalFenceHandleTypeFlagBits::eSyncFd;
272 import_info.flags = vk::FenceImportFlagBitsKHR::eTemporary;
274 const auto import_result = device.importFenceFdKHR(import_info);
276 if (import_result != vk::Result::eSuccess) {
278 << vk::to_string(import_result);
286 [[maybe_unused]]
auto released = fd->release();
288 return std::move(signal_wait.value);
291 bool AHBSwapchainImplVK::SubmitWaitForRenderReady(
292 const std::shared_ptr<fml::UniqueFD>& render_ready_fence,
293 const std::shared_ptr<AHBTextureSourceVK>& texture)
const {
296 if (!render_ready_fence || !render_ready_fence->is_valid()) {
300 auto context = transients_->GetContext().lock();
305 auto fence = CreateRenderReadyFence(render_ready_fence);
307 auto result = ContextVK::Cast(*context).GetDevice().waitForFences(
310 std::numeric_limits<uint64_t>::max()
313 if (!(result == vk::Result::eSuccess || result == vk::Result::eTimeout)) {
314 VALIDATION_LOG <<
"Encountered error while waiting on swapchain image: "
315 << vk::to_string(result);
322 void AHBSwapchainImplVK::OnTextureUpdatedOnSurfaceControl(
323 const AutoSemaSignaler& signaler,
324 std::shared_ptr<AHBTextureSourceVK> texture,
325 ASurfaceTransactionStats* stats) {
326 auto control = surface_control_.lock();
333 auto render_ready_fence =
339 Lock lock(currently_displayed_texture_mutex_);
340 auto old_texture = currently_displayed_texture_;
341 currently_displayed_texture_ = std::move(texture);
342 pool_->Push(std::move(old_texture), std::move(render_ready_fence));