4
* An object oriented GL/GLES Abstraction/Utility Layer
6
* Copyright (C) 2007,2008,2009 Intel Corporation.
8
* This library is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Lesser General Public
10
* License as published by the Free Software Foundation; either
11
* version 2 of the License, or (at your option) any later version.
13
* This library is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Lesser General Public License for more details.
18
* You should have received a copy of the GNU Lesser General Public
19
* License along with this library; if not, write to the
20
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21
* Boston, MA 02111-1307, USA.
29
#include "cogl-internal.h"
30
#include "cogl-util.h"
31
#include "cogl-texture-private.h"
33
#include "cogl-context.h"
34
#include "cogl-handle.h"
36
/* Expecting EXT functions not to be defined - redirect to pointers in context */
37
#define glGenRenderbuffersEXT ctx->pf_glGenRenderbuffersEXT
38
#define glDeleteRenderbuffersEXT ctx->pf_glDeleteRenderbuffersEXT
39
#define glBindRenderbufferEXT ctx->pf_glBindRenderbufferEXT
40
#define glRenderbufferStorageEXT ctx->pf_glRenderbufferStorageEXT
41
#define glGenFramebuffersEXT ctx->pf_glGenFramebuffersEXT
42
#define glBindFramebufferEXT ctx->pf_glBindFramebufferEXT
43
#define glFramebufferTexture2DEXT ctx->pf_glFramebufferTexture2DEXT
44
#define glFramebufferRenderbufferEXT ctx->pf_glFramebufferRenderbufferEXT
45
#define glCheckFramebufferStatusEXT ctx->pf_glCheckFramebufferStatusEXT
46
#define glDeleteFramebuffersEXT ctx->pf_glDeleteFramebuffersEXT
47
#define glBlitFramebufferEXT ctx->pf_glBlitFramebufferEXT
48
#define glRenderbufferStorageMultisampleEXT ctx->pf_glRenderbufferStorageMultisampleEXT
50
#ifndef GL_READ_FRAMEBUFFER_EXT
51
#define GL_READ_FRAMEBUFFER_EXT 0x8CA8
53
#ifndef GL_DRAW_FRAMEBUFFER_EXT
54
#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9
57
static void _cogl_offscreen_free (CoglFbo *fbo);
59
COGL_HANDLE_DEFINE (Fbo, offscreen);
62
cogl_offscreen_new_to_texture (CoglHandle texhandle)
66
CoglTexSliceSpan *x_span;
67
CoglTexSliceSpan *y_span;
70
GLuint gl_stencil_handle;
73
_COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
75
if (!cogl_features_available (COGL_FEATURE_OFFSCREEN))
76
return COGL_INVALID_HANDLE;
78
/* Make texhandle is a valid texture object */
79
if (!cogl_is_texture (texhandle))
80
return COGL_INVALID_HANDLE;
82
tex = _cogl_texture_pointer_from_handle (texhandle);
84
/* The texture must not be sliced */
85
if (tex->slice_gl_handles == NULL)
86
return COGL_INVALID_HANDLE;
88
if (tex->slice_gl_handles->len != 1)
89
return COGL_INVALID_HANDLE;
91
/* Pick the single texture slice width, height and GL id */
92
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0);
93
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0);
94
tex_gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0);
96
/* Create a renderbuffer for stenciling */
97
GE( glGenRenderbuffersEXT (1, &gl_stencil_handle) );
98
GE( glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, gl_stencil_handle) );
99
GE( glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX8_EXT,
100
cogl_texture_get_width (texhandle),
101
cogl_texture_get_height (texhandle)) );
102
GE( glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, 0) );
104
/* Generate framebuffer */
105
glGenFramebuffersEXT (1, &fbo_gl_handle);
106
GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo_gl_handle) );
107
GE( glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
108
tex->gl_target, tex_gl_handle, 0) );
109
GE( glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT,
110
GL_STENCIL_ATTACHMENT_EXT,
111
GL_RENDERBUFFER_EXT, gl_stencil_handle) );
113
/* XXX: The framebuffer_object spec isn't clear in defining whether attaching
114
* a texture as a renderbuffer with mipmap filtering enabled while the
115
* mipmaps have not been uploaded should result in an incomplete framebuffer
116
* object. (different drivers make different decisions)
118
* To avoid an error with drivers that do consider this a problem we
119
* explicitly set non mipmapped filters here. These will later be reset when
120
* the texture is actually used for rendering according to the filters set on
121
* the corresponding CoglMaterial.
123
_cogl_texture_set_filters (texhandle, GL_NEAREST, GL_NEAREST);
125
/* Make sure it's complete */
126
status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
128
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
130
/* Stencil renderbuffers aren't always supported. Try again
131
without the stencil buffer */
132
GE( glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT,
133
GL_STENCIL_ATTACHMENT_EXT,
136
GE( glDeleteRenderbuffersEXT (1, &gl_stencil_handle) );
137
gl_stencil_handle = 0;
139
status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
141
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
143
/* Still failing, so give up */
144
GE( glDeleteFramebuffersEXT (1, &fbo_gl_handle) );
145
GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0) );
146
return COGL_INVALID_HANDLE;
150
GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0) );
152
/* Allocate and init a CoglFbo object (store non-wasted size
153
for subsequent blits and viewport setup) */
154
fbo = (CoglFbo*) g_malloc (sizeof (CoglFbo));
155
fbo->width = x_span->size - x_span->waste;
156
fbo->height = y_span->size - y_span->waste;
157
fbo->gl_handle = fbo_gl_handle;
158
fbo->gl_stencil_handle = gl_stencil_handle;
160
return _cogl_offscreen_handle_new (fbo);
164
_cogl_offscreen_free (CoglFbo *fbo)
166
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
168
/* Frees FBO resources but its handle is not
169
released! Do that separately before this! */
170
if (fbo->gl_stencil_handle)
171
GE( glDeleteRenderbuffersEXT (1, &fbo->gl_stencil_handle) );
172
GE( glDeleteFramebuffersEXT (1, &fbo->gl_handle) );
177
cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
180
CoglDrawBufferState *draw_buffer;
182
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
184
_cogl_journal_flush ();
186
g_assert (ctx->draw_buffer_stack != NULL);
187
draw_buffer = ctx->draw_buffer_stack->data;
189
if (target == COGL_OFFSCREEN_BUFFER)
191
/* Make sure it is a valid fbo handle */
192
if (!cogl_is_offscreen (offscreen))
195
fbo = _cogl_offscreen_pointer_from_handle (offscreen);
197
/* Check current draw buffer target */
198
if (draw_buffer->target != COGL_OFFSCREEN_BUFFER)
200
/* Push the viewport and matrix setup if redirecting
201
from a non-screen buffer */
202
GE( glPushAttrib (GL_VIEWPORT_BIT) );
204
_cogl_set_current_matrix (COGL_MATRIX_PROJECTION);
205
_cogl_current_matrix_push ();
206
_cogl_current_matrix_identity ();
208
_cogl_set_current_matrix (COGL_MATRIX_MODELVIEW);
209
_cogl_current_matrix_push ();
210
_cogl_current_matrix_identity ();
214
/* Override viewport and matrix setup if redirecting
215
from another offscreen buffer */
216
_cogl_set_current_matrix (COGL_MATRIX_PROJECTION);
217
_cogl_current_matrix_identity ();
219
_cogl_set_current_matrix (COGL_MATRIX_MODELVIEW);
220
_cogl_current_matrix_identity ();
223
/* Setup new viewport and matrices */
224
cogl_viewport (fbo->width, fbo->height);
225
_cogl_current_matrix_translate (-1.0f, -1.0f, 0.0f);
226
_cogl_current_matrix_scale (2.0f / fbo->width, 2.0f / fbo->height, 1.0f);
228
/* Bind offscreen framebuffer object */
229
GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo->gl_handle) );
230
GE( glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) );
232
/* Some implementation require a clear before drawing
233
to an fbo. Luckily it is affected by scissor test. */
234
/* FIXME: test where exactly this is needed end whether
235
a glClear with 0 argument is enough */
236
GE( glPushAttrib (GL_SCISSOR_BIT) );
237
GE( glScissor (0,0,0,0) );
238
GE( glEnable (GL_SCISSOR_TEST) );
239
GE( glClear (GL_COLOR_BUFFER_BIT) );
240
GE( glPopAttrib () );
242
else if (target & COGL_WINDOW_BUFFER)
244
/* Check current draw buffer target */
245
if (draw_buffer->target == COGL_OFFSCREEN_BUFFER)
247
/* Pop viewport and matrices if redirecting back
248
from an offscreen buffer */
249
GE( glPopAttrib () );
251
_cogl_set_current_matrix (COGL_MATRIX_PROJECTION);
252
_cogl_current_matrix_pop ();
254
_cogl_set_current_matrix (COGL_MATRIX_MODELVIEW);
255
_cogl_current_matrix_pop ();
258
/* Bind window framebuffer object */
259
GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0) );
262
/* Store new target */
263
draw_buffer->target = target;
264
if (draw_buffer->offscreen != offscreen)
266
if (draw_buffer->offscreen != COGL_INVALID_HANDLE)
267
cogl_handle_unref (draw_buffer->offscreen);
268
if (offscreen != COGL_INVALID_HANDLE)
269
cogl_handle_ref (offscreen);
270
draw_buffer->offscreen = offscreen;
275
cogl_push_draw_buffer(void)
277
CoglDrawBufferState *old;
278
CoglDrawBufferState *draw_buffer;
280
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
282
g_assert (ctx->draw_buffer_stack != NULL);
283
old = ctx->draw_buffer_stack->data;
285
draw_buffer = g_slice_new0 (CoglDrawBufferState);
288
ctx->draw_buffer_stack =
289
g_slist_prepend (ctx->draw_buffer_stack, draw_buffer);
293
cogl_pop_draw_buffer(void)
295
CoglDrawBufferState *to_pop;
296
CoglDrawBufferState *to_restore;
298
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
300
g_assert (ctx->draw_buffer_stack != NULL);
301
if (ctx->draw_buffer_stack->next == NULL)
303
g_warning ("1 more cogl_pop_draw_buffer() than cogl_push_draw_buffer()");
307
to_pop = ctx->draw_buffer_stack->data;
308
to_restore = ctx->draw_buffer_stack->next->data;
310
/* the logic in cogl_set_draw_buffer() only works if
311
* to_pop is still on top of the stack, because
312
* cogl_set_draw_buffer() needs to know the previous
315
cogl_set_draw_buffer (to_restore->target, to_restore->offscreen);
317
/* cogl_set_draw_buffer() should have set top of stack
320
g_assert (to_restore->target == to_pop->target);
321
g_assert (to_restore->offscreen == to_pop->offscreen);
323
g_assert (ctx->draw_buffer_stack->data == to_pop);
324
ctx->draw_buffer_stack =
325
g_slist_remove_link (ctx->draw_buffer_stack,
326
ctx->draw_buffer_stack);
328
g_slice_free (CoglDrawBufferState, to_pop);