renderer.cc (32760B)
1 #include <algorithm> 2 3 #include "intrinsics.h" 4 #include "game.h" 5 #include "gl.h" 6 #include "renderer.h" 7 #include "log.h" 8 #include "linear_algebra.h" 9 #include "blue_noise.h" 10 #include "obj.h" 11 #include "fnv.h" 12 13 #include "glad.h" 14 15 STATIC_ASSERT( SAME_TYPE( VB, GLuint ) ); 16 STATIC_ASSERT( SAME_TYPE( IB, GLuint ) ); 17 STATIC_ASSERT( SAME_TYPE( Texture, GLuint ) ); 18 STATIC_ASSERT( SAME_TYPE( FramebufferObject, GLuint ) ); 19 STATIC_ASSERT( SAME_TYPE( u32, GLuint ) ); 20 21 static const GLuint ATTR_POSITION = 0; 22 static const GLuint ATTR_NORMAL = 1; 23 static const GLuint ATTR_TEX_COORD0 = 2; 24 static const GLuint ATTR_TEX_COORD1 = 3; 25 static const GLuint ATTR_COLOUR = 4; 26 static const GLuint ATTR_JOINTS = 5; 27 static const GLuint ATTR_WEIGHTS = 6; 28 static const GLuint ATTR_MODEL_TO_WORLD_COL0 = 7; 29 30 static const u32 UNIFORM_BUFFER_SIZE = kilobytes( 64 ); 31 32 struct DrawCall { 33 RenderState render_state; 34 Mesh mesh; 35 u32 num_instances; 36 VB instance_data; 37 }; 38 39 enum DeleteCommandType { 40 DELETE_VB, 41 DELETE_IB, 42 DELETE_TEXTURE, 43 DELETE_MESH, 44 }; 45 46 struct DeleteCommand { 47 DeleteCommandType type; 48 union { 49 VB vb; 50 IB ib; 51 Shader shader; 52 Texture texture; 53 Mesh mesh; 54 }; 55 }; 56 57 static DynamicArray< DrawCall > draw_calls; 58 static DynamicArray< RenderPass > render_passes; 59 static DynamicArray< DeleteCommand > deletes; 60 61 static u32 draw_calls_this_frame; 62 static u32 vertices_this_frame; 63 64 static bool in_frame; 65 66 struct UBO { 67 GLuint ubo; 68 u8 * buffer; 69 u32 bytes_used; 70 }; 71 72 static UBO ubos[ 8 ]; 73 static size_t ubo_offset_alignment; 74 75 static Texture blue_noise; 76 static Mesh fullscreen_triangle; 77 78 static RenderState previous_render_state; 79 static FramebufferObject previous_fbo; 80 static u32 previous_viewport_width; 81 static u32 previous_viewport_height; 82 83 void renderer_init() { 84 GLint alignment; 85 glGetIntegerv( GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment ); 86 ubo_offset_alignment = checked_cast< size_t >( alignment ); 87 88 GLint max_ubo_size; 89 glGetIntegerv( GL_MAX_UNIFORM_BLOCK_SIZE, &max_ubo_size ); 90 ASSERT( max_ubo_size >= UNIFORM_BUFFER_SIZE ); 91 92 for( size_t i = 0; i < ARRAY_COUNT( ubos ); i++ ) { 93 glGenBuffers( 1, &ubos[ i ].ubo ); 94 glBindBuffer( GL_UNIFORM_BUFFER, ubos[ i ].ubo ); 95 glBufferData( GL_UNIFORM_BUFFER, UNIFORM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW ); 96 } 97 98 in_frame = false; 99 100 previous_fbo = 0; 101 previous_viewport_width = 0; 102 previous_viewport_height = 0; 103 104 blue_noise = load_png_memory( blue_noise_png, blue_noise_png_len, TEXFMT_R_U8NORM, 1 ); 105 106 v3 tri[] = { 107 v3( -1.0f, -1.0f, 0.0f ), 108 v3( 3.0f, -1.0f, 0.0f ), 109 v3( -1.0f, 3.0f, 0.0f ), 110 }; 111 MeshConfig config; 112 config.positions = renderer_new_vb( tri, sizeof( tri ) ); 113 config.num_vertices = 3; 114 config.primitive_type = PRIMITIVETYPE_TRIANGLES; 115 fullscreen_triangle = renderer_new_mesh( config ); 116 } 117 118 void renderer_term() { 119 for( size_t i = 0; i < ARRAY_COUNT( ubos ); i++ ) { 120 glDeleteBuffers( 1, &ubos[ i ].ubo ); 121 } 122 123 renderer_delete_texture( blue_noise ); 124 renderer_delete_mesh( fullscreen_triangle ); 125 } 126 127 void renderer_begin_frame() { 128 ASSERT( !in_frame ); 129 in_frame = true; 130 131 draw_calls.clear(); 132 render_passes.clear(); 133 deletes.clear(); 134 135 draw_calls_this_frame = 0; 136 vertices_this_frame = 0; 137 138 for( size_t i = 0; i < ARRAY_COUNT( ubos ); i++ ) { 139 glBindBuffer( GL_UNIFORM_BUFFER, ubos[ i ].ubo ); 140 ubos[ i ].buffer = ( u8 * ) glMapBufferRange( GL_UNIFORM_BUFFER, 0, UNIFORM_BUFFER_SIZE, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT ); 141 ubos[ i ].bytes_used = 0; 142 ASSERT( ubos[ i ].buffer != NULL ); 143 } 144 145 v2u32 window_size = get_window_size(); 146 if( window_size.x != previous_viewport_width || window_size.y != previous_viewport_height ) { 147 previous_viewport_width = window_size.x; 148 previous_viewport_height = window_size.y; 149 glViewport( 0, 0, window_size.x, window_size.y ); 150 } 151 } 152 153 static GLenum depthfunc_to_glenum( DepthFunc depth_func ) { 154 switch( depth_func ) { 155 case DEPTHFUNC_LESS: return GL_LESS; 156 case DEPTHFUNC_EQUAL: return GL_EQUAL; 157 case DEPTHFUNC_ALWAYS: return GL_ALWAYS; 158 case DEPTHFUNC_DISABLED: return GL_ALWAYS; 159 } 160 161 FATAL( "unsupported DepthFunc: {}", depth_func ); 162 return GL_INVALID_ENUM; 163 } 164 165 static GLenum primitivetype_to_glenum( PrimitiveType primitive_type ) { 166 switch( primitive_type ) { 167 case PRIMITIVETYPE_TRIANGLES: return GL_TRIANGLES; 168 case PRIMITIVETYPE_TRIANGLE_STRIP: return GL_TRIANGLE_STRIP; 169 case PRIMITIVETYPE_POINTS: return GL_POINTS; 170 case PRIMITIVETYPE_LINES: return GL_LINES; 171 } 172 173 FATAL( "unsupported PrimitiveType: {}", primitive_type ); 174 return GL_INVALID_ENUM; 175 } 176 177 static void set_render_state( const RenderState & state ) { 178 if( state.shader != previous_render_state.shader ) { 179 glUseProgram( state.shader->program ); 180 } 181 182 // uniforms 183 // TODO: maybe these shouldn't always get rebound 184 for( size_t i = 0; i < ARRAY_COUNT( state.shader->uniforms ); i++ ) { 185 bool found = false; 186 for( size_t j = 0; j < state.num_uniforms; j++ ) { 187 UniformBinding binding = state.uniforms[ j ].binding; 188 if( state.uniforms[ j ].name_hash == state.shader->uniforms[ i ] && binding.size > 0 ) { 189 glBindBufferRange( GL_UNIFORM_BUFFER, i, binding.ubo, binding.offset, binding.size ); 190 found = true; 191 break; 192 } 193 } 194 195 if( !found ) { 196 glBindBufferBase( GL_UNIFORM_BUFFER, i, 0 ); 197 } 198 } 199 200 // textures 201 for( size_t i = 0; i < ARRAY_COUNT( state.shader->textures ); i++ ) { 202 glActiveTexture( GL_TEXTURE0 + i ); 203 204 bool found = false; 205 for( size_t j = 0; j < state.num_textures; j++ ) { 206 if( state.textures[ j ].name_hash == state.shader->textures[ i ] ) { 207 glBindTexture( GL_TEXTURE_2D, state.textures[ j ].texture ); 208 found = true; 209 break; 210 } 211 } 212 213 if( !found ) { 214 glBindTexture( GL_TEXTURE_2D, 0 ); 215 } 216 } 217 218 // depth writing 219 if( state.disable_depth_writes != previous_render_state.disable_depth_writes ) { 220 glDepthMask( state.disable_depth_writes ? GL_FALSE : GL_TRUE ); 221 } 222 223 // backface culling 224 if( state.cull_face != previous_render_state.cull_face ) { 225 if( state.cull_face == CULLFACE_DISABLED ) { 226 glDisable( GL_CULL_FACE ); 227 } 228 else { 229 if( previous_render_state.cull_face == CULLFACE_DISABLED ) { 230 glEnable( GL_CULL_FACE ); 231 } 232 glCullFace( state.cull_face == CULLFACE_FRONT ? GL_FRONT : GL_BACK ); 233 } 234 } 235 236 // depth testing 237 if( state.depth_func != previous_render_state.depth_func ) { 238 if( state.depth_func == DEPTHFUNC_DISABLED ) { 239 glDisable( GL_DEPTH_TEST ); 240 } 241 else { 242 if( previous_render_state.depth_func == DEPTHFUNC_DISABLED ) { 243 glEnable( GL_DEPTH_TEST ); 244 } 245 glDepthFunc( depthfunc_to_glenum( state.depth_func ) ); 246 } 247 } 248 249 // alpha blending 250 if( state.enable_alpha_blending != previous_render_state.enable_alpha_blending ) { 251 if( state.enable_alpha_blending ) { 252 glEnable( GL_BLEND ); 253 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); 254 } 255 else { 256 glDisable( GL_BLEND ); 257 } 258 } 259 260 // polygon fill mode 261 if( state.wireframe != previous_render_state.wireframe ) { 262 if( state.wireframe ) { 263 glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); 264 glEnable( GL_POLYGON_OFFSET_LINE ); 265 glPolygonOffset( -1, -1 ); 266 } 267 else { 268 glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); 269 glDisable( GL_POLYGON_OFFSET_LINE ); 270 } 271 } 272 273 previous_render_state = state; 274 } 275 276 static bool compare_drawcall( const DrawCall & a, const DrawCall & b ) { 277 if( a.render_state.pass != b.render_state.pass ) 278 return a.render_state.pass < b.render_state.pass; 279 return a.render_state.shader < b.render_state.shader; 280 } 281 282 static void setup_render_pass( const RenderPass & pass ) { 283 if( GLAD_GL_KHR_debug != 0 ) { 284 glPushDebugGroup( GL_DEBUG_SOURCE_APPLICATION, 0, -1, pass.name ); 285 } 286 287 const FB & fb = pass.target; 288 if( fb.fbo != previous_fbo ) { 289 glBindFramebuffer( GL_DRAW_FRAMEBUFFER, fb.fbo ); 290 previous_fbo = fb.fbo; 291 292 u32 viewport_width, viewport_height; 293 if( fb.fbo == 0 ) { 294 v2u32 window_size = get_window_size(); 295 viewport_width = window_size.x; 296 viewport_height = window_size.y; 297 } 298 else { 299 viewport_width = fb.width; 300 viewport_height = fb.height; 301 } 302 303 if( viewport_width != previous_viewport_width || viewport_height != previous_viewport_height ) { 304 previous_viewport_width = viewport_width; 305 previous_viewport_height = viewport_height; 306 glViewport( 0, 0, viewport_width, viewport_height ); 307 } 308 } 309 310 GLbitfield clear_mask = 0; 311 clear_mask |= pass.clear_colour ? GL_COLOR_BUFFER_BIT : 0; 312 clear_mask |= pass.clear_depth ? GL_DEPTH_BUFFER_BIT : 0; 313 if( clear_mask != 0 ) { 314 if( pass.clear_colour ) 315 glClearColor( pass.colour.x, pass.colour.y, pass.colour.z, pass.colour.w ); 316 if( pass.clear_depth ) 317 glClearDepth( pass.depth ); 318 glClear( clear_mask ); 319 } 320 } 321 322 static void drawcall_single( const Mesh & mesh, const RenderState & state ) { 323 set_render_state( state ); 324 325 glBindVertexArray( mesh.vao ); 326 GLenum primitive = primitivetype_to_glenum( mesh.primitive_type ); 327 if( mesh.indices != 0 ) { 328 glDrawElements( primitive, mesh.num_vertices, mesh.indices_format == INDEXFMT_U16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, 0 ); 329 } 330 else { 331 glDrawArrays( primitive, 0, mesh.num_vertices ); 332 } 333 glBindVertexArray( 0 ); 334 } 335 336 static void drawcall_instanced( const Mesh & mesh, const RenderState & state, u32 num_instances, VB instance_data ) { 337 set_render_state( state ); 338 339 glBindVertexArray( mesh.vao ); 340 glBindBuffer( GL_ARRAY_BUFFER, instance_data ); 341 342 for( int i = 0; i < 4; i++ ) { 343 GLuint loc = ATTR_MODEL_TO_WORLD_COL0 + i; 344 glEnableVertexAttribArray( loc ); 345 glVertexAttribPointer( loc, 4, GL_FLOAT, GL_FALSE, sizeof( m4 ), ( GLvoid * ) ( i * sizeof( v4 ) ) ); 346 glVertexAttribDivisor( loc, 1 ); 347 } 348 349 GLenum primitive = primitivetype_to_glenum( mesh.primitive_type ); 350 if( mesh.indices != 0 ) { 351 glDrawElementsInstanced( primitive, mesh.num_vertices, GL_UNSIGNED_INT, 0, checked_cast< s32 >( num_instances ) ); 352 } 353 else { 354 glDrawArraysInstanced( primitive, 0, mesh.num_vertices, checked_cast< s32 >( num_instances ) ); 355 } 356 357 glBindVertexArray( 0 ); 358 } 359 360 void renderer_end_frame() { 361 ASSERT( in_frame ); 362 in_frame = false; 363 364 for( size_t i = 0; i < ARRAY_COUNT( ubos ); i++ ) { 365 glBindBuffer( GL_UNIFORM_BUFFER, ubos[ i ].ubo ); 366 glUnmapBuffer( GL_UNIFORM_BUFFER ); 367 } 368 369 std::sort( draw_calls.begin(), draw_calls.end(), compare_drawcall ); 370 371 u8 pass_idx = U8_MAX; 372 for( const DrawCall & dc : draw_calls ) { 373 if( dc.render_state.pass != pass_idx ) { 374 if( GLAD_GL_KHR_debug != 0 && pass_idx != U8_MAX ) 375 glPopDebugGroup(); 376 setup_render_pass( render_passes[ dc.render_state.pass ] ); 377 pass_idx = dc.render_state.pass; 378 } 379 380 if( dc.render_state.shader == NULL ) { 381 FB fb = render_passes[ dc.render_state.pass ].msaa_source; 382 v2u32 window_size = get_window_size(); 383 ASSERT( fb.width == window_size.x && fb.height == window_size.y ); 384 glBindFramebuffer( GL_READ_FRAMEBUFFER, fb.fbo ); 385 glBlitFramebuffer( 0, 0, fb.width, fb.height, 0, 0, fb.width, fb.height, GL_COLOR_BUFFER_BIT, GL_NEAREST ); 386 } 387 else if( dc.num_instances == 0 ) { 388 drawcall_single( dc.mesh, dc.render_state ); 389 } 390 else { 391 drawcall_instanced( dc.mesh, dc.render_state, dc.num_instances, dc.instance_data ); 392 } 393 } 394 395 if( GLAD_GL_KHR_debug != 0 && pass_idx != U8_MAX ) 396 glPopDebugGroup(); 397 398 for( const DeleteCommand & del : deletes ) { 399 switch( del.type ) { 400 case DELETE_VB: 401 glDeleteBuffers( 1, &del.vb ); 402 break; 403 404 case DELETE_IB: 405 glDeleteBuffers( 1, &del.ib ); 406 break; 407 408 case DELETE_TEXTURE: 409 glDeleteTextures( 1, &del.texture ); 410 break; 411 412 case DELETE_MESH: 413 if( del.mesh.positions != 0 ) 414 renderer_delete_vb( del.mesh.positions ); 415 if( del.mesh.normals != 0 ) 416 renderer_delete_vb( del.mesh.normals ); 417 if( del.mesh.tex_coords0 != 0 ) 418 renderer_delete_vb( del.mesh.tex_coords0 ); 419 if( del.mesh.tex_coords1 != 0 ) 420 renderer_delete_vb( del.mesh.tex_coords1 ); 421 if( del.mesh.colours != 0 ) 422 renderer_delete_vb( del.mesh.colours ); 423 if( del.mesh.indices != 0 ) 424 renderer_delete_ib( del.mesh.indices ); 425 if( del.mesh.joints != 0 ) 426 renderer_delete_vb( del.mesh.joints ); 427 if( del.mesh.weights != 0 ) 428 renderer_delete_vb( del.mesh.weights ); 429 430 glDeleteVertexArrays( 1, &del.mesh.vao ); 431 break; 432 } 433 } 434 } 435 436 u8 renderer_add_pass( const RenderPass & pass ) { 437 return checked_cast< u8 >( render_passes.add( pass ) ); 438 } 439 440 u8 renderer_add_pass( const char * name, FB target, ClearColourBool clear_colour, ClearDepthBool clear_depth ) { 441 RenderPass pass; 442 pass.target = target; 443 pass.name = name; 444 pass.clear_colour = clear_colour == RENDERER_CLEAR_COLOUR_DO; 445 pass.clear_depth = clear_depth == RENDERER_CLEAR_DEPTH_DO; 446 return renderer_add_pass( pass ); 447 } 448 449 u8 renderer_add_pass( const char * name, ClearColourBool clear_colour, ClearDepthBool clear_depth ) { 450 FB target = { }; 451 return renderer_add_pass( name, target, clear_colour, clear_depth ); 452 } 453 454 void renderer_resolve_msaa( FB fb ) { 455 RenderPass pass; 456 pass.name = "Resolve MSAA"; 457 pass.msaa_source = fb; 458 459 RenderState dummy; 460 dummy.pass = renderer_add_pass( pass ); 461 dummy.shader = NULL; 462 463 DrawCall dc; 464 dc.render_state = dummy; 465 draw_calls.add( dc ); 466 } 467 468 u32 renderer_num_draw_calls() { 469 return draw_calls_this_frame; 470 } 471 472 u32 renderer_num_vertices() { 473 return vertices_this_frame; 474 } 475 476 Texture renderer_blue_noise() { 477 return blue_noise; 478 } 479 480 UniformBinding renderer_upload_uniforms( const void * data, size_t size ) { 481 ASSERT( in_frame ); 482 483 UBO * ubo = NULL; 484 u32 offset; 485 486 for( size_t i = 0; i < ARRAY_COUNT( ubos ); i++ ) { 487 offset = checked_cast< u32 >( align_power_of_2( ubos[ i ].bytes_used, ubo_offset_alignment ) ); 488 if( UNIFORM_BUFFER_SIZE - offset >= size ) { 489 ubo = &ubos[ i ]; 490 break; 491 } 492 } 493 494 if( ubo == NULL ) 495 FATAL( "no ubo space" ); 496 497 UniformBinding binding; 498 binding.ubo = ubo->ubo; 499 binding.offset = offset; 500 binding.size = checked_cast< u32 >( size ); 501 502 // memset so we don't leave any gaps. good for write combined memory! 503 memset( ubo->buffer + ubo->bytes_used, 0, offset - ubo->bytes_used ); 504 memcpy( ubo->buffer + offset, data, size ); 505 ubo->bytes_used = offset + size; 506 507 return binding; 508 } 509 510 static GLenum bufferusage_to_glenum( BufferUsage usage ) { 511 switch( usage ) { 512 case BUFFERUSAGE_STATIC: return GL_STATIC_DRAW; 513 case BUFFERUSAGE_DYNAMIC: return GL_DYNAMIC_DRAW; 514 case BUFFERUSAGE_STREAM: return GL_STREAM_DRAW; 515 } 516 517 FATAL( "unsupported BufferUsage: {}", usage ); 518 return GL_INVALID_ENUM; 519 } 520 521 static GLenum texfmt_to_internal_format( TextureFormat format ) { 522 switch( format ) { 523 case TEXFMT_INVALID: 524 break; 525 526 case TEXFMT_R_U8: 527 return GL_R8; 528 case TEXFMT_R_U8NORM: 529 return GL_R8_SNORM; 530 case TEXFMT_R_U16: 531 return GL_R16; 532 case TEXFMT_R_FLOAT: 533 return GL_R32F; 534 535 case TEXFMT_RGB_U8: 536 return GL_RGB8; 537 case TEXFMT_RGB_U8_SRGB: 538 return GL_SRGB8; 539 case TEXFMT_RGB_HALF: 540 return GL_RGB16F; 541 case TEXFMT_RGB_FLOAT: 542 return GL_RGB32F; 543 544 case TEXFMT_RGBA_U8: 545 return GL_RGBA8; 546 case TEXFMT_RGBA_U8_SRGB: 547 return GL_SRGB8_ALPHA8; 548 case TEXFMT_RGBA_FLOAT: 549 return GL_RGBA32F; 550 551 case TEXFMT_DEPTH: 552 return GL_DEPTH_COMPONENT24; 553 554 case TEXFMT_BC1: 555 return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; 556 case TEXFMT_BC1_SRGB: 557 return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT; 558 case TEXFMT_BC4: 559 return GL_COMPRESSED_RED_RGTC1; 560 case TEXFMT_BC5: 561 return GL_COMPRESSED_RG_RGTC2; 562 } 563 564 FATAL( "unsupported TextureFormat: {}", format ); 565 return GL_INVALID_ENUM; 566 } 567 568 static GLenum texturewrap_to_glenum( TextureWrapMode mode ) { 569 switch( mode ) { 570 case TEXWRAP_REPEAT: 571 return GL_REPEAT; 572 case TEXWRAP_CLAMP: 573 return GL_CLAMP_TO_EDGE; 574 case TEXWRAP_MIRROR: 575 return GL_MIRRORED_REPEAT; 576 case TEXWRAP_BORDER: 577 return GL_CLAMP_TO_BORDER; 578 } 579 580 FATAL( "unsupported TextureWrapMode: {}", mode ); 581 return GL_INVALID_ENUM; 582 } 583 584 static void texturefilter_to_glenum( TextureFilterMode mode, bool mipmaps, GLenum * min_filter, GLenum * mag_filter ) { 585 switch( mode ) { 586 case TEXFILTER_LINEAR: 587 *min_filter = mipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR; 588 *mag_filter = GL_LINEAR; 589 return; 590 case TEXFILTER_POINT: 591 *min_filter = mipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST; 592 *mag_filter = GL_NEAREST; 593 return; 594 } 595 596 FATAL( "unsupported TextureFilterMode: {}", mode ); 597 } 598 599 static bool is_compressed( TextureFormat format ) { 600 return format == TEXFMT_BC1 || format == TEXFMT_BC4 || format == TEXFMT_BC5; 601 } 602 603 VB renderer_new_vb( const void * data, u32 len, BufferUsage usage ) { 604 // glBufferData's length parameter is GLsizeiptr, so we need to make 605 // sure len fits in a signed 32bit int 606 ASSERT( len < S32_MAX ); 607 608 GLuint vbo; 609 glGenBuffers( 1, &vbo ); 610 611 if( data != NULL ) { 612 glBindBuffer( GL_ARRAY_BUFFER, vbo ); 613 glBufferData( GL_ARRAY_BUFFER, len, data, bufferusage_to_glenum( usage ) ); 614 } 615 616 return vbo; 617 } 618 619 void renderer_delete_vb( VB vb ) { 620 glDeleteBuffers( 1, &vb ); 621 } 622 623 IB renderer_new_ib( const void * data, u32 len, BufferUsage usage ) { 624 ASSERT( len < S32_MAX ); 625 626 GLuint ebo; 627 glGenBuffers( 1, &ebo ); 628 629 if( data != NULL ) { 630 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ebo ); 631 glBufferData( GL_ELEMENT_ARRAY_BUFFER, len, data, bufferusage_to_glenum( usage ) ); 632 } 633 634 return ebo; 635 } 636 637 void renderer_delete_ib( IB ib ) { 638 glDeleteBuffers( 1, &ib ); 639 } 640 641 static u32 mipmap_dim( u32 dim, u32 level ) { 642 return max( dim >> level, u32( 1 ) ); 643 } 644 645 // TODO: use clz 646 static u32 mipmap_levels( u32 width, u32 height ) { 647 u32 levels = 1; 648 u32 dim = max( width, height ); 649 while( dim > 1 ) { 650 dim >>= 1; 651 levels++; 652 } 653 return levels; 654 } 655 656 static u32 texture_byte_size( u32 width, u32 height, TextureFormat format, bool mipmaps ) { 657 u32 total_dim = width * height; 658 if( mipmaps ) { 659 for( u32 i = 1; i < mipmap_levels( width, height ); i++ ) { 660 total_dim += mipmap_dim( width, i ) * mipmap_dim( height, i ); 661 } 662 } 663 664 switch( format ) { 665 case TEXFMT_INVALID: 666 case TEXFMT_DEPTH: 667 break; 668 669 case TEXFMT_R_U8: 670 case TEXFMT_R_U8NORM: 671 return total_dim * 1 * sizeof( u8 ); 672 case TEXFMT_R_U16: 673 return total_dim * 1 * sizeof( u16 ); 674 case TEXFMT_R_FLOAT: 675 return total_dim * 1 * sizeof( float ); 676 677 case TEXFMT_RGB_U8: 678 return total_dim * 3 * sizeof( u8 ); 679 case TEXFMT_RGB_U8_SRGB: 680 return total_dim * 3 * sizeof( u8 ); 681 case TEXFMT_RGB_HALF: 682 return total_dim * 3 * sizeof( u16 ); 683 case TEXFMT_RGB_FLOAT: 684 return total_dim * 3 * sizeof( float ); 685 686 case TEXFMT_RGBA_U8: 687 return total_dim * 4 * sizeof( u8 ); 688 case TEXFMT_RGBA_U8_SRGB: 689 return total_dim * 4 * sizeof( u8 ); 690 case TEXFMT_RGBA_FLOAT: 691 return total_dim * 4 * sizeof( float ); 692 693 case TEXFMT_BC1: 694 case TEXFMT_BC1_SRGB: 695 return total_dim / 2; 696 case TEXFMT_BC4: 697 return total_dim / 2; 698 case TEXFMT_BC5: 699 return total_dim; 700 } 701 702 FATAL( "unsupported TextureFormat: {}", format ); 703 return GL_INVALID_ENUM; 704 } 705 706 static Texture new_texture( TextureConfig config, int msaa_samples ) { 707 ASSERT( config.format != TEXFMT_INVALID ); 708 ASSERT( !is_compressed( config.format ) || msaa_samples == 0 ); 709 ASSERT( !config.has_mipmaps ); // TODO 710 711 GLenum target = msaa_samples == 0 ? GL_TEXTURE_2D : GL_TEXTURE_2D_MULTISAMPLE; 712 713 GLuint texture; 714 glGenTextures( 1, &texture ); 715 // TODO: should probably update the gl state since we bind a new texture 716 glBindTexture( target, texture ); 717 718 if( msaa_samples == 0 ) { 719 glTexParameteri( target, GL_TEXTURE_WRAP_S, texturewrap_to_glenum( config.wrap ) ); 720 glTexParameteri( target, GL_TEXTURE_WRAP_T, texturewrap_to_glenum( config.wrap ) ); 721 722 GLenum min_filter, mag_filter; 723 texturefilter_to_glenum( config.filter, config.has_mipmaps, &min_filter, &mag_filter ); 724 glTexParameteri( target, GL_TEXTURE_MIN_FILTER, min_filter ); 725 glTexParameteri( target, GL_TEXTURE_MAG_FILTER, mag_filter ); 726 727 if( config.wrap == TEXWRAP_BORDER ) { 728 glTexParameterfv( target, GL_TEXTURE_BORDER_COLOR, ( GLfloat * ) &config.border_colour ); 729 } 730 } 731 732 GLenum internal_format = texfmt_to_internal_format( config.format ); 733 734 if( is_compressed( config.format ) ) { 735 u32 dxt_size = texture_byte_size( config.width, config.height, config.format, false ); 736 glCompressedTexImage2D( GL_TEXTURE_2D, 0, internal_format, 737 config.width, config.height, 0, dxt_size, config.data ); 738 } 739 else { 740 GLenum channels = GL_INVALID_ENUM; 741 GLenum type = GL_INVALID_ENUM; 742 743 switch( config.format ) { 744 case TEXFMT_R_U8: 745 case TEXFMT_R_U8NORM: 746 channels = GL_RED; 747 type = GL_UNSIGNED_BYTE; 748 break; 749 case TEXFMT_R_U16: 750 channels = GL_RED; 751 type = GL_UNSIGNED_SHORT; 752 break; 753 case TEXFMT_R_FLOAT: 754 channels = GL_RED; 755 type = GL_FLOAT; 756 break; 757 758 case TEXFMT_RGB_U8: 759 case TEXFMT_RGB_U8_SRGB: 760 channels = GL_RGB; 761 type = GL_UNSIGNED_BYTE; 762 break; 763 case TEXFMT_RGB_HALF: 764 channels = GL_RGB; 765 type = GL_HALF_FLOAT; 766 break; 767 case TEXFMT_RGB_FLOAT: 768 channels = GL_RGB; 769 type = GL_FLOAT; 770 break; 771 772 case TEXFMT_RGBA_U8: 773 case TEXFMT_RGBA_U8_SRGB: 774 channels = GL_RGBA; 775 type = GL_UNSIGNED_BYTE; 776 break; 777 case TEXFMT_RGBA_FLOAT: 778 channels = GL_RGBA; 779 type = GL_FLOAT; 780 break; 781 782 case TEXFMT_DEPTH: 783 channels = GL_DEPTH_COMPONENT; 784 type = GL_FLOAT; 785 break; 786 787 default: 788 FATAL( "implement channel/type selection for {}", config.format ); 789 break; 790 } 791 792 if( msaa_samples == 0 ) { 793 glTexImage2D( GL_TEXTURE_2D, 0, internal_format, 794 config.width, config.height, 0, channels, type, config.data ); 795 } 796 else { 797 glTexImage2DMultisample( GL_TEXTURE_2D_MULTISAMPLE, msaa_samples, 798 internal_format, config.width, config.height, GL_TRUE ); 799 } 800 } 801 802 return texture; 803 } 804 805 Texture renderer_new_texture( const TextureConfig & config ) { 806 return new_texture( config, 0 ); 807 } 808 809 void renderer_delete_texture( Texture texture ) { 810 glDeleteTextures( 1, &texture ); 811 } 812 813 static GLenum framebufferattachment_to_glenum( FramebufferAttachment attachment ) { 814 switch( attachment ) { 815 case FB_COLOUR: return GL_COLOR_ATTACHMENT0; 816 case FB_DEPTH: return GL_DEPTH_ATTACHMENT; 817 case FB_NORMAL: return GL_COLOR_ATTACHMENT1; 818 } 819 820 FATAL( "invalid FramebufferAttachment: {}", attachment ); 821 return GL_INVALID_ENUM; 822 } 823 824 FB renderer_new_fb( const FramebufferConfig & config ) { 825 GLuint fbo; 826 glGenFramebuffers( 1, &fbo ); 827 glBindFramebuffer( GL_FRAMEBUFFER, fbo ); 828 829 FB fb; 830 fb.fbo = fbo; 831 832 u32 width = 0; 833 u32 height = 0; 834 GLenum bufs[ OUTPUTS_COUNT ]; 835 836 for( size_t i = 0; i < config.textures.size(); i++ ) { 837 bufs[ i ] = GL_NONE; 838 839 const TextureConfig & texture_config = config.textures[ i ].config; 840 if( texture_config.format == TEXFMT_INVALID ) 841 continue; 842 843 ASSERT( !is_compressed( texture_config.format ) ); 844 845 GLenum attachment = framebufferattachment_to_glenum( config.textures[ i ].attachment ); 846 Texture texture = new_texture( texture_config, config.msaa_samples ); 847 848 GLenum target = config.msaa_samples == 0 ? GL_TEXTURE_2D : GL_TEXTURE_2D_MULTISAMPLE; 849 glFramebufferTexture2D( GL_FRAMEBUFFER, attachment, target, texture, 0 ); 850 851 width = texture_config.width; 852 height = texture_config.height; 853 fb.textures[ i ] = texture; 854 if( config.textures[ i ].attachment != FB_DEPTH ) 855 bufs[ i ] = attachment; 856 } 857 858 glDrawBuffers( ARRAY_COUNT( bufs ), bufs ); 859 860 ASSERT( glCheckFramebufferStatus( GL_FRAMEBUFFER ) == GL_FRAMEBUFFER_COMPLETE ); 861 ASSERT( width > 0 && height > 0 ); 862 glBindFramebuffer( GL_FRAMEBUFFER, 0 ); 863 864 fb.width = width; 865 fb.height = height; 866 867 return fb; 868 } 869 870 FB renderer_new_fb( TextureConfig texture_config, FramebufferAttachment attachment ) { 871 FramebufferConfig config; 872 config.textures[ 0 ].config = texture_config; 873 config.textures[ 0 ].attachment = attachment; 874 return renderer_new_fb( config ); 875 } 876 877 void renderer_delete_fb( FB fb ) { 878 if( fb.fbo == 0 ) 879 return; 880 881 glDeleteFramebuffers( 1, &fb.fbo ); 882 for( Texture texture : fb.textures ) { 883 if( texture != 0 ) { 884 glDeleteTextures( 1, &texture ); 885 } 886 } 887 } 888 889 static GLuint new_gl_shader( GLenum type, array< const char * > srcs ) { 890 StaticArray< const char *, 16 > full_srcs; 891 full_srcs[ 0 ] = "#version 330\n"; 892 full_srcs[ 1 ] = type == GL_VERTEX_SHADER ? "#define VERTEX_SHADER 1\n" : "#define FRAGMENT_SHADER 1\n"; 893 GLsizei n = 2; 894 for( size_t i = 0; i < srcs.n; i++ ) { 895 if( srcs[ i ] != NULL ) { 896 full_srcs[ n ] = srcs[ i ]; 897 n++; 898 } 899 } 900 901 GLuint shader = glCreateShader( type ); 902 glShaderSource( shader, n, full_srcs.ptr(), NULL ); 903 glCompileShader( shader ); 904 905 GLint status; 906 glGetShaderiv( shader, GL_COMPILE_STATUS, &status ); 907 908 if( status == GL_FALSE ) { 909 char buf[ 1024 ]; 910 glGetShaderInfoLog( shader, sizeof( buf ), NULL, buf ); 911 WARN( "shader compilation failed: {}", buf ); 912 glDeleteShader( shader ); 913 914 // static char src[ 65536 ]; 915 // glGetShaderSource( shader, sizeof( src ), NULL, src ); 916 // printf( "%s\n", src ); 917 918 return 0; 919 } 920 921 return shader; 922 } 923 924 Shader renderer_new_shader( array< const char * > srcs ) { 925 Shader shader = { }; 926 927 GLuint vs = new_gl_shader( GL_VERTEX_SHADER, srcs ); 928 GLuint fs = new_gl_shader( GL_FRAGMENT_SHADER, srcs ); 929 930 if( vs == 0 || fs == 0 ) { 931 return shader; 932 } 933 934 GLuint program = glCreateProgram(); 935 glAttachShader( program, vs ); 936 glAttachShader( program, fs ); 937 938 glBindAttribLocation( program, ATTR_POSITION, "position" ); 939 glBindAttribLocation( program, ATTR_NORMAL, "normal" ); 940 glBindAttribLocation( program, ATTR_TEX_COORD0, "tex_coord0" ); 941 glBindAttribLocation( program, ATTR_TEX_COORD1, "tex_coord1" ); 942 glBindAttribLocation( program, ATTR_COLOUR, "colour" ); 943 glBindAttribLocation( program, ATTR_JOINTS, "joints" ); 944 glBindAttribLocation( program, ATTR_WEIGHTS, "weights" ); 945 glBindAttribLocation( program, ATTR_MODEL_TO_WORLD_COL0, "model_to_world" ); 946 947 glBindFragDataLocation( program, 0, "output_albedo" ); 948 glBindFragDataLocation( program, 1, "output_normal" ); 949 950 glLinkProgram( program ); 951 952 glDeleteShader( vs ); 953 glDeleteShader( fs ); 954 955 GLint status; 956 glGetProgramiv( program, GL_LINK_STATUS, &status ); 957 if( status == GL_FALSE ) { 958 char buf[ 1024 ]; 959 glGetProgramInfoLog( program, sizeof( buf ), NULL, buf ); 960 WARN( "shader linking failed: {}", buf ); 961 962 return shader; 963 } 964 965 966 glUseProgram( program ); 967 shader.program = program; 968 969 GLint count, maxlen; 970 glGetProgramiv( program, GL_ACTIVE_UNIFORMS, &count ); 971 glGetProgramiv( program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxlen ); 972 973 size_t numtextures = 0; 974 for( GLint i = 0; i < count; i++ ) { 975 char name[ 128 ]; 976 GLint size, len; 977 GLenum type; 978 glGetActiveUniform( program, i, sizeof( name ), &len, &size, &type, name ); 979 980 if( type == GL_SAMPLER_2D ) { 981 glUniform1i( glGetUniformLocation( program, name ), numtextures ); 982 shader.textures[ numtextures ] = fnv1a32( name, len ); 983 numtextures++; 984 } 985 } 986 987 glGetProgramiv( program, GL_ACTIVE_UNIFORM_BLOCKS, &count ); 988 glGetProgramiv( program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &maxlen ); 989 990 size_t numubos = 0; 991 for( GLint i = 0; i < count; i++ ) { 992 char name[ 128 ]; 993 GLint len; 994 glGetActiveUniformBlockName( program, i, sizeof( name ), &len, name ); 995 glUniformBlockBinding( program, i, numubos ); 996 shader.uniforms[ numubos ] = fnv1a32( name, len ); 997 numubos++; 998 } 999 1000 glUseProgram( 0 ); 1001 1002 return shader; 1003 } 1004 1005 void renderer_delete_shader( Shader shader ) { 1006 glDeleteProgram( shader.program ); 1007 } 1008 1009 static void vertexfmt_to_glenum( VertexFormat format, GLenum * type, int * components ) { 1010 switch( format ) { 1011 case VERTEXFMT_U8x3: 1012 *type = GL_UNSIGNED_BYTE; 1013 *components = 3; 1014 break; 1015 case VERTEXFMT_U8x4: 1016 *type = GL_UNSIGNED_BYTE; 1017 *components = 4; 1018 break; 1019 1020 case VERTEXFMT_U16x4: 1021 *type = GL_UNSIGNED_SHORT; 1022 *components = 4; 1023 break; 1024 1025 case VERTEXFMT_HALFx2: 1026 *type = GL_HALF_FLOAT; 1027 *components = 2; 1028 break; 1029 case VERTEXFMT_HALFx3: 1030 *type = GL_HALF_FLOAT; 1031 *components = 3; 1032 break; 1033 case VERTEXFMT_HALFx4: 1034 *type = GL_HALF_FLOAT; 1035 *components = 4; 1036 break; 1037 1038 case VERTEXFMT_FLOATx2: 1039 *type = GL_FLOAT; 1040 *components = 2; 1041 break; 1042 case VERTEXFMT_FLOATx3: 1043 *type = GL_FLOAT; 1044 *components = 3; 1045 break; 1046 case VERTEXFMT_FLOATx4: 1047 *type = GL_FLOAT; 1048 *components = 4; 1049 break; 1050 } 1051 } 1052 1053 static void setup_vertex_attrib( GLuint index, VertexFormat format, u32 stride = 0, u32 offset = 0 ) { 1054 GLvoid * gl_offset = checked_cast< GLvoid * >( checked_cast< uptr >( offset ) ); 1055 GLenum type; 1056 int components; 1057 vertexfmt_to_glenum( format, &type, &components ); 1058 1059 GLboolean normalized = index == ATTR_WEIGHTS; 1060 1061 glEnableVertexAttribArray( index ); 1062 if( index == ATTR_JOINTS ) 1063 glVertexAttribIPointer( index, components, type, stride, gl_offset ); 1064 else 1065 glVertexAttribPointer( index, components, type, normalized, stride, gl_offset ); 1066 } 1067 1068 Mesh renderer_new_mesh( MeshConfig config ) { 1069 ASSERT( config.num_vertices != 0 ); 1070 1071 switch( config.primitive_type ) { 1072 case PRIMITIVETYPE_TRIANGLES: 1073 ASSERT( config.num_vertices % 3 == 0 ); 1074 break; 1075 case PRIMITIVETYPE_TRIANGLE_STRIP: 1076 ASSERT( config.num_vertices >= 3 ); 1077 break; 1078 case PRIMITIVETYPE_POINTS: 1079 break; 1080 case PRIMITIVETYPE_LINES: 1081 ASSERT( config.num_vertices % 2 == 0 ); 1082 break; 1083 } 1084 1085 GLuint vao; 1086 glGenVertexArrays( 1, &vao ); 1087 glBindVertexArray( vao ); 1088 1089 if( config.unified_buffer == 0 ) { 1090 ASSERT( config.positions != 0 ); 1091 1092 glBindBuffer( GL_ARRAY_BUFFER, config.positions ); 1093 setup_vertex_attrib( ATTR_POSITION, config.positions_format ); 1094 1095 if( config.normals != 0 ) { 1096 glBindBuffer( GL_ARRAY_BUFFER, config.normals ); 1097 setup_vertex_attrib( ATTR_NORMAL, config.normals_format ); 1098 } 1099 1100 if( config.tex_coords0 != 0 ) { 1101 glBindBuffer( GL_ARRAY_BUFFER, config.tex_coords0 ); 1102 setup_vertex_attrib( ATTR_TEX_COORD0, config.tex_coords0_format ); 1103 } 1104 1105 if( config.tex_coords1 != 0 ) { 1106 glBindBuffer( GL_ARRAY_BUFFER, config.tex_coords1 ); 1107 setup_vertex_attrib( ATTR_TEX_COORD1, config.tex_coords1_format ); 1108 } 1109 1110 if( config.colours != 0 ) { 1111 glBindBuffer( GL_ARRAY_BUFFER, config.colours ); 1112 setup_vertex_attrib( ATTR_COLOUR, config.colours_format ); 1113 } 1114 1115 if( config.joints != 0 ) { 1116 glBindBuffer( GL_ARRAY_BUFFER, config.joints ); 1117 setup_vertex_attrib( ATTR_JOINTS, config.joints_format ); 1118 } 1119 1120 if( config.weights != 0 ) { 1121 glBindBuffer( GL_ARRAY_BUFFER, config.weights ); 1122 setup_vertex_attrib( ATTR_WEIGHTS, config.weights_format ); 1123 } 1124 } 1125 else { 1126 ASSERT( config.stride != 0 ); 1127 1128 glBindBuffer( GL_ARRAY_BUFFER, config.unified_buffer ); 1129 1130 setup_vertex_attrib( ATTR_POSITION, config.positions_format, config.stride, config.positions_offset ); 1131 1132 if( config.normals_offset != 0 ) { 1133 setup_vertex_attrib( ATTR_NORMAL, config.normals_format, config.stride, config.normals_offset ); 1134 } 1135 1136 if( config.tex_coords0_offset != 0 ) { 1137 setup_vertex_attrib( ATTR_TEX_COORD0, config.tex_coords0_format, config.stride, config.tex_coords0_offset ); 1138 } 1139 1140 if( config.tex_coords1_offset != 0 ) { 1141 setup_vertex_attrib( ATTR_TEX_COORD1, config.tex_coords1_format, config.stride, config.tex_coords1_offset ); 1142 } 1143 1144 if( config.colours_offset != 0 ) { 1145 setup_vertex_attrib( ATTR_COLOUR, config.colours_format, config.stride, config.colours_offset ); 1146 } 1147 1148 if( config.joints_offset != 0 ) { 1149 setup_vertex_attrib( ATTR_JOINTS, config.joints_format, config.stride, config.joints_offset ); 1150 } 1151 1152 if( config.weights_offset != 0 ) { 1153 setup_vertex_attrib( ATTR_WEIGHTS, config.weights_format, config.stride, config.weights_offset ); 1154 } 1155 } 1156 1157 if( config.indices != 0 ) { 1158 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, config.indices ); 1159 } 1160 1161 glBindVertexArray( 0 ); 1162 1163 Mesh mesh = { }; 1164 mesh.num_vertices = config.num_vertices; 1165 mesh.primitive_type = config.primitive_type; 1166 mesh.vao = vao; 1167 if( config.unified_buffer == 0 ) { 1168 mesh.positions = config.positions; 1169 mesh.normals = config.normals; 1170 mesh.tex_coords0 = config.tex_coords0; 1171 mesh.tex_coords1 = config.tex_coords1; 1172 mesh.colours = config.colours; 1173 mesh.joints = config.joints; 1174 mesh.weights = config.weights; 1175 } 1176 else { 1177 mesh.positions = config.unified_buffer; 1178 } 1179 mesh.indices = config.indices; 1180 mesh.indices_format = config.indices_format; 1181 1182 return mesh; 1183 } 1184 1185 void renderer_delete_mesh( const Mesh & mesh ) { 1186 DeleteCommand command; 1187 command.type = DELETE_MESH; 1188 command.mesh = mesh; 1189 deletes.add( command ); 1190 } 1191 1192 void renderer_draw_mesh( const Mesh & mesh, const RenderState & render_state ) { 1193 ASSERT( in_frame ); 1194 ASSERT( render_state.pass != U8_MAX ); 1195 ASSERT( render_state.shader != NULL ); 1196 1197 DrawCall dc; 1198 dc.mesh = mesh; 1199 dc.render_state = render_state; 1200 dc.num_instances = 0; 1201 dc.instance_data = 0; 1202 draw_calls.add( dc ); 1203 1204 draw_calls_this_frame++; 1205 vertices_this_frame += mesh.num_vertices; 1206 } 1207 1208 void renderer_draw_instances( const Mesh & mesh, const RenderState & render_state, u32 num_instances, VB instance_data ) { 1209 ASSERT( in_frame ); 1210 1211 if( num_instances == 0 ) { 1212 return; 1213 } 1214 1215 DrawCall dc; 1216 dc.mesh = mesh; 1217 dc.render_state = render_state; 1218 dc.num_instances = num_instances; 1219 dc.instance_data = instance_data; 1220 draw_calls.add( dc ); 1221 1222 draw_calls_this_frame++; 1223 vertices_this_frame += mesh.num_vertices * num_instances; 1224 } 1225 1226 void renderer_draw_fullscreen_triangle( const RenderState & render_state ) { 1227 renderer_draw_mesh( fullscreen_triangle, render_state ); 1228 }