From efbe5bc4b651d1f7f726bb064255e0e2562f7490 Mon Sep 17 00:00:00 2001
From: degasus <wickmarkus@web.de>
Date: Fri, 9 Oct 2015 20:50:36 +0200
Subject: [PATCH] VideoSW: Use more VideoCommon

Now we require lots of empty functions, but this removes by far more duplicated code.
---
 Source/Core/DolphinWX/FrameTools.cpp          |   2 -
 .../DolphinWX/SoftwareVideoConfigDialog.cpp   |  23 +-
 .../DolphinWX/SoftwareVideoConfigDialog.h     |   6 +-
 Source/Core/DolphinWX/VideoConfigDiag.h       |   2 -
 .../VideoBackends/Software/BPMemLoader.cpp    | 178 --------
 .../Core/VideoBackends/Software/BPMemLoader.h |  13 -
 .../VideoBackends/Software/CMakeLists.txt     |  11 +-
 .../VideoBackends/Software/CPMemLoader.cpp    |  60 ---
 .../Core/VideoBackends/Software/CPMemLoader.h |  10 -
 .../Core/VideoBackends/Software/Clipper.cpp   |  24 +-
 Source/Core/VideoBackends/Software/Clipper.h  |   3 -
 .../Core/VideoBackends/Software/DebugUtil.cpp |  42 +-
 .../Core/VideoBackends/Software/DebugUtil.h   |   2 -
 .../Core/VideoBackends/Software/EfbCopy.cpp   |  39 +-
 Source/Core/VideoBackends/Software/EfbCopy.h  |   3 +-
 .../VideoBackends/Software/EfbInterface.cpp   |   7 +-
 .../VideoBackends/Software/EfbInterface.h     |   2 -
 .../Software/NativeVertexFormat.h             |  12 -
 .../VideoBackends/Software/OpcodeDecoder.cpp  | 304 --------------
 .../VideoBackends/Software/OpcodeDecoder.h    |  52 ---
 .../VideoBackends/Software/Rasterizer.cpp     |  37 +-
 .../Core/VideoBackends/Software/Rasterizer.h  |   8 -
 .../Software/SWCommandProcessor.cpp           | 354 ----------------
 .../Software/SWCommandProcessor.h             |  61 ---
 .../VideoBackends/Software/SWRenderer.cpp     | 154 ++++---
 .../Core/VideoBackends/Software/SWRenderer.h  |  40 +-
 .../VideoBackends/Software/SWStatistics.cpp   |  18 -
 .../VideoBackends/Software/SWStatistics.h     |  47 ---
 .../VideoBackends/Software/SWVertexLoader.cpp | 172 +++++---
 .../VideoBackends/Software/SWVertexLoader.h   |  35 +-
 .../VideoBackends/Software/SWVideoConfig.cpp  |  91 ----
 .../VideoBackends/Software/SWVideoConfig.h    |  43 --
 Source/Core/VideoBackends/Software/SWmain.cpp | 397 +++++++-----------
 .../Core/VideoBackends/Software/SetupUnit.cpp |  21 +-
 .../Core/VideoBackends/Software/SetupUnit.h   |   3 -
 .../VideoBackends/Software/Software.vcxproj   |  14 -
 Source/Core/VideoBackends/Software/Tev.cpp    |  49 +--
 Source/Core/VideoBackends/Software/Tev.h      |   6 +-
 .../VideoBackends/Software/TextureEncoder.cpp |   2 +-
 .../VideoBackends/Software/TextureSampler.cpp |   3 +-
 .../VideoBackends/Software/TransformUnit.cpp  |   5 +-
 Source/Core/VideoBackends/Software/Vec3.h     |   7 -
 .../VideoBackends/Software/VideoBackend.h     |  34 +-
 .../VideoBackends/Software/XFMemLoader.cpp    |  86 ----
 .../Core/VideoBackends/Software/XFMemLoader.h |  17 -
 Source/Core/VideoCommon/CPMemory.h            |   1 +
 Source/Core/VideoCommon/Statistics.cpp        |  16 +
 Source/Core/VideoCommon/Statistics.h          |  11 +
 .../Core/VideoCommon/VertexLoaderManager.cpp  |   1 +
 Source/Core/VideoCommon/VideoConfig.cpp       |  17 +
 Source/Core/VideoCommon/VideoConfig.h         |   9 +
 51 files changed, 529 insertions(+), 2025 deletions(-)
 delete mode 100644 Source/Core/VideoBackends/Software/BPMemLoader.cpp
 delete mode 100644 Source/Core/VideoBackends/Software/BPMemLoader.h
 delete mode 100644 Source/Core/VideoBackends/Software/CPMemLoader.cpp
 delete mode 100644 Source/Core/VideoBackends/Software/CPMemLoader.h
 delete mode 100644 Source/Core/VideoBackends/Software/OpcodeDecoder.cpp
 delete mode 100644 Source/Core/VideoBackends/Software/OpcodeDecoder.h
 delete mode 100644 Source/Core/VideoBackends/Software/SWCommandProcessor.cpp
 delete mode 100644 Source/Core/VideoBackends/Software/SWCommandProcessor.h
 delete mode 100644 Source/Core/VideoBackends/Software/SWStatistics.cpp
 delete mode 100644 Source/Core/VideoBackends/Software/SWStatistics.h
 delete mode 100644 Source/Core/VideoBackends/Software/SWVideoConfig.cpp
 delete mode 100644 Source/Core/VideoBackends/Software/SWVideoConfig.h
 delete mode 100644 Source/Core/VideoBackends/Software/XFMemLoader.cpp
 delete mode 100644 Source/Core/VideoBackends/Software/XFMemLoader.h

diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp
index e960eda15d..db0acc7fe0 100644
--- a/Source/Core/DolphinWX/FrameTools.cpp
+++ b/Source/Core/DolphinWX/FrameTools.cpp
@@ -76,8 +76,6 @@
 
 #include "InputCommon/ControllerInterface/ControllerInterface.h"
 
-#include "VideoBackends/Software/SWVideoConfig.h"
-
 #include "VideoCommon/VideoBackendBase.h"
 #include "VideoCommon/VideoConfig.h"
 
diff --git a/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp b/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp
index fb2fbddbcd..eba84552a2 100644
--- a/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp
+++ b/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp
@@ -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());
 }
diff --git a/Source/Core/DolphinWX/SoftwareVideoConfigDialog.h b/Source/Core/DolphinWX/SoftwareVideoConfigDialog.h
index 7b23211476..221ec0f209 100644
--- a/Source/Core/DolphinWX/SoftwareVideoConfigDialog.h
+++ b/Source/Core/DolphinWX/SoftwareVideoConfigDialog.h
@@ -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;
 };
diff --git a/Source/Core/DolphinWX/VideoConfigDiag.h b/Source/Core/DolphinWX/VideoConfigDiag.h
index a52960953a..24f91d87f0 100644
--- a/Source/Core/DolphinWX/VideoConfigDiag.h
+++ b/Source/Core/DolphinWX/VideoConfigDiag.h
@@ -65,8 +65,6 @@ private:
 	T& m_setting;
 };
 
