Esempio n. 1
0
void
_cogl_buffer_unmap_for_fill_or_fallback (CoglBuffer *buffer)
{
  CoglContext *ctx = buffer->context;

  _COGL_RETURN_IF_FAIL (ctx->buffer_map_fallback_in_use);

  ctx->buffer_map_fallback_in_use = FALSE;

  if ((buffer->flags & COGL_BUFFER_FLAG_MAPPED_FALLBACK))
    {
      /* Note: don't try to catch OOM errors here since the use cases
       * we currently have for this api (the journal and path stroke
       * tesselator) don't have anything particularly sensible they
       * can do in response to a failure anyway so it seems better to
       * simply abort instead.
       *
       * If we find this is a problem for real world applications
       * then in the path tesselation case we could potentially add an
       * explicit cogl_path_tesselate_stroke() api that can throw an
       * error for the app to cache. For the journal we could
       * potentially flush the journal in smaller batches so we use
       * smaller buffers, though that would probably not help for
       * deferred renderers.
       */
      cogl_buffer_set_data (buffer,
                            ctx->buffer_map_fallback_offset,
                            ctx->buffer_map_fallback_array->data,
                            ctx->buffer_map_fallback_array->len,
                            NULL);
      buffer->flags &= ~COGL_BUFFER_FLAG_MAPPED_FALLBACK;
    }
  else
    cogl_buffer_unmap (buffer);
}
Esempio n. 2
0
CoglAttributeBuffer *
cogl_attribute_buffer_new (CoglContext *context,
                           size_t bytes,
                           const void *data)
{
  CoglAttributeBuffer *array = g_slice_new (CoglAttributeBuffer);
  CoglBool use_malloc;

  if (!(context->private_feature_flags & COGL_PRIVATE_FEATURE_VBOS))
    use_malloc = TRUE;
  else
    use_malloc = FALSE;

  /* parent's constructor */
  _cogl_buffer_initialize (COGL_BUFFER (array),
                           context,
                           bytes,
                           use_malloc,
                           COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER,
                           COGL_BUFFER_USAGE_HINT_ATTRIBUTE_BUFFER,
                           COGL_BUFFER_UPDATE_HINT_STATIC);

  _cogl_attribute_buffer_object_new (array);

  if (data)
    cogl_buffer_set_data (COGL_BUFFER (array),
                          0,
                          data,
                          bytes);
  return array;
}
Esempio n. 3
0
CoglVertexArray *
cogl_vertex_array_new (gsize bytes, const void *data)
{
    CoglVertexArray *array = g_slice_new (CoglVertexArray);
    gboolean use_malloc;

    if (!cogl_features_available (COGL_FEATURE_VBOS))
        use_malloc = TRUE;
    else
        use_malloc = FALSE;

    /* parent's constructor */
    _cogl_buffer_initialize (COGL_BUFFER (array),
                             bytes,
                             use_malloc,
                             COGL_BUFFER_BIND_TARGET_VERTEX_ARRAY,
                             COGL_BUFFER_USAGE_HINT_VERTEX_ARRAY,
                             COGL_BUFFER_UPDATE_HINT_STATIC);

    _cogl_vertex_array_object_new (array);

    if (data)
        cogl_buffer_set_data (COGL_BUFFER (array),
                              0,
                              data,
                              bytes);
    return array;
}
Esempio n. 4
0
CoglIndices *
cogl_indices_new (CoglContext *context,
                  CoglIndicesType type,
                  const void *indices_data,
                  int n_indices)
{
  size_t buffer_bytes = sizeof_indices_type (type) * n_indices;
  CoglIndexBuffer *index_buffer = cogl_index_buffer_new (context, buffer_bytes);
  CoglBuffer *buffer = COGL_BUFFER (index_buffer);
  CoglIndices *indices;
  CoglError *ignore_error = NULL;

  cogl_buffer_set_data (buffer,
                        0,
                        indices_data,
                        buffer_bytes,
                        &ignore_error);
  if (ignore_error)
    {
      cogl_error_free (ignore_error);
      cogl_object_unref (index_buffer);
      return NULL;
    }

  indices = cogl_indices_new_for_buffer (type, index_buffer, 0);
  cogl_object_unref (index_buffer);

  return indices;
}
Esempio n. 5
0
void
_cogl_buffer_unmap_for_fill_or_fallback (CoglBuffer *buffer)
{
  CoglContext *ctx = buffer->context;

  _COGL_RETURN_IF_FAIL (ctx->buffer_map_fallback_in_use);

  ctx->buffer_map_fallback_in_use = FALSE;

  if ((buffer->flags & COGL_BUFFER_FLAG_MAPPED_FALLBACK))
    {
      cogl_buffer_set_data (buffer, 0,
                            ctx->buffer_map_fallback_array->data,
                            buffer->size);
      buffer->flags &= ~COGL_BUFFER_FLAG_MAPPED_FALLBACK;
    }
  else
    cogl_buffer_unmap (buffer);
}
Esempio n. 6
0
CoglIndices *
cogl_indices_new (CoglIndicesType type,
                  const void *indices_data,
                  int n_indices)
{
  size_t array_bytes = sizeof_indices_type (type) * n_indices;
  CoglIndexArray *array = cogl_index_array_new (array_bytes);
  CoglBuffer *buffer = COGL_BUFFER (array);
  CoglIndices *indices;

  cogl_buffer_set_data (buffer,
                        0,
                        indices_data,
                        array_bytes);

  indices = cogl_indices_new_for_array (type, array, 0);
  cogl_object_unref (array);

  return indices;
}
Esempio n. 7
0
CoglIndices *
cogl_indices_new (CoglIndicesType type,
                  const void *indices_data,
                  int n_indices)
{
  size_t buffer_bytes = sizeof_indices_type (type) * n_indices;
  CoglIndexBuffer *index_buffer = cogl_index_buffer_new (buffer_bytes);
  CoglBuffer *buffer = COGL_BUFFER (index_buffer);
  CoglIndices *indices;

  cogl_buffer_set_data (buffer,
                        0,
                        indices_data,
                        buffer_bytes);

  indices = cogl_indices_new_for_buffer (type, index_buffer, 0);
  cogl_object_unref (index_buffer);

  return indices;
}
Esempio n. 8
0
static void
emit_vertex_buffer_geometry (CoglFramebuffer *fb,
                             CoglPipeline *pipeline,
                             CoglPangoDisplayListNode *node)
{
  CoglContext *ctx = fb->context;

  /* It's expensive to go through the Cogl journal for large runs
   * of text in part because the journal transforms the quads in software
   * to avoid changing the modelview matrix. So for larger runs of text
   * we load the vertices into a VBO, and this has the added advantage
   * that if the text doesn't change from frame to frame the VBO can
   * be re-used avoiding the repeated cost of validating the data and
   * mapping it into the GPU... */

  if (node->d.texture.primitive == NULL)
    {
      CoglAttributeBuffer *buffer;
      CoglVertexP2T2 *verts, *v;
      int n_verts;
      CoglBool allocated = FALSE;
      CoglAttribute *attributes[2];
      CoglPrimitive *prim;
      int i;
      CoglError *ignore_error = NULL;

      n_verts = node->d.texture.rectangles->len * 4;

      buffer
        = cogl_attribute_buffer_new_with_size (ctx,
                                               n_verts *
                                               sizeof (CoglVertexP2T2));

      if ((verts = cogl_buffer_map (COGL_BUFFER (buffer),
                                    COGL_BUFFER_ACCESS_WRITE,
                                    COGL_BUFFER_MAP_HINT_DISCARD,
                                    &ignore_error)) == NULL)
        {
          cogl_error_free (ignore_error);
          verts = g_new (CoglVertexP2T2, n_verts);
          allocated = TRUE;
        }

      v = verts;

      /* Copy the rectangles into the buffer and expand into four
         vertices instead of just two */
      for (i = 0; i < node->d.texture.rectangles->len; i++)
        {
          const CoglPangoDisplayListRectangle *rectangle
            = &g_array_index (node->d.texture.rectangles,
                              CoglPangoDisplayListRectangle, i);

          v->x = rectangle->x_1;
          v->y = rectangle->y_1;
          v->s = rectangle->s_1;
          v->t = rectangle->t_1;
          v++;
          v->x = rectangle->x_1;
          v->y = rectangle->y_2;
          v->s = rectangle->s_1;
          v->t = rectangle->t_2;
          v++;
          v->x = rectangle->x_2;
          v->y = rectangle->y_2;
          v->s = rectangle->s_2;
          v->t = rectangle->t_2;
          v++;
          v->x = rectangle->x_2;
          v->y = rectangle->y_1;
          v->s = rectangle->s_2;
          v->t = rectangle->t_1;
          v++;
        }

      if (allocated)
        {
          cogl_buffer_set_data (COGL_BUFFER (buffer),
                                0, /* offset */
                                verts,
                                sizeof (CoglVertexP2T2) * n_verts,
                                NULL);
          g_free (verts);
        }
      else
        cogl_buffer_unmap (COGL_BUFFER (buffer));

      attributes[0] = cogl_attribute_new (buffer,
                                          "cogl_position_in",
                                          sizeof (CoglVertexP2T2),
                                          G_STRUCT_OFFSET (CoglVertexP2T2, x),
                                          2, /* n_components */
                                          COGL_ATTRIBUTE_TYPE_FLOAT);
      attributes[1] = cogl_attribute_new (buffer,
                                          "cogl_tex_coord0_in",
                                          sizeof (CoglVertexP2T2),
                                          G_STRUCT_OFFSET (CoglVertexP2T2, s),
                                          2, /* n_components */
                                          COGL_ATTRIBUTE_TYPE_FLOAT);

      prim = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES,
                                                 n_verts,
                                                 attributes,
                                                 2 /* n_attributes */);

#ifdef CLUTTER_COGL_HAS_GL
      if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_QUADS))
        cogl_primitive_set_mode (prim, GL_QUADS);
      else
