2020-12-05 13:08:24 +01:00
|
|
|
#include "stdafx.h"
|
2016-04-01 23:24:58 +02:00
|
|
|
#include "../Common/BufferUtils.h"
|
2020-12-13 12:54:43 +01:00
|
|
|
#include "../rsx_methods.h"
|
|
|
|
|
#include "GLGSRender.h"
|
2016-09-18 07:19:26 +02:00
|
|
|
#include "GLHelpers.h"
|
2016-04-01 23:24:58 +02:00
|
|
|
|
2016-08-26 16:23:23 +02:00
|
|
|
namespace
|
|
|
|
|
{
|
2021-01-12 11:01:06 +01:00
|
|
|
[[maybe_unused]] constexpr std::array<const char*, 16> s_reg_table =
|
2016-08-26 16:23:23 +02:00
|
|
|
{
|
|
|
|
|
"in_pos_buffer", "in_weight_buffer", "in_normal_buffer",
|
|
|
|
|
"in_diff_color_buffer", "in_spec_color_buffer",
|
|
|
|
|
"in_fog_buffer",
|
|
|
|
|
"in_point_size_buffer", "in_7_buffer",
|
|
|
|
|
"in_tc0_buffer", "in_tc1_buffer", "in_tc2_buffer", "in_tc3_buffer",
|
|
|
|
|
"in_tc4_buffer", "in_tc5_buffer", "in_tc6_buffer", "in_tc7_buffer"
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-01 23:24:58 +02:00
|
|
|
namespace
|
|
|
|
|
{
|
2016-06-12 11:05:22 +02:00
|
|
|
// return vertex count if primitive type is not native (empty array otherwise)
|
2018-10-01 22:05:51 +02:00
|
|
|
std::tuple<u32, u32> get_index_array_for_emulated_non_indexed_draw(rsx::primitive_type primitive_mode, gl::ring_buffer &dst, u32 vertex_count)
|
2016-04-01 23:24:58 +02:00
|
|
|
{
|
2018-10-01 22:05:51 +02:00
|
|
|
// This is an emulated buffer, so our indices only range from 0->original_vertex_array_length
|
|
|
|
|
const auto element_count = get_index_count(primitive_mode, vertex_count);
|
2020-12-09 08:47:45 +01:00
|
|
|
ensure(!gl::is_primitive_native(primitive_mode));
|
2016-04-01 23:24:58 +02:00
|
|
|
|
2017-06-26 23:34:22 +02:00
|
|
|
auto mapping = dst.alloc_from_heap(element_count * sizeof(u16), 256);
|
2019-12-03 23:34:23 +01:00
|
|
|
auto mapped_buffer = static_cast<char*>(mapping.first);
|
2016-06-12 11:05:22 +02:00
|
|
|
|
2017-06-26 23:34:22 +02:00
|
|
|
write_index_array_for_non_indexed_non_native_primitive_to_buffer(mapped_buffer, primitive_mode, vertex_count);
|
|
|
|
|
return std::make_tuple(element_count, mapping.second);
|
2016-04-01 23:24:58 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-10 16:52:35 +02:00
|
|
|
namespace
|
|
|
|
|
{
|
|
|
|
|
GLenum get_index_type(rsx::index_array_type type)
|
|
|
|
|
{
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case rsx::index_array_type::u16: return GL_UNSIGNED_SHORT;
|
|
|
|
|
case rsx::index_array_type::u32: return GL_UNSIGNED_INT;
|
|
|
|
|
}
|
2020-03-09 17:18:39 +01:00
|
|
|
fmt::throw_exception("Invalid index array type (%u)", static_cast<u8>(type));
|
2016-08-10 16:52:35 +02:00
|
|
|
}
|
2016-06-11 21:51:34 +02:00
|
|
|
|
2017-07-31 13:38:28 +02:00
|
|
|
struct vertex_input_state
|
2016-08-10 16:52:35 +02:00
|
|
|
{
|
2019-01-21 19:07:27 +01:00
|
|
|
bool index_rebase;
|
|
|
|
|
u32 min_index;
|
|
|
|
|
u32 max_index;
|
2017-07-31 13:38:28 +02:00
|
|
|
u32 vertex_draw_count;
|
2019-01-14 13:33:05 +01:00
|
|
|
u32 vertex_index_offset;
|
2017-07-31 13:38:28 +02:00
|
|
|
std::optional<std::tuple<GLenum, u32>> index_info;
|
2016-08-21 19:17:09 +02:00
|
|
|
};
|
|
|
|
|
|
2016-08-28 17:00:02 +02:00
|
|
|
struct draw_command_visitor
|
2016-08-21 19:17:09 +02:00
|
|
|
{
|
2017-07-31 13:38:28 +02:00
|
|
|
draw_command_visitor(gl::ring_buffer& index_ring_buffer, rsx::vertex_input_layout& vertex_layout)
|
2020-12-18 18:35:02 +01:00
|
|
|
: m_index_ring_buffer(index_ring_buffer)
|
2017-07-31 13:38:28 +02:00
|
|
|
, m_vertex_layout(vertex_layout)
|
|
|
|
|
{}
|
2016-07-09 16:21:06 +02:00
|
|
|
|
2021-03-05 20:05:37 +01:00
|
|
|
vertex_input_state operator()(const rsx::draw_array_command& /*command*/)
|
2016-08-28 17:00:02 +02:00
|
|
|
{
|
2017-08-04 23:11:14 +02:00
|
|
|
const u32 vertex_count = rsx::method_registers.current_draw_clause.get_elements_count();
|
2018-09-24 15:03:25 +02:00
|
|
|
const u32 min_index = rsx::method_registers.current_draw_clause.min_index();
|
2019-01-21 19:07:27 +01:00
|
|
|
const u32 max_index = (min_index + vertex_count) - 1;
|
2016-06-11 21:51:34 +02:00
|
|
|
|
2017-07-31 13:38:28 +02:00
|
|
|
if (!gl::is_primitive_native(rsx::method_registers.current_draw_clause.primitive))
|
|
|
|
|
{
|
2016-08-28 17:00:02 +02:00
|
|
|
u32 index_count;
|
|
|
|
|
u32 offset_in_index_buffer;
|
|
|
|
|
std::tie(index_count, offset_in_index_buffer) = get_index_array_for_emulated_non_indexed_draw(
|
2020-12-18 18:35:02 +01:00
|
|
|
rsx::method_registers.current_draw_clause.primitive, m_index_ring_buffer,
|
2018-10-01 22:05:51 +02:00
|
|
|
rsx::method_registers.current_draw_clause.get_elements_count());
|
2016-04-01 23:24:58 +02:00
|
|
|
|
2019-01-21 19:07:27 +01:00
|
|
|
return{ false, min_index, max_index, index_count, 0, std::make_tuple(static_cast<GLenum>(GL_UNSIGNED_SHORT), offset_in_index_buffer) };
|
2016-08-28 17:00:02 +02:00
|
|
|
}
|
2016-04-01 23:24:58 +02:00
|
|
|
|
2019-01-21 19:07:27 +01:00
|
|
|
return{ false, min_index, max_index, vertex_count, 0, std::optional<std::tuple<GLenum, u32>>() };
|
2016-08-10 16:52:35 +02:00
|
|
|
}
|
2016-04-01 23:24:58 +02:00
|
|
|
|
2017-07-31 13:38:28 +02:00
|
|
|
vertex_input_state operator()(const rsx::draw_indexed_array_command& command)
|
2016-08-28 17:00:02 +02:00
|
|
|
{
|
|
|
|
|
u32 min_index = 0, max_index = 0;
|
|
|
|
|
|
2017-03-28 12:41:45 +02:00
|
|
|
rsx::index_array_type type = rsx::method_registers.current_draw_clause.is_immediate_draw?
|
|
|
|
|
rsx::index_array_type::u32:
|
|
|
|
|
rsx::method_registers.index_type();
|
2019-12-03 23:34:23 +01:00
|
|
|
|
2019-10-21 21:59:34 +02:00
|
|
|
u32 type_size = get_index_type_size(type);
|
2016-08-28 17:00:02 +02:00
|
|
|
|
2017-07-31 13:38:28 +02:00
|
|
|
const u32 vertex_count = rsx::method_registers.current_draw_clause.get_elements_count();
|
2016-09-29 09:16:00 +02:00
|
|
|
u32 index_count = vertex_count;
|
2019-12-03 23:34:23 +01:00
|
|
|
|
2016-09-29 09:16:00 +02:00
|
|
|
if (!gl::is_primitive_native(rsx::method_registers.current_draw_clause.primitive))
|
2019-12-03 23:34:23 +01:00
|
|
|
index_count = static_cast<u32>(get_index_count(rsx::method_registers.current_draw_clause.primitive, vertex_count));
|
2016-04-01 23:24:58 +02:00
|
|
|
|
2019-01-14 13:33:05 +01:00
|
|
|
u32 max_size = index_count * type_size;
|
2016-10-18 09:57:28 +02:00
|
|
|
auto mapping = m_index_ring_buffer.alloc_from_heap(max_size, 256);
|
2016-08-28 17:00:02 +02:00
|
|
|
void* ptr = mapping.first;
|
|
|
|
|
u32 offset_in_index_buffer = mapping.second;
|
2016-04-01 23:24:58 +02:00
|
|
|
|
2019-01-14 13:33:05 +01:00
|
|
|
std::tie(min_index, max_index, index_count) = write_index_array_data_to_buffer(
|
2019-11-09 15:17:41 +01:00
|
|
|
{ reinterpret_cast<std::byte*>(ptr), max_size },
|
2019-01-14 13:33:05 +01:00
|
|
|
command.raw_index_buffer, type,
|
|
|
|
|
rsx::method_registers.current_draw_clause.primitive,
|
|
|
|
|
rsx::method_registers.restart_index_enabled(),
|
|
|
|
|
rsx::method_registers.restart_index(),
|
|
|
|
|
[](auto prim) { return !gl::is_primitive_native(prim); });
|
2016-08-10 16:52:35 +02:00
|
|
|
|
2018-01-01 09:43:06 +01:00
|
|
|
if (min_index >= max_index)
|
|
|
|
|
{
|
|
|
|
|
//empty set, do not draw
|
2019-01-21 19:07:27 +01:00
|
|
|
return{ false, 0, 0, 0, 0, std::make_tuple(get_index_type(type), offset_in_index_buffer) };
|
2018-01-01 09:43:06 +01:00
|
|
|
}
|
|
|
|
|
|
2019-01-21 19:07:27 +01:00
|
|
|
// Prefer only reading the vertices that are referenced in the index buffer itself
|
|
|
|
|
// Offset data source by min_index verts, but also notify the shader to offset the vertexID (important for modulo op)
|
2019-01-14 13:33:05 +01:00
|
|
|
const auto index_offset = rsx::method_registers.vertex_data_base_index();
|
2019-01-21 19:07:27 +01:00
|
|
|
return{ true, min_index, max_index, index_count, index_offset, std::make_tuple(get_index_type(type), offset_in_index_buffer) };
|
2016-08-28 17:00:02 +02:00
|
|
|
}
|
2016-08-10 16:52:35 +02:00
|
|
|
|
2021-03-05 20:05:37 +01:00
|
|
|
vertex_input_state operator()(const rsx::draw_inlined_array& /*command*/)
|
2016-08-10 16:52:35 +02:00
|
|
|
{
|
2018-09-24 15:03:25 +02:00
|
|
|
const auto stream_length = rsx::method_registers.current_draw_clause.inline_vertex_array.size();
|
|
|
|
|
const u32 vertex_count = u32(stream_length * sizeof(u32)) / m_vertex_layout.interleaved_blocks[0].attribute_stride;
|
2016-08-28 17:00:02 +02:00
|
|
|
|
2017-07-31 13:38:28 +02:00
|
|
|
if (!gl::is_primitive_native(rsx::method_registers.current_draw_clause.primitive))
|
|
|
|
|
{
|
2016-08-28 17:00:02 +02:00
|
|
|
u32 offset_in_index_buffer;
|
|
|
|
|
u32 index_count;
|
|
|
|
|
std::tie(index_count, offset_in_index_buffer) = get_index_array_for_emulated_non_indexed_draw(
|
2018-10-01 22:05:51 +02:00
|
|
|
rsx::method_registers.current_draw_clause.primitive, m_index_ring_buffer, vertex_count);
|
2017-07-31 13:38:28 +02:00
|
|
|
|
2019-01-23 23:16:35 +01:00
|
|
|
return{ false, 0, vertex_count, index_count, 0, std::make_tuple(static_cast<GLenum>(GL_UNSIGNED_SHORT), offset_in_index_buffer) };
|
2016-04-01 23:24:58 +02:00
|
|
|
}
|
2017-07-31 13:38:28 +02:00
|
|
|
|
2019-01-23 23:16:35 +01:00
|
|
|
return{ false, 0, vertex_count, vertex_count, 0, std::optional<std::tuple<GLenum, u32>>() };
|
2016-08-28 17:00:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
gl::ring_buffer& m_index_ring_buffer;
|
2017-07-31 13:38:28 +02:00
|
|
|
rsx::vertex_input_layout& m_vertex_layout;
|
|
|
|
|
};
|
|
|
|
|
}
|
2016-08-28 17:00:02 +02:00
|
|
|
|
2018-02-21 18:50:27 +01:00
|
|
|
gl::vertex_upload_info GLGSRender::set_vertex_buffer()
|
2017-07-31 13:38:28 +02:00
|
|
|
{
|
2019-06-18 20:31:35 +02:00
|
|
|
m_profiler.start();
|
2016-08-28 17:00:02 +02:00
|
|
|
|
2017-07-31 13:38:28 +02:00
|
|
|
//Write index buffers and count verts
|
2018-08-29 19:20:52 +02:00
|
|
|
auto result = std::visit(draw_command_visitor(*m_index_ring_buffer, m_vertex_layout), get_draw_command(rsx::method_registers));
|
2016-08-28 17:00:02 +02:00
|
|
|
|
2019-01-21 19:07:27 +01:00
|
|
|
const u32 vertex_count = (result.max_index - result.min_index) + 1;
|
|
|
|
|
u32 vertex_base = result.min_index;
|
|
|
|
|
u32 index_base = 0;
|
|
|
|
|
|
|
|
|
|
if (result.index_rebase)
|
|
|
|
|
{
|
|
|
|
|
vertex_base = rsx::get_index_from_base(vertex_base, rsx::method_registers.vertex_data_base_index());
|
|
|
|
|
index_base = result.min_index;
|
|
|
|
|
}
|
2016-08-28 17:00:02 +02:00
|
|
|
|
2017-07-31 13:38:28 +02:00
|
|
|
//Do actual vertex upload
|
2019-01-21 19:07:27 +01:00
|
|
|
auto required = calculate_memory_requirements(m_vertex_layout, vertex_base, vertex_count);
|
2016-08-28 17:00:02 +02:00
|
|
|
|
2017-07-31 13:38:28 +02:00
|
|
|
std::pair<void*, u32> persistent_mapping = {}, volatile_mapping = {};
|
2019-01-14 13:33:05 +01:00
|
|
|
gl::vertex_upload_info upload_info =
|
|
|
|
|
{
|
|
|
|
|
result.vertex_draw_count, // Vertex count
|
2019-01-21 19:07:27 +01:00
|
|
|
vertex_count, // Allocated vertex count
|
|
|
|
|
vertex_base, // First vertex in block
|
|
|
|
|
index_base, // Index of attribute at data location 0
|
2019-01-14 13:33:05 +01:00
|
|
|
result.vertex_index_offset, // Hw index offset
|
|
|
|
|
0u, 0u, // Mapping
|
|
|
|
|
result.index_info // Index buffer info
|
|
|
|
|
};
|
2016-08-28 17:00:02 +02:00
|
|
|
|
2017-07-31 13:38:28 +02:00
|
|
|
if (required.first > 0)
|
|
|
|
|
{
|
|
|
|
|
//Check if cacheable
|
|
|
|
|
//Only data in the 'persistent' block may be cached
|
|
|
|
|
//TODO: make vertex cache keep local data beyond frame boundaries and hook notify command
|
|
|
|
|
bool in_cache = false;
|
|
|
|
|
bool to_store = false;
|
2021-05-22 20:46:10 +02:00
|
|
|
u32 storage_address = -1;
|
2017-07-31 13:38:28 +02:00
|
|
|
|
|
|
|
|
if (m_vertex_layout.interleaved_blocks.size() == 1 &&
|
|
|
|
|
rsx::method_registers.current_draw_clause.command != rsx::draw_command::inlined_array)
|
|
|
|
|
{
|
2019-01-14 13:33:05 +01:00
|
|
|
const auto data_offset = (vertex_base * m_vertex_layout.interleaved_blocks[0].attribute_stride);
|
|
|
|
|
storage_address = m_vertex_layout.interleaved_blocks[0].real_offset_address + data_offset;
|
|
|
|
|
|
2017-07-31 13:38:28 +02:00
|
|
|
if (auto cached = m_vertex_cache->find_vertex_range(storage_address, GL_R8UI, required.first))
|
|
|
|
|
{
|
2020-12-09 08:47:45 +01:00
|
|
|
ensure(cached->local_address == storage_address);
|
2018-10-01 22:05:51 +02:00
|
|
|
|
2017-07-31 13:38:28 +02:00
|
|
|
in_cache = true;
|
2018-01-21 16:31:35 +01:00
|
|
|
upload_info.persistent_mapping_offset = cached->offset_in_heap;
|
2017-07-31 13:38:28 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
to_store = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-08-28 17:00:02 +02:00
|
|
|
|
2017-07-31 13:38:28 +02:00
|
|
|
if (!in_cache)
|
|
|
|
|
{
|
|
|
|
|
persistent_mapping = m_attrib_ring_buffer->alloc_from_heap(required.first, m_min_texbuffer_alignment);
|
2018-01-21 16:31:35 +01:00
|
|
|
upload_info.persistent_mapping_offset = persistent_mapping.second;
|
2016-08-28 17:00:02 +02:00
|
|
|
|
2017-07-31 13:38:28 +02:00
|
|
|
if (to_store)
|
|
|
|
|
{
|
|
|
|
|
//store ref in vertex cache
|
|
|
|
|
m_vertex_cache->store_range(storage_address, GL_R8UI, required.first, persistent_mapping.second);
|
2016-08-28 17:00:02 +02:00
|
|
|
}
|
|
|
|
|
}
|
2018-02-22 09:13:01 +01:00
|
|
|
|
|
|
|
|
if (!m_persistent_stream_view.in_range(upload_info.persistent_mapping_offset, required.first, upload_info.persistent_mapping_offset))
|
|
|
|
|
{
|
2020-12-09 08:47:45 +01:00
|
|
|
ensure(m_max_texbuffer_size < m_attrib_ring_buffer->size());
|
2020-12-18 08:39:54 +01:00
|
|
|
const usz view_size = ((upload_info.persistent_mapping_offset + m_max_texbuffer_size) > m_attrib_ring_buffer->size()) ?
|
2018-02-22 09:13:01 +01:00
|
|
|
(m_attrib_ring_buffer->size() - upload_info.persistent_mapping_offset) : m_max_texbuffer_size;
|
|
|
|
|
|
2019-12-03 23:34:23 +01:00
|
|
|
m_persistent_stream_view.update(m_attrib_ring_buffer.get(), upload_info.persistent_mapping_offset, static_cast<u32>(view_size));
|
2018-04-07 12:19:49 +02:00
|
|
|
m_gl_persistent_stream_buffer->copy_from(m_persistent_stream_view);
|
2018-02-22 09:13:01 +01:00
|
|
|
upload_info.persistent_mapping_offset = 0;
|
|
|
|
|
}
|
2017-07-31 13:38:28 +02:00
|
|
|
}
|
2016-08-28 17:00:02 +02:00
|
|
|
|
2017-07-31 13:38:28 +02:00
|
|
|
if (required.second > 0)
|
|
|
|
|
{
|
|
|
|
|
volatile_mapping = m_attrib_ring_buffer->alloc_from_heap(required.second, m_min_texbuffer_alignment);
|
2018-01-21 16:31:35 +01:00
|
|
|
upload_info.volatile_mapping_offset = volatile_mapping.second;
|
2018-02-22 09:13:01 +01:00
|
|
|
|
|
|
|
|
if (!m_volatile_stream_view.in_range(upload_info.volatile_mapping_offset, required.second, upload_info.volatile_mapping_offset))
|
|
|
|
|
{
|
2020-12-09 08:47:45 +01:00
|
|
|
ensure(m_max_texbuffer_size < m_attrib_ring_buffer->size());
|
2020-12-18 08:39:54 +01:00
|
|
|
const usz view_size = ((upload_info.volatile_mapping_offset + m_max_texbuffer_size) > m_attrib_ring_buffer->size()) ?
|
2018-02-22 09:13:01 +01:00
|
|
|
(m_attrib_ring_buffer->size() - upload_info.volatile_mapping_offset) : m_max_texbuffer_size;
|
|
|
|
|
|
2019-12-03 23:34:23 +01:00
|
|
|
m_volatile_stream_view.update(m_attrib_ring_buffer.get(), upload_info.volatile_mapping_offset, static_cast<u32>(view_size));
|
2018-04-07 12:19:49 +02:00
|
|
|
m_gl_volatile_stream_buffer->copy_from(m_volatile_stream_view);
|
2018-02-22 09:13:01 +01:00
|
|
|
upload_info.volatile_mapping_offset = 0;
|
|
|
|
|
}
|
2017-07-31 13:38:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Write all the data
|
|
|
|
|
write_vertex_data_to_memory(m_vertex_layout, vertex_base, vertex_count, persistent_mapping.first, volatile_mapping.first);
|
2016-10-11 02:55:42 +02:00
|
|
|
|
2019-09-19 19:08:06 +02:00
|
|
|
m_frame_stats.vertex_upload_time += m_profiler.duration();
|
2018-01-21 16:31:35 +01:00
|
|
|
return upload_info;
|
2016-08-05 08:38:58 +02:00
|
|
|
}
|