~noskcaj/ubuntu/trusty/cogl/1.16.2

« back to all changes in this revision

Viewing changes to cogl/driver/gl/cogl-framebuffer-gl.c

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha, Jeremy Bicha, Rico Tzschichholz
  • Date: 2013-02-26 16:43:25 UTC
  • mfrom: (1.1.10)
  • Revision ID: package-import@ubuntu.com-20130226164325-t4z9rylpa20v0p6q
Tags: 1.13.4-0ubuntu1
[ Jeremy Bicha ]
* New upstream release
  - soname bump
* debian/control.in:
  - Bump minimum glib to 2.32
  - Drop obsolete breaks/replaces
  - Bump libclutter-1.0-dev breaks for soname transition
* debian/libcogl-dev.install:
  - Add some missing files

[ Rico Tzschichholz ]
* debian/control.in:
  - Build-depend on libxrandr-dev

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,2012 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, see
 
20
 * <http://www.gnu.org/licenses/>.
 
21
 *
 
22
 *
 
23
 */
 
24
 
 
25
#ifdef HAVE_CONFIG_H
 
26
#include "config.h"
 
27
#endif
 
28
 
 
29
#include "cogl-context-private.h"
 
30
#include "cogl-util-gl-private.h"
 
31
#include "cogl-framebuffer-private.h"
 
32
#include "cogl-framebuffer-gl-private.h"
 
33
#include "cogl-buffer-gl-private.h"
 
34
#include "cogl-error-private.h"
 
35
#include "cogl-texture-gl-private.h"
 
36
#include "cogl-texture-private.h"
 
37
 
 
38
#include <glib.h>
 
39
#include <string.h>
 
40
 
 
41
#ifndef GL_FRAMEBUFFER
 
42
#define GL_FRAMEBUFFER          0x8D40
 
43
#endif
 
44
#ifndef GL_RENDERBUFFER
 
45
#define GL_RENDERBUFFER         0x8D41
 
46
#endif
 
47
#ifndef GL_STENCIL_ATTACHMENT
 
48
#define GL_STENCIL_ATTACHMENT   0x8D00
 
49
#endif
 
50
#ifndef GL_COLOR_ATTACHMENT0
 
51
#define GL_COLOR_ATTACHMENT0    0x8CE0
 
52
#endif
 
53
#ifndef GL_FRAMEBUFFER_COMPLETE
 
54
#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
 
55
#endif
 
56
#ifndef GL_STENCIL_INDEX8
 
57
#define GL_STENCIL_INDEX8       0x8D48
 
58
#endif
 
59
#ifndef GL_DEPTH_STENCIL
 
60
#define GL_DEPTH_STENCIL        0x84F9
 
61
#endif
 
62
#ifndef GL_DEPTH24_STENCIL8
 
63
#define GL_DEPTH24_STENCIL8     0x88F0
 
64
#endif
 
65
#ifndef GL_DEPTH_ATTACHMENT
 
66
#define GL_DEPTH_ATTACHMENT     0x8D00
 
67
#endif
 
68
#ifndef GL_DEPTH_COMPONENT16
 
69
#define GL_DEPTH_COMPONENT16    0x81A5
 
70
#endif
 
71
#ifndef GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE
 
72
#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE      0x8212
 
73
#endif
 
74
#ifndef GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE
 
75
#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE    0x8213
 
76
#endif
 
77
#ifndef GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE
 
78
#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE     0x8214
 
79
#endif
 
80
#ifndef GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE
 
81
#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE    0x8215
 
82
#endif
 
83
#ifndef GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE
 
84
#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE    0x8216
 
85
#endif
 
86
#ifndef GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE
 
87
#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE  0x8217
 
88
#endif
 
89
#ifndef GL_READ_FRAMEBUFFER
 
90
#define GL_READ_FRAMEBUFFER               0x8CA8
 
91
#endif
 
92
#ifndef GL_DRAW_FRAMEBUFFER
 
93
#define GL_DRAW_FRAMEBUFFER               0x8CA9
 
94
#endif
 
95
#ifndef GL_TEXTURE_SAMPLES_IMG
 
96
#define GL_TEXTURE_SAMPLES_IMG            0x9136
 
97
#endif
 
98
#ifndef GL_PACK_INVERT_MESA
 
99
#define GL_PACK_INVERT_MESA 0x8758
 
100
#endif
 
101
 
 
102
#ifndef GL_COLOR
 
103
#define GL_COLOR 0x1800
 
104
#endif
 
105
#ifndef GL_DEPTH
 
106
#define GL_DEPTH 0x1801
 
107
#endif
 
108
#ifndef GL_STENCIL
 
109
#define GL_STENCIL 0x1802
 
110
#endif
 
111
 
 
112
 
 
113
static void
 
114
_cogl_framebuffer_gl_flush_viewport_state (CoglFramebuffer *framebuffer)
 
115
{
 
116
  float gl_viewport_y;
 
117
 
 
118
  g_assert (framebuffer->viewport_width >=0 &&
 
119
            framebuffer->viewport_height >=0);
 
120
 
 
121
  /* Convert the Cogl viewport y offset to an OpenGL viewport y offset
 
122
   * NB: OpenGL defines its window and viewport origins to be bottom
 
123
   * left, while Cogl defines them to be top left.
 
124
   * NB: We render upside down to offscreen framebuffers so we don't
 
125
   * need to convert the y offset in this case. */
 
126
  if (cogl_is_offscreen (framebuffer))
 
127
    gl_viewport_y = framebuffer->viewport_y;
 
128
  else
 
129
    gl_viewport_y = framebuffer->height -
 
130
      (framebuffer->viewport_y + framebuffer->viewport_height);
 
131
 
 
132
  COGL_NOTE (OPENGL, "Calling glViewport(%f, %f, %f, %f)",
 
133
             framebuffer->viewport_x,
 
134
             gl_viewport_y,
 
135
             framebuffer->viewport_width,
 
136
             framebuffer->viewport_height);
 
137
 
 
138
  GE (framebuffer->context,
 
139
      glViewport (framebuffer->viewport_x,
 
140
                  gl_viewport_y,
 
141
                  framebuffer->viewport_width,
 
142
                  framebuffer->viewport_height));
 
143
}
 
144
 
 
145
static void
 
146
_cogl_framebuffer_gl_flush_clip_state (CoglFramebuffer *framebuffer)
 
147
{
 
148
  CoglClipStack *stack = _cogl_clip_state_get_stack (&framebuffer->clip_state);
 
149
  _cogl_clip_stack_flush (stack, framebuffer);
 
150
}
 
151
 
 
152
static void
 
153
_cogl_framebuffer_gl_flush_dither_state (CoglFramebuffer *framebuffer)
 
154
{
 
155
  CoglContext *ctx = framebuffer->context;
 
156
 
 
157
  if (ctx->current_gl_dither_enabled != framebuffer->dither_enabled)
 
158
    {
 
159
      if (framebuffer->dither_enabled)
 
160
        GE (ctx, glEnable (GL_DITHER));
 
161
      else
 
162
        GE (ctx, glDisable (GL_DITHER));
 
163
      ctx->current_gl_dither_enabled = framebuffer->dither_enabled;
 
164
    }
 
165
}
 
166
 
 
167
static void
 
168
_cogl_framebuffer_gl_flush_modelview_state (CoglFramebuffer *framebuffer)
 
169
{
 
170
  CoglMatrixEntry *modelview_entry =
 
171
    _cogl_framebuffer_get_modelview_entry (framebuffer);
 
172
  _cogl_context_set_current_modelview_entry (framebuffer->context,
 
173
                                             modelview_entry);
 
174
}
 
175
 
 
176
static void
 
177
_cogl_framebuffer_gl_flush_projection_state (CoglFramebuffer *framebuffer)
 
178
{
 
179
  CoglMatrixEntry *projection_entry =
 
180
    _cogl_framebuffer_get_projection_entry (framebuffer);
 
181
  _cogl_context_set_current_projection_entry (framebuffer->context,
 
182
                                             projection_entry);
 
183
}
 
184
 
 
185
static void
 
186
_cogl_framebuffer_gl_flush_color_mask_state (CoglFramebuffer *framebuffer)
 
