From b0708f165601fad16aa59715dbe32796a6e7081e Mon Sep 17 00:00:00 2001 From: ladevieq Date: Tue, 6 Sep 2022 22:41:00 +0200 Subject: Setup for texture upload system --- src/CMakeLists.txt | 27 ++++++++-- src/gltf.cpp | 47 +++++++---------- src/main.cpp | 2 - src/mesh.cpp | 4 +- src/vk-api.cpp | 127 +++++++++++++++++++------------------------- src/vk-context.cpp | 78 ++++++++++++++------------- src/vk-renderer.cpp | 148 ++++++++++++++++++++++++++-------------------------- 7 files changed, 217 insertions(+), 216 deletions(-) (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b56a871..54a4c54 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LIBRARIES imgui::imgui nlohmann_json::nlohmann_json Tracy::TracyClient) +set(LIBRARIES imgui::imgui) set(DEFINES -DNOMINMAX -D_USE_MATH_DEFINES -DVK_NO_PROTOTYPES) @@ -29,9 +29,31 @@ add_executable( primitive-renderpass.cpp bvh.cpp mesh.cpp - # ${Tracy_SOURCE_DIR}/TracyClient.cpp ) +if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + target_compile_options( + path-tracer + PRIVATE + # -fsanitize=address TODO: enable once compiling with the flag works + -fcolor-diagnostics -fansi-escape-codes # colored output when using ninja + -ftime-trace + -msse4.1 + # https://github.com/cpp-best-practices/cppbestpractices/blob/master/02-Use_the_Tools_Available.md#gcc--clang + -Wall + -Wextra + -Wshadow + -Wcast-align + -Wnon-virtual-dtor + -Wpedantic + -Wunused + ) + +# target_link_options(path-tracer PRIVATE -fsanitize=address) +endif() + +target_link_directories(path-tracer PRIVATE "C:\\Program Files\\LLVM\\lib\\clang\\14.0.6\\lib\\windows") + target_compile_definitions(path-tracer PUBLIC ${DEFINES}) target_include_directories(path-tracer SYSTEM PUBLIC ${CMAKE_SOURCE_DIR}/thirdparty) @@ -43,7 +65,6 @@ if(UNIX AND NOT APPLE) target_include_directories(path-tracer PUBLIC ${X11_xcb_INCLUDE_PATH}) endif() - if(UNIX AND NOT APPLE) list(APPEND LIBRARIES ${CMAKE_DL_LIBS} ${X11_xcb_LIB} ${X11_xkbcommon_LIB} ${X11_xkbcommon_X11_LIB}) endif() diff --git a/src/gltf.cpp b/src/gltf.cpp index a05237c..59094d9 100644 --- a/src/gltf.cpp +++ b/src/gltf.cpp @@ -18,10 +18,11 @@ gltf::gltf(const std::filesystem::path &filepath) { auto& scene = gltf_json["scenes"][0]; auto &gltf_buffers = gltf_json["buffers"]; - buffers.reserve(gltf_buffers.size()); - for (auto& gltf_buffer : gltf_buffers) { - auto buffer_path = parent_path / gltf_buffer["uri"].get(); - buffers.emplace_back(read_file(buffer_path.string().c_str())); + auto buffer_count = gltf_buffers.size(); + buffers.resize(gltf_buffers.size()); + for (auto buffer_index { 0U }; buffer_index < buffer_count; buffer_index++) { + auto buffer_path = parent_path / gltf_buffers[buffer_index]["uri"].get(); + buffers[buffer_index] = read_file(buffer_path.string().c_str()); } load_textures(parent_path); @@ -68,7 +69,8 @@ void gltf::load_meshes() { const auto &primitives = gltf_meshes[mesh_index]["primitives"]; for (const auto &primitive : primitives) { - mesh.add_submesh(load_primitive(primitive)); + auto material = materials[primitive["material"].get()]; + mesh.add_submesh(load_primitive(primitive), material); } Mesh::register_mesh(mesh); @@ -91,7 +93,6 @@ Mesh::submesh gltf::load_primitive(const json &primitive) { submesh.index_count = gltf_json["accessors"][primitive["indices"].get()]["count"].get(); submesh.vertex_count = gltf_json["accessors"][primitive["attributes"]["POSITION"].get()]["count"].get(); - // submesh.mat = materials[gltf_primitive["material"].get()]; return submesh; } @@ -111,22 +112,13 @@ Mesh::attribute gltf::load_attribute(uint32_t accessor_index) { void gltf::load_textures(const std::filesystem::path &path) { const auto &gltf_images = gltf_json["images"]; auto images_count = gltf_images.size(); - std::vector images{images_count}; + std::vector images{images_count}; for (size_t image_index = 0; image_index < images_count; image_index++) { const auto &gltf_image = gltf_images[image_index]; - int x; - int y; - int n; auto filepath = (path / gltf_image["uri"].get()).string(); - unsigned char *data = stbi_load(filepath.c_str(), &x, &y, &n, 4); - auto *img = vkrenderer::create_2d_texture(static_cast(x), static_cast(y), VK_FORMAT_R8G8B8A8_UNORM); - - // renderer.update_image(img, data); - - stbi_image_free(data); - - images[image_index] = img; + auto& image = images[image_index]; + image.data = stbi_load(filepath.c_str(), &image.x, &image.y, &image.n, 4); } const auto &gltf_samplers = gltf_json["samplers"]; @@ -144,19 +136,20 @@ void gltf::load_textures(const std::filesystem::path &path) { for (size_t texture_index = 0; texture_index < textures_count; texture_index++) { auto gltf_texture = gltf_textures[texture_index]; - auto image_index = gltf_texture["source"].get(); - auto &image = images[image_index]; - - uint32_t image_id = vkrenderer::api.get_image(image->device_image).bindless_sampled_index; - uint32_t sampler_id = 0; + auto& image = images[gltf_texture["source"].get()]; + Sampler *sampler = nullptr; if (gltf_texture.contains("sampler")) { auto sampler_index = gltf_texture["sampler"].get(); - auto &sampler = samplers[sampler_index]; - sampler_id = vkrenderer::api.get_sampler(sampler->device_sampler).bindless_index; + sampler = samplers[sampler_index]; } - textures[texture_index] = - texture{.image_id = image_id, .sampler_id = sampler_id}; + auto *texture = vkrenderer::create_2d_texture(static_cast(image.x), static_cast(image.y), VK_FORMAT_R8G8B8A8_UNORM, sampler); + + texture->write(image.data); + + stbi_image_free(image.data); + + textures[texture_index] = texture; } } diff --git a/src/main.cpp b/src/main.cpp index 58882d3..5e39a09 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,8 +14,6 @@ #include "window.hpp" #include "utils.hpp" -#include "Tracy.hpp" - #if defined(LINUX) #include #include diff --git a/src/mesh.cpp b/src/mesh.cpp index 191aaf7..b3916aa 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -2,13 +2,13 @@ static std::vector meshes {}; -void Mesh::add_submesh(const submesh& submesh) { +void Mesh::add_submesh(const submesh& submesh, material& material) { submeshes.emplace_back( submesh_info { (uint32_t)vertex_count, (uint32_t)index_count, submesh.index_count / 3, - 0 + material } ); diff --git a/src/vk-api.cpp b/src/vk-api.cpp index ebffd38..81242a5 100644 --- a/src/vk-api.cpp +++ b/src/vk-api.cpp @@ -20,15 +20,7 @@ vkapi::vkapi(vkcontext& context) : context(context) { - VkCommandPoolCreateInfo cmd_pool_create_info = {}; - cmd_pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - cmd_pool_create_info.pNext = nullptr; - cmd_pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - cmd_pool_create_info.queueFamilyIndex = context.queue_index; - - VKRESULT(vkCreateCommandPool(context.device, &cmd_pool_create_info, nullptr, &command_pool)) - - std::vector descriptor_pools_sizes = { + VkDescriptorPoolSize descriptor_pools_sizes[] = { { .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .descriptorCount = (uint32_t)global_descriptor::pool_size, @@ -52,8 +44,8 @@ vkapi::vkapi(vkcontext& context) descriptor_pool_create_info.pNext = nullptr; descriptor_pool_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; descriptor_pool_create_info.maxSets = 0xff; - descriptor_pool_create_info.poolSizeCount = descriptor_pools_sizes.size(); - descriptor_pool_create_info.pPoolSizes = descriptor_pools_sizes.data(); + descriptor_pool_create_info.poolSizeCount = sizeof(descriptor_pools_sizes) / sizeof(descriptor_pools_sizes[0]); + descriptor_pool_create_info.pPoolSizes = descriptor_pools_sizes; VKRESULT(vkCreateDescriptorPool(context.device, &descriptor_pool_create_info, nullptr, &descriptor_pool)) @@ -146,6 +138,7 @@ vkapi::vkapi(vkcontext& context) } vkapi::~vkapi() { + // Free resources for (handle buffer_handle = 0; buffer_handle < buffers.size(); buffer_handle++) { destroy_buffer(buffer_handle); } @@ -163,7 +156,6 @@ vkapi::~vkapi() { vkDestroyPipelineLayout(context.device, bindless_descriptor.pipeline_layout, nullptr); vkFreeDescriptorSets(context.device, descriptor_pool, 1, &bindless_descriptor.set); - vkDestroyCommandPool(context.device, command_pool, nullptr); vkDestroyDescriptorPool(context.device, descriptor_pool, nullptr); } @@ -309,8 +301,14 @@ handle vkapi::create_image(VkExtent3D size, VkFormat format, VkImageUsageFlags u } void vkapi::destroy_image(handle image) { auto* current_image = images[image]; - bindless_descriptor.free(current_image->bindless_storage_index, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); - bindless_descriptor.free(current_image->bindless_sampled_index, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); + + if (current_image->bindless_storage_index != 0U) { + bindless_descriptor.free(current_image->bindless_storage_index, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); + } + + if (current_image->bindless_sampled_index != 0U) { + bindless_descriptor.free(current_image->bindless_sampled_index, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); + } vmaDestroyImage(context.allocator, current_image->handle, current_image->alloc); vkDestroyImageView(context.device, current_image->view, nullptr); @@ -437,7 +435,7 @@ handle vkapi::create_sampler(VkFilter filter, VkSamplerAddressMode address_mode) } void vkapi::destroy_sampler(handle sampler) { - auto current_sampler = samplers[sampler]; + auto* current_sampler = samplers[sampler]; bindless_descriptor.free(current_sampler->bindless_index, VK_DESCRIPTOR_TYPE_SAMPLER); vkDestroySampler(context.device, current_sampler->handle, VK_NULL_HANDLE); @@ -446,25 +444,31 @@ void vkapi::destroy_sampler(handle sampler) { } -std::vector vkapi::create_command_buffers(size_t command_buffers_count) { +VkCommandPool vkapi::create_command_pool() const { + VkCommandPoolCreateInfo cmd_pool_create_info = {}; + cmd_pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + cmd_pool_create_info.pNext = nullptr; + cmd_pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + cmd_pool_create_info.queueFamilyIndex = context.graphics_queue.index; + + VkCommandPool command_pool; + VKRESULT(vkCreateCommandPool(context.device, &cmd_pool_create_info, nullptr, &command_pool)) + + return command_pool; +} + + +void vkapi::allocate_command_buffers(VkCommandPool command_pool, VkCommandBuffer* command_buffers, size_t count) const { VkCommandBufferAllocateInfo cmd_buf_allocate_info = {}; cmd_buf_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; cmd_buf_allocate_info.pNext = VK_NULL_HANDLE; cmd_buf_allocate_info.commandPool = command_pool; cmd_buf_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - cmd_buf_allocate_info.commandBufferCount = command_buffers_count; + cmd_buf_allocate_info.commandBufferCount = count; - std::vector command_buffers { command_buffers_count }; - vkAllocateCommandBuffers(context.device, &cmd_buf_allocate_info, command_buffers.data()); - - return command_buffers; + vkAllocateCommandBuffers(context.device, &cmd_buf_allocate_info, command_buffers); } -void vkapi::destroy_command_buffers(std::vector &command_buffers) { - vkFreeCommandBuffers(context.device, command_pool, command_buffers.size(), command_buffers.data()); -} - - // TODO: attachment structure VkRenderPass vkapi::create_render_pass(std::vector& color_attachments_format, VkImageLayout initial_layout, VkImageLayout final_layout) { std::vector attachments_description = {}; @@ -621,7 +625,7 @@ pipeline vkapi::create_compute_pipeline(const char* shader_name) const { auto shader_filename = std::string(shader_name) + ".comp.spv"; auto shader_path = std::filesystem::path{ "./shaders" } / shader_filename; - std::vector shader_code = read_file(shader_path.string().c_str()); + auto shader_code = read_file(shader_path.string().c_str()); assert(!shader_code.empty()); pipeline.shader_modules.resize(1); @@ -799,27 +803,6 @@ void vkapi::destroy_pipeline(pipeline &pipeline) const { } -std::vector vkapi::create_descriptor_sets(VkDescriptorSetLayout descriptor_sets_layout, size_t descriptor_sets_count) { - std::vector sets_layouts = { descriptor_sets_count, descriptor_sets_layout }; - - VkDescriptorSetAllocateInfo descriptor_set_allocate_info = {}; - descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - descriptor_set_allocate_info.pNext = nullptr; - descriptor_set_allocate_info.descriptorPool = descriptor_pool; - descriptor_set_allocate_info.descriptorSetCount = sets_layouts.size(); - descriptor_set_allocate_info.pSetLayouts = sets_layouts.data(); - - std::vector descriptor_sets { descriptor_sets_count }; - vkAllocateDescriptorSets(context.device, &descriptor_set_allocate_info, descriptor_sets.data()); - - return descriptor_sets; -} - -void vkapi::destroy_descriptor_sets(std::vector &descriptor_sets) { - vkFreeDescriptorSets(context.device, descriptor_pool, descriptor_sets.size(), descriptor_sets.data()); -} - - VkSurfaceKHR vkapi::create_surface(window& wnd) const { VkSurfaceKHR surface; @@ -863,7 +846,7 @@ swapchain vkapi::create_swapchain(VkSurfaceKHR surface, size_t min_image_count, swapchain swapchain; VkBool32 queue_support_presentation = VK_FALSE; - VKRESULT(vkGetPhysicalDeviceSurfaceSupportKHR(context.physical_device, context.queue_index, surface, &queue_support_presentation)) + VKRESULT(vkGetPhysicalDeviceSurfaceSupportKHR(context.physical_device, context.graphics_queue.index, surface, &queue_support_presentation)) assert(queue_support_presentation == VK_TRUE); @@ -944,7 +927,7 @@ swapchain vkapi::create_swapchain(VkSurfaceKHR surface, size_t min_image_count, }; for (size_t image_index = 0; image_index < swapchain.image_count; image_index++) { - struct image* current_image = new struct image(); + auto* current_image = new struct image(); current_image->handle = vk_images[image_index]; current_image->size = image_size; @@ -973,12 +956,12 @@ swapchain vkapi::create_swapchain(VkSurfaceKHR surface, size_t min_image_count, auto current_image_handle = images.size() - 1; - if (usages & VK_IMAGE_USAGE_STORAGE_BIT) { + if ((usages & VK_IMAGE_USAGE_STORAGE_BIT) != 0U) { current_image->bindless_storage_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); update_descriptor_image(current_image_handle, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); } - if (usages & VK_IMAGE_USAGE_SAMPLED_BIT) { + if ((usages & VK_IMAGE_USAGE_SAMPLED_BIT) != 0U) { current_image->bindless_sampled_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); update_descriptor_image(current_image_handle, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); } @@ -1117,19 +1100,19 @@ void vkapi::start_record(VkCommandBuffer command_buffer) { } void vkapi::image_barrier(VkCommandBuffer command_buffer, VkImageLayout dst_layout, VkPipelineStageFlagBits dst_stage, VkAccessFlags dst_access, handle image) { - auto current_image = images[image]; - - VkImageMemoryBarrier undefined_to_general_barrier = {}; - undefined_to_general_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - undefined_to_general_barrier.pNext = nullptr; - undefined_to_general_barrier.srcAccessMask = current_image->previous_access; - undefined_to_general_barrier.dstAccessMask = dst_access; - undefined_to_general_barrier.oldLayout = current_image->previous_layout; - undefined_to_general_barrier.newLayout = dst_layout; - undefined_to_general_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - undefined_to_general_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - undefined_to_general_barrier.image = current_image->handle; - undefined_to_general_barrier.subresourceRange = current_image->subresource_range; + auto *current_image = images[image]; + + VkImageMemoryBarrier image_barrier = {}; + image_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_barrier.pNext = nullptr; + image_barrier.srcAccessMask = current_image->previous_access; + image_barrier.dstAccessMask = dst_access; + image_barrier.oldLayout = current_image->previous_layout; + image_barrier.newLayout = dst_layout; + image_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barrier.image = current_image->handle; + image_barrier.subresourceRange = current_image->subresource_range; vkCmdPipelineBarrier( command_buffer, @@ -1141,7 +1124,7 @@ void vkapi::image_barrier(VkCommandBuffer command_buffer, VkImageLayout dst_layo 0, nullptr, 1, - &undefined_to_general_barrier + &image_barrier ); current_image->previous_layout = dst_layout; @@ -1242,21 +1225,21 @@ void vkapi::end_record(VkCommandBuffer command_buffer) { VKRESULT(vkEndCommandBuffer(command_buffer)) } -VkResult vkapi::submit(VkCommandBuffer command_buffer, VkSemaphore wait_semaphore, VkSemaphore signal_semaphore, VkFence submission_fence) const { +VkResult vkapi::submit_graphics(VkCommandBuffer command_buffer, VkSemaphore wait_semaphore, VkSemaphore signal_semaphore, VkFence submission_fence) const { VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; VkSubmitInfo submit_info = {}; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.pNext = nullptr; - submit_info.waitSemaphoreCount = wait_semaphore ? 1 : 0; + submit_info.waitSemaphoreCount = wait_semaphore != nullptr ? 1 : 0; submit_info.pWaitSemaphores = &wait_semaphore; - submit_info.pWaitDstStageMask = wait_semaphore ? &wait_stage : VK_NULL_HANDLE; - submit_info.signalSemaphoreCount = signal_semaphore ? 1 : 0; + submit_info.pWaitDstStageMask = wait_semaphore != nullptr ? &wait_stage : VK_NULL_HANDLE; + submit_info.signalSemaphoreCount = signal_semaphore != nullptr ? 1 : 0; submit_info.pSignalSemaphores = &signal_semaphore; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &command_buffer; - return vkQueueSubmit(context.queue, 1, &submit_info, submission_fence); + return vkQueueSubmit(context.graphics_queue.handle, 1, &submit_info, submission_fence); } VkResult vkapi::present(swapchain& swapchain, uint32_t image_index, VkSemaphore wait_semaphore) const { @@ -1270,7 +1253,7 @@ VkResult vkapi::present(swapchain& swapchain, uint32_t image_index, VkSemaphore present_info.pImageIndices = &image_index; present_info.pResults = nullptr; - return vkQueuePresentKHR(context.queue, &present_info); + return vkQueuePresentKHR(context.graphics_queue.handle, &present_info); } diff --git a/src/vk-context.cpp b/src/vk-context.cpp index 2783c6a..e4a8815 100644 --- a/src/vk-context.cpp +++ b/src/vk-context.cpp @@ -2,6 +2,8 @@ #include #include +#include +#include #define VMA_IMPLEMENTATION #include @@ -83,15 +85,16 @@ void vkcontext::create_instance() { app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0); app_info.apiVersion = VK_API_VERSION_1_2; - std::vector needed_layers = { + const char* needed_layers[] = { #if defined(_DEBUG) "VK_LAYER_KHRONOS_validation", #endif }; + auto needed_layers_count = sizeof(needed_layers) / sizeof(needed_layers[0]); - check_available_instance_layers(needed_layers); + check_available_instance_layers(needed_layers, needed_layers_count); - std::vector needed_extensions = { + const char* needed_extensions[] = { VK_EXT_DEBUG_UTILS_EXTENSION_NAME, "VK_KHR_surface", #if defined(LINUX) @@ -102,16 +105,17 @@ void vkcontext::create_instance() { "VK_EXT_metal_surface" #endif }; + auto needed_extensions_count = sizeof(needed_extensions) / sizeof(needed_extensions[0]); - check_available_instance_extensions(needed_extensions); + check_available_instance_extensions(needed_extensions, needed_extensions_count); VkInstanceCreateInfo instance_create_info = {}; instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instance_create_info.pApplicationInfo = &app_info; - instance_create_info.enabledLayerCount = needed_layers.size(); - instance_create_info.ppEnabledLayerNames = needed_layers.data(); - instance_create_info.enabledExtensionCount = needed_extensions.size(); - instance_create_info.ppEnabledExtensionNames = needed_extensions.data(); + instance_create_info.enabledLayerCount = needed_layers_count; + instance_create_info.ppEnabledLayerNames = needed_layers; + instance_create_info.enabledExtensionCount = needed_extensions_count; + instance_create_info.ppEnabledExtensionNames = needed_extensions; VKRESULT(vkCreateInstance(&instance_create_info, nullptr, &instance)) @@ -142,15 +146,19 @@ void vkcontext::create_debugger() { void vkcontext::create_device() { select_physical_device(); - select_queue(VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT); - VkDeviceQueueCreateInfo queue_create_info = {}; - queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queue_create_info.queueFamilyIndex = queue_index; - queue_create_info.queueCount = 1; - - float queue_priority = 1.f; - queue_create_info.pQueuePriorities = &queue_priority; + graphics_queue = { + .usages = VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT, + }; + auto queue_priority = 1.f; + graphics_queue.index = select_queue(graphics_queue.usages); + auto queue_create_info = VkDeviceQueueCreateInfo { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .queueFamilyIndex = graphics_queue.index, + .queueCount = 1, + + .pQueuePriorities = &queue_priority + }; VkPhysicalDeviceVulkan12Features physical_device_12_features = {}; physical_device_12_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; @@ -168,7 +176,7 @@ void vkcontext::create_device() { device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; device_features.pNext = &physical_device_12_features; - std::vector device_ext = { + const char* device_ext[] = { "VK_KHR_swapchain", }; @@ -177,15 +185,15 @@ void vkcontext::create_device() { device_create_info.pNext = &device_features; device_create_info.pQueueCreateInfos = &queue_create_info; device_create_info.queueCreateInfoCount = 1; - device_create_info.ppEnabledExtensionNames = device_ext.data(); - device_create_info.enabledExtensionCount = device_ext.size(); + device_create_info.ppEnabledExtensionNames = device_ext; + device_create_info.enabledExtensionCount = sizeof(device_ext) / sizeof(device_ext[0]); device_create_info.enabledLayerCount = 0; // Deprecated https://www.khronos.org/registry/vulkan/specs/1.2/html/chap31.html#extendingvulkan-layers-devicelayerdeprecation VKRESULT(vkCreateDevice(physical_device, &device_create_info, nullptr, &device)) load_device_functions(device); - vkGetDeviceQueue(device, queue_index, 0, &queue); + vkGetDeviceQueue(device, graphics_queue.index, 0, &graphics_queue.handle); std::cerr << "Device ready" << std::endl; } @@ -208,7 +216,6 @@ void vkcontext::select_physical_device() { if (physical_devices_count < 1) { std::cerr << "No physical device found !" << std::endl; - exit(1); } std::vector physical_devices { physical_devices_count }; @@ -224,7 +231,7 @@ void vkcontext::select_physical_device() { assert(physical_device != VK_NULL_HANDLE); } -void vkcontext::select_queue(VkQueueFlags queueUsage) { +uint32_t vkcontext::select_queue(VkQueueFlags queue_usage) const { uint32_t queue_properties_count = 0; vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_properties_count, nullptr); @@ -232,17 +239,16 @@ void vkcontext::select_queue(VkQueueFlags queueUsage) { vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_properties_count, queue_properties.data()); for (uint32_t properties_index = 0; properties_index < queue_properties_count; properties_index++) { - if ((queue_properties[properties_index].queueFlags & queueUsage) != 0U) { - queue_index = properties_index; - return; + if ((queue_properties[properties_index].queueFlags & queue_usage) != 0U) { + return properties_index; } } - std::cerr << "No compute queue found !" << std::endl; - exit(1); + assert(true); + return UINT_MAX; } -void vkcontext::check_available_instance_layers(std::vector& needed_layers) { +void vkcontext::check_available_instance_layers(const char* needed_layers[], size_t needed_layers_count) { uint32_t property_count = 0; vkEnumerateInstanceLayerProperties(&property_count, VK_NULL_HANDLE); @@ -251,18 +257,18 @@ void vkcontext::check_available_instance_layers(std::vector& needed uint32_t available_needed_layers_count = 0; - for (auto& layer_property: layer_properties) { - for (auto& needed_layer: needed_layers) { - if (strcmp(layer_property.layerName, needed_layer) == 0) { + for (auto layer_property: layer_properties) { + for (auto layer_index { 0U }; layer_index < needed_layers_count; layer_index++) { + if (strcmp(layer_property.layerName, needed_layers[layer_index]) == 0) { available_needed_layers_count++; } } } - assert(available_needed_layers_count == needed_layers.size()); + assert(available_needed_layers_count == needed_layers_count); } -void vkcontext::check_available_instance_extensions(std::vector& needed_extensions) { +void vkcontext::check_available_instance_extensions(const char* needed_extensions[], size_t needed_extensions_count) { uint32_t vulkan_extensions_count = 0; vkEnumerateInstanceExtensionProperties(VK_NULL_HANDLE, &vulkan_extensions_count, VK_NULL_HANDLE); @@ -271,14 +277,14 @@ void vkcontext::check_available_instance_extensions(std::vector& ne uint32_t available_needed_extensions_count = 0; for (auto& extension: vulkan_extensions_properties) { - for (auto& needed_extension: needed_extensions) { - if (strcmp(extension.extensionName, needed_extension) == 0) { + for (auto extension_index { 0U }; extension_index < needed_extensions_count; extension_index++) { + if (strcmp(extension.extensionName, needed_extensions[extension_index]) == 0) { available_needed_extensions_count++; } } } - assert(available_needed_extensions_count == needed_extensions.size()); + assert(available_needed_extensions_count == needed_extensions_count); } bool vkcontext::support_required_features(VkPhysicalDevice physical_device) { diff --git a/src/vk-renderer.cpp b/src/vk-renderer.cpp index 189ac33..91115ba 100644 --- a/src/vk-renderer.cpp +++ b/src/vk-renderer.cpp @@ -18,8 +18,8 @@ #define VKRESULT(result) result; #endif -vkcontext vkrenderer::context = vkcontext(); -vkapi vkrenderer::api = vkapi(vkrenderer::context); +auto vkrenderer::context = vkcontext(); +auto vkrenderer::api = vkapi(vkrenderer::context); vkrenderer::vkrenderer(window& wnd) { platform_surface = api.create_surface(wnd); @@ -40,15 +40,21 @@ vkrenderer::vkrenderer(window& wnd) { tonemapping_pipeline = api.create_compute_pipeline("tonemapping"); - command_buffers = api.create_command_buffers(virtual_frames_count); + graphics_command_pool = api.create_command_pool(); + api.allocate_command_buffers(graphics_command_pool, graphics_command_buffers, virtual_frames_count); for(size_t index { 0 }; index < virtual_frames_count; index++) { submission_fences[index] = api.create_fence(); execution_semaphores[index] = api.create_semaphore(); acquire_semaphores[index] = api.create_semaphore(); + + copy_command_pools[index] = api.create_command_pool(); + copy_command_buffers[index].resize(initial_copy_command_buffers); + api.allocate_command_buffers(copy_command_pools[index], copy_command_buffers[index].data(), copy_command_buffers[index].size()); } - staging_buffer = api.create_buffer(4096 * 4096 * 4 * sizeof(uint32_t), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); + + // staging_buffer = api.create_buffer(4096 * 4096 * 4 * sizeof(uint32_t), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); } vkrenderer::~vkrenderer() { @@ -58,44 +64,28 @@ vkrenderer::~vkrenderer() { delete renderpass; } + for(size_t index { 0 }; index < virtual_frames_count; index++) { + vkFreeCommandBuffers( + context.device, + copy_command_pools[index], + copy_command_buffers[index].size(), + copy_command_buffers[index].data() + ); + } + api.destroy_fences(submission_fences, virtual_frames_count); api.destroy_semaphores(execution_semaphores, virtual_frames_count); api.destroy_semaphores(acquire_semaphores, virtual_frames_count); - api.destroy_command_buffers(command_buffers); + vkDestroyCommandPool(context.device, graphics_command_pool, nullptr); + + vkFreeCommandBuffers(context.device, graphics_command_pool, virtual_frames_count, graphics_command_buffers); api.destroy_pipeline(tonemapping_pipeline); api.destroy_swapchain(swapchain); api.destroy_surface(platform_surface); } - -void vkrenderer::begin_frame() { - VKRESULT(vkWaitForFences(context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX)) - VKRESULT(vkResetFences(context.device, 1, &submission_fences[virtual_frame_index])) - - swapchain_image_index = 0; - auto acquire_result = vkAcquireNextImageKHR(context.device, swapchain.handle, UINT64_MAX, acquire_semaphores[virtual_frame_index], VK_NULL_HANDLE, &swapchain_image_index); - handle_swapchain_result(acquire_result); - - api.start_record(command_buffers[virtual_frame_index]); -} - -void vkrenderer::finish_frame() { - auto* cmd_buf = command_buffers[virtual_frame_index]; - - // api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, swapchain.images[swapchain_image_index]); - - api.end_record(cmd_buf); - - api.submit(cmd_buf, acquire_semaphores[virtual_frame_index], execution_semaphores[virtual_frame_index], submission_fences[virtual_frame_index]); - - auto present_result = api.present(swapchain, swapchain_image_index, execution_semaphores[virtual_frame_index]); - handle_swapchain_result(present_result); - - virtual_frame_index = ++virtual_frame_index % virtual_frames_count; -} - void vkrenderer::recreate_swapchain() { VKRESULT(vkWaitForFences(context.device, vkrenderer::virtual_frames_count, submission_fences, VK_TRUE, UINT64_MAX)) @@ -117,47 +107,12 @@ void vkrenderer::recreate_swapchain() { } } -void vkrenderer::handle_swapchain_result(VkResult function_result) { - switch(function_result) { - case VK_ERROR_OUT_OF_DATE_KHR: - return recreate_swapchain(); - case VK_ERROR_SURFACE_LOST_KHR: - assert(true && "surface lost"); - default: - return; - } -} - -void vkrenderer::update_image(Texture* texture, void* data) { - auto image = api.get_image(texture->device_image); - auto max_texture_size = image.size.width * image.size.height * 4; - auto buffer = api.get_buffer(staging_buffer); - if (buffer.size < max_texture_size) { - api.destroy_buffer(staging_buffer); - - staging_buffer = api.create_buffer(max_texture_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); - } - - std::memcpy(buffer.device_ptr, data, max_texture_size); - - VKRESULT(vkWaitForFences(context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX)) - VKRESULT(vkResetFences(context.device, 1, &submission_fences[virtual_frame_index])) - - auto* cmd_buf = command_buffers[virtual_frame_index]; - api.start_record(cmd_buf); +void upload_image(void* data, size_t size) { + // copy to staging buffer - api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, texture->device_image); - - api.copy_buffer(cmd_buf, staging_buffer, texture->device_image); - - api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, texture->device_image); - - api.end_record(cmd_buf); - - - api.submit(cmd_buf, VK_NULL_HANDLE, VK_NULL_HANDLE, submission_fences[virtual_frame_index]); - - VKRESULT(vkWaitForFences(context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX)) + // allocate command buffers + // get command buffer + // copy to gpu resident texture } Buffer* vkrenderer::create_buffer(size_t size) { @@ -176,8 +131,9 @@ Buffer* vkrenderer::create_index_buffer(size_t size) { return buffer; } -Texture* vkrenderer::create_2d_texture(size_t width, size_t height, VkFormat format) { +Texture* vkrenderer::create_2d_texture(size_t width, size_t height, VkFormat format, Sampler *sampler) { auto* texture = new Texture(); + texture->sampler = sampler; texture->device_image = api.create_image( { .width = (uint32_t)width, .height = (uint32_t)height, .depth = 1 }, format, @@ -220,7 +176,7 @@ Primitive* vkrenderer::create_primitive(PrimitiveRenderpass& primitive_render_pa void vkrenderer::render() { begin_frame(); - auto* cmd_buf = command_buffers[virtual_frame_index]; + auto* cmd_buf = graphics_command_buffers[virtual_frame_index]; for (auto& renderpass: renderpasses) { renderpass->execute(*this, cmd_buf); @@ -242,7 +198,51 @@ void vkrenderer::render() { finish_frame(); } +// private functions +void vkrenderer::begin_frame() { + + VKRESULT(vkWaitForFences(context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX)) + VKRESULT(vkResetFences(context.device, 1, &submission_fences[virtual_frame_index])) + + swapchain_image_index = 0; + auto acquire_result = vkAcquireNextImageKHR(context.device, swapchain.handle, UINT64_MAX, acquire_semaphores[virtual_frame_index], VK_NULL_HANDLE, &swapchain_image_index); + handle_swapchain_result(acquire_result); + + api.start_record(graphics_command_buffers[virtual_frame_index]); +} + +void vkrenderer::finish_frame() { + auto* cmd_buf = graphics_command_buffers[virtual_frame_index]; + + // api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, swapchain.images[swapchain_image_index]); + + api.end_record(cmd_buf); + + // wait for acquire + copy semaphores + + api.submit_graphics(cmd_buf, acquire_semaphores[virtual_frame_index], execution_semaphores[virtual_frame_index], submission_fences[virtual_frame_index]); + + auto present_result = api.present(swapchain, swapchain_image_index, execution_semaphores[virtual_frame_index]); + handle_swapchain_result(present_result); + + virtual_frame_index = ++virtual_frame_index % virtual_frames_count; +} + + +void vkrenderer::handle_swapchain_result(VkResult function_result) { + switch(function_result) { + case VK_ERROR_OUT_OF_DATE_KHR: + return recreate_swapchain(); + case VK_ERROR_SURFACE_LOST_KHR: + assert(true && "surface lost"); + default: + return; + } +} + + Buffer::Buffer(size_t size) : buffer_size(size) { device_buffer = vkrenderer::api.create_buffer(size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU); } + -- cgit v1.3