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>(
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);
145bool 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(),
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);
190std::shared_ptr<ExternalFenceVK>
191AHBSwapchainImplVK::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) {
240vk::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) {
281 [[maybe_unused]]
auto released = fd->release();
283 return std::move(signal_wait.value);
286bool 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]() {});
360void 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));
AHBSwapchainImplVK(const AHBSwapchainImplVK &)=delete
static std::shared_ptr< AHBSwapchainImplVK > Create(const std::weak_ptr< Context > &context, std::weak_ptr< android::SurfaceControl > surface_control, const ISize &size, bool enable_msaa, size_t swapchain_image_count)
Create a swapchain of a specific size whose images will be presented to the provided surface control.
std::unique_ptr< Surface > AcquireNextDrawable()
Acquire the next surface that can be used to present to the swapchain.
const android::HardwareBufferDescriptor & GetDescriptor() const
Get the descriptor used to create the hardware buffers that will be displayed on the surface control.
const ISize & GetSize() const
static ContextVK & Cast(Context &base)
std::shared_ptr< GPUTracerVK > GetGPUTracer() const
static std::unique_ptr< SurfaceVK > WrapSwapchainImage(const std::shared_ptr< SwapchainTransientsVK > &transients, const std::shared_ptr< TextureSourceVK > &swapchain_image, SwapCallback swap_callback)
Wrap the swapchain image in a Surface, which provides the additional configuration required for usage...
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
fml::UniqueFD CreatePreviousReleaseFence(const SurfaceControl &control, ASurfaceTransactionStats *stats)
static constexpr const size_t kMaxPendingPresents
static PixelFormat ToPixelFormat(AHardwareBuffer_Format format)
static TextureDescriptor ToSwapchainTextureDescriptor(const android::HardwareBufferDescriptor &ahb_desc)
auto MakeSharedVK(vk::UniqueHandle< T, VULKAN_HPP_DEFAULT_DISPATCHER_TYPE > handle)
static SkString to_string(int n)
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
A descriptor use to specify hardware buffer allocations.
static HardwareBufferDescriptor MakeForSwapchainImage(const ISize &size)
Create a descriptor of the given size that is suitable for use as a swapchain image.
HardwareBufferFormat format
#define TRACE_EVENT0(category_group, name)