rsx/common/d3d12/gl: Implement draw inline array support

This commit is contained in:
Vincent Lejeune 2015-12-31 19:15:44 +01:00
parent 34336ebfce
commit cae2d929ab
6 changed files with 293 additions and 125 deletions

View File

@ -34,9 +34,10 @@ void D3D12GSRender::load_vertex_data(u32 first, u32 count)
vertex_draw_count += count; vertex_draw_count += count;
} }
void D3D12GSRender::upload_vertex_attributes(const std::vector<std::pair<u32, u32> > &vertex_ranges) std::vector<D3D12_VERTEX_BUFFER_VIEW> D3D12GSRender::upload_vertex_attributes(const std::vector<std::pair<u32, u32> > &vertex_ranges)
{ {
m_vertex_buffer_views.clear(); std::vector<D3D12_VERTEX_BUFFER_VIEW> vertex_buffer_views;
m_IASet.clear(); m_IASet.clear();
size_t input_slot = 0; size_t input_slot = 0;
@ -81,7 +82,7 @@ void D3D12GSRender::upload_vertex_attributes(const std::vector<std::pair<u32, u3
(UINT)buffer_size, (UINT)buffer_size,
(UINT)element_size (UINT)element_size
}; };
m_vertex_buffer_views.push_back(vertex_buffer_view); vertex_buffer_views.push_back(vertex_buffer_view);
m_timers.m_buffer_upload_size += buffer_size; m_timers.m_buffer_upload_size += buffer_size;
@ -120,7 +121,7 @@ void D3D12GSRender::upload_vertex_attributes(const std::vector<std::pair<u32, u3
(UINT)buffer_size, (UINT)buffer_size,
(UINT)element_size (UINT)element_size
}; };
m_vertex_buffer_views.push_back(vertex_buffer_view); vertex_buffer_views.push_back(vertex_buffer_view);
D3D12_INPUT_ELEMENT_DESC IAElement = {}; D3D12_INPUT_ELEMENT_DESC IAElement = {};
IAElement.SemanticName = "TEXCOORD"; IAElement.SemanticName = "TEXCOORD";
@ -133,11 +134,12 @@ void D3D12GSRender::upload_vertex_attributes(const std::vector<std::pair<u32, u3
m_IASet.push_back(IAElement); m_IASet.push_back(IAElement);
} }
} }
return vertex_buffer_views;
} }
void D3D12GSRender::load_vertex_index_data(u32 first, u32 count) void D3D12GSRender::load_vertex_index_data(u32 first, u32 count)
{ {
m_rendering_info.m_indexed = true;
} }
void D3D12GSRender::upload_and_bind_scale_offset_matrix(size_t descriptorIndex) void D3D12GSRender::upload_and_bind_scale_offset_matrix(size_t descriptorIndex)
@ -227,82 +229,162 @@ void D3D12GSRender::upload_and_bind_fragment_shader_constants(size_t descriptor_
.Offset((INT)descriptor_index, g_descriptor_stride_srv_cbv_uav)); .Offset((INT)descriptor_index, g_descriptor_stride_srv_cbv_uav));
} }
void D3D12GSRender::upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list)
std::tuple<D3D12_VERTEX_BUFFER_VIEW, size_t> D3D12GSRender::upload_inlined_vertex_array()
{ {
// Index count UINT offset = 0;
m_rendering_info.m_count = 0; m_IASet.clear();
for (const auto &pair : m_first_count_pairs) // Bind attributes
m_rendering_info.m_count += get_index_count(draw_mode, pair.second); for (int index = 0; index < rsx::limits::vertex_count; ++index)
if (!m_rendering_info.m_indexed)
{ {
// Non indexed const auto &info = vertex_arrays_info[index];
upload_vertex_attributes(m_first_count_pairs);
command_list->IASetVertexBuffers(0, (UINT)m_vertex_buffer_views.size(), m_vertex_buffer_views.data()); if (!info.size) // disabled
continue;
D3D12_INPUT_ELEMENT_DESC IAElement = {};
IAElement.SemanticName = "TEXCOORD";
IAElement.SemanticIndex = (UINT)index;
IAElement.InputSlot = 0;
IAElement.Format = get_vertex_attribute_format(info.type, info.size);
IAElement.AlignedByteOffset = offset;
IAElement.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
IAElement.InstanceDataStepRate = 0;
m_IASet.push_back(IAElement);
offset += rsx::get_vertex_type_size(info.type) * info.size;
}
// Copy inline buffer
size_t buffer_size = inline_vertex_array.size() * sizeof(int);
assert(m_vertex_index_data.can_alloc(buffer_size));
size_t heap_offset = m_vertex_index_data.alloc(buffer_size);
void *buffer;
CHECK_HRESULT(m_vertex_index_data.m_heap->Map(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size), (void**)&buffer));
void *mapped_buffer = (char*)buffer + heap_offset;
write_inline_array_to_buffer(mapped_buffer);
m_vertex_index_data.m_heap->Unmap(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view =
{
m_vertex_index_data.m_heap->GetGPUVirtualAddress() + heap_offset,
(UINT)buffer_size,
(UINT)offset
};
return std::make_tuple(vertex_buffer_view, (u32)buffer_size / offset);
}
std::tuple<D3D12_INDEX_BUFFER_VIEW, size_t> D3D12GSRender::generate_index_buffer_for_emulated_primitives_array(const std::vector<std::pair<u32, u32> > &vertex_ranges)
{
size_t index_count = 0;
for (const auto &pair : vertex_ranges)
index_count += get_index_count(draw_mode, pair.second);
// Alloc
size_t buffer_size = align(index_count * sizeof(u16), 64);
assert(m_vertex_index_data.can_alloc(buffer_size));
size_t heap_offset = m_vertex_index_data.alloc(buffer_size);
void *buffer;
CHECK_HRESULT(m_vertex_index_data.m_heap->Map(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size), (void**)&buffer));
void *mapped_buffer = (char*)buffer + heap_offset;
size_t first = 0;
for (const auto &pair : vertex_ranges)
{
size_t element_count = get_index_count(draw_mode, pair.second);
write_index_array_for_non_indexed_non_native_primitive_to_buffer((char*)mapped_buffer, draw_mode, (u32)first, (u32)pair.second);
mapped_buffer = (char*)mapped_buffer + element_count * sizeof(u16);
first += pair.second;
}
m_vertex_index_data.m_heap->Unmap(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
D3D12_INDEX_BUFFER_VIEW index_buffer_view = {
m_vertex_index_data.m_heap->GetGPUVirtualAddress() + heap_offset,
(UINT)buffer_size,
DXGI_FORMAT_R16_UINT
};
return std::make_tuple(index_buffer_view, index_count);
}
std::tuple<bool, size_t> D3D12GSRender::upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list)
{
if (draw_command == Draw_command::draw_command_inlined_array)
{
size_t vertex_count;
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view;
std::tie(vertex_buffer_view, vertex_count) = upload_inlined_vertex_array();
command_list->IASetVertexBuffers(0, (UINT)1, &vertex_buffer_view);
if (is_primitive_native(draw_mode)) if (is_primitive_native(draw_mode))
return; return std::make_tuple(false, vertex_count);
// Handle non native primitive
// Alloc D3D12_INDEX_BUFFER_VIEW index_buffer_view;
size_t buffer_size = align(m_rendering_info.m_count * sizeof(u16), 64); size_t index_count;
assert(m_vertex_index_data.can_alloc(buffer_size)); std::tie(index_buffer_view, index_count) = generate_index_buffer_for_emulated_primitives_array({ { 0, (u32)vertex_count } });
size_t heap_offset = m_vertex_index_data.alloc(buffer_size);
void *buffer;
CHECK_HRESULT(m_vertex_index_data.m_heap->Map(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size), (void**)&buffer));
void *mapped_buffer = (char*)buffer + heap_offset;
size_t first = 0;
for (const auto &pair : m_first_count_pairs)
{
size_t element_count = get_index_count(draw_mode, pair.second);
write_index_array_for_non_indexed_non_native_primitive_to_buffer((char*)mapped_buffer, draw_mode, (u32)first, (u32)pair.second);
mapped_buffer = (char*)mapped_buffer + element_count * sizeof(u16);
first += pair.second;
}
m_vertex_index_data.m_heap->Unmap(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
D3D12_INDEX_BUFFER_VIEW index_buffer_view = {
m_vertex_index_data.m_heap->GetGPUVirtualAddress() + heap_offset,
(UINT)buffer_size,
DXGI_FORMAT_R16_UINT
};
command_list->IASetIndexBuffer(&index_buffer_view); command_list->IASetIndexBuffer(&index_buffer_view);
m_rendering_info.m_indexed = true; return std::make_tuple(true, index_count);
} }
else
if (draw_command == Draw_command::draw_command_array)
{ {
u32 indexed_type = rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4; const std::vector<D3D12_VERTEX_BUFFER_VIEW> &vertex_buffer_views = upload_vertex_attributes(m_first_count_pairs);
command_list->IASetVertexBuffers(0, (UINT)vertex_buffer_views.size(), vertex_buffer_views.data());
// Index type if (is_primitive_native(draw_mode))
size_t index_size = get_index_type_size(indexed_type);
// Alloc
size_t buffer_size = align(m_rendering_info.m_count * index_size, 64);
assert(m_vertex_index_data.can_alloc(buffer_size));
size_t heap_offset = m_vertex_index_data.alloc(buffer_size);
void *buffer;
CHECK_HRESULT(m_vertex_index_data.m_heap->Map(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size), (void**)&buffer));
void *mapped_buffer = (char*)buffer + heap_offset;
u32 min_index = (u32)-1, max_index = 0;
for (const auto &pair : m_first_count_pairs)
{ {
size_t element_count = get_index_count(draw_mode, pair.second); // Index count
write_index_array_data_to_buffer((char*)mapped_buffer, draw_mode, pair.first, pair.second, min_index, max_index); size_t vertex_count = 0;
mapped_buffer = (char*)mapped_buffer + element_count * index_size; for (const auto &pair : m_first_count_pairs)
vertex_count += pair.second;
return std::make_tuple(false, vertex_count);
} }
m_vertex_index_data.m_heap->Unmap(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
D3D12_INDEX_BUFFER_VIEW index_buffer_view = {
m_vertex_index_data.m_heap->GetGPUVirtualAddress() + heap_offset,
(UINT)buffer_size,
get_index_type(indexed_type)
};
m_timers.m_buffer_upload_size += buffer_size;
command_list->IASetIndexBuffer(&index_buffer_view);
m_rendering_info.m_indexed = true;
upload_vertex_attributes({ std::make_pair(0, max_index + 1) }); D3D12_INDEX_BUFFER_VIEW index_buffer_view;
command_list->IASetVertexBuffers(0, (UINT)m_vertex_buffer_views.size(), m_vertex_buffer_views.data()); size_t index_count;
std::tie(index_buffer_view, index_count) = generate_index_buffer_for_emulated_primitives_array(m_first_count_pairs);
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);
// Alloc
size_t buffer_size = align(index_count * index_size, 64);
assert(m_vertex_index_data.can_alloc(buffer_size));
size_t heap_offset = m_vertex_index_data.alloc(buffer_size);
void *buffer;
CHECK_HRESULT(m_vertex_index_data.m_heap->Map(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size), (void**)&buffer));
void *mapped_buffer = (char*)buffer + heap_offset;
u32 min_index = (u32)-1, max_index = 0;
for (const auto &pair : m_first_count_pairs)
{
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;
}
m_vertex_index_data.m_heap->Unmap(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
D3D12_INDEX_BUFFER_VIEW index_buffer_view = {
m_vertex_index_data.m_heap->GetGPUVirtualAddress() + heap_offset,
(UINT)buffer_size,
get_index_type(indexed_type)
};
m_timers.m_buffer_upload_size += buffer_size;
command_list->IASetIndexBuffer(&index_buffer_view);
const std::vector<D3D12_VERTEX_BUFFER_VIEW> &vertex_buffer_views = upload_vertex_attributes({ std::make_pair(0, max_index + 1) });
command_list->IASetVertexBuffers(0, (UINT)vertex_buffer_views.size(), vertex_buffer_views.data());
return std::make_tuple(true, index_count);
} }
#endif #endif

