7#include "gfx_surface_vulkan_intf.hpp"
8#include "gfx_surface_delegate_vulkan.hpp"
9#include "gfx_system_vulkan_intf.hpp"
10#include "gfx_device_vulkan_impl.hpp"
11#include "gfx_pipeline_box_vulkan_intf.hpp"
12#include "gfx_pipeline_image_vulkan_intf.hpp"
13#include "gfx_pipeline_SDF_vulkan_intf.hpp"
14#include "gfx_pipeline_override_vulkan_intf.hpp"
15#include "gfx_pipeline_tone_mapper_vulkan_intf.hpp"
16#include "../telemetry/telemetry.hpp"
17#include "../utility/utility.hpp"
18#include "../macros.hpp"
20#include <vulkan/vulkan.hpp>
22hi_export_module(hikogui.GFX : gfx_surface_impl);
24hi_export
namespace hi::inline
v1 {
26inline void gfx_surface::set_device(
gfx_device *new_device)
noexcept
28 hi_assert_not_null(new_device);
34 if (_device == new_device) {
39 loss = gfx_surface_loss::device_lost;
45 _present_queue =
std::addressof(_device->get_present_queue(intrinsic));
46 _graphics_queue =
std::addressof(_device->get_graphics_queue(intrinsic));
51 auto const lock = std::scoped_lock(gfx_system_mutex);
53 hi_assert_not_null(delegate);
54 auto& delegate_info = _delegates.emplace_back(delegate, _device->createSemaphore());
56 if (state >= gfx_surface_state::has_device) {
57 auto& graphics_queue = _device->get_graphics_queue(intrinsic);
59 delegate_info.delegate->build_for_new_device(
60 _device->allocator, vulkan_instance(), _device->intrinsic, graphics_queue.queue, graphics_queue.family_queue_index);
62 if (state >= gfx_surface_state::has_swapchain) {
64 image_views.
reserve(swapchain_image_infos.size());
65 for (
auto const& image_info : swapchain_image_infos) {
66 image_views.push_back(image_info.image_view);
69 delegate_info.delegate->build_for_new_swapchain(image_views, swapchainImageExtent, swapchainImageFormat);
73inline void gfx_surface::remove_delegate(gfx_surface_delegate *delegate)
noexcept
75 auto const lock = std::scoped_lock(gfx_system_mutex);
77 hi_assert_not_null(delegate);
78 auto it =
std::find_if(_delegates.begin(), _delegates.end(), [delegate](
auto const& item) {
79 return item.delegate == delegate;
82 if (state >= gfx_surface_state::has_swapchain) {
83 it->delegate->teardown_for_swapchain_lost();
85 if (state >= gfx_surface_state::has_device) {
86 it->delegate->teardown_for_device_lost();
89 _device->destroy(it->semaphore);
94[[nodiscard]]
inline extent2 gfx_surface::size() const noexcept
96 return {narrow_cast<float>(swapchainImageExtent.width), narrow_cast<float>(swapchainImageExtent.height)};
99inline void gfx_surface::wait_idle()
104 if (renderFinishedFence) {
108 hi_log_info(
"/waitIdle");
111inline std::optional<uint32_t> gfx_surface::acquire_next_image_from_swapchain()
116 uint32_t frameBufferIndex = 0;
119 auto const result = _device->acquireNextImageKHR(swapchain, 0, imageAvailableSemaphore, vk::Fence(), &frameBufferIndex);
123 case vk::Result::eSuccess:
124 return {frameBufferIndex};
126 case vk::Result::eSuboptimalKHR:
130 hi_log_info(
"acquireNextImageKHR() eSuboptimalKHR");
131 loss = gfx_surface_loss::swapchain_lost;
134 case vk::Result::eNotReady:
140 case vk::Result::eTimeout:
144 hi_log_info(
"acquireNextImageKHR() eTimeout");
147 case vk::Result::eErrorOutOfDateKHR:
148 hi_log_info(
"acquireNextImageKHR() eErrorOutOfDateKHR");
149 loss = gfx_surface_loss::swapchain_lost;
152 case vk::Result::eErrorSurfaceLostKHR:
153 hi_log_info(
"acquireNextImageKHR() eErrorSurfaceLostKHR");
154 loss = gfx_surface_loss::window_lost;
158 throw gui_error(std::format(
"Unknown result from acquireNextImageKHR(). '{}'",
to_string(result)));
162inline void gfx_surface::present_image_to_queue(uint32_t frameBufferIndex, vk::Semaphore semaphore)
166 hi_assert_not_null(_device);
171 hi_assert(presentSwapchains.
size() == presentImageIndices.
size());
175 auto const result = _present_queue->queue.presentKHR(
176 {narrow_cast<uint32_t>(renderFinishedSemaphores.
size()),
177 renderFinishedSemaphores.
data(),
178 narrow_cast<uint32_t>(presentSwapchains.
size()),
179 presentSwapchains.
data(),
180 presentImageIndices.
data()});
183 case vk::Result::eSuccess:
186 case vk::Result::eSuboptimalKHR:
187 hi_log_info(
"presentKHR() eSuboptimalKHR");
188 loss = gfx_surface_loss::swapchain_lost;
192 throw gui_error(std::format(
"Unknown result from presentKHR(). '{}'",
to_string(result)));
195 }
catch (vk::OutOfDateKHRError
const&) {
196 hi_log_info(
"presentKHR() eErrorOutOfDateKHR");
197 loss = gfx_surface_loss::swapchain_lost;
200 }
catch (vk::SurfaceLostKHRError
const&) {
201 hi_log_info(
"presentKHR() eErrorSurfaceLostKHR");
202 loss = gfx_surface_loss::window_lost;
209 if (_device->score(intrinsic) <= 0) {
210 return gfx_surface_loss::device_lost;
213 box_pipeline->build_for_new_device();
214 image_pipeline->build_for_new_device();
215 SDF_pipeline->build_for_new_device();
216 override_pipeline->build_for_new_device();
217 tone_mapper_pipeline->build_for_new_device();
219 auto& graphics_queue = _device->get_graphics_queue(intrinsic);
220 for (
auto [delegate, semaphore] : _delegates) {
221 hi_assert_not_null(delegate);
223 delegate->build_for_new_device(
224 _device->allocator, vulkan_instance(), _device->intrinsic, graphics_queue.queue, graphics_queue.family_queue_index);
227 return gfx_surface_loss::none;
230inline gfx_surface_loss gfx_surface::build_for_new_swapchain(extent2 new_size)
noexcept
233 auto const[clamped_count, clamped_size] = get_image_count_and_size(defaultNumberOfSwapchainImages, new_size);
236 return gfx_surface_loss::swapchain_lost;
239 if (loss = build_swapchain(clamped_count, clamped_size); loss != gfx_surface_loss::none) {
243 auto const[clamped_count_check, clamped_size_check] = get_image_count_and_size(clamped_count, clamped_size);
244 if (clamped_count_check != clamped_count or clamped_size_check != clamped_size) {
247 teardown_swapchain();
248 return gfx_surface_loss::swapchain_lost;
251 build_render_passes();
252 build_frame_buffers();
253 build_command_buffers();
255 hi_assert_not_null(box_pipeline);
256 hi_assert_not_null(image_pipeline);
257 hi_assert_not_null(SDF_pipeline);
258 hi_assert_not_null(override_pipeline);
259 hi_assert_not_null(tone_mapper_pipeline);
260 box_pipeline->build_for_new_swapchain(renderPass, 0, swapchainImageExtent);
261 image_pipeline->build_for_new_swapchain(renderPass, 1, swapchainImageExtent);
262 SDF_pipeline->build_for_new_swapchain(renderPass, 2, swapchainImageExtent);
263 override_pipeline->build_for_new_swapchain(renderPass, 3, swapchainImageExtent);
264 tone_mapper_pipeline->build_for_new_swapchain(renderPass, 4, swapchainImageExtent);
267 image_views.
reserve(swapchain_image_infos.size());
268 for (
auto const& image_info : swapchain_image_infos) {
269 image_views.push_back(image_info.image_view);
272 for (
auto [delegate, semaphore] : _delegates) {
273 hi_assert_not_null(delegate);
274 delegate->build_for_new_swapchain(image_views, swapchainImageExtent, swapchainImageFormat);
277 return gfx_surface_loss::none;
279 }
catch (vk::SurfaceLostKHRError
const&) {
282 return gfx_surface_loss::window_lost;
286inline void gfx_surface::build(extent2 new_size)
noexcept
289 hi_assert(loss == gfx_surface_loss::none);
291 if (state == gfx_surface_state::has_window) {
293 if (loss = build_for_new_device(); loss != gfx_surface_loss::none) {
296 state = gfx_surface_state::has_device;
300 if (state == gfx_surface_state::has_device) {
301 if (
auto const tmp = build_for_new_swapchain(new_size); tmp == gfx_surface_loss::swapchain_lost) {
305 }
else if (loss = tmp; tmp != gfx_surface_loss::none) {
309 state = gfx_surface_state::has_swapchain;
313inline void gfx_surface::teardown_for_swapchain_lost() noexcept
315 hi_log_info(
"Tearing down because the window lost the swapchain.");
318 for (
auto [delegate, semaphore] : _delegates) {
319 hi_assert_not_null(delegate);
320 delegate->teardown_for_swapchain_lost();
323 tone_mapper_pipeline->teardown_for_swapchain_lost();
324 override_pipeline->teardown_for_swapchain_lost();
325 SDF_pipeline->teardown_for_swapchain_lost();
326 image_pipeline->teardown_for_swapchain_lost();
327 box_pipeline->teardown_for_swapchain_lost();
328 teardown_semaphores();
329 teardown_command_buffers();
330 teardown_frame_buffers();
331 teardown_render_passes();
332 teardown_swapchain();
335inline void gfx_surface::teardown_for_device_lost() noexcept
337 hi_log_info(
"Tearing down because the window lost the vulkan device.");
338 for (
auto [delegate, semaphore] : _delegates) {
339 hi_assert_not_null(delegate);
340 delegate->teardown_for_device_lost();
342 tone_mapper_pipeline->teardown_for_device_lost();
343 override_pipeline->teardown_for_device_lost();
344 SDF_pipeline->teardown_for_device_lost();
345 image_pipeline->teardown_for_device_lost();
346 box_pipeline->teardown_for_device_lost();
350inline void gfx_surface::teardown_for_window_lost() noexcept
352 gfx_system::global().destroySurfaceKHR(intrinsic);
355inline void gfx_surface::teardown() noexcept
359 if (state == gfx_surface_state::has_swapchain and loss >= gfx_surface_loss::swapchain_lost) {
360 teardown_for_swapchain_lost();
361 state = gfx_surface_state::has_device;
364 if (state == gfx_surface_state::has_device and loss >= gfx_surface_loss::device_lost) {
365 teardown_for_device_lost();
366 state = gfx_surface_state::has_window;
369 if (state == gfx_surface_state::has_window and loss >= gfx_surface_loss::window_lost) {
370 hi_log_info(
"Tearing down because the window doesn't exist anymore.");
371 teardown_for_window_lost();
372 state = gfx_surface_state::no_window;
374 loss = gfx_surface_loss::none;
377inline void gfx_surface::update(extent2 new_size)
noexcept
379 auto const lock = std::scoped_lock(gfx_system_mutex);
381 if (size() != new_size and state == gfx_surface_state::has_swapchain) {
383 loss = gfx_surface_loss::swapchain_lost;
391inline draw_context gfx_surface::render_start(aarectangle redraw_rectangle)
394 redraw_rectangle =
ceil(redraw_rectangle, _render_area_granularity);
396 auto const lock = std::scoped_lock(gfx_system_mutex);
398 auto r = draw_context{
400 box_pipeline->vertexBufferData,
401 image_pipeline->vertexBufferData,
402 SDF_pipeline->vertexBufferData,
403 override_pipeline->vertexBufferData};
406 if (state != gfx_surface_state::has_swapchain or not redraw_rectangle) {
410 auto const optional_frame_buffer_index = acquire_next_image_from_swapchain();
411 if (!optional_frame_buffer_index) {
418 r.frame_buffer_index = narrow_cast<size_t>(*optional_frame_buffer_index);
421 auto& current_image = swapchain_image_infos.at(r.frame_buffer_index);
422 current_image.redraw_rectangle = redraw_rectangle;
426 r.scissor_rectangle =
427 std::accumulate(swapchain_image_infos.cbegin(), swapchain_image_infos.cend(), aarectangle{}, [](
auto const& sum,
auto const& item) {
428 return sum | item.redraw_rectangle;
435 _device->resetFences({renderFinishedFence});
440inline void gfx_surface::render_finish(draw_context
const& context)
442 auto const lock = std::scoped_lock(gfx_system_mutex);
444 auto& current_image = swapchain_image_infos.at(context.frame_buffer_index);
449 if (not current_image.layout_is_present) {
450 _device->transition_layout(
451 current_image.image, swapchainImageFormat.format, vk::ImageLayout::eUndefined, vk::ImageLayout::ePresentSrcKHR);
453 current_image.layout_is_present =
true;
457 auto const clamped_scissor_rectangle = intersect(
458 context.scissor_rectangle,
459 aarectangle{0, 0, narrow_cast<float>(swapchainImageExtent.width), narrow_cast<float>(swapchainImageExtent.height)});
461 auto const render_area = vk::Rect2D{
463 round_cast<uint32_t>(clamped_scissor_rectangle.left()),
464 round_cast<uint32_t>(
465 swapchainImageExtent.height - clamped_scissor_rectangle.bottom() - clamped_scissor_rectangle.height())),
467 round_cast<uint32_t>(clamped_scissor_rectangle.width()), round_cast<uint32_t>(clamped_scissor_rectangle.height()))};
470 auto start_semaphore = imageAvailableSemaphore;
471 for (
auto [delegate, end_semaphore] : _delegates) {
472 hi_assert_not_null(delegate);
474 delegate->draw(narrow_cast<uint32_t>(context.frame_buffer_index), start_semaphore, end_semaphore, render_area);
475 start_semaphore = end_semaphore;
479 fill_command_buffer(current_image, context, render_area);
480 submit_command_buffer(start_semaphore);
484 [[maybe_unused]]
auto const submit_result = _graphics_queue->queue.submit(0,
nullptr, renderFinishedFence);
486 present_image_to_queue(narrow_cast<uint32_t>(context.frame_buffer_index), renderFinishedSemaphore);
492inline void gfx_surface::fill_command_buffer(
493 swapchain_image_info
const& current_image,
494 draw_context
const& context,
495 vk::Rect2D render_area)
499 auto t = trace<
"fill_command_buffer">{};
501 commandBuffer.reset(vk::CommandBufferResetFlagBits::eReleaseResources);
502 commandBuffer.begin({vk::CommandBufferUsageFlagBits::eSimultaneousUse});
504 auto const background_color_f32x4 = f32x4{1.0f, 0.0f, 0.0f, 1.0f};
507 auto const colorClearValue = vk::ClearColorValue{background_color_array};
508 auto const sdfClearValue = vk::ClearColorValue{
std::array{0.0f, 0.0f, 0.0f, 0.0f}};
509 auto const depthClearValue = vk::ClearDepthStencilValue{0.0, 0};
511 vk::ClearValue{depthClearValue},
512 vk::ClearValue{colorClearValue},
513 vk::ClearValue{sdfClearValue},
514 vk::ClearValue{colorClearValue}};
517 auto const scissors =
std::array{render_area};
518 commandBuffer.setScissor(0, scissors);
520 commandBuffer.beginRenderPass(
521 {renderPass, current_image.frame_buffer, render_area, narrow_cast<uint32_t>(clearValues.size()), clearValues.data()},
522 vk::SubpassContents::eInline);
524 box_pipeline->draw_in_command_buffer(commandBuffer, context);
525 commandBuffer.nextSubpass(vk::SubpassContents::eInline);
526 image_pipeline->draw_in_command_buffer(commandBuffer, context);
527 commandBuffer.nextSubpass(vk::SubpassContents::eInline);
528 SDF_pipeline->draw_in_command_buffer(commandBuffer, context);
529 commandBuffer.nextSubpass(vk::SubpassContents::eInline);
530 override_pipeline->draw_in_command_buffer(commandBuffer, context);
531 commandBuffer.nextSubpass(vk::SubpassContents::eInline);
532 tone_mapper_pipeline->draw_in_command_buffer(commandBuffer, context);
534 commandBuffer.endRenderPass();
538inline void gfx_surface::submit_command_buffer(vk::Semaphore delegate_semaphore)
542 auto const waitSemaphores =
std::array{delegate_semaphore};
544 auto const waitStages =
std::array{vk::PipelineStageFlags{vk::PipelineStageFlagBits::eColorAttachmentOutput}};
546 hi_assert(waitSemaphores.size() == waitStages.size());
548 auto const signalSemaphores =
std::array{renderFinishedSemaphore};
549 auto const commandBuffersToSubmit =
std::array{commandBuffer};
551 auto const submitInfo =
std::array{vk::SubmitInfo{
552 narrow_cast<uint32_t>(waitSemaphores.size()),
553 waitSemaphores.
data(),
555 narrow_cast<uint32_t>(commandBuffersToSubmit.size()),
556 commandBuffersToSubmit.data(),
557 narrow_cast<uint32_t>(signalSemaphores.size()),
558 signalSemaphores.data()}};
560 _graphics_queue->queue.submit(submitInfo, vk::Fence());
567 auto const surfaceCapabilities = _device->getSurfaceCapabilitiesKHR(intrinsic);
569 auto const min_count = narrow_cast<std::size_t>(surfaceCapabilities.minImageCount);
570 auto const max_count = narrow_cast<std::size_t>(surfaceCapabilities.maxImageCount ? surfaceCapabilities.maxImageCount : 3);
571 auto const clamped_count = std::clamp(new_count, min_count, max_count);
573 "gfx_surface min_count={}, max_count={}, requested_count={}, count={}", min_count, max_count, new_count, clamped_count);
576 auto const min_size = extent2{
577 narrow_cast<float>(surfaceCapabilities.minImageExtent.width),
578 narrow_cast<float>(surfaceCapabilities.minImageExtent.height)};
579 auto const max_size = extent2{
580 narrow_cast<float>(surfaceCapabilities.maxImageExtent.width),
581 narrow_cast<float>(surfaceCapabilities.maxImageExtent.height)};
582 auto const clamped_size = clamp(new_size, min_size, max_size);
584 hi_log_info(
"gfx_surface min_size={}, max_size={}, requested_size={}, size={}", min_size, max_size, new_size, clamped_size);
585 return {clamped_count, clamped_size};
592 hi_log_info(
"Building swap chain");
594 auto const sharingMode = _graphics_queue == _present_queue ? vk::SharingMode::eExclusive : vk::SharingMode::eConcurrent;
597 _graphics_queue->family_queue_index, _present_queue->family_queue_index};
599 swapchainImageFormat = _device->get_surface_format(intrinsic);
600 nrSwapchainImages = narrow_cast<uint32_t>(new_count);
601 swapchainImageExtent = VkExtent2D{round_cast<uint32_t>(new_size.width()), round_cast<uint32_t>(new_size.height())};
602 vk::SwapchainCreateInfoKHR swapchainCreateInfo{
603 vk::SwapchainCreateFlagsKHR(),
606 swapchainImageFormat.format,
607 swapchainImageFormat.colorSpace,
608 swapchainImageExtent,
610 vk::ImageUsageFlagBits::eColorAttachment,
612 sharingMode == vk::SharingMode::eConcurrent ? narrow_cast<uint32_t>(sharingQueueFamilyAllIndices.
size()) : 0,
613 sharingMode == vk::SharingMode::eConcurrent ? sharingQueueFamilyAllIndices.data() : nullptr,
614 vk::SurfaceTransformFlagBitsKHR::eIdentity,
615 vk::CompositeAlphaFlagBitsKHR::eOpaque,
616 _device->get_present_mode(intrinsic),
620 vk::Result
const result = _device->createSwapchainKHR(&swapchainCreateInfo,
nullptr, &swapchain);
622 case vk::Result::eSuccess:
625 case vk::Result::eErrorSurfaceLostKHR:
626 return gfx_surface_loss::window_lost;
629 throw gui_error(std::format(
"Unknown result from createSwapchainKHR(). '{}'",
to_string(result)));
632 hi_log_info(
"Finished building swap chain");
633 hi_log_info(
" - extent=({}, {})", swapchainCreateInfo.imageExtent.width, swapchainCreateInfo.imageExtent.height);
635 " - colorSpace={}, format={}",
636 vk::to_string(swapchainCreateInfo.imageColorSpace),
637 vk::to_string(swapchainCreateInfo.imageFormat));
639 " - presentMode={}, imageCount={}", vk::to_string(swapchainCreateInfo.presentMode), swapchainCreateInfo.minImageCount);
642 vk::ImageCreateInfo
const depthImageCreateInfo = {
643 vk::ImageCreateFlags(),
646 vk::Extent3D(swapchainCreateInfo.imageExtent.width, swapchainCreateInfo.imageExtent.height, 1),
649 vk::SampleCountFlagBits::e1,
650 vk::ImageTiling::eOptimal,
651 vk::ImageUsageFlagBits::eDepthStencilAttachment | _device->transientImageUsageFlags,
652 vk::SharingMode::eExclusive,
655 vk::ImageLayout::eUndefined};
657 VmaAllocationCreateInfo depthAllocationCreateInfo = {};
658 depthAllocationCreateInfo.flags = VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT;
659 depthAllocationCreateInfo.pUserData =
const_cast<char *
>(
"vk::Image depth attachment");
660 depthAllocationCreateInfo.usage = _device->lazyMemoryUsage;
661 std::tie(depthImage, depthImageAllocation) = _device->createImage(depthImageCreateInfo, depthAllocationCreateInfo);
662 _device->setDebugUtilsObjectNameEXT(depthImage,
"vk::Image depth attachment");
665 vk::ImageCreateInfo
const colorImageCreateInfo = {
666 vk::ImageCreateFlags(),
669 vk::Extent3D(swapchainCreateInfo.imageExtent.width, swapchainCreateInfo.imageExtent.height, 1),
672 vk::SampleCountFlagBits::e1,
673 vk::ImageTiling::eOptimal,
674 vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eInputAttachment | _device->transientImageUsageFlags,
675 vk::SharingMode::eExclusive,
678 vk::ImageLayout::eUndefined};
680 VmaAllocationCreateInfo colorAllocationCreateInfo = {};
681 colorAllocationCreateInfo.flags = VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT;
682 colorAllocationCreateInfo.pUserData =
const_cast<char *
>(
"vk::Image color attachment");
683 colorAllocationCreateInfo.usage = _device->lazyMemoryUsage;
685 std::tie(colorImages[0], colorImageAllocations[0]) = _device->createImage(colorImageCreateInfo, colorAllocationCreateInfo);
686 _device->setDebugUtilsObjectNameEXT(colorImages[0],
"vk::Image color attachment");
688 return gfx_surface_loss::none;
691inline void gfx_surface::teardown_swapchain()
695 _device->destroy(swapchain);
696 _device->destroyImage(depthImage, depthImageAllocation);
698 for (
std::size_t i = 0; i != colorImages.size(); ++i) {
699 _device->destroyImage(colorImages[i], colorImageAllocations[i]);
703inline void gfx_surface::build_frame_buffers()
707 depthImageView = _device->createImageView(
708 {vk::ImageViewCreateFlags(),
710 vk::ImageViewType::e2D,
712 vk::ComponentMapping(),
713 {vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}});
715 for (
std::size_t i = 0; i != colorImageViews.size(); ++i) {
716 colorImageViews[i] = _device->createImageView(
717 {vk::ImageViewCreateFlags(),
719 vk::ImageViewType::e2D,
721 vk::ComponentMapping(),
722 {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}});
724 colorDescriptorImageInfos[i] = {vk::Sampler(), colorImageViews[i], vk::ImageLayout::eShaderReadOnlyOptimal};
727 auto swapchain_images = _device->getSwapchainImagesKHR(swapchain);
728 for (
auto image : swapchain_images) {
729 auto image_view = _device->createImageView(
730 {vk::ImageViewCreateFlags(),
732 vk::ImageViewType::e2D,
733 swapchainImageFormat.format,
734 vk::ComponentMapping(),
735 {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}});
737 auto const attachments =
std::array{depthImageView, colorImageViews[0], image_view};
739 auto const frame_buffer = _device->createFramebuffer({
740 vk::FramebufferCreateFlags(),
742 narrow_cast<uint32_t>(attachments.size()),
744 swapchainImageExtent.width,
745 swapchainImageExtent.height,
749 swapchain_image_infos.emplace_back(
753 hi_assert(swapchain_image_infos.size() == swapchain_images.size());
756inline void gfx_surface::teardown_frame_buffers()
760 for (
auto& info : swapchain_image_infos) {
761 _device->destroy(info.frame_buffer);
762 _device->destroy(info.image_view);
764 swapchain_image_infos.clear();
766 _device->destroy(depthImageView);
767 for (
std::size_t i = 0; i != colorImageViews.size(); ++i) {
768 _device->destroy(colorImageViews[i]);
784inline void gfx_surface::build_render_passes()
788 auto const attachment_descriptions =
std::array{
789 vk::AttachmentDescription{
791 vk::AttachmentDescriptionFlags(),
793 vk::SampleCountFlagBits::e1,
794 vk::AttachmentLoadOp::eClear,
795 vk::AttachmentStoreOp::eDontCare,
796 vk::AttachmentLoadOp::eDontCare,
797 vk::AttachmentStoreOp::eDontCare,
798 vk::ImageLayout::eUndefined,
799 vk::ImageLayout::eDepthStencilAttachmentOptimal
801 vk::AttachmentDescription{
803 vk::AttachmentDescriptionFlags(),
805 vk::SampleCountFlagBits::e1,
806 vk::AttachmentLoadOp::eClear,
807 vk::AttachmentStoreOp::eDontCare,
808 vk::AttachmentLoadOp::eDontCare,
809 vk::AttachmentStoreOp::eDontCare,
810 vk::ImageLayout::eUndefined,
811 vk::ImageLayout::eColorAttachmentOptimal
813 vk::AttachmentDescription{
815 vk::AttachmentDescriptionFlags(),
816 swapchainImageFormat.format,
817 vk::SampleCountFlagBits::e1,
818 vk::AttachmentLoadOp::eLoad,
819 vk::AttachmentStoreOp::eStore,
820 vk::AttachmentLoadOp::eDontCare,
821 vk::AttachmentStoreOp::eDontCare,
822 vk::ImageLayout::ePresentSrcKHR,
823 vk::ImageLayout::ePresentSrcKHR
826 auto const depth_attachment_reference = vk::AttachmentReference{0, vk::ImageLayout::eDepthStencilAttachmentOptimal};
827 auto const color_attachment_references =
std::array{vk::AttachmentReference{1, vk::ImageLayout::eColorAttachmentOptimal}};
828 auto const color_input_attachment_references =
std::array{vk::AttachmentReference{1, vk::ImageLayout::eShaderReadOnlyOptimal}};
829 auto const swapchain_attachment_references =
std::array{vk::AttachmentReference{2, vk::ImageLayout::eColorAttachmentOptimal}};
832 vk::SubpassDescription{
833 vk::SubpassDescriptionFlags(),
834 vk::PipelineBindPoint::eGraphics,
837 narrow_cast<uint32_t>(color_attachment_references.size()),
838 color_attachment_references.
data(),
840 &depth_attachment_reference
843 vk::SubpassDescription{
844 vk::SubpassDescriptionFlags(),
845 vk::PipelineBindPoint::eGraphics,
848 narrow_cast<uint32_t>(color_attachment_references.size()),
849 color_attachment_references.data(),
851 &depth_attachment_reference
854 vk::SubpassDescription{
855 vk::SubpassDescriptionFlags(),
856 vk::PipelineBindPoint::eGraphics,
859 narrow_cast<uint32_t>(color_attachment_references.size()),
860 color_attachment_references.data(),
862 &depth_attachment_reference
865 vk::SubpassDescription{
866 vk::SubpassDescriptionFlags(),
867 vk::PipelineBindPoint::eGraphics,
870 narrow_cast<uint32_t>(color_attachment_references.size()),
871 color_attachment_references.data(),
873 &depth_attachment_reference
876 vk::SubpassDescription{
877 vk::SubpassDescriptionFlags(),
878 vk::PipelineBindPoint::eGraphics,
879 narrow_cast<uint32_t>(color_input_attachment_references.size()),
880 color_input_attachment_references.data(),
881 narrow_cast<uint32_t>(swapchain_attachment_references.size()),
882 swapchain_attachment_references.data(),
887 vk::SubpassDependency{
890 vk::PipelineStageFlagBits::eBottomOfPipe,
891 vk::PipelineStageFlagBits::eColorAttachmentOutput,
892 vk::AccessFlagBits::eMemoryRead,
893 vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite,
894 vk::DependencyFlagBits::eByRegion},
896 vk::SubpassDependency{
899 vk::PipelineStageFlagBits::eColorAttachmentOutput,
900 vk::PipelineStageFlagBits::eColorAttachmentOutput,
901 vk::AccessFlagBits::eColorAttachmentWrite,
902 vk::AccessFlagBits::eColorAttachmentRead,
903 vk::DependencyFlagBits::eByRegion},
905 vk::SubpassDependency{
908 vk::PipelineStageFlagBits::eColorAttachmentOutput,
909 vk::PipelineStageFlagBits::eColorAttachmentOutput,
910 vk::AccessFlagBits::eColorAttachmentWrite,
911 vk::AccessFlagBits::eColorAttachmentRead,
912 vk::DependencyFlagBits::eByRegion},
914 vk::SubpassDependency{
917 vk::PipelineStageFlagBits::eColorAttachmentOutput,
918 vk::PipelineStageFlagBits::eFragmentShader,
919 vk::AccessFlagBits::eColorAttachmentWrite,
920 vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eInputAttachmentRead,
921 vk::DependencyFlagBits::eByRegion},
923 vk::SubpassDependency{
926 vk::PipelineStageFlagBits::eColorAttachmentOutput,
927 vk::PipelineStageFlagBits::eFragmentShader,
928 vk::AccessFlagBits::eColorAttachmentWrite,
929 vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eInputAttachmentRead,
930 vk::DependencyFlagBits::eByRegion},
932 vk::SubpassDependency{
935 vk::PipelineStageFlagBits::eColorAttachmentOutput,
936 vk::PipelineStageFlagBits::eBottomOfPipe,
937 vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite,
938 vk::AccessFlagBits::eMemoryRead,
939 vk::DependencyFlagBits::eByRegion}};
941 vk::RenderPassCreateInfo
const render_pass_create_info = {
942 vk::RenderPassCreateFlags(),
943 narrow_cast<uint32_t>(attachment_descriptions.size()),
944 attachment_descriptions.
data(),
945 narrow_cast<uint32_t>(subpass_descriptions.size()),
946 subpass_descriptions.data(),
947 narrow_cast<uint32_t>(subpass_dependency.size()),
948 subpass_dependency.data()
951 renderPass = _device->createRenderPass(render_pass_create_info);
952 auto const granularity = _device->getRenderAreaGranularity(renderPass);
953 _render_area_granularity = extent2{narrow_cast<float>(granularity.width), narrow_cast<float>(granularity.height)};
956inline void gfx_surface::teardown_render_passes()
960 _device->destroy(renderPass);
963inline void gfx_surface::build_semaphores()
967 imageAvailableSemaphore = _device->createSemaphore();
968 renderFinishedSemaphore = _device->createSemaphore();
973 renderFinishedFence = _device->createFence({vk::FenceCreateFlagBits::eSignaled});
976inline void gfx_surface::teardown_semaphores()
980 _device->destroy(renderFinishedSemaphore);
981 _device->destroy(imageAvailableSemaphore);
982 _device->destroy(renderFinishedFence);
985inline void gfx_surface::build_command_buffers()
989 auto const commandBuffers = _device->allocateCommandBuffers({_graphics_queue->command_pool, vk::CommandBufferLevel::ePrimary, 1});
991 commandBuffer = commandBuffers.at(0);
994inline void gfx_surface::teardown_command_buffers()
999 _device->freeCommandBuffers(_graphics_queue->command_pool, commandBuffers);
1004 auto const lock = std::scoped_lock(gfx_system_mutex);
1006 auto surface_create_info = vk::Win32SurfaceCreateInfoKHR{
1007 vk::Win32SurfaceCreateFlagsKHR(),
reinterpret_cast<HINSTANCE
>(instance),
reinterpret_cast<HWND
>(os_window)};
1009 auto vulkan_surface = vulkan_instance().createWin32SurfaceKHR(surface_create_info);
1011 auto surface = std::make_unique<gfx_surface>(vulkan_surface);
1017 throw gfx_error(
"Could not find a vulkan-device matching this surface");
1019 surface->set_device(device);
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
gfx_device * find_best_device(gfx_surface const &surface)
Find the best device for a surface.
Definition gfx_surface_vulkan_intf.hpp:191
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
Definition gfx_device_vulkan_intf.hpp:26
A delegate for drawing on a window below the HikoGUI user interface.
Definition gfx_surface_delegate_vulkan.hpp:24