From c9d886c84e4102f7b9c464c704eecb61d37b3df4 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sun, 7 Jul 2019 20:36:42 -0300 Subject: gl_shader_decompiler: Implement gl_ViewportIndex and gl_Layer in vertex shaders This commit implements gl_ViewportIndex and gl_Layer in vertex and geometry shaders. In the case it's used in a vertex shader, it requires ARB_shader_viewport_layer_array. This extension is available on AMD and Nvidia devices (mesa and proprietary drivers), but not available on Intel on any platform. At the moment of writing this description I don't know if this is a hardware limitation or a driver limitation. In the case that ARB_shader_viewport_layer_array is not available, writes to these registers on a vertex shader are ignored, with the appropriate logging. --- src/video_core/engines/shader_bytecode.h | 2 +- src/video_core/renderer_opengl/gl_device.cpp | 2 + src/video_core/renderer_opengl/gl_device.h | 5 + src/video_core/renderer_opengl/gl_shader_cache.cpp | 7 +- .../renderer_opengl/gl_shader_decompiler.cpp | 104 +++++++++++++++------ .../renderer_opengl/gl_shader_decompiler.h | 1 + .../renderer_opengl/gl_shader_disk_cache.cpp | 10 ++ .../renderer_vulkan/vk_shader_decompiler.cpp | 14 ++- src/video_core/shader/shader_ir.cpp | 16 ++++ src/video_core/shader/shader_ir.h | 15 +++ 10 files changed, 136 insertions(+), 40 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 404d4f5aa..b92921d0f 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -78,7 +78,7 @@ union Attribute { constexpr explicit Attribute(u64 value) : value(value) {} enum class Index : u64 { - PointSize = 6, + LayerViewportPointSize = 6, Position = 7, Attribute_0 = 8, Attribute_31 = 39, diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index a48e14d2e..4b1f22f7a 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp @@ -26,6 +26,7 @@ Device::Device() { uniform_buffer_alignment = GetInteger(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT); max_vertex_attributes = GetInteger(GL_MAX_VERTEX_ATTRIBS); max_varyings = GetInteger(GL_MAX_VARYING_VECTORS); + has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array; has_variable_aoffi = TestVariableAoffi(); has_component_indexing_bug = TestComponentIndexingBug(); } @@ -34,6 +35,7 @@ Device::Device(std::nullptr_t) { uniform_buffer_alignment = 0; max_vertex_attributes = 16; max_varyings = 15; + has_vertex_viewport_layer = true; has_variable_aoffi = true; has_component_indexing_bug = false; } diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index 8c8c93760..7a3a0675b 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h @@ -26,6 +26,10 @@ public: return max_varyings; } + bool HasVertexViewportLayer() const { + return has_vertex_viewport_layer; + } + bool HasVariableAoffi() const { return has_variable_aoffi; } @@ -41,6 +45,7 @@ private: std::size_t uniform_buffer_alignment{}; u32 max_vertex_attributes{}; u32 max_varyings{}; + bool has_vertex_viewport_layer{}; bool has_variable_aoffi{}; bool has_component_indexing_bug{}; }; diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index f9b2b03a0..7fea92713 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -182,8 +182,11 @@ CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEn const auto texture_buffer_usage{variant.texture_buffer_usage}; std::string source = "#version 430 core\n" - "#extension GL_ARB_separate_shader_objects : enable\n\n"; - source += fmt::format("#define EMULATION_UBO_BINDING {}\n", base_bindings.cbuf++); + "#extension GL_ARB_separate_shader_objects : enable\n"; + if (entries.shader_viewport_layer_array) { + source += "#extension GL_ARB_shader_viewport_layer_array : enable\n"; + } + source += fmt::format("\n#define EMULATION_UBO_BINDING {}\n", base_bindings.cbuf++); for (const auto& cbuf : entries.const_buffers) { source += diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 5f2f1510c..a4451dd2f 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -14,6 +14,7 @@ #include "common/alignment.h" #include "common/assert.h" #include "common/common_types.h" +#include "common/logging/log.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/renderer_opengl/gl_device.h" #include "video_core/renderer_opengl/gl_rasterizer.h" @@ -244,6 +245,8 @@ public: usage.is_read, usage.is_written); } entries.clip_distances = ir.GetClipDistances(); + entries.shader_viewport_layer_array = + stage == ShaderStage::Vertex && (ir.UsesLayer() || ir.UsesPointSize()); entries.shader_length = ir.GetLength(); return entries; } @@ -280,22 +283,34 @@ private: } void DeclareVertexRedeclarations() { - bool clip_distances_declared = false; - code.AddLine("out gl_PerVertex {{"); ++code.scope; code.AddLine("vec4 gl_Position;"); - for (const auto o : ir.GetOutputAttributes()) { - if (o == Attribute::Index::PointSize) - code.AddLine("float gl_PointSize;"); - if (!clip_distances_declared && (o == Attribute::Index::ClipDistances0123 || - o == Attribute::Index::ClipDistances4567)) { + for (const auto attribute : ir.GetOutputAttributes()) { + if (attribute == Attribute::Index::ClipDistances0123 || + attribute == Attribute::Index::ClipDistances4567) { code.AddLine("float gl_ClipDistance[];"); - clip_distances_declared = true; + break; } } + if (stage != ShaderStage::Vertex || device.HasVertexViewportLayer()) { + if (ir.UsesLayer()) { + code.AddLine("int gl_Layer;"); + } + if (ir.UsesViewportIndex()) { + code.AddLine("int gl_ViewportIndex;"); + } + } else if (stage == ShaderStage::Vertex && !device.HasVertexViewportLayer()) { + LOG_ERROR( + Render_OpenGL, + "GL_ARB_shader_viewport_layer_array is not available and its required by a shader"); + } + + if (ir.UsesPointSize()) { + code.AddLine("int gl_PointSize;"); + } --code.scope; code.AddLine("}};"); @@ -803,6 +818,45 @@ private: return CastOperand(VisitOperand(operation, operand_index), type); } + std::optional> GetOutputAttribute(const AbufNode* abuf) { + switch (const auto attribute = abuf->GetIndex()) { + case Attribute::Index::Position: + return std::make_pair("gl_Position"s + GetSwizzle(abuf->GetElement()), false); + case Attribute::Index::LayerViewportPointSize: + switch (abuf->GetElement()) { + case 0: + UNIMPLEMENTED(); + return {}; + case 1: + if (stage == ShaderStage::Vertex && !device.HasVertexViewportLayer()) { + return {}; + } + return std::make_pair("gl_Layer", true); + case 2: + if (stage == ShaderStage::Vertex && !device.HasVertexViewportLayer()) { + return {}; + } + return std::make_pair("gl_ViewportIndex", true); + case 3: + UNIMPLEMENTED_MSG("Requires some state changes for gl_PointSize to work in shader"); + return std::make_pair("gl_PointSize", false); + } + return {}; + case Attribute::Index::ClipDistances0123: + return std::make_pair(fmt::format("gl_ClipDistance[{}]", abuf->GetElement()), false); + case Attribute::Index::ClipDistances4567: + return std::make_pair(fmt::format("gl_ClipDistance[{}]", abuf->GetElement() + 4), + false); + default: + if (IsGenericAttribute(attribute)) { + return std::make_pair( + GetOutputAttribute(attribute) + GetSwizzle(abuf->GetElement()), false); + } + UNIMPLEMENTED_MSG("Unhandled output attribute: {}", static_cast(attribute)); + return {}; + } + } + std::string CastOperand(const std::string& value, Type type) const { switch (type) { case Type::Bool: @@ -999,6 +1053,8 @@ private: const Node& src = operation[1]; std::string target; + bool is_integer = false; + if (const auto gpr = std::get_if(&*dest)) { if (gpr->GetIndex() == Register::ZeroIndex) { // Writing to Register::ZeroIndex is a no op @@ -1007,26 +1063,12 @@ private: target = GetRegister(gpr->GetIndex()); } else if (const auto abuf = std::get_if(&*dest)) { UNIMPLEMENTED_IF(abuf->IsPhysicalBuffer()); - - target = [&]() -> std::string { - switch (const auto attribute = abuf->GetIndex(); abuf->GetIndex()) { - case Attribute::Index::Position: - return "gl_Position"s + GetSwizzle(abuf->GetElement()); - case Attribute::Index::PointSize: - return "gl_PointSize"; - case Attribute::Index::ClipDistances0123: - return fmt::format("gl_ClipDistance[{}]", abuf->GetElement()); - case Attribute::Index::ClipDistances4567: - return fmt::format("gl_ClipDistance[{}]", abuf->GetElement() + 4); - default: - if (IsGenericAttribute(attribute)) { - return GetOutputAttribute(attribute) + GetSwizzle(abuf->GetElement()); - } - UNIMPLEMENTED_MSG("Unhandled output attribute: {}", - static_cast(attribute)); - return "0"; - } - }(); + const auto result = GetOutputAttribute(abuf); + if (!result) { + return {}; + } + target = result->first; + is_integer = result->second; } else if (const auto lmem = std::get_if(&*dest)) { target = fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress())); } else if (const auto gmem = std::get_if(&*dest)) { @@ -1038,7 +1080,11 @@ private: UNREACHABLE_MSG("Assign called without a proper target"); } - code.AddLine("{} = {};", target, Visit(src)); + if (is_integer) { + code.AddLine("{} = ftoi({});", target, Visit(src)); + } else { + code.AddLine("{} = {};", target, Visit(src)); + } return {}; } diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.h b/src/video_core/renderer_opengl/gl_shader_decompiler.h index 14d11c7fc..02586736d 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.h +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h @@ -78,6 +78,7 @@ struct ShaderEntries { std::vector images; std::vector global_memory_entries; std::array clip_distances{}; + bool shader_viewport_layer_array{}; std::size_t shader_length{}; }; diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp index 10688397b..7893d1e26 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp @@ -373,6 +373,12 @@ std::optional ShaderDiskCacheOpenGL::LoadDecompiledEn } } + bool shader_viewport_layer_array{}; + if (!LoadObjectFromPrecompiled(shader_viewport_layer_array)) { + return {}; + } + entry.entries.shader_viewport_layer_array = shader_viewport_layer_array; + u64 shader_length{}; if (!LoadObjectFromPrecompiled(shader_length)) { return {}; @@ -445,6 +451,10 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std: } } + if (!SaveObjectToPrecompiled(entries.shader_viewport_layer_array)) { + return false; + } + if (!SaveObjectToPrecompiled(static_cast(entries.shader_length))) { return false; } diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 97ce214b1..6071c6d99 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp @@ -430,20 +430,17 @@ private: instance_index = DeclareBuiltIn(spv::BuiltIn::InstanceIndex, spv::StorageClass::Input, t_in_uint, "instance_index"); - bool is_point_size_declared = false; bool is_clip_distances_declared = false; for (const auto index : ir.GetOutputAttributes()) { - if (index == Attribute::Index::PointSize) { - is_point_size_declared = true; - } else if (index == Attribute::Index::ClipDistances0123 || - index == Attribute::Index::ClipDistances4567) { + if (index == Attribute::Index::ClipDistances0123 || + index == Attribute::Index::ClipDistances4567) { is_clip_distances_declared = true; } } std::vector members; members.push_back(t_float4); - if (is_point_size_declared) { + if (ir.UsesPointSize()) { members.push_back(t_float); } if (is_clip_distances_declared) { @@ -466,7 +463,7 @@ private: position_index = MemberDecorateBuiltIn(spv::BuiltIn::Position, "position", true); point_size_index = - MemberDecorateBuiltIn(spv::BuiltIn::PointSize, "point_size", is_point_size_declared); + MemberDecorateBuiltIn(spv::BuiltIn::PointSize, "point_size", ir.UsesPointSize()); clip_distances_index = MemberDecorateBuiltIn(spv::BuiltIn::ClipDistance, "clip_distances", is_clip_distances_declared); @@ -712,7 +709,8 @@ private: case Attribute::Index::Position: return AccessElement(t_out_float, per_vertex, position_index, abuf->GetElement()); - case Attribute::Index::PointSize: + case Attribute::Index::LayerViewportPointSize: + UNIMPLEMENTED_IF(abuf->GetElement() != 3); return AccessElement(t_out_float, per_vertex, point_size_index); case Attribute::Index::ClipDistances0123: return AccessElement(t_out_float, per_vertex, clip_distances_index, diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp index 11b545cca..fd80dd116 100644 --- a/src/video_core/shader/shader_ir.cpp +++ b/src/video_core/shader/shader_ir.cpp @@ -89,6 +89,22 @@ Node ShaderIR::GetPhysicalInputAttribute(Tegra::Shader::Register physical_addres } Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buffer) { + if (index == Attribute::Index::LayerViewportPointSize) { + switch (element) { + case 0: + UNIMPLEMENTED(); + break; + case 1: + uses_layer = true; + break; + case 2: + uses_viewport_index = true; + break; + case 3: + uses_point_size = true; + break; + } + } if (index == Attribute::Index::ClipDistances0123 || index == Attribute::Index::ClipDistances4567) { const auto clip_index = diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index e22548208..a656761ea 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h @@ -121,6 +121,18 @@ public: return static_cast(coverage_end * sizeof(u64)); } + bool UsesLayer() const { + return uses_layer; + } + + bool UsesViewportIndex() const { + return uses_viewport_index; + } + + bool UsesPointSize() const { + return uses_point_size; + } + bool HasPhysicalAttributes() const { return uses_physical_attributes; } @@ -343,6 +355,9 @@ private: std::set used_images; std::array used_clip_distances{}; std::map used_global_memory; + bool uses_layer{}; + bool uses_viewport_index{}; + bool uses_point_size{}; bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes Tegra::Shader::Header header; -- cgit v1.2.3 From aca40de224994ba6bc7547224a4f8450a840fde3 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 11 Jul 2019 04:24:57 -0300 Subject: gl_shader_decompiler: Fix conditional usage of GL_ARB_shader_viewport_layer_array --- src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index a4451dd2f..d0f579323 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -246,7 +246,7 @@ public: } entries.clip_distances = ir.GetClipDistances(); entries.shader_viewport_layer_array = - stage == ShaderStage::Vertex && (ir.UsesLayer() || ir.UsesPointSize()); + stage == ShaderStage::Vertex && (ir.UsesLayer() || ir.UsesViewportIndex()); entries.shader_length = ir.GetLength(); return entries; } @@ -302,7 +302,8 @@ private: if (ir.UsesViewportIndex()) { code.AddLine("int gl_ViewportIndex;"); } - } else if (stage == ShaderStage::Vertex && !device.HasVertexViewportLayer()) { + } else if ((ir.UsesLayer() || ir.UsesViewportIndex()) && stage == ShaderStage::Vertex && + !device.HasVertexViewportLayer()) { LOG_ERROR( Render_OpenGL, "GL_ARB_shader_viewport_layer_array is not available and its required by a shader"); -- cgit v1.2.3 From 0eb0c24269677cda2ba8c5be216a3c87520f2e70 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 11 Jul 2019 16:10:59 -0300 Subject: gl_shader_decompiler: Fix gl_PointSize redeclaration --- src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/video_core') diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index d0f579323..3408e6c41 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -310,7 +310,7 @@ private: } if (ir.UsesPointSize()) { - code.AddLine("int gl_PointSize;"); + code.AddLine("float gl_PointSize;"); } --code.scope; -- cgit v1.2.3