187
{
 
188
  CoglContext *context = framebuffer->context;
 
189
 
 
190
  /* The color mask state is really owned by a CoglPipeline so to
 
191
   * ensure the color mask is updated the next time we draw something
 
192
   * we need to make sure the logic ops for the pipeline are
 
193
   * re-flushed... */
 
194
  context->current_pipeline_changes_since_flush |=
 
195
    COGL_PIPELINE_STATE_LOGIC_OPS;
 
196
  context->current_pipeline_age--;
 
197
}
 
198
 
 
199
static void
 
200
_cogl_framebuffer_gl_flush_front_face_winding_state (CoglFramebuffer *framebuffer)
 
201
{
 
202
  CoglContext *context = framebuffer->context;
 
203
  CoglPipelineCullFaceMode mode;
 
204
 
 
205
  /* NB: The face winding state is actually owned by the current
 
206
   * CoglPipeline.
 
207
   *
 
208
   * If we don't have a current pipeline then we can just assume that
 
209
   * when we later do flush a pipeline we will check the current
 
210
   * framebuffer to know how to setup the winding */
 
211
  if (!context->current_pipeline)
 
212
    return;
 
213
 
 
214
  mode = cogl_pipeline_get_cull_face_mode (context->current_pipeline);
 
215
 
 
216
  /* If the current CoglPipeline has a culling mode that doesn't care
 
217
   * about the winding we can avoid forcing an update of the state and
 
218
   * bail out. */
 
219
  if (mode == COGL_PIPELINE_CULL_FACE_MODE_NONE ||
 
220
      mode == COGL_PIPELINE_CULL_FACE_MODE_BOTH)
 
221
    return;
 
222
 
 
223
  /* Since the winding state is really owned by the current pipeline
 
224
   * the way we "flush" an updated winding is to dirty the pipeline
 
225
   * state... */
 
226
  context->current_pipeline_changes_since_flush |=
 
227
    COGL_PIPELINE_STATE_CULL_FACE;
 
228
  context->current_pipeline_age--;
 
229
}
 
230
 
 
231
void
 
232
_cogl_framebuffer_gl_bind (CoglFramebuffer *framebuffer, GLenum target)
 
233
{
 
234
  CoglContext *ctx = framebuffer->context;
 
235
 
 
236
  if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN)
 
237
    {
 
238
      CoglOffscreen *offscreen = COGL_OFFSCREEN (framebuffer);
 
239
      GE (ctx, glBindFramebuffer (target,
 
240
                                  offscreen->gl_framebuffer.fbo_handle));
 
241
    }
 
242
  else
 
243
    {
 
244
      const CoglWinsysVtable *winsys =
 
245
        _cogl_framebuffer_get_winsys (framebuffer);
 
246
      winsys->onscreen_bind (COGL_ONSCREEN (framebuffer));
 
247
      /* glBindFramebuffer is an an extension with OpenGL ES 1.1 */
 
248
      if (cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
 
249
        GE (ctx, glBindFramebuffer (target, 0));
 
250
    }
 
251
}
 
252
 
 
253
void
 
254
_cogl_framebuffer_gl_flush_state (CoglFramebuffer *draw_buffer,
 
255
                                  CoglFramebuffer *read_buffer,
 
256
                                  CoglFramebufferState state)
 
257
{
 
258
  CoglContext *ctx = draw_buffer->context;
 
259
  unsigned long differences;
 
260
  int bit;
 
261
 
 
262
  /* We can assume that any state that has changed for the current
 
263
   * framebuffer is different to the currently flushed value. */
 
264
  differences = ctx->current_draw_buffer_changes;
 
265
 
 
266
  /* Any state of the current framebuffer that hasn't already been
 
267
   * flushed is assumed to be unknown so we will always flush that
 
268
   * state if asked. */
 
269
  differences |= ~ctx->current_draw_buffer_state_flushed;
 
270
 
 
271
  /* We only need to consider the state we've been asked to flush */
 
272
  differences &= state;
 
273
 
 
274
  if (ctx->current_draw_buffer != draw_buffer)
 
275
    {
 
276
      /* If the previous draw buffer is NULL then we'll assume
 
277
         everything has changed. This can happen if a framebuffer is
 
278
         destroyed while it is the last flushed draw buffer. In that
 
279
         case the framebuffer destructor will set
 
280
         ctx->current_draw_buffer to NULL */
 
281
      if (ctx->current_draw_buffer == NULL)
 
282
        differences |= state;
 
283
      else
 
284
        /* NB: we only need to compare the state we're being asked to flush
 
285
         * and we don't need to compare the state we've already decided
 
286
         * we will definitely flush... */
 
287
        differences |= _cogl_framebuffer_compare (ctx->current_draw_buffer,
 
288
                                                  draw_buffer,
 
289
                                                  state & ~differences);
 
290
 
 
291
      /* NB: we don't take a reference here, to avoid a circular
 
292
       * reference. */
 
293
      ctx->current_draw_buffer = draw_buffer;
 
294
      ctx->current_draw_buffer_state_flushed = 0;
 
295
    }
 
296
 
 
297
  if (ctx->current_read_buffer != read_buffer &&
 
298
      state & COGL_FRAMEBUFFER_STATE_BIND)
 
299
    {
 
300
      differences |= COGL_FRAMEBUFFER_STATE_BIND;
 
301
      /* NB: we don't take a reference here, to avoid a circular
 
302
       * reference. */
 
303
      ctx->current_read_buffer = read_buffer;
 
304
    }
 
305
 
 
306
  if (!differences)
 
307
    return;
 
308
 
 
309
  /* Lazily ensure the framebuffers have been allocated */
 
310
  if (G_UNLIKELY (!draw_buffer->allocated))
 
311
    cogl_framebuffer_allocate (draw_buffer, NULL);
 
312
  if (G_UNLIKELY (!read_buffer->allocated))
 
313
    cogl_framebuffer_allocate (read_buffer, NULL);
 
314
 
 
315
  /* We handle buffer binding separately since the method depends on whether
 
316
   * we are binding the same buffer for read and write or not unlike all
 
317
   * other state that only relates to the draw_buffer. */
 
318
  if (differences & COGL_FRAMEBUFFER_STATE_BIND)
 
319
    {
 
320
      if (draw_buffer == read_buffer)
 
321
        _cogl_framebuffer_gl_bind (draw_buffer, GL_FRAMEBUFFER);
 
322
      else
 
323
        {
 
324
          /* NB: Currently we only take advantage of binding separate
 
325
           * read/write buffers for offscreen framebuffer blit
 
326
           * purposes.  */
 
327
          _COGL_RETURN_IF_FAIL (ctx->private_feature_flags &
 
328
                                COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT);
 
329
          _COGL_RETURN_IF_FAIL (draw_buffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN);
 
330
          _COGL_RETURN_IF_FAIL (read_buffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN);
 
331
 
 
332
          _cogl_framebuffer_gl_bind (draw_buffer, GL_DRAW_FRAMEBUFFER);
 
333
          _cogl_framebuffer_gl_bind (read_buffer, GL_READ_FRAMEBUFFER);
 
334
        }
 
335
 
 
336
      differences &= ~COGL_FRAMEBUFFER_STATE_BIND;
 
337
    }
 
338
 
 
339
  COGL_FLAGS_FOREACH_START (&differences, 1, bit)
 
340
    {
 
341
      /* XXX: We considered having an array of callbacks for each state index
 
342
       * that we'd call here but decided that this way the compiler is more
 
343
       * likely going to be able to in-line the flush functions and use the
 
344
       * index to jump straight to the required code. */
 
345
      switch (bit)
 
346
        {
 
347
        case COGL_FRAMEBUFFER_STATE_INDEX_VIEWPORT:
 
348
          _cogl_framebuffer_gl_flush_viewport_state (draw_buffer);
 
349
          break;
 
350
        case COGL_FRAMEBUFFER_STATE_INDEX_CLIP:
 
351
          _cogl_framebuffer_gl_flush_clip_state (draw_buffer);
 
352
          break;
 
353
        case COGL_FRAMEBUFFER_STATE_INDEX_DITHER:
 
354
          _cogl_framebuffer_gl_flush_dither_state (draw_buffer);
 
355
          break;
 
356
        case COGL_FRAMEBUFFER_STATE_INDEX_MODELVIEW:
 
357
          _cogl_framebuffer_gl_flush_modelview_state (draw_buffer);
 
358
          break;
 
359
        case COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION:
 
360
          _cogl_framebuffer_gl_flush_projection_state (draw_buffer);
 
361
          break;
 
362
        case COGL_FRAMEBUFFER_STATE_INDEX_COLOR_MASK:
 
363
          _cogl_framebuffer_gl_flush_color_mask_state (draw_buffer);
 
364
          break;
 
365
        case COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING:
 
366
          _cogl_framebuffer_gl_flush_front_face_winding_state (draw_buffer);
 
367
          break;
 
368
        default:
 
369
          g_warn_if_reached ();
 
370
        }
 
371
    }
 
372
  COGL_FLAGS_FOREACH_END;
 
373
 
 
374
  ctx->current_draw_buffer_state_flushed |= state;
 
375
  ctx->current_draw_buffer_changes &= ~state;
 
376
}
 
377
 
 
378
static CoglTexture *
 
379
create_depth_texture (CoglContext *ctx,
 
380
                      int width,
 
381
                      int height)
 
382
{
 
383
  CoglPixelFormat format;
 
384
  CoglTexture2D *depth_texture;
 
385
 
 
386
  if (ctx->private_feature_flags &
 
387
      (COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL |
 
388
       COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL))
 
389
    {
 
390
      format = COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8;
 
391
    }
 
392
  else
 
393
    format = COGL_PIXEL_FORMAT_DEPTH_16;
 
394
 
 
395
  depth_texture =  cogl_texture_2d_new_with_size (ctx,
 
396
                                                  width, height,
 
397
                                                  format);
 
398
 
 
399
  return COGL_TEXTURE (depth_texture);
 
400
}
 
401
 
 
402
static CoglTexture *
 
403
attach_depth_texture (CoglContext *ctx,
 
404
                      CoglTexture *depth_texture,
 
405
                      CoglOffscreenAllocateFlags flags)
 
406
{
 
407
  GLuint tex_gl_handle;
 
408
  GLenum tex_gl_target;
 
409
 
 
410
  if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL)
 
411
    {
 
412
      /* attach a GL_DEPTH_STENCIL texture to the GL_DEPTH_ATTACHMENT and
 
413
       * GL_STENCIL_ATTACHMENT attachement points */
 
414
      g_assert (cogl_texture_get_format (depth_texture) ==
 
415
                COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8);
 
416
 
 
417
      cogl_texture_get_gl_texture (depth_texture,
 
418
                                   &tex_gl_handle, &tex_gl_target);
 
419
 
 
420
      GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER,
 
421
                                       GL_DEPTH_ATTACHMENT,
 
422
                                       tex_gl_target, tex_gl_handle,
 
423
                                       0));
 
424
      GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER,
 
425
                                       GL_STENCIL_ATTACHMENT,
 
426
                                       tex_gl_target, tex_gl_handle,
 
427
                                       0));
 
428
    }
 
429
  else if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH)
 
430
    {
 
431
      /* attach a newly created GL_DEPTH_COMPONENT16 texture to the
 
432
       * GL_DEPTH_ATTACHMENT attachement point */
 
433
      g_assert (cogl_texture_get_format (depth_texture) ==
 
434
                COGL_PIXEL_FORMAT_DEPTH_16);
 
435
 
 
436
      cogl_texture_get_gl_texture (COGL_TEXTURE (depth_texture),
 
437
                                   &tex_gl_handle, &tex_gl_target);
 
438
 
 
439
      GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER,
 
440
                                       GL_DEPTH_ATTACHMENT,
 
441
                                       tex_gl_target, tex_gl_handle,
 
442
                                       0));
 
443
    }
 
444
 
 
445
  return COGL_TEXTURE (depth_texture);
 
446
}
 
447
 
 
448
static GList *
 
449
try_creating_renderbuffers (CoglContext *ctx,
 
450
                            int width,
 
451
                            int height,
 
452
                            CoglOffscreenAllocateFlags flags,
 
453
                            int n_samples)
 
454
{
 
455
  GList *renderbuffers = NULL;
 
456
  GLuint gl_depth_stencil_handle;
 
457
 
 
458
  if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL)
 
459
    {
 
460
      GLenum format;
 
461
 
 
462
      /* Although GL_OES_packed_depth_stencil is mostly equivalent to
 
463
       * GL_EXT_packed_depth_stencil, one notable difference is that
 
464
       * GL_OES_packed_depth_stencil doesn't allow GL_DEPTH_STENCIL to
 
465
       * be passed as an internal format to glRenderbufferStorage.
 
466
       */
 
467
      if (ctx->private_feature_flags &
 
468
          COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL)
 
469
        format = GL_DEPTH_STENCIL;
 
470
      else
 
471
        {
 
472
          _COGL_RETURN_VAL_IF_FAIL (
 
473
                                  ctx->private_feature_flags &
 
474
                                  COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL,
 
475
                                  NULL);
 
476
          format = GL_DEPTH24_STENCIL8;
 
477
        }
 
478
 
 
479
      /* Create a renderbuffer for depth and stenciling */
 
480
      GE (ctx, glGenRenderbuffers (1, &gl_depth_stencil_handle));
 
481
      GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_stencil_handle));
 
482
      if (n_samples)
 
483
        GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER,
 
484
                                                      n_samples,
 
485
                                                      format,
 
486
                                                      width, height));
 
487
      else
 
488
        GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, format,
 
489
                                        width, height));
 
490
      GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0));
 
491
      GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
 
492
                                          GL_STENCIL_ATTACHMENT,
 
493
                                          GL_RENDERBUFFER,
 
494
                                          gl_depth_stencil_handle));
 
495
      GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
 
496
                                          GL_DEPTH_ATTACHMENT,
 
497
                                          GL_RENDERBUFFER,
 
498
                                          gl_depth_stencil_handle));
 
499
      renderbuffers =
 
500
        g_list_prepend (renderbuffers,
 
501
                        GUINT_TO_POINTER (gl_depth_stencil_handle));
 
502
    }
 
503
 
 
504
  if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH)
 
505
    {
 
506
      GLuint gl_depth_handle;
 
507
 
 
508
      GE (ctx, glGenRenderbuffers (1, &gl_depth_handle));
 
509
      GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_handle));
 
510
      /* For now we just ask for GL_DEPTH_COMPONENT16 since this is all that's
 
511
       * available under GLES */
 
512
      if (n_samples)
 
513
        GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER,
 
514
                                                      n_samples,
 
515
                                                      GL_DEPTH_COMPONENT16,
 
516
                                                      width, height));
 
517
      else
 
518
        GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
 
519
                                        width, height));
 
520
      GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0));
 
521
      GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
 
522
                                          GL_DEPTH_ATTACHMENT,
 
523
                                          GL_RENDERBUFFER, gl_depth_handle));
 
524
      renderbuffers =
 
525
        g_list_prepend (renderbuffers, GUINT_TO_POINTER (gl_depth_handle));
 
526
    }
 
527
 
 
528
  if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL)
 
529
    {
 
530
      GLuint gl_stencil_handle;
 
531
 
 
532
      GE (ctx, glGenRenderbuffers (1, &gl_stencil_handle));
 
533
      GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_stencil_handle));
 
534
      if (n_samples)
 
535
        GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER,
 
536
                                                      n_samples,
 
537
                                                      GL_STENCIL_INDEX8,
 
538
                                                      width, height));
 
539
      else
 
540
        GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_STENCIL_INDEX8,
 
541
                                        width, height));
 
542
      GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0));
 
543
      GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
 
544
                                          GL_STENCIL_ATTACHMENT,
 
545
                                          GL_RENDERBUFFER, gl_stencil_handle));
 
546
      renderbuffers =
 
547
        g_list_prepend (renderbuffers, GUINT_TO_POINTER (gl_stencil_handle));
 
548
    }
 
549
 
 
550
  return renderbuffers;
 
551
}
 
552
 
 
553
static void
 
554
delete_renderbuffers (CoglContext *ctx, GList *renderbuffers)
 
555
{
 
556
  GList *l;
 
557
 
 
558
  for (l = renderbuffers; l; l = l->next)
 
559
    {
 
560
      GLuint renderbuffer = GPOINTER_TO_UINT (l->data);
 
561
      GE (ctx, glDeleteRenderbuffers (1, &renderbuffer));
 
562
    }
 
563
 
 
564
  g_list_free (renderbuffers);
 
565
}
 
566
 
 
567
/*
 
568
 * NB: This function may be called with a standalone GLES2 context
 
569
 * bound so we can create a shadow framebuffer that wraps the same
 
570
 * CoglTexture as the given CoglOffscreen. This function shouldn't
 
571
 * modify anything in
 
572
 */
 
