committed by
FernandoS27
6 changed files with 510 additions and 5 deletions
-
3src/video_core/CMakeLists.txt
-
180src/video_core/shader/ast.cpp
-
184src/video_core/shader/ast.h
-
58src/video_core/shader/control_flow.cpp
-
4src/video_core/shader/control_flow.h
-
86src/video_core/shader/expr.h
@ -0,0 +1,180 @@ |
|||||
|
// Copyright 2019 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include <string>
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/shader/ast.h"
|
||||
|
#include "video_core/shader/expr.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
class ExprPrinter final { |
||||
|
public: |
||||
|
ExprPrinter() = default; |
||||
|
|
||||
|
void operator()(ExprAnd const& expr) { |
||||
|
inner += "( "; |
||||
|
std::visit(*this, *expr.operand1); |
||||
|
inner += " && "; |
||||
|
std::visit(*this, *expr.operand2); |
||||
|
inner += ')'; |
||||
|
} |
||||
|
|
||||
|
void operator()(ExprOr const& expr) { |
||||
|
inner += "( "; |
||||
|
std::visit(*this, *expr.operand1); |
||||
|
inner += " || "; |
||||
|
std::visit(*this, *expr.operand2); |
||||
|
inner += ')'; |
||||
|
} |
||||
|
|
||||
|
void operator()(ExprNot const& expr) { |
||||
|
inner += "!"; |
||||
|
std::visit(*this, *expr.operand1); |
||||
|
} |
||||
|
|
||||
|
void operator()(ExprPredicate const& expr) { |
||||
|
u32 pred = static_cast<u32>(expr.predicate); |
||||
|
if (pred > 7) { |
||||
|
inner += "!"; |
||||
|
pred -= 8; |
||||
|
} |
||||
|
inner += "P" + std::to_string(pred); |
||||
|
} |
||||
|
|
||||
|
void operator()(ExprCondCode const& expr) { |
||||
|
u32 cc = static_cast<u32>(expr.cc); |
||||
|
inner += "CC" + std::to_string(cc); |
||||
|
} |
||||
|
|
||||
|
void operator()(ExprVar const& expr) { |
||||
|
inner += "V" + std::to_string(expr.var_index); |
||||
|
} |
||||
|
|
||||
|
void operator()(ExprBoolean const& expr) { |
||||
|
inner += expr.value ? "true" : "false"; |
||||
|
} |
||||
|
|
||||
|
std::string& GetResult() { |
||||
|
return inner; |
||||
|
} |
||||
|
|
||||
|
std::string inner{}; |
||||
|
}; |
||||
|
|
||||
|
class ASTPrinter { |
||||
|
public: |
||||
|
ASTPrinter() = default; |
||||
|
|
||||
|
void operator()(ASTProgram& ast) { |
||||
|
scope++; |
||||
|
inner += "program {\n"; |
||||
|
for (ASTNode& node : ast.nodes) { |
||||
|
Visit(node); |
||||
|
} |
||||
|
inner += "}\n"; |
||||
|
scope--; |
||||
|
} |
||||
|
|
||||
|
void operator()(ASTIf& ast) { |
||||
|
ExprPrinter expr_parser{}; |
||||
|
std::visit(expr_parser, *ast.condition); |
||||
|
inner += Ident() + "if (" + expr_parser.GetResult() + ") {\n"; |
||||
|
scope++; |
||||
|
for (auto& node : ast.then_nodes) { |
||||
|
Visit(node); |
||||
|
} |
||||
|
scope--; |
||||
|
if (ast.else_nodes.size() > 0) { |
||||
|
inner += Ident() + "} else {\n"; |
||||
|
scope++; |
||||
|
for (auto& node : ast.else_nodes) { |
||||
|
Visit(node); |
||||
|
} |
||||
|
scope--; |
||||
|
} else { |
||||
|
inner += Ident() + "}\n"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void operator()(ASTBlockEncoded& ast) { |
||||
|
inner += Ident() + "Block(" + std::to_string(ast.start) + ", " + std::to_string(ast.end) + |
||||
|
");\n"; |
||||
|
} |
||||
|
|
||||
|
void operator()(ASTVarSet& ast) { |
||||
|
ExprPrinter expr_parser{}; |
||||
|
std::visit(expr_parser, *ast.condition); |
||||
|
inner += |
||||
|
Ident() + "V" + std::to_string(ast.index) + " := " + expr_parser.GetResult() + ";\n"; |
||||
|
} |
||||
|
|
||||
|
void operator()(ASTLabel& ast) { |
||||
|
inner += "Label_" + std::to_string(ast.index) + ":\n"; |
||||
|
} |
||||
|
|
||||
|
void operator()(ASTGoto& ast) { |
||||
|
ExprPrinter expr_parser{}; |
||||
|
std::visit(expr_parser, *ast.condition); |
||||
|
inner += Ident() + "(" + expr_parser.GetResult() + ") -> goto Label_" + |
||||
|
std::to_string(ast.label) + ";\n"; |
||||
|
} |
||||
|
|
||||
|
void operator()(ASTDoWhile& ast) { |
||||
|
ExprPrinter expr_parser{}; |
||||
|
std::visit(expr_parser, *ast.condition); |
||||
|
inner += Ident() + "do {\n"; |
||||
|
scope++; |
||||
|
for (auto& node : ast.loop_nodes) { |
||||
|
Visit(node); |
||||
|
} |
||||
|
scope--; |
||||
|
inner += Ident() + "} while (" + expr_parser.GetResult() + ")\n"; |
||||
|
} |
||||
|
|
||||
|
void operator()(ASTReturn& ast) { |
||||
|
ExprPrinter expr_parser{}; |
||||
|
std::visit(expr_parser, *ast.condition); |
||||
|
inner += Ident() + "(" + expr_parser.GetResult() + ") -> " + |
||||
|
(ast.kills ? "discard" : "exit") + ";\n"; |
||||
|
} |
||||
|
|
||||
|
std::string& Ident() { |
||||
|
if (memo_scope == scope) { |
||||
|
return tabs_memo; |
||||
|
} |
||||
|
tabs_memo = tabs.substr(0, scope * 2); |
||||
|
memo_scope = scope; |
||||
|
return tabs_memo; |
||||
|
} |
||||
|
|
||||
|
void Visit(ASTNode& node) { |
||||
|
std::visit(*this, *node->GetInnerData()); |
||||
|
} |
||||
|
|
||||
|
std::string& GetResult() { |
||||
|
return inner; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
std::string inner{}; |
||||
|
u32 scope{}; |
||||
|
|
||||
|
std::string tabs_memo{}; |
||||
|
u32 memo_scope{}; |
||||
|
|
||||
|
static std::string tabs; |
||||
|
}; |
||||
|
|
||||
|
std::string ASTPrinter::tabs = " "; |
||||
|
|
||||
|
std::string ASTManager::Print() { |
||||
|
ASTPrinter printer{}; |
||||
|
printer.Visit(main_node); |
||||
|
return printer.GetResult(); |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,184 @@ |
|||||
|
// Copyright 2019 yuzu Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <list> |
||||
|
#include <memory> |
||||
|
#include <optional> |
||||
|
#include <string> |
||||
|
#include <unordered_map> |
||||
|
#include <vector> |
||||
|
|
||||
|
#include "video_core/shader/expr.h" |
||||
|
#include "video_core/shader/node.h" |
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
class ASTBase; |
||||
|
class ASTProgram; |
||||
|
class ASTIf; |
||||
|
class ASTBlockEncoded; |
||||
|
class ASTVarSet; |
||||
|
class ASTGoto; |
||||
|
class ASTLabel; |
||||
|
class ASTDoWhile; |
||||
|
class ASTReturn; |
||||
|
|
||||
|
using ASTData = std::variant<ASTProgram, ASTIf, ASTBlockEncoded, ASTVarSet, ASTGoto, ASTLabel, |
||||
|
ASTDoWhile, ASTReturn>; |
||||
|
|
||||
|
using ASTNode = std::shared_ptr<ASTBase>; |
||||
|
|
||||
|
class ASTProgram { |
||||
|
public: |
||||
|
ASTProgram() = default; |
||||
|
std::list<ASTNode> nodes; |
||||
|
}; |
||||
|
|
||||
|
class ASTIf { |
||||
|
public: |
||||
|
ASTIf(Expr condition, std::list<ASTNode> then_nodes, std::list<ASTNode> else_nodes) |
||||
|
: condition(condition), then_nodes{then_nodes}, else_nodes{then_nodes} {} |
||||
|
Expr condition; |
||||
|
std::list<ASTNode> then_nodes; |
||||
|
std::list<ASTNode> else_nodes; |
||||
|
}; |
||||
|
|
||||
|
class ASTBlockEncoded { |
||||
|
public: |
||||
|
ASTBlockEncoded(u32 start, u32 end) : start{start}, end{end} {} |
||||
|
u32 start; |
||||
|
u32 end; |
||||
|
}; |
||||
|
|
||||
|
class ASTVarSet { |
||||
|
public: |
||||
|
ASTVarSet(u32 index, Expr condition) : index{index}, condition{condition} {} |
||||
|
u32 index; |
||||
|
Expr condition; |
||||
|
}; |
||||
|
|
||||
|
class ASTLabel { |
||||
|
public: |
||||
|
ASTLabel(u32 index) : index{index} {} |
||||
|
u32 index; |
||||
|
}; |
||||
|
|
||||
|
class ASTGoto { |
||||
|
public: |
||||
|
ASTGoto(Expr condition, u32 label) : condition{condition}, label{label} {} |
||||
|
Expr condition; |
||||
|
u32 label; |
||||
|
}; |
||||
|
|
||||
|
class ASTDoWhile { |
||||
|
public: |
||||
|
ASTDoWhile(Expr condition, std::list<ASTNode> loop_nodes) |
||||
|
: condition(condition), loop_nodes{loop_nodes} {} |
||||
|
Expr condition; |
||||
|
std::list<ASTNode> loop_nodes; |
||||
|
}; |
||||
|
|
||||
|
class ASTReturn { |
||||
|
public: |
||||
|
ASTReturn(Expr condition, bool kills) : condition{condition}, kills{kills} {} |
||||
|
Expr condition; |
||||
|
bool kills; |
||||
|
}; |
||||
|
|
||||
|
class ASTBase { |
||||
|
public: |
||||
|
explicit ASTBase(ASTNode parent, ASTData data) : parent{parent}, data{data} {} |
||||
|
|
||||
|
template <class U, class... Args> |
||||
|
static ASTNode Make(ASTNode parent, Args&&... args) { |
||||
|
return std::make_shared<ASTBase>(parent, ASTData(U(std::forward<Args>(args)...))); |
||||
|
} |
||||
|
|
||||
|
void SetParent(ASTNode new_parent) { |
||||
|
parent = new_parent; |
||||
|
} |
||||
|
|
||||
|
ASTNode& GetParent() { |
||||
|
return parent; |
||||
|
} |
||||
|
|
||||
|
const ASTNode& GetParent() const { |
||||
|
return parent; |
||||
|
} |
||||
|
|
||||
|
u32 GetLevel() const { |
||||
|
u32 level = 0; |
||||
|
auto next = parent; |
||||
|
while (next) { |
||||
|
next = next->GetParent(); |
||||
|
level++; |
||||
|
} |
||||
|
return level; |
||||
|
} |
||||
|
|
||||
|
ASTData* GetInnerData() { |
||||
|
return &data; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
ASTData data; |
||||
|
ASTNode parent; |
||||
|
}; |
||||
|
|
||||
|
class ASTManager final { |
||||
|
public: |
||||
|
explicit ASTManager() { |
||||
|
main_node = ASTBase::Make<ASTProgram>(nullptr); |
||||
|
program = std::get_if<ASTProgram>(main_node->GetInnerData()); |
||||
|
} |
||||
|
|
||||
|
void DeclareLabel(u32 address) { |
||||
|
const auto pair = labels_map.emplace(address, labels_count); |
||||
|
if (pair.second) { |
||||
|
labels_count++; |
||||
|
labels.resize(labels_count); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void InsertLabel(u32 address) { |
||||
|
u32 index = labels_map[address]; |
||||
|
ASTNode label = ASTBase::Make<ASTLabel>(main_node, index); |
||||
|
labels[index] = label; |
||||
|
program->nodes.push_back(label); |
||||
|
} |
||||
|
|
||||
|
void InsertGoto(Expr condition, u32 address) { |
||||
|
u32 index = labels_map[address]; |
||||
|
ASTNode goto_node = ASTBase::Make<ASTGoto>(main_node, condition, index); |
||||
|
gotos.push_back(goto_node); |
||||
|
program->nodes.push_back(goto_node); |
||||
|
} |
||||
|
|
||||
|
void InsertBlock(u32 start_address, u32 end_address) { |
||||
|
ASTNode block = ASTBase::Make<ASTBlockEncoded>(main_node, start_address, end_address); |
||||
|
program->nodes.push_back(block); |
||||
|
} |
||||
|
|
||||
|
void InsertReturn(Expr condition, bool kills) { |
||||
|
ASTNode node = ASTBase::Make<ASTReturn>(main_node, condition, kills); |
||||
|
program->nodes.push_back(node); |
||||
|
} |
||||
|
|
||||
|
std::string Print(); |
||||
|
|
||||
|
void Decompile() {} |
||||
|
|
||||
|
private: |
||||
|
std::unordered_map<u32, u32> labels_map{}; |
||||
|
u32 labels_count{}; |
||||
|
std::vector<ASTNode> labels{}; |
||||
|
std::list<ASTNode> gotos{}; |
||||
|
u32 variables{}; |
||||
|
ASTProgram* program; |
||||
|
ASTNode main_node; |
||||
|
}; |
||||
|
|
||||
|
} // namespace VideoCommon::Shader |
||||
@ -0,0 +1,86 @@ |
|||||
|
// Copyright 2019 yuzu Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <variant> |
||||
|
#include <memory> |
||||
|
|
||||
|
#include "video_core/engines/shader_bytecode.h" |
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::ConditionCode; |
||||
|
using Tegra::Shader::Pred; |
||||
|
|
||||
|
class ExprAnd; |
||||
|
class ExprOr; |
||||
|
class ExprNot; |
||||
|
class ExprPredicate; |
||||
|
class ExprCondCode; |
||||
|
class ExprVar; |
||||
|
class ExprBoolean; |
||||
|
|
||||
|
using ExprData = |
||||
|
std::variant<ExprVar, ExprCondCode, ExprPredicate, ExprNot, ExprOr, ExprAnd, ExprBoolean>; |
||||
|
using Expr = std::shared_ptr<ExprData>; |
||||
|
|
||||
|
class ExprAnd final { |
||||
|
public: |
||||
|
ExprAnd(Expr a, Expr b) : operand1{a}, operand2{b} {} |
||||
|
|
||||
|
Expr operand1; |
||||
|
Expr operand2; |
||||
|
}; |
||||
|
|
||||
|
class ExprOr final { |
||||
|
public: |
||||
|
ExprOr(Expr a, Expr b) : operand1{a}, operand2{b} {} |
||||
|
|
||||
|
Expr operand1; |
||||
|
Expr operand2; |
||||
|
}; |
||||
|
|
||||
|
class ExprNot final { |
||||
|
public: |
||||
|
ExprNot(Expr a) : operand1{a} {} |
||||
|
|
||||
|
Expr operand1; |
||||
|
}; |
||||
|
|
||||
|
class ExprVar final { |
||||
|
public: |
||||
|
ExprVar(u32 index) : var_index{index} {} |
||||
|
|
||||
|
u32 var_index; |
||||
|
}; |
||||
|
|
||||
|
class ExprPredicate final { |
||||
|
public: |
||||
|
ExprPredicate(Pred predicate) : predicate{predicate} {} |
||||
|
|
||||
|
Pred predicate; |
||||
|
}; |
||||
|
|
||||
|
class ExprCondCode final { |
||||
|
public: |
||||
|
ExprCondCode(ConditionCode cc) : cc{cc} {} |
||||
|
|
||||
|
ConditionCode cc; |
||||
|
}; |
||||
|
|
||||
|
class ExprBoolean final { |
||||
|
public: |
||||
|
ExprBoolean(bool val) : value{val} {} |
||||
|
|
||||
|
bool value; |
||||
|
}; |
||||
|
|
||||
|
template <typename T, typename... Args> |
||||
|
Expr MakeExpr(Args&&... args) { |
||||
|
static_assert(std::is_convertible_v<T, ExprData>); |
||||
|
return std::make_shared<ExprData>(T(std::forward<Args>(args)...)); |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue