diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 85d309d9b..b1e640dd1 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -51,6 +51,7 @@ public: static constexpr std::size_t NumCBData = 16; static constexpr std::size_t NumVertexArrays = 32; static constexpr std::size_t NumVertexAttributes = 32; + static constexpr std::size_t NumVaryings = 31; static constexpr std::size_t NumTextureSamplers = 32; static constexpr std::size_t NumClipDistances = 8; static constexpr std::size_t MaxShaderProgram = 6; diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index b6d9e0ddb..38497678a 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp @@ -21,9 +21,18 @@ T GetInteger(GLenum pname) { 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_variable_aoffi = TestVariableAoffi(); } +Device::Device(std::nullptr_t) { + uniform_buffer_alignment = 0; + max_vertex_attributes = 16; + max_varyings = 15; + has_variable_aoffi = true; +} + bool Device::TestVariableAoffi() { const GLchar* AOFFI_TEST = R"(#version 430 core uniform sampler2D tex; diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index 78ff5ee58..de8490682 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h @@ -5,17 +5,27 @@ #pragma once #include +#include "common/common_types.h" namespace OpenGL { class Device { public: - Device(); + explicit Device(); + explicit Device(std::nullptr_t); std::size_t GetUniformBufferAlignment() const { return uniform_buffer_alignment; } + u32 GetMaxVertexAttributes() const { + return max_vertex_attributes; + } + + u32 GetMaxVaryings() const { + return max_varyings; + } + bool HasVariableAoffi() const { return has_variable_aoffi; } @@ -24,6 +34,8 @@ private: static bool TestVariableAoffi(); std::size_t uniform_buffer_alignment{}; + u32 max_vertex_attributes{}; + u32 max_varyings{}; bool has_variable_aoffi{}; }; diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 33c0edca9..8df91a4c6 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -316,55 +316,85 @@ private: } void DeclareInputAttributes() { + if (ir.HasPhysicalAttributes()) { + const u32 num_inputs{stage == ShaderStage::Vertex ? GetNumPhysicalAttributes() + : GetNumPhysicalVaryings()}; + for (u32 i = 0; i < num_inputs; ++i) { + constexpr auto generic_base{static_cast(Attribute::Index::Attribute_0)}; + const auto index{static_cast(generic_base + i)}; + DeclareInputAttribute(index); + } + code.AddNewLine(); + return; + } + const auto& attributes = ir.GetInputAttributes(); for (const auto index : attributes) { if (index < Attribute::Index::Attribute_0 || index > Attribute::Index::Attribute_31) { // Skip when it's not a generic attribute continue; } - - // TODO(bunnei): Use proper number of elements for these - u32 idx = static_cast(index) - static_cast(Attribute::Index::Attribute_0); - if (stage != ShaderStage::Vertex) { - // If inputs are varyings, add an offset - idx += GENERIC_VARYING_START_LOCATION; - } - - std::string attr = GetInputAttribute(index); - if (stage == ShaderStage::Geometry) { - attr = "gs_" + attr + "[]"; - } - std::string suffix; - if (stage == ShaderStage::Fragment) { - const auto input_mode = - header.ps.GetAttributeUse(idx - GENERIC_VARYING_START_LOCATION); - suffix = GetInputFlags(input_mode); - } - code.AddLine("layout (location = " + std::to_string(idx) + ") " + suffix + "in vec4 " + - attr + ';'); + DeclareInputAttribute(index); } if (!attributes.empty()) code.AddNewLine(); } + void DeclareInputAttribute(Attribute::Index index) { + const u32 generic_index{static_cast(index) - + static_cast(Attribute::Index::Attribute_0)}; + + std::string name{GetInputAttribute(index)}; + if (stage == ShaderStage::Geometry) { + name = "gs_" + name + "[]"; + } + std::string suffix; + if (stage == ShaderStage::Fragment) { + const auto input_mode{header.ps.GetAttributeUse(generic_index)}; + suffix = GetInputFlags(input_mode); + } + + u32 location = generic_index; + if (stage != ShaderStage::Vertex) { + // If inputs are varyings, add an offset + location += GENERIC_VARYING_START_LOCATION; + } + + code.AddLine("layout (location = " + std::to_string(location) + ") " + suffix + "in vec4 " + + name + ';'); + } + void DeclareOutputAttributes() { + if (ir.HasPhysicalAttributes()) { + for (u32 i = 0; i < GetNumPhysicalVaryings(); ++i) { + constexpr auto generic_base{static_cast(Attribute::Index::Attribute_0)}; + const auto index{static_cast(generic_base + i)}; + DeclareOutputAttribute(index); + } + code.AddNewLine(); + return; + } + const auto& attributes = ir.GetOutputAttributes(); for (const auto index : attributes) { if (index < Attribute::Index::Attribute_0 || index > Attribute::Index::Attribute_31) { // Skip when it's not a generic attribute continue; } - // TODO(bunnei): Use proper number of elements for these - const auto idx = static_cast(index) - - static_cast(Attribute::Index::Attribute_0) + - GENERIC_VARYING_START_LOCATION; - code.AddLine("layout (location = " + std::to_string(idx) + ") out vec4 " + - GetOutputAttribute(index) + ';'); + DeclareOutputAttribute(index); } if (!attributes.empty()) code.AddNewLine(); } + void DeclareOutputAttribute(Attribute::Index index) { + const auto location{static_cast(index) - + static_cast(Attribute::Index::Attribute_0) + + GENERIC_VARYING_START_LOCATION}; + code.AddLine("layout (location = " + std::to_string(location) + ") out vec4 " + + GetOutputAttribute(index) + ';'); + } + void DeclareConstantBuffers() { for (const auto& entry : ir.GetConstantBuffers()) { const auto [index, size] = entry; @@ -1650,6 +1680,15 @@ private: return name + '_' + std::to_string(index) + '_' + suffix; } + u32 GetNumPhysicalAttributes() const { + return std::min(device.GetMaxVertexAttributes(), Maxwell::NumVertexAttributes); + } + + u32 GetNumPhysicalVaryings() const { + return std::min(device.GetMaxVaryings() - GENERIC_VARYING_START_LOCATION, + Maxwell::NumVaryings); + } + const Device& device; const ShaderIR& ir; const ShaderStage stage;