From a1b845b6514e135a5810b12c20261ec646216c28 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Mon, 24 Dec 2018 01:23:00 -0300 Subject: shader_decode: Implement VMAD and VSETP --- src/video_core/shader/decode/video.cpp | 120 +++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 src/video_core/shader/decode/video.cpp (limited to 'src/video_core/shader/decode/video.cpp') diff --git a/src/video_core/shader/decode/video.cpp b/src/video_core/shader/decode/video.cpp new file mode 100644 index 000000000..9510896e4 --- /dev/null +++ b/src/video_core/shader/decode/video.cpp @@ -0,0 +1,120 @@ +// 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; +using Tegra::Shader::Pred; +using Tegra::Shader::VideoType; +using Tegra::Shader::VmadShr; + +u32 ShaderIR::DecodeVideo(BasicBlock& bb, u32 pc) { + const Instruction instr = {program_code[pc]}; + const auto opcode = OpCode::Decode(instr); + + const Node op_a = + GetVideoOperand(GetRegister(instr.gpr8), instr.video.is_byte_chunk_a, instr.video.signed_a, + instr.video.type_a, instr.video.byte_height_a); + const Node op_b = [&]() { + if (instr.video.use_register_b) { + return GetVideoOperand(GetRegister(instr.gpr20), instr.video.is_byte_chunk_b, + instr.video.signed_b, instr.video.type_b, + instr.video.byte_height_b); + } + if (instr.video.signed_b) { + const auto imm = static_cast(instr.alu.GetImm20_16()); + return Immediate(static_cast(imm)); + } else { + return Immediate(instr.alu.GetImm20_16()); + } + }(); + + switch (opcode->get().GetId()) { + case OpCode::Id::VMAD: { + UNIMPLEMENTED_IF_MSG(instr.generates_cc, + "Condition codes generation in VMAD is not implemented"); + + const bool result_signed = instr.video.signed_a == 1 || instr.video.signed_b == 1; + const Node op_c = GetRegister(instr.gpr39); + + Node value = SignedOperation(OperationCode::IMul, result_signed, NO_PRECISE, op_a, op_b); + value = SignedOperation(OperationCode::IAdd, result_signed, NO_PRECISE, value, op_c); + + if (instr.vmad.shr == VmadShr::Shr7 || instr.vmad.shr == VmadShr::Shr15) { + const Node shift = Immediate(instr.vmad.shr == VmadShr::Shr7 ? 7 : 15); + value = + SignedOperation(OperationCode::IArithmeticShiftRight, result_signed, value, shift); + } + + SetRegister(bb, instr.gpr0, value); + + break; + } + case OpCode::Id::VSETP: { + // We can't use the constant predicate as destination. + ASSERT(instr.vsetp.pred3 != static_cast(Pred::UnusedIndex)); + + const bool sign = instr.video.signed_a == 1 || instr.video.signed_b == 1; + const Node first_pred = GetPredicateComparisonInteger(instr.vsetp.cond, sign, op_a, op_b); + const Node second_pred = GetPredicate(instr.vsetp.pred39, false); + + const OperationCode combiner = GetPredicateCombiner(instr.vsetp.op); + + // Set the primary predicate to the result of Predicate OP SecondPredicate + SetPredicate(bb, instr.vsetp.pred3, Operation(combiner, first_pred, second_pred)); + + if (instr.vsetp.pred0 != static_cast(Pred::UnusedIndex)) { + // Set the secondary predicate to the result of !Predicate OP SecondPredicate, + // if enabled + const Node negate_pred = Operation(OperationCode::LogicalNegate, first_pred); + SetPredicate(bb, instr.vsetp.pred0, Operation(combiner, negate_pred, second_pred)); + } + break; + } + default: + UNIMPLEMENTED_MSG("Unhandled video instruction: {}", opcode->get().GetName()); + } + + return pc; +} + +Node ShaderIR::GetVideoOperand(Node op, bool is_chunk, bool is_signed, + Tegra::Shader::VideoType type, u64 byte_height) { + if (!is_chunk) { + const auto offset = static_cast(byte_height * 8); + const Node shift = SignedOperation(OperationCode::ILogicalShiftRight, is_signed, NO_PRECISE, + op, Immediate(offset)); + return SignedOperation(OperationCode::IBitwiseAnd, is_signed, NO_PRECISE, shift, + Immediate(0xff)); + } + const Node zero = Immediate(0); + + switch (type) { + case Tegra::Shader::VideoType::Size16_Low: + return SignedOperation(OperationCode::IBitwiseAnd, is_signed, NO_PRECISE, op, + Immediate(0xffff)); + case Tegra::Shader::VideoType::Size16_High: + return SignedOperation(OperationCode::ILogicalShiftRight, is_signed, NO_PRECISE, op, + Immediate(16)); + case Tegra::Shader::VideoType::Size32: + // TODO(Rodrigo): From my hardware tests it becomes a bit "mad" when this type is used + // (1 * 1 + 0 == 0x5b800000). Until a better explanation is found: abort. + UNIMPLEMENTED(); + return zero; + case Tegra::Shader::VideoType::Invalid: + UNREACHABLE_MSG("Invalid instruction encoding"); + return zero; + default: + UNREACHABLE(); + return zero; + } +} + +} // namespace VideoCommon::Shader \ No newline at end of file -- cgit v1.2.3 From 2faad9bf23dbcedc80dca7ed9ad4b81c0416dd5e Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Wed, 26 Dec 2018 02:58:47 -0300 Subject: shader_decode: Use BitfieldExtract instead of shift + and --- src/video_core/shader/decode/video.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'src/video_core/shader/decode/video.cpp') diff --git a/src/video_core/shader/decode/video.cpp b/src/video_core/shader/decode/video.cpp index 9510896e4..b491fbadb 100644 --- a/src/video_core/shader/decode/video.cpp +++ b/src/video_core/shader/decode/video.cpp @@ -88,21 +88,15 @@ u32 ShaderIR::DecodeVideo(BasicBlock& bb, u32 pc) { Node ShaderIR::GetVideoOperand(Node op, bool is_chunk, bool is_signed, Tegra::Shader::VideoType type, u64 byte_height) { if (!is_chunk) { - const auto offset = static_cast(byte_height * 8); - const Node shift = SignedOperation(OperationCode::ILogicalShiftRight, is_signed, NO_PRECISE, - op, Immediate(offset)); - return SignedOperation(OperationCode::IBitwiseAnd, is_signed, NO_PRECISE, shift, - Immediate(0xff)); + return BitfieldExtract(op, static_cast(byte_height * 8), 8); } const Node zero = Immediate(0); switch (type) { case Tegra::Shader::VideoType::Size16_Low: - return SignedOperation(OperationCode::IBitwiseAnd, is_signed, NO_PRECISE, op, - Immediate(0xffff)); + return BitfieldExtract(op, 0, 16); case Tegra::Shader::VideoType::Size16_High: - return SignedOperation(OperationCode::ILogicalShiftRight, is_signed, NO_PRECISE, op, - Immediate(16)); + return BitfieldExtract(op, 16, 16); case Tegra::Shader::VideoType::Size32: // TODO(Rodrigo): From my hardware tests it becomes a bit "mad" when this type is used // (1 * 1 + 0 == 0x5b800000). Until a better explanation is found: abort. -- cgit v1.2.3 From 2d6c064e66bac4cb871aa26a12066441a8852008 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 27 Dec 2018 16:50:36 -0300 Subject: shader_decode: Improve zero flag implementation --- src/video_core/shader/decode/video.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src/video_core/shader/decode/video.cpp') diff --git a/src/video_core/shader/decode/video.cpp b/src/video_core/shader/decode/video.cpp index b491fbadb..609b3a257 100644 --- a/src/video_core/shader/decode/video.cpp +++ b/src/video_core/shader/decode/video.cpp @@ -38,9 +38,6 @@ u32 ShaderIR::DecodeVideo(BasicBlock& bb, u32 pc) { switch (opcode->get().GetId()) { case OpCode::Id::VMAD: { - UNIMPLEMENTED_IF_MSG(instr.generates_cc, - "Condition codes generation in VMAD is not implemented"); - const bool result_signed = instr.video.signed_a == 1 || instr.video.signed_b == 1; const Node op_c = GetRegister(instr.gpr39); @@ -53,8 +50,8 @@ u32 ShaderIR::DecodeVideo(BasicBlock& bb, u32 pc) { SignedOperation(OperationCode::IArithmeticShiftRight, result_signed, value, shift); } + SetInternalFlagsFromInteger(bb, value, instr.generates_cc); SetRegister(bb, instr.gpr0, value); - break; } case OpCode::Id::VSETP: { -- cgit v1.2.3 From 170c8212bbb10129dfbaed8eb7ab67138c932af2 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Fri, 28 Dec 2018 20:00:36 -0300 Subject: shader_ir: Pass to decoder functions basic block's code --- src/video_core/shader/decode/video.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/video_core/shader/decode/video.cpp') diff --git a/src/video_core/shader/decode/video.cpp b/src/video_core/shader/decode/video.cpp index 609b3a257..c3432356d 100644 --- a/src/video_core/shader/decode/video.cpp +++ b/src/video_core/shader/decode/video.cpp @@ -15,7 +15,7 @@ using Tegra::Shader::Pred; using Tegra::Shader::VideoType; using Tegra::Shader::VmadShr; -u32 ShaderIR::DecodeVideo(BasicBlock& bb, u32 pc) { +u32 ShaderIR::DecodeVideo(BasicBlock& bb, const BasicBlock& code, u32 pc) { const Instruction instr = {program_code[pc]}; const auto opcode = OpCode::Decode(instr); -- cgit v1.2.3