2006-07-24 Matthew Allum <mallum@openedhand.com>

* clutter/Makefile.am:
        * clutter/clutter-feature.c:
        * clutter/clutter-feature.h:

        Add new funcs for checking for available runtime GL
        extensions.

        * clutter/clutter-clone-texture.c:
        * clutter/clutter-texture.c:

        Add support for non power of two textures
       if GL_TEXTURE_RECTANGLE_ARB extension available ( at runtime ).
       Should lower texture memory needs a little.
This commit is contained in:
Matthew Allum 2006-07-24 21:15:19 +00:00
parent 55f9adeb41
commit ecccec75cb
8 changed files with 311 additions and 42 deletions

View File

@ -1,3 +1,19 @@
2006-07-24 Matthew Allum <mallum@openedhand.com>
* clutter/Makefile.am:
* clutter/clutter-feature.c:
* clutter/clutter-feature.h:
Add new funcs for checking for available runtime GL
extensions.
* clutter/clutter-clone-texture.c:
* clutter/clutter-texture.c:
Add support for non power of two textures
if GL_TEXTURE_RECTANGLE_ARB extension available ( at runtime ).
Should lower texture memory needs a little.
2006-07-17 Emmanuele Bassi <ebassi@openedhand.com>
* clutter/clutter-stage.c (clutter_stage_get_default): Fix

View File

@ -11,6 +11,7 @@ source_h = \
$(srcdir)/clutter-media.h \
$(srcdir)/clutter-event.h \
$(srcdir)/clutter-color.h \
$(srcdir)/clutter-feature.h \
$(srcdir)/clutter-timeline.h \
$(srcdir)/clutter-actor.h \
$(srcdir)/clutter-group.h \
@ -69,6 +70,7 @@ CLEANFILES = $(BUILT_SOURCES) stamp-clutter-enum-types.h
source_c = clutter-main.c \
clutter-util.c \
clutter-feature.c \
clutter-media.c \
clutter-event.c \
clutter-color.c \

View File

@ -34,6 +34,7 @@
#include "clutter-clone-texture.h"
#include "clutter-main.h"
#include "clutter-feature.h"
#include "clutter-util.h"
#include "clutter-enum-types.h"
#include "clutter-private.h" /* for DBG */
@ -91,8 +92,18 @@ clone_texture_render_to_gl_quad (ClutterCloneTexture *ctexture,
{
clutter_texture_bind_tile (priv->parent_texture, 0);
tx = (float) pwidth / clutter_util_next_p2 (pwidth);
ty = (float) pheight / clutter_util_next_p2 (pheight);
/* NPOTS textures *always* used if extension available
*/
if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE))
{
tx = (float) pwidth;
ty = (float) pheight;
}
else
{
tx = (float) pwidth / clutter_util_next_p2 (pwidth);
ty = (float) pheight / clutter_util_next_p2 (pheight);
}
qx1 = x1; qx2 = x2;
qy1 = y1; qy2 = y2;
@ -160,11 +171,13 @@ static void
clutter_clone_texture_paint (ClutterActor *self)
{
ClutterCloneTexturePrivate *priv;
ClutterActor *parent_texture;
ClutterActor *parent_texture;
gint x1, y1, x2, y2;
GLenum target_type;
priv = CLUTTER_CLONE_TEXTURE (self)->priv;
/* parent texture may have been hidden, there for need to make sure its
* realised with resources available.
*/
@ -172,8 +185,16 @@ clutter_clone_texture_paint (ClutterActor *self)
if (!CLUTTER_ACTOR_IS_REALIZED (parent_texture))
clutter_actor_realize (parent_texture);
/* FIXME: figure out nicer way of getting at this info...
*/
if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE)
&& clutter_texture_is_tiled (CLUTTER_TEXTURE(parent_texture)) == FALSE)
target_type = GL_TEXTURE_RECTANGLE_ARB;
else
target_type = GL_TEXTURE_2D;
glEnable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
glEnable(target_type);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4ub(255, 255, 255, clutter_actor_get_opacity(self));
@ -185,8 +206,7 @@ clutter_clone_texture_paint (ClutterActor *self)
clone_texture_render_to_gl_quad (CLUTTER_CLONE_TEXTURE(self),
x1, y1, x2, y2);
glDisable(GL_TEXTURE_2D);
glDisable(target_type);
glDisable(GL_BLEND);
}

91
clutter/clutter-feature.c Normal file
View File

