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 "VideoBackends/Software/SWVideoConfig.h"
#include "VideoCommon/VideoBackendBase.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,
wxString(wxString::Format(_("Dolphin %s Graphics Configuration"), title))),
vconfig(g_SWVideoConfig),
ininame(_ininame)
wxString(wxString::Format(_("Dolphin %s Graphics Configuration"), title)))
{
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);
@ -77,7 +80,7 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
}
// 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
@ -87,7 +90,7 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
wxGridSizer* const szr_info = new wxGridSizer(2, 5, 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
@ -117,8 +120,8 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
wxFlexGridSizer* const szr_misc = new wxFlexGridSizer(2, 5, 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 U32Setting(page_general, _("End"), vconfig.drawEnd, 0, 100000));
szr_misc->Add(new IntegerSetting<int>(page_general, _("Start"), vconfig.drawStart, 0, 100000));
szr_misc->Add(new IntegerSetting<int>(page_general, _("End"), vconfig.drawEnd, 0, 100000));
}
page_general->SetSizerAndFit(szr_general);
@ -136,5 +139,5 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
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 "Core/ConfigManager.h"
#include "VideoBackends/Software/SWVideoConfig.h"
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoConfig.h"
class SoftwareVideoConfigDialog : public wxDialog
{
@ -37,8 +37,4 @@ public:
}
ev.Skip();
}
protected:
SWVideoConfig& vconfig;
std::string ininame;
};

View File

@ -65,8 +65,6 @@ private:
T& m_setting;
};
typedef IntegerSetting<u32> U32Setting;
class SettingChoice : public wxChoice
{
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
CPMemLoader.cpp
Clipper.cpp
set(SRCS Clipper.cpp
DebugUtil.cpp
EfbCopy.cpp
EfbInterface.cpp
OpcodeDecoder.cpp
Rasterizer.cpp
SWCommandProcessor.cpp
SWOGLWindow.cpp
SWRenderer.cpp
SWStatistics.cpp
SWVertexLoader.cpp
SWVideoConfig.cpp
SWmain.cpp
SetupUnit.cpp
Tev.cpp
TextureEncoder.cpp
TextureSampler.cpp
TransformUnit.cpp
XFMemLoader.cpp)
TransformUnit.cpp)
set(LIBS videocommon
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 "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/Clipper.h"
#include "VideoBackends/Software/NativeVertexFormat.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
{
@ -56,13 +57,6 @@ namespace Clipper
static OutputVertexData ClippedVertices[NUM_CLIPPED_VERTICES];
static OutputVertexData *Vertices[NUM_INDICES];
void DoState(PointerWrap &p)
{
p.DoArray(m_ViewOffset);
for (auto& ClippedVertice : ClippedVertices)
ClippedVertice.DoState(p);
}
void Init()
{
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_NEG_Z_BIT, 0, 0, 1, 1);
INCSTAT(swstats.thisFrame.numTrianglesClipped);
INCSTAT(stats.thisFrame.numTrianglesClipped);
// transform the poly in inlist into triangles
indices[0] = inlist[0];
@ -287,7 +281,7 @@ namespace Clipper
void ProcessTriangle(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
{
INCSTAT(swstats.thisFrame.numTrianglesIn)
INCSTAT(stats.thisFrame.numTrianglesIn)
bool backface;
@ -411,7 +405,7 @@ namespace Clipper
if (mask)
{
INCSTAT(swstats.thisFrame.numTrianglesRejected)
INCSTAT(stats.thisFrame.numTrianglesRejected)
return false;
}
@ -431,13 +425,13 @@ namespace Clipper
if ((bpmem.genMode.cullmode & 1) && !backface) // cull frontfacing
{
INCSTAT(swstats.thisFrame.numTrianglesCulled)
INCSTAT(stats.thisFrame.numTrianglesCulled)
return false;
}
if ((bpmem.genMode.cullmode & 2) && backface) // cull backfacing
{
INCSTAT(swstats.thisFrame.numTrianglesCulled)
INCSTAT(stats.thisFrame.numTrianglesCulled)
return false;
}

View File

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

View File

@ -8,18 +8,16 @@
#include "Core/ConfigManager.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/DebugUtil.h"
#include "VideoBackends/Software/EfbInterface.h"
#include "VideoBackends/Software/SWCommandProcessor.h"
#include "VideoBackends/Software/SWRenderer.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/SWVideoConfig.h"
#include "VideoBackends/Software/TextureSampler.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/Fifo.h"
#include "VideoCommon/ImageWrite.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/VideoConfig.h"
namespace DebugUtil
{
@ -109,7 +107,7 @@ void DumpActiveTextures()
{
SaveTexture(StringFromFormat("%star%i_ind%i_map%i_mip%i.png",
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",
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;
}
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)
{
int buffer = bufferBase + subBuffer;
@ -202,7 +193,7 @@ void OnObjectBegin()
{
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();
}
}
@ -211,10 +202,10 @@ void OnObjectEnd()
{
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",
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(),
swstats.thisFrame.numDrawnObjects));
stats.thisFrame.numDrawnObjects));
for (int i = 0; i < NUM_OBJECT_BUFFERS; i++)
{
@ -223,7 +214,7 @@ void OnObjectEnd()
DrawnToBuffer[i] = false;
std::string filename = StringFromFormat("%sobject%i_%s(%i).png",
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);
memset(ObjectBuffer[i], 0, EFB_WIDTH * EFB_HEIGHT * sizeof(u32));
@ -231,20 +222,7 @@ void OnObjectEnd()
}
}
swstats.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);
}
stats.thisFrame.numDrawnObjects++;
}
}

