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
111 return desc_.size;
112}
113
115 return is_valid_;
116}
117
122
123std::unique_ptr<Surface> AHBSwapchainImplVK::AcquireNextDrawable() {
124 auto context = transients_->GetContext().lock();
125 if (!context) {
126 return nullptr;
127 }
128
129 frame_index_ = (frame_index_ + 1) % kMaxPendingPresents;
130
131 if (!frame_data_[frame_index_]->WaitForFence(
132 ContextVK::Cast(*context).GetDevice())) {
133 return nullptr;
134 }
135
136 if (!is_valid_) {
137 return nullptr;
138 }
139
140 auto pool_entry = pool_->Pop();
141
142 if (!pool_entry.IsValid()) {
143 VALIDATION_LOG << "Could not create AHB texture source.";
144 return nullptr;
145 }
146
147 // Import the render ready semaphore that will block onscreen rendering until
148 // it is ready.
149 if (!ImportRenderReady(pool_entry.render_ready_fence, pool_entry.texture)) {
150 VALIDATION_LOG << "Could wait on render ready fence.";
151 return nullptr;
152 }
153
154#if IMPELLER_DEBUG
155 if (context) {
156 ContextVK::Cast(*context).GetGPUTracer()->MarkFrameStart();
157 }
158#endif // IMPELLER_DEBUG
159
161 transients_, pool_entry.texture,
162 [weak = weak_from_this(), texture = pool_entry.texture]() {
163 auto thiz = weak.lock();
164 if (!thiz) {
165 VALIDATION_LOG << "Swapchain died before image could be presented.";
166 return false;
167 }
168 return thiz->Present(texture);
169 });
170
171 if (!surface) {
172 return nullptr;
173 }
174
175 return surface;
176}
177
178bool AHBSwapchainImplVK::Present(
179 const std::shared_ptr<AHBTextureSourceVK>& texture) {
180 auto control = surface_control_.lock();
181 if (!control || !control->IsValid()) {
182 VALIDATION_LOG << "Surface control died before swapchain image could be "
183 "presented.";
184 return false;
185 }
186
187#if IMPELLER_DEBUG
188 auto context = transients_->GetContext().lock();
189 if (context) {
190 ContextVK::Cast(*context).GetGPUTracer()->MarkFrameEnd();
191 }
192#endif // IMPELLER_DEBUG
193
194 if (!texture) {
195 return false;
196 }
197
198 auto present_ready = SubmitSignalForPresentReady(texture);
199
200 if (!present_ready) {
201 VALIDATION_LOG << "Could not submit completion signal.";
202 return false;
203 }
204
205 android::SurfaceTransaction transaction =
207 if (!transaction.SetContents(control.get(), //
208 texture->GetBackingStore(), //
209 present_ready->CreateFD() //
210 )) {
211 VALIDATION_LOG << "Could not set swapchain image contents on the surface "
212 "control.";
213 return false;
214 }
215 return transaction.Apply(
216 [texture, weak = weak_from_this()](ASurfaceTransactionStats* stats) {
217 auto thiz = weak.lock();
218 if (!thiz) {
219 return;
220 }
221 thiz->OnTextureUpdatedOnSurfaceControl(texture, stats);
222 });
223}
224
225void AHBSwapchainImplVK::AddFinalCommandBuffer(
226 std::shared_ptr<CommandBuffer> cmd_buffer) {
227 frame_data_[frame_index_]->final_cmd_buffer = std::move(cmd_buffer);
228}
229
230std::shared_ptr<ExternalSemaphoreVK>
231AHBSwapchainImplVK::SubmitSignalForPresentReady(
232 const std::shared_ptr<AHBTextureSourceVK>& texture) const {
233 auto context = transients_->GetContext().lock();
234 if (!context) {
235 return nullptr;
236 }
237
238 auto present_ready = std::make_shared<ExternalSemaphoreVK>(context);
239 if (!present_ready || !present_ready->IsValid()) {
240 return nullptr;
241 }
242
243 auto& sync = frame_data_[frame_index_];
244 auto command_buffer = sync->final_cmd_buffer;
245 if (!command_buffer) {
246 return nullptr;
247 }
248 CommandBufferVK& command_buffer_vk = CommandBufferVK::Cast(*command_buffer);
249 const auto command_encoder_vk = command_buffer_vk.GetCommandBuffer();
250 if (!command_buffer_vk.EndCommandBuffer()) {
251 return nullptr;
252 }
253 sync->present_ready = present_ready;
254
255 vk::SubmitInfo submit_info;
256 vk::PipelineStageFlags wait_stage =
257 vk::PipelineStageFlagBits::eColorAttachmentOutput;
258 if (sync->render_ready) {
259 submit_info.setPWaitSemaphores(&sync->render_ready.get());
260 submit_info.setWaitSemaphoreCount(1);
261 submit_info.setWaitDstStageMask(wait_stage);
262 }
263 submit_info.setCommandBuffers(command_encoder_vk);
264 submit_info.setPSignalSemaphores(&sync->present_ready->GetHandle());
265 submit_info.setSignalSemaphoreCount(1);
266
267 auto result = ContextVK::Cast(*context).GetGraphicsQueue()->Submit(
268 submit_info, *sync->acquire);
269 if (result != vk::Result::eSuccess) {
270 return nullptr;
271 }
272 sync->acquire_fence_pending = true;
273 return present_ready;
274}
275
276vk::UniqueSemaphore AHBSwapchainImplVK::CreateRenderReadySemaphore(
277 const std::shared_ptr<fml::UniqueFD>& fd) const {
278 if (!fd->is_valid()) {
279 return {};
280 }
281
282 auto context = transients_->GetContext().lock();
283 if (!context) {
284 return {};
285 }
286
287 const auto& context_vk = ContextVK::Cast(*context);
288 const auto& device = context_vk.GetDevice();
289
290 auto signal_wait = device.createSemaphoreUnique({});
291 if (signal_wait.result != vk::Result::eSuccess) {
292 return {};
293 }
294
295 context_vk.SetDebugName(*signal_wait.value, "AHBRenderReadySemaphore");
296
297 vk::ImportSemaphoreFdInfoKHR import_info;
298 import_info.semaphore = *signal_wait.value;
299 import_info.fd = fd->get();
300 import_info.handleType = vk::ExternalSemaphoreHandleTypeFlagBits::eSyncFd;
301 // From the spec: Sync FDs can only be imported temporarily.
302 import_info.flags = vk::SemaphoreImportFlagBitsKHR::eTemporary;
303
304 const auto import_result = device.importSemaphoreFdKHR(import_info);
305
306 if (import_result != vk::Result::eSuccess) {
307 VALIDATION_LOG << "Could not import semaphore FD: "
308 << vk::to_string(import_result);
309 return {};
310 }
311
312 // From the spec: Importing a semaphore payload from a file descriptor
313 // transfers ownership of the file descriptor from the application to the
314 // Vulkan implementation. The application must not perform any operations on
315 // the file descriptor after a successful import.
316 [[maybe_unused]] auto released = fd->release();
317
318 return std::move(signal_wait.value);
319}
320
321bool AHBSwapchainImplVK::ImportRenderReady(
322 const std::shared_ptr<fml::UniqueFD>& render_ready_fence,
323 const std::shared_ptr<AHBTextureSourceVK>& texture) {
324 auto context = transients_->GetContext().lock();
325 if (!context) {
326 return false;
327 }
328
329 // If there is no render ready fence, we are already ready to render into
330 // the texture. There is nothing more to do.
331 if (!render_ready_fence || !render_ready_fence->is_valid()) {
332 frame_data_[frame_index_]->render_ready = {};
333 return true;
334 }
335
336 auto semaphore = CreateRenderReadySemaphore(render_ready_fence);
337 if (!semaphore) {
338 return false;
339 }
340 // This semaphore will be later used to block the onscreen render pass
341 // from starting until the system is done reading the onscreen.
342 frame_data_[frame_index_]->render_ready = std::move(semaphore);
343 return true;
344}
345
346void AHBSwapchainImplVK::OnTextureUpdatedOnSurfaceControl(
347 std::shared_ptr<AHBTextureSourceVK> texture,
348 ASurfaceTransactionStats* stats) {
349 auto control = surface_control_.lock();
350 if (!control) {
351 return;
352 }
353
354 // Ask for an FD that gets signaled when the previous buffer is released. This
355 // can be invalid if there is no wait necessary.
356 auto render_ready_fence =
357 android::CreatePreviousReleaseFence(*control, stats);
358
359 // The transaction completion indicates that the surface control now
360 // references the hardware buffer. We can recycle the previous set buffer
361 // safely.
362 Lock lock(currently_displayed_texture_mutex_);
363 auto old_texture = currently_displayed_texture_;
364 currently_displayed_texture_ = std::move(texture);
365 pool_->Push(std::move(old_texture), std::move(render_ready_fence));
366}
367
368} // 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
FlTexture * texture
std::function< android::SurfaceTransaction()> CreateTransactionCB
constexpr PixelFormat ToPixelFormat(vk::Format format)
Definition formats_vk.h:185
static constexpr const size_t kMaxPendingPresents
static TextureDescriptor ToSwapchainTextureDescriptor(const android::HardwareBufferDescriptor &ahb_desc)
Definition ref_ptr.h:261
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