mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-03 12:00:22 +01:00
perf(gl46): the geometry of the banks without user data in a few large buffers shared by them, so the multi draws take the chunks of many models at once (gfx.geometry.shared)
This commit is contained in:
@@ -381,6 +381,13 @@ geometry_bank::draw_indirect_multi( gfx::geometry_handle const &Geometry, std::i
|
|||||||
return draw_indirect_multi_( Geometry, Offset, Count, Stride );
|
return draw_indirect_multi_( Geometry, Offset, Count, Stride );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the buffers the bank keeps its geometry in, when they're shared with other banks, 0 otherwise
|
||||||
|
std::uint32_t
|
||||||
|
geometry_bank::draw_group() const {
|
||||||
|
// template method implementation
|
||||||
|
return draw_group_();
|
||||||
|
}
|
||||||
|
|
||||||
// frees subclass-specific resources associated with the bank, typically called when the bank wasn't in use for a period of time
|
// frees subclass-specific resources associated with the bank, typically called when the bank wasn't in use for a period of time
|
||||||
void
|
void
|
||||||
geometry_bank::release() {
|
geometry_bank::release() {
|
||||||
@@ -588,6 +595,17 @@ geometrybank_manager::draw_indirect_multi( gfx::geometry_handle const &Geometry,
|
|||||||
return bankrecord.first->draw_indirect_multi( Geometry, Offset, Count, Stride );
|
return bankrecord.first->draw_indirect_multi( Geometry, Offset, Count, Stride );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// what the chunks of a multi draw have to share: the shared buffers of the bank of the chunk, or the bank itself. the groups of
|
||||||
|
// shared buffers have the highest bit set, apart from the numbers of the banks
|
||||||
|
std::uint32_t
|
||||||
|
geometrybank_manager::draw_group( gfx::geometry_handle const &Geometry ) const {
|
||||||
|
|
||||||
|
if( Geometry == null_handle ) { return 0; }
|
||||||
|
|
||||||
|
auto const group { bank( Geometry ).first->draw_group() };
|
||||||
|
return ( group != 0 ? ( group | 0x80000000u ) : Geometry.bank );
|
||||||
|
}
|
||||||
|
|
||||||
// provides direct access to index data of specfied chunk
|
// provides direct access to index data of specfied chunk
|
||||||
gfx::index_array const &
|
gfx::index_array const &
|
||||||
geometrybank_manager::indices( gfx::geometry_handle const &Geometry ) const {
|
geometrybank_manager::indices( gfx::geometry_handle const &Geometry ) const {
|
||||||
|
|||||||
@@ -145,6 +145,10 @@ public:
|
|||||||
// with a single glMultiDrawElementsIndirect (or glMultiDrawArraysIndirect). the chunks have to be of the type of the
|
// with a single glMultiDrawElementsIndirect (or glMultiDrawArraysIndirect). the chunks have to be of the type of the
|
||||||
// specified one and indexed alike. returns: false if the bank can't, nothing is drawn then
|
// specified one and indexed alike. returns: false if the bank can't, nothing is drawn then
|
||||||
auto draw_indirect_multi( gfx::geometry_handle const &Geometry, std::intptr_t const Offset, std::uint32_t const Count, std::uint32_t const Stride ) -> bool;
|
auto draw_indirect_multi( gfx::geometry_handle const &Geometry, std::intptr_t const Offset, std::uint32_t const Count, std::uint32_t const Stride ) -> bool;
|
||||||
|
// the buffers the bank keeps its geometry in, when they're shared with other banks: chunks of banks of the same group can go
|
||||||
|
// in one multi draw (draw_indirect_multi()). 0 when the bank has buffers of its own. valid once the chunks were made ready
|
||||||
|
// for drawing (indirect_source())
|
||||||
|
auto draw_group() const -> std::uint32_t;
|
||||||
// draws geometry stored in supplied list of chunks
|
// draws geometry stored in supplied list of chunks
|
||||||
template <typename Iterator_>
|
template <typename Iterator_>
|
||||||
auto draw( Iterator_ First, Iterator_ Last, gfx::stream_units const &Units, unsigned int const Streams = basic_streams ) ->std::size_t {
|
auto draw( Iterator_ First, Iterator_ Last, gfx::stream_units const &Units, unsigned int const Streams = basic_streams ) ->std::size_t {
|
||||||
@@ -225,6 +229,8 @@ private:
|
|||||||
virtual auto indirect_source_( gfx::geometry_handle const & /*Geometry*/, gfx::indirect_source & /*Source*/ ) -> bool { return false; }
|
virtual auto indirect_source_( gfx::geometry_handle const & /*Geometry*/, gfx::indirect_source & /*Source*/ ) -> bool { return false; }
|
||||||
virtual void draw_indirect_( gfx::geometry_handle const & /*Geometry*/, std::intptr_t const /*Offset*/, unsigned int const /*Streams*/ ) {}
|
virtual void draw_indirect_( gfx::geometry_handle const & /*Geometry*/, std::intptr_t const /*Offset*/, unsigned int const /*Streams*/ ) {}
|
||||||
virtual auto draw_indirect_multi_( gfx::geometry_handle const & /*Geometry*/, std::intptr_t const /*Offset*/, std::uint32_t const /*Count*/, std::uint32_t const /*Stride*/ ) -> bool { return false; }
|
virtual auto draw_indirect_multi_( gfx::geometry_handle const & /*Geometry*/, std::intptr_t const /*Offset*/, std::uint32_t const /*Count*/, std::uint32_t const /*Stride*/ ) -> bool { return false; }
|
||||||
|
// draw_group() subclass details. by default the bank keeps its geometry to itself
|
||||||
|
virtual auto draw_group_() const -> std::uint32_t { return 0; }
|
||||||
// resource release subclass details
|
// resource release subclass details
|
||||||
virtual void release_() = 0;
|
virtual void release_() = 0;
|
||||||
};
|
};
|
||||||
@@ -267,6 +273,10 @@ public:
|
|||||||
// draws chunks of the bank of the specified one, of its type and indexed alike, with Count commands from Offset in the bound
|
// draws chunks of the bank of the specified one, of its type and indexed alike, with Count commands from Offset in the bound
|
||||||
// draw indirect buffer, Stride bytes apart, in one call. returns: false if the bank can't, nothing is drawn then
|
// draw indirect buffer, Stride bytes apart, in one call. returns: false if the bank can't, nothing is drawn then
|
||||||
auto draw_indirect_multi( gfx::geometry_handle const &Geometry, std::intptr_t const Offset, std::uint32_t const Count, std::uint32_t const Stride ) -> bool;
|
auto draw_indirect_multi( gfx::geometry_handle const &Geometry, std::intptr_t const Offset, std::uint32_t const Count, std::uint32_t const Stride ) -> bool;
|
||||||
|
// what the chunks of a multi draw (draw_indirect_multi()) have to share, besides their type and whether they're indexed: the
|
||||||
|
// buffers of the bank of the specified chunk. the same for chunks of banks which share their buffers, the bank otherwise.
|
||||||
|
// valid once the chunk was made ready for drawing (indirect_source())
|
||||||
|
auto draw_group( gfx::geometry_handle const &Geometry ) const -> std::uint32_t;
|
||||||
template <typename Iterator_>
|
template <typename Iterator_>
|
||||||
void draw( Iterator_ First, Iterator_ Last, unsigned int const Streams = basic_streams ) {
|
void draw( Iterator_ First, Iterator_ Last, unsigned int const Streams = basic_streams ) {
|
||||||
while( First != Last ) {
|
while( First != Last ) {
|
||||||
|
|||||||
@@ -11,9 +11,84 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "rendering/opengl46/opengl46geometrybank.h"
|
#include "rendering/opengl46/opengl46geometrybank.h"
|
||||||
|
|
||||||
#include "utilities/Logs.h"
|
#include "utilities/Logs.h"
|
||||||
|
#include "utilities/Globals.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
namespace gfx {
|
namespace gfx {
|
||||||
|
|
||||||
|
// a vertex and an index buffer shared by banks, with the vao they're drawn with. the banks take parts of them, given back when the
|
||||||
|
// bank lets its buffers go (a chunk added or resized, the bank released); the free parts are kept by their place, joined with the
|
||||||
|
// neighbouring ones when given back
|
||||||
|
struct opengl46_geometry_page {
|
||||||
|
// the size of a page: 4M vertices (192 MiB) and 12M indices (48 MiB). a bank larger than that gets a page of its own size
|
||||||
|
static constexpr std::size_t VERTICES { 4u << 20 };
|
||||||
|
static constexpr std::size_t INDICES { 12u << 20 };
|
||||||
|
|
||||||
|
gl::buffer vertices;
|
||||||
|
gl::buffer indices;
|
||||||
|
gl::vao vao;
|
||||||
|
std::size_t vertexcapacity { 0 };
|
||||||
|
std::size_t indexcapacity { 0 };
|
||||||
|
std::map<std::size_t, std::size_t> freevertices; // place -> count
|
||||||
|
std::map<std::size_t, std::size_t> freeindices;
|
||||||
|
std::size_t users { 0 }; // banks with a part of the page
|
||||||
|
std::uint32_t id { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<opengl46_geometry_page>> &geometry_pages() {
|
||||||
|
static std::vector<std::unique_ptr<opengl46_geometry_page>> pages;
|
||||||
|
return pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
// takes Count elements from the free parts, the first one large enough. returns: false if there's none
|
||||||
|
bool take_part( std::map<std::size_t, std::size_t> &Free, std::size_t const Count, std::size_t &Offset ) {
|
||||||
|
|
||||||
|
if( Count == 0 ) {
|
||||||
|
Offset = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for( auto part { Free.begin() }; part != Free.end(); ++part ) {
|
||||||
|
if( part->second < Count ) { continue; }
|
||||||
|
Offset = part->first;
|
||||||
|
auto const rest { part->second - Count };
|
||||||
|
Free.erase( part );
|
||||||
|
if( rest > 0 ) {
|
||||||
|
Free.emplace( Offset + Count, rest );
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// gives back Count elements from Offset, joined with the free parts next to them
|
||||||
|
void give_part( std::map<std::size_t, std::size_t> &Free, std::size_t const Offset, std::size_t const Count ) {
|
||||||
|
|
||||||
|
if( Count == 0 ) { return; }
|
||||||
|
auto part { Free.emplace( Offset, Count ).first };
|
||||||
|
auto const next { std::next( part ) };
|
||||||
|
if( ( next != Free.end() ) && ( part->first + part->second == next->first ) ) {
|
||||||
|
part->second += next->second;
|
||||||
|
Free.erase( next );
|
||||||
|
}
|
||||||
|
if( part != Free.begin() ) {
|
||||||
|
auto const previous { std::prev( part ) };
|
||||||
|
if( previous->first + previous->second == part->first ) {
|
||||||
|
previous->second += part->second;
|
||||||
|
Free.erase( part );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t next_page_id() {
|
||||||
|
static std::uint32_t id { 0 };
|
||||||
|
return ++id;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
// opengl vao/vbo-based variant of the geometry bank
|
// opengl vao/vbo-based variant of the geometry bank
|
||||||
|
|
||||||
// create() subclass details
|
// create() subclass details
|
||||||
@@ -43,7 +118,7 @@ opengl46_vaogeometrybank::replace_( gfx::geometry_handle const &Geometry ) {
|
|||||||
|
|
||||||
void opengl46_vaogeometrybank::setup_buffer()
|
void opengl46_vaogeometrybank::setup_buffer()
|
||||||
{
|
{
|
||||||
if( m_vertexbuffer ) { return; }
|
if( has_buffer() ) { return; }
|
||||||
// if there's no buffer, we'll have to make one
|
// if there's no buffer, we'll have to make one
|
||||||
// NOTE: this isn't exactly optimal in terms of ensuring the gfx card doesn't stall waiting for the data
|
// NOTE: this isn't exactly optimal in terms of ensuring the gfx card doesn't stall waiting for the data
|
||||||
// may be better to initiate upload earlier (during update phase) and trust this effort won't go to waste
|
// may be better to initiate upload earlier (during update phase) and trust this effort won't go to waste
|
||||||
@@ -70,6 +145,67 @@ void opengl46_vaogeometrybank::setup_buffer()
|
|||||||
// the odds for all created chunks to get replaced with empty ones are quite low, but the possibility does exist
|
// the odds for all created chunks to get replaced with empty ones are quite low, but the possibility does exist
|
||||||
if( vertexcount == 0 ) { return; }
|
if( vertexcount == 0 ) { return; }
|
||||||
|
|
||||||
|
if( Global.gfx_geometry_shared && ( false == has_userdata ) ) {
|
||||||
|
// a part of the shared buffers: of a page with room for it, or of a new one
|
||||||
|
auto &pages { geometry_pages() };
|
||||||
|
opengl46_geometry_page *page { nullptr };
|
||||||
|
std::size_t vertexoffset { 0 };
|
||||||
|
std::size_t indexoffset { 0 };
|
||||||
|
for( auto &candidate : pages ) {
|
||||||
|
if( false == take_part( candidate->freevertices, vertexcount, vertexoffset ) ) { continue; }
|
||||||
|
if( false == take_part( candidate->freeindices, indexcount, indexoffset ) ) {
|
||||||
|
give_part( candidate->freevertices, vertexoffset, vertexcount );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
page = candidate.get();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( page == nullptr ) {
|
||||||
|
auto newpage { std::make_unique<opengl46_geometry_page>() };
|
||||||
|
newpage->id = next_page_id();
|
||||||
|
newpage->vertexcapacity = std::max( opengl46_geometry_page::VERTICES, vertexcount );
|
||||||
|
newpage->indexcapacity = std::max( opengl46_geometry_page::INDICES, indexcount );
|
||||||
|
newpage->vao.bind();
|
||||||
|
newpage->indices.allocate( gl::buffer::ELEMENT_ARRAY_BUFFER, static_cast<GLsizeiptr>( newpage->indexcapacity * sizeof( gfx::basic_index ) ), GL_STATIC_DRAW );
|
||||||
|
if( ::glGetError() == GL_OUT_OF_MEMORY ) {
|
||||||
|
ErrorLog( "openGL error: out of memory; failed to create a shared geometry index buffer" );
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
newpage->vao.setup_ebo( newpage->indices );
|
||||||
|
newpage->vertices.allocate( gl::buffer::ARRAY_BUFFER, static_cast<GLsizeiptr>( newpage->vertexcapacity * sizeof( gfx::basic_vertex ) ), GL_STATIC_DRAW );
|
||||||
|
if( ::glGetError() == GL_OUT_OF_MEMORY ) {
|
||||||
|
ErrorLog( "openGL error: out of memory; failed to create a shared geometry buffer" );
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
auto &vao { newpage->vao };
|
||||||
|
auto &buffer { newpage->vertices };
|
||||||
|
vao.setup_attrib( buffer, 0, 3, GL_FLOAT, sizeof( basic_vertex ), offsetof( basic_vertex, position ) );
|
||||||
|
// NOTE: normal and color streams share the data
|
||||||
|
vao.setup_attrib( buffer, 1, 3, GL_FLOAT, sizeof( basic_vertex ), offsetof( basic_vertex, normal ) );
|
||||||
|
vao.setup_attrib( buffer, 2, 2, GL_FLOAT, sizeof( basic_vertex ), offsetof( basic_vertex, texture ) );
|
||||||
|
vao.setup_attrib( buffer, 3, 4, GL_FLOAT, sizeof( basic_vertex ), offsetof( basic_vertex, tangent ) );
|
||||||
|
newpage->freevertices.emplace( 0, newpage->vertexcapacity );
|
||||||
|
newpage->freeindices.emplace( 0, newpage->indexcapacity );
|
||||||
|
take_part( newpage->freevertices, vertexcount, vertexoffset );
|
||||||
|
take_part( newpage->freeindices, indexcount, indexoffset );
|
||||||
|
page = newpage.get();
|
||||||
|
pages.emplace_back( std::move( newpage ) );
|
||||||
|
}
|
||||||
|
++page->users;
|
||||||
|
m_page = page;
|
||||||
|
m_pagevertexoffset = vertexoffset;
|
||||||
|
m_pagevertexcount = vertexcount;
|
||||||
|
m_pageindexoffset = indexoffset;
|
||||||
|
m_pageindexcount = indexcount;
|
||||||
|
// the chunks lie in the shared buffers after one another, from the place of the bank
|
||||||
|
for( auto &chunkrecord : m_chunkrecords ) {
|
||||||
|
chunkrecord.vertex_offset += vertexoffset;
|
||||||
|
chunkrecord.index_offset += indexoffset;
|
||||||
|
}
|
||||||
|
m_vertex_count = static_cast<int>( vertexcount );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if( !m_vao ) {
|
if( !m_vao ) {
|
||||||
m_vao.emplace();
|
m_vao.emplace();
|
||||||
}
|
}
|
||||||
@@ -115,6 +251,73 @@ opengl46_vaogeometrybank::setup_attrib(size_t offset)
|
|||||||
m_vao->setup_attrib( *m_vertexbuffer, 3, 4, GL_FLOAT, sizeof( basic_vertex ), offsetof(basic_vertex, tangent) + offset * sizeof( basic_vertex ) );
|
m_vao->setup_attrib( *m_vertexbuffer, 3, 4, GL_FLOAT, sizeof( basic_vertex ), offsetof(basic_vertex, tangent) + offset * sizeof( basic_vertex ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// a line for the debug panel: the pages of the shared buffers and how much of them the banks take
|
||||||
|
std::string
|
||||||
|
opengl46_vaogeometrybank::shared_info() {
|
||||||
|
|
||||||
|
auto const &pages { geometry_pages() };
|
||||||
|
if( pages.empty() ) { return {}; }
|
||||||
|
std::size_t users { 0 }, vertices { 0 }, vertexcapacity { 0 }, indices { 0 }, indexcapacity { 0 }, parts { 0 };
|
||||||
|
for( auto const &page : pages ) {
|
||||||
|
users += page->users;
|
||||||
|
vertexcapacity += page->vertexcapacity;
|
||||||
|
indexcapacity += page->indexcapacity;
|
||||||
|
vertices += page->vertexcapacity;
|
||||||
|
indices += page->indexcapacity;
|
||||||
|
for( auto const &part : page->freevertices ) { vertices -= part.second; }
|
||||||
|
for( auto const &part : page->freeindices ) { indices -= part.second; }
|
||||||
|
parts += page->freevertices.size();
|
||||||
|
}
|
||||||
|
auto const mib = []( std::size_t const Bytes ) { return std::to_string( ( Bytes + ( 1u << 19 ) ) >> 20 ) + " MiB"; };
|
||||||
|
return
|
||||||
|
" shared geometry buffers: " + std::to_string( pages.size() ) + " pages, " + std::to_string( users ) + " banks, vertices "
|
||||||
|
+ mib( vertices * sizeof( basic_vertex ) ) + " of " + mib( vertexcapacity * sizeof( basic_vertex ) ) + ", indices "
|
||||||
|
+ mib( indices * sizeof( basic_index ) ) + " of " + mib( indexcapacity * sizeof( basic_index ) ) + ", " + std::to_string( parts ) + " free parts\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// binds the vao the bank is drawn with: the one of its page of the shared buffers, or its own
|
||||||
|
void
|
||||||
|
opengl46_vaogeometrybank::bind_vao() {
|
||||||
|
|
||||||
|
if( m_page != nullptr ) { m_page->vao.bind(); }
|
||||||
|
else { m_vao->bind(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// sends the data of a chunk to the buffers, unless they hold it already
|
||||||
|
void
|
||||||
|
opengl46_vaogeometrybank::upload_chunk( chunk_record &Record, geometry_chunk const &Chunk ) {
|
||||||
|
|
||||||
|
if( Record.is_good ) { return; }
|
||||||
|
if( m_page != nullptr ) {
|
||||||
|
// straight to the shared buffers, without binding them: the element buffer is a part of whichever vao is bound
|
||||||
|
if( Record.index_count > 0 ) {
|
||||||
|
::glNamedBufferSubData( m_page->indices, static_cast<GLintptr>( Record.index_offset * sizeof( gfx::basic_index ) ), static_cast<GLsizeiptr>( Record.index_count * sizeof( gfx::basic_index ) ), Chunk.indices.data() );
|
||||||
|
}
|
||||||
|
::glNamedBufferSubData( m_page->vertices, static_cast<GLintptr>( Record.vertex_offset * sizeof( gfx::basic_vertex ) ), static_cast<GLsizeiptr>( Record.vertex_count * sizeof( gfx::basic_vertex ) ), Chunk.vertices.data() );
|
||||||
|
Record.is_good = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_vao->bind();
|
||||||
|
// we may potentially need to upload new buffer data before we can draw it
|
||||||
|
if( Record.index_count > 0 ) {
|
||||||
|
m_indexbuffer->upload( gl::buffer::ELEMENT_ARRAY_BUFFER, Chunk.indices.data(), Record.index_offset * sizeof( gfx::basic_index ), Record.index_count * sizeof( gfx::basic_index ) );
|
||||||
|
}
|
||||||
|
m_vertexbuffer->upload( gl::buffer::ARRAY_BUFFER, Chunk.vertices.data(), Record.vertex_offset * sizeof( gfx::basic_vertex ), Record.vertex_count * sizeof( gfx::basic_vertex ) );
|
||||||
|
if( Record.has_userdata ) {
|
||||||
|
m_vertexbuffer->upload( gl::buffer::ARRAY_BUFFER, Chunk.userdata.data(),
|
||||||
|
static_cast<int>( m_vertex_count * sizeof( gfx::basic_vertex ) + Record.vertex_offset * sizeof( gfx::vertex_userdata ) ),
|
||||||
|
static_cast<int>( Record.vertex_count * sizeof( gfx::vertex_userdata ) ) );
|
||||||
|
}
|
||||||
|
Record.is_good = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw_group() subclass details
|
||||||
|
std::uint32_t
|
||||||
|
opengl46_vaogeometrybank::draw_group_() const {
|
||||||
|
|
||||||
|
return ( m_page != nullptr ? m_page->id : 0 );
|
||||||
|
}
|
||||||
|
|
||||||
void opengl46_vaogeometrybank::setup_userdata(size_t offset) {
|
void opengl46_vaogeometrybank::setup_userdata(size_t offset) {
|
||||||
const size_t offset_evaluated = m_vertex_count * sizeof(basic_vertex) + offset * sizeof( vertex_userdata );
|
const size_t offset_evaluated = m_vertex_count * sizeof(basic_vertex) + offset * sizeof( vertex_userdata );
|
||||||
m_vao->setup_attrib( *m_vertexbuffer, 4, 4, GL_FLOAT, sizeof( vertex_userdata ), offsetof(vertex_userdata, data) + offset_evaluated );}
|
m_vao->setup_attrib( *m_vertexbuffer, 4, 4, GL_FLOAT, sizeof( vertex_userdata ), offsetof(vertex_userdata, data) + offset_evaluated );}
|
||||||
@@ -133,22 +336,10 @@ opengl46_vaogeometrybank::draw_( gfx::geometry_handle const &Geometry, gfx::stre
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
auto const &chunk = gfx::geometry_bank::chunk( Geometry );
|
auto const &chunk = gfx::geometry_bank::chunk( Geometry );
|
||||||
if( !chunkrecord.is_good ) {
|
upload_chunk( chunkrecord, chunk );
|
||||||
m_vao->bind();
|
|
||||||
// we may potentially need to upload new buffer data before we can draw it
|
|
||||||
if( chunkrecord.index_count > 0 ) {
|
|
||||||
m_indexbuffer->upload( gl::buffer::ELEMENT_ARRAY_BUFFER, chunk.indices.data(), chunkrecord.index_offset * sizeof( gfx::basic_index ), chunkrecord.index_count * sizeof( gfx::basic_index ) );
|
|
||||||
}
|
|
||||||
m_vertexbuffer->upload( gl::buffer::ARRAY_BUFFER, chunk.vertices.data(), chunkrecord.vertex_offset * sizeof( gfx::basic_vertex ), chunkrecord.vertex_count * sizeof( gfx::basic_vertex ) );
|
|
||||||
if(chunkrecord.has_userdata)
|
|
||||||
m_vertexbuffer->upload(gl::buffer::ARRAY_BUFFER, chunk.userdata.data(),
|
|
||||||
static_cast<int>(m_vertex_count * sizeof(gfx::basic_vertex) + chunkrecord.vertex_offset * sizeof(gfx::vertex_userdata)),
|
|
||||||
static_cast<int>(chunkrecord.vertex_count * sizeof(gfx::vertex_userdata)));
|
|
||||||
chunkrecord.is_good = true;
|
|
||||||
}
|
|
||||||
// render
|
// render
|
||||||
if( chunkrecord.index_count > 0 ) {
|
if( chunkrecord.index_count > 0 ) {
|
||||||
m_vao->bind();
|
bind_vao();
|
||||||
::glDrawRangeElementsBaseVertex(
|
::glDrawRangeElementsBaseVertex(
|
||||||
chunk.type,
|
chunk.type,
|
||||||
0, chunkrecord.vertex_count,
|
0, chunkrecord.vertex_count,
|
||||||
@@ -156,7 +347,7 @@ opengl46_vaogeometrybank::draw_( gfx::geometry_handle const &Geometry, gfx::stre
|
|||||||
chunkrecord.vertex_offset );
|
chunkrecord.vertex_offset );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_vao->bind();
|
bind_vao();
|
||||||
::glDrawArrays( chunk.type, chunkrecord.vertex_offset, chunkrecord.vertex_count );
|
::glDrawArrays( chunk.type, chunkrecord.vertex_offset, chunkrecord.vertex_count );
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@@ -181,24 +372,12 @@ opengl46_vaogeometrybank::draw_instanced_( gfx::geometry_handle const &Geometry,
|
|||||||
if( chunkrecord.vertex_count == 0 ) { return 0; }
|
if( chunkrecord.vertex_count == 0 ) { return 0; }
|
||||||
|
|
||||||
auto const &chunk = gfx::geometry_bank::chunk( Geometry );
|
auto const &chunk = gfx::geometry_bank::chunk( Geometry );
|
||||||
if( !chunkrecord.is_good ) {
|
upload_chunk( chunkrecord, chunk );
|
||||||
m_vao->bind();
|
|
||||||
if( chunkrecord.index_count > 0 ) {
|
|
||||||
m_indexbuffer->upload( gl::buffer::ELEMENT_ARRAY_BUFFER, chunk.indices.data(), chunkrecord.index_offset * sizeof( gfx::basic_index ), chunkrecord.index_count * sizeof( gfx::basic_index ) );
|
|
||||||
}
|
|
||||||
m_vertexbuffer->upload( gl::buffer::ARRAY_BUFFER, chunk.vertices.data(), chunkrecord.vertex_offset * sizeof( gfx::basic_vertex ), chunkrecord.vertex_count * sizeof( gfx::basic_vertex ) );
|
|
||||||
if( chunkrecord.has_userdata ) {
|
|
||||||
m_vertexbuffer->upload( gl::buffer::ARRAY_BUFFER, chunk.userdata.data(),
|
|
||||||
static_cast<int>(m_vertex_count * sizeof(gfx::basic_vertex) + chunkrecord.vertex_offset * sizeof(gfx::vertex_userdata)),
|
|
||||||
static_cast<int>(chunkrecord.vertex_count * sizeof(gfx::vertex_userdata)) );
|
|
||||||
}
|
|
||||||
chunkrecord.is_good = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLsizei const inst_count = static_cast<GLsizei>(InstanceCount);
|
GLsizei const inst_count = static_cast<GLsizei>(InstanceCount);
|
||||||
|
|
||||||
if( chunkrecord.index_count > 0 ) {
|
if( chunkrecord.index_count > 0 ) {
|
||||||
m_vao->bind();
|
bind_vao();
|
||||||
::glDrawElementsInstancedBaseVertexBaseInstance(
|
::glDrawElementsInstancedBaseVertexBaseInstance(
|
||||||
chunk.type,
|
chunk.type,
|
||||||
chunkrecord.index_count, GL_UNSIGNED_INT,
|
chunkrecord.index_count, GL_UNSIGNED_INT,
|
||||||
@@ -208,7 +387,7 @@ opengl46_vaogeometrybank::draw_instanced_( gfx::geometry_handle const &Geometry,
|
|||||||
BaseInstance );
|
BaseInstance );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_vao->bind();
|
bind_vao();
|
||||||
::glDrawArraysInstancedBaseInstance( chunk.type, chunkrecord.vertex_offset, chunkrecord.vertex_count, inst_count, BaseInstance );
|
::glDrawArraysInstancedBaseInstance( chunk.type, chunkrecord.vertex_offset, chunkrecord.vertex_count, inst_count, BaseInstance );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,19 +412,7 @@ opengl46_vaogeometrybank::indirect_source_( gfx::geometry_handle const &Geometry
|
|||||||
if( chunkrecord.vertex_count == 0 ) { return false; }
|
if( chunkrecord.vertex_count == 0 ) { return false; }
|
||||||
|
|
||||||
auto const &chunk = gfx::geometry_bank::chunk( Geometry );
|
auto const &chunk = gfx::geometry_bank::chunk( Geometry );
|
||||||
if( !chunkrecord.is_good ) {
|
upload_chunk( chunkrecord, chunk );
|
||||||
m_vao->bind();
|
|
||||||
if( chunkrecord.index_count > 0 ) {
|
|
||||||
m_indexbuffer->upload( gl::buffer::ELEMENT_ARRAY_BUFFER, chunk.indices.data(), chunkrecord.index_offset * sizeof( gfx::basic_index ), chunkrecord.index_count * sizeof( gfx::basic_index ) );
|
|
||||||
}
|
|
||||||
m_vertexbuffer->upload( gl::buffer::ARRAY_BUFFER, chunk.vertices.data(), chunkrecord.vertex_offset * sizeof( gfx::basic_vertex ), chunkrecord.vertex_count * sizeof( gfx::basic_vertex ) );
|
|
||||||
if( chunkrecord.has_userdata ) {
|
|
||||||
m_vertexbuffer->upload( gl::buffer::ARRAY_BUFFER, chunk.userdata.data(),
|
|
||||||
static_cast<int>(m_vertex_count * sizeof(gfx::basic_vertex) + chunkrecord.vertex_offset * sizeof(gfx::vertex_userdata)),
|
|
||||||
static_cast<int>(chunkrecord.vertex_count * sizeof(gfx::vertex_userdata)) );
|
|
||||||
}
|
|
||||||
chunkrecord.is_good = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Source.indexed = ( chunkrecord.index_count > 0 );
|
Source.indexed = ( chunkrecord.index_count > 0 );
|
||||||
Source.count = static_cast<std::uint32_t>( Source.indexed ? chunkrecord.index_count : chunkrecord.vertex_count );
|
Source.count = static_cast<std::uint32_t>( Source.indexed ? chunkrecord.index_count : chunkrecord.vertex_count );
|
||||||
@@ -265,7 +432,7 @@ opengl46_vaogeometrybank::draw_indirect_( gfx::geometry_handle const &Geometry,
|
|||||||
if( chunkrecord.vertex_count == 0 ) { return; }
|
if( chunkrecord.vertex_count == 0 ) { return; }
|
||||||
|
|
||||||
auto const &chunk = gfx::geometry_bank::chunk( Geometry );
|
auto const &chunk = gfx::geometry_bank::chunk( Geometry );
|
||||||
m_vao->bind();
|
bind_vao();
|
||||||
if( chunkrecord.index_count > 0 ) {
|
if( chunkrecord.index_count > 0 ) {
|
||||||
::glDrawElementsIndirect( chunk.type, GL_UNSIGNED_INT, reinterpret_cast<void const *>( Offset ) );
|
::glDrawElementsIndirect( chunk.type, GL_UNSIGNED_INT, reinterpret_cast<void const *>( Offset ) );
|
||||||
}
|
}
|
||||||
@@ -282,11 +449,11 @@ opengl46_vaogeometrybank::draw_indirect_multi_( gfx::geometry_handle const &Geom
|
|||||||
setup_buffer();
|
setup_buffer();
|
||||||
|
|
||||||
// the counts of the chunks are in the commands, which may be for chunks other than this one
|
// the counts of the chunks are in the commands, which may be for chunks other than this one
|
||||||
if( ( false == m_vao.has_value() ) || ( Count == 0 ) ) { return true; }
|
if( ( false == has_buffer() ) || ( Count == 0 ) ) { return true; }
|
||||||
|
|
||||||
auto const &chunkrecord = m_chunkrecords.at(Geometry.chunk - 1);
|
auto const &chunkrecord = m_chunkrecords.at(Geometry.chunk - 1);
|
||||||
auto const &chunk = gfx::geometry_bank::chunk( Geometry );
|
auto const &chunk = gfx::geometry_bank::chunk( Geometry );
|
||||||
m_vao->bind();
|
bind_vao();
|
||||||
if( chunkrecord.index_count > 0 ) {
|
if( chunkrecord.index_count > 0 ) {
|
||||||
::glMultiDrawElementsIndirect( chunk.type, GL_UNSIGNED_INT, reinterpret_cast<void const *>( Offset ), static_cast<GLsizei>( Count ), static_cast<GLsizei>( Stride ) );
|
::glMultiDrawElementsIndirect( chunk.type, GL_UNSIGNED_INT, reinterpret_cast<void const *>( Offset ), static_cast<GLsizei>( Count ), static_cast<GLsizei>( Stride ) );
|
||||||
}
|
}
|
||||||
@@ -312,7 +479,7 @@ opengl46_vaogeometrybank::draw_batch_( gfx::geometry_handle const *First, gfx::g
|
|||||||
|
|
||||||
auto const flush = [ & ]() {
|
auto const flush = [ & ]() {
|
||||||
if( pending == 0 ) { return; }
|
if( pending == 0 ) { return; }
|
||||||
m_vao->bind();
|
bind_vao();
|
||||||
if( pending == 1 ) { ::glDrawArrays( pendingtype, offsets[ 0 ], sizes[ 0 ] ); }
|
if( pending == 1 ) { ::glDrawArrays( pendingtype, offsets[ 0 ], sizes[ 0 ] ); }
|
||||||
else { ::glMultiDrawArrays( pendingtype, offsets.data(), sizes.data(), pending ); }
|
else { ::glMultiDrawArrays( pendingtype, offsets.data(), sizes.data(), pending ); }
|
||||||
pending = 0;
|
pending = 0;
|
||||||
@@ -360,6 +527,20 @@ opengl46_vaogeometrybank::release_() {
|
|||||||
void
|
void
|
||||||
opengl46_vaogeometrybank::delete_buffer() {
|
opengl46_vaogeometrybank::delete_buffer() {
|
||||||
|
|
||||||
|
if( m_page != nullptr ) {
|
||||||
|
// the part of the shared buffers goes back; a page nobody has a part of goes, as the buffers of a bank did
|
||||||
|
give_part( m_page->freevertices, m_pagevertexoffset, m_pagevertexcount );
|
||||||
|
give_part( m_page->freeindices, m_pageindexoffset, m_pageindexcount );
|
||||||
|
if( --m_page->users == 0 ) {
|
||||||
|
auto &pages { geometry_pages() };
|
||||||
|
auto *const emptied { m_page };
|
||||||
|
pages.erase(
|
||||||
|
std::remove_if( std::begin( pages ), std::end( pages ), [ emptied ]( std::unique_ptr<opengl46_geometry_page> const &Page ) { return Page.get() == emptied; } ),
|
||||||
|
std::end( pages ) );
|
||||||
|
}
|
||||||
|
m_page = nullptr;
|
||||||
|
m_pagevertexoffset = m_pagevertexcount = m_pageindexoffset = m_pageindexcount = 0;
|
||||||
|
}
|
||||||
m_vao.reset();
|
m_vao.reset();
|
||||||
m_vertexbuffer.reset();
|
m_vertexbuffer.reset();
|
||||||
m_indexbuffer.reset();
|
m_indexbuffer.reset();
|
||||||
|
|||||||
@@ -15,7 +15,12 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
|
|
||||||
namespace gfx {
|
namespace gfx {
|
||||||
|
|
||||||
// opengl vao/vbo-based variant of the geometry bank
|
struct opengl46_geometry_page;
|
||||||
|
|
||||||
|
// opengl vao/vbo-based variant of the geometry bank.
|
||||||
|
// a bank without user data keeps its geometry in a part of a large vertex and index buffer shared with other banks, with one
|
||||||
|
// vao for all of them (opengl46_geometry_page), so the chunks of many banks can be drawn in one multi draw; the offsets of its
|
||||||
|
// chunks are places in the shared buffers. a bank with user data (an extra vertex stream) has buffers and a vao of its own
|
||||||
|
|
||||||
class opengl46_vaogeometrybank : public geometry_bank {
|
class opengl46_vaogeometrybank : public geometry_bank {
|
||||||
|
|
||||||
@@ -29,6 +34,10 @@ public:
|
|||||||
static
|
static
|
||||||
void
|
void
|
||||||
reset() {;}
|
reset() {;}
|
||||||
|
// a line for the debug panel: the pages of the shared buffers and how much of them the banks take
|
||||||
|
static
|
||||||
|
std::string
|
||||||
|
shared_info();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// types:
|
// types:
|
||||||
@@ -71,8 +80,21 @@ private:
|
|||||||
// release() subclass details
|
// release() subclass details
|
||||||
void
|
void
|
||||||
release_() override;
|
release_() override;
|
||||||
|
// draw_group() subclass details: the shared buffers, if the bank keeps its geometry in them
|
||||||
|
auto
|
||||||
|
draw_group_() const -> std::uint32_t override;
|
||||||
void
|
void
|
||||||
setup_buffer();
|
setup_buffer();
|
||||||
|
// the buffers of the bank were set up
|
||||||
|
bool
|
||||||
|
has_buffer() const {
|
||||||
|
return ( ( m_page != nullptr ) || m_vertexbuffer.has_value() ); }
|
||||||
|
// binds the vao the bank is drawn with
|
||||||
|
void
|
||||||
|
bind_vao();
|
||||||
|
// sends the data of a chunk to the buffers, unless they hold it already
|
||||||
|
void
|
||||||
|
upload_chunk( chunk_record &Record, geometry_chunk const &Chunk );
|
||||||
void
|
void
|
||||||
setup_attrib(size_t offset = 0);
|
setup_attrib(size_t offset = 0);
|
||||||
void
|
void
|
||||||
@@ -86,6 +108,12 @@ private:
|
|||||||
std::optional<gl::vao> m_vao;
|
std::optional<gl::vao> m_vao;
|
||||||
chunkrecord_sequence m_chunkrecords; // helper data for all stored geometry chunks, in matching order
|
chunkrecord_sequence m_chunkrecords; // helper data for all stored geometry chunks, in matching order
|
||||||
int m_vertex_count;
|
int m_vertex_count;
|
||||||
|
// the shared buffers holding the geometry of the bank, and its part of them: places of the first vertex and index, counts
|
||||||
|
opengl46_geometry_page *m_page { nullptr };
|
||||||
|
std::size_t m_pagevertexoffset { 0 };
|
||||||
|
std::size_t m_pagevertexcount { 0 };
|
||||||
|
std::size_t m_pageindexoffset { 0 };
|
||||||
|
std::size_t m_pageindexcount { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gfx
|
} // namespace gfx
|
||||||
|
|||||||
@@ -1280,6 +1280,7 @@ void opengl46_renderer::Update_Memory_Info()
|
|||||||
accounted += geometry.vertices.bytes + geometry.indices.bytes + geometry.userdata.bytes;
|
accounted += geometry.vertices.bytes + geometry.indices.bytes + geometry.userdata.bytes;
|
||||||
text += "geometry banks: " + std::to_string( geometry.banks ) + ", " + counted( geometry.vertices, "chunks" ) + ": vertices " + mb( geometry.vertices.bytes )
|
text += "geometry banks: " + std::to_string( geometry.banks ) + ", " + counted( geometry.vertices, "chunks" ) + ": vertices " + mb( geometry.vertices.bytes )
|
||||||
+ ", indices " + mb( geometry.indices.bytes ) + ", user data " + mb( geometry.userdata.bytes ) + "\n";
|
+ ", indices " + mb( geometry.indices.bytes ) + ", user data " + mb( geometry.userdata.bytes ) + "\n";
|
||||||
|
text += gfx::opengl46_vaogeometrybank::shared_info();
|
||||||
// models: the geometry their submodels keep of their own
|
// models: the geometry their submodels keep of their own
|
||||||
auto const models { TModelsManager::memory() };
|
auto const models { TModelsManager::memory() };
|
||||||
accounted += models.submodels.bytes;
|
accounted += models.submodels.bytes;
|
||||||
@@ -4186,7 +4187,7 @@ void opengl46_renderer::draw(const gfx::geometry_handle &handle)
|
|||||||
gfx::indirect_source source;
|
gfx::indirect_source source;
|
||||||
if( m_geometry.indirect_source( handle, source ) ) {
|
if( m_geometry.indirect_source( handle, source ) ) {
|
||||||
m_indirectcommands.push_back( { source.count, 0, source.first, static_cast<std::uint32_t>( source.basevertex ), 0, m_indirectentry, ( source.indexed ? 1u : 0u ), 0 } );
|
m_indirectcommands.push_back( { source.count, 0, source.first, static_cast<std::uint32_t>( source.basevertex ), 0, m_indirectentry, ( source.indexed ? 1u : 0u ), 0 } );
|
||||||
m_indirectdraws.push_back( { model_ubs, m_indirectmaterial, m_indirectsubmodel, handle, source.type, m_blendingenabled } );
|
m_indirectdraws.push_back( { model_ubs, m_indirectmaterial, m_indirectsubmodel, handle, source.type, m_blendingenabled, m_geometry.draw_group( handle ) } );
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -5259,6 +5260,7 @@ void opengl46_renderer::Replay_Walk( walk_band const &Walk, bool const Shadows )
|
|||||||
m_indirectcommands.push_back( { source.count, 0, source.first, static_cast<std::uint32_t>( source.basevertex ), 0, m_indirectentry, ( source.indexed ? 1u : 0u ), 0 } );
|
m_indirectcommands.push_back( { source.count, 0, source.first, static_cast<std::uint32_t>( source.basevertex ), 0, m_indirectentry, ( source.indexed ? 1u : 0u ), 0 } );
|
||||||
auto &draw { m_indirectdraws.emplace_back( walkdraw ) };
|
auto &draw { m_indirectdraws.emplace_back( walkdraw ) };
|
||||||
draw.type = source.type;
|
draw.type = source.type;
|
||||||
|
draw.group = m_geometry.draw_group( walkdraw.geometry );
|
||||||
// the walk sets the placement of the submodel, and before each draw of the colour passes the parameters of its material
|
// the walk sets the placement of the submodel, and before each draw of the colour passes the parameters of its material
|
||||||
// (Bind_Material()); the rest of the block is what the pass has at the moment, as the walk would leave it
|
// (Bind_Material()); the rest of the block is what the pass has at the moment, as the walk would leave it
|
||||||
auto const &walked { walkdraw.ubs };
|
auto const &walked { walkdraw.ubs };
|
||||||
@@ -5344,7 +5346,7 @@ opengl46_renderer::indirect_counts opengl46_renderer::Render_Instances_Indirect_
|
|||||||
auto last { index + 1 };
|
auto last { index + 1 };
|
||||||
texture_handle othertexture;
|
texture_handle othertexture;
|
||||||
while( ( last < count )
|
while( ( last < count )
|
||||||
&& ( m_indirectdraws[ last ].geometry.bank == draw.geometry.bank )
|
&& ( m_indirectdraws[ last ].group == draw.group )
|
||||||
&& ( m_indirectdraws[ last ].type == draw.type )
|
&& ( m_indirectdraws[ last ].type == draw.type )
|
||||||
&& ( m_indirectcommands[ last ].indexed == m_indirectcommands[ index ].indexed )
|
&& ( m_indirectcommands[ last ].indexed == m_indirectcommands[ index ].indexed )
|
||||||
&& ( prepass_texture( last, prepassclass, othertexture ) )
|
&& ( prepass_texture( last, prepassclass, othertexture ) )
|
||||||
@@ -5446,7 +5448,7 @@ opengl46_renderer::indirect_counts opengl46_renderer::Render_Instances_Indirect_
|
|||||||
// the draws which follow in the same bank and of the same primitive, with the same texture for the alpha test
|
// the draws which follow in the same bank and of the same primitive, with the same texture for the alpha test
|
||||||
auto last { index + 1 };
|
auto last { index + 1 };
|
||||||
while( ( last < count )
|
while( ( last < count )
|
||||||
&& ( m_indirectdraws[ last ].geometry.bank == draw.geometry.bank )
|
&& ( m_indirectdraws[ last ].group == draw.group )
|
||||||
&& ( m_indirectdraws[ last ].type == draw.type )
|
&& ( m_indirectdraws[ last ].type == draw.type )
|
||||||
&& ( m_indirectcommands[ last ].indexed == m_indirectcommands[ index ].indexed )
|
&& ( m_indirectcommands[ last ].indexed == m_indirectcommands[ index ].indexed )
|
||||||
&& ( Indirect_Shadow_Texture( m_indirectdraws[ last ].material ) == texture ) ) {
|
&& ( Indirect_Shadow_Texture( m_indirectdraws[ last ].material ) == texture ) ) {
|
||||||
@@ -5537,7 +5539,7 @@ void opengl46_renderer::Order_Indirect_Draws()
|
|||||||
for( std::size_t index = 0; index < count; ++index ) {
|
for( std::size_t index = 0; index < count; ++index ) {
|
||||||
auto const &draw { m_indirectdraws[ index ] };
|
auto const &draw { m_indirectdraws[ index ] };
|
||||||
if( shadows ) {
|
if( shadows ) {
|
||||||
m_indirectstatekeys.push_back( { Indirect_Shadow_Texture( draw.material ), 0u, draw.geometry.bank, draw.type, m_indirectcommands[ index ].indexed, draw.blending, static_cast<std::uint32_t>( index ) } );
|
m_indirectstatekeys.push_back( { Indirect_Shadow_Texture( draw.material ), 0u, draw.group, draw.type, m_indirectcommands[ index ].indexed, draw.blending, static_cast<std::uint32_t>( index ) } );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto variant { 0u };
|
auto variant { 0u };
|
||||||
@@ -5547,7 +5549,7 @@ void opengl46_renderer::Order_Indirect_Draws()
|
|||||||
variant = TSubModel::VariantId( draw.submodel ) % static_cast<std::uint32_t>( material.texture_variants.size() );
|
variant = TSubModel::VariantId( draw.submodel ) % static_cast<std::uint32_t>( material.texture_variants.size() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_indirectstatekeys.push_back( { draw.material, variant, draw.geometry.bank, draw.type, m_indirectcommands[ index ].indexed, draw.blending, static_cast<std::uint32_t>( index ) } );
|
m_indirectstatekeys.push_back( { draw.material, variant, draw.group, draw.type, m_indirectcommands[ index ].indexed, draw.blending, static_cast<std::uint32_t>( index ) } );
|
||||||
}
|
}
|
||||||
std::sort(
|
std::sort(
|
||||||
std::begin( m_indirectstatekeys ), std::end( m_indirectstatekeys ),
|
std::begin( m_indirectstatekeys ), std::end( m_indirectstatekeys ),
|
||||||
@@ -5654,7 +5656,7 @@ bool opengl46_renderer::Indirect_Mergeable( std::size_t const First, std::size_t
|
|||||||
if( ( first.material != other.material )
|
if( ( first.material != other.material )
|
||||||
|| ( first.blending != other.blending )
|
|| ( first.blending != other.blending )
|
||||||
|| ( first.type != other.type )
|
|| ( first.type != other.type )
|
||||||
|| ( first.geometry.bank != other.geometry.bank )
|
|| ( first.group != other.group )
|
||||||
|| ( m_indirectcommands[ First ].indexed != m_indirectcommands[ Other ].indexed ) ) {
|
|| ( m_indirectcommands[ First ].indexed != m_indirectcommands[ Other ].indexed ) ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -5873,7 +5875,8 @@ void opengl46_renderer::Render_Scene_Prepass()
|
|||||||
auto &item { m_sceneprepassitems.emplace_back() };
|
auto &item { m_sceneprepassitems.emplace_back() };
|
||||||
item.prepassclass = draw.prepassclass;
|
item.prepassclass = draw.prepassclass;
|
||||||
item.texture = ( draw.prepassclass == 2 ? draw.prepasstexture : null_handle );
|
item.texture = ( draw.prepassclass == 2 ? draw.prepasstexture : null_handle );
|
||||||
item.bank = chunk.geometry.bank;
|
// the buffers the geometry lies in, shared by many banks
|
||||||
|
item.bank = m_geometry.draw_group( chunk.geometry );
|
||||||
item.type = source.type;
|
item.type = source.type;
|
||||||
item.indexed = ( source.indexed ? 1u : 0u );
|
item.indexed = ( source.indexed ? 1u : 0u );
|
||||||
item.instancebuffer = draw.instancebuffer;
|
item.instancebuffer = draw.instancebuffer;
|
||||||
|
|||||||
@@ -748,6 +748,7 @@ class opengl46_renderer : public gfx_renderer {
|
|||||||
gfx::geometry_handle geometry;
|
gfx::geometry_handle geometry;
|
||||||
unsigned int type; // primitive
|
unsigned int type; // primitive
|
||||||
bool blending; // drawn with the transparency hack of submodels faded out
|
bool blending; // drawn with the transparency hack of submodels faded out
|
||||||
|
std::uint32_t group { 0 }; // the buffers of the geometry, which the draws of a multi draw share (geometrybank_manager::draw_group())
|
||||||
};
|
};
|
||||||
std::vector<indirect_draw> m_indirectdraws;
|
std::vector<indirect_draw> m_indirectdraws;
|
||||||
std::vector<gl::instance_draw_command> m_indirectcommands; // in the order of m_indirectdraws
|
std::vector<gl::instance_draw_command> m_indirectcommands; // in the order of m_indirectdraws
|
||||||
|
|||||||
@@ -1552,6 +1552,11 @@ global_settings::ConfigParse_gfx( cParser &Parser, std::string_view const Token
|
|||||||
Parser.getTokens(1);
|
Parser.getTokens(1);
|
||||||
Parser >> gfx_gpucull_walkcache;
|
Parser >> gfx_gpucull_walkcache;
|
||||||
}
|
}
|
||||||
|
else if (Token == "gfx.geometry.shared")
|
||||||
|
{
|
||||||
|
Parser.getTokens(1);
|
||||||
|
Parser >> gfx_geometry_shared;
|
||||||
|
}
|
||||||
else if (Token == "gfx.depthprepass.scene")
|
else if (Token == "gfx.depthprepass.scene")
|
||||||
{
|
{
|
||||||
Parser.getTokens(1);
|
Parser.getTokens(1);
|
||||||
@@ -2130,6 +2135,7 @@ global_settings::export_as_text( std::ostream &Output ) const {
|
|||||||
export_as_text( Output, "gfx.gpucull.models", gfx_gpucull_models );
|
export_as_text( Output, "gfx.gpucull.models", gfx_gpucull_models );
|
||||||
export_as_text( Output, "gfx.gpucull.bucketrange", gfx_gpucull_bucketrange );
|
export_as_text( Output, "gfx.gpucull.bucketrange", gfx_gpucull_bucketrange );
|
||||||
export_as_text( Output, "gfx.gpucull.walkcache", gfx_gpucull_walkcache );
|
export_as_text( Output, "gfx.gpucull.walkcache", gfx_gpucull_walkcache );
|
||||||
|
export_as_text( Output, "gfx.geometry.shared", gfx_geometry_shared );
|
||||||
export_as_text( Output, "gfx.depthprepass.scene", gfx_depthprepass_scene );
|
export_as_text( Output, "gfx.depthprepass.scene", gfx_depthprepass_scene );
|
||||||
export_as_text( Output, "gfx.depthprepass.replay", gfx_depthprepass_replay );
|
export_as_text( Output, "gfx.depthprepass.replay", gfx_depthprepass_replay );
|
||||||
export_as_text( Output, "gfx.grass", gfx_grass );
|
export_as_text( Output, "gfx.grass", gfx_grass );
|
||||||
|
|||||||
@@ -327,6 +327,9 @@ struct global_settings {
|
|||||||
// made again only when the model changes: the trees of animated models, ones lit by the luminance and the models drawn on their
|
// made again only when the model changes: the trees of animated models, ones lit by the luminance and the models drawn on their
|
||||||
// own are walked every time
|
// own are walked every time
|
||||||
bool gfx_gpucull_walkcache = true;
|
bool gfx_gpucull_walkcache = true;
|
||||||
|
// (opengl 4.6) the geometry of the banks without user data (models, scenery) is kept in a few large buffers shared by them, so
|
||||||
|
// the multi draws can take the chunks of many models at once. read when a bank sets its buffers up (load time)
|
||||||
|
bool gfx_geometry_shared = true;
|
||||||
// (opengl 4.6) the depth of the whole opaque scene of the main view is drawn before its colour, the instances included
|
// (opengl 4.6) the depth of the whole opaque scene of the main view is drawn before its colour, the instances included
|
||||||
bool gfx_depthprepass_scene = false;
|
bool gfx_depthprepass_scene = false;
|
||||||
// (opengl 4.6) the depth pass of the scene (gfx_depthprepass_scene, or the one of the contact shadows) walks the scene for
|
// (opengl 4.6) the depth pass of the scene (gfx_depthprepass_scene, or the one of the contact shadows) walks the scene for
|
||||||
|
|||||||
Reference in New Issue
Block a user