View File

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

View File

@ -5,15 +5,13 @@
#include "Common/GL/GLInterfaceBase.h"
#include "Core/Core.h"
#include "Core/HW/Memmap.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/DebugUtil.h"
#include "VideoBackends/Software/EfbCopy.h"
#include "VideoBackends/Software/EfbInterface.h"
#include "VideoBackends/Software/SWCommandProcessor.h"
#include "VideoBackends/Software/SWRenderer.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/SWVideoConfig.h"
#include "VideoBackends/Software/TextureEncoder.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/Fifo.h"
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",
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);
}
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);
}
EfbInterface::CopyToXFB(xfb_in_ram, fbWidth, fbHeight, sourceRc, Gamma);
}
static void CopyToRam()
@ -67,7 +43,7 @@ namespace EfbCopy
TextureEncoder::Encode(dest_ptr);
}
static void ClearEfb()
void ClearEfb()
{
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
}
if (bpmem.triggerEFBCopy.clear)
{
ClearEfb();
}
}
}
}

View File

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

View File

@ -8,9 +8,9 @@
#include "Common/CommonTypes.h"
#include "Core/HW/Memmap.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/EfbInterface.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/LookUpTables.h"
#include "VideoCommon/PixelEngine.h"
@ -31,11 +31,6 @@ namespace EfbInterface
return (x + y * EFB_WIDTH) * 3 + DEPTH_BUFFER_START;
}
void DoState(PointerWrap &p)
{
p.DoArray(efb);
}
static void SetPixelAlphaOnly(u32 offset, u8 a)
{
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 BypassXFB(u8* texture, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma);
void DoState(PointerWrap &p);
extern u32 perf_values[PQ_NUM_MEMBERS];
inline void IncPerfCounterQuadCount(PerfQueryType type)
{

View File

@ -77,16 +77,4 @@ struct OutputVertexData
#undef LINTERP
#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 "Common/CommonTypes.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/EfbInterface.h"
#include "VideoBackends/Software/NativeVertexFormat.h"
#include "VideoBackends/Software/Rasterizer.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/SWVideoConfig.h"
#include "VideoBackends/Software/Tev.h"
#include "VideoBackends/Software/XFMemLoader.h"
#include "VideoCommon/BoundingBox.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h"
namespace Rasterizer
{
@ -38,28 +37,6 @@ static s32 scissorBottom = 0;
static Tev tev;
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()
{
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)
{
INCSTAT(swstats.thisFrame.rasterizedPixels);
INCSTAT(stats.thisFrame.rasterizedPixels);
float dx = vertexOffsetX + (float)(x - vertex0X);
float dy = vertexOffsetY + (float)(y - vertex0Y);
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
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)
{
INCSTAT(swstats.thisFrame.numTrianglesDrawn);
INCSTAT(stats.thisFrame.numTrianglesDrawn);
// 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).
// 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.
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);
for (unsigned int i = 0; i < bpmem.genMode.numcolchans; i++)

View File

@ -25,12 +25,6 @@ namespace Rasterizer
float f0;
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
@ -47,6 +41,4 @@ namespace Rasterizer
s32 TextureLod[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/StringUtil.h"
#include "Core/ConfigManager.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/SWRenderer.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoCommon/BoundingBox.h"
#include "VideoCommon/Fifo.h"
#include "VideoCommon/ImageWrite.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/VideoConfig.h"
static u8 *s_xfbColorTexture[2];
static int s_currentColorTexture = 0;
static std::atomic<bool> s_bScreenshot;
static std::mutex s_criticalScreenshot;
static std::string s_sScreenshotName;
void SWRenderer::Init()
{
s_bScreenshot.store(false);
}
void SWRenderer::Shutdown()
SWRenderer::~SWRenderer()
{
delete[] s_xfbColorTexture[0];
delete[] s_xfbColorTexture[1];
}
void SWRenderer::Prepare()
void SWRenderer::Init()
{
s_xfbColorTexture[0] = 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;
}
void SWRenderer::SetScreenshot(const char *_szFilename)
void SWRenderer::Shutdown()
{
std::lock_guard<std::mutex> lk(s_criticalScreenshot);
s_sScreenshotName = _szFilename;
s_bScreenshot.store(true);
g_Config.bRunning = false;
UpdateActiveConfig();
}
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);
}
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()
{
return s_xfbColorTexture[!s_currentColorTexture];
@ -138,16 +106,42 @@ void SWRenderer::UpdateColorTexture(EfbInterface::yuv422_packed *xfb, u32 fbWidt
}
// 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 (s_bScreenshot.load())
if (!g_bSkipCurrentFrame)
{
std::lock_guard<std::mutex> lk(s_criticalScreenshot);
TextureToPng(GetCurrentColorTexture(), fbWidth * 4, s_sScreenshotName, fbWidth, fbHeight, false);
// Reset settings
s_sScreenshotName.clear();
s_bScreenshot.store(false);
if (g_ActiveConfig.bUseXFB)
{
EfbInterface::yuv422_packed* xfb = (EfbInterface::yuv422_packed*) Memory::GetPointer(xfbAddr);
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);
@ -156,7 +150,57 @@ void SWRenderer::Swap(u32 fbWidth, u32 fbHeight)
SWOGLWindow::s_instance->ShowImage(GetCurrentColorTexture(), fbWidth * 4, fbWidth, fbHeight, 1.0);
swstats.frameCount++;
swstats.ResetFrame();
Core::Callback_VideoCopiedToXFB(true); // FIXME: should this function be called FrameRendered?
UpdateActiveConfig();
}
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/Thread.h"
#include "VideoBackends/Software/EfbInterface.h"
namespace SWRenderer
#include "VideoCommon/RenderBase.h"
class SWRenderer : public Renderer
{
void Init();
void Prepare();
void Shutdown();
public:
~SWRenderer() override;
void SetScreenshot(const char *_szFilename);
void RenderText(const char* pstr, int left, int top, u32 color);
void DrawDebugText();
static void Init();
static void Shutdown();
u8* GetNextColorTexture();
u8* GetCurrentColorTexture();
static u8* GetNextColorTexture();
static u8* GetCurrentColorTexture();
void SwapColorTexture();
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/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/Rasterizer.h"
#include "VideoBackends/Software/SetupUnit.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/SWVertexLoader.h"
#include "VideoBackends/Software/Tev.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/VertexLoaderManager.h"
#include "VideoCommon/VertexLoaderUtils.h"
#include "VideoCommon/XFMemory.h"
SWVertexLoader::SWVertexLoader() :
m_VertexSize(0)
class NullNativeVertexFormat : public NativeVertexFormat
{
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;
}
@ -32,25 +50,89 @@ SWVertexLoader::~SWVertexLoader()
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]);
m_CurrentLoader = m_VertexLoaderMap[uid].get();
if (!m_CurrentLoader)
u8 primitiveType = 0;
switch (current_primitive_type)
{
m_VertexLoaderMap[uid] = VertexLoaderBase::CreateVertexLoader(g_main_cp_state.vtx_desc, g_main_cp_state.vtx_attr[m_attributeIndex]);
m_CurrentLoader = m_VertexLoaderMap[uid].get();
case PRIMITIVE_POINTS:
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_CurrentVat = &g_main_cp_state.vtx_attr[m_attributeIndex];
m_SetupUnit->Init(primitiveType);
// 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?
if (xfmem.MatrixIndexA.PosNormalMtxIdx != g_main_cp_state.matrix_index_a.PosNormalMtxIdx ||
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.Tex0Coord != NOT_PRESENT) &&
(xfmem.texMtxInfo[0].projection == XF_TEXPROJ_ST);
m_SetupUnit->Init(primitiveType);
}
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);
@ -167,52 +248,3 @@ void SWVertexLoader::ParseVertex(const PortableVertexDeclaration& vdec)
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 <unordered_map>
#include <vector>
#include "Common/CommonTypes.h"
#include "VideoBackends/Software/CPMemLoader.h"
#include "VideoBackends/Software/NativeVertexFormat.h"
#include "VideoCommon/VertexLoaderBase.h"
#include "VideoCommon/VertexManagerBase.h"
class PointerWrap;
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;
void ParseVertex(const PortableVertexDeclaration& vdec);
void ParseVertex(const PortableVertexDeclaration& vdec, int index);
SetupUnit *m_SetupUnit;
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:
SWVertexLoader();
~SWVertexLoader();
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.
#include <atomic>
#include <memory>
#include <string>
#include "Common/CommonTypes.h"
@ -16,25 +17,29 @@
#include "Core/HW/Memmap.h"
#include "Core/HW/VideoInterface.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/Clipper.h"
#include "VideoBackends/Software/DebugUtil.h"
#include "VideoBackends/Software/EfbCopy.h"
#include "VideoBackends/Software/EfbInterface.h"
#include "VideoBackends/Software/OpcodeDecoder.h"
#include "VideoBackends/Software/Rasterizer.h"
#include "VideoBackends/Software/SWCommandProcessor.h"
#include "VideoBackends/Software/SWOGLWindow.h"
#include "VideoBackends/Software/SWRenderer.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/SWVertexLoader.h"
#include "VideoBackends/Software/SWVideoConfig.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/IndexGenerator.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/OpcodeDecoding.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"
#define VSYNC_ENABLED 0
@ -51,6 +56,86 @@ static volatile struct
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> emuRunningState;
static std::mutex m_csSWVidOccupied;
@ -65,93 +150,57 @@ std::string VideoSoftware::GetDisplayName() const
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)
{
if (!m_initialized)
InitBackendInfo();
Host_ShowVideoConfig(hParent, GetDisplayName(), "gfx_software");
}
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);
InitBPMemory();
InitXFMemory();
SWCommandProcessor::Init();
PixelEngine::Init();
OpcodeDecoder::Init();
Clipper::Init();
Rasterizer::Init();
SWRenderer::Init();
DebugUtil::Init();
// Do our OSD callbacks
OSD::DoCallbacks(OSD::CallbackType::Initialization);
m_initialized = 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()
{
m_initialized = false;
// TODO: should be in Video_Cleanup
SWRenderer::Shutdown();
DebugUtil::Shutdown();
// Do our OSD callbacks
OSD::DoCallbacks(OSD::CallbackType::Shutdown);
@ -160,186 +209,54 @@ void VideoSoftware::Shutdown()
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
void VideoSoftware::Video_Prepare()
{
// Do our OSD callbacks
OSD::DoCallbacks(OSD::CallbackType::Initialization);
g_renderer = std::make_unique<SWRenderer>();
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.");
}
// 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()
{
return SWOGLWindow::s_instance->PeekMessages();

View File

@ -4,11 +4,9 @@
#include "Common/ChunkFile.h"
#include "VideoBackends/Software/Clipper.h"
#include "VideoBackends/Software/CPMemLoader.h"
#include "VideoBackends/Software/OpcodeDecoder.h"
#include "VideoBackends/Software/SetupUnit.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoCommon/OpcodeDecoding.h"
void SetupUnit::Init(u8 primitiveType)
{
@ -167,20 +165,3 @@ void SetupUnit::SetupLineStrip()
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 "VideoBackends/Software/NativeVertexFormat.h"
class PointerWrap;
class SetupUnit
{
u8 m_PrimType;
@ -32,5 +30,4 @@ public:
OutputVertexData* GetVertex();
void SetupVertex();
void DoState(PointerWrap &p);
};

View File

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

View File

@ -8,12 +8,13 @@
#include "Common/CommonTypes.h"
#include "VideoBackends/Software/DebugUtil.h"
#include "VideoBackends/Software/EfbInterface.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/SWVideoConfig.h"
#include "VideoBackends/Software/Tev.h"
#include "VideoBackends/Software/TextureSampler.h"
#include "VideoBackends/Software/XFMemLoader.h"
#include "VideoCommon/BoundingBox.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h"
#ifdef _DEBUG
#define ALLOW_TEV_DUMPS 1
@ -509,7 +510,7 @@ void Tev::Draw()
_assert_(Position[0] >= 0 && Position[0] < EFB_WIDTH);
_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++)
{
@ -527,7 +528,7 @@ void Tev::Draw()
IndirectLod[stageNum], IndirectLinear[stageNum], texmap, IndirectTex[stageNum]);
#if ALLOW_TEV_DUMPS
if (g_SWVideoConfig.bDumpTevStages)
if (g_ActiveConfig.bDumpTevStages)
{
u8 stage[4] = {
IndirectTex[stageNum][TextureSampler::ALP_SMP],
@ -565,7 +566,7 @@ void Tev::Draw()
TextureSampler::Sample(TexCoord.s, TexCoord.t, TextureLod[stageNum], TextureLinear[stageNum], texmap, texel);
#if ALLOW_TEV_DUMPS
if (g_SWVideoConfig.bDumpTevTextureFetches)
if (g_ActiveConfig.bDumpTevTextureFetches)
DebugUtil::DrawTempBuffer(texel, DIRECT_TFETCH + stageNum);
#endif
@ -632,7 +633,7 @@ void Tev::Draw()
Reg[ac.dest][ALP_C] = Clamp1024(Reg[ac.dest][ALP_C]);
#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]};
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;
}
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)
{
// 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]);
#if ALLOW_TEV_DUMPS
if (g_SWVideoConfig.bDumpTevStages)
if (g_ActiveConfig.bDumpTevStages)
{
for (u32 i = 0; i < bpmem.genMode.numindstages; ++i)
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");
}
if (g_SWVideoConfig.bDumpTevTextureFetches)
if (g_ActiveConfig.bDumpTevTextureFetches)
{
for (u32 i = 0; i <= bpmem.genMode.numtevstages; ++i)
{
@ -792,7 +793,7 @@ void Tev::Draw()
}
#endif
INCSTAT(swstats.thisFrame.tevPixelsOut);
INCSTAT(stats.thisFrame.tevPixelsOut);
EfbInterface::IncPerfCounterQuadCount(PQ_BLEND_INPUT);
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
#include "VideoBackends/Software/BPMemLoader.h"
class PointerWrap;
#include "VideoCommon/BPMemory.h"
class Tev
{
@ -90,6 +88,4 @@ public:
void Draw();
void SetRegColor(int reg, int comp, bool konst, s16 color);
void DoState(PointerWrap &p);
};

View File

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

View File

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

View File

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

View File

@ -159,11 +159,4 @@ public:
y = 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
{
class VideoSoftware : public VideoBackend
class VideoSoftware : public VideoBackendHardware
{
bool Initialize(void *window_handle) override;
void Shutdown() override;
@ -20,42 +20,12 @@ class VideoSoftware : public VideoBackend
std::string GetName() 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_Cleanup() override;
void Video_EnterLoop() 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;
void ShowConfig(void* parent) 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;
bool bases_dirty;
VertexLoaderBase* vertex_loaders[8];
int last_id;
};
class PointerWrap;

View File

@ -8,6 +8,7 @@
#include "Common/StringUtil.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/VertexLoaderManager.h"
#include "VideoCommon/VideoConfig.h"
Statistics stats;
@ -27,6 +28,21 @@ void Statistics::SwapDL()
std::string Statistics::ToString()
{
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 uploaded: %i\n", stats.numTexturesUploaded);
str += StringFromFormat("Textures alive: %i\n", stats.numTexturesAlive);

View File

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

View File

@ -124,6 +124,7 @@ void MarkAllDirty()
static VertexLoaderBase* RefreshLoader(int vtx_attr_group, bool preprocess = false)
{
CPState* state = preprocess ? &g_preprocess_cp_state : &g_main_cp_state;
state->last_id = vtx_attr_group;
VertexLoaderBase* loader;
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("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");
enhancements->Get("ForceFiltering", &bForceFiltering, 0);
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("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");
enhancements->Set("ForceFiltering", bForceFiltering);
enhancements->Set("MaxAnisotropy", iMaxAnisotropy);

View File

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