2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 BFG Edition GPL Source Code
2012-11-28 15:47:07 +00:00
Copyright ( C ) 1993 - 2012 id Software LLC , a ZeniMax Media company .
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ( " Doom 3 BFG Edition Source Code " ) .
2012-11-26 18:58:24 +00:00
Doom 3 BFG Edition Source Code is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code . If not , see < http : //www.gnu.org/licenses/>.
In addition , the Doom 3 BFG Edition Source Code is also subject to certain additional terms . You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code . If not , please request a copy in writing from id Software at the address below .
If you have questions concerning this license or the applicable additional terms , you may contact in writing id Software LLC , c / o ZeniMax Media Inc . , Suite 120 , Rockville , Maryland 20850 USA .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# pragma hdrstop
2012-12-22 15:18:19 +00:00
# include "precompiled.h"
2012-11-26 18:58:24 +00:00
# include "../tr_local.h"
# include "../../framework/Common_local.h"
idCVar r_drawFlickerBox ( " r_drawFlickerBox " , " 0 " , CVAR_RENDERER | CVAR_BOOL , " visual test for dropping frames " ) ;
idCVar stereoRender_warp ( " stereoRender_warp " , " 0 " , CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL , " use the optical warping renderprog instead of stereoDeGhost " ) ;
idCVar stereoRender_warpStrength ( " stereoRender_warpStrength " , " 1.45 " , CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT , " amount of pre-distortion " ) ;
idCVar stereoRender_warpCenterX ( " stereoRender_warpCenterX " , " 0.5 " , CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE , " center for left eye, right eye will be 1.0 - this " ) ;
idCVar stereoRender_warpCenterY ( " stereoRender_warpCenterY " , " 0.5 " , CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE , " center for both eyes " ) ;
idCVar stereoRender_warpParmZ ( " stereoRender_warpParmZ " , " 0 " , CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE , " development parm " ) ;
idCVar stereoRender_warpParmW ( " stereoRender_warpParmW " , " 0 " , CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE , " development parm " ) ;
idCVar stereoRender_warpTargetFraction ( " stereoRender_warpTargetFraction " , " 1.0 " , CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE , " fraction of half-width the through-lens view covers " ) ;
2012-11-28 15:47:07 +00:00
idCVar r_showSwapBuffers ( " r_showSwapBuffers " , " 0 " , CVAR_BOOL , " Show timings from GL_BlockingSwapBuffers " ) ;
idCVar r_syncEveryFrame ( " r_syncEveryFrame " , " 1 " , CVAR_BOOL , " Don't let the GPU buffer execution past swapbuffers " ) ;
2012-11-26 18:58:24 +00:00
static int swapIndex ; // 0 or 1 into renderSync
static GLsync renderSync [ 2 ] ;
void GLimp_SwapBuffers ( ) ;
2012-11-28 15:47:07 +00:00
void RB_SetMVP ( const idRenderMatrix & mvp ) ;
2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
RENDER BACK END THREAD FUNCTIONS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = =
RB_DrawFlickerBox
= = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_DrawFlickerBox ( )
{
if ( ! r_drawFlickerBox . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( tr . frameCount & 1 )
{
2012-11-26 18:58:24 +00:00
qglClearColor ( 1 , 0 , 0 , 1 ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
qglClearColor ( 0 , 1 , 0 , 1 ) ;
}
qglScissor ( 0 , 0 , 256 , 256 ) ;
qglClear ( GL_COLOR_BUFFER_BIT ) ;
}
/*
= = = = = = = = = = = = =
RB_SetBuffer
= = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_SetBuffer ( const void * data )
{
2012-11-26 18:58:24 +00:00
// see which draw buffer we want to render the frame to
2012-11-28 15:47:07 +00:00
const setBufferCommand_t * cmd = ( const setBufferCommand_t * ) data ;
2012-11-26 18:58:24 +00:00
RENDERLOG_PRINTF ( " ---------- RB_SetBuffer ---------- to buffer # %d \n " , cmd - > buffer ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_Scissor ( 0 , 0 , tr . GetWidth ( ) , tr . GetHeight ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// clear screen for debugging
// automatically enable this with several other debug tools
// that might leave unrendered portions of the screen
2012-11-28 15:47:07 +00:00
if ( r_clear . GetFloat ( ) | | idStr : : Length ( r_clear . GetString ( ) ) ! = 1 | | r_singleArea . GetBool ( ) | | r_showOverDraw . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
float c [ 3 ] ;
2012-11-28 15:47:07 +00:00
if ( sscanf ( r_clear . GetString ( ) , " %f %f %f " , & c [ 0 ] , & c [ 1 ] , & c [ 2 ] ) = = 3 )
{
2012-11-26 18:58:24 +00:00
GL_Clear ( true , false , false , 0 , c [ 0 ] , c [ 1 ] , c [ 2 ] , 1.0f ) ;
2012-11-28 15:47:07 +00:00
}
else if ( r_clear . GetInteger ( ) = = 2 )
{
2012-11-26 18:58:24 +00:00
GL_Clear ( true , false , false , 0 , 0.0f , 0.0f , 0.0f , 1.0f ) ;
2012-11-28 15:47:07 +00:00
}
else if ( r_showOverDraw . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
GL_Clear ( true , false , false , 0 , 1.0f , 1.0f , 1.0f , 1.0f ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
GL_Clear ( true , false , false , 0 , 0.4f , 0.0f , 0.25f , 1.0f ) ;
}
}
}
/*
= = = = = = = = = = = = =
GL_BlockingSwapBuffers
We want to exit this with the GPU idle , right at vsync
= = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
const void GL_BlockingSwapBuffers ( )
{
RENDERLOG_PRINTF ( " ***************** GL_BlockingSwapBuffers ***************** \n \n \n " ) ;
2012-11-26 18:58:24 +00:00
const int beforeFinish = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
if ( ! glConfig . syncAvailable )
{
2012-11-26 18:58:24 +00:00
glFinish ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const int beforeSwap = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
if ( r_showSwapBuffers . GetBool ( ) & & beforeSwap - beforeFinish > 1 )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " %i msec to glFinish \n " , beforeSwap - beforeFinish ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GLimp_SwapBuffers ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const int beforeFence = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
if ( r_showSwapBuffers . GetBool ( ) & & beforeFence - beforeSwap > 1 )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " %i msec to swapBuffers \n " , beforeFence - beforeSwap ) ;
}
2012-11-28 15:47:07 +00:00
if ( glConfig . syncAvailable )
{
2012-11-26 18:58:24 +00:00
swapIndex ^ = 1 ;
2012-11-28 15:47:07 +00:00
if ( qglIsSync ( renderSync [ swapIndex ] ) )
{
2012-11-26 18:58:24 +00:00
qglDeleteSync ( renderSync [ swapIndex ] ) ;
}
// draw something tiny to ensure the sync is after the swap
const int start = Sys_Milliseconds ( ) ;
qglScissor ( 0 , 0 , 1 , 1 ) ;
qglEnable ( GL_SCISSOR_TEST ) ;
qglClear ( GL_COLOR_BUFFER_BIT ) ;
renderSync [ swapIndex ] = qglFenceSync ( GL_SYNC_GPU_COMMANDS_COMPLETE , 0 ) ;
const int end = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
if ( r_showSwapBuffers . GetBool ( ) & & end - start > 1 )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " %i msec to start fence \n " , end - start ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GLsync syncToWaitOn ;
2012-11-28 15:47:07 +00:00
if ( r_syncEveryFrame . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
syncToWaitOn = renderSync [ swapIndex ] ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
syncToWaitOn = renderSync [ ! swapIndex ] ;
}
2012-11-28 15:47:07 +00:00
if ( qglIsSync ( syncToWaitOn ) )
{
for ( GLenum r = GL_TIMEOUT_EXPIRED ; r = = GL_TIMEOUT_EXPIRED ; )
{
2012-11-26 18:58:24 +00:00
r = qglClientWaitSync ( syncToWaitOn , GL_SYNC_FLUSH_COMMANDS_BIT , 1000 * 1000 ) ;
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const int afterFence = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
if ( r_showSwapBuffers . GetBool ( ) & & afterFence - beforeFence > 1 )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " %i msec to wait on fence \n " , afterFence - beforeFence ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const int64 exitBlockTime = Sys_Microseconds ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
static int64 prevBlockTime ;
2012-11-28 15:47:07 +00:00
if ( r_showSwapBuffers . GetBool ( ) & & prevBlockTime )
{
const int delta = ( int ) ( exitBlockTime - prevBlockTime ) ;
2012-11-26 18:58:24 +00:00
common - > Printf ( " blockToBlock: %i \n " , delta ) ;
}
prevBlockTime = exitBlockTime ;
}
/*
= = = = = = = = = = = = = = = = = = = =
R_MakeStereoRenderImage
= = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void R_MakeStereoRenderImage ( idImage * image )
{
2012-11-26 18:58:24 +00:00
idImageOpts opts ;
opts . width = renderSystem - > GetWidth ( ) ;
opts . height = renderSystem - > GetHeight ( ) ;
opts . numLevels = 1 ;
opts . format = FMT_RGBA8 ;
image - > AllocImage ( opts , TF_LINEAR , TR_CLAMP ) ;
}
/*
= = = = = = = = = = = = = = = = = = = =
RB_StereoRenderExecuteBackEndCommands
Renders the draw list twice , with slight modifications for left eye / right eye
= = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void RB_StereoRenderExecuteBackEndCommands ( const emptyCommand_t * const allCmds )
{
2012-11-26 18:58:24 +00:00
uint64 backEndStartTime = Sys_Microseconds ( ) ;
// If we are in a monoscopic context, this draws to the only buffer, and is
// the same as GL_BACK. In a quad-buffer stereo context, this is necessary
// to prevent GL from forcing the rendering to go to both BACK_LEFT and
// BACK_RIGHT at a performance penalty.
// To allow stereo deghost processing, the views have to be copied to separate
// textures anyway, so there isn't any benefit to rendering to BACK_RIGHT for
// that eye.
qglDrawBuffer ( GL_BACK_LEFT ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// create the stereoRenderImage if we haven't already
2012-11-28 15:47:07 +00:00
static idImage * stereoRenderImages [ 2 ] ;
for ( int i = 0 ; i < 2 ; i + + )
{
if ( stereoRenderImages [ i ] = = NULL )
{
stereoRenderImages [ i ] = globalImages - > ImageFromFunction ( va ( " _stereoRender%i " , i ) , R_MakeStereoRenderImage ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// resize the stereo render image if the main window has changed size
2012-11-28 15:47:07 +00:00
if ( stereoRenderImages [ i ] - > GetUploadWidth ( ) ! = renderSystem - > GetWidth ( ) | |
stereoRenderImages [ i ] - > GetUploadHeight ( ) ! = renderSystem - > GetHeight ( ) )
{
2012-11-26 18:58:24 +00:00
stereoRenderImages [ i ] - > Resize ( renderSystem - > GetWidth ( ) , renderSystem - > GetHeight ( ) ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// In stereoRender mode, the front end has generated two RC_DRAW_VIEW commands
// with slightly different origins for each eye.
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// TODO: only do the copy after the final view has been rendered, not mirror subviews?
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Render the 3D draw views from the screen origin so all the screen relative
// texture mapping works properly, then copy the portion we are going to use
// off to a texture.
bool foundEye [ 2 ] = { false , false } ;
2012-11-28 15:47:07 +00:00
for ( int stereoEye = 1 ; stereoEye > = - 1 ; stereoEye - = 2 )
{
2012-11-26 18:58:24 +00:00
// set up the target texture we will draw to
const int targetEye = ( stereoEye = = 1 ) ? 1 : 0 ;
// Set the back end into a known default state to fix any stale render state issues
GL_SetDefaultState ( ) ;
renderProgManager . Unbind ( ) ;
renderProgManager . ZeroUniforms ( ) ;
2012-11-28 15:47:07 +00:00
for ( const emptyCommand_t * cmds = allCmds ; cmds ! = NULL ; cmds = ( const emptyCommand_t * ) cmds - > next )
{
switch ( cmds - > commandId )
{
case RC_NOP :
break ;
case RC_DRAW_VIEW_GUI :
case RC_DRAW_VIEW_3D :
2012-11-26 18:58:24 +00:00
{
2012-11-28 15:47:07 +00:00
const drawSurfsCommand_t * const dsc = ( const drawSurfsCommand_t * ) cmds ;
const viewDef_t & eyeViewDef = * dsc - > viewDef ;
if ( eyeViewDef . renderView . viewEyeBuffer & & eyeViewDef . renderView . viewEyeBuffer ! = stereoEye )
{
2012-11-26 18:58:24 +00:00
// this is the render view for the other eye
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
foundEye [ targetEye ] = true ;
RB_DrawView ( dsc , stereoEye ) ;
2012-11-28 15:47:07 +00:00
if ( cmds - > commandId = = RC_DRAW_VIEW_GUI )
{
2012-11-26 18:58:24 +00:00
}
}
break ;
2012-11-28 15:47:07 +00:00
case RC_SET_BUFFER :
RB_SetBuffer ( cmds ) ;
break ;
case RC_COPY_RENDER :
RB_CopyRender ( cmds ) ;
break ;
case RC_POST_PROCESS :
2012-11-26 18:58:24 +00:00
{
2012-11-28 15:47:07 +00:00
postProcessCommand_t * cmd = ( postProcessCommand_t * ) cmds ;
if ( cmd - > viewDef - > renderView . viewEyeBuffer ! = stereoEye )
{
2012-11-26 18:58:24 +00:00
break ;
}
RB_PostProcess ( cmds ) ;
}
break ;
2012-11-28 15:47:07 +00:00
default :
common - > Error ( " RB_ExecuteBackEndCommands: bad commandId " ) ;
break ;
2012-11-26 18:58:24 +00:00
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// copy to the target
stereoRenderImages [ targetEye ] - > CopyFramebuffer ( 0 , 0 , renderSystem - > GetWidth ( ) , renderSystem - > GetHeight ( ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// perform the final compositing / warping / deghosting to the actual framebuffer(s)
assert ( foundEye [ 0 ] & & foundEye [ 1 ] ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_SetDefaultState ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RB_SetMVP ( renderMatrix_identity ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If we are in quad-buffer pixel format but testing another 3D mode,
// make sure we draw to both eyes. This is likely to be sub-optimal
// performance on most cards and drivers, but it is better than getting
// a confusing, half-ghosted view.
2012-11-28 15:47:07 +00:00
if ( renderSystem - > GetStereo3DMode ( ) ! = STEREO3D_QUAD_BUFFER )
{
2012-11-26 18:58:24 +00:00
glDrawBuffer ( GL_BACK ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_State ( GLS_DEPTHFUNC_ALWAYS ) ;
GL_Cull ( CT_TWO_SIDED ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// We just want to do a quad pass - so make sure we disable any texgen and
2012-11-28 15:47:07 +00:00
// set the texture matrix to the identity so we don't get anomalies from
2012-11-26 18:58:24 +00:00
// any stale uniform data being present from a previous draw call
const float texS [ 4 ] = { 1.0f , 0.0f , 0.0f , 0.0f } ;
const float texT [ 4 ] = { 0.0f , 1.0f , 0.0f , 0.0f } ;
renderProgManager . SetRenderParm ( RENDERPARM_TEXTUREMATRIX_S , texS ) ;
renderProgManager . SetRenderParm ( RENDERPARM_TEXTUREMATRIX_T , texT ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// disable any texgen
const float texGenEnabled [ 4 ] = { 0.0f , 0.0f , 0.0f , 0.0f } ;
renderProgManager . SetRenderParm ( RENDERPARM_TEXGEN_0_ENABLED , texGenEnabled ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_Texture ( ) ;
GL_Color ( 1 , 1 , 1 , 1 ) ;
2012-11-28 15:47:07 +00:00
switch ( renderSystem - > GetStereo3DMode ( ) )
{
case STEREO3D_QUAD_BUFFER :
glDrawBuffer ( GL_BACK_RIGHT ) ;
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
GL_SelectTexture ( 1 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
RB_DrawElementsWithCounters ( & backEnd . unitSquareSurface ) ;
glDrawBuffer ( GL_BACK_LEFT ) ;
GL_SelectTexture ( 1 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
RB_DrawElementsWithCounters ( & backEnd . unitSquareSurface ) ;
break ;
case STEREO3D_HDMI_720 :
// HDMI 720P 3D
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
GL_SelectTexture ( 1 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
GL_ViewportAndScissor ( 0 , 0 , 1280 , 720 ) ;
RB_DrawElementsWithCounters ( & backEnd . unitSquareSurface ) ;
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
GL_SelectTexture ( 1 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
GL_ViewportAndScissor ( 0 , 750 , 1280 , 720 ) ;
RB_DrawElementsWithCounters ( & backEnd . unitSquareSurface ) ;
// force the HDMI 720P 3D guard band to a constant color
glScissor ( 0 , 720 , 1280 , 30 ) ;
2012-11-26 18:58:24 +00:00
glClear ( GL_COLOR_BUFFER_BIT ) ;
2012-11-28 15:47:07 +00:00
break ;
default :
case STEREO3D_SIDE_BY_SIDE :
if ( stereoRender_warp . GetBool ( ) )
{
// this is the Rift warp
// renderSystem->GetWidth() / GetHeight() have returned equal values (640 for initial Rift)
// and we are going to warp them onto a symetric square region of each half of the screen
renderProgManager . BindShader_StereoWarp ( ) ;
// clear the entire screen to black
// we could be smart and only clear the areas we aren't going to draw on, but
// clears are fast...
glScissor ( 0 , 0 , glConfig . nativeScreenWidth , glConfig . nativeScreenHeight ) ;
glClearColor ( 0 , 0 , 0 , 0 ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
// the size of the box that will get the warped pixels
// With the 7" displays, this will be less than half the screen width
const int pixelDimensions = ( glConfig . nativeScreenWidth > > 1 ) * stereoRender_warpTargetFraction . GetFloat ( ) ;
// Always scissor to the half-screen boundary, but the viewports
// might cross that boundary if the lenses can be adjusted closer
// together.
glViewport ( ( glConfig . nativeScreenWidth > > 1 ) - pixelDimensions ,
( glConfig . nativeScreenHeight > > 1 ) - ( pixelDimensions > > 1 ) ,
pixelDimensions , pixelDimensions ) ;
glScissor ( 0 , 0 , glConfig . nativeScreenWidth > > 1 , glConfig . nativeScreenHeight ) ;
idVec4 color ( stereoRender_warpCenterX . GetFloat ( ) , stereoRender_warpCenterY . GetFloat ( ) , stereoRender_warpParmZ . GetFloat ( ) , stereoRender_warpParmW . GetFloat ( ) ) ;
// don't use GL_Color(), because we don't want to clamp
renderProgManager . SetRenderParm ( RENDERPARM_COLOR , color . ToFloatPtr ( ) ) ;
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
qglTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_BORDER ) ;
qglTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_BORDER ) ;
RB_DrawElementsWithCounters ( & backEnd . unitSquareSurface ) ;
idVec4 color2 ( stereoRender_warpCenterX . GetFloat ( ) , stereoRender_warpCenterY . GetFloat ( ) , stereoRender_warpParmZ . GetFloat ( ) , stereoRender_warpParmW . GetFloat ( ) ) ;
// don't use GL_Color(), because we don't want to clamp
renderProgManager . SetRenderParm ( RENDERPARM_COLOR , color2 . ToFloatPtr ( ) ) ;
glViewport ( ( glConfig . nativeScreenWidth > > 1 ) ,
( glConfig . nativeScreenHeight > > 1 ) - ( pixelDimensions > > 1 ) ,
pixelDimensions , pixelDimensions ) ;
glScissor ( glConfig . nativeScreenWidth > > 1 , 0 , glConfig . nativeScreenWidth > > 1 , glConfig . nativeScreenHeight ) ;
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
qglTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_BORDER ) ;
qglTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_BORDER ) ;
RB_DrawElementsWithCounters ( & backEnd . unitSquareSurface ) ;
break ;
}
// a non-warped side-by-side-uncompressed (dual input cable) is rendered
// just like STEREO3D_SIDE_BY_SIDE_COMPRESSED, so fall through.
case STEREO3D_SIDE_BY_SIDE_COMPRESSED :
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
2012-11-28 15:47:07 +00:00
GL_SelectTexture ( 1 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
GL_ViewportAndScissor ( 0 , 0 , renderSystem - > GetWidth ( ) , renderSystem - > GetHeight ( ) ) ;
2012-11-26 18:58:24 +00:00
RB_DrawElementsWithCounters ( & backEnd . unitSquareSurface ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
2012-11-28 15:47:07 +00:00
GL_SelectTexture ( 1 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
GL_ViewportAndScissor ( renderSystem - > GetWidth ( ) , 0 , renderSystem - > GetWidth ( ) , renderSystem - > GetHeight ( ) ) ;
2012-11-26 18:58:24 +00:00
RB_DrawElementsWithCounters ( & backEnd . unitSquareSurface ) ;
break ;
2012-11-28 15:47:07 +00:00
case STEREO3D_TOP_AND_BOTTOM_COMPRESSED :
GL_SelectTexture ( 1 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
GL_ViewportAndScissor ( 0 , 0 , renderSystem - > GetWidth ( ) , renderSystem - > GetHeight ( ) ) ;
RB_DrawElementsWithCounters ( & backEnd . unitSquareSurface ) ;
GL_SelectTexture ( 1 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
GL_ViewportAndScissor ( 0 , renderSystem - > GetHeight ( ) , renderSystem - > GetWidth ( ) , renderSystem - > GetHeight ( ) ) ;
RB_DrawElementsWithCounters ( & backEnd . unitSquareSurface ) ;
break ;
case STEREO3D_INTERLACED :
// every other scanline
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
qglTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
qglTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
GL_SelectTexture ( 1 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
qglTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
qglTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
GL_ViewportAndScissor ( 0 , 0 , renderSystem - > GetWidth ( ) , renderSystem - > GetHeight ( ) * 2 ) ;
renderProgManager . BindShader_StereoInterlace ( ) ;
RB_DrawElementsWithCounters ( & backEnd . unitSquareSurface ) ;
GL_SelectTexture ( 0 ) ;
qglTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
qglTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
GL_SelectTexture ( 1 ) ;
qglTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
qglTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
break ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// debug tool
RB_DrawFlickerBox ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// make sure the drawing is actually started
qglFlush ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// we may choose to sync to the swapbuffers before the next frame
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// stop rendering on this thread
uint64 backEndFinishTime = Sys_Microseconds ( ) ;
backEnd . pc . totalMicroSec = backEndFinishTime - backEndStartTime ;
}
/*
= = = = = = = = = = = = = = = = = = = =
RB_ExecuteBackEndCommands
This function will be called syncronously if running without
smp extensions , or asyncronously by another thread .
= = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void RB_ExecuteBackEndCommands ( const emptyCommand_t * cmds )
{
2012-11-26 18:58:24 +00:00
// r_debugRenderToTexture
int c_draw3d = 0 ;
int c_draw2d = 0 ;
int c_setBuffers = 0 ;
int c_copyRenders = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
resolutionScale . SetCurrentGPUFrameTime ( commonLocal . GetRendererGPUMicroseconds ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . StartFrame ( ) ;
2012-11-28 15:47:07 +00:00
if ( cmds - > commandId = = RC_NOP & & ! cmds - > next )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( renderSystem - > GetStereo3DMode ( ) ! = STEREO3D_OFF )
{
2012-11-26 18:58:24 +00:00
RB_StereoRenderExecuteBackEndCommands ( cmds ) ;
renderLog . EndFrame ( ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
uint64 backEndStartTime = Sys_Microseconds ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// needed for editor rendering
GL_SetDefaultState ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If we have a stereo pixel format, this will draw to both
// the back left and back right buffers, which will have a
// performance penalty.
qglDrawBuffer ( GL_BACK ) ;
2012-11-28 15:47:07 +00:00
for ( ; cmds ! = NULL ; cmds = ( const emptyCommand_t * ) cmds - > next )
{
switch ( cmds - > commandId )
{
case RC_NOP :
break ;
case RC_DRAW_VIEW_3D :
case RC_DRAW_VIEW_GUI :
RB_DrawView ( cmds , 0 ) ;
if ( ( ( const drawSurfsCommand_t * ) cmds ) - > viewDef - > viewEntitys )
{
c_draw3d + + ;
}
else
{
c_draw2d + + ;
}
break ;
case RC_SET_BUFFER :
c_setBuffers + + ;
break ;
case RC_COPY_RENDER :
RB_CopyRender ( cmds ) ;
c_copyRenders + + ;
break ;
case RC_POST_PROCESS :
RB_PostProcess ( cmds ) ;
break ;
default :
common - > Error ( " RB_ExecuteBackEndCommands: bad commandId " ) ;
break ;
2012-11-26 18:58:24 +00:00
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RB_DrawFlickerBox ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Fix for the steam overlay not showing up while in game without Shell/Debug/Console/Menu also rendering
qglColorMask ( 1 , 1 , 1 , 1 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
qglFlush ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// stop rendering on this thread
uint64 backEndFinishTime = Sys_Microseconds ( ) ;
backEnd . pc . totalMicroSec = backEndFinishTime - backEndStartTime ;
2012-11-28 15:47:07 +00:00
if ( r_debugRenderToTexture . GetInteger ( ) = = 1 )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " 3d: %i, 2d: %i, SetBuf: %i, CpyRenders: %i, CpyFrameBuf: %i \n " , c_draw3d , c_draw2d , c_setBuffers , c_copyRenders , backEnd . pc . c_copyFrameBuffer ) ;
backEnd . pc . c_copyFrameBuffer = 0 ;
}
renderLog . EndFrame ( ) ;
}