7#include "gfx_surface_vulkan.hpp"
8#include "gfx_surface_delegate_vulkan.hpp"
9#include "gfx_system_vulkan.hpp"
10#include "gfx_device_vulkan_impl.hpp"
11#include "gfx_pipeline_box_vulkan.hpp"
12#include "gfx_pipeline_image_vulkan.hpp"
13#include "gfx_pipeline_SDF_vulkan.hpp"
14#include "gfx_pipeline_alpha_vulkan.hpp"
15#include "gfx_pipeline_tone_mapper_vulkan.hpp"
16#include "../telemetry/telemetry.hpp"
17#include "../utility/utility.hpp"
18#include "../macros.hpp"
36 loss = gfx_surface_loss::device_lost;
42 _present_queue =
std::addressof(_device->get_present_queue(intrinsic));
43 _graphics_queue =
std::addressof(_device->get_graphics_queue(intrinsic));
48 hilet lock = std::scoped_lock(gfx_system_mutex);
50 hi_assert_not_null(delegate);
51 auto&
delegate_info = _delegates.emplace_back(delegate, _device->createSemaphore());
53 if (state >= gfx_surface_state::has_device) {
59 if (state >= gfx_surface_state::has_swapchain) {
62 for (hilet&
image_info : swapchain_image_infos) {
70inline void gfx_surface::remove_delegate(gfx_surface_delegate *delegate)
noexcept
72 hilet
lock = std::scoped_lock(gfx_system_mutex);
74 hi_assert_not_null(delegate);
75 auto it =
std::find_if(_delegates.begin(), _delegates.end(), [delegate](hilet& item) {
76 return item.delegate == delegate;
79 if (state >= gfx_surface_state::has_swapchain) {
80 it->delegate->teardown_for_swapchain_lost();
82 if (state >= gfx_surface_state::has_device) {
83 it->delegate->teardown_for_device_lost();
86 _device->destroy(
it->semaphore);
96inline void gfx_surface::wait_idle()
101 if (renderFinishedFence) {
105 hi_log_info(
"/waitIdle");
108inline std::optional<uint32_t> gfx_surface::acquire_next_image_from_swapchain()
116 hilet
result = _device->acquireNextImageKHR(swapchain, 0, imageAvailableSemaphore, vk::Fence(), &
frameBufferIndex);
120 case vk::Result::eSuccess:
123 case vk::Result::eSuboptimalKHR:
127 hi_log_info(
"acquireNextImageKHR() eSuboptimalKHR");
128 loss = gfx_surface_loss::swapchain_lost;
131 case vk::Result::eNotReady:
137 case vk::Result::eTimeout:
141 hi_log_info(
"acquireNextImageKHR() eTimeout");
144 case vk::Result::eErrorOutOfDateKHR:
145 hi_log_info(
"acquireNextImageKHR() eErrorOutOfDateKHR");
146 loss = gfx_surface_loss::swapchain_lost;
149 case vk::Result::eErrorSurfaceLostKHR:
150 hi_log_info(
"acquireNextImageKHR() eErrorSurfaceLostKHR");
151 loss = gfx_surface_loss::window_lost;
155 throw gui_error(std::format(
"Unknown result from acquireNextImageKHR(). '{}'",
to_string(
result)));
159inline void gfx_surface::present_image_to_queue(uint32_t
frameBufferIndex, vk::Semaphore semaphore)
163 hi_assert_not_null(_device);
172 hilet
result = _present_queue->queue.presentKHR(
180 case vk::Result::eSuccess:
183 case vk::Result::eSuboptimalKHR:
184 hi_log_info(
"presentKHR() eSuboptimalKHR");
185 loss = gfx_surface_loss::swapchain_lost;
189 throw gui_error(std::format(
"Unknown result from presentKHR(). '{}'",
to_string(
result)));
192 }
catch (vk::OutOfDateKHRError
const&) {
193 hi_log_info(
"presentKHR() eErrorOutOfDateKHR");
194 loss = gfx_surface_loss::swapchain_lost;
197 }
catch (vk::SurfaceLostKHRError
const&) {
198 hi_log_info(
"presentKHR() eErrorSurfaceLostKHR");
199 loss = gfx_surface_loss::window_lost;
206 if (_device->score(intrinsic) <= 0) {
207 return gfx_surface_loss::device_lost;
210 box_pipeline->build_for_new_device();
211 image_pipeline->build_for_new_device();
212 SDF_pipeline->build_for_new_device();
213 alpha_pipeline->build_for_new_device();
214 tone_mapper_pipeline->build_for_new_device();
217 for (
auto [delegate, semaphore] : _delegates) {
218 hi_assert_not_null(delegate);
220 delegate->build_for_new_device(
224 return gfx_surface_loss::none;
233 return gfx_surface_loss::swapchain_lost;
244 teardown_swapchain();
245 return gfx_surface_loss::swapchain_lost;
248 build_render_passes();
249 build_frame_buffers();
250 build_command_buffers();
252 hi_assert_not_null(box_pipeline);
253 hi_assert_not_null(image_pipeline);
254 hi_assert_not_null(SDF_pipeline);
255 hi_assert_not_null(alpha_pipeline);
256 hi_assert_not_null(tone_mapper_pipeline);
257 box_pipeline->build_for_new_swapchain(renderPass, 0, swapchainImageExtent);
258 image_pipeline->build_for_new_swapchain(renderPass, 1, swapchainImageExtent);
259 SDF_pipeline->build_for_new_swapchain(renderPass, 2, swapchainImageExtent);
260 alpha_pipeline->build_for_new_swapchain(renderPass, 3, swapchainImageExtent);
261 tone_mapper_pipeline->build_for_new_swapchain(renderPass, 4, swapchainImageExtent);
265 for (hilet&
image_info : swapchain_image_infos) {
269 for (
auto [delegate, semaphore] : _delegates) {
270 hi_assert_not_null(delegate);
271 delegate->build_for_new_swapchain(
image_views, swapchainImageExtent, swapchainImageFormat);
274 return gfx_surface_loss::none;
276 }
catch (vk::SurfaceLostKHRError
const&) {
279 return gfx_surface_loss::window_lost;
283inline void gfx_surface::build(extent2
new_size)
noexcept
286 hi_assert(loss == gfx_surface_loss::none);
288 if (state == gfx_surface_state::has_window) {
290 if (loss = build_for_new_device(); loss != gfx_surface_loss::none) {
293 state = gfx_surface_state::has_device;
297 if (state == gfx_surface_state::has_device) {
298 if (hilet
tmp = build_for_new_swapchain(
new_size);
tmp == gfx_surface_loss::swapchain_lost) {
302 }
else if (loss =
tmp;
tmp != gfx_surface_loss::none) {
306 state = gfx_surface_state::has_swapchain;
310inline void gfx_surface::teardown_for_swapchain_lost()
noexcept
312 hi_log_info(
"Tearing down because the window lost the swapchain.");
315 for (
auto [delegate, semaphore] : _delegates) {
316 hi_assert_not_null(delegate);
317 delegate->teardown_for_swapchain_lost();
320 tone_mapper_pipeline->teardown_for_swapchain_lost();
321 alpha_pipeline->teardown_for_swapchain_lost();
322 SDF_pipeline->teardown_for_swapchain_lost();
323 image_pipeline->teardown_for_swapchain_lost();
324 box_pipeline->teardown_for_swapchain_lost();
325 teardown_semaphores();
326 teardown_command_buffers();
327 teardown_frame_buffers();
328 teardown_render_passes();
329 teardown_swapchain();
332inline void gfx_surface::teardown_for_device_lost()
noexcept
334 hi_log_info(
"Tearing down because the window lost the vulkan device.");
335 for (
auto [delegate, semaphore] : _delegates) {
336 hi_assert_not_null(delegate);
337 delegate->teardown_for_device_lost();
339 tone_mapper_pipeline->teardown_for_device_lost();
340 alpha_pipeline->teardown_for_device_lost();
341 SDF_pipeline->teardown_for_device_lost();
342 image_pipeline->teardown_for_device_lost();
343 box_pipeline->teardown_for_device_lost();
347inline void gfx_surface::teardown_for_window_lost()
noexcept
349 gfx_system::global().destroySurfaceKHR(intrinsic);
352inline void gfx_surface::teardown()
noexcept
356 if (state == gfx_surface_state::has_swapchain
and loss >= gfx_surface_loss::swapchain_lost) {
357 teardown_for_swapchain_lost();
358 state = gfx_surface_state::has_device;
361 if (state == gfx_surface_state::has_device
and loss >= gfx_surface_loss::device_lost) {
362 teardown_for_device_lost();
363 state = gfx_surface_state::has_window;
366 if (state == gfx_surface_state::has_window
and loss >= gfx_surface_loss::window_lost) {
367 hi_log_info(
"Tearing down because the window doesn't exist anymore.");
368 teardown_for_window_lost();
369 state = gfx_surface_state::no_window;
371 loss = gfx_surface_loss::none;
374inline void gfx_surface::update(extent2
new_size)
noexcept
376 hilet
lock = std::scoped_lock(gfx_system_mutex);
378 if (size() !=
new_size and state == gfx_surface_state::has_swapchain) {
380 loss = gfx_surface_loss::swapchain_lost;
388inline draw_context gfx_surface::render_start(aarectangle redraw_rectangle)
391 redraw_rectangle =
ceil(redraw_rectangle, _render_area_granularity);
393 hilet
lock = std::scoped_lock(gfx_system_mutex);
395 auto r = draw_context{
397 box_pipeline->vertexBufferData,
398 image_pipeline->vertexBufferData,
399 SDF_pipeline->vertexBufferData,
400 alpha_pipeline->vertexBufferData};
403 if (state != gfx_surface_state::has_swapchain
or not redraw_rectangle) {
418 auto&
current_image = swapchain_image_infos.at(r.frame_buffer_index);
423 r.scissor_rectangle =
424 std::accumulate(swapchain_image_infos.cbegin(), swapchain_image_infos.cend(), aarectangle{}, [](hilet&
sum, hilet& item) {
425 return sum | item.redraw_rectangle;
432 _device->resetFences({renderFinishedFence});
437inline void gfx_surface::render_finish(draw_context
const&
context)
439 hilet
lock = std::scoped_lock(gfx_system_mutex);
447 _device->transition_layout(
448 current_image.image, swapchainImageFormat.format, vk::ImageLayout::eUndefined, vk::ImageLayout::ePresentSrcKHR);
456 aarectangle{0, 0, narrow_cast<float>(swapchainImageExtent.width), narrow_cast<float>(swapchainImageExtent.height)});
469 hi_assert_not_null(delegate);
489inline void gfx_surface::fill_command_buffer(
496 auto t = trace<
"fill_command_buffer">{};
498 commandBuffer.reset(vk::CommandBufferResetFlagBits::eReleaseResources);
499 commandBuffer.begin({vk::CommandBufferUsageFlagBits::eSimultaneousUse});
515 commandBuffer.setScissor(0,
scissors);
517 commandBuffer.beginRenderPass(
519 vk::SubpassContents::eInline);
521 box_pipeline->draw_in_command_buffer(commandBuffer,
context);
522 commandBuffer.nextSubpass(vk::SubpassContents::eInline);
523 image_pipeline->draw_in_command_buffer(commandBuffer,
context);
524 commandBuffer.nextSubpass(vk::SubpassContents::eInline);
525 SDF_pipeline->draw_in_command_buffer(commandBuffer,
context);
526 commandBuffer.nextSubpass(vk::SubpassContents::eInline);
527 alpha_pipeline->draw_in_command_buffer(commandBuffer,
context);
528 commandBuffer.nextSubpass(vk::SubpassContents::eInline);
529 tone_mapper_pipeline->draw_in_command_buffer(commandBuffer,
context);
531 commandBuffer.endRenderPass();
541 hilet
waitStages =
std::array{vk::PipelineStageFlags{vk::PipelineStageFlagBits::eColorAttachmentOutput}};
557 _graphics_queue->queue.submit(
submitInfo, vk::Fence());
576 hilet max_size = extent2{
589 hi_log_info(
"Building swap chain");
591 hilet
sharingMode = _graphics_queue == _present_queue ? vk::SharingMode::eExclusive : vk::SharingMode::eConcurrent;
594 _graphics_queue->family_queue_index, _present_queue->family_queue_index};
596 swapchainImageFormat = _device->get_surface_format(intrinsic);
600 vk::SwapchainCreateFlagsKHR(),
603 swapchainImageFormat.format,
604 swapchainImageFormat.colorSpace,
605 swapchainImageExtent,
607 vk::ImageUsageFlagBits::eColorAttachment,
613 _device->get_present_mode(intrinsic),
619 case vk::Result::eSuccess:
622 case vk::Result::eErrorSurfaceLostKHR:
623 return gfx_surface_loss::window_lost;
626 throw gui_error(std::format(
"Unknown result from createSwapchainKHR(). '{}'",
to_string(
result)));
629 hi_log_info(
"Finished building swap chain");
632 " - colorSpace={}, format={}",
640 vk::ImageCreateFlags(),
646 vk::SampleCountFlagBits::e1,
647 vk::ImageTiling::eOptimal,
648 vk::ImageUsageFlagBits::eDepthStencilAttachment | _device->transientImageUsageFlags,
649 vk::SharingMode::eExclusive,
652 vk::ImageLayout::eUndefined};
659 _device->setDebugUtilsObjectNameEXT(depthImage,
"vk::Image depth attachment");
663 vk::ImageCreateFlags(),
669 vk::SampleCountFlagBits::e1,
670 vk::ImageTiling::eOptimal,
671 vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eInputAttachment | _device->transientImageUsageFlags,
672 vk::SharingMode::eExclusive,
675 vk::ImageLayout::eUndefined};
683 _device->setDebugUtilsObjectNameEXT(colorImages[0],
"vk::Image color attachment");
685 return gfx_surface_loss::none;
688inline void gfx_surface::teardown_swapchain()
692 _device->destroy(swapchain);
693 _device->destroyImage(depthImage, depthImageAllocation);
695 for (
std::size_t i = 0; i != colorImages.size(); ++i) {
696 _device->destroyImage(colorImages[i], colorImageAllocations[i]);
700inline void gfx_surface::build_frame_buffers()
704 depthImageView = _device->createImageView(
705 {vk::ImageViewCreateFlags(),
707 vk::ImageViewType::e2D,
709 vk::ComponentMapping(),
710 {vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}});
712 for (
std::size_t i = 0; i != colorImageViews.size(); ++i) {
713 colorImageViews[i] = _device->createImageView(
714 {vk::ImageViewCreateFlags(),
716 vk::ImageViewType::e2D,
718 vk::ComponentMapping(),
719 {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}});
721 colorDescriptorImageInfos[i] = {vk::Sampler(), colorImageViews[i], vk::ImageLayout::eShaderReadOnlyOptimal};
726 auto image_view = _device->createImageView(
727 {vk::ImageViewCreateFlags(),
729 vk::ImageViewType::e2D,
730 swapchainImageFormat.format,
731 vk::ComponentMapping(),
732 {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}});
736 hilet frame_buffer = _device->createFramebuffer({
737 vk::FramebufferCreateFlags(),
741 swapchainImageExtent.width,
742 swapchainImageExtent.height,
746 swapchain_image_infos.emplace_back(
753inline void gfx_surface::teardown_frame_buffers()
757 for (
auto&
info : swapchain_image_infos) {
758 _device->destroy(
info.frame_buffer);
759 _device->destroy(
info.image_view);
761 swapchain_image_infos.clear();
763 _device->destroy(depthImageView);
764 for (
std::size_t i = 0; i != colorImageViews.size(); ++i) {
765 _device->destroy(colorImageViews[i]);
781inline void gfx_surface::build_render_passes()
786 vk::AttachmentDescription{
788 vk::AttachmentDescriptionFlags(),
790 vk::SampleCountFlagBits::e1,
791 vk::AttachmentLoadOp::eClear,
792 vk::AttachmentStoreOp::eDontCare,
793 vk::AttachmentLoadOp::eDontCare,
794 vk::AttachmentStoreOp::eDontCare,
795 vk::ImageLayout::eUndefined,
796 vk::ImageLayout::eDepthStencilAttachmentOptimal
798 vk::AttachmentDescription{
800 vk::AttachmentDescriptionFlags(),
802 vk::SampleCountFlagBits::e1,
803 vk::AttachmentLoadOp::eClear,
804 vk::AttachmentStoreOp::eDontCare,
805 vk::AttachmentLoadOp::eDontCare,
806 vk::AttachmentStoreOp::eDontCare,
807 vk::ImageLayout::eUndefined,
808 vk::ImageLayout::eColorAttachmentOptimal
810 vk::AttachmentDescription{
812 vk::AttachmentDescriptionFlags(),
813 swapchainImageFormat.format,
814 vk::SampleCountFlagBits::e1,
815 vk::AttachmentLoadOp::eLoad,
816 vk::AttachmentStoreOp::eStore,
817 vk::AttachmentLoadOp::eDontCare,
818 vk::AttachmentStoreOp::eDontCare,
819 vk::ImageLayout::ePresentSrcKHR,
820 vk::ImageLayout::ePresentSrcKHR
829 vk::SubpassDescription{
830 vk::SubpassDescriptionFlags(),
831 vk::PipelineBindPoint::eGraphics,
840 vk::SubpassDescription{
841 vk::SubpassDescriptionFlags(),
842 vk::PipelineBindPoint::eGraphics,
851 vk::SubpassDescription{
852 vk::SubpassDescriptionFlags(),
853 vk::PipelineBindPoint::eGraphics,
862 vk::SubpassDescription{
863 vk::SubpassDescriptionFlags(),
864 vk::PipelineBindPoint::eGraphics,
873 vk::SubpassDescription{
874 vk::SubpassDescriptionFlags(),
875 vk::PipelineBindPoint::eGraphics,
884 vk::SubpassDependency{
887 vk::PipelineStageFlagBits::eBottomOfPipe,
888 vk::PipelineStageFlagBits::eColorAttachmentOutput,
889 vk::AccessFlagBits::eMemoryRead,
890 vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite,
891 vk::DependencyFlagBits::eByRegion},
893 vk::SubpassDependency{
896 vk::PipelineStageFlagBits::eColorAttachmentOutput,
897 vk::PipelineStageFlagBits::eColorAttachmentOutput,
898 vk::AccessFlagBits::eColorAttachmentWrite,
899 vk::AccessFlagBits::eColorAttachmentRead,
900 vk::DependencyFlagBits::eByRegion},
902 vk::SubpassDependency{
905 vk::PipelineStageFlagBits::eColorAttachmentOutput,
906 vk::PipelineStageFlagBits::eColorAttachmentOutput,
907 vk::AccessFlagBits::eColorAttachmentWrite,
908 vk::AccessFlagBits::eColorAttachmentRead,
909 vk::DependencyFlagBits::eByRegion},
911 vk::SubpassDependency{
914 vk::PipelineStageFlagBits::eColorAttachmentOutput,
915 vk::PipelineStageFlagBits::eFragmentShader,
916 vk::AccessFlagBits::eColorAttachmentWrite,
917 vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eInputAttachmentRead,
918 vk::DependencyFlagBits::eByRegion},
920 vk::SubpassDependency{
923 vk::PipelineStageFlagBits::eColorAttachmentOutput,
924 vk::PipelineStageFlagBits::eFragmentShader,
925 vk::AccessFlagBits::eColorAttachmentWrite,
926 vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eInputAttachmentRead,
927 vk::DependencyFlagBits::eByRegion},
929 vk::SubpassDependency{
932 vk::PipelineStageFlagBits::eColorAttachmentOutput,
933 vk::PipelineStageFlagBits::eBottomOfPipe,
934 vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite,
935 vk::AccessFlagBits::eMemoryRead,
936 vk::DependencyFlagBits::eByRegion}};
939 vk::RenderPassCreateFlags(),
949 hilet
granularity = _device->getRenderAreaGranularity(renderPass);
953inline void gfx_surface::teardown_render_passes()
957 _device->destroy(renderPass);
960inline void gfx_surface::build_semaphores()
964 imageAvailableSemaphore = _device->createSemaphore();
965 renderFinishedSemaphore = _device->createSemaphore();
970 renderFinishedFence = _device->createFence({vk::FenceCreateFlagBits::eSignaled});
973inline void gfx_surface::teardown_semaphores()
977 _device->destroy(renderFinishedSemaphore);
978 _device->destroy(imageAvailableSemaphore);
979 _device->destroy(renderFinishedFence);
982inline void gfx_surface::build_command_buffers()
986 hilet
commandBuffers = _device->allocateCommandBuffers({_graphics_queue->command_pool, vk::CommandBufferLevel::ePrimary, 1});
991inline void gfx_surface::teardown_command_buffers()
996 _device->freeCommandBuffers(_graphics_queue->command_pool,
commandBuffers);
1001 hilet
lock = std::scoped_lock(gfx_system_mutex);
1012 auto device = find_best_device_for_surface(surface->intrinsic);
1014 throw gfx_error(
"Could not find a vulkan-device matching this surface");
1016 surface->set_device(device);
DOXYGEN BUG.
Definition algorithm.hpp:16
unfair_recursive_mutex gfx_system_mutex
Global mutex for GUI elements, like gfx_system, gfx_device, Windows and Widgets.
Definition gfx_system_globals.hpp:18
gfx_surface_loss
Definition gfx_surface_state.hpp:20
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
Definition gfx_device_vulkan.hpp:24
A delegate for drawing on a window below the HikoGUI user interface.
Definition gfx_surface_delegate_vulkan.hpp:23