diff --git a/config/visual-studio/renderer.vcxproj b/config/visual-studio/renderer.vcxproj index 0d592d3..c071283 100644 --- a/config/visual-studio/renderer.vcxproj +++ b/config/visual-studio/renderer.vcxproj @@ -104,7 +104,6 @@ - @@ -136,7 +135,6 @@ - diff --git a/config/visual-studio/renderer.vcxproj.filters b/config/visual-studio/renderer.vcxproj.filters index 573c97b..17ad847 100644 --- a/config/visual-studio/renderer.vcxproj.filters +++ b/config/visual-studio/renderer.vcxproj.filters @@ -92,9 +92,6 @@ Source Files - - Source Files - Source Files @@ -148,9 +145,6 @@ Header Files - - Source Files - Source Files diff --git a/src/engine/renderer/tr_backend.c b/src/engine/renderer/tr_backend.c index ce26b84..6666f7a 100644 --- a/src/engine/renderer/tr_backend.c +++ b/src/engine/renderer/tr_backend.c @@ -736,8 +736,8 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte * Vk_Image& vk_image = tr.vk_resources.images[tr.scratchImage[client]->index]; vkDestroyImage(vk.device, vk_image.image, nullptr); vkDestroyImageView(vk.device, vk_image.image_view, nullptr); - vk_image.image = vk_create_cinematic_image(cols, rows, vk_image.staging_buffer, vk_image.image_view); - vk_update_cinematic_image(vk_image.image, vk_image.staging_buffer, cols, rows, data); + vk_image.image = vk_create_cinematic_image(cols, rows, vk_image.image_view); + vk_update_cinematic_image(vk_image.image, cols, rows, data); VkDescriptorImageInfo image_info; image_info.sampler = vk.sampler; @@ -765,7 +765,7 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte * // VULKAN const Vk_Image& vk_image = tr.vk_resources.images[tr.scratchImage[client]->index]; - vk_update_cinematic_image(vk_image.image, vk_image.staging_buffer, cols, rows, data); + vk_update_cinematic_image(vk_image.image, cols, rows, data); } } diff --git a/src/engine/renderer/vk.cpp b/src/engine/renderer/vk.cpp index cf3d653..e72274d 100644 --- a/src/engine/renderer/vk.cpp +++ b/src/engine/renderer/vk.cpp @@ -1,10 +1,9 @@ #include "tr_local.h" -#include "vk_allocator.h" - #include #include #include +#include FILE* vk_log_file; @@ -492,25 +491,46 @@ static void allocate_and_bind_image_memory(VkImage image) { VK_CHECK(vkBindImageMemory(vk.device, image, chunk->memory, chunk->used - memory_requirements.size)); } -static void ensure_allocation_for_staging_buffer(VkBuffer buffer) { +static void ensure_staging_buffer_allocation(VkDeviceSize size) { + if (tr.vk_resources.staging_buffer_size >= size) + return; + + if (tr.vk_resources.staging_buffer != VK_NULL_HANDLE) + vkDestroyBuffer(vk.device, tr.vk_resources.staging_buffer, nullptr); + + if (tr.vk_resources.staging_buffer_memory != VK_NULL_HANDLE) + vkFreeMemory(vk.device, tr.vk_resources.staging_buffer_memory, nullptr); + + tr.vk_resources.staging_buffer_size = size; + + VkBufferCreateInfo buffer_desc; + buffer_desc.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_desc.pNext = nullptr; + buffer_desc.flags = 0; + buffer_desc.size = size; + buffer_desc.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + buffer_desc.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + buffer_desc.queueFamilyIndexCount = 0; + buffer_desc.pQueueFamilyIndices = nullptr; + VK_CHECK(vkCreateBuffer(vk.device, &buffer_desc, nullptr, &tr.vk_resources.staging_buffer)); + VkMemoryRequirements memory_requirements; - vkGetBufferMemoryRequirements(vk.device, buffer, &memory_requirements); + vkGetBufferMemoryRequirements(vk.device, tr.vk_resources.staging_buffer, &memory_requirements); - if (tr.vk_resources.texture_staging_memory_size < memory_requirements.size) { - if (tr.vk_resources.texture_staging_memory != VK_NULL_HANDLE) { - vkFreeMemory(vk.device, tr.vk_resources.texture_staging_memory, nullptr); - } + uint32_t memory_type = find_memory_type(vk.physical_device, memory_requirements.memoryTypeBits, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - VkMemoryAllocateInfo alloc_info; - alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - alloc_info.pNext = nullptr; - alloc_info.allocationSize = memory_requirements.size; - alloc_info.memoryTypeIndex = find_memory_type(vk.physical_device, memory_requirements.memoryTypeBits, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + VkMemoryAllocateInfo alloc_info; + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.pNext = nullptr; + alloc_info.allocationSize = memory_requirements.size; + alloc_info.memoryTypeIndex = memory_type; + VK_CHECK(vkAllocateMemory(vk.device, &alloc_info, nullptr, &tr.vk_resources.staging_buffer_memory)); + VK_CHECK(vkBindBufferMemory(vk.device, tr.vk_resources.staging_buffer, tr.vk_resources.staging_buffer_memory, 0)); - VK_CHECK(vkAllocateMemory(vk.device, &alloc_info, nullptr, &tr.vk_resources.texture_staging_memory)); - tr.vk_resources.texture_staging_memory_size = memory_requirements.size; - } + void* data; + VK_CHECK(vkMapMemory(vk.device, tr.vk_resources.staging_buffer_memory, 0, VK_WHOLE_SIZE, 0, &data)); + tr.vk_resources.staging_buffer_ptr = (byte*)data; } static void deallocate_image_chunks() { @@ -864,7 +884,6 @@ void vk_deinitialize() { fclose(vk_log_file); vk_log_file = nullptr; - get_allocator()->deallocate_all(); deallocate_image_chunks(); vkDestroyImage(vk.device, vk.depth_image, nullptr); @@ -931,27 +950,8 @@ static void record_buffer_memory_barrier(VkCommandBuffer cb, VkBuffer buffer, VkImage vk_create_texture(const uint8_t* rgba_pixels, int image_width, int image_height, VkImageView& image_view) { int image_size = image_width * image_height * 4; - // create staging buffer - VkBufferCreateInfo buffer_desc; - buffer_desc.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buffer_desc.pNext = nullptr; - buffer_desc.flags = 0; - buffer_desc.size = image_size; - buffer_desc.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - buffer_desc.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - buffer_desc.queueFamilyIndexCount = 0; - buffer_desc.pQueueFamilyIndices = nullptr; - - VkBuffer staging_buffer; - VK_CHECK(vkCreateBuffer(vk.device, &buffer_desc, nullptr, &staging_buffer)); - - ensure_allocation_for_staging_buffer(staging_buffer); - VK_CHECK(vkBindBufferMemory(vk.device, staging_buffer, tr.vk_resources.texture_staging_memory, 0)); - - void* buffer_data; - VK_CHECK(vkMapMemory(vk.device, tr.vk_resources.texture_staging_memory, 0, image_size, 0, &buffer_data)); - Com_Memcpy(buffer_data, rgba_pixels, image_size); - vkUnmapMemory(vk.device, tr.vk_resources.texture_staging_memory); + ensure_staging_buffer_allocation(image_size); + Com_Memcpy(tr.vk_resources.staging_buffer_ptr, rgba_pixels, image_size); // create texture image VkImageCreateInfo desc; @@ -979,9 +979,9 @@ VkImage vk_create_texture(const uint8_t* rgba_pixels, int image_width, int image // copy buffer's content to texture record_and_run_commands(vk.command_pool, vk.queue, - [&texture_image, &staging_buffer, &image_width, &image_height](VkCommandBuffer command_buffer) { + [&texture_image, &image_width, &image_height](VkCommandBuffer command_buffer) { - record_buffer_memory_barrier(command_buffer, staging_buffer, + record_buffer_memory_barrier(command_buffer, tr.vk_resources.staging_buffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); @@ -999,35 +999,17 @@ VkImage vk_create_texture(const uint8_t* rgba_pixels, int image_width, int image region.imageOffset = VkOffset3D{ 0, 0, 0 }; region.imageExtent = VkExtent3D{ (uint32_t)image_width, (uint32_t)image_height, 1 }; - vkCmdCopyBufferToImage(command_buffer, staging_buffer, texture_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + vkCmdCopyBufferToImage(command_buffer, tr.vk_resources.staging_buffer, texture_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); record_image_layout_transition(command_buffer, texture_image, VK_FORMAT_R8G8B8A8_UNORM, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); }); - vkDestroyBuffer(vk.device, staging_buffer, nullptr); - image_view = create_image_view(texture_image, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); return texture_image; } -VkImage vk_create_cinematic_image(int width, int height, Vk_Staging_Buffer& staging_buffer, VkImageView& image_view) { - VkBufferCreateInfo buffer_desc; - buffer_desc.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buffer_desc.pNext = nullptr; - buffer_desc.flags = 0; - buffer_desc.size = width * height * 4; - buffer_desc.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - buffer_desc.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - buffer_desc.queueFamilyIndexCount = 0; - buffer_desc.pQueueFamilyIndices = nullptr; - - VkBuffer buffer; - VK_CHECK(vkCreateBuffer(vk.device, &buffer_desc, nullptr, &buffer)); - - VkDeviceMemory buffer_memory = get_allocator()->allocate_staging_memory(buffer); - VK_CHECK(vkBindBufferMemory(vk.device, buffer, buffer_memory, 0)); - +VkImage vk_create_cinematic_image(int width, int height, VkImageView& image_view) { VkImageCreateInfo image_desc; image_desc.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_desc.pNext = nullptr; @@ -1049,27 +1031,23 @@ VkImage vk_create_cinematic_image(int width, int height, Vk_Staging_Buffer& stag VkImage image; VK_CHECK(vkCreateImage(vk.device, &image_desc, nullptr, &image)); - allocate_and_bind_image_memory(image); - - staging_buffer.handle = buffer; - staging_buffer.memory = buffer_memory; - staging_buffer.offset = 0; - staging_buffer.size = width * height * 4; - image_view = create_image_view(image, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); - return image; } -void vk_update_cinematic_image(VkImage image, const Vk_Staging_Buffer& staging_buffer, int width, int height, const uint8_t* rgba_pixels) { - void* buffer_data; - VK_CHECK(vkMapMemory(vk.device, staging_buffer.memory, staging_buffer.offset, staging_buffer.size, 0, &buffer_data)); - memcpy(buffer_data, rgba_pixels, staging_buffer.size); - vkUnmapMemory(vk.device, staging_buffer.memory); +void vk_update_cinematic_image(VkImage image, int width, int height, const uint8_t* rgba_pixels) { + VkDeviceSize size = width * height * 4; + + ensure_staging_buffer_allocation(size); + Com_Memcpy(tr.vk_resources.staging_buffer_ptr, rgba_pixels, size); record_and_run_commands(vk.command_pool, vk.queue, - [&image, &staging_buffer, &width, &height](VkCommandBuffer command_buffer) { + [&image, &width, &height](VkCommandBuffer command_buffer) { + + record_buffer_memory_barrier(command_buffer, tr.vk_resources.staging_buffer, + VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); record_image_layout_transition(command_buffer, image, VK_FORMAT_R8G8B8A8_UNORM, 0, VK_IMAGE_LAYOUT_UNDEFINED, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); @@ -1085,7 +1063,7 @@ void vk_update_cinematic_image(VkImage image, const Vk_Staging_Buffer& staging_b region.imageOffset = VkOffset3D{ 0, 0, 0 }; region.imageExtent = VkExtent3D{ (uint32_t)width, (uint32_t)height, 1 }; - vkCmdCopyBufferToImage(command_buffer, staging_buffer.handle, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + vkCmdCopyBufferToImage(command_buffer, tr.vk_resources.staging_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); record_image_layout_transition(command_buffer, image, VK_FORMAT_R8G8B8A8_UNORM, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); @@ -1477,8 +1455,11 @@ void vk_destroy_resources() { auto& res = tr.vk_resources; - if (res.texture_staging_memory != VK_NULL_HANDLE) - vkFreeMemory(vk.device, res.texture_staging_memory, nullptr); + if (res.staging_buffer != VK_NULL_HANDLE) + vkDestroyBuffer(vk.device, res.staging_buffer, nullptr); + + if (res.staging_buffer_memory != VK_NULL_HANDLE) + vkFreeMemory(vk.device, res.staging_buffer_memory, nullptr); // Destroy pipelines for (int i = 0; i < tr.vk_resources.num_pipelines; i++) { @@ -1495,9 +1476,6 @@ void vk_destroy_resources() { vkDestroyImage(vk.device, vk_image.image, nullptr); vkDestroyImageView(vk.device, vk_image.image_view, nullptr); - - if (vk_image.staging_buffer.handle != VK_NULL_HANDLE) - vkDestroyBuffer(vk.device, vk_image.staging_buffer.handle, nullptr); } Com_Memset(&res, 0, sizeof(res)); diff --git a/src/engine/renderer/vk.h b/src/engine/renderer/vk.h index aab991b..46089a6 100644 --- a/src/engine/renderer/vk.h +++ b/src/engine/renderer/vk.h @@ -41,13 +41,6 @@ struct Vk_Pipeline_Desc { } }; -struct Vk_Staging_Buffer { - VkBuffer handle = VK_NULL_HANDLE; - VkDeviceMemory memory = VK_NULL_HANDLE; // memory associated with a buffer - VkDeviceSize offset = -1; - VkDeviceSize size = 0; -}; - struct Vk_Image { VkImage image = VK_NULL_HANDLE; VkImageView image_view = VK_NULL_HANDLE; @@ -55,9 +48,6 @@ struct Vk_Image { // One to one correspondence between images and descriptor sets. // We update descriptor set during image initialization and then never touch it again (except for cinematic images). VkDescriptorSet descriptor_set; - - // Staging buffer for cinematic images. - Vk_Staging_Buffer staging_buffer; }; bool vk_initialize(HWND hwnd); @@ -65,8 +55,8 @@ void vk_deinitialize(); void vk_destroy_resources(); VkImage vk_create_texture(const uint8_t* rgba_pixels, int width, int height, VkImageView& image_view); -VkImage vk_create_cinematic_image(int width, int height, Vk_Staging_Buffer& staging_buffer, VkImageView& image_view); -void vk_update_cinematic_image(VkImage image, const Vk_Staging_Buffer& staging_buffer, int width, int height, const uint8_t* rgba_pixels); +VkImage vk_create_cinematic_image(int width, int height, VkImageView& image_view); +void vk_update_cinematic_image(VkImage image, int width, int height, const uint8_t* rgba_pixels); VkPipeline vk_find_pipeline(const Vk_Pipeline_Desc& desc); VkDescriptorSet vk_create_descriptor_set(VkImageView image_view); @@ -135,7 +125,7 @@ struct Vulkan_Instance { byte* index_buffer_ptr = nullptr; // pointer to mapped index buffer VkDeviceSize index_buffer_offset = 0; - // host visible memory that holds vertex/index data + // host visible memory that holds both vertex and index data VkDeviceMemory geometry_buffer_memory = VK_NULL_HANDLE; VkSemaphore image_acquired = VK_NULL_HANDLE; @@ -169,6 +159,9 @@ struct Vulkan_Resources { int num_image_chunks = 0; Chunk image_chunks[MAX_IMAGE_CHUNKS]; - VkDeviceMemory texture_staging_memory = VK_NULL_HANDLE; - VkDeviceSize texture_staging_memory_size = 0; + // Host visible memory used to copy image data to device local memory. + VkBuffer staging_buffer = VK_NULL_HANDLE; + VkDeviceMemory staging_buffer_memory = VK_NULL_HANDLE; + VkDeviceSize staging_buffer_size = 0; + byte* staging_buffer_ptr = nullptr; // pointer to mapped staging buffer }; diff --git a/src/engine/renderer/vk_allocator.cpp b/src/engine/renderer/vk_allocator.cpp deleted file mode 100644 index 0595e33..0000000 --- a/src/engine/renderer/vk_allocator.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "vk_allocator.h" -#include "tr_local.h" - -static Device_Memory_Allocator allocator; - -Device_Memory_Allocator* get_allocator() { - return &allocator; -} - -void Device_Memory_Allocator::deallocate_all() { - for (auto chunk : chunks) { - vkFreeMemory(vk.device, chunk, nullptr); - } - chunks.clear(); -} - -static uint32_t find_memory_type(VkPhysicalDevice physical_device, uint32_t memory_type_bits, VkMemoryPropertyFlags properties) { - VkPhysicalDeviceMemoryProperties memory_properties; - vkGetPhysicalDeviceMemoryProperties(physical_device, &memory_properties); - - for (uint32_t i = 0; i < memory_properties.memoryTypeCount; i++) { - if ((memory_type_bits & (1 << i)) != 0 && - (memory_properties.memoryTypes[i].propertyFlags & properties) == properties) { - return i; - } - } - ri.Error(ERR_FATAL, "Vulkan error: failed to find matching memory type with requested properties"); - return -1; -} - -VkDeviceMemory Device_Memory_Allocator::allocate_staging_memory(VkBuffer buffer) { - VkMemoryRequirements memory_requirements; - vkGetBufferMemoryRequirements(vk.device, buffer, &memory_requirements); - - VkMemoryAllocateInfo alloc_info; - alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - alloc_info.pNext = nullptr; - alloc_info.allocationSize = memory_requirements.size; - alloc_info.memoryTypeIndex = find_memory_type(vk.physical_device, memory_requirements.memoryTypeBits, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - VkDeviceMemory chunk; - VK_CHECK(vkAllocateMemory(vk.device, &alloc_info, nullptr, &chunk)); - chunks.push_back(chunk); - return chunk; -} diff --git a/src/engine/renderer/vk_allocator.h b/src/engine/renderer/vk_allocator.h deleted file mode 100644 index 8118b3f..0000000 --- a/src/engine/renderer/vk_allocator.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "vk.h" -#include - -// NOTE: in this implementation I do memory allocation for each allocation request. -// TODO: sub-allocate from larger chunks and return chunk handle plus offset withing corresponding chunk. -class Device_Memory_Allocator { -public: - void deallocate_all(); - - VkDeviceMemory allocate_staging_memory(VkBuffer buffer); - -private: - std::vector chunks; -}; - -Device_Memory_Allocator* get_allocator();