Flutter Engine
The Flutter Engine
ahb_swapchain_impl_vk.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include "flutter/fml/trace_event.h"
18
19namespace impeller {
20
21//------------------------------------------------------------------------------
22/// The maximum number of presents pending in the compositor after which the
23/// acquire calls will block. This value is 2 images given to the system
24/// compositor and one for the raster thread, Because the semaphore is acquired
25/// when the CPU Begins working on the texture
26///
27static constexpr const size_t kMaxPendingPresents = 3u;
28
30 const android::HardwareBufferDescriptor& ahb_desc) {
32 desc.storage_mode = StorageMode::kDevicePrivate;
34 desc.format = ToPixelFormat(ahb_desc.format);
35 desc.size = ahb_desc.size;
36 desc.mip_count = 1u;
38 desc.sample_count = SampleCount::kCount1;
39 desc.compression_type = CompressionType::kLossless;
40 return desc;
41}
42
43std::shared_ptr<AHBSwapchainImplVK> AHBSwapchainImplVK::Create(
44 const std::weak_ptr<Context>& context,
45 std::weak_ptr<android::SurfaceControl> surface_control,
46 const ISize& size,
47 bool enable_msaa,
48 size_t swapchain_image_count) {
49 auto impl = std::shared_ptr<AHBSwapchainImplVK>(
50 new AHBSwapchainImplVK(context, std::move(surface_control), size,
51 enable_msaa, swapchain_image_count));
52 return impl->IsValid() ? impl : nullptr;
53}
54
56 const std::weak_ptr<Context>& context,
57 std::weak_ptr<android::SurfaceControl> surface_control,
58 const ISize& size,
59 bool enable_msaa,
60 size_t swapchain_image_count)
61 : surface_control_(std::move(surface_control)),
62 pending_presents_(std::make_shared<fml::Semaphore>(kMaxPendingPresents)) {
64 pool_ =
65 std::make_shared<AHBTexturePoolVK>(context, desc_, swapchain_image_count);
66 if (!pool_->IsValid()) {
67 return;
68 }
69 transients_ = std::make_shared<SwapchainTransientsVK>(
70 context, ToSwapchainTextureDescriptor(desc_), enable_msaa);
71 is_valid_ = true;
72}
73
75
77 return desc_.size;
78}
79
81 return is_valid_;
82}
83
85 const {
86 return desc_;
87}
88
89std::unique_ptr<Surface> AHBSwapchainImplVK::AcquireNextDrawable() {
90 {
91 TRACE_EVENT0("impeller", "CompositorPendingWait");
92 if (!pending_presents_->Wait()) {
93 return nullptr;
94 }
95 }
96
97 AutoSemaSignaler auto_sema_signaler =
98 std::make_shared<fml::ScopedCleanupClosure>(
99 [sema = pending_presents_]() { sema->Signal(); });
100
101 if (!is_valid_) {
102 return nullptr;
103 }
104
105 auto pool_entry = pool_->Pop();
106
107 if (!pool_entry.IsValid()) {
108 VALIDATION_LOG << "Could not create AHB texture source.";
109 return nullptr;
110 }
111
112 auto context = transients_->GetContext().lock();
113 if (context) {
114 ContextVK::Cast(*context).GetGPUTracer()->MarkFrameStart();
115 }
116
117 // Ask the GPU to wait for the render ready semaphore to be signaled before
118 // performing rendering operations.
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 "
122 "readiness.";
123 return nullptr;
124 }
125
127 transients_, pool_entry.texture,
128 [signaler = auto_sema_signaler, weak = weak_from_this(),
129 texture = pool_entry.texture]() {
130 auto thiz = weak.lock();
131 if (!thiz) {
132 VALIDATION_LOG << "Swapchain died before image could be presented.";
133 return false;
134 }
135 return thiz->Present(signaler, texture);
136 });
137
138 if (!surface) {
139 return nullptr;
140 }
141
142 return surface;
143}
144
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 "
151 "presented.";
152 return false;
153 }
154
155 auto context = transients_->GetContext().lock();
156 if (context) {
157 ContextVK::Cast(*context).GetGPUTracer()->MarkFrameEnd();
158 }
159
160 if (!texture) {
161 return false;
162 }
163
164 auto fence = SubmitSignalForPresentReady(texture);
165
166 if (!fence) {
167 VALIDATION_LOG << "Could not submit completion signal.";
168 return false;
169 }
170
171 android::SurfaceTransaction transaction;
172 if (!transaction.SetContents(control.get(), //
173 texture->GetBackingStore(), //
174 fence->CreateFD() //
175 )) {
176 VALIDATION_LOG << "Could not set swapchain image contents on the surface "
177 "control.";
178 return false;
179 }
180 return transaction.Apply([signaler, texture, weak = weak_from_this()](
181 ASurfaceTransactionStats* stats) {
182 auto thiz = weak.lock();
183 if (!thiz) {
184 return;
185 }
186 thiz->OnTextureUpdatedOnSurfaceControl(signaler, texture, stats);
187 });
188}
189
190std::shared_ptr<ExternalFenceVK>
191AHBSwapchainImplVK::SubmitSignalForPresentReady(
192 const std::shared_ptr<AHBTextureSourceVK>& texture) const {
193 auto context = transients_->GetContext().lock();
194 if (!context) {
195 return nullptr;
196 }
197 auto fence = std::make_shared<ExternalFenceVK>(context);
198 if (!fence || !fence->IsValid()) {
199 return nullptr;
200 }
201
202 auto command_buffer = context->CreateCommandBuffer();
203 if (!command_buffer) {
204 return nullptr;
205 }
206 command_buffer->SetLabel("AHBSubmitSignalForPresentReadyCB");
207 const auto& encoder = CommandBufferVK::Cast(*command_buffer).GetEncoder();
208
209 const auto command_encoder_vk = encoder->GetCommandBuffer();
210
211 BarrierVK barrier;
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 = {};
218
219 if (!texture->SetLayout(barrier).ok()) {
220 return nullptr;
221 }
222
223 encoder->Track(fence->GetSharedHandle());
224
225 if (!encoder->EndCommandBuffer()) {
226 return nullptr;
227 }
228
229 vk::SubmitInfo submit_info;
230 submit_info.setCommandBuffers(command_encoder_vk);
231
232 auto result = ContextVK::Cast(*context).GetGraphicsQueue()->Submit(
233 submit_info, fence->GetHandle());
234 if (result != vk::Result::eSuccess) {
235 return nullptr;
236 }
237 return fence;
238}
239
240vk::UniqueSemaphore AHBSwapchainImplVK::CreateRenderReadySemaphore(
241 const std::shared_ptr<fml::UniqueFD>& fd) const {
242 if (!fd->is_valid()) {
243 return {};
244 }
245
246 auto context = transients_->GetContext().lock();
247 if (!context) {
248 return {};
249 }
250
251 const auto& context_vk = ContextVK::Cast(*context);
252 const auto& device = context_vk.GetDevice();
253
254 auto signal_wait = device.createSemaphoreUnique({});
255
256 if (signal_wait.result != vk::Result::eSuccess) {
257 return {};
258 }
259
260 context_vk.SetDebugName(*signal_wait.value, "AHBRenderReadySemaphore");
261
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;
266 // From the spec: Sync FDs can only be imported temporarily.
267 import_info.flags = vk::SemaphoreImportFlagBitsKHR::eTemporary;
268
269 const auto import_result = device.importSemaphoreFdKHR(import_info);
270
271 if (import_result != vk::Result::eSuccess) {
272 VALIDATION_LOG << "Could not import semaphore FD: "
273 << vk::to_string(import_result);
274 return {};
275 }
276
277 // From the spec: Importing a semaphore payload from a file descriptor
278 // transfers ownership of the file descriptor from the application to the
279 // Vulkan implementation. The application must not perform any operations on
280 // the file descriptor after a successful import.
281 [[maybe_unused]] auto released = fd->release();
282
283 return std::move(signal_wait.value);
284}
285
286bool AHBSwapchainImplVK::SubmitWaitForRenderReady(
287 const std::shared_ptr<fml::UniqueFD>& render_ready_fence,
288 const std::shared_ptr<AHBTextureSourceVK>& texture) const {
289 // If there is no render ready fence, we are already ready to render into
290 // the texture. There is nothing more to do.
291 if (!render_ready_fence || !render_ready_fence->is_valid()) {
292 return true;
293 }
294
295 auto context = transients_->GetContext().lock();
296 if (!context) {
297 return false;
298 }
299
300 auto completion_fence =
301 ContextVK::Cast(*context).GetDevice().createFenceUnique({}).value;
302 if (!completion_fence) {
303 return false;
304 }
305
306 auto command_buffer = context->CreateCommandBuffer();
307 if (!command_buffer) {
308 return false;
309 }
310 command_buffer->SetLabel("AHBSubmitWaitForRenderReadyCB");
311 const auto& encoder = CommandBufferVK::Cast(*command_buffer).GetEncoder();
312
313 const auto command_buffer_vk = encoder->GetCommandBuffer();
314
315 BarrierVK barrier;
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 = {};
322
323 if (!texture->SetLayout(barrier).ok()) {
324 return false;
325 }
326
327 auto render_ready_semaphore =
328 MakeSharedVK(CreateRenderReadySemaphore(render_ready_fence));
329 encoder->Track(render_ready_semaphore);
330
331 if (!encoder->EndCommandBuffer()) {
332 return false;
333 }
334
335 vk::SubmitInfo submit_info;
336
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);
344 }
345
346 submit_info.setCommandBuffers(command_buffer_vk);
347
348 auto result = ContextVK::Cast(*context).GetGraphicsQueue()->Submit(
349 submit_info, *completion_fence);
350 if (result != vk::Result::eSuccess) {
351 return false;
352 }
353
354 ContextVK::Cast(*context).GetFenceWaiter()->AddFence(
355 std::move(completion_fence), [encoder]() {});
356
357 return true;
358}
359
360void AHBSwapchainImplVK::OnTextureUpdatedOnSurfaceControl(
361 const AutoSemaSignaler& signaler,
362 std::shared_ptr<AHBTextureSourceVK> texture,
363 ASurfaceTransactionStats* stats) {
364 auto control = surface_control_.lock();
365 if (!control) {
366 return;
367 }
368
369 // Ask for an FD that gets signaled when the previous buffer is released. This
370 // can be invalid if there is no wait necessary.
371 auto render_ready_fence =
373
374 // The transaction completion indicates that the surface control now
375 // references the hardware buffer. We can recycle the previous set buffer
376 // safely.
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));
381}
382
383} // namespace impeller
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.
static ContextVK & Cast(Context &base)
Definition: backend_cast.h:13
std::shared_ptr< GPUTracerVK > GetGPUTracer() const
Definition: context_vk.cc:568
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...
Definition: surface_vk.cc:13
VkDevice device
Definition: main.cc:53
VkSurfaceKHR surface
Definition: main.cc:49
uint8_t value
GAsyncResult * result
FlTexture * texture
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
Definition: switches.h:259
Definition: ascii_trie.cc:9
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)
dictionary stats
Definition: malisc.py:20
Definition: ref_ptr.h:256
static SkString to_string(int n)
Definition: nanobench.cpp:119
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.
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131
#define VALIDATION_LOG
Definition: validation.h:73