573
static CoglBool
 
574
try_creating_fbo (CoglContext *ctx,
 
575
                  CoglTexture *texture,
 
576
                  int texture_level,
 
577
                  int texture_level_width,
 
578
                  int texture_level_height,
 
579
                  CoglTexture *depth_texture,
 
580
                  CoglFramebufferConfig *config,
 
581
                  CoglOffscreenAllocateFlags flags,
 
582
                  CoglGLFramebuffer *gl_framebuffer)
 
583
{
 
584
  GLuint tex_gl_handle;
 
585
  GLenum tex_gl_target;
 
586
  GLenum status;
 
587
  int n_samples;
 
588
 
 
589
  if (!cogl_texture_get_gl_texture (texture, &tex_gl_handle, &tex_gl_target))
 
590
    return FALSE;
 
591
 
 
592
  if (tex_gl_target != GL_TEXTURE_2D
 
593
#ifdef HAVE_COGL_GL
 
594
      && tex_gl_target != GL_TEXTURE_RECTANGLE_ARB
 
595
#endif
 
596
      )
 
597
    return FALSE;
 
598
 
 
599
  if (config->samples_per_pixel)
 
600
    {
 
601
      if (!ctx->glFramebufferTexture2DMultisampleIMG)
 
602
        return FALSE;
 
603
      n_samples = config->samples_per_pixel;
 
604
    }
 
605
  else
 
606
    n_samples = 0;
 
607
 
 
608
  /* We are about to generate and bind a new fbo, so we pretend to
 
609
   * change framebuffer state so that the old framebuffer will be
 
610
   * rebound again before drawing. */
 
611
  ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_BIND;
 
612
 
 
613
  /* Generate framebuffer */
 
614
  ctx->glGenFramebuffers (1, &gl_framebuffer->fbo_handle);
 
615
  GE (ctx, glBindFramebuffer (GL_FRAMEBUFFER, gl_framebuffer->fbo_handle));
 
616
 
 
617
  if (n_samples)
 
618
    {
 
619
      GE (ctx, glFramebufferTexture2DMultisampleIMG (GL_FRAMEBUFFER,
 
620
                                                     GL_COLOR_ATTACHMENT0,
 
621
                                                     tex_gl_target, tex_gl_handle,
 
622
                                                     n_samples,
 
623
                                                     texture_level));
 
624
    }
 
625
  else
 
626
    GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
 
627
                                     tex_gl_target, tex_gl_handle,
 
628
                                     texture_level));
 
629
 
 
630
  /* attach either a depth/stencil texture, a depth texture or render buffers
 
631
   * depending on what we've been asked to provide */
 
632
 
 
633
  if (depth_texture &&
 
634
      flags & (COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL |
 
635
               COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH))
 
636
    {
 
637
      attach_depth_texture (ctx, depth_texture, flags);
 
638
 
 
639
      /* Let's clear the flags that are now fulfilled as we might need to
 
640
       * create renderbuffers (for the ALLOCATE_FLAG_DEPTH |
 
641
       * ALLOCATE_FLAG_STENCIL case) */
 
642
      flags &= ~(COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL |
 
643
                 COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH);
 
644
    }
 
645
 
 
646
  if (flags)
 
647
    {
 
648
      gl_framebuffer->renderbuffers =
 
649
        try_creating_renderbuffers (ctx,
 
650
                                    texture_level_width,
 
651
                                    texture_level_height,
 
652
                                    flags,
 
653
                                    n_samples);
 
654
    }
 
655
 
 
656
  /* Make sure it's complete */
 
657
  status = ctx->glCheckFramebufferStatus (GL_FRAMEBUFFER);
 
658
 
 
659
  if (status != GL_FRAMEBUFFER_COMPLETE)
 
660
    {
 
661
      GE (ctx, glDeleteFramebuffers (1, &gl_framebuffer->fbo_handle));
 
662
 
 
663
      delete_renderbuffers (ctx, gl_framebuffer->renderbuffers);
 
664
      gl_framebuffer->renderbuffers = NULL;
 
665
 
 
666
      return FALSE;
 
667
    }
 
668
 
 
669
  /* Update the real number of samples_per_pixel now that we have a
 
670
   * complete framebuffer */
 
671
  if (n_samples)
 
672
    {
 
673
      GLenum attachment = GL_COLOR_ATTACHMENT0;
 
674
      GLenum pname = GL_TEXTURE_SAMPLES_IMG;
 
675
      int texture_samples;
 
676
 
 
677
      GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
 
678
                                                      attachment,
 
679
                                                      pname,
 
680
                                                      &texture_samples) );
 
681
      gl_framebuffer->samples_per_pixel = texture_samples;
 
682
    }
 
683
 
 
684
  return TRUE;
 
685
}
 
686
 
 
687
CoglBool
 
688
_cogl_framebuffer_try_creating_gl_fbo (CoglContext *ctx,
 
689
                                       CoglTexture *texture,
 
690
                                       int texture_level,
 
691
                                       int texture_level_width,
 
692
                                       int texture_level_height,
 
693
                                       CoglTexture *depth_texture,
 
694
                                       CoglFramebufferConfig *config,
 
695
                                       CoglOffscreenAllocateFlags flags,
 
696
                                       CoglGLFramebuffer *gl_framebuffer)
 
697
{
 
698
  return try_creating_fbo (ctx,
 
699
                           texture,
 
700
                           texture_level,
 
701
                           texture_level_width,
 
702
                           texture_level_height,
 
703
                           depth_texture,
 
704
                           config,
 
705
                           flags,
 
706
                           gl_framebuffer);
 
707
}
 
708
 
 
709
CoglBool
 
710
_cogl_offscreen_gl_allocate (CoglOffscreen *offscreen,
 
711
                             CoglError **error)
 
