9
9
#include " impeller/renderer/backend/vulkan/barrier_vk.h"
10
10
#include " impeller/renderer/backend/vulkan/command_buffer_vk.h"
11
11
#include " impeller/renderer/backend/vulkan/command_encoder_vk.h"
12
+ #include " impeller/renderer/backend/vulkan/fence_waiter_vk.h"
12
13
#include " impeller/renderer/backend/vulkan/gpu_tracer_vk.h"
13
14
#include " impeller/renderer/backend/vulkan/swapchain/ahb/ahb_formats.h"
14
15
#include " impeller/renderer/backend/vulkan/swapchain/surface_vk.h"
15
16
#include " impeller/toolkit/android/surface_transaction.h"
17
+ #include " impeller/toolkit/android/surface_transaction_stats.h"
16
18
17
19
namespace impeller {
18
20
@@ -96,9 +98,9 @@ std::unique_ptr<Surface> AHBSwapchainImplVK::AcquireNextDrawable() {
96
98
return nullptr ;
97
99
}
98
100
99
- auto texture = pool_->Pop ();
101
+ auto pool_entry = pool_->Pop ();
100
102
101
- if (!texture ) {
103
+ if (!pool_entry. IsValid () ) {
102
104
VALIDATION_LOG << " Could not create AHB texture source." ;
103
105
return nullptr ;
104
106
}
@@ -108,9 +110,19 @@ std::unique_ptr<Surface> AHBSwapchainImplVK::AcquireNextDrawable() {
108
110
ContextVK::Cast (*context).GetGPUTracer ()->MarkFrameStart ();
109
111
}
110
112
113
+ // Ask the GPU to wait for the render ready semaphore to be signaled before
114
+ // performing rendering operations.
115
+ if (!SubmitWaitForRenderReady (pool_entry.render_ready_fence ,
116
+ pool_entry.texture )) {
117
+ VALIDATION_LOG << " Could not submit a command to the GPU to wait on render "
118
+ " readiness." ;
119
+ return nullptr ;
120
+ }
121
+
111
122
auto surface = SurfaceVK::WrapSwapchainImage (
112
- transients_, texture,
113
- [signaler = auto_sema_signaler, weak = weak_from_this (), texture]() {
123
+ transients_, pool_entry.texture ,
124
+ [signaler = auto_sema_signaler, weak = weak_from_this (),
125
+ texture = pool_entry.texture ]() {
114
126
auto thiz = weak.lock ();
115
127
if (!thiz) {
116
128
VALIDATION_LOG << " Swapchain died before image could be presented." ;
@@ -145,7 +157,7 @@ bool AHBSwapchainImplVK::Present(
145
157
return false ;
146
158
}
147
159
148
- auto fence = SubmitCompletionSignal (texture);
160
+ auto fence = SubmitSignalForPresentReady (texture);
149
161
150
162
if (!fence) {
151
163
VALIDATION_LOG << " Could not submit completion signal." ;
@@ -161,16 +173,18 @@ bool AHBSwapchainImplVK::Present(
161
173
" control." ;
162
174
return false ;
163
175
}
164
- return transaction.Apply ([signaler, texture, weak = weak_from_this ()]() {
176
+ return transaction.Apply ([signaler, texture, weak = weak_from_this ()](
177
+ ASurfaceTransactionStats* stats) {
165
178
auto thiz = weak.lock ();
166
179
if (!thiz) {
167
180
return ;
168
181
}
169
- thiz->OnTextureSetOnSurfaceControl (signaler, texture);
182
+ thiz->OnTextureUpdatedOnSurfaceControl (signaler, texture, stats );
170
183
});
171
184
}
172
185
173
- std::shared_ptr<ExternalFenceVK> AHBSwapchainImplVK::SubmitCompletionSignal (
186
+ std::shared_ptr<ExternalFenceVK>
187
+ AHBSwapchainImplVK::SubmitSignalForPresentReady (
174
188
const std::shared_ptr<AHBTextureSourceVK>& texture) const {
175
189
auto context = transients_->GetContext ().lock ();
176
190
if (!context) {
@@ -185,7 +199,7 @@ std::shared_ptr<ExternalFenceVK> AHBSwapchainImplVK::SubmitCompletionSignal(
185
199
if (!command_buffer) {
186
200
return nullptr ;
187
201
}
188
- command_buffer->SetLabel (" AHBPresentCommandBuffer " );
202
+ command_buffer->SetLabel (" AHBSubmitSignalForPresentReadyCB " );
189
203
const auto & encoder = CommandBufferVK::Cast (*command_buffer).GetEncoder ();
190
204
191
205
const auto command_encoder_vk = encoder->GetCommandBuffer ();
@@ -219,17 +233,148 @@ std::shared_ptr<ExternalFenceVK> AHBSwapchainImplVK::SubmitCompletionSignal(
219
233
return fence;
220
234
}
221
235
222
- void AHBSwapchainImplVK::OnTextureSetOnSurfaceControl (
236
+ vk::UniqueSemaphore AHBSwapchainImplVK::CreateRenderReadySemaphore (
237
+ const std::shared_ptr<fml::UniqueFD>& fd) const {
238
+ if (!fd->is_valid ()) {
239
+ return {};
240
+ }
241
+
242
+ auto context = transients_->GetContext ().lock ();
243
+ if (!context) {
244
+ return {};
245
+ }
246
+
247
+ const auto & context_vk = ContextVK::Cast (*context);
248
+
249
+ const auto & device = context_vk.GetDevice ();
250
+
251
+ auto signal_wait = device.createSemaphoreUnique ({});
252
+
253
+ if (signal_wait.result != vk::Result::eSuccess) {
254
+ return {};
255
+ }
256
+
257
+ context_vk.SetDebugName (*signal_wait.value , " AHBRenderReadySemaphore" );
258
+
259
+ vk::ImportSemaphoreFdInfoKHR import_info;
260
+ import_info.semaphore = *signal_wait.value ;
261
+ import_info.fd = fd->get ();
262
+ import_info.handleType = vk::ExternalSemaphoreHandleTypeFlagBits::eSyncFd;
263
+ // From the spec: Sync FDs can only be imported temporarily.
264
+ import_info.flags = vk::SemaphoreImportFlagBitsKHR::eTemporary;
265
+
266
+ const auto import_result = device.importSemaphoreFdKHR (import_info);
267
+
268
+ if (import_result != vk::Result::eSuccess) {
269
+ VALIDATION_LOG << " Could not import semaphore FD: "
270
+ << vk::to_string (import_result);
271
+ return {};
272
+ }
273
+
274
+ // From the spec: Importing a semaphore payload from a file descriptor
275
+ // transfers ownership of the file descriptor from the application to the
276
+ // Vulkan implementation. The application must not perform any operations on
277
+ // the file descriptor after a successful import.
278
+ [[maybe_unused]] auto released = fd->release ();
279
+
280
+ return std::move (signal_wait.value );
281
+ }
282
+
283
+ bool AHBSwapchainImplVK::SubmitWaitForRenderReady (
284
+ const std::shared_ptr<fml::UniqueFD>& render_ready_fence,
285
+ const std::shared_ptr<AHBTextureSourceVK>& texture) const {
286
+ // If there is no render ready fence, we are already ready to render into
287
+ // the texture. There is nothing more to do.
288
+ if (!render_ready_fence || !render_ready_fence->is_valid ()) {
289
+ return true ;
290
+ }
291
+
292
+ auto context = transients_->GetContext ().lock ();
293
+ if (!context) {
294
+ return false ;
295
+ }
296
+
297
+ auto completion_fence =
298
+ ContextVK::Cast (*context).GetDevice ().createFenceUnique ({}).value ;
299
+ if (!completion_fence) {
300
+ return false ;
301
+ }
302
+
303
+ auto command_buffer = context->CreateCommandBuffer ();
304
+ if (!command_buffer) {
305
+ return false ;
306
+ }
307
+ command_buffer->SetLabel (" AHBSubmitWaitForRenderReadyCB" );
308
+ const auto & encoder = CommandBufferVK::Cast (*command_buffer).GetEncoder ();
309
+
310
+ const auto command_buffer_vk = encoder->GetCommandBuffer ();
311
+
312
+ BarrierVK barrier;
313
+ barrier.cmd_buffer = command_buffer_vk;
314
+ barrier.new_layout = vk::ImageLayout::eColorAttachmentOptimal;
315
+ barrier.src_stage = vk::PipelineStageFlagBits::eBottomOfPipe;
316
+ barrier.src_access = {};
317
+ barrier.dst_stage = vk::PipelineStageFlagBits::eTopOfPipe;
318
+ barrier.dst_access = {};
319
+
320
+ if (!texture->SetLayout (barrier).ok ()) {
321
+ return false ;
322
+ }
323
+
324
+ auto render_ready_semaphore =
325
+ MakeSharedVK (CreateRenderReadySemaphore (render_ready_fence));
326
+ encoder->Track (render_ready_semaphore);
327
+
328
+ if (!encoder->EndCommandBuffer ()) {
329
+ return false ;
330
+ }
331
+
332
+ vk::SubmitInfo submit_info;
333
+
334
+ if (render_ready_semaphore) {
335
+ constexpr const auto kWaitStages =
336
+ vk::PipelineStageFlagBits::eColorAttachmentOutput |
337
+ vk::PipelineStageFlagBits::eFragmentShader |
338
+ vk::PipelineStageFlagBits::eTransfer;
339
+ submit_info.setWaitSemaphores (render_ready_semaphore->Get ());
340
+ submit_info.setWaitDstStageMask (kWaitStages );
341
+ }
342
+
343
+ submit_info.setCommandBuffers (command_buffer_vk);
344
+
345
+ auto result = ContextVK::Cast (*context).GetGraphicsQueue ()->Submit (
346
+ submit_info, *completion_fence);
347
+ if (result != vk::Result::eSuccess) {
348
+ return false ;
349
+ }
350
+
351
+ ContextVK::Cast (*context).GetFenceWaiter ()->AddFence (
352
+ std::move (completion_fence), [encoder]() {});
353
+
354
+ return true ;
355
+ }
356
+
357
+ void AHBSwapchainImplVK::OnTextureUpdatedOnSurfaceControl (
223
358
const AutoSemaSignaler& signaler,
224
- std::shared_ptr<AHBTextureSourceVK> texture) {
225
- signaler->Reset ();
359
+ std::shared_ptr<AHBTextureSourceVK> texture,
360
+ ASurfaceTransactionStats* stats) {
361
+ auto control = surface_control_.lock ();
362
+ if (!control) {
363
+ return ;
364
+ }
365
+
366
+ // Ask for an FD that gets signaled when the previous buffer is released. This
367
+ // can be invalid if there is no wait necessary.
368
+ auto render_ready_fence =
369
+ android::CreatePreviousReleaseFence (*control, stats);
370
+
226
371
// The transaction completion indicates that the surface control now
227
372
// references the hardware buffer. We can recycle the previous set buffer
228
373
// safely.
229
374
Lock lock (currently_displayed_texture_mutex_);
230
375
auto old_texture = currently_displayed_texture_;
231
376
currently_displayed_texture_ = std::move (texture);
232
- pool_->Push (std::move (old_texture));
377
+ pool_->Push (std::move (old_texture), std::move (render_ready_fence) );
233
378
}
234
379
235
380
} // namespace impeller
0 commit comments