From 63c62b277d6850279bd2a982535d5abde824e6e2 Mon Sep 17 00:00:00 2001 From: comex Date: Sun, 24 Aug 2014 23:53:28 -0400 Subject: Some changes to VertexLoaderManager: - Lazily create the native vertex format (which involves GL calls) from RunVertices rather than RefreshLoader itself, freeing the latter to be run from the CPU thread (hopefully). - In order to avoid useless allocations while doing so, store the native format inside the VertexLoader rather than using a cache entry. - Wrap the s_vertex_loader_map in a lock, for similar reasons. --- Source/Core/VideoCommon/VertexLoaderManager.cpp | 88 ++++++++++--------------- 1 file changed, 36 insertions(+), 52 deletions(-) (limited to 'Source/Core/VideoCommon/VertexLoaderManager.cpp') diff --git a/Source/Core/VideoCommon/VertexLoaderManager.cpp b/Source/Core/VideoCommon/VertexLoaderManager.cpp index dbf22c9c3d..b3a1c97c3f 100644 --- a/Source/Core/VideoCommon/VertexLoaderManager.cpp +++ b/Source/Core/VideoCommon/VertexLoaderManager.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -24,8 +25,7 @@ static int s_attr_dirty; // bitfield static NativeVertexFormat* s_current_vtx_fmt; -typedef std::pair VertexLoaderCacheItem; -static VertexLoaderCacheItem s_VertexLoaders[8]; +static VertexLoader* s_VertexLoaders[8]; namespace std { @@ -41,14 +41,13 @@ struct hash } -typedef std::unordered_map VertexLoaderMap; -typedef std::map> NativeVertexLoaderMap; +typedef std::unordered_map> VertexLoaderMap; namespace VertexLoaderManager { -static VertexLoaderMap s_VertexLoaderMap; -static NativeVertexLoaderMap s_native_vertex_map; +static std::mutex s_vertex_loader_map_lock; +static VertexLoaderMap s_vertex_loader_map; // TODO - change into array of pointers. Keep a map of all seen so far. void Init() @@ -56,20 +55,16 @@ void Init() MarkAllDirty(); for (auto& map_entry : s_VertexLoaders) { - map_entry.first = nullptr; - map_entry.second = nullptr; + map_entry = nullptr; } RecomputeCachedArraybases(); } void Shutdown() { - for (auto& map_entry : s_VertexLoaderMap) - { - delete map_entry.second.first; - } - s_VertexLoaderMap.clear(); - s_native_vertex_map.clear(); + std::lock_guard lk(s_vertex_loader_map_lock); + s_vertex_loader_map.clear(); + VertexLoader::ClearNativeVertexFormatCache(); } namespace @@ -87,14 +82,15 @@ struct entry void AppendListToString(std::string *dest) { + std::lock_guard lk(s_vertex_loader_map_lock); std::vector entries; size_t total_size = 0; - for (const auto& map_entry : s_VertexLoaderMap) + for (const auto& map_entry : s_vertex_loader_map) { entry e; - map_entry.second.first->AppendToString(&e.text); - e.num_verts = map_entry.second.first->GetNumLoadedVerts(); + map_entry.second->AppendToString(&e.text); + e.num_verts = map_entry.second->GetNumLoadedVerts(); entries.push_back(e); total_size += e.text.size() + 1; } @@ -111,54 +107,39 @@ void MarkAllDirty() s_attr_dirty = 0xff; } -static NativeVertexFormat* GetNativeVertexFormat(const PortableVertexDeclaration& format, - u32 components) -{ - auto& native = s_native_vertex_map[format]; - if (!native) - { - auto raw_pointer = g_vertex_manager->CreateNativeVertexFormat(); - native = std::unique_ptr(raw_pointer); - native->Initialize(format); - native->m_components = components; - } - return native.get(); -} - -static VertexLoaderCacheItem RefreshLoader(int vtx_attr_group) +static VertexLoader* RefreshLoader(int vtx_attr_group) { + VertexLoader* loader; if ((s_attr_dirty >> vtx_attr_group) & 1) { VertexLoaderUID uid(g_VtxDesc, g_VtxAttr[vtx_attr_group]); - VertexLoaderMap::iterator iter = s_VertexLoaderMap.find(uid); - if (iter != s_VertexLoaderMap.end()) + std::lock_guard lk(s_vertex_loader_map_lock); + VertexLoaderMap::iterator iter = s_vertex_loader_map.find(uid); + if (iter != s_vertex_loader_map.end()) { - s_VertexLoaders[vtx_attr_group] = iter->second; + loader = iter->second.get(); } else { - VertexLoader* loader = new VertexLoader(g_VtxDesc, g_VtxAttr[vtx_attr_group]); - - NativeVertexFormat* vtx_fmt = GetNativeVertexFormat( - loader->GetNativeVertexDeclaration(), - loader->GetNativeComponents()); - - s_VertexLoaderMap[uid] = std::make_pair(loader, vtx_fmt); - s_VertexLoaders[vtx_attr_group] = std::make_pair(loader, vtx_fmt); + loader = new VertexLoader(g_VtxDesc, g_VtxAttr[vtx_attr_group]); + s_vertex_loader_map[uid] = std::unique_ptr(loader); INCSTAT(stats.numVertexLoaders); } + s_VertexLoaders[vtx_attr_group] = loader; + s_attr_dirty &= ~(1 << vtx_attr_group); + } else { + loader = s_VertexLoaders[vtx_attr_group]; } - s_attr_dirty &= ~(1 << vtx_attr_group); - return s_VertexLoaders[vtx_attr_group]; + return loader; } bool RunVertices(int vtx_attr_group, int primitive, int count, size_t buf_size, bool skip_drawing) { if (!count) return true; - auto loader = RefreshLoader(vtx_attr_group); + VertexLoader* loader = RefreshLoader(vtx_attr_group); - size_t size = count * loader.first->GetVertexSize(); + size_t size = count * loader->GetVertexSize(); if (buf_size < size) return false; @@ -169,15 +150,18 @@ bool RunVertices(int vtx_attr_group, int primitive, int count, size_t buf_size, return true; } + NativeVertexFormat* native = loader->GetNativeVertexFormat(); + + // If the native vertex format changed, force a flush. - if (loader.second != s_current_vtx_fmt) + if (native != s_current_vtx_fmt) VertexManager::Flush(); - s_current_vtx_fmt = loader.second; + s_current_vtx_fmt = native; VertexManager::PrepareForAdditionalData(primitive, count, - loader.first->GetNativeVertexDeclaration().stride); + loader->GetNativeVertexDeclaration().stride); - loader.first->RunVertices(g_VtxAttr[vtx_attr_group], primitive, count); + loader->RunVertices(g_VtxAttr[vtx_attr_group], primitive, count); IndexGenerator::AddIndices(primitive, count); @@ -188,7 +172,7 @@ bool RunVertices(int vtx_attr_group, int primitive, int count, size_t buf_size, int GetVertexSize(int vtx_attr_group) { - return RefreshLoader(vtx_attr_group).first->GetVertexSize(); + return RefreshLoader(vtx_attr_group)->GetVertexSize(); } NativeVertexFormat* GetCurrentVertexFormat() -- cgit v1.2.3 From f0131c2e09faba0d65fa5b7360898e514e3636f5 Mon Sep 17 00:00:00 2001 From: comex Date: Wed, 27 Aug 2014 13:26:06 -0400 Subject: Mechanical changes to move most CP state to a struct rather than separate globals. The next commit will add a separate copy of the struct and the ability for LoadCPReg to work on it. --- Source/Core/VideoCommon/VertexLoaderManager.cpp | 44 ++++++++++++------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'Source/Core/VideoCommon/VertexLoaderManager.cpp') diff --git a/Source/Core/VideoCommon/VertexLoaderManager.cpp b/Source/Core/VideoCommon/VertexLoaderManager.cpp index b3a1c97c3f..88c8b2d668 100644 --- a/Source/Core/VideoCommon/VertexLoaderManager.cpp +++ b/Source/Core/VideoCommon/VertexLoaderManager.cpp @@ -112,7 +112,7 @@ static VertexLoader* RefreshLoader(int vtx_attr_group) VertexLoader* loader; if ((s_attr_dirty >> vtx_attr_group) & 1) { - VertexLoaderUID uid(g_VtxDesc, g_VtxAttr[vtx_attr_group]); + VertexLoaderUID uid(g_main_cp_state.vtx_desc, g_main_cp_state.vtx_attr[vtx_attr_group]); std::lock_guard lk(s_vertex_loader_map_lock); VertexLoaderMap::iterator iter = s_vertex_loader_map.find(uid); if (iter != s_vertex_loader_map.end()) @@ -121,7 +121,7 @@ static VertexLoader* RefreshLoader(int vtx_attr_group) } else { - loader = new VertexLoader(g_VtxDesc, g_VtxAttr[vtx_attr_group]); + loader = new VertexLoader(g_main_cp_state.vtx_desc, g_main_cp_state.vtx_attr[vtx_attr_group]); s_vertex_loader_map[uid] = std::unique_ptr(loader); INCSTAT(stats.numVertexLoaders); } @@ -161,7 +161,7 @@ bool RunVertices(int vtx_attr_group, int primitive, int count, size_t buf_size, VertexManager::PrepareForAdditionalData(primitive, count, loader->GetNativeVertexDeclaration().stride); - loader->RunVertices(g_VtxAttr[vtx_attr_group], primitive, count); + loader->RunVertices(g_main_cp_state.vtx_attr[vtx_attr_group], primitive, count); IndexGenerator::AddIndices(primitive, count); @@ -195,65 +195,65 @@ void LoadCPReg(u32 sub_cmd, u32 value) break; case 0x50: - g_VtxDesc.Hex &= ~0x1FFFF; // keep the Upper bits - g_VtxDesc.Hex |= value; + g_main_cp_state.vtx_desc.Hex &= ~0x1FFFF; // keep the Upper bits + g_main_cp_state.vtx_desc.Hex |= value; s_attr_dirty = 0xFF; break; case 0x60: - g_VtxDesc.Hex &= 0x1FFFF; // keep the lower 17Bits - g_VtxDesc.Hex |= (u64)value << 17; + g_main_cp_state.vtx_desc.Hex &= 0x1FFFF; // keep the lower 17Bits + g_main_cp_state.vtx_desc.Hex |= (u64)value << 17; s_attr_dirty = 0xFF; break; case 0x70: _assert_((sub_cmd & 0x0F) < 8); - g_VtxAttr[sub_cmd & 7].g0.Hex = value; + g_main_cp_state.vtx_attr[sub_cmd & 7].g0.Hex = value; s_attr_dirty |= 1 << (sub_cmd & 7); break; case 0x80: _assert_((sub_cmd & 0x0F) < 8); - g_VtxAttr[sub_cmd & 7].g1.Hex = value; + g_main_cp_state.vtx_attr[sub_cmd & 7].g1.Hex = value; s_attr_dirty |= 1 << (sub_cmd & 7); break; case 0x90: _assert_((sub_cmd & 0x0F) < 8); - g_VtxAttr[sub_cmd & 7].g2.Hex = value; + g_main_cp_state.vtx_attr[sub_cmd & 7].g2.Hex = value; s_attr_dirty |= 1 << (sub_cmd & 7); break; // Pointers to vertex arrays in GC RAM case 0xA0: - arraybases[sub_cmd & 0xF] = value; + g_main_cp_state.array_bases[sub_cmd & 0xF] = value; cached_arraybases[sub_cmd & 0xF] = Memory::GetPointer(value); break; case 0xB0: - arraystrides[sub_cmd & 0xF] = value & 0xFF; + g_main_cp_state.array_strides[sub_cmd & 0xF] = value & 0xFF; break; } } void FillCPMemoryArray(u32 *memory) { - memory[0x30] = MatrixIndexA.Hex; - memory[0x40] = MatrixIndexB.Hex; - memory[0x50] = (u32)g_VtxDesc.Hex; - memory[0x60] = (u32)(g_VtxDesc.Hex >> 17); + memory[0x30] = g_main_cp_state.matrix_index_a.Hex; + memory[0x40] = g_main_cp_state.matrix_index_b.Hex; + memory[0x50] = (u32)g_main_cp_state.vtx_desc.Hex; + memory[0x60] = (u32)(g_main_cp_state.vtx_desc.Hex >> 17); for (int i = 0; i < 8; ++i) { - memory[0x70 + i] = g_VtxAttr[i].g0.Hex; - memory[0x80 + i] = g_VtxAttr[i].g1.Hex; - memory[0x90 + i] = g_VtxAttr[i].g2.Hex; + memory[0x70 + i] = g_main_cp_state.vtx_attr[i].g0.Hex; + memory[0x80 + i] = g_main_cp_state.vtx_attr[i].g1.Hex; + memory[0x90 + i] = g_main_cp_state.vtx_attr[i].g2.Hex; } for (int i = 0; i < 16; ++i) { - memory[0xA0 + i] = arraybases[i]; - memory[0xB0 + i] = arraystrides[i]; + memory[0xA0 + i] = g_main_cp_state.array_bases[i]; + memory[0xB0 + i] = g_main_cp_state.array_strides[i]; } } @@ -261,6 +261,6 @@ void RecomputeCachedArraybases() { for (int i = 0; i < 16; i++) { - cached_arraybases[i] = Memory::GetPointer(arraybases[i]); + cached_arraybases[i] = Memory::GetPointer(g_main_cp_state.array_bases[i]); } } -- cgit v1.2.3 From e86ddacb18affaef2d773b0c86fdf57f93d594c4 Mon Sep 17 00:00:00 2001 From: comex Date: Wed, 27 Aug 2014 13:38:00 -0400 Subject: 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. --- Source/Core/VideoCommon/VertexLoaderManager.cpp | 80 +++++++++++++------------ 1 file changed, 42 insertions(+), 38 deletions(-) (limited to 'Source/Core/VideoCommon/VertexLoaderManager.cpp') diff --git a/Source/Core/VideoCommon/VertexLoaderManager.cpp b/Source/Core/VideoCommon/VertexLoaderManager.cpp index 88c8b2d668..ca925d0302 100644 --- a/Source/Core/VideoCommon/VertexLoaderManager.cpp +++ b/Source/Core/VideoCommon/VertexLoaderManager.cpp @@ -21,12 +21,8 @@ #include "VideoCommon/VertexShaderManager.h" #include "VideoCommon/VideoCommon.h" -static int s_attr_dirty; // bitfield - static NativeVertexFormat* s_current_vtx_fmt; -static VertexLoader* s_VertexLoaders[8]; - namespace std { @@ -53,10 +49,10 @@ static VertexLoaderMap s_vertex_loader_map; void Init() { 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; - } RecomputeCachedArraybases(); } @@ -104,15 +100,16 @@ void AppendListToString(std::string *dest) 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; - 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 lk(s_vertex_loader_map_lock); VertexLoaderMap::iterator iter = s_vertex_loader_map.find(uid); if (iter != s_vertex_loader_map.end()) @@ -121,14 +118,14 @@ static VertexLoader* RefreshLoader(int vtx_attr_group) } 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(loader); INCSTAT(stats.numVertexLoaders); } - s_VertexLoaders[vtx_attr_group] = loader; - s_attr_dirty &= ~(1 << vtx_attr_group); + state->vertex_loaders[vtx_attr_group] = loader; + state->attr_dirty &= ~(1 << vtx_attr_group); } else { - loader = s_VertexLoaders[vtx_attr_group]; + loader = state->vertex_loaders[vtx_attr_group]; } return loader; } @@ -137,7 +134,10 @@ bool RunVertices(int vtx_attr_group, int primitive, int count, size_t buf_size, { if (!count) 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(); 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(); - // If the native vertex format changed, force a flush. if (native != s_current_vtx_fmt) VertexManager::Flush(); @@ -161,7 +160,7 @@ bool RunVertices(int vtx_attr_group, int primitive, int count, size_t buf_size, VertexManager::PrepareForAdditionalData(primitive, count, 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); @@ -170,9 +169,9 @@ bool RunVertices(int vtx_attr_group, int primitive, int count, size_t buf_size, 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() @@ -182,56 +181,61 @@ NativeVertexFormat* GetCurrentVertexFormat() } // 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) { case 0x30: - VertexShaderManager::SetTexMatrixChangedA(value); + if (update_global_state) + VertexShaderManager::SetTexMatrixChangedA(value); break; case 0x40: - VertexShaderManager::SetTexMatrixChangedB(value); + if (update_global_state) + VertexShaderManager::SetTexMatrixChangedB(value); break; case 0x50: - g_main_cp_state.vtx_desc.Hex &= ~0x1FFFF; // keep the Upper bits - g_main_cp_state.vtx_desc.Hex |= value; - s_attr_dirty = 0xFF; + state->vtx_desc.Hex &= ~0x1FFFF; // keep the Upper bits + state->vtx_desc.Hex |= value; + state->attr_dirty = 0xFF; 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; - s_attr_dirty = 0xFF; + state->vtx_desc.Hex &= 0x1FFFF; // keep the lower 17Bits + state->vtx_desc.Hex |= (u64)value << 17; + state->attr_dirty = 0xFF; break; case 0x70: _assert_((sub_cmd & 0x0F) < 8); - g_main_cp_state.vtx_attr[sub_cmd & 7].g0.Hex = value; - s_attr_dirty |= 1 << (sub_cmd & 7); + state->vtx_attr[sub_cmd & 7].g0.Hex = value; + state->attr_dirty |= 1 << (sub_cmd & 7); break; case 0x80: _assert_((sub_cmd & 0x0F) < 8); - g_main_cp_state.vtx_attr[sub_cmd & 7].g1.Hex = value; - s_attr_dirty |= 1 << (sub_cmd & 7); + state->vtx_attr[sub_cmd & 7].g1.Hex = value; + state->attr_dirty |= 1 << (sub_cmd & 7); break; case 0x90: _assert_((sub_cmd & 0x0F) < 8); - g_main_cp_state.vtx_attr[sub_cmd & 7].g2.Hex = value; - s_attr_dirty |= 1 << (sub_cmd & 7); + state->vtx_attr[sub_cmd & 7].g2.Hex = value; + state->attr_dirty |= 1 << (sub_cmd & 7); break; // Pointers to vertex arrays in GC RAM case 0xA0: - g_main_cp_state.array_bases[sub_cmd & 0xF] = value; - cached_arraybases[sub_cmd & 0xF] = Memory::GetPointer(value); + state->array_bases[sub_cmd & 0xF] = value; + if (update_global_state) + cached_arraybases[sub_cmd & 0xF] = Memory::GetPointer(value); break; case 0xB0: - g_main_cp_state.array_strides[sub_cmd & 0xF] = value & 0xFF; + state->array_strides[sub_cmd & 0xF] = value & 0xFF; break; } } -- cgit v1.2.3