-typedef IntegerSetting<u32> U32Setting;
-
 class SettingChoice : public wxChoice
 {
 public:
diff --git a/Source/Core/VideoBackends/Software/BPMemLoader.cpp b/Source/Core/VideoBackends/Software/BPMemLoader.cpp
deleted file mode 100644
index fefe028f64..0000000000
--- a/Source/Core/VideoBackends/Software/BPMemLoader.cpp
+++ /dev/null
@@ -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;
-		}
-
-	}
-}
-
diff --git a/Source/Core/VideoBackends/Software/BPMemLoader.h b/Source/Core/VideoBackends/Software/BPMemLoader.h
deleted file mode 100644
index 71cd076d8e..0000000000
--- a/Source/Core/VideoBackends/Software/BPMemLoader.h
+++ /dev/null
@@ -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);
diff --git a/Source/Core/VideoBackends/Software/CMakeLists.txt b/Source/Core/VideoBackends/Software/CMakeLists.txt
index 14bde663d1..5706726770 100644
--- a/Source/Core/VideoBackends/Software/CMakeLists.txt
+++ b/Source/Core/VideoBackends/Software/CMakeLists.txt
@@ -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
diff --git a/Source/Core/VideoBackends/Software/CPMemLoader.cpp b/Source/Core/VideoBackends/Software/CPMemLoader.cpp
deleted file mode 100644
index c33cd2dd0e..0000000000
--- a/Source/Core/VideoBackends/Software/CPMemLoader.cpp
+++ /dev/null
@@ -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;
-	}
-}
diff --git a/Source/Core/VideoBackends/Software/CPMemLoader.h b/Source/Core/VideoBackends/Software/CPMemLoader.h
deleted file mode 100644
index 5760505a41..0000000000
--- a/Source/Core/VideoBackends/Software/CPMemLoader.h
+++ /dev/null
@@ -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);
diff --git a/Source/Core/VideoBackends/Software/Clipper.cpp b/Source/Core/VideoBackends/Software/Clipper.cpp
index d28b1517cb..7c360c65b0 100644
--- a/Source/Core/VideoBackends/Software/Clipper.cpp
+++ b/Source/Core/VideoBackends/Software/Clipper.cpp
@@ -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;
 		}
 
diff --git a/Source/Core/VideoBackends/Software/Clipper.h b/Source/Core/VideoBackends/Software/Clipper.h
index 263fbd0854..8cf82a0e31 100644
--- a/Source/Core/VideoBackends/Software/Clipper.h
+++ b/Source/Core/VideoBackends/Software/Clipper.h
@@ -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);
 }
diff --git a/Source/Core/VideoBackends/Software/DebugUtil.cpp b/Source/Core/VideoBackends/Software/DebugUtil.cpp
index 7be0692088..493fe51352 100644
--- a/Source/Core/VideoBackends/Software/DebugUtil.cpp
+++ b/Source/Core/VideoBackends/Software/DebugUtil.cpp
@@ -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++;
 	}
 }
 
diff --git a/Source/Core/VideoBackends/Software/DebugUtil.h b/Source/Core/VideoBackends/Software/DebugUtil.h
index 8607a6e4c0..1d5b072500 100644
--- a/Source/Core/VideoBackends/Software/DebugUtil.h
+++ b/Source/Core/VideoBackends/Software/DebugUtil.h
@@ -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);
diff --git a/Source/Core/VideoBackends/Software/EfbCopy.cpp b/Source/Core/VideoBackends/Software/EfbCopy.cpp
index 39dff99ad0..9637ef7af0 100644
--- a/Source/Core/VideoBackends/Software/EfbCopy.cpp
+++ b/Source/Core/VideoBackends/Software/EfbCopy.cpp
@@ -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();
-			}
 		}
 	}
 }
diff --git a/Source/Core/VideoBackends/Software/EfbCopy.h b/Source/Core/VideoBackends/Software/EfbCopy.h
index 3d3b5939ad..97698d3c5f 100644
--- a/Source/Core/VideoBackends/Software/EfbCopy.h
+++ b/Source/Core/VideoBackends/Software/EfbCopy.h
@@ -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();
 }
diff --git a/Source/Core/VideoBackends/Software/EfbInterface.cpp b/Source/Core/VideoBackends/Software/EfbInterface.cpp
index ca6221ef26..b6b55b7204 100644
--- a/Source/Core/VideoBackends/Software/EfbInterface.cpp
+++ b/Source/Core/VideoBackends/Software/EfbInterface.cpp
@@ -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)
diff --git a/Source/Core/VideoBackends/Software/EfbInterface.h b/Source/Core/VideoBackends/Software/EfbInterface.h
index 999dfbf8c4..0f09000a33 100644
--- a/Source/Core/VideoBackends/Software/EfbInterface.h
+++ b/Source/Core/VideoBackends/Software/EfbInterface.h
@@ -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)
 	{
diff --git a/Source/Core/VideoBackends/Software/NativeVertexFormat.h b/Source/Core/VideoBackends/Software/NativeVertexFormat.h
index 83f771b26b..6fb0f7c1ae 100644
--- a/Source/Core/VideoBackends/Software/NativeVertexFormat.h
+++ b/Source/Core/VideoBackends/Software/NativeVertexFormat.h
@@ -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);
-	}
-
 };
diff --git a/Source/Core/VideoBackends/Software/OpcodeDecoder.cpp b/Source/Core/VideoBackends/Software/OpcodeDecoder.cpp
deleted file mode 100644
index 6a7279440d..0000000000
--- a/Source/Core/VideoBackends/Software/OpcodeDecoder.cpp
+++ /dev/null
@@ -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);
-}
-
-}
diff --git a/Source/Core/VideoBackends/Software/OpcodeDecoder.h b/Source/Core/VideoBackends/Software/OpcodeDecoder.h
deleted file mode 100644
index 83630fa202..0000000000
--- a/Source/Core/VideoBackends/Software/OpcodeDecoder.h
+++ /dev/null
@@ -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);
-}
diff --git a/Source/Core/VideoBackends/Software/Rasterizer.cpp b/Source/Core/VideoBackends/Software/Rasterizer.cpp
index 79332b6cdb..03d352beb5 100644
--- a/Source/Core/VideoBackends/Software/Rasterizer.cpp
+++ b/Source/Core/VideoBackends/Software/Rasterizer.cpp
@@ -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++)
diff --git a/Source/Core/VideoBackends/Software/Rasterizer.h b/Source/Core/VideoBackends/Software/Rasterizer.h
index 3a6a72852f..a80565647e 100644
--- a/Source/Core/VideoBackends/Software/Rasterizer.h
+++ b/Source/Core/VideoBackends/Software/Rasterizer.h
@@ -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);
 }
diff --git a/Source/Core/VideoBackends/Software/SWCommandProcessor.cpp b/Source/Core/VideoBackends/Software/SWCommandProcessor.cpp
deleted file mode 100644
index 42528603a6..0000000000
--- a/Source/Core/VideoBackends/Software/SWCommandProcessor.cpp
+++ /dev/null
@@ -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
-
diff --git a/Source/Core/VideoBackends/Software/SWCommandProcessor.h b/Source/Core/VideoBackends/Software/SWCommandProcessor.h
deleted file mode 100644
index 539be4263f..0000000000
--- a/Source/Core/VideoBackends/Software/SWCommandProcessor.h
+++ /dev/null
@@ -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
diff --git a/Source/Core/VideoBackends/Software/SWRenderer.cpp b/Source/Core/VideoBackends/Software/SWRenderer.cpp
index 3eeed2958b..ba3f2a9fcc 100644
--- a/Source/Core/VideoBackends/Software/SWRenderer.cpp
+++ b/Source/Core/VideoBackends/Software/SWRenderer.cpp
@@ -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();
 }
diff --git a/Source/Core/VideoBackends/Software/SWRenderer.h b/Source/Core/VideoBackends/Software/SWRenderer.h
index c7cafe344a..3ce1cc4593 100644
--- a/Source/Core/VideoBackends/Software/SWRenderer.h
+++ b/Source/Core/VideoBackends/Software/SWRenderer.h
@@ -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; };
+};
diff --git a/Source/Core/VideoBackends/Software/SWStatistics.cpp b/Source/Core/VideoBackends/Software/SWStatistics.cpp
deleted file mode 100644
index 44892d6b94..0000000000
--- a/Source/Core/VideoBackends/Software/SWStatistics.cpp
+++ /dev/null
@@ -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));
-}
diff --git a/Source/Core/VideoBackends/Software/SWStatistics.h b/Source/Core/VideoBackends/Software/SWStatistics.h
deleted file mode 100644
index 6b343ca44b..0000000000
--- a/Source/Core/VideoBackends/Software/SWStatistics.h
+++ /dev/null
@@ -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
diff --git a/Source/Core/VideoBackends/Software/SWVertexLoader.cpp b/Source/Core/VideoBackends/Software/SWVertexLoader.cpp
index bda8714f00..86855db446 100644
--- a/Source/Core/VideoBackends/Software/SWVertexLoader.cpp
+++ b/Source/Core/VideoBackends/Software/SWVertexLoader.cpp
@@ -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);
-}
diff --git a/Source/Core/VideoBackends/Software/SWVertexLoader.h b/Source/Core/VideoBackends/Software/SWVertexLoader.h
index 4972364c1b..7166ae6697 100644
--- a/Source/Core/VideoBackends/Software/SWVertexLoader.h
+++ b/Source/Core/VideoBackends/Software/SWVertexLoader.h
@@ -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);
 };
diff --git a/Source/Core/VideoBackends/Software/SWVideoConfig.cpp b/Source/Core/VideoBackends/Software/SWVideoConfig.cpp
deleted file mode 100644
index 4bd011e2df..0000000000
--- a/Source/Core/VideoBackends/Software/SWVideoConfig.cpp
+++ /dev/null
@@ -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);
-}
-
diff --git a/Source/Core/VideoBackends/Software/SWVideoConfig.h b/Source/Core/VideoBackends/Software/SWVideoConfig.h
deleted file mode 100644
index 4dfa8ac87d..0000000000
--- a/Source/Core/VideoBackends/Software/SWVideoConfig.h
+++ /dev/null
@@ -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;
diff --git a/Source/Core/VideoBackends/Software/SWmain.cpp b/Source/Core/VideoBackends/Software/SWmain.cpp
index b0f0af66f8..59162c2f06 100644
--- a/Source/Core/VideoBackends/Software/SWmain.cpp
+++ b/Source/Core/VideoBackends/Software/SWmain.cpp
@@ -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();
diff --git a/Source/Core/VideoBackends/Software/SetupUnit.cpp b/Source/Core/VideoBackends/Software/SetupUnit.cpp
index e433ae17f0..a9ef985963 100644
--- a/Source/Core/VideoBackends/Software/SetupUnit.cpp
+++ b/Source/Core/VideoBackends/Software/SetupUnit.cpp
@@ -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];
-	}*/
-}
diff --git a/Source/Core/VideoBackends/Software/SetupUnit.h b/Source/Core/VideoBackends/Software/SetupUnit.h
index c68d6b9c73..a00fc29634 100644
--- a/Source/Core/VideoBackends/Software/SetupUnit.h
+++ b/Source/Core/VideoBackends/Software/SetupUnit.h
@@ -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);
 };
diff --git a/Source/Core/VideoBackends/Software/Software.vcxproj b/Source/Core/VideoBackends/Software/Software.vcxproj
index edf569db32..488a9609aa 100644
--- a/Source/Core/VideoBackends/Software/Software.vcxproj
+++ b/Source/Core/VideoBackends/Software/Software.vcxproj
@@ -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" />
diff --git a/Source/Core/VideoBackends/Software/Tev.cpp b/Source/Core/VideoBackends/Software/Tev.cpp
index 7391dfefb3..939b9f98a4 100644
--- a/Source/Core/VideoBackends/Software/Tev.cpp
+++ b/Source/Core/VideoBackends/Software/Tev.cpp
@@ -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);
-}
diff --git a/Source/Core/VideoBackends/Software/Tev.h b/Source/Core/VideoBackends/Software/Tev.h
index 9da27acc52..64e195555b 100644
--- a/Source/Core/VideoBackends/Software/Tev.h
+++ b/Source/Core/VideoBackends/Software/Tev.h
@@ -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);
 };
diff --git a/Source/Core/VideoBackends/Software/TextureEncoder.cpp b/Source/Core/VideoBackends/Software/TextureEncoder.cpp
index 13c5973c95..4b38d1c19a 100644
--- a/Source/Core/VideoBackends/Software/TextureEncoder.cpp
+++ b/Source/Core/VideoBackends/Software/TextureEncoder.cpp
@@ -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"
 
