ShaderIR: Implement Multiple Functions in GLSL.
This commit is contained in:
@@ -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;");
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
if (context_func->IsMain()) {
|
||||
PreExit();
|
||||
}
|
||||
code.AddLine("return;");
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -2177,7 +2177,9 @@ private:
|
||||
}
|
||||
|
||||
Expression Exit(Operation operation) {
|
||||
if (context_func->IsMain()) {
|
||||
PreExit();
|
||||
}
|
||||
inside_branch = true;
|
||||
if (conditional_branch_set) {
|
||||
OpReturn();
|
||||
@@ -3066,7 +3068,9 @@ public:
|
||||
if (ast.kills) {
|
||||
decomp.OpKill();
|
||||
} else {
|
||||
if (decomp.context_func->IsMain()) {
|
||||
decomp.PreExit();
|
||||
}
|
||||
decomp.OpReturn();
|
||||
}
|
||||
decomp.AddLabel(decomp.OpLabel());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user