From 2d16fbd7e235bf2cc96d451469d8d39cae1917c3 Mon Sep 17 00:00:00 2001 From: ladevieq Date: Thu, 8 Sep 2022 23:04:06 +0200 Subject: First render using new texture uploading system --- CMakeLists.txt | 2 +- include/material.hpp | 16 +++++++++------ include/vk-api.hpp | 3 +-- include/vk-renderer.hpp | 29 ++++++++++++++++---------- src/compute-renderpass.cpp | 4 ++-- src/gltf.cpp | 26 +++++++++++------------ src/main.cpp | 8 ++++++-- src/mesh.cpp | 2 +- src/primitive-renderpass.cpp | 8 ++++---- src/scene.cpp | 35 +++++++++++++++++++++++-------- src/vk-api.cpp | 7 ++++--- src/vk-context.cpp | 2 +- src/vk-renderer.cpp | 49 ++++++++++++++++++++++---------------------- 13 files changed, 112 insertions(+), 79 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1180fe7..6d62555 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake" CACHE STRING "Vcpkg toolchain file") -set(CMAKE_BUILD_TYPE Release) +set(CMAKE_BUILD_TYPE Debug) project(path-tracer VERSION 1.0 LANGUAGES CXX) diff --git a/include/material.hpp b/include/material.hpp index 5ac08f1..71dd4ca 100644 --- a/include/material.hpp +++ b/include/material.hpp @@ -6,12 +6,6 @@ class Texture; -struct gpu_texture { - uint32_t image_id; - uint32_t sampler_id; - uint32_t padding[2]; -}; - struct material { color base_color; Texture* base_color_texture; @@ -19,3 +13,13 @@ struct material { float metalness = 1.f; float roughness = 1.f; }; + +struct gpu_material { + color base_color; + uint32_t albedo_texture_id = 0; + uint32_t albedo_texture_sampler_id = 0; + uint32_t metallic_roughness_texture_id = 0; + uint32_t metallic_roughness_texture_sampler_id = 0; + float metalness = 1.f; + float roughness = 1.f; +}; diff --git a/include/vk-api.hpp b/include/vk-api.hpp index 40ccb50..2318eff 100644 --- a/include/vk-api.hpp +++ b/include/vk-api.hpp @@ -192,8 +192,7 @@ class vkapi { void end_record(VkCommandBuffer command_buffer); - VkResult submit_graphics(VkCommandBuffer command_buffer, VkSemaphore wait_semaphore, VkSemaphore signal_semaphore, VkFence submission_fence) const; - VkResult submit_copy(VkCommandBuffer command_buffer, VkSemaphore wait_semaphore, VkSemaphore signal_semaphore, VkFence submission_fence) const; + VkResult submit(VkCommandBuffer command_buffers[], size_t command_buffers_count, VkSemaphore wait_semaphore, VkSemaphore signal_semaphore, VkFence submission_fence) const; VkResult present(swapchain& swapchain, uint32_t image_index, VkSemaphore wait_semaphore) const; diff --git a/include/vk-renderer.hpp b/include/vk-renderer.hpp index 63dcbf7..614569a 100644 --- a/include/vk-renderer.hpp +++ b/include/vk-renderer.hpp @@ -49,6 +49,10 @@ class vkrenderer { void update_images(); + void begin_frame(); + + void finish_frame(); + static void queue_image_update(Texture* texture); static Buffer* create_buffer(size_t size); @@ -59,8 +63,6 @@ class vkrenderer { static Texture* create_2d_texture(size_t width, size_t height, VkFormat format, Sampler *sampler = nullptr); - static void destroy_2d_texture(Texture* texture); - static Sampler* create_sampler(VkFilter filter, VkSamplerAddressMode address_mode); @@ -86,10 +88,6 @@ class vkrenderer { private: - void begin_frame(); - - void finish_frame(); - void handle_swapchain_result(VkResult function_result); @@ -116,6 +114,7 @@ class vkrenderer { VkSurfaceKHR platform_surface; swapchain swapchain; std::vector swapchain_textures; + std::vector recorded_command_buffers; const uint32_t min_swapchain_image_count = 3; @@ -151,7 +150,7 @@ class RingBuffer { handle device_buffer; size_t buffer_size; - off_t ptr; + off_t ptr = 0; }; class Sampler { @@ -164,7 +163,7 @@ class Texture { public: Texture(handle image_handle) { - auto image = vkrenderer::api.get_image(image_handle); + const auto &image = vkrenderer::api.get_image(image_handle); width = image.size.width; height = image.size.height; depth = image.size.depth; @@ -188,11 +187,19 @@ class Texture { } data = new_data; - // vkrenderer::update_image(this); + vkrenderer::queue_image_update(this); + } + + ~Texture() { + vkrenderer::api.destroy_image(device_image); + + if (data == nullptr) { + free(data); + } } - size_t size() const { - auto image = vkrenderer::api.get_image(device_image); + [[nodiscard]]size_t size() const { + const auto& image = vkrenderer::api.get_image(device_image); return width * height * depth * pixel_size(image.format); } diff --git a/src/compute-renderpass.cpp b/src/compute-renderpass.cpp index 9a1d43e..d5dbaa0 100644 --- a/src/compute-renderpass.cpp +++ b/src/compute-renderpass.cpp @@ -19,7 +19,7 @@ void ComputeRenderpass::set_pipeline(const char* shader_name) { void ComputeRenderpass::set_ouput_texture(Texture* out_texture) { this->output_texture = out_texture; - auto image = api.get_image(output_texture->device_image); + const auto& image = api.get_image(output_texture->device_image); // TODO: Remove hardcoded offset memcpy(constants + 56, &image.bindless_storage_index, sizeof(bindless_index)); @@ -36,7 +36,7 @@ void ComputeRenderpass::set_constant(off_t offset, uint64_t* constant) { } void ComputeRenderpass::set_constant(off_t offset, Texture* texture) { - auto image = api.get_image(texture->device_image); + const auto& image = api.get_image(texture->device_image); memcpy(constants + offset, (void*)&image.bindless_storage_index, sizeof(bindless_index)); diff --git a/src/gltf.cpp b/src/gltf.cpp index 882a64b..64e5644 100644 --- a/src/gltf.cpp +++ b/src/gltf.cpp @@ -69,7 +69,7 @@ void gltf::load_meshes() { const auto &primitives = gltf_meshes[mesh_index]["primitives"]; for (const auto &primitive : primitives) { - auto material = materials[primitive["material"].get()]; + auto& material = materials[primitive["material"].get()]; mesh.add_submesh(load_primitive(primitive), material); } @@ -121,13 +121,14 @@ void gltf::load_textures(const std::filesystem::path &path) { image.data = stbi_load(filepath.c_str(), &image.x, &image.y, &image.n, 4); } - const auto &gltf_samplers = gltf_json["samplers"]; - auto samplers_count = gltf_samplers.size(); - std::vector samplers{samplers_count}; + // const auto &gltf_samplers = gltf_json["samplers"]; + // auto samplers_count = gltf_samplers.size(); + // std::vector samplers{samplers_count}; - for (size_t sampler_index = 0; sampler_index < samplers_count; sampler_index++) { - samplers[sampler_index] = vkrenderer::create_sampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT); - } + Sampler* sampler = vkrenderer::create_sampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT); + // for (size_t sampler_index = 0; sampler_index < samplers_count; sampler_index++) { + // samplers[sampler_index] = vkrenderer::create_sampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT); + // } const auto &gltf_textures = gltf_json["textures"]; auto textures_count = gltf_textures.size(); @@ -137,18 +138,15 @@ void gltf::load_textures(const std::filesystem::path &path) { auto gltf_texture = gltf_textures[texture_index]; auto& image = images[gltf_texture["source"].get()]; - Sampler *sampler = nullptr; - if (gltf_texture.contains("sampler")) { - auto sampler_index = gltf_texture["sampler"].get(); - sampler = samplers[sampler_index]; - } + // if (gltf_texture.contains("sampler")) { + // auto sampler_index = gltf_texture["sampler"].get(); + // sampler = samplers[sampler_index]; + // } auto *texture = vkrenderer::create_2d_texture(static_cast(image.x), static_cast(image.y), VK_FORMAT_R8G8B8A8_UNORM, sampler); texture->update(image.data); - stbi_image_free(image.data); - textures[texture_index] = texture; } } diff --git a/src/main.cpp b/src/main.cpp index 5e39a09..805a0b4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -319,8 +319,8 @@ int main() { renderer.recreate_swapchain(); main_scene.meta.cam.set_aspect_ratio((float)event.width / (float)event.height); - vkrenderer::destroy_2d_texture(accumulation_texture); - vkrenderer::destroy_2d_texture(output_texture); + delete accumulation_texture; + delete output_texture; accumulation_texture = vkrenderer::create_2d_texture(event.width, event.height, VK_FORMAT_R32G32B32A32_SFLOAT); output_texture = vkrenderer::create_2d_texture(event.width, event.height, VK_FORMAT_R32G32B32A32_SFLOAT); raytracing_pass->set_dispatch_size(event.width / 8 + 1, event.height / 8 + 1, 1); @@ -406,6 +406,8 @@ int main() { raytracing_pass->set_ouput_texture(output_texture); raytracing_pass->set_constant(60, accumulation_texture); + renderer.begin_frame(); + // update_ui(main_scene, delta_time); if (can_render) { @@ -414,6 +416,8 @@ int main() { std::swap(output_texture, accumulation_texture); } + renderer.finish_frame(); + frame_count++; } diff --git a/src/mesh.cpp b/src/mesh.cpp index b3916aa..3863ca8 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -42,5 +42,5 @@ void Mesh::add_submesh(const submesh& submesh, material& material) { } void Mesh::register_mesh(const Mesh& mesh) { - meshes.emplace_back(mesh); + meshes.push_back(mesh); } diff --git a/src/primitive-renderpass.cpp b/src/primitive-renderpass.cpp index 316cf6d..45d48e8 100644 --- a/src/primitive-renderpass.cpp +++ b/src/primitive-renderpass.cpp @@ -25,18 +25,18 @@ void Primitive::set_constant(off_t offset, uint64_t* constant) { } void Primitive::set_constant(off_t offset, Texture* texture) { - auto image = api.get_image(texture->device_image); + const auto& image = api.get_image(texture->device_image); memcpy(constants + offset, (void*)&image.bindless_storage_index, sizeof(bindless_index)); } void Primitive::set_constant(off_t offset, Buffer* buffer) { - auto device_buffer = api.get_buffer(buffer->device_buffer); + const auto& device_buffer = api.get_buffer(buffer->device_buffer); memcpy(constants + offset, (void*)&device_buffer.device_address, sizeof(VkDeviceAddress)); } void Primitive::set_constant(off_t offset, Sampler* sampler) { - auto device_sampler = api.get_sampler(sampler->device_sampler); + const auto& device_sampler = api.get_sampler(sampler->device_sampler); memcpy(constants + offset, (void*)&device_sampler.bindless_index, sizeof(bindless_index)); } @@ -93,7 +93,7 @@ void PrimitiveRenderpass::set_viewport(float x, float y, float width, float heig } void PrimitiveRenderpass::set_color_attachment(uint32_t index, Texture* attachment) { - auto device_image = api.get_image(attachment->device_image); + const auto& device_image = api.get_image(attachment->device_image); if (device_image.size.width != framebuffers[0].size.width || device_image.size.height != framebuffers[0].size.height) { diff --git a/src/scene.cpp b/src/scene.cpp index f58ac30..dcbafe3 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -65,11 +65,11 @@ scene::scene(const camera& cam, uint32_t width, uint32_t height) :meta(cam, width, height){ // Geometry & BVH - std::vector indices; - std::vector positions; - std::vector normals; - std::vector uvs; - std::vector materials; + std::vector indices; + std::vector positions; + std::vector normals; + std::vector uvs; + std::vector materials; std::vector packed_nodes; // auto root_node = gltf::load("../models/BistroInterior", "BistroInterior.gltf"); @@ -140,7 +140,26 @@ scene::scene(const camera& cam, uint32_t width, uint32_t height) indices[triangle_offset + 1] = (submesh_level_index_2 + vertex_offset); // | (0xff000000 & (materials.size() << 16)); indices[triangle_offset + 2] = (submesh_level_index_3 + vertex_offset); // | (0xff000000 & (materials.size() << 24)); - // materials.push_back(submesh.mat); + const auto& material = submesh.material; + const auto& albedo_image = vkrenderer::api.get_image(material.base_color_texture->device_image); + const auto& albedo_sampler = vkrenderer::api.get_sampler(material.base_color_texture->sampler->device_sampler); + + materials.emplace_back(gpu_material { + .base_color = material.base_color, + .albedo_texture_id = albedo_image.bindless_sampled_index, + .albedo_texture_sampler_id = albedo_sampler.bindless_index, + .metalness = material.metalness, + .roughness = material.roughness + }); + + if (material.metallic_roughness_texture != nullptr) { + auto& gpu_material = materials.back(); + const auto& metallic_roughness_image = vkrenderer::api.get_image(material.metallic_roughness_texture->device_image); + const auto& metallic_roughness_sampler = vkrenderer::api.get_sampler(material.metallic_roughness_texture->sampler->device_sampler); + + gpu_material.metallic_roughness_texture_id = metallic_roughness_image.bindless_sampled_index; + gpu_material.metallic_roughness_texture_sampler_id = metallic_roughness_sampler.bindless_index; + } } } @@ -180,6 +199,6 @@ scene::scene(const camera& cam, uint32_t width, uint32_t height) bvh_buffer = vkrenderer::create_buffer(packed_nodes.size() * sizeof(packed_nodes[0])); bvh_buffer->write(packed_nodes.data(), 0, packed_nodes.size() * sizeof(packed_nodes[0])); - // materials_buffer = vkrenderer::create_buffer(materials.size() * sizeof(materials[0])); - // materials_buffer->write(materials.data(), 0, materials.size() * sizeof(materials[0])); + materials_buffer = vkrenderer::create_buffer(materials.size() * sizeof(materials[0])); + materials_buffer->write(materials.data(), 0, materials.size() * sizeof(materials[0])); } diff --git a/src/vk-api.cpp b/src/vk-api.cpp index 04e5cc0..cb9ec0a 100644 --- a/src/vk-api.cpp +++ b/src/vk-api.cpp @@ -281,6 +281,7 @@ handle vkapi::create_image(VkExtent3D size, VkFormat format, VkImageUsageFlags u VKRESULT(vkCreateImageView(context.device, &image_view_create_info, VK_NULL_HANDLE, &image->view)) + image->format = format; image->usages = usages; image->device_ptr = alloc_info.pMappedData; @@ -1226,7 +1227,7 @@ void vkapi::end_record(VkCommandBuffer command_buffer) { VKRESULT(vkEndCommandBuffer(command_buffer)) } -VkResult vkapi::submit_graphics(VkCommandBuffer command_buffer, VkSemaphore wait_semaphore, VkSemaphore signal_semaphore, VkFence submission_fence) const { +VkResult vkapi::submit(VkCommandBuffer command_buffers[], size_t command_buffers_count, VkSemaphore wait_semaphore, VkSemaphore signal_semaphore, VkFence submission_fence) const { VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; VkSubmitInfo submit_info = {}; @@ -1237,8 +1238,8 @@ VkResult vkapi::submit_graphics(VkCommandBuffer command_buffer, VkSemaphore wait 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; + submit_info.commandBufferCount = command_buffers_count; + submit_info.pCommandBuffers = command_buffers; return vkQueueSubmit(context.graphics_queue.handle, 1, &submit_info, submission_fence); } diff --git a/src/vk-context.cpp b/src/vk-context.cpp index e4a8815..824c216 100644 --- a/src/vk-context.cpp +++ b/src/vk-context.cpp @@ -284,7 +284,7 @@ void vkcontext::check_available_instance_extensions(const char* needed_extension } } - assert(available_needed_extensions_count == needed_extensions_count); + // 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 bfe8e5d..1cbf0be 100644 --- a/src/vk-renderer.cpp +++ b/src/vk-renderer.cpp @@ -52,6 +52,7 @@ vkrenderer::vkrenderer(window& wnd) { api.allocate_command_buffers(copy_command_pools[index], ©_command_buffers[index], 1); // staging_buffers[index] = create_staging_buffer(4096 * 4096 * sizeof(uint32_t)); + staging_buffers[index] = new RingBuffer(4096ULL * 4096ULL * sizeof(uint32_t)); } } @@ -64,15 +65,16 @@ vkrenderer::~vkrenderer() { for(size_t index { 0 }; index < virtual_frames_count; index++) { vkFreeCommandBuffers(context.device, copy_command_pools[index], 1, ©_command_buffers[index]); + vkDestroyCommandPool(context.device, copy_command_pools[index], nullptr); } api.destroy_fences(submission_fences, virtual_frames_count); api.destroy_semaphores(execution_semaphores, virtual_frames_count); api.destroy_semaphores(acquire_semaphores, virtual_frames_count); + vkFreeCommandBuffers(context.device, graphics_command_pool, virtual_frames_count, graphics_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); @@ -109,7 +111,9 @@ void vkrenderer::update_images() { VkCommandBuffer command_buffer = copy_command_buffers[virtual_frame_index]; vkrenderer::api.start_record(command_buffer); - for (auto* texture : upload_queue) { + while(!upload_queue.empty()) { + auto* texture = upload_queue.back(); + upload_queue.pop_back(); auto texture_size = texture->size(); auto offset = staging_buffer->alloc(texture_size); @@ -119,10 +123,14 @@ void vkrenderer::update_images() { staging_buffer->write(texture->data, offset, texture_size); + vkrenderer::api.image_barrier(command_buffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, texture->device_image); vkrenderer::api.copy_buffer(command_buffer, staging_buffer->device_buffer, texture->device_image, offset); + vkrenderer::api.image_barrier(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, texture->device_image); } vkrenderer::api.end_record(command_buffer); + + recorded_command_buffers.push_back(command_buffer); } Buffer* vkrenderer::create_buffer(size_t size) { @@ -141,11 +149,6 @@ Texture* vkrenderer::create_2d_texture(size_t width, size_t height, VkFormat for return new Texture(width, height, 1, format, sampler); } -void vkrenderer::destroy_2d_texture(Texture* texture) { - api.destroy_image(texture->device_image); - delete texture; -} - // TODO: Check if a similar sampler has been allocated Sampler* vkrenderer::create_sampler(VkFilter filter, VkSamplerAddressMode address_mode) { auto* sampler = new Sampler(); @@ -172,10 +175,16 @@ Primitive* vkrenderer::create_primitive(PrimitiveRenderpass& primitive_render_pa } void vkrenderer::render() { - begin_frame(); + 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]); auto* cmd_buf = graphics_command_buffers[virtual_frame_index]; + // wait for transfer operations + for (auto& renderpass: renderpasses) { renderpass->execute(*this, cmd_buf); @@ -193,32 +202,22 @@ void vkrenderer::render() { api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, swapchain.images[swapchain_image_index]); - finish_frame(); + api.end_record(cmd_buf); + + recorded_command_buffers.push_back(cmd_buf); } -// private functions void vkrenderer::begin_frame() { + recorded_command_buffers.clear(); 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]); + update_images(); } 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); - - - // TODO: Submit copy command buffer - api.submit_graphics(cmd_buf, acquire_semaphores[virtual_frame_index], execution_semaphores[virtual_frame_index], submission_fences[virtual_frame_index]); + api.submit(recorded_command_buffers.data(), recorded_command_buffers.size(), 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); @@ -227,6 +226,8 @@ void vkrenderer::finish_frame() { } + +// private functions void vkrenderer::handle_swapchain_result(VkResult function_result) { switch(function_result) { case VK_ERROR_OUT_OF_DATE_KHR: -- cgit v1.3