Merge pull request #3156 from degasus/videosw2

VideoSW: Use VideoCommon framework and drop redundant code
This commit is contained in:
Pierre Bourdon 2016-01-06 23:29:51 +01:00
commit 3c65a7dd7f
51 changed files with 529 additions and 2025 deletions

View File

@ -76,8 +76,6 @@
#include "InputCommon/ControllerInterface/ControllerInterface.h" #include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "VideoBackends/Software/SWVideoConfig.h"
#include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"

View File

@ -31,13 +31,16 @@ IntegerSetting<T>::IntegerSetting(wxWindow* parent, const wxString& label, T& se
} }
SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std::string& title, const std::string& _ininame) : SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std::string& title, const std::string& ininame) :
wxDialog(parent, wxID_ANY, wxDialog(parent, wxID_ANY,
wxString(wxString::Format(_("Dolphin %s Graphics Configuration"), title))), wxString(wxString::Format(_("Dolphin %s Graphics Configuration"), title)))
vconfig(g_SWVideoConfig),
ininame(_ininame)
{ {
vconfig.Load((File::GetUserPath(D_CONFIG_IDX) + ininame + ".ini").c_str()); VideoConfig& vconfig = g_ActiveConfig;
if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini"))
vconfig.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini");
else
vconfig.Load(File::GetUserPath(D_CONFIG_IDX) + ininame + ".ini");
wxNotebook* const notebook = new wxNotebook(this, wxID_ANY); wxNotebook* const notebook = new wxNotebook(this, wxID_ANY);
@ -77,7 +80,7 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
} }
// xfb // xfb
szr_rendering->Add(new SettingCheckBox(page_general, _("Bypass XFB"), "", vconfig.bBypassXFB)); szr_rendering->Add(new SettingCheckBox(page_general, _("Bypass XFB"), "", vconfig.bUseXFB, true));
} }
// - info // - info
@ -87,7 +90,7 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
wxGridSizer* const szr_info = new wxGridSizer(2, 5, 5); wxGridSizer* const szr_info = new wxGridSizer(2, 5, 5);
group_info->Add(szr_info, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); group_info->Add(szr_info, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
szr_info->Add(new SettingCheckBox(page_general, _("Various Statistics"), "", vconfig.bShowStats)); szr_info->Add(new SettingCheckBox(page_general, _("Various Statistics"), "", vconfig.bOverlayStats));
} }
// - utility // - utility
@ -117,8 +120,8 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
wxFlexGridSizer* const szr_misc = new wxFlexGridSizer(2, 5, 5); wxFlexGridSizer* const szr_misc = new wxFlexGridSizer(2, 5, 5);
group_misc->Add(szr_misc, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); group_misc->Add(szr_misc, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
szr_misc->Add(new U32Setting(page_general, _("Start"), vconfig.drawStart, 0, 100000)); szr_misc->Add(new IntegerSetting<int>(page_general, _("Start"), vconfig.drawStart, 0, 100000));
szr_misc->Add(new U32Setting(page_general, _("End"), vconfig.drawEnd, 0, 100000)); szr_misc->Add(new IntegerSetting<int>(page_general, _("End"), vconfig.drawEnd, 0, 100000));
} }
page_general->SetSizerAndFit(szr_general); page_general->SetSizerAndFit(szr_general);
@ -136,5 +139,5 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
SoftwareVideoConfigDialog::~SoftwareVideoConfigDialog() SoftwareVideoConfigDialog::~SoftwareVideoConfigDialog()
{ {
g_SWVideoConfig.Save((File::GetUserPath(D_CONFIG_IDX) + ininame + ".ini").c_str()); g_ActiveConfig.Save((File::GetUserPath(D_CONFIG_IDX) + "GFX.ini").c_str());
} }

View File

@ -13,8 +13,8 @@
#include <wx/dialog.h> #include <wx/dialog.h>
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "VideoBackends/Software/SWVideoConfig.h"
#include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoConfig.h"
class SoftwareVideoConfigDialog : public wxDialog class SoftwareVideoConfigDialog : public wxDialog
{ {
@ -37,8 +37,4 @@ public:
} }
ev.Skip(); ev.Skip();
} }
protected:
SWVideoConfig& vconfig;
std::string ininame;
}; };

View File

