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; }
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; }
static CoglBool allocate_with_size (CoglTexture3D *tex_3d, CoglTextureLoader *loader, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_3d); CoglContext *ctx = tex->context; CoglPixelFormat internal_format; int width = loader->src.sized.width; int height = loader->src.sized.height; int depth = loader->src.sized.depth; GLenum gl_intformat; GLenum gl_format; GLenum gl_type; GLenum gl_texture; internal_format = _cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY); if (!_cogl_texture_3d_can_create (ctx, width, height, depth, 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_3D, internal_format); _cogl_bind_gl_texture_transient (GL_TEXTURE_3D, gl_texture, FALSE); /* Clear any GL errors */ _cogl_gl_util_clear_gl_errors (ctx); ctx->glTexImage3D (GL_TEXTURE_3D, 0, gl_intformat, width, height, depth, 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_3d->gl_texture = gl_texture; tex_3d->gl_format = gl_intformat; tex_3d->depth = depth; tex_3d->internal_format = internal_format; _cogl_texture_set_allocated (tex, internal_format, width, height); return TRUE; }
static CoglBool _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx, GLenum gl_target, GLuint gl_handle, CoglBool is_foreign, GLint height, GLint depth, CoglBitmap *source_bmp, GLint internal_gl_format, GLuint source_gl_format, GLuint source_gl_type, CoglError **error) { CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); int rowstride = cogl_bitmap_get_rowstride (source_bmp); int bmp_width = cogl_bitmap_get_width (source_bmp); int bmp_height = cogl_bitmap_get_height (source_bmp); uint8_t *data; GLenum gl_error; _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); /* If the rowstride or image height can't be specified with just GL_ALIGNMENT alone then we need to copy the bitmap because there is no GL_ROW_LENGTH */ if (rowstride / bpp != bmp_width || height != bmp_height / depth) { CoglBitmap *bmp; int image_height = bmp_height / depth; CoglPixelFormat source_bmp_format = cogl_bitmap_get_format (source_bmp); int i; _cogl_texture_driver_prep_gl_for_pixels_upload (ctx, bmp_width * bpp, bpp); /* Initialize the texture with empty data and then upload each image with a sub-region update */ /* Clear any GL errors */ while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) ; ctx->glTexImage3D (gl_target, 0, /* level */ internal_gl_format, bmp_width, height, depth, 0, source_gl_format, source_gl_type, NULL); if (_cogl_gl_util_catch_out_of_memory (ctx, error)) return FALSE; bmp = _cogl_bitmap_new_with_malloc_buffer (ctx, bmp_width, height, source_bmp_format, error); if (!bmp) return FALSE; for (i = 0; i < depth; i++) { if (!_cogl_bitmap_copy_subregion (source_bmp, bmp, 0, image_height * i, 0, 0, bmp_width, height, error)) { cogl_object_unref (bmp); return FALSE; } data = _cogl_bitmap_gl_bind (bmp, COGL_BUFFER_ACCESS_READ, 0, error); if (!data) { cogl_object_unref (bmp); return FALSE; } /* Clear any GL errors */ while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) ; ctx->glTexSubImage3D (gl_target, 0, /* level */ 0, /* xoffset */ 0, /* yoffset */ i, /* zoffset */ bmp_width, /* width */ height, /* height */ 1, /* depth */ source_gl_format, source_gl_type, data); if (_cogl_gl_util_catch_out_of_memory (ctx, error)) { cogl_object_unref (bmp); _cogl_bitmap_gl_unbind (bmp); return FALSE; } _cogl_bitmap_gl_unbind (bmp); } cogl_object_unref (bmp); } else { data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0, error); if (!data) return FALSE; _cogl_texture_driver_prep_gl_for_pixels_upload (ctx, rowstride, bpp); /* Clear any GL errors */ while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) ; ctx->glTexImage3D (gl_target, 0, /* level */ internal_gl_format, bmp_width, height, depth, 0, source_gl_format, source_gl_type, data); if (_cogl_gl_util_catch_out_of_memory (ctx, error)) { _cogl_bitmap_gl_unbind (source_bmp); return FALSE; } _cogl_bitmap_gl_unbind (source_bmp); } return TRUE; }
static CoglBool _cogl_texture_driver_upload_to_gl (CoglContext *ctx, GLenum gl_target, GLuint gl_handle, CoglBool is_foreign, CoglBitmap *source_bmp, GLint internal_gl_format, GLuint source_gl_format, GLuint source_gl_type, CoglError **error) { CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); int rowstride; int bmp_width = cogl_bitmap_get_width (source_bmp); int bmp_height = cogl_bitmap_get_height (source_bmp); CoglBitmap *bmp; uint8_t *data; GLenum gl_error; CoglError *internal_error = NULL; CoglBool status = TRUE; bmp = prepare_bitmap_alignment_for_upload (ctx, source_bmp, error); if (!bmp) return FALSE; rowstride = cogl_bitmap_get_rowstride (bmp); /* Setup gl alignment to match rowstride and top-left corner */ _cogl_texture_driver_prep_gl_for_pixels_upload (ctx, rowstride, bpp); _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); data = _cogl_bitmap_gl_bind (bmp, COGL_BUFFER_ACCESS_READ, 0, /* hints */ &internal_error); /* NB: _cogl_bitmap_gl_bind() may return NULL when successful so we * have to explicitly check the cogl error pointer to catch * problems... */ if (internal_error) { cogl_object_unref (bmp); _cogl_propagate_error (error, internal_error); return FALSE; } /* Clear any GL errors */ while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) ; ctx->glTexImage2D (gl_target, 0, internal_gl_format, bmp_width, bmp_height, 0, source_gl_format, source_gl_type, data); if (_cogl_gl_util_catch_out_of_memory (ctx, error)) status = FALSE; _cogl_bitmap_gl_unbind (bmp); cogl_object_unref (bmp); return status; }
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; GLenum gl_error; 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 (!(ctx->private_feature_flags & 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 */ while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) ; _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; }
static gboolean allocate_with_size (CoglTexture2D *tex_2d, CoglTextureLoader *loader, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_2d); CoglPixelFormat internal_format; int width = loader->src.sized.width; int height = loader->src.sized.height; CoglContext *ctx = tex->context; GLenum gl_intformat; GLenum gl_format; GLenum gl_type; GLenum gl_texture; internal_format = _cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY); if (!_cogl_texture_2d_gl_can_create (ctx, width, height, internal_format)) { _cogl_set_error (error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_SIZE, "Failed to create texture 2d due to size/format" " constraints"); 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_2D, internal_format); tex_2d->gl_internal_format = gl_intformat; _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, gl_texture, tex_2d->is_foreign); /* Clear any GL errors */ _cogl_gl_util_clear_gl_errors (ctx); ctx->glTexImage2D (GL_TEXTURE_2D, 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_2d->gl_texture = gl_texture; tex_2d->gl_internal_format = gl_intformat; tex_2d->internal_format = internal_format; _cogl_texture_set_allocated (tex, internal_format, width, height); return TRUE; }
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; }
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; }