/* ============ R_InitFBOs ============ */ void R_InitFBOs( void ) { int i; int width, height; ri.Printf( PRINT_DEVELOPER, "------- R_InitFBOs -------\n" ); if ( !glConfig2.framebufferObjectAvailable ) { return; } tr.numFBOs = 0; #if !defined( USE_D3D10 ) GL_CheckErrors(); #endif // make sure the render thread is stopped R_SyncRenderThread(); #if defined( USE_D3D10 ) // TODO #else if ( DS_STANDARD_ENABLED() ) { // geometricRender FBO as G-Buffer for deferred shading ri.Printf( PRINT_ALL, "Deferred Shading enabled\n" ); if ( glConfig2.textureNPOTAvailable ) { width = glConfig.vidWidth; height = glConfig.vidHeight; } else { width = NearestPowerOfTwo( glConfig.vidWidth ); height = NearestPowerOfTwo( glConfig.vidHeight ); } tr.geometricRenderFBO = R_CreateFBO( "_geometricRender", width, height ); R_BindFBO( tr.geometricRenderFBO ); #if 0 if ( glConfig2.framebufferPackedDepthStencilAvailable ) { R_AttachFBOTexturePackedDepthStencil( tr.depthRenderImage->texnum ); } else if ( glConfig.hardwareType == GLHW_ATI || glConfig.hardwareType == GLHW_ATI_DX10 ) // || glConfig.hardwareType == GLHW_NV_DX10) { R_AttachFBOTextureDepth( tr.depthRenderImage->texnum ); } else #endif { R_AttachFBOTextureDepth( tr.depthRenderImage->texnum ); } // enable all attachments as draw buffers //glDrawBuffers(4, geometricRenderTargets); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.deferredRenderFBOImage->texnum, 0 ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.deferredDiffuseFBOImage->texnum, 1 ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.deferredNormalFBOImage->texnum, 2 ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.deferredSpecularFBOImage->texnum, 3 ); R_CheckFBO( tr.geometricRenderFBO ); } else { // forward shading if ( glConfig2.textureNPOTAvailable ) { width = glConfig.vidWidth; height = glConfig.vidHeight; } else { width = NearestPowerOfTwo( glConfig.vidWidth ); height = NearestPowerOfTwo( glConfig.vidHeight ); } // deferredRender FBO for the HDR or LDR context tr.deferredRenderFBO = R_CreateFBO( "_deferredRender", width, height ); R_BindFBO( tr.deferredRenderFBO ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.deferredRenderFBOImage->texnum, 0 ); #if 0 if ( glConfig2.framebufferPackedDepthStencilAvailable ) { R_AttachFBOTexturePackedDepthStencil( tr.depthRenderImage->texnum ); } else if ( glConfig.hardwareType == GLHW_ATI || glConfig.hardwareType == GLHW_ATI_DX10 ) // || glConfig.hardwareType == GLHW_NV_DX10) { R_AttachFBOTextureDepth( tr.depthRenderImage->texnum ); } else #endif { R_AttachFBOTextureDepth( tr.depthRenderImage->texnum ); } R_CheckFBO( tr.deferredRenderFBO ); } if ( glConfig2.framebufferBlitAvailable ) { if ( glConfig2.textureNPOTAvailable ) { width = glConfig.vidWidth; height = glConfig.vidHeight; } else { width = NearestPowerOfTwo( glConfig.vidWidth ); height = NearestPowerOfTwo( glConfig.vidHeight ); } tr.occlusionRenderFBO = R_CreateFBO( "_occlusionRender", width, height ); R_BindFBO( tr.occlusionRenderFBO ); if ( glConfig.hardwareType == GLHW_ATI_DX10 ) { //R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_ALPHA16F, 0); R_CreateFBODepthBuffer( tr.occlusionRenderFBO, GL_DEPTH_COMPONENT16 ); } else if ( glConfig.hardwareType == GLHW_NV_DX10 ) { //R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_ALPHA32F, 0); R_CreateFBODepthBuffer( tr.occlusionRenderFBO, GL_DEPTH_COMPONENT24 ); } else if ( glConfig2.framebufferPackedDepthStencilAvailable ) { //R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_ALPHA32F, 0); R_CreateFBOPackedDepthStencilBuffer( tr.occlusionRenderFBO, GL_DEPTH24_STENCIL8_EXT ); } else { //R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_RGBA, 0); R_CreateFBODepthBuffer( tr.occlusionRenderFBO, GL_DEPTH_COMPONENT24 ); } R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.occlusionRenderFBOImage->texnum, 0 ); R_CheckFBO( tr.occlusionRenderFBO ); } if ( r_shadows->integer >= SHADOWING_ESM16 && glConfig2.textureFloatAvailable ) { // shadowMap FBOs for shadow mapping offscreen rendering for ( i = 0; i < MAX_SHADOWMAPS; i++ ) { width = height = shadowMapResolutions[ i ]; tr.shadowMapFBO[ i ] = R_CreateFBO( va( "_shadowMap%d", i ), width, height ); R_BindFBO( tr.shadowMapFBO[ i ] ); if ( ( glConfig.driverType == GLDRV_OPENGL3 ) || ( glConfig.hardwareType == GLHW_NV_DX10 || glConfig.hardwareType == GLHW_ATI_DX10 ) ) { if ( r_shadows->integer == SHADOWING_ESM32 ) { R_CreateFBOColorBuffer( tr.shadowMapFBO[ i ], GL_ALPHA32F_ARB, 0 ); } else if ( r_shadows->integer == SHADOWING_VSM32 ) { R_CreateFBOColorBuffer( tr.shadowMapFBO[ i ], GL_LUMINANCE_ALPHA32F_ARB, 0 ); } else if ( r_shadows->integer == SHADOWING_EVSM32 ) { if ( r_evsmPostProcess->integer ) { R_CreateFBOColorBuffer( tr.shadowMapFBO[ i ], GL_ALPHA32F_ARB, 0 ); } else { R_CreateFBOColorBuffer( tr.shadowMapFBO[ i ], GL_RGBA32F, 0 ); } } else { R_CreateFBOColorBuffer( tr.shadowMapFBO[ i ], GL_RGBA16F, 0 ); } } else { if ( r_shadows->integer == SHADOWING_ESM16 ) { R_CreateFBOColorBuffer( tr.shadowMapFBO[ i ], GL_ALPHA16F_ARB, 0 ); } else if ( r_shadows->integer == SHADOWING_VSM16 ) { R_CreateFBOColorBuffer( tr.shadowMapFBO[ i ], GL_LUMINANCE_ALPHA16F_ARB, 0 ); } else { R_CreateFBOColorBuffer( tr.shadowMapFBO[ i ], GL_RGBA16F, 0 ); } } R_CreateFBODepthBuffer( tr.shadowMapFBO[ i ], GL_DEPTH_COMPONENT24 ); R_CheckFBO( tr.shadowMapFBO[ i ] ); } // sun requires different resolutions for ( i = 0; i < MAX_SHADOWMAPS; i++ ) { width = height = sunShadowMapResolutions[ i ]; tr.sunShadowMapFBO[ i ] = R_CreateFBO( va( "_sunShadowMap%d", i ), width, height ); R_BindFBO( tr.sunShadowMapFBO[ i ] ); if ( ( glConfig.driverType == GLDRV_OPENGL3 ) || ( glConfig.hardwareType == GLHW_NV_DX10 || glConfig.hardwareType == GLHW_ATI_DX10 ) ) { if ( r_shadows->integer == SHADOWING_ESM32 ) { R_CreateFBOColorBuffer( tr.sunShadowMapFBO[ i ], GL_ALPHA32F_ARB, 0 ); } else if ( r_shadows->integer == SHADOWING_VSM32 ) { R_CreateFBOColorBuffer( tr.sunShadowMapFBO[ i ], GL_LUMINANCE_ALPHA32F_ARB, 0 ); } else if ( r_shadows->integer == SHADOWING_EVSM32 ) { if ( !r_evsmPostProcess->integer ) { R_CreateFBOColorBuffer( tr.sunShadowMapFBO[ i ], GL_RGBA32F, 0 ); } } else { R_CreateFBOColorBuffer( tr.sunShadowMapFBO[ i ], GL_RGBA16F, 0 ); } } else { if ( r_shadows->integer == SHADOWING_ESM16 ) { R_CreateFBOColorBuffer( tr.sunShadowMapFBO[ i ], GL_ALPHA16F_ARB, 0 ); } else if ( r_shadows->integer == SHADOWING_VSM16 ) { R_CreateFBOColorBuffer( tr.sunShadowMapFBO[ i ], GL_LUMINANCE_ALPHA16F_ARB, 0 ); } else { R_CreateFBOColorBuffer( tr.sunShadowMapFBO[ i ], GL_RGBA16F, 0 ); } } R_CreateFBODepthBuffer( tr.sunShadowMapFBO[ i ], GL_DEPTH_COMPONENT24 ); if ( r_shadows->integer == SHADOWING_EVSM32 && r_evsmPostProcess->integer ) { R_AttachFBOTextureDepth( tr.sunShadowMapFBOImage[ i ]->texnum ); /* Since we don't have a color attachment, the framebuffer will be considered incomplete. Consequently, we must inform the driver that we do not wish to render to the color buffer. We do this with a call to set the draw-buffer and read-buffer to GL_NONE: */ glDrawBuffer( GL_NONE ); glReadBuffer( GL_NONE ); } R_CheckFBO( tr.sunShadowMapFBO[ i ] ); } } { if ( glConfig2.textureNPOTAvailable ) { width = glConfig.vidWidth; height = glConfig.vidHeight; } else { width = NearestPowerOfTwo( glConfig.vidWidth ); height = NearestPowerOfTwo( glConfig.vidHeight ); } // portalRender FBO for portals, mirrors, water, cameras et cetera tr.portalRenderFBO = R_CreateFBO( "_portalRender", width, height ); R_BindFBO( tr.portalRenderFBO ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.portalRenderImage->texnum, 0 ); R_CheckFBO( tr.portalRenderFBO ); } { if ( glConfig2.textureNPOTAvailable ) { width = glConfig.vidWidth * 0.25f; height = glConfig.vidHeight * 0.25f; } else { width = NearestPowerOfTwo( glConfig.vidWidth * 0.25f ); height = NearestPowerOfTwo( glConfig.vidHeight * 0.25f ); } tr.downScaleFBO_quarter = R_CreateFBO( "_downScale_quarter", width, height ); R_BindFBO( tr.downScaleFBO_quarter ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.downScaleFBOImage_quarter->texnum, 0 ); R_CheckFBO( tr.downScaleFBO_quarter ); tr.downScaleFBO_64x64 = R_CreateFBO( "_downScale_64x64", 64, 64 ); R_BindFBO( tr.downScaleFBO_64x64 ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.downScaleFBOImage_64x64->texnum, 0 ); R_CheckFBO( tr.downScaleFBO_64x64 ); #if 0 tr.downScaleFBO_16x16 = R_CreateFBO( "_downScale_16x16", 16, 16 ); R_BindFBO( tr.downScaleFBO_16x16 ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.downScaleFBOImage_16x16->texnum, 0 ); R_CheckFBO( tr.downScaleFBO_16x16 ); tr.downScaleFBO_4x4 = R_CreateFBO( "_downScale_4x4", 4, 4 ); R_BindFBO( tr.downScaleFBO_4x4 ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.downScaleFBOImage_4x4->texnum, 0 ); R_CheckFBO( tr.downScaleFBO_4x4 ); tr.downScaleFBO_1x1 = R_CreateFBO( "_downScale_1x1", 1, 1 ); R_BindFBO( tr.downScaleFBO_1x1 ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.downScaleFBOImage_1x1->texnum, 0 ); R_CheckFBO( tr.downScaleFBO_1x1 ); #endif if ( glConfig2.textureNPOTAvailable ) { width = glConfig.vidWidth * 0.25f; height = glConfig.vidHeight * 0.25f; } else { width = NearestPowerOfTwo( glConfig.vidWidth * 0.25f ); height = NearestPowerOfTwo( glConfig.vidHeight * 0.25f ); } tr.contrastRenderFBO = R_CreateFBO( "_contrastRender", width, height ); R_BindFBO( tr.contrastRenderFBO ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.contrastRenderFBOImage->texnum, 0 ); R_CheckFBO( tr.contrastRenderFBO ); for ( i = 0; i < 2; i++ ) { tr.bloomRenderFBO[ i ] = R_CreateFBO( va( "_bloomRender%d", i ), width, height ); R_BindFBO( tr.bloomRenderFBO[ i ] ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.bloomRenderFBOImage[ i ]->texnum, 0 ); R_CheckFBO( tr.bloomRenderFBO[ i ] ); } } GL_CheckErrors(); #endif // defined(USE_D3D10) R_BindNullFBO(); }
/* ===================== R_PerformanceCounters ===================== */ void R_PerformanceCounters(void) { if (!r_speeds->integer) { // clear the counters even if we aren't printing Com_Memset(&tr.pc, 0, sizeof(tr.pc)); Com_Memset(&backEnd.pc, 0, sizeof(backEnd.pc)); return; } if (r_speeds->integer == RSPEEDS_GENERAL) { ri.Printf(PRINT_ALL, "%i views %i portals %i batches %i surfs %i leafs %i verts %i tris\n", backEnd.pc.c_views, backEnd.pc.c_portals, backEnd.pc.c_batches, backEnd.pc.c_surfaces, tr.pc.c_leafs, backEnd.pc.c_vertexes, backEnd.pc.c_indexes / 3); ri.Printf(PRINT_ALL, "%i lights %i bout %i pvsout %i queryout %i interactions\n", tr.pc.c_dlights + tr.pc.c_slights - backEnd.pc.c_occlusionQueriesLightsCulled, tr.pc.c_box_cull_light_out, tr.pc.c_pvs_cull_light_out, backEnd.pc.c_occlusionQueriesLightsCulled, tr.pc.c_dlightInteractions + tr.pc.c_slightInteractions - backEnd.pc.c_occlusionQueriesInteractionsCulled); ri.Printf(PRINT_ALL, "%i draws %i queries %i CHC++ ms %i vbos %i ibos %i verts %i tris\n", backEnd.pc.c_drawElements, tr.pc.c_occlusionQueries, tr.pc.c_CHCTime, backEnd.pc.c_vboVertexBuffers, backEnd.pc.c_vboIndexBuffers, backEnd.pc.c_vboVertexes, backEnd.pc.c_vboIndexes / 3); ri.Printf(PRINT_ALL, "%i multidraws %i primitives %i tris\n", backEnd.pc.c_multiDrawElements, backEnd.pc.c_multiDrawPrimitives, backEnd.pc.c_multiVboIndexes / 3); } else if (r_speeds->integer == RSPEEDS_CULLING) { ri.Printf(PRINT_ALL, "(gen) %i sin %i sout %i pin %i pout\n", tr.pc.c_sphere_cull_in, tr.pc.c_sphere_cull_out, tr.pc.c_plane_cull_in, tr.pc.c_plane_cull_out); ri.Printf(PRINT_ALL, "(patch) %i sin %i sclip %i sout %i bin %i bclip %i bout\n", tr.pc.c_sphere_cull_patch_in, tr.pc.c_sphere_cull_patch_clip, tr.pc.c_sphere_cull_patch_out, tr.pc.c_box_cull_patch_in, tr.pc.c_box_cull_patch_clip, tr.pc.c_box_cull_patch_out); ri.Printf(PRINT_ALL, "(mdx) %i sin %i sclip %i sout %i bin %i bclip %i bout\n", tr.pc.c_sphere_cull_mdx_in, tr.pc.c_sphere_cull_mdx_clip, tr.pc.c_sphere_cull_mdx_out, tr.pc.c_box_cull_mdx_in, tr.pc.c_box_cull_mdx_clip, tr.pc.c_box_cull_mdx_out); ri.Printf(PRINT_ALL, "(md5) %i bin %i bclip %i bout\n", tr.pc.c_box_cull_md5_in, tr.pc.c_box_cull_md5_clip, tr.pc.c_box_cull_md5_out); } else if (r_speeds->integer == RSPEEDS_VIEWCLUSTER) { ri.Printf(PRINT_ALL, "viewcluster: %i\n", tr.visClusters[tr.visIndex]); } else if (r_speeds->integer == RSPEEDS_LIGHTS) { ri.Printf(PRINT_ALL, "dlight srf:%i culled:%i\n", tr.pc.c_dlightSurfaces, tr.pc.c_dlightSurfacesCulled); ri.Printf(PRINT_ALL, "dlights:%i interactions:%i\n", tr.pc.c_dlights, tr.pc.c_dlightInteractions); ri.Printf(PRINT_ALL, "slights:%i interactions:%i\n", tr.pc.c_slights, tr.pc.c_slightInteractions); } else if (r_speeds->integer == RSPEEDS_SHADOWCUBE_CULLING) { ri.Printf(PRINT_ALL, "omni pyramid tests:%i bin:%i bclip:%i bout:%i\n", tr.pc.c_pyramidTests, tr.pc.c_pyramid_cull_ent_in, tr.pc.c_pyramid_cull_ent_clip, tr.pc.c_pyramid_cull_ent_out); } else if (r_speeds->integer == RSPEEDS_FOG) { ri.Printf(PRINT_ALL, "fog srf:%i batches:%i\n", backEnd.pc.c_fogSurfaces, backEnd.pc.c_fogBatches); } else if (r_speeds->integer == RSPEEDS_FLARES) { ri.Printf(PRINT_ALL, "flare adds:%i tests:%i renders:%i\n", backEnd.pc.c_flareAdds, backEnd.pc.c_flareTests, backEnd.pc.c_flareRenders); } else if (r_speeds->integer == RSPEEDS_OCCLUSION_QUERIES) { ri.Printf(PRINT_ALL, "occlusion queries:%i multi:%i saved:%i culled lights:%i culled entities:%i culled leafs:%i response time:%i fetch time:%i\n", backEnd.pc.c_occlusionQueries, backEnd.pc.c_occlusionQueriesMulti, backEnd.pc.c_occlusionQueriesSaved, backEnd.pc.c_occlusionQueriesLightsCulled, backEnd.pc.c_occlusionQueriesEntitiesCulled, backEnd.pc.c_occlusionQueriesLeafsCulled, backEnd.pc.c_occlusionQueriesResponseTime, backEnd.pc.c_occlusionQueriesFetchTime); } #if 0 else if (r_speeds->integer == RSPEEDS_DEPTH_BOUNDS_TESTS) { ri.Printf(PRINT_ALL, "depth bounds tests:%i rejected:%i\n", tr.pc.c_depthBoundsTests, tr.pc.c_depthBoundsTestsRejected); } #endif else if (r_speeds->integer == RSPEEDS_SHADING_TIMES) { if (DS_STANDARD_ENABLED()) { ri.Printf(PRINT_ALL, "deferred shading times: g-buffer:%i lighting:%i translucent:%i\n", backEnd.pc.c_deferredGBufferTime, backEnd.pc.c_deferredLightingTime, backEnd.pc.c_forwardTranslucentTime); } else { ri.Printf(PRINT_ALL, "forward shading times: ambient:%i lighting:%i\n", backEnd.pc.c_forwardAmbientTime, backEnd.pc.c_forwardLightingTime); } } else if (r_speeds->integer == RSPEEDS_CHC) { ri.Printf(PRINT_ALL, "%i CHC++ ms %i queries %i multi queries %i saved\n", tr.pc.c_CHCTime, tr.pc.c_occlusionQueries, tr.pc.c_occlusionQueriesMulti, tr.pc.c_occlusionQueriesSaved); } else if (r_speeds->integer == RSPEEDS_NEAR_FAR) { ri.Printf(PRINT_ALL, "zNear: %.0f zFar: %.0f\n", tr.viewParms.zNear, tr.viewParms.zFar); } else if (r_speeds->integer == RSPEEDS_DECALS) { ri.Printf(PRINT_ALL, "decal projectors: %d test surfs: %d clip surfs: %d decal surfs: %d created: %d\n", tr.pc.c_decalProjectors, tr.pc.c_decalTestSurfaces, tr.pc.c_decalClipSurfaces, tr.pc.c_decalSurfaces, tr.pc.c_decalSurfacesCreated); } Com_Memset(&tr.pc, 0, sizeof(tr.pc)); Com_Memset(&backEnd.pc, 0, sizeof(backEnd.pc)); }