@ -65,8 +65,6 @@ private:
T& m_setting; T& m_setting;
}; };
typedef IntegerSetting<u32> U32Setting;
class SettingChoice : public wxChoice class SettingChoice : public wxChoice
{ {
public: public:

View File

@ -1,178 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/HW/Memmap.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/EfbCopy.h"
#include "VideoBackends/Software/EfbInterface.h"
#include "VideoBackends/Software/Rasterizer.h"
#include "VideoBackends/Software/Tev.h"
#include "VideoCommon/BoundingBox.h"
#include "VideoCommon/PixelEngine.h"
#include "VideoCommon/TextureDecoder.h"
#include "VideoCommon/VideoCommon.h"
void InitBPMemory()
{
memset(&bpmem, 0, sizeof(bpmem));
bpmem.bpMask = 0xFFFFFF;
}
void SWLoadBPReg(u32 value)
{
//handle the mask register
int address = value >> 24;
int oldval = ((u32*)&bpmem)[address];
int newval = (oldval & ~bpmem.bpMask) | (value & bpmem.bpMask);
((u32*)&bpmem)[address] = newval;
//reset the mask register
if (address != 0xFE)
bpmem.bpMask = 0xFFFFFF;
SWBPWritten(address, newval);
}
void SWBPWritten(int address, int newvalue)
{
switch (address)
{
case BPMEM_SCISSORTL:
case BPMEM_SCISSORBR:
case BPMEM_SCISSOROFFSET:
Rasterizer::SetScissor();
break;
case BPMEM_SETDRAWDONE: // This is called when the game is done drawing (eg: like in DX: Begin(); Draw(); End();)
switch (bpmem.drawdone & 0xFF)
{
case 0x02:
PixelEngine::SetFinish(); // may generate interrupt
DEBUG_LOG(VIDEO, "GXSetDrawDone SetPEFinish (value: 0x%02X)", (bpmem.drawdone & 0xFFFF));
break;
default:
WARN_LOG(VIDEO, "GXSetDrawDone ??? (value 0x%02X)", (bpmem.drawdone & 0xFFFF));
break;
}
break;
case BPMEM_PE_TOKEN_ID: // Pixel Engine Token ID
DEBUG_LOG(VIDEO, "SetPEToken 0x%04x", (bpmem.petoken & 0xFFFF));
PixelEngine::SetToken(static_cast<u16>(bpmem.petokenint & 0xFFFF), false);
break;
case BPMEM_PE_TOKEN_INT_ID: // Pixel Engine Interrupt Token ID
DEBUG_LOG(VIDEO, "SetPEToken + INT 0x%04x", (bpmem.petokenint & 0xFFFF));
PixelEngine::SetToken(static_cast<u16>(bpmem.petokenint & 0xFFFF), true);
break;
case BPMEM_TRIGGER_EFB_COPY:
EfbCopy::CopyEfb();
break;
case BPMEM_CLEARBBOX1:
BoundingBox::coords[BoundingBox::LEFT] = newvalue >> 10;
BoundingBox::coords[BoundingBox::RIGHT] = newvalue & 0x3ff;
break;
case BPMEM_CLEARBBOX2:
BoundingBox::coords[BoundingBox::TOP] = newvalue >> 10;
BoundingBox::coords[BoundingBox::BOTTOM] = newvalue & 0x3ff;
break;
case BPMEM_CLEAR_PIXEL_PERF:
// TODO: I didn't test if the value written to this register affects the amount of cleared registers
memset(EfbInterface::perf_values, 0, sizeof(EfbInterface::perf_values));
break;
case BPMEM_LOADTLUT0: // This one updates bpmem.tlutXferSrc, no need to do anything here.
break;
case BPMEM_LOADTLUT1: // Load a Texture Look Up Table
{
u32 tlutTMemAddr = (newvalue & 0x3FF) << 9;
u32 tlutXferCount = (newvalue & 0x1FFC00) >> 5;
u32 addr = bpmem.tmem_config.tlut_src << 5;
// The GameCube ignores the upper bits of this address. Some games (WW, MKDD) set them.
if (!SConfig::GetInstance().bWii)
addr = addr & 0x01FFFFFF;
Memory::CopyFromEmu(texMem + tlutTMemAddr, addr, tlutXferCount);
break;
}
case BPMEM_PRELOAD_MODE:
if (newvalue != 0)
{
// TODO: Not quite sure if this is completely correct (likely not)
// NOTE: libogc's implementation of GX_PreloadEntireTexture seems flawed, so it's not necessarily a good reference for RE'ing this feature.
BPS_TmemConfig& tmem_cfg = bpmem.tmem_config;
u32 src_addr = tmem_cfg.preload_addr << 5; // TODO: Should we add mask here on GC?
u32 size = tmem_cfg.preload_tile_info.count * TMEM_LINE_SIZE;
u32 tmem_addr_even = tmem_cfg.preload_tmem_even * TMEM_LINE_SIZE;
if (tmem_cfg.preload_tile_info.type != 3)
{
if (tmem_addr_even + size > TMEM_SIZE)
size = TMEM_SIZE - tmem_addr_even;
Memory::CopyFromEmu(texMem + tmem_addr_even, src_addr, size);
}
else // RGBA8 tiles (and CI14, but that might just be stupid libogc!)
{
u8* src_ptr = Memory::GetPointer(src_addr);
// AR and GB tiles are stored in separate TMEM banks => can't use a single memcpy for everything
u32 tmem_addr_odd = tmem_cfg.preload_tmem_odd * TMEM_LINE_SIZE;
for (unsigned int i = 0; i < tmem_cfg.preload_tile_info.count; ++i)
{
if (tmem_addr_even + TMEM_LINE_SIZE > TMEM_SIZE ||
tmem_addr_odd + TMEM_LINE_SIZE > TMEM_SIZE)
break;
memcpy(texMem + tmem_addr_even, src_ptr, TMEM_LINE_SIZE);
memcpy(texMem + tmem_addr_odd, src_ptr + TMEM_LINE_SIZE, TMEM_LINE_SIZE);
tmem_addr_even += TMEM_LINE_SIZE;
tmem_addr_odd += TMEM_LINE_SIZE;
src_ptr += TMEM_LINE_SIZE * 2;
}
}
}
break;
case BPMEM_TEV_COLOR_RA:
case BPMEM_TEV_COLOR_RA + 2:
case BPMEM_TEV_COLOR_RA + 4:
case BPMEM_TEV_COLOR_RA + 6:
{
int regNum = (address >> 1 ) & 0x3;
TevReg& reg = bpmem.tevregs[regNum];
bool is_konst = reg.type_ra != 0;
Rasterizer::SetTevReg(regNum, Tev::ALP_C, is_konst, static_cast<s16>(reg.alpha));
Rasterizer::SetTevReg(regNum, Tev::RED_C, is_konst, static_cast<s16>(reg.red));
break;
}
case BPMEM_TEV_COLOR_BG:
case BPMEM_TEV_COLOR_BG + 2:
case BPMEM_TEV_COLOR_BG + 4:
case BPMEM_TEV_COLOR_BG + 6:
{
int regNum = (address >> 1 ) & 0x3;
TevReg& reg = bpmem.tevregs[regNum];
bool is_konst = reg.type_bg != 0;
Rasterizer::SetTevReg(regNum, Tev::GRN_C, is_konst, static_cast<s16>(reg.green));
Rasterizer::SetTevReg(regNum, Tev::BLU_C, is_konst, static_cast<s16>(reg.blue));
break;
}
}
}

View File

@ -1,13 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "Common/CommonTypes.h"
#include "VideoCommon/BPMemory.h"
void InitBPMemory();
void SWBPWritten(int address, int newvalue);
void SWLoadBPReg(u32 value);

View File

@ -1,24 +1,17 @@
set(SRCS BPMemLoader.cpp set(SRCS Clipper.cpp
CPMemLoader.cpp
Clipper.cpp
DebugUtil.cpp DebugUtil.cpp
EfbCopy.cpp EfbCopy.cpp
EfbInterface.cpp EfbInterface.cpp
OpcodeDecoder.cpp
Rasterizer.cpp Rasterizer.cpp
SWCommandProcessor.cpp
SWOGLWindow.cpp SWOGLWindow.cpp
SWRenderer.cpp SWRenderer.cpp
SWStatistics.cpp
SWVertexLoader.cpp SWVertexLoader.cpp
SWVideoConfig.cpp
SWmain.cpp SWmain.cpp
SetupUnit.cpp SetupUnit.cpp
Tev.cpp Tev.cpp
TextureEncoder.cpp TextureEncoder.cpp
TextureSampler.cpp TextureSampler.cpp
TransformUnit.cpp TransformUnit.cpp)
XFMemLoader.cpp)
set(LIBS videocommon set(LIBS videocommon
SOIL SOIL

View File

@ -1,60 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Common/CommonFuncs.h"
#include "Core/HW/Memmap.h"
#include "VideoBackends/Software/CPMemLoader.h"
#include "VideoCommon/VideoCommon.h"
void SWLoadCPReg(u32 sub_cmd, u32 value)
{
switch (sub_cmd & 0xF0)
{
case 0x30:
g_main_cp_state.matrix_index_a.Hex = value;
break;
case 0x40:
g_main_cp_state.matrix_index_b.Hex = value;
break;
case 0x50:
g_main_cp_state.vtx_desc.Hex &= ~0x1FFFF; // keep the Upper bits
g_main_cp_state.vtx_desc.Hex |= value;
g_main_cp_state.bases_dirty = true;
break;
case 0x60:
g_main_cp_state.vtx_desc.Hex &= 0x1FFFF; // keep the lower 17Bits
g_main_cp_state.vtx_desc.Hex |= (u64)value << 17;
g_main_cp_state.bases_dirty = true;
break;
case 0x70:
_assert_((sub_cmd & 0x0F) < 8);
g_main_cp_state.vtx_attr[sub_cmd & 7].g0.Hex = value;
break;
case 0x80:
_assert_((sub_cmd & 0x0F) < 8);
g_main_cp_state.vtx_attr[sub_cmd & 7].g1.Hex = value;
break;
case 0x90:
_assert_((sub_cmd & 0x0F) < 8);
g_main_cp_state.vtx_attr[sub_cmd & 7].g2.Hex = value;
break;
// Pointers to vertex arrays in GC RAM
case 0xA0:
g_main_cp_state.array_bases[sub_cmd & 0xF] = value;
g_main_cp_state.bases_dirty = true;
break;
case 0xB0:
g_main_cp_state.array_strides[sub_cmd & 0xF] = value & 0xFF;
break;
}
}

View File

@ -1,10 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "Common/CommonTypes.h"
#include "VideoCommon/CPMemory.h"
void SWLoadCPReg(u32 sub_cmd, u32 value);

View File

@ -36,12 +36,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "Common/ChunkFile.h" #include "Common/ChunkFile.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/Clipper.h" #include "VideoBackends/Software/Clipper.h"
#include "VideoBackends/Software/NativeVertexFormat.h" #include "VideoBackends/Software/NativeVertexFormat.h"
#include "VideoBackends/Software/Rasterizer.h" #include "VideoBackends/Software/Rasterizer.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/XFMemLoader.h" #include "VideoCommon/BPMemory.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/XFMemory.h"
namespace Clipper namespace Clipper
{ {
@ -56,13 +57,6 @@ namespace Clipper
static OutputVertexData ClippedVertices[NUM_CLIPPED_VERTICES]; static OutputVertexData ClippedVertices[NUM_CLIPPED_VERTICES];
static OutputVertexData *Vertices[NUM_INDICES]; static OutputVertexData *Vertices[NUM_INDICES];
void DoState(PointerWrap &p)
{
p.DoArray(m_ViewOffset);
for (auto& ClippedVertice : ClippedVertices)
ClippedVertice.DoState(p);
}
void Init() void Init()
{ {
for (int i = 0; i < NUM_CLIPPED_VERTICES; ++i) for (int i = 0; i < NUM_CLIPPED_VERTICES; ++i)
@ -220,7 +214,7 @@ namespace Clipper
POLY_CLIP(CLIP_POS_Z_BIT, 0, 0, 0, 1); POLY_CLIP(CLIP_POS_Z_BIT, 0, 0, 0, 1);
POLY_CLIP(CLIP_NEG_Z_BIT, 0, 0, 1, 1); POLY_CLIP(CLIP_NEG_Z_BIT, 0, 0, 1, 1);
INCSTAT(swstats.thisFrame.numTrianglesClipped); INCSTAT(stats.thisFrame.numTrianglesClipped);
// transform the poly in inlist into triangles // transform the poly in inlist into triangles
indices[0] = inlist[0]; indices[0] = inlist[0];
@ -287,7 +281,7 @@ namespace Clipper
void ProcessTriangle(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2) void ProcessTriangle(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
{ {
INCSTAT(swstats.thisFrame.numTrianglesIn) INCSTAT(stats.thisFrame.numTrianglesIn)
bool backface; bool backface;
@ -411,7 +405,7 @@ namespace Clipper
if (mask) if (mask)
{ {
INCSTAT(swstats.thisFrame.numTrianglesRejected) INCSTAT(stats.thisFrame.numTrianglesRejected)
return false; return false;
} }
@ -431,13 +425,13 @@ namespace Clipper
if ((bpmem.genMode.cullmode & 1) && !backface) // cull frontfacing if ((bpmem.genMode.cullmode & 1) && !backface) // cull frontfacing
{ {
INCSTAT(swstats.thisFrame.numTrianglesCulled) INCSTAT(stats.thisFrame.numTrianglesCulled)
return false; return false;
} }
if ((bpmem.genMode.cullmode & 2) && backface) // cull backfacing if ((bpmem.genMode.cullmode & 2) && backface) // cull backfacing
{ {
INCSTAT(swstats.thisFrame.numTrianglesCulled) INCSTAT(stats.thisFrame.numTrianglesCulled)
return false; return false;
} }

View File

@ -5,7 +5,6 @@
#pragma once #pragma once
struct OutputVertexData; struct OutputVertexData;
class PointerWrap;
namespace Clipper namespace Clipper
{ {
@ -20,6 +19,4 @@ namespace Clipper
bool CullTest(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2, bool &backface); bool CullTest(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2, bool &backface);
void PerspectiveDivide(OutputVertexData *vertex); void PerspectiveDivide(OutputVertexData *vertex);
void DoState(PointerWrap &p);
} }

View File

@ -8,18 +8,16 @@
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/DebugUtil.h" #include "VideoBackends/Software/DebugUtil.h"
#include "VideoBackends/Software/EfbInterface.h" #include "VideoBackends/Software/EfbInterface.h"
#include "VideoBackends/Software/SWCommandProcessor.h"
#include "VideoBackends/Software/SWRenderer.h" #include "VideoBackends/Software/SWRenderer.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/SWVideoConfig.h"
#include "VideoBackends/Software/TextureSampler.h" #include "VideoBackends/Software/TextureSampler.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/Fifo.h" #include "VideoCommon/Fifo.h"
#include "VideoCommon/ImageWrite.h" #include "VideoCommon/ImageWrite.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/VideoConfig.h"
namespace DebugUtil namespace DebugUtil
{ {
@ -109,7 +107,7 @@ void DumpActiveTextures()
{ {
SaveTexture(StringFromFormat("%star%i_ind%i_map%i_mip%i.png", SaveTexture(StringFromFormat("%star%i_ind%i_map%i_mip%i.png",
File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(), File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
swstats.thisFrame.numDrawnObjects, stageNum, texmap, mip), texmap, mip); stats.thisFrame.numDrawnObjects, stageNum, texmap, mip), texmap, mip);
} }
} }
@ -126,7 +124,7 @@ void DumpActiveTextures()
{ {
SaveTexture(StringFromFormat("%star%i_stage%i_map%i_mip%i.png", SaveTexture(StringFromFormat("%star%i_stage%i_map%i_mip%i.png",
File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(), File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
swstats.thisFrame.numDrawnObjects, stageNum, texmap, mip), texmap, mip); stats.thisFrame.numDrawnObjects, stageNum, texmap, mip), texmap, mip);
} }
} }
} }
@ -154,13 +152,6 @@ static void DumpEfb(const std::string& filename)
delete[] data; delete[] data;
} }
static void DumpColorTexture(const std::string& filename, u32 width, u32 height)
{
TextureToPng(SWRenderer::GetCurrentColorTexture(), width * 4, filename, width, height, true);
}
void DrawObjectBuffer(s16 x, s16 y, u8 *color, int bufferBase, int subBuffer, const char *name) void DrawObjectBuffer(s16 x, s16 y, u8 *color, int bufferBase, int subBuffer, const char *name)
{ {
int buffer = bufferBase + subBuffer; int buffer = bufferBase + subBuffer;
@ -202,7 +193,7 @@ void OnObjectBegin()
{ {
if (!g_bSkipCurrentFrame) if (!g_bSkipCurrentFrame)
{ {
if (g_SWVideoConfig.bDumpTextures && swstats.thisFrame.numDrawnObjects >= g_SWVideoConfig.drawStart && swstats.thisFrame.numDrawnObjects < g_SWVideoConfig.drawEnd) if (g_ActiveConfig.bDumpTextures && stats.thisFrame.numDrawnObjects >= g_ActiveConfig.drawStart && stats.thisFrame.numDrawnObjects < g_ActiveConfig.drawEnd)
DumpActiveTextures(); DumpActiveTextures();
} }
} }
@ -211,10 +202,10 @@ void OnObjectEnd()
{ {
if (!g_bSkipCurrentFrame) if (!g_bSkipCurrentFrame)
{ {
if (g_SWVideoConfig.bDumpObjects && swstats.thisFrame.numDrawnObjects >= g_SWVideoConfig.drawStart && swstats.thisFrame.numDrawnObjects < g_SWVideoConfig.drawEnd) if (g_ActiveConfig.bDumpObjects && stats.thisFrame.numDrawnObjects >= g_ActiveConfig.drawStart && stats.thisFrame.numDrawnObjects < g_ActiveConfig.drawEnd)
DumpEfb(StringFromFormat("%sobject%i.png", DumpEfb(StringFromFormat("%sobject%i.png",
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), File::GetUserPath(D_DUMPFRAMES_IDX).c_str(),
swstats.thisFrame.numDrawnObjects)); stats.thisFrame.numDrawnObjects));
for (int i = 0; i < NUM_OBJECT_BUFFERS; i++) for (int i = 0; i < NUM_OBJECT_BUFFERS; i++)
{ {
@ -223,7 +214,7 @@ void OnObjectEnd()
DrawnToBuffer[i] = false; DrawnToBuffer[i] = false;
std::string filename = StringFromFormat("%sobject%i_%s(%i).png", std::string filename = StringFromFormat("%sobject%i_%s(%i).png",
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), File::GetUserPath(D_DUMPFRAMES_IDX).c_str(),
swstats.thisFrame.numDrawnObjects, ObjectBufferName[i], i - BufferBase[i]); stats.thisFrame.numDrawnObjects, ObjectBufferName[i], i - BufferBase[i]);
TextureToPng((u8*)ObjectBuffer[i], EFB_WIDTH * 4, filename, EFB_WIDTH, EFB_HEIGHT, true); TextureToPng((u8*)ObjectBuffer[i], EFB_WIDTH * 4, filename, EFB_WIDTH, EFB_HEIGHT, true);
memset(ObjectBuffer[i], 0, EFB_WIDTH * EFB_HEIGHT * sizeof(u32)); memset(ObjectBuffer[i], 0, EFB_WIDTH * EFB_HEIGHT * sizeof(u32));
@ -231,20 +222,7 @@ void OnObjectEnd()
} }
} }
swstats.thisFrame.numDrawnObjects++; stats.thisFrame.numDrawnObjects++;
}
}
// If frame dumping is enabled, dump whatever is drawn to the screen.
void OnFrameEnd(u32 width, u32 height)
{
if (!g_bSkipCurrentFrame)
{
if (SConfig::GetInstance().m_DumpFrames)
{
DumpColorTexture(StringFromFormat("%sframe%i_color.png",
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), swstats.frameCount), width, height);
}
} }
} }

View File

@ -18,8 +18,6 @@ namespace DebugUtil
void OnObjectBegin(); void OnObjectBegin();
void OnObjectEnd(); void OnObjectEnd();
void OnFrameEnd(u32 width, u32 height);
void DrawObjectBuffer(s16 x, s16 y, u8 *color, int bufferBase, int subBuffer, const char *name); void DrawObjectBuffer(s16 x, s16 y, u8 *color, int bufferBase, int subBuffer, const char *name);
void DrawTempBuffer(u8 *color, int buffer); void DrawTempBuffer(u8 *color, int buffer);

View File

@ -5,15 +5,13 @@
#include "Common/GL/GLInterfaceBase.h" #include "Common/GL/GLInterfaceBase.h"
#include "Core/Core.h" #include "Core/Core.h"
#include "Core/HW/Memmap.h" #include "Core/HW/Memmap.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/DebugUtil.h" #include "VideoBackends/Software/DebugUtil.h"
#include "VideoBackends/Software/EfbCopy.h" #include "VideoBackends/Software/EfbCopy.h"
#include "VideoBackends/Software/EfbInterface.h" #include "VideoBackends/Software/EfbInterface.h"
#include "VideoBackends/Software/SWCommandProcessor.h"
#include "VideoBackends/Software/SWRenderer.h" #include "VideoBackends/Software/SWRenderer.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/SWVideoConfig.h"
#include "VideoBackends/Software/TextureEncoder.h" #include "VideoBackends/Software/TextureEncoder.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/Fifo.h" #include "VideoCommon/Fifo.h"
static const float s_gammaLUT[] = static const float s_gammaLUT[] =
@ -33,31 +31,9 @@ namespace EfbCopy
INFO_LOG(VIDEO, "xfbaddr: %x, fbwidth: %i, fbheight: %i, source: (%i, %i, %i, %i), Gamma %f", INFO_LOG(VIDEO, "xfbaddr: %x, fbwidth: %i, fbheight: %i, source: (%i, %i, %i, %i), Gamma %f",
xfbAddr, fbWidth, fbHeight, sourceRc.top, sourceRc.left, sourceRc.bottom, sourceRc.right, Gamma); xfbAddr, fbWidth, fbHeight, sourceRc.top, sourceRc.left, sourceRc.bottom, sourceRc.right, Gamma);
if (!g_SWVideoConfig.bBypassXFB) EfbInterface::yuv422_packed* xfb_in_ram = (EfbInterface::yuv422_packed*) Memory::GetPointer(xfbAddr);
{
EfbInterface::yuv422_packed* xfb_in_ram = (EfbInterface::yuv422_packed *) Memory::GetPointer(xfbAddr);
EfbInterface::CopyToXFB(xfb_in_ram, fbWidth, fbHeight, sourceRc, Gamma); EfbInterface::CopyToXFB(xfb_in_ram, fbWidth, fbHeight, sourceRc, Gamma);
}
else
{
// Ask SWRenderer for the next color texture
u8 *colorTexture = SWRenderer::GetNextColorTexture();
EfbInterface::BypassXFB(colorTexture, fbWidth, fbHeight, sourceRc, Gamma);
// Tell SWRenderer we are now finished with it.
SWRenderer::SwapColorTexture();
// FifoPlayer is broken and never calls BeginFrame/EndFrame.
// Hence, we manually force a swap now. This emulates the behavior
// of hardware backends with XFB emulation disabled.
// TODO: Fix FifoPlayer by making proper use of VideoInterface!
// This requires careful synchronization since GPU commands
// are processed on a different thread than VI commands.
SWRenderer::Swap(fbWidth, fbHeight);
DebugUtil::OnFrameEnd(fbWidth, fbHeight);
}
} }
static void CopyToRam() static void CopyToRam()
@ -67,7 +43,7 @@ namespace EfbCopy
TextureEncoder::Encode(dest_ptr); TextureEncoder::Encode(dest_ptr);
} }
static void ClearEfb() void ClearEfb()
{ {
u32 clearColor = (bpmem.clearcolorAR & 0xff) << 24 | bpmem.clearcolorGB << 8 | (bpmem.clearcolorAR & 0xff00) >> 8; u32 clearColor = (bpmem.clearcolorAR & 0xff) << 24 | bpmem.clearcolorGB << 8 | (bpmem.clearcolorAR & 0xff00) >> 8;
@ -128,11 +104,6 @@ namespace EfbCopy
{ {
CopyToRam(); // FIXME: should use the rectangle we have already created above CopyToRam(); // FIXME: should use the rectangle we have already created above
} }
if (bpmem.triggerEFBCopy.clear)
{
ClearEfb();
}
} }
} }
} }

View File

@ -9,6 +9,7 @@
namespace EfbCopy namespace EfbCopy
{ {
// Copy the EFB to RAM as a texture format or XFB // Copy the EFB to RAM as a texture format or XFB
// Clear the EFB if needed
void CopyEfb(); void CopyEfb();
void ClearEfb();
} }

View File

@ -8,9 +8,9 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Core/HW/Memmap.h" #include "Core/HW/Memmap.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/EfbInterface.h" #include "VideoBackends/Software/EfbInterface.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/LookUpTables.h" #include "VideoCommon/LookUpTables.h"
#include "VideoCommon/PixelEngine.h" #include "VideoCommon/PixelEngine.h"
@ -31,11 +31,6 @@ namespace EfbInterface
return (x + y * EFB_WIDTH) * 3 + DEPTH_BUFFER_START; return (x + y * EFB_WIDTH) * 3 + DEPTH_BUFFER_START;
} }
void DoState(PointerWrap &p)
{
p.DoArray(efb);
}
static void SetPixelAlphaOnly(u32 offset, u8 a) static void SetPixelAlphaOnly(u32 offset, u8 a)
{ {
switch (bpmem.zcontrol.pixel_format) switch (bpmem.zcontrol.pixel_format)

View File

@ -58,8 +58,6 @@ namespace EfbInterface
void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma); void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma);
void BypassXFB(u8* texture, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma); void BypassXFB(u8* texture, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma);
void DoState(PointerWrap &p);
extern u32 perf_values[PQ_NUM_MEMBERS]; extern u32 perf_values[PQ_NUM_MEMBERS];
inline void IncPerfCounterQuadCount(PerfQueryType type) inline void IncPerfCounterQuadCount(PerfQueryType type)
{ {

View File

@ -77,16 +77,4 @@ struct OutputVertexData
#undef LINTERP #undef LINTERP
#undef LINTERP_INT #undef LINTERP_INT
} }
void DoState(PointerWrap &p)
{
mvPosition.DoState(p);
p.Do(projectedPosition);
screenPosition.DoState(p);
for (auto& vec : normal)
vec.DoState(p);
p.DoArray(color, sizeof color);
for (auto& vec : texCoords)
vec.DoState(p);
}
}; };

View File