View File

@ -264,8 +264,9 @@ void D3D12GSRender::end()
std::chrono::time_point<std::chrono::system_clock> vertex_index_duration_start = std::chrono::system_clock::now(); std::chrono::time_point<std::chrono::system_clock> vertex_index_duration_start = std::chrono::system_clock::now();
if (!vertex_index_array.empty() || vertex_draw_count) size_t vertex_count;
upload_and_set_vertex_index_data(get_current_resource_storage().command_list.Get()); bool indexed_draw;
std::tie(indexed_draw, vertex_count) = upload_and_set_vertex_index_data(get_current_resource_storage().command_list.Get());
std::chrono::time_point<std::chrono::system_clock> vertex_index_duration_end = std::chrono::system_clock::now(); std::chrono::time_point<std::chrono::system_clock> vertex_index_duration_end = std::chrono::system_clock::now();
m_timers.m_vertex_index_duration += std::chrono::duration_cast<std::chrono::microseconds>(vertex_index_duration_end - vertex_index_duration_start).count(); m_timers.m_vertex_index_duration += std::chrono::duration_cast<std::chrono::microseconds>(vertex_index_duration_end - vertex_index_duration_start).count();
@ -341,10 +342,10 @@ void D3D12GSRender::end()
get_current_resource_storage().command_list->IASetPrimitiveTopology(get_primitive_topology(draw_mode)); get_current_resource_storage().command_list->IASetPrimitiveTopology(get_primitive_topology(draw_mode));
if (m_rendering_info.m_indexed) if (indexed_draw)
get_current_resource_storage().command_list->DrawIndexedInstanced((UINT)m_rendering_info.m_count, 1, 0, 0, 0); get_current_resource_storage().command_list->DrawIndexedInstanced((UINT)vertex_count, 1, 0, 0, 0);
else else
get_current_resource_storage().command_list->DrawInstanced((UINT)m_rendering_info.m_count, 1, 0, 0); get_current_resource_storage().command_list->DrawInstanced((UINT)vertex_count, 1, 0, 0);
vertex_index_array.clear(); vertex_index_array.clear();
std::chrono::time_point<std::chrono::system_clock> end_duration = std::chrono::system_clock::now(); std::chrono::time_point<std::chrono::system_clock> end_duration = std::chrono::system_clock::now();
@ -358,7 +359,6 @@ void D3D12GSRender::end()
get_current_resource_storage().set_new_command_list(); get_current_resource_storage().set_new_command_list();
} }
m_first_count_pairs.clear(); m_first_count_pairs.clear();
m_rendering_info.m_indexed = false;
thread::end(); thread::end();
} }

View File

@ -121,16 +121,9 @@ private:
data_heap<ID3D12Heap, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT> m_uav_heap; data_heap<ID3D12Heap, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT> m_uav_heap;
data_heap<ID3D12Resource, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT> m_readback_resources; data_heap<ID3D12Resource, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT> m_readback_resources;
struct
{
bool m_indexed; /*<! is draw call using an index buffer */
size_t m_count; /*<! draw call vertex count */
} m_rendering_info;
render_targets m_rtts; render_targets m_rtts;
std::vector<D3D12_INPUT_ELEMENT_DESC> m_IASet; std::vector<D3D12_INPUT_ELEMENT_DESC> m_IASet;
std::vector<D3D12_VERTEX_BUFFER_VIEW> m_vertex_buffer_views;
INT g_descriptor_stride_srv_cbv_uav; INT g_descriptor_stride_srv_cbv_uav;
INT g_descriptor_stride_dsv; INT g_descriptor_stride_dsv;
@ -158,10 +151,11 @@ private:
void set_rtt_and_ds(ID3D12GraphicsCommandList *command_list); void set_rtt_and_ds(ID3D12GraphicsCommandList *command_list);
/** /**
* Create vertex and index buffers (if needed) and set them to cmdlist. * Create vertex and index buffers (if needed) and set them to cmdlist.
* Non native primitive type are emulated by index buffers expansion. * Non native primitive type are emulated by index buffers expansion.
* Returns whether the draw call is indexed or not and the vertex count to draw.
*/ */
void upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list); std::tuple<bool, size_t> upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list);
std::vector<std::pair<u32, u32> > m_first_count_pairs; std::vector<std::pair<u32, u32> > m_first_count_pairs;
/** /**
@ -169,7 +163,11 @@ private:
* A range in vertex_range is a pair whose first element is the index of the beginning of the * A range in vertex_range is a pair whose first element is the index of the beginning of the
* range, and whose second element is the number of vertex in this range. * range, and whose second element is the number of vertex in this range.
*/ */
void upload_vertex_attributes(const std::vector<std::pair<u32, u32> > &vertex_ranges); std::vector<D3D12_VERTEX_BUFFER_VIEW> upload_vertex_attributes(const std::vector<std::pair<u32, u32> > &vertex_ranges);
std::tuple<D3D12_VERTEX_BUFFER_VIEW, size_t> upload_inlined_vertex_array();
std::tuple<D3D12_INDEX_BUFFER_VIEW, size_t> generate_index_buffer_for_emulated_primitives_array(const std::vector<std::pair<u32, u32> > &vertex_ranges);
void upload_and_bind_scale_offset_matrix(size_t descriptor_index); void upload_and_bind_scale_offset_matrix(size_t descriptor_index);
void upload_and_bind_vertex_shader_constants(size_t descriptor_index); void upload_and_bind_vertex_shader_constants(size_t descriptor_index);

