Play-/Source/ui_qt/DebugSupport/FrameDebugger/GsContextView.cpp

297 lines
8.7 KiB
C++
Raw Normal View History

#include "GsContextView.h"
#include "GsStateUtils.h"
#include "gs/GsDebuggerInterface.h"
2019-06-04 22:56:44 -04:00
#include "gs/GsPixelFormats.h"
2021-01-11 23:13:52 +00:00
#include "../../../AppConfig.h"
2020-02-02 19:46:03 +00:00
#include <QVBoxLayout>
2016-08-27 12:47:37 +09:00
enum TAB_IDS
{
TAB_ID_FRAMEBUFFER,
TAB_ID_TEXTURE_BASE,
TAB_ID_TEXTURE_MIP1,
TAB_ID_TEXTURE_MIP2,
TAB_ID_TEXTURE_MIP3,
TAB_ID_TEXTURE_MIP4,
TAB_ID_TEXTURE_MIP5,
TAB_ID_TEXTURE_MIP6
};
2020-02-06 15:17:16 +00:00
CGsContextView::CGsContextView(QWidget* parent, QComboBox* contextBuffer, QPushButton* fitButton, QPushButton* saveButton, CGSHandler* gs, unsigned int contextId)
2020-02-02 19:46:03 +00:00
: QWidget(parent)
, m_contextId(contextId)
2018-04-30 21:01:23 +01:00
, m_gs(gs)
{
2020-02-02 19:46:03 +00:00
m_bufferView = std::make_unique<CPixelBufferView>(this, contextBuffer);
auto layout = new QVBoxLayout;
setLayout(layout);
layout->addWidget(m_bufferView.get());
2020-02-06 12:39:36 +00:00
connect(fitButton, &QPushButton::clicked, [&]() {
2020-02-02 19:46:03 +00:00
m_bufferView->FitBitmap();
2020-02-06 15:17:16 +00:00
});
2020-07-03 23:31:40 +01:00
connect(saveButton, &QPushButton::clicked, [&]() {
2020-02-06 15:17:16 +00:00
m_bufferView->OnSaveBitmap();
2020-02-02 19:46:03 +00:00
});
}
void CGsContextView::SetFbDisplayMode(FB_DISPLAY_MODE fbDisplayMode)
{
m_fbDisplayMode = fbDisplayMode;
UpdateBufferView();
}
void CGsContextView::UpdateState(CGSHandler* gs, CGsPacketMetadata*, DRAWINGKICK_INFO* drawingKick)
{
assert(gs == m_gs);
m_drawingKick = (*drawingKick);
UpdateBufferView();
2020-02-02 19:46:03 +00:00
}
void CGsContextView::SetSelection(int selected)
{
m_selected = selected;
UpdateBufferView();
}
void CGsContextView::UpdateBufferView()
{
2020-02-02 19:46:03 +00:00
uint32 selectedId = m_selected;
2016-08-27 12:47:37 +09:00
switch(selectedId)
{
2016-08-27 12:47:37 +09:00
case TAB_ID_FRAMEBUFFER:
2017-04-08 17:38:27 -04:00
UpdateFramebufferView();
2016-08-27 12:47:37 +09:00
break;
case TAB_ID_TEXTURE_BASE:
case TAB_ID_TEXTURE_MIP1:
case TAB_ID_TEXTURE_MIP2:
case TAB_ID_TEXTURE_MIP3:
case TAB_ID_TEXTURE_MIP4:
case TAB_ID_TEXTURE_MIP5:
case TAB_ID_TEXTURE_MIP6:
2018-04-30 21:01:23 +01:00
{
uint64 tex0Reg = m_gs->GetRegisters()[GS_REG_TEX0_1 + m_contextId];
uint64 tex1Reg = m_gs->GetRegisters()[GS_REG_TEX1_1 + m_contextId];
uint64 miptbp1Reg = m_gs->GetRegisters()[GS_REG_MIPTBP1_1 + m_contextId];
uint64 miptbp2Reg = m_gs->GetRegisters()[GS_REG_MIPTBP2_1 + m_contextId];
auto tex0 = make_convertible<CGSHandler::TEX0>(tex0Reg);
auto tex1 = make_convertible<CGSHandler::TEX1>(tex1Reg);
uint32 mipLevel = selectedId - TAB_ID_TEXTURE_BASE;
Framework::CBitmap texture, clutTexture, alphaTexture;
2018-04-30 21:01:23 +01:00
if(mipLevel <= tex1.nMaxMip)
2016-08-27 12:47:37 +09:00
{
if(auto debuggerInterface = dynamic_cast<CGsDebuggerInterface*>(m_gs))
{
texture = debuggerInterface->GetTexture(tex0Reg, tex1.nMaxMip, miptbp1Reg, miptbp2Reg, mipLevel);
}
2016-08-27 12:47:37 +09:00
}
2018-04-30 21:01:23 +01:00
if(!texture.IsEmpty() && CGsPixelFormats::IsPsmIDTEX(tex0.nPsm))
{
ColorArray convertedClut;
m_gs->MakeLinearCLUT(tex0, convertedClut);
clutTexture = LookupBitmap(texture, convertedClut);
if(tex0.nCPSM == CGSHandler::PSMCT32)
{
alphaTexture = ExtractAlpha32(clutTexture);
}
2018-04-30 21:01:23 +01:00
}
if(!texture.IsEmpty() && CGsPixelFormats::IsPsmIDTEX4(tex0.nPsm))
{
//Too hard to see if pixel brightness is not boosted
BrightenBitmap(texture);
}
if(!texture.IsEmpty() && tex0.nPsm == CGSHandler::PSMCT32)
{
alphaTexture = ExtractAlpha32(texture);
}
2018-04-30 21:01:23 +01:00
CPixelBufferView::PixelBufferArray pixelBuffers;
pixelBuffers.emplace_back("Raw", std::move(texture));
if(!clutTexture.IsEmpty())
{
pixelBuffers.emplace_back("+ CLUT", std::move(clutTexture));
}
if(!alphaTexture.IsEmpty())
{
pixelBuffers.emplace_back("Alpha", std::move(alphaTexture));
}
2018-04-30 21:01:23 +01:00
m_bufferView->SetPixelBuffers(std::move(pixelBuffers));
}
break;
}
2020-02-02 19:46:03 +00:00
m_bufferView->repaint();
}
2017-04-08 17:38:27 -04:00
void CGsContextView::UpdateFramebufferView()
{
uint64 frameReg = m_gs->GetRegisters()[GS_REG_FRAME_1 + m_contextId];
auto frame = make_convertible<CGSHandler::FRAME>(frameReg);
Framework::CBitmap framebuffer;
if(auto debuggerInterface = dynamic_cast<CGsDebuggerInterface*>(m_gs))
{
framebuffer = debuggerInterface->GetFramebuffer(frame);
}
2017-04-08 17:38:27 -04:00
if(framebuffer.IsEmpty())
{
m_bufferView->SetPixelBuffers(CPixelBufferView::PixelBufferArray());
return;
}
2021-01-11 23:19:07 +00:00
auto scale = CAppConfig::GetInstance().GetPreferenceInteger(PREF_CGSH_OPENGL_RESOLUTION_FACTOR);
2017-04-08 17:38:27 -04:00
//Clip framebuffer
if(m_fbDisplayMode == FB_DISPLAY_MODE_448P)
{
2021-01-11 23:19:07 +00:00
framebuffer = framebuffer.ResizeCanvas(640 * scale, 448 * scale);
2017-04-08 17:38:27 -04:00
}
else if(m_fbDisplayMode == FB_DISPLAY_MODE_448I)
{
2021-01-11 23:19:07 +00:00
framebuffer = framebuffer.ResizeCanvas(640 * scale, 224 * scale);
2017-04-08 17:38:27 -04:00
}
Framework::CBitmap alphaFramebuffer;
if(frame.nPsm == CGSHandler::PSMCT32)
{
assert(framebuffer.GetBitsPerPixel() == 32);
alphaFramebuffer = ExtractAlpha32(framebuffer);
}
auto postProcessFramebuffer =
2021-01-11 23:19:07 +00:00
[this, scale](Framework::CBitmap src) {
2018-04-30 21:01:23 +01:00
if(!src.IsEmpty())
{
RenderDrawKick(src);
if(m_fbDisplayMode == FB_DISPLAY_MODE_448I)
{
2021-01-11 23:19:07 +00:00
src = src.Resize(640 * scale, 448 * scale);
2018-04-30 21:01:23 +01:00
}
}
return src;
};
2017-04-08 17:38:27 -04:00
framebuffer = postProcessFramebuffer(std::move(framebuffer));
alphaFramebuffer = postProcessFramebuffer(std::move(alphaFramebuffer));
CPixelBufferView::PixelBufferArray pixelBuffers;
pixelBuffers.emplace_back("Raw", std::move(framebuffer));
if(!alphaFramebuffer.IsEmpty())
{
pixelBuffers.emplace_back("Alpha", std::move(alphaFramebuffer));
}
m_bufferView->SetPixelBuffers(std::move(pixelBuffers));
}
void CGsContextView::RenderDrawKick(Framework::CBitmap& bitmap)
{
if(m_drawingKick.primType == CGSHandler::PRIM_INVALID) return;
if(m_drawingKick.context != m_contextId) return;
auto primHighlightColor = Framework::CColor(0, 0xFF, 0, 0xFF);
2021-01-11 23:13:52 +00:00
int scale = CAppConfig::GetInstance().GetPreferenceInteger(PREF_CGSH_OPENGL_RESOLUTION_FACTOR);
switch(m_drawingKick.primType)
{
case CGSHandler::PRIM_TRIANGLE:
case CGSHandler::PRIM_TRIANGLESTRIP:
case CGSHandler::PRIM_TRIANGLEFAN:
2018-04-30 21:01:23 +01:00
{
2021-01-11 23:13:52 +00:00
int x1 = (static_cast<int16>(m_drawingKick.vertex[0].x) / 16) * scale;
int y1 = (static_cast<int16>(m_drawingKick.vertex[0].y) / 16) * scale;
int x2 = (static_cast<int16>(m_drawingKick.vertex[1].x) / 16) * scale;
int y2 = (static_cast<int16>(m_drawingKick.vertex[1].y) / 16) * scale;
int x3 = (static_cast<int16>(m_drawingKick.vertex[2].x) / 16) * scale;
int y3 = (static_cast<int16>(m_drawingKick.vertex[2].y) / 16) * scale;
2018-04-30 21:01:23 +01:00
bitmap.DrawLine(x1, y1, x2, y2, primHighlightColor);
bitmap.DrawLine(x1, y1, x3, y3, primHighlightColor);
bitmap.DrawLine(x2, y2, x3, y3, primHighlightColor);
}
break;
case CGSHandler::PRIM_SPRITE:
2018-04-30 21:01:23 +01:00
{
2021-01-11 23:13:52 +00:00
int x1 = (static_cast<int16>(m_drawingKick.vertex[0].x) / 16) * scale;
int y1 = (static_cast<int16>(m_drawingKick.vertex[0].y) / 16) * scale;
int x2 = (static_cast<int16>(m_drawingKick.vertex[1].x) / 16) * scale;
int y2 = (static_cast<int16>(m_drawingKick.vertex[1].y) / 16) * scale;
2018-04-30 21:01:23 +01:00
bitmap.DrawLine(x1, y1, x1, y2, primHighlightColor);
bitmap.DrawLine(x1, y2, x2, y2, primHighlightColor);
bitmap.DrawLine(x2, y2, x2, y1, primHighlightColor);
bitmap.DrawLine(x2, y1, x1, y1, primHighlightColor);
}
break;
}
}
2016-10-17 20:01:03 -04:00
void CGsContextView::BrightenBitmap(Framework::CBitmap& bitmap)
{
assert(!bitmap.IsEmpty());
assert(bitmap.GetBitsPerPixel() == 8);
auto pixels = reinterpret_cast<uint8*>(bitmap.GetPixels());
for(uint32 y = 0; y < bitmap.GetHeight(); y++)
{
for(uint32 x = 0; x < bitmap.GetWidth(); x++)
{
pixels[x] <<= 4;
}
pixels += bitmap.GetPitch();
}
}
2020-01-26 12:12:50 +00:00
uint32 CGsContextView::Color_Ps2ToRGBA(uint32 color)
{
uint8 r = (color & 0xFF);
uint8 b = (color & 0xFF00) >> 8;
uint8 g = (color & 0xFF0000) >> 16;
uint8 a = (color & 0xFF000000) >> 24;
return g << 0 | b << 8 | r << 16 | a << 24;
}
2016-10-31 10:42:31 -04:00
Framework::CBitmap CGsContextView::LookupBitmap(const Framework::CBitmap& srcBitmap, const ColorArray& clut)
{
assert(!srcBitmap.IsEmpty());
assert(srcBitmap.GetBitsPerPixel() == 8);
auto dstBitmap = Framework::CBitmap(srcBitmap.GetWidth(), srcBitmap.GetHeight(), 32);
auto srcPixels = reinterpret_cast<uint8*>(srcBitmap.GetPixels());
auto dstPixels = reinterpret_cast<uint32*>(dstBitmap.GetPixels());
for(uint32 y = 0; y < srcBitmap.GetHeight(); y++)
{
for(uint32 x = 0; x < srcBitmap.GetWidth(); x++)
{
uint8 index = srcPixels[x];
uint32 color = clut[index];
2020-01-26 12:12:50 +00:00
uint32 newColor = Color_Ps2ToRGBA(color);
2016-10-31 10:42:31 -04:00
dstPixels[x] = newColor;
}
srcPixels += srcBitmap.GetPitch();
dstPixels += dstBitmap.GetPitch() / 4;
}
return std::move(dstBitmap);
}
2017-04-08 17:38:27 -04:00
Framework::CBitmap CGsContextView::ExtractAlpha32(const Framework::CBitmap& srcBitmap)
{
assert(!srcBitmap.IsEmpty());
assert(srcBitmap.GetBitsPerPixel() == 32);
auto dstBitmap = Framework::CBitmap(srcBitmap.GetWidth(), srcBitmap.GetHeight(), 32);
auto srcPixels = reinterpret_cast<uint32*>(srcBitmap.GetPixels());
auto dstPixels = reinterpret_cast<uint32*>(dstBitmap.GetPixels());
for(uint32 y = 0; y < srcBitmap.GetHeight(); y++)
{
for(uint32 x = 0; x < srcBitmap.GetWidth(); x++)
{
uint32 color = srcPixels[x];
uint32 alpha = color >> 24;
dstPixels[x] = (alpha) | (alpha << 8) | (alpha << 16) | 0xFF000000;
}
srcPixels += srcBitmap.GetPitch() / 4;
dstPixels += dstBitmap.GetPitch() / 4;
}
return std::move(dstBitmap);
}