Improve cogl-texture maintainability by moving 90% into cogl/common

This splits the limited components that differed between
cogl/{gl,gles}/cogl-texture.c into new {gl,gles}/cogl-texture-driver.c files
and the rest that can now be shared into cogl/common/cogl-texture.c
This commit is contained in:
Robert Bragg 2009-07-28 00:37:11 +01:00
parent 4f5e6b77d5
commit 739b460c7a
12 changed files with 1188 additions and 2611 deletions

View File

@ -84,6 +84,9 @@ libclutter_cogl_common_la_SOURCES = \
cogl-blend-string.c \ cogl-blend-string.c \
cogl-blend-string.h \ cogl-blend-string.h \
cogl-debug.c \ cogl-debug.c \
cogl-texture-private.h \
cogl-texture-driver.h \
cogl-texture.c \
$(NULL) $(NULL)
EXTRA_DIST = stb_image.c cogl-enum-types.h.in cogl-enum-types.c.in EXTRA_DIST = stb_image.c cogl-enum-types.h.in cogl-enum-types.c.in

View File

@ -25,6 +25,7 @@
#define __COGL_INTERNAL_H #define __COGL_INTERNAL_H
#include "cogl-debug.h" #include "cogl-debug.h"
#include "cogl-types.h"
#ifdef HAVE_COGL_GLES2 #ifdef HAVE_COGL_GLES2
typedef enum { typedef enum {

View File

@ -0,0 +1,157 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2007,2008,2009 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.
*/
#ifndef __COGL_TEXTURE_DRIVER_H
#define __COGL_TEXTURE_DRIVER_H
/*
* Basically just a wrapper around glBindTexture, but the GLES2 backend
* for example also wants to know about the internal format so it can
* identify when alpha only textures are bound.
*/
void
_cogl_texture_driver_bind (GLenum gl_target, GLuint gl_handle, GLenum gl_intformat);
/*
* This sets up the glPixelStore state for an upload to a destination with
* the same size, and with no offset.
*/
/* NB: GLES can't upload a sub region of pixel data from a larger source
* buffer which is why this interface is limited. The GL driver has a more
* flexible version of this function that is uses internally */
void
_cogl_texture_driver_prep_gl_for_pixels_upload (int pixels_rowstride,
int pixels_bpp);
/*
* This uploads a sub-region from source_bmp to a single GL texture handle (i.e
* a single CoglTexture slice)
*
* It also updates the array of tex->first_pixels[slice_index] if
* dst_{x,y} == 0
*
* The driver abstraction is in place because GLES doesn't support the pixel
* store options required to source from a subregion, so for GLES we have
* to manually create a transient source bitmap.
*
* XXX: sorry for the ridiculous number of arguments :-(
*/
void
_cogl_texture_driver_upload_subregion_to_gl (CoglTexture *tex,
int src_x,
int src_y,
int dst_x,
int dst_y,
int width,
int height,
CoglBitmap *source_bmp,
GLuint source_gl_format,
GLuint source_gl_type,
GLuint gl_handle);
/*
* This sets up the glPixelStore state for an download to a destination with
* the same size, and with no offset.
*/
/* NB: GLES can't download pixel data into a sub region of a larger destination
* buffer, the GL driver has a more flexible version of this function that it
* uses internally. */
void
_cogl_texture_driver_prep_gl_for_pixels_download (int pixels_rowstride,
int pixels_bpp);
/*
* This driver abstraction is in place because GLES doesn't have a sane way to
* download data from a texture so you litterally render the texture to the
* backbuffer, and retrive the data using glReadPixels :-(
*/
gboolean
_cogl_texture_driver_download_from_gl (CoglTexture *tex,
CoglBitmap *target_bmp,
GLuint target_gl_format,
GLuint target_gl_type);
/*
* It may depend on the driver as to what texture sizes are supported...
*/
gboolean
_cogl_texture_driver_size_supported (GLenum gl_target,
GLenum gl_format,
GLenum gl_type,
int width,
int height);
/*
* This driver abstraction is needed because GLES doesn't support setting
* a texture border color.
*/
void
_cogl_texture_driver_try_setting_gl_border_color (
GLuint gl_target,
const GLfloat *transparent_color);
/*
* XXX: this should live in cogl/{gl,gles}/cogl.c
*/
gboolean
_cogl_pixel_format_from_gl_internal (GLenum gl_int_format,
CoglPixelFormat *out_format);
/*
* XXX: this should live in cogl/{gl,gles}/cogl.c
*/
CoglPixelFormat
_cogl_pixel_format_to_gl (CoglPixelFormat format,
GLenum *out_glintformat,
GLenum *out_glformat,
GLenum *out_gltype);
/*
* It may depend on the driver as to what texture targets may be used when
* creating a foreign texture. E.g. OpenGL supports ARB_texture_rectangle
* but GLES doesn't
*/
gboolean
_cogl_texture_driver_allows_foreign_gl_target (GLenum gl_target);
/*
* glGenerateMipmap semantics may need to be emulated for some drivers. E.g. by
* enabling auto mipmap generation an re-loading a number of known texels.
*/
void
_cogl_texture_driver_gl_generate_mipmaps (GLenum texture_target);
/*
* The driver may impose constraints on what formats can be used to store
* texture data read from textures. For example GLES currently only supports
* RGBA_8888, and so we need to manually convert the data if the final
* destination has another format.
*/
CoglPixelFormat
_cogl_texture_driver_find_best_gl_get_data_format (
CoglPixelFormat format,
GLenum *closest_gl_format,
GLenum *closest_gl_type);
#endif /* __COGL_TEXTURE_DRIVER_H */

View File

@ -21,8 +21,8 @@
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
#ifndef __COGL_TEXTURE_H #ifndef __COGL_TEXTURE_PRIVATE_H
#define __COGL_TEXTURE_H #define __COGL_TEXTURE_PRIVATE_H
#include "cogl-bitmap-private.h" #include "cogl-bitmap-private.h"
#include "cogl-handle.h" #include "cogl-handle.h"
@ -142,4 +142,10 @@ _cogl_span_iter_end (CoglSpanIter *iter);
void void
_cogl_span_iter_next (CoglSpanIter *iter); _cogl_span_iter_next (CoglSpanIter *iter);
#endif /* __COGL_TEXTURE_H */ void
_cogl_texture_prep_gl_alignment_for_pixels_upload (int pixels_rowstride);
void
_cogl_texture_prep_gl_alignment_for_pixels_download (int pixels_rowstride);
#endif /* __COGL_TEXTURE_PRIVATE_H */

View File

@ -36,6 +36,7 @@
#include "cogl-bitmap.h" #include "cogl-bitmap.h"
#include "cogl-bitmap-private.h" #include "cogl-bitmap-private.h"
#include "cogl-texture-private.h" #include "cogl-texture-private.h"
#include "cogl-texture-driver.h"
#include "cogl-material.h" #include "cogl-material.h"
#include "cogl-context.h" #include "cogl-context.h"
#include "cogl-handle.h" #include "cogl-handle.h"
@ -45,22 +46,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#ifdef HAVE_COGL_GL
#define glDrawRangeElements ctx->pf_glDrawRangeElements
#define glActiveTexture ctx->pf_glActiveTexture
#define glClientActiveTexture ctx->pf_glClientActiveTexture
#define glGenerateMipmap ctx->pf_glGenerateMipmapEXT
#else
/* GLES doesn't have glDrawRangeElements, so we simply pretend it does
* but that it makes no use of the start, end constraints: */
#define glDrawRangeElements(mode, start, end, count, type, indices) \
glDrawElements (mode, count, type, indices)
#endif
static void _cogl_texture_free (CoglTexture *tex); static void _cogl_texture_free (CoglTexture *tex);
COGL_HANDLE_DEFINE (Texture, texture); COGL_HANDLE_DEFINE (Texture, texture);
@ -162,17 +147,9 @@ _cogl_span_iter_end (CoglSpanIter *iter)
return iter->pos >= iter->cover_end; return iter->pos >= iter->cover_end;
} }
static void void
prep_for_gl_pixels_upload (gint pixels_rowstride, _cogl_texture_prep_gl_alignment_for_pixels_upload (int pixels_rowstride)
gint pixels_src_x,
gint pixels_src_y,
gint pixels_bpp)
{ {
GE( glPixelStorei (GL_UNPACK_ROW_LENGTH, pixels_rowstride / pixels_bpp) );
GE( glPixelStorei (GL_UNPACK_SKIP_PIXELS, pixels_src_x) );
GE( glPixelStorei (GL_UNPACK_SKIP_ROWS, pixels_src_y) );
if (!(pixels_rowstride & 0x7)) if (!(pixels_rowstride & 0x7))
GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 8) ); GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 8) );
else if (!(pixels_rowstride & 0x3)) else if (!(pixels_rowstride & 0x3))
@ -183,17 +160,9 @@ prep_for_gl_pixels_upload (gint pixels_rowstride,
GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 1) ); GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 1) );
} }
static void void
prep_for_gl_pixels_download (gint pixels_rowstride, _cogl_texture_prep_gl_alignment_for_pixels_download (int pixels_rowstride)
gint pixels_src_x,
gint pixels_src_y,
gint pixels_bpp)
{ {
GE( glPixelStorei (GL_PACK_ROW_LENGTH, pixels_rowstride / pixels_bpp) );
GE( glPixelStorei (GL_PACK_SKIP_PIXELS, pixels_src_x) );
GE( glPixelStorei (GL_PACK_SKIP_ROWS, pixels_src_y) );
if (!(pixels_rowstride & 0x7)) if (!(pixels_rowstride & 0x7))
GE( glPixelStorei (GL_PACK_ALIGNMENT, 8) ); GE( glPixelStorei (GL_PACK_ALIGNMENT, 8) );
else if (!(pixels_rowstride & 0x3)) else if (!(pixels_rowstride & 0x3))
@ -262,11 +231,18 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
/* Pick the gl texture object handle */ /* Pick the gl texture object handle */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num); gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num);
/* Setup gl alignment to match rowstride and top-left corner */ _cogl_texture_driver_upload_subregion_to_gl (
prep_for_gl_pixels_upload (tex->bitmap.rowstride, tex,
x_span->start, x_span->start, /* src x */
y_span->start, y_span->start, /* src y */
bpp); 0, /* dst x */
0, /* dst y */
x_span->size - x_span->waste, /* width */
y_span->size - y_span->waste, /* height */
&tex->bitmap,
tex->gl_format,
tex->gl_type,
gl_handle);
/* Keep a copy of the first pixel if needed */ /* Keep a copy of the first pixel if needed */
if (tex->first_pixels) if (tex->first_pixels)
@ -279,17 +255,6 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
tex->first_pixels[slice_num].gl_type = tex->gl_type; tex->first_pixels[slice_num].gl_type = tex->gl_type;
} }
/* Upload new image data */
GE( glBindTexture (tex->gl_target, gl_handle) );
GE( glTexSubImage2D (tex->gl_target, 0,
0,
0,
x_span->size - x_span->waste,
y_span->size - y_span->waste,
tex->gl_format, tex->gl_type,
tex->bitmap.data) );
/* Fill the waste with a copies of the rightmost pixels */ /* Fill the waste with a copies of the rightmost pixels */
if (x_span->waste > 0) if (x_span->waste > 0)
{ {
@ -309,9 +274,8 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
src += tex->bitmap.rowstride; src += tex->bitmap.rowstride;
} }
prep_for_gl_pixels_upload (x_span->waste * bpp, _cogl_texture_driver_prep_gl_for_pixels_upload (
0, /* src x */ x_span->waste * bpp,
0, /* src y */
bpp); bpp);
GE( glTexSubImage2D (tex->gl_target, 0, GE( glTexSubImage2D (tex->gl_target, 0,
@ -344,9 +308,8 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
} }
} }
prep_for_gl_pixels_upload (x_span->size * bpp, _cogl_texture_driver_prep_gl_for_pixels_upload (
0, /* src x */ x_span->size * bpp,
0, /* src y */
bpp); bpp);
GE( glTexSubImage2D (tex->gl_target, 0, GE( glTexSubImage2D (tex->gl_target, 0,
@ -368,95 +331,6 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
return TRUE; return TRUE;
} }
static gboolean
_cogl_texture_download_from_gl (CoglTexture *tex,
CoglBitmap *target_bmp,
GLuint target_gl_format,
GLuint target_gl_type)
{
CoglTexSliceSpan *x_span;
CoglTexSliceSpan *y_span;
GLuint gl_handle;
gint bpp;
gint x,y;
CoglBitmap slice_bmp;
bpp = _cogl_get_format_bpp (target_bmp->format);
/* Iterate vertical slices */
for (y = 0; y < tex->slice_y_spans->len; ++y)
{
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y);
/* Iterate horizontal slices */
for (x = 0; x < tex->slice_x_spans->len; ++x)
{
/*if (x != 0 || y != 1) continue;*/
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x);
/* Pick the gl texture object handle */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
y * tex->slice_x_spans->len + x);
/* If there's any waste we need to copy manually
(no glGetTexSubImage) */
if (y_span->waste != 0 || x_span->waste != 0)
{
/* Setup temp bitmap for slice subregion */
slice_bmp.format = target_bmp->format;
slice_bmp.width = x_span->size;
slice_bmp.height = y_span->size;
slice_bmp.rowstride = bpp * slice_bmp.width;
slice_bmp.data = (guchar*) g_malloc (slice_bmp.rowstride *
slice_bmp.height);
/* Setup gl alignment to 0,0 top-left corner */
prep_for_gl_pixels_download (slice_bmp.rowstride, 0, 0, bpp);
/* Download slice image data into temp bmp */
GE( glBindTexture (tex->gl_target, gl_handle) );
GE (glGetTexImage (tex->gl_target,
0, /* level */
target_gl_format,
target_gl_type,
slice_bmp.data) );
/* Copy portion of slice from temp to target bmp */
_cogl_bitmap_copy_subregion (&slice_bmp,
target_bmp,
0, 0,
x_span->start,
y_span->start,
x_span->size - x_span->waste,
y_span->size - y_span->waste);
/* Free temp bitmap */
g_free (slice_bmp.data);
}
else
{
GLvoid *dst = target_bmp->data
+ x_span->start * bpp
+ y_span->start * target_bmp->rowstride;
prep_for_gl_pixels_download (target_bmp->rowstride, 0, 0, bpp);
/* Download slice image data */
GE( glBindTexture (tex->gl_target, gl_handle) );
GE( glGetTexImage (tex->gl_target,
0, /* level */
target_gl_format,
target_gl_type,
dst) );
}
}
}
return TRUE;
}
static gboolean static gboolean
_cogl_texture_upload_subregion_to_gl (CoglTexture *tex, _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
gint src_x, gint src_x,
@ -529,27 +403,29 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
x_iter.index); x_iter.index);
/* Pick intersection width and height */ /* Pick intersection width and height */
inter_w = (x_iter.intersect_end - inter_w = (x_iter.intersect_end - x_iter.intersect_start);
x_iter.intersect_start); inter_h = (y_iter.intersect_end - y_iter.intersect_start);
inter_h = (y_iter.intersect_end -
y_iter.intersect_start);
/* Localize intersection top-left corner to slice*/ /* Localize intersection top-left corner to slice*/
local_x = (x_iter.intersect_start - local_x = (x_iter.intersect_start - x_iter.pos);
x_iter.pos); local_y = (y_iter.intersect_start - y_iter.pos);
local_y = (y_iter.intersect_start -
y_iter.pos);
slice_num = y_iter.index * tex->slice_x_spans->len + x_iter.index; slice_num = y_iter.index * tex->slice_x_spans->len + x_iter.index;
/* Pick slice GL handle */ /* Pick slice GL handle */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num); gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num);
/* Setup gl alignment to match rowstride and top-left corner */ _cogl_texture_driver_upload_subregion_to_gl (tex,
prep_for_gl_pixels_upload (source_bmp->rowstride,
source_x, source_x,
source_y, source_y,
bpp); local_x, /* dst x */
local_y, /* dst x */
inter_w, /* width */
inter_h, /* height */
source_bmp,
source_gl_format,
source_gl_type,
gl_handle);
/* Keep a copy of the first pixel if needed */ /* Keep a copy of the first pixel if needed */
if (tex->first_pixels && local_x == 0 && local_y == 0) if (tex->first_pixels && local_x == 0 && local_y == 0)
@ -562,16 +438,6 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
tex->first_pixels[slice_num].gl_type = source_gl_type; tex->first_pixels[slice_num].gl_type = source_gl_type;
} }
/* Upload new image data */
GE( glBindTexture (tex->gl_target, gl_handle) );
GE( glTexSubImage2D (tex->gl_target, 0,
local_x, local_y,
inter_w, inter_h,
source_gl_format,
source_gl_type,
source_bmp->data) );
/* If the x_span is sliced and the upload touches the /* If the x_span is sliced and the upload touches the
rightmost pixels then fill the waste with copies of the rightmost pixels then fill the waste with copies of the
pixels */ pixels */
@ -603,9 +469,8 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
src += source_bmp->rowstride; src += source_bmp->rowstride;
} }
prep_for_gl_pixels_upload (x_span->waste * bpp, _cogl_texture_driver_prep_gl_for_pixels_upload (
0, /* src x */ x_span->waste * bpp,
0, /* src y */
bpp); bpp);
GE( glTexSubImage2D (tex->gl_target, 0, GE( glTexSubImage2D (tex->gl_target, 0,
@ -655,9 +520,8 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
} }
} }
prep_for_gl_pixels_upload (copy_width * bpp, _cogl_texture_driver_prep_gl_for_pixels_upload (
0, /* src x */ copy_width * bpp,
0, /* src y */
bpp); bpp);
GE( glTexSubImage2D (tex->gl_target, 0, GE( glTexSubImage2D (tex->gl_target, 0,
@ -739,7 +603,9 @@ _cogl_pot_slices_for_size (gint size_to_fill,
if (size_to_fill > span.size) if (size_to_fill > span.size)
{ {
/* Not yet - add a span of this size */ /* Not yet - add a span of this size */
if (out_spans) g_array_append_val (out_spans, span); if (out_spans)
g_array_append_val (out_spans, span);
span.start += span.size; span.start += span.size;
size_to_fill -= span.size; size_to_fill -= span.size;
n_spans++; n_spans++;
@ -748,7 +614,9 @@ _cogl_pot_slices_for_size (gint size_to_fill,
{ {
/* Yes and waste is small enough */ /* Yes and waste is small enough */
span.waste = span.size - size_to_fill; span.waste = span.size - size_to_fill;
if (out_spans) g_array_append_val (out_spans, span); if (out_spans)
g_array_append_val (out_spans, span);
return ++n_spans; return ++n_spans;
} }
else else
@ -766,35 +634,6 @@ _cogl_pot_slices_for_size (gint size_to_fill,
return 0; return 0;
} }
static gboolean
_cogl_texture_size_supported (GLenum gl_target,
GLenum gl_format,
GLenum gl_type,
int width,
int height)
{
if (gl_target == GL_TEXTURE_2D)
{
/* Proxy texture allows for a quick check for supported size */
GLint new_width = 0;
GE( glTexImage2D (GL_PROXY_TEXTURE_2D, 0, GL_RGBA,
width, height, 0 /* border */,
gl_format, gl_type, NULL) );
GE( glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0,
GL_TEXTURE_WIDTH, &new_width) );
return new_width != 0;
}
else
{
/* not used */
return 0;
}
}
void void
_cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, _cogl_texture_set_wrap_mode_parameter (CoglTexture *tex,
GLenum wrap_mode) GLenum wrap_mode)
@ -863,7 +702,7 @@ _cogl_texture_slices_create (CoglTexture *tex)
CoglTexSliceSpan span; CoglTexSliceSpan span;
/* Check if size supported else bail out */ /* Check if size supported else bail out */
if (!_cogl_texture_size_supported (tex->gl_target, if (!_cogl_texture_driver_size_supported (tex->gl_target,
tex->gl_format, tex->gl_format,
tex->gl_type, tex->gl_type,
max_width, max_width,
@ -897,7 +736,7 @@ _cogl_texture_slices_create (CoglTexture *tex)
else else
{ {
/* Decrease the size of largest slice until supported by GL */ /* Decrease the size of largest slice until supported by GL */
while (!_cogl_texture_size_supported (tex->gl_target, while (!_cogl_texture_driver_size_supported (tex->gl_target,
tex->gl_format, tex->gl_format,
tex->gl_type, tex->gl_type,
max_width, max_width,
@ -951,7 +790,7 @@ _cogl_texture_slices_create (CoglTexture *tex)
g_array_set_size (tex->slice_gl_handles, n_slices); g_array_set_size (tex->slice_gl_handles, n_slices);
/* Allocate some space to store a copy of the first pixel of each /* Allocate some space to store a copy of the first pixel of each
slice. This is only needed to glGenerateMipmap (which is part of slice. This is only needed if glGenerateMipmap (which is part of
the FBO extension) is not available */ the FBO extension) is not available */
if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) if (cogl_features_available (COGL_FEATURE_OFFSCREEN))
tex->first_pixels = NULL; tex->first_pixels = NULL;
@ -984,14 +823,12 @@ _cogl_texture_slices_create (CoglTexture *tex)
y_span->size - y_span->waste); y_span->size - y_span->waste);
/* Setup texture parameters */ /* Setup texture parameters */
GE( glBindTexture (tex->gl_target, GE( _cogl_texture_driver_bind (tex->gl_target,
gl_handles[y * n_x_slices + x]) ); gl_handles[y * n_x_slices + x],
tex->gl_intformat) );
/* Use a transparent border color so that we can leave the _cogl_texture_driver_try_setting_gl_border_color (tex->gl_target,
color buffer alone when using texture co-ordinates transparent_color);
outside of the texture */
GE( glTexParameterfv (tex->gl_target, GL_TEXTURE_BORDER_COLOR,
transparent_color) );
/* Pass NULL data to init size and internal format */ /* Pass NULL data to init size and internal format */
GE( glTexImage2D (tex->gl_target, 0, tex->gl_intformat, GE( glTexImage2D (tex->gl_target, 0, tex->gl_intformat,
@ -1041,153 +878,6 @@ _cogl_texture_span_has_waste (CoglTexture *tex,
return (x_span->waste || y_span->waste) ? TRUE : FALSE; return (x_span->waste || y_span->waste) ? TRUE : FALSE;
} }
static gboolean
_cogl_pixel_format_from_gl_internal (GLenum gl_int_format,
CoglPixelFormat *out_format)
{
/* It doesn't really matter we convert to exact same
format (some have no cogl match anyway) since format
is re-matched against cogl when getting or setting
texture image data.
*/
switch (gl_int_format)
{
case GL_ALPHA: case GL_ALPHA4: case GL_ALPHA8:
case GL_ALPHA12: case GL_ALPHA16:
*out_format = COGL_PIXEL_FORMAT_A_8;
return TRUE;
case GL_LUMINANCE: case GL_LUMINANCE4: case GL_LUMINANCE8:
case GL_LUMINANCE12: case GL_LUMINANCE16:
*out_format = COGL_PIXEL_FORMAT_G_8;
return TRUE;
case GL_RGB: case GL_RGB4: case GL_RGB5: case GL_RGB8:
case GL_RGB10: case GL_RGB12: case GL_RGB16: case GL_R3_G3_B2:
*out_format = COGL_PIXEL_FORMAT_RGB_888;
return TRUE;
case GL_RGBA: case GL_RGBA2: case GL_RGBA4: case GL_RGB5_A1:
case GL_RGBA8: case GL_RGB10_A2: case GL_RGBA12: case GL_RGBA16:
*out_format = COGL_PIXEL_FORMAT_RGBA_8888;
return TRUE;
}
return FALSE;
}
static CoglPixelFormat
_cogl_pixel_format_to_gl (CoglPixelFormat format,
GLenum *out_glintformat,
GLenum *out_glformat,
GLenum *out_gltype)
{
CoglPixelFormat required_format;
GLenum glintformat = 0;
GLenum glformat = 0;
GLenum gltype = 0;
/* FIXME: check YUV support */
required_format = format;
/* Find GL equivalents */
switch (format & COGL_UNPREMULT_MASK)
{
case COGL_PIXEL_FORMAT_A_8:
glintformat = GL_ALPHA;
glformat = GL_ALPHA;
gltype = GL_UNSIGNED_BYTE;
break;
case COGL_PIXEL_FORMAT_G_8:
glintformat = GL_LUMINANCE;
glformat = GL_LUMINANCE;
gltype = GL_UNSIGNED_BYTE;
break;
case COGL_PIXEL_FORMAT_RGB_888:
glintformat = GL_RGB;
glformat = GL_RGB;
gltype = GL_UNSIGNED_BYTE;
break;
case COGL_PIXEL_FORMAT_BGR_888:
glintformat = GL_RGB;
glformat = GL_BGR;
gltype = GL_UNSIGNED_BYTE;
break;
case COGL_PIXEL_FORMAT_RGBA_8888:
glintformat = GL_RGBA;
glformat = GL_RGBA;
gltype = GL_UNSIGNED_BYTE;
break;
case COGL_PIXEL_FORMAT_BGRA_8888:
glintformat = GL_RGBA;
glformat = GL_BGRA;
gltype = GL_UNSIGNED_BYTE;
break;
/* The following two types of channel ordering
* have no GL equivalent unless defined using
* system word byte ordering */
case COGL_PIXEL_FORMAT_ARGB_8888:
glintformat = GL_RGBA;
glformat = GL_BGRA;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
gltype = GL_UNSIGNED_INT_8_8_8_8;
#else
gltype = GL_UNSIGNED_INT_8_8_8_8_REV;
#endif
break;
case COGL_PIXEL_FORMAT_ABGR_8888:
glintformat = GL_RGBA;
glformat = GL_RGBA;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
gltype = GL_UNSIGNED_INT_8_8_8_8;
#else
gltype = GL_UNSIGNED_INT_8_8_8_8_REV;
#endif
break;
/* The following three types of channel ordering
* are always defined using system word byte
* ordering (even according to GLES spec) */
case COGL_PIXEL_FORMAT_RGB_565:
glintformat = GL_RGB;
glformat = GL_RGB;
gltype = GL_UNSIGNED_SHORT_5_6_5;
break;
case COGL_PIXEL_FORMAT_RGBA_4444:
glintformat = GL_RGBA;
glformat = GL_RGBA;
gltype = GL_UNSIGNED_SHORT_4_4_4_4;
break;
case COGL_PIXEL_FORMAT_RGBA_5551:
glintformat = GL_RGBA;
glformat = GL_RGBA;
gltype = GL_UNSIGNED_SHORT_5_5_5_1;
break;
/* FIXME: check extensions for YUV support */
default:
break;
}
if (out_glintformat != NULL)
*out_glintformat = glintformat;
if (out_glformat != NULL)
*out_glformat = glformat;
if (out_gltype != NULL)
*out_gltype = gltype;
return required_format;
}
static gboolean static gboolean
_cogl_texture_bitmap_prepare (CoglTexture *tex, _cogl_texture_bitmap_prepare (CoglTexture *tex,
CoglPixelFormat internal_format) CoglPixelFormat internal_format)
@ -1496,14 +1186,7 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
CoglTexSliceSpan x_span; CoglTexSliceSpan x_span;
CoglTexSliceSpan y_span; CoglTexSliceSpan y_span;
/* GL_ARB_texture_rectangle textures are supported if they are if (!_cogl_texture_driver_allows_foreign_gl_target (gl_target))
created from foreign because some chipsets have trouble with
GL_ARB_texture_non_power_of_two. There is no Cogl call to create
them directly to emphasize the fact that they don't work fully
(for example, no mipmapping and complicated shader support) */
/* Allow 2-dimensional or rectangle textures only */
if (gl_target != GL_TEXTURE_2D && gl_target != CGL_TEXTURE_RECTANGLE_ARB)
return COGL_INVALID_HANDLE; return COGL_INVALID_HANDLE;
/* Make sure it is a valid GL texture object */ /* Make sure it is a valid GL texture object */
@ -1520,6 +1203,7 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
/* Obtain texture parameters /* Obtain texture parameters
(only level 0 we are interested in) */ (only level 0 we are interested in) */
#if HAVE_COGL_GL
GE( glGetTexLevelParameteriv (gl_target, 0, GE( glGetTexLevelParameteriv (gl_target, 0,
GL_TEXTURE_COMPRESSED, GL_TEXTURE_COMPRESSED,
&gl_compressed) ); &gl_compressed) );
@ -1536,6 +1220,10 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
GE( glGetTexLevelParameteriv (gl_target, 0, GE( glGetTexLevelParameteriv (gl_target, 0,
GL_TEXTURE_HEIGHT, GL_TEXTURE_HEIGHT,
&gl_height) ); &gl_height) );
#else
gl_width = width + x_pot_waste;
gl_height = height + y_pot_waste;
#endif
GE( glGetTexParameteriv (gl_target, GE( glGetTexParameteriv (gl_target,
GL_GENERATE_MIPMAP, GL_GENERATE_MIPMAP,
@ -1796,7 +1484,7 @@ _cogl_texture_ensure_mipmaps (CoglHandle handle)
/* glGenerateMipmap is defined in the FBO extension */ /* glGenerateMipmap is defined in the FBO extension */
if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) if (cogl_features_available (COGL_FEATURE_OFFSCREEN))
GE( glGenerateMipmap (tex->gl_target) ); _cogl_texture_driver_gl_generate_mipmaps (tex->gl_target);
else if (tex->first_pixels) else if (tex->first_pixels)
{ {
CoglTexturePixel *pixel = tex->first_pixels + i; CoglTexturePixel *pixel = tex->first_pixels + i;
@ -1935,12 +1623,10 @@ cogl_texture_get_data (CoglHandle handle,
byte_size = tex->bitmap.height * rowstride; byte_size = tex->bitmap.height * rowstride;
if (data == NULL) return byte_size; if (data == NULL) return byte_size;
/* Find closest format that's supported by GL */ closest_format =
closest_format = _cogl_pixel_format_to_gl (format, _cogl_texture_driver_find_best_gl_get_data_format (format,
NULL, /* don't need */
&closest_gl_format, &closest_gl_format,
&closest_gl_type); &closest_gl_type);
closest_bpp = _cogl_get_format_bpp (closest_format); closest_bpp = _cogl_get_format_bpp (closest_format);
/* Is the requested format supported? */ /* Is the requested format supported? */
@ -1963,7 +1649,7 @@ cogl_texture_get_data (CoglHandle handle,
} }
/* Retrieve data from slices */ /* Retrieve data from slices */
_cogl_texture_download_from_gl (tex, &target_bmp, _cogl_texture_driver_download_from_gl (tex, &target_bmp,
closest_gl_format, closest_gl_format,
closest_gl_type); closest_gl_type);

View File

@ -20,7 +20,6 @@ cogl_headers = \
$(NULL) $(NULL)
cogl_priv_headers = \ cogl_priv_headers = \
cogl-texture-private.h \
cogl-fbo.h \ cogl-fbo.h \
cogl-shader-private.h \ cogl-shader-private.h \
cogl-program.h \ cogl-program.h \
@ -30,7 +29,7 @@ cogl_priv_headers = \
cogl_sources = \ cogl_sources = \
cogl.c \ cogl.c \
cogl-primitives.c \ cogl-primitives.c \
cogl-texture.c \ cogl-texture-driver.c \
cogl-fbo.c \ cogl-fbo.c \
cogl-shader.c \ cogl-shader.c \
cogl-program.c \ cogl-program.c \

454
gl/cogl-texture-driver.c Normal file
View File

@ -0,0 +1,454 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2007,2008,2009 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:
* Matthew Allum <mallum@openedhand.com>
* Neil Roberts <neil@linux.intel.com>
* Robert Bragg <robert@linux.intel.com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "cogl.h"
#include "cogl-internal.h"
#include "cogl-util.h"
#include "cogl-bitmap.h"
#include "cogl-bitmap-private.h"
#include "cogl-texture-private.h"
#include "cogl-material.h"
#include "cogl-context.h"
#include "cogl-handle.h"
#include "cogl-primitives.h"
#include <string.h>
#include <stdlib.h>
#include <math.h>
#define glGenerateMipmap ctx->pf_glGenerateMipmapEXT
void
_cogl_texture_driver_bind (GLenum gl_target,
GLuint gl_handle,
GLenum gl_intformat)
{
GE (glBindTexture (gl_target, gl_handle));
}
/* OpenGL - unlike GLES - can upload a sub region of pixel data from a larger
* source buffer */
static void
prep_gl_for_pixels_upload_full (int pixels_rowstride,
int pixels_src_x,
int pixels_src_y,
int pixels_bpp)
{
GE( glPixelStorei (GL_UNPACK_ROW_LENGTH, pixels_rowstride / pixels_bpp) );
GE( glPixelStorei (GL_UNPACK_SKIP_PIXELS, pixels_src_x) );
GE( glPixelStorei (GL_UNPACK_SKIP_ROWS, pixels_src_y) );
_cogl_texture_prep_gl_alignment_for_pixels_upload (pixels_rowstride);
}
void
_cogl_texture_driver_prep_gl_for_pixels_upload (int pixels_rowstride,
int pixels_bpp)
{
prep_gl_for_pixels_upload_full (pixels_rowstride, 0, 0, pixels_bpp);
}
/* OpenGL - unlike GLES - can download pixel data into a sub region of
* a larger destination buffer */
static void
prep_gl_for_pixels_download_full (int pixels_rowstride,
int pixels_src_x,
int pixels_src_y,
int pixels_bpp)
{
GE( glPixelStorei (GL_PACK_ROW_LENGTH, pixels_rowstride / pixels_bpp) );
GE( glPixelStorei (GL_PACK_SKIP_PIXELS, pixels_src_x) );
GE( glPixelStorei (GL_PACK_SKIP_ROWS, pixels_src_y) );
_cogl_texture_prep_gl_alignment_for_pixels_download (pixels_rowstride);
}
void
_cogl_texture_driver_prep_gl_for_pixels_download (int pixels_rowstride,
int pixels_bpp)
{
prep_gl_for_pixels_download_full (pixels_rowstride, 0, 0, pixels_bpp);
}
void
_cogl_texture_driver_upload_subregion_to_gl (CoglTexture *tex,
int src_x,
int src_y,
int dst_x,
int dst_y,
int width,
int height,
CoglBitmap *source_bmp,
GLuint source_gl_format,
GLuint source_gl_type,
GLuint gl_handle)
{
int bpp = _cogl_get_format_bpp (source_bmp->format);
/* Setup gl alignment to match rowstride and top-left corner */
prep_gl_for_pixels_upload_full (source_bmp->rowstride,
src_x,
src_y,
bpp);
/* Upload new image data */
GE( _cogl_texture_driver_bind (tex->gl_target,
gl_handle, tex->gl_intformat) );
GE( glTexSubImage2D (tex->gl_target, 0,
dst_x, dst_y,
width, height,
source_gl_format,
source_gl_type,
source_bmp->data) );
}
gboolean
_cogl_texture_driver_download_from_gl (CoglTexture *tex,
CoglBitmap *target_bmp,
GLuint target_gl_format,
GLuint target_gl_type)
{
CoglTexSliceSpan *x_span;
CoglTexSliceSpan *y_span;
GLuint gl_handle;
gint bpp;
gint x,y;
CoglBitmap slice_bmp;
bpp = _cogl_get_format_bpp (target_bmp->format);
/* Iterate vertical slices */
for (y = 0; y < tex->slice_y_spans->len; ++y)
{
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y);
/* Iterate horizontal slices */
for (x = 0; x < tex->slice_x_spans->len; ++x)
{
/*if (x != 0 || y != 1) continue;*/
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x);
/* Pick the gl texture object handle */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
y * tex->slice_x_spans->len + x);
/* If there's any waste we need to copy manually
(no glGetTexSubImage) */
if (y_span->waste != 0 || x_span->waste != 0)
{
/* Setup temp bitmap for slice subregion */
slice_bmp.format = target_bmp->format;
slice_bmp.width = x_span->size;
slice_bmp.height = y_span->size;
slice_bmp.rowstride = bpp * slice_bmp.width;
slice_bmp.data = (guchar*) g_malloc (slice_bmp.rowstride *
slice_bmp.height);
/* Setup gl alignment to 0,0 top-left corner */
_cogl_texture_driver_prep_gl_for_pixels_download (
slice_bmp.rowstride,
bpp);
/* Download slice image data into temp bmp */
GE( glBindTexture (tex->gl_target, gl_handle) );
GE (glGetTexImage (tex->gl_target,
0, /* level */
target_gl_format,
target_gl_type,
slice_bmp.data) );
/* Copy portion of slice from temp to target bmp */
_cogl_bitmap_copy_subregion (&slice_bmp,
target_bmp,
0, 0,
x_span->start,
y_span->start,
x_span->size - x_span->waste,
y_span->size - y_span->waste);
/* Free temp bitmap */
g_free (slice_bmp.data);
}
else
{
GLvoid *dst = target_bmp->data
+ x_span->start * bpp
+ y_span->start * target_bmp->rowstride;
_cogl_texture_driver_prep_gl_for_pixels_download (
target_bmp->rowstride,
bpp);
/* Download slice image data */
GE( glBindTexture (tex->gl_target, gl_handle) );
GE( glGetTexImage (tex->gl_target,
0, /* level */
target_gl_format,
target_gl_type,
dst) );
}
}
}
return TRUE;
}
gboolean
_cogl_texture_driver_size_supported (GLenum gl_target,
GLenum gl_format,
GLenum gl_type,
int width,
int height)
{
if (gl_target == GL_TEXTURE_2D)
{
/* Proxy texture allows for a quick check for supported size */
GLint new_width = 0;
GE( glTexImage2D (GL_PROXY_TEXTURE_2D, 0, GL_RGBA,
width, height, 0 /* border */,
gl_format, gl_type, NULL) );
GE( glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0,
GL_TEXTURE_WIDTH, &new_width) );
return new_width != 0;
}
else
{
/* not used */
return 0;
}
}
void
_cogl_texture_driver_try_setting_gl_border_color (
GLuint gl_target,
const GLfloat *transparent_color)
{
/* Use a transparent border color so that we can leave the
color buffer alone when using texture co-ordinates
outside of the texture */
GE( glTexParameterfv (gl_target, GL_TEXTURE_BORDER_COLOR,
transparent_color) );
}
gboolean
_cogl_pixel_format_from_gl_internal (GLenum gl_int_format,
CoglPixelFormat *out_format)
{
/* It doesn't really matter we convert to exact same
format (some have no cogl match anyway) since format
is re-matched against cogl when getting or setting
texture image data.
*/
switch (gl_int_format)
{
case GL_ALPHA: case GL_ALPHA4: case GL_ALPHA8:
case GL_ALPHA12: case GL_ALPHA16:
*out_format = COGL_PIXEL_FORMAT_A_8;
return TRUE;
case GL_LUMINANCE: case GL_LUMINANCE4: case GL_LUMINANCE8:
case GL_LUMINANCE12: case GL_LUMINANCE16:
*out_format = COGL_PIXEL_FORMAT_G_8;
return TRUE;
case GL_RGB: case GL_RGB4: case GL_RGB5: case GL_RGB8:
case GL_RGB10: case GL_RGB12: case GL_RGB16: case GL_R3_G3_B2:
*out_format = COGL_PIXEL_FORMAT_RGB_888;
return TRUE;
case GL_RGBA: case GL_RGBA2: case GL_RGBA4: case GL_RGB5_A1:
case GL_RGBA8: case GL_RGB10_A2: case GL_RGBA12: case GL_RGBA16:
*out_format = COGL_PIXEL_FORMAT_RGBA_8888;
return TRUE;
}
return FALSE;
}
CoglPixelFormat
_cogl_pixel_format_to_gl (CoglPixelFormat format,
GLenum *out_glintformat,
GLenum *out_glformat,
GLenum *out_gltype)
{
CoglPixelFormat required_format;
GLenum glintformat = 0;
GLenum glformat = 0;
GLenum gltype = 0;
/* FIXME: check YUV support */
required_format = format;
/* Find GL equivalents */
switch (format & COGL_UNPREMULT_MASK)
{
case COGL_PIXEL_FORMAT_A_8:
glintformat = GL_ALPHA;
glformat = GL_ALPHA;
gltype = GL_UNSIGNED_BYTE;
break;
case COGL_PIXEL_FORMAT_G_8:
glintformat = GL_LUMINANCE;
glformat = GL_LUMINANCE;
gltype = GL_UNSIGNED_BYTE;
break;
case COGL_PIXEL_FORMAT_RGB_888:
glintformat = GL_RGB;
glformat = GL_RGB;
gltype = GL_UNSIGNED_BYTE;
break;
case COGL_PIXEL_FORMAT_BGR_888:
glintformat = GL_RGB;
glformat = GL_BGR;
gltype = GL_UNSIGNED_BYTE;
break;
case COGL_PIXEL_FORMAT_RGBA_8888:
glintformat = GL_RGBA;
glformat = GL_RGBA;
gltype = GL_UNSIGNED_BYTE;
break;
case COGL_PIXEL_FORMAT_BGRA_8888:
glintformat = GL_RGBA;
glformat = GL_BGRA;
gltype = GL_UNSIGNED_BYTE;
break;
/* The following two types of channel ordering
* have no GL equivalent unless defined using
* system word byte ordering */
case COGL_PIXEL_FORMAT_ARGB_8888:
glintformat = GL_RGBA;
glformat = GL_BGRA;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
gltype = GL_UNSIGNED_INT_8_8_8_8;
#else
gltype = GL_UNSIGNED_INT_8_8_8_8_REV;
#endif
break;
case COGL_PIXEL_FORMAT_ABGR_8888:
glintformat = GL_RGBA;
glformat = GL_RGBA;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
gltype = GL_UNSIGNED_INT_8_8_8_8;
#else
gltype = GL_UNSIGNED_INT_8_8_8_8_REV;
#endif
break;
/* The following three types of channel ordering
* are always defined using system word byte
* ordering (even according to GLES spec) */
case COGL_PIXEL_FORMAT_RGB_565:
glintformat = GL_RGB;
glformat = GL_RGB;
gltype = GL_UNSIGNED_SHORT_5_6_5;
break;
case COGL_PIXEL_FORMAT_RGBA_4444:
glintformat = GL_RGBA;
glformat = GL_RGBA;
gltype = GL_UNSIGNED_SHORT_4_4_4_4;
break;
case COGL_PIXEL_FORMAT_RGBA_5551:
glintformat = GL_RGBA;
glformat = GL_RGBA;
gltype = GL_UNSIGNED_SHORT_5_5_5_1;
break;
/* FIXME: check extensions for YUV support */
default:
break;
}
if (out_glintformat != NULL)
*out_glintformat = glintformat;
if (out_glformat != NULL)
*out_glformat = glformat;
if (out_gltype != NULL)
*out_gltype = gltype;
return required_format;
}
gboolean
_cogl_texture_driver_allows_foreign_gl_target (GLenum gl_target)
{
/* GL_ARB_texture_rectangle textures are supported if they are
created from foreign because some chipsets have trouble with
GL_ARB_texture_non_power_of_two. There is no Cogl call to create
them directly to emphasize the fact that they don't work fully
(for example, no mipmapping and complicated shader support) */
/* Allow 2-dimensional or rectangle textures only */
if (gl_target != GL_TEXTURE_2D && gl_target != CGL_TEXTURE_RECTANGLE_ARB)
return FALSE;
return TRUE;
}
void
_cogl_texture_driver_gl_generate_mipmaps (GLenum gl_target)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
GE( glGenerateMipmap (gl_target) );
}
CoglPixelFormat
_cogl_texture_driver_find_best_gl_get_data_format (
CoglPixelFormat format,
GLenum *closest_gl_format,
GLenum *closest_gl_type)
{
/* Find closest format that's supported by GL */
return _cogl_pixel_format_to_gl (format,
NULL, /* don't need */
closest_gl_format,
closest_gl_type);
}

View File

@ -48,12 +48,11 @@ libclutter_cogl_gles_la_SOURCES = \
$(top_builddir)/clutter/cogl/cogl-texture.h \ $(top_builddir)/clutter/cogl/cogl-texture.h \
$(top_builddir)/clutter/cogl/cogl-types.h \ $(top_builddir)/clutter/cogl/cogl-types.h \
$(top_builddir)/clutter/cogl/cogl-debug.h \ $(top_builddir)/clutter/cogl/cogl-debug.h \
cogl-texture-private.h \
cogl-fbo.h \ cogl-fbo.h \
cogl-context.h \ cogl-context.h \
cogl.c \ cogl.c \
cogl-primitives.c \ cogl-primitives.c \
cogl-texture.c \ cogl-texture-driver.c \
cogl-fbo.c \ cogl-fbo.c \
cogl-context.c \ cogl-context.c \
cogl-gles2-wrapper.h \ cogl-gles2-wrapper.h \

View File

@ -24,6 +24,7 @@
#ifndef __COGL_GLES2_WRAPPER_H__ #ifndef __COGL_GLES2_WRAPPER_H__
#define __COGL_GLES2_WRAPPER_H__ #define __COGL_GLES2_WRAPPER_H__
#include "cogl.h" /* needed for gl header include */
#include "cogl-internal.h" #include "cogl-internal.h"
G_BEGIN_DECLS G_BEGIN_DECLS

481
gles/cogl-texture-driver.c Normal file
View File

@ -0,0 +1,481 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2007,2008,2009 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:
* Matthew Allum <mallum@openedhand.com>
* Neil Roberts <neil@linux.intel.com>
* Robert Bragg <robert@linux.intel.com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "cogl.h"
#include "cogl-internal.h"
#include "cogl-util.h"
#include "cogl-bitmap.h"
#include "cogl-bitmap-private.h"
#include "cogl-texture-private.h"
#include "cogl-material.h"
#include "cogl-context.h"
#include "cogl-handle.h"
#include "cogl-primitives.h"
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "cogl-gles2-wrapper.h"
void
_cogl_texture_driver_bind (GLenum gl_target,
GLuint gl_handle,
GLenum gl_intformat)
{
GE (cogl_gles2_wrapper_bind_texture (gl_target, gl_handle, gl_intformat));
}
void
_cogl_texture_driver_prep_gl_for_pixels_upload (int pixels_rowstride,
int pixels_bpp)
{
_cogl_texture_prep_gl_alignment_for_pixels_upload (pixels_rowstride);
}
void
_cogl_texture_driver_prep_gl_for_pixels_download (int pixels_rowstride,
int pixels_bpp)
{
_cogl_texture_prep_gl_alignment_for_pixels_download (pixels_rowstride);
}
void
_cogl_texture_driver_upload_subregion_to_gl (CoglTexture *tex,
int src_x,
int src_y,
int dst_x,
int dst_y,
int width,
int height,
CoglBitmap *source_bmp,
GLuint source_gl_format,
GLuint source_gl_type,
GLuint gl_handle)
{
int bpp = _cogl_get_format_bpp (source_bmp->format);
CoglBitmap slice_bmp;
/* NB: GLES doesn't support the GL_UNPACK_ROW_LENGTH, GL_UNPACK_SKIP_PIXELS
* or GL_UNPACK_SKIP_ROWS pixel store options so we can't directly source a
* sub-region from source_bmp, we need to use a transient bitmap instead. */
/* FIXME: optimize by not copying to intermediate slice bitmap when source
* rowstride = bpp * width and the texture image is not sliced */
/* Setup temp bitmap for slice subregion */
slice_bmp.format = tex->bitmap.format;
slice_bmp.width = width;
slice_bmp.height = height;
slice_bmp.rowstride = bpp * slice_bmp.width;
slice_bmp.data = (guchar*) g_malloc (slice_bmp.rowstride * slice_bmp.height);
/* Setup gl alignment to match rowstride and top-left corner */
_cogl_texture_driver_prep_gl_for_pixels_upload (slice_bmp.rowstride,
bpp);
/* Copy subregion data */
_cogl_bitmap_copy_subregion (source_bmp,
&slice_bmp,
src_x,
src_y,
0, 0,
slice_bmp.width,
slice_bmp.height);
/* Upload new image data */
GE( _cogl_texture_driver_bind (tex->gl_target,
gl_handle, tex->gl_intformat) );
GE( glTexSubImage2D (tex->gl_target, 0,
dst_x, dst_y,
width, height,
source_gl_format,
source_gl_type,
slice_bmp.data) );
/* Free temp bitmap */
g_free (slice_bmp.data);
}
static void
_cogl_texture_draw_and_read (CoglTexture *tex,
CoglBitmap *target_bmp,
GLint *viewport)
{
gint bpp;
float rx1, ry1;
float rx2, ry2;
float tx1, ty1;
float tx2, ty2;
int bw, bh;
CoglBitmap rect_bmp;
CoglHandle handle;
handle = (CoglHandle) tex;
bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888);
ry1 = 0; ry2 = 0;
ty1 = 0; ty2 = 0;
/* Walk Y axis until whole bitmap height consumed */
for (bh = tex->bitmap.height; bh > 0; bh -= viewport[3])
{
/* Rectangle Y coords */
ry1 = ry2;
ry2 += (bh < viewport[3]) ? bh : viewport[3];
/* Normalized texture Y coords */
ty1 = ty2;
ty2 = (ry2 / (float)tex->bitmap.height);
rx1 = 0; rx2 = 0;
tx1 = 0; tx2 = 0;
/* Walk X axis until whole bitmap width consumed */
for (bw = tex->bitmap.width; bw > 0; bw-=viewport[2])
{
/* Rectangle X coords */
rx1 = rx2;
rx2 += (bw < viewport[2]) ? bw : viewport[2];
/* Normalized texture X coords */
tx1 = tx2;
tx2 = (rx2 / (float)tex->bitmap.width);
/* Draw a portion of texture */
cogl_rectangle_with_texture_coords (0, 0,
rx2 - rx1,
ry2 - ry1,
tx1, ty1,
tx2, ty2);
/* Read into a temporary bitmap */
rect_bmp.format = COGL_PIXEL_FORMAT_RGBA_8888;
rect_bmp.width = rx2 - rx1;
rect_bmp.height = ry2 - ry1;
rect_bmp.rowstride = bpp * rect_bmp.width;
rect_bmp.data = (guchar*) g_malloc (rect_bmp.rowstride *
rect_bmp.height);
_cogl_texture_driver_prep_gl_for_pixels_download (rect_bmp.rowstride,
bpp);
GE( glReadPixels (viewport[0], viewport[1],
rect_bmp.width,
rect_bmp.height,
GL_RGBA, GL_UNSIGNED_BYTE,
rect_bmp.data) );
/* Copy to target bitmap */
_cogl_bitmap_copy_subregion (&rect_bmp,
target_bmp,
0,0,
rx1,ry1,
rect_bmp.width,
rect_bmp.height);
/* Free temp bitmap */
g_free (rect_bmp.data);
}
}
}
gboolean
_cogl_texture_driver_download_from_gl (CoglTexture *tex,
CoglBitmap *target_bmp,
GLuint target_gl_format,
GLuint target_gl_type)
{
gint bpp;
GLint viewport[4];
CoglBitmap alpha_bmp;
CoglHandle prev_source;
_COGL_GET_CONTEXT (ctx, FALSE);
bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888);
/* Viewport needs to have some size and be inside the window for this */
GE( glGetIntegerv (GL_VIEWPORT, viewport) );
if (viewport[0] < 0 || viewport[1] < 0 ||
viewport[2] <= 0 || viewport[3] <= 0)
return FALSE;
/* Setup orthographic projection into current viewport
(0,0 in bottom-left corner to draw the texture
upside-down so we match the way glReadPixels works) */
_cogl_set_current_matrix (COGL_MATRIX_PROJECTION);
_cogl_current_matrix_push ();
_cogl_current_matrix_identity ();
_cogl_current_matrix_ortho (0, (float)(viewport[2]),
0, (float)(viewport[3]),
(float)(0),
(float)(100));
_cogl_set_current_matrix (COGL_MATRIX_MODELVIEW);
_cogl_current_matrix_push ();
_cogl_current_matrix_identity ();
/* Direct copy operation */
if (ctx->texture_download_material == COGL_INVALID_HANDLE)
{
ctx->texture_download_material = cogl_material_new ();
cogl_material_set_blend (ctx->texture_download_material,
"RGBA = ADD (SRC_COLOR, 0)",
NULL);
}
prev_source = cogl_handle_ref (ctx->source_material);
cogl_set_source (ctx->texture_download_material);
cogl_material_set_layer (ctx->texture_download_material, 0, tex);
cogl_material_set_layer_combine (ctx->texture_download_material,
0, /* layer */
"RGBA = REPLACE (TEXTURE)",
NULL);
_cogl_texture_draw_and_read (tex, target_bmp, viewport);
/* Check whether texture has alpha and framebuffer not */
/* FIXME: For some reason even if ALPHA_BITS is 8, the framebuffer
still doesn't seem to have an alpha buffer. This might be just
a PowerVR issue.
GLint r_bits, g_bits, b_bits, a_bits;
GE( glGetIntegerv (GL_ALPHA_BITS, &a_bits) );
GE( glGetIntegerv (GL_RED_BITS, &r_bits) );
GE( glGetIntegerv (GL_GREEN_BITS, &g_bits) );
GE( glGetIntegerv (GL_BLUE_BITS, &b_bits) );
printf ("R bits: %d\n", r_bits);
printf ("G bits: %d\n", g_bits);
printf ("B bits: %d\n", b_bits);
printf ("A bits: %d\n", a_bits); */
if ((tex->bitmap.format & COGL_A_BIT)/* && a_bits == 0*/)
{
guchar *srcdata;
guchar *dstdata;
guchar *srcpixel;
guchar *dstpixel;
gint x,y;
/* Create temp bitmap for alpha values */
alpha_bmp.format = COGL_PIXEL_FORMAT_RGBA_8888;
alpha_bmp.width = target_bmp->width;
alpha_bmp.height = target_bmp->height;
alpha_bmp.rowstride = bpp * alpha_bmp.width;
alpha_bmp.data = (guchar*) g_malloc (alpha_bmp.rowstride *
alpha_bmp.height);
/* Draw alpha values into RGB channels */
cogl_material_set_layer_combine (ctx->texture_download_material,
0, /* layer */
"RGBA = REPLACE (TEXTURE[A])",
NULL);
_cogl_texture_draw_and_read (tex, &alpha_bmp, viewport);
/* Copy temp R to target A */
srcdata = alpha_bmp.data;
dstdata = target_bmp->data;
for (y=0; y<target_bmp->height; ++y)
{
for (x=0; x<target_bmp->width; ++x)
{
srcpixel = srcdata + x*bpp;
dstpixel = dstdata + x*bpp;
dstpixel[3] = srcpixel[0];
}
srcdata += alpha_bmp.rowstride;
dstdata += target_bmp->rowstride;
}
g_free (alpha_bmp.data);
}
/* Restore old state */
_cogl_set_current_matrix (COGL_MATRIX_PROJECTION);
_cogl_current_matrix_pop ();
_cogl_set_current_matrix (COGL_MATRIX_MODELVIEW);
_cogl_current_matrix_pop ();
/* restore the original material */
cogl_set_source (prev_source);
cogl_handle_unref (prev_source);
return TRUE;
}
gboolean
_cogl_texture_driver_size_supported (GLenum gl_target,
GLenum gl_format,
GLenum gl_type,
int width,
int height)
{
return TRUE;
}
void
_cogl_texture_driver_try_setting_gl_border_color (
GLuint gl_target,
const GLfloat *transparent_color)
{
/* FAIL! */
}
gboolean
_cogl_pixel_format_from_gl_internal (GLenum gl_int_format,
CoglPixelFormat *out_format)
{
return TRUE;
}
CoglPixelFormat
_cogl_pixel_format_to_gl (CoglPixelFormat format,
GLenum *out_glintformat,
GLenum *out_glformat,
GLenum *out_gltype)
{
CoglPixelFormat required_format;
GLenum glintformat = 0;
GLenum glformat = 0;
GLenum gltype = 0;
/* FIXME: check YUV support */
required_format = format;
/* Find GL equivalents */
switch (format & COGL_UNPREMULT_MASK)
{
case COGL_PIXEL_FORMAT_A_8:
glintformat = GL_ALPHA;
glformat = GL_ALPHA;
gltype = GL_UNSIGNED_BYTE;
break;
case COGL_PIXEL_FORMAT_G_8:
glintformat = GL_LUMINANCE;
glformat = GL_LUMINANCE;
gltype = GL_UNSIGNED_BYTE;
break;
/* Just one 24-bit ordering supported */
case COGL_PIXEL_FORMAT_RGB_888:
case COGL_PIXEL_FORMAT_BGR_888:
glintformat = GL_RGB;
glformat = GL_RGB;
gltype = GL_UNSIGNED_BYTE;
required_format = COGL_PIXEL_FORMAT_RGB_888;
break;
/* Just one 32-bit ordering supported */
case COGL_PIXEL_FORMAT_RGBA_8888:
case COGL_PIXEL_FORMAT_BGRA_8888:
case COGL_PIXEL_FORMAT_ARGB_8888:
case COGL_PIXEL_FORMAT_ABGR_8888:
glintformat = GL_RGBA;
glformat = GL_RGBA;
gltype = GL_UNSIGNED_BYTE;
required_format = COGL_PIXEL_FORMAT_RGBA_8888;
required_format |= (format & COGL_PREMULT_BIT);
break;
/* The following three types of channel ordering
* are always defined using system word byte
* ordering (even according to GLES spec) */
case COGL_PIXEL_FORMAT_RGB_565:
glintformat = GL_RGB;
glformat = GL_RGB;
gltype = GL_UNSIGNED_SHORT_5_6_5;
break;
case COGL_PIXEL_FORMAT_RGBA_4444:
glintformat = GL_RGBA;
glformat = GL_RGBA;
gltype = GL_UNSIGNED_SHORT_4_4_4_4;
break;
case COGL_PIXEL_FORMAT_RGBA_5551:
glintformat = GL_RGBA;
glformat = GL_RGBA;
gltype = GL_UNSIGNED_SHORT_5_5_5_1;
break;
/* FIXME: check extensions for YUV support */
default:
break;
}
if (out_glintformat != NULL)
*out_glintformat = glintformat;
if (out_glformat != NULL)
*out_glformat = glformat;
if (out_gltype != NULL)
*out_gltype = gltype;
return required_format;
}
gboolean
_cogl_texture_driver_allows_foreign_gl_target (GLenum gl_target)
{
/* Allow 2-dimensional textures only */
if (gl_target != GL_TEXTURE_2D)
return FALSE;
return TRUE;
}
void
_cogl_texture_driver_gl_generate_mipmaps (GLenum gl_target)
{
GE( cogl_wrap_glGenerateMipmap (gl_target) );
}
CoglPixelFormat
_cogl_texture_driver_find_best_gl_get_data_format (
CoglPixelFormat format,
GLenum *closest_gl_format,
GLenum *closest_gl_type)
{
/* Find closest format that's supported by GL
(Can't use _cogl_pixel_format_to_gl since available formats
when reading pixels on GLES are severely limited) */
*closest_gl_format = GL_RGBA;
*closest_gl_type = GL_UNSIGNED_BYTE;
return COGL_PIXEL_FORMAT_RGBA_8888;
}

View File

@ -1,144 +0,0 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2007,2008,2009 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.
*/
#ifndef __COGL_TEXTURE_H
#define __COGL_TEXTURE_H
#include "cogl-bitmap-private.h"
#include "cogl-material-private.h"
#include "cogl-handle.h"
typedef struct _CoglTexture CoglTexture;
typedef struct _CoglTexSliceSpan CoglTexSliceSpan;
typedef struct _CoglSpanIter CoglSpanIter;
typedef struct _CoglTexturePixel CoglTexturePixel;
struct _CoglTexSliceSpan
{
gint start;
gint size;
gint waste;
};
struct _CoglSpanIter
{
gint index;
GArray *array;
CoglTexSliceSpan *span;
float pos;
float next_pos;
float origin;
float cover_start;
float cover_end;
float intersect_start;
float intersect_end;
float intersect_start_local;
float intersect_end_local;
gboolean intersects;
};
/* This is used to store the first pixel of each slice. This is only
used when glGenerateMipmap is not available */
struct _CoglTexturePixel
{
/* We need to store the format of the pixel because we store the
data in the source format which might end up being different for
each slice if a subregion is updated with a different format */
GLenum gl_format;
GLenum gl_type;
guint8 data[4];
};
struct _CoglTexture
{
CoglHandleObject _parent;
CoglBitmap bitmap;
gboolean bitmap_owner;
GLenum gl_target;
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
GArray *slice_x_spans;
GArray *slice_y_spans;
GArray *slice_gl_handles;
gint max_waste;
GLenum min_filter;
GLenum mag_filter;
gboolean is_foreign;
GLint wrap_mode;
gboolean auto_mipmap;
gboolean mipmaps_dirty;
/* This holds a copy of the first pixel in each slice. It is only
used to force an automatic update of the mipmaps when
glGenerateMipmap is not available. */
CoglTexturePixel *first_pixels;
};
/* To improve batching of geometry when submitting vertices to OpenGL we
* log the texture rectangles we want to draw to a journal, so when we
* later flush the journal we aim to batch data, and gl draw calls. */
typedef struct _CoglJournalEntry
{
CoglHandle material;
gint n_layers;
guint32 fallback_mask;
GLuint layer0_override_texture;
CoglMatrix model_view;
CoglMaterialFlushOptions flush_options;
} CoglJournalEntry;
CoglTexture*
_cogl_texture_pointer_from_handle (CoglHandle handle);
void
_cogl_texture_set_wrap_mode_parameter (CoglTexture *tex,
GLenum wrap_mode);
void
_cogl_texture_set_filters (CoglHandle handle,
GLenum min_filter,
GLenum mag_filter);
void
_cogl_texture_ensure_mipmaps (CoglHandle handle);
gboolean
_cogl_texture_span_has_waste (CoglTexture *tex,
gint x_span_index,
gint y_span_index);
void
_cogl_span_iter_begin (CoglSpanIter *iter,
GArray *array,
float origin,
float cover_start,
float cover_end);
gboolean
_cogl_span_iter_end (CoglSpanIter *iter);
void
_cogl_span_iter_next (CoglSpanIter *iter);
#endif /* __COGL_TEXTURE_H */

File diff suppressed because it is too large Load Diff