|
|
|
@ -4,6 +4,7 @@
|
|
|
|
|
#include <cstring>
|
|
|
|
|
#include <optional>
|
|
|
|
|
#include "common/assert.h"
|
|
|
|
|
#include "common/scope_exit.h"
|
|
|
|
|
#include "common/settings.h"
|
|
|
|
|
#include "core/core.h"
|
|
|
|
|
#include "core/core_timing.h"
|
|
|
|
@ -30,6 +31,10 @@ Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_)
|
|
|
|
|
regs.upload} {
|
|
|
|
|
dirty.flags.flip();
|
|
|
|
|
InitializeRegisterDefaults();
|
|
|
|
|
execution_mask.reset();
|
|
|
|
|
for (size_t i = 0; i < execution_mask.size(); i++) {
|
|
|
|
|
execution_mask[i] = IsMethodExecutable(static_cast<u32>(i));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Maxwell3D::~Maxwell3D() = default;
|
|
|
|
@ -123,6 +128,71 @@ void Maxwell3D::InitializeRegisterDefaults() {
|
|
|
|
|
shadow_state = regs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Maxwell3D::IsMethodExecutable(u32 method) {
|
|
|
|
|
if (method >= MacroRegistersStart) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
switch (method) {
|
|
|
|
|
case MAXWELL3D_REG_INDEX(draw.end):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(draw.begin):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(vertex_buffer.first):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(vertex_buffer.count):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(index_buffer.first):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(index_buffer.count):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(draw_inline_index):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(index_buffer32_subsequent):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(index_buffer16_subsequent):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(index_buffer8_subsequent):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(index_buffer32_first):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(index_buffer16_first):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(index_buffer8_first):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(inline_index_2x16.even):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(inline_index_4x8.index0):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(vertex_array_instance_first):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(vertex_array_instance_subsequent):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(wait_for_idle):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(shadow_ram_control):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(load_mme.instruction_ptr):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(load_mme.instruction):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(load_mme.start_address):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(falcon[4]):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.buffer):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 1:
|
|
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 2:
|
|
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 3:
|
|
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 4:
|
|
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 5:
|
|
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 6:
|
|
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 7:
|
|
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 8:
|
|
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 9:
|
|
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 10:
|
|
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 11:
|
|
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 12:
|
|
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 13:
|
|
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 14:
|
|
|
|
|
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 15:
|
|
|
|
|
case MAXWELL3D_REG_INDEX(bind_groups[0].raw_config):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(bind_groups[1].raw_config):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(bind_groups[2].raw_config):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(bind_groups[3].raw_config):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(bind_groups[4].raw_config):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(topology_override):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(clear_surface):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(report_semaphore.query):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(render_enable.mode):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(clear_report_value):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(sync_info):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(launch_dma):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(inline_data):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(fragment_barrier):
|
|
|
|
|
case MAXWELL3D_REG_INDEX(tiled_cache_barrier):
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
@ -141,6 +211,7 @@ void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool
|
|
|
|
|
|
|
|
|
|
// Call the macro when there are no more parameters in the command buffer
|
|
|
|
|
if (is_last_call) {
|
|
|
|
|
ConsumeSink();
|
|
|
|
|
CallMacroMethod(executing_macro, macro_params);
|
|
|
|
|
macro_params.clear();
|
|
|
|
|
macro_addresses.clear();
|
|
|
|
@ -214,6 +285,29 @@ u32 Maxwell3D::ProcessShadowRam(u32 method, u32 argument) {
|
|
|
|
|
return argument;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Maxwell3D::ConsumeSinkImpl() {
|
|
|
|
|
SCOPE_EXIT({ method_sink.clear(); });
|
|
|
|
|
const auto control = shadow_state.shadow_ram_control;
|
|
|
|
|
if (control == Regs::ShadowRamControl::Track ||
|
|
|
|
|
control == Regs::ShadowRamControl::TrackWithFilter) {
|
|
|
|
|
|
|
|
|
|
for (auto [method, value] : method_sink) {
|
|
|
|
|
shadow_state.reg_array[method] = value;
|
|
|
|
|
ProcessDirtyRegisters(method, value);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (control == Regs::ShadowRamControl::Replay) {
|
|
|
|
|
for (auto [method, value] : method_sink) {
|
|
|
|
|
ProcessDirtyRegisters(method, shadow_state.reg_array[method]);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (auto [method, value] : method_sink) {
|
|
|
|
|
ProcessDirtyRegisters(method, value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Maxwell3D::ProcessDirtyRegisters(u32 method, u32 argument) {
|
|
|
|
|
if (regs.reg_array[method] == argument) {
|
|
|
|
|
return;
|
|
|
|
|