Add a Cogl texture 3D backend

This adds a publicly exposed experimental API for a 3D texture
backend. There is a feature flag which can be checked for whether 3D
textures are supported. Although we require OpenGL 1.2 which has 3D
textures in core, GLES only provides them through an extension so the
feature can be used to detect that.

The textures can be created with one of two new API functions :-

cogl_texture_3d_new_with_size

 and

cogl_texture_3d_new_from_data

There is also internally a new_from_bitmap function. new_from_data is
implemented in terms of this function.

The two constructors are effectively the only way to upload data to a
3D texture. It does not work to call glTexImage2D with the
GL_TEXTURE_3D target so the virtual for cogl_texture_set_region does
nothing. It would be possible to make cogl_texture_get_data do
something sensible like returning all of the images as a single long
image but this is not currently implemented and instead the virtual
just always fails. We may want to add API specific to the 3D texture
backend to get and set a sub region of the texture.

All of those three functions can throw a GError. This will happen if
the GPU does not support 3D textures or it does not support NPOTs and
an NPOT size is requested. It will also fail if the FBO extension is
not supported and the COGL_TEXTURE_NO_AUTO_MIPMAP flag is not
given. This could be avoided by copying the code for the
GL_GENERATE_MIPMAP TexParameter fallback, but in the interests of
keeping the code simple this is not yet done.

This adds a couple of functions to cogl-texture-driver for uploading
3D data and querying the 3D proxy
texture. prep_gl_for_pixels_upload_full now also takes sets the
GL_UNPACK_IMAGE_HEIGHT parameter so that 3D textures can have padding
between the images. Whenever 3D texture is uploading, both the height
of the images and the height of all of the data is specified (either
explicitly or implicilty from the CoglBitmap) so that the image height
can be deduced by dividing by the depth.
This commit is contained in:
Neil Roberts 2010-07-01 22:04:59 +01:00
parent 159c7ed7e5
commit 5288f6d88d
16 changed files with 1230 additions and 24 deletions

View File

@ -68,6 +68,7 @@ cogl_public_h = \
$(srcdir)/cogl-pixel-array.h \ $(srcdir)/cogl-pixel-array.h \
$(srcdir)/cogl-shader.h \ $(srcdir)/cogl-shader.h \
$(srcdir)/cogl-texture.h \ $(srcdir)/cogl-texture.h \
$(srcdir)/cogl-texture-3d.h \
$(srcdir)/cogl-types.h \ $(srcdir)/cogl-types.h \
$(srcdir)/cogl-vertex-buffer.h \ $(srcdir)/cogl-vertex-buffer.h \
$(srcdir)/cogl.h \ $(srcdir)/cogl.h \
@ -132,11 +133,13 @@ cogl_sources_c = \
$(srcdir)/cogl-texture-private.h \ $(srcdir)/cogl-texture-private.h \
$(srcdir)/cogl-texture-2d-private.h \ $(srcdir)/cogl-texture-2d-private.h \
$(srcdir)/cogl-texture-2d-sliced-private.h \ $(srcdir)/cogl-texture-2d-sliced-private.h \
$(srcdir)/cogl-texture-3d-private.h \
$(srcdir)/cogl-texture-driver.h \ $(srcdir)/cogl-texture-driver.h \
$(srcdir)/cogl-sub-texture.c \ $(srcdir)/cogl-sub-texture.c \
$(srcdir)/cogl-texture.c \ $(srcdir)/cogl-texture.c \
$(srcdir)/cogl-texture-2d.c \ $(srcdir)/cogl-texture-2d.c \
$(srcdir)/cogl-texture-2d-sliced.c \ $(srcdir)/cogl-texture-2d-sliced.c \
$(srcdir)/cogl-texture-3d.c \
$(srcdir)/cogl-texture-rectangle-private.h \ $(srcdir)/cogl-texture-rectangle-private.h \
$(srcdir)/cogl-texture-rectangle.c \ $(srcdir)/cogl-texture-rectangle.c \
$(srcdir)/cogl-atlas.h \ $(srcdir)/cogl-atlas.h \

View File

@ -68,6 +68,11 @@
#define glUseProgram ctx->drv.pf_glUseProgram #define glUseProgram ctx->drv.pf_glUseProgram
#endif #endif
/* This might not be defined on GLES */
#ifndef GL_TEXTURE_3D
#define GL_TEXTURE_3D 0x806F
#endif
typedef struct _CoglMaterialBackendARBfpPrivate typedef struct _CoglMaterialBackendARBfpPrivate
{ {
CoglMaterial *authority_cache; CoglMaterial *authority_cache;
@ -415,6 +420,8 @@ gl_target_to_arbfp_string (GLenum gl_target)
else if (gl_target == GL_TEXTURE_RECTANGLE_ARB) else if (gl_target == GL_TEXTURE_RECTANGLE_ARB)
return "RECT"; return "RECT";
#endif #endif
else if (gl_target == GL_TEXTURE_3D)
return "3D";
else else
return "2D"; return "2D";
} }

View File

@ -0,0 +1,96 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2010 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 <http://www.gnu.org/licenses/>.
*
* Authors:
* Neil Roberts <neil@linux.intel.com>
*/
#ifndef __COGL_TEXTURE_3D_PRIVATE_H
#define __COGL_TEXTURE_3D_PRIVATE_H
#include "cogl-handle.h"
#include "cogl-material-private.h"
#include "cogl-texture-private.h"
#define COGL_TEXTURE_3D(tex) ((CoglTexture3D *) tex)
typedef struct _CoglTexture3D CoglTexture3D;
struct _CoglTexture3D
{
CoglTexture _parent;
/* The internal format of the GL texture represented as a
CoglPixelFormat */
CoglPixelFormat format;
/* The internal format of the GL texture represented as a GL enum */
GLenum gl_format;
/* The texture object number */
GLuint gl_texture;
int width;
int height;
int depth;
GLenum min_filter;
GLenum mag_filter;
GLint wrap_mode_s;
GLint wrap_mode_t;
GLint wrap_mode_r;
gboolean auto_mipmap;
gboolean mipmaps_dirty;
};
GQuark
_cogl_handle_texture_3d_get_type (void);
/*
* cogl_texture_3d_new_from_bitmap:
* @bmp_handle: A #CoglHandle to a bitmap.
* @height: height of the texture in pixels.
* @depth: depth of the texture in pixels.
* @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE
* @internal_format: the #CoglPixelFormat that will be used for storing
* the buffer on the GPU. If COGL_PIXEL_FORMAT_ANY is given then a
* premultiplied format similar to the format of the source data will
* be used. The default blending equations of Cogl expect premultiplied
* color data; the main use of passing a non-premultiplied format here
* is if you have non-premultiplied source data and are going to adjust
* the blend mode (see cogl_material_set_blend()) or use the data for
* something other than straight blending.
* @error: A GError return location.
*
* Creates a new 3D texture and initializes it with the images in
* @bmp_handle. The images are assumed to be packed together after one
* another in the increasing y axis. The height of individual image is
* given as @height and the number of images is given in @depth. The
* actual height of the bitmap can be larger than @height × @depth. In
* this case it assumes there is padding between the images.
*
* Return value: the newly created texture or %COGL_INVALID_HANDLE if
* there was an error.
*/
CoglHandle
_cogl_texture_3d_new_from_bitmap (CoglHandle bmp_handle,
unsigned int height,
unsigned int depth,
CoglTextureFlags flags,
CoglPixelFormat internal_format,
GError **error);
#endif /* __COGL_TEXTURE_3D_PRIVATE_H */

