30 changed files with 1573 additions and 0 deletions
-
27src/video_core/CMakeLists.txt
-
4src/video_core/engines/shader_bytecode.h
-
199src/video_core/shader/decode.cpp
-
24src/video_core/shader/decode/arithmetic.cpp
-
24src/video_core/shader/decode/arithmetic_half.cpp
-
24src/video_core/shader/decode/arithmetic_half_immediate.cpp
-
24src/video_core/shader/decode/arithmetic_immediate.cpp
-
24src/video_core/shader/decode/arithmetic_integer.cpp
-
24src/video_core/shader/decode/arithmetic_integer_immediate.cpp
-
24src/video_core/shader/decode/bfe.cpp
-
24src/video_core/shader/decode/bfi.cpp
-
24src/video_core/shader/decode/conversion.cpp
-
0src/video_core/shader/decode/decode_integer_set.cpp
-
24src/video_core/shader/decode/ffma.cpp
-
24src/video_core/shader/decode/float_set.cpp
-
24src/video_core/shader/decode/float_set_predicate.cpp
-
24src/video_core/shader/decode/half_set.cpp
-
24src/video_core/shader/decode/half_set_predicate.cpp
-
24src/video_core/shader/decode/hfma2.cpp
-
24src/video_core/shader/decode/integer_set.cpp
-
24src/video_core/shader/decode/integer_set_predicate.cpp
-
24src/video_core/shader/decode/memory.cpp
-
24src/video_core/shader/decode/other.cpp
-
24src/video_core/shader/decode/predicate_set_predicate.cpp
-
24src/video_core/shader/decode/predicate_set_register.cpp
-
24src/video_core/shader/decode/register_set_predicate.cpp
-
24src/video_core/shader/decode/shift.cpp
-
24src/video_core/shader/decode/xmad.cpp
-
105src/video_core/shader/shader_ir.cpp
-
662src/video_core/shader/shader_ir.h
@ -0,0 +1,199 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include <cstring>
|
||||
|
#include <set>
|
||||
|
|
||||
|
#include <fmt/format.h>
|
||||
|
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/engines/shader_header.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
/// Merges exit method of two parallel branches.
|
||||
|
constexpr ExitMethod ParallelExit(ExitMethod a, ExitMethod b) { |
||||
|
if (a == ExitMethod::Undetermined) { |
||||
|
return b; |
||||
|
} |
||||
|
if (b == ExitMethod::Undetermined) { |
||||
|
return a; |
||||
|
} |
||||
|
if (a == b) { |
||||
|
return a; |
||||
|
} |
||||
|
return ExitMethod::Conditional; |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* Returns whether the instruction at the specified offset is a 'sched' instruction. |
||||
|
* Sched instructions always appear before a sequence of 3 instructions. |
||||
|
*/ |
||||
|
constexpr bool IsSchedInstruction(u32 offset, u32 main_offset) { |
||||
|
constexpr u32 SchedPeriod = 4; |
||||
|
u32 absolute_offset = offset - main_offset; |
||||
|
|
||||
|
return (absolute_offset % SchedPeriod) == 0; |
||||
|
} |
||||
|
|
||||
|
void ShaderIR::Decode() { |
||||
|
std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header)); |
||||
|
|
||||
|
std::set<u32> labels; |
||||
|
const ExitMethod exit_method = Scan(main_offset, MAX_PROGRAM_LENGTH, labels); |
||||
|
if (exit_method != ExitMethod::AlwaysEnd) { |
||||
|
UNREACHABLE_MSG("Program does not always end"); |
||||
|
} |
||||
|
|
||||
|
if (labels.empty()) { |
||||
|
basic_blocks.insert({main_offset, DecodeRange(main_offset, MAX_PROGRAM_LENGTH)}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
labels.insert(main_offset); |
||||
|
|
||||
|
for (const u32 label : labels) { |
||||
|
const auto next_it = labels.lower_bound(label + 1); |
||||
|
const u32 next_label = next_it == labels.end() ? MAX_PROGRAM_LENGTH : *next_it; |
||||
|
|
||||
|
basic_blocks.insert({label, DecodeRange(label, next_label)}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
ExitMethod ShaderIR::Scan(u32 begin, u32 end, std::set<u32>& labels) { |
||||
|
const auto [iter, inserted] = |
||||
|
exit_method_map.emplace(std::make_pair(begin, end), ExitMethod::Undetermined); |
||||
|
ExitMethod& exit_method = iter->second; |
||||
|
if (!inserted) |
||||
|
return exit_method; |
||||
|
|
||||
|
for (u32 offset = begin; offset != end && offset != MAX_PROGRAM_LENGTH; ++offset) { |
||||
|
coverage_begin = std::min(coverage_begin, offset); |
||||
|
coverage_end = std::max(coverage_end, offset + 1); |
||||
|
|
||||
|
const Instruction instr = {program_code[offset]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
if (!opcode) |
||||
|
continue; |
||||
|
switch (opcode->get().GetId()) { |
||||
|
case OpCode::Id::EXIT: { |
||||
|
// The EXIT instruction can be predicated, which means that the shader can conditionally
|
||||
|
// end on this instruction. We have to consider the case where the condition is not met
|
||||
|
// and check the exit method of that other basic block.
|
||||
|
using Tegra::Shader::Pred; |
||||
|
if (instr.pred.pred_index == static_cast<u64>(Pred::UnusedIndex)) { |
||||
|
return exit_method = ExitMethod::AlwaysEnd; |
||||
|
} else { |
||||
|
const ExitMethod not_met = Scan(offset + 1, end, labels); |
||||
|
return exit_method = ParallelExit(ExitMethod::AlwaysEnd, not_met); |
||||
|
} |
||||
|
} |
||||
|
case OpCode::Id::BRA: { |
||||
|
const u32 target = offset + instr.bra.GetBranchTarget(); |
||||
|
labels.insert(target); |
||||
|
const ExitMethod no_jmp = Scan(offset + 1, end, labels); |
||||
|
const ExitMethod jmp = Scan(target, end, labels); |
||||
|
return exit_method = ParallelExit(no_jmp, jmp); |
||||
|
} |
||||
|
case OpCode::Id::SSY: |
||||
|
case OpCode::Id::PBK: { |
||||
|
// The SSY and PBK use a similar encoding as the BRA instruction.
|
||||
|
UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0, |
||||
|
"Constant buffer branching is not supported"); |
||||
|
const u32 target = offset + instr.bra.GetBranchTarget(); |
||||
|
labels.insert(target); |
||||
|
// Continue scanning for an exit method.
|
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return exit_method = ExitMethod::AlwaysReturn; |
||||
|
} |
||||
|
|
||||
|
BasicBlock ShaderIR::DecodeRange(u32 begin, u32 end) { |
||||
|
BasicBlock basic_block; |
||||
|
for (u32 pc = begin; pc < (begin > end ? MAX_PROGRAM_LENGTH : end);) { |
||||
|
pc = DecodeInstr(basic_block, pc); |
||||
|
} |
||||
|
return std::move(basic_block); |
||||
|
} |
||||
|
|
||||
|
u32 ShaderIR::DecodeInstr(BasicBlock& bb, u32 pc) { |
||||
|
// Ignore sched instructions when generating code.
|
||||
|
if (IsSchedInstruction(pc, main_offset)) { |
||||
|
return pc + 1; |
||||
|
} |
||||
|
|
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
// Decoding failure
|
||||
|
if (!opcode) { |
||||
|
UNIMPLEMENTED_MSG("Unhandled instruction: {0:x}", instr.value); |
||||
|
return pc + 1; |
||||
|
} |
||||
|
|
||||
|
bb.push_back( |
||||
|
Comment(fmt::format("{}: {} (0x{:016x})", pc, opcode->get().GetName(), instr.value))); |
||||
|
|
||||
|
using Tegra::Shader::Pred; |
||||
|
UNIMPLEMENTED_IF_MSG(instr.pred.full_pred == Pred::NeverExecute, |
||||
|
"NeverExecute predicate not implemented"); |
||||
|
|
||||
|
static const std::map<OpCode::Type, u32 (ShaderIR::*)(BasicBlock & code, u32 pc)> decoders = { |
||||
|
{OpCode::Type::Arithmetic, &ShaderIR::DecodeArithmetic}, |
||||
|
{OpCode::Type::ArithmeticImmediate, &ShaderIR::DecodeArithmeticImmediate}, |
||||
|
{OpCode::Type::Bfe, &ShaderIR::DecodeBfe}, |
||||
|
{OpCode::Type::Bfi, &ShaderIR::DecodeBfi}, |
||||
|
{OpCode::Type::Shift, &ShaderIR::DecodeShift}, |
||||
|
{OpCode::Type::ArithmeticInteger, &ShaderIR::DecodeArithmeticInteger}, |
||||
|
{OpCode::Type::ArithmeticIntegerImmediate, &ShaderIR::DecodeArithmeticIntegerImmediate}, |
||||
|
{OpCode::Type::ArithmeticHalf, &ShaderIR::DecodeArithmeticHalf}, |
||||
|
{OpCode::Type::ArithmeticHalfImmediate, &ShaderIR::DecodeArithmeticHalfImmediate}, |
||||
|
{OpCode::Type::Ffma, &ShaderIR::DecodeFfma}, |
||||
|
{OpCode::Type::Hfma2, &ShaderIR::DecodeHfma2}, |
||||
|
{OpCode::Type::Conversion, &ShaderIR::DecodeConversion}, |
||||
|
{OpCode::Type::Memory, &ShaderIR::DecodeMemory}, |
||||
|
{OpCode::Type::FloatSetPredicate, &ShaderIR::DecodeFloatSetPredicate}, |
||||
|
{OpCode::Type::IntegerSetPredicate, &ShaderIR::DecodeIntegerSetPredicate}, |
||||
|
{OpCode::Type::HalfSetPredicate, &ShaderIR::DecodeHalfSetPredicate}, |
||||
|
{OpCode::Type::PredicateSetRegister, &ShaderIR::DecodePredicateSetRegister}, |
||||
|
{OpCode::Type::PredicateSetPredicate, &ShaderIR::DecodePredicateSetPredicate}, |
||||
|
{OpCode::Type::RegisterSetPredicate, &ShaderIR::DecodeRegisterSetPredicate}, |
||||
|
{OpCode::Type::FloatSet, &ShaderIR::DecodeFloatSet}, |
||||
|
{OpCode::Type::IntegerSet, &ShaderIR::DecodeIntegerSet}, |
||||
|
{OpCode::Type::HalfSet, &ShaderIR::DecodeHalfSet}, |
||||
|
{OpCode::Type::Xmad, &ShaderIR::DecodeXmad}, |
||||
|
}; |
||||
|
|
||||
|
std::vector<Node> code; |
||||
|
if (const auto decoder = decoders.find(opcode->get().GetType()); decoder != decoders.end()) { |
||||
|
pc = (this->*decoder->second)(code, pc); |
||||
|
} else { |
||||
|
pc = DecodeOther(code, pc); |
||||
|
} |
||||
|
|
||||
|
// Some instructions (like SSY) don't have a predicate field, they are always unconditionally
|
||||
|
// executed.
|
||||
|
const bool can_be_predicated = OpCode::IsPredicatedInstruction(opcode->get().GetId()); |
||||
|
const auto pred_index = static_cast<u32>(instr.pred.pred_index); |
||||
|
|
||||
|
if (can_be_predicated && pred_index != static_cast<u32>(Pred::UnusedIndex)) { |
||||
|
bb.push_back( |
||||
|
Conditional(GetPredicate(pred_index, instr.negate_pred != 0), std::move(code))); |
||||
|
} else { |
||||
|
for (auto& node : code) { |
||||
|
bb.push_back(std::move(node)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return pc + 1; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeArithmetic(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeArithmeticHalf(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeArithmeticHalfImmediate(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeArithmeticImmediate(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeArithmeticInteger(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeArithmeticIntegerImmediate(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeBfe(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeBfi(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeConversion(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeFfma(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeFloatSet(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeFloatSetPredicate(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeHalfSet(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeHalfSetPredicate(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeHfma2(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeIntegerSet(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeIntegerSetPredicate(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeMemory(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeOther(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodePredicateSetPredicate(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodePredicateSetRegister(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeRegisterSetPredicate(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeShift(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::OpCode; |
||||
|
|
||||
|
u32 ShaderIR::DecodeXmad(BasicBlock& bb, u32 pc) { |
||||
|
const Instruction instr = {program_code[pc]}; |
||||
|
const auto opcode = OpCode::Decode(instr); |
||||
|
|
||||
|
UNIMPLEMENTED(); |
||||
|
|
||||
|
return pc; |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,105 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include <cmath>
|
||||
|
#include <unordered_map>
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||
|
#include "video_core/shader/shader_ir.h"
|
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
using Tegra::Shader::Attribute; |
||||
|
using Tegra::Shader::Instruction; |
||||
|
using Tegra::Shader::IpaMode; |
||||
|
using Tegra::Shader::Pred; |
||||
|
using Tegra::Shader::PredCondition; |
||||
|
using Tegra::Shader::PredOperation; |
||||
|
using Tegra::Shader::Register; |
||||
|
|
||||
|
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(const std::string& text) { |
||||
|
return StoreNode(CommentNode(text)); |
||||
|
} |
||||
|
|
||||
|
Node ShaderIR::GetPredicate(u64 pred_, bool negated) { |
||||
|
const auto pred = static_cast<Pred>(pred_); |
||||
|
if (pred != Pred::UnusedIndex && pred != Pred::NeverExecute) { |
||||
|
used_predicates.insert(pred); |
||||
|
} |
||||
|
|
||||
|
return StoreNode(PredicateNode(pred, negated)); |
||||
|
} |
||||
|
|
||||
|
/*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::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"); |
||||
|
case OperationCode::IAbsolute: |
||||
|
UNREACHABLE_MSG("Can't apply absolute to an unsigned integer"); |
||||
|
} |
||||
|
UNREACHABLE_MSG("Unknown signed operation with code={}", static_cast<u32>(operation_code)); |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Shader
|
||||
@ -0,0 +1,662 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <map> |
||||
|
#include <set> |
||||
|
#include <string> |
||||
|
#include <tuple> |
||||
|
#include <variant> |
||||
|
#include <vector> |
||||
|
|
||||
|
#include "common/assert.h" |
||||
|
#include "common/common_types.h" |
||||
|
#include "video_core/engines/maxwell_3d.h" |
||||
|
#include "video_core/engines/shader_bytecode.h" |
||||
|
#include "video_core/engines/shader_header.h" |
||||
|
|
||||
|
namespace VideoCommon::Shader { |
||||
|
|
||||
|
class OperationNode; |
||||
|
class ConditionalNode; |
||||
|
class GprNode; |
||||
|
class ImmediateNode; |
||||
|
class InternalFlagNode; |
||||
|
class PredicateNode; |
||||
|
class AbufNode; ///< Attribute buffer |
||||
|
class CbufNode; ///< Constant buffer |
||||
|
class LmemNode; ///< Local memory |
||||
|
class GmemNode; ///< Global memory |
||||
|
class CommentNode; |
||||
|
|
||||
|
using ProgramCode = std::vector<u64>; |
||||
|
|
||||
|
using NodeData = |
||||
|
std::variant<OperationNode, ConditionalNode, GprNode, ImmediateNode, InternalFlagNode, |
||||
|
PredicateNode, AbufNode, CbufNode, LmemNode, GmemNode, CommentNode>; |
||||
|
using Node = const NodeData*; |
||||
|
using BasicBlock = std::vector<Node>; |
||||
|
|
||||
|
constexpr u32 MAX_PROGRAM_LENGTH = 0x1000; |
||||
|
|
||||
|
constexpr u32 RZ = 0xff; |
||||
|
|
||||
|
enum class OperationCode { |
||||
|
Assign, /// (float& dest, float src) -> void |
||||
|
AssignComposite, /// (MetaComponents, float4 src, float&[4] dst) -> void |
||||
|
|
||||
|
Composite, /// (float[4] values) -> float4 |
||||
|
Select, /// (MetaArithmetic, bool pred, float a, float b) -> float |
||||
|
|
||||
|
FAdd, /// (MetaArithmetic, float a, float b) -> float |
||||
|
FMul, /// (MetaArithmetic, float a, float b) -> float |
||||
|
FDiv, /// (MetaArithmetic, float a, float b) -> float |
||||
|
FFma, /// (MetaArithmetic, float a, float b, float c) -> float |
||||
|
FNegate, /// (MetaArithmetic, float a) -> float |
||||
|
FAbsolute, /// (MetaArithmetic, float a) -> float |
||||
|
FClamp, /// (MetaArithmetic, float value, float min, float max) -> float |
||||
|
FMin, /// (MetaArithmetic, float a, float b) -> float |
||||
|
FMax, /// (MetaArithmetic, float a, float b) -> float |
||||
|
FCos, /// (MetaArithmetic, float a) -> float |
||||
|
FSin, /// (MetaArithmetic, float a) -> float |
||||
|
FExp2, /// (MetaArithmetic, float a) -> float |
||||
|
FLog2, /// (MetaArithmetic, float a) -> float |
||||
|
FInverseSqrt, /// (MetaArithmetic, float a) -> float |
||||
|
FSqrt, /// (MetaArithmetic, float a) -> float |
||||
|
FRoundEven, /// (MetaArithmetic, float a) -> float |
||||
|
FFloor, /// (MetaArithmetic, float a) -> float |
||||
|
FCeil, /// (MetaArithmetic, float a) -> float |
||||
|
FTrunc, /// (MetaArithmetic, float a) -> float |
||||
|
FCastInteger, /// (MetaArithmetic, int a) -> float |
||||
|
FCastUInteger, /// (MetaArithmetic, uint a) -> float |
||||
|
|
||||
|
IAdd, /// (MetaArithmetic, int a, int b) -> int |
||||
|
IMul, /// (MetaArithmetic, int a, int b) -> int |
||||
|
IDiv, /// (MetaArithmetic, int a, int b) -> int |
||||
|
INegate, /// (MetaArithmetic, int a) -> int |
||||
|
IAbsolute, /// (MetaArithmetic, int a) -> int |
||||
|
IMin, /// (MetaArithmetic, int a, int b) -> int |
||||
|
IMax, /// (MetaArithmetic, int a, int b) -> int |
||||
|
ICastFloat, /// (MetaArithmetic, float a) -> int |
||||
|
ICastUnsigned, /// (MetaArithmetic, uint a) -> int |
||||
|
ILogicalShiftLeft, /// (MetaArithmetic, int a, uint b) -> int |
||||
|
ILogicalShiftRight, /// (MetaArithmetic, int a, uint b) -> int |
||||
|
IArithmeticShiftRight, /// (MetaArithmetic, int a, uint b) -> int |
||||
|
IBitwiseAnd, /// (MetaArithmetic, int a, int b) -> int |
||||
|
IBitwiseOr, /// (MetaArithmetic, int a, int b) -> int |
||||
|
IBitwiseXor, /// (MetaArithmetic, int a, int b) -> int |
||||
|
IBitwiseNot, /// (MetaArithmetic, int a) -> int |
||||
|
IBitfieldInsert, /// (MetaArithmetic, int base, int insert, int offset, int bits) -> int |
||||
|
|
||||
|
UAdd, /// (MetaArithmetic, uint a, uint b) -> uint |
||||
|
UMul, /// (MetaArithmetic, uint a, uint b) -> uint |
||||
|
UDiv, /// (MetaArithmetic, uint a, uint b) -> uint |
||||
|
UMin, /// (MetaArithmetic, uint a, uint b) -> uint |
||||
|
UMax, /// (MetaArithmetic, uint a, uint b) -> uint |
||||
|
UCastFloat, /// (MetaArithmetic, float a) -> uint |
||||
|
UCastSigned, /// (MetaArithmetic, int a) -> uint |
||||
|
ULogicalShiftLeft, /// (MetaArithmetic, uint a, uint b) -> uint |
||||
|
ULogicalShiftRight, /// (MetaArithmetic, uint a, uint b) -> uint |
||||
|
UArithmeticShiftRight, /// (MetaArithmetic, uint a, uint b) -> uint |
||||
|
UBitwiseAnd, /// (MetaArithmetic, uint a, uint b) -> uint |
||||
|
UBitwiseOr, /// (MetaArithmetic, uint a, uint b) -> uint |
||||
|
UBitwiseXor, /// (MetaArithmetic, uint a, uint b) -> uint |
||||
|
UBitwiseNot, /// (MetaArithmetic, uint a) -> int |
||||
|
UBitfieldInsert, /// (MetaArithmetic, uint base, uint insert, int offset, int bits) -> uint |
||||
|
|
||||
|
HAdd, /// (MetaHalfArithmetic, f16vec2 a, f16vec2 b) -> f16vec2 |
||||
|
HMul, /// (MetaHalfArithmetic, f16vec2 a, f16vec2 b) -> f16vec2 |
||||
|
HAbsolute, /// (f16vec2 a) -> f16vec2 |
||||
|
HNegate, /// (f16vec2 a, bool first, bool second) -> f16vec2 |
||||
|
HMergeF32, /// (f16vec2 src) -> float |
||||
|
HMergeH0, /// (f16vec2 dest, f16vec2 src) -> f16vec2 |
||||
|
HMergeH1, /// (f16vec2 dest, f16vec2 src) -> f16vec2 |
||||
|
|
||||
|
LogicalAssign, /// (bool& dst, bool src) -> void |
||||
|
LogicalAnd, /// (bool a, bool b) -> bool |
||||
|
LogicalOr, /// (bool a, bool b) -> bool |
||||
|
LogicalXor, /// (bool a, bool b) -> bool |
||||
|
LogicalNegate, /// (bool a) -> bool |
||||
|
|
||||
|
LogicalFLessThan, /// (float a, float b) -> bool |
||||
|
LogicalFEqual, /// (float a, float b) -> bool |
||||
|
LogicalFLessEqual, /// (float a, float b) -> bool |
||||
|
LogicalFGreaterThan, /// (float a, float b) -> bool |
||||
|
LogicalFNotEqual, /// (float a, float b) -> bool |
||||
|
LogicalFGreaterEqual, /// (float a, float b) -> bool |
||||
|
LogicalFIsNan, /// (float a) -> bool |
||||
|
|
||||
|
LogicalILessThan, /// (int a, int b) -> bool |
||||
|
LogicalIEqual, /// (int a, int b) -> bool |
||||
|
LogicalILessEqual, /// (int a, int b) -> bool |
||||
|
LogicalIGreaterThan, /// (int a, int b) -> bool |
||||
|
LogicalINotEqual, /// (int a, int b) -> bool |
||||
|
LogicalIGreaterEqual, /// (int a, int b) -> bool |
||||
|
|
||||
|
LogicalULessThan, /// (uint a, uint b) -> bool |
||||
|
LogicalUEqual, /// (uint a, uint b) -> bool |
||||
|
LogicalULessEqual, /// (uint a, uint b) -> bool |
||||
|
LogicalUGreaterThan, /// (uint a, uint b) -> bool |
||||
|
LogicalUNotEqual, /// (uint a, uint b) -> bool |
||||
|
LogicalUGreaterEqual, /// (uint a, uint b) -> bool |
||||
|
|
||||
|
LogicalHLessThan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool |
||||
|
LogicalHEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool |
||||
|
LogicalHLessEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool |
||||
|
LogicalHGreaterThan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool |
||||
|
LogicalHNotEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool |
||||
|
LogicalHGreaterEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool |
||||
|
|
||||
|
F4Texture, /// (MetaTexture, float[N] coords, float[M] params) -> float4 |
||||
|
F4TextureLod, /// (MetaTexture, float[N] coords, float[M] params) -> float4 |
||||
|
F4TextureGather, /// (MetaTexture, float[N] coords, float[M] params) -> float4 |
||||
|
F4TextureQueryDimensions, /// (MetaTexture, float a) -> float4 |
||||
|
F4TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4 |
||||
|
|
||||
|
Ipa, /// (abuf src) -> float |
||||
|
|
||||
|
Bra, /// (uint branch_target) -> void |
||||
|
Ssy, /// (uint branch_target) -> void |
||||
|
Pbk, /// (uint branch_target) -> void |
||||
|
Sync, /// () -> void |
||||
|
Brk, /// () -> void |
||||
|
Exit, /// () -> void |
||||
|
Kil, /// () -> void |
||||
|
|
||||
|
YNegate, /// () -> float |
||||
|
|
||||
|
Amount, |
||||
|
}; |
||||
|
|
||||
|
enum class InternalFlag { |
||||
|
Zero = 0, |
||||
|
Sign = 1, |
||||
|
Carry = 2, |
||||
|
Overflow = 3, |
||||
|
Amount = 4, |
||||
|
}; |
||||
|
|
||||
|
/// Describes the behaviour of code path of a given entry point and a return point. |
||||
|
enum class ExitMethod { |
||||
|
Undetermined, ///< Internal value. Only occur when analyzing JMP loop. |
||||
|
AlwaysReturn, ///< All code paths reach the return point. |
||||
|
Conditional, ///< Code path reaches the return point or an END instruction conditionally. |
||||
|
AlwaysEnd, ///< All code paths reach a END instruction. |
||||
|
}; |
||||
|
|
||||
|
class Sampler { |
||||
|
public: |
||||
|
explicit Sampler(std::size_t offset, std::size_t index, Tegra::Shader::TextureType type, |
||||
|
bool is_array, bool is_shadow) |
||||
|
: offset{offset}, index{index}, type{type}, is_array{is_array}, is_shadow{is_shadow} {} |
||||
|
|
||||
|
std::size_t GetOffset() const { |
||||
|
return offset; |
||||
|
} |
||||
|
|
||||
|
u32 GetIndex() const { |
||||
|
return static_cast<u32>(index); |
||||
|
} |
||||
|
|
||||
|
Tegra::Shader::TextureType GetType() const { |
||||
|
return type; |
||||
|
} |
||||
|
|
||||
|
bool IsArray() const { |
||||
|
return is_array; |
||||
|
} |
||||
|
|
||||
|
bool IsShadow() const { |
||||
|
return is_shadow; |
||||
|
} |
||||
|
|
||||
|
bool operator<(const Sampler& rhs) const { |
||||
|
return std::tie(offset, index, type, is_array, is_shadow) < |
||||
|
std::tie(rhs.offset, rhs.index, rhs.type, rhs.is_array, rhs.is_shadow); |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
/// Offset in TSC memory from which to read the sampler object, as specified by the sampling |
||||
|
/// instruction. |
||||
|
std::size_t offset{}; |
||||
|
std::size_t index{}; ///< Value used to index into the generated GLSL sampler array. |
||||
|
Tegra::Shader::TextureType type{}; ///< The type used to sample this texture (Texture2D, etc) |
||||
|
bool is_array{}; ///< Whether the texture is being sampled as an array texture or not. |
||||
|
bool is_shadow{}; ///< Whether the texture is being sampled as a depth texture or not. |
||||
|
}; |
||||
|
|
||||
|
class ConstBuffer { |
||||
|
public: |
||||
|
void MarkAsUsed(u64 offset) { |
||||
|
max_offset = std::max(max_offset, static_cast<u32>(offset)); |
||||
|
} |
||||
|
|
||||
|
void MarkAsUsedIndirect() { |
||||
|
is_indirect = true; |
||||
|
} |
||||
|
|
||||
|
bool IsIndirect() const { |
||||
|
return is_indirect; |
||||
|
} |
||||
|
|
||||
|
u32 GetSize() const { |
||||
|
return max_offset + 1; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
u32 max_offset{}; |
||||
|
bool is_indirect{}; |
||||
|
}; |
||||
|
|
||||
|
struct MetaArithmetic { |
||||
|
bool precise{}; |
||||
|
}; |
||||
|
|
||||
|
struct MetaHalfArithmetic { |
||||
|
bool precise{}; |
||||
|
std::array<Tegra::Shader::HalfType, 3> types = {Tegra::Shader::HalfType::H0_H1, |
||||
|
Tegra::Shader::HalfType::H0_H1, |
||||
|
Tegra::Shader::HalfType::H0_H1}; |
||||
|
bool and_comparison{}; |
||||
|
}; |
||||
|
|
||||
|
struct MetaTexture { |
||||
|
const Sampler& sampler; |
||||
|
u32 coords_count{}; |
||||
|
}; |
||||
|
|
||||
|
struct MetaComponents { |
||||
|
std::array<u32, 4> components_map{}; |
||||
|
|
||||
|
u32 GetSourceComponent(u32 dest_index) const { |
||||
|
return components_map[dest_index]; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
constexpr MetaArithmetic PRECISE = {true}; |
||||
|
constexpr MetaArithmetic NO_PRECISE = {false}; |
||||
|
constexpr MetaHalfArithmetic HALF_NO_PRECISE = {false}; |
||||
|
|
||||
|
using Meta = std::variant<MetaArithmetic, MetaHalfArithmetic, MetaTexture, MetaComponents>; |
||||
|
|
||||
|
/// Holds any kind of operation that can be done in the IR |
||||
|
class OperationNode final { |
||||
|
public: |
||||
|
template <typename... T> |
||||
|
explicit constexpr OperationNode(OperationCode code) : code{code}, meta{} {} |
||||
|
|
||||
|
template <typename... T> |
||||
|
explicit constexpr OperationNode(OperationCode code, Meta&& meta) |
||||
|
: code{code}, meta{std::move(meta)} {} |
||||
|
|
||||
|
template <typename... T> |
||||
|
explicit constexpr OperationNode(OperationCode code, const T*... operands) |
||||
|
: OperationNode(code, {}, operands...) {} |
||||
|
|
||||
|
template <typename... T> |
||||
|
explicit constexpr OperationNode(OperationCode code, Meta&& meta, const T*... operands_) |
||||
|
: code{code}, meta{std::move(meta)} { |
||||
|
|
||||
|
auto operands_list = {operands_...}; |
||||
|
for (auto& operand : operands_list) { |
||||
|
operands.push_back(operand); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
explicit OperationNode(OperationCode code, Meta&& meta, std::vector<Node>&& operands) |
||||
|
: code{code}, meta{meta}, operands{std::move(operands)} {} |
||||
|
|
||||
|
explicit OperationNode(OperationCode code, std::vector<Node>&& operands) |
||||
|
: code{code}, meta{}, operands{std::move(operands)} {} |
||||
|
|
||||
|
OperationCode GetCode() const { |
||||
|
return code; |
||||
|
} |
||||
|
|
||||
|
const Meta& GetMeta() const { |
||||
|
return meta; |
||||
|
} |
||||
|
|
||||
|
std::size_t GetOperandsCount() const { |
||||
|
return operands.size(); |
||||
|
} |
||||
|
|
||||
|
Node operator[](std::size_t operand_index) const { |
||||
|
return operands.at(operand_index); |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
const OperationCode code; |
||||
|
const Meta meta; |
||||
|
std::vector<Node> operands; |
||||
|
}; |
||||
|
|
||||
|
/// Encloses inside any kind of node that returns a boolean conditionally-executed code |
||||
|
class ConditionalNode final { |
||||
|
public: |
||||
|
explicit ConditionalNode(Node condition, std::vector<Node>&& code) |
||||
|
: condition{condition}, code{std::move(code)} {} |
||||
|
|
||||
|
Node GetCondition() const { |
||||
|
return condition; |
||||
|
} |
||||
|
|
||||
|
const std::vector<Node>& GetCode() const { |
||||
|
return code; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
const Node condition; ///< Condition to be satisfied |
||||
|
std::vector<Node> code; ///< Code to execute |
||||
|
}; |
||||
|
|
||||
|
/// A general purpose register |
||||
|
class GprNode final { |
||||
|
public: |
||||
|
explicit constexpr GprNode(Tegra::Shader::Register index) : index{index} {} |
||||
|
|
||||
|
u32 GetIndex() const { |
||||
|
return static_cast<u32>(index); |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
const Tegra::Shader::Register index; |
||||
|
}; |
||||
|
|
||||
|
/// A 32-bits value that represents an immediate value |
||||
|
class ImmediateNode final { |
||||
|
public: |
||||
|
explicit constexpr ImmediateNode(u32 value) : value{value} {} |
||||
|
|
||||
|
u32 GetValue() const { |
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
const u32 value; |
||||
|
}; |
||||
|
|
||||
|
/// One of Maxwell's internal flags |
||||
|
class InternalFlagNode final { |
||||
|
public: |
||||
|
explicit constexpr InternalFlagNode(InternalFlag flag) : flag{flag} {} |
||||
|
|
||||
|
InternalFlag GetFlag() const { |
||||
|
return flag; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
const InternalFlag flag; |
||||
|
}; |
||||
|
|
||||
|
/// A predicate register, it can be negated without aditional nodes |
||||
|
class PredicateNode final { |
||||
|
public: |
||||
|
explicit constexpr PredicateNode(Tegra::Shader::Pred index, bool negated) |
||||
|
: index{index}, negated{negated} {} |
||||
|
|
||||
|
Tegra::Shader::Pred GetIndex() const { |
||||
|
return index; |
||||
|
} |
||||
|
|
||||
|
bool IsNegated() const { |
||||
|
return negated; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
const Tegra::Shader::Pred index; |
||||
|
const bool negated; |
||||
|
}; |
||||
|
|
||||
|
/// Attribute buffer memory (known as attributes or varyings in GLSL terms) |
||||
|
class AbufNode final { |
||||
|
public: |
||||
|
explicit constexpr AbufNode(Tegra::Shader::Attribute::Index index, u32 element, |
||||
|
const Tegra::Shader::IpaMode& input_mode, Node buffer = {}) |
||||
|
: input_mode{input_mode}, index{index}, element{element}, buffer{buffer} {} |
||||
|
|
||||
|
explicit constexpr AbufNode(Tegra::Shader::Attribute::Index index, u32 element, |
||||
|
Node buffer = {}) |
||||
|
: input_mode{}, index{index}, element{element}, buffer{buffer} {} |
||||
|
|
||||
|
Tegra::Shader::IpaMode GetInputMode() const { |
||||
|
return input_mode; |
||||
|
} |
||||
|
|
||||
|
Tegra::Shader::Attribute::Index GetIndex() const { |
||||
|
return index; |
||||
|
} |
||||
|
|
||||
|
u32 GetElement() const { |
||||
|
return element; |
||||
|
} |
||||
|
|
||||
|
Node GetBuffer() const { |
||||
|
return buffer; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
const Tegra::Shader::IpaMode input_mode; |
||||
|
const Node buffer; |
||||
|
const Tegra::Shader::Attribute::Index index; |
||||
|
const u32 element; |
||||
|
}; |
||||
|
|
||||
|
/// Constant buffer node, usually mapped to uniform buffers in GLSL |
||||
|
class CbufNode final { |
||||
|
public: |
||||
|
explicit constexpr CbufNode(u32 index, Node offset) : index{index}, offset{offset} {} |
||||
|
|
||||
|
u32 GetIndex() const { |
||||
|
return index; |
||||
|
} |
||||
|
|
||||
|
Node GetOffset() const { |
||||
|
return offset; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
const u32 index; |
||||
|
const Node offset; |
||||
|
}; |
||||
|
|
||||
|
/// Local memory node |
||||
|
class LmemNode final { |
||||
|
public: |
||||
|
explicit constexpr LmemNode(Node address) : address{address} {} |
||||
|
|
||||
|
Node GetAddress() const { |
||||
|
return address; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
const Node address; |
||||
|
}; |
||||
|
|
||||
|
/// Global memory node |
||||
|
class GmemNode final { |
||||
|
public: |
||||
|
explicit GmemNode(Node address) : address{address} {} |
||||
|
|
||||
|
Node GetAddress() const { |
||||
|
return address; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
const Node address; |
||||
|
}; |
||||
|
|
||||
|
/// Commentary, can be dropped |
||||
|
class CommentNode final { |
||||
|
public: |
||||
|
explicit CommentNode(const std::string& text) : text{text} {} |
||||
|
|
||||
|
const std::string& GetText() const { |
||||
|
return text; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
const std::string text; |
||||
|
}; |
||||
|
|
||||
|
class ShaderIR final { |
||||
|
public: |
||||
|
explicit ShaderIR(const ProgramCode& program_code, u32 main_offset) |
||||
|
: program_code{program_code}, main_offset{main_offset} { |
||||
|
|
||||
|
Decode(); |
||||
|
} |
||||
|
|
||||
|
const std::map<u32, BasicBlock>& GetBasicBlocks() const { |
||||
|
return basic_blocks; |
||||
|
} |
||||
|
|
||||
|
const std::set<u32>& GetRegisters() const { |
||||
|
return used_registers; |
||||
|
} |
||||
|
|
||||
|
const std::set<Tegra::Shader::Pred>& GetPredicates() const { |
||||
|
return used_predicates; |
||||
|
} |
||||
|
|
||||
|
const std::map<Tegra::Shader::Attribute::Index, std::set<Tegra::Shader::IpaMode>>& |
||||
|
GetInputAttributes() const { |
||||
|
return used_input_attributes; |
||||
|
} |
||||
|
|
||||
|
const std::set<Tegra::Shader::Attribute::Index>& GetOutputAttributes() const { |
||||
|
return used_output_attributes; |
||||
|
} |
||||
|
|
||||
|
const std::map<u32, ConstBuffer>& GetConstantBuffers() const { |
||||
|
return used_cbufs; |
||||
|
} |
||||
|
|
||||
|
const std::set<Sampler>& GetSamplers() const { |
||||
|
return used_samplers; |
||||
|
} |
||||
|
|
||||
|
const std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances>& GetClipDistances() |
||||
|
const { |
||||
|
return used_clip_distances; |
||||
|
} |
||||
|
|
||||
|
std::size_t GetLength() const { |
||||
|
return static_cast<std::size_t>(coverage_end * sizeof(u64)); |
||||
|
} |
||||
|
|
||||
|
const Tegra::Shader::Header& GetHeader() const { |
||||
|
return header; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
void Decode(); |
||||
|
|
||||
|
ExitMethod Scan(u32 begin, u32 end, std::set<u32>& labels); |
||||
|
|
||||
|
BasicBlock DecodeRange(u32 begin, u32 end); |
||||
|
|
||||
|
/** |
||||
|
* Decodes a single instruction from Tegra to IR. |
||||
|
* @param bb Basic block where the nodes will be written to. |
||||
|
* @param pc Program counter. Offset to decode. |
||||
|
* @return Next address to decode. |
||||
|
*/ |
||||
|
u32 DecodeInstr(BasicBlock& bb, u32 pc); |
||||
|
|
||||
|
u32 DecodeArithmetic(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeArithmeticImmediate(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeBfe(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeBfi(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeShift(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeArithmeticInteger(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeArithmeticIntegerImmediate(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeArithmeticHalf(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeArithmeticHalfImmediate(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeFfma(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeHfma2(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeConversion(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeMemory(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeFloatSetPredicate(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeIntegerSetPredicate(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeHalfSetPredicate(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodePredicateSetRegister(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodePredicateSetPredicate(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeRegisterSetPredicate(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeFloatSet(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeIntegerSet(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeHalfSet(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeXmad(BasicBlock& bb, u32 pc); |
||||
|
u32 DecodeOther(BasicBlock& 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(const std::string& text); |
||||
|
|
||||
|
/// Generates a node for a passed predicate. It can be optionally negated |
||||
|
Node GetPredicate(u64 pred, bool negated = false); |
||||
|
|
||||
|
template <typename... T> |
||||
|
inline Node Operation(OperationCode code, const T*... operands) { |
||||
|
return StoreNode(OperationNode(code, operands...)); |
||||
|
} |
||||
|
|
||||
|
template <typename... T> |
||||
|
inline Node Operation(OperationCode code, Meta&& meta, const T*... operands) { |
||||
|
return StoreNode(OperationNode(code, std::move(meta), operands...)); |
||||
|
} |
||||
|
|
||||
|
template <typename... T> |
||||
|
inline Node Operation(OperationCode code, std::vector<Node>&& operands) { |
||||
|
return StoreNode(OperationNode(code, std::move(operands))); |
||||
|
} |
||||
|
|
||||
|
template <typename... T> |
||||
|
inline Node Operation(OperationCode code, Meta&& meta, std::vector<Node>&& operands) { |
||||
|
return StoreNode(OperationNode(code, std::move(meta), std::move(operands))); |
||||
|
} |
||||
|
|
||||
|
template <typename... T> |
||||
|
inline Node SignedOperation(OperationCode code, bool is_signed, const T*... operands) { |
||||
|
return StoreNode(OperationNode(SignedToUnsignedCode(code, is_signed), operands...)); |
||||
|
} |
||||
|
|
||||
|
template <typename... T> |
||||
|
inline 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 u32 main_offset; |
||||
|
|
||||
|
u32 coverage_begin{}; |
||||
|
u32 coverage_end{}; |
||||
|
std::map<std::pair<u32, u32>, ExitMethod> exit_method_map; |
||||
|
|
||||
|
std::map<u32, BasicBlock> basic_blocks; |
||||
|
|
||||
|
std::vector<std::unique_ptr<NodeData>> stored_nodes; |
||||
|
|
||||
|
std::set<u32> used_registers; |
||||
|
std::set<Tegra::Shader::Pred> used_predicates; |
||||
|
std::map<Tegra::Shader::Attribute::Index, std::set<Tegra::Shader::IpaMode>> |
||||
|
used_input_attributes; |
||||
|
std::set<Tegra::Shader::Attribute::Index> used_output_attributes; |
||||
|
std::map<u32, ConstBuffer> used_cbufs; |
||||
|
std::set<Sampler> used_samplers; |
||||
|
std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{}; |
||||
|
|
||||
|
Tegra::Shader::Header header; |
||||
|
}; |
||||
|
|
||||
|
} // namespace VideoCommon::Shader |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue