2009-09-25 13:34:34 +00:00
|
|
|
/*
|
|
|
|
* 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-draw-buffer-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_draw_buffer_free (CoglDrawBuffer *draw_buffer);
|
|
|
|
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 CoglDrawBuffer
|
|
|
|
* abstract class manually.
|
|
|
|
*/
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
cogl_is_draw_buffer (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_draw_buffer_init (CoglDrawBuffer *draw_buffer,
|
|
|
|
CoglDrawBufferType type,
|
|
|
|
int width,
|
|
|
|
int height)
|
|
|
|
{
|
|
|
|
draw_buffer->type = type;
|
|
|
|
draw_buffer->width = width;
|
|
|
|
draw_buffer->height = height;
|
|
|
|
draw_buffer->viewport_x = 0;
|
|
|
|
draw_buffer->viewport_y = 0;
|
|
|
|
draw_buffer->viewport_width = width;
|
|
|
|
draw_buffer->viewport_height = height;
|
|
|
|
|
|
|
|
draw_buffer->modelview_stack = _cogl_matrix_stack_new ();
|
|
|
|
draw_buffer->projection_stack = _cogl_matrix_stack_new ();
|
|
|
|
|
|
|
|
/* Initialise the clip stack */
|
|
|
|
_cogl_clip_stack_state_init (&draw_buffer->clip_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_draw_buffer_free (CoglDrawBuffer *draw_buffer)
|
|
|
|
{
|
|
|
|
_cogl_clip_stack_state_destroy (&draw_buffer->clip_state);
|
|
|
|
|
|
|
|
_cogl_matrix_stack_destroy (draw_buffer->modelview_stack);
|
|
|
|
draw_buffer->modelview_stack = NULL;
|
|
|
|
|
|
|
|
_cogl_matrix_stack_destroy (draw_buffer->projection_stack);
|
|
|
|
draw_buffer->projection_stack = NULL;
|
|
|
|
}
|
|
|
|
|
2009-10-21 22:20:44 +00:00
|
|
|
int
|
|
|
|
_cogl_draw_buffer_get_width (CoglHandle handle)
|
|
|
|
{
|
|
|
|
CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
|
|
|
|
return draw_buffer->width;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
_cogl_draw_buffer_get_height (CoglHandle handle)
|
|
|
|
{
|
|
|
|
CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
|
|
|
|
return draw_buffer->height;
|
|
|
|
}
|
|
|
|
|
2009-09-25 13:34:34 +00:00
|
|
|
CoglClipStackState *
|
|
|
|
_cogl_draw_buffer_get_clip_state (CoglHandle handle)
|
|
|
|
{
|
|
|
|
CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
|
|
|
|
|
|
|
|
return &draw_buffer->clip_state;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_draw_buffer_set_viewport (CoglHandle handle,
|
|
|
|
int x,
|
|
|
|
int y,
|
|
|
|
int width,
|
|
|
|
int height)
|
|
|
|
{
|
|
|
|
CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
|
|
|
|
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
|
|
|
|
if (draw_buffer->viewport_x == x &&
|
|
|
|
draw_buffer->viewport_y == y &&
|
|
|
|
draw_buffer->viewport_width == width &&
|
|
|
|
draw_buffer->viewport_height == height)
|
|
|
|
return;
|
|
|
|
|
|
|
|
_cogl_journal_flush ();
|
|
|
|
|
|
|
|
draw_buffer->viewport_x = x;
|
|
|
|
draw_buffer->viewport_y = y;
|
|
|
|
draw_buffer->viewport_width = width;
|
|
|
|
draw_buffer->viewport_height = height;
|
|
|
|
|
|
|
|
if (_cogl_get_draw_buffer () == draw_buffer)
|
2009-10-21 22:24:49 +00:00
|
|
|
ctx->dirty_gl_viewport = TRUE;
|
2009-09-25 13:34:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
_cogl_draw_buffer_get_viewport_x (CoglHandle handle)
|
|
|
|
{
|
|
|
|
CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
|
|
|
|
return draw_buffer->viewport_x;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
_cogl_draw_buffer_get_viewport_y (CoglHandle handle)
|
|
|
|
{
|
|
|
|
CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
|
|
|
|
return draw_buffer->viewport_y;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
_cogl_draw_buffer_get_viewport_width (CoglHandle handle)
|
|
|
|
{
|
|
|
|
CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
|
|
|
|
return draw_buffer->viewport_width;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
_cogl_draw_buffer_get_viewport_height (CoglHandle handle)
|
|
|
|
{
|
|
|
|
CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
|
|
|
|
return draw_buffer->viewport_height;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_draw_buffer_get_viewport4fv (CoglHandle handle, int *viewport)
|
|
|
|
{
|
|
|
|
CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
|
|
|
|
viewport[0] = draw_buffer->viewport_x;
|
|
|
|
viewport[1] = draw_buffer->viewport_y;
|
|
|
|
viewport[2] = draw_buffer->viewport_width;
|
|
|
|
viewport[3] = draw_buffer->viewport_height;
|
|
|
|
}
|
|
|
|
|
|
|
|
CoglMatrixStack *
|
|
|
|
_cogl_draw_buffer_get_modelview_stack (CoglHandle handle)
|
|
|
|
{
|
|
|
|
CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
|
|
|
|
return draw_buffer->modelview_stack;
|
|
|
|
}
|
|
|
|
|
|
|
|
CoglMatrixStack *
|
|
|
|
_cogl_draw_buffer_get_projection_stack (CoglHandle handle)
|
|
|
|
{
|
|
|
|
CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
|
|
|
|
return draw_buffer->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)
|
|
|
|
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 draw buffer... */
|
|
|
|
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_draw_buffer_init (COGL_DRAW_BUFFER (offscreen),
|
|
|
|
COGL_DRAW_BUFFER_TYPE_OFFSCREEN,
|
|
|
|
width,
|
|
|
|
height);
|
|
|
|
|
|
|
|
offscreen->fbo_handle = fbo_gl_handle;
|
|
|
|
offscreen->gl_stencil_handle = gl_stencil_handle;
|
|
|
|
|
|
|
|
/* 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 (&draw_buffer->modelview, -1.0f, -1.0f, 0.0f);
|
|
|
|
cogl_matrix_scale (&draw_buffer->modelview,
|
|
|
|
2.0f / draw_buffer->width, 2.0f / draw_buffer->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_draw_buffer_free (COGL_DRAW_BUFFER (offscreen));
|
|
|
|
|
|
|
|
if (offscreen->gl_stencil_handle)
|
|
|
|
GE (glDeleteRenderbuffers (1, &offscreen->gl_stencil_handle));
|
|
|
|
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 draw buffers, since we can't, e.g. keep track of
|
|
|
|
* the window size. */
|
|
|
|
|
|
|
|
onscreen = g_new0 (CoglOnscreen, 1);
|
|
|
|
_cogl_draw_buffer_init (COGL_DRAW_BUFFER (onscreen),
|
|
|
|
COGL_DRAW_BUFFER_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_draw_buffer_free (COGL_DRAW_BUFFER (onscreen));
|
|
|
|
|
|
|
|
g_free (onscreen);
|
|
|
|
}
|
|
|
|
|
2009-10-21 22:24:49 +00:00
|
|
|
void
|
|
|
|
_cogl_onscreen_clutter_backend_set_size (int width, int height)
|
|
|
|
{
|
|
|
|
CoglDrawBuffer *draw_buffer;
|
|
|
|
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
|
|
|
|
draw_buffer = COGL_DRAW_BUFFER (ctx->window_buffer);
|
|
|
|
|
|
|
|
if (draw_buffer->width == width && draw_buffer->height == height)
|
|
|
|
return;
|
|
|
|
|
|
|
|
draw_buffer->width = width;
|
|
|
|
draw_buffer->height = height;
|
|
|
|
|
|
|
|
/* We'll need to recalculate the GL viewport state derived
|
|
|
|
* from the Cogl viewport */
|
|
|
|
ctx->dirty_gl_viewport = 1;
|
|
|
|
}
|
|
|
|
|
2009-09-25 13:34:34 +00:00
|
|
|
GSList *
|
|
|
|
_cogl_create_draw_buffer_stack (void)
|
|
|
|
{
|
|
|
|
GSList *stack = NULL;
|
|
|
|
CoglDrawBufferStackEntry *entry;
|
|
|
|
|
|
|
|
entry = g_slice_new0 (CoglDrawBufferStackEntry);
|
|
|
|
entry->target = COGL_WINDOW_BUFFER;
|
|
|
|
entry->draw_buffer = COGL_INVALID_HANDLE;
|
|
|
|
|
|
|
|
return g_slist_prepend (stack, entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_free_draw_buffer_stack (GSList *stack)
|
|
|
|
{
|
|
|
|
GSList *l;
|
|
|
|
|
|
|
|
for (l = stack; l != NULL; l = l->next)
|
|
|
|
{
|
|
|
|
CoglDrawBufferStackEntry *entry = l->data;
|
|
|
|
CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (entry->draw_buffer);
|
|
|
|
if (draw_buffer->type == COGL_DRAW_BUFFER_TYPE_OFFSCREEN)
|
|
|
|
_cogl_offscreen_free (COGL_OFFSCREEN (draw_buffer));
|
|
|
|
else
|
|
|
|
_cogl_onscreen_free (COGL_ONSCREEN (draw_buffer));
|
|
|
|
}
|
|
|
|
g_slist_free (stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX: The target argument is redundant; when we break API, we should
|
|
|
|
* remove it! */
|
|
|
|
void
|
|
|
|
cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle handle)
|
|
|
|
{
|
|
|
|
CoglDrawBuffer *draw_buffer = NULL;
|
|
|
|
CoglDrawBufferStackEntry *entry;
|
|
|
|
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
|
|
|
|
_cogl_journal_flush ();
|
|
|
|
|
|
|
|
g_assert (ctx->draw_buffer_stack != NULL);
|
|
|
|
entry = ctx->draw_buffer_stack->data;
|
|
|
|
|
|
|
|
if (target == COGL_WINDOW_BUFFER)
|
|
|
|
handle = ctx->window_buffer;
|
|
|
|
else if (!cogl_is_draw_buffer (handle))
|
|
|
|
return;
|
|
|
|
|
|
|
|
draw_buffer = COGL_DRAW_BUFFER (handle);
|
|
|
|
|
|
|
|
if (entry->draw_buffer != draw_buffer)
|
|
|
|
{
|
|
|
|
entry->target = target;
|
|
|
|
|
|
|
|
ctx->dirty_bound_framebuffer = 1;
|
2009-10-21 22:24:49 +00:00
|
|
|
ctx->dirty_gl_viewport = 1;
|
2009-09-25 13:34:34 +00:00
|
|
|
|
|
|
|
if (draw_buffer != COGL_INVALID_HANDLE)
|
|
|
|
cogl_handle_ref (draw_buffer);
|
|
|
|
if (entry->draw_buffer != COGL_INVALID_HANDLE)
|
|
|
|
cogl_handle_unref (entry->draw_buffer);
|
|
|
|
entry->draw_buffer = draw_buffer;
|
|
|
|
|
|
|
|
/* 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 (draw_buffer->modelview_stack);
|
|
|
|
_cogl_matrix_stack_dirty (draw_buffer->projection_stack);
|
|
|
|
_cogl_clip_stack_state_dirty (&draw_buffer->clip_state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CoglHandle
|
|
|
|
_cogl_get_draw_buffer (void)
|
|
|
|
{
|
|
|
|
CoglDrawBufferStackEntry *entry;
|
|
|
|
|
|
|
|
_COGL_GET_CONTEXT (ctx, NULL);
|
|
|
|
|
|
|
|
g_assert (ctx->draw_buffer_stack);
|
|
|
|
entry = ctx->draw_buffer_stack->data;
|
|
|
|
|
|
|
|
return entry->draw_buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cogl_push_draw_buffer (void)
|
|
|
|
{
|
|
|
|
CoglDrawBufferStackEntry *old;
|
|
|
|
CoglDrawBufferStackEntry *entry;
|
|
|
|
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
|
|
|
|
entry = g_slice_new0 (CoglDrawBufferStackEntry);
|
|
|
|
|
|
|
|
g_assert (ctx->draw_buffer_stack);
|
|
|
|
|
|
|
|
old = ctx->draw_buffer_stack->data;
|
|
|
|
*entry = *old;
|
|
|
|
|
|
|
|
cogl_handle_ref (entry->draw_buffer);
|
|
|
|
|
|
|
|
ctx->draw_buffer_stack =
|
|
|
|
g_slist_prepend (ctx->draw_buffer_stack, entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cogl_pop_draw_buffer (void)
|
|
|
|
{
|
|
|
|
CoglDrawBufferStackEntry *to_pop;
|
|
|
|
CoglDrawBufferStackEntry *to_restore;
|
|
|
|
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
|
|
|
|
g_assert (ctx->draw_buffer_stack != NULL);
|
|
|
|
|
|
|
|
to_pop = ctx->draw_buffer_stack->data;
|
|
|
|
to_restore = ctx->draw_buffer_stack->next->data;
|
|
|
|
|
|
|
|
cogl_set_draw_buffer (to_restore->target, to_restore->draw_buffer);
|
|
|
|
|
|
|
|
cogl_handle_unref (to_pop->draw_buffer);
|
|
|
|
ctx->draw_buffer_stack =
|
|
|
|
g_slist_remove_link (ctx->draw_buffer_stack,
|
|
|
|
ctx->draw_buffer_stack);
|
|
|
|
g_slice_free (CoglDrawBufferStackEntry, to_pop);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_draw_buffer_flush_state (CoglHandle handle,
|
|
|
|
CoglDrawBufferFlushFlags flags)
|
|
|
|
{
|
|
|
|
CoglDrawBuffer *draw_buffer;
|
|
|
|
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
|
|
|
|
draw_buffer = COGL_DRAW_BUFFER (handle);
|
|
|
|
|
|
|
|
if (cogl_features_available (COGL_FEATURE_OFFSCREEN) &&
|
|
|
|
ctx->dirty_bound_framebuffer)
|
|
|
|
{
|
|
|
|
if (draw_buffer->type == COGL_DRAW_BUFFER_TYPE_OFFSCREEN)
|
|
|
|
{
|
|
|
|
GE (glBindFramebuffer (GL_FRAMEBUFFER,
|
|
|
|
COGL_OFFSCREEN (draw_buffer)->fbo_handle));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
GE (glBindFramebuffer (GL_FRAMEBUFFER, 0));
|
|
|
|
ctx->dirty_bound_framebuffer = FALSE;
|
|
|
|
}
|
|
|
|
|
2009-10-21 22:24:49 +00:00
|
|
|
if (ctx->dirty_gl_viewport)
|
2009-09-25 13:34:34 +00:00
|
|
|
{
|
2009-10-31 00:00:33 +00:00
|
|
|
int gl_viewport_y;
|
|
|
|
|
2009-10-21 22:24:49 +00:00
|
|
|
/* Convert the Cogl viewport y offset to an OpenGL viewport y offset
|
2009-10-31 00:00:33 +00:00
|
|
|
* 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 draw buffers so we don't
|
|
|
|
* need to convert the y offset in this case. */
|
|
|
|
if (cogl_is_offscreen (draw_buffer))
|
|
|
|
gl_viewport_y = draw_buffer->viewport_y;
|
|
|
|
else
|
|
|
|
gl_viewport_y = draw_buffer->height -
|
|
|
|
(draw_buffer->viewport_y + draw_buffer->viewport_height);
|
2009-10-21 22:24:49 +00:00
|
|
|
|
2009-09-25 13:34:34 +00:00
|
|
|
GE (glViewport (draw_buffer->viewport_x,
|
2009-10-21 22:24:49 +00:00
|
|
|
gl_viewport_y,
|
2009-09-25 13:34:34 +00:00
|
|
|
draw_buffer->viewport_width,
|
|
|
|
draw_buffer->viewport_height));
|
2009-10-21 22:24:49 +00:00
|
|
|
ctx->dirty_gl_viewport = FALSE;
|
2009-09-25 13:34:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX: Flushing clip state may trash the modelview and projection
|
|
|
|
* matrices so we must do it before flushing the matrices...
|
|
|
|
*/
|
|
|
|
_cogl_flush_clip_state (&draw_buffer->clip_state);
|
|
|
|
|
|
|
|
if (!(flags & COGL_DRAW_BUFFER_FLUSH_SKIP_MODELVIEW))
|
|
|
|
_cogl_matrix_stack_flush_to_gl (draw_buffer->modelview_stack,
|
|
|
|
COGL_MATRIX_MODELVIEW);
|
|
|
|
|
|
|
|
_cogl_matrix_stack_flush_to_gl (draw_buffer->projection_stack,
|
|
|
|
COGL_MATRIX_PROJECTION);
|
|
|
|
}
|
|
|
|
|