Changes to allow LoadCPReg to work in a preprocess mode which affects a separate state.

This state will be used to calculate sizes for skipping over commands on
a separate thread.  An alternative to having these state variables would
be to have the preprocessor stash "state as we go" somewhere, but I
think that would be much uglier.

GetVertexSize now takes an extra argument to determine which state to
use, as does FifoCommandRunnable, which calls it.  While I'm modifying
FifoCommandRunnable, I also change it to take a buffer and size as
parameters rather than using g_pVideoData, which will also be necessary
later.  I also get rid of an unused overload.
This commit is contained in:
comex 2014-08-27 13:38:00 -04:00
parent f0131c2e09
commit e86ddacb18
5 changed files with 64 additions and 40 deletions

View File

@ -10,9 +10,12 @@
u8 *cached_arraybases[16]; u8 *cached_arraybases[16];
CPState g_main_cp_state; CPState g_main_cp_state;
CPState g_preprocess_cp_state;
void DoCPState(PointerWrap& p) void DoCPState(PointerWrap& p)
{ {
// We don't save g_preprocess_cp_state separately because the GPU should be
// synced around state save/load.
p.DoArray(g_main_cp_state.array_bases, 16); p.DoArray(g_main_cp_state.array_bases, 16);
p.DoArray(g_main_cp_state.array_strides, 16); p.DoArray(g_main_cp_state.array_strides, 16);
p.Do(g_main_cp_state.matrix_index_a); p.Do(g_main_cp_state.matrix_index_a);
@ -20,4 +23,11 @@ void DoCPState(PointerWrap& p)
p.Do(g_main_cp_state.vtx_desc.Hex); p.Do(g_main_cp_state.vtx_desc.Hex);
p.DoArray(g_main_cp_state.vtx_attr, 8); p.DoArray(g_main_cp_state.vtx_attr, 8);
p.DoMarker("CP Memory"); p.DoMarker("CP Memory");
if (p.mode == PointerWrap::MODE_READ)
CopyPreprocessCPStateFromMain();
}
void CopyPreprocessCPStateFromMain()
{
memcpy(&g_preprocess_cp_state, &g_main_cp_state, sizeof(CPState));
} }

View File

@ -238,6 +238,8 @@ struct VAT
UVAT_group2 g2; UVAT_group2 g2;
}; };
class VertexLoader;
// STATE_TO_SAVE // STATE_TO_SAVE
struct CPState final struct CPState final
{ {
@ -248,18 +250,25 @@ struct CPState final
TVtxDesc vtx_desc; TVtxDesc vtx_desc;
// Most games only use the first VtxAttr and simply reconfigure it all the time as needed. // Most games only use the first VtxAttr and simply reconfigure it all the time as needed.
VAT vtx_attr[8]; VAT vtx_attr[8];
// Attributes that actually belong to VertexLoaderManager:
int attr_dirty; // bitfield
VertexLoader* vertex_loaders[8];
}; };
class PointerWrap; class PointerWrap;
extern void DoCPState(PointerWrap& p); extern void DoCPState(PointerWrap& p);
extern void CopyPreprocessCPStateFromMain();
extern CPState g_main_cp_state; extern CPState g_main_cp_state;
extern CPState g_preprocess_cp_state;
extern u8 *cached_arraybases[16]; extern u8 *cached_arraybases[16];
// Might move this into its own file later. // Might move this into its own file later.
void LoadCPReg(u32 SubCmd, u32 Value); void LoadCPReg(u32 SubCmd, u32 Value, bool is_preprocess = false);
// Fills memory with data from CP regs // Fills memory with data from CP regs
void FillCPMemoryArray(u32 *memory); void FillCPMemoryArray(u32 *memory);

View File