@ -1,304 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Common/ChunkFile.h"
#include "Common/CommonTypes.h"
#include "Core/HW/Memmap.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/CPMemLoader.h"
#include "VideoBackends/Software/DebugUtil.h"
#include "VideoBackends/Software/OpcodeDecoder.h"
#include "VideoBackends/Software/SWCommandProcessor.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/SWVertexLoader.h"
#include "VideoBackends/Software/SWVideoConfig.h"
#include "VideoBackends/Software/XFMemLoader.h"
#include "VideoCommon/Fifo.h"
#include "VideoCommon/VertexLoaderUtils.h"
typedef void (*DecodingFunction)(u32);
namespace OpcodeDecoder
{
static DecodingFunction currentFunction = nullptr;
static u32 minCommandSize;
static u16 streamSize;
static u16 streamAddress;
static bool readOpcode;
static SWVertexLoader vertexLoader;
static bool inObjectStream;
static u8 lastPrimCmd;
void DoState(PointerWrap &p)
{
p.Do(minCommandSize);
// Not sure what is wrong with this. Something(s) in here is causing Dolphin to crash/hang when loading states saved from another run of Dolphin. Doesn't seem too important anyway...
//vertexLoader.DoState(p);
p.Do(readOpcode);
p.Do(inObjectStream);
p.Do(lastPrimCmd);
p.Do(streamSize);
p.Do(streamAddress);
if (p.GetMode() == PointerWrap::MODE_READ)
ResetDecoding();
}
static void DecodePrimitiveStream(u32 iBufferSize)
{
u32 vertexSize = vertexLoader.GetVertexSize();
bool skipPrimitives = g_bSkipCurrentFrame ||
swstats.thisFrame.numDrawnObjects < g_SWVideoConfig.drawStart ||
swstats.thisFrame.numDrawnObjects >= g_SWVideoConfig.drawEnd;
if (skipPrimitives)
{
while (streamSize > 0 && iBufferSize >= vertexSize)
{
g_video_buffer_read_ptr += vertexSize;
iBufferSize -= vertexSize;
streamSize--;
}
}
else
{
while (streamSize > 0 && iBufferSize >= vertexSize)
{
vertexLoader.LoadVertex();
iBufferSize -= vertexSize;
streamSize--;
}
}
if (streamSize == 0)
{
// return to normal command processing
ResetDecoding();
}
}
static void ReadXFData(u32 iBufferSize)
{
_assert_msg_(VIDEO, iBufferSize >= (u32)(streamSize * 4), "Underflow during standard opcode decoding");
u32 pData[16];
for (int i = 0; i < streamSize; i++)
pData[i] = DataRead<u32>();
SWLoadXFReg(streamSize, streamAddress, pData);
// return to normal command processing
ResetDecoding();
}
static void ExecuteDisplayList(u32 addr, u32 count)
{
u8 *videoDataSave = g_video_buffer_read_ptr;
u8 *dlStart = Memory::GetPointer(addr);
g_video_buffer_read_ptr = dlStart;
while (OpcodeDecoder::CommandRunnable(count))
{
OpcodeDecoder::Run(count);
// if data was read by the opcode decoder then the video data pointer changed
u32 readCount = (u32)(g_video_buffer_read_ptr - dlStart);
dlStart = g_video_buffer_read_ptr;
_assert_msg_(VIDEO, count >= readCount, "Display list underrun");
count -= readCount;
}
g_video_buffer_read_ptr = videoDataSave;
}
static void DecodeStandard(u32 bufferSize)
{
_assert_msg_(VIDEO, CommandRunnable(bufferSize), "Underflow during standard opcode decoding");
int Cmd = DataRead<u8>();
if (Cmd == GX_NOP)
return;
// Causes a SIGBUS error on Android
// XXX: Investigate
#ifndef ANDROID
// check if switching in or out of an object
// only used for debugging
if (inObjectStream && (Cmd & 0x87) != lastPrimCmd)
{
inObjectStream = false;
DebugUtil::OnObjectEnd();
}
if (Cmd & 0x80 && !inObjectStream)
{
inObjectStream = true;
lastPrimCmd = Cmd & 0x87;
DebugUtil::OnObjectBegin();
}
#endif
switch (Cmd)
{
case GX_NOP:
break;
case GX_LOAD_CP_REG: //0x08
{
u32 SubCmd = DataRead<u8>();
u32 Value = DataRead<u32>();
SWLoadCPReg(SubCmd, Value);
}
break;
case GX_LOAD_XF_REG:
{
u32 Cmd2 = DataRead<u32>();
streamSize = ((Cmd2 >> 16) & 15) + 1;
streamAddress = Cmd2 & 0xFFFF;
currentFunction = ReadXFData;
minCommandSize = streamSize * 4;
readOpcode = false;
}
break;
case GX_LOAD_INDX_A: //used for position matrices
SWLoadIndexedXF(DataRead<u32>(), 0xC);
break;
case GX_LOAD_INDX_B: //used for normal matrices
SWLoadIndexedXF(DataRead<u32>(), 0xD);
break;
case GX_LOAD_INDX_C: //used for postmatrices
SWLoadIndexedXF(DataRead<u32>(), 0xE);
break;
case GX_LOAD_INDX_D: //used for lights
SWLoadIndexedXF(DataRead<u32>(), 0xF);
break;
case GX_CMD_CALL_DL:
{
u32 dwAddr = DataRead<u32>();
u32 dwCount = DataRead<u32>();
ExecuteDisplayList(dwAddr, dwCount);
}
break;
case 0x44:
// zelda 4 swords calls it and checks the metrics registers after that
break;
case GX_CMD_INVL_VC:// Invalidate (vertex cache?)
DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)");
break;
case GX_LOAD_BP_REG: //0x61
{
u32 cmd = DataRead<u32>();
SWLoadBPReg(cmd);
}
break;
// draw primitives
default:
if ((Cmd & 0xC0) == 0x80)
{
u8 vatIndex = Cmd & GX_VAT_MASK;
u8 primitiveType = (Cmd & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT;
vertexLoader.SetFormat(vatIndex, primitiveType);
// switch to primitive processing
streamSize = DataRead<u16>();
currentFunction = DecodePrimitiveStream;
minCommandSize = vertexLoader.GetVertexSize();
readOpcode = false;
INCSTAT(swstats.thisFrame.numPrimatives);
DEBUG_LOG(VIDEO, "Draw begin");
}
else
{
PanicAlert("GFX: Unknown Opcode (0x%x).\n", Cmd);
break;
}
break;
}
}
void Init()
{
inObjectStream = false;
lastPrimCmd = 0;
ResetDecoding();
}
void ResetDecoding()
{
currentFunction = DecodeStandard;
minCommandSize = 1;
readOpcode = true;
}
bool CommandRunnable(u32 iBufferSize)
{
if (iBufferSize < minCommandSize)
return false;
if (readOpcode)
{
u8 Cmd = DataPeek<u8>(0);
u32 minSize = 1;
switch (Cmd)
{
case GX_LOAD_CP_REG: //0x08
minSize = 6;
break;
case GX_LOAD_XF_REG:
minSize = 5;
break;
case GX_LOAD_INDX_A: //used for position matrices
minSize = 5;
break;
case GX_LOAD_INDX_B: //used for normal matrices
minSize = 5;
break;
case GX_LOAD_INDX_C: //used for postmatrices
minSize = 5;
break;
case GX_LOAD_INDX_D: //used for lights
minSize = 5;
break;
case GX_CMD_CALL_DL:
minSize = 9;
break;
case GX_LOAD_BP_REG: //0x61
minSize = 5;
break;
// draw primitives
default:
if ((Cmd & 0xC0) == 0x80)
minSize = 3;
break;
}
return (iBufferSize >= minSize);
}
return true;
}
void Run(u32 iBufferSize)
{
currentFunction(iBufferSize);
}
}

View File

@ -1,52 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "Common/CommonTypes.h"
class PointerWrap;
namespace OpcodeDecoder
{
#define GX_NOP 0x00
#define GX_LOAD_BP_REG 0x61
#define GX_LOAD_CP_REG 0x08
#define GX_LOAD_XF_REG 0x10
#define GX_LOAD_INDX_A 0x20
#define GX_LOAD_INDX_B 0x28
#define GX_LOAD_INDX_C 0x30
#define GX_LOAD_INDX_D 0x38
#define GX_CMD_CALL_DL 0x40
#define GX_CMD_INVL_VC 0x48
#define GX_PRIMITIVE_MASK 0x38
#define GX_PRIMITIVE_SHIFT 3
#define GX_VAT_MASK 0x07
// These values are the values extracted using GX_PRIMITIVE_MASK
// and GX_PRIMITIVE_SHIFT.
// GX_DRAW_QUADS_2 behaves the same way as GX_DRAW_QUADS.
#define GX_DRAW_QUADS 0x0 //0x80
#define GX_DRAW_QUADS_2 0x1 //0x88
#define GX_DRAW_TRIANGLES 0x2 //0x90
#define GX_DRAW_TRIANGLE_STRIP 0x3 //0x98
#define GX_DRAW_TRIANGLE_FAN 0x4 //0xA0
#define GX_DRAW_LINES 0x5 //0xA8
#define GX_DRAW_LINE_STRIP 0x6 //0xB0
#define GX_DRAW_POINTS 0x7 //0xB8
void Init();
void ResetDecoding();
bool CommandRunnable(u32 iBufferSize);
void Run(u32 iBufferSize);
void DoState(PointerWrap &p);
}

View File

