commit d4919997d29c007a8a95c92476528dba7bd604cc
parent 9d39dc6fdc489d0d22f62f9cdb0b04b46a4b85fa
Author: Michael Savage <mikejsavage@gmail.com>
Date: Fri, 2 Aug 2019 19:35:20 +0300
Support multiple UBOs
Diffstat:
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 ) );
}