712
{
 
713
  CoglFramebuffer *fb = COGL_FRAMEBUFFER (offscreen);
 
714
  CoglContext *ctx = fb->context;
 
715
  CoglOffscreenAllocateFlags flags;
 
716
  CoglGLFramebuffer *gl_framebuffer = &offscreen->gl_framebuffer;
 
717
 
 
718
  if (fb->config.depth_texture_enabled &&
 
719
      offscreen->depth_texture == NULL)
 
720
    {
 
721
      offscreen->depth_texture =
 
722
        create_depth_texture (ctx,
 
723
                              offscreen->texture_level_width,
 
724
                              offscreen->texture_level_height);
 
725
 
 
726
      if (!cogl_texture_allocate (offscreen->depth_texture, error))
 
727
        {
 
728
          cogl_object_unref (offscreen->depth_texture);
 
729
          offscreen->depth_texture = NULL;
 
730
          return FALSE;
 
731
        }
 
732
 
 
733
      _cogl_texture_associate_framebuffer (offscreen->depth_texture, fb);
 
734
    }
 
735
 
 
736
  /* XXX: The framebuffer_object spec isn't clear in defining whether attaching
 
737
   * a texture as a renderbuffer with mipmap filtering enabled while the
 
738
   * mipmaps have not been uploaded should result in an incomplete framebuffer
 
739
   * object. (different drivers make different decisions)
 
740
   *
 
741
   * To avoid an error with drivers that do consider this a problem we
 
742
   * explicitly set non mipmapped filters here. These will later be reset when
 
743
   * the texture is actually used for rendering according to the filters set on
 
744
   * the corresponding CoglPipeline.
 
745
   */
 
746
  _cogl_texture_gl_flush_legacy_texobj_filters (offscreen->texture,
 
747
                                                GL_NEAREST, GL_NEAREST);
 
748
 
 
749
  if (((offscreen->create_flags & COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL) &&
 
750
       try_creating_fbo (ctx,
 
751
                         offscreen->texture,
 
752
                         offscreen->texture_level,
 
753
                         offscreen->texture_level_width,
 
754
                         offscreen->texture_level_height,
 
755
                         offscreen->depth_texture,
 
756
                         &fb->config,
 
757
                         flags = 0,
 
758
                         gl_framebuffer)) ||
 
759
 
 
760
      (ctx->have_last_offscreen_allocate_flags &&
 
761
       try_creating_fbo (ctx,
 
762
                         offscreen->texture,
 
763
                         offscreen->texture_level,
 
764
                         offscreen->texture_level_width,
 
765
                         offscreen->texture_level_height,
 
766
                         offscreen->depth_texture,
 
767
                         &fb->config,
 
768
                         flags = ctx->last_offscreen_allocate_flags,
 
769
                         gl_framebuffer)) ||
 
770
 
 
771
      ((ctx->private_feature_flags &
 
772
        (COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL |
 
773
         COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL)) &&
 
774
       try_creating_fbo (ctx,
 
775
                         offscreen->texture,
 
776
                         offscreen->texture_level,
 
777
                         offscreen->texture_level_width,
 
778
                         offscreen->texture_level_height,
 
779
                         offscreen->depth_texture,
 
780
                         &fb->config,
 
781
                         flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL,
 
782
                         gl_framebuffer)) ||
 
783
 
 
784
      try_creating_fbo (ctx,
 
785
                        offscreen->texture,
 
786
                        offscreen->texture_level,
 
787
                        offscreen->texture_level_width,
 
788
                        offscreen->texture_level_height,
 
789
                        offscreen->depth_texture,
 
790
                        &fb->config,
 
791
                        flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH |
 
792
                        COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL,
 
793
                        gl_framebuffer) ||
 
794
 
 
795
      try_creating_fbo (ctx,
 
796
                        offscreen->texture,
 
797
                        offscreen->texture_level,
 
798
                        offscreen->texture_level_width,
 
799
                        offscreen->texture_level_height,
 
800
                        offscreen->depth_texture,
 
801
                        &fb->config,
 
802
                        flags = COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL,
 
803
                        gl_framebuffer) ||
 
804
 
 
805
      try_creating_fbo (ctx,
 
806
                        offscreen->texture,
 
807
                        offscreen->texture_level,
 
808
                        offscreen->texture_level_width,
 
809
                        offscreen->texture_level_height,
 
810
                        offscreen->depth_texture,
 
811
                        &fb->config,
 
812
                        flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH,
 
813
                        gl_framebuffer) ||
 
814
 
 
815
      try_creating_fbo (ctx,
 
816
                        offscreen->texture,
 
817
                        offscreen->texture_level,
 
818
                        offscreen->texture_level_width,
 
819
                        offscreen->texture_level_height,
 
820
                        offscreen->depth_texture,
 
821
                        &fb->config,
 
822
                        flags = 0,
 
823
                        gl_framebuffer))
 
824
    {
 
825
      fb->samples_per_pixel = gl_framebuffer->samples_per_pixel;
 
826
 
 
827
      if (!offscreen->create_flags & COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL)
 
828
        {
 
829
          /* Record that the last set of flags succeeded so that we can
 
830
             try that set first next time */
 
831
          ctx->last_offscreen_allocate_flags = flags;
 
832
          ctx->have_last_offscreen_allocate_flags = TRUE;
 
833
        }
 
834
 
 
835
      /* Save the flags we managed to successfully allocate the
 
836
       * renderbuffers with in case we need to make renderbuffers for a
 
837
       * GLES2 context later */
 
838
      offscreen->allocation_flags = flags;
 
839
 
 
840
      return TRUE;
 
841
    }
 
842
  else
 
843
    {
 
844
      _cogl_set_error (error, COGL_FRAMEBUFFER_ERROR,
 
845
                       COGL_FRAMEBUFFER_ERROR_ALLOCATE,
 
846
                       "Failed to create an OpenGL framebuffer object");
 
847
      return FALSE;
 
848
    }
 
849
}
 
850
 
 
851
void
 
852
_cogl_offscreen_gl_free (CoglOffscreen *offscreen)
 
853
{
 
854
  CoglContext *ctx = COGL_FRAMEBUFFER (offscreen)->context;
 
855
 
 
856
  delete_renderbuffers (ctx, offscreen->gl_framebuffer.renderbuffers);
 
857
 
 
858
  GE (ctx, glDeleteFramebuffers (1, &offscreen->gl_framebuffer.fbo_handle));
 
859
}
 
860
 
 
861
void
 
862
_cogl_framebuffer_gl_clear (CoglFramebuffer *framebuffer,
 
863
                            unsigned long buffers,
 
864
                            float red,
 
865
                            float green,
 
866
                            float blue,
 
867
                            float alpha)
 
868
{
 
869
  CoglContext *ctx = framebuffer->context;
 
870
  GLbitfield gl_buffers = 0;
 
871
 
 
872
  if (buffers & COGL_BUFFER_BIT_COLOR)
 
873
    {
 
874
      GE( ctx, glClearColor (red, green, blue, alpha) );
 
875
      gl_buffers |= GL_COLOR_BUFFER_BIT;
 
876
 
 
877
      if (ctx->current_gl_color_mask != framebuffer->color_mask)
 
878
        {
 
879
          CoglColorMask color_mask = framebuffer->color_mask;
 
880
          GE( ctx, glColorMask (!!(color_mask & COGL_COLOR_MASK_RED),
 
881
                                !!(color_mask & COGL_COLOR_MASK_GREEN),
 
882
                                !!(color_mask & COGL_COLOR_MASK_BLUE),
 
883
                                !!(color_mask & COGL_COLOR_MASK_ALPHA)));
 
884
          ctx->current_gl_color_mask = color_mask;
 
885
          /* Make sure the ColorMask is updated when the next primitive is drawn */
 
886
          ctx->current_pipeline_changes_since_flush |=
 
887
            COGL_PIPELINE_STATE_LOGIC_OPS;
 
888
          ctx->current_pipeline_age--;
 
889
        }
 
890
    }
 
891
 
 
892
  if (buffers & COGL_BUFFER_BIT_DEPTH)
 
893
    gl_buffers |= GL_DEPTH_BUFFER_BIT;
 
894
 
 
895
  if (buffers & COGL_BUFFER_BIT_STENCIL)
 
896
    gl_buffers |= GL_STENCIL_BUFFER_BIT;
 
897
 
 
898
 
 
899
  GE (ctx, glClear (gl_buffers));
 
900
}
 
901
 
 
902
static inline void
 
903
_cogl_framebuffer_init_bits (CoglFramebuffer *framebuffer)
 
904
{
 
905
  CoglContext *ctx = framebuffer->context;
 
906
 
 
907
  if (G_LIKELY (!framebuffer->dirty_bitmasks))
 
908
    return;
 
909
 
 
910
  cogl_framebuffer_allocate (framebuffer, NULL);
 
911
 
 
912
  _cogl_framebuffer_flush_state (framebuffer,
 
913
                                 framebuffer,
 
914
                                 COGL_FRAMEBUFFER_STATE_BIND);
 
915
 
 
916
#ifdef HAVE_COGL_GL
 
917
  if ((ctx->private_feature_flags &
 
918
       COGL_PRIVATE_FEATURE_QUERY_FRAMEBUFFER_BITS) &&
 
919
      framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN)
 
920
    {
 
921
      static const struct
 
922
      {
 
923
        GLenum attachment, pname;
 
924
        size_t offset;
 
925
      } params[] =
 
926
          {
 
927
            { GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE,
 
928
              offsetof (CoglFramebufferBits, red) },
 
929
            { GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE,
 
930
              offsetof (CoglFramebufferBits, green) },
 
931
            { GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE,
 
932
              offsetof (CoglFramebufferBits, blue) },
 
933
            { GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE,
 
934
              offsetof (CoglFramebufferBits, alpha) },
 
935
            { GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE,
 
936
              offsetof (CoglFramebufferBits, depth) },
 
937
            { GL_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE,
 
938
              offsetof (CoglFramebufferBits, stencil) },
 
939
          };
 
940
      int i;
 
941
 
 
942
      for (i = 0; i < G_N_ELEMENTS (params); i++)
 
943
        {
 
944
          int *value =
 
945
            (int *) ((uint8_t *) &framebuffer->bits + params[i].offset);
 
946
          GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
 
947
                                                          params[i].attachment,
 
948
                                                          params[i].pname,
 
949
                                                          value) );
 
950
        }
 
951
    }
 
952
  else
 
953
#endif /* HAVE_COGL_GL */
 
954
    {
 
955
      GE( ctx, glGetIntegerv (GL_RED_BITS,   &framebuffer->bits.red)   );
 
956
      GE( ctx, glGetIntegerv (GL_GREEN_BITS, &framebuffer->bits.green) );
 
957
      GE( ctx, glGetIntegerv (GL_BLUE_BITS,  &framebuffer->bits.blue)  );
 
958
      GE( ctx, glGetIntegerv (GL_ALPHA_BITS, &framebuffer->bits.alpha) );
 
959
      GE( ctx, glGetIntegerv (GL_DEPTH_BITS, &framebuffer->bits.depth) );
 
960
      GE( ctx, glGetIntegerv (GL_STENCIL_BITS, &framebuffer->bits.stencil) );
 
961
    }
 
