diff options
Diffstat (limited to '')
| -rw-r--r-- | src/video_core/renderer_vulkan/renderer_vulkan.cpp | 9 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_blit_screen.cpp | 6 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_blit_screen.h | 1 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_buffer_cache.cpp | 81 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_buffer_cache.h | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_smaa.cpp | 12 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp | 105 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_staging_buffer_pool.h | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_texture_cache.cpp | 9 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_texture_cache.h | 1 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_turbo_mode.cpp | 8 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_device.cpp | 1 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_memory_allocator.cpp | 107 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_memory_allocator.h | 12 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_wrapper.cpp | 24 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_wrapper.h | 91 |
16 files changed, 262 insertions, 211 deletions
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index e569523b6..ddf28ca28 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -233,8 +233,8 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr | |||
| 233 | .queueFamilyIndexCount = 0, | 233 | .queueFamilyIndexCount = 0, |
| 234 | .pQueueFamilyIndices = nullptr, | 234 | .pQueueFamilyIndices = nullptr, |
| 235 | }; | 235 | }; |
| 236 | const vk::Buffer dst_buffer = device.GetLogical().CreateBuffer(dst_buffer_info); | 236 | const vk::Buffer dst_buffer = |
| 237 | MemoryCommit dst_buffer_memory = memory_allocator.Commit(dst_buffer, MemoryUsage::Download); | 237 | memory_allocator.CreateBuffer(dst_buffer_info, MemoryUsage::Download); |
| 238 | 238 | ||
| 239 | scheduler.RequestOutsideRenderPassOperationContext(); | 239 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 240 | scheduler.Record([&](vk::CommandBuffer cmdbuf) { | 240 | scheduler.Record([&](vk::CommandBuffer cmdbuf) { |
| @@ -308,8 +308,9 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr | |||
| 308 | scheduler.Finish(); | 308 | scheduler.Finish(); |
| 309 | 309 | ||
| 310 | // Copy backing image data to the QImage screenshot buffer | 310 | // Copy backing image data to the QImage screenshot buffer |
| 311 | const auto dst_memory_map = dst_buffer_memory.Map(); | 311 | dst_buffer.Invalidate(); |
| 312 | std::memcpy(renderer_settings.screenshot_bits, dst_memory_map.data(), dst_memory_map.size()); | 312 | std::memcpy(renderer_settings.screenshot_bits, dst_buffer.Mapped().data(), |
| 313 | dst_buffer.Mapped().size()); | ||
| 313 | renderer_settings.screenshot_complete_callback(false); | 314 | renderer_settings.screenshot_complete_callback(false); |
| 314 | renderer_settings.screenshot_requested = false; | 315 | renderer_settings.screenshot_requested = false; |
| 315 | } | 316 | } |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 82ca81c7e..ad3b29f0e 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp | |||
| @@ -162,7 +162,7 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, | |||
| 162 | SetUniformData(data, layout); | 162 | SetUniformData(data, layout); |
| 163 | SetVertexData(data, framebuffer, layout); | 163 | SetVertexData(data, framebuffer, layout); |
| 164 | 164 | ||
| 165 | const std::span<u8> mapped_span = buffer_commit.Map(); | 165 | const std::span<u8> mapped_span = buffer.Mapped(); |
| 166 | std::memcpy(mapped_span.data(), &data, sizeof(data)); | 166 | std::memcpy(mapped_span.data(), &data, sizeof(data)); |
| 167 | 167 | ||
| 168 | if (!use_accelerated) { | 168 | if (!use_accelerated) { |
| @@ -1074,7 +1074,6 @@ void BlitScreen::ReleaseRawImages() { | |||
| 1074 | aa_image_view.reset(); | 1074 | aa_image_view.reset(); |
| 1075 | aa_image.reset(); | 1075 | aa_image.reset(); |
| 1076 | buffer.reset(); | 1076 | buffer.reset(); |
| 1077 | buffer_commit = MemoryCommit{}; | ||
| 1078 | } | 1077 | } |
| 1079 | 1078 | ||
| 1080 | void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { | 1079 | void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { |
| @@ -1090,8 +1089,7 @@ void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer | |||
| 1090 | .pQueueFamilyIndices = nullptr, | 1089 | .pQueueFamilyIndices = nullptr, |
| 1091 | }; | 1090 | }; |
| 1092 | 1091 | ||
| 1093 | buffer = device.GetLogical().CreateBuffer(ci); | 1092 | buffer = memory_allocator.CreateBuffer(ci, MemoryUsage::Upload); |
| 1094 | buffer_commit = memory_allocator.Commit(buffer, MemoryUsage::Upload); | ||
| 1095 | } | 1093 | } |
| 1096 | 1094 | ||
| 1097 | void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | 1095 | void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index 7fcfa9976..8365b5668 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h | |||
| @@ -142,7 +142,6 @@ private: | |||
| 142 | vk::Sampler sampler; | 142 | vk::Sampler sampler; |
| 143 | 143 | ||
| 144 | vk::Buffer buffer; | 144 | vk::Buffer buffer; |
| 145 | MemoryCommit buffer_commit; | ||
| 146 | 145 | ||
| 147 | std::vector<u64> resource_ticks; | 146 | std::vector<u64> resource_ticks; |
| 148 | 147 | ||
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 8c33722d3..67356c679 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp | |||
| @@ -50,7 +50,7 @@ size_t BytesPerIndex(VkIndexType index_type) { | |||
| 50 | } | 50 | } |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | vk::Buffer CreateBuffer(const Device& device, u64 size) { | 53 | vk::Buffer CreateBuffer(const Device& device, const MemoryAllocator& memory_allocator, u64 size) { |
| 54 | VkBufferUsageFlags flags = | 54 | VkBufferUsageFlags flags = |
| 55 | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | | 55 | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | |
| 56 | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | | 56 | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | |
| @@ -60,7 +60,7 @@ vk::Buffer CreateBuffer(const Device& device, u64 size) { | |||
| 60 | if (device.IsExtTransformFeedbackSupported()) { | 60 | if (device.IsExtTransformFeedbackSupported()) { |
| 61 | flags |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; | 61 | flags |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; |
| 62 | } | 62 | } |
| 63 | return device.GetLogical().CreateBuffer({ | 63 | const VkBufferCreateInfo buffer_ci = { |
| 64 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 64 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 65 | .pNext = nullptr, | 65 | .pNext = nullptr, |
| 66 | .flags = 0, | 66 | .flags = 0, |
| @@ -69,7 +69,8 @@ vk::Buffer CreateBuffer(const Device& device, u64 size) { | |||
| 69 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 69 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 70 | .queueFamilyIndexCount = 0, | 70 | .queueFamilyIndexCount = 0, |
| 71 | .pQueueFamilyIndices = nullptr, | 71 | .pQueueFamilyIndices = nullptr, |
| 72 | }); | 72 | }; |
| 73 | return memory_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal); | ||
| 73 | } | 74 | } |
| 74 | } // Anonymous namespace | 75 | } // Anonymous namespace |
| 75 | 76 | ||
| @@ -79,8 +80,8 @@ Buffer::Buffer(BufferCacheRuntime&, VideoCommon::NullBufferParams null_params) | |||
| 79 | Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_, | 80 | Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_, |
| 80 | VAddr cpu_addr_, u64 size_bytes_) | 81 | VAddr cpu_addr_, u64 size_bytes_) |
| 81 | : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(rasterizer_, cpu_addr_, size_bytes_), | 82 | : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(rasterizer_, cpu_addr_, size_bytes_), |
| 82 | device{&runtime.device}, buffer{CreateBuffer(*device, SizeBytes())}, | 83 | device{&runtime.device}, buffer{ |
| 83 | commit{runtime.memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal)} { | 84 | CreateBuffer(*device, runtime.memory_allocator, SizeBytes())} { |
| 84 | if (runtime.device.HasDebuggingToolAttached()) { | 85 | if (runtime.device.HasDebuggingToolAttached()) { |
| 85 | buffer.SetObjectNameEXT(fmt::format("Buffer 0x{:x}", CpuAddr()).c_str()); | 86 | buffer.SetObjectNameEXT(fmt::format("Buffer 0x{:x}", CpuAddr()).c_str()); |
| 86 | } | 87 | } |
| @@ -138,7 +139,7 @@ public: | |||
| 138 | const u32 num_first_offset_copies = 4; | 139 | const u32 num_first_offset_copies = 4; |
| 139 | const size_t bytes_per_index = BytesPerIndex(index_type); | 140 | const size_t bytes_per_index = BytesPerIndex(index_type); |
| 140 | const size_t size_bytes = num_triangle_indices * bytes_per_index * num_first_offset_copies; | 141 | const size_t size_bytes = num_triangle_indices * bytes_per_index * num_first_offset_copies; |
| 141 | buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{ | 142 | const VkBufferCreateInfo buffer_ci = { |
| 142 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 143 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 143 | .pNext = nullptr, | 144 | .pNext = nullptr, |
| 144 | .flags = 0, | 145 | .flags = 0, |
| @@ -147,14 +148,21 @@ public: | |||
| 147 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 148 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 148 | .queueFamilyIndexCount = 0, | 149 | .queueFamilyIndexCount = 0, |
| 149 | .pQueueFamilyIndices = nullptr, | 150 | .pQueueFamilyIndices = nullptr, |
| 150 | }); | 151 | }; |
| 152 | buffer = memory_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal); | ||
| 151 | if (device.HasDebuggingToolAttached()) { | 153 | if (device.HasDebuggingToolAttached()) { |
| 152 | buffer.SetObjectNameEXT("Quad LUT"); | 154 | buffer.SetObjectNameEXT("Quad LUT"); |
| 153 | } | 155 | } |
| 154 | memory_commit = memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal); | ||
| 155 | 156 | ||
| 156 | const StagingBufferRef staging = staging_pool.Request(size_bytes, MemoryUsage::Upload); | 157 | const bool host_visible = buffer.IsHostVisible(); |
| 157 | u8* staging_data = staging.mapped_span.data(); | 158 | const StagingBufferRef staging = [&] { |
| 159 | if (host_visible) { | ||
| 160 | return StagingBufferRef{}; | ||
| 161 | } | ||
| 162 | return staging_pool.Request(size_bytes, MemoryUsage::Upload); | ||
| 163 | }(); | ||
| 164 | |||
| 165 | u8* staging_data = host_visible ? buffer.Mapped().data() : staging.mapped_span.data(); | ||
| 158 | const size_t quad_size = bytes_per_index * 6; | 166 | const size_t quad_size = bytes_per_index * 6; |
| 159 | 167 | ||
| 160 | for (u32 first = 0; first < num_first_offset_copies; ++first) { | 168 | for (u32 first = 0; first < num_first_offset_copies; ++first) { |
| @@ -164,29 +172,33 @@ public: | |||
| 164 | } | 172 | } |
| 165 | } | 173 | } |
| 166 | 174 | ||
| 167 | scheduler.RequestOutsideRenderPassOperationContext(); | 175 | if (!host_visible) { |
| 168 | scheduler.Record([src_buffer = staging.buffer, src_offset = staging.offset, | 176 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 169 | dst_buffer = *buffer, size_bytes](vk::CommandBuffer cmdbuf) { | 177 | scheduler.Record([src_buffer = staging.buffer, src_offset = staging.offset, |
| 170 | const VkBufferCopy copy{ | 178 | dst_buffer = *buffer, size_bytes](vk::CommandBuffer cmdbuf) { |
| 171 | .srcOffset = src_offset, | 179 | const VkBufferCopy copy{ |
| 172 | .dstOffset = 0, | 180 | .srcOffset = src_offset, |
| 173 | .size = size_bytes, | 181 | .dstOffset = 0, |
| 174 | }; | 182 | .size = size_bytes, |
| 175 | const VkBufferMemoryBarrier write_barrier{ | 183 | }; |
| 176 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, | 184 | const VkBufferMemoryBarrier write_barrier{ |
| 177 | .pNext = nullptr, | 185 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, |
| 178 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | 186 | .pNext = nullptr, |
| 179 | .dstAccessMask = VK_ACCESS_INDEX_READ_BIT, | 187 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, |
| 180 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | 188 | .dstAccessMask = VK_ACCESS_INDEX_READ_BIT, |
| 181 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | 189 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, |
| 182 | .buffer = dst_buffer, | 190 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, |
| 183 | .offset = 0, | 191 | .buffer = dst_buffer, |
| 184 | .size = size_bytes, | 192 | .offset = 0, |
| 185 | }; | 193 | .size = size_bytes, |
| 186 | cmdbuf.CopyBuffer(src_buffer, dst_buffer, copy); | 194 | }; |
| 187 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, | 195 | cmdbuf.CopyBuffer(src_buffer, dst_buffer, copy); |
| 188 | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, write_barrier); | 196 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, |
| 189 | }); | 197 | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, write_barrier); |
| 198 | }); | ||
| 199 | } else { | ||
| 200 | buffer.Flush(); | ||
| 201 | } | ||
| 190 | } | 202 | } |
| 191 | 203 | ||
| 192 | void BindBuffer(u32 first) { | 204 | void BindBuffer(u32 first) { |
| @@ -587,11 +599,10 @@ void BufferCacheRuntime::ReserveNullBuffer() { | |||
| 587 | create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; | 599 | create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; |
| 588 | } | 600 | } |
| 589 | create_info.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; | 601 | create_info.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; |
| 590 | null_buffer = device.GetLogical().CreateBuffer(create_info); | 602 | null_buffer = memory_allocator.CreateBuffer(create_info, MemoryUsage::DeviceLocal); |
| 591 | if (device.HasDebuggingToolAttached()) { | 603 | if (device.HasDebuggingToolAttached()) { |
| 592 | null_buffer.SetObjectNameEXT("Null buffer"); | 604 | null_buffer.SetObjectNameEXT("Null buffer"); |
| 593 | } | 605 | } |
| 594 | null_buffer_commit = memory_allocator.Commit(null_buffer, MemoryUsage::DeviceLocal); | ||
| 595 | 606 | ||
| 596 | scheduler.RequestOutsideRenderPassOperationContext(); | 607 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 597 | scheduler.Record([buffer = *null_buffer](vk::CommandBuffer cmdbuf) { | 608 | scheduler.Record([buffer = *null_buffer](vk::CommandBuffer cmdbuf) { |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index cdeef8846..95446c732 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h | |||
| @@ -48,7 +48,6 @@ private: | |||
| 48 | 48 | ||
| 49 | const Device* device{}; | 49 | const Device* device{}; |
| 50 | vk::Buffer buffer; | 50 | vk::Buffer buffer; |
| 51 | MemoryCommit commit; | ||
| 52 | std::vector<BufferView> views; | 51 | std::vector<BufferView> views; |
| 53 | }; | 52 | }; |
| 54 | 53 | ||
| @@ -142,7 +141,6 @@ private: | |||
| 142 | std::shared_ptr<QuadStripIndexBuffer> quad_strip_index_buffer; | 141 | std::shared_ptr<QuadStripIndexBuffer> quad_strip_index_buffer; |
| 143 | 142 | ||
| 144 | vk::Buffer null_buffer; | 143 | vk::Buffer null_buffer; |
| 145 | MemoryCommit null_buffer_commit; | ||
| 146 | 144 | ||
| 147 | std::unique_ptr<Uint8Pass> uint8_pass; | 145 | std::unique_ptr<Uint8Pass> uint8_pass; |
| 148 | QuadIndexedPass quad_index_pass; | 146 | QuadIndexedPass quad_index_pass; |
diff --git a/src/video_core/renderer_vulkan/vk_smaa.cpp b/src/video_core/renderer_vulkan/vk_smaa.cpp index ff7c3a419..5efd7d66e 100644 --- a/src/video_core/renderer_vulkan/vk_smaa.cpp +++ b/src/video_core/renderer_vulkan/vk_smaa.cpp | |||
| @@ -76,7 +76,7 @@ void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayo | |||
| 76 | void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler, | 76 | void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler, |
| 77 | vk::Image& image, VkExtent2D dimensions, VkFormat format, | 77 | vk::Image& image, VkExtent2D dimensions, VkFormat format, |
| 78 | std::span<const u8> initial_contents = {}) { | 78 | std::span<const u8> initial_contents = {}) { |
| 79 | auto upload_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{ | 79 | const VkBufferCreateInfo upload_ci = { |
| 80 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 80 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 81 | .pNext = nullptr, | 81 | .pNext = nullptr, |
| 82 | .flags = 0, | 82 | .flags = 0, |
| @@ -85,9 +85,10 @@ void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& sc | |||
| 85 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 85 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 86 | .queueFamilyIndexCount = 0, | 86 | .queueFamilyIndexCount = 0, |
| 87 | .pQueueFamilyIndices = nullptr, | 87 | .pQueueFamilyIndices = nullptr, |
| 88 | }); | 88 | }; |
| 89 | auto upload_commit = allocator.Commit(upload_buffer, MemoryUsage::Upload); | 89 | auto upload_buffer = allocator.CreateBuffer(upload_ci, MemoryUsage::Upload); |
| 90 | std::ranges::copy(initial_contents, upload_commit.Map().begin()); | 90 | std::ranges::copy(initial_contents, upload_buffer.Mapped().begin()); |
| 91 | upload_buffer.Flush(); | ||
| 91 | 92 | ||
| 92 | const std::array<VkBufferImageCopy, 1> regions{{{ | 93 | const std::array<VkBufferImageCopy, 1> regions{{{ |
| 93 | .bufferOffset = 0, | 94 | .bufferOffset = 0, |
| @@ -111,9 +112,6 @@ void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& sc | |||
| 111 | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); | 112 | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); |
| 112 | }); | 113 | }); |
| 113 | scheduler.Finish(); | 114 | scheduler.Finish(); |
| 114 | |||
| 115 | // This should go out of scope before the commit | ||
| 116 | auto upload_buffer2 = std::move(upload_buffer); | ||
| 117 | } | 115 | } |
| 118 | 116 | ||
| 119 | vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format) { | 117 | vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format) { |
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp index 74ca77216..62b251a9b 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp | |||
| @@ -30,55 +30,6 @@ constexpr VkDeviceSize MAX_STREAM_BUFFER_REQUEST_SIZE = 8_MiB; | |||
| 30 | constexpr VkDeviceSize STREAM_BUFFER_SIZE = 128_MiB; | 30 | constexpr VkDeviceSize STREAM_BUFFER_SIZE = 128_MiB; |
| 31 | constexpr VkDeviceSize REGION_SIZE = STREAM_BUFFER_SIZE / StagingBufferPool::NUM_SYNCS; | 31 | constexpr VkDeviceSize REGION_SIZE = STREAM_BUFFER_SIZE / StagingBufferPool::NUM_SYNCS; |
| 32 | 32 | ||
| 33 | constexpr VkMemoryPropertyFlags HOST_FLAGS = | ||
| 34 | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | ||
| 35 | constexpr VkMemoryPropertyFlags STREAM_FLAGS = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | HOST_FLAGS; | ||
| 36 | |||
| 37 | bool IsStreamHeap(VkMemoryHeap heap) noexcept { | ||
| 38 | return STREAM_BUFFER_SIZE < (heap.size * 2) / 3; | ||
| 39 | } | ||
| 40 | |||
| 41 | std::optional<u32> FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask, | ||
| 42 | VkMemoryPropertyFlags flags) noexcept { | ||
| 43 | for (u32 type_index = 0; type_index < props.memoryTypeCount; ++type_index) { | ||
| 44 | if (((type_mask >> type_index) & 1) == 0) { | ||
| 45 | // Memory type is incompatible | ||
| 46 | continue; | ||
| 47 | } | ||
| 48 | const VkMemoryType& memory_type = props.memoryTypes[type_index]; | ||
| 49 | if ((memory_type.propertyFlags & flags) != flags) { | ||
| 50 | // Memory type doesn't have the flags we want | ||
| 51 | continue; | ||
| 52 | } | ||
| 53 | if (!IsStreamHeap(props.memoryHeaps[memory_type.heapIndex])) { | ||
| 54 | // Memory heap is not suitable for streaming | ||
| 55 | continue; | ||
| 56 | } | ||
| 57 | // Success! | ||
| 58 | return type_index; | ||
| 59 | } | ||
| 60 | return std::nullopt; | ||
| 61 | } | ||
| 62 | |||
| 63 | u32 FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask, | ||
| 64 | bool try_device_local) { | ||
| 65 | std::optional<u32> type; | ||
| 66 | if (try_device_local) { | ||
| 67 | // Try to find a DEVICE_LOCAL_BIT type, Nvidia and AMD have a dedicated heap for this | ||
| 68 | type = FindMemoryTypeIndex(props, type_mask, STREAM_FLAGS); | ||
| 69 | if (type) { | ||
| 70 | return *type; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | // Otherwise try without the DEVICE_LOCAL_BIT | ||
| 74 | type = FindMemoryTypeIndex(props, type_mask, HOST_FLAGS); | ||
| 75 | if (type) { | ||
| 76 | return *type; | ||
| 77 | } | ||
| 78 | // This should never happen, and in case it does, signal it as an out of memory situation | ||
| 79 | throw vk::Exception(VK_ERROR_OUT_OF_DEVICE_MEMORY); | ||
| 80 | } | ||
| 81 | |||
| 82 | size_t Region(size_t iterator) noexcept { | 33 | size_t Region(size_t iterator) noexcept { |
| 83 | return iterator / REGION_SIZE; | 34 | return iterator / REGION_SIZE; |
| 84 | } | 35 | } |
| @@ -87,8 +38,7 @@ size_t Region(size_t iterator) noexcept { | |||
| 87 | StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_, | 38 | StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_, |
| 88 | Scheduler& scheduler_) | 39 | Scheduler& scheduler_) |
| 89 | : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} { | 40 | : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} { |
| 90 | const vk::Device& dev = device.GetLogical(); | 41 | const VkBufferCreateInfo stream_ci = { |
| 91 | stream_buffer = dev.CreateBuffer(VkBufferCreateInfo{ | ||
| 92 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 42 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 93 | .pNext = nullptr, | 43 | .pNext = nullptr, |
| 94 | .flags = 0, | 44 | .flags = 0, |
| @@ -99,46 +49,13 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem | |||
| 99 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 49 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 100 | .queueFamilyIndexCount = 0, | 50 | .queueFamilyIndexCount = 0, |
| 101 | .pQueueFamilyIndices = nullptr, | 51 | .pQueueFamilyIndices = nullptr, |
| 102 | }); | ||
| 103 | if (device.HasDebuggingToolAttached()) { | ||
| 104 | stream_buffer.SetObjectNameEXT("Stream Buffer"); | ||
| 105 | } | ||
| 106 | VkMemoryDedicatedRequirements dedicated_reqs{ | ||
| 107 | .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, | ||
| 108 | .pNext = nullptr, | ||
| 109 | .prefersDedicatedAllocation = VK_FALSE, | ||
| 110 | .requiresDedicatedAllocation = VK_FALSE, | ||
| 111 | }; | ||
| 112 | const auto requirements = dev.GetBufferMemoryRequirements(*stream_buffer, &dedicated_reqs); | ||
| 113 | const bool make_dedicated = dedicated_reqs.prefersDedicatedAllocation == VK_TRUE || | ||
| 114 | dedicated_reqs.requiresDedicatedAllocation == VK_TRUE; | ||
| 115 | const VkMemoryDedicatedAllocateInfo dedicated_info{ | ||
| 116 | .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, | ||
| 117 | .pNext = nullptr, | ||
| 118 | .image = nullptr, | ||
| 119 | .buffer = *stream_buffer, | ||
| 120 | }; | 52 | }; |
| 121 | const auto memory_properties = device.GetPhysical().GetMemoryProperties().memoryProperties; | 53 | stream_buffer = memory_allocator.CreateBuffer(stream_ci, MemoryUsage::Stream); |
| 122 | VkMemoryAllocateInfo stream_memory_info{ | ||
| 123 | .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | ||
| 124 | .pNext = make_dedicated ? &dedicated_info : nullptr, | ||
| 125 | .allocationSize = requirements.size, | ||
| 126 | .memoryTypeIndex = | ||
| 127 | FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, true), | ||
| 128 | }; | ||
| 129 | stream_memory = dev.TryAllocateMemory(stream_memory_info); | ||
| 130 | if (!stream_memory) { | ||
| 131 | LOG_INFO(Render_Vulkan, "Dynamic memory allocation failed, trying with system memory"); | ||
| 132 | stream_memory_info.memoryTypeIndex = | ||
| 133 | FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, false); | ||
| 134 | stream_memory = dev.AllocateMemory(stream_memory_info); | ||
| 135 | } | ||
| 136 | |||
| 137 | if (device.HasDebuggingToolAttached()) { | 54 | if (device.HasDebuggingToolAttached()) { |
| 138 | stream_memory.SetObjectNameEXT("Stream Buffer Memory"); | 55 | stream_buffer.SetObjectNameEXT("Stream Buffer"); |
| 139 | } | 56 | } |
| 140 | stream_buffer.BindMemory(*stream_memory, 0); | 57 | stream_pointer = stream_buffer.Mapped(); |
| 141 | stream_pointer = stream_memory.Map(0, STREAM_BUFFER_SIZE); | 58 | ASSERT_MSG(!stream_pointer.empty(), "Stream buffer must be host visible!"); |
| 142 | } | 59 | } |
| 143 | 60 | ||
| 144 | StagingBufferPool::~StagingBufferPool() = default; | 61 | StagingBufferPool::~StagingBufferPool() = default; |
| @@ -199,7 +116,7 @@ StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) { | |||
| 199 | return StagingBufferRef{ | 116 | return StagingBufferRef{ |
| 200 | .buffer = *stream_buffer, | 117 | .buffer = *stream_buffer, |
| 201 | .offset = static_cast<VkDeviceSize>(offset), | 118 | .offset = static_cast<VkDeviceSize>(offset), |
| 202 | .mapped_span = std::span<u8>(stream_pointer + offset, size), | 119 | .mapped_span = stream_pointer.subspan(offset, size), |
| 203 | .usage{}, | 120 | .usage{}, |
| 204 | .log2_level{}, | 121 | .log2_level{}, |
| 205 | .index{}, | 122 | .index{}, |
| @@ -247,7 +164,7 @@ std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t s | |||
| 247 | StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage, | 164 | StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage, |
| 248 | bool deferred) { | 165 | bool deferred) { |
| 249 | const u32 log2 = Common::Log2Ceil64(size); | 166 | const u32 log2 = Common::Log2Ceil64(size); |
| 250 | vk::Buffer buffer = device.GetLogical().CreateBuffer({ | 167 | const VkBufferCreateInfo buffer_ci = { |
| 251 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 168 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 252 | .pNext = nullptr, | 169 | .pNext = nullptr, |
| 253 | .flags = 0, | 170 | .flags = 0, |
| @@ -259,17 +176,15 @@ StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage | |||
| 259 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 176 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 260 | .queueFamilyIndexCount = 0, | 177 | .queueFamilyIndexCount = 0, |
| 261 | .pQueueFamilyIndices = nullptr, | 178 | .pQueueFamilyIndices = nullptr, |
| 262 | }); | 179 | }; |
| 180 | vk::Buffer buffer = memory_allocator.CreateBuffer(buffer_ci, usage); | ||
| 263 | if (device.HasDebuggingToolAttached()) { | 181 | if (device.HasDebuggingToolAttached()) { |
| 264 | ++buffer_index; | 182 | ++buffer_index; |
| 265 | buffer.SetObjectNameEXT(fmt::format("Staging Buffer {}", buffer_index).c_str()); | 183 | buffer.SetObjectNameEXT(fmt::format("Staging Buffer {}", buffer_index).c_str()); |
| 266 | } | 184 | } |
| 267 | MemoryCommit commit = memory_allocator.Commit(buffer, usage); | 185 | const std::span<u8> mapped_span = buffer.Mapped(); |
| 268 | const std::span<u8> mapped_span = IsHostVisible(usage) ? commit.Map() : std::span<u8>{}; | ||
| 269 | |||
| 270 | StagingBuffer& entry = GetCache(usage)[log2].entries.emplace_back(StagingBuffer{ | 186 | StagingBuffer& entry = GetCache(usage)[log2].entries.emplace_back(StagingBuffer{ |
| 271 | .buffer = std::move(buffer), | 187 | .buffer = std::move(buffer), |
| 272 | .commit = std::move(commit), | ||
| 273 | .mapped_span = mapped_span, | 188 | .mapped_span = mapped_span, |
| 274 | .usage = usage, | 189 | .usage = usage, |
| 275 | .log2_level = log2, | 190 | .log2_level = log2, |
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h index 4fd15f11a..5f69f08b1 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h | |||
| @@ -46,7 +46,6 @@ private: | |||
| 46 | 46 | ||
| 47 | struct StagingBuffer { | 47 | struct StagingBuffer { |
| 48 | vk::Buffer buffer; | 48 | vk::Buffer buffer; |
| 49 | MemoryCommit commit; | ||
| 50 | std::span<u8> mapped_span; | 49 | std::span<u8> mapped_span; |
| 51 | MemoryUsage usage; | 50 | MemoryUsage usage; |
| 52 | u32 log2_level; | 51 | u32 log2_level; |
| @@ -97,8 +96,7 @@ private: | |||
| 97 | Scheduler& scheduler; | 96 | Scheduler& scheduler; |
| 98 | 97 | ||
| 99 | vk::Buffer stream_buffer; | 98 | vk::Buffer stream_buffer; |
| 100 | vk::DeviceMemory stream_memory; | 99 | std::span<u8> stream_pointer; |
| 101 | u8* stream_pointer = nullptr; | ||
| 102 | 100 | ||
| 103 | size_t iterator = 0; | 101 | size_t iterator = 0; |
| 104 | size_t used_iterator = 0; | 102 | size_t used_iterator = 0; |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 10defe6cb..28985b6fe 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -839,14 +839,14 @@ bool TextureCacheRuntime::ShouldReinterpret(Image& dst, Image& src) { | |||
| 839 | 839 | ||
| 840 | VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { | 840 | VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { |
| 841 | const auto level = (8 * sizeof(size_t)) - std::countl_zero(needed_size - 1ULL); | 841 | const auto level = (8 * sizeof(size_t)) - std::countl_zero(needed_size - 1ULL); |
| 842 | if (buffer_commits[level]) { | 842 | if (buffers[level]) { |
| 843 | return *buffers[level]; | 843 | return *buffers[level]; |
| 844 | } | 844 | } |
| 845 | const auto new_size = Common::NextPow2(needed_size); | 845 | const auto new_size = Common::NextPow2(needed_size); |
| 846 | static constexpr VkBufferUsageFlags flags = | 846 | static constexpr VkBufferUsageFlags flags = |
| 847 | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | | 847 | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | |
| 848 | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; | 848 | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; |
| 849 | buffers[level] = device.GetLogical().CreateBuffer({ | 849 | const VkBufferCreateInfo temp_ci = { |
| 850 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 850 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 851 | .pNext = nullptr, | 851 | .pNext = nullptr, |
| 852 | .flags = 0, | 852 | .flags = 0, |
| @@ -855,9 +855,8 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { | |||
| 855 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 855 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 856 | .queueFamilyIndexCount = 0, | 856 | .queueFamilyIndexCount = 0, |
| 857 | .pQueueFamilyIndices = nullptr, | 857 | .pQueueFamilyIndices = nullptr, |
| 858 | }); | 858 | }; |
| 859 | buffer_commits[level] = std::make_unique<MemoryCommit>( | 859 | buffers[level] = memory_allocator.CreateBuffer(temp_ci, MemoryUsage::DeviceLocal); |
| 860 | memory_allocator.Commit(buffers[level], MemoryUsage::DeviceLocal)); | ||
| 861 | return *buffers[level]; | 860 | return *buffers[level]; |
| 862 | } | 861 | } |
| 863 | 862 | ||
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 9481f2531..220943116 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h | |||
| @@ -116,7 +116,6 @@ public: | |||
| 116 | 116 | ||
| 117 | static constexpr size_t indexing_slots = 8 * sizeof(size_t); | 117 | static constexpr size_t indexing_slots = 8 * sizeof(size_t); |
| 118 | std::array<vk::Buffer, indexing_slots> buffers{}; | 118 | std::array<vk::Buffer, indexing_slots> buffers{}; |
| 119 | std::array<std::unique_ptr<MemoryCommit>, indexing_slots> buffer_commits{}; | ||
| 120 | }; | 119 | }; |
| 121 | 120 | ||
| 122 | class Image : public VideoCommon::ImageBase { | 121 | class Image : public VideoCommon::ImageBase { |
diff --git a/src/video_core/renderer_vulkan/vk_turbo_mode.cpp b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp index 6417d7e31..460d8d59d 100644 --- a/src/video_core/renderer_vulkan/vk_turbo_mode.cpp +++ b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp | |||
| @@ -41,7 +41,7 @@ void TurboMode::Run(std::stop_token stop_token) { | |||
| 41 | auto& dld = m_device.GetLogical(); | 41 | auto& dld = m_device.GetLogical(); |
| 42 | 42 | ||
| 43 | // Allocate buffer. 2MiB should be sufficient. | 43 | // Allocate buffer. 2MiB should be sufficient. |
| 44 | auto buffer = dld.CreateBuffer(VkBufferCreateInfo{ | 44 | const VkBufferCreateInfo buffer_ci = { |
| 45 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 45 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 46 | .pNext = nullptr, | 46 | .pNext = nullptr, |
| 47 | .flags = 0, | 47 | .flags = 0, |
| @@ -50,10 +50,8 @@ void TurboMode::Run(std::stop_token stop_token) { | |||
| 50 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 50 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 51 | .queueFamilyIndexCount = 0, | 51 | .queueFamilyIndexCount = 0, |
| 52 | .pQueueFamilyIndices = nullptr, | 52 | .pQueueFamilyIndices = nullptr, |
| 53 | }); | 53 | }; |
| 54 | 54 | vk::Buffer buffer = m_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal); | |
| 55 | // Commit some device local memory for the buffer. | ||
| 56 | auto commit = m_allocator.Commit(buffer, MemoryUsage::DeviceLocal); | ||
| 57 | 55 | ||
| 58 | // Create the descriptor pool to contain our descriptor. | 56 | // Create the descriptor pool to contain our descriptor. |
| 59 | static constexpr VkDescriptorPoolSize pool_size{ | 57 | static constexpr VkDescriptorPoolSize pool_size{ |
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 631d5e378..541f0c1da 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp | |||
| @@ -603,6 +603,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 603 | }; | 603 | }; |
| 604 | 604 | ||
| 605 | const VmaAllocatorCreateInfo allocator_info = { | 605 | const VmaAllocatorCreateInfo allocator_info = { |
| 606 | .flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT, | ||
| 606 | .physicalDevice = physical, | 607 | .physicalDevice = physical, |
| 607 | .device = *logical, | 608 | .device = *logical, |
| 608 | .pVulkanFunctions = &functions, | 609 | .pVulkanFunctions = &functions, |
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index 7f860cccd..d2e1ef58e 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp | |||
| @@ -51,11 +51,59 @@ struct Range { | |||
| 51 | case MemoryUsage::Download: | 51 | case MemoryUsage::Download: |
| 52 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | | 52 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | |
| 53 | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; | 53 | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; |
| 54 | case MemoryUsage::Stream: | ||
| 55 | return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | | ||
| 56 | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | ||
| 54 | } | 57 | } |
| 55 | ASSERT_MSG(false, "Invalid memory usage={}", usage); | 58 | ASSERT_MSG(false, "Invalid memory usage={}", usage); |
| 56 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | 59 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; |
| 57 | } | 60 | } |
| 58 | 61 | ||
| 62 | [[nodiscard]] VkMemoryPropertyFlags MemoryUsageRequiredVmaFlags(MemoryUsage usage) { | ||
| 63 | switch (usage) { | ||
| 64 | case MemoryUsage::DeviceLocal: | ||
| 65 | return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; | ||
| 66 | case MemoryUsage::Upload: | ||
| 67 | case MemoryUsage::Stream: | ||
| 68 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; | ||
| 69 | case MemoryUsage::Download: | ||
| 70 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; | ||
| 71 | } | ||
| 72 | ASSERT_MSG(false, "Invalid memory usage={}", usage); | ||
| 73 | return {}; | ||
| 74 | } | ||
| 75 | |||
| 76 | [[nodiscard]] VkMemoryPropertyFlags MemoryUsagePreferedVmaFlags(MemoryUsage usage) { | ||
| 77 | return usage != MemoryUsage::DeviceLocal ? VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | ||
| 78 | : VkMemoryPropertyFlags{}; | ||
| 79 | } | ||
| 80 | |||
| 81 | [[nodiscard]] VmaAllocationCreateFlags MemoryUsageVmaFlags(MemoryUsage usage) { | ||
| 82 | switch (usage) { | ||
| 83 | case MemoryUsage::Upload: | ||
| 84 | case MemoryUsage::Stream: | ||
| 85 | return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; | ||
| 86 | case MemoryUsage::Download: | ||
| 87 | return VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; | ||
| 88 | case MemoryUsage::DeviceLocal: | ||
| 89 | return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | | ||
| 90 | VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT; | ||
| 91 | } | ||
| 92 | return {}; | ||
| 93 | } | ||
| 94 | |||
| 95 | [[nodiscard]] VmaMemoryUsage MemoryUsageVma(MemoryUsage usage) { | ||
| 96 | switch (usage) { | ||
| 97 | case MemoryUsage::DeviceLocal: | ||
| 98 | case MemoryUsage::Stream: | ||
| 99 | return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; | ||
| 100 | case MemoryUsage::Upload: | ||
| 101 | case MemoryUsage::Download: | ||
| 102 | return VMA_MEMORY_USAGE_AUTO_PREFER_HOST; | ||
| 103 | } | ||
| 104 | return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; | ||
| 105 | } | ||
| 106 | |||
| 59 | } // Anonymous namespace | 107 | } // Anonymous namespace |
| 60 | 108 | ||
| 61 | class MemoryAllocation { | 109 | class MemoryAllocation { |
| @@ -178,17 +226,18 @@ void MemoryCommit::Release() { | |||
| 178 | } | 226 | } |
| 179 | 227 | ||
| 180 | MemoryAllocator::MemoryAllocator(const Device& device_) | 228 | MemoryAllocator::MemoryAllocator(const Device& device_) |
| 181 | : device{device_}, properties{device_.GetPhysical().GetMemoryProperties().memoryProperties}, | 229 | : device{device_}, allocator{device.GetAllocator()}, |
| 230 | properties{device_.GetPhysical().GetMemoryProperties().memoryProperties}, | ||
| 182 | buffer_image_granularity{ | 231 | buffer_image_granularity{ |
| 183 | device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {} | 232 | device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {} |
| 184 | 233 | ||
| 185 | MemoryAllocator::~MemoryAllocator() = default; | 234 | MemoryAllocator::~MemoryAllocator() = default; |
| 186 | 235 | ||
| 187 | vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const { | 236 | vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const { |
| 188 | const VmaAllocationCreateInfo alloc_info = { | 237 | const VmaAllocationCreateInfo alloc_ci = { |
| 189 | .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT, | 238 | .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT, |
| 190 | .usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, | 239 | .usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, |
| 191 | .requiredFlags = 0, | 240 | .requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, |
| 192 | .preferredFlags = 0, | 241 | .preferredFlags = 0, |
| 193 | .pool = VK_NULL_HANDLE, | 242 | .pool = VK_NULL_HANDLE, |
| 194 | .pUserData = nullptr, | 243 | .pUserData = nullptr, |
| @@ -196,12 +245,40 @@ vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const { | |||
| 196 | 245 | ||
| 197 | VkImage handle{}; | 246 | VkImage handle{}; |
| 198 | VmaAllocation allocation{}; | 247 | VmaAllocation allocation{}; |
| 199 | vk::Check( | 248 | |
| 200 | vmaCreateImage(device.GetAllocator(), &ci, &alloc_info, &handle, &allocation, nullptr)); | 249 | vk::Check(vmaCreateImage(allocator, &ci, &alloc_ci, &handle, &allocation, nullptr)); |
| 201 | return vk::Image(handle, *device.GetLogical(), device.GetAllocator(), allocation, | 250 | |
| 251 | return vk::Image(handle, *device.GetLogical(), allocator, allocation, | ||
| 202 | device.GetDispatchLoader()); | 252 | device.GetDispatchLoader()); |
| 203 | } | 253 | } |
| 204 | 254 | ||
| 255 | vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const { | ||
| 256 | const VmaAllocationCreateInfo alloc_ci = { | ||
| 257 | .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT | | ||
| 258 | MemoryUsageVmaFlags(usage), | ||
| 259 | .usage = MemoryUsageVma(usage), | ||
| 260 | .requiredFlags = MemoryUsageRequiredVmaFlags(usage), | ||
| 261 | .preferredFlags = MemoryUsagePreferedVmaFlags(usage), | ||
| 262 | .pool = VK_NULL_HANDLE, | ||
| 263 | .pUserData = nullptr, | ||
| 264 | }; | ||
| 265 | |||
| 266 | VkBuffer handle{}; | ||
| 267 | VmaAllocationInfo alloc_info{}; | ||
| 268 | VmaAllocation allocation{}; | ||
| 269 | VkMemoryPropertyFlags property_flags{}; | ||
| 270 | |||
| 271 | vk::Check(vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info)); | ||
| 272 | vmaGetAllocationMemoryProperties(allocator, allocation, &property_flags); | ||
| 273 | |||
| 274 | u8* data = reinterpret_cast<u8*>(alloc_info.pMappedData); | ||
| 275 | const std::span<u8> mapped_data = data ? std::span<u8>{data, ci.size} : std::span<u8>{}; | ||
| 276 | const bool is_coherent = property_flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | ||
| 277 | |||
| 278 | return vk::Buffer(handle, *device.GetLogical(), allocator, allocation, mapped_data, is_coherent, | ||
| 279 | device.GetDispatchLoader()); | ||
| 280 | } | ||
| 281 | |||
| 205 | MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { | 282 | MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { |
| 206 | // Find the fastest memory flags we can afford with the current requirements | 283 | // Find the fastest memory flags we can afford with the current requirements |
| 207 | const u32 type_mask = requirements.memoryTypeBits; | 284 | const u32 type_mask = requirements.memoryTypeBits; |
| @@ -221,12 +298,6 @@ MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, M | |||
| 221 | return TryCommit(requirements, flags).value(); | 298 | return TryCommit(requirements, flags).value(); |
| 222 | } | 299 | } |
| 223 | 300 | ||
| 224 | MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, MemoryUsage usage) { | ||
| 225 | auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), usage); | ||
| 226 | buffer.BindMemory(commit.Memory(), commit.Offset()); | ||
| 227 | return commit; | ||
| 228 | } | ||
| 229 | |||
| 230 | bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { | 301 | bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { |
| 231 | const u32 type = FindType(flags, type_mask).value(); | 302 | const u32 type = FindType(flags, type_mask).value(); |
| 232 | vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ | 303 | vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ |
| @@ -302,16 +373,4 @@ std::optional<u32> MemoryAllocator::FindType(VkMemoryPropertyFlags flags, u32 ty | |||
| 302 | return std::nullopt; | 373 | return std::nullopt; |
| 303 | } | 374 | } |
| 304 | 375 | ||
| 305 | bool IsHostVisible(MemoryUsage usage) noexcept { | ||
| 306 | switch (usage) { | ||
| 307 | case MemoryUsage::DeviceLocal: | ||
| 308 | return false; | ||
| 309 | case MemoryUsage::Upload: | ||
| 310 | case MemoryUsage::Download: | ||
| 311 | return true; | ||
| 312 | } | ||
| 313 | ASSERT_MSG(false, "Invalid memory usage={}", usage); | ||
| 314 | return false; | ||
| 315 | } | ||
| 316 | |||
| 317 | } // namespace Vulkan | 376 | } // namespace Vulkan |
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h index f9ee53cfb..f449bc8d0 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.h +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h | |||
| @@ -9,6 +9,8 @@ | |||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 10 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 11 | 11 | ||
| 12 | VK_DEFINE_HANDLE(VmaAllocator) | ||
| 13 | |||
| 12 | namespace Vulkan { | 14 | namespace Vulkan { |
| 13 | 15 | ||
| 14 | class Device; | 16 | class Device; |
| @@ -17,9 +19,11 @@ class MemoryAllocation; | |||
| 17 | 19 | ||
| 18 | /// Hints and requirements for the backing memory type of a commit | 20 | /// Hints and requirements for the backing memory type of a commit |
| 19 | enum class MemoryUsage { | 21 | enum class MemoryUsage { |
| 20 | DeviceLocal, ///< Hints device local usages, fastest memory type to read and write from the GPU | 22 | DeviceLocal, ///< Requests device local host visible buffer, falling back to device local |
| 23 | ///< memory. | ||
| 21 | Upload, ///< Requires a host visible memory type optimized for CPU to GPU uploads | 24 | Upload, ///< Requires a host visible memory type optimized for CPU to GPU uploads |
| 22 | Download, ///< Requires a host visible memory type optimized for GPU to CPU readbacks | 25 | Download, ///< Requires a host visible memory type optimized for GPU to CPU readbacks |
| 26 | Stream, ///< Requests device local host visible buffer, falling back host memory. | ||
| 23 | }; | 27 | }; |
| 24 | 28 | ||
| 25 | /// Ownership handle of a memory commitment. | 29 | /// Ownership handle of a memory commitment. |
| @@ -82,6 +86,8 @@ public: | |||
| 82 | 86 | ||
| 83 | vk::Image CreateImage(const VkImageCreateInfo& ci) const; | 87 | vk::Image CreateImage(const VkImageCreateInfo& ci) const; |
| 84 | 88 | ||
| 89 | vk::Buffer CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const; | ||
| 90 | |||
| 85 | /** | 91 | /** |
| 86 | * Commits a memory with the specified requirements. | 92 | * Commits a memory with the specified requirements. |
| 87 | * | 93 | * |
| @@ -113,13 +119,11 @@ private: | |||
| 113 | std::optional<u32> FindType(VkMemoryPropertyFlags flags, u32 type_mask) const; | 119 | std::optional<u32> FindType(VkMemoryPropertyFlags flags, u32 type_mask) const; |
| 114 | 120 | ||
| 115 | const Device& device; ///< Device handle. | 121 | const Device& device; ///< Device handle. |
| 122 | VmaAllocator allocator; ///< Vma allocator. | ||
| 116 | const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. | 123 | const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. |
| 117 | std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations. | 124 | std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations. |
| 118 | VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers | 125 | VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers |
| 119 | // and optimal images | 126 | // and optimal images |
| 120 | }; | 127 | }; |
| 121 | 128 | ||
| 122 | /// Returns true when a memory usage is guaranteed to be host visible. | ||
| 123 | bool IsHostVisible(MemoryUsage usage) noexcept; | ||
| 124 | |||
| 125 | } // namespace Vulkan | 129 | } // namespace Vulkan |
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 5d088dc58..c01a9478e 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp | |||
| @@ -561,14 +561,28 @@ void Image::Release() const noexcept { | |||
| 561 | } | 561 | } |
| 562 | } | 562 | } |
| 563 | 563 | ||
| 564 | void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { | 564 | void Buffer::Flush() const { |
| 565 | Check(dld->vkBindBufferMemory(owner, handle, memory, offset)); | 565 | if (!is_coherent) { |
| 566 | vmaFlushAllocation(allocator, allocation, 0, VK_WHOLE_SIZE); | ||
| 567 | } | ||
| 568 | } | ||
| 569 | |||
| 570 | void Buffer::Invalidate() const { | ||
| 571 | if (!is_coherent) { | ||
| 572 | vmaInvalidateAllocation(allocator, allocation, 0, VK_WHOLE_SIZE); | ||
| 573 | } | ||
| 566 | } | 574 | } |
| 567 | 575 | ||
| 568 | void Buffer::SetObjectNameEXT(const char* name) const { | 576 | void Buffer::SetObjectNameEXT(const char* name) const { |
| 569 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER, name); | 577 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER, name); |
| 570 | } | 578 | } |
| 571 | 579 | ||
| 580 | void Buffer::Release() const noexcept { | ||
| 581 | if (handle) { | ||
| 582 | vmaDestroyBuffer(allocator, handle, allocation); | ||
| 583 | } | ||
| 584 | } | ||
| 585 | |||
| 572 | void BufferView::SetObjectNameEXT(const char* name) const { | 586 | void BufferView::SetObjectNameEXT(const char* name) const { |
| 573 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name); | 587 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name); |
| 574 | } | 588 | } |
| @@ -707,12 +721,6 @@ Queue Device::GetQueue(u32 family_index) const noexcept { | |||
| 707 | return Queue(queue, *dld); | 721 | return Queue(queue, *dld); |
| 708 | } | 722 | } |
| 709 | 723 | ||
| 710 | Buffer Device::CreateBuffer(const VkBufferCreateInfo& ci) const { | ||
| 711 | VkBuffer object; | ||
| 712 | Check(dld->vkCreateBuffer(handle, &ci, nullptr, &object)); | ||
| 713 | return Buffer(object, handle, *dld); | ||
| 714 | } | ||
| 715 | |||
| 716 | BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const { | 724 | BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const { |
| 717 | VkBufferView object; | 725 | VkBufferView object; |
| 718 | Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object)); | 726 | Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object)); |
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 8ec708774..44fce47a5 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h | |||
| @@ -673,6 +673,84 @@ private: | |||
| 673 | const DeviceDispatch* dld = nullptr; | 673 | const DeviceDispatch* dld = nullptr; |
| 674 | }; | 674 | }; |
| 675 | 675 | ||
| 676 | class Buffer { | ||
| 677 | public: | ||
| 678 | explicit Buffer(VkBuffer handle_, VkDevice owner_, VmaAllocator allocator_, | ||
| 679 | VmaAllocation allocation_, std::span<u8> mapped_, bool is_coherent_, | ||
| 680 | const DeviceDispatch& dld_) noexcept | ||
| 681 | : handle{handle_}, owner{owner_}, allocator{allocator_}, | ||
| 682 | allocation{allocation_}, mapped{mapped_}, is_coherent{is_coherent_}, dld{&dld_} {} | ||
| 683 | Buffer() = default; | ||
| 684 | |||
| 685 | Buffer(const Buffer&) = delete; | ||
| 686 | Buffer& operator=(const Buffer&) = delete; | ||
| 687 | |||
| 688 | Buffer(Buffer&& rhs) noexcept | ||
| 689 | : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, allocator{rhs.allocator}, | ||
| 690 | allocation{rhs.allocation}, mapped{rhs.mapped}, | ||
| 691 | is_coherent{rhs.is_coherent}, dld{rhs.dld} {} | ||
| 692 | |||
| 693 | Buffer& operator=(Buffer&& rhs) noexcept { | ||
| 694 | Release(); | ||
| 695 | handle = std::exchange(rhs.handle, nullptr); | ||
| 696 | owner = rhs.owner; | ||
| 697 | allocator = rhs.allocator; | ||
| 698 | allocation = rhs.allocation; | ||
| 699 | mapped = rhs.mapped; | ||
| 700 | is_coherent = rhs.is_coherent; | ||
| 701 | dld = rhs.dld; | ||
| 702 | return *this; | ||
| 703 | } | ||
| 704 | |||
| 705 | ~Buffer() noexcept { | ||
| 706 | Release(); | ||
| 707 | } | ||
| 708 | |||
| 709 | VkBuffer operator*() const noexcept { | ||
| 710 | return handle; | ||
| 711 | } | ||
| 712 | |||
| 713 | void reset() noexcept { | ||
| 714 | Release(); | ||
| 715 | handle = nullptr; | ||
| 716 | } | ||
| 717 | |||
| 718 | explicit operator bool() const noexcept { | ||
| 719 | return handle != nullptr; | ||
| 720 | } | ||
| 721 | |||
| 722 | /// Returns the host mapped memory, an empty span otherwise. | ||
| 723 | std::span<u8> Mapped() noexcept { | ||
| 724 | return mapped; | ||
| 725 | } | ||
| 726 | |||
| 727 | std::span<const u8> Mapped() const noexcept { | ||
| 728 | return mapped; | ||
| 729 | } | ||
| 730 | |||
| 731 | /// Returns true if the buffer is mapped to the host. | ||
| 732 | bool IsHostVisible() const noexcept { | ||
| 733 | return !mapped.empty(); | ||
| 734 | } | ||
| 735 | |||
| 736 | void Flush() const; | ||
| 737 | |||
| 738 | void Invalidate() const; | ||
| 739 | |||
| 740 | void SetObjectNameEXT(const char* name) const; | ||
| 741 | |||
| 742 | private: | ||
| 743 | void Release() const noexcept; | ||
| 744 | |||
| 745 | VkBuffer handle = nullptr; | ||
| 746 | VkDevice owner = nullptr; | ||
| 747 | VmaAllocator allocator = nullptr; | ||
| 748 | VmaAllocation allocation = nullptr; | ||
| 749 | std::span<u8> mapped = {}; | ||
| 750 | bool is_coherent = false; | ||
| 751 | const DeviceDispatch* dld = nullptr; | ||
| 752 | }; | ||
| 753 | |||
| 676 | class Queue { | 754 | class Queue { |
| 677 | public: | 755 | public: |
| 678 | /// Construct an empty queue handle. | 756 | /// Construct an empty queue handle. |
| @@ -696,17 +774,6 @@ private: | |||
| 696 | const DeviceDispatch* dld = nullptr; | 774 | const DeviceDispatch* dld = nullptr; |
| 697 | }; | 775 | }; |
| 698 | 776 | ||
| 699 | class Buffer : public Handle<VkBuffer, VkDevice, DeviceDispatch> { | ||
| 700 | using Handle<VkBuffer, VkDevice, DeviceDispatch>::Handle; | ||
| 701 | |||
| 702 | public: | ||
| 703 | /// Attaches a memory allocation. | ||
| 704 | void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const; | ||
| 705 | |||
| 706 | /// Set object name. | ||
| 707 | void SetObjectNameEXT(const char* name) const; | ||
| 708 | }; | ||
| 709 | |||
| 710 | class BufferView : public Handle<VkBufferView, VkDevice, DeviceDispatch> { | 777 | class BufferView : public Handle<VkBufferView, VkDevice, DeviceDispatch> { |
| 711 | using Handle<VkBufferView, VkDevice, DeviceDispatch>::Handle; | 778 | using Handle<VkBufferView, VkDevice, DeviceDispatch>::Handle; |
| 712 | 779 | ||
| @@ -886,8 +953,6 @@ public: | |||
| 886 | 953 | ||
| 887 | Queue GetQueue(u32 family_index) const noexcept; | 954 | Queue GetQueue(u32 family_index) const noexcept; |
| 888 | 955 | ||
| 889 | Buffer CreateBuffer(const VkBufferCreateInfo& ci) const; | ||
| 890 | |||
| 891 | BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const; | 956 | BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const; |
| 892 | 957 | ||
| 893 | ImageView CreateImageView(const VkImageViewCreateInfo& ci) const; | 958 | ImageView CreateImageView(const VkImageViewCreateInfo& ci) const; |