@ -6,15 +6,14 @@
#include <cstring> #include <cstring>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/EfbInterface.h" #include "VideoBackends/Software/EfbInterface.h"
#include "VideoBackends/Software/NativeVertexFormat.h" #include "VideoBackends/Software/NativeVertexFormat.h"
#include "VideoBackends/Software/Rasterizer.h" #include "VideoBackends/Software/Rasterizer.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/SWVideoConfig.h"
#include "VideoBackends/Software/Tev.h" #include "VideoBackends/Software/Tev.h"
#include "VideoBackends/Software/XFMemLoader.h"
#include "VideoCommon/BoundingBox.h" #include "VideoCommon/BoundingBox.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h"
namespace Rasterizer namespace Rasterizer
{ {
@ -38,28 +37,6 @@ static s32 scissorBottom = 0;
static Tev tev; static Tev tev;
static RasterBlock rasterBlock; static RasterBlock rasterBlock;
void DoState(PointerWrap &p)
{
ZSlope.DoState(p);
WSlope.DoState(p);
for (auto& color_slopes_1d : ColorSlopes)
for (Slope& color_slope : color_slopes_1d)
color_slope.DoState(p);
for (auto& tex_slopes_1d : TexSlopes)
for (Slope& tex_slope : tex_slopes_1d)
tex_slope.DoState(p);
p.Do(vertex0X);
p.Do(vertex0Y);
p.Do(vertexOffsetX);
p.Do(vertexOffsetY);
p.Do(scissorLeft);
p.Do(scissorTop);
p.Do(scissorRight);
p.Do(scissorBottom);
tev.DoState(p);
p.Do(rasterBlock);
}
void Init() void Init()
{ {
tev.Init(); tev.Init();
@ -121,14 +98,14 @@ void SetTevReg(int reg, int comp, bool konst, s16 color)
static void Draw(s32 x, s32 y, s32 xi, s32 yi) static void Draw(s32 x, s32 y, s32 xi, s32 yi)
{ {
INCSTAT(swstats.thisFrame.rasterizedPixels); INCSTAT(stats.thisFrame.rasterizedPixels);
float dx = vertexOffsetX + (float)(x - vertex0X); float dx = vertexOffsetX + (float)(x - vertex0X);
float dy = vertexOffsetY + (float)(y - vertex0Y); float dy = vertexOffsetY + (float)(y - vertex0Y);
s32 z = (s32)MathUtil::Clamp<float>(ZSlope.GetValue(dx, dy), 0.0f, 16777215.0f); s32 z = (s32)MathUtil::Clamp<float>(ZSlope.GetValue(dx, dy), 0.0f, 16777215.0f);
if (bpmem.UseEarlyDepthTest() && g_SWVideoConfig.bZComploc) if (bpmem.UseEarlyDepthTest() && g_ActiveConfig.bZComploc)
{ {
// TODO: Test if perf regs are incremented even if test is disabled // TODO: Test if perf regs are incremented even if test is disabled
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT_ZCOMPLOC); EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT_ZCOMPLOC);
@ -314,7 +291,7 @@ static void BuildBlock(s32 blockX, s32 blockY)
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2) void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
{ {
INCSTAT(swstats.thisFrame.numTrianglesDrawn); INCSTAT(stats.thisFrame.numTrianglesDrawn);
// adapted from http://devmaster.net/posts/6145/advanced-rasterization // adapted from http://devmaster.net/posts/6145/advanced-rasterization
@ -378,7 +355,7 @@ void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVer
// Many things might prevent us from reaching this line (culling, clipping, scissoring). // Many things might prevent us from reaching this line (culling, clipping, scissoring).
// However, the zslope is always guaranteed to be calculated unless all vertices are trivially rejected during clipping! // However, the zslope is always guaranteed to be calculated unless all vertices are trivially rejected during clipping!
// We're currently sloppy at this since we abort early if any of the culling/clipping/scissoring tests fail. // We're currently sloppy at this since we abort early if any of the culling/clipping/scissoring tests fail.
if (!bpmem.genMode.zfreeze || !g_SWVideoConfig.bZFreeze) if (!bpmem.genMode.zfreeze || !g_ActiveConfig.bZFreeze)
InitSlope(&ZSlope, v0->screenPosition[2], v1->screenPosition[2], v2->screenPosition[2], fltdx31, fltdx12, fltdy12, fltdy31); InitSlope(&ZSlope, v0->screenPosition[2], v1->screenPosition[2], v2->screenPosition[2], fltdx31, fltdx12, fltdy12, fltdy31);
for (unsigned int i = 0; i < bpmem.genMode.numcolchans; i++) for (unsigned int i = 0; i < bpmem.genMode.numcolchans; i++)

View File

@ -25,12 +25,6 @@ namespace Rasterizer
float f0; float f0;
float GetValue(float dx, float dy) { return f0 + (dfdx * dx) + (dfdy * dy); } float GetValue(float dx, float dy) { return f0 + (dfdx * dx) + (dfdy * dy); }
void DoState(PointerWrap &p)
{
p.Do(dfdx);
p.Do(dfdy);
p.Do(f0);
}
}; };
struct RasterBlockPixel struct RasterBlockPixel
@ -47,6 +41,4 @@ namespace Rasterizer
s32 TextureLod[16]; s32 TextureLod[16];
bool TextureLinear[16]; bool TextureLinear[16];
}; };
void DoState(PointerWrap &p);
} }

View File

@ -1,354 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <atomic>
#include "Common/Atomic.h"
#include "Common/ChunkFile.h"
#include "Common/CommonTypes.h"
#include "Common/FPURoundMode.h"
#include "Common/MathUtil.h"
#include "Common/Thread.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h"
#include "Core/HW/Memmap.h"
#include "Core/HW/MMIO.h"
#include "Core/HW/ProcessorInterface.h"
#include "VideoBackends/Software/OpcodeDecoder.h"
#include "VideoBackends/Software/SWCommandProcessor.h"
#include "VideoBackends/Software/VideoBackend.h"
#include "VideoCommon/Fifo.h"
#include "VideoCommon/VertexLoaderUtils.h"
namespace SWCommandProcessor
{
enum
{
GATHER_PIPE_SIZE = 32,
INT_CAUSE_CP = 0x800
};
// STATE_TO_SAVE
// variables
static const int commandBufferSize = 1024 * 1024;
static const int maxCommandBufferWrite = commandBufferSize - GATHER_PIPE_SIZE;
static u8 commandBuffer[commandBufferSize];
static u32 readPos;
static u32 writePos;
static int et_UpdateInterrupts;
static std::atomic<bool> interruptSet;
static std::atomic<bool> interruptWaiting;
static CPReg cpreg; // shared between gfx and emulator thread
void DoState(PointerWrap &p)
{
p.DoPOD(cpreg);
p.DoArray(commandBuffer, commandBufferSize);
p.Do(readPos);
p.Do(writePos);
p.Do(et_UpdateInterrupts);
p.Do(interruptSet);
p.Do(interruptWaiting);
// Is this right?
p.DoArray(g_video_buffer_read_ptr, writePos);
}
static void UpdateInterrupts_Wrapper(u64 userdata, int cyclesLate)
{
UpdateInterrupts(userdata);
}
static inline bool AtBreakpoint()
{
return cpreg.ctrl.BPEnable && (cpreg.readptr == cpreg.breakpt);
}
void Init()
{
cpreg.status.Hex = 0;
cpreg.status.CommandIdle = 1;
cpreg.status.ReadIdle = 1;
cpreg.ctrl.Hex = 0;
cpreg.clear.Hex = 0;
cpreg.bboxleft = 0;
cpreg.bboxtop = 0;
cpreg.bboxright = 0;
cpreg.bboxbottom = 0;
cpreg.token = 0;
et_UpdateInterrupts = CoreTiming::RegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper);
// internal buffer position
readPos = 0;
writePos = 0;
interruptSet.store(false);
interruptWaiting.store(false);
g_video_buffer_read_ptr = nullptr;
g_bSkipCurrentFrame = false;
}
void Shutdown()
{
}
void RunGpu()
{
if (!SConfig::GetInstance().bCPUThread)
{
// We are going to do FP math on the main thread so have to save the current state
FPURoundMode::SaveSIMDState();
FPURoundMode::LoadDefaultSIMDState();
// run the opcode decoder
do
{
RunBuffer();
} while (cpreg.ctrl.GPReadEnable && !AtBreakpoint() && cpreg.readptr != cpreg.writeptr);
FPURoundMode::LoadSIMDState();
}
}
void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
{
// Directly map reads and writes to the cpreg structure.
for (u32 i = 0; i < sizeof (cpreg) / sizeof (u16); ++i)
{
u16* ptr = ((u16*)&cpreg) + i;
mmio->Register(base | (i * 2),
MMIO::DirectRead<u16>(ptr),
MMIO::DirectWrite<u16>(ptr)
);
}
// Bleh. Apparently SWCommandProcessor does not know about regs 0x40 to
// 0x64...
for (u32 i = 0x40; i < 0x64; ++i)
{
mmio->Register(base | i,
MMIO::Constant<u16>(0),
MMIO::Nop<u16>()
);
}
// The low part of MMIO regs for FIFO addresses needs to be aligned to 32
// bytes.
u32 fifo_addr_lo_regs[] = {
CommandProcessor::FIFO_BASE_LO,
CommandProcessor::FIFO_END_LO,
CommandProcessor::FIFO_WRITE_POINTER_LO,
CommandProcessor::FIFO_READ_POINTER_LO,
CommandProcessor::FIFO_BP_LO,
CommandProcessor::FIFO_RW_DISTANCE_LO,
};
for (u32 reg : fifo_addr_lo_regs)
{
mmio->RegisterWrite(base | reg,
MMIO::DirectWrite<u16>(((u16*)&cpreg) + (reg / 2), 0xFFE0)
);
}
// The clear register needs to perform some more complicated operations on
// writes.
mmio->RegisterWrite(base | CommandProcessor::CLEAR_REGISTER,
MMIO::ComplexWrite<u16>([](u32, u16 val) {
UCPClearReg tmpClear(val);
if (tmpClear.ClearFifoOverflow)
cpreg.status.OverflowHiWatermark = 0;
if (tmpClear.ClearFifoUnderflow)
cpreg.status.UnderflowLoWatermark = 0;
})
);
}
void GatherPipeBursted()
{
if (cpreg.ctrl.GPLinkEnable)
{
DEBUG_LOG(COMMANDPROCESSOR,"\t WGP burst. write thru : %08x", cpreg.writeptr);
if (cpreg.writeptr == cpreg.fifoend)
cpreg.writeptr = cpreg.fifobase;
else
cpreg.writeptr += GATHER_PIPE_SIZE;
Common::AtomicAdd(cpreg.rwdistance, GATHER_PIPE_SIZE);
}
RunGpu();
}
void UpdateInterrupts(u64 userdata)
{
if (userdata)
{
interruptSet.store(true);
INFO_LOG(COMMANDPROCESSOR,"Interrupt set");
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true);
}
else
{
interruptSet.store(false);
INFO_LOG(COMMANDPROCESSOR,"Interrupt cleared");
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, false);
}
interruptWaiting.store(false);
}
void UpdateInterruptsFromVideoBackend(u64 userdata)
{
CoreTiming::ScheduleEvent_Threadsafe(0, et_UpdateInterrupts, userdata);
}
static void ReadFifo()
{
bool canRead = cpreg.readptr != cpreg.writeptr && writePos < (int)maxCommandBufferWrite;
bool atBreakpoint = AtBreakpoint();
if (canRead && !atBreakpoint)
{
// read from fifo
u8 *ptr = Memory::GetPointer(cpreg.readptr);
int bytesRead = 0;
do
{
// copy to buffer
memcpy(&commandBuffer[writePos], ptr, GATHER_PIPE_SIZE);
writePos += GATHER_PIPE_SIZE;
bytesRead += GATHER_PIPE_SIZE;
if (cpreg.readptr == cpreg.fifoend)
{
cpreg.readptr = cpreg.fifobase;
ptr = Memory::GetPointer(cpreg.readptr);
}
else
{
cpreg.readptr += GATHER_PIPE_SIZE;
ptr += GATHER_PIPE_SIZE;
}
canRead = cpreg.readptr != cpreg.writeptr && writePos < (int)maxCommandBufferWrite;
atBreakpoint = AtBreakpoint();
} while (canRead && !atBreakpoint);
Common::AtomicAdd(cpreg.rwdistance, -bytesRead);
}
}
static void SetStatus()
{
// overflow check
if (cpreg.rwdistance > cpreg.hiwatermark)
cpreg.status.OverflowHiWatermark = 1;
// underflow check
if (cpreg.rwdistance < cpreg.lowatermark)
cpreg.status.UnderflowLoWatermark = 1;
// breakpoint
if (cpreg.ctrl.BPEnable)
{
if (cpreg.breakpt == cpreg.readptr)
{
if (!cpreg.status.Breakpoint)
INFO_LOG(COMMANDPROCESSOR, "Hit breakpoint at %x", cpreg.readptr);
cpreg.status.Breakpoint = 1;
}
}
else
{
if (cpreg.status.Breakpoint)
INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %x", cpreg.readptr);
cpreg.status.Breakpoint = 0;
}
cpreg.status.ReadIdle = cpreg.readptr == cpreg.writeptr;
bool bpInt = cpreg.status.Breakpoint && cpreg.ctrl.BPInt;
bool ovfInt = cpreg.status.OverflowHiWatermark && cpreg.ctrl.FifoOverflowIntEnable;
bool undfInt = cpreg.status.UnderflowLoWatermark && cpreg.ctrl.FifoUnderflowIntEnable;
bool interrupt = bpInt || ovfInt || undfInt;
if (interrupt != interruptSet.load() && !interruptWaiting.load())
{
u64 userdata = interrupt?1:0;
if (SConfig::GetInstance().bCPUThread)
{
interruptWaiting.store(true);
SWCommandProcessor::UpdateInterruptsFromVideoBackend(userdata);
}
else
{
SWCommandProcessor::UpdateInterrupts(userdata);
}
}
}
bool RunBuffer()
{
// fifo is read 32 bytes at a time
// read fifo data to internal buffer
if (cpreg.ctrl.GPReadEnable)
ReadFifo();
SetStatus();
_dbg_assert_(COMMANDPROCESSOR, writePos >= readPos);
g_video_buffer_read_ptr = &commandBuffer[readPos];
u32 availableBytes = writePos - readPos;
while (OpcodeDecoder::CommandRunnable(availableBytes))
{
cpreg.status.CommandIdle = 0;
OpcodeDecoder::Run(availableBytes);
// if data was read by the opcode decoder then the video data pointer changed
readPos = (u32)(g_video_buffer_read_ptr - &commandBuffer[0]);
_dbg_assert_(VIDEO, writePos >= readPos);
availableBytes = writePos - readPos;
}
cpreg.status.CommandIdle = 1;
bool ranDecoder = false;
// move data remaining in the command buffer
if (readPos > 0)
{
memmove(&commandBuffer[0], &commandBuffer[readPos], availableBytes);
writePos -= readPos;
readPos = 0;
ranDecoder = true;
}
return ranDecoder;
}
void SetRendering(bool enabled)
{
g_bSkipCurrentFrame = !enabled;
}
} // end of namespace SWCommandProcessor

View File

@ -1,61 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "Common/CommonTypes.h"
#include "VideoCommon/CommandProcessor.h"
class PointerWrap;
namespace MMIO { class Mapping; }
namespace SWCommandProcessor
{
using UCPStatusReg = CommandProcessor::UCPStatusReg;
using UCPCtrlReg = CommandProcessor::UCPCtrlReg;
using UCPClearReg = CommandProcessor::UCPClearReg;
struct CPReg
{
UCPStatusReg status; // 0x00
UCPCtrlReg ctrl; // 0x02
UCPClearReg clear; // 0x04
u32 unk0; // 0x08
u16 unk1; // 0x0c
u16 token; // 0x0e
u16 bboxleft; // 0x10
u16 bboxtop; // 0x12
u16 bboxright; // 0x14
u16 bboxbottom; // 0x16
u32 unk2; // 0x18
u32 unk3; // 0x1c
u32 fifobase; // 0x20
u32 fifoend; // 0x24
u32 hiwatermark; // 0x28
u32 lowatermark; // 0x2c
u32 rwdistance; // 0x30
u32 writeptr; // 0x34
u32 readptr; // 0x38
u32 breakpt; // 0x3c
};
// Init
void Init();
void Shutdown();
void DoState(PointerWrap &p);
void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
bool RunBuffer();
void RunGpu();
// for CGPFIFO
void GatherPipeBursted();
void UpdateInterrupts(u64 userdata);
void UpdateInterruptsFromVideoBackend(u64 userdata);
void SetRendering(bool enabled);
} // end of namespace SWCommandProcessor

View File

@ -10,35 +10,30 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h" #include "Core/Core.h"
#include "Core/HW/Memmap.h"
#include "VideoBackends/Software/SWCommandProcessor.h" #include "VideoBackends/Software/EfbCopy.h"
#include "VideoBackends/Software/SWOGLWindow.h" #include "VideoBackends/Software/SWOGLWindow.h"
#include "VideoBackends/Software/SWRenderer.h" #include "VideoBackends/Software/SWRenderer.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoCommon/BoundingBox.h"
#include "VideoCommon/Fifo.h"
#include "VideoCommon/ImageWrite.h" #include "VideoCommon/ImageWrite.h"
#include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/VideoConfig.h"
static u8 *s_xfbColorTexture[2]; static u8 *s_xfbColorTexture[2];
static int s_currentColorTexture = 0; static int s_currentColorTexture = 0;
static std::atomic<bool> s_bScreenshot; SWRenderer::~SWRenderer()
static std::mutex s_criticalScreenshot;
static std::string s_sScreenshotName;
void SWRenderer::Init()
{
s_bScreenshot.store(false);
}
void SWRenderer::Shutdown()
{ {
delete[] s_xfbColorTexture[0]; delete[] s_xfbColorTexture[0];
delete[] s_xfbColorTexture[1]; delete[] s_xfbColorTexture[1];
} }
void SWRenderer::Prepare() void SWRenderer::Init()
{ {
s_xfbColorTexture[0] = new u8[MAX_XFB_WIDTH * MAX_XFB_HEIGHT * 4]; s_xfbColorTexture[0] = new u8[MAX_XFB_WIDTH * MAX_XFB_HEIGHT * 4];
s_xfbColorTexture[1] = new u8[MAX_XFB_WIDTH * MAX_XFB_HEIGHT * 4]; s_xfbColorTexture[1] = new u8[MAX_XFB_WIDTH * MAX_XFB_HEIGHT * 4];
@ -46,44 +41,17 @@ void SWRenderer::Prepare()
s_currentColorTexture = 0; s_currentColorTexture = 0;
} }
void SWRenderer::SetScreenshot(const char *_szFilename) void SWRenderer::Shutdown()
{ {
std::lock_guard<std::mutex> lk(s_criticalScreenshot); g_Config.bRunning = false;
s_sScreenshotName = _szFilename; UpdateActiveConfig();
s_bScreenshot.store(true);
} }
void SWRenderer::RenderText(const char* pstr, int left, int top, u32 color) void SWRenderer::RenderText(const std::string& pstr, int left, int top, u32 color)
{ {
SWOGLWindow::s_instance->PrintText(pstr, left, top, color); SWOGLWindow::s_instance->PrintText(pstr, left, top, color);
} }
void SWRenderer::DrawDebugText()
{
std::string debugtext;
if (g_SWVideoConfig.bShowStats)
{
debugtext += StringFromFormat("Objects: %i\n", swstats.thisFrame.numDrawnObjects);
debugtext += StringFromFormat("Primitives: %i\n", swstats.thisFrame.numPrimatives);
debugtext += StringFromFormat("Vertices Loaded: %i\n", swstats.thisFrame.numVerticesLoaded);
debugtext += StringFromFormat("Triangles Input: %i\n", swstats.thisFrame.numTrianglesIn);
debugtext += StringFromFormat("Triangles Rejected: %i\n", swstats.thisFrame.numTrianglesRejected);
debugtext += StringFromFormat("Triangles Culled: %i\n", swstats.thisFrame.numTrianglesCulled);
debugtext += StringFromFormat("Triangles Clipped: %i\n", swstats.thisFrame.numTrianglesClipped);
debugtext += StringFromFormat("Triangles Drawn: %i\n", swstats.thisFrame.numTrianglesDrawn);
debugtext += StringFromFormat("Rasterized Pix: %i\n", swstats.thisFrame.rasterizedPixels);
debugtext += StringFromFormat("TEV Pix In: %i\n", swstats.thisFrame.tevPixelsIn);
debugtext += StringFromFormat("TEV Pix Out: %i\n", swstats.thisFrame.tevPixelsOut);
}
// Render a shadow, and then the text.
SWRenderer::RenderText(debugtext.c_str(), 21, 21, 0xDD000000);
SWRenderer::RenderText(debugtext.c_str(), 20, 20, 0xFFFFFF00);
}
u8* SWRenderer::GetNextColorTexture() u8* SWRenderer::GetNextColorTexture()
{ {
return s_xfbColorTexture[!s_currentColorTexture]; return s_xfbColorTexture[!s_currentColorTexture];
@ -138,16 +106,42 @@ void SWRenderer::UpdateColorTexture(EfbInterface::yuv422_packed *xfb, u32 fbWidt
} }
// Called on the GPU thread // Called on the GPU thread
void SWRenderer::Swap(u32 fbWidth, u32 fbHeight) void SWRenderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, float Gamma)
{ {
// Save screenshot if (!g_bSkipCurrentFrame)
if (s_bScreenshot.load())
{ {
std::lock_guard<std::mutex> lk(s_criticalScreenshot);
TextureToPng(GetCurrentColorTexture(), fbWidth * 4, s_sScreenshotName, fbWidth, fbHeight, false); if (g_ActiveConfig.bUseXFB)
// Reset settings {
s_sScreenshotName.clear(); EfbInterface::yuv422_packed* xfb = (EfbInterface::yuv422_packed*) Memory::GetPointer(xfbAddr);
s_bScreenshot.store(false); UpdateColorTexture(xfb, fbWidth, fbHeight);
}
else
{
EfbInterface::BypassXFB(GetCurrentColorTexture(), fbWidth, fbHeight, rc, Gamma);
}
// Save screenshot
if (s_bScreenshot)
{
std::lock_guard<std::mutex> lk(s_criticalScreenshot);
if (TextureToPng(GetCurrentColorTexture(), fbWidth * 4, s_sScreenshotName, fbWidth, fbHeight, false))
OSD::AddMessage("Screenshot saved to " + s_sScreenshotName);
// Reset settings
s_sScreenshotName.clear();
s_bScreenshot = false;
s_screenshotCompleted.Set();
}
if (SConfig::GetInstance().m_DumpFrames)
{
static int frame_index = 0;
TextureToPng(GetCurrentColorTexture(), fbWidth * 4, StringFromFormat("%sframe%i_color.png",
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), frame_index), fbWidth, fbHeight, true);
frame_index++;
}
} }
OSD::DoCallbacks(OSD::CallbackType::OnFrame); OSD::DoCallbacks(OSD::CallbackType::OnFrame);
@ -156,7 +150,57 @@ void SWRenderer::Swap(u32 fbWidth, u32 fbHeight)
SWOGLWindow::s_instance->ShowImage(GetCurrentColorTexture(), fbWidth * 4, fbWidth, fbHeight, 1.0); SWOGLWindow::s_instance->ShowImage(GetCurrentColorTexture(), fbWidth * 4, fbWidth, fbHeight, 1.0);
swstats.frameCount++; UpdateActiveConfig();
swstats.ResetFrame(); }
Core::Callback_VideoCopiedToXFB(true); // FIXME: should this function be called FrameRendered?
u32 SWRenderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData)
{
u32 value = 0;
switch (type)
{
case PEEK_Z:
{
value = EfbInterface::GetDepth(x, y);
break;
}
case PEEK_COLOR:
{
u32 color = 0;
EfbInterface::GetColor(x, y, (u8*)&color);
// rgba to argb
value = (color >> 8) | (color & 0xff) << 24;
break;
}
default:
break;
}
return value;
}
u16 SWRenderer::BBoxRead(int index)
{
return BoundingBox::coords[index];
}
void SWRenderer::BBoxWrite(int index, u16 value)
{
BoundingBox::coords[index] = value;
}
TargetRectangle SWRenderer::ConvertEFBRectangle(const EFBRectangle& rc)
{
TargetRectangle result;
result.left = rc.left;
result.top = rc.top;
result.right = rc.right;
result.bottom = rc.bottom;
return result;
}
void SWRenderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z)
{
EfbCopy::ClearEfb();
} }

