static CoglBool
_cogl_pipeline_progend_fixed_arbfp_start (CoglPipeline *pipeline)
{
  _COGL_GET_CONTEXT (ctx, FALSE);

  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED)))
    return FALSE;

  if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_FIXED))
    return FALSE;

  /* Vertex snippets are only supported in the GLSL fragend */
  if (_cogl_pipeline_has_vertex_snippets (pipeline))
    return FALSE;

  /* Validate that we can handle the fragment state using ARBfp
   */

  if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_ARBFP))
    return FALSE;

  /* Fragment snippets are only supported in the GLSL fragend */
  if (_cogl_pipeline_has_fragment_snippets (pipeline))
    return FALSE;

  /* The ARBfp progend can't handle the per-vertex point size
   * attribute */
  if (cogl_pipeline_get_per_vertex_point_size (pipeline))
    return FALSE;

  return TRUE;
}
Example #2
0
void
_cogl_buffer_initialize (CoglBuffer *buffer,
                         CoglContext *ctx,
                         size_t size,
                         CoglBufferBindTarget default_target,
                         CoglBufferUsageHint usage_hint,
                         CoglBufferUpdateHint update_hint)
{
  CoglBool use_malloc = FALSE;

  buffer->context = ctx;
  buffer->flags = COGL_BUFFER_FLAG_NONE;
  buffer->store_created = FALSE;
  buffer->size = size;
  buffer->last_target = default_target;
  buffer->usage_hint = usage_hint;
  buffer->update_hint = update_hint;
  buffer->data = NULL;
  buffer->immutable_ref = 0;

  if (default_target == COGL_BUFFER_BIND_TARGET_PIXEL_PACK ||
      default_target == COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK)
    {
      if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_PBOS))
        use_malloc = TRUE;
    }
  else if (default_target == COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER ||
           default_target == COGL_BUFFER_BIND_TARGET_INDEX_BUFFER)
    {
      if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_VBOS))
        use_malloc = TRUE;
    }

  if (use_malloc)
    {
      buffer->vtable.map_range = malloc_map_range;
      buffer->vtable.unmap = malloc_unmap;
      buffer->vtable.set_data = malloc_set_data;

      buffer->data = g_malloc (size);
    }
  else
    {
      buffer->vtable.map_range = ctx->driver_vtable->buffer_map_range;
      buffer->vtable.unmap = ctx->driver_vtable->buffer_unmap;
      buffer->vtable.set_data = ctx->driver_vtable->buffer_set_data;

      ctx->driver_vtable->buffer_create (buffer);

      buffer->flags |= COGL_BUFFER_FLAG_BUFFER_OBJECT;
    }
}
Example #3
0
/* NB: The reason we require the width, height and format to be passed
 * even though they may seem redundant is because GLES 1/2 don't
 * provide a way to query these properties. */
CoglTexture2D *
_cogl_egl_texture_2d_new_from_image (CoglContext *ctx,
                                     int width,
                                     int height,
                                     CoglPixelFormat format,
                                     EGLImageKHR image,
                                     CoglError **error)
{
  _COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints &
                            COGL_RENDERER_CONSTRAINT_USES_EGL,
                            NULL);

  _COGL_RETURN_VAL_IF_FAIL (_cogl_has_private_feature
                            (ctx,
                             COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE),
                            NULL);

  if (ctx->driver_vtable->egl_texture_2d_new_from_image)
    return ctx->driver_vtable->egl_texture_2d_new_from_image (ctx,
                                                              width,
                                                              height,
                                                              format,
                                                              image,
                                                              error);
  else
    {
      _cogl_set_error (error,
                       COGL_SYSTEM_ERROR,
                       COGL_SYSTEM_ERROR_UNSUPPORTED,
                       "Creating 2D textures from EGL images is not "
                       "supported by the current driver");
      return NULL;
    }
}
Example #4
0
/* NB: The reason we require the width, height and format to be passed
 * even though they may seem redundant is because GLES 1/2 don't
 * provide a way to query these properties. */
CoglTexture2D *
_cogl_egl_texture_2d_new_from_image (CoglContext *ctx,
                                     int width,
                                     int height,
                                     CoglPixelFormat format,
                                     EGLImageKHR image,
                                     CoglError **error)
{
    CoglTextureLoader *loader;

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

    _COGL_RETURN_VAL_IF_FAIL (_cogl_has_private_feature
                              (ctx,
                               COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE),
                              NULL);

    loader = _cogl_texture_create_loader ();
    loader->src_type = COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE;
    loader->src.egl_image.image = image;
    loader->src.egl_image.width = width;
    loader->src.egl_image.height = height;
    loader->src.egl_image.format = format;

    return _cogl_texture_2d_create_base (ctx, width, height, format, loader);
}
Example #5
0
static gboolean
toggle_texcood_attribute_enabled_cb (int bit_num, void *user_data)
{
  ForeachChangedBitState *state = user_data;
  CoglContext *context = state->context;

  _COGL_RETURN_VAL_IF_FAIL (_cogl_has_private_feature
                            (context, COGL_PRIVATE_FEATURE_GL_FIXED),
                            FALSE);

#ifdef HAVE_COGL_GL
  {
    gboolean enabled = _cogl_bitmask_get (state->new_bits, bit_num);

    GE( context, glClientActiveTexture (GL_TEXTURE0 + bit_num) );

    if (enabled)
      GE( context, glEnableClientState (GL_TEXTURE_COORD_ARRAY) );
    else
      GE( context, glDisableClientState (GL_TEXTURE_COORD_ARRAY) );
  }
#endif

  return TRUE;
}
Example #6
0
void
_cogl_texture_gl_maybe_update_max_level (CoglTexture *texture,
                                         int max_level)
{
  /* This isn't supported on GLES */
#ifdef HAVE_COGL_GL
  CoglContext *ctx = texture->context;

  if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_TEXTURE_MAX_LEVEL) &&
      texture->max_level < max_level)
    {
      CoglContext *ctx = texture->context;
      GLuint gl_handle;
      GLenum gl_target;

      cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target);

      texture->max_level = max_level;

      _cogl_bind_gl_texture_transient (gl_target,
                                       gl_handle,
                                       _cogl_texture_is_foreign (texture));

      GE( ctx, glTexParameteri (gl_target,
                                GL_TEXTURE_MAX_LEVEL, texture->max_level));
    }
