static gboolean allocate_custom_egl_image_external (CoglTexture2D *tex_2d, CoglTextureLoader *loader, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_2d); CoglContext *ctx = tex->context; CoglPixelFormat external_format; CoglPixelFormat internal_format; external_format = loader->src.egl_image_external.format; internal_format = _cogl_texture_determine_internal_format (tex, external_format); _cogl_gl_util_clear_gl_errors (ctx); GE (ctx, glActiveTexture (GL_TEXTURE0)); GE (ctx, glGenTextures (1, &tex_2d->gl_texture)); GE (ctx, glBindTexture (GL_TEXTURE_EXTERNAL_OES, tex_2d->gl_texture)); if (_cogl_gl_util_get_error (ctx) != GL_NO_ERROR) { _cogl_set_error (error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_BAD_PARAMETER, "Could not create a CoglTexture2D from a given " "EGLImage"); GE( ctx, glDeleteTextures (1, &tex_2d->gl_texture) ); return FALSE; } GE (ctx, glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); GE (ctx, glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); if (!loader->src.egl_image_external.alloc (tex_2d, tex_2d->egl_image_external.user_data, error)) { GE (ctx, glBindTexture (GL_TEXTURE_EXTERNAL_OES, 0)); GE (ctx, glDeleteTextures (1, &tex_2d->gl_texture)); return FALSE; } GE (ctx, glBindTexture (GL_TEXTURE_EXTERNAL_OES, 0)); tex_2d->internal_format = internal_format; tex_2d->gl_target = GL_TEXTURE_EXTERNAL_OES; return TRUE; }
static gboolean allocate_from_egl_image (CoglTexture2D *tex_2d, CoglTextureLoader *loader, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_2d); CoglContext *ctx = tex->context; CoglPixelFormat internal_format = loader->src.egl_image.format; tex_2d->gl_texture = ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format); _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, tex_2d->gl_texture, FALSE); _cogl_gl_util_clear_gl_errors (ctx); ctx->glEGLImageTargetTexture2D (GL_TEXTURE_2D, loader->src.egl_image.image); if (_cogl_gl_util_get_error (ctx) != GL_NO_ERROR) { _cogl_set_error (error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_BAD_PARAMETER, "Could not create a CoglTexture2D from a given " "EGLImage"); GE( ctx, glDeleteTextures (1, &tex_2d->gl_texture) ); return FALSE; } tex_2d->internal_format = internal_format; _cogl_texture_set_allocated (tex, internal_format, loader->src.egl_image.width, loader->src.egl_image.height); return TRUE; }
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 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; }
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; }
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; _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 */ _cogl_gl_util_clear_gl_errors (ctx); 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 */ _cogl_gl_util_clear_gl_errors (ctx); 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 */ _cogl_gl_util_clear_gl_errors (ctx); 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; 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 */ _cogl_gl_util_clear_gl_errors (ctx); 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; 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; }
void _cogl_shader_compile_real (CoglHandle handle, CoglPipeline *pipeline) { CoglShader *shader = handle; _COGL_GET_CONTEXT (ctx, NO_RETVAL); #ifdef HAVE_COGL_GL if (shader->language == COGL_SHADER_LANGUAGE_ARBFP) { #ifdef COGL_GL_DEBUG GLenum gl_error; #endif if (shader->gl_handle) return; GE (ctx, glGenPrograms (1, &shader->gl_handle)); GE (ctx, glBindProgram (GL_FRAGMENT_PROGRAM_ARB, shader->gl_handle)); if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_SHOW_SOURCE))) g_message ("user ARBfp program:\n%s", shader->source); #ifdef COGL_GL_DEBUG _cogl_gl_util_clear_gl_errors (ctx); #endif ctx->glProgramString (GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen (shader->source), shader->source); #ifdef COGL_GL_DEBUG gl_error = _cogl_gl_util_get_error (ctx); if (gl_error != GL_NO_ERROR) { g_warning ("%s: GL error (%d): Failed to compile ARBfp:\n%s\n%s", G_STRLOC, gl_error, shader->source, ctx->glGetString (GL_PROGRAM_ERROR_STRING_ARB)); } #endif } else #endif { GLenum gl_type; GLint status; if (shader->gl_handle) { CoglPipeline *prev = shader->compilation_pipeline; /* XXX: currently the only things that will affect the * boilerplate for user shaders, apart from driver features, * are the pipeline layer-indices and texture-unit-indices */ if (pipeline == prev || _cogl_pipeline_layer_and_unit_numbers_equal (prev, pipeline)) return; } if (shader->gl_handle) delete_shader (shader); switch (shader->type) { case COGL_SHADER_TYPE_VERTEX: gl_type = GL_VERTEX_SHADER; break; case COGL_SHADER_TYPE_FRAGMENT: gl_type = GL_FRAGMENT_SHADER; break; default: g_assert_not_reached (); break; } shader->gl_handle = ctx->glCreateShader (gl_type); _cogl_glsl_shader_set_source_with_boilerplate (ctx, shader->gl_handle, gl_type, pipeline, 1, (const char **) &shader->source, NULL); GE (ctx, glCompileShader (shader->gl_handle)); shader->compilation_pipeline = cogl_object_ref (pipeline); GE (ctx, glGetShaderiv (shader->gl_handle, GL_COMPILE_STATUS, &status)); if (!status) { char buffer[512]; int len = 0; ctx->glGetShaderInfoLog (shader->gl_handle, 511, &len, buffer); buffer[len] = '\0'; g_warning ("Failed to compile GLSL program:\n" "src:\n%s\n" "error:\n%s\n", shader->source, buffer); } } }