diff --git a/rpcs3/Emu/RSX/Common/ProgramStateCache.cpp b/rpcs3/Emu/RSX/Common/ProgramStateCache.cpp index 32b2ebb2d808..d98ef92d2bae 100644 --- a/rpcs3/Emu/RSX/Common/ProgramStateCache.cpp +++ b/rpcs3/Emu/RSX/Common/ProgramStateCache.cpp @@ -3,14 +3,14 @@ using namespace program_hash_util; -size_t vertex_program_hash::operator()(const std::vector &program) const +size_t vertex_program_hash::operator()(const RSXVertexProgram &program) const { // 64-bit Fowler/Noll/Vo FNV-1a hash code size_t hash = 0xCBF29CE484222325ULL; - const qword *instbuffer = (const qword*)program.data(); + const qword *instbuffer = (const qword*)program.data.data(); size_t instIndex = 0; bool end = false; - for (unsigned i = 0; i < program.size() / 4; i++) + for (unsigned i = 0; i < program.data.size() / 4; i++) { const qword inst = instbuffer[instIndex]; hash ^= inst.dword[0]; @@ -22,13 +22,17 @@ size_t vertex_program_hash::operator()(const std::vector &program) const return hash; } -bool vertex_program_compare::operator()(const std::vector &binary1, const std::vector &binary2) const +bool vertex_program_compare::operator()(const RSXVertexProgram &binary1, const RSXVertexProgram &binary2) const { - if (binary1.size() != binary2.size()) return false; - const qword *instBuffer1 = (const qword*)binary1.data(); - const qword *instBuffer2 = (const qword*)binary2.data(); + if (binary1.output_mask != binary2.output_mask) + return false; + if (binary1.rsx_vertex_inputs != binary2.rsx_vertex_inputs) + return false; + if (binary1.data.size() != binary2.data.size()) return false; + const qword *instBuffer1 = (const qword*)binary1.data.data(); + const qword *instBuffer2 = (const qword*)binary2.data.data(); size_t instIndex = 0; - for (unsigned i = 0; i < binary1.size() / 4; i++) + for (unsigned i = 0; i < binary1.data.size() / 4; i++) { const qword& inst1 = instBuffer1[instIndex]; const qword& inst2 = instBuffer2[instIndex]; diff --git a/rpcs3/Emu/RSX/Common/ProgramStateCache.h b/rpcs3/Emu/RSX/Common/ProgramStateCache.h index a2cddff089f1..eef6eecb3df4 100644 --- a/rpcs3/Emu/RSX/Common/ProgramStateCache.h +++ b/rpcs3/Emu/RSX/Common/ProgramStateCache.h @@ -23,12 +23,12 @@ namespace program_hash_util struct vertex_program_hash { - size_t operator()(const std::vector &program) const; + size_t operator()(const RSXVertexProgram &program) const; }; struct vertex_program_compare { - bool operator()(const std::vector &binary1, const std::vector &binary2) const; + bool operator()(const RSXVertexProgram &binary1, const RSXVertexProgram &binary2) const; }; struct fragment_program_utils @@ -75,7 +75,7 @@ class program_state_cache using vertex_program_type = typename backend_traits::vertex_program_type; using fragment_program_type = typename backend_traits::fragment_program_type; - using binary_to_vertex_program = std::unordered_map, vertex_program_type, program_hash_util::vertex_program_hash, program_hash_util::vertex_program_compare> ; + using binary_to_vertex_program = std::unordered_map ; using binary_to_fragment_program = std::unordered_map; @@ -115,13 +115,13 @@ class program_state_cache /// bool here to inform that the program was preexisting. std::tuple search_vertex_program(const RSXVertexProgram& rsx_vp) { - const auto& I = m_vertex_shader_cache.find(rsx_vp.data); + const auto& I = m_vertex_shader_cache.find(rsx_vp); if (I != m_vertex_shader_cache.end()) { return std::forward_as_tuple(I->second, true); } LOG_NOTICE(RSX, "VP not found in buffer!"); - vertex_program_type& new_shader = m_vertex_shader_cache[rsx_vp.data]; + vertex_program_type& new_shader = m_vertex_shader_cache[rsx_vp]; backend_traits::recompile_vertex_program(rsx_vp, new_shader, m_next_id++); return std::forward_as_tuple(new_shader, false); @@ -151,7 +151,7 @@ class program_state_cache const vertex_program_type& get_transform_program(const RSXVertexProgram& rsx_vp) const { - auto I = m_vertex_shader_cache.find(rsx_vp.data); + auto I = m_vertex_shader_cache.find(rsx_vp); if (I != m_vertex_shader_cache.end()) return I->second; throw new EXCEPTION("Trying to get unknow transform program"); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp index ba79339463e3..dab3df407da1 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp @@ -38,20 +38,7 @@ void Shader::Compile(const std::string &code, SHADER_TYPE st) void D3D12GSRender::load_program() { - u32 transform_program_start = rsx::method_registers[NV4097_SET_TRANSFORM_PROGRAM_START]; - m_vertex_program.data.reserve((512 - transform_program_start) * 4); - - for (int i = transform_program_start; i < 512; ++i) - { - m_vertex_program.data.resize((i - transform_program_start) * 4 + 4); - memcpy(m_vertex_program.data.data() + (i - transform_program_start) * 4, transform_program + i * 4, 4 * sizeof(u32)); - - D3 d3; - d3.HEX = transform_program[i * 4 + 3]; - - if (d3.end) - break; - } + m_vertex_program = get_current_vertex_program(); u32 shader_program = rsx::method_registers[NV4097_SET_SHADER_PROGRAM]; m_fragment_program.offset = shader_program & ~0x3; diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 68ff2cee109b..81e6d4397871 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -738,22 +738,7 @@ bool GLGSRender::do_method(u32 cmd, u32 arg) bool GLGSRender::load_program() { #if 1 - RSXVertexProgram vertex_program; - u32 transform_program_start = rsx::method_registers[NV4097_SET_TRANSFORM_PROGRAM_START]; - vertex_program.data.reserve((512 - transform_program_start) * 4); - - for (int i = transform_program_start; i < 512; ++i) - { - vertex_program.data.resize((i - transform_program_start) * 4 + 4); - memcpy(vertex_program.data.data() + (i - transform_program_start) * 4, transform_program + i * 4, 4 * sizeof(u32)); - - D3 d3; - d3.HEX = transform_program[i * 4 + 3]; - - if (d3.end) - break; - } - + RSXVertexProgram vertex_program = get_current_vertex_program(); RSXFragmentProgram fragment_program; u32 shader_program = rsx::method_registers[NV4097_SET_SHADER_PROGRAM]; fragment_program.offset = shader_program & ~0x3; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index bdcd893639af..ea77a3e5c933 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -597,6 +597,62 @@ namespace rsx return rsx::get_address(offset_zeta, m_context_dma_z); } + RSXVertexProgram thread::get_current_vertex_program() const + { + RSXVertexProgram result = {}; + u32 transform_program_start = rsx::method_registers[NV4097_SET_TRANSFORM_PROGRAM_START]; + result.data.reserve((512 - transform_program_start) * 4); + + for (int i = transform_program_start; i < 512; ++i) + { + result.data.resize((i - transform_program_start) * 4 + 4); + memcpy(result.data.data() + (i - transform_program_start) * 4, transform_program + i * 4, 4 * sizeof(u32)); + + D3 d3; + d3.HEX = transform_program[i * 4 + 3]; + + if (d3.end) + break; + } + result.output_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_OUTPUT_MASK]; + + u32 input_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_INPUT_MASK]; + u32 modulo_mask = rsx::method_registers[NV4097_SET_FREQUENCY_DIVIDER_OPERATION]; + result.rsx_vertex_inputs.clear(); + for (u8 index = 0; index < rsx::limits::vertex_count; ++index) + { + bool enabled = !!(input_mask & (1 << index)); + if (!enabled) + continue; + + if (vertex_arrays_info[index].size > 0) + { + result.rsx_vertex_inputs.push_back( + { + index, + vertex_arrays_info[index].size, + vertex_arrays_info[index].frequency, + !!((modulo_mask >> index) & 0x1), + true + } + ); + } + else if (register_vertex_info[index].size > 0) + { + result.rsx_vertex_inputs.push_back( + { + index, + register_vertex_info[index].size, + register_vertex_info[index].frequency, + !!((modulo_mask >> index) & 0x1), + false + } + ); + } + } + return result; + } + void thread::reset() { //setup method registers diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 7537ba32b343..7fec2719721d 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -292,6 +292,7 @@ namespace rsx protected: std::array get_color_surface_addresses() const; u32 get_zeta_surface_address() const; + RSXVertexProgram get_current_vertex_program() const; public: u32 draw_array_count; diff --git a/rpcs3/Emu/RSX/RSXVertexProgram.h b/rpcs3/Emu/RSX/RSXVertexProgram.h index f16d811011bf..94f8198d8d12 100644 --- a/rpcs3/Emu/RSX/RSXVertexProgram.h +++ b/rpcs3/Emu/RSX/RSXVertexProgram.h @@ -190,7 +190,23 @@ static const std::string rsx_vp_vec_op_names[] = "SEQ", "SFL", "SGT", "SLE", "SNE", "STR", "SSG", "NULL", "NULL", "TXL" }; +struct rsx_vertex_input +{ + u8 location; // between 0 and 15 + u8 size; // between 1 and 4 + u16 frequency; + bool is_modulo; // either modulo frequency or divide frequency + bool is_array; // false if "reg value" + + bool operator==(const rsx_vertex_input other) const + { + return location == other.location && size == other.size && frequency == other.frequency && is_modulo == other.is_modulo && is_array == other.is_array; + } +}; + struct RSXVertexProgram { std::vector data; + std::vector rsx_vertex_inputs; + u32 output_mask; };