From 689dee9944ce384b0734f79c637d60f9c7d4d3a1 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Tue, 12 Jan 2016 00:54:07 +0100 Subject: [PATCH] rsx/common/d3d12: Consider separate index range as a whole. Fix Wolf of the Battlefield 3 --- rpcs3/Emu/RSX/Common/BufferUtils.cpp | 354 +++++++++++++-------- rpcs3/Emu/RSX/Common/BufferUtils.h | 28 +- rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp | 60 ++-- rpcs3/Emu/RSX/D3D12/D3D12Formats.cpp | 50 +-- rpcs3/Emu/RSX/D3D12/D3D12Formats.h | 6 +- rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp | 2 - rpcs3/Emu/RSX/D3D12/D3D12GSRender.h | 4 - rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp | 13 +- rpcs3/Emu/RSX/GCM.cpp | 56 +++- rpcs3/Emu/RSX/GCM.h | 37 ++- rpcs3/Emu/RSX/GL/GLGSRender.cpp | 87 +++-- rpcs3/Emu/RSX/GL/gl_helpers.cpp | 52 ++- rpcs3/Emu/RSX/GL/gl_helpers.h | 41 +-- rpcs3/Emu/RSX/RSXThread.cpp | 61 +--- rpcs3/Emu/RSX/RSXThread.h | 12 +- rpcs3/Emu/RSX/rsx_methods.cpp | 42 +-- 16 files changed, 490 insertions(+), 415 deletions(-) diff --git a/rpcs3/Emu/RSX/Common/BufferUtils.cpp b/rpcs3/Emu/RSX/Common/BufferUtils.cpp index ee36d55530..3528c0383d 100644 --- a/rpcs3/Emu/RSX/Common/BufferUtils.cpp +++ b/rpcs3/Emu/RSX/Common/BufferUtils.cpp @@ -26,6 +26,8 @@ namespace } } +// 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) { assert(vertex_array_desc.size > 0); @@ -97,131 +99,169 @@ void write_vertex_array_data_to_buffer(void *buffer, u32 first, u32 count, size_ namespace { -template -void uploadAsIt(char *dst, u32 address, size_t indexCount, bool is_primitive_restart_enabled, u32 primitive_restart_index, u32 &min_index, u32 &max_index) +template +std::tuple upload_untouched(gsl::span> src, gsl::span dst, bool is_primitive_restart_enabled, T primitive_restart_index) { - for (u32 i = 0; i < indexCount; ++i) + T min_index = -1; + T max_index = 0; + + Expects(dst.size_bytes() >= src.size_bytes()); + + size_t dst_idx = 0; + for (T index : src) { - IndexType index = vm::ps3::_ref(address + i * sizeof(IndexType)); - if (is_primitive_restart_enabled && index == (IndexType)primitive_restart_index) - index = (IndexType)-1; - (IndexType&)dst[i * sizeof(IndexType)] = index; - if (is_primitive_restart_enabled && index == (IndexType)-1) // Cut - continue; - max_index = MAX2(max_index, index); - min_index = MIN2(min_index, index); + if (is_primitive_restart_enabled && index == primitive_restart_index) + { + index = -1; + } + else + { + max_index = MAX2(max_index, index); + min_index = MIN2(min_index, index); + } + dst[dst_idx++] = index; } + return std::make_tuple(min_index, max_index); } // FIXME: expanded primitive type may not support primitive restart correctly - -template -void expandIndexedTriangleFan(char *dst, u32 address, size_t indexCount, bool is_primitive_restart_enabled, u32 primitive_restart_index, u32 &min_index, u32 &max_index) +template +std::tuple expand_indexed_triangle_fan(gsl::span> src, gsl::span dst, bool is_primitive_restart_enabled, T primitive_restart_index) { - for (unsigned i = 0; i < indexCount - 2; i++) + T min_index = -1; + T max_index = 0; + + Expects(dst.size() >= 3 * (src.size() - 2)); + + const T index0 = src[0]; + if (!is_primitive_restart_enabled || index0 != -1) // Cut { - IndexType index0 = vm::ps3::_ref(address); - if (index0 == (IndexType)primitive_restart_index) - index0 = (IndexType)-1; - IndexType index1 = vm::ps3::_ref(address + (i + 2 - 1) * sizeof(IndexType)); - if (index1 == (IndexType)primitive_restart_index) - index1 = (IndexType)-1; - IndexType index2 = vm::ps3::_ref(address + (i + 2) * sizeof(IndexType)); - if (index2 == (IndexType)primitive_restart_index) - index2 = (IndexType)-1; + min_index = MIN2(min_index, index0); + max_index = MAX2(max_index, index0); + } - (IndexType&)dst[(3 * i) * sizeof(IndexType)] = index0; - (IndexType&)dst[(3 * i + 1) * sizeof(IndexType)] = index1; - (IndexType&)dst[(3 * i + 2) * sizeof(IndexType)] = index2; - - if (!is_primitive_restart_enabled || index0 != (IndexType)-1) // Cut + size_t dst_idx = 0; + while (src.size() > 2) + { + gsl::span> tri_indexes = src.subspan(0, 2); + T index1 = tri_indexes[0]; + if (is_primitive_restart_enabled && index1 == primitive_restart_index) { - min_index = MIN2(min_index, index0); - max_index = MAX2(max_index, index0); + index1 = -1; } - if (!is_primitive_restart_enabled || index1 != (IndexType)-1) // Cut + else { min_index = MIN2(min_index, index1); max_index = MAX2(max_index, index1); } - if (!is_primitive_restart_enabled || index2 != (IndexType)-1) // Cut + T index2 = tri_indexes[1]; + if (is_primitive_restart_enabled && index2 == primitive_restart_index) + { + index2 = -1; + } + else { min_index = MIN2(min_index, index2); max_index = MAX2(max_index, index2); } + + dst[dst_idx++] = index0; + dst[dst_idx++] = index1; + dst[dst_idx++] = index2; + + src = src.subspan(2); } + return std::make_tuple(min_index, max_index); } -template -void expandIndexedQuads(char *dst, u32 address, size_t indexCount, bool is_primitive_restart_enabled, u32 primitive_restart_index, u32 &min_index, u32 &max_index) +// FIXME: expanded primitive type may not support primitive restart correctly +template +std::tuple expand_indexed_quads(gsl::span> src, gsl::span dst, bool is_primitive_restart_enabled, T primitive_restart_index) { - for (unsigned i = 0; i < indexCount / 4; i++) + T min_index = -1; + T max_index = 0; + + Expects(4 * dst.size_bytes() >= 6 * src.size_bytes()); + + size_t dst_idx = 0; + while (!src.empty()) { - IndexType index0 = vm::ps3::_ref(address + 4 * i * sizeof(IndexType)); - if (is_primitive_restart_enabled && index0 == (IndexType)primitive_restart_index) - index0 = (IndexType)-1; - IndexType index1 = vm::ps3::_ref(address + (4 * i + 1) * sizeof(IndexType)); - if (is_primitive_restart_enabled && index1 == (IndexType)primitive_restart_index) - index1 = (IndexType)-1; - IndexType index2 = vm::ps3::_ref(address + (4 * i + 2) * sizeof(IndexType)); - if (is_primitive_restart_enabled && index2 == (IndexType)primitive_restart_index) - index2 = (IndexType)-1; - IndexType index3 = vm::ps3::_ref(address + (4 * i + 3) * sizeof(IndexType)); - if (is_primitive_restart_enabled &&index3 == (IndexType)primitive_restart_index) - index3 = (IndexType)-1; - - // First triangle - (IndexType&)dst[(6 * i) * sizeof(IndexType)] = index0; - (IndexType&)dst[(6 * i + 1) * sizeof(IndexType)] = index1; - (IndexType&)dst[(6 * i + 2) * sizeof(IndexType)] = index2; - // Second triangle - (IndexType&)dst[(6 * i + 3) * sizeof(IndexType)] = index2; - (IndexType&)dst[(6 * i + 4) * sizeof(IndexType)] = index3; - (IndexType&)dst[(6 * i + 5) * sizeof(IndexType)] = index0; - - if (!is_primitive_restart_enabled || index0 != (IndexType)-1) // Cut + gsl::span> quad_indexes = src.subspan(0, 4); + T index0 = quad_indexes[0]; + if (is_primitive_restart_enabled && index0 == primitive_restart_index) + { + index0 = -1; + } + else { min_index = MIN2(min_index, index0); max_index = MAX2(max_index, index0); } - if (!is_primitive_restart_enabled || index1 != (IndexType)-1) // Cut + T index1 = quad_indexes[1]; + if (is_primitive_restart_enabled && index1 == primitive_restart_index) + { + index1 = -1; + } + else { min_index = MIN2(min_index, index1); max_index = MAX2(max_index, index1); } - if (!is_primitive_restart_enabled || index2 != (IndexType)-1) // Cut + T index2 = quad_indexes[2]; + if (is_primitive_restart_enabled && index2 == primitive_restart_index) + { + index2 = -1; + } + else { min_index = MIN2(min_index, index2); max_index = MAX2(max_index, index2); } - if (!is_primitive_restart_enabled || index3 != (IndexType)-1) // Cut + T index3 = quad_indexes[3]; + if (is_primitive_restart_enabled &&index3 == primitive_restart_index) + { + index3 = -1; + } + else { min_index = MIN2(min_index, index3); max_index = MAX2(max_index, index3); } + + // First triangle + dst[dst_idx++] = index0; + dst[dst_idx++] = index1; + dst[dst_idx++] = index2; + // Second triangle + dst[dst_idx++] = index2; + dst[dst_idx++] = index3; + dst[dst_idx++] = index0; + + src = src.subspan(4); } + return std::make_tuple(min_index, max_index); } } // Only handle quads and triangle fan now -bool is_primitive_native(unsigned m_draw_mode) +bool is_primitive_native(Primitive_type m_draw_mode) { switch (m_draw_mode) { - default: - case CELL_GCM_PRIMITIVE_POINTS: - case CELL_GCM_PRIMITIVE_LINES: - case CELL_GCM_PRIMITIVE_LINE_LOOP: - case CELL_GCM_PRIMITIVE_LINE_STRIP: - case CELL_GCM_PRIMITIVE_TRIANGLES: - case CELL_GCM_PRIMITIVE_TRIANGLE_STRIP: - case CELL_GCM_PRIMITIVE_QUAD_STRIP: + case Primitive_type::points: + case Primitive_type::lines: + case Primitive_type::line_loop: + case Primitive_type::line_strip: + case Primitive_type::triangles: + case Primitive_type::triangle_strip: + case Primitive_type::quad_strip: return true; - case CELL_GCM_PRIMITIVE_POLYGON: - case CELL_GCM_PRIMITIVE_TRIANGLE_FAN: - case CELL_GCM_PRIMITIVE_QUADS: + case Primitive_type::polygon: + case Primitive_type::triangle_fan: + case Primitive_type::quads: return false; } + throw new EXCEPTION("Wrong primitive type"); } /** We assume that polygon is convex in polygon mode (constraints in OpenGL) @@ -229,7 +269,7 @@ bool is_primitive_native(unsigned m_draw_mode) * see http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/polygon-triangulation-r3334 */ -size_t get_index_count(unsigned m_draw_mode, unsigned initial_index_count) +size_t get_index_count(Primitive_type m_draw_mode, unsigned initial_index_count) { // Index count if (is_primitive_native(m_draw_mode)) @@ -237,33 +277,33 @@ size_t get_index_count(unsigned m_draw_mode, unsigned initial_index_count) switch (m_draw_mode) { - case CELL_GCM_PRIMITIVE_POLYGON: - case CELL_GCM_PRIMITIVE_TRIANGLE_FAN: + case Primitive_type::polygon: + case Primitive_type::triangle_fan: return (initial_index_count - 2) * 3; - case CELL_GCM_PRIMITIVE_QUADS: + case Primitive_type::quads: return (6 * initial_index_count) / 4; default: return 0; } } -size_t get_index_type_size(u32 type) +size_t get_index_type_size(Index_array_type type) { switch (type) { - case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16: return 2; - case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32: return 4; - default: return 0; + case Index_array_type::unsigned_16b: return 2; + case Index_array_type::unsigned_32b: return 4; } + throw new EXCEPTION("Wrong index type"); } -void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, unsigned draw_mode, unsigned first, unsigned count) +void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, Primitive_type draw_mode, unsigned first, unsigned count) { unsigned short *typedDst = (unsigned short *)(dst); switch (draw_mode) { - case CELL_GCM_PRIMITIVE_TRIANGLE_FAN: - case CELL_GCM_PRIMITIVE_POLYGON: + case Primitive_type::triangle_fan: + case Primitive_type::polygon: for (unsigned i = 0; i < (count - 2); i++) { typedDst[3 * i] = first; @@ -271,7 +311,7 @@ void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, typedDst[3 * i + 2] = i + 2; } return; - case CELL_GCM_PRIMITIVE_QUADS: + case Primitive_type::quads: for (unsigned i = 0; i < count / 4; i++) { // First triangle @@ -284,62 +324,118 @@ void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, typedDst[6 * i + 5] = 4 * i + first; } return; + case Primitive_type::points: + case Primitive_type::lines: + case Primitive_type::line_loop: + case Primitive_type::line_strip: + case Primitive_type::triangles: + case Primitive_type::triangle_strip: + case Primitive_type::quad_strip: + throw new EXCEPTION("Native primitive type doesn't require expansion"); } } -void write_index_array_data_to_buffer(char* dst, unsigned m_draw_mode, unsigned first, unsigned count, unsigned &min_index, unsigned &max_index) +// TODO: Unify indexed and non indexed primitive expansion ? + +template +std::tuple write_index_array_data_to_buffer_impl(gsl::span dst, Primitive_type m_draw_mode, const std::vector > &first_count_arguments) { u32 address = rsx::get_address(rsx::method_registers[NV4097_SET_INDEX_ARRAY_ADDRESS], rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] & 0xf); - u32 type = rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4; + Index_array_type type = to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4); - u32 type_size = type == CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32 ? sizeof(u32) : sizeof(u16); + u32 type_size = gsl::narrow(get_index_type_size(type)); + + Expects(rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_OFFSET] == 0); + Expects(rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_INDEX] == 0); - u32 base_offset = rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_OFFSET]; - u32 base_index = 0;//rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_INDEX]; bool is_primitive_restart_enabled = !!rsx::method_registers[NV4097_SET_RESTART_INDEX_ENABLE]; u32 primitive_restart_index = rsx::method_registers[NV4097_SET_RESTART_INDEX]; + // Disjoint first_counts ranges not supported atm + for (int i = 0; i < first_count_arguments.size() - 1; i++) + { + const std::tuple &range = first_count_arguments[i]; + const std::tuple &next_range = first_count_arguments[i + 1]; + Expects(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range)); + } + u32 first = std::get<0>(first_count_arguments.front()); + u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first; + auto ptr = vm::ps3::_ptr(address + first * type_size); + switch (m_draw_mode) { - case CELL_GCM_PRIMITIVE_POINTS: - case CELL_GCM_PRIMITIVE_LINES: - case CELL_GCM_PRIMITIVE_LINE_LOOP: - case CELL_GCM_PRIMITIVE_LINE_STRIP: - case CELL_GCM_PRIMITIVE_TRIANGLES: - case CELL_GCM_PRIMITIVE_TRIANGLE_STRIP: - case CELL_GCM_PRIMITIVE_QUAD_STRIP: - case CELL_GCM_PRIMITIVE_POLYGON: - switch (type) - { - case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32: - uploadAsIt(dst, address + (first + base_index) * sizeof(u32), count, is_primitive_restart_enabled, primitive_restart_index, min_index, max_index); - return; - case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16: - uploadAsIt(dst, address + (first + base_index) * sizeof(u16), count, is_primitive_restart_enabled, primitive_restart_index, min_index, max_index); - return; - } - return; - case CELL_GCM_PRIMITIVE_TRIANGLE_FAN: - switch (type) - { - case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32: - expandIndexedTriangleFan(dst, address + (first + base_index) * sizeof(u32), count, is_primitive_restart_enabled, primitive_restart_index, min_index, max_index); - return; - case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16: - expandIndexedTriangleFan(dst, address + (first + base_index) * sizeof(u16), count, is_primitive_restart_enabled, primitive_restart_index, min_index, max_index); - return; - } - case CELL_GCM_PRIMITIVE_QUADS: - switch (type) - { - case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32: - expandIndexedQuads(dst, address + (first + base_index) * sizeof(u32), count, is_primitive_restart_enabled, primitive_restart_index, min_index, max_index); - return; - case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16: - expandIndexedQuads(dst, address + (first + base_index) * sizeof(u16), count, is_primitive_restart_enabled, primitive_restart_index, min_index, max_index); - return; - } + case Primitive_type::points: + case Primitive_type::lines: + case Primitive_type::line_loop: + case Primitive_type::line_strip: + case Primitive_type::triangles: + case Primitive_type::triangle_strip: + case Primitive_type::quad_strip: + return upload_untouched({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index); + case Primitive_type::polygon: + case Primitive_type::triangle_fan: + return expand_indexed_triangle_fan({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index); + case Primitive_type::quads: + return expand_indexed_quads({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index); } + + throw new EXCEPTION("Unknow draw mode"); +} + +std::tuple write_index_array_data_to_buffer(gsl::span dst, Primitive_type m_draw_mode, const std::vector > &first_count_arguments) +{ + return write_index_array_data_to_buffer_impl(dst, m_draw_mode, first_count_arguments); +} + +std::tuple write_index_array_data_to_buffer(gsl::span dst, Primitive_type m_draw_mode, const std::vector > &first_count_arguments) +{ + return write_index_array_data_to_buffer_impl(dst, m_draw_mode, first_count_arguments); +} + +std::tuple write_index_array_data_to_buffer_untouched(gsl::span dst, const std::vector > &first_count_arguments) +{ + u32 address = rsx::get_address(rsx::method_registers[NV4097_SET_INDEX_ARRAY_ADDRESS], rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] & 0xf); + Index_array_type type = to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4); + + u32 type_size = gsl::narrow(get_index_type_size(type)); + bool is_primitive_restart_enabled = !!rsx::method_registers[NV4097_SET_RESTART_INDEX_ENABLE]; + u32 primitive_restart_index = rsx::method_registers[NV4097_SET_RESTART_INDEX]; + + // Disjoint first_counts ranges not supported atm + for (int i = 0; i < first_count_arguments.size() - 1; i++) + { + const std::tuple &range = first_count_arguments[i]; + const std::tuple &next_range = first_count_arguments[i + 1]; + Expects(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range)); + } + u32 first = std::get<0>(first_count_arguments.front()); + u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first; + auto ptr = vm::ps3::_ptr(address + first * type_size); + + return upload_untouched({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index); +} + +std::tuple write_index_array_data_to_buffer_untouched(gsl::span dst, const std::vector > &first_count_arguments) +{ + u32 address = rsx::get_address(rsx::method_registers[NV4097_SET_INDEX_ARRAY_ADDRESS], rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] & 0xf); + Index_array_type type = to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4); + + u32 type_size = gsl::narrow(get_index_type_size(type)); + bool is_primitive_restart_enabled = !!rsx::method_registers[NV4097_SET_RESTART_INDEX_ENABLE]; + u16 primitive_restart_index = rsx::method_registers[NV4097_SET_RESTART_INDEX]; + + // Disjoint first_counts ranges not supported atm + for (int i = 0; i < first_count_arguments.size() - 1; i++) + { + const std::tuple &range = first_count_arguments[i]; + const std::tuple &next_range = first_count_arguments[i + 1]; + Expects(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range)); + } + u32 first = std::get<0>(first_count_arguments.front()); + u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first; + auto ptr = vm::ps3::_ptr(address + first * type_size); + + return upload_untouched({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index); } void stream_vector(void *dst, u32 x, u32 y, u32 z, u32 w) diff --git a/rpcs3/Emu/RSX/Common/BufferUtils.h b/rpcs3/Emu/RSX/Common/BufferUtils.h index 062a7336d8..f2bba57cb1 100644 --- a/rpcs3/Emu/RSX/Common/BufferUtils.h +++ b/rpcs3/Emu/RSX/Common/BufferUtils.h @@ -3,15 +3,6 @@ #include "Emu/Memory/vm.h" #include "../RSXThread.h" - -struct VertexBufferFormat -{ - std::pair range; - std::vector attributeId; - size_t elementCount; - size_t stride; -}; - /** * Write count vertex attributes from index array buffer starting at first, using vertex_array_desc */ @@ -20,29 +11,36 @@ void write_vertex_array_data_to_buffer(void *buffer, u32 first, u32 count, size_ /* * If primitive mode is not supported and need to be emulated (using an index buffer) returns false. */ -bool is_primitive_native(unsigned m_draw_mode); +bool is_primitive_native(Primitive_type m_draw_mode); /** * Returns a fixed index count for emulated primitive, otherwise returns initial_index_count */ -size_t get_index_count(unsigned m_draw_mode, unsigned initial_index_count); +size_t get_index_count(Primitive_type m_draw_mode, unsigned initial_index_count); /** * Returns index type size in byte */ -size_t get_index_type_size(u32 type); +size_t get_index_type_size(Index_array_type type); /** - * Write count indexes starting at first to dst buffer. + * Write count indexes using (first, first + count) ranges. * Returns min/max index found during the process. * The function expands index buffer for non native primitive type. */ -void write_index_array_data_to_buffer(char* dst, unsigned m_draw_mode, unsigned first, unsigned count, unsigned &min_index, unsigned &max_index); +std::tuple write_index_array_data_to_buffer(gsl::span dst, Primitive_type m_draw_mode, const std::vector > &first_count_arguments); +std::tuple write_index_array_data_to_buffer(gsl::span dst, Primitive_type m_draw_mode, const std::vector > &first_count_arguments); + +/** + * Doesn't expand index + */ +std::tuple write_index_array_data_to_buffer_untouched(gsl::span dst, const std::vector > &first_count_arguments); +std::tuple write_index_array_data_to_buffer_untouched(gsl::span dst, const std::vector > &first_count_arguments); /** * Write index data needed to emulate non indexed non native primitive mode. */ -void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, unsigned m_draw_mode, unsigned first, unsigned count); +void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, Primitive_type m_draw_mode, unsigned first, unsigned count); /** * Stream a 128 bits vector to dst. diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp index 0c88a57585..71cad3cf89 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp @@ -8,28 +8,6 @@ #include "D3D12Formats.h" #include "../rsx_methods.h" -namespace -{ -/** - * - */ -D3D12_GPU_VIRTUAL_ADDRESS createVertexBuffer(const rsx::data_array_format_info &vertex_array_desc, const std::vector &vertex_data, ID3D12Device *device, data_heap &vertex_index_heap) -{ - size_t buffer_size = vertex_data.size(); - size_t heap_offset = vertex_index_heap.alloc(buffer_size); - - memcpy(vertex_index_heap.map(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)), vertex_data.data(), vertex_data.size()); - vertex_index_heap.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); - return vertex_index_heap.get_heap()->GetGPUVirtualAddress() + heap_offset; -} - -} - -void D3D12GSRender::load_vertex_data(u32 first, u32 count) -{ - m_first_count_pairs.emplace_back(std::make_pair(first, count)); - vertex_draw_count += count; -} std::vector D3D12GSRender::upload_vertex_attributes(const std::vector > &vertex_ranges) { @@ -127,10 +105,6 @@ std::vector D3D12GSRender::upload_vertex_attributes(co return vertex_buffer_views; } -void D3D12GSRender::load_vertex_index_data(u32 first, u32 count) -{ -} - void D3D12GSRender::upload_and_bind_scale_offset_matrix(size_t descriptorIndex) { size_t heap_offset = m_buffer_data.alloc(256); @@ -305,47 +279,55 @@ std::tuple D3D12GSRender::upload_and_set_vertex_index_data(ID3D12G if (draw_command == Draw_command::draw_command_array) { - const std::vector &vertex_buffer_views = upload_vertex_attributes(m_first_count_pairs); + const std::vector &vertex_buffer_views = upload_vertex_attributes(first_count_commands); command_list->IASetVertexBuffers(0, (UINT)vertex_buffer_views.size(), vertex_buffer_views.data()); if (is_primitive_native(draw_mode)) { // Index count size_t vertex_count = 0; - for (const auto &pair : m_first_count_pairs) + for (const auto &pair : first_count_commands) vertex_count += pair.second; return std::make_tuple(false, vertex_count); } D3D12_INDEX_BUFFER_VIEW index_buffer_view; size_t index_count; - std::tie(index_buffer_view, index_count) = generate_index_buffer_for_emulated_primitives_array(m_first_count_pairs); + std::tie(index_buffer_view, index_count) = generate_index_buffer_for_emulated_primitives_array(first_count_commands); command_list->IASetIndexBuffer(&index_buffer_view); return std::make_tuple(true, index_count); } assert(draw_command == Draw_command::draw_command_indexed); - u32 indexed_type = rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4; - size_t index_size = get_index_type_size(indexed_type); - // Index count size_t index_count = 0; - for (const auto &pair : m_first_count_pairs) - index_count += get_index_count(draw_mode, pair.second); + for (const auto &pair : first_count_commands) + index_count += pair.second; + index_count = get_index_count(draw_mode, gsl::narrow(index_count)); + + Index_array_type indexed_type = to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4); + size_t index_size = get_index_type_size(indexed_type); // Alloc size_t buffer_size = align(index_count * index_size, 64); size_t heap_offset = m_buffer_data.alloc(buffer_size); void *mapped_buffer = m_buffer_data.map(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); - u32 min_index = (u32)-1, max_index = 0; - for (const auto &pair : m_first_count_pairs) + u32 min_index, max_index; + + if (indexed_type == Index_array_type::unsigned_16b) { - size_t element_count = get_index_count(draw_mode, pair.second); - write_index_array_data_to_buffer((char*)mapped_buffer, draw_mode, pair.first, pair.second, min_index, max_index); - mapped_buffer = (char*)mapped_buffer + element_count * index_size; + gsl::span dst = { (u16*)mapped_buffer, gsl::narrow(buffer_size / index_size) }; + std::tie(min_index, max_index) = write_index_array_data_to_buffer(dst, draw_mode, first_count_commands); } + + if (indexed_type == Index_array_type::unsigned_32b) + { + gsl::span dst = { (u32*)mapped_buffer, gsl::narrow(buffer_size / index_size) }; + std::tie(min_index, max_index) = write_index_array_data_to_buffer(dst, draw_mode, first_count_commands); + } + m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); D3D12_INDEX_BUFFER_VIEW index_buffer_view = { m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset, diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Formats.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Formats.cpp index 01ac2cee03..3f9e4cfd97 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Formats.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Formats.cpp @@ -262,38 +262,38 @@ D3D12_FILTER get_texture_filter(u8 min_filter, u8 mag_filter) return D3D12_ENCODE_BASIC_FILTER(min, mag, mip, D3D12_FILTER_REDUCTION_TYPE_STANDARD); } -D3D12_PRIMITIVE_TOPOLOGY get_primitive_topology(u8 draw_mode) +D3D12_PRIMITIVE_TOPOLOGY get_primitive_topology(Primitive_type draw_mode) { switch (draw_mode) { - case CELL_GCM_PRIMITIVE_POINTS: return D3D_PRIMITIVE_TOPOLOGY_POINTLIST; - case CELL_GCM_PRIMITIVE_LINES: return D3D_PRIMITIVE_TOPOLOGY_LINELIST; - case CELL_GCM_PRIMITIVE_LINE_LOOP: return D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ; - case CELL_GCM_PRIMITIVE_LINE_STRIP: return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; - case CELL_GCM_PRIMITIVE_TRIANGLES: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; - case CELL_GCM_PRIMITIVE_TRIANGLE_STRIP: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; - case CELL_GCM_PRIMITIVE_TRIANGLE_FAN: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; - case CELL_GCM_PRIMITIVE_QUADS: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; - case CELL_GCM_PRIMITIVE_QUAD_STRIP: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; - case CELL_GCM_PRIMITIVE_POLYGON: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + case Primitive_type::points: return D3D_PRIMITIVE_TOPOLOGY_POINTLIST; + case Primitive_type::lines: return D3D_PRIMITIVE_TOPOLOGY_LINELIST; + case Primitive_type::line_loop: return D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ; + case Primitive_type::line_strip: return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; + case Primitive_type::triangles: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + case Primitive_type::triangle_strip: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; + case Primitive_type::triangle_fan: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + case Primitive_type::quads: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + case Primitive_type::quad_strip: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + case Primitive_type::polygon: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; } throw EXCEPTION("Invalid draw mode (0x%x)", draw_mode); } -D3D12_PRIMITIVE_TOPOLOGY_TYPE get_primitive_topology_type(u8 draw_mode) +D3D12_PRIMITIVE_TOPOLOGY_TYPE get_primitive_topology_type(Primitive_type draw_mode) { switch (draw_mode) { - case CELL_GCM_PRIMITIVE_POINTS: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; - case CELL_GCM_PRIMITIVE_LINES: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; - case CELL_GCM_PRIMITIVE_LINE_STRIP: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; - case CELL_GCM_PRIMITIVE_TRIANGLES: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; - case CELL_GCM_PRIMITIVE_TRIANGLE_STRIP: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; - case CELL_GCM_PRIMITIVE_TRIANGLE_FAN: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; - case CELL_GCM_PRIMITIVE_QUADS: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; - case CELL_GCM_PRIMITIVE_QUAD_STRIP: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; - case CELL_GCM_PRIMITIVE_POLYGON: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; - case CELL_GCM_PRIMITIVE_LINE_LOOP: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; + case Primitive_type::points: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; + case Primitive_type::lines: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; + case Primitive_type::line_strip: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; + case Primitive_type::triangles: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + case Primitive_type::triangle_strip: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + case Primitive_type::triangle_fan: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + case Primitive_type::quads: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + case Primitive_type::quad_strip: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + case Primitive_type::polygon: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + case Primitive_type::line_loop: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; } throw EXCEPTION("Invalid or unsupported draw mode (0x%x)", draw_mode); } @@ -363,12 +363,12 @@ BOOL get_front_face_ccw(u32 ffv) throw EXCEPTION("Invalid front face value (0x%x)", ffv); } -DXGI_FORMAT get_index_type(u8 index_type) +DXGI_FORMAT get_index_type(Index_array_type index_type) { switch (index_type) { - case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16: return DXGI_FORMAT_R16_UINT; - case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32: return DXGI_FORMAT_R32_UINT; + case Index_array_type::unsigned_16b: return DXGI_FORMAT_R16_UINT; + case Index_array_type::unsigned_32b: return DXGI_FORMAT_R32_UINT; } throw EXCEPTION("Invalid index_type (0x%x)", index_type); } diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Formats.h b/rpcs3/Emu/RSX/D3D12/D3D12Formats.h index 9df0944136..cfa47e8bda 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Formats.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12Formats.h @@ -56,12 +56,12 @@ D3D12_FILTER get_texture_filter(u8 min_filter, u8 mag_filter); /** * Convert draw mode to D3D12_PRIMITIVE_TOPOLOGY */ -D3D12_PRIMITIVE_TOPOLOGY get_primitive_topology(u8 draw_mode); +D3D12_PRIMITIVE_TOPOLOGY get_primitive_topology(Primitive_type draw_mode); /** * Convert draw mode to D3D12_PRIMITIVE_TOPOLOGY_TYPE */ -D3D12_PRIMITIVE_TOPOLOGY_TYPE get_primitive_topology_type(u8 draw_mode); +D3D12_PRIMITIVE_TOPOLOGY_TYPE get_primitive_topology_type(Primitive_type draw_mode); /** * Convert color surface format to DXGI_FORMAT @@ -96,7 +96,7 @@ BOOL get_front_face_ccw(u32 set_front_face_value); /** * Convert index type to DXGI_FORMAT */ -DXGI_FORMAT get_index_type(u8 index_type); +DXGI_FORMAT get_index_type(Index_array_type index_type); /** * Convert vertex attribute format and size to DXGI_FORMAT diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp index 003f41db02..9dd5df2ab0 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp @@ -333,7 +333,6 @@ void D3D12GSRender::end() else get_current_resource_storage().command_list->DrawInstanced((UINT)vertex_count, 1, 0, 0); - vertex_index_array.clear(); std::chrono::time_point end_duration = std::chrono::system_clock::now(); m_timers.m_draw_calls_duration += std::chrono::duration_cast(end_duration - start_duration).count(); m_timers.m_draw_calls_count++; @@ -344,7 +343,6 @@ void D3D12GSRender::end() m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf()); get_current_resource_storage().set_new_command_list(); } - m_first_count_pairs.clear(); thread::end(); } diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h index faf49573b6..deba2e0d46 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h @@ -152,7 +152,6 @@ private: */ std::tuple upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list); - std::vector > m_first_count_pairs; /** * Upload all enabled vertex attributes for vertex in ranges described by vertex_ranges. * A range in vertex_range is a pair whose first element is the index of the beginning of the @@ -201,9 +200,6 @@ protected: virtual void end() override; virtual void flip(int buffer) override; - virtual void load_vertex_data(u32 first, u32 count) override; - virtual void load_vertex_index_data(u32 first, u32 count) override; - virtual void copy_render_targets_to_memory(void *buffer, u8 rtt) override; virtual void copy_depth_buffer_to_memory(void *buffer) override; virtual void copy_stencil_buffer_to_memory(void *buffer) override; diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp index e3c8f1a714..85f0940848 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp @@ -253,8 +253,17 @@ void D3D12GSRender::load_program() prop.IASet = m_IASet; if (!!rsx::method_registers[NV4097_SET_RESTART_INDEX_ENABLE]) - prop.CutValue = ((rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4) == CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32) ? - D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF : D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF; + { + Index_array_type index_type = to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4); + if (index_type == Index_array_type::unsigned_32b) + { + prop.CutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF; + } + if (index_type == Index_array_type::unsigned_16b) + { + prop.CutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF; + } + } m_current_pso = m_pso_cache.getGraphicPipelineState(vertex_program, fragment_program, prop, m_device.Get(), m_root_signatures); return; diff --git a/rpcs3/Emu/RSX/GCM.cpp b/rpcs3/Emu/RSX/GCM.cpp index 0b886d861f..6d0d3bf7e8 100644 --- a/rpcs3/Emu/RSX/GCM.cpp +++ b/rpcs3/Emu/RSX/GCM.cpp @@ -734,6 +734,34 @@ Vertex_base_type to_vertex_base_type(u8 in) throw new EXCEPTION("Unknow vertex base type %d", in); } +Index_array_type to_index_array_type(u8 in) +{ + switch (in) + { + case 0: return Index_array_type::unsigned_32b; + case 1: return Index_array_type::unsigned_16b; + } + throw new EXCEPTION("Unknown index array type %d", in); +} + +Primitive_type to_primitive_type(u8 in) +{ + switch (in) + { + case 1: return Primitive_type::points; + case 2: return Primitive_type::lines; + case 3: return Primitive_type::line_loop; + case 4: return Primitive_type::line_strip; + case 5: return Primitive_type::triangles; + case 6: return Primitive_type::triangle_strip; + case 7: return Primitive_type::triangle_fan; + case 8: return Primitive_type::quads; + case 9: return Primitive_type::quad_strip; + case 10: return Primitive_type::polygon; + } + throw new EXCEPTION("Unknow primitive type %d", in); +} + std::string rsx::get_method_name(const u32 id) { auto found = methods.find(id); @@ -828,18 +856,18 @@ namespace std::string get_primitive_mode(u8 draw_mode) { - switch (draw_mode) + switch (to_primitive_type(draw_mode)) { - case CELL_GCM_PRIMITIVE_POINTS: return "Points"; - case CELL_GCM_PRIMITIVE_LINES: return "Lines"; - case CELL_GCM_PRIMITIVE_LINE_LOOP: return "Line_loop"; - case CELL_GCM_PRIMITIVE_LINE_STRIP: return "Line_strip"; - case CELL_GCM_PRIMITIVE_TRIANGLES: return "Triangles"; - case CELL_GCM_PRIMITIVE_TRIANGLE_STRIP: return "Triangle_strip"; - case CELL_GCM_PRIMITIVE_TRIANGLE_FAN: return "Triangle_fan"; - case CELL_GCM_PRIMITIVE_QUADS: return "Quads"; - case CELL_GCM_PRIMITIVE_QUAD_STRIP: return "Quad_strip"; - case CELL_GCM_PRIMITIVE_POLYGON: return "Polygon"; + case Primitive_type::points: return "Points"; + case Primitive_type::lines: return "Lines"; + case Primitive_type::line_loop: return "Line_loop"; + case Primitive_type::line_strip: return "Line_strip"; + case Primitive_type::triangles: return "Triangles"; + case Primitive_type::triangle_strip: return "Triangle_strip"; + case Primitive_type::triangle_fan: return "Triangle_fan"; + case Primitive_type::quads: return "Quads"; + case Primitive_type::quad_strip: return "Quad_strip"; + case Primitive_type::polygon: return "Polygon"; } return "Error"; } @@ -967,10 +995,10 @@ namespace std::string index_type(u16 arg) { - switch (arg) + switch (to_index_array_type(arg)) { - case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16: return "unsigned short"; - case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32: return "unsigned int"; + case Index_array_type::unsigned_16b: return "unsigned short"; + case Index_array_type::unsigned_32b: return "unsigned int"; } return "Error"; } diff --git a/rpcs3/Emu/RSX/GCM.h b/rpcs3/Emu/RSX/GCM.h index 9f529de592..6a97a25e89 100644 --- a/rpcs3/Emu/RSX/GCM.h +++ b/rpcs3/Emu/RSX/GCM.h @@ -23,7 +23,7 @@ enum CELL_GCM_DISPLAY_FREQUENCY_DISABLE = 3, }; -enum class Vertex_base_type +enum class Vertex_base_type : u8 { s1, ///< signed byte f, ///< float @@ -36,12 +36,30 @@ enum class Vertex_base_type Vertex_base_type to_vertex_base_type(u8 in); -enum +enum class Index_array_type : u8 { - CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32 = 0, - CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16 = 1, + unsigned_32b, + unsigned_16b, }; +Index_array_type to_index_array_type(u8 in); + +enum class Primitive_type : u8 +{ + points, + lines, + line_loop, // line strip with last end being joined with first end. + line_strip, + triangles, + triangle_strip, + triangle_fan, // like strip except that every triangle share the first vertex and one instead of 2 from previous triangle. + quads, + quad_strip, + polygon, // convex polygon +}; + +Primitive_type to_primitive_type(u8 in); + enum { CELL_GCM_DISPLAY_FLIP_STATUS_ = 0, @@ -292,17 +310,6 @@ enum CELL_GCM_TEXTURE_CONVOLUTION_MIN = 7, CELL_GCM_TEXTURE_UNKNOWN_MAG_FILTER = 4, - CELL_GCM_PRIMITIVE_POINTS = 1, - CELL_GCM_PRIMITIVE_LINES = 2, - CELL_GCM_PRIMITIVE_LINE_LOOP = 3, - CELL_GCM_PRIMITIVE_LINE_STRIP = 4, - CELL_GCM_PRIMITIVE_TRIANGLES = 5, - CELL_GCM_PRIMITIVE_TRIANGLE_STRIP = 6, - CELL_GCM_PRIMITIVE_TRIANGLE_FAN = 7, - CELL_GCM_PRIMITIVE_QUADS = 8, - CELL_GCM_PRIMITIVE_QUAD_STRIP = 9, - CELL_GCM_PRIMITIVE_POLYGON = 10, - CELL_GCM_COLOR_MASK_B = 1 << 0, CELL_GCM_COLOR_MASK_G = 1 << 8, CELL_GCM_COLOR_MASK_R = 1 << 16, diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 9ab40ae66d..e51b5a58e6 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -5,6 +5,7 @@ #include "Emu/state.h" #include "GLGSRender.h" #include "../rsx_methods.h" +#include "../Common/BufferUtils.h" #define DUMP_VERTEX_DATA 0 @@ -327,7 +328,7 @@ namespace void GLGSRender::end() { - if (!draw_fbo || !vertex_draw_count) + if (!draw_fbo) { rsx::thread::end(); return; @@ -356,9 +357,6 @@ void GLGSRender::end() //initialize vertex attributes - - - //merge all vertex arrays std::vector vertex_arrays_data; size_t vertex_arrays_offsets[rsx::limits::vertex_count]; @@ -376,6 +374,31 @@ void GLGSRender::end() u32 input_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_INPUT_MASK]; m_vao.bind(); + std::vector vertex_index_array; + vertex_draw_count = 0; + u32 min_index, max_index; + if (draw_command == Draw_command::draw_command_indexed) + { + Index_array_type type = to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4); + u32 type_size = get_index_type_size(type); + for (const auto& first_count : first_count_commands) + { + vertex_draw_count += first_count.second; + } + + vertex_index_array.resize(vertex_draw_count * type_size); + + switch (type) + { + case Index_array_type::unsigned_32b: + std::tie(min_index, max_index) = write_index_array_data_to_buffer_untouched(gsl::span((u32*)vertex_index_array.data(), vertex_draw_count), first_count_commands); + break; + case Index_array_type::unsigned_16b: + std::tie(min_index, max_index) = write_index_array_data_to_buffer_untouched(gsl::span((u16*)vertex_index_array.data(), vertex_draw_count), first_count_commands); + break; + } + } + if (draw_command == Draw_command::draw_command_inlined_array) { write_inline_array_to_buffer(vertex_arrays_data.data()); @@ -397,7 +420,16 @@ void GLGSRender::end() offset += rsx::get_vertex_type_size_on_host(vertex_info.type, vertex_info.size); } } - else + + if (draw_command == Draw_command::draw_command_array) + { + for (const auto &first_count : first_count_commands) + { + vertex_draw_count += first_count.second; + } + } + + if (draw_command == Draw_command::draw_command_array || draw_command == Draw_command::draw_command_indexed) { for (int index = 0; index < rsx::limits::vertex_count; ++index) { @@ -413,17 +445,32 @@ void GLGSRender::end() { auto &vertex_info = vertex_arrays_info[index]; // Active 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); + if (draw_command == Draw_command::draw_command_array) + { + size_t offset = 0; + 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); + offset += first_count.second * element_size; + } + } + if (draw_command == Draw_command::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); + } + + size_t size = vertex_array.size(); size_t position = vertex_arrays_data.size(); vertex_arrays_offsets[index] = position; - - if (vertex_arrays[index].empty()) - continue; - - size_t size = vertex_arrays[index].size(); vertex_arrays_data.resize(position + size); - memcpy(vertex_arrays_data.data() + position, vertex_arrays[index].data(), size); + memcpy(vertex_arrays_data.data() + position, vertex_array.data(), size); __glcheck m_program->attribs[location] = (m_vao + vertex_arrays_offsets[index]) @@ -455,18 +502,20 @@ void GLGSRender::end() } m_vbo.data(vertex_arrays_data.size(), vertex_arrays_data.data()); - if (vertex_index_array.empty()) - { - draw_fbo.draw_arrays(gl::draw_mode(draw_mode - 1), vertex_draw_count); - } - else + if (draw_command == Draw_command::draw_command_indexed) { m_ebo.data(vertex_index_array.size(), vertex_index_array.data()); - u32 indexed_type = rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4; + Index_array_type indexed_type = to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4); - __glcheck glDrawElements(draw_mode - 1, vertex_draw_count, - (indexed_type == CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32 ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT), nullptr); + if (indexed_type == Index_array_type::unsigned_32b) + __glcheck glDrawElements(gl::draw_mode(draw_mode), vertex_draw_count, GL_UNSIGNED_INT, nullptr); + if (indexed_type == Index_array_type::unsigned_16b) + __glcheck glDrawElements(gl::draw_mode(draw_mode), vertex_draw_count, GL_UNSIGNED_SHORT, nullptr); + } + else + { + draw_fbo.draw_arrays(draw_mode, vertex_draw_count); } write_buffers(); diff --git a/rpcs3/Emu/RSX/GL/gl_helpers.cpp b/rpcs3/Emu/RSX/GL/gl_helpers.cpp index a670ccad83..d8ec50be12 100644 --- a/rpcs3/Emu/RSX/GL/gl_helpers.cpp +++ b/rpcs3/Emu/RSX/GL/gl_helpers.cpp @@ -5,6 +5,24 @@ namespace gl { const fbo screen{}; + GLenum draw_mode(Primitive_type in) + { + switch (in) + { + case Primitive_type::points: return GL_POINTS; + case Primitive_type::lines: return GL_LINES; + case Primitive_type::line_loop: return GL_LINE_LOOP; + case Primitive_type::line_strip: return GL_LINE_STRIP; + case Primitive_type::triangles: return GL_TRIANGLES; + case Primitive_type::triangle_strip: return GL_TRIANGLE_STRIP; + case Primitive_type::triangle_fan: return GL_TRIANGLE_FAN; + case Primitive_type::quads: return GL_QUADS; + case Primitive_type::quad_strip: return GL_QUAD_STRIP; + case Primitive_type::polygon: return GL_POLYGON; + } + throw new EXCEPTION("unknow primitive type"); + } + void fbo::create() { glGenFramebuffers(1, &m_id); @@ -79,74 +97,74 @@ namespace gl __glcheck glDrawBuffers((GLsizei)ids.size(), ids.data()); } - void fbo::draw_arrays(draw_mode mode, GLsizei count, GLint first) const + void fbo::draw_arrays(Primitive_type mode, GLsizei count, GLint first) const { save_binding_state save(*this); - __glcheck glDrawArrays((GLenum)mode, first, count); + __glcheck glDrawArrays(draw_mode(mode), first, count); } - void fbo::draw_arrays(const buffer& buffer, draw_mode mode, GLsizei count, GLint first) const + void fbo::draw_arrays(const buffer& buffer, Primitive_type mode, GLsizei count, GLint first) const { buffer.bind(buffer::target::array); draw_arrays(mode, count, first); } - void fbo::draw_arrays(const vao& buffer, draw_mode mode, GLsizei count, GLint first) const + void fbo::draw_arrays(const vao& buffer, Primitive_type mode, GLsizei count, GLint first) const { buffer.bind(); draw_arrays(mode, count, first); } - void fbo::draw_elements(draw_mode mode, GLsizei count, indices_type type, const GLvoid *indices) const + void fbo::draw_elements(Primitive_type mode, GLsizei count, indices_type type, const GLvoid *indices) const { save_binding_state save(*this); - __glcheck glDrawElements((GLenum)mode, count, (GLenum)type, indices); + __glcheck glDrawElements(draw_mode(mode), count, (GLenum)type, indices); } - void fbo::draw_elements(const buffer& buffer, draw_mode mode, GLsizei count, indices_type type, const GLvoid *indices) const + void fbo::draw_elements(const buffer& buffer, Primitive_type mode, GLsizei count, indices_type type, const GLvoid *indices) const { buffer.bind(buffer::target::array); - __glcheck glDrawElements((GLenum)mode, count, (GLenum)type, indices); + __glcheck glDrawElements(draw_mode(mode), count, (GLenum)type, indices); } - void fbo::draw_elements(draw_mode mode, GLsizei count, indices_type type, const buffer& indices, size_t indices_buffer_offset) const + void fbo::draw_elements(Primitive_type mode, GLsizei count, indices_type type, const buffer& indices, size_t indices_buffer_offset) const { indices.bind(buffer::target::element_array); - __glcheck glDrawElements((GLenum)mode, count, (GLenum)type, (GLvoid*)indices_buffer_offset); + __glcheck glDrawElements(draw_mode(mode), count, (GLenum)type, (GLvoid*)indices_buffer_offset); } - void fbo::draw_elements(const buffer& buffer_, draw_mode mode, GLsizei count, indices_type type, const buffer& indices, size_t indices_buffer_offset) const + void fbo::draw_elements(const buffer& buffer_, Primitive_type mode, GLsizei count, indices_type type, const buffer& indices, size_t indices_buffer_offset) const { buffer_.bind(buffer::target::array); draw_elements(mode, count, type, indices, indices_buffer_offset); } - void fbo::draw_elements(draw_mode mode, GLsizei count, const GLubyte *indices) const + void fbo::draw_elements(Primitive_type mode, GLsizei count, const GLubyte *indices) const { draw_elements(mode, count, indices_type::ubyte, indices); } - void fbo::draw_elements(const buffer& buffer, draw_mode mode, GLsizei count, const GLubyte *indices) const + void fbo::draw_elements(const buffer& buffer, Primitive_type mode, GLsizei count, const GLubyte *indices) const { draw_elements(buffer, mode, count, indices_type::ubyte, indices); } - void fbo::draw_elements(draw_mode mode, GLsizei count, const GLushort *indices) const + void fbo::draw_elements(Primitive_type mode, GLsizei count, const GLushort *indices) const { draw_elements(mode, count, indices_type::ushort, indices); } - void fbo::draw_elements(const buffer& buffer, draw_mode mode, GLsizei count, const GLushort *indices) const + void fbo::draw_elements(const buffer& buffer, Primitive_type mode, GLsizei count, const GLushort *indices) const { draw_elements(buffer, mode, count, indices_type::ushort, indices); } - void fbo::draw_elements(draw_mode mode, GLsizei count, const GLuint *indices) const + void fbo::draw_elements(Primitive_type mode, GLsizei count, const GLuint *indices) const { draw_elements(mode, count, indices_type::uint, indices); } - void fbo::draw_elements(const buffer& buffer, draw_mode mode, GLsizei count, const GLuint *indices) const + void fbo::draw_elements(const buffer& buffer, Primitive_type mode, GLsizei count, const GLuint *indices) const { draw_elements(buffer, mode, count, indices_type::uint, indices); } diff --git a/rpcs3/Emu/RSX/GL/gl_helpers.h b/rpcs3/Emu/RSX/GL/gl_helpers.h index c2914eea4a..bae1a00c52 100644 --- a/rpcs3/Emu/RSX/GL/gl_helpers.h +++ b/rpcs3/Emu/RSX/GL/gl_helpers.h @@ -11,6 +11,7 @@ #include #include "OpenGL.h" +#include "../GCM.h" namespace gl { @@ -1379,19 +1380,7 @@ namespace gl settings& border_color(color4f value); }; - enum class draw_mode - { - points = GL_POINTS, - lines = GL_LINES, - line_loop = GL_LINE_LOOP, - line_strip = GL_LINE_STRIP, - triangles = GL_TRIANGLES, - triangle_strip = GL_TRIANGLE_STRIP, - triangle_fan = GL_TRIANGLE_FAN, - quads = GL_QUADS, - quad_strip = GL_QUAD_STRIP, - polygone = GL_POLYGON - }; + GLenum draw_mode(Primitive_type in); enum class indices_type { @@ -1534,20 +1523,20 @@ namespace gl void draw_buffer(const attachment& buffer) const; void draw_buffers(const std::initializer_list& indexes) const; - void draw_arrays(draw_mode mode, GLsizei count, GLint first = 0) const; - void draw_arrays(const buffer& buffer, draw_mode mode, GLsizei count, GLint first = 0) const; - void draw_arrays(const vao& buffer, draw_mode mode, GLsizei count, GLint first = 0) const; + void draw_arrays(Primitive_type mode, GLsizei count, GLint first = 0) const; + void draw_arrays(const buffer& buffer, Primitive_type mode, GLsizei count, GLint first = 0) const; + void draw_arrays(const vao& buffer, Primitive_type mode, GLsizei count, GLint first = 0) const; - void draw_elements(draw_mode mode, GLsizei count, indices_type type, const GLvoid *indices) const; - void draw_elements(const buffer& buffer, draw_mode mode, GLsizei count, indices_type type, const GLvoid *indices) const; - void draw_elements(draw_mode mode, GLsizei count, indices_type type, const buffer& indices, size_t indices_buffer_offset = 0) const; - void draw_elements(const buffer& buffer_, draw_mode mode, GLsizei count, indices_type type, const buffer& indices, size_t indices_buffer_offset = 0) const; - void draw_elements(draw_mode mode, GLsizei count, const GLubyte *indices) const; - void draw_elements(const buffer& buffer, draw_mode mode, GLsizei count, const GLubyte *indices) const; - void draw_elements(draw_mode mode, GLsizei count, const GLushort *indices) const; - void draw_elements(const buffer& buffer, draw_mode mode, GLsizei count, const GLushort *indices) const; - void draw_elements(draw_mode mode, GLsizei count, const GLuint *indices) const; - void draw_elements(const buffer& buffer, draw_mode mode, GLsizei count, const GLuint *indices) const; + void draw_elements(Primitive_type mode, GLsizei count, indices_type type, const GLvoid *indices) const; + void draw_elements(const buffer& buffer, Primitive_type mode, GLsizei count, indices_type type, const GLvoid *indices) const; + void draw_elements(Primitive_type mode, GLsizei count, indices_type type, const buffer& indices, size_t indices_buffer_offset = 0) const; + void draw_elements(const buffer& buffer_, Primitive_type mode, GLsizei count, indices_type type, const buffer& indices, size_t indices_buffer_offset = 0) const; + void draw_elements(Primitive_type mode, GLsizei count, const GLubyte *indices) const; + void draw_elements(const buffer& buffer, Primitive_type mode, GLsizei count, const GLubyte *indices) const; + void draw_elements(Primitive_type mode, GLsizei count, const GLushort *indices) const; + void draw_elements(const buffer& buffer, Primitive_type mode, GLsizei count, const GLushort *indices) const; + void draw_elements(Primitive_type mode, GLsizei count, const GLuint *indices) const; + void draw_elements(const buffer& buffer, Primitive_type mode, GLsizei count, const GLuint *indices) const; void clear(buffers buffers_) const; void clear(buffers buffers_, color4f color_value, double depth_value, u8 stencil_value) const; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 2e7f52fb1c..0f485e156a 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -270,57 +270,6 @@ namespace rsx } } - void thread::load_vertex_data(u32 first, u32 count) - { - vertex_draw_count += count; - - for (int index = 0; index < limits::vertex_count; ++index) - { - const auto &info = vertex_arrays_info[index]; - - if (info.size == 0) // disabled - continue; - - auto &data = vertex_arrays[index]; - - u32 element_size = get_vertex_type_size_on_host(info.type, info.size); - - u32 dst_position = (u32)data.size(); - data.resize(dst_position + count * element_size); - write_vertex_array_data_to_buffer(data.data() + dst_position, first, count, index, info); - } - } - - void thread::load_vertex_index_data(u32 first, u32 count) - { - u32 address = get_address(method_registers[NV4097_SET_INDEX_ARRAY_ADDRESS], method_registers[NV4097_SET_INDEX_ARRAY_DMA] & 0xf); - u32 type = method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4; - - u32 type_size = type == CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32 ? sizeof(u32) : sizeof(u16); - u32 dst_offset = (u32)vertex_index_array.size(); - vertex_index_array.resize(dst_offset + count * type_size); - - u32 base_offset = method_registers[NV4097_SET_VERTEX_DATA_BASE_OFFSET]; - u32 base_index = method_registers[NV4097_SET_VERTEX_DATA_BASE_INDEX]; - - switch (type) - { - case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32: - for (u32 i = 0; i < count; ++i) - { - (u32&)vertex_index_array[dst_offset + i * sizeof(u32)] = vm::read32(address + (first + i) * sizeof(u32)); - } - break; - - case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16: - for (u32 i = 0; i < count; ++i) - { - (u16&)vertex_index_array[dst_offset + i * sizeof(u16)] = vm::read16(address + (first + i) * sizeof(u16)); - } - break; - } - } - void thread::capture_frame(const std::string &name) { frame_capture_data::draw_state draw_state = {}; @@ -372,18 +321,12 @@ namespace rsx void thread::begin() { - draw_mode = method_registers[NV4097_SET_BEGIN_END]; + first_count_commands.clear(); + draw_mode = to_primitive_type(method_registers[NV4097_SET_BEGIN_END]); } void thread::end() { - vertex_index_array.clear(); - - for (auto &vertex_array : vertex_arrays) - { - vertex_array.clear(); - } - transform_constants.clear(); if (capture_current_frame) diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index b80d89fbad..c92549e59d 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -244,20 +244,20 @@ namespace rsx data_array_format_info register_vertex_info[limits::vertex_count]; std::vector register_vertex_data[limits::vertex_count]; data_array_format_info vertex_arrays_info[limits::vertex_count]; - std::vector vertex_arrays[limits::vertex_count]; - std::vector vertex_index_array; u32 vertex_draw_count = 0; std::unordered_map> transform_constants; + /** + * Stores the first and count argument from draw/draw indexed parameters between begin/end clauses. + */ + std::vector > first_count_commands; + // Constant stored for whole frame std::unordered_map local_transform_constants; u32 transform_program[512 * 4] = {}; - virtual void load_vertex_data(u32 first, u32 count); - virtual void load_vertex_index_data(u32 first, u32 count); - bool capture_current_frame = false; void capture_frame(const std::string &name); public: @@ -281,7 +281,7 @@ namespace rsx draw_command_inlined_array, draw_command_indexed, } draw_command; - u32 draw_mode; + Primitive_type draw_mode; u32 local_mem_addr, main_mem_addr; bool strict_ordering[0x1000]; diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index 578e4080fc..06e09d1db6 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -164,7 +164,7 @@ namespace rsx u32 first = arg & 0xffffff; u32 count = (arg >> 24) + 1; - rsx->load_vertex_data(first, count); + rsx->first_count_commands.emplace_back(std::make_pair(first, count)); } force_inline void draw_index_array(thread* rsx, u32 arg) @@ -173,8 +173,7 @@ namespace rsx u32 first = arg & 0xffffff; u32 count = (arg >> 24) + 1; - rsx->load_vertex_data(first, count); - rsx->load_vertex_index_data(first, count); + rsx->first_count_commands.emplace_back(std::make_pair(first, count)); } force_inline void draw_inline_array(thread* rsx, u32 arg) @@ -225,44 +224,7 @@ namespace rsx return; } - if (!rsx->vertex_draw_count) - { - bool has_array = false; - - for (int i = 0; i < rsx::limits::vertex_count; ++i) - { - if (rsx->vertex_arrays_info[i].size > 0) - { - has_array = true; - break; - } - } - - if (!has_array) - { - u32 min_count = ~0; - - for (int i = 0; i < rsx::limits::vertex_count; ++i) - { - if (!rsx->register_vertex_info[i].size) - continue; - - u32 count = u32(rsx->register_vertex_data[i].size()) / - rsx::get_vertex_type_size_on_host(rsx->register_vertex_info[i].type, rsx->register_vertex_info[i].size); - - if (count < min_count) - min_count = count; - } - - if (min_count && min_count < ~0) - { - rsx->vertex_draw_count = min_count; - } - } - } - rsx->end(); - rsx->vertex_draw_count = 0; } force_inline void get_report(thread* rsx, u32 arg)