diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index 9034b120e1..0427ebc95e 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -175,29 +175,29 @@ int GPUCommandListModel::rowCount(const QModelIndex& parent) const { } int GPUCommandListModel::columnCount(const QModelIndex& parent) const { - return 3; + return 4; } QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); - const auto& writes = pica_trace.writes; - const Pica::CommandProcessor::CommandHeader cmd{writes[index.row()].Id()}; - const u32 val{writes[index.row()].Value()}; + const auto& write = pica_trace.writes[index.row()]; if (role == Qt::DisplayRole) { QString content; switch ( index.column() ) { case 0: - return QString::fromLatin1(Pica::Regs::GetCommandName(cmd.cmd_id).c_str()); + return QString::fromLatin1(Pica::Regs::GetCommandName(write.cmd_id).c_str()); case 1: - return QString("%1").arg(cmd.cmd_id, 3, 16, QLatin1Char('0')); + return QString("%1").arg(write.cmd_id, 3, 16, QLatin1Char('0')); case 2: - return QString("%1").arg(val, 8, 16, QLatin1Char('0')); + return QString("%1").arg(write.mask, 4, 2, QLatin1Char('0')); + case 3: + return QString("%1").arg(write.value, 8, 16, QLatin1Char('0')); } } else if (role == CommandIdRole) { - return QVariant::fromValue(cmd.cmd_id.Value()); + return QVariant::fromValue(write.cmd_id); } return QVariant(); @@ -213,6 +213,8 @@ QVariant GPUCommandListModel::headerData(int section, Qt::Orientation orientatio case 1: return tr("Register"); case 2: + return tr("Mask"); + case 3: return tr("New Value"); } diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 43ae06181a..deed244121 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -35,7 +35,15 @@ static u32 default_attr_write_buffer[3]; Common::Profiling::TimingCategory category_drawing("Drawing"); -static inline void WritePicaReg(u32 id, u32 value, u32 mask) { +// Expand a 4-bit mask to 4-byte mask, e.g. 0b0101 -> 0x00FF00FF +static const u32 expand_bits_to_bytes[] = { + 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff, + 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff, + 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff, + 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff +}; + +static void WritePicaReg(u32 id, u32 value, u32 mask) { auto& regs = g_state.regs; if (id >= regs.NumIds()) @@ -47,13 +55,16 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { // TODO: Figure out how register masking acts on e.g. vs.uniform_setup.set_value u32 old_value = regs[id]; - regs[id] = (old_value & ~mask) | (value & mask); + + const u32 write_mask = expand_bits_to_bytes[mask]; + + regs[id] = (old_value & ~write_mask) | (value & write_mask); + + DebugUtils::OnPicaRegWrite({ (u16)id, (u16)mask, regs[id] }); if (g_debug_context) g_debug_context->OnEvent(DebugContext::Event::PicaCommandLoaded, reinterpret_cast(&id)); - DebugUtils::OnPicaRegWrite(id, regs[id]); - switch(id) { // Trigger IRQ case PICA_REG_INDEX(trigger_irq): @@ -436,13 +447,6 @@ void ProcessCommandList(const u32* list, u32 size) { g_state.cmd_list.length = size / sizeof(u32); while (g_state.cmd_list.current_ptr < g_state.cmd_list.head_ptr + g_state.cmd_list.length) { - // Expand a 4-bit mask to 4-byte mask, e.g. 0b0101 -> 0x00FF00FF - static const u32 expand_bits_to_bytes[] = { - 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff, - 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff, - 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff, - 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff - }; // Align read pointer to 8 bytes if ((g_state.cmd_list.head_ptr - g_state.cmd_list.current_ptr) % 2 != 0) @@ -450,14 +454,13 @@ void ProcessCommandList(const u32* list, u32 size) { u32 value = *g_state.cmd_list.current_ptr++; const CommandHeader header = { *g_state.cmd_list.current_ptr++ }; - const u32 write_mask = expand_bits_to_bytes[header.parameter_mask]; u32 cmd = header.cmd_id; - WritePicaReg(cmd, value, write_mask); + WritePicaReg(cmd, value, header.parameter_mask); for (unsigned i = 0; i < header.extra_data_length; ++i) { u32 cmd = header.cmd_id + (header.group_commands ? i + 1 : 0); - WritePicaReg(cmd, *g_state.cmd_list.current_ptr++, write_mask); + WritePicaReg(cmd, *g_state.cmd_list.current_ptr++, header.parameter_mask); } } } diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp index c3f8321c69..827b09dffe 100644 --- a/src/video_core/debug_utils/debug_utils.cpp +++ b/src/video_core/debug_utils/debug_utils.cpp @@ -280,7 +280,7 @@ bool IsPicaTracing() return is_pica_tracing != 0; } -void OnPicaRegWrite(u32 id, u32 value) +void OnPicaRegWrite(PicaTrace::Write write) { // Double check for is_pica_tracing to avoid pointless locking overhead if (!is_pica_tracing) @@ -291,7 +291,7 @@ void OnPicaRegWrite(u32 id, u32 value) if (!is_pica_tracing) return; - pica_trace->writes.emplace_back(id, value); + pica_trace->writes.push_back(write); } std::unique_ptr FinishPicaTracing() diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h index 3f109dcb7b..acb75a4b26 100644 --- a/src/video_core/debug_utils/debug_utils.h +++ b/src/video_core/debug_utils/debug_utils.h @@ -183,21 +183,17 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data // Utility class to log Pica commands. struct PicaTrace { - struct Write : public std::pair { - Write(u32 id, u32 value) : std::pair(id, value) {} - - u32& Id() { return first; } - const u32& Id() const { return first; } - - u32& Value() { return second; } - const u32& Value() const { return second; } + struct Write { + u16 cmd_id; + u16 mask; + u32 value; }; std::vector writes; }; void StartPicaTracing(); bool IsPicaTracing(); -void OnPicaRegWrite(u32 id, u32 value); +void OnPicaRegWrite(PicaTrace::Write write); std::unique_ptr FinishPicaTracing(); struct TextureInfo {