Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
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
14
15namespace impeller {
16
30
32 auto acquire_res = device.createFenceUnique({});
33 if (acquire_res.result != vk::Result::eSuccess) {
34 VALIDATION_LOG << "Could not create synchronizer.";
35 return;
36 }
37 acquire = std::move(acquire_res.value);
38 is_valid = true;
39}
40
42
44 return is_valid;
45}
46
49 return true;
50 }
51 if (auto result = device.waitForFences(
52 *acquire, // fence
53 true, // wait all
54 std::numeric_limits<uint64_t>::max() // timeout (ns)
55 );
56 result != vk::Result::eSuccess) {
57 VALIDATION_LOG << "Fence wait failed: " << vk::to_string(result);
58 return false;
59 }
61 if (auto result = device.resetFences(*acquire);
62 result != vk::Result::eSuccess) {
63 VALIDATION_LOG << "Could not reset fence: " << vk::to_string(result);
64 return false;
65 }
66 return true;
67}
68
69std::shared_ptr<AHBSwapchainImplVK> AHBSwapchainImplVK::Create(
70 const std::weak_ptr<Context>& context,
71 std::weak_ptr<android::SurfaceControl> surface_control,
72 const CreateTransactionCB& cb,
73 const ISize& size,
74 bool enable_msaa) {
75 auto impl = std::shared_ptr<AHBSwapchainImplVK>(new AHBSwapchainImplVK(
76 context, std::move(surface_control), cb, size, enable_msaa));
77 return impl->IsValid() ? impl : nullptr;
78}
79
81 const std::weak_ptr<Context>& context,
82 std::weak_ptr<android::SurfaceControl> surface_control,
83 const CreateTransactionCB& cb,
84 const ISize& size,
85 bool enable_msaa)
86 : surface_control_(std::move(surface_control)), cb_(cb) {
88 pool_ = std::make_shared<AHBTexturePoolVK>(context, desc_);
89 if (!pool_->IsValid()) {
90 return;
91 }
92 transients_ = std::make_shared<SwapchainTransientsVK>(
93 context, ToSwapchainTextureDescriptor(desc_), enable_msaa);
94
95 for (auto i = 0u; i < kMaxPendingPresents; i++) {
96 auto sync = std::make_unique<AHBFrameSynchronizerVK>(
97 ContextVK::Cast(*context.lock()).GetDeviceHolder()->GetDevice());
98 if (!sync->IsValid()) {
99 return;
100 }
101 frame_data_.push_back(std::move(sync));
102 }
103
104 auto control = surface_control_.lock();
105 is_valid_ = control && control->IsValid();
106}
107
109 // Ensure that the Vulkan device is idle before destroying objects that the
110 // device may have been using.
111 WaitIdle();
112}
113
115 return desc_.size;
116}
117
119 return is_valid_;
120}
121
126
127void AHBSwapchainImplVK::WaitIdle() const {
128 if (transients_) {
129 if (auto context = transients_->GetContext().lock()) {
130 auto result = ContextVK::Cast(*context).GetDevice().waitIdle();
131 if (result != vk::Result::eSuccess) {
132 FML_LOG(INFO) << "Device waitIdle failed: " << vk::to_string(result);
133 }
134 }
135 }
136}
137
138std::unique_ptr<Surface> AHBSwapchainImplVK::AcquireNextDrawable() {
139 auto context = transients_->GetContext().lock();
140 if (!context) {
141 return nullptr;
142 }
143
144 frame_index_ = (frame_index_ + 1) % kMaxPendingPresents;
145
146 if (!frame_data_[frame_index_]->WaitForFence(
147 ContextVK::Cast(*context).GetDevice())) {
148 return nullptr;
149 }
150
151 if (!is_valid_) {
152 return nullptr;
153 }
154
155 auto pool_entry = pool_->Pop();
156
157 if (!pool_entry.IsValid()) {
158 VALIDATION_LOG << "Could not create AHB texture source.";
159 return nullptr;
160 }
161
162 // Import the render ready semaphore that will block onscreen rendering until
163 // it is ready.
164 if (!ImportRenderReady(pool_entry.render_ready_fence, pool_entry.texture)) {
165 VALIDATION_LOG << "Could wait on render ready fence.";
166 return nullptr;
167 }
168
169#if IMPELLER_DEBUG
170 if (context) {
171 ContextVK::Cast(*context).GetGPUTracer()->MarkFrameStart();
172 }
173#endif // IMPELLER_DEBUG
174
176 transients_, pool_entry.texture,
177 [weak = weak_from_this(), texture = pool_entry.texture]() {
178 auto thiz = weak.lock();
179 if (!thiz) {
180 VALIDATION_LOG << "Swapchain died before image could be presented.";
181 return false;
182 }
183 return thiz->Present(texture);
184 });
185
186 if (!surface) {
187 return nullptr;
188 }
189
190 return surface;
191}
192
193bool AHBSwapchainImplVK::Present(
194 const std::shared_ptr<AHBTextureSourceVK>& texture) {
195 auto control = surface_control_.lock();
196 if (!control || !control->IsValid()) {
197 VALIDATION_LOG << "Surface control died before swapchain image could be "
198 "presented.";
199 return false;
200 }
201
202#if IMPELLER_DEBUG
203 auto context = transients_->GetContext().lock();
204 if (context) {
205 ContextVK::Cast(*context).GetGPUTracer()->MarkFrameEnd();
206 }
207#endif // IMPELLER_DEBUG
208
209 if (!texture) {
210 return false;
211 }
212
213 auto present_ready = SubmitSignalForPresentReady(texture);
214
215 if (!present_ready) {
216 VALIDATION_LOG << "Could not submit completion signal.";
217 return false;
218 }
219
220 android::SurfaceTransaction transaction =
222 if (!transaction.SetContents(control.get(), //
223 texture->GetBackingStore(), //
224 present_ready->CreateFD() //
225 )) {
226 VALIDATION_LOG << "Could not set swapchain image contents on the surface "
227 "control.";
228 return false;
229 }
230 return transaction.Apply(
231 [texture, weak = weak_from_this()](ASurfaceTransactionStats* stats) {
232 auto thiz = weak.lock();
233 if (!thiz) {
234 return;
235 }
236 thiz->OnTextureUpdatedOnSurfaceControl(texture, stats);
237 });
238}
239
240void AHBSwapchainImplVK::AddFinalCommandBuffer(
241 std::shared_ptr<CommandBuffer> cmd_buffer) {
242 frame_data_[frame_index_]->final_cmd_buffer = std::move(cmd_buffer);
243}
244
245std::shared_ptr<ExternalSemaphoreVK>
246AHBSwapchainImplVK::SubmitSignalForPresentReady(
247 const std::shared_ptr<AHBTextureSourceVK>& texture) const {
248 auto context = transients_->GetContext().lock();
249 if (!context) {
250 return nullptr;
251 }
252
253 auto present_ready = std::make_shared<ExternalSemaphoreVK>(context);
254 if (!present_ready || !present_ready->IsValid()) {
255 return nullptr;
256 }
257
258 auto& sync = frame_data_[frame_index_];
259 auto command_buffer = sync->final_cmd_buffer;
260 if (!command_buffer) {
261 return nullptr;
262 }
263 CommandBufferVK& command_buffer_vk = CommandBufferVK::Cast(*command_buffer);
264 const auto command_encoder_vk = command_buffer_vk.GetCommandBuffer();
265 if (!command_buffer_vk.EndCommandBuffer()) {
266 return nullptr;
267 }
268 sync->present_ready = present_ready;
269
270 vk::SubmitInfo submit_info;
271 vk::PipelineStageFlags wait_stage =
272 vk::PipelineStageFlagBits::eColorAttachmentOutput;
273 if (sync->render_ready) {
274 submit_info.setPWaitSemaphores(&sync->render_ready.get());
275 submit_info.setWaitSemaphoreCount(1);
276 submit_info.setWaitDstStageMask(wait_stage);
277 }
278 submit_info.setCommandBuffers(command_encoder_vk);
279 submit_info.setPSignalSemaphores(&sync->present_ready->GetHandle());
280 submit_info.setSignalSemaphoreCount(1);
281
282 auto result = ContextVK::Cast(*context).GetGraphicsQueue()->Submit(
283 submit_info, *sync->acquire);
284 if (result != vk::Result::eSuccess) {
285 return nullptr;
286 }
287 sync->acquire_fence_pending = true;
288 return present_ready;
289}
290
291vk::UniqueSemaphore AHBSwapchainImplVK::CreateRenderReadySemaphore(
292 const std::shared_ptr<fml::UniqueFD>& fd) const {
293 if (!fd->is_valid()) {
294 return {};
295 }
296
297 auto context = transients_->GetContext().lock();
298 if (!context) {
299 return {};
300 }
301
302 const auto& context_vk = ContextVK::Cast(*context);
303 const auto& device = context_vk.GetDevice();
304
305 auto signal_wait = device.createSemaphoreUnique({});
306 if (signal_wait.result != vk::Result::eSuccess) {
307 return {};
308 }
309
310 context_vk.SetDebugName(*signal_wait.value, "AHBRenderReadySemaphore");
311
312 vk::ImportSemaphoreFdInfoKHR import_info;
313 import_info.semaphore = *signal_wait.value;
314 import_info.fd = fd->get();
315 import_info.handleType = vk::ExternalSemaphoreHandleTypeFlagBits::eSyncFd;
316 // From the spec: Sync FDs can only be imported temporarily.
317 import_info.flags = vk::SemaphoreImportFlagBitsKHR::eTemporary;
318
319 const auto import_result = device.importSemaphoreFdKHR(import_info);
320
321 if (import_result != vk::Result::eSuccess) {
322 VALIDATION_LOG << "Could not import semaphore FD: "
323 << vk::to_string(import_result);
324 return {};
325 }
326
327 // From the spec: Importing a semaphore payload from a file descriptor
328 // transfers ownership of the file descriptor from the application to the
329 // Vulkan implementation. The application must not perform any operations on
330 // the file descriptor after a successful import.
331 [[maybe_unused]] auto released = fd->release();
332
333 return std::move(signal_wait.value);
334}
335
336bool AHBSwapchainImplVK::ImportRenderReady(
337 const std::shared_ptr<fml::UniqueFD>& render_ready_fence,
338 const std::shared_ptr<AHBTextureSourceVK>& texture) {
339 auto context = transients_->GetContext().lock();
340 if (!context) {
341 return false;
342 }
343
344 // If there is no render ready fence, we are already ready to render into
345 // the texture. There is nothing more to do.
346 if (!render_ready_fence || !render_ready_fence->is_valid()) {
347 frame_data_[frame_index_]->render_ready = {};
348 return true;
349 }
350
351 auto semaphore = CreateRenderReadySemaphore(render_ready_fence);
352 if (!semaphore) {
353 return false;
354 }
355 // This semaphore will be later used to block the onscreen render pass
356 // from starting until the system is done reading the onscreen.
357 frame_data_[frame_index_]->render_ready = std::move(semaphore);
358 return true;
359}
360
361void AHBSwapchainImplVK::OnTextureUpdatedOnSurfaceControl(
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
The implementation of a swapchain at a specific size. Resizes to the surface will cause the instance ...
static std::shared_ptr< AHBSwapchainImplVK > Create(const std::weak_ptr< Context > &context, std::weak_ptr< android::SurfaceControl > surface_control, const CreateTransactionCB &cb, const ISize &size, bool enable_msaa)
Create a swapchain of a specific size whose images will be presented to the provided surface control.
AHBSwapchainImplVK(const AHBSwapchainImplVK &)=delete
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)
std::shared_ptr< DeviceHolderVK > GetDeviceHolder() const
Definition context_vk.h:191
const vk::Device & GetDevice() const
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...
Definition surface_vk.cc:13
A wrapper for ASurfaceTransaction. https://developer.android.com/ndk/reference/group/native-activity#...
VkDevice device
Definition main.cc:69
VkSurfaceKHR surface
Definition main.cc:65
#define FML_LOG(severity)
Definition logging.h:101
FlTexture * texture
std::function< android::SurfaceTransaction()> CreateTransactionCB
constexpr PixelFormat ToPixelFormat(vk::Format format)
Definition formats_vk.h:219
static constexpr const size_t kMaxPendingPresents
static TextureDescriptor ToSwapchainTextureDescriptor(const android::HardwareBufferDescriptor &ahb_desc)
Definition ref_ptr.h:261
std::shared_ptr< ContextGLES > context
std::shared_ptr< CommandBuffer > command_buffer
AHBFrameSynchronizerVK(const vk::Device &device)
bool WaitForFence(const vk::Device &device)
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 VALIDATION_LOG
Definition validation.h:91