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_sub_texture_get_gl_texture (CoglTexture *tex, GLuint *out_gl_handle, GLenum *out_gl_target) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); return cogl_texture_get_gl_texture (sub_tex->full_texture, out_gl_handle, out_gl_target); }
static gboolean _cogl_texture_pixmap_x11_get_gl_texture (CoglTexture *tex, GLuint *out_gl_handle, GLenum *out_gl_target) { CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (tex); CoglTexture *child_tex = _cogl_texture_pixmap_x11_get_texture (tex_pixmap); /* Forward on to the child texture */ return cogl_texture_get_gl_texture (child_tex, out_gl_handle, out_gl_target); }
void _cogl_texture_gl_generate_mipmaps (CoglTexture *texture) { CoglContext *ctx = texture->context; int n_levels = _cogl_texture_get_n_levels (texture); GLuint gl_handle; GLenum gl_target; _cogl_texture_gl_maybe_update_max_level (texture, n_levels - 1); cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target); _cogl_bind_gl_texture_transient (gl_target, gl_handle, _cogl_texture_is_foreign (texture)); GE( ctx, glGenerateMipmap (gl_target) ); }
static gboolean texture_bind (ClutterGLXTexturePixmap *tex) { GLuint handle = 0; GLenum target = 0; CoglHandle cogl_tex; cogl_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE(tex)); if (!cogl_texture_get_gl_texture (cogl_tex, &handle, &target)) return FALSE; glEnable(target); /* FIXME: fire off an error here? */ glBindTexture (target, handle); return TRUE; }
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; }
Context::Context( ClutterActor * actor ) : unpack_flip_y( false ), unpack_premultiply_alpha( false ), unpack_colorspace_conversion( GL_BROWSER_DEFAULT_WEBGL ), have_depth( false ), have_stencil( false ), acquisitions( 0 ), texture( 0 ), texture_target( 0 ), framebuffer( 0 ) { g_assert( CLUTTER_IS_TEXTURE( actor ) ); // Make sure we are in the clutter context context_op( SWITCH_TO_CLUTTER_CONTEXT ); // Get the Clutter GL texture id and target #ifdef CLUTTER_VERSION_1_10 CoglTexture * th = COGL_TEXTURE( clutter_texture_get_cogl_texture( CLUTTER_TEXTURE( actor ) ) ); #else CoglHandle th = clutter_texture_get_cogl_texture( CLUTTER_TEXTURE( actor ) ); #endif if ( ! cogl_texture_get_gl_texture( th , & texture , & texture_target ) ) { tpwarn( "FAILED TO GET GL TEXTURE HANDLE" ); } // Now, create our context and switch to it context_op( CREATE_CONTEXT ); context_op( SWITCH_TO_MY_CONTEXT ); // Get the width and height of the actor gfloat width; gfloat height; clutter_actor_get_size( actor , & width , & height ); // Try to create the frame buffer in different ways until one // succeeds (or all fail). const int try_flags[] = { #if defined(CLUTTER_WINDOWING_GLX) || defined(CLUTTER_WINDOWING_OSX) FBO_TRY_DEPTH_STENCIL , #endif FBO_TRY_DEPTH | FBO_TRY_STENCIL , FBO_TRY_DEPTH , FBO_TRY_STENCIL , 0 }; for ( size_t i = 0; i < sizeof( try_flags ) / sizeof( int ); ++i ) { if ( try_create_fbo( width , height , try_flags[ i ] ) ) { break; } } if ( ! framebuffer ) { tpwarn( "UNABLE TO CREATE FRAMEBUFFER" ); } else { tplog2( "FRAMEBUFFER READY : DEPTH = %s : STENCIL = %s" , have_depth ? "YES" : "NO" , have_stencil ? "YES" : "NO" ); } context_op( SWITCH_TO_CLUTTER_CONTEXT ); }
static gboolean _cogl_texture_pixmap_x11_update_glx_texture (CoglTexturePixmapX11 *tex_pixmap, gboolean needs_mipmap) { gboolean ret = TRUE; _COGL_GET_CONTEXT (ctx, FALSE); /* If we don't have a GLX pixmap then fallback */ if (tex_pixmap->glx_pixmap == None) ret = FALSE; else { /* Lazily create a texture to hold the pixmap */ if (tex_pixmap->glx_tex == COGL_INVALID_HANDLE) { CoglPixelFormat texture_format; texture_format = (tex_pixmap->depth >= 32 ? COGL_PIXEL_FORMAT_RGBA_8888_PRE : COGL_PIXEL_FORMAT_RGB_888); if (should_use_rectangle ()) { tex_pixmap->glx_tex = _cogl_texture_rectangle_new_with_size (tex_pixmap->width, tex_pixmap->height, COGL_TEXTURE_NO_ATLAS, texture_format); if (tex_pixmap->glx_tex) COGL_NOTE (TEXTURE_PIXMAP, "Created a texture rectangle for %p", tex_pixmap); else { COGL_NOTE (TEXTURE_PIXMAP, "Falling back for %p because a " "texture rectangle could not be created", tex_pixmap); _cogl_texture_pixmap_x11_free_glx_pixmap (tex_pixmap); ret = FALSE; } } else { tex_pixmap->glx_tex = _cogl_texture_2d_new_with_size (tex_pixmap->width, tex_pixmap->height, COGL_TEXTURE_NO_ATLAS, texture_format); if (tex_pixmap->glx_tex) COGL_NOTE (TEXTURE_PIXMAP, "Created a texture 2d for %p", tex_pixmap); else { COGL_NOTE (TEXTURE_PIXMAP, "Falling back for %p because a " "texture 2d could not be created", tex_pixmap); _cogl_texture_pixmap_x11_free_glx_pixmap (tex_pixmap); ret = FALSE; } } } if (ret && needs_mipmap) { /* If we can't support mipmapping then temporarily fallback */ if (!tex_pixmap->glx_can_mipmap) ret = FALSE; /* Recreate the GLXPixmap if it wasn't previously created with a mipmap tree */ else if (!tex_pixmap->glx_pixmap_has_mipmap) { _cogl_texture_pixmap_x11_free_glx_pixmap (tex_pixmap); COGL_NOTE (TEXTURE_PIXMAP, "Recreating GLXPixmap with mipmap " "support for %p", tex_pixmap); try_create_glx_pixmap (tex_pixmap, TRUE); /* If the pixmap failed then we'll permanently fallback to using XImage. This shouldn't happen */ if (tex_pixmap->glx_pixmap == None) { COGL_NOTE (TEXTURE_PIXMAP, "Falling back to XGetImage " "updates for %p because creating the GLXPixmap " "with mipmap support failed", tex_pixmap); if (tex_pixmap->glx_tex) cogl_handle_unref (tex_pixmap->glx_tex); ret = FALSE; } else tex_pixmap->bind_tex_image_queued = TRUE; } } if (ret && tex_pixmap->bind_tex_image_queued) { GLuint gl_handle, gl_target; cogl_texture_get_gl_texture (tex_pixmap->glx_tex, &gl_handle, &gl_target); COGL_NOTE (TEXTURE_PIXMAP, "Rebinding GLXPixmap for %p", tex_pixmap); GE( _cogl_bind_gl_texture_transient (gl_target, gl_handle, FALSE) ); if (tex_pixmap->pixmap_bound) glXReleaseTexImage (_cogl_xlib_get_display (), tex_pixmap->glx_pixmap, GLX_FRONT_LEFT_EXT); glXBindTexImage (_cogl_xlib_get_display (), tex_pixmap->glx_pixmap, GLX_FRONT_LEFT_EXT, NULL); /* According to the recommended usage in the spec for GLX_EXT_texture_pixmap we should release the texture after we've finished drawing with it and it is undefined what happens if you render to a pixmap that is bound to a texture. However that would require the texture backend to know when Cogl has finished painting and it may be more expensive to keep unbinding the texture. Leaving it bound appears to work on Mesa and NVidia drivers and it is also what Compiz does so it is probably ok */ tex_pixmap->bind_tex_image_queued = FALSE; tex_pixmap->pixmap_bound = TRUE; _cogl_texture_2d_externally_modified (tex_pixmap->glx_tex); } } return ret; }