962
 
 
963
  /* If we don't have alpha textures then the alpha bits are actually
 
964
   * stored in the red component */
 
965
  if ((ctx->private_feature_flags &
 
966
       COGL_PRIVATE_FEATURE_ALPHA_TEXTURES) == 0 &&
 
967
      framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN &&
 
968
      framebuffer->format == COGL_PIXEL_FORMAT_A_8)
 
969
    {
 
970
      framebuffer->bits.alpha = framebuffer->bits.red;
 
971
      framebuffer->bits.red = 0;
 
972
    }
 
973
 
 
974
  COGL_NOTE (OFFSCREEN,
 
975
             "RGBA/D/S Bits for framebuffer[%p, %s]: %d, %d, %d, %d, %d, %d",
 
976
             framebuffer,
 
977
             framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN
 
978
               ? "offscreen"
 
979
               : "onscreen",
 
980
             framebuffer->bits.red,
 
981
             framebuffer->bits.blue,
 
982
             framebuffer->bits.green,
 
983
             framebuffer->bits.alpha,
 
984
             framebuffer->bits.depth,
 
985
             framebuffer->bits.stencil);
 
986
 
 
987
  framebuffer->dirty_bitmasks = FALSE;
 
988
}
 
989
 
 
990
void
 
991
_cogl_framebuffer_gl_query_bits (CoglFramebuffer *framebuffer,
 
992
                                 CoglFramebufferBits *bits)
 
993
{
 
994
  _cogl_framebuffer_init_bits (framebuffer);
 
995
 
 
996
  /* TODO: cache these in some driver specific location not
 
997
   * directly as part of CoglFramebuffer. */
 
998
  *bits = framebuffer->bits;
 
999
}
 
1000
 
 
1001
void
 
1002
_cogl_framebuffer_gl_finish (CoglFramebuffer *framebuffer)
 
1003
{
 
1004
  GE (framebuffer->context, glFinish ());
 
1005
}
 
1006
 
 
1007
void
 
1008
_cogl_framebuffer_gl_discard_buffers (CoglFramebuffer *framebuffer,
 
1009
                                      unsigned long buffers)
 
1010
{
 
1011
  CoglContext *ctx = framebuffer->context;
 
1012
 
 
1013
  if (ctx->glDiscardFramebuffer)
 
1014
    {
 
1015
      GLenum attachments[3];
 
1016
      int i = 0;
 
1017
 
 
1018
      if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
 
1019
        {
 
1020
          if (buffers & COGL_BUFFER_BIT_COLOR)
 
1021
            attachments[i++] = GL_COLOR;
 
1022
          if (buffers & COGL_BUFFER_BIT_DEPTH)
 
1023
            attachments[i++] = GL_DEPTH;
 
1024
          if (buffers & COGL_BUFFER_BIT_STENCIL)
 
1025
            attachments[i++] = GL_STENCIL;
 
1026
        }
 
1027
      else
 
1028
        {
 
1029
          if (buffers & COGL_BUFFER_BIT_COLOR)
 
1030
            attachments[i++] = GL_COLOR_ATTACHMENT0;
 
1031
          if (buffers & COGL_BUFFER_BIT_DEPTH)
 
1032
            attachments[i++] = GL_DEPTH_ATTACHMENT;
 
1033
          if (buffers & COGL_BUFFER_BIT_STENCIL)
 
1034
            attachments[i++] = GL_STENCIL_ATTACHMENT;
 
1035
        }
 
1036
 
 
1037
      _cogl_framebuffer_flush_state (framebuffer,
 
1038
                                     framebuffer,
 
1039
                                     COGL_FRAMEBUFFER_STATE_BIND);
 
1040
      GE (ctx, glDiscardFramebuffer (GL_FRAMEBUFFER, i, attachments));
 
1041
    }
 
1042
}
 
1043
 
 
1044
void
 
1045
_cogl_framebuffer_gl_draw_attributes (CoglFramebuffer *framebuffer,
 
1046
                                      CoglPipeline *pipeline,
 
1047
                                      CoglVerticesMode mode,
 
1048
                                      int first_vertex,
 
1049
                                      int n_vertices,
 
1050
                                      CoglAttribute **attributes,
 
1051
                                      int n_attributes,
 
1052
                                      CoglDrawFlags flags)
 
1053
{
 
1054
  _cogl_flush_attributes_state (framebuffer, pipeline, flags,
 
1055
                                attributes, n_attributes);
 
1056
 
 
1057
  GE (framebuffer->context,
 
1058
      glDrawArrays ((GLenum)mode, first_vertex, n_vertices));
 
1059
}
 
1060
 
 
1061
static size_t
 
1062
sizeof_index_type (CoglIndicesType type)
 
1063
{
 
1064
  switch (type)
 
1065
    {
 
1066
    case COGL_INDICES_TYPE_UNSIGNED_BYTE:
 
1067
      return 1;
 
1068
    case COGL_INDICES_TYPE_UNSIGNED_SHORT:
 
1069
      return 2;
 
1070
    case COGL_INDICES_TYPE_UNSIGNED_INT:
 
1071
      return 4;
 
1072
    }
 
1073
  g_return_val_if_reached (0);
 
1074
}
 
1075
 
 
1076
void
 
1077
_cogl_framebuffer_gl_draw_indexed_attributes (CoglFramebuffer *framebuffer,
 
1078
                                              CoglPipeline *pipeline,
 
1079
                                              CoglVerticesMode mode,
 
1080
                                              int first_vertex,
 
1081
                                              int n_vertices,
 
1082
                                              CoglIndices *indices,
 
1083
                                              CoglAttribute **attributes,
 
1084
                                              int n_attributes,
 
1085
                                              CoglDrawFlags flags)
 
1086
{
 
1087
  CoglBuffer *buffer;
 
1088
  uint8_t *base;
 
1089
  size_t buffer_offset;
 
1090
  size_t index_size;
 
1091
  GLenum indices_gl_type = 0;
 
1092
 
 
1093
  _cogl_flush_attributes_state (framebuffer, pipeline, flags,
 
1094
                                attributes, n_attributes);
 
1095
 
 
1096
  buffer = COGL_BUFFER (cogl_indices_get_buffer (indices));
 
1097
 
 
1098
  /* Note: we don't try and catch errors with binding the index buffer
 
1099
   * here since OOM errors at this point indicate that nothing has yet
 
1100
   * been uploaded to the indices buffer which we consider to be a
 
1101
   * programmer error.
 
1102
   */
 
1103
  base = _cogl_buffer_gl_bind (buffer,
 
1104
                               COGL_BUFFER_BIND_TARGET_INDEX_BUFFER, NULL);
 
1105
  buffer_offset = cogl_indices_get_offset (indices);
 
1106
  index_size = sizeof_index_type (cogl_indices_get_type (indices));
 
1107
 
 
1108
  switch (cogl_indices_get_type (indices))
 
1109
    {
 
1110
    case COGL_INDICES_TYPE_UNSIGNED_BYTE:
 
1111
      indices_gl_type = GL_UNSIGNED_BYTE;
 
1112
      break;
 
1113
    case COGL_INDICES_TYPE_UNSIGNED_SHORT:
 
1114
      indices_gl_type = GL_UNSIGNED_SHORT;
 
1115
      break;
 
1116
    case COGL_INDICES_TYPE_UNSIGNED_INT:
 
1117
      indices_gl_type = GL_UNSIGNED_INT;
 
1118
      break;
 
1119
    }
 
1120
 
 
1121
  GE (framebuffer->context,
 
1122
      glDrawElements ((GLenum)mode,
 
1123
                      n_vertices,
 
1124
                      indices_gl_type,
 
1125
                      base + buffer_offset + index_size * first_vertex));
 
1126
 
 
1127
  _cogl_buffer_gl_unbind (buffer);
 
1128
}
 
1129
 
 
1130
static CoglBool
 
1131
mesa_46631_slow_read_pixels_workaround (CoglFramebuffer *framebuffer,
 
1132
                                        int x,
 
1133
                                        int y,
 
1134
                                        CoglReadPixelsFlags source,
 
1135
                                        CoglBitmap *bitmap,
 
1136
                                        CoglError **error)
 
