diff options
| author | ladevieq <ladevie.quentin@gmail.com> | 2026-05-05 00:43:54 +0200 |
|---|---|---|
| committer | ladevieq <ladevie.quentin@gmail.com> | 2026-05-05 00:49:12 +0200 |
| commit | c3aac9026951e2a6e35e76b9c7d36e114a281453 (patch) | |
| tree | bdfc2ab5d5f1d196ba8c7a76371a29911f75913e /src/vk-device.cpp | |
| parent | 754249d9c652ef941e6b082d2e86538d15ba9434 (diff) | |
Remove old api and move api-test content to src and include dirs
Diffstat (limited to 'src/vk-device.cpp')
| -rw-r--r-- | src/vk-device.cpp | 1311 |
1 files changed, 1311 insertions, 0 deletions
diff --git a/src/vk-device.cpp b/src/vk-device.cpp new file mode 100644 index 0000000..6fa3533 --- /dev/null +++ b/src/vk-device.cpp @@ -0,0 +1,1311 @@ +#include "vk-device.hpp" + +#define VMA_IMPLEMENTATION +#include <vk_mem_alloc.h> + +static VkShaderModule create_shader_module(VkDevice device, uint8_t* code, size_t code_size) { + VkShaderModule shader_module; + VkShaderModuleCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .codeSize = code_size, + .pCode = reinterpret_cast<uint32_t*>(code), + }; + + VKCHECK(vkCreateShaderModule(device, &create_info, nullptr, &shader_module)); + return shader_module; +} + + +vkdevice vkdevice::render_device = vkdevice(); + +void vkdevice::init() { + queues[static_cast<uint32_t>(QueueType::GRAPHICS)] = { + .usages = VK_QUEUE_GRAPHICS_BIT | + VK_QUEUE_COMPUTE_BIT | + VK_QUEUE_TRANSFER_BIT, + }; + queues[static_cast<uint32_t>(QueueType::ASYNC_COMPUTE)] = { + .usages = VK_QUEUE_COMPUTE_BIT, + }; + queues[static_cast<uint32_t>(QueueType::TRANSFER)] = { + .usages = VK_QUEUE_TRANSFER_BIT, + }; + + load_vulkan(); + + create_instance(); + +#ifdef _DEBUG + create_debug_layer_callback(); +#endif // _DEBUG + + create_device(); + + create_memory_allocator(); + + bindless.init(); + + auto semaphore = create_semaphore({ + .type = VK_SEMAPHORE_TYPE_TIMELINE, + }, "timeline_semaphore"); + timeline_semaphore = get_semaphore(semaphore); +} + +void vkdevice::deinit() { + vkDeviceWaitIdle(device); + + bindless.deinit(); + + vmaDestroyAllocator(gpu_allocator); + + for (auto& queue : queues) { + vkDestroyCommandPool(device, queue.command_pool, nullptr); + } + + vkDestroySemaphore(device, timeline_semaphore.vk_semaphore, nullptr); + + vkDestroyDevice(device, nullptr); + +#ifdef _DEBUG + vkDestroyDebugUtilsMessengerEXT(instance, debug_messenger, nullptr); +#endif // _DEBUG + + vkDestroyInstance(instance, nullptr); +} + + +void vkdevice::wait() { vkDeviceWaitIdle(device); }; + +handle<device_texture> vkdevice::create_texture(const texture_desc& desc) { + device_texture device_texture; + // TODO: This must always be present since we want to display images in ImGui + const_cast<texture_desc&>(desc).usages |= VK_IMAGE_USAGE_SAMPLED_BIT; + device_texture.init(desc); + + return textures.add(device_texture); +} + +handle<device_sampler> vkdevice::create_sampler(const sampler_desc& desc) { + device_sampler device_sampler; + device_sampler.init(desc); + + return samplers.add(device_sampler); +} + +handle<device_buffer> vkdevice::create_buffer(const buffer_desc& desc) { + device_buffer device_buffer{ + .size = desc.size, + .usages = desc.usages, + .name = desc.name, + }; + + VkBufferCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .size = desc.size, + .usage = desc.usages, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + }; + + VmaAllocatorCreateFlags alloc_create_flags = + desc.memory_usage != VMA_MEMORY_USAGE_GPU_ONLY ? VMA_ALLOCATION_CREATE_MAPPED_BIT : 0U; + + VmaAllocationCreateInfo alloc_create_info{ + .flags = alloc_create_flags, + .usage = static_cast<VmaMemoryUsage>(desc.memory_usage), + .requiredFlags = desc.memory_properties, + .preferredFlags = 0U, + .memoryTypeBits = 0U, + .pool = nullptr, + .pUserData = nullptr, + }; + + VmaAllocationInfo alloc_info{}; + + VKCHECK(vmaCreateBuffer(gpu_allocator, &create_info, &alloc_create_info, &device_buffer.vk_buffer, &device_buffer.alloc, &alloc_info)); + vmaSetAllocationName(render_device.get_allocator(), device_buffer.alloc, desc.name); + + if ((desc.usages & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) != 0U) { + VkBufferDeviceAddressInfo address_info { + .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + .pNext = nullptr, + .buffer = device_buffer.vk_buffer, + }; + device_buffer.device_address = vkGetBufferDeviceAddress(device, &address_info); + } + + device_buffer.mapped_ptr = alloc_info.pMappedData; + + return buffers.add(device_buffer); +} + +handle<device_pipeline> vkdevice::create_graphics_pipeline(const graphics_pipeline_desc& desc) { + device_pipeline device_pipeline{ + }; + + VkPipelineShaderStageCreateInfo shader_stages_create_info[2U]{ { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = create_shader_module(device, desc.vs_code, desc.vs_code_size), + .pName = "main", + .pSpecializationInfo = nullptr, + }, + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .module = create_shader_module(device, desc.fs_code, desc.fs_code_size), + .pName = "main", + .pSpecializationInfo = nullptr, + }, + }; + + VkPipelineVertexInputStateCreateInfo vertex_input_state_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + }; + + VkPipelineInputAssemblyStateCreateInfo input_assembly_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + .primitiveRestartEnable = VK_FALSE, + }; + + VkPipelineViewportStateCreateInfo viewport_state_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .viewportCount = 1U, + .pViewports = nullptr, + .scissorCount = 1U, + .pScissors = nullptr, + }; + + VkPipelineRasterizationStateCreateInfo rasterization_state_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .depthClampEnable = VK_FALSE, + .rasterizerDiscardEnable = VK_FALSE, + .polygonMode = VK_POLYGON_MODE_FILL, + .cullMode = VK_CULL_MODE_NONE, + .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, + .depthBiasEnable = VK_FALSE, + .lineWidth = 1.f, + }; + + VkPipelineMultisampleStateCreateInfo multisample_state_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, + .sampleShadingEnable = VK_FALSE, + .minSampleShading = 1.f, + }; + + VkPipelineColorBlendAttachmentState color_attachment_state{ + .blendEnable = VK_TRUE, + .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, + .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .alphaBlendOp = VK_BLEND_OP_ADD, + .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, + }; + + VkPipelineColorBlendStateCreateInfo color_blend_state_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .logicOpEnable = VK_FALSE, + .attachmentCount = 1, + .pAttachments = &color_attachment_state, + }; + + VkDynamicState dynamic_states[]{ + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + }; + + VkPipelineDynamicStateCreateInfo dynamic_state_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .dynamicStateCount = sizeof(dynamic_states) / sizeof(VkDynamicState), + .pDynamicStates = dynamic_states, + }; + + VkPipelineRenderingCreateInfo pipeline_rendering_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, + .pNext = nullptr, + .viewMask = 0U, + .colorAttachmentCount = static_cast<uint32_t>(desc.color_attachments_format.size()), + .pColorAttachmentFormats = desc.color_attachments_format.data(), + .depthAttachmentFormat = VK_FORMAT_UNDEFINED, + .stencilAttachmentFormat = VK_FORMAT_UNDEFINED, + }; + + VkGraphicsPipelineCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = &pipeline_rendering_create_info, + .flags = 0U, + .stageCount = sizeof(shader_stages_create_info) / sizeof(VkPipelineShaderStageCreateInfo), + .pStages = shader_stages_create_info, + .pVertexInputState = &vertex_input_state_create_info, + .pInputAssemblyState = &input_assembly_create_info, + .pTessellationState = nullptr, + .pViewportState = &viewport_state_create_info, + .pRasterizationState = &rasterization_state_create_info, + .pMultisampleState = &multisample_state_create_info, + .pDepthStencilState = nullptr, + .pColorBlendState = &color_blend_state_create_info, + .pDynamicState = &dynamic_state_create_info, + .layout = bindless.global_layout, + .renderPass = nullptr, + .subpass = 0U, + .basePipelineHandle = nullptr, + .basePipelineIndex = 0, + }; + + device_pipeline.bind_point = VK_PIPELINE_BIND_POINT_GRAPHICS; + VKCHECK(vkCreateGraphicsPipelines(device, nullptr, 1U, &create_info, nullptr, &device_pipeline.vk_pipeline)); + + for(auto& stage_create_info : shader_stages_create_info) { + vkDestroyShaderModule(device, stage_create_info.module, nullptr); + } + + if (desc.name) { + VkDebugUtilsObjectNameInfoEXT object_name{ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + .pNext = nullptr, + .objectType = VK_OBJECT_TYPE_PIPELINE, + .objectHandle = reinterpret_cast<uint64_t>(device_pipeline.vk_pipeline), + .pObjectName = desc.name, + }; + vkSetDebugUtilsObjectNameEXT(device, &object_name); + } + + return pipelines.add(device_pipeline); +} + +handle<device_pipeline> vkdevice::create_compute_pipeline(const compute_pipeline_desc& desc) { + device_pipeline device_pipeline{ + }; + + VkPipelineShaderStageCreateInfo stage_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .stage = VK_SHADER_STAGE_COMPUTE_BIT, + .module = create_shader_module(device, desc.cs_code, desc.cs_code_size), + .pName = "main", + .pSpecializationInfo = nullptr, + }; + + VkComputePipelineCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .stage = stage_create_info, + .layout = bindless.global_layout, + .basePipelineHandle = nullptr, + .basePipelineIndex = 0, + }; + + device_pipeline.bind_point = VK_PIPELINE_BIND_POINT_COMPUTE; + VKCHECK(vkCreateComputePipelines(device, nullptr, 1U, &create_info, nullptr, &device_pipeline.vk_pipeline)); + + vkDestroyShaderModule(device, stage_create_info.module, nullptr); + + if (desc.name) { + VkDebugUtilsObjectNameInfoEXT object_name{ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + .pNext = nullptr, + .objectType = VK_OBJECT_TYPE_PIPELINE, + .objectHandle = reinterpret_cast<uint64_t>(device_pipeline.vk_pipeline), + .pObjectName = desc.name, + }; + vkSetDebugUtilsObjectNameEXT(device, &object_name); + } + + return pipelines.add(device_pipeline); +} + +handle<device_surface> vkdevice::create_surface(const surface_desc& desc) { + device_surface device_surface { + }; + + { + VkWin32SurfaceCreateInfoKHR create_info{ + .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, + .pNext = nullptr, + .flags = 0U, + .hinstance = GetModuleHandle(nullptr), + .hwnd = desc.window_handle, + }; + + VKCHECK(vkCreateWin32SurfaceKHR(instance, &create_info, nullptr, &device_surface.vk_surface)); + } + + create_swapchain(desc, device_surface); + + assert(surface_desc::max_image_count >= device_surface.image_count); + + for (uint32_t index = 0u; index < device_surface.image_count; index++) { + device_surface.acquire_semaphores[index] = create_semaphore({ + .type = VK_SEMAPHORE_TYPE_BINARY, + }, "acquire_semaphore"); + device_surface.submit_semaphores[index] = create_semaphore({ + .type = VK_SEMAPHORE_TYPE_BINARY, + }, "submit_semaphore"); + } + + return surfaces.add(device_surface); +} + +handle<device_semaphore> vkdevice::create_semaphore(const semaphore_desc& desc, const char* name) { + device_semaphore semaphore { + .value = desc.initial_value, + }; + VkSemaphoreTypeCreateInfo semaphore_type_create_info{ + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, + .pNext = nullptr, + .semaphoreType = desc.type, + .initialValue = desc.initial_value, + }; + + VkSemaphoreCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .pNext = &semaphore_type_create_info, + .flags = 0U, + }; + + VKCHECK(vkCreateSemaphore(device, &create_info, nullptr, &semaphore.vk_semaphore)); + + if (name) { + VkDebugUtilsObjectNameInfoEXT object_name{ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + .pNext = nullptr, + .objectType = VK_OBJECT_TYPE_SEMAPHORE, + .objectHandle = reinterpret_cast<uint64_t>(semaphore.vk_semaphore), + .pObjectName = name, + }; + vkSetDebugUtilsObjectNameEXT(device, &object_name); + } + return semaphores.add(semaphore); +} + +void vkdevice::destroy_texture(handle<device_texture> handle) { + auto& texture = get_texture(handle); + + texture.release(); + textures.remove(handle); +} + +void vkdevice::destroy_buffer(handle<device_buffer> handle) { + const auto& buffer = get_buffer(handle); + + vmaDestroyBuffer(gpu_allocator, buffer.vk_buffer, buffer.alloc); + buffers.remove(handle); +} + +void vkdevice::destroy_pipeline(handle<device_pipeline> handle) { + const auto& pipeline = vkdevice::get_pipeline(handle); + + vkDestroyPipeline(device, pipeline.vk_pipeline, nullptr); + pipelines.remove(handle); +} + +void vkdevice::destroy_semaphore(handle<device_semaphore> handle) { + auto& semaphore = vkdevice::get_semaphore(handle); + + vkDestroySemaphore(device, semaphore.vk_semaphore, nullptr); + semaphores.remove(handle); +} + +void vkdevice::destroy_surface(handle<device_surface> handle) { + auto& surface = vkdevice::get_surface(handle); + + for (auto texture_index{0U}; texture_index < surface.image_count; texture_index++) { + auto texture_handle = surface.swapchain_images[texture_index]; + destroy_texture(texture_handle); + } + + for (uint32_t index = 0u; index < surface.image_count; index++) { + destroy_semaphore(surface.acquire_semaphores[index]); + destroy_semaphore(surface.submit_semaphores[index]); + } + + vkDestroySwapchainKHR(device, surface.vk_swapchain, nullptr); + + vkDestroySurfaceKHR(instance, surface.vk_surface, nullptr); +} + +// uint64_t vkdevice::submit(std::span<command_buffer> buffers, handle<device_semaphore> wait_handle, handle<device_semaphore> signal_handle, handle<device_semaphore> fence_handle) { +// assert((max_submitable_command_buffers - buffers.size()) >= 0); +// const auto queue_type = buffers[0].queue_type; +// +// VkCommandBufferSubmitInfo command_buffers_info[buffers.size()]; +// +// for (auto index{ 0U }; index < buffers.size(); index++) { +// assert(queue_type == buffers[index].queue_type); +// +// auto& command_buffer_info = command_buffers_info[index]; +// command_buffer_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO; +// command_buffer_info.pNext = nullptr; +// command_buffer_info.commandBuffer = buffers[index].vk_command_buffer; +// command_buffer_info.deviceMask = 0U; +// } +// +// VkSemaphoreSubmitInfo wait_semaphore_info{ +// .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, +// .pNext = nullptr, +// .stageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT, +// .deviceIndex = 0U, +// }; +// +// VkSemaphoreSubmitInfo signal_semaphore_infos[2U]; +// +// VkSubmitInfo2 submit_info{ +// .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, +// .pNext = nullptr, +// .flags = 0U, +// .waitSemaphoreInfoCount = 0U, +// .commandBufferInfoCount = static_cast<uint32_t>(buffers.size()), +// .pCommandBufferInfos = command_buffers_info, +// .pSignalSemaphoreInfos = signal_semaphore_infos, +// }; +// +// if (wait_handle.is_valid()) { +// const auto& wait = vkdevice::get_render_device().get_semaphore(wait_handle); +// wait_semaphore_info.semaphore = wait.vk_semaphore; +// wait_semaphore_info.value = wait.value; +// submit_info.waitSemaphoreInfoCount++; +// submit_info.pWaitSemaphoreInfos = &wait_semaphore_info; +// } +// +// if (signal_handle.is_valid()) { +// auto& signal = vkdevice::get_render_device().get_semaphore(signal_handle); +// signal_semaphore_infos[0U] = { +// .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, +// .pNext = nullptr, +// .semaphore = signal.vk_semaphore, +// .value = signal.value, +// .stageMask = VK_PIPELINE_STAGE_2_NONE, +// .deviceIndex = 0U, +// }; +// submit_info.signalSemaphoreInfoCount++; +// } +// +// uint64_t ret = -1; +// +// if (fence_handle.is_valid()) { +// auto& fence = vkdevice::get_render_device().get_semaphore(fence_handle); +// auto fence_index = submit_info.signalSemaphoreInfoCount; +// signal_semaphore_infos[fence_index] = { +// .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, +// .pNext = nullptr, +// .semaphore = fence.vk_semaphore, +// .value = ++fence.value, +// .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, +// .deviceIndex = 0U, +// }; +// ret = fence.value; +// } +// +// VKCHECK(vkQueueSubmit2(queues[static_cast<uint32_t>(queue_type)].vk_queue, 1, &submit_info, nullptr)); +// +// return ret; +// } + +uint64_t vkdevice::submit(command_buffer* cmd_buffers, uint32_t count) { + assert((max_submitable_command_buffers - count) >= 0); + const auto queue_type = cmd_buffers[0].queue_type; + + // VkCommandBufferSubmitInfo command_buffers_info[count]; + VkCommandBufferSubmitInfo command_buffers_info[max_submitable_command_buffers]; + + for (auto index{ 0U }; index < count; index++) { + assert(queue_type == cmd_buffers[index].queue_type); + + auto& command_buffer_info = command_buffers_info[index]; + command_buffer_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO; + command_buffer_info.pNext = nullptr; + command_buffer_info.commandBuffer = cmd_buffers[index].vk_command_buffer; + command_buffer_info.deviceMask = 0U; + } + + VkSubmitInfo2 submit_info{ + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + .pNext = nullptr, + .flags = 0U, + .waitSemaphoreInfoCount = 0U, + .pWaitSemaphoreInfos = nullptr, + .commandBufferInfoCount = count, + .pCommandBufferInfos = command_buffers_info, + }; + + auto& fence = timeline_semaphore; + VkSemaphoreSubmitInfo signal_semaphore_infos[] = { + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .pNext = nullptr, + .semaphore = fence.vk_semaphore, + .value = ++fence.value, + .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + .deviceIndex = 0U, + }, + }; + submit_info.signalSemaphoreInfoCount = sizeof(signal_semaphore_infos) / sizeof(signal_semaphore_infos[0U]); + submit_info.pSignalSemaphoreInfos = signal_semaphore_infos; + + VKCHECK(vkQueueSubmit2(queues[static_cast<uint32_t>(queue_type)].vk_queue, 1, &submit_info, nullptr)); + + return fence.value; +} + +uint64_t vkdevice::submit_before_present(handle<device_surface> surface_handle, command_buffer* cmd_buffers, uint32_t count) { + assert((max_submitable_command_buffers - count) >= 0); + const QueueType queue_type = cmd_buffers[0].queue_type; + + // VkCommandBufferSubmitInfo command_buffers_info[count]; + VkCommandBufferSubmitInfo command_buffers_info[max_submitable_command_buffers]; + + for (uint32_t index{ 0U }; index < count; index++) { + assert(queue_type == cmd_buffers[index].queue_type); + + auto& command_buffer_info = command_buffers_info[index]; + command_buffer_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO; + command_buffer_info.pNext = nullptr; + command_buffer_info.commandBuffer = cmd_buffers[index].vk_command_buffer; + command_buffer_info.deviceMask = 0U; + } + + const device_surface& surface = get_surface(surface_handle); + device_semaphore& wait = get_semaphore(surface.acquire_semaphores[surface.frame_index]); + VkSemaphoreSubmitInfo wait_semaphore_info = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .pNext = nullptr, + .semaphore = wait.vk_semaphore, + .value = wait.value, + .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + .deviceIndex = 0U, + }; + + VkSubmitInfo2 submit_info{ + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + .pNext = nullptr, + .flags = 0U, + .waitSemaphoreInfoCount = 1U, + .pWaitSemaphoreInfos = &wait_semaphore_info, + .commandBufferInfoCount = count, + .pCommandBufferInfos = command_buffers_info, + }; + + auto& fence = timeline_semaphore; + auto& signal = get_semaphore(surface.submit_semaphores[surface.frame_index]); + VkSemaphoreSubmitInfo signal_semaphore_infos[] = { + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .pNext = nullptr, + .semaphore = fence.vk_semaphore, + .value = ++fence.value, + .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + .deviceIndex = 0U, + }, + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .pNext = nullptr, + .semaphore = signal.vk_semaphore, + .value = signal.value, + .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + .deviceIndex = 0U, + }, + }; + submit_info.signalSemaphoreInfoCount = sizeof(signal_semaphore_infos) / sizeof(signal_semaphore_infos[0U]); + submit_info.pSignalSemaphoreInfos = signal_semaphore_infos; + + VKCHECK(vkQueueSubmit2(queues[static_cast<uint32_t>(queue_type)].vk_queue, 1, &submit_info, nullptr)); + + return fence.value; +} + +void vkdevice::present(handle<device_surface> surface_handle) { + auto& surface = render_device.get_surface(surface_handle); + VkResult result; + VkPresentInfoKHR present_info{ + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .pNext = nullptr, + .swapchainCount = 1U, + .pSwapchains = &surface.vk_swapchain, + .pImageIndices = &surface.image_index, + .pResults = &result, + }; + + const auto& semaphore = get_semaphore(surface.submit_semaphores[surface.frame_index]); + present_info.waitSemaphoreCount = 1U; + present_info.pWaitSemaphores = &semaphore.vk_semaphore; + + VKCHECK(vkQueuePresentKHR(queues[static_cast<uint32_t>(QueueType::GRAPHICS)].vk_queue, &present_info)); + + VKCHECK(result); + surface.frame_index = (surface.frame_index + 1) % surface.image_count; +} + +// private +void vkdevice::allocate_command_buffers(command_buffer* cmd_buffers, size_t count, QueueType type, const char* name) { + assert((max_allocable_command_buffers - count) >= 0); + const auto& queue = queues[static_cast<uint32_t>(type)]; + VkCommandBuffer command_buffers[max_allocable_command_buffers]; + + VkCommandBufferAllocateInfo allocate_info{ + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .pNext = nullptr, + .commandPool = queue.command_pool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = static_cast<uint32_t>(count), + }; + + VKCHECK(vkAllocateCommandBuffers(device, &allocate_info, command_buffers)); + + for (uint32_t index{ 0U }; index < count; index++) { + cmd_buffers[index].vk_command_buffer = command_buffers[index]; + cmd_buffers[index].queue_type = type; + + if (name) { + VkDebugUtilsObjectNameInfoEXT object_name{ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + .pNext = nullptr, + .objectType = VK_OBJECT_TYPE_COMMAND_BUFFER, + .objectHandle = reinterpret_cast<uint64_t>(command_buffers[index]), + .pObjectName = name, + }; + vkSetDebugUtilsObjectNameEXT(device, &object_name); + } + } +} + +void vkdevice::create_swapchain(const surface_desc& desc, device_surface& surface) { + VkSurfaceKHR vk_surface = surface.vk_surface; + + auto& queue = queues[static_cast<uint32_t>(QueueType::GRAPHICS)]; + + { + VkBool32 supported = VK_FALSE; + VKCHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue.index, vk_surface, &supported)); + + assert(supported); + } + + VkSurfaceCapabilitiesKHR surface_capabilities; + VKCHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, vk_surface, &surface_capabilities)); + + VkExtent2D extent = surface_capabilities.currentExtent; + if (extent.width < surface_capabilities.minImageExtent.width) { + extent.width = surface_capabilities.minImageExtent.width; + } else if (extent.width > surface_capabilities.maxImageExtent.width) { + extent.width = surface_capabilities.maxImageExtent.width; + } + + if (extent.height < surface_capabilities.minImageExtent.height) { + extent.height = surface_capabilities.minImageExtent.height; + } else if (extent.height > surface_capabilities.maxImageExtent.height) { + extent.height = surface_capabilities.maxImageExtent.height; + } + + { + auto supported = false; + auto supported_formats_count = 0U; + VKCHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, vk_surface, &supported_formats_count, nullptr)); + + std::vector<VkSurfaceFormatKHR> supported_formats{ supported_formats_count }; + VKCHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, vk_surface, &supported_formats_count, supported_formats.data())); + + for (auto& surface_format : supported_formats) { + if (surface_format.format == desc.surface_format.format && + surface_format.colorSpace == desc.surface_format.colorSpace) { + supported = true; + break; + } + } + + assert(supported); + } + + { + auto supported = false; + auto supported_present_modes_count = 0U; + VKCHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, vk_surface, &supported_present_modes_count, nullptr)); + + std::vector<VkPresentModeKHR> supported_present_modes{ supported_present_modes_count }; + VKCHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, vk_surface, &supported_present_modes_count, supported_present_modes.data())); + + for (auto& present_mode : supported_present_modes) { + if (present_mode == desc.present_mode) { + supported = true; + break; + } + } + + assert(supported); + } + + assert(desc.image_count >= surface_capabilities.minImageCount); + assert(desc.image_count <= surface_capabilities.maxImageCount); + + VkSwapchainCreateInfoKHR create_info = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .pNext = nullptr, + .flags = 0U, + .surface = vk_surface, + .minImageCount = desc.image_count, + .imageFormat = desc.surface_format.format, + .imageColorSpace = desc.surface_format.colorSpace, + .imageExtent = extent, + .imageArrayLayers = 1U, + .imageUsage = desc.usages, + .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0U, + .pQueueFamilyIndices = nullptr, + .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR, + .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + .presentMode = desc.present_mode, + .clipped = VK_TRUE, + .oldSwapchain = nullptr, + }; + + VKCHECK(vkCreateSwapchainKHR(device, &create_info, nullptr, &surface.vk_swapchain)); + + surface.surface_format = desc.surface_format; + + vkGetSwapchainImagesKHR(device, surface.vk_swapchain, &surface.image_count, nullptr); + assert(surface.image_count <= surface_desc::max_image_count); + + std::vector<VkImage> images {surface.image_count}; + vkGetSwapchainImagesKHR(device, surface.vk_swapchain, &surface.image_count, images.data()); + + for (auto index {0U}; index < surface.image_count; index++) { + surface.swapchain_images[index] = create_texture({ + .width = extent.width, + .height = extent.height, + .depth = 1U, + .mips = 1U, + .usages = desc.usages, + .format = desc.surface_format.format, + .type = VK_IMAGE_TYPE_2D, + .vk_image = images[index], + .name = "swapchain image" + }); + } +} + +// ----------------- vkadapter ----------------- + +void vkdevice::create_instance() { + VkApplicationInfo app_info{ + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pApplicationName = "path-tracer", + .applicationVersion = VK_MAKE_VERSION(1, 0, 0), + .pEngineName = "gpu-path-tracer", + .engineVersion = VK_MAKE_VERSION(1, 0, 0), + .apiVersion = VK_API_VERSION_1_3, + }; + + constexpr const char* instance_layers[]{ + "VK_LAYER_KHRONOS_validation", + }; + + constexpr const char* instance_extensions[]{ + VK_EXT_DEBUG_UTILS_EXTENSION_NAME, + "VK_KHR_surface", + "VK_KHR_win32_surface" + }; + + VkInstanceCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .pApplicationInfo = &app_info, + .enabledLayerCount = sizeof(instance_layers) / sizeof(instance_layers[0]), + .ppEnabledLayerNames = instance_layers, + .enabledExtensionCount = sizeof(instance_extensions) / sizeof(instance_extensions[0]), + .ppEnabledExtensionNames = instance_extensions, + }; + + VKCHECK(vkCreateInstance(&create_info, nullptr, &instance)); + + load_instance_functions(instance); +} + +void vkdevice::create_device() { + pick_physical_device(); + + float queue_priority = 1.f; + VkDeviceQueueCreateInfo queue_create_infos[static_cast<uint32_t>(QueueType::MAX)]; + + for (auto& queue_create_info : queue_create_infos) { + queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queue_create_info.pNext = nullptr; + queue_create_info.flags = 0U; + queue_create_info.queueCount = 1; + queue_create_info.pQueuePriorities = &queue_priority; + } + + auto queue_properties_count = 0U; + vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_properties_count, nullptr); + + std::vector<VkQueueFamilyProperties> queue_properties{ queue_properties_count }; + vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_properties_count, queue_properties.data()); + + for (auto index{ 0U }; index < static_cast<uint32_t>(QueueType::MAX); index++) { + auto& queue = queues[index]; + + for (auto properties_index{ 0U }; properties_index < queue_properties_count; properties_index++) { + auto& queue_property = queue_properties[properties_index]; + + if ((queue_property.queueFlags & queue.usages) == queue.usages) { + queue_create_infos[index].queueFamilyIndex = queue.index = properties_index; + queue_property.queueFlags = 0U; + } + } + } + + constexpr const char* device_extensions[] = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + // VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME + }; + + VkPhysicalDeviceVulkan12Features physical_device_12_features{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, + .pNext = nullptr, + .shaderSampledImageArrayNonUniformIndexing = VK_TRUE, + .shaderStorageImageArrayNonUniformIndexing = VK_TRUE, + .descriptorBindingUpdateUnusedWhilePending = VK_TRUE, + .descriptorBindingPartiallyBound = VK_TRUE, + .runtimeDescriptorArray = VK_TRUE, + .timelineSemaphore = VK_TRUE, + .bufferDeviceAddress = VK_TRUE, + }; + + VkPhysicalDeviceVulkan13Features physical_device_13_features{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, + .pNext = &physical_device_12_features, + .synchronization2 = VK_TRUE, + .dynamicRendering = VK_TRUE, + }; + + VkDeviceCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pNext = &physical_device_13_features, + .flags = 0U, + .queueCreateInfoCount = static_cast<uint32_t>(QueueType::MAX), + .pQueueCreateInfos = queue_create_infos, + .enabledLayerCount = 0, + .ppEnabledLayerNames = nullptr, + .enabledExtensionCount = sizeof(device_extensions) / sizeof(device_extensions[0]), + .ppEnabledExtensionNames = device_extensions, + .pEnabledFeatures = nullptr, + }; + + VKCHECK(vkCreateDevice(physical_device, &create_info, nullptr, &device)); + + load_device_functions(device); + + for (auto& queue : queues) { + vkGetDeviceQueue(device, queue.index, 0, &queue.vk_queue); + } + + create_command_pools(); +} + +void vkdevice::create_memory_allocator() { + VmaVulkanFunctions functions = { + .vkGetInstanceProcAddr = vkGetInstanceProcAddr, + .vkGetDeviceProcAddr = vkGetDeviceProcAddr, + }; + VmaAllocatorCreateInfo create_info{ + .flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT, + .physicalDevice = physical_device, + .device = device, + .pVulkanFunctions = &functions, + .instance = instance, + .vulkanApiVersion = VK_API_VERSION_1_2, + }; + + VKCHECK(vmaCreateAllocator(&create_info, &gpu_allocator)); +} + +void vkdevice::create_command_pools() { + VkCommandPoolCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .pNext = nullptr, + .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, + }; + + for (auto& queue : queues) { + create_info.queueFamilyIndex = queue.index; + + VKCHECK(vkCreateCommandPool(device, &create_info, nullptr, &queue.command_pool)); + } +} + +void vkdevice::pick_physical_device() { + auto physical_devices_count = 0U; + vkEnumeratePhysicalDevices(instance, &physical_devices_count, nullptr); + + assert(physical_devices_count > 0); + + std::vector<VkPhysicalDevice> physical_devices{ physical_devices_count }; + vkEnumeratePhysicalDevices(instance, &physical_devices_count, physical_devices.data()); + + physical_device_props = VkPhysicalDeviceProperties2 { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, + .pNext = nullptr, + }; + + for (auto& physical_dev : physical_devices) { + if (device_support_features(physical_dev)) { + physical_device = physical_dev; + + return; + } + } + + assert(true); +} + +bool vkdevice::device_support_features(VkPhysicalDevice physical_dev) { + // limits + { + vkGetPhysicalDeviceProperties2(physical_dev, &physical_device_props); + + VkPhysicalDeviceLimits* limits = &physical_device_props.properties.limits; + if (limits->maxPerStageDescriptorSampledImages < 0x10000 || + limits->maxPerStageDescriptorStorageImages < 0x10000 || + limits->maxDescriptorSetSampledImages < 0x10000 || + limits->maxDescriptorSetStorageImages < 0x10000) { + return false; + } + } + + // Vulkan 1.2 physical device features support + { + VkPhysicalDeviceVulkan12Features vulkan_12_features{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, + }; + + VkPhysicalDeviceFeatures2 physical_device_features{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + .pNext = &vulkan_12_features, + }; + + vkGetPhysicalDeviceFeatures2(physical_dev, &physical_device_features); + + // clang-format off + if (vulkan_12_features.bufferDeviceAddress == VK_FALSE || + vulkan_12_features.runtimeDescriptorArray == VK_FALSE || + vulkan_12_features.shaderStorageImageArrayNonUniformIndexing == VK_FALSE || + vulkan_12_features.shaderSampledImageArrayNonUniformIndexing == VK_FALSE || + vulkan_12_features.descriptorBindingPartiallyBound == VK_FALSE || + vulkan_12_features.descriptorBindingUpdateUnusedWhilePending == VK_FALSE || + vulkan_12_features.imagelessFramebuffer == VK_FALSE) { + return false; + } + // clang-format on + } + + // Vulkan 1.3 physical device features support + { + VkPhysicalDeviceVulkan13Features vulkan_13_features{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, + .pNext = nullptr, + }; + + VkPhysicalDeviceFeatures2 physical_device_features{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + .pNext = &vulkan_13_features, + }; + + vkGetPhysicalDeviceFeatures2(physical_dev, &physical_device_features); + + if (vulkan_13_features.synchronization2 == VK_FALSE || + vulkan_13_features.dynamicRendering == VK_FALSE) { + return false; + } + } + + return true; +} + +void vkdevice::create_debug_layer_callback() { +#ifdef _DEBUG + VkDebugUtilsMessengerCreateInfoEXT create_info{ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .pNext = nullptr, + .flags = 0U, + .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT, + .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, + .pfnUserCallback = debug_callback, + .pUserData = nullptr, + }; + + VKCHECK(vkCreateDebugUtilsMessengerEXT(instance, &create_info, nullptr, &debug_messenger)); +#endif // _DEBUG +} + + +idlist<> device_texture::sampled_indices = {}; +idlist<> device_texture::storage_indices = {}; +idlist<> device_sampler::sampler_indices = {}; + +void device_texture::init(const texture_desc& desc) { + auto& render_device = vkdevice::get(); + const auto& bindless = render_device.get_bindingmodel(); + auto* device = render_device.get_device(); + + vk_image = desc.vk_image; + format = desc.format; + width = desc.width; + height = desc.height; + mips = desc.mips; + name = desc.name; + aspects = ((desc.usages & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0U) + ? VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT + : VK_IMAGE_ASPECT_COLOR_BIT; + + assert(mips <= texture_desc::max_mips); + + if (vk_image == nullptr) { + VkImageCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .imageType = desc.type, + .format = desc.format, + .extent = { + .width = desc.width, + .height = desc.height, + .depth = desc.depth + }, + .mipLevels = desc.mips, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = desc.usages, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }; + + VmaAllocationCreateInfo alloc_create_info{ + .flags = 0U, + .usage = VMA_MEMORY_USAGE_GPU_ONLY, + .requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + .preferredFlags = 0U, + .memoryTypeBits = 0U, + .pool = nullptr, + .pUserData = nullptr, + }; + + VKCHECK(vmaCreateImage(render_device.get_allocator(), &create_info, &alloc_create_info, &vk_image, &alloc, nullptr)); + vmaSetAllocationName(render_device.get_allocator(), alloc, desc.name); + } + + if (desc.name) { + VkDebugUtilsObjectNameInfoEXT object_name{ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + .pNext = nullptr, + .objectType = VK_OBJECT_TYPE_IMAGE, + .objectHandle = reinterpret_cast<uint64_t>(vk_image), + .pObjectName = desc.name, + }; + vkSetDebugUtilsObjectNameEXT(device, &object_name); + } + + create_views(); + + // TODO: Handle mips views + VkDescriptorImageInfo images_info[]{ + { + nullptr, + whole_view, + VK_IMAGE_LAYOUT_GENERAL, + }, + }; + + std::vector<VkWriteDescriptorSet> write_descriptor_sets; + if ((desc.usages & VK_IMAGE_USAGE_STORAGE_BIT) != 0) { + storage_index = storage_indices.add(); + + write_descriptor_sets.push_back({ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + // .dstSet = bindless.sets[BindlessSetType::GLOBAL], + .dstSet = bindless.global_set, + .dstBinding = 2U, + .dstArrayElement = storage_index.id, + .descriptorCount = sizeof(images_info) / sizeof(VkDescriptorImageInfo), + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .pImageInfo = images_info, + .pBufferInfo = nullptr, + .pTexelBufferView = nullptr, + }); + } + if ((desc.usages & VK_IMAGE_USAGE_SAMPLED_BIT) != 0) { + sampled_index = sampled_indices.add(); + + write_descriptor_sets.push_back({ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + // .dstSet = bindless.sets[BindlessSetType::GLOBAL], + .dstSet = bindless.global_set, + .dstBinding = 1U, + .dstArrayElement = sampled_index.id, + .descriptorCount = sizeof(images_info) / sizeof(VkDescriptorImageInfo), + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .pImageInfo = images_info, + .pBufferInfo = nullptr, + .pTexelBufferView = nullptr, + }); + } + + vkUpdateDescriptorSets(device, static_cast<uint32_t>(write_descriptor_sets.size()), write_descriptor_sets.data(), 0U, nullptr); +} + +void device_texture::release() { + auto& render_device = vkdevice::get(); + auto* device = render_device.get_device(); + auto* gpu_allocator = render_device.get_allocator(); + + if (alloc != nullptr) { + vmaDestroyImage(gpu_allocator, vk_image, alloc); + } + + vkDestroyImageView(device, whole_view, nullptr); + + for (auto mip_index{ 0U }; mip_index < mips; mip_index++) { + const auto& mip_view = mips_views[mip_index]; + vkDestroyImageView(device, mip_view, nullptr); + } + + if (storage_index.is_valid()) { + storage_indices.remove(storage_index); + } + + if (sampled_index.is_valid()) { + sampled_indices.remove(sampled_index); + } +} + +void device_texture::create_views() { + auto* device = vkdevice::get().get_device(); + + VkImageViewCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .image = vk_image, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = format, + .components = { + .r = VK_COMPONENT_SWIZZLE_R, + .g = VK_COMPONENT_SWIZZLE_G, + .b = VK_COMPONENT_SWIZZLE_B, + .a = VK_COMPONENT_SWIZZLE_A, + }, + .subresourceRange = { + .aspectMask = aspects, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + + for (auto mip_index{ 0U }; mip_index < mips; mip_index++) { + create_info.subresourceRange.baseMipLevel = mip_index; + VKCHECK(vkCreateImageView(device, &create_info, nullptr, &mips_views[mip_index])); + } + + create_info.subresourceRange.baseMipLevel = 0; + create_info.subresourceRange.levelCount = mips; + VKCHECK(vkCreateImageView(device, &create_info, nullptr, &whole_view)); +} + + +void device_sampler::init(const sampler_desc& desc) { + auto& render_device = vkdevice::get(); + // const auto& bindless = render_device.get_bindingmodel(); + auto* device = render_device.get_device(); + + VkSamplerCreateInfo sampler_create_info{ + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .magFilter = desc.mag_filter, + .minFilter = desc.min_filter, + .mipmapMode = desc.mipmap_mode, + .addressModeU = desc.address_mode_u, + .addressModeV = desc.address_mode_v, + .addressModeW = desc.address_mode_w, + .mipLodBias = desc.mip_lod_bias, + .anisotropyEnable = desc.anisotropy, + .maxAnisotropy = desc.max_anisotropy, + .compareEnable = desc.compare_enabled, + .compareOp = desc.compare_op, + .minLod = desc.min_lod, + .maxLod = desc.max_lod, + .borderColor = desc.border_color, + .unnormalizedCoordinates = desc.unnomalized_coords, + }; + + VKCHECK(vkCreateSampler(device, &sampler_create_info, nullptr, &vk_sampler)); + + sampler_index = sampler_indices.add(); + + // VkWriteDescriptorSet write_descriptor_set{ + // .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + // .pNext = nullptr, + // .dstSet = bindless.sets[BindlessSetType::GLOBAL], + // .dstBinding = 1U, + // .dstArrayElement = sampler_index.id, + // .descriptorCount = 1U, + // .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + // .pImageInfo = images_info, + // .pBufferInfo = nullptr, + // .pTexelBufferView = nullptr, + // }); +} + + +uint32_t vkdevice::acquire_image_index(handle<device_surface> surface_handle) { + auto& surface = get_surface(surface_handle); + const auto& signal = get_semaphore(surface.acquire_semaphores[surface.frame_index]); + + VkSemaphoreWaitInfo wait_info { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, + .pNext = nullptr, + .flags = 0U, + .semaphoreCount = 1U, + .pSemaphores = &timeline_semaphore.vk_semaphore, + .pValues = &timeline_semaphore.value, + }; + vkWaitSemaphores(device, &wait_info, UINT64_MAX); + VKCHECK(vkAcquireNextImageKHR(device, surface.vk_swapchain, UINT64_MAX, signal.vk_semaphore, nullptr, &surface.image_index)); + + return surface.image_index; +} |
