diff --git a/rpcs3/Emu/RSX/Common/BufferUtils.cpp b/rpcs3/Emu/RSX/Common/BufferUtils.cpp index eb6264e122..2ab5677c8d 100644 --- a/rpcs3/Emu/RSX/Common/BufferUtils.cpp +++ b/rpcs3/Emu/RSX/Common/BufferUtils.cpp @@ -5,6 +5,16 @@ #define MIN2(x, y) ((x) < (y)) ? (x) : (y) #define MAX2(x, y) ((x) > (y)) ? (x) : (y) +namespace +{ + // FIXME: GSL as_span break build if template parameter is non const with current revision. + // Replace with true as_span when fixed. + template + gsl::span as_span_workaround(gsl::span unformated_span) + { + return{ (T*)unformated_span.data(), gsl::narrow(unformated_span.size_bytes() / sizeof(T)) }; + } +} namespace { @@ -24,73 +34,64 @@ namespace X = X << 5; return{ X, Y, Z, 1 }; } + + template + void copy_whole_attribute_array(gsl::span dst, const gsl::byte* src_ptr, u8 attribute_size, u8 dst_stride, u32 src_stride, u32 first, u32 vertex_count) + { + for (u32 vertex = 0; vertex < vertex_count; ++vertex) + { + const U* src = reinterpret_cast(src_ptr + src_stride * (first + vertex)); + for (u32 i = 0; i < attribute_size; ++i) + { + dst[vertex * dst_stride / sizeof(T) + i] = src[i]; + } + } + } } -// FIXME: these functions shouldn't access rsx::method_registers (global) - -void write_vertex_array_data_to_buffer(void *buffer, u32 first, u32 count, size_t index, const rsx::data_array_format_info &vertex_array_desc) +void write_vertex_array_data_to_buffer(gsl::span raw_dst_span, const gsl::byte *src_ptr, u32 first, u32 count, rsx::vertex_base_type type, u32 vector_element_count, u32 attribute_src_stride) { - Expects(vertex_array_desc.size > 0); + Expects(vector_element_count > 0); - u32 base_offset = rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_OFFSET]; - u32 offset = rsx::method_registers[NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + index]; - u32 address = base_offset + rsx::get_address(offset & 0x7fffffff, offset >> 31); + u32 element_size = rsx::get_vertex_type_size_on_host(type, vector_element_count); - u32 element_size = rsx::get_vertex_type_size_on_host(vertex_array_desc.type, vertex_array_desc.size); - - u32 base_index = rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_INDEX]; - - for (u32 i = 0; i < count; ++i) + switch (type) { - auto src = vm::ps3::_ptr(address + vertex_array_desc.stride * (first + i + base_index)); - u8* dst = (u8*)buffer + i * element_size; - - switch (vertex_array_desc.type) + case rsx::vertex_base_type::ub: + { + gsl::span dst_span = as_span_workaround(raw_dst_span); + copy_whole_attribute_array(dst_span, src_ptr, vector_element_count, element_size, attribute_src_stride, first, count); + return; + } + case rsx::vertex_base_type::s1: + case rsx::vertex_base_type::sf: + { + gsl::span dst_span = as_span_workaround(raw_dst_span); + copy_whole_attribute_array>(dst_span, src_ptr, vector_element_count, element_size, attribute_src_stride, first, count); + return; + } + case rsx::vertex_base_type::f: + case rsx::vertex_base_type::s32k: + case rsx::vertex_base_type::ub256: + { + gsl::span dst_span = as_span_workaround(raw_dst_span); + copy_whole_attribute_array>(dst_span, src_ptr, vector_element_count, element_size, attribute_src_stride, first, count); + return; + } + case rsx::vertex_base_type::cmp: + { + gsl::span dst_span = as_span_workaround(raw_dst_span); + for (u32 i = 0; i < count; ++i) { - case rsx::vertex_base_type::ub: - memcpy(dst, src, vertex_array_desc.size); - break; - - case rsx::vertex_base_type::s1: - case rsx::vertex_base_type::sf: - { - auto* c_src = (const be_t*)src; - u16* c_dst = (u16*)dst; - - for (u32 j = 0; j < vertex_array_desc.size; ++j) - { - *c_dst++ = *c_src++; - } - if (vertex_array_desc.size * sizeof(u16) < element_size) - *c_dst++ = 0x3c00; - break; - } - - case rsx::vertex_base_type::f: - case rsx::vertex_base_type::s32k: - case rsx::vertex_base_type::ub256: - { - auto* c_src = (const be_t*)src; - u32* c_dst = (u32*)dst; - - for (u32 j = 0; j < vertex_array_desc.size; ++j) - { - *c_dst++ = *c_src++; - } - break; - } - case rsx::vertex_base_type::cmp: - { - auto* c_src = (const be_t*)src; + auto* c_src = (const be_t*)(src_ptr + attribute_src_stride * (first + i)); const auto& decoded_vector = decode_cmp_vector(*c_src); - u16* c_dst = (u16*)dst; - c_dst[0] = decoded_vector[0]; - c_dst[1] = decoded_vector[1]; - c_dst[2] = decoded_vector[2]; - c_dst[3] = decoded_vector[3]; - break; - } + dst_span[i * element_size / sizeof(u16)] = decoded_vector[0]; + dst_span[i * element_size / sizeof(u16) + 1] = decoded_vector[1]; + dst_span[i * element_size / sizeof(u16) + 2] = decoded_vector[2]; + dst_span[i * element_size / sizeof(u16) + 3] = decoded_vector[3]; } + return; + } } } @@ -333,7 +334,7 @@ void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, } // TODO: Unify indexed and non indexed primitive expansion ? - +// FIXME: these functions shouldn't access rsx::method_registers (global) template std::tuple write_index_array_data_to_buffer_impl(gsl::span dst, rsx::primitive_type draw_mode, const std::vector > &first_count_arguments) { diff --git a/rpcs3/Emu/RSX/Common/BufferUtils.h b/rpcs3/Emu/RSX/Common/BufferUtils.h index bfe1be21b7..df0d0d18c2 100644 --- a/rpcs3/Emu/RSX/Common/BufferUtils.h +++ b/rpcs3/Emu/RSX/Common/BufferUtils.h @@ -4,9 +4,10 @@ #include "../RSXThread.h" /** - * Write count vertex attributes from index array buffer starting at first, using vertex_array_desc + * Write count vertex attributes from src_ptr starting at first. + * src_ptr array layout is deduced from the type, vector element count and src_stride arguments. */ -void write_vertex_array_data_to_buffer(void *buffer, u32 first, u32 count, size_t index, const rsx::data_array_format_info &vertex_array_desc); +void write_vertex_array_data_to_buffer(gsl::span raw_dst_span, const gsl::byte *src_ptr, u32 first, u32 count, rsx::vertex_base_type type, u32 vector_element_count, u32 attribute_src_stride); /* * If primitive mode is not supported and need to be emulated (using an index buffer) returns false. diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp index 246140bc1a..6f60855f9f 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp @@ -78,6 +78,7 @@ std::vector D3D12GSRender::upload_vertex_attrib u32 vertex_count = get_vertex_count(vertex_ranges); size_t offset_in_vertex_buffers_buffer = 0; u32 input_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_INPUT_MASK]; + Expects(rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_INDEX] == 0); for (int index = 0; index < rsx::limits::vertex_count; ++index) { @@ -94,10 +95,16 @@ std::vector D3D12GSRender::upload_vertex_attrib UINT buffer_size = element_size * vertex_count; size_t heap_offset = m_buffer_data.alloc(buffer_size); + u32 base_offset = rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_OFFSET]; + u32 offset = rsx::method_registers[NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + index]; + u32 address = base_offset + rsx::get_address(offset & 0x7fffffff, offset >> 31); + const gsl::byte *src_ptr = gsl::narrow_cast(vm::base(address)); + void *mapped_buffer = m_buffer_data.map(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); for (const auto &range : vertex_ranges) { - write_vertex_array_data_to_buffer(mapped_buffer, range.first, range.second, index, info); + gsl::span mapped_buffer_span = { (gsl::byte*)mapped_buffer, gsl::narrow_cast(buffer_size) }; + write_vertex_array_data_to_buffer(mapped_buffer_span, src_ptr, range.first, range.second, info.type, info.size, info.stride); mapped_buffer = (char*)mapped_buffer + range.second * element_size; } m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 0c7d1cbec1..1a359e7b03 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -564,24 +564,33 @@ void GLGSRender::end() { auto &vertex_info = vertex_arrays_info[index]; // Active vertex array - std::vector vertex_array; + std::vector vertex_array; // Fill vertex_array u32 element_size = rsx::get_vertex_type_size_on_host(vertex_info.type, vertex_info.size); vertex_array.resize(vertex_draw_count * element_size); + + // Get source pointer + u32 base_offset = rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_OFFSET]; + u32 offset = rsx::method_registers[NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + index]; + u32 address = base_offset + rsx::get_address(offset & 0x7fffffff, offset >> 31); + const gsl::byte *src_ptr = gsl::narrow_cast(vm::base(address)); + if (draw_command == rsx::draw_command::array) { size_t offset = 0; + gsl::span dest_span(vertex_array); for (const auto &first_count : first_count_commands) { - write_vertex_array_data_to_buffer(vertex_array.data() + offset, first_count.first, first_count.second, index, vertex_info); + write_vertex_array_data_to_buffer(dest_span.subspan(offset), src_ptr, first_count.first, first_count.second, vertex_info.type, vertex_info.size, vertex_info.stride); offset += first_count.second * element_size; } } if (draw_command == rsx::draw_command::indexed) { vertex_array.resize((max_index + 1) * element_size); - write_vertex_array_data_to_buffer(vertex_array.data(), 0, max_index + 1, index, vertex_info); + gsl::span dest_span(vertex_array); + write_vertex_array_data_to_buffer(dest_span, src_ptr, 0, max_index + 1, vertex_info.type, vertex_info.size, vertex_info.stride); } size_t size = vertex_array.size(); diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 887cc5a5e4..1861bd7ce0 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -83,7 +83,13 @@ - + + true + true + true + true + true +