#endif /* HAVE_COGL_GL */
}
static CoglBool
_cogl_pipeline_progend_fixed_start (CoglPipeline *pipeline)
{
  _COGL_GET_CONTEXT (ctx, FALSE);

  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED)))
    return FALSE;

  if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_FIXED))
    return FALSE;

  /* Vertex snippets are only supported in the GLSL fragend */
  if (_cogl_pipeline_has_vertex_snippets (pipeline))
    return FALSE;

  /* Fragment snippets are only supported in the GLSL fragend */
  if (_cogl_pipeline_has_fragment_snippets (pipeline))
    return FALSE;

  /* If there is a user program then the appropriate backend for that
   * language should handle it. */
  if (cogl_pipeline_get_user_program (pipeline))
    return FALSE;

  /* The fixed progend can't handle the per-vertex point size
   * attribute */
  if (cogl_pipeline_get_per_vertex_point_size (pipeline))
    return FALSE;

  return TRUE;
}
Example #8
0
static CoglBitmap *
prepare_bitmap_alignment_for_upload (CoglContext *ctx,
                                     CoglBitmap *src_bmp,
                                     CoglError **error)
{
  CoglPixelFormat format = cogl_bitmap_get_format (src_bmp);
  int bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
  int src_rowstride = cogl_bitmap_get_rowstride (src_bmp);
  int width = cogl_bitmap_get_width (src_bmp);
  int alignment = 1;

  if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_UNPACK_SUBIMAGE) ||
      src_rowstride == 0)
    return cogl_object_ref (src_bmp);

  /* Work out the alignment of the source rowstride */
  alignment = 1 << (_cogl_util_ffs (src_rowstride) - 1);
  alignment = MIN (alignment, 8);

  /* If the aligned data equals the rowstride then we can upload from
     the bitmap directly using GL_UNPACK_ALIGNMENT */
  if (((width * bpp + alignment - 1) & ~(alignment - 1)) == src_rowstride)
    return cogl_object_ref (src_bmp);
  /* Otherwise we need to copy the bitmap to pack the alignment
     because GLES has no GL_ROW_LENGTH */
  else
    return _cogl_bitmap_copy (src_bmp, error);
}
Example #9
0
static CoglBool
_cogl_winsys_texture_pixmap_x11_create (CoglTexturePixmapX11 *tex_pixmap)
{
  CoglTexture *tex = COGL_TEXTURE (tex_pixmap);
  CoglContext *ctx = tex->context;
  CoglTexturePixmapEGL *egl_tex_pixmap;
  EGLint attribs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
  CoglPixelFormat texture_format;
  CoglRendererEGL *egl_renderer;

  egl_renderer = ctx->display->renderer->winsys;

  if (!(egl_renderer->private_features &
        COGL_EGL_WINSYS_FEATURE_EGL_IMAGE_FROM_X11_PIXMAP) ||
      !_cogl_has_private_feature
      (ctx, COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE))
    {
      tex_pixmap->winsys = NULL;
      return FALSE;
    }

  egl_tex_pixmap = g_new0 (CoglTexturePixmapEGL, 1);

  egl_tex_pixmap->image =
    _cogl_egl_create_image (ctx,
                            EGL_NATIVE_PIXMAP_KHR,
                            (EGLClientBuffer)tex_pixmap->pixmap,
                            attribs);
  if (egl_tex_pixmap->image == EGL_NO_IMAGE_KHR)
    {
      g_free (egl_tex_pixmap);
      return FALSE;
    }

  texture_format = (tex_pixmap->depth >= 32 ?
                    COGL_PIXEL_FORMAT_RGBA_8888_PRE :
                    COGL_PIXEL_FORMAT_RGB_888);

  egl_tex_pixmap->texture = COGL_TEXTURE (
    cogl_egl_texture_2d_new_from_image (ctx,
                                        tex->width,
                                        tex->height,
                                        texture_format,
                                        egl_tex_pixmap->image,
                                        NULL));

  tex_pixmap->winsys = egl_tex_pixmap;

  return TRUE;
}
Example #10
0
static void
_cogl_texture_3d_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags)
{
  CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex);
  CoglContext *ctx = tex->context;

  /* Only update if the mipmaps are dirty */
  if ((flags & COGL_TEXTURE_NEEDS_MIPMAP) &&
      tex_3d->auto_mipmap && tex_3d->mipmaps_dirty)
    {
      /* glGenerateMipmap is defined in the FBO extension. If it's not
         available we'll fallback to temporarily enabling
         GL_GENERATE_MIPMAP and reuploading the first pixel */
      if (cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
        _cogl_texture_gl_generate_mipmaps (tex);
#if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
      else if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_FIXED))
        {
          _cogl_bind_gl_texture_transient (GL_TEXTURE_3D,
                                           tex_3d->gl_texture,
                                           FALSE);

          GE( ctx, glTexParameteri (GL_TEXTURE_3D,
                                    GL_GENERATE_MIPMAP,
                                    GL_TRUE) );
          GE( ctx, glTexSubImage3D (GL_TEXTURE_3D,
                                    0, /* level */
                                    0, /* xoffset */
                                    0, /* yoffset */
                                    0, /* zoffset */
                                    1, /* width */
                                    1, /* height */
                                    1, /* depth */
                                    tex_3d->first_pixel.gl_format,
                                    tex_3d->first_pixel.gl_type,
                                    tex_3d->first_pixel.data) );
          GE( ctx, glTexParameteri (GL_TEXTURE_3D,
                                    GL_GENERATE_MIPMAP,
                                    GL_FALSE) );
        }
