| Flutter Impeller |

khr_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
5 #include "impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.h"
6
7 #include "fml/synchronization/semaphore.h"
8 #include "impeller/base/validation.h"
9 #include "impeller/core/formats.h"
10 #include "impeller/renderer/backend/vulkan/command_buffer_vk.h"
11 #include "impeller/renderer/backend/vulkan/context_vk.h"
12 #include "impeller/renderer/backend/vulkan/formats_vk.h"
13 #include "impeller/renderer/backend/vulkan/gpu_tracer_vk.h"
14 #include "impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.h"
15 #include "impeller/renderer/backend/vulkan/swapchain/surface_vk.h"
16 #include "impeller/renderer/backend/vulkan/texture_vk.h"
17 #include "impeller/renderer/context.h"
18
19 namespace impeller {
20
21 static constexpr size_t kMaxFramesInFlight = 2u;
22
23 struct KHRFrameSynchronizerVK {
24 vk::UniqueFence acquire;
25 vk::UniqueSemaphore render_ready;
26 vk::UniqueSemaphore present_ready;
27 std::shared_ptr<CommandBuffer> final_cmd_buffer;
28 bool is_valid = false;
29 // Whether the renderer attached an onscreen command buffer to render to.
30 bool has_onscreen = false;
31
32 explicit KHRFrameSynchronizerVK(const vk::Device& device) {
33 auto acquire_res = device.createFenceUnique(
34 vk::FenceCreateInfo{vk::FenceCreateFlagBits::eSignaled});
35 auto render_res = device.createSemaphoreUnique({});
36 auto present_res = device.createSemaphoreUnique({});
37 if (acquire_res.result != vk::Result::eSuccess ||
38 render_res.result != vk::Result::eSuccess ||
39 present_res.result != vk::Result::eSuccess) {
40 VALIDATION_LOG << "Could not create synchronizer.";
41 return;
42 }
43 acquire = std::move(acquire_res.value);
44 render_ready = std::move(render_res.value);
45 present_ready = std::move(present_res.value);
46 is_valid = true;
47 }
48
49 ~KHRFrameSynchronizerVK() = default;
50
51 bool WaitForFence(const vk::Device& device) {
52 if (auto result = device.waitForFences(
53 *acquire, // fence
54 true, // wait all
55 std::numeric_limits<uint64_t>::max() // timeout (ns)
56 );
57 result != vk::Result::eSuccess) {
58 VALIDATION_LOG << "Fence wait failed: " << vk::to_string(result);
59 return false;
60 }
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 };
69
70 static bool ContainsFormat(const std::vector<vk::SurfaceFormatKHR>& formats,
71 vk::SurfaceFormatKHR format) {
72 return std::find(formats.begin(), formats.end(), format) != formats.end();
73 }
74
75 static std::optional<vk::SurfaceFormatKHR> ChooseSurfaceFormat(
76 const std::vector<vk::SurfaceFormatKHR>& formats,
77 PixelFormat preference) {
78 const auto colorspace = vk::ColorSpaceKHR::eSrgbNonlinear;
79 const auto vk_preference =
80 vk::SurfaceFormatKHR{ToVKImageFormat(preference), colorspace};
81 if (ContainsFormat(formats, vk_preference)) {
82 return vk_preference;
83 }
84
85 std::vector<vk::SurfaceFormatKHR> options = {
86 {vk::Format::eB8G8R8A8Unorm, colorspace},
87 {vk::Format::eR8G8B8A8Unorm, colorspace}};
88 for (const auto& format : options) {
89 if (ContainsFormat(formats, format)) {
90 return format;
91 }
92 }
93
94 return std::nullopt;
95 }
96
97 static std::optional<vk::CompositeAlphaFlagBitsKHR> ChooseAlphaCompositionMode(
98 vk::CompositeAlphaFlagsKHR flags) {
99 if (flags & vk::CompositeAlphaFlagBitsKHR::eInherit) {
100 return vk::CompositeAlphaFlagBitsKHR::eInherit;
101 }
102 if (flags & vk::CompositeAlphaFlagBitsKHR::ePreMultiplied) {
103 return vk::CompositeAlphaFlagBitsKHR::ePreMultiplied;
104 }
105 if (flags & vk::CompositeAlphaFlagBitsKHR::ePostMultiplied) {
106 return vk::CompositeAlphaFlagBitsKHR::ePostMultiplied;
107 }
108 if (flags & vk::CompositeAlphaFlagBitsKHR::eOpaque) {
109 return vk::CompositeAlphaFlagBitsKHR::eOpaque;
110 }
111
112 return std::nullopt;
113 }
114
115 std::shared_ptr<KHRSwapchainImplVK> KHRSwapchainImplVK::Create(
116 const std::shared_ptr<Context>& context,
117 vk::UniqueSurfaceKHR surface,
118 const ISize& size,
119 bool enable_msaa,
120 vk::SwapchainKHR old_swapchain) {
121 return std::shared_ptr<KHRSwapchainImplVK>(new KHRSwapchainImplVK(
122 context, std::move(surface), size, enable_msaa, old_swapchain));
123 }
124
125 KHRSwapchainImplVK::KHRSwapchainImplVK(const std::shared_ptr<Context>& context,
126 vk::UniqueSurfaceKHR surface,
127 const ISize& size,
128 bool enable_msaa,
129 vk::SwapchainKHR old_swapchain) {
130 if (!context) {
131 VALIDATION_LOG << "Cannot create a swapchain without a context.";
132 return;
133 }
134
135 auto& vk_context = ContextVK::Cast(*context);
136
137 const auto [caps_result, surface_caps] =
138 vk_context.GetPhysicalDevice().getSurfaceCapabilitiesKHR(*surface);
139 if (caps_result != vk::Result::eSuccess) {
140 VALIDATION_LOG << "Could not get surface capabilities: "
141 << vk::to_string(caps_result);
142 return;
143 }
144
145 auto [formats_result, formats] =
146 vk_context.GetPhysicalDevice().getSurfaceFormatsKHR(*surface);
147 if (formats_result != vk::Result::eSuccess) {
148 VALIDATION_LOG << "Could not get surface formats: "
149 << vk::to_string(formats_result);
150 return;
151 }
152
153 const auto format = ChooseSurfaceFormat(
154 formats, vk_context.GetCapabilities()->GetDefaultColorFormat());
155 if (!format.has_value()) {
156 VALIDATION_LOG << "Swapchain has no supported formats.";
157 return;
158 }
159 vk_context.SetOffscreenFormat(ToPixelFormat(format.value().format));
160
161 const auto composite =
162 ChooseAlphaCompositionMode(surface_caps.supportedCompositeAlpha);
163 if (!composite.has_value()) {
164 VALIDATION_LOG << "No composition mode supported.";
165 return;
166 }
167
168 vk::SwapchainCreateInfoKHR swapchain_info;
169 swapchain_info.surface = *surface;
170 swapchain_info.imageFormat = format.value().format;
171 swapchain_info.imageColorSpace = format.value().colorSpace;
172 swapchain_info.presentMode = vk::PresentModeKHR::eFifo;
173 swapchain_info.imageExtent = vk::Extent2D{
174 std::clamp(static_cast<uint32_t>(size.width),
175 surface_caps.minImageExtent.width,
176 surface_caps.maxImageExtent.width),
177 std::clamp(static_cast<uint32_t>(size.height),
178 surface_caps.minImageExtent.height,
179 surface_caps.maxImageExtent.height),
180 };
181 swapchain_info.minImageCount =
182 std::clamp(surface_caps.minImageCount + 1u, // preferred image count
183 surface_caps.minImageCount, // min count cannot be zero
184 surface_caps.maxImageCount == 0u
185 ? surface_caps.minImageCount + 1u
186 : surface_caps.maxImageCount // max zero means no limit
187 );
188 swapchain_info.imageArrayLayers = 1u;
189 // Swapchain images are primarily used as color attachments (via resolve) or
190 // input attachments.
191 swapchain_info.imageUsage = vk::ImageUsageFlagBits::eColorAttachment |
192 vk::ImageUsageFlagBits::eInputAttachment;
193 swapchain_info.preTransform = vk::SurfaceTransformFlagBitsKHR::eIdentity;
194 swapchain_info.compositeAlpha = composite.value();
195 // If we set the clipped value to true, Vulkan expects we will never read back
196 // from the buffer. This is analogous to [CAMetalLayer framebufferOnly] in
197 // Metal.
198 swapchain_info.clipped = true;
199 // Setting queue family indices is irrelevant since the present mode is
200 // exclusive.
201 swapchain_info.imageSharingMode = vk::SharingMode::eExclusive;
202 swapchain_info.oldSwapchain = old_swapchain;
203
204 auto [swapchain_result, swapchain] =
205 vk_context.GetDevice().createSwapchainKHRUnique(swapchain_info);
206 if (swapchain_result != vk::Result::eSuccess) {
207 VALIDATION_LOG << "Could not create swapchain: "
208 << vk::to_string(swapchain_result);
209 return;
210 }
211
212 auto [images_result, images] =
213 vk_context.GetDevice().getSwapchainImagesKHR(*swapchain);
214 if (images_result != vk::Result::eSuccess) {
215 VALIDATION_LOG << "Could not get swapchain images.";
216 return;
217 }
218
219 TextureDescriptor texture_desc;
220 texture_desc.usage = TextureUsage::kRenderTarget;
221 texture_desc.storage_mode = StorageMode::kDevicePrivate;
222 texture_desc.format = ToPixelFormat(swapchain_info.imageFormat);
223 texture_desc.size = ISize::MakeWH(swapchain_info.imageExtent.width,
224 swapchain_info.imageExtent.height);
225
226 std::vector<std::shared_ptr<KHRSwapchainImageVK>> swapchain_images;
227 for (const auto& image : images) {
228 auto swapchain_image = std::make_shared<KHRSwapchainImageVK>(
229 texture_desc, // texture descriptor
230 vk_context.GetDevice(), // device
231 image // image
232 );
233 if (!swapchain_image->IsValid()) {
234 VALIDATION_LOG << "Could not create swapchain image.";
235 return;
236 }
237 ContextVK::SetDebugName(
238 vk_context.GetDevice(), swapchain_image->GetImage(),
239 "SwapchainImage" + std::to_string(swapchain_images.size()));
240 ContextVK::SetDebugName(
241 vk_context.GetDevice(), swapchain_image->GetImageView(),
242 "SwapchainImageView" + std::to_string(swapchain_images.size()));
243
244 swapchain_images.emplace_back(swapchain_image);
245 }
246
247 std::vector<std::unique_ptr<KHRFrameSynchronizerVK>> synchronizers;
248 for (size_t i = 0u; i < kMaxFramesInFlight; i++) {
249 auto sync =
250 std::make_unique<KHRFrameSynchronizerVK>(vk_context.GetDevice());
251 if (!sync->is_valid) {
252 VALIDATION_LOG << "Could not create frame synchronizers.";
253 return;
254 }
255 synchronizers.emplace_back(std::move(sync));
256 }
257 FML_DCHECK(!synchronizers.empty());
258
259 context_ = context;
260 surface_ = std::move(surface);
261 surface_format_ = swapchain_info.imageFormat;
262 swapchain_ = std::move(swapchain);
263 transients_ = std::make_shared<SwapchainTransientsVK>(context, texture_desc,
264 enable_msaa);
265 images_ = std::move(swapchain_images);
266 synchronizers_ = std::move(synchronizers);
267 current_frame_ = synchronizers_.size() - 1u;
268 size_ = size;
269 enable_msaa_ = enable_msaa;
270 is_valid_ = true;
271 }
272
273 KHRSwapchainImplVK::~KHRSwapchainImplVK() {
274 DestroySwapchain();
275 }
276
277 const ISize& KHRSwapchainImplVK::GetSize() const {
278 return size_;
279 }
280
281 std::optional<ISize> KHRSwapchainImplVK::GetCurrentUnderlyingSurfaceSize()
282 const {
283 if (!IsValid()) {
284 return std::nullopt;
285 }
286
287 auto context = context_.lock();
288 if (!context) {
289 return std::nullopt;
290 }
291
292 auto& vk_context = ContextVK::Cast(*context);
293 const auto [result, surface_caps] =
294 vk_context.GetPhysicalDevice().getSurfaceCapabilitiesKHR(surface_.get());
295 if (result != vk::Result::eSuccess) {
296 return std::nullopt;
297 }
298
299 // From the spec: `currentExtent` is the current width and height of the
300 // surface, or the special value (0xFFFFFFFF, 0xFFFFFFFF) indicating that the
301 // surface size will be determined by the extent of a swapchain targeting the
302 // surface.
303 constexpr uint32_t kCurrentExtentsPlaceholder = 0xFFFFFFFF;
304 if (surface_caps.currentExtent.width == kCurrentExtentsPlaceholder ||
305 surface_caps.currentExtent.height == kCurrentExtentsPlaceholder) {
306 return std::nullopt;
307 }
308
309 return ISize::MakeWH(surface_caps.currentExtent.width,
310 surface_caps.currentExtent.height);
311 }
312
313 bool KHRSwapchainImplVK::IsValid() const {
314 return is_valid_;
315 }
316
317 void KHRSwapchainImplVK::WaitIdle() const {
318 if (auto context = context_.lock()) {
319 [[maybe_unused]] auto result =
320 ContextVK::Cast(*context).GetDevice().waitIdle();
321 }
322 }
323
324 std::pair<vk::UniqueSurfaceKHR, vk::UniqueSwapchainKHR>
325 KHRSwapchainImplVK::DestroySwapchain() {
326 WaitIdle();
327 is_valid_ = false;
328 synchronizers_.clear();
329 images_.clear();
330 context_.reset();
331 return {std::move(surface_), std::move(swapchain_)};
332 }
333
334 vk::Format KHRSwapchainImplVK::GetSurfaceFormat() const {
335 return surface_format_;
336 }
337
338 std::shared_ptr<Context> KHRSwapchainImplVK::GetContext() const {
339 return context_.lock();
340 }
341
342 KHRSwapchainImplVK::AcquireResult KHRSwapchainImplVK::AcquireNextDrawable() {
343 auto context_strong = context_.lock();
344 if (!context_strong) {
345 return KHRSwapchainImplVK::AcquireResult{};
346 }
347
348 const auto& context = ContextVK::Cast(*context_strong);
349
350 current_frame_ = (current_frame_ + 1u) % synchronizers_.size();
351
352 const auto& sync = synchronizers_[current_frame_];
353
354 //----------------------------------------------------------------------------
355 /// Wait on the host for the synchronizer fence.
356 ///
357 if (!sync->WaitForFence(context.GetDevice())) {
358 VALIDATION_LOG << "Could not wait for fence.";
359 return KHRSwapchainImplVK::AcquireResult{};
360 }
361
362 //----------------------------------------------------------------------------
363 /// Get the next image index.
364 ///
365 /// @bug Non-infinite timeouts are not supported on some older Android
366 /// devices and the only indication we get is log spam which serves to
367 /// add confusion. Just use an infinite timeout instead of being
368 /// defensive.
369 auto [acq_result, index] = context.GetDevice().acquireNextImageKHR(
370 *swapchain_, // swapchain
371 std::numeric_limits<uint64_t>::max(), // timeout (ns)
372 *sync->render_ready, // signal semaphore
373 nullptr // fence
374 );
375
376 switch (acq_result) {
377 case vk::Result::eSuccess:
378 // Keep going.
379 break;
380 case vk::Result::eSuboptimalKHR:
381 case vk::Result::eErrorOutOfDateKHR:
382 // A recoverable error. Just say we are out of date.
383 return AcquireResult{true /* out of date */};
384 break;
385 default:
386 // An unrecoverable error.
387 VALIDATION_LOG << "Could not acquire next swapchain image: "
388 << vk::to_string(acq_result);
389 return AcquireResult{false /* out of date */};
390 }
391
392 if (index >= images_.size()) {
393 VALIDATION_LOG << "Swapchain returned an invalid image index.";
394 return KHRSwapchainImplVK::AcquireResult{};
395 }
396
397 /// Record all subsequent cmd buffers as part of the current frame.
398 context.GetGPUTracer()->MarkFrameStart();
399
400 auto image = images_[index % images_.size()];
401 uint32_t image_index = index;
402 return AcquireResult{SurfaceVK::WrapSwapchainImage(
403 transients_, // transients
404 image, // swapchain image
405 [weak_swapchain = weak_from_this(), image, image_index]() -> bool {
406 auto swapchain = weak_swapchain.lock();
407 if (!swapchain) {
408 return false;
409 }
410 return swapchain->Present(image, image_index);
411 } // swap callback
412 )};
413 }
414
415 void KHRSwapchainImplVK::AddFinalCommandBuffer(
416 std::shared_ptr<CommandBuffer> cmd_buffer) {
417 const auto& sync = synchronizers_[current_frame_];
418 sync->final_cmd_buffer = std::move(cmd_buffer);
419 sync->has_onscreen = true;
420 }
421
422 bool KHRSwapchainImplVK::Present(
423 const std::shared_ptr<KHRSwapchainImageVK>& image,
424 uint32_t index) {
425 auto context_strong = context_.lock();
426 if (!context_strong) {
427 return false;
428 }
429
430 const auto& context = ContextVK::Cast(*context_strong);
431 const auto& sync = synchronizers_[current_frame_];
432 context.GetGPUTracer()->MarkFrameEnd();
433
434 //----------------------------------------------------------------------------
435 /// Transition the image to color-attachment-optimal.
436 ///
437 if (!sync->has_onscreen) {
438 sync->final_cmd_buffer = context.CreateCommandBuffer();
439 }
440 sync->has_onscreen = false;
441 if (!sync->final_cmd_buffer) {
442 return false;
443 }
444
445 auto vk_final_cmd_buffer =
446 CommandBufferVK::Cast(*sync->final_cmd_buffer).GetCommandBuffer();
447 {
448 BarrierVK barrier;
449 barrier.new_layout = vk::ImageLayout::ePresentSrcKHR;
450 barrier.cmd_buffer = vk_final_cmd_buffer;
451 barrier.src_access = vk::AccessFlagBits::eColorAttachmentWrite;
452 barrier.src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput;
453 barrier.dst_access = {};
454 barrier.dst_stage = vk::PipelineStageFlagBits::eBottomOfPipe;
455
456 if (!image->SetLayout(barrier).ok()) {
457 return false;
458 }
459
460 if (vk_final_cmd_buffer.end() != vk::Result::eSuccess) {
461 return false;
462 }
463 }
464
465 //----------------------------------------------------------------------------
466 /// Signal that the presentation semaphore is ready.
467 ///
468 {
469 vk::SubmitInfo submit_info;
470 vk::PipelineStageFlags wait_stage =
471 vk::PipelineStageFlagBits::eColorAttachmentOutput;
472 submit_info.setWaitDstStageMask(wait_stage);
473 submit_info.setWaitSemaphores(*sync->render_ready);
474 submit_info.setSignalSemaphores(*sync->present_ready);
475 submit_info.setCommandBuffers(vk_final_cmd_buffer);
476 auto result =
477 context.GetGraphicsQueue()->Submit(submit_info, *sync->acquire);
478 if (result != vk::Result::eSuccess) {
479 VALIDATION_LOG << "Could not wait on render semaphore: "
480 << vk::to_string(result);
481 return false;
482 }
483 }
484
485 //----------------------------------------------------------------------------
486 /// Present the image.
487 ///
488 uint32_t indices[] = {static_cast<uint32_t>(index)};
489
490 vk::PresentInfoKHR present_info;
491 present_info.setSwapchains(*swapchain_);
492 present_info.setImageIndices(indices);
493 present_info.setWaitSemaphores(*sync->present_ready);
494
495 auto result = context.GetGraphicsQueue()->Present(present_info);
496
497 switch (result) {
498 case vk::Result::eErrorOutOfDateKHR:
499 // Caller will recreate the impl on acquisition, not submission.
500 [[fallthrough]];
501 case vk::Result::eErrorSurfaceLostKHR:
502 // Vulkan guarantees that the set of queue operations will still
503 // complete successfully.
504 [[fallthrough]];
505 case vk::Result::eSuboptimalKHR:
506 // Even though we're handling rotation changes via polling, we
507 // still need to handle the case where the swapchain signals that
508 // it's suboptimal (i.e. every frame when we are rotated given we
509 // aren't doing Vulkan pre-rotation).
510 [[fallthrough]];
511 case vk::Result::eSuccess:
512 break;
513 default:
514 VALIDATION_LOG << "Could not present queue: " << vk::to_string(result);
515 break;
516 }
517
518 return true;
519 }
520
521 } // namespace impeller
impeller::BackendCast< ContextVK, Context >::Cast
static ContextVK & Cast(Context &base)
Definition: backend_cast.h:13
impeller::CommandBufferVK::GetCommandBuffer
vk::CommandBuffer GetCommandBuffer() const
Retrieve the native command buffer from this object.
Definition: command_buffer_vk.cc:119
impeller::ContextVK::SetDebugName
bool SetDebugName(T handle, std::string_view label) const
Definition: context_vk.h:151
impeller::ContextVK::GetDevice
const vk::Device & GetDevice() const
Definition: context_vk.cc:589
impeller::KHRSwapchainImplVK
An instance of a swapchain that does NOT adapt to going out of date with the underlying surface....
Definition: khr_swapchain_impl_vk.h:31
impeller::KHRSwapchainImplVK::GetContext
std::shared_ptr< Context > GetContext() const
Definition: khr_swapchain_impl_vk.cc:338
impeller::KHRSwapchainImplVK::AddFinalCommandBuffer
void AddFinalCommandBuffer(std::shared_ptr< CommandBuffer > cmd_buffer)
Definition: khr_swapchain_impl_vk.cc:415
impeller::KHRSwapchainImplVK::Create
static std::shared_ptr< KHRSwapchainImplVK > Create(const std::shared_ptr< Context > &context, vk::UniqueSurfaceKHR surface, const ISize &size, bool enable_msaa=true, vk::SwapchainKHR old_swapchain=VK_NULL_HANDLE)
Definition: khr_swapchain_impl_vk.cc:115
impeller::KHRSwapchainImplVK::AcquireNextDrawable
AcquireResult AcquireNextDrawable()
Definition: khr_swapchain_impl_vk.cc:342
impeller::KHRSwapchainImplVK::GetSurfaceFormat
vk::Format GetSurfaceFormat() const
Definition: khr_swapchain_impl_vk.cc:334
impeller::KHRSwapchainImplVK::IsValid
bool IsValid() const
Definition: khr_swapchain_impl_vk.cc:313
impeller::KHRSwapchainImplVK::GetCurrentUnderlyingSurfaceSize
std::optional< ISize > GetCurrentUnderlyingSurfaceSize() const
Definition: khr_swapchain_impl_vk.cc:281
impeller::KHRSwapchainImplVK::DestroySwapchain
std::pair< vk::UniqueSurfaceKHR, vk::UniqueSwapchainKHR > DestroySwapchain()
Definition: khr_swapchain_impl_vk.cc:325
impeller::KHRSwapchainImplVK::GetSize
const ISize & GetSize() const
Definition: khr_swapchain_impl_vk.cc:277
impeller::KHRSwapchainImplVK::~KHRSwapchainImplVK
~KHRSwapchainImplVK()
Definition: khr_swapchain_impl_vk.cc:273
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
command_buffer_vk.h
formats.h
formats_vk.h
gpu_tracer_vk.h
khr_swapchain_image_vk.h
khr_swapchain_impl_vk.h
impeller
Definition: allocation.cc:12
impeller::ToPixelFormat
constexpr PixelFormat ToPixelFormat(vk::Format format)
Definition: formats_vk.h:183
impeller::ChooseSurfaceFormat
static std::optional< vk::SurfaceFormatKHR > ChooseSurfaceFormat(const std::vector< vk::SurfaceFormatKHR > &formats, PixelFormat preference)
Definition: khr_swapchain_impl_vk.cc:75
impeller::kMaxFramesInFlight
static constexpr size_t kMaxFramesInFlight
Definition: khr_swapchain_impl_vk.cc:21
impeller::StorageMode::kDevicePrivate
@ kDevicePrivate
impeller::ContainsFormat
static bool ContainsFormat(const std::vector< vk::SurfaceFormatKHR > &formats, vk::SurfaceFormatKHR format)
Definition: khr_swapchain_impl_vk.cc:70
impeller::PixelFormat
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition: formats.h:99
impeller::ToVKImageFormat
constexpr vk::Format ToVKImageFormat(PixelFormat format)
Definition: formats_vk.h:146
impeller::ChooseAlphaCompositionMode
static std::optional< vk::CompositeAlphaFlagBitsKHR > ChooseAlphaCompositionMode(vk::CompositeAlphaFlagsKHR flags)
Definition: khr_swapchain_impl_vk.cc:97
impeller::TextureUsage::kRenderTarget
@ kRenderTarget
context_vk.h
surface_vk.h
context.h
impeller::KHRFrameSynchronizerVK
Definition: khr_swapchain_impl_vk.cc:23
impeller::KHRFrameSynchronizerVK::render_ready
vk::UniqueSemaphore render_ready
Definition: khr_swapchain_impl_vk.cc:25
impeller::KHRFrameSynchronizerVK::WaitForFence
bool WaitForFence(const vk::Device &device)
Definition: khr_swapchain_impl_vk.cc:51
impeller::KHRFrameSynchronizerVK::acquire
vk::UniqueFence acquire
Definition: khr_swapchain_impl_vk.cc:24
impeller::KHRFrameSynchronizerVK::is_valid
bool is_valid
Definition: khr_swapchain_impl_vk.cc:28
impeller::KHRFrameSynchronizerVK::KHRFrameSynchronizerVK
KHRFrameSynchronizerVK(const vk::Device &device)
Definition: khr_swapchain_impl_vk.cc:32
impeller::KHRFrameSynchronizerVK::has_onscreen
bool has_onscreen
Definition: khr_swapchain_impl_vk.cc:30
impeller::KHRFrameSynchronizerVK::~KHRFrameSynchronizerVK
~KHRFrameSynchronizerVK()=default
impeller::KHRFrameSynchronizerVK::present_ready
vk::UniqueSemaphore present_ready
Definition: khr_swapchain_impl_vk.cc:26
impeller::KHRFrameSynchronizerVK::final_cmd_buffer
std::shared_ptr< CommandBuffer > final_cmd_buffer
Definition: khr_swapchain_impl_vk.cc:27
impeller::KHRSwapchainImplVK::AcquireResult
Definition: khr_swapchain_impl_vk.h:44
impeller::TSize
Definition: size.h:25
impeller::TSize::height
Type height
Definition: size.h:29
impeller::TSize::width
Type width
Definition: size.h:28
impeller::TSize::MakeWH
static constexpr TSize MakeWH(Type width, Type height)
Definition: size.h:43
texture_vk.h
validation.h
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:91