medfall

A super great game engine
Log | Files | Refs

commit 11a7af72bf36a3fde504a61f7f3fe4810e590581
parent 63f14949f9a472c0c412d2187a91151dd2c674ba
Author: Michael Savage <mikejsavage@gmail.com>
Date:   Sat,  3 Aug 2019 21:35:54 +0300

Out of order drawcall submission/named render passes

Diffstat:
Marray.h | 3++-
Mbsp.cc | 52+++++++++++++++++++++++++---------------------------
Mclipmap.cc | 23+++++++++++++++++------
Mfullscreen.cc | 24+++++++++---------------
Mgltf.cc | 7+++++--
Mmsdf.cc | 12+++++++-----
Mrenderer.cc | 109++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mrenderer.h | 13++++++++-----
Mshadow_map.cc | 24++++++++++++------------
Mskybox.cc | 3++-
Mskybox.h | 2+-
Mtext_renderer.cc | 7++++---
Mtext_renderer.h | 4++--
13 files changed, 149 insertions(+), 134 deletions(-)

diff --git a/array.h b/array.h @@ -298,9 +298,10 @@ public: free( elems ); } - void add( const T & x ) { + size_t add( const T & x ) { size_t idx = extend( 1 ); elems[ idx ] = x; + return idx; } void clear() { diff --git a/bsp.cc b/bsp.cc @@ -447,6 +447,22 @@ GAME_FRAME( game_frame ) { renderer_begin_frame(); + u8 write_gbuffer_pass = renderer_add_pass( "World outlines gbuffer", world_depth_and_normals, RENDERER_CLEAR_COLOUR_DO, RENDERER_CLEAR_DEPTH_DO ); + + u8 write_teammate_depth_pass; + { + RenderPass pass; + pass.name = "Write teammate depth"; + pass.target = model_depth; + pass.clear_depth = true; + pass.depth = 0.0f; + write_teammate_depth_pass = renderer_add_pass( pass ); + } + + u8 teammate_edge_detection_pass = renderer_add_pass( "Teammate edge detection", model_depth_outline ); + u8 compose_pass = renderer_add_pass( "Compose", RENDERER_CLEAR_COLOUR_DO, RENDERER_CLEAR_DEPTH_DO ); + u8 ui_pass = renderer_add_pass( "UI" ); + m4 P = m4_perspective( 90, get_aspect_ratio(), NEAR_PLANE_DEPTH, FAR_PLANE_DEPTH ); m4 V = m4_view( forward, right, up, game->pos ); @@ -456,9 +472,8 @@ GAME_FRAME( game_frame ) { // depth/normals pre pass { - renderer_begin_pass( world_depth_and_normals, RENDERER_CLEAR_COLOUR_DO, RENDERER_CLEAR_DEPTH_DO ); - RenderState render_state; + render_state.pass = write_gbuffer_pass; render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS_TO_GBUFFER ); render_state.set_uniform( "view", view_uniforms ); render_state.set_uniform( "model", world_model_uniforms ); @@ -489,48 +504,35 @@ GAME_FRAME( game_frame ) { // render_state.set_uniform( "model", tree_model_uniforms ); renderer_draw_mesh( tree_mesh, render_state ); - - renderer_end_pass(); } // model depth { - RenderPassConfig pass; - pass.target = model_depth; - pass.clear_depth = true; - pass.depth = 0.0f; - renderer_begin_pass( pass ); - RenderState render_state; + render_state.pass = write_teammate_depth_pass; render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS_TO_GBUFFER ); render_state.depth_func = DEPTHFUNC_ALWAYS; render_state.set_uniform( "view", view_uniforms ); render_state.set_uniform( "model", tree_model_uniforms ); renderer_draw_mesh( tree_mesh, render_state ); - - renderer_end_pass(); } // model depth edge detection { - renderer_begin_pass( model_depth_outline, RENDERER_CLEAR_COLOUR_DONT, RENDERER_CLEAR_DEPTH_DONT ); - RenderState render_state; + render_state.pass = teammate_edge_detection_pass; render_state.shader = get_shader( SHADER_DEPTH_EDGE ); render_state.depth_func = DEPTHFUNC_ALWAYS; render_state.set_texture( "model_depth", model_depth.textures[ OUTPUT_DEPTH ] ); renderer_draw_fullscreen_triangle( render_state ); - - renderer_end_pass(); } // compose { - renderer_begin_pass( RENDERER_CLEAR_COLOUR_DO, RENDERER_CLEAR_DEPTH_DO ); - RenderState render_state; + render_state.pass = compose_pass; render_state.shader = get_shader( SHADER_GBUFFER ); render_state.set_uniform( "view", view_uniforms ); render_state.set_uniform( "model", world_model_uniforms ); @@ -566,13 +568,8 @@ GAME_FRAME( game_frame ) { render_state.set_uniform( "model", tree_model_uniforms ); renderer_draw_mesh( tree_mesh, render_state ); - - renderer_end_pass(); } - // UI pass - renderer_begin_pass( RENDERER_CLEAR_COLOUR_DONT, RENDERER_CLEAR_DEPTH_DONT ); - // draw crosshair { const float aspect = get_aspect_ratio(); @@ -605,6 +602,7 @@ GAME_FRAME( game_frame ) { red ); RenderState render_state; + render_state.pass = ui_pass; render_state.shader = get_shader( SHADER_UI ); render_state.depth_func = DEPTHFUNC_ALWAYS; immediate_render( render_state ); @@ -641,6 +639,7 @@ GAME_FRAME( game_frame ) { red ); RenderState render_state; + render_state.pass = ui_pass; render_state.shader = get_shader( SHADER_UI ); render_state.depth_func = DEPTHFUNC_ALWAYS; immediate_render( render_state ); @@ -649,7 +648,7 @@ GAME_FRAME( game_frame ) { v2 p = ( a + 1.0f ) / 2.0f; p.y = 1.0f - p.y; p *= v2( window_size.x, window_size.y ); - draw_centered_text( "DEFEND", p.x, p.y - 16 - pxsize / 2, 12 ); + draw_centered_text( ui_pass, "DEFEND", p.x, p.y - 16 - pxsize / 2, 12 ); } } @@ -660,10 +659,9 @@ GAME_FRAME( game_frame ) { right.x, right.y, right.z, up.x, up.y, up.z ); - draw_text( buf, 2, 2, 16 ); - draw_text( str< 128 >( "drawcalls = {}, tris = {}", renderer_num_draw_calls(), renderer_num_vertices() / 3 ).c_str(), 2, 20, 16 ); + draw_text( ui_pass, buf, 2, 2, 16 ); + draw_text( ui_pass, str< 128 >( "drawcalls = {}, tris = {}", renderer_num_draw_calls(), renderer_num_vertices() / 3 ).c_str(), 2, 20, 16 ); } - renderer_end_pass(); renderer_end_frame(); } diff --git a/clipmap.cc b/clipmap.cc @@ -755,7 +755,11 @@ GAME_FRAME( game_frame ) { v3 sun_dir = v3( -cosf( game->sun_angle ), 0, sinf( game->sun_angle ) ); renderer_begin_frame(); - renderer_begin_pass( RENDERER_CLEAR_COLOUR_DO, RENDERER_CLEAR_DEPTH_DO ); + + u8 world_pass = renderer_add_pass( "Render world", RENDERER_CLEAR_COLOUR_DO, RENDERER_CLEAR_DEPTH_DO ); + u8 ents_pass = renderer_add_pass( "Render entities" ); + u8 sky_pass = renderer_add_pass( "Render sky" ); + u8 ui_pass = renderer_add_pass( "Render UI" ); UniformBinding view_uniforms = renderer_uniforms( V, P, game->pos ); UniformBinding inf_view_uniforms = renderer_uniforms( V, Pinf, game->pos ); @@ -774,6 +778,7 @@ GAME_FRAME( game_frame ) { // draw terrain { RenderState render_state; + render_state.pass = world_pass; render_state.shader = get_shader( SHADER_CLIPMAP ); render_state.set_uniform( "view", view_uniforms ); render_state.set_uniform( "sun", sun_uniforms ); @@ -866,6 +871,7 @@ GAME_FRAME( game_frame ) { float scale = checked_cast< float >( u32( 1 ) << ( NUM_CLIPMAP_LEVELS - 1 ) ); RenderState skirt_render_state; + skirt_render_state.pass = world_pass; skirt_render_state.shader = get_shader( SHADER_CLIPMAP_SKIRT ); skirt_render_state.set_uniform( "view", inf_view_uniforms ); skirt_render_state.set_uniform( "sun", sun_uniforms ); @@ -878,6 +884,7 @@ GAME_FRAME( game_frame ) { // draw trees { RenderState render_state; + render_state.pass = ents_pass; render_state.shader = get_shader( SHADER_TREE ); render_state.set_uniform( "view", view_uniforms ); render_state.set_uniform( "sun", renderer_uniforms( sun_dir ) ); @@ -918,6 +925,7 @@ GAME_FRAME( game_frame ) { red ); RenderState render_state; + render_state.pass = ui_pass; render_state.shader = get_shader( SHADER_UI ); render_state.depth_func = DEPTHFUNC_ALWAYS; immediate_render( render_state ); @@ -960,6 +968,7 @@ GAME_FRAME( game_frame ) { } RenderState fireball_render_state; + fireball_render_state.pass = ents_pass; fireball_render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS ); fireball_render_state.set_uniform( "view", view_uniforms ); immediate_render( fireball_render_state ); @@ -977,12 +986,13 @@ GAME_FRAME( game_frame ) { } RenderState explosion_render_state; + explosion_render_state.pass = ents_pass; explosion_render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS ); explosion_render_state.set_uniform( "view", view_uniforms ); immediate_render( explosion_render_state ); } - skybox_render( &game->skybox, Vsky, Pinf, game->sun_angle, sun_dir ); + skybox_render( &game->skybox, sky_pass, Vsky, Pinf, game->sun_angle, sun_dir ); // networking { @@ -1081,6 +1091,7 @@ GAME_FRAME( game_frame ) { } RenderState impact_render_state; + impact_render_state.pass = world_pass; impact_render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS ); impact_render_state.set_uniform( "view", view_uniforms ); immediate_render( impact_render_state ); @@ -1092,6 +1103,7 @@ GAME_FRAME( game_frame ) { draw_qt( MinMaxu32( mins, maxs ), clipmap.quadtree.nodes, 0 ); RenderState render_state; + render_state.pass = world_pass; render_state.shader = get_shader( SHADER_WIREFRAME ); render_state.set_uniform( "view", view_uniforms ); render_state.wireframe = true; @@ -1102,11 +1114,10 @@ GAME_FRAME( game_frame ) { { const str< 128 > status( "Frame time: {.1}ms FPS: {.1} {}", dt * 1000.0f, 1.0f / dt, connected ? "connected!" : "connecting" ); - draw_text( status.c_str(), 2, 2, 16.0f ); - draw_text( str< 128 >( "pos = {.1} vel = {.1}", game->pos, game->velocity ).c_str(), 2, 20, 16 ); - draw_text( str< 128 >( "drawcalls = {}, tris = {}", renderer_num_draw_calls(), renderer_num_vertices() / 3 ).c_str(), 2, 38, 16 ); + draw_text( ui_pass, status.c_str(), 2, 2, 16.0f ); + draw_text( ui_pass, str< 128 >( "pos = {.1} vel = {.1}", game->pos, game->velocity ).c_str(), 2, 20, 16 ); + draw_text( ui_pass, str< 128 >( "drawcalls = {}, tris = {}", renderer_num_draw_calls(), renderer_num_vertices() / 3 ).c_str(), 2, 38, 16 ); } - renderer_end_pass(); renderer_end_frame(); } diff --git a/fullscreen.cc b/fullscreen.cc @@ -147,6 +147,11 @@ GAME_FRAME( game_frame ) { renderer_begin_frame(); + u8 shadowmap_pass = renderer_add_pass( "Write shadowmap", shadow_fb, RENDERER_CLEAR_COLOUR_DONT, RENDERER_CLEAR_DEPTH_DO ); + u8 gbuffer_pass = renderer_add_pass( "Write gbuffer", gbuffer, RENDERER_CLEAR_COLOUR_DO, RENDERER_CLEAR_DEPTH_DO ); + u8 compose_pass = renderer_add_pass( "Compose" ); + u8 ui_pass = renderer_add_pass( "Render UI" ); + UniformBinding light_view_uniforms; { @@ -161,22 +166,18 @@ GAME_FRAME( game_frame ) { // fill shadow map { - renderer_begin_pass( shadow_fb, RENDERER_CLEAR_COLOUR_DONT, RENDERER_CLEAR_DEPTH_DO ); - RenderState render_state; + render_state.pass = shadowmap_pass; render_state.shader = get_shader( SHADER_WRITE_SHADOW_MAP ); render_state.set_uniform( "light_view", light_view_uniforms ); draw_scene( render_state ); - - renderer_end_pass(); } // fill gbuffers { - renderer_begin_pass( gbuffer, RENDERER_CLEAR_COLOUR_DO, RENDERER_CLEAR_DEPTH_DO ); - RenderState render_state; + render_state.pass = gbuffer_pass; render_state.shader = get_shader( SHADER_SHADOWED_VERTEX_COLOURS_TO_GBUFFER ); render_state.set_uniform( "view", renderer_uniforms( V, P, game->pos ) ); render_state.set_uniform( "light_view", light_view_uniforms ); @@ -184,15 +185,12 @@ GAME_FRAME( game_frame ) { render_state.set_texture( "dither_noise", renderer_blue_noise() ); draw_scene( render_state, true ); - - renderer_end_pass(); } // final pass { - renderer_begin_pass( RENDERER_CLEAR_COLOUR_DONT, RENDERER_CLEAR_DEPTH_DONT ); - RenderState render_state; + render_state.pass = compose_pass; render_state.shader = get_shader( SHADER_GBUFFER ); render_state.depth_func = DEPTHFUNC_DISABLED; render_state.set_texture( "outline_depth", gbuffer.textures[ OUTPUT_ALBEDO ] ); @@ -201,15 +199,11 @@ GAME_FRAME( game_frame ) { render_state.set_texture( "blue_noise", renderer_blue_noise() ); renderer_draw_fullscreen_triangle( render_state ); - - renderer_end_pass(); } { - renderer_begin_pass( RENDERER_CLEAR_COLOUR_DONT, RENDERER_CLEAR_DEPTH_DONT ); const str< 128 > status( "Frame time: {.1}ms FPS: {.1}", dt * 1000.0f, 1.0f / dt ); - draw_text( status.c_str(), 2, 2, 16 ); - renderer_end_pass(); + draw_text( ui_pass, status.c_str(), 2, 2, 16 ); } renderer_end_frame(); diff --git a/gltf.cc b/gltf.cc @@ -542,7 +542,8 @@ GAME_FRAME( game_frame ) { ComputeMatrixPalette( model.animation, sample_sqt, joint_matrices, skinning_matrices ); renderer_begin_frame(); - renderer_begin_pass( RENDERER_CLEAR_COLOUR_DO, RENDERER_CLEAR_DEPTH_DO ); + + u8 main_pass = renderer_add_pass( "Render frame", RENDERER_CLEAR_COLOUR_DO, RENDERER_CLEAR_DEPTH_DO ); UniformBinding view_uniforms = renderer_uniforms( V, P, game->pos ); UniformBinding model_uniforms = renderer_uniforms( y_up_to_z_up ); @@ -552,6 +553,7 @@ GAME_FRAME( game_frame ) { // draw skinned model { RenderState render_state; + render_state.pass = main_pass; render_state.shader = get_shader( SHADER_SKINNED_FLAT_VERTEX_COLOURS ); render_state.set_uniform( "view", view_uniforms ); render_state.set_uniform( "model", model_uniforms ); @@ -572,6 +574,7 @@ GAME_FRAME( game_frame ) { immediate_arrow( pos, up, 1, v4( 0, 1, 0, 1 ) ); RenderState render_state; + render_state.pass = main_pass; render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS ); render_state.set_uniform( "view", renderer_uniforms( V, P ) ); immediate_render( render_state ); @@ -591,11 +594,11 @@ GAME_FRAME( game_frame ) { } RenderState render_state; + render_state.pass = main_pass; render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS ); render_state.set_uniform( "view", renderer_uniforms( V, P ) ); immediate_render( render_state ); } - renderer_end_pass(); renderer_end_frame(); } diff --git a/msdf.cc b/msdf.cc @@ -35,7 +35,7 @@ static v2 glyph_bounds( u8 glyph, float scale ) { return v2(); } -static void msdf_text( const char * str, int x, int y, float scale ) { +static void msdf_text( u8 pass, const char * str, int x, int y, float scale ) { const v4 white( 1, 1, 1, 1 ); float height = font_information.max_y - font_information.min_y; @@ -90,6 +90,7 @@ static void msdf_text( const char * str, int x, int y, float scale ) { } RenderState render_state; + render_state.pass = pass; render_state.shader = get_shader( SHADER_MSDF ); render_state.set_texture( "atlas", atlas ); render_state.depth_func = DEPTHFUNC_DISABLED; @@ -102,7 +103,8 @@ static void msdf_text( const char * str, int x, int y, float scale ) { float lol = 0.5; GAME_FRAME( game_frame ) { - RenderPassConfig pass; + RenderPass pass; + pass.name = "Render frame"; pass.clear_colour = true; pass.colour = v4( 0.1, 0.1, 0.1, 0 ); @@ -112,7 +114,8 @@ GAME_FRAME( game_frame ) { lol += 0.1 * dt; renderer_begin_frame(); - renderer_begin_pass( pass ); + + u8 main_pass = renderer_add_pass( pass ); { // for( int i = 0; i < 8; i++ ) { @@ -133,9 +136,8 @@ GAME_FRAME( game_frame ) { y += 16 << i; } - msdf_text( "Thanks again!", 10, 200, 50 ); + msdf_text( main_pass, "Thanks again!", 10, 200, 50 ); } - renderer_end_pass(); renderer_end_frame(); } diff --git a/renderer.cc b/renderer.cc @@ -1,4 +1,4 @@ -#include "glad.h" +#include <algorithm> #include "intrinsics.h" #include "game.h" @@ -10,6 +10,8 @@ #include "obj.h" #include "fnv.h" +#include "glad.h" + STATIC_ASSERT( SAME_TYPE( VB, GLuint ) ); STATIC_ASSERT( SAME_TYPE( IB, GLuint ) ); STATIC_ASSERT( SAME_TYPE( Texture, GLuint ) ); @@ -52,11 +54,6 @@ struct DeleteCommand { }; }; -struct RenderPass { - size_t begin, one_past_end; - RenderPassConfig config; -}; - static DynamicArray< DrawCall > draw_calls; static DynamicArray< RenderPass > render_passes; static DynamicArray< DeleteCommand > deletes; @@ -64,9 +61,7 @@ static DynamicArray< DeleteCommand > deletes; static u32 draw_calls_this_frame; static u32 vertices_this_frame; -static RenderPass current_render_pass; static bool in_frame; -static bool in_pass; struct UBO { GLuint ubo; @@ -101,7 +96,6 @@ void renderer_init() { } in_frame = false; - in_pass = false; previous_fbo = 0; previous_viewport_width = 0; @@ -135,8 +129,8 @@ void renderer_begin_frame() { in_frame = true; draw_calls.clear(); - deletes.clear(); render_passes.clear(); + deletes.clear(); draw_calls_this_frame = 0; vertices_this_frame = 0; @@ -272,7 +266,18 @@ static void set_render_state( const RenderState & state ) { previous_render_state = state; } -static void bind_fb( FB fb ) { +static bool compare_drawcall( const DrawCall & a, const DrawCall & b ) { + if( a.render_state.pass != b.render_state.pass ) + return a.render_state.pass < b.render_state.pass; + return a.render_state.shader < b.render_state.shader; +} + +static void setup_render_pass( const RenderPass & pass ) { + if( GLAD_GL_KHR_debug != 0 ) { + glPushDebugGroup( GL_DEBUG_SOURCE_APPLICATION, 0, -1, pass.name ); + } + + const FB & fb = pass.target; if( fb.fbo != previous_fbo ) { glBindFramebuffer( GL_DRAW_FRAMEBUFFER, fb.fbo ); previous_fbo = fb.fbo; @@ -294,6 +299,17 @@ static void bind_fb( FB fb ) { glViewport( 0, 0, viewport_width, viewport_height ); } } + + GLbitfield clear_mask = 0; + clear_mask |= pass.clear_colour ? GL_COLOR_BUFFER_BIT : 0; + clear_mask |= pass.clear_depth ? GL_DEPTH_BUFFER_BIT : 0; + if( clear_mask != 0 ) { + if( pass.clear_colour ) + glClearColor( pass.colour.x, pass.colour.y, pass.colour.z, pass.colour.w ); + if( pass.clear_depth ) + glClearDepth( pass.depth ); + glClear( clear_mask ); + } } static void drawcall_single( const Mesh & mesh, const RenderState & state ) { @@ -335,7 +351,6 @@ static void drawcall_instanced( const Mesh & mesh, const RenderState & state, u3 } void renderer_end_frame() { - ASSERT( !in_pass ); ASSERT( in_frame ); in_frame = false; @@ -344,33 +359,28 @@ void renderer_end_frame() { glUnmapBuffer( GL_UNIFORM_BUFFER ); } - for( const RenderPass & pass : render_passes ) { - bind_fb( pass.config.target ); + std::sort( draw_calls.begin(), draw_calls.end(), compare_drawcall ); - GLbitfield clear_mask = 0; - if( pass.config.clear_colour ) - clear_mask |= GL_COLOR_BUFFER_BIT; - if( pass.config.clear_depth ) - clear_mask |= GL_DEPTH_BUFFER_BIT; - - if( clear_mask != 0 ) { - glClearColor( pass.config.colour.x, pass.config.colour.y, pass.config.colour.z, pass.config.colour.w ); - glClearDepth( pass.config.depth ); - glClear( clear_mask ); + u8 pass_idx = U8_MAX; + for( const DrawCall & dc : draw_calls ) { + if( dc.render_state.pass != pass_idx ) { + if( GLAD_GL_KHR_debug != 0 && pass_idx != U8_MAX ) + glPopDebugGroup(); + setup_render_pass( render_passes[ dc.render_state.pass ] ); + pass_idx = dc.render_state.pass; } - // TODO: sort draw calls - - for( const DrawCall & dc : draw_calls.slice( pass.begin, pass.one_past_end ) ) { - if( dc.num_instances == 0 ) { - drawcall_single( dc.mesh, dc.render_state ); - } - else { - drawcall_instanced( dc.mesh, dc.render_state, dc.num_instances, dc.instance_data ); - } + if( dc.num_instances == 0 ) { + drawcall_single( dc.mesh, dc.render_state ); + } + else { + drawcall_instanced( dc.mesh, dc.render_state, dc.num_instances, dc.instance_data ); } } + if( GLAD_GL_KHR_debug != 0 && pass_idx != U8_MAX ) + glPopDebugGroup(); + for( const DeleteCommand & del : deletes ) { switch( del.type ) { case DELETE_VB: @@ -409,33 +419,22 @@ void renderer_end_frame() { } } -void renderer_begin_pass( const RenderPassConfig & pass ) { - ASSERT( !in_pass ); - in_pass = true; - - current_render_pass.begin = draw_calls.size(); - current_render_pass.config = pass; +u8 renderer_add_pass( const RenderPass & pass ) { + return checked_cast< u8 >( render_passes.add( pass ) ); } -void renderer_begin_pass( FB target, ClearColourBool clear_colour, ClearDepthBool clear_depth ) { - RenderPassConfig pass; +u8 renderer_add_pass( const char * name, FB target, ClearColourBool clear_colour, ClearDepthBool clear_depth ) { + RenderPass pass; pass.target = target; + pass.name = name; pass.clear_colour = clear_colour == RENDERER_CLEAR_COLOUR_DO; pass.clear_depth = clear_depth == RENDERER_CLEAR_DEPTH_DO; - renderer_begin_pass( pass ); + return renderer_add_pass( pass ); } -void renderer_begin_pass( ClearColourBool clear_colour, ClearDepthBool clear_depth ) { +u8 renderer_add_pass( const char * name, ClearColourBool clear_colour, ClearDepthBool clear_depth ) { FB target = { }; - renderer_begin_pass( target, clear_colour, clear_depth ); -} - -void renderer_end_pass() { - ASSERT( in_pass ); - in_pass = false; - - current_render_pass.one_past_end = draw_calls.size(); - render_passes.add( current_render_pass ); + return renderer_add_pass( name, target, clear_colour, clear_depth ); } u32 renderer_num_draw_calls() { @@ -1163,7 +1162,9 @@ void renderer_delete_mesh( const Mesh & mesh ) { } void renderer_draw_mesh( const Mesh & mesh, const RenderState & render_state ) { - ASSERT( in_frame && in_pass ); + ASSERT( in_frame ); + ASSERT( render_state.pass != U8_MAX ); + ASSERT( render_state.shader != NULL ); DrawCall dc; dc.mesh = mesh; @@ -1177,7 +1178,7 @@ void renderer_draw_mesh( const Mesh & mesh, const RenderState & render_state ) { } void renderer_draw_instances( const Mesh & mesh, const RenderState & render_state, u32 num_instances, VB instance_data ) { - ASSERT( in_frame && in_pass ); + ASSERT( in_frame ); if( num_instances == 0 ) { return; diff --git a/renderer.h b/renderer.h @@ -129,6 +129,7 @@ struct RenderState { size_t num_uniforms = 0; size_t num_textures = 0; + u8 pass = U8_MAX; const Shader * shader = NULL; DepthFunc depth_func = DEPTHFUNC_LESS; CullFace cull_face = CULLFACE_BACK; @@ -264,7 +265,9 @@ struct TextureConfig { v4 border_colour; }; -struct RenderPassConfig { +struct RenderPass { + const char * name = NULL; + FB target = { }; bool clear_colour = false; @@ -290,12 +293,12 @@ void renderer_init(); void renderer_term(); void renderer_begin_frame(); -void renderer_begin_pass( const RenderPassConfig & pass ); -void renderer_begin_pass( FB target, ClearColourBool clear_colour, ClearDepthBool clear_depth ); -void renderer_begin_pass( ClearColourBool clear_colour, ClearDepthBool clear_depth ); -void renderer_end_pass(); void renderer_end_frame(); +u8 renderer_add_pass( const RenderPass & config ); +u8 renderer_add_pass( const char * name, ClearColourBool clear_colour = RENDERER_CLEAR_COLOUR_DONT, ClearDepthBool clear_depth = RENDERER_CLEAR_DEPTH_DONT ); +u8 renderer_add_pass( const char * name, FB target, ClearColourBool clear_colour = RENDERER_CLEAR_COLOUR_DONT, ClearDepthBool clear_depth = RENDERER_CLEAR_DEPTH_DONT ); + u32 renderer_num_draw_calls(); u32 renderer_num_vertices(); diff --git a/shadow_map.cc b/shadow_map.cc @@ -114,6 +114,10 @@ GAME_FRAME( game_frame ) { renderer_begin_frame(); + u8 write_shadowmap_pass = renderer_add_pass( "Write shadowmap", shadow_fb, RENDERER_CLEAR_COLOUR_DONT, RENDERER_CLEAR_DEPTH_DO ); + u8 world_pass = renderer_add_pass( "Render world", RENDERER_CLEAR_COLOUR_DO, RENDERER_CLEAR_DEPTH_DO ); + u8 ui_pass = renderer_add_pass( "Render UI" ); + UniformBinding light_view_uniforms; { @@ -128,30 +132,27 @@ GAME_FRAME( game_frame ) { // fill shadow map { - renderer_begin_pass( shadow_fb, RENDERER_CLEAR_COLOUR_DONT, RENDERER_CLEAR_DEPTH_DO ); - RenderState render_state; + render_state.pass = write_shadowmap_pass; render_state.shader = get_shader( SHADER_WRITE_SHADOW_MAP ); render_state.set_uniform( "light_view", light_view_uniforms ); draw_scene( render_state ); - - renderer_end_pass(); } - renderer_begin_pass( RENDERER_CLEAR_COLOUR_DO, RENDERER_CLEAR_DEPTH_DO ); - // render shadow map { - RenderState state; - state.shader = get_shader( SHADER_DEBUG_RENDER_SHADOW_MAP ); - state.set_texture( "tex", shadow_fb.textures[ OUTPUT_DEPTH ] ); - renderer_draw_mesh( square, state ); + RenderState render_state; + render_state.pass = ui_pass; + render_state.shader = get_shader( SHADER_DEBUG_RENDER_SHADOW_MAP ); + render_state.set_texture( "tex", shadow_fb.textures[ OUTPUT_DEPTH ] ); + renderer_draw_mesh( square, render_state ); } // draw world { RenderState render_state; + render_state.pass = world_pass; render_state.shader = get_shader( SHADER_SHADOWED_VERTEX_COLOURS ); render_state.set_uniform( "view", renderer_uniforms( V, P, game->pos ) ); render_state.set_uniform( "light_view", light_view_uniforms ); @@ -163,9 +164,8 @@ GAME_FRAME( game_frame ) { { const str< 128 > status( "Frame time: {.1}ms FPS: {.1}", dt * 1000.0f, 1.0f / dt ); - draw_text( status.c_str(), 2, 2, 16 ); + draw_text( ui_pass, status.c_str(), 2, 2, 16 ); } - renderer_end_pass(); renderer_end_frame(); } diff --git a/skybox.cc b/skybox.cc @@ -110,7 +110,7 @@ void skybox_init( Skybox * skybox ) { par_shapes_free_mesh( sphere ); } -void skybox_render( const Skybox * skybox, const m4 & Vsky, const m4 & P, float sun_angle, v3 sun_dir ) { +void skybox_render( const Skybox * skybox, u8 pass, const m4 & Vsky, const m4 & P, float sun_angle, v3 sun_dir ) { const float turbidity = 4.0f; const float normalized_sun_y = 1.1f; @@ -120,6 +120,7 @@ void skybox_render( const Skybox * skybox, const m4 & Vsky, const m4 & P, float Hosek hosek = compute_hosek( hosek_elevation, turbidity, normalized_sun_y ); RenderState render_state; + render_state.pass = pass; render_state.shader = get_shader( SHADER_SKYBOX ); render_state.set_uniform( "view", renderer_uniforms( Vsky, P ) ); render_state.set_uniform( "sky", renderer_uniforms( hosek.A, hosek.B, hosek.C, hosek.D, hosek.E, hosek.F, hosek.G, hosek.H, hosek.I, hosek.Z, sun_dir ) ); diff --git a/skybox.h b/skybox.h @@ -8,5 +8,5 @@ struct Skybox { }; void skybox_init( Skybox * skybox ); -void skybox_render( const Skybox * skybox, const m4 & V, const m4 & P, float sun_angle, v3 sun_dir ); +void skybox_render( const Skybox * skybox, u8 pass, const m4 & V, const m4 & P, float sun_angle, v3 sun_dir ); void skybox_destroy( Skybox * skybox ); diff --git a/text_renderer.cc b/text_renderer.cc @@ -91,7 +91,7 @@ float text_width( const char * str, float pixel_size ) { return width * scale; } -void draw_text( const char * str, int x, int y, float pixel_size ) { +void draw_text( u8 pass, const char * str, int x, int y, float pixel_size ) { const v4 white( 1, 1, 1, 1 ); size_t size_idx = 0; @@ -146,6 +146,7 @@ void draw_text( const char * str, int x, int y, float pixel_size ) { } RenderState render_state; + render_state.pass = pass; render_state.shader = get_shader( SHADER_TEXT ); render_state.set_uniform( "window", renderer_uniforms( get_window_size() ) ); render_state.set_texture( "atlas", atlas ); @@ -156,7 +157,7 @@ void draw_text( const char * str, int x, int y, float pixel_size ) { immediate_render( render_state ); } -void draw_centered_text( const char * str, int x, int y, float pixel_size ) { +void draw_centered_text( u8 pass, const char * str, int x, int y, float pixel_size ) { float w = text_width( str, pixel_size ); - draw_text( str, x - w / 2.0f, y, pixel_size ); + draw_text( pass, str, x - w / 2.0f, y, pixel_size ); } diff --git a/text_renderer.h b/text_renderer.h @@ -7,5 +7,5 @@ void text_renderer_term(); float text_width( const char * str, float pixel_size ); -void draw_text( const char * str, int x, int y, float pixel_size ); -void draw_centered_text( const char * str, int x, int y, float pixel_size ); +void draw_text( u8 pass, const char * str, int x, int y, float pixel_size ); +void draw_centered_text( u8 pass, const char * str, int x, int y, float pixel_size );