/* ============ FBO_Init ============ */ void FBO_Init(void) { int i; // int width, height, hdrFormat, multisample; int hdrFormat, multisample; ri.Printf(PRINT_ALL, "------- FBO_Init -------\n"); if(!glRefConfig.framebufferObject) return; tr.numFBOs = 0; GL_CheckErrors(); R_IssuePendingRenderCommands(); /* if(glRefConfig.textureNonPowerOfTwo) { width = glConfig.vidWidth; height = glConfig.vidHeight; } else { width = NextPowerOfTwo(glConfig.vidWidth); height = NextPowerOfTwo(glConfig.vidHeight); } */ hdrFormat = GL_RGBA8; if (r_hdr->integer && glRefConfig.framebufferObject && glRefConfig.textureFloat) { hdrFormat = GL_RGBA16F_ARB; } qglGetIntegerv(GL_MAX_SAMPLES_EXT, &multisample); if (r_ext_framebuffer_multisample->integer < multisample) { multisample = r_ext_framebuffer_multisample->integer; } if (multisample < 2 || !glRefConfig.framebufferBlit) multisample = 0; if (multisample != r_ext_framebuffer_multisample->integer) { ri.Cvar_SetValue("r_ext_framebuffer_multisample", (float)multisample); } // only create a render FBO if we need to resolve MSAA or do HDR // otherwise just render straight to the screen (tr.renderFbo = NULL) if (multisample && glRefConfig.framebufferMultisample) { tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height); FBO_Bind(tr.renderFbo); FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, multisample); FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, multisample); R_CheckFBO(tr.renderFbo); tr.msaaResolveFbo = FBO_Create("_msaaResolve", tr.renderDepthImage->width, tr.renderDepthImage->height); FBO_Bind(tr.msaaResolveFbo); //FBO_CreateBuffer(tr.msaaResolveFbo, hdrFormat, 0, 0); FBO_AttachTextureImage(tr.renderImage, 0); //FBO_CreateBuffer(tr.msaaResolveFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); R_AttachFBOTextureDepth(tr.renderDepthImage->texnum); R_CheckFBO(tr.msaaResolveFbo); } else if (r_hdr->integer) { tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height); FBO_Bind(tr.renderFbo); //FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, 0); FBO_AttachTextureImage(tr.renderImage, 0); //FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); R_AttachFBOTextureDepth(tr.renderDepthImage->texnum); R_CheckFBO(tr.renderFbo); } // clear render buffer // this fixes the corrupt screen bug with r_hdr 1 on older hardware if (tr.renderFbo) { FBO_Bind(tr.renderFbo); qglClearColor( 1, 0, 0.5, 1 ); qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); FBO_Bind(NULL); } if (r_drawSunRays->integer) { tr.sunRaysFbo = FBO_Create("_sunRays", tr.renderDepthImage->width, tr.renderDepthImage->height); FBO_Bind(tr.sunRaysFbo); FBO_AttachTextureImage(tr.sunRaysImage, 0); R_AttachFBOTextureDepth(tr.renderDepthImage->texnum); R_CheckFBO(tr.sunRaysFbo); } // FIXME: Don't use separate color/depth buffers for a shadow buffer if (MAX_DRAWN_PSHADOWS && tr.pshadowMaps[0]) { for( i = 0; i < MAX_DRAWN_PSHADOWS; i++) { tr.pshadowFbos[i] = FBO_Create(va("_shadowmap%d", i), tr.pshadowMaps[i]->width, tr.pshadowMaps[i]->height); FBO_Bind(tr.pshadowFbos[i]); //FBO_CreateBuffer(tr.pshadowFbos[i], GL_RGBA8, 0, 0); FBO_AttachTextureImage(tr.pshadowMaps[i], 0); FBO_CreateBuffer(tr.pshadowFbos[i], GL_DEPTH_COMPONENT24_ARB, 0, 0); //R_AttachFBOTextureDepth(tr.textureDepthImage->texnum); R_CheckFBO(tr.pshadowFbos[i]); } } if (tr.sunShadowDepthImage[0]) { for ( i = 0; i < 4; i++) { tr.sunShadowFbo[i] = FBO_Create("_sunshadowmap", tr.sunShadowDepthImage[i]->width, tr.sunShadowDepthImage[i]->height); FBO_Bind(tr.sunShadowFbo[i]); //FBO_CreateBuffer(tr.sunShadowFbo[i], GL_RGBA8, 0, 0); //FBO_AttachTextureImage(tr.sunShadowImage, 0); qglDrawBuffer(GL_NONE); qglReadBuffer(GL_NONE); //FBO_CreateBuffer(tr.sunShadowFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); R_AttachFBOTextureDepth(tr.sunShadowDepthImage[i]->texnum); R_CheckFBO(tr.sunShadowFbo[i]); } tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height); FBO_Bind(tr.screenShadowFbo); FBO_AttachTextureImage(tr.screenShadowImage, 0); R_CheckFBO(tr.screenShadowFbo); } for (i = 0; i < 2; i++) { tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height); FBO_Bind(tr.textureScratchFbo[i]); //FBO_CreateBuffer(tr.textureScratchFbo[i], GL_RGBA8, 0, 0); FBO_AttachTextureImage(tr.textureScratchImage[i], 0); R_CheckFBO(tr.textureScratchFbo[i]); } { tr.calcLevelsFbo = FBO_Create("_calclevels", tr.calcLevelsImage->width, tr.calcLevelsImage->height); FBO_Bind(tr.calcLevelsFbo); //FBO_CreateBuffer(tr.calcLevelsFbo, hdrFormat, 0, 0); FBO_AttachTextureImage(tr.calcLevelsImage, 0); R_CheckFBO(tr.calcLevelsFbo); } { tr.targetLevelsFbo = FBO_Create("_targetlevels", tr.targetLevelsImage->width, tr.targetLevelsImage->height); FBO_Bind(tr.targetLevelsFbo); //FBO_CreateBuffer(tr.targetLevelsFbo, hdrFormat, 0, 0); FBO_AttachTextureImage(tr.targetLevelsImage, 0); R_CheckFBO(tr.targetLevelsFbo); } for (i = 0; i < 2; i++) { tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height); FBO_Bind(tr.quarterFbo[i]); //FBO_CreateBuffer(tr.quarterFbo[i], hdrFormat, 0, 0); FBO_AttachTextureImage(tr.quarterImage[i], 0); R_CheckFBO(tr.quarterFbo[i]); } if (r_ssao->integer) { tr.hdrDepthFbo = FBO_Create("_hdrDepth", tr.hdrDepthImage->width, tr.hdrDepthImage->height); FBO_Bind(tr.hdrDepthFbo); FBO_AttachTextureImage(tr.hdrDepthImage, 0); R_CheckFBO(tr.hdrDepthFbo); tr.screenSsaoFbo = FBO_Create("_screenssao", tr.screenSsaoImage->width, tr.screenSsaoImage->height); FBO_Bind(tr.screenSsaoFbo); FBO_AttachTextureImage(tr.screenSsaoImage, 0); R_CheckFBO(tr.screenSsaoFbo); } if (tr.renderCubeImage) { tr.renderCubeFbo = FBO_Create("_renderCubeFbo", tr.renderCubeImage->width, tr.renderCubeImage->height); FBO_Bind(tr.renderCubeFbo); //FBO_AttachTextureImage(tr.renderCubeImage, 0); R_AttachFBOTexture2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, tr.renderCubeImage->texnum, 0); glState.currentFBO->colorImage[0] = tr.renderCubeImage; FBO_CreateBuffer(tr.renderCubeFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); R_CheckFBO(tr.renderCubeFbo); } GL_CheckErrors(); FBO_Bind(NULL); }
/* ============ FBO_Init ============ */ void FBO_Init(void) { int i; int hdrFormat, multisample = 0; ri.Printf(PRINT_ALL, "------- FBO_Init -------\n"); if(!glRefConfig.framebufferObject) return; tr.numFBOs = 0; GL_CheckErrors(); R_IssuePendingRenderCommands(); hdrFormat = GL_RGBA8; if (r_hdr->integer && glRefConfig.textureFloat) hdrFormat = GL_RGBA16F_ARB; if (glRefConfig.framebufferMultisample) qglGetIntegerv(GL_MAX_SAMPLES, &multisample); if (r_ext_framebuffer_multisample->integer < multisample) multisample = r_ext_framebuffer_multisample->integer; if (multisample < 2 || !glRefConfig.framebufferBlit) multisample = 0; if (multisample != r_ext_framebuffer_multisample->integer) ri.Cvar_SetValue("r_ext_framebuffer_multisample", (float)multisample); // only create a render FBO if we need to resolve MSAA or do HDR // otherwise just render straight to the screen (tr.renderFbo = NULL) if (multisample && glRefConfig.framebufferMultisample) { tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height); FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, multisample); FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24, 0, multisample); R_CheckFBO(tr.renderFbo); tr.msaaResolveFbo = FBO_Create("_msaaResolve", tr.renderDepthImage->width, tr.renderDepthImage->height); FBO_AttachImage(tr.msaaResolveFbo, tr.renderImage, GL_COLOR_ATTACHMENT0, 0); FBO_AttachImage(tr.msaaResolveFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0); R_CheckFBO(tr.msaaResolveFbo); } else if (r_hdr->integer) { tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height); FBO_AttachImage(tr.renderFbo, tr.renderImage, GL_COLOR_ATTACHMENT0, 0); FBO_AttachImage(tr.renderFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0); R_CheckFBO(tr.renderFbo); } // clear render buffer // this fixes the corrupt screen bug with r_hdr 1 on older hardware if (tr.renderFbo) { GL_BindFramebuffer(GL_FRAMEBUFFER, tr.renderFbo->frameBuffer); qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); } if (tr.screenScratchImage) { tr.screenScratchFbo = FBO_Create("screenScratch", tr.screenScratchImage->width, tr.screenScratchImage->height); FBO_AttachImage(tr.screenScratchFbo, tr.screenScratchImage, GL_COLOR_ATTACHMENT0, 0); FBO_AttachImage(tr.screenScratchFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0); R_CheckFBO(tr.screenScratchFbo); } if (tr.sunRaysImage) { tr.sunRaysFbo = FBO_Create("_sunRays", tr.renderDepthImage->width, tr.renderDepthImage->height); FBO_AttachImage(tr.sunRaysFbo, tr.sunRaysImage, GL_COLOR_ATTACHMENT0, 0); FBO_AttachImage(tr.sunRaysFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0); R_CheckFBO(tr.sunRaysFbo); } if (MAX_DRAWN_PSHADOWS && tr.pshadowMaps[0]) { for( i = 0; i < MAX_DRAWN_PSHADOWS; i++) { tr.pshadowFbos[i] = FBO_Create(va("_shadowmap%d", i), tr.pshadowMaps[i]->width, tr.pshadowMaps[i]->height); // FIXME: this next line wastes 16mb with 16x512x512 sun shadow maps, skip if OpenGL 4.3+ or ARB_framebuffer_no_attachments FBO_CreateBuffer(tr.pshadowFbos[i], GL_RGBA8, 0, 0); FBO_AttachImage(tr.pshadowFbos[i], tr.pshadowMaps[i], GL_DEPTH_ATTACHMENT, 0); R_CheckFBO(tr.pshadowFbos[i]); } } if (tr.sunShadowDepthImage[0]) { for (i = 0; i < 4; i++) { tr.sunShadowFbo[i] = FBO_Create("_sunshadowmap", tr.sunShadowDepthImage[i]->width, tr.sunShadowDepthImage[i]->height); // FIXME: this next line wastes 16mb with 4x1024x1024 sun shadow maps, skip if OpenGL 4.3+ or ARB_framebuffer_no_attachments // This at least gets sun shadows working on older GPUs (Intel) FBO_CreateBuffer(tr.sunShadowFbo[i], GL_RGBA8, 0, 0); FBO_AttachImage(tr.sunShadowFbo[i], tr.sunShadowDepthImage[i], GL_DEPTH_ATTACHMENT, 0); R_CheckFBO(tr.sunShadowFbo[i]); } } if (tr.screenShadowImage) { tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height); FBO_AttachImage(tr.screenShadowFbo, tr.screenShadowImage, GL_COLOR_ATTACHMENT0, 0); R_CheckFBO(tr.screenShadowFbo); } if (tr.textureScratchImage[0]) { for (i = 0; i < 2; i++) { tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height); FBO_AttachImage(tr.textureScratchFbo[i], tr.textureScratchImage[i], GL_COLOR_ATTACHMENT0, 0); R_CheckFBO(tr.textureScratchFbo[i]); } } if (tr.calcLevelsImage) { tr.calcLevelsFbo = FBO_Create("_calclevels", tr.calcLevelsImage->width, tr.calcLevelsImage->height); FBO_AttachImage(tr.calcLevelsFbo, tr.calcLevelsImage, GL_COLOR_ATTACHMENT0, 0); R_CheckFBO(tr.calcLevelsFbo); } if (tr.targetLevelsImage) { tr.targetLevelsFbo = FBO_Create("_targetlevels", tr.targetLevelsImage->width, tr.targetLevelsImage->height); FBO_AttachImage(tr.targetLevelsFbo, tr.targetLevelsImage, GL_COLOR_ATTACHMENT0, 0); R_CheckFBO(tr.targetLevelsFbo); } if (tr.quarterImage[0]) { for (i = 0; i < 2; i++) { tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height); FBO_AttachImage(tr.quarterFbo[i], tr.quarterImage[i], GL_COLOR_ATTACHMENT0, 0); R_CheckFBO(tr.quarterFbo[i]); } } if (tr.hdrDepthImage) { tr.hdrDepthFbo = FBO_Create("_hdrDepth", tr.hdrDepthImage->width, tr.hdrDepthImage->height); FBO_AttachImage(tr.hdrDepthFbo, tr.hdrDepthImage, GL_COLOR_ATTACHMENT0, 0); R_CheckFBO(tr.hdrDepthFbo); } if (tr.screenSsaoImage) { tr.screenSsaoFbo = FBO_Create("_screenssao", tr.screenSsaoImage->width, tr.screenSsaoImage->height); FBO_AttachImage(tr.screenSsaoFbo, tr.screenSsaoImage, GL_COLOR_ATTACHMENT0, 0); R_CheckFBO(tr.screenSsaoFbo); } if (tr.renderCubeImage) { tr.renderCubeFbo = FBO_Create("_renderCubeFbo", tr.renderCubeImage->width, tr.renderCubeImage->height); FBO_AttachImage(tr.renderCubeFbo, tr.renderCubeImage, GL_COLOR_ATTACHMENT0, 0); FBO_CreateBuffer(tr.renderCubeFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); R_CheckFBO(tr.renderCubeFbo); } GL_CheckErrors(); GL_BindFramebuffer(GL_FRAMEBUFFER, 0); glState.currentFBO = NULL; }