Пример #1
0
void
cogl_begin_gl (void)
{
    CoglPipeline *pipeline;

    _COGL_GET_CONTEXT (ctx, NO_RETVAL);

    if (ctx->in_begin_gl_block)
    {
        static gboolean shown = FALSE;
        if (!shown)
            g_warning ("You should not nest cogl_begin_gl/cogl_end_gl blocks");
        shown = TRUE;
        return;
    }
    ctx->in_begin_gl_block = TRUE;

    /* Flush all batched primitives */
    cogl_flush ();

    /* Flush framebuffer state, including clip state, modelview and
     * projection matrix state
     *
     * NB: _cogl_framebuffer_flush_state may disrupt various state (such
     * as the pipeline state) when flushing the clip stack, so should
     * always be done first when preparing to draw. */
    _cogl_framebuffer_flush_state (cogl_get_draw_framebuffer (),
                                   _cogl_get_read_framebuffer (),
                                   COGL_FRAMEBUFFER_STATE_ALL);

    /* Setup the state for the current pipeline */

    /* We considered flushing a specific, minimal pipeline here to try and
     * simplify the GL state, but decided to avoid special cases and second
     * guessing what would be actually helpful.
     *
     * A user should instead call cogl_set_source_color4ub() before
     * cogl_begin_gl() to simplify the state flushed.
     *
     * XXX: note defining n_tex_coord_attribs using
     * cogl_pipeline_get_n_layers is a hack, but the problem is that
     * n_tex_coord_attribs is usually defined when drawing a primitive
     * which isn't happening here.
     *
     * Maybe it would be more useful if this code did flush the
     * opaque_color_pipeline and then call into cogl-pipeline-opengl.c to then
     * restore all state for the material's backend back to default OpenGL
     * values.
     */
    pipeline = cogl_get_source ();
    _cogl_pipeline_flush_gl_state (pipeline,
                                   FALSE,
                                   cogl_pipeline_get_n_layers (pipeline));

    /* Disable any cached vertex arrays */
    _cogl_attribute_disable_cached_arrays ();
}
Пример #2
0
void
cogl_path_stroke (CoglPath *path,
                  CoglFramebuffer *framebuffer,
                  CoglPipeline *pipeline)
{
  CoglPathData *data;
  CoglPipeline *copy = NULL;
  unsigned int path_start;
  int path_num = 0;
  CoglPathNode *node;

  _COGL_RETURN_IF_FAIL (cogl_is_path (path));
  _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (framebuffer));
  _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));

  data = path->data;

  if (data->path_nodes->len == 0)
    return;

  if (cogl_pipeline_get_n_layers (pipeline) != 0)
    {
      copy = cogl_pipeline_copy (pipeline);
      _cogl_pipeline_prune_to_n_layers (copy, 0);
      pipeline = copy;
    }

  _cogl_path_build_stroke_attribute_buffer (path);

  for (path_start = 0;
       path_start < data->path_nodes->len;
       path_start += node->path_size)
    {
      CoglPrimitive *primitive;

      node = &g_array_index (data->path_nodes, CoglPathNode, path_start);

      primitive =
        cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_LINE_STRIP,
                                            node->path_size,
                                            &data->stroke_attributes[path_num],
                                            1);
      cogl_primitive_draw (primitive, framebuffer, pipeline);
      cogl_object_unref (primitive);

      path_num++;
    }

  if (copy)
    cogl_object_unref (copy);
}
Пример #3
0
static void
_cogl_path_stroke_nodes (CoglPath *path)
{
  CoglPathData *data = path->data;
  CoglPipeline *copy = NULL;
  CoglPipeline *source;
  unsigned int path_start;
  int path_num = 0;
  CoglPathNode *node;

  _COGL_GET_CONTEXT (ctx, NO_RETVAL);

  source = cogl_get_source ();

  if (cogl_pipeline_get_n_layers (source) != 0)
    {
      copy = cogl_pipeline_copy (source);
      _cogl_pipeline_prune_to_n_layers (copy, 0);
      source = copy;
    }

  _cogl_path_build_stroke_attribute_buffer (path);

  cogl_push_source (source);

  for (path_start = 0;
       path_start < data->path_nodes->len;
       path_start += node->path_size)
    {
      node = &g_array_index (data->path_nodes, CoglPathNode, path_start);

      cogl_framebuffer_vdraw_attributes (cogl_get_draw_framebuffer (),
                                         source,
                                         COGL_VERTICES_MODE_LINE_STRIP,
                                         0, node->path_size,
                                         data->stroke_attributes[path_num],
                                         NULL);

      path_num++;
    }

  cogl_pop_source ();

  if (copy)
    cogl_object_unref (copy);
}
Пример #4
0
/* This path supports multitexturing but only when each of the layers is
 * handled with a single GL texture. Also if repeating is necessary then
 * _cogl_texture_can_hardware_repeat() must return TRUE.
 * This includes layers made from:
 *
 * - CoglTexture2DSliced: if only comprised of a single slice with optional
 *   waste, assuming the users given texture coordinates don't require
 *   repeating.
 * - CoglTexture{1D,2D,3D}: always.
 * - CoglTexture2DAtlas: assuming the users given texture coordinates don't
 *   require repeating.
 * - CoglTextureRectangle: assuming the users given texture coordinates don't
 *   require repeating.
 * - CoglTexturePixmap: assuming the users given texture coordinates don't
 *   require repeating.
 */
