Beispiel #1
0
CoglTexture2D *
cogl_texture_2d_new_from_data (CoglContext *ctx,
                               int width,
                               int height,
                               CoglPixelFormat format,
                               CoglPixelFormat internal_format,
                               int rowstride,
                               const uint8_t *data,
                               CoglError **error)
{
  CoglBitmap *bmp;
  CoglTexture2D *tex_2d;

  _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, NULL);
  _COGL_RETURN_VAL_IF_FAIL (data != NULL, NULL);

  /* Rowstride from width if not given */
  if (rowstride == 0)
    rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format);

  /* Wrap the data into a bitmap */
  bmp = cogl_bitmap_new_for_data (ctx,
                                  width, height,
                                  format,
                                  rowstride,
                                  (uint8_t *) data);

  tex_2d = cogl_texture_2d_new_from_bitmap (bmp,
                                            internal_format,
                                            error);

  cogl_object_unref (bmp);

  return tex_2d;
}
Beispiel #2
0
static CoglTexture2D *
_cogl_atlas_create_texture (CoglAtlas *atlas,
                            int width,
                            int height)
{
  CoglTexture2D *tex;
  CoglError *ignore_error = NULL;

  _COGL_GET_CONTEXT (ctx, NULL);

  if ((atlas->flags & COGL_ATLAS_CLEAR_TEXTURE))
    {
      uint8_t *clear_data;
      CoglBitmap *clear_bmp;
      int bpp = _cogl_pixel_format_get_bytes_per_pixel (atlas->texture_format);

      /* Create a buffer of zeroes to initially clear the texture */
      clear_data = g_malloc0 (width * height * bpp);
      clear_bmp = cogl_bitmap_new_for_data (ctx,
                                            width,
                                            height,
                                            atlas->texture_format,
                                            width * bpp,
                                            clear_data);

      tex = cogl_texture_2d_new_from_bitmap (clear_bmp);

      _cogl_texture_set_internal_format (COGL_TEXTURE (tex),
                                         atlas->texture_format);

      if (!cogl_texture_allocate (COGL_TEXTURE (tex), &ignore_error))
        {
          cogl_error_free (ignore_error);
          cogl_object_unref (tex);
          tex = NULL;
        }

      cogl_object_unref (clear_bmp);

      g_free (clear_data);
    }
  else
    {
      tex = cogl_texture_2d_new_with_size (ctx, width, height);

      _cogl_texture_set_internal_format (COGL_TEXTURE (tex),
                                         atlas->texture_format);

      if (!cogl_texture_allocate (COGL_TEXTURE (tex), &ignore_error))
        {
          cogl_error_free (ignore_error);
          cogl_object_unref (tex);
          tex = NULL;
        }
    }

  return tex;
}
Beispiel #3
0
/* This first tries to upload the texture to a CoglTexture2D, but
 * if that's not possible it falls back to a CoglTexture2DSliced.
 *
 * Auto-mipmapping of any uploaded texture is disabled
 */
static CoglTexture *
video_texture_new_from_data (CoglContext *ctx,
                             int width,
                             int height,
                             CoglPixelFormat format,
                             CoglPixelFormat internal_format,
                             int rowstride,
                             const uint8_t *data,
                             CoglError **error)
{
  CoglBitmap *bitmap;
  CoglTexture *tex;
  CoglError *internal_error = NULL;

  bitmap = cogl_bitmap_new_for_data (ctx,
                                     width, height,
                                     format,
                                     rowstride,
                                     (uint8_t *) data);

  if ((is_pot (cogl_bitmap_get_width (bitmap)) &&
       is_pot (cogl_bitmap_get_height (bitmap))) ||
      cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC))
    {
      tex = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmap,
                                                           internal_format,
                                                           &internal_error));
      if (!tex)
        {
          cogl_error_free (internal_error);
          internal_error = NULL;
        }
    }
  else
    tex = NULL;

  if (!tex)
    {
      /* Otherwise create a sliced texture */
      CoglTexture2DSliced *tex_2ds =
        cogl_texture_2d_sliced_new_from_bitmap (bitmap,
                                                -1, /* no maximum waste */
                                                internal_format,
                                                error);
      tex = COGL_TEXTURE (tex_2ds);
    }

  cogl_object_unref (bitmap);

  return tex;
}
Beispiel #4
0
/* For reference: There was some deliberation over whether to have a
 * constructor that could throw an exception but looking at standard
 * practices with several high level OO languages including python, C++,
 * C# Java and Ruby they all support exceptions in constructors and the
 * general consensus appears to be that throwing an exception is neater
 * than successfully constructing with an internal error status that
 * would then have to be explicitly checked via some form of ::is_ok()
 * method.
 */
CoglContext *
cogl_context_new (CoglDisplay *display,
                  GError **error)
{
  CoglContext *context;
  GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 };
  CoglBitmap *default_texture_bitmap;
  const CoglWinsysVtable *winsys;
  int i;

  _cogl_init ();

#ifdef COGL_ENABLE_PROFILE
  /* We need to be absolutely sure that uprof has been initialized
   * before calling _cogl_uprof_init. uprof_init (NULL, NULL)
   * will be a NOP if it has been initialized but it will also
   * mean subsequent parsing of the UProf GOptionGroup will have no
   * affect.
   *
   * Sadly GOptionGroup based library initialization is extremely
   * fragile by design because GOptionGroups have no notion of
   * dependencies and so the order things are initialized isn't
   * currently under tight control.
   */
  uprof_init (NULL, NULL);
  _cogl_uprof_init ();
#endif

  /* Allocate context memory */
  context = g_malloc0 (sizeof (CoglContext));

  /* Convert the context into an object immediately in case any of the
     code below wants to verify that the context pointer is a valid
     object */
  _cogl_context_object_new (context);

  /* XXX: Gross hack!
   * Currently everything in Cogl just assumes there is a default
   * context which it can access via _COGL_GET_CONTEXT() including
   * code used to construct a CoglContext. Until all of that code
   * has been updated to take an explicit context argument we have
   * to immediately make our pointer the default context.
   */
  _context = context;

  /* Init default values */
  memset (context->features, 0, sizeof (context->features));
  context->feature_flags = 0;
  context->private_feature_flags = 0;

  context->texture_types = NULL;
  context->buffer_types = NULL;

  context->rectangle_state = COGL_WINSYS_RECTANGLE_STATE_UNKNOWN;

  memset (context->winsys_features, 0, sizeof (context->winsys_features));

  if (!display)
    {
      CoglRenderer *renderer = cogl_renderer_new ();
      if (!cogl_renderer_connect (renderer, error))
        {
          g_free (context);
          return NULL;
        }

      display = cogl_display_new (renderer, NULL);
    }
  else
    cogl_object_ref (display);

  if (!cogl_display_setup (display, error))
    {
      cogl_object_unref (display);
      g_free (context);
      return NULL;
    }

  context->display = display;

  /* This is duplicated data, but it's much more convenient to have
     the driver attached to the context and the value is accessed a
     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 ();
    }

  winsys = _cogl_context_get_winsys (context);
  if (!winsys->context_init (context, error))
    {
      cogl_object_unref (display);
      g_free (context);
      return NULL;
    }

  context->attribute_name_states_hash =
    g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
  context->attribute_name_index_map = NULL;
  context->n_attribute_names = 0;

  /* The "cogl_color_in" attribute needs a deterministic name_index
   * so we make sure it's the first attribute name we register */
  _cogl_attribute_register_attribute_name (context, "cogl_color_in");


  context->uniform_names =
    g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
  context->uniform_name_hash = g_hash_table_new (g_str_hash, g_str_equal);
  context->n_uniform_names = 0;

  /* Initialise the driver specific state */
  _cogl_init_feature_overrides (context);

  _context->sampler_cache = _cogl_sampler_cache_new (_context);

  _cogl_pipeline_init_default_pipeline ();
  _cogl_pipeline_init_default_layers ();
  _cogl_pipeline_init_state_hash_functions ();
  _cogl_pipeline_init_layer_state_hash_functions ();

  context->current_clip_stack_valid = FALSE;
  context->current_clip_stack = NULL;

  cogl_matrix_init_identity (&context->identity_matrix);
  cogl_matrix_init_identity (&context->y_flip_matrix);
  cogl_matrix_scale (&context->y_flip_matrix, 1, -1, 1);

  context->flushed_matrix_mode = COGL_MATRIX_MODELVIEW;

  context->texture_units =
    g_array_new (FALSE, FALSE, sizeof (CoglTextureUnit));

  /* See cogl-pipeline.c for more details about why we leave texture unit 1
   * active by default... */
  context->active_texture_unit = 1;
  GE (context, glActiveTexture (GL_TEXTURE1));

  context->opaque_color_pipeline = cogl_pipeline_new (context);
  context->blended_color_pipeline = cogl_pipeline_new (context);
  context->texture_pipeline = cogl_pipeline_new (context);
  context->codegen_header_buffer = g_string_new ("");
  context->codegen_source_buffer = g_string_new ("");

  context->default_gl_texture_2d_tex = NULL;
  context->default_gl_texture_3d_tex = NULL;
  context->default_gl_texture_rect_tex = NULL;

  context->framebuffers = NULL;
  context->current_draw_buffer = NULL;
  context->current_read_buffer = NULL;
  context->current_draw_buffer_state_flushed = 0;
  context->current_draw_buffer_changes = COGL_FRAMEBUFFER_STATE_ALL;

  g_queue_init (&context->gles2_context_stack);

  context->journal_flush_attributes_array =
    g_array_new (TRUE, FALSE, sizeof (CoglAttribute *));
  context->journal_clip_bounds = NULL;

  context->polygon_vertices = g_array_new (FALSE, FALSE, sizeof (float));

  context->current_pipeline = NULL;
  context->current_pipeline_changes_since_flush = 0;
  context->current_pipeline_skip_gl_color = FALSE;

  _cogl_bitmask_init (&context->enabled_builtin_attributes);
  _cogl_bitmask_init (&context->enable_builtin_attributes_tmp);
  _cogl_bitmask_init (&context->enabled_texcoord_attributes);
  _cogl_bitmask_init (&context->enable_texcoord_attributes_tmp);
  _cogl_bitmask_init (&context->enabled_custom_attributes);
  _cogl_bitmask_init (&context->enable_custom_attributes_tmp);
  _cogl_bitmask_init (&context->changed_bits_tmp);

  context->max_texture_units = -1;
  context->max_activateable_texture_units = -1;

  context->current_fragment_program_type = COGL_PIPELINE_PROGRAM_TYPE_FIXED;
  context->current_vertex_program_type = COGL_PIPELINE_PROGRAM_TYPE_FIXED;
  context->current_gl_program = 0;

  context->current_gl_dither_enabled = TRUE;
  context->current_gl_color_mask = COGL_COLOR_MASK_ALL;

  context->gl_blend_enable_cache = FALSE;

  context->depth_test_enabled_cache = FALSE;
  context->depth_test_function_cache = COGL_DEPTH_TEST_FUNCTION_LESS;
  context->depth_writing_enabled_cache = TRUE;
  context->depth_range_near_cache = 0;
  context->depth_range_far_cache = 1;

  context->pipeline_cache = cogl_pipeline_cache_new ();

  for (i = 0; i < COGL_BUFFER_BIND_TARGET_COUNT; i++)
    context->current_buffer[i] = NULL;

  context->window_buffer = NULL;
  context->framebuffer_stack = _cogl_create_framebuffer_stack ();

  /* XXX: In this case the Clutter backend is still responsible for
   * the OpenGL binding API and for creating onscreen framebuffers and
   * so we have to add a dummy framebuffer to represent the backend
   * owned window... */
  if (_cogl_context_get_winsys (context) == _cogl_winsys_stub_get_vtable ())
    {
      CoglOnscreen *window = _cogl_onscreen_new ();
      cogl_set_framebuffer (COGL_FRAMEBUFFER (window));
      cogl_object_unref (COGL_FRAMEBUFFER (window));
    }

  context->stencil_pipeline = cogl_pipeline_new (context);

  context->in_begin_gl_block = FALSE;

  context->quad_buffer_indices_byte = NULL;
  context->quad_buffer_indices = NULL;
  context->quad_buffer_indices_len = 0;

  context->rectangle_byte_indices = NULL;
  context->rectangle_short_indices = NULL;
  context->rectangle_short_indices_len = 0;

  context->texture_download_pipeline = NULL;
  context->blit_texture_pipeline = NULL;

