Example #1
0
/**
 * clutter_image_set_area:
 * @image: a #ClutterImage
 * @data: (array): the image data, as an array of bytes
 * @pixel_format: the Cogl pixel format of the image data
 * @rect: a rectangle indicating the area that should be set
 * @row_stride: the length of each row inside @data
 * @error: return location for a #GError, or %NULL
 *
 * Sets the image data to be display by @image, using @rect to indicate
 * the position and size of the image data to be set.
 *
 * If the @image does not have any image data set when this function is
 * called, a new texture will be created with the size of the width and
 * height of the rectangle, i.e. calling this function on a newly created
 * #ClutterImage will be the equivalent of calling clutter_image_set_data().
 *
 * If the image data was successfully loaded, the @image will be invalidated.
 *
 * In case of error, the @error value will be set, and this function will
 * return %FALSE.
 *
 * The image data is copied in texture memory.
 *
 * Return value: %TRUE if the image data was successfully loaded,
 *   and %FALSE otherwise.
 *
 * Since: 1.10
 */
gboolean
clutter_image_set_area (ClutterImage                 *image,
                        const guint8                 *data,
                        CoglPixelFormat               pixel_format,
                        const cairo_rectangle_int_t  *area,
                        guint                         row_stride,
                        GError                      **error)
{
  ClutterImagePrivate *priv;

  g_return_val_if_fail (CLUTTER_IS_IMAGE (image), FALSE);
  g_return_val_if_fail (data != NULL, FALSE);
  g_return_val_if_fail (area != NULL, FALSE);

  priv = image->priv;

  if (priv->texture == NULL)
    {
      CoglTextureFlags flags = COGL_TEXTURE_NONE;

      if (area->width >= 512 && area->height >= 512)
        flags |= COGL_TEXTURE_NO_ATLAS;

      priv->texture = cogl_texture_new_from_data (area->width,
                                                  area->height,
                                                  flags,
                                                  pixel_format,
                                                  COGL_PIXEL_FORMAT_ANY,
                                                  row_stride,
                                                  data);
    }
  else
    {
      gboolean res;

      res = cogl_texture_set_region (priv->texture,
                                     0, 0,
                                     area->x, area->y,
                                     area->width, area->height,
                                     area->width, area->height,
                                     pixel_format,
                                     row_stride,
                                     data);

      if (!res)
        {
          cogl_object_unref (priv->texture);
          priv->texture = NULL;
        }
    }

  if (priv->texture == NULL)
    {
      g_set_error_literal (error, CLUTTER_IMAGE_ERROR,
                           CLUTTER_IMAGE_ERROR_INVALID_DATA,
                           _("Unable to load image data"));
      return FALSE;
    }

  clutter_content_invalidate (CLUTTER_CONTENT (image));

  return TRUE;
}
void
_cogl_texture_driver_upload_to_gl_3d (GLenum       gl_target,
                                      GLuint       gl_handle,
                                      gboolean     is_foreign,
                                      GLint        height,
                                      GLint        depth,
                                      CoglBitmap  *source_bmp,
                                      GLint        internal_gl_format,
                                      GLuint       source_gl_format,
                                      GLuint       source_gl_type)
{
    int bpp = _cogl_get_format_bpp (_cogl_bitmap_get_format (source_bmp));
    int rowstride = _cogl_bitmap_get_rowstride (source_bmp);
    int bmp_width = _cogl_bitmap_get_width (source_bmp);
    int bmp_height = _cogl_bitmap_get_height (source_bmp);
    guint8 *data;

    _COGL_GET_CONTEXT (ctx, NO_RETVAL);

    _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);

    /* If the rowstride or image height can't be specified with just
       GL_ALIGNMENT alone then we need to copy the bitmap because there
       is no GL_ROW_LENGTH */
    if (rowstride / bpp != bmp_width ||
            height != bmp_height / depth)
    {
        CoglBitmap *bmp;
        int image_height = bmp_height / depth;
        int i;

        _cogl_texture_driver_prep_gl_for_pixels_upload (bmp_width * bpp, bpp);

        /* Initialize the texture with empty data and then upload each
           image with a sub-region update */

        GE( glTexImage3D (gl_target,
                          0, /* level */
                          internal_gl_format,
                          bmp_width,
                          height,
                          depth,
                          0,
                          source_gl_format,
                          source_gl_type,
                          NULL) );

        bmp = _cogl_bitmap_new_from_data (g_malloc (bpp * bmp_width * height),
                                          _cogl_bitmap_get_format (source_bmp),
                                          bmp_width,
                                          height,
                                          bpp * bmp_width,
                                          (CoglBitmapDestroyNotify) g_free,
                                          NULL);

        for (i = 0; i < depth; i++)
        {
            _cogl_bitmap_copy_subregion (source_bmp,
                                         bmp,
                                         0, image_height * i,
                                         0, 0,
                                         bmp_width,
                                         height);

            data = _cogl_bitmap_bind (bmp,
                                      COGL_BUFFER_ACCESS_READ, 0);

            GE( glTexSubImage3D (gl_target,
                                 0, /* level */
                                 0, /* xoffset */
                                 0, /* yoffset */
                                 i, /* zoffset */
                                 bmp_width, /* width */
                                 height, /* height */
                                 1, /* depth */
                                 source_gl_format,
                                 source_gl_type,
                                 data) );

            _cogl_bitmap_unbind (bmp);
        }

        cogl_object_unref (bmp);
    }
    else
    {
        data = _cogl_bitmap_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0);

        _cogl_texture_driver_prep_gl_for_pixels_upload (rowstride, bpp);

        GE( glTexImage3D (gl_target,
                          0, /* level */
                          internal_gl_format,
                          bmp_width,
                          height,
                          depth,
                          0,
                          source_gl_format,
                          source_gl_type,
                          data) );

        _cogl_bitmap_unbind (source_bmp);
    }
}
Example #3
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;
}
static void
paint_test_backface_culling (TestState *state,
                             CoglFramebuffer *framebuffer)
{
  int draw_num;
  CoglPipeline *base_pipeline = cogl_pipeline_new (test_ctx);

  cogl_framebuffer_orthographic (framebuffer,
                                 0, 0,
                                 state->width,
                                 state->height,
                                 -1,
                                 100);

  cogl_framebuffer_clear4f (framebuffer,
                            COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_STENCIL,
                            0, 0, 0, 1);

  cogl_pipeline_set_layer_texture (base_pipeline, 0, state->texture);

  cogl_pipeline_set_layer_filters (base_pipeline, 0,
                                   COGL_PIPELINE_FILTER_NEAREST,
                                   COGL_PIPELINE_FILTER_NEAREST);

  /* Render the scene eight times to test all of the combinations of
     cull face mode and winding orders */
  for (draw_num = 0; draw_num < 8; draw_num++)
    {
      float x1 = 0, x2, y1 = 0, y2 = (float)(TEXTURE_RENDER_SIZE);
      CoglTextureVertex verts[4];
      CoglPipeline *pipeline;

      cogl_framebuffer_push_matrix (framebuffer);
      cogl_framebuffer_translate (framebuffer,
                                  0, TEXTURE_RENDER_SIZE * draw_num, 0);

      pipeline = cogl_pipeline_copy (base_pipeline);

      cogl_pipeline_set_front_face_winding (pipeline, FRONT_WINDING (draw_num));
      cogl_pipeline_set_cull_face_mode (pipeline, CULL_FACE_MODE (draw_num));

      memset (verts, 0, sizeof (verts));

      x2 = x1 + (float)(TEXTURE_RENDER_SIZE);

      /* Draw a front-facing texture */
      cogl_framebuffer_draw_rectangle (framebuffer, pipeline, x1, y1, x2, y2);

      x1 = x2;
      x2 = x1 + (float)(TEXTURE_RENDER_SIZE);

      /* Draw a front-facing texture with flipped texcoords */
      cogl_framebuffer_draw_textured_rectangle (framebuffer,
                                                pipeline,
                                                x1, y1, x2, y2,
                                                1.0, 0.0, 0.0, 1.0);

      x1 = x2;
      x2 = x1 + (float)(TEXTURE_RENDER_SIZE);

      /* Draw a back-facing texture */
      cogl_framebuffer_draw_rectangle (framebuffer, pipeline, x2, y1, x1, y2);

      cogl_framebuffer_pop_matrix (framebuffer);

      cogl_object_unref (pipeline);
    }

  cogl_object_unref (base_pipeline);
}
Example #5
0
static void
ensure_xfixes_cursor (MetaCursorTracker *tracker)
{
  MetaDisplay *display = meta_get_display ();
  XFixesCursorImage *cursor_image;
  CoglTexture2D *sprite;
  guint8 *cursor_data;
  gboolean free_cursor_data;
  CoglContext *ctx;
  CoglError *error = NULL;

  if (tracker->xfixes_cursor)
    return;

  cursor_image = XFixesGetCursorImage (display->xdisplay);
  if (!cursor_image)
    return;

  /* Like all X APIs, XFixesGetCursorImage() returns arrays of 32-bit
   * quantities as arrays of long; we need to convert on 64 bit */
  if (sizeof(long) == 4)
    {
      cursor_data = (guint8 *)cursor_image->pixels;
      free_cursor_data = FALSE;
    }
  else
    {
      int i, j;
      guint32 *cursor_words;
      gulong *p;
      guint32 *q;

      cursor_words = g_new (guint32, cursor_image->width * cursor_image->height);
      cursor_data = (guint8 *)cursor_words;

      p = cursor_image->pixels;
      q = cursor_words;
      for (j = 0; j < cursor_image->height; j++)
        for (i = 0; i < cursor_image->width; i++)
          *(q++) = *(p++);

      free_cursor_data = TRUE;
    }

  ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
  sprite = cogl_texture_2d_new_from_data (ctx,
                                          cursor_image->width,
                                          cursor_image->height,
                                          CLUTTER_CAIRO_FORMAT_ARGB32,
                                          cursor_image->width * 4, /* stride */
                                          cursor_data,
                                          &error);

  if (free_cursor_data)
    g_free (cursor_data);

  if (error != NULL)
    {
      meta_warning ("Failed to allocate cursor sprite texture: %s\n", error->message);
      cogl_error_free (error);
    }

  if (sprite != NULL)
    {
      MetaCursorSprite *cursor_sprite = meta_cursor_sprite_new ();
      meta_cursor_sprite_set_texture (cursor_sprite,
                                      sprite,
                                      cursor_image->xhot,
                                      cursor_image->yhot);
      cogl_object_unref (sprite);
      tracker->xfixes_cursor = cursor_sprite;
    }
  XFree (cursor_image);
}
Example #6
0
int
main (int argc, char *argv[])
{
  CoglTexture *tex;
  CoglOnscreen *onscreen;
  GSource *cogl_source;
  GMainLoop *loop;
  Data data;
  int i;

  data.context = cogl_context_new (NULL, NULL);

  create_primitive (&data);

  data.pipeline = cogl_pipeline_new (data.context);
  data.last_spark_time = g_timer_new ();
  data.next_spark_num = 0;
  cogl_pipeline_set_point_size (data.pipeline, TEXTURE_SIZE);

  tex = generate_round_texture (data.context);
  cogl_pipeline_set_layer_texture (data.pipeline, 0, tex);
  cogl_object_unref (tex);

  cogl_pipeline_set_layer_point_sprite_coords_enabled (data.pipeline,
                                                       0, /* layer */
                                                       TRUE,
                                                       NULL /* error */);

  for (i = 0; i < N_FIREWORKS; i++)
    {
      data.fireworks[i].x = -FLT_MAX;
      data.fireworks[i].y = FLT_MAX;
      data.fireworks[i].size = 0.0f;
      data.fireworks[i].timer = g_timer_new ();
    }

  for (i = 0; i < N_SPARKS; i++)
    {
      data.sparks[i].x = 2.0f;
      data.sparks[i].y = 2.0f;
    }

  onscreen = cogl_onscreen_new (data.context, 800, 600);
  cogl_onscreen_show (onscreen);
  data.fb = onscreen;

  cogl_source = cogl_glib_source_new (data.context, G_PRIORITY_DEFAULT);

  g_source_attach (cogl_source, NULL);

  cogl_onscreen_add_frame_callback (onscreen,
                                    frame_event_cb,
                                    &data,
                                    NULL /* destroy notify */);

  loop = g_main_loop_new (NULL, TRUE);

  paint (&data);

  g_main_loop_run (loop);

  g_main_loop_unref (loop);

  g_source_destroy (cogl_source);

  cogl_object_unref (data.pipeline);
  cogl_object_unref (data.attribute_buffer);
  cogl_object_unref (data.primitive);
  cogl_object_unref (onscreen);
  cogl_object_unref (data.context);

  g_timer_destroy (data.last_spark_time);

  for (i = 0; i < N_FIREWORKS; i++)
    g_timer_destroy (data.fireworks[i].timer);

  return 0;
}
Example #7
0
static void
test_byte_verts (TestState *state, int offset_x, int offset_y)
{
  CoglAttribute *attributes[2];
  CoglAttributeBuffer *buffer, *unnorm_buffer;
  CoglPrimitive *primitive;

  static const ByteVert norm_verts[] =
    {
      { 0, 10, /**/ 255, 0, 0, 255 },
      { 10, 10, /**/ 255, 0, 0, 255 },
      { 5, 0, /**/ 255, 0, 0, 255 },

      { 10, 10, /**/ 0, 255, 0, 255 },
      { 20, 10, /**/ 0, 255, 0, 255 },
      { 15, 0, /**/ 0, 255, 0, 255 }
    };

  static const ByteVert unnorm_verts[] =
    {
      { 0, 0, /**/ 0, 0, 1, 1 },
      { 0, 0, /**/ 0, 0, 1, 1 },
      { 0, 0, /**/ 0, 0, 1, 1 },
    };

  buffer = cogl_attribute_buffer_new (test_ctx,
                                      sizeof (norm_verts), norm_verts);
  attributes[0] = cogl_attribute_new (buffer,
                                      "cogl_position_in",
                                      sizeof (ByteVert),
                                      G_STRUCT_OFFSET (ByteVert, x),
                                      2, /* n_components */
                                      COGL_ATTRIBUTE_TYPE_SHORT);
  attributes[1] = cogl_attribute_new (buffer,
                                      "color",
                                      sizeof (ByteVert),
                                      G_STRUCT_OFFSET (ByteVert, r),
                                      4, /* n_components */
                                      COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
  cogl_attribute_set_normalized (attributes[1], TRUE);

  cogl_framebuffer_push_matrix (test_fb);
  cogl_framebuffer_translate (test_fb, offset_x, offset_y, 0.0f);

  primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES,
                                                  6, /* n_vertices */
                                                  attributes,
                                                  2); /* n_attributes */
  cogl_primitive_draw (primitive, test_fb, state->pipeline);
  cogl_object_unref (primitive);

  cogl_object_unref (attributes[1]);

  /* Test again with unnormalized attributes */
  unnorm_buffer = cogl_attribute_buffer_new (test_ctx,
                                             sizeof (unnorm_verts),
                                             unnorm_verts);
  attributes[1] = cogl_attribute_new (unnorm_buffer,
                                      "color",
                                      sizeof (ByteVert),
                                      G_STRUCT_OFFSET (ByteVert, r),
                                      4, /* n_components */
                                      COGL_ATTRIBUTE_TYPE_BYTE);

  cogl_framebuffer_translate (test_fb, 20, 0, 0);

  primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES,
                                                  3, /* n_vertices */
                                                  attributes,
                                                  2); /* n_attributes */
  cogl_primitive_draw (primitive, test_fb, state->pipeline);
  cogl_object_unref (primitive);

  cogl_framebuffer_pop_matrix (test_fb);

  cogl_object_unref (attributes[0]);
  cogl_object_unref (attributes[1]);
  cogl_object_unref (buffer);
  cogl_object_unref (unnorm_buffer);

  test_utils_check_pixel (test_fb, offset_x + 5, offset_y + 5, 0xff0000ff);
  test_utils_check_pixel (test_fb, offset_x + 15, offset_y + 5, 0x00ff00ff);
  test_utils_check_pixel (test_fb, offset_x + 25, offset_y + 5, 0x0000ffff);
}
Example #8
0
void
cogl_handle_unref (CoglHandle handle)
{
  cogl_object_unref (handle);
}
Example #9
0
static void
clutter_stage_glx_redraw (ClutterStageWindow *stage_window)
{
  ClutterBackendX11 *backend_x11;
  ClutterBackendGLX *backend_glx;
  ClutterStageX11 *stage_x11;
  ClutterStageGLX *stage_glx;
  GLXDrawable drawable;
  unsigned int video_sync_count;
  gboolean may_use_clipped_redraw;
  gboolean use_clipped_redraw;

  CLUTTER_STATIC_TIMER (painting_timer,
                        "Redrawing", /* parent */
                        "Painting actors",
                        "The time spent painting actors",
                        0 /* no application private data */);
  CLUTTER_STATIC_TIMER (swapbuffers_timer,
                        "Redrawing", /* parent */
                        "glXSwapBuffers",
                        "The time spent blocked by glXSwapBuffers",
                        0 /* no application private data */);
  CLUTTER_STATIC_TIMER (blit_sub_buffer_timer,
                        "Redrawing", /* parent */
                        "glx_blit_sub_buffer",
                        "The time spent in _glx_blit_sub_buffer",
                        0 /* no application private data */);

  stage_x11 = CLUTTER_STAGE_X11 (stage_window);
  if (stage_x11->xwin == None)
    return;

  stage_glx = CLUTTER_STAGE_GLX (stage_window);

  backend_x11 = stage_x11->backend;
  backend_glx = CLUTTER_BACKEND_GLX (backend_x11);

  CLUTTER_TIMER_START (_clutter_uprof_context, painting_timer);

  if (G_LIKELY (backend_glx->can_blit_sub_buffer) &&
      /* NB: a zero width redraw clip == full stage redraw */
      stage_glx->bounding_redraw_clip.width != 0 &&
      /* some drivers struggle to get going and produce some junk
       * frames when starting up... */
      G_LIKELY (stage_glx->frame_count > 3) &&
      /* While resizing a window clipped redraws are disabled to avoid
       * artefacts. See clutter-event-x11.c:event_translate for a
       * detailed explanation */
      G_LIKELY (stage_x11->clipped_redraws_cool_off == 0))
    {
      may_use_clipped_redraw = TRUE;
    }
  else
    may_use_clipped_redraw = FALSE;

  if (may_use_clipped_redraw &&
      G_LIKELY (!(clutter_paint_debug_flags &
                  CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
    use_clipped_redraw = TRUE;
  else
    use_clipped_redraw = FALSE;

  if (use_clipped_redraw)
    {
      CLUTTER_NOTE (CLIPPING,
                    "Stage clip pushed: x=%d, y=%d, width=%d, height=%d\n",
                    stage_glx->bounding_redraw_clip.x,
                    stage_glx->bounding_redraw_clip.y,
                    stage_glx->bounding_redraw_clip.width,
                    stage_glx->bounding_redraw_clip.height);
      cogl_clip_push_window_rectangle (stage_glx->bounding_redraw_clip.x,
                                       stage_glx->bounding_redraw_clip.y,
                                       stage_glx->bounding_redraw_clip.width,
                                       stage_glx->bounding_redraw_clip.height);
      _clutter_stage_do_paint (stage_x11->wrapper,
                               &stage_glx->bounding_redraw_clip);
      cogl_clip_pop ();
    }
  else
    {
      CLUTTER_NOTE (CLIPPING, "Unclipped stage paint\n");
      _clutter_stage_do_paint (stage_x11->wrapper, NULL);
    }

  if (may_use_clipped_redraw &&
      G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS)))
    {
      static CoglMaterial *outline = NULL;
      ClutterGeometry *clip = &stage_glx->bounding_redraw_clip;
      ClutterActor *actor = CLUTTER_ACTOR (stage_x11->wrapper);
      CoglHandle vbo;
      float x_1 = clip->x;
      float x_2 = clip->x + clip->width;
      float y_1 = clip->y;
      float y_2 = clip->y + clip->height;
      float quad[8] = {
        x_1, y_1,
        x_2, y_1,
        x_2, y_2,
        x_1, y_2
      };
      CoglMatrix modelview;

      if (outline == NULL)
        {
          outline = cogl_material_new ();
          cogl_material_set_color4ub (outline, 0xff, 0x00, 0x00, 0xff);
        }

      vbo = cogl_vertex_buffer_new (4);
      cogl_vertex_buffer_add (vbo,
                              "gl_Vertex",
                              2, /* n_components */
                              COGL_ATTRIBUTE_TYPE_FLOAT,
                              FALSE, /* normalized */
                              0, /* stride */
                              quad);
      cogl_vertex_buffer_submit (vbo);

      cogl_push_matrix ();
      cogl_matrix_init_identity (&modelview);
      _clutter_actor_apply_modelview_transform (actor, &modelview);
      cogl_set_modelview_matrix (&modelview);
      cogl_set_source (outline);
      cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_LINE_LOOP,
                               0 , 4);
      cogl_pop_matrix ();
      cogl_object_unref (vbo);
    }

  cogl_flush ();
  CLUTTER_TIMER_STOP (_clutter_uprof_context, painting_timer);

  drawable = stage_glx->glxwin
           ? stage_glx->glxwin
           : stage_x11->xwin;

  /* If we might ever use _clutter_backend_glx_blit_sub_buffer then we
   * always need to keep track of the video_sync_count so that we can
   * throttle blits.
   *
   * Note: we get the count *before* we issue any glXCopySubBuffer or
   * blit_sub_buffer request in case the count would go up before
   * returning control to us.
   */
  if (backend_glx->can_blit_sub_buffer && backend_glx->get_video_sync)
    backend_glx->get_video_sync (&video_sync_count);

  /* push on the screen */
  if (use_clipped_redraw)
    {
      ClutterGeometry *clip = &stage_glx->bounding_redraw_clip;
      ClutterGeometry copy_area;
      ClutterActor *actor;

      CLUTTER_NOTE (BACKEND,
                    "_glx_blit_sub_buffer (window: 0x%lx, "
                                          "x: %d, y: %d, "
                                          "width: %d, height: %d)",
                    (unsigned long) drawable,
                    stage_glx->bounding_redraw_clip.x,
                    stage_glx->bounding_redraw_clip.y,
                    stage_glx->bounding_redraw_clip.width,
                    stage_glx->bounding_redraw_clip.height);

      /* XXX: It seems there will be a race here in that the stage
       * window may be resized before glXCopySubBufferMESA is handled
       * and so we may copy the wrong region. I can't really see how
       * we can handle this with the current state of X but at least
       * in this case a full redraw should be queued by the resize
       * anyway so it should only exhibit temporary artefacts.
       */
      actor = CLUTTER_ACTOR (stage_x11->wrapper);
      copy_area.y = clutter_actor_get_height (actor)
                  - clip->y
                  - clip->height;
      copy_area.x = clip->x;
      copy_area.width = clip->width;
      copy_area.height = clip->height;

      /* glXCopySubBufferMESA and glBlitFramebuffer are not integrated
       * with the glXSwapIntervalSGI mechanism which we usually use to
       * throttle the Clutter framerate to the vertical refresh and so
       * we have to manually wait for the vblank period...
       */

      /* Here 'is_synchronized' only means that the blit won't cause a
       * tear, ie it won't prevent multiple blits per retrace if they
       * can all be performed in the blanking period. If that's the
       * case then we still want to use the vblank sync menchanism but
       * we only need it to throttle redraws.
       */
      if (!backend_glx->blit_sub_buffer_is_synchronized)
        {
          /* XXX: note that glXCopySubBuffer, at least for Intel, is
           * synchronized with the vblank but glBlitFramebuffer may
           * not be so we use the same scheme we do when calling
           * glXSwapBuffers without the swap_control extension and
           * call glFinish () before waiting for the vblank period.
           *
           * See where we call glXSwapBuffers for more details.
           */
          glFinish ();
          wait_for_vblank (backend_glx);
        }
      else if (backend_glx->get_video_sync)
        {
          /* If we have the GLX_SGI_video_sync extension then we can
           * be a bit smarter about how we throttle blits by avoiding
           * any waits if we can see that the video sync count has
           * already progressed. */
          if (backend_glx->last_video_sync_count == video_sync_count)
            wait_for_vblank (backend_glx);
        }
      else
        wait_for_vblank (backend_glx);

      CLUTTER_TIMER_START (_clutter_uprof_context, blit_sub_buffer_timer);
      _clutter_backend_glx_blit_sub_buffer (backend_glx,
                                            drawable,
                                            copy_area.x,
                                            copy_area.y,
                                            copy_area.width,
                                            copy_area.height);
      CLUTTER_TIMER_STOP (_clutter_uprof_context, blit_sub_buffer_timer);
    }
  else
    {
      CLUTTER_NOTE (BACKEND, "glXSwapBuffers (display: %p, window: 0x%lx)",
                    backend_x11->xdpy,
                    (unsigned long) drawable);

      /* If we have GLX swap buffer events then glXSwapBuffers will return
       * immediately and we need to track that there is a swap in
       * progress... */
      if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS))
        stage_glx->pending_swaps++;

      if (backend_glx->vblank_type != CLUTTER_VBLANK_GLX_SWAP &&
          backend_glx->vblank_type != CLUTTER_VBLANK_NONE)
        {
          /* If we are going to wait for VBLANK manually, we not only
           * need to flush out pending drawing to the GPU before we
           * sleep, we need to wait for it to finish. Otherwise, we
           * may end up with the situation:
           *
           *        - We finish drawing      - GPU drawing continues
           *        - We go to sleep         - GPU drawing continues
           * VBLANK - We call glXSwapBuffers - GPU drawing continues
           *                                 - GPU drawing continues
           *                                 - Swap buffers happens
           *
           * Producing a tear. Calling glFinish() first will cause us
           * to properly wait for the next VBLANK before we swap. This
           * obviously does not happen when we use _GLX_SWAP and let
           * the driver do the right thing
           */
          glFinish ();

          wait_for_vblank (backend_glx);
        }

      CLUTTER_TIMER_START (_clutter_uprof_context, swapbuffers_timer);
      glXSwapBuffers (backend_x11->xdpy, drawable);
      CLUTTER_TIMER_STOP (_clutter_uprof_context, swapbuffers_timer);

      _cogl_swap_buffers_notify ();
    }

  backend_glx->last_video_sync_count = video_sync_count;

  /* reset the redraw clipping for the next paint... */
  stage_glx->initialized_redraw_clip = FALSE;

  stage_glx->frame_count++;
}
Example #10
0
CoglPipeline *
_st_create_shadow_pipeline_from_actor (StShadow     *shadow_spec,
                                       ClutterActor *actor)
{
  CoglPipeline *shadow_pipeline = NULL;

  if (CLUTTER_IS_TEXTURE (actor))
    {
      CoglTexture *texture;

      texture = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (actor));
      shadow_pipeline = _st_create_shadow_pipeline (shadow_spec, texture);
    }
  else
    {
      CoglTexture *buffer;
      CoglOffscreen *offscreen;
      CoglFramebuffer *fb;
      ClutterActorBox box;
      CoglColor clear_color;
      float width, height;
      CoglError *catch_error = NULL;

      clutter_actor_get_allocation_box (actor, &box);
      clutter_actor_box_get_size (&box, &width, &height);

      if (width == 0 || height == 0)
        return NULL;

      buffer = cogl_texture_new_with_size (width,
                                           height,
                                           COGL_TEXTURE_NO_SLICING,
                                           COGL_PIXEL_FORMAT_ANY);

      if (buffer == NULL)
        return NULL;

      offscreen = cogl_offscreen_new_with_texture (buffer);
      fb = COGL_FRAMEBUFFER (offscreen);

      if (!cogl_framebuffer_allocate (fb, &catch_error))
        {
          cogl_error_free (catch_error);
          cogl_object_unref (buffer);
          return NULL;
        }

      cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0);

      /* XXX: There's no way to render a ClutterActor to an offscreen
       * as it uses the implicit API. */
      G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
      cogl_push_framebuffer (fb);
      G_GNUC_END_IGNORE_DEPRECATIONS;

      cogl_framebuffer_clear (fb, COGL_BUFFER_BIT_COLOR, &clear_color);
      cogl_framebuffer_translate (fb, -box.x1, -box.y1, 0);
      cogl_framebuffer_orthographic (fb, 0, 0, width, height, 0, 1.0);

      clutter_actor_set_opacity_override (actor, 255);
      clutter_actor_paint (actor);
      clutter_actor_set_opacity_override (actor, -1);

      G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
      cogl_pop_framebuffer ();
      G_GNUC_END_IGNORE_DEPRECATIONS;

      cogl_object_unref (fb);

      shadow_pipeline = _st_create_shadow_pipeline (shadow_spec, buffer);

      cogl_object_unref (buffer);
    }

  return shadow_pipeline;
}
Example #11
0
static CoglBool
draw_rectangle (TestState *state,
                int x,
                int y,
                TestDepthState *rect_state,
                CoglBool legacy_mode)
{
  uint8_t Cr = MASK_RED (rect_state->color);
  uint8_t Cg = MASK_GREEN (rect_state->color);
  uint8_t Cb = MASK_BLUE (rect_state->color);
  uint8_t Ca = MASK_ALPHA (rect_state->color);
  CoglPipeline *pipeline;
  CoglDepthState depth_state;

  cogl_depth_state_init (&depth_state);
  cogl_depth_state_set_test_enabled (&depth_state, rect_state->test_enable);
  cogl_depth_state_set_test_function (&depth_state, rect_state->test_function);
  cogl_depth_state_set_write_enabled (&depth_state, rect_state->write_enable);
  cogl_depth_state_set_range (&depth_state,
                              rect_state->range_near,
                              rect_state->range_far);

  pipeline = cogl_pipeline_new (test_ctx);
  if (!cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL))
    {
      cogl_object_unref (pipeline);
      return FALSE;
    }

  if (!legacy_mode)
    {
      cogl_pipeline_set_color4ub (pipeline, Cr, Cg, Cb, Ca);

      cogl_framebuffer_set_depth_write_enabled (test_fb,
                                                rect_state->fb_write_enable);
      cogl_framebuffer_push_matrix (test_fb);
      cogl_framebuffer_translate (test_fb, 0, 0, rect_state->depth);
      cogl_framebuffer_draw_rectangle (test_fb,
                                       pipeline,
                                       x * QUAD_WIDTH,
                                       y * QUAD_WIDTH,
                                       x * QUAD_WIDTH + QUAD_WIDTH,
                                       y * QUAD_WIDTH + QUAD_WIDTH);
      cogl_framebuffer_pop_matrix (test_fb);
    }
  else
    {
      cogl_push_framebuffer (test_fb);
      cogl_push_matrix ();
      cogl_set_source_color4ub (Cr, Cg, Cb, Ca);
      cogl_translate (0, 0, rect_state->depth);
      cogl_rectangle (x * QUAD_WIDTH,
                      y * QUAD_WIDTH,
                      x * QUAD_WIDTH + QUAD_WIDTH,
                      y * QUAD_WIDTH + QUAD_WIDTH);
      cogl_pop_matrix ();
      cogl_pop_framebuffer ();
    }

  cogl_object_unref (pipeline);

  return TRUE;
}
Example #12
0
void
_cogl_matrix_stack_destroy_cache (CoglMatrixStackCache *cache)
{
  if (cache->stack)
    cogl_object_unref (cache->stack);
}
Example #13
0
CoglBool
_cogl_atlas_reserve_space (CoglAtlas             *atlas,
                           unsigned int           width,
                           unsigned int           height,
                           void                  *user_data)
{
  CoglAtlasGetRectanglesData data;
  CoglRectangleMap *new_map;
  CoglTexture2D *new_tex;
  unsigned int map_width = 0, map_height = 0;
  CoglBool ret;
  CoglRectangleMapEntry new_position;

  /* Check if we can fit the rectangle into the existing map */
  if (atlas->map &&
      _cogl_rectangle_map_add (atlas->map, width, height,
                               user_data,
                               &new_position))
    {
      COGL_NOTE (ATLAS, "%p: Atlas is %ix%i, has %i textures and is %i%% waste",
                 atlas,
                 _cogl_rectangle_map_get_width (atlas->map),
                 _cogl_rectangle_map_get_height (atlas->map),
                 _cogl_rectangle_map_get_n_rectangles (atlas->map),
                 /* waste as a percentage */
                 _cogl_rectangle_map_get_remaining_space (atlas->map) *
                 100 / (_cogl_rectangle_map_get_width (atlas->map) *
                        _cogl_rectangle_map_get_height (atlas->map)));

      atlas->update_position_cb (user_data,
                                 atlas->texture,
                                 &new_position);

      return TRUE;
    }

  /* If we make it here then we need to reorganize the atlas. First
     we'll notify any users of the atlas that this is going to happen
     so that for example in CoglAtlasTexture it can notify that the
     storage has changed and cause a flush */
  _cogl_atlas_notify_pre_reorganize (atlas);

  /* Get an array of all the textures currently in the atlas. */
  data.n_textures = 0;
  if (atlas->map == NULL)
    data.textures = g_malloc (sizeof (CoglAtlasRepositionData));
  else
    {
      unsigned int n_rectangles =
        _cogl_rectangle_map_get_n_rectangles (atlas->map);
      data.textures = g_malloc (sizeof (CoglAtlasRepositionData) *
                                (n_rectangles + 1));
      _cogl_rectangle_map_foreach (atlas->map,
                                   _cogl_atlas_get_rectangles_cb,
                                   &data);
    }

  /* Add the new rectangle as a dummy texture so that it can be
     positioned with the rest */
  data.textures[data.n_textures].old_position.x = 0;
  data.textures[data.n_textures].old_position.y = 0;
  data.textures[data.n_textures].old_position.width = width;
  data.textures[data.n_textures].old_position.height = height;
  data.textures[data.n_textures++].user_data = user_data;

  /* The atlasing algorithm works a lot better if the rectangles are
     added in decreasing order of size so we'll first sort the
     array */
  qsort (data.textures, data.n_textures,
         sizeof (CoglAtlasRepositionData),
         _cogl_atlas_compare_size_cb);

  /* Try to create a new atlas that can contain all of the textures */
  if (atlas->map)
    {
      map_width = _cogl_rectangle_map_get_width (atlas->map);
      map_height = _cogl_rectangle_map_get_height (atlas->map);

      /* If there is enough space in for the new rectangle in the
         existing atlas with at least 6% waste we'll start with the
         same size, otherwise we'll immediately double it */
      if ((map_width * map_height -
           _cogl_rectangle_map_get_remaining_space (atlas->map) +
           width * height) * 53 / 50 >
          map_width * map_height)
        _cogl_atlas_get_next_size (&map_width, &map_height);
    }
  else
    _cogl_atlas_get_initial_size (atlas->texture_format,
                                  &map_width, &map_height);

  new_map = _cogl_atlas_create_map (atlas->texture_format,
                                    map_width, map_height,
                                    data.n_textures, data.textures);

  /* If we can't create a map with the texture then give up */
  if (new_map == NULL)
    {
      COGL_NOTE (ATLAS, "%p: Could not fit texture in the atlas", atlas);
      ret = FALSE;
    }
  /* We need to migrate the existing textures into a new texture */
  else if ((new_tex = _cogl_atlas_create_texture
            (atlas,
             _cogl_rectangle_map_get_width (new_map),
             _cogl_rectangle_map_get_height (new_map))) == NULL)
    {
      COGL_NOTE (ATLAS, "%p: Could not create a CoglTexture2D", atlas);
      _cogl_rectangle_map_free (new_map);
      ret = FALSE;
    }
  else
    {
      int waste;

      COGL_NOTE (ATLAS,
                 "%p: Atlas %s with size %ix%i",
                 atlas,
                 atlas->map == NULL ||
                 _cogl_rectangle_map_get_width (atlas->map) !=
                 _cogl_rectangle_map_get_width (new_map) ||
                 _cogl_rectangle_map_get_height (atlas->map) !=
                 _cogl_rectangle_map_get_height (new_map) ?
                 "resized" : "reorganized",
                 _cogl_rectangle_map_get_width (new_map),
                 _cogl_rectangle_map_get_height (new_map));

      if (atlas->map)
        {
          /* Move all the textures to the right position in the new
             texture. This will also update the texture's rectangle */
          _cogl_atlas_migrate (atlas,
                               data.n_textures,
                               data.textures,
                               atlas->texture,
                               COGL_TEXTURE (new_tex),
                               user_data);
          _cogl_rectangle_map_free (atlas->map);
          cogl_object_unref (atlas->texture);
        }
      else
        /* We know there's only one texture so we can just directly
           update the rectangle from its new position */
        atlas->update_position_cb (data.textures[0].user_data,
                                   COGL_TEXTURE (new_tex),
                                   &data.textures[0].new_position);

      atlas->map = new_map;
      atlas->texture = COGL_TEXTURE (new_tex);

      waste = (_cogl_rectangle_map_get_remaining_space (atlas->map) *
               100 / (_cogl_rectangle_map_get_width (atlas->map) *
                      _cogl_rectangle_map_get_height (atlas->map)));

      COGL_NOTE (ATLAS, "%p: Atlas is %ix%i, has %i textures and is %i%% waste",
                 atlas,
                 _cogl_rectangle_map_get_width (atlas->map),
                 _cogl_rectangle_map_get_height (atlas->map),
                 _cogl_rectangle_map_get_n_rectangles (atlas->map),
                 waste);

      ret = TRUE;
    }

  g_free (data.textures);

  _cogl_atlas_notify_post_reorganize (atlas);

  return ret;
}
Example #14
0
static CoglPrimitive *
primitive_new_p2t2t2 (CoglContext *ctx,
                      CoglVerticesMode mode,
                      int n_vertices,
                      const VertexP2T2T2 *data)
{
  CoglAttributeBuffer *attribute_buffer =
    cogl_attribute_buffer_new (ctx, n_vertices * sizeof (VertexP2T2T2), data);
  int n_attributes = 7;
  CoglAttribute *attributes[n_attributes];
  CoglPrimitive *primitive;
#ifndef MESA_CONST_ATTRIB_BUG_WORKAROUND
  const float normal[3] = { 0, 0, 1 };
  const float tangent[3] = { 1, 0, 0 };
#endif
  int i;

  attributes[0] = cogl_attribute_new (attribute_buffer,
                                      "cogl_position_in",
                                      sizeof (VertexP2T2T2),
                                      offsetof (VertexP2T2T2, x),
                                      2,
                                      COGL_ATTRIBUTE_TYPE_FLOAT);

  /* coords for circle mask, for rounded corners */
  attributes[1] = cogl_attribute_new (attribute_buffer,
                                      "cogl_tex_coord0_in",
                                      sizeof (VertexP2T2T2),
                                      offsetof (VertexP2T2T2, s0),
                                      2,
                                      COGL_ATTRIBUTE_TYPE_FLOAT);
  /* coords for primary texture */
  attributes[2] = cogl_attribute_new (attribute_buffer,
                                      "cogl_tex_coord1_in",
                                      sizeof (VertexP2T2T2),
                                      offsetof (VertexP2T2T2, s1),
                                      2,
                                      COGL_ATTRIBUTE_TYPE_FLOAT);
  /* coords for alpha mask texture */
  attributes[3] = cogl_attribute_new (attribute_buffer,
                                      "cogl_tex_coord4_in",
                                      sizeof (VertexP2T2T2),
                                      offsetof (VertexP2T2T2, s1),
                                      2,
                                      COGL_ATTRIBUTE_TYPE_FLOAT);

  /* coords for normal map */
  attributes[4] = cogl_attribute_new (attribute_buffer,
                                      "cogl_tex_coord7_in",
                                      sizeof (VertexP2T2T2),
                                      offsetof (VertexP2T2T2, s1),
                                      2,
                                      COGL_ATTRIBUTE_TYPE_FLOAT);

#ifdef MESA_CONST_ATTRIB_BUG_WORKAROUND
  attributes[5] = cogl_attribute_new (attribute_buffer,
                                      "cogl_normal_in",
                                      sizeof (VertexP2T2T2),
                                      offsetof (VertexP2T2T2, Nx),
                                      3,
                                      COGL_ATTRIBUTE_TYPE_FLOAT);
  attributes[6] = cogl_attribute_new (attribute_buffer,
                                      "tangent_in",
                                      sizeof (VertexP2T2T2),
                                      offsetof (VertexP2T2T2, Tx),
                                      3,
                                      COGL_ATTRIBUTE_TYPE_FLOAT);
#else
  attributes[5] = cogl_attribute_new_const_3fv (ctx,
                                                "cogl_normal_in",
                                                normal);

  attributes[6] = cogl_attribute_new_const_3fv (ctx,
                                                "tangent_in",
                                                tangent);
#endif

  cogl_object_unref (attribute_buffer);

  primitive = cogl_primitive_new_with_attributes (mode,
                                                  n_vertices,
                                                  attributes,
                                                  n_attributes);

  for (i = 0; i < n_attributes; i++)
    cogl_object_unref (attributes[i]);

  return primitive;
}
Example #15
0
static CoglTexture *
_cogl_texture_new_from_bitmap (CoglBitmap *bitmap,
                               CoglTextureFlags flags,
                               CoglPixelFormat internal_format,
                               CoglBool can_convert_in_place,
                               CoglError **error)
{
  CoglContext *ctx = _cogl_bitmap_get_context (bitmap);
  CoglTexture *tex;
  CoglError *internal_error = NULL;

  if (!flags &&
      !COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_ATLAS))
    {
      /* First try putting the texture in the atlas */
      CoglAtlasTexture *atlas_tex =
        _cogl_atlas_texture_new_from_bitmap (bitmap,
                                             can_convert_in_place);

      _cogl_texture_set_internal_format (COGL_TEXTURE (atlas_tex),
                                         internal_format);

      if (cogl_texture_allocate (COGL_TEXTURE (atlas_tex), &internal_error))
        return COGL_TEXTURE (atlas_tex);

      cogl_error_free (internal_error);
      internal_error = NULL;
      cogl_object_unref (atlas_tex);
    }

  /* 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,
                                                            can_convert_in_place));

      _cogl_texture_set_internal_format (tex, internal_format);

      if (!cogl_texture_allocate (tex, &internal_error))
        {
          cogl_error_free (internal_error);
          internal_error = NULL;
          cogl_object_unref (tex);
          tex = NULL;
        }
    }
  else
    tex = NULL;

  if (!tex)
    {
      /* Otherwise create a sliced texture */
      int max_waste = flags & COGL_TEXTURE_NO_SLICING ? -1 : COGL_TEXTURE_MAX_WASTE;
      tex = COGL_TEXTURE (_cogl_texture_2d_sliced_new_from_bitmap (bitmap,
                                                             max_waste,
                                                             can_convert_in_place));

      _cogl_texture_set_internal_format (tex, internal_format);

      if (!cogl_texture_allocate (tex, error))
        {
          cogl_object_unref (tex);
          tex = NULL;
        }
    }

  if (tex &&
      flags & COGL_TEXTURE_NO_AUTO_MIPMAP)
    {
      cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (tex),
                                           0, 0, 1, 1,
                                           COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE,
                                           COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE,
                                           set_auto_mipmap_cb,
                                           NULL);
    }

  return tex;
}
Example #16
0
void
_cogl_gl_flush_attributes_state (CoglFramebuffer *framebuffer,
                                 CoglPipeline *pipeline,
                                 CoglFlushLayerState *layers_state,
                                 CoglDrawFlags flags,
                                 CoglAttribute **attributes,
                                 int n_attributes)
{
  CoglContext *ctx = framebuffer->context;
  int i;
  gboolean with_color_attrib = FALSE;
  gboolean unknown_color_alpha = FALSE;
  CoglPipeline *copy = NULL;

  /* Iterate the attributes to see if we have a color attribute which
   * may affect our decision to enable blending or not.
   *
   * We need to do this before flushing the pipeline. */
  for (i = 0; i < n_attributes; i++)
    switch (attributes[i]->name_state->name_id)
      {
      case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
        if ((flags & COGL_DRAW_COLOR_ATTRIBUTE_IS_OPAQUE) == 0 &&
            _cogl_attribute_get_n_components (attributes[i]) == 4)
          unknown_color_alpha = TRUE;
        with_color_attrib = TRUE;
        break;

      default:
        break;
      }

  if (G_UNLIKELY (layers_state->options.flags))
    {
      /* If we haven't already created a derived pipeline... */
      if (!copy)
        {
          copy = cogl_pipeline_copy (pipeline);
          pipeline = copy;
        }
      _cogl_pipeline_apply_overrides (pipeline, &layers_state->options);

      /* TODO:
       * overrides = cogl_pipeline_get_data (pipeline,
       *                                     last_overrides_key);
       * if (overrides)
       *   {
       *     age = cogl_pipeline_get_age (pipeline);
       *     XXX: actually we also need to check for legacy_state
       *     and blending overrides for use of glColorPointer...
       *     if (overrides->ags != age ||
       *         memcmp (&overrides->options, &options,
       *                 sizeof (options) != 0)
       *       {
       *         cogl_object_unref (overrides->weak_pipeline);
       *         g_slice_free (Overrides, overrides);
       *         overrides = NULL;
       *       }
       *   }
       * if (!overrides)
       *   {
       *     overrides = g_slice_new (Overrides);
       *     overrides->weak_pipeline =
       *       cogl_pipeline_weak_copy (pipeline);
       *     _cogl_pipeline_apply_overrides (overrides->weak_pipeline,
       *                                     &options);
       *
       *     cogl_pipeline_set_data (pipeline, last_overrides_key,
       *                             weak_overrides,
       *                             free_overrides_cb,
       *                             NULL);
       *   }
       * pipeline = overrides->weak_pipeline;
       */
    }

  _cogl_pipeline_flush_gl_state (ctx,
                                 pipeline,
                                 framebuffer,
                                 with_color_attrib,
                                 unknown_color_alpha);

  _cogl_bitmask_clear_all (&ctx->enable_builtin_attributes_tmp);
  _cogl_bitmask_clear_all (&ctx->enable_texcoord_attributes_tmp);
  _cogl_bitmask_clear_all (&ctx->enable_custom_attributes_tmp);

  /* Bind the attribute pointers. We need to do this after the
   * pipeline is flushed because when using GLSL that is the only
   * point when we can determine the attribute locations */

  for (i = 0; i < n_attributes; i++)
    {
      CoglAttribute *attribute = attributes[i];
      CoglAttributeBuffer *attribute_buffer;
      CoglBuffer *buffer;
      uint8_t *base;

      if (attribute->is_buffered)
        {
          attribute_buffer = cogl_attribute_get_buffer (attribute);
          buffer = COGL_BUFFER (attribute_buffer);

          /* Note: we don't try and catch errors with binding buffers
           * here since OOM errors at this point indicate that nothing
           * has yet been uploaded to attribute buffer which we
           * consider to be a programmer error.
           */
          base =
            _cogl_buffer_gl_bind (buffer,
                                  COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER,
                                  NULL);

          if (pipeline->progend == COGL_PIPELINE_PROGEND_GLSL)
            setup_generic_buffered_attribute (ctx, pipeline, attribute, base);
          else
            setup_legacy_buffered_attribute (ctx, pipeline, attribute, base);

          _cogl_buffer_gl_unbind (buffer);
        }
      else
        {
          if (pipeline->progend == COGL_PIPELINE_PROGEND_GLSL)
            setup_generic_const_attribute (ctx, pipeline, attribute);
          else
            setup_legacy_const_attribute (ctx, pipeline, attribute);
        }
    }

  apply_attribute_enable_updates (ctx, pipeline);

  if (copy)
    cogl_object_unref (copy);
}
Example #17
0
CoglTexture *
cogl_texture_new_with_size (unsigned int width,
			    unsigned int height,
                            CoglTextureFlags flags,
			    CoglPixelFormat internal_format)
{
  CoglTexture *tex;
  CoglError *skip_error = NULL;

  _COGL_GET_CONTEXT (ctx, NULL);

  if ((_cogl_util_is_pot (width) && _cogl_util_is_pot (height)) ||
      (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) &&
       cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP)))
    {
      /* First try creating a fast-path non-sliced texture */
      tex = COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx, width, height));

      _cogl_texture_set_internal_format (tex, internal_format);

      if (!cogl_texture_allocate (tex, &skip_error))
        {
          cogl_error_free (skip_error);
          cogl_object_unref (tex);
          tex = NULL;
        }
    }
  else
    tex = NULL;

  if (!tex)
    {
      /* If it fails resort to sliced textures */
      int max_waste = flags & COGL_TEXTURE_NO_SLICING ? -1 : COGL_TEXTURE_MAX_WASTE;
      tex = COGL_TEXTURE (cogl_texture_2d_sliced_new_with_size (ctx,
                                                                width,
                                                                height,
                                                                max_waste));

      _cogl_texture_set_internal_format (tex, internal_format);
    }

  /* NB: This api existed before Cogl introduced lazy allocation of
   * textures and so we maintain its original synchronous allocation
   * semantics and return NULL if allocation fails... */
  if (!cogl_texture_allocate (tex, &skip_error))
    {
      cogl_error_free (skip_error);
      cogl_object_unref (tex);
      return NULL;
    }

  if (tex &&
      flags & COGL_TEXTURE_NO_AUTO_MIPMAP)
    {
      cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (tex),
                                           0, 0, 1, 1,
                                           COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE,
                                           COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE,
                                           set_auto_mipmap_cb,
                                           NULL);
    }

  return tex;
}
Example #18
0
static void
do_test (CoglBool check_orientation)
{
  int fb_width = cogl_framebuffer_get_width (test_fb);
  int fb_height = cogl_framebuffer_get_height (test_fb);
  CoglPrimitive *prim;
  CoglError *error = NULL;
  CoglTexture2D *tex_2d;
  CoglPipeline *pipeline, *solid_pipeline;
  CoglBool res;
  int tex_height;

  cogl_framebuffer_orthographic (test_fb,
                                 0, 0, /* x_1, y_1 */
                                 fb_width, /* x_2 */
                                 fb_height /* y_2 */,
                                 -1, 100 /* near/far */);

  cogl_framebuffer_clear4f (test_fb,
                            COGL_BUFFER_BIT_COLOR,
                            1.0f, 1.0f, 1.0f, 1.0f);

  /* If we're not checking the orientation of the point sprite then
   * we'll set the height of the texture to 1 so that the vertical
   * orientation does not matter */
  if (check_orientation)
    tex_height = 2;
  else
    tex_height = 1;

  tex_2d = cogl_texture_2d_new_from_data (test_ctx,
                                          2, tex_height, /* width/height */
                                          COGL_PIXEL_FORMAT_RGB_888,
                                          COGL_PIXEL_FORMAT_ANY,
                                          6, /* row stride */
                                          tex_data,
                                          &error);
  g_assert (tex_2d != NULL);
  g_assert (error == NULL);

  pipeline = cogl_pipeline_new (test_ctx);
  cogl_pipeline_set_layer_texture (pipeline, 0, COGL_TEXTURE (tex_2d));

  res = cogl_pipeline_set_layer_point_sprite_coords_enabled (pipeline,
                                                             /* layer_index */
                                                             0,
                                                             /* enable */
                                                             TRUE,
                                                             &error);
  g_assert (res == TRUE);
  g_assert (error == NULL);

  cogl_pipeline_set_layer_filters (pipeline,
                                   0, /* layer_index */
                                   COGL_PIPELINE_FILTER_NEAREST,
                                   COGL_PIPELINE_FILTER_NEAREST);
  cogl_pipeline_set_point_size (pipeline, POINT_SIZE);

  prim = cogl_primitive_new_p2t2 (test_ctx,
                                  COGL_VERTICES_MODE_POINTS,
                                  1, /* n_vertices */
                                  &point);

  cogl_primitive_draw (prim, test_fb, pipeline);

  /* Render the primitive again without point sprites to make sure
     disabling it works */
  solid_pipeline = cogl_pipeline_copy (pipeline);
  cogl_pipeline_set_layer_point_sprite_coords_enabled (solid_pipeline,
                                                       /* layer_index */
                                                       0,
                                                       /* enable */
                                                       FALSE,
                                                       &error);
  cogl_framebuffer_push_matrix (test_fb);
  cogl_framebuffer_translate (test_fb,
                              POINT_SIZE * 2, /* x */
                              0.0f, /* y */
                              0.0f /* z */);
  cogl_primitive_draw (prim, test_fb, solid_pipeline);
  cogl_framebuffer_pop_matrix (test_fb);

  cogl_object_unref (prim);
  cogl_object_unref (solid_pipeline);
  cogl_object_unref (pipeline);
  cogl_object_unref (tex_2d);

  test_utils_check_pixel (test_fb,
                          POINT_SIZE - POINT_SIZE / 4,
                          POINT_SIZE - POINT_SIZE / 4,
                          0x0000ffff);
  test_utils_check_pixel (test_fb,
                          POINT_SIZE + POINT_SIZE / 4,
                          POINT_SIZE - POINT_SIZE / 4,
                          0x00ff00ff);
  test_utils_check_pixel (test_fb,
                          POINT_SIZE - POINT_SIZE / 4,
                          POINT_SIZE + POINT_SIZE / 4,
                          check_orientation ?
                          0x00ffffff :
                          0x0000ffff);
  test_utils_check_pixel (test_fb,
                          POINT_SIZE + POINT_SIZE / 4,
                          POINT_SIZE + POINT_SIZE / 4,
                          check_orientation ?
                          0xff0000ff :
                          0x00ff00ff);

  /* When rendering without the point sprites all of the texture
     coordinates should be 0,0 so it should get the top-left texel
     which is blue */
  test_utils_check_region (test_fb,
                           POINT_SIZE * 3 - POINT_SIZE / 2 + 1,
                           POINT_SIZE - POINT_SIZE / 2 + 1,
                           POINT_SIZE - 2, POINT_SIZE - 2,
                           0x0000ffff);

  if (cogl_test_verbose ())
    g_print ("OK\n");
}
Example #19
0
static void
test_short_verts (TestState *state, int offset_x, int offset_y)
{
  CoglAttribute *attributes[2];
  CoglAttributeBuffer *buffer;
  CoglPipeline *pipeline, *pipeline2;
  CoglSnippet *snippet;
  CoglPrimitive *primitive;

  static const ShortVert short_verts[] =
    {
      { -10, -10, /**/ 0xffff, 0, 0, 0xffff },
      { -1, -10,  /**/ 0xffff, 0, 0, 0xffff },
      { -5, -1, /**/ 0xffff, 0, 0, 0xffff }
    };


  pipeline = cogl_pipeline_copy (state->pipeline);

  cogl_pipeline_set_color4ub (pipeline, 255, 0, 0, 255);

  buffer = cogl_attribute_buffer_new (test_ctx,
                                      sizeof (short_verts), short_verts);
  attributes[0] = cogl_attribute_new (buffer,
                                      "cogl_position_in",
                                      sizeof (ShortVert),
                                      G_STRUCT_OFFSET (ShortVert, x),
                                      2, /* n_components */
                                      COGL_ATTRIBUTE_TYPE_SHORT);
  attributes[1] = cogl_attribute_new (buffer,
                                      "color",
                                      sizeof (ShortVert),
                                      G_STRUCT_OFFSET (ShortVert, r),
                                      4, /* n_components */
                                      COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT);
  cogl_attribute_set_normalized (attributes[1], TRUE);

  cogl_framebuffer_push_matrix (test_fb);
  cogl_framebuffer_translate (test_fb,
                              offset_x + 10.0f,
                              offset_y + 10.0f,
                              0.0f);

  primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES,
                                                  3, /* n_vertices */
                                                  attributes,
                                                  2); /* n_attributes */
  cogl_primitive_draw (primitive, test_fb, pipeline);
  cogl_object_unref (primitive);

  cogl_framebuffer_pop_matrix (test_fb);

  cogl_object_unref (attributes[0]);

  /* Test again treating the attribute as unsigned */
  attributes[0] = cogl_attribute_new (buffer,
                                      "cogl_position_in",
                                      sizeof (ShortVert),
                                      G_STRUCT_OFFSET (ShortVert, x),
                                      2, /* n_components */
                                      COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT);

  /* XXX: this is a hack to force the pipeline to use the glsl backend
   * because we know it's not possible to test short vertex position
   * components with the legacy GL backend since which might otherwise
   * be used internally... */
  pipeline2 = cogl_pipeline_new (test_ctx);
  snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX,
                              "attribute vec4 color;",
                              "cogl_color_out = vec4 (0.0, 1.0, 0.0, 1.0);");
  cogl_pipeline_add_snippet (pipeline2, snippet);

  cogl_framebuffer_push_matrix (test_fb);
  cogl_framebuffer_translate (test_fb,
                              offset_x + 10.0f - 65525.0f,
                              offset_y - 65525,
                              0.0f);

  primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES,
                                                  3, /* n_vertices */
                                                  attributes,
                                                  1); /* n_attributes */
  cogl_primitive_draw (primitive, test_fb, pipeline2);
  cogl_object_unref (primitive);

  cogl_framebuffer_pop_matrix (test_fb);

  cogl_object_unref (attributes[0]);

  cogl_object_unref (pipeline2);
  cogl_object_unref (pipeline);
  cogl_object_unref (buffer);

  test_utils_check_pixel (test_fb, offset_x + 5, offset_y + 5, 0xff0000ff);
  test_utils_check_pixel (test_fb, offset_x + 15, offset_y + 5, 0x00ff00ff);
}
Example #20
0
static void
_cogl_pipeline_snippet_free (CoglPipelineSnippet *pipeline_snippet)
{
  cogl_object_unref (pipeline_snippet->snippet);
  g_slice_free (CoglPipelineSnippet, pipeline_snippet);
}
Example #21
0
void
test_texture_no_allocate (void)
{
  uint8_t *tex_data;
  CoglTexture *texture;
  CoglTexture2D *texture_2d;
  CoglError *error = NULL;

  tex_data = g_malloc (BIG_TEX_WIDTH * BIG_TEX_HEIGHT * 4);

  /* NB: if we make the atlas and sliced texture APIs public then this
   * could changed to explicitly use that instead of the magic texture
   * API */

  /* Try to create an atlas texture that is too big so it will
   * internally be freed without allocating */
  texture =
    cogl_atlas_texture_new_from_data (test_ctx,
                                      BIG_TEX_WIDTH,
                                      BIG_TEX_HEIGHT,
                                      /* format */
                                      COGL_PIXEL_FORMAT_RGBA_8888_PRE,
                                      /* rowstride */
                                      BIG_TEX_WIDTH * 4,
                                      tex_data,
                                      &error);

  g_free (tex_data);

  /* It's ok if this causes an error, we just don't want it to
   * crash */

  if (texture == NULL)
    cogl_error_free (error);
  else
    cogl_object_unref (texture);

  /* Try to create a sliced texture without allocating it */
  texture =
    cogl_texture_2d_sliced_new_with_size (test_ctx,
                                          BIG_TEX_WIDTH,
                                          BIG_TEX_HEIGHT,
                                          COGL_TEXTURE_MAX_WASTE);
  cogl_object_unref (texture);

  /* 2D texture */
  texture_2d = cogl_texture_2d_new_with_size (test_ctx,
                                              64, 64);
  cogl_object_unref (texture_2d);

  /* 3D texture */
  if (cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_3D))
    {
      CoglTexture3D *texture_3d =
        cogl_texture_3d_new_with_size (test_ctx,
                                       64, 64, 64);
      cogl_object_unref (texture_3d);
    }

  /* Rectangle texture */
  if (cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_RECTANGLE))
    {
      CoglTextureRectangle *texture_rect =
        cogl_texture_rectangle_new_with_size (test_ctx,
                                              64, 64);
      cogl_object_unref (texture_rect);
    }
}
Example #22
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;
}
static gboolean
clutter_backend_real_create_context (ClutterBackend  *backend,
                                     GError         **error)
{
  ClutterBackendClass *klass;
  CoglSwapChain *swap_chain;
  GError *internal_error;

  if (backend->cogl_context != NULL)
    return TRUE;

  klass = CLUTTER_BACKEND_GET_CLASS (backend);

  swap_chain = NULL;
  internal_error = NULL;

  CLUTTER_NOTE (BACKEND, "Creating Cogl renderer");
  if (klass->get_renderer != NULL)
    backend->cogl_renderer = klass->get_renderer (backend, &internal_error);
  else
    backend->cogl_renderer = cogl_renderer_new ();

  if (backend->cogl_renderer == NULL)
    goto error;

#ifdef HAVE_CLUTTER_WAYLAND_COMPOSITOR
  /* If the application is trying to act as a Wayland compositor then
     it needs to have an EGL-based renderer backend */
  if (_wayland_compositor_display)
    cogl_renderer_add_constraint (backend->cogl_renderer,
                                  COGL_RENDERER_CONSTRAINT_USES_EGL);
#endif

  CLUTTER_NOTE (BACKEND, "Connecting the renderer");
  if (!cogl_renderer_connect (backend->cogl_renderer, &internal_error))
    goto error;

  CLUTTER_NOTE (BACKEND, "Creating Cogl swap chain");
  swap_chain = cogl_swap_chain_new ();

  CLUTTER_NOTE (BACKEND, "Creating Cogl display");
  if (klass->get_display != NULL)
    {
      backend->cogl_display = klass->get_display (backend,
                                                  backend->cogl_renderer,
                                                  swap_chain,
                                                  &internal_error);
    }
  else
    {
      CoglOnscreenTemplate *tmpl;
      gboolean res;

      tmpl = cogl_onscreen_template_new (swap_chain);

      /* XXX: I have some doubts that this is a good design.
       *
       * Conceptually should we be able to check an onscreen_template
       * without more details about the CoglDisplay configuration?
       */
      res = cogl_renderer_check_onscreen_template (backend->cogl_renderer,
                                                   tmpl,
                                                   &internal_error);

      if (!res)
        goto error;

      backend->cogl_display = cogl_display_new (backend->cogl_renderer, tmpl);

      /* the display owns the template */
      cogl_object_unref (tmpl);
    }

  if (backend->cogl_display == NULL)
    goto error;

#ifdef HAVE_CLUTTER_WAYLAND_COMPOSITOR
  cogl_wayland_display_set_compositor_display (backend->cogl_display,
                                               _wayland_compositor_display);
#endif

  CLUTTER_NOTE (BACKEND, "Setting up the display");
  if (!cogl_display_setup (backend->cogl_display, &internal_error))
    goto error;

  CLUTTER_NOTE (BACKEND, "Creating the Cogl context");
  backend->cogl_context = cogl_context_new (backend->cogl_display, &internal_error);
  if (backend->cogl_context == NULL)
    goto error;

  backend->cogl_source = cogl_glib_source_new (backend->cogl_context,
                                               G_PRIORITY_DEFAULT);
  g_source_attach (backend->cogl_source, NULL);

  /* the display owns the renderer and the swap chain */
  cogl_object_unref (backend->cogl_renderer);
  cogl_object_unref (swap_chain);

  return TRUE;

error:
  if (backend->cogl_display != NULL)
    {
      cogl_object_unref (backend->cogl_display);
      backend->cogl_display = NULL;
    }

  if (backend->cogl_renderer != NULL)
    {
      cogl_object_unref (backend->cogl_renderer);
      backend->cogl_renderer = NULL;
    }

  if (swap_chain != NULL)
    cogl_object_unref (swap_chain);

  if (internal_error != NULL)
    g_propagate_error (error, internal_error);
  else
    g_set_error_literal (error, CLUTTER_INIT_ERROR,
                         CLUTTER_INIT_ERROR_BACKEND,
                         _("Unable to initialize the Clutter backend"));

  return FALSE;
}
Example #24
0
static CoglBool
_cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
                                             CoglTexture *texture,
                                             CoglBool is_foreign,
                                             int src_x,
                                             int src_y,
                                             int dst_x,
                                             int dst_y,
                                             int width,
                                             int height,
                                             int level,
                                             CoglBitmap *source_bmp,
				             GLuint source_gl_format,
				             GLuint source_gl_type,
                                             CoglError **error)
{
  GLenum gl_target;
  GLuint gl_handle;
  uint8_t *data;
  CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
  int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format);
  CoglBitmap *slice_bmp;
  int rowstride;
  CoglBool status = TRUE;
  CoglError *internal_error = NULL;
  int level_width;
  int level_height;

  cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target);

  /* If we have the GL_EXT_unpack_subimage extension then we can
     upload from subregions directly. Otherwise we may need to copy
     the bitmap */
  if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_UNPACK_SUBIMAGE) &&
      (src_x != 0 || src_y != 0 ||
       width != cogl_bitmap_get_width (source_bmp) ||
       height != cogl_bitmap_get_height (source_bmp)))
    {
      slice_bmp =
        _cogl_bitmap_new_with_malloc_buffer (ctx,
                                             width, height,
                                             source_format,
                                             error);
      if (!slice_bmp)
        return FALSE;

      if (!_cogl_bitmap_copy_subregion (source_bmp,
                                        slice_bmp,
                                        src_x, src_y,
                                        0, 0, /* dst_x/y */
                                        width, height,
                                        error))
        {
          cogl_object_unref (slice_bmp);
          return FALSE;
        }

      src_x = src_y = 0;
    }
  else
    {
      slice_bmp = prepare_bitmap_alignment_for_upload (ctx, source_bmp, error);
      if (!slice_bmp)
        return FALSE;
    }

  rowstride = cogl_bitmap_get_rowstride (slice_bmp);

  /* Setup gl alignment to match rowstride and top-left corner */
  prep_gl_for_pixels_upload_full (ctx, rowstride, src_x, src_y, bpp);

  data = _cogl_bitmap_gl_bind (slice_bmp, COGL_BUFFER_ACCESS_READ, 0, &internal_error);

  /* NB: _cogl_bitmap_gl_bind() may return NULL when successfull so we
   * have to explicitly check the cogl error pointer to catch
   * problems... */
  if (internal_error)
    {
      _cogl_propagate_error (error, internal_error);
      cogl_object_unref (slice_bmp);
      return FALSE;
    }

  _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);

  /* Clear any GL errors */
  _cogl_gl_util_clear_gl_errors (ctx);

  _cogl_texture_get_level_size (texture,
                                level,
                                &level_width,
                                &level_height,
                                NULL);

  if (level_width == width && level_height == height)
    {
      /* GL gets upset if you use glTexSubImage2D to define the
       * contents of a mipmap level so we make sure to use
       * glTexImage2D if we are uploading a full mipmap level.
       */
      ctx->glTexImage2D (gl_target,
                         level,
                         _cogl_texture_gl_get_format (texture),
                         width,
                         height,
                         0,
                         source_gl_format,
                         source_gl_type,
                         data);
    }
  else
    {
      /* GL gets upset if you use glTexSubImage2D to initialize the
       * contents of a mipmap level so if this is the first time
       * we've seen a request to upload to this level we call
       * glTexImage2D first to assert that the storage for this
       * level exists.
       */
      if (texture->max_level < level)
        {
          ctx->glTexImage2D (gl_target,
                             level,
                             _cogl_texture_gl_get_format (texture),
                             level_width,
                             level_height,
                             0,
                             source_gl_format,
                             source_gl_type,
                             NULL);
        }

      ctx->glTexSubImage2D (gl_target,
                            level,
                            dst_x, dst_y,
                            width, height,
                            source_gl_format,
                            source_gl_type,
                            data);
    }

  if (_cogl_gl_util_catch_out_of_memory (ctx, error))
    status = FALSE;

  _cogl_bitmap_gl_unbind (slice_bmp);

  cogl_object_unref (slice_bmp);

  return status;
}
Example #25
0
void
_cogl_texture_driver_upload_subregion_to_gl (GLenum       gl_target,
        GLuint       gl_handle,
        gboolean     is_foreign,
        int          src_x,
        int          src_y,
        int          dst_x,
        int          dst_y,
        int          width,
        int          height,
        CoglBitmap  *source_bmp,
        GLuint       source_gl_format,
        GLuint       source_gl_type)
{
    guint8 *data;
    CoglPixelFormat source_format = _cogl_bitmap_get_format (source_bmp);
    int bpp = _cogl_get_format_bpp (source_format);
    CoglBitmap *slice_bmp;
    int rowstride;

    /* If we are copying a sub region of the source bitmap then we need
       to copy it because GLES does not support GL_UNPACK_ROW_LENGTH */
    if (src_x != 0 || src_y != 0 ||
            width != _cogl_bitmap_get_width (source_bmp) ||
            height != _cogl_bitmap_get_height (source_bmp))
    {
        rowstride = bpp * width;
        rowstride = (rowstride + 3) & ~3;
        slice_bmp =
            _cogl_bitmap_new_from_data (g_malloc (height * rowstride),
                                        source_format,
                                        width, height,
                                        rowstride,
                                        (CoglBitmapDestroyNotify) g_free,
                                        NULL);
        _cogl_bitmap_copy_subregion (source_bmp,
                                     slice_bmp,
                                     src_x, src_y,
                                     0, 0, /* dst_x/y */
                                     width, height);
    }
    else
    {
        slice_bmp = prepare_bitmap_alignment_for_upload (source_bmp);
        rowstride = _cogl_bitmap_get_rowstride (slice_bmp);
    }

    /* Setup gl alignment to match rowstride and top-left corner */
    _cogl_texture_driver_prep_gl_for_pixels_upload (rowstride, bpp);

    data = _cogl_bitmap_bind (slice_bmp, COGL_BUFFER_ACCESS_READ, 0);

    _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);

    GE( glTexSubImage2D (gl_target, 0,
                         dst_x, dst_y,
                         width, height,
                         source_gl_format,
                         source_gl_type,
                         data) );

    _cogl_bitmap_unbind (slice_bmp);

    cogl_object_unref (slice_bmp);
}
Example #26
0
static CoglBool
_cogl_texture_driver_upload_to_gl (CoglContext *ctx,
                                   GLenum gl_target,
                                   GLuint gl_handle,
                                   CoglBool is_foreign,
                                   CoglBitmap *source_bmp,
                                   GLint internal_gl_format,
                                   GLuint source_gl_format,
                                   GLuint source_gl_type,
                                   CoglError **error)
{
  CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
  int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format);
  int rowstride;
  int bmp_width = cogl_bitmap_get_width (source_bmp);
  int bmp_height = cogl_bitmap_get_height (source_bmp);
  CoglBitmap *bmp;
  uint8_t *data;
  CoglError *internal_error = NULL;
  CoglBool status = TRUE;

  bmp = prepare_bitmap_alignment_for_upload (ctx, source_bmp, error);
  if (!bmp)
    return FALSE;

  rowstride = cogl_bitmap_get_rowstride (bmp);

  /* Setup gl alignment to match rowstride and top-left corner */
  _cogl_texture_driver_prep_gl_for_pixels_upload (ctx, rowstride, bpp);

  _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);

  data = _cogl_bitmap_gl_bind (bmp,
                               COGL_BUFFER_ACCESS_READ,
                               0, /* hints */
                               &internal_error);

  /* NB: _cogl_bitmap_gl_bind() may return NULL when successful so we
   * have to explicitly check the cogl error pointer to catch
   * problems... */
  if (internal_error)
    {
      cogl_object_unref (bmp);
      _cogl_propagate_error (error, internal_error);
      return FALSE;
    }

  /* Clear any GL errors */
  _cogl_gl_util_clear_gl_errors (ctx);

  ctx->glTexImage2D (gl_target, 0,
                     internal_gl_format,
                     bmp_width, bmp_height,
                     0,
                     source_gl_format,
                     source_gl_type,
                     data);

  if (_cogl_gl_util_catch_out_of_memory (ctx, error))
    status = FALSE;

  _cogl_bitmap_gl_unbind (bmp);

  cogl_object_unref (bmp);

  return status;
}
Example #27
0
static CoglHandle
data_to_cogl_handle (const guchar *data,
                     gboolean      has_alpha,
                     int           width,
                     int           height,
                     int           rowstride,
                     gboolean      add_padding)
{
  CoglHandle texture, offscreen;
  CoglColor clear_color;
  guint size;
  GError *error;

  size = MAX (width, height);

  if (!add_padding || width == height)
    return cogl_texture_new_from_data (width,
                                       height,
                                       COGL_TEXTURE_NONE,
                                       has_alpha ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888,
                                       COGL_PIXEL_FORMAT_ANY,
                                       rowstride,
                                       data);

  texture = cogl_texture_new_with_size (size, size,
                                        COGL_TEXTURE_NO_SLICING,
                                        COGL_PIXEL_FORMAT_ANY);

  offscreen = cogl_offscreen_new_with_texture (texture);

  error = NULL;
  if (!cogl_framebuffer_allocate (offscreen, &error))
    {
      g_warning ("Failed to allocate FBO (sized %d): %s", size, error->message);

      cogl_object_unref (texture);
      cogl_object_unref (offscreen);
      g_clear_error (&error);

      return cogl_texture_new_from_data (width,
                                         height,
                                         COGL_TEXTURE_NONE,
                                         has_alpha ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888,
                                         COGL_PIXEL_FORMAT_ANY,
                                         rowstride,
                                         data);
  }

  cogl_color_set_from_4ub (&clear_color, 0, 0, 0, 0);
  cogl_push_framebuffer (offscreen);
  cogl_clear (&clear_color, COGL_BUFFER_BIT_COLOR);
  cogl_pop_framebuffer ();
  cogl_handle_unref (offscreen);

  cogl_texture_set_region (texture,
                           0, 0,
                           (size - width) / 2, (size - height) / 2,
                           width, height,
                           width, height,
                           has_alpha ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888,
                           rowstride,
                           data);
  return texture;
}
Example #28
0
static CoglBool
_cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx,
                                      GLenum gl_target,
                                      GLuint gl_handle,
                                      CoglBool is_foreign,
                                      GLint height,
                                      GLint depth,
                                      CoglBitmap *source_bmp,
                                      GLint internal_gl_format,
                                      GLuint source_gl_format,
                                      GLuint source_gl_type,
                                      CoglError **error)
{
  CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
  int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format);
  int rowstride = cogl_bitmap_get_rowstride (source_bmp);
  int bmp_width = cogl_bitmap_get_width (source_bmp);
  int bmp_height = cogl_bitmap_get_height (source_bmp);
  uint8_t *data;

  _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);

  /* If the rowstride or image height can't be specified with just
     GL_ALIGNMENT alone then we need to copy the bitmap because there
     is no GL_ROW_LENGTH */
  if (rowstride / bpp != bmp_width ||
      height != bmp_height / depth)
    {
      CoglBitmap *bmp;
      int image_height = bmp_height / depth;
      CoglPixelFormat source_bmp_format = cogl_bitmap_get_format (source_bmp);
      int i;

      _cogl_texture_driver_prep_gl_for_pixels_upload (ctx, bmp_width * bpp, bpp);

      /* Initialize the texture with empty data and then upload each
         image with a sub-region update */

      /* Clear any GL errors */
      _cogl_gl_util_clear_gl_errors (ctx);

      ctx->glTexImage3D (gl_target,
                         0, /* level */
                         internal_gl_format,
                         bmp_width,
                         height,
                         depth,
                         0,
                         source_gl_format,
                         source_gl_type,
                         NULL);

      if (_cogl_gl_util_catch_out_of_memory (ctx, error))
        return FALSE;

      bmp = _cogl_bitmap_new_with_malloc_buffer (ctx,
                                                 bmp_width,
                                                 height,
                                                 source_bmp_format,
                                                 error);
      if (!bmp)
        return FALSE;

      for (i = 0; i < depth; i++)
        {
          if (!_cogl_bitmap_copy_subregion (source_bmp,
                                            bmp,
                                            0, image_height * i,
                                            0, 0,
                                            bmp_width,
                                            height,
                                            error))
            {
              cogl_object_unref (bmp);
              return FALSE;
            }

          data = _cogl_bitmap_gl_bind (bmp,
                                       COGL_BUFFER_ACCESS_READ, 0, error);
          if (!data)
            {
              cogl_object_unref (bmp);
              return FALSE;
            }

          /* Clear any GL errors */
          _cogl_gl_util_clear_gl_errors (ctx);

          ctx->glTexSubImage3D (gl_target,
                                0, /* level */
                                0, /* xoffset */
                                0, /* yoffset */
                                i, /* zoffset */
                                bmp_width, /* width */
                                height, /* height */
                                1, /* depth */
                                source_gl_format,
                                source_gl_type,
                                data);

          if (_cogl_gl_util_catch_out_of_memory (ctx, error))
            {
              cogl_object_unref (bmp);
              _cogl_bitmap_gl_unbind (bmp);
              return FALSE;
            }

          _cogl_bitmap_gl_unbind (bmp);
        }

      cogl_object_unref (bmp);
    }
  else
    {
      data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0, error);
      if (!data)
        return FALSE;

      _cogl_texture_driver_prep_gl_for_pixels_upload (ctx, rowstride, bpp);

      /* Clear any GL errors */
      _cogl_gl_util_clear_gl_errors (ctx);

      ctx->glTexImage3D (gl_target,
                         0, /* level */
                         internal_gl_format,
                         bmp_width,
                         height,
                         depth,
                         0,
                         source_gl_format,
                         source_gl_type,
                         data);

      if (_cogl_gl_util_catch_out_of_memory (ctx, error))
        {
          _cogl_bitmap_gl_unbind (source_bmp);
          return FALSE;
        }

      _cogl_bitmap_gl_unbind (source_bmp);
    }

  return TRUE;
}
Example #29
0
static void
_cogl_context_free (CoglContext *context)
{
  const CoglWinsysVtable *winsys = _cogl_context_get_winsys (context);

  winsys->context_deinit (context);

  _cogl_free_framebuffer_stack (context->framebuffer_stack);

  if (context->default_gl_texture_2d_tex)
    cogl_object_unref (context->default_gl_texture_2d_tex);
  if (context->default_gl_texture_3d_tex)
    cogl_object_unref (context->default_gl_texture_3d_tex);
  if (context->default_gl_texture_rect_tex)
    cogl_object_unref (context->default_gl_texture_rect_tex);

  if (context->opaque_color_pipeline)
    cogl_object_unref (context->opaque_color_pipeline);
  if (context->blended_color_pipeline)
    cogl_object_unref (context->blended_color_pipeline);
  if (context->texture_pipeline)
    cogl_object_unref (context->texture_pipeline);

  if (context->blit_texture_pipeline)
    cogl_object_unref (context->blit_texture_pipeline);

  g_warn_if_fail (context->gles2_context_stack.length == 0);

  if (context->journal_flush_attributes_array)
    g_array_free (context->journal_flush_attributes_array, TRUE);
  if (context->journal_clip_bounds)
    g_array_free (context->journal_clip_bounds, TRUE);

  if (context->polygon_vertices)
    g_array_free (context->polygon_vertices, TRUE);

  if (context->quad_buffer_indices_byte)
    cogl_object_unref (context->quad_buffer_indices_byte);
  if (context->quad_buffer_indices)
    cogl_object_unref (context->quad_buffer_indices);

  if (context->rectangle_byte_indices)
    cogl_object_unref (context->rectangle_byte_indices);
  if (context->rectangle_short_indices)
    cogl_object_unref (context->rectangle_short_indices);

  if (context->default_pipeline)
    cogl_object_unref (context->default_pipeline);

  if (context->dummy_layer_dependant)
    cogl_object_unref (context->dummy_layer_dependant);
  if (context->default_layer_n)
    cogl_object_unref (context->default_layer_n);
  if (context->default_layer_0)
    cogl_object_unref (context->default_layer_0);

  if (context->current_clip_stack_valid)
    _cogl_clip_stack_unref (context->current_clip_stack);

  g_slist_free (context->atlases);
  g_hook_list_clear (&context->atlas_reorganize_callbacks);

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

  g_slist_free (context->texture_types);
  g_slist_free (context->buffer_types);

  if (_context->current_modelview_entry)
    _cogl_matrix_entry_unref (_context->current_modelview_entry);
  if (_context->current_projection_entry)
    _cogl_matrix_entry_unref (_context->current_projection_entry);
  _cogl_matrix_entry_cache_destroy (&context->builtin_flushed_projection);
  _cogl_matrix_entry_cache_destroy (&context->builtin_flushed_modelview);

  cogl_pipeline_cache_free (context->pipeline_cache);

  _cogl_sampler_cache_free (context->sampler_cache);

  _cogl_destroy_texture_units ();

  g_ptr_array_free (context->uniform_names, TRUE);
  g_hash_table_destroy (context->uniform_name_hash);

  g_hash_table_destroy (context->attribute_name_states_hash);
  g_array_free (context->attribute_name_index_map, TRUE);

  g_byte_array_free (context->buffer_map_fallback_array, TRUE);

  cogl_object_unref (context->display);

  g_free (context);
}
Example #30
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;
}