657
cogl/cogl-texture-3d.c Normal file
View File

@ -0,0 +1,657 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2010 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 <http://www.gnu.org/licenses/>.
*
* Authors:
* Neil Roberts <neil@linux.intel.com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "cogl.h"
#include "cogl-internal.h"
#include "cogl-util.h"
#include "cogl-texture-private.h"
#include "cogl-texture-2d-private.h"
#include "cogl-texture-3d-private.h"
#include "cogl-texture-driver.h"
#include "cogl-context.h"
#include "cogl-handle.h"
#include "cogl-journal-private.h"
#include "cogl-material-private.h"
#include <string.h>
#include <math.h>
/* These might not be defined on GLES */
#ifndef GL_TEXTURE_3D
#define GL_TEXTURE_3D 0x806F
#endif
#ifndef GL_TEXTURE_WRAP_R
#define GL_TEXTURE_WRAP_R 0x8072
#endif
#define glTexImage3D ctx->drv.pf_glTexImage3D
static void _cogl_texture_3d_free (CoglTexture3D *tex_3d);
COGL_TEXTURE_DEFINE (Texture3D, texture_3d);
static const CoglTextureVtable cogl_texture_3d_vtable;
typedef struct _CoglTexture3DManualRepeatData
{
CoglTexture3D *tex_3d;
CoglTextureSliceCallback callback;
void *user_data;
} CoglTexture3DManualRepeatData;
static void
_cogl_texture_3d_wrap_coords (float t_1, float t_2,
float *out_t_1, float *out_t_2)
{
float int_part;
/* Wrap t_1 and t_2 to the range [0,1] */
modff (t_1 < t_2 ? t_1 : t_2, &int_part);
t_1 -= int_part;
t_2 -= int_part;
if (cogl_util_float_signbit (int_part))
{
*out_t_1 = 1.0f + t_1;
*out_t_2 = 1.0f + t_2;
}
else
{
*out_t_1 = t_1;
*out_t_2 = t_2;
}
}
static void
_cogl_texture_3d_manual_repeat_cb (const float *coords,
void *user_data)
{
CoglTexture3DManualRepeatData *data = user_data;
float slice_coords[4];
_cogl_texture_3d_wrap_coords (coords[0], coords[2],
slice_coords + 0, slice_coords + 2);
_cogl_texture_3d_wrap_coords (coords[1], coords[3],
slice_coords + 1, slice_coords + 3);
data->callback (COGL_TEXTURE (data->tex_3d),
data->tex_3d->gl_texture,
GL_TEXTURE_3D,
slice_coords,
coords,
data->user_data);
}
static void
_cogl_texture_3d_foreach_sub_texture_in_region (
CoglTexture *tex,
float virtual_tx_1,
float virtual_ty_1,
float virtual_tx_2,
float virtual_ty_2,
CoglTextureSliceCallback callback,
void *user_data)
{
CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex);
CoglTexture3DManualRepeatData data;
data.tex_3d = tex_3d;
data.callback = callback;
data.user_data = user_data;
/* We need to implement manual repeating because if Cogl is calling
this function then it will set the wrap mode to GL_CLAMP_TO_EDGE
and hardware repeating can't be done */
_cogl_texture_iterate_manual_repeats (_cogl_texture_3d_manual_repeat_cb,
virtual_tx_1, virtual_ty_1,
virtual_tx_2, virtual_ty_2,
&data);
}
static void
_cogl_texture_3d_set_wrap_mode_parameters (CoglTexture *tex,
GLenum wrap_mode_s,
GLenum wrap_mode_t,
GLenum wrap_mode_r)
{
CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex);
/* Only set the wrap mode if it's different from the current value
to avoid too many GL calls. */
if (tex_3d->wrap_mode_s != wrap_mode_s ||
tex_3d->wrap_mode_t != wrap_mode_t ||
tex_3d->wrap_mode_r != wrap_mode_r)
{
_cogl_bind_gl_texture_transient (GL_TEXTURE_3D,
tex_3d->gl_texture,
FALSE);
GE( glTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, wrap_mode_s) );
GE( glTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, wrap_mode_t) );
GE( glTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, wrap_mode_r) );
tex_3d->wrap_mode_s = wrap_mode_s;
tex_3d->wrap_mode_t = wrap_mode_t;
tex_3d->wrap_mode_r = wrap_mode_r;
}
}
static void
_cogl_texture_3d_free (CoglTexture3D *tex_3d)
{
_cogl_delete_gl_texture (tex_3d->gl_texture);
/* Chain up */
_cogl_texture_free (COGL_TEXTURE (tex_3d));
}
static CoglTexture3D *
_cogl_texture_3d_create_base (unsigned int width,
unsigned int height,
unsigned int depth,
CoglTextureFlags flags,
CoglPixelFormat internal_format)
{
CoglTexture3D *tex_3d = g_new (CoglTexture3D, 1);
CoglTexture *tex = COGL_TEXTURE (tex_3d);
tex->vtable = &cogl_texture_3d_vtable;
tex_3d->width = width;
tex_3d->height = height;
tex_3d->depth = depth;
tex_3d->mipmaps_dirty = TRUE;
tex_3d->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0;
/* We default to GL_LINEAR for both filters */
tex_3d->min_filter = GL_LINEAR;
tex_3d->mag_filter = GL_LINEAR;
/* Wrap mode not yet set */
tex_3d->wrap_mode_s = GL_FALSE;
tex_3d->wrap_mode_t = GL_FALSE;
tex_3d->wrap_mode_r = GL_FALSE;
tex_3d->format = internal_format;
return tex_3d;
}
static gboolean
_cogl_texture_3d_can_create (unsigned int width,
unsigned int height,
unsigned int depth,
CoglTextureFlags flags,
CoglPixelFormat internal_format,
GError **error)
{
GLenum gl_intformat;
GLenum gl_type;
/* This should only happen on GLES */
if (!cogl_features_available (COGL_FEATURE_TEXTURE_3D))
{
g_set_error (error,
COGL_ERROR,
COGL_ERROR_UNSUPPORTED,
"3D textures are not supported by the GPU");
return FALSE;
}
/* If the driver doesn't support glGenerateMipmap then we need to
store a copy of the first pixels to cause an update. Instead of
duplicating the code here we'll just make it throw an error */
if ((flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0 &&
!cogl_features_available (COGL_FEATURE_OFFSCREEN))
{
g_set_error (error,
COGL_ERROR,
COGL_ERROR_UNSUPPORTED,
"Auto mipmapping was requested but this is not supported "
"by Cogl with this driver");
return FALSE;
}
/* If NPOT textures aren't supported then the size must be a power
of two */
if (!cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) &&
(!_cogl_util_is_pot (width) ||
!_cogl_util_is_pot (height) ||
!_cogl_util_is_pot (depth)))
{
g_set_error (error,
COGL_ERROR,
COGL_ERROR_UNSUPPORTED,
"A non-power-of-two size was requested but this is not "
"supported by the GPU");
return FALSE;
}
_cogl_pixel_format_to_gl (internal_format,
&gl_intformat,
NULL,
&gl_type);
/* Check that the driver can create a texture with that size */
if (!_cogl_texture_driver_size_supported_3d (GL_TEXTURE_3D,
gl_intformat,
gl_type,
width,
height,
depth))
{
g_set_error (error,
COGL_ERROR,
COGL_ERROR_UNSUPPORTED,
"The requested dimensions are not supported by the GPU");
return FALSE;
}
return TRUE;
}
CoglHandle
cogl_texture_3d_new_with_size (unsigned int width,
unsigned int height,
unsigned int depth,
CoglTextureFlags flags,
CoglPixelFormat internal_format,
GError **error)
{
CoglTexture3D *tex_3d;
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
_COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
/* Since no data, we need some internal format */
if (internal_format == COGL_PIXEL_FORMAT_ANY)
internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
if (!_cogl_texture_3d_can_create (width, height, depth,
flags, internal_format,
error))
return COGL_INVALID_HANDLE;
internal_format = _cogl_pixel_format_to_gl (internal_format,
&gl_intformat,
&gl_format,
&gl_type);
tex_3d = _cogl_texture_3d_create_base (width, height, depth,
flags, internal_format);
_cogl_texture_driver_gen (GL_TEXTURE_3D, 1, &tex_3d->gl_texture);
_cogl_bind_gl_texture_transient (GL_TEXTURE_3D,
tex_3d->gl_texture,
FALSE);
GE( glTexImage3D (GL_TEXTURE_3D, 0, gl_intformat,
width, height, depth, 0, gl_format, gl_type, NULL) );
return _cogl_texture_3d_handle_new (tex_3d);
}
CoglHandle
_cogl_texture_3d_new_from_bitmap (CoglHandle bmp_handle,
unsigned int height,
unsigned int depth,
CoglTextureFlags flags,
CoglPixelFormat internal_format,
GError **error)
{
CoglTexture3D *tex_3d;
CoglBitmap *bmp = (CoglBitmap *) bmp_handle;
CoglBitmap dst_bmp;
gboolean dst_bmp_owner;
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
_COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
internal_format = _cogl_texture_determine_internal_format (bmp->format,
internal_format);
if (!_cogl_texture_3d_can_create (bmp->width, height, depth,
flags, internal_format,
error))
return COGL_INVALID_HANDLE;
if (!_cogl_texture_prepare_for_upload (bmp,
internal_format,
&internal_format,
&dst_bmp,
&dst_bmp_owner,
&gl_intformat,
&gl_format,
&gl_type))
{
g_set_error (error, COGL_BITMAP_ERROR, COGL_BITMAP_ERROR_FAILED,
"Bitmap conversion failed");
return COGL_INVALID_HANDLE;
}
tex_3d = _cogl_texture_3d_create_base (dst_bmp.width, height, depth,
flags, internal_format);
_cogl_texture_driver_gen (GL_TEXTURE_3D, 1, &tex_3d->gl_texture);
_cogl_texture_driver_upload_to_gl_3d (GL_TEXTURE_3D,
tex_3d->gl_texture,
FALSE, /* is_foreign */
height,
depth,
&dst_bmp,
gl_intformat,
gl_format,
gl_type);
tex_3d->gl_format = gl_intformat;
if (dst_bmp_owner)
g_free (dst_bmp.data);
return _cogl_texture_3d_handle_new (tex_3d);
}
CoglHandle
cogl_texture_3d_new_from_data (unsigned int width,
unsigned int height,
unsigned int depth,
CoglTextureFlags flags,
CoglPixelFormat format,
CoglPixelFormat internal_format,
unsigned int rowstride,
unsigned int image_stride,
const guint8 *data,
GError **error)
{
CoglBitmap bitmap;
gboolean bitmap_owned = FALSE;
CoglHandle ret;
/* These are considered a programmer errors so we won't set a
GError. It would be nice if this was a g_return_if_fail but the
rest of Cogl isn't using that */
if (format == COGL_PIXEL_FORMAT_ANY)
return COGL_INVALID_HANDLE;
if (data == NULL)
return COGL_INVALID_HANDLE;
/* Rowstride from width if not given */
if (rowstride == 0)
rowstride = width * _cogl_get_format_bpp (format);
/* Image stride from height and rowstride if not given */
if (image_stride == 0)
image_stride = height * rowstride;
if (image_stride < rowstride * height)
return COGL_INVALID_HANDLE;
/* GL doesn't support uploading when the image_stride isn't a
multiple of the rowstride. If this happens we'll just pack the
image into a new bitmap. The documentation for this function
recommends avoiding this situation. */
if (image_stride % rowstride != 0)
{
int z, y;
bitmap.width = width;
bitmap.height = depth * height;
bitmap.rowstride = _cogl_get_format_bpp (format) * width;
bitmap.data = g_malloc (bitmap.rowstride * height * depth);
bitmap.format = format;
/* Copy all of the images in */
for (z = 0; z < depth; z++)
for (y = 0; y < height; y++)
memcpy (bitmap.data + (z * bitmap.rowstride * height +
bitmap.rowstride * y),
data + z * image_stride + rowstride * y,
bitmap.rowstride);
bitmap_owned = TRUE;
}
else
{
/* Wrap the data into a bitmap */
bitmap.width = width;
bitmap.height = image_stride / rowstride * depth;
bitmap.data = (guint8 *) data;
bitmap.format = format;
bitmap.rowstride = rowstride;
}
ret = _cogl_texture_3d_new_from_bitmap (&bitmap,
height,
depth,
flags,
internal_format,
error);
if (bitmap_owned)
g_free (bitmap.data);
return ret;
}
GQuark
cogl_texture_3d_error_quark (void)
{
return g_quark_from_static_string ("cogl-texture-3d-error-quark");
}
static int
_cogl_texture_3d_get_max_waste (CoglTexture *tex)
{
return -1;
}
static gboolean
_cogl_texture_3d_is_sliced (CoglTexture *tex)
{
return FALSE;
}
static gboolean
_cogl_texture_3d_can_hardware_repeat (CoglTexture *tex)
{
return TRUE;
}
static void
_cogl_texture_3d_transform_coords_to_gl (CoglTexture *tex,
float *s,
float *t)
{
/* The texture coordinates map directly so we don't need to do
anything */
}
static CoglTransformResult
_cogl_texture_3d_transform_quad_coords_to_gl (CoglTexture *tex,
float *coords)
{
/* The texture coordinates map directly so we don't need to do
anything other than check for repeats */
gboolean need_repeat = FALSE;
int i;
for (i = 0; i < 4; i++)
if (coords[i] < 0.0f || coords[i] > 1.0f)
need_repeat = TRUE;
return (need_repeat ? COGL_TRANSFORM_HARDWARE_REPEAT
: COGL_TRANSFORM_NO_REPEAT);
}
static gboolean
_cogl_texture_3d_get_gl_texture (CoglTexture *tex,
GLuint *out_gl_handle,
GLenum *out_gl_target)
{
CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex);
if (out_gl_handle)
*out_gl_handle = tex_3d->gl_texture;
if (out_gl_target)
*out_gl_target = GL_TEXTURE_3D;
return TRUE;
}
static void
_cogl_texture_3d_set_filters (CoglTexture *tex,
GLenum min_filter,
GLenum mag_filter)
{
CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex);
if (min_filter == tex_3d->min_filter
&& mag_filter == tex_3d->mag_filter)
return;
/* Store new values */
tex_3d->min_filter = min_filter;
tex_3d->mag_filter = mag_filter;
/* Apply new filters to the texture */
_cogl_bind_gl_texture_transient (GL_TEXTURE_3D,
tex_3d->gl_texture,
FALSE);
GE( glTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, mag_filter) );
GE( glTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, min_filter) );
}
static void
_cogl_texture_3d_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags)
{
CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex);
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* Only update if the mipmaps are dirty */
if ((flags & COGL_TEXTURE_NEEDS_MIPMAP) &&
tex_3d->auto_mipmap && tex_3d->mipmaps_dirty)
{
_cogl_bind_gl_texture_transient (GL_TEXTURE_3D,
tex_3d->gl_texture,
FALSE);
/* glGenerateMipmap is defined in the FBO extension. We only allow
CoglTexture3D instances to be created if this feature is
available so we don't need to check for the extension */
_cogl_texture_driver_gl_generate_mipmaps (GL_TEXTURE_3D);
tex_3d->mipmaps_dirty = FALSE;
}
}
static void
_cogl_texture_3d_ensure_non_quad_rendering (CoglTexture *tex)
{
/* Nothing needs to be done */
}
static gboolean
_cogl_texture_3d_set_region (CoglTexture *tex,
int src_x,
int src_y,
int dst_x,
int dst_y,
unsigned int dst_width,
unsigned int dst_height,
CoglBitmap *bmp)
{
/* This function doesn't really make sense for 3D textures because
it can't specify which image to upload to */
return FALSE;
}
static int
_cogl_texture_3d_get_data (CoglTexture *tex,
CoglPixelFormat format,
unsigned int rowstride,
guint8 *data)
{
/* FIXME: we could probably implement this by assuming the data is
big enough to hold all of the images and that there is no stride
between the images. However it would be better to have an API
that can provide an image stride and this function probably isn't
particularly useful anyway so for now it just reports failure */
return 0;
}
static CoglPixelFormat
_cogl_texture_3d_get_format (CoglTexture *tex)
{
return COGL_TEXTURE_3D (tex)->format;
}
static GLenum
_cogl_texture_3d_get_gl_format (CoglTexture *tex)
{
return COGL_TEXTURE_3D (tex)->gl_format;
}
static int
_cogl_texture_3d_get_width (CoglTexture *tex)
{
return COGL_TEXTURE_3D (tex)->width;
}
static int
_cogl_texture_3d_get_height (CoglTexture *tex)
{
return COGL_TEXTURE_3D (tex)->height;
}
static const CoglTextureVtable
cogl_texture_3d_vtable =
{
_cogl_texture_3d_set_region,
_cogl_texture_3d_get_data,
_cogl_texture_3d_foreach_sub_texture_in_region,
_cogl_texture_3d_get_max_waste,
_cogl_texture_3d_is_sliced,
_cogl_texture_3d_can_hardware_repeat,
_cogl_texture_3d_transform_coords_to_gl,
_cogl_texture_3d_transform_quad_coords_to_gl,
_cogl_texture_3d_get_gl_texture,
_cogl_texture_3d_set_filters,
_cogl_texture_3d_pre_paint,
_cogl_texture_3d_ensure_non_quad_rendering,
_cogl_texture_3d_set_wrap_mode_parameters,
_cogl_texture_3d_get_format,
_cogl_texture_3d_get_gl_format,
_cogl_texture_3d_get_width,
_cogl_texture_3d_get_height,
NULL /* is_foreign */
};

