GLvoid APIENTRY GLDSA_GenerateTextureMipmap(GLuint texture, GLenum target) { GL_BindMultiTexture(glDsaState.texunit, target, texture); qglGenerateMipmapEXT(target); }
/* ============= RB_DrawSurfs ============= */ const void *RB_DrawSurfs( const void *data ) { const drawSurfsCommand_t *cmd; // finish any 2D drawing if needed if ( tess.numIndexes ) { RB_EndSurface(); } cmd = (const drawSurfsCommand_t *)data; backEnd.refdef = cmd->refdef; backEnd.viewParms = cmd->viewParms; // clear the z buffer, set the modelview, etc RB_BeginDrawingView (); if (glRefConfig.framebufferObject && (backEnd.viewParms.flags & VPF_DEPTHCLAMP) && glRefConfig.depthClamp) { qglEnable(GL_DEPTH_CLAMP); } if (glRefConfig.framebufferObject && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) && (r_depthPrepass->integer || (backEnd.viewParms.flags & VPF_DEPTHSHADOW))) { FBO_t *oldFbo = glState.currentFBO; backEnd.depthFill = qtrue; qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); qglColorMask(!backEnd.colorMask[0], !backEnd.colorMask[1], !backEnd.colorMask[2], !backEnd.colorMask[3]); backEnd.depthFill = qfalse; if (tr.msaaResolveFbo) { // If we're using multisampling, resolve the depth first FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_DEPTH_BUFFER_BIT, GL_NEAREST); } else if (tr.renderFbo == NULL) { // If we're rendering directly to the screen, copy the depth to a texture GL_BindToTMU(tr.renderDepthImage, 0); qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 0, 0, glConfig.vidWidth, glConfig.vidHeight, 0); } if (r_ssao->integer) { // need the depth in a texture we can do GL_LINEAR sampling on, so copy it to an HDR image FBO_BlitFromTexture(tr.renderDepthImage, NULL, NULL, tr.hdrDepthFbo, NULL, NULL, NULL, 0); } if (r_sunlightMode->integer && backEnd.viewParms.flags & VPF_USESUNLIGHT) { vec4_t quadVerts[4]; vec2_t texCoords[4]; vec4_t box; FBO_Bind(tr.screenShadowFbo); box[0] = backEnd.viewParms.viewportX * tr.screenShadowFbo->width / (float)glConfig.vidWidth; box[1] = backEnd.viewParms.viewportY * tr.screenShadowFbo->height / (float)glConfig.vidHeight; box[2] = backEnd.viewParms.viewportWidth * tr.screenShadowFbo->width / (float)glConfig.vidWidth; box[3] = backEnd.viewParms.viewportHeight * tr.screenShadowFbo->height / (float)glConfig.vidHeight; qglViewport(box[0], box[1], box[2], box[3]); qglScissor(box[0], box[1], box[2], box[3]); box[0] = backEnd.viewParms.viewportX / (float)glConfig.vidWidth; box[1] = backEnd.viewParms.viewportY / (float)glConfig.vidHeight; box[2] = box[0] + backEnd.viewParms.viewportWidth / (float)glConfig.vidWidth; box[3] = box[1] + backEnd.viewParms.viewportHeight / (float)glConfig.vidHeight; texCoords[0][0] = box[0]; texCoords[0][1] = box[3]; texCoords[1][0] = box[2]; texCoords[1][1] = box[3]; texCoords[2][0] = box[2]; texCoords[2][1] = box[1]; texCoords[3][0] = box[0]; texCoords[3][1] = box[1]; box[0] = -1.0f; box[1] = -1.0f; box[2] = 1.0f; box[3] = 1.0f; VectorSet4(quadVerts[0], box[0], box[3], 0, 1); VectorSet4(quadVerts[1], box[2], box[3], 0, 1); VectorSet4(quadVerts[2], box[2], box[1], 0, 1); VectorSet4(quadVerts[3], box[0], box[1], 0, 1); GL_State( GLS_DEPTHTEST_DISABLE ); GLSL_BindProgram(&tr.shadowmaskShader); GL_BindToTMU(tr.renderDepthImage, TB_COLORMAP); if (r_shadowCascadeZFar->integer != 0) { GL_BindToTMU(tr.sunShadowDepthImage[0], TB_SHADOWMAP); GL_BindToTMU(tr.sunShadowDepthImage[1], TB_SHADOWMAP2); GL_BindToTMU(tr.sunShadowDepthImage[2], TB_SHADOWMAP3); GL_BindToTMU(tr.sunShadowDepthImage[3], TB_SHADOWMAP4); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[0]); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP2, backEnd.refdef.sunShadowMvp[1]); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP3, backEnd.refdef.sunShadowMvp[2]); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP4, backEnd.refdef.sunShadowMvp[3]); } else { GL_BindToTMU(tr.sunShadowDepthImage[3], TB_SHADOWMAP); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[3]); } GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWORIGIN, backEnd.refdef.vieworg); { vec4_t viewInfo; vec3_t viewVector; float zmax = backEnd.viewParms.zFar; float ymax = zmax * tan(backEnd.viewParms.fovY * M_PI / 360.0f); float xmax = zmax * tan(backEnd.viewParms.fovX * M_PI / 360.0f); float zmin = r_znear->value; VectorScale(backEnd.refdef.viewaxis[0], zmax, viewVector); GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWFORWARD, viewVector); VectorScale(backEnd.refdef.viewaxis[1], xmax, viewVector); GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWLEFT, viewVector); VectorScale(backEnd.refdef.viewaxis[2], ymax, viewVector); GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWUP, viewVector); VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); GLSL_SetUniformVec4(&tr.shadowmaskShader, UNIFORM_VIEWINFO, viewInfo); } RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); } if (r_ssao->integer) { vec4_t quadVerts[4]; vec2_t texCoords[4]; FBO_Bind(tr.quarterFbo[0]); qglViewport(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height); qglScissor(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height); VectorSet4(quadVerts[0], -1, 1, 0, 1); VectorSet4(quadVerts[1], 1, 1, 0, 1); VectorSet4(quadVerts[2], 1, -1, 0, 1); VectorSet4(quadVerts[3], -1, -1, 0, 1); texCoords[0][0] = 0; texCoords[0][1] = 1; texCoords[1][0] = 1; texCoords[1][1] = 1; texCoords[2][0] = 1; texCoords[2][1] = 0; texCoords[3][0] = 0; texCoords[3][1] = 0; GL_State( GLS_DEPTHTEST_DISABLE ); GLSL_BindProgram(&tr.ssaoShader); GL_BindToTMU(tr.hdrDepthImage, TB_COLORMAP); { vec4_t viewInfo; float zmax = backEnd.viewParms.zFar; float zmin = r_znear->value; VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); GLSL_SetUniformVec4(&tr.ssaoShader, UNIFORM_VIEWINFO, viewInfo); } RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); FBO_Bind(tr.quarterFbo[1]); qglViewport(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height); qglScissor(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height); GLSL_BindProgram(&tr.depthBlurShader[0]); GL_BindToTMU(tr.quarterImage[0], TB_COLORMAP); GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP); { vec4_t viewInfo; float zmax = backEnd.viewParms.zFar; float zmin = r_znear->value; VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo); } RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); FBO_Bind(tr.screenSsaoFbo); qglViewport(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height); qglScissor(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height); GLSL_BindProgram(&tr.depthBlurShader[1]); GL_BindToTMU(tr.quarterImage[1], TB_COLORMAP); GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP); { vec4_t viewInfo; float zmax = backEnd.viewParms.zFar; float zmin = r_znear->value; VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo); } RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); } // reset viewport and scissor FBO_Bind(oldFbo); SetViewportAndScissor(); } if (glRefConfig.framebufferObject && (backEnd.viewParms.flags & VPF_DEPTHCLAMP) && glRefConfig.depthClamp) { qglDisable(GL_DEPTH_CLAMP); } if (!(backEnd.viewParms.flags & VPF_DEPTHSHADOW)) { RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); if (r_drawSun->integer) { RB_DrawSun(0.1, tr.sunShader); } if (r_drawSunRays->integer) { FBO_t *oldFbo = glState.currentFBO; FBO_Bind(tr.sunRaysFbo); qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); qglClear( GL_COLOR_BUFFER_BIT ); if (glRefConfig.occlusionQuery) { tr.sunFlareQueryActive[tr.sunFlareQueryIndex] = qtrue; qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, tr.sunFlareQuery[tr.sunFlareQueryIndex]); } RB_DrawSun(0.3, tr.sunFlareShader); if (glRefConfig.occlusionQuery) { qglEndQueryARB(GL_SAMPLES_PASSED_ARB); } FBO_Bind(oldFbo); } // darken down any stencil shadows RB_ShadowFinish(); // add light flares on lights that aren't obscured RB_RenderFlares(); } if (glRefConfig.framebufferObject && tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo) { FBO_Bind(NULL); GL_SelectTexture(TB_CUBEMAP); GL_BindToTMU(tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex], TB_CUBEMAP); qglGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP); GL_SelectTexture(0); } return (const void *)(cmd + 1); }
/** * @brief handle post-processing bloom */ void R_DrawBloom (void) { int i; bool renderBufferState; if (!r_config.frameBufferObject || !r_postprocess->integer || !r_programs->integer) return; /* save state, then set up for blit-style rendering to quads */ renderBufferState = R_RenderbufferEnabled(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); #ifndef GL_VERSION_ES_CM_1_0 glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT | GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT); #endif glOrtho(0, viddef.context.width, viddef.context.height, 0, 9999.0f, SKYBOX_DEPTH); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); /* downsample into image pyramid */ R_ResolveMSAA(fbo_render); R_BindTexture(fbo_render->textures[1]); qglGenerateMipmapEXT(GL_TEXTURE_2D); R_Blur(fbo_render, fbo_bloom0, 1, 0); R_Blur(fbo_bloom0, fbo_bloom1, 0, 1); R_UseFramebuffer(r_state.buffers0[0]); R_BindTexture(fbo_bloom1->textures[0]); qglGenerateMipmapEXT(GL_TEXTURE_2D); R_UseViewport(r_state.buffers0[0]); R_DrawQuad(); for (i = 1; i < DOWNSAMPLE_PASSES; i++) { R_Blur(r_state.buffers0[i - 1], r_state.buffers1[i - 1], 0, 0); R_Blur(r_state.buffers1[i - 1], r_state.buffers2[i - 1], 0, 1); R_UseFramebuffer(r_state.buffers0[i]); R_BindTexture(r_state.buffers2[i - 1]->textures[0]); R_UseViewport(r_state.buffers0[i]); R_DrawQuad(); } /* blur and combine downsampled images */ R_BlurStack(DOWNSAMPLE_PASSES, r_state.buffers0, r_state.buffers1); /* re-combine the blurred version with the original "glow" image */ R_UseProgram(r_state.combine2_program); R_UseFramebuffer(fbo_bloom0); R_BindTextureForTexUnit(fbo_render->textures[1], &texunit_0); R_BindTextureForTexUnit(r_state.buffers1[0]->textures[0], &texunit_1); R_UseViewport(fbo_screen); R_DrawQuad(); /* draw final result to the screenbuffer */ R_UseFramebuffer(fbo_screen); R_UseProgram(r_state.combine2_program); R_BindTextureForTexUnit(fbo_render->textures[0], &texunit_0); R_BindTextureForTexUnit(fbo_bloom0->textures[0], &texunit_1); R_DrawQuad(); /* cleanup before returning */ R_UseProgram(default_program); R_CheckError(); #ifndef GL_VERSION_ES_CM_1_0 glPopAttrib(); #endif glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); R_CheckError(); /* reset renderbuffer state to what it was before */ R_EnableRenderbuffer(renderBufferState); }
/** * @brief create a new framebuffer object * @param[in] width The width of the framebuffer * @param[in] height The height of the framebuffer * @param[in] ntextures The amount of textures for this framebuffer. See also the filters array. * @param[in] depth Also generate a depth buffer * @param[in] halfFloat Use half float pixel format * @param[in] filters Filters for the textures. Must have @c ntextures entries */ r_framebuffer_t * R_CreateFramebuffer (int width, int height, int ntextures, bool depth, bool halfFloat, unsigned int *filters) { r_framebuffer_t *buf; int i; if (!r_state.frameBufferObjectsInitialized) { Com_Printf("Warning: framebuffer creation failed; framebuffers not initialized!\n"); return NULL; } if (frameBufferObjectCount >= lengthof(frameBufferObjects)) { Com_Printf("Warning: framebuffer creation failed; already created too many framebuffers!\n"); return NULL; } buf = &frameBufferObjects[frameBufferObjectCount++]; OBJZERO(*buf); if (ntextures > r_config.maxDrawBuffers) { Com_Printf("Couldn't allocate requested number of drawBuffers in R_SetupFramebuffer!\n"); ntextures = r_config.maxDrawBuffers; } Vector4Clear(buf->clearColor); buf->width = width; buf->height = height; R_SetupViewport(buf, 0, 0, width, height); buf->nTextures = ntextures; buf->textures = Mem_AllocTypeN(unsigned int, ntextures); buf->pixelFormat = halfFloat ? GL_RGBA16F_ARB : GL_RGBA8; buf->byteFormat = halfFloat ? GL_HALF_FLOAT_ARB : GL_UNSIGNED_BYTE; /* Presence of depth buffer indicates render target that could use antialiasing*/ if (depth) { /** @todo also check if we are running on older (SM2.0) hardware, which doesn't support antialiased MRT */ if (qglRenderbufferStorageMultisampleEXT && qglBlitFramebuffer) { int samples = std::min(4, std::max(0, r_multisample->integer)); if (samples>1) buf->samples = samples; } } for (i = 0; i < buf->nTextures; i++) { buf->textures[i] = R_GetFreeFBOTexture(); glBindTexture(GL_TEXTURE_2D, buf->textures[i]); glTexImage2D(GL_TEXTURE_2D, 0, buf->pixelFormat, buf->width, buf->height, 0, GL_RGBA, buf->byteFormat, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filters[i]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); qglGenerateMipmapEXT(GL_TEXTURE_2D); if (r_config.anisotropic) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, r_config.maxAnisotropic); R_CheckError(); } glBindTexture(GL_TEXTURE_2D, 0); /* create FBO itself */ qglGenFramebuffersEXT(1, &buf->fbo); R_CheckError(); qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buf->fbo); /* create&attach depth renderbuffer */ if (depth) { qglGenRenderbuffersEXT(1, &buf->depth); qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, buf->depth); if (buf->samples) qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, buf->samples, GL_DEPTH_COMPONENT, buf->width, buf->height); else qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, buf->width, buf->height); qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, buf->depth); } else { buf->depth = 0; } /* create multisample color buffers if needed */ if (buf->samples) { /* generate color buffers */ for (i = 0; i < buf->nTextures; i++) { unsigned colorbuffer; qglGenRenderbuffersEXT(1, &colorbuffer); qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, colorbuffer); qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, buf->samples, buf->pixelFormat, buf->width, buf->height); qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, colorAttachments[i], GL_RENDERBUFFER_EXT, colorbuffer); R_CheckError(); } /* proxy framebuffer object for resolving MSAA */ qglGenFramebuffersEXT(1, &buf->proxyFBO); R_CheckError(); qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buf->proxyFBO); } /* Whether multisampling was enabled or not, current FBO should be populated with render-to-texture bindings */ for (i = 0; i < buf->nTextures; i++) { qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, colorAttachments[i], GL_TEXTURE_2D, buf->textures[i], 0); R_CheckError(); } R_CheckError(); /* unbind the framebuffer and return to default state */ qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); return buf; }