UFO: Alien Invasion
Loading...
Searching...
No Matches
r_framebuffer.cpp
Go to the documentation of this file.
1
5
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
50static 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
65void R_InitFBObjects (void)
66{
67 if (!r_config.frameBufferObject || !r_programs->integer)
68 return;
69
73
74 r_state.frameBufferObjectsInitialized = true;
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);
92 r_state.activeFramebuffer = &screenBuffer;
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 */
103 r_state.renderBuffer = R_CreateFramebuffer(viddef.context.width, viddef.context.height, 2, true, false, filters);
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{
150 if (!r_state.frameBufferObjectsInitialized)
151 return;
152
153 for (int i = 0; i < frameBufferObjectCount; i++)
155
157
160 r_state.frameBufferObjectsInitialized = false;
161
163}
164
165
175r_framebuffer_t* R_CreateFramebuffer (int width, int height, int ntextures, bool depth, bool halfFloat, unsigned int* filters)
176{
178 int i;
179
180 if (!r_state.frameBufferObjectsInitialized) {
181 Com_Printf("Warning: framebuffer creation failed; framebuffers not initialized!\n");
182 return nullptr;
183 }
184
186 Com_Printf("Warning: framebuffer creation failed; already created too many framebuffers!\n");
187 return nullptr;
188 }
189
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{
325 if (!r_config.frameBufferObject || !r_programs->integer || !r_postprocess->integer)
326 return;
327
328 if (!r_state.frameBufferObjectsInitialized) {
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
347 glClearColor(r_state.activeFramebuffer->clearColor[0], r_state.activeFramebuffer->clearColor[1], r_state.activeFramebuffer->clearColor[2], r_state.activeFramebuffer->clearColor[3]);
348 glClear(GL_COLOR_BUFFER_BIT | (buf->depth ? GL_DEPTH_BUFFER_BIT : 0));
349
350 r_state.activeFramebuffer = buf;
351
352 R_CheckError();
353}
354
362void 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{
380 if (!r_state.frameBufferObjectsInitialized || !r_config.frameBufferObject || !r_postprocess->integer || !r_programs->integer)
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
393void R_DrawBuffers (unsigned int drawBufferNum)
394{
396}
397
404void R_BindColorAttachments (unsigned int n, unsigned int* attachments)
405{
406 if (!r_state.frameBufferObjectsInitialized || !r_config.frameBufferObject || !r_postprocess->integer || !r_programs->integer)
407 return;
408
409 if (n >= r_config.maxDrawBuffers) {
410 Com_DPrintf(DEBUG_RENDERER, "Max drawbuffers hit\n");
411 n = r_config.maxDrawBuffers;
412 }
413
414 if (r_state.activeFramebuffer && r_state.activeFramebuffer->nTextures > 0)
415 qglDrawBuffers(n, attachments);
416}
417
425bool R_EnableRenderbuffer (bool enable)
426{
427 if (!r_state.frameBufferObjectsInitialized || !r_config.frameBufferObject || !r_postprocess->integer || !r_programs->integer)
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{
445 return r_state.renderbuffer_enabled;
446}
viddef_t viddef
Definition cl_video.cpp:34
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition common.cpp:440
void Com_Error(int code, const char *fmt,...)
Definition common.cpp:459
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
#define ERR_FATAL
Definition common.h:210
#define DEBUG_RENDERER
Definition defines.h:62
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 glGenTextures(GLsizei n, GLuint *textures)
Definition gldummy.cpp:22
void glBindTexture(GLenum target, GLuint id)
Definition gldummy.cpp:4
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
voidpf void * buf
Definition ioapi.h:42
#define Mem_Free(ptr)
Definition mem.h:35
#define Mem_AllocTypeN(type, n)
Definition mem.h:38
Error checking function.
#define R_CheckError()
Definition r_error.h:30
void R_BindColorAttachments(unsigned int n, unsigned int *attachments)
Activate draw buffer(s).
static GLuint frameBufferTextures[MAX_GL_FRAMEBUFFERS]
void R_InitFBObjects(void)
void R_UseFramebuffer(const r_framebuffer_t *buf)
bind specified framebuffer object so we render to it
bool R_EnableRenderbuffer(bool enable)
Enable the render to the framebuffer.
void R_UseViewport(const r_framebuffer_t *buf)
Set the viewport to the dimensions of the given framebuffer.
static void R_FreeFBOTexture(int texnum)
void R_DrawBuffers(unsigned int drawBufferNum)
Activate draw buffer(s).
static int frameBufferObjectCount
void R_ResolveMSAA(const r_framebuffer_t *buf)
Forces multisample antialiasing resolve on given framebuffer, if needed.
static GLuint R_GetFreeFBOTexture(void)
void R_SetupViewport(r_framebuffer_t *buf, int x, int y, int width, int height)
Sets the framebuffer dimensions of the viewport.
void R_ShutdownFBObjects(void)
Delete all registered framebuffer and render buffer objects, clear memory.
void R_DeleteFBObject(r_framebuffer_t *buf)
Delete framebuffer object along with attached render buffer.
static r_framebuffer_t screenBuffer
r_framebuffer_t * R_CreateFramebuffer(int width, int height, int ntextures, bool depth, bool halfFloat, unsigned int *filters)
create a new framebuffer object
static r_framebuffer_t frameBufferObjects[MAX_GL_FRAMEBUFFERS]
static GLenum * colorAttachments
bool R_RenderbufferEnabled(void)
#define GL_READ_FRAMEBUFFER_EXT
Definition r_gl.h:63
QGL_EXTERN GLint i
Definition r_gl.h:113
#define GL_DRAW_FRAMEBUFFER_EXT
Definition r_gl.h:67
QGL_EXTERN GLuint
Definition r_gl.h:124
QGL_EXTERN const GLuint *QGL_EXTERN GLuint *QGL_EXTERN GLenum
Definition r_gl.h:127
#define GL_DEPTH_ATTACHMENT_EXT
#define GL_CLAMP
#define GL_COLOR_ATTACHMENT0_EXT
#define GL_DEPTH_COMPONENT
#define GL_RENDERBUFFER_EXT
#define GL_FRAMEBUFFER_EXT
#define MAX_GL_FRAMEBUFFERS
Definition r_image.h:79
local graphics definitions
cvar_t * r_postprocess
Definition r_main.cpp:100
cvar_t * r_multisample
Definition r_main.cpp:90
cvar_t * r_programs
Definition r_main.cpp:97
rconfig_t r_config
Definition r_main.cpp:47
rstate_t r_state
Definition r_main.cpp:48
#define DOWNSAMPLE_PASSES
Definition r_state.h:84
#define fbo_render
Definition r_state.h:88
#define fbo_bloom0
Definition r_state.h:89
#define fbo_bloom1
Definition r_state.h:90
#define DOWNSAMPLE_SCALE
Definition r_state.h:85
#define fbo_screen
Definition r_state.h:87
#define OBJZERO(obj)
Definition shared.h:178
#define lengthof(x)
Definition shared.h:105
#define Vector4Clear(a)
Definition vector.h:57