diff options
| author | Quentin LADEVIE <qladevie@wanadev.fr> | 2023-01-22 17:59:24 +0100 |
|---|---|---|
| committer | Quentin LADEVIE <qladevie@wanadev.fr> | 2023-01-22 17:59:24 +0100 |
| commit | 0a882c4b85423a170455f05a52d18f7fa7c9220b (patch) | |
| tree | 3bdc24d73ba7cc828fce2b93ce85f73831b12204 /api-test | |
| parent | 5e3bb454d50091e581d5d1d03af34e38277694b3 (diff) | |
Api test bindless and command buffers
Diffstat (limited to 'api-test')
| -rw-r--r-- | api-test/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | api-test/command-buffer.cpp | 123 | ||||
| -rw-r--r-- | api-test/main.cpp | 101 | ||||
| -rw-r--r-- | api-test/vk-bindless.cpp | 218 | ||||
| -rw-r--r-- | api-test/vk-device.cpp | 365 |
5 files changed, 678 insertions, 130 deletions
diff --git a/api-test/CMakeLists.txt b/api-test/CMakeLists.txt index 849f242..402ae10 100644 --- a/api-test/CMakeLists.txt +++ b/api-test/CMakeLists.txt @@ -3,6 +3,7 @@ add_executable( main.cpp vk-device.cpp command-buffer.cpp + vk-bindless.cpp ${CMAKE_SOURCE_DIR}/src/window.cpp ${CMAKE_SOURCE_DIR}/src/utils.cpp ${CMAKE_SOURCE_DIR}/src/vulkan-loader.cpp diff --git a/api-test/command-buffer.cpp b/api-test/command-buffer.cpp index 9e37f95..8d2d8c7 100644 --- a/api-test/command-buffer.cpp +++ b/api-test/command-buffer.cpp @@ -1,54 +1,117 @@ #include "command-buffer.hpp" #include <cassert> +#include <vulkan/vulkan_core.h> #include "vulkan-loader.hpp" -#include"vk-device.hpp" - -#ifdef _DEBUG -#define VKCHECK(result) assert(result == VK_SUCCESS); -#else -#define VKCHECK(result) result; -#endif +#include "vk-device.hpp" +#include "vk-utils.hpp" void command_buffer::start() const { - VkCommandBufferBeginInfo begin_info { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - .pNext = nullptr, - .flags = 0U, - .pInheritanceInfo = nullptr + VkCommandBufferBeginInfo begin_info{ + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .pNext = nullptr, + .flags = 0U, + .pInheritanceInfo = nullptr }; - VKCHECK(vkBeginCommandBuffer(handle, &begin_info)) + VKCHECK(vkBeginCommandBuffer(vk_command_buffer, &begin_info)); + + const auto& bindless = vkdevice::get_device()->get_bindingmodel(); + if (queue_type == QueueType::GRAPHICS) { + vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bindless.layout, 0, BindlessSetType::MAX, bindless.sets, 0, nullptr); + vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.layout, 0, BindlessSetType::MAX, bindless.sets, 0, nullptr); + } else if (queue_type == QueueType::ASYNC_COMPUTE) { + vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.layout, 0, BindlessSetType::MAX, bindless.sets, 0, nullptr); + } } void command_buffer::stop() const { - VKCHECK(vkEndCommandBuffer(handle)) + VKCHECK(vkEndCommandBuffer(vk_command_buffer)); } -void transfer_command_buffer::copy(::handle<device_buffer> buffer_handle, ::handle<device_texture> texture_handle) { - const auto& buffer = vkdevice::get_buffer(buffer_handle); - const auto& texture = vkdevice::get_texture(texture_handle); - VkImageSubresourceLayers image_subresource_layers { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, +void command_buffer::barrier(handle<device_texture> texture_handle, VkPipelineStageFlags2 stage, VkAccessFlags2 access, VkImageLayout layout) const { + auto& texture = vkdevice::get_device()->get_texture(texture_handle); + VkImageAspectFlags aspect_mask = ((texture.desc.usages & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0U) + ? VK_IMAGE_ASPECT_DEPTH_BIT + : VK_IMAGE_ASPECT_COLOR_BIT; + + VkImageSubresourceRange subresource_range{ + .aspectMask = aspect_mask, + .baseMipLevel = 0U, + .levelCount = 1U, + .baseArrayLayer = 0U, + .layerCount = 1U, + }; + + VkImageMemoryBarrier2 image_barrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + .pNext = nullptr, + .srcStageMask = texture.stage, + .srcAccessMask = texture.access, + .dstStageMask = stage, + .dstAccessMask = access, + .oldLayout = texture.layout, + .newLayout = layout, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = texture.vk_image, + .subresourceRange = subresource_range, + }; + + VkDependencyInfo dependency_info{ + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pNext = nullptr, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT, + .memoryBarrierCount = 0U, + .pMemoryBarriers = nullptr, + .bufferMemoryBarrierCount = 0U, + .pBufferMemoryBarriers = nullptr, + .imageMemoryBarrierCount = 1U, + .pImageMemoryBarriers = &image_barrier, + }; + vkCmdPipelineBarrier2(vk_command_buffer, &dependency_info); + + texture.layout = layout; + texture.stage = stage; + texture.access = access; +} + +void command_buffer::copy(handle<device_buffer> buffer_handle, ::handle<device_texture> texture_handle, VkDeviceSize offset) const { + auto* device = vkdevice::get_device(); + const auto& buffer = device->get_buffer(buffer_handle); + const auto& texture = device->get_texture(texture_handle); + VkImageAspectFlags aspect_mask = ((texture.desc.usages & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0U) + ? VK_IMAGE_ASPECT_DEPTH_BIT + : VK_IMAGE_ASPECT_COLOR_BIT; + VkImageSubresourceLayers image_subresource_layers{ + .aspectMask = aspect_mask, .mipLevel = 0, .baseArrayLayer = 0, .layerCount = 1, }; - VkBufferImageCopy buffer_to_image_copy { - .bufferOffset = 0, - .bufferRowLength = 0, - .bufferImageHeight = 0, - .imageSubresource = image_subresource_layers, - .imageOffset = { .x = 0, .y = 0, .z = 0 }, - .imageExtent = { - .width = texture.desc.width, - .height = texture.desc.height, - .depth = texture.desc.depth, + VkBufferImageCopy buffer_to_image_copy{ + .bufferOffset = offset, + .bufferRowLength = 0, + .bufferImageHeight = 0, + .imageSubresource = image_subresource_layers, + .imageOffset = { .x = 0, .y = 0, .z = 0 }, + .imageExtent = { + .width = texture.desc.width, + .height = texture.desc.height, + .depth = texture.desc.depth, }, }; - vkCmdCopyBufferToImage(handle, buffer.handle, texture.handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_to_image_copy); + vkCmdCopyBufferToImage(vk_command_buffer, buffer.vk_buffer, texture.vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_to_image_copy); +} + +void graphics_command_buffer::dispatch(const dispatch_params& params) { + const auto& pipeline = vkdevice::get_device()->get_pipeline(params.pipeline); + + vkCmdBindPipeline(vk_command_buffer, pipeline.bind_point, pipeline.vk_pipeline); + + vkCmdDispatch(vk_command_buffer, params.group_size.x / params.local_group_size.x, params.group_size.y / params.local_group_size.y, params.group_size.z / params.local_group_size.z); } diff --git a/api-test/main.cpp b/api-test/main.cpp index 40f5c72..4ac68ad 100644 --- a/api-test/main.cpp +++ b/api-test/main.cpp @@ -1,10 +1,14 @@ #include <cassert> #include <cstdio> +#include <span> #include <vk_mem_alloc.h> +#define STB_IMAGE_IMPLEMENTATION +#include <stb_image.h> + #include "window.hpp" #include "vk-device.hpp" -// #include "resource-manager.hpp" +#include "utils.hpp" #define ENABLE_RENDERDOC @@ -26,50 +30,97 @@ int main() { } #endif - window wnd { 1280U, 720U }; + window wnd { 640U, 360U }; #ifdef ENABLE_RENDERDOC if(rdoc_api != nullptr) rdoc_api->StartFrameCapture(nullptr, nullptr); #endif - vkdevice device { wnd }; + auto* device = vkdevice::init_device(wnd); + + constexpr size_t image_size = 1024U; + constexpr size_t image_count = 4U; + auto staging_buffer_handle = device->create_buffer({ + .size = image_size * image_size * sizeof(uint32_t) * image_count, + .usages = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, + }); + const auto& staging_buffer = device->get_buffer(staging_buffer_handle); + + int width; + int height; + int channels; + uint8_t* data = stbi_load("../models/sponza/466164707995436622.jpg", &width, &height, &channels, 4); + size_t size = static_cast<size_t>(width) * height * 4U; + memcpy(staging_buffer.mapped_ptr, data, size); - auto gpu_texture_handle = device.create_texture({ - .width = 1024U, - .height = 1024U, - .usages = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + auto gpu_texture_handle = device->create_texture({ + .width = static_cast<uint32_t>(width), + .height = static_cast<uint32_t>(height), + .usages = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT, .format = VK_FORMAT_R8G8B8A8_UNORM, - .type = VK_IMAGE_TYPE_2D, + .type = VK_IMAGE_TYPE_2D, }); - auto gpu_buffer = device.get_buffer(device.create_buffer({ - .size = 1024U * sizeof(uint32_t), - .usages = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, - .memory_properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - .memory_usage = VMA_MEMORY_USAGE_GPU_ONLY, - })); + off_t offset = width * height * 4; + data = stbi_load("../models/sponza/715093869573992647.jpg", &width, &height, &channels, 4); + size = static_cast<size_t>(width) * height * 4U; + auto* addr = static_cast<void*>(static_cast<uint8_t*>(staging_buffer.mapped_ptr) + offset); + memcpy(addr, data, size); - auto staging_buffer_handle = device.create_buffer({ - .size = 1024U * sizeof(uint32_t), - .usages = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, + auto second_texture = device->create_texture({ + .width = static_cast<uint32_t>(width), + .height = static_cast<uint32_t>(height), + .usages = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT, + .format = VK_FORMAT_R8G8B8A8_UNORM, + .type = VK_IMAGE_TYPE_2D, + }); + + auto output_texture_handle = device->create_texture({ + .width = static_cast<uint32_t>(width), + .height = static_cast<uint32_t>(height), + .usages = VK_IMAGE_USAGE_STORAGE_BIT, + .format = VK_FORMAT_R8G8B8A8_UNORM, + .type = VK_IMAGE_TYPE_2D, + }); + + // auto gpu_buffer = vkdevice::get_buffer(device.create_buffer({ + // .size = 1024U * sizeof(uint32_t), + // .usages = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + // .memory_properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + // .memory_usage = VMA_MEMORY_USAGE_GPU_ONLY, + // })); + + auto code = read_file("shaders/test.comp.spv"); + auto compute = device->create_pipeline({ + .cs_code = std::span(code), }); - auto staging_buffer = device.get_buffer(staging_buffer_handle); - uint64_t t = 7; - (*(uint64_t*)staging_buffer.mapped_ptr) = t; - transfer_command_buffer command_buffer; - device.allocate_command_buffers(&command_buffer, 1, QueueType::GRAPHICS); + graphics_command_buffer command_buffer; + device->allocate_command_buffers(&command_buffer, 1, QueueType::GRAPHICS); command_buffer.start(); + command_buffer.barrier(gpu_texture_handle, VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + command_buffer.barrier(second_texture, VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); command_buffer.copy(staging_buffer_handle, gpu_texture_handle); + command_buffer.copy(staging_buffer_handle, second_texture, static_cast<VkDeviceSize>(offset)); + + command_buffer.barrier(gpu_texture_handle, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); + command_buffer.barrier(second_texture, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_READ_BIT, VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL); + command_buffer.barrier(output_texture_handle, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); + + command_buffer.dispatch({ + .pipeline = compute, + .group_size = { image_size, image_size, 1U }, + .local_group_size = { 8U, 8U, 1U }, + }); command_buffer.stop(); - device.submit(&command_buffer, 1); + device->submit(&command_buffer, 1); #ifdef ENABLE_RENDERDOC if(rdoc_api != nullptr) rdoc_api->EndFrameCapture(nullptr, nullptr); diff --git a/api-test/vk-bindless.cpp b/api-test/vk-bindless.cpp new file mode 100644 index 0000000..d1dbf03 --- /dev/null +++ b/api-test/vk-bindless.cpp @@ -0,0 +1,218 @@ +#include "vk-bindless.hpp" + +#include "vk-utils.hpp" +#include "vulkan-loader.hpp" + +bindless_model bindless_model::create_bindless_model(VkDevice device) { + bindless_model bindless; +#ifndef USE_VK_DESCRIPTOR_BUFFER + bindless.create_immutable_samplers(device); + bindless.create_layout(device); + bindless.create_descriptor_pool(device); + bindless.allocate_sets(device); +#else + VkBufferCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .size = desc.size, + .usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + }; + + VmaAllocatorCreateFlags alloc_create_flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; + + VmaAllocationCreateInfo alloc_create_info{ + .flags = alloc_create_flags, + .usage = VMA_MEMORY_USAGE_CPU_TO_GPU, + .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)); + + device_buffer.mapped_ptr = alloc_info.pMappedData; + + return { buffers.add(device_buffer) }; +#endif + + return bindless; +} + +void bindless_model::destroy_bindless_model(VkDevice device, bindless_model& bindless) { + vkDestroyDescriptorPool(device, bindless.descriptor_pool, nullptr); + + for (auto index{ 0U }; index < BindlessSetType::MAX; index++) { + vkDestroyDescriptorSetLayout(device, bindless.sets_layout[index], nullptr); + } + + vkDestroyPipelineLayout(device, bindless.layout, nullptr); + + bindless.destroy_immutable_samplers(device); +} + +void bindless_model::create_layout(VkDevice device) { + // Set 0 global resources + // Binding 0 Storage images + // Binding 1 Sampled images + // Binding 2 Samplers + { + VkDescriptorSetLayoutBinding set_layout_bindings[]{ + { + .binding = 0U, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, + .descriptorCount = SamplerType::MAX_SAMPLER, + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers = samplers, + }, + { + .binding = 1U, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = set_descriptors_count[BindlessSetType::GLOBAL], + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers = nullptr, + }, + { + .binding = 2U, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .descriptorCount = set_descriptors_count[BindlessSetType::GLOBAL], + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers = nullptr, + }, + }; + + VkDescriptorBindingFlags flags[]{ + VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, + VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, + VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, + }; + + VkDescriptorSetLayoutBindingFlagsCreateInfo layout_binding_flags{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, + .pNext = VK_NULL_HANDLE, + .bindingCount = sizeof(flags) / sizeof(VkDescriptorBindingFlags), + .pBindingFlags = flags, + }; + + VkDescriptorSetLayoutCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .pNext = &layout_binding_flags, + .flags = 0U, + .bindingCount = sizeof(set_layout_bindings) / sizeof(VkDescriptorSetLayoutBinding), + .pBindings = set_layout_bindings, + }; + + VKCHECK(vkCreateDescriptorSetLayout(device, &create_info, nullptr, &sets_layout[BindlessSetType::GLOBAL])); + } + + VkPipelineLayoutCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .setLayoutCount = sizeof(sets_layout) / sizeof(VkDescriptorSetLayout), + .pSetLayouts = sets_layout, + .pushConstantRangeCount = 0U, + .pPushConstantRanges = nullptr, + }; + + VKCHECK(vkCreatePipelineLayout(device, &create_info, nullptr, &layout)); +} + +#ifndef USE_VK_DESCRIPTOR_BUFFER +void bindless_model::create_descriptor_pool(VkDevice device) { + VkDescriptorPoolSize pool_sizes[]{ + { + .type = VK_DESCRIPTOR_TYPE_SAMPLER, + .descriptorCount = set_descriptors_count[BindlessSetType::MAX], + }, + { + .type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = set_descriptors_count[BindlessSetType::MAX], + }, + { + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .descriptorCount = set_descriptors_count[BindlessSetType::MAX], + }, + }; + + VkDescriptorPoolCreateInfo descriptor_pool_create_info{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .maxSets = descriptor_pool_allocable_sets_count, + .poolSizeCount = sizeof(pool_sizes) / sizeof(VkDescriptorPoolSize), + .pPoolSizes = pool_sizes, + }; + VKCHECK(vkCreateDescriptorPool(device, &descriptor_pool_create_info, nullptr, &descriptor_pool)); +} + +void bindless_model::allocate_sets(VkDevice device) { + VkDescriptorSetAllocateInfo allocate_info{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .pNext = nullptr, + .descriptorPool = descriptor_pool, + .descriptorSetCount = 1U, + .pSetLayouts = &sets_layout[BindlessSetType::GLOBAL], + }; + VKCHECK(vkAllocateDescriptorSets(device, &allocate_info, &sets[BindlessSetType::GLOBAL])); +} + +void bindless_model::create_immutable_samplers(VkDevice device) { + VkSamplerCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .pNext = VK_NULL_HANDLE, + .flags = 0, + .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, + .mipLodBias = 0.f, + .anisotropyEnable = VK_FALSE, + .compareEnable = VK_FALSE, + .compareOp = VK_COMPARE_OP_ALWAYS, + .minLod = 0.f, + .maxLod = 0.f, + .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, + .unnormalizedCoordinates = VK_FALSE, + }; + + // Nearest sampler creation + { + VkFilter filter = VK_FILTER_NEAREST; + VkSamplerAddressMode address_mode = VK_SAMPLER_ADDRESS_MODE_REPEAT; + + create_info.magFilter = filter, + create_info.minFilter = filter, + create_info.addressModeU = address_mode, + create_info.addressModeV = address_mode, + create_info.addressModeW = address_mode, + + VKCHECK(vkCreateSampler(device, &create_info, VK_NULL_HANDLE, &samplers[SamplerType::NEAREST])); + } + + // Linear sampler creation + { + VkFilter filter = VK_FILTER_LINEAR; + VkSamplerAddressMode address_mode = VK_SAMPLER_ADDRESS_MODE_REPEAT; + + create_info.magFilter = filter, + create_info.minFilter = filter, + create_info.addressModeU = address_mode, + create_info.addressModeV = address_mode, + create_info.addressModeW = address_mode, + + VKCHECK(vkCreateSampler(device, &create_info, VK_NULL_HANDLE, &samplers[SamplerType::LINEAR])); + } +} + +void bindless_model::destroy_immutable_samplers(VkDevice device) { + for (auto* sampler : samplers) { + vkDestroySampler(device, sampler, nullptr); + } +} +#else +#endif diff --git a/api-test/vk-device.cpp b/api-test/vk-device.cpp index ef57f01..404cd43 100644 --- a/api-test/vk-device.cpp +++ b/api-test/vk-device.cpp @@ -9,12 +9,9 @@ #include "vulkan-loader.hpp" #include "window.hpp" +#include "vk-utils.hpp" -#ifdef _DEBUG -#define VKCHECK(result) assert(result == VK_SUCCESS); -#else -#define VKCHECK(result) result; -#endif +vkdevice* vkdevice::render_device = nullptr; VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT type, @@ -72,8 +69,11 @@ vkdevice::vkdevice(const window& window) }, } { load_vulkan(); + create_instance(); + create_surface(window); + #ifdef _DEBUG create_debug_layer_callback(); #endif // _DEBUG @@ -82,9 +82,58 @@ vkdevice::vkdevice(const window& window) create_memory_allocator(); - create_surface(window); - create_swapchain(); + + bindless = bindless_model::create_bindless_model(device); +} + +vkdevice* vkdevice::init_device(const window& window) { + vkdevice::render_device = new vkdevice(window); + return render_device; +} + +void vkdevice::free_device() { + delete render_device; + render_device = nullptr; +} + +vkdevice::~vkdevice() { + vkDeviceWaitIdle(device); + + bindless_model::destroy_bindless_model(device, bindless); + + for (auto& texture : textures) { + destroy_texture(texture); + } + + for (auto& buffer : buffers) { + destroy_buffer(buffer); + } + + for (auto& pipeline : pipelines) { + destroy_pipeline(pipeline); + } + + if (swapchain != nullptr) { + vkDestroySwapchainKHR(device, swapchain, nullptr); + } + + vmaDestroyAllocator(gpu_allocator); + + for (auto& queue : queues) { + vkDestroyCommandPool(device, queue.command_pool, nullptr); + } + + vkDestroyDevice(device, nullptr); + +#ifdef _DEBUG + vkDestroyDebugUtilsMessengerEXT(instance, debug_messenger, nullptr); +#endif // _DEBUG + + if (surface != nullptr) { + vkDestroySurfaceKHR(instance, surface, nullptr); + } + vkDestroyInstance(instance, nullptr); } handle<device_texture> vkdevice::create_texture(const texture_desc& desc) { @@ -126,12 +175,53 @@ handle<device_texture> vkdevice::create_texture(const texture_desc& desc) { .pUserData = nullptr, }; - VKCHECK(vmaCreateImage(gpu_allocator, &create_info, &alloc_create_info, &device_texture.handle, &device_texture.alloc, nullptr)) + VKCHECK(vmaCreateImage(gpu_allocator, &create_info, &alloc_create_info, &device_texture.vk_image, &device_texture.alloc, nullptr)); + + create_views(device_texture); + + // TODO: Handle mips views + std::vector<VkDescriptorImageInfo> images_info; + images_info.push_back({ + .sampler = nullptr, + .imageView = device_texture.whole_view, + .imageLayout = VK_IMAGE_LAYOUT_GENERAL, + }); + + std::vector<VkWriteDescriptorSet> write_descriptor_sets; + if ((desc.usages & VK_IMAGE_USAGE_STORAGE_BIT) != 0) { + device_texture.storage_index = storage_indices.add(&device_texture); - if ((desc.usages & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0U || - (desc.usages & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0U) { - create_views(device_texture); + write_descriptor_sets.push_back({ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + .dstSet = bindless.sets[BindlessSetType::GLOBAL], + .dstBinding = 2U, + .dstArrayElement = device_texture.storage_index, + .descriptorCount = static_cast<uint32_t>(images_info.size()), + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .pImageInfo = images_info.data(), + .pBufferInfo = nullptr, + .pTexelBufferView = nullptr, + }); } + if ((desc.usages & VK_IMAGE_USAGE_SAMPLED_BIT) != 0) { + device_texture.sampled_index = sampled_indices.add(&device_texture); + + write_descriptor_sets.push_back({ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + .dstSet = bindless.sets[BindlessSetType::GLOBAL], + .dstBinding = 1U, + .dstArrayElement = device_texture.sampled_index, + .descriptorCount = static_cast<uint32_t>(images_info.size()), + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .pImageInfo = images_info.data(), + .pBufferInfo = nullptr, + .pTexelBufferView = nullptr, + }); + } + + vkUpdateDescriptorSets(device, write_descriptor_sets.size(), write_descriptor_sets.data(), 0U, nullptr); return { textures.add(device_texture) }; } @@ -168,21 +258,118 @@ handle<device_buffer> vkdevice::create_buffer(const buffer_desc& desc) { VmaAllocationInfo alloc_info {}; - VKCHECK(vmaCreateBuffer(gpu_allocator, &create_info, &alloc_create_info, &device_buffer.handle, &device_buffer.alloc, &alloc_info)) + VKCHECK(vmaCreateBuffer(gpu_allocator, &create_info, &alloc_create_info, &device_buffer.vk_buffer, &device_buffer.alloc, &alloc_info)); device_buffer.mapped_ptr = alloc_info.pMappedData; return { buffers.add(device_buffer) }; } +handle<device_pipeline> vkdevice::create_pipeline(const pipeline_desc& desc) { + device_pipeline device_pipeline { + .desc = desc, + .bindless = &bindless, + }; + if (!desc.cs_code.empty()) { + const auto& code = desc.cs_code; + VkShaderModule shader_module; + VkShaderModuleCreateInfo module_create_info { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .codeSize = code.size(), + .pCode = (uint32_t*)code.data(), + }; + + VKCHECK(vkCreateShaderModule(device, &module_create_info, nullptr, &shader_module)); + + VkPipelineShaderStageCreateInfo stage_create_info { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .stage = VK_SHADER_STAGE_COMPUTE_BIT, + .module = shader_module, + .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.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, shader_module, nullptr); + } else { + + VkGraphicsPipelineCreateInfo create_info { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .layout = bindless.layout, + .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)); + } + + return { pipelines.add(device_pipeline) }; +} + +void vkdevice::destroy_texture(const device_texture& texture) { + destroy_texture({ .id = textures.find(texture) }); +} + +void vkdevice::destroy_texture(handle<device_texture> handle) { + const auto& texture = get_texture(handle); + textures.remove(handle.id); + + vmaDestroyImage(gpu_allocator, texture.vk_image, texture.alloc); + + vkDestroyImageView(device, texture.whole_view, nullptr); + + for (const auto& mip_view : texture.mips_views) { + vkDestroyImageView(device, mip_view, nullptr); + } +} + +void vkdevice::destroy_buffer(const device_buffer& buffer) { + destroy_buffer({ .id = buffers.find(buffer) }); +} + +void vkdevice::destroy_buffer(handle<device_buffer> handle) { + const auto& buffer = get_buffer(handle); + + vmaDestroyBuffer(gpu_allocator, buffer.vk_buffer, buffer.alloc); +} + +void vkdevice::destroy_pipeline(const device_pipeline& pipeline) { + destroy_pipeline({ .id = pipelines.find(pipeline) }); +} + +void vkdevice::destroy_pipeline(handle<device_pipeline> handle) { + const auto& pipeline = vkdevice::get_pipeline(handle); + + vkDestroyPipeline(device, pipeline.vk_pipeline, nullptr); +} + void vkdevice::submit(command_buffer* buffers, size_t count) { - assert((count - max_submitable_command_buffers) <= 0); + assert((max_submitable_command_buffers - count) >= 0); const auto queue_type = buffers[0].queue_type; VkCommandBuffer to_submit[max_submitable_command_buffers]; for (auto index { 0U }; index < count; index++) { assert(queue_type == buffers[index].queue_type); - to_submit[index] = buffers[index].handle; + to_submit[index] = buffers[index].vk_command_buffer; } VkSubmitInfo submit_info { @@ -197,13 +384,22 @@ void vkdevice::submit(command_buffer* buffers, size_t count) { .pSignalSemaphores = nullptr, }; - VKCHECK(vkQueueSubmit(queues[static_cast<uint32_t>(queue_type)].handle, 1, &submit_info, nullptr)) + VKCHECK(vkQueueSubmit(queues[static_cast<uint32_t>(queue_type)].vk_queue, 1, &submit_info, nullptr)); +} + +void vkdevice::present() { + VkPresentInfoKHR present_info { + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .pNext = nullptr, + }; + + // VKCHECK(vkQueuePresentKHR(queues[static_cast<uint32_t>(QueueType::GRAPHICS)].vk_queue, &present_info)); } // private void vkdevice::allocate_command_buffers(command_buffer* buffers, size_t count, QueueType type) { - assert((count - max_allocable_command_buffers) <= 0); + assert((max_allocable_command_buffers - count) >= 0); const auto& queue = queues[static_cast<uint32_t>(type)]; VkCommandBuffer command_buffers[max_allocable_command_buffers]; @@ -215,22 +411,23 @@ void vkdevice::allocate_command_buffers(command_buffer* buffers, size_t count, Q .commandBufferCount = static_cast<uint32_t>(count), }; - VKCHECK(vkAllocateCommandBuffers(device, &allocate_info, command_buffers)) + VKCHECK(vkAllocateCommandBuffers(device, &allocate_info, command_buffers)); for (auto index { 0U }; index < count; index++) { - buffers[index].handle = command_buffers[index]; + buffers[index].vk_command_buffer = command_buffers[index]; + buffers[index].queue_type = type; } } void vkdevice::create_views(device_texture& texture) { - VkImageAspectFlags aspect_mask = ((texture.desc.usages & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0U) - ? VK_IMAGE_ASPECT_COLOR_BIT - : VK_IMAGE_ASPECT_DEPTH_BIT; + VkImageAspectFlags aspect_mask = ((texture.desc.usages & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0U) + ? VK_IMAGE_ASPECT_DEPTH_BIT + : VK_IMAGE_ASPECT_COLOR_BIT; VkImageViewCreateInfo create_info { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .pNext = nullptr, .flags = 0U, - .image = texture.handle, + .image = texture.vk_image, .viewType = VK_IMAGE_VIEW_TYPE_2D, .format = texture.desc.format, .components = { @@ -240,7 +437,7 @@ void vkdevice::create_views(device_texture& texture) { .a = VK_COMPONENT_SWIZZLE_A, }, .subresourceRange = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, // TODO: Choose either color or depth based on format ? + .aspectMask = aspect_mask, .baseMipLevel = 0, .levelCount = 1, .baseArrayLayer = 0, @@ -250,14 +447,15 @@ void vkdevice::create_views(device_texture& texture) { for (auto mip_index{ 0 }; mip_index < texture.desc.mips; mip_index++) { create_info.subresourceRange.baseMipLevel = mip_index; - VKCHECK(vkCreateImageView(device, &create_info, nullptr, &texture.mips_views[mip_index])) + VKCHECK(vkCreateImageView(device, &create_info, nullptr, &texture.mips_views[mip_index])); } create_info.subresourceRange.baseMipLevel = 0; create_info.subresourceRange.levelCount = texture.desc.mips; - VKCHECK(vkCreateImageView(device, &create_info, nullptr, &texture.whole_view)) + VKCHECK(vkCreateImageView(device, &create_info, nullptr, &texture.whole_view)); } +// Presentation stuff void vkdevice::create_surface(const window& window) { VkWin32SurfaceCreateInfoKHR create_info { .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, @@ -267,20 +465,18 @@ void vkdevice::create_surface(const window& window) { .hwnd = window.handle, }; - VKCHECK(vkCreateWin32SurfaceKHR(instance, &create_info, nullptr, &surface)) + VKCHECK(vkCreateWin32SurfaceKHR(instance, &create_info, nullptr, &surface)); } void vkdevice::create_swapchain() { VkBool32 supported = VK_FALSE; - for (auto index{ 0U }; index < static_cast<uint32_t>(QueueType::MAX); index++) { - auto& queue = queues[index]; - VKCHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue.index, surface, &supported)) + auto& queue = queues[static_cast<uint32_t>(QueueType::GRAPHICS)]; + VKCHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue.index, surface, &supported)); - assert(supported); - } + assert(supported); VkSurfaceCapabilitiesKHR surface_capabilities = {}; - VKCHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &surface_capabilities)) + VKCHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &surface_capabilities)); VkExtent2D extent = surface_capabilities.currentExtent; @@ -297,25 +493,27 @@ void vkdevice::create_swapchain() { } auto supported_formats_count = 0U; - VKCHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &supported_formats_count, VK_NULL_HANDLE)) + VKCHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &supported_formats_count, nullptr)); std::vector<VkSurfaceFormatKHR> supported_formats{ supported_formats_count }; - VKCHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &supported_formats_count, supported_formats.data())) + VKCHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &supported_formats_count, supported_formats.data())); auto supported_present_modes_count = 0U; - VKCHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &supported_present_modes_count, VK_NULL_HANDLE)) + VKCHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &supported_present_modes_count, nullptr)); std::vector<VkPresentModeKHR> supported_present_modes{ supported_present_modes_count }; - VKCHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &supported_present_modes_count, supported_present_modes.data())) + VKCHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &supported_present_modes_count, supported_present_modes.data())); + + auto min_image_count = (surface_capabilities.minImageCount <= virtual_frames_count) ? virtual_frames_count : surface_capabilities.minImageCount; VkSwapchainCreateInfoKHR create_info = { .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, .pNext = nullptr, .flags = 0U, .surface = surface, - .minImageCount = surface_capabilities.minImageCount, + .minImageCount = min_image_count, .imageFormat = supported_formats[0].format, .imageColorSpace = supported_formats[0].colorSpace, .imageExtent = extent, @@ -331,7 +529,28 @@ void vkdevice::create_swapchain() { .oldSwapchain = nullptr, }; - VKCHECK(vkCreateSwapchainKHR(device, &create_info, nullptr, &swapchain)) + VKCHECK(vkCreateSwapchainKHR(device, &create_info, nullptr, &swapchain)); +} + +void vkdevice::create_virtual_frames() { + for (auto index { 0U }; index < virtual_frames_count; index++) { + { + VkSemaphoreTypeCreateInfo semaphore_type_create_info { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, + .pNext = nullptr, + .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE, + .initialValue = 0U, + }; + + VkSemaphoreCreateInfo create_info { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .pNext = &semaphore_type_create_info, + .flags = 0U, + }; + + VKCHECK(vkCreateSemaphore(device, &create_info, nullptr, &semaphores[index])); + } + } } // ----------------- vkadapter ----------------- @@ -367,7 +586,7 @@ void vkdevice::create_instance() { .ppEnabledExtensionNames = instance_extensions, }; - VKCHECK(vkCreateInstance(&create_info, nullptr, &instance)) + VKCHECK(vkCreateInstance(&create_info, nullptr, &instance)); load_instance_functions(instance); } @@ -376,35 +595,49 @@ void vkdevice::create_device() { pick_physical_device(); float queue_priority = 1.f; - VkDeviceQueueCreateInfo queue_create_infos[static_cast<uint32_t>(QueueType::MAX)] { - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - nullptr, - 0U, - 0, - 1, - &queue_priority, - }; + 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]; - auto queue_index = pick_queue(queue.usages); - queue.index = queue_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 = VK_NULL_HANDLE, + .pNext = nullptr, .shaderSampledImageArrayNonUniformIndexing = VK_TRUE, .shaderStorageImageArrayNonUniformIndexing = VK_TRUE, .descriptorBindingUpdateUnusedWhilePending = VK_TRUE, .descriptorBindingPartiallyBound = VK_TRUE, .runtimeDescriptorArray = VK_TRUE, - .imagelessFramebuffer = VK_TRUE, + .timelineSemaphore = VK_TRUE, .bufferDeviceAddress = VK_TRUE, }; @@ -428,12 +661,12 @@ void vkdevice::create_device() { .pEnabledFeatures = nullptr, }; - VKCHECK(vkCreateDevice(physical_device, &create_info, nullptr, &device)) + VKCHECK(vkCreateDevice(physical_device, &create_info, nullptr, &device)); load_device_functions(device); for (auto& queue : queues) { - vkGetDeviceQueue(device, queue.index, 0, &queue.handle); + vkGetDeviceQueue(device, queue.index, 0, &queue.vk_queue); } create_command_pools(); @@ -448,7 +681,7 @@ void vkdevice::create_memory_allocator() { .vulkanApiVersion = VK_API_VERSION_1_2, }; - VKCHECK(vmaCreateAllocator(&create_info, &gpu_allocator)) + VKCHECK(vmaCreateAllocator(&create_info, &gpu_allocator)); } void vkdevice::create_command_pools() { @@ -461,25 +694,8 @@ void vkdevice::create_command_pools() { for (auto& queue : queues) { create_info.queueFamilyIndex = queue.index; - VKCHECK(vkCreateCommandPool(device, &create_info, nullptr, &queue.command_pool)) - } -} - -uint32_t vkdevice::pick_queue(VkQueueFlags queue_usages) const { - 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 properties_index{ 0U }; properties_index < queue_properties_count; properties_index++) { - if ((queue_properties[properties_index].queueFlags & queue_usages) == queue_usages) { - return properties_index; - } + VKCHECK(vkCreateCommandPool(device, &create_info, nullptr, &queue.command_pool)); } - - assert(true); - return UINT_MAX; } void vkdevice::pick_physical_device() { @@ -521,7 +737,6 @@ bool vkdevice::device_support_features(VkPhysicalDevice physical_dev) { vulkan_12_features.shaderStorageImageArrayNonUniformIndexing == VK_FALSE || vulkan_12_features.shaderSampledImageArrayNonUniformIndexing == VK_FALSE || vulkan_12_features.descriptorBindingPartiallyBound == VK_FALSE || - vulkan_12_features.descriptorBindingPartiallyBound == VK_FALSE || vulkan_12_features.descriptorBindingUpdateUnusedWhilePending == VK_FALSE || vulkan_12_features.imagelessFramebuffer == VK_FALSE) { return false; @@ -532,7 +747,7 @@ bool vkdevice::device_support_features(VkPhysicalDevice physical_dev) { // Vulkan 1.3 physical device features support { VkPhysicalDeviceVulkan13Features vulkan_13_features { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, }; VkPhysicalDeviceFeatures2 physical_device_features { @@ -565,5 +780,5 @@ void vkdevice::create_debug_layer_callback() { .pUserData = nullptr, }; - VKCHECK(vkCreateDebugUtilsMessengerEXT(instance, &create_info, nullptr, &debug_messenger)) + VKCHECK(vkCreateDebugUtilsMessengerEXT(instance, &create_info, nullptr, &debug_messenger)); } |