#endif

      tex_3d->mipmaps_dirty = FALSE;
    }
}
Example #11
0
static gboolean
toggle_builtin_attribute_enabled_cb (int bit_num, void *user_data)
{
  ForeachChangedBitState *state = user_data;
  CoglContext *context = state->context;

  _COGL_RETURN_VAL_IF_FAIL (_cogl_has_private_feature
                            (context, COGL_PRIVATE_FEATURE_GL_FIXED),
                            FALSE);

#ifdef HAVE_COGL_GL
  {
    gboolean enabled = _cogl_bitmask_get (state->new_bits, bit_num);
    GLenum cap;

    switch (bit_num)
      {
      case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
        cap = GL_COLOR_ARRAY;
        break;
      case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
        cap = GL_VERTEX_ARRAY;
        break;
      case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY:
        cap = GL_NORMAL_ARRAY;
        break;
      default:
        g_assert_not_reached ();
      }
    if (enabled)
      GE (context, glEnableClientState (cap));
    else
      GE (context, glDisableClientState (cap));
  }
#endif

  return TRUE;
}
Example #12
0
static void
_cogl_matrix_flush_to_gl_builtin (CoglContext *ctx,
                                  CoglBool is_identity,
                                  CoglMatrix *matrix,
                                  CoglMatrixMode mode)
{
  g_assert (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_FIXED));

#if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
  if (ctx->flushed_matrix_mode != mode)
    {
      GLenum gl_mode = 0;

      switch (mode)
        {
        case COGL_MATRIX_MODELVIEW:
          gl_mode = GL_MODELVIEW;
          break;

        case COGL_MATRIX_PROJECTION:
          gl_mode = GL_PROJECTION;
          break;

        case COGL_MATRIX_TEXTURE:
          gl_mode = GL_TEXTURE;
          break;
        }

      GE (ctx, glMatrixMode (gl_mode));
      ctx->flushed_matrix_mode = mode;
    }

  if (is_identity)
    GE (ctx, glLoadIdentity ());
  else
    GE (ctx, glLoadMatrixf (cogl_matrix_get_array (matrix)));
#endif
}
Example #13
0
static void
prep_gl_for_pixels_upload_full (CoglContext *ctx,
                                int pixels_rowstride,
                                int pixels_src_x,
                                int pixels_src_y,
                                int pixels_bpp)
{
  if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_UNPACK_SUBIMAGE))
    {
      GE( ctx, glPixelStorei (GL_UNPACK_ROW_LENGTH,
                              pixels_rowstride / pixels_bpp) );

      GE( ctx, glPixelStorei (GL_UNPACK_SKIP_PIXELS, pixels_src_x) );
      GE( ctx, glPixelStorei (GL_UNPACK_SKIP_ROWS, pixels_src_y) );
    }
  else
    {
      g_assert (pixels_src_x == 0);
      g_assert (pixels_src_y == 0);
    }

  _cogl_texture_gl_prep_alignment_for_pixels_upload (ctx, pixels_rowstride);
}
Example #14
0
void
_cogl_matrix_entry_flush_to_gl_builtins (CoglContext *ctx,
                                         CoglMatrixEntry *entry,
                                         CoglMatrixMode mode,
                                         CoglFramebuffer *framebuffer,
                                         CoglBool disable_flip)
{
  g_assert (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_FIXED));

