From ce5d06afe1d4f890fb11b885cfeabf253c466a51 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Sat, 1 Sep 2012 00:04:00 +0100 Subject: [PATCH] framebuffer: split GL code out from cogl-framebuffer.c This splits out most of the OpenGL specific code from cogl-framebuffer.c into cogl-framebuffer-gl.c and extends the CoglDriverVtable interface for cogl-framebuffer.c to use. There are hopes to support several different backends for Cogl eventually to hopefully get us closer to the metal so this makes some progress in organizing which parts of Cogl are OpenGL specific so these parts can potentially be switched out later. The only remaining use of OpenGL still in cogl-framebuffer.c is to handle cogl_framebuffer_read_pixels. --- cogl/Makefile.am | 2 + cogl/cogl-context.c | 33 +- cogl/cogl-driver.h | 57 ++ cogl/cogl-framebuffer-gl-private.h | 91 +++ cogl/cogl-framebuffer-gl.c | 1091 ++++++++++++++++++++++++++++ cogl/cogl-framebuffer-private.h | 40 +- cogl/cogl-framebuffer.c | 1083 ++------------------------- cogl/cogl-gles2-context.c | 9 +- cogl/cogl-renderer-private.h | 4 + cogl/cogl-renderer.c | 30 + cogl/driver/gl/cogl-gl.c | 12 +- cogl/driver/gles/cogl-gles.c | 12 +- 12 files changed, 1403 insertions(+), 1061 deletions(-) create mode 100644 cogl/cogl-framebuffer-gl-private.h create mode 100644 cogl/cogl-framebuffer-gl.c diff --git a/cogl/Makefile.am b/cogl/Makefile.am index a73d3f854..2639a06d6 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -382,6 +382,8 @@ cogl_sources_c = \ $(srcdir)/cogl-magazine.c \ $(srcdir)/cogl-gles2-context-private.h \ $(srcdir)/cogl-gles2-context.c \ + $(srcdir)/cogl-framebuffer-gl-private.h \ + $(srcdir)/cogl-framebuffer-gl.c \ $(NULL) if USE_GLIB diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c index f14846444..9a02a409c 100644 --- a/cogl/cogl-context.c +++ b/cogl/cogl-context.c @@ -61,15 +61,6 @@ #define GL_POINT_SPRITE 0x8861 #endif -#ifdef HAVE_COGL_GL -extern const CoglTextureDriver _cogl_texture_driver_gl; -extern const CoglDriverVtable _cogl_driver_gl; -#endif -#if defined (HAVE_COGL_GLES) || defined (HAVE_COGL_GLES2) -extern const CoglTextureDriver _cogl_texture_driver_gles; -extern const CoglDriverVtable _cogl_driver_gles; -#endif - static void _cogl_context_free (CoglContext *context); COGL_OBJECT_DEFINE (Context, context); @@ -216,26 +207,10 @@ cogl_context_new (CoglDisplay *display, lot throughout Cogl */ context->driver = display->renderer->driver; - switch (context->driver) - { -#ifdef HAVE_COGL_GL - case COGL_DRIVER_GL: - context->driver_vtable = &_cogl_driver_gl; - context->texture_driver = &_cogl_texture_driver_gl; - break; -#endif - -#if defined (HAVE_COGL_GLES) || defined (HAVE_COGL_GLES2) - case COGL_DRIVER_GLES1: - case COGL_DRIVER_GLES2: - context->driver_vtable = &_cogl_driver_gles; - context->texture_driver = &_cogl_texture_driver_gles; - break; -#endif - - default: - g_assert_not_reached (); - } + /* Again this is duplicated data, but it convenient to be able + * access these from the context. */ + context->driver_vtable = display->renderer->driver_vtable; + context->texture_driver = display->renderer->texture_driver; winsys = _cogl_context_get_winsys (context); if (!winsys->context_init (context, error)) diff --git a/cogl/cogl-driver.h b/cogl/cogl-driver.h index e22439a34..7b82628dd 100644 --- a/cogl/cogl-driver.h +++ b/cogl/cogl-driver.h @@ -25,6 +25,8 @@ #define __COGL_DRIVER_H #include "cogl-context.h" +#include "cogl-offscreen.h" +#include "cogl-framebuffer-private.h" typedef struct _CoglDriverVtable CoglDriverVtable; @@ -45,6 +47,61 @@ struct _CoglDriverVtable CoglBool (* update_features) (CoglContext *context, GError **error); + + CoglBool + (* offscreen_allocate) (CoglOffscreen *offscreen, + GError **error); + + void + (* offscreen_free) (CoglOffscreen *offscreen); + + void + (* framebuffer_flush_state) (CoglFramebuffer *draw_buffer, + CoglFramebuffer *read_buffer, + CoglFramebufferState state); + + void + (* framebuffer_clear) (CoglFramebuffer *framebuffer, + unsigned long buffers, + float red, + float green, + float blue, + float alpha); + + void + (* framebuffer_query_bits) (CoglFramebuffer *framebuffer, + int *red, + int *green, + int *blue, + int *alpha); + + void + (* framebuffer_finish) (CoglFramebuffer *framebuffer); + + void + (* framebuffer_discard_buffers) (CoglFramebuffer *framebuffer, + unsigned long buffers); + + void + (* framebuffer_draw_attributes) (CoglFramebuffer *framebuffer, + CoglPipeline *pipeline, + CoglVerticesMode mode, + int first_vertex, + int n_vertices, + CoglAttribute **attributes, + int n_attributes, + CoglDrawFlags flags); + + void + (* framebuffer_draw_indexed_attributes) (CoglFramebuffer *framebuffer, + CoglPipeline *pipeline, + CoglVerticesMode mode, + int first_vertex, + int n_vertices, + CoglIndices *indices, + CoglAttribute **attributes, + int n_attributes, + CoglDrawFlags flags); }; #endif /* __COGL_DRIVER_H */ diff --git a/cogl/cogl-framebuffer-gl-private.h b/cogl/cogl-framebuffer-gl-private.h new file mode 100644 index 000000000..4a616a156 --- /dev/null +++ b/cogl/cogl-framebuffer-gl-private.h @@ -0,0 +1,91 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2008,2009,2010,2011 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, see + * . + * + * + * + * Authors: + * Robert Bragg + */ + +#ifndef __COGL_FRAMEBUFFER_GL_PRIVATE_H__ +#define __COGL_FRAMEBUFFER_GL_PRIVATE_H__ + +CoglBool +_cogl_offscreen_gl_allocate (CoglOffscreen *offscreen, + GError **error); + +void +_cogl_offscreen_gl_free (CoglOffscreen *offscreen); + +void +_cogl_framebuffer_gl_flush_state (CoglFramebuffer *draw_buffer, + CoglFramebuffer *read_buffer, + CoglFramebufferState state); + +void +_cogl_framebuffer_gl_clear (CoglFramebuffer *framebuffer, + unsigned long buffers, + float red, + float green, + float blue, + float alpha); + +void +_cogl_framebuffer_gl_query_bits (CoglFramebuffer *framebuffer, + int *red, + int *green, + int *blue, + int *alpha); + +void +_cogl_framebuffer_gl_finish (CoglFramebuffer *framebuffer); + +void +_cogl_framebuffer_gl_discard_buffers (CoglFramebuffer *framebuffer, + unsigned long buffers); + +void +_cogl_framebuffer_gl_bind (CoglFramebuffer *framebuffer, GLenum target); + +void +_cogl_framebuffer_gl_draw_attributes (CoglFramebuffer *framebuffer, + CoglPipeline *pipeline, + CoglVerticesMode mode, + int first_vertex, + int n_vertices, + CoglAttribute **attributes, + int n_attributes, + CoglDrawFlags flags); + +void +_cogl_framebuffer_gl_draw_indexed_attributes (CoglFramebuffer *framebuffer, + CoglPipeline *pipeline, + CoglVerticesMode mode, + int first_vertex, + int n_vertices, + CoglIndices *indices, + CoglAttribute **attributes, + int n_attributes, + CoglDrawFlags flags); + +#endif /* __COGL_FRAMEBUFFER_GL_PRIVATE_H__ */ + + diff --git a/cogl/cogl-framebuffer-gl.c b/cogl/cogl-framebuffer-gl.c new file mode 100644 index 000000000..38ef260b2 --- /dev/null +++ b/cogl/cogl-framebuffer-gl.c @@ -0,0 +1,1091 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2007,2008,2009,2012 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, see + * . + * + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cogl-context-private.h" +#include "cogl-framebuffer-private.h" +#include "cogl-framebuffer-gl-private.h" + +#include + +#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 +#ifndef GL_DEPTH_STENCIL +#define GL_DEPTH_STENCIL 0x84F9 +#endif +#ifndef GL_DEPTH24_STENCIL8 +#define GL_DEPTH24_STENCIL8 0x88F0 +#endif +#ifndef GL_DEPTH_ATTACHMENT +#define GL_DEPTH_ATTACHMENT 0x8D00 +#endif +#ifndef GL_DEPTH_COMPONENT16 +#define GL_DEPTH_COMPONENT16 0x81A5 +#endif +#ifndef GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE +#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 +#endif +#ifndef GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE +#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 +#endif +#ifndef GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE +#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 +#endif +#ifndef GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE +#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 +#endif +#ifndef GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE +#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 +#endif +#ifndef GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE +#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 +#endif +#ifndef GL_READ_FRAMEBUFFER +#define GL_READ_FRAMEBUFFER 0x8CA8 +#endif +#ifndef GL_DRAW_FRAMEBUFFER +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#endif +#ifndef GL_TEXTURE_SAMPLES_IMG +#define GL_TEXTURE_SAMPLES_IMG 0x9136 +#endif +#ifndef GL_PACK_INVERT_MESA +#define GL_PACK_INVERT_MESA 0x8758 +#endif + +static void +_cogl_framebuffer_gl_flush_viewport_state (CoglFramebuffer *framebuffer) +{ + float gl_viewport_y; + + g_assert (framebuffer->viewport_width >=0 && + framebuffer->viewport_height >=0); + + /* 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); + + COGL_NOTE (OPENGL, "Calling glViewport(%f, %f, %f, %f)", + framebuffer->viewport_x, + gl_viewport_y, + framebuffer->viewport_width, + framebuffer->viewport_height); + + GE (framebuffer->context, + glViewport (framebuffer->viewport_x, + gl_viewport_y, + framebuffer->viewport_width, + framebuffer->viewport_height)); +} + +static void +_cogl_framebuffer_gl_flush_clip_state (CoglFramebuffer *framebuffer) +{ + CoglClipStack *stack = _cogl_clip_state_get_stack (&framebuffer->clip_state); + _cogl_clip_stack_flush (stack, framebuffer); +} + +static void +_cogl_framebuffer_gl_flush_dither_state (CoglFramebuffer *framebuffer) +{ + CoglContext *ctx = framebuffer->context; + + if (ctx->current_gl_dither_enabled != framebuffer->dither_enabled) + { + if (framebuffer->dither_enabled) + GE (ctx, glEnable (GL_DITHER)); + else + GE (ctx, glDisable (GL_DITHER)); + ctx->current_gl_dither_enabled = framebuffer->dither_enabled; + } +} + +static void +_cogl_framebuffer_gl_flush_modelview_state (CoglFramebuffer *framebuffer) +{ + CoglMatrixEntry *modelview_entry = + _cogl_framebuffer_get_modelview_entry (framebuffer); + _cogl_context_set_current_modelview_entry (framebuffer->context, + modelview_entry); +} + +static void +_cogl_framebuffer_gl_flush_projection_state (CoglFramebuffer *framebuffer) +{ + CoglMatrixEntry *projection_entry = + _cogl_framebuffer_get_projection_entry (framebuffer); + _cogl_context_set_current_projection_entry (framebuffer->context, + projection_entry); +} + +static void +_cogl_framebuffer_gl_flush_color_mask_state (CoglFramebuffer *framebuffer) +{ + CoglContext *context = framebuffer->context; + + /* The color mask state is really owned by a CoglPipeline so to + * ensure the color mask is updated the next time we draw something + * we need to make sure the logic ops for the pipeline are + * re-flushed... */ + context->current_pipeline_changes_since_flush |= + COGL_PIPELINE_STATE_LOGIC_OPS; + context->current_pipeline_age--; +} + +static void +_cogl_framebuffer_gl_flush_front_face_winding_state (CoglFramebuffer *framebuffer) +{ + CoglContext *context = framebuffer->context; + CoglPipelineCullFaceMode mode; + + /* NB: The face winding state is actually owned by the current + * CoglPipeline. + * + * If we don't have a current pipeline then we can just assume that + * when we later do flush a pipeline we will check the current + * framebuffer to know how to setup the winding */ + if (!context->current_pipeline) + return; + + mode = cogl_pipeline_get_cull_face_mode (context->current_pipeline); + + /* If the current CoglPipeline has a culling mode that doesn't care + * about the winding we can avoid forcing an update of the state and + * bail out. */ + if (mode == COGL_PIPELINE_CULL_FACE_MODE_NONE || + mode == COGL_PIPELINE_CULL_FACE_MODE_BOTH) + return; + + /* Since the winding state is really owned by the current pipeline + * the way we "flush" an updated winding is to dirty the pipeline + * state... */ + context->current_pipeline_changes_since_flush |= + COGL_PIPELINE_STATE_CULL_FACE; + context->current_pipeline_age--; +} + +void +_cogl_framebuffer_gl_bind (CoglFramebuffer *framebuffer, GLenum target) +{ + CoglContext *ctx = framebuffer->context; + + if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN) + { + CoglOffscreen *offscreen = COGL_OFFSCREEN (framebuffer); + GE (ctx, glBindFramebuffer (target, + offscreen->gl_framebuffer.fbo_handle)); + } + else + { + const CoglWinsysVtable *winsys = + _cogl_framebuffer_get_winsys (framebuffer); + winsys->onscreen_bind (COGL_ONSCREEN (framebuffer)); + /* glBindFramebuffer is an an extension with OpenGL ES 1.1 */ + if (cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) + GE (ctx, glBindFramebuffer (target, 0)); + } +} + +void +_cogl_framebuffer_gl_flush_state (CoglFramebuffer *draw_buffer, + CoglFramebuffer *read_buffer, + CoglFramebufferState state) +{ + CoglContext *ctx = draw_buffer->context; + unsigned long differences; + int bit; + + /* We can assume that any state that has changed for the current + * framebuffer is different to the currently flushed value. */ + differences = ctx->current_draw_buffer_changes; + + /* Any state of the current framebuffer that hasn't already been + * flushed is assumed to be unknown so we will always flush that + * state if asked. */ + differences |= ~ctx->current_draw_buffer_state_flushed; + + /* We only need to consider the state we've been asked to flush */ + differences &= state; + + if (ctx->current_draw_buffer != draw_buffer) + { + /* If the previous draw buffer is NULL then we'll assume + everything has changed. This can happen if a framebuffer is + destroyed while it is the last flushed draw buffer. In that + case the framebuffer destructor will set + ctx->current_draw_buffer to NULL */ + if (ctx->current_draw_buffer == NULL) + differences |= state; + else + /* NB: we only need to compare the state we're being asked to flush + * and we don't need to compare the state we've already decided + * we will definitely flush... */ + differences |= _cogl_framebuffer_compare (ctx->current_draw_buffer, + draw_buffer, + state & ~differences); + + /* NB: we don't take a reference here, to avoid a circular + * reference. */ + ctx->current_draw_buffer = draw_buffer; + ctx->current_draw_buffer_state_flushed = 0; + } + + if (ctx->current_read_buffer != read_buffer && + state & COGL_FRAMEBUFFER_STATE_BIND) + { + differences |= COGL_FRAMEBUFFER_STATE_BIND; + /* NB: we don't take a reference here, to avoid a circular + * reference. */ + ctx->current_read_buffer = read_buffer; + } + + if (!differences) + return; + + /* Lazily ensure the framebuffers have been allocated */ + if (G_UNLIKELY (!draw_buffer->allocated)) + cogl_framebuffer_allocate (draw_buffer, NULL); + if (G_UNLIKELY (!read_buffer->allocated)) + cogl_framebuffer_allocate (read_buffer, NULL); + + /* We handle buffer binding separately since the method depends on whether + * we are binding the same buffer for read and write or not unlike all + * other state that only relates to the draw_buffer. */ + if (differences & COGL_FRAMEBUFFER_STATE_BIND) + { + if (draw_buffer == read_buffer) + _cogl_framebuffer_gl_bind (draw_buffer, GL_FRAMEBUFFER); + else + { + /* NB: Currently we only take advantage of binding separate + * read/write buffers for offscreen framebuffer blit + * purposes. */ + _COGL_RETURN_IF_FAIL (ctx->private_feature_flags & + COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT); + _COGL_RETURN_IF_FAIL (draw_buffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN); + _COGL_RETURN_IF_FAIL (read_buffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN); + + _cogl_framebuffer_gl_bind (draw_buffer, GL_DRAW_FRAMEBUFFER); + _cogl_framebuffer_gl_bind (read_buffer, GL_READ_FRAMEBUFFER); + } + + differences &= ~COGL_FRAMEBUFFER_STATE_BIND; + } + + COGL_FLAGS_FOREACH_START (&differences, 1, bit) + { + /* XXX: We considered having an array of callbacks for each state index + * that we'd call here but decided that this way the compiler is more + * likely going to be able to in-line the flush functions and use the + * index to jump straight to the required code. */ + switch (bit) + { + case COGL_FRAMEBUFFER_STATE_INDEX_VIEWPORT: + _cogl_framebuffer_gl_flush_viewport_state (draw_buffer); + break; + case COGL_FRAMEBUFFER_STATE_INDEX_CLIP: + _cogl_framebuffer_gl_flush_clip_state (draw_buffer); + break; + case COGL_FRAMEBUFFER_STATE_INDEX_DITHER: + _cogl_framebuffer_gl_flush_dither_state (draw_buffer); + break; + case COGL_FRAMEBUFFER_STATE_INDEX_MODELVIEW: + _cogl_framebuffer_gl_flush_modelview_state (draw_buffer); + break; + case COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION: + _cogl_framebuffer_gl_flush_projection_state (draw_buffer); + break; + case COGL_FRAMEBUFFER_STATE_INDEX_COLOR_MASK: + _cogl_framebuffer_gl_flush_color_mask_state (draw_buffer); + break; + case COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING: + _cogl_framebuffer_gl_flush_front_face_winding_state (draw_buffer); + break; + default: + g_warn_if_reached (); + } + } + COGL_FLAGS_FOREACH_END; + + ctx->current_draw_buffer_state_flushed |= state; + ctx->current_draw_buffer_changes &= ~state; +} + +static CoglTexture * +create_depth_texture (CoglContext *ctx, + int width, + int height) +{ + CoglPixelFormat format; + CoglTexture2D *depth_texture; + + if (ctx->private_feature_flags & + (COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL | + COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL)) + { + format = COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8; + } + else + format = COGL_PIXEL_FORMAT_DEPTH_16; + + depth_texture = cogl_texture_2d_new_with_size (ctx, + width, height, + format, + NULL); + + return COGL_TEXTURE (depth_texture); +} + +static CoglTexture * +attach_depth_texture (CoglContext *ctx, + CoglTexture *depth_texture, + CoglOffscreenAllocateFlags flags) +{ + GLuint tex_gl_handle; + GLenum tex_gl_target; + + if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL) + { + /* attach a GL_DEPTH_STENCIL texture to the GL_DEPTH_ATTACHMENT and + * GL_STENCIL_ATTACHMENT attachement points */ + g_assert (cogl_texture_get_format (depth_texture) == + COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8); + + cogl_texture_get_gl_texture (depth_texture, + &tex_gl_handle, &tex_gl_target); + + GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + tex_gl_target, tex_gl_handle, + 0)); + GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, + GL_STENCIL_ATTACHMENT, + tex_gl_target, tex_gl_handle, + 0)); + } + else if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH) + { + /* attach a newly created GL_DEPTH_COMPONENT16 texture to the + * GL_DEPTH_ATTACHMENT attachement point */ + g_assert (cogl_texture_get_format (depth_texture) == + COGL_PIXEL_FORMAT_DEPTH_16); + + cogl_texture_get_gl_texture (COGL_TEXTURE (depth_texture), + &tex_gl_handle, &tex_gl_target); + + GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + tex_gl_target, tex_gl_handle, + 0)); + } + + return COGL_TEXTURE (depth_texture); +} + +static GList * +try_creating_renderbuffers (CoglContext *ctx, + int width, + int height, + CoglOffscreenAllocateFlags flags, + int n_samples) +{ + GList *renderbuffers = NULL; + GLuint gl_depth_stencil_handle; + + if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL) + { + GLenum format; + + /* Although GL_OES_packed_depth_stencil is mostly equivalent to + * GL_EXT_packed_depth_stencil, one notable difference is that + * GL_OES_packed_depth_stencil doesn't allow GL_DEPTH_STENCIL to + * be passed as an internal format to glRenderbufferStorage. + */ + if (ctx->private_feature_flags & + COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL) + format = GL_DEPTH_STENCIL; + else + { + _COGL_RETURN_VAL_IF_FAIL ( + ctx->private_feature_flags & + COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL, + NULL); + format = GL_DEPTH24_STENCIL8; + } + + /* Create a renderbuffer for depth and stenciling */ + GE (ctx, glGenRenderbuffers (1, &gl_depth_stencil_handle)); + GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_stencil_handle)); + if (n_samples) + GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER, + n_samples, + format, + width, height)); + else + GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, format, + width, height)); + GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0)); + GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER, + GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, + gl_depth_stencil_handle)); + GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, + gl_depth_stencil_handle)); + renderbuffers = + g_list_prepend (renderbuffers, + GUINT_TO_POINTER (gl_depth_stencil_handle)); + } + + if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH) + { + GLuint gl_depth_handle; + + GE (ctx, glGenRenderbuffers (1, &gl_depth_handle)); + GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_handle)); + /* For now we just ask for GL_DEPTH_COMPONENT16 since this is all that's + * available under GLES */ + if (n_samples) + GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER, + n_samples, + GL_DEPTH_COMPONENT16, + width, height)); + else + GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, + width, height)); + GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0)); + GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, gl_depth_handle)); + renderbuffers = + g_list_prepend (renderbuffers, GUINT_TO_POINTER (gl_depth_handle)); + } + + if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL) + { + GLuint gl_stencil_handle; + + GE (ctx, glGenRenderbuffers (1, &gl_stencil_handle)); + GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_stencil_handle)); + if (n_samples) + GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER, + n_samples, + GL_STENCIL_INDEX8, + width, height)); + else + GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_STENCIL_INDEX8, + width, height)); + GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0)); + GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER, + GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, gl_stencil_handle)); + renderbuffers = + g_list_prepend (renderbuffers, GUINT_TO_POINTER (gl_stencil_handle)); + } + + return renderbuffers; +} + +static void +delete_renderbuffers (CoglContext *ctx, GList *renderbuffers) +{ + GList *l; + + for (l = renderbuffers; l; l = l->next) + { + GLuint renderbuffer = GPOINTER_TO_UINT (l->data); + GE (ctx, glDeleteRenderbuffers (1, &renderbuffer)); + } + + g_list_free (renderbuffers); +} + +/* + * NB: This function may be called with a standalone GLES2 context + * bound so we can create a shadow framebuffer that wraps the same + * CoglTexture as the given CoglOffscreen. This function shouldn't + * modify anything in + */ +static CoglBool +try_creating_fbo (CoglContext *ctx, + CoglTexture *texture, + int texture_level, + int texture_level_width, + int texture_level_height, + CoglTexture *depth_texture, + CoglFramebufferConfig *config, + CoglOffscreenAllocateFlags flags, + CoglGLFramebuffer *gl_framebuffer) +{ + GLuint tex_gl_handle; + GLenum tex_gl_target; + GLenum status; + int n_samples; + + if (!cogl_texture_get_gl_texture (texture, &tex_gl_handle, &tex_gl_target)) + return FALSE; + + if (tex_gl_target != GL_TEXTURE_2D +#ifdef HAVE_COGL_GL + && tex_gl_target != GL_TEXTURE_RECTANGLE_ARB +#endif + ) + return FALSE; + + if (config->samples_per_pixel) + { + if (!ctx->glFramebufferTexture2DMultisampleIMG) + return FALSE; + n_samples = config->samples_per_pixel; + } + else + n_samples = 0; + + /* We are about to generate and bind a new fbo, so we pretend to + * change framebuffer state so that the old framebuffer will be + * rebound again before drawing. */ + ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_BIND; + + /* Generate framebuffer */ + ctx->glGenFramebuffers (1, &gl_framebuffer->fbo_handle); + GE (ctx, glBindFramebuffer (GL_FRAMEBUFFER, gl_framebuffer->fbo_handle)); + + if (n_samples) + { + GE (ctx, glFramebufferTexture2DMultisampleIMG (GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + tex_gl_target, tex_gl_handle, + n_samples, + texture_level)); + } + else + GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + tex_gl_target, tex_gl_handle, + texture_level)); + + /* attach either a depth/stencil texture, a depth texture or render buffers + * depending on what we've been asked to provide */ + + if (depth_texture && + flags & (COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL | + COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH)) + { + attach_depth_texture (ctx, depth_texture, flags); + + /* Let's clear the flags that are now fulfilled as we might need to + * create renderbuffers (for the ALLOCATE_FLAG_DEPTH | + * ALLOCATE_FLAG_STENCIL case) */ + flags &= ~(COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL | + COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH); + } + + if (flags) + { + gl_framebuffer->renderbuffers = + try_creating_renderbuffers (ctx, + texture_level_width, + texture_level_height, + flags, + n_samples); + } + + /* Make sure it's complete */ + status = ctx->glCheckFramebufferStatus (GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) + { + GE (ctx, glDeleteFramebuffers (1, &gl_framebuffer->fbo_handle)); + + delete_renderbuffers (ctx, gl_framebuffer->renderbuffers); + gl_framebuffer->renderbuffers = NULL; + + return FALSE; + } + + /* Update the real number of samples_per_pixel now that we have a + * complete framebuffer */ + if (n_samples) + { + GLenum attachment = GL_COLOR_ATTACHMENT0; + GLenum pname = GL_TEXTURE_SAMPLES_IMG; + int texture_samples; + + GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, + attachment, + pname, + &texture_samples) ); + gl_framebuffer->samples_per_pixel = texture_samples; + } + + return TRUE; +} + +CoglBool +_cogl_framebuffer_try_creating_gl_fbo (CoglContext *ctx, + CoglTexture *texture, + int texture_level, + int texture_level_width, + int texture_level_height, + CoglTexture *depth_texture, + CoglFramebufferConfig *config, + CoglOffscreenAllocateFlags flags, + CoglGLFramebuffer *gl_framebuffer) +{ + return try_creating_fbo (ctx, + texture, + texture_level, + texture_level_width, + texture_level_height, + depth_texture, + config, + flags, + gl_framebuffer); +} + +CoglBool +_cogl_offscreen_gl_allocate (CoglOffscreen *offscreen, + GError **error) +{ + CoglFramebuffer *fb = COGL_FRAMEBUFFER (offscreen); + CoglContext *ctx = fb->context; + CoglOffscreenAllocateFlags flags; + CoglGLFramebuffer *gl_framebuffer = &offscreen->gl_framebuffer; + + if (fb->config.depth_texture_enabled && + offscreen->depth_texture == NULL) + { + offscreen->depth_texture = + create_depth_texture (ctx, + offscreen->texture_level_width, + offscreen->texture_level_height); + + if (offscreen->depth_texture) + _cogl_texture_associate_framebuffer (offscreen->depth_texture, fb); + else + { + g_set_error (error, COGL_FRAMEBUFFER_ERROR, + COGL_FRAMEBUFFER_ERROR_ALLOCATE, + "Failed to allocate depth texture for framebuffer"); + } + } + + /* 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 CoglPipeline. + */ + _cogl_texture_set_filters (offscreen->texture, GL_NEAREST, GL_NEAREST); + + if (((offscreen->create_flags & COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL) && + try_creating_fbo (ctx, + offscreen->texture, + offscreen->texture_level, + offscreen->texture_level_width, + offscreen->texture_level_height, + offscreen->depth_texture, + &fb->config, + flags = 0, + gl_framebuffer)) || + + (ctx->have_last_offscreen_allocate_flags && + try_creating_fbo (ctx, + offscreen->texture, + offscreen->texture_level, + offscreen->texture_level_width, + offscreen->texture_level_height, + offscreen->depth_texture, + &fb->config, + flags = ctx->last_offscreen_allocate_flags, + gl_framebuffer)) || + + ((ctx->private_feature_flags & + (COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL | + COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL)) && + try_creating_fbo (ctx, + offscreen->texture, + offscreen->texture_level, + offscreen->texture_level_width, + offscreen->texture_level_height, + offscreen->depth_texture, + &fb->config, + flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL, + gl_framebuffer)) || + + try_creating_fbo (ctx, + offscreen->texture, + offscreen->texture_level, + offscreen->texture_level_width, + offscreen->texture_level_height, + offscreen->depth_texture, + &fb->config, + flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH | + COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL, + gl_framebuffer) || + + try_creating_fbo (ctx, + offscreen->texture, + offscreen->texture_level, + offscreen->texture_level_width, + offscreen->texture_level_height, + offscreen->depth_texture, + &fb->config, + flags = COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL, + gl_framebuffer) || + + try_creating_fbo (ctx, + offscreen->texture, + offscreen->texture_level, + offscreen->texture_level_width, + offscreen->texture_level_height, + offscreen->depth_texture, + &fb->config, + flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH, + gl_framebuffer) || + + try_creating_fbo (ctx, + offscreen->texture, + offscreen->texture_level, + offscreen->texture_level_width, + offscreen->texture_level_height, + offscreen->depth_texture, + &fb->config, + flags = 0, + gl_framebuffer)) + { + fb->samples_per_pixel = gl_framebuffer->samples_per_pixel; + + if (!offscreen->create_flags & COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL) + { + /* Record that the last set of flags succeeded so that we can + try that set first next time */ + ctx->last_offscreen_allocate_flags = flags; + ctx->have_last_offscreen_allocate_flags = TRUE; + } + + /* Save the flags we managed to successfully allocate the + * renderbuffers with in case we need to make renderbuffers for a + * GLES2 context later */ + offscreen->allocation_flags = flags; + + return TRUE; + } + else + { + g_set_error (error, COGL_FRAMEBUFFER_ERROR, + COGL_FRAMEBUFFER_ERROR_ALLOCATE, + "Failed to create an OpenGL framebuffer object"); + return FALSE; + } +} + +void +_cogl_offscreen_gl_free (CoglOffscreen *offscreen) +{ + CoglContext *ctx = COGL_FRAMEBUFFER (offscreen)->context; + + delete_renderbuffers (ctx, offscreen->gl_framebuffer.renderbuffers); + + GE (ctx, glDeleteFramebuffers (1, &offscreen->gl_framebuffer.fbo_handle)); +} + +void +_cogl_framebuffer_gl_clear (CoglFramebuffer *framebuffer, + unsigned long buffers, + float red, + float green, + float blue, + float alpha) +{ + CoglContext *ctx = framebuffer->context; + GLbitfield gl_buffers = 0; + + if (buffers & COGL_BUFFER_BIT_COLOR) + { + GE( ctx, glClearColor (red, green, blue, alpha) ); + gl_buffers |= GL_COLOR_BUFFER_BIT; + + if (ctx->current_gl_color_mask != framebuffer->color_mask) + { + CoglColorMask color_mask = framebuffer->color_mask; + GE( ctx, glColorMask (!!(color_mask & COGL_COLOR_MASK_RED), + !!(color_mask & COGL_COLOR_MASK_GREEN), + !!(color_mask & COGL_COLOR_MASK_BLUE), + !!(color_mask & COGL_COLOR_MASK_ALPHA))); + ctx->current_gl_color_mask = color_mask; + /* Make sure the ColorMask is updated when the next primitive is drawn */ + ctx->current_pipeline_changes_since_flush |= + COGL_PIPELINE_STATE_LOGIC_OPS; + ctx->current_pipeline_age--; + } + } + + if (buffers & COGL_BUFFER_BIT_DEPTH) + gl_buffers |= GL_DEPTH_BUFFER_BIT; + + if (buffers & COGL_BUFFER_BIT_STENCIL) + gl_buffers |= GL_STENCIL_BUFFER_BIT; + + + GE (ctx, glClear (gl_buffers)); +} + +static inline void +_cogl_framebuffer_init_bits (CoglFramebuffer *framebuffer) +{ + CoglContext *ctx = framebuffer->context; + + cogl_framebuffer_allocate (framebuffer, NULL); + + if (G_LIKELY (!framebuffer->dirty_bitmasks)) + return; + +#ifdef HAVE_COGL_GL + if (ctx->driver == COGL_DRIVER_GL && + cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) && + framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN) + { + GLenum attachment, pname; + + attachment = GL_COLOR_ATTACHMENT0; + + pname = GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE; + GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, + attachment, + pname, + &framebuffer->red_bits) ); + + pname = GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE; + GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, + attachment, + pname, + &framebuffer->green_bits) + ); + + pname = GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE; + GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, + attachment, + pname, + &framebuffer->blue_bits) + ); + + pname = GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE; + GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, + attachment, + pname, + &framebuffer->alpha_bits) + ); + } + else +#endif /* HAVE_COGL_GL */ + { + GE( ctx, glGetIntegerv (GL_RED_BITS, &framebuffer->red_bits) ); + GE( ctx, glGetIntegerv (GL_GREEN_BITS, &framebuffer->green_bits) ); + GE( ctx, glGetIntegerv (GL_BLUE_BITS, &framebuffer->blue_bits) ); + GE( ctx, glGetIntegerv (GL_ALPHA_BITS, &framebuffer->alpha_bits) ); + } + + + COGL_NOTE (OFFSCREEN, + "RGBA Bits for framebuffer[%p, %s]: %d, %d, %d, %d", + framebuffer, + framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN + ? "offscreen" + : "onscreen", + framebuffer->red_bits, + framebuffer->blue_bits, + framebuffer->green_bits, + framebuffer->alpha_bits); + + framebuffer->dirty_bitmasks = FALSE; +} + +void +_cogl_framebuffer_gl_query_bits (CoglFramebuffer *framebuffer, + int *red, + int *green, + int *blue, + int *alpha) +{ + _cogl_framebuffer_init_bits (framebuffer); + + /* TODO: cache these in some driver specific location not + * directly as part of CoglFramebuffer. */ + *red = framebuffer->red_bits; + *green = framebuffer->green_bits; + *blue = framebuffer->blue_bits; + *alpha = framebuffer->alpha_bits; +} + +void +_cogl_framebuffer_gl_finish (CoglFramebuffer *framebuffer) +{ + GE (framebuffer->context, glFinish ()); +} + +void +_cogl_framebuffer_gl_discard_buffers (CoglFramebuffer *framebuffer, + unsigned long buffers) +{ +#ifdef GL_EXT_discard_framebuffer + CoglContext *ctx = framebuffer->context; + + if (ctx->glDiscardFramebuffer) + { + GLenum attachments[3]; + int i = 0; + + if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN) + { + if (buffers & COGL_BUFFER_BIT_COLOR) + attachments[i++] = GL_COLOR_EXT; + if (buffers & COGL_BUFFER_BIT_DEPTH) + attachments[i++] = GL_DEPTH_EXT; + if (buffers & COGL_BUFFER_BIT_STENCIL) + attachments[i++] = GL_STENCIL_EXT; + } + else + { + if (buffers & COGL_BUFFER_BIT_COLOR) + attachments[i++] = GL_COLOR_ATTACHMENT0; + if (buffers & COGL_BUFFER_BIT_DEPTH) + attachments[i++] = GL_DEPTH_ATTACHMENT; + if (buffers & COGL_BUFFER_BIT_STENCIL) + attachments[i++] = GL_STENCIL_ATTACHMENT; + } + + GE (ctx, glDiscardFramebuffer (GL_FRAMEBUFFER, i, attachments)); + } +#endif /* GL_EXT_discard_framebuffer */ +} + +void +_cogl_framebuffer_gl_draw_attributes (CoglFramebuffer *framebuffer, + CoglPipeline *pipeline, + CoglVerticesMode mode, + int first_vertex, + int n_vertices, + CoglAttribute **attributes, + int n_attributes, + CoglDrawFlags flags) +{ + _cogl_flush_attributes_state (framebuffer, pipeline, flags, + attributes, n_attributes); + + GE (framebuffer->context, + glDrawArrays ((GLenum)mode, first_vertex, n_vertices)); +} + +static size_t +sizeof_index_type (CoglIndicesType type) +{ + switch (type) + { + case COGL_INDICES_TYPE_UNSIGNED_BYTE: + return 1; + case COGL_INDICES_TYPE_UNSIGNED_SHORT: + return 2; + case COGL_INDICES_TYPE_UNSIGNED_INT: + return 4; + } + g_return_val_if_reached (0); +} + +void +_cogl_framebuffer_gl_draw_indexed_attributes (CoglFramebuffer *framebuffer, + CoglPipeline *pipeline, + CoglVerticesMode mode, + int first_vertex, + int n_vertices, + CoglIndices *indices, + CoglAttribute **attributes, + int n_attributes, + CoglDrawFlags flags) +{ + CoglBuffer *buffer; + uint8_t *base; + size_t buffer_offset; + size_t index_size; + GLenum indices_gl_type = 0; + + _cogl_flush_attributes_state (framebuffer, pipeline, flags, + attributes, n_attributes); + + buffer = COGL_BUFFER (cogl_indices_get_buffer (indices)); + base = _cogl_buffer_bind (buffer, COGL_BUFFER_BIND_TARGET_INDEX_BUFFER); + buffer_offset = cogl_indices_get_offset (indices); + index_size = sizeof_index_type (cogl_indices_get_type (indices)); + + switch (cogl_indices_get_type (indices)) + { + case COGL_INDICES_TYPE_UNSIGNED_BYTE: + indices_gl_type = GL_UNSIGNED_BYTE; + break; + case COGL_INDICES_TYPE_UNSIGNED_SHORT: + indices_gl_type = GL_UNSIGNED_SHORT; + break; + case COGL_INDICES_TYPE_UNSIGNED_INT: + indices_gl_type = GL_UNSIGNED_INT; + break; + } + + GE (framebuffer->context, + glDrawElements ((GLenum)mode, + n_vertices, + indices_gl_type, + base + buffer_offset + index_size * first_vertex)); + + _cogl_buffer_unbind (buffer); +} diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h index a13f2b9a8..d2c2c36e1 100644 --- a/cogl/cogl-framebuffer-private.h +++ b/cogl/cogl-framebuffer-private.h @@ -130,17 +130,9 @@ struct _CoglFramebuffer CoglClipState clip_state; - CoglBool dirty_bitmasks; - int red_bits; - int blue_bits; - int green_bits; - int alpha_bits; - CoglBool dither_enabled; CoglColorMask color_mask; - int samples_per_pixel; - /* We journal the textured rectangles we want to submit to OpenGL so * we have an oppertunity to batch them together into less draw * calls. */ @@ -165,6 +157,15 @@ struct _CoglFramebuffer int clear_clip_x1; int clear_clip_y1; CoglBool clear_clip_dirty; + + /* driver specific */ + CoglBool dirty_bitmasks; + int red_bits; + int blue_bits; + int green_bits; + int alpha_bits; + + int samples_per_pixel; }; typedef enum { @@ -429,7 +430,26 @@ _cogl_framebuffer_try_creating_gl_fbo (CoglContext *ctx, CoglOffscreenAllocateFlags flags, CoglGLFramebuffer *gl_framebuffer); -void -_cogl_gl_framebuffer_bind (CoglFramebuffer *framebuffer, GLenum target); +unsigned long +_cogl_framebuffer_compare (CoglFramebuffer *a, + CoglFramebuffer *b, + unsigned long state); + +static inline CoglMatrixEntry * +_cogl_framebuffer_get_modelview_entry (CoglFramebuffer *framebuffer) +{ + CoglMatrixStack *modelview_stack = + _cogl_framebuffer_get_modelview_stack (framebuffer); + return modelview_stack->last_entry; +} + +static inline CoglMatrixEntry * +_cogl_framebuffer_get_projection_entry (CoglFramebuffer *framebuffer) +{ + CoglMatrixStack *projection_stack = + _cogl_framebuffer_get_projection_stack (framebuffer); + return projection_stack->last_entry; +} + #endif /* __COGL_FRAMEBUFFER_PRIVATE_H */ diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c index 250d6544e..3b927c223 100644 --- a/cogl/cogl-framebuffer.c +++ b/cogl/cogl-framebuffer.c @@ -3,7 +3,7 @@ * * An object oriented GL/GLES Abstraction/Utility Layer * - * Copyright (C) 2007,2008,2009 Intel Corporation. + * Copyright (C) 2007,2008,2009,2012 Intel Corporation. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,7 +16,8 @@ * 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, see . + * License along with this library. If not, see + * . * * */ @@ -49,68 +50,6 @@ #include "cogl-primitives-private.h" #include "cogl-path-private.h" -#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 -#ifndef GL_DEPTH_STENCIL -#define GL_DEPTH_STENCIL 0x84F9 -#endif -#ifndef GL_DEPTH24_STENCIL8 -#define GL_DEPTH24_STENCIL8 0x88F0 -#endif -#ifndef GL_DEPTH_ATTACHMENT -#define GL_DEPTH_ATTACHMENT 0x8D00 -#endif -#ifndef GL_DEPTH_COMPONENT16 -#define GL_DEPTH_COMPONENT16 0x81A5 -#endif -#ifndef GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE -#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 -#endif -#ifndef GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE -#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 -#endif -#ifndef GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE -#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 -#endif -#ifndef GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE -#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 -#endif -#ifndef GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE -#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 -#endif -#ifndef GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE -#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 -#endif -#ifndef GL_READ_FRAMEBUFFER -#define GL_READ_FRAMEBUFFER 0x8CA8 -#endif -#ifndef GL_DRAW_FRAMEBUFFER -#define GL_DRAW_FRAMEBUFFER 0x8CA9 -#endif -#ifndef GL_TEXTURE_SAMPLES_IMG -#define GL_TEXTURE_SAMPLES_IMG 0x9136 -#endif -#ifndef GL_PACK_INVERT_MESA -#define GL_PACK_INVERT_MESA 0x8758 -#endif - - typedef struct _CoglFramebufferStackEntry { CoglFramebuffer *draw_buffer; @@ -265,50 +204,24 @@ _cogl_framebuffer_clear_without_flush4f (CoglFramebuffer *framebuffer, float blue, float alpha) { - GLbitfield gl_buffers = 0; + CoglContext *ctx = framebuffer->context; - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if (buffers & COGL_BUFFER_BIT_COLOR) - { - GE( ctx, glClearColor (red, green, blue, alpha) ); - gl_buffers |= GL_COLOR_BUFFER_BIT; - - if (ctx->current_gl_color_mask != framebuffer->color_mask) - { - CoglColorMask color_mask = framebuffer->color_mask; - GE( ctx, glColorMask (!!(color_mask & COGL_COLOR_MASK_RED), - !!(color_mask & COGL_COLOR_MASK_GREEN), - !!(color_mask & COGL_COLOR_MASK_BLUE), - !!(color_mask & COGL_COLOR_MASK_ALPHA))); - ctx->current_gl_color_mask = color_mask; - /* Make sure the ColorMask is updated when the next primitive is drawn */ - ctx->current_pipeline_changes_since_flush |= - COGL_PIPELINE_STATE_LOGIC_OPS; - ctx->current_pipeline_age--; - } - } - - if (buffers & COGL_BUFFER_BIT_DEPTH) - gl_buffers |= GL_DEPTH_BUFFER_BIT; - - if (buffers & COGL_BUFFER_BIT_STENCIL) - gl_buffers |= GL_STENCIL_BUFFER_BIT; - - if (!gl_buffers) + if (!buffers) { static CoglBool shown = FALSE; if (!shown) { g_warning ("You should specify at least one auxiliary buffer " - "when calling cogl_clear"); + "when calling cogl_framebuffer_clear"); } return; } - GE (ctx, glClear (gl_buffers)); + ctx->driver_vtable->framebuffer_clear (framebuffer, + buffers, + red, green, blue, alpha); } void @@ -641,76 +554,6 @@ _cogl_framebuffer_flush_dependency_journals (CoglFramebuffer *framebuffer) _cogl_framebuffer_remove_all_dependencies (framebuffer); } -static inline void -_cogl_framebuffer_init_bits (CoglFramebuffer *framebuffer) -{ - CoglContext *ctx = framebuffer->context; - - cogl_framebuffer_allocate (framebuffer, NULL); - - if (G_LIKELY (!framebuffer->dirty_bitmasks)) - return; - -#ifdef HAVE_COGL_GL - if (ctx->driver == COGL_DRIVER_GL && - cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) && - framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN) - { - GLenum attachment, pname; - - attachment = GL_COLOR_ATTACHMENT0; - - pname = GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE; - GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, - attachment, - pname, - &framebuffer->red_bits) ); - - pname = GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE; - GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, - attachment, - pname, - &framebuffer->green_bits) - ); - - pname = GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE; - GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, - attachment, - pname, - &framebuffer->blue_bits) - ); - - pname = GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE; - GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, - attachment, - pname, - &framebuffer->alpha_bits) - ); - } - else -#endif /* HAVE_COGL_GL */ - { - GE( ctx, glGetIntegerv (GL_RED_BITS, &framebuffer->red_bits) ); - GE( ctx, glGetIntegerv (GL_GREEN_BITS, &framebuffer->green_bits) ); - GE( ctx, glGetIntegerv (GL_BLUE_BITS, &framebuffer->blue_bits) ); - GE( ctx, glGetIntegerv (GL_ALPHA_BITS, &framebuffer->alpha_bits) ); - } - - - COGL_NOTE (OFFSCREEN, - "RGBA Bits for framebuffer[%p, %s]: %d, %d, %d, %d", - framebuffer, - framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN - ? "offscreen" - : "onscreen", - framebuffer->red_bits, - framebuffer->blue_bits, - framebuffer->green_bits, - framebuffer->alpha_bits); - - framebuffer->dirty_bitmasks = FALSE; -} - CoglOffscreen * _cogl_offscreen_new_to_texture_full (CoglTexture *texture, CoglOffscreenFlags create_flags, @@ -787,33 +630,17 @@ cogl_offscreen_new_to_texture (CoglTexture *texture) return _cogl_offscreen_new_to_texture_full (texture, 0, 0); } -static void -delete_renderbuffers (CoglContext *ctx, GList *renderbuffers) -{ - GList *l; - - for (l = renderbuffers; l; l = l->next) - { - GLuint renderbuffer = GPOINTER_TO_UINT (l->data); - GE (ctx, glDeleteRenderbuffers (1, &renderbuffer)); - } - - g_list_free (renderbuffers); -} - static void _cogl_offscreen_free (CoglOffscreen *offscreen) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (offscreen); CoglContext *ctx = framebuffer->context; + ctx->driver_vtable->offscreen_free (offscreen); + /* Chain up to parent */ _cogl_framebuffer_free (framebuffer); - delete_renderbuffers (ctx, offscreen->gl_framebuffer.renderbuffers); - - GE (ctx, glDeleteFramebuffers (1, &offscreen->gl_framebuffer.fbo_handle)); - if (offscreen->texture != NULL) cogl_object_unref (offscreen->texture); @@ -823,465 +650,6 @@ _cogl_offscreen_free (CoglOffscreen *offscreen) g_free (offscreen); } -static CoglTexture * -create_depth_texture (CoglContext *ctx, - int width, - int height) -{ - CoglPixelFormat format; - CoglTexture2D *depth_texture; - - if (ctx->private_feature_flags & - (COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL | - COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL)) - { - format = COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8; - } - else - format = COGL_PIXEL_FORMAT_DEPTH_16; - - depth_texture = cogl_texture_2d_new_with_size (ctx, - width, height, - format, - NULL); - - return COGL_TEXTURE (depth_texture); -} - -static CoglTexture * -attach_depth_texture (CoglContext *ctx, - CoglTexture *depth_texture, - CoglOffscreenAllocateFlags flags) -{ - GLuint tex_gl_handle; - GLenum tex_gl_target; - - if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL) - { - /* attach a GL_DEPTH_STENCIL texture to the GL_DEPTH_ATTACHMENT and - * GL_STENCIL_ATTACHMENT attachement points */ - g_assert (cogl_texture_get_format (depth_texture) == - COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8); - - cogl_texture_get_gl_texture (depth_texture, - &tex_gl_handle, &tex_gl_target); - - GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - tex_gl_target, tex_gl_handle, - 0)); - GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, - GL_STENCIL_ATTACHMENT, - tex_gl_target, tex_gl_handle, - 0)); - } - else if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH) - { - /* attach a newly created GL_DEPTH_COMPONENT16 texture to the - * GL_DEPTH_ATTACHMENT attachement point */ - g_assert (cogl_texture_get_format (depth_texture) == - COGL_PIXEL_FORMAT_DEPTH_16); - - cogl_texture_get_gl_texture (COGL_TEXTURE (depth_texture), - &tex_gl_handle, &tex_gl_target); - - GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - tex_gl_target, tex_gl_handle, - 0)); - } - - return COGL_TEXTURE (depth_texture); -} - -static GList * -try_creating_renderbuffers (CoglContext *ctx, - int width, - int height, - CoglOffscreenAllocateFlags flags, - int n_samples) -{ - GList *renderbuffers = NULL; - GLuint gl_depth_stencil_handle; - - if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL) - { - GLenum format; - - /* Although GL_OES_packed_depth_stencil is mostly equivalent to - * GL_EXT_packed_depth_stencil, one notable difference is that - * GL_OES_packed_depth_stencil doesn't allow GL_DEPTH_STENCIL to - * be passed as an internal format to glRenderbufferStorage. - */ - if (ctx->private_feature_flags & - COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL) - format = GL_DEPTH_STENCIL; - else - { - _COGL_RETURN_VAL_IF_FAIL ( - ctx->private_feature_flags & - COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL, - NULL); - format = GL_DEPTH24_STENCIL8; - } - - /* Create a renderbuffer for depth and stenciling */ - GE (ctx, glGenRenderbuffers (1, &gl_depth_stencil_handle)); - GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_stencil_handle)); - if (n_samples) - GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER, - n_samples, - format, - width, height)); - else - GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, format, - width, height)); - GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0)); - GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER, - GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, - gl_depth_stencil_handle)); - GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - GL_RENDERBUFFER, - gl_depth_stencil_handle)); - renderbuffers = - g_list_prepend (renderbuffers, - GUINT_TO_POINTER (gl_depth_stencil_handle)); - } - - if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH) - { - GLuint gl_depth_handle; - - GE (ctx, glGenRenderbuffers (1, &gl_depth_handle)); - GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_handle)); - /* For now we just ask for GL_DEPTH_COMPONENT16 since this is all that's - * available under GLES */ - if (n_samples) - GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER, - n_samples, - GL_DEPTH_COMPONENT16, - width, height)); - else - GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, - width, height)); - GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0)); - GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - GL_RENDERBUFFER, gl_depth_handle)); - renderbuffers = - g_list_prepend (renderbuffers, GUINT_TO_POINTER (gl_depth_handle)); - } - - if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL) - { - GLuint gl_stencil_handle; - - GE (ctx, glGenRenderbuffers (1, &gl_stencil_handle)); - GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_stencil_handle)); - if (n_samples) - GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER, - n_samples, - GL_STENCIL_INDEX8, - width, height)); - else - GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_STENCIL_INDEX8, - width, height)); - GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0)); - GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER, - GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, gl_stencil_handle)); - renderbuffers = - g_list_prepend (renderbuffers, GUINT_TO_POINTER (gl_stencil_handle)); - } - - return renderbuffers; -} - -/* - * NB: This function may be called with a standalone GLES2 context - * bound so we can create a shadow framebuffer that wraps the same - * CoglTexture as the given CoglOffscreen. This function shouldn't - * modify anything in - */ -static CoglBool -try_creating_fbo (CoglContext *ctx, - CoglTexture *texture, - int texture_level, - int texture_level_width, - int texture_level_height, - CoglTexture *depth_texture, - CoglFramebufferConfig *config, - CoglOffscreenAllocateFlags flags, - CoglGLFramebuffer *gl_framebuffer) -{ - GLuint tex_gl_handle; - GLenum tex_gl_target; - GLenum status; - int n_samples; - - if (!cogl_texture_get_gl_texture (texture, &tex_gl_handle, &tex_gl_target)) - return FALSE; - - if (tex_gl_target != GL_TEXTURE_2D -#ifdef HAVE_COGL_GL - && tex_gl_target != GL_TEXTURE_RECTANGLE_ARB -#endif - ) - return FALSE; - - if (config->samples_per_pixel) - { - if (!ctx->glFramebufferTexture2DMultisampleIMG) - return FALSE; - n_samples = config->samples_per_pixel; - } - else - n_samples = 0; - - /* We are about to generate and bind a new fbo, so we pretend to - * change framebuffer state so that the old framebuffer will be - * rebound again before drawing. */ - ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_BIND; - - /* Generate framebuffer */ - ctx->glGenFramebuffers (1, &gl_framebuffer->fbo_handle); - GE (ctx, glBindFramebuffer (GL_FRAMEBUFFER, gl_framebuffer->fbo_handle)); - - if (n_samples) - { - GE (ctx, glFramebufferTexture2DMultisampleIMG (GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - tex_gl_target, tex_gl_handle, - n_samples, - texture_level)); - } - else - GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - tex_gl_target, tex_gl_handle, - texture_level)); - - /* attach either a depth/stencil texture, a depth texture or render buffers - * depending on what we've been asked to provide */ - - if (depth_texture && - flags & (COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL | - COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH)) - { - attach_depth_texture (ctx, depth_texture, flags); - - /* Let's clear the flags that are now fulfilled as we might need to - * create renderbuffers (for the ALLOCATE_FLAG_DEPTH | - * ALLOCATE_FLAG_STENCIL case) */ - flags &= ~(COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL | - COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH); - } - - if (flags) - { - gl_framebuffer->renderbuffers = - try_creating_renderbuffers (ctx, - texture_level_width, - texture_level_height, - flags, - n_samples); - } - - /* Make sure it's complete */ - status = ctx->glCheckFramebufferStatus (GL_FRAMEBUFFER); - - if (status != GL_FRAMEBUFFER_COMPLETE) - { - GE (ctx, glDeleteFramebuffers (1, &gl_framebuffer->fbo_handle)); - - delete_renderbuffers (ctx, gl_framebuffer->renderbuffers); - gl_framebuffer->renderbuffers = NULL; - - return FALSE; - } - - /* Update the real number of samples_per_pixel now that we have a - * complete framebuffer */ - if (n_samples) - { - GLenum attachment = GL_COLOR_ATTACHMENT0; - GLenum pname = GL_TEXTURE_SAMPLES_IMG; - int texture_samples; - - GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, - attachment, - pname, - &texture_samples) ); - gl_framebuffer->samples_per_pixel = texture_samples; - } - - return TRUE; -} - -CoglBool -_cogl_framebuffer_try_creating_gl_fbo (CoglContext *ctx, - CoglTexture *texture, - int texture_level, - int texture_level_width, - int texture_level_height, - CoglTexture *depth_texture, - CoglFramebufferConfig *config, - CoglOffscreenAllocateFlags flags, - CoglGLFramebuffer *gl_framebuffer) -{ - return try_creating_fbo (ctx, - texture, - texture_level, - texture_level_width, - texture_level_height, - depth_texture, - config, - flags, - gl_framebuffer); -} - -static CoglBool -_cogl_offscreen_allocate (CoglOffscreen *offscreen, - GError **error) -{ - CoglFramebuffer *fb = COGL_FRAMEBUFFER (offscreen); - CoglContext *ctx = fb->context; - CoglOffscreenAllocateFlags flags; - CoglGLFramebuffer *gl_framebuffer = &offscreen->gl_framebuffer; - - if (fb->config.depth_texture_enabled && - offscreen->depth_texture == NULL) - { - offscreen->depth_texture = - create_depth_texture (ctx, - offscreen->texture_level_width, - offscreen->texture_level_height); - - if (offscreen->depth_texture) - _cogl_texture_associate_framebuffer (offscreen->depth_texture, fb); - else - { - g_set_error (error, COGL_FRAMEBUFFER_ERROR, - COGL_FRAMEBUFFER_ERROR_ALLOCATE, - "Failed to allocate depth texture for framebuffer"); - } - } - - /* 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 CoglPipeline. - */ - _cogl_texture_set_filters (offscreen->texture, GL_NEAREST, GL_NEAREST); - - if (((offscreen->create_flags & COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL) && - try_creating_fbo (ctx, - offscreen->texture, - offscreen->texture_level, - offscreen->texture_level_width, - offscreen->texture_level_height, - offscreen->depth_texture, - &fb->config, - flags = 0, - gl_framebuffer)) || - - (ctx->have_last_offscreen_allocate_flags && - try_creating_fbo (ctx, - offscreen->texture, - offscreen->texture_level, - offscreen->texture_level_width, - offscreen->texture_level_height, - offscreen->depth_texture, - &fb->config, - flags = ctx->last_offscreen_allocate_flags, - gl_framebuffer)) || - - ((ctx->private_feature_flags & - (COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL | - COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL)) && - try_creating_fbo (ctx, - offscreen->texture, - offscreen->texture_level, - offscreen->texture_level_width, - offscreen->texture_level_height, - offscreen->depth_texture, - &fb->config, - flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL, - gl_framebuffer)) || - - try_creating_fbo (ctx, - offscreen->texture, - offscreen->texture_level, - offscreen->texture_level_width, - offscreen->texture_level_height, - offscreen->depth_texture, - &fb->config, - flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH | - COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL, - gl_framebuffer) || - - try_creating_fbo (ctx, - offscreen->texture, - offscreen->texture_level, - offscreen->texture_level_width, - offscreen->texture_level_height, - offscreen->depth_texture, - &fb->config, - flags = COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL, - gl_framebuffer) || - - try_creating_fbo (ctx, - offscreen->texture, - offscreen->texture_level, - offscreen->texture_level_width, - offscreen->texture_level_height, - offscreen->depth_texture, - &fb->config, - flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH, - gl_framebuffer) || - - try_creating_fbo (ctx, - offscreen->texture, - offscreen->texture_level, - offscreen->texture_level_width, - offscreen->texture_level_height, - offscreen->depth_texture, - &fb->config, - flags = 0, - gl_framebuffer)) - { - fb->samples_per_pixel = gl_framebuffer->samples_per_pixel; - - if (!offscreen->create_flags & COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL) - { - /* Record that the last set of flags succeeded so that we can - try that set first next time */ - ctx->last_offscreen_allocate_flags = flags; - ctx->have_last_offscreen_allocate_flags = TRUE; - } - - /* Save the flags we managed to successfully allocate the - * renderbuffers with in case we need to make renderbuffers for a - * GLES2 context later */ - offscreen->allocation_flags = flags; - - return TRUE; - } - else - { - g_set_error (error, COGL_FRAMEBUFFER_ERROR, - COGL_FRAMEBUFFER_ERROR_ALLOCATE, - "Failed to create an OpenGL framebuffer object"); - return FALSE; - } -} - CoglBool cogl_framebuffer_allocate (CoglFramebuffer *framebuffer, GError **error) @@ -1308,7 +676,8 @@ cogl_framebuffer_allocate (CoglFramebuffer *framebuffer, } else { - if (!_cogl_offscreen_allocate (COGL_OFFSCREEN (framebuffer), error)) + CoglContext *ctx = framebuffer->context; + if (!ctx->driver_vtable->offscreen_allocate (COGL_OFFSCREEN (framebuffer), error)) return FALSE; } @@ -1563,28 +932,6 @@ cogl_pop_draw_buffer (void) cogl_pop_framebuffer (); } -void -_cogl_gl_framebuffer_bind (CoglFramebuffer *framebuffer, GLenum target) -{ - CoglContext *ctx = framebuffer->context; - - if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN) - { - CoglOffscreen *offscreen = COGL_OFFSCREEN (framebuffer); - GE (ctx, glBindFramebuffer (target, - offscreen->gl_framebuffer.fbo_handle)); - } - else - { - const CoglWinsysVtable *winsys = - _cogl_framebuffer_get_winsys (framebuffer); - winsys->onscreen_bind (COGL_ONSCREEN (framebuffer)); - /* glBindFramebuffer is an an extension with OpenGL ES 1.1 */ - if (cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) - GE (ctx, glBindFramebuffer (target, 0)); - } -} - static unsigned long _cogl_framebuffer_compare_viewport_state (CoglFramebuffer *a, CoglFramebuffer *b) @@ -1663,7 +1010,7 @@ _cogl_framebuffer_compare_front_face_winding_state (CoglFramebuffer *a, return 0; } -static unsigned long +unsigned long _cogl_framebuffer_compare (CoglFramebuffer *a, CoglFramebuffer *b, unsigned long state) @@ -1720,295 +1067,63 @@ _cogl_framebuffer_compare (CoglFramebuffer *a, return differences; } -static void -_cogl_framebuffer_flush_viewport_state (CoglFramebuffer *framebuffer) -{ - float gl_viewport_y; - - g_assert (framebuffer->viewport_width >=0 && - framebuffer->viewport_height >=0); - - /* 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); - - COGL_NOTE (OPENGL, "Calling glViewport(%f, %f, %f, %f)", - framebuffer->viewport_x, - gl_viewport_y, - framebuffer->viewport_width, - framebuffer->viewport_height); - - GE (framebuffer->context, - glViewport (framebuffer->viewport_x, - gl_viewport_y, - framebuffer->viewport_width, - framebuffer->viewport_height)); -} - -static void -_cogl_framebuffer_flush_clip_state (CoglFramebuffer *framebuffer) -{ - CoglClipStack *stack = _cogl_clip_state_get_stack (&framebuffer->clip_state); - _cogl_clip_stack_flush (stack, framebuffer); -} - -static void -_cogl_framebuffer_flush_dither_state (CoglFramebuffer *framebuffer) -{ - CoglContext *ctx = framebuffer->context; - - if (ctx->current_gl_dither_enabled != framebuffer->dither_enabled) - { - if (framebuffer->dither_enabled) - GE (ctx, glEnable (GL_DITHER)); - else - GE (ctx, glDisable (GL_DITHER)); - ctx->current_gl_dither_enabled = framebuffer->dither_enabled; - } -} - -static CoglMatrixEntry * -_cogl_framebuffer_get_modelview_entry (CoglFramebuffer *framebuffer) -{ - CoglMatrixStack *modelview_stack = - _cogl_framebuffer_get_modelview_stack (framebuffer); - return modelview_stack->last_entry; -} - -static void -_cogl_framebuffer_flush_modelview_state (CoglFramebuffer *framebuffer) -{ - CoglMatrixEntry *modelview_entry = - _cogl_framebuffer_get_modelview_entry (framebuffer); - _cogl_context_set_current_modelview_entry (framebuffer->context, - modelview_entry); -} - -static CoglMatrixEntry * -_cogl_framebuffer_get_projection_entry (CoglFramebuffer *framebuffer) -{ - CoglMatrixStack *projection_stack = - _cogl_framebuffer_get_projection_stack (framebuffer); - return projection_stack->last_entry; -} - -static void -_cogl_framebuffer_flush_projection_state (CoglFramebuffer *framebuffer) -{ - CoglMatrixEntry *projection_entry = - _cogl_framebuffer_get_projection_entry (framebuffer); - _cogl_context_set_current_projection_entry (framebuffer->context, - projection_entry); -} - -static void -_cogl_framebuffer_flush_color_mask_state (CoglFramebuffer *framebuffer) -{ - CoglContext *context = framebuffer->context; - - /* The color mask state is really owned by a CoglPipeline so to - * ensure the color mask is updated the next time we draw something - * we need to make sure the logic ops for the pipeline are - * re-flushed... */ - context->current_pipeline_changes_since_flush |= - COGL_PIPELINE_STATE_LOGIC_OPS; - context->current_pipeline_age--; -} - -static void -_cogl_framebuffer_flush_front_face_winding_state (CoglFramebuffer *framebuffer) -{ - CoglContext *context = framebuffer->context; - CoglPipelineCullFaceMode mode; - - /* NB: The face winding state is actually owned by the current - * CoglPipeline. - * - * If we don't have a current pipeline then we can just assume that - * when we later do flush a pipeline we will check the current - * framebuffer to know how to setup the winding */ - if (!context->current_pipeline) - return; - - mode = cogl_pipeline_get_cull_face_mode (context->current_pipeline); - - /* If the current CoglPipeline has a culling mode that doesn't care - * about the winding we can avoid forcing an update of the state and - * bail out. */ - if (mode == COGL_PIPELINE_CULL_FACE_MODE_NONE || - mode == COGL_PIPELINE_CULL_FACE_MODE_BOTH) - return; - - /* Since the winding state is really owned by the current pipeline - * the way we "flush" an updated winding is to dirty the pipeline - * state... */ - context->current_pipeline_changes_since_flush |= - COGL_PIPELINE_STATE_CULL_FACE; - context->current_pipeline_age--; -} - void _cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer, CoglFramebuffer *read_buffer, CoglFramebufferState state) { CoglContext *ctx = draw_buffer->context; - unsigned long differences; - int bit; - /* We can assume that any state that has changed for the current - * framebuffer is different to the currently flushed value. */ - differences = ctx->current_draw_buffer_changes; - - /* Any state of the current framebuffer that hasn't already been - * flushed is assumed to be unknown so we will always flush that - * state if asked. */ - differences |= ~ctx->current_draw_buffer_state_flushed; - - /* We only need to consider the state we've been asked to flush */ - differences &= state; - - if (ctx->current_draw_buffer != draw_buffer) - { - /* If the previous draw buffer is NULL then we'll assume - everything has changed. This can happen if a framebuffer is - destroyed while it is the last flushed draw buffer. In that - case the framebuffer destructor will set - ctx->current_draw_buffer to NULL */ - if (ctx->current_draw_buffer == NULL) - differences |= state; - else - /* NB: we only need to compare the state we're being asked to flush - * and we don't need to compare the state we've already decided - * we will definitely flush... */ - differences |= _cogl_framebuffer_compare (ctx->current_draw_buffer, - draw_buffer, - state & ~differences); - - /* NB: we don't take a reference here, to avoid a circular - * reference. */ - ctx->current_draw_buffer = draw_buffer; - ctx->current_draw_buffer_state_flushed = 0; - } - - if (ctx->current_read_buffer != read_buffer && - state & COGL_FRAMEBUFFER_STATE_BIND) - { - differences |= COGL_FRAMEBUFFER_STATE_BIND; - /* NB: we don't take a reference here, to avoid a circular - * reference. */ - ctx->current_read_buffer = read_buffer; - } - - if (!differences) - return; - - /* Lazily ensure the framebuffers have been allocated */ - if (G_UNLIKELY (!draw_buffer->allocated)) - cogl_framebuffer_allocate (draw_buffer, NULL); - if (G_UNLIKELY (!read_buffer->allocated)) - cogl_framebuffer_allocate (read_buffer, NULL); - - /* We handle buffer binding separately since the method depends on whether - * we are binding the same buffer for read and write or not unlike all - * other state that only relates to the draw_buffer. */ - if (differences & COGL_FRAMEBUFFER_STATE_BIND) - { - if (draw_buffer == read_buffer) - _cogl_gl_framebuffer_bind (draw_buffer, GL_FRAMEBUFFER); - else - { - /* NB: Currently we only take advantage of binding separate - * read/write buffers for offscreen framebuffer blit - * purposes. */ - _COGL_RETURN_IF_FAIL (ctx->private_feature_flags & - COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT); - _COGL_RETURN_IF_FAIL (draw_buffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN); - _COGL_RETURN_IF_FAIL (read_buffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN); - - _cogl_gl_framebuffer_bind (draw_buffer, GL_DRAW_FRAMEBUFFER); - _cogl_gl_framebuffer_bind (read_buffer, GL_READ_FRAMEBUFFER); - } - - differences &= ~COGL_FRAMEBUFFER_STATE_BIND; - } - - COGL_FLAGS_FOREACH_START (&differences, 1, bit) - { - /* XXX: We considered having an array of callbacks for each state index - * that we'd call here but decided that this way the compiler is more - * likely going to be able to in-line the flush functions and use the - * index to jump straight to the required code. */ - switch (bit) - { - case COGL_FRAMEBUFFER_STATE_INDEX_VIEWPORT: - _cogl_framebuffer_flush_viewport_state (draw_buffer); - break; - case COGL_FRAMEBUFFER_STATE_INDEX_CLIP: - _cogl_framebuffer_flush_clip_state (draw_buffer); - break; - case COGL_FRAMEBUFFER_STATE_INDEX_DITHER: - _cogl_framebuffer_flush_dither_state (draw_buffer); - break; - case COGL_FRAMEBUFFER_STATE_INDEX_MODELVIEW: - _cogl_framebuffer_flush_modelview_state (draw_buffer); - break; - case COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION: - _cogl_framebuffer_flush_projection_state (draw_buffer); - break; - case COGL_FRAMEBUFFER_STATE_INDEX_COLOR_MASK: - _cogl_framebuffer_flush_color_mask_state (draw_buffer); - break; - case COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING: - _cogl_framebuffer_flush_front_face_winding_state (draw_buffer); - break; - default: - g_warn_if_reached (); - } - } - COGL_FLAGS_FOREACH_END; - - ctx->current_draw_buffer_state_flushed |= state; - ctx->current_draw_buffer_changes &= ~state; + ctx->driver_vtable->framebuffer_flush_state (draw_buffer, + read_buffer, + state); } int cogl_framebuffer_get_red_bits (CoglFramebuffer *framebuffer) { - _cogl_framebuffer_init_bits (framebuffer); + CoglContext *ctx = framebuffer->context; + int red, green, blue, alpha; - return framebuffer->red_bits; + ctx->driver_vtable->framebuffer_query_bits (framebuffer, + &red, &green, &blue, &alpha); + + return red; } - int cogl_framebuffer_get_green_bits (CoglFramebuffer *framebuffer) { - _cogl_framebuffer_init_bits (framebuffer); + CoglContext *ctx = framebuffer->context; + int red, green, blue, alpha; - return framebuffer->green_bits; + ctx->driver_vtable->framebuffer_query_bits (framebuffer, + &red, &green, &blue, &alpha); + + return green; } int cogl_framebuffer_get_blue_bits (CoglFramebuffer *framebuffer) { - _cogl_framebuffer_init_bits (framebuffer); + CoglContext *ctx = framebuffer->context; + int red, green, blue, alpha; - return framebuffer->blue_bits; + ctx->driver_vtable->framebuffer_query_bits (framebuffer, + &red, &green, &blue, &alpha); + + return blue; } int cogl_framebuffer_get_alpha_bits (CoglFramebuffer *framebuffer) { - _cogl_framebuffer_init_bits (framebuffer); + CoglContext *ctx = framebuffer->context; + int red, green, blue, alpha; - return framebuffer->alpha_bits; + ctx->driver_vtable->framebuffer_query_bits (framebuffer, + &red, &green, &blue, &alpha); + + return alpha; } CoglColorMask @@ -2680,56 +1795,25 @@ _cogl_blit_framebuffer (unsigned int src_x, GL_NEAREST); } -static void -_cogl_framebuffer_discard_buffers_real (CoglFramebuffer *framebuffer, - unsigned long buffers) -{ -#ifdef GL_EXT_discard_framebuffer - CoglContext *ctx = framebuffer->context; - - if (ctx->glDiscardFramebuffer) - { - GLenum attachments[3]; - int i = 0; - - if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN) - { - if (buffers & COGL_BUFFER_BIT_COLOR) - attachments[i++] = GL_COLOR_EXT; - if (buffers & COGL_BUFFER_BIT_DEPTH) - attachments[i++] = GL_DEPTH_EXT; - if (buffers & COGL_BUFFER_BIT_STENCIL) - attachments[i++] = GL_STENCIL_EXT; - } - else - { - if (buffers & COGL_BUFFER_BIT_COLOR) - attachments[i++] = GL_COLOR_ATTACHMENT0; - if (buffers & COGL_BUFFER_BIT_DEPTH) - attachments[i++] = GL_DEPTH_ATTACHMENT; - if (buffers & COGL_BUFFER_BIT_STENCIL) - attachments[i++] = GL_STENCIL_ATTACHMENT; - } - - GE (ctx, glDiscardFramebuffer (GL_FRAMEBUFFER, i, attachments)); - } -#endif /* GL_EXT_discard_framebuffer */ -} - void cogl_framebuffer_discard_buffers (CoglFramebuffer *framebuffer, unsigned long buffers) { + CoglContext *ctx = framebuffer->context; + _COGL_RETURN_IF_FAIL (buffers & COGL_BUFFER_BIT_COLOR); - _cogl_framebuffer_discard_buffers_real (framebuffer, buffers); + ctx->driver_vtable->framebuffer_discard_buffers (framebuffer, buffers); } void cogl_framebuffer_finish (CoglFramebuffer *framebuffer) { + CoglContext *ctx = framebuffer->context; + _cogl_framebuffer_flush_journal (framebuffer); - GE (framebuffer->context, glFinish ()); + + ctx->driver_vtable->framebuffer_finish (framebuffer); } void @@ -3508,11 +2592,16 @@ _cogl_framebuffer_draw_attributes (CoglFramebuffer *framebuffer, else #endif { - _cogl_flush_attributes_state (framebuffer, pipeline, flags, - attributes, n_attributes); + CoglContext *ctx = framebuffer->context; - GE (framebuffer->context, - glDrawArrays ((GLenum)mode, first_vertex, n_vertices)); + ctx->driver_vtable->framebuffer_draw_attributes (framebuffer, + pipeline, + mode, + first_vertex, + n_vertices, + attributes, + n_attributes, + flags); } } @@ -3567,21 +2656,6 @@ cogl_framebuffer_vdraw_attributes (CoglFramebuffer *framebuffer, COGL_DRAW_SKIP_LEGACY_STATE); } -static size_t -sizeof_index_type (CoglIndicesType type) -{ - switch (type) - { - case COGL_INDICES_TYPE_UNSIGNED_BYTE: - return 1; - case COGL_INDICES_TYPE_UNSIGNED_SHORT: - return 2; - case COGL_INDICES_TYPE_UNSIGNED_INT: - return 4; - } - g_return_val_if_reached (0); -} - void _cogl_framebuffer_draw_indexed_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, @@ -3607,40 +2681,17 @@ _cogl_framebuffer_draw_indexed_attributes (CoglFramebuffer *framebuffer, else #endif { - CoglBuffer *buffer; - uint8_t *base; - size_t buffer_offset; - size_t index_size; - GLenum indices_gl_type = 0; + CoglContext *ctx = framebuffer->context; - _cogl_flush_attributes_state (framebuffer, pipeline, flags, - attributes, n_attributes); - - buffer = COGL_BUFFER (cogl_indices_get_buffer (indices)); - base = _cogl_buffer_bind (buffer, COGL_BUFFER_BIND_TARGET_INDEX_BUFFER); - buffer_offset = cogl_indices_get_offset (indices); - index_size = sizeof_index_type (cogl_indices_get_type (indices)); - - switch (cogl_indices_get_type (indices)) - { - case COGL_INDICES_TYPE_UNSIGNED_BYTE: - indices_gl_type = GL_UNSIGNED_BYTE; - break; - case COGL_INDICES_TYPE_UNSIGNED_SHORT: - indices_gl_type = GL_UNSIGNED_SHORT; - break; - case COGL_INDICES_TYPE_UNSIGNED_INT: - indices_gl_type = GL_UNSIGNED_INT; - break; - } - - GE (framebuffer->context, - glDrawElements ((GLenum)mode, - n_vertices, - indices_gl_type, - base + buffer_offset + index_size * first_vertex)); - - _cogl_buffer_unbind (buffer); + ctx->driver_vtable->framebuffer_draw_indexed_attributes (framebuffer, + pipeline, + mode, + first_vertex, + n_vertices, + indices, + attributes, + n_attributes, + flags); } } diff --git a/cogl/cogl-gles2-context.c b/cogl/cogl-gles2-context.c index 3d5fef45d..14f091c6e 100644 --- a/cogl/cogl-gles2-context.c +++ b/cogl/cogl-gles2-context.c @@ -39,6 +39,7 @@ #include "cogl-context-private.h" #include "cogl-display-private.h" #include "cogl-framebuffer-private.h" +#include "cogl-framebuffer-gl-private.h" #include "cogl-onscreen-template-private.h" #include "cogl-renderer-private.h" #include "cogl-swap-chain-private.h" @@ -424,7 +425,7 @@ transient_bind_read_buffer (CoglGLES2Context *gles2_ctx) } else { - _cogl_gl_framebuffer_bind (gles2_ctx->read_buffer, + _cogl_framebuffer_gl_bind (gles2_ctx->read_buffer, 0 /* target ignored */); return RESTORE_FB_FROM_ONSCREEN; @@ -448,14 +449,14 @@ restore_write_buffer (CoglGLES2Context *gles2_ctx, case RESTORE_FB_FROM_ONSCREEN: /* Note: we can't restore the original write buffer using - * _cogl_gl_framebuffer_bind() if it's an offscreen - * framebuffer because _cogl_gl_framebuffer_bind() doesn't + * _cogl_framebuffer_gl_bind() if it's an offscreen + * framebuffer because _cogl_framebuffer_gl_bind() doesn't * know about the fbo handle owned by the gles2 context. */ if (cogl_is_offscreen (gles2_ctx->write_buffer)) gl_bind_framebuffer_wrapper (GL_FRAMEBUFFER, 0); else - _cogl_gl_framebuffer_bind (gles2_ctx->write_buffer, GL_FRAMEBUFFER); + _cogl_framebuffer_gl_bind (gles2_ctx->write_buffer, GL_FRAMEBUFFER); break; case RESTORE_FB_NONE: diff --git a/cogl/cogl-renderer-private.h b/cogl/cogl-renderer-private.h index 72ea9d05b..565d2c967 100644 --- a/cogl/cogl-renderer-private.h +++ b/cogl/cogl-renderer-private.h @@ -29,6 +29,8 @@ #include "cogl-object-private.h" #include "cogl-winsys-private.h" #include "cogl-internal.h" +#include "cogl-driver.h" +#include "cogl-texture-driver.h" #ifdef COGL_HAS_XLIB_SUPPORT #include @@ -43,6 +45,8 @@ struct _CoglRenderer CoglObject _parent; CoglBool connected; CoglDriver driver_override; + const CoglDriverVtable *driver_vtable; + const CoglTextureDriver *texture_driver; const CoglWinsysVtable *winsys_vtable; CoglWinsysID winsys_id_override; GList *constraints; diff --git a/cogl/cogl-renderer.c b/cogl/cogl-renderer.c index d47e97210..bf971a19a 100644 --- a/cogl/cogl-renderer.c +++ b/cogl/cogl-renderer.c @@ -78,6 +78,15 @@ typedef const CoglWinsysVtable *(*CoglWinsysVtableGetter) (void); +#ifdef HAVE_COGL_GL +extern const CoglTextureDriver _cogl_texture_driver_gl; +extern const CoglDriverVtable _cogl_driver_gl; +#endif +#if defined (HAVE_COGL_GLES) || defined (HAVE_COGL_GLES2) +extern const CoglTextureDriver _cogl_texture_driver_gles; +extern const CoglDriverVtable _cogl_driver_gles; +#endif + static CoglWinsysVtableGetter _cogl_winsys_vtable_getters[] = { #ifdef COGL_HAS_GLX_SUPPORT @@ -332,6 +341,27 @@ found: #endif /* HAVE_DIRECTLY_LINKED_GL_LIBRARY */ + switch (renderer->driver) + { +#ifdef HAVE_COGL_GL + case COGL_DRIVER_GL: + renderer->driver_vtable = &_cogl_driver_gl; + renderer->texture_driver = &_cogl_texture_driver_gl; + break; +#endif + +#if defined (HAVE_COGL_GLES) || defined (HAVE_COGL_GLES2) + case COGL_DRIVER_GLES1: + case COGL_DRIVER_GLES2: + renderer->driver_vtable = &_cogl_driver_gles; + renderer->texture_driver = &_cogl_texture_driver_gles; + break; +#endif + + default: + g_assert_not_reached (); + } + return TRUE; } diff --git a/cogl/driver/gl/cogl-gl.c b/cogl/driver/gl/cogl-gl.c index e734805ff..991440f76 100644 --- a/cogl/driver/gl/cogl-gl.c +++ b/cogl/driver/gl/cogl-gl.c @@ -32,6 +32,7 @@ #include "cogl-context-private.h" #include "cogl-feature-private.h" #include "cogl-renderer-private.h" +#include "cogl-framebuffer-gl-private.h" static CoglBool _cogl_driver_pixel_format_from_gl_internal (CoglContext *context, @@ -522,5 +523,14 @@ _cogl_driver_gl = { _cogl_driver_pixel_format_from_gl_internal, _cogl_driver_pixel_format_to_gl, - _cogl_driver_update_features + _cogl_driver_update_features, + _cogl_offscreen_gl_allocate, + _cogl_offscreen_gl_free, + _cogl_framebuffer_gl_flush_state, + _cogl_framebuffer_gl_clear, + _cogl_framebuffer_gl_query_bits, + _cogl_framebuffer_gl_finish, + _cogl_framebuffer_gl_discard_buffers, + _cogl_framebuffer_gl_draw_attributes, + _cogl_framebuffer_gl_draw_indexed_attributes, }; diff --git a/cogl/driver/gles/cogl-gles.c b/cogl/driver/gles/cogl-gles.c index d0c96b844..85811e989 100644 --- a/cogl/driver/gles/cogl-gles.c +++ b/cogl/driver/gles/cogl-gles.c @@ -32,6 +32,7 @@ #include "cogl-feature-private.h" #include "cogl-renderer-private.h" #include "cogl-private.h" +#include "cogl-framebuffer-gl-private.h" #ifndef GL_UNSIGNED_INT_24_8 #define GL_UNSIGNED_INT_24_8 0x84FA @@ -341,5 +342,14 @@ _cogl_driver_gles = { _cogl_driver_pixel_format_from_gl_internal, _cogl_driver_pixel_format_to_gl, - _cogl_driver_update_features + _cogl_driver_update_features, + _cogl_offscreen_gl_allocate, + _cogl_offscreen_gl_free, + _cogl_framebuffer_gl_flush_state, + _cogl_framebuffer_gl_clear, + _cogl_framebuffer_gl_query_bits, + _cogl_framebuffer_gl_finish, + _cogl_framebuffer_gl_discard_buffers, + _cogl_framebuffer_gl_draw_attributes, + _cogl_framebuffer_gl_draw_indexed_attributes, };