mirror of
https://github.com/brl/mutter.git
synced 2024-11-10 07:56:14 -05:00
05ce533fc8
We weren't taking a reference on the texture to be used as the color buffer for offscreen rendering, so it was possible to free the texture leaving the framebuffer in an inconsistent state.
625 lines
18 KiB
C
625 lines
18 KiB
C
/*
|
|
* Cogl
|
|
*
|
|
* An object oriented GL/GLES Abstraction/Utility Layer
|
|
*
|
|
* Copyright (C) 2007,2008,2009 Intel Corporation.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "cogl.h"
|
|
#include "cogl-internal.h"
|
|
#include "cogl-context.h"
|
|
#include "cogl-handle.h"
|
|
#include "cogl-util.h"
|
|
#include "cogl-texture-private.h"
|
|
#include "cogl-framebuffer-private.h"
|
|
#include "cogl-clip-stack.h"
|
|
|
|
#ifdef HAVE_COGL_GLES2
|
|
|
|
#include "../gles/cogl-gles2-wrapper.h"
|
|
|
|
#else
|
|
|
|
#define glGenRenderbuffers ctx->drv.pf_glGenRenderbuffers
|
|
#define glDeleteRenderbuffers ctx->drv.pf_glDeleteRenderbuffers
|
|
#define glBindRenderbuffer ctx->drv.pf_glBindRenderbuffer
|
|
#define glRenderbufferStorage ctx->drv.pf_glRenderbufferStorage
|
|
#define glGenFramebuffers ctx->drv.pf_glGenFramebuffers
|
|
#define glBindFramebuffer ctx->drv.pf_glBindFramebuffer
|
|
#define glFramebufferTexture2D ctx->drv.pf_glFramebufferTexture2D
|
|
#define glFramebufferRenderbuffer ctx->drv.pf_glFramebufferRenderbuffer
|
|
#define glCheckFramebufferStatus ctx->drv.pf_glCheckFramebufferStatus
|
|
#define glDeleteFramebuffers ctx->drv.pf_glDeleteFramebuffers
|
|
|
|
#endif
|
|
|
|
#ifndef GL_FRAMEBUFFER
|
|
#define GL_FRAMEBUFFER 0x8D40
|
|
#endif
|
|
#ifndef GL_RENDERBUFFER
|
|
#define GL_RENDERBUFFER 0x8D41
|
|
#endif
|
|
#ifndef GL_STENCIL_ATTACHMENT
|
|
#define GL_STENCIL_ATTACHMENT 0x8D00
|
|
#endif
|
|
#ifndef GL_COLOR_ATTACHMENT0
|
|
#define GL_COLOR_ATTACHMENT0 0x8CE0
|
|
#endif
|
|
#ifndef GL_FRAMEBUFFER_COMPLETE
|
|
#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
|
|
#endif
|
|
#ifndef GL_STENCIL_INDEX8
|
|
#define GL_STENCIL_INDEX8 0x8D48
|
|
#endif
|
|
|
|
static void _cogl_framebuffer_free (CoglFramebuffer *framebuffer);
|
|
static void _cogl_onscreen_free (CoglOnscreen *onscreen);
|
|
static void _cogl_offscreen_free (CoglOffscreen *offscreen);
|
|
|
|
COGL_HANDLE_DEFINE (Onscreen, onscreen);
|
|
COGL_HANDLE_DEFINE (Offscreen, offscreen);
|
|
|
|
/* XXX:
|
|
* The CoglHandle macros don't support any form of inheritance, so for
|
|
* now we implement the CoglHandle support for the CoglFramebuffer
|
|
* abstract class manually.
|
|
*/
|
|
|
|
gboolean
|
|
cogl_is_framebuffer (CoglHandle handle)
|
|
{
|
|
CoglHandleObject *obj = (CoglHandleObject *)handle;
|
|
|
|
if (handle == COGL_INVALID_HANDLE)
|
|
return FALSE;
|
|
|
|
return obj->klass->type == _cogl_handle_onscreen_get_type ()
|
|
|| obj->klass->type == _cogl_handle_offscreen_get_type ();
|
|
}
|
|
|
|
static void
|
|
_cogl_framebuffer_init (CoglFramebuffer *framebuffer,
|
|
CoglFramebufferType type,
|
|
int width,
|
|
int height)
|
|
{
|
|
framebuffer->type = type;
|
|
framebuffer->width = width;
|
|
framebuffer->height = height;
|
|
framebuffer->viewport_x = 0;
|
|
framebuffer->viewport_y = 0;
|
|
framebuffer->viewport_width = width;
|
|
framebuffer->viewport_height = height;
|
|
|
|
framebuffer->modelview_stack = _cogl_matrix_stack_new ();
|
|
framebuffer->projection_stack = _cogl_matrix_stack_new ();
|
|
|
|
/* Initialise the clip stack */
|
|
_cogl_clip_stack_state_init (&framebuffer->clip_state);
|
|
}
|
|
|
|
void
|
|
_cogl_framebuffer_free (CoglFramebuffer *framebuffer)
|
|
{
|
|
_cogl_clip_stack_state_destroy (&framebuffer->clip_state);
|
|
|
|
_cogl_matrix_stack_destroy (framebuffer->modelview_stack);
|
|
framebuffer->modelview_stack = NULL;
|
|
|
|
_cogl_matrix_stack_destroy (framebuffer->projection_stack);
|
|
framebuffer->projection_stack = NULL;
|
|
}
|
|
|
|
int
|
|
_cogl_framebuffer_get_width (CoglHandle handle)
|
|
{
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (handle);
|
|
return framebuffer->width;
|
|
}
|
|
|
|
int
|
|
_cogl_framebuffer_get_height (CoglHandle handle)
|
|
{
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (handle);
|
|
return framebuffer->height;
|
|
}
|
|
|
|
CoglClipStackState *
|
|
_cogl_framebuffer_get_clip_state (CoglHandle handle)
|
|
{
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (handle);
|
|
|
|
return &framebuffer->clip_state;
|
|
}
|
|
|
|
void
|
|
_cogl_framebuffer_set_viewport (CoglHandle handle,
|
|
int x,
|
|
int y,
|
|
int width,
|
|
int height)
|
|
{
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (handle);
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
if (framebuffer->viewport_x == x &&
|
|
framebuffer->viewport_y == y &&
|
|
framebuffer->viewport_width == width &&
|
|
framebuffer->viewport_height == height)
|
|
return;
|
|
|
|
_cogl_journal_flush ();
|
|
|
|
framebuffer->viewport_x = x;
|
|
framebuffer->viewport_y = y;
|
|
framebuffer->viewport_width = width;
|
|
framebuffer->viewport_height = height;
|
|
|
|
if (_cogl_get_framebuffer () == framebuffer)
|
|
ctx->dirty_gl_viewport = TRUE;
|
|
}
|
|
|
|
int
|
|
_cogl_framebuffer_get_viewport_x (CoglHandle handle)
|
|
{
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (handle);
|
|
return framebuffer->viewport_x;
|
|
}
|
|
|
|
int
|
|
_cogl_framebuffer_get_viewport_y (CoglHandle handle)
|
|
{
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (handle);
|
|
return framebuffer->viewport_y;
|
|
}
|
|
|
|
int
|
|
_cogl_framebuffer_get_viewport_width (CoglHandle handle)
|
|
{
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (handle);
|
|
return framebuffer->viewport_width;
|
|
}
|
|
|
|
int
|
|
_cogl_framebuffer_get_viewport_height (CoglHandle handle)
|
|
{
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (handle);
|
|
return framebuffer->viewport_height;
|
|
}
|
|
|
|
void
|
|
_cogl_framebuffer_get_viewport4fv (CoglHandle handle, int *viewport)
|
|
{
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (handle);
|
|
viewport[0] = framebuffer->viewport_x;
|
|
viewport[1] = framebuffer->viewport_y;
|
|
viewport[2] = framebuffer->viewport_width;
|
|
viewport[3] = framebuffer->viewport_height;
|
|
}
|
|
|
|
CoglMatrixStack *
|
|
_cogl_framebuffer_get_modelview_stack (CoglHandle handle)
|
|
{
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (handle);
|
|
return framebuffer->modelview_stack;
|
|
}
|
|
|
|
CoglMatrixStack *
|
|
_cogl_framebuffer_get_projection_stack (CoglHandle handle)
|
|
{
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (handle);
|
|
return framebuffer->projection_stack;
|
|
}
|
|
|
|
CoglHandle
|
|
cogl_offscreen_new_to_texture (CoglHandle texhandle)
|
|
{
|
|
CoglOffscreen *offscreen;
|
|
int width;
|
|
int height;
|
|
GLuint tex_gl_handle;
|
|
GLenum tex_gl_target;
|
|
GLuint fbo_gl_handle;
|
|
GLuint gl_stencil_handle;
|
|
GLenum status;
|
|
|
|
_COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
|
|
|
|
if (!cogl_features_available (COGL_FEATURE_OFFSCREEN))
|
|
return COGL_INVALID_HANDLE;
|
|
|
|
/* Make texhandle is a valid texture object */
|
|
if (!cogl_is_texture (texhandle))
|
|
return COGL_INVALID_HANDLE;
|
|
|
|
/* The texture must not be sliced */
|
|
if (cogl_texture_is_sliced (texhandle))
|
|
return COGL_INVALID_HANDLE;
|
|
|
|
/* Pick the single texture slice width, height and GL id */
|
|
|
|
width = cogl_texture_get_width (texhandle);
|
|
height = cogl_texture_get_height (texhandle);
|
|
|
|
if (!cogl_texture_get_gl_texture (texhandle, &tex_gl_handle, &tex_gl_target))
|
|
return COGL_INVALID_HANDLE;
|
|
|
|
if (tex_gl_target != GL_TEXTURE_2D
|
|
#ifdef HAVE_COGL_GL
|
|
&& tex_gl_target != GL_TEXTURE_RECTANGLE_ARB
|
|
#endif
|
|
)
|
|
return COGL_INVALID_HANDLE;
|
|
|
|
/* Create a renderbuffer for stenciling */
|
|
GE (glGenRenderbuffers (1, &gl_stencil_handle));
|
|
GE (glBindRenderbuffer (GL_RENDERBUFFER, gl_stencil_handle));
|
|
GE (glRenderbufferStorage (GL_RENDERBUFFER, GL_STENCIL_INDEX8,
|
|
cogl_texture_get_width (texhandle),
|
|
cogl_texture_get_height (texhandle)));
|
|
GE (glBindRenderbuffer (GL_RENDERBUFFER, 0));
|
|
|
|
/* We are about to generate and bind a new fbo, so when next flushing the
|
|
* journal, we will need to rebind the current framebuffer... */
|
|
ctx->dirty_bound_framebuffer = 1;
|
|
|
|
/* Generate framebuffer */
|
|
glGenFramebuffers (1, &fbo_gl_handle);
|
|
GE (glBindFramebuffer (GL_FRAMEBUFFER, fbo_gl_handle));
|
|
GE (glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
|
tex_gl_target, tex_gl_handle, 0));
|
|
GE (glFramebufferRenderbuffer (GL_FRAMEBUFFER,
|
|
GL_STENCIL_ATTACHMENT,
|
|
GL_RENDERBUFFER, gl_stencil_handle));
|
|
|
|
/* XXX: The framebuffer_object spec isn't clear in defining whether attaching
|
|
* a texture as a renderbuffer with mipmap filtering enabled while the
|
|
* mipmaps have not been uploaded should result in an incomplete framebuffer
|
|
* object. (different drivers make different decisions)
|
|
*
|
|
* To avoid an error with drivers that do consider this a problem we
|
|
* explicitly set non mipmapped filters here. These will later be reset when
|
|
* the texture is actually used for rendering according to the filters set on
|
|
* the corresponding CoglMaterial.
|
|
*/
|
|
_cogl_texture_set_filters (texhandle, GL_NEAREST, GL_NEAREST);
|
|
|
|
/* Make sure it's complete */
|
|
status = glCheckFramebufferStatus (GL_FRAMEBUFFER);
|
|
|
|
if (status != GL_FRAMEBUFFER_COMPLETE)
|
|
{
|
|
/* Stencil renderbuffers aren't always supported. Try again
|
|
without the stencil buffer */
|
|
GE (glFramebufferRenderbuffer (GL_FRAMEBUFFER,
|
|
GL_STENCIL_ATTACHMENT,
|
|
GL_RENDERBUFFER,
|
|
0));
|
|
GE (glDeleteRenderbuffers (1, &gl_stencil_handle));
|
|
gl_stencil_handle = 0;
|
|
|
|
status = glCheckFramebufferStatus (GL_FRAMEBUFFER);
|
|
|
|
if (status != GL_FRAMEBUFFER_COMPLETE)
|
|
{
|
|
/* Still failing, so give up */
|
|
GE (glDeleteFramebuffers (1, &fbo_gl_handle));
|
|
GE (glBindFramebuffer (GL_FRAMEBUFFER, 0));
|
|
return COGL_INVALID_HANDLE;
|
|
}
|
|
}
|
|
|
|
offscreen = g_new0 (CoglOffscreen, 1);
|
|
|
|
_cogl_framebuffer_init (COGL_FRAMEBUFFER (offscreen),
|
|
COGL_FRAMEBUFFER_TYPE_OFFSCREEN,
|
|
width,
|
|
height);
|
|
|
|
offscreen->fbo_handle = fbo_gl_handle;
|
|
offscreen->gl_stencil_handle = gl_stencil_handle;
|
|
offscreen->texture = cogl_handle_ref (texhandle);
|
|
|
|
/* XXX: Can we get a away with removing this? It wasn't documented, and most
|
|
* users of the API are hopefully setting up the modelview from scratch
|
|
* anyway */
|
|
#if 0
|
|
cogl_matrix_translate (&framebuffer->modelview, -1.0f, -1.0f, 0.0f);
|
|
cogl_matrix_scale (&framebuffer->modelview,
|
|
2.0f / framebuffer->width, 2.0f / framebuffer->height, 1.0f);
|
|
#endif
|
|
|
|
return _cogl_offscreen_handle_new (offscreen);
|
|
}
|
|
|
|
static void
|
|
_cogl_offscreen_free (CoglOffscreen *offscreen)
|
|
{
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
/* Chain up to parent */
|
|
_cogl_framebuffer_free (COGL_FRAMEBUFFER (offscreen));
|
|
|
|
if (offscreen->gl_stencil_handle)
|
|
GE (glDeleteRenderbuffers (1, &offscreen->gl_stencil_handle));
|
|
if (offscreen->texture != COGL_INVALID_HANDLE)
|
|
cogl_handle_unref (offscreen->texture);
|
|
GE (glDeleteFramebuffers (1, &offscreen->fbo_handle));
|
|
g_free (offscreen);
|
|
}
|
|
|
|
CoglHandle
|
|
_cogl_onscreen_new (void)
|
|
{
|
|
CoglOnscreen *onscreen;
|
|
|
|
/* XXX: Until we have full winsys support in Cogl then we can't fully
|
|
* implement CoglOnscreen framebuffers, since we can't, e.g. keep track of
|
|
* the window size. */
|
|
|
|
onscreen = g_new0 (CoglOnscreen, 1);
|
|
_cogl_framebuffer_init (COGL_FRAMEBUFFER (onscreen),
|
|
COGL_FRAMEBUFFER_TYPE_ONSCREEN,
|
|
0xdeadbeef, /* width */
|
|
0xdeadbeef); /* height */
|
|
|
|
return _cogl_onscreen_handle_new (onscreen);
|
|
}
|
|
|
|
static void
|
|
_cogl_onscreen_free (CoglOnscreen *onscreen)
|
|
{
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
/* Chain up to parent */
|
|
_cogl_framebuffer_free (COGL_FRAMEBUFFER (onscreen));
|
|
|
|
g_free (onscreen);
|
|
}
|
|
|
|
void
|
|
_cogl_onscreen_clutter_backend_set_size (int width, int height)
|
|
{
|
|
CoglFramebuffer *framebuffer;
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
framebuffer = COGL_FRAMEBUFFER (ctx->window_buffer);
|
|
|
|
if (framebuffer->width == width && framebuffer->height == height)
|
|
return;
|
|
|
|
framebuffer->width = width;
|
|
framebuffer->height = height;
|
|
|
|
/* We'll need to recalculate the GL viewport state derived
|
|
* from the Cogl viewport */
|
|
ctx->dirty_gl_viewport = 1;
|
|
}
|
|
|
|
GSList *
|
|
_cogl_create_framebuffer_stack (void)
|
|
{
|
|
GSList *stack = NULL;
|
|
|
|
return g_slist_prepend (stack, COGL_INVALID_HANDLE);
|
|
}
|
|
|
|
void
|
|
_cogl_free_framebuffer_stack (GSList *stack)
|
|
{
|
|
GSList *l;
|
|
|
|
for (l = stack; l != NULL; l = l->next)
|
|
{
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (l->data);
|
|
if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN)
|
|
_cogl_offscreen_free (COGL_OFFSCREEN (framebuffer));
|
|
else
|
|
_cogl_onscreen_free (COGL_ONSCREEN (framebuffer));
|
|
}
|
|
g_slist_free (stack);
|
|
}
|
|
|
|
/* Set the current framebuffer without checking if it's already the
|
|
* current framebuffer. This is used by cogl_pop_framebuffer while
|
|
* the top of the stack is currently not up to date. */
|
|
static void
|
|
_cogl_set_framebuffer_real (CoglFramebuffer *framebuffer)
|
|
{
|
|
CoglHandle *entry;
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
cogl_flush ();
|
|
|
|
entry = &ctx->framebuffer_stack->data;
|
|
|
|
ctx->dirty_bound_framebuffer = 1;
|
|
ctx->dirty_gl_viewport = 1;
|
|
|
|
if (framebuffer != COGL_INVALID_HANDLE)
|
|
cogl_handle_ref (framebuffer);
|
|
if (*entry != COGL_INVALID_HANDLE)
|
|
cogl_handle_unref (*entry);
|
|
|
|
*entry = framebuffer;
|
|
|
|
/* We've effectively just switched the current modelview and
|
|
* projection matrix stacks and clip state so we need to dirty
|
|
* them to ensure they get flushed for the next batch of geometry
|
|
* we flush */
|
|
_cogl_matrix_stack_dirty (framebuffer->modelview_stack);
|
|
_cogl_matrix_stack_dirty (framebuffer->projection_stack);
|
|
_cogl_clip_stack_state_dirty (&framebuffer->clip_state);
|
|
}
|
|
|
|
void
|
|
cogl_set_framebuffer (CoglHandle handle)
|
|
{
|
|
g_return_if_fail (cogl_is_framebuffer (handle));
|
|
|
|
if (_cogl_get_framebuffer () != handle)
|
|
_cogl_set_framebuffer_real (COGL_FRAMEBUFFER (handle));
|
|
}
|
|
|
|
/* XXX: deprecated API */
|
|
void
|
|
cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle handle)
|
|
{
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
if (target == COGL_WINDOW_BUFFER)
|
|
handle = ctx->window_buffer;
|
|
|
|
cogl_set_framebuffer (handle);
|
|
}
|
|
|
|
CoglHandle
|
|
_cogl_get_framebuffer (void)
|
|
{
|
|
_COGL_GET_CONTEXT (ctx, NULL);
|
|
|
|
g_assert (ctx->framebuffer_stack);
|
|
|
|
return (CoglHandle)ctx->framebuffer_stack->data;
|
|
}
|
|
|
|
void
|
|
cogl_push_framebuffer (CoglHandle buffer)
|
|
{
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
g_return_if_fail (cogl_is_framebuffer (buffer));
|
|
g_assert (ctx->framebuffer_stack);
|
|
|
|
cogl_flush ();
|
|
|
|
ctx->framebuffer_stack =
|
|
g_slist_prepend (ctx->framebuffer_stack, COGL_INVALID_HANDLE);
|
|
|
|
cogl_set_framebuffer (buffer);
|
|
}
|
|
|
|
/* XXX: deprecated API */
|
|
void
|
|
cogl_push_draw_buffer (void)
|
|
{
|
|
cogl_push_framebuffer (_cogl_get_framebuffer ());
|
|
}
|
|
|
|
void
|
|
cogl_pop_framebuffer (void)
|
|
{
|
|
CoglHandle to_pop;
|
|
CoglHandle to_restore;
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
g_assert (ctx->framebuffer_stack != NULL);
|
|
g_assert (ctx->framebuffer_stack->next != NULL);
|
|
|
|
to_pop = ctx->framebuffer_stack->data;
|
|
to_restore = ctx->framebuffer_stack->next->data;
|
|
|
|
cogl_flush ();
|
|
|
|
cogl_handle_unref (to_pop);
|
|
ctx->framebuffer_stack =
|
|
g_slist_remove_link (ctx->framebuffer_stack,
|
|
ctx->framebuffer_stack);
|
|
|
|
/* If the framebuffer has changed as a result of popping the top
|
|
* then re-assert the current buffer so as to dirty state as
|
|
* necessary. */
|
|
if (to_pop != to_restore)
|
|
_cogl_set_framebuffer_real (to_restore);
|
|
}
|
|
|
|
/* XXX: deprecated API */
|
|
void
|
|
cogl_pop_draw_buffer (void)
|
|
{
|
|
cogl_pop_framebuffer ();
|
|
}
|
|
|
|
void
|
|
_cogl_framebuffer_flush_state (CoglHandle handle,
|
|
CoglFramebufferFlushFlags flags)
|
|
{
|
|
CoglFramebuffer *framebuffer;
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
framebuffer = COGL_FRAMEBUFFER (handle);
|
|
|
|
if (cogl_features_available (COGL_FEATURE_OFFSCREEN) &&
|
|
ctx->dirty_bound_framebuffer)
|
|
{
|
|
if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN)
|
|
{
|
|
GE (glBindFramebuffer (GL_FRAMEBUFFER,
|
|
COGL_OFFSCREEN (framebuffer)->fbo_handle));
|
|
}
|
|
else
|
|
GE (glBindFramebuffer (GL_FRAMEBUFFER, 0));
|
|
ctx->dirty_bound_framebuffer = FALSE;
|
|
}
|
|
|
|
if (ctx->dirty_gl_viewport)
|
|
{
|
|
int gl_viewport_y;
|
|
|
|
/* Convert the Cogl viewport y offset to an OpenGL viewport y offset
|
|
* NB: OpenGL defines its window and viewport origins to be bottom
|
|
* left, while Cogl defines them to be top left.
|
|
* NB: We render upside down to offscreen framebuffers so we don't
|
|
* need to convert the y offset in this case. */
|
|
if (cogl_is_offscreen (framebuffer))
|
|
gl_viewport_y = framebuffer->viewport_y;
|
|
else
|
|
gl_viewport_y = framebuffer->height -
|
|
(framebuffer->viewport_y + framebuffer->viewport_height);
|
|
|
|
GE (glViewport (framebuffer->viewport_x,
|
|
gl_viewport_y,
|
|
framebuffer->viewport_width,
|
|
framebuffer->viewport_height));
|
|
ctx->dirty_gl_viewport = FALSE;
|
|
}
|
|
|
|
/* XXX: Flushing clip state may trash the modelview and projection
|
|
* matrices so we must do it before flushing the matrices...
|
|
*/
|
|
_cogl_flush_clip_state (&framebuffer->clip_state);
|
|
|
|
if (!(flags & COGL_FRAMEBUFFER_FLUSH_SKIP_MODELVIEW))
|
|
_cogl_matrix_stack_flush_to_gl (framebuffer->modelview_stack,
|
|
COGL_MATRIX_MODELVIEW);
|
|
|
|
_cogl_matrix_stack_flush_to_gl (framebuffer->projection_stack,
|
|
COGL_MATRIX_PROJECTION);
|
|
}
|
|
|