1137
{
 
1138
  CoglContext *ctx;
 
1139
  CoglPixelFormat format;
 
1140
  CoglBitmap *pbo;
 
1141
  int width;
 
1142
  int height;
 
1143
  CoglBool res;
 
1144
  uint8_t *dst;
 
1145
  const uint8_t *src;
 
1146
 
 
1147
  ctx = cogl_framebuffer_get_context (framebuffer);
 
1148
 
 
1149
  width = cogl_bitmap_get_width (bitmap);
 
1150
  height = cogl_bitmap_get_height (bitmap);
 
1151
  format = cogl_bitmap_get_format (bitmap);
 
1152
 
 
1153
  pbo = cogl_bitmap_new_with_size (ctx, width, height, format);
 
1154
 
 
1155
  /* Read into the pbo. We need to disable the flipping because the
 
1156
     blit fast path in the driver does not work with
 
1157
     GL_PACK_INVERT_MESA is set */
 
1158
  res = _cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
 
1159
                                                   x, y,
 
1160
                                                   source |
 
1161
                                                   COGL_READ_PIXELS_NO_FLIP,
 
1162
                                                   pbo,
 
1163
                                                   error);
 
1164
  if (!res)
 
1165
    {
 
1166
      cogl_object_unref (pbo);
 
1167
      return FALSE;
 
1168
    }
 
1169
 
 
1170
  /* Copy the pixels back into application's buffer */
 
1171
  dst = _cogl_bitmap_map (bitmap,
 
1172
                          COGL_BUFFER_ACCESS_WRITE,
 
1173
                          COGL_BUFFER_MAP_HINT_DISCARD,
 
1174
                          error);
 
1175
  if (!dst)
 
1176
    {
 
1177
      cogl_object_unref (pbo);
 
1178
      return FALSE;
 
1179
    }
 
1180
 
 
1181
  src = _cogl_bitmap_map (pbo,
 
1182
                          COGL_BUFFER_ACCESS_READ,
 
1183
                          0, /* hints */
 
1184
                          error);
 
1185
  if (src)
 
1186
    {
 
1187
      int src_rowstride = cogl_bitmap_get_rowstride (pbo);
 
1188
      int dst_rowstride = cogl_bitmap_get_rowstride (bitmap);
 
1189
      int to_copy =
 
1190
        _cogl_pixel_format_get_bytes_per_pixel (format) * width;
 
1191
      int y;
 
1192
 
 
1193
      /* If the framebuffer is onscreen we need to flip the
 
1194
         data while copying */
 
1195
      if (!cogl_is_offscreen (framebuffer))
 
1196
        {
 
1197
          src += src_rowstride * (height - 1);
 
1198
          src_rowstride = -src_rowstride;
 
1199
        }
 
1200
 
 
1201
      for (y = 0; y < height; y++)
 
1202
        {
 
1203
          memcpy (dst, src, to_copy);
 
1204
          dst += dst_rowstride;
 
1205
          src += src_rowstride;
 
1206
        }
 
1207
 
 
1208
      _cogl_bitmap_unmap (pbo);
 
1209
    }
 
1210
  else
 
1211
    res = FALSE;
 
1212
 
 
1213
  _cogl_bitmap_unmap (bitmap);
 
1214
 
 
1215
  cogl_object_unref (pbo);
 
1216
 
 
1217
  return res;
 
1218
}
 
1219
 
 
1220
CoglBool
 
1221
_cogl_framebuffer_gl_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
 
1222
                                              int x,
 
1223
                                              int y,
 
1224
                                              CoglReadPixelsFlags source,
 
1225
                                              CoglBitmap *bitmap,
 
1226
                                              CoglError **error)
 
1227
{
 
1228
  CoglContext *ctx = framebuffer->context;
 
1229
  int framebuffer_height = cogl_framebuffer_get_height (framebuffer);
 
1230
  int width = cogl_bitmap_get_width (bitmap);
 
1231
  int height = cogl_bitmap_get_height (bitmap);
 
1232
  CoglPixelFormat format = cogl_bitmap_get_format (bitmap);
 
1233
  CoglPixelFormat required_format;
 
1234
  GLenum gl_intformat;
 
1235
  GLenum gl_format;
 
1236
  GLenum gl_type;
 
1237
  CoglBool pack_invert_set;
 
1238
  int status = FALSE;
 
1239
 
 
1240
  /* Workaround for cases where its faster to read into a temporary
 
1241
   * PBO. This is only worth doing if:
 
1242
   *
 
1243
   * • The GPU is an Intel GPU. In that case there is a known
 
1244
   *   fast-path when reading into a PBO that will use the blitter
 
1245
   *   instead of the Mesa fallback code. The driver bug will only be
 
1246
   *   set if this is the case.
 
1247
   * • We're not already reading into a PBO.
 
1248
   * • The target format is BGRA. The fast-path blit does not get hit
 
1249
   *   otherwise.
 
1250
   * • The size of the data is not trivially small. This isn't a
 
1251
   *   requirement to hit the fast-path blit but intuitively it feels
 
1252
   *   like if the amount of data is too small then the cost of
 
1253
   *   allocating a PBO will outweigh the cost of temporarily
 
1254
   *   converting the data to floats.
 
1255
   */
 
1256
  if ((ctx->gpu.driver_bugs &
 
1257
       COGL_GPU_INFO_DRIVER_BUG_MESA_46631_SLOW_READ_PIXELS) &&
 
1258
      (width > 8 || height > 8) &&
 
1259
      (format & ~COGL_PREMULT_BIT) == COGL_PIXEL_FORMAT_BGRA_8888 &&
 
1260
      cogl_bitmap_get_buffer (bitmap) == NULL)
 
1261
    {
 
1262
      CoglError *ignore_error = NULL;
 
1263
 
 
1264
      if (mesa_46631_slow_read_pixels_workaround (framebuffer,
 
1265
                                                  x, y,
 
1266
                                                  source,
 
1267
                                                  bitmap,
 
1268
                                                  &ignore_error))
 
1269
        return TRUE;
 
1270
      else
 
1271
        cogl_error_free (ignore_error);
 
1272
    }
 
1273
 
 
1274
  _cogl_framebuffer_flush_state (framebuffer,
 
1275
                                 framebuffer,
 
1276
                                 COGL_FRAMEBUFFER_STATE_BIND);
 
1277
 
 
1278
  /* The y co-ordinate should be given in OpenGL's coordinate system
 
1279
   * so 0 is the bottom row
 
1280
   *
 
1281
   * NB: all offscreen rendering is done upside down so no conversion
 
1282
   * is necissary in this case.
 
1283
   */
 
1284
  if (!cogl_is_offscreen (framebuffer))
 
1285
    y = framebuffer_height - y - height;
 
1286
 
 
1287
  required_format = ctx->driver_vtable->pixel_format_to_gl (ctx,
 
1288
                                                            format,
 
1289
                                                            &gl_intformat,
 
1290
                                                            &gl_format,
 
1291
                                                            &gl_type);
 
1292
 
 
1293
  /* NB: All offscreen rendering is done upside down so there is no need
 
1294
   * to flip in this case... */
 
1295
  if ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_MESA_PACK_INVERT) &&
 
1296
      (source & COGL_READ_PIXELS_NO_FLIP) == 0 &&
 
1297
      !cogl_is_offscreen (framebuffer))
 
1298
    {
 
1299
      GE (ctx, glPixelStorei (GL_PACK_INVERT_MESA, TRUE));
 
1300
      pack_invert_set = TRUE;
 
1301
    }
 
1302
  else
 
1303
    pack_invert_set = FALSE;
 
1304
 
 
1305
  /* Under GLES only GL_RGBA with GL_UNSIGNED_BYTE as well as an
 
1306
     implementation specific format under
 
1307
     GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES and
 
1308
     GL_IMPLEMENTATION_COLOR_READ_TYPE_OES is supported. We could try
 
1309
     to be more clever and check if the requested type matches that
 
1310
     but we would need some reliable functions to convert from GL
 
1311
     types to Cogl types. For now, lets just always read in
 
1312
     GL_RGBA/GL_UNSIGNED_BYTE and convert if necessary. We also need
 
1313
     to use this intermediate buffer if the rowstride has padding
 
1314
     because GLES does not support setting GL_ROW_LENGTH */
 
