rsx/common/d3d12: Consider separate index range as a whole.

Fix Wolf of the Battlefield 3
This commit is contained in:
Vincent Lejeune 2016-01-12 00:54:07 +01:00
parent 68f9898171
commit 689dee9944
16 changed files with 490 additions and 415 deletions

View File

@ -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<typename IndexType>
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<typename T>
std::tuple<T, T> upload_untouched(gsl::span<to_be_t<const T>> src, gsl::span<T> 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<IndexType>(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<typename IndexType>
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<typename T>
std::tuple<T, T> expand_indexed_triangle_fan(gsl::span<to_be_t<const T>> src, gsl::span<T> 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<IndexType>(address);
if (index0 == (IndexType)primitive_restart_index)
index0 = (IndexType)-1;
IndexType index1 = vm::ps3::_ref<IndexType>(address + (i + 2 - 1) * sizeof(IndexType));
if (index1 == (IndexType)primitive_restart_index)
index1 = (IndexType)-1;
IndexType index2 = vm::ps3::_ref<IndexType>(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<to_be_t<const T>> 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<typename IndexType>
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<typename T>
std::tuple<T, T> expand_indexed_quads(gsl::span<to_be_t<const T>> src, gsl::span<T> 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<IndexType>(address + 4 * i * sizeof(IndexType));
if (is_primitive_restart_enabled && index0 == (IndexType)primitive_restart_index)
index0 = (IndexType)-1;
IndexType index1 = vm::ps3::_ref<IndexType>(address + (4 * i + 1) * sizeof(IndexType));
if (is_primitive_restart_enabled && index1 == (IndexType)primitive_restart_index)
index1 = (IndexType)-1;
IndexType index2 = vm::ps3::_ref<IndexType>(address + (4 * i + 2) * sizeof(IndexType));
if (is_primitive_restart_enabled && index2 == (IndexType)primitive_restart_index)
index2 = (IndexType)-1;
IndexType index3 = vm::ps3::_ref<IndexType>(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<to_be_t<const T>> 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<typename T>
std::tuple<T, T> write_index_array_data_to_buffer_impl(gsl::span<T, gsl::dynamic_range> dst, Primitive_type m_draw_mode, const std::vector<std::pair<u32, u32> > &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<u32>(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<u32, u32> &range = first_count_arguments[i];
const std::tuple<u32, u32> &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<const T>(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<u32>(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<u16>(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<u32>(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<u16>(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<u32>(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<u16>(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<T>({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index);
case Primitive_type::polygon:
case Primitive_type::triangle_fan:
return expand_indexed_triangle_fan<T>({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index);
case Primitive_type::quads:
return expand_indexed_quads<T>({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index);
}
throw new EXCEPTION("Unknow draw mode");
}
std::tuple<u32, u32> write_index_array_data_to_buffer(gsl::span<u32, gsl::dynamic_range> dst, Primitive_type m_draw_mode, const std::vector<std::pair<u32, u32> > &first_count_arguments)
{
return write_index_array_data_to_buffer_impl(dst, m_draw_mode, first_count_arguments);
}
std::tuple<u16, u16> write_index_array_data_to_buffer(gsl::span<u16, gsl::dynamic_range> dst, Primitive_type m_draw_mode, const std::vector<std::pair<u32, u32> > &first_count_arguments)
{
return write_index_array_data_to_buffer_impl(dst, m_draw_mode, first_count_arguments);
}
std::tuple<u32, u32> write_index_array_data_to_buffer_untouched(gsl::span<u32, gsl::dynamic_range> dst, const std::vector<std::pair<u32, u32> > &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<u32>(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<u32, u32> &range = first_count_arguments[i];
const std::tuple<u32, u32> &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<const u32>(address + first * type_size);
return upload_untouched<u32>({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index);
}
std::tuple<u16, u16> write_index_array_data_to_buffer_untouched(gsl::span<u16, gsl::dynamic_range> dst, const std::vector<std::pair<u32, u32> > &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<u32>(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<u32, u32> &range = first_count_arguments[i];
const std::tuple<u32, u32> &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<const u16>(address + first * type_size);
return upload_untouched<u16>({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index);
}
void stream_vector(void *dst, u32 x, u32 y, u32 z, u32 w)

View File

@ -3,15 +3,6 @@
#include "Emu/Memory/vm.h"
#include "../RSXThread.h"
struct VertexBufferFormat
{
std::pair<size_t, size_t> range;
std::vector<size_t> 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<u32, u32> write_index_array_data_to_buffer(gsl::span<u32, gsl::dynamic_range> dst, Primitive_type m_draw_mode, const std::vector<std::pair<u32, u32> > &first_count_arguments);
std::tuple<u16, u16> write_index_array_data_to_buffer(gsl::span<u16, gsl::dynamic_range> dst, Primitive_type m_draw_mode, const std::vector<std::pair<u32, u32> > &first_count_arguments);
/**
* Doesn't expand index
*/
std::tuple<u32, u32> write_index_array_data_to_buffer_untouched(gsl::span<u32, gsl::dynamic_range> dst, const std::vector<std::pair<u32, u32> > &first_count_arguments);
std::tuple<u16, u16> write_index_array_data_to_buffer_untouched(gsl::span<u16, gsl::dynamic_range> dst, const std::vector<std::pair<u32, u32> > &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.

View File

@ -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<u8> &vertex_data, ID3D12Device *device, data_heap &vertex_index_heap)
{
size_t buffer_size = vertex_data.size();
size_t heap_offset = vertex_index_heap.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
memcpy(vertex_index_heap.map<float>(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<D3D12_VERTEX_BUFFER_VIEW> D3D12GSRender::upload_vertex_attributes(const std::vector<std::pair<u32, u32> > &vertex_ranges)
{
@ -127,10 +105,6 @@ std::vector<D3D12_VERTEX_BUFFER_VIEW> 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<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(256);
@ -305,47 +279,55 @@ std::tuple<bool, size_t> D3D12GSRender::upload_and_set_vertex_index_data(ID3D12G
if (draw_command == Draw_command::draw_command_array)
{
const std::vector<D3D12_VERTEX_BUFFER_VIEW> &vertex_buffer_views = upload_vertex_attributes(m_first_count_pairs);
const std::vector<D3D12_VERTEX_BUFFER_VIEW> &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<int>(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<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
void *mapped_buffer = m_buffer_data.map<void>(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<u16> dst = { (u16*)mapped_buffer, gsl::narrow<int>(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<u32> dst = { (u32*)mapped_buffer, gsl::narrow<int>(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,

View File

@ -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);
}

View File

@ -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

View File

@ -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<std::chrono::system_clock> end_duration = std::chrono::system_clock::now();
m_timers.m_draw_calls_duration += std::chrono::duration_cast<std::chrono::microseconds>(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();
}

View File

@ -152,7 +152,6 @@ private:
*/
std::tuple<bool, size_t> upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list);
std::vector<std::pair<u32, u32> > 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;

View File

@ -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;

View File

@ -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";
}

View File

@ -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,

View File

@ -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<u8> 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<u8> 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>((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>((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<u8> 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();

View File

@ -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);
}

View File

@ -11,6 +11,7 @@
#include <glm/gtc/type_ptr.hpp>
#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<attachment>& 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;

View File

@ -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)

View File

@ -244,20 +244,20 @@ namespace rsx
data_array_format_info register_vertex_info[limits::vertex_count];
std::vector<u8> register_vertex_data[limits::vertex_count];
data_array_format_info vertex_arrays_info[limits::vertex_count];
std::vector<u8> vertex_arrays[limits::vertex_count];
std::vector<u8> vertex_index_array;
u32 vertex_draw_count = 0;
std::unordered_map<u32, color4_base<f32>> transform_constants;
/**
* Stores the first and count argument from draw/draw indexed parameters between begin/end clauses.
*/
std::vector<std::pair<u32, u32> > first_count_commands;
// Constant stored for whole frame
std::unordered_map<u32, color4f> 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];

View File

@ -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)