@ -0,0 +1,91 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2006 OpenedHand
*
* 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.
*/
/**
* SECTION:clutter-feature
* @short_description: functions to query available GL features ay runtime
*
* Functions to query available GL features ay runtime
*/
#include "config.h"
#include "clutter-feature.h"
#include "string.h"
static gulong __features;
/* Note must be called after context created */
static gboolean
check_gl_extension (const gchar *name)
{
const gchar *ext;
gchar *end;
gint name_len, n;
ext = (const gchar*)glGetString(GL_EXTENSIONS);
if (name == NULL || ext == NULL)
return FALSE;
end = (gchar*)(ext + strlen(ext));
name_len = strlen(name);
while (ext < end)
{
n = strcspn(ext, " ");
if ((name_len == n) && (!strncmp(name, ext, n)))
return TRUE;
ext += (n + 1);
}
return FALSE;
}
gboolean
clutter_feature_available (gulong query)
{
return (__features & query);
}
gulong
clutter_feature_all (void)
{
return __features;
}
void
clutter_feature_init (void)
{
if (__features)
return;
__features = 0;
if (check_gl_extension ("GL_ARB_texture_rectangle"))
__features |= CLUTTER_FEATURE_TEXTURE_RECTANGLE;
}

59
clutter/clutter-feature.h Normal file
View File

@ -0,0 +1,59 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2006 OpenedHand
*
* 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.
*/
/**
* SECTION:clutter-main
* @short_description: Various 'global' clutter functions.
*
* Functions to retrieve various global Clutter resources and other utility
* functions for mainloops, events and threads
*/
#ifndef _HAVE_CLUTTER_FEATURE_H
#define _HAVE_CLUTTER_FEATURE_H
#include <glib.h>
#include <GL/glx.h>
#include <GL/gl.h>
G_END_DECLS
enum
{
CLUTTER_FEATURE_TEXTURE_RECTANGLE = (1 << 1)
};
gboolean
clutter_feature_available (gulong query);
gulong
clutter_feature_get_all (void);
void
clutter_feature_init (void);
G_END_DECLS
#endif

View File

@ -36,6 +36,7 @@
#include <stdlib.h>
#include "clutter-main.h"
#include "clutter-feature.h"
#include "clutter-actor.h"
#include "clutter-stage.h"
#include "clutter-private.h"
@ -516,6 +517,7 @@ is_gl_version_at_least_12 (void)
return FALSE;
}
/**
* clutter_init:
* @argc: The number of arguments in @argv
@ -573,13 +575,18 @@ clutter_init (int *argc, char ***argv)
g_return_val_if_fail (CLUTTER_IS_STAGE (context->stage), -3);
g_object_ref_sink (context->stage);
/* Realize to get context */
clutter_actor_realize (CLUTTER_ACTOR (context->stage));
g_return_val_if_fail
(CLUTTER_ACTOR_IS_REALIZED(CLUTTER_ACTOR(context->stage)), -4);
/* At least GL 1.2 is needed for CLAMP_TO_EDGE */
g_return_val_if_fail(is_gl_version_at_least_12 (), -5);
/* Check available features */
clutter_feature_init ();
events_init ();
context->is_initialized = TRUE;

View File

@ -34,6 +34,8 @@
#include <GL/glx.h>
#include <GL/gl.h>
G_BEGIN_DECLS
#define CLUTTER_HAS_DEBUG_MESSGES 1
#if (CLUTTER_HAS_DEBUG_MESSGES)
@ -92,5 +94,6 @@ clutter_threads_enter (void);
void
clutter_threads_leave (void);
G_END_DECLS
#endif

View File

