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"
21namespace hi::inline
v1 {
25 hi_assert_not_null(new_device);
31 if (_device == new_device) {
42 _present_queue =
std::addressof(_device->get_present_queue(intrinsic));
43 _graphics_queue =
std::addressof(_device->get_graphics_queue(intrinsic));
50 hi_assert_not_null(delegate);
51 auto& delegate_info = _delegates.emplace_back(delegate, _device->createSemaphore());
54 auto& graphics_queue = _device->get_graphics_queue(intrinsic);
56 delegate_info.delegate->build_for_new_device(
57 _device->allocator, vulkan_instance(), _device->intrinsic, graphics_queue.queue, graphics_queue.family_queue_index);
59 if (state >= gfx_surface_state::has_swapchain) {
61 image_views.
reserve(swapchain_image_infos.size());
62 for (hilet& image_info : swapchain_image_infos) {
63 image_views.push_back(image_info.image_view);
66 delegate_info.delegate->build_for_new_swapchain(image_views, swapchainImageExtent, swapchainImageFormat);
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);
91[[nodiscard]]
inline extent2 gfx_surface::size() const noexcept
93 return {narrow_cast<float>(swapchainImageExtent.width), narrow_cast<float>(swapchainImageExtent.height)};
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()
113 uint32_t frameBufferIndex = 0;
116 hilet result = _device->acquireNextImageKHR(swapchain, 0, imageAvailableSemaphore, vk::Fence(), &frameBufferIndex);
120 case vk::Result::eSuccess:
121 return {frameBufferIndex};
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);
165 std::array<vk::Semaphore, 1>
const renderFinishedSemaphores = {semaphore};
166 std::array<vk::SwapchainKHR, 1>
const presentSwapchains = {swapchain};
167 std::array<uint32_t, 1>
const presentImageIndices = {frameBufferIndex};
168 hi_assert(presentSwapchains.
size() == presentImageIndices.
size());
172 hilet result = _present_queue->queue.presentKHR(
173 {narrow_cast<uint32_t>(renderFinishedSemaphores.
size()),
174 renderFinishedSemaphores.
data(),
175 narrow_cast<uint32_t>(presentSwapchains.
size()),
176 presentSwapchains.
data(),
177 presentImageIndices.
data()});
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();
216 auto& graphics_queue = _device->get_graphics_queue(intrinsic);
217 for (
auto [delegate, semaphore] : _delegates) {
218 hi_assert_not_null(delegate);
220 delegate->build_for_new_device(
221 _device->allocator, vulkan_instance(), _device->intrinsic, graphics_queue.queue, graphics_queue.family_queue_index);
224 return gfx_surface_loss::none;
227inline gfx_surface_loss gfx_surface::build_for_new_swapchain(extent2 new_size)
noexcept
230 hilet[clamped_count, clamped_size] = get_image_count_and_size(defaultNumberOfSwapchainImages, new_size);
233 return gfx_surface_loss::swapchain_lost;
236 if (loss = build_swapchain(clamped_count, clamped_size); loss != gfx_surface_loss::none) {
240 hilet[clamped_count_check, clamped_size_check] = get_image_count_and_size(clamped_count, clamped_size);
241 if (clamped_count_check != clamped_count or clamped_size_check != clamped_size) {
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);
263 auto image_views = std::vector<vk::ImageView>{};
264 image_views.reserve(swapchain_image_infos.size());
265 for (hilet& image_info : swapchain_image_infos) {
266 image_views.push_back(image_info.image_view);
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) {
407 hilet optional_frame_buffer_index = acquire_next_image_from_swapchain();
408 if (!optional_frame_buffer_index) {
415 r.frame_buffer_index = narrow_cast<size_t>(*optional_frame_buffer_index);
418 auto& current_image = swapchain_image_infos.at(r.frame_buffer_index);
419 current_image.redraw_rectangle = redraw_rectangle;
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);
441 auto& current_image = swapchain_image_infos.at(context.frame_buffer_index);
446 if (not current_image.layout_is_present) {
447 _device->transition_layout(
448 current_image.image, swapchainImageFormat.format, vk::ImageLayout::eUndefined, vk::ImageLayout::ePresentSrcKHR);
450 current_image.layout_is_present =
true;
454 hilet clamped_scissor_rectangle = intersect(
455 context.scissor_rectangle,
456 aarectangle{0, 0, narrow_cast<float>(swapchainImageExtent.width), narrow_cast<float>(swapchainImageExtent.height)});
458 hilet render_area = vk::Rect2D{
460 round_cast<uint32_t>(clamped_scissor_rectangle.left()),
461 round_cast<uint32_t>(
462 swapchainImageExtent.height - clamped_scissor_rectangle.bottom() - clamped_scissor_rectangle.height())),
464 round_cast<uint32_t>(clamped_scissor_rectangle.width()), round_cast<uint32_t>(clamped_scissor_rectangle.height()))};
467 auto start_semaphore = imageAvailableSemaphore;
468 for (
auto [delegate, end_semaphore] : _delegates) {
469 hi_assert_not_null(delegate);
471 delegate->draw(narrow_cast<uint32_t>(context.frame_buffer_index), start_semaphore, end_semaphore, render_area);
472 start_semaphore = end_semaphore;
476 fill_command_buffer(current_image, context, render_area);
477 submit_command_buffer(start_semaphore);
481 [[maybe_unused]] hilet submit_result = _graphics_queue->queue.submit(0,
nullptr, renderFinishedFence);
483 present_image_to_queue(narrow_cast<uint32_t>(context.frame_buffer_index), renderFinishedSemaphore);
489inline void gfx_surface::fill_command_buffer(
490 swapchain_image_info
const& current_image,
491 draw_context
const& context,
492 vk::Rect2D render_area)
496 auto t = trace<
"fill_command_buffer">{};
498 commandBuffer.reset(vk::CommandBufferResetFlagBits::eReleaseResources);
499 commandBuffer.begin({vk::CommandBufferUsageFlagBits::eSimultaneousUse});
501 hilet background_color_f32x4 = f32x4{1.0f, 0.0f, 0.0f, 1.0f};
502 hilet background_color_array =
static_cast<std::array<float, 4>
>(background_color_f32x4);
504 hilet colorClearValue = vk::ClearColorValue{background_color_array};
505 hilet sdfClearValue = vk::ClearColorValue{std::array{0.0f, 0.0f, 0.0f, 0.0f}};
506 hilet depthClearValue = vk::ClearDepthStencilValue{0.0, 0};
507 hilet clearValues = std::array{
508 vk::ClearValue{depthClearValue},
509 vk::ClearValue{colorClearValue},
510 vk::ClearValue{sdfClearValue},
511 vk::ClearValue{colorClearValue}};
514 hilet scissors = std::array{render_area};
515 commandBuffer.setScissor(0, scissors);
517 commandBuffer.beginRenderPass(
518 {renderPass, current_image.frame_buffer, render_area, narrow_cast<uint32_t>(clearValues.size()), clearValues.data()},
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();
535inline void gfx_surface::submit_command_buffer(vk::Semaphore delegate_semaphore)
539 hilet waitSemaphores = std::array{delegate_semaphore};
541 hilet waitStages = std::array{vk::PipelineStageFlags{vk::PipelineStageFlagBits::eColorAttachmentOutput}};
543 hi_assert(waitSemaphores.size() == waitStages.size());
545 hilet signalSemaphores = std::array{renderFinishedSemaphore};
546 hilet commandBuffersToSubmit = std::array{commandBuffer};
548 hilet submitInfo = std::array{vk::SubmitInfo{
549 narrow_cast<uint32_t>(waitSemaphores.size()),
550 waitSemaphores.data(),
552 narrow_cast<uint32_t>(commandBuffersToSubmit.size()),
553 commandBuffersToSubmit.data(),
554 narrow_cast<uint32_t>(signalSemaphores.size()),
555 signalSemaphores.data()}};
557 _graphics_queue->queue.submit(submitInfo, vk::Fence());
560inline std::tuple<std::size_t, extent2> gfx_surface::get_image_count_and_size(std::size_t new_count, extent2 new_size)
564 hilet surfaceCapabilities = _device->getSurfaceCapabilitiesKHR(intrinsic);
566 hilet min_count = narrow_cast<std::size_t>(surfaceCapabilities.minImageCount);
567 hilet max_count = narrow_cast<std::size_t>(surfaceCapabilities.maxImageCount ? surfaceCapabilities.maxImageCount : 3);
568 hilet clamped_count = std::clamp(new_count, min_count, max_count);
570 "gfx_surface min_count={}, max_count={}, requested_count={}, count={}", min_count, max_count, new_count, clamped_count);
573 hilet min_size = extent2{
574 narrow_cast<float>(surfaceCapabilities.minImageExtent.width),
575 narrow_cast<float>(surfaceCapabilities.minImageExtent.height)};
576 hilet max_size = extent2{
577 narrow_cast<float>(surfaceCapabilities.maxImageExtent.width),
578 narrow_cast<float>(surfaceCapabilities.maxImageExtent.height)};
579 hilet clamped_size = clamp(new_size, min_size, max_size);
581 hi_log_info(
"gfx_surface min_size={}, max_size={}, requested_size={}, size={}", min_size, max_size, new_size, clamped_size);
582 return {clamped_count, clamped_size};
585inline gfx_surface_loss gfx_surface::build_swapchain(std::size_t new_count, extent2 new_size)
589 hi_log_info(
"Building swap chain");
591 hilet sharingMode = _graphics_queue == _present_queue ? vk::SharingMode::eExclusive : vk::SharingMode::eConcurrent;
593 std::array<uint32_t, 2>
const sharingQueueFamilyAllIndices = {
594 _graphics_queue->family_queue_index, _present_queue->family_queue_index};
596 swapchainImageFormat = _device->get_surface_format(intrinsic);
597 nrSwapchainImages = narrow_cast<uint32_t>(new_count);
598 swapchainImageExtent = VkExtent2D{round_cast<uint32_t>(new_size.width()), round_cast<uint32_t>(new_size.height())};
599 vk::SwapchainCreateInfoKHR swapchainCreateInfo{
600 vk::SwapchainCreateFlagsKHR(),
603 swapchainImageFormat.format,
604 swapchainImageFormat.colorSpace,
605 swapchainImageExtent,
607 vk::ImageUsageFlagBits::eColorAttachment,
609 sharingMode == vk::SharingMode::eConcurrent ? narrow_cast<uint32_t>(sharingQueueFamilyAllIndices.
size()) : 0,
610 sharingMode == vk::SharingMode::eConcurrent ? sharingQueueFamilyAllIndices.data() : nullptr,
611 vk::SurfaceTransformFlagBitsKHR::eIdentity,
612 vk::CompositeAlphaFlagBitsKHR::eOpaque,
613 _device->get_present_mode(intrinsic),
617 vk::Result
const result = _device->createSwapchainKHR(&swapchainCreateInfo,
nullptr, &swapchain);
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");
630 hi_log_info(
" - extent=({}, {})", swapchainCreateInfo.imageExtent.width, swapchainCreateInfo.imageExtent.height);
632 " - colorSpace={}, format={}",
633 vk::to_string(swapchainCreateInfo.imageColorSpace),
634 vk::to_string(swapchainCreateInfo.imageFormat));
636 " - presentMode={}, imageCount={}", vk::to_string(swapchainCreateInfo.presentMode), swapchainCreateInfo.minImageCount);
639 vk::ImageCreateInfo
const depthImageCreateInfo = {
640 vk::ImageCreateFlags(),
643 vk::Extent3D(swapchainCreateInfo.imageExtent.width, swapchainCreateInfo.imageExtent.height, 1),
646 vk::SampleCountFlagBits::e1,
647 vk::ImageTiling::eOptimal,
648 vk::ImageUsageFlagBits::eDepthStencilAttachment | _device->transientImageUsageFlags,
649 vk::SharingMode::eExclusive,
652 vk::ImageLayout::eUndefined};
654 VmaAllocationCreateInfo depthAllocationCreateInfo = {};
655 depthAllocationCreateInfo.flags = VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT;
656 depthAllocationCreateInfo.pUserData =
const_cast<char *
>(
"vk::Image depth attachment");
657 depthAllocationCreateInfo.usage = _device->lazyMemoryUsage;
658 std::tie(depthImage, depthImageAllocation) = _device->createImage(depthImageCreateInfo, depthAllocationCreateInfo);
659 _device->setDebugUtilsObjectNameEXT(depthImage,
"vk::Image depth attachment");
662 vk::ImageCreateInfo
const colorImageCreateInfo = {
663 vk::ImageCreateFlags(),
666 vk::Extent3D(swapchainCreateInfo.imageExtent.width, swapchainCreateInfo.imageExtent.height, 1),
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};
677 VmaAllocationCreateInfo colorAllocationCreateInfo = {};
678 colorAllocationCreateInfo.flags = VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT;
679 colorAllocationCreateInfo.pUserData =
const_cast<char *
>(
"vk::Image color attachment");
680 colorAllocationCreateInfo.usage = _device->lazyMemoryUsage;
682 std::tie(colorImages[0], colorImageAllocations[0]) = _device->createImage(colorImageCreateInfo, colorAllocationCreateInfo);
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};
724 auto swapchain_images = _device->getSwapchainImagesKHR(swapchain);
725 for (
auto image : swapchain_images) {
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}});
734 hilet attachments = std::array{depthImageView, colorImageViews[0], image_view};
736 hilet frame_buffer = _device->createFramebuffer({
737 vk::FramebufferCreateFlags(),
739 narrow_cast<uint32_t>(attachments.size()),
741 swapchainImageExtent.width,
742 swapchainImageExtent.height,
746 swapchain_image_infos.emplace_back(
750 hi_assert(swapchain_image_infos.size() == swapchain_images.size());
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()
785 hilet attachment_descriptions = std::array{
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
823 hilet depth_attachment_reference = vk::AttachmentReference{0, vk::ImageLayout::eDepthStencilAttachmentOptimal};
824 hilet color_attachment_references = std::array{vk::AttachmentReference{1, vk::ImageLayout::eColorAttachmentOptimal}};
825 hilet color_input_attachment_references = std::array{vk::AttachmentReference{1, vk::ImageLayout::eShaderReadOnlyOptimal}};
826 hilet swapchain_attachment_references = std::array{vk::AttachmentReference{2, vk::ImageLayout::eColorAttachmentOptimal}};
828 hilet subpass_descriptions = std::array{
829 vk::SubpassDescription{
830 vk::SubpassDescriptionFlags(),
831 vk::PipelineBindPoint::eGraphics,
834 narrow_cast<uint32_t>(color_attachment_references.size()),
835 color_attachment_references.data(),
837 &depth_attachment_reference
840 vk::SubpassDescription{
841 vk::SubpassDescriptionFlags(),
842 vk::PipelineBindPoint::eGraphics,
845 narrow_cast<uint32_t>(color_attachment_references.size()),
846 color_attachment_references.data(),
848 &depth_attachment_reference
851 vk::SubpassDescription{
852 vk::SubpassDescriptionFlags(),
853 vk::PipelineBindPoint::eGraphics,
856 narrow_cast<uint32_t>(color_attachment_references.size()),
857 color_attachment_references.data(),
859 &depth_attachment_reference
862 vk::SubpassDescription{
863 vk::SubpassDescriptionFlags(),
864 vk::PipelineBindPoint::eGraphics,
867 narrow_cast<uint32_t>(color_attachment_references.size()),
868 color_attachment_references.data(),
870 &depth_attachment_reference
873 vk::SubpassDescription{
874 vk::SubpassDescriptionFlags(),
875 vk::PipelineBindPoint::eGraphics,
876 narrow_cast<uint32_t>(color_input_attachment_references.size()),
877 color_input_attachment_references.data(),
878 narrow_cast<uint32_t>(swapchain_attachment_references.size()),
879 swapchain_attachment_references.data(),
883 hilet subpass_dependency = std::array{
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}};
938 vk::RenderPassCreateInfo
const render_pass_create_info = {
939 vk::RenderPassCreateFlags(),
940 narrow_cast<uint32_t>(attachment_descriptions.size()),
941 attachment_descriptions.data(),
942 narrow_cast<uint32_t>(subpass_descriptions.size()),
943 subpass_descriptions.data(),
944 narrow_cast<uint32_t>(subpass_dependency.size()),
945 subpass_dependency.data()
948 renderPass = _device->createRenderPass(render_pass_create_info);
949 hilet granularity = _device->getRenderAreaGranularity(renderPass);
950 _render_area_granularity = extent2{narrow_cast<float>(granularity.width), narrow_cast<float>(granularity.height)};
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});
988 commandBuffer = commandBuffers.at(0);
991inline void gfx_surface::teardown_command_buffers()
994 hilet commandBuffers = std::vector<vk::CommandBuffer>{commandBuffer};
996 _device->freeCommandBuffers(_graphics_queue->command_pool, commandBuffers);
999[[nodiscard]]
inline std::unique_ptr<gfx_surface> make_unique_gfx_surface(os_handle instance,
void *os_window)
1001 hilet
lock = std::scoped_lock(gfx_system_mutex);
1003 auto surface_create_info = vk::Win32SurfaceCreateInfoKHR{
1004 vk::Win32SurfaceCreateFlagsKHR(),
reinterpret_cast<HINSTANCE
>(instance),
reinterpret_cast<HWND
>(os_window)};
1006 auto vulkan_surface = vulkan_instance().createWin32SurfaceKHR(surface_create_info);
1008 auto surface = std::make_unique<gfx_surface>(vulkan_surface);
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
@ has_device
The surface has been associated with a device to use for rendering.
Definition gfx_surface_state.hpp:16
gfx_surface_loss
Definition gfx_surface_state.hpp:20
@ device_lost
The device was lost, but the window could move to a new device, or the device can be recreated.
Definition gfx_surface_state.hpp:23
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
void set_device(gfx_device *device) noexcept
Definition gfx_surface_vulkan_impl.hpp:23