#if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
  if (context->driver != COGL_DRIVER_GLES2)
    /* The default for GL_ALPHA_TEST is to always pass which is equivalent to
     * the test being disabled therefore we assume that for all drivers there
     * will be no performance impact if we always leave the test enabled which
     * makes things a bit simpler for us. Under GLES2 the alpha test is
     * implemented in the fragment shader so there is no enable for it
     */
    GE (context, glEnable (GL_ALPHA_TEST));
#endif

  _context->current_modelview_entry = NULL;
  _context->current_projection_entry = NULL;
  _cogl_matrix_entry_identity_init (&_context->identity_entry);
  _cogl_matrix_entry_cache_init (&_context->builtin_flushed_projection);
  _cogl_matrix_entry_cache_init (&_context->builtin_flushed_modelview);

  default_texture_bitmap =
    cogl_bitmap_new_for_data (_context,
                              1, 1, /* width/height */
                              COGL_PIXEL_FORMAT_RGBA_8888_PRE,
                              4, /* rowstride */
                              default_texture_data);

  /* Create default textures used for fall backs */
  context->default_gl_texture_2d_tex =
    cogl_texture_2d_new_from_bitmap (default_texture_bitmap,
                                     /* internal format */
                                     COGL_PIXEL_FORMAT_RGBA_8888_PRE,
                                     NULL);
  /* If 3D or rectangle textures aren't supported then these should
     just silently return NULL */
  context->default_gl_texture_3d_tex =
    cogl_texture_3d_new_from_bitmap (default_texture_bitmap,
                                     1, /* height */
                                     1, /* depth */
                                     COGL_PIXEL_FORMAT_RGBA_8888_PRE,
                                     NULL);
  context->default_gl_texture_rect_tex =
    cogl_texture_rectangle_new_from_bitmap (default_texture_bitmap,
                                            COGL_PIXEL_FORMAT_RGBA_8888_PRE,
                                            NULL);

  cogl_object_unref (default_texture_bitmap);

  context->atlases = NULL;
  g_hook_list_init (&context->atlas_reorganize_callbacks, sizeof (GHook));

  _context->buffer_map_fallback_array = g_byte_array_new ();
  _context->buffer_map_fallback_in_use = FALSE;

  /* As far as I can tell, GL_POINT_SPRITE doesn't have any effect
     unless GL_COORD_REPLACE is enabled for an individual
     layer. Therefore it seems like it should be ok to just leave it
     enabled all the time instead of having to have a set property on
     each pipeline to track whether any layers have point sprite
     coords enabled. We don't need to do this for GLES2 because point
     sprites are handled using a builtin varying in the shader. */
  if (_context->driver != COGL_DRIVER_GLES2 &&
      cogl_has_feature (context, COGL_FEATURE_ID_POINT_SPRITE))
    GE (context, glEnable (GL_POINT_SPRITE));

  return context;
}
Beispiel #5
0
CoglTexture2D *
cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx,
        struct wl_resource *buffer,
        CoglError **error)
{
    struct wl_shm_buffer *shm_buffer;
    CoglTexture2D *tex = NULL;

    shm_buffer = wl_shm_buffer_get (buffer);

    if (shm_buffer)
    {
        int stride = wl_shm_buffer_get_stride (shm_buffer);
        int width = wl_shm_buffer_get_width (shm_buffer);
        int height = wl_shm_buffer_get_height (shm_buffer);
        CoglPixelFormat format;
        CoglTextureComponents components;
        CoglBitmap *bmp;

        shm_buffer_get_cogl_pixel_format (shm_buffer, &format, &components);

        bmp = cogl_bitmap_new_for_data (ctx,
                                        width, height,
                                        format,
                                        stride,
                                        wl_shm_buffer_get_data (shm_buffer));

        tex = cogl_texture_2d_new_from_bitmap (bmp);

        cogl_texture_set_components (COGL_TEXTURE (tex), components);

        cogl_object_unref (bmp);

        if (!cogl_texture_allocate (COGL_TEXTURE (tex), error))
        {
            cogl_object_unref (tex);
            return NULL;
        }
        else
            return tex;
    }
    else
    {
        int format, width, height;

        if (_cogl_egl_query_wayland_buffer (ctx,
                                            buffer,
                                            EGL_TEXTURE_FORMAT,
                                            &format) &&
                _cogl_egl_query_wayland_buffer (ctx,
                                                buffer,
                                                EGL_WIDTH,
                                                &width) &&
                _cogl_egl_query_wayland_buffer (ctx,
                                                buffer,
                                                EGL_HEIGHT,
                                                &height))
        {
            EGLImageKHR image;
            CoglPixelFormat internal_format;

            _COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints &
                                      COGL_RENDERER_CONSTRAINT_USES_EGL,
                                      NULL);

            switch (format)
            {
            case EGL_TEXTURE_RGB:
                internal_format = COGL_PIXEL_FORMAT_RGB_888;
                break;
            case EGL_TEXTURE_RGBA:
                internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
                break;
            default:
                _cogl_set_error (error,
                                 COGL_SYSTEM_ERROR,
                                 COGL_SYSTEM_ERROR_UNSUPPORTED,
                                 "Can't create texture from unknown "
                                 "wayland buffer format %d\n", format);
                return NULL;
            }

            image = _cogl_egl_create_image (ctx,
                                            EGL_WAYLAND_BUFFER_WL,
                                            buffer,
                                            NULL);
            tex = _cogl_egl_texture_2d_new_from_image (ctx,
                    width, height,
                    internal_format,
                    image,
                    error);
            _cogl_egl_destroy_image (ctx, image);
            return tex;
        }
    }

    _cogl_set_error (error,
                     COGL_SYSTEM_ERROR,
                     COGL_SYSTEM_ERROR_UNSUPPORTED,
                     "Can't create texture from unknown "
                     "wayland buffer type\n");
    return NULL;
}
CoglTexture *
cogl_texture_new_from_bitmap (CoglBitmap *bitmap,
                              CoglTextureFlags flags,
                              CoglPixelFormat internal_format,
                              CoglError **error)
{
  CoglContext *ctx = _cogl_bitmap_get_context (bitmap);
  CoglAtlasTexture *atlas_tex;
  CoglTexture *tex;
  CoglError *internal_error = NULL;

  /* First try putting the texture in the atlas */
  if ((atlas_tex = _cogl_atlas_texture_new_from_bitmap (bitmap,
                                                        flags,
                                                        internal_format,
                                                        &internal_error)))
    return COGL_TEXTURE (atlas_tex);

  if (cogl_error_matches (internal_error,
                          COGL_SYSTEM_ERROR,
                          COGL_SYSTEM_ERROR_NO_MEMORY))
    {
      _cogl_propagate_error (error, internal_error);
      return NULL;
    }

  cogl_error_free (internal_error);
  internal_error = NULL;

  /* If that doesn't work try a fast path 2D texture */
  if ((_cogl_util_is_pot (bitmap->width) &&
       _cogl_util_is_pot (bitmap->height)) ||
      (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) &&
       cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP)))
    {
      tex = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmap,
                                                           internal_format,
                                                           &internal_error));

      if (cogl_error_matches (internal_error,
                              COGL_SYSTEM_ERROR,
                              COGL_SYSTEM_ERROR_NO_MEMORY))
        {
          _cogl_propagate_error (error, internal_error);
          return NULL;
        }

      if (!tex)
        {
          cogl_error_free (internal_error);
          internal_error = NULL;
        }
    }
  else
    tex = NULL;

  if (tex)
    {
      CoglBool auto_mipmap = !(flags & COGL_TEXTURE_NO_AUTO_MIPMAP);
      cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (tex),
                                              auto_mipmap);
    }
  else
    {
      /* Otherwise create a sliced texture */
      tex = COGL_TEXTURE (_cogl_texture_2d_sliced_new_from_bitmap (bitmap,
                                                             flags,
                                                             internal_format,
                                                             error));
    }

  return tex;
}
Beispiel #7
0
RutAsset *
rut_asset_new_from_data (RutContext *ctx,
                         const char *path,
                         RutAssetType type,
                         uint8_t *data,
                         size_t len)
{
  RutAsset *asset = g_slice_new0 (RutAsset);

  rut_object_init (&asset->_parent, &rut_asset_type);

  asset->ref_count = 1;

  asset->ctx = ctx;

  asset->type = type;

  switch (type)
    {
    case RUT_ASSET_TYPE_BUILTIN:
    case RUT_ASSET_TYPE_TEXTURE:
    case RUT_ASSET_TYPE_NORMAL_MAP:
    case RUT_ASSET_TYPE_ALPHA_MASK:
      {
        GInputStream *istream = g_memory_input_stream_new_from_data (data, len, NULL);
        GError *error = NULL;
        GdkPixbuf *pixbuf = gdk_pixbuf_new_from_stream (istream, NULL, &error);
        CoglBitmap *bitmap;
        CoglError *cogl_error = NULL;

        if (!pixbuf)
          {
            g_slice_free (RutAsset, asset);
            g_warning ("Failed to load asset texture: %s", error->message);
            g_error_free (error);
            return NULL;
          }

        g_object_unref (istream);

        bitmap = bitmap_new_from_pixbuf (ctx->cogl_context, pixbuf);

        asset->texture = COGL_TEXTURE (
          cogl_texture_2d_new_from_bitmap (bitmap,
                                           COGL_PIXEL_FORMAT_ANY,
                                           &cogl_error));

        cogl_object_unref (bitmap);
        g_object_unref (pixbuf);

        if (!asset->texture)
          {
            g_slice_free (RutAsset, asset);
            g_warning ("Failed to load asset texture: %s", cogl_error->message);
            cogl_error_free (cogl_error);
            return NULL;
          }

        break;
      }
    case RUT_ASSET_TYPE_PLY_MODEL:
      {
        RutPLYAttributeStatus padding_status[G_N_ELEMENTS (ply_attributes)];
        GError *error = NULL;

        asset->mesh = rut_mesh_new_from_ply_data (ctx,
                                                  data,
                                                  len,
                                                  ply_attributes,
                                                  G_N_ELEMENTS (ply_attributes),
                                                  padding_status,
                                                  &error);
        if (!asset->mesh)
          {
            g_slice_free (RutAsset, asset);
            g_warning ("could not load model %s: %s", path, error->message);
            g_error_free (error);
            return NULL;
          }

        break;
      }
    }

  asset->path = g_strdup (path);

  return asset;
}
Beispiel #8
0
static gboolean
shm_buffer_attach (MetaWaylandBuffer  *buffer,
                   CoglTexture       **texture,
                   gboolean           *changed_texture,
                   GError            **error)
{
  MetaBackend *backend = meta_get_backend ();
  ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
  CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
  struct wl_shm_buffer *shm_buffer;
  int stride, width, height;
  CoglPixelFormat format;
  CoglTextureComponents components;
  CoglBitmap *bitmap;
  CoglTexture *new_texture;

  shm_buffer = wl_shm_buffer_get (buffer->resource);
  stride = wl_shm_buffer_get_stride (shm_buffer);
  width = wl_shm_buffer_get_width (shm_buffer);
  height = wl_shm_buffer_get_height (shm_buffer);
  shm_buffer_get_cogl_pixel_format (shm_buffer, &format, &components);

  if (*texture &&
      cogl_texture_get_width (*texture) == width &&
      cogl_texture_get_height (*texture) == height &&
      cogl_texture_get_components (*texture) == components &&
      _cogl_texture_get_format (*texture) == format)
    {
      buffer->is_y_inverted = TRUE;
      *changed_texture = FALSE;
      return TRUE;
    }

  cogl_clear_object (texture);

  wl_shm_buffer_begin_access (shm_buffer);

  bitmap = cogl_bitmap_new_for_data (cogl_context,
                                     width, height,
                                     format,
                                     stride,
                                     wl_shm_buffer_get_data (shm_buffer));

  new_texture = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmap));
  cogl_texture_set_components (new_texture, components);

  if (!cogl_texture_allocate (new_texture, error))
    {
      g_clear_pointer (&new_texture, cogl_object_unref);
      if (g_error_matches (*error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_SIZE))
        {
          CoglTexture2DSliced *texture_sliced;

          g_clear_error (error);

          texture_sliced =
            cogl_texture_2d_sliced_new_from_bitmap (bitmap,
                                                    COGL_TEXTURE_MAX_WASTE);
          new_texture = COGL_TEXTURE (texture_sliced);
          cogl_texture_set_components (new_texture, components);

          if (!cogl_texture_allocate (new_texture, error))
            g_clear_pointer (&new_texture, cogl_object_unref);
        }
    }

  cogl_object_unref (bitmap);

  wl_shm_buffer_end_access (shm_buffer);

  if (!new_texture)
    return FALSE;

  *texture = new_texture;
  *changed_texture = TRUE;
  buffer->is_y_inverted = TRUE;

  return TRUE;
}