Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

tr_cmds.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 #include "tr_local.h"
00023 
00024 volatile renderCommandList_t    *renderCommandList;
00025 
00026 volatile qboolean   renderThreadActive;
00027 
00028 
00029 /*
00030 =====================
00031 R_PerformanceCounters
00032 =====================
00033 */
00034 void R_PerformanceCounters( void ) {
00035     if ( !r_speeds->integer ) {
00036         // clear the counters even if we aren't printing
00037         Com_Memset( &tr.pc, 0, sizeof( tr.pc ) );
00038         Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
00039         return;
00040     }
00041 
00042     if (r_speeds->integer == 1) {
00043         ri.Printf (PRINT_ALL, "%i/%i shaders/surfs %i leafs %i verts %i/%i tris %.2f mtex %.2f dc\n",
00044             backEnd.pc.c_shaders, backEnd.pc.c_surfaces, tr.pc.c_leafs, backEnd.pc.c_vertexes, 
00045             backEnd.pc.c_indexes/3, backEnd.pc.c_totalIndexes/3, 
00046             R_SumOfUsedImages()/(1000000.0f), backEnd.pc.c_overDraw / (float)(glConfig.vidWidth * glConfig.vidHeight) ); 
00047     } else if (r_speeds->integer == 2) {
00048         ri.Printf (PRINT_ALL, "(patch) %i sin %i sclip  %i sout %i bin %i bclip %i bout\n",
00049             tr.pc.c_sphere_cull_patch_in, tr.pc.c_sphere_cull_patch_clip, tr.pc.c_sphere_cull_patch_out, 
00050             tr.pc.c_box_cull_patch_in, tr.pc.c_box_cull_patch_clip, tr.pc.c_box_cull_patch_out );
00051         ri.Printf (PRINT_ALL, "(md3) %i sin %i sclip  %i sout %i bin %i bclip %i bout\n",
00052             tr.pc.c_sphere_cull_md3_in, tr.pc.c_sphere_cull_md3_clip, tr.pc.c_sphere_cull_md3_out, 
00053             tr.pc.c_box_cull_md3_in, tr.pc.c_box_cull_md3_clip, tr.pc.c_box_cull_md3_out );
00054     } else if (r_speeds->integer == 3) {
00055         ri.Printf (PRINT_ALL, "viewcluster: %i\n", tr.viewCluster );
00056     } else if (r_speeds->integer == 4) {
00057         if ( backEnd.pc.c_dlightVertexes ) {
00058             ri.Printf (PRINT_ALL, "dlight srf:%i  culled:%i  verts:%i  tris:%i\n", 
00059                 tr.pc.c_dlightSurfaces, tr.pc.c_dlightSurfacesCulled,
00060                 backEnd.pc.c_dlightVertexes, backEnd.pc.c_dlightIndexes / 3 );
00061         }
00062     } 
00063     else if (r_speeds->integer == 5 )
00064     {
00065         ri.Printf( PRINT_ALL, "zFar: %.0f\n", tr.viewParms.zFar );
00066     }
00067     else if (r_speeds->integer == 6 )
00068     {
00069         ri.Printf( PRINT_ALL, "flare adds:%i tests:%i renders:%i\n", 
00070             backEnd.pc.c_flareAdds, backEnd.pc.c_flareTests, backEnd.pc.c_flareRenders );
00071     }
00072 
00073     Com_Memset( &tr.pc, 0, sizeof( tr.pc ) );
00074     Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
00075 }
00076 
00077 
00078 /*
00079 ====================
00080 R_InitCommandBuffers
00081 ====================
00082 */
00083 void R_InitCommandBuffers( void ) {
00084     glConfig.smpActive = qfalse;
00085     if ( r_smp->integer ) {
00086         ri.Printf( PRINT_ALL, "Trying SMP acceleration...\n" );
00087         if ( GLimp_SpawnRenderThread( RB_RenderThread ) ) {
00088             ri.Printf( PRINT_ALL, "...succeeded.\n" );
00089             glConfig.smpActive = qtrue;
00090         } else {
00091             ri.Printf( PRINT_ALL, "...failed.\n" );
00092         }
00093     }
00094 }
00095 
00096 /*
00097 ====================
00098 R_ShutdownCommandBuffers
00099 ====================
00100 */
00101 void R_ShutdownCommandBuffers( void ) {
00102     // kill the rendering thread
00103     if ( glConfig.smpActive ) {
00104         GLimp_WakeRenderer( NULL );
00105         glConfig.smpActive = qfalse;
00106     }
00107 }
00108 
00109 /*
00110 ====================
00111 R_IssueRenderCommands
00112 ====================
00113 */
00114 int c_blockedOnRender;
00115 int c_blockedOnMain;
00116 
00117 void R_IssueRenderCommands( qboolean runPerformanceCounters ) {
00118     renderCommandList_t *cmdList;
00119 
00120     cmdList = &backEndData[tr.smpFrame]->commands;
00121     assert(cmdList); // bk001205
00122     // add an end-of-list command
00123     *(int *)(cmdList->cmds + cmdList->used) = RC_END_OF_LIST;
00124 
00125     // clear it out, in case this is a sync and not a buffer flip
00126     cmdList->used = 0;
00127 
00128     if ( glConfig.smpActive ) {
00129         // if the render thread is not idle, wait for it
00130         if ( renderThreadActive ) {
00131             c_blockedOnRender++;
00132             if ( r_showSmp->integer ) {
00133                 ri.Printf( PRINT_ALL, "R" );
00134             }
00135         } else {
00136             c_blockedOnMain++;
00137             if ( r_showSmp->integer ) {
00138                 ri.Printf( PRINT_ALL, "." );
00139             }
00140         }
00141 
00142         // sleep until the renderer has completed
00143         GLimp_FrontEndSleep();
00144     }
00145 
00146     // at this point, the back end thread is idle, so it is ok
00147     // to look at it's performance counters
00148     if ( runPerformanceCounters ) {
00149         R_PerformanceCounters();
00150     }
00151 
00152     // actually start the commands going
00153     if ( !r_skipBackEnd->integer ) {
00154         // let it start on the new batch
00155         if ( !glConfig.smpActive ) {
00156             RB_ExecuteRenderCommands( cmdList->cmds );
00157         } else {
00158             GLimp_WakeRenderer( cmdList );
00159         }
00160     }
00161 }
00162 
00163 
00164 /*
00165 ====================
00166 R_SyncRenderThread
00167 
00168 Issue any pending commands and wait for them to complete.
00169 After exiting, the render thread will have completed its work
00170 and will remain idle and the main thread is free to issue
00171 OpenGL calls until R_IssueRenderCommands is called.
00172 ====================
00173 */
00174 void R_SyncRenderThread( void ) {
00175     if ( !tr.registered ) {
00176         return;
00177     }
00178     R_IssueRenderCommands( qfalse );
00179 
00180     if ( !glConfig.smpActive ) {
00181         return;
00182     }
00183     GLimp_FrontEndSleep();
00184 }
00185 
00186 /*
00187 ============
00188 R_GetCommandBuffer
00189 
00190 make sure there is enough command space, waiting on the
00191 render thread if needed.
00192 ============
00193 */
00194 void *R_GetCommandBuffer( int bytes ) {
00195     renderCommandList_t *cmdList;
00196 
00197     cmdList = &backEndData[tr.smpFrame]->commands;
00198 
00199     // always leave room for the end of list command
00200     if ( cmdList->used + bytes + 4 > MAX_RENDER_COMMANDS ) {
00201         if ( bytes > MAX_RENDER_COMMANDS - 4 ) {
00202             ri.Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes );
00203         }
00204         // if we run out of room, just start dropping commands
00205         return NULL;
00206     }
00207 
00208     cmdList->used += bytes;
00209 
00210     return cmdList->cmds + cmdList->used - bytes;
00211 }
00212 
00213 
00214 /*
00215 =============
00216 R_AddDrawSurfCmd
00217 
00218 =============
00219 */
00220 void    R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ) {
00221     drawSurfsCommand_t  *cmd;
00222 
00223     cmd = R_GetCommandBuffer( sizeof( *cmd ) );
00224     if ( !cmd ) {
00225         return;
00226     }
00227     cmd->commandId = RC_DRAW_SURFS;
00228 
00229     cmd->drawSurfs = drawSurfs;
00230     cmd->numDrawSurfs = numDrawSurfs;
00231 
00232     cmd->refdef = tr.refdef;
00233     cmd->viewParms = tr.viewParms;
00234 }
00235 
00236 
00237 /*
00238 =============
00239 RE_SetColor
00240 
00241 Passing NULL will set the color to white
00242 =============
00243 */
00244 void    RE_SetColor( const float *rgba ) {
00245     setColorCommand_t   *cmd;
00246 
00247   if ( !tr.registered ) {
00248     return;
00249   }
00250     cmd = R_GetCommandBuffer( sizeof( *cmd ) );
00251     if ( !cmd ) {
00252         return;
00253     }
00254     cmd->commandId = RC_SET_COLOR;
00255     if ( !rgba ) {
00256         static float colorWhite[4] = { 1, 1, 1, 1 };
00257 
00258         rgba = colorWhite;
00259     }
00260 
00261     cmd->color[0] = rgba[0];
00262     cmd->color[1] = rgba[1];
00263     cmd->color[2] = rgba[2];
00264     cmd->color[3] = rgba[3];
00265 }
00266 
00267 
00268 /*
00269 =============
00270 RE_StretchPic
00271 =============
00272 */
00273 void RE_StretchPic ( float x, float y, float w, float h, 
00274                       float s1, float t1, float s2, float t2, qhandle_t hShader ) {
00275     stretchPicCommand_t *cmd;
00276 
00277   if (!tr.registered) {
00278     return;
00279   }
00280     cmd = R_GetCommandBuffer( sizeof( *cmd ) );
00281     if ( !cmd ) {
00282         return;
00283     }
00284     cmd->commandId = RC_STRETCH_PIC;
00285     cmd->shader = R_GetShaderByHandle( hShader );
00286     cmd->x = x;
00287     cmd->y = y;
00288     cmd->w = w;
00289     cmd->h = h;
00290     cmd->s1 = s1;
00291     cmd->t1 = t1;
00292     cmd->s2 = s2;
00293     cmd->t2 = t2;
00294 }
00295 
00296 
00297 /*
00298 ====================
00299 RE_BeginFrame
00300 
00301 If running in stereo, RE_BeginFrame will be called twice
00302 for each RE_EndFrame
00303 ====================
00304 */
00305 void RE_BeginFrame( stereoFrame_t stereoFrame ) {
00306     drawBufferCommand_t *cmd;
00307 
00308     if ( !tr.registered ) {
00309         return;
00310     }
00311     glState.finishCalled = qfalse;
00312 
00313     tr.frameCount++;
00314     tr.frameSceneNum = 0;
00315 
00316     //
00317     // do overdraw measurement
00318     //
00319     if ( r_measureOverdraw->integer )
00320     {
00321         if ( glConfig.stencilBits < 4 )
00322         {
00323             ri.Printf( PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits );
00324             ri.Cvar_Set( "r_measureOverdraw", "0" );
00325             r_measureOverdraw->modified = qfalse;
00326         }
00327         else if ( r_shadows->integer == 2 )
00328         {
00329             ri.Printf( PRINT_ALL, "Warning: stencil shadows and overdraw measurement are mutually exclusive\n" );
00330             ri.Cvar_Set( "r_measureOverdraw", "0" );
00331             r_measureOverdraw->modified = qfalse;
00332         }
00333         else
00334         {
00335             R_SyncRenderThread();
00336             qglEnable( GL_STENCIL_TEST );
00337             qglStencilMask( ~0U );
00338             qglClearStencil( 0U );
00339             qglStencilFunc( GL_ALWAYS, 0U, ~0U );
00340             qglStencilOp( GL_KEEP, GL_INCR, GL_INCR );
00341         }
00342         r_measureOverdraw->modified = qfalse;
00343     }
00344     else
00345     {
00346         // this is only reached if it was on and is now off
00347         if ( r_measureOverdraw->modified ) {
00348             R_SyncRenderThread();
00349             qglDisable( GL_STENCIL_TEST );
00350         }
00351         r_measureOverdraw->modified = qfalse;
00352     }
00353 
00354     //
00355     // texturemode stuff
00356     //
00357     if ( r_textureMode->modified ) {
00358         R_SyncRenderThread();
00359         GL_TextureMode( r_textureMode->string );
00360         r_textureMode->modified = qfalse;
00361     }
00362 
00363     //
00364     // gamma stuff
00365     //
00366     if ( r_gamma->modified ) {
00367         r_gamma->modified = qfalse;
00368 
00369         R_SyncRenderThread();
00370         R_SetColorMappings();
00371     }
00372 
00373     // check for errors
00374     if ( !r_ignoreGLErrors->integer ) {
00375         int err;
00376 
00377         R_SyncRenderThread();
00378         if ( ( err = qglGetError() ) != GL_NO_ERROR ) {
00379             ri.Error( ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!\n", err );
00380         }
00381     }
00382 
00383     //
00384     // draw buffer stuff
00385     //
00386     cmd = R_GetCommandBuffer( sizeof( *cmd ) );
00387     if ( !cmd ) {
00388         return;
00389     }
00390     cmd->commandId = RC_DRAW_BUFFER;
00391 
00392     if ( glConfig.stereoEnabled ) {
00393         if ( stereoFrame == STEREO_LEFT ) {
00394             cmd->buffer = (int)GL_BACK_LEFT;
00395         } else if ( stereoFrame == STEREO_RIGHT ) {
00396             cmd->buffer = (int)GL_BACK_RIGHT;
00397         } else {
00398             ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
00399         }
00400     } else {
00401         if ( stereoFrame != STEREO_CENTER ) {
00402             ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame );
00403         }
00404         if ( !Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) ) {
00405             cmd->buffer = (int)GL_FRONT;
00406         } else {
00407             cmd->buffer = (int)GL_BACK;
00408         }
00409     }
00410 }
00411 
00412 
00413 /*
00414 =============
00415 RE_EndFrame
00416 
00417 Returns the number of msec spent in the back end
00418 =============
00419 */
00420 void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) {
00421     swapBuffersCommand_t    *cmd;
00422 
00423     if ( !tr.registered ) {
00424         return;
00425     }
00426     cmd = R_GetCommandBuffer( sizeof( *cmd ) );
00427     if ( !cmd ) {
00428         return;
00429     }
00430     cmd->commandId = RC_SWAP_BUFFERS;
00431 
00432     R_IssueRenderCommands( qtrue );
00433 
00434     // use the other buffers next frame, because another CPU
00435     // may still be rendering into the current ones
00436     R_ToggleSmpFrame();
00437 
00438     if ( frontEndMsec ) {
00439         *frontEndMsec = tr.frontEndMsec;
00440     }
00441     tr.frontEndMsec = 0;
00442     if ( backEndMsec ) {
00443         *backEndMsec = backEnd.pc.msec;
00444     }
00445     backEnd.pc.msec = 0;
00446 }
00447 

Generated on Thu Aug 25 12:37:51 2005 for Quake III Arena by  doxygen 1.3.9.1