ShaderIR: Implement Multiple Functions in GLSL.

This commit is contained in:
Fernando Sahmkow
2021-01-03 13:06:22 +01:00
committed by Morph
parent b75a9b20e4
commit 6b09561ef6
10 changed files with 93 additions and 19 deletions

View File

@@ -1178,11 +1178,7 @@ void ARBDecompiler::VisitAST(const ASTNode& node) {
if (ast_return->kills) {
AddLine("KIL TR;");
} else {
if (context_func->IsMain()) {
Exit();
} else {
AddLine("RET;");
}
Exit();
}
if (!is_true) {
AddLine("ENDIF;");
@@ -1487,7 +1483,7 @@ std::string ARBDecompiler::GlobalMemoryPointer(const GmemNode& gmem) {
}
void ARBDecompiler::Exit() {
if (stage != ShaderType::Fragment) {
if (!context_func->IsMain() || stage != ShaderType::Fragment) {
AddLine("RET;");
return;
}

View File

@@ -435,6 +435,25 @@ public:
DeclareCustomVariables();
DeclarePhysicalAttributeReader();
const auto& subfunctions = ir.GetSubFunctions();
auto it = subfunctions.rbegin();
while (it != subfunctions.rend()) {
context_func = *it;
code.AddLine("void func_{}() {{", context_func->GetId());
++code.scope;
if (context_func->IsDecompiled()) {
DecompileAST();
} else {
DecompileBranchMode();
}
--code.scope;
code.AddLine("}}");
it++;
}
context_func = ir.GetMainFunction();
code.AddLine("void main() {{");
@@ -1133,6 +1152,11 @@ private:
return {};
}
if (const auto func_call = std::get_if<FunctionCallNode>(&*node)) {
code.AddLine("func_{}();", func_call->GetFuncId());
return {};
}
if (const auto comment = std::get_if<CommentNode>(&*node)) {
code.AddLine("// " + comment->GetText());
return {};
@@ -2269,7 +2293,9 @@ private:
}
Expression Exit(Operation operation) {
PreExit();
if (context_func->IsMain()) {
PreExit();
}
code.AddLine("return;");
return {};
}

View File

@@ -2177,7 +2177,9 @@ private:
}
Expression Exit(Operation operation) {
PreExit();
if (context_func->IsMain()) {
PreExit();
}
inside_branch = true;
if (conditional_branch_set) {
OpReturn();
@@ -3066,7 +3068,9 @@ public:
if (ast.kills) {
decomp.OpKill();
} else {
decomp.PreExit();
if (decomp.context_func->IsMain()) {
decomp.PreExit();
}
decomp.OpReturn();
}
decomp.AddLabel(decomp.OpLabel());

View File

@@ -5,6 +5,7 @@
#pragma once
#include <list>
#include <map>
#include <optional>
#include <set>
#include <variant>
@@ -112,12 +113,10 @@ struct ShaderFunction {
struct ShaderProgram {
ShaderFunction main;
std::unordered_map<u32, ShaderFunction> subfunctions;
std::map<u32, ShaderFunction> subfunctions;
};
std::unique_ptr<ShaderProgram> ScanFlow(const ProgramCode& program_code, u32 start_address,
const CompilerSettings& settings,
Registry& registry);
const CompilerSettings& settings, Registry& registry);
} // namespace VideoCommon::Shader

View File

@@ -216,10 +216,22 @@ void ShaderIR::Decode() {
decompiled = false;
auto info = ScanFlow(program_code, main_offset, settings, registry);
u32 id_start = 1;
for (auto& pair : info->subfunctions) {
func_map.emplace(pair.first, id_start);
id_start++;
}
coverage_begin = info->main.start;
coverage_end = 0;
decode_function(info->main);
main_function = gen_function(info->main, 0);
subfunctions.resize(info->subfunctions.size());
for (auto& pair : info->subfunctions) {
auto& func_info = pair.second;
decode_function(func_info);
u32 id = func_map[pair.first];
subfunctions[id - 1] = gen_function(func_info, id);
}
}
NodeBlock ShaderIR::DecodeRange(u32 begin, u32 end) {

View File

@@ -33,6 +33,7 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
// With the previous preconditions, this instruction is a no-operation.
break;
}
case OpCode::Id::RET:
case OpCode::Id::EXIT: {
const ConditionCode cc = instr.flow_condition_code;
UNIMPLEMENTED_IF_MSG(cc != ConditionCode::T, "EXIT condition code used: {}", cc);
@@ -312,6 +313,16 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
LOG_DEBUG(HW_GPU, "DEPBAR instruction is stubbed");
break;
}
case OpCode::Id::CAL: {
const u32 target = pc + instr.bra.GetBranchTarget();
const auto it = func_map.find(target);
if (it == func_map.end()) {
UNREACHABLE();
break;
}
bb.push_back(FunctionCall(it->second));
break;
}
default:
UNIMPLEMENTED_MSG("Unhandled instruction: {}", opcode->get().GetName());
}

View File

@@ -267,10 +267,11 @@ class PatchNode;
class SmemNode;
class GmemNode;
class CommentNode;
class FunctionCallNode;
using NodeData = std::variant<OperationNode, ConditionalNode, GprNode, CustomVarNode, ImmediateNode,
InternalFlagNode, PredicateNode, AbufNode, PatchNode, CbufNode,
LmemNode, SmemNode, GmemNode, CommentNode>;
LmemNode, SmemNode, GmemNode, FunctionCallNode, CommentNode>;
using Node = std::shared_ptr<NodeData>;
using Node4 = std::array<Node, 4>;
using NodeBlock = std::vector<Node>;
@@ -494,6 +495,18 @@ private:
std::vector<Node> code; ///< Code to execute
};
class FunctionCallNode final : public AmendNode {
public:
explicit FunctionCallNode(u32 func_id_) : func_id{func_id_} {}
[[nodiscard]] u32 GetFuncId() const {
return func_id;
}
private:
u32 func_id; ///< Id of the function to call
};
/// A general purpose register
class GprNode final {
public:

View File

@@ -19,6 +19,11 @@ Node Comment(std::string text) {
return MakeNode<CommentNode>(std::move(text));
}
/// Creates a function call
Node FunctionCall(u32 func_id) {
return MakeNode<FunctionCallNode>(func_id);
}
Node Immediate(u32 value) {
return MakeNode<ImmediateNode>(value);
}

View File

@@ -27,6 +27,9 @@ Node Conditional(Node condition, std::vector<Node> code);
/// Creates a commentary node
Node Comment(std::string text);
/// Creates a function call
Node FunctionCall(u32 func_id);
/// Creates an u32 immediate
Node Immediate(u32 value);

View File

@@ -69,7 +69,7 @@ public:
explicit ShaderFunctionIR(std::map<u32, NodeBlock>&& basic_blocks_, bool disable_flow_stack_,
u32 id_, u32 coverage_begin_, u32 coverage_end_)
: basic_blocks{std::move(basic_blocks_)}, decompiled{false},
disable_flow_stack{disable_flow_stack}, id{id_}, coverage_begin{coverage_begin_},
disable_flow_stack{disable_flow_stack_}, id{id_}, coverage_begin{coverage_begin_},
coverage_end{coverage_end_} {}
explicit ShaderFunctionIR(ASTManager&& program_manager_, u32 id_, u32 coverage_begin_,
u32 coverage_end_)
@@ -80,11 +80,11 @@ public:
return basic_blocks;
}
bool IsFlowStackDisabled() const {
[[nodiscard]] bool IsFlowStackDisabled() const {
return disable_flow_stack;
}
bool IsDecompiled() const {
[[nodiscard]] bool IsDecompiled() const {
return decompiled;
}
@@ -100,11 +100,11 @@ public:
return program_manager.GetVariables();
}
bool IsMain() const {
[[nodiscard]] bool IsMain() const {
return id == 0;
}
u32 GetId() const {
[[nodiscard]] u32 GetId() const {
return id;
}
@@ -226,6 +226,10 @@ public:
return main_function;
}
const std::vector<std::shared_ptr<ShaderFunctionIR>>& GetSubFunctions() const {
return subfunctions;
}
private:
friend class ASTDecoder;
@@ -491,6 +495,7 @@ private:
std::shared_ptr<ShaderFunctionIR> main_function;
std::vector<std::shared_ptr<ShaderFunctionIR>> subfunctions;
std::unordered_map<u32, u32> func_map;
std::set<u32> used_registers;
std::set<Tegra::Shader::Pred> used_predicates;