summaryrefslogtreecommitdiffstats
path: root/src/video_core
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/engines/maxwell_3d.h40
-rw-r--r--src/video_core/engines/shader_bytecode.h27
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp4
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp3
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp111
5 files changed, 159 insertions, 26 deletions
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 5cf62fb01..245410c95 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -354,10 +354,35 @@ public:
f32 scale_x;
f32 scale_y;
f32 scale_z;
- u32 translate_x;
- u32 translate_y;
- u32 translate_z;
+ f32 translate_x;
+ f32 translate_y;
+ f32 translate_z;
INSERT_PADDING_WORDS(2);
+
+ MathUtil::Rectangle<s32> GetRect() const {
+ return {
+ GetX(), // left
+ GetY() + GetHeight(), // top
+ GetX() + GetWidth(), // right
+ GetY() // bottom
+ };
+ };
+
+ s32 GetX() const {
+ return static_cast<s32>(std::max(0.0f, translate_x - std::fabs(scale_x)));
+ }
+
+ s32 GetY() const {
+ return static_cast<s32>(std::max(0.0f, translate_y - std::fabs(scale_y)));
+ }
+
+ s32 GetWidth() const {
+ return static_cast<s32>(translate_x + std::fabs(scale_x)) - GetX();
+ }
+
+ s32 GetHeight() const {
+ return static_cast<s32>(translate_y + std::fabs(scale_y)) - GetY();
+ }
} viewport_transform[NumViewports];
struct {
@@ -371,15 +396,6 @@ public:
};
float depth_range_near;
float depth_range_far;
-
- MathUtil::Rectangle<s32> GetRect() const {
- return {
- static_cast<s32>(x), // left
- static_cast<s32>(y + height), // top
- static_cast<s32>(x + width), // right
- static_cast<s32>(y) // bottom
- };
- };
} viewport[NumViewports];
INSERT_PADDING_WORDS(0x1D);
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 14d72920f..22c122fcc 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -252,15 +252,25 @@ union Instruction {
} fsetp;
union {
+ BitField<0, 3, u64> pred0;
+ BitField<3, 3, u64> pred3;
+ BitField<39, 3, u64> pred39;
+ BitField<42, 1, u64> neg_pred;
+ BitField<45, 2, PredOperation> op;
+ BitField<48, 1, u64> is_signed;
+ BitField<49, 3, PredCondition> cond;
+ } isetp;
+
+ union {
BitField<39, 3, u64> pred39;
BitField<42, 1, u64> neg_pred;
BitField<43, 1, u64> neg_a;
BitField<44, 1, u64> abs_b;
BitField<45, 2, PredOperation> op;
BitField<48, 4, PredCondition> cond;
+ BitField<52, 1, u64> bf;
BitField<53, 1, u64> neg_b;
BitField<54, 1, u64> abs_a;
- BitField<52, 1, u64> bf;
BitField<55, 1, u64> ftz;
BitField<56, 1, u64> neg_imm;
} fset;
@@ -301,6 +311,19 @@ union Instruction {
}
} texs;
+ union {
+ BitField<20, 5, u64> target;
+ BitField<5, 1, u64> constant_buffer;
+
+ s32 GetBranchTarget() const {
+ // Sign extend the branch target offset
+ u32 mask = 1U << (5 - 1);
+ u32 value = static_cast<u32>(target);
+ // The branch offset is relative to the next instruction, so add 1 to it.
+ return static_cast<s32>((value ^ mask) - mask) + 1;
+ }
+ } bra;
+
BitField<61, 1, u64> is_b_imm;
BitField<60, 1, u64> is_b_gpr;
BitField<59, 1, u64> is_c_gpr;
@@ -319,6 +342,7 @@ class OpCode {
public:
enum class Id {
KIL,
+ BRA,
LD_A,
ST_A,
TEX,
@@ -484,6 +508,7 @@ private:
std::vector<Matcher> table = {
#define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name)
INST("111000110011----", Id::KIL, Type::Flow, "KIL"),
+ INST("111000100100----", Id::BRA, Type::Flow, "BRA"),
INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"),
INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"),
INST("1100000000111---", Id::TEX, Type::Memory, "TEX"),
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 35c1b1890..0a33868b7 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -298,7 +298,7 @@ void RasterizerOpenGL::DrawArrays() {
const bool has_stencil = false;
const bool using_color_fb = true;
const bool using_depth_fb = false;
- const MathUtil::Rectangle<s32> viewport_rect{regs.viewport[0].GetRect()};
+ const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()};
const bool write_color_fb =
state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE ||
@@ -702,7 +702,7 @@ void RasterizerOpenGL::BindFramebufferSurfaces(const Surface& color_surface,
void RasterizerOpenGL::SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect, u16 res_scale) {
const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
- const MathUtil::Rectangle<s32> viewport_rect{regs.viewport[0].GetRect()};
+ const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()};
state.viewport.x = static_cast<GLint>(surfaces_rect.left) + viewport_rect.left * res_scale;
state.viewport.y = static_cast<GLint>(surfaces_rect.bottom) + viewport_rect.bottom * res_scale;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 65d643447..d6048f639 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -933,7 +933,8 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, ScaleMatc
// Use GetSurfaceSubRect instead
ASSERT(params.width == params.stride);
- ASSERT(!params.is_tiled || (params.width % 8 == 0 && params.height % 8 == 0));
+ ASSERT(!params.is_tiled ||
+ (params.GetActualWidth() % 8 == 0 && params.GetActualHeight() % 8 == 0));
// Check for an exact match in existing surfaces
Surface surface =
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index e29f0a1d3..9943394c6 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -88,6 +88,20 @@ private:
return *subroutines.insert(std::move(subroutine)).first;
}
+ /// Merges exit method of two parallel branches.
+ static 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;
+ }
+
/// Scans a range of code for labels and determines the exit method.
ExitMethod Scan(u32 begin, u32 end, std::set<u32>& labels) {
auto [iter, inserted] =
@@ -97,11 +111,19 @@ private:
return exit_method;
for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) {
- if (const auto opcode = OpCode::Decode({program_code[offset]})) {
+ const Instruction instr = {program_code[offset]};
+ if (const auto opcode = OpCode::Decode(instr)) {
switch (opcode->GetId()) {
case OpCode::Id::EXIT: {
return exit_method = ExitMethod::AlwaysEnd;
}
+ case OpCode::Id::BRA: {
+ u32 target = offset + instr.bra.GetBranchTarget();
+ labels.insert(target);
+ ExitMethod no_jmp = Scan(offset + 1, end, labels);
+ ExitMethod jmp = Scan(target, end, labels);
+ return exit_method = ParallelExit(no_jmp, jmp);
+ }
}
}
}
@@ -197,6 +219,11 @@ public:
return active_type == Type::Integer;
}
+ /// Returns the current active type of the register
+ Type GetActiveType() const {
+ return active_type;
+ }
+
/// Returns the index of the register
size_t GetIndex() const {
return index;
@@ -328,22 +355,28 @@ public:
shader.AddLine(dest + " = " + src + ';');
}
- /// Generates code representing a uniform (C buffer) register.
- std::string GetUniform(const Uniform& uniform, const Register& dest_reg) {
+ /// Generates code representing a uniform (C buffer) register, interpreted as the input type.
+ std::string GetUniform(const Uniform& uniform, GLSLRegister::Type type) {
declr_const_buffers[uniform.index].MarkAsUsed(static_cast<unsigned>(uniform.index),
static_cast<unsigned>(uniform.offset), stage);
std::string value =
'c' + std::to_string(uniform.index) + '[' + std::to_string(uniform.offset) + ']';
- if (regs[dest_reg].IsFloat()) {
+ if (type == GLSLRegister::Type::Float) {
return value;
- } else if (regs[dest_reg].IsInteger()) {
+ } else if (type == GLSLRegister::Type::Integer) {
return "floatBitsToInt(" + value + ')';
} else {
UNREACHABLE();
}
}
+ /// Generates code representing a uniform (C buffer) register, interpreted as the type of the
+ /// destination register.
+ std::string GetUniform(const Uniform& uniform, const Register& dest_reg) {
+ return GetUniform(uniform, regs[dest_reg].GetActiveType());
+ }
+
/// Add declarations for registers
void GenerateDeclarations() {
for (const auto& reg : regs) {
@@ -892,8 +925,7 @@ private:
ASSERT_MSG(!instr.conversion.saturate_a, "Unimplemented");
switch (opcode->GetId()) {
- case OpCode::Id::I2I_R:
- case OpCode::Id::I2F_R: {
+ case OpCode::Id::I2I_R: {
ASSERT_MSG(!instr.conversion.selector, "Unimplemented");
std::string op_a =
@@ -906,6 +938,17 @@ private:
regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_signed, 0, op_a, 1, 1);
break;
}
+ case OpCode::Id::I2F_R: {
+ std::string op_a =
+ regs.GetRegisterAsInteger(instr.gpr20, 0, instr.conversion.is_signed);
+
+ if (instr.conversion.abs_a) {
+ op_a = "abs(" + op_a + ')';
+ }
+
+ regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1);
+ break;
+ }
case OpCode::Id::F2F_R: {
std::string op_a = regs.GetRegisterAsFloat(instr.gpr20);
@@ -1029,7 +1072,7 @@ private:
if (instr.is_b_gpr) {
op_b += regs.GetRegisterAsFloat(instr.gpr20);
} else {
- op_b += regs.GetUniform(instr.uniform, instr.gpr0);
+ op_b += regs.GetUniform(instr.uniform, GLSLRegister::Type::Float);
}
}
@@ -1060,6 +1103,42 @@ private:
}
break;
}
+ case OpCode::Type::IntegerSetPredicate: {
+ std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, instr.isetp.is_signed);
+
+ std::string op_b{};
+
+ ASSERT_MSG(!instr.is_b_imm, "ISETP_IMM not implemented");
+
+ if (instr.is_b_gpr) {
+ op_b += regs.GetRegisterAsInteger(instr.gpr20, 0, instr.isetp.is_signed);
+ } else {
+ op_b += regs.GetUniform(instr.uniform, GLSLRegister::Type::Integer);
+ }
+
+ using Tegra::Shader::Pred;
+ // We can't use the constant predicate as destination.
+ ASSERT(instr.isetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
+
+ std::string second_pred =
+ GetPredicateCondition(instr.isetp.pred39, instr.isetp.neg_pred != 0);
+
+ std::string comparator = GetPredicateComparison(instr.isetp.cond);
+ std::string combiner = GetPredicateCombiner(instr.isetp.op);
+
+ std::string predicate = '(' + op_a + ") " + comparator + " (" + op_b + ')';
+ // Set the primary predicate to the result of Predicate OP SecondPredicate
+ SetPredicate(instr.isetp.pred3,
+ '(' + predicate + ") " + combiner + " (" + second_pred + ')');
+
+ if (instr.isetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
+ // Set the secondary predicate to the result of !Predicate OP SecondPredicate,
+ // if enabled
+ SetPredicate(instr.isetp.pred0,
+ "!(" + predicate + ") " + combiner + " (" + second_pred + ')');
+ }
+ break;
+ }
case OpCode::Type::FloatSet: {
std::string op_a = instr.fset.neg_a ? "-" : "";
op_a += regs.GetRegisterAsFloat(instr.gpr8);
@@ -1080,7 +1159,7 @@ private:
if (instr.is_b_gpr) {
op_b += regs.GetRegisterAsFloat(instr.gpr20);
} else {
- op_b += regs.GetUniform(instr.uniform, instr.gpr0);
+ op_b += regs.GetUniform(instr.uniform, GLSLRegister::Type::Float);
}
}
@@ -1099,7 +1178,12 @@ private:
std::string predicate = "(((" + op_a + ") " + comparator + " (" + op_b + ")) " +
combiner + " (" + second_pred + "))";
- regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1);
+ if (instr.fset.bf) {
+ regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1);
+ } else {
+ regs.SetRegisterToInteger(instr.gpr0, false, 0, predicate + " ? 0xFFFFFFFF : 0", 1,
+ 1);
+ }
break;
}
default: {
@@ -1124,6 +1208,13 @@ private:
shader.AddLine("discard;");
break;
}
+ case OpCode::Id::BRA: {
+ ASSERT_MSG(instr.bra.constant_buffer == 0,
+ "BRA with constant buffers are not implemented");
+ u32 target = offset + instr.bra.GetBranchTarget();
+ shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }");
+ break;
+ }
case OpCode::Id::IPA: {
const auto& attribute = instr.attribute.fmt28;
regs.SetRegisterToInputAttibute(instr.gpr0, attribute.element, attribute.index);