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