View File

@ -6,22 +6,40 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Thread.h" #include "Common/Thread.h"
#include "VideoBackends/Software/EfbInterface.h" #include "VideoBackends/Software/EfbInterface.h"
namespace SWRenderer #include "VideoCommon/RenderBase.h"
class SWRenderer : public Renderer
{ {
void Init(); public:
void Prepare(); ~SWRenderer() override;
void Shutdown();
void SetScreenshot(const char *_szFilename); static void Init();
void RenderText(const char* pstr, int left, int top, u32 color); static void Shutdown();
void DrawDebugText();
u8* GetNextColorTexture(); static u8* GetNextColorTexture();
u8* GetCurrentColorTexture(); static u8* GetCurrentColorTexture();
void SwapColorTexture(); void SwapColorTexture();
void UpdateColorTexture(EfbInterface::yuv422_packed *xfb, u32 fbWidth, u32 fbHeight); void UpdateColorTexture(EfbInterface::yuv422_packed *xfb, u32 fbWidth, u32 fbHeight);
void Swap(u32 fbWidth, u32 fbHeight); void RenderText(const std::string& pstr, int left, int top, u32 color) override;
} u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override;
void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override {};
u16 BBoxRead(int index) override;
void BBoxWrite(int index, u16 value) override;
int GetMaxTextureSize() override { return 16 * 1024; };
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, float Gamma) override;
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) override;
void ReinterpretPixelData(unsigned int convtype) override {}
bool SaveScreenshot(const std::string& filename, const TargetRectangle& rc) override { return true; };
};

View File

@ -1,18 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <cstring>
#include "VideoBackends/Software/SWStatistics.h"
SWStatistics swstats;
SWStatistics::SWStatistics()
{
frameCount = 0;
}
void SWStatistics::ResetFrame()
{
memset(&thisFrame, 0, sizeof(ThisFrame));
}

View File

@ -1,47 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Common/CommonTypes.h"
#include "VideoBackends/Software/SWVideoConfig.h"
#pragma once
struct SWStatistics
{
struct ThisFrame
{
u32 numDrawnObjects;
u32 numPrimatives;
u32 numVerticesLoaded;
u32 numVerticesOut;
u32 numTrianglesIn;
u32 numTrianglesRejected;
u32 numTrianglesCulled;
u32 numTrianglesClipped;
u32 numTrianglesDrawn;
u32 rasterizedPixels;
u32 tevPixelsIn;
u32 tevPixelsOut;
};
u32 frameCount;
SWStatistics();
ThisFrame thisFrame;
void ResetFrame();
};
extern SWStatistics swstats;
#if (STATISTICS)
#define INCSTAT(a) (a)++;
#define ADDSTAT(a,b) (a)+=(b);
#define SETSTAT(a,x) (a)=(int)(x);
#else
#define INCSTAT(a) ;
#define ADDSTAT(a,b) ;
#define SETSTAT(a,x) ;
#endif

View File

@ -7,22 +7,40 @@
#include "Common/ChunkFile.h" #include "Common/ChunkFile.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "VideoBackends/Software/CPMemLoader.h" #include "VideoBackends/Software/Clipper.h"
#include "VideoBackends/Software/DebugUtil.h"
#include "VideoBackends/Software/NativeVertexFormat.h" #include "VideoBackends/Software/NativeVertexFormat.h"
#include "VideoBackends/Software/Rasterizer.h"
#include "VideoBackends/Software/SetupUnit.h" #include "VideoBackends/Software/SetupUnit.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/SWVertexLoader.h" #include "VideoBackends/Software/SWVertexLoader.h"
#include "VideoBackends/Software/Tev.h"
#include "VideoBackends/Software/TransformUnit.h" #include "VideoBackends/Software/TransformUnit.h"
#include "VideoBackends/Software/XFMemLoader.h"
#include "VideoCommon/IndexGenerator.h"
#include "VideoCommon/OpcodeDecoding.h"
#include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/VertexLoaderBase.h" #include "VideoCommon/VertexLoaderBase.h"
#include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VertexLoaderManager.h"
#include "VideoCommon/VertexLoaderUtils.h" #include "VideoCommon/VertexLoaderUtils.h"
#include "VideoCommon/XFMemory.h"
class NullNativeVertexFormat : public NativeVertexFormat
SWVertexLoader::SWVertexLoader() :
m_VertexSize(0)
{ {
public:
NullNativeVertexFormat(const PortableVertexDeclaration& _vtx_decl) { vtx_decl = _vtx_decl; }
void SetupVertexPointers() override {}
};
NativeVertexFormat* SWVertexLoader::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{
return new NullNativeVertexFormat(vtx_decl);
}
SWVertexLoader::SWVertexLoader()
{
LocalVBuffer.resize(MAXVBUFFERSIZE);
LocalIBuffer.resize(MAXIBUFFERSIZE);
m_SetupUnit = new SetupUnit; m_SetupUnit = new SetupUnit;
} }
@ -32,25 +50,89 @@ SWVertexLoader::~SWVertexLoader()
m_SetupUnit = nullptr; m_SetupUnit = nullptr;
} }
void SWVertexLoader::SetFormat(u8 attributeIndex, u8 primitiveType) void SWVertexLoader::ResetBuffer(u32 stride)
{ {
memset(&m_Vertex, 0, sizeof(m_Vertex)); s_pCurBufferPointer = s_pBaseBufferPointer = LocalVBuffer.data();
s_pEndBufferPointer = s_pCurBufferPointer + LocalVBuffer.size();
IndexGenerator::Start(GetIndexBuffer());
}
m_attributeIndex = attributeIndex; void SWVertexLoader::vFlush(bool useDstAlpha)
{
DebugUtil::OnObjectBegin();
VertexLoaderUID uid(g_main_cp_state.vtx_desc, g_main_cp_state.vtx_attr[m_attributeIndex]); u8 primitiveType = 0;
m_CurrentLoader = m_VertexLoaderMap[uid].get(); switch (current_primitive_type)
if (!m_CurrentLoader)
{ {
m_VertexLoaderMap[uid] = VertexLoaderBase::CreateVertexLoader(g_main_cp_state.vtx_desc, g_main_cp_state.vtx_attr[m_attributeIndex]); case PRIMITIVE_POINTS:
m_CurrentLoader = m_VertexLoaderMap[uid].get(); primitiveType = GX_DRAW_POINTS;
break;
case PRIMITIVE_LINES:
primitiveType = GX_DRAW_LINES;
break;
case PRIMITIVE_TRIANGLES:
primitiveType = g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? GX_DRAW_TRIANGLE_STRIP : GX_DRAW_TRIANGLES;
break;
} }
m_VertexSize = m_CurrentLoader->m_VertexSize; m_SetupUnit->Init(primitiveType);
m_CurrentVat = &g_main_cp_state.vtx_attr[m_attributeIndex];
// set all states with are stored within video sw
Clipper::SetViewOffset();
Rasterizer::SetScissor();
for (int i = 0; i < 4; i++)
{
Rasterizer::SetTevReg(i, Tev::RED_C, false, PixelShaderManager::constants.colors[i][0]);
Rasterizer::SetTevReg(i, Tev::GRN_C, false, PixelShaderManager::constants.colors[i][1]);
Rasterizer::SetTevReg(i, Tev::BLU_C, false, PixelShaderManager::constants.colors[i][2]);
Rasterizer::SetTevReg(i, Tev::ALP_C, false, PixelShaderManager::constants.colors[i][3]);
Rasterizer::SetTevReg(i, Tev::RED_C, true, PixelShaderManager::constants.kcolors[i][0]);
Rasterizer::SetTevReg(i, Tev::GRN_C, true, PixelShaderManager::constants.kcolors[i][1]);
Rasterizer::SetTevReg(i, Tev::BLU_C, true, PixelShaderManager::constants.kcolors[i][2]);
Rasterizer::SetTevReg(i, Tev::ALP_C, true, PixelShaderManager::constants.kcolors[i][3]);
}
for (u32 i = 0; i < IndexGenerator::GetIndexLen(); i++)
{
u16 index = LocalIBuffer[i];
if (index == 0xffff)
{
// primitive restart
m_SetupUnit->Init(primitiveType);
continue;
}
memset(&m_Vertex, 0, sizeof(m_Vertex));
// Super Mario Sunshine requires those to be zero for those debug boxes.
memset(&m_Vertex.color, 0, sizeof(m_Vertex.color));
// parse the videocommon format to our own struct format (m_Vertex)
SetFormat(g_main_cp_state.last_id, primitiveType);
ParseVertex(VertexLoaderManager::GetCurrentVertexFormat()->GetVertexDeclaration(), index);
// transform this vertex so that it can be used for rasterization (outVertex)
OutputVertexData* outVertex = m_SetupUnit->GetVertex();
TransformUnit::TransformPosition(&m_Vertex, outVertex);
memset(&outVertex->normal, 0, sizeof(outVertex->normal));
if (VertexLoaderManager::g_current_components & VB_HAS_NRM0)
{
TransformUnit::TransformNormal(&m_Vertex, (VertexLoaderManager::g_current_components & VB_HAS_NRM2) != 0, outVertex);
}
TransformUnit::TransformColor(&m_Vertex, outVertex);
TransformUnit::TransformTexCoord(&m_Vertex, outVertex, m_TexGenSpecialCase);
// assemble and rasterize the primitive
m_SetupUnit->SetupVertex();
INCSTAT(stats.thisFrame.numVerticesLoaded)
}
DebugUtil::OnObjectEnd();
}
void SWVertexLoader::SetFormat(u8 attributeIndex, u8 primitiveType)
{
// matrix index from xf regs or cp memory? // matrix index from xf regs or cp memory?
if (xfmem.MatrixIndexA.PosNormalMtxIdx != g_main_cp_state.matrix_index_a.PosNormalMtxIdx || if (xfmem.MatrixIndexA.PosNormalMtxIdx != g_main_cp_state.matrix_index_a.PosNormalMtxIdx ||
xfmem.MatrixIndexA.Tex0MtxIdx != g_main_cp_state.matrix_index_a.Tex0MtxIdx || xfmem.MatrixIndexA.Tex0MtxIdx != g_main_cp_state.matrix_index_a.Tex0MtxIdx ||
@ -81,8 +163,6 @@ void SWVertexLoader::SetFormat(u8 attributeIndex, u8 primitiveType)
((g_main_cp_state.vtx_desc.Hex & 0x60600L) == g_main_cp_state.vtx_desc.Hex) && // only pos and tex coord 0 ((g_main_cp_state.vtx_desc.Hex & 0x60600L) == g_main_cp_state.vtx_desc.Hex) && // only pos and tex coord 0
(g_main_cp_state.vtx_desc.Tex0Coord != NOT_PRESENT) && (g_main_cp_state.vtx_desc.Tex0Coord != NOT_PRESENT) &&
(xfmem.texMtxInfo[0].projection == XF_TEXPROJ_ST); (xfmem.texMtxInfo[0].projection == XF_TEXPROJ_ST);
m_SetupUnit->Init(primitiveType);
} }
template <typename T, typename I> template <typename T, typename I>
@ -138,9 +218,10 @@ static void ReadVertexAttribute(T* dst, DataReader src, const AttributeFormat& f
} }
} }
void SWVertexLoader::ParseVertex(const PortableVertexDeclaration& vdec) void SWVertexLoader::ParseVertex(const PortableVertexDeclaration& vdec, int index)
{ {
DataReader src(m_LoadedVertices.data(), m_LoadedVertices.data() + m_LoadedVertices.size()); DataReader src(LocalVBuffer.data(), LocalVBuffer.data() + LocalVBuffer.size());
src.Skip(index * vdec.stride);
ReadVertexAttribute<float>(&m_Vertex.position[0], src, vdec.position, 0, 3, false); ReadVertexAttribute<float>(&m_Vertex.position[0], src, vdec.position, 0, 3, false);
@ -167,52 +248,3 @@ void SWVertexLoader::ParseVertex(const PortableVertexDeclaration& vdec)
ReadVertexAttribute<u8>(&m_Vertex.posMtx, src, vdec.posmtx, 0, 1, false); ReadVertexAttribute<u8>(&m_Vertex.posMtx, src, vdec.posmtx, 0, 1, false);
} }
void SWVertexLoader::LoadVertex()
{
const PortableVertexDeclaration& vdec = m_CurrentLoader->m_native_vtx_decl;
// reserve memory for the destination of the vertex loader
m_LoadedVertices.resize(vdec.stride + 4);
VertexLoaderManager::UpdateVertexArrayPointers();
// convert the vertex from the gc format to the videocommon (hardware optimized) format
u8* old = g_video_buffer_read_ptr;
int converted_vertices = m_CurrentLoader->RunVertices(
DataReader(g_video_buffer_read_ptr, nullptr), // src
DataReader(m_LoadedVertices.data(), m_LoadedVertices.data() + m_LoadedVertices.size()), // dst
1 // vertices
);
g_video_buffer_read_ptr = old + m_CurrentLoader->m_VertexSize;
if (converted_vertices == 0)
return;
// parse the videocommon format to our own struct format (m_Vertex)
ParseVertex(vdec);
// transform this vertex so that it can be used for rasterization (outVertex)
OutputVertexData* outVertex = m_SetupUnit->GetVertex();
TransformUnit::TransformPosition(&m_Vertex, outVertex);
memset(&outVertex->normal, 0, sizeof(outVertex->normal));
if (g_main_cp_state.vtx_desc.Normal != NOT_PRESENT)
{
TransformUnit::TransformNormal(&m_Vertex, m_CurrentVat->g0.NormalElements, outVertex);
}
TransformUnit::TransformColor(&m_Vertex, outVertex);
TransformUnit::TransformTexCoord(&m_Vertex, outVertex, m_TexGenSpecialCase);
// assemble and rasterize the primitive
m_SetupUnit->SetupVertex();
INCSTAT(swstats.thisFrame.numVerticesLoaded)
}
void SWVertexLoader::DoState(PointerWrap &p)
{
p.Do(m_VertexSize);
p.Do(*m_CurrentVat);
m_SetupUnit->DoState(p);
p.Do(m_TexGenSpecialCase);
}

View File

