~ubuntu-branches/ubuntu/precise/clutter-1.0/precise

« back to all changes in this revision

Viewing changes to clutter/cogl/gl/cogl-fbo.c

  • Committer: Bazaar Package Importer
  • Author(s): Emilio Pozuelo Monfort
  • Date: 2010-03-21 13:27:56 UTC
  • mto: (2.1.3 experimental) (1.3.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: james.westby@ubuntu.com-20100321132756-nf8yd30yxo3zzwcm
Tags: upstream-1.2.2
ImportĀ upstreamĀ versionĀ 1.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Cogl
3
 
 *
4
 
 * An object oriented GL/GLES Abstraction/Utility Layer
5
 
 *
6
 
 * Copyright (C) 2007,2008,2009 Intel Corporation.
7
 
 *
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.
12
 
 *
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.
17
 
 *
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.
22
 
 */
23
 
 
24
 
#ifdef HAVE_CONFIG_H
25
 
#include "config.h"
26
 
#endif
27
 
 
28
 
#include "cogl.h"
29
 
#include "cogl-internal.h"
30
 
#include "cogl-util.h"
31
 
#include "cogl-texture-private.h"
32
 
#include "cogl-fbo.h"
33
 
#include "cogl-context.h"
34
 
#include "cogl-handle.h"
35
 
 
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
49
 
 
50
 
#ifndef GL_READ_FRAMEBUFFER_EXT
51
 
#define GL_READ_FRAMEBUFFER_EXT 0x8CA8
52
 
#endif
53
 
#ifndef GL_DRAW_FRAMEBUFFER_EXT
54
 
#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9
55
 
#endif
56
 
 
57
 
static void _cogl_offscreen_free (CoglFbo *fbo);
58
 
 
59
 
COGL_HANDLE_DEFINE (Fbo, offscreen);
60
 
 
61
 
CoglHandle
62
 
cogl_offscreen_new_to_texture (CoglHandle texhandle)
63
 
{
64
 
  CoglTexture      *tex;
65
 
  CoglFbo          *fbo;
66
 
  CoglTexSliceSpan *x_span;
67
 
  CoglTexSliceSpan *y_span;
68
 
  GLuint            tex_gl_handle;
69
 
  GLuint            fbo_gl_handle;
70
 
  GLuint            gl_stencil_handle;
71
 
  GLenum            status;
72
 
 
73
 
  _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
74
 
 
75
 
  if (!cogl_features_available (COGL_FEATURE_OFFSCREEN))
76
 
    return COGL_INVALID_HANDLE;
77
 
 
78
 
  /* Make texhandle is a valid texture object */
79
 
  if (!cogl_is_texture (texhandle))
80
 
    return COGL_INVALID_HANDLE;
81
 
 
82
 
  tex = _cogl_texture_pointer_from_handle (texhandle);
83
 
 
84
 
  /* The texture must not be sliced */
85
 
  if (tex->slice_gl_handles == NULL)
86
 
    return COGL_INVALID_HANDLE;
87
 
 
88
 
  if (tex->slice_gl_handles->len != 1)
89
 
    return COGL_INVALID_HANDLE;
90
 
 
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);
95
 
 
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) );
103
 
 
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) );
112
 
 
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)
117
 
   *
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.
122
 
   */
123
 
  _cogl_texture_set_filters (texhandle, GL_NEAREST, GL_NEAREST);
124
 
 
125
 
  /* Make sure it's complete */
126
 
  status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
127
 
 
128
 
  if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
129
 
    {
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,
134
 
                                        GL_RENDERBUFFER_EXT,
135
 
                                        0) );
136
 
      GE( glDeleteRenderbuffersEXT (1, &gl_stencil_handle) );
137
 
      gl_stencil_handle = 0;
138
 
 
139
 
      status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
140
 
 
141
 
      if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
142
 
        {
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;
147
 
        }
148
 
    }
149
 
 
150
 
  GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0) );
151
 
 
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;
159
 
 
160
 
  return _cogl_offscreen_handle_new (fbo);
161
 
}
162
 
 
163
 
static void
164
 
_cogl_offscreen_free (CoglFbo *fbo)
165
 
{
166
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
167
 
 
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) );
173
 
  g_free (fbo);
174
 
}
175
 
 
176
 
void
177
 
cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
178
 
