diff options
-rw-r--r-- | src/video_core/engines/shader_bytecode.h | 12 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 133 |
2 files changed, 98 insertions, 47 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index a7daea766..d2388673e 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -76,6 +76,7 @@ union Attribute { Position = 7, Attribute_0 = 8, Attribute_31 = 39, + PointCoord = 46, // This attribute contains a tuple of (~, ~, InstanceId, VertexId) when inside a vertex // shader, and a tuple of (TessCoord.x, TessCoord.y, TessCoord.z, ~) when inside a Tess Eval // shader. @@ -246,6 +247,17 @@ enum class TextureType : u64 { enum class IpaInterpMode : u64 { Linear = 0, Perspective = 1, Flat = 2, Sc = 3 }; enum class IpaSampleMode : u64 { Default = 0, Centroid = 1, Offset = 2 }; +struct IpaMode { + IpaInterpMode interpolation_mode; + IpaSampleMode sampling_mode; + inline bool operator==(const IpaMode& a) { + return (a.interpolation_mode == interpolation_mode) && (a.sampling_mode == sampling_mode); + } + inline bool operator!=(const IpaMode& a) { + return !((*this) == a); + } +}; + union Instruction { Instruction& operator=(const Instruction& instr) { value = instr.value; diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index d3e8f5078..781ddb073 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -247,6 +247,7 @@ public: const Maxwell3D::Regs::ShaderStage& stage, const std::string& suffix) : shader{shader}, declarations{declarations}, stage{stage}, suffix{suffix} { BuildRegisterList(); + BuildInputList(); } /** @@ -343,9 +344,10 @@ public: * @param elem The element to use for the operation. * @param attribute The input attribute to use as the source value. */ - void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute) { + void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute, + const Tegra::Shader::IpaMode& input_mode) { std::string dest = GetRegisterAsFloat(reg); - std::string src = GetInputAttribute(attribute) + GetSwizzle(elem); + std::string src = GetInputAttribute(attribute, input_mode) + GetSwizzle(elem); shader.AddLine(dest + " = " + src + ';'); } @@ -412,12 +414,13 @@ public: } declarations.AddNewLine(); - for (const auto& index : declr_input_attribute) { + for (const auto element : declr_input_attribute) { // TODO(bunnei): Use proper number of elements for these - declarations.AddLine("layout(location = " + - std::to_string(static_cast<u32>(index) - - static_cast<u32>(Attribute::Index::Attribute_0)) + - ") in vec4 " + GetInputAttribute(index) + ';'); + u32 idx = + static_cast<u32>(element.first) - static_cast<u32>(Attribute::Index::Attribute_0); + declarations.AddLine("layout(location = " + std::to_string(idx) + ")" + + GetInputFlags(element.first) + "in vec4 " + + GetInputAttribute(element.first, element.second) + ';'); } declarations.AddNewLine(); @@ -532,11 +535,24 @@ private: } } + void BuildInputList() { + const u32 size = static_cast<u32>(Attribute::Index::Attribute_31) - + static_cast<u32>(Attribute::Index::Attribute_0) + 1; + declr_input_attribute.reserve(size); + } + /// Generates code representing an input attribute register. - std::string GetInputAttribute(Attribute::Index attribute) { + std::string GetInputAttribute(Attribute::Index attribute, + const Tegra::Shader::IpaMode& input_mode) { switch (attribute) { case Attribute::Index::Position: - return "position"; + if (stage != Maxwell3D::Regs::ShaderStage::Fragment) { + return "position"; + } else { + return "vec4(gl_FragCoord.x, gl_FragCoord.y, gl_FragCoord.z, 1.0)"; + } + case Attribute::Index::PointCoord: + return "vec4(gl_PointCoord.x, gl_PointCoord.y, 0, 0)"; case Attribute::Index::TessCoordInstanceIDVertexID: // TODO(Subv): Find out what the values are for the first two elements when inside a // vertex shader, and what's the value of the fourth element when inside a Tess Eval @@ -552,7 +568,14 @@ private: static_cast<u32>(Attribute::Index::Attribute_0)}; if (attribute >= Attribute::Index::Attribute_0 && attribute <= Attribute::Index::Attribute_31) { - declr_input_attribute.insert(attribute); + if (declr_input_attribute.count(attribute) == 0) { + declr_input_attribute[attribute] = input_mode; + } else { + if (declr_input_attribute[attribute] != input_mode) { + LOG_CRITICAL(HW_GPU, "Same Input multiple input modes"); + UNREACHABLE(); + } + } return "input_attribute_" + std::to_string(index); } @@ -563,6 +586,49 @@ private: return "vec4(0, 0, 0, 0)"; } + std::string GetInputFlags(const Attribute::Index attribute) { + const Tegra::Shader::IpaSampleMode sample_mode = + declr_input_attribute[attribute].sampling_mode; + const Tegra::Shader::IpaInterpMode interp_mode = + declr_input_attribute[attribute].interpolation_mode; + std::string out; + switch (interp_mode) { + case Tegra::Shader::IpaInterpMode::Flat: { + out += "flat "; + break; + } + case Tegra::Shader::IpaInterpMode::Linear: { + out += "noperspective "; + break; + } + case Tegra::Shader::IpaInterpMode::Perspective: { + // Default, Smooth + break; + } + default: { + LOG_CRITICAL(HW_GPU, "Unhandled Ipa InterpMode: {}", static_cast<u32>(interp_mode)); + UNREACHABLE(); + } + } + switch (sample_mode) { + case Tegra::Shader::IpaSampleMode::Centroid: { + // Note not implemented, it can be implemented with the "centroid " keyword in glsl; + LOG_CRITICAL(HW_GPU, "Ipa Sampler Mode: centroid, not implemented"); + UNREACHABLE(); + break; + } + case Tegra::Shader::IpaSampleMode::Default: { + // Default, n/a + break; + } + default: { + LOG_CRITICAL(HW_GPU, "Unhandled Ipa SampleMode: {}", static_cast<u32>(sample_mode)); + UNREACHABLE(); + } + } + return out; + } + /// Generates code representing an output attribute register. std::string GetOutputAttribute(Attribute::Index attribute) { switch (attribute) { @@ -593,7 +659,7 @@ private: ShaderWriter& shader; ShaderWriter& declarations; std::vector<GLSLRegister> regs; - std::set<Attribute::Index> declr_input_attribute; + std::unordered_map<Attribute::Index, Tegra::Shader::IpaMode> declr_input_attribute; std::set<Attribute::Index> declr_output_attribute; std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers; std::vector<SamplerEntry> used_samplers; @@ -1634,8 +1700,12 @@ private: switch (opcode->GetId()) { case OpCode::Id::LD_A: { ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested"); + // Note: Shouldn't this be interp mode flat? As in no interpolation made. + + Tegra::Shader::IpaMode input_mode{Tegra::Shader::IpaInterpMode::Perspective, + Tegra::Shader::IpaSampleMode::Default}; regs.SetRegisterToInputAttibute(instr.gpr0, instr.attribute.fmt20.element, - instr.attribute.fmt20.index); + instr.attribute.fmt20.index, input_mode); break; } case OpCode::Id::LD_C: { @@ -2127,42 +2197,11 @@ private: case OpCode::Id::IPA: { const auto& attribute = instr.attribute.fmt28; const auto& reg = instr.gpr0; - ASSERT_MSG(instr.ipa.sample_mode == Tegra::Shader::IpaSampleMode::Default, - "Unhandled IPA sample mode: {}", - static_cast<u32>(instr.ipa.sample_mode.Value())); ASSERT_MSG(instr.ipa.saturate == 0, "IPA saturate not implemented"); - switch (instr.ipa.interp_mode) { - case Tegra::Shader::IpaInterpMode::Linear: - if (stage == Maxwell3D::Regs::ShaderStage::Fragment && - attribute.index == Attribute::Index::Position) { - switch (attribute.element) { - case 0: - shader.AddLine(regs.GetRegisterAsFloat(reg) + " = gl_FragCoord.x;"); - break; - case 1: - shader.AddLine(regs.GetRegisterAsFloat(reg) + " = gl_FragCoord.y;"); - break; - case 2: - shader.AddLine(regs.GetRegisterAsFloat(reg) + " = gl_FragCoord.z;"); - break; - case 3: - shader.AddLine(regs.GetRegisterAsFloat(reg) + " = 1.0;"); - break; - } - } else { - regs.SetRegisterToInputAttibute(reg, attribute.element, attribute.index); - } - break; - case Tegra::Shader::IpaInterpMode::Perspective: - regs.SetRegisterToInputAttibute(reg, attribute.element, attribute.index); - break; - default: - LOG_CRITICAL(HW_GPU, "Unhandled IPA mode: {}", - static_cast<u32>(instr.ipa.interp_mode.Value())); - UNREACHABLE(); - regs.SetRegisterToInputAttibute(reg, attribute.element, attribute.index); - } - + Tegra::Shader::IpaMode input_mode{instr.ipa.interp_mode.Value(), + instr.ipa.sample_mode.Value()}; + regs.SetRegisterToInputAttibute(reg, attribute.element, attribute.index, + input_mode); break; } case OpCode::Id::SSY: { |