diff --git a/cogl/Makefile.am b/cogl/Makefile.am index d42f52a4d..f7719e18b 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -118,6 +118,7 @@ cogl_experimental_h = \ $(srcdir)/cogl-poll.h \ $(srcdir)/cogl-texture-3d.h \ $(srcdir)/cogl-texture-2d.h \ + $(srcdir)/cogl-texture-2d-gl.h \ $(srcdir)/cogl-texture-rectangle.h \ $(srcdir)/cogl-texture-2d-sliced.h \ $(srcdir)/cogl-sub-texture.h \ @@ -147,6 +148,8 @@ cogl_gl_prototypes_h = \ # driver sources cogl_driver_sources = \ $(srcdir)/driver/gl/cogl-framebuffer-gl.c \ + $(srcdir)/driver/gl/cogl-texture-2d-gl-private.h \ + $(srcdir)/driver/gl/cogl-texture-2d-gl.c \ $(srcdir)/driver/gl/cogl-pipeline-opengl.c \ $(srcdir)/driver/gl/cogl-pipeline-opengl-private.h \ $(srcdir)/driver/gl/cogl-pipeline-fragend-glsl.c \ diff --git a/cogl/cogl-driver.h b/cogl/cogl-driver.h index 63b737d33..bfedbff8f 100644 --- a/cogl/cogl-driver.h +++ b/cogl/cogl-driver.h @@ -32,11 +32,15 @@ typedef struct _CoglDriverVtable CoglDriverVtable; struct _CoglDriverVtable { + /* TODO: factor this out since this is OpenGL specific and + * so can be ignored by non-OpenGL drivers. */ CoglBool (* pixel_format_from_gl_internal) (CoglContext *context, GLenum gl_int_format, CoglPixelFormat *out_format); + /* TODO: factor this out since this is OpenGL specific and + * so can be ignored by non-OpenGL drivers. */ CoglPixelFormat (* pixel_format_to_gl) (CoglContext *context, CoglPixelFormat format, @@ -102,6 +106,110 @@ struct _CoglDriverVtable CoglAttribute **attributes, int n_attributes, CoglDrawFlags flags); + + /* Destroys any driver specific resources associated with the given + * 2D texture. */ + void + (* texture_2d_free) (CoglTexture2D *tex_2d); + + /* Returns TRUE if the driver can support creating a 2D texture with + * the given geometry and specified internal format. + */ + CoglBool + (* texture_2d_can_create) (CoglContext *ctx, + int width, + int height, + CoglPixelFormat internal_format); + + /* Initializes driver private state before allocating any specific + * storage for a 2D texture, where base texture and texture 2D + * members will already be initialized before passing control to + * the driver. + */ + void + (* texture_2d_init) (CoglTexture2D *tex_2d); + + /* Instantiates a new CoglTexture2D object with un-initialized + * storage for a given size and internal format */ + CoglTexture2D * + (* texture_2d_new_with_size) (CoglContext *ctx, + int width, + int height, + CoglPixelFormat internal_format, + CoglError **error); + + /* Instantiates a new CoglTexture2D object with storage initialized + * with the contents of the given bitmap, using the specified + * internal format. + */ + CoglTexture2D * + (* texture_2d_new_from_bitmap) (CoglBitmap *bmp, + CoglPixelFormat internal_format, + CoglError **error); + +#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) + /* Instantiates a new CoglTexture2D object with storage initialized + * with the contents of the given EGL image. + * + * This is optional for drivers to support + */ + CoglTexture2D * + (* egl_texture_2d_new_from_image) (CoglContext *ctx, + int width, + int height, + CoglPixelFormat format, + EGLImageKHR image, + CoglError **error); +#endif + + /* Initialize the specified region of storage of the given texture + * with the contents of the specified framebuffer region + */ + void + (* texture_2d_copy_from_framebuffer) (CoglTexture2D *tex_2d, + CoglFramebuffer *src_fb, + int dst_x, + int dst_y, + int src_x, + int src_y, + int width, + int height); + + /* If the given texture has a corresponding OpenGL texture handle + * then return that. + * + * This is optional + */ + unsigned int + (* texture_2d_get_gl_handle) (CoglTexture2D *tex_2d); + + /* Update all mipmap levels > 0 */ + void + (* texture_2d_generate_mipmap) (CoglTexture2D *tex_2d); + + /* Initialize the specified region of storage of the given texture + * with the contents of the specified bitmap region + */ + void + (* texture_2d_copy_from_bitmap) (CoglTexture2D *tex_2d, + CoglBitmap *bitmap, + int dst_x, + int dst_y, + int src_x, + int src_y, + int width, + int height); + + /* Reads back the full contents of the given texture and write it to + * @data in the given @format and with the given @rowstride. + * + * This is optional + */ + void + (* texture_2d_get_data) (CoglTexture2D *tex_2d, + CoglPixelFormat format, + unsigned int rowstride, + uint8_t *data); }; #endif /* __COGL_DRIVER_H */ diff --git a/cogl/cogl-gles2-context.c b/cogl/cogl-gles2-context.c index c8d0e20b6..c2b61fd59 100644 --- a/cogl/cogl-gles2-context.c +++ b/cogl/cogl-gles2-context.c @@ -43,6 +43,7 @@ #include "cogl-onscreen-template-private.h" #include "cogl-renderer-private.h" #include "cogl-swap-chain-private.h" +#include "cogl-texture-2d-gl.h" #include "cogl-texture-2d-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-error-private.h" diff --git a/cogl/cogl-texture-2d-gl.h b/cogl/cogl-texture-2d-gl.h new file mode 100644 index 000000000..c70f4c308 --- /dev/null +++ b/cogl/cogl-texture-2d-gl.h @@ -0,0 +1,75 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2012 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * + * Authors: + * Robert Bragg + */ + +#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef _COGL_TEXTURE_2D_GL_H_ +#define _COGL_TEXTURE_2D_GL_H_ + +#include "cogl-context.h" +#include "cogl-texture-2d.h" + +#include + +G_BEGIN_DECLS + +/** + * cogl_texture_2d_new_from_foreign: + * @ctx: A #CoglContext + * @gl_handle: A GL handle for a GL_TEXTURE_2D texture object + * @width: Width of the foreign GL texture + * @height: Height of the foreign GL texture + * @internal_format: The format of the texture + * @error: A #CoglError for exceptions + * + * Wraps an existing GL_TEXTURE_2D texture object as a #CoglTexture2D. + * This can be used for integrating Cogl with software using OpenGL + * directly. + * + * The results are undefined for passing an invalid @gl_handle + * or if @width or @height don't have the correct texture + * geometry. + * + * Returns: A newly allocated #CoglTexture2D, or if Cogl could not + * validate the @gl_handle in some way (perhaps because of + * an unsupported format) it will return %NULL and set + * @error. + * + * Since: 2.0 + */ +CoglTexture2D * +cogl_texture_2d_new_from_foreign (CoglContext *ctx, + unsigned int gl_handle, + int width, + int height, + CoglPixelFormat format, + CoglError **error); + +G_END_DECLS + +#endif /* _COGL_TEXTURE_2D_GL_H_ */ diff --git a/cogl/cogl-texture-2d-private.h b/cogl/cogl-texture-2d-private.h index 3180a3f82..2a5708177 100644 --- a/cogl/cogl-texture-2d-private.h +++ b/cogl/cogl-texture-2d-private.h @@ -74,6 +74,16 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx, CoglError **error); #endif +CoglTexture2D * +_cogl_texture_2d_create_base (CoglContext *ctx, + int width, + int height, + CoglPixelFormat internal_format); + +void +_cogl_texture_2d_set_auto_mipmap (CoglTexture *tex, + CoglBool value); + /* * _cogl_texture_2d_externally_modified: * @texture: A #CoglTexture2D object diff --git a/cogl/cogl-texture-2d-sliced.c b/cogl/cogl-texture-2d-sliced.c index e988a4ab7..7b4fee59b 100644 --- a/cogl/cogl-texture-2d-sliced.c +++ b/cogl/cogl-texture-2d-sliced.c @@ -36,6 +36,7 @@ #include "cogl-bitmap.h" #include "cogl-bitmap-private.h" #include "cogl-texture-private.h" +#include "cogl-texture-2d-gl.h" #include "cogl-texture-2d-private.h" #include "cogl-texture-2d-sliced-private.h" #include "cogl-texture-driver.h" diff --git a/cogl/cogl-texture-2d.c b/cogl/cogl-texture-2d.c index e69b044b3..6b902fb11 100644 --- a/cogl/cogl-texture-2d.c +++ b/cogl/cogl-texture-2d.c @@ -32,6 +32,7 @@ #include "cogl-util.h" #include "cogl-texture-private.h" #include "cogl-texture-2d-private.h" +#include "cogl-texture-2d-gl-private.h" #include "cogl-texture-driver.h" #include "cogl-context-private.h" #include "cogl-object-private.h" @@ -63,41 +64,12 @@ typedef struct _CoglTexture2DManualRepeatData void *user_data; } CoglTexture2DManualRepeatData; -static void -_cogl_texture_2d_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex, - GLenum wrap_mode_s, - GLenum wrap_mode_t, - GLenum wrap_mode_p) -{ - CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); - CoglContext *ctx = tex->context; - - /* Only set the wrap mode if it's different from the current value - to avoid too many GL calls. Texture 2D doesn't make use of the r - coordinate so we can ignore its wrap mode */ - if (tex_2d->gl_legacy_texobj_wrap_mode_s != wrap_mode_s || - tex_2d->gl_legacy_texobj_wrap_mode_t != wrap_mode_t) - { - _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, - tex_2d->gl_texture, - tex_2d->is_foreign); - GE( ctx, glTexParameteri (GL_TEXTURE_2D, - GL_TEXTURE_WRAP_S, - wrap_mode_s) ); - GE( ctx, glTexParameteri (GL_TEXTURE_2D, - GL_TEXTURE_WRAP_T, - wrap_mode_t) ); - - tex_2d->gl_legacy_texobj_wrap_mode_s = wrap_mode_s; - tex_2d->gl_legacy_texobj_wrap_mode_t = wrap_mode_t; - } -} - static void _cogl_texture_2d_free (CoglTexture2D *tex_2d) { - if (!tex_2d->is_foreign) - _cogl_delete_gl_texture (tex_2d->gl_texture); + CoglContext *ctx = COGL_TEXTURE (tex_2d)->context; + + ctx->driver_vtable->texture_2d_free (tex_2d); /* Chain up */ _cogl_texture_free (COGL_TEXTURE (tex_2d)); @@ -109,10 +81,6 @@ _cogl_texture_2d_can_create (CoglContext *ctx, unsigned int height, CoglPixelFormat internal_format) { - GLenum gl_intformat; - GLenum gl_format; - GLenum gl_type; - /* If NPOT textures aren't supported then the size must be a power of two */ if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) && @@ -120,26 +88,13 @@ _cogl_texture_2d_can_create (CoglContext *ctx, !_cogl_util_is_pot (height))) return FALSE; - ctx->driver_vtable->pixel_format_to_gl (ctx, - internal_format, - &gl_intformat, - &gl_format, - &gl_type); - - /* Check that the driver can create a texture with that size */ - if (!ctx->texture_driver->size_supported (ctx, - GL_TEXTURE_2D, - gl_intformat, - gl_format, - gl_type, - width, - height)) - return FALSE; - - return TRUE; + return ctx->driver_vtable->texture_2d_can_create (ctx, + width, + height, + internal_format); } -static void +void _cogl_texture_2d_set_auto_mipmap (CoglTexture *tex, CoglBool value) { @@ -148,7 +103,7 @@ _cogl_texture_2d_set_auto_mipmap (CoglTexture *tex, tex_2d->auto_mipmap = value; } -static CoglTexture2D * +CoglTexture2D * _cogl_texture_2d_create_base (CoglContext *ctx, int width, int height, @@ -164,19 +119,13 @@ _cogl_texture_2d_create_base (CoglContext *ctx, tex_2d->mipmaps_dirty = TRUE; tex_2d->auto_mipmap = TRUE; - /* We default to GL_LINEAR for both filters */ - tex_2d->gl_legacy_texobj_min_filter = GL_LINEAR; - tex_2d->gl_legacy_texobj_mag_filter = GL_LINEAR; - - /* Wrap mode not yet set */ - tex_2d->gl_legacy_texobj_wrap_mode_s = GL_FALSE; - tex_2d->gl_legacy_texobj_wrap_mode_t = GL_FALSE; - tex_2d->is_foreign = FALSE; tex_2d->format = internal_format; - return tex_2d; + ctx->driver_vtable->texture_2d_init (tex_2d); + + return _cogl_texture_2d_object_new (tex_2d); } CoglTexture2D * @@ -186,11 +135,6 @@ cogl_texture_2d_new_with_size (CoglContext *ctx, CoglPixelFormat internal_format, CoglError **error) { - CoglTexture2D *tex_2d; - GLenum gl_intformat; - GLenum gl_format; - GLenum gl_type; - /* Since no data, we need some internal format */ if (internal_format == COGL_PIXEL_FORMAT_ANY) internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE; @@ -204,24 +148,11 @@ cogl_texture_2d_new_with_size (CoglContext *ctx, return NULL; } - internal_format = ctx->driver_vtable->pixel_format_to_gl (ctx, - internal_format, - &gl_intformat, - &gl_format, - &gl_type); - - tex_2d = _cogl_texture_2d_create_base (ctx, - width, height, - internal_format); - - ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, 1, &tex_2d->gl_texture); - _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, - tex_2d->gl_texture, - tex_2d->is_foreign); - GE( ctx, glTexImage2D (GL_TEXTURE_2D, 0, gl_intformat, - width, height, 0, gl_format, gl_type, NULL) ); - - return _cogl_texture_2d_object_new (tex_2d); + return ctx->driver_vtable->texture_2d_new_with_size (ctx, + width, + height, + internal_format, + error); } CoglTexture2D * @@ -229,12 +160,6 @@ cogl_texture_2d_new_from_bitmap (CoglBitmap *bmp, CoglPixelFormat internal_format, CoglError **error) { - CoglTexture2D *tex_2d; - CoglBitmap *dst_bmp; - GLenum gl_intformat; - GLenum gl_format; - GLenum gl_type; - uint8_t *data; CoglContext *ctx; _COGL_RETURN_VAL_IF_FAIL (bmp != NULL, NULL); @@ -258,54 +183,9 @@ cogl_texture_2d_new_from_bitmap (CoglBitmap *bmp, } - if ((dst_bmp = _cogl_texture_prepare_for_upload (bmp, - internal_format, - &internal_format, - &gl_intformat, - &gl_format, - &gl_type)) == NULL) - { - _cogl_set_error (error, COGL_TEXTURE_ERROR, - COGL_TEXTURE_ERROR_FORMAT, - "Failed to prepare texture upload due to format"); - return NULL; - } - - tex_2d = _cogl_texture_2d_create_base (ctx, - cogl_bitmap_get_width (bmp), - cogl_bitmap_get_height (bmp), - internal_format); - - /* Keep a copy of the first pixel so that if glGenerateMipmap isn't - supported we can fallback to using GL_GENERATE_MIPMAP */ - if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) && - (data = _cogl_bitmap_map (dst_bmp, - COGL_BUFFER_ACCESS_READ, 0))) - { - CoglPixelFormat format = cogl_bitmap_get_format (dst_bmp); - tex_2d->first_pixel.gl_format = gl_format; - tex_2d->first_pixel.gl_type = gl_type; - memcpy (tex_2d->first_pixel.data, data, - _cogl_pixel_format_get_bytes_per_pixel (format)); - - _cogl_bitmap_unmap (dst_bmp); - } - - ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, 1, &tex_2d->gl_texture); - ctx->texture_driver->upload_to_gl (ctx, - GL_TEXTURE_2D, - tex_2d->gl_texture, - FALSE, - dst_bmp, - gl_intformat, - gl_format, - gl_type); - - tex_2d->gl_format = gl_intformat; - - cogl_object_unref (dst_bmp); - - return _cogl_texture_2d_object_new (tex_2d); + return ctx->driver_vtable->texture_2d_new_from_bitmap (bmp, + internal_format, + error); } CoglTexture2D * @@ -344,149 +224,6 @@ cogl_texture_2d_new_from_data (CoglContext *ctx, return tex_2d; } -CoglTexture2D * -cogl_texture_2d_new_from_foreign (CoglContext *ctx, - unsigned int gl_handle, - int width, - int height, - CoglPixelFormat format, - CoglError **error) -{ - /* NOTE: width, height and internal format are not queriable - * in GLES, hence such a function prototype. - */ - - GLenum gl_error = 0; - GLint gl_compressed = GL_FALSE; - GLenum gl_int_format = 0; - CoglTexture2D *tex_2d; - - /* Assert it is a valid GL texture object */ - g_return_val_if_fail (ctx->glIsTexture (gl_handle), NULL); - - 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 NULL; - } - - - /* Make sure binding succeeds */ - while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) - ; - - _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, 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_2D texture"); - return NULL; - } - - /* Obtain texture parameters - (only level 0 we are interested in) */ - -#if HAVE_COGL_GL - if (ctx->driver == COGL_DRIVER_GL) - { - 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 NULL; - } - } - 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); - } - - /* Note: We always trust the given width and height without querying - * the texture object because the user may be creating a Cogl - * texture for a texture_from_pixmap object where glTexImage2D may - * not have been called and the texture_from_pixmap spec doesn't - * clarify that it is reliable to query back the size from OpenGL. - */ - - /* Validate width and height */ - g_return_val_if_fail (width > 0 && height > 0, 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 NULL; - } - - /* 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_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. */ - - /* Create new texture */ - tex_2d = _cogl_texture_2d_create_base (ctx, - width, height, - format); - _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->format = format; - - tex_2d->gl_texture = gl_handle; - tex_2d->gl_format = gl_int_format; - - /* Unknown filter */ - tex_2d->gl_legacy_texobj_min_filter = GL_FALSE; - tex_2d->gl_legacy_texobj_mag_filter = GL_FALSE; - - return _cogl_texture_2d_object_new (tex_2d); -} - #if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) /* 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 @@ -499,9 +236,6 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx, EGLImageKHR image, CoglError **error) { - CoglTexture2D *tex_2d; - GLenum gl_error; - _COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints & COGL_RENDERER_CONSTRAINT_USES_EGL, NULL); @@ -510,29 +244,22 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx, COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE, NULL); - tex_2d = _cogl_texture_2d_create_base (ctx, - width, height, - format); - - ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, 1, &tex_2d->gl_texture); - _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, - tex_2d->gl_texture, - FALSE); - - while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) - ; - ctx->glEGLImageTargetTexture2D (GL_TEXTURE_2D, image); - if (ctx->glGetError () != GL_NO_ERROR) + 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_TEXTURE_ERROR, - COGL_TEXTURE_ERROR_BAD_PARAMETER, - "Could not create a CoglTexture2D from a given " - "EGLImage"); + COGL_SYSTEM_ERROR, + COGL_SYSTEM_ERROR_UNSUPPORTED, + "Creating 2D textures from EGL images is not " + "supported by the current driver"); return NULL; } - - return _cogl_texture_2d_object_new (tex_2d); } #endif /* defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) */ @@ -624,28 +351,20 @@ _cogl_texture_2d_copy_from_framebuffer (CoglTexture2D *tex_2d, int height) { CoglContext *ctx; + CoglFramebuffer *read_fb = _cogl_get_read_framebuffer (); _COGL_RETURN_IF_FAIL (cogl_is_texture_2d (tex_2d)); ctx = COGL_TEXTURE (tex_2d)->context; - /* Make sure the current framebuffers are bound, though we don't need to - * flush the clip state here since we aren't going to draw to the - * framebuffer. */ - _cogl_framebuffer_flush_state (cogl_get_draw_framebuffer (), - _cogl_get_read_framebuffer (), - COGL_FRAMEBUFFER_STATE_ALL & - ~COGL_FRAMEBUFFER_STATE_CLIP); - - _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, - tex_2d->gl_texture, - tex_2d->is_foreign); - - ctx->glCopyTexSubImage2D (GL_TEXTURE_2D, - 0, /* level */ - dst_x, dst_y, - src_x, src_y, - width, height); + ctx->driver_vtable->texture_2d_copy_from_framebuffer (tex_2d, + read_fb, + dst_x, + dst_y, + src_x, + src_y, + width, + height); tex_2d->mipmaps_dirty = TRUE; } @@ -712,75 +431,39 @@ _cogl_texture_2d_get_gl_texture (CoglTexture *tex, GLuint *out_gl_handle, GLenum *out_gl_target) { - CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); - - if (out_gl_handle) - *out_gl_handle = tex_2d->gl_texture; - - if (out_gl_target) - *out_gl_target = GL_TEXTURE_2D; - - return TRUE; -} - -static void -_cogl_texture_2d_gl_flush_legacy_texobj_filters (CoglTexture *tex, - GLenum min_filter, - GLenum mag_filter) -{ - CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); CoglContext *ctx = tex->context; + CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); - if (min_filter == tex_2d->gl_legacy_texobj_min_filter - && mag_filter == tex_2d->gl_legacy_texobj_mag_filter) - return; + if (ctx->driver_vtable->texture_2d_get_gl_handle) + { + GLuint handle; - /* Store new values */ - tex_2d->gl_legacy_texobj_min_filter = min_filter; - tex_2d->gl_legacy_texobj_mag_filter = mag_filter; + if (out_gl_target) + *out_gl_target = GL_TEXTURE_2D; - /* Apply new filters to the texture */ - _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, - tex_2d->gl_texture, - tex_2d->is_foreign); - GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter) ); - GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter) ); + handle = ctx->driver_vtable->texture_2d_get_gl_handle (tex_2d); + + if (out_gl_handle) + *out_gl_handle = handle; + + return handle ? TRUE : FALSE; + } + else + return FALSE; } static void _cogl_texture_2d_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags) { CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); - CoglContext *ctx = tex->context; /* Only update if the mipmaps are dirty */ if ((flags & COGL_TEXTURE_NEEDS_MIPMAP) && tex_2d->auto_mipmap && tex_2d->mipmaps_dirty) { - _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, - tex_2d->gl_texture, - tex_2d->is_foreign); + CoglContext *ctx = tex->context; - /* 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)) - ctx->texture_driver->gl_generate_mipmaps (ctx, GL_TEXTURE_2D); -#if defined(HAVE_COGL_GLES) || defined(HAVE_COGL_GL) - else - { - GE( ctx, glTexParameteri (GL_TEXTURE_2D, - GL_GENERATE_MIPMAP, - GL_TRUE) ); - GE( ctx, glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, 1, 1, - tex_2d->first_pixel.gl_format, - tex_2d->first_pixel.gl_type, - tex_2d->first_pixel.data) ); - GE( ctx, glTexParameteri (GL_TEXTURE_2D, - GL_GENERATE_MIPMAP, - GL_FALSE) ); - } -#endif + ctx->driver_vtable->texture_2d_generate_mipmap (tex_2d); tex_2d->mipmaps_dirty = FALSE; } @@ -798,55 +481,24 @@ _cogl_texture_2d_set_region (CoglTexture *tex, int src_y, int dst_x, int dst_y, - unsigned int dst_width, - unsigned int dst_height, + unsigned int width, + unsigned int height, CoglBitmap *bmp) { - CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); CoglContext *ctx = tex->context; - GLenum gl_format; - GLenum gl_type; - uint8_t *data; + CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); - bmp = _cogl_texture_prepare_for_upload (bmp, - cogl_texture_get_format (tex), - NULL, - NULL, - &gl_format, - &gl_type); - - /* If this touches the first pixel then we'll update our copy */ - if (dst_x == 0 && dst_y == 0 && - !cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) && - (data = _cogl_bitmap_map (bmp, COGL_BUFFER_ACCESS_READ, 0))) - { - CoglPixelFormat bpp = - _cogl_pixel_format_get_bytes_per_pixel (cogl_bitmap_get_format (bmp)); - tex_2d->first_pixel.gl_format = gl_format; - tex_2d->first_pixel.gl_type = gl_type; - memcpy (tex_2d->first_pixel.data, - data + cogl_bitmap_get_rowstride (bmp) * src_y + bpp * src_x, - bpp); - - _cogl_bitmap_unmap (bmp); - } - - /* Send data to GL */ - ctx->texture_driver->upload_subregion_to_gl (ctx, - GL_TEXTURE_2D, - tex_2d->gl_texture, - FALSE, - src_x, src_y, - dst_x, dst_y, - dst_width, dst_height, - bmp, - gl_format, - gl_type); + ctx->driver_vtable->texture_2d_copy_from_bitmap (tex_2d, + bmp, + dst_x, + dst_y, + src_x, + src_y, + width, + height); tex_2d->mipmaps_dirty = TRUE; - cogl_object_unref (bmp); - return TRUE; } @@ -856,33 +508,16 @@ _cogl_texture_2d_get_data (CoglTexture *tex, unsigned int rowstride, uint8_t *data) { - CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); CoglContext *ctx = tex->context; - int bpp; - GLenum gl_format; - GLenum gl_type; - bpp = _cogl_pixel_format_get_bytes_per_pixel (format); - - ctx->driver_vtable->pixel_format_to_gl (ctx, - format, - NULL, /* internal format */ - &gl_format, - &gl_type); - - ctx->texture_driver->prep_gl_for_pixels_download (ctx, - rowstride, - tex_2d->width, - bpp); - - _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, - tex_2d->gl_texture, - tex_2d->is_foreign); - return ctx->texture_driver->gl_get_tex_image (ctx, - GL_TEXTURE_2D, - gl_format, - gl_type, - data); + if (ctx->driver_vtable->texture_2d_get_data) + { + CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); + ctx->driver_vtable->texture_2d_get_data (tex_2d, format, rowstride, data); + return TRUE; + } + else + return FALSE; } static CoglPixelFormat diff --git a/cogl/cogl-texture-2d.h b/cogl/cogl-texture-2d.h index 1fc3d12ff..d07cdef4d 100644 --- a/cogl/cogl-texture-2d.h +++ b/cogl/cogl-texture-2d.h @@ -32,6 +32,7 @@ #define __COGL_TEXTURE_2D_H #include "cogl-context.h" +#include "cogl-bitmap.h" #include @@ -186,39 +187,6 @@ cogl_texture_2d_new_from_bitmap (CoglBitmap *bitmap, CoglPixelFormat internal_format, CoglError **error); - -/** - * cogl_texture_2d_new_from_foreign: - * @ctx: A #CoglContext - * @gl_handle: A GL handle for a GL_TEXTURE_2D texture object - * @width: Width of the foreign GL texture - * @height: Height of the foreign GL texture - * @internal_format: The format of the texture - * @error: A #CoglError for exceptions - * - * Wraps an existing GL_TEXTURE_2D texture object as a #CoglTexture2D. - * This can be used for integrating Cogl with software using OpenGL - * directly. - * - * The results are undefined for passing an invalid @gl_handle - * or if @width or @height don't have the correct texture - * geometry. - * - * Returns: A newly allocated #CoglTexture2D, or if Cogl could not - * validate the @gl_handle in some way (perhaps because of - * an unsupported format) it will return %NULL and set - * @error. - * - * Since: 2.0 - */ -CoglTexture2D * -cogl_texture_2d_new_from_foreign (CoglContext *ctx, - unsigned int gl_handle, - int width, - int height, - CoglPixelFormat format, - CoglError **error); - G_END_DECLS #endif /* __COGL_TEXTURE_2D_H */ diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c index 079d99cbd..ebc137f07 100644 --- a/cogl/cogl-texture.c +++ b/cogl/cogl-texture.c @@ -42,6 +42,7 @@ #include "cogl-texture-driver.h" #include "cogl-texture-2d-sliced-private.h" #include "cogl-texture-2d-private.h" +#include "cogl-texture-2d-gl.h" #include "cogl-texture-rectangle-private.h" #include "cogl-sub-texture-private.h" #include "cogl-atlas-texture-private.h" diff --git a/cogl/cogl.h b/cogl/cogl.h index 5f939e6ed..681b708c0 100644 --- a/cogl/cogl.h +++ b/cogl/cogl.h @@ -86,6 +86,7 @@ #include #include #include +#include #include #include #include diff --git a/cogl/driver/gl/cogl-texture-2d-gl-private.h b/cogl/driver/gl/cogl-texture-2d-gl-private.h new file mode 100644 index 000000000..492c31477 --- /dev/null +++ b/cogl/driver/gl/cogl-texture-2d-gl-private.h @@ -0,0 +1,112 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2012 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * + * + * Authors: + * Robert Bragg + */ + +#ifndef _COGL_TEXTURE_2D_GL_PRIVATE_H_ +#define _COGL_TEXTURE_2D_GL_PRIVATE_H_ + +#include "cogl-types.h" +#include "cogl-context-private.h" +#include "cogl-texture.h" + +void +_cogl_texture_2d_gl_free (CoglTexture2D *tex_2d); + +CoglBool +_cogl_texture_2d_gl_can_create (CoglContext *ctx, + int width, + int height, + CoglPixelFormat internal_format); + +void +_cogl_texture_2d_gl_init (CoglTexture2D *tex_2d); + +CoglTexture2D * +_cogl_texture_2d_gl_new_with_size (CoglContext *ctx, + int width, + int height, + CoglPixelFormat internal_format, + CoglError **error); + +CoglTexture2D * +_cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp, + CoglPixelFormat internal_format, + CoglError **error); + +#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) +CoglTexture2D * +_cogl_egl_texture_2d_gl_new_from_image (CoglContext *ctx, + int width, + int height, + CoglPixelFormat format, + EGLImageKHR image, + CoglError **error); +#endif + +void +_cogl_texture_2d_gl_flush_legacy_texobj_filters (CoglTexture *tex, + GLenum min_filter, + GLenum mag_filter); + +void +_cogl_texture_2d_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex, + GLenum wrap_mode_s, + GLenum wrap_mode_t, + GLenum wrap_mode_p); + +void +_cogl_texture_2d_gl_copy_from_framebuffer (CoglTexture2D *tex_2d, + CoglFramebuffer *src_fb, + int dst_x, + int dst_y, + int src_x, + int src_y, + int width, + int height); + +unsigned int +_cogl_texture_2d_gl_get_gl_handle (CoglTexture2D *tex_2d); + +void +_cogl_texture_2d_gl_generate_mipmap (CoglTexture2D *tex_2d); + +void +_cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d, + CoglBitmap *bitmap, + int dst_x, + int dst_y, + int src_x, + int src_y, + int width, + int height); + +void +_cogl_texture_2d_gl_get_data (CoglTexture2D *tex_2d, + CoglPixelFormat format, + size_t rowstride, + uint8_t *data); + +#endif /* _COGL_TEXTURE_2D_GL_PRIVATE_H_ */ diff --git a/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/driver/gl/cogl-texture-2d-gl.c new file mode 100644 index 000000000..889ae121d --- /dev/null +++ b/cogl/driver/gl/cogl-texture-2d-gl.c @@ -0,0 +1,575 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2009,2010,2011,2012 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * + * + * Authors: + * Neil Roberts + * Robert Bragg + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "cogl-private.h" +#include "cogl-texture-2d-gl.h" +#include "cogl-texture-2d-gl-private.h" +#include "cogl-texture-2d-private.h" +#include "cogl-pipeline-opengl-private.h" +#include "cogl-error-private.h" + +void +_cogl_texture_2d_gl_free (CoglTexture2D *tex_2d) +{ + if (!tex_2d->is_foreign) + _cogl_delete_gl_texture (tex_2d->gl_texture); +} + +CoglBool +_cogl_texture_2d_gl_can_create (CoglContext *ctx, + int width, + int height, + CoglPixelFormat internal_format) +{ + GLenum gl_intformat; + GLenum gl_format; + GLenum gl_type; + + ctx->driver_vtable->pixel_format_to_gl (ctx, + internal_format, + &gl_intformat, + &gl_format, + &gl_type); + + /* Check that the driver can create a texture with that size */ + if (!ctx->texture_driver->size_supported (ctx, + GL_TEXTURE_2D, + gl_intformat, + gl_format, + gl_type, + width, + height)) + return FALSE; + + return TRUE; +} + +void +_cogl_texture_2d_gl_init (CoglTexture2D *tex_2d) +{ + /* We default to GL_LINEAR for both filters */ + tex_2d->gl_legacy_texobj_min_filter = GL_LINEAR; + tex_2d->gl_legacy_texobj_mag_filter = GL_LINEAR; + + /* Wrap mode not yet set */ + tex_2d->gl_legacy_texobj_wrap_mode_s = GL_FALSE; + tex_2d->gl_legacy_texobj_wrap_mode_t = GL_FALSE; +} + +CoglTexture2D * +_cogl_texture_2d_gl_new_with_size (CoglContext *ctx, + int width, + int height, + CoglPixelFormat internal_format, + CoglError **error) +{ + CoglTexture2D *tex_2d; + GLenum gl_intformat; + GLenum gl_format; + GLenum gl_type; + + internal_format = ctx->driver_vtable->pixel_format_to_gl (ctx, + internal_format, + &gl_intformat, + &gl_format, + &gl_type); + + tex_2d = _cogl_texture_2d_create_base (ctx, + width, height, + internal_format); + + ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, 1, &tex_2d->gl_texture); + _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, + tex_2d->gl_texture, + tex_2d->is_foreign); + GE( ctx, glTexImage2D (GL_TEXTURE_2D, 0, gl_intformat, + width, height, 0, gl_format, gl_type, NULL) ); + + return tex_2d; +} + +CoglTexture2D * +_cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp, + CoglPixelFormat internal_format, + CoglError **error) +{ + CoglContext *ctx = _cogl_bitmap_get_context (bmp); + CoglTexture2D *tex_2d; + CoglBitmap *dst_bmp; + GLenum gl_intformat; + GLenum gl_format; + GLenum gl_type; + uint8_t *data; + + if ((dst_bmp = _cogl_texture_prepare_for_upload (bmp, + internal_format, + &internal_format, + &gl_intformat, + &gl_format, + &gl_type)) == NULL) + { + _cogl_set_error (error, COGL_TEXTURE_ERROR, + COGL_TEXTURE_ERROR_FORMAT, + "Failed to prepare texture upload due to format"); + return NULL; + } + + tex_2d = _cogl_texture_2d_create_base (ctx, + cogl_bitmap_get_width (bmp), + cogl_bitmap_get_height (bmp), + internal_format); + + /* Keep a copy of the first pixel so that if glGenerateMipmap isn't + supported we can fallback to using GL_GENERATE_MIPMAP */ + if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) && + (data = _cogl_bitmap_map (dst_bmp, + COGL_BUFFER_ACCESS_READ, 0))) + { + CoglPixelFormat format = cogl_bitmap_get_format (dst_bmp); + tex_2d->first_pixel.gl_format = gl_format; + tex_2d->first_pixel.gl_type = gl_type; + memcpy (tex_2d->first_pixel.data, data, + _cogl_pixel_format_get_bytes_per_pixel (format)); + + _cogl_bitmap_unmap (dst_bmp); + } + + ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, 1, &tex_2d->gl_texture); + ctx->texture_driver->upload_to_gl (ctx, + GL_TEXTURE_2D, + tex_2d->gl_texture, + FALSE, + dst_bmp, + gl_intformat, + gl_format, + gl_type); + + tex_2d->gl_format = gl_intformat; + + cogl_object_unref (dst_bmp); + + return tex_2d; + +} + +#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) +CoglTexture2D * +_cogl_egl_texture_2d_gl_new_from_image (CoglContext *ctx, + int width, + int height, + CoglPixelFormat format, + EGLImageKHR image, + CoglError **error) +{ + CoglTexture2D *tex_2d; + GLenum gl_error; + + tex_2d = _cogl_texture_2d_create_base (ctx, + width, height, + format); + + ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, 1, &tex_2d->gl_texture); + _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, + tex_2d->gl_texture, + FALSE); + + while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) + ; + ctx->glEGLImageTargetTexture2D (GL_TEXTURE_2D, image); + if (ctx->glGetError () != GL_NO_ERROR) + { + _cogl_set_error (error, + COGL_TEXTURE_ERROR, + COGL_TEXTURE_ERROR_BAD_PARAMETER, + "Could not create a CoglTexture2D from a given " + "EGLImage"); + return NULL; + } + + return tex_2d; +} +#endif + +void +_cogl_texture_2d_gl_flush_legacy_texobj_filters (CoglTexture *tex, + GLenum min_filter, + GLenum mag_filter) +{ + CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); + CoglContext *ctx = tex->context; + + if (min_filter == tex_2d->gl_legacy_texobj_min_filter + && mag_filter == tex_2d->gl_legacy_texobj_mag_filter) + return; + + /* Store new values */ + tex_2d->gl_legacy_texobj_min_filter = min_filter; + tex_2d->gl_legacy_texobj_mag_filter = mag_filter; + + /* Apply new filters to the texture */ + _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, + tex_2d->gl_texture, + tex_2d->is_foreign); + GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter) ); + GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter) ); +} + +void +_cogl_texture_2d_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex, + GLenum wrap_mode_s, + GLenum wrap_mode_t, + GLenum wrap_mode_p) +{ + CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); + CoglContext *ctx = tex->context; + + /* Only set the wrap mode if it's different from the current value + to avoid too many GL calls. Texture 2D doesn't make use of the r + coordinate so we can ignore its wrap mode */ + if (tex_2d->gl_legacy_texobj_wrap_mode_s != wrap_mode_s || + tex_2d->gl_legacy_texobj_wrap_mode_t != wrap_mode_t) + { + _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, + tex_2d->gl_texture, + tex_2d->is_foreign); + GE( ctx, glTexParameteri (GL_TEXTURE_2D, + GL_TEXTURE_WRAP_S, + wrap_mode_s) ); + GE( ctx, glTexParameteri (GL_TEXTURE_2D, + GL_TEXTURE_WRAP_T, + wrap_mode_t) ); + + tex_2d->gl_legacy_texobj_wrap_mode_s = wrap_mode_s; + tex_2d->gl_legacy_texobj_wrap_mode_t = wrap_mode_t; + } +} + +CoglTexture2D * +cogl_texture_2d_new_from_foreign (CoglContext *ctx, + unsigned int gl_handle, + int width, + int height, + CoglPixelFormat format, + CoglError **error) +{ + /* NOTE: width, height and internal format are not queriable + * in GLES, hence such a function prototype. + */ + + GLenum gl_error = 0; + GLint gl_compressed = GL_FALSE; + GLenum gl_int_format = 0; + CoglTexture2D *tex_2d; + + /* Assert it is a valid GL texture object */ + g_return_val_if_fail (ctx->glIsTexture (gl_handle), NULL); + + 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 NULL; + } + + + /* Make sure binding succeeds */ + while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) + ; + + _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, 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_2D texture"); + return NULL; + } + + /* Obtain texture parameters + (only level 0 we are interested in) */ + +#if HAVE_COGL_GL + if (ctx->driver == COGL_DRIVER_GL) + { + 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 NULL; + } + } + 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); + } + + /* Note: We always trust the given width and height without querying + * the texture object because the user may be creating a Cogl + * texture for a texture_from_pixmap object where glTexImage2D may + * not have been called and the texture_from_pixmap spec doesn't + * clarify that it is reliable to query back the size from OpenGL. + */ + + /* Validate width and height */ + g_return_val_if_fail (width > 0 && height > 0, 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 NULL; + } + + /* 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_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. */ + + /* Create new texture */ + tex_2d = _cogl_texture_2d_create_base (ctx, + width, height, + format); + _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->format = format; + + tex_2d->gl_texture = gl_handle; + tex_2d->gl_format = gl_int_format; + + /* Unknown filter */ + tex_2d->gl_legacy_texobj_min_filter = GL_FALSE; + tex_2d->gl_legacy_texobj_mag_filter = GL_FALSE; + + return tex_2d; +} + +void +_cogl_texture_2d_gl_copy_from_framebuffer (CoglTexture2D *tex_2d, + CoglFramebuffer *src_fb, + int dst_x, + int dst_y, + int src_x, + int src_y, + int width, + int height) +{ + CoglContext *ctx = COGL_TEXTURE (tex_2d)->context; + + /* Make sure the current framebuffers are bound, though we don't need to + * flush the clip state here since we aren't going to draw to the + * framebuffer. */ + _cogl_framebuffer_flush_state (cogl_get_draw_framebuffer (), + src_fb, + COGL_FRAMEBUFFER_STATE_ALL & + ~COGL_FRAMEBUFFER_STATE_CLIP); + + _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, + tex_2d->gl_texture, + tex_2d->is_foreign); + + ctx->glCopyTexSubImage2D (GL_TEXTURE_2D, + 0, /* level */ + dst_x, dst_y, + src_x, src_y, + width, height); +} + +unsigned int +_cogl_texture_2d_gl_get_gl_handle (CoglTexture2D *tex_2d) +{ + return tex_2d->gl_texture; +} + +void +_cogl_texture_2d_gl_generate_mipmap (CoglTexture2D *tex_2d) +{ + CoglContext *ctx = COGL_TEXTURE (tex_2d)->context; + + _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, + tex_2d->gl_texture, + tex_2d->is_foreign); + + /* 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)) + ctx->texture_driver->gl_generate_mipmaps (ctx, GL_TEXTURE_2D); +#if defined(HAVE_COGL_GLES) || defined(HAVE_COGL_GL) + else + { + GE( ctx, glTexParameteri (GL_TEXTURE_2D, + GL_GENERATE_MIPMAP, + GL_TRUE) ); + GE( ctx, glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, 1, 1, + tex_2d->first_pixel.gl_format, + tex_2d->first_pixel.gl_type, + tex_2d->first_pixel.data) ); + GE( ctx, glTexParameteri (GL_TEXTURE_2D, + GL_GENERATE_MIPMAP, + GL_FALSE) ); + } +#endif +} + +void +_cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d, + CoglBitmap *bmp, + int dst_x, + int dst_y, + int src_x, + int src_y, + int width, + int height) +{ + CoglTexture *tex = COGL_TEXTURE (tex_2d); + CoglContext *ctx = tex->context; + GLenum gl_format; + GLenum gl_type; + uint8_t *data; + + bmp = _cogl_texture_prepare_for_upload (bmp, + cogl_texture_get_format (tex), + NULL, + NULL, + &gl_format, + &gl_type); + + /* If this touches the first pixel then we'll update our copy */ + if (dst_x == 0 && dst_y == 0 && + !cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) && + (data = _cogl_bitmap_map (bmp, COGL_BUFFER_ACCESS_READ, 0))) + { + CoglPixelFormat bpp = + _cogl_pixel_format_get_bytes_per_pixel (cogl_bitmap_get_format (bmp)); + tex_2d->first_pixel.gl_format = gl_format; + tex_2d->first_pixel.gl_type = gl_type; + memcpy (tex_2d->first_pixel.data, + data + cogl_bitmap_get_rowstride (bmp) * src_y + bpp * src_x, + bpp); + + _cogl_bitmap_unmap (bmp); + } + + /* Send data to GL */ + ctx->texture_driver->upload_subregion_to_gl (ctx, + GL_TEXTURE_2D, + tex_2d->gl_texture, + FALSE, + src_x, src_y, + dst_x, dst_y, + width, height, + bmp, + gl_format, + gl_type); + + cogl_object_unref (bmp); +} + +void +_cogl_texture_2d_gl_get_data (CoglTexture2D *tex_2d, + CoglPixelFormat format, + size_t rowstride, + uint8_t *data) +{ + CoglContext *ctx = COGL_TEXTURE (tex_2d)->context; + int bpp; + GLenum gl_format; + GLenum gl_type; + + bpp = _cogl_pixel_format_get_bytes_per_pixel (format); + + ctx->driver_vtable->pixel_format_to_gl (ctx, + format, + NULL, /* internal format */ + &gl_format, + &gl_type); + + ctx->texture_driver->prep_gl_for_pixels_download (ctx, + rowstride, + tex_2d->width, + bpp); + + _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, + tex_2d->gl_texture, + tex_2d->is_foreign); + + ctx->texture_driver->gl_get_tex_image (ctx, + GL_TEXTURE_2D, + gl_format, + gl_type, + data); +} diff --git a/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/driver/gl/gl/cogl-driver-gl.c index 593942bc4..7bb172637 100644 --- a/cogl/driver/gl/gl/cogl-driver-gl.c +++ b/cogl/driver/gl/gl/cogl-driver-gl.c @@ -32,8 +32,9 @@ #include "cogl-context-private.h" #include "cogl-feature-private.h" #include "cogl-renderer-private.h" -#include "cogl-framebuffer-gl-private.h" #include "cogl-error-private.h" +#include "cogl-framebuffer-gl-private.h" +#include "cogl-texture-2d-gl-private.h" static CoglBool _cogl_driver_pixel_format_from_gl_internal (CoglContext *context, @@ -534,4 +535,17 @@ _cogl_driver_gl = _cogl_framebuffer_gl_discard_buffers, _cogl_framebuffer_gl_draw_attributes, _cogl_framebuffer_gl_draw_indexed_attributes, + _cogl_texture_2d_gl_free, + _cogl_texture_2d_gl_can_create, + _cogl_texture_2d_gl_init, + _cogl_texture_2d_gl_new_with_size, + _cogl_texture_2d_gl_new_from_bitmap, +#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) + _cogl_egl_texture_2d_gl_new_from_image, +#endif + _cogl_texture_2d_gl_copy_from_framebuffer, + _cogl_texture_2d_gl_get_gl_handle, + _cogl_texture_2d_gl_generate_mipmap, + _cogl_texture_2d_gl_copy_from_bitmap, + _cogl_texture_2d_gl_get_data, }; diff --git a/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/driver/gl/gles/cogl-driver-gles.c index d3e557cd4..b8c0168d9 100644 --- a/cogl/driver/gl/gles/cogl-driver-gles.c +++ b/cogl/driver/gl/gles/cogl-driver-gles.c @@ -33,6 +33,7 @@ #include "cogl-renderer-private.h" #include "cogl-private.h" #include "cogl-framebuffer-gl-private.h" +#include "cogl-texture-2d-gl-private.h" #ifndef GL_UNSIGNED_INT_24_8 #define GL_UNSIGNED_INT_24_8 0x84FA @@ -352,4 +353,17 @@ _cogl_driver_gles = _cogl_framebuffer_gl_discard_buffers, _cogl_framebuffer_gl_draw_attributes, _cogl_framebuffer_gl_draw_indexed_attributes, + _cogl_texture_2d_gl_free, + _cogl_texture_2d_gl_can_create, + _cogl_texture_2d_gl_init, + _cogl_texture_2d_gl_new_with_size, + _cogl_texture_2d_gl_new_from_bitmap, +#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) + _cogl_egl_texture_2d_gl_new_from_image, +#endif + _cogl_texture_2d_gl_copy_from_framebuffer, + _cogl_texture_2d_gl_get_gl_handle, + _cogl_texture_2d_gl_generate_mipmap, + _cogl_texture_2d_gl_copy_from_bitmap, + NULL, /* texture_2d_get_data */ };