VideoSW: Use more VideoCommon

Now we require lots of empty functions, but this removes by far more duplicated code.
This commit is contained in:
degasus
2016-01-06 22:10:29 +01:00
parent 7fcb5a803b
commit efbe5bc4b6
51 changed files with 529 additions and 2025 deletions
@@ -1,178 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/HW/Memmap.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/EfbCopy.h"
#include "VideoBackends/Software/EfbInterface.h"
#include "VideoBackends/Software/Rasterizer.h"
#include "VideoBackends/Software/Tev.h"
#include "VideoCommon/BoundingBox.h"
#include "VideoCommon/PixelEngine.h"
#include "VideoCommon/TextureDecoder.h"
#include "VideoCommon/VideoCommon.h"
void InitBPMemory()
{
memset(&bpmem, 0, sizeof(bpmem));
bpmem.bpMask = 0xFFFFFF;
}
void SWLoadBPReg(u32 value)
{
//handle the mask register
int address = value >> 24;
int oldval = ((u32*)&bpmem)[address];
int newval = (oldval & ~bpmem.bpMask) | (value & bpmem.bpMask);
((u32*)&bpmem)[address] = newval;
//reset the mask register
if (address != 0xFE)
bpmem.bpMask = 0xFFFFFF;
SWBPWritten(address, newval);
}
void SWBPWritten(int address, int newvalue)
{
switch (address)
{
case BPMEM_SCISSORTL:
case BPMEM_SCISSORBR:
case BPMEM_SCISSOROFFSET:
Rasterizer::SetScissor();
break;
case BPMEM_SETDRAWDONE: // This is called when the game is done drawing (eg: like in DX: Begin(); Draw(); End();)
switch (bpmem.drawdone & 0xFF)
{
case 0x02:
PixelEngine::SetFinish(); // may generate interrupt
DEBUG_LOG(VIDEO, "GXSetDrawDone SetPEFinish (value: 0x%02X)", (bpmem.drawdone & 0xFFFF));
break;
default:
WARN_LOG(VIDEO, "GXSetDrawDone ??? (value 0x%02X)", (bpmem.drawdone & 0xFFFF));
break;
}
break;
case BPMEM_PE_TOKEN_ID: // Pixel Engine Token ID
DEBUG_LOG(VIDEO, "SetPEToken 0x%04x", (bpmem.petoken & 0xFFFF));
PixelEngine::SetToken(static_cast<u16>(bpmem.petokenint & 0xFFFF), false);
break;
case BPMEM_PE_TOKEN_INT_ID: // Pixel Engine Interrupt Token ID
DEBUG_LOG(VIDEO, "SetPEToken + INT 0x%04x", (bpmem.petokenint & 0xFFFF));
PixelEngine::SetToken(static_cast<u16>(bpmem.petokenint & 0xFFFF), true);
break;
case BPMEM_TRIGGER_EFB_COPY:
EfbCopy::CopyEfb();
break;
case BPMEM_CLEARBBOX1:
BoundingBox::coords[BoundingBox::LEFT] = newvalue >> 10;
BoundingBox::coords[BoundingBox::RIGHT] = newvalue & 0x3ff;
break;
case BPMEM_CLEARBBOX2:
BoundingBox::coords[BoundingBox::TOP] = newvalue >> 10;
BoundingBox::coords[BoundingBox::BOTTOM] = newvalue & 0x3ff;
break;
case BPMEM_CLEAR_PIXEL_PERF:
// TODO: I didn't test if the value written to this register affects the amount of cleared registers
memset(EfbInterface::perf_values, 0, sizeof(EfbInterface::perf_values));
break;
case BPMEM_LOADTLUT0: // This one updates bpmem.tlutXferSrc, no need to do anything here.
break;
case BPMEM_LOADTLUT1: // Load a Texture Look Up Table
{
u32 tlutTMemAddr = (newvalue & 0x3FF) << 9;
u32 tlutXferCount = (newvalue & 0x1FFC00) >> 5;
u32 addr = bpmem.tmem_config.tlut_src << 5;
// The GameCube ignores the upper bits of this address. Some games (WW, MKDD) set them.
if (!SConfig::GetInstance().bWii)
addr = addr & 0x01FFFFFF;
Memory::CopyFromEmu(texMem + tlutTMemAddr, addr, tlutXferCount);
break;
}
case BPMEM_PRELOAD_MODE:
if (newvalue != 0)
{
// TODO: Not quite sure if this is completely correct (likely not)
// NOTE: libogc's implementation of GX_PreloadEntireTexture seems flawed, so it's not necessarily a good reference for RE'ing this feature.
BPS_TmemConfig& tmem_cfg = bpmem.tmem_config;
u32 src_addr = tmem_cfg.preload_addr << 5; // TODO: Should we add mask here on GC?
u32 size = tmem_cfg.preload_tile_info.count * TMEM_LINE_SIZE;
u32 tmem_addr_even = tmem_cfg.preload_tmem_even * TMEM_LINE_SIZE;
if (tmem_cfg.preload_tile_info.type != 3)
{
if (tmem_addr_even + size > TMEM_SIZE)
size = TMEM_SIZE - tmem_addr_even;
Memory::CopyFromEmu(texMem + tmem_addr_even, src_addr, size);
}
else // RGBA8 tiles (and CI14, but that might just be stupid libogc!)
{
u8* src_ptr = Memory::GetPointer(src_addr);
// AR and GB tiles are stored in separate TMEM banks => can't use a single memcpy for everything
u32 tmem_addr_odd = tmem_cfg.preload_tmem_odd * TMEM_LINE_SIZE;
for (unsigned int i = 0; i < tmem_cfg.preload_tile_info.count; ++i)
{
if (tmem_addr_even + TMEM_LINE_SIZE > TMEM_SIZE ||
tmem_addr_odd + TMEM_LINE_SIZE > TMEM_SIZE)
break;
memcpy(texMem + tmem_addr_even, src_ptr, TMEM_LINE_SIZE);
memcpy(texMem + tmem_addr_odd, src_ptr + TMEM_LINE_SIZE, TMEM_LINE_SIZE);
tmem_addr_even += TMEM_LINE_SIZE;
tmem_addr_odd += TMEM_LINE_SIZE;
src_ptr += TMEM_LINE_SIZE * 2;
}
}
}
break;
case BPMEM_TEV_COLOR_RA:
case BPMEM_TEV_COLOR_RA + 2:
case BPMEM_TEV_COLOR_RA + 4:
case BPMEM_TEV_COLOR_RA + 6:
{
int regNum = (address >> 1 ) & 0x3;
TevReg& reg = bpmem.tevregs[regNum];
bool is_konst = reg.type_ra != 0;
Rasterizer::SetTevReg(regNum, Tev::ALP_C, is_konst, static_cast<s16>(reg.alpha));
Rasterizer::SetTevReg(regNum, Tev::RED_C, is_konst, static_cast<s16>(reg.red));
break;
}
case BPMEM_TEV_COLOR_BG:
case BPMEM_TEV_COLOR_BG + 2:
case BPMEM_TEV_COLOR_BG + 4:
case BPMEM_TEV_COLOR_BG + 6:
{
int regNum = (address >> 1 ) & 0x3;
TevReg& reg = bpmem.tevregs[regNum];
bool is_konst = reg.type_bg != 0;
Rasterizer::SetTevReg(regNum, Tev::GRN_C, is_konst, static_cast<s16>(reg.green));
Rasterizer::SetTevReg(regNum, Tev::BLU_C, is_konst, static_cast<s16>(reg.blue));
break;
}
}
}
@@ -1,13 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "Common/CommonTypes.h"
#include "VideoCommon/BPMemory.h"
void InitBPMemory();
void SWBPWritten(int address, int newvalue);
void SWLoadBPReg(u32 value);
@@ -1,24 +1,17 @@
set(SRCS BPMemLoader.cpp
CPMemLoader.cpp
Clipper.cpp
set(SRCS Clipper.cpp
DebugUtil.cpp
EfbCopy.cpp
EfbInterface.cpp
OpcodeDecoder.cpp
Rasterizer.cpp
SWCommandProcessor.cpp
SWOGLWindow.cpp
SWRenderer.cpp
SWStatistics.cpp
SWVertexLoader.cpp
SWVideoConfig.cpp
SWmain.cpp
SetupUnit.cpp
Tev.cpp
TextureEncoder.cpp
TextureSampler.cpp
TransformUnit.cpp
XFMemLoader.cpp)
TransformUnit.cpp)
set(LIBS videocommon
SOIL
@@ -1,60 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Common/CommonFuncs.h"
#include "Core/HW/Memmap.h"
#include "VideoBackends/Software/CPMemLoader.h"
#include "VideoCommon/VideoCommon.h"
void SWLoadCPReg(u32 sub_cmd, u32 value)
{
switch (sub_cmd & 0xF0)
{
case 0x30:
g_main_cp_state.matrix_index_a.Hex = value;
break;
case 0x40:
g_main_cp_state.matrix_index_b.Hex = value;
break;
case 0x50:
g_main_cp_state.vtx_desc.Hex &= ~0x1FFFF; // keep the Upper bits
g_main_cp_state.vtx_desc.Hex |= value;
g_main_cp_state.bases_dirty = true;
break;
case 0x60:
g_main_cp_state.vtx_desc.Hex &= 0x1FFFF; // keep the lower 17Bits
g_main_cp_state.vtx_desc.Hex |= (u64)value << 17;
g_main_cp_state.bases_dirty = true;
break;
case 0x70:
_assert_((sub_cmd & 0x0F) < 8);
g_main_cp_state.vtx_attr[sub_cmd & 7].g0.Hex = value;
break;
case 0x80:
_assert_((sub_cmd & 0x0F) < 8);
g_main_cp_state.vtx_attr[sub_cmd & 7].g1.Hex = value;
break;
case 0x90:
_assert_((sub_cmd & 0x0F) < 8);
g_main_cp_state.vtx_attr[sub_cmd & 7].g2.Hex = value;
break;
// Pointers to vertex arrays in GC RAM
case 0xA0:
g_main_cp_state.array_bases[sub_cmd & 0xF] = value;
g_main_cp_state.bases_dirty = true;
break;
case 0xB0:
g_main_cp_state.array_strides[sub_cmd & 0xF] = value & 0xFF;
break;
}
}
@@ -1,10 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "Common/CommonTypes.h"
#include "VideoCommon/CPMemory.h"
void SWLoadCPReg(u32 sub_cmd, u32 value);
+9 -15
View File
@@ -36,12 +36,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Common/ChunkFile.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/Clipper.h"
#include "VideoBackends/Software/NativeVertexFormat.h"
#include "VideoBackends/Software/Rasterizer.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/XFMemLoader.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/XFMemory.h"
namespace Clipper
{
@@ -56,13 +57,6 @@ namespace Clipper
static OutputVertexData ClippedVertices[NUM_CLIPPED_VERTICES];
static OutputVertexData *Vertices[NUM_INDICES];
void DoState(PointerWrap &p)
{
p.DoArray(m_ViewOffset);
for (auto& ClippedVertice : ClippedVertices)
ClippedVertice.DoState(p);
}
void Init()
{
for (int i = 0; i < NUM_CLIPPED_VERTICES; ++i)
@@ -220,7 +214,7 @@ namespace Clipper
POLY_CLIP(CLIP_POS_Z_BIT, 0, 0, 0, 1);
POLY_CLIP(CLIP_NEG_Z_BIT, 0, 0, 1, 1);
INCSTAT(swstats.thisFrame.numTrianglesClipped);
INCSTAT(stats.thisFrame.numTrianglesClipped);
// transform the poly in inlist into triangles
indices[0] = inlist[0];
@@ -287,7 +281,7 @@ namespace Clipper
void ProcessTriangle(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
{
INCSTAT(swstats.thisFrame.numTrianglesIn)
INCSTAT(stats.thisFrame.numTrianglesIn)
bool backface;
@@ -411,7 +405,7 @@ namespace Clipper
if (mask)
{
INCSTAT(swstats.thisFrame.numTrianglesRejected)
INCSTAT(stats.thisFrame.numTrianglesRejected)
return false;
}
@@ -431,13 +425,13 @@ namespace Clipper
if ((bpmem.genMode.cullmode & 1) && !backface) // cull frontfacing
{
INCSTAT(swstats.thisFrame.numTrianglesCulled)
INCSTAT(stats.thisFrame.numTrianglesCulled)
return false;
}
if ((bpmem.genMode.cullmode & 2) && backface) // cull backfacing
{
INCSTAT(swstats.thisFrame.numTrianglesCulled)
INCSTAT(stats.thisFrame.numTrianglesCulled)
return false;
}
@@ -5,7 +5,6 @@
#pragma once
struct OutputVertexData;
class PointerWrap;
namespace Clipper
{
@@ -20,6 +19,4 @@ namespace Clipper
bool CullTest(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2, bool &backface);
void PerspectiveDivide(OutputVertexData *vertex);
void DoState(PointerWrap &p);
}
@@ -8,18 +8,16 @@
#include "Core/ConfigManager.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/DebugUtil.h"
#include "VideoBackends/Software/EfbInterface.h"
#include "VideoBackends/Software/SWCommandProcessor.h"
#include "VideoBackends/Software/SWRenderer.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/SWVideoConfig.h"
#include "VideoBackends/Software/TextureSampler.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/Fifo.h"
#include "VideoCommon/ImageWrite.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/VideoConfig.h"
namespace DebugUtil
{
@@ -109,7 +107,7 @@ void DumpActiveTextures()
{
SaveTexture(StringFromFormat("%star%i_ind%i_map%i_mip%i.png",
File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
swstats.thisFrame.numDrawnObjects, stageNum, texmap, mip), texmap, mip);
stats.thisFrame.numDrawnObjects, stageNum, texmap, mip), texmap, mip);
}
}
@@ -126,7 +124,7 @@ void DumpActiveTextures()
{
SaveTexture(StringFromFormat("%star%i_stage%i_map%i_mip%i.png",
File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
swstats.thisFrame.numDrawnObjects, stageNum, texmap, mip), texmap, mip);
stats.thisFrame.numDrawnObjects, stageNum, texmap, mip), texmap, mip);
}
}
}
@@ -154,13 +152,6 @@ static void DumpEfb(const std::string& filename)
delete[] data;
}
static void DumpColorTexture(const std::string& filename, u32 width, u32 height)
{
TextureToPng(SWRenderer::GetCurrentColorTexture(), width * 4, filename, width, height, true);
}
void DrawObjectBuffer(s16 x, s16 y, u8 *color, int bufferBase, int subBuffer, const char *name)
{
int buffer = bufferBase + subBuffer;
@@ -202,7 +193,7 @@ void OnObjectBegin()
{
if (!g_bSkipCurrentFrame)
{
if (g_SWVideoConfig.bDumpTextures && swstats.thisFrame.numDrawnObjects >= g_SWVideoConfig.drawStart && swstats.thisFrame.numDrawnObjects < g_SWVideoConfig.drawEnd)
if (g_ActiveConfig.bDumpTextures && stats.thisFrame.numDrawnObjects >= g_ActiveConfig.drawStart && stats.thisFrame.numDrawnObjects < g_ActiveConfig.drawEnd)
DumpActiveTextures();
}
}
@@ -211,10 +202,10 @@ void OnObjectEnd()
{
if (!g_bSkipCurrentFrame)
{
if (g_SWVideoConfig.bDumpObjects && swstats.thisFrame.numDrawnObjects >= g_SWVideoConfig.drawStart && swstats.thisFrame.numDrawnObjects < g_SWVideoConfig.drawEnd)
if (g_ActiveConfig.bDumpObjects && stats.thisFrame.numDrawnObjects >= g_ActiveConfig.drawStart && stats.thisFrame.numDrawnObjects < g_ActiveConfig.drawEnd)
DumpEfb(StringFromFormat("%sobject%i.png",
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(),
swstats.thisFrame.numDrawnObjects));
stats.thisFrame.numDrawnObjects));
for (int i = 0; i < NUM_OBJECT_BUFFERS; i++)
{
@@ -223,7 +214,7 @@ void OnObjectEnd()
DrawnToBuffer[i] = false;
std::string filename = StringFromFormat("%sobject%i_%s(%i).png",
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(),
swstats.thisFrame.numDrawnObjects, ObjectBufferName[i], i - BufferBase[i]);
stats.thisFrame.numDrawnObjects, ObjectBufferName[i], i - BufferBase[i]);
TextureToPng((u8*)ObjectBuffer[i], EFB_WIDTH * 4, filename, EFB_WIDTH, EFB_HEIGHT, true);
memset(ObjectBuffer[i], 0, EFB_WIDTH * EFB_HEIGHT * sizeof(u32));
@@ -231,20 +222,7 @@ void OnObjectEnd()
}
}
swstats.thisFrame.numDrawnObjects++;
}
}
// If frame dumping is enabled, dump whatever is drawn to the screen.
void OnFrameEnd(u32 width, u32 height)
{
if (!g_bSkipCurrentFrame)
{
if (SConfig::GetInstance().m_DumpFrames)
{
DumpColorTexture(StringFromFormat("%sframe%i_color.png",
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), swstats.frameCount), width, height);
}
stats.thisFrame.numDrawnObjects++;
}
}
@@ -18,8 +18,6 @@ namespace DebugUtil
void OnObjectBegin();
void OnObjectEnd();
void OnFrameEnd(u32 width, u32 height);
void DrawObjectBuffer(s16 x, s16 y, u8 *color, int bufferBase, int subBuffer, const char *name);
void DrawTempBuffer(u8 *color, int buffer);
+5 -34
View File
@@ -5,15 +5,13 @@
#include "Common/GL/GLInterfaceBase.h"
#include "Core/Core.h"
#include "Core/HW/Memmap.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/DebugUtil.h"
#include "VideoBackends/Software/EfbCopy.h"
#include "VideoBackends/Software/EfbInterface.h"
#include "VideoBackends/Software/SWCommandProcessor.h"
#include "VideoBackends/Software/SWRenderer.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/SWVideoConfig.h"
#include "VideoBackends/Software/TextureEncoder.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/Fifo.h"
static const float s_gammaLUT[] =
@@ -33,31 +31,9 @@ namespace EfbCopy
INFO_LOG(VIDEO, "xfbaddr: %x, fbwidth: %i, fbheight: %i, source: (%i, %i, %i, %i), Gamma %f",
xfbAddr, fbWidth, fbHeight, sourceRc.top, sourceRc.left, sourceRc.bottom, sourceRc.right, Gamma);
if (!g_SWVideoConfig.bBypassXFB)
{
EfbInterface::yuv422_packed* xfb_in_ram = (EfbInterface::yuv422_packed *) Memory::GetPointer(xfbAddr);
EfbInterface::yuv422_packed* xfb_in_ram = (EfbInterface::yuv422_packed*) Memory::GetPointer(xfbAddr);
EfbInterface::CopyToXFB(xfb_in_ram, fbWidth, fbHeight, sourceRc, Gamma);
}
else
{
// Ask SWRenderer for the next color texture
u8 *colorTexture = SWRenderer::GetNextColorTexture();
EfbInterface::BypassXFB(colorTexture, fbWidth, fbHeight, sourceRc, Gamma);
// Tell SWRenderer we are now finished with it.
SWRenderer::SwapColorTexture();
// FifoPlayer is broken and never calls BeginFrame/EndFrame.
// Hence, we manually force a swap now. This emulates the behavior
// of hardware backends with XFB emulation disabled.
// TODO: Fix FifoPlayer by making proper use of VideoInterface!
// This requires careful synchronization since GPU commands
// are processed on a different thread than VI commands.
SWRenderer::Swap(fbWidth, fbHeight);
DebugUtil::OnFrameEnd(fbWidth, fbHeight);
}
EfbInterface::CopyToXFB(xfb_in_ram, fbWidth, fbHeight, sourceRc, Gamma);
}
static void CopyToRam()
@@ -67,7 +43,7 @@ namespace EfbCopy
TextureEncoder::Encode(dest_ptr);
}
static void ClearEfb()
void ClearEfb()
{
u32 clearColor = (bpmem.clearcolorAR & 0xff) << 24 | bpmem.clearcolorGB << 8 | (bpmem.clearcolorAR & 0xff00) >> 8;
@@ -128,11 +104,6 @@ namespace EfbCopy
{
CopyToRam(); // FIXME: should use the rectangle we have already created above
}
if (bpmem.triggerEFBCopy.clear)
{
ClearEfb();
}
}
}
}
+2 -1
View File
@@ -9,6 +9,7 @@
namespace EfbCopy
{
// Copy the EFB to RAM as a texture format or XFB
// Clear the EFB if needed
void CopyEfb();
void ClearEfb();
}
@@ -8,9 +8,9 @@
#include "Common/CommonTypes.h"
#include "Core/HW/Memmap.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/EfbInterface.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/LookUpTables.h"
#include "VideoCommon/PixelEngine.h"
@@ -31,11 +31,6 @@ namespace EfbInterface
return (x + y * EFB_WIDTH) * 3 + DEPTH_BUFFER_START;
}
void DoState(PointerWrap &p)
{
p.DoArray(efb);
}
static void SetPixelAlphaOnly(u32 offset, u8 a)
{
switch (bpmem.zcontrol.pixel_format)
@@ -58,8 +58,6 @@ namespace EfbInterface
void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma);
void BypassXFB(u8* texture, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma);
void DoState(PointerWrap &p);
extern u32 perf_values[PQ_NUM_MEMBERS];
inline void IncPerfCounterQuadCount(PerfQueryType type)
{
@@ -77,16 +77,4 @@ struct OutputVertexData
#undef LINTERP
#undef LINTERP_INT
}
void DoState(PointerWrap &p)
{
mvPosition.DoState(p);
p.Do(projectedPosition);
screenPosition.DoState(p);
for (auto& vec : normal)
vec.DoState(p);
p.DoArray(color, sizeof color);
for (auto& vec : texCoords)
vec.DoState(p);
}
};
@@ -1,304 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Common/ChunkFile.h"
#include "Common/CommonTypes.h"
#include "Core/HW/Memmap.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/CPMemLoader.h"
#include "VideoBackends/Software/DebugUtil.h"
#include "VideoBackends/Software/OpcodeDecoder.h"
#include "VideoBackends/Software/SWCommandProcessor.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/SWVertexLoader.h"
#include "VideoBackends/Software/SWVideoConfig.h"
#include "VideoBackends/Software/XFMemLoader.h"
#include "VideoCommon/Fifo.h"
#include "VideoCommon/VertexLoaderUtils.h"
typedef void (*DecodingFunction)(u32);
namespace OpcodeDecoder
{
static DecodingFunction currentFunction = nullptr;
static u32 minCommandSize;
static u16 streamSize;
static u16 streamAddress;
static bool readOpcode;
static SWVertexLoader vertexLoader;
static bool inObjectStream;
static u8 lastPrimCmd;
void DoState(PointerWrap &p)
{
p.Do(minCommandSize);
// Not sure what is wrong with this. Something(s) in here is causing Dolphin to crash/hang when loading states saved from another run of Dolphin. Doesn't seem too important anyway...
//vertexLoader.DoState(p);
p.Do(readOpcode);
p.Do(inObjectStream);
p.Do(lastPrimCmd);
p.Do(streamSize);
p.Do(streamAddress);
if (p.GetMode() == PointerWrap::MODE_READ)
ResetDecoding();
}
static void DecodePrimitiveStream(u32 iBufferSize)
{
u32 vertexSize = vertexLoader.GetVertexSize();
bool skipPrimitives = g_bSkipCurrentFrame ||
swstats.thisFrame.numDrawnObjects < g_SWVideoConfig.drawStart ||
swstats.thisFrame.numDrawnObjects >= g_SWVideoConfig.drawEnd;
if (skipPrimitives)
{
while (streamSize > 0 && iBufferSize >= vertexSize)
{
g_video_buffer_read_ptr += vertexSize;
iBufferSize -= vertexSize;
streamSize--;
}
}
else
{
while (streamSize > 0 && iBufferSize >= vertexSize)
{
vertexLoader.LoadVertex();
iBufferSize -= vertexSize;
streamSize--;
}
}
if (streamSize == 0)
{
// return to normal command processing
ResetDecoding();
}
}
static void ReadXFData(u32 iBufferSize)
{
_assert_msg_(VIDEO, iBufferSize >= (u32)(streamSize * 4), "Underflow during standard opcode decoding");
u32 pData[16];
for (int i = 0; i < streamSize; i++)
pData[i] = DataRead<u32>();
SWLoadXFReg(streamSize, streamAddress, pData);
// return to normal command processing
ResetDecoding();
}
static void ExecuteDisplayList(u32 addr, u32 count)
{
u8 *videoDataSave = g_video_buffer_read_ptr;
u8 *dlStart = Memory::GetPointer(addr);
g_video_buffer_read_ptr = dlStart;
while (OpcodeDecoder::CommandRunnable(count))
{
OpcodeDecoder::Run(count);
// if data was read by the opcode decoder then the video data pointer changed
u32 readCount = (u32)(g_video_buffer_read_ptr - dlStart);
dlStart = g_video_buffer_read_ptr;
_assert_msg_(VIDEO, count >= readCount, "Display list underrun");
count -= readCount;
}
g_video_buffer_read_ptr = videoDataSave;
}
static void DecodeStandard(u32 bufferSize)
{
_assert_msg_(VIDEO, CommandRunnable(bufferSize), "Underflow during standard opcode decoding");
int Cmd = DataRead<u8>();
if (Cmd == GX_NOP)
return;
// Causes a SIGBUS error on Android
// XXX: Investigate
#ifndef ANDROID
// check if switching in or out of an object
// only used for debugging
if (inObjectStream && (Cmd & 0x87) != lastPrimCmd)
{
inObjectStream = false;
DebugUtil::OnObjectEnd();
}
if (Cmd & 0x80 && !inObjectStream)
{
inObjectStream = true;
lastPrimCmd = Cmd & 0x87;
DebugUtil::OnObjectBegin();
}
#endif
switch (Cmd)
{
case GX_NOP:
break;
case GX_LOAD_CP_REG: //0x08
{
u32 SubCmd = DataRead<u8>();
u32 Value = DataRead<u32>();
SWLoadCPReg(SubCmd, Value);
}
break;
case GX_LOAD_XF_REG:
{
u32 Cmd2 = DataRead<u32>();
streamSize = ((Cmd2 >> 16) & 15) + 1;
streamAddress = Cmd2 & 0xFFFF;
currentFunction = ReadXFData;
minCommandSize = streamSize * 4;
readOpcode = false;
}
break;
case GX_LOAD_INDX_A: //used for position matrices
SWLoadIndexedXF(DataRead<u32>(), 0xC);
break;
case GX_LOAD_INDX_B: //used for normal matrices
SWLoadIndexedXF(DataRead<u32>(), 0xD);
break;
case GX_LOAD_INDX_C: //used for postmatrices
SWLoadIndexedXF(DataRead<u32>(), 0xE);
break;
case GX_LOAD_INDX_D: //used for lights
SWLoadIndexedXF(DataRead<u32>(), 0xF);
break;
case GX_CMD_CALL_DL:
{
u32 dwAddr = DataRead<u32>();
u32 dwCount = DataRead<u32>();
ExecuteDisplayList(dwAddr, dwCount);
}
break;
case 0x44:
// zelda 4 swords calls it and checks the metrics registers after that
break;
case GX_CMD_INVL_VC:// Invalidate (vertex cache?)
DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)");
break;
case GX_LOAD_BP_REG: //0x61
{
u32 cmd = DataRead<u32>();
SWLoadBPReg(cmd);
}
break;
// draw primitives
default:
if ((Cmd & 0xC0) == 0x80)
{
u8 vatIndex = Cmd & GX_VAT_MASK;
u8 primitiveType = (Cmd & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT;
vertexLoader.SetFormat(vatIndex, primitiveType);
// switch to primitive processing
streamSize = DataRead<u16>();
currentFunction = DecodePrimitiveStream;
minCommandSize = vertexLoader.GetVertexSize();
readOpcode = false;
INCSTAT(swstats.thisFrame.numPrimatives);
DEBUG_LOG(VIDEO, "Draw begin");
}
else
{
PanicAlert("GFX: Unknown Opcode (0x%x).\n", Cmd);
break;
}
break;
}
}
void Init()
{
inObjectStream = false;
lastPrimCmd = 0;
ResetDecoding();
}
void ResetDecoding()
{
currentFunction = DecodeStandard;
minCommandSize = 1;
readOpcode = true;
}
bool CommandRunnable(u32 iBufferSize)
{
if (iBufferSize < minCommandSize)
return false;
if (readOpcode)
{
u8 Cmd = DataPeek<u8>(0);
u32 minSize = 1;
switch (Cmd)
{
case GX_LOAD_CP_REG: //0x08
minSize = 6;
break;
case GX_LOAD_XF_REG:
minSize = 5;
break;
case GX_LOAD_INDX_A: //used for position matrices
minSize = 5;
break;
case GX_LOAD_INDX_B: //used for normal matrices
minSize = 5;
break;
case GX_LOAD_INDX_C: //used for postmatrices
minSize = 5;
break;
case GX_LOAD_INDX_D: //used for lights
minSize = 5;
break;
case GX_CMD_CALL_DL:
minSize = 9;
break;
case GX_LOAD_BP_REG: //0x61
minSize = 5;
break;
// draw primitives
default:
if ((Cmd & 0xC0) == 0x80)
minSize = 3;
break;
}
return (iBufferSize >= minSize);
}
return true;
}
void Run(u32 iBufferSize)
{
currentFunction(iBufferSize);
}
}
@@ -1,52 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "Common/CommonTypes.h"
class PointerWrap;
namespace OpcodeDecoder
{
#define GX_NOP 0x00
#define GX_LOAD_BP_REG 0x61
#define GX_LOAD_CP_REG 0x08
#define GX_LOAD_XF_REG 0x10
#define GX_LOAD_INDX_A 0x20
#define GX_LOAD_INDX_B 0x28
#define GX_LOAD_INDX_C 0x30
#define GX_LOAD_INDX_D 0x38
#define GX_CMD_CALL_DL 0x40
#define GX_CMD_INVL_VC 0x48
#define GX_PRIMITIVE_MASK 0x38
#define GX_PRIMITIVE_SHIFT 3
#define GX_VAT_MASK 0x07
// These values are the values extracted using GX_PRIMITIVE_MASK
// and GX_PRIMITIVE_SHIFT.
// GX_DRAW_QUADS_2 behaves the same way as GX_DRAW_QUADS.
#define GX_DRAW_QUADS 0x0 //0x80
#define GX_DRAW_QUADS_2 0x1 //0x88
#define GX_DRAW_TRIANGLES 0x2 //0x90
#define GX_DRAW_TRIANGLE_STRIP 0x3 //0x98
#define GX_DRAW_TRIANGLE_FAN 0x4 //0xA0
#define GX_DRAW_LINES 0x5 //0xA8
#define GX_DRAW_LINE_STRIP 0x6 //0xB0
#define GX_DRAW_POINTS 0x7 //0xB8
void Init();
void ResetDecoding();
bool CommandRunnable(u32 iBufferSize);
void Run(u32 iBufferSize);
void DoState(PointerWrap &p);
}
@@ -6,15 +6,14 @@
#include <cstring>
#include "Common/CommonTypes.h"
#include "VideoBackends/Software/BPMemLoader.h"
#include "VideoBackends/Software/EfbInterface.h"
#include "VideoBackends/Software/NativeVertexFormat.h"
#include "VideoBackends/Software/Rasterizer.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/SWVideoConfig.h"
#include "VideoBackends/Software/Tev.h"
#include "VideoBackends/Software/XFMemLoader.h"
#include "VideoCommon/BoundingBox.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h"
namespace Rasterizer
{
@@ -38,28 +37,6 @@ static s32 scissorBottom = 0;
static Tev tev;
static RasterBlock rasterBlock;
void DoState(PointerWrap &p)
{
ZSlope.DoState(p);
WSlope.DoState(p);
for (auto& color_slopes_1d : ColorSlopes)
for (Slope& color_slope : color_slopes_1d)
color_slope.DoState(p);
for (auto& tex_slopes_1d : TexSlopes)
for (Slope& tex_slope : tex_slopes_1d)
tex_slope.DoState(p);
p.Do(vertex0X);
p.Do(vertex0Y);
p.Do(vertexOffsetX);
p.Do(vertexOffsetY);
p.Do(scissorLeft);
p.Do(scissorTop);
p.Do(scissorRight);
p.Do(scissorBottom);
tev.DoState(p);
p.Do(rasterBlock);
}
void Init()
{
tev.Init();
@@ -121,14 +98,14 @@ void SetTevReg(int reg, int comp, bool konst, s16 color)
static void Draw(s32 x, s32 y, s32 xi, s32 yi)
{
INCSTAT(swstats.thisFrame.rasterizedPixels);
INCSTAT(stats.thisFrame.rasterizedPixels);
float dx = vertexOffsetX + (float)(x - vertex0X);
float dy = vertexOffsetY + (float)(y - vertex0Y);
s32 z = (s32)MathUtil::Clamp<float>(ZSlope.GetValue(dx, dy), 0.0f, 16777215.0f);
if (bpmem.UseEarlyDepthTest() && g_SWVideoConfig.bZComploc)
if (bpmem.UseEarlyDepthTest() && g_ActiveConfig.bZComploc)
{
// TODO: Test if perf regs are incremented even if test is disabled
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT_ZCOMPLOC);
@@ -314,7 +291,7 @@ static void BuildBlock(s32 blockX, s32 blockY)
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
{
INCSTAT(swstats.thisFrame.numTrianglesDrawn);
INCSTAT(stats.thisFrame.numTrianglesDrawn);
// adapted from http://devmaster.net/posts/6145/advanced-rasterization
@@ -378,7 +355,7 @@ void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVer
// Many things might prevent us from reaching this line (culling, clipping, scissoring).
// However, the zslope is always guaranteed to be calculated unless all vertices are trivially rejected during clipping!
// We're currently sloppy at this since we abort early if any of the culling/clipping/scissoring tests fail.
if (!bpmem.genMode.zfreeze || !g_SWVideoConfig.bZFreeze)
if (!bpmem.genMode.zfreeze || !g_ActiveConfig.bZFreeze)
InitSlope(&ZSlope, v0->screenPosition[2], v1->screenPosition[2], v2->screenPosition[2], fltdx31, fltdx12, fltdy12, fltdy31);
for (unsigned int i = 0; i < bpmem.genMode.numcolchans; i++)
@@ -25,12 +25,6 @@ namespace Rasterizer
float f0;
float GetValue(float dx, float dy) { return f0 + (dfdx * dx) + (dfdy * dy); }
void DoState(PointerWrap &p)
{
p.Do(dfdx);
p.Do(dfdy);
p.Do(f0);
}
};
struct RasterBlockPixel
@@ -47,6 +41,4 @@ namespace Rasterizer
s32 TextureLod[16];
bool TextureLinear[16];
};
void DoState(PointerWrap &p);
}
@@ -1,354 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <atomic>
#include "Common/Atomic.h"
#include "Common/ChunkFile.h"
#include "Common/CommonTypes.h"
#include "Common/FPURoundMode.h"
#include "Common/MathUtil.h"
#include "Common/Thread.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h"
#include "Core/HW/Memmap.h"
#include "Core/HW/MMIO.h"
#include "Core/HW/ProcessorInterface.h"
#include "VideoBackends/Software/OpcodeDecoder.h"
#include "VideoBackends/Software/SWCommandProcessor.h"
#include "VideoBackends/Software/VideoBackend.h"
#include "VideoCommon/Fifo.h"
#include "VideoCommon/VertexLoaderUtils.h"
namespace SWCommandProcessor
{
enum
{
GATHER_PIPE_SIZE = 32,
INT_CAUSE_CP = 0x800
};
// STATE_TO_SAVE
// variables
static const int commandBufferSize = 1024 * 1024;
static const int maxCommandBufferWrite = commandBufferSize - GATHER_PIPE_SIZE;
static u8 commandBuffer[commandBufferSize];
static u32 readPos;
static u32 writePos;
static int et_UpdateInterrupts;
static std::atomic<bool> interruptSet;
static std::atomic<bool> interruptWaiting;
static CPReg cpreg; // shared between gfx and emulator thread
void DoState(PointerWrap &p)
{
p.DoPOD(cpreg);
p.DoArray(commandBuffer, commandBufferSize);
p.Do(readPos);
p.Do(writePos);
p.Do(et_UpdateInterrupts);
p.Do(interruptSet);
p.Do(interruptWaiting);
// Is this right?
p.DoArray(g_video_buffer_read_ptr, writePos);
}
static void UpdateInterrupts_Wrapper(u64 userdata, int cyclesLate)
{
UpdateInterrupts(userdata);
}
static inline bool AtBreakpoint()
{
return cpreg.ctrl.BPEnable && (cpreg.readptr == cpreg.breakpt);
}
void Init()
{
cpreg.status.Hex = 0;
cpreg.status.CommandIdle = 1;
cpreg.status.ReadIdle = 1;
cpreg.ctrl.Hex = 0;
cpreg.clear.Hex = 0;
cpreg.bboxleft = 0;
cpreg.bboxtop = 0;
cpreg.bboxright = 0;
cpreg.bboxbottom = 0;
cpreg.token = 0;
et_UpdateInterrupts = CoreTiming::RegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper);
// internal buffer position
readPos = 0;
writePos = 0;
interruptSet.store(false);
interruptWaiting.store(false);
g_video_buffer_read_ptr = nullptr;
g_bSkipCurrentFrame = false;
}
void Shutdown()
{
}
void RunGpu()
{
if (!SConfig::GetInstance().bCPUThread)
{
// We are going to do FP math on the main thread so have to save the current state
FPURoundMode::SaveSIMDState();
FPURoundMode::LoadDefaultSIMDState();
// run the opcode decoder
do
{
RunBuffer();
} while (cpreg.ctrl.GPReadEnable && !AtBreakpoint() && cpreg.readptr != cpreg.writeptr);
FPURoundMode::LoadSIMDState();
}
}
void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
{
// Directly map reads and writes to the cpreg structure.
for (u32 i = 0; i < sizeof (cpreg) / sizeof (u16); ++i)
{
u16* ptr = ((u16*)&cpreg) + i;
mmio->Register(base | (i * 2),
MMIO::DirectRead<u16>(ptr),
MMIO::DirectWrite<u16>(ptr)
);
}
// Bleh. Apparently SWCommandProcessor does not know about regs 0x40 to
// 0x64...
for (u32 i = 0x40; i < 0x64; ++i)
{
mmio->Register(base | i,
MMIO::Constant<u16>(0),
MMIO::Nop<u16>()
);
}
// The low part of MMIO regs for FIFO addresses needs to be aligned to 32
// bytes.
u32 fifo_addr_lo_regs[] = {
CommandProcessor::FIFO_BASE_LO,
CommandProcessor::FIFO_END_LO,
CommandProcessor::FIFO_WRITE_POINTER_LO,
CommandProcessor::FIFO_READ_POINTER_LO,
CommandProcessor::FIFO_BP_LO,
CommandProcessor::FIFO_RW_DISTANCE_LO,
};
for (u32 reg : fifo_addr_lo_regs)
{
mmio->RegisterWrite(base | reg,
MMIO::DirectWrite<u16>(((u16*)&cpreg) + (reg / 2), 0xFFE0)
);
}
// The clear register needs to perform some more complicated operations on
// writes.
mmio->RegisterWrite(base | CommandProcessor::CLEAR_REGISTER,
MMIO::ComplexWrite<u16>([](u32, u16 val) {
UCPClearReg tmpClear(val);
if (tmpClear.ClearFifoOverflow)
cpreg.status.OverflowHiWatermark = 0;
if (tmpClear.ClearFifoUnderflow)
cpreg.status.UnderflowLoWatermark = 0;
})
);
}
void GatherPipeBursted()
{
if (cpreg.ctrl.GPLinkEnable)
{
DEBUG_LOG(COMMANDPROCESSOR,"\t WGP burst. write thru : %08x", cpreg.writeptr);
if (cpreg.writeptr == cpreg.fifoend)
cpreg.writeptr = cpreg.fifobase;
else
cpreg.writeptr += GATHER_PIPE_SIZE;
Common::AtomicAdd(cpreg.rwdistance, GATHER_PIPE_SIZE);
}
RunGpu();
}
void UpdateInterrupts(u64 userdata)
{
if (userdata)
{
interruptSet.store(true);
INFO_LOG(COMMANDPROCESSOR,"Interrupt set");
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true);
}
else
{
interruptSet.store(false);
INFO_LOG(COMMANDPROCESSOR,"Interrupt cleared");
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, false);
}
interruptWaiting.store(false);
}
void UpdateInterruptsFromVideoBackend(u64 userdata)
{
CoreTiming::ScheduleEvent_Threadsafe(0, et_UpdateInterrupts, userdata);
}
static void ReadFifo()
{
bool canRead = cpreg.readptr != cpreg.writeptr && writePos < (int)maxCommandBufferWrite;
bool atBreakpoint = AtBreakpoint();
if (canRead && !atBreakpoint)
{
// read from fifo
u8 *ptr = Memory::GetPointer(cpreg.readptr);
int bytesRead = 0;
do
{
// copy to buffer
memcpy(&commandBuffer[writePos], ptr, GATHER_PIPE_SIZE);
writePos += GATHER_PIPE_SIZE;
bytesRead += GATHER_PIPE_SIZE;
if (cpreg.readptr == cpreg.fifoend)
{
cpreg.readptr = cpreg.fifobase;
ptr = Memory::GetPointer(cpreg.readptr);
}
else
{
cpreg.readptr += GATHER_PIPE_SIZE;
ptr += GATHER_PIPE_SIZE;
}
canRead = cpreg.readptr != cpreg.writeptr && writePos < (int)maxCommandBufferWrite;
atBreakpoint = AtBreakpoint();
} while (canRead && !atBreakpoint);
Common::AtomicAdd(cpreg.rwdistance, -bytesRead);
}
}
static void SetStatus()
{
// overflow check
if (cpreg.rwdistance > cpreg.hiwatermark)
cpreg.status.OverflowHiWatermark = 1;
// underflow check
if (cpreg.rwdistance < cpreg.lowatermark)
cpreg.status.UnderflowLoWatermark = 1;
// breakpoint
if (cpreg.ctrl.BPEnable)
{
if (cpreg.breakpt == cpreg.readptr)
{
if (!cpreg.status.Breakpoint)
INFO_LOG(COMMANDPROCESSOR, "Hit breakpoint at %x", cpreg.readptr);
cpreg.status.Breakpoint = 1;
}
}
else
{
if (cpreg.status.Breakpoint)
INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %x", cpreg.readptr);
cpreg.status.Breakpoint = 0;
}
cpreg.status.ReadIdle = cpreg.readptr == cpreg.writeptr;
bool bpInt = cpreg.status.Breakpoint && cpreg.ctrl.BPInt;
bool ovfInt = cpreg.status.OverflowHiWatermark && cpreg.ctrl.FifoOverflowIntEnable;
bool undfInt = cpreg.status.UnderflowLoWatermark && cpreg.ctrl.FifoUnderflowIntEnable;
bool interrupt = bpInt || ovfInt || undfInt;
if (interrupt != interruptSet.load() && !interruptWaiting.load())
{
u64 userdata = interrupt?1:0;
if (SConfig::GetInstance().bCPUThread)
{
interruptWaiting.store(true);
SWCommandProcessor::UpdateInterruptsFromVideoBackend(userdata);
}
else
{
SWCommandProcessor::UpdateInterrupts(userdata);
}
}
}
bool RunBuffer()
{
// fifo is read 32 bytes at a time
// read fifo data to internal buffer
if (cpreg.ctrl.GPReadEnable)
ReadFifo();
SetStatus();
_dbg_assert_(COMMANDPROCESSOR, writePos >= readPos);
g_video_buffer_read_ptr = &commandBuffer[readPos];
u32 availableBytes = writePos - readPos;
while (OpcodeDecoder::CommandRunnable(availableBytes))
{
cpreg.status.CommandIdle = 0;
OpcodeDecoder::Run(availableBytes);
// if data was read by the opcode decoder then the video data pointer changed
readPos = (u32)(g_video_buffer_read_ptr - &commandBuffer[0]);
_dbg_assert_(VIDEO, writePos >= readPos);
availableBytes = writePos - readPos;
}
cpreg.status.CommandIdle = 1;
bool ranDecoder = false;
// move data remaining in the command buffer
if (readPos > 0)
{
memmove(&commandBuffer[0], &commandBuffer[readPos], availableBytes);
writePos -= readPos;
readPos = 0;
ranDecoder = true;
}
return ranDecoder;
}
void SetRendering(bool enabled)
{
g_bSkipCurrentFrame = !enabled;
}
} // end of namespace SWCommandProcessor
@@ -1,61 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "Common/CommonTypes.h"
#include "VideoCommon/CommandProcessor.h"
class PointerWrap;
namespace MMIO { class Mapping; }
namespace SWCommandProcessor
{
using UCPStatusReg = CommandProcessor::UCPStatusReg;
using UCPCtrlReg = CommandProcessor::UCPCtrlReg;
using UCPClearReg = CommandProcessor::UCPClearReg;
struct CPReg
{
UCPStatusReg status; // 0x00
UCPCtrlReg ctrl; // 0x02
UCPClearReg clear; // 0x04
u32 unk0; // 0x08
u16 unk1; // 0x0c
u16 token; // 0x0e
u16 bboxleft; // 0x10
u16 bboxtop; // 0x12
u16 bboxright; // 0x14
u16 bboxbottom; // 0x16
u32 unk2; // 0x18
u32 unk3; // 0x1c
u32 fifobase; // 0x20
u32 fifoend; // 0x24
u32 hiwatermark; // 0x28
u32 lowatermark; // 0x2c
u32 rwdistance; // 0x30
u32 writeptr; // 0x34
u32 readptr; // 0x38
u32 breakpt; // 0x3c
};
// Init
void Init();
void Shutdown();
void DoState(PointerWrap &p);
void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
bool RunBuffer();
void RunGpu();
// for CGPFIFO
void GatherPipeBursted();
void UpdateInterrupts(u64 userdata);
void UpdateInterruptsFromVideoBackend(u64 userdata);
void SetRendering(bool enabled);
} // end of namespace SWCommandProcessor

Some files were not shown because too many files have changed in this diff Show More