diff --git a/.compat-cogl114.metadata b/.compat-cogl114.metadata new file mode 100644 index 0000000..4cad1c6 --- /dev/null +++ b/.compat-cogl114.metadata @@ -0,0 +1 @@ +ff9a60b54fe79eb336af9c1b686f71f6af6f84f9 SOURCES/cogl-1.14.0.tar.xz diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..00e2a73 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/cogl-1.14.0.tar.xz diff --git a/README.md b/README.md deleted file mode 100644 index 98f42b4..0000000 --- a/README.md +++ /dev/null @@ -1,4 +0,0 @@ -The master branch has no content - -Look at the c7 branch if you are working with CentOS-7, or the c4/c5/c6 branch for CentOS-4, 5 or 6 -If you find this file in a distro specific branch, it means that no content has been checked in yet diff --git a/SOURCES/Add-support-for-setting-up-stereo-CoglOnscreens.patch b/SOURCES/Add-support-for-setting-up-stereo-CoglOnscreens.patch new file mode 100644 index 0000000..b4cced9 --- /dev/null +++ b/SOURCES/Add-support-for-setting-up-stereo-CoglOnscreens.patch @@ -0,0 +1,392 @@ +From 0c547943ce2e7daae80bfbe72aa3e8ea88e1ba0b Mon Sep 17 00:00:00 2001 +From: "Owen W. Taylor" +Date: Mon, 28 Apr 2014 12:37:32 -0400 +Subject: [PATCH 4/8] Add support for setting up stereo CoglOnscreens + +If we want to show quad-buffer stereo with Cogl, we need to pick an +appropriate fbconfig for creating the CoglOnscreen objects. Add +cogl_onscreen_template_set_stereo_enabled() to indicate whether +stereo support is needed. + +Add cogl_framebuffer_get_stereo_mode() to see if a framebuffer was +created with stereo support. + +Add cogl_framebuffer_get_stereo_mode() to pick whether to draw to +the left, right, or both buffers. +--- + cogl/cogl-context-private.h | 1 + + cogl/cogl-framebuffer-private.h | 8 +++- + cogl/cogl-framebuffer.c | 41 +++++++++++++++++++ + cogl/cogl-framebuffer.h | 52 +++++++++++++++++++++++++ + cogl/cogl-onscreen-template.c | 8 ++++ + cogl/cogl-onscreen-template.h | 18 +++++++++ + cogl/cogl-types.h | 15 +++++++ + cogl/driver/gl/cogl-framebuffer-gl.c | 32 +++++++++++++++ + cogl/winsys/cogl-winsys-glx-feature-functions.h | 1 + + cogl/winsys/cogl-winsys-glx.c | 8 +++- + 10 files changed, 181 insertions(+), 3 deletions(-) + +diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h +index 31033d0..f725993 100644 +--- a/cogl/cogl-context-private.h ++++ b/cogl/cogl-context-private.h +@@ -242,6 +242,7 @@ struct _CoglContext + + CoglBool current_gl_dither_enabled; + CoglColorMask current_gl_color_mask; ++ GLenum current_gl_draw_buffer; + + /* Clipping */ + /* TRUE if we have a valid clipping stack flushed. In that case +diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h +index 267dbf6..747a699 100644 +--- a/cogl/cogl-framebuffer-private.h ++++ b/cogl/cogl-framebuffer-private.h +@@ -54,6 +54,7 @@ typedef struct + int samples_per_pixel; + CoglBool swap_throttled; + CoglBool depth_texture_enabled; ++ CoglBool stereo_enabled; + } CoglFramebufferConfig; + + /* Flags to pass to _cogl_offscreen_new_to_texture_full */ +@@ -78,7 +79,8 @@ typedef enum _CoglFramebufferStateIndex + COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION = 5, + COGL_FRAMEBUFFER_STATE_INDEX_COLOR_MASK = 6, + COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING = 7, +- COGL_FRAMEBUFFER_STATE_INDEX_MAX = 8 ++ COGL_FRAMEBUFFER_STATE_INDEX_STEREO_MODE = 8, ++ COGL_FRAMEBUFFER_STATE_INDEX_MAX = 9 + } CoglFramebufferStateIndex; + + typedef enum _CoglFramebufferState +@@ -90,7 +92,8 @@ typedef enum _CoglFramebufferState + COGL_FRAMEBUFFER_STATE_MODELVIEW = 1<<4, + COGL_FRAMEBUFFER_STATE_PROJECTION = 1<<5, + COGL_FRAMEBUFFER_STATE_COLOR_MASK = 1<<6, +- COGL_FRAMEBUFFER_STATE_FRONT_FACE_WINDING = 1<<7 ++ COGL_FRAMEBUFFER_STATE_FRONT_FACE_WINDING = 1<<7, ++ COGL_FRAMEBUFFER_STATE_STEREO_MODE = 1<<8 + } CoglFramebufferState; + + #define COGL_FRAMEBUFFER_STATE_ALL ((1<stereo_mode != b->stereo_mode ? ++ COGL_FRAMEBUFFER_STATE_STEREO_MODE : 0; ++} ++ + unsigned long + _cogl_framebuffer_compare (CoglFramebuffer *a, + CoglFramebuffer *b, +@@ -1125,6 +1133,10 @@ _cogl_framebuffer_compare (CoglFramebuffer *a, + differences |= + _cogl_framebuffer_compare_front_face_winding_state (a, b); + break; ++ case COGL_FRAMEBUFFER_STATE_INDEX_STEREO_MODE: ++ differences |= ++ _cogl_framebuffer_compare_stereo_mode (a, b); ++ break; + default: + g_warn_if_reached (); + } +@@ -1212,6 +1224,12 @@ _cogl_framebuffer_get_stencil_bits (CoglFramebuffer *framebuffer) + return bits.stencil; + } + ++gboolean ++cogl_framebuffer_get_is_stereo (CoglFramebuffer *framebuffer) ++{ ++ return framebuffer->config.stereo_enabled; ++} ++ + CoglColorMask + cogl_framebuffer_get_color_mask (CoglFramebuffer *framebuffer) + { +@@ -1232,6 +1250,29 @@ cogl_framebuffer_set_color_mask (CoglFramebuffer *framebuffer, + COGL_FRAMEBUFFER_STATE_COLOR_MASK; + } + ++CoglStereoMode ++cogl_framebuffer_get_stereo_mode (CoglFramebuffer *framebuffer) ++{ ++ return framebuffer->stereo_mode; ++} ++ ++void ++cogl_framebuffer_set_stereo_mode (CoglFramebuffer *framebuffer, ++ CoglStereoMode stereo_mode) ++{ ++ if (framebuffer->stereo_mode == stereo_mode) ++ return; ++ ++ /* Stereo mode changes don't go through the journal */ ++ _cogl_framebuffer_flush_journal (framebuffer); ++ ++ framebuffer->stereo_mode = stereo_mode; ++ ++ if (framebuffer->context->current_draw_buffer == framebuffer) ++ framebuffer->context->current_draw_buffer_changes |= ++ COGL_FRAMEBUFFER_STATE_STEREO_MODE; ++} ++ + CoglBool + cogl_framebuffer_get_dither_enabled (CoglFramebuffer *framebuffer) + { +diff --git a/cogl/cogl-framebuffer.h b/cogl/cogl-framebuffer.h +index e3fdb12..595a374 100644 +--- a/cogl/cogl-framebuffer.h ++++ b/cogl/cogl-framebuffer.h +@@ -733,6 +733,23 @@ cogl_framebuffer_get_alpha_bits (CoglFramebuffer *framebuffer); + int + cogl_framebuffer_get_depth_bits (CoglFramebuffer *framebuffer); + ++/* ++ * cogl_framebuffer_get_is_stereo: ++ * @framebuffer: a pointer to a #CoglFramebuffer ++ * ++ * Retrieves whether @framebuffer has separate left and right ++ * buffers for use with stereo drawing. See ++ * cogl_framebuffer_set_stereo_mode(). ++ * ++ * Return value: %TRUE if @framebuffer has separate left and ++ * right buffers. ++ * ++ * Since: 1.20 ++ * Stability: unstable ++ */ ++CoglBool ++cogl_framebuffer_get_is_stereo (CoglFramebuffer *framebuffer); ++ + /** + * cogl_framebuffer_get_dither_enabled: + * @framebuffer: a pointer to a #CoglFramebuffer +@@ -825,6 +842,41 @@ CoglPixelFormat + cogl_framebuffer_get_color_format (CoglFramebuffer *framebuffer); + + /** ++ * cogl_framebuffer_get_stereo_mode: ++ * @framebuffer: a pointer to a #CoglFramebuffer ++ * ++ * Gets the current #CoglStereoMode, which defines which stereo buffers ++ * should be drawn to. See cogl_framebuffer_set_stereo_mode(). ++ * ++ * Returns: A #CoglStereoMode ++ * Since: 1.20 ++ * Stability: unstable ++ */ ++CoglStereoMode ++cogl_framebuffer_get_stereo_mode (CoglFramebuffer *framebuffer); ++ ++/** ++ * cogl_framebuffer_set_stereo_mode: ++ * @framebuffer: a pointer to a #CoglFramebuffer ++ * @stereo_mode: A #CoglStereoMode specifying which stereo buffers ++ * should be drawn tow. ++ * ++ * Sets which stereo buffers should be drawn to. The default ++ * is %COGL_STEREO_BOTH, which means that both the left and ++ * right buffers will be affected by drawing. For this to have ++ * an effect, the display system must support stereo drawables, ++ * and the framebuffer must have been created with stereo ++ * enabled. (See cogl_onscreen_template_set_stereo_enabled(), ++ * cogl_framebuffer_get_is_stereo().) ++ * ++ * Since: 1.20 ++ * Stability: unstable ++ */ ++void ++cogl_framebuffer_set_stereo_mode (CoglFramebuffer *framebuffer, ++ CoglStereoMode stereo_mode); ++ ++/** + * cogl_framebuffer_set_depth_texture_enabled: + * @framebuffer: A #CoglFramebuffer + * @enabled: TRUE or FALSE +diff --git a/cogl/cogl-onscreen-template.c b/cogl/cogl-onscreen-template.c +index 5fa5b99..8854069 100644 +--- a/cogl/cogl-onscreen-template.c ++++ b/cogl/cogl-onscreen-template.c +@@ -88,3 +88,11 @@ cogl_onscreen_template_set_swap_throttled ( + { + onscreen_template->config.swap_throttled = throttled; + } ++ ++void ++cogl_onscreen_template_set_stereo_enabled ( ++ CoglOnscreenTemplate *onscreen_template, ++ CoglBool enabled) ++{ ++ onscreen_template->config.stereo_enabled = enabled; ++} +diff --git a/cogl/cogl-onscreen-template.h b/cogl/cogl-onscreen-template.h +index 58d88d4..f4645bb 100644 +--- a/cogl/cogl-onscreen-template.h ++++ b/cogl/cogl-onscreen-template.h +@@ -88,6 +88,24 @@ cogl_onscreen_template_set_swap_throttled ( + CoglBool throttled); + + /** ++ * cogl_onscreen_template_set_stereo_enabled: ++ * @onscreen_template: A #CoglOnscreenTemplate template framebuffer ++ * @enabled: Whether framebuffers are created with stereo buffers ++ * ++ * Sets whether future #CoglOnscreen framebuffers derived from this ++ * template are attempted to be created with both left and right ++ * buffers, for use with stereo display. If the display system ++ * does not support stereo, then creation of the framebuffer will ++ * fail. ++ * ++ * Since: 1.20 ++ * Stability: unstable ++ */ ++void ++cogl_onscreen_template_set_stereo_enabled ( ++ CoglOnscreenTemplate *onscreen_template, ++ CoglBool enabled); ++/** + * cogl_is_onscreen_template: + * @object: A #CoglObject pointer + * +diff --git a/cogl/cogl-types.h b/cogl/cogl-types.h +index 227b7ec..0a9b20c 100644 +--- a/cogl/cogl-types.h ++++ b/cogl/cogl-types.h +@@ -907,6 +907,21 @@ typedef enum { /*< prefix=COGL_READ_PIXELS >*/ + COGL_READ_PIXELS_COLOR_BUFFER = 1L << 0 + } CoglReadPixelsFlags; + ++/** ++ * CoglStereoMode: ++ * @COGL_STEREO_BOTH: draw to both stereo buffers ++ * @COGL_STEREO_LEFT: draw only to the left stereo buffer ++ * @COGL_STEREO_RIGHT: draw only to the left stereo buffer ++ * ++ * Represents how draw should affect the two buffers ++ * of a stereo framebuffer. See cogl_framebuffer_set_stereo_mode(). ++ */ ++typedef enum { ++ COGL_STEREO_BOTH, ++ COGL_STEREO_LEFT, ++ COGL_STEREO_RIGHT ++} CoglStereoMode; ++ + COGL_END_DECLS + + #endif /* __COGL_TYPES_H__ */ +diff --git a/cogl/driver/gl/cogl-framebuffer-gl.c b/cogl/driver/gl/cogl-framebuffer-gl.c +index 660098e..86b693b 100644 +--- a/cogl/driver/gl/cogl-framebuffer-gl.c ++++ b/cogl/driver/gl/cogl-framebuffer-gl.c +@@ -228,6 +228,35 @@ _cogl_framebuffer_gl_flush_front_face_winding_state (CoglFramebuffer *framebuffe + context->current_pipeline_age--; + } + ++static void ++_cogl_framebuffer_gl_flush_stereo_mode_state (CoglFramebuffer *framebuffer) ++{ ++ CoglContext *ctx = framebuffer->context; ++ GLenum draw_buffer = GL_BACK; ++ ++ if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN) ++ return; ++ ++ switch (framebuffer->stereo_mode) ++ { ++ case COGL_STEREO_BOTH: ++ draw_buffer = GL_BACK; ++ break; ++ case COGL_STEREO_LEFT: ++ draw_buffer = GL_BACK_LEFT; ++ break; ++ case COGL_STEREO_RIGHT: ++ draw_buffer = GL_BACK_RIGHT; ++ break; ++ } ++ ++ if (ctx->current_gl_draw_buffer != draw_buffer) ++ { ++ GE (ctx, glDrawBuffer (draw_buffer)); ++ ctx->current_gl_draw_buffer = draw_buffer; ++ } ++} ++ + void + _cogl_framebuffer_gl_bind (CoglFramebuffer *framebuffer, GLenum target) + { +@@ -365,6 +394,9 @@ _cogl_framebuffer_gl_flush_state (CoglFramebuffer *draw_buffer, + case COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING: + _cogl_framebuffer_gl_flush_front_face_winding_state (draw_buffer); + break; ++ case COGL_FRAMEBUFFER_STATE_INDEX_STEREO_MODE: ++ _cogl_framebuffer_gl_flush_stereo_mode_state (draw_buffer); ++ break; + default: + g_warn_if_reached (); + } +diff --git a/cogl/winsys/cogl-winsys-glx-feature-functions.h b/cogl/winsys/cogl-winsys-glx-feature-functions.h +index 9e7b49d..1e56c66 100644 +--- a/cogl/winsys/cogl-winsys-glx-feature-functions.h ++++ b/cogl/winsys/cogl-winsys-glx-feature-functions.h +@@ -179,6 +179,7 @@ COGL_WINSYS_FEATURE_BEGIN (255, 255, + 0, + COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT | + COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT) ++ + COGL_WINSYS_FEATURE_END () + + COGL_WINSYS_FEATURE_BEGIN (255, 255, +diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c +index a58a6ce..bff5178 100644 +--- a/cogl/winsys/cogl-winsys-glx.c ++++ b/cogl/winsys/cogl-winsys-glx.c +@@ -775,6 +775,11 @@ glx_attributes_from_framebuffer_config (CoglDisplay *display, + attributes[i++] = 1; + attributes[i++] = GLX_STENCIL_SIZE; + attributes[i++] = config->need_stencil ? 1: GLX_DONT_CARE; ++ if (config->stereo_enabled) ++ { ++ attributes[i++] = GLX_STEREO; ++ attributes[i++] = TRUE; ++ } + + if (glx_renderer->glx_major == 1 && glx_renderer->glx_minor >= 4 && + config->samples_per_pixel) +@@ -814,6 +819,7 @@ find_fbconfig (CoglDisplay *display, + xscreen_num, + attributes, + &n_configs); ++ + if (!configs || n_configs == 0) + { + _cogl_set_error (error, COGL_WINSYS_ERROR, +@@ -1722,7 +1728,7 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen, + rect[0], rect[1], x2, y2, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + } +- context->glDrawBuffer (GL_BACK); ++ context->glDrawBuffer (context->current_gl_draw_buffer); + } + + /* NB: unlike glXSwapBuffers, glXCopySubBuffer and +-- +1.9.3 + diff --git a/SOURCES/CoglTexturePixmapX11-add-support-for-stereo-content.patch b/SOURCES/CoglTexturePixmapX11-add-support-for-stereo-content.patch new file mode 100644 index 0000000..1eac9ce --- /dev/null +++ b/SOURCES/CoglTexturePixmapX11-add-support-for-stereo-content.patch @@ -0,0 +1,657 @@ +From e0243443ccb12eb1a9f62d9b4258bb111551998c Mon Sep 17 00:00:00 2001 +From: "Owen W. Taylor" +Date: Sat, 26 Apr 2014 16:38:58 -0400 +Subject: [PATCH 6/8] CoglTexturePixmapX11: add support for stereo content + +Add cogl_texture_pixmap_x11_new_left() and +cogl_texture_pixmap_x11_new_right() (which takes the left texture +as an argument) for texture pixmap rendering with stereo content. +The underlying GLXPixmap is created using a stereo visual and shared +between the left and right textures. +--- + cogl/cogl-glx-display-private.h | 3 +- + cogl/winsys/cogl-texture-pixmap-x11-private.h | 18 ++++ + cogl/winsys/cogl-texture-pixmap-x11.c | 92 +++++++++++++++++++-- + cogl/winsys/cogl-texture-pixmap-x11.h | 56 +++++++++++++ + cogl/winsys/cogl-winsys-egl-x11.c | 4 +- + cogl/winsys/cogl-winsys-glx.c | 113 ++++++++++++++++++-------- + cogl/winsys/cogl-winsys-private.h | 4 +- + 7 files changed, 246 insertions(+), 44 deletions(-) + +diff --git a/cogl/cogl-glx-display-private.h b/cogl/cogl-glx-display-private.h +index 69b1570..9f7ad47 100644 +--- a/cogl/cogl-glx-display-private.h ++++ b/cogl/cogl-glx-display-private.h +@@ -33,10 +33,11 @@ typedef struct _CoglGLXCachedConfig + int depth; + CoglBool found; + GLXFBConfig fb_config; ++ CoglBool stereo; + CoglBool can_mipmap; + } CoglGLXCachedConfig; + +-#define COGL_GLX_N_CACHED_CONFIGS 3 ++#define COGL_GLX_N_CACHED_CONFIGS 6 + + typedef struct _CoglGLXDisplay + { +diff --git a/cogl/winsys/cogl-texture-pixmap-x11-private.h b/cogl/winsys/cogl-texture-pixmap-x11-private.h +index b99dfa6..ce79bd3 100644 +--- a/cogl/winsys/cogl-texture-pixmap-x11-private.h ++++ b/cogl/winsys/cogl-texture-pixmap-x11-private.h +@@ -48,10 +48,27 @@ struct _CoglDamageRectangle + unsigned int y2; + }; + ++/* For stereo, there are a pair of textures, but we want to share most ++ * other state (the GLXPixmap, visual, etc.) The way we do this is that ++ * the left-eye texture has all the state (there is in fact, no internal ++ * difference between the a MONO and a LEFT texture ), and the ++ * right-eye texture simply points to the left eye texture, with all ++ * other fields ignored. ++ */ ++typedef enum ++{ ++ COGL_TEXTURE_PIXMAP_MONO, ++ COGL_TEXTURE_PIXMAP_LEFT, ++ COGL_TEXTURE_PIXMAP_RIGHT ++} CoglTexturePixmapStereoMode; ++ + struct _CoglTexturePixmapX11 + { + CoglTexture _parent; + ++ CoglTexturePixmapStereoMode stereo_mode; ++ CoglTexturePixmapX11 *left; /* Set only if stereo_mode=RIGHT */ ++ + Pixmap pixmap; + CoglTexture *tex; + +@@ -75,4 +92,5 @@ struct _CoglTexturePixmapX11 + CoglBool use_winsys_texture; + }; + ++ + #endif /* __COGL_TEXTURE_PIXMAP_X11_PRIVATE_H */ +diff --git a/cogl/winsys/cogl-texture-pixmap-x11.c b/cogl/winsys/cogl-texture-pixmap-x11.c +index 71d00ea..baf27e1 100644 +--- a/cogl/winsys/cogl-texture-pixmap-x11.c ++++ b/cogl/winsys/cogl-texture-pixmap-x11.c +@@ -274,11 +274,12 @@ set_damage_object_internal (CoglContext *ctx, + tex_pixmap); + } + +-CoglTexturePixmapX11 * +-cogl_texture_pixmap_x11_new (CoglContext *ctxt, +- uint32_t pixmap, +- CoglBool automatic_updates, +- CoglError **error) ++static CoglTexturePixmapX11 * ++_cogl_texture_pixmap_x11_new (CoglContext *ctxt, ++ uint32_t pixmap, ++ CoglBool automatic_updates, ++ CoglTexturePixmapStereoMode stereo_mode, ++ CoglError **error) + { + CoglTexturePixmapX11 *tex_pixmap = g_new (CoglTexturePixmapX11, 1); + Display *display = cogl_xlib_renderer_get_display (ctxt->display->renderer); +@@ -308,6 +309,8 @@ cogl_texture_pixmap_x11_new (CoglContext *ctxt, + &cogl_texture_pixmap_x11_vtable); + + tex_pixmap->pixmap = pixmap; ++ tex_pixmap->stereo_mode = stereo_mode; ++ tex_pixmap->left = NULL; + tex_pixmap->image = NULL; + tex_pixmap->shm_info.shmid = -1; + tex_pixmap->tex = NULL; +@@ -366,6 +369,52 @@ cogl_texture_pixmap_x11_new (CoglContext *ctxt, + return _cogl_texture_pixmap_x11_object_new (tex_pixmap); + } + ++CoglTexturePixmapX11 * ++cogl_texture_pixmap_x11_new (CoglContext *ctxt, ++ uint32_t pixmap, ++ CoglBool automatic_updates, ++ CoglError **error) ++ ++{ ++ return _cogl_texture_pixmap_x11_new (ctxt, pixmap, ++ automatic_updates, COGL_TEXTURE_PIXMAP_MONO, ++ error); ++} ++ ++CoglTexturePixmapX11 * ++cogl_texture_pixmap_x11_new_left (CoglContext *ctxt, ++ uint32_t pixmap, ++ CoglBool automatic_updates, ++ CoglError **error) ++{ ++ return _cogl_texture_pixmap_x11_new (ctxt, pixmap, ++ automatic_updates, COGL_TEXTURE_PIXMAP_LEFT, ++ error); ++} ++ ++CoglTexturePixmapX11 * ++cogl_texture_pixmap_x11_new_right (CoglTexturePixmapX11 *tfp_left) ++{ ++ CoglTexture *texture_left = COGL_TEXTURE (tfp_left); ++ CoglTexturePixmapX11 *tfp_right; ++ ++ g_return_val_if_fail (tfp_left->stereo_mode == COGL_TEXTURE_PIXMAP_LEFT, NULL); ++ ++ tfp_right = g_new0 (CoglTexturePixmapX11, 1); ++ tfp_right->stereo_mode = COGL_TEXTURE_PIXMAP_RIGHT; ++ tfp_right->left = cogl_object_ref (tfp_left); ++ ++ _cogl_texture_init (COGL_TEXTURE (tfp_right), ++ texture_left->context, ++ texture_left->width, ++ texture_left->height, ++ &cogl_texture_pixmap_x11_vtable); ++ ++ _cogl_texture_set_allocated (COGL_TEXTURE (tfp_right), TRUE); ++ ++ return _cogl_texture_pixmap_x11_object_new (tfp_right); ++} ++ + static CoglBool + _cogl_texture_pixmap_x11_allocate (CoglTexture *tex, + CoglError **error) +@@ -457,6 +506,9 @@ cogl_texture_pixmap_x11_update_area (CoglTexturePixmapX11 *tex_pixmap, + texture because we can't determine which will be needed until we + actually render something */ + ++ if (tex_pixmap->stereo_mode == COGL_TEXTURE_PIXMAP_RIGHT) ++ tex_pixmap = tex_pixmap->left; ++ + if (tex_pixmap->winsys) + { + const CoglWinsysVtable *winsys; +@@ -471,6 +523,9 @@ cogl_texture_pixmap_x11_update_area (CoglTexturePixmapX11 *tex_pixmap, + CoglBool + cogl_texture_pixmap_x11_is_using_tfp_extension (CoglTexturePixmapX11 *tex_pixmap) + { ++ if (tex_pixmap->stereo_mode == COGL_TEXTURE_PIXMAP_RIGHT) ++ tex_pixmap = tex_pixmap->left; ++ + return !!tex_pixmap->winsys; + } + +@@ -484,6 +539,8 @@ cogl_texture_pixmap_x11_set_damage_object (CoglTexturePixmapX11 *tex_pixmap, + + _COGL_GET_CONTEXT (ctxt, NO_RETVAL); + ++ g_return_if_fail (tex_pixmap->stereo_mode != COGL_TEXTURE_PIXMAP_RIGHT); ++ + damage_base = _cogl_xlib_get_damage_base (); + if (damage_base >= 0) + set_damage_object_internal (ctxt, tex_pixmap, damage, report_level); +@@ -648,12 +705,16 @@ static void + _cogl_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap, + CoglBool needs_mipmap) + { ++ CoglTexturePixmapStereoMode stereo_mode = tex_pixmap->stereo_mode; ++ if (stereo_mode == COGL_TEXTURE_PIXMAP_RIGHT) ++ tex_pixmap = tex_pixmap->left; ++ + if (tex_pixmap->winsys) + { + const CoglWinsysVtable *winsys = + _cogl_texture_pixmap_x11_get_winsys (tex_pixmap); + +- if (winsys->texture_pixmap_x11_update (tex_pixmap, needs_mipmap)) ++ if (winsys->texture_pixmap_x11_update (tex_pixmap, stereo_mode, needs_mipmap)) + { + _cogl_texture_pixmap_x11_set_use_winsys_texture (tex_pixmap, TRUE); + return; +@@ -670,8 +731,13 @@ _cogl_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap, + static CoglTexture * + _cogl_texture_pixmap_x11_get_texture (CoglTexturePixmapX11 *tex_pixmap) + { ++ CoglTexturePixmapX11 *original_pixmap = tex_pixmap; + CoglTexture *tex; + int i; ++ CoglTexturePixmapStereoMode stereo_mode = tex_pixmap->stereo_mode; ++ ++ if (stereo_mode == COGL_TEXTURE_PIXMAP_RIGHT) ++ tex_pixmap = tex_pixmap->left; + + /* We try getting the texture twice, once without flushing the + updates and once with. If pre_paint has been called already then +@@ -688,7 +754,7 @@ _cogl_texture_pixmap_x11_get_texture (CoglTexturePixmapX11 *tex_pixmap) + { + const CoglWinsysVtable *winsys = + _cogl_texture_pixmap_x11_get_winsys (tex_pixmap); +- tex = winsys->texture_pixmap_x11_get_texture (tex_pixmap); ++ tex = winsys->texture_pixmap_x11_get_texture (tex_pixmap, stereo_mode); + } + else + tex = tex_pixmap->tex; +@@ -696,7 +762,7 @@ _cogl_texture_pixmap_x11_get_texture (CoglTexturePixmapX11 *tex_pixmap) + if (tex) + return tex; + +- _cogl_texture_pixmap_x11_update (tex_pixmap, FALSE); ++ _cogl_texture_pixmap_x11_update (original_pixmap, FALSE); + } + + g_assert_not_reached (); +@@ -978,6 +1044,16 @@ _cogl_texture_pixmap_x11_free (CoglTexturePixmapX11 *tex_pixmap) + + _COGL_GET_CONTEXT (ctxt, NO_RETVAL); + ++ if (tex_pixmap->stereo_mode == COGL_TEXTURE_PIXMAP_RIGHT) ++ { ++ cogl_object_unref (tex_pixmap->left); ++ ++ /* Chain up */ ++ _cogl_texture_free (COGL_TEXTURE (tex_pixmap)); ++ ++ return; ++ } ++ + display = cogl_xlib_renderer_get_display (ctxt->display->renderer); + + set_damage_object_internal (ctxt, tex_pixmap, 0, 0); +diff --git a/cogl/winsys/cogl-texture-pixmap-x11.h b/cogl/winsys/cogl-texture-pixmap-x11.h +index 5d78af3..a3652a4 100644 +--- a/cogl/winsys/cogl-texture-pixmap-x11.h ++++ b/cogl/winsys/cogl-texture-pixmap-x11.h +@@ -103,6 +103,62 @@ cogl_texture_pixmap_x11_new (CoglContext *context, + CoglError **error); + + /** ++ * cogl_texture_pixmap_x11_new_left: ++ * @context: A #CoglContext ++ * @pixmap: A X11 pixmap ID ++ * @automatic_updates: Whether to automatically copy the contents of ++ * the pixmap to the texture. ++ * @error: A #CoglError for exceptions ++ * ++ * Creates one of a pair of textures to contain the contents of @pixmap, ++ * which has stereo content. (Different images for the right and left eyes.) ++ * The left image is drawn using this texture; the right image is drawn ++ * using a texture created by calling ++ * cogl_texture_pixmap_x11_new_right() and passing in this texture as an ++ * argument. ++ * ++ * In general, you should not use this function unless you have ++ * queried the %GLX_STEREO_TREE_EXT attribute of the corresponding ++ * window using glXQueryDrawable() and determined that the window is ++ * stereo. Note that this attribute can change over time and ++ * notification is also provided through events defined in the ++ * EXT_stereo_tree GLX extension. As long as the system has support for ++ * stereo content, drawing using the left and right pixmaps will not ++ * produce an error even if the window doesn't have stereo ++ * content any more, but drawing with the right pixmap will produce ++ * undefined output, so you need to listen for these events and ++ * re-render to avoid race conditions. (Recreating a non-stereo ++ * pixmap is not necessary, but may save resources.) ++ * ++ * Return value: a new #CoglTexturePixmapX11 instance ++ * ++ * Since: 1.20 ++ * Stability: Unstable ++ */ ++CoglTexturePixmapX11 * ++cogl_texture_pixmap_x11_new_left (CoglContext *context, ++ uint32_t pixmap, ++ CoglBool automatic_updates, ++ CoglError **error); ++ ++/** ++ * cogl_texture_pixmap_x11_new_right: ++ * @left_texture: A #CoglTexturePixmapX11 instance created with ++ * cogl_texture_pixmap_x11_new_left(). ++ * ++ * Creates a texture object that corresponds to the right-eye image ++ * of a pixmap with stereo content. @left_texture must have been ++ * created using cogl_texture_pixmap_x11_new_left(). ++ * ++ * Return value: a new #CoglTexturePixmapX11 instance ++ * ++ * Since: 1.20 ++ * Stability: Unstable ++ */ ++CoglTexturePixmapX11 * ++cogl_texture_pixmap_x11_new_right (CoglTexturePixmapX11 *left_texture); ++ ++/** + * cogl_texture_pixmap_x11_update_area: + * @texture: A #CoglTexturePixmapX11 instance + * @x: x coordinate of the area to update +diff --git a/cogl/winsys/cogl-winsys-egl-x11.c b/cogl/winsys/cogl-winsys-egl-x11.c +index 3e91b99..6752029 100644 +--- a/cogl/winsys/cogl-winsys-egl-x11.c ++++ b/cogl/winsys/cogl-winsys-egl-x11.c +@@ -760,6 +760,7 @@ _cogl_winsys_texture_pixmap_x11_free (CoglTexturePixmapX11 *tex_pixmap) + + static CoglBool + _cogl_winsys_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap, ++ CoglBool right, + CoglBool needs_mipmap) + { + if (needs_mipmap) +@@ -774,7 +775,8 @@ _cogl_winsys_texture_pixmap_x11_damage_notify (CoglTexturePixmapX11 *tex_pixmap) + } + + static CoglTexture * +-_cogl_winsys_texture_pixmap_x11_get_texture (CoglTexturePixmapX11 *tex_pixmap) ++_cogl_winsys_texture_pixmap_x11_get_texture (CoglTexturePixmapX11 *tex_pixmap, ++ CoglBool right) + { + CoglTexturePixmapEGL *egl_tex_pixmap = tex_pixmap->winsys; + +diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c +index bff5178..334691c 100644 +--- a/cogl/winsys/cogl-winsys-glx.c ++++ b/cogl/winsys/cogl-winsys-glx.c +@@ -89,16 +89,21 @@ typedef struct _CoglOnscreenGLX + CoglBool pending_resize_notify; + } CoglOnscreenGLX; + ++typedef struct _CoglPixmapTextureEyeGLX ++{ ++ CoglTexture *glx_tex; ++ CoglBool bind_tex_image_queued; ++ CoglBool pixmap_bound; ++} CoglPixmapTextureEyeGLX; ++ + typedef struct _CoglTexturePixmapGLX + { + GLXPixmap glx_pixmap; + CoglBool has_mipmap_space; + CoglBool can_mipmap; + +- CoglTexture *glx_tex; +- +- CoglBool bind_tex_image_queued; +- CoglBool pixmap_bound; ++ CoglPixmapTextureEyeGLX left; ++ CoglPixmapTextureEyeGLX right; + } CoglTexturePixmapGLX; + + /* Define a set of arrays containing the functions required from GL +@@ -1965,6 +1970,7 @@ _cogl_winsys_xlib_get_visual_info (void) + static CoglBool + get_fbconfig_for_depth (CoglContext *context, + unsigned int depth, ++ CoglBool stereo, + GLXFBConfig *fbconfig_ret, + CoglBool *can_mipmap_ret) + { +@@ -1982,11 +1988,12 @@ get_fbconfig_for_depth (CoglContext *context, + glx_renderer = context->display->renderer->winsys; + glx_display = context->display->winsys; + +- /* Check if we've already got a cached config for this depth */ ++ /* Check if we've already got a cached config for this depth and stereo */ + for (i = 0; i < COGL_GLX_N_CACHED_CONFIGS; i++) + if (glx_display->glx_cached_configs[i].depth == -1) + spare_cache_slot = i; +- else if (glx_display->glx_cached_configs[i].depth == depth) ++ else if (glx_display->glx_cached_configs[i].depth == depth && ++ glx_display->glx_cached_configs[i].stereo == stereo) + { + *fbconfig_ret = glx_display->glx_cached_configs[i].fb_config; + *can_mipmap_ret = glx_display->glx_cached_configs[i].can_mipmap; +@@ -2030,6 +2037,13 @@ get_fbconfig_for_depth (CoglContext *context, + if (value != depth && (value - alpha) != depth) + continue; + ++ glx_renderer->glXGetFBConfigAttrib (dpy, ++ fbconfigs[i], ++ GLX_STEREO, ++ &value); ++ if (!!value != !!stereo) ++ continue; ++ + if (glx_renderer->glx_major == 1 && glx_renderer->glx_minor >= 4) + { + glx_renderer->glXGetFBConfigAttrib (dpy, +@@ -2187,7 +2201,9 @@ try_create_glx_pixmap (CoglContext *context, + glx_renderer = renderer->winsys; + dpy = xlib_renderer->xdpy; + +- if (!get_fbconfig_for_depth (context, depth, &fb_config, ++ if (!get_fbconfig_for_depth (context, depth, ++ tex_pixmap->stereo_mode != COGL_TEXTURE_PIXMAP_MONO, ++ &fb_config, + &glx_tex_pixmap->can_mipmap)) + { + COGL_NOTE (TEXTURE_PIXMAP, "No suitable FBConfig found for depth %i", +@@ -2276,10 +2292,13 @@ _cogl_winsys_texture_pixmap_x11_create (CoglTexturePixmapX11 *tex_pixmap) + glx_tex_pixmap->can_mipmap = FALSE; + glx_tex_pixmap->has_mipmap_space = FALSE; + +- glx_tex_pixmap->glx_tex = NULL; ++ glx_tex_pixmap->left.glx_tex = NULL; ++ glx_tex_pixmap->right.glx_tex = NULL; + +- glx_tex_pixmap->bind_tex_image_queued = TRUE; +- glx_tex_pixmap->pixmap_bound = FALSE; ++ glx_tex_pixmap->left.bind_tex_image_queued = TRUE; ++ glx_tex_pixmap->right.bind_tex_image_queued = TRUE; ++ glx_tex_pixmap->left.pixmap_bound = FALSE; ++ glx_tex_pixmap->right.pixmap_bound = FALSE; + + tex_pixmap->winsys = glx_tex_pixmap; + +@@ -2306,10 +2325,14 @@ free_glx_pixmap (CoglContext *context, + xlib_renderer = _cogl_xlib_renderer_get_data (renderer); + glx_renderer = renderer->winsys; + +- if (glx_tex_pixmap->pixmap_bound) ++ if (glx_tex_pixmap->left.pixmap_bound) + glx_renderer->glXReleaseTexImage (xlib_renderer->xdpy, + glx_tex_pixmap->glx_pixmap, + GLX_FRONT_LEFT_EXT); ++ if (glx_tex_pixmap->right.pixmap_bound) ++ glx_renderer->glXReleaseTexImage (xlib_renderer->xdpy, ++ glx_tex_pixmap->glx_pixmap, ++ GLX_FRONT_RIGHT_EXT); + + /* FIXME - we need to trap errors and synchronize here because + * of ordering issues between the XPixmap destruction and the +@@ -2334,7 +2357,8 @@ free_glx_pixmap (CoglContext *context, + _cogl_xlib_renderer_untrap_errors (renderer, &trap_state); + + glx_tex_pixmap->glx_pixmap = None; +- glx_tex_pixmap->pixmap_bound = FALSE; ++ glx_tex_pixmap->left.pixmap_bound = FALSE; ++ glx_tex_pixmap->right.pixmap_bound = FALSE; + } + + static void +@@ -2349,8 +2373,11 @@ _cogl_winsys_texture_pixmap_x11_free (CoglTexturePixmapX11 *tex_pixmap) + + free_glx_pixmap (COGL_TEXTURE (tex_pixmap)->context, glx_tex_pixmap); + +- if (glx_tex_pixmap->glx_tex) +- cogl_object_unref (glx_tex_pixmap->glx_tex); ++ if (glx_tex_pixmap->left.glx_tex) ++ cogl_object_unref (glx_tex_pixmap->left.glx_tex); ++ ++ if (glx_tex_pixmap->right.glx_tex) ++ cogl_object_unref (glx_tex_pixmap->right.glx_tex); + + tex_pixmap->winsys = NULL; + g_free (glx_tex_pixmap); +@@ -2358,13 +2385,27 @@ _cogl_winsys_texture_pixmap_x11_free (CoglTexturePixmapX11 *tex_pixmap) + + static CoglBool + _cogl_winsys_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap, ++ CoglTexturePixmapStereoMode stereo_mode, + CoglBool needs_mipmap) + { + CoglTexture *tex = COGL_TEXTURE (tex_pixmap); + CoglContext *ctx = COGL_TEXTURE (tex_pixmap)->context; + CoglTexturePixmapGLX *glx_tex_pixmap = tex_pixmap->winsys; ++ CoglPixmapTextureEyeGLX *texture_info; ++ int buffer; + CoglGLXRenderer *glx_renderer; + ++ if (stereo_mode == COGL_TEXTURE_PIXMAP_RIGHT) ++ { ++ texture_info = &glx_tex_pixmap->right; ++ buffer = GLX_FRONT_RIGHT_EXT; ++ } ++ else ++ { ++ texture_info = &glx_tex_pixmap->left; ++ buffer = GLX_FRONT_LEFT_EXT; ++ } ++ + /* If we don't have a GLX pixmap then fallback */ + if (glx_tex_pixmap->glx_pixmap == None) + return FALSE; +@@ -2372,7 +2413,7 @@ _cogl_winsys_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap, + glx_renderer = ctx->display->renderer->winsys; + + /* Lazily create a texture to hold the pixmap */ +- if (glx_tex_pixmap->glx_tex == NULL) ++ if (texture_info->glx_tex == NULL) + { + CoglPixelFormat texture_format; + CoglError *error = NULL; +@@ -2383,14 +2424,14 @@ _cogl_winsys_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap, + + if (should_use_rectangle (ctx)) + { +- glx_tex_pixmap->glx_tex = COGL_TEXTURE ( ++ texture_info->glx_tex = COGL_TEXTURE ( + cogl_texture_rectangle_new_with_size (ctx, + tex->width, + tex->height, + texture_format, + &error)); + +- if (glx_tex_pixmap->glx_tex) ++ if (texture_info->glx_tex) + COGL_NOTE (TEXTURE_PIXMAP, "Created a texture rectangle for %p", + tex_pixmap); + else +@@ -2405,13 +2446,13 @@ _cogl_winsys_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap, + } + else + { +- glx_tex_pixmap->glx_tex = COGL_TEXTURE ( ++ texture_info->glx_tex = COGL_TEXTURE ( + cogl_texture_2d_new_with_size (ctx, + tex->width, + tex->height, + texture_format)); + +- if (cogl_texture_allocate (glx_tex_pixmap->glx_tex, &error)) ++ if (cogl_texture_allocate (texture_info->glx_tex, &error)) + COGL_NOTE (TEXTURE_PIXMAP, "Created a texture 2d for %p", + tex_pixmap); + else +@@ -2449,36 +2490,37 @@ _cogl_winsys_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap, + "updates for %p because creating the GLXPixmap " + "with mipmap support failed", tex_pixmap); + +- if (glx_tex_pixmap->glx_tex) +- cogl_object_unref (glx_tex_pixmap->glx_tex); ++ if (texture_info->glx_tex) ++ cogl_object_unref (texture_info->glx_tex); + return FALSE; + } + +- glx_tex_pixmap->bind_tex_image_queued = TRUE; ++ glx_tex_pixmap->left.bind_tex_image_queued = TRUE; ++ glx_tex_pixmap->right.bind_tex_image_queued = TRUE; + } + } + +- if (glx_tex_pixmap->bind_tex_image_queued) ++ if (texture_info->bind_tex_image_queued) + { + GLuint gl_handle, gl_target; + CoglXlibRenderer *xlib_renderer = + _cogl_xlib_renderer_get_data (ctx->display->renderer); + +- cogl_texture_get_gl_texture (glx_tex_pixmap->glx_tex, ++ cogl_texture_get_gl_texture (texture_info->glx_tex, + &gl_handle, &gl_target); + + COGL_NOTE (TEXTURE_PIXMAP, "Rebinding GLXPixmap for %p", tex_pixmap); + + _cogl_bind_gl_texture_transient (gl_target, gl_handle, FALSE); + +- if (glx_tex_pixmap->pixmap_bound) ++ if (texture_info->pixmap_bound) + glx_renderer->glXReleaseTexImage (xlib_renderer->xdpy, + glx_tex_pixmap->glx_pixmap, +- GLX_FRONT_LEFT_EXT); ++ buffer); + + glx_renderer->glXBindTexImage (xlib_renderer->xdpy, + glx_tex_pixmap->glx_pixmap, +- GLX_FRONT_LEFT_EXT, ++ buffer, + NULL); + + /* According to the recommended usage in the spec for +@@ -2491,10 +2533,10 @@ _cogl_winsys_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap, + * on Mesa and NVidia drivers and it is also what Compiz does so + * it is probably ok */ + +- glx_tex_pixmap->bind_tex_image_queued = FALSE; +- glx_tex_pixmap->pixmap_bound = TRUE; ++ texture_info->bind_tex_image_queued = FALSE; ++ texture_info->pixmap_bound = TRUE; + +- _cogl_texture_2d_externally_modified (glx_tex_pixmap->glx_tex); ++ _cogl_texture_2d_externally_modified (texture_info->glx_tex); + } + + return TRUE; +@@ -2505,15 +2547,20 @@ _cogl_winsys_texture_pixmap_x11_damage_notify (CoglTexturePixmapX11 *tex_pixmap) + { + CoglTexturePixmapGLX *glx_tex_pixmap = tex_pixmap->winsys; + +- glx_tex_pixmap->bind_tex_image_queued = TRUE; ++ glx_tex_pixmap->left.bind_tex_image_queued = TRUE; ++ glx_tex_pixmap->right.bind_tex_image_queued = TRUE; + } + + static CoglTexture * +-_cogl_winsys_texture_pixmap_x11_get_texture (CoglTexturePixmapX11 *tex_pixmap) ++_cogl_winsys_texture_pixmap_x11_get_texture (CoglTexturePixmapX11 *tex_pixmap, ++ CoglTexturePixmapStereoMode stereo_mode) + { + CoglTexturePixmapGLX *glx_tex_pixmap = tex_pixmap->winsys; + +- return glx_tex_pixmap->glx_tex; ++ if (stereo_mode == COGL_TEXTURE_PIXMAP_RIGHT) ++ return glx_tex_pixmap->right.glx_tex; ++ else ++ return glx_tex_pixmap->left.glx_tex; + } + + static void +diff --git a/cogl/winsys/cogl-winsys-private.h b/cogl/winsys/cogl-winsys-private.h +index 7cd2b24..31a1af9 100644 +--- a/cogl/winsys/cogl-winsys-private.h ++++ b/cogl/winsys/cogl-winsys-private.h +@@ -172,13 +172,15 @@ typedef struct _CoglWinsysVtable + + CoglBool + (*texture_pixmap_x11_update) (CoglTexturePixmapX11 *tex_pixmap, ++ CoglTexturePixmapStereoMode stereo_mode, + CoglBool needs_mipmap); + + void + (*texture_pixmap_x11_damage_notify) (CoglTexturePixmapX11 *tex_pixmap); + + CoglTexture * +- (*texture_pixmap_x11_get_texture) (CoglTexturePixmapX11 *tex_pixmap); ++ (*texture_pixmap_x11_get_texture) (CoglTexturePixmapX11 *tex_pixmap, ++ CoglTexturePixmapStereoMode stereo_mode); + #endif + + void +-- +1.9.3 + diff --git a/SOURCES/cogl-1.14.0-21-ge26464f.patch b/SOURCES/cogl-1.14.0-21-ge26464f.patch new file mode 100644 index 0000000..80e96c5 --- /dev/null +++ b/SOURCES/cogl-1.14.0-21-ge26464f.patch @@ -0,0 +1,1434 @@ +Only things missing here from upstream are translations and .gitignore changes + +diff --git a/cogl/Makefile.am b/cogl/Makefile.am +index 33214ab..80d3b09 100644 +--- a/cogl/Makefile.am ++++ b/cogl/Makefile.am +@@ -349,6 +349,8 @@ cogl_sources_c = \ + $(srcdir)/cogl-pipeline-snippet.c \ + $(srcdir)/cogl-pipeline-cache.h \ + $(srcdir)/cogl-pipeline-cache.c \ ++ $(srcdir)/cogl-pipeline-hash-table.h \ ++ $(srcdir)/cogl-pipeline-hash-table.c \ + $(srcdir)/cogl-material-compat.c \ + $(srcdir)/cogl-program.c \ + $(srcdir)/cogl-program-private.h \ +@@ -552,7 +554,7 @@ include $(top_srcdir)/build/autotools/Makefile.am.enums + + lib_LTLIBRARIES += libcogl.la + +-libcogl_la_LIBADD = -lm $(COGL_DEP_LIBS) $(COGL_EXTRA_LDFLAGS) ++libcogl_la_LIBADD = $(LIBM) $(COGL_DEP_LIBS) $(COGL_EXTRA_LDFLAGS) + if !USE_GLIB + libcogl_la_LIBADD += $(top_builddir)/deps/glib/libglib.la + libcogl_la_LIBADD += $(top_builddir)/deps/gmodule/libgmodule.la +diff --git a/cogl/cogl-bitmap-pixbuf.c b/cogl/cogl-bitmap-pixbuf.c +index a02b253..ad34234 100644 +--- a/cogl/cogl-bitmap-pixbuf.c ++++ b/cogl/cogl-bitmap-pixbuf.c +@@ -125,11 +125,24 @@ _cogl_bitmap_from_file (CoglContext *ctx, + /* allocate buffer big enough to hold pixel data */ + bmp = _cogl_bitmap_new_with_malloc_buffer (ctx, + width, height, +- COGL_PIXEL_FORMAT_ARGB_8888); ++ COGL_PIXEL_FORMAT_ARGB_8888, ++ error); ++ if (bmp == NULL) ++ { ++ CFRelease (image); ++ return NULL; ++ } + rowstride = cogl_bitmap_get_rowstride (bmp); + out_data = _cogl_bitmap_map (bmp, + COGL_BUFFER_ACCESS_WRITE, +- COGL_BUFFER_MAP_HINT_DISCARD); ++ COGL_BUFFER_MAP_HINT_DISCARD, ++ error); ++ if (out_data == NULL) ++ { ++ cogl_object_unref (bmp); ++ CFRelease (image); ++ return NULL; ++ } + + /* render to buffer */ + color_space = CGColorSpaceCreateWithName (kCGColorSpaceGenericRGB); +diff --git a/cogl/cogl-matrix.h b/cogl/cogl-matrix.h +index 90f3ea9..a136ea0 100644 +--- a/cogl/cogl-matrix.h ++++ b/cogl/cogl-matrix.h +@@ -27,6 +27,8 @@ + #ifndef __COGL_MATRIX_H + #define __COGL_MATRIX_H + ++#include ++ + #ifdef COGL_HAS_GTYPE_SUPPORT + #include + #endif /* COGL_HAS_GTYPE_SUPPORT */ +diff --git a/cogl/cogl-pipeline-cache.c b/cogl/cogl-pipeline-cache.c +index fab3614..df4c433 100644 +--- a/cogl/cogl-pipeline-cache.c ++++ b/cogl/cogl-pipeline-cache.c +@@ -3,7 +3,7 @@ + * + * An object oriented GL/GLES Abstraction/Utility Layer + * +- * Copyright (C) 2011 Intel Corporation. ++ * Copyright (C) 2011, 2013 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public +@@ -32,133 +32,47 @@ + #include "cogl-context-private.h" + #include "cogl-pipeline-private.h" + #include "cogl-pipeline-cache.h" ++#include "cogl-pipeline-hash-table.h" + + struct _CoglPipelineCache + { +- GHashTable *fragment_hash; +- GHashTable *vertex_hash; +- GHashTable *combined_hash; ++ CoglPipelineHashTable fragment_hash; ++ CoglPipelineHashTable vertex_hash; ++ CoglPipelineHashTable combined_hash; + }; + +-static unsigned int +-pipeline_fragment_hash (const void *data) +-{ +- unsigned int fragment_state; +- unsigned int layer_fragment_state; +- +- _COGL_GET_CONTEXT (ctx, 0); +- +- fragment_state = +- _cogl_pipeline_get_state_for_fragment_codegen (ctx); +- layer_fragment_state = +- _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx); +- +- return _cogl_pipeline_hash ((CoglPipeline *)data, +- fragment_state, layer_fragment_state, +- 0); +-} +- +-static CoglBool +-pipeline_fragment_equal (const void *a, const void *b) ++CoglPipelineCache * ++_cogl_pipeline_cache_new (void) + { ++ CoglPipelineCache *cache = g_new (CoglPipelineCache, 1); ++ unsigned long vertex_state; ++ unsigned long layer_vertex_state; + unsigned int fragment_state; + unsigned int layer_fragment_state; + + _COGL_GET_CONTEXT (ctx, 0); + ++ vertex_state = ++ COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN; ++ layer_vertex_state = ++ COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN; + fragment_state = + _cogl_pipeline_get_state_for_fragment_codegen (ctx); + layer_fragment_state = + _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx); + +- return _cogl_pipeline_equal ((CoglPipeline *)a, (CoglPipeline *)b, +- fragment_state, layer_fragment_state, +- 0); +-} +- +-static unsigned int +-pipeline_vertex_hash (const void *data) +-{ +- unsigned long vertex_state = +- COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN; +- unsigned long layer_vertex_state = +- COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN; +- +- return _cogl_pipeline_hash ((CoglPipeline *)data, +- vertex_state, layer_vertex_state, +- 0); +-} +- +-static CoglBool +-pipeline_vertex_equal (const void *a, const void *b) +-{ +- unsigned long vertex_state = +- COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN; +- unsigned long layer_vertex_state = +- COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN; +- +- return _cogl_pipeline_equal ((CoglPipeline *)a, (CoglPipeline *)b, +- vertex_state, layer_vertex_state, +- 0); +-} +- +-static unsigned int +-pipeline_combined_hash (const void *data) +-{ +- unsigned int combined_state; +- unsigned int layer_combined_state; +- +- _COGL_GET_CONTEXT (ctx, 0); +- +- combined_state = +- _cogl_pipeline_get_state_for_fragment_codegen (ctx) | +- COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN; +- layer_combined_state = +- _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx) | +- COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN; +- +- return _cogl_pipeline_hash ((CoglPipeline *)data, +- combined_state, layer_combined_state, +- 0); +-} +- +-static CoglBool +-pipeline_combined_equal (const void *a, const void *b) +-{ +- unsigned int combined_state; +- unsigned int layer_combined_state; +- +- _COGL_GET_CONTEXT (ctx, 0); +- +- combined_state = +- _cogl_pipeline_get_state_for_fragment_codegen (ctx) | +- COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN; +- layer_combined_state = +- _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx) | +- COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN; +- +- return _cogl_pipeline_equal ((CoglPipeline *)a, (CoglPipeline *)b, +- combined_state, layer_combined_state, +- 0); +-} +- +-CoglPipelineCache * +-_cogl_pipeline_cache_new (void) +-{ +- CoglPipelineCache *cache = g_new (CoglPipelineCache, 1); +- +- cache->fragment_hash = g_hash_table_new_full (pipeline_fragment_hash, +- pipeline_fragment_equal, +- cogl_object_unref, +- cogl_object_unref); +- cache->vertex_hash = g_hash_table_new_full (pipeline_vertex_hash, +- pipeline_vertex_equal, +- cogl_object_unref, +- cogl_object_unref); +- cache->combined_hash = g_hash_table_new_full (pipeline_combined_hash, +- pipeline_combined_equal, +- cogl_object_unref, +- cogl_object_unref); ++ _cogl_pipeline_hash_table_init (&cache->vertex_hash, ++ vertex_state, ++ layer_vertex_state, ++ "vertex shaders"); ++ _cogl_pipeline_hash_table_init (&cache->fragment_hash, ++ fragment_state, ++ layer_fragment_state, ++ "fragment shaders"); ++ _cogl_pipeline_hash_table_init (&cache->combined_hash, ++ vertex_state | fragment_state, ++ layer_vertex_state | layer_fragment_state, ++ "programs"); + + return cache; + } +@@ -166,9 +80,9 @@ _cogl_pipeline_cache_new (void) + void + _cogl_pipeline_cache_free (CoglPipelineCache *cache) + { +- g_hash_table_destroy (cache->fragment_hash); +- g_hash_table_destroy (cache->vertex_hash); +- g_hash_table_destroy (cache->combined_hash); ++ _cogl_pipeline_hash_table_destroy (&cache->fragment_hash); ++ _cogl_pipeline_hash_table_destroy (&cache->vertex_hash); ++ _cogl_pipeline_hash_table_destroy (&cache->combined_hash); + g_free (cache); + } + +@@ -176,107 +90,22 @@ CoglPipeline * + _cogl_pipeline_cache_get_fragment_template (CoglPipelineCache *cache, + CoglPipeline *key_pipeline) + { +- CoglPipeline *template = +- g_hash_table_lookup (cache->fragment_hash, key_pipeline); +- +- if (template == NULL) +- { +- /* XXX: I wish there was a way to insert into a GHashTable with +- * a pre-calculated hash value since there is a cost to +- * calculating the hash of a CoglPipeline and in this case we +- * know we have already called _cogl_pipeline_hash during the +- * lookup so we could pass the value through to here to avoid +- * hashing it again. +- */ +- +- /* XXX: Any keys referenced by the hash table need to remain +- * valid all the while that there are corresponding values, +- * so for now we simply make a copy of the current authority +- * pipeline. +- * +- * FIXME: A problem with this is that our key into the cache may +- * hold references to some arbitrary user textures which will +- * now be kept alive indefinitly which is a shame. A better +- * solution will be to derive a special "key pipeline" from the +- * authority which derives from the base Cogl pipeline (to avoid +- * affecting the lifetime of any other pipelines) and only takes +- * a copy of the state that relates to the fragment shader and +- * references small dummy textures instead of potentially large +- * user textures. */ +- template = cogl_pipeline_copy (key_pipeline); +- +- g_hash_table_insert (cache->fragment_hash, +- template, +- cogl_object_ref (template)); +- +- if (G_UNLIKELY (g_hash_table_size (cache->fragment_hash) > 50)) +- { +- static CoglBool seen = FALSE; +- if (!seen) +- g_warning ("Over 50 separate fragment shaders have been " +- "generated which is very unusual, so something " +- "is probably wrong!\n"); +- seen = TRUE; +- } +- } +- +- return template; ++ return _cogl_pipeline_hash_table_get (&cache->fragment_hash, ++ key_pipeline); + } + + CoglPipeline * + _cogl_pipeline_cache_get_vertex_template (CoglPipelineCache *cache, + CoglPipeline *key_pipeline) + { +- CoglPipeline *template = +- g_hash_table_lookup (cache->vertex_hash, key_pipeline); +- +- if (template == NULL) +- { +- template = cogl_pipeline_copy (key_pipeline); +- +- g_hash_table_insert (cache->vertex_hash, +- template, +- cogl_object_ref (template)); +- +- if (G_UNLIKELY (g_hash_table_size (cache->vertex_hash) > 50)) +- { +- static CoglBool seen = FALSE; +- if (!seen) +- g_warning ("Over 50 separate vertex shaders have been " +- "generated which is very unusual, so something " +- "is probably wrong!\n"); +- seen = TRUE; +- } +- } +- +- return template; ++ return _cogl_pipeline_hash_table_get (&cache->vertex_hash, ++ key_pipeline); + } + + CoglPipeline * + _cogl_pipeline_cache_get_combined_template (CoglPipelineCache *cache, + CoglPipeline *key_pipeline) + { +- CoglPipeline *template = +- g_hash_table_lookup (cache->combined_hash, key_pipeline); +- +- if (template == NULL) +- { +- template = cogl_pipeline_copy (key_pipeline); +- +- g_hash_table_insert (cache->combined_hash, +- template, +- cogl_object_ref (template)); +- +- if (G_UNLIKELY (g_hash_table_size (cache->combined_hash) > 50)) +- { +- static CoglBool seen = FALSE; +- if (!seen) +- g_warning ("Over 50 separate programs have been " +- "generated which is very unusual, so something " +- "is probably wrong!\n"); +- seen = TRUE; +- } +- } +- +- return template; ++ return _cogl_pipeline_hash_table_get (&cache->combined_hash, ++ key_pipeline); + } +diff --git a/cogl/cogl-pipeline-hash-table.c b/cogl/cogl-pipeline-hash-table.c +new file mode 100644 +index 0000000..8921efc +--- /dev/null ++++ b/cogl/cogl-pipeline-hash-table.c +@@ -0,0 +1,153 @@ ++/* ++ * Cogl ++ * ++ * An object oriented GL/GLES Abstraction/Utility Layer ++ * ++ * Copyright (C) 2013 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: ++ * Neil Roberts ++ * Robert Bragg ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include "cogl-context-private.h" ++#include "cogl-pipeline-private.h" ++#include "cogl-pipeline-hash-table.h" ++ ++typedef struct ++{ ++ /* The template pipeline */ ++ CoglPipeline *pipeline; ++ ++ /* Calculating the hash is a little bit expensive for pipelines so ++ * we don't want to do it repeatedly for entries that are already in ++ * the hash table. Instead we cache the value here and calculate it ++ * outside of the GHashTable. */ ++ unsigned int hash_value; ++ ++ /* GHashTable annoyingly doesn't let us pass a user data pointer to ++ * the hash and equal functions so to work around it we have to ++ * store the pointer in every hash table entry. We will use this ++ * entry as both the key and the value */ ++ CoglPipelineHashTable *hash; ++} CoglPipelineHashTableEntry; ++ ++static void ++value_destroy_cb (void *value) ++{ ++ CoglPipelineHashTableEntry *entry = value; ++ ++ cogl_object_unref (entry->pipeline); ++ ++ g_slice_free (CoglPipelineHashTableEntry, entry); ++} ++ ++static unsigned int ++entry_hash (const void *data) ++{ ++ const CoglPipelineHashTableEntry *entry = data; ++ ++ return entry->hash_value; ++} ++ ++static CoglBool ++entry_equal (const void *a, ++ const void *b) ++{ ++ const CoglPipelineHashTableEntry *entry_a = a; ++ const CoglPipelineHashTableEntry *entry_b = b; ++ const CoglPipelineHashTable *hash = entry_a->hash; ++ ++ return _cogl_pipeline_equal (entry_a->pipeline, ++ entry_b->pipeline, ++ hash->main_state, ++ hash->layer_state, ++ 0); ++} ++ ++void ++_cogl_pipeline_hash_table_init (CoglPipelineHashTable *hash, ++ unsigned int main_state, ++ unsigned int layer_state, ++ const char *debug_string) ++{ ++ hash->n_unique_pipelines = 0; ++ hash->debug_string = debug_string; ++ hash->main_state = main_state; ++ hash->layer_state = layer_state; ++ hash->table = g_hash_table_new_full (entry_hash, ++ entry_equal, ++ NULL, /* key destroy */ ++ value_destroy_cb); ++} ++ ++void ++_cogl_pipeline_hash_table_destroy (CoglPipelineHashTable *hash) ++{ ++ g_hash_table_destroy (hash->table); ++} ++ ++CoglPipeline * ++_cogl_pipeline_hash_table_get (CoglPipelineHashTable *hash, ++ CoglPipeline *key_pipeline) ++{ ++ CoglPipelineHashTableEntry dummy_entry; ++ CoglPipelineHashTableEntry *entry; ++ unsigned int copy_state; ++ ++ dummy_entry.pipeline = key_pipeline; ++ dummy_entry.hash = hash; ++ dummy_entry.hash_value = _cogl_pipeline_hash (key_pipeline, ++ hash->main_state, ++ hash->layer_state, ++ 0); ++ entry = g_hash_table_lookup (hash->table, &dummy_entry); ++ ++ if (entry) ++ return entry->pipeline; ++ ++ if (hash->n_unique_pipelines == 50) ++ g_warning ("Over 50 separate %s have been generated which is very " ++ "unusual, so something is probably wrong!\n", ++ hash->debug_string); ++ ++ entry = g_slice_new (CoglPipelineHashTableEntry); ++ entry->hash = hash; ++ entry->hash_value = dummy_entry.hash_value; ++ ++ copy_state = hash->main_state; ++ if (hash->layer_state) ++ copy_state |= COGL_PIPELINE_STATE_LAYERS; ++ ++ /* Create a new pipeline that is a child of the root pipeline ++ * instead of a normal copy so that the template pipeline won't hold ++ * a reference to the original pipeline */ ++ entry->pipeline = _cogl_pipeline_deep_copy (key_pipeline, ++ copy_state, ++ hash->layer_state); ++ ++ g_hash_table_insert (hash->table, entry, entry); ++ ++ hash->n_unique_pipelines++; ++ ++ return entry->pipeline; ++} +diff --git a/cogl/cogl-pipeline-hash-table.h b/cogl/cogl-pipeline-hash-table.h +new file mode 100644 +index 0000000..1b0a0d9 +--- /dev/null ++++ b/cogl/cogl-pipeline-hash-table.h +@@ -0,0 +1,69 @@ ++/* ++ * Cogl ++ * ++ * An object oriented GL/GLES Abstraction/Utility Layer ++ * ++ * Copyright (C) 2013 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 . ++ * ++ * ++ */ ++ ++#ifndef __COGL_PIPELINE_HASH_H__ ++#define __COGL_PIPELINE_HASH_H__ ++ ++#include "cogl-pipeline.h" ++ ++typedef struct ++{ ++ /* Total number of pipelines that were ever added to the hash. This ++ * is not decremented when a pipeline is removed. It is only used to ++ * generate a warning if an unusually high number of pipelines are ++ * generated */ ++ int n_unique_pipelines; ++ ++ /* String that will be used to describe the usage of this hash table ++ * in the debug warning when too many pipelines are generated. This ++ * must be a static string because it won't be copied or freed */ ++ const char *debug_string; ++ ++ unsigned int main_state; ++ unsigned int layer_state; ++ ++ GHashTable *table; ++} CoglPipelineHashTable; ++ ++void ++_cogl_pipeline_hash_table_init (CoglPipelineHashTable *hash, ++ unsigned int main_state, ++ unsigned int layer_state, ++ const char *debug_string); ++ ++void ++_cogl_pipeline_hash_table_destroy (CoglPipelineHashTable *hash); ++ ++/* ++ * Gets a pipeline from the hash that has the same state as ++ * @key_pipeline according to the limited state bits passed to ++ * _cogl_pipeline_hash_table_init(). If there is no matching pipelines ++ * already then a copy of key_pipeline is stored in the hash so that ++ * it will be used next time the function is called with a similar ++ * pipeline. In that case the copy itself will be returned ++ */ ++CoglPipeline * ++_cogl_pipeline_hash_table_get (CoglPipelineHashTable *hash, ++ CoglPipeline *key_pipeline); ++ ++#endif /* __COGL_PIPELINE_HASH_H__ */ +diff --git a/cogl/cogl-pipeline-layer-private.h b/cogl/cogl-pipeline-layer-private.h +index 125b967..7577559 100644 +--- a/cogl/cogl-pipeline-layer-private.h ++++ b/cogl/cogl-pipeline-layer-private.h +@@ -358,6 +358,11 @@ _cogl_pipeline_layer_get_wrap_mode_t (CoglPipelineLayer *layer); + CoglPipelineWrapMode + _cogl_pipeline_layer_get_wrap_mode_p (CoglPipelineLayer *layer); + ++void ++_cogl_pipeline_layer_copy_differences (CoglPipelineLayer *dest, ++ CoglPipelineLayer *src, ++ unsigned long differences); ++ + unsigned long + _cogl_pipeline_layer_compare_differences (CoglPipelineLayer *layer0, + CoglPipelineLayer *layer1); +diff --git a/cogl/cogl-pipeline-layer.c b/cogl/cogl-pipeline-layer.c +index d9590c8..9bc26ef 100644 +--- a/cogl/cogl-pipeline-layer.c ++++ b/cogl/cogl-pipeline-layer.c +@@ -42,6 +42,8 @@ + #include "cogl-context-private.h" + #include "cogl-texture-private.h" + ++#include ++ + static void + _cogl_pipeline_layer_free (CoglPipelineLayer *layer); + +@@ -146,6 +148,107 @@ _cogl_get_n_args_for_combine_func (CoglPipelineCombineFunc func) + return 0; + } + ++void ++_cogl_pipeline_layer_copy_differences (CoglPipelineLayer *dest, ++ CoglPipelineLayer *src, ++ unsigned long differences) ++{ ++ CoglPipelineLayerBigState *big_dest, *big_src; ++ ++ if ((differences & COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE) && ++ !dest->has_big_state) ++ { ++ dest->big_state = g_slice_new (CoglPipelineLayerBigState); ++ dest->has_big_state = TRUE; ++ } ++ ++ big_dest = dest->big_state; ++ big_src = src->big_state; ++ ++ dest->differences |= differences; ++ ++ while (differences) ++ { ++ int index = _cogl_util_ffs (differences) - 1; ++ ++ differences &= ~(1 << index); ++ ++ /* This convoluted switch statement is just here so that we'll ++ * get a warning if a new state is added without handling it ++ * here */ ++ switch (index) ++ { ++ case COGL_PIPELINE_LAYER_STATE_COUNT: ++ case COGL_PIPELINE_LAYER_STATE_UNIT_INDEX: ++ g_warn_if_reached (); ++ break; ++ ++ case COGL_PIPELINE_LAYER_STATE_TEXTURE_TYPE_INDEX: ++ dest->texture_type = src->texture_type; ++ break; ++ ++ case COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX: ++ dest->texture = src->texture; ++ if (dest->texture) ++ cogl_object_ref (dest->texture); ++ break; ++ ++ case COGL_PIPELINE_LAYER_STATE_SAMPLER_INDEX: ++ dest->sampler_cache_entry = src->sampler_cache_entry; ++ break; ++ ++ case COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX: ++ { ++ CoglPipelineCombineFunc func; ++ int n_args, i; ++ ++ func = big_src->texture_combine_rgb_func; ++ big_dest->texture_combine_rgb_func = func; ++ n_args = _cogl_get_n_args_for_combine_func (func); ++ for (i = 0; i < n_args; i++) ++ { ++ big_dest->texture_combine_rgb_src[i] = ++ big_src->texture_combine_rgb_src[i]; ++ big_dest->texture_combine_rgb_op[i] = ++ big_src->texture_combine_rgb_op[i]; ++ } ++ ++ func = big_src->texture_combine_alpha_func; ++ big_dest->texture_combine_alpha_func = func; ++ n_args = _cogl_get_n_args_for_combine_func (func); ++ for (i = 0; i < n_args; i++) ++ { ++ big_dest->texture_combine_alpha_src[i] = ++ big_src->texture_combine_alpha_src[i]; ++ big_dest->texture_combine_alpha_op[i] = ++ big_src->texture_combine_alpha_op[i]; ++ } ++ } ++ break; ++ ++ case COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX: ++ memcpy (big_dest->texture_combine_constant, ++ big_src->texture_combine_constant, ++ sizeof (big_dest->texture_combine_constant)); ++ break; ++ ++ case COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX: ++ big_dest->point_sprite_coords = big_src->point_sprite_coords; ++ break; ++ ++ case COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS_INDEX: ++ _cogl_pipeline_snippet_list_copy (&big_dest->vertex_snippets, ++ &big_src->vertex_snippets); ++ break; ++ ++ case COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS_INDEX: ++ _cogl_pipeline_snippet_list_copy (&big_dest->fragment_snippets, ++ &big_src->fragment_snippets); ++ break; ++ } ++ } ++} ++ + static void + _cogl_pipeline_layer_init_multi_property_sparse_state ( + CoglPipelineLayer *layer, +diff --git a/cogl/cogl-pipeline-private.h b/cogl/cogl-pipeline-private.h +index 56700b5..acb5653 100644 +--- a/cogl/cogl-pipeline-private.h ++++ b/cogl/cogl-pipeline-private.h +@@ -845,6 +845,17 @@ _cogl_pipeline_hash (CoglPipeline *pipeline, + unsigned long layer_differences, + CoglPipelineEvalFlags flags); + ++/* Makes a copy of the given pipeline that is a child of the root ++ * pipeline rather than a child of the source pipeline. That way the ++ * new pipeline won't hold a reference to the source pipeline. The ++ * differences specified in @differences and @layer_differences are ++ * copied across and all other state is left with the default ++ * values. */ ++CoglPipeline * ++_cogl_pipeline_deep_copy (CoglPipeline *pipeline, ++ unsigned long differences, ++ unsigned long layer_differences); ++ + CoglPipeline * + _cogl_pipeline_journal_ref (CoglPipeline *pipeline); + +diff --git a/cogl/cogl-pipeline.c b/cogl/cogl-pipeline.c +index c029f45..a91ad25 100644 +--- a/cogl/cogl-pipeline.c ++++ b/cogl/cogl-pipeline.c +@@ -2771,6 +2771,97 @@ _cogl_pipeline_hash (CoglPipeline *pipeline, + + typedef struct + { ++ CoglContext *context; ++ CoglPipeline *src_pipeline; ++ CoglPipeline *dst_pipeline; ++ unsigned int layer_differences; ++} DeepCopyData; ++ ++static CoglBool ++deep_copy_layer_cb (CoglPipelineLayer *src_layer, ++ void *user_data) ++{ ++ DeepCopyData *data = user_data; ++ CoglPipelineLayer *dst_layer; ++ unsigned int differences = data->layer_differences; ++ ++ dst_layer = _cogl_pipeline_get_layer (data->dst_pipeline, src_layer->index); ++ ++ while (src_layer != data->context->default_layer_n && ++ src_layer != data->context->default_layer_0 && ++ differences) ++ { ++ unsigned long to_copy = differences & src_layer->differences; ++ ++ if (to_copy) ++ { ++ _cogl_pipeline_layer_copy_differences (dst_layer, src_layer, to_copy); ++ differences ^= to_copy; ++ } ++ ++ src_layer = COGL_PIPELINE_LAYER (COGL_NODE (src_layer)->parent); ++ } ++ ++ return TRUE; ++} ++ ++CoglPipeline * ++_cogl_pipeline_deep_copy (CoglPipeline *pipeline, ++ unsigned long differences, ++ unsigned long layer_differences) ++{ ++ CoglPipeline *new, *authority; ++ CoglBool copy_layer_state; ++ ++ _COGL_GET_CONTEXT (ctx, NULL); ++ ++ if ((differences & COGL_PIPELINE_STATE_LAYERS)) ++ { ++ copy_layer_state = TRUE; ++ differences &= ~COGL_PIPELINE_STATE_LAYERS; ++ } ++ else ++ copy_layer_state = FALSE; ++ ++ new = cogl_pipeline_new (ctx); ++ ++ for (authority = pipeline; ++ authority != ctx->default_pipeline && differences; ++ authority = COGL_PIPELINE (COGL_NODE (authority)->parent)) ++ { ++ unsigned long to_copy = differences & authority->differences; ++ ++ if (to_copy) ++ { ++ _cogl_pipeline_copy_differences (new, authority, to_copy); ++ differences ^= to_copy; ++ } ++ } ++ ++ if (copy_layer_state) ++ { ++ DeepCopyData data; ++ ++ /* The unit index doesn't need to be copied because it should ++ * end up with the same values anyway because the new pipeline ++ * will have the same indices as the source pipeline */ ++ layer_differences &= ~COGL_PIPELINE_LAYER_STATE_UNIT; ++ ++ data.context = ctx; ++ data.src_pipeline = pipeline; ++ data.dst_pipeline = new; ++ data.layer_differences = layer_differences; ++ ++ _cogl_pipeline_foreach_layer_internal (pipeline, ++ deep_copy_layer_cb, ++ &data); ++ } ++ ++ return new; ++} ++ ++typedef struct ++{ + int i; + CoglPipelineLayer **layers; + } AddLayersToArrayState; +diff --git a/cogl/cogl-xlib-renderer.c b/cogl/cogl-xlib-renderer.c +index 18c0fe6..eb1f51a 100644 +--- a/cogl/cogl-xlib-renderer.c ++++ b/cogl/cogl-xlib-renderer.c +@@ -238,7 +238,7 @@ update_outputs (CoglRenderer *renderer, + + _cogl_xlib_renderer_trap_errors (renderer, &state); + +- for (i = 0; i < resources->ncrtc && !error; i++) ++ for (i = 0; resources && i < resources->ncrtc && !error; i++) + { + XRRCrtcInfo *crtc_info = NULL; + XRROutputInfo *output_info = NULL; +diff --git a/cogl/cogl-xlib.h b/cogl/cogl-xlib.h +index 7a6bc7e..5dab8ae 100644 +--- a/cogl/cogl-xlib.h ++++ b/cogl/cogl-xlib.h +@@ -79,6 +79,8 @@ cogl_xlib_set_display (Display *display); + CoglFilterReturn + cogl_xlib_handle_event (XEvent *xevent); + ++COGL_END_DECLS ++ + #undef __COGL_XLIB_H_INSIDE__ + + #endif /* __COGL_XLIB_H__ */ +diff --git a/configure.ac b/configure.ac +index 43bf407..4ba85b8 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -25,7 +25,7 @@ m4_define([cogl_version], + dnl Since the core Cogl library has to also maintain support for the + dnl Cogl 1.x API for Clutter then we track the 1.x version separately. + m4_define([cogl_1_minor_version], [14]) +-m4_define([cogl_1_micro_version], [0]) ++m4_define([cogl_1_micro_version], [1]) + m4_define([cogl_1_version], [1.cogl_1_minor_version.cogl_1_micro_version]) + + dnl ================================================================ +@@ -70,7 +70,7 @@ dnl ================================================================ + # libtool version info we don't automatically derive this from the + # pretty version number because we want to test the results of + # updating the version number in advance of a release. +-m4_define([cogl_release_status], [release]) ++m4_define([cogl_release_status], [git]) + + AC_INIT(cogl, [cogl_1_version]) + AC_CONFIG_SRCDIR(cogl/cogl.h) +@@ -178,6 +178,12 @@ dnl internal glib configure (as-glibconfig.m4) + m4_ifdef([LT_OUTPUT], [LT_OUTPUT]) + + dnl ================================================================ ++dnl Find an appropriate libm, for sin() etc. ++dnl ================================================================ ++LT_LIB_M ++AC_SUBST(LIBM) ++ ++dnl ================================================================ + dnl See what platform we are building for + dnl ================================================================ + AC_CANONICAL_HOST +@@ -474,6 +480,7 @@ AS_IF( + EXPERIMENTAL_OPTIONS="$EXPERIMENTAL_OPTIONS Quartz Core Graphics," + AC_DEFINE([USE_QUARTZ], 1, + [Use Core Graphics (Quartz) for loading image data]) ++ COGL_EXTRA_LDFLAGS="$COGL_EXTRA_LDFLAGS -framework ApplicationServices" + COGL_IMAGE_BACKEND="quartz" + ], + [ +@@ -1173,6 +1180,12 @@ AC_CHECK_FUNCS([ffs]) + dnl 'memmem' is a GNU extension but we have a simple fallback + AC_CHECK_FUNCS([memmem]) + ++dnl This is used in the cogl-gles2-gears example but it is a GNU extension ++save_libs="$LIBS" ++LIBS="$LIBS $LIBM" ++AC_CHECK_FUNCS([sincos]) ++LIBS="$save_libs" ++ + dnl ================================================================ + dnl Platform values + dnl ================================================================ +diff --git a/examples/Makefile.am b/examples/Makefile.am +index 86801c6..ae3e5f7 100644 +--- a/examples/Makefile.am ++++ b/examples/Makefile.am +@@ -20,7 +20,8 @@ endif + + common_ldadd = \ + $(COGL_DEP_LIBS) \ +- $(top_builddir)/cogl/libcogl.la ++ $(top_builddir)/cogl/libcogl.la \ ++ $(LIBM) + + if !USE_GLIB + common_ldadd += $(top_builddir)/deps/glib/libglib.la +diff --git a/examples/android/hello/jni/main.c b/examples/android/hello/jni/main.c +index 2c5bd9b..c9a8401 100644 +--- a/examples/android/hello/jni/main.c ++++ b/examples/android/hello/jni/main.c +@@ -42,7 +42,7 @@ static int test_init (TestData* data) + CoglOnscreen *onscreen; + CoglError *error = NULL; + CoglVertexP2C4 triangle_vertices[] = { +- {0, 0.7, 0xff, 0x00, 0x00, 0x80}, ++ {0, 0.7, 0xff, 0x00, 0x00, 0xff}, + {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff}, + {0.7, -0.7, 0x00, 0x00, 0xff, 0xff} + }; +diff --git a/examples/cogl-gles2-context.c b/examples/cogl-gles2-context.c +index 1cf375f..de66c21 100644 +--- a/examples/cogl-gles2-context.c ++++ b/examples/cogl-gles2-context.c +@@ -70,7 +70,7 @@ main (int argc, char **argv) + CoglOnscreen *onscreen; + CoglError *error = NULL; + CoglVertexP2C4 triangle_vertices[] = { +- {0, 0.7, 0xff, 0x00, 0x00, 0x80}, ++ {0, 0.7, 0xff, 0x00, 0x00, 0xff}, + {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff}, + {0.7, -0.7, 0x00, 0x00, 0xff, 0xff} + }; +diff --git a/examples/cogl-gles2-gears.c b/examples/cogl-gles2-gears.c +index d7dd271..c7185b6 100644 +--- a/examples/cogl-gles2-gears.c ++++ b/examples/cogl-gles2-gears.c +@@ -35,6 +35,10 @@ + * Jul 13, 2010 + */ + ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ + #define GL_GLEXT_PROTOTYPES + + #include +@@ -110,6 +114,15 @@ static GLfloat ProjectionMatrix[16]; + /** The direction of the directional light for the scene */ + static const GLfloat LightSourcePosition[4] = { 5.0, 5.0, 10.0, 1.0}; + ++#ifndef HAVE_SINCOS ++static void ++sincos (double x, double *sinx, double *cosx) ++{ ++ *sinx = sin (x); ++ *cosx = cos (x); ++} ++#endif /* HAVE_SINCOS */ ++ + /** + * Fills a gear vertex. + * +diff --git a/examples/cogl-hello.c b/examples/cogl-hello.c +index 5bda9bf..3ba1e31 100644 +--- a/examples/cogl-hello.c ++++ b/examples/cogl-hello.c +@@ -39,7 +39,7 @@ main (int argc, char **argv) + CoglOnscreen *onscreen; + CoglError *error = NULL; + CoglVertexP2C4 triangle_vertices[] = { +- {0, 0.7, 0xff, 0x00, 0x00, 0x80}, ++ {0, 0.7, 0xff, 0x00, 0x00, 0xff}, + {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff}, + {0.7, -0.7, 0x00, 0x00, 0xff, 0xff} + }; +diff --git a/examples/cogl-msaa.c b/examples/cogl-msaa.c +index 73f9c4e..4a388bc 100644 +--- a/examples/cogl-msaa.c ++++ b/examples/cogl-msaa.c +@@ -12,7 +12,7 @@ main (int argc, char **argv) + CoglFramebuffer *fb; + CoglError *error = NULL; + CoglVertexP2C4 triangle_vertices[] = { +- {0, 0.7, 0xff, 0x00, 0x00, 0x80}, ++ {0, 0.7, 0xff, 0x00, 0x00, 0xff}, + {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff}, + {0.7, -0.7, 0x00, 0x00, 0xff, 0xff} + }; +diff --git a/examples/cogl-sdl-hello.c b/examples/cogl-sdl-hello.c +index 961137a..acb9125 100644 +--- a/examples/cogl-sdl-hello.c ++++ b/examples/cogl-sdl-hello.c +@@ -80,7 +80,7 @@ main (int argc, char **argv) + CoglOnscreen *onscreen; + CoglError *error = NULL; + CoglVertexP2C4 triangle_vertices[] = { +- {0, 0.7, 0xff, 0x00, 0x00, 0x80}, ++ {0, 0.7, 0xff, 0x00, 0x00, 0xff}, + {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff}, + {0.7, -0.7, 0x00, 0x00, 0xff, 0xff} + }; +diff --git a/examples/cogl-sdl2-hello.c b/examples/cogl-sdl2-hello.c +index 405cb92..12e6ced 100644 +--- a/examples/cogl-sdl2-hello.c ++++ b/examples/cogl-sdl2-hello.c +@@ -89,7 +89,7 @@ main (int argc, char **argv) + CoglOnscreen *onscreen; + CoglError *error = NULL; + CoglVertexP2C4 triangle_vertices[] = { +- {0, 0.7, 0xff, 0x00, 0x00, 0x80}, ++ {0, 0.7, 0xff, 0x00, 0x00, 0xff}, + {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff}, + {0.7, -0.7, 0x00, 0x00, 0xff, 0xff} + }; +diff --git a/examples/cogl-x11-foreign.c b/examples/cogl-x11-foreign.c +index ca9e3ed..a60397c 100644 +--- a/examples/cogl-x11-foreign.c ++++ b/examples/cogl-x11-foreign.c +@@ -61,7 +61,7 @@ main (int argc, char **argv) + unsigned long mask; + Window xwin; + CoglVertexP2C4 triangle_vertices[] = { +- {0, 0.7, 0xff, 0x00, 0x00, 0x80}, ++ {0, 0.7, 0xff, 0x00, 0x00, 0xff}, + {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff}, + {0.7, -0.7, 0x00, 0x00, 0xff, 0xff} + }; +diff --git a/examples/cogland.c b/examples/cogland.c +index c18850a..7a02719 100644 +--- a/examples/cogland.c ++++ b/examples/cogland.c +@@ -93,7 +93,6 @@ struct _CoglandCompositor + struct wl_display *wayland_display; + struct wl_event_loop *wayland_loop; + +- CoglDisplay *cogl_display; + CoglContext *cogl_context; + + int virtual_width; +@@ -336,15 +335,16 @@ cogland_queue_redraw (CoglandCompositor *compositor) + } + + static void +-shm_buffer_damaged (CoglandSurface *surface, +- int32_t x, +- int32_t y, +- int32_t width, +- int32_t height) ++surface_damaged (CoglandSurface *surface, ++ int32_t x, ++ int32_t y, ++ int32_t width, ++ int32_t height) + { + struct wl_buffer *wayland_buffer = surface->buffer; + +- if (surface->texture) ++ if (surface->texture && ++ wl_buffer_is_shm (surface->buffer)) + { + CoglPixelFormat format; + int stride = wl_shm_buffer_get_stride (wayland_buffer); +@@ -381,6 +381,8 @@ shm_buffer_damaged (CoglandSurface *surface, + stride, + data); + } ++ ++ cogland_queue_redraw (surface->compositor); + } + + static void +@@ -546,16 +548,18 @@ cogland_surface_commit (struct wl_client *client, + + wl_signal_add (&surface->buffer->resource.destroy_signal, + &surface->buffer_destroy_listener); +- wl_list_remove (&surface->pending.buffer_destroy_listener.link); + } + } +- surface->pending.buffer = NULL; ++ if (surface->pending.buffer) ++ { ++ wl_list_remove (&surface->pending.buffer_destroy_listener.link); ++ surface->pending.buffer = NULL; ++ } + surface->pending.sx = 0; + surface->pending.sy = 0; + + /* wl_surface.damage */ + if (surface->buffer && +- wl_buffer_is_shm (surface->buffer) && + surface->texture && + !region_is_empty (&surface->pending.damage)) + { +@@ -571,11 +575,11 @@ cogland_surface_commit (struct wl_client *client, + if (region->y1 < 0) + region->y1 = 0; + +- shm_buffer_damaged (surface, +- region->x1, +- region->y1, +- region->x2 - region->x1, +- region->y2 - region->y1); ++ surface_damaged (surface, ++ region->x1, ++ region->y1, ++ region->x2 - region->x1, ++ region->y2 - region->y1); + } + region_init (&surface->pending.damage); + +@@ -583,8 +587,6 @@ cogland_surface_commit (struct wl_client *client, + wl_list_insert_list (&compositor->frame_callbacks, + &surface->pending.frame_callback_list); + wl_list_init (&surface->pending.frame_callback_list); +- +- cogland_queue_redraw (compositor); + } + + static void +@@ -614,6 +616,9 @@ cogland_surface_free (CoglandSurface *surface) + compositor->surfaces = g_list_remove (compositor->surfaces, surface); + cogland_surface_detach_buffer_and_notify (surface); + ++ if (surface->pending.buffer) ++ wl_list_remove (&surface->pending.buffer_destroy_listener.link); ++ + wl_list_for_each_safe (cb, next, + &surface->pending.frame_callback_list, link) + wl_resource_destroy (&cb->resource); +@@ -970,7 +975,7 @@ get_shell_surface (struct wl_client *client, + struct wl_resource *surface_resource) + { + CoglandSurface *surface = surface_resource->data; +- CoglandShellSurface *shell_surface = g_new0 (CoglandShellSurface, 1); ++ CoglandShellSurface *shell_surface; + + if (surface->has_shell_surface) + { +@@ -980,6 +985,7 @@ get_shell_surface (struct wl_client *client, + return; + } + ++ shell_surface = g_new0 (CoglandShellSurface, 1); + shell_surface->resource.destroy = destroy_shell_surface; + shell_surface->resource.object.id = id; + shell_surface->resource.object.interface = &wl_shell_surface_interface; +@@ -1012,6 +1018,36 @@ bind_shell (struct wl_client *client, + &cogland_shell_interface, id, data); + } + ++static CoglContext * ++create_cogl_context (CoglandCompositor *compositor, ++ CoglBool use_egl_constraint, ++ CoglError **error) ++{ ++ CoglRenderer *renderer = renderer = cogl_renderer_new (); ++ CoglDisplay *display; ++ CoglContext *context; ++ ++ if (use_egl_constraint) ++ cogl_renderer_add_constraint (renderer, COGL_RENDERER_CONSTRAINT_USES_EGL); ++ ++ if (!cogl_renderer_connect (renderer, error)) ++ { ++ cogl_object_unref (renderer); ++ return NULL; ++ } ++ ++ display = cogl_display_new (renderer, NULL); ++ cogl_wayland_display_set_compositor_display (display, ++ compositor->wayland_display); ++ ++ context = cogl_context_new (display, error); ++ ++ cogl_object_unref (renderer); ++ cogl_object_unref (display); ++ ++ return context; ++} ++ + int + main (int argc, char **argv) + { +@@ -1020,7 +1056,7 @@ main (int argc, char **argv) + CoglError *error = NULL; + GError *gerror = NULL; + CoglVertexP2C4 triangle_vertices[] = { +- {0, 0.7, 0xff, 0x00, 0x00, 0x80}, ++ {0, 0.7, 0xff, 0x00, 0x00, 0xff}, + {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff}, + {0.7, -0.7, 0x00, 0x00, 0xff, 0xff} + }; +@@ -1055,13 +1091,30 @@ main (int argc, char **argv) + wayland_event_source_new (compositor.wayland_display); + g_source_attach (compositor.wayland_event_source, NULL); + +- compositor.cogl_display = cogl_display_new (NULL, NULL); +- cogl_wayland_display_set_compositor_display (compositor.cogl_display, +- compositor.wayland_display); +- +- compositor.cogl_context = cogl_context_new (compositor.cogl_display, &error); +- if (!compositor.cogl_context) +- g_error ("Failed to create a Cogl context: %s\n", error->message); ++ /* We want Cogl to use an EGL renderer because otherwise it won't ++ * set up the wl_drm object and only SHM buffers will work. */ ++ compositor.cogl_context = ++ create_cogl_context (&compositor, ++ TRUE /* use EGL constraint */, ++ &error); ++ if (compositor.cogl_context == NULL) ++ { ++ /* If we couldn't get an EGL context then try any type of ++ * context */ ++ cogl_error_free (error); ++ error = NULL; ++ ++ compositor.cogl_context = ++ create_cogl_context (&compositor, ++ FALSE, /* don't set EGL constraint */ ++ &error); ++ ++ if (compositor.cogl_context) ++ g_warning ("Failed to create context with EGL constraint, " ++ "falling back"); ++ else ++ g_error ("Failed to create a Cogl context: %s\n", error->message); ++ } + + compositor.virtual_width = 800; + compositor.virtual_height = 600; +diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am +index 69a460d..9782755 100644 +--- a/tests/conform/Makefile.am ++++ b/tests/conform/Makefile.am +@@ -65,6 +65,7 @@ test_sources = \ + test-framebuffer-get-bits.c \ + test-primitive-and-journal.c \ + test-copy-replace-texture.c \ ++ test-pipeline-cache-unrefs-texture.c \ + $(NULL) + + test_conformance_SOURCES = $(common_sources) $(test_sources) +@@ -131,7 +132,10 @@ AM_CPPFLAGS += \ + -DCOGL_COMPILATION + + test_conformance_CFLAGS = -g3 -O0 $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) +-test_conformance_LDADD = $(COGL_DEP_LIBS) $(top_builddir)/cogl/libcogl.la ++test_conformance_LDADD = \ ++ $(COGL_DEP_LIBS) \ ++ $(top_builddir)/cogl/libcogl.la \ ++ $(LIBM) + if !USE_GLIB + test_conformance_LDADD += $(top_builddir)/deps/glib/libglib.la + endif +diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c +index 0b55db6..1d1447e 100644 +--- a/tests/conform/test-conform-main.c ++++ b/tests/conform/test-conform-main.c +@@ -120,6 +120,8 @@ main (int argc, char **argv) + + ADD_TEST (test_copy_replace_texture, 0, 0); + ++ ADD_TEST (test_pipeline_cache_unrefs_texture, 0, 0); ++ + UNPORTED_TEST (test_viewport); + + ADD_TEST (test_gles2_context, TEST_REQUIREMENT_GLES2_CONTEXT, 0); +diff --git a/tests/conform/test-pipeline-cache-unrefs-texture.c b/tests/conform/test-pipeline-cache-unrefs-texture.c +new file mode 100644 +index 0000000..ccd02e7 +--- /dev/null ++++ b/tests/conform/test-pipeline-cache-unrefs-texture.c +@@ -0,0 +1,92 @@ ++#include ++ ++#include "test-utils.h" ++ ++/* Keep track of the number of textures that we've created and are ++ * still alive */ ++static int destroyed_texture_count = 0; ++ ++#define N_TEXTURES 3 ++ ++static void ++free_texture_cb (void *user_data) ++{ ++ destroyed_texture_count++; ++} ++ ++static CoglTexture * ++create_texture (void) ++{ ++ static const guint8 data[] = ++ { 0xff, 0xff, 0xff, 0xff }; ++ static CoglUserDataKey texture_data_key; ++ CoglTexture2D *tex_2d; ++ ++ tex_2d = cogl_texture_2d_new_from_data (test_ctx, ++ 1, 1, /* width / height */ ++ COGL_PIXEL_FORMAT_RGBA_8888_PRE, ++ COGL_PIXEL_FORMAT_ANY, ++ 4, /* rowstride */ ++ data, ++ NULL); ++ ++ /* Set some user data on the texture so we can track when it has ++ * been destroyed */ ++ cogl_object_set_user_data (COGL_OBJECT (tex_2d), ++ &texture_data_key, ++ GINT_TO_POINTER (1), ++ free_texture_cb); ++ ++ return COGL_TEXTURE (tex_2d); ++} ++ ++void ++test_pipeline_cache_unrefs_texture (void) ++{ ++ CoglPipeline *pipeline = cogl_pipeline_new (test_ctx); ++ CoglPipeline *simple_pipeline; ++ int i; ++ ++ /* Create a pipeline with three texture layers. That way we can be ++ * pretty sure the pipeline will cause a unique shader to be ++ * generated in the cache */ ++ for (i = 0; i < N_TEXTURES; i++) ++ { ++ CoglTexture *tex = create_texture (); ++ cogl_pipeline_set_layer_texture (pipeline, i, tex); ++ cogl_object_unref (tex); ++ } ++ ++ /* Draw something with the pipeline to ensure it gets into the ++ * pipeline cache */ ++ cogl_framebuffer_draw_rectangle (test_fb, ++ pipeline, ++ 0, 0, 10, 10); ++ cogl_framebuffer_finish (test_fb); ++ ++ /* Draw something else so that it is no longer the current flushed ++ * pipeline, and the units have a different texture bound */ ++ simple_pipeline = cogl_pipeline_new (test_ctx); ++ for (i = 0; i < N_TEXTURES; i++) ++ { ++ CoglColor combine_constant; ++ cogl_color_init_from_4ub (&combine_constant, i, 0, 0, 255); ++ cogl_pipeline_set_layer_combine_constant (simple_pipeline, ++ i, ++ &combine_constant); ++ } ++ cogl_framebuffer_draw_rectangle (test_fb, simple_pipeline, 0, 0, 10, 10); ++ cogl_framebuffer_finish (test_fb); ++ cogl_object_unref (simple_pipeline); ++ ++ g_assert_cmpint (destroyed_texture_count, ==, 0); ++ ++ /* Destroy the pipeline. This should immediately cause the textures ++ * to be freed */ ++ cogl_object_unref (pipeline); ++ ++ g_assert_cmpint (destroyed_texture_count, ==, N_TEXTURES); ++ ++ if (cogl_test_verbose ()) ++ g_print ("OK\n"); ++} +diff --git a/tests/micro-perf/Makefile.am b/tests/micro-perf/Makefile.am +index c221dd6..5c5f69d 100644 +--- a/tests/micro-perf/Makefile.am ++++ b/tests/micro-perf/Makefile.am +@@ -19,5 +19,10 @@ endif + + AM_CFLAGS = $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) + ++common_ldadd = \ ++ $(COGL_DEP_LIBS) \ ++ $(top_builddir)/cogl/libcogl.la \ ++ $(LIBM) ++ + test_journal_SOURCES = test-journal.c +-test_journal_LDADD = $(COGL_DEP_LIBS) $(top_builddir)/cogl/libcogl.la ++test_journal_LDADD = $(common_ldadd) diff --git a/SOURCES/cogl-1.14.0-swrast-copy-sub-buffer.patch b/SOURCES/cogl-1.14.0-swrast-copy-sub-buffer.patch new file mode 100644 index 0000000..6531d6b --- /dev/null +++ b/SOURCES/cogl-1.14.0-swrast-copy-sub-buffer.patch @@ -0,0 +1,44 @@ +diff -up cogl-1.14.0/cogl/winsys/cogl-winsys-glx.c.jx cogl-1.14.0/cogl/winsys/cogl-winsys-glx.c +--- cogl-1.14.0/cogl/winsys/cogl-winsys-glx.c.jx 2013-02-21 10:41:08.000000000 -0500 ++++ cogl-1.14.0/cogl/winsys/cogl-winsys-glx.c 2014-01-29 16:16:00.501264635 -0500 +@@ -698,30 +698,18 @@ update_winsys_features (CoglContext *con + COGL_FLAGS_SET (context->features, + COGL_FEATURE_ID_ONSCREEN_MULTIPLE, TRUE); + +- if (glx_renderer->glXCopySubBuffer || context->glBlitFramebuffer) ++ /* our swrast has working CopySubBuffer, but not BlitFramebuffer */ ++ if (context->gpu.architecture == COGL_GPU_INFO_ARCHITECTURE_LLVMPIPE || ++ context->gpu.architecture == COGL_GPU_INFO_ARCHITECTURE_SOFTPIPE || ++ context->gpu.architecture == COGL_GPU_INFO_ARCHITECTURE_SWRAST) + { +- CoglGpuInfoArchitecture arch; ++ context->glBlitFramebuffer = NULL; ++ } + +- /* XXX: ONGOING BUG: +- * (Don't change the line above since we use this to grep for +- * un-resolved bug workarounds as part of the release process.) +- * +- * "The "drisw" binding in Mesa for loading sofware renderers is +- * broken, and neither glBlitFramebuffer nor glXCopySubBuffer +- * work correctly." +- * - ajax +- * - https://bugzilla.gnome.org/show_bug.cgi?id=674208 +- * +- * This is broken in software Mesa at least as of 7.10 +- */ +- arch = context->gpu.architecture; +- if (arch != COGL_GPU_INFO_ARCHITECTURE_LLVMPIPE && +- arch != COGL_GPU_INFO_ARCHITECTURE_SOFTPIPE && +- arch != COGL_GPU_INFO_ARCHITECTURE_SWRAST) +- { +- COGL_FLAGS_SET (context->winsys_features, +- COGL_WINSYS_FEATURE_SWAP_REGION, TRUE); +- } ++ if (glx_renderer->glXCopySubBuffer || context->glBlitFramebuffer) ++ { ++ COGL_FLAGS_SET (context->winsys_features, ++ COGL_WINSYS_FEATURE_SWAP_REGION, TRUE); + } + + /* Note: glXCopySubBuffer and glBlitFramebuffer won't be throttled diff --git a/SPECS/compat-cogl114.spec b/SPECS/compat-cogl114.spec new file mode 100644 index 0000000..0864fd2 --- /dev/null +++ b/SPECS/compat-cogl114.spec @@ -0,0 +1,107 @@ +Name: compat-cogl114 +Version: 1.14.0 +Release: 3%{?dist} +Summary: Compat package with cogl 1.14 libraries + +Group: Development/Libraries +License: LGPLv2+ +URL: http://www.clutter-project.org/ +Source0: http://download.gnome.org/sources/cogl/1.14/cogl-%{version}.tar.xz +# Updates to a git snapshot of the 1.4 branch of Cogl as of 2013-05-01, +# since there is no 1.4.1 yet. Fixes, among other things +# https://bugzilla.gnome.org/show_bug.cgi?id=699431 +# extra BRs just because we're touching Makefile.am in this patch +Patch0: cogl-1.14.0-21-ge26464f.patch +# Don't disable copy_sub_buffer on llvmpipe +Patch1: cogl-1.14.0-swrast-copy-sub-buffer.patch + +# Support for quadbuffer stereo (patches upstream as of the Cogl 1.20 +# development branch) +Patch10: Add-support-for-setting-up-stereo-CoglOnscreens.patch +Patch11: CoglTexturePixmapX11-add-support-for-stereo-content.patch + +BuildRequires: autoconf automake libtool gettext-devel + +BuildRequires: cairo-devel +BuildRequires: gdk-pixbuf2-devel +BuildRequires: glib2-devel +BuildRequires: gobject-introspection-devel +BuildRequires: gtk-doc +BuildRequires: libXrandr-devel +BuildRequires: libXcomposite-devel +BuildRequires: libXdamage-devel +BuildRequires: libXext-devel +BuildRequires: libXfixes-devel +BuildRequires: mesa-libGL-devel +BuildRequires: pango-devel +BuildRequires: pkgconfig + +%description +Compatibility package with cogl 1.14 librarires. + +%package -n compat-libcogl12 +Summary: Compat package with cogl 1.14 libraries +Conflicts: cogl < 1.15 + +%description -n compat-libcogl12 +Compatibility package with cogl 1.14 librarires. + +%package -n compat-libcogl-pango12 +Summary: Compat package with cogl 1.14 libraries +Conflicts: cogl < 1.15 +Requires: compat-libcogl12 = %{version}-%{release} + +%description -n compat-libcogl-pango12 +Compatibility package with cogl 1.14 librarires. + +%prep +%setup -q -n cogl-%{version} +%patch0 -p1 +%patch1 -p1 + +%patch10 -p1 +%patch11 -p1 + +%build +CFLAGS="$RPM_OPT_FLAGS -fPIC" +autoreconf -vif +%configure --enable-cairo=yes --enable-gdk-pixbuf=yes --enable-cogl-pango=yes --enable-glx=yes --enable-gtk-doc --enable-introspection=yes + +make V=1 + +%install +make install DESTDIR=%{buildroot} INSTALL='install -p' + +#Remove libtool archives. +find %{buildroot} -name '*.la' -exec rm -f {} ';' + +rm -rf %{buildroot}%{_includedir} +rm -rf %{buildroot}%{_libdir}/girepository-1.0/ +rm -rf %{buildroot}%{_libdir}/*.so +rm -rf %{buildroot}%{_libdir}/pkgconfig/ +rm -rf %{buildroot}%{_datadir} + +%post -n compat-libcogl12 -p /sbin/ldconfig +%postun -n compat-libcogl12 -p /sbin/ldconfig + +%post -n compat-libcogl-pango12 -p /sbin/ldconfig +%postun -n compat-libcogl-pango12 -p /sbin/ldconfig + +%files -n compat-libcogl12 +%doc COPYING +%{_libdir}/libcogl.so.* + +%files -n compat-libcogl-pango12 +%doc COPYING +%{_libdir}/libcogl-pango.so.* + +%changelog +* Fri May 22 2015 Florian Müllner - 1.14.0-3 +- Add explicit requirement to subpackage + Related: #1184209 + +* Fri Nov 07 2014 Kalev Lember - 1.14.0-2 +- Add missing ldconfig calls + +* Thu Nov 06 2014 Kalev Lember - 1.14.0-1 +- Cogl 1.14 compat package for el7-gnome-3-14 copr