diff options
Diffstat (limited to 'src')
8 files changed, 143 insertions, 91 deletions
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 8e1b46277..281bf9ac3 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp | |||
| @@ -53,8 +53,9 @@ vk::DescriptorSetLayout VKComputePipeline::CreateDescriptorSetLayout() const { | |||
| 53 | }; | 53 | }; |
| 54 | add_bindings(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, entries.const_buffers.size()); | 54 | add_bindings(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, entries.const_buffers.size()); |
| 55 | add_bindings(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, entries.global_buffers.size()); | 55 | add_bindings(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, entries.global_buffers.size()); |
| 56 | add_bindings(VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, entries.texel_buffers.size()); | 56 | add_bindings(VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, entries.uniform_texels.size()); |
| 57 | add_bindings(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, entries.samplers.size()); | 57 | add_bindings(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, entries.samplers.size()); |
| 58 | add_bindings(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, entries.storage_texels.size()); | ||
| 58 | add_bindings(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, entries.images.size()); | 59 | add_bindings(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, entries.images.size()); |
| 59 | 60 | ||
| 60 | VkDescriptorSetLayoutCreateInfo ci; | 61 | VkDescriptorSetLayoutCreateInfo ci; |
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp index 890fd52cf..9259b618d 100644 --- a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp | |||
| @@ -42,6 +42,7 @@ vk::DescriptorPool* VKDescriptorPool::AllocateNewPool() { | |||
| 42 | {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, num_sets * 60}, | 42 | {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, num_sets * 60}, |
| 43 | {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, num_sets * 64}, | 43 | {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, num_sets * 64}, |
| 44 | {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, num_sets * 64}, | 44 | {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, num_sets * 64}, |
| 45 | {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, num_sets * 64}, | ||
| 45 | {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, num_sets * 40}}; | 46 | {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, num_sets * 40}}; |
| 46 | 47 | ||
| 47 | VkDescriptorPoolCreateInfo ci; | 48 | VkDescriptorPoolCreateInfo ci; |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 65a1c6245..b8ccf164f 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -45,6 +45,7 @@ constexpr VkDescriptorType UNIFORM_BUFFER = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; | |||
| 45 | constexpr VkDescriptorType STORAGE_BUFFER = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; | 45 | constexpr VkDescriptorType STORAGE_BUFFER = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; |
| 46 | constexpr VkDescriptorType UNIFORM_TEXEL_BUFFER = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; | 46 | constexpr VkDescriptorType UNIFORM_TEXEL_BUFFER = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; |
| 47 | constexpr VkDescriptorType COMBINED_IMAGE_SAMPLER = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; | 47 | constexpr VkDescriptorType COMBINED_IMAGE_SAMPLER = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; |
| 48 | constexpr VkDescriptorType STORAGE_TEXEL_BUFFER = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; | ||
| 48 | constexpr VkDescriptorType STORAGE_IMAGE = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; | 49 | constexpr VkDescriptorType STORAGE_IMAGE = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; |
| 49 | 50 | ||
| 50 | constexpr VideoCommon::Shader::CompilerSettings compiler_settings{ | 51 | constexpr VideoCommon::Shader::CompilerSettings compiler_settings{ |
| @@ -104,8 +105,9 @@ u32 FillDescriptorLayout(const ShaderEntries& entries, | |||
| 104 | u32 binding = base_binding; | 105 | u32 binding = base_binding; |
| 105 | AddBindings<UNIFORM_BUFFER>(bindings, binding, flags, entries.const_buffers); | 106 | AddBindings<UNIFORM_BUFFER>(bindings, binding, flags, entries.const_buffers); |
| 106 | AddBindings<STORAGE_BUFFER>(bindings, binding, flags, entries.global_buffers); | 107 | AddBindings<STORAGE_BUFFER>(bindings, binding, flags, entries.global_buffers); |
| 107 | AddBindings<UNIFORM_TEXEL_BUFFER>(bindings, binding, flags, entries.texel_buffers); | 108 | AddBindings<UNIFORM_TEXEL_BUFFER>(bindings, binding, flags, entries.uniform_texels); |
| 108 | AddBindings<COMBINED_IMAGE_SAMPLER>(bindings, binding, flags, entries.samplers); | 109 | AddBindings<COMBINED_IMAGE_SAMPLER>(bindings, binding, flags, entries.samplers); |
| 110 | AddBindings<STORAGE_TEXEL_BUFFER>(bindings, binding, flags, entries.storage_texels); | ||
| 109 | AddBindings<STORAGE_IMAGE>(bindings, binding, flags, entries.images); | 111 | AddBindings<STORAGE_IMAGE>(bindings, binding, flags, entries.images); |
| 110 | return binding; | 112 | return binding; |
| 111 | } | 113 | } |
| @@ -377,16 +379,17 @@ void AddEntry(std::vector<VkDescriptorUpdateTemplateEntry>& template_entries, u3 | |||
| 377 | return; | 379 | return; |
| 378 | } | 380 | } |
| 379 | 381 | ||
| 380 | if constexpr (descriptor_type == UNIFORM_TEXEL_BUFFER) { | 382 | if constexpr (descriptor_type == UNIFORM_TEXEL_BUFFER || |
| 381 | // Nvidia has a bug where updating multiple uniform texels at once causes the driver to | 383 | descriptor_type == STORAGE_TEXEL_BUFFER) { |
| 382 | // crash. | 384 | // Nvidia has a bug where updating multiple texels at once causes the driver to crash. |
| 385 | // Note: Fixed in driver Windows 443.24, Linux 440.66.15 | ||
| 383 | for (u32 i = 0; i < count; ++i) { | 386 | for (u32 i = 0; i < count; ++i) { |
| 384 | VkDescriptorUpdateTemplateEntry& entry = template_entries.emplace_back(); | 387 | VkDescriptorUpdateTemplateEntry& entry = template_entries.emplace_back(); |
| 385 | entry.dstBinding = binding + i; | 388 | entry.dstBinding = binding + i; |
| 386 | entry.dstArrayElement = 0; | 389 | entry.dstArrayElement = 0; |
| 387 | entry.descriptorCount = 1; | 390 | entry.descriptorCount = 1; |
| 388 | entry.descriptorType = descriptor_type; | 391 | entry.descriptorType = descriptor_type; |
| 389 | entry.offset = offset + i * entry_size; | 392 | entry.offset = static_cast<std::size_t>(offset + i * entry_size); |
| 390 | entry.stride = entry_size; | 393 | entry.stride = entry_size; |
| 391 | } | 394 | } |
| 392 | } else if (count > 0) { | 395 | } else if (count > 0) { |
| @@ -407,8 +410,9 @@ void FillDescriptorUpdateTemplateEntries( | |||
| 407 | std::vector<VkDescriptorUpdateTemplateEntryKHR>& template_entries) { | 410 | std::vector<VkDescriptorUpdateTemplateEntryKHR>& template_entries) { |
| 408 | AddEntry<UNIFORM_BUFFER>(template_entries, offset, binding, entries.const_buffers); | 411 | AddEntry<UNIFORM_BUFFER>(template_entries, offset, binding, entries.const_buffers); |
| 409 | AddEntry<STORAGE_BUFFER>(template_entries, offset, binding, entries.global_buffers); | 412 | AddEntry<STORAGE_BUFFER>(template_entries, offset, binding, entries.global_buffers); |
| 410 | AddEntry<UNIFORM_TEXEL_BUFFER>(template_entries, offset, binding, entries.texel_buffers); | 413 | AddEntry<UNIFORM_TEXEL_BUFFER>(template_entries, offset, binding, entries.uniform_texels); |
| 411 | AddEntry<COMBINED_IMAGE_SAMPLER>(template_entries, offset, binding, entries.samplers); | 414 | AddEntry<COMBINED_IMAGE_SAMPLER>(template_entries, offset, binding, entries.samplers); |
| 415 | AddEntry<STORAGE_TEXEL_BUFFER>(template_entries, offset, binding, entries.storage_texels); | ||
| 412 | AddEntry<STORAGE_IMAGE>(template_entries, offset, binding, entries.images); | 416 | AddEntry<STORAGE_IMAGE>(template_entries, offset, binding, entries.images); |
| 413 | } | 417 | } |
| 414 | 418 | ||
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 86328237e..d86c46412 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -468,8 +468,9 @@ void RasterizerVulkan::DispatchCompute(GPUVAddr code_addr) { | |||
| 468 | const auto& entries = pipeline.GetEntries(); | 468 | const auto& entries = pipeline.GetEntries(); |
| 469 | SetupComputeConstBuffers(entries); | 469 | SetupComputeConstBuffers(entries); |
| 470 | SetupComputeGlobalBuffers(entries); | 470 | SetupComputeGlobalBuffers(entries); |
| 471 | SetupComputeTexelBuffers(entries); | 471 | SetupComputeUniformTexels(entries); |
| 472 | SetupComputeTextures(entries); | 472 | SetupComputeTextures(entries); |
| 473 | SetupComputeStorageTexels(entries); | ||
| 473 | SetupComputeImages(entries); | 474 | SetupComputeImages(entries); |
| 474 | 475 | ||
| 475 | buffer_cache.Unmap(); | 476 | buffer_cache.Unmap(); |
| @@ -787,8 +788,9 @@ void RasterizerVulkan::SetupShaderDescriptors( | |||
| 787 | const auto& entries = shader->GetEntries(); | 788 | const auto& entries = shader->GetEntries(); |
| 788 | SetupGraphicsConstBuffers(entries, stage); | 789 | SetupGraphicsConstBuffers(entries, stage); |
| 789 | SetupGraphicsGlobalBuffers(entries, stage); | 790 | SetupGraphicsGlobalBuffers(entries, stage); |
| 790 | SetupGraphicsTexelBuffers(entries, stage); | 791 | SetupGraphicsUniformTexels(entries, stage); |
| 791 | SetupGraphicsTextures(entries, stage); | 792 | SetupGraphicsTextures(entries, stage); |
| 793 | SetupGraphicsStorageTexels(entries, stage); | ||
| 792 | SetupGraphicsImages(entries, stage); | 794 | SetupGraphicsImages(entries, stage); |
| 793 | } | 795 | } |
| 794 | texture_cache.GuardSamplers(false); | 796 | texture_cache.GuardSamplers(false); |
| @@ -983,12 +985,12 @@ void RasterizerVulkan::SetupGraphicsGlobalBuffers(const ShaderEntries& entries, | |||
| 983 | } | 985 | } |
| 984 | } | 986 | } |
| 985 | 987 | ||
| 986 | void RasterizerVulkan::SetupGraphicsTexelBuffers(const ShaderEntries& entries, std::size_t stage) { | 988 | void RasterizerVulkan::SetupGraphicsUniformTexels(const ShaderEntries& entries, std::size_t stage) { |
| 987 | MICROPROFILE_SCOPE(Vulkan_Textures); | 989 | MICROPROFILE_SCOPE(Vulkan_Textures); |
| 988 | const auto& gpu = system.GPU().Maxwell3D(); | 990 | const auto& gpu = system.GPU().Maxwell3D(); |
| 989 | for (const auto& entry : entries.texel_buffers) { | 991 | for (const auto& entry : entries.uniform_texels) { |
| 990 | const auto image = GetTextureInfo(gpu, entry, stage).tic; | 992 | const auto image = GetTextureInfo(gpu, entry, stage).tic; |
| 991 | SetupTexelBuffer(image, entry); | 993 | SetupUniformTexels(image, entry); |
| 992 | } | 994 | } |
| 993 | } | 995 | } |
| 994 | 996 | ||
| @@ -1003,6 +1005,15 @@ void RasterizerVulkan::SetupGraphicsTextures(const ShaderEntries& entries, std:: | |||
| 1003 | } | 1005 | } |
| 1004 | } | 1006 | } |
| 1005 | 1007 | ||
| 1008 | void RasterizerVulkan::SetupGraphicsStorageTexels(const ShaderEntries& entries, std::size_t stage) { | ||
| 1009 | MICROPROFILE_SCOPE(Vulkan_Textures); | ||
| 1010 | const auto& gpu = system.GPU().Maxwell3D(); | ||
| 1011 | for (const auto& entry : entries.storage_texels) { | ||
| 1012 | const auto image = GetTextureInfo(gpu, entry, stage).tic; | ||
| 1013 | SetupStorageTexel(image, entry); | ||
| 1014 | } | ||
| 1015 | } | ||
| 1016 | |||
| 1006 | void RasterizerVulkan::SetupGraphicsImages(const ShaderEntries& entries, std::size_t stage) { | 1017 | void RasterizerVulkan::SetupGraphicsImages(const ShaderEntries& entries, std::size_t stage) { |
| 1007 | MICROPROFILE_SCOPE(Vulkan_Images); | 1018 | MICROPROFILE_SCOPE(Vulkan_Images); |
| 1008 | const auto& gpu = system.GPU().Maxwell3D(); | 1019 | const auto& gpu = system.GPU().Maxwell3D(); |
| @@ -1035,12 +1046,12 @@ void RasterizerVulkan::SetupComputeGlobalBuffers(const ShaderEntries& entries) { | |||
| 1035 | } | 1046 | } |
| 1036 | } | 1047 | } |
| 1037 | 1048 | ||
| 1038 | void RasterizerVulkan::SetupComputeTexelBuffers(const ShaderEntries& entries) { | 1049 | void RasterizerVulkan::SetupComputeUniformTexels(const ShaderEntries& entries) { |
| 1039 | MICROPROFILE_SCOPE(Vulkan_Textures); | 1050 | MICROPROFILE_SCOPE(Vulkan_Textures); |
| 1040 | const auto& gpu = system.GPU().KeplerCompute(); | 1051 | const auto& gpu = system.GPU().KeplerCompute(); |
| 1041 | for (const auto& entry : entries.texel_buffers) { | 1052 | for (const auto& entry : entries.uniform_texels) { |
| 1042 | const auto image = GetTextureInfo(gpu, entry, ComputeShaderIndex).tic; | 1053 | const auto image = GetTextureInfo(gpu, entry, ComputeShaderIndex).tic; |
| 1043 | SetupTexelBuffer(image, entry); | 1054 | SetupUniformTexels(image, entry); |
| 1044 | } | 1055 | } |
| 1045 | } | 1056 | } |
| 1046 | 1057 | ||
| @@ -1055,6 +1066,15 @@ void RasterizerVulkan::SetupComputeTextures(const ShaderEntries& entries) { | |||
| 1055 | } | 1066 | } |
| 1056 | } | 1067 | } |
| 1057 | 1068 | ||
| 1069 | void RasterizerVulkan::SetupComputeStorageTexels(const ShaderEntries& entries) { | ||
| 1070 | MICROPROFILE_SCOPE(Vulkan_Textures); | ||
| 1071 | const auto& gpu = system.GPU().KeplerCompute(); | ||
| 1072 | for (const auto& entry : entries.storage_texels) { | ||
| 1073 | const auto image = GetTextureInfo(gpu, entry, ComputeShaderIndex).tic; | ||
| 1074 | SetupStorageTexel(image, entry); | ||
| 1075 | } | ||
| 1076 | } | ||
| 1077 | |||
| 1058 | void RasterizerVulkan::SetupComputeImages(const ShaderEntries& entries) { | 1078 | void RasterizerVulkan::SetupComputeImages(const ShaderEntries& entries) { |
| 1059 | MICROPROFILE_SCOPE(Vulkan_Images); | 1079 | MICROPROFILE_SCOPE(Vulkan_Images); |
| 1060 | const auto& gpu = system.GPU().KeplerCompute(); | 1080 | const auto& gpu = system.GPU().KeplerCompute(); |
| @@ -1104,8 +1124,8 @@ void RasterizerVulkan::SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAdd | |||
| 1104 | update_descriptor_queue.AddBuffer(buffer, offset, size); | 1124 | update_descriptor_queue.AddBuffer(buffer, offset, size); |
| 1105 | } | 1125 | } |
| 1106 | 1126 | ||
| 1107 | void RasterizerVulkan::SetupTexelBuffer(const Tegra::Texture::TICEntry& tic, | 1127 | void RasterizerVulkan::SetupUniformTexels(const Tegra::Texture::TICEntry& tic, |
| 1108 | const TexelBufferEntry& entry) { | 1128 | const UniformTexelEntry& entry) { |
| 1109 | const auto view = texture_cache.GetTextureSurface(tic, entry); | 1129 | const auto view = texture_cache.GetTextureSurface(tic, entry); |
| 1110 | ASSERT(view->IsBufferView()); | 1130 | ASSERT(view->IsBufferView()); |
| 1111 | 1131 | ||
| @@ -1127,6 +1147,14 @@ void RasterizerVulkan::SetupTexture(const Tegra::Texture::FullTextureInfo& textu | |||
| 1127 | sampled_views.push_back(ImageView{std::move(view), image_layout}); | 1147 | sampled_views.push_back(ImageView{std::move(view), image_layout}); |
| 1128 | } | 1148 | } |
| 1129 | 1149 | ||
| 1150 | void RasterizerVulkan::SetupStorageTexel(const Tegra::Texture::TICEntry& tic, | ||
| 1151 | const StorageTexelEntry& entry) { | ||
| 1152 | const auto view = texture_cache.GetImageSurface(tic, entry); | ||
| 1153 | ASSERT(view->IsBufferView()); | ||
| 1154 | |||
| 1155 | update_descriptor_queue.AddTexelBuffer(view->GetBufferView()); | ||
| 1156 | } | ||
| 1157 | |||
| 1130 | void RasterizerVulkan::SetupImage(const Tegra::Texture::TICEntry& tic, const ImageEntry& entry) { | 1158 | void RasterizerVulkan::SetupImage(const Tegra::Texture::TICEntry& tic, const ImageEntry& entry) { |
| 1131 | auto view = texture_cache.GetImageSurface(tic, entry); | 1159 | auto view = texture_cache.GetImageSurface(tic, entry); |
| 1132 | 1160 | ||
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 0ed0e48c6..04be37a5e 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h | |||
| @@ -193,12 +193,15 @@ private: | |||
| 193 | /// Setup global buffers in the graphics pipeline. | 193 | /// Setup global buffers in the graphics pipeline. |
| 194 | void SetupGraphicsGlobalBuffers(const ShaderEntries& entries, std::size_t stage); | 194 | void SetupGraphicsGlobalBuffers(const ShaderEntries& entries, std::size_t stage); |
| 195 | 195 | ||
| 196 | /// Setup texel buffers in the graphics pipeline. | 196 | /// Setup uniform texels in the graphics pipeline. |
| 197 | void SetupGraphicsTexelBuffers(const ShaderEntries& entries, std::size_t stage); | 197 | void SetupGraphicsUniformTexels(const ShaderEntries& entries, std::size_t stage); |
| 198 | 198 | ||
| 199 | /// Setup textures in the graphics pipeline. | 199 | /// Setup textures in the graphics pipeline. |
| 200 | void SetupGraphicsTextures(const ShaderEntries& entries, std::size_t stage); | 200 | void SetupGraphicsTextures(const ShaderEntries& entries, std::size_t stage); |
| 201 | 201 | ||
| 202 | /// Setup storage texels in the graphics pipeline. | ||
| 203 | void SetupGraphicsStorageTexels(const ShaderEntries& entries, std::size_t stage); | ||
| 204 | |||
| 202 | /// Setup images in the graphics pipeline. | 205 | /// Setup images in the graphics pipeline. |
| 203 | void SetupGraphicsImages(const ShaderEntries& entries, std::size_t stage); | 206 | void SetupGraphicsImages(const ShaderEntries& entries, std::size_t stage); |
| 204 | 207 | ||
| @@ -209,11 +212,14 @@ private: | |||
| 209 | void SetupComputeGlobalBuffers(const ShaderEntries& entries); | 212 | void SetupComputeGlobalBuffers(const ShaderEntries& entries); |
| 210 | 213 | ||
| 211 | /// Setup texel buffers in the compute pipeline. | 214 | /// Setup texel buffers in the compute pipeline. |
| 212 | void SetupComputeTexelBuffers(const ShaderEntries& entries); | 215 | void SetupComputeUniformTexels(const ShaderEntries& entries); |
| 213 | 216 | ||
| 214 | /// Setup textures in the compute pipeline. | 217 | /// Setup textures in the compute pipeline. |
| 215 | void SetupComputeTextures(const ShaderEntries& entries); | 218 | void SetupComputeTextures(const ShaderEntries& entries); |
| 216 | 219 | ||
| 220 | /// Setup storage texels in the compute pipeline. | ||
| 221 | void SetupComputeStorageTexels(const ShaderEntries& entries); | ||
| 222 | |||
| 217 | /// Setup images in the compute pipeline. | 223 | /// Setup images in the compute pipeline. |
| 218 | void SetupComputeImages(const ShaderEntries& entries); | 224 | void SetupComputeImages(const ShaderEntries& entries); |
| 219 | 225 | ||
| @@ -222,10 +228,12 @@ private: | |||
| 222 | 228 | ||
| 223 | void SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAddr address); | 229 | void SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAddr address); |
| 224 | 230 | ||
| 225 | void SetupTexelBuffer(const Tegra::Texture::TICEntry& image, const TexelBufferEntry& entry); | 231 | void SetupUniformTexels(const Tegra::Texture::TICEntry& image, const UniformTexelEntry& entry); |
| 226 | 232 | ||
| 227 | void SetupTexture(const Tegra::Texture::FullTextureInfo& texture, const SamplerEntry& entry); | 233 | void SetupTexture(const Tegra::Texture::FullTextureInfo& texture, const SamplerEntry& entry); |
| 228 | 234 | ||
| 235 | void SetupStorageTexel(const Tegra::Texture::TICEntry& tic, const StorageTexelEntry& entry); | ||
| 236 | |||
| 229 | void SetupImage(const Tegra::Texture::TICEntry& tic, const ImageEntry& entry); | 237 | void SetupImage(const Tegra::Texture::TICEntry& tic, const ImageEntry& entry); |
| 230 | 238 | ||
| 231 | void UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs); | 239 | void UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs); |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index a13e8baa7..97429cc59 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | |||
| @@ -400,8 +400,9 @@ private: | |||
| 400 | u32 binding = specialization.base_binding; | 400 | u32 binding = specialization.base_binding; |
| 401 | binding = DeclareConstantBuffers(binding); | 401 | binding = DeclareConstantBuffers(binding); |
| 402 | binding = DeclareGlobalBuffers(binding); | 402 | binding = DeclareGlobalBuffers(binding); |
| 403 | binding = DeclareTexelBuffers(binding); | 403 | binding = DeclareUniformTexels(binding); |
| 404 | binding = DeclareSamplers(binding); | 404 | binding = DeclareSamplers(binding); |
| 405 | binding = DeclareStorageTexels(binding); | ||
| 405 | binding = DeclareImages(binding); | 406 | binding = DeclareImages(binding); |
| 406 | 407 | ||
| 407 | const Id main = OpFunction(t_void, {}, TypeFunction(t_void)); | 408 | const Id main = OpFunction(t_void, {}, TypeFunction(t_void)); |
| @@ -889,7 +890,7 @@ private: | |||
| 889 | return binding; | 890 | return binding; |
| 890 | } | 891 | } |
| 891 | 892 | ||
| 892 | u32 DeclareTexelBuffers(u32 binding) { | 893 | u32 DeclareUniformTexels(u32 binding) { |
| 893 | for (const auto& sampler : ir.GetSamplers()) { | 894 | for (const auto& sampler : ir.GetSamplers()) { |
| 894 | if (!sampler.is_buffer) { | 895 | if (!sampler.is_buffer) { |
| 895 | continue; | 896 | continue; |
| @@ -910,7 +911,7 @@ private: | |||
| 910 | Decorate(id, spv::Decoration::Binding, binding++); | 911 | Decorate(id, spv::Decoration::Binding, binding++); |
| 911 | Decorate(id, spv::Decoration::DescriptorSet, DESCRIPTOR_SET); | 912 | Decorate(id, spv::Decoration::DescriptorSet, DESCRIPTOR_SET); |
| 912 | 913 | ||
| 913 | texel_buffers.emplace(sampler.index, TexelBuffer{image_type, id}); | 914 | uniform_texels.emplace(sampler.index, TexelBuffer{image_type, id}); |
| 914 | } | 915 | } |
| 915 | return binding; | 916 | return binding; |
| 916 | } | 917 | } |
| @@ -945,31 +946,48 @@ private: | |||
| 945 | return binding; | 946 | return binding; |
| 946 | } | 947 | } |
| 947 | 948 | ||
| 948 | u32 DeclareImages(u32 binding) { | 949 | u32 DeclareStorageTexels(u32 binding) { |
| 949 | for (const auto& image : ir.GetImages()) { | 950 | for (const auto& image : ir.GetImages()) { |
| 950 | const auto [dim, arrayed] = GetImageDim(image); | 951 | if (image.type != Tegra::Shader::ImageType::TextureBuffer) { |
| 951 | constexpr int depth = 0; | 952 | continue; |
| 952 | constexpr bool ms = false; | ||
| 953 | constexpr int sampled = 2; // This won't be accessed with a sampler | ||
| 954 | constexpr auto format = spv::ImageFormat::Unknown; | ||
| 955 | const Id image_type = TypeImage(t_uint, dim, depth, arrayed, ms, sampled, format, {}); | ||
| 956 | const Id pointer_type = TypePointer(spv::StorageClass::UniformConstant, image_type); | ||
| 957 | const Id id = OpVariable(pointer_type, spv::StorageClass::UniformConstant); | ||
| 958 | AddGlobalVariable(Name(id, fmt::format("image_{}", image.index))); | ||
| 959 | |||
| 960 | Decorate(id, spv::Decoration::Binding, binding++); | ||
| 961 | Decorate(id, spv::Decoration::DescriptorSet, DESCRIPTOR_SET); | ||
| 962 | if (image.is_read && !image.is_written) { | ||
| 963 | Decorate(id, spv::Decoration::NonWritable); | ||
| 964 | } else if (image.is_written && !image.is_read) { | ||
| 965 | Decorate(id, spv::Decoration::NonReadable); | ||
| 966 | } | 953 | } |
| 954 | DeclareImage(image, binding); | ||
| 955 | } | ||
| 956 | return binding; | ||
| 957 | } | ||
| 967 | 958 | ||
| 968 | images.emplace(image.index, StorageImage{image_type, id}); | 959 | u32 DeclareImages(u32 binding) { |
| 960 | for (const auto& image : ir.GetImages()) { | ||
| 961 | if (image.type == Tegra::Shader::ImageType::TextureBuffer) { | ||
| 962 | continue; | ||
| 963 | } | ||
| 964 | DeclareImage(image, binding); | ||
| 969 | } | 965 | } |
| 970 | return binding; | 966 | return binding; |
| 971 | } | 967 | } |
| 972 | 968 | ||
| 969 | void DeclareImage(const Image& image, u32& binding) { | ||
| 970 | const auto [dim, arrayed] = GetImageDim(image); | ||
| 971 | constexpr int depth = 0; | ||
| 972 | constexpr bool ms = false; | ||
| 973 | constexpr int sampled = 2; // This won't be accessed with a sampler | ||
| 974 | const auto format = image.is_atomic ? spv::ImageFormat::R32ui : spv::ImageFormat::Unknown; | ||
| 975 | const Id image_type = TypeImage(t_uint, dim, depth, arrayed, ms, sampled, format, {}); | ||
| 976 | const Id pointer_type = TypePointer(spv::StorageClass::UniformConstant, image_type); | ||
| 977 | const Id id = OpVariable(pointer_type, spv::StorageClass::UniformConstant); | ||
| 978 | AddGlobalVariable(Name(id, fmt::format("image_{}", image.index))); | ||
| 979 | |||
| 980 | Decorate(id, spv::Decoration::Binding, binding++); | ||
| 981 | Decorate(id, spv::Decoration::DescriptorSet, DESCRIPTOR_SET); | ||
| 982 | if (image.is_read && !image.is_written) { | ||
| 983 | Decorate(id, spv::Decoration::NonWritable); | ||
| 984 | } else if (image.is_written && !image.is_read) { | ||
| 985 | Decorate(id, spv::Decoration::NonReadable); | ||
| 986 | } | ||
| 987 | |||
| 988 | images.emplace(image.index, StorageImage{image_type, id}); | ||
| 989 | } | ||
| 990 | |||
| 973 | bool IsRenderTargetEnabled(u32 rt) const { | 991 | bool IsRenderTargetEnabled(u32 rt) const { |
| 974 | for (u32 component = 0; component < 4; ++component) { | 992 | for (u32 component = 0; component < 4; ++component) { |
| 975 | if (header.ps.IsColorComponentOutputEnabled(rt, component)) { | 993 | if (header.ps.IsColorComponentOutputEnabled(rt, component)) { |
| @@ -1256,7 +1274,7 @@ private: | |||
| 1256 | } else { | 1274 | } else { |
| 1257 | UNREACHABLE_MSG("Unmanaged offset node type"); | 1275 | UNREACHABLE_MSG("Unmanaged offset node type"); |
| 1258 | } | 1276 | } |
| 1259 | pointer = OpAccessChain(t_cbuf_float, buffer_id, Constant(t_uint, 0), buffer_index, | 1277 | pointer = OpAccessChain(t_cbuf_float, buffer_id, v_uint_zero, buffer_index, |
| 1260 | buffer_element); | 1278 | buffer_element); |
| 1261 | } | 1279 | } |
| 1262 | return {OpLoad(t_float, pointer), Type::Float}; | 1280 | return {OpLoad(t_float, pointer), Type::Float}; |
| @@ -1611,7 +1629,7 @@ private: | |||
| 1611 | 1629 | ||
| 1612 | const Id result = OpIAddCarry(TypeStruct({t_uint, t_uint}), op_a, op_b); | 1630 | const Id result = OpIAddCarry(TypeStruct({t_uint, t_uint}), op_a, op_b); |
| 1613 | const Id carry = OpCompositeExtract(t_uint, result, 1); | 1631 | const Id carry = OpCompositeExtract(t_uint, result, 1); |
| 1614 | return {OpINotEqual(t_bool, carry, Constant(t_uint, 0)), Type::Bool}; | 1632 | return {OpINotEqual(t_bool, carry, v_uint_zero), Type::Bool}; |
| 1615 | } | 1633 | } |
| 1616 | 1634 | ||
| 1617 | Expression LogicalAssign(Operation operation) { | 1635 | Expression LogicalAssign(Operation operation) { |
| @@ -1674,7 +1692,7 @@ private: | |||
| 1674 | const auto& meta = std::get<MetaTexture>(operation.GetMeta()); | 1692 | const auto& meta = std::get<MetaTexture>(operation.GetMeta()); |
| 1675 | const u32 index = meta.sampler.index; | 1693 | const u32 index = meta.sampler.index; |
| 1676 | if (meta.sampler.is_buffer) { | 1694 | if (meta.sampler.is_buffer) { |
| 1677 | const auto& entry = texel_buffers.at(index); | 1695 | const auto& entry = uniform_texels.at(index); |
| 1678 | return OpLoad(entry.image_type, entry.image); | 1696 | return OpLoad(entry.image_type, entry.image); |
| 1679 | } else { | 1697 | } else { |
| 1680 | const auto& entry = sampled_images.at(index); | 1698 | const auto& entry = sampled_images.at(index); |
| @@ -1951,39 +1969,20 @@ private: | |||
| 1951 | return {}; | 1969 | return {}; |
| 1952 | } | 1970 | } |
| 1953 | 1971 | ||
| 1954 | Expression AtomicImageAdd(Operation operation) { | 1972 | template <Id (Module::*func)(Id, Id, Id, Id, Id)> |
| 1955 | UNIMPLEMENTED(); | 1973 | Expression AtomicImage(Operation operation) { |
| 1956 | return {}; | 1974 | const auto& meta{std::get<MetaImage>(operation.GetMeta())}; |
| 1957 | } | 1975 | ASSERT(meta.values.size() == 1); |
| 1958 | |||
| 1959 | Expression AtomicImageMin(Operation operation) { | ||
| 1960 | UNIMPLEMENTED(); | ||
| 1961 | return {}; | ||
| 1962 | } | ||
| 1963 | |||
| 1964 | Expression AtomicImageMax(Operation operation) { | ||
| 1965 | UNIMPLEMENTED(); | ||
| 1966 | return {}; | ||
| 1967 | } | ||
| 1968 | |||
| 1969 | Expression AtomicImageAnd(Operation operation) { | ||
| 1970 | UNIMPLEMENTED(); | ||
| 1971 | return {}; | ||
| 1972 | } | ||
| 1973 | |||
| 1974 | Expression AtomicImageOr(Operation operation) { | ||
| 1975 | UNIMPLEMENTED(); | ||
| 1976 | return {}; | ||
| 1977 | } | ||
| 1978 | 1976 | ||
| 1979 | Expression AtomicImageXor(Operation operation) { | 1977 | const Id coordinate = GetCoordinates(operation, Type::Int); |
| 1980 | UNIMPLEMENTED(); | 1978 | const Id image = images.at(meta.image.index).image; |
| 1981 | return {}; | 1979 | const Id sample = v_uint_zero; |
| 1982 | } | 1980 | const Id pointer = OpImageTexelPointer(t_image_uint, image, coordinate, sample); |
| 1983 | 1981 | ||
| 1984 | Expression AtomicImageExchange(Operation operation) { | 1982 | const Id scope = Constant(t_uint, static_cast<u32>(spv::Scope::Device)); |
| 1985 | UNIMPLEMENTED(); | 1983 | const Id semantics = v_uint_zero; |
| 1986 | return {}; | 1984 | const Id value = AsUint(Visit(meta.values[0])); |
| 1985 | return {(this->*func)(t_uint, pointer, scope, semantics, value), Type::Uint}; | ||
| 1987 | } | 1986 | } |
| 1988 | 1987 | ||
| 1989 | template <Id (Module::*func)(Id, Id, Id, Id, Id)> | 1988 | template <Id (Module::*func)(Id, Id, Id, Id, Id)> |
| @@ -1998,7 +1997,7 @@ private: | |||
| 1998 | return {v_float_zero, Type::Float}; | 1997 | return {v_float_zero, Type::Float}; |
| 1999 | } | 1998 | } |
| 2000 | const Id scope = Constant(t_uint, static_cast<u32>(spv::Scope::Device)); | 1999 | const Id scope = Constant(t_uint, static_cast<u32>(spv::Scope::Device)); |
| 2001 | const Id semantics = Constant(t_uint, 0); | 2000 | const Id semantics = v_uint_zero; |
| 2002 | const Id value = AsUint(Visit(operation[1])); | 2001 | const Id value = AsUint(Visit(operation[1])); |
| 2003 | 2002 | ||
| 2004 | return {(this->*func)(t_uint, pointer, scope, semantics, value), Type::Uint}; | 2003 | return {(this->*func)(t_uint, pointer, scope, semantics, value), Type::Uint}; |
| @@ -2622,11 +2621,11 @@ private: | |||
| 2622 | 2621 | ||
| 2623 | &SPIRVDecompiler::ImageLoad, | 2622 | &SPIRVDecompiler::ImageLoad, |
| 2624 | &SPIRVDecompiler::ImageStore, | 2623 | &SPIRVDecompiler::ImageStore, |
| 2625 | &SPIRVDecompiler::AtomicImageAdd, | 2624 | &SPIRVDecompiler::AtomicImage<&Module::OpAtomicIAdd>, |
| 2626 | &SPIRVDecompiler::AtomicImageAnd, | 2625 | &SPIRVDecompiler::AtomicImage<&Module::OpAtomicAnd>, |
| 2627 | &SPIRVDecompiler::AtomicImageOr, | 2626 | &SPIRVDecompiler::AtomicImage<&Module::OpAtomicOr>, |
| 2628 | &SPIRVDecompiler::AtomicImageXor, | 2627 | &SPIRVDecompiler::AtomicImage<&Module::OpAtomicXor>, |
| 2629 | &SPIRVDecompiler::AtomicImageExchange, | 2628 | &SPIRVDecompiler::AtomicImage<&Module::OpAtomicExchange>, |
| 2630 | 2629 | ||
| 2631 | &SPIRVDecompiler::Atomic<&Module::OpAtomicExchange>, | 2630 | &SPIRVDecompiler::Atomic<&Module::OpAtomicExchange>, |
| 2632 | &SPIRVDecompiler::Atomic<&Module::OpAtomicIAdd>, | 2631 | &SPIRVDecompiler::Atomic<&Module::OpAtomicIAdd>, |
| @@ -2768,8 +2767,11 @@ private: | |||
| 2768 | Decorate(TypeStruct(t_gmem_array), spv::Decoration::Block), 0, spv::Decoration::Offset, 0); | 2767 | Decorate(TypeStruct(t_gmem_array), spv::Decoration::Block), 0, spv::Decoration::Offset, 0); |
| 2769 | const Id t_gmem_ssbo = TypePointer(spv::StorageClass::StorageBuffer, t_gmem_struct); | 2768 | const Id t_gmem_ssbo = TypePointer(spv::StorageClass::StorageBuffer, t_gmem_struct); |
| 2770 | 2769 | ||
| 2770 | const Id t_image_uint = TypePointer(spv::StorageClass::Image, t_uint); | ||
| 2771 | |||
| 2771 | const Id v_float_zero = Constant(t_float, 0.0f); | 2772 | const Id v_float_zero = Constant(t_float, 0.0f); |
| 2772 | const Id v_float_one = Constant(t_float, 1.0f); | 2773 | const Id v_float_one = Constant(t_float, 1.0f); |
| 2774 | const Id v_uint_zero = Constant(t_uint, 0); | ||
| 2773 | 2775 | ||
| 2774 | // Nvidia uses these defaults for varyings (e.g. position and generic attributes) | 2776 | // Nvidia uses these defaults for varyings (e.g. position and generic attributes) |
| 2775 | const Id v_varying_default = | 2777 | const Id v_varying_default = |
| @@ -2794,15 +2796,16 @@ private: | |||
| 2794 | std::unordered_map<u8, GenericVaryingDescription> output_attributes; | 2796 | std::unordered_map<u8, GenericVaryingDescription> output_attributes; |
| 2795 | std::map<u32, Id> constant_buffers; | 2797 | std::map<u32, Id> constant_buffers; |
| 2796 | std::map<GlobalMemoryBase, Id> global_buffers; | 2798 | std::map<GlobalMemoryBase, Id> global_buffers; |
| 2797 | std::map<u32, TexelBuffer> texel_buffers; | 2799 | std::map<u32, TexelBuffer> uniform_texels; |
| 2798 | std::map<u32, SampledImage> sampled_images; | 2800 | std::map<u32, SampledImage> sampled_images; |
| 2801 | std::map<u32, TexelBuffer> storage_texels; | ||
| 2799 | std::map<u32, StorageImage> images; | 2802 | std::map<u32, StorageImage> images; |
| 2800 | 2803 | ||
| 2804 | std::array<Id, Maxwell::NumRenderTargets> frag_colors{}; | ||
| 2801 | Id instance_index{}; | 2805 | Id instance_index{}; |
| 2802 | Id vertex_index{}; | 2806 | Id vertex_index{}; |
| 2803 | Id base_instance{}; | 2807 | Id base_instance{}; |
| 2804 | Id base_vertex{}; | 2808 | Id base_vertex{}; |
| 2805 | std::array<Id, Maxwell::NumRenderTargets> frag_colors{}; | ||
| 2806 | Id frag_depth{}; | 2809 | Id frag_depth{}; |
| 2807 | Id frag_coord{}; | 2810 | Id frag_coord{}; |
| 2808 | Id front_facing{}; | 2811 | Id front_facing{}; |
| @@ -3058,13 +3061,17 @@ ShaderEntries GenerateShaderEntries(const VideoCommon::Shader::ShaderIR& ir) { | |||
| 3058 | } | 3061 | } |
| 3059 | for (const auto& sampler : ir.GetSamplers()) { | 3062 | for (const auto& sampler : ir.GetSamplers()) { |
| 3060 | if (sampler.is_buffer) { | 3063 | if (sampler.is_buffer) { |
| 3061 | entries.texel_buffers.emplace_back(sampler); | 3064 | entries.uniform_texels.emplace_back(sampler); |
| 3062 | } else { | 3065 | } else { |
| 3063 | entries.samplers.emplace_back(sampler); | 3066 | entries.samplers.emplace_back(sampler); |
| 3064 | } | 3067 | } |
| 3065 | } | 3068 | } |
| 3066 | for (const auto& image : ir.GetImages()) { | 3069 | for (const auto& image : ir.GetImages()) { |
| 3067 | entries.images.emplace_back(image); | 3070 | if (image.type == Tegra::Shader::ImageType::TextureBuffer) { |
| 3071 | entries.storage_texels.emplace_back(image); | ||
| 3072 | } else { | ||
| 3073 | entries.images.emplace_back(image); | ||
| 3074 | } | ||
| 3068 | } | 3075 | } |
| 3069 | for (const auto& attribute : ir.GetInputAttributes()) { | 3076 | for (const auto& attribute : ir.GetInputAttributes()) { |
| 3070 | if (IsGenericAttribute(attribute)) { | 3077 | if (IsGenericAttribute(attribute)) { |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.h b/src/video_core/renderer_vulkan/vk_shader_decompiler.h index b7af26388..2b0e90396 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.h +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.h | |||
| @@ -21,8 +21,9 @@ class VKDevice; | |||
| 21 | namespace Vulkan { | 21 | namespace Vulkan { |
| 22 | 22 | ||
| 23 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | 23 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; |
| 24 | using TexelBufferEntry = VideoCommon::Shader::Sampler; | 24 | using UniformTexelEntry = VideoCommon::Shader::Sampler; |
| 25 | using SamplerEntry = VideoCommon::Shader::Sampler; | 25 | using SamplerEntry = VideoCommon::Shader::Sampler; |
| 26 | using StorageTexelEntry = VideoCommon::Shader::Image; | ||
| 26 | using ImageEntry = VideoCommon::Shader::Image; | 27 | using ImageEntry = VideoCommon::Shader::Image; |
| 27 | 28 | ||
| 28 | constexpr u32 DESCRIPTOR_SET = 0; | 29 | constexpr u32 DESCRIPTOR_SET = 0; |
| @@ -66,13 +67,15 @@ private: | |||
| 66 | struct ShaderEntries { | 67 | struct ShaderEntries { |
| 67 | u32 NumBindings() const { | 68 | u32 NumBindings() const { |
| 68 | return static_cast<u32>(const_buffers.size() + global_buffers.size() + | 69 | return static_cast<u32>(const_buffers.size() + global_buffers.size() + |
| 69 | texel_buffers.size() + samplers.size() + images.size()); | 70 | uniform_texels.size() + samplers.size() + storage_texels.size() + |
| 71 | images.size()); | ||
| 70 | } | 72 | } |
| 71 | 73 | ||
| 72 | std::vector<ConstBufferEntry> const_buffers; | 74 | std::vector<ConstBufferEntry> const_buffers; |
| 73 | std::vector<GlobalBufferEntry> global_buffers; | 75 | std::vector<GlobalBufferEntry> global_buffers; |
| 74 | std::vector<TexelBufferEntry> texel_buffers; | 76 | std::vector<UniformTexelEntry> uniform_texels; |
| 75 | std::vector<SamplerEntry> samplers; | 77 | std::vector<SamplerEntry> samplers; |
| 78 | std::vector<StorageTexelEntry> storage_texels; | ||
| 76 | std::vector<ImageEntry> images; | 79 | std::vector<ImageEntry> images; |
| 77 | std::set<u32> attributes; | 80 | std::set<u32> attributes; |
| 78 | std::array<bool, Maxwell::NumClipDistances> clip_distances{}; | 81 | std::array<bool, Maxwell::NumClipDistances> clip_distances{}; |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 2f1d5021d..ea487b770 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -100,8 +100,8 @@ vk::Buffer CreateBuffer(const VKDevice& device, const SurfaceParams& params, | |||
| 100 | ci.pNext = nullptr; | 100 | ci.pNext = nullptr; |
| 101 | ci.flags = 0; | 101 | ci.flags = 0; |
| 102 | ci.size = static_cast<VkDeviceSize>(host_memory_size); | 102 | ci.size = static_cast<VkDeviceSize>(host_memory_size); |
| 103 | ci.usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | | 103 | ci.usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | |
| 104 | VK_BUFFER_USAGE_TRANSFER_DST_BIT; | 104 | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; |
| 105 | ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; | 105 | ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| 106 | ci.queueFamilyIndexCount = 0; | 106 | ci.queueFamilyIndexCount = 0; |
| 107 | ci.pQueueFamilyIndices = nullptr; | 107 | ci.pQueueFamilyIndices = nullptr; |