#if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
  {
    CoglBool needs_flip;
    CoglMatrixEntryCache *cache;

    if (mode == COGL_MATRIX_PROJECTION)
      {
        /* Because Cogl defines texture coordinates to have a top left
         * origin and because offscreen framebuffers may be used for
         * rendering to textures we always render upside down to
         * offscreen buffers. Also for some backends we need to render
         * onscreen buffers upside-down too.
         */
        if (disable_flip)
          needs_flip = FALSE;
        else
          needs_flip = cogl_is_offscreen (framebuffer);

        cache = &ctx->builtin_flushed_projection;
      }
    else
      {
        needs_flip = FALSE;

        if (mode == COGL_MATRIX_MODELVIEW)
          cache = &ctx->builtin_flushed_modelview;
        else
          cache = NULL;
      }

    /* We don't need to do anything if the state is the same */
    if (!cache ||
        _cogl_matrix_entry_cache_maybe_update (cache, entry, needs_flip))
      {
        CoglBool is_identity;
        CoglMatrix matrix;

        if (entry->op == COGL_MATRIX_OP_LOAD_IDENTITY)
          is_identity = TRUE;
        else
          {
            is_identity = FALSE;
            cogl_matrix_entry_get (entry, &matrix);
          }

        if (needs_flip)
          {
            CoglMatrix flipped_matrix;

            cogl_matrix_multiply (&flipped_matrix,
                                  &ctx->y_flip_matrix,
                                  is_identity ?
                                  &ctx->identity_matrix :
                                  &matrix);

            _cogl_matrix_flush_to_gl_builtin (ctx,
                                              /* not identity */
                                              FALSE,
                                              &flipped_matrix,
                                              mode);
          }
        else
          {
            _cogl_matrix_flush_to_gl_builtin (ctx,
                                              is_identity,
                                              &matrix,
                                              mode);
          }
      }
  }
#endif
}
Example #15
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,
                  CoglError **error)
{
  CoglContext *context;
  uint8_t white_pixel[] = { 0xff, 0xff, 0xff, 0xff };
  CoglBitmap *white_pixel_bitmap;
  const CoglWinsysVtable *winsys;
  int i;
  CoglError *internal_error = NULL;

  _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.
   */
  _cogl_context = context;

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

  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);
      cogl_object_unref(renderer);
    }
  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;

  /* Again this is duplicated data, but it convenient to be able
   * access these from the context. */
  context->driver_vtable = display->renderer->driver_vtable;
  context->texture_driver = display->renderer->texture_driver;

  for (i = 0; i < G_N_ELEMENTS (context->private_features); i++)
    context->private_features[i] |= display->renderer->private_features[i];

  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);

  /* XXX: ONGOING BUG: Intel viewport scissor
   *
   * Intel gen6 drivers don't currently correctly handle offset
   * viewports, since primitives aren't clipped within the bounds of
   * the viewport.  To workaround this we push our own clip for the
   * viewport that will use scissoring to ensure we clip as expected.
   *
   * TODO: file a bug upstream!
   */
  if (context->gpu.driver_package == COGL_GPU_INFO_DRIVER_PACKAGE_MESA &&
      context->gpu.architecture == COGL_GPU_INFO_ARCHITECTURE_SANDYBRIDGE &&
      !getenv ("COGL_DISABLE_INTEL_VIEWPORT_SCISSORT_WORKAROUND"))
    context->needs_viewport_scissor_workaround = TRUE;
  else
    context->needs_viewport_scissor_workaround = FALSE;

  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;

  context->legacy_backface_culling_enabled = FALSE;

  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));

  if (_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_ANY_GL))
    {
      /* 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->legacy_fog_state.enabled = FALSE;

  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->codegen_boilerplate_buffer = g_string_new ("");
  context->source_stack = NULL;

  context->legacy_state_set = 0;

  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;

  context->swap_callback_closures =
    g_hash_table_new (g_direct_hash, g_direct_equal);

  _cogl_list_init (&context->onscreen_events_queue);
  _cogl_list_init (&context->onscreen_dirty_queue);

  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_with_color_attrib = 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_GLSL;
  context->current_vertex_program_type = COGL_PIPELINE_PROGRAM_TYPE_GLSL;
  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->legacy_depth_test_enabled = FALSE;

  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->current_path = NULL;
  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;

#ifdef HAVE_COGL_GL
  if (_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_ALPHA_TEST))
    /* 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));

  if ((context->driver == COGL_DRIVER_GL3))
    {
      GLuint vertex_array;

      /* In a forward compatible context, GL 3 doesn't support rendering
       * using the default vertex array object. Cogl doesn't use vertex
       * array objects yet so for now we just create a dummy array
       * object that we will use as our own default object. Eventually
       * it could be good to attach the vertex array objects to
       * CoglPrimitives */
      context->glGenVertexArrays (1, &vertex_array);
      context->glBindVertexArray (vertex_array);
    }
