UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
r_framebuffer.cpp
Go to the documentation of this file.
1 
6 /*
7  Copyright (C) 2008 Victor Luchits
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License
11  as published by the Free Software Foundation; either version 2
12  of the License, or (at your option) any later version.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 
18  See the GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with this program; if not, write to the Free Software
22  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23  */
24 
25 #include "r_local.h"
26 #include "r_framebuffer.h"
27 #include "r_error.h"
28 
32 
35 
37 {
38  int i;
39 
40  for (i = 0; i < MAX_GL_FRAMEBUFFERS; i++) {
41  if (frameBufferTextures[i] == 0) {
43  return frameBufferTextures[i];
44  }
45  }
46 
47  Com_Error(ERR_FATAL, "Exceeded max frame buffer textures");
48 }
49 
50 static void R_FreeFBOTexture (int texnum)
51 {
52  int i;
53 
54  for (i = 0; i < MAX_GL_FRAMEBUFFERS; i++) {
55  if (frameBufferTextures[i] == texnum)
56  break;
57  }
58 
59  assert(i >= 0);
60  assert(i < MAX_GL_FRAMEBUFFERS);
61  glDeleteTextures(1, &frameBufferTextures[i]);
63 }
64 
65 void R_InitFBObjects (void)
66 {
68  return;
69 
71  OBJZERO(frameBufferObjects);
73 
75 
76  float scales[DOWNSAMPLE_PASSES];
77  int i;
78  for (i = 0; i < DOWNSAMPLE_PASSES; i++)
79  scales[i] = powf(DOWNSAMPLE_SCALE, i + 1);
80 
81  /* setup default screen framebuffer */
82  screenBuffer.fbo = 0;
83  screenBuffer.depth = 0;
84  screenBuffer.nTextures = 0;
85  screenBuffer.width = viddef.context.width;
86  screenBuffer.height = viddef.context.height;
87  R_SetupViewport(&screenBuffer, 0, 0, viddef.context.width, viddef.context.height);
88  Vector4Clear(screenBuffer.clearColor);
89 
90  /* use default framebuffer */
91  qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
93 
95  for (i = 0; i < r_config.maxDrawBuffers; i++)
97 
98  unsigned int filters[2];
99  filters[0] = GL_NEAREST;
100  filters[1] = GL_LINEAR_MIPMAP_LINEAR;
101 
102  /* setup main 3D render target */
104 
105  /* setup bloom render targets */
106  fbo_bloom0 = R_CreateFramebuffer(viddef.context.width, viddef.context.height, 1, false, false, filters);
107  fbo_bloom1 = R_CreateFramebuffer(viddef.context.width, viddef.context.height, 1, false, false, filters);
108 
109  filters[0] = GL_LINEAR;
110  /* setup extra framebuffers */
111  for (i = 0; i < DOWNSAMPLE_PASSES; i++) {
112  const int h = (int)((float)viddef.context.height / scales[i]);
113  const int w = (int)((float)viddef.context.width / scales[i]);
114  r_state.buffers0[i] = R_CreateFramebuffer(w, h, 1, false, false, filters);
115  r_state.buffers1[i] = R_CreateFramebuffer(w, h, 1, false, false, filters);
116  r_state.buffers2[i] = R_CreateFramebuffer(w, h, 1, false, false, filters);
117 
118  R_CheckError();
119  }
120 }
121 
122 
127 {
128  if (buf->depth)
129  qglDeleteRenderbuffersEXT(1, &buf->depth);
130  buf->depth = 0;
131 
132  if (buf->textures) {
133  for (int i = 0; i < buf->nTextures; i++)
134  R_FreeFBOTexture(buf->textures[i]);
135  Mem_Free(buf->textures);
136  }
137  buf->textures = 0;
138 
139  if (buf->fbo)
140  qglDeleteFramebuffersEXT(1, &buf->fbo);
141  buf->fbo = 0;
142 }
143 
144 
149 {
151  return;
152 
153  for (int i = 0; i < frameBufferObjectCount; i++)
154  R_DeleteFBObject(&frameBufferObjects[i]);
155 
156  R_UseFramebuffer(&screenBuffer);
157 
158  frameBufferObjectCount = 0;
159  OBJZERO(frameBufferObjects);
161 
163 }
164 
165 
175 r_framebuffer_t* R_CreateFramebuffer (int width, int height, int ntextures, bool depth, bool halfFloat, unsigned int* filters)
176 {
178  int i;
179 
181  Com_Printf("Warning: framebuffer creation failed; framebuffers not initialized!\n");
182  return nullptr;
183  }
184 
185  if (frameBufferObjectCount >= lengthof(frameBufferObjects)) {
186  Com_Printf("Warning: framebuffer creation failed; already created too many framebuffers!\n");
187  return nullptr;
188  }
189 
190  buf = &frameBufferObjects[frameBufferObjectCount++];
191  OBJZERO(*buf);
192 
193  if (ntextures > r_config.maxDrawBuffers) {
194  Com_Printf("Couldn't allocate requested number of drawBuffers in R_SetupFramebuffer!\n");
195  ntextures = r_config.maxDrawBuffers;
196  }
197 
198  Vector4Clear(buf->clearColor);
199 
200  buf->width = width;
201  buf->height = height;
202  R_SetupViewport(buf, 0, 0, width, height);
203 
204  buf->nTextures = ntextures;
205  buf->textures = Mem_AllocTypeN(unsigned int, ntextures);
206 
207 #ifdef GL_VERSION_ES_CM_1_0
208  buf->pixelFormat = GL_RGBA;
209  buf->byteFormat = GL_UNSIGNED_BYTE;
210 #else
211  buf->pixelFormat = halfFloat ? GL_RGBA16F_ARB : GL_RGBA8;
212  buf->byteFormat = halfFloat ? GL_HALF_FLOAT_ARB : GL_UNSIGNED_BYTE;
213 #endif
214 
215  /* Presence of depth buffer indicates render target that could use antialiasing */
216  if (depth) {
218  if (qglRenderbufferStorageMultisampleEXT && qglBlitFramebuffer) {
219  const int samples = r_multisample->integer;
220  if (samples > 1)
221  buf->samples = samples;
222  }
223  }
224 
225  for (i = 0; i < buf->nTextures; i++) {
226  buf->textures[i] = R_GetFreeFBOTexture();
227  glBindTexture(GL_TEXTURE_2D, buf->textures[i]);
228  glTexImage2D(GL_TEXTURE_2D, 0, buf->pixelFormat, buf->width, buf->height, 0, GL_RGBA, buf->byteFormat, 0);
229 
230  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filters[i]);
231  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
232  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
233  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
234  glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
235  qglGenerateMipmapEXT(GL_TEXTURE_2D);
236  if (r_config.anisotropic)
237  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, r_config.maxAnisotropic);
238 
239  R_CheckError();
240  }
241  glBindTexture(GL_TEXTURE_2D, 0);
242 
243  /* create FBO itself */
244  qglGenFramebuffersEXT(1, &buf->fbo);
245  R_CheckError();
246  qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buf->fbo);
247 
248  /* create&attach depth renderbuffer */
249  if (depth) {
250  qglGenRenderbuffersEXT(1, &buf->depth);
251  qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, buf->depth);
252  if (buf->samples)
253  qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, buf->samples, GL_DEPTH_COMPONENT, buf->width, buf->height);
254  else
255  qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, buf->width, buf->height);
256  qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, buf->depth);
257  } else {
258  buf->depth = 0;
259  }
260 
261  /* create multisample color buffers if needed */
262  if (buf->samples) {
263  /* generate color buffers */
264  for (i = 0; i < buf->nTextures; i++) {
265  unsigned colorbuffer;
266  qglGenRenderbuffersEXT(1, &colorbuffer);
267  qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, colorbuffer);
268  qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, buf->samples, buf->pixelFormat, buf->width, buf->height);
269  qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, colorAttachments[i], GL_RENDERBUFFER_EXT, colorbuffer);
270  R_CheckError();
271  }
272  /* proxy framebuffer object for resolving MSAA */
273  qglGenFramebuffersEXT(1, &buf->proxyFBO);
274  R_CheckError();
275  qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buf->proxyFBO);
276  }
277 
278  /* Whether multisampling was enabled or not, current FBO should be populated with render-to-texture bindings */
279  for (i = 0; i < buf->nTextures; i++) {
280  qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, colorAttachments[i], GL_TEXTURE_2D, buf->textures[i], 0);
281  R_CheckError();
282  }
283 
284  R_CheckError();
285 
286  /* unbind the framebuffer and return to default state */
287  qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
288 
289  return buf;
290 }
291 
297 {
298  if (!buf->samples)
299  return;
300 
301  qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, buf->fbo);
302  qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, buf->proxyFBO);
303  for (int i = 0; i < buf->nTextures; i++) {
304 #ifndef GL_VERSION_ES_CM_1_0
305  glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + i);
306  glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + i);
307 #endif
308  qglBlitFramebuffer(0, 0, buf->width, buf-> height, 0, 0, buf->width, buf->height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
309 
310  R_CheckError();
311  }
312  R_CheckError();
313 
314  qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, screenBuffer.fbo);
315  R_CheckError();
316 }
317 
318 
324 {
326  return;
327 
329  Com_Printf("Can't bind framebuffer: framebuffers not initialized\n");
330  return;
331  }
332 
333  if (!buf)
334  buf = &screenBuffer;
335 
336  /* don't re-bind if we're already using the requested buffer */
337  if (buf == r_state.activeFramebuffer)
338  return;
339 
340  qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buf->fbo);
341 
342  /* don't call glDrawBuffers for main screenbuffer */
344  if (buf->nTextures > 0)
345  qglDrawBuffers(buf->nTextures, colorAttachments);
346 
348  glClear(GL_COLOR_BUFFER_BIT | (buf->depth ? GL_DEPTH_BUFFER_BIT : 0));
349 
351 
352  R_CheckError();
353 }
354 
362 void R_SetupViewport (r_framebuffer_t* buf, int x, int y, int width, int height)
363 {
364  if (!buf)
365  buf = &screenBuffer;
366 
367  buf->viewport.x = x;
368  buf->viewport.y = y;
369  buf->viewport.width = width;
370  buf->viewport.height = height;
371 }
372 
379 {
381  return;
382 
383  if (!buf)
384  buf = &screenBuffer;
385  glViewport(buf->viewport.x, buf->viewport.y, buf->viewport.width, buf->viewport.height);
386 }
387 
393 void R_DrawBuffers (unsigned int drawBufferNum)
394 {
396 }
397 
404 void R_BindColorAttachments (unsigned int n, unsigned int* attachments)
405 {
407  return;
408 
409  if (n >= r_config.maxDrawBuffers) {
410  Com_DPrintf(DEBUG_RENDERER, "Max drawbuffers hit\n");
412  }
413 
415  qglDrawBuffers(n, attachments);
416 }
417 
425 bool R_EnableRenderbuffer (bool enable)
426 {
428  return false;
429 
430  if (enable != r_state.renderbuffer_enabled) {
431  r_state.renderbuffer_enabled = enable;
432  if (enable)
434  else
436  }
437 
438  R_DrawBuffers(1);
439 
440  return true;
441 }
442 
444 {
446 }
int maxDrawBuffers
Definition: r_local.h:173
void R_SetupViewport(r_framebuffer_t *buf, int x, int y, int width, int height)
Sets the framebuffer dimensions of the viewport.
bool R_EnableRenderbuffer(bool enable)
Enable the render to the framebuffer.
static r_framebuffer_t frameBufferObjects[MAX_GL_FRAMEBUFFERS]
#define Mem_AllocTypeN(type, n)
Definition: mem.h:38
void R_UseFramebuffer(const r_framebuffer_t *buf)
bind specified framebuffer object so we render to it
#define fbo_bloom0
Definition: r_state.h:89
#define DOWNSAMPLE_SCALE
Definition: r_state.h:85
void glBindTexture(GLenum target, GLuint id)
Definition: gldummy.cpp:4
void R_ShutdownFBObjects(void)
Delete all registered framebuffer and render buffer objects, clear memory.
r_framebuffer_t * buffers2[DOWNSAMPLE_PASSES]
Definition: r_state.h:125
static GLuint frameBufferTextures[MAX_GL_FRAMEBUFFERS]
r_framebuffer_t * renderBuffer
Definition: r_state.h:120
unsigned int * textures
Definition: r_framebuffer.h:44
#define GL_RENDERBUFFER_EXT
cvar_t * r_programs
Definition: r_main.cpp:97
viddef_t viddef
Definition: cl_video.cpp:34
local graphics definitions
unsigned width
Definition: cl_video.h:44
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
rconfig_t r_config
Definition: r_main.cpp:47
QGL_EXTERN GLuint
Definition: r_gl.h:124
cvar_t * r_postprocess
Definition: r_main.cpp:100
int integer
Definition: cvar.h:81
#define GL_DEPTH_ATTACHMENT_EXT
bool renderbuffer_enabled
Definition: r_state.h:164
const GLuint *typedef GLuint *typedef GLenum
Definition: r_gl.h:190
voidpf void * buf
Definition: ioapi.h:42
#define ERR_FATAL
Definition: common.h:210
unsigned int depth
Definition: r_framebuffer.h:41
bool frameBufferObject
Definition: r_local.h:186
void Com_Error(int code, const char *fmt,...)
Definition: common.cpp:417
static r_framebuffer_t screenBuffer
cvar_t * r_multisample
Definition: r_main.cpp:90
const r_framebuffer_t * activeFramebuffer
Definition: r_state.h:127
#define GL_DEPTH_COMPONENT
unsigned int proxyFBO
Definition: r_framebuffer.h:45
bool R_RenderbufferEnabled(void)
#define fbo_render
Definition: r_state.h:88
#define OBJZERO(obj)
Definition: shared.h:178
r_framebuffer_t * R_CreateFramebuffer(int width, int height, int ntextures, bool depth, bool halfFloat, unsigned int *filters)
create a new framebuffer object
#define DOWNSAMPLE_PASSES
Definition: r_state.h:84
void R_DeleteFBObject(r_framebuffer_t *buf)
Delete framebuffer object along with attached render buffer.
bool frameBufferObjectsInitialized
Definition: r_state.h:126
#define GL_READ_FRAMEBUFFER_EXT
Definition: r_gl.h:63
static GLuint R_GetFreeFBOTexture(void)
void R_InitFBObjects(void)
static void R_FreeFBOTexture(int texnum)
void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *texels)
Definition: gldummy.cpp:17
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition: common.cpp:398
viddefContext_t context
Definition: cl_video.h:67
static int frameBufferObjectCount
r_viewport_t viewport
Definition: r_framebuffer.h:38
#define GL_FRAMEBUFFER_EXT
void R_DrawBuffers(unsigned int drawBufferNum)
Activate draw buffer(s)
bool anisotropic
Definition: r_local.h:185
r_framebuffer_t * buffers0[DOWNSAMPLE_PASSES]
Definition: r_state.h:123
QGL_EXTERN GLint i
Definition: r_gl.h:113
static GLenum * colorAttachments
#define GL_COLOR_ATTACHMENT0_EXT
#define Mem_Free(ptr)
Definition: mem.h:35
Error checking function.
void glGenTextures(GLsizei n, GLuint *textures)
Definition: gldummy.cpp:22
void R_BindColorAttachments(unsigned int n, unsigned int *attachments)
Activate draw buffer(s)
rstate_t r_state
Definition: r_main.cpp:48
#define fbo_bloom1
Definition: r_state.h:90
int32_t maxAnisotropic
Definition: r_local.h:184
#define lengthof(x)
Definition: shared.h:105
#define R_CheckError()
Definition: r_error.h:30
#define GL_DRAW_FRAMEBUFFER_EXT
Definition: r_gl.h:67
r_framebuffer_t * buffers1[DOWNSAMPLE_PASSES]
Definition: r_state.h:124
void R_ResolveMSAA(const r_framebuffer_t *buf)
Forces multisample antialiasing resolve on given framebuffer, if needed.
unsigned height
Definition: cl_video.h:45
void R_UseViewport(const r_framebuffer_t *buf)
Set the viewport to the dimensions of the given framebuffer.
#define fbo_screen
Definition: r_state.h:87
#define GL_CLAMP
unsigned int fbo
Definition: r_framebuffer.h:42
#define DEBUG_RENDERER
Definition: defines.h:62
#define Vector4Clear(a)
Definition: vector.h:57
#define MAX_GL_FRAMEBUFFERS
Definition: r_image.h:79