|
|
@@ -124,6 +124,112 @@ void Maxwell3D::InitializeRegisterDefaults() {
|
|
|
mme_inline[MAXWELL3D_REG_INDEX(index_array.count)] = true;
|
|
|
}
|
|
|
|
|
|
+void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) {
|
|
|
+ if (executing_macro == 0) {
|
|
|
+ // A macro call must begin by writing the macro method's register, not its argument.
|
|
|
+ ASSERT_MSG((method % 2) == 0,
|
|
|
+ "Can't start macro execution by writing to the ARGS register");
|
|
|
+ executing_macro = method;
|
|
|
+ }
|
|
|
+
|
|
|
+ macro_params.insert(macro_params.end(), base_start, base_start + amount);
|
|
|
+
|
|
|
+ // Call the macro when there are no more parameters in the command buffer
|
|
|
+ if (is_last_call) {
|
|
|
+ CallMacroMethod(executing_macro, macro_params);
|
|
|
+ macro_params.clear();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+u32 Maxwell3D::ProcessShadowRam(u32 method, u32 argument) {
|
|
|
+ // Keep track of the register value in shadow_state when requested.
|
|
|
+ const auto control = shadow_state.shadow_ram_control;
|
|
|
+ if (control == Regs::ShadowRamControl::Track ||
|
|
|
+ control == Regs::ShadowRamControl::TrackWithFilter) {
|
|
|
+ shadow_state.reg_array[method] = argument;
|
|
|
+ return argument;
|
|
|
+ }
|
|
|
+ if (control == Regs::ShadowRamControl::Replay) {
|
|
|
+ return shadow_state.reg_array[method];
|
|
|
+ }
|
|
|
+ return argument;
|
|
|
+}
|
|
|
+
|
|
|
+void Maxwell3D::ProcessDirtyRegisters(u32 method, u32 argument) {
|
|
|
+ if (regs.reg_array[method] == argument) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ regs.reg_array[method] = argument;
|
|
|
+
|
|
|
+ for (const auto& table : dirty.tables) {
|
|
|
+ dirty.flags[table[method]] = true;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argument,
|
|
|
+ bool is_last_call) {
|
|
|
+ switch (method) {
|
|
|
+ case MAXWELL3D_REG_INDEX(wait_for_idle):
|
|
|
+ return rasterizer->WaitForIdle();
|
|
|
+ case MAXWELL3D_REG_INDEX(shadow_ram_control):
|
|
|
+ shadow_state.shadow_ram_control = static_cast<Regs::ShadowRamControl>(nonshadow_argument);
|
|
|
+ return;
|
|
|
+ case MAXWELL3D_REG_INDEX(macros.data):
|
|
|
+ return macro_engine->AddCode(regs.macros.upload_address, argument);
|
|
|
+ case MAXWELL3D_REG_INDEX(macros.bind):
|
|
|
+ return ProcessMacroBind(argument);
|
|
|
+ case MAXWELL3D_REG_INDEX(firmware[4]):
|
|
|
+ return ProcessFirmwareCall4();
|
|
|
+ case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]):
|
|
|
+ case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]):
|
|
|
+ case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]):
|
|
|
+ case MAXWELL3D_REG_INDEX(const_buffer.cb_data[3]):
|
|
|
+ case MAXWELL3D_REG_INDEX(const_buffer.cb_data[4]):
|
|
|
+ case MAXWELL3D_REG_INDEX(const_buffer.cb_data[5]):
|
|
|
+ case MAXWELL3D_REG_INDEX(const_buffer.cb_data[6]):
|
|
|
+ case MAXWELL3D_REG_INDEX(const_buffer.cb_data[7]):
|
|
|
+ case MAXWELL3D_REG_INDEX(const_buffer.cb_data[8]):
|
|
|
+ case MAXWELL3D_REG_INDEX(const_buffer.cb_data[9]):
|
|
|
+ case MAXWELL3D_REG_INDEX(const_buffer.cb_data[10]):
|
|
|
+ case MAXWELL3D_REG_INDEX(const_buffer.cb_data[11]):
|
|
|
+ case MAXWELL3D_REG_INDEX(const_buffer.cb_data[12]):
|
|
|
+ case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]):
|
|
|
+ case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]):
|
|
|
+ case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]):
|
|
|
+ return StartCBData(method);
|
|
|
+ case MAXWELL3D_REG_INDEX(cb_bind[0]):
|
|
|
+ return ProcessCBBind(0);
|
|
|
+ case MAXWELL3D_REG_INDEX(cb_bind[1]):
|
|
|
+ return ProcessCBBind(1);
|
|
|
+ case MAXWELL3D_REG_INDEX(cb_bind[2]):
|
|
|
+ return ProcessCBBind(2);
|
|
|
+ case MAXWELL3D_REG_INDEX(cb_bind[3]):
|
|
|
+ return ProcessCBBind(3);
|
|
|
+ case MAXWELL3D_REG_INDEX(cb_bind[4]):
|
|
|
+ return ProcessCBBind(4);
|
|
|
+ case MAXWELL3D_REG_INDEX(draw.vertex_end_gl):
|
|
|
+ return DrawArrays();
|
|
|
+ case MAXWELL3D_REG_INDEX(clear_buffers):
|
|
|
+ return ProcessClearBuffers();
|
|
|
+ case MAXWELL3D_REG_INDEX(query.query_get):
|
|
|
+ return ProcessQueryGet();
|
|
|
+ case MAXWELL3D_REG_INDEX(condition.mode):
|
|
|
+ return ProcessQueryCondition();
|
|
|
+ case MAXWELL3D_REG_INDEX(counter_reset):
|
|
|
+ return ProcessCounterReset();
|
|
|
+ case MAXWELL3D_REG_INDEX(sync_info):
|
|
|
+ return ProcessSyncPoint();
|
|
|
+ case MAXWELL3D_REG_INDEX(exec_upload):
|
|
|
+ return upload_state.ProcessExec(regs.exec_upload.linear != 0);
|
|
|
+ case MAXWELL3D_REG_INDEX(data_upload):
|
|
|
+ upload_state.ProcessData(argument, is_last_call);
|
|
|
+ if (is_last_call) {
|
|
|
+ OnMemoryWrite();
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters) {
|
|
|
// Reset the current macro.
|
|
|
executing_macro = 0;
|
|
|
@@ -157,142 +263,16 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
|
|
|
// Methods after 0xE00 are special, they're actually triggers for some microcode that was
|
|
|
// uploaded to the GPU during initialization.
|
|
|
if (method >= MacroRegistersStart) {
|
|
|
- // We're trying to execute a macro
|
|
|
- if (executing_macro == 0) {
|
|
|
- // A macro call must begin by writing the macro method's register, not its argument.
|
|
|
- ASSERT_MSG((method % 2) == 0,
|
|
|
- "Can't start macro execution by writing to the ARGS register");
|
|
|
- executing_macro = method;
|
|
|
- }
|
|
|
-
|
|
|
- macro_params.push_back(method_argument);
|
|
|
-
|
|
|
- // Call the macro when there are no more parameters in the command buffer
|
|
|
- if (is_last_call) {
|
|
|
- CallMacroMethod(executing_macro, macro_params);
|
|
|
- macro_params.clear();
|
|
|
- }
|
|
|
+ ProcessMacro(method, &method_argument, 1, is_last_call);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
ASSERT_MSG(method < Regs::NUM_REGS,
|
|
|
"Invalid Maxwell3D register, increase the size of the Regs structure");
|
|
|
|
|
|
- u32 arg = method_argument;
|
|
|
- // Keep track of the register value in shadow_state when requested.
|
|
|
- if (shadow_state.shadow_ram_control == Regs::ShadowRamControl::Track ||
|
|
|
- shadow_state.shadow_ram_control == Regs::ShadowRamControl::TrackWithFilter) {
|
|
|
- shadow_state.reg_array[method] = arg;
|
|
|
- } else if (shadow_state.shadow_ram_control == Regs::ShadowRamControl::Replay) {
|
|
|
- arg = shadow_state.reg_array[method];
|
|
|
- }
|
|
|
-
|
|
|
- if (regs.reg_array[method] != arg) {
|
|
|
- regs.reg_array[method] = arg;
|
|
|
-
|
|
|
- for (const auto& table : dirty.tables) {
|
|
|
- dirty.flags[table[method]] = true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- switch (method) {
|
|
|
- case MAXWELL3D_REG_INDEX(wait_for_idle): {
|
|
|
- rasterizer->WaitForIdle();
|
|
|
- break;
|
|
|
- }
|
|
|
- case MAXWELL3D_REG_INDEX(shadow_ram_control): {
|
|
|
- shadow_state.shadow_ram_control = static_cast<Regs::ShadowRamControl>(method_argument);
|
|
|
- break;
|
|
|
- }
|
|
|
- case MAXWELL3D_REG_INDEX(macros.data): {
|
|
|
- macro_engine->AddCode(regs.macros.upload_address, arg);
|
|
|
- break;
|
|
|
- }
|
|
|
- case MAXWELL3D_REG_INDEX(macros.bind): {
|
|
|
- ProcessMacroBind(arg);
|
|
|
- break;
|
|
|
- }
|
|
|
- case MAXWELL3D_REG_INDEX(firmware[4]): {
|
|
|
- ProcessFirmwareCall4();
|
|
|
- break;
|
|
|
- }
|
|
|
- case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]):
|
|
|
- case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]):
|
|
|
- case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]):
|
|
|
- case MAXWELL3D_REG_INDEX(const_buffer.cb_data[3]):
|
|
|
- case MAXWELL3D_REG_INDEX(const_buffer.cb_data[4]):
|
|
|
- case MAXWELL3D_REG_INDEX(const_buffer.cb_data[5]):
|
|
|
- case MAXWELL3D_REG_INDEX(const_buffer.cb_data[6]):
|
|
|
- case MAXWELL3D_REG_INDEX(const_buffer.cb_data[7]):
|
|
|
- case MAXWELL3D_REG_INDEX(const_buffer.cb_data[8]):
|
|
|
- case MAXWELL3D_REG_INDEX(const_buffer.cb_data[9]):
|
|
|
- case MAXWELL3D_REG_INDEX(const_buffer.cb_data[10]):
|
|
|
- case MAXWELL3D_REG_INDEX(const_buffer.cb_data[11]):
|
|
|
- case MAXWELL3D_REG_INDEX(const_buffer.cb_data[12]):
|
|
|
- case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]):
|
|
|
- case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]):
|
|
|
- case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]): {
|
|
|
- StartCBData(method);
|
|
|
- break;
|
|
|
- }
|
|
|
- case MAXWELL3D_REG_INDEX(cb_bind[0]): {
|
|
|
- ProcessCBBind(0);
|
|
|
- break;
|
|
|
- }
|
|
|
- case MAXWELL3D_REG_INDEX(cb_bind[1]): {
|
|
|
- ProcessCBBind(1);
|
|
|
- break;
|
|
|
- }
|
|
|
- case MAXWELL3D_REG_INDEX(cb_bind[2]): {
|
|
|
- ProcessCBBind(2);
|
|
|
- break;
|
|
|
- }
|
|
|
- case MAXWELL3D_REG_INDEX(cb_bind[3]): {
|
|
|
- ProcessCBBind(3);
|
|
|
- break;
|
|
|
- }
|
|
|
- case MAXWELL3D_REG_INDEX(cb_bind[4]): {
|
|
|
- ProcessCBBind(4);
|
|
|
- break;
|
|
|
- }
|
|
|
- case MAXWELL3D_REG_INDEX(draw.vertex_end_gl): {
|
|
|
- DrawArrays();
|
|
|
- break;
|
|
|
- }
|
|
|
- case MAXWELL3D_REG_INDEX(clear_buffers): {
|
|
|
- ProcessClearBuffers();
|
|
|
- break;
|
|
|
- }
|
|
|
- case MAXWELL3D_REG_INDEX(query.query_get): {
|
|
|
- ProcessQueryGet();
|
|
|
- break;
|
|
|
- }
|
|
|
- case MAXWELL3D_REG_INDEX(condition.mode): {
|
|
|
- ProcessQueryCondition();
|
|
|
- break;
|
|
|
- }
|
|
|
- case MAXWELL3D_REG_INDEX(counter_reset): {
|
|
|
- ProcessCounterReset();
|
|
|
- break;
|
|
|
- }
|
|
|
- case MAXWELL3D_REG_INDEX(sync_info): {
|
|
|
- ProcessSyncPoint();
|
|
|
- break;
|
|
|
- }
|
|
|
- case MAXWELL3D_REG_INDEX(exec_upload): {
|
|
|
- upload_state.ProcessExec(regs.exec_upload.linear != 0);
|
|
|
- break;
|
|
|
- }
|
|
|
- case MAXWELL3D_REG_INDEX(data_upload): {
|
|
|
- upload_state.ProcessData(arg, is_last_call);
|
|
|
- if (is_last_call) {
|
|
|
- OnMemoryWrite();
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
+ const u32 argument = ProcessShadowRam(method, method_argument);
|
|
|
+ ProcessDirtyRegisters(method, argument);
|
|
|
+ ProcessMethodCall(method, argument, method_argument, is_last_call);
|
|
|
}
|
|
|
|
|
|
void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
|
|
|
@@ -300,23 +280,7 @@ void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
|
|
|
// Methods after 0xE00 are special, they're actually triggers for some microcode that was
|
|
|
// uploaded to the GPU during initialization.
|
|
|
if (method >= MacroRegistersStart) {
|
|
|
- // We're trying to execute a macro
|
|
|
- if (executing_macro == 0) {
|
|
|
- // A macro call must begin by writing the macro method's register, not its argument.
|
|
|
- ASSERT_MSG((method % 2) == 0,
|
|
|
- "Can't start macro execution by writing to the ARGS register");
|
|
|
- executing_macro = method;
|
|
|
- }
|
|
|
-
|
|
|
- for (std::size_t i = 0; i < amount; i++) {
|
|
|
- macro_params.push_back(base_start[i]);
|
|
|
- }
|
|
|
-
|
|
|
- // Call the macro when there are no more parameters in the command buffer
|
|
|
- if (amount == methods_pending) {
|
|
|
- CallMacroMethod(executing_macro, macro_params);
|
|
|
- macro_params.clear();
|
|
|
- }
|
|
|
+ ProcessMacro(method, base_start, amount, amount == methods_pending);
|
|
|
return;
|
|
|
}
|
|
|
switch (method) {
|
|
|
@@ -335,15 +299,14 @@ void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[12]):
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]):
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]):
|
|
|
- case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]): {
|
|
|
+ case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]):
|
|
|
ProcessCBMultiData(method, base_start, amount);
|
|
|
break;
|
|
|
- }
|
|
|
- default: {
|
|
|
+ default:
|
|
|
for (std::size_t i = 0; i < amount; i++) {
|
|
|
CallMethod(method, base_start[i], methods_pending - static_cast<u32>(i) <= 1);
|
|
|
}
|
|
|
- }
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
|