#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);

  /* Create default textures used for fall backs */
  context->default_gl_texture_2d_tex =
    cogl_texture_2d_new_from_data (context,
                                   1, 1,
                                   COGL_PIXEL_FORMAT_RGBA_8888_PRE,
                                   0, /* rowstride */
                                   white_pixel,
                                   NULL); /* abort on error */

  /* If 3D or rectangle textures aren't supported then these will
   * return errors that we can simply ignore. */
  internal_error = NULL;
  context->default_gl_texture_3d_tex =
    cogl_texture_3d_new_from_data (context,
                                   1, 1, 1, /* width, height, depth */
                                   COGL_PIXEL_FORMAT_RGBA_8888_PRE,
                                   0, /* rowstride */
                                   0, /* image stride */
                                   white_pixel,
                                   &internal_error);
  if (internal_error)
    cogl_error_free (internal_error);

  /* TODO: add cogl_texture_rectangle_new_from_data() */
  white_pixel_bitmap =
    cogl_bitmap_new_for_data (context,
                              1, 1, /* width/height */
                              COGL_PIXEL_FORMAT_RGBA_8888_PRE,
                              4, /* rowstride */
                              white_pixel);

  internal_error = NULL;
  context->default_gl_texture_rect_tex =
    cogl_texture_rectangle_new_from_bitmap (white_pixel_bitmap);

  /* XXX: we need to allocate the texture now because the white_pixel
   * data is on the stack */
  cogl_texture_allocate (COGL_TEXTURE (context->default_gl_texture_rect_tex),
                         &internal_error);
  if (internal_error)
    cogl_error_free (internal_error);

  cogl_object_unref (white_pixel_bitmap);

  cogl_push_source (context->opaque_color_pipeline);

  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 GL3 or GLES2 because point
     sprites are handled using a builtin varying in the shader. */
  if (_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_GL_FIXED) &&
      cogl_has_feature (context, COGL_FEATURE_ID_POINT_SPRITE))
    GE (context, glEnable (GL_POINT_SPRITE));

  _cogl_list_init (&context->fences);

  return context;
}
Example #16
0
static gboolean
allocate_from_gl_foreign (CoglTexture2D *tex_2d,
                          CoglTextureLoader *loader,
                          CoglError **error)
{
  CoglTexture *tex = COGL_TEXTURE (tex_2d);
  CoglContext *ctx = tex->context;
  CoglPixelFormat format = loader->src.gl_foreign.format;
  GLint gl_compressed = GL_FALSE;
  GLenum gl_int_format = 0;

  if (!ctx->texture_driver->allows_foreign_gl_target (ctx, GL_TEXTURE_2D))
    {
      _cogl_set_error (error,
                       COGL_SYSTEM_ERROR,
                       COGL_SYSTEM_ERROR_UNSUPPORTED,
                       "Foreign GL_TEXTURE_2D textures are not "
                       "supported by your system");
      return FALSE;
    }

  /* Make sure binding succeeds */
  _cogl_gl_util_clear_gl_errors (ctx);

  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
                                   loader->src.gl_foreign.gl_handle, TRUE);
  if (_cogl_gl_util_get_error (ctx) != GL_NO_ERROR)
    {
      _cogl_set_error (error,
                       COGL_SYSTEM_ERROR,
                       COGL_SYSTEM_ERROR_UNSUPPORTED,
                       "Failed to bind foreign GL_TEXTURE_2D texture");
      return FALSE;
    }

  /* Obtain texture parameters
     (only level 0 we are interested in) */

#ifdef HAVE_COGL_GL
  if (_cogl_has_private_feature
      (ctx, COGL_PRIVATE_FEATURE_QUERY_TEXTURE_PARAMETERS))
    {
      GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_2D, 0,
                                         GL_TEXTURE_COMPRESSED,
                                         &gl_compressed) );

      {
        GLint val;

        GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_2D, 0,
                                           GL_TEXTURE_INTERNAL_FORMAT,
                                           &val) );

        gl_int_format = val;
      }

      /* If we can query GL for the actual pixel format then we'll ignore
         the passed in format and use that. */
      if (!ctx->driver_vtable->pixel_format_from_gl_internal (ctx,
                                                              gl_int_format,
                                                              &format))
        {
          _cogl_set_error (error,
                           COGL_SYSTEM_ERROR,
                           COGL_SYSTEM_ERROR_UNSUPPORTED,
                           "Unsupported internal format for foreign texture");
          return FALSE;
        }
    }
  else
#endif
    {
      /* Otherwise we'll assume we can derive the GL format from the
         passed in format */
      ctx->driver_vtable->pixel_format_to_gl (ctx,
                                              format,
                                              &gl_int_format,
                                              NULL,
                                              NULL);
    }

  /* Compressed texture images not supported */
  if (gl_compressed == GL_TRUE)
    {
      _cogl_set_error (error,
                       COGL_SYSTEM_ERROR,
                       COGL_SYSTEM_ERROR_UNSUPPORTED,
                       "Compressed foreign textures aren't currently supported");
      return FALSE;
    }

  /* Note: previously this code would query the texture object for
     whether it has GL_GENERATE_MIPMAP enabled to determine whether to
     auto-generate the mipmap. This doesn't make much sense any more
     since Cogl switch to using glGenerateMipmap. Ideally I think
     cogl_texture_2d_gl_new_from_foreign should take a flags parameter so
     that the application can decide whether it wants
     auto-mipmapping. To be compatible with existing code, Cogl now
     disables its own auto-mipmapping but leaves the value of
     GL_GENERATE_MIPMAP alone so that it would still work but without
     the dirtiness tracking that Cogl would do. */

  _cogl_texture_2d_set_auto_mipmap (COGL_TEXTURE (tex_2d), FALSE);

  /* Setup bitmap info */
  tex_2d->is_foreign = TRUE;
  tex_2d->mipmaps_dirty = TRUE;

  tex_2d->gl_texture = loader->src.gl_foreign.gl_handle;
  tex_2d->gl_internal_format = gl_int_format;

  /* Unknown filter */
  tex_2d->gl_legacy_texobj_min_filter = GL_FALSE;
  tex_2d->gl_legacy_texobj_mag_filter = GL_FALSE;

  tex_2d->internal_format = format;

  _cogl_texture_set_allocated (tex,
                               format,
                               loader->src.gl_foreign.width,
                               loader->src.gl_foreign.height);
  return TRUE;
}
Example #17
0
static CoglBool
allocate_from_gl_foreign (CoglTextureRectangle *tex_rect,
                          CoglTextureLoader *loader,
                          CoglError **error)
{
  CoglTexture *tex = COGL_TEXTURE (tex_rect);
  CoglContext *ctx = tex->context;
  CoglPixelFormat format = loader->src.gl_foreign.format;
  GLenum gl_error = 0;
  GLint gl_compressed = GL_FALSE;
  GLenum gl_int_format = 0;

  if (!ctx->texture_driver->allows_foreign_gl_target (ctx,
                                                      GL_TEXTURE_RECTANGLE_ARB))
    {
      _cogl_set_error (error,
                       COGL_SYSTEM_ERROR,
                       COGL_SYSTEM_ERROR_UNSUPPORTED,
                       "Foreign GL_TEXTURE_RECTANGLE textures are not "
                       "supported by your system");
      return FALSE;
    }

  /* Make sure binding succeeds */
  while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
    ;

  _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB,
                                   loader->src.gl_foreign.gl_handle, TRUE);
  if (ctx->glGetError () != GL_NO_ERROR)
    {
      _cogl_set_error (error,
                       COGL_SYSTEM_ERROR,
                       COGL_SYSTEM_ERROR_UNSUPPORTED,
                       "Failed to bind foreign GL_TEXTURE_RECTANGLE texture");
      return FALSE;
    }

  /* Obtain texture parameters */

