medfall

A super great game engine
Log | Files | Refs

commit d4919997d29c007a8a95c92476528dba7bd604cc
parent 9d39dc6fdc489d0d22f62f9cdb0b04b46a4b85fa
Author: Michael Savage <mikejsavage@gmail.com>
Date:   Fri,  2 Aug 2019 19:35:20 +0300

Support multiple UBOs

Diffstat:
Mgltf.cc | 2+-
Mrenderer.cc | 82+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Mrenderer.h | 10++--------
3 files changed, 56 insertions(+), 38 deletions(-)

diff --git a/gltf.cc b/gltf.cc @@ -546,7 +546,7 @@ GAME_FRAME( game_frame ) { UniformBinding view_uniforms = renderer_uniforms( V, P, game->pos ); UniformBinding model_uniforms = renderer_uniforms( y_up_to_z_up ); - UniformBinding joints_uniforms = renderer_upload_uniforms( skinning_matrices, model.animation.num_joints * sizeof( Mat4 ), 16 ); + UniformBinding joints_uniforms = renderer_upload_uniforms( skinning_matrices, model.animation.num_joints * sizeof( Mat4 ) ); if( !input->keys[ KEY_LEFTCTRL ] ) { // draw skinned model diff --git a/renderer.cc b/renderer.cc @@ -68,10 +68,14 @@ static RenderPass current_render_pass; static bool in_frame; static bool in_pass; -static GLuint uniforms; +struct UBO { + GLuint ubo; + u8 * buffer; + u32 bytes_used; +}; + +static UBO ubos[ 8 ]; static size_t ubo_offset_alignment; -static u8 * uniforms_buffer; -static size_t uniforms_offset; static Texture blue_noise; static Mesh fullscreen_triangle; @@ -82,8 +86,19 @@ static u32 previous_viewport_width; static u32 previous_viewport_height; void renderer_init() { - glGenBuffers( 1, &uniforms ); - glBindBuffer( GL_UNIFORM_BUFFER, uniforms ); + GLint alignment; + glGetIntegerv( GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment ); + ubo_offset_alignment = checked_cast< size_t >( alignment ); + + GLint max_ubo_size; + glGetIntegerv( GL_MAX_UNIFORM_BLOCK_SIZE, &max_ubo_size ); + ASSERT( max_ubo_size >= UNIFORM_BUFFER_SIZE ); + + for( size_t i = 0; i < ARRAY_COUNT( ubos ); i++ ) { + glGenBuffers( 1, &ubos[ i ].ubo ); + glBindBuffer( GL_UNIFORM_BUFFER, ubos[ i ].ubo ); + glBufferData( GL_UNIFORM_BUFFER, UNIFORM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW ); + } in_frame = false; in_pass = false; @@ -92,10 +107,6 @@ void renderer_init() { previous_viewport_width = 0; previous_viewport_height = 0; - GLint alignment; - glGetIntegerv( GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment ); - ubo_offset_alignment = checked_cast< size_t >( alignment ); - blue_noise = load_png_memory( blue_noise_png, blue_noise_png_len, TEXFMT_R_U8NORM, 1 ); v3 tri[] = { @@ -111,7 +122,10 @@ void renderer_init() { } void renderer_term() { - glDeleteBuffers( 1, &uniforms ); + for( size_t i = 0; i < ARRAY_COUNT( ubos ); i++ ) { + glDeleteBuffers( 1, &ubos[ i ].ubo ); + } + renderer_delete_texture( blue_noise ); renderer_delete_mesh( fullscreen_triangle ); } @@ -127,11 +141,12 @@ void renderer_begin_frame() { draw_calls_this_frame = 0; vertices_this_frame = 0; - glBindBuffer( GL_UNIFORM_BUFFER, uniforms ); - glBufferData( GL_UNIFORM_BUFFER, UNIFORM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW ); - uniforms_buffer = ( u8 * ) glMapBuffer( GL_UNIFORM_BUFFER, GL_WRITE_ONLY ); - ASSERT( uniforms_buffer != NULL ); - uniforms_offset = 0; + for( size_t i = 0; i < ARRAY_COUNT( ubos ); i++ ) { + glBindBuffer( GL_UNIFORM_BUFFER, ubos[ i ].ubo ); + ubos[ i ].buffer = ( u8 * ) glMapBufferRange( GL_UNIFORM_BUFFER, 0, UNIFORM_BUFFER_SIZE, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT ); + ubos[ i ].bytes_used = 0; + ASSERT( ubos[ i ].buffer != NULL ); + } } static GLenum depthfunc_to_glenum( DepthFunc depth_func ) { @@ -184,7 +199,6 @@ static void set_render_state( const RenderState & state ) { // textures for( size_t i = 0; i < ARRAY_COUNT( state.shader->textures ); i++ ) { glActiveTexture( GL_TEXTURE0 + i ); - // ggprint( "shader texture = {}\n", state.shader->textures[ i ] ); bool found = false; for( size_t j = 0; j < state.num_textures; j++ ) { @@ -325,8 +339,10 @@ void renderer_end_frame() { ASSERT( in_frame ); in_frame = false; - glUnmapBuffer( GL_UNIFORM_BUFFER ); - uniforms_buffer = NULL; + for( size_t i = 0; i < ARRAY_COUNT( ubos ); i++ ) { + glBindBuffer( GL_UNIFORM_BUFFER, ubos[ i ].ubo ); + glUnmapBuffer( GL_UNIFORM_BUFFER ); + } for( const RenderPass & pass : render_passes ) { bind_fb( pass.config.target ); @@ -434,24 +450,32 @@ Texture renderer_blue_noise() { return blue_noise; } -UniformBinding renderer_upload_uniforms( const void * data, size_t size, size_t alignment ) { +UniformBinding renderer_upload_uniforms( const void * data, size_t size ) { ASSERT( in_frame ); - alignment = max( alignment, ubo_offset_alignment ); + UBO * ubo = NULL; + u32 offset; + + for( size_t i = 0; i < ARRAY_COUNT( ubos ); i++ ) { + offset = checked_cast< u32 >( align_power_of_2( ubos[ i ].bytes_used, ubo_offset_alignment ) ); + if( UNIFORM_BUFFER_SIZE - offset >= size ) { + ubo = &ubos[ i ]; + break; + } + } + + if( ubo == NULL ) + FATAL( "no ubo space" ); UniformBinding binding; - binding.ubo = uniforms; - binding.offset = checked_cast< u32 >( align_power_of_2( uniforms_offset, alignment ) ); + binding.ubo = ubo->ubo; + binding.offset = offset; binding.size = checked_cast< u32 >( size ); - size_t new_uniforms_offset = binding.offset + binding.size; - ASSERT( new_uniforms_offset < UNIFORM_BUFFER_SIZE ); - // memset so we don't leave any gaps. good for write combined memory! - memset( uniforms_buffer + uniforms_offset, 0, binding.offset - uniforms_offset ); - memcpy( uniforms_buffer + binding.offset, data, size ); - - uniforms_offset = new_uniforms_offset; + memset( ubo->buffer + ubo->bytes_used, 0, offset - ubo->bytes_used ); + memcpy( ubo->buffer + offset, data, size ); + ubo->bytes_used = offset + size; return binding; } diff --git a/renderer.h b/renderer.h @@ -301,7 +301,7 @@ u32 renderer_num_vertices(); Texture renderer_blue_noise(); -UniformBinding renderer_upload_uniforms( const void * data, size_t size, size_t alignment ); +UniformBinding renderer_upload_uniforms( const void * data, size_t size ); VB renderer_new_vb( const void * data = NULL, u32 len = 0, BufferUsage usage = BUFFERUSAGE_STATIC ); void renderer_delete_vb( VB vb ); @@ -359,11 +359,6 @@ constexpr size_t renderer_ub_alignment() { return renderer_ubo_alignment< T >(); } -template< typename S, typename T, typename... Rest > -constexpr size_t renderer_ub_alignment() { - return max( renderer_ub_alignment< T, Rest... >(), renderer_ubo_alignment< S >() ); -} - template< typename T > constexpr size_t renderer_uniforms_size( size_t size ) { return sizeof( T ) + align_power_of_2( size, renderer_ubo_alignment< T >() ); @@ -386,9 +381,8 @@ inline void renderer_serialise_uniforms( char * buf, size_t len, const T & first template< typename... Rest > inline UniformBinding renderer_uniforms( Rest... rest ) { constexpr size_t buf_size = renderer_uniforms_size< Rest... >( 0 ); - constexpr size_t alignment = renderer_ub_alignment< Rest... >(); char buf[ buf_size ]; memset( buf, 0, sizeof( buf ) ); renderer_serialise_uniforms( buf, 0, rest... ); - return renderer_upload_uniforms( buf, sizeof( buf ), alignment ); + return renderer_upload_uniforms( buf, sizeof( buf ) ); }