aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt27
-rw-r--r--src/gltf.cpp47
-rw-r--r--src/main.cpp2
-rw-r--r--src/mesh.cpp4
-rw-r--r--src/vk-api.cpp125
-rw-r--r--src/vk-context.cpp76
-rw-r--r--src/vk-renderer.cpp148
7 files changed, 215 insertions, 214 deletions
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<std::string>();
- 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<std::string>();
+ 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<uint32_t>()];
+ 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<uint32_t>()]["count"].get<uint32_t>();
submesh.vertex_count = gltf_json["accessors"][primitive["attributes"]["POSITION"].get<uint32_t>()]["count"].get<uint32_t>();
- // submesh.mat = materials[gltf_primitive["material"].get<uint32_t>()];
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<Texture *> images{images_count};
+ std::vector<raw_image> 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<std::string>()).string();
- unsigned char *data = stbi_load(filepath.c_str(), &x, &y, &n, 4);
- auto *img = vkrenderer::create_2d_texture(static_cast<uint32_t>(x), static_cast<uint32_t>(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<uint32_t>();
- 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<uint32_t>()];
+ Sampler *sampler = nullptr;
if (gltf_texture.contains("sampler")) {
auto sampler_index = gltf_texture["sampler"].get<uint32_t>();
- 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<uint32_t>(image.x), static_cast<uint32_t>(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 <dlfcn.h>
#include <unistd.h>
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<Mesh> 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<VkDescriptorPoolSize> 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<VkCommandBuffer> 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<VkCommandBuffer> 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<VkCommandBuffer> &command_buffers) {
- vkFreeCommandBuffers(context.device, command_pool, command_buffers.size(), command_buffers.data());
-}
-
-
// TODO: attachment structure
VkRenderPass vkapi::create_render_pass(std::vector<VkFormat>& color_attachments_format, VkImageLayout initial_layout, VkImageLayout final_layout) {
std::vector<VkAttachmentDescription> 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<uint8_t> 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<VkDescriptorSet> vkapi::create_descriptor_sets(VkDescriptorSetLayout descriptor_sets_layout, size_t descriptor_sets_count) {
- std::vector<VkDescriptorSetLayout> 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<VkDescriptorSet> 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<VkDescriptorSet> &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];
+ 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;
+ 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 <iostream>
#include <cassert>
+#include <vector>
+#include <array>
#define VMA_IMPLEMENTATION
#include <vk_mem_alloc.h>
@@ -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<const char*> 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<const char*> 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;
+ 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,
- float queue_priority = 1.f;
- queue_create_info.pQueuePriorities = &queue_priority;
+ .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<const char*> 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<VkPhysicalDevice> 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<const char*>& 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<const char*>& 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<const char*>& 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<const char*>& 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);
}
+