#ifdef HAVE_COGL_GL
  if (_cogl_has_private_feature
      (ctx, COGL_PRIVATE_FEATURE_QUERY_TEXTURE_PARAMETERS))
    {
      GLint val;

      GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_RECTANGLE_ARB, 0,
                                         GL_TEXTURE_COMPRESSED,
                                         &gl_compressed) );

      GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_RECTANGLE_ARB, 0,
                                         GL_TEXTURE_INTERNAL_FORMAT,
                                         &val) );

      gl_int_format = val;

      /* If we can query GL for the actual pixel format then we'll ignore
         the passed in format and use that. */
      if (!ctx->driver_vtable->pixel_format_from_gl_internal (ctx,
                                                              gl_int_format,
                                                              &format))
        {
          _cogl_set_error (error,
                           COGL_SYSTEM_ERROR,
                           COGL_SYSTEM_ERROR_UNSUPPORTED,
                           "Unsupported internal format for foreign texture");
          return FALSE;
        }
    }
  else
#endif
    {
      /* Otherwise we'll assume we can derive the GL format from the
         passed in format */
      ctx->driver_vtable->pixel_format_to_gl (ctx,
                                              format,
                                              &gl_int_format,
                                              NULL,
                                              NULL);
    }

  /* Compressed texture images not supported */
  if (gl_compressed == GL_TRUE)
    {
      _cogl_set_error (error,
                       COGL_SYSTEM_ERROR,
                       COGL_SYSTEM_ERROR_UNSUPPORTED,
                       "Compressed foreign textures aren't currently supported");
      return FALSE;
    }

  /* Setup bitmap info */
  tex_rect->is_foreign = TRUE;

  tex_rect->gl_texture = loader->src.gl_foreign.gl_handle;
  tex_rect->gl_format = gl_int_format;

  /* Unknown filter */
  tex_rect->gl_legacy_texobj_min_filter = GL_FALSE;
  tex_rect->gl_legacy_texobj_mag_filter = GL_FALSE;

  tex_rect->internal_format = format;

  _cogl_texture_set_allocated (COGL_TEXTURE (tex_rect),
                               format,
                               loader->src.gl_foreign.width,
                               loader->src.gl_foreign.height);

  return TRUE;
}
Example #18
0
static CoglBool
validate_blend_statements (CoglBlendStringStatement *statements,
                           int n_statements,
                           CoglError **error)
{
  int i, j;
  const char *error_string;
  CoglBlendStringError detail = COGL_BLEND_STRING_ERROR_INVALID_ERROR;

  _COGL_GET_CONTEXT (ctx, 0);

  if (n_statements == 2 &&
      !ctx->glBlendEquationSeparate &&
      statements[0].function->type != statements[1].function->type)
    {
      error_string = "Separate blend functions for the RGB an A "
        "channels isn't supported by the driver";
      detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR;
      goto error;
    }

  for (i = 0; i < n_statements; i++)
    for (j = 0; j < statements[i].function->argc; j++)
      {
        CoglBlendStringArgument *arg = &statements[i].args[j];

        if (arg->source.is_zero)
          continue;

        if ((j == 0 &&
             arg->source.info->type !=
             COGL_BLEND_STRING_COLOR_SOURCE_SRC_COLOR)
            || (j == 1 &&
                arg->source.info->type !=
                COGL_BLEND_STRING_COLOR_SOURCE_DST_COLOR))
          {
            error_string = "For blending you must always use SRC_COLOR "
                           "for arg0 and DST_COLOR for arg1";
            goto error;
          }

        if (!_cogl_has_private_feature (ctx,
                                        COGL_PRIVATE_FEATURE_BLEND_CONSTANT) &&
            arg->factor.is_color &&
            (arg->factor.source.info->type ==
             COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT))
          {
            error_string = "Driver doesn't support constant blend factors";
            detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR;
            goto error;
          }
      }

  return TRUE;

error:
  _cogl_set_error (error,
                   COGL_BLEND_STRING_ERROR,
                   detail,
                   "Invalid blend string: %s",
                   error_string);
  return FALSE;
}
Example #19
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);
}
Example #20
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 #21
0
static void
setup_legacy_buffered_attribute (CoglContext *ctx,
                                 CoglPipeline *pipeline,
                                 CoglAttribute *attribute,
                                 uint8_t *base)
{
  switch (attribute->name_state->name_id)
    {
    case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
      _cogl_bitmask_set (&ctx->enable_builtin_attributes_tmp,
                         COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY, TRUE);
      GE (ctx, glColorPointer (attribute->d.buffered.n_components,
                               attribute->d.buffered.type,
                               attribute->d.buffered.stride,
                               base + attribute->d.buffered.offset));
      break;
    case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY:
      _cogl_bitmask_set (&ctx->enable_builtin_attributes_tmp,
                         COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY, TRUE);
      GE (ctx, glNormalPointer (attribute->d.buffered.type,
                                attribute->d.buffered.stride,
                                base + attribute->d.buffered.offset));
      break;
    case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
      {
        int layer_number = attribute->name_state->layer_number;
        const CoglPipelineGetLayerFlags flags =
          COGL_PIPELINE_GET_LAYER_NO_CREATE;
        CoglPipelineLayer *layer =
          _cogl_pipeline_get_layer_with_flags (pipeline, layer_number, flags);

        if (layer)
          {
            int unit = _cogl_pipeline_layer_get_unit_index (layer);

            _cogl_bitmask_set (&ctx->enable_texcoord_attributes_tmp,
                               unit,
                               TRUE);

            GE (ctx, glClientActiveTexture (GL_TEXTURE0 + unit));
            GE (ctx, glTexCoordPointer (attribute->d.buffered.n_components,
                                        attribute->d.buffered.type,
                                        attribute->d.buffered.stride,
                                        base + attribute->d.buffered.offset));
          }
        break;
      }
    case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
      _cogl_bitmask_set (&ctx->enable_builtin_attributes_tmp,
                         COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY, TRUE);
      GE (ctx, glVertexPointer (attribute->d.buffered.n_components,
                                attribute->d.buffered.type,
                                attribute->d.buffered.stride,
                                base + attribute->d.buffered.offset));
      break;
    case COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY:
#ifdef COGL_PIPELINE_PROGEND_GLSL
      if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_PROGRAMMABLE))
        setup_generic_buffered_attribute (ctx, pipeline, attribute, base);
