4
* An object oriented GL/GLES Abstraction/Utility Layer
6
* Copyright (C) 2007,2008,2009,2012 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, see
20
* <http://www.gnu.org/licenses/>.
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"
41
#ifndef GL_FRAMEBUFFER
42
#define GL_FRAMEBUFFER 0x8D40
44
#ifndef GL_RENDERBUFFER
45
#define GL_RENDERBUFFER 0x8D41
47
#ifndef GL_STENCIL_ATTACHMENT
48
#define GL_STENCIL_ATTACHMENT 0x8D00
50
#ifndef GL_COLOR_ATTACHMENT0
51
#define GL_COLOR_ATTACHMENT0 0x8CE0
53
#ifndef GL_FRAMEBUFFER_COMPLETE
54
#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
56
#ifndef GL_STENCIL_INDEX8
57
#define GL_STENCIL_INDEX8 0x8D48
59
#ifndef GL_DEPTH_STENCIL
60
#define GL_DEPTH_STENCIL 0x84F9
62
#ifndef GL_DEPTH24_STENCIL8
63
#define GL_DEPTH24_STENCIL8 0x88F0
65
#ifndef GL_DEPTH_ATTACHMENT
66
#define GL_DEPTH_ATTACHMENT 0x8D00
68
#ifndef GL_DEPTH_COMPONENT16
69
#define GL_DEPTH_COMPONENT16 0x81A5
71
#ifndef GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE
72
#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212
74
#ifndef GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE
75
#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213
77
#ifndef GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE
78
#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214
80
#ifndef GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE
81
#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215
83
#ifndef GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE
84
#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216
86
#ifndef GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE
87
#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217
89
#ifndef GL_READ_FRAMEBUFFER
90
#define GL_READ_FRAMEBUFFER 0x8CA8
92
#ifndef GL_DRAW_FRAMEBUFFER
93
#define GL_DRAW_FRAMEBUFFER 0x8CA9
95
#ifndef GL_TEXTURE_SAMPLES_IMG
96
#define GL_TEXTURE_SAMPLES_IMG 0x9136
98
#ifndef GL_PACK_INVERT_MESA
99
#define GL_PACK_INVERT_MESA 0x8758
103
#define GL_COLOR 0x1800
106
#define GL_DEPTH 0x1801
109
#define GL_STENCIL 0x1802
114
_cogl_framebuffer_gl_flush_viewport_state (CoglFramebuffer *framebuffer)
118
g_assert (framebuffer->viewport_width >=0 &&
119
framebuffer->viewport_height >=0);
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;
129
gl_viewport_y = framebuffer->height -
130
(framebuffer->viewport_y + framebuffer->viewport_height);
132
COGL_NOTE (OPENGL, "Calling glViewport(%f, %f, %f, %f)",
133
framebuffer->viewport_x,
135
framebuffer->viewport_width,
136
framebuffer->viewport_height);
138
GE (framebuffer->context,
139
glViewport (framebuffer->viewport_x,
141
framebuffer->viewport_width,
142
framebuffer->viewport_height));
146
_cogl_framebuffer_gl_flush_clip_state (CoglFramebuffer *framebuffer)
148
CoglClipStack *stack = _cogl_clip_state_get_stack (&framebuffer->clip_state);
149
_cogl_clip_stack_flush (stack, framebuffer);
153
_cogl_framebuffer_gl_flush_dither_state (CoglFramebuffer *framebuffer)
155
CoglContext *ctx = framebuffer->context;
157
if (ctx->current_gl_dither_enabled != framebuffer->dither_enabled)
159
if (framebuffer->dither_enabled)
160
GE (ctx, glEnable (GL_DITHER));
162
GE (ctx, glDisable (GL_DITHER));
163
ctx->current_gl_dither_enabled = framebuffer->dither_enabled;
168
_cogl_framebuffer_gl_flush_modelview_state (CoglFramebuffer *framebuffer)
170
CoglMatrixEntry *modelview_entry =
171
_cogl_framebuffer_get_modelview_entry (framebuffer);
172
_cogl_context_set_current_modelview_entry (framebuffer->context,
177
_cogl_framebuffer_gl_flush_projection_state (CoglFramebuffer *framebuffer)
179
CoglMatrixEntry *projection_entry =
180
_cogl_framebuffer_get_projection_entry (framebuffer);
181
_cogl_context_set_current_projection_entry (framebuffer->context,
186
_cogl_framebuffer_gl_flush_color_mask_state (CoglFramebuffer *framebuffer)
188
CoglContext *context = framebuffer->context;
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
194
context->current_pipeline_changes_since_flush |=
195
COGL_PIPELINE_STATE_LOGIC_OPS;
196
context->current_pipeline_age--;
200
_cogl_framebuffer_gl_flush_front_face_winding_state (CoglFramebuffer *framebuffer)
202
CoglContext *context = framebuffer->context;
203
CoglPipelineCullFaceMode mode;
205
/* NB: The face winding state is actually owned by the current
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)
214
mode = cogl_pipeline_get_cull_face_mode (context->current_pipeline);
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
219
if (mode == COGL_PIPELINE_CULL_FACE_MODE_NONE ||
220
mode == COGL_PIPELINE_CULL_FACE_MODE_BOTH)
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
226
context->current_pipeline_changes_since_flush |=
227
COGL_PIPELINE_STATE_CULL_FACE;
228
context->current_pipeline_age--;
232
_cogl_framebuffer_gl_bind (CoglFramebuffer *framebuffer, GLenum target)
234
CoglContext *ctx = framebuffer->context;
236
if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN)
238
CoglOffscreen *offscreen = COGL_OFFSCREEN (framebuffer);
239
GE (ctx, glBindFramebuffer (target,
240
offscreen->gl_framebuffer.fbo_handle));
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));
254
_cogl_framebuffer_gl_flush_state (CoglFramebuffer *draw_buffer,
255
CoglFramebuffer *read_buffer,
256
CoglFramebufferState state)
258
CoglContext *ctx = draw_buffer->context;
259
unsigned long differences;
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;
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
269
differences |= ~ctx->current_draw_buffer_state_flushed;
271
/* We only need to consider the state we've been asked to flush */
272
differences &= state;
274
if (ctx->current_draw_buffer != draw_buffer)
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;
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,
289
state & ~differences);
291
/* NB: we don't take a reference here, to avoid a circular
293
ctx->current_draw_buffer = draw_buffer;
294
ctx->current_draw_buffer_state_flushed = 0;
297
if (ctx->current_read_buffer != read_buffer &&
298
state & COGL_FRAMEBUFFER_STATE_BIND)
300
differences |= COGL_FRAMEBUFFER_STATE_BIND;
301
/* NB: we don't take a reference here, to avoid a circular
303
ctx->current_read_buffer = read_buffer;
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);
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)
320
if (draw_buffer == read_buffer)
321
_cogl_framebuffer_gl_bind (draw_buffer, GL_FRAMEBUFFER);
324
/* NB: Currently we only take advantage of binding separate
325
* read/write buffers for offscreen framebuffer blit
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);
332
_cogl_framebuffer_gl_bind (draw_buffer, GL_DRAW_FRAMEBUFFER);
333
_cogl_framebuffer_gl_bind (read_buffer, GL_READ_FRAMEBUFFER);
336
differences &= ~COGL_FRAMEBUFFER_STATE_BIND;
339
COGL_FLAGS_FOREACH_START (&differences, 1, bit)
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. */
347
case COGL_FRAMEBUFFER_STATE_INDEX_VIEWPORT:
348
_cogl_framebuffer_gl_flush_viewport_state (draw_buffer);
350
case COGL_FRAMEBUFFER_STATE_INDEX_CLIP:
351
_cogl_framebuffer_gl_flush_clip_state (draw_buffer);
353
case COGL_FRAMEBUFFER_STATE_INDEX_DITHER:
354
_cogl_framebuffer_gl_flush_dither_state (draw_buffer);
356
case COGL_FRAMEBUFFER_STATE_INDEX_MODELVIEW:
357
_cogl_framebuffer_gl_flush_modelview_state (draw_buffer);
359
case COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION:
360
_cogl_framebuffer_gl_flush_projection_state (draw_buffer);
362
case COGL_FRAMEBUFFER_STATE_INDEX_COLOR_MASK:
363
_cogl_framebuffer_gl_flush_color_mask_state (draw_buffer);
365
case COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING:
366
_cogl_framebuffer_gl_flush_front_face_winding_state (draw_buffer);
369
g_warn_if_reached ();
372
COGL_FLAGS_FOREACH_END;
374
ctx->current_draw_buffer_state_flushed |= state;
375
ctx->current_draw_buffer_changes &= ~state;
379
create_depth_texture (CoglContext *ctx,
383
CoglPixelFormat format;
384
CoglTexture2D *depth_texture;
386
if (ctx->private_feature_flags &
387
(COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL |
388
COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL))
390
format = COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8;
393
format = COGL_PIXEL_FORMAT_DEPTH_16;
395
depth_texture = cogl_texture_2d_new_with_size (ctx,
399
return COGL_TEXTURE (depth_texture);
403
attach_depth_texture (CoglContext *ctx,
404
CoglTexture *depth_texture,
405
CoglOffscreenAllocateFlags flags)
407
GLuint tex_gl_handle;
408
GLenum tex_gl_target;
410
if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL)
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);
417
cogl_texture_get_gl_texture (depth_texture,
418
&tex_gl_handle, &tex_gl_target);
420
GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER,
422
tex_gl_target, tex_gl_handle,
424
GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER,
425
GL_STENCIL_ATTACHMENT,
426
tex_gl_target, tex_gl_handle,
429
else if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH)
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);
436
cogl_texture_get_gl_texture (COGL_TEXTURE (depth_texture),
437
&tex_gl_handle, &tex_gl_target);
439
GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER,
441
tex_gl_target, tex_gl_handle,
445
return COGL_TEXTURE (depth_texture);
449
try_creating_renderbuffers (CoglContext *ctx,
452
CoglOffscreenAllocateFlags flags,
455
GList *renderbuffers = NULL;
456
GLuint gl_depth_stencil_handle;
458
if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL)
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.
467
if (ctx->private_feature_flags &
468
COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL)
469
format = GL_DEPTH_STENCIL;
472
_COGL_RETURN_VAL_IF_FAIL (
473
ctx->private_feature_flags &
474
COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL,
476
format = GL_DEPTH24_STENCIL8;
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));
483
GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER,
488
GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, format,
490
GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0));
491
GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
492
GL_STENCIL_ATTACHMENT,
494
gl_depth_stencil_handle));
495
GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
498
gl_depth_stencil_handle));
500
g_list_prepend (renderbuffers,
501
GUINT_TO_POINTER (gl_depth_stencil_handle));
504
if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH)
506
GLuint gl_depth_handle;
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 */
513
GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER,
515
GL_DEPTH_COMPONENT16,
518
GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
520
GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0));
521
GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
523
GL_RENDERBUFFER, gl_depth_handle));
525
g_list_prepend (renderbuffers, GUINT_TO_POINTER (gl_depth_handle));
528
if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL)
530
GLuint gl_stencil_handle;
532
GE (ctx, glGenRenderbuffers (1, &gl_stencil_handle));
533
GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_stencil_handle));
535
GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER,
540
GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_STENCIL_INDEX8,
542
GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0));
543
GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
544
GL_STENCIL_ATTACHMENT,
545
GL_RENDERBUFFER, gl_stencil_handle));
547
g_list_prepend (renderbuffers, GUINT_TO_POINTER (gl_stencil_handle));
550
return renderbuffers;
554
delete_renderbuffers (CoglContext *ctx, GList *renderbuffers)
558
for (l = renderbuffers; l; l = l->next)
560
GLuint renderbuffer = GPOINTER_TO_UINT (l->data);
561
GE (ctx, glDeleteRenderbuffers (1, &renderbuffer));
564
g_list_free (renderbuffers);
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
574
try_creating_fbo (CoglContext *ctx,
575
CoglTexture *texture,
577
int texture_level_width,
578
int texture_level_height,
579
CoglTexture *depth_texture,
580
CoglFramebufferConfig *config,
581
CoglOffscreenAllocateFlags flags,
582
CoglGLFramebuffer *gl_framebuffer)
584
GLuint tex_gl_handle;
585
GLenum tex_gl_target;
589
if (!cogl_texture_get_gl_texture (texture, &tex_gl_handle, &tex_gl_target))
592
if (tex_gl_target != GL_TEXTURE_2D
594
&& tex_gl_target != GL_TEXTURE_RECTANGLE_ARB
599
if (config->samples_per_pixel)
601
if (!ctx->glFramebufferTexture2DMultisampleIMG)
603
n_samples = config->samples_per_pixel;
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;
613
/* Generate framebuffer */
614
ctx->glGenFramebuffers (1, &gl_framebuffer->fbo_handle);
615
GE (ctx, glBindFramebuffer (GL_FRAMEBUFFER, gl_framebuffer->fbo_handle));
619
GE (ctx, glFramebufferTexture2DMultisampleIMG (GL_FRAMEBUFFER,
620
GL_COLOR_ATTACHMENT0,
621
tex_gl_target, tex_gl_handle,
626
GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
627
tex_gl_target, tex_gl_handle,
630
/* attach either a depth/stencil texture, a depth texture or render buffers
631
* depending on what we've been asked to provide */
634
flags & (COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL |
635
COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH))
637
attach_depth_texture (ctx, depth_texture, flags);
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);
648
gl_framebuffer->renderbuffers =
649
try_creating_renderbuffers (ctx,
651
texture_level_height,
656
/* Make sure it's complete */
657
status = ctx->glCheckFramebufferStatus (GL_FRAMEBUFFER);
659
if (status != GL_FRAMEBUFFER_COMPLETE)
661
GE (ctx, glDeleteFramebuffers (1, &gl_framebuffer->fbo_handle));
663
delete_renderbuffers (ctx, gl_framebuffer->renderbuffers);
664
gl_framebuffer->renderbuffers = NULL;
669
/* Update the real number of samples_per_pixel now that we have a
670
* complete framebuffer */
673
GLenum attachment = GL_COLOR_ATTACHMENT0;
674
GLenum pname = GL_TEXTURE_SAMPLES_IMG;
677
GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
681
gl_framebuffer->samples_per_pixel = texture_samples;
688
_cogl_framebuffer_try_creating_gl_fbo (CoglContext *ctx,
689
CoglTexture *texture,
691
int texture_level_width,
692
int texture_level_height,
693
CoglTexture *depth_texture,
694
CoglFramebufferConfig *config,
695
CoglOffscreenAllocateFlags flags,
696
CoglGLFramebuffer *gl_framebuffer)
698
return try_creating_fbo (ctx,
702
texture_level_height,
710
_cogl_offscreen_gl_allocate (CoglOffscreen *offscreen,
713
CoglFramebuffer *fb = COGL_FRAMEBUFFER (offscreen);
714
CoglContext *ctx = fb->context;
715
CoglOffscreenAllocateFlags flags;
716
CoglGLFramebuffer *gl_framebuffer = &offscreen->gl_framebuffer;
718
if (fb->config.depth_texture_enabled &&
719
offscreen->depth_texture == NULL)
721
offscreen->depth_texture =
722
create_depth_texture (ctx,
723
offscreen->texture_level_width,
724
offscreen->texture_level_height);
726
if (!cogl_texture_allocate (offscreen->depth_texture, error))
728
cogl_object_unref (offscreen->depth_texture);
729
offscreen->depth_texture = NULL;
733
_cogl_texture_associate_framebuffer (offscreen->depth_texture, fb);
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)
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.
746
_cogl_texture_gl_flush_legacy_texobj_filters (offscreen->texture,
747
GL_NEAREST, GL_NEAREST);
749
if (((offscreen->create_flags & COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL) &&
750
try_creating_fbo (ctx,
752
offscreen->texture_level,
753
offscreen->texture_level_width,
754
offscreen->texture_level_height,
755
offscreen->depth_texture,
760
(ctx->have_last_offscreen_allocate_flags &&
761
try_creating_fbo (ctx,
763
offscreen->texture_level,
764
offscreen->texture_level_width,
765
offscreen->texture_level_height,
766
offscreen->depth_texture,
768
flags = ctx->last_offscreen_allocate_flags,
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,
776
offscreen->texture_level,
777
offscreen->texture_level_width,
778
offscreen->texture_level_height,
779
offscreen->depth_texture,
781
flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL,
784
try_creating_fbo (ctx,
786
offscreen->texture_level,
787
offscreen->texture_level_width,
788
offscreen->texture_level_height,
789
offscreen->depth_texture,
791
flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH |
792
COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL,
795
try_creating_fbo (ctx,
797
offscreen->texture_level,
798
offscreen->texture_level_width,
799
offscreen->texture_level_height,
800
offscreen->depth_texture,
802
flags = COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL,
805
try_creating_fbo (ctx,
807
offscreen->texture_level,
808
offscreen->texture_level_width,
809
offscreen->texture_level_height,
810
offscreen->depth_texture,
812
flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH,
815
try_creating_fbo (ctx,
817
offscreen->texture_level,
818
offscreen->texture_level_width,
819
offscreen->texture_level_height,
820
offscreen->depth_texture,
825
fb->samples_per_pixel = gl_framebuffer->samples_per_pixel;
827
if (!offscreen->create_flags & COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL)
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;
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;
844
_cogl_set_error (error, COGL_FRAMEBUFFER_ERROR,
845
COGL_FRAMEBUFFER_ERROR_ALLOCATE,
846
"Failed to create an OpenGL framebuffer object");
852
_cogl_offscreen_gl_free (CoglOffscreen *offscreen)
854
CoglContext *ctx = COGL_FRAMEBUFFER (offscreen)->context;
856
delete_renderbuffers (ctx, offscreen->gl_framebuffer.renderbuffers);
858
GE (ctx, glDeleteFramebuffers (1, &offscreen->gl_framebuffer.fbo_handle));
862
_cogl_framebuffer_gl_clear (CoglFramebuffer *framebuffer,
863
unsigned long buffers,
869
CoglContext *ctx = framebuffer->context;
870
GLbitfield gl_buffers = 0;
872
if (buffers & COGL_BUFFER_BIT_COLOR)
874
GE( ctx, glClearColor (red, green, blue, alpha) );
875
gl_buffers |= GL_COLOR_BUFFER_BIT;
877
if (ctx->current_gl_color_mask != framebuffer->color_mask)
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--;
892
if (buffers & COGL_BUFFER_BIT_DEPTH)
893
gl_buffers |= GL_DEPTH_BUFFER_BIT;
895
if (buffers & COGL_BUFFER_BIT_STENCIL)
896
gl_buffers |= GL_STENCIL_BUFFER_BIT;
899
GE (ctx, glClear (gl_buffers));
903
_cogl_framebuffer_init_bits (CoglFramebuffer *framebuffer)
905
CoglContext *ctx = framebuffer->context;
907
if (G_LIKELY (!framebuffer->dirty_bitmasks))
910
cogl_framebuffer_allocate (framebuffer, NULL);
912
_cogl_framebuffer_flush_state (framebuffer,
914
COGL_FRAMEBUFFER_STATE_BIND);
917
if ((ctx->private_feature_flags &
918
COGL_PRIVATE_FEATURE_QUERY_FRAMEBUFFER_BITS) &&
919
framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN)
923
GLenum attachment, pname;
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) },
942
for (i = 0; i < G_N_ELEMENTS (params); i++)
945
(int *) ((uint8_t *) &framebuffer->bits + params[i].offset);
946
GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
947
params[i].attachment,
953
#endif /* HAVE_COGL_GL */
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) );
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)
970
framebuffer->bits.alpha = framebuffer->bits.red;
971
framebuffer->bits.red = 0;
974
COGL_NOTE (OFFSCREEN,
975
"RGBA/D/S Bits for framebuffer[%p, %s]: %d, %d, %d, %d, %d, %d",
977
framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN
980
framebuffer->bits.red,
981
framebuffer->bits.blue,
982
framebuffer->bits.green,
983
framebuffer->bits.alpha,
984
framebuffer->bits.depth,
985
framebuffer->bits.stencil);
987
framebuffer->dirty_bitmasks = FALSE;
991
_cogl_framebuffer_gl_query_bits (CoglFramebuffer *framebuffer,
992
CoglFramebufferBits *bits)
994
_cogl_framebuffer_init_bits (framebuffer);
996
/* TODO: cache these in some driver specific location not
997
* directly as part of CoglFramebuffer. */
998
*bits = framebuffer->bits;
1002
_cogl_framebuffer_gl_finish (CoglFramebuffer *framebuffer)
1004
GE (framebuffer->context, glFinish ());
1008
_cogl_framebuffer_gl_discard_buffers (CoglFramebuffer *framebuffer,
1009
unsigned long buffers)
1011
CoglContext *ctx = framebuffer->context;
1013
if (ctx->glDiscardFramebuffer)
1015
GLenum attachments[3];
1018
if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
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;
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;
1037
_cogl_framebuffer_flush_state (framebuffer,
1039
COGL_FRAMEBUFFER_STATE_BIND);
1040
GE (ctx, glDiscardFramebuffer (GL_FRAMEBUFFER, i, attachments));
1045
_cogl_framebuffer_gl_draw_attributes (CoglFramebuffer *framebuffer,
1046
CoglPipeline *pipeline,
1047
CoglVerticesMode mode,
1050
CoglAttribute **attributes,
1052
CoglDrawFlags flags)
1054
_cogl_flush_attributes_state (framebuffer, pipeline, flags,
1055
attributes, n_attributes);
1057
GE (framebuffer->context,
1058
glDrawArrays ((GLenum)mode, first_vertex, n_vertices));
1062
sizeof_index_type (CoglIndicesType type)
1066
case COGL_INDICES_TYPE_UNSIGNED_BYTE:
1068
case COGL_INDICES_TYPE_UNSIGNED_SHORT:
1070
case COGL_INDICES_TYPE_UNSIGNED_INT:
1073
g_return_val_if_reached (0);
1077
_cogl_framebuffer_gl_draw_indexed_attributes (CoglFramebuffer *framebuffer,
1078
CoglPipeline *pipeline,
1079
CoglVerticesMode mode,
1082
CoglIndices *indices,
1083
CoglAttribute **attributes,
1085
CoglDrawFlags flags)
1089
size_t buffer_offset;
1091
GLenum indices_gl_type = 0;
1093
_cogl_flush_attributes_state (framebuffer, pipeline, flags,
1094
attributes, n_attributes);
1096
buffer = COGL_BUFFER (cogl_indices_get_buffer (indices));
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
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));
1108
switch (cogl_indices_get_type (indices))
1110
case COGL_INDICES_TYPE_UNSIGNED_BYTE:
1111
indices_gl_type = GL_UNSIGNED_BYTE;
1113
case COGL_INDICES_TYPE_UNSIGNED_SHORT:
1114
indices_gl_type = GL_UNSIGNED_SHORT;
1116
case COGL_INDICES_TYPE_UNSIGNED_INT:
1117
indices_gl_type = GL_UNSIGNED_INT;
1121
GE (framebuffer->context,
1122
glDrawElements ((GLenum)mode,
1125
base + buffer_offset + index_size * first_vertex));
1127
_cogl_buffer_gl_unbind (buffer);
1131
mesa_46631_slow_read_pixels_workaround (CoglFramebuffer *framebuffer,
1134
CoglReadPixelsFlags source,
1139
CoglPixelFormat format;
1147
ctx = cogl_framebuffer_get_context (framebuffer);
1149
width = cogl_bitmap_get_width (bitmap);
1150
height = cogl_bitmap_get_height (bitmap);
1151
format = cogl_bitmap_get_format (bitmap);
1153
pbo = cogl_bitmap_new_with_size (ctx, width, height, format);
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,
1161
COGL_READ_PIXELS_NO_FLIP,
1166
cogl_object_unref (pbo);
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,
1177
cogl_object_unref (pbo);
1181
src = _cogl_bitmap_map (pbo,
1182
COGL_BUFFER_ACCESS_READ,
1187
int src_rowstride = cogl_bitmap_get_rowstride (pbo);
1188
int dst_rowstride = cogl_bitmap_get_rowstride (bitmap);
1190
_cogl_pixel_format_get_bytes_per_pixel (format) * width;
1193
/* If the framebuffer is onscreen we need to flip the
1194
data while copying */
1195
if (!cogl_is_offscreen (framebuffer))
1197
src += src_rowstride * (height - 1);
1198
src_rowstride = -src_rowstride;
1201
for (y = 0; y < height; y++)
1203
memcpy (dst, src, to_copy);
1204
dst += dst_rowstride;
1205
src += src_rowstride;
1208
_cogl_bitmap_unmap (pbo);
1213
_cogl_bitmap_unmap (bitmap);
1215
cogl_object_unref (pbo);
1221
_cogl_framebuffer_gl_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
1224
CoglReadPixelsFlags source,
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;
1237
CoglBool pack_invert_set;
1240
/* Workaround for cases where its faster to read into a temporary
1241
* PBO. This is only worth doing if:
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
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.
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)
1262
CoglError *ignore_error = NULL;
1264
if (mesa_46631_slow_read_pixels_workaround (framebuffer,
1271
cogl_error_free (ignore_error);
1274
_cogl_framebuffer_flush_state (framebuffer,
1276
COGL_FRAMEBUFFER_STATE_BIND);
1278
/* The y co-ordinate should be given in OpenGL's coordinate system
1279
* so 0 is the bottom row
1281
* NB: all offscreen rendering is done upside down so no conversion
1282
* is necissary in this case.
1284
if (!cogl_is_offscreen (framebuffer))
1285
y = framebuffer_height - y - height;
1287
required_format = ctx->driver_vtable->pixel_format_to_gl (ctx,
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))
1299
GE (ctx, glPixelStorei (GL_PACK_INVERT_MESA, TRUE));
1300
pack_invert_set = TRUE;
1303
pack_invert_set = FALSE;
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))
1321
CoglBitmap *tmp_bmp;
1322
CoglPixelFormat read_format;
1327
if ((ctx->private_feature_flags &
1328
COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT))
1329
read_format = required_format;
1332
read_format = COGL_PIXEL_FORMAT_RGBA_8888;
1333
gl_format = GL_RGBA;
1334
gl_type = GL_UNSIGNED_BYTE;
1337
if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (read_format))
1338
read_format = ((read_format & ~COGL_PREMULT_BIT) |
1339
(framebuffer->format & COGL_PREMULT_BIT));
1341
tmp_bmp = _cogl_bitmap_new_with_malloc_buffer (ctx,
1348
bpp = _cogl_pixel_format_get_bytes_per_pixel (read_format);
1349
rowstride = cogl_bitmap_get_rowstride (tmp_bmp);
1351
ctx->texture_driver->prep_gl_for_pixels_download (ctx,
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,
1364
GE( ctx, glReadPixels (x, y, width, height,
1368
_cogl_bitmap_gl_unbind (tmp_bmp);
1370
succeeded = _cogl_bitmap_convert_into_bitmap (tmp_bmp, bitmap, error);
1372
cogl_object_unref (tmp_bmp);
1379
CoglBitmap *shared_bmp;
1380
CoglPixelFormat bmp_format;
1382
CoglBool succeeded = FALSE;
1384
CoglError *internal_error = NULL;
1386
rowstride = cogl_bitmap_get_rowstride (bitmap);
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));
1395
bmp_format = format;
1397
if (bmp_format != format)
1398
shared_bmp = _cogl_bitmap_new_shared (bitmap,
1403
shared_bmp = cogl_object_ref (bitmap);
1405
bpp = _cogl_pixel_format_get_bytes_per_pixel (bmp_format);
1407
ctx->texture_driver->prep_gl_for_pixels_download (ctx,
1412
pixels = _cogl_bitmap_gl_bind (shared_bmp,
1413
COGL_BUFFER_ACCESS_WRITE,
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 */
1421
cogl_object_unref (shared_bmp);
1422
_cogl_propagate_error (error, internal_error);
1426
GE( ctx, glReadPixels (x, y,
1431
_cogl_bitmap_gl_unbind (shared_bmp);
1433
/* Convert to the premult format specified by the caller
1434
in-place. This will do nothing if the premult status is already
1436
if (_cogl_bitmap_convert_premult_status (shared_bmp, format, error))
1439
cogl_object_unref (shared_bmp);
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 &&
1455
rowstride = cogl_bitmap_get_rowstride (bitmap);
1456
pixels = _cogl_bitmap_map (bitmap,
1457
COGL_BUFFER_ACCESS_READ |
1458
COGL_BUFFER_ACCESS_WRITE,
1465
temprow = g_alloca (rowstride * sizeof (uint8_t));
1467
/* vertically flip the buffer in-place */
1468
for (y = 0; y < height / 2; y++)
1470
if (y != height - y - 1) /* skip center row */
1473
pixels + y * rowstride, rowstride);
1474
memcpy (pixels + y * rowstride,
1475
pixels + (height - y - 1) * rowstride, rowstride);
1476
memcpy (pixels + (height - y - 1) * rowstride,
1482
_cogl_bitmap_unmap (bitmap);
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));