@ -34,6 +34,7 @@
#include "clutter-texture.h"
#include "clutter-main.h"
#include "clutter-marshal.h"
#include "clutter-feature.h"
#include "clutter-util.h"
#include "clutter-private.h" /* for DBG */
@ -60,16 +61,19 @@ struct ClutterTexturePrivate
gint width, height;
GLenum pixel_format;
GLenum pixel_type;
GLenum target_type;
gboolean sync_actor_size;
gint max_tile_waste;
guint filter_quality;
gboolean repeat_x, repeat_y; /* non working */
gboolean tiled;
ClutterTextureTileDimention *x_tiles, *y_tiles;
gint n_x_tiles, n_y_tiles;
GLuint *tiles;
};
enum
@ -104,7 +108,7 @@ can_create (int width,
GLenum pixel_format,
GLenum pixel_type)
{
GLint new_width;
GLint new_width = 0;
CLUTTER_DBG("checking %ix%i", width, height);
@ -120,6 +124,19 @@ can_create (int width,
return new_width != 0;
}
static gboolean
can_create_rect_arb (int width,
int height,
GLenum pixel_format,
GLenum pixel_type)
{
/* FIXME: How to correctly query what max size of NPOTS text can be */
if (width > 4096 || height > 4096)
return FALSE;
return TRUE;
}
static int
tile_dimension (int to_fill,
int start_size,
@ -224,6 +241,8 @@ texture_render_to_gl_quad (ClutterTexture *texture,
priv = texture->priv;
qwidth = x2-x1;
qheight = y2-y1;
@ -240,10 +259,19 @@ texture_render_to_gl_quad (ClutterTexture *texture,
if (!priv->tiled)
{
glBindTexture(GL_TEXTURE_2D, priv->tiles[0]);
glBindTexture(priv->target_type, priv->tiles[0]);
tx = (float) priv->width / clutter_util_next_p2 (priv->width);
ty = (float) priv->height / clutter_util_next_p2 (priv->height);
if (priv->target_type == GL_TEXTURE_2D) /* POT */
{
tx = (float) priv->width / clutter_util_next_p2 (priv->width);
ty = (float) priv->height / clutter_util_next_p2 (priv->height);
}
else
{
tx = (float) priv->width;
ty = (float) priv->height;
}
qx1 = x1; qx2 = x2;
qy1 = y1; qy2 = y2;
@ -266,7 +294,7 @@ texture_render_to_gl_quad (ClutterTexture *texture,
{
int actual_w, actual_h;
glBindTexture(GL_TEXTURE_2D, priv->tiles[i]);
glBindTexture(priv->target_type, priv->tiles[i]);
actual_w = priv->x_tiles[x].size - priv->x_tiles[x].waste;
actual_h = priv->y_tiles[y].size - priv->y_tiles[y].waste;
@ -356,7 +384,6 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
g_return_if_fail (priv->pixbuf != NULL);
CLUTTER_MARK();
if (!priv->tiled)
@ -373,20 +400,22 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
CLUTTER_DBG("syncing for single tile");
glBindTexture(GL_TEXTURE_2D, priv->tiles[0]);
glBindTexture(priv->target_type, priv->tiles[0]);
glTexParameteri(GL_TEXTURE_2D,
glTexParameteri(priv->target_type,
GL_TEXTURE_WRAP_S,
priv->repeat_x ? GL_REPEAT : GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,
glTexParameteri(priv->target_type,
GL_TEXTURE_WRAP_T,
priv->repeat_y ? GL_REPEAT : GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
priv->filter_quality = 1;
glTexParameteri(priv->target_type, GL_TEXTURE_MAG_FILTER,
priv->filter_quality ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
glTexParameteri(priv->target_type, GL_TEXTURE_MIN_FILTER,
priv->filter_quality ? GL_LINEAR : GL_NEAREST);
glPixelStorei (GL_UNPACK_ROW_LENGTH,
@ -396,20 +425,31 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
if (create_textures)
{
gint width, height;
width = priv->width;
height = priv->height;
if (priv->target_type == GL_TEXTURE_2D) /* POT */
{
width = clutter_util_next_p2(priv->width);
height = clutter_util_next_p2(priv->height);
}
/* NOTE: Change to GL_RGB for non alpha textures */
glTexImage2D(GL_TEXTURE_2D,
glTexImage2D(priv->target_type,
0,
(gdk_pixbuf_get_n_channels (priv->pixbuf) == 4) ?
GL_RGBA : GL_RGB,
clutter_util_next_p2(priv->width),
clutter_util_next_p2(priv->height),
width,
height,
0,
priv->pixel_format,
priv->pixel_type,
NULL);
}
glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0,
glTexSubImage2D (priv->target_type, 0, 0, 0,
priv->width,
priv->height,
priv->pixel_format,
@ -489,20 +529,20 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
}
#endif
glBindTexture(GL_TEXTURE_2D, priv->tiles[i]);
glBindTexture(priv->target_type, priv->tiles[i]);
glTexParameteri(GL_TEXTURE_2D,
glTexParameteri(priv->target_type,
GL_TEXTURE_WRAP_S,
priv->repeat_x ? GL_REPEAT : GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,
glTexParameteri(priv->target_type,
GL_TEXTURE_WRAP_T,
priv->repeat_y ? GL_REPEAT : GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
glTexParameteri(priv->target_type, GL_TEXTURE_MAG_FILTER,
priv->filter_quality ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
glTexParameteri(priv->target_type, GL_TEXTURE_MIN_FILTER,
priv->filter_quality ? GL_LINEAR : GL_NEAREST);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
@ -514,7 +554,7 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
if (create_textures)
{
glTexImage2D(GL_TEXTURE_2D,
glTexImage2D(priv->target_type,
0,
(gdk_pixbuf_get_n_channels (priv->pixbuf) == 4) ?
GL_RGBA : GL_RGB,
@ -529,7 +569,7 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
{
/* Textures already created, so just update whats inside
*/
glTexSubImage2D (GL_TEXTURE_2D, 0,
glTexSubImage2D (priv->target_type, 0,
0, 0,
priv->x_tiles[x].size,
priv->y_tiles[y].size,
@ -595,7 +635,7 @@ clutter_texture_paint (ClutterActor *self)
glPushMatrix();
glEnable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
glEnable(texture->priv->target_type);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
opacity = clutter_actor_get_opacity(self);
@ -606,7 +646,7 @@ clutter_texture_paint (ClutterActor *self)
clutter_actor_get_coords (self, &x1, &y1, &x2, &y2);
texture_render_to_gl_quad (texture, x1, y1, x2, y2);
glDisable(GL_TEXTURE_2D);
glDisable(texture->priv->target_type);
glDisable(GL_BLEND);
glPopMatrix();
@ -668,6 +708,11 @@ clutter_texture_set_property (GObject *object,
break;
case PROP_USE_TILES:
priv->tiled = g_value_get_boolean (value);
if (priv->target_type == GL_TEXTURE_RECTANGLE_ARB
&& priv->tiled == TRUE)
priv->target_type = GL_TEXTURE_2D;
CLUTTER_DBG("Texture is tiled ? %i", priv->tiled);
break;
case PROP_MAX_TILE_WASTE:
@ -778,7 +823,12 @@ clutter_texture_class_init (ClutterTextureClass *klass)
"Enable use of tiled textures",
"Enables the use of tiled GL textures to more "
"efficiently use available texture memory",
TRUE,
/* FIXME: This default set at runtime :/
* As tiling depends on what GL features available.
* Need to figure out better solution
*/
(clutter_feature_available
(CLUTTER_FEATURE_TEXTURE_RECTANGLE) == FALSE),
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
g_object_class_install_property
@ -897,8 +947,15 @@ clutter_texture_init (ClutterTexture *self)
priv->pixel_format = GL_RGBA;
priv->repeat_x = FALSE;
priv->repeat_y = FALSE;
priv->pixbuf = NULL;
priv->pixbuf = NULL;
if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE))
{
priv->target_type = GL_TEXTURE_RECTANGLE_ARB;
priv->tiled = FALSE;
}
else
priv->target_type = GL_TEXTURE_2D;
self->priv = priv;
}
@ -986,19 +1043,33 @@ clutter_texture_set_pixbuf (ClutterTexture *texture, GdkPixbuf *pixbuf)
priv->pixel_format = GL_RGBA;
/* Force tiling if pixbuf is too big for single texture */
if (priv->tiled == FALSE
&& texture_dirty
&& !can_create(clutter_util_next_p2(priv->width),
clutter_util_next_p2(priv->height),
priv->pixel_format,
priv->pixel_type))
priv->tiled = TRUE;
if (priv->tiled == FALSE && texture_dirty)
{
if (priv->target_type == GL_TEXTURE_RECTANGLE_ARB
&& !can_create_rect_arb (priv->width,
priv->height,
priv->pixel_format,
priv->pixel_type))
{
/* If we cant create NPOT tex of this size fall back to tiles */
priv->tiled = TRUE;
priv->target_type = GL_TEXTURE_2D;
}
else if (priv->target_type == GL_TEXTURE_2D
&& !can_create(clutter_util_next_p2(priv->width),
clutter_util_next_p2(priv->height),
priv->pixel_format,
priv->pixel_type))
{
priv->tiled = TRUE;
}
}
clutter_threads_leave();
if (priv->sync_actor_size)
clutter_actor_set_size (CLUTTER_ACTOR(texture),
priv->width,
priv->height);
priv->width,
priv->height);
CLUTTER_DBG("set size %ix%i\n", priv->width, priv->height);
@ -1096,7 +1167,7 @@ clutter_texture_bind_tile (ClutterTexture *texture, gint index)
ClutterTexturePrivate *priv;
priv = texture->priv;
glBindTexture(GL_TEXTURE_2D, priv->tiles[index]);
glBindTexture(priv->target_type, priv->tiles[index]);
}
/**