#endif
      break;
    default:
      g_warn_if_reached ();
    }
}
Example #22
0
static void
setup_legacy_const_attribute (CoglContext *ctx,
                              CoglPipeline *pipeline,
                              CoglAttribute *attribute)
{
#ifdef COGL_PIPELINE_PROGEND_GLSL
  if (attribute->name_state->name_id == COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY)
    {
      if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_PROGRAMMABLE))
        setup_generic_const_attribute (ctx, pipeline, attribute);
    }
  else
#endif
    {
      float vector[4] = { 0, 0, 0, 1 };
      float *boxed = attribute->d.constant.boxed.v.float_value;
      int n_components = attribute->d.constant.boxed.size;
      int i;

      for (i = 0; i < n_components; i++)
        vector[i] = boxed[i];

      switch (attribute->name_state->name_id)
        {
        case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
          GE (ctx, glColor4f (vector[0], vector[1], vector[2], vector[3]));
          break;
        case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY:
          GE (ctx, glNormal3f (vector[0], vector[1], vector[2]));
          break;
        case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
          {
            int layer_number = attribute->name_state->layer_number;
            const CoglPipelineGetLayerFlags flags =
              COGL_PIPELINE_GET_LAYER_NO_CREATE;
            CoglPipelineLayer *layer =
              _cogl_pipeline_get_layer_with_flags (pipeline,
                                                   layer_number,
                                                   flags);

            if (layer)
              {
                int unit = _cogl_pipeline_layer_get_unit_index (layer);

                GE (ctx, glClientActiveTexture (GL_TEXTURE0 + unit));

                GE (ctx, glMultiTexCoord4f (vector[0],
                                            vector[1],
                                            vector[2],
                                            vector[3]));
              }
            break;
          }
        case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
          GE (ctx, glVertex4f (vector[0], vector[1], vector[2], vector[3]));
          break;
        default:
          g_warn_if_reached ();
        }
    }
}
Example #23
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);
}
Example #24
0
void
_cogl_clip_stack_gl_flush (CoglClipStack *stack,
                           CoglFramebuffer *framebuffer)
{
  CoglContext *ctx = framebuffer->context;
  int has_clip_planes;
  CoglBool using_clip_planes = FALSE;
  CoglBool using_stencil_buffer = FALSE;
  int scissor_x0;
  int scissor_y0;
  int scissor_x1;
  int scissor_y1;
  CoglClipStack *entry;
  int scissor_y_start;

  /* If we have already flushed this state then we don't need to do
     anything */
  if (ctx->current_clip_stack_valid)
    {
      if (ctx->current_clip_stack == stack &&
          (ctx->needs_viewport_scissor_workaround == FALSE ||
           (framebuffer->viewport_age ==
            framebuffer->viewport_age_for_scissor_workaround &&
            ctx->viewport_scissor_workaround_framebuffer ==
            framebuffer)))
        return;

      _cogl_clip_stack_unref (ctx->current_clip_stack);
    }

  ctx->current_clip_stack_valid = TRUE;
  ctx->current_clip_stack = _cogl_clip_stack_ref (stack);

  has_clip_planes =
    _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES);

  if (has_clip_planes)
    disable_clip_planes (ctx);
  GE( ctx, glDisable (GL_STENCIL_TEST) );

  /* If the stack is empty then there's nothing else to do
   *
   * See comment below about ctx->needs_viewport_scissor_workaround
   */
  if (stack == NULL && !ctx->needs_viewport_scissor_workaround)
    {
      COGL_NOTE (CLIPPING, "Flushed empty clip stack");

      GE (ctx, glDisable (GL_SCISSOR_TEST));
      return;
    }

  /* Calculate the scissor rect first so that if we eventually have to
     clear the stencil buffer then the clear will be clipped to the
     intersection of all of the bounding boxes. This saves having to
     clear the whole stencil buffer */
  _cogl_clip_stack_get_bounds (stack,
                               &scissor_x0, &scissor_y0,
                               &scissor_x1, &scissor_y1);

  /* XXX: ONGOING BUG: Intel viewport scissor
   *
   * Intel gen6 drivers don't correctly handle offset viewports, since
   * primitives aren't clipped within the bounds of the viewport.  To
   * workaround this we push our own clip for the viewport that will
   * use scissoring to ensure we clip as expected.
   *
   * TODO: file a bug upstream!
   */
  if (ctx->needs_viewport_scissor_workaround)
    {
      _cogl_util_scissor_intersect (framebuffer->viewport_x,
                                    framebuffer->viewport_y,
                                    framebuffer->viewport_x +
                                      framebuffer->viewport_width,
                                    framebuffer->viewport_y +
                                      framebuffer->viewport_height,
                                    &scissor_x0, &scissor_y0,
                                    &scissor_x1, &scissor_y1);
      framebuffer->viewport_age_for_scissor_workaround =
        framebuffer->viewport_age;
      ctx->viewport_scissor_workaround_framebuffer =
        framebuffer;
    }

  /* Enable scissoring as soon as possible */
  if (scissor_x0 >= scissor_x1 || scissor_y0 >= scissor_y1)
    scissor_x0 = scissor_y0 = scissor_x1 = scissor_y1 = scissor_y_start = 0;
  else
    {
      /* We store the entry coordinates in Cogl coordinate space
       * but OpenGL requires the window origin to be the bottom
       * left so we may need to convert the incoming coordinates.
       *
       * NB: Cogl forces all offscreen rendering to be done upside
       * down so in this case no conversion is needed.
       */

      if (cogl_is_offscreen (framebuffer))
        scissor_y_start = scissor_y0;
      else
        {
          int framebuffer_height =
            cogl_framebuffer_get_height (framebuffer);

          scissor_y_start = framebuffer_height - scissor_y1;
        }
    }

  COGL_NOTE (CLIPPING, "Flushing scissor to (%i, %i, %i, %i)",
             scissor_x0, scissor_y0,
             scissor_x1, scissor_y1);

  GE (ctx, glEnable (GL_SCISSOR_TEST));
  GE (ctx, glScissor (scissor_x0, scissor_y_start,
                      scissor_x1 - scissor_x0,
                      scissor_y1 - scissor_y0));

  /* Add all of the entries. This will end up adding them in the
     reverse order that they were specified but as all of the clips
     are intersecting it should work out the same regardless of the
     order */
  for (entry = stack; entry; entry = entry->parent)
    {
      switch (entry->type)
        {
        case COGL_CLIP_STACK_PRIMITIVE:
            {
              CoglClipStackPrimitive *primitive_entry =
                (CoglClipStackPrimitive *) entry;

              COGL_NOTE (CLIPPING, "Adding stencil clip for primitive");

              add_stencil_clip_primitive (framebuffer,
                                          primitive_entry->matrix_entry,
                                          primitive_entry->primitive,
                                          primitive_entry->bounds_x1,
                                          primitive_entry->bounds_y1,
                                          primitive_entry->bounds_x2,
                                          primitive_entry->bounds_y2,
                                          using_stencil_buffer,
                                          TRUE);

              using_stencil_buffer = TRUE;
              break;
            }
        case COGL_CLIP_STACK_RECT:
            {
              CoglClipStackRect *rect = (CoglClipStackRect *) entry;

              /* We don't need to do anything extra if the clip for this
                 rectangle was entirely described by its scissor bounds */
              if (!rect->can_be_scissor)
                {
                  /* If we support clip planes and we haven't already used
                     them then use that instead */
                  if (has_clip_planes)
                    {
                      COGL_NOTE (CLIPPING,
                                 "Adding clip planes clip for rectangle");

                      set_clip_planes (framebuffer,
                                       rect->matrix_entry,
                                       rect->x0,
                                       rect->y0,
                                       rect->x1,
                                       rect->y1);
                      using_clip_planes = TRUE;
                      /* We can't use clip planes a second time */
                      has_clip_planes = FALSE;
                    }
                  else
                    {
                      COGL_NOTE (CLIPPING, "Adding stencil clip for rectangle");

                      add_stencil_clip_rectangle (framebuffer,
                                                  rect->matrix_entry,
                                                  rect->x0,
                                                  rect->y0,
                                                  rect->x1,
                                                  rect->y1,
                                                  !using_stencil_buffer);
                      using_stencil_buffer = TRUE;
                    }
                }
              break;
            }
        case COGL_CLIP_STACK_WINDOW_RECT:
          break;
          /* We don't need to do anything for window space rectangles because
           * their functionality is entirely implemented by the entry bounding
           * box */
        }
    }

  /* Enabling clip planes is delayed to now so that they won't affect
     setting up the stencil buffer */
  if (using_clip_planes)
    enable_clip_planes (ctx);
}