154
cogl/cogl-texture-3d.h Normal file
View File

@ -0,0 +1,154 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2010 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, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Authors:
* Neil Roberts <neil@linux.intel.com>
*/
#if !defined(__COGL_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <cogl/cogl.h> can be included directly."
#endif
#ifndef __COGL_TEXTURE_3D_H
#define __COGL_TEXTURE_3D_H
#include <glib.h>
G_BEGIN_DECLS
/**
* SECTION:cogl-texture-3d
* @short_description: Fuctions for creating and manipulating 3D textures
*
* These functions allow 3D textures to be used. 3D textures can be
* thought of as layers of 2D images arranged into a cuboid
* shape. When choosing a texel from the texture, Cogl will take into
* account the 'r' texture coordinate to select one of the images.
*/
/* All of the cogl-texture-3d API is currently experimental so we
* suffix the actual symbols with _EXP so if somone is monitoring for
* ABI changes it will hopefully be clearer to them what's going on if
* any of the symbols dissapear at a later date.
*/
#define cogl_texture_3d_new_with_size cogl_texture_3d_new_with_size_EXP
#define cogl_texture_3d_new_from_data cogl_texture_3d_new_from_data_EXP
#define cogl_is_texture_3d cogl_is_texture_3d_EXP
/**
* cogl_texture_3d_new_with_size:
* @width: width of the texture in pixels.
* @height: height of the texture in pixels.
* @depth: depth of the texture in pixels.
* @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE
* @internal_format: the #CoglPixelFormat to use for the GPU
* storage of the texture.
* @error: A GError return location.
*
* Creates a new Cogl 3D texture with the specified dimensions and
* pixel format.
*
* Note that this function will throw a #GError if
* %COGL_FEATURE_TEXTURE_3D is not advertised. It can also fail if the
* requested dimensions are not supported by the GPU.
*
* Return value: a new handle to a CoglTexture3D object or
* %COGL_INVALID_HANDLE on failure.
* Since: 1.4
* Stability: Unstable
*/
CoglHandle
cogl_texture_3d_new_with_size (unsigned int width,
unsigned int height,
unsigned int depth,
CoglTextureFlags flags,
CoglPixelFormat internal_format,
GError **error);
/**
* cogl_texture_3d_new_from_data:
* @width: width of the texture in pixels.
* @height: height of the texture in pixels.
* @depth: depth of the texture in pixels.
* @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE
* @format: the #CoglPixelFormat the buffer is stored in in RAM
* @internal_format: the #CoglPixelFormat that will be used for storing
* the buffer on the GPU. If COGL_PIXEL_FORMAT_ANY is given then a
* premultiplied format similar to the format of the source data will
* be used. The default blending equations of Cogl expect premultiplied
* color data; the main use of passing a non-premultiplied format here
* is if you have non-premultiplied source data and are going to adjust
* the blend mode (see cogl_material_set_blend()) or use the data for
* something other than straight blending.
* @rowstride: the memory offset in bytes between the starts of
* scanlines in @data or 0 to infer it from the width and format
* @image_stride: the number of bytes from one image to the next. This
* can be used to add padding between the images in a similar way
* that the rowstride can be used to add padding between
* rows. Alternatively 0 can be passed to infer the @image_stride
* from the @height.
* @data: pointer the memory region where the source buffer resides
* @error: A GError return location.
*
* Creates a new 3D texture and initializes it with @data. The data is
* assumed to be packed array of @depth images. There can be padding
* between the images using @image_stride.
*
* Note that this function will throw a #GError if
* %COGL_FEATURE_TEXTURE_3D is not advertised. It can also fail if the
* requested dimensions are not supported by the GPU.
*
* Return value: the newly created texture or %COGL_INVALID_HANDLE if
* there was an error.
* Since: 1.4
* Stability: Unstable
*/
CoglHandle
cogl_texture_3d_new_from_data (unsigned int width,
unsigned int height,
unsigned int depth,
CoglTextureFlags flags,
CoglPixelFormat format,
CoglPixelFormat internal_format,
unsigned int rowstride,
unsigned int image_stride,
const guint8 *data,
GError **error);
/**
* cogl_is_texture_3d:
* @handle: a #CoglHandle
*
* Checks whether @handle is a #CoglHandle for a 3D texture.
*
* Return value: %TRUE if the passed handle represents a 3D texture
* and %FALSE otherwise
*
* Since: 1.4
* Stability: Unstable
*/
gboolean
cogl_is_texture_3d (CoglHandle handle);
G_END_DECLS
#endif /* __COGL_TEXTURE_3D_H */

