From 8a6fc529a968e007f01464abadd32f9b5eb0a26c Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 24 Jun 2019 21:25:38 -0400 Subject: shader_ir: Implement BRX & BRA.CC --- src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/video_core/renderer_opengl') diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 5f2f1510c..cedfe30b1 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -1555,6 +1555,14 @@ private: return {}; } + std::string BranchIndirect(Operation operation) { + const std::string op_a = VisitOperand(operation, 0, Type::Uint); + + code.AddLine("jmp_to = {};", op_a); + code.AddLine("break;"); + return {}; + } + std::string PushFlowStack(Operation operation) { const auto stack = std::get(operation.GetMeta()); const auto target = std::get_if(&*operation[0]); @@ -1789,6 +1797,7 @@ private: &GLSLDecompiler::ImageStore, &GLSLDecompiler::Branch, + &GLSLDecompiler::BranchIndirect, &GLSLDecompiler::PushFlowStack, &GLSLDecompiler::PopFlowStack, &GLSLDecompiler::Exit, -- cgit v1.2.3 From 459fce3a8f26241ff2a68c323e75fb70e7e1ba79 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 25 Jun 2019 07:57:32 -0400 Subject: shader_ir: propagate shader size to the IR --- src/video_core/renderer_opengl/gl_shader_cache.cpp | 22 +++++++++++++++------- src/video_core/renderer_opengl/gl_shader_gen.cpp | 8 ++++---- src/video_core/renderer_opengl/gl_shader_gen.h | 2 ++ src/video_core/shader/decode.cpp | 6 +++--- src/video_core/shader/shader_ir.cpp | 4 ++-- src/video_core/shader/shader_ir.h | 3 ++- 6 files changed, 28 insertions(+), 17 deletions(-) (limited to 'src/video_core/renderer_opengl') diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index f9b2b03a0..5d76ee12d 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -129,9 +129,11 @@ std::size_t CalculateProgramSize(const GLShader::ProgramCode& program) { /// Hashes one (or two) program streams u64 GetUniqueIdentifier(Maxwell::ShaderProgram program_type, const ProgramCode& code, - const ProgramCode& code_b) { - u64 unique_identifier = - Common::CityHash64(reinterpret_cast(code.data()), CalculateProgramSize(code)); + const ProgramCode& code_b, std::size_t size_a = 0, std::size_t size_b = 0) { + if (size_a == 0) { + size_a = CalculateProgramSize(code); + } + u64 unique_identifier = Common::CityHash64(reinterpret_cast(code.data()), size_a); if (program_type != Maxwell::ShaderProgram::VertexA) { return unique_identifier; } @@ -140,8 +142,11 @@ u64 GetUniqueIdentifier(Maxwell::ShaderProgram program_type, const ProgramCode& std::size_t seed = 0; boost::hash_combine(seed, unique_identifier); - const u64 identifier_b = Common::CityHash64(reinterpret_cast(code_b.data()), - CalculateProgramSize(code_b)); + if (size_b == 0) { + size_b = CalculateProgramSize(code_b); + } + const u64 identifier_b = + Common::CityHash64(reinterpret_cast(code_b.data()), size_b); boost::hash_combine(seed, identifier_b); return static_cast(seed); } @@ -150,14 +155,17 @@ u64 GetUniqueIdentifier(Maxwell::ShaderProgram program_type, const ProgramCode& GLShader::ProgramResult CreateProgram(const Device& device, Maxwell::ShaderProgram program_type, ProgramCode program_code, ProgramCode program_code_b) { GLShader::ShaderSetup setup(program_code); + setup.program.size_a = CalculateProgramSize(program_code); + setup.program.size_b = 0; if (program_type == Maxwell::ShaderProgram::VertexA) { // VertexB is always enabled, so when VertexA is enabled, we have two vertex shaders. // Conventional HW does not support this, so we combine VertexA and VertexB into one // stage here. setup.SetProgramB(program_code_b); + setup.program.size_b = CalculateProgramSize(program_code_b); } - setup.program.unique_identifier = - GetUniqueIdentifier(program_type, program_code, program_code_b); + setup.program.unique_identifier = GetUniqueIdentifier( + program_type, program_code, program_code_b, setup.program.size_a, setup.program.size_b); switch (program_type) { case Maxwell::ShaderProgram::VertexA: diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 9148629ec..f9ee8429e 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -29,14 +29,14 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config { }; )"; - const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET); + const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET, setup.program.size_a); ProgramResult program = Decompile(device, program_ir, Maxwell3D::Regs::ShaderStage::Vertex, "vertex"); out += program.first; if (setup.IsDualProgram()) { - const ShaderIR program_ir_b(setup.program.code_b, PROGRAM_OFFSET); + const ShaderIR program_ir_b(setup.program.code_b, PROGRAM_OFFSET, setup.program.size_b); ProgramResult program_b = Decompile(device, program_ir_b, Maxwell3D::Regs::ShaderStage::Vertex, "vertex_b"); @@ -80,7 +80,7 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform gs_config { }; )"; - const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET); + const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET, setup.program.size_a); ProgramResult program = Decompile(device, program_ir, Maxwell3D::Regs::ShaderStage::Geometry, "geometry"); out += program.first; @@ -115,7 +115,7 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform fs_config { }; )"; - const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET); + const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET, setup.program.size_a); ProgramResult program = Decompile(device, program_ir, Maxwell3D::Regs::ShaderStage::Fragment, "fragment"); diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index 0536c8a03..7cbc590f8 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h @@ -27,6 +27,8 @@ struct ShaderSetup { ProgramCode code; ProgramCode code_b; // Used for dual vertex shaders u64 unique_identifier; + std::size_t size_a; + std::size_t size_b; } program; /// Used in scenarios where we have a dual vertex shaders diff --git a/src/video_core/shader/decode.cpp b/src/video_core/shader/decode.cpp index 65029d35e..09f55bd21 100644 --- a/src/video_core/shader/decode.cpp +++ b/src/video_core/shader/decode.cpp @@ -39,7 +39,7 @@ void ShaderIR::Decode() { std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header)); ShaderCharacteristics shader_info{}; - bool can_proceed = ScanFlow(program_code, MAX_PROGRAM_LENGTH, main_offset, shader_info); + bool can_proceed = ScanFlow(program_code, program_code.size(), main_offset, shader_info); if (can_proceed) { coverage_begin = shader_info.start; coverage_end = shader_info.end; @@ -52,12 +52,12 @@ void ShaderIR::Decode() { } return; } - LOG_CRITICAL(HW_GPU, "Flow Analysis failed, falling back to brute force compiling"); + LOG_WARNING(HW_GPU, "Flow Analysis failed, falling back to brute force compiling"); // Now we need to deal with an undecompilable shader. We need to brute force // a shader that captures every position. coverage_begin = shader_info.start; - const u32 shader_end = static_cast(MAX_PROGRAM_LENGTH); + const u32 shader_end = static_cast(program_size / sizeof(u64)); coverage_end = shader_end; for (u32 label = main_offset; label < shader_end; label++) { basic_blocks.insert({label, DecodeRange(label, label + 1)}); diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp index 11b545cca..5994bfc4e 100644 --- a/src/video_core/shader/shader_ir.cpp +++ b/src/video_core/shader/shader_ir.cpp @@ -22,8 +22,8 @@ using Tegra::Shader::PredCondition; using Tegra::Shader::PredOperation; using Tegra::Shader::Register; -ShaderIR::ShaderIR(const ProgramCode& program_code, u32 main_offset) - : program_code{program_code}, main_offset{main_offset} { +ShaderIR::ShaderIR(const ProgramCode& program_code, u32 main_offset, const std::size_t size) + : program_code{program_code}, main_offset{main_offset}, program_size{size} { Decode(); } diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index e71462e02..a67d4f390 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h @@ -65,7 +65,7 @@ struct GlobalMemoryUsage { class ShaderIR final { public: - explicit ShaderIR(const ProgramCode& program_code, u32 main_offset); + explicit ShaderIR(const ProgramCode& program_code, u32 main_offset, std::size_t size); ~ShaderIR(); const std::map& GetBasicBlocks() const { @@ -316,6 +316,7 @@ private: const ProgramCode& program_code; const u32 main_offset; + const std::size_t program_size; u32 coverage_begin{}; u32 coverage_end{}; -- cgit v1.2.3 From d5533b440c764093c04a4859b30fc78ddb0e0bbe Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 25 Jun 2019 13:03:51 -0400 Subject: shader_ir: Unify blocks in decompiled shaders. --- .../renderer_opengl/gl_shader_decompiler.cpp | 10 +++-- src/video_core/shader/control_flow.cpp | 47 +++++++--------------- src/video_core/shader/control_flow.h | 3 +- src/video_core/shader/decode.cpp | 35 ++++++++++++---- src/video_core/shader/decode/other.cpp | 30 ++++++++++---- src/video_core/shader/node.h | 12 +++--- src/video_core/shader/shader_ir.h | 6 +++ 7 files changed, 85 insertions(+), 58 deletions(-) (limited to 'src/video_core/renderer_opengl') diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index cedfe30b1..bfc975a04 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -191,10 +191,12 @@ public: // 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; - for (const auto stack : std::array{MetaStackClass::Ssy, MetaStackClass::Pbk}) { - code.AddLine("uint {}[{}];", FlowStackName(stack), FLOW_STACK_SIZE); - code.AddLine("uint {} = 0u;", FlowStackTopName(stack)); + if (!ir.IsFlowStackDisabled()) { + constexpr u32 FLOW_STACK_SIZE = 20; + for (const auto stack : std::array{MetaStackClass::Ssy, MetaStackClass::Pbk}) { + code.AddLine("uint {}[{}];", FlowStackName(stack), FLOW_STACK_SIZE); + code.AddLine("uint {} = 0u;", FlowStackTopName(stack)); + } } code.AddLine("while (true) {{"); diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp index 3af4c6190..c99d95b57 100644 --- a/src/video_core/shader/control_flow.cpp +++ b/src/video_core/shader/control_flow.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -104,28 +105,6 @@ struct BlockInfo { } }; -struct Stamp { - Stamp() = default; - Stamp(u32 address, u32 target) : address{address}, target{target} {} - u32 address{}; - u32 target{}; - bool operator==(const Stamp& sb) const { - return std::tie(address, target) == std::tie(sb.address, sb.target); - } - bool operator<(const Stamp& sb) const { - return address < sb.address; - } - bool operator>(const Stamp& sb) const { - return address > sb.address; - } - bool operator<=(const Stamp& sb) const { - return address <= sb.address; - } - bool operator>=(const Stamp& sb) const { - return address >= sb.address; - } -}; - struct CFGRebuildState { explicit CFGRebuildState(const ProgramCode& program_code, const std::size_t program_size) : program_code{program_code}, program_size{program_size} { @@ -144,8 +123,8 @@ struct CFGRebuildState { std::list queries{}; std::unordered_map registered{}; std::unordered_set labels{}; - std::set ssy_labels; - std::set pbk_labels; + std::map ssy_labels; + std::map pbk_labels; std::unordered_map stacks{}; const ProgramCode& program_code; const std::size_t program_size; @@ -393,7 +372,7 @@ bool TryInspectAddress(CFGRebuildState& state) { } case BlockCollision::Inside: { // This case is the tricky one: - // We need to Split the block in 2 sepprate blocks + // We need to Split the block in 2 sepparate blocks auto it = search_result.second; block_info = CreateBlockInfo(state, address, it->end); it->end = address - 1; @@ -428,13 +407,11 @@ bool TryInspectAddress(CFGRebuildState& state) { } bool TryQuery(CFGRebuildState& state) { - auto gather_labels = ([](ControlStack& cc, std::set labels, BlockInfo& block) { - Stamp start{block.start, 0}; - Stamp end{block.end, 0}; - auto gather_start = labels.lower_bound(start); - auto gather_end = labels.upper_bound(end); + auto gather_labels = ([](ControlStack& cc, std::map& labels, BlockInfo& block) { + auto gather_start = labels.lower_bound(block.start); + auto gather_end = labels.upper_bound(block.end); while (gather_start != gather_end) { - cc.Push(gather_start->target); + cc.Push(gather_start->second); gather_start++; } }); @@ -444,9 +421,13 @@ bool TryQuery(CFGRebuildState& state) { Query& q = state.queries.front(); u32 block_index = state.registered[q.address]; BlockInfo& block = state.block_info[block_index]; + // If the block is visted, check if the stacks match, else gather the ssy/pbk + // labels into the current stack and look if the branch at the end of the block + // consumes a label. Schedule new queries accordingly if (block.visited) { BlockStack& stack = state.stacks[q.address]; - bool all_okay = q.ssy_stack.Compare(stack.ssy_stack) && q.pbk_stack.Compare(stack.pbk_stack); + bool all_okay = (stack.ssy_stack.Size() == 0 || q.ssy_stack.Compare(stack.ssy_stack)) && + (stack.pbk_stack.Size() == 0 || q.pbk_stack.Compare(stack.pbk_stack)); state.queries.pop_front(); return all_okay; } @@ -523,8 +504,10 @@ bool ScanFlow(const ProgramCode& program_code, u32 program_size, u32 start_addre result_out.blocks.push_back(new_block); } if (result_out.decompilable) { + result_out.labels = std::move(state.labels); return true; } + // If it's not decompilable, merge the unlabelled blocks together auto back = result_out.blocks.begin(); auto next = std::next(back); while (next != result_out.blocks.end()) { diff --git a/src/video_core/shader/control_flow.h b/src/video_core/shader/control_flow.h index f5d37a231..4a2cd622c 100644 --- a/src/video_core/shader/control_flow.h +++ b/src/video_core/shader/control_flow.h @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include "video_core/engines/shader_bytecode.h" #include "video_core/shader/shader_ir.h" @@ -48,6 +48,7 @@ struct ShaderCharacteristics { bool decompilable{}; u32 start; u32 end; + std::unordered_set labels{}; }; bool ScanFlow(const ProgramCode& program_code, u32 program_size, u32 start_address, diff --git a/src/video_core/shader/decode.cpp b/src/video_core/shader/decode.cpp index 1a74b70cb..f9b1960da 100644 --- a/src/video_core/shader/decode.cpp +++ b/src/video_core/shader/decode.cpp @@ -38,32 +38,47 @@ constexpr bool IsSchedInstruction(u32 offset, u32 main_offset) { void ShaderIR::Decode() { std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header)); + disable_flow_stack = false; ShaderCharacteristics shader_info{}; bool can_proceed = ScanFlow(program_code, program_code.size(), main_offset, shader_info); if (can_proceed) { coverage_begin = shader_info.start; coverage_end = shader_info.end; if (shader_info.decompilable) { + disable_flow_stack = true; + auto insert_block = ([this](NodeBlock& nodes, u32 label) { + if (label == exit_branch) { + return; + } + basic_blocks.insert({label, nodes}); + }); std::list& blocks = shader_info.blocks; + NodeBlock current_block; + u32 current_label = exit_branch; for (auto& block : blocks) { - NodeBlock nodes; + if (shader_info.labels.count(block.start) != 0) { + insert_block(current_block, current_label); + current_block.clear(); + current_label = block.start; + } if (!block.ignore_branch) { - nodes = DecodeRange(block.start, block.end); - InsertControlFlow(nodes, block); + DecodeRangeInner(current_block, block.start, block.end); + InsertControlFlow(current_block, block); } else { - nodes = DecodeRange(block.start, block.end + 1); + DecodeRangeInner(current_block, block.start, block.end + 1); } - basic_blocks.insert({block.start, nodes}); } + insert_block(current_block, current_label); return; } + LOG_WARNING(HW_GPU, "Flow Stack Removing Failed! Falling back to old method"); // we can't decompile it, fallback to standard method for (const auto& block : shader_info.blocks) { basic_blocks.insert({block.start, DecodeRange(block.start, block.end + 1)}); } return; } - LOG_WARNING(HW_GPU, "Flow Analysis failed, falling back to brute force compiling"); + LOG_WARNING(HW_GPU, "Flow Analysis Failed! Falling back to brute force compiling"); // Now we need to deal with an undecompilable shader. We need to brute force // a shader that captures every position. @@ -78,10 +93,14 @@ void ShaderIR::Decode() { NodeBlock ShaderIR::DecodeRange(u32 begin, u32 end) { NodeBlock basic_block; + DecodeRangeInner(basic_block, begin, end); + return basic_block; +} + +void ShaderIR::DecodeRangeInner(NodeBlock& bb, u32 begin, u32 end) { for (u32 pc = begin; pc < (begin > end ? MAX_PROGRAM_LENGTH : end);) { - pc = DecodeInstr(basic_block, pc); + pc = DecodeInstr(bb, pc); } - return basic_block; } void ShaderIR::InsertControlFlow(NodeBlock& bb, const ShaderBlock& block) { diff --git a/src/video_core/shader/decode/other.cpp b/src/video_core/shader/decode/other.cpp index ed3c63781..42e3de02f 100644 --- a/src/video_core/shader/decode/other.cpp +++ b/src/video_core/shader/decode/other.cpp @@ -98,9 +98,10 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { } else { const u32 target = pc + 1; const Node op_a = GetConstBuffer(instr.cbuf36.index, instr.cbuf36.GetOffset()); - const Node convert = SignedOperation(OperationCode::IArithmeticShiftRight, - true, PRECISE, op_a, Immediate(3)); - const Node operand = Operation(OperationCode::IAdd, PRECISE, convert, Immediate(target)); + const Node convert = SignedOperation(OperationCode::IArithmeticShiftRight, true, + PRECISE, op_a, Immediate(3)); + const Node operand = + Operation(OperationCode::IAdd, PRECISE, convert, Immediate(target)); branch = Operation(OperationCode::BranchIndirect, convert); } @@ -119,14 +120,14 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { const Node index = GetRegister(instr.gpr8); const Node op_a = GetConstBufferIndirect(instr.cbuf36.index, instr.cbuf36.GetOffset() + 0, index); - const Node convert = SignedOperation(OperationCode::IArithmeticShiftRight, - true, PRECISE, op_a, Immediate(3)); + const Node convert = SignedOperation(OperationCode::IArithmeticShiftRight, true, + PRECISE, op_a, Immediate(3)); operand = Operation(OperationCode::IAdd, PRECISE, convert, Immediate(target)); } else { const s32 target = pc + instr.brx.GetBranchExtend(); const Node op_a = GetRegister(instr.gpr8); - const Node convert = SignedOperation(OperationCode::IArithmeticShiftRight, - true, PRECISE, op_a, Immediate(3)); + const Node convert = SignedOperation(OperationCode::IArithmeticShiftRight, true, + PRECISE, op_a, Immediate(3)); operand = Operation(OperationCode::IAdd, PRECISE, convert, Immediate(target)); } const Node branch = Operation(OperationCode::BranchIndirect, operand); @@ -143,6 +144,10 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0, "Constant buffer flow is not supported"); + if (disable_flow_stack) { + break; + } + // The SSY opcode tells the GPU where to re-converge divergent execution paths with SYNC. const u32 target = pc + instr.bra.GetBranchTarget(); bb.push_back( @@ -153,6 +158,10 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0, "Constant buffer PBK is not supported"); + if (disable_flow_stack) { + break; + } + // PBK pushes to a stack the address where BRK will jump to. const u32 target = pc + instr.bra.GetBranchTarget(); bb.push_back( @@ -164,6 +173,10 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "SYNC condition code used: {}", static_cast(cc)); + if (disable_flow_stack) { + break; + } + // The SYNC opcode jumps to the address previously set by the SSY opcode bb.push_back(Operation(OperationCode::PopFlowStack, MetaStackClass::Ssy)); break; @@ -172,6 +185,9 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { const Tegra::Shader::ConditionCode cc = instr.flow_condition_code; UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "BRK condition code used: {}", static_cast(cc)); + if (disable_flow_stack) { + break; + } // The BRK opcode jumps to the address previously set by the PBK opcode bb.push_back(Operation(OperationCode::PopFlowStack, MetaStackClass::Pbk)); diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h index e468758a6..7427ed896 100644 --- a/src/video_core/shader/node.h +++ b/src/video_core/shader/node.h @@ -148,12 +148,12 @@ enum class OperationCode { ImageStore, /// (MetaImage, float[N] coords) -> void - Branch, /// (uint branch_target) -> void - BranchIndirect,/// (uint branch_target) -> void - PushFlowStack, /// (uint branch_target) -> void - PopFlowStack, /// () -> void - Exit, /// () -> void - Discard, /// () -> void + Branch, /// (uint branch_target) -> void + BranchIndirect, /// (uint branch_target) -> void + PushFlowStack, /// (uint branch_target) -> void + PopFlowStack, /// () -> void + Exit, /// () -> void + Discard, /// () -> void EmitVertex, /// () -> void EndPrimitive, /// () -> void diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index a6729064b..928ac7cb5 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h @@ -123,10 +123,15 @@ public: return header; } + bool IsFlowStackDisabled() const { + return disable_flow_stack; + } + private: void Decode(); NodeBlock DecodeRange(u32 begin, u32 end); + void DecodeRangeInner(NodeBlock& bb, u32 begin, u32 end); void InsertControlFlow(NodeBlock& bb, const ShaderBlock& block); /** @@ -320,6 +325,7 @@ private: const ProgramCode& program_code; const u32 main_offset; const std::size_t program_size; + bool disable_flow_stack{}; u32 coverage_begin{}; u32 coverage_end{}; -- cgit v1.2.3