Flutter Impeller
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 
19 namespace 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 ///
27 static constexpr const size_t kMaxPendingPresents = 3u;
28 
30  const android::HardwareBufferDescriptor& ahb_desc) {
31  TextureDescriptor desc;
34  desc.format = ToPixelFormat(ahb_desc.format);
35  desc.size = ahb_desc.size;
36  desc.mip_count = 1u;
40  return desc;
41 }
42 
43 std::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 
89 std::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 
126  auto surface = SurfaceVK::WrapSwapchainImage(
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 
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 "
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 
190 std::shared_ptr<ExternalFenceVK>
191 AHBSwapchainImplVK::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 
240 vk::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 
286 bool 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 
360 void 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 =
372  android::CreatePreviousReleaseFence(*control, stats);
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
impeller::AHBSwapchainImplVK::GetDescriptor
const android::HardwareBufferDescriptor & GetDescriptor() const
Get the descriptor used to create the hardware buffers that will be displayed on the surface control.
Definition: ahb_swapchain_impl_vk.cc:84
fence_waiter_vk.h
impeller::SurfaceVK::WrapSwapchainImage
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
impeller::AHBSwapchainImplVK::AcquireNextDrawable
std::unique_ptr< Surface > AcquireNextDrawable()
Acquire the next surface that can be used to present to the swapchain.
Definition: ahb_swapchain_impl_vk.cc:89
gpu_tracer_vk.h
barrier_vk.h
ahb_formats.h
surface_vk.h
command_encoder_vk.h
impeller::TextureDescriptor::format
PixelFormat format
Definition: texture_descriptor.h:41
surface_transaction_stats.h
impeller::TextureDescriptor::mip_count
size_t mip_count
Definition: texture_descriptor.h:43
impeller::android::CreatePreviousReleaseFence
fml::UniqueFD CreatePreviousReleaseFence(const SurfaceControl &control, ASurfaceTransactionStats *stats)
Definition: surface_transaction_stats.cc:11
impeller::TextureUsage::kRenderTarget
@ kRenderTarget
impeller::AHBSwapchainImplVK::Create
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.
Definition: ahb_swapchain_impl_vk.cc:43
impeller::TextureDescriptor::sample_count
SampleCount sample_count
Definition: texture_descriptor.h:45
validation.h
impeller::TextureDescriptor::usage
TextureUsageMask usage
Definition: texture_descriptor.h:44
impeller::ToSwapchainTextureDescriptor
static TextureDescriptor ToSwapchainTextureDescriptor(const android::HardwareBufferDescriptor &ahb_desc)
Definition: ahb_swapchain_impl_vk.cc:29
impeller::kMaxPendingPresents
static constexpr const size_t kMaxPendingPresents
Definition: ahb_swapchain_impl_vk.cc:27
impeller::android::HardwareBufferDescriptor::MakeForSwapchainImage
static HardwareBufferDescriptor MakeForSwapchainImage(const ISize &size)
Create a descriptor of the given size that is suitable for use as a swapchain image.
Definition: hardware_buffer.cc:87
impeller::TextureDescriptor::type
TextureType type
Definition: texture_descriptor.h:40
impeller::AHBSwapchainImplVK::AHBSwapchainImplVK
AHBSwapchainImplVK(const AHBSwapchainImplVK &)=delete
command_buffer_vk.h
impeller::TSize
Definition: size.h:19
ahb_swapchain_impl_vk.h
impeller::StorageMode::kDevicePrivate
@ kDevicePrivate
impeller::CompressionType::kLossless
@ kLossless
impeller::android::HardwareBufferDescriptor
A descriptor use to specify hardware buffer allocations.
Definition: hardware_buffer.h:47
impeller::TextureType::kTexture2D
@ kTexture2D
impeller::ContextVK::GetGPUTracer
std::shared_ptr< GPUTracerVK > GetGPUTracer() const
Definition: context_vk.cc:568
impeller::android::HardwareBufferDescriptor::size
ISize size
Definition: hardware_buffer.h:49
impeller::TextureDescriptor::size
ISize size
Definition: texture_descriptor.h:42
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:73
surface_transaction.h
impeller::MakeSharedVK
auto MakeSharedVK(vk::UniqueHandle< T, VULKAN_HPP_DEFAULT_DISPATCHER_TYPE > handle)
Definition: shared_object_vk.h:44
std
Definition: comparable.h:95
impeller::BackendCast< ContextVK, Context >::Cast
static ContextVK & Cast(Context &base)
Definition: backend_cast.h:13
impeller::SampleCount::kCount1
@ kCount1
impeller::TextureDescriptor::storage_mode
StorageMode storage_mode
Definition: texture_descriptor.h:39
impeller::android::HardwareBufferDescriptor::format
HardwareBufferFormat format
Definition: hardware_buffer.h:48
impeller::AHBSwapchainImplVK::~AHBSwapchainImplVK
~AHBSwapchainImplVK()
impeller::TextureDescriptor
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
Definition: texture_descriptor.h:38
impeller::AHBSwapchainImplVK::GetSize
const ISize & GetSize() const
Definition: ahb_swapchain_impl_vk.cc:76
impeller::AHBSwapchainImplVK::IsValid
bool IsValid() const
Definition: ahb_swapchain_impl_vk.cc:80
impeller::TextureDescriptor::compression_type
CompressionType compression_type
Definition: texture_descriptor.h:46
impeller
Definition: aiks_blend_unittests.cc:18
impeller::ToPixelFormat
static PixelFormat ToPixelFormat(AHardwareBuffer_Format format)
Definition: ahb_texture_source_vk.cc:221