View File

@ -87,6 +87,24 @@ _cogl_texture_driver_upload_to_gl (GLenum gl_target,
GLuint source_gl_format, GLuint source_gl_format,
GLuint source_gl_type); GLuint source_gl_type);
/*
* Replaces the contents of the GL texture with the entire bitmap. The
* width of the texture is inferred from the bitmap. The height and
* depth of the texture is given directly. The 'image_height' (which
* is the number of rows between images) is inferred by dividing the
* height of the bitmap by the depth.
*/
void
_cogl_texture_driver_upload_to_gl_3d (GLenum gl_target,
GLuint gl_handle,
gboolean is_foreign,
GLint height,
GLint depth,
CoglBitmap *source_bmp,
GLint internal_gl_format,
GLuint source_gl_format,
GLuint source_gl_type);
/* /*
* This sets up the glPixelStore state for an download to a destination with * This sets up the glPixelStore state for an download to a destination with
* the same size, and with no offset. * the same size, and with no offset.
@ -131,6 +149,14 @@ _cogl_texture_driver_size_supported (GLenum gl_target,
int width, int width,
int height); int height);
gboolean
_cogl_texture_driver_size_supported_3d (GLenum gl_target,
GLenum gl_format,
GLenum gl_type,
int width,
int height,
int depth);
/* /*
* This driver abstraction is needed because GLES doesn't support setting * This driver abstraction is needed because GLES doesn't support setting
* a texture border color. * a texture border color.

View File

@ -250,6 +250,7 @@ typedef enum { /*< prefix=COGL_PIXEL_FORMAT >*/
* hardware. * hardware.
* @COGL_FEATURE_POINT_SPRITE: Whether * @COGL_FEATURE_POINT_SPRITE: Whether
* cogl_material_set_layer_point_sprite_coords_enabled() is supported. * cogl_material_set_layer_point_sprite_coords_enabled() is supported.
* @COGL_FEATURE_TEXTURE_3D: 3D texture support
* *
* Flags for the supported features. * Flags for the supported features.
* *
@ -274,7 +275,8 @@ typedef enum
COGL_FEATURE_TEXTURE_NPOT_BASIC = (1 << 15), COGL_FEATURE_TEXTURE_NPOT_BASIC = (1 << 15),
COGL_FEATURE_TEXTURE_NPOT_MIPMAP = (1 << 16), COGL_FEATURE_TEXTURE_NPOT_MIPMAP = (1 << 16),
COGL_FEATURE_TEXTURE_NPOT_REPEAT = (1 << 17), COGL_FEATURE_TEXTURE_NPOT_REPEAT = (1 << 17),
COGL_FEATURE_POINT_SPRITE = (1 << 18) COGL_FEATURE_POINT_SPRITE = (1 << 18),
COGL_FEATURE_TEXTURE_3D = (1 << 19)
} CoglFeatureFlags; } CoglFeatureFlags;
/** /**

View File

@ -54,6 +54,7 @@
#include <cogl/cogl-buffer.h> #include <cogl/cogl-buffer.h>
#include <cogl/cogl-pixel-array.h> #include <cogl/cogl-pixel-array.h>
#include <cogl/cogl-vector.h> #include <cogl/cogl-vector.h>
#include <cogl/cogl-texture-3d.h>
#endif #endif
G_BEGIN_DECLS G_BEGIN_DECLS

View File

@ -344,6 +344,20 @@ COGL_FEATURE_FUNCTION (void, glBlendColor,
GLclampf alpha)) GLclampf alpha))
COGL_FEATURE_END () COGL_FEATURE_END ()
COGL_FEATURE_BEGIN (texture_3d, 1, 2,
"\0",
"\0",
COGL_FEATURE_TEXTURE_3D,
0)
COGL_FEATURE_FUNCTION (void, glTexImage3D,
(GLenum target, GLint level,
GLint internalFormat,
GLsizei width, GLsizei height,
GLsizei depth, GLint border,
GLenum format, GLenum type,
const GLvoid *pixels))
COGL_FEATURE_END ()
/* Available in GL 1.3 or the multitexture extension. These are /* Available in GL 1.3 or the multitexture extension. These are
required */ required */
COGL_FEATURE_BEGIN (multitexture, 1, 3, COGL_FEATURE_BEGIN (multitexture, 1, 3,

View File

@ -47,6 +47,7 @@
#include <math.h> #include <math.h>
#define glGenerateMipmap ctx->drv.pf_glGenerateMipmap #define glGenerateMipmap ctx->drv.pf_glGenerateMipmap
#define glTexImage3D ctx->drv.pf_glTexImage3D
void void
_cogl_texture_driver_gen (GLenum gl_target, _cogl_texture_driver_gen (GLenum gl_target,
@ -65,20 +66,22 @@ _cogl_texture_driver_gen (GLenum gl_target,
switch (gl_target) switch (gl_target)
{ {
case GL_TEXTURE_2D: case GL_TEXTURE_2D:
/* GL_TEXTURE_MAG_FILTER defaults to GL_LINEAR, no need to set it */ case GL_TEXTURE_3D:
GE( glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) ); /* GL_TEXTURE_MAG_FILTER defaults to GL_LINEAR, no need to set it */
break; GE( glTexParameteri (gl_target,
GL_TEXTURE_MIN_FILTER,
GL_LINEAR) );
break;
case GL_TEXTURE_RECTANGLE_ARB: case GL_TEXTURE_RECTANGLE_ARB:
/* Texture rectangles already default to GL_LINEAR so nothing /* Texture rectangles already default to GL_LINEAR so nothing
needs to be done */ needs to be done */
break; break;
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }
} }
} }
@ -86,6 +89,7 @@ _cogl_texture_driver_gen (GLenum gl_target,
* source buffer */ * source buffer */
static void static void
prep_gl_for_pixels_upload_full (int pixels_rowstride, prep_gl_for_pixels_upload_full (int pixels_rowstride,
int image_height,
int pixels_src_x, int pixels_src_x,
int pixels_src_y, int pixels_src_y,
int pixels_bpp) int pixels_bpp)
@ -95,6 +99,9 @@ prep_gl_for_pixels_upload_full (int pixels_rowstride,
GE( glPixelStorei (GL_UNPACK_SKIP_PIXELS, pixels_src_x) ); GE( glPixelStorei (GL_UNPACK_SKIP_PIXELS, pixels_src_x) );
GE( glPixelStorei (GL_UNPACK_SKIP_ROWS, pixels_src_y) ); GE( glPixelStorei (GL_UNPACK_SKIP_ROWS, pixels_src_y) );
if (cogl_features_available (COGL_FEATURE_TEXTURE_3D))
GE( glPixelStorei (GL_UNPACK_IMAGE_HEIGHT, image_height) );
_cogl_texture_prep_gl_alignment_for_pixels_upload (pixels_rowstride); _cogl_texture_prep_gl_alignment_for_pixels_upload (pixels_rowstride);
} }
@ -102,13 +109,14 @@ void
_cogl_texture_driver_prep_gl_for_pixels_upload (int pixels_rowstride, _cogl_texture_driver_prep_gl_for_pixels_upload (int pixels_rowstride,
int pixels_bpp) int pixels_bpp)
{ {
prep_gl_for_pixels_upload_full (pixels_rowstride, 0, 0, pixels_bpp); prep_gl_for_pixels_upload_full (pixels_rowstride, 0, 0, 0, pixels_bpp);
} }
/* OpenGL - unlike GLES - can download pixel data into a sub region of /* OpenGL - unlike GLES - can download pixel data into a sub region of
* a larger destination buffer */ * a larger destination buffer */
static void static void
prep_gl_for_pixels_download_full (int pixels_rowstride, prep_gl_for_pixels_download_full (int pixels_rowstride,
int image_height,
int pixels_src_x, int pixels_src_x,
int pixels_src_y, int pixels_src_y,
int pixels_bpp) int pixels_bpp)
@ -118,6 +126,9 @@ prep_gl_for_pixels_download_full (int pixels_rowstride,
GE( glPixelStorei (GL_PACK_SKIP_PIXELS, pixels_src_x) ); GE( glPixelStorei (GL_PACK_SKIP_PIXELS, pixels_src_x) );
GE( glPixelStorei (GL_PACK_SKIP_ROWS, pixels_src_y) ); GE( glPixelStorei (GL_PACK_SKIP_ROWS, pixels_src_y) );
if (cogl_features_available (COGL_FEATURE_TEXTURE_3D))
GE( glPixelStorei (GL_PACK_IMAGE_HEIGHT, image_height) );
_cogl_texture_prep_gl_alignment_for_pixels_download (pixels_rowstride); _cogl_texture_prep_gl_alignment_for_pixels_download (pixels_rowstride);
} }
@ -125,7 +136,7 @@ void
_cogl_texture_driver_prep_gl_for_pixels_download (int pixels_rowstride, _cogl_texture_driver_prep_gl_for_pixels_download (int pixels_rowstride,
int pixels_bpp) int pixels_bpp)
{ {
prep_gl_for_pixels_download_full (pixels_rowstride, 0, 0, pixels_bpp); prep_gl_for_pixels_download_full (pixels_rowstride, 0, 0, 0, pixels_bpp);
} }
void void
@ -146,6 +157,7 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target,
/* Setup gl alignment to match rowstride and top-left corner */ /* Setup gl alignment to match rowstride and top-left corner */
prep_gl_for_pixels_upload_full (source_bmp->rowstride, prep_gl_for_pixels_upload_full (source_bmp->rowstride,
0,
src_x, src_x,
src_y, src_y,
bpp); bpp);
@ -172,7 +184,7 @@ _cogl_texture_driver_upload_to_gl (GLenum gl_target,
int bpp = _cogl_get_format_bpp (source_bmp->format); int bpp = _cogl_get_format_bpp (source_bmp->format);
/* Setup gl alignment to match rowstride and top-left corner */ /* Setup gl alignment to match rowstride and top-left corner */
prep_gl_for_pixels_upload_full (source_bmp->rowstride, 0, 0, bpp); prep_gl_for_pixels_upload_full (source_bmp->rowstride, 0, 0, 0, bpp);
_cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
@ -185,6 +197,40 @@ _cogl_texture_driver_upload_to_gl (GLenum gl_target,
source_bmp->data) ); source_bmp->data) );
} }
void
_cogl_texture_driver_upload_to_gl_3d (GLenum gl_target,
GLuint gl_handle,
gboolean is_foreign,
GLint height,
GLint depth,
CoglBitmap *source_bmp,
GLint internal_gl_format,
GLuint source_gl_format,
GLuint source_gl_type)
{
int bpp = _cogl_get_format_bpp (source_bmp->format);
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* Setup gl alignment to match rowstride and top-left corner */
prep_gl_for_pixels_upload_full (source_bmp->rowstride,
source_bmp->height / depth,
0, 0, bpp);
_cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
GE( glTexImage3D (gl_target,
0, /* level */
internal_gl_format,
source_bmp->width,
height,
depth,
0,
source_gl_format,
source_gl_type,
source_bmp->data) );
}
gboolean gboolean
_cogl_texture_driver_gl_get_tex_image (GLenum gl_target, _cogl_texture_driver_gl_get_tex_image (GLenum gl_target,
GLenum dest_gl_format, GLenum dest_gl_format,
@ -199,6 +245,36 @@ _cogl_texture_driver_gl_get_tex_image (GLenum gl_target,
return TRUE; return TRUE;
} }
gboolean
_cogl_texture_driver_size_supported_3d (GLenum gl_target,
GLenum gl_format,
GLenum gl_type,
int width,
int height,
int depth)
{
GLenum proxy_target;
GLint new_width = 0;
_COGL_GET_CONTEXT (ctx, FALSE);
if (gl_target == GL_TEXTURE_3D)
proxy_target = GL_PROXY_TEXTURE_3D;
else
/* Unknown target, assume it's not supported */
return FALSE;
/* Proxy texture allows for a quick check for supported size */
GE( glTexImage3D (proxy_target, 0, GL_RGBA,
width, height, depth, 0 /* border */,
gl_format, gl_type, NULL) );
GE( glGetTexLevelParameteriv (proxy_target, 0,
GL_TEXTURE_WIDTH, &new_width) );
return new_width != 0;
}
gboolean gboolean
_cogl_texture_driver_size_supported (GLenum gl_target, _cogl_texture_driver_size_supported (GLenum gl_target,
GLenum gl_format, GLenum gl_format,

View File

@ -90,3 +90,22 @@ COGL_FEATURE_BEGIN (texture_npot, 255, 255,
COGL_FEATURE_TEXTURE_NPOT_REPEAT, COGL_FEATURE_TEXTURE_NPOT_REPEAT,
0) 0)
COGL_FEATURE_END () COGL_FEATURE_END ()
COGL_FEATURE_BEGIN (texture_3d, 1, 2,
"OES\0",
"texture_3D\0",
COGL_FEATURE_TEXTURE_3D,
0)
COGL_FEATURE_FUNCTION (void, glTexImage3D,
(GLenum target, GLint level,
GLint internalFormat,
GLsizei width, GLsizei height,
GLsizei depth, GLint border,
GLenum format, GLenum type,
const GLvoid *pixels))
COGL_FEATURE_FUNCTION (void, glTexSubImage3D,
(GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLenum type, const GLvoid* pixels))
COGL_FEATURE_END ()

View File

@ -264,6 +264,9 @@ cogl_gles2_settings_equal (const CoglGles2WrapperSettings *a,
int arg, n_args; int arg, n_args;
GLenum func; GLenum func;
if (tex_env_a->texture_target != tex_env_b->texture_target)
return FALSE;
if (tex_env_a->point_sprite_coords != if (tex_env_a->point_sprite_coords !=
tex_env_b->point_sprite_coords) tex_env_b->point_sprite_coords)
return FALSE; return FALSE;
@ -407,7 +410,12 @@ cogl_gles2_add_texture_lookup (int unit,
{ {
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL); _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
g_string_append_printf (shader_source, "texture2D (texture_unit[%d], ", unit); if (w->settings.tex_env[unit].texture_target == GL_TEXTURE_3D_OES)
g_string_append_printf (shader_source, "texture3D (texture_unit[%d], ",
unit);
else
g_string_append_printf (shader_source, "texture2D (texture_unit[%d], ",
unit);
/* If point sprite coord generation is being used then divert to the /* If point sprite coord generation is being used then divert to the
built-in varying var for that instead of the texture built-in varying var for that instead of the texture
@ -1476,6 +1484,7 @@ _cogl_wrap_glEnable (GLenum cap)
switch (cap) switch (cap)
{ {
case GL_TEXTURE_2D: case GL_TEXTURE_2D:
case GL_TEXTURE_3D_OES:
if (!COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (w->settings.texture_units, if (!COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (w->settings.texture_units,
w->active_texture_unit)) w->active_texture_unit))
{ {
@ -1484,6 +1493,12 @@ _cogl_wrap_glEnable (GLenum cap)
TRUE); TRUE);
w->settings_dirty = TRUE; w->settings_dirty = TRUE;
} }
/* Keep track of the last enabled texture unit */
if (w->settings.tex_env[w->active_texture_unit].texture_target != cap)
{
w->settings.tex_env[w->active_texture_unit].texture_target = cap;
w->settings_dirty = TRUE;
}
break; break;
case GL_FOG: case GL_FOG:
@ -1507,8 +1522,12 @@ _cogl_wrap_glDisable (GLenum cap)
switch (cap) switch (cap)
{ {
case GL_TEXTURE_2D: case GL_TEXTURE_2D:
case GL_TEXTURE_3D_OES:
/* If this was the last enabled texture target then we'll
completely disable the unit */
if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (w->settings.texture_units, if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (w->settings.texture_units,
w->active_texture_unit)) w->active_texture_unit) &&
w->settings.tex_env[w->active_texture_unit].texture_target == cap)
{ {
COGL_GLES2_TEXTURE_UNIT_SET_ENABLED (w->settings.texture_units, COGL_GLES2_TEXTURE_UNIT_SET_ENABLED (w->settings.texture_units,
w->active_texture_unit, w->active_texture_unit,

View File

@ -128,6 +128,10 @@ struct _CoglGles2WrapperTexEnv
GLfloat texture_combine_constant[4]; GLfloat texture_combine_constant[4];
GLboolean point_sprite_coords; GLboolean point_sprite_coords;
/* Texture target that was last enabled for this unit. This assumes
that there can only be one target enabled per unit */
GLenum texture_target;
}; };
/* NB: We get a copy of this for each fragment/vertex /* NB: We get a copy of this for each fragment/vertex

View File

@ -48,6 +48,16 @@
#include "cogl-gles2-wrapper.h" #include "cogl-gles2-wrapper.h"
#define glTexImage3D ctx->drv.pf_glTexImage3D
#define glTexSubImage3D ctx->drv.pf_glTexSubImage3D
#ifndef GL_TEXTURE_3D
#define GL_TEXTURE_3D 0x806F
#endif
#ifndef GL_MAX_3D_TEXTURE_SIZE_OES
#define GL_MAX_3D_TEXTURE_SIZE_OES 0x8073
#endif
void void
_cogl_texture_driver_gen (GLenum gl_target, _cogl_texture_driver_gen (GLenum gl_target,
GLsizei n, GLsizei n,
@ -63,15 +73,15 @@ _cogl_texture_driver_gen (GLenum gl_target,
switch (gl_target) switch (gl_target)
{ {
case GL_TEXTURE_2D: case GL_TEXTURE_2D:
/* GL_TEXTURE_MAG_FILTER defaults to GL_LINEAR, no need to set it */ case GL_TEXTURE_3D:
GE( glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) ); /* GL_TEXTURE_MAG_FILTER defaults to GL_LINEAR, no need to set it */
break; GE( glTexParameteri (gl_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR) );
break;
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }
} }
} }
@ -192,6 +202,97 @@ _cogl_texture_driver_upload_to_gl (GLenum gl_target,
g_free (bmp.data); g_free (bmp.data);
} }
void
_cogl_texture_driver_upload_to_gl_3d (GLenum gl_target,
GLuint gl_handle,
gboolean is_foreign,
GLint height,
GLint depth,
CoglBitmap *source_bmp,
GLint internal_gl_format,
GLuint source_gl_format,
GLuint source_gl_type)
{
int bpp = _cogl_get_format_bpp (source_bmp->format);
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_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 (source_bmp->rowstride / bpp != source_bmp->width ||
height != source_bmp->height / depth)
{
int image_height = source_bmp->height / depth;
int i;
_cogl_texture_driver_prep_gl_for_pixels_upload (source_bmp->width * bpp,
bpp);
/* Initialize the texture with empty data and then upload each
image with a sub-region update */
GE( glTexImage3D (gl_target,
0, /* level */
internal_gl_format,
source_bmp->width,
height,
depth,
0,
source_gl_format,
source_gl_type,
NULL) );
for (i = 0; i < depth; i++)
{
CoglBitmap bmp = *source_bmp;
bmp.rowstride = bpp * bmp.width;
bmp.height = height;
bmp.data = g_malloc (bmp.rowstride * bmp.height);
_cogl_bitmap_copy_subregion (source_bmp,
&bmp,
0, image_height * i,
0, 0,
bmp.width,
bmp.height);
GE( glTexSubImage3D (gl_target,
0, /* level */
0, /* xoffset */
0, /* yoffset */
i, /* zoffset */
bmp.width, /* width */
height, /* height */
1, /* depth */
source_gl_format,
source_gl_type,
bmp.data) );
g_free (bmp.data);
}
}
else
{
_cogl_texture_driver_prep_gl_for_pixels_upload (source_bmp->rowstride,
bpp);
GE( glTexImage3D (gl_target,
0, /* level */
internal_gl_format,
source_bmp->width,
height,
depth,
0,
source_gl_format,
source_gl_type,
source_bmp->data) );
}
}
/* NB: GLES doesn't support glGetTexImage2D, so cogl-texture will instead /* NB: GLES doesn't support glGetTexImage2D, so cogl-texture will instead
* fallback to a generic render + readpixels approach to downloading * fallback to a generic render + readpixels approach to downloading
* texture data. (See _cogl_texture_draw_and_read() ) */ * texture data. (See _cogl_texture_draw_and_read() ) */
@ -204,6 +305,24 @@ _cogl_texture_driver_gl_get_tex_image (GLenum gl_target,
return FALSE; return FALSE;
} }
gboolean
_cogl_texture_driver_size_supported_3d (GLenum gl_target,
GLenum gl_format,
GLenum gl_type,
int width,
int height,
int depth)
{
GLint max_size;
/* GLES doesn't support a proxy texture target so let's at least
check whether the size is greater than
GL_MAX_3D_TEXTURE_SIZE_OES */
GE( glGetIntegerv (GL_MAX_3D_TEXTURE_SIZE_OES, &max_size) );
return width <= max_size && height <= max_size && depth <= max_size;
}
gboolean gboolean
_cogl_texture_driver_size_supported (GLenum gl_target, _cogl_texture_driver_size_supported (GLenum gl_target,
GLenum gl_format, GLenum gl_format,

View File

@ -60,6 +60,7 @@
<xi:include href="xml/cogl.xml"/> <xi:include href="xml/cogl.xml"/>
<xi:include href="xml/cogl-color.xml"/> <xi:include href="xml/cogl-color.xml"/>
<xi:include href="xml/cogl-texture.xml"/> <xi:include href="xml/cogl-texture.xml"/>
<xi:include href="xml/cogl-texture-3d.xml"/>
<xi:include href="blend-strings.xml"/> <xi:include href="blend-strings.xml"/>
<xi:include href="xml/cogl-material.xml"/> <xi:include href="xml/cogl-material.xml"/>
<xi:include href="xml/cogl-primitives.xml"/> <xi:include href="xml/cogl-primitives.xml"/>

View File

@ -232,6 +232,14 @@ cogl_texture_set_region
COGL_TEXTURE_MAX_WASTE COGL_TEXTURE_MAX_WASTE
</SECTION> </SECTION>
<SECTION>
<FILE>cogl-texture-3d</FILE>
<TITLE>3D textures</TITLE>
cogl_texture_3d_new_with_size
cogl_texture_3d_new_from_data
cogl_is_texture_3d
</SECTION>
<SECTION> <SECTION>
<FILE>cogl-shaders</FILE> <FILE>cogl-shaders</FILE>
<TITLE>Shaders and Programmable Pipeline</TITLE> <TITLE>Shaders and Programmable Pipeline</TITLE>