mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-21 05:09:34 -06:00
Software: Remove dedicated texture/frame dumping infrastructure
Texture dumping can already be done using VideoCommon's system (and in fact the same setting already enabled *both* of these). Dumping objects/TEV stages/texture fetches doesn't currently have an equivalent, but could be added to the FIFO player instead.
This commit is contained in:
@ -2,8 +2,6 @@ add_library(videosoftware
|
||||
Clipper.cpp
|
||||
Clipper.h
|
||||
CopyRegion.h
|
||||
DebugUtil.cpp
|
||||
DebugUtil.h
|
||||
EfbCopy.cpp
|
||||
EfbCopy.h
|
||||
EfbInterface.cpp
|
||||
|
@ -1,219 +0,0 @@
|
||||
// Copyright 2009 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "VideoBackends/Software/DebugUtil.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/Image.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Common/Swap.h"
|
||||
|
||||
#include "VideoBackends/Software/EfbInterface.h"
|
||||
#include "VideoBackends/Software/TextureSampler.h"
|
||||
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
#include "VideoCommon/Statistics.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace DebugUtil
|
||||
{
|
||||
static const int NUM_OBJECT_BUFFERS = 40;
|
||||
|
||||
static u32* ObjectBuffer[NUM_OBJECT_BUFFERS];
|
||||
static u32 TempBuffer[NUM_OBJECT_BUFFERS];
|
||||
|
||||
static bool DrawnToBuffer[NUM_OBJECT_BUFFERS];
|
||||
static const char* ObjectBufferName[NUM_OBJECT_BUFFERS];
|
||||
static int BufferBase[NUM_OBJECT_BUFFERS];
|
||||
|
||||
void Init()
|
||||
{
|
||||
for (int i = 0; i < NUM_OBJECT_BUFFERS; i++)
|
||||
{
|
||||
ObjectBuffer[i] = new u32[EFB_WIDTH * EFB_HEIGHT]();
|
||||
DrawnToBuffer[i] = false;
|
||||
ObjectBufferName[i] = nullptr;
|
||||
BufferBase[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
for (auto& slot : ObjectBuffer)
|
||||
{
|
||||
delete[] slot;
|
||||
}
|
||||
}
|
||||
|
||||
static void SaveTexture(const std::string& filename, u32 texmap, s32 mip)
|
||||
{
|
||||
u32 width = bpmem.tex.GetUnit(texmap).texImage0.width + 1;
|
||||
u32 height = bpmem.tex.GetUnit(texmap).texImage0.height + 1;
|
||||
|
||||
auto data = std::make_unique<u8[]>(width * height * 4);
|
||||
|
||||
GetTextureRGBA(data.get(), texmap, mip, width, height);
|
||||
Common::SavePNG(filename, data.get(), Common::ImageByteFormat::RGBA, width, height, width * 4);
|
||||
}
|
||||
|
||||
void GetTextureRGBA(u8* dst, u32 texmap, s32 mip, u32 width, u32 height)
|
||||
{
|
||||
for (u32 y = 0; y < height; y++)
|
||||
{
|
||||
for (u32 x = 0; x < width; x++)
|
||||
{
|
||||
TextureSampler::SampleMip(x << 7, y << 7, mip, false, texmap, dst);
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static s32 GetMaxTextureLod(u32 texmap)
|
||||
{
|
||||
u8 maxLod = bpmem.tex.GetUnit(texmap).texMode1.max_lod;
|
||||
u8 mip = maxLod >> 4;
|
||||
u8 fract = maxLod & 0xf;
|
||||
|
||||
if (fract)
|
||||
++mip;
|
||||
|
||||
return (s32)mip;
|
||||
}
|
||||
|
||||
void DumpActiveTextures()
|
||||
{
|
||||
for (unsigned int stageNum = 0; stageNum < bpmem.genMode.numindstages; stageNum++)
|
||||
{
|
||||
u32 texmap = bpmem.tevindref.getTexMap(stageNum);
|
||||
|
||||
s32 maxLod = GetMaxTextureLod(texmap);
|
||||
for (s32 mip = 0; mip <= maxLod; ++mip)
|
||||
{
|
||||
SaveTexture(StringFromFormat("%star%i_ind%i_map%i_mip%i.png",
|
||||
File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
|
||||
g_stats.this_frame.num_drawn_objects, stageNum, texmap, mip),
|
||||
texmap, mip);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int stageNum = 0; stageNum <= bpmem.genMode.numtevstages; stageNum++)
|
||||
{
|
||||
int stageNum2 = stageNum >> 1;
|
||||
int stageOdd = stageNum & 1;
|
||||
TwoTevStageOrders& order = bpmem.tevorders[stageNum2];
|
||||
|
||||
int texmap = order.getTexMap(stageOdd);
|
||||
|
||||
s32 maxLod = GetMaxTextureLod(texmap);
|
||||
for (s32 mip = 0; mip <= maxLod; ++mip)
|
||||
{
|
||||
SaveTexture(StringFromFormat("%star%i_stage%i_map%i_mip%i.png",
|
||||
File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
|
||||
g_stats.this_frame.num_drawn_objects, stageNum, texmap, mip),
|
||||
texmap, mip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void DumpEfb(const std::string& filename)
|
||||
{
|
||||
auto data = std::make_unique<u8[]>(EFB_WIDTH * EFB_HEIGHT * 4);
|
||||
u8* writePtr = data.get();
|
||||
|
||||
for (u32 y = 0; y < EFB_HEIGHT; y++)
|
||||
{
|
||||
for (u32 x = 0; x < EFB_WIDTH; x++)
|
||||
{
|
||||
// ABGR to RGBA
|
||||
const u32 sample = Common::swap32(EfbInterface::GetColor(x, y));
|
||||
|
||||
std::memcpy(writePtr, &sample, sizeof(u32));
|
||||
writePtr += sizeof(u32);
|
||||
}
|
||||
}
|
||||
|
||||
Common::SavePNG(filename, data.get(), Common::ImageByteFormat::RGBA, EFB_WIDTH, EFB_HEIGHT,
|
||||
EFB_WIDTH * 4);
|
||||
}
|
||||
|
||||
void DrawObjectBuffer(s16 x, s16 y, const u8* color, int bufferBase, int subBuffer,
|
||||
const char* name)
|
||||
{
|
||||
int buffer = bufferBase + subBuffer;
|
||||
|
||||
u32 offset = (x + y * EFB_WIDTH) * 4;
|
||||
u8* dst = (u8*)&ObjectBuffer[buffer][offset];
|
||||
*(dst++) = color[2];
|
||||
*(dst++) = color[1];
|
||||
*(dst++) = color[0];
|
||||
*(dst++) = color[3];
|
||||
|
||||
DrawnToBuffer[buffer] = true;
|
||||
ObjectBufferName[buffer] = name;
|
||||
BufferBase[buffer] = bufferBase;
|
||||
}
|
||||
|
||||
void DrawTempBuffer(const u8* color, int buffer)
|
||||
{
|
||||
u8* dst = (u8*)&TempBuffer[buffer];
|
||||
*(dst++) = color[2];
|
||||
*(dst++) = color[1];
|
||||
*(dst++) = color[0];
|
||||
*(dst++) = color[3];
|
||||
}
|
||||
|
||||
void CopyTempBuffer(s16 x, s16 y, int bufferBase, int subBuffer, const char* name)
|
||||
{
|
||||
int buffer = bufferBase + subBuffer;
|
||||
|
||||
u32 offset = (x + y * EFB_WIDTH);
|
||||
ObjectBuffer[buffer][offset] = TempBuffer[buffer];
|
||||
|
||||
DrawnToBuffer[buffer] = true;
|
||||
ObjectBufferName[buffer] = name;
|
||||
BufferBase[buffer] = bufferBase;
|
||||
}
|
||||
|
||||
void OnObjectBegin()
|
||||
{
|
||||
if (g_ActiveConfig.bDumpTextures &&
|
||||
g_stats.this_frame.num_drawn_objects >= g_ActiveConfig.drawStart &&
|
||||
g_stats.this_frame.num_drawn_objects < g_ActiveConfig.drawEnd)
|
||||
{
|
||||
DumpActiveTextures();
|
||||
}
|
||||
}
|
||||
|
||||
void OnObjectEnd()
|
||||
{
|
||||
if (g_ActiveConfig.bDumpObjects &&
|
||||
g_stats.this_frame.num_drawn_objects >= g_ActiveConfig.drawStart &&
|
||||
g_stats.this_frame.num_drawn_objects < g_ActiveConfig.drawEnd)
|
||||
{
|
||||
DumpEfb(StringFromFormat("%sobject%i.png", File::GetUserPath(D_DUMPOBJECTS_IDX).c_str(),
|
||||
g_stats.this_frame.num_drawn_objects));
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUM_OBJECT_BUFFERS; i++)
|
||||
{
|
||||
if (DrawnToBuffer[i])
|
||||
{
|
||||
DrawnToBuffer[i] = false;
|
||||
std::string filename = StringFromFormat(
|
||||
"%sobject%i_%s(%i).png", File::GetUserPath(D_DUMPOBJECTS_IDX).c_str(),
|
||||
g_stats.this_frame.num_drawn_objects, ObjectBufferName[i], i - BufferBase[i]);
|
||||
|
||||
Common::SavePNG(filename, reinterpret_cast<u8*>(ObjectBuffer[i]),
|
||||
Common::ImageByteFormat::RGBA, EFB_WIDTH, EFB_HEIGHT, EFB_WIDTH * 4);
|
||||
memset(ObjectBuffer[i], 0, EFB_WIDTH * EFB_HEIGHT * sizeof(u32));
|
||||
}
|
||||
}
|
||||
|
||||
g_stats.this_frame.num_drawn_objects++;
|
||||
}
|
||||
} // namespace DebugUtil
|
@ -1,25 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
namespace DebugUtil
|
||||
{
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
void GetTextureRGBA(u8* dst, u32 texmap, s32 mip, u32 width, u32 height);
|
||||
|
||||
void DumpActiveTextures();
|
||||
|
||||
void OnObjectBegin();
|
||||
void OnObjectEnd();
|
||||
|
||||
void DrawObjectBuffer(s16 x, s16 y, const u8* color, int bufferBase, int subBuffer,
|
||||
const char* name);
|
||||
|
||||
void DrawTempBuffer(const u8* color, int buffer);
|
||||
void CopyTempBuffer(s16 x, s16 y, int bufferBase, int subBuffer, const char* name);
|
||||
} // namespace DebugUtil
|
@ -10,7 +10,6 @@
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
#include "VideoBackends/Software/DebugUtil.h"
|
||||
#include "VideoBackends/Software/NativeVertexFormat.h"
|
||||
#include "VideoBackends/Software/Rasterizer.h"
|
||||
#include "VideoBackends/Software/SWRenderer.h"
|
||||
@ -42,8 +41,6 @@ DataReader SWVertexLoader::PrepareForAdditionalData(OpcodeDecoder::Primitive pri
|
||||
|
||||
void SWVertexLoader::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex)
|
||||
{
|
||||
DebugUtil::OnObjectBegin();
|
||||
|
||||
using OpcodeDecoder::Primitive;
|
||||
Primitive primitive_type = Primitive::GX_DRAW_QUADS;
|
||||
switch (m_current_primitive_type)
|
||||
@ -90,10 +87,10 @@ void SWVertexLoader::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_
|
||||
// assemble and rasterize the primitive
|
||||
m_setup_unit.SetupVertex();
|
||||
|
||||
INCSTAT(g_stats.this_frame.num_vertices_loaded)
|
||||
INCSTAT(g_stats.this_frame.num_vertices_loaded);
|
||||
}
|
||||
|
||||
DebugUtil::OnObjectEnd();
|
||||
INCSTAT(g_stats.this_frame.num_drawn_objects);
|
||||
}
|
||||
|
||||
void SWVertexLoader::SetFormat()
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "Common/MsgHandler.h"
|
||||
|
||||
#include "VideoBackends/Software/Clipper.h"
|
||||
#include "VideoBackends/Software/DebugUtil.h"
|
||||
#include "VideoBackends/Software/EfbInterface.h"
|
||||
#include "VideoBackends/Software/Rasterizer.h"
|
||||
#include "VideoBackends/Software/SWOGLWindow.h"
|
||||
@ -105,7 +104,6 @@ bool VideoSoftware::Initialize(const WindowSystemInfo& wsi)
|
||||
|
||||
Clipper::Init();
|
||||
Rasterizer::Init();
|
||||
DebugUtil::Init();
|
||||
|
||||
g_renderer = std::make_unique<SWRenderer>(std::move(window));
|
||||
g_vertex_manager = std::make_unique<SWVertexLoader>();
|
||||
@ -135,7 +133,6 @@ void VideoSoftware::Shutdown()
|
||||
if (g_renderer)
|
||||
g_renderer->Shutdown();
|
||||
|
||||
DebugUtil::Shutdown();
|
||||
g_texture_cache.reset();
|
||||
g_perf_query.reset();
|
||||
g_framebuffer_manager.reset();
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "VideoBackends/Software/DebugUtil.h"
|
||||
#include "VideoBackends/Software/EfbInterface.h"
|
||||
#include "VideoBackends/Software/SWBoundingBox.h"
|
||||
#include "VideoBackends/Software/TextureSampler.h"
|
||||
@ -428,16 +427,6 @@ void Tev::Draw()
|
||||
TextureSampler::Sample(Uv[texcoordSel].s >> scaleS, Uv[texcoordSel].t >> scaleT,
|
||||
IndirectLod[stageNum], IndirectLinear[stageNum], texmap,
|
||||
IndirectTex[stageNum]);
|
||||
|
||||
#if ALLOW_TEV_DUMPS
|
||||
if (g_ActiveConfig.bDumpTevStages)
|
||||
{
|
||||
u8 stage[4] = {IndirectTex[stageNum][TextureSampler::ALP_SMP],
|
||||
IndirectTex[stageNum][TextureSampler::BLU_SMP],
|
||||
IndirectTex[stageNum][TextureSampler::GRN_SMP], 255};
|
||||
DebugUtil::DrawTempBuffer(stage, INDIRECT + stageNum);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
for (unsigned int stageNum = 0; stageNum <= bpmem.genMode.numtevstages; stageNum++)
|
||||
@ -478,11 +467,6 @@ void Tev::Draw()
|
||||
std::memset(texel, 0, 4);
|
||||
}
|
||||
|
||||
#if ALLOW_TEV_DUMPS
|
||||
if (g_ActiveConfig.bDumpTevTextureFetches)
|
||||
DebugUtil::DrawTempBuffer(texel, DIRECT_TFETCH + stageNum);
|
||||
#endif
|
||||
|
||||
const auto& swap = bpmem.tevksel.GetSwapTable(ac.tswap);
|
||||
TexColor.r = texel[u32(swap[ColorChannel::Red])];
|
||||
TexColor.g = texel[u32(swap[ColorChannel::Green])];
|
||||
@ -547,15 +531,6 @@ void Tev::Draw()
|
||||
Reg[ac.dest].a = Clamp255(Reg[ac.dest].a);
|
||||
else
|
||||
Reg[ac.dest].a = Clamp1024(Reg[ac.dest].a);
|
||||
|
||||
#if ALLOW_TEV_DUMPS
|
||||
if (g_ActiveConfig.bDumpTevStages)
|
||||
{
|
||||
u8 stage[4] = {(u8)Reg[cc.dest].r, (u8)Reg[cc.dest].g, (u8)Reg[cc.dest].b,
|
||||
(u8)Reg[ac.dest].a};
|
||||
DebugUtil::DrawTempBuffer(stage, DIRECT + stageNum);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// convert to 8 bits per component
|
||||
@ -711,26 +686,6 @@ void Tev::Draw()
|
||||
BBoxManager::Update(static_cast<u16>(Position[0] & ~1), static_cast<u16>(Position[0] | 1),
|
||||
static_cast<u16>(Position[1] & ~1), static_cast<u16>(Position[1] | 1));
|
||||
|
||||
#if ALLOW_TEV_DUMPS
|
||||
if (g_ActiveConfig.bDumpTevStages)
|
||||
{
|
||||
for (u32 i = 0; i < bpmem.genMode.numindstages; ++i)
|
||||
DebugUtil::CopyTempBuffer(Position[0], Position[1], INDIRECT, i, "Indirect");
|
||||
for (u32 i = 0; i <= bpmem.genMode.numtevstages; ++i)
|
||||
DebugUtil::CopyTempBuffer(Position[0], Position[1], DIRECT, i, "Stage");
|
||||
}
|
||||
|
||||
if (g_ActiveConfig.bDumpTevTextureFetches)
|
||||
{
|
||||
for (u32 i = 0; i <= bpmem.genMode.numtevstages; ++i)
|
||||
{
|
||||
TwoTevStageOrders& order = bpmem.tevorders[i >> 1];
|
||||
if (order.getEnable(i & 1))
|
||||
DebugUtil::CopyTempBuffer(Position[0], Position[1], DIRECT_TFETCH, i, "TFetch");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
INCSTAT(g_stats.this_frame.tev_pixels_out);
|
||||
EfbInterface::IncPerfCounterQuadCount(PQ_BLEND_INPUT);
|
||||
|
||||
|
Reference in New Issue
Block a user