shader: Use shared_ptr to store nodes and move initialization to file

Instead of having a vector of unique_ptr stored in a vector and
returning star pointers to this, use shared_ptr. While changing
initialization code, move it to a separate file when possible.

This is a first step to allow code analysis and node generation beyond
the ShaderIR class.
This commit is contained in:
ReinUsesLisp 2019-06-04 22:44:06 -03:00
parent a20ba09bfd
commit bf4dfb3ad4
35 changed files with 296 additions and 248 deletions

View file

@ -102,6 +102,8 @@ add_library(video_core STATIC
shader/decode/xmad.cpp shader/decode/xmad.cpp
shader/decode/other.cpp shader/decode/other.cpp
shader/decode.cpp shader/decode.cpp
shader/node_helper.cpp
shader/node_helper.h
shader/shader_ir.cpp shader/shader_ir.cpp
shader/shader_ir.h shader/shader_ir.h
shader/track.cpp shader/track.cpp

View file

@ -123,8 +123,8 @@ bool IsPrecise(Operation operand) {
return false; return false;
} }
bool IsPrecise(Node node) { bool IsPrecise(const Node& node) {
if (const auto operation = std::get_if<OperationNode>(node)) { if (const auto operation = std::get_if<OperationNode>(&*node)) {
return IsPrecise(*operation); return IsPrecise(*operation);
} }
return false; return false;
@ -497,15 +497,15 @@ private:
} }
void VisitBlock(const NodeBlock& bb) { void VisitBlock(const NodeBlock& bb) {
for (const Node node : bb) { for (const auto& node : bb) {
if (const std::string expr = Visit(node); !expr.empty()) { if (const std::string expr = Visit(node); !expr.empty()) {
code.AddLine(expr); code.AddLine(expr);
} }
} }
} }
std::string Visit(Node node) { std::string Visit(const Node& node) {
if (const auto operation = std::get_if<OperationNode>(node)) { if (const auto operation = std::get_if<OperationNode>(&*node)) {
const auto operation_index = static_cast<std::size_t>(operation->GetCode()); const auto operation_index = static_cast<std::size_t>(operation->GetCode());
if (operation_index >= operation_decompilers.size()) { if (operation_index >= operation_decompilers.size()) {
UNREACHABLE_MSG("Out of bounds operation: {}", operation_index); UNREACHABLE_MSG("Out of bounds operation: {}", operation_index);
@ -519,7 +519,7 @@ private:
return (this->*decompiler)(*operation); return (this->*decompiler)(*operation);
} }
if (const auto gpr = std::get_if<GprNode>(node)) { if (const auto gpr = std::get_if<GprNode>(&*node)) {
const u32 index = gpr->GetIndex(); const u32 index = gpr->GetIndex();
if (index == Register::ZeroIndex) { if (index == Register::ZeroIndex) {
return "0"; return "0";
@ -527,7 +527,7 @@ private:
return GetRegister(index); return GetRegister(index);
} }
if (const auto immediate = std::get_if<ImmediateNode>(node)) { if (const auto immediate = std::get_if<ImmediateNode>(&*node)) {
const u32 value = immediate->GetValue(); const u32 value = immediate->GetValue();
if (value < 10) { if (value < 10) {
// For eyecandy avoid using hex numbers on single digits // For eyecandy avoid using hex numbers on single digits
@ -536,7 +536,7 @@ private:
return fmt::format("utof(0x{:x}u)", immediate->GetValue()); return fmt::format("utof(0x{:x}u)", immediate->GetValue());
} }
if (const auto predicate = std::get_if<PredicateNode>(node)) { if (const auto predicate = std::get_if<PredicateNode>(&*node)) {
const auto value = [&]() -> std::string { const auto value = [&]() -> std::string {
switch (const auto index = predicate->GetIndex(); index) { switch (const auto index = predicate->GetIndex(); index) {
case Tegra::Shader::Pred::UnusedIndex: case Tegra::Shader::Pred::UnusedIndex:
@ -553,7 +553,7 @@ private:
return value; return value;
} }
if (const auto abuf = std::get_if<AbufNode>(node)) { if (const auto abuf = std::get_if<AbufNode>(&*node)) {
UNIMPLEMENTED_IF_MSG(abuf->IsPhysicalBuffer() && stage == ShaderStage::Geometry, UNIMPLEMENTED_IF_MSG(abuf->IsPhysicalBuffer() && stage == ShaderStage::Geometry,
"Physical attributes in geometry shaders are not implemented"); "Physical attributes in geometry shaders are not implemented");
if (abuf->IsPhysicalBuffer()) { if (abuf->IsPhysicalBuffer()) {
@ -563,9 +563,9 @@ private:
return ReadAttribute(abuf->GetIndex(), abuf->GetElement(), abuf->GetBuffer()); return ReadAttribute(abuf->GetIndex(), abuf->GetElement(), abuf->GetBuffer());
} }
if (const auto cbuf = std::get_if<CbufNode>(node)) { if (const auto cbuf = std::get_if<CbufNode>(&*node)) {
const Node offset = cbuf->GetOffset(); const Node offset = cbuf->GetOffset();
if (const auto immediate = std::get_if<ImmediateNode>(offset)) { if (const auto immediate = std::get_if<ImmediateNode>(&*offset)) {
// Direct access // Direct access
const u32 offset_imm = immediate->GetValue(); const u32 offset_imm = immediate->GetValue();
ASSERT_MSG(offset_imm % 4 == 0, "Unaligned cbuf direct access"); ASSERT_MSG(offset_imm % 4 == 0, "Unaligned cbuf direct access");
@ -601,22 +601,22 @@ private:
UNREACHABLE_MSG("Unmanaged offset node type"); UNREACHABLE_MSG("Unmanaged offset node type");
} }
if (const auto gmem = std::get_if<GmemNode>(node)) { if (const auto gmem = std::get_if<GmemNode>(&*node)) {
const std::string real = Visit(gmem->GetRealAddress()); const std::string real = Visit(gmem->GetRealAddress());
const std::string base = Visit(gmem->GetBaseAddress()); const std::string base = Visit(gmem->GetBaseAddress());
const std::string final_offset = fmt::format("(ftou({}) - ftou({})) / 4", real, base); const std::string final_offset = fmt::format("(ftou({}) - ftou({})) / 4", real, base);
return fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset); return fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset);
} }
if (const auto lmem = std::get_if<LmemNode>(node)) { if (const auto lmem = std::get_if<LmemNode>(&*node)) {
return fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress())); return fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress()));
} }
if (const auto internal_flag = std::get_if<InternalFlagNode>(node)) { if (const auto internal_flag = std::get_if<InternalFlagNode>(&*node)) {
return GetInternalFlag(internal_flag->GetFlag()); return GetInternalFlag(internal_flag->GetFlag());
} }
if (const auto conditional = std::get_if<ConditionalNode>(node)) { if (const auto conditional = std::get_if<ConditionalNode>(&*node)) {
// It's invalid to call conditional on nested nodes, use an operation instead // It's invalid to call conditional on nested nodes, use an operation instead
code.AddLine("if ({}) {{", Visit(conditional->GetCondition())); code.AddLine("if ({}) {{", Visit(conditional->GetCondition()));
++code.scope; ++code.scope;
@ -628,7 +628,7 @@ private:
return {}; return {};
} }
if (const auto comment = std::get_if<CommentNode>(node)) { if (const auto comment = std::get_if<CommentNode>(&*node)) {
return "// " + comment->GetText(); return "// " + comment->GetText();
} }
@ -636,7 +636,7 @@ private:
return {}; return {};
} }
std::string ReadAttribute(Attribute::Index attribute, u32 element, Node buffer = {}) { std::string ReadAttribute(Attribute::Index attribute, u32 element, const Node& buffer = {}) {
const auto GeometryPass = [&](std::string_view name) { const auto GeometryPass = [&](std::string_view name) {
if (stage == ShaderStage::Geometry && buffer) { if (stage == ShaderStage::Geometry && buffer) {
// TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games // TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games
@ -872,7 +872,7 @@ private:
std::string expr = ", "; std::string expr = ", ";
switch (type) { switch (type) {
case Type::Int: case Type::Int:
if (const auto immediate = std::get_if<ImmediateNode>(operand)) { if (const auto immediate = std::get_if<ImmediateNode>(&*operand)) {
// Inline the string as an immediate integer in GLSL (some extra arguments are // Inline the string as an immediate integer in GLSL (some extra arguments are
// required to be constant) // required to be constant)
expr += std::to_string(static_cast<s32>(immediate->GetValue())); expr += std::to_string(static_cast<s32>(immediate->GetValue()));
@ -904,7 +904,7 @@ private:
for (std::size_t index = 0; index < aoffi.size(); ++index) { for (std::size_t index = 0; index < aoffi.size(); ++index) {
const auto operand{aoffi.at(index)}; const auto operand{aoffi.at(index)};
if (const auto immediate = std::get_if<ImmediateNode>(operand)) { if (const auto immediate = std::get_if<ImmediateNode>(&*operand)) {
// Inline the string as an immediate integer in GLSL (AOFFI arguments are required // Inline the string as an immediate integer in GLSL (AOFFI arguments are required
// to be constant by the standard). // to be constant by the standard).
expr += std::to_string(static_cast<s32>(immediate->GetValue())); expr += std::to_string(static_cast<s32>(immediate->GetValue()));
@ -925,17 +925,17 @@ private:
} }
std::string Assign(Operation operation) { std::string Assign(Operation operation) {
const Node dest = operation[0]; const Node& dest = operation[0];
const Node src = operation[1]; const Node& src = operation[1];
std::string target; std::string target;
if (const auto gpr = std::get_if<GprNode>(dest)) { if (const auto gpr = std::get_if<GprNode>(&*dest)) {
if (gpr->GetIndex() == Register::ZeroIndex) { if (gpr->GetIndex() == Register::ZeroIndex) {
// Writing to Register::ZeroIndex is a no op // Writing to Register::ZeroIndex is a no op
return {}; return {};
} }
target = GetRegister(gpr->GetIndex()); target = GetRegister(gpr->GetIndex());
} else if (const auto abuf = std::get_if<AbufNode>(dest)) { } else if (const auto abuf = std::get_if<AbufNode>(&*dest)) {
UNIMPLEMENTED_IF(abuf->IsPhysicalBuffer()); UNIMPLEMENTED_IF(abuf->IsPhysicalBuffer());
target = [&]() -> std::string { target = [&]() -> std::string {
@ -957,9 +957,9 @@ private:
return "0"; return "0";
} }
}(); }();
} else if (const auto lmem = std::get_if<LmemNode>(dest)) { } else if (const auto lmem = std::get_if<LmemNode>(&*dest)) {
target = fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress())); target = fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress()));
} else if (const auto gmem = std::get_if<GmemNode>(dest)) { } else if (const auto gmem = std::get_if<GmemNode>(&*dest)) {
const std::string real = Visit(gmem->GetRealAddress()); const std::string real = Visit(gmem->GetRealAddress());
const std::string base = Visit(gmem->GetBaseAddress()); const std::string base = Visit(gmem->GetBaseAddress());
const std::string final_offset = fmt::format("(ftou({}) - ftou({})) / 4", real, base); const std::string final_offset = fmt::format("(ftou({}) - ftou({})) / 4", real, base);
@ -1236,12 +1236,12 @@ private:
} }
std::string LogicalAssign(Operation operation) { std::string LogicalAssign(Operation operation) {
const Node dest = operation[0]; const Node& dest = operation[0];
const Node src = operation[1]; const Node& src = operation[1];
std::string target; std::string target;
if (const auto pred = std::get_if<PredicateNode>(dest)) { if (const auto pred = std::get_if<PredicateNode>(&*dest)) {
ASSERT_MSG(!pred->IsNegated(), "Negating logical assignment"); ASSERT_MSG(!pred->IsNegated(), "Negating logical assignment");
const auto index = pred->GetIndex(); const auto index = pred->GetIndex();
@ -1252,7 +1252,7 @@ private:
return {}; return {};
} }
target = GetPredicate(index); target = GetPredicate(index);
} else if (const auto flag = std::get_if<InternalFlagNode>(dest)) { } else if (const auto flag = std::get_if<InternalFlagNode>(&*dest)) {
target = GetInternalFlag(flag->GetFlag()); target = GetInternalFlag(flag->GetFlag());
} }
@ -1429,7 +1429,7 @@ private:
} }
std::string Branch(Operation operation) { std::string Branch(Operation operation) {
const auto target = std::get_if<ImmediateNode>(operation[0]); const auto target = std::get_if<ImmediateNode>(&*operation[0]);
UNIMPLEMENTED_IF(!target); UNIMPLEMENTED_IF(!target);
code.AddLine("jmp_to = 0x{:x}u;", target->GetValue()); code.AddLine("jmp_to = 0x{:x}u;", target->GetValue());
@ -1438,7 +1438,7 @@ private:
} }
std::string PushFlowStack(Operation operation) { std::string PushFlowStack(Operation operation) {
const auto target = std::get_if<ImmediateNode>(operation[0]); const auto target = std::get_if<ImmediateNode>(&*operation[0]);
UNIMPLEMENTED_IF(!target); UNIMPLEMENTED_IF(!target);
code.AddLine("flow_stack[flow_stack_top++] = 0x{:x}u;", target->GetValue()); code.AddLine("flow_stack[flow_stack_top++] = 0x{:x}u;", target->GetValue());

View file

@ -481,13 +481,13 @@ private:
} }
void VisitBasicBlock(const NodeBlock& bb) { void VisitBasicBlock(const NodeBlock& bb) {
for (const Node node : bb) { for (const auto& node : bb) {
static_cast<void>(Visit(node)); static_cast<void>(Visit(node));
} }
} }
Id Visit(Node node) { Id Visit(const Node& node) {
if (const auto operation = std::get_if<OperationNode>(node)) { if (const auto operation = std::get_if<OperationNode>(&*node)) {
const auto operation_index = static_cast<std::size_t>(operation->GetCode()); const auto operation_index = static_cast<std::size_t>(operation->GetCode());
const auto decompiler = operation_decompilers[operation_index]; const auto decompiler = operation_decompilers[operation_index];
if (decompiler == nullptr) { if (decompiler == nullptr) {
@ -495,17 +495,17 @@ private:
} }
return (this->*decompiler)(*operation); return (this->*decompiler)(*operation);
} else if (const auto gpr = std::get_if<GprNode>(node)) { } else if (const auto gpr = std::get_if<GprNode>(&*node)) {
const u32 index = gpr->GetIndex(); const u32 index = gpr->GetIndex();
if (index == Register::ZeroIndex) { if (index == Register::ZeroIndex) {
return Constant(t_float, 0.0f); return Constant(t_float, 0.0f);
} }
return Emit(OpLoad(t_float, registers.at(index))); return Emit(OpLoad(t_float, registers.at(index)));
} else if (const auto immediate = std::get_if<ImmediateNode>(node)) { } else if (const auto immediate = std::get_if<ImmediateNode>(&*node)) {
return BitcastTo<Type::Float>(Constant(t_uint, immediate->GetValue())); return BitcastTo<Type::Float>(Constant(t_uint, immediate->GetValue()));
} else if (const auto predicate = std::get_if<PredicateNode>(node)) { } else if (const auto predicate = std::get_if<PredicateNode>(&*node)) {
const auto value = [&]() -> Id { const auto value = [&]() -> Id {
switch (const auto index = predicate->GetIndex(); index) { switch (const auto index = predicate->GetIndex(); index) {
case Tegra::Shader::Pred::UnusedIndex: case Tegra::Shader::Pred::UnusedIndex:
@ -521,7 +521,7 @@ private:
} }
return value; return value;
} else if (const auto abuf = std::get_if<AbufNode>(node)) { } else if (const auto abuf = std::get_if<AbufNode>(&*node)) {
const auto attribute = abuf->GetIndex(); const auto attribute = abuf->GetIndex();
const auto element = abuf->GetElement(); const auto element = abuf->GetElement();
@ -571,8 +571,8 @@ private:
} }
UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute)); UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute));
} else if (const auto cbuf = std::get_if<CbufNode>(node)) { } else if (const auto cbuf = std::get_if<CbufNode>(&*node)) {
const Node offset = cbuf->GetOffset(); const Node& offset = cbuf->GetOffset();
const Id buffer_id = constant_buffers.at(cbuf->GetIndex()); const Id buffer_id = constant_buffers.at(cbuf->GetIndex());
Id pointer{}; Id pointer{};
@ -584,7 +584,7 @@ private:
} else { } else {
Id buffer_index{}; Id buffer_index{};
Id buffer_element{}; Id buffer_element{};
if (const auto immediate = std::get_if<ImmediateNode>(offset)) { if (const auto immediate = std::get_if<ImmediateNode>(&*offset)) {
// Direct access // Direct access
const u32 offset_imm = immediate->GetValue(); const u32 offset_imm = immediate->GetValue();
ASSERT(offset_imm % 4 == 0); ASSERT(offset_imm % 4 == 0);
@ -606,7 +606,7 @@ private:
} }
return Emit(OpLoad(t_float, pointer)); return Emit(OpLoad(t_float, pointer));
} else if (const auto gmem = std::get_if<GmemNode>(node)) { } else if (const auto gmem = std::get_if<GmemNode>(&*node)) {
const Id gmem_buffer = global_buffers.at(gmem->GetDescriptor()); const Id gmem_buffer = global_buffers.at(gmem->GetDescriptor());
const Id real = BitcastTo<Type::Uint>(Visit(gmem->GetRealAddress())); const Id real = BitcastTo<Type::Uint>(Visit(gmem->GetRealAddress()));
const Id base = BitcastTo<Type::Uint>(Visit(gmem->GetBaseAddress())); const Id base = BitcastTo<Type::Uint>(Visit(gmem->GetBaseAddress()));
@ -616,7 +616,7 @@ private:
return Emit(OpLoad(t_float, Emit(OpAccessChain(t_gmem_float, gmem_buffer, return Emit(OpLoad(t_float, Emit(OpAccessChain(t_gmem_float, gmem_buffer,
Constant(t_uint, 0u), offset)))); Constant(t_uint, 0u), offset))));
} else if (const auto conditional = std::get_if<ConditionalNode>(node)) { } else if (const auto conditional = std::get_if<ConditionalNode>(&*node)) {
// It's invalid to call conditional on nested nodes, use an operation instead // It's invalid to call conditional on nested nodes, use an operation instead
const Id true_label = OpLabel(); const Id true_label = OpLabel();
const Id skip_label = OpLabel(); const Id skip_label = OpLabel();
@ -631,7 +631,7 @@ private:
Emit(skip_label); Emit(skip_label);
return {}; return {};
} else if (const auto comment = std::get_if<CommentNode>(node)) { } else if (const auto comment = std::get_if<CommentNode>(&*node)) {
Name(Emit(OpUndef(t_void)), comment->GetText()); Name(Emit(OpUndef(t_void)), comment->GetText());
return {}; return {};
} }
@ -699,18 +699,18 @@ private:
} }
Id Assign(Operation operation) { Id Assign(Operation operation) {
const Node dest = operation[0]; const Node& dest = operation[0];
const Node src = operation[1]; const Node& src = operation[1];
Id target{}; Id target{};
if (const auto gpr = std::get_if<GprNode>(dest)) { if (const auto gpr = std::get_if<GprNode>(&*dest)) {
if (gpr->GetIndex() == Register::ZeroIndex) { if (gpr->GetIndex() == Register::ZeroIndex) {
// Writing to Register::ZeroIndex is a no op // Writing to Register::ZeroIndex is a no op
return {}; return {};
} }
target = registers.at(gpr->GetIndex()); target = registers.at(gpr->GetIndex());
} else if (const auto abuf = std::get_if<AbufNode>(dest)) { } else if (const auto abuf = std::get_if<AbufNode>(&*dest)) {
target = [&]() -> Id { target = [&]() -> Id {
switch (const auto attribute = abuf->GetIndex(); attribute) { switch (const auto attribute = abuf->GetIndex(); attribute) {
case Attribute::Index::Position: case Attribute::Index::Position:
@ -735,7 +735,7 @@ private:
} }
}(); }();
} else if (const auto lmem = std::get_if<LmemNode>(dest)) { } else if (const auto lmem = std::get_if<LmemNode>(&*dest)) {
Id address = BitcastTo<Type::Uint>(Visit(lmem->GetAddress())); Id address = BitcastTo<Type::Uint>(Visit(lmem->GetAddress()));
address = Emit(OpUDiv(t_uint, address, Constant(t_uint, 4))); address = Emit(OpUDiv(t_uint, address, Constant(t_uint, 4)));
target = Emit(OpAccessChain(t_prv_float, local_memory, {address})); target = Emit(OpAccessChain(t_prv_float, local_memory, {address}));
@ -781,11 +781,11 @@ private:
} }
Id LogicalAssign(Operation operation) { Id LogicalAssign(Operation operation) {
const Node dest = operation[0]; const Node& dest = operation[0];
const Node src = operation[1]; const Node& src = operation[1];
Id target{}; Id target{};
if (const auto pred = std::get_if<PredicateNode>(dest)) { if (const auto pred = std::get_if<PredicateNode>(&*dest)) {
ASSERT_MSG(!pred->IsNegated(), "Negating logical assignment"); ASSERT_MSG(!pred->IsNegated(), "Negating logical assignment");
const auto index = pred->GetIndex(); const auto index = pred->GetIndex();
@ -797,7 +797,7 @@ private:
} }
target = predicates.at(index); target = predicates.at(index);
} else if (const auto flag = std::get_if<InternalFlagNode>(dest)) { } else if (const auto flag = std::get_if<InternalFlagNode>(&*dest)) {
target = internal_flags.at(static_cast<u32>(flag->GetFlag())); target = internal_flags.at(static_cast<u32>(flag->GetFlag()));
} }
@ -883,7 +883,7 @@ private:
} else { } else {
u32 component_value = 0; u32 component_value = 0;
if (meta->component) { if (meta->component) {
const auto component = std::get_if<ImmediateNode>(meta->component); const auto component = std::get_if<ImmediateNode>(&*meta->component);
ASSERT_MSG(component, "Component is not an immediate value"); ASSERT_MSG(component, "Component is not an immediate value");
component_value = component->GetValue(); component_value = component->GetValue();
} }
@ -940,7 +940,7 @@ private:
} }
Id Branch(Operation operation) { Id Branch(Operation operation) {
const auto target = std::get_if<ImmediateNode>(operation[0]); const auto target = std::get_if<ImmediateNode>(&*operation[0]);
UNIMPLEMENTED_IF(!target); UNIMPLEMENTED_IF(!target);
Emit(OpStore(jmp_to, Constant(t_uint, target->GetValue()))); Emit(OpStore(jmp_to, Constant(t_uint, target->GetValue())));
@ -949,7 +949,7 @@ private:
} }
Id PushFlowStack(Operation operation) { Id PushFlowStack(Operation operation) {
const auto target = std::get_if<ImmediateNode>(operation[0]); const auto target = std::get_if<ImmediateNode>(&*operation[0]);
ASSERT(target); ASSERT(target);
const Id current = Emit(OpLoad(t_uint, flow_stack_top)); const Id current = Emit(OpLoad(t_uint, flow_stack_top));

View file

@ -11,6 +11,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/engines/shader_header.h" #include "video_core/engines/shader_header.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -6,6 +6,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -6,6 +6,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -6,6 +6,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -5,6 +5,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -5,6 +5,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -5,6 +5,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -5,6 +5,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -5,6 +5,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -5,6 +5,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -5,6 +5,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -5,6 +5,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -5,6 +5,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -8,6 +8,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -5,6 +5,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -7,6 +7,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -4,6 +4,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -5,6 +5,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -10,6 +10,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {
@ -169,7 +170,7 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
const Node it_offset = Immediate(i * 4); const Node it_offset = Immediate(i * 4);
const Node real_address = const Node real_address =
Operation(OperationCode::UAdd, NO_PRECISE, real_address_base, it_offset); Operation(OperationCode::UAdd, NO_PRECISE, real_address_base, it_offset);
const Node gmem = StoreNode(GmemNode(real_address, base_address, descriptor)); const Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor);
SetTemporal(bb, i, gmem); SetTemporal(bb, i, gmem);
} }
@ -262,7 +263,7 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
const Node it_offset = Immediate(i * 4); const Node it_offset = Immediate(i * 4);
const Node real_address = const Node real_address =
Operation(OperationCode::UAdd, NO_PRECISE, real_address_base, it_offset); Operation(OperationCode::UAdd, NO_PRECISE, real_address_base, it_offset);
const Node gmem = StoreNode(GmemNode(real_address, base_address, descriptor)); const Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor);
bb.push_back(Operation(OperationCode::Assign, gmem, GetTemporal(i + 1))); bb.push_back(Operation(OperationCode::Assign, gmem, GetTemporal(i + 1)));
} }
@ -298,9 +299,9 @@ std::tuple<Node, Node, GlobalMemoryBase> ShaderIR::TrackAndGetGlobalMemory(NodeB
const Node base_address{ const Node base_address{
TrackCbuf(addr_register, global_code, static_cast<s64>(global_code.size()))}; TrackCbuf(addr_register, global_code, static_cast<s64>(global_code.size()))};
const auto cbuf = std::get_if<CbufNode>(base_address); const auto cbuf = std::get_if<CbufNode>(&*base_address);
ASSERT(cbuf != nullptr); ASSERT(cbuf != nullptr);
const auto cbuf_offset_imm = std::get_if<ImmediateNode>(cbuf->GetOffset()); const auto cbuf_offset_imm = std::get_if<ImmediateNode>(&*cbuf->GetOffset());
ASSERT(cbuf_offset_imm != nullptr); ASSERT(cbuf_offset_imm != nullptr);
const auto cbuf_offset = cbuf_offset_imm->GetValue(); const auto cbuf_offset = cbuf_offset_imm->GetValue();

View file

@ -6,6 +6,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -5,6 +5,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -5,6 +5,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -5,6 +5,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -5,6 +5,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -11,6 +11,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {
@ -291,8 +292,8 @@ const Sampler& ShaderIR::GetBindlessSampler(const Tegra::Shader::Register& reg,
const Node sampler_register = GetRegister(reg); const Node sampler_register = GetRegister(reg);
const Node base_sampler = const Node base_sampler =
TrackCbuf(sampler_register, global_code, static_cast<s64>(global_code.size())); TrackCbuf(sampler_register, global_code, static_cast<s64>(global_code.size()));
const auto cbuf = std::get_if<CbufNode>(base_sampler); const auto cbuf = std::get_if<CbufNode>(&*base_sampler);
const auto cbuf_offset_imm = std::get_if<ImmediateNode>(cbuf->GetOffset()); const auto cbuf_offset_imm = std::get_if<ImmediateNode>(&*cbuf->GetOffset());
ASSERT(cbuf_offset_imm != nullptr); ASSERT(cbuf_offset_imm != nullptr);
const auto cbuf_offset = cbuf_offset_imm->GetValue(); const auto cbuf_offset = cbuf_offset_imm->GetValue();
const auto cbuf_index = cbuf->GetIndex(); const auto cbuf_index = cbuf->GetIndex();
@ -388,8 +389,8 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type,
Node array, Node depth_compare, u32 bias_offset, Node array, Node depth_compare, u32 bias_offset,
std::vector<Node> aoffi, std::vector<Node> aoffi,
std::optional<Tegra::Shader::Register> bindless_reg) { std::optional<Tegra::Shader::Register> bindless_reg) {
const bool is_array = array; const auto is_array = static_cast<bool>(array);
const bool is_shadow = depth_compare; const auto is_shadow = static_cast<bool>(depth_compare);
const bool is_bindless = bindless_reg.has_value(); const bool is_bindless = bindless_reg.has_value();
UNIMPLEMENTED_IF_MSG((texture_type == TextureType::Texture3D && (is_array || is_shadow)) || UNIMPLEMENTED_IF_MSG((texture_type == TextureType::Texture3D && (is_array || is_shadow)) ||

View file

@ -5,6 +5,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -5,6 +5,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {

View file

@ -0,0 +1,99 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <cstring>
#include <vector>
#include "common/common_types.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {
Node Conditional(Node condition, std::vector<Node> code) {
return MakeNode<ConditionalNode>(condition, std::move(code));
}
Node Comment(std::string text) {
return MakeNode<CommentNode>(std::move(text));
}
Node Immediate(u32 value) {
return MakeNode<ImmediateNode>(value);
}
Node Immediate(s32 value) {
return Immediate(static_cast<u32>(value));
}
Node Immediate(f32 value) {
u32 integral;
std::memcpy(&integral, &value, sizeof(u32));
return Immediate(integral);
}
OperationCode SignedToUnsignedCode(OperationCode operation_code, bool is_signed) {
if (is_signed) {
return operation_code;
}
switch (operation_code) {
case OperationCode::FCastInteger:
return OperationCode::FCastUInteger;
case OperationCode::IAdd:
return OperationCode::UAdd;
case OperationCode::IMul:
return OperationCode::UMul;
case OperationCode::IDiv:
return OperationCode::UDiv;
case OperationCode::IMin:
return OperationCode::UMin;
case OperationCode::IMax:
return OperationCode::UMax;
case OperationCode::ICastFloat:
return OperationCode::UCastFloat;
case OperationCode::ICastUnsigned:
return OperationCode::UCastSigned;
case OperationCode::ILogicalShiftLeft:
return OperationCode::ULogicalShiftLeft;
case OperationCode::ILogicalShiftRight:
return OperationCode::ULogicalShiftRight;
case OperationCode::IArithmeticShiftRight:
return OperationCode::UArithmeticShiftRight;
case OperationCode::IBitwiseAnd:
return OperationCode::UBitwiseAnd;
case OperationCode::IBitwiseOr:
return OperationCode::UBitwiseOr;
case OperationCode::IBitwiseXor:
return OperationCode::UBitwiseXor;
case OperationCode::IBitwiseNot:
return OperationCode::UBitwiseNot;
case OperationCode::IBitfieldInsert:
return OperationCode::UBitfieldInsert;
case OperationCode::IBitCount:
return OperationCode::UBitCount;
case OperationCode::LogicalILessThan:
return OperationCode::LogicalULessThan;
case OperationCode::LogicalIEqual:
return OperationCode::LogicalUEqual;
case OperationCode::LogicalILessEqual:
return OperationCode::LogicalULessEqual;
case OperationCode::LogicalIGreaterThan:
return OperationCode::LogicalUGreaterThan;
case OperationCode::LogicalINotEqual:
return OperationCode::LogicalUNotEqual;
case OperationCode::LogicalIGreaterEqual:
return OperationCode::LogicalUGreaterEqual;
case OperationCode::INegate:
UNREACHABLE_MSG("Can't negate an unsigned integer");
return {};
case OperationCode::IAbsolute:
UNREACHABLE_MSG("Can't apply absolute to an unsigned integer");
return {};
default:
UNREACHABLE_MSG("Unknown signed operation with code={}", static_cast<u32>(operation_code));
return {};
}
}
} // namespace VideoCommon::Shader

View file

@ -0,0 +1,60 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
#include "common/common_types.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {
/// Creates a conditional node
Node Conditional(Node condition, std::vector<Node> code);
/// Creates a commentary node
Node Comment(std::string text);
/// Creates an u32 immediate
Node Immediate(u32 value);
/// Creates a s32 immediate
Node Immediate(s32 value);
/// Creates a f32 immediate
Node Immediate(f32 value);
/// Converts an signed operation code to an unsigned operation code
OperationCode SignedToUnsignedCode(OperationCode operation_code, bool is_signed);
template <typename T, typename... Args>
Node MakeNode(Args&&... args) {
static_assert(std::is_convertible_v<T, NodeData>);
return std::make_shared<NodeData>(T(std::forward<Args>(args)...));
}
template <typename... Args>
Node Operation(OperationCode code, Args&&... args) {
if constexpr (sizeof...(args) == 0) {
return MakeNode<OperationNode>(code);
} else if constexpr (std::is_convertible_v<std::tuple_element_t<0, std::tuple<Args...>>,
Meta>) {
return MakeNode<OperationNode>(code, std::forward<Args>(args)...);
} else {
return MakeNode<OperationNode>(code, Meta{}, std::forward<Args>(args)...);
}
}
template <typename... Args>
Node SignedOperation(OperationCode code, bool is_signed, Args&&... args) {
return Operation(SignedToUnsignedCode(code, is_signed), std::forward<Args>(args)...);
}
} // namespace VideoCommon::Shader

View file

@ -9,6 +9,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader { namespace VideoCommon::Shader {
@ -28,30 +29,11 @@ ShaderIR::ShaderIR(const ProgramCode& program_code, u32 main_offset)
ShaderIR::~ShaderIR() = default; ShaderIR::~ShaderIR() = default;
Node ShaderIR::StoreNode(NodeData&& node_data) {
auto store = std::make_unique<NodeData>(node_data);
const Node node = store.get();
stored_nodes.push_back(std::move(store));
return node;
}
Node ShaderIR::Conditional(Node condition, std::vector<Node>&& code) {
return StoreNode(ConditionalNode(condition, std::move(code)));
}
Node ShaderIR::Comment(std::string text) {
return StoreNode(CommentNode(std::move(text)));
}
Node ShaderIR::Immediate(u32 value) {
return StoreNode(ImmediateNode(value));
}
Node ShaderIR::GetRegister(Register reg) { Node ShaderIR::GetRegister(Register reg) {
if (reg != Register::ZeroIndex) { if (reg != Register::ZeroIndex) {
used_registers.insert(static_cast<u32>(reg)); used_registers.insert(static_cast<u32>(reg));
} }
return StoreNode(GprNode(reg)); return MakeNode<GprNode>(reg);
} }
Node ShaderIR::GetImmediate19(Instruction instr) { Node ShaderIR::GetImmediate19(Instruction instr) {
@ -69,7 +51,7 @@ Node ShaderIR::GetConstBuffer(u64 index_, u64 offset_) {
const auto [entry, is_new] = used_cbufs.try_emplace(index); const auto [entry, is_new] = used_cbufs.try_emplace(index);
entry->second.MarkAsUsed(offset); entry->second.MarkAsUsed(offset);
return StoreNode(CbufNode(index, Immediate(offset))); return MakeNode<CbufNode>(index, Immediate(offset));
} }
Node ShaderIR::GetConstBufferIndirect(u64 index_, u64 offset_, Node node) { Node ShaderIR::GetConstBufferIndirect(u64 index_, u64 offset_, Node node) {
@ -80,7 +62,7 @@ Node ShaderIR::GetConstBufferIndirect(u64 index_, u64 offset_, Node node) {
entry->second.MarkAsUsedIndirect(); entry->second.MarkAsUsedIndirect();
const Node final_offset = Operation(OperationCode::UAdd, NO_PRECISE, node, Immediate(offset)); const Node final_offset = Operation(OperationCode::UAdd, NO_PRECISE, node, Immediate(offset));
return StoreNode(CbufNode(index, final_offset)); return MakeNode<CbufNode>(index, final_offset);
} }
Node ShaderIR::GetPredicate(u64 pred_, bool negated) { Node ShaderIR::GetPredicate(u64 pred_, bool negated) {
@ -89,7 +71,7 @@ Node ShaderIR::GetPredicate(u64 pred_, bool negated) {
used_predicates.insert(pred); used_predicates.insert(pred);
} }
return StoreNode(PredicateNode(pred, negated)); return MakeNode<PredicateNode>(pred, negated);
} }
Node ShaderIR::GetPredicate(bool immediate) { Node ShaderIR::GetPredicate(bool immediate) {
@ -98,12 +80,12 @@ Node ShaderIR::GetPredicate(bool immediate) {
Node ShaderIR::GetInputAttribute(Attribute::Index index, u64 element, Node buffer) { Node ShaderIR::GetInputAttribute(Attribute::Index index, u64 element, Node buffer) {
used_input_attributes.emplace(index); used_input_attributes.emplace(index);
return StoreNode(AbufNode(index, static_cast<u32>(element), buffer)); return MakeNode<AbufNode>(index, static_cast<u32>(element), buffer);
} }
Node ShaderIR::GetPhysicalInputAttribute(Tegra::Shader::Register physical_address, Node buffer) { Node ShaderIR::GetPhysicalInputAttribute(Tegra::Shader::Register physical_address, Node buffer) {
uses_physical_attributes = true; uses_physical_attributes = true;
return StoreNode(AbufNode(GetRegister(physical_address), buffer)); return MakeNode<AbufNode>(GetRegister(physical_address), buffer);
} }
Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buffer) { Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buffer) {
@ -115,11 +97,11 @@ Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buff
} }
used_output_attributes.insert(index); used_output_attributes.insert(index);
return StoreNode(AbufNode(index, static_cast<u32>(element), buffer)); return MakeNode<AbufNode>(index, static_cast<u32>(element), buffer);
} }
Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) { Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) {
const Node node = StoreNode(InternalFlagNode(flag)); const Node node = MakeNode<InternalFlagNode>(flag);
if (negated) { if (negated) {
return Operation(OperationCode::LogicalNegate, node); return Operation(OperationCode::LogicalNegate, node);
} }
@ -127,7 +109,7 @@ Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) {
} }
Node ShaderIR::GetLocalMemory(Node address) { Node ShaderIR::GetLocalMemory(Node address) {
return StoreNode(LmemNode(address)); return MakeNode<LmemNode>(address);
} }
Node ShaderIR::GetTemporal(u32 id) { Node ShaderIR::GetTemporal(u32 id) {
@ -393,68 +375,4 @@ Node ShaderIR::BitfieldExtract(Node value, u32 offset, u32 bits) {
Immediate(bits)); Immediate(bits));
} }
/*static*/ OperationCode ShaderIR::SignedToUnsignedCode(OperationCode operation_code,
bool is_signed) {
if (is_signed) {
return operation_code;
}
switch (operation_code) {
case OperationCode::FCastInteger:
return OperationCode::FCastUInteger;
case OperationCode::IAdd:
return OperationCode::UAdd;
case OperationCode::IMul:
return OperationCode::UMul;
case OperationCode::IDiv:
return OperationCode::UDiv;
case OperationCode::IMin:
return OperationCode::UMin;
case OperationCode::IMax:
return OperationCode::UMax;
case OperationCode::ICastFloat:
return OperationCode::UCastFloat;
case OperationCode::ICastUnsigned:
return OperationCode::UCastSigned;
case OperationCode::ILogicalShiftLeft:
return OperationCode::ULogicalShiftLeft;
case OperationCode::ILogicalShiftRight:
return OperationCode::ULogicalShiftRight;
case OperationCode::IArithmeticShiftRight:
return OperationCode::UArithmeticShiftRight;
case OperationCode::IBitwiseAnd:
return OperationCode::UBitwiseAnd;
case OperationCode::IBitwiseOr:
return OperationCode::UBitwiseOr;
case OperationCode::IBitwiseXor:
return OperationCode::UBitwiseXor;
case OperationCode::IBitwiseNot:
return OperationCode::UBitwiseNot;
case OperationCode::IBitfieldInsert:
return OperationCode::UBitfieldInsert;
case OperationCode::IBitCount:
return OperationCode::UBitCount;
case OperationCode::LogicalILessThan:
return OperationCode::LogicalULessThan;
case OperationCode::LogicalIEqual:
return OperationCode::LogicalUEqual;
case OperationCode::LogicalILessEqual:
return OperationCode::LogicalULessEqual;
case OperationCode::LogicalIGreaterThan:
return OperationCode::LogicalUGreaterThan;
case OperationCode::LogicalINotEqual:
return OperationCode::LogicalUNotEqual;
case OperationCode::LogicalIGreaterEqual:
return OperationCode::LogicalUGreaterEqual;
case OperationCode::INegate:
UNREACHABLE_MSG("Can't negate an unsigned integer");
return {};
case OperationCode::IAbsolute:
UNREACHABLE_MSG("Can't apply absolute to an unsigned integer");
return {};
default:
UNREACHABLE_MSG("Unknown signed operation with code={}", static_cast<u32>(operation_code));
return {};
}
}
} // namespace VideoCommon::Shader } // namespace VideoCommon::Shader

View file

@ -38,7 +38,7 @@ using ProgramCode = std::vector<u64>;
using NodeData = using NodeData =
std::variant<OperationNode, ConditionalNode, GprNode, ImmediateNode, InternalFlagNode, std::variant<OperationNode, ConditionalNode, GprNode, ImmediateNode, InternalFlagNode,
PredicateNode, AbufNode, CbufNode, LmemNode, GmemNode, CommentNode>; PredicateNode, AbufNode, CbufNode, LmemNode, GmemNode, CommentNode>;
using Node = const NodeData*; using Node = std::shared_ptr<NodeData>;
using Node4 = std::array<Node, 4>; using Node4 = std::array<Node, 4>;
using NodeBlock = std::vector<Node>; using NodeBlock = std::vector<Node>;
@ -342,23 +342,20 @@ using Meta = std::variant<MetaArithmetic, MetaTexture, Tegra::Shader::HalfType>;
/// Holds any kind of operation that can be done in the IR /// Holds any kind of operation that can be done in the IR
class OperationNode final { class OperationNode final {
public: public:
explicit OperationNode(OperationCode code) : code{code} {} explicit OperationNode(OperationCode code) : OperationNode(code, Meta{}) {}
explicit OperationNode(OperationCode code, Meta&& meta) : code{code}, meta{std::move(meta)} {} explicit OperationNode(OperationCode code, Meta meta)
: OperationNode(code, meta, std::vector<Node>{}) {}
template <typename... T> explicit OperationNode(OperationCode code, std::vector<Node> operands)
explicit OperationNode(OperationCode code, const T*... operands) : OperationNode(code, Meta{}, std::move(operands)) {}
: OperationNode(code, {}, operands...) {}
template <typename... T> explicit OperationNode(OperationCode code, Meta meta, std::vector<Node> operands)
explicit OperationNode(OperationCode code, Meta&& meta, const T*... operands_) : code{code}, meta{std::move(meta)}, operands{std::move(operands)} {}
: code{code}, meta{std::move(meta)}, operands{operands_...} {}
explicit OperationNode(OperationCode code, Meta&& meta, std::vector<Node>&& operands) template <typename... Args>
: code{code}, meta{meta}, operands{std::move(operands)} {} explicit OperationNode(OperationCode code, Meta meta, Args&&... operands)
: code{code}, meta{std::move(meta)}, operands{operands...} {}
explicit OperationNode(OperationCode code, std::vector<Node>&& operands)
: code{code}, operands{std::move(operands)} {}
OperationCode GetCode() const { OperationCode GetCode() const {
return code; return code;
@ -372,13 +369,13 @@ public:
return operands.size(); return operands.size();
} }
Node operator[](std::size_t operand_index) const { const Node& operator[](std::size_t operand_index) const {
return operands.at(operand_index); return operands.at(operand_index);
} }
private: private:
const OperationCode code; OperationCode code{};
const Meta meta; Meta meta{};
std::vector<Node> operands; std::vector<Node> operands;
}; };
@ -463,13 +460,12 @@ private:
class AbufNode final { class AbufNode final {
public: public:
// Initialize for standard attributes (index is explicit). // Initialize for standard attributes (index is explicit).
explicit constexpr AbufNode(Tegra::Shader::Attribute::Index index, u32 element, explicit AbufNode(Tegra::Shader::Attribute::Index index, u32 element, Node buffer = {})
Node buffer = {}) : buffer{std::move(buffer)}, index{index}, element{element} {}
: buffer{buffer}, index{index}, element{element} {}
// Initialize for physical attributes (index is a variable value). // Initialize for physical attributes (index is a variable value).
explicit constexpr AbufNode(Node physical_address, Node buffer = {}) explicit AbufNode(Node physical_address, Node buffer = {})
: physical_address{physical_address}, buffer{buffer} {} : physical_address{physical_address}, buffer{std::move(buffer)} {}
Tegra::Shader::Attribute::Index GetIndex() const { Tegra::Shader::Attribute::Index GetIndex() const {
return index; return index;
@ -484,16 +480,16 @@ public:
} }
bool IsPhysicalBuffer() const { bool IsPhysicalBuffer() const {
return physical_address != nullptr; return static_cast<bool>(physical_address);
} }
Node GetPhysicalAddress() const { const Node& GetPhysicalAddress() const {
return physical_address; return physical_address;
} }
private: private:
Node physical_address{}; Node physical_address;
Node buffer{}; Node buffer;
Tegra::Shader::Attribute::Index index{}; Tegra::Shader::Attribute::Index index{};
u32 element{}; u32 element{};
}; };
@ -501,7 +497,7 @@ private:
/// Constant buffer node, usually mapped to uniform buffers in GLSL /// Constant buffer node, usually mapped to uniform buffers in GLSL
class CbufNode final { class CbufNode final {
public: public:
explicit constexpr CbufNode(u32 index, Node offset) : index{index}, offset{offset} {} explicit CbufNode(u32 index, Node offset) : index{index}, offset{offset} {}
u32 GetIndex() const { u32 GetIndex() const {
return index; return index;
@ -519,7 +515,7 @@ private:
/// Local memory node /// Local memory node
class LmemNode final { class LmemNode final {
public: public:
explicit constexpr LmemNode(Node address) : address{address} {} explicit LmemNode(Node address) : address{address} {}
Node GetAddress() const { Node GetAddress() const {
return address; return address;
@ -532,8 +528,7 @@ private:
/// Global memory node /// Global memory node
class GmemNode final { class GmemNode final {
public: public:
explicit constexpr GmemNode(Node real_address, Node base_address, explicit GmemNode(Node real_address, Node base_address, const GlobalMemoryBase& descriptor)
const GlobalMemoryBase& descriptor)
: real_address{real_address}, base_address{base_address}, descriptor{descriptor} {} : real_address{real_address}, base_address{base_address}, descriptor{descriptor} {}
Node GetRealAddress() const { Node GetRealAddress() const {
@ -663,26 +658,6 @@ private:
u32 DecodeXmad(NodeBlock& bb, u32 pc); u32 DecodeXmad(NodeBlock& bb, u32 pc);
u32 DecodeOther(NodeBlock& bb, u32 pc); u32 DecodeOther(NodeBlock& bb, u32 pc);
/// Internalizes node's data and returns a managed pointer to a clone of that node
Node StoreNode(NodeData&& node_data);
/// Creates a conditional node
Node Conditional(Node condition, std::vector<Node>&& code);
/// Creates a commentary
Node Comment(std::string text);
/// Creates an u32 immediate
Node Immediate(u32 value);
/// Creates a s32 immediate
Node Immediate(s32 value) {
return Immediate(static_cast<u32>(value));
}
/// Creates a f32 immediate
Node Immediate(f32 value) {
u32 integral;
std::memcpy(&integral, &value, sizeof(u32));
return Immediate(integral);
}
/// Generates a node for a passed register. /// Generates a node for a passed register.
Node GetRegister(Tegra::Shader::Register reg); Node GetRegister(Tegra::Shader::Register reg);
/// Generates a node representing a 19-bit immediate value /// Generates a node representing a 19-bit immediate value
@ -827,37 +802,6 @@ private:
std::tuple<Node, Node, GlobalMemoryBase> TrackAndGetGlobalMemory( std::tuple<Node, Node, GlobalMemoryBase> TrackAndGetGlobalMemory(
NodeBlock& bb, Tegra::Shader::Instruction instr, bool is_write); NodeBlock& bb, Tegra::Shader::Instruction instr, bool is_write);
template <typename... T>
Node Operation(OperationCode code, const T*... operands) {
return StoreNode(OperationNode(code, operands...));
}
template <typename... T>
Node Operation(OperationCode code, Meta&& meta, const T*... operands) {
return StoreNode(OperationNode(code, std::move(meta), operands...));
}
Node Operation(OperationCode code, std::vector<Node>&& operands) {
return StoreNode(OperationNode(code, std::move(operands)));
}
Node Operation(OperationCode code, Meta&& meta, std::vector<Node>&& operands) {
return StoreNode(OperationNode(code, std::move(meta), std::move(operands)));
}
template <typename... T>
Node SignedOperation(OperationCode code, bool is_signed, const T*... operands) {
return StoreNode(OperationNode(SignedToUnsignedCode(code, is_signed), operands...));
}
template <typename... T>
Node SignedOperation(OperationCode code, bool is_signed, Meta&& meta, const T*... operands) {
return StoreNode(
OperationNode(SignedToUnsignedCode(code, is_signed), std::move(meta), operands...));
}
static OperationCode SignedToUnsignedCode(OperationCode operation_code, bool is_signed);
const ProgramCode& program_code; const ProgramCode& program_code;
const u32 main_offset; const u32 main_offset;
@ -868,8 +812,6 @@ private:
std::map<u32, NodeBlock> basic_blocks; std::map<u32, NodeBlock> basic_blocks;
NodeBlock global_code; NodeBlock global_code;
std::vector<std::unique_ptr<NodeData>> stored_nodes;
std::set<u32> used_registers; std::set<u32> used_registers;
std::set<Tegra::Shader::Pred> used_predicates; std::set<Tegra::Shader::Pred> used_predicates;
std::set<Tegra::Shader::Attribute::Index> used_input_attributes; std::set<Tegra::Shader::Attribute::Index> used_input_attributes;

View file

@ -16,12 +16,12 @@ std::pair<Node, s64> FindOperation(const NodeBlock& code, s64 cursor,
OperationCode operation_code) { OperationCode operation_code) {
for (; cursor >= 0; --cursor) { for (; cursor >= 0; --cursor) {
const Node node = code.at(cursor); const Node node = code.at(cursor);
if (const auto operation = std::get_if<OperationNode>(node)) { if (const auto operation = std::get_if<OperationNode>(&*node)) {
if (operation->GetCode() == operation_code) { if (operation->GetCode() == operation_code) {
return {node, cursor}; return {node, cursor};
} }
} }
if (const auto conditional = std::get_if<ConditionalNode>(node)) { if (const auto conditional = std::get_if<ConditionalNode>(&*node)) {
const auto& conditional_code = conditional->GetCode(); const auto& conditional_code = conditional->GetCode();
const auto [found, internal_cursor] = FindOperation( const auto [found, internal_cursor] = FindOperation(
conditional_code, static_cast<s64>(conditional_code.size() - 1), operation_code); conditional_code, static_cast<s64>(conditional_code.size() - 1), operation_code);
@ -35,11 +35,11 @@ std::pair<Node, s64> FindOperation(const NodeBlock& code, s64 cursor,
} // namespace } // namespace
Node ShaderIR::TrackCbuf(Node tracked, const NodeBlock& code, s64 cursor) const { Node ShaderIR::TrackCbuf(Node tracked, const NodeBlock& code, s64 cursor) const {
if (const auto cbuf = std::get_if<CbufNode>(tracked)) { if (const auto cbuf = std::get_if<CbufNode>(&*tracked)) {
// Cbuf found, but it has to be immediate // Cbuf found, but it has to be immediate
return std::holds_alternative<ImmediateNode>(*cbuf->GetOffset()) ? tracked : nullptr; return std::holds_alternative<ImmediateNode>(*cbuf->GetOffset()) ? tracked : nullptr;
} }
if (const auto gpr = std::get_if<GprNode>(tracked)) { if (const auto gpr = std::get_if<GprNode>(&*tracked)) {
if (gpr->GetIndex() == Tegra::Shader::Register::ZeroIndex) { if (gpr->GetIndex() == Tegra::Shader::Register::ZeroIndex) {
return nullptr; return nullptr;
} }
@ -51,7 +51,7 @@ Node ShaderIR::TrackCbuf(Node tracked, const NodeBlock& code, s64 cursor) const
} }
return TrackCbuf(source, code, new_cursor); return TrackCbuf(source, code, new_cursor);
} }
if (const auto operation = std::get_if<OperationNode>(tracked)) { if (const auto operation = std::get_if<OperationNode>(&*tracked)) {
for (std::size_t i = 0; i < operation->GetOperandsCount(); ++i) { for (std::size_t i = 0; i < operation->GetOperandsCount(); ++i) {
if (const auto found = TrackCbuf((*operation)[i], code, cursor)) { if (const auto found = TrackCbuf((*operation)[i], code, cursor)) {
// Cbuf found in operand // Cbuf found in operand
@ -60,7 +60,7 @@ Node ShaderIR::TrackCbuf(Node tracked, const NodeBlock& code, s64 cursor) const
} }
return nullptr; return nullptr;
} }
if (const auto conditional = std::get_if<ConditionalNode>(tracked)) { if (const auto conditional = std::get_if<ConditionalNode>(&*tracked)) {
const auto& conditional_code = conditional->GetCode(); const auto& conditional_code = conditional->GetCode();
return TrackCbuf(tracked, conditional_code, static_cast<s64>(conditional_code.size())); return TrackCbuf(tracked, conditional_code, static_cast<s64>(conditional_code.size()));
} }
@ -75,7 +75,7 @@ std::optional<u32> ShaderIR::TrackImmediate(Node tracked, const NodeBlock& code,
if (!found) { if (!found) {
return {}; return {};
} }
if (const auto immediate = std::get_if<ImmediateNode>(found)) { if (const auto immediate = std::get_if<ImmediateNode>(&*found)) {
return immediate->GetValue(); return immediate->GetValue();
} }
return {}; return {};
@ -88,11 +88,11 @@ std::pair<Node, s64> ShaderIR::TrackRegister(const GprNode* tracked, const NodeB
if (!found_node) { if (!found_node) {
return {}; return {};
} }
const auto operation = std::get_if<OperationNode>(found_node); const auto operation = std::get_if<OperationNode>(&*found_node);
ASSERT(operation); ASSERT(operation);
const auto& target = (*operation)[0]; const auto& target = (*operation)[0];
if (const auto gpr_target = std::get_if<GprNode>(target)) { if (const auto gpr_target = std::get_if<GprNode>(&*target)) {
if (gpr_target->GetIndex() == tracked->GetIndex()) { if (gpr_target->GetIndex() == tracked->GetIndex()) {
return {(*operation)[1], new_cursor}; return {(*operation)[1], new_cursor};
} }