diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 0961a3251..bd35f4540 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -63,6 +63,7 @@ set(HEADERS texture/texture_decode.h utils.h vertex_loader.h + vertex_loader_base.h video_core.h ) diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 4633a1df1..59bbb6648 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -308,14 +308,23 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { // Processes information about internal vertex attributes to figure out how a vertex is // loaded. - // Later, these can be compiled and cached. - const u32 base_address = regs.pipeline.vertex_attributes.GetPhysicalBaseAddress(); - VertexLoader loader(regs.pipeline); + VertexLoaderBase* loader; + const auto& vertex_attributes = regs.pipeline.vertex_attributes; + const u64 cache_key = Common::ComputeHash64(&vertex_attributes, sizeof(vertex_attributes)); + auto iter = vertex_loader_cache.find(cache_key); + if (iter != vertex_loader_cache.end()) { + loader = iter->second.get(); + } else { + auto new_loader = std::make_unique(vertex_attributes); + loader = new_loader.get(); + vertex_loader_cache.emplace_hint(iter, cache_key, std::move(new_loader)); + } // Load vertices bool is_indexed = (id == PICA_REG_INDEX(pipeline.trigger_draw_indexed)); const auto& index_info = regs.pipeline.index_array; + const u32 base_address = vertex_attributes.GetPhysicalBaseAddress(); const u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset); const u16* index_address_16 = reinterpret_cast(index_address_8); bool index_u16 = index_info.format != 0; @@ -384,7 +393,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { if (!vertex_cache_hit) { // Initialize data for the current vertex Shader::AttributeBuffer input, output{}; - loader.LoadVertex(base_address, index, vertex, input, memory_accesses); + loader->LoadVertex(base_address, index, vertex, input, memory_accesses); // Send to vertex shader if (g_debug_context) @@ -620,6 +629,6 @@ void ProcessCommandList(const u32* list, u32 size) { } } -} // namespace +} // namespace CommandProcessor -} // namespace +} // namespace Pica diff --git a/src/video_core/regs_pipeline.h b/src/video_core/regs_pipeline.h index 31c747d77..eb5ee1e4b 100644 --- a/src/video_core/regs_pipeline.h +++ b/src/video_core/regs_pipeline.h @@ -21,7 +21,7 @@ struct PipelineRegs { FLOAT = 3, }; - struct { + struct VertexAttributes { BitField<1, 28, u32> base_address; PAddr GetPhysicalBaseAddress() const { diff --git a/src/video_core/vertex_loader.cpp b/src/video_core/vertex_loader.cpp index 37c5224a9..aacf29d5c 100644 --- a/src/video_core/vertex_loader.cpp +++ b/src/video_core/vertex_loader.cpp @@ -16,10 +16,7 @@ namespace Pica { -void VertexLoader::Setup(const PipelineRegs& regs) { - ASSERT_MSG(!is_setup, "VertexLoader is not intended to be setup more than once."); - - const auto& attribute_config = regs.vertex_attributes; +VertexLoader::VertexLoader(const PipelineRegs::VertexAttributes& attribute_config) { num_total_attributes = attribute_config.GetNumTotalAttributes(); boost::fill(vertex_attribute_sources, 0xdeadbeef); @@ -66,15 +63,11 @@ void VertexLoader::Setup(const PipelineRegs& regs) { } } } - - is_setup = true; } void VertexLoader::LoadVertex(u32 base_address, int index, int vertex, Shader::AttributeBuffer& input, DebugUtils::MemoryAccessTracker& memory_accesses) { - ASSERT_MSG(is_setup, "A VertexLoader needs to be setup before loading vertices."); - for (int i = 0; i < num_total_attributes; ++i) { if (vertex_attribute_elements[i] != 0) { // Load per-vertex data from the loader arrays diff --git a/src/video_core/vertex_loader.h b/src/video_core/vertex_loader.h index 02db10aee..fe9157f98 100644 --- a/src/video_core/vertex_loader.h +++ b/src/video_core/vertex_loader.h @@ -3,6 +3,7 @@ #include #include "common/common_types.h" #include "video_core/regs_pipeline.h" +#include "video_core/vertex_loader_base.h" namespace Pica { @@ -14,16 +15,11 @@ namespace Shader { struct AttributeBuffer; } -class VertexLoader { +class VertexLoader : public VertexLoaderBase { public: - VertexLoader() = default; - explicit VertexLoader(const PipelineRegs& regs) { - Setup(regs); - } - - void Setup(const PipelineRegs& regs); + explicit VertexLoader(const PipelineRegs::VertexAttributes& vertex_attributes); void LoadVertex(u32 base_address, int index, int vertex, Shader::AttributeBuffer& input, - DebugUtils::MemoryAccessTracker& memory_accesses); + DebugUtils::MemoryAccessTracker& memory_accesses) override; int GetNumTotalAttributes() const { return num_total_attributes; @@ -36,7 +32,6 @@ private: std::array vertex_attribute_elements{}; std::array vertex_attribute_is_default; int num_total_attributes = 0; - bool is_setup = false; }; } // namespace Pica diff --git a/src/video_core/vertex_loader_base.h b/src/video_core/vertex_loader_base.h new file mode 100644 index 000000000..24fca6cc5 --- /dev/null +++ b/src/video_core/vertex_loader_base.h @@ -0,0 +1,32 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "common/common_types.h" +#include "common/hash.h" + +namespace Pica { +namespace DebugUtils { +class MemoryAccessTracker; +} + +namespace Shader { +struct AttributeBuffer; +} + +class VertexLoaderBase { +public: + virtual void LoadVertex(u32 base_address, int index, int vertex, Shader::AttributeBuffer& input, + DebugUtils::MemoryAccessTracker& memory_accesses) = 0; +}; + +using VertexLoaderCache = std::unordered_map>; + +static VertexLoaderCache vertex_loader_cache; + +} // namespace Pica