|
|
@ -124,6 +124,112 @@ void Maxwell3D::InitializeRegisterDefaults() {
|
|
|
|
mme_inline[MAXWELL3D_REG_INDEX(index_array.count)] = true;
|
|
|
|
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) {
|
|
|
|
void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters) {
|
|
|
|
// Reset the current macro.
|
|
|
|
// Reset the current macro.
|
|
|
|
executing_macro = 0;
|
|
|
|
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
|
|
|
|
// Methods after 0xE00 are special, they're actually triggers for some microcode that was
|
|
|
|
// uploaded to the GPU during initialization.
|
|
|
|
// uploaded to the GPU during initialization.
|
|
|
|
if (method >= MacroRegistersStart) {
|
|
|
|
if (method >= MacroRegistersStart) {
|
|
|
|
// We're trying to execute a macro
|
|
|
|
ProcessMacro(method, &method_argument, 1, 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.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();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ASSERT_MSG(method < Regs::NUM_REGS,
|
|
|
|
ASSERT_MSG(method < Regs::NUM_REGS,
|
|
|
|
"Invalid Maxwell3D register, increase the size of the Regs structure");
|
|
|
|
"Invalid Maxwell3D register, increase the size of the Regs structure");
|
|
|
|
|
|
|
|
|
|
|
|
u32 arg = method_argument;
|
|
|
|
const u32 argument = ProcessShadowRam(method, method_argument);
|
|
|
|
// Keep track of the register value in shadow_state when requested.
|
|
|
|
ProcessDirtyRegisters(method, argument);
|
|
|
|
if (shadow_state.shadow_ram_control == Regs::ShadowRamControl::Track ||
|
|
|
|
ProcessMethodCall(method, argument, method_argument, is_last_call);
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
|
|
|
|
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
|
|
|
|
// Methods after 0xE00 are special, they're actually triggers for some microcode that was
|
|
|
|
// uploaded to the GPU during initialization.
|
|
|
|
// uploaded to the GPU during initialization.
|
|
|
|
if (method >= MacroRegistersStart) {
|
|
|
|
if (method >= MacroRegistersStart) {
|
|
|
|
// We're trying to execute a macro
|
|
|
|
ProcessMacro(method, base_start, amount, amount == methods_pending);
|
|
|
|
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();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
switch (method) {
|
|
|
|
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[12]):
|
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]):
|
|
|
|
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[14]):
|
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]): {
|
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]):
|
|
|
|
ProcessCBMultiData(method, base_start, amount);
|
|
|
|
ProcessCBMultiData(method, base_start, amount);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
default: {
|
|
|
|
|
|
|
|
for (std::size_t i = 0; i < amount; i++) {
|
|
|
|
for (std::size_t i = 0; i < amount; i++) {
|
|
|
|
CallMethod(method, base_start[i], methods_pending - static_cast<u32>(i) <= 1);
|
|
|
|
CallMethod(method, base_start[i], methods_pending - static_cast<u32>(i) <= 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|