Merge pull request #3156 from degasus/videosw2
VideoSW: Use VideoCommon framework and drop redundant code
This commit is contained in:
commit
3c65a7dd7f
|
@ -76,8 +76,6 @@
|
|||
|
||||
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||
|
||||
#include "VideoBackends/Software/SWVideoConfig.h"
|
||||
|
||||
#include "VideoCommon/VideoBackendBase.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -65,8 +65,6 @@ private:
|
|||
T& m_setting;
|
||||
};
|
||||
|
||||
typedef IntegerSetting<u32> U32Setting;
|
||||
|
||||
class SettingChoice : public wxChoice
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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++)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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; };
|
||||
};
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
|
@ -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();
|
||||
|
|
|
@ -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];
|
||||
}*/
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -159,11 +159,4 @@ public:
|
|||
y = 0.0f;
|
||||
z = 0.0f;
|
||||
}
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
p.Do(x);
|
||||
p.Do(y);
|
||||
p.Do(z);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
|
@ -257,6 +257,7 @@ struct CPState final
|
|||
BitSet32 attr_dirty;
|
||||
bool bases_dirty;
|
||||
VertexLoaderBase* vertex_loaders[8];
|
||||
int last_id;
|
||||
};
|
||||
|
||||
class PointerWrap;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue