1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-25 12:12:50 +01:00

gl: Refactor vertex_buffer.cpp

This commit is contained in:
Vincent Lejeune 2016-08-10 16:52:35 +02:00
parent a94b9d38b0
commit b8721b6475
3 changed files with 253 additions and 228 deletions

View File

@ -487,7 +487,9 @@ void GLGSRender::end()
}
}
u32 offset_in_index_buffer = set_vertex_buffer();
u32 vertex_draw_count;
std::optional<std::tuple<GLenum, u32> > indexed_draw_info;
std::tie(vertex_draw_count, indexed_draw_info) = set_vertex_buffer();
m_vao.bind();
std::chrono::time_point<std::chrono::system_clock> then = std::chrono::system_clock::now();
@ -497,26 +499,9 @@ void GLGSRender::end()
m_program->validate();
}
if (rsx::method_registers.current_draw_clause.command == rsx::draw_command::indexed)
if (indexed_draw_info)
{
rsx::index_array_type indexed_type = rsx::method_registers.index_type();
if (indexed_type == rsx::index_array_type::u32)
{
__glcheck glDrawElements(gl::draw_mode(rsx::method_registers.current_draw_clause.primitive), vertex_draw_count, GL_UNSIGNED_INT, (GLvoid *)(std::ptrdiff_t)offset_in_index_buffer);
}
else if (indexed_type == rsx::index_array_type::u16)
{
__glcheck glDrawElements(gl::draw_mode(rsx::method_registers.current_draw_clause.primitive), vertex_draw_count, GL_UNSIGNED_SHORT, (GLvoid *)(std::ptrdiff_t)offset_in_index_buffer);
}
else
{
throw std::logic_error("bad index array type");
}
}
else if (!gl::is_primitive_native(rsx::method_registers.current_draw_clause.primitive))
{
__glcheck glDrawElements(gl::draw_mode(rsx::method_registers.current_draw_clause.primitive), vertex_draw_count, GL_UNSIGNED_SHORT, (GLvoid *)(std::ptrdiff_t)offset_in_index_buffer);
__glcheck glDrawElements(gl::draw_mode(rsx::method_registers.current_draw_clause.primitive), vertex_draw_count, std::get<0>(indexed_draw_info.value()), (GLvoid *)(std::ptrdiff_t)std::get<1>(indexed_draw_info.value()));
}
else
{

View File

@ -4,6 +4,7 @@
#include "rsx_gl_texture.h"
#include "gl_texture_cache.h"
#include "gl_render_targets.h"
#include <Utilities/optional.hpp>
#define RSX_DEBUG 1
@ -56,7 +57,14 @@ public:
private:
static u32 enable(u32 enable, u32 cap);
static u32 enable(u32 enable, u32 cap, u32 index);
u32 set_vertex_buffer();
// Return element to draw and in case of indexed draw index type and offset in index buffer
std::tuple<u32, std::optional<std::tuple<GLenum, u32> > > set_vertex_buffer();
void upload_vertex_buffers(const u32 &max_index, const u32 &max_vertex_attrib_size, const u32 &input_mask, const u32 &texture_index_offset);
// Returns vertex count
u32 upload_inline_array(const u32 &max_vertex_attrib_size, const u32 &texture_index_offset);
public:
bool load_program();

View File

@ -172,7 +172,20 @@ namespace
}
}
u32 GLGSRender::set_vertex_buffer()
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;
}
throw;
}
}
std::tuple<u32, std::optional<std::tuple<GLenum, u32> > > GLGSRender::set_vertex_buffer()
{
//initialize vertex attributes
//merge all vertex arrays
@ -184,12 +197,7 @@ u32 GLGSRender::set_vertex_buffer()
u32 input_mask = rsx::method_registers.vertex_attrib_input_mask();
u32 min_index = 0, max_index = 0;
u32 max_vertex_attrib_size = 0;
u32 offset_in_index_buffer = 0;
vertex_draw_count = 0;
//place holder; replace with actual index buffer
gsl::span<gsl::byte> index_array;
u32 vertex_or_index_count;
for (u8 index = 0; index < rsx::limits::vertex_count; ++index)
{
@ -199,225 +207,249 @@ u32 GLGSRender::set_vertex_buffer()
}
}
std::optional<std::tuple<GLenum, u32> > index_info;
if (rsx::method_registers.current_draw_clause.command == rsx::draw_command::indexed)
{
rsx::index_array_type type = rsx::method_registers.index_type();
u32 type_size = ::narrow<u32>(get_index_type_size(type));
vertex_draw_count += rsx::method_registers.current_draw_clause.get_elements_count();
vertex_or_index_count = get_index_count(rsx::method_registers.current_draw_clause.primitive, rsx::method_registers.current_draw_clause.get_elements_count());
u32 max_size = get_index_count(rsx::method_registers.current_draw_clause.primitive, vertex_draw_count) * type_size;
u32 max_size = vertex_or_index_count * type_size;
auto mapping = m_index_ring_buffer.alloc_and_map(max_size);
void *ptr = mapping.first;
offset_in_index_buffer = mapping.second;
u32 offset_in_index_buffer = mapping.second;
std::tie(min_index, max_index, vertex_draw_count) = upload_index_buffer(get_raw_index_array(rsx::method_registers.current_draw_clause.first_count_commands), ptr, type, rsx::method_registers.current_draw_clause.primitive, rsx::method_registers.current_draw_clause.first_count_commands, vertex_draw_count);
std::tie(min_index, max_index, vertex_or_index_count) = upload_index_buffer(get_raw_index_array(rsx::method_registers.current_draw_clause.first_count_commands), ptr, type, rsx::method_registers.current_draw_clause.primitive, rsx::method_registers.current_draw_clause.first_count_commands, vertex_or_index_count);
m_index_ring_buffer.unmap();
index_info = std::make_tuple(get_index_type(type), offset_in_index_buffer);
}
else
{
u32 vertex_count;
if (rsx::method_registers.current_draw_clause.command == rsx::draw_command::inlined_array)
{
// We need to go through array to determine vertex count so upload it
vertex_count = upload_inline_array(max_vertex_attrib_size, texture_index_offset);
}
else
{
assert(rsx::method_registers.current_draw_clause.command == rsx::draw_command::array);
vertex_count = rsx::method_registers.current_draw_clause.get_elements_count();
max_index = vertex_count - 1;
}
if (!gl::is_primitive_native(rsx::method_registers.current_draw_clause.primitive))
{
u32 offset_in_index_buffer;
std::tie(vertex_or_index_count, offset_in_index_buffer) = get_index_array_for_emulated_non_indexed_draw(rsx::method_registers.current_draw_clause.first_count_commands, rsx::method_registers.current_draw_clause.primitive, m_index_ring_buffer);
index_info = std::make_tuple(static_cast<GLenum>(GL_UNSIGNED_SHORT), offset_in_index_buffer);
}
else
{
vertex_or_index_count = vertex_count;
}
}
if (rsx::method_registers.current_draw_clause.command == rsx::draw_command::inlined_array)
{
u32 stride = 0;
u32 offsets[rsx::limits::vertex_count] = { 0 };
for (u32 i = 0; i < rsx::limits::vertex_count; ++i)
{
const auto &info = rsx::method_registers.vertex_arrays_info[i];
if (!info.size) continue;
offsets[i] = stride;
stride += rsx::get_vertex_type_size_on_host(info.type, info.size);
}
vertex_draw_count = (u32)(inline_vertex_array.size() * sizeof(u32)) / stride;
m_attrib_ring_buffer.reserve_and_map(vertex_draw_count * max_vertex_attrib_size);
for (int index = 0; index < rsx::limits::vertex_count; ++index)
{
auto &vertex_info = rsx::method_registers.vertex_arrays_info[index];
int location;
if (!m_program->uniforms.has_location(rsx::vertex_program::input_attrib_names[index] + "_buffer", &location))
continue;
if (!vertex_info.size) // disabled, bind a null sampler
{
glActiveTexture(GL_TEXTURE0 + index + texture_index_offset);
glBindTexture(GL_TEXTURE_BUFFER, 0);
glProgramUniform1i(m_program->id(), location, index + texture_index_offset);
continue;
}
const u32 element_size = rsx::get_vertex_type_size_on_host(vertex_info.type, vertex_info.size);
u32 data_size = element_size * vertex_draw_count;
u32 gl_type = to_gl_internal_type(vertex_info.type, vertex_info.size);
auto &texture = m_gl_attrib_buffers[index];
u8 *src = reinterpret_cast<u8*>(inline_vertex_array.data());
auto mapping = m_attrib_ring_buffer.alloc_from_reserve(data_size, m_min_texbuffer_alignment);
u8 *dst = static_cast<u8*>(mapping.first);
src += offsets[index];
prepare_buffer_for_writing(dst, vertex_info.type, vertex_info.size, vertex_draw_count);
//TODO: properly handle compressed data
for (u32 i = 0; i < vertex_draw_count; ++i)
{
if (vertex_info.type == rsx::vertex_base_type::ub && vertex_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 += stride;
dst += element_size;
}
texture.copy_from(m_attrib_ring_buffer, gl_type, mapping.second, data_size);
//Link texture to uniform
m_program->uniforms.texture(location, index + texture_index_offset, texture);
if (!gl::is_primitive_native(rsx::method_registers.current_draw_clause.primitive))
{
std::tie(vertex_draw_count, offset_in_index_buffer) = get_index_array_for_emulated_non_indexed_draw({ { 0, vertex_draw_count } }, rsx::method_registers.current_draw_clause.primitive, m_index_ring_buffer);
}
}
// Already uploaded when determining vertex count, we can return here
return std::make_tuple(vertex_or_index_count, index_info);
}
if (rsx::method_registers.current_draw_clause.command == rsx::draw_command::array)
{
vertex_draw_count += rsx::method_registers.current_draw_clause.get_elements_count();
}
upload_vertex_buffers(max_index, max_vertex_attrib_size, input_mask, texture_index_offset);
if (rsx::method_registers.current_draw_clause.command == rsx::draw_command::array || rsx::method_registers.current_draw_clause.command == rsx::draw_command::indexed)
{
u32 verts_allocated = std::max(vertex_draw_count, max_index + 1);
__glcheck m_attrib_ring_buffer.reserve_and_map(verts_allocated * max_vertex_attrib_size);
for (int index = 0; index < rsx::limits::vertex_count; ++index)
{
int location;
if (!m_program->uniforms.has_location(rsx::vertex_program::input_attrib_names[index] + "_buffer", &location))
continue;
bool enabled = !!(input_mask & (1 << index));
if (!enabled)
{
glActiveTexture(GL_TEXTURE0 + index + texture_index_offset);
glBindTexture(GL_TEXTURE_BUFFER, 0);
glProgramUniform1i(m_program->id(), location, index + texture_index_offset);
continue;
}
if (rsx::method_registers.vertex_arrays_info[index].size > 0)
{
auto &vertex_info = rsx::method_registers.vertex_arrays_info[index];
// 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);
u32 data_size = vertex_draw_count * element_size;
u32 gl_type = to_gl_internal_type(vertex_info.type, vertex_info.size);
auto &texture = m_gl_attrib_buffers[index];
u32 buffer_offset = 0;
// Get source pointer
u32 base_offset = rsx::method_registers.vertex_data_base_offset();
u32 offset = rsx::method_registers.vertex_arrays_info[index].offset();
u32 address = base_offset + rsx::get_address(offset & 0x7fffffff, offset >> 31);
const gsl::byte *src_ptr = gsl::narrow_cast<const gsl::byte*>(vm::base(address));
if (rsx::method_registers.current_draw_clause.command == rsx::draw_command::array)
{
auto mapping = m_attrib_ring_buffer.alloc_from_reserve(data_size, m_min_texbuffer_alignment);
gsl::byte *dst = static_cast<gsl::byte*>(mapping.first);
buffer_offset = mapping.second;
size_t offset = 0;
gsl::span<gsl::byte> dest_span(dst, data_size);
prepare_buffer_for_writing(dst, vertex_info.type, vertex_info.size, vertex_draw_count);
for (const auto &first_count : rsx::method_registers.current_draw_clause.first_count_commands)
{
write_vertex_array_data_to_buffer(dest_span.subspan(offset), src_ptr, first_count.first, first_count.second, vertex_info.type, vertex_info.size, vertex_info.stride, rsx::get_vertex_type_size_on_host(vertex_info.type, vertex_info.size));
offset += first_count.second * element_size;
}
}
if (rsx::method_registers.current_draw_clause.command == rsx::draw_command::indexed)
{
data_size = (max_index + 1) * element_size;
auto mapping = m_attrib_ring_buffer.alloc_from_reserve(data_size, m_min_texbuffer_alignment);
gsl::byte *dst = static_cast<gsl::byte*>(mapping.first);
buffer_offset = mapping.second;
gsl::span<gsl::byte> dest_span(dst, data_size);
prepare_buffer_for_writing(dst, vertex_info.type, vertex_info.size, vertex_draw_count);
write_vertex_array_data_to_buffer(dest_span, src_ptr, 0, max_index + 1, vertex_info.type, vertex_info.size, vertex_info.stride, rsx::get_vertex_type_size_on_host(vertex_info.type, vertex_info.size));
}
texture.copy_from(m_attrib_ring_buffer, gl_type, buffer_offset, data_size);
//Link texture to uniform
m_program->uniforms.texture(location, index + texture_index_offset, texture);
}
else if (rsx::method_registers.register_vertex_info[index].size > 0)
{
auto &vertex_info = rsx::method_registers.register_vertex_info[index];
switch (vertex_info.type)
{
case rsx::vertex_base_type::f:
{
const u32 element_size = rsx::get_vertex_type_size_on_host(vertex_info.type, vertex_info.size);
const u32 gl_type = to_gl_internal_type(vertex_info.type, vertex_info.size);
const size_t data_size = element_size;
auto &texture = m_gl_attrib_buffers[index];
auto mapping = m_attrib_ring_buffer.alloc_from_reserve(data_size, m_min_texbuffer_alignment);
u8 *dst = static_cast<u8*>(mapping.first);
memcpy(dst, vertex_info.data.data(), element_size);
texture.copy_from(m_attrib_ring_buffer, gl_type, mapping.second, data_size);
//Link texture to uniform
m_program->uniforms.texture(location, index + texture_index_offset, texture);
break;
}
default:
LOG_ERROR(RSX, "bad non array vertex data format (type=%d, size=%d)", (u32)vertex_info.type, vertex_info.size);
break;
}
}
else
{
glActiveTexture(GL_TEXTURE0 + index + texture_index_offset);
glBindTexture(GL_TEXTURE_BUFFER, 0);
glProgramUniform1i(m_program->id(), location, index + texture_index_offset);
continue;
}
}
if (rsx::method_registers.current_draw_clause.command == rsx::draw_command::array && !gl::is_primitive_native(rsx::method_registers.current_draw_clause.primitive))
{
std::tie(vertex_draw_count, offset_in_index_buffer) = get_index_array_for_emulated_non_indexed_draw(rsx::method_registers.current_draw_clause.first_count_commands, rsx::method_registers.current_draw_clause.primitive, m_index_ring_buffer);
}
}
m_attrib_ring_buffer.unmap();
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
m_vertex_upload_time += std::chrono::duration_cast<std::chrono::microseconds>(now - then).count();
return offset_in_index_buffer;
return std::make_tuple(vertex_or_index_count, index_info);
}
void GLGSRender::upload_vertex_buffers(const u32 &max_index, const u32 &max_vertex_attrib_size, const u32 &input_mask, const u32 &texture_index_offset)
{
u32 verts_allocated = max_index + 1;
__glcheck m_attrib_ring_buffer.reserve_and_map(verts_allocated * max_vertex_attrib_size);
for (int index = 0; index < rsx::limits::vertex_count; ++index)
{
int location;
if (!m_program->uniforms.has_location(rsx::vertex_program::input_attrib_names[index] + "_buffer", &location))
continue;
bool enabled = !!(input_mask & (1 << index));
if (!enabled)
{
glActiveTexture(GL_TEXTURE0 + index + texture_index_offset);
glBindTexture(GL_TEXTURE_BUFFER, 0);
glProgramUniform1i(m_program->id(), location, index + texture_index_offset);
continue;
}
if (rsx::method_registers.vertex_arrays_info[index].size > 0)
{
auto &vertex_info = rsx::method_registers.vertex_arrays_info[index];
// 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);
u32 data_size = verts_allocated * element_size;
u32 gl_type = to_gl_internal_type(vertex_info.type, vertex_info.size);
auto &texture = m_gl_attrib_buffers[index];
u32 buffer_offset = 0;
// Get source pointer
u32 base_offset = rsx::method_registers.vertex_data_base_offset();
u32 offset = rsx::method_registers.vertex_arrays_info[index].offset();
u32 address = base_offset + rsx::get_address(offset & 0x7fffffff, offset >> 31);
const gsl::byte *src_ptr = gsl::narrow_cast<const gsl::byte*>(vm::base(address));
if (rsx::method_registers.current_draw_clause.command == rsx::draw_command::array)
{
auto mapping = m_attrib_ring_buffer.alloc_from_reserve(data_size, m_min_texbuffer_alignment);
gsl::byte *dst = static_cast<gsl::byte*>(mapping.first);
buffer_offset = mapping.second;
size_t offset = 0;
gsl::span<gsl::byte> dest_span(dst, data_size);
prepare_buffer_for_writing(dst, vertex_info.type, vertex_info.size, verts_allocated);
for (const auto &first_count : rsx::method_registers.current_draw_clause.first_count_commands)
{
write_vertex_array_data_to_buffer(dest_span.subspan(offset), src_ptr, first_count.first, first_count.second, vertex_info.type, vertex_info.size, vertex_info.stride, rsx::get_vertex_type_size_on_host(vertex_info.type, vertex_info.size));
offset += first_count.second * element_size;
}
}
if (rsx::method_registers.current_draw_clause.command == rsx::draw_command::indexed)
{
data_size = (max_index + 1) * element_size;
auto mapping = m_attrib_ring_buffer.alloc_from_reserve(data_size, m_min_texbuffer_alignment);
gsl::byte *dst = static_cast<gsl::byte*>(mapping.first);
buffer_offset = mapping.second;
gsl::span<gsl::byte> dest_span(dst, data_size);
prepare_buffer_for_writing(dst, vertex_info.type, vertex_info.size, verts_allocated);
write_vertex_array_data_to_buffer(dest_span, src_ptr, 0, max_index + 1, vertex_info.type, vertex_info.size, vertex_info.stride, rsx::get_vertex_type_size_on_host(vertex_info.type, vertex_info.size));
}
texture.copy_from(m_attrib_ring_buffer, gl_type, buffer_offset, data_size);
//Link texture to uniform
m_program->uniforms.texture(location, index + texture_index_offset, texture);
}
else if (rsx::method_registers.register_vertex_info[index].size > 0)
{
auto &vertex_info = rsx::method_registers.register_vertex_info[index];
switch (vertex_info.type)
{
case rsx::vertex_base_type::f:
{
const u32 element_size = rsx::get_vertex_type_size_on_host(vertex_info.type, vertex_info.size);
const u32 gl_type = to_gl_internal_type(vertex_info.type, vertex_info.size);
const size_t data_size = element_size;
auto &texture = m_gl_attrib_buffers[index];
auto mapping = m_attrib_ring_buffer.alloc_from_reserve(data_size, m_min_texbuffer_alignment);
u8 *dst = static_cast<u8*>(mapping.first);
memcpy(dst, vertex_info.data.data(), element_size);
texture.copy_from(m_attrib_ring_buffer, gl_type, mapping.second, data_size);
//Link texture to uniform
m_program->uniforms.texture(location, index + texture_index_offset, texture);
break;
}
default:
LOG_ERROR(RSX, "bad non array vertex data format (type=%d, size=%d)", (u32)vertex_info.type, vertex_info.size);
break;
}
}
else
{
glActiveTexture(GL_TEXTURE0 + index + texture_index_offset);
glBindTexture(GL_TEXTURE_BUFFER, 0);
glProgramUniform1i(m_program->id(), location, index + texture_index_offset);
continue;
}
}
m_attrib_ring_buffer.unmap();
}
u32 GLGSRender::upload_inline_array(const u32 &max_vertex_attrib_size, const u32 &texture_index_offset)
{
u32 stride = 0;
u32 offsets[rsx::limits::vertex_count] = { 0 };
for (u32 i = 0; i < rsx::limits::vertex_count; ++i)
{
const auto &info = rsx::method_registers.vertex_arrays_info[i];
if (!info.size) continue;
offsets[i] = stride;
stride += rsx::get_vertex_type_size_on_host(info.type, info.size);
}
u32 vertex_draw_count = (u32)(inline_vertex_array.size() * sizeof(u32)) / stride;
m_attrib_ring_buffer.reserve_and_map(vertex_draw_count * max_vertex_attrib_size);
for (int index = 0; index < rsx::limits::vertex_count; ++index)
{
auto &vertex_info = rsx::method_registers.vertex_arrays_info[index];
int location;
if (!m_program->uniforms.has_location(rsx::vertex_program::input_attrib_names[index] + "_buffer", &location))
continue;
if (!vertex_info.size) // disabled, bind a null sampler
{
glActiveTexture(GL_TEXTURE0 + index + texture_index_offset);
glBindTexture(GL_TEXTURE_BUFFER, 0);
glProgramUniform1i(m_program->id(), location, index + texture_index_offset);
continue;
}
const u32 element_size = rsx::get_vertex_type_size_on_host(vertex_info.type, vertex_info.size);
u32 data_size = element_size * vertex_draw_count;
u32 gl_type = to_gl_internal_type(vertex_info.type, vertex_info.size);
auto &texture = m_gl_attrib_buffers[index];
u8 *src = reinterpret_cast<u8*>(inline_vertex_array.data());
auto mapping = m_attrib_ring_buffer.alloc_from_reserve(data_size, m_min_texbuffer_alignment);
u8 *dst = static_cast<u8*>(mapping.first);
src += offsets[index];
prepare_buffer_for_writing(dst, vertex_info.type, vertex_info.size, vertex_draw_count);
//TODO: properly handle compressed data
for (u32 i = 0; i < vertex_draw_count; ++i)
{
if (vertex_info.type == rsx::vertex_base_type::ub && vertex_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 += stride;
dst += element_size;
}
texture.copy_from(m_attrib_ring_buffer, gl_type, mapping.second, data_size);
//Link texture to uniform
m_program->uniforms.texture(location, index + texture_index_offset, texture);
m_attrib_ring_buffer.unmap();
}
return vertex_draw_count;
}