From f75701a9abf73435cfcc3322cd8788c0f3df5141 Mon Sep 17 00:00:00 2001 From: Stephen Saunders Date: Wed, 22 Sep 2021 17:40:11 -0400 Subject: [PATCH] Fix overwrite of RC_DRAW_VIEW_3D timestamps by RC_DRAW_VIEW_GUI rendering pass --- neo/renderer/OpenGL/RenderBackend_GL.cpp | 23 +++++- neo/renderer/RenderBackend.cpp | 29 +++++--- neo/renderer/RenderLog.cpp | 93 ++++++++++++------------ neo/renderer/RenderLog.h | 1 + neo/renderer/RenderSystem.cpp | 7 ++ neo/renderer/Vulkan/RenderBackend_VK.cpp | 1 + 6 files changed, 96 insertions(+), 58 deletions(-) diff --git a/neo/renderer/OpenGL/RenderBackend_GL.cpp b/neo/renderer/OpenGL/RenderBackend_GL.cpp index 26565f70..b9a72ca4 100644 --- a/neo/renderer/OpenGL/RenderBackend_GL.cpp +++ b/neo/renderer/OpenGL/RenderBackend_GL.cpp @@ -350,7 +350,7 @@ static void R_CheckPortableExtensions() #if defined(__APPLE__) // SRS - DSA not available in Apple OpenGL 4.1, but enable for OSX anyways since elapsed time query will be used to get timing info instead - glConfig.timerQueryAvailable = ( GLEW_ARB_timer_query != 0 || GLEW_EXT_timer_query != 0 ) && ( glConfig.vendor != VENDOR_INTEL || r_skipIntelWorkarounds.GetBool() ) && glConfig.driverType != GLDRV_OPENGL_MESA; + glConfig.timerQueryAvailable = ( GLEW_ARB_timer_query != 0 || GLEW_EXT_timer_query != 0 ); #else // GL_ARB_timer_query using the DSA interface glConfig.timerQueryAvailable = ( GLEW_ARB_direct_state_access != 0 && GLEW_ARB_timer_query != 0 ); @@ -1960,6 +1960,9 @@ void idRenderBackend::StereoRenderExecuteBackEndCommands( const emptyCommand_t* // off to a texture. bool foundEye[2] = { false, false }; + // SRS - Save glConfig.timerQueryAvailable state so it can be disabled for RC_DRAW_VIEW_GUI then restored after it is finished + const bool timerQueryAvailable = glConfig.timerQueryAvailable; + for( int stereoEye = 1; stereoEye >= -1; stereoEye -= 2 ) { // set up the target texture we will draw to @@ -1991,10 +1994,25 @@ void idRenderBackend::StereoRenderExecuteBackEndCommands( const emptyCommand_t* } foundEye[ targetEye ] = true; - DrawView( dsc, stereoEye ); if( cmds->commandId == RC_DRAW_VIEW_GUI ) { + // SRS - Capture separate timestamps for GUI rendering + renderLog.OpenMainBlock( MRB_DRAW_GUI ); + renderLog.OpenBlock( "Render_DrawViewGUI", colorBlue ); + // SRS - Disable detailed timestamps during GUI rendering so they do not overwrite timestamps from 3D rendering + glConfig.timerQueryAvailable = false; + + DrawView( dsc, stereoEye ); + + // SRS - Restore timestamp capture state after GUI rendering is finished + glConfig.timerQueryAvailable = timerQueryAvailable; + renderLog.CloseBlock(); + renderLog.CloseMainBlock(); } + else + { + DrawView( dsc, stereoEye ); + } } break; @@ -2016,6 +2034,7 @@ void idRenderBackend::StereoRenderExecuteBackEndCommands( const emptyCommand_t* PostProcess( cmds ); } break; + default: common->Error( "RB_ExecuteBackEndCommands: bad commandId" ); break; diff --git a/neo/renderer/RenderBackend.cpp b/neo/renderer/RenderBackend.cpp index 72700bb8..dd73c688 100644 --- a/neo/renderer/RenderBackend.cpp +++ b/neo/renderer/RenderBackend.cpp @@ -5561,6 +5561,9 @@ void idRenderBackend::ExecuteBackEndCommands( const emptyCommand_t* cmds ) // needed for editor rendering GL_SetDefaultState(); + + // SRS - Save glConfig.timerQueryAvailable state so it can be disabled for RC_DRAW_VIEW_GUI then restored after it is finished + const bool timerQueryAvailable = glConfig.timerQueryAvailable; for( ; cmds != NULL; cmds = ( const emptyCommand_t* )cmds->next ) { @@ -5569,19 +5572,27 @@ void idRenderBackend::ExecuteBackEndCommands( const emptyCommand_t* cmds ) case RC_NOP: break; - case RC_DRAW_VIEW_3D: case RC_DRAW_VIEW_GUI: + // SRS - Capture separate timestamps for GUI rendering + renderLog.OpenMainBlock( MRB_DRAW_GUI ); + renderLog.OpenBlock( "Render_DrawViewGUI", colorBlue ); + // SRS - Disable detailed timestamps during GUI rendering so they do not overwrite timestamps from 3D rendering + glConfig.timerQueryAvailable = false; + DrawView( cmds, 0 ); - if( ( ( const drawSurfsCommand_t* )cmds )->viewDef->viewEntitys ) - { - c_draw3d++; - } - else - { - c_draw2d++; - } + c_draw2d++; + + // SRS - Restore timestamp capture state after GUI rendering is finished + glConfig.timerQueryAvailable = timerQueryAvailable; + renderLog.CloseBlock(); + renderLog.CloseMainBlock(); break; + case RC_DRAW_VIEW_3D: + DrawView( cmds, 0 ); + c_draw3d++; + break; + case RC_SET_BUFFER: SetBuffer( cmds ); c_setBuffers++; diff --git a/neo/renderer/RenderLog.cpp b/neo/renderer/RenderLog.cpp index 06c9f101..a1bd1b21 100644 --- a/neo/renderer/RenderLog.cpp +++ b/neo/renderer/RenderLog.cpp @@ -57,7 +57,8 @@ const char* renderLogMainBlockLabels[] = ASSERT_ENUM_STRING( MRB_DRAW_DEBUG_TOOLS, 10 ), ASSERT_ENUM_STRING( MRB_CAPTURE_COLORBUFFER, 11 ), ASSERT_ENUM_STRING( MRB_POSTPROCESS, 12 ), - ASSERT_ENUM_STRING( MRB_TOTAL, 13 ) + ASSERT_ENUM_STRING( MRB_DRAW_GUI, 13 ), + ASSERT_ENUM_STRING( MRB_TOTAL, 14 ) }; #if defined( USE_VULKAN ) @@ -603,38 +604,37 @@ idRenderLog::OpenMainBlock */ void idRenderLog::OpenMainBlock( renderLogMainBlock_t block ) { - mainBlock = block; + // SRS - Use glConfig.timerQueryAvailable flag to control timestamp capture for all platforms + if( glConfig.timerQueryAvailable ) + { + mainBlock = block; #if defined( USE_VULKAN ) - if( vkcontext.queryIndex[ vkcontext.frameParity ] >= ( NUM_TIMESTAMP_QUERIES - 1 ) ) - { - return; - } + if( vkcontext.queryIndex[ vkcontext.frameParity ] >= ( NUM_TIMESTAMP_QUERIES - 1 ) ) + { + return; + } - VkCommandBuffer commandBuffer = vkcontext.commandBuffer[ vkcontext.frameParity ]; - VkQueryPool queryPool = vkcontext.queryPools[ vkcontext.frameParity ]; + VkCommandBuffer commandBuffer = vkcontext.commandBuffer[ vkcontext.frameParity ]; + VkQueryPool queryPool = vkcontext.queryPools[ vkcontext.frameParity ]; - uint32 queryIndex = vkcontext.queryAssignedIndex[ vkcontext.frameParity ][ mainBlock * 2 + 0 ] = vkcontext.queryIndex[ vkcontext.frameParity ]++; - vkCmdWriteTimestamp( commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, queryPool, queryIndex ); + uint32 queryIndex = vkcontext.queryAssignedIndex[ vkcontext.frameParity ][ mainBlock * 2 + 0 ] = vkcontext.queryIndex[ vkcontext.frameParity ]++; + vkCmdWriteTimestamp( commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, queryPool, queryIndex ); -// SRS - For OSX use elapsed time query for Apple OpenGL 4.1 using GL_TIME_ELAPSED vs GL_TIMESTAMP (which is not implemented on OSX) #elif defined(__APPLE__) + // SRS - For OSX use elapsed time query for Apple OpenGL 4.1 using GL_TIME_ELAPSED vs GL_TIMESTAMP (which is not implemented on OSX) + // SRS - OSX AMD drivers have a rendering bug (flashing colours) with an elasped time query when Shadow Mapping is on - turn off query for that case unless r_skipAMDWorkarounds is set + if( !r_useShadowMapping.GetBool() || glConfig.vendor != VENDOR_AMD || r_skipAMDWorkarounds.GetBool() ) + { + if( glcontext.renderLogMainBlockTimeQueryIds[ glcontext.frameParity ][ mainBlock * 2 + 1 ] == 0 ) + { + glGenQueries( 1, &glcontext.renderLogMainBlockTimeQueryIds[ glcontext.frameParity ][ mainBlock * 2 + 1 ] ); + } - // SRS - OSX AMD drivers have a rendering bug (flashing colours) with an elasped time query when Shadow Mapping is on - turn off query for that case unless r_skipAMDWorkarounds is set - if( glConfig.timerQueryAvailable && ( !r_useShadowMapping.GetBool() || glConfig.vendor != VENDOR_AMD || r_skipAMDWorkarounds.GetBool() ) ) - { - if( glcontext.renderLogMainBlockTimeQueryIds[ glcontext.frameParity ][ mainBlock * 2 + 1 ] == 0 ) - { - glGenQueries( 1, &glcontext.renderLogMainBlockTimeQueryIds[ glcontext.frameParity ][ mainBlock * 2 + 1 ] ); - } - - glBeginQuery( GL_TIME_ELAPSED_EXT, glcontext.renderLogMainBlockTimeQueryIds[ glcontext.frameParity ][ mainBlock * 2 + 1 ] ); - } - + glBeginQuery( GL_TIME_ELAPSED_EXT, glcontext.renderLogMainBlockTimeQueryIds[ glcontext.frameParity ][ mainBlock * 2 + 1 ] ); + } + #else - - if( glConfig.timerQueryAvailable ) - { if( glcontext.renderLogMainBlockTimeQueryIds[ glcontext.frameParity ][ mainBlock * 2 ] == 0 ) { glCreateQueries( GL_TIMESTAMP, 2, &glcontext.renderLogMainBlockTimeQueryIds[ glcontext.frameParity ][ mainBlock * 2 ] ); @@ -642,8 +642,8 @@ void idRenderLog::OpenMainBlock( renderLogMainBlock_t block ) glQueryCounter( glcontext.renderLogMainBlockTimeQueryIds[ glcontext.frameParity ][ mainBlock * 2 + 0 ], GL_TIMESTAMP ); glcontext.renderLogMainBlockTimeQueryIssued[ glcontext.frameParity ][ mainBlock * 2 + 0 ]++; - } #endif + } } /* @@ -653,37 +653,36 @@ idRenderLog::CloseMainBlock */ void idRenderLog::CloseMainBlock() { + // SRS - Use glConfig.timerQueryAvailable flag to control timestamp capture for all platforms + if( glConfig.timerQueryAvailable ) + { + #if defined( USE_VULKAN ) + if( vkcontext.queryIndex[ vkcontext.frameParity ] >= ( NUM_TIMESTAMP_QUERIES - 1 ) ) + { + return; + } - if( vkcontext.queryIndex[ vkcontext.frameParity ] >= ( NUM_TIMESTAMP_QUERIES - 1 ) ) - { - return; - } + VkCommandBuffer commandBuffer = vkcontext.commandBuffer[ vkcontext.frameParity ]; + VkQueryPool queryPool = vkcontext.queryPools[ vkcontext.frameParity ]; - VkCommandBuffer commandBuffer = vkcontext.commandBuffer[ vkcontext.frameParity ]; - VkQueryPool queryPool = vkcontext.queryPools[ vkcontext.frameParity ]; + uint32 queryIndex = vkcontext.queryAssignedIndex[ vkcontext.frameParity ][ mainBlock * 2 + 1 ] = vkcontext.queryIndex[ vkcontext.frameParity ]++; + vkCmdWriteTimestamp( commandBuffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, queryIndex ); - uint32 queryIndex = vkcontext.queryAssignedIndex[ vkcontext.frameParity ][ mainBlock * 2 + 1 ] = vkcontext.queryIndex[ vkcontext.frameParity ]++; - vkCmdWriteTimestamp( commandBuffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, queryIndex ); - -// SRS - For OSX use elapsed time query for Apple OpenGL 4.1 using GL_TIME_ELAPSED vs GL_TIMESTAMP (which is not implemented on OSX) #elif defined(__APPLE__) - - // SRS - OSX AMD drivers have a rendering bug (flashing colours) with an elasped time query when Shadow Mapping is on - turn off query for that case unless r_skipAMDWorkarounds is set - if( glConfig.timerQueryAvailable && ( !r_useShadowMapping.GetBool() || glConfig.vendor != VENDOR_AMD || r_skipAMDWorkarounds.GetBool() ) ) - { - glEndQuery( GL_TIME_ELAPSED_EXT ); - glcontext.renderLogMainBlockTimeQueryIssued[ glcontext.frameParity ][ mainBlock * 2 + 1 ]++; - } + // SRS - For OSX use elapsed time query for Apple OpenGL 4.1 using GL_TIME_ELAPSED vs GL_TIMESTAMP (which is not implemented on OSX) + // SRS - OSX AMD drivers have a rendering bug (flashing colours) with an elasped time query when Shadow Mapping is on - turn off query for that case unless r_skipAMDWorkarounds is set + if( !r_useShadowMapping.GetBool() || glConfig.vendor != VENDOR_AMD || r_skipAMDWorkarounds.GetBool() ) + { + glEndQuery( GL_TIME_ELAPSED_EXT ); + glcontext.renderLogMainBlockTimeQueryIssued[ glcontext.frameParity ][ mainBlock * 2 + 1 ]++; + } #else - - if( glConfig.timerQueryAvailable ) - { glQueryCounter( glcontext.renderLogMainBlockTimeQueryIds[ glcontext.frameParity ][ mainBlock * 2 + 1 ], GL_TIMESTAMP ); glcontext.renderLogMainBlockTimeQueryIssued[ glcontext.frameParity ][ mainBlock * 2 + 1 ]++; - } #endif + } } #endif diff --git a/neo/renderer/RenderLog.h b/neo/renderer/RenderLog.h index 628fdbf0..7f6cf87c 100644 --- a/neo/renderer/RenderLog.h +++ b/neo/renderer/RenderLog.h @@ -55,6 +55,7 @@ enum renderLogMainBlock_t MRB_DRAW_DEBUG_TOOLS, MRB_CAPTURE_COLORBUFFER, MRB_POSTPROCESS, + MRB_DRAW_GUI, MRB_TOTAL, MRB_TOTAL_QUERIES = MRB_TOTAL * 2, diff --git a/neo/renderer/RenderSystem.cpp b/neo/renderer/RenderSystem.cpp index f7354313..efa9a10c 100644 --- a/neo/renderer/RenderSystem.cpp +++ b/neo/renderer/RenderSystem.cpp @@ -778,6 +778,13 @@ void idRenderSystemLocal::SwapCommandBuffers_FinishRendering( { glGetQueryObjectui64vEXT( glcontext.renderLogMainBlockTimeQueryIds[ glcontext.frameParity ^ 1 ][ MRB_DRAW_DEBUG_TOOLS * 2 + 1], GL_QUERY_RESULT, &gpuEndNanoseconds ); + backend.pc.gpuMicroSec += gpuEndNanoseconds / 1000; + } + + if( glcontext.renderLogMainBlockTimeQueryIssued[ glcontext.frameParity ^ 1 ][ MRB_DRAW_GUI * 2 + 1 ] > 0 ) + { + glGetQueryObjectui64vEXT( glcontext.renderLogMainBlockTimeQueryIds[ glcontext.frameParity ^ 1 ][ MRB_DRAW_GUI * 2 + 1], GL_QUERY_RESULT, &gpuEndNanoseconds ); + backend.pc.gpuMicroSec += gpuEndNanoseconds / 1000; } diff --git a/neo/renderer/Vulkan/RenderBackend_VK.cpp b/neo/renderer/Vulkan/RenderBackend_VK.cpp index f603ff17..afc641d6 100644 --- a/neo/renderer/Vulkan/RenderBackend_VK.cpp +++ b/neo/renderer/Vulkan/RenderBackend_VK.cpp @@ -1498,6 +1498,7 @@ void idRenderBackend::Init() idLib::Printf( "----- Initializing Vulkan driver -----\n" ); glConfig.driverType = GLDRV_VULKAN; + glConfig.timerQueryAvailable = true; // SRS - Use glConfig.timerQueryAvailable flag to control Vulkan timestamp capture glConfig.gpuSkinningAvailable = true; // create the Vulkan instance and enable validation layers