예제 #1
0
static CoglBool
recreate_store (CoglBuffer *buffer,
                CoglError **error)
{
  CoglContext *ctx = buffer->context;
  GLenum gl_target;
  GLenum gl_enum;
  GLenum gl_error;

  /* This assumes the buffer is already bound */

  gl_target = convert_bind_target_to_gl_target (buffer->last_target);
  gl_enum = update_hints_to_gl_enum (buffer);

  /* Clear any GL errors */
  while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
    ;

  ctx->glBufferData (gl_target,
                     buffer->size,
                     NULL,
                     gl_enum);

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

  buffer->store_created = TRUE;
  return TRUE;
}
예제 #2
0
CoglBool
_cogl_buffer_gl_set_data (CoglBuffer *buffer,
                          unsigned int offset,
                          const void *data,
                          unsigned int size,
                          CoglError **error)
{
  CoglBufferBindTarget target;
  GLenum gl_target;
  CoglContext *ctx = buffer->context;
  GLenum gl_error;
  CoglBool status = TRUE;
  CoglError *internal_error = NULL;

  target = buffer->last_target;

  _cogl_buffer_gl_bind (buffer, target, &internal_error);

  /* NB: _cogl_buffer_gl_bind() may return NULL in non-error
   * conditions so we have to explicity check internal_error
   * to see if an exception was thrown.
   */
  if (internal_error)
    {
      _cogl_propagate_error (error, internal_error);
      return FALSE;
    }

  gl_target = convert_bind_target_to_gl_target (target);

  /* Clear any GL errors */
  while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
    ;

  ctx->glBufferSubData (gl_target, offset, size, data);

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

  _cogl_buffer_gl_unbind (buffer);

  return status;
}
예제 #3
0
void *
_cogl_buffer_gl_map_range (CoglBuffer *buffer,
                           size_t offset,
                           size_t size,
                           CoglBufferAccess access,
                           CoglBufferMapHint hints,
                           CoglError **error)
{
  uint8_t *data;
  CoglBufferBindTarget target;
  GLenum gl_target;
  CoglContext *ctx = buffer->context;
  GLenum gl_error;

  if (((access & COGL_BUFFER_ACCESS_READ) &&
       !cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_READ)) ||
      ((access & COGL_BUFFER_ACCESS_WRITE) &&
       !cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE)))
    {
      _cogl_set_error (error,
                       COGL_SYSTEM_ERROR,
                       COGL_SYSTEM_ERROR_UNSUPPORTED,
                       "Tried to map a buffer with unsupported access mode");
      return NULL;
    }

  target = buffer->last_target;
  _cogl_buffer_bind_no_create (buffer, target);

  gl_target = convert_bind_target_to_gl_target (target);

  if ((hints & COGL_BUFFER_MAP_HINT_DISCARD_RANGE) &&
      offset == 0 && size >= buffer->size)
    hints |= COGL_BUFFER_MAP_HINT_DISCARD;

  /* If the map buffer range extension is supported then we will
   * always use it even if we are mapping the full range because the
   * normal mapping function doesn't support passing the discard
   * hints */
  if (ctx->glMapBufferRange)
    {
      GLbitfield gl_access = 0;
      CoglBool should_recreate_store = !buffer->store_created;

      if ((access & COGL_BUFFER_ACCESS_READ))
        gl_access |= GL_MAP_READ_BIT;
      if ((access & COGL_BUFFER_ACCESS_WRITE))
        gl_access |= GL_MAP_WRITE_BIT;

      if ((hints & COGL_BUFFER_MAP_HINT_DISCARD))
        {
          /* glMapBufferRange generates an error if you pass the
           * discard hint along with asking for read access. However
           * it can make sense to ask for both if write access is also
           * requested so that the application can immediately read
           * back what it just wrote. To work around the restriction
           * in GL we just recreate the buffer storage in that case
           * which is an alternative way to indicate that the buffer
           * contents can be discarded. */
          if ((access & COGL_BUFFER_ACCESS_READ))
            should_recreate_store = TRUE;
          else
            gl_access |= GL_MAP_INVALIDATE_BUFFER_BIT;
        }
      else if ((hints & COGL_BUFFER_MAP_HINT_DISCARD_RANGE) &&
               !(access & COGL_BUFFER_ACCESS_READ))
        gl_access |= GL_MAP_INVALIDATE_RANGE_BIT;

      if (should_recreate_store)
        {
          if (!recreate_store (buffer, error))
            {
              _cogl_buffer_gl_unbind (buffer);
              return NULL;
            }
        }

      /* Clear any GL errors */
      while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
        ;

      data = ctx->glMapBufferRange (gl_target,
                                    offset,
                                    size,
                                    gl_access);

      if (_cogl_gl_util_catch_out_of_memory (ctx, error))
        {
          _cogl_buffer_gl_unbind (buffer);
          return NULL;
        }

      _COGL_RETURN_VAL_IF_FAIL (data != NULL, NULL);
    }
  else
    {
      /* create an empty store if we don't have one yet. creating the store
       * lazily allows the user of the CoglBuffer to set a hint before the
       * store is created. */
      if (!buffer->store_created ||
          (hints & COGL_BUFFER_MAP_HINT_DISCARD))
        {
          if (!recreate_store (buffer, error))
            {
              _cogl_buffer_gl_unbind (buffer);
              return NULL;
            }
        }

      /* Clear any GL errors */
      while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
        ;

      data = ctx->glMapBuffer (gl_target,
                               _cogl_buffer_access_to_gl_enum (access));

      if (_cogl_gl_util_catch_out_of_memory (ctx, error))
        {
          _cogl_buffer_gl_unbind (buffer);
          return NULL;
        }

      _COGL_RETURN_VAL_IF_FAIL (data != NULL, NULL);

      data += offset;
    }

  if (data)
    buffer->flags |= COGL_BUFFER_FLAG_MAPPED;

  _cogl_buffer_gl_unbind (buffer);

  return data;
}
예제 #4
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;
}
예제 #5
0
static CoglBool
allocate_with_size (CoglTextureRectangle *tex_rect,
                    CoglTextureLoader *loader,
                    CoglError **error)
{
  CoglTexture *tex = COGL_TEXTURE (tex_rect);
  CoglContext *ctx = tex->context;
  CoglPixelFormat internal_format;
  int width = loader->src.sized.width;
  int height = loader->src.sized.height;
  GLenum gl_intformat;
  GLenum gl_format;
  GLenum gl_type;
  GLenum gl_error;
  GLenum gl_texture;

  internal_format =
    _cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY);

  if (!_cogl_texture_rectangle_can_create (ctx,
                                           width,
                                           height,
                                           internal_format,
                                           error))
    return FALSE;

  ctx->driver_vtable->pixel_format_to_gl (ctx,
                                          internal_format,
                                          &gl_intformat,
                                          &gl_format,
                                          &gl_type);

  gl_texture =
    ctx->texture_driver->gen (ctx,
                              GL_TEXTURE_RECTANGLE_ARB,
                              internal_format);
  _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB,
                                   gl_texture,
                                   tex_rect->is_foreign);

  /* Clear any GL errors */
  while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
    ;

  ctx->glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, gl_intformat,
                     width, height, 0, gl_format, gl_type, NULL);

  if (_cogl_gl_util_catch_out_of_memory (ctx, error))
    {
      GE( ctx, glDeleteTextures (1, &gl_texture) );
      return FALSE;
    }

  tex_rect->internal_format = internal_format;

  tex_rect->gl_texture = gl_texture;
  tex_rect->gl_format = gl_intformat;

  _cogl_texture_set_allocated (COGL_TEXTURE (tex_rect),
                               internal_format, width, height);

  return TRUE;
}