@ -6,45 +6,42 @@
#include <memory> #include <memory>
#include <unordered_map> #include <unordered_map>
#include <vector>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "VideoBackends/Software/CPMemLoader.h"
#include "VideoBackends/Software/NativeVertexFormat.h" #include "VideoBackends/Software/NativeVertexFormat.h"
#include "VideoCommon/VertexLoaderBase.h" #include "VideoCommon/VertexLoaderBase.h"
#include "VideoCommon/VertexManagerBase.h"
class PointerWrap;
class SetupUnit; class SetupUnit;
class SWVertexLoader class SWVertexLoader : public VertexManagerBase
{ {
u32 m_VertexSize; public:
SWVertexLoader();
~SWVertexLoader();
VAT* m_CurrentVat; NativeVertexFormat* CreateNativeVertexFormat(const PortableVertexDeclaration& vdec) override;
protected:
virtual void ResetBuffer(u32 stride);
u16* GetIndexBuffer() { return &LocalIBuffer[0]; }
private:
void vFlush(bool useDstAlpha) override;
std::vector<u8> LocalVBuffer;
std::vector<u16> LocalIBuffer;
InputVertexData m_Vertex; InputVertexData m_Vertex;
void ParseVertex(const PortableVertexDeclaration& vdec); void ParseVertex(const PortableVertexDeclaration& vdec, int index);
SetupUnit *m_SetupUnit; SetupUnit *m_SetupUnit;
bool m_TexGenSpecialCase; bool m_TexGenSpecialCase;
std::unordered_map<VertexLoaderUID, std::unique_ptr<VertexLoaderBase>> m_VertexLoaderMap;
std::vector<u8> m_LoadedVertices;
VertexLoaderBase* m_CurrentLoader;
u8 m_attributeIndex;
public: public:
SWVertexLoader();
~SWVertexLoader();
void SetFormat(u8 attributeIndex, u8 primitiveType); void SetFormat(u8 attributeIndex, u8 primitiveType);
u32 GetVertexSize() { return m_VertexSize; }
void LoadVertex();
void DoState(PointerWrap &p);
}; };

View File

@ -1,91 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Common/FileUtil.h"
#include "Common/IniFile.h"
#include "VideoBackends/Software/SWVideoConfig.h"
SWVideoConfig g_SWVideoConfig;
SWVideoConfig::SWVideoConfig()
{
bFullscreen = false;
bHideCursor = false;
renderToMainframe = false;
bBypassXFB = false;
bShowStats = false;
bDumpTextures = false;
bDumpObjects = false;
bZComploc = true;
bZFreeze = true;
bDumpTevStages = false;
bDumpTevTextureFetches = false;
drawStart = 0;
drawEnd = 100000;
}
void SWVideoConfig::Load(const char* ini_file)
{
IniFile iniFile;
iniFile.Load(ini_file);
IniFile::Section* hardware = iniFile.GetOrCreateSection("Hardware");
hardware->Get("Fullscreen", &bFullscreen, 0); // Hardware
hardware->Get("RenderToMainframe", &renderToMainframe, false);
IniFile::Section* rendering = iniFile.GetOrCreateSection("Rendering");
rendering->Get("BypassXFB", &bBypassXFB, false);
rendering->Get("ZComploc", &bZComploc, true);
rendering->Get("ZFreeze", &bZFreeze, true);
IniFile::Section* info = iniFile.GetOrCreateSection("Info");
info->Get("ShowStats", &bShowStats, false);
IniFile::Section* utility = iniFile.GetOrCreateSection("Utility");
utility->Get("DumpTexture", &bDumpTextures, false);
utility->Get("DumpObjects", &bDumpObjects, false);
utility->Get("DumpTevStages", &bDumpTevStages, false);
utility->Get("DumpTevTexFetches", &bDumpTevTextureFetches, false);
IniFile::Section* misc = iniFile.GetOrCreateSection("Misc");
misc->Get("DrawStart", &drawStart, 0);
misc->Get("DrawEnd", &drawEnd, 100000);
}
void SWVideoConfig::Save(const char* ini_file)
{
IniFile iniFile;
iniFile.Load(ini_file);
IniFile::Section* hardware = iniFile.GetOrCreateSection("Hardware");
hardware->Set("Fullscreen", bFullscreen);
hardware->Set("RenderToMainframe", renderToMainframe);
IniFile::Section* rendering = iniFile.GetOrCreateSection("Rendering");
rendering->Set("BypassXFB", bBypassXFB);
rendering->Set("ZComploc", bZComploc);
rendering->Set("ZFreeze", bZFreeze);
IniFile::Section* info = iniFile.GetOrCreateSection("Info");
info->Set("ShowStats", bShowStats);
IniFile::Section* utility = iniFile.GetOrCreateSection("Utility");
utility->Set("DumpTexture", bDumpTextures);
utility->Set("DumpObjects", bDumpObjects);
utility->Set("DumpTevStages", bDumpTevStages);
utility->Set("DumpTevTexFetches", bDumpTevTextureFetches);
IniFile::Section* misc = iniFile.GetOrCreateSection("Misc");
misc->Set("DrawStart", drawStart);
misc->Set("DrawEnd", drawEnd);
iniFile.Save(ini_file);
}

View File

@ -1,43 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "Common/CommonTypes.h"
#include "Common/NonCopyable.h"
#define STATISTICS 1
// NEVER inherit from this class.
struct SWVideoConfig : NonCopyable
{
SWVideoConfig();
void Load(const char* ini_file);
void Save(const char* ini_file);
// General
bool bFullscreen;
bool bHideCursor;
bool renderToMainframe;
bool bBypassXFB;
// Emulation features
bool bZComploc;
bool bZFreeze;
bool bShowStats;
bool bDumpTextures;
bool bDumpObjects;
// Debug only
bool bDumpTevStages;
bool bDumpTevTextureFetches;
u32 drawStart;
u32 drawEnd;
};
extern SWVideoConfig g_SWVideoConfig;

View File