{
179
 
  CoglFbo *fbo = NULL;
180
 
  CoglDrawBufferState *draw_buffer;
181
 
 
182
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
183
 
 
184
 
  _cogl_journal_flush ();
185
 
 
186
 
  g_assert (ctx->draw_buffer_stack != NULL);
187
 
  draw_buffer = ctx->draw_buffer_stack->data;
188
 
 
189
 
  if (target == COGL_OFFSCREEN_BUFFER)
190
 
    {
191
 
      /* Make sure it is a valid fbo handle */
192
 
      if (!cogl_is_offscreen (offscreen))
193
 
        return;
194
 
 
195
 
      fbo = _cogl_offscreen_pointer_from_handle (offscreen);
196
 
 
197
 
      /* Check current draw buffer target */
198
 
      if (draw_buffer->target != COGL_OFFSCREEN_BUFFER)
199
 
        {
200
 
          /* Push the viewport and matrix setup if redirecting
201
 
             from a non-screen buffer */
202
 
          GE( glPushAttrib (GL_VIEWPORT_BIT) );
203
 
 
204
 
          _cogl_set_current_matrix (COGL_MATRIX_PROJECTION);
205
 
          _cogl_current_matrix_push ();
206
 
          _cogl_current_matrix_identity ();
207
 
 
208
 
          _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW);
209
 
          _cogl_current_matrix_push ();
210
 
          _cogl_current_matrix_identity ();
211
 
        }
212
 
      else
213
 
        {
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 ();
218
 
 
219
 
          _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW);
220
 
          _cogl_current_matrix_identity ();
221
 
        }
222
 
 
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);
227
 
 
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) );
231
 
 
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 () );
241
 
    }
242
 
  else if (target & COGL_WINDOW_BUFFER)
243
 
    {
244
 
      /* Check current draw buffer target */
245
 
      if (draw_buffer->target == COGL_OFFSCREEN_BUFFER)
246
 
        {
247
 
          /* Pop viewport and matrices if redirecting back
248
 
             from an offscreen buffer */
249
 
          GE( glPopAttrib () );
250
 
 
251
 
          _cogl_set_current_matrix (COGL_MATRIX_PROJECTION);
252
 
          _cogl_current_matrix_pop ();
253
 
 
254
 
          _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW);
255
 
          _cogl_current_matrix_pop ();
256
 
        }
257
 
 
258
 
      /* Bind window framebuffer object */
259
 
      GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0) );
260
 
    }
261
 
 
262
 
  /* Store new target */
263
 
  draw_buffer->target = target;
264
 
  if (draw_buffer->offscreen != offscreen)
265
 
    {
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;
271
 
    }
272
 
}
273
 
 
274
 
void
275
 
cogl_push_draw_buffer(void)
276
 
{
277
 
  CoglDrawBufferState *old;
278
 
  CoglDrawBufferState *draw_buffer;
279
 
 
280
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
281
 
 
282
 
  g_assert (ctx->draw_buffer_stack != NULL);
283
 
  old = ctx->draw_buffer_stack->data;
284
 
 
285
 
  draw_buffer = g_slice_new0 (CoglDrawBufferState);
286
 
  *draw_buffer = *old;
287
 
 
288
 
  ctx->draw_buffer_stack =
289
 
    g_slist_prepend (ctx->draw_buffer_stack, draw_buffer);
290
 
}
291
 
 
292
 
void
293
 
cogl_pop_draw_buffer(void)
294
 
{
295
 
  CoglDrawBufferState *to_pop;
296
 
  CoglDrawBufferState *to_restore;
297
 
 
298
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
299
 
 
300
 
  g_assert (ctx->draw_buffer_stack != NULL);
301
 
  if (ctx->draw_buffer_stack->next == NULL)
302
 
    {
303
 
      g_warning ("1 more cogl_pop_draw_buffer() than cogl_push_draw_buffer()");
304
 
      return;
305
 
    }
306
 
 
307
 
  to_pop = ctx->draw_buffer_stack->data;
308
 
  to_restore = ctx->draw_buffer_stack->next->data;
309
 
 
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
313
 
   * state.
314
 
   */
315
 
  cogl_set_draw_buffer (to_restore->target, to_restore->offscreen);
316
 
 
317
 
  /* cogl_set_draw_buffer() should have set top of stack
318
 
   * to to_restore
319
 
   */
320
 
  g_assert (to_restore->target == to_pop->target);
321
 
  g_assert (to_restore->offscreen == to_pop->offscreen);
322
 
 
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);
327
 
 
328
 
  g_slice_free (CoglDrawBufferState, to_pop);
329
 
}
330