#endif
        {
          /* GLES doesn't support GL_QUADS so instead we use a VBO
             with indexed vertices to generate GL_TRIANGLES from the
             quads */

          CoglIndices *indices =
            cogl_get_rectangle_indices (ctx, node->d.texture.rectangles->len);

          cogl_primitive_set_indices (prim, indices,
                                      node->d.texture.rectangles->len * 6);
        }

      node->d.texture.primitive = prim;

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

  cogl_primitive_draw (node->d.texture.primitive,
                       fb,
                       pipeline);
}
Esempio n. 9
0
static void
clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect)
{
  ClutterDeformEffect *self= CLUTTER_DEFORM_EFFECT (effect);
  ClutterDeformEffectPrivate *priv = self->priv;
  CoglHandle material;
  CoglPipeline *pipeline;
  CoglDepthState depth_state;
  CoglFramebuffer *fb = cogl_get_draw_framebuffer ();

  if (priv->is_dirty)
    {
      ClutterRect rect;
      gboolean mapped_buffer;
      CoglVertexP3T2C4 *verts;
      ClutterActor *actor;
      gfloat width, height;
      guint opacity;
      gint i, j;

      actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
      opacity = clutter_actor_get_paint_opacity (actor);

      /* if we don't have a target size, fall back to the actor's
       * allocation, though wrong it might be
       */
      if (clutter_offscreen_effect_get_target_rect (effect, &rect))
        {
          width = clutter_rect_get_width (&rect);
          height = clutter_rect_get_height (&rect);
        }
      else
        clutter_actor_get_size (actor, &width, &height);

      /* XXX ideally, the sub-classes should tell us what they
       * changed in the texture vertices; we then would be able to
       * avoid resubmitting the same data, if it did not change. for
       * the time being, we resubmit everything
       */
      verts = cogl_buffer_map (COGL_BUFFER (priv->buffer),
                               COGL_BUFFER_ACCESS_WRITE,
                               COGL_BUFFER_MAP_HINT_DISCARD);

      /* If the map failed then we'll resort to allocating a temporary
         buffer */
      if (verts == NULL)
        {
          mapped_buffer = FALSE;
          verts = g_malloc (sizeof (*verts) * priv->n_vertices);
        }
      else
        mapped_buffer = TRUE;

      for (i = 0; i < priv->y_tiles + 1; i++)
        {
          for (j = 0; j < priv->x_tiles + 1; j++)
            {
              CoglVertexP3T2C4 *vertex_out;
              CoglTextureVertex vertex;

              /* CoglTextureVertex isn't an ideal structure to use for
                 this because it contains a CoglColor. The internal
                 layout of CoglColor is mean to be private so Clutter
                 can not pass a pointer to it as a vertex
                 attribute. Also it contains padding so we end up
                 storing more data in the vertex buffer than we need
                 to. Instead we let the application modify a dummy
                 vertex and then copy the details back out to a more
                 well-defined struct */

              vertex.tx = (float) j / priv->x_tiles;
              vertex.ty = (float) i / priv->y_tiles;

              vertex.x = width * vertex.tx;
              vertex.y = height * vertex.ty;
              vertex.z = 0.0f;

              cogl_color_init_from_4ub (&vertex.color, 255, 255, 255, opacity);

              clutter_deform_effect_deform_vertex (self,
                                                   width, height,
                                                   &vertex);

              vertex_out = verts + i * (priv->x_tiles + 1) + j;

              vertex_out->x = vertex.x;
              vertex_out->y = vertex.y;
              vertex_out->z = vertex.z;
              vertex_out->s = vertex.tx;
              vertex_out->t = vertex.ty;
              vertex_out->r = cogl_color_get_red_byte (&vertex.color);
              vertex_out->g = cogl_color_get_green_byte (&vertex.color);
              vertex_out->b = cogl_color_get_blue_byte (&vertex.color);
              vertex_out->a = cogl_color_get_alpha_byte (&vertex.color);
            }
        }

      if (mapped_buffer)
        cogl_buffer_unmap (COGL_BUFFER (priv->buffer));
      else
        {
          cogl_buffer_set_data (COGL_BUFFER (priv->buffer),
                                0, /* offset */
                                verts,
                                sizeof (*verts) * priv->n_vertices);
          g_free (verts);
        }

      priv->is_dirty = FALSE;
    }

  material = clutter_offscreen_effect_get_target (effect);
  pipeline = COGL_PIPELINE (material);

  /* enable depth testing */
  cogl_depth_state_init (&depth_state);
  cogl_depth_state_set_test_enabled (&depth_state, TRUE);
  cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL);

  /* enable backface culling if we have a back material */
  if (priv->back_pipeline != NULL)
    cogl_pipeline_set_cull_face_mode (pipeline,
                                      COGL_PIPELINE_CULL_FACE_MODE_BACK);

  /* draw the front */
  if (material != NULL)
    cogl_framebuffer_draw_primitive (fb, pipeline, priv->primitive);

  /* draw the back */
  if (priv->back_pipeline != NULL)
    {
      CoglPipeline *back_pipeline;

      /* We probably shouldn't be modifying the user's material so
         instead we make a temporary copy */
      back_pipeline = cogl_pipeline_copy (priv->back_pipeline);
      cogl_pipeline_set_depth_state (back_pipeline, &depth_state, NULL);
      cogl_pipeline_set_cull_face_mode (back_pipeline,
                                        COGL_PIPELINE_CULL_FACE_MODE_FRONT);

      cogl_framebuffer_draw_primitive (fb, back_pipeline, priv->primitive);

      cogl_object_unref (back_pipeline);
    }

  if (G_UNLIKELY (priv->lines_primitive != NULL))
    {
      CoglContext *ctx =
        clutter_backend_get_cogl_context (clutter_get_default_backend ());
      CoglPipeline *lines_pipeline = cogl_pipeline_new (ctx);
      cogl_pipeline_set_color4f (lines_pipeline, 1.0, 0, 0, 1.0);
      cogl_framebuffer_draw_primitive (fb, lines_pipeline,
                                       priv->lines_primitive);
      cogl_object_unref (lines_pipeline);
    }
}
Esempio n. 10
0
static void
paint (Data *data)
{
  int i;
  float diff_time;

  /* Update all of the firework's positions */
  for (i = 0; i < N_FIREWORKS; i++)
    {
      Firework *firework = data->fireworks + i;

      if ((fabsf (firework->x - firework->start_x) > 2.0f) ||
          firework->y < -1.0f)
        {
          firework->size = g_random_double_range (0.001f, 0.1f);
          firework->start_x = 1.0f + firework->size;
          firework->start_y = -1.0f;
          firework->initial_x_velocity = g_random_double_range (-0.1f, -2.0f);
          firework->initial_y_velocity = g_random_double_range (0.1f, 4.0f);
          g_timer_reset (firework->timer);

          /* Pick a random color out of six */
          if (g_random_boolean ())
            {
              memset (&firework->color, 0, sizeof (Color));
              ((uint8_t *) &firework->color)[g_random_int_range (0, 3)] = 255;
            }
          else
            {
              memset (&firework->color, 255, sizeof (Color));
              ((uint8_t *) &firework->color)[g_random_int_range (0, 3)] = 0;
            }
          firework->color.alpha = 255;

          /* Fire some of the fireworks from the other side */
          if (g_random_boolean ())
            {
              firework->start_x = -firework->start_x;
              firework->initial_x_velocity = -firework->initial_x_velocity;
            }
        }

      diff_time = g_timer_elapsed (firework->timer, NULL);

      firework->x = (firework->start_x +
                     firework->initial_x_velocity * diff_time);

      firework->y = ((firework->initial_y_velocity * diff_time +
                      0.5f * GRAVITY * diff_time * diff_time) +
                     firework->start_y);
    }

  diff_time = g_timer_elapsed (data->last_spark_time, NULL);
  if (diff_time < 0.0f || diff_time >= TIME_PER_SPARK)
    {
      /* Add a new spark for each firework, overwriting the oldest ones */
      for (i = 0; i < N_FIREWORKS; i++)
        {
          Spark *spark = data->sparks + data->next_spark_num;
          Firework *firework = data->fireworks + i;

          spark->x = (firework->x +
                      g_random_double_range (-firework->size / 2.0f,
                                             firework->size / 2.0f));
          spark->y = (firework->y +
                      g_random_double_range (-firework->size / 2.0f,
                                             firework->size / 2.0f));
          spark->base_color = firework->color;

          data->next_spark_num = (data->next_spark_num + 1) & (N_SPARKS - 1);
        }

      /* Update the colour of each spark */
      for (i = 0; i < N_SPARKS; i++)
        {
          float color_value;

          /* First spark is the oldest */
          Spark *spark = data->sparks + ((data->next_spark_num + i)
                                         & (N_SPARKS - 1));

          color_value = i / (N_SPARKS - 1.0f);
          spark->color.red = spark->base_color.red * color_value;
          spark->color.green = spark->base_color.green * color_value;
          spark->color.blue = spark->base_color.blue * color_value;
          spark->color.alpha = 255.0f * color_value;
        }

      g_timer_reset (data->last_spark_time);
    }

  cogl_buffer_set_data (data->attribute_buffer,
                        0, /* offset */
                        data->sparks,
                        sizeof (data->sparks),
                        NULL /* error */);

  cogl_framebuffer_clear4f (data->fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);

  cogl_primitive_draw (data->primitive,
                       data->fb,
                       data->pipeline);

  cogl_onscreen_swap_buffers (data->fb);
}
Esempio n. 11
0
void
cogl_polygon (const CoglTextureVertex *vertices,
              unsigned int n_vertices,
	      CoglBool use_color)
{
  CoglPipeline *pipeline;
  ValidateState validate_state;
  int n_layers;
  int n_attributes;
  CoglAttribute **attributes;
  int i;
  unsigned int stride;
  size_t stride_bytes;
  CoglAttributeBuffer *attribute_buffer;
  float *v;

  _COGL_GET_CONTEXT (ctx, NO_RETVAL);

  pipeline = cogl_get_source ();

  validate_state.original_pipeline = pipeline;
  validate_state.pipeline = pipeline;
  cogl_pipeline_foreach_layer (pipeline,
                               _cogl_polygon_validate_layer_cb,
                               &validate_state);
  pipeline = validate_state.pipeline;

  n_layers = cogl_pipeline_get_n_layers (pipeline);

  n_attributes = 1 + n_layers + (use_color ? 1 : 0);
  attributes = g_alloca (sizeof (CoglAttribute *) * n_attributes);

  /* Our data is arranged like:
   * [X, Y, Z, TX0, TY0, TX1, TY1..., R, G, B, A,...] */
  stride = 3 + (2 * n_layers) + (use_color ? 1 : 0);
  stride_bytes = stride * sizeof (float);

  /* Make sure there is enough space in the global vertex array. This
   * is used so we can render the polygon with a single call to OpenGL
   * but still support any number of vertices */
  g_array_set_size (ctx->polygon_vertices, n_vertices * stride);

  attribute_buffer =
    cogl_attribute_buffer_new (ctx, n_vertices * stride_bytes, NULL);

  attributes[0] = cogl_attribute_new (attribute_buffer,
                                      "cogl_position_in",
                                      stride_bytes,
                                      0,
                                      3,
                                      COGL_ATTRIBUTE_TYPE_FLOAT);

  for (i = 0; i < n_layers; i++)
    {
      static const char *names[] = {
          "cogl_tex_coord0_in",
          "cogl_tex_coord1_in",
          "cogl_tex_coord2_in",
          "cogl_tex_coord3_in",
          "cogl_tex_coord4_in",
          "cogl_tex_coord5_in",
          "cogl_tex_coord6_in",
          "cogl_tex_coord7_in"
      };
      char *allocated_name = NULL;
      const char *name;

      if (i < 8)
        name = names[i];
      else
        name = allocated_name = g_strdup_printf ("cogl_tex_coord%d_in", i);

      attributes[i + 1] = cogl_attribute_new (attribute_buffer,
                                              name,
                                              stride_bytes,
                                              /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
                                              12 + 8 * i,
                                              2,
                                              COGL_ATTRIBUTE_TYPE_FLOAT);

      g_free (allocated_name);
    }

  if (use_color)
    {
      attributes[n_attributes - 1] =
        cogl_attribute_new (attribute_buffer,
                            "cogl_color_in",
                            stride_bytes,
                            /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
                            12 + 8 * n_layers,
                            4,
                            COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
    }

  /* Convert the vertices into an array of float vertex attributes */
  v = (float *)ctx->polygon_vertices->data;
  for (i = 0; i < n_vertices; i++)
    {
      AppendTexCoordsState append_tex_coords_state;
      uint8_t *c;

      /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
      v[0] = vertices[i].x;
      v[1] = vertices[i].y;
      v[2] = vertices[i].z;

      append_tex_coords_state.vertices_in = vertices;
      append_tex_coords_state.vertex = i;
      append_tex_coords_state.layer = 0;
      append_tex_coords_state.vertices_out = v;
      cogl_pipeline_foreach_layer (pipeline,
                                   append_tex_coord_attributes_cb,
                                   &append_tex_coords_state);

      if (use_color)
        {
          /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
          c = (uint8_t *) (v + 3 + 2 * n_layers);
          c[0] = cogl_color_get_red_byte (&vertices[i].color);
          c[1] = cogl_color_get_green_byte (&vertices[i].color);
          c[2] = cogl_color_get_blue_byte (&vertices[i].color);
          c[3] = cogl_color_get_alpha_byte (&vertices[i].color);
        }

      v += stride;
    }

  v = (float *)ctx->polygon_vertices->data;
  cogl_buffer_set_data (COGL_BUFFER (attribute_buffer),
                        0,
                        v,
                        ctx->polygon_vertices->len * sizeof (float));

  /* XXX: although this may seem redundant, we need to do this since
   * cogl_polygon() can be used with legacy state and its the source stack
   * which track whether legacy state is enabled.
   *
   * (We only have a CoglDrawFlag to disable legacy state not one
   *  to enable it) */
  cogl_push_source (pipeline);

  _cogl_framebuffer_draw_attributes (cogl_get_draw_framebuffer (),
                                     pipeline,
                                     COGL_VERTICES_MODE_TRIANGLE_FAN,
                                     0, n_vertices,
                                     attributes,
                                     n_attributes,
                                     0 /* no draw flags */);

  cogl_pop_source ();

  if (pipeline != validate_state.original_pipeline)
    cogl_object_unref (pipeline);

  cogl_object_unref (attribute_buffer);

  for (i = 0; i < n_attributes; i++)
    cogl_object_unref (attributes[i]);
}
Esempio n. 12
0
static void
clutter_canvas_emit_draw (ClutterCanvas *self)
{
  ClutterCanvasPrivate *priv = self->priv;
  int real_width, real_height;
  cairo_surface_t *surface;
  gboolean mapped_buffer;
  unsigned char *data;
  CoglBuffer *buffer;
  int window_scale = 1;
  gboolean res;
  cairo_t *cr;

  g_assert (priv->height > 0 && priv->width > 0);

  priv->dirty = TRUE;

  if (priv->scale_factor_set)
    window_scale = priv->scale_factor;
  else
    g_object_get (clutter_settings_get_default (),
                  "window-scaling-factor", &window_scale,
                  NULL);

  real_width = priv->width * window_scale;
  real_height = priv->height * window_scale;

  CLUTTER_NOTE (MISC, "Creating Cairo surface with size %d x %d (real: %d x %d, scale: %d)",
                priv->width, priv->height,
                real_width, real_height,
                window_scale);

  if (priv->buffer == NULL)
    {
      CoglContext *ctx;

      ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
      priv->buffer = cogl_bitmap_new_with_size (ctx,
                                                real_width,
                                                real_height,
                                                CLUTTER_CAIRO_FORMAT_ARGB32);
    }

  buffer = COGL_BUFFER (cogl_bitmap_get_buffer (priv->buffer));
  if (buffer == NULL)
    return;

  cogl_buffer_set_update_hint (buffer, COGL_BUFFER_UPDATE_HINT_DYNAMIC);

  data = cogl_buffer_map (buffer,
                          COGL_BUFFER_ACCESS_READ_WRITE,
                          COGL_BUFFER_MAP_HINT_DISCARD);

  if (data != NULL)
    {
      int bitmap_stride = cogl_bitmap_get_rowstride (priv->buffer);

      surface = cairo_image_surface_create_for_data (data,
                                                     CAIRO_FORMAT_ARGB32,
                                                     real_width,
                                                     real_height,
                                                     bitmap_stride);
      mapped_buffer = TRUE;
    }
  else
    {
      surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
                                            real_width,
                                            real_height);

      mapped_buffer = FALSE;
    }

  cairo_surface_set_device_scale (surface, window_scale, window_scale);

  self->priv->cr = cr = cairo_create (surface);

  g_signal_emit (self, canvas_signals[DRAW], 0,
                 cr, priv->width, priv->height,
                 &res);

#ifdef CLUTTER_ENABLE_DEBUG
  if (_clutter_diagnostic_enabled () && cairo_status (cr))
    {
      g_warning ("Drawing failed for <ClutterCanvas>[%p]: %s",
                 self,
                 cairo_status_to_string (cairo_status (cr)));
    }
#endif

  self->priv->cr = NULL;
  cairo_destroy (cr);

  if (mapped_buffer)
    cogl_buffer_unmap (buffer);
  else
    {
      int size = cairo_image_surface_get_stride (surface) * priv->height;
      cogl_buffer_set_data (buffer,
                            0,
                            cairo_image_surface_get_data (surface),
                            size);
    }

  cairo_surface_destroy (surface);
}