33 auto acquire_res =
device.createFenceUnique({});
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);
51 if (
auto result =
device.waitForFences(
54 std::numeric_limits<uint64_t>::max()
56 result != vk::Result::eSuccess) {
62 result != vk::Result::eSuccess) {
63 VALIDATION_LOG <<
"Could not reset fence: " << vk::to_string(result);
71 vk::SurfaceFormatKHR format) {
72 return std::find(formats.begin(), formats.end(),
format) != formats.end();
76 const std::vector<vk::SurfaceFormatKHR>& formats,
78 const auto colorspace = vk::ColorSpaceKHR::eSrgbNonlinear;
79 const auto vk_preference =
85 std::vector<vk::SurfaceFormatKHR> options = {
86 {vk::Format::eB8G8R8A8Unorm, colorspace},
87 {vk::Format::eR8G8B8A8Unorm, colorspace}};
88 for (
const auto&
format : options) {
98 vk::CompositeAlphaFlagsKHR flags) {
99 if (flags & vk::CompositeAlphaFlagBitsKHR::eInherit) {
100 return vk::CompositeAlphaFlagBitsKHR::eInherit;
102 if (flags & vk::CompositeAlphaFlagBitsKHR::ePreMultiplied) {
103 return vk::CompositeAlphaFlagBitsKHR::ePreMultiplied;
105 if (flags & vk::CompositeAlphaFlagBitsKHR::ePostMultiplied) {
106 return vk::CompositeAlphaFlagBitsKHR::ePostMultiplied;
108 if (flags & vk::CompositeAlphaFlagBitsKHR::eOpaque) {
109 return vk::CompositeAlphaFlagBitsKHR::eOpaque;
116 const std::shared_ptr<Context>& context,
117 vk::UniqueSurfaceKHR surface,
120 vk::SwapchainKHR old_swapchain) {
122 context, std::move(
surface), size, enable_msaa, old_swapchain));
125KHRSwapchainImplVK::KHRSwapchainImplVK(
const std::shared_ptr<Context>& context,
126 vk::UniqueSurfaceKHR surface,
129 vk::SwapchainKHR old_swapchain) {
137 const auto [caps_result, surface_caps] =
138 vk_context.GetPhysicalDevice().getSurfaceCapabilitiesKHR(*surface);
139 if (caps_result != vk::Result::eSuccess) {
141 << vk::to_string(caps_result);
145 auto [formats_result, formats] =
146 vk_context.GetPhysicalDevice().getSurfaceFormatsKHR(*surface);
147 if (formats_result != vk::Result::eSuccess) {
149 << vk::to_string(formats_result);
154 formats, vk_context.GetCapabilities()->GetDefaultColorFormat());
155 if (!
format.has_value()) {
161 const auto composite =
163 if (!composite.has_value()) {
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),
181 swapchain_info.minImageCount =
182 std::clamp(surface_caps.minImageCount + 1u,
183 surface_caps.minImageCount,
184 surface_caps.maxImageCount == 0u
185 ? surface_caps.minImageCount + 1u
186 : surface_caps.maxImageCount
188 swapchain_info.imageArrayLayers = 1u;
191 swapchain_info.imageUsage = vk::ImageUsageFlagBits::eColorAttachment |
192 vk::ImageUsageFlagBits::eInputAttachment;
193 swapchain_info.preTransform = vk::SurfaceTransformFlagBitsKHR::eIdentity;
194 swapchain_info.compositeAlpha = composite.value();
198 swapchain_info.clipped =
true;
201 swapchain_info.imageSharingMode = vk::SharingMode::eExclusive;
202 swapchain_info.oldSwapchain = old_swapchain;
205 vk_context.GetDevice().createSwapchainKHRUnique(swapchain_info);
206 if (swapchain_result != vk::Result::eSuccess) {
208 << vk::to_string(swapchain_result);
212 auto [images_result,
images] =
213 vk_context.GetDevice().getSwapchainImagesKHR(*swapchain);
214 if (images_result != vk::Result::eSuccess) {
219 TextureDescriptor texture_desc;
222 texture_desc.format =
ToPixelFormat(swapchain_info.imageFormat);
223 texture_desc.size =
ISize::MakeWH(swapchain_info.imageExtent.width,
224 swapchain_info.imageExtent.height);
227 std::vector<vk::UniqueSemaphore> present_semaphores;
229 auto swapchain_image = std::make_shared<KHRSwapchainImageVK>(
231 vk_context.GetDevice(),
234 if (!swapchain_image->IsValid()) {
239 vk_context.GetDevice(), swapchain_image->GetImage(),
242 vk_context.GetDevice(), swapchain_image->GetImageView(),
247 auto present_res = vk_context.GetDevice().createSemaphoreUnique({});
248 if (present_res.result != vk::Result::eSuccess) {
252 present_semaphores.push_back(std::move(present_res.value));
255 std::vector<std::unique_ptr<KHRFrameSynchronizerVK>> synchronizers;
258 std::make_unique<KHRFrameSynchronizerVK>(vk_context.GetDevice());
259 if (!sync->is_valid) {
263 synchronizers.emplace_back(std::move(sync));
268 surface_ = std::move(surface);
269 surface_format_ = swapchain_info.imageFormat;
270 swapchain_ = std::move(swapchain);
271 transients_ = std::make_shared<SwapchainTransientsVK>(context, texture_desc,
274 synchronizers_ = std::move(synchronizers);
275 present_semaphores_ = std::move(present_semaphores);
276 current_frame_ = synchronizers_.size() - 1u;
278 enable_msaa_ = enable_msaa;
296 auto context = context_.lock();
302 const auto [result, surface_caps] =
303 vk_context.GetPhysicalDevice().getSurfaceCapabilitiesKHR(surface_.get());
304 if (result != vk::Result::eSuccess) {
312 constexpr uint32_t kCurrentExtentsPlaceholder = 0xFFFFFFFF;
313 if (surface_caps.currentExtent.width == kCurrentExtentsPlaceholder ||
314 surface_caps.currentExtent.height == kCurrentExtentsPlaceholder) {
319 surface_caps.currentExtent.height);
326void KHRSwapchainImplVK::WaitIdle()
const {
327 if (
auto context = context_.lock()) {
328 [[maybe_unused]]
auto result =
333std::pair<vk::UniqueSurfaceKHR, vk::UniqueSwapchainKHR>
337 synchronizers_.clear();
340 return {std::move(surface_), std::move(swapchain_)};
344 return surface_format_;
348 return context_.lock();
352 auto context_strong = context_.lock();
353 if (!context_strong) {
359 current_frame_ = (current_frame_ + 1u) % synchronizers_.size();
361 const auto& sync = synchronizers_[current_frame_];
366 if (!sync->WaitForFence(context.GetDevice())) {
378 auto [acq_result, index] = context.GetDevice().acquireNextImageKHR(
380 std::numeric_limits<uint64_t>::max(),
385 switch (acq_result) {
386 case vk::Result::eSuccess:
389 case vk::Result::eSuboptimalKHR:
390 case vk::Result::eErrorOutOfDateKHR:
394 case vk::Result::eErrorSurfaceLostKHR:
401 << vk::to_string(acq_result);
405 if (index >= images_.size()) {
411 context.GetGPUTracer()->MarkFrameStart();
413 auto image = images_[index % images_.size()];
414 uint32_t image_index = index;
418 [weak_swapchain = weak_from_this(),
image, image_index]() ->
bool {
429 std::shared_ptr<CommandBuffer> cmd_buffer) {
430 const auto& sync = synchronizers_[current_frame_];
431 sync->final_cmd_buffer = std::move(cmd_buffer);
432 sync->has_onscreen =
true;
435bool KHRSwapchainImplVK::Present(
436 const std::shared_ptr<KHRSwapchainImageVK>&
image,
438 auto context_strong = context_.lock();
439 if (!context_strong) {
444 const auto& sync = synchronizers_[current_frame_];
445 context.GetGPUTracer()->MarkFrameEnd();
450 if (!sync->has_onscreen) {
451 sync->final_cmd_buffer = context.CreateCommandBuffer();
453 sync->has_onscreen =
false;
454 if (!sync->final_cmd_buffer) {
458 auto vk_final_cmd_buffer =
462 barrier.new_layout = vk::ImageLayout::ePresentSrcKHR;
463 barrier.cmd_buffer = vk_final_cmd_buffer;
464 barrier.src_access = vk::AccessFlagBits::eColorAttachmentWrite;
465 barrier.src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput;
466 barrier.dst_access = {};
467 barrier.dst_stage = vk::PipelineStageFlagBits::eBottomOfPipe;
469 if (!
image->SetLayout(barrier).ok()) {
473 if (vk_final_cmd_buffer.end() != vk::Result::eSuccess) {
482 vk::SubmitInfo submit_info;
483 vk::PipelineStageFlags wait_stage =
484 vk::PipelineStageFlagBits::eColorAttachmentOutput;
485 submit_info.setWaitDstStageMask(wait_stage);
486 submit_info.setWaitSemaphores(*sync->render_ready);
487 submit_info.setSignalSemaphores(*present_semaphores_[index]);
488 submit_info.setCommandBuffers(vk_final_cmd_buffer);
490 context.GetGraphicsQueue()->Submit(submit_info, *sync->acquire);
491 if (result != vk::Result::eSuccess) {
493 << vk::to_string(result);
496 sync->acquire_fence_pending =
true;
502 uint32_t indices[] = {
static_cast<uint32_t
>(index)};
504 vk::PresentInfoKHR present_info;
505 present_info.setSwapchains(*swapchain_);
506 present_info.setImageIndices(indices);
507 present_info.setWaitSemaphores(*present_semaphores_[index]);
509 auto result = context.GetGraphicsQueue()->Present(present_info);
512 case vk::Result::eErrorOutOfDateKHR:
515 case vk::Result::eErrorSurfaceLostKHR:
519 case vk::Result::eSuboptimalKHR:
525 case vk::Result::eSuccess:
528 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)
bool acquire_fence_pending
~KHRFrameSynchronizerVK()=default
std::shared_ptr< CommandBuffer > final_cmd_buffer
static constexpr TSize MakeWH(Type width, Type height)