summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2020-02-23 02:35:16 -0300
committerGravatar ReinUsesLisp2020-02-24 01:26:07 -0300
commit1e9213632a709716e20d2b8690f8fe31654496ba (patch)
treebf8b4148aa9ec6cce99764a40e9558080ca65a09 /src
parentshader: Simplify indexed sampler usages (diff)
downloadyuzu-1e9213632a709716e20d2b8690f8fe31654496ba.tar.gz
yuzu-1e9213632a709716e20d2b8690f8fe31654496ba.tar.xz
yuzu-1e9213632a709716e20d2b8690f8fe31654496ba.zip
vk_shader_decompiler: Implement indexed textures
Implement accessing textures through an index. It uses the same interface as OpenGL, the main difference is that Vulkan bindings are forced to be arrayed (the binding index doesn't change for stacked textures in SPIR-V).
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp99
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp21
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp26
6 files changed, 99 insertions, 54 deletions
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
index 9d5b8de7a..60f57d83e 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
@@ -73,7 +73,7 @@ UniqueDescriptorUpdateTemplate VKComputePipeline::CreateDescriptorUpdateTemplate
73 std::vector<vk::DescriptorUpdateTemplateEntry> template_entries; 73 std::vector<vk::DescriptorUpdateTemplateEntry> template_entries;
74 u32 binding = 0; 74 u32 binding = 0;
75 u32 offset = 0; 75 u32 offset = 0;
76 FillDescriptorUpdateTemplateEntries(device, entries, binding, offset, template_entries); 76 FillDescriptorUpdateTemplateEntries(entries, binding, offset, template_entries);
77 if (template_entries.empty()) { 77 if (template_entries.empty()) {
78 // If the shader doesn't use descriptor sets, skip template creation. 78 // If the shader doesn't use descriptor sets, skip template creation.
79 return UniqueDescriptorUpdateTemplate{}; 79 return UniqueDescriptorUpdateTemplate{};
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index b155dfb49..6a02403c1 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -97,8 +97,7 @@ UniqueDescriptorUpdateTemplate VKGraphicsPipeline::CreateDescriptorUpdateTemplat
97 u32 offset = 0; 97 u32 offset = 0;
98 for (const auto& stage : program) { 98 for (const auto& stage : program) {
99 if (stage) { 99 if (stage) {
100 FillDescriptorUpdateTemplateEntries(device, stage->entries, binding, offset, 100 FillDescriptorUpdateTemplateEntries(stage->entries, binding, offset, template_entries);
101 template_entries);
102 } 101 }
103 } 102 }
104 if (template_entries.empty()) { 103 if (template_entries.empty()) {
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 7ddf7d3ee..696e4b291 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -36,6 +36,13 @@ using Tegra::Engines::ShaderType;
36 36
37namespace { 37namespace {
38 38
39// C++20's using enum
40constexpr auto eUniformBuffer = vk::DescriptorType::eUniformBuffer;
41constexpr auto eStorageBuffer = vk::DescriptorType::eStorageBuffer;
42constexpr auto eUniformTexelBuffer = vk::DescriptorType::eUniformTexelBuffer;
43constexpr auto eCombinedImageSampler = vk::DescriptorType::eCombinedImageSampler;
44constexpr auto eStorageImage = vk::DescriptorType::eStorageImage;
45
39constexpr VideoCommon::Shader::CompilerSettings compiler_settings{ 46constexpr VideoCommon::Shader::CompilerSettings compiler_settings{
40 VideoCommon::Shader::CompileDepth::FullDecompile}; 47 VideoCommon::Shader::CompileDepth::FullDecompile};
41 48
@@ -119,23 +126,32 @@ ShaderType GetShaderType(Maxwell::ShaderProgram program) {
119 } 126 }
120} 127}
121 128
129template <vk::DescriptorType descriptor_type, class Container>
130void AddBindings(std::vector<vk::DescriptorSetLayoutBinding>& bindings, u32& binding,
131 vk::ShaderStageFlags stage_flags, const Container& container) {
132 const u32 num_entries = static_cast<u32>(std::size(container));
133 for (std::size_t i = 0; i < num_entries; ++i) {
134 u32 count = 1;
135 if constexpr (descriptor_type == eCombinedImageSampler) {
136 // Combined image samplers can be arrayed.
137 count = container[i].Size();
138 }
139 bindings.emplace_back(binding++, descriptor_type, count, stage_flags, nullptr);
140 }
141}
142
122u32 FillDescriptorLayout(const ShaderEntries& entries, 143u32 FillDescriptorLayout(const ShaderEntries& entries,
123 std::vector<vk::DescriptorSetLayoutBinding>& bindings, 144 std::vector<vk::DescriptorSetLayoutBinding>& bindings,
124 Maxwell::ShaderProgram program_type, u32 base_binding) { 145 Maxwell::ShaderProgram program_type, u32 base_binding) {
125 const ShaderType stage = GetStageFromProgram(program_type); 146 const ShaderType stage = GetStageFromProgram(program_type);
126 const vk::ShaderStageFlags stage_flags = MaxwellToVK::ShaderStage(stage); 147 const vk::ShaderStageFlags flags = MaxwellToVK::ShaderStage(stage);
127 148
128 u32 binding = base_binding; 149 u32 binding = base_binding;
129 const auto AddBindings = [&](vk::DescriptorType descriptor_type, std::size_t num_entries) { 150 AddBindings<eUniformBuffer>(bindings, binding, flags, entries.const_buffers);
130 for (std::size_t i = 0; i < num_entries; ++i) { 151 AddBindings<eStorageBuffer>(bindings, binding, flags, entries.global_buffers);
131 bindings.emplace_back(binding++, descriptor_type, 1, stage_flags, nullptr); 152 AddBindings<eUniformTexelBuffer>(bindings, binding, flags, entries.texel_buffers);
132 } 153 AddBindings<eCombinedImageSampler>(bindings, binding, flags, entries.samplers);
133 }; 154 AddBindings<eStorageImage>(bindings, binding, flags, entries.images);
134 AddBindings(vk::DescriptorType::eUniformBuffer, entries.const_buffers.size());
135 AddBindings(vk::DescriptorType::eStorageBuffer, entries.global_buffers.size());
136 AddBindings(vk::DescriptorType::eUniformTexelBuffer, entries.texel_buffers.size());
137 AddBindings(vk::DescriptorType::eCombinedImageSampler, entries.samplers.size());
138 AddBindings(vk::DescriptorType::eStorageImage, entries.images.size());
139 return binding; 155 return binding;
140} 156}
141 157
@@ -361,32 +377,45 @@ VKPipelineCache::DecompileShaders(const GraphicsPipelineCacheKey& key) {
361 return {std::move(program), std::move(bindings)}; 377 return {std::move(program), std::move(bindings)};
362} 378}
363 379
364void FillDescriptorUpdateTemplateEntries( 380template <vk::DescriptorType descriptor_type, class Container>
365 const VKDevice& device, const ShaderEntries& entries, u32& binding, u32& offset, 381void AddEntry(std::vector<vk::DescriptorUpdateTemplateEntry>& template_entries, u32& binding,
366 std::vector<vk::DescriptorUpdateTemplateEntry>& template_entries) { 382 u32& offset, const Container& container) {
367 static constexpr auto entry_size = static_cast<u32>(sizeof(DescriptorUpdateEntry)); 383 static constexpr u32 entry_size = static_cast<u32>(sizeof(DescriptorUpdateEntry));
368 const auto AddEntry = [&](vk::DescriptorType descriptor_type, std::size_t count_) { 384 const u32 count = static_cast<u32>(std::size(container));
369 const u32 count = static_cast<u32>(count_); 385
370 if (descriptor_type == vk::DescriptorType::eUniformTexelBuffer && 386 if constexpr (descriptor_type == eCombinedImageSampler) {
371 device.GetDriverID() == vk::DriverIdKHR::eNvidiaProprietary) { 387 for (u32 i = 0; i < count; ++i) {
372 // Nvidia has a bug where updating multiple uniform texels at once causes the driver to 388 const u32 num_samplers = container[i].Size();
373 // crash. 389 template_entries.emplace_back(binding, 0, num_samplers, descriptor_type, offset,
374 for (u32 i = 0; i < count; ++i) { 390 entry_size);
375 template_entries.emplace_back(binding + i, 0, 1, descriptor_type, 391 ++binding;
376 offset + i * entry_size, entry_size); 392 offset += num_samplers * entry_size;
377 }
378 } else if (count != 0) {
379 template_entries.emplace_back(binding, 0, count, descriptor_type, offset, entry_size);
380 } 393 }
381 offset += count * entry_size; 394 return;
382 binding += count; 395 }
383 };
384 396
385 AddEntry(vk::DescriptorType::eUniformBuffer, entries.const_buffers.size()); 397 if constexpr (descriptor_type == eUniformTexelBuffer) {
386 AddEntry(vk::DescriptorType::eStorageBuffer, entries.global_buffers.size()); 398 // Nvidia has a bug where updating multiple uniform texels at once causes the driver to
387 AddEntry(vk::DescriptorType::eUniformTexelBuffer, entries.texel_buffers.size()); 399 // crash.
388 AddEntry(vk::DescriptorType::eCombinedImageSampler, entries.samplers.size()); 400 for (u32 i = 0; i < count; ++i) {
389 AddEntry(vk::DescriptorType::eStorageImage, entries.images.size()); 401 template_entries.emplace_back(binding + i, 0, 1, descriptor_type,
402 offset + i * entry_size, entry_size);
403 }
404 } else if (count > 0) {
405 template_entries.emplace_back(binding, 0, count, descriptor_type, offset, entry_size);
406 }
407 offset += count * entry_size;
408 binding += count;
409}
410
411void FillDescriptorUpdateTemplateEntries(
412 const ShaderEntries& entries, u32& binding, u32& offset,
413 std::vector<vk::DescriptorUpdateTemplateEntry>& template_entries) {
414 AddEntry<eUniformBuffer>(template_entries, offset, binding, entries.const_buffers);
415 AddEntry<eStorageBuffer>(template_entries, offset, binding, entries.global_buffers);
416 AddEntry<eUniformTexelBuffer>(template_entries, offset, binding, entries.texel_buffers);
417 AddEntry<eCombinedImageSampler>(template_entries, offset, binding, entries.samplers);
418 AddEntry<eStorageImage>(template_entries, offset, binding, entries.images);
390} 419}
391 420
392} // namespace Vulkan 421} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
index 8678fc9c3..92a670cc7 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
@@ -194,7 +194,7 @@ private:
194}; 194};
195 195
196void FillDescriptorUpdateTemplateEntries( 196void FillDescriptorUpdateTemplateEntries(
197 const VKDevice& device, const ShaderEntries& entries, u32& binding, u32& offset, 197 const ShaderEntries& entries, u32& binding, u32& offset,
198 std::vector<vk::DescriptorUpdateTemplateEntry>& template_entries); 198 std::vector<vk::DescriptorUpdateTemplateEntry>& template_entries);
199 199
200} // namespace Vulkan 200} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 31c078f6a..ad837dd4a 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -105,17 +105,20 @@ void TransitionImages(const std::vector<ImageView>& views, vk::PipelineStageFlag
105 105
106template <typename Engine, typename Entry> 106template <typename Engine, typename Entry>
107Tegra::Texture::FullTextureInfo GetTextureInfo(const Engine& engine, const Entry& entry, 107Tegra::Texture::FullTextureInfo GetTextureInfo(const Engine& engine, const Entry& entry,
108 std::size_t stage) { 108 std::size_t stage, std::size_t index = 0) {
109 const auto stage_type = static_cast<Tegra::Engines::ShaderType>(stage); 109 const auto stage_type = static_cast<Tegra::Engines::ShaderType>(stage);
110 if (entry.IsBindless()) { 110 if (entry.IsBindless()) {
111 const Tegra::Texture::TextureHandle tex_handle = 111 const Tegra::Texture::TextureHandle tex_handle =
112 engine.AccessConstBuffer32(stage_type, entry.GetBuffer(), entry.GetOffset()); 112 engine.AccessConstBuffer32(stage_type, entry.GetBuffer(), entry.GetOffset());
113 return engine.GetTextureInfo(tex_handle); 113 return engine.GetTextureInfo(tex_handle);
114 } 114 }
115 const auto& gpu_profile = engine.AccessGuestDriverProfile();
116 const u32 entry_offset = static_cast<u32>(index * gpu_profile.GetTextureHandlerSize());
117 const u32 offset = entry.GetOffset() + entry_offset;
115 if constexpr (std::is_same_v<Engine, Tegra::Engines::Maxwell3D>) { 118 if constexpr (std::is_same_v<Engine, Tegra::Engines::Maxwell3D>) {
116 return engine.GetStageTexture(stage_type, entry.GetOffset()); 119 return engine.GetStageTexture(stage_type, offset);
117 } else { 120 } else {
118 return engine.GetTexture(entry.GetOffset()); 121 return engine.GetTexture(offset);
119 } 122 }
120} 123}
121 124
@@ -835,8 +838,10 @@ void RasterizerVulkan::SetupGraphicsTextures(const ShaderEntries& entries, std::
835 MICROPROFILE_SCOPE(Vulkan_Textures); 838 MICROPROFILE_SCOPE(Vulkan_Textures);
836 const auto& gpu = system.GPU().Maxwell3D(); 839 const auto& gpu = system.GPU().Maxwell3D();
837 for (const auto& entry : entries.samplers) { 840 for (const auto& entry : entries.samplers) {
838 const auto texture = GetTextureInfo(gpu, entry, stage); 841 for (std::size_t i = 0; i < entry.Size(); ++i) {
839 SetupTexture(texture, entry); 842 const auto texture = GetTextureInfo(gpu, entry, stage, i);
843 SetupTexture(texture, entry);
844 }
840 } 845 }
841} 846}
842 847
@@ -885,8 +890,10 @@ void RasterizerVulkan::SetupComputeTextures(const ShaderEntries& entries) {
885 MICROPROFILE_SCOPE(Vulkan_Textures); 890 MICROPROFILE_SCOPE(Vulkan_Textures);
886 const auto& gpu = system.GPU().KeplerCompute(); 891 const auto& gpu = system.GPU().KeplerCompute();
887 for (const auto& entry : entries.samplers) { 892 for (const auto& entry : entries.samplers) {
888 const auto texture = GetTextureInfo(gpu, entry, ComputeShaderIndex); 893 for (std::size_t i = 0; i < entry.Size(); ++i) {
889 SetupTexture(texture, entry); 894 const auto texture = GetTextureInfo(gpu, entry, ComputeShaderIndex, i);
895 SetupTexture(texture, entry);
896 }
890 } 897 }
891} 898}
892 899
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index 2da622d15..9841f0dd1 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -69,8 +69,9 @@ struct TexelBuffer {
69 69
70struct SampledImage { 70struct SampledImage {
71 Id image_type{}; 71 Id image_type{};
72 Id sampled_image_type{}; 72 Id sampler_type{};
73 Id sampler{}; 73 Id sampler_pointer_type{};
74 Id variable{};
74}; 75};
75 76
76struct StorageImage { 77struct StorageImage {
@@ -833,16 +834,20 @@ private:
833 constexpr int sampled = 1; 834 constexpr int sampled = 1;
834 constexpr auto format = spv::ImageFormat::Unknown; 835 constexpr auto format = spv::ImageFormat::Unknown;
835 const Id image_type = TypeImage(t_float, dim, depth, arrayed, ms, sampled, format); 836 const Id image_type = TypeImage(t_float, dim, depth, arrayed, ms, sampled, format);
836 const Id sampled_image_type = TypeSampledImage(image_type); 837 const Id sampler_type = TypeSampledImage(image_type);
837 const Id pointer_type = 838 const Id sampler_pointer_type =
838 TypePointer(spv::StorageClass::UniformConstant, sampled_image_type); 839 TypePointer(spv::StorageClass::UniformConstant, sampler_type);
840 const Id type = sampler.IsIndexed()
841 ? TypeArray(sampler_type, Constant(t_uint, sampler.Size()))
842 : sampler_type;
843 const Id pointer_type = TypePointer(spv::StorageClass::UniformConstant, type);
839 const Id id = OpVariable(pointer_type, spv::StorageClass::UniformConstant); 844 const Id id = OpVariable(pointer_type, spv::StorageClass::UniformConstant);
840 AddGlobalVariable(Name(id, fmt::format("sampler_{}", sampler.GetIndex()))); 845 AddGlobalVariable(Name(id, fmt::format("sampler_{}", sampler.GetIndex())));
841 Decorate(id, spv::Decoration::Binding, binding++); 846 Decorate(id, spv::Decoration::Binding, binding++);
842 Decorate(id, spv::Decoration::DescriptorSet, DESCRIPTOR_SET); 847 Decorate(id, spv::Decoration::DescriptorSet, DESCRIPTOR_SET);
843 848
844 sampled_images.emplace(sampler.GetIndex(), 849 sampled_images.emplace(sampler.GetIndex(), SampledImage{image_type, sampler_type,
845 SampledImage{image_type, sampled_image_type, id}); 850 sampler_pointer_type, id});
846 } 851 }
847 return binding; 852 return binding;
848 } 853 }
@@ -1525,7 +1530,12 @@ private:
1525 ASSERT(!meta.sampler.IsBuffer()); 1530 ASSERT(!meta.sampler.IsBuffer());
1526 1531
1527 const auto& entry = sampled_images.at(meta.sampler.GetIndex()); 1532 const auto& entry = sampled_images.at(meta.sampler.GetIndex());
1528 return OpLoad(entry.sampled_image_type, entry.sampler); 1533 Id sampler = entry.variable;
1534 if (meta.sampler.IsIndexed()) {
1535 const Id index = AsInt(Visit(meta.index));
1536 sampler = OpAccessChain(entry.sampler_pointer_type, sampler, index);
1537 }
1538 return OpLoad(entry.sampler_type, sampler);
1529 } 1539 }
1530 1540
1531 Id GetTextureImage(Operation operation) { 1541 Id GetTextureImage(Operation operation) {