diff options
| -rw-r--r-- | include/vk-api.hpp | 2 | ||||
| -rw-r--r-- | include/vk-renderer.hpp | 131 | ||||
| -rw-r--r-- | src/gltf.cpp | 2 | ||||
| -rw-r--r-- | src/vk-api.cpp | 5 | ||||
| -rw-r--r-- | src/vk-renderer.cpp | 113 |
5 files changed, 151 insertions, 102 deletions
diff --git a/include/vk-api.hpp b/include/vk-api.hpp index 6baaa73..40ccb50 100644 --- a/include/vk-api.hpp +++ b/include/vk-api.hpp @@ -115,7 +115,7 @@ class vkapi { handle create_buffer(size_t data_size, VkBufferUsageFlags buffer_usage, uint32_t mem_usage); void copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst, size_t size); - void copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst); + void copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst, off_t buffer_offset = 0); void destroy_buffer(handle buffer); diff --git a/include/vk-renderer.hpp b/include/vk-renderer.hpp index ca4c261..63dcbf7 100644 --- a/include/vk-renderer.hpp +++ b/include/vk-renderer.hpp @@ -2,6 +2,7 @@ #define __VK_RENDERER_HPP_ #include <cstdint> +#include <format> #include <vector> #include "vk-context.hpp" @@ -15,10 +16,28 @@ class Primitive; class window; class Texture; -class Buffer; class Sampler; class RingBuffer; + +class Buffer { + public: + + Buffer(size_t size, VkBufferUsageFlagBits usage); + ~Buffer(); + + void write(void* data, off_t alloc_offset, size_t data_size) const; + + void resize(size_t new_size); + + handle device_buffer; + + size_t buffer_size; + + VkBufferUsageFlagBits usage; +}; + + class vkrenderer { public: vkrenderer(window& wnd); @@ -28,10 +47,16 @@ class vkrenderer { void recreate_swapchain(); + void update_images(); + + static void queue_image_update(Texture* texture); + static Buffer* create_buffer(size_t size); static Buffer* create_index_buffer(size_t size); + static Buffer* create_staging_buffer(size_t size); + static Texture* create_2d_texture(size_t width, size_t height, VkFormat format, Sampler *sampler = nullptr); static void destroy_2d_texture(Texture* texture); @@ -47,8 +72,6 @@ class vkrenderer { void render(); - RingBuffer* get_staging_buffer() { return staging_buffer; } - [[nodiscard]]uint32_t frame_index() const { return this->virtual_frame_index; } [[nodiscard]]Texture* back_buffer() const { return swapchain_textures[swapchain_image_index]; } @@ -72,14 +95,13 @@ class vkrenderer { std::vector<Renderpass*> renderpasses; - static constexpr uint32_t initial_copy_command_buffers = 10U; uint32_t virtual_frame_index = 0; uint32_t swapchain_image_index = 0; VkCommandBuffer graphics_command_buffers[virtual_frames_count]; - std::vector<VkCommandBuffer> copy_command_buffers[virtual_frames_count]; + VkCommandBuffer copy_command_buffers[virtual_frames_count]; - RingBuffer* staging_buffer; + RingBuffer* staging_buffers[virtual_frames_count]; pipeline tonemapping_pipeline; @@ -96,20 +118,24 @@ class vkrenderer { std::vector<Texture*> swapchain_textures; const uint32_t min_swapchain_image_count = 3; + + static std::vector<Texture*> upload_queue; }; class RingBuffer { public: - RingBuffer(size_t size) - : buffer_size(size) {} - [[nodiscard]]size_t alloc(size_t alloc_size) const { + static const off_t invalid_alloc = -1; + + RingBuffer(size_t size); + + [[nodiscard]]off_t alloc(size_t alloc_size) const { assert(alloc_size > 0); if (ptr + alloc_size < buffer_size) { return ptr; } - return 0; + return invalid_alloc; } void write(void* data, off_t alloc_offset, size_t data_size) const { @@ -134,66 +160,59 @@ class Sampler { handle device_sampler; }; -// TODO: Move those to there own files class Texture { public: - void write(void* data) const { - auto image = vkrenderer::api.get_image(device_image); - auto texture_size = image.size.width * image.size.height * 4; - - // TODO: Do all this inside vkrenderer - // auto* buffer = vkrenderer::get_staging_buffer(); - // auto alloc_offset = buffer->alloc(texture_size); - // assert(alloc_offset > 0); - - // // std::memcpy(buffer.device_ptr, data, texture_size); - // buffer->write(data, alloc_offset, texture_size); - - // vkrenderer::api.create_command_buffers - // submit upload work - // VKRESULT(vkWaitForFences(vkrenderer::context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX)) - // VKRESULT(vkResetFences(vkrenderer::context.device, 1, &submission_fences[virtual_frame_index])) + Texture(handle image_handle) { + auto image = vkrenderer::api.get_image(image_handle); + width = image.size.width; + height = image.size.height; + depth = image.size.depth; - // auto* cmd_buf = command_buffers[virtual_frame_index]; - // api.start_record(cmd_buf); - - // api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, device_image); - - // api.copy_buffer(cmd_buf, buffer, device_image); - - // api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, device_image); - - // api.end_record(cmd_buf); - - - - // VKRESULT(vkWaitForFences(vkrenderer::context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX)) + device_image = image_handle; } - Sampler* sampler = nullptr; + Texture(size_t width, size_t height, size_t depth, VkFormat format = VK_FORMAT_R8G8B8A8_UNORM, Sampler* texture_sampler = nullptr) + : width(width), height(height), depth(depth) { + sampler = texture_sampler; + device_image = vkrenderer::api.create_image( + { .width = (uint32_t)width, .height = (uint32_t)height, .depth = 1 }, + format, + VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + ); + } - handle device_image; -}; + void update(void* new_data) { + if (data == nullptr) { + free(data); + } + data = new_data; -class Buffer { - public: + // vkrenderer::update_image(this); + } - Buffer(size_t size); + size_t size() const { + auto image = vkrenderer::api.get_image(device_image); + return width * height * depth * pixel_size(image.format); + } - ~Buffer() { - vkrenderer::api.destroy_buffer(device_buffer); + static size_t pixel_size(VkFormat format) { + switch (format) { + case VK_FORMAT_R8G8B8A8_UNORM: + return 4; + default: + return 0; + } } - void write(void* data, off_t alloc_offset, size_t data_size) const { - auto api_buffer = vkrenderer::api.get_buffer(device_buffer); + Sampler* sampler = nullptr; - std::memcpy((uint8_t*)api_buffer.device_ptr + alloc_offset, data, data_size); - } + void* data = nullptr; - handle device_buffer; + size_t width = 0; + size_t height = 0; + size_t depth = 0; - size_t buffer_size; + handle device_image; }; - #endif // !__VK_RENDERER_HPP_ diff --git a/src/gltf.cpp b/src/gltf.cpp index 59094d9..882a64b 100644 --- a/src/gltf.cpp +++ b/src/gltf.cpp @@ -145,7 +145,7 @@ void gltf::load_textures(const std::filesystem::path &path) { 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); + texture->update(image.data); stbi_image_free(image.data); diff --git a/src/vk-api.cpp b/src/vk-api.cpp index 81242a5..04e5cc0 100644 --- a/src/vk-api.cpp +++ b/src/vk-api.cpp @@ -200,7 +200,8 @@ void vkapi::copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst, size_t vkCmdCopyBuffer(cmd_buf, buffers[src]->handle, buffers[dst]->handle, 1, &buffer_copy); } -void vkapi::copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst) { +// TODO: Change handle type, here we don't know what type of ressources we are working with +void vkapi::copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst, off_t buffer_offset) { auto& dst_image = images[dst]; VkImageSubresourceLayers image_subresource_layers = {}; @@ -210,7 +211,7 @@ void vkapi::copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst) { image_subresource_layers.layerCount = 1; VkBufferImageCopy buffer_to_image_copy = {}; - buffer_to_image_copy.bufferOffset = 0; + buffer_to_image_copy.bufferOffset = buffer_offset; buffer_to_image_copy.bufferRowLength = 0; buffer_to_image_copy.bufferImageHeight = 0; buffer_to_image_copy.imageSubresource = image_subresource_layers; diff --git a/src/vk-renderer.cpp b/src/vk-renderer.cpp index 91115ba..bfe8e5d 100644 --- a/src/vk-renderer.cpp +++ b/src/vk-renderer.cpp @@ -20,6 +20,7 @@ auto vkrenderer::context = vkcontext(); auto vkrenderer::api = vkapi(vkrenderer::context); +auto vkrenderer::upload_queue = std::vector<Texture*>(); vkrenderer::vkrenderer(window& wnd) { platform_surface = api.create_surface(wnd); @@ -34,8 +35,7 @@ vkrenderer::vkrenderer(window& wnd) { swapchain_textures.resize(swapchain.image_count); for (size_t index = 0; index < swapchain.image_count; index++) { - swapchain_textures[index] = new Texture(); - swapchain_textures[index]->device_image = swapchain.images[index]; + swapchain_textures[index] = new Texture(swapchain.images[index]); } tonemapping_pipeline = api.create_compute_pipeline("tonemapping"); @@ -49,12 +49,10 @@ vkrenderer::vkrenderer(window& wnd) { 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()); - } - + api.allocate_command_buffers(copy_command_pools[index], ©_command_buffers[index], 1); - // staging_buffer = api.create_buffer(4096 * 4096 * 4 * sizeof(uint32_t), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); + // staging_buffers[index] = create_staging_buffer(4096 * 4096 * sizeof(uint32_t)); + } } vkrenderer::~vkrenderer() { @@ -65,12 +63,7 @@ vkrenderer::~vkrenderer() { } 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() - ); + vkFreeCommandBuffers(context.device, copy_command_pools[index], 1, ©_command_buffers[index]); } api.destroy_fences(submission_fences, virtual_frames_count); @@ -102,45 +95,50 @@ void vkrenderer::recreate_swapchain() { swapchain_textures.resize(swapchain.image_count); for (size_t index = 0; index < swapchain.image_count; index++) { - swapchain_textures[index] = new Texture(); - swapchain_textures[index]->device_image = swapchain.images[index]; + swapchain_textures[index] = new Texture(swapchain.images[index]); } } -void upload_image(void* data, size_t size) { - // copy to staging buffer - - // allocate command buffers - // get command buffer - // copy to gpu resident texture +void vkrenderer::queue_image_update(Texture* texture) { + upload_queue.push_back(texture); } -Buffer* vkrenderer::create_buffer(size_t size) { - auto* buffer = new Buffer(size); +void vkrenderer::update_images() { + auto* staging_buffer = staging_buffers[virtual_frame_index]; - buffer->device_buffer = api.create_buffer(size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU); + VkCommandBuffer command_buffer = copy_command_buffers[virtual_frame_index]; + vkrenderer::api.start_record(command_buffer); - return buffer; + for (auto* texture : upload_queue) { + auto texture_size = texture->size(); + auto offset = staging_buffer->alloc(texture_size); + + if (offset == RingBuffer::invalid_alloc) { + break; + } + + staging_buffer->write(texture->data, offset, texture_size); + + vkrenderer::api.copy_buffer(command_buffer, staging_buffer->device_buffer, texture->device_image, offset); + } + + vkrenderer::api.end_record(command_buffer); } -Buffer* vkrenderer::create_index_buffer(size_t size) { - auto* buffer = new Buffer(size); +Buffer* vkrenderer::create_buffer(size_t size) { + return new Buffer(size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); +} - buffer->device_buffer = api.create_buffer(size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU); +Buffer* vkrenderer::create_index_buffer(size_t size) { + return new Buffer(size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT); +} - return buffer; +Buffer* vkrenderer::create_staging_buffer(size_t size) { + return new Buffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); } 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, - VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - ); - - return texture; + return new Texture(width, height, 1, format, sampler); } void vkrenderer::destroy_2d_texture(Texture* texture) { @@ -218,8 +216,8 @@ void vkrenderer::finish_frame() { api.end_record(cmd_buf); - // wait for acquire + copy semaphores + // 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]); auto present_result = api.present(swapchain, swapchain_image_index, execution_semaphores[virtual_frame_index]); @@ -241,8 +239,39 @@ void vkrenderer::handle_swapchain_result(VkResult function_result) { } -Buffer::Buffer(size_t size) + +Buffer::Buffer(size_t size, VkBufferUsageFlagBits usage) + : buffer_size(size), usage(usage) { + device_buffer = vkrenderer::api.create_buffer(size, usage, VMA_MEMORY_USAGE_CPU_TO_GPU); +} + +Buffer::~Buffer() { + vkrenderer::api.destroy_buffer(device_buffer); +} + +void Buffer::write(void* data, off_t alloc_offset, size_t data_size) const { + auto api_buffer = vkrenderer::api.get_buffer(device_buffer); + + std::memcpy((uint8_t*)api_buffer.device_ptr + alloc_offset, data, data_size); +} + +void Buffer::resize(size_t new_size) { + auto old_device_buffer = device_buffer; + new_size = static_cast<uint32_t>(exp2(ceil(log2((double)new_size)))); + + device_buffer = vkrenderer::api.create_buffer(new_size, usage, VMA_MEMORY_USAGE_CPU_TO_GPU); + + auto old_buffer = vkrenderer::api.get_buffer(device_buffer); + auto new_buffer = vkrenderer::api.get_buffer(device_buffer); + std::memcpy(new_buffer.device_ptr, old_buffer.device_ptr, buffer_size); + + buffer_size = new_size; + + vkrenderer::api.destroy_buffer(old_device_buffer); +} + + +RingBuffer::RingBuffer(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); + device_buffer = vkrenderer::api.create_buffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); } - |
