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