@ -3,6 +3,7 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <atomic> #include <atomic>
#include <memory>
#include <string> #include <string>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
@ -16,25 +17,29 @@
#include "Core/HW/Memmap.h" #include "Core/HW/Memmap.h"
#include "Core/HW/VideoInterface.h" #include "Core/HW/VideoInterface.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/Clipper.h" #include "VideoBackends/Software/Clipper.h"
#include "VideoBackends/Software/DebugUtil.h" #include "VideoBackends/Software/DebugUtil.h"
#include "VideoBackends/Software/EfbCopy.h"
#include "VideoBackends/Software/EfbInterface.h" #include "VideoBackends/Software/EfbInterface.h"
#include "VideoBackends/Software/OpcodeDecoder.h"
#include "VideoBackends/Software/Rasterizer.h" #include "VideoBackends/Software/Rasterizer.h"
#include "VideoBackends/Software/SWCommandProcessor.h"
#include "VideoBackends/Software/SWOGLWindow.h" #include "VideoBackends/Software/SWOGLWindow.h"
#include "VideoBackends/Software/SWRenderer.h" #include "VideoBackends/Software/SWRenderer.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/SWVertexLoader.h" #include "VideoBackends/Software/SWVertexLoader.h"
#include "VideoBackends/Software/SWVideoConfig.h"
#include "VideoBackends/Software/VideoBackend.h" #include "VideoBackends/Software/VideoBackend.h"
#include "VideoBackends/Software/XFMemLoader.h"
#include "VideoCommon/BoundingBox.h" #include "VideoCommon/BPStructs.h"
#include "VideoCommon/CommandProcessor.h"
#include "VideoCommon/Fifo.h" #include "VideoCommon/Fifo.h"
#include "VideoCommon/Fifo.h"
#include "VideoCommon/IndexGenerator.h"
#include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/OpcodeDecoding.h"
#include "VideoCommon/PixelEngine.h" #include "VideoCommon/PixelEngine.h"
#include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/TextureCacheBase.h"
#include "VideoCommon/VertexLoaderManager.h"
#include "VideoCommon/VertexShaderManager.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h" #include "VideoCommon/XFMemory.h"
#define VSYNC_ENABLED 0 #define VSYNC_ENABLED 0
@ -51,6 +56,86 @@ static volatile struct
namespace SW namespace SW
{ {
class PerfQuery : public PerfQueryBase
{
public:
PerfQuery() {}
~PerfQuery() {}
void EnableQuery(PerfQueryGroup type) override {}
void DisableQuery(PerfQueryGroup type) override {}
void ResetQuery() override
{
memset(EfbInterface::perf_values, 0, sizeof(EfbInterface::perf_values));
}
u32 GetQueryResult(PerfQueryType type) override
{
return EfbInterface::perf_values[type];
};
void FlushResults() override {}
bool IsFlushed() const {return true;};
};
class TextureCache : public TextureCacheBase
{
public:
void CompileShaders() override {};
void DeleteShaders() override {};
void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, TlutFormat format) override {};
void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect,
bool isIntensity, bool scaleByHalf) override
{
EfbCopy::CopyEfb();
}
private:
struct TCacheEntry : TCacheEntryBase
{
TCacheEntry(const TCacheEntryConfig& _config) : TCacheEntryBase(_config) {}
~TCacheEntry() {}
void Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level) override {}
void FromRenderTarget(u8* dst, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect,
bool scaleByHalf, unsigned int cbufid, const float *colmat) override
{
EfbCopy::CopyEfb();
}
void CopyRectangleFromTexture(
const TCacheEntryBase* source,
const MathUtil::Rectangle<int>& srcrect,
const MathUtil::Rectangle<int>& dstrect) override {}
void Bind(unsigned int stage) override {}
bool Save(const std::string& filename, unsigned int level) override { return false; }
};
TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) override
{
return new TCacheEntry(config);
}
};
class XFBSource : public XFBSourceBase
{
void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override {}
void CopyEFB(float Gamma) override {}
};
class FramebufferManager : public FramebufferManagerBase
{
std::unique_ptr<XFBSourceBase> CreateXFBSource(unsigned int target_width, unsigned int target_height, unsigned int layers) override { return std::make_unique<XFBSource>(); }
void GetTargetSize(unsigned int* width, unsigned int* height) override {};
void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma = 1.0f) override
{
EfbCopy::CopyEfb();
}
};
static std::atomic<bool> fifoStateRun; static std::atomic<bool> fifoStateRun;
static std::atomic<bool> emuRunningState; static std::atomic<bool> emuRunningState;
static std::mutex m_csSWVidOccupied; static std::mutex m_csSWVidOccupied;
@ -65,93 +150,57 @@ std::string VideoSoftware::GetDisplayName() const
return "Software Renderer"; return "Software Renderer";
} }
static void InitBackendInfo()
{
g_Config.backend_info.APIType = API_NONE;
g_Config.backend_info.bSupports3DVision = false;
g_Config.backend_info.bSupportsDualSourceBlend = true;
g_Config.backend_info.bSupportsEarlyZ = true;
g_Config.backend_info.bSupportsOversizedViewports = true;
g_Config.backend_info.bSupportsPrimitiveRestart = false;
// aamodes
g_Config.backend_info.AAModes = {1};
}
void VideoSoftware::ShowConfig(void *hParent) void VideoSoftware::ShowConfig(void *hParent)
{ {
if (!m_initialized)
InitBackendInfo();
Host_ShowVideoConfig(hParent, GetDisplayName(), "gfx_software"); Host_ShowVideoConfig(hParent, GetDisplayName(), "gfx_software");
} }
bool VideoSoftware::Initialize(void *window_handle) bool VideoSoftware::Initialize(void *window_handle)
{ {
g_SWVideoConfig.Load((File::GetUserPath(D_CONFIG_IDX) + "gfx_software.ini").c_str()); InitializeShared();
InitBackendInfo();
g_Config.Load((File::GetUserPath(D_CONFIG_IDX) + "gfx_software.ini").c_str());
g_Config.GameIniLoad();
g_Config.UpdateProjectionHack();
g_Config.VerifyValidity();
UpdateActiveConfig();
SWOGLWindow::Init(window_handle); SWOGLWindow::Init(window_handle);
InitBPMemory();
InitXFMemory();
SWCommandProcessor::Init();
PixelEngine::Init(); PixelEngine::Init();
OpcodeDecoder::Init();
Clipper::Init(); Clipper::Init();
Rasterizer::Init(); Rasterizer::Init();
SWRenderer::Init(); SWRenderer::Init();
DebugUtil::Init(); DebugUtil::Init();
// Do our OSD callbacks
OSD::DoCallbacks(OSD::CallbackType::Initialization);
m_initialized = true; m_initialized = true;
return true; return true;
} }
void VideoSoftware::DoState(PointerWrap& p)
{
bool software = true;
p.Do(software);
if (p.GetMode() == PointerWrap::MODE_READ && software == false)
// change mode to abort load of incompatible save state.
p.SetMode(PointerWrap::MODE_VERIFY);
// TODO: incomplete?
SWCommandProcessor::DoState(p);
PixelEngine::DoState(p);
EfbInterface::DoState(p);
OpcodeDecoder::DoState(p);
Clipper::DoState(p);
p.Do(xfmem);
p.Do(bpmem);
p.DoPOD(swstats);
// CP Memory
DoCPState(p);
}
void VideoSoftware::CheckInvalidState()
{
// there is no state to invalidate
}
void VideoSoftware::PauseAndLock(bool doLock, bool unpauseOnUnlock)
{
if (doLock)
{
EmuStateChange(EMUSTATE_CHANGE_PAUSE);
if (!Core::IsGPUThread())
m_csSWVidOccupied.lock();
}
else
{
if (unpauseOnUnlock)
EmuStateChange(EMUSTATE_CHANGE_PLAY);
if (!Core::IsGPUThread())
m_csSWVidOccupied.unlock();
}
}
void VideoSoftware::RunLoop(bool enable)
{
emuRunningState.store(enable);
}
void VideoSoftware::EmuStateChange(EMUSTATE_CHANGE newState)
{
emuRunningState.store(newState == EMUSTATE_CHANGE_PLAY);
}
void VideoSoftware::Shutdown() void VideoSoftware::Shutdown()
{ {
m_initialized = false; m_initialized = false;
// TODO: should be in Video_Cleanup
SWRenderer::Shutdown();
DebugUtil::Shutdown();
// Do our OSD callbacks // Do our OSD callbacks
OSD::DoCallbacks(OSD::CallbackType::Shutdown); OSD::DoCallbacks(OSD::CallbackType::Shutdown);
@ -160,186 +209,54 @@ void VideoSoftware::Shutdown()
void VideoSoftware::Video_Cleanup() void VideoSoftware::Video_Cleanup()
{ {
if (g_renderer)
{
Fifo_Shutdown();
SWRenderer::Shutdown();
DebugUtil::Shutdown();
// The following calls are NOT Thread Safe
// And need to be called from the video thread
SWRenderer::Shutdown();
VertexLoaderManager::Shutdown();
g_framebuffer_manager.reset();
g_texture_cache.reset();
VertexShaderManager::Shutdown();
PixelShaderManager::Shutdown();
g_perf_query.reset();
g_vertex_manager.reset();
OpcodeDecoder_Shutdown();
g_renderer.reset();
}
} }
// This is called after Video_Initialize() from the Core // This is called after Video_Initialize() from the Core
void VideoSoftware::Video_Prepare() void VideoSoftware::Video_Prepare()
{ {
// Do our OSD callbacks g_renderer = std::make_unique<SWRenderer>();
OSD::DoCallbacks(OSD::CallbackType::Initialization);
SWRenderer::Prepare(); CommandProcessor::Init();
PixelEngine::Init();
BPInit();
g_vertex_manager = std::make_unique<SWVertexLoader>();
g_perf_query = std::make_unique<PerfQuery>();
Fifo_Init(); // must be done before OpcodeDecoder_Init()
OpcodeDecoder_Init();
IndexGenerator::Init();
VertexShaderManager::Init();
PixelShaderManager::Init();
g_texture_cache = std::make_unique<TextureCache>();
SWRenderer::Init();
VertexLoaderManager::Init();
g_framebuffer_manager = std::make_unique<FramebufferManager>();
// Notify the core that the video backend is ready
Host_Message(WM_USER_CREATE);
INFO_LOG(VIDEO, "Video backend initialized."); INFO_LOG(VIDEO, "Video backend initialized.");
} }
// Run from the CPU thread (from VideoInterface.cpp)
void VideoSoftware::Video_BeginField(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight)
{
// XXX: fbStride should be implemented properly here
// If stride isn't implemented then there are problems with XFB
// Animal Crossing is a good example for this.
s_beginFieldArgs.xfbAddr = xfbAddr;
s_beginFieldArgs.fbWidth = fbWidth;
s_beginFieldArgs.fbHeight = fbHeight;
}
// Run from the CPU thread (from VideoInterface.cpp)
void VideoSoftware::Video_EndField()
{
// Techincally the XFB is continually rendered out scanline by scanline between
// BeginField and EndFeild, We could possibly get away with copying out the whole thing
// at BeginField for less lag, but for the safest emulation we run it here.
if (g_bSkipCurrentFrame || s_beginFieldArgs.xfbAddr == 0)
{
swstats.frameCount++;
swstats.ResetFrame();
Core::Callback_VideoCopiedToXFB(false);
return;
}
if (!g_SWVideoConfig.bBypassXFB)
{
EfbInterface::yuv422_packed *xfb = (EfbInterface::yuv422_packed *) Memory::GetPointer(s_beginFieldArgs.xfbAddr);
SWRenderer::UpdateColorTexture(xfb, s_beginFieldArgs.fbWidth, s_beginFieldArgs.fbHeight);
}
// Ideally we would just move all the OpenGL context stuff to the CPU thread,
// but this gets messy when the hardware rasterizer is enabled.
// And neobrain loves his hardware rasterizer.
// If BypassXFB has already done a swap (cf. EfbCopy::CopyToXfb), skip this.
if (!g_SWVideoConfig.bBypassXFB)
{
// Dump frame if needed
DebugUtil::OnFrameEnd(s_beginFieldArgs.fbWidth, s_beginFieldArgs.fbHeight);
// If we are in dual core mode, notify the GPU thread about the new color texture.
if (SConfig::GetInstance().bCPUThread)
s_swapRequested.store(true);
else
SWRenderer::Swap(s_beginFieldArgs.fbWidth, s_beginFieldArgs.fbHeight);
}
}
u32 VideoSoftware::Video_AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData)
{
u32 value = 0;
switch (type)
{
case PEEK_Z:
{
value = EfbInterface::GetDepth(x, y);
break;
}
case POKE_Z:
break;
case PEEK_COLOR:
{
u32 color = 0;
EfbInterface::GetColor(x, y, (u8*)&color);
// rgba to argb
value = (color >> 8) | (color & 0xff) << 24;
break;
}
case POKE_COLOR:
break;
}
return value;
}
u32 VideoSoftware::Video_GetQueryResult(PerfQueryType type)
{
return EfbInterface::perf_values[type];
}
u16 VideoSoftware::Video_GetBoundingBox(int index)
{
return BoundingBox::coords[index];
}
bool VideoSoftware::Video_Screenshot(const std::string& filename)
{
SWRenderer::SetScreenshot(filename.c_str());
return true;
}
// Run from the graphics thread
static void VideoFifo_CheckSwapRequest()
{
if (s_swapRequested.load())
{
SWRenderer::Swap(s_beginFieldArgs.fbWidth, s_beginFieldArgs.fbHeight);
s_swapRequested.store(false);
}
}
// -------------------------------
// Enter and exit the video loop
// -------------------------------
void VideoSoftware::Video_EnterLoop()
{
std::lock_guard<std::mutex> lk(m_csSWVidOccupied);
fifoStateRun.store(true);
while (fifoStateRun.load())
{
VideoFifo_CheckSwapRequest();
g_video_backend->PeekMessages();
if (!SWCommandProcessor::RunBuffer())
{
Common::YieldCPU();
}
while (!emuRunningState.load() && fifoStateRun.load())
{
g_video_backend->PeekMessages();
VideoFifo_CheckSwapRequest();
m_csSWVidOccupied.unlock();
Common::SleepCurrentThread(1);
m_csSWVidOccupied.lock();
}
}
}
void VideoSoftware::Video_ExitLoop()
{
fifoStateRun.store(false);
}
// TODO : could use the OSD class in video common, we would need to implement the Renderer class
// however most of it is useless for the SW backend so we could as well move it to its own class
void VideoSoftware::Video_AddMessage(const std::string& msg, u32 milliseconds)
{
}
void VideoSoftware::Video_ClearMessages()
{
}
void VideoSoftware::Video_SetRendering(bool bEnabled)
{
SWCommandProcessor::SetRendering(bEnabled);
}
void VideoSoftware::Video_GatherPipeBursted()
{
SWCommandProcessor::GatherPipeBursted();
}
void VideoSoftware::RegisterCPMMIO(MMIO::Mapping* mmio, u32 base)
{
SWCommandProcessor::RegisterMMIO(mmio, base);
}
// Draw messages on top of the screen
unsigned int VideoSoftware::PeekMessages() unsigned int VideoSoftware::PeekMessages()
{ {
return SWOGLWindow::s_instance->PeekMessages(); return SWOGLWindow::s_instance->PeekMessages();

View File

@ -4,11 +4,9 @@
#include "Common/ChunkFile.h" #include "Common/ChunkFile.h"
#include "VideoBackends/Software/Clipper.h" #include "VideoBackends/Software/Clipper.h"
#include "VideoBackends/Software/CPMemLoader.h"
#include "VideoBackends/Software/OpcodeDecoder.h"
#include "VideoBackends/Software/SetupUnit.h" #include "VideoBackends/Software/SetupUnit.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoCommon/OpcodeDecoding.h"
void SetupUnit::Init(u8 primitiveType) void SetupUnit::Init(u8 primitiveType)
{ {
@ -167,20 +165,3 @@ void SetupUnit::SetupLineStrip()
void SetupUnit::SetupPoint() void SetupUnit::SetupPoint()
{} {}
void SetupUnit::DoState(PointerWrap &p)
{
// TODO: some or all of this is making the save states stop working once Dolphin is closed...sometimes (usually)
// I have no idea what specifically is wrong, or if this is even important. Disabling it doesn't seem to make any noticible difference...
/* p.Do(m_PrimType);
p.Do(m_VertexCounter);
for (int i = 0; i < 3; ++i)
m_Vertices[i].DoState(p);
if (p.GetMode() == PointerWrap::MODE_READ)
{
m_VertPointer[0] = &m_Vertices[0];
m_VertPointer[1] = &m_Vertices[1];
m_VertPointer[2] = &m_Vertices[2];
m_VertWritePointer = m_VertPointer[0];
}*/
}

View File

@ -7,8 +7,6 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "VideoBackends/Software/NativeVertexFormat.h" #include "VideoBackends/Software/NativeVertexFormat.h"
class PointerWrap;
class SetupUnit class SetupUnit
{ {
u8 m_PrimType; u8 m_PrimType;
@ -32,5 +30,4 @@ public:
OutputVertexData* GetVertex(); OutputVertexData* GetVertex();
void SetupVertex(); void SetupVertex();
void DoState(PointerWrap &p);
}; };

View File

@ -35,52 +35,38 @@
</ImportGroup> </ImportGroup>
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
<ItemGroup> <ItemGroup>
<ClCompile Include="BPMemLoader.cpp" />
<ClCompile Include="Clipper.cpp" /> <ClCompile Include="Clipper.cpp" />
<ClCompile Include="CPMemLoader.cpp" />
<ClCompile Include="DebugUtil.cpp" /> <ClCompile Include="DebugUtil.cpp" />
<ClCompile Include="EfbCopy.cpp" /> <ClCompile Include="EfbCopy.cpp" />
<ClCompile Include="EfbInterface.cpp" /> <ClCompile Include="EfbInterface.cpp" />
<ClCompile Include="OpcodeDecoder.cpp" />
<ClCompile Include="Rasterizer.cpp" /> <ClCompile Include="Rasterizer.cpp" />
<ClCompile Include="SetupUnit.cpp" /> <ClCompile Include="SetupUnit.cpp" />
<ClCompile Include="SWCommandProcessor.cpp" />
<ClCompile Include="SWmain.cpp" /> <ClCompile Include="SWmain.cpp" />
<ClCompile Include="SWOGLWindow.cpp" /> <ClCompile Include="SWOGLWindow.cpp" />
<ClCompile Include="SWRenderer.cpp" /> <ClCompile Include="SWRenderer.cpp" />
<ClCompile Include="SWStatistics.cpp" />
<ClCompile Include="SWVertexLoader.cpp" /> <ClCompile Include="SWVertexLoader.cpp" />
<ClCompile Include="SWVideoConfig.cpp" />
<ClCompile Include="Tev.cpp" /> <ClCompile Include="Tev.cpp" />
<ClCompile Include="TextureEncoder.cpp" /> <ClCompile Include="TextureEncoder.cpp" />
<ClCompile Include="TextureSampler.cpp" /> <ClCompile Include="TextureSampler.cpp" />
<ClCompile Include="TransformUnit.cpp" /> <ClCompile Include="TransformUnit.cpp" />
<ClCompile Include="XFMemLoader.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="BPMemLoader.h" />
<ClInclude Include="Clipper.h" /> <ClInclude Include="Clipper.h" />
<ClInclude Include="CPMemLoader.h" />
<ClInclude Include="DebugUtil.h" /> <ClInclude Include="DebugUtil.h" />
<ClInclude Include="EfbCopy.h" /> <ClInclude Include="EfbCopy.h" />
<ClInclude Include="EfbInterface.h" /> <ClInclude Include="EfbInterface.h" />
<ClInclude Include="NativeVertexFormat.h" /> <ClInclude Include="NativeVertexFormat.h" />
<ClInclude Include="OpcodeDecoder.h" />
<ClInclude Include="Rasterizer.h" /> <ClInclude Include="Rasterizer.h" />
<ClInclude Include="SetupUnit.h" /> <ClInclude Include="SetupUnit.h" />
<ClInclude Include="SWCommandProcessor.h" />
<ClInclude Include="SWOGLWindow.h" /> <ClInclude Include="SWOGLWindow.h" />
<ClInclude Include="SWRenderer.h" /> <ClInclude Include="SWRenderer.h" />
<ClInclude Include="SWStatistics.h" />
<ClInclude Include="SWVertexLoader.h" /> <ClInclude Include="SWVertexLoader.h" />
<ClInclude Include="SWVideoConfig.h" />
<ClInclude Include="Tev.h" /> <ClInclude Include="Tev.h" />
<ClInclude Include="TextureEncoder.h" /> <ClInclude Include="TextureEncoder.h" />
<ClInclude Include="TextureSampler.h" /> <ClInclude Include="TextureSampler.h" />
<ClInclude Include="TransformUnit.h" /> <ClInclude Include="TransformUnit.h" />
<ClInclude Include="Vec3.h" /> <ClInclude Include="Vec3.h" />
<ClInclude Include="VideoBackend.h" /> <ClInclude Include="VideoBackend.h" />
<ClInclude Include="XFMemLoader.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Text Include="CMakeLists.txt" /> <Text Include="CMakeLists.txt" />

View File

@ -8,12 +8,13 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "VideoBackends/Software/DebugUtil.h" #include "VideoBackends/Software/DebugUtil.h"
#include "VideoBackends/Software/EfbInterface.h" #include "VideoBackends/Software/EfbInterface.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/SWVideoConfig.h"
#include "VideoBackends/Software/Tev.h" #include "VideoBackends/Software/Tev.h"
#include "VideoBackends/Software/TextureSampler.h" #include "VideoBackends/Software/TextureSampler.h"
#include "VideoBackends/Software/XFMemLoader.h"
#include "VideoCommon/BoundingBox.h" #include "VideoCommon/BoundingBox.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h"
#ifdef _DEBUG #ifdef _DEBUG
#define ALLOW_TEV_DUMPS 1 #define ALLOW_TEV_DUMPS 1
@ -509,7 +510,7 @@ void Tev::Draw()
_assert_(Position[0] >= 0 && Position[0] < EFB_WIDTH); _assert_(Position[0] >= 0 && Position[0] < EFB_WIDTH);
_assert_(Position[1] >= 0 && Position[1] < EFB_HEIGHT); _assert_(Position[1] >= 0 && Position[1] < EFB_HEIGHT);
INCSTAT(swstats.thisFrame.tevPixelsIn); INCSTAT(stats.thisFrame.tevPixelsIn);
for (unsigned int stageNum = 0; stageNum < bpmem.genMode.numindstages; stageNum++) for (unsigned int stageNum = 0; stageNum < bpmem.genMode.numindstages; stageNum++)
{ {
@ -527,7 +528,7 @@ void Tev::Draw()
IndirectLod[stageNum], IndirectLinear[stageNum], texmap, IndirectTex[stageNum]); IndirectLod[stageNum], IndirectLinear[stageNum], texmap, IndirectTex[stageNum]);
#if ALLOW_TEV_DUMPS #if ALLOW_TEV_DUMPS
if (g_SWVideoConfig.bDumpTevStages) if (g_ActiveConfig.bDumpTevStages)
{ {
u8 stage[4] = { u8 stage[4] = {
IndirectTex[stageNum][TextureSampler::ALP_SMP], IndirectTex[stageNum][TextureSampler::ALP_SMP],
@ -565,7 +566,7 @@ void Tev::Draw()
TextureSampler::Sample(TexCoord.s, TexCoord.t, TextureLod[stageNum], TextureLinear[stageNum], texmap, texel); TextureSampler::Sample(TexCoord.s, TexCoord.t, TextureLod[stageNum], TextureLinear[stageNum], texmap, texel);
#if ALLOW_TEV_DUMPS #if ALLOW_TEV_DUMPS
if (g_SWVideoConfig.bDumpTevTextureFetches) if (g_ActiveConfig.bDumpTevTextureFetches)
DebugUtil::DrawTempBuffer(texel, DIRECT_TFETCH + stageNum); DebugUtil::DrawTempBuffer(texel, DIRECT_TFETCH + stageNum);
#endif #endif
@ -632,7 +633,7 @@ void Tev::Draw()
Reg[ac.dest][ALP_C] = Clamp1024(Reg[ac.dest][ALP_C]); Reg[ac.dest][ALP_C] = Clamp1024(Reg[ac.dest][ALP_C]);
#if ALLOW_TEV_DUMPS #if ALLOW_TEV_DUMPS
if (g_SWVideoConfig.bDumpTevStages) if (g_ActiveConfig.bDumpTevStages)
{ {
u8 stage[4] = {(u8)Reg[0][RED_C], (u8)Reg[0][GRN_C], (u8)Reg[0][BLU_C], (u8)Reg[0][ALP_C]}; u8 stage[4] = {(u8)Reg[0][RED_C], (u8)Reg[0][GRN_C], (u8)Reg[0][BLU_C], (u8)Reg[0][ALP_C]};
DebugUtil::DrawTempBuffer(stage, DIRECT + stageNum); DebugUtil::DrawTempBuffer(stage, DIRECT + stageNum);
@ -754,7 +755,7 @@ void Tev::Draw()
output[BLU_C] = (output[BLU_C] * invFog + fogInt * bpmem.fog.color.b) >> 8; output[BLU_C] = (output[BLU_C] * invFog + fogInt * bpmem.fog.color.b) >> 8;
} }
bool late_ztest = !bpmem.zcontrol.early_ztest || !g_SWVideoConfig.bZComploc; bool late_ztest = !bpmem.zcontrol.early_ztest || !g_ActiveConfig.bZComploc;
if (late_ztest && bpmem.zmode.testenable) if (late_ztest && bpmem.zmode.testenable)
{ {
// TODO: Check against hw if these values get incremented even if depth testing is disabled // TODO: Check against hw if these values get incremented even if depth testing is disabled
@ -773,7 +774,7 @@ void Tev::Draw()
BoundingBox::coords[BoundingBox::BOTTOM] = std::max((u16)Position[1], BoundingBox::coords[BoundingBox::BOTTOM]); BoundingBox::coords[BoundingBox::BOTTOM] = std::max((u16)Position[1], BoundingBox::coords[BoundingBox::BOTTOM]);
#if ALLOW_TEV_DUMPS #if ALLOW_TEV_DUMPS
if (g_SWVideoConfig.bDumpTevStages) if (g_ActiveConfig.bDumpTevStages)
{ {
for (u32 i = 0; i < bpmem.genMode.numindstages; ++i) for (u32 i = 0; i < bpmem.genMode.numindstages; ++i)
DebugUtil::CopyTempBuffer(Position[0], Position[1], INDIRECT, i, "Indirect"); DebugUtil::CopyTempBuffer(Position[0], Position[1], INDIRECT, i, "Indirect");
@ -781,7 +782,7 @@ void Tev::Draw()
DebugUtil::CopyTempBuffer(Position[0], Position[1], DIRECT, i, "Stage"); DebugUtil::CopyTempBuffer(Position[0], Position[1], DIRECT, i, "Stage");
} }
if (g_SWVideoConfig.bDumpTevTextureFetches) if (g_ActiveConfig.bDumpTevTextureFetches)
{ {
for (u32 i = 0; i <= bpmem.genMode.numtevstages; ++i) for (u32 i = 0; i <= bpmem.genMode.numtevstages; ++i)
{ {
@ -792,7 +793,7 @@ void Tev::Draw()
} }
#endif #endif
INCSTAT(swstats.thisFrame.tevPixelsOut); INCSTAT(stats.thisFrame.tevPixelsOut);
EfbInterface::IncPerfCounterQuadCount(PQ_BLEND_INPUT); EfbInterface::IncPerfCounterQuadCount(PQ_BLEND_INPUT);
EfbInterface::BlendTev(Position[0], Position[1], output); EfbInterface::BlendTev(Position[0], Position[1], output);
@ -810,29 +811,3 @@ void Tev::SetRegColor(int reg, int comp, bool konst, s16 color)
} }
} }
void Tev::DoState(PointerWrap &p)
{
p.DoArray(Reg);
p.DoArray(KonstantColors);
p.DoArray(TexColor);
p.DoArray(RasColor);
p.DoArray(StageKonst);
p.DoArray(FixedConstants);
p.Do(AlphaBump);
p.DoArray(IndirectTex);
p.Do(TexCoord);
p.DoArray(m_BiasLUT);
p.DoArray(m_ScaleLShiftLUT);
p.DoArray(m_ScaleRShiftLUT);
p.DoArray(Position);
p.DoArray(Color);
p.DoArray(Uv);
p.DoArray(IndirectLod);
p.DoArray(IndirectLinear);
p.DoArray(TextureLod);
p.DoArray(TextureLinear);
}

View File

@ -4,9 +4,7 @@
#pragma once #pragma once
#include "VideoBackends/Software/BPMemLoader.h" #include "VideoCommon/BPMemory.h"
class PointerWrap;
class Tev class Tev
{ {
@ -90,6 +88,4 @@ public:
void Draw(); void Draw();
void SetRegColor(int reg, int comp, bool konst, s16 color); void SetRegColor(int reg, int comp, bool konst, s16 color);
void DoState(PointerWrap &p);
}; };

View File

@ -2,10 +2,10 @@
// Licensed under GPLv2+ // Licensed under GPLv2+
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/EfbInterface.h" #include "VideoBackends/Software/EfbInterface.h"
#include "VideoBackends/Software/TextureEncoder.h" #include "VideoBackends/Software/TextureEncoder.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/LookUpTables.h" #include "VideoCommon/LookUpTables.h"
#include "VideoCommon/TextureDecoder.h" #include "VideoCommon/TextureDecoder.h"

View File

@ -7,8 +7,9 @@
#include "Common/Common.h" #include "Common/Common.h"
#include "Core/HW/Memmap.h" #include "Core/HW/Memmap.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/TextureSampler.h" #include "VideoBackends/Software/TextureSampler.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/TextureDecoder.h" #include "VideoCommon/TextureDecoder.h"
#define ALLOW_MIPMAP 1 #define ALLOW_MIPMAP 1

View File

@ -8,13 +8,12 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/MathUtil.h" #include "Common/MathUtil.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/CPMemLoader.h"
#include "VideoBackends/Software/NativeVertexFormat.h" #include "VideoBackends/Software/NativeVertexFormat.h"
#include "VideoBackends/Software/TransformUnit.h" #include "VideoBackends/Software/TransformUnit.h"
#include "VideoBackends/Software/Vec3.h" #include "VideoBackends/Software/Vec3.h"
#include "VideoBackends/Software/XFMemLoader.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/XFMemory.h"
namespace TransformUnit namespace TransformUnit
{ {

View File

@ -159,11 +159,4 @@ public:
y = 0.0f; y = 0.0f;
z = 0.0f; z = 0.0f;
} }
void DoState(PointerWrap &p)
{
p.Do(x);
p.Do(y);
p.Do(z);
}
}; };

View File

@ -12,7 +12,7 @@ namespace MMIO { class Mapping; }
namespace SW namespace SW
{ {
class VideoSoftware : public VideoBackend class VideoSoftware : public VideoBackendHardware
{ {
bool Initialize(void *window_handle) override; bool Initialize(void *window_handle) override;
void Shutdown() override; void Shutdown() override;
@ -20,42 +20,12 @@ class VideoSoftware : public VideoBackend
std::string GetName() const override; std::string GetName() const override;
std::string GetDisplayName() const override; std::string GetDisplayName() const override;
void EmuStateChange(EMUSTATE_CHANGE newState) override;
void RunLoop(bool enable) override;
void ShowConfig(void* parent) override;
void Video_Prepare() override; void Video_Prepare() override;
void Video_Cleanup() override; void Video_Cleanup() override;
void Video_EnterLoop() override; void ShowConfig(void* parent) override;
void Video_ExitLoop() override;
void Video_BeginField(u32, u32, u32, u32) override;
void Video_EndField() override;
u32 Video_AccessEFB(EFBAccessType, u32, u32, u32) override;
u32 Video_GetQueryResult(PerfQueryType type) override;
u16 Video_GetBoundingBox(int index) override;
void Video_AddMessage(const std::string& msg, unsigned int milliseconds) override;
void Video_ClearMessages() override;
bool Video_Screenshot(const std::string& filename) override;
void Video_SetRendering(bool bEnabled) override;
void Video_GatherPipeBursted() override;
int Video_Sync(int ticks) override { return 0; }
void RegisterCPMMIO(MMIO::Mapping* mmio, u32 base) override;
unsigned int PeekMessages() override; unsigned int PeekMessages() override;
void PauseAndLock(bool doLock, bool unpauseOnUnlock=true) override;
void DoState(PointerWrap &p) override;
public:
void CheckInvalidState() override;
}; };
} }

View File

@ -1,86 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Common/Common.h"
#include "Common/CommonFuncs.h"
#include "Core/HW/Memmap.h"
#include "VideoBackends/Software/Clipper.h"
#include "VideoBackends/Software/CPMemLoader.h"
#include "VideoBackends/Software/XFMemLoader.h"
#include "VideoCommon/VideoCommon.h"
void InitXFMemory()
{
memset(&xfmem, 0, sizeof(xfmem));
}
void XFWritten(u32 transferSize, u32 baseAddress)
{
u32 topAddress = baseAddress + transferSize;
if (baseAddress <= 0x1026 && topAddress >= 0x1020)
Clipper::SetViewOffset();
// fix lights so invalid values don't trash the lighting computations
if (baseAddress <= 0x067f && topAddress >= 0x0604)
{
u32* x = (u32*)xfmem.lights;
// go through all lights
for (int light = 0; light < 8; light++)
{
// skip to floating point values
x += 4;
for (int i = 0; i < 12; i++)
{
u32 xVal = *x;
// if the exponent is 255 then the number is inf or nan
if ((xVal & 0x7f800000) == 0x7f800000)
*x = 0;
x++;
}
}
}
}
void SWLoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData)
{
// do not allow writes past registers
if (baseAddress + transferSize > 0x1058)
{
INFO_LOG(VIDEO, "XF load exceeds address space: %x %d bytes", baseAddress, transferSize);
if (baseAddress >= 0x1058)
transferSize = 0;
else
transferSize = 0x1058 - baseAddress;
}
// write to XF regs
if (transferSize > 0)
{
memcpy((u32*)(&xfmem) + baseAddress, pData, transferSize * 4);
XFWritten(transferSize, baseAddress);
}
}
void SWLoadIndexedXF(u32 val, int array)
{
int index = val >> 16;
int address = val & 0xFFF; //check mask
int size = ((val >> 12) & 0xF) + 1;
//load stuff from array to address in xf mem
u32 *pData = (u32*)Memory::GetPointer(g_main_cp_state.array_bases[array] + g_main_cp_state.array_strides[array]*index);
// byteswap data
u32 buffer[16];
for (int i = 0; i < size; ++i)
buffer[i] = Common::swap32(*(pData + i));
SWLoadXFReg(size, address, buffer);
}

View File

@ -1,17 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "Common/CommonTypes.h"
#include "VideoCommon/XFMemory.h"
void InitXFMemory();
void XFWritten(u32 transferSize, u32 baseAddress);
void SWLoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData);
void SWLoadIndexedXF(u32 val, int array);

View File

@ -257,6 +257,7 @@ struct CPState final
BitSet32 attr_dirty; BitSet32 attr_dirty;
bool bases_dirty; bool bases_dirty;
VertexLoaderBase* vertex_loaders[8]; VertexLoaderBase* vertex_loaders[8];
int last_id;
}; };
class PointerWrap; class PointerWrap;

View File

@ -8,6 +8,7 @@
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "VideoCommon/Statistics.h" #include "VideoCommon/Statistics.h"
#include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VertexLoaderManager.h"
#include "VideoCommon/VideoConfig.h"
Statistics stats; Statistics stats;
@ -27,6 +28,21 @@ void Statistics::SwapDL()
std::string Statistics::ToString() std::string Statistics::ToString()
{ {
std::string str; std::string str;
if (g_ActiveConfig.backend_info.APIType == API_TYPE::API_NONE)
{
str += StringFromFormat("Objects: %i\n", stats.thisFrame.numDrawnObjects);
str += StringFromFormat("Vertices Loaded: %i\n", stats.thisFrame.numVerticesLoaded);
str += StringFromFormat("Triangles Input: %i\n", stats.thisFrame.numTrianglesIn);
str += StringFromFormat("Triangles Rejected: %i\n", stats.thisFrame.numTrianglesRejected);
str += StringFromFormat("Triangles Culled: %i\n", stats.thisFrame.numTrianglesCulled);
str += StringFromFormat("Triangles Clipped: %i\n", stats.thisFrame.numTrianglesClipped);
str += StringFromFormat("Triangles Drawn: %i\n", stats.thisFrame.numTrianglesDrawn);
str += StringFromFormat("Rasterized Pix: %i\n", stats.thisFrame.rasterizedPixels);
str += StringFromFormat("TEV Pix In: %i\n", stats.thisFrame.tevPixelsIn);
str += StringFromFormat("TEV Pix Out: %i\n", stats.thisFrame.tevPixelsOut);
}
str += StringFromFormat("Textures created: %i\n", stats.numTexturesCreated); str += StringFromFormat("Textures created: %i\n", stats.numTexturesCreated);
str += StringFromFormat("Textures uploaded: %i\n", stats.numTexturesUploaded); str += StringFromFormat("Textures uploaded: %i\n", stats.numTexturesUploaded);
str += StringFromFormat("Textures alive: %i\n", stats.numTexturesAlive); str += StringFromFormat("Textures alive: %i\n", stats.numTexturesAlive);

View File

@ -52,6 +52,17 @@ struct Statistics
int bytesVertexStreamed; int bytesVertexStreamed;
int bytesIndexStreamed; int bytesIndexStreamed;
int bytesUniformStreamed; int bytesUniformStreamed;
int numTrianglesClipped;
int numTrianglesIn;
int numTrianglesRejected;
int numTrianglesCulled;
int numDrawnObjects;
int rasterizedPixels;
int numTrianglesDrawn;
int numVerticesLoaded;
int tevPixelsIn;
int tevPixelsOut;
}; };
ThisFrame thisFrame; ThisFrame thisFrame;
void ResetFrame(); void ResetFrame();

View File

@ -124,6 +124,7 @@ void MarkAllDirty()
static VertexLoaderBase* RefreshLoader(int vtx_attr_group, bool preprocess = false) static VertexLoaderBase* RefreshLoader(int vtx_attr_group, bool preprocess = false)
{ {
CPState* state = preprocess ? &g_preprocess_cp_state : &g_main_cp_state; CPState* state = preprocess ? &g_preprocess_cp_state : &g_main_cp_state;
state->last_id = vtx_attr_group;
VertexLoaderBase* loader; VertexLoaderBase* loader;
if (state->attr_dirty[vtx_attr_group]) if (state->attr_dirty[vtx_attr_group])

View File

@ -87,6 +87,15 @@ void VideoConfig::Load(const std::string& ini_file)
settings->Get("EnableShaderDebugging", &bEnableShaderDebugging, false); settings->Get("EnableShaderDebugging", &bEnableShaderDebugging, false);
settings->Get("BorderlessFullscreen", &bBorderlessFullscreen, false); settings->Get("BorderlessFullscreen", &bBorderlessFullscreen, false);
settings->Get("SWZComploc", &bZComploc, true);
settings->Get("SWZFreeze", &bZFreeze, true);
settings->Get("SWDumpObjects", &bDumpObjects, false);
settings->Get("SWDumpTevStages", &bDumpTevStages, false);
settings->Get("SWDumpTevTexFetches", &bDumpTevTextureFetches, false);
settings->Get("SWDrawStart", &drawStart, 0);
settings->Get("SWDrawEnd", &drawEnd, 100000);
IniFile::Section* enhancements = iniFile.GetOrCreateSection("Enhancements"); IniFile::Section* enhancements = iniFile.GetOrCreateSection("Enhancements");
enhancements->Get("ForceFiltering", &bForceFiltering, 0); enhancements->Get("ForceFiltering", &bForceFiltering, 0);
enhancements->Get("MaxAnisotropy", &iMaxAnisotropy, 0); // NOTE - this is x in (1 << x) enhancements->Get("MaxAnisotropy", &iMaxAnisotropy, 0); // NOTE - this is x in (1 << x)
@ -287,6 +296,14 @@ void VideoConfig::Save(const std::string& ini_file)
settings->Set("EnableShaderDebugging", bEnableShaderDebugging); settings->Set("EnableShaderDebugging", bEnableShaderDebugging);
settings->Set("BorderlessFullscreen", bBorderlessFullscreen); settings->Set("BorderlessFullscreen", bBorderlessFullscreen);
settings->Set("SWZComploc", bZComploc);
settings->Set("SWZFreeze", bZFreeze);
settings->Set("SWDumpObjects", bDumpObjects);
settings->Set("SWDumpTevStages", bDumpTevStages);
settings->Set("SWDumpTevTexFetches", bDumpTevTextureFetches);
settings->Set("SWDrawStart", drawStart);
settings->Set("SWDrawEnd", drawEnd);
IniFile::Section* enhancements = iniFile.GetOrCreateSection("Enhancements"); IniFile::Section* enhancements = iniFile.GetOrCreateSection("Enhancements");
enhancements->Set("ForceFiltering", bForceFiltering); enhancements->Set("ForceFiltering", bForceFiltering);
enhancements->Set("MaxAnisotropy", iMaxAnisotropy); enhancements->Set("MaxAnisotropy", iMaxAnisotropy);

View File

@ -136,6 +136,15 @@ struct VideoConfig final
// Debugging // Debugging
bool bEnableShaderDebugging; bool bEnableShaderDebugging;
// VideoSW Debugging
int drawStart;
int drawEnd;
bool bZComploc;
bool bZFreeze;
bool bDumpObjects;
bool bDumpTevStages;
bool bDumpTevTextureFetches;
// Static config per API // Static config per API
// TODO: Move this out of VideoConfig // TODO: Move this out of VideoConfig
struct struct