diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 11d1169f0..df00ea85d 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -34,14 +34,20 @@ using Maxwell = Tegra::Engines::Maxwell3D::Regs; using ShaderStage = Tegra::Engines::Maxwell3D::Regs::ShaderStage; using Operation = const OperationNode&; +enum class Type { Bool, Bool2, Float, Int, Uint, HalfFloat }; + +namespace { +struct TextureAoffi {}; +using TextureArgument = std::pair; +using TextureIR = std::variant; +} // namespace + enum : u32 { POSITION_VARYING_LOCATION = 0, GENERIC_VARYING_START_LOCATION = 1 }; constexpr u32 MAX_CONSTBUFFER_ELEMENTS = static_cast(RasterizerOpenGL::MaxConstbufferSize) / (4 * sizeof(float)); constexpr u32 MAX_GLOBALMEMORY_ELEMENTS = static_cast(RasterizerOpenGL::MaxGlobalMemorySize) / sizeof(float); -enum class Type { Bool, Bool2, Float, Int, Uint, HalfFloat }; - class ShaderWriter { public: void AddExpression(std::string_view text) { @@ -718,8 +724,8 @@ private: result_type)); } - std::string GenerateTexture(Operation operation, const std::string& func, - const std::vector>& extras) { + std::string GenerateTexture(Operation operation, const std::string& function_suffix, + const std::vector& extras) { constexpr std::array coord_constructors = {"float", "vec2", "vec3", "vec4"}; const auto meta = std::get_if(&operation.GetMeta()); @@ -729,11 +735,11 @@ private: const bool has_array = meta->sampler.IsArray(); const bool has_shadow = meta->sampler.IsShadow(); - std::string expr = func; - expr += '('; - expr += GetSampler(meta->sampler); - expr += ", "; - + std::string expr = "texture" + function_suffix; + if (!meta->aoffi.empty()) { + expr += "Offset"; + } + expr += '(' + GetSampler(meta->sampler) + ", "; expr += coord_constructors.at(count + (has_array ? 1 : 0) + (has_shadow ? 1 : 0) - 1); expr += '('; for (std::size_t i = 0; i < count; ++i) { @@ -751,38 +757,76 @@ private: } expr += ')'; - for (const auto& extra_pair : extras) { - const auto [type, operand] = extra_pair; - if (operand == nullptr) { - continue; - } - expr += ", "; - - switch (type) { - case Type::Int: - if (const auto immediate = std::get_if(operand)) { - // Inline the string as an immediate integer in GLSL (some extra arguments are - // required to be constant) - expr += std::to_string(static_cast(immediate->GetValue())); - } else { - expr += "ftoi(" + Visit(operand) + ')'; - } - break; - case Type::Float: - expr += Visit(operand); - break; - default: { - const auto type_int = static_cast(type); - UNIMPLEMENTED_MSG("Unimplemented extra type={}", type_int); - expr += '0'; - break; - } + for (const auto& variant : extras) { + if (const auto argument = std::get_if(&variant)) { + expr += GenerateTextureArgument(*argument); + } else if (std::get_if(&variant)) { + expr += GenerateTextureAoffi(meta->aoffi); + } else { + UNREACHABLE(); } } return expr + ')'; } + std::string GenerateTextureArgument(TextureArgument argument) { + const auto [type, operand] = argument; + if (operand == nullptr) { + return {}; + } + + std::string expr = ", "; + switch (type) { + case Type::Int: + if (const auto immediate = std::get_if(operand)) { + // Inline the string as an immediate integer in GLSL (some extra arguments are + // required to be constant) + expr += std::to_string(static_cast(immediate->GetValue())); + } else { + expr += "ftoi(" + Visit(operand) + ')'; + } + break; + case Type::Float: + expr += Visit(operand); + break; + default: { + const auto type_int = static_cast(type); + UNIMPLEMENTED_MSG("Unimplemented extra type={}", type_int); + expr += '0'; + break; + } + } + return expr; + } + + std::string GenerateTextureAoffi(const std::vector& aoffi) { + if (aoffi.empty()) { + return {}; + } + constexpr std::array coord_constructors = {"int", "ivec2", "ivec3"}; + std::string expr = ", "; + expr += coord_constructors.at(aoffi.size() - 1); + expr += '('; + + for (std::size_t index = 0; index < aoffi.size(); ++index) { + const auto operand{aoffi.at(index)}; + if (const auto immediate = std::get_if(operand)) { + // Inline the string as an immediate integer in GLSL (AOFFI arguments are required + // to be constant by the standard). + expr += std::to_string(static_cast(immediate->GetValue())); + } else { + expr += "ftoi(" + Visit(operand) + ')'; + } + if (index + 1 < aoffi.size()) { + expr += ", "; + } + } + expr += ')'; + + return expr; + } + std::string Assign(Operation operation) { const Node dest = operation[0]; const Node src = operation[1]; @@ -1159,7 +1203,8 @@ private: const auto meta = std::get_if(&operation.GetMeta()); ASSERT(meta); - std::string expr = GenerateTexture(operation, "texture", {{Type::Float, meta->bias}}); + std::string expr = GenerateTexture( + operation, "", {TextureAoffi{}, TextureArgument{Type::Float, meta->bias}}); if (meta->sampler.IsShadow()) { expr = "vec4(" + expr + ')'; } @@ -1170,7 +1215,8 @@ private: const auto meta = std::get_if(&operation.GetMeta()); ASSERT(meta); - std::string expr = GenerateTexture(operation, "textureLod", {{Type::Float, meta->lod}}); + std::string expr = GenerateTexture( + operation, "Lod", {TextureArgument{Type::Float, meta->lod}, TextureAoffi{}}); if (meta->sampler.IsShadow()) { expr = "vec4(" + expr + ')'; } @@ -1182,7 +1228,8 @@ private: ASSERT(meta); const auto type = meta->sampler.IsShadow() ? Type::Float : Type::Int; - return GenerateTexture(operation, "textureGather", {{type, meta->component}}) + + return GenerateTexture(operation, "Gather", + {TextureArgument{type, meta->component}, TextureAoffi{}}) + GetSwizzle(meta->element); } @@ -1211,8 +1258,8 @@ private: ASSERT(meta); if (meta->element < 2) { - return "itof(int((" + GenerateTexture(operation, "textureQueryLod", {}) + - " * vec2(256))" + GetSwizzle(meta->element) + "))"; + return "itof(int((" + GenerateTexture(operation, "QueryLod", {}) + " * vec2(256))" + + GetSwizzle(meta->element) + "))"; } return "0"; }