diff --git a/Source/Core/VideoCommon/CPMemory.h b/Source/Core/VideoCommon/CPMemory.h index 4626f35f33..89f790b9a1 100644 --- a/Source/Core/VideoCommon/CPMemory.h +++ b/Source/Core/VideoCommon/CPMemory.h @@ -88,6 +88,12 @@ union TVtxDesc { u32 Hex0, Hex1; }; + + // Easily index into the Position..Tex7Coord fields. + u32 GetVertexArrayStatus(int idx) + { + return (Hex >> (9 + idx * 2)) & 0x3; + } }; union UVAT_group0 @@ -239,6 +245,7 @@ class VertexLoaderBase; // STATE_TO_SAVE struct CPState final { + // Only 12 of these arrays are used. u32 array_bases[16]; u32 array_strides[16]; TMatrixIndexA matrix_index_a; diff --git a/Source/Core/VideoCommon/MainBase.cpp b/Source/Core/VideoCommon/MainBase.cpp index 0b9dd58f27..96aa34de90 100644 --- a/Source/Core/VideoCommon/MainBase.cpp +++ b/Source/Core/VideoCommon/MainBase.cpp @@ -212,7 +212,6 @@ void VideoBackendHardware::DoState(PointerWrap& p) if (p.GetMode() == PointerWrap::MODE_READ) { m_invalid = true; - RecomputeCachedArraybases(); // Clear all caches that touch RAM // (? these don't appear to touch any emulation state that gets saved. moved to on load only.) diff --git a/Source/Core/VideoCommon/VertexLoaderManager.cpp b/Source/Core/VideoCommon/VertexLoaderManager.cpp index 4168f7c777..8d2acecc66 100644 --- a/Source/Core/VideoCommon/VertexLoaderManager.cpp +++ b/Source/Core/VideoCommon/VertexLoaderManager.cpp @@ -42,7 +42,6 @@ void Init() map_entry = nullptr; for (auto& map_entry : g_preprocess_cp_state.vertex_loaders) map_entry = nullptr; - RecomputeCachedArraybases(); SETSTAT(stats.numVertexLoaders, 0); } @@ -136,6 +135,11 @@ static VertexLoaderBase* RefreshLoader(int vtx_attr_group, bool preprocess = fal } else { loader = state->vertex_loaders[vtx_attr_group]; } + + // Lookup pointers for any vertex arrays. + if (!preprocess) + ComputeCachedArrayBases(); + return loader; } @@ -232,8 +236,6 @@ void LoadCPReg(u32 sub_cmd, u32 value, bool is_preprocess) // Pointers to vertex arrays in GC RAM case 0xA0: state->array_bases[sub_cmd & 0xF] = value; - if (update_global_state) - cached_arraybases[sub_cmd & 0xF] = Memory::GetPointer(value); break; case 0xB0: @@ -263,10 +265,15 @@ void FillCPMemoryArray(u32 *memory) } } -void RecomputeCachedArraybases() +void ComputeCachedArrayBases() { - for (int i = 0; i < 16; i++) + // Some games such as Burnout 2 can put invalid addresses into + // the array base registers. (see issue 8591) + // But the vertex arrays with invalid addresses aren't actually enabled. + for (int i = 0; i < 12; i++) { - cached_arraybases[i] = Memory::GetPointer(g_main_cp_state.array_bases[i]); + // Only update the array base if the vertex description states we are going to use it. + if (g_main_cp_state.vtx_desc.GetVertexArrayStatus(i) >= 0x2) + cached_arraybases[i] = Memory::GetPointer(g_main_cp_state.array_bases[i]); } } diff --git a/Source/Core/VideoCommon/VertexLoaderManager.h b/Source/Core/VideoCommon/VertexLoaderManager.h index 25c40cb440..f745ec26a7 100644 --- a/Source/Core/VideoCommon/VertexLoaderManager.h +++ b/Source/Core/VideoCommon/VertexLoaderManager.h @@ -26,4 +26,4 @@ namespace VertexLoaderManager NativeVertexFormat* GetCurrentVertexFormat(); } -void RecomputeCachedArraybases(); +void ComputeCachedArrayBases();