7 #include "fml/synchronization/semaphore.h"
30 auto acquire_res = device.createFenceUnique(
31 vk::FenceCreateInfo{vk::FenceCreateFlagBits::eSignaled});
32 auto render_res = device.createSemaphoreUnique({});
33 auto present_res = device.createSemaphoreUnique({});
34 if (acquire_res.result != vk::Result::eSuccess ||
35 render_res.result != vk::Result::eSuccess ||
36 present_res.result != vk::Result::eSuccess) {
40 acquire = std::move(acquire_res.value);
49 if (
auto result = device.waitForFences(
52 std::numeric_limits<uint64_t>::max()
54 result != vk::Result::eSuccess) {
58 if (
auto result = device.resetFences(*
acquire);
59 result != vk::Result::eSuccess) {
60 VALIDATION_LOG <<
"Could not reset fence: " << vk::to_string(result);
68 vk::SurfaceFormatKHR format) {
69 return std::find(formats.begin(), formats.end(), format) != formats.end();
73 const std::vector<vk::SurfaceFormatKHR>& formats,
75 const auto colorspace = vk::ColorSpaceKHR::eSrgbNonlinear;
76 const auto vk_preference =
82 std::vector<vk::SurfaceFormatKHR> options = {
83 {vk::Format::eB8G8R8A8Unorm, colorspace},
84 {vk::Format::eR8G8B8A8Unorm, colorspace}};
85 for (
const auto& format : options) {
95 vk::CompositeAlphaFlagsKHR flags) {
96 if (flags & vk::CompositeAlphaFlagBitsKHR::eInherit) {
97 return vk::CompositeAlphaFlagBitsKHR::eInherit;
99 if (flags & vk::CompositeAlphaFlagBitsKHR::ePreMultiplied) {
100 return vk::CompositeAlphaFlagBitsKHR::ePreMultiplied;
102 if (flags & vk::CompositeAlphaFlagBitsKHR::ePostMultiplied) {
103 return vk::CompositeAlphaFlagBitsKHR::ePostMultiplied;
105 if (flags & vk::CompositeAlphaFlagBitsKHR::eOpaque) {
106 return vk::CompositeAlphaFlagBitsKHR::eOpaque;
113 const std::shared_ptr<Context>& context,
114 vk::UniqueSurfaceKHR surface,
117 vk::SwapchainKHR old_swapchain) {
119 context, std::move(surface), size, enable_msaa, old_swapchain));
122 KHRSwapchainImplVK::KHRSwapchainImplVK(
const std::shared_ptr<Context>& context,
123 vk::UniqueSurfaceKHR surface,
126 vk::SwapchainKHR old_swapchain) {
134 const auto [caps_result, surface_caps] =
135 vk_context.GetPhysicalDevice().getSurfaceCapabilitiesKHR(*surface);
136 if (caps_result != vk::Result::eSuccess) {
138 << vk::to_string(caps_result);
142 auto [formats_result, formats] =
143 vk_context.GetPhysicalDevice().getSurfaceFormatsKHR(*surface);
144 if (formats_result != vk::Result::eSuccess) {
146 << vk::to_string(formats_result);
151 formats, vk_context.GetCapabilities()->GetDefaultColorFormat());
152 if (!format.has_value()) {
156 vk_context.SetOffscreenFormat(
ToPixelFormat(format.value().format));
158 const auto composite =
160 if (!composite.has_value()) {
165 vk::SwapchainCreateInfoKHR swapchain_info;
166 swapchain_info.surface = *surface;
167 swapchain_info.imageFormat = format.value().format;
168 swapchain_info.imageColorSpace = format.value().colorSpace;
169 swapchain_info.presentMode = vk::PresentModeKHR::eFifo;
170 swapchain_info.imageExtent = vk::Extent2D{
171 std::clamp(
static_cast<uint32_t
>(size.
width),
172 surface_caps.minImageExtent.width,
173 surface_caps.maxImageExtent.width),
174 std::clamp(
static_cast<uint32_t
>(size.
height),
175 surface_caps.minImageExtent.height,
176 surface_caps.maxImageExtent.height),
178 swapchain_info.minImageCount =
179 std::clamp(surface_caps.minImageCount + 1u,
180 surface_caps.minImageCount,
181 surface_caps.maxImageCount == 0u
182 ? surface_caps.minImageCount + 1u
183 : surface_caps.maxImageCount
185 swapchain_info.imageArrayLayers = 1u;
188 swapchain_info.imageUsage = vk::ImageUsageFlagBits::eColorAttachment |
189 vk::ImageUsageFlagBits::eTransferDst |
190 vk::ImageUsageFlagBits::eInputAttachment;
191 swapchain_info.preTransform = vk::SurfaceTransformFlagBitsKHR::eIdentity;
192 swapchain_info.compositeAlpha = composite.value();
196 swapchain_info.clipped =
true;
199 swapchain_info.imageSharingMode = vk::SharingMode::eExclusive;
200 swapchain_info.oldSwapchain = old_swapchain;
202 auto [swapchain_result, swapchain] =
203 vk_context.GetDevice().createSwapchainKHRUnique(swapchain_info);
204 if (swapchain_result != vk::Result::eSuccess) {
206 << vk::to_string(swapchain_result);
210 auto [images_result, images] =
211 vk_context.GetDevice().getSwapchainImagesKHR(*swapchain);
212 if (images_result != vk::Result::eSuccess) {
217 TextureDescriptor texture_desc;
220 texture_desc.format =
ToPixelFormat(swapchain_info.imageFormat);
221 texture_desc.size =
ISize::MakeWH(swapchain_info.imageExtent.width,
222 swapchain_info.imageExtent.height);
224 std::vector<std::shared_ptr<KHRSwapchainImageVK>> swapchain_images;
225 for (
const auto& image : images) {
226 auto swapchain_image = std::make_shared<KHRSwapchainImageVK>(
228 vk_context.GetDevice(),
231 if (!swapchain_image->IsValid()) {
236 vk_context.GetDevice(), swapchain_image->GetImage(),
237 "SwapchainImage" + std::to_string(swapchain_images.size()));
239 vk_context.GetDevice(), swapchain_image->GetImageView(),
240 "SwapchainImageView" + std::to_string(swapchain_images.size()));
242 swapchain_images.emplace_back(swapchain_image);
245 std::vector<std::unique_ptr<KHRFrameSynchronizerVK>> synchronizers;
248 std::make_unique<KHRFrameSynchronizerVK>(vk_context.GetDevice());
249 if (!sync->is_valid) {
253 synchronizers.emplace_back(std::move(sync));
255 FML_DCHECK(!synchronizers.empty());
258 surface_ = std::move(surface);
259 surface_format_ = swapchain_info.imageFormat;
260 swapchain_ = std::move(swapchain);
261 transients_ = std::make_shared<SwapchainTransientsVK>(context, texture_desc,
263 images_ = std::move(swapchain_images);
264 synchronizers_ = std::move(synchronizers);
265 current_frame_ = synchronizers_.size() - 1u;
267 enable_msaa_ = enable_msaa;
283 void KHRSwapchainImplVK::WaitIdle()
const {
284 if (
auto context = context_.lock()) {
285 [[maybe_unused]]
auto result =
290 std::pair<vk::UniqueSurfaceKHR, vk::UniqueSwapchainKHR>
294 synchronizers_.clear();
297 return {std::move(surface_), std::move(swapchain_)};
301 return surface_format_;
305 return context_.lock();
309 auto context_strong = context_.lock();
310 if (!context_strong) {
316 current_frame_ = (current_frame_ + 1u) % synchronizers_.size();
318 const auto& sync = synchronizers_[current_frame_];
323 if (!sync->WaitForFence(context.GetDevice())) {
335 auto [acq_result, index] = context.GetDevice().acquireNextImageKHR(
337 std::numeric_limits<uint64_t>::max(),
342 switch (acq_result) {
343 case vk::Result::eSuccess:
346 case vk::Result::eSuboptimalKHR:
347 case vk::Result::eErrorOutOfDateKHR:
354 << vk::to_string(acq_result);
358 if (index >= images_.size()) {
364 context.GetGPUTracer()->MarkFrameStart();
366 auto image = images_[index % images_.size()];
367 uint32_t image_index = index;
371 [weak_swapchain = weak_from_this(), image, image_index]() ->
bool {
372 auto swapchain = weak_swapchain.lock();
376 return swapchain->Present(image, image_index);
381 bool KHRSwapchainImplVK::Present(
382 const std::shared_ptr<KHRSwapchainImageVK>& image,
384 auto context_strong = context_.lock();
385 if (!context_strong) {
390 const auto& sync = synchronizers_[current_frame_];
391 context.GetGPUTracer()->MarkFrameEnd();
396 sync->final_cmd_buffer = context.CreateCommandBuffer();
397 if (!sync->final_cmd_buffer) {
401 auto vk_final_cmd_buffer =
405 barrier.new_layout = vk::ImageLayout::ePresentSrcKHR;
406 barrier.cmd_buffer = vk_final_cmd_buffer;
407 barrier.src_access = vk::AccessFlagBits::eColorAttachmentWrite;
408 barrier.src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput;
409 barrier.dst_access = {};
410 barrier.dst_stage = vk::PipelineStageFlagBits::eBottomOfPipe;
412 if (!image->SetLayout(barrier).ok()) {
416 if (vk_final_cmd_buffer.end() != vk::Result::eSuccess) {
425 vk::SubmitInfo submit_info;
426 vk::PipelineStageFlags wait_stage =
427 vk::PipelineStageFlagBits::eColorAttachmentOutput;
428 submit_info.setWaitDstStageMask(wait_stage);
429 submit_info.setWaitSemaphores(*sync->render_ready);
430 submit_info.setSignalSemaphores(*sync->present_ready);
431 submit_info.setCommandBuffers(vk_final_cmd_buffer);
433 context.GetGraphicsQueue()->Submit(submit_info, *sync->acquire);
434 if (result != vk::Result::eSuccess) {
436 << vk::to_string(result);
444 uint32_t indices[] = {
static_cast<uint32_t
>(index)};
446 vk::PresentInfoKHR present_info;
447 present_info.setSwapchains(*swapchain_);
448 present_info.setImageIndices(indices);
449 present_info.setWaitSemaphores(*sync->present_ready);
451 auto result = context.GetGraphicsQueue()->Present(present_info);
454 case vk::Result::eErrorOutOfDateKHR:
457 case vk::Result::eErrorSurfaceLostKHR:
461 case vk::Result::eSuboptimalKHR:
467 case vk::Result::eSuccess:
470 VALIDATION_LOG <<
"Could not present queue: " << vk::to_string(result);