diff options
author | ReinUsesLisp <reinuseslisp@airmail.cc> | 2018-12-26 05:57:14 +0100 |
---|---|---|
committer | ReinUsesLisp <reinuseslisp@airmail.cc> | 2019-01-15 21:54:53 +0100 |
commit | af5d7e2c49d1cfe470b0b4ebd55561f9f22dc677 (patch) | |
tree | fe95585385e2569af1f80b6e6c63918e24b64e5f /src/video_core/shader | |
parent | shader_ir: Remove RZ and use Register::ZeroIndex instead (diff) | |
download | yuzu-af5d7e2c49d1cfe470b0b4ebd55561f9f22dc677.tar yuzu-af5d7e2c49d1cfe470b0b4ebd55561f9f22dc677.tar.gz yuzu-af5d7e2c49d1cfe470b0b4ebd55561f9f22dc677.tar.bz2 yuzu-af5d7e2c49d1cfe470b0b4ebd55561f9f22dc677.tar.lz yuzu-af5d7e2c49d1cfe470b0b4ebd55561f9f22dc677.tar.xz yuzu-af5d7e2c49d1cfe470b0b4ebd55561f9f22dc677.tar.zst yuzu-af5d7e2c49d1cfe470b0b4ebd55561f9f22dc677.zip |
Diffstat (limited to 'src/video_core/shader')
-rw-r--r-- | src/video_core/shader/glsl_decompiler.cpp | 1543 | ||||
-rw-r--r-- | src/video_core/shader/glsl_decompiler.h | 88 |
2 files changed, 0 insertions, 1631 deletions
diff --git a/src/video_core/shader/glsl_decompiler.cpp b/src/video_core/shader/glsl_decompiler.cpp deleted file mode 100644 index 27f1e0dde..000000000 --- a/src/video_core/shader/glsl_decompiler.cpp +++ /dev/null @@ -1,1543 +0,0 @@ -// Copyright 2018 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <string> -#include <string_view> -#include <variant> - -#include <fmt/format.h> - -#include "common/alignment.h" -#include "common/assert.h" -#include "common/common_types.h" -#include "video_core/engines/maxwell_3d.h" -#include "video_core/shader/glsl_decompiler.h" -#include "video_core/shader/shader_ir.h" - -namespace OpenGL::GLShader { - -using Tegra::Shader::Attribute; -using Tegra::Shader::Header; -using Tegra::Shader::IpaInterpMode; -using Tegra::Shader::IpaMode; -using Tegra::Shader::IpaSampleMode; -using Tegra::Shader::Register; -using namespace VideoCommon::Shader; - -using Maxwell = Tegra::Engines::Maxwell3D::Regs; -using ShaderStage = Tegra::Engines::Maxwell3D::Regs::ShaderStage; -using Operation = const OperationNode&; - -enum : u32 { POSITION_VARYING_LOCATION = 0, GENERIC_VARYING_START_LOCATION = 1 }; -constexpr u32 MAX_CONSTBUFFER_ELEMENTS = 65536 / 16; // TODO(Rodrigo): Use rasterizer's value - -enum class Type { Bool, Bool2, Float, Int, Uint, HalfFloat }; - -class ShaderWriter { -public: - void AddExpression(std::string_view text) { - DEBUG_ASSERT(scope >= 0); - if (!text.empty()) { - AppendIndentation(); - } - shader_source += text; - } - - void AddLine(std::string_view text) { - AddExpression(text); - AddNewLine(); - } - - void AddLine(char character) { - DEBUG_ASSERT(scope >= 0); - AppendIndentation(); - shader_source += character; - AddNewLine(); - } - - void AddNewLine() { - DEBUG_ASSERT(scope >= 0); - shader_source += '\n'; - } - - std::string GenerateTemporal() { - std::string temporal = "tmp"; - temporal += std::to_string(temporal_index++); - return temporal; - } - - std::string GetResult() { - return std::move(shader_source); - } - - s32 scope = 0; - -private: - void AppendIndentation() { - shader_source.append(static_cast<std::size_t>(scope) * 4, ' '); - } - - std::string shader_source; - u32 temporal_index = 1; -}; - -/// Generates code to use for a swizzle operation. -static std::string GetSwizzle(u32 elem) { - ASSERT(elem <= 3); - std::string swizzle = "."; - swizzle += "xyzw"[elem]; - return swizzle; -} - -/// Translate topology -static std::string GetTopologyName(Tegra::Shader::OutputTopology topology) { - switch (topology) { - case Tegra::Shader::OutputTopology::PointList: - return "points"; - case Tegra::Shader::OutputTopology::LineStrip: - return "line_strip"; - case Tegra::Shader::OutputTopology::TriangleStrip: - return "triangle_strip"; - default: - UNIMPLEMENTED_MSG("Unknown output topology: {}", static_cast<u32>(topology)); - return "points"; - } -} - -/// Returns true if an object has to be treated as precise -static bool IsPrecise(Operation operand) { - const auto& meta = operand.GetMeta(); - - if (std::holds_alternative<MetaArithmetic>(meta)) { - return std::get<MetaArithmetic>(meta).precise; - } - if (std::holds_alternative<MetaHalfArithmetic>(meta)) { - return std::get<MetaHalfArithmetic>(meta).precise; - } - return false; -} - -static bool IsPrecise(Node node) { - if (!std::holds_alternative<OperationNode>(*node)) { - return false; - } - return IsPrecise(std::get<OperationNode>(*node)); -} - -class GLSLDecompiler final { -public: - explicit GLSLDecompiler(const ShaderIR& ir, ShaderStage stage, std::string suffix) - : ir{ir}, stage{stage}, suffix{suffix}, header{ir.GetHeader()} {} - - void Decompile() { - DeclareVertex(); - DeclareGeometry(); - DeclareRegisters(); - DeclarePredicates(); - DeclareLocalMemory(); - DeclareInternalFlags(); - DeclareInputAttributes(); - DeclareOutputAttributes(); - DeclareConstantBuffers(); - DeclareSamplers(); - - code.AddLine("void execute_" + suffix + "() {"); - ++code.scope; - - // VM's program counter - const auto first_address = ir.GetBasicBlocks().begin()->first; - code.AddLine("uint jmp_to = " + std::to_string(first_address) + "u;"); - - // TODO(Subv): Figure out the actual depth of the flow stack, for now it seems - // unlikely that shaders will use 20 nested SSYs and PBKs. - constexpr u32 FLOW_STACK_SIZE = 20; - code.AddLine(fmt::format("uint flow_stack[{}];", FLOW_STACK_SIZE)); - code.AddLine("uint flow_stack_top = 0u;"); - - code.AddLine("while (true) {"); - ++code.scope; - - code.AddLine("switch (jmp_to) {"); - - for (const auto& pair : ir.GetBasicBlocks()) { - const auto [address, bb] = pair; - code.AddLine(fmt::format("case 0x{:x}u: {{", address)); - ++code.scope; - - VisitBasicBlock(bb); - - --code.scope; - code.AddLine('}'); - } - - code.AddLine("default: return;"); - code.AddLine('}'); - - for (std::size_t i = 0; i < 2; ++i) { - --code.scope; - code.AddLine('}'); - } - } - - std::string GetResult() { - return code.GetResult(); - } - - ShaderEntries GetShaderEntries() const { - ShaderEntries entries; - for (const auto& cbuf : ir.GetConstantBuffers()) { - ConstBufferEntry desc(cbuf.second, stage, GetConstBufferBlock(cbuf.first), cbuf.first); - entries.const_buffers.push_back(desc); - } - for (const auto& sampler : ir.GetSamplers()) { - SamplerEntry desc(sampler, stage, GetSampler(sampler)); - entries.samplers.push_back(desc); - } - entries.clip_distances = ir.GetClipDistances(); - entries.shader_length = ir.GetLength(); - return entries; - } - -private: - using OperationDecompilerFn = std::string (GLSLDecompiler::*)(Operation); - using OperationDecompilersArray = - std::array<OperationDecompilerFn, static_cast<std::size_t>(OperationCode::Amount)>; - - void DeclareVertex() { - if (stage != ShaderStage::Vertex) - return; - - DeclareVertexRedeclarations(); - } - - void DeclareGeometry() { - if (stage != ShaderStage::Geometry) - return; - - const auto topology = GetTopologyName(header.common3.output_topology); - const auto max_vertices = std::to_string(header.common4.max_output_vertices); - code.AddLine("layout (" + topology + ", max_vertices = " + max_vertices + ") out;"); - code.AddNewLine(); - - DeclareVertexRedeclarations(); - } - - 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)) { - code.AddLine("float gl_ClipDistance[];"); - clip_distances_declared = true; - } - } - - --code.scope; - code.AddLine("};"); - code.AddNewLine(); - } - - void DeclareRegisters() { - const auto& registers = ir.GetRegisters(); - for (const u32 gpr : registers) { - code.AddLine("float " + GetRegister(gpr) + " = 0;"); - } - if (!registers.empty()) - code.AddNewLine(); - } - - void DeclarePredicates() { - const auto& predicates = ir.GetPredicates(); - for (const auto pred : predicates) { - code.AddLine("bool " + GetPredicate(pred) + " = false;"); - } - if (!predicates.empty()) - code.AddNewLine(); - } - - void DeclareLocalMemory() { - if (const u64 local_memory_size = header.GetLocalMemorySize(); local_memory_size > 0) { - const auto element_count = Common::AlignUp(local_memory_size, 4) / 4; - code.AddLine("float " + GetLocalMemory() + '[' + std::to_string(element_count) + "];"); - code.AddNewLine(); - } - } - - void DeclareInternalFlags() { - for (u32 flag = 0; flag < static_cast<u32>(InternalFlag::Amount); flag++) { - const InternalFlag flag_code = static_cast<InternalFlag>(flag); - code.AddLine("bool " + GetInternalFlag(flag_code) + " = false;"); - } - code.AddNewLine(); - } - - std::string GetInputFlags(const IpaMode& input_mode) { - const IpaSampleMode sample_mode = input_mode.sampling_mode; - const IpaInterpMode interp_mode = input_mode.interpolation_mode; - std::string out; - - switch (interp_mode) { - case IpaInterpMode::Flat: - out += "flat "; - break; - case IpaInterpMode::Linear: - out += "noperspective "; - break; - case IpaInterpMode::Perspective: - // Default, Smooth - break; - default: - UNIMPLEMENTED_MSG("Unhandled IPA interp mode: {}", static_cast<u32>(interp_mode)); - } - switch (sample_mode) { - case IpaSampleMode::Centroid: - // It can be implemented with the "centroid " keyword in GLSL - UNIMPLEMENTED_MSG("Unimplemented IPA sampler mode centroid"); - break; - case IpaSampleMode::Default: - // Default, n/a - break; - default: - UNIMPLEMENTED_MSG("Unimplemented IPA sampler mode: {}", static_cast<u32>(sample_mode)); - } - return out; - } - - void DeclareInputAttributes() { - const auto& attributes = ir.GetInputAttributes(); - for (const auto element : attributes) { - const Attribute::Index index = element.first; - const IpaMode& input_mode = *element.second.begin(); - if (index < Attribute::Index::Attribute_0 || index > Attribute::Index::Attribute_31) { - // Skip when it's not a generic attribute - continue; - } - - ASSERT(element.second.size() > 0); - // UNIMPLEMENTED_IF_MSG(element.second.size() > 1, - // "Multiple input flag modes are not supported in GLSL"); - - // TODO(bunnei): Use proper number of elements for these - u32 idx = static_cast<u32>(index) - static_cast<u32>(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 + "[]"; - } - code.AddLine("layout (location = " + std::to_string(idx) + ") " + - GetInputFlags(input_mode) + "in vec4 " + attr + ';'); - } - if (!attributes.empty()) - code.AddNewLine(); - } - - void DeclareOutputAttributes() { - 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<u32>(index) - - static_cast<u32>(Attribute::Index::Attribute_0) + - GENERIC_VARYING_START_LOCATION; - code.AddLine("layout (location = " + std::to_string(idx) + ") out vec4 " + - GetOutputAttribute(index) + ';'); - } - if (!attributes.empty()) - code.AddNewLine(); - } - - void DeclareConstantBuffers() { - for (const auto& entry : ir.GetConstantBuffers()) { - const auto [index, size] = entry; - code.AddLine("layout (std140) uniform " + GetConstBufferBlock(index) + " {"); - code.AddLine(" vec4 " + GetConstBuffer(index) + "[MAX_CONSTBUFFER_ELEMENTS];"); - code.AddLine("};"); - code.AddNewLine(); - } - } - - void DeclareSamplers() { - const auto& samplers = ir.GetSamplers(); - for (const auto& sampler : samplers) { - std::string sampler_type = [&]() { - switch (sampler.GetType()) { - case Tegra::Shader::TextureType::Texture1D: - return "sampler1D"; - case Tegra::Shader::TextureType::Texture2D: - return "sampler2D"; - case Tegra::Shader::TextureType::Texture3D: - return "sampler3D"; - case Tegra::Shader::TextureType::TextureCube: - return "samplerCube"; - default: - UNREACHABLE(); - return "sampler2D"; - } - }(); - if (sampler.IsArray()) - sampler_type += "Array"; - if (sampler.IsShadow()) - sampler_type += "Shadow"; - - code.AddLine("uniform " + sampler_type + ' ' + GetSampler(sampler) + ';'); - } - if (!samplers.empty()) - code.AddNewLine(); - } - - void VisitBasicBlock(const BasicBlock& bb) { - for (const Node node : bb) { - if (const std::string expr = Visit(node); !expr.empty()) { - code.AddLine(expr); - } - } - } - - std::string Visit(Node node) { - if (const auto operation = std::get_if<OperationNode>(node)) { - const auto operation_index = static_cast<std::size_t>(operation->GetCode()); - const auto decompiler = operation_decompilers[operation_index]; - if (decompiler == nullptr) { - UNREACHABLE_MSG("Operation decompiler {} not defined", operation_index); - } - return (this->*decompiler)(*operation); - - } else if (const auto gpr = std::get_if<GprNode>(node)) { - const u32 index = gpr->GetIndex(); - if (index == Register::ZeroIndex) { - return "0"; - } - return GetRegister(index); - - } else if (const auto immediate = std::get_if<ImmediateNode>(node)) { - const u32 value = immediate->GetValue(); - if (value < 10) { - // For eyecandy avoid using hex numbers on single digits - return fmt::format("utof({}u)", immediate->GetValue()); - } - return fmt::format("utof(0x{:x}u)", immediate->GetValue()); - - } else if (const auto predicate = std::get_if<PredicateNode>(node)) { - const auto value = [&]() -> std::string { - switch (const auto index = predicate->GetIndex(); index) { - case Tegra::Shader::Pred::UnusedIndex: - return "true"; - case Tegra::Shader::Pred::NeverExecute: - return "false"; - default: - return GetPredicate(index); - } - }(); - if (predicate->IsNegated()) { - return "!(" + value + ')'; - } - return value; - - } else if (const auto abuf = std::get_if<AbufNode>(node)) { - const auto attribute = abuf->GetIndex(); - const auto element = abuf->GetElement(); - - const auto GeometryPass = [&](const std::string& name) { - if (stage == ShaderStage::Geometry && abuf->GetBuffer()) { - // TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games - // set an 0x80000000 index for those and the shader fails to build. Find out why - // this happens and what's its intent. - return "gs_" + name + "[ftou(" + Visit(abuf->GetBuffer()) + - ") % MAX_VERTEX_INPUT]"; - } - return name; - }; - - switch (attribute) { - case Attribute::Index::Position: - if (stage != ShaderStage::Fragment) { - return GeometryPass("position") + GetSwizzle(element); - } else { - return element == 3 ? "1.0f" : "gl_FragCoord" + GetSwizzle(element); - } - case Attribute::Index::PointCoord: - switch (element) { - case 0: - return "gl_PointCoord.x"; - case 1: - return "gl_PointCoord.y"; - case 2: - case 3: - return "0"; - } - UNREACHABLE(); - return "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 - // shader. - ASSERT(stage == ShaderStage::Vertex); - switch (element) { - case 2: - // Config pack's first value is instance_id. - return "uintBitsToFloat(config_pack[0])"; - case 3: - return "uintBitsToFloat(gl_VertexID)"; - } - UNIMPLEMENTED_MSG("Unmanaged TessCoordInstanceIDVertexID element={}", element); - return "0"; - case Attribute::Index::FrontFacing: - // TODO(Subv): Find out what the values are for the other elements. - ASSERT(stage == ShaderStage::Fragment); - switch (element) { - case 3: - return "itof(gl_FrontFacing ? -1 : 0)"; - } - UNIMPLEMENTED_MSG("Unmanaged FrontFacing element={}", element); - return "0"; - default: - if (attribute >= Attribute::Index::Attribute_0 && - attribute <= Attribute::Index::Attribute_31) { - return GeometryPass(GetInputAttribute(attribute)) + GetSwizzle(element); - } - break; - } - UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute)); - - } else if (const auto cbuf = std::get_if<CbufNode>(node)) { - const Node offset = cbuf->GetOffset(); - if (const auto immediate = std::get_if<ImmediateNode>(offset)) { - // Direct access - const u32 offset_imm = immediate->GetValue(); - return fmt::format("{}[{}][{}]", GetConstBuffer(cbuf->GetIndex()), offset_imm / 4, - offset_imm % 4); - - } else if (std::holds_alternative<OperationNode>(*offset)) { - // Indirect access - const std::string final_offset = code.GenerateTemporal(); - code.AddLine("uint " + final_offset + " = (ftou(" + Visit(offset) + ") / 4) & " + - std::to_string(MAX_CONSTBUFFER_ELEMENTS - 1) + ';'); - return fmt::format("{}[{} / 4][{} % 4]", GetConstBuffer(cbuf->GetIndex()), - final_offset, final_offset); - - } else { - UNREACHABLE_MSG("Unmanaged offset node type"); - } - - } else if (const auto lmem = std::get_if<LmemNode>(node)) { - return fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress())); - - } else if (const auto internal_flag = std::get_if<InternalFlagNode>(node)) { - return GetInternalFlag(internal_flag->GetFlag()); - - } else if (const auto conditional = std::get_if<ConditionalNode>(node)) { - // It's invalid to call conditional on nested nodes, use an operation instead - code.AddLine("if (" + Visit(conditional->GetCondition()) + ") {"); - ++code.scope; - - VisitBasicBlock(conditional->GetCode()); - - --code.scope; - code.AddLine('}'); - return {}; - - } else if (const auto comment = std::get_if<CommentNode>(node)) { - return "// " + comment->GetText(); - } - UNREACHABLE(); - return {}; - } - - std::string ApplyPrecise(Operation operation, const std::string& value) { - if (!IsPrecise(operation)) { - return value; - } - // There's a bug in NVidia's proprietary drivers that makes precise fail on fragment shaders - const std::string precise = stage != ShaderStage::Fragment ? "precise " : ""; - - const std::string temporal = code.GenerateTemporal(); - code.AddLine(precise + "float " + temporal + " = " + value + ';'); - return temporal; - } - - std::string VisitOperand(Operation operation, std::size_t operand_index) { - const auto& operand = operation[operand_index]; - const bool parent_precise = IsPrecise(operation); - const bool child_precise = IsPrecise(operand); - const bool child_trivial = !std::holds_alternative<OperationNode>(*operand); - if (!parent_precise || child_precise || child_trivial) { - return Visit(operand); - } - - const std::string temporal = code.GenerateTemporal(); - code.AddLine("float " + temporal + " = " + Visit(operand) + ';'); - return temporal; - } - - std::string VisitOperand(Operation operation, std::size_t operand_index, Type type) { - std::string value = VisitOperand(operation, operand_index); - - switch (type) { - case Type::Bool: - case Type::Bool2: - case Type::Float: - return value; - case Type::Int: - return "ftoi(" + value + ')'; - case Type::Uint: - return "ftou(" + value + ')'; - case Type::HalfFloat: - if (!std::holds_alternative<MetaHalfArithmetic>(operation.GetMeta())) { - value = "toHalf2(" + value + ')'; - } - - const auto& half_meta = std::get<MetaHalfArithmetic>(operation.GetMeta()); - switch (half_meta.types.at(operand_index)) { - case Tegra::Shader::HalfType::H0_H1: - return "toHalf2(" + value + ')'; - case Tegra::Shader::HalfType::F32: - return "vec2(" + value + ')'; - case Tegra::Shader::HalfType::H0_H0: - return "vec2(toHalf2(" + value + ")[0])"; - case Tegra::Shader::HalfType::H1_H1: - return "vec2(toHalf2(" + value + ")[1])"; - } - } - UNREACHABLE(); - return value; - } - - std::string BitwiseCastResult(std::string value, Type type, bool needs_parenthesis = false) { - switch (type) { - case Type::Bool: - case Type::Float: - if (needs_parenthesis) { - return '(' + value + ')'; - } - return value; - case Type::Int: - return "itof(" + value + ')'; - case Type::Uint: - return "utof(" + value + ')'; - case Type::HalfFloat: - return "fromHalf2(" + value + ')'; - } - UNREACHABLE(); - return value; - } - - std::string GenerateUnary(Operation operation, const std::string& func, Type result_type, - Type type_a, bool needs_parenthesis = true) { - return ApplyPrecise(operation, - BitwiseCastResult(func + '(' + VisitOperand(operation, 0, type_a) + ')', - result_type, needs_parenthesis)); - } - - std::string GenerateBinaryInfix(Operation operation, const std::string& func, Type result_type, - Type type_a, Type type_b) { - const std::string op_a = VisitOperand(operation, 0, type_a); - const std::string op_b = VisitOperand(operation, 1, type_b); - - return ApplyPrecise( - operation, BitwiseCastResult('(' + op_a + ' ' + func + ' ' + op_b + ')', result_type)); - } - - std::string GenerateBinaryCall(Operation operation, const std::string& func, Type result_type, - Type type_a, Type type_b) { - const std::string op_a = VisitOperand(operation, 0, type_a); - const std::string op_b = VisitOperand(operation, 1, type_b); - - return ApplyPrecise(operation, - BitwiseCastResult(func + '(' + op_a + ", " + op_b + ')', result_type)); - } - - std::string GenerateTernary(Operation operation, const std::string& func, Type result_type, - Type type_a, Type type_b, Type type_c) { - const std::string op_a = VisitOperand(operation, 0, type_a); - const std::string op_b = VisitOperand(operation, 1, type_b); - const std::string op_c = VisitOperand(operation, 2, type_c); - - return ApplyPrecise( - operation, - BitwiseCastResult(func + '(' + op_a + ", " + op_b + ", " + op_c + ')', result_type)); - } - - std::string GenerateQuaternary(Operation operation, const std::string& func, Type result_type, - Type type_a, Type type_b, Type type_c, Type type_d) { - const std::string op_a = VisitOperand(operation, 0, type_a); - const std::string op_b = VisitOperand(operation, 1, type_b); - const std::string op_c = VisitOperand(operation, 2, type_c); - const std::string op_d = VisitOperand(operation, 3, type_d); - - return ApplyPrecise(operation, BitwiseCastResult(func + '(' + op_a + ", " + op_b + ", " + - op_c + ", " + op_d + ')', - result_type)); - } - - std::string GenerateTexture(Operation operation, const std::string& func, - std::string extra_cast(std::string) = nullptr) { - constexpr std::array<const char*, 4> coord_constructors = {"float", "vec2", "vec3", "vec4"}; - - const auto& meta = std::get<MetaTexture>(operation.GetMeta()); - const auto count = static_cast<u32>(operation.GetOperandsCount()); - - std::string expr = func; - expr += '('; - expr += GetSampler(meta.sampler); - expr += ", "; - - expr += coord_constructors[meta.coords_count - 1]; - expr += '('; - for (u32 i = 0; i < count; ++i) { - const bool is_extra = i >= meta.coords_count; - const bool is_array = i == meta.array_index; - - std::string operand = Visit(operation[i]); - if (is_extra && extra_cast != nullptr) { - operand = extra_cast(operand); - } - if (is_array) { - ASSERT(!is_extra); - operand = "float(ftoi(" + operand + "))"; - } - expr += operand; - if (i + 1 == meta.coords_count) { - expr += ')'; - } - if (i + 1 < count) { - expr += ", "; - } - } - expr += ')'; - return expr; - } - - std::string Assign(Operation operation) { - const Node dest = operation[0]; - const Node src = operation[1]; - - std::string target; - if (const auto gpr = std::get_if<GprNode>(dest)) { - if (gpr->GetIndex() == Register::ZeroIndex) { - // Writing to Register::ZeroIndex is a no op - return {}; - } - target = GetRegister(gpr->GetIndex()); - - } else if (const auto abuf = std::get_if<AbufNode>(dest)) { - target = [&]() -> std::string { - switch (const auto attribute = abuf->GetIndex(); abuf->GetIndex()) { - case Attribute::Index::Position: - return "position" + GetSwizzle(abuf->GetElement()); - case Attribute::Index::PointSize: - return "gl_PointSize"; - case Attribute::Index::ClipDistances0123: - return "gl_ClipDistance[" + std::to_string(abuf->GetElement()) + ']'; - case Attribute::Index::ClipDistances4567: - return "gl_ClipDistance[" + std::to_string(abuf->GetElement() + 4) + ']'; - default: - if (attribute >= Attribute::Index::Attribute_0 && - attribute <= Attribute::Index::Attribute_31) { - return GetOutputAttribute(attribute) + GetSwizzle(abuf->GetElement()); - } - UNIMPLEMENTED_MSG("Unhandled output attribute: {}", - static_cast<u32>(attribute)); - return "0"; - } - }(); - - } else if (const auto lmem = std::get_if<LmemNode>(dest)) { - target = GetLocalMemory() + "[ftou(" + Visit(lmem->GetAddress()) + ") / 4]"; - - } else { - UNREACHABLE_MSG("Assign called without a proper target"); - } - - code.AddLine(target + " = " + Visit(src) + ';'); - return {}; - } - - std::string AssignComposite(Operation operation) { - const auto& meta = std::get<MetaComponents>(operation.GetMeta()); - - const std::string composite = code.GenerateTemporal(); - code.AddLine("vec4 " + composite + " = " + Visit(operation[0]) + ';'); - - constexpr u32 composite_size = 4; - for (u32 i = 0; i < composite_size; ++i) { - const auto gpr = std::get<GprNode>(*operation[i + 1]).GetIndex(); - if (gpr == Register::ZeroIndex) { - continue; - } - code.AddLine(GetRegister(gpr) + " = " + composite + - GetSwizzle(meta.GetSourceComponent(i)) + ';'); - } - return {}; - } - - std::string AssignCompositeHalf(Operation operation) { - const auto& meta = std::get<MetaComponents>(operation.GetMeta()); - - const std::string composite = code.GenerateTemporal(); - code.AddLine("vec4 " + composite + " = " + Visit(operation[0]) + ';'); - - const auto ReadComponent = [&](u32 component) { - if (component < meta.count) { - return composite + '[' + std::to_string(meta.GetSourceComponent(component)) + ']'; - } - return std::string("0"); - }; - - const auto dst1 = std::get<GprNode>(*operation[1]).GetIndex(); - const std::string src1 = "vec2(" + ReadComponent(0) + ", " + ReadComponent(1) + ')'; - code.AddLine(GetRegister(dst1) + " = utof(packHalf2x16(" + src1 + "))"); - - if (meta.count > 2) { - const auto dst2 = std::get<GprNode>(*operation[2]).GetIndex(); - const std::string src2 = "vec2(" + ReadComponent(2) + ", " + ReadComponent(3) + ')'; - code.AddLine(GetRegister(dst2) + " = utof(packHalf2x16(" + src2 + "))"); - } - return {}; - } - - std::string Composite(Operation operation) { - std::string value = "vec4("; - for (std::size_t i = 0; i < 4; ++i) { - value += Visit(operation[i]); - if (i < 3) - value += ", "; - } - value += ')'; - return value; - } - - template <Type type> - std::string Add(Operation operation) { - return GenerateBinaryInfix(operation, "+", type, type, type); - } - - template <Type type> - std::string Mul(Operation operation) { - return GenerateBinaryInfix(operation, "*", type, type, type); - } - - template <Type type> - std::string Div(Operation operation) { - return GenerateBinaryInfix(operation, "/", type, type, type); - } - - template <Type type> - std::string Fma(Operation operation) { - return GenerateTernary(operation, "fma", type, type, type, type); - } - - template <Type type> - std::string Negate(Operation operation) { - return GenerateUnary(operation, "-", type, type, true); - } - - template <Type type> - std::string Absolute(Operation operation) { - return GenerateUnary(operation, "abs", type, type, false); - } - - std::string FClamp(Operation operation) { - return GenerateTernary(operation, "clamp", Type::Float, Type::Float, Type::Float, - Type::Float); - } - - template <Type type> - std::string Min(Operation operation) { - return GenerateBinaryCall(operation, "min", type, type, type); - } - - template <Type type> - std::string Max(Operation operation) { - return GenerateBinaryCall(operation, "max", type, type, type); - } - - std::string Select(Operation operation) { - const std::string condition = Visit(operation[0]); - const std::string true_case = Visit(operation[1]); - const std::string false_case = Visit(operation[2]); - return ApplyPrecise(operation, - '(' + condition + " ? " + true_case + " : " + false_case + ')'); - } - - std::string FCos(Operation operation) { - return GenerateUnary(operation, "cos", Type::Float, Type::Float, false); - } - - std::string FSin(Operation operation) { - return GenerateUnary(operation, "sin", Type::Float, Type::Float, false); - } - - std::string FExp2(Operation operation) { - return GenerateUnary(operation, "exp2", Type::Float, Type::Float, false); - } - - std::string FLog2(Operation operation) { - return GenerateUnary(operation, "log2", Type::Float, Type::Float, false); - } - - std::string FInverseSqrt(Operation operation) { - return GenerateUnary(operation, "inversesqrt", Type::Float, Type::Float, false); - } - - std::string FSqrt(Operation operation) { - return GenerateUnary(operation, "sqrt", Type::Float, Type::Float, false); - } - - std::string FRoundEven(Operation operation) { - return GenerateUnary(operation, "roundEven", Type::Float, Type::Float, false); - } - - std::string FFloor(Operation operation) { - return GenerateUnary(operation, "floor", Type::Float, Type::Float, false); - } - - std::string FCeil(Operation operation) { - return GenerateUnary(operation, "ceil", Type::Float, Type::Float, false); - } - - std::string FTrunc(Operation operation) { - return GenerateUnary(operation, "trunc", Type::Float, Type::Float, false); - } - - template <Type type> - std::string FCastInteger(Operation operation) { - return GenerateUnary(operation, "float", Type::Float, type, false); - } - - std::string ICastFloat(Operation operation) { - return GenerateUnary(operation, "int", Type::Int, Type::Float, false); - } - - std::string ICastUnsigned(Operation operation) { - return GenerateUnary(operation, "int", Type::Int, Type::Uint, false); - } - - template <Type type> - std::string LogicalShiftLeft(Operation operation) { - return GenerateBinaryInfix(operation, "<<", type, type, Type::Uint); - } - - std::string ILogicalShiftRight(Operation operation) { - const std::string op_a = VisitOperand(operation, 0, Type::Uint); - const std::string op_b = VisitOperand(operation, 1, Type::Uint); - - return ApplyPrecise(operation, - BitwiseCastResult("int(" + op_a + " >> " + op_b + ')', Type::Int)); - } - - std::string IArithmeticShiftRight(Operation operation) { - return GenerateBinaryInfix(operation, ">>", Type::Int, Type::Int, Type::Uint); - } - - template <Type type> - std::string BitwiseAnd(Operation operation) { - return GenerateBinaryInfix(operation, "&", type, type, type); - } - - template <Type type> - std::string BitwiseOr(Operation operation) { - return GenerateBinaryInfix(operation, "|", type, type, type); - } - - template <Type type> - std::string BitwiseXor(Operation operation) { - return GenerateBinaryInfix(operation, "^", type, type, type); - } - - template <Type type> - std::string BitwiseNot(Operation operation) { - return GenerateUnary(operation, "~", type, type, false); - } - - std::string UCastFloat(Operation operation) { - return GenerateUnary(operation, "uint", Type::Uint, Type::Float, false); - } - - std::string UCastSigned(Operation operation) { - return GenerateUnary(operation, "uint", Type::Uint, Type::Int, false); - } - - std::string UShiftRight(Operation operation) { - return GenerateBinaryInfix(operation, ">>", Type::Uint, Type::Uint, Type::Uint); - } - - template <Type type> - std::string BitfieldInsert(Operation operation) { - return GenerateQuaternary(operation, "bitfieldInsert", type, type, type, Type::Int, - Type::Int); - } - - template <Type type> - std::string BitCount(Operation operation) { - return GenerateUnary(operation, "bitCount", type, type, false); - } - - std::string HNegate(Operation operation) { - const auto GetNegate = [&](std::size_t index) -> std::string { - return VisitOperand(operation, index, Type::Bool) + " ? -1 : 1"; - }; - const std::string value = '(' + VisitOperand(operation, 0, Type::HalfFloat) + " * vec2(" + - GetNegate(1) + ", " + GetNegate(2) + "))"; - return BitwiseCastResult(value, Type::HalfFloat); - } - - std::string HMergeF32(Operation operation) { - return "float(toHalf2(" + Visit(operation[0]) + ")[0])"; - } - - std::string HMergeH0(Operation operation) { - return "fromHalf2(vec2(toHalf2(" + Visit(operation[0]) + ")[1], toHalf2(" + - Visit(operation[1]) + ")[0]))"; - } - - std::string HMergeH1(Operation operation) { - return "fromHalf2(vec2(toHalf2(" + Visit(operation[0]) + ")[0], toHalf2(" + - Visit(operation[1]) + ")[1]))"; - } - - template <Type type> - std::string LogicalLessThan(Operation operation) { - return GenerateBinaryInfix(operation, "<", Type::Bool, type, type); - } - - template <Type type> - std::string LogicalEqual(Operation operation) { - return GenerateBinaryInfix(operation, "==", Type::Bool, type, type); - } - - template <Type type> - std::string LogicalLessEqual(Operation operation) { - return GenerateBinaryInfix(operation, "<=", Type::Bool, type, type); - } - - template <Type type> - std::string LogicalGreaterThan(Operation operation) { - return GenerateBinaryInfix(operation, ">", Type::Bool, type, type); - } - - template <Type type> - std::string LogicalNotEqual(Operation operation) { - return GenerateBinaryInfix(operation, "!=", Type::Bool, type, type); - } - - template <Type type> - std::string LogicalGreaterEqual(Operation operation) { - return GenerateBinaryInfix(operation, ">=", Type::Bool, type, type); - } - - std::string LogicalFIsNan(Operation operation) { - return GenerateUnary(operation, "isnan", Type::Bool, Type::Float, false); - } - - std::string LogicalAssign(Operation operation) { - const Node dest = operation[0]; - const Node src = operation[1]; - - std::string target; - - if (const auto pred = std::get_if<PredicateNode>(dest)) { - ASSERT_MSG(!pred->IsNegated(), "Negating logical assignment"); - - const auto index = pred->GetIndex(); - switch (index) { - case Tegra::Shader::Pred::NeverExecute: - case Tegra::Shader::Pred::UnusedIndex: - // Writing to these predicates is a no-op - return {}; - } - target = GetPredicate(index); - } else if (const auto flag = std::get_if<InternalFlagNode>(dest)) { - target = GetInternalFlag(flag->GetFlag()); - } - - code.AddLine(target + " = " + Visit(src) + ';'); - return {}; - } - - std::string LogicalAnd(Operation operation) { - return GenerateBinaryInfix(operation, "&&", Type::Bool, Type::Bool, Type::Bool); - } - - std::string LogicalOr(Operation operation) { - return GenerateBinaryInfix(operation, "||", Type::Bool, Type::Bool, Type::Bool); - } - - std::string LogicalXor(Operation operation) { - return GenerateBinaryInfix(operation, "^^", Type::Bool, Type::Bool, Type::Bool); - } - - std::string LogicalNegate(Operation operation) { - return GenerateUnary(operation, "!", Type::Bool, Type::Bool, false); - } - - std::string LogicalPick2(Operation operation) { - const std::string pair = VisitOperand(operation, 0, Type::Bool2); - return pair + '[' + VisitOperand(operation, 1, Type::Uint) + ']'; - } - - std::string LogicalAll2(Operation operation) { - return GenerateUnary(operation, "all", Type::Bool, Type::Bool2); - } - - std::string LogicalAny2(Operation operation) { - return GenerateUnary(operation, "any", Type::Bool, Type::Bool2); - } - - std::string Logical2HLessThan(Operation operation) { - return GenerateBinaryCall(operation, "lessThan", Type::Bool2, Type::HalfFloat, - Type::HalfFloat); - } - - std::string Logical2HEqual(Operation operation) { - return GenerateBinaryCall(operation, "equal", Type::Bool2, Type::HalfFloat, - Type::HalfFloat); - } - - std::string Logical2HLessEqual(Operation operation) { - return GenerateBinaryCall(operation, "lessThanEqual", Type::Bool2, Type::HalfFloat, - Type::HalfFloat); - } - - std::string Logical2HGreaterThan(Operation operation) { - return GenerateBinaryCall(operation, "greaterThan", Type::Bool2, Type::HalfFloat, - Type::HalfFloat); - } - - std::string Logical2HNotEqual(Operation operation) { - return GenerateBinaryCall(operation, "notEqual", Type::Bool2, Type::HalfFloat, - Type::HalfFloat); - } - - std::string Logical2HGreaterEqual(Operation operation) { - return GenerateBinaryCall(operation, "greaterThanEqual", Type::Bool2, Type::HalfFloat, - Type::HalfFloat); - } - - std::string F4Texture(Operation operation) { - std::string expr = GenerateTexture(operation, "texture"); - if (std::get<MetaTexture>(operation.GetMeta()).sampler.IsShadow()) { - expr = "vec4(" + expr + ')'; - } - return expr; - } - - std::string F4TextureLod(Operation operation) { - std::string expr = GenerateTexture(operation, "textureLod"); - if (std::get<MetaTexture>(operation.GetMeta()).sampler.IsShadow()) { - expr = "vec4(" + expr + ')'; - } - return expr; - } - - std::string F4TextureGather(Operation operation) { - const bool is_shadow = std::get<MetaTexture>(operation.GetMeta()).sampler.IsShadow(); - if (is_shadow) { - return GenerateTexture(operation, "textureGather", - [](std::string ref_z) { return ref_z; }); - } else { - return GenerateTexture(operation, "textureGather", - [](std::string comp) { return "ftoi(" + comp + ')'; }); - } - } - - std::string F4TextureQueryDimensions(Operation operation) { - const auto& meta = std::get<MetaTexture>(operation.GetMeta()); - const std::string sampler = GetSampler(meta.sampler); - const std::string lod = VisitOperand(operation, 0, Type::Int); - - const std::string sizes = code.GenerateTemporal(); - code.AddLine("ivec2 " + sizes + " = textureSize(" + sampler + ", " + lod + ");"); - - const std::string mip_level = "textureQueryLevels(" + sampler + ')'; - - return "itof(ivec4(" + sizes + ", 0, " + mip_level + "))"; - } - - std::string F4TextureQueryLod(Operation operation) { - const std::string tmp = code.GenerateTemporal(); - code.AddLine("vec2 " + tmp + " = " + GenerateTexture(operation, "textureQueryLod") + - " * vec2(256);"); - - return "vec4(itof(int(" + tmp + ".y)), utof(uint(" + tmp + ".x)), 0, 0)"; - } - - std::string F4TexelFetch(Operation operation) { - constexpr std::array<const char*, 4> constructors = {"int", "ivec2", "ivec3", "ivec4"}; - const auto& meta = std::get<MetaTexture>(operation.GetMeta()); - const auto count = static_cast<u32>(operation.GetOperandsCount()); - - std::string expr = "texelFetch("; - expr += GetSampler(meta.sampler); - expr += ", "; - - expr += constructors[meta.coords_count - 1]; - expr += '('; - for (u32 i = 0; i < count; ++i) { - expr += VisitOperand(operation, i, Type::Int); - - if (i + 1 == meta.coords_count) { - expr += ')'; - } - if (i + 1 < count) { - expr += ", "; - } - } - expr += ')'; - return expr; - } - - std::string Ipa(Operation operation) { - const auto& attribute = operation[0]; - // TODO(Rodrigo): Special IPA attribute interactions - return Visit(attribute); - } - - std::string Bra(Operation operation) { - const auto target = std::get<ImmediateNode>(*operation[0]); - code.AddLine(fmt::format("jmp_to = 0x{:x}u;", target.GetValue())); - code.AddLine("break;"); - return {}; - } - - std::string PushFlowStack(Operation operation) { - const auto target = std::get<ImmediateNode>(*operation[0]); - code.AddLine(fmt::format("flow_stack[flow_stack_top] = 0x{:x}u;", target.GetValue())); - code.AddLine("flow_stack_top++;"); - return {}; - } - - std::string PopFlowStack(Operation operation) { - code.AddLine("flow_stack_top--;"); - code.AddLine("jmp_to = flow_stack[flow_stack_top];"); - code.AddLine("break;"); - return {}; - } - - std::string Exit(Operation operation) { - if (stage != ShaderStage::Fragment) { - code.AddLine("return;"); - return {}; - } - const auto& used_registers = ir.GetRegisters(); - const auto SafeGetRegister = [&](u32 reg) -> std::string { - // TODO(Rodrigo): Replace with contains once C++20 releases - if (used_registers.find(reg) != used_registers.end()) { - return GetRegister(reg); - } - return "0.0f"; - }; - - UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, "Sample mask write is unimplemented"); - - code.AddLine("if (alpha_test[0] != 0) {"); - ++code.scope; - // We start on the register containing the alpha value in the first RT. - u32 current_reg = 3; - for (u32 render_target = 0; render_target < Maxwell::NumRenderTargets; ++render_target) { - // TODO(Blinkhawk): verify the behavior of alpha testing on hardware when - // multiple render targets are used. - if (header.ps.IsColorComponentOutputEnabled(render_target, 0) || - header.ps.IsColorComponentOutputEnabled(render_target, 1) || - header.ps.IsColorComponentOutputEnabled(render_target, 2) || - header.ps.IsColorComponentOutputEnabled(render_target, 3)) { - code.AddLine( - fmt::format("if (!AlphaFunc({})) discard;", SafeGetRegister(current_reg))); - current_reg += 4; - } - } - --code.scope; - code.AddLine('}'); - - // Write the color outputs using the data in the shader registers, disabled - // rendertargets/components are skipped in the register assignment. - current_reg = 0; - for (u32 render_target = 0; render_target < Maxwell::NumRenderTargets; ++render_target) { - // TODO(Subv): Figure out how dual-source blending is configured in the Switch. - for (u32 component = 0; component < 4; ++component) { - if (header.ps.IsColorComponentOutputEnabled(render_target, component)) { - code.AddLine(fmt::format("FragColor{}[{}] = {};", render_target, component, - SafeGetRegister(current_reg))); - ++current_reg; - } - } - } - - if (header.ps.omap.depth) { - // The depth output is always 2 registers after the last color output, and current_reg - // already contains one past the last color register. - code.AddLine("gl_FragDepth = " + SafeGetRegister(current_reg + 1) + ';'); - } - - code.AddLine("return;"); - return {}; - } - - std::string Kil(Operation operation) { - // Enclose "discard" in a conditional, so that GLSL compilation does not complain - // about unexecuted instructions that may follow this. - code.AddLine("if (true) {"); - ++code.scope; - code.AddLine("discard;"); - --code.scope; - code.AddLine("}"); - return {}; - } - - std::string EmitVertex(Operation operation) { - ASSERT_MSG(stage == ShaderStage::Geometry, - "EmitVertex is expected to be used in a geometry shader."); - - // If a geometry shader is attached, it will always flip (it's the last stage before - // fragment). For more info about flipping, refer to gl_shader_gen.cpp. - code.AddLine("position.xy *= viewport_flip.xy;"); - code.AddLine("gl_Position = position;"); - code.AddLine("position.w = 1.0;"); - code.AddLine("EmitVertex();"); - return {}; - } - - std::string EndPrimitive(Operation operation) { - ASSERT_MSG(stage == ShaderStage::Geometry, - "EndPrimitive is expected to be used in a geometry shader."); - - code.AddLine("EndPrimitive();"); - return {}; - } - - std::string YNegate(Operation operation) { - // Config pack's third value is Y_NEGATE's state. - return "uintBitsToFloat(config_pack[2])"; - } - - static constexpr OperationDecompilersArray operation_decompilers = { - &GLSLDecompiler::Assign, - &GLSLDecompiler::AssignComposite, - &GLSLDecompiler::AssignCompositeHalf, - - &GLSLDecompiler::Composite, - &GLSLDecompiler::Select, - - &GLSLDecompiler::Add<Type::Float>, - &GLSLDecompiler::Mul<Type::Float>, - &GLSLDecompiler::Div<Type::Float>, - &GLSLDecompiler::Fma<Type::Float>, - &GLSLDecompiler::Negate<Type::Float>, - &GLSLDecompiler::Absolute<Type::Float>, - &GLSLDecompiler::FClamp, - &GLSLDecompiler::Min<Type::Float>, - &GLSLDecompiler::Max<Type::Float>, - &GLSLDecompiler::FCos, - &GLSLDecompiler::FSin, - &GLSLDecompiler::FExp2, - &GLSLDecompiler::FLog2, - &GLSLDecompiler::FInverseSqrt, - &GLSLDecompiler::FSqrt, - &GLSLDecompiler::FRoundEven, - &GLSLDecompiler::FFloor, - &GLSLDecompiler::FCeil, - &GLSLDecompiler::FTrunc, - &GLSLDecompiler::FCastInteger<Type::Int>, - &GLSLDecompiler::FCastInteger<Type::Uint>, - - &GLSLDecompiler::Add<Type::Int>, - &GLSLDecompiler::Mul<Type::Int>, - &GLSLDecompiler::Div<Type::Int>, - &GLSLDecompiler::Negate<Type::Int>, - &GLSLDecompiler::Absolute<Type::Int>, - &GLSLDecompiler::Min<Type::Int>, - &GLSLDecompiler::Max<Type::Int>, - - &GLSLDecompiler::ICastFloat, - &GLSLDecompiler::ICastUnsigned, - &GLSLDecompiler::LogicalShiftLeft<Type::Int>, - &GLSLDecompiler::ILogicalShiftRight, - &GLSLDecompiler::IArithmeticShiftRight, - &GLSLDecompiler::BitwiseAnd<Type::Int>, - &GLSLDecompiler::BitwiseOr<Type::Int>, - &GLSLDecompiler::BitwiseXor<Type::Int>, - &GLSLDecompiler::BitwiseNot<Type::Int>, - &GLSLDecompiler::BitfieldInsert<Type::Int>, - &GLSLDecompiler::BitCount<Type::Int>, - - &GLSLDecompiler::Add<Type::Uint>, - &GLSLDecompiler::Mul<Type::Uint>, - &GLSLDecompiler::Div<Type::Uint>, - &GLSLDecompiler::Min<Type::Uint>, - &GLSLDecompiler::Max<Type::Uint>, - &GLSLDecompiler::UCastFloat, - &GLSLDecompiler::UCastSigned, - &GLSLDecompiler::LogicalShiftLeft<Type::Uint>, - &GLSLDecompiler::UShiftRight, - &GLSLDecompiler::UShiftRight, - &GLSLDecompiler::BitwiseAnd<Type::Uint>, - &GLSLDecompiler::BitwiseOr<Type::Uint>, - &GLSLDecompiler::BitwiseXor<Type::Uint>, - &GLSLDecompiler::BitwiseNot<Type::Uint>, - &GLSLDecompiler::BitfieldInsert<Type::Uint>, - &GLSLDecompiler::BitCount<Type::Uint>, - - &GLSLDecompiler::Add<Type::HalfFloat>, - &GLSLDecompiler::Mul<Type::HalfFloat>, - &GLSLDecompiler::Fma<Type::HalfFloat>, - &GLSLDecompiler::Absolute<Type::HalfFloat>, - &GLSLDecompiler::HNegate, - &GLSLDecompiler::HMergeF32, - &GLSLDecompiler::HMergeH0, - &GLSLDecompiler::HMergeH1, - - &GLSLDecompiler::LogicalAssign, - &GLSLDecompiler::LogicalAnd, - &GLSLDecompiler::LogicalOr, - &GLSLDecompiler::LogicalXor, - &GLSLDecompiler::LogicalNegate, - &GLSLDecompiler::LogicalPick2, - &GLSLDecompiler::LogicalAll2, - &GLSLDecompiler::LogicalAny2, - - &GLSLDecompiler::LogicalLessThan<Type::Float>, - &GLSLDecompiler::LogicalEqual<Type::Float>, - &GLSLDecompiler::LogicalLessEqual<Type::Float>, - &GLSLDecompiler::LogicalGreaterThan<Type::Float>, - &GLSLDecompiler::LogicalNotEqual<Type::Float>, - &GLSLDecompiler::LogicalGreaterEqual<Type::Float>, - &GLSLDecompiler::LogicalFIsNan, - - &GLSLDecompiler::LogicalLessThan<Type::Int>, - &GLSLDecompiler::LogicalEqual<Type::Int>, - &GLSLDecompiler::LogicalLessEqual<Type::Int>, - &GLSLDecompiler::LogicalGreaterThan<Type::Int>, - &GLSLDecompiler::LogicalNotEqual<Type::Int>, - &GLSLDecompiler::LogicalGreaterEqual<Type::Int>, - - &GLSLDecompiler::LogicalLessThan<Type::Uint>, - &GLSLDecompiler::LogicalEqual<Type::Uint>, - &GLSLDecompiler::LogicalLessEqual<Type::Uint>, - &GLSLDecompiler::LogicalGreaterThan<Type::Uint>, - &GLSLDecompiler::LogicalNotEqual<Type::Uint>, - &GLSLDecompiler::LogicalGreaterEqual<Type::Uint>, - - &GLSLDecompiler::Logical2HLessThan, - &GLSLDecompiler::Logical2HEqual, - &GLSLDecompiler::Logical2HLessEqual, - &GLSLDecompiler::Logical2HGreaterThan, - &GLSLDecompiler::Logical2HNotEqual, - &GLSLDecompiler::Logical2HGreaterEqual, - - &GLSLDecompiler::F4Texture, - &GLSLDecompiler::F4TextureLod, - &GLSLDecompiler::F4TextureGather, - &GLSLDecompiler::F4TextureQueryDimensions, - &GLSLDecompiler::F4TextureQueryLod, - &GLSLDecompiler::F4TexelFetch, - - &GLSLDecompiler::Ipa, - - &GLSLDecompiler::Bra, - &GLSLDecompiler::PushFlowStack, // Ssy - &GLSLDecompiler::PushFlowStack, // Brk - &GLSLDecompiler::PopFlowStack, // Sync - &GLSLDecompiler::PopFlowStack, // Brk - &GLSLDecompiler::Exit, - &GLSLDecompiler::Kil, - - &GLSLDecompiler::EmitVertex, - &GLSLDecompiler::EndPrimitive, - - &GLSLDecompiler::YNegate, - }; - - std::string GetRegister(u32 index) const { - return GetDeclarationWithSuffix(index, "gpr"); - } - - std::string GetPredicate(Tegra::Shader::Pred pred) const { - return GetDeclarationWithSuffix(static_cast<u32>(pred), "pred"); - } - - std::string GetInputAttribute(Attribute::Index attribute) const { - const auto index{static_cast<u32>(attribute) - - static_cast<u32>(Attribute::Index::Attribute_0)}; - return GetDeclarationWithSuffix(index, "input_attr"); - } - - std::string GetOutputAttribute(Attribute::Index attribute) const { - const auto index{static_cast<u32>(attribute) - - static_cast<u32>(Attribute::Index::Attribute_0)}; - return GetDeclarationWithSuffix(index, "output_attr"); - } - - std::string GetConstBuffer(u32 index) const { - return GetDeclarationWithSuffix(index, "cbuf"); - } - - std::string GetConstBufferBlock(u32 index) const { - return GetDeclarationWithSuffix(index, "cbuf_block"); - } - - std::string GetLocalMemory() const { - return "lmem_" + suffix; - } - - std::string GetInternalFlag(InternalFlag flag) const { - constexpr std::array<const char*, 4> InternalFlagNames = {"zero_flag", "sign_flag", - "carry_flag", "overflow_flag"}; - const auto index = static_cast<u32>(flag); - ASSERT(index < static_cast<u32>(InternalFlag::Amount)); - - return std::string(InternalFlagNames[index]) + '_' + suffix; - } - - std::string GetSampler(const Sampler& sampler) const { - return GetDeclarationWithSuffix(static_cast<u32>(sampler.GetIndex()), "sampler"); - } - - std::string GetDeclarationWithSuffix(u32 index, const std::string& name) const { - return name + '_' + std::to_string(index) + '_' + suffix; - } - - const ShaderIR& ir; - const ShaderStage stage; - const std::string suffix; - const Header header; - - ShaderWriter code; -}; - -std::string GetCommonDeclarations() { - return "#define MAX_CONSTBUFFER_ELEMENTS " + std::to_string(MAX_CONSTBUFFER_ELEMENTS) + - "\n" - "#define ftoi floatBitsToInt\n" - "#define ftou floatBitsToUint\n" - "#define itof intBitsToFloat\n" - "#define utof uintBitsToFloat\n\n" - "float fromHalf2(vec2 pair) {\n" - " return utof(packHalf2x16(pair));\n" - "}\n\n" - "vec2 toHalf2(float value) {\n" - " return unpackHalf2x16(ftou(value));\n" - "}\n\n"; -} - -ProgramResult Decompile(const ShaderIR& ir, Maxwell::ShaderStage stage, const std::string& suffix) { - GLSLDecompiler decompiler(ir, stage, suffix); - decompiler.Decompile(); - return {decompiler.GetResult(), decompiler.GetShaderEntries()}; -} - -} // namespace OpenGL::GLShader
\ No newline at end of file diff --git a/src/video_core/shader/glsl_decompiler.h b/src/video_core/shader/glsl_decompiler.h deleted file mode 100644 index 396a560d8..000000000 --- a/src/video_core/shader/glsl_decompiler.h +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2018 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <array> -#include <string> -#include <utility> -#include <vector> -#include "common/common_types.h" -#include "video_core/engines/maxwell_3d.h" -#include "video_core/shader/shader_ir.h" - -namespace VideoCommon::Shader { -class ShaderIR; -} - -namespace OpenGL::GLShader { - -using Maxwell = Tegra::Engines::Maxwell3D::Regs; - -class ConstBufferEntry : public VideoCommon::Shader::ConstBuffer { -public: - explicit ConstBufferEntry(const VideoCommon::Shader::ConstBuffer& entry, - Maxwell::ShaderStage stage, const std::string& name, u32 index) - : VideoCommon::Shader::ConstBuffer{entry}, stage{stage}, name{name}, index{index} {} - - const std::string& GetName() const { - return name; - } - - Maxwell::ShaderStage GetStage() const { - return stage; - } - - u32 GetIndex() const { - return index; - } - - u32 GetHash() const { - return (static_cast<u32>(stage) << 16) | index; - } - -private: - std::string name; - Maxwell::ShaderStage stage{}; - u32 index{}; -}; - -class SamplerEntry : public VideoCommon::Shader::Sampler { -public: - explicit SamplerEntry(const VideoCommon::Shader::Sampler& entry, Maxwell::ShaderStage stage, - const std::string& name) - : VideoCommon::Shader::Sampler{entry}, stage{stage}, name{name} {} - - const std::string& GetName() const { - return name; - } - - Maxwell::ShaderStage GetStage() const { - return stage; - } - - u32 GetHash() const { - return (static_cast<u32>(stage) << 16) | static_cast<u32>(GetIndex()); - } - -private: - std::string name; - Maxwell::ShaderStage stage{}; -}; - -struct ShaderEntries { - std::vector<ConstBufferEntry> const_buffers; - std::vector<SamplerEntry> samplers; - std::array<bool, Maxwell::NumClipDistances> clip_distances{}; - std::size_t shader_length{}; -}; - -using ProgramResult = std::pair<std::string, ShaderEntries>; - -std::string GetCommonDeclarations(); - -ProgramResult Decompile(const VideoCommon::Shader::ShaderIR& ir, Maxwell::ShaderStage stage, - const std::string& suffix); - -} // namespace OpenGL::GLShader
\ No newline at end of file |