static CoglBool
_cogl_multitexture_quad_single_primitive (CoglFramebuffer *framebuffer,
                                          CoglPipeline *pipeline,
                                          const float  *position,
                                          const float  *user_tex_coords,
                                          int user_tex_coords_len)
{
  int n_layers = cogl_pipeline_get_n_layers (pipeline);
  ValidateTexCoordsState state;
  float *final_tex_coords = alloca (sizeof (float) * 4 * n_layers);

  state.i = -1;
  state.n_layers = n_layers;
  state.user_tex_coords = user_tex_coords;
  state.user_tex_coords_len = user_tex_coords_len;
  state.final_tex_coords = final_tex_coords;
  state.override_pipeline = NULL;
  state.needs_multiple_primitives = FALSE;

  cogl_pipeline_foreach_layer (pipeline,
                               validate_tex_coords_cb,
                               &state);

  if (state.needs_multiple_primitives)
    return FALSE;

  if (state.override_pipeline)
    pipeline = state.override_pipeline;

  _cogl_journal_log_quad (framebuffer->journal,
                          position,
                          pipeline,
                          n_layers,
                          NULL, /* no texture override */
                          final_tex_coords,
                          n_layers * 4);

  if (state.override_pipeline)
    cogl_object_unref (state.override_pipeline);

  return TRUE;
}
Пример #5
0
void
_cogl_glsl_shader_set_source_with_boilerplate (CoglContext *ctx,
                                               GLuint shader_gl_handle,
                                               GLenum shader_gl_type,
                                               CoglPipeline *pipeline,
                                               GLsizei count_in,
                                               const char **strings_in,
                                               const GLint *lengths_in)
{
  const char *vertex_boilerplate;
  const char *fragment_boilerplate;

  const char **strings = g_alloca (sizeof (char *) * (count_in + 4));
  GLint *lengths = g_alloca (sizeof (GLint) * (count_in + 4));
  char *version_string;
  int count = 0;

  int n_layers;

  vertex_boilerplate = _COGL_VERTEX_SHADER_BOILERPLATE;
  fragment_boilerplate = _COGL_FRAGMENT_SHADER_BOILERPLATE;

  version_string = g_strdup_printf ("#version %i\n\n",
                                    ctx->glsl_version_to_use);
  strings[count] = version_string;
  lengths[count++] = -1;

  if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_EMBEDDED) &&
      cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_3D))
    {
      static const char texture_3d_extension[] =
        "#extension GL_OES_texture_3D : enable\n";
      strings[count] = texture_3d_extension;
      lengths[count++] = sizeof (texture_3d_extension) - 1;
    }

  if (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_EGL_IMAGE_EXTERNAL))
    {
      static const char texture_3d_extension[] =
        "#extension GL_OES_EGL_image_external : require\n";
      strings[count] = texture_3d_extension;
      lengths[count++] = sizeof (texture_3d_extension) - 1;
    }

  if (shader_gl_type == GL_VERTEX_SHADER)
    {
      strings[count] = vertex_boilerplate;
      lengths[count++] = strlen (vertex_boilerplate);
    }
  else if (shader_gl_type == GL_FRAGMENT_SHADER)
    {
      strings[count] = fragment_boilerplate;
      lengths[count++] = strlen (fragment_boilerplate);
    }

  n_layers = cogl_pipeline_get_n_layers (pipeline);
  if (n_layers)
    {
      GString *layer_declarations = ctx->codegen_boilerplate_buffer;
      g_string_set_size (layer_declarations, 0);

      g_string_append_printf (layer_declarations,
                              "varying vec4 _cogl_tex_coord[%d];\n",
                              n_layers);

      if (shader_gl_type == GL_VERTEX_SHADER)
        {
          g_string_append_printf (layer_declarations,
                                  "uniform mat4 cogl_texture_matrix[%d];\n",
                                  n_layers);

          _cogl_pipeline_foreach_layer_internal (pipeline,
                                                 add_layer_vertex_boilerplate_cb,
                                                 layer_declarations);
        }
      else if (shader_gl_type == GL_FRAGMENT_SHADER)
        {
          _cogl_pipeline_foreach_layer_internal (pipeline,
                                                 add_layer_fragment_boilerplate_cb,
                                                 layer_declarations);
        }

      strings[count] = layer_declarations->str;
      lengths[count++] = -1; /* null terminated */
    }

  memcpy (strings + count, strings_in, sizeof (char *) * count_in);
  if (lengths_in)
    memcpy (lengths + count, lengths_in, sizeof (GLint) * count_in);
  else
    {
      int i;

      for (i = 0; i < count_in; i++)
        lengths[count + i] = -1; /* null terminated */
    }
  count += count_in;

  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_SHOW_SOURCE)))
    {
      GString *buf = g_string_new (NULL);
      int i;

      g_string_append_printf (buf,
                              "%s shader:\n",
                              shader_gl_type == GL_VERTEX_SHADER ?
                              "vertex" : "fragment");
      for (i = 0; i < count; i++)
        if (lengths[i] != -1)
          g_string_append_len (buf, strings[i], lengths[i]);
        else
          g_string_append (buf, strings[i]);

      g_message ("%s", buf->str);

      g_string_free (buf, TRUE);
    }

  GE( ctx, glShaderSource (shader_gl_handle, count,
                           (const char **) strings, lengths) );

  g_free (version_string);
}
static gboolean
_cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
                                 unsigned long pipelines_difference)
{
  CoglPipelineShaderState *shader_state;

  _COGL_GET_CONTEXT (ctx, FALSE);

  shader_state = get_shader_state (pipeline);

  if (shader_state->source)
    {
      const char *source_strings[2];
      GLint lengths[2];
      GLint compile_status;
      GLuint shader;
      int n_layers;

      COGL_STATIC_COUNTER (vertend_glsl_compile_counter,
                           "glsl vertex compile counter",
                           "Increments each time a new GLSL "
                           "vertex shader is compiled",
                           0 /* no application private data */);
      COGL_COUNTER_INC (_cogl_uprof_context, vertend_glsl_compile_counter);

      g_string_append (shader_state->source,
                       "  cogl_position_out = "
                       "cogl_modelview_projection_matrix * "
                       "cogl_position_in;\n"
                       "  cogl_color_out = cogl_color_in;\n"
                       "}\n");

      GE_RET( shader, ctx, glCreateShader (GL_VERTEX_SHADER) );

      lengths[0] = shader_state->header->len;
      source_strings[0] = shader_state->header->str;
      lengths[1] = shader_state->source->len;
      source_strings[1] = shader_state->source->str;

      n_layers = cogl_pipeline_get_n_layers (pipeline);

      _cogl_shader_set_source_with_boilerplate (shader, GL_VERTEX_SHADER,
                                                n_layers,
                                                2, /* count */
                                                source_strings, lengths);

      GE( ctx, glCompileShader (shader) );
      GE( ctx, glGetShaderiv (shader, GL_COMPILE_STATUS, &compile_status) );

      if (!compile_status)
        {
          GLint len = 0;
          char *shader_log;

          GE( ctx, glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &len) );
          shader_log = g_alloca (len);
          GE( ctx, glGetShaderInfoLog (shader, len, &len, shader_log) );
          g_warning ("Shader compilation failed:\n%s", shader_log);
        }

      shader_state->header = NULL;
      shader_state->source = NULL;
      shader_state->gl_shader = shader;
    }

  return TRUE;
}
Пример #7
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]);
}
Пример #8
0
static CoglBool
_cogl_rectangles_validate_layer_cb (CoglPipeline *pipeline,
                                    int layer_index,
                                    void *user_data)
{
  ValidateLayerState *state = user_data;
  CoglTexture *texture;

  state->i++;

  /* We need to ensure the mipmaps are ready before deciding
   * anything else about the texture because the texture storage
   * could completely change if it needs to be migrated out of the
   * atlas and will affect how we validate the layer.
   *
   * FIXME: this needs to be generalized. There could be any
   * number of things that might require a shuffling of the
   * underlying texture storage. We could add two mechanisms to
   * generalize this a bit...
   *
   * 1) add a _cogl_pipeline_layer_update_storage() function that
   * would for instance consider if mipmapping is necessary and
   * potentially migrate the texture from an atlas.
   *
   * 2) allow setting of transient primitive-flags on a pipeline
   * that may affect the outcome of _update_storage(). One flag
   * could indicate that we expect to sample beyond the bounds of
   * the texture border.
   *
   *   flags = COGL_PIPELINE_PRIMITIVE_FLAG_VALID_BORDERS;
   *   _cogl_pipeline_layer_assert_primitive_flags (layer, flags)
   *   _cogl_pipeline_layer_update_storage (layer)
   *   enqueue primitive in journal
   *
   *   when the primitive is dequeued and drawn we should:
   *   _cogl_pipeline_flush_gl_state (pipeline)
   *   draw primitive
   *   _cogl_pipeline_unassert_primitive_flags (layer, flags);
   *
   * _cogl_pipeline_layer_update_storage should take into
   * consideration all the asserted primitive requirements.  (E.g.
   * there could be multiple primitives in the journal - or in a
   * renderlist in the future - that need mipmaps or that need
   * valid contents beyond their borders (for cogl_polygon)
   * meaning they can't work with textures in an atas, so
   * _cogl_pipeline_layer_update_storage would pass on these
   * requirements to the texture atlas backend which would make
   * sure the referenced texture is migrated out of the atlas and
   * mipmaps are generated.)
   */
  _cogl_pipeline_pre_paint_for_layer (pipeline, layer_index);

  texture = cogl_pipeline_get_layer_texture (pipeline, layer_index);

  /* NULL textures are handled by
   * _cogl_pipeline_flush_gl_state */
  if (texture == NULL)
    return TRUE;

  if (state->i == 0)
    state->first_layer = layer_index;

  /* XXX:
   * For now, if the first layer is sliced then all other layers are
   * ignored since we currently don't support multi-texturing with
   * sliced textures. If the first layer is not sliced then any other
   * layers found to be sliced will be skipped. (with a warning)
   *
   * TODO: Add support for multi-texturing rectangles with sliced
   * textures if no texture matrices are in use.
   */
  if (cogl_texture_is_sliced (texture))
    {
      if (state->i == 0)
        {
          if (cogl_pipeline_get_n_layers (pipeline) > 1)
            {
              static CoglBool warning_seen = FALSE;

              if (!state->override_source)
                state->override_source = cogl_pipeline_copy (pipeline);
              _cogl_pipeline_prune_to_n_layers (state->override_source, 1);

              if (!warning_seen)
                g_warning ("Skipping layers 1..n of your pipeline since "
                           "the first layer is sliced. We don't currently "
                           "support any multi-texturing with sliced "
                           "textures but assume layer 0 is the most "
                           "important to keep");
              warning_seen = TRUE;
            }

          state->all_use_sliced_quad_fallback = TRUE;

          return FALSE;
        }
      else
        {
          static CoglBool warning_seen = FALSE;
          CoglTexture2D *tex_2d;

          if (!warning_seen)
            g_warning ("Skipping layer %d of your pipeline consisting of "
                       "a sliced texture (unsuported for multi texturing)",
                       state->i);
          warning_seen = TRUE;

          /* Note: currently only 2D textures can be sliced. */
          tex_2d = state->ctx->default_gl_texture_2d_tex;
          cogl_pipeline_set_layer_texture (pipeline, layer_index,
                                           COGL_TEXTURE (tex_2d));
          return TRUE;
        }
    }

#ifdef COGL_ENABLE_DEBUG
  /* If the texture can't be repeated with the GPU (e.g. because it has
   * waste or if using GL_TEXTURE_RECTANGLE_ARB) then if a texture matrix
   * is also in use we don't know if the result will end up trying
   * to texture from the waste area.
   *
   * Note: we check can_hardware_repeat() first since it's cheaper.
   *
   * Note: cases where the texture coordinates will require repeating
   * will be caught by later validation.
   */
  if (!_cogl_texture_can_hardware_repeat (texture) &&
      _cogl_pipeline_layer_has_user_matrix (pipeline, layer_index))
    {
      static CoglBool warning_seen = FALSE;
      if (!warning_seen)
        g_warning ("layer %d of your pipeline uses a custom "
                   "texture matrix but because the texture doesn't "
                   "support hardware repeating you may see artefacts "
                   "due to sampling beyond the texture's bounds.",
                   state->i);
      warning_seen = TRUE;
    }
#endif

  return TRUE;
}