View File

@ -379,62 +379,85 @@ void GLGSRender::end()
u32 input_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_INPUT_MASK]; u32 input_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_INPUT_MASK];
m_vao.bind(); m_vao.bind();
for (int index = 0; index < rsx::limits::vertex_count; ++index) if (draw_command == Draw_command::draw_command_inlined_array)
{ {
bool enabled = !!(input_mask & (1 << index)); write_inline_array_to_buffer(vertex_arrays_data.data());
if (!enabled) size_t offset = 0;
continue; for (int index = 0; index < rsx::limits::vertex_count; ++index)
int location;
if (!m_program->attribs.has_location(reg_table[index], &location))
continue;
if (vertex_arrays_info[index].size > 0)
{ {
auto &vertex_info = vertex_arrays_info[index]; auto &vertex_info = vertex_arrays_info[index];
// Active vertex array
size_t position = vertex_arrays_data.size(); if (!vertex_info.size) // disabled
vertex_arrays_offsets[index] = position;
if (vertex_arrays[index].empty())
continue; continue;
size_t size = vertex_arrays[index].size(); int location;
vertex_arrays_data.resize(position + size); if (!m_program->attribs.has_location(reg_table[index], &location))
continue;
memcpy(vertex_arrays_data.data() + position, vertex_arrays[index].data(), size);
__glcheck m_program->attribs[location] = __glcheck m_program->attribs[location] =
(m_vao + vertex_arrays_offsets[index]) (m_vao + offset)
.config(gl_types[vertex_info.type], vertex_info.size, gl_normalized[vertex_info.type]); .config(gl_types[vertex_info.type], vertex_info.size, gl_normalized[vertex_info.type]);
offset += rsx::get_vertex_type_size(vertex_info.type) * vertex_info.size;
} }
else if (register_vertex_info[index].size > 0) }
else
{
for (int index = 0; index < rsx::limits::vertex_count; ++index)
{ {
auto &vertex_data = register_vertex_data[index]; bool enabled = !!(input_mask & (1 << index));
auto &vertex_info = register_vertex_info[index]; if (!enabled)
continue;
switch (vertex_info.type) int location;
if (!m_program->attribs.has_location(reg_table[index], &location))
continue;
if (vertex_arrays_info[index].size > 0)
{ {
case CELL_GCM_VERTEX_F: auto &vertex_info = vertex_arrays_info[index];
switch (register_vertex_info[index].size) // Active vertex array
{
case 1: apply_attrib_array<f32, 1>(*m_program, location, vertex_data); break;
case 2: apply_attrib_array<f32, 2>(*m_program, location, vertex_data); break;
case 3: apply_attrib_array<f32, 3>(*m_program, location, vertex_data); break;
case 4: apply_attrib_array<f32, 4>(*m_program, location, vertex_data); break;
}
break;
default: size_t position = vertex_arrays_data.size();
LOG_ERROR(RSX, "bad non array vertex data format (type = %d, size = %d)", vertex_info.type, vertex_info.size); vertex_arrays_offsets[index] = position;
break;
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);
__glcheck m_program->attribs[location] =
(m_vao + vertex_arrays_offsets[index])
.config(gl_types[vertex_info.type], vertex_info.size, gl_normalized[vertex_info.type]);
}
else if (register_vertex_info[index].size > 0)
{
auto &vertex_data = register_vertex_data[index];
auto &vertex_info = register_vertex_info[index];
switch (vertex_info.type)
{
case CELL_GCM_VERTEX_F:
switch (register_vertex_info[index].size)
{
case 1: apply_attrib_array<f32, 1>(*m_program, location, vertex_data); break;
case 2: apply_attrib_array<f32, 2>(*m_program, location, vertex_data); break;
case 3: apply_attrib_array<f32, 3>(*m_program, location, vertex_data); break;
case 4: apply_attrib_array<f32, 4>(*m_program, location, vertex_data); break;
}
break;
default:
LOG_ERROR(RSX, "bad non array vertex data format (type = %d, size = %d)", vertex_info.type, vertex_info.size);
break;
}
} }
} }
} }
m_vbo.data(vertex_arrays_data.size(), vertex_arrays_data.data()); m_vbo.data(vertex_arrays_data.size(), vertex_arrays_data.data());
if (vertex_index_array.empty()) if (vertex_index_array.empty())
{ {
draw_fbo.draw_arrays(gl::draw_mode(draw_mode - 1), vertex_draw_count); draw_fbo.draw_arrays(gl::draw_mode(draw_mode - 1), vertex_draw_count);

View File

@ -175,6 +175,7 @@ namespace rsx
force_inline void draw_arrays(thread* rsx, u32 arg) force_inline void draw_arrays(thread* rsx, u32 arg)
{ {
rsx->draw_command = thread::Draw_command::draw_command_array;
u32 first = arg & 0xffffff; u32 first = arg & 0xffffff;
u32 count = (arg >> 24) + 1; u32 count = (arg >> 24) + 1;
@ -183,6 +184,7 @@ namespace rsx
force_inline void draw_index_array(thread* rsx, u32 arg) force_inline void draw_index_array(thread* rsx, u32 arg)
{ {
rsx->draw_command = thread::Draw_command::draw_command_indexed;
u32 first = arg & 0xffffff; u32 first = arg & 0xffffff;
u32 count = (arg >> 24) + 1; u32 count = (arg >> 24) + 1;
@ -190,6 +192,13 @@ namespace rsx
rsx->load_vertex_index_data(first, count); rsx->load_vertex_index_data(first, count);
} }
force_inline void draw_inline_array(thread* rsx, u32 arg)
{
rsx->draw_command = thread::Draw_command::draw_command_inlined_array;
rsx->draw_inline_vertex_array = true;
rsx->inline_vertex_array.push_back(arg);
}
template<u32 index> template<u32 index>
struct set_transform_constant struct set_transform_constant
{ {
@ -225,6 +234,8 @@ namespace rsx
{ {
if (arg) if (arg)
{ {
rsx->draw_inline_vertex_array = false;
rsx->inline_vertex_array.clear();
rsx->begin(); rsx->begin();
return; return;
} }
@ -774,6 +785,7 @@ namespace rsx
bind<NV4097_CLEAR_SURFACE>(); bind<NV4097_CLEAR_SURFACE>();
bind<NV4097_DRAW_ARRAYS, nv4097::draw_arrays>(); bind<NV4097_DRAW_ARRAYS, nv4097::draw_arrays>();
bind<NV4097_DRAW_INDEX_ARRAY, nv4097::draw_index_array>(); bind<NV4097_DRAW_INDEX_ARRAY, nv4097::draw_index_array>();
bind<NV4097_INLINE_ARRAY, nv4097::draw_inline_array>();
bind_range<NV4097_SET_VERTEX_DATA_ARRAY_FORMAT, 1, 16, nv4097::set_vertex_data_array_format>(); bind_range<NV4097_SET_VERTEX_DATA_ARRAY_FORMAT, 1, 16, nv4097::set_vertex_data_array_format>();
bind_range<NV4097_SET_VERTEX_DATA4UB_M, 1, 16, nv4097::set_vertex_data4ub_m>(); bind_range<NV4097_SET_VERTEX_DATA4UB_M, 1, 16, nv4097::set_vertex_data4ub_m>();
bind_range<NV4097_SET_VERTEX_DATA1F_M, 1, 16, nv4097::set_vertex_data1f_m>(); bind_range<NV4097_SET_VERTEX_DATA1F_M, 1, 16, nv4097::set_vertex_data1f_m>();
@ -1001,7 +1013,7 @@ namespace rsx
color_index_to_record = { 0, 1, 2, 3 }; color_index_to_record = { 0, 1, 2, 3 };
break; break;
} }
for (size_t i : color_index_to_record) /* for (size_t i : color_index_to_record)
{ {
draw_state.color_buffer[i].width = clip_w; draw_state.color_buffer[i].width = clip_w;
draw_state.color_buffer[i].height = clip_h; draw_state.color_buffer[i].height = clip_h;
@ -1018,7 +1030,7 @@ namespace rsx
draw_state.stencil.height = clip_h; draw_state.stencil.height = clip_h;
draw_state.stencil.data.resize(clip_w * clip_h * 4); draw_state.stencil.data.resize(clip_w * clip_h * 4);
copy_stencil_buffer_to_memory(draw_state.stencil.data.data()); copy_stencil_buffer_to_memory(draw_state.stencil.data.data());
} }*/
draw_state.programs = get_programs(); draw_state.programs = get_programs();
draw_state.name = name; draw_state.name = name;
frame_debug.draw_calls.push_back(draw_state); frame_debug.draw_calls.push_back(draw_state);
@ -1199,6 +1211,42 @@ namespace rsx
stream_vector_from_memory((char*)buffer + entry.first * 4 * sizeof(float), (void*)entry.second.rgba); stream_vector_from_memory((char*)buffer + entry.first * 4 * sizeof(float), (void*)entry.second.rgba);
} }
void thread::write_inline_array_to_buffer(void *dst_buffer)
{
u8* src = reinterpret_cast<u8*>(inline_vertex_array.data());
u8* dst = (u8*)dst_buffer;
size_t bytes_written = 0;
while (bytes_written < inline_vertex_array.size() * sizeof(u32))
{
for (int index = 0; index < rsx::limits::vertex_count; ++index)
{
const auto &info = vertex_arrays_info[index];
if (!info.size) // disabled
continue;
u32 type_size = rsx::get_vertex_type_size(info.type);
u32 element_size = type_size * info.size;
if (type_size == 1 && info.size == 4)
{
dst[0] = src[3];
dst[1] = src[2];
dst[2] = src[1];
dst[3] = src[0];
}
else
memcpy(dst, src, element_size);
src += element_size;
dst += element_size;
bytes_written += element_size;
}
}
}
u64 thread::timestamp() const u64 thread::timestamp() const
{ {
// Get timestamp, and convert it from microseconds to nanoseconds // Get timestamp, and convert it from microseconds to nanoseconds

View File

@ -413,11 +413,21 @@ namespace rsx
u32 ctxt_addr; u32 ctxt_addr;
u32 report_main_addr; u32 report_main_addr;
u32 label_addr; u32 label_addr;
enum class Draw_command
{
draw_command_array,
draw_command_inlined_array,
draw_command_indexed,
} draw_command;
u32 draw_mode; u32 draw_mode;
u32 local_mem_addr, main_mem_addr; u32 local_mem_addr, main_mem_addr;
bool strict_ordering[0x1000]; bool strict_ordering[0x1000];
bool draw_inline_vertex_array;
std::vector<u32> inline_vertex_array;
public: public:
u32 draw_array_count; u32 draw_array_count;
u32 draw_array_first; u32 draw_array_first;
@ -464,6 +474,13 @@ namespace rsx
*/ */
void fill_vertex_program_constants_data(void *buffer); void fill_vertex_program_constants_data(void *buffer);
/**
* Write inlined array data to buffer.
* The storage of inlined data looks different from memory stored arrays.
* There is no swapping required except for 4 u8 (according to Bleach Soul Resurection)
*/
void write_inline_array_to_buffer(void *dst_buffer);
/** /**
* Copy rtt values to buffer. * Copy rtt values to buffer.
* TODO: It's more efficient to combine multiple call of this function into one. * TODO: It's more efficient to combine multiple call of this function into one.