GS/HW: Add option for dumping HW config data.

Dumps HW config per draw.

Helps debugging/optimizing HW pipeline changes.
This commit is contained in:
TJnotJT
2026-02-18 22:25:54 +01:00
committed by lightningterror
parent 62c40f1f01
commit 24090772cd
8 changed files with 521 additions and 8 deletions
+4 -2
View File
@@ -436,8 +436,8 @@ static void PrintCommandLineHelp(const char* progname)
std::fprintf(stderr, " -help: Displays this information and exits.\n");
std::fprintf(stderr, " -version: Displays version information and exits.\n");
std::fprintf(stderr, " -dumpdir <dir>: Frame dump directory (will be dumped as filename_frameN.png).\n");
std::fprintf(stderr, " -dump [rt|tex|z|f|a|i|tr|ds|fs]: Enabling dumping of render target, texture, z buffer, frame, "
"alphas, and info (context, vertices, list of transfers), transfers images, draw stats, frame stats, respectively, per draw. Generates lots of data.\n");
std::fprintf(stderr, " -dump [rt|tex|z|f|a|i|tr|ds|fs|hw]: Enabling dumping of render target, texture, z buffer, frame, "
"alphas, and info (context, vertices, list of transfers), transfers images, draw stats, frame stats, HW config, respectively, per draw. Generates lots of data.\n");
std::fprintf(stderr, " -dumprange N[,L,B]: Start dumping from draw N (base 0), stops after L draws, and only "
"those draws that are multiples of B (intersection of -dumprange and -dumprangef used)."
"Defaults to 0,-1,1 (all draws). Only used if -dump used.\n");
@@ -527,6 +527,8 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveDrawStats", true);
if (str.find("fs") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveFrameStats", true);
if (str.find("hw") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveHWConfig", true);
continue;
}
else if (CHECK_ARG_PARAM("-dumprange"))
+7
View File
@@ -92,6 +92,13 @@
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="saveHWConfig">
<property name="text">
<string>Save HW Config</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
@@ -112,6 +112,7 @@ DebugSettingsWidget::DebugSettingsWidget(SettingsWindow* settings_dialog, QWidge
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_gs.saveTransferImages, "EmuCore/GS", "SaveTransferImages", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_gs.saveDrawStats, "EmuCore/GS", "SaveDrawStats", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_gs.saveFrameStats, "EmuCore/GS", "SaveFrameStats", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_gs.saveHWConfig, "EmuCore/GS", "SaveHWConfig", false);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_gs.saveDrawStart, "EmuCore/GS", "SaveDrawStart", 0);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_gs.saveDrawCount, "EmuCore/GS", "SaveDrawCount", 5000);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_gs.saveFrameStart, "EmuCore/GS", "SaveFrameStart", 0);
@@ -219,6 +220,7 @@ void DebugSettingsWidget::onDrawDumpingChanged()
m_gs.saveTransferImages->setEnabled(enabled);
m_gs.saveDrawStats->setEnabled(enabled);
m_gs.saveFrameStats->setEnabled(enabled);
m_gs.saveHWConfig->setEnabled(enabled);
m_gs.saveDrawStart->setEnabled(enabled);
m_gs.saveDrawCount->setEnabled(enabled);
m_gs.saveFrameStart->setEnabled(enabled);
+1
View File
@@ -788,6 +788,7 @@ struct Pcsx2Config
SaveTransferImages : 1,
SaveDrawStats : 1,
SaveFrameStats : 1,
SaveHWConfig : 1,
DumpReplaceableTextures : 1,
DumpReplaceableMipmaps : 1,
DumpTexturesWithFMVActive : 1,
+454
View File
@@ -4,6 +4,7 @@
#include "GS/Renderers/Common/GSDevice.h"
#include "GS/GSGL.h"
#include "GS/GS.h"
#include "GS/GSUtil.h"
#include "Host.h"
#include "common/Console.h"
@@ -18,6 +19,8 @@
#include "imgui.h"
#include <algorithm>
#include <ostream>
#include <fstream>
int SetDATMShader(SetDATM datm)
{
@@ -1054,6 +1057,457 @@ bool GSHWDrawConfig::BlendState::IsEffective(ColorMaskSelector colormask) const
((colormask.key & 8u) && (src_factor_alpha != GSDevice::CONST_ONE || dst_factor_alpha != GSDevice::CONST_ZERO)));
}
std::string GSHWDrawConfig::GetTopologyName(u32 topology)
{
switch (static_cast<GSHWDrawConfig::Topology>(topology))
{
case GSHWDrawConfig::Topology::Point: return "Point";
case GSHWDrawConfig::Topology::Line: return "Line";
case GSHWDrawConfig::Topology::Triangle: return "Triangle";
default: return std::to_string(topology);
}
}
std::string GSHWDrawConfig::GetVSExpandName(u32 vsexpand)
{
switch (static_cast<GSHWDrawConfig::VSExpand>(vsexpand))
{
case GSHWDrawConfig::VSExpand::None: return "None";
case GSHWDrawConfig::VSExpand::Point: return "Point";
case GSHWDrawConfig::VSExpand::Line: return "Line";
case GSHWDrawConfig::VSExpand::Sprite: return "Sprite";
default: return std::to_string(vsexpand);
}
}
std::string GSHWDrawConfig::GetPSDateName(u32 date)
{
switch (date)
{
case 0: return "None";
case 1: return "0_pass_PrimID_init";
case 2: return "1_pass_PrimID_init";
case 3: return "PrimID_main";
case 5: return "0_pass_main";
case 6: return "1_pass_main";
default: return std::to_string(date);
}
}
std::string GSHWDrawConfig::GetPSAlphaTestName(u32 atst)
{
switch (static_cast<GSHWDrawConfig::PSAlphaTest>(atst))
{
case GSHWDrawConfig::PSAlphaTest::PS_ATST_NONE: return "NONE";
case GSHWDrawConfig::PSAlphaTest::PS_ATST_LEQUAL: return "LEQUAL";
case GSHWDrawConfig::PSAlphaTest::PS_ATST_GEQUAL: return "GEQUAL";
case GSHWDrawConfig::PSAlphaTest::PS_ATST_EQUAL: return "EQUAL";
case GSHWDrawConfig::PSAlphaTest::PS_ATST_NOTEQUAL: return "NOTEQUAL";
default: return std::to_string(atst);
};
}
std::string GSHWDrawConfig::GetPSDstFmtName(u32 dstfmt)
{
switch (dstfmt)
{
case 0: return "32bit";
case 1: return "24bit";
case 2: return "16bit";
default: return std::to_string(dstfmt);
}
}
std::string GSHWDrawConfig::GetPSDepthFmtName(u32 depthfmt)
{
switch (depthfmt)
{
case 0: return "None";
case 1: return "32bit";
case 2: return "16bit";
case 3: return "RGBA";
default: return std::to_string(depthfmt);
}
}
std::string GSHWDrawConfig::GetPSBlendABDName(u32 abd)
{
switch (abd)
{
case 0: return "Cs";
case 1: return "Cd";
case 2: return "Zero";
default: return std::to_string(abd);
}
}
std::string GSHWDrawConfig::GetPSBlendCName(u32 c)
{
switch (c)
{
case 0: return "As";
case 1: return "Ad";
case 2: return "Af";
default: return std::to_string(c);
}
}
std::string GSHWDrawConfig::GetPSBlendHWName(u32 blendhw)
{
switch (static_cast<HWBlendType>(blendhw))
{
case HWBlendType::SRC_ONE_DST_FACTOR: return "SRC_ONE_DST_FACTOR";
case HWBlendType::SRC_ALPHA_DST_FACTOR: return "SRC_ALPHA_DST_FACTOR";
case HWBlendType::SRC_DOUBLE: return "SRC_DOUBLE";
case HWBlendType::SRC_HALF_ONE_DST_FACTOR: return "SRC_HALF_ONE_DST_FACTOR";
case HWBlendType::SRC_INV_DST_BLEND_HALF: return "SRC_INV_DST_BLEND_HALF";
case HWBlendType::INV_SRC_DST_BLEND_HALF: return "INV_SRC_DST_BLEND_HALF";
default: return std::to_string(blendhw);
}
}
std::string GSHWDrawConfig::GetPSBlendMixName(u32 blendmix)
{
switch (static_cast<HWBlendType>(blendmix))
{
case HWBlendType::BMIX1_ALPHA_HIGH_ONE: return "BMIX1_ALPHA_HIGH_ONE";
case HWBlendType::BMIX1_SRC_HALF: return "BMIX1_SRC_HALF";
case HWBlendType::BMIX2_OVERFLOW: return "BMIX2_OVERFLOW";
default: return std::to_string(blendmix);
}
}
std::string GSHWDrawConfig::GetPSChannelName(u32 channel)
{
switch (channel)
{
case 0: return "None";
case 1: return "FetchRed";
case 2: return "FetchGreen";
case 3: return "FetchBlue";
case 4: return "FetchAlpha";
case 5: return "FetchRGB";
case 6: return "FetchGXBY";
default: return std::to_string(channel);
}
}
std::string GSHWDrawConfig::GetPSDitherName(u32 dither)
{
switch (dither)
{
case 0: return "None";
case 1: return "Standard";
case 2: return "ReciprocalScaled";
default: return std::to_string(dither);
}
}
std::string GSHWDrawConfig::GetSSTrilnName(u32 triln)
{
switch (static_cast<GS_MIN_FILTER>(triln))
{
case GS_MIN_FILTER::Nearest: return "Nearest";
case GS_MIN_FILTER::Linear: return "Linear";
case GS_MIN_FILTER::Nearest_Mipmap_Nearest: return "Nearest_Mipmap_Nearest";
case GS_MIN_FILTER::Nearest_Mipmap_Linear: return "Nearest_Mipmap_Linear";
case GS_MIN_FILTER::Linear_Mipmap_Nearest: return "Linear_Mipmap_Nearest";
case GS_MIN_FILTER::Linear_Mipmap_Linear: return "Linear_Mipmap_Linear";
default: return std::to_string(triln);
}
}
std::string GSHWDrawConfig::GetBlendOpName(u32 blendop)
{
switch (blendop)
{
case 0: return "ADD";
case 1: return "SUBTRACT";
case 2: return "REVERSE_SUBTRACT";
default: return std::to_string(blendop);
}
}
std::string GSHWDrawConfig::GetBlendFactorName(u32 blendfactor)
{
switch (blendfactor)
{
case 0: return "SRC_COLOR";
case 1: return "ONE_MINUS_SRC_COLOR";
case 2: return "DST_COLOR";
case 3: return "ONE_MINUS_DST_COLOR";
case 4: return "SRC1_COLOR";
case 5: return "ONE_MINUS_SRC1_COLOR";
case 6: return "SRC_ALPHA";
case 7: return "ONE_MINUS_SRC_ALPHA";
case 8: return "DST_ALPHA";
case 9: return "ONE_MINUS_DST_ALPHA";
case 10: return "SRC1_ALPHA";
case 11: return "ONE_MINUS_SRC1_ALPHA";
case 12: return "CONSTANT_COLOR";
case 13: return "ONE_MINUS_CONSTANT_COLOR";
case 14: return "ONE";
case 15: return "ZERO";
default: return std::to_string(blendfactor);
}
}
std::string GSHWDrawConfig::GetDestinationAlphaModeName(u32 datm)
{
switch (static_cast<GSHWDrawConfig::DestinationAlphaMode>(datm))
{
case GSHWDrawConfig::DestinationAlphaMode::Off: return "Off";
case GSHWDrawConfig::DestinationAlphaMode::Stencil: return "Stencil";
case GSHWDrawConfig::DestinationAlphaMode::StencilOne: return "StencilOne";
case GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking: return "PrimIDTracking";
case GSHWDrawConfig::DestinationAlphaMode::Full: return "Full";
default: return std::to_string(datm);
}
}
std::string GSHWDrawConfig::GetColClipModeName(u32 ccmode)
{
switch (static_cast<GSHWDrawConfig::ColClipMode>(ccmode))
{
case GSHWDrawConfig::ColClipMode::NoModify: return "NoModify";
case GSHWDrawConfig::ColClipMode::ConvertOnly: return "ConvertOnly";
case GSHWDrawConfig::ColClipMode::ResolveOnly: return "ResolveOnly";
case GSHWDrawConfig::ColClipMode::ConvertAndResolve: return "ConvertAndResolve";
case GSHWDrawConfig::ColClipMode::EarlyResolve: return "EarlyResolve";
default: return std::to_string(ccmode);
}
}
std::string GSHWDrawConfig::GetSetDATMName(u32 datm)
{
switch (static_cast<SetDATM>(datm))
{
case SetDATM::DATM0: return "DATM0";
case SetDATM::DATM1: return "DATM1";
case SetDATM::DATM0_RTA_CORRECTION: return "DATM0_RTA_CORRECTION";
case SetDATM::DATM1_RTA_CORRECTION: return "DATM1_RTA_CORRECTION";
default: return std::to_string(datm);
};
}
static constexpr const char* INDENT = " ";
void GSHWDrawConfig::DumpPSSelector(std::ostream& out, const PSSelector& ps, const std::string& indent)
{
out.imbue(std::locale::classic()); // Disable integer separators
out << std::dec;
out << indent << "aem_fmt: " << static_cast<u32>(ps.aem_fmt) << std::endl;
out << indent << "pal_fmt: " << static_cast<u32>(ps.pal_fmt) << std::endl;
out << indent << "dst_fmt: " << static_cast<u32>(ps.dst_fmt) << " # " << GetPSDstFmtName(static_cast<u32>(ps.dst_fmt)) << std::endl;
out << indent << "depth_fmt: " << static_cast<u32>(ps.depth_fmt) << " # " << GetPSDepthFmtName(static_cast<u32>(ps.depth_fmt)) << std::endl;
out << indent << "aem: " << static_cast<u32>(ps.aem) << std::endl;
out << indent << "fba: " << static_cast<u32>(ps.fba) << std::endl;
out << indent << "fog: " << static_cast<u32>(ps.fog) << std::endl;
out << indent << "iip: " << static_cast<u32>(ps.iip) << std::endl;
out << indent << "date: " << static_cast<u32>(ps.date) << " # " << GetPSDateName(static_cast<u32>(ps.date)) << std::endl;
out << indent << "atst: " << static_cast<u32>(ps.atst) << " # " << GetPSAlphaTestName(static_cast<u32>(ps.atst)) << std::endl;
out << indent << "afail: " << static_cast<u32>(ps.afail) << " # " << GSUtil::GetAFAILName(static_cast<u32>(ps.afail)) << std::endl;
out << indent << "fst: " << static_cast<u32>(ps.fst) << std::endl;
out << indent << "tfx: " << static_cast<u32>(ps.tfx) << std::endl;
out << indent << "tcc: " << GSUtil::GetTCCName(static_cast<u32>(ps.tcc)) << std::endl;
out << indent << "wms: " << static_cast<u32>(ps.tcc) << " # " << static_cast<u32>(ps.wms) << std::endl;
out << indent << "wmt: " << static_cast<u32>(ps.wmt) << std::endl;
out << indent << "adjs: " << static_cast<u32>(ps.adjs) << std::endl;
out << indent << "adjt: " << static_cast<u32>(ps.adjt) << std::endl;
out << indent << "ltf: " << static_cast<u32>(ps.ltf) << std::endl;
out << indent << "shuffle: " << static_cast<u32>(ps.shuffle) << std::endl;
out << indent << "shuffle_same: " << static_cast<u32>(ps.shuffle_same) << std::endl;
out << indent << "real16src: " << static_cast<u32>(ps.real16src) << std::endl;
out << indent << "process_ba: " << static_cast<u32>(ps.process_ba) << std::endl;
out << indent << "process_rg: " << static_cast<u32>(ps.process_rg) << std::endl;
out << indent << "shuffle_across: " << static_cast<u32>(ps.shuffle_across) << std::endl;
out << indent << "write_rg: " << static_cast<u32>(ps.write_rg) << std::endl;
out << indent << "fbmask: " << static_cast<u32>(ps.fbmask) << std::endl;
out << indent << "blend_a: " << static_cast<u32>(ps.blend_a) << " # " << GetPSBlendABDName(static_cast<u32>(ps.blend_a)) << std::endl;
out << indent << "blend_b: " << static_cast<u32>(ps.blend_b) << " # " << GetPSBlendABDName(static_cast<u32>(ps.blend_b)) << std::endl;
out << indent << "blend_c: " << static_cast<u32>(ps.blend_c) << " # " << GetPSBlendCName(static_cast<u32>(ps.blend_c)) << std::endl;
out << indent << "blend_d: " << static_cast<u32>(ps.blend_d) << " # " << GetPSBlendABDName(static_cast<u32>(ps.blend_d)) << std::endl;
out << indent << "fixed_one_a: " << static_cast<u32>(ps.fixed_one_a) << std::endl;
out << indent << "blend_hw: " << static_cast<u32>(ps.blend_hw) << " # " << GetPSBlendHWName(static_cast<u32>(ps.blend_hw)) << std::endl;
out << indent << "a_masked: " << static_cast<u32>(ps.a_masked) << std::endl;
out << indent << "colclip_hw: " << static_cast<u32>(ps.colclip_hw) << std::endl;
out << indent << "rta_correction: " << static_cast<u32>(ps.rta_correction) << std::endl;
out << indent << "rta_source_correction: " << static_cast<u32>(ps.rta_source_correction) << std::endl;
out << indent << "colclip: " << static_cast<u32>(ps.colclip) << std::endl;
out << indent << "blend_mix: " << static_cast<u32>(ps.blend_mix) << " # " << GetPSBlendMixName(static_cast<u32>(ps.blend_mix)) << std::endl;
out << indent << "round_inv: " << static_cast<u32>(ps.round_inv) << std::endl;
out << indent << "pabe: " << static_cast<u32>(ps.pabe) << std::endl;
out << indent << "no_color: " << static_cast<u32>(ps.no_color) << std::endl;
out << indent << "no_color1: " << static_cast<u32>(ps.no_color1) << std::endl;
out << indent << "channel: " << static_cast<u32>(ps.channel) << " # " << GetPSChannelName(static_cast<u32>(ps.channel)) << std::endl;
out << indent << "channel_fb: " << static_cast<u32>(ps.channel_fb) << std::endl;
out << indent << "dither: " << static_cast<u32>(ps.dither) << " # " << GetPSDitherName(static_cast<u32>(ps.dither)) << std::endl;
out << indent << "dither_adjust: " << static_cast<u32>(ps.dither_adjust) << std::endl;
out << indent << "zclamp: " << static_cast<u32>(ps.zclamp) << std::endl;
out << indent << "tcoffsethack: " << static_cast<u32>(ps.tcoffsethack) << std::endl;
out << indent << "urban_chaos_hle: " << static_cast<u32>(ps.urban_chaos_hle) << std::endl;
out << indent << "tales_of_abyss_hle: " << static_cast<u32>(ps.tales_of_abyss_hle) << std::endl;
out << indent << "tex_is_fb: " << static_cast<u32>(ps.tex_is_fb) << std::endl;
out << indent << "automatic_lod: " << static_cast<u32>(ps.automatic_lod) << std::endl;
out << indent << "manual_lod: " << static_cast<u32>(ps.manual_lod) << std::endl;
out << indent << "point_sampler: " << static_cast<u32>(ps.point_sampler) << std::endl;
out << indent << "region_rect: " << static_cast<u32>(ps.region_rect) << std::endl;
out << indent << "scanmsk: " << static_cast<u32>(ps.scanmsk) << " # " << GSUtil::GetSCANMSKName(static_cast<u32>(ps.scanmsk)) << std::endl;
}
void GSHWDrawConfig::DumpVSSelector(std::ostream& out, const VSSelector& vs, const std::string& indent)
{
out.imbue(std::locale::classic()); // Disable integer separators
out << std::dec;
out << indent << "fst: " << static_cast<u32>(vs.fst) << std::endl;
out << indent << "tme: " << static_cast<u32>(vs.tme) << std::endl;
out << indent << "iip: " << static_cast<u32>(vs.iip) << std::endl;
out << indent << "point_size: " << static_cast<u32>(vs.point_size) << std::endl;
out << indent << "expand: " << static_cast<u32>(vs.expand) << " # " << GetVSExpandName(static_cast<u32>(vs.expand)) << std::endl;
}
void GSHWDrawConfig::DumpBlendState(std::ostream& out, const BlendState& bs, const std::string& indent)
{
out.imbue(std::locale::classic()); // Disable integer separators
out << std::dec;
out << indent << "enable: " << static_cast<u32>(bs.enable) << std::endl;
out << indent << "constant_enable: " << static_cast<u32>(bs.constant_enable) << std::endl;
out << indent << "op: " << static_cast<u32>(bs.op) << " # " << GetBlendOpName(static_cast<u32>(bs.op)) << std::endl;
out << indent << "src_factor: " << static_cast<u32>(bs.src_factor) << " # " << GetBlendFactorName(static_cast<u32>(bs.src_factor)) << std::endl;
out << indent << "dst_factor: " << static_cast<u32>(bs.dst_factor) << " # " << GetBlendFactorName(static_cast<u32>(bs.dst_factor)) << std::endl;
out << indent << "src_factor_alpha: " << static_cast<u32>(bs.src_factor_alpha) << " # " << GetBlendFactorName(static_cast<u32>(bs.src_factor_alpha)) << std::endl;
out << indent << "dst_factor_alpha: " << static_cast<u32>(bs.dst_factor_alpha) << " # " << GetBlendFactorName(static_cast<u32>(bs.dst_factor_alpha)) << std::endl;
out << indent << "constant: " << static_cast<u32>(bs.constant) << std::endl;
}
void GSHWDrawConfig::DumpDepthStencilSelctor(std::ostream& out, const DepthStencilSelector& dss, const std::string& indent)
{
out.imbue(std::locale::classic()); // Disable integer separators
out << std::dec;
out << indent << "ztst: " << static_cast<u32>(dss.ztst) << " # " << GSUtil::GetZTSTName(static_cast<u32>(dss.ztst)) << std::endl;
out << indent << "zwe: " << static_cast<u32>(dss.zwe) << std::endl;
out << indent << "date: " << static_cast<u32>(dss.date) << std::endl;
out << indent << "date_one: " << static_cast<u32>(dss.date_one) << std::endl;
}
void GSHWDrawConfig::DumpSamplerSelector(std::ostream& out, const SamplerSelector& ss, const std::string& indent)
{
out.imbue(std::locale::classic()); // Disable integer separators
out << std::dec;
out << indent << "tau: " << static_cast<u32>(ss.tau) << std::endl;
out << indent << "tav: " << static_cast<u32>(ss.tav) << std::endl;
out << indent << "biln: " << static_cast<u32>(ss.biln) << std::endl;
out << indent << "triln: " << static_cast<u32>(ss.triln) << " # " << GetSSTrilnName(static_cast<u32>(ss.triln)) << std::endl;
out << indent << "aniso: " << static_cast<u32>(ss.aniso) << std::endl;
out << indent << "lodclamp: " << static_cast<u32>(ss.lodclamp) << std::endl;
}
void GSHWDrawConfig::DumpAlphaPass(std::ostream& out, const AlphaPass& ap, const std::string& indent)
{
out.imbue(std::locale::classic()); // Disable integer separators
out << std::dec;
out << indent << "enable: " << static_cast<u32>(ap.enable) << std::endl;
out << indent << "require_one_barrier: " << static_cast<u32>(ap.require_one_barrier) << std::endl;
out << indent << "require_full_barrier: " << static_cast<u32>(ap.require_full_barrier) << std::endl;
out << indent << "colormask: " << std::showbase << std::hex << static_cast<u32>(ap.colormask.wrgba) << std::dec << std::endl;
out << indent << "ps_aref: " << static_cast<u32>(ap.ps_aref) << std::endl;
out << indent << "ps:" << std::endl;
DumpPSSelector(out, ap.ps, indent + INDENT);
out << indent << "dss:" << std::endl;
DumpDepthStencilSelctor(out, ap.depth, indent + INDENT);
}
void GSHWDrawConfig::DumpBlendMultipass(std::ostream& out, const BlendMultiPass& bmp, const std::string& indent)
{
out.imbue(std::locale::classic()); // Disable integer separators
out << std::dec;
out << indent << "enable: " << static_cast<u32>(bmp.enable) << std::endl;
out << indent << "no_color1: " << static_cast<u32>(bmp.no_color1) << std::endl;
out << indent << "blend_hw: " << static_cast<u32>(bmp.blend_hw) << " # " << GetPSBlendHWName(static_cast<u32>(bmp.blend_hw)) << std::endl;
out << indent << "dither: " << static_cast<u32>(bmp.dither) << std::endl;
out << indent << "blend:" << std::endl;
DumpBlendState(out, bmp.blend, indent + INDENT);
}
void GSHWDrawConfig::DumpConfig(std::ostream& out, const GSHWDrawConfig& conf,
bool ps, bool vs, bool bs, bool dss, bool ss, bool asp, bool bmp)
{
out.imbue(std::locale::classic()); // Disable integer separators
out << std::dec;
out << "topology: " << static_cast<u32>(conf.topology) << " # " << GetTopologyName(static_cast<u32>(conf.topology)) << std::endl;
out << "require_one_barrier: " << static_cast<u32>(conf.require_one_barrier) << std::endl;
out << "require_full_barrier: " << static_cast<u32>(conf.require_full_barrier) << std::endl;
out << "destination_alpha: " << static_cast<u32>(conf.destination_alpha) << " # " << GetDestinationAlphaModeName(static_cast<u32>(conf.destination_alpha)) << std::endl;
out << "datm: " << static_cast<u32>(conf.datm) << " # " << GetSetDATMName(static_cast<u32>(conf.datm)) << std::endl;
out << "line_expand: " << conf.line_expand << std::endl;
out << "colormask: " << std::hex << std::showbase << static_cast<u32>(conf.colormask.wrgba) << std::dec << std::endl;
if (ps)
{
out << "ps:" << std::endl;
DumpPSSelector(out, conf.ps, INDENT);
}
if (vs)
{
out << "vs:" << std::endl;
DumpVSSelector(out, conf.vs, INDENT);
}
if (bs)
{
out << "blend:" << std::endl;
DumpBlendState(out, conf.blend, INDENT);
}
if (ss)
{
out << "sampler:" << std::endl;
DumpSamplerSelector(out, conf.sampler, INDENT);
}
if (dss)
{
out << "depth:" << std::endl;
DumpDepthStencilSelctor(out, conf.depth, INDENT);
}
if (asp)
{
out << "alpha_second_pass:" << std::endl;
DumpAlphaPass(out, conf.alpha_second_pass, INDENT);
}
if (bmp)
{
out << "blend_multi_pass:" << std::endl;
DumpBlendMultipass(out, conf.blend_multi_pass, INDENT);
}
}
void GSHWDrawConfig::DumpConfig(const std::string& fn, const GSHWDrawConfig& conf,
bool ps, bool vs, bool bs, bool dss, bool ss, bool asp, bool bmp)
{
std::ofstream file(fn);
if (!file.is_open())
return;
DumpConfig(file, conf, ps, vs, bs, dss, ss, asp, bmp);
}
// clang-format off
// Maps PS2 blend modes to our best approximation of them with PC hardware
+41
View File
@@ -328,6 +328,16 @@ struct alignas(16) GSHWDrawConfig
};
static_assert(sizeof(VSSelector) == 1, "VSSelector is a single byte");
#pragma pack(pop)
enum PSAlphaTest
{
PS_ATST_NONE = 0,
PS_ATST_LEQUAL = 1,
PS_ATST_GEQUAL = 2,
PS_ATST_EQUAL = 3,
PS_ATST_NOTEQUAL = 4
};
#pragma pack(push, 4)
struct PSSelector
{
@@ -780,6 +790,37 @@ struct alignas(16) GSHWDrawConfig
ColClipMode colclip_mode;
GIFRegFRAME colclip_frame;
GSVector4i colclip_update_area; ///< Area in the framebuffer which colclip will modify;
// Dumping
static std::string GetTopologyName(u32 topology);
static std::string GetVSExpandName(u32 vsexpand);
static std::string GetPSAlphaTestName(u32 dstfmt);
static std::string GetPSDstFmtName(u32 dstfmt);
static std::string GetPSDepthFmtName(u32 depthfmt);
static std::string GetPSBlendABDName(u32 abd);
static std::string GetPSBlendCName(u32 c);
static std::string GetPSBlendHWName(u32 blendhw);
static std::string GetPSBlendMixName(u32 blendmix);
static std::string GetPSDitherName(u32 dither);
static std::string GetPSChannelName(u32 channel);
static std::string GetSSTrilnName(u32 triln);
static std::string GetBlendOpName(u32 blendop);
static std::string GetBlendFactorName(u32 blendfactor);
static std::string GetDestinationAlphaModeName(u32 datm);
static std::string GetPSDateName(u32 date);
static std::string GetColClipModeName(u32 ccmode);
static std::string GetSetDATMName(u32 setdatm);
static void DumpPSSelector(std::ostream& out, const PSSelector& ps, const std::string& indent = "");
static void DumpVSSelector(std::ostream& out, const VSSelector& vs, const std::string& indent = "");
static void DumpBlendState(std::ostream& out, const BlendState& bs, const std::string& indent = "");
static void DumpDepthStencilSelctor(std::ostream& out, const DepthStencilSelector& ds, const std::string& indent = "");
static void DumpSamplerSelector(std::ostream& out, const SamplerSelector& ss, const std::string& indent = "");
static void DumpAlphaPass(std::ostream& out, const AlphaPass& ap, const std::string& indent = "");
static void DumpBlendMultipass(std::ostream& out, const BlendMultiPass& bmp, const std::string& indent = "");
static void DumpConfig(std::ostream& out, const GSHWDrawConfig& conf,
bool ps = true, bool vs = true, bool bs = true, bool dss = true, bool ss = true, bool asp = true, bool bmp = true);
static void DumpConfig(const std::string& fn, const GSHWDrawConfig& conf,
bool ps = true, bool vs = true, bool bs = true, bool dss = true, bool ss = true, bool asp = true, bool bmp = true);
};
static inline u32 GetExpansionFactor(GSHWDrawConfig::VSExpand expand)
+11 -6
View File
@@ -7280,27 +7280,27 @@ void GSRendererHW::EmulateATST(float& AREF, GSHWDrawConfig::PSSelector& ps, bool
{
case ATST_LESS:
AREF = aref - 0.1f;
ps.atst = 1;
ps.atst = GSHWDrawConfig::PSAlphaTest::PS_ATST_LEQUAL;
break;
case ATST_LEQUAL:
AREF = aref - 0.1f + 1.0f;
ps.atst = 1;
ps.atst = GSHWDrawConfig::PSAlphaTest::PS_ATST_LEQUAL;
break;
case ATST_GEQUAL:
AREF = aref - 0.1f;
ps.atst = 2;
ps.atst = GSHWDrawConfig::PSAlphaTest::PS_ATST_GEQUAL;
break;
case ATST_GREATER:
AREF = aref - 0.1f + 1.0f;
ps.atst = 2;
ps.atst = GSHWDrawConfig::PSAlphaTest::PS_ATST_GEQUAL;
break;
case ATST_EQUAL:
AREF = aref;
ps.atst = 3;
ps.atst = GSHWDrawConfig::PSAlphaTest::PS_ATST_EQUAL;
break;
case ATST_NOTEQUAL:
AREF = aref;
ps.atst = 4;
ps.atst = GSHWDrawConfig::PSAlphaTest::PS_ATST_NOTEQUAL;
break;
case ATST_NEVER: // Draw won't be done so no need to implement it in shader
case ATST_ALWAYS:
@@ -8209,6 +8209,11 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
m_conf.alpha_second_pass.enable = false;
}
if (GSConfig.SaveHWConfig && GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
{
GSHWDrawConfig::DumpConfig(GetDrawDumpPath("%05d_hwconfig.txt", s_n), m_conf);
}
if (!m_channel_shuffle_width)
g_gs_device->RenderHW(m_conf);
else
+1
View File
@@ -999,6 +999,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapBitBoolEx(SaveTransferImages, "SaveTransferImages");
SettingsWrapBitBoolEx(SaveDrawStats, "SaveDrawStats");
SettingsWrapBitBoolEx(SaveFrameStats, "SaveFrameStats");
SettingsWrapBitBoolEx(SaveHWConfig, "SaveHWConfig");
SettingsWrapBitBool(DumpReplaceableTextures);
SettingsWrapBitBool(DumpReplaceableMipmaps);
SettingsWrapBitBool(DumpTexturesWithFMVActive);