mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Merge pull request #997 from Lectem/cmdlist_full_debug
citra-qt: Improve pica command list widget (add mask, fix some issues)
This commit is contained in:
		
						commit
						f5144e6c10
					
				
					 4 changed files with 52 additions and 50 deletions
				
			
		|  | @ -175,29 +175,29 @@ int GPUCommandListModel::rowCount(const QModelIndex& parent) const { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int GPUCommandListModel::columnCount(const QModelIndex& parent) const { | int GPUCommandListModel::columnCount(const QModelIndex& parent) const { | ||||||
|     return 3; |     return 4; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const { | QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const { | ||||||
|     if (!index.isValid()) |     if (!index.isValid()) | ||||||
|         return QVariant(); |         return QVariant(); | ||||||
| 
 | 
 | ||||||
|     const auto& writes = pica_trace.writes; |     const auto& write = pica_trace.writes[index.row()]; | ||||||
|     const Pica::CommandProcessor::CommandHeader cmd{writes[index.row()].Id()}; |  | ||||||
|     const u32 val{writes[index.row()].Value()}; |  | ||||||
| 
 | 
 | ||||||
|     if (role == Qt::DisplayRole) { |     if (role == Qt::DisplayRole) { | ||||||
|         QString content; |         QString content; | ||||||
|         switch ( index.column() ) { |         switch ( index.column() ) { | ||||||
|         case 0: |         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: |         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: |         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) { |     } else if (role == CommandIdRole) { | ||||||
|         return QVariant::fromValue<int>(cmd.cmd_id.Value()); |         return QVariant::fromValue<int>(write.cmd_id); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return QVariant(); |     return QVariant(); | ||||||
|  | @ -213,6 +213,8 @@ QVariant GPUCommandListModel::headerData(int section, Qt::Orientation orientatio | ||||||
|         case 1: |         case 1: | ||||||
|             return tr("Register"); |             return tr("Register"); | ||||||
|         case 2: |         case 2: | ||||||
|  |             return tr("Mask"); | ||||||
|  |         case 3: | ||||||
|             return tr("New Value"); |             return tr("New Value"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -260,7 +262,7 @@ void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) { | void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) { | ||||||
|     QWidget* new_info_widget; |     QWidget* new_info_widget = nullptr; | ||||||
| 
 | 
 | ||||||
|     const unsigned int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt(); |     const unsigned int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt(); | ||||||
|     if (COMMAND_IN_RANGE(command_id, texture0) || |     if (COMMAND_IN_RANGE(command_id, texture0) || | ||||||
|  | @ -281,15 +283,16 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) { | ||||||
|         auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format); |         auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format); | ||||||
|         u8* src = Memory::GetPhysicalPointer(config.GetPhysicalAddress()); |         u8* src = Memory::GetPhysicalPointer(config.GetPhysicalAddress()); | ||||||
|         new_info_widget = new TextureInfoWidget(src, info); |         new_info_widget = new TextureInfoWidget(src, info); | ||||||
|     } else { |  | ||||||
|         new_info_widget = new QWidget; |  | ||||||
|     } |     } | ||||||
| 
 |     if (command_info_widget) { | ||||||
|     widget()->layout()->removeWidget(command_info_widget); |  | ||||||
|         delete command_info_widget; |         delete command_info_widget; | ||||||
|  |         command_info_widget = nullptr; | ||||||
|  |     } | ||||||
|  |     if (new_info_widget) { | ||||||
|         widget()->layout()->addWidget(new_info_widget); |         widget()->layout()->addWidget(new_info_widget); | ||||||
|         command_info_widget = new_info_widget; |         command_info_widget = new_info_widget; | ||||||
|     } |     } | ||||||
|  | } | ||||||
| #undef COMMAND_IN_RANGE | #undef COMMAND_IN_RANGE | ||||||
| 
 | 
 | ||||||
| GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pica Command List"), parent) { | GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pica Command List"), parent) { | ||||||
|  | @ -300,7 +303,9 @@ GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pi | ||||||
| 
 | 
 | ||||||
|     list_widget = new QTreeView; |     list_widget = new QTreeView; | ||||||
|     list_widget->setModel(model); |     list_widget->setModel(model); | ||||||
|     list_widget->setFont(QFont("monospace")); |     QFont font("monospace"); | ||||||
|  |     font.setStyleHint(QFont::Monospace); // Automatic fallback to a monospace font on on platforms without a font called "monospace"
 | ||||||
|  |     list_widget->setFont(font); | ||||||
|     list_widget->setRootIsDecorated(false); |     list_widget->setRootIsDecorated(false); | ||||||
|     list_widget->setUniformRowHeights(true); |     list_widget->setUniformRowHeights(true); | ||||||
| 
 | 
 | ||||||
|  | @ -324,7 +329,7 @@ GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pi | ||||||
| 
 | 
 | ||||||
|     connect(copy_all, SIGNAL(clicked()), this, SLOT(CopyAllToClipboard())); |     connect(copy_all, SIGNAL(clicked()), this, SLOT(CopyAllToClipboard())); | ||||||
| 
 | 
 | ||||||
|     command_info_widget = new QWidget; |     command_info_widget = nullptr; | ||||||
| 
 | 
 | ||||||
|     QVBoxLayout* main_layout = new QVBoxLayout; |     QVBoxLayout* main_layout = new QVBoxLayout; | ||||||
|     main_layout->addWidget(list_widget); |     main_layout->addWidget(list_widget); | ||||||
|  | @ -334,7 +339,6 @@ GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pi | ||||||
|         sub_layout->addWidget(copy_all); |         sub_layout->addWidget(copy_all); | ||||||
|         main_layout->addLayout(sub_layout); |         main_layout->addLayout(sub_layout); | ||||||
|     } |     } | ||||||
|     main_layout->addWidget(command_info_widget); |  | ||||||
|     main_widget->setLayout(main_layout); |     main_widget->setLayout(main_layout); | ||||||
| 
 | 
 | ||||||
|     setWidget(main_widget); |     setWidget(main_widget); | ||||||
|  |  | ||||||
|  | @ -35,7 +35,15 @@ static u32 default_attr_write_buffer[3]; | ||||||
| 
 | 
 | ||||||
| Common::Profiling::TimingCategory category_drawing("Drawing"); | 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; |     auto& regs = g_state.regs; | ||||||
| 
 | 
 | ||||||
|     if (id >= regs.NumIds()) |     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
 |     // TODO: Figure out how register masking acts on e.g. vs.uniform_setup.set_value
 | ||||||
|     u32 old_value = regs[id]; |     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) |     if (g_debug_context) | ||||||
|         g_debug_context->OnEvent(DebugContext::Event::PicaCommandLoaded, reinterpret_cast<void*>(&id)); |         g_debug_context->OnEvent(DebugContext::Event::PicaCommandLoaded, reinterpret_cast<void*>(&id)); | ||||||
| 
 | 
 | ||||||
|     DebugUtils::OnPicaRegWrite(id, regs[id]); |  | ||||||
| 
 |  | ||||||
|     switch(id) { |     switch(id) { | ||||||
|         // Trigger IRQ
 |         // Trigger IRQ
 | ||||||
|         case PICA_REG_INDEX(trigger_irq): |         case PICA_REG_INDEX(trigger_irq): | ||||||
|  | @ -469,13 +480,6 @@ void ProcessCommandList(const u32* list, u32 size) { | ||||||
|     g_state.cmd_list.length = size / sizeof(u32); |     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) { |     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
 |         // Align read pointer to 8 bytes
 | ||||||
|         if ((g_state.cmd_list.head_ptr - g_state.cmd_list.current_ptr) % 2 != 0) |         if ((g_state.cmd_list.head_ptr - g_state.cmd_list.current_ptr) % 2 != 0) | ||||||
|  | @ -483,14 +487,13 @@ void ProcessCommandList(const u32* list, u32 size) { | ||||||
| 
 | 
 | ||||||
|         u32 value = *g_state.cmd_list.current_ptr++; |         u32 value = *g_state.cmd_list.current_ptr++; | ||||||
|         const CommandHeader header = { *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; |         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) { |         for (unsigned i = 0; i < header.extra_data_length; ++i) { | ||||||
|             u32 cmd = header.cmd_id + (header.group_commands ? i + 1 : 0); |             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); | ||||||
|          } |          } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -64,7 +64,7 @@ void DebugContext::OnEvent(Event event, void* data) { | ||||||
| 
 | 
 | ||||||
| void DebugContext::Resume() { | void DebugContext::Resume() { | ||||||
|     { |     { | ||||||
|         std::unique_lock<std::mutex> lock(breakpoint_mutex); |         std::lock_guard<std::mutex> lock(breakpoint_mutex); | ||||||
| 
 | 
 | ||||||
|         // Tell all observers that we are about to resume
 |         // Tell all observers that we are about to resume
 | ||||||
|         for (auto& breakpoint_observer : breakpoint_observers) { |         for (auto& breakpoint_observer : breakpoint_observers) { | ||||||
|  | @ -312,11 +312,10 @@ void StartPicaTracing() | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pica_trace_mutex.lock(); |     std::lock_guard<std::mutex> lock(pica_trace_mutex); | ||||||
|     pica_trace = std::unique_ptr<PicaTrace>(new PicaTrace); |     pica_trace = std::unique_ptr<PicaTrace>(new PicaTrace); | ||||||
| 
 | 
 | ||||||
|     is_pica_tracing = true; |     is_pica_tracing = true; | ||||||
|     pica_trace_mutex.unlock(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool IsPicaTracing() | bool IsPicaTracing() | ||||||
|  | @ -324,18 +323,18 @@ bool IsPicaTracing() | ||||||
|     return is_pica_tracing != 0; |     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
 |     // Double check for is_pica_tracing to avoid pointless locking overhead
 | ||||||
|     if (!is_pica_tracing) |     if (!is_pica_tracing) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     std::unique_lock<std::mutex> lock(pica_trace_mutex); |     std::lock_guard<std::mutex> lock(pica_trace_mutex); | ||||||
| 
 | 
 | ||||||
|     if (!is_pica_tracing) |     if (!is_pica_tracing) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     pica_trace->writes.emplace_back(id, value); |     pica_trace->writes.push_back(write); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::unique_ptr<PicaTrace> FinishPicaTracing() | std::unique_ptr<PicaTrace> FinishPicaTracing() | ||||||
|  | @ -349,9 +348,9 @@ std::unique_ptr<PicaTrace> FinishPicaTracing() | ||||||
|     is_pica_tracing = false; |     is_pica_tracing = false; | ||||||
| 
 | 
 | ||||||
|     // Wait until running tracing is finished
 |     // Wait until running tracing is finished
 | ||||||
|     pica_trace_mutex.lock(); |     std::lock_guard<std::mutex> lock(pica_trace_mutex); | ||||||
|     std::unique_ptr<PicaTrace> ret(std::move(pica_trace)); |     std::unique_ptr<PicaTrace> ret(std::move(pica_trace)); | ||||||
|     pica_trace_mutex.unlock(); | 
 | ||||||
|     return std::move(ret); |     return std::move(ret); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -187,21 +187,17 @@ void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, | ||||||
| 
 | 
 | ||||||
| // Utility class to log Pica commands.
 | // Utility class to log Pica commands.
 | ||||||
| struct PicaTrace { | struct PicaTrace { | ||||||
|     struct Write : public std::pair<u32,u32> { |     struct Write { | ||||||
|         Write(u32 id, u32 value) : std::pair<u32,u32>(id, value) {} |         u16 cmd_id; | ||||||
| 
 |         u16 mask; | ||||||
|         u32& Id() { return first; } |         u32 value; | ||||||
|         const u32& Id() const { return first; } |  | ||||||
| 
 |  | ||||||
|         u32& Value() { return second; } |  | ||||||
|         const u32& Value() const { return second; } |  | ||||||
|     }; |     }; | ||||||
|     std::vector<Write> writes; |     std::vector<Write> writes; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void StartPicaTracing(); | void StartPicaTracing(); | ||||||
| bool IsPicaTracing(); | bool IsPicaTracing(); | ||||||
| void OnPicaRegWrite(u32 id, u32 value); | void OnPicaRegWrite(PicaTrace::Write write); | ||||||
| std::unique_ptr<PicaTrace> FinishPicaTracing(); | std::unique_ptr<PicaTrace> FinishPicaTracing(); | ||||||
| 
 | 
 | ||||||
| struct TextureInfo { | struct TextureInfo { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue