summaryrefslogtreecommitdiffstats
path: root/src/video_core/engines
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/engines')
-rw-r--r--src/video_core/engines/fermi_2d.cpp4
-rw-r--r--src/video_core/engines/maxwell_3d.cpp104
-rw-r--r--src/video_core/engines/maxwell_3d.h29
-rw-r--r--src/video_core/engines/shader_bytecode.h13
4 files changed, 145 insertions, 5 deletions
diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp
index 98a8b5337..7ff44f06d 100644
--- a/src/video_core/engines/fermi_2d.cpp
+++ b/src/video_core/engines/fermi_2d.cpp
@@ -29,8 +29,8 @@ void Fermi2D::CallMethod(const GPU::MethodCall& method_call) {
}
void Fermi2D::HandleSurfaceCopy() {
- LOG_WARNING(HW_GPU, "Requested a surface copy with operation {}",
- static_cast<u32>(regs.operation));
+ LOG_DEBUG(HW_GPU, "Requested a surface copy with operation {}",
+ static_cast<u32>(regs.operation));
// TODO(Subv): Only raw copies are implemented.
ASSERT(regs.operation == Operation::SrcCopy);
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index c7a3c85a0..b318aedb8 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -92,6 +92,10 @@ void Maxwell3D::InitializeRegisterDefaults() {
// Some games (like Super Mario Odyssey) assume that SRGB is enabled.
regs.framebuffer_srgb = 1;
+ mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_end_gl)] = true;
+ mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_begin_gl)] = true;
+ mme_inline[MAXWELL3D_REG_INDEX(vertex_buffer.count)] = true;
+ mme_inline[MAXWELL3D_REG_INDEX(index_array.count)] = true;
}
#define DIRTY_REGS_POS(field_name) (offsetof(Maxwell3D::DirtyRegs, field_name))
@@ -256,6 +260,9 @@ void Maxwell3D::CallMacroMethod(u32 method, std::size_t num_parameters, const u3
// Execute the current macro.
macro_interpreter.Execute(macro_positions[entry], num_parameters, parameters);
+ if (mme_draw.current_mode != MMEDrawMode::Undefined) {
+ FlushMMEInlineDraw();
+ }
}
void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
@@ -416,6 +423,97 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
}
}
+void Maxwell3D::StepInstance(const MMEDrawMode expected_mode, const u32 count) {
+ if (mme_draw.current_mode == MMEDrawMode::Undefined) {
+ if (mme_draw.gl_begin_consume) {
+ mme_draw.current_mode = expected_mode;
+ mme_draw.current_count = count;
+ mme_draw.instance_count = 1;
+ mme_draw.gl_begin_consume = false;
+ mme_draw.gl_end_count = 0;
+ }
+ return;
+ } else {
+ if (mme_draw.current_mode == expected_mode && count == mme_draw.current_count &&
+ mme_draw.instance_mode && mme_draw.gl_begin_consume) {
+ mme_draw.instance_count++;
+ mme_draw.gl_begin_consume = false;
+ return;
+ } else {
+ FlushMMEInlineDraw();
+ }
+ }
+ // Tail call in case it needs to retry.
+ StepInstance(expected_mode, count);
+}
+
+void Maxwell3D::CallMethodFromMME(const GPU::MethodCall& method_call) {
+ const u32 method = method_call.method;
+ if (mme_inline[method]) {
+ regs.reg_array[method] = method_call.argument;
+ if (method == MAXWELL3D_REG_INDEX(vertex_buffer.count) ||
+ method == MAXWELL3D_REG_INDEX(index_array.count)) {
+ const MMEDrawMode expected_mode = method == MAXWELL3D_REG_INDEX(vertex_buffer.count)
+ ? MMEDrawMode::Array
+ : MMEDrawMode::Indexed;
+ StepInstance(expected_mode, method_call.argument);
+ } else if (method == MAXWELL3D_REG_INDEX(draw.vertex_begin_gl)) {
+ mme_draw.instance_mode =
+ (regs.draw.instance_next != 0) || (regs.draw.instance_cont != 0);
+ mme_draw.gl_begin_consume = true;
+ } else {
+ mme_draw.gl_end_count++;
+ }
+ } else {
+ if (mme_draw.current_mode != MMEDrawMode::Undefined) {
+ FlushMMEInlineDraw();
+ }
+ CallMethod(method_call);
+ }
+}
+
+void Maxwell3D::FlushMMEInlineDraw() {
+ LOG_DEBUG(HW_GPU, "called, topology={}, count={}", static_cast<u32>(regs.draw.topology.Value()),
+ regs.vertex_buffer.count);
+ ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?");
+ ASSERT(mme_draw.instance_count == mme_draw.gl_end_count);
+
+ auto debug_context = system.GetGPUDebugContext();
+
+ if (debug_context) {
+ debug_context->OnEvent(Tegra::DebugContext::Event::IncomingPrimitiveBatch, nullptr);
+ }
+
+ // Both instance configuration registers can not be set at the same time.
+ ASSERT_MSG(!regs.draw.instance_next || !regs.draw.instance_cont,
+ "Illegal combination of instancing parameters");
+
+ const bool is_indexed = mme_draw.current_mode == MMEDrawMode::Indexed;
+ if (ShouldExecute()) {
+ rasterizer.DrawMultiBatch(is_indexed);
+ }
+
+ if (debug_context) {
+ debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr);
+ }
+
+ // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if
+ // the game is trying to draw indexed or direct mode. This needs to be verified on HW still -
+ // it's possible that it is incorrect and that there is some other register used to specify the
+ // drawing mode.
+ if (is_indexed) {
+ regs.index_array.count = 0;
+ } else {
+ regs.vertex_buffer.count = 0;
+ }
+ mme_draw.current_mode = MMEDrawMode::Undefined;
+ mme_draw.current_count = 0;
+ mme_draw.instance_count = 0;
+ mme_draw.instance_mode = false;
+ mme_draw.gl_begin_consume = false;
+ mme_draw.gl_end_count = 0;
+}
+
void Maxwell3D::ProcessMacroUpload(u32 data) {
ASSERT_MSG(regs.macros.upload_address < macro_memory.size(),
"upload_address exceeded macro_memory size!");
@@ -541,7 +639,7 @@ void Maxwell3D::ProcessSyncPoint() {
}
void Maxwell3D::DrawArrays() {
- LOG_DEBUG(HW_GPU, "called, topology={}, count={}", static_cast<u32>(regs.draw.topology.Value()),
+ LOG_TRACE(HW_GPU, "called, topology={}, count={}", static_cast<u32>(regs.draw.topology.Value()),
regs.vertex_buffer.count);
ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?");
@@ -564,7 +662,9 @@ void Maxwell3D::DrawArrays() {
}
const bool is_indexed{regs.index_array.count && !regs.vertex_buffer.count};
- rasterizer.AccelerateDrawBatch(is_indexed);
+ if (ShouldExecute()) {
+ rasterizer.DrawBatch(is_indexed);
+ }
if (debug_context) {
debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr);
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index e5ec90717..4c97759ed 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -811,8 +811,9 @@ public:
INSERT_PADDING_WORDS(0x21);
u32 vb_element_base;
+ u32 vb_base_instance;
- INSERT_PADDING_WORDS(0x36);
+ INSERT_PADDING_WORDS(0x35);
union {
BitField<0, 1, u32> c0;
@@ -1238,6 +1239,11 @@ public:
/// Write the value to the register identified by method.
void CallMethod(const GPU::MethodCall& method_call);
+ /// Write the value to the register identified by method.
+ void CallMethodFromMME(const GPU::MethodCall& method_call);
+
+ void FlushMMEInlineDraw();
+
/// Given a Texture Handle, returns the TSC and TIC entries.
Texture::FullTextureInfo GetTextureInfo(const Texture::TextureHandle tex_handle,
std::size_t offset) const;
@@ -1263,6 +1269,21 @@ public:
return execute_on;
}
+ enum class MMEDrawMode : u32 {
+ Undefined,
+ Array,
+ Indexed,
+ };
+
+ struct MMEDrawState {
+ MMEDrawMode current_mode{MMEDrawMode::Undefined};
+ u32 current_count{};
+ u32 instance_count{};
+ bool instance_mode{};
+ bool gl_begin_consume{};
+ u32 gl_end_count{};
+ } mme_draw;
+
private:
void InitializeRegisterDefaults();
@@ -1275,6 +1296,8 @@ private:
/// Start offsets of each macro in macro_memory
std::array<u32, 0x80> macro_positions = {};
+ std::array<bool, Regs::NUM_REGS> mme_inline{};
+
/// Memory for macro code
MacroMemory macro_memory;
@@ -1346,6 +1369,9 @@ private:
/// Handles a write to the VERTEX_END_GL register, triggering a draw.
void DrawArrays();
+
+ // Handles a instance drawcall from MME
+ void StepInstance(MMEDrawMode expected_mode, u32 count);
};
#define ASSERT_REG_POSITION(field_name, position) \
@@ -1402,6 +1428,7 @@ ASSERT_REG_POSITION(stencil_front_mask, 0x4E7);
ASSERT_REG_POSITION(frag_color_clamp, 0x4EA);
ASSERT_REG_POSITION(screen_y_control, 0x4EB);
ASSERT_REG_POSITION(vb_element_base, 0x50D);
+ASSERT_REG_POSITION(vb_base_instance, 0x50E);
ASSERT_REG_POSITION(clip_distance_enabled, 0x544);
ASSERT_REG_POSITION(point_size, 0x546);
ASSERT_REG_POSITION(zeta_enable, 0x54E);
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index b46fcf03d..7a6355ce2 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -950,6 +950,11 @@ union Instruction {
} isetp;
union {
+ BitField<48, 1, u64> is_signed;
+ BitField<49, 3, PredCondition> cond;
+ } icmp;
+
+ union {
BitField<0, 3, u64> pred0;
BitField<3, 3, u64> pred3;
BitField<12, 3, u64> pred12;
@@ -1646,6 +1651,10 @@ public:
SEL_C,
SEL_R,
SEL_IMM,
+ ICMP_RC,
+ ICMP_R,
+ ICMP_CR,
+ ICMP_IMM,
MUFU, // Multi-Function Operator
RRO_C, // Range Reduction Operator
RRO_R,
@@ -1912,6 +1921,10 @@ private:
INST("0100110010100---", Id::SEL_C, Type::ArithmeticInteger, "SEL_C"),
INST("0101110010100---", Id::SEL_R, Type::ArithmeticInteger, "SEL_R"),
INST("0011100-10100---", Id::SEL_IMM, Type::ArithmeticInteger, "SEL_IMM"),
+ INST("010100110100----", Id::ICMP_RC, Type::ArithmeticInteger, "ICMP_RC"),
+ INST("010110110100----", Id::ICMP_R, Type::ArithmeticInteger, "ICMP_R"),
+ INST("010010110100----", Id::ICMP_CR, Type::ArithmeticInteger, "ICMP_CR"),
+ INST("0011011-0100----", Id::ICMP_IMM, Type::ArithmeticInteger, "ICMP_IMM"),
INST("0101101111011---", Id::LEA_R2, Type::ArithmeticInteger, "LEA_R2"),
INST("0101101111010---", Id::LEA_R1, Type::ArithmeticInteger, "LEA_R1"),
INST("001101101101----", Id::LEA_IMM, Type::ArithmeticInteger, "LEA_IMM"),