32 auto acquire_res =
device.createFenceUnique(
33 vk::FenceCreateInfo{vk::FenceCreateFlagBits::eSignaled});
34 auto render_res =
device.createSemaphoreUnique({});
35 if (acquire_res.result != vk::Result::eSuccess ||
36 render_res.result != vk::Result::eSuccess) {
40 acquire = std::move(acquire_res.value);
48 if (
auto result =
device.waitForFences(
51 std::numeric_limits<uint64_t>::max()
53 result != vk::Result::eSuccess) {
58 result != vk::Result::eSuccess) {
59 VALIDATION_LOG <<
"Could not reset fence: " << vk::to_string(result);
67 vk::SurfaceFormatKHR format) {
68 return std::find(formats.begin(), formats.end(),
format) != formats.end();
72 const std::vector<vk::SurfaceFormatKHR>& formats,
74 const auto colorspace = vk::ColorSpaceKHR::eSrgbNonlinear;
75 const auto vk_preference =
81 std::vector<vk::SurfaceFormatKHR> options = {
82 {vk::Format::eB8G8R8A8Unorm, colorspace},
83 {vk::Format::eR8G8B8A8Unorm, colorspace}};
84 for (
const auto&
format : options) {
94 vk::CompositeAlphaFlagsKHR flags) {
95 if (flags & vk::CompositeAlphaFlagBitsKHR::eInherit) {
96 return vk::CompositeAlphaFlagBitsKHR::eInherit;
98 if (flags & vk::CompositeAlphaFlagBitsKHR::ePreMultiplied) {
99 return vk::CompositeAlphaFlagBitsKHR::ePreMultiplied;
101 if (flags & vk::CompositeAlphaFlagBitsKHR::ePostMultiplied) {
102 return vk::CompositeAlphaFlagBitsKHR::ePostMultiplied;
104 if (flags & vk::CompositeAlphaFlagBitsKHR::eOpaque) {
105 return vk::CompositeAlphaFlagBitsKHR::eOpaque;
112 const std::shared_ptr<Context>& context,
113 vk::UniqueSurfaceKHR surface,
116 vk::SwapchainKHR old_swapchain) {
118 context, std::move(
surface), size, enable_msaa, old_swapchain));
121KHRSwapchainImplVK::KHRSwapchainImplVK(
const std::shared_ptr<Context>& context,
122 vk::UniqueSurfaceKHR surface,
125 vk::SwapchainKHR old_swapchain) {
133 const auto [caps_result, surface_caps] =
134 vk_context.GetPhysicalDevice().getSurfaceCapabilitiesKHR(*surface);
135 if (caps_result != vk::Result::eSuccess) {
137 << vk::to_string(caps_result);
141 auto [formats_result, formats] =
142 vk_context.GetPhysicalDevice().getSurfaceFormatsKHR(*surface);
143 if (formats_result != vk::Result::eSuccess) {
145 << vk::to_string(formats_result);
150 formats, vk_context.GetCapabilities()->GetDefaultColorFormat());
151 if (!
format.has_value()) {
157 const auto composite =
159 if (!composite.has_value()) {
164 vk::SwapchainCreateInfoKHR swapchain_info;
165 swapchain_info.surface = *
surface;
166 swapchain_info.imageFormat =
format.value().format;
167 swapchain_info.imageColorSpace =
format.value().colorSpace;
168 swapchain_info.presentMode = vk::PresentModeKHR::eFifo;
169 swapchain_info.imageExtent = vk::Extent2D{
170 std::clamp(
static_cast<uint32_t
>(
size.width),
171 surface_caps.minImageExtent.width,
172 surface_caps.maxImageExtent.width),
173 std::clamp(
static_cast<uint32_t
>(
size.height),
174 surface_caps.minImageExtent.height,
175 surface_caps.maxImageExtent.height),
177 swapchain_info.minImageCount =
178 std::clamp(surface_caps.minImageCount + 1u,
179 surface_caps.minImageCount,
180 surface_caps.maxImageCount == 0u
181 ? surface_caps.minImageCount + 1u
182 : surface_caps.maxImageCount
184 swapchain_info.imageArrayLayers = 1u;
187 swapchain_info.imageUsage = vk::ImageUsageFlagBits::eColorAttachment |
188 vk::ImageUsageFlagBits::eInputAttachment;
189 swapchain_info.preTransform = vk::SurfaceTransformFlagBitsKHR::eIdentity;
190 swapchain_info.compositeAlpha = composite.value();
194 swapchain_info.clipped =
true;
197 swapchain_info.imageSharingMode = vk::SharingMode::eExclusive;
198 swapchain_info.oldSwapchain = old_swapchain;
201 vk_context.GetDevice().createSwapchainKHRUnique(swapchain_info);
202 if (swapchain_result != vk::Result::eSuccess) {
204 << vk::to_string(swapchain_result);
208 auto [images_result,
images] =
209 vk_context.GetDevice().getSwapchainImagesKHR(*swapchain);
210 if (images_result != vk::Result::eSuccess) {
215 TextureDescriptor texture_desc;
218 texture_desc.format =
ToPixelFormat(swapchain_info.imageFormat);
219 texture_desc.size =
ISize::MakeWH(swapchain_info.imageExtent.width,
220 swapchain_info.imageExtent.height);
223 std::vector<vk::UniqueSemaphore> present_semaphores;
225 auto swapchain_image = std::make_shared<KHRSwapchainImageVK>(
227 vk_context.GetDevice(),
230 if (!swapchain_image->IsValid()) {
235 vk_context.GetDevice(), swapchain_image->GetImage(),
238 vk_context.GetDevice(), swapchain_image->GetImageView(),
243 auto present_res = vk_context.GetDevice().createSemaphoreUnique({});
244 if (present_res.result != vk::Result::eSuccess) {
248 present_semaphores.push_back(std::move(present_res.value));
251 std::vector<std::unique_ptr<KHRFrameSynchronizerVK>> synchronizers;
254 std::make_unique<KHRFrameSynchronizerVK>(vk_context.GetDevice());
255 if (!sync->is_valid) {
259 synchronizers.emplace_back(std::move(sync));
264 surface_ = std::move(surface);
265 surface_format_ = swapchain_info.imageFormat;
266 swapchain_ = std::move(swapchain);
267 transients_ = std::make_shared<SwapchainTransientsVK>(context, texture_desc,
270 synchronizers_ = std::move(synchronizers);
271 present_semaphores_ = std::move(present_semaphores);
272 current_frame_ = synchronizers_.size() - 1u;
274 enable_msaa_ = enable_msaa;
292 auto context = context_.lock();
298 const auto [result, surface_caps] =
299 vk_context.GetPhysicalDevice().getSurfaceCapabilitiesKHR(surface_.get());
300 if (result != vk::Result::eSuccess) {
308 constexpr uint32_t kCurrentExtentsPlaceholder = 0xFFFFFFFF;
309 if (surface_caps.currentExtent.width == kCurrentExtentsPlaceholder ||
310 surface_caps.currentExtent.height == kCurrentExtentsPlaceholder) {
315 surface_caps.currentExtent.height);
322void KHRSwapchainImplVK::WaitIdle()
const {
323 if (
auto context = context_.lock()) {
324 [[maybe_unused]]
auto result =
329std::pair<vk::UniqueSurfaceKHR, vk::UniqueSwapchainKHR>
333 synchronizers_.clear();
336 return {std::move(surface_), std::move(swapchain_)};
340 return surface_format_;
344 return context_.lock();
348 auto context_strong = context_.lock();
349 if (!context_strong) {
355 current_frame_ = (current_frame_ + 1u) % synchronizers_.size();
357 const auto& sync = synchronizers_[current_frame_];
362 if (!sync->WaitForFence(context.GetDevice())) {
374 auto [acq_result, index] = context.GetDevice().acquireNextImageKHR(
376 std::numeric_limits<uint64_t>::max(),
381 switch (acq_result) {
382 case vk::Result::eSuccess:
385 case vk::Result::eSuboptimalKHR:
386 case vk::Result::eErrorOutOfDateKHR:
393 << vk::to_string(acq_result);
397 if (index >= images_.size()) {
403 context.GetGPUTracer()->MarkFrameStart();
405 auto image = images_[index % images_.size()];
406 uint32_t image_index = index;
410 [weak_swapchain = weak_from_this(),
image, image_index]() ->
bool {
421 std::shared_ptr<CommandBuffer> cmd_buffer) {
422 const auto& sync = synchronizers_[current_frame_];
423 sync->final_cmd_buffer = std::move(cmd_buffer);
424 sync->has_onscreen =
true;
427bool KHRSwapchainImplVK::Present(
428 const std::shared_ptr<KHRSwapchainImageVK>&
image,
430 auto context_strong = context_.lock();
431 if (!context_strong) {
436 const auto& sync = synchronizers_[current_frame_];
437 context.GetGPUTracer()->MarkFrameEnd();
442 if (!sync->has_onscreen) {
443 sync->final_cmd_buffer = context.CreateCommandBuffer();
445 sync->has_onscreen =
false;
446 if (!sync->final_cmd_buffer) {
450 auto vk_final_cmd_buffer =
454 barrier.new_layout = vk::ImageLayout::ePresentSrcKHR;
455 barrier.cmd_buffer = vk_final_cmd_buffer;
456 barrier.src_access = vk::AccessFlagBits::eColorAttachmentWrite;
457 barrier.src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput;
458 barrier.dst_access = {};
459 barrier.dst_stage = vk::PipelineStageFlagBits::eBottomOfPipe;
461 if (!
image->SetLayout(barrier).ok()) {
465 if (vk_final_cmd_buffer.end() != vk::Result::eSuccess) {
474 vk::SubmitInfo submit_info;
475 vk::PipelineStageFlags wait_stage =
476 vk::PipelineStageFlagBits::eColorAttachmentOutput;
477 submit_info.setWaitDstStageMask(wait_stage);
478 submit_info.setWaitSemaphores(*sync->render_ready);
479 submit_info.setSignalSemaphores(*present_semaphores_[index]);
480 submit_info.setCommandBuffers(vk_final_cmd_buffer);
482 context.GetGraphicsQueue()->Submit(submit_info, *sync->acquire);
483 if (result != vk::Result::eSuccess) {
485 << vk::to_string(result);
493 uint32_t indices[] = {
static_cast<uint32_t
>(index)};
495 vk::PresentInfoKHR present_info;
496 present_info.setSwapchains(*swapchain_);
497 present_info.setImageIndices(indices);
498 present_info.setWaitSemaphores(*present_semaphores_[index]);
500 auto result = context.GetGraphicsQueue()->Present(present_info);
503 case vk::Result::eErrorOutOfDateKHR:
506 case vk::Result::eErrorSurfaceLostKHR:
510 case vk::Result::eSuboptimalKHR:
516 case vk::Result::eSuccess:
519 VALIDATION_LOG <<
"Could not present queue: " << vk::to_string(result);
static ContextVK & Cast(Context &base)
vk::CommandBuffer GetCommandBuffer() const
Retrieve the native command buffer from this object.
bool SetDebugName(T handle, std::string_view label) const
const vk::Device & GetDevice() const
An instance of a swapchain that does NOT adapt to going out of date with the underlying surface....
std::shared_ptr< Context > GetContext() const
void AddFinalCommandBuffer(std::shared_ptr< CommandBuffer > cmd_buffer)
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)
AcquireResult AcquireNextDrawable()
vk::Format GetSurfaceFormat() const
std::optional< ISize > GetCurrentUnderlyingSurfaceSize() const
std::pair< vk::UniqueSurfaceKHR, vk::UniqueSwapchainKHR > DestroySwapchain()
const ISize & GetSize() 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...
FlutterVulkanImage * image
std::vector< VkImage > swapchain_images
uint32_t uint32_t * format
#define FML_DCHECK(condition)
std::array< MockImage, 3 > images
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
static std::optional< vk::SurfaceFormatKHR > ChooseSurfaceFormat(const std::vector< vk::SurfaceFormatKHR > &formats, PixelFormat preference)
constexpr PixelFormat ToPixelFormat(vk::Format format)
static constexpr size_t kMaxFramesInFlight
static bool ContainsFormat(const std::vector< vk::SurfaceFormatKHR > &formats, vk::SurfaceFormatKHR format)
static std::optional< vk::CompositeAlphaFlagBitsKHR > ChooseAlphaCompositionMode(vk::CompositeAlphaFlagsKHR flags)
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
constexpr vk::Format ToVKImageFormat(PixelFormat format)
vk::UniqueSemaphore render_ready
bool WaitForFence(const vk::Device &device)
KHRFrameSynchronizerVK(const vk::Device &device)
~KHRFrameSynchronizerVK()=default
std::shared_ptr< CommandBuffer > final_cmd_buffer
static constexpr TSize MakeWH(Type width, Type height)