diff --git a/Source/Core/VideoBackends/Software/TextureSampler.cpp b/Source/Core/VideoBackends/Software/TextureSampler.cpp
index 3490133942..6c1001a6c8 100644
--- a/Source/Core/VideoBackends/Software/TextureSampler.cpp
+++ b/Source/Core/VideoBackends/Software/TextureSampler.cpp
@@ -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
diff --git a/Source/Core/VideoBackends/Software/TransformUnit.cpp b/Source/Core/VideoBackends/Software/TransformUnit.cpp
index b3cd45a8a3..ab75964c24 100644
--- a/Source/Core/VideoBackends/Software/TransformUnit.cpp
+++ b/Source/Core/VideoBackends/Software/TransformUnit.cpp
@@ -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
 {
diff --git a/Source/Core/VideoBackends/Software/Vec3.h b/Source/Core/VideoBackends/Software/Vec3.h
index da54327fe2..f6c806847e 100644
--- a/Source/Core/VideoBackends/Software/Vec3.h
+++ b/Source/Core/VideoBackends/Software/Vec3.h
@@ -159,11 +159,4 @@ public:
 		y = 0.0f;
 		z = 0.0f;
 	}
-
-	void DoState(PointerWrap &p)
-	{
-		p.Do(x);
-		p.Do(y);
-		p.Do(z);
-	}
 };
diff --git a/Source/Core/VideoBackends/Software/VideoBackend.h b/Source/Core/VideoBackends/Software/VideoBackend.h
index e34ae07f9a..7d9d4437db 100644
--- a/Source/Core/VideoBackends/Software/VideoBackend.h
+++ b/Source/Core/VideoBackends/Software/VideoBackend.h
@@ -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;
 };
 
 }
diff --git a/Source/Core/VideoBackends/Software/XFMemLoader.cpp b/Source/Core/VideoBackends/Software/XFMemLoader.cpp
deleted file mode 100644
index 3aa86aea8e..0000000000
--- a/Source/Core/VideoBackends/Software/XFMemLoader.cpp
+++ /dev/null
@@ -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);
-}
diff --git a/Source/Core/VideoBackends/Software/XFMemLoader.h b/Source/Core/VideoBackends/Software/XFMemLoader.h
deleted file mode 100644
index cfbaecfd1b..0000000000
--- a/Source/Core/VideoBackends/Software/XFMemLoader.h
+++ /dev/null
@@ -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);
diff --git a/Source/Core/VideoCommon/CPMemory.h b/Source/Core/VideoCommon/CPMemory.h
index 491f818305..59183fe47f 100644
--- a/Source/Core/VideoCommon/CPMemory.h
+++ b/Source/Core/VideoCommon/CPMemory.h
@@ -257,6 +257,7 @@ struct CPState final
 	BitSet32 attr_dirty;
 	bool bases_dirty;
 	VertexLoaderBase* vertex_loaders[8];
+	int last_id;
 };
 
 class PointerWrap;
diff --git a/Source/Core/VideoCommon/Statistics.cpp b/Source/Core/VideoCommon/Statistics.cpp
index 04164cdaed..53db2fcf50 100644
--- a/Source/Core/VideoCommon/Statistics.cpp
+++ b/Source/Core/VideoCommon/Statistics.cpp
@@ -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);
diff --git a/Source/Core/VideoCommon/Statistics.h b/Source/Core/VideoCommon/Statistics.h
index edd70bdf97..26c663a513 100644
--- a/Source/Core/VideoCommon/Statistics.h
+++ b/Source/Core/VideoCommon/Statistics.h
@@ -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();
diff --git a/Source/Core/VideoCommon/VertexLoaderManager.cpp b/Source/Core/VideoCommon/VertexLoaderManager.cpp
index baf04ba52a..5012dea9d8 100644
--- a/Source/Core/VideoCommon/VertexLoaderManager.cpp
+++ b/Source/Core/VideoCommon/VertexLoaderManager.cpp
@@ -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])
diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp
index 626e1f0bd0..50486d716a 100644
--- a/Source/Core/VideoCommon/VideoConfig.cpp
+++ b/Source/Core/VideoCommon/VideoConfig.cpp
@@ -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);
diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h
index 5b88e64c2f..bc0250ab2f 100644
--- a/Source/Core/VideoCommon/VideoConfig.h
+++ b/Source/Core/VideoCommon/VideoConfig.h
@@ -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