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.h17
-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.cpp52
5 files changed, 96 insertions, 20 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 83f7cc3a9..3add56155 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -255,9 +255,9 @@ union Instruction {
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;
@@ -298,6 +298,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;
@@ -316,6 +329,7 @@ class OpCode {
public:
enum class Id {
KIL,
+ BRA,
LD_A,
ST_A,
TEX,
@@ -480,6 +494,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 618c603c2..8c263f15f 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);
+ }
}
}
}
@@ -860,8 +882,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 =
@@ -874,6 +895,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);
@@ -1103,7 +1135,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: {
@@ -1128,6 +1165,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);