r_framebuffer.c

Go to the documentation of this file.
00001 
00006 /*
00007  Copyright (C) 2008 Victor Luchits
00008 
00009  This program is free software; you can redistribute it and/or
00010  modify it under the terms of the GNU General Public License
00011  as published by the Free Software Foundation; either version 2
00012  of the License, or (at your option) any later version.
00013 
00014  This program is distributed in the hope that it will be useful,
00015  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018  See the GNU General Public License for more details.
00019 
00020  You should have received a copy of the GNU General Public License
00021  along with this program; if not, write to the Free Software
00022  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023  */
00024 
00025 #include "r_local.h"
00026 #include "r_framebuffer.h"
00027 #include "r_error.h"
00028 
00029 #define MAX_FRAMEBUFFER_OBJECTS     64
00030 
00031 static int frameBufferObjectCount;
00032 static r_framebuffer_t frameBufferObjects[MAX_FRAMEBUFFER_OBJECTS];
00033 static GLuint frameBufferTextures[TEXNUM_FRAMEBUFFER_TEXTURES];
00034 
00035 static r_framebuffer_t screenBuffer;
00036 static GLenum *colorAttachments;
00037 
00038 static GLuint R_GetFreeFBOTexture (void)
00039 {
00040     int i;
00041 
00042     for (i = 0; i < TEXNUM_FRAMEBUFFER_TEXTURES; i++) {
00043         if (frameBufferTextures[i] == 0) {
00044             frameBufferTextures[i] = 1;
00045             return TEXNUM_FRAMEBUFFER_TEXTURES + i;
00046         }
00047     }
00048 
00049     Com_Error(ERR_FATAL, "Exceeded max frame buffer textures");
00050 }
00051 
00052 static void R_FreeFBOTexture (int texnum)
00053 {
00054     const int i = texnum - TEXNUM_FRAMEBUFFER_TEXTURES;
00055     assert(i >= 0);
00056     assert(i < TEXNUM_FRAMEBUFFER_TEXTURES);
00057     frameBufferTextures[i] = 0;
00058     glDeleteTextures(1, (GLuint *) &texnum);
00059 }
00060 
00061 void R_InitFBObjects (void)
00062 {
00063     unsigned int filters[2];
00064     float scales[DOWNSAMPLE_PASSES];
00065     int i;
00066 
00067     if (!r_config.frameBufferObject || !r_programs->integer)
00068         return;
00069 
00070     frameBufferObjectCount = 0;
00071     memset(frameBufferObjects, 0, sizeof(frameBufferObjects));
00072     memset(frameBufferTextures, 0, sizeof(frameBufferTextures));
00073 
00074     r_state.frameBufferObjectsInitialized = qtrue;
00075 
00076     for (i = 0; i < DOWNSAMPLE_PASSES; i++)
00077         scales[i] = powf(DOWNSAMPLE_SCALE, i + 1);
00078 
00079     /* setup default screen framebuffer */
00080     screenBuffer.fbo = 0;
00081     screenBuffer.depth = 0;
00082     screenBuffer.nTextures = 0;
00083     screenBuffer.width = viddef.width;
00084     screenBuffer.height = viddef.height;
00085     R_SetupViewport(&screenBuffer, 0, 0, viddef.width, viddef.height);
00086     Vector4Clear(screenBuffer.clearColor);
00087 
00088     qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
00089     r_state.activeFramebuffer = &screenBuffer;
00090 
00091     colorAttachments = Mem_Alloc(sizeof(GLenum) * r_config.maxDrawBuffers);
00092     for (i = 0; i < r_config.maxDrawBuffers; i++)
00093         colorAttachments[i] = GL_COLOR_ATTACHMENT0_EXT + i;
00094 
00095     filters[0] = GL_NEAREST;
00096     filters[1] = GL_LINEAR_MIPMAP_LINEAR;
00097 
00098     /* setup main 3D render target */
00099     r_state.renderBuffer = R_CreateFramebuffer(viddef.width, viddef.height, 2, qtrue, qfalse, filters);
00100 
00101     /* setup bloom render targets */
00102     fbo_bloom0 = R_CreateFramebuffer(viddef.width, viddef.height, 1, qfalse, qfalse, filters);
00103     fbo_bloom1 = R_CreateFramebuffer(viddef.width, viddef.height, 1, qfalse, qfalse, filters);
00104 
00105     filters[0] = GL_LINEAR;
00106     /* setup extra framebuffers */
00107     for (i = 0; i < DOWNSAMPLE_PASSES; i++) {
00108         const int h = (int)((float)viddef.height / scales[i]);
00109         const int w = (int)((float)viddef.width / scales[i]);
00110         r_state.buffers0[i] = R_CreateFramebuffer(w, h, 1, qfalse, qfalse, filters);
00111         r_state.buffers1[i] = R_CreateFramebuffer(w, h, 1, qfalse, qfalse, filters);
00112         r_state.buffers2[i] = R_CreateFramebuffer(w, h, 1, qfalse, qfalse, filters);
00113 
00114         R_CheckError();
00115     }
00116 }
00117 
00118 
00122 void R_DeleteFBObject (r_framebuffer_t *buf)
00123 {
00124     if (buf->depth)
00125         qglDeleteRenderbuffersEXT(1, &buf->depth);
00126     buf->depth = 0;
00127 
00128     if (buf->textures) {
00129         int i;
00130         for (i = 0; i < buf->nTextures; i++)
00131             R_FreeFBOTexture(buf->textures[i]);
00132         Mem_Free(buf->textures);
00133     }
00134     buf->textures = 0;
00135 
00136     if (buf->fbo)
00137         qglDeleteFramebuffersEXT(1, &buf->fbo);
00138     buf->fbo = 0;
00139 }
00140 
00141 
00145 void R_ShutdownFBObjects (void)
00146 {
00147     int i;
00148 
00149     if (!r_state.frameBufferObjectsInitialized)
00150         return;
00151 
00152     for (i = 0; i < frameBufferObjectCount; i++)
00153         R_DeleteFBObject(&frameBufferObjects[i]);
00154 
00155     R_UseFramebuffer(&screenBuffer);
00156 
00157     frameBufferObjectCount = 0;
00158     memset(frameBufferObjects, 0, sizeof(frameBufferObjects));
00159     r_state.frameBufferObjectsInitialized = qfalse;
00160 
00161     Mem_Free(colorAttachments);
00162 }
00163 
00164 
00174 r_framebuffer_t * R_CreateFramebuffer (int width, int height, int ntextures, qboolean depth, qboolean halfFloat, unsigned int *filters)
00175 {
00176     r_framebuffer_t *buf;
00177     int i;
00178 
00179     if (!r_state.frameBufferObjectsInitialized) {
00180         Com_Printf("Warning: framebuffer creation failed; framebuffers not initialized!\n");
00181         return NULL;
00182     }
00183 
00184     if (frameBufferObjectCount >= lengthof(frameBufferObjects)) {
00185         Com_Printf("Warning: framebuffer creation failed; already created too many framebuffers!\n");
00186         return NULL;
00187     }
00188 
00189     buf = &frameBufferObjects[frameBufferObjectCount++];
00190 
00191     if (ntextures > r_config.maxDrawBuffers) {
00192         Com_Printf("Couldn't allocate requested number of drawBuffers in R_SetupFramebuffer!\n");
00193         ntextures = r_config.maxDrawBuffers;
00194     }
00195 
00196     Vector4Clear(buf->clearColor);
00197 
00198     buf->width = width;
00199     buf->height = height;
00200     R_SetupViewport(buf, 0, 0, width, height);
00201 
00202     buf->nTextures = ntextures;
00203     buf->textures = Mem_Alloc(sizeof(GLuint) * ntextures);
00204 
00205     buf->pixelFormat = (halfFloat == qtrue) ? GL_RGBA16F_ARB : GL_RGBA8;
00206     buf->byteFormat = (halfFloat == qtrue) ? GL_HALF_FLOAT_ARB : GL_UNSIGNED_BYTE;
00207 
00208     for (i = 0 ; i < buf->nTextures; i++) {
00209         buf->textures[i] = R_GetFreeFBOTexture();
00210         glBindTexture(GL_TEXTURE_2D, buf->textures[i]);
00211         glTexImage2D(GL_TEXTURE_2D, 0, buf->pixelFormat, buf->width, buf->height, 0, GL_RGBA, buf->byteFormat, 0);
00212 
00213         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filters[i]);
00214         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00215         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00216         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00217         glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
00218         qglGenerateMipmapEXT(GL_TEXTURE_2D);
00219         if (r_config.anisotropic)
00220             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, r_config.maxAnisotropic);
00221 
00222         R_CheckError();
00223     }
00224 
00225     /* create depth renderbuffer */
00226     if (depth == qtrue) {
00227         qglGenRenderbuffersEXT(1, &buf->depth);
00228         qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, buf->depth);
00229         qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, buf->width, buf->height);
00230         R_CheckError();
00231     } else {
00232         buf->depth = 0;
00233     }
00234 
00235     R_CheckError();
00236 
00237     /* create FBO itself */
00238     qglGenFramebuffersEXT(1, &buf->fbo);
00239     R_CheckError();
00240     qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buf->fbo);
00241 
00242     for (i = 0; i < buf->nTextures; i++) {
00243         glBindTexture(GL_TEXTURE_2D, buf->textures[i]);
00244         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, colorAttachments[i], GL_TEXTURE_2D, buf->textures[i], 0);
00245         R_CheckError();
00246     }
00247 
00248     glBindTexture(GL_TEXTURE_2D, 0);
00249     if (depth)
00250         qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, buf->depth);
00251 
00252     R_CheckError();
00253 
00254     qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
00255 
00256     return buf;
00257 }
00258 
00263 void R_UseFramebuffer (const r_framebuffer_t *buf)
00264 {
00265     if (!r_config.frameBufferObject || !r_programs->integer || !r_postprocess->integer)
00266         return;
00267 
00268     if (!r_state.frameBufferObjectsInitialized) {
00269         Com_Printf("Can't bind framebuffer: framebuffers not initialized\n");
00270         return;
00271     }
00272 
00273     if (!buf)
00274         buf = &screenBuffer;
00275 
00276     /* don't re-bind if we're already using the requested buffer */
00277     if (buf == r_state.activeFramebuffer)
00278         return;
00279 
00280     qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buf->fbo);
00281 
00282     /* don't call glDrawBuffers for main screenbuffer */
00284     if (buf->nTextures > 0)
00285         qglDrawBuffers(buf->nTextures, colorAttachments);
00286 
00287     glClearColor(r_state.activeFramebuffer->clearColor[0], r_state.activeFramebuffer->clearColor[1], r_state.activeFramebuffer->clearColor[2], r_state.activeFramebuffer->clearColor[3]);
00288     glClear(GL_COLOR_BUFFER_BIT | (buf->depth ? GL_DEPTH_BUFFER_BIT : 0));
00289 
00290     r_state.activeFramebuffer = buf;
00291 
00292     R_CheckError();
00293 }
00294 
00300 void R_SetupViewport (r_framebuffer_t *buf, int x, int y, int width, int height)
00301 {
00302     if (!buf)
00303         buf = &screenBuffer;
00304 
00305     buf->viewport.x = x;
00306     buf->viewport.y = y;
00307     buf->viewport.width = width;
00308     buf->viewport.height = height;
00309 }
00310 
00316 void R_UseViewport (const r_framebuffer_t *buf)
00317 {
00318     if (!r_state.frameBufferObjectsInitialized || !r_config.frameBufferObject || !r_postprocess->integer || !r_programs->integer)
00319         return;
00320 
00321     if (!buf)
00322         buf = &screenBuffer;
00323     glViewport(buf->viewport.x, buf->viewport.y, buf->viewport.width, buf->viewport.height);
00324 }
00325 
00327 void R_DrawBuffers (int n)
00328 {
00329     R_BindColorAttachments(n, colorAttachments);
00330 }
00331 
00332 void R_BindColorAttachments (int n, unsigned int *attachments)
00333 {
00334     if (!r_state.frameBufferObjectsInitialized || !r_config.frameBufferObject || !r_postprocess->integer || !r_programs->integer)
00335         return;
00336 
00337     if (n >= r_config.maxDrawBuffers) {
00338         Com_DPrintf(DEBUG_RENDERER, "Max drawbuffers hit\n");
00339         n = r_config.maxDrawBuffers;
00340     }
00341 
00342     if (r_state.activeFramebuffer && r_state.activeFramebuffer->nTextures > 0)
00343         qglDrawBuffers(n, attachments);
00344 }
00345 
00346 qboolean R_EnableRenderbuffer (qboolean enable)
00347 {
00348     if (!r_state.frameBufferObjectsInitialized || !r_config.frameBufferObject || !r_postprocess->integer || !r_programs->integer)
00349         return qfalse;
00350 
00351     if (enable != r_state.renderbuffer_enabled) {
00352         r_state.renderbuffer_enabled = enable;
00353         if (enable)
00354             R_UseFramebuffer(fbo_render);
00355         else
00356             R_UseFramebuffer(fbo_screen);
00357     }
00358 
00359     R_DrawBuffers(1);
00360 
00361     return qtrue;
00362 }
00363 
00364 qboolean R_RenderbufferEnabled (void)
00365 {
00366     return r_state.renderbuffer_enabled;
00367 }
00368 

Generated by  doxygen 1.6.2