1315
  if ((!(ctx->private_feature_flags &
 
1316
         COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT) &&
 
1317
       (gl_format != GL_RGBA || gl_type != GL_UNSIGNED_BYTE ||
 
1318
        cogl_bitmap_get_rowstride (bitmap) != 4 * width)) ||
 
1319
      (required_format & ~COGL_PREMULT_BIT) != (format & ~COGL_PREMULT_BIT))
 
1320
    {
 
1321
      CoglBitmap *tmp_bmp;
 
1322
      CoglPixelFormat read_format;
 
1323
      int bpp, rowstride;
 
1324
      uint8_t *tmp_data;
 
1325
      CoglBool succeeded;
 
1326
 
 
1327
      if ((ctx->private_feature_flags &
 
1328
           COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT))
 
1329
        read_format = required_format;
 
1330
      else
 
1331
        {
 
1332
          read_format = COGL_PIXEL_FORMAT_RGBA_8888;
 
1333
          gl_format = GL_RGBA;
 
1334
          gl_type = GL_UNSIGNED_BYTE;
 
1335
        }
 
1336
 
 
1337
      if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (read_format))
 
1338
        read_format = ((read_format & ~COGL_PREMULT_BIT) |
 
1339
                       (framebuffer->format & COGL_PREMULT_BIT));
 
1340
 
 
1341
      tmp_bmp = _cogl_bitmap_new_with_malloc_buffer (ctx,
 
1342
                                                     width, height,
 
1343
                                                     read_format,
 
1344
                                                     error);
 
1345
      if (!tmp_bmp)
 
1346
        goto EXIT;
 
1347
 
 
1348
      bpp = _cogl_pixel_format_get_bytes_per_pixel (read_format);
 
1349
      rowstride = cogl_bitmap_get_rowstride (tmp_bmp);
 
1350
 
 
1351
      ctx->texture_driver->prep_gl_for_pixels_download (ctx,
 
1352
                                                        rowstride,
 
1353
                                                        width,
 
1354
                                                        bpp);
 
1355
 
 
1356
      /* Note: we don't worry about catching errors here since we know
 
1357
       * we won't be lazily allocating storage for this buffer so it
 
1358
       * won't fail due to lack of memory. */
 
1359
      tmp_data = _cogl_bitmap_gl_bind (tmp_bmp,
 
1360
                                       COGL_BUFFER_ACCESS_WRITE,
 
1361
                                       COGL_BUFFER_MAP_HINT_DISCARD,
 
1362
                                       NULL);
 
1363
 
 
1364
      GE( ctx, glReadPixels (x, y, width, height,
 
1365
                             gl_format, gl_type,
 
1366
                             tmp_data) );
 
1367
 
 
1368
      _cogl_bitmap_gl_unbind (tmp_bmp);
 
1369
 
 
1370
      succeeded = _cogl_bitmap_convert_into_bitmap (tmp_bmp, bitmap, error);
 
1371
 
 
1372
      cogl_object_unref (tmp_bmp);
 
1373
 
 
1374
      if (!succeeded)
 
1375
        goto EXIT;
 
1376
    }
 
1377
  else
 
1378
    {
 
1379
      CoglBitmap *shared_bmp;
 
1380
      CoglPixelFormat bmp_format;
 
1381
      int bpp, rowstride;
 
1382
      CoglBool succeeded = FALSE;
 
1383
      uint8_t *pixels;
 
1384
      CoglError *internal_error = NULL;
 
1385
 
 
1386
      rowstride = cogl_bitmap_get_rowstride (bitmap);
 
1387
 
 
1388
      /* We match the premultiplied state of the target buffer to the
 
1389
       * premultiplied state of the framebuffer so that it will get
 
1390
       * converted to the right format below */
 
1391
      if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (format))
 
1392
        bmp_format = ((format & ~COGL_PREMULT_BIT) |
 
1393
                      (framebuffer->format & COGL_PREMULT_BIT));
 
1394
      else
 
1395
        bmp_format = format;
 
1396
 
 
1397
      if (bmp_format != format)
 
1398
        shared_bmp = _cogl_bitmap_new_shared (bitmap,
 
1399
                                              bmp_format,
 
1400
                                              width, height,
 
1401
                                              rowstride);
 
1402
      else
 
1403
        shared_bmp = cogl_object_ref (bitmap);
 
1404
 
 
1405
      bpp = _cogl_pixel_format_get_bytes_per_pixel (bmp_format);
 
1406
 
 
1407
      ctx->texture_driver->prep_gl_for_pixels_download (ctx,
 
1408
                                                        rowstride,
 
1409
                                                        width,
 
1410
                                                        bpp);
 
1411
 
 
1412
      pixels = _cogl_bitmap_gl_bind (shared_bmp,
 
1413
                                     COGL_BUFFER_ACCESS_WRITE,
 
1414
                                     0, /* hints */
 
1415
                                     &internal_error);
 
1416
      /* NB: _cogl_bitmap_gl_bind() can return NULL in sucessfull
 
1417
       * cases so we have to explicitly check the cogl error pointer
 
1418
       * to know if there was a problem */
 
1419
      if (internal_error)
 
1420
        {
 
1421
          cogl_object_unref (shared_bmp);
 
1422
          _cogl_propagate_error (error, internal_error);
 
1423
          goto EXIT;
 
1424
        }
 
1425
 
 
1426
      GE( ctx, glReadPixels (x, y,
 
1427
                             width, height,
 
1428
                             gl_format, gl_type,
 
1429
                             pixels) );
 
1430
 
 
1431
      _cogl_bitmap_gl_unbind (shared_bmp);
 
1432
 
 
1433
      /* Convert to the premult format specified by the caller
 
1434
         in-place. This will do nothing if the premult status is already
 
1435
         correct. */
 
1436
      if (_cogl_bitmap_convert_premult_status (shared_bmp, format, error))
 
1437
        succeeded = TRUE;
 
1438
 
 
1439
      cogl_object_unref (shared_bmp);
 
1440
 
 
1441
      if (!succeeded)
 
1442
        goto EXIT;
 
1443
    }
 
1444
 
 
1445
  /* NB: All offscreen rendering is done upside down so there is no need
 
1446
   * to flip in this case... */
 
1447
  if (!cogl_is_offscreen (framebuffer) &&
 
1448
      (source & COGL_READ_PIXELS_NO_FLIP) == 0 &&
 
1449
      !pack_invert_set)
 
1450
    {
 
1451
      uint8_t *temprow;
 
1452
      int rowstride;
 
1453
      uint8_t *pixels;
 
1454
 
 
1455
      rowstride = cogl_bitmap_get_rowstride (bitmap);
 
1456
      pixels = _cogl_bitmap_map (bitmap,
 
1457
                                 COGL_BUFFER_ACCESS_READ |
 
1458
                                 COGL_BUFFER_ACCESS_WRITE,
 
1459
                                 0, /* hints */
 
1460
                                 error);
 
1461
 
 
1462
      if (pixels == NULL)
 
1463
        goto EXIT;
 
1464
 
 
1465
      temprow = g_alloca (rowstride * sizeof (uint8_t));
 
1466
 
 
1467
      /* vertically flip the buffer in-place */
 
1468
      for (y = 0; y < height / 2; y++)
 
1469
        {
 
1470
          if (y != height - y - 1) /* skip center row */
 
1471
            {
 
1472
              memcpy (temprow,
 
1473
                      pixels + y * rowstride, rowstride);
 
1474
              memcpy (pixels + y * rowstride,
 
1475
                      pixels + (height - y - 1) * rowstride, rowstride);
 
1476
              memcpy (pixels + (height - y - 1) * rowstride,
 
1477
                      temprow,
 
1478
                      rowstride);
 
1479
            }
 
1480
        }
 
1481
 
 
1482
      _cogl_bitmap_unmap (bitmap);
 
1483
    }
 
1484
 
 
1485
  status = TRUE;
 
1486
 
 
1487
EXIT:
 
1488
 
 
1489
  /* Currently this function owns the pack_invert state and we don't want this
 
1490
   * to interfere with other Cogl components so all other code can assume that
 
1491
   * we leave the pack_invert state off. */
 
1492
  if (pack_invert_set)
 
1493
    GE (ctx, glPixelStorei (GL_PACK_INVERT_MESA, FALSE));
 
1494
 
 
1495
  return status;
 
1496
}