ppsspp/Qt/debugger_displaylist.cpp

1521 lines
42 KiB
C++
Raw Normal View History

2013-02-17 01:06:06 +01:00
#include "debugger_displaylist.h"
#include <QTimer>
#include <set>
#include "Core/CPU.h"
#include "ui_debugger_displaylist.h"
#include "GPU/GPUInterface.h"
#include "GPU/GeDisasm.h"
#include "EmuThread.h"
#include "Core/Host.h"
#include "base/display.h"
#include "mainwindow.h"
#include "GPU/GLES/VertexDecoder.h"
#include <QDebug>
Debugger_DisplayList::Debugger_DisplayList(DebugInterface *_cpu, MainWindow* mainWindow_, QWidget *parent) :
QDialog(parent),
ui(new Ui::Debugger_DisplayList),
cpu(_cpu),
mainWindow(mainWindow_),
currentRenderFrameDisplay(0),
currentTextureDisplay(0),
fboZoomFactor(1),
maxVtxDisplay(20),
maxIdxDisplay(20)
{
ui->setupUi(this);
QObject::connect(this, SIGNAL(updateDisplayList_()), this, SLOT(UpdateDisplayListGUI()));
QObject::connect(this, SIGNAL(updateRenderBufferList_()), this, SLOT(UpdateRenderBufferListGUI()));
}
Debugger_DisplayList::~Debugger_DisplayList()
{
delete ui;
}
void Debugger_DisplayList::showEvent(QShowEvent *)
{
#ifdef Q_WS_X11
// Hack to remove the X11 crash with threaded opengl when opening the first dialog
EmuThread_LockDraw(true);
QTimer::singleShot(100, this, SLOT(releaseLock()));
#endif
}
void Debugger_DisplayList::releaseLock()
{
EmuThread_LockDraw(false);
}
void Debugger_DisplayList::UpdateDisplayList()
{
emit updateDisplayList_();
}
void Debugger_DisplayList::UpdateDisplayListGUI()
{
u32 curDlId = 0;
QTreeWidgetItem* curItem = ui->displayList->currentItem();
if(curItem)
curDlId = ui->displayList->currentItem()->data(0,Qt::UserRole).toInt();
displayListRowSelected = 0;
ui->displayList->clear();
ui->displayListData->clear();
EmuThread_LockDraw(true);
const std::deque<DisplayList>& dlQueue = gpu->GetDisplayLists();
DisplayList* dl = gpu->GetCurrentDisplayList();
if(dl)
{
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0,QString::number(dl->id));
item->setData(0, Qt::UserRole, dl->id);
switch(dl->status)
{
case PSP_GE_LIST_DONE: item->setText(1,"Done"); break;
case PSP_GE_LIST_QUEUED: item->setText(1,"Queued"); break;
case PSP_GE_LIST_DRAWING: item->setText(1,"Drawing"); break;
case PSP_GE_LIST_STALL_REACHED: item->setText(1,"Stall Reached"); break;
case PSP_GE_LIST_END_REACHED: item->setText(1,"End Reached"); break;
case PSP_GE_LIST_CANCEL_DONE: item->setText(1,"Cancel Done"); break;
default: break;
}
item->setText(2,QString("%1").arg(dl->startpc,8,16,QChar('0')));
item->setData(2, Qt::UserRole, dl->startpc);
item->setText(3,QString("%1").arg(dl->pc,8,16,QChar('0')));
item->setData(3, Qt::UserRole, dl->pc);
ui->displayList->addTopLevelItem(item);
if(curDlId == dl->id)
{
ui->displayList->setCurrentItem(item);
displayListRowSelected = item;
ShowDLCode();
}
}
for(auto it = dlQueue.begin(); it != dlQueue.end(); ++it)
{
if(dl && it->id == dl->id)
continue;
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0,QString::number(it->id));
item->setData(0, Qt::UserRole, it->id);
switch(it->status)
{
case PSP_GE_LIST_DONE: item->setText(1,"Done"); break;
case PSP_GE_LIST_QUEUED: item->setText(1,"Queued"); break;
case PSP_GE_LIST_DRAWING: item->setText(1,"Drawing"); break;
case PSP_GE_LIST_STALL_REACHED: item->setText(1,"Stall Reached"); break;
case PSP_GE_LIST_END_REACHED: item->setText(1,"End Reached"); break;
case PSP_GE_LIST_CANCEL_DONE: item->setText(1,"Cancel Done"); break;
default: break;
}
item->setText(2,QString("%1").arg(it->startpc,8,16,QChar('0')));
item->setData(2, Qt::UserRole, it->startpc);
item->setText(3,QString("%1").arg(it->pc,8,16,QChar('0')));
item->setData(3, Qt::UserRole, it->pc);
ui->displayList->addTopLevelItem(item);
if(curDlId == it->id)
{
ui->displayList->setCurrentItem(item);
displayListRowSelected = item;
ShowDLCode();
}
}
for(int i = 0; i < ui->displayList->columnCount(); i++)
ui->displayList->resizeColumnToContents(i);
EmuThread_LockDraw(false);
}
void Debugger_DisplayList::ShowDLCode()
{
ui->displayListData->clear();
ui->displayListData->setColumnCount(4);
u32 startPc = displayListRowSelected->data(2,Qt::UserRole).toInt();
u32 curPc = displayListRowSelected->data(3,Qt::UserRole).toInt();
std::map<int,DListLine> data;
GPUgstate listState;
memset(&listState,0,sizeof(GPUgstate));
drawGPUState.clear();
vtxBufferSize.clear();
idxBufferSize.clear();
FillDisplayListCmd(data, startPc,0, listState);
u32 curTexAddr;
u32 curVtxAddr;
u32 curIdxAddr;
for(std::map<int,DListLine>::iterator it = data.begin(); it != data.end(); it++)
{
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0,QString("%1").arg(it->first,8,16,QChar('0')));
item->setData(0, Qt::UserRole, it->first);
item->setText(1,QString("%1").arg(it->second.cmd,2,16,QChar('0')));
item->setText(2,QString("%1").arg(it->second.data,6,16,QChar('0')));
item->setText(3,it->second.comment);
if(curPc == it->first)
{
curTexAddr = it->second.texAddr;
curVtxAddr = it->second.vtxAddr;
curIdxAddr = it->second.idxAddr;
setCurrentFBO(it->second.fboAddr);
for(int j = 0; j < ui->displayListData->columnCount(); j++)
item->setTextColor(j, Qt::green);
}
if(it->second.implementationNotFinished)
{
for(int j = 0; j < ui->displayListData->columnCount(); j++)
item->setBackgroundColor(j, Qt::red);
}
ui->displayListData->addTopLevelItem(item);
if(curPc == it->first)
{
ui->displayListData->setCurrentItem(item);
}
}
for(int j = 0; j < ui->displayListData->columnCount(); j++)
ui->displayListData->resizeColumnToContents(j);
ui->texturesList->clear();
ui->vertexData->clear();
ui->vertexList->clear();
ui->indexData->clear();
ui->indexList->clear();
std::set<u32> usedTexAddr;
std::set<u32> usedVtxAddr;
std::set<u32> usedIdxAddr;
for(int i = 0; i < drawGPUState.size(); i++)
{
// Textures
QTreeWidgetItem* item = new QTreeWidgetItem();
u32 texaddr = (drawGPUState[i].texaddr[0] & 0xFFFFF0) | ((drawGPUState[i].texbufwidth[0]<<8) & 0x0F000000);
if(!(usedTexAddr.find(texaddr) != usedTexAddr.end() || !Memory::IsValidAddress(texaddr)))
{
u32 format = drawGPUState[i].texformat & 0xF;
int w = 1 << (drawGPUState[i].texsize[0] & 0xf);
int h = 1 << ((drawGPUState[i].texsize[0]>>8) & 0xf);
item->setText(0,QString("%1").arg(texaddr,8,16,QChar('0')));
item->setData(0, Qt::UserRole, i);
item->setText(1,QString::number(w));
item->setText(2,QString::number(h));
item->setText(3,QString::number(format,16));
ui->texturesList->addTopLevelItem(item);
if(curTexAddr == texaddr)
{
ui->texturesList->setCurrentItem(item);
for(int j = 0; j < ui->texturesList->columnCount(); j++)
item->setTextColor(j,Qt::green);
}
usedTexAddr.insert(texaddr);
}
// Vertex
QTreeWidgetItem* vertexItem = new QTreeWidgetItem();
u32 baseExtended = ((drawGPUState[i].base & 0x0F0000) << 8) | (drawGPUState[i].vaddr & 0xFFFFFF);
u32 vaddr = ((drawGPUState[i].offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF;
if(!((drawGPUState[i].vaddr) == 0 || !Memory::IsValidAddress(vaddr) || usedVtxAddr.find(vaddr) != usedVtxAddr.end()))
{
vertexItem->setText(0, QString("%1").arg(vaddr,8,16,QChar('0')));
vertexItem->setData(0,Qt::UserRole, i);
if((drawGPUState[i].vertType & GE_VTYPE_THROUGH_MASK) == GE_VTYPE_TRANSFORM)
vertexItem->setText(1, "Transform");
else
vertexItem->setText(1, "Raw");
vertexItem->setText(2, QString::number((drawGPUState[i].vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT));
vertexItem->setText(3, QString::number((drawGPUState[i].vertType & GE_VTYPE_WEIGHTCOUNT_MASK) >> GE_VTYPE_WEIGHTCOUNT_SHIFT));
switch(drawGPUState[i].vertType & GE_VTYPE_WEIGHT_MASK)
{
case GE_VTYPE_WEIGHT_8BIT: vertexItem->setText(4, "8bit"); break;
case GE_VTYPE_WEIGHT_16BIT: vertexItem->setText(4, "16bit"); break;
case GE_VTYPE_WEIGHT_FLOAT: vertexItem->setText(4, "float"); break;
default: vertexItem->setText(4, "No"); break;
}
switch(drawGPUState[i].vertType & GE_VTYPE_POS_MASK)
{
case GE_VTYPE_POS_8BIT: vertexItem->setText(5, "8bit"); break;
case GE_VTYPE_POS_16BIT: vertexItem->setText(5, "16bit"); break;
case GE_VTYPE_POS_FLOAT: vertexItem->setText(5, "float"); break;
default: vertexItem->setText(5, "No"); break;
}
switch(drawGPUState[i].vertType & GE_VTYPE_NRM_MASK)
{
case GE_VTYPE_NRM_8BIT: vertexItem->setText(6, "8bit"); break;
case GE_VTYPE_NRM_16BIT: vertexItem->setText(6, "16bit"); break;
case GE_VTYPE_NRM_FLOAT: vertexItem->setText(6, "float"); break;
default: vertexItem->setText(6, "No"); break;
}
switch(drawGPUState[i].vertType & GE_VTYPE_COL_MASK)
{
case GE_VTYPE_COL_4444: vertexItem->setText(7, "4444"); break;
case GE_VTYPE_COL_5551: vertexItem->setText(7, "5551"); break;
case GE_VTYPE_COL_565: vertexItem->setText(7, "565"); break;
case GE_VTYPE_COL_8888: vertexItem->setText(7, "8888"); break;
default: vertexItem->setText(7, "No"); break;
}
switch(drawGPUState[i].vertType & GE_VTYPE_TC_MASK)
{
case GE_VTYPE_TC_8BIT: vertexItem->setText(8, "8bit"); break;
case GE_VTYPE_TC_16BIT: vertexItem->setText(8, "16bit"); break;
case GE_VTYPE_TC_FLOAT: vertexItem->setText(8, "float"); break;
default: vertexItem->setText(8, "No"); break;
}
ui->vertexList->addTopLevelItem(vertexItem);
if(curVtxAddr == vaddr)
{
ui->vertexList->setCurrentItem(vertexItem);
for(int j = 0; j < ui->vertexList->columnCount(); j++)
vertexItem->setTextColor(j,Qt::green);
}
usedVtxAddr.insert(vaddr);
}
// Index
QTreeWidgetItem* indexItem = new QTreeWidgetItem();
baseExtended = ((drawGPUState[i].base & 0x0F0000) << 8) | (drawGPUState[i].iaddr & 0xFFFFFF);
u32 iaddr = ((drawGPUState[i].offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF;
if(!((drawGPUState[i].iaddr & 0xFFFFFF) == 0 || !Memory::IsValidAddress(iaddr) || usedIdxAddr.find(iaddr) != usedIdxAddr.end()))
{
indexItem->setText(0, QString("%1").arg(iaddr,8,16,QChar('0')));
indexItem->setData(0,Qt::UserRole, i);
ui->indexList->addTopLevelItem(indexItem);
if(curIdxAddr == iaddr)
{
ui->indexList->setCurrentItem(indexItem);
for(int j = 0; j < ui->indexList->columnCount(); j++)
indexItem->setTextColor(j,Qt::green);
}
usedIdxAddr.insert(iaddr);
}
for(int i = 0; i < ui->texturesList->columnCount(); i++)
ui->texturesList->resizeColumnToContents(i);
for(int i = 0; i < ui->vertexList->columnCount(); i++)
ui->vertexList->resizeColumnToContents(i);
for(int i = 0; i < ui->indexList->columnCount(); i++)
ui->indexList->resizeColumnToContents(i);
}
UpdateVertexInfo();
UpdateIndexInfo();
}
QString Debugger_DisplayList::DisassembleOp(u32 pc, u32 op, u32 prev, const GPUgstate& state) {
u32 cmd = op >> 24;
u32 data = op & 0xFFFFFF;
// Handle control and drawing commands here directly. The others we delegate.
switch (cmd)
{
case GE_CMD_BASE:
return QString("BASE: %1").arg(data & 0xFFFFFF,6,16,QChar('0'));
break;
case GE_CMD_VADDR: /// <<8????
{
u32 baseExtended = ((state.base & 0x0F0000) << 8) | (data & 0xFFFFFF);
baseExtended = (state.offsetAddr + baseExtended) & 0x0FFFFFFF;
return QString("VADDR: %1").arg(baseExtended,6,16,QChar('0'));
break;
}
case GE_CMD_IADDR:
{
u32 baseExtended = ((state.base & 0x0F0000) << 8) | (data & 0xFFFFFF);
baseExtended = (state.offsetAddr + baseExtended) & 0x0FFFFFFF;
return QString("IADDR: %1").arg(baseExtended,6,16,QChar('0'));
break;
}
case GE_CMD_PRIM:
{
u32 count = data & 0xFFFF;
u32 type = data >> 16;
static const char* types[7] = {
"POINTS",
"LINES",
"LINE_STRIP",
"TRIANGLES",
"TRIANGLE_STRIP",
"TRIANGLE_FAN",
"RECTANGLES",
};
return QString("DrawPrim type: %1 count: %2").arg(type < 7 ? types[type] : "INVALID").arg(count);
}
break;
// The arrow and other rotary items in Puzbob are bezier patches, strangely enough.
case GE_CMD_BEZIER:
{
int bz_ucount = data & 0xFF;
int bz_vcount = (data >> 8) & 0xFF;
return QString("DRAW BEZIER: %1 x %2").arg(bz_ucount).arg(bz_vcount);
}
break;
case GE_CMD_SPLINE:
{
int sp_ucount = data & 0xFF;
int sp_vcount = (data >> 8) & 0xFF;
int sp_utype = (data >> 16) & 0x3;
int sp_vtype = (data >> 18) & 0x3;
return QString("DRAW SPLINE: %1 x %2, %3 x %4").arg(sp_ucount).arg(sp_vcount).arg(sp_utype).arg(sp_vtype);
}
break;
case GE_CMD_JUMP:
{
u32 target = (((state.base & 0x00FF0000) << 8) | (op & 0xFFFFFC)) & 0x0FFFFFFF;
return QString("CMD JUMP - %1 to %2").arg(pc,8,16,QChar('0')).arg(target,8,16,QChar('0'));
}
break;
case GE_CMD_CALL:
{
u32 retval = pc + 4;
u32 baseExtended = ((state.base & 0x0F0000) << 8) | (op & 0xFFFFFF);
u32 target = (state.offsetAddr + baseExtended) & 0x0FFFFFFF;
return QString("CMD CALL - %1 to %2, ret=%3").arg(pc,8,16,QChar('0')).arg(target,8,16,QChar('0')).arg(retval,8,16,QChar('0'));
}
break;
case GE_CMD_RET:
return QString("CMD RET");
break;
case GE_CMD_SIGNAL:
return QString("GE_CMD_SIGNAL %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_FINISH:
return QString("CMD FINISH %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_END:
switch (prev >> 24)
{
case GE_CMD_SIGNAL:
{
// TODO: see http://code.google.com/p/jpcsp/source/detail?r=2935#
int behaviour = (prev >> 16) & 0xFF;
int signal = prev & 0xFFFF;
int enddata = data & 0xFFFF;
// We should probably defer to sceGe here, no sense in implementing this stuff in every GPU
switch (behaviour) {
case 1: // Signal with Wait
return QString("Signal with Wait UNIMPLEMENTED! signal/end: %1 %2").arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0'));
break;
case 2:
return QString("Signal without wait. signal/end: %1 %2").arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0'));
break;
case 3:
return QString("Signal with Pause UNIMPLEMENTED! signal/end: %1 %2").arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0'));
break;
case 0x10:
return QString("Signal with Jump UNIMPLEMENTED! signal/end: %1 %2").arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0'));
break;
case 0x11:
return QString("Signal with Call UNIMPLEMENTED! signal/end: %1 %2").arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0'));
break;
case 0x12:
return QString("Signal with Return UNIMPLEMENTED! signal/end: %1 %2").arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0'));
break;
default:
return QString("UNKNOWN Signal UNIMPLEMENTED %1 ! signal/end: %1 %2").arg(behaviour).arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0'));
break;
}
}
break;
case GE_CMD_FINISH:
break;
default:
return QString("Ah, not finished: %1").arg(prev & 0xFFFFFF,6,16,QChar('0'));
break;
}
return "CMD END";
break;
case GE_CMD_BJUMP:
// bounding box jump. Let's just not jump, for now.
return QString("BBOX JUMP - unimplemented");
break;
case GE_CMD_BOUNDINGBOX:
// bounding box test. Let's do nothing.
return QString("BBOX TEST - unimplemented");
break;
case GE_CMD_ORIGIN:
return QString("Origin: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_VERTEXTYPE:
return QString("SetVertexType: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_OFFSETADDR:
return QString("OffsetAddr: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_REGION1:
{
int x1 = data & 0x3ff;
int y1 = data >> 10;
//topleft
return QString("Region TL: %1 %2").arg(x1).arg(y1);
}
break;
case GE_CMD_REGION2:
{
int x2 = data & 0x3ff;
int y2 = data >> 10;
return QString("Region BR: %1 %2").arg(x2).arg(y2);
}
break;
case GE_CMD_CLIPENABLE:
return QString("Clip Enable: %1").arg(data);
break;
case GE_CMD_CULLFACEENABLE:
return QString("CullFace Enable: %1").arg(data);
break;
case GE_CMD_TEXTUREMAPENABLE:
return QString("Texture map enable: %1").arg(data);
break;
case GE_CMD_LIGHTINGENABLE:
return QString("Lighting enable: %1").arg(data);
break;
case GE_CMD_FOGENABLE:
return QString("Fog Enable: %1").arg(data);
break;
case GE_CMD_DITHERENABLE:
return QString("Dither Enable: %1").arg(data);
break;
case GE_CMD_OFFSETX:
return QString("Offset X: %1").arg(data);
break;
case GE_CMD_OFFSETY:
return QString("Offset Y: %1").arg(data);
break;
case GE_CMD_TEXSCALEU:
return QString("Texture U Scale: %1").arg(getFloat24(data));
break;
case GE_CMD_TEXSCALEV:
return QString("Texture V Scale: %1").arg(getFloat24(data));
break;
case GE_CMD_TEXOFFSETU:
return QString("Texture U Offset: %1").arg(getFloat24(data));
break;
case GE_CMD_TEXOFFSETV:
return QString("Texture V Offset: %1").arg(getFloat24(data));
break;
case GE_CMD_SCISSOR1:
{
int x1 = data & 0x3ff;
int y1 = data >> 10;
return QString("Scissor TL: %1, %2").arg(x1).arg(y1);
}
break;
case GE_CMD_SCISSOR2:
{
int x2 = data & 0x3ff;
int y2 = data >> 10;
return QString("Scissor BR: %1, %2").arg(x2).arg(y2);
}
break;
case GE_CMD_MINZ:
{
float zMin = getFloat24(data) / 65535.f;
return QString("MinZ: %1").arg(zMin);
}
break;
case GE_CMD_MAXZ:
{
float zMax = getFloat24(data) / 65535.f;
return QString("MaxZ: %1").arg(zMax);
}
break;
case GE_CMD_FRAMEBUFPTR:
{
u32 ptr = op & 0xFFE000;
return QString("FramebufPtr: %1").arg(data,8,16,QChar('0'));
}
break;
case GE_CMD_FRAMEBUFWIDTH:
{
return QString("FramebufWidth: %1").arg(data);
}
break;
case GE_CMD_FRAMEBUFPIXFORMAT:
return QString("FramebufPixeFormat: %1").arg(data);
break;
case GE_CMD_TEXADDR0:
case GE_CMD_TEXADDR1:
case GE_CMD_TEXADDR2:
case GE_CMD_TEXADDR3:
case GE_CMD_TEXADDR4:
case GE_CMD_TEXADDR5:
case GE_CMD_TEXADDR6:
case GE_CMD_TEXADDR7:
return QString("Texture address %1: %2").arg(cmd-GE_CMD_TEXADDR0).arg(data,6,16,QChar('0'));
break;
case GE_CMD_TEXBUFWIDTH0:
case GE_CMD_TEXBUFWIDTH1:
case GE_CMD_TEXBUFWIDTH2:
case GE_CMD_TEXBUFWIDTH3:
case GE_CMD_TEXBUFWIDTH4:
case GE_CMD_TEXBUFWIDTH5:
case GE_CMD_TEXBUFWIDTH6:
case GE_CMD_TEXBUFWIDTH7:
return QString("Texture BUFWIDTHess %1: %2").arg(cmd-GE_CMD_TEXBUFWIDTH0).arg(data,6,16,QChar('0'));
break;
case GE_CMD_CLUTADDR:
return QString("CLUT base addr: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_CLUTADDRUPPER:
return QString("CLUT addr upper %1").arg(data,8,16,QChar('0'));
break;
case GE_CMD_LOADCLUT:
// This could be used to "dirty" textures with clut.
return QString("Clut load");
break;
case GE_CMD_TEXMAPMODE:
return QString("Tex map mode: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_TEXSHADELS:
return QString("Tex shade light sources: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_CLUTFORMAT:
{
return QString("Clut format: %1").arg(data,6,16,QChar('0'));
}
break;
case GE_CMD_TRANSFERSRC:
{
return QString("Block Transfer Src: %1").arg(data,6,16,QChar('0'));
// Nothing to do, the next one prints
}
break;
case GE_CMD_TRANSFERSRCW:
{
u32 xferSrc = state.transfersrc | ((data&0xFF0000)<<8);
u32 xferSrcW = state.transfersrcw & 1023;
return QString("Block Transfer Src: %1 W: %2").arg(xferSrc,8,16,QChar('0')).arg(xferSrcW);
break;
}
case GE_CMD_TRANSFERDST:
{
// Nothing to do, the next one prints
return QString("Block Transfer Dst: %1").arg(data,6,16,QChar('0'));
}
break;
case GE_CMD_TRANSFERDSTW:
{
u32 xferDst= state.transferdst | ((data&0xFF0000)<<8);
u32 xferDstW = state.transferdstw & 1023;
return QString("Block Transfer Dest: %1 W: %2").arg(xferDst,8,16,QChar('0')).arg(xferDstW);
break;
}
case GE_CMD_TRANSFERSRCPOS:
{
u32 x = (data & 1023)+1;
u32 y = ((data>>10) & 1023)+1;
return QString("Block Transfer Src Rect TL: %1, %2").arg(x).arg(y);
break;
}
case GE_CMD_TRANSFERDSTPOS:
{
u32 x = (data & 1023)+1;
u32 y = ((data>>10) & 1023)+1;
return QString("Block Transfer Dest Rect TL: %1, %2").arg(x).arg(y);
break;
}
case GE_CMD_TRANSFERSIZE:
{
u32 w = (data & 1023)+1;
u32 h = ((data>>10) & 1023)+1;
return QString("Block Transfer Rect Size: %1 x %2").arg(w).arg(h);
break;
}
case GE_CMD_TRANSFERSTART: // Orphis calls this TRXKICK
{
return QString("Block Transfer Start");
break;
}
case GE_CMD_TEXSIZE0:
case GE_CMD_TEXSIZE1:
case GE_CMD_TEXSIZE2:
case GE_CMD_TEXSIZE3:
case GE_CMD_TEXSIZE4:
case GE_CMD_TEXSIZE5:
case GE_CMD_TEXSIZE6:
case GE_CMD_TEXSIZE7:
{
int w = 1 << (data & 0xf);
int h = 1 << ((data>>8) & 0xf);
return QString("Texture Size %1: %2, width : %3, height : %4").arg(cmd - GE_CMD_TEXSIZE0).arg(data,6,16,QChar('0')).arg(w).arg(h);
}
break;
case GE_CMD_ZBUFPTR:
{
u32 ptr = op & 0xFFE000;
return QString("Zbuf Ptr: %1").arg(ptr,6,16,QChar('0'));
}
break;
case GE_CMD_ZBUFWIDTH:
{
return QString("Zbuf Width: %1").arg(data,6,16,QChar('0'));
}
break;
case GE_CMD_AMBIENTCOLOR:
return QString("Ambient Color: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_AMBIENTALPHA:
return QString("Ambient Alpha: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_MATERIALAMBIENT:
return QString("Material Ambient Color: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_MATERIALDIFFUSE:
return QString("Material Diffuse Color: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_MATERIALEMISSIVE:
return QString("Material Emissive Color: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_MATERIALSPECULAR:
return QString("Material Specular Color: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_MATERIALALPHA:
return QString("Material Alpha Color: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_MATERIALSPECULARCOEF:
return QString("Material specular coef: %1").arg(getFloat24(data));
break;
case GE_CMD_SHADEMODE:
return QString("Shade: %1 (%2)").arg(data,6,16,QChar('0')).arg(data ? "gouraud" : "flat");
break;
case GE_CMD_LIGHTMODE:
return QString("Lightmode: %1 (%2)").arg(data,6,16,QChar('0')).arg(data ? "separate spec" : "single color");
break;
case GE_CMD_LIGHTTYPE0:
case GE_CMD_LIGHTTYPE1:
case GE_CMD_LIGHTTYPE2:
case GE_CMD_LIGHTTYPE3:
return QString("Light %1 type: %2").arg(cmd-GE_CMD_LIGHTTYPE0).arg(data,6,16,QChar('0'));
break;
case GE_CMD_LX0:case GE_CMD_LY0:case GE_CMD_LZ0:
case GE_CMD_LX1:case GE_CMD_LY1:case GE_CMD_LZ1:
case GE_CMD_LX2:case GE_CMD_LY2:case GE_CMD_LZ2:
case GE_CMD_LX3:case GE_CMD_LY3:case GE_CMD_LZ3:
{
int n = cmd - GE_CMD_LX0;
int l = n / 3;
int c = n % 3;
float val = getFloat24(data);
return QString("Light %1 %2 pos: %3").arg(l).arg(QChar('X')+c).arg(val);
}
break;
case GE_CMD_LDX0:case GE_CMD_LDY0:case GE_CMD_LDZ0:
case GE_CMD_LDX1:case GE_CMD_LDY1:case GE_CMD_LDZ1:
case GE_CMD_LDX2:case GE_CMD_LDY2:case GE_CMD_LDZ2:
case GE_CMD_LDX3:case GE_CMD_LDY3:case GE_CMD_LDZ3:
{
int n = cmd - GE_CMD_LDX0;
int l = n / 3;
int c = n % 3;
float val = getFloat24(data);
return QString("Light %1 %2 dir: %3").arg(l).arg(QChar('X')+c).arg(val);
}
break;
case GE_CMD_LKA0:case GE_CMD_LKB0:case GE_CMD_LKC0:
case GE_CMD_LKA1:case GE_CMD_LKB1:case GE_CMD_LKC1:
case GE_CMD_LKA2:case GE_CMD_LKB2:case GE_CMD_LKC2:
case GE_CMD_LKA3:case GE_CMD_LKB3:case GE_CMD_LKC3:
{
int n = cmd - GE_CMD_LKA0;
int l = n / 3;
int c = n % 3;
float val = getFloat24(data);
return QString("Light %1 %2 att: %3").arg(l).arg(QChar('X')+c).arg(val);
}
break;
case GE_CMD_LAC0:case GE_CMD_LAC1:case GE_CMD_LAC2:case GE_CMD_LAC3:
case GE_CMD_LDC0:case GE_CMD_LDC1:case GE_CMD_LDC2:case GE_CMD_LDC3:
case GE_CMD_LSC0:case GE_CMD_LSC1:case GE_CMD_LSC2:case GE_CMD_LSC3:
{
float r = (float)(data & 0xff)/255.0f;
float g = (float)((data>>8) & 0xff)/255.0f;
float b = (float)(data>>16)/255.0f;
int l = (cmd - GE_CMD_LAC0) / 3;
int t = (cmd - GE_CMD_LAC0) % 3;
return QString("Light %1 color %2: %3 %4 %5").arg(l).arg(t).arg(r).arg(g).arg(b);
}
break;
case GE_CMD_VIEWPORTX1:
case GE_CMD_VIEWPORTY1:
case GE_CMD_VIEWPORTX2:
case GE_CMD_VIEWPORTY2:
return QString("Viewport param %1: %2").arg(cmd-GE_CMD_VIEWPORTX1).arg(getFloat24(data));
break;
case GE_CMD_VIEWPORTZ1:
{
float zScale = getFloat24(data) / 65535.f;
return QString("Viewport Z scale: %1").arg(zScale);
}
break;
case GE_CMD_VIEWPORTZ2:
{
float zOff = getFloat24(data) / 65535.f;
return QString("Viewport Z pos: %1").arg(zOff);
}
break;
case GE_CMD_LIGHTENABLE0:
case GE_CMD_LIGHTENABLE1:
case GE_CMD_LIGHTENABLE2:
case GE_CMD_LIGHTENABLE3:
return QString("Light %1 enable: %2").arg(cmd-GE_CMD_LIGHTENABLE0).arg(data);
break;
case GE_CMD_CULL:
return QString("cull: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_PATCHDIVISION:
{
int patch_div_s = data & 0xFF;
int patch_div_t = (data >> 8) & 0xFF;
return QString("Patch subdivision: %1 x %2").arg(patch_div_s).arg(patch_div_t);
}
break;
case GE_CMD_PATCHPRIMITIVE:
return QString("Patch Primitive: %1").arg(data);
break;
case GE_CMD_PATCHFACING:
return QString( "Patch Facing: %1").arg(data);
break;
case GE_CMD_REVERSENORMAL:
return QString("Reverse normal: %1").arg(data);
break;
case GE_CMD_MATERIALUPDATE:
return QString("Material Update: %1").arg(data);
break;
//////////////////////////////////////////////////////////////////
// CLEARING
//////////////////////////////////////////////////////////////////
case GE_CMD_CLEARMODE:
// If it becomes a performance problem, check diff&1
return QString("Clear mode: %1").arg(data,6,16,QChar('0'));
break;
//////////////////////////////////////////////////////////////////
// ALPHA BLENDING
//////////////////////////////////////////////////////////////////
case GE_CMD_ALPHABLENDENABLE:
return QString("Alpha blend enable: %1").arg(data);
break;
case GE_CMD_BLENDMODE:
return QString("Blend mode: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_BLENDFIXEDA:
return QString("Blend fix A: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_BLENDFIXEDB:
return QString("Blend fix B: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_ALPHATESTENABLE:
return QString("Alpha test enable: %1").arg(data);
break;
case GE_CMD_ALPHATEST:
return QString("Alpha test settings");
break;
case GE_CMD_ANTIALIASENABLE:
return QString("Antialias enable: %1").arg(data);
break;
case GE_CMD_PATCHCULLENABLE:
return QString("Antialias enable: %1").arg(data);
break;
case GE_CMD_COLORTESTENABLE:
return QString("Color Test enable: %1").arg(data);
break;
case GE_CMD_LOGICOPENABLE:
return QString("Logic op enable: %1").arg(data);
break;
case GE_CMD_TEXFUNC:
return QString("TexFunc %1").arg(data&7);
break;
case GE_CMD_TEXFILTER:
{
int min = data & 7;
int mag = (data >> 8) & 1;
return QString("TexFilter min: %1 mag: %2").arg( min).arg(mag);
}
break;
case GE_CMD_TEXENVCOLOR:
return QString("TexEnvColor %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_TEXMODE:
return QString("TexMode %1").arg(data,8,16,QChar('0'));
break;
case GE_CMD_TEXFORMAT:
return QString("TexFormat %1").arg(data,8,16,QChar('0'));
break;
case GE_CMD_TEXFLUSH:
return QString("TexFlush");
break;
case GE_CMD_TEXSYNC:
return QString("TexSync");
break;
case GE_CMD_TEXWRAP:
return QString("TexWrap %1").arg(data,8,16,QChar('0'));
break;
case GE_CMD_TEXLEVEL:
return QString("TexWrap Mode: %1 Offset: %2").arg(data&3).arg(data >> 16);
break;
case GE_CMD_FOG1:
return QString("Fog1 %1").arg(getFloat24(data));
break;
case GE_CMD_FOG2:
return QString( "Fog2 %1").arg(getFloat24(data));
break;
case GE_CMD_FOGCOLOR:
return QString("FogColor %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_TEXLODSLOPE:
return QString( "TexLodSlope %1").arg(data,6,16,QChar('0'));
break;
//////////////////////////////////////////////////////////////////
// Z/STENCIL TESTING
//////////////////////////////////////////////////////////////////
case GE_CMD_ZTESTENABLE:
return QString( "Z test enable: %1").arg(data&1);
break;
case GE_CMD_STENCILOP:
return QString("Stencil op: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_STENCILTEST:
return QString("Stencil test: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_STENCILTESTENABLE:
return QString("Stencil test enable: %1").arg(data);
break;
case GE_CMD_ZTEST:
return QString("Z test mode: %1").arg(data);
break;
case GE_CMD_MORPHWEIGHT0:
case GE_CMD_MORPHWEIGHT1:
case GE_CMD_MORPHWEIGHT2:
case GE_CMD_MORPHWEIGHT3:
case GE_CMD_MORPHWEIGHT4:
case GE_CMD_MORPHWEIGHT5:
case GE_CMD_MORPHWEIGHT6:
case GE_CMD_MORPHWEIGHT7:
{
int index = cmd - GE_CMD_MORPHWEIGHT0;
float weight = getFloat24(data);
return QString("MorphWeight %1 = %2").arg(index).arg(weight);
}
break;
case GE_CMD_DITH0:
case GE_CMD_DITH1:
case GE_CMD_DITH2:
case GE_CMD_DITH3:
return QString("DitherMatrix %1 = %2").arg(cmd-GE_CMD_DITH0).arg(data,6,16,QChar('0'));
break;
case GE_CMD_LOGICOP:
return QString("LogicOp: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_ZWRITEDISABLE:
return QString("ZMask: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_COLORTEST:
return QString("ColorTest: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_COLORREF:
return QString("ColorRef: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_COLORTESTMASK:
return QString( "ColorTestMask: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_MASKRGB:
return QString("MaskRGB: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_MASKALPHA:
return QString("MaskAlpha: %1").arg(data,6,16,QChar('0'));
break;
case GE_CMD_WORLDMATRIXNUMBER:
return QString("World # %1").arg(data & 0xF);
break;
case GE_CMD_WORLDMATRIXDATA:
return QString("World data # %1").arg(getFloat24(data));
break;
case GE_CMD_VIEWMATRIXNUMBER:
return QString("VIEW # %1").arg(data & 0xF);
break;
case GE_CMD_VIEWMATRIXDATA:
return QString("VIEW data # %1").arg(getFloat24(data));
break;
case GE_CMD_PROJMATRIXNUMBER:
return QString("PROJECTION # %1").arg(data & 0xF);
break;
case GE_CMD_PROJMATRIXDATA:
return QString("PROJECTION matrix data # %1").arg(getFloat24(data));
break;
case GE_CMD_TGENMATRIXNUMBER:
return QString("TGEN # %1").arg(data & 0xF);
break;
case GE_CMD_TGENMATRIXDATA:
return QString("TGEN data # %1").arg(getFloat24(data));
break;
case GE_CMD_BONEMATRIXNUMBER:
return QString("BONE #%1").arg(data);
break;
case GE_CMD_BONEMATRIXDATA:
return QString("BONE data #%1 %2").arg(state.boneMatrixNumber & 0x7f).arg(getFloat24(data));
break;
default:
return QString("Unknown: %1").arg(op,8,16,QChar('0'));
break;
}
}
void Debugger_DisplayList::FillDisplayListCmd(std::map<int,DListLine>& data, u32 pc, u32 prevAddr, GPUgstate& state)
{
u32 curPc = pc;
int debugLimit = 10000; // Anti crash if this code is bugged
while(Memory::IsValidAddress(curPc) && debugLimit > 0)
{
if(data.find(curPc) != data.end())
return;
u32 op = Memory::ReadUnchecked_U32(curPc); //read from memory
u32 cmd = op >> 24;
u32 data_ = op & 0xFFFFFF;
u32 diff = op ^ gstate.cmdmem[cmd];
state.cmdmem[cmd] = op;
u32 prevOp = 0;
if(Memory::IsValidAddress(prevAddr))
Memory::ReadUnchecked_U32(prevAddr);
data[curPc].comment = DisassembleOp(curPc, op, prevOp, state);
data[curPc].addr = curPc;
data[curPc].cmd = cmd;
data[curPc].data = data_;
data[curPc].implementationNotFinished = false;
data[curPc].texAddr = (gstate.texaddr[0] & 0xFFFFF0) | ((gstate.texbufwidth[0]<<8) & 0x0F000000);
data[curPc].fboAddr = state.fbptr & 0xFFFFFF;
u32 baseExtended = ((state.base & 0x0F0000) << 8) | (state.vaddr & 0xFFFFFF);
data[curPc].vtxAddr = ((state.offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF;
baseExtended = ((state.base & 0x0F0000) << 8) | (state.iaddr & 0xFFFFFF);
data[curPc].idxAddr = ((state.offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF;
// Add or remove bugged functions for highlight
if(cmd == GE_CMD_BEZIER ||
cmd == GE_CMD_SPLINE ||
cmd == GE_CMD_BJUMP ||
cmd == GE_CMD_BOUNDINGBOX)
{
data[curPc].implementationNotFinished = true;
}
// We are drawing, save the GPU state for texture, vertex and index list
if(cmd == GE_CMD_PRIM || cmd == GE_CMD_BEZIER || cmd == GE_CMD_SPLINE)
{
drawGPUState.push_back(state);
}
if(cmd == GE_CMD_JUMP)
{
u32 baseExtended = ((state.base & 0x0F0000) << 8) | (data_ & 0xFFFFFF);
u32 target = (((state.offsetAddr & 0xFFFFFF) << 8) + baseExtended) & 0x0FFFFFFF;
FillDisplayListCmd(data, target, prevAddr, state);
return;
}
else if(cmd == GE_CMD_CALL)
{
u32 baseExtended = ((state.base & 0x0F0000) << 8) | (data_ & 0xFFFFFF);
u32 target = (((state.offsetAddr & 0xFFFFFF) << 8) + baseExtended) & 0x0FFFFFFF;
FillDisplayListCmd(data, target, prevAddr, state);
}
else if(cmd == GE_CMD_RET)
{
return;
}
else if(cmd == GE_CMD_FINISH)
{
return;
}
else if(cmd == GE_CMD_END)
{
if(prevOp >> 24 == GE_CMD_FINISH)
return;
}
prevAddr = curPc;
curPc += 4;
debugLimit--;
}
}
void Debugger_DisplayList::Update()
{
UpdateRenderBuffer();
UpdateRenderBufferList();
UpdateDisplayList();
}
void Debugger_DisplayList::on_displayList_itemClicked(QTreeWidgetItem *item, int column)
{
displayListRowSelected = item;
ShowDLCode();
}
void Debugger_DisplayList::on_stepBtn_clicked()
{
host->SetGPUStep(true);
host->NextGPUStep();
}
void Debugger_DisplayList::on_runBtn_clicked()
{
ui->displayList->clear();
ui->displayListData->clear();
host->SetGPUStep(false);
host->NextGPUStep();
}
void Debugger_DisplayList::on_stopBtn_clicked()
{
host->SetGPUStep(true);
}
void Debugger_DisplayList::UpdateRenderBuffer()
{
EmuThread_LockDraw(true);
gpu->Flush();
int FRAME_WIDTH;
int FRAME_HEIGHT;
u8 *data = 0;
int curTex;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &curTex);
if(currentTextureDisplay == 0)
{
FRAME_WIDTH = pixel_xres;
FRAME_HEIGHT = pixel_yres;
data = new u8[FRAME_WIDTH * FRAME_HEIGHT * 4];
memset(data,0,FRAME_WIDTH * FRAME_HEIGHT * 4);
if(currentRenderFrameDisplay == 0)
{
glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(0, 0, FRAME_WIDTH, FRAME_HEIGHT, GL_BGRA, GL_UNSIGNED_BYTE, data);
}
else
{
glReadBuffer(GL_DEPTH_ATTACHMENT);
glReadPixels(0, 0, FRAME_WIDTH, FRAME_HEIGHT, GL_DEPTH_COMPONENT, GL_FLOAT, data);
}
}
else
{
fbo_get_dimensions(currentTextureDisplay, &FRAME_WIDTH, &FRAME_HEIGHT);
data = new u8[FRAME_WIDTH * FRAME_HEIGHT * 4];
memset(data,0,FRAME_WIDTH * FRAME_HEIGHT * 4);
if(currentRenderFrameDisplay == 0)
{
fbo_bind_color_as_texture(currentTextureDisplay,0);
glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, data);
}
}
glBindTexture(GL_TEXTURE_2D, curTex);
QImage img = QImage(data, FRAME_WIDTH, FRAME_HEIGHT, FRAME_WIDTH*4, QImage::Format_ARGB32).mirrored(false,true);
QPixmap pixmap = QPixmap::fromImage(img);
ui->fboImg->setPixmap(pixmap);
ui->fboImg->setMinimumWidth(pixmap.width() * fboZoomFactor);
ui->fboImg->setMinimumHeight(pixmap.height() * fboZoomFactor);
ui->fboImg->setMaximumWidth(pixmap.width() * fboZoomFactor);
ui->fboImg->setMaximumHeight(pixmap.height() * fboZoomFactor);
delete[] data;
EmuThread_LockDraw(false);
}
void Debugger_DisplayList::on_nextDrawBtn_clicked()
{
host->SetGPUStep(true, 1);
host->NextGPUStep();
}
void Debugger_DisplayList::on_gotoPCBtn_clicked()
{
if(!displayListRowSelected)
return;
u32 currentPC = displayListRowSelected->data(3, Qt::UserRole).toInt();
for(int i = 0; i < ui->displayListData->topLevelItemCount(); i++)
{
if(ui->displayListData->topLevelItem(i)->data(0, Qt::UserRole).toInt() == currentPC)
{
ui->displayListData->setCurrentItem(ui->displayListData->topLevelItem(i));
}
}
}
void Debugger_DisplayList::on_texturesList_itemDoubleClicked(QTreeWidgetItem *item, int column)
{
mainWindow->GetDialogMemoryTex()->ShowTex(drawGPUState[item->data(0,Qt::UserRole).toInt()]);
}
void Debugger_DisplayList::on_comboBox_currentIndexChanged(int index)
{
currentRenderFrameDisplay = index;
UpdateRenderBuffer();
}
void Debugger_DisplayList::UpdateRenderBufferList()
{
emit updateRenderBufferList_();
}
void Debugger_DisplayList::UpdateRenderBufferListGUI()
{
ui->fboList->clear();
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0,"Framebuffer");
item->setData(0,Qt::UserRole, 0);
item->setText(1,QString::number(pixel_xres));
item->setText(2,QString::number(pixel_yres));
item->setText(3,QString::number(4));
ui->fboList->addTopLevelItem(item);
std::vector<FramebufferInfo> fboList = gpu->GetFramebufferList();
for(int i = 0; i < fboList.size(); i++)
{
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0,QString("%1").arg(fboList[i].fb_address,8,16,QChar('0')));
u64 addr = (u64)fboList[i].fbo;
item->setData(0,Qt::UserRole, addr);
item->setData(0,Qt::UserRole+1, fboList[i].fb_address);
item->setText(1,QString::number(fboList[i].width));
item->setText(2,QString::number(fboList[i].height));
item->setText(3,QString::number(fboList[i].format));
ui->fboList->addTopLevelItem(item);
}
}
void Debugger_DisplayList::on_fboList_itemClicked(QTreeWidgetItem *item, int column)
{
u64 addr = item->data(0,Qt::UserRole).toULongLong();
FBO* fbo = (FBO*)addr;
currentTextureDisplay = fbo;
UpdateRenderBuffer();
}
void Debugger_DisplayList::on_nextDLBtn_clicked()
{
host->SetGPUStep(true,-1);
host->NextGPUStep();
}
void Debugger_DisplayList::setCurrentFBO(u32 addr)
{
for(int i = 0; i < ui->fboList->topLevelItemCount(); i++)
{
if(ui->fboList->topLevelItem(i)->data(0,Qt::UserRole+1).toInt() == addr)
{
for(int j = 0; j < ui->fboList->colorCount(); j++)
ui->fboList->topLevelItem(i)->setTextColor(j,Qt::green);
}
else
{
for(int j = 0; j < ui->fboList->colorCount(); j++)
ui->fboList->topLevelItem(i)->setTextColor(j,Qt::black);
}
}
}
void Debugger_DisplayList::on_zoommBtn_clicked()
{
fboZoomFactor *= 0.5;
ui->fboImg->setMinimumWidth(ui->fboImg->minimumWidth()*0.5);
ui->fboImg->setMinimumHeight(ui->fboImg->minimumHeight()*0.5);
ui->fboImg->setMaximumWidth(ui->fboImg->minimumWidth()*0.5);
ui->fboImg->setMaximumHeight(ui->fboImg->minimumHeight()*0.5);
}
void Debugger_DisplayList::on_zoompBtn_clicked()
{
fboZoomFactor *= 2;
ui->fboImg->setMinimumWidth(ui->fboImg->minimumWidth()*2);
ui->fboImg->setMinimumHeight(ui->fboImg->minimumHeight()*2);
ui->fboImg->setMaximumWidth(ui->fboImg->minimumWidth()*2);
ui->fboImg->setMaximumHeight(ui->fboImg->minimumHeight()*2);
}
void Debugger_DisplayList::UpdateVertexInfo()
{
ui->vertexData->clear();
QTreeWidgetItem* item = ui->vertexList->currentItem();
if(item == 0)
return;
GPUgstate state = drawGPUState[item->data(0,Qt::UserRole).toInt()];
u32 baseExtended = ((state.base & 0x0F0000) << 8) | (state.vaddr & 0xFFFFFF);
u32 vaddr = ((state.offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF;
VertexDecoder vtcDec;
vtcDec.SetVertexType(state.vertType);
u8 tmp[20*vtcDec.GetDecVtxFmt().stride];
vtcDec.DecodeVerts(tmp,Memory::GetPointer(vaddr),0,0,0,0,19);
VertexReader vtxRead(tmp,vtcDec.GetDecVtxFmt(),state.vertType);
for(int i = 0; i < maxVtxDisplay; i++)
{
vtxRead.Goto(i);
QTreeWidgetItem* itemTop = new QTreeWidgetItem();
itemTop->setText(0,QString::number(i));
itemTop->setText(1,QString("%1").arg(vaddr+i*vtcDec.GetDecVtxFmt().stride,8,16,QChar('0')));
ui->vertexData->addTopLevelItem(itemTop);
if (vtxRead.hasNormal())
{
float nrm[3];
vtxRead.ReadNrm(nrm);
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(1,"Normal");
item->setText(2,QString("X: %1, Y: %2, Z: %3").arg(nrm[0]).arg(nrm[1]).arg(nrm[2]));
itemTop->addChild(item);
}
if (vtxRead.hasUV()) {
float uv[2];
vtxRead.ReadUV(uv);
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(1,"Uv");
item->setText(2,QString("X: %1, Y: %2").arg(uv[0]).arg(uv[1]));
itemTop->addChild(item);
}
if (vtxRead.hasColor0()) {
float col0[4];
vtxRead.ReadColor0(col0);
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(1,"Color0");
item->setText(2,QString("X: %1, Y: %2, Z: %3").arg(col0[0]).arg(col0[1]).arg(col0[2]));
itemTop->addChild(item);
}
if (vtxRead.hasColor0()) {
float col1[3];
vtxRead.ReadColor1(col1);
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(1,"Color1");
item->setText(2,QString("X: %1, Y: %2, Z: %3").arg(col1[0]).arg(col1[1]).arg(col1[2]));
itemTop->addChild(item);
}
float pos[3];
vtxRead.ReadPos(pos);
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(1,"Position");
item->setText(2,QString("X: %1, Y: %2, Z: %3").arg(pos[0]).arg(pos[1]).arg(pos[2]));
itemTop->addChild(item);
}
for(int i = 0; i < ui->vertexData->columnCount(); i++)
{
ui->vertexData->resizeColumnToContents(i);
}
}
void Debugger_DisplayList::on_vertexList_itemClicked(QTreeWidgetItem *item, int column)
{
UpdateVertexInfo();
}
void Debugger_DisplayList::on_pushButton_clicked()
{
maxVtxDisplay += 20;
UpdateVertexInfo();
}
void Debugger_DisplayList::UpdateIndexInfo()
{
ui->indexData->clear();
QTreeWidgetItem* item = ui->indexList->currentItem();
if(item == 0)
return;
GPUgstate state = drawGPUState[item->data(0,Qt::UserRole).toInt()];
u32 baseExtended = ((state.base & 0x0F0000) << 8) | (state.iaddr & 0xFFFFFF);
u32 iaddr = ((state.offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF;
int sizeIdx = 1;
if((state.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_16BIT)
sizeIdx = 2;
for(int i = 0; i < maxIdxDisplay; i++)
{
QTreeWidgetItem* itemTop = new QTreeWidgetItem();
itemTop->setText(0,QString::number(i));
itemTop->setText(1,QString("%1").arg(iaddr+i*sizeIdx,8,16,QChar('0')));
int idx = 0;
if(sizeIdx == 1)
idx = Memory::Read_U8(iaddr+i*sizeIdx);
else
idx = Memory::Read_U16(iaddr+i*sizeIdx);
itemTop->setText(2,QString::number(idx));
ui->indexData->addTopLevelItem(itemTop);
}
for(int i = 0; i < ui->indexData->columnCount(); i++)
{
ui->indexData->resizeColumnToContents(i);
}
}
void Debugger_DisplayList::on_nextIdx_clicked()
{
maxIdxDisplay += 20;
UpdateIndexInfo();
}
void Debugger_DisplayList::on_indexList_itemClicked(QTreeWidgetItem *item, int column)
{
UpdateIndexInfo();
}