@ -21,12 +21,8 @@
#include "VideoCommon/VertexShaderManager.h" #include "VideoCommon/VertexShaderManager.h"
#include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoCommon.h"
static int s_attr_dirty; // bitfield
static NativeVertexFormat* s_current_vtx_fmt; static NativeVertexFormat* s_current_vtx_fmt;
static VertexLoader* s_VertexLoaders[8];
namespace std namespace std
{ {
@ -53,10 +49,10 @@ static VertexLoaderMap s_vertex_loader_map;
void Init() void Init()
{ {
MarkAllDirty(); MarkAllDirty();
for (auto& map_entry : s_VertexLoaders) for (auto& map_entry : g_main_cp_state.vertex_loaders)
{ map_entry = nullptr;
for (auto& map_entry : g_preprocess_cp_state.vertex_loaders)
map_entry = nullptr; map_entry = nullptr;
}
RecomputeCachedArraybases(); RecomputeCachedArraybases();
} }
@ -104,15 +100,16 @@ void AppendListToString(std::string *dest)
void MarkAllDirty() void MarkAllDirty()
{ {
s_attr_dirty = 0xff; g_main_cp_state.attr_dirty = 0xff;
g_preprocess_cp_state.attr_dirty = 0xff;
} }
static VertexLoader* RefreshLoader(int vtx_attr_group) static VertexLoader* RefreshLoader(int vtx_attr_group, CPState* state)
{ {
VertexLoader* loader; VertexLoader* loader;
if ((s_attr_dirty >> vtx_attr_group) & 1) if ((state->attr_dirty >> vtx_attr_group) & 1)
{ {
VertexLoaderUID uid(g_main_cp_state.vtx_desc, g_main_cp_state.vtx_attr[vtx_attr_group]); VertexLoaderUID uid(state->vtx_desc, state->vtx_attr[vtx_attr_group]);
std::lock_guard<std::mutex> lk(s_vertex_loader_map_lock); std::lock_guard<std::mutex> lk(s_vertex_loader_map_lock);
VertexLoaderMap::iterator iter = s_vertex_loader_map.find(uid); VertexLoaderMap::iterator iter = s_vertex_loader_map.find(uid);
if (iter != s_vertex_loader_map.end()) if (iter != s_vertex_loader_map.end())
@ -121,14 +118,14 @@ static VertexLoader* RefreshLoader(int vtx_attr_group)
} }
else else
{ {
loader = new VertexLoader(g_main_cp_state.vtx_desc, g_main_cp_state.vtx_attr[vtx_attr_group]); loader = new VertexLoader(state->vtx_desc, state->vtx_attr[vtx_attr_group]);
s_vertex_loader_map[uid] = std::unique_ptr<VertexLoader>(loader); s_vertex_loader_map[uid] = std::unique_ptr<VertexLoader>(loader);
INCSTAT(stats.numVertexLoaders); INCSTAT(stats.numVertexLoaders);
} }
s_VertexLoaders[vtx_attr_group] = loader; state->vertex_loaders[vtx_attr_group] = loader;
s_attr_dirty &= ~(1 << vtx_attr_group); state->attr_dirty &= ~(1 << vtx_attr_group);
} else { } else {
loader = s_VertexLoaders[vtx_attr_group]; loader = state->vertex_loaders[vtx_attr_group];
} }
return loader; return loader;
} }
@ -137,7 +134,10 @@ bool RunVertices(int vtx_attr_group, int primitive, int count, size_t buf_size,
{ {
if (!count) if (!count)
return true; return true;
VertexLoader* loader = RefreshLoader(vtx_attr_group);
CPState* state = &g_main_cp_state;
VertexLoader* loader = RefreshLoader(vtx_attr_group, state);
size_t size = count * loader->GetVertexSize(); size_t size = count * loader->GetVertexSize();
if (buf_size < size) if (buf_size < size)
@ -152,7 +152,6 @@ bool RunVertices(int vtx_attr_group, int primitive, int count, size_t buf_size,
NativeVertexFormat* native = loader->GetNativeVertexFormat(); NativeVertexFormat* native = loader->GetNativeVertexFormat();
// If the native vertex format changed, force a flush. // If the native vertex format changed, force a flush.
if (native != s_current_vtx_fmt) if (native != s_current_vtx_fmt)
VertexManager::Flush(); VertexManager::Flush();
@ -161,7 +160,7 @@ bool RunVertices(int vtx_attr_group, int primitive, int count, size_t buf_size,
VertexManager::PrepareForAdditionalData(primitive, count, VertexManager::PrepareForAdditionalData(primitive, count,
loader->GetNativeVertexDeclaration().stride); loader->GetNativeVertexDeclaration().stride);
loader->RunVertices(g_main_cp_state.vtx_attr[vtx_attr_group], primitive, count); loader->RunVertices(state->vtx_attr[vtx_attr_group], primitive, count);
IndexGenerator::AddIndices(primitive, count); IndexGenerator::AddIndices(primitive, count);
@ -170,9 +169,9 @@ bool RunVertices(int vtx_attr_group, int primitive, int count, size_t buf_size,
return true; return true;
} }
int GetVertexSize(int vtx_attr_group) int GetVertexSize(int vtx_attr_group, bool preprocess)
{ {
return RefreshLoader(vtx_attr_group)->GetVertexSize(); return RefreshLoader(vtx_attr_group, preprocess ? &g_preprocess_cp_state : &g_main_cp_state)->GetVertexSize();
} }
NativeVertexFormat* GetCurrentVertexFormat() NativeVertexFormat* GetCurrentVertexFormat()
@ -182,56 +181,61 @@ NativeVertexFormat* GetCurrentVertexFormat()
} // namespace } // namespace
void LoadCPReg(u32 sub_cmd, u32 value) void LoadCPReg(u32 sub_cmd, u32 value, bool is_preprocess)
{ {
bool update_global_state = !is_preprocess;
CPState* state = is_preprocess ? &g_preprocess_cp_state : &g_main_cp_state;
switch (sub_cmd & 0xF0) switch (sub_cmd & 0xF0)
{ {
case 0x30: case 0x30:
VertexShaderManager::SetTexMatrixChangedA(value); if (update_global_state)
VertexShaderManager::SetTexMatrixChangedA(value);
break; break;
case 0x40: case 0x40:
VertexShaderManager::SetTexMatrixChangedB(value); if (update_global_state)
VertexShaderManager::SetTexMatrixChangedB(value);
break; break;
case 0x50: case 0x50:
g_main_cp_state.vtx_desc.Hex &= ~0x1FFFF; // keep the Upper bits state->vtx_desc.Hex &= ~0x1FFFF; // keep the Upper bits
g_main_cp_state.vtx_desc.Hex |= value; state->vtx_desc.Hex |= value;
s_attr_dirty = 0xFF; state->attr_dirty = 0xFF;
break; break;
case 0x60: case 0x60:
g_main_cp_state.vtx_desc.Hex &= 0x1FFFF; // keep the lower 17Bits state->vtx_desc.Hex &= 0x1FFFF; // keep the lower 17Bits
g_main_cp_state.vtx_desc.Hex |= (u64)value << 17; state->vtx_desc.Hex |= (u64)value << 17;
s_attr_dirty = 0xFF; state->attr_dirty = 0xFF;
break; break;
case 0x70: case 0x70:
_assert_((sub_cmd & 0x0F) < 8); _assert_((sub_cmd & 0x0F) < 8);
g_main_cp_state.vtx_attr[sub_cmd & 7].g0.Hex = value; state->vtx_attr[sub_cmd & 7].g0.Hex = value;
s_attr_dirty |= 1 << (sub_cmd & 7); state->attr_dirty |= 1 << (sub_cmd & 7);
break; break;
case 0x80: case 0x80:
_assert_((sub_cmd & 0x0F) < 8); _assert_((sub_cmd & 0x0F) < 8);
g_main_cp_state.vtx_attr[sub_cmd & 7].g1.Hex = value; state->vtx_attr[sub_cmd & 7].g1.Hex = value;
s_attr_dirty |= 1 << (sub_cmd & 7); state->attr_dirty |= 1 << (sub_cmd & 7);
break; break;
case 0x90: case 0x90:
_assert_((sub_cmd & 0x0F) < 8); _assert_((sub_cmd & 0x0F) < 8);
g_main_cp_state.vtx_attr[sub_cmd & 7].g2.Hex = value; state->vtx_attr[sub_cmd & 7].g2.Hex = value;
s_attr_dirty |= 1 << (sub_cmd & 7); state->attr_dirty |= 1 << (sub_cmd & 7);
break; break;
// Pointers to vertex arrays in GC RAM // Pointers to vertex arrays in GC RAM
case 0xA0: case 0xA0:
g_main_cp_state.array_bases[sub_cmd & 0xF] = value; state->array_bases[sub_cmd & 0xF] = value;
cached_arraybases[sub_cmd & 0xF] = Memory::GetPointer(value); if (update_global_state)
cached_arraybases[sub_cmd & 0xF] = Memory::GetPointer(value);
break; break;
case 0xB0: case 0xB0:
g_main_cp_state.array_strides[sub_cmd & 0xF] = value & 0xFF; state->array_strides[sub_cmd & 0xF] = value & 0xFF;
break; break;
} }
} }

View File

@ -16,7 +16,7 @@ namespace VertexLoaderManager
void MarkAllDirty(); void MarkAllDirty();
int GetVertexSize(int vtx_attr_group); int GetVertexSize(int vtx_attr_group, bool preprocess);
// Returns false if buf_size is insufficient. // Returns false if buf_size is insufficient.
bool RunVertices(int vtx_attr_group, int primitive, int count, size_t buf_size, bool skip_drawing = false); bool RunVertices(int vtx_attr_group, int primitive, int count, size_t buf_size, bool skip_drawing = false);

View File

@ -68,5 +68,6 @@ void VideoCommon_RunLoop(bool enable)
void VideoCommon_Init() void VideoCommon_Init()
{ {
memset(&g_main_cp_state, 0, sizeof(g_main_cp_state)); memset(&g_main_cp_state, 0, sizeof(g_main_cp_state));
memset(&g_preprocess_cp_state, 0, sizeof(g_preprocess_cp_state));
memset(texMem, 0, TMEM_SIZE); memset(texMem, 0, TMEM_SIZE);
} }