Starts porting Cogl conformance tests from Clutter

This makes a start on porting the Cogl conformance tests that currently
still live in the Clutter repository to be standalone Cogl tests that no
longer require a ClutterStage.

The main thing is that this commit brings in is the basic testing
infrastructure we need, so now we can port more and more tests
incrementally.

Since the test suite wants a way to synchronize X requests/replies and
we can't simply call XSynchronize in the test-utils code before we know
if we are really running on X this adds a check for an environment
variable named "COGL_X11_SYNC" in cogl-xlib-renderer.c and if it's set
it forces XSynchronize (dpy, TRUE) to be called.

By default the conformance tests are run off screen. This makes the
tests run much faster and they also don't interfere with other work you
may want to do by constantly stealing focus. CoglOnscreen framebuffers
obviously don't get tested this way so it's important that the tests
also get run on screen every once in a while, especially if changes are
being made to CoglFramebuffer related code.  On screen testing can be
enabled by setting COGL_TEST_ONSCREEN=1 in your environment.
This commit is contained in:
Robert Bragg 2011-05-05 23:34:38 +01:00
parent 40848e72dc
commit b5a7657076
42 changed files with 7430 additions and 1 deletions

View File

@ -1,4 +1,4 @@
SUBDIRS = cogl
SUBDIRS = cogl tests
if BUILD_COGL_PANGO
SUBDIRS += cogl-pango

View File

@ -40,6 +40,8 @@
#include <X11/Xlib.h>
#include <X11/extensions/Xdamage.h>
#include <stdlib.h>
static char *_cogl_x11_display_name = NULL;
static GList *_cogl_xlib_renderers = NULL;
@ -163,6 +165,9 @@ _cogl_xlib_renderer_connect (CoglRenderer *renderer, GError **error)
if (!assert_xlib_display (renderer, error))
return FALSE;
if (getenv ("COGL_X11_SYNC"))
XSynchronize (xlib_renderer->xdpy, TRUE);
/* Check whether damage events are supported on this display */
if (!XDamageQueryExtension (xlib_renderer->xdpy,
&x11_renderer->damage_base,

View File

@ -968,6 +968,10 @@ doc/reference/cogl/cogl-docs.xml
doc/reference/cogl-2.0-experimental/Makefile
doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-docs.xml
examples/Makefile
tests/Makefile
tests/conform/Makefile
tests/conform/test-launcher.sh
tests/data/Makefile
po/Makefile.in
)

16
tests/Makefile.am Normal file
View File

@ -0,0 +1,16 @@
SUBDIRS = conform data
DIST_SUBDIRS = conform data
EXTRA_DIST = README
test conform:
( cd ./conform && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $$?
test-report full-report:
( cd ./conform && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $$?
.PHONY: test conform test-report full-report
# run make test as part of make check
check-local: test

63
tests/README Normal file
View File

@ -0,0 +1,63 @@
Outline of test categories:
The conform/ tests:
-------------------
These tests should be non-interactive unit-tests that verify a single
feature is behaving as documented. See conform/ADDING_NEW_TESTS for more
details.
Although it may seem a bit awkward; all the tests are built into a
single binary because it makes building the tests *much* faster by avoiding
lots of linking.
Each test has a wrapper script generated though so running the individual tests
should be convenient enough. Running the wrapper script will also print out for
convenience how you could run the test under gdb or valgrind like this for
example:
NOTE: For debugging purposes, you can run this single test as follows:
$ libtool --mode=execute \
gdb --eval-command="b test_cogl_depth_test" \
--args ./test-conformance -p /conform/cogl/test_cogl_depth_test
or:
$ env G_SLICE=always-malloc \
libtool --mode=execute \
valgrind ./test-conformance -p /conform/cogl/test_cogl_depth_test
By default the conformance tests are run offscreen. This makes the tests run
much faster and they also don't interfere with other work you may want to do by
constantly stealing focus. CoglOnscreen framebuffers obviously don't get tested
this way so it's important that the tests also get run onscreen every once in a
while, especially if changes are being made to CoglFramebuffer related code.
Onscreen testing can be enabled by setting COGL_TEST_ONSCREEN=1 in your
environment.
The micro-bench/ tests:
-----------------------
These should be focused performance tests, ideally testing a
single metric. Please never forget that these tests are synthetic and if you
are using them then you understand what metric is being tested. They probably
don't reflect any real world application loads and the intention is that you
use these tests once you have already determined the crux of your problem and
need focused feedback that your changes are indeed improving matters. There is
no exit status requirements for these tests, but they should give clear
feedback as to their performance. If the framerate is the feedback metric, then
the test should forcibly enable FPS debugging.
The data/ directory:
--------------------
This contains optional data (like images) that can be referenced by a test.
Misc notes:
-----------
• All tests should ideally include a detailed description in the source
explaining exactly what the test is for, how the test was designed to work,
and possibly a rationale for the approach taken for testing.
• When running tests under Valgrind, you should follow the instructions
available here:
http://live.gnome.org/Valgrind
and also use the suppression file available inside the data/ directory.

236
tests/conform/Makefile.am Normal file
View File

@ -0,0 +1,236 @@
include $(top_srcdir)/build/autotools/Makefile.am.silent
NULL =
noinst_PROGRAMS = test-conformance
common_sources = \
test-utils.h \
test-utils.c \
test-conform-main.c \
$(NULL)
unported_test_sources = \
test-backface-culling.c \
test-blend-strings.c \
test-fixed.c \
test-materials.c \
test-pipeline-user-matrix.c \
test-viewport.c \
test-multitexture.c \
test-npot-texture.c \
test-object.c \
test-offscreen.c \
test-path.c \
test-pixel-buffer.c \
test-premult.c \
test-readpixels.c \
test-sub-texture.c \
test-texture-3d.c \
test-texture-get-set-data.c \
test-texture-mipmaps.c \
test-texture-pixmap-x11.c \
test-texture-rectangle.c \
test-atlas-migration.c \
test-vertex-buffer-contiguous.c \
test-vertex-buffer-interleved.c \
test-vertex-buffer-mutability.c \
test-wrap-modes.c \
test-primitive.c \
test-just-vertex-shader.c \
$(NULL)
test_sources = \
test-depth-test.c \
$(NULL)
test_conformance_SOURCES = $(common_sources) $(test_sources)
if OS_WIN32
SHEXT =
else
SHEXT = $(EXEEXT)
endif
# For convenience, this provides a way to easily run individual unit tests:
.PHONY: wrappers clean-wrappers
#UNIT_TESTS = `./test-conformance -l -m thorough | $(GREP) '^/'`
wrappers: stamp-test-conformance
@true
stamp-test-conformance: Makefile $(srcdir)/test-conform-main.c
@mkdir -p wrappers
@sed -n \
-e 's/^ \{1,\}ADD_TEST *(.*"\([^",]\{1,\}\)", *\([a-zA-Z0-9_]\{1,\}\).*/\/conform\1\/\2/p' \
-e 's/^ \{1,\}ADD_CONDITIONAL_TEST *(.*"\([^",]\{1,\}\)", *\([a-zA-Z0-9_]\{1,\}\).*/\/conform\1\/\2/p' \
-e 's/^ \{1,\}ADD_TODO_TEST *(.*"\([^",]\{1,\}\)", *\([a-zA-Z0-9_]\{1,\}\).*/\/conform\1\/\2/p' \
$(srcdir)/test-conform-main.c > unit-tests
@chmod +x test-launcher.sh
@( echo "/stamp-test-conformance" ; \
echo "/test-conformance" ; \
echo "*.o" ; \
echo "*.xml" ; \
echo "*.html" ; \
echo ".gitignore" ; \
echo "unit-tests" ; \
echo "/wrappers/" ) > .gitignore
@for i in `cat unit-tests`; \
do \
unit=`basename $$i | sed -e s/_/-/g`; \
echo " GEN $$unit"; \
( echo "#!/bin/sh" ; echo "$(abs_builddir)/test-launcher.sh '$$i' \"\$$@\"" ) > $$unit$(SHEXT) ; \
( echo "#!/bin/sh" ; echo "exec $(abs_builddir)/test-conformance$(EXEEXT) -p $$i \"\$$@\"" ) > wrappers/$$unit$(SHEXT) ; \
chmod +x $$unit$(SHEXT); \
chmod +x wrappers/$$unit$(SHEXT); \
echo "/$$unit$(SHEXT)" >> .gitignore; \
done \
&& echo timestamp > $(@F)
clean-wrappers:
@for i in `cat unit-tests`; \
do \
unit=`basename $$i | sed -e s/_/-/g`; \
echo " RM $$unit"; \
rm -f $$unit$(SHEXT) ; \
rm -f wrappers/$$unit$(SHEXT) ; \
done \
&& rm -f unit-tests \
&& rm -f stamp-test-conformance
# NB: BUILT_SOURCES here a misnomer. We aren't building source, just inserting
# a phony rule that will generate symlink scripts for running individual tests
BUILT_SOURCES = wrappers
INCLUDES = -I$(top_srcdir)
test_conformance_CPPFLAGS = \
-DG_DISABLE_SINGLE_INCLUDES \
-DCOGL_ENABLE_EXPERIMENTAL_API \
-DCOGL_DISABLE_DEPRECATED \
-DTESTS_DATADIR=\""$(top_srcdir)/tests/data"\"
test_conformance_CFLAGS = -g3 -O0 $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS)
test_conformance_LDADD = $(COGL_DEP_LIBS) $(top_builddir)/cogl/libcogl.la
test_conformance_LDFLAGS = -export-dynamic
test: wrappers
@$(top_srcdir)/tests/conform/run-tests.sh \
./test-conformance$(EXEEXT) -o test-report.xml
test-verbose: wrappers
@$(top_srcdir)/tests/conform/run-tests.sh \
./test-conformance$(EXEEXT) -o test-report.xml --verbose
GTESTER = gtester
GTESTER_REPORT = gtester-report
# XXX: we could prevent the conformance test suite from running
# by simply defining this variable conditionally
TEST_PROGS = test-conformance
.PHONY: test
.PHONY: test-report perf-report full-report
.PHONY: test-report-npot perf-report-npot full-report-npot
# test-report: run tests and generate report
# perf-report: run tests with -m perf and generate report
# full-report: like test-report: with -m perf and -m slow
test-report perf-report full-report: ${TEST_PROGS}
@test -z "${TEST_PROGS}" || { \
export GTESTER_LOGDIR=`mktemp -d "$(srcdir)/.testlogs-XXXXXX"` ; \
if test -d "$(top_srcdir)/.git"; then \
export REVISION="`git describe`" ; \
else \
export REVISION="$(VERSION) $(CLUTTER_RELEASE_STATUS)" ; \
fi ; \
export TIMESTAMP=`date +%Y-%m-%dT%H:%M:%S%z` ; \
case $@ in \
test-report) test_options="-k";; \
perf-report) test_options="-k -m=perf";; \
full-report) test_options="-k -m=perf -m=slow";; \
esac ; \
$(top_srcdir)/tests/conform/run-tests.sh \
./test-conformance$(EXEEXT) \
--verbose \
$$test_options \
-o `mktemp "$$GTESTER_LOGDIR/log-XXXXXX"` ; \
echo '<?xml version="1.0"?>' > $@.xml ; \
echo '<report-collection>' >> $@.xml ; \
echo '<info>' >> $@.xml ; \
echo ' <package>$(PACKAGE)</package>' >> $@.xml ; \
echo ' <version>$(VERSION)</version>' >> $@.xml ; \
echo " <revision>$$REVISION</revision>" >> $@.xml ; \
echo " <date>$$TIMESTAMP</date>" >> $@.xml ; \
echo '</info>' >> $@.xml ; \
for lf in `ls -L "$$GTESTER_LOGDIR"/.` ; do \
sed '1,1s/^<?xml\b[^>?]*?>//' <"$$GTESTER_LOGDIR"/"$$lf" >> $@.xml ; \
done ; \
echo >> $@.xml ; \
echo '</report-collection>' >> $@.xml ; \
${GTESTER_REPORT} --version 2>/dev/null 1>&2 ; test "$$?" != 0 || ${GTESTER_REPORT} $@.xml >$@.html ; \
rm -rf "$$GTESTER_LOGDIR" ; \
}
# same as above, but with a wrapper that forcibly disables non-power of
# two textures
test-report-npot perf-report-npot full-report-npot: ${TEST_PROGS}
@test -z "${TEST_PROGS}" || { \
export COGL_DEBUG="$COGL_DEBUG,disable-npot-textures"; \
export GTESTER_LOGDIR=`mktemp -d "$(srcdir)/.testlogs-XXXXXX"` ; \
if test -d "$(top_srcdir)/.git"; then \
export REVISION="`git describe`" ; \
else \
export REVISION="$(VERSION) $(CLUTTER_RELEASE_STATUS)" ; \
fi ; \
export TIMESTAMP=`date +%Y-%m-%dT%H:%M:%S%z` ; \
case $@ in \
test-report-npot) test_options="-k";; \
perf-report-npot) test_options="-k -m=perf";; \
full-report-npot) test_options="-k -m=perf -m=slow";; \
esac ; \
$(top_srcdir)/tests/conform/run-tests.sh \
./test-conformance$(EXEEXT) \
--verbose \
$$test_options \
-o `mktemp "$$GTESTER_LOGDIR/log-XXXXXX"` ; \
echo '<?xml version="1.0"?>' > $@.xml ; \
echo '<report-collection>' >> $@.xml ; \
echo '<info>' >> $@.xml ; \
echo ' <package>$(PACKAGE)</package>' >> $@.xml ; \
echo ' <version>$(VERSION)</version>' >> $@.xml ; \
echo " <revision>$$REVISION</revision>" >> $@.xml ; \
echo " <date>$$TIMESTAMP</date>" >> $@.xml ; \
echo '</info>' >> $@.xml ; \
for lf in `ls -L "$$GTESTER_LOGDIR"/.` ; do \
sed '1,1s/^<?xml\b[^>?]*?>//' <"$$GTESTER_LOGDIR"/"$$lf" >> $@.xml ; \
done ; \
echo >> $@.xml ; \
echo '</report-collection>' >> $@.xml ; \
${GTESTER_REPORT} --version 2>/dev/null 1>&2 ; test "$$?" != 0 || ${GTESTER_REPORT} $@.xml >$@.html ; \
rm -rf "$$GTESTER_LOGDIR" ; \
}
XML_REPORTS = \
test-report.xml \
perf-report.xml \
full-report.xml \
test-report-npot.xml \
perf-report-npot.xml \
full-report-npot.xml
HTML_REPORTS = \
test-report.html \
perf-report.html \
full-report.html \
test-report-npot.html \
perf-report-npot.html \
full-report-npot.html
EXTRA_DIST = test-launcher.sh.in run-tests.sh
DISTCLEANFILES = test-launcher.sh .gitignore
# we override the clean-generic target to clean up the wrappers so
# we cannot use CLEANFILES
clean-generic: clean-wrappers
$(QUIET_RM)rm -f $(XML_REPORTS) $(HTML_REPORTS)

12
tests/conform/run-tests.sh Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
BINARY=$1
shift
TMP=`./$BINARY -l -m thorough | grep '^/' | sed -e s/_/-/g`
for i in $TMP
do
TESTS="$TESTS wrappers/`basename $i`"
done
exec gtester "$@" $TESTS

View File

@ -0,0 +1,133 @@
#include <clutter/clutter.h>
#include "test-conform-common.h"
#define N_TEXTURES 128
#define OPACITY_FOR_ROW(y) \
(0xff - ((y) & 0xf) * 0x10)
#define COLOR_FOR_SIZE(size) \
(colors + (size) % 3)
static const ClutterColor colors[] =
{ { 0xff, 0x00, 0x00, 0xff },
{ 0x00, 0xff, 0x00, 0xff },
{ 0x00, 0x00, 0xff, 0xff } };
static CoglHandle
create_texture (int size)
{
CoglHandle texture;
const ClutterColor *color;
guint8 *data, *p;
int x, y;
/* Create a red, green or blue texture depending on the size */
color = COLOR_FOR_SIZE (size);
p = data = g_malloc (size * size * 4);
/* Fill the data with the color but fade the opacity out with
increasing y coordinates so that we can see the blending it the
atlas migration accidentally blends with garbage in the
texture */
for (y = 0; y < size; y++)
{
int opacity = OPACITY_FOR_ROW (y);
for (x = 0; x < size; x++)
{
/* Store the colors premultiplied */
p[0] = color->red * opacity / 255;
p[1] = color->green * opacity / 255;
p[2] = color->blue * opacity / 255;
p[3] = opacity;
p += 4;
}
}
texture = cogl_texture_new_from_data (size, /* width */
size, /* height */
COGL_TEXTURE_NONE, /* flags */
/* format */
COGL_PIXEL_FORMAT_RGBA_8888,
/* internal format */
COGL_PIXEL_FORMAT_RGBA_8888,
/* rowstride */
size * 4,
data);
g_free (data);
return texture;
}
static void
verify_texture (CoglHandle texture, int size)
{
guint8 *data, *p;
int x, y;
const ClutterColor *color;
color = COLOR_FOR_SIZE (size);
p = data = g_malloc (size * size * 4);
cogl_texture_get_data (texture,
COGL_PIXEL_FORMAT_RGBA_8888,
size * 4,
data);
for (y = 0; y < size; y++)
{
int opacity = OPACITY_FOR_ROW (y);
for (x = 0; x < size; x++)
{
g_assert_cmpint (p[0], ==, color->red * opacity / 255);
g_assert_cmpint (p[1], ==, color->green * opacity / 255);
g_assert_cmpint (p[2], ==, color->blue * opacity / 255);
g_assert_cmpint (p[3], ==, opacity);
p += 4;
}
}
g_free (data);
}
void
test_cogl_atlas_migration (TestUtilsGTestFixture *fixture,
void *data)
{
CoglHandle textures[N_TEXTURES];
int i, tex_num;
/* Create and destroy all of the textures a few times to increase
the chances that we'll end up reusing the buffers for previously
discarded atlases */
for (i = 0; i < 5; i++)
{
for (tex_num = 0; tex_num < N_TEXTURES; tex_num++)
textures[tex_num] = create_texture (tex_num + 1);
for (tex_num = 0; tex_num < N_TEXTURES; tex_num++)
cogl_object_unref (textures[tex_num]);
}
/* Create all the textures again */
for (tex_num = 0; tex_num < N_TEXTURES; tex_num++)
textures[tex_num] = create_texture (tex_num + 1);
/* Verify that they all still have the right data */
for (tex_num = 0; tex_num < N_TEXTURES; tex_num++)
verify_texture (textures[tex_num], tex_num + 1);
/* Destroy them all */
for (tex_num = 0; tex_num < N_TEXTURES; tex_num++)
cogl_object_unref (textures[tex_num]);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,339 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <string.h>
#include "test-conform-common.h"
#ifdef CLUTTER_COGL_HAS_GL
/* Size the texture so that it is just off a power of two to enourage
it so use software tiling when NPOTs aren't available */
#define TEXTURE_SIZE 257
#else /* CLUTTER_COGL_HAS_GL */
/* We can't use the funny-sized texture on GL ES because it will break
cogl_texture_polygon. However there is only one code path for
rendering quads so there is no need */
#define TEXTURE_SIZE 32
#endif /* CLUTTER_COGL_HAS_GL */
/* Amount of pixels to skip off the top, bottom, left and right of the
texture when reading back the stage */
#define TEST_INSET 4
/* Size to actually render the texture at */
#define TEXTURE_RENDER_SIZE 32
typedef struct _TestState
{
CoglHandle texture;
CoglHandle offscreen;
CoglHandle offscreen_tex;
} TestState;
static gboolean
validate_part (int xnum, int ynum, gboolean shown)
{
guchar *pixels, *p;
gboolean ret = TRUE;
pixels = g_malloc0 ((TEXTURE_RENDER_SIZE - TEST_INSET * 2)
* (TEXTURE_RENDER_SIZE - TEST_INSET * 2) * 4);
/* Read the appropriate part but skip out a few pixels around the
edges */
cogl_read_pixels (xnum * TEXTURE_RENDER_SIZE + TEST_INSET,
ynum * TEXTURE_RENDER_SIZE + TEST_INSET,
TEXTURE_RENDER_SIZE - TEST_INSET * 2,
TEXTURE_RENDER_SIZE - TEST_INSET * 2,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixels);
/* Make sure every pixels is the appropriate color */
for (p = pixels;
p < pixels + ((TEXTURE_RENDER_SIZE - TEST_INSET * 2)
* (TEXTURE_RENDER_SIZE - TEST_INSET * 2));
p += 4)
{
if (p[0] != (shown ? 255 : 0))
ret = FALSE;
if (p[1] != 0)
ret = FALSE;
if (p[2] != 0)
ret = FALSE;
}
g_free (pixels);
return ret;
}
static void
do_test_backface_culling (TestState *state)
{
int i;
CoglHandle material = cogl_material_new ();
cogl_material_set_layer_filters (material, 0,
COGL_MATERIAL_FILTER_NEAREST,
COGL_MATERIAL_FILTER_NEAREST);
cogl_set_backface_culling_enabled (TRUE);
cogl_push_matrix ();
/* Render the scene twice - once with backface culling enabled and
once without. The second time is translated so that it is below
the first */
for (i = 0; i < 2; i++)
{
float x1 = 0, x2, y1 = 0, y2 = (float)(TEXTURE_RENDER_SIZE);
CoglTextureVertex verts[4];
cogl_set_source (material);
memset (verts, 0, sizeof (verts));
x2 = x1 + (float)(TEXTURE_RENDER_SIZE);
/* Draw a front-facing texture */
cogl_material_set_layer (material, 0, state->texture);
cogl_rectangle (x1, y1, x2, y2);
x1 = x2;
x2 = x1 + (float)(TEXTURE_RENDER_SIZE);
/* Draw a front-facing texture with flipped texcoords */
cogl_material_set_layer (material, 0, state->texture);
cogl_rectangle_with_texture_coords (x1, y1, x2, y2,
1.0, 0.0, 0.0, 1.0);
x1 = x2;
x2 = x1 + (float)(TEXTURE_RENDER_SIZE);
/* Draw a back-facing texture */
cogl_material_set_layer (material, 0, state->texture);
cogl_rectangle (x2, y1, x1, y2);
x1 = x2;
x2 = x1 + (float)(TEXTURE_RENDER_SIZE);
/* Draw a front-facing texture polygon */
verts[0].x = x1; verts[0].y = y2;
verts[1].x = x2; verts[1].y = y2;
verts[2].x = x2; verts[2].y = y1;
verts[3].x = x1; verts[3].y = y1;
verts[0].tx = 0; verts[0].ty = 0;
verts[1].tx = 1.0; verts[1].ty = 0;
verts[2].tx = 1.0; verts[2].ty = 1.0;
verts[3].tx = 0; verts[3].ty = 1.0;
cogl_material_set_layer (material, 0, state->texture);
cogl_polygon (verts, 4, FALSE);
x1 = x2;
x2 = x1 + (float)(TEXTURE_RENDER_SIZE);
/* Draw a back-facing texture polygon */
verts[0].x = x1; verts[0].y = y1;
verts[1].x = x2; verts[1].y = y1;
verts[2].x = x2; verts[2].y = y2;
verts[3].x = x1; verts[3].y = y2;
verts[0].tx = 0; verts[0].ty = 0;
verts[1].tx = 1.0; verts[1].ty = 0;
verts[2].tx = 1.0; verts[2].ty = 1.0;
verts[3].tx = 0; verts[3].ty = 1.0;
cogl_material_set_layer (material, 0, state->texture);
cogl_polygon (verts, 4, FALSE);
x1 = x2;
x2 = x1 + (float)(TEXTURE_RENDER_SIZE);
/* Draw a regular rectangle (this should always show) */
cogl_set_source_color4f (1.0, 0, 0, 1.0);
cogl_rectangle (x1, y1, x2, y2);
/* The second time round draw beneath the first with backface
culling disabled */
cogl_translate (0, TEXTURE_RENDER_SIZE, 0);
cogl_set_backface_culling_enabled (FALSE);
}
cogl_handle_unref (material);
cogl_pop_matrix ();
/* Front-facing texture */
g_assert (validate_part (0, 0, TRUE));
/* Front-facing texture with flipped tex coords */
g_assert (validate_part (1, 0, TRUE));
/* Back-facing texture */
g_assert (validate_part (2, 0, FALSE));
/* Front-facing texture polygon */
g_assert (validate_part (3, 0, TRUE));
/* Back-facing texture polygon */
g_assert (validate_part (4, 0, FALSE));
/* Regular rectangle */
g_assert (validate_part (5, 0, TRUE));
/* Backface culling disabled - everything should be shown */
/* Front-facing texture */
g_assert (validate_part (0, 1, TRUE));
/* Front-facing texture with flipped tex coords */
g_assert (validate_part (1, 1, TRUE));
/* Back-facing texture */
g_assert (validate_part (2, 1, TRUE));
/* Front-facing texture polygon */
g_assert (validate_part (3, 1, TRUE));
/* Back-facing texture polygon */
g_assert (validate_part (4, 1, TRUE));
/* Regular rectangle */
g_assert (validate_part (5, 1, TRUE));
}
static void
on_paint (ClutterActor *actor, TestState *state)
{
CoglColor clr;
float stage_viewport[4];
CoglMatrix stage_projection;
CoglMatrix stage_modelview;
cogl_color_init_from_4ub (&clr, 0x00, 0x00, 0x00, 0xff);
do_test_backface_culling (state);
/* Since we are going to repeat the test rendering offscreen we clear the
* stage, just to minimize the chance of a some other bug causing us
* mistakenly reading back the results from the stage and giving a false
* posistive. */
cogl_clear (&clr, COGL_BUFFER_BIT_COLOR|COGL_BUFFER_BIT_STENCIL);
/*
* Now repeat the test but rendered to an offscreen framebuffer...
*/
cogl_get_viewport (stage_viewport);
cogl_get_projection_matrix (&stage_projection);
cogl_get_modelview_matrix (&stage_modelview);
cogl_push_framebuffer (state->offscreen);
cogl_clear (&clr, COGL_BUFFER_BIT_COLOR|COGL_BUFFER_BIT_STENCIL);
cogl_set_viewport (stage_viewport[0],
stage_viewport[1],
stage_viewport[2],
stage_viewport[3]);
cogl_set_projection_matrix (&stage_projection);
cogl_set_modelview_matrix (&stage_modelview);
do_test_backface_culling (state);
cogl_pop_framebuffer ();
/* Incase we want feedback of what was drawn offscreen we draw it
* to the stage... */
cogl_set_source_texture (state->offscreen_tex);
cogl_rectangle (0, 0, stage_viewport[2], stage_viewport[3]);
/* Comment this out if you want visual feedback of what this test
* paints.
*/
clutter_main_quit ();
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
static CoglHandle
make_texture (void)
{
guchar *tex_data, *p;
CoglHandle tex;
tex_data = g_malloc (TEXTURE_SIZE * TEXTURE_SIZE * 4);
for (p = tex_data + TEXTURE_SIZE * TEXTURE_SIZE * 4; p > tex_data;)
{
*(--p) = 255;
*(--p) = 0;
*(--p) = 0;
*(--p) = 255;
}
tex = cogl_texture_new_from_data (TEXTURE_SIZE,
TEXTURE_SIZE,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_RGBA_8888,
COGL_PIXEL_FORMAT_ANY,
TEXTURE_SIZE * 4,
tex_data);
g_free (tex_data);
return tex;
}
void
test_cogl_backface_culling (TestUtilsGTestFixture *fixture,
void *data)
{
TestState state;
CoglHandle tex;
ClutterActor *stage;
float stage_width;
float stage_height;
const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
ClutterActor *group;
unsigned int idle_source;
stage = clutter_stage_get_default ();
clutter_actor_get_size (stage, &stage_width, &stage_height);
state.offscreen = COGL_INVALID_HANDLE;
state.texture = make_texture ();
tex = cogl_texture_new_with_size (stage_width, stage_height,
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_ANY); /* internal fmt */
state.offscreen = cogl_offscreen_new_to_texture (tex);
state.offscreen_tex = tex;
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
group = clutter_group_new ();
clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
/* We force continuous redrawing of the stage, since we need to skip
* the first few frames, and we wont be doing anything else that
* will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, stage);
g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
clutter_actor_show_all (stage);
clutter_main ();
g_source_remove (idle_source);
cogl_handle_unref (state.offscreen);
cogl_handle_unref (state.offscreen_tex);
cogl_handle_unref (state.texture);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,434 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <string.h>
#include "test-conform-common.h"
static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
#define QUAD_WIDTH 20
#define RED 0
#define GREEN 1
#define BLUE 2
#define ALPHA 3
#define MASK_RED(COLOR) ((COLOR & 0xff000000) >> 24)
#define MASK_GREEN(COLOR) ((COLOR & 0xff0000) >> 16)
#define MASK_BLUE(COLOR) ((COLOR & 0xff00) >> 8)
#define MASK_ALPHA(COLOR) (COLOR & 0xff)
#define BLEND_CONSTANT_UNUSED 0xDEADBEEF
#define TEX_CONSTANT_UNUSED 0xDEADBEEF
typedef struct _TestState
{
ClutterGeometry stage_geom;
} TestState;
static void
check_pixel (GLubyte *pixel, guint32 color)
{
guint8 r = MASK_RED (color);
guint8 g = MASK_GREEN (color);
guint8 b = MASK_BLUE (color);
guint8 a = MASK_ALPHA (color);
if (g_test_verbose ())
g_print (" expected = %x, %x, %x, %x\n",
r, g, b, a);
/* FIXME - allow for hardware in-precision */
g_assert_cmpint (pixel[RED], ==, r);
g_assert_cmpint (pixel[GREEN], ==, g);
g_assert_cmpint (pixel[BLUE], ==, b);
/* FIXME
* We ignore the alpha, since we don't know if our render target is
* RGB or RGBA */
/* g_assert (pixel[ALPHA] == a); */
}
static void
test_blend (TestState *state,
int x,
int y,
guint32 src_color,
guint32 dst_color,
const char *blend_string,
guint32 blend_constant,
guint32 expected_result)
{
/* src color */
guint8 Sr = MASK_RED (src_color);
guint8 Sg = MASK_GREEN (src_color);
guint8 Sb = MASK_BLUE (src_color);
guint8 Sa = MASK_ALPHA (src_color);
/* dest color */
guint8 Dr = MASK_RED (dst_color);
guint8 Dg = MASK_GREEN (dst_color);
guint8 Db = MASK_BLUE (dst_color);
guint8 Da = MASK_ALPHA (dst_color);
/* blend constant - when applicable */
guint8 Br = MASK_RED (blend_constant);
guint8 Bg = MASK_GREEN (blend_constant);
guint8 Bb = MASK_BLUE (blend_constant);
guint8 Ba = MASK_ALPHA (blend_constant);
CoglColor blend_const_color;
CoglHandle material;
gboolean status;
GError *error = NULL;
GLubyte pixel[4];
GLint y_off;
GLint x_off;
/* First write out the destination color without any blending... */
material = cogl_material_new ();
cogl_material_set_color4ub (material, Dr, Dg, Db, Da);
cogl_material_set_blend (material, "RGBA = ADD (SRC_COLOR, 0)", NULL);
cogl_set_source (material);
cogl_rectangle (x * QUAD_WIDTH,
y * QUAD_WIDTH,
x * QUAD_WIDTH + QUAD_WIDTH,
y * QUAD_WIDTH + QUAD_WIDTH);
cogl_handle_unref (material);
/*
* Now blend a rectangle over our well defined destination:
*/
material = cogl_material_new ();
cogl_material_set_color4ub (material, Sr, Sg, Sb, Sa);
status = cogl_material_set_blend (material, blend_string, &error);
if (!status)
{
/* It's not strictly a test failure; you need a more capable GPU or
* driver to test this blend string. */
g_debug ("Failed to test blend string %s: %s",
blend_string, error->message);
}
cogl_color_init_from_4ub (&blend_const_color, Br, Bg, Bb, Ba);
cogl_material_set_blend_constant (material, &blend_const_color);
cogl_set_source (material);
cogl_rectangle (x * QUAD_WIDTH,
y * QUAD_WIDTH,
x * QUAD_WIDTH + QUAD_WIDTH,
y * QUAD_WIDTH + QUAD_WIDTH);
cogl_handle_unref (material);
/* See what we got... */
y_off = y * QUAD_WIDTH + (QUAD_WIDTH / 2);
x_off = x * QUAD_WIDTH + (QUAD_WIDTH / 2);
cogl_read_pixels (x_off, y_off, 1, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixel);
if (g_test_verbose ())
{
g_print ("test_blend (%d, %d):\n%s\n", x, y, blend_string);
g_print (" src color = %02x, %02x, %02x, %02x\n", Sr, Sg, Sb, Sa);
g_print (" dst color = %02x, %02x, %02x, %02x\n", Dr, Dg, Db, Da);
if (blend_constant != BLEND_CONSTANT_UNUSED)
g_print (" blend constant = %02x, %02x, %02x, %02x\n",
Br, Bg, Bb, Ba);
else
g_print (" blend constant = UNUSED\n");
g_print (" result = %x, %x, %x, %x\n",
pixel[RED], pixel[GREEN], pixel[BLUE], pixel[ALPHA]);
}
check_pixel (pixel, expected_result);
}
static CoglHandle
make_texture (guint32 color)
{
guchar *tex_data, *p;
guint8 r = MASK_RED (color);
guint8 g = MASK_GREEN (color);
guint8 b = MASK_BLUE (color);
guint8 a = MASK_ALPHA (color);
CoglHandle tex;
tex_data = g_malloc (QUAD_WIDTH * QUAD_WIDTH * 4);
for (p = tex_data + QUAD_WIDTH * QUAD_WIDTH * 4; p > tex_data;)
{
*(--p) = a;
*(--p) = b;
*(--p) = g;
*(--p) = r;
}
/* Note: we don't use COGL_PIXEL_FORMAT_ANY for the internal format here
* since we don't want to allow Cogl to premultiply our data. */
tex = cogl_texture_new_from_data (QUAD_WIDTH,
QUAD_WIDTH,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_RGBA_8888,
COGL_PIXEL_FORMAT_RGBA_8888,
QUAD_WIDTH * 4,
tex_data);
g_free (tex_data);
return tex;
}
static void
test_tex_combine (TestState *state,
int x,
int y,
guint32 tex0_color,
guint32 tex1_color,
guint32 combine_constant,
const char *combine_string,
guint32 expected_result)
{
CoglHandle tex0, tex1;
/* combine constant - when applicable */
guint8 Cr = MASK_RED (combine_constant);
guint8 Cg = MASK_GREEN (combine_constant);
guint8 Cb = MASK_BLUE (combine_constant);
guint8 Ca = MASK_ALPHA (combine_constant);
CoglColor combine_const_color;
CoglHandle material;
gboolean status;
GError *error = NULL;
GLubyte pixel[4];
GLint y_off;
GLint x_off;
tex0 = make_texture (tex0_color);
tex1 = make_texture (tex1_color);
material = cogl_material_new ();
cogl_material_set_color4ub (material, 0x80, 0x80, 0x80, 0x80);
cogl_material_set_blend (material, "RGBA = ADD (SRC_COLOR, 0)", NULL);
cogl_material_set_layer (material, 0, tex0);
cogl_material_set_layer_combine (material, 0,
"RGBA = REPLACE (TEXTURE)", NULL);
cogl_material_set_layer (material, 1, tex1);
status = cogl_material_set_layer_combine (material, 1,
combine_string, &error);
if (!status)
{
/* It's not strictly a test failure; you need a more capable GPU or
* driver to test this texture combine string. */
g_debug ("Failed to test texture combine string %s: %s",
combine_string, error->message);
}
cogl_color_init_from_4ub (&combine_const_color, Cr, Cg, Cb, Ca);
cogl_material_set_layer_combine_constant (material, 1, &combine_const_color);
cogl_set_source (material);
cogl_rectangle (x * QUAD_WIDTH,
y * QUAD_WIDTH,
x * QUAD_WIDTH + QUAD_WIDTH,
y * QUAD_WIDTH + QUAD_WIDTH);
cogl_handle_unref (material);
cogl_handle_unref (tex0);
cogl_handle_unref (tex1);
/* See what we got... */
y_off = y * QUAD_WIDTH + (QUAD_WIDTH / 2);
x_off = x * QUAD_WIDTH + (QUAD_WIDTH / 2);
cogl_read_pixels (x_off, y_off, 1, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixel);
if (g_test_verbose ())
{
g_print ("test_tex_combine (%d, %d):\n%s\n", x, y, combine_string);
g_print (" texture 0 color = 0x%08lX\n", (unsigned long)tex0_color);
g_print (" texture 1 color = 0x%08lX\n", (unsigned long)tex1_color);
if (combine_constant != TEX_CONSTANT_UNUSED)
g_print (" combine constant = %02x, %02x, %02x, %02x\n",
Cr, Cg, Cb, Ca);
else
g_print (" combine constant = UNUSED\n");
g_print (" result = %02x, %02x, %02x, %02x\n",
pixel[RED], pixel[GREEN], pixel[BLUE], pixel[ALPHA]);
}
check_pixel (pixel, expected_result);
}
static void
on_paint (ClutterActor *actor, TestState *state)
{
test_blend (state, 0, 0, /* position */
0xff0000ff, /* src */
0xffffffff, /* dst */
"RGBA = ADD (SRC_COLOR, 0)",
BLEND_CONSTANT_UNUSED,
0xff0000ff); /* expected */
test_blend (state, 1, 0, /* position */
0x11223344, /* src */
0x11223344, /* dst */
"RGBA = ADD (SRC_COLOR, DST_COLOR)",
BLEND_CONSTANT_UNUSED,
0x22446688); /* expected */
test_blend (state, 2, 0, /* position */
0x80808080, /* src */
0xffffffff, /* dst */
"RGBA = ADD (SRC_COLOR * (CONSTANT), 0)",
0x80808080, /* constant (RGBA all = 0.5 when normalized) */
0x40404040); /* expected */
test_blend (state, 3, 0, /* position */
0x80000080, /* src (alpha = 0.5 when normalized) */
0x40000000, /* dst */
"RGBA = ADD (SRC_COLOR * (SRC_COLOR[A]),"
" DST_COLOR * (1-SRC_COLOR[A]))",
BLEND_CONSTANT_UNUSED,
0x60000040); /* expected */
/* XXX:
* For all texture combine tests tex0 will use a combine mode of
* "RGBA = REPLACE (TEXTURE)"
*/
test_tex_combine (state, 4, 0, /* position */
0x11111111, /* texture 0 color */
0x22222222, /* texture 1 color */
TEX_CONSTANT_UNUSED,
"RGBA = ADD (PREVIOUS, TEXTURE)", /* tex combine */
0x33333333); /* expected */
test_tex_combine (state, 5, 0, /* position */
0x40404040, /* texture 0 color */
0x80808080, /* texture 1 color (RGBA all = 0.5) */
TEX_CONSTANT_UNUSED,
"RGBA = MODULATE (PREVIOUS, TEXTURE)", /* tex combine */
0x20202020); /* expected */
test_tex_combine (state, 6, 0, /* position */
0xffffff80, /* texture 0 color (alpha = 0.5) */
0xDEADBE40, /* texture 1 color */
TEX_CONSTANT_UNUSED,
"RGB = REPLACE (PREVIOUS)"
"A = MODULATE (PREVIOUS, TEXTURE)", /* tex combine */
0xffffff20); /* expected */
/* XXX: we are assuming test_tex_combine creates a material with
* a color of 0x80808080 (i.e. the "PRIMARY" color) */
test_tex_combine (state, 7, 0, /* position */
0xffffff80, /* texture 0 color (alpha = 0.5) */
0xDEADBE20, /* texture 1 color */
TEX_CONSTANT_UNUSED,
"RGB = REPLACE (PREVIOUS)"
"A = MODULATE (PRIMARY, TEXTURE)", /* tex combine */
0xffffff10); /* expected */
test_tex_combine (state, 8, 0, /* position */
0x11111111, /* texture 0 color */
0x22222222, /* texture 1 color */
TEX_CONSTANT_UNUSED,
"RGBA = ADD (PREVIOUS, 1-TEXTURE)", /* tex combine */
0xeeeeeeee); /* expected */
/* this is again assuming a primary color of 0x80808080 */
test_tex_combine (state, 9, 0, /* position */
0x10101010, /* texture 0 color */
0x20202020, /* texture 1 color */
TEX_CONSTANT_UNUSED,
"RGBA = INTERPOLATE (PREVIOUS, TEXTURE, PRIMARY)",
0x18181818); /* expected */
#if 0 /* using TEXTURE_N appears to be broken in cogl-blend-string.c */
test_tex_combine (state, 0, 1, /* position */
0xDEADBEEF, /* texture 0 color (not used) */
0x11223344, /* texture 1 color */
TEX_CONSTANT_UNUSED,
"RGBA = ADD (TEXTURE_1, TEXTURE)", /* tex combine */
0x22446688); /* expected */
#endif
test_tex_combine (state, 1, 1, /* position */
0x21314151, /* texture 0 color */
0x99999999, /* texture 1 color */
TEX_CONSTANT_UNUSED,
"RGBA = ADD_SIGNED (PREVIOUS, TEXTURE)", /* tex combine */
0x3a4a5a6a); /* expected */
test_tex_combine (state, 2, 1, /* position */
0xfedcba98, /* texture 0 color */
0x11111111, /* texture 1 color */
TEX_CONSTANT_UNUSED,
"RGBA = SUBTRACT (PREVIOUS, TEXTURE)", /* tex combine */
0xedcba987); /* expected */
test_tex_combine (state, 3, 1, /* position */
0x8899aabb, /* texture 0 color */
0xbbaa9988, /* texture 1 color */
TEX_CONSTANT_UNUSED,
"RGB = DOT3_RGBA (PREVIOUS, TEXTURE)"
"A = REPLACE (PREVIOUS)",
0x2a2a2abb); /* expected */
/* Comment this out if you want visual feedback for what this test paints */
clutter_main_quit ();
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
void
test_cogl_blend_strings (TestUtilsGTestFixture *fixture,
void *data)
{
TestState state;
ClutterActor *stage;
ClutterActor *group;
unsigned int idle_source;
stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
clutter_actor_get_geometry (stage, &state.stage_geom);
group = clutter_group_new ();
clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
/* We force continuous redrawing incase someone comments out the
* clutter_main_quit and wants visual feedback for the test since we
* wont be doing anything else that will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, stage);
g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
clutter_actor_show_all (stage);
clutter_main ();
g_source_remove (idle_source);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,170 @@
#include "config.h"
#include <cogl/cogl.h>
#include <glib.h>
#include <locale.h>
#include <stdlib.h>
#include "test-utils.h"
#if 0
void
skip_init (TestUtilsGTestFixture *fixture,
const void *data)
{
/* void */
}
static void
skip_test (TestUtilsGTestFixture *fixture,
const void *data)
{
/* void */
}
void
skip_fini (TestUtilsGTestFixture *fixture,
const void *data)
{
/* void */
}
#endif
static void
run_todo_test (TestUtilsGTestFixture *fixture,
void *data)
{
#ifdef G_OS_UNIX
TestUtilsSharedState *state = data;
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
{
state->todo_func (fixture, data);
exit (0);
}
g_test_trap_assert_failed ();
#endif
}
void
verify_failure (TestUtilsGTestFixture *fixture,
void *data)
{
g_assert (FALSE);
}
static TestUtilsSharedState *shared_state = NULL;
/* This is a bit of sugar for adding new conformance tests:
*
* - It adds an extern function definition just to save maintaining a header
* that lists test entry points.
* - It sets up callbacks for a fixture, which lets us share initialization
* code between tests. (see test-utils.c)
* - It passes in a shared data pointer that is initialised once in main(),
* that gets passed to the fixture setup and test functions. (See the
* definition in test-utils.h)
*/
#define ADD_TEST(NAMESPACE, FUNC) G_STMT_START { \
extern void FUNC (TestUtilsGTestFixture *, void *); \
g_test_add ("/conform" NAMESPACE "/" #FUNC, \
TestUtilsGTestFixture, \
shared_state, /* data argument for test */ \
test_utils_init, \
(void *)(FUNC), \
test_utils_fini); } G_STMT_END
/* this is a macro that conditionally executes a test if CONDITION
* evaluates to TRUE; otherwise, it will put the test under the
* "/skip" namespace and execute a dummy function that will always
* pass.
*/
#define ADD_CONDITIONAL_TEST(CONDITION, NAMESPACE, FUNC) G_STMT_START { \
if (!(CONDITION)) { \
g_test_add ("/skipped" NAMESPACE "/" #FUNC, \
TestUtilsGTestFixture, \
shared_state, /* data argument for test */ \
skip_init, \
skip_test, \
skip_fini); \
} else { ADD_TEST (NAMESPACE, FUNC); } } G_STMT_END
#define ADD_TODO_TEST(NAMESPACE, FUNC) G_STMT_START { \
extern void FUNC (TestUtilsGTestFixture *, void *); \
shared_state->todo_func = FUNC; \
g_test_add ("/todo" NAMESPACE "/" #FUNC, \
TestUtilsGTestFixture, \
shared_state, \
test_utils_init, \
(void *)(run_todo_test), \
test_utils_fini); } G_STMT_END
#define UNPORTED_TEST(NAMESPACE, FUNC)
gchar *
clutter_test_get_data_file (const gchar *filename)
{
return g_build_filename (TESTS_DATADIR, filename, NULL);
}
int
main (int argc, char **argv)
{
g_test_init (&argc, &argv, NULL);
g_test_bug_base ("http://bugzilla.gnome.org/show_bug.cgi?id=%s");
/* Initialise the state you need to share with everything.
*/
shared_state = g_new0 (TestUtilsSharedState, 1);
shared_state->argc_addr = &argc;
shared_state->argv_addr = &argv;
/* This file is run through a sed script during the make step so the
* lines containing the tests need to be formatted on a single line
* each. To comment out a test use the SKIP or TODO macros. Using
* #if 0 would break the script. */
/* sanity check for the test suite itself */
ADD_TODO_TEST ("/suite", verify_failure);
UNPORTED_TEST ("/cogl", test_cogl_object);
UNPORTED_TEST ("/cogl", test_cogl_fixed);
UNPORTED_TEST ("/cogl", test_cogl_backface_culling);
UNPORTED_TEST ("/cogl", test_cogl_materials);
UNPORTED_TEST ("/cogl", test_cogl_pipeline_user_matrix);
UNPORTED_TEST ("/cogl", test_cogl_blend_strings);
UNPORTED_TEST ("/cogl", test_cogl_premult);
UNPORTED_TEST ("/cogl", test_cogl_readpixels);
UNPORTED_TEST ("/cogl", test_cogl_path);
ADD_TEST ("/cogl", test_cogl_depth_test);
UNPORTED_TEST ("/cogl/texture", test_cogl_npot_texture);
UNPORTED_TEST ("/cogl/texture", test_cogl_multitexture);
UNPORTED_TEST ("/cogl/texture", test_cogl_texture_mipmaps);
UNPORTED_TEST ("/cogl/texture", test_cogl_sub_texture);
UNPORTED_TEST ("/cogl/texture", test_cogl_pixel_array);
UNPORTED_TEST ("/cogl/texture", test_cogl_texture_rectangle);
UNPORTED_TEST ("/cogl/texture", test_cogl_texture_3d);
UNPORTED_TEST ("/cogl/texture", test_cogl_wrap_modes);
UNPORTED_TEST ("/cogl/texture", test_cogl_texture_pixmap_x11);
UNPORTED_TEST ("/cogl/texture", test_cogl_texture_get_set_data);
UNPORTED_TEST ("/cogl/texture", test_cogl_atlas_migration);
UNPORTED_TEST ("/cogl/vertex-buffer", test_cogl_vertex_buffer_contiguous);
UNPORTED_TEST ("/cogl/vertex-buffer", test_cogl_vertex_buffer_interleved);
UNPORTED_TEST ("/cogl/vertex-buffer", test_cogl_vertex_buffer_mutability);
UNPORTED_TEST ("/cogl/vertex-array", test_cogl_primitive);
UNPORTED_TEST ("/cogl/shaders", test_cogl_just_vertex_shader);
/* left to the end because they aren't currently very orthogonal and tend to
* break subsequent tests! */
UNPORTED_TEST ("/cogl", test_cogl_viewport);
UNPORTED_TEST ("/cogl", test_cogl_offscreen);
return g_test_run ();
}

View File

@ -0,0 +1,291 @@
#include <cogl/cogl.h>
#include <string.h>
#include "test-utils.h"
#define QUAD_WIDTH 20
#define RED 0
#define GREEN 1
#define BLUE 2
#define ALPHA 3
#define MASK_RED(COLOR) ((COLOR & 0xff000000) >> 24)
#define MASK_GREEN(COLOR) ((COLOR & 0xff0000) >> 16)
#define MASK_BLUE(COLOR) ((COLOR & 0xff00) >> 8)
#define MASK_ALPHA(COLOR) (COLOR & 0xff)
typedef struct _TestState
{
int width;
int height;
} TestState;
typedef struct
{
guint32 color;
float depth;
gboolean test_enable;
CoglDepthTestFunction test_function;
gboolean write_enable;
float range_near;
float range_far;
} TestDepthState;
static void
check_pixel (GLubyte *pixel, guint32 color)
{
guint8 r = MASK_RED (color);
guint8 g = MASK_GREEN (color);
guint8 b = MASK_BLUE (color);
guint8 a = MASK_ALPHA (color);
if (g_test_verbose ())
g_print (" expected = %x, %x, %x, %x\n",
r, g, b, a);
/* FIXME - allow for hardware in-precision */
g_assert_cmpint (pixel[RED], ==, r);
g_assert_cmpint (pixel[GREEN], ==, g);
g_assert_cmpint (pixel[BLUE], ==, b);
/* FIXME
* We ignore the alpha, since we don't know if our render target is
* RGB or RGBA */
/* g_assert (pixel[ALPHA] == a); */
}
static gboolean
draw_rectangle (TestState *state,
int x,
int y,
TestDepthState *rect_state)
{
guint8 Cr = MASK_RED (rect_state->color);
guint8 Cg = MASK_GREEN (rect_state->color);
guint8 Cb = MASK_BLUE (rect_state->color);
guint8 Ca = MASK_ALPHA (rect_state->color);
CoglHandle pipeline;
CoglDepthState depth_state;
cogl_depth_state_init (&depth_state);
cogl_depth_state_set_test_enabled (&depth_state, rect_state->test_enable);
cogl_depth_state_set_test_function (&depth_state, rect_state->test_function);
cogl_depth_state_set_write_enabled (&depth_state, rect_state->write_enable);
cogl_depth_state_set_range (&depth_state,
rect_state->range_near,
rect_state->range_far);
pipeline = cogl_pipeline_new ();
if (!cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL))
{
cogl_object_unref (pipeline);
return FALSE;
}
cogl_pipeline_set_color4ub (pipeline, Cr, Cg, Cb, Ca);
cogl_set_source (pipeline);
cogl_push_matrix ();
cogl_translate (0, 0, rect_state->depth);
cogl_rectangle (x * QUAD_WIDTH,
y * QUAD_WIDTH,
x * QUAD_WIDTH + QUAD_WIDTH,
y * QUAD_WIDTH + QUAD_WIDTH);
cogl_pop_matrix ();
cogl_object_unref (pipeline);
return TRUE;
}
static void
test_depth (TestState *state,
int x,
int y,
TestDepthState *rect0_state,
TestDepthState *rect1_state,
TestDepthState *rect2_state,
guint32 expected_result)
{
GLubyte pixel[4];
int y_off;
int x_off;
gboolean missing_feature = FALSE;
if (rect0_state)
missing_feature |= !draw_rectangle (state, x, y, rect0_state);
if (rect1_state)
missing_feature |= !draw_rectangle (state, x, y, rect1_state);
if (rect2_state)
missing_feature |= !draw_rectangle (state, x, y, rect2_state);
/* We don't consider it an error that we can't test something
* the driver doesn't support. */
if (missing_feature)
return;
/* See what we got... */
y_off = y * QUAD_WIDTH + (QUAD_WIDTH / 2);
x_off = x * QUAD_WIDTH + (QUAD_WIDTH / 2);
cogl_read_pixels (x_off, y_off, 1, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixel);
check_pixel (pixel, expected_result);
}
static void
paint (TestState *state)
{
CoglMatrix identity;
cogl_ortho (0, state->width, /* left, right */
state->height, 0, /* bottom, top */
-1, 100 /* z near, far */);
cogl_push_matrix ();
cogl_matrix_init_identity (&identity);
cogl_set_modelview_matrix (&identity);
/* Sanity check a few of the different depth test functions
* and that depth writing can be disabled... */
{
/* Closest */
TestDepthState rect0_state = {
0xff0000ff, /* rgba color */
-10, /* depth */
FALSE, /* depth test enable */
COGL_DEPTH_TEST_FUNCTION_ALWAYS,
TRUE, /* depth write enable */
0, 1 /* depth range */
};
/* Furthest */
TestDepthState rect1_state = {
0x00ff00ff, /* rgba color */
-70, /* depth */
TRUE, /* depth test enable */
COGL_DEPTH_TEST_FUNCTION_ALWAYS,
TRUE, /* depth write enable */
0, 1 /* depth range */
};
/* In the middle */
TestDepthState rect2_state = {
0x0000ffff, /* rgba color */
-20, /* depth */
TRUE, /* depth test enable */
COGL_DEPTH_TEST_FUNCTION_NEVER,
TRUE, /* depth write enable */
0, 1 /* depth range */
};
test_depth (state, 0, 0, /* position */
&rect0_state, &rect1_state, &rect2_state,
0x00ff00ff); /* expected */
rect2_state.test_function = COGL_DEPTH_TEST_FUNCTION_ALWAYS;
test_depth (state, 1, 0, /* position */
&rect0_state, &rect1_state, &rect2_state,
0x0000ffff); /* expected */
rect2_state.test_function = COGL_DEPTH_TEST_FUNCTION_LESS;
test_depth (state, 2, 0, /* position */
&rect0_state, &rect1_state, &rect2_state,
0x0000ffff); /* expected */
rect2_state.test_function = COGL_DEPTH_TEST_FUNCTION_GREATER;
test_depth (state, 3, 0, /* position */
&rect0_state, &rect1_state, &rect2_state,
0x00ff00ff); /* expected */
rect0_state.test_enable = TRUE;
rect1_state.write_enable = FALSE;
test_depth (state, 4, 0, /* position */
&rect0_state, &rect1_state, &rect2_state,
0x0000ffff); /* expected */
}
/* Check that the depth buffer values can be mapped into different
* ranges... */
{
/* Closest by depth, furthest by depth range */
TestDepthState rect0_state = {
0xff0000ff, /* rgba color */
-10, /* depth */
TRUE, /* depth test enable */
COGL_DEPTH_TEST_FUNCTION_ALWAYS,
TRUE, /* depth write enable */
0.5, 1 /* depth range */
};
/* Furthest by depth, nearest by depth range */
TestDepthState rect1_state = {
0x00ff00ff, /* rgba color */
-70, /* depth */
TRUE, /* depth test enable */
COGL_DEPTH_TEST_FUNCTION_GREATER,
TRUE, /* depth write enable */
0, 0.5 /* depth range */
};
test_depth (state, 0, 1, /* position */
&rect0_state, &rect1_state, NULL,
0xff0000ff); /* expected */
}
/* Test that the legacy cogl_set_depth_test_enabled() API still
* works... */
{
/* Nearest */
TestDepthState rect0_state = {
0xff0000ff, /* rgba color */
-10, /* depth */
FALSE, /* depth test enable */
COGL_DEPTH_TEST_FUNCTION_LESS,
TRUE, /* depth write enable */
0, 1 /* depth range */
};
/* Furthest */
TestDepthState rect1_state = {
0x00ff00ff, /* rgba color */
-70, /* depth */
FALSE, /* depth test enable */
COGL_DEPTH_TEST_FUNCTION_LESS,
TRUE, /* depth write enable */
0, 1 /* depth range */
};
cogl_set_depth_test_enabled (TRUE);
test_depth (state, 0, 2, /* position */
&rect0_state, &rect1_state, NULL,
0xff0000ff); /* expected */
cogl_set_depth_test_enabled (FALSE);
test_depth (state, 1, 2, /* position */
&rect0_state, &rect1_state, NULL,
0x00ff00ff); /* expected */
}
cogl_pop_matrix ();
}
void
test_cogl_depth_test (TestUtilsGTestFixture *fixture,
void *data)
{
TestUtilsSharedState *shared_state = data;
TestState state;
state.width = cogl_framebuffer_get_width (shared_state->fb);
state.height = cogl_framebuffer_get_height (shared_state->fb);
paint (&state);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,18 @@
#include <stdio.h>
#include <clutter/clutter.h>
#include "test-conform-common.h"
void
test_cogl_fixed (TestUtilsGTestFixture *fixture,
void *data)
{
g_assert_cmpint (COGL_FIXED_1, ==, COGL_FIXED_FROM_FLOAT (1.0));
g_assert_cmpint (COGL_FIXED_1, ==, COGL_FIXED_FROM_INT (1));
g_assert_cmpint (COGL_FIXED_0_5, ==, COGL_FIXED_FROM_FLOAT (0.5));
g_assert_cmpfloat (COGL_FIXED_TO_FLOAT (COGL_FIXED_1), ==, 1.0);
g_assert_cmpfloat (COGL_FIXED_TO_FLOAT (COGL_FIXED_0_5), ==, 0.5);
}

View File

@ -0,0 +1,12 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
void
test_cogl_simple_rig (void)
{
ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
}

View File

@ -0,0 +1,137 @@
#include <clutter/clutter.h>
#include <string.h>
#include "test-conform-common.h"
static const ClutterColor stage_color = { 0x00, 0x00, 0xff, 0xff };
static void
draw_frame (void)
{
CoglHandle material = cogl_material_new ();
CoglColor color;
GError *error = NULL;
CoglHandle shader, program;
/* Set the primary vertex color as red */
cogl_color_set_from_4ub (&color, 0xff, 0x00, 0x00, 0xff);
cogl_material_set_color (material, &color);
/* Override the vertex color in the texture environment with a
constant green color */
cogl_color_set_from_4ub (&color, 0x00, 0xff, 0x00, 0xff);
cogl_material_set_layer_combine_constant (material, 0, &color);
if (!cogl_material_set_layer_combine (material, 0,
"RGBA=REPLACE(CONSTANT)",
&error))
{
g_warning ("Error setting blend constant: %s", error->message);
g_assert_not_reached ();
}
/* Set up a dummy vertex shader that does nothing but the usual
fixed function transform */
shader = cogl_create_shader (COGL_SHADER_TYPE_VERTEX);
cogl_shader_source (shader,
"void\n"
"main ()\n"
"{\n"
" cogl_position_out = "
"cogl_modelview_projection_matrix * "
"cogl_position_in;\n"
" cogl_color_out = cogl_color_in;\n"
"}\n");
cogl_shader_compile (shader);
if (!cogl_shader_is_compiled (shader))
{
char *log = cogl_shader_get_info_log (shader);
g_warning ("Shader compilation failed:\n%s", log);
g_free (log);
g_assert_not_reached ();
}
program = cogl_create_program ();
cogl_program_attach_shader (program, shader);
cogl_program_link (program);
cogl_handle_unref (shader);
/* Draw something using the material */
cogl_set_source (material);
cogl_rectangle (0, 0, 50, 50);
/* Draw it again using the program. It should look exactly the same */
cogl_program_use (program);
cogl_rectangle (50, 0, 100, 50);
cogl_program_use (COGL_INVALID_HANDLE);
cogl_handle_unref (material);
cogl_handle_unref (program);
}
static void
validate_pixel (int x, int y)
{
guint8 pixels[4];
cogl_read_pixels (x, y, 1, 1, COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE, pixels);
/* The final color should be green. If it's blue then the layer
state is being ignored. If it's green then the stage is showing
through */
g_assert_cmpint (pixels[0], ==, 0x00);
g_assert_cmpint (pixels[1], ==, 0xff);
g_assert_cmpint (pixels[2], ==, 0x00);
}
static void
validate_result (void)
{
/* Non-shader version */
validate_pixel (25, 25);
/* Shader version */
validate_pixel (75, 25);
}
static void
on_paint (void)
{
draw_frame ();
validate_result ();
/* Comment this out to see what the test paints */
clutter_main_quit ();
}
void
test_cogl_just_vertex_shader (TestUtilsGTestFixture *fixture,
void *data)
{
ClutterActor *stage;
unsigned int paint_handler;
stage = clutter_stage_get_default ();
/* If shaders aren't supported then we can't run the test */
if (cogl_features_available (COGL_FEATURE_SHADERS_GLSL))
{
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
paint_handler = g_signal_connect_after (stage, "paint",
G_CALLBACK (on_paint), NULL);
clutter_actor_show (stage);
clutter_main ();
g_signal_handler_disconnect (stage, paint_handler);
if (g_test_verbose ())
g_print ("OK\n");
}
else if (g_test_verbose ())
g_print ("Skipping\n");
}

View File

@ -0,0 +1,25 @@
#!/bin/sh
UNIT_TEST_PATH=$1
shift
test -z ${UNIT_TEST_PATH} && {
echo "Usage: $0 /path/to/unit_test"
exit 1
}
UNIT_TEST=`basename ${UNIT_TEST_PATH}`
echo "Running: ./test-conformance -p ${UNIT_TEST_PATH} $@"
echo ""
@abs_builddir@/test-conformance -p ${UNIT_TEST_PATH} "$@"
echo ""
echo "NOTE: For debugging purposes, you can run this single test as follows:"
echo "$ libtool --mode=execute \\"
echo " gdb --eval-command=\"b ${UNIT_TEST}\" \\"
echo " --args ./test-conformance -p ${UNIT_TEST_PATH}"
echo "or:"
echo "$ env G_SLICE=always-malloc \\"
echo " libtool --mode=execute \\"
echo " valgrind ./test-conformance -p ${UNIT_TEST_PATH}"

View File

@ -0,0 +1,285 @@
#include "config.h"
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <string.h>
#include "test-conform-common.h"
static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
#define QUAD_WIDTH 20
#define RED 0
#define GREEN 1
#define BLUE 2
#define ALPHA 3
#define MASK_RED(COLOR) ((COLOR & 0xff000000) >> 24)
#define MASK_GREEN(COLOR) ((COLOR & 0xff0000) >> 16)
#define MASK_BLUE(COLOR) ((COLOR & 0xff00) >> 8)
#define MASK_ALPHA(COLOR) (COLOR & 0xff)
typedef struct _TestState
{
ClutterGeometry stage_geom;
} TestState;
static void
check_pixel (TestState *state, int x, int y, guint32 color)
{
GLint y_off;
GLint x_off;
GLubyte pixel[4];
guint8 r = MASK_RED (color);
guint8 g = MASK_GREEN (color);
guint8 b = MASK_BLUE (color);
guint8 a = MASK_ALPHA (color);
/* See what we got... */
/* NB: glReadPixels is done in GL screen space so y = 0 is at the bottom */
y_off = y * QUAD_WIDTH + (QUAD_WIDTH / 2);
x_off = x * QUAD_WIDTH + (QUAD_WIDTH / 2);
cogl_read_pixels (x_off, y_off, 1, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixel);
if (g_test_verbose ())
g_print (" result = %02x, %02x, %02x, %02x\n",
pixel[RED], pixel[GREEN], pixel[BLUE], pixel[ALPHA]);
if (g_test_verbose ())
g_print (" expected = %x, %x, %x, %x\n",
r, g, b, a);
/* FIXME - allow for hardware in-precision */
g_assert (pixel[RED] == r);
g_assert (pixel[GREEN] == g);
g_assert (pixel[BLUE] == b);
/* FIXME
* We ignore the alpha, since we don't know if our render target is
* RGB or RGBA */
/* g_assert (pixel[ALPHA] == a); */
}
static void
test_material_with_primitives (TestState *state,
int x, int y,
guint32 color)
{
CoglTextureVertex verts[4] = {
{ .x = 0, .y = 0, .z = 0 },
{ .x = 0, .y = QUAD_WIDTH, .z = 0 },
{ .x = QUAD_WIDTH, .y = QUAD_WIDTH, .z = 0 },
{ .x = QUAD_WIDTH, .y = 0, .z = 0 },
};
CoglHandle vbo;
cogl_push_matrix ();
cogl_translate (x * QUAD_WIDTH, y * QUAD_WIDTH, 0);
cogl_rectangle (0, 0, QUAD_WIDTH, QUAD_WIDTH);
cogl_translate (0, QUAD_WIDTH, 0);
cogl_polygon (verts, 4, FALSE);
cogl_translate (0, QUAD_WIDTH, 0);
vbo = cogl_vertex_buffer_new (4);
cogl_vertex_buffer_add (vbo,
"gl_Vertex",
2, /* n components */
COGL_ATTRIBUTE_TYPE_FLOAT,
FALSE, /* normalized */
sizeof (CoglTextureVertex), /* stride */
verts);
cogl_vertex_buffer_draw (vbo,
COGL_VERTICES_MODE_TRIANGLE_FAN,
0, /* first */
4); /* count */
cogl_handle_unref (vbo);
cogl_pop_matrix ();
check_pixel (state, x, y, color);
check_pixel (state, x, y+1, color);
check_pixel (state, x, y+2, color);
}
static void
test_invalid_texture_layers (TestState *state, int x, int y)
{
CoglHandle material = cogl_material_new ();
/* explicitly create a layer with an invalid handle. This may be desireable
* if the user also sets a texture combine string that e.g. refers to a
* constant color. */
cogl_material_set_layer (material, 0, COGL_INVALID_HANDLE);
cogl_set_source (material);
cogl_handle_unref (material);
/* We expect a white fallback material to be used */
test_material_with_primitives (state, x, y, 0xffffffff);
}
static void
test_using_all_layers (TestState *state, int x, int y)
{
CoglHandle material = cogl_material_new ();
guint8 white_pixel[] = { 0xff, 0xff, 0xff, 0xff };
guint8 red_pixel[] = { 0xff, 0x00, 0x00, 0xff };
CoglHandle white_texture;
CoglHandle red_texture;
GLint n_layers;
int i;
/* Create a material that uses the maximum number of layers. All but
the last layer will use a solid white texture. The last layer
will use a red texture. The layers will all be modulated together
so the final fragment should be red. */
white_texture = cogl_texture_new_from_data (1, 1, COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
COGL_PIXEL_FORMAT_ANY,
4, white_pixel);
red_texture = cogl_texture_new_from_data (1, 1, COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
COGL_PIXEL_FORMAT_ANY,
4, red_pixel);
/* FIXME: Cogl doesn't provide a way to query the maximum number of
texture layers so for now we'll just ask GL directly. */
#ifdef HAVE_COGL_GLES2
{
GLint n_image_units, n_attribs;
/* GLES 2 doesn't have GL_MAX_TEXTURE_UNITS and it uses
GL_MAX_TEXTURE_IMAGE_UNITS instead */
glGetIntegerv (GL_MAX_TEXTURE_IMAGE_UNITS, &n_image_units);
/* Cogl needs a vertex attrib for each layer to upload the texture
coordinates */
glGetIntegerv (GL_MAX_VERTEX_ATTRIBS, &n_attribs);
/* We can't use two of the attribs because they are used by the
position and color */
n_attribs -= 2;
n_layers = MIN (n_attribs, n_image_units);
}
#else
glGetIntegerv (GL_MAX_TEXTURE_UNITS, &n_layers);
#endif
/* FIXME: is this still true? */
/* Cogl currently can't cope with more than 32 layers so we'll also
limit the maximum to that. */
if (n_layers > 32)
n_layers = 32;
for (i = 0; i < n_layers; i++)
{
cogl_material_set_layer_filters (material, i,
COGL_MATERIAL_FILTER_NEAREST,
COGL_MATERIAL_FILTER_NEAREST);
cogl_material_set_layer (material, i,
i == n_layers - 1 ? red_texture : white_texture);
}
cogl_set_source (material);
cogl_handle_unref (material);
cogl_handle_unref (white_texture);
cogl_handle_unref (red_texture);
/* We expect the final fragment to be red */
test_material_with_primitives (state, x, y, 0xff0000ff);
}
static void
test_invalid_texture_layers_with_constant_colors (TestState *state,
int x, int y)
{
CoglHandle material = cogl_material_new ();
CoglColor constant_color;
/* explicitly create a layer with an invalid handle */
cogl_material_set_layer (material, 0, COGL_INVALID_HANDLE);
/* ignore the fallback texture on the layer and use a constant color
instead */
cogl_color_init_from_4ub (&constant_color, 0, 0, 255, 255);
cogl_material_set_layer_combine (material, 0,
"RGBA=REPLACE(CONSTANT)",
NULL);
cogl_material_set_layer_combine_constant (material, 0, &constant_color);
cogl_set_source (material);
cogl_handle_unref (material);
/* We expect the final fragments to be green */
test_material_with_primitives (state, x, y, 0x0000ffff);
}
static void
on_paint (ClutterActor *actor, TestState *state)
{
test_invalid_texture_layers (state,
0, 0 /* position */
);
test_invalid_texture_layers_with_constant_colors (state,
1, 0 /* position */
);
test_using_all_layers (state,
2, 0 /* position */
);
/* Comment this out if you want visual feedback for what this test paints */
#if 1
clutter_main_quit ();
#endif
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
void
test_cogl_materials (TestUtilsGTestFixture *fixture,
void *data)
{
TestState state;
ClutterActor *stage;
ClutterActor *group;
unsigned int idle_source;
stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
clutter_actor_get_geometry (stage, &state.stage_geom);
group = clutter_group_new ();
clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
/* We force continuous redrawing of the stage, since we need to skip
* the first few frames, and we wont be doing anything else that
* will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, stage);
g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
clutter_actor_show_all (stage);
clutter_main ();
g_source_remove (idle_source);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,206 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <string.h>
#include "test-conform-common.h"
static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
#define QUAD_WIDTH 20
#define RED 0
#define GREEN 1
#define BLUE 2
#define ALPHA 3
typedef struct _TestState
{
unsigned int padding;
} TestState;
static void
assert_region_color (int x,
int y,
int width,
int height,
guint8 red,
guint8 green,
guint8 blue,
guint8 alpha)
{
guint8 *data = g_malloc0 (width * height * 4);
cogl_read_pixels (x, y, width, height,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
data);
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
{
guint8 *pixel = &data[y * width * 4 + x * 4];
#if 1
g_assert (pixel[RED] == red &&
pixel[GREEN] == green &&
pixel[BLUE] == blue);
#endif
}
g_free (data);
}
/* Creates a texture divided into 4 quads with colors arranged as follows:
* (The same value are used in all channels for each texel)
*
* |-----------|
* |0x11 |0x00 |
* |+ref | |
* |-----------|
* |0x00 |0x33 |
* | |+ref |
* |-----------|
*
*
*/
static CoglHandle
make_texture (guchar ref)
{
int x;
int y;
guchar *tex_data, *p;
CoglHandle tex;
guchar val;
tex_data = g_malloc (QUAD_WIDTH * QUAD_WIDTH * 16);
for (y = 0; y < QUAD_WIDTH * 2; y++)
for (x = 0; x < QUAD_WIDTH * 2; x++)
{
p = tex_data + (QUAD_WIDTH * 8 * y) + x * 4;
if (x < QUAD_WIDTH && y < QUAD_WIDTH)
val = 0x11 + ref;
else if (x >= QUAD_WIDTH && y >= QUAD_WIDTH)
val = 0x33 + ref;
else
val = 0x00;
p[0] = p[1] = p[2] = p[3] = val;
}
/* Note: we don't use COGL_PIXEL_FORMAT_ANY for the internal format here
* since we don't want to allow Cogl to premultiply our data. */
tex = cogl_texture_new_from_data (QUAD_WIDTH * 2,
QUAD_WIDTH * 2,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_RGBA_8888,
COGL_PIXEL_FORMAT_RGBA_8888,
QUAD_WIDTH * 8,
tex_data);
g_free (tex_data);
return tex;
}
static void
on_paint (ClutterActor *actor, TestState *state)
{
CoglHandle tex0, tex1;
CoglHandle material;
gboolean status;
GError *error = NULL;
float tex_coords[] = {
0, 0, 0.5, 0.5, /* tex0 */
0.5, 0.5, 1, 1 /* tex1 */
};
tex0 = make_texture (0x00);
tex1 = make_texture (0x11);
material = cogl_material_new ();
/* An arbitrary color which should be replaced by the first texture layer */
cogl_material_set_color4ub (material, 0x80, 0x80, 0x80, 0x80);
cogl_material_set_blend (material, "RGBA = ADD (SRC_COLOR, 0)", NULL);
cogl_material_set_layer (material, 0, tex0);
cogl_material_set_layer_combine (material, 0,
"RGBA = REPLACE (TEXTURE)", NULL);
/* We'll use nearest filtering mode on the textures, otherwise the
edge of the quad can pull in texels from the neighbouring
quarters of the texture due to imprecision */
cogl_material_set_layer_filters (material, 0,
COGL_MATERIAL_FILTER_NEAREST,
COGL_MATERIAL_FILTER_NEAREST);
cogl_material_set_layer (material, 1, tex1);
cogl_material_set_layer_filters (material, 1,
COGL_MATERIAL_FILTER_NEAREST,
COGL_MATERIAL_FILTER_NEAREST);
status = cogl_material_set_layer_combine (material, 1,
"RGBA = ADD (PREVIOUS, TEXTURE)",
&error);
if (!status)
{
/* It's not strictly a test failure; you need a more capable GPU or
* driver to test this texture combine string. */
g_debug ("Failed to setup texture combine string "
"RGBA = ADD (PREVIOUS, TEXTURE): %s",
error->message);
}
cogl_set_source (material);
cogl_rectangle_with_multitexture_coords (0, 0, QUAD_WIDTH, QUAD_WIDTH,
tex_coords, 8);
cogl_handle_unref (material);
cogl_handle_unref (tex0);
cogl_handle_unref (tex1);
/* See what we got... */
assert_region_color (0, 0, QUAD_WIDTH, QUAD_WIDTH,
0x55, 0x55, 0x55, 0x55);
/* Comment this out if you want visual feedback for what this test paints */
#if 1
clutter_main_quit ();
#endif
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
void
test_cogl_multitexture (TestUtilsGTestFixture *fixture,
void *data)
{
TestState state;
ClutterActor *stage;
ClutterActor *group;
unsigned int idle_source;
stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
group = clutter_group_new ();
clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
/* We force continuous redrawing incase someone comments out the
* clutter_main_quit and wants visual feedback for the test since we
* wont be doing anything else that will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, stage);
g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
clutter_actor_show_all (stage);
clutter_main ();
g_source_remove (idle_source);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,236 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <string.h>
#include "test-conform-common.h"
static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
/* Non-power-of-two sized texture that should cause slicing */
#define TEXTURE_SIZE 384
/* Number of times to split the texture up on each axis */
#define PARTS 2
/* The texture is split into four parts, each with a different colour */
#define PART_SIZE (TEXTURE_SIZE / PARTS)
/* Amount of pixels to skip off the top, bottom, left and right of the
texture when reading back the stage */
#define TEST_INSET 4
/* Size to actually render the texture at */
#define TEXTURE_RENDER_SIZE TEXTURE_SIZE
/* The size of a part once rendered */
#define PART_RENDER_SIZE (TEXTURE_RENDER_SIZE / PARTS)
static const ClutterColor corner_colors[PARTS * PARTS] =
{
/* Top left - red */ { 255, 0, 0, 255 },
/* Top right - green */ { 0, 255, 0, 255 },
/* Bottom left - blue */ { 0, 0, 255, 255 },
/* Bottom right - yellow */ { 255, 255, 0, 255 }
};
typedef struct _TestState
{
unsigned int frame;
CoglHandle texture;
} TestState;
static gboolean
validate_part (int xnum, int ynum, const ClutterColor *color)
{
guchar *pixels, *p;
ClutterActor *stage = clutter_stage_get_default ();
gboolean ret = TRUE;
/* Read the appropriate part but skip out a few pixels around the
edges */
pixels = clutter_stage_read_pixels (CLUTTER_STAGE (stage),
xnum * PART_RENDER_SIZE + TEST_INSET,
ynum * PART_RENDER_SIZE + TEST_INSET,
PART_RENDER_SIZE - TEST_INSET * 2,
PART_RENDER_SIZE - TEST_INSET * 2);
/* Make sure every pixels is the appropriate color */
for (p = pixels;
p < pixels + ((PART_RENDER_SIZE - TEST_INSET * 2)
* (PART_RENDER_SIZE - TEST_INSET * 2));
p += 4)
{
if (p[0] != color->red)
ret = FALSE;
if (p[1] != color->green)
ret = FALSE;
if (p[2] != color->blue)
ret = FALSE;
}
g_free (pixels);
return ret;
}
static void
validate_result (TestState *state)
{
/* Validate that all four corners of the texture are drawn in the
right color */
g_assert (validate_part (0, 0, corner_colors + 0));
g_assert (validate_part (1, 0, corner_colors + 1));
g_assert (validate_part (0, 1, corner_colors + 2));
g_assert (validate_part (1, 1, corner_colors + 3));
/* Comment this out if you want visual feedback of what this test
* paints.
*/
clutter_main_quit ();
}
static void
on_paint (ClutterActor *actor, TestState *state)
{
int frame_num;
int y, x;
/* Just render the texture in the top left corner */
cogl_set_source_texture (state->texture);
/* Render the texture using four separate rectangles */
for (y = 0; y < 2; y++)
for (x = 0; x < 2; x++)
cogl_rectangle_with_texture_coords (x * TEXTURE_RENDER_SIZE / 2,
y * TEXTURE_RENDER_SIZE / 2,
(x + 1) * TEXTURE_RENDER_SIZE / 2,
(y + 1) * TEXTURE_RENDER_SIZE / 2,
x / 2.0f,
y / 2.0f,
(x + 1) / 2.0f,
(y + 1) / 2.0f);
/* XXX: validate_result calls clutter_stage_read_pixels which will result in
* another paint run so to avoid infinite recursion we only aim to validate
* the first frame. */
frame_num = state->frame++;
if (frame_num == 1)
validate_result (state);
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
static CoglHandle
make_texture (void)
{
guchar *tex_data, *p;
CoglHandle tex;
int partx, party, width, height;
p = tex_data = g_malloc (TEXTURE_SIZE * TEXTURE_SIZE * 4);
/* Make a texture with a different color for each part */
for (party = 0; party < PARTS; party++)
{
height = (party < PARTS - 1
? PART_SIZE
: TEXTURE_SIZE - PART_SIZE * (PARTS - 1));
for (partx = 0; partx < PARTS; partx++)
{
const ClutterColor *color = corner_colors + party * PARTS + partx;
width = (partx < PARTS - 1
? PART_SIZE
: TEXTURE_SIZE - PART_SIZE * (PARTS - 1));
while (width-- > 0)
{
*(p++) = color->red;
*(p++) = color->green;
*(p++) = color->blue;
*(p++) = color->alpha;
}
}
while (--height > 0)
{
memcpy (p, p - TEXTURE_SIZE * 4, TEXTURE_SIZE * 4);
p += TEXTURE_SIZE * 4;
}
}
tex = cogl_texture_new_from_data (TEXTURE_SIZE,
TEXTURE_SIZE,
COGL_TEXTURE_NO_ATLAS,
COGL_PIXEL_FORMAT_RGBA_8888,
COGL_PIXEL_FORMAT_ANY,
TEXTURE_SIZE * 4,
tex_data);
g_free (tex_data);
if (g_test_verbose ())
{
if (cogl_texture_is_sliced (tex))
g_print ("Texture is sliced\n");
else
g_print ("Texture is not sliced\n");
}
/* The texture should be sliced unless NPOTs are supported */
g_assert (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT)
? !cogl_texture_is_sliced (tex)
: cogl_texture_is_sliced (tex));
return tex;
}
void
test_cogl_npot_texture (TestUtilsGTestFixture *fixture,
void *data)
{
TestState state;
ClutterActor *stage;
ClutterActor *group;
unsigned int idle_source;
if (g_test_verbose ())
{
if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT))
g_print ("NPOT textures are supported\n");
else
g_print ("NPOT textures are not supported\n");
}
state.frame = 0;
state.texture = make_texture ();
stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
group = clutter_group_new ();
clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
/* We force continuous redrawing of the stage, since we need to skip
* the first few frames, and we wont be doing anything else that
* will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, stage);
g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
clutter_actor_show_all (stage);
clutter_main ();
g_source_remove (idle_source);
cogl_handle_unref (state.texture);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,86 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <string.h>
#include "test-conform-common.h"
CoglUserDataKey private_key0;
CoglUserDataKey private_key1;
CoglUserDataKey private_key2;
static int user_data0;
static int user_data1;
static int user_data2;
static int destroy0_count = 0;
static int destroy1_count = 0;
static int destroy2_count = 0;
static void
destroy0_cb (void *user_data)
{
g_assert (user_data == &user_data0);
destroy0_count++;
}
static void
destroy1_cb (void *user_data)
{
g_assert (user_data == &user_data1);
destroy1_count++;
}
static void
destroy2_cb (void *user_data)
{
g_assert (user_data == &user_data2);
destroy2_count++;
}
void
test_cogl_object (TestUtilsGTestFixture *fixture,
void *data)
{
CoglPath *path;
/* Assuming that COGL_OBJECT_N_PRE_ALLOCATED_USER_DATA_ENTRIES == 2
* test associating 2 pointers to private data with an object */
cogl_path_new ();
path = cogl_get_path ();
cogl_object_set_user_data (COGL_OBJECT (path),
&private_key0,
&user_data0,
destroy0_cb);
cogl_object_set_user_data (COGL_OBJECT (path),
&private_key1,
&user_data1,
destroy1_cb);
cogl_object_set_user_data (COGL_OBJECT (path),
&private_key2,
&user_data2,
destroy2_cb);
cogl_object_set_user_data (COGL_OBJECT (path),
&private_key1,
NULL,
destroy1_cb);
cogl_object_set_user_data (COGL_OBJECT (path),
&private_key1,
&user_data1,
destroy1_cb);
cogl_object_unref (path);
g_assert_cmpint (destroy0_count, ==, 1);
g_assert_cmpint (destroy1_count, ==, 2);
g_assert_cmpint (destroy2_count, ==, 1);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,167 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include "test-conform-common.h"
#define RED 0
#define GREEN 1
#define BLUE 2
#define FRAMEBUFFER_WIDTH 640
#define FRAMEBUFFER_HEIGHT 480
static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
static void
on_paint (ClutterActor *actor, void *state)
{
float saved_viewport[4];
CoglMatrix saved_projection;
CoglMatrix projection;
CoglMatrix modelview;
guchar *data;
CoglHandle tex;
CoglHandle offscreen;
guint8 pixel[4];
/* Save the Clutter viewport/matrices and load identity matrices */
cogl_get_viewport (saved_viewport);
cogl_get_projection_matrix (&saved_projection);
cogl_push_matrix ();
cogl_matrix_init_identity (&projection);
cogl_matrix_init_identity (&modelview);
cogl_set_projection_matrix (&projection);
cogl_set_modelview_matrix (&modelview);
data = g_malloc (FRAMEBUFFER_WIDTH * 4 * FRAMEBUFFER_HEIGHT);
tex = cogl_texture_new_from_data (FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT,
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_RGBA_8888, /* data fmt */
COGL_PIXEL_FORMAT_ANY, /* internal fmt */
FRAMEBUFFER_WIDTH * 4, /* rowstride */
data);
g_free (data);
offscreen = cogl_offscreen_new_to_texture (tex);
/* Set a scale and translate transform on the window framebuffer before
* switching to the offscreen framebuffer so we can verify it gets restored
* when we switch back
*
* The test is going to draw a grid of 4 colors to a texture which we
* subsequently draw to the window with a fullscreen rectangle. This
* transform will flip the texture left to right, scale it to a quater of the
* window size and slide it to the top right of the window.
*/
cogl_translate (0.5, 0.5, 0);
cogl_scale (-0.5, 0.5, 1);
cogl_push_framebuffer (offscreen);
/* Cogl should release the last reference when we call cogl_pop_framebuffer()
*/
cogl_handle_unref (offscreen);
/* Setup something other than the identity matrix for the modelview so we can
* verify it gets restored when we call cogl_pop_framebuffer () */
cogl_scale (2, 2, 1);
/* red, top left */
cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
cogl_rectangle (-0.5, 0.5, 0, 0);
/* green, top right */
cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff);
cogl_rectangle (0, 0.5, 0.5, 0);
/* blue, bottom left */
cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff);
cogl_rectangle (-0.5, 0, 0, -0.5);
/* white, bottom right */
cogl_set_source_color4ub (0xff, 0xff, 0xff, 0xff);
cogl_rectangle (0, 0, 0.5, -0.5);
cogl_pop_framebuffer ();
cogl_set_source_texture (tex);
cogl_rectangle (-1, 1, 1, -1);
cogl_handle_unref (tex);
/* NB: The texture is drawn flipped horizontally and scaled to fit in the
* top right corner of the window. */
/* red, top right */
cogl_read_pixels (FRAMEBUFFER_WIDTH - 1, 0, 1, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixel);
g_assert (pixel[RED] == 0xff && pixel[GREEN] == 0x00 && pixel[BLUE] == 0x00);
/* green, top left */
cogl_read_pixels ((FRAMEBUFFER_WIDTH/2), 0, 1, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixel);
g_assert (pixel[RED] == 0x00 && pixel[GREEN] == 0xff && pixel[BLUE] == 0x00);
/* blue, bottom right */
cogl_read_pixels (FRAMEBUFFER_WIDTH - 1, (FRAMEBUFFER_HEIGHT/2) - 1, 1, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixel);
g_assert (pixel[RED] == 0x00 && pixel[GREEN] == 0x00 && pixel[BLUE] == 0xff);
/* white, bottom left */
cogl_read_pixels ((FRAMEBUFFER_WIDTH/2), (FRAMEBUFFER_HEIGHT/2) - 1, 1, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixel);
g_assert (pixel[RED] == 0xff && pixel[GREEN] == 0xff && pixel[BLUE] == 0xff);
/* Comment this out if you want visual feedback of what this test
* paints.
*/
clutter_main_quit ();
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
void
test_cogl_offscreen (TestUtilsGTestFixture *fixture,
void *data)
{
unsigned int idle_source;
ClutterActor *stage;
stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
/* We force continuous redrawing of the stage, since we need to skip
* the first few frames, and we wont be doing anything else that
* will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, stage);
g_signal_connect_after (stage, "paint", G_CALLBACK (on_paint), NULL);
clutter_actor_show (stage);
clutter_main ();
g_source_remove (idle_source);
/* Remove all of the actors from the stage */
clutter_container_foreach (CLUTTER_CONTAINER (stage),
(ClutterCallback) clutter_actor_destroy,
NULL);
if (g_test_verbose ())
g_print ("OK\n");
}

234
tests/conform/test-path.c Normal file
View File

@ -0,0 +1,234 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include "test-conform-common.h"
#define BLOCK_SIZE 16
/* Number of pixels at the border of a block quadrant to skip when verifying */
#define TEST_INSET 1
static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
static const ClutterColor block_color = { 0xff, 0xff, 0xff, 0xff };
typedef struct _TestState
{
ClutterActor *stage;
unsigned int frame;
} TestState;
static void
draw_path_at (int x, int y)
{
cogl_push_matrix ();
cogl_translate (x * BLOCK_SIZE, y * BLOCK_SIZE, 0.0f);
cogl_path_fill ();
cogl_pop_matrix ();
}
static void
verify_block (int block_x, int block_y, int block_mask)
{
guint8 data[BLOCK_SIZE * BLOCK_SIZE * 4];
int qx, qy;
/* Block mask represents which quarters of the block should be
filled. The bits from 0->3 represent the top left, top right,
bottom left and bottom right respectively */
cogl_read_pixels (block_x * BLOCK_SIZE,
block_y * BLOCK_SIZE,
BLOCK_SIZE, BLOCK_SIZE,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
data);
for (qy = 0; qy < 2; qy++)
for (qx = 0; qx < 2; qx++)
{
int bit = qx | (qy << 1);
const ClutterColor *color =
((block_mask & (1 << bit)) ? &block_color : &stage_color);
int x, y;
for (x = 0; x < BLOCK_SIZE / 2 - TEST_INSET * 2; x++)
for (y = 0; y < BLOCK_SIZE / 2 - TEST_INSET * 2; y++)
{
const guint8 *p = data + (qx * BLOCK_SIZE / 2 * 4 +
qy * BLOCK_SIZE * 4 * BLOCK_SIZE / 2 +
(x + TEST_INSET) * 4 +
(y + TEST_INSET) * BLOCK_SIZE * 4);
g_assert_cmpint (p[0], ==, color->red);
g_assert_cmpint (p[1], ==, color->green);
g_assert_cmpint (p[2], ==, color->blue);
}
}
}
static void
on_paint (ClutterActor *actor, TestState *state)
{
CoglHandle path_a, path_b, path_c;
if (state->frame++ < 2)
return;
cogl_set_source_color4ub (255, 255, 255, 255);
/* Create a path filling just a quarter of a block. It will use two
rectangles so that we have a sub path in the path */
cogl_path_new ();
cogl_path_rectangle (BLOCK_SIZE * 3 / 4, BLOCK_SIZE / 2,
BLOCK_SIZE, BLOCK_SIZE);
cogl_path_rectangle (BLOCK_SIZE / 2, BLOCK_SIZE / 2,
BLOCK_SIZE * 3 / 4, BLOCK_SIZE);
path_a = cogl_handle_ref (cogl_get_path ());
draw_path_at (0, 0);
/* Create another path filling the whole block */
cogl_path_rectangle (0, 0, BLOCK_SIZE, BLOCK_SIZE);
path_b = cogl_handle_ref (cogl_get_path ());
draw_path_at (1, 0);
/* Draw the first path again */
cogl_set_path (path_a);
draw_path_at (2, 0);
/* Draw a copy of path a */
path_c = cogl_path_copy (path_a);
cogl_set_path (path_c);
draw_path_at (3, 0);
/* Add another rectangle to path a. We'll use line_to's instead of
cogl_rectangle so that we don't create another sub-path because
that is more likely to break the copy */
cogl_set_path (path_a);
cogl_path_line_to (0, BLOCK_SIZE / 2);
cogl_path_line_to (0, 0);
cogl_path_line_to (BLOCK_SIZE / 2, 0);
cogl_path_line_to (BLOCK_SIZE / 2, BLOCK_SIZE / 2);
draw_path_at (4, 0);
/* Draw the copy again. It should not have changed */
cogl_set_path (path_c);
draw_path_at (5, 0);
/* Add another rectangle to path c. It will be added in two halves,
one as an extension of the previous path and the other as a new
sub path */
cogl_set_path (path_c);
cogl_path_line_to (BLOCK_SIZE / 2, 0);
cogl_path_line_to (BLOCK_SIZE * 3 / 4, 0);
cogl_path_line_to (BLOCK_SIZE * 3 / 4, BLOCK_SIZE / 2);
cogl_path_line_to (BLOCK_SIZE / 2, BLOCK_SIZE / 2);
cogl_path_rectangle (BLOCK_SIZE * 3 / 4, 0, BLOCK_SIZE, BLOCK_SIZE / 2);
draw_path_at (6, 0);
/* Draw the original path again. It should not have changed */
cogl_set_path (path_a);
draw_path_at (7, 0);
cogl_handle_unref (path_a);
cogl_handle_unref (path_b);
cogl_handle_unref (path_c);
/* Draw a self-intersecting path. The part that intersects should be
inverted */
cogl_path_rectangle (0, 0, BLOCK_SIZE, BLOCK_SIZE);
cogl_path_line_to (0, BLOCK_SIZE / 2);
cogl_path_line_to (BLOCK_SIZE / 2, BLOCK_SIZE / 2);
cogl_path_line_to (BLOCK_SIZE / 2, 0);
cogl_path_close ();
draw_path_at (8, 0);
/* Draw two sub paths. Where the paths intersect it should be
inverted */
cogl_path_rectangle (0, 0, BLOCK_SIZE, BLOCK_SIZE);
cogl_path_rectangle (BLOCK_SIZE / 2, BLOCK_SIZE / 2, BLOCK_SIZE, BLOCK_SIZE);
draw_path_at (9, 0);
/* Draw a clockwise outer path */
cogl_path_move_to (0, 0);
cogl_path_line_to (BLOCK_SIZE, 0);
cogl_path_line_to (BLOCK_SIZE, BLOCK_SIZE);
cogl_path_line_to (0, BLOCK_SIZE);
cogl_path_close ();
/* Add a clockwise sub path in the upper left quadrant */
cogl_path_move_to (0, 0);
cogl_path_line_to (BLOCK_SIZE / 2, 0);
cogl_path_line_to (BLOCK_SIZE / 2, BLOCK_SIZE / 2);
cogl_path_line_to (0, BLOCK_SIZE / 2);
cogl_path_close ();
/* Add a counter-clockwise sub path in the upper right quadrant */
cogl_path_move_to (BLOCK_SIZE / 2, 0);
cogl_path_line_to (BLOCK_SIZE / 2, BLOCK_SIZE / 2);
cogl_path_line_to (BLOCK_SIZE, BLOCK_SIZE / 2);
cogl_path_line_to (BLOCK_SIZE, 0);
cogl_path_close ();
/* Retain the path for the next test */
path_a = cogl_handle_ref (cogl_get_path ());
draw_path_at (10, 0);
/* Draw the same path again with the other fill rule */
cogl_set_path (path_a);
cogl_path_set_fill_rule (COGL_PATH_FILL_RULE_NON_ZERO);
draw_path_at (11, 0);
cogl_handle_unref (path_a);
verify_block (0, 0, 0x8 /* bottom right */);
verify_block (1, 0, 0xf /* all of them */);
verify_block (2, 0, 0x8 /* bottom right */);
verify_block (3, 0, 0x8 /* bottom right */);
verify_block (4, 0, 0x9 /* top left and bottom right */);
verify_block (5, 0, 0x8 /* bottom right */);
verify_block (6, 0, 0xa /* bottom right and top right */);
verify_block (7, 0, 0x9 /* top_left and bottom right */);
verify_block (8, 0, 0xe /* all but top left */);
verify_block (9, 0, 0x7 /* all but bottom right */);
verify_block (10, 0, 0xc /* bottom two */);
verify_block (11, 0, 0xd /* all but top right */);
/* Comment this out if you want visual feedback of what this test
* paints.
*/
clutter_main_quit ();
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
void
test_cogl_path (TestUtilsGTestFixture *fixture,
void *data)
{
TestState state;
unsigned int idle_source;
unsigned int paint_handler;
state.frame = 0;
state.stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (state.stage), &stage_color);
/* We force continuous redrawing of the stage, since we need to skip
* the first few frames, and we wont be doing anything else that
* will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, state.stage);
paint_handler = g_signal_connect_after (state.stage, "paint",
G_CALLBACK (on_paint), &state);
clutter_actor_show (state.stage);
clutter_main ();
g_signal_handler_disconnect (state.stage, paint_handler);
g_source_remove (idle_source);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,144 @@
#include <clutter/clutter.h>
#include <string.h>
#include "test-conform-common.h"
static const ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff };
static void
paint_cb (ClutterActor *stage)
{
/* This texture is painted mirrored around the x-axis */
guint8 data0[] = {
0xff, 0x00, 0x00, /* red -> becomes bottom left */
0x00, 0xff, 0x00, /* green -> becomes bottom right */
0x00, 0x00, 0xff, /* blue -> becomes top left */
0xff, 0x00, 0xff /* magenta -> becomes top right */
};
/* This texture is painted mirrored about the y-axis */
guint8 data1[] = {
0x00, 0xff, 0x00, /* green -> becomes top right */
0xff, 0xff, 0x00, /* yellow -> becomes top left */
0xff, 0x00, 0xff, /* magenta -> becomes bottom right */
0x00, 0xff, 0xff /* cyan -> becomes bottom left */
};
CoglHandle tex0, tex1;
CoglPipeline *pipeline;
CoglMatrix matrix;
int width, height;
guint8 *pixels, *p;
width = clutter_actor_get_width (stage);
height = clutter_actor_get_height (stage);
tex0 = cogl_texture_new_from_data (2, 2,
COGL_TEXTURE_NO_ATLAS,
COGL_PIXEL_FORMAT_RGB_888,
COGL_PIXEL_FORMAT_ANY,
6,
data0);
tex1 = cogl_texture_new_from_data (2, 2,
COGL_TEXTURE_NO_ATLAS,
COGL_PIXEL_FORMAT_RGB_888,
COGL_PIXEL_FORMAT_ANY,
6,
data1);
pipeline = cogl_pipeline_new ();
/* Set the two textures as layers */
cogl_pipeline_set_layer_texture (pipeline, 0, tex0);
cogl_pipeline_set_layer_filters (pipeline, 0,
COGL_PIPELINE_FILTER_NEAREST,
COGL_PIPELINE_FILTER_NEAREST);
cogl_pipeline_set_layer_texture (pipeline, 1, tex1);
cogl_pipeline_set_layer_filters (pipeline, 1,
COGL_PIPELINE_FILTER_NEAREST,
COGL_PIPELINE_FILTER_NEAREST);
/* Set a combine mode so that the two textures get added together */
cogl_pipeline_set_layer_combine (pipeline, 1,
"RGBA=ADD(PREVIOUS, TEXTURE)",
NULL);
/* Set a matrix on the first layer so that it will mirror about the y-axis */
cogl_matrix_init_identity (&matrix);
cogl_matrix_translate (&matrix, 0.0f, 1.0f, 0.0f);
cogl_matrix_scale (&matrix, 1.0f, -1.0f, 1.0f);
cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix);
/* Set a matrix on the second layer so that it will mirror about the x-axis */
cogl_matrix_init_identity (&matrix);
cogl_matrix_translate (&matrix, 1.0f, 0.0f, 0.0f);
cogl_matrix_scale (&matrix, -1.0f, 1.0f, 1.0f);
cogl_pipeline_set_layer_matrix (pipeline, 1, &matrix);
cogl_set_source (pipeline);
cogl_rectangle (0, 0, width, height);
cogl_handle_unref (tex1);
cogl_handle_unref (tex0);
cogl_object_unref (pipeline);
/* The textures are setup so that when added together with the
correct matrices then all of the pixels should be white. We can
verify this by reading back the entire stage */
pixels = g_malloc (width * height * 4);
cogl_read_pixels (0, 0, width, height,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixels);
for (p = pixels + width * height * 4; p > pixels;)
{
p -= 4;
g_assert_cmpint (p[0], ==, 0xff);
g_assert_cmpint (p[1], ==, 0xff);
g_assert_cmpint (p[2], ==, 0xff);
}
g_free (pixels);
clutter_main_quit ();
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
void
test_cogl_pipeline_user_matrix (TestUtilsGTestFixture *fixture,
void *data)
{
ClutterActor *stage;
unsigned int idle_source;
unsigned int paint_handler;
stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
/* We force continuous redrawing of the stage, since we need to skip
* the first few frames, and we wont be doing anything else that
* will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, stage);
paint_handler = g_signal_connect_after (stage, "paint",
G_CALLBACK (paint_cb),
NULL);
clutter_actor_show (stage);
clutter_main ();
g_source_remove (idle_source);
g_signal_handler_disconnect (stage, paint_handler);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,330 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <string.h>
#include "test-conform-common.h"
#define TILE_SIZE 32.0f
enum
{
TILE_MAP,
TILE_SET_DATA,
NB_TILES,
TILE_SET_REGION,
};
typedef struct test_tile
{
ClutterColor color;
gfloat x, y;
CoglHandle buffer;
CoglHandle texture;
} TestTile;
static const ClutterColor
buffer_colors[] =
{
};
static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
typedef struct _TestState
{
ClutterActor *stage;
unsigned int frame;
TestTile *tiles;
} TestState;
static CoglHandle
create_texture_from_buffer (CoglHandle buffer)
{
CoglHandle texture;
texture = cogl_texture_new_from_buffer (buffer,
TILE_SIZE, TILE_SIZE,
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_RGBA_8888,
COGL_PIXEL_FORMAT_RGBA_8888,
TILE_SIZE * 4,
0);
g_assert (texture != COGL_INVALID_HANDLE);
return texture;
}
static void
create_map_tile (TestTile *tile)
{
CoglHandle buffer;
guchar *map;
unsigned int i;
unsigned int stride = 0;
guint8 *line;
buffer = cogl_pixel_array_new_with_size (TILE_SIZE,
TILE_SIZE,
COGL_PIXEL_FORMAT_RGBA_8888,
&stride);
g_assert (cogl_is_pixel_array (buffer));
g_assert (cogl_is_buffer (buffer));
cogl_buffer_set_update_hint (buffer, COGL_BUFFER_UPDATE_HINT_DYNAMIC);
g_assert_cmpint (cogl_buffer_get_update_hint (buffer),
==,
COGL_BUFFER_UPDATE_HINT_DYNAMIC);
map = cogl_buffer_map (buffer,
COGL_BUFFER_ACCESS_WRITE,
COGL_BUFFER_MAP_HINT_DISCARD);
g_assert (map);
line = g_alloca (TILE_SIZE * 4);
for (i = 0; i < TILE_SIZE * 4; i += 4)
memcpy (line + i, &tile->color, 4);
for (i = 0; i < TILE_SIZE; i++)
memcpy (map + stride * i, line, TILE_SIZE * 4);
cogl_buffer_unmap (buffer);
tile->buffer = buffer;
tile->texture = create_texture_from_buffer (tile->buffer);
}
#if 0
static void
create_set_region_tile (TestTile *tile)
{
CoglHandle buffer;
ClutterColor bottom_color;
unsigned int rowstride = 0;
guchar *data;
unsigned int i;
buffer = cogl_pixel_array_with_size (TILE_SIZE,
TILE_SIZE,
COGL_PIXEL_FORMAT_RGBA_8888,
&rowstride);
g_assert (cogl_is_pixel_array (buffer));
g_assert (cogl_is_buffer (buffer));
/* while at it, set/get the hint */
cogl_buffer_set_hint (buffer, COGL_BUFFER_HINT_STATIC_TEXTURE);
g_assert (cogl_buffer_get_hint (buffer) == COGL_BUFFER_HINT_STATIC_TEXTURE);
data = g_malloc (TILE_SIZE * TILE_SIZE * 4);
/* create a buffer with the data we want to copy to the buffer */
for (i = 0; i < TILE_SIZE * TILE_SIZE * 4; i += 4)
memcpy (data + i, &tile->color, 4);
cogl_pixel_array_set_region (buffer,
data,
TILE_SIZE, TILE_SIZE,
TILE_SIZE,
0, 0);
bottom_color.red = tile->color.red;
bottom_color.green = tile->color.blue;
bottom_color.blue = tile->color.green;
bottom_color.alpha = tile->color.alpha;
for (i = 0; i < TILE_SIZE / 2; i++)
memcpy (data + i, &bottom_color, 4);
cogl_buffer_set_data (buffer, data, 0, TILE_SIZE * TILE_SIZE * 4 / 2);
g_free (data);
tile->buffer = buffer;
tile->texture = create_texture_from_buffer (tile->buffer);
}
#endif
static void
create_set_data_tile (TestTile *tile)
{
CoglHandle buffer;
unsigned int rowstride = 0;
gboolean res;
guchar *data;
unsigned int i;
buffer = cogl_pixel_array_new_with_size (TILE_SIZE,
TILE_SIZE,
COGL_PIXEL_FORMAT_RGBA_8888,
&rowstride);
g_assert (cogl_is_pixel_array (buffer));
g_assert (cogl_is_buffer (buffer));
g_assert_cmpint (cogl_buffer_get_size (buffer), ==, rowstride * TILE_SIZE);
/* create a buffer with the data we want to copy to the buffer */
data = g_malloc (TILE_SIZE * TILE_SIZE * 4);
for (i = 0; i < TILE_SIZE * TILE_SIZE * 4; i += 4)
memcpy (data + i, &tile->color, 4);
/* FIXME: this doesn't consider the rowstride */
res = cogl_buffer_set_data (buffer, 0, data, TILE_SIZE * TILE_SIZE * 4);
g_assert (res);
g_free (data);
tile->buffer = buffer;
tile->texture = create_texture_from_buffer (tile->buffer);
}
static void
draw_frame (TestState *state)
{
unsigned int i;
/* Paint the textures */
for (i = 0; i < NB_TILES; i++)
{
cogl_set_source_texture (state->tiles[i].texture);
cogl_rectangle (state->tiles[i].x,
state->tiles[i].y,
state->tiles[i].x + TILE_SIZE,
state->tiles[i].y + TILE_SIZE);
}
}
static gboolean
validate_tile (TestState *state,
TestTile *tile)
{
int x, y;
guchar *pixels, *p;
p = pixels = clutter_stage_read_pixels (CLUTTER_STAGE (state->stage),
tile->x,
tile->y,
TILE_SIZE,
TILE_SIZE);
/* Check whether the center of each division is the right color */
for (y = 0; y < TILE_SIZE; y++)
for (x = 0; x < TILE_SIZE; x++)
{
if (p[0] != tile->color.red ||
p[1] != tile->color.green ||
p[2] != tile->color.blue ||
p[3] != tile->color.alpha)
{
return FALSE;
}
p += 4;
}
return TRUE;
}
static void
validate_result (TestState *state)
{
unsigned int i;
for (i = 0; i < NB_TILES; i++)
g_assert (validate_tile (state, &state->tiles[i]));
/* comment this if you want to see what's being drawn */
#if 1
clutter_main_quit ();
#endif
}
static void
on_paint (ClutterActor *actor, TestState *state)
{
int frame_num;
draw_frame (state);
/* XXX: validate_result calls clutter_stage_read_pixels which will result in
* another paint run so to avoid infinite recursion we only aim to validate
* the first frame. */
frame_num = state->frame++;
if (frame_num == 1)
validate_result (state);
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
void
test_cogl_pixel_array (TestUtilsGTestFixture *fixture,
void * data)
{
TestState state;
unsigned int idle_source;
unsigned int paint_handler, i;
static TestTile tiles[NB_TILES] =
{
/* color x y buffer tex */
/* MAP */
{ { 0xff, 0x00, 0x00, 0xff }, 0.0f, 0.0f, NULL, NULL },
#if 0
/* SET_REGION */
{ { 0x7e, 0x7e, 0xff, 0x7e }, 0.0f, TILE_SIZE, NULL, NULL },
#endif
/* SET_DATA */
{ { 0x7e, 0xff, 0x7e, 0xff }, 0.0f, TILE_SIZE, NULL, NULL }
};
state.frame = 0;
state.stage = clutter_stage_get_default ();
create_map_tile (&tiles[TILE_MAP]);
#if 0
create_set_region_tile (&tiles[TILE_SET_REGION]);
#endif
create_set_data_tile (&tiles[TILE_SET_DATA]);
state.tiles = tiles;
clutter_stage_set_color (CLUTTER_STAGE (state.stage), &stage_color);
/* We force continuous redrawing of the stage, since we need to skip
* the first few frames, and we wont be doing anything else that
* will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, state.stage);
paint_handler = g_signal_connect_after (state.stage, "paint",
G_CALLBACK (on_paint), &state);
clutter_actor_show_all (state.stage);
clutter_main ();
g_source_remove (idle_source);
g_signal_handler_disconnect (state.stage, paint_handler);
for (i = 0; i < NB_TILES; i++)
{
cogl_handle_unref (state.tiles[i].buffer);
cogl_handle_unref (state.tiles[i].texture);
}
/* Remove all of the actors from the stage */
clutter_container_foreach (CLUTTER_CONTAINER (state.stage),
(ClutterCallback) clutter_actor_destroy,
NULL);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,367 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <string.h>
#include "test-conform-common.h"
static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
#define QUAD_WIDTH 20
#define RED 0
#define GREEN 1
#define BLUE 2
#define ALPHA 3
#define MASK_RED(COLOR) ((COLOR & 0xff000000) >> 24)
#define MASK_GREEN(COLOR) ((COLOR & 0xff0000) >> 16)
#define MASK_BLUE(COLOR) ((COLOR & 0xff00) >> 8)
#define MASK_ALPHA(COLOR) (COLOR & 0xff)
typedef struct _TestState
{
ClutterGeometry stage_geom;
CoglHandle passthrough_material;
} TestState;
static void
check_pixel (GLubyte *pixel, guint32 color)
{
guint8 r = MASK_RED (color);
guint8 g = MASK_GREEN (color);
guint8 b = MASK_BLUE (color);
guint8 a = MASK_ALPHA (color);
if (g_test_verbose ())
g_print (" expected = %x, %x, %x, %x\n",
r, g, b, a);
/* FIXME - allow for hardware in-precision */
g_assert (pixel[RED] == r);
g_assert (pixel[GREEN] == g);
g_assert (pixel[BLUE] == b);
/* FIXME
* We ignore the alpha, since we don't know if our render target is
* RGB or RGBA */
/* g_assert (pixel[ALPHA] == a); */
}
static guchar *
gen_tex_data (guint32 color)
{
guchar *tex_data, *p;
guint8 r = MASK_RED (color);
guint8 g = MASK_GREEN (color);
guint8 b = MASK_BLUE (color);
guint8 a = MASK_ALPHA (color);
tex_data = g_malloc (QUAD_WIDTH * QUAD_WIDTH * 4);
for (p = tex_data + QUAD_WIDTH * QUAD_WIDTH * 4; p > tex_data;)
{
*(--p) = a;
*(--p) = b;
*(--p) = g;
*(--p) = r;
}
return tex_data;
}
static CoglHandle
make_texture (guint32 color,
CoglPixelFormat src_format,
CoglPixelFormat internal_format)
{
CoglHandle tex;
guchar *tex_data = gen_tex_data (color);
tex = cogl_texture_new_from_data (QUAD_WIDTH,
QUAD_WIDTH,
COGL_TEXTURE_NONE,
src_format,
internal_format,
QUAD_WIDTH * 4,
tex_data);
g_free (tex_data);
return tex;
}
static void
check_texture (TestState *state,
int x,
int y,
CoglHandle tex,
guint32 expected_result)
{
guchar pixel[4];
int y_off;
int x_off;
cogl_material_set_layer (state->passthrough_material, 0, tex);
cogl_set_source (state->passthrough_material);
cogl_rectangle (x * QUAD_WIDTH,
y * QUAD_WIDTH,
x * QUAD_WIDTH + QUAD_WIDTH,
y * QUAD_WIDTH + QUAD_WIDTH);
/* See what we got... */
y_off = y * QUAD_WIDTH + (QUAD_WIDTH / 2);
x_off = x * QUAD_WIDTH + (QUAD_WIDTH / 2);
cogl_read_pixels (x_off, y_off, 1, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixel);
if (g_test_verbose ())
{
g_print ("check texture (%d, %d):\n", x, y);
g_print (" result = %02x, %02x, %02x, %02x\n",
pixel[RED], pixel[GREEN], pixel[BLUE], pixel[ALPHA]);
}
check_pixel (pixel, expected_result);
}
static void
on_paint (ClutterActor *actor, TestState *state)
{
CoglHandle tex;
guchar *tex_data;
/* If the user explicitly specifies an unmultiplied internal format then
* Cogl shouldn't automatically premultiply the given texture data... */
if (g_test_verbose ())
g_print ("make_texture (0xff00ff80, "
"src = RGBA_8888, internal = RGBA_8888)\n");
tex = make_texture (0xff00ff80,
COGL_PIXEL_FORMAT_RGBA_8888, /* src format */
COGL_PIXEL_FORMAT_RGBA_8888); /* internal format */
check_texture (state, 0, 0, /* position */
tex,
0xff00ff80); /* expected */
/* If the user explicitly requests a premultiplied internal format and
* gives unmultiplied src data then Cogl should always premultiply that
* for us */
if (g_test_verbose ())
g_print ("make_texture (0xff00ff80, "
"src = RGBA_8888, internal = RGBA_8888_PRE)\n");
tex = make_texture (0xff00ff80,
COGL_PIXEL_FORMAT_RGBA_8888, /* src format */
COGL_PIXEL_FORMAT_RGBA_8888_PRE); /* internal format */
check_texture (state, 1, 0, /* position */
tex,
0x80008080); /* expected */
/* If the user gives COGL_PIXEL_FORMAT_ANY for the internal format then
* by default Cogl should premultiply the given texture data...
* (In the future there will be additional Cogl API to control this
* behaviour) */
if (g_test_verbose ())
g_print ("make_texture (0xff00ff80, "
"src = RGBA_8888, internal = ANY)\n");
tex = make_texture (0xff00ff80,
COGL_PIXEL_FORMAT_RGBA_8888, /* src format */
COGL_PIXEL_FORMAT_ANY); /* internal format */
check_texture (state, 2, 0, /* position */
tex,
0x80008080); /* expected */
/* If the user requests a premultiplied internal texture format and supplies
* premultiplied source data, Cogl should never modify that source data...
*/
if (g_test_verbose ())
g_print ("make_texture (0x80008080, "
"src = RGBA_8888_PRE, "
"internal = RGBA_8888_PRE)\n");
tex = make_texture (0x80008080,
COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */
COGL_PIXEL_FORMAT_RGBA_8888_PRE); /* internal format */
check_texture (state, 3, 0, /* position */
tex,
0x80008080); /* expected */
/* If the user requests an unmultiplied internal texture format, but
* supplies premultiplied source data, then Cogl should always
* un-premultiply the source data... */
if (g_test_verbose ())
g_print ("make_texture (0x80008080, "
"src = RGBA_8888_PRE, internal = RGBA_8888)\n");
tex = make_texture (0x80008080,
COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */
COGL_PIXEL_FORMAT_RGBA_8888); /* internal format */
check_texture (state, 4, 0, /* position */
tex,
0xff00ff80); /* expected */
/* If the user allows any internal texture format and provides premultipled
* source data then by default Cogl shouldn't modify the source data...
* (In the future there will be additional Cogl API to control this
* behaviour) */
if (g_test_verbose ())
g_print ("make_texture (0x80008080, "
"src = RGBA_8888_PRE, internal = ANY)\n");
tex = make_texture (0x80008080,
COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */
COGL_PIXEL_FORMAT_ANY); /* internal format */
check_texture (state, 5, 0, /* position */
tex,
0x80008080); /* expected */
/*
* Test cogl_texture_set_region() ....
*/
if (g_test_verbose ())
g_print ("make_texture (0xDEADBEEF, "
"src = RGBA_8888, internal = RGBA_8888)\n");
tex = make_texture (0xDEADBEEF,
COGL_PIXEL_FORMAT_RGBA_8888, /* src format */
COGL_PIXEL_FORMAT_RGBA_8888); /* internal format */
if (g_test_verbose ())
g_print ("set_region (0xff00ff80, RGBA_8888)\n");
tex_data = gen_tex_data (0xff00ff80);
cogl_texture_set_region (tex,
0, 0, /* src x, y */
0, 0, /* dst x, y */
QUAD_WIDTH, QUAD_WIDTH, /* dst width, height */
QUAD_WIDTH, QUAD_WIDTH, /* src width, height */
COGL_PIXEL_FORMAT_RGBA_8888,
0, /* auto compute row stride */
tex_data);
check_texture (state, 6, 0, /* position */
tex,
0xff00ff80); /* expected */
/* Updating a texture region for an unmultiplied texture using premultiplied
* region data should result in Cogl unmultiplying the given region data...
*/
if (g_test_verbose ())
g_print ("make_texture (0xDEADBEEF, "
"src = RGBA_8888, internal = RGBA_8888)\n");
tex = make_texture (0xDEADBEEF,
COGL_PIXEL_FORMAT_RGBA_8888, /* src format */
COGL_PIXEL_FORMAT_RGBA_8888); /* internal format */
if (g_test_verbose ())
g_print ("set_region (0x80008080, RGBA_8888_PRE)\n");
tex_data = gen_tex_data (0x80008080);
cogl_texture_set_region (tex,
0, 0, /* src x, y */
0, 0, /* dst x, y */
QUAD_WIDTH, QUAD_WIDTH, /* dst width, height */
QUAD_WIDTH, QUAD_WIDTH, /* src width, height */
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
0, /* auto compute row stride */
tex_data);
check_texture (state, 7, 0, /* position */
tex,
0xff00ff80); /* expected */
if (g_test_verbose ())
g_print ("make_texture (0xDEADBEEF, "
"src = RGBA_8888_PRE, "
"internal = RGBA_8888_PRE)\n");
tex = make_texture (0xDEADBEEF,
COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */
COGL_PIXEL_FORMAT_RGBA_8888_PRE); /* internal format */
if (g_test_verbose ())
g_print ("set_region (0x80008080, RGBA_8888_PRE)\n");
tex_data = gen_tex_data (0x80008080);
cogl_texture_set_region (tex,
0, 0, /* src x, y */
0, 0, /* dst x, y */
QUAD_WIDTH, QUAD_WIDTH, /* dst width, height */
QUAD_WIDTH, QUAD_WIDTH, /* src width, height */
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
0, /* auto compute row stride */
tex_data);
check_texture (state, 8, 0, /* position */
tex,
0x80008080); /* expected */
/* Updating a texture region for a premultiplied texture using unmultiplied
* region data should result in Cogl premultiplying the given region data...
*/
if (g_test_verbose ())
g_print ("make_texture (0xDEADBEEF, "
"src = RGBA_8888_PRE, "
"internal = RGBA_8888_PRE)\n");
tex = make_texture (0xDEADBEEF,
COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */
COGL_PIXEL_FORMAT_RGBA_8888_PRE); /* internal format */
if (g_test_verbose ())
g_print ("set_region (0xff00ff80, RGBA_8888)\n");
tex_data = gen_tex_data (0xff00ff80);
cogl_texture_set_region (tex,
0, 0, /* src x, y */
0, 0, /* dst x, y */
QUAD_WIDTH, QUAD_WIDTH, /* dst width, height */
QUAD_WIDTH, QUAD_WIDTH, /* src width, height */
COGL_PIXEL_FORMAT_RGBA_8888,
0, /* auto compute row stride */
tex_data);
check_texture (state, 9, 0, /* position */
tex,
0x80008080); /* expected */
/* Comment this out if you want visual feedback for what this test paints */
clutter_main_quit ();
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
void
test_cogl_premult (TestUtilsGTestFixture *fixture,
void *data)
{
TestState state;
ClutterActor *stage;
ClutterActor *group;
unsigned int idle_source;
state.passthrough_material = cogl_material_new ();
cogl_material_set_blend (state.passthrough_material,
"RGBA = ADD (SRC_COLOR, 0)", NULL);
cogl_material_set_layer_combine (state.passthrough_material, 0,
"RGBA = REPLACE (TEXTURE)", NULL);
stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
clutter_actor_get_geometry (stage, &state.stage_geom);
group = clutter_group_new ();
clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
/* We force continuous redrawing incase someone comments out the
* clutter_main_quit and wants visual feedback for the test since we
* wont be doing anything else that will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, stage);
g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
clutter_actor_show_all (stage);
clutter_main ();
g_source_remove (idle_source);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,230 @@
#include <clutter/clutter.h>
#include <string.h>
#include "test-conform-common.h"
static const ClutterColor stage_color = { 0x00, 0xff, 0x00, 0xff };
static const ClutterColor prim_color = { 0xff, 0x00, 0xff, 0xff };
static const ClutterColor tex_color = { 0x00, 0x00, 0xff, 0xff };
typedef CoglPrimitive * (* TestPrimFunc) (ClutterColor *expected_color);
static CoglPrimitive *
test_prim_p2 (ClutterColor *expected_color)
{
static const CoglVertexP2 verts[] =
{ { 0, 0 }, { 0, 10 }, { 10, 0 } };
return cogl_primitive_new_p2 (COGL_VERTICES_MODE_TRIANGLES,
3, /* n_vertices */
verts);
}
static CoglPrimitive *
test_prim_p3 (ClutterColor *expected_color)
{
static const CoglVertexP3 verts[] =
{ { 0, 0, 0 }, { 0, 10, 0 }, { 10, 0, 0 } };
return cogl_primitive_new_p3 (COGL_VERTICES_MODE_TRIANGLES,
3, /* n_vertices */
verts);
}
static CoglPrimitive *
test_prim_p2c4 (ClutterColor *expected_color)
{
static const CoglVertexP2C4 verts[] =
{ { 0, 0, 255, 255, 0, 255 },
{ 0, 10, 255, 255, 0, 255 },
{ 10, 0, 255, 255, 0, 255 } };
expected_color->red = 255;
expected_color->green = 255;
expected_color->blue = 0;
return cogl_primitive_new_p2c4 (COGL_VERTICES_MODE_TRIANGLES,
3, /* n_vertices */
verts);
}
static CoglPrimitive *
test_prim_p3c4 (ClutterColor *expected_color)
{
static const CoglVertexP3C4 verts[] =
{ { 0, 0, 0, 255, 255, 0, 255 },
{ 0, 10, 0, 255, 255, 0, 255 },
{ 10, 0, 0, 255, 255, 0, 255 } };
expected_color->red = 255;
expected_color->green = 255;
expected_color->blue = 0;
return cogl_primitive_new_p3c4 (COGL_VERTICES_MODE_TRIANGLES,
3, /* n_vertices */
verts);
}
static CoglPrimitive *
test_prim_p2t2 (ClutterColor *expected_color)
{
static const CoglVertexP2T2 verts[] =
{ { 0, 0, 1, 0 },
{ 0, 10, 1, 0 },
{ 10, 0, 1, 0 } };
*expected_color = tex_color;
return cogl_primitive_new_p2t2 (COGL_VERTICES_MODE_TRIANGLES,
3, /* n_vertices */
verts);
}
static CoglPrimitive *
test_prim_p3t2 (ClutterColor *expected_color)
{
static const CoglVertexP3T2 verts[] =
{ { 0, 0, 0, 1, 0 },
{ 0, 10, 0, 1, 0 },
{ 10, 0, 0, 1, 0 } };
*expected_color = tex_color;
return cogl_primitive_new_p3t2 (COGL_VERTICES_MODE_TRIANGLES,
3, /* n_vertices */
verts);
}
static CoglPrimitive *
test_prim_p2t2c4 (ClutterColor *expected_color)
{
static const CoglVertexP2T2C4 verts[] =
{ { 0, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff },
{ 0, 10, 1, 0, 0xff, 0xff, 0xf0, 0xff },
{ 10, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff } };
*expected_color = tex_color;
expected_color->blue = 0xf0;
return cogl_primitive_new_p2t2c4 (COGL_VERTICES_MODE_TRIANGLES,
3, /* n_vertices */
verts);
}
static CoglPrimitive *
test_prim_p3t2c4 (ClutterColor *expected_color)
{
static const CoglVertexP3T2C4 verts[] =
{ { 0, 0, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff },
{ 0, 10, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff },
{ 10, 0, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff } };
*expected_color = tex_color;
expected_color->blue = 0xf0;
return cogl_primitive_new_p3t2c4 (COGL_VERTICES_MODE_TRIANGLES,
3, /* n_vertices */
verts);
}
static const TestPrimFunc
test_prim_funcs[] =
{
test_prim_p2,
test_prim_p3,
test_prim_p2c4,
test_prim_p3c4,
test_prim_p2t2,
test_prim_p3t2,
test_prim_p2t2c4,
test_prim_p3t2c4
};
static void
paint_cb (void)
{
CoglPipeline *pipeline;
CoglHandle tex;
guint8 tex_data[6];
int i;
/* Create a two pixel texture. The first pixel is white and the
second pixel is tex_color. The assumption is that if no texture
coordinates are specified then it will default to 0,0 and get
white */
tex_data[0] = 255;
tex_data[1] = 255;
tex_data[2] = 255;
tex_data[3] = tex_color.red;
tex_data[4] = tex_color.green;
tex_data[5] = tex_color.blue;
tex = cogl_texture_new_from_data (2, 1, /* size */
COGL_TEXTURE_NO_ATLAS,
COGL_PIXEL_FORMAT_RGB_888,
COGL_PIXEL_FORMAT_ANY,
6, /* rowstride */
tex_data);
pipeline = cogl_pipeline_new ();
cogl_pipeline_set_color4ub (pipeline,
prim_color.red,
prim_color.green,
prim_color.blue,
prim_color.alpha);
cogl_pipeline_set_layer_texture (pipeline, 0, tex);
cogl_handle_unref (tex);
cogl_set_source (pipeline);
cogl_object_unref (pipeline);
for (i = 0; i < G_N_ELEMENTS (test_prim_funcs); i++)
{
CoglPrimitive *prim;
ClutterColor expected_color = prim_color;
guint8 pixel[4];
prim = test_prim_funcs[i] (&expected_color);
cogl_push_matrix ();
cogl_translate (i * 10, 0, 0);
cogl_primitive_draw (prim);
cogl_pop_matrix ();
cogl_read_pixels (i * 10 + 2, 2, 1, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixel);
g_assert_cmpint (pixel[0], ==, expected_color.red);
g_assert_cmpint (pixel[1], ==, expected_color.green);
g_assert_cmpint (pixel[2], ==, expected_color.blue);
cogl_object_unref (prim);
}
/* Comment this out to see what the test paints */
clutter_main_quit ();
}
void
test_cogl_primitive (TestUtilsGTestFixture *fixture,
void *data)
{
ClutterActor *stage;
unsigned int paint_handler;
stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
paint_handler = g_signal_connect_after (stage, "paint",
G_CALLBACK (paint_cb), NULL);
clutter_actor_show (stage);
clutter_main ();
g_signal_handler_disconnect (stage, paint_handler);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,178 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include "test-conform-common.h"
#define RED 0
#define GREEN 1
#define BLUE 2
#define FRAMEBUFFER_WIDTH 640
#define FRAMEBUFFER_HEIGHT 480
static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
static void
on_paint (ClutterActor *actor, void *state)
{
float saved_viewport[4];
CoglMatrix saved_projection;
CoglMatrix projection;
CoglMatrix modelview;
guchar *data;
CoglHandle tex;
CoglHandle offscreen;
guint32 *pixels;
guint8 *pixelsc;
/* Save the Clutter viewport/matrices and load identity matrices */
cogl_get_viewport (saved_viewport);
cogl_get_projection_matrix (&saved_projection);
cogl_push_matrix ();
cogl_matrix_init_identity (&projection);
cogl_matrix_init_identity (&modelview);
cogl_set_projection_matrix (&projection);
cogl_set_modelview_matrix (&modelview);
/* All offscreen rendering is done upside down so the first thing we
* verify is reading back grid of colors from a CoglOffscreen framebuffer
*/
data = g_malloc (FRAMEBUFFER_WIDTH * 4 * FRAMEBUFFER_HEIGHT);
tex = cogl_texture_new_from_data (FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT,
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_RGBA_8888, /* data fmt */
COGL_PIXEL_FORMAT_ANY, /* internal fmt */
FRAMEBUFFER_WIDTH * 4, /* rowstride */
data);
g_free (data);
offscreen = cogl_offscreen_new_to_texture (tex);
cogl_push_framebuffer (offscreen);
/* red, top left */
cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
cogl_rectangle (-1, 1, 0, 0);
/* green, top right */
cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff);
cogl_rectangle (0, 1, 1, 0);
/* blue, bottom left */
cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff);
cogl_rectangle (-1, 0, 0, -1);
/* white, bottom right */
cogl_set_source_color4ub (0xff, 0xff, 0xff, 0xff);
cogl_rectangle (0, 0, 1, -1);
pixels = g_malloc0 (FRAMEBUFFER_WIDTH * 4 * FRAMEBUFFER_HEIGHT);
cogl_read_pixels (0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
(guchar *)pixels);
g_assert_cmpint (pixels[0], ==, 0xff0000ff);
g_assert_cmpint (pixels[FRAMEBUFFER_WIDTH - 1], ==, 0xff00ff00);
g_assert_cmpint (pixels[(FRAMEBUFFER_HEIGHT - 1) * FRAMEBUFFER_WIDTH], ==, 0xffff0000);
g_assert_cmpint (pixels[(FRAMEBUFFER_HEIGHT - 1) * FRAMEBUFFER_WIDTH + FRAMEBUFFER_WIDTH - 1], ==, 0xffffffff);
g_free (pixels);
cogl_pop_framebuffer ();
cogl_handle_unref (offscreen);
/* Now verify reading back from an onscreen framebuffer...
*/
cogl_set_source_texture (tex);
cogl_rectangle (-1, 1, 1, -1);
pixels = g_malloc0 (FRAMEBUFFER_WIDTH * 4 * FRAMEBUFFER_HEIGHT);
cogl_read_pixels (0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
(guchar *)pixels);
g_assert_cmpint (pixels[0], ==, 0xff0000ff);
g_assert_cmpint (pixels[FRAMEBUFFER_WIDTH - 1], ==, 0xff00ff00);
g_assert_cmpint (pixels[(FRAMEBUFFER_HEIGHT - 1) * FRAMEBUFFER_WIDTH], ==, 0xffff0000);
g_assert_cmpint (pixels[(FRAMEBUFFER_HEIGHT - 1) * FRAMEBUFFER_WIDTH + FRAMEBUFFER_WIDTH - 1], ==, 0xffffffff);
g_free (pixels);
/* Verify using BGR format */
cogl_set_source_texture (tex);
cogl_rectangle (-1, 1, 1, -1);
pixelsc = g_malloc0 (FRAMEBUFFER_WIDTH * 3 * FRAMEBUFFER_HEIGHT);
cogl_read_pixels (0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_BGR_888,
(guchar *)pixelsc);
g_assert_cmpint (pixelsc[0], ==, 0x00);
g_assert_cmpint (pixelsc[1], ==, 0x00);
g_assert_cmpint (pixelsc[2], ==, 0xff);
g_assert_cmpint (pixelsc[(FRAMEBUFFER_WIDTH - 1) * 3 + 0], ==, 0x00);
g_assert_cmpint (pixelsc[(FRAMEBUFFER_WIDTH - 1) * 3 + 1], ==, 0xff);
g_assert_cmpint (pixelsc[(FRAMEBUFFER_WIDTH - 1) * 3 + 2], ==, 0x00);
g_free (pixelsc);
cogl_handle_unref (tex);
/* Restore the viewport and matrices state */
cogl_set_viewport (saved_viewport[0],
saved_viewport[1],
saved_viewport[2],
saved_viewport[3]);
cogl_set_projection_matrix (&saved_projection);
cogl_pop_matrix ();
/* Comment this out if you want visual feedback of what this test
* paints.
*/
clutter_main_quit ();
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
void
test_cogl_readpixels (TestUtilsGTestFixture *fixture,
void *data)
{
unsigned int idle_source;
ClutterActor *stage;
stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
/* We force continuous redrawing of the stage, since we need to skip
* the first few frames, and we wont be doing anything else that
* will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, stage);
g_signal_connect_after (stage, "paint", G_CALLBACK (on_paint), NULL);
clutter_actor_show (stage);
clutter_main ();
g_source_remove (idle_source);
/* Remove all of the actors from the stage */
clutter_container_foreach (CLUTTER_CONTAINER (stage),
(ClutterCallback) clutter_actor_destroy,
NULL);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,371 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <string.h>
#include "test-conform-common.h"
#define SOURCE_SIZE 32
#define SOURCE_DIVISIONS_X 2
#define SOURCE_DIVISIONS_Y 2
#define DIVISION_WIDTH (SOURCE_SIZE / SOURCE_DIVISIONS_X)
#define DIVISION_HEIGHT (SOURCE_SIZE / SOURCE_DIVISIONS_Y)
#define TEST_INSET 1
static const ClutterColor
corner_colors[SOURCE_DIVISIONS_X * SOURCE_DIVISIONS_Y] =
{
{ 0xff, 0x00, 0x00, 0xff }, /* red top left */
{ 0x00, 0xff, 0x00, 0xff }, /* green top right */
{ 0x00, 0x00, 0xff, 0xff }, /* blue bottom left */
{ 0xff, 0x00, 0xff, 0xff } /* purple bottom right */
};
static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
typedef struct _TestState
{
ClutterActor *stage;
unsigned int frame;
CoglHandle tex;
} TestState;
static CoglHandle
create_source (void)
{
int dx, dy;
guchar *data = g_malloc (SOURCE_SIZE * SOURCE_SIZE * 4);
/* Create a texture with a different coloured rectangle at each
corner */
for (dy = 0; dy < SOURCE_DIVISIONS_Y; dy++)
for (dx = 0; dx < SOURCE_DIVISIONS_X; dx++)
{
guchar *p = (data + dy * DIVISION_HEIGHT * SOURCE_SIZE * 4 +
dx * DIVISION_WIDTH * 4);
int x, y;
for (y = 0; y < DIVISION_HEIGHT; y++)
{
for (x = 0; x < DIVISION_WIDTH; x++)
{
memcpy (p, corner_colors + dx + dy * SOURCE_DIVISIONS_X, 4);
p += 4;
}
p += SOURCE_SIZE * 4 - DIVISION_WIDTH * 4;
}
}
return cogl_texture_new_from_data (SOURCE_SIZE, SOURCE_SIZE,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_RGBA_8888,
COGL_PIXEL_FORMAT_ANY,
SOURCE_SIZE * 4,
data);
}
static CoglHandle
create_test_texture (void)
{
CoglHandle tex;
guint8 *data = g_malloc (256 * 256 * 4), *p = data;
int x, y;
/* Create a texture that is 256x256 where the red component ranges
from 0->255 along the x axis and the green component ranges from
0->255 along the y axis. The blue and alpha components are all
255 */
for (y = 0; y < 256; y++)
for (x = 0; x < 256; x++)
{
*(p++) = x;
*(p++) = y;
*(p++) = 255;
*(p++) = 255;
}
tex = cogl_texture_new_from_data (256, 256, COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
COGL_PIXEL_FORMAT_ANY,
256 * 4,
data);
g_free (data);
return tex;
}
static void
draw_frame (TestState *state)
{
CoglHandle full_texture, sub_texture, sub_sub_texture;
/* Create a sub texture of the bottom right quarter of the texture */
sub_texture = cogl_texture_new_from_sub_texture (state->tex,
DIVISION_WIDTH,
DIVISION_HEIGHT,
DIVISION_WIDTH,
DIVISION_HEIGHT);
/* Paint it */
cogl_set_source_texture (sub_texture);
cogl_rectangle (0.0f, 0.0f, DIVISION_WIDTH, DIVISION_HEIGHT);
cogl_handle_unref (sub_texture);
/* Repeat a sub texture of the top half of the full texture. This is
documented to be undefined so it doesn't technically have to work
but it will with the current implementation */
sub_texture = cogl_texture_new_from_sub_texture (state->tex,
0, 0,
SOURCE_SIZE,
DIVISION_HEIGHT);
cogl_set_source_texture (sub_texture);
cogl_rectangle_with_texture_coords (0.0f, SOURCE_SIZE,
SOURCE_SIZE * 2.0f, SOURCE_SIZE * 1.5f,
0.0f, 0.0f,
2.0f, 1.0f);
cogl_handle_unref (sub_texture);
/* Create a sub texture of a sub texture */
full_texture = create_test_texture ();
sub_texture = cogl_texture_new_from_sub_texture (full_texture,
20, 10, 30, 20);
sub_sub_texture = cogl_texture_new_from_sub_texture (sub_texture,
20, 10, 10, 10);
cogl_set_source_texture (sub_sub_texture);
cogl_rectangle (0.0f, SOURCE_SIZE * 2.0f,
10.0f, SOURCE_SIZE * 2.0f + 10.0f);
cogl_handle_unref (sub_sub_texture);
cogl_handle_unref (sub_texture);
cogl_handle_unref (full_texture);
}
static gboolean
validate_part (TestState *state,
int xpos, int ypos,
int width, int height,
const ClutterColor *color)
{
int x, y;
gboolean pass = TRUE;
guchar *pixels, *p;
p = pixels = clutter_stage_read_pixels (CLUTTER_STAGE (state->stage),
xpos + TEST_INSET,
ypos + TEST_INSET,
width - TEST_INSET - 2,
height - TEST_INSET - 2);
/* Check whether the center of each division is the right color */
for (y = 0; y < height - TEST_INSET - 2; y++)
for (x = 0; x < width - TEST_INSET - 2; x++)
{
if (p[0] != color->red ||
p[1] != color->green ||
p[2] != color->blue)
pass = FALSE;
p += 4;
}
return pass;
}
static guint8 *
create_update_data (void)
{
guint8 *data = g_malloc (256 * 256 * 4), *p = data;
int x, y;
/* Create some image data that is 256x256 where the blue component
ranges from 0->255 along the x axis and the alpha component
ranges from 0->255 along the y axis. The red and green components
are all zero */
for (y = 0; y < 256; y++)
for (x = 0; x < 256; x++)
{
*(p++) = 0;
*(p++) = 0;
*(p++) = x;
*(p++) = y;
}
return data;
}
static void
validate_result (TestState *state)
{
int i, division_num, x, y;
CoglHandle sub_texture, test_tex;
guchar *texture_data, *p;
int tex_width, tex_height;
/* Sub texture of the bottom right corner of the texture */
g_assert (validate_part (state, 0, 0, DIVISION_WIDTH, DIVISION_HEIGHT,
corner_colors +
(SOURCE_DIVISIONS_Y - 1) * SOURCE_DIVISIONS_X +
SOURCE_DIVISIONS_X - 1));
/* Sub texture of the top half repeated horizontally */
for (i = 0; i < 2; i++)
for (division_num = 0; division_num < SOURCE_DIVISIONS_X; division_num++)
g_assert (validate_part (state,
i * SOURCE_SIZE + division_num * DIVISION_WIDTH,
SOURCE_SIZE,
DIVISION_WIDTH, DIVISION_HEIGHT,
corner_colors + division_num));
/* Sub sub texture */
p = texture_data = clutter_stage_read_pixels (CLUTTER_STAGE (state->stage),
0, SOURCE_SIZE * 2, 10, 10);
for (y = 0; y < 10; y++)
for (x = 0; x < 10; x++)
{
g_assert (*(p++) == x + 40);
g_assert (*(p++) == y + 20);
p += 2;
}
g_free (texture_data);
/* Try reading back the texture data */
sub_texture = cogl_texture_new_from_sub_texture (state->tex,
SOURCE_SIZE / 4,
SOURCE_SIZE / 4,
SOURCE_SIZE / 2,
SOURCE_SIZE / 2);
tex_width = cogl_texture_get_width (sub_texture);
tex_height = cogl_texture_get_height (sub_texture);
p = texture_data = g_malloc (tex_width * tex_height * 4);
cogl_texture_get_data (sub_texture, COGL_PIXEL_FORMAT_RGBA_8888,
tex_width * 4,
texture_data);
for (y = 0; y < tex_height; y++)
for (x = 0; x < tex_width; x++)
{
int div_x = ((x * SOURCE_SIZE / 2 / tex_width + SOURCE_SIZE / 4) /
DIVISION_WIDTH);
int div_y = ((y * SOURCE_SIZE / 2 / tex_height + SOURCE_SIZE / 4) /
DIVISION_HEIGHT);
const ClutterColor *color = (corner_colors + div_x +
div_y * SOURCE_DIVISIONS_X);
g_assert (p[0] == color->red);
g_assert (p[1] == color->green);
g_assert (p[2] == color->blue);
p += 4;
}
g_free (texture_data);
cogl_handle_unref (sub_texture);
/* Create a 256x256 test texture */
test_tex = create_test_texture ();
/* Create a sub texture the views the center half of the texture */
sub_texture = cogl_texture_new_from_sub_texture (test_tex,
64, 64, 128, 128);
/* Update the center half of the sub texture */
texture_data = create_update_data ();
cogl_texture_set_region (sub_texture, 0, 0, 32, 32, 64, 64, 256, 256,
COGL_PIXEL_FORMAT_RGBA_8888_PRE, 256 * 4,
texture_data);
g_free (texture_data);
cogl_handle_unref (sub_texture);
/* Get the texture data */
p = texture_data = g_malloc (256 * 256 * 4);
cogl_texture_get_data (test_tex, COGL_PIXEL_FORMAT_RGBA_8888,
256 * 4, texture_data);
/* Verify the texture data */
for (y = 0; y < 256; y++)
for (x = 0; x < 256; x++)
{
/* If we're in the center quarter */
if (x >= 96 && x < 160 && y >= 96 && y < 160)
{
g_assert ((*p++) == 0);
g_assert ((*p++) == 0);
g_assert ((*p++) == x - 96);
g_assert ((*p++) == y - 96);
}
else
{
g_assert ((*p++) == x);
g_assert ((*p++) == y);
g_assert ((*p++) == 255);
g_assert ((*p++) == 255);
}
}
g_free (texture_data);
cogl_handle_unref (test_tex);
/* Comment this out to see what the test paints */
clutter_main_quit ();
}
static void
on_paint (ClutterActor *actor, TestState *state)
{
int frame_num;
draw_frame (state);
/* XXX: validate_result calls clutter_stage_read_pixels which will result in
* another paint run so to avoid infinite recursion we only aim to validate
* the first frame. */
frame_num = state->frame++;
if (frame_num == 1)
validate_result (state);
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
void
test_cogl_sub_texture (TestUtilsGTestFixture *fixture,
void *data)
{
TestState state;
unsigned int idle_source;
unsigned int paint_handler;
state.frame = 0;
state.stage = clutter_stage_get_default ();
state.tex = create_source ();
clutter_stage_set_color (CLUTTER_STAGE (state.stage), &stage_color);
/* We force continuous redrawing of the stage, since we need to skip
* the first few frames, and we wont be doing anything else that
* will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, state.stage);
paint_handler = g_signal_connect_after (state.stage, "paint",
G_CALLBACK (on_paint), &state);
clutter_actor_show_all (state.stage);
clutter_main ();
g_source_remove (idle_source);
g_signal_handler_disconnect (state.stage, paint_handler);
cogl_handle_unref (state.tex);
/* Remove all of the actors from the stage */
clutter_container_foreach (CLUTTER_CONTAINER (state.stage),
(ClutterCallback) clutter_actor_destroy,
NULL);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,230 @@
#include <clutter/clutter.h>
#include <string.h>
#include "test-conform-common.h"
static const ClutterColor stage_color = { 0x0, 0xff, 0x0, 0xff };
#define TEX_WIDTH 4
#define TEX_HEIGHT 8
#define TEX_DEPTH 16
/* Leave four bytes of padding between each row */
#define TEX_ROWSTRIDE (TEX_WIDTH * 4 + 4)
/* Leave four rows of padding between each image */
#define TEX_IMAGE_STRIDE ((TEX_HEIGHT + 4) * TEX_ROWSTRIDE)
static CoglHandle
create_texture_3d (void)
{
int x, y, z;
guint8 *data = g_malloc (TEX_IMAGE_STRIDE * TEX_DEPTH);
guint8 *p = data;
CoglHandle tex;
GError *error = NULL;
for (z = 0; z < TEX_DEPTH; z++)
{
for (y = 0; y < TEX_HEIGHT; y++)
{
for (x = 0; x < TEX_WIDTH; x++)
{
/* Set red, green, blue to values based on x, y, z */
*(p++) = 255 - x * 8;
*(p++) = y * 8;
*(p++) = 255 - z * 8;
/* Fully opaque */
*(p++) = 0xff;
}
/* Set the padding between rows to 0xde */
memset (p, 0xde, TEX_ROWSTRIDE - (TEX_WIDTH * 4));
p += TEX_ROWSTRIDE - (TEX_WIDTH * 4);
}
/* Set the padding between images to 0xad */
memset (p, 0xba, TEX_IMAGE_STRIDE - (TEX_HEIGHT * TEX_ROWSTRIDE));
p += TEX_IMAGE_STRIDE - (TEX_HEIGHT * TEX_ROWSTRIDE);
}
tex = cogl_texture_3d_new_from_data (TEX_WIDTH, TEX_HEIGHT, TEX_DEPTH,
COGL_TEXTURE_NO_AUTO_MIPMAP,
COGL_PIXEL_FORMAT_RGBA_8888,
COGL_PIXEL_FORMAT_ANY,
TEX_ROWSTRIDE,
TEX_IMAGE_STRIDE,
data,
&error);
if (tex == COGL_INVALID_HANDLE)
{
g_assert (error != NULL);
g_warning ("Failed to create 3D texture: %s", error->message);
g_assert_not_reached ();
}
g_free (data);
return tex;
}
static void
draw_frame (void)
{
CoglHandle tex = create_texture_3d ();
CoglHandle material = cogl_material_new ();
typedef struct { float x, y, s, t, r; } Vert;
CoglHandle vbo, indices;
Vert *verts, *v;
int i;
cogl_material_set_layer (material, 0, tex);
cogl_handle_unref (tex);
cogl_material_set_layer_filters (material, 0,
COGL_MATERIAL_FILTER_NEAREST,
COGL_MATERIAL_FILTER_NEAREST);
cogl_set_source (material);
cogl_handle_unref (material);
/* Render the texture repeated horizontally twice using a regular
cogl rectangle. This should end up with the r texture coordinates
as zero */
cogl_rectangle_with_texture_coords (0.0f, 0.0f, TEX_WIDTH * 2, TEX_HEIGHT,
0.0f, 0.0f, 2.0f, 1.0f);
/* Render all of the images in the texture using coordinates from a VBO */
v = verts = g_new (Vert, 4 * TEX_DEPTH);
for (i = 0; i < TEX_DEPTH; i++)
{
float r = (i + 0.5f) / TEX_DEPTH;
v->x = i * TEX_WIDTH;
v->y = TEX_HEIGHT;
v->s = 0;
v->t = 0;
v->r = r;
v++;
v->x = i * TEX_WIDTH;
v->y = TEX_HEIGHT * 2;
v->s = 0;
v->t = 1;
v->r = r;
v++;
v->x = i * TEX_WIDTH + TEX_WIDTH;
v->y = TEX_HEIGHT * 2;
v->s = 1;
v->t = 1;
v->r = r;
v++;
v->x = i * TEX_WIDTH + TEX_WIDTH;
v->y = TEX_HEIGHT;
v->s = 1;
v->t = 0;
v->r = r;
v++;
}
vbo = cogl_vertex_buffer_new (4 * TEX_DEPTH);
cogl_vertex_buffer_add (vbo, "gl_Vertex",
2, COGL_ATTRIBUTE_TYPE_FLOAT, FALSE,
sizeof (Vert),
&verts->x);
cogl_vertex_buffer_add (vbo, "gl_MultiTexCoord0",
3, COGL_ATTRIBUTE_TYPE_FLOAT, FALSE,
sizeof (Vert),
&verts->s);
cogl_vertex_buffer_submit (vbo);
g_free (verts);
indices = cogl_vertex_buffer_indices_get_for_quads (6 * TEX_DEPTH);
cogl_vertex_buffer_draw_elements (vbo,
COGL_VERTICES_MODE_TRIANGLES,
indices,
0, TEX_DEPTH * 4 - 1,
0, TEX_DEPTH * 6);
cogl_handle_unref (vbo);
}
static void
validate_block (int block_x, int block_y, int z)
{
guint8 *data, *p;
int x, y;
p = data = g_malloc (TEX_WIDTH * TEX_HEIGHT * 4);
cogl_read_pixels (block_x * TEX_WIDTH, block_y * TEX_HEIGHT,
TEX_WIDTH, TEX_HEIGHT,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
data);
for (y = 0; y < TEX_HEIGHT; y++)
for (x = 0; x < TEX_WIDTH; x++)
{
g_assert_cmpint (p[0], ==, 255 - x * 8);
g_assert_cmpint (p[1], ==, y * 8);
g_assert_cmpint (p[2], ==, 255 - z * 8);
p += 4;
}
g_free (data);
}
static void
validate_result (void)
{
int i;
validate_block (0, 0, 0);
for (i = 0; i < TEX_DEPTH; i++)
validate_block (i, 1, i);
}
static void
on_paint (void)
{
draw_frame ();
validate_result ();
/* Comment this out to see what the test paints */
clutter_main_quit ();
}
void
test_cogl_texture_3d (TestUtilsGTestFixture *fixture,
void *data)
{
ClutterActor *stage;
unsigned int paint_handler;
stage = clutter_stage_get_default ();
/* Check whether GL supports the rectangle extension. If not we'll
just assume the test passes */
if (cogl_features_available (COGL_FEATURE_TEXTURE_3D))
{
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
paint_handler = g_signal_connect_after (stage, "paint",
G_CALLBACK (on_paint), NULL);
clutter_actor_show (stage);
clutter_main ();
g_signal_handler_disconnect (stage, paint_handler);
if (g_test_verbose ())
g_print ("OK\n");
}
else if (g_test_verbose ())
g_print ("Skipping\n");
}

View File

@ -0,0 +1,166 @@
#include <clutter/clutter.h>
#include <glib.h>
#include <string.h>
#include "test-conform-common.h"
static void
check_texture (int width, int height, CoglTextureFlags flags)
{
CoglHandle tex;
guint8 *data, *p;
int y, x;
p = data = g_malloc (width * height * 4);
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
{
*(p++) = x;
*(p++) = y;
*(p++) = 128;
*(p++) = (x ^ y);
}
tex = cogl_texture_new_from_data (width, height,
flags,
COGL_PIXEL_FORMAT_RGBA_8888,
COGL_PIXEL_FORMAT_RGBA_8888,
width * 4,
data);
/* Replace the bottom right quarter of the data with negated data to
test set_region */
p = data + (height + 1) * width * 2;
for (y = 0; y < height / 2; y++)
{
for (x = 0; x < width / 2; x++)
{
p[0] = ~p[0];
p[1] = ~p[1];
p[2] = ~p[2];
p[3] = ~p[3];
p += 4;
}
p += width * 2;
}
cogl_texture_set_region (tex,
width / 2, /* src_x */
height / 2, /* src_y */
width / 2, /* dst_x */
height / 2, /* dst_y */
width / 2, /* dst_width */
height / 2, /* dst_height */
width,
height,
COGL_PIXEL_FORMAT_RGBA_8888,
width * 4, /* rowstride */
data);
/* Check passing a NULL pointer and a zero rowstride. The texture
should calculate the needed data size and return it */
g_assert_cmpint (cogl_texture_get_data (tex, COGL_PIXEL_FORMAT_ANY, 0, NULL),
==,
width * height * 4);
/* Try first receiving the data as RGB. This should cause a
* conversion */
memset (data, 0, width * height * 4);
cogl_texture_get_data (tex, COGL_PIXEL_FORMAT_RGB_888,
width * 3, data);
p = data;
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
{
if (x >= width / 2 && y >= height / 2)
{
g_assert_cmpint (p[0], ==, ~x & 0xff);
g_assert_cmpint (p[1], ==, ~y & 0xff);
g_assert_cmpint (p[2], ==, ~128 & 0xff);
}
else
{
g_assert_cmpint (p[0], ==, x & 0xff);
g_assert_cmpint (p[1], ==, y & 0xff);
g_assert_cmpint (p[2], ==, 128);
}
p += 3;
}
/* Now try receiving the data as RGBA. This should not cause a
* conversion and no unpremultiplication because we explicitly set
* the internal format when we created the texture */
memset (data, 0, width * height * 4);
cogl_texture_get_data (tex, COGL_PIXEL_FORMAT_RGBA_8888,
width * 4, data);
p = data;
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
{
if (x >= width / 2 && y >= height / 2)
{
g_assert_cmpint (p[0], ==, ~x & 0xff);
g_assert_cmpint (p[1], ==, ~y & 0xff);
g_assert_cmpint (p[2], ==, ~128 & 0xff);
g_assert_cmpint (p[3], ==, ~(x ^ y) & 0xff);
}
else
{
g_assert_cmpint (p[0], ==, x & 0xff);
g_assert_cmpint (p[1], ==, y & 0xff);
g_assert_cmpint (p[2], ==, 128);
g_assert_cmpint (p[3], ==, (x ^ y) & 0xff);
}
p += 4;
}
cogl_handle_unref (tex);
g_free (data);
}
static void
paint_cb (void)
{
/* First try without atlasing */
check_texture (256, 256, COGL_TEXTURE_NO_ATLAS);
/* Try again with atlasing. This should end up testing the atlas
backend and the sub texture backend */
check_texture (256, 256, 0);
/* Try with a really big texture in the hope that it will end up
sliced. */
check_texture (4, 5128, COGL_TEXTURE_NO_ATLAS);
/* And in the other direction. */
check_texture (5128, 4, COGL_TEXTURE_NO_ATLAS);
clutter_main_quit ();
}
void
test_cogl_texture_get_set_data (TestUtilsGTestFixture *fixture,
void *data)
{
ClutterActor *stage;
unsigned int paint_handler;
/* We create a stage even though we don't usually need it so that if
the draw-and-read texture fallback is needed then it will have
something to draw to */
stage = clutter_stage_get_default ();
paint_handler = g_signal_connect_after (stage, "paint",
G_CALLBACK (paint_cb), NULL);
clutter_actor_show (stage);
clutter_main ();
g_signal_handler_disconnect (stage, paint_handler);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,136 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <string.h>
#include "test-conform-common.h"
static const ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff };
#define TEX_SIZE 64
typedef struct _TestState
{
unsigned int padding;
} TestState;
/* Creates a texture where the pixels are evenly divided between
selecting just one of the R,G and B components */
static CoglHandle
make_texture (void)
{
guchar *tex_data = g_malloc (TEX_SIZE * TEX_SIZE * 3), *p = tex_data;
CoglHandle tex;
int x, y;
for (y = 0; y < TEX_SIZE; y++)
for (x = 0; x < TEX_SIZE; x++)
{
memset (p, 0, 3);
/* Set one of the components to full. The components should be
evenly represented so that each gets a third of the
texture */
p[(p - tex_data) / (TEX_SIZE * TEX_SIZE * 3 / 3)] = 255;
p += 3;
}
tex = cogl_texture_new_from_data (TEX_SIZE, TEX_SIZE, COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_RGB_888,
COGL_PIXEL_FORMAT_ANY,
TEX_SIZE * 3,
tex_data);
g_free (tex_data);
return tex;
}
static void
on_paint (ClutterActor *actor, TestState *state)
{
CoglHandle tex;
CoglHandle material;
guint8 pixels[8];
tex = make_texture ();
material = cogl_material_new ();
cogl_material_set_layer (material, 0, tex);
cogl_handle_unref (tex);
/* Render a 1x1 pixel quad without mipmaps */
cogl_set_source (material);
cogl_material_set_layer_filters (material, 0,
COGL_MATERIAL_FILTER_NEAREST,
COGL_MATERIAL_FILTER_NEAREST);
cogl_rectangle (0, 0, 1, 1);
/* Then with mipmaps */
cogl_material_set_layer_filters (material, 0,
COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST,
COGL_MATERIAL_FILTER_NEAREST);
cogl_rectangle (1, 0, 2, 1);
cogl_handle_unref (material);
/* Read back the two pixels we rendered */
cogl_read_pixels (0, 0, 2, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixels);
/* The first pixel should be just one of the colors from the
texture. It doesn't matter which one */
g_assert ((pixels[0] == 255 && pixels[1] == 0 && pixels[2] == 0) ||
(pixels[0] == 0 && pixels[1] == 255 && pixels[2] == 0) ||
(pixels[0] == 0 && pixels[1] == 0 && pixels[2] == 255));
/* The second pixel should be more or less the average of all of the
pixels in the texture. Each component gets a third of the image
so each component should be approximately 255/3 */
g_assert (ABS (pixels[4] - 255 / 3) <= 3 &&
ABS (pixels[5] - 255 / 3) <= 3 &&
ABS (pixels[6] - 255 / 3) <= 3);
/* Comment this out if you want visual feedback for what this test paints */
#if 1
clutter_main_quit ();
#endif
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
void
test_cogl_texture_mipmaps (TestUtilsGTestFixture *fixture,
void *data)
{
TestState state;
ClutterActor *stage;
ClutterActor *group;
unsigned int idle_source;
stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
group = clutter_group_new ();
clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
/* We force continuous redrawing of the stage, since we need to skip
* the first few frames, and we wont be doing anything else that
* will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, stage);
g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
clutter_actor_show_all (stage);
clutter_main ();
g_source_remove (idle_source);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,245 @@
#include <clutter/clutter.h>
#include "test-conform-common.h"
static const ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff };
#ifdef COGL_HAS_XLIB
#include <clutter/x11/clutter-x11.h>
#include <cogl/cogl-texture-pixmap-x11.h>
#define PIXMAP_WIDTH 512
#define PIXMAP_HEIGHT 256
#define GRID_SQUARE_SIZE 16
/* Coordinates of a square that we'll update */
#define PIXMAP_CHANGE_X 1
#define PIXMAP_CHANGE_Y 1
typedef struct _TestState
{
ClutterActor *stage;
CoglHandle tfp;
Pixmap pixmap;
unsigned int frame_count;
Display *display;
} TestState;
static Pixmap
create_pixmap (TestState *state)
{
Pixmap pixmap;
XGCValues gc_values = { 0, };
GC black_gc, white_gc;
int screen = DefaultScreen (state->display);
int x, y;
pixmap = XCreatePixmap (state->display,
DefaultRootWindow (state->display),
PIXMAP_WIDTH, PIXMAP_HEIGHT,
DefaultDepth (state->display, screen));
gc_values.foreground = BlackPixel (state->display, screen);
black_gc = XCreateGC (state->display, pixmap, GCForeground, &gc_values);
gc_values.foreground = WhitePixel (state->display, screen);
white_gc = XCreateGC (state->display, pixmap, GCForeground, &gc_values);
/* Draw a grid of alternative black and white rectangles to the
pixmap */
for (y = 0; y < PIXMAP_HEIGHT / GRID_SQUARE_SIZE; y++)
for (x = 0; x < PIXMAP_WIDTH / GRID_SQUARE_SIZE; x++)
XFillRectangle (state->display, pixmap,
((x ^ y) & 1) ? black_gc : white_gc,
x * GRID_SQUARE_SIZE,
y * GRID_SQUARE_SIZE,
GRID_SQUARE_SIZE,
GRID_SQUARE_SIZE);
XFreeGC (state->display, black_gc);
XFreeGC (state->display, white_gc);
return pixmap;
}
static void
update_pixmap (TestState *state)
{
XGCValues gc_values = { 0, };
GC black_gc;
int screen = DefaultScreen (state->display);
gc_values.foreground = BlackPixel (state->display, screen);
black_gc = XCreateGC (state->display, state->pixmap,
GCForeground, &gc_values);
/* Fill in one the rectangles with black */
XFillRectangle (state->display, state->pixmap,
black_gc,
PIXMAP_CHANGE_X * GRID_SQUARE_SIZE,
PIXMAP_CHANGE_Y * GRID_SQUARE_SIZE,
GRID_SQUARE_SIZE, GRID_SQUARE_SIZE);
XFreeGC (state->display, black_gc);
}
static gboolean
check_paint (TestState *state, int x, int y, int scale)
{
guint8 *data, *p, update_value = 0;
p = data = g_malloc (PIXMAP_WIDTH * PIXMAP_HEIGHT * 4);
cogl_read_pixels (x, y, PIXMAP_WIDTH / scale, PIXMAP_HEIGHT / scale,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
data);
for (y = 0; y < PIXMAP_HEIGHT / scale; y++)
for (x = 0; x < PIXMAP_WIDTH / scale; x++)
{
int grid_x = x * scale / GRID_SQUARE_SIZE;
int grid_y = y * scale / GRID_SQUARE_SIZE;
/* If this is the updatable square then we'll let it be either
color but we'll return which one it was */
if (grid_x == PIXMAP_CHANGE_X && grid_y == PIXMAP_CHANGE_Y)
{
if (x % (GRID_SQUARE_SIZE / scale) == 0 &&
y % (GRID_SQUARE_SIZE / scale) == 0)
update_value = *p;
else
g_assert_cmpint (p[0], ==, update_value);
g_assert (p[1] == update_value);
g_assert (p[2] == update_value);
p += 4;
}
else
{
guint8 value = ((grid_x ^ grid_y) & 1) ? 0x00 : 0xff;
g_assert_cmpint (*(p++), ==, value);
g_assert_cmpint (*(p++), ==, value);
g_assert_cmpint (*(p++), ==, value);
p++;
}
}
g_free (data);
return update_value == 0x00;
}
/* We skip these frames first */
#define FRAME_COUNT_BASE 5
/* First paint the tfp with no mipmaps */
#define FRAME_COUNT_NORMAL 6
/* Then use mipmaps */
#define FRAME_COUNT_MIPMAP 7
/* After this frame will start waiting for the pixmap to change */
#define FRAME_COUNT_UPDATED 8
static void
on_paint (ClutterActor *actor, TestState *state)
{
CoglHandle material;
material = cogl_material_new ();
cogl_material_set_layer (material, 0, state->tfp);
if (state->frame_count == FRAME_COUNT_MIPMAP)
{
const CoglMaterialFilter min_filter =
COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST;
cogl_material_set_layer_filters (material, 0,
min_filter,
COGL_MATERIAL_FILTER_NEAREST);
}
else
cogl_material_set_layer_filters (material, 0,
COGL_MATERIAL_FILTER_NEAREST,
COGL_MATERIAL_FILTER_NEAREST);
cogl_set_source (material);
cogl_rectangle (0, 0, PIXMAP_WIDTH, PIXMAP_HEIGHT);
cogl_rectangle (0, PIXMAP_HEIGHT,
PIXMAP_WIDTH / 4, PIXMAP_HEIGHT * 5 / 4);
if (state->frame_count >= 5)
{
gboolean big_updated, small_updated;
big_updated = check_paint (state, 0, 0, 1);
small_updated = check_paint (state, 0, PIXMAP_HEIGHT, 4);
g_assert (big_updated == small_updated);
if (state->frame_count < FRAME_COUNT_UPDATED)
g_assert (big_updated == FALSE);
else if (state->frame_count == FRAME_COUNT_UPDATED)
/* Change the pixmap and keep drawing until it updates */
update_pixmap (state);
else if (big_updated)
/* If we successfully got the update then the test is over */
clutter_main_quit ();
}
state->frame_count++;
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
#endif /* COGL_HAS_XLIB */
void
test_cogl_texture_pixmap_x11 (TestUtilsGTestFixture *fixture,
void *data)
{
#ifdef COGL_HAS_XLIB
TestState state;
unsigned int idle_handler;
unsigned int paint_handler;
state.frame_count = 0;
state.stage = clutter_stage_get_default ();
state.display = clutter_x11_get_default_display ();
state.pixmap = create_pixmap (&state);
state.tfp = cogl_texture_pixmap_x11_new (state.pixmap, TRUE);
clutter_stage_set_color (CLUTTER_STAGE (state.stage), &stage_color);
paint_handler = g_signal_connect_after (state.stage, "paint",
G_CALLBACK (on_paint), &state);
idle_handler = g_idle_add (queue_redraw, state.stage);
clutter_actor_show_all (state.stage);
clutter_main ();
g_signal_handler_disconnect (state.stage, paint_handler);
g_source_remove (idle_handler);
XFreePixmap (state.display, state.pixmap);
if (g_test_verbose ())
g_print ("OK\n");
#else /* COGL_HAS_XLIB */
if (g_test_verbose ())
g_print ("Skipping\n");
#endif /* COGL_HAS_XLIB */
}

View File

@ -0,0 +1,276 @@
#include <clutter/clutter.h>
#include <string.h>
#include "test-conform-common.h"
static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
typedef struct _TestState
{
ClutterActor *stage;
} TestState;
static CoglHandle
create_source_rect (void)
{
#ifdef GL_TEXTURE_RECTANGLE_ARB
int x, y;
GLint prev_unpack_row_length;
GLint prev_unpack_alignment;
GLint prev_unpack_skip_rows;
GLint prev_unpack_skip_pixles;
GLint prev_rectangle_binding;
guint8 *data = g_malloc (256 * 256 * 4), *p = data;
CoglHandle tex;
GLuint gl_tex;
for (y = 0; y < 256; y++)
for (x = 0; x < 256; x++)
{
*(p++) = x;
*(p++) = y;
*(p++) = 0;
*(p++) = 255;
}
/* We are about to use OpenGL directly to create a TEXTURE_RECTANGLE
* texture so we need to save the state that we modify so we can
* restore it afterwards and be sure not to interfere with any state
* caching that Cogl may do internally.
*/
glGetIntegerv (GL_UNPACK_ROW_LENGTH, &prev_unpack_row_length);
glGetIntegerv (GL_UNPACK_ALIGNMENT, &prev_unpack_alignment);
glGetIntegerv (GL_UNPACK_SKIP_ROWS, &prev_unpack_skip_rows);
glGetIntegerv (GL_UNPACK_SKIP_PIXELS, &prev_unpack_skip_pixles);
glGetIntegerv (GL_TEXTURE_BINDING_RECTANGLE_ARB, &prev_rectangle_binding);
glPixelStorei (GL_UNPACK_ROW_LENGTH, 256);
glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
glGenTextures (1, &gl_tex);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, gl_tex);
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0,
GL_RGBA, 256, 256, 0,
GL_RGBA,
GL_UNSIGNED_BYTE,
data);
/* Now restore the original GL state as Cogl had left it */
glPixelStorei (GL_UNPACK_ROW_LENGTH, prev_unpack_row_length);
glPixelStorei (GL_UNPACK_ALIGNMENT, prev_unpack_alignment);
glPixelStorei (GL_UNPACK_SKIP_ROWS, prev_unpack_skip_rows);
glPixelStorei (GL_UNPACK_SKIP_PIXELS, prev_unpack_skip_pixles);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, prev_rectangle_binding);
g_assert (glGetError () == GL_NO_ERROR);
g_free (data);
tex = cogl_texture_new_from_foreign (gl_tex,
GL_TEXTURE_RECTANGLE_ARB,
256, 256, 0, 0,
COGL_PIXEL_FORMAT_RGBA_8888);
return tex;
#else /* GL_TEXTURE_RECTANGLE_ARB */
return COGL_INVALID_HANDLE;
#endif /* GL_TEXTURE_RECTANGLE_ARB */
}
static CoglHandle
create_source_2d (void)
{
int x, y;
guint8 *data = g_malloc (256 * 256 * 4), *p = data;
CoglHandle tex;
for (y = 0; y < 256; y++)
for (x = 0; x < 256; x++)
{
*(p++) = 0;
*(p++) = x;
*(p++) = y;
*(p++) = 255;
}
tex = cogl_texture_new_from_data (256, 256, COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
COGL_PIXEL_FORMAT_ANY,
256 * 4,
data);
g_free (data);
return tex;
}
static void
draw_frame (TestState *state)
{
GLuint gl_tex;
CoglHandle tex_rect = create_source_rect ();
CoglHandle material_rect = cogl_material_new ();
CoglHandle tex_2d = create_source_2d ();
CoglHandle material_2d = cogl_material_new ();
g_assert (tex_rect != COGL_INVALID_HANDLE);
cogl_material_set_layer (material_rect, 0, tex_rect);
cogl_material_set_layer_filters (material_rect, 0,
COGL_MATERIAL_FILTER_NEAREST,
COGL_MATERIAL_FILTER_NEAREST);
cogl_material_set_layer (material_2d, 0, tex_2d);
cogl_material_set_layer_filters (material_2d, 0,
COGL_MATERIAL_FILTER_NEAREST,
COGL_MATERIAL_FILTER_NEAREST);
cogl_set_source (material_rect);
/* Render the texture repeated horizontally twice */
cogl_rectangle_with_texture_coords (0.0f, 0.0f, 512.0f, 256.0f,
0.0f, 0.0f, 2.0f, 1.0f);
/* Render the top half of the texture to test without repeating */
cogl_rectangle_with_texture_coords (0.0f, 256.0f, 256.0f, 384.0f,
0.0f, 0.0f, 1.0f, 0.5f);
cogl_set_source (material_2d);
/* Render the top half of a regular 2D texture */
cogl_rectangle_with_texture_coords (256.0f, 256.0f, 512.0f, 384.0f,
0.0f, 0.0f, 1.0f, 0.5f);
/* Flush the rendering now so we can safely delete the texture */
cogl_flush ();
cogl_handle_unref (material_rect);
/* Cogl doesn't destroy foreign textures so we have to do it manually */
cogl_texture_get_gl_texture (tex_rect, &gl_tex, NULL);
glDeleteTextures (1, &gl_tex);
cogl_handle_unref (tex_rect);
}
static void
validate_result (TestState *state)
{
guint8 *data, *p;
int x, y;
p = data = g_malloc (512 * 384 * 4);
cogl_read_pixels (0, 0, 512, 384,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888,
data);
for (y = 0; y < 384; y++)
for (x = 0; x < 512; x++)
{
if (x >= 256 && y >= 256)
{
g_assert_cmpint (p[0], ==, 0);
g_assert_cmpint (p[1], ==, x & 0xff);
g_assert_cmpint (p[2], ==, y & 0xff);
}
else
{
g_assert_cmpint (p[0], ==, x & 0xff);
g_assert_cmpint (p[1], ==, y & 0xff);
g_assert_cmpint (p[2], ==, 0);
}
p += 4;
}
g_free (data);
/* Comment this out to see what the test paints */
clutter_main_quit ();
}
static void
on_paint (ClutterActor *actor, TestState *state)
{
draw_frame (state);
validate_result (state);
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
static gboolean
check_rectangle_extension (void)
{
static const char rect_extension[] = "GL_ARB_texture_rectangle";
const char *extensions = (const char *) glGetString (GL_EXTENSIONS);
const char *extensions_end;
extensions_end = extensions + strlen (extensions);
while (extensions < extensions_end)
{
const char *end = strchr (extensions, ' ');
if (end == NULL)
end = extensions_end;
if (end - extensions == sizeof (rect_extension) - 1 &&
!memcmp (extensions, rect_extension, sizeof (rect_extension) - 1))
return TRUE;
extensions = end + 1;
}
return FALSE;
}
void
test_cogl_texture_rectangle (TestUtilsGTestFixture *fixture,
void *data)
{
TestState state;
unsigned int idle_source;
unsigned int paint_handler;
state.stage = clutter_stage_get_default ();
/* Check whether GL supports the rectangle extension. If not we'll
just assume the test passes */
if (check_rectangle_extension ())
{
clutter_stage_set_color (CLUTTER_STAGE (state.stage), &stage_color);
/* We force continuous redrawing of the stage, since we need to skip
* the first few frames, and we wont be doing anything else that
* will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, state.stage);
paint_handler = g_signal_connect_after (state.stage, "paint",
G_CALLBACK (on_paint), &state);
clutter_actor_show_all (state.stage);
clutter_main ();
g_source_remove (idle_source);
g_signal_handler_disconnect (state.stage, paint_handler);
if (g_test_verbose ())
g_print ("OK\n");
}
else if (g_test_verbose ())
g_print ("Skipping\n");
}

View File

@ -0,0 +1,80 @@
#include <cogl/cogl.h>
#include <stdlib.h>
#include "test-utils.h"
#define FB_WIDTH 640
#define FB_HEIGHT 480
void
test_utils_init (TestUtilsGTestFixture *fixture,
const void *data)
{
TestUtilsSharedState *state = (TestUtilsSharedState *)data;
static int counter = 0;
GError *error = NULL;
CoglOnscreen *onscreen = NULL;
if (counter != 0)
g_critical ("We don't support running more than one test at a time\n"
"in a single test run due to the state leakage that can\n"
"cause subsequent tests to fail.\n"
"\n"
"If you want to run all the tests you should run\n"
"$ make test-report");
counter++;
setenv ("COGL_X11_SYNC", "1", 0);
state->ctx = cogl_context_new (NULL, &error);
if (!state->ctx)
g_critical ("Failed to create a CoglContext: %s", error->message);
if (getenv ("COGL_TEST_ONSCREEN"))
{
onscreen = cogl_onscreen_new (state->ctx, 640, 480);
state->fb = COGL_FRAMEBUFFER (onscreen);
}
else
{
CoglHandle offscreen;
CoglHandle tex = cogl_texture_2d_new_with_size (state->ctx,
FB_WIDTH, FB_HEIGHT,
COGL_PIXEL_FORMAT_ANY,
&error);
if (!tex)
g_critical ("Failed to allocate texture: %s", error->message);
offscreen = cogl_offscreen_new_to_texture (tex);
state->fb = COGL_FRAMEBUFFER (offscreen);
}
if (!cogl_framebuffer_allocate (state->fb, &error))
g_critical ("Failed to allocate framebuffer: %s", error->message);
if (onscreen)
cogl_onscreen_show (onscreen);
cogl_framebuffer_clear4f (state->fb,
COGL_BUFFER_BIT_COLOR |
COGL_BUFFER_BIT_DEPTH |
COGL_BUFFER_BIT_STENCIL,
0, 0, 0, 1);
cogl_push_framebuffer (state->fb);
}
void
test_utils_fini (TestUtilsGTestFixture *fixture,
const void *data)
{
const TestUtilsSharedState *state = (TestUtilsSharedState *)data;
cogl_pop_framebuffer ();
if (state->fb)
cogl_object_unref (state->fb);
if (state->ctx)
cogl_object_unref (state->ctx);
}

View File

@ -0,0 +1,41 @@
#ifndef _TEST_UTILS_H_
#define _TEST_UTILS_H_
/* This fixture structure is allocated by glib, and before running
* each test we get a callback to initialize it.
*
* Actually we don't use this currently, we instead manage our own
* TestUtilsSharedState structure which also gets passed as a private
* data argument to the same initialization callback. The advantage of
* allocating our own shared state structure is that we can put data
* in it before we start running anything.
*/
typedef struct _TestUtilsGTestFixture
{
/**/
int dummy;
} TestUtilsGTestFixture;
/* Stuff you put in here is setup once in main() and gets passed around to
* all test functions and fixture setup/teardown functions in the data
* argument */
typedef struct _TestUtilsSharedState
{
int *argc_addr;
char ***argv_addr;
void (* todo_func) (TestUtilsGTestFixture *, void *data);
CoglContext *ctx;
CoglFramebuffer *fb;
} TestUtilsSharedState;
void
test_utils_init (TestUtilsGTestFixture *fixture,
const void *data);
void
test_utils_fini (TestUtilsGTestFixture *fixture,
const void *data);
#endif /* _TEST_UTILS_H_ */

View File

@ -0,0 +1,257 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include "test-conform-common.h"
/* This test verifies that the simplest usage of the vertex buffer API,
* where we add contiguous (x,y) GLfloat vertices, and RGBA GLubyte color
* attributes to a buffer, submit, and draw.
*
* It also tries to verify that the enable/disable attribute APIs are working
* too.
*
* If you want visual feedback of what this test paints for debugging purposes,
* then remove the call to clutter_main_quit() in validate_result.
*/
typedef struct _TestState
{
CoglHandle buffer;
CoglHandle texture;
CoglHandle material;
ClutterGeometry stage_geom;
} TestState;
static void
validate_result (TestState *state)
{
GLubyte pixel[4];
GLint y_off = 90;
if (g_test_verbose ())
g_print ("y_off = %d\n", y_off);
/* NB: We ignore the alpha, since we don't know if our render target is
* RGB or RGBA */
#define RED 0
#define GREEN 1
#define BLUE 2
/* Should see a blue pixel */
cogl_read_pixels (10, y_off, 1, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixel);
if (g_test_verbose ())
g_print ("pixel 0 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]);
g_assert (pixel[RED] == 0 && pixel[GREEN] == 0 && pixel[BLUE] != 0);
/* Should see a red pixel */
cogl_read_pixels (110, y_off, 1, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixel);
if (g_test_verbose ())
g_print ("pixel 1 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]);
g_assert (pixel[RED] != 0 && pixel[GREEN] == 0 && pixel[BLUE] == 0);
/* Should see a blue pixel */
cogl_read_pixels (210, y_off, 1, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixel);
if (g_test_verbose ())
g_print ("pixel 2 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]);
g_assert (pixel[RED] == 0 && pixel[GREEN] == 0 && pixel[BLUE] != 0);
/* Should see a green pixel, at bottom of 4th triangle */
cogl_read_pixels (310, y_off, 1, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixel);
if (g_test_verbose ())
g_print ("pixel 3 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]);
g_assert (pixel[GREEN] > pixel[RED] && pixel[GREEN] > pixel[BLUE]);
/* Should see a red pixel, at top of 4th triangle */
cogl_read_pixels (310, y_off - 70, 1, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixel);
if (g_test_verbose ())
g_print ("pixel 4 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]);
g_assert (pixel[RED] > pixel[GREEN] && pixel[RED] > pixel[BLUE]);
#undef RED
#undef GREEN
#undef BLUE
/* Comment this out if you want visual feedback of what this test
* paints.
*/
clutter_main_quit ();
}
static void
on_paint (ClutterActor *actor, TestState *state)
{
/* Draw a faded blue triangle */
cogl_vertex_buffer_enable (state->buffer, "gl_Color::blue");
cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
cogl_vertex_buffer_draw (state->buffer,
GL_TRIANGLE_STRIP, /* mode */
0, /* first */
3); /* count */
/* Draw a red triangle */
/* Here we are testing that the disable attribute works; if it doesn't
* the triangle will remain faded blue */
cogl_translate (100, 0, 0);
cogl_vertex_buffer_disable (state->buffer, "gl_Color::blue");
cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
cogl_vertex_buffer_draw (state->buffer,
GL_TRIANGLE_STRIP, /* mode */
0, /* first */
3); /* count */
/* Draw a faded blue triangle */
/* Here we are testing that the re-enable works; if it doesn't
* the triangle will remain red */
cogl_translate (100, 0, 0);
cogl_vertex_buffer_enable (state->buffer, "gl_Color::blue");
cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
cogl_vertex_buffer_draw (state->buffer,
GL_TRIANGLE_STRIP, /* mode */
0, /* first */
3); /* count */
/* Draw a textured triangle */
cogl_translate (100, 0, 0);
cogl_vertex_buffer_disable (state->buffer, "gl_Color::blue");
cogl_set_source (state->material);
cogl_material_set_color4ub (state->material, 0xff, 0xff, 0xff, 0xff);
cogl_vertex_buffer_draw (state->buffer,
GL_TRIANGLE_STRIP, /* mode */
0, /* first */
3); /* count */
validate_result (state);
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
void
test_cogl_vertex_buffer_contiguous (TestUtilsGTestFixture *fixture,
void *data)
{
TestState state;
ClutterActor *stage;
ClutterColor stage_clr = {0x0, 0x0, 0x0, 0xff};
ClutterActor *group;
unsigned int idle_source;
guchar tex_data[] = {
0xff, 0x00, 0x00, 0xff,
0xff, 0x00, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff
};
stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_clr);
clutter_actor_get_geometry (stage, &state.stage_geom);
group = clutter_group_new ();
clutter_actor_set_size (group,
state.stage_geom.width,
state.stage_geom.height);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
/* We force continuous redrawing incase someone comments out the
* clutter_main_quit and wants visual feedback for the test since we
* wont be doing anything else that will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, stage);
g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
state.texture = cogl_texture_new_from_data (2, 2,
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_RGBA_8888,
COGL_PIXEL_FORMAT_ANY,
0, /* auto calc row stride */
tex_data);
state.material = cogl_material_new ();
cogl_material_set_color4ub (state.material, 0x00, 0xff, 0x00, 0xff);
cogl_material_set_layer (state.material, 0, state.texture);
{
GLfloat triangle_verts[3][2] =
{
{0.0, 0.0},
{100.0, 100.0},
{0.0, 100.0}
};
GLbyte triangle_colors[3][4] =
{
{0x00, 0x00, 0xff, 0xff}, /* blue */
{0x00, 0x00, 0xff, 0x00}, /* transparent blue */
{0x00, 0x00, 0xff, 0x00} /* transparent blue */
};
GLfloat triangle_tex_coords[3][2] =
{
{0.0, 0.0},
{1.0, 1.0},
{0.0, 1.0}
};
state.buffer = cogl_vertex_buffer_new (3 /* n vertices */);
cogl_vertex_buffer_add (state.buffer,
"gl_Vertex",
2, /* n components */
GL_FLOAT,
FALSE, /* normalized */
0, /* stride */
triangle_verts);
cogl_vertex_buffer_add (state.buffer,
"gl_Color::blue",
4, /* n components */
GL_UNSIGNED_BYTE,
FALSE, /* normalized */
0, /* stride */
triangle_colors);
cogl_vertex_buffer_add (state.buffer,
"gl_MultiTexCoord0",
2, /* n components */
GL_FLOAT,
FALSE, /* normalized */
0, /* stride */
triangle_tex_coords);
cogl_vertex_buffer_submit (state.buffer);
}
clutter_actor_show_all (stage);
clutter_main ();
cogl_handle_unref (state.buffer);
cogl_handle_unref (state.material);
cogl_handle_unref (state.texture);
g_source_remove (idle_source);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,162 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include "test-conform-common.h"
/* This test verifies that interleved attributes work with the vertex buffer
* API. We add (x,y) GLfloat vertices, interleved with RGBA GLubyte color
* attributes to a buffer, submit and draw.
*
* If you want visual feedback of what this test paints for debugging purposes,
* then remove the call to clutter_main_quit() in validate_result.
*/
typedef struct _TestState
{
CoglHandle buffer;
ClutterGeometry stage_geom;
} TestState;
typedef struct _InterlevedVertex
{
GLfloat x;
GLfloat y;
GLubyte r;
GLubyte g;
GLubyte b;
GLubyte a;
} InterlevedVertex;
static void
validate_result (TestState *state)
{
GLubyte pixel[4];
GLint y_off = 90;
/* NB: We ignore the alpha, since we don't know if our render target is
* RGB or RGBA */
#define RED 0
#define GREEN 1
#define BLUE 2
/* Should see a blue pixel */
cogl_read_pixels (10, y_off, 1, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixel);
if (g_test_verbose ())
g_print ("pixel 0 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]);
g_assert (pixel[RED] == 0 && pixel[GREEN] == 0 && pixel[BLUE] != 0);
#undef RED
#undef GREEN
#undef BLUE
/* Comment this out if you want visual feedback of what this test
* paints.
*/
clutter_main_quit ();
}
static void
on_paint (ClutterActor *actor, TestState *state)
{
/* Draw a faded blue triangle */
cogl_vertex_buffer_draw (state->buffer,
GL_TRIANGLE_STRIP, /* mode */
0, /* first */
3); /* count */
validate_result (state);
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
void
test_cogl_vertex_buffer_interleved (TestUtilsGTestFixture *fixture,
void *data)
{
TestState state;
ClutterActor *stage;
ClutterColor stage_clr = {0x0, 0x0, 0x0, 0xff};
ClutterActor *group;
unsigned int idle_source;
stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_clr);
clutter_actor_get_geometry (stage, &state.stage_geom);
group = clutter_group_new ();
clutter_actor_set_size (group,
state.stage_geom.width,
state.stage_geom.height);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
/* We force continuous redrawing incase someone comments out the
* clutter_main_quit and wants visual feedback for the test since we
* wont be doing anything else that will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, stage);
g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
{
InterlevedVertex verts[3] =
{
{ /* .x = */ 0.0, /* .y = */ 0.0,
/* blue */
/* .r = */ 0x00, /* .g = */ 0x00, /* .b = */ 0xff, /* .a = */ 0xff },
{ /* .x = */ 100.0, /* .y = */ 100.0,
/* transparent blue */
/* .r = */ 0x00, /* .g = */ 0x00, /* .b = */ 0xff, /* .a = */ 0x00 },
{ /* .x = */ 0.0, /* .y = */ 100.0,
/* transparent blue */
/* .r = */ 0x00, /* .g = */ 0x00, /* .b = */ 0xff, /* .a = */ 0x00 },
};
/* We assume the compiler is doing no funny struct padding for this test:
*/
g_assert (sizeof (InterlevedVertex) == 12);
state.buffer = cogl_vertex_buffer_new (3 /* n vertices */);
cogl_vertex_buffer_add (state.buffer,
"gl_Vertex",
2, /* n components */
GL_FLOAT,
FALSE, /* normalized */
12, /* stride */
&verts[0].x);
cogl_vertex_buffer_add (state.buffer,
"gl_Color",
4, /* n components */
GL_UNSIGNED_BYTE,
FALSE, /* normalized */
12, /* stride */
&verts[0].r);
cogl_vertex_buffer_submit (state.buffer);
}
clutter_actor_show_all (stage);
clutter_main ();
cogl_handle_unref (state.buffer);
g_source_remove (idle_source);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,198 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include "test-conform-common.h"
/* This test verifies that modifying a vertex buffer works, by updating
* vertex positions, and deleting and re-adding different color attributes.
*
* If you want visual feedback of what this test paints for debugging purposes,
* then remove the call to clutter_main_quit() in validate_result.
*/
typedef struct _TestState
{
CoglHandle buffer;
ClutterGeometry stage_geom;
} TestState;
static void
validate_result (TestState *state)
{
GLubyte pixel[4];
GLint y_off = 90;
/* NB: We ignore the alpha, since we don't know if our render target is
* RGB or RGBA */
#define RED 0
#define GREEN 1
#define BLUE 2
/* Should see a red pixel */
cogl_read_pixels (110, y_off, 1, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixel);
if (g_test_verbose ())
g_print ("pixel 0 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]);
g_assert (pixel[RED] != 0 && pixel[GREEN] == 0 && pixel[BLUE] == 0);
/* Should see a green pixel */
cogl_read_pixels (210, y_off, 1, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixel);
if (g_test_verbose ())
g_print ("pixel 1 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]);
g_assert (pixel[RED] == 0 && pixel[GREEN] != 0 && pixel[BLUE] == 0);
#undef RED
#undef GREEN
#undef BLUE
/* Comment this out if you want visual feedback of what this test
* paints.
*/
clutter_main_quit ();
}
static void
on_paint (ClutterActor *actor, TestState *state)
{
GLfloat triangle_verts[3][2] =
{
{100.0, 0.0},
{200.0, 100.0},
{100.0, 100.0}
};
GLbyte triangle_colors[3][4] =
{
{0x00, 0xff, 0x00, 0xff}, /* blue */
{0x00, 0xff, 0x00, 0x00}, /* transparent blue */
{0x00, 0xff, 0x00, 0x00} /* transparent blue */
};
/*
* Draw a red triangle
*/
cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
cogl_vertex_buffer_add (state->buffer,
"gl_Vertex",
2, /* n components */
GL_FLOAT,
FALSE, /* normalized */
0, /* stride */
triangle_verts);
cogl_vertex_buffer_delete (state->buffer, "gl_Color");
cogl_vertex_buffer_submit (state->buffer);
cogl_vertex_buffer_draw (state->buffer,
GL_TRIANGLE_STRIP, /* mode */
0, /* first */
3); /* count */
/*
* Draw a faded green triangle
*/
cogl_vertex_buffer_add (state->buffer,
"gl_Color",
4, /* n components */
GL_UNSIGNED_BYTE,
FALSE, /* normalized */
0, /* stride */
triangle_colors);
cogl_vertex_buffer_submit (state->buffer);
cogl_translate (100, 0, 0);
cogl_vertex_buffer_draw (state->buffer,
GL_TRIANGLE_STRIP, /* mode */
0, /* first */
3); /* count */
validate_result (state);
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
void
test_cogl_vertex_buffer_mutability (TestUtilsGTestFixture *fixture,
void *data)
{
TestState state;
ClutterActor *stage;
ClutterColor stage_clr = {0x0, 0x0, 0x0, 0xff};
ClutterActor *group;
unsigned int idle_source;
stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_clr);
clutter_actor_get_geometry (stage, &state.stage_geom);
group = clutter_group_new ();
clutter_actor_set_size (group,
state.stage_geom.width,
state.stage_geom.height);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
/* We force continuous redrawing incase someone comments out the
* clutter_main_quit and wants visual feedback for the test since we
* wont be doing anything else that will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, stage);
g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
{
GLfloat triangle_verts[3][2] =
{
{0.0, 0.0},
{100.0, 100.0},
{0.0, 100.0}
};
GLbyte triangle_colors[3][4] =
{
{0x00, 0x00, 0xff, 0xff}, /* blue */
{0x00, 0x00, 0xff, 0x00}, /* transparent blue */
{0x00, 0x00, 0xff, 0x00} /* transparent blue */
};
state.buffer = cogl_vertex_buffer_new (3 /* n vertices */);
cogl_vertex_buffer_add (state.buffer,
"gl_Vertex",
2, /* n components */
GL_FLOAT,
FALSE, /* normalized */
0, /* stride */
triangle_verts);
cogl_vertex_buffer_add (state.buffer,
"gl_Color",
4, /* n components */
GL_UNSIGNED_BYTE,
FALSE, /* normalized */
0, /* stride */
triangle_colors);
cogl_vertex_buffer_submit (state.buffer);
}
clutter_actor_show_all (stage);
clutter_main ();
cogl_handle_unref (state.buffer);
g_source_remove (idle_source);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,416 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include "test-conform-common.h"
#define RED 0
#define GREEN 1
#define BLUE 2
#define ALPHA 3
#define FRAMEBUFFER_WIDTH 640
#define FRAMEBUFFER_HEIGHT 480
static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
static void
assert_region_color (int x,
int y,
int width,
int height,
guint8 red,
guint8 green,
guint8 blue,
guint8 alpha)
{
guint8 *data = g_malloc0 (width * height * 4);
cogl_read_pixels (x, y, width, height,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
data);
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
{
guint8 *pixel = &data[y*width*4 + x*4];
#if 1
g_assert (pixel[RED] == red &&
pixel[GREEN] == green &&
pixel[BLUE] == blue &&
pixel[ALPHA] == alpha);
#endif
}
g_free (data);
}
static void
assert_rectangle_color_and_black_border (int x,
int y,
int width,
int height,
guint8 red,
guint8 green,
guint8 blue)
{
/* check the rectangle itself... */
assert_region_color (x, y, width, height, red, green, blue, 0xff);
/* black to left of the rectangle */
assert_region_color (x-10, y-10, 10, height+20, 0x00, 0x00, 0x00, 0xff);
/* black to right of the rectangle */
assert_region_color (x+width, y-10, 10, height+20, 0x00, 0x00, 0x00, 0xff);
/* black above the rectangle */
assert_region_color (x-10, y-10, width+20, 10, 0x00, 0x00, 0x00, 0xff);
/* and black below the rectangle */
assert_region_color (x-10, y+height, width+20, 10, 0x00, 0x00, 0x00, 0xff);
}
static void
on_paint (ClutterActor *actor, void *state)
{
float saved_viewport[4];
CoglMatrix saved_projection;
CoglMatrix projection;
CoglMatrix modelview;
guchar *data;
CoglHandle tex;
CoglHandle offscreen;
CoglColor black;
float x0;
float y0;
float width;
float height;
/* for clearing the offscreen framebuffer to black... */
cogl_color_init_from_4ub (&black, 0x00, 0x00, 0x00, 0xff);
cogl_get_viewport (saved_viewport);
cogl_get_projection_matrix (&saved_projection);
cogl_push_matrix ();
cogl_matrix_init_identity (&projection);
cogl_matrix_init_identity (&modelview);
cogl_set_projection_matrix (&projection);
cogl_set_modelview_matrix (&modelview);
/* - Create a 100x200 viewport (i.e. smaller than the onscreen framebuffer)
* and position it a (20, 10) inside the framebuffer.
* - Fill the whole viewport with a purple rectangle
* - Verify that the framebuffer is black with a 100x200 purple rectangle at
* (20, 10)
*/
cogl_set_viewport (20, /* x */
10, /* y */
100, /* width */
200); /* height */
/* clear everything... */
cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
/* fill the viewport with purple.. */
cogl_set_source_color4ub (0xff, 0x00, 0xff, 0xff);
cogl_rectangle (-1, 1, 1, -1);
assert_rectangle_color_and_black_border (20, 10, 100, 200,
0xff, 0x00, 0xff);
/* - Create a viewport twice the size of the onscreen framebuffer with
* a negative offset positioning it at (-20, -10) relative to the
* buffer itself.
* - Draw a 100x200 green rectangle at (40, 20) within the viewport (which
* is (20, 10) within the framebuffer)
* - Verify that the framebuffer is black with a 100x200 green rectangle at
* (20, 10)
*/
cogl_set_viewport (-20, /* x */
-10, /* y */
FRAMEBUFFER_WIDTH * 2, /* width */
FRAMEBUFFER_HEIGHT * 2); /* height */
/* clear everything... */
cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
/* draw a 100x200 green rectangle offset into the viewport such that its
* top left corner should be found at (20, 10) in the offscreen buffer */
/* (offset 40 pixels right from the left of the viewport) */
x0 = -1.0f + (1.0f / FRAMEBUFFER_WIDTH) * 40.f;
/* (offset 20 pixels down from the top of the viewport) */
y0 = 1.0f - (1.0f / FRAMEBUFFER_HEIGHT) * 20.0f;
width = (1.0f / FRAMEBUFFER_WIDTH) * 100;
height = (1.0f / FRAMEBUFFER_HEIGHT) * 200;
cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff);
cogl_rectangle (x0, y0, x0 + width, y0 - height);
assert_rectangle_color_and_black_border (20, 10, 100, 200,
0x00, 0xff, 0x00);
/* - Create a 200x400 viewport and position it a (20, 10) inside the draw
* buffer.
* - Push a 100x200 window space clip rectangle at (20, 10)
* - Fill the whole viewport with a blue rectangle
* - Verify that the framebuffer is black with a 100x200 blue rectangle at
* (20, 10)
*/
cogl_set_viewport (20, /* x */
10, /* y */
200, /* width */
400); /* height */
/* clear everything... */
cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
cogl_clip_push_window_rectangle (20, 10, 100, 200);
/* fill the viewport with blue.. */
cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff);
cogl_rectangle (-1, 1, 1, -1);
cogl_clip_pop ();
assert_rectangle_color_and_black_border (20, 10, 100, 200,
0x00, 0x00, 0xff);
/* - Create a 200x400 viewport and position it a (20, 10) inside the draw
* buffer.
* - Push a 100x200 model space clip rectangle at (20, 10) in the viewport
* (i.e. (40, 20) inside the framebuffer)
* - Fill the whole viewport with a green rectangle
* - Verify that the framebuffer is black with a 100x200 green rectangle at
* (40, 20)
*/
cogl_set_viewport (20, /* x */
10, /* y */
200, /* width */
400); /* height */
/* clear everything... */
cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
/* figure out where to position our clip rectangle in model space
* coordinates... */
/* (offset 40 pixels right from the left of the viewport) */
x0 = -1.0f + (2.0f / 200) * 20.f;
/* (offset 20 pixels down from the top of the viewport) */
y0 = 1.0f - (2.0f / 400) * 10.0f;
width = (2.0f / 200) * 100;
height = (2.0f / 400) * 200;
/* add the clip rectangle... */
cogl_push_matrix ();
cogl_translate (x0 + (width/2.0), y0 - (height/2.0), 0);
/* XXX: Rotate just enough to stop Cogl from converting our model space
* rectangle into a window space rectangle.. */
cogl_rotate (0.1, 0, 0, 1);
cogl_clip_push_rectangle (-(width/2.0), -(height/2.0),
width/2.0, height/2.0);
cogl_pop_matrix ();
/* fill the viewport with green.. */
cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff);
cogl_rectangle (-1, 1, 1, -1);
cogl_clip_pop ();
assert_rectangle_color_and_black_border (40, 20, 100, 200,
0x00, 0xff, 0x00);
/* Set the viewport to something specific so we can verify that it gets
* restored after we are done testing with an offscreen framebuffer... */
cogl_set_viewport (20, 10, 100, 200);
/*
* Next test offscreen drawing...
*/
data = g_malloc (FRAMEBUFFER_WIDTH * 4 * FRAMEBUFFER_HEIGHT);
tex = cogl_texture_new_from_data (FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT,
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_RGBA_8888, /* data fmt */
COGL_PIXEL_FORMAT_ANY, /* internal fmt */
FRAMEBUFFER_WIDTH * 4, /* rowstride */
data);
g_free (data);
offscreen = cogl_offscreen_new_to_texture (tex);
cogl_push_framebuffer (offscreen);
/* - Create a 100x200 viewport (i.e. smaller than the offscreen framebuffer)
* and position it a (20, 10) inside the framebuffer.
* - Fill the whole viewport with a blue rectangle
* - Verify that the framebuffer is black with a 100x200 blue rectangle at
* (20, 10)
*/
cogl_set_viewport (20, /* x */
10, /* y */
100, /* width */
200); /* height */
/* clear everything... */
cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
/* fill the viewport with blue.. */
cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff);
cogl_rectangle (-1, 1, 1, -1);
assert_rectangle_color_and_black_border (20, 10, 100, 200,
0x00, 0x00, 0xff);
/* - Create a viewport twice the size of the offscreen framebuffer with
* a negative offset positioning it at (-20, -10) relative to the
* buffer itself.
* - Draw a 100x200 red rectangle at (40, 20) within the viewport (which
* is (20, 10) within the framebuffer)
* - Verify that the framebuffer is black with a 100x200 red rectangle at
* (20, 10)
*/
cogl_set_viewport (-20, /* x */
-10, /* y */
FRAMEBUFFER_WIDTH * 2, /* width */
FRAMEBUFFER_HEIGHT * 2); /* height */
/* clear everything... */
cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
/* draw a 100x200 red rectangle offset into the viewport such that its
* top left corner should be found at (20, 10) in the offscreen buffer */
/* (offset 40 pixels right from the left of the viewport) */
x0 = -1.0f + (1.0f / FRAMEBUFFER_WIDTH) * 40.f;
/* (offset 20 pixels down from the top of the viewport) */
y0 = 1.0f - (1.0f / FRAMEBUFFER_HEIGHT) * 20.0f;
width = (1.0f / FRAMEBUFFER_WIDTH) * 100;
height = (1.0f / FRAMEBUFFER_HEIGHT) * 200;
cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
cogl_rectangle (x0, y0, x0 + width, y0 - height);
assert_rectangle_color_and_black_border (20, 10, 100, 200,
0xff, 0x00, 0x00);
/* - Create a 200x400 viewport and position it a (20, 10) inside the draw
* buffer.
* - Push a 100x200 window space clip rectangle at (20, 10)
* - Fill the whole viewport with a blue rectangle
* - Verify that the framebuffer is black with a 100x200 blue rectangle at
* (20, 10)
*/
cogl_set_viewport (20, /* x */
10, /* y */
200, /* width */
400); /* height */
/* clear everything... */
cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
cogl_clip_push_window_rectangle (20, 10, 100, 200);
/* fill the viewport with blue.. */
cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff);
cogl_rectangle (-1, 1, 1, -1);
cogl_clip_pop ();
assert_rectangle_color_and_black_border (20, 10, 100, 200,
0x00, 0x00, 0xff);
/* - Create a 200x400 viewport and position it a (20, 10) inside the draw
* buffer.
* - Push a 100x200 model space clip rectangle at (20, 10) in the viewport
* (i.e. (40, 20) inside the framebuffer)
* - Fill the whole viewport with a green rectangle
* - Verify that the framebuffer is black with a 100x200 green rectangle at
* (40, 20)
*/
cogl_set_viewport (20, /* x */
10, /* y */
200, /* width */
400); /* height */
/* clear everything... */
cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
/* figure out where to position our clip rectangle in model space
* coordinates... */
/* (offset 40 pixels right from the left of the viewport) */
x0 = -1.0f + (2.0f / 200) * 20.f;
/* (offset 20 pixels down from the top of the viewport) */
y0 = 1.0f - (2.0f / 400) * 10.0f;
width = (2.0f / 200) * 100;
height = (2.0f / 400) * 200;
/* add the clip rectangle... */
cogl_push_matrix ();
cogl_translate (x0 + (width/2.0), y0 - (height/2.0), 0);
/* XXX: Rotate just enough to stop Cogl from converting our model space
* rectangle into a window space rectangle.. */
cogl_rotate (0.1, 0, 0, 1);
cogl_clip_push_rectangle (-(width/2.0), -(height/2.0),
width/2, height/2);
cogl_pop_matrix ();
/* fill the viewport with green.. */
cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff);
cogl_rectangle (-1, 1, 1, -1);
cogl_clip_pop ();
assert_rectangle_color_and_black_border (40, 20, 100, 200,
0x00, 0xff, 0x00);
/* Set the viewport to something obscure to verify that it gets
* replace when we switch back to the onscreen framebuffer... */
cogl_set_viewport (0, 0, 10, 10);
cogl_pop_framebuffer ();
cogl_handle_unref (offscreen);
/*
* Verify that the previous onscreen framebuffer's viewport was restored
* by drawing a white rectangle across the whole viewport. This should
* draw a 100x200 rectangle at (20,10) relative to the onscreen draw
* buffer...
*/
cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
cogl_set_source_color4ub (0xff, 0xff, 0xff, 0xff);
cogl_rectangle (-1, 1, 1, -1);
assert_rectangle_color_and_black_border (20, 10, 100, 200,
0xff, 0xff, 0xff);
/* Uncomment to display the last contents of the offscreen framebuffer */
#if 1
cogl_matrix_init_identity (&projection);
cogl_matrix_init_identity (&modelview);
cogl_set_viewport (0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT);
cogl_set_projection_matrix (&projection);
cogl_set_modelview_matrix (&modelview);
cogl_set_source_texture (tex);
cogl_rectangle (-1, 1, 1, -1);
#endif
cogl_handle_unref (tex);
/* Finally restore the stage's original state... */
cogl_pop_matrix ();
cogl_set_projection_matrix (&saved_projection);
cogl_set_viewport (saved_viewport[0], saved_viewport[1],
saved_viewport[2], saved_viewport[3]);
/* Comment this out if you want visual feedback of what this test
* paints.
*/
clutter_main_quit ();
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
void
test_cogl_viewport (TestUtilsGTestFixture *fixture,
void *data)
{
unsigned int idle_source;
ClutterActor *stage;
stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
/* We force continuous redrawing of the stage, since we need to skip
* the first few frames, and we wont be doing anything else that
* will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, stage);
g_signal_connect_after (stage, "paint", G_CALLBACK (on_paint), NULL);
clutter_actor_show (stage);
clutter_main ();
g_source_remove (idle_source);
/* Remove all of the actors from the stage */
clutter_container_foreach (CLUTTER_CONTAINER (stage),
(ClutterCallback) clutter_actor_destroy,
NULL);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -0,0 +1,317 @@
#include <clutter/clutter.h>
#include <string.h>
#include "test-conform-common.h"
#define TEX_SIZE 4
static const ClutterColor stage_color = { 0x80, 0x80, 0x80, 0xff };
typedef struct _TestState
{
ClutterActor *stage;
CoglHandle texture;
} TestState;
static CoglHandle
create_texture (CoglTextureFlags flags)
{
guint8 *data = g_malloc (TEX_SIZE * TEX_SIZE * 4), *p = data;
CoglHandle tex;
int x, y;
for (y = 0; y < TEX_SIZE; y++)
for (x = 0; x < TEX_SIZE; x++)
{
*(p++) = 0;
*(p++) = (x & 1) * 255;
*(p++) = (y & 1) * 255;
*(p++) = 255;
}
tex = cogl_texture_new_from_data (TEX_SIZE, TEX_SIZE, flags,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
COGL_PIXEL_FORMAT_ANY,
TEX_SIZE * 4,
data);
g_free (data);
return tex;
}
static CoglHandle
create_material (TestState *state,
CoglMaterialWrapMode wrap_mode_s,
CoglMaterialWrapMode wrap_mode_t)
{
CoglHandle material;
material = cogl_material_new ();
cogl_material_set_layer (material, 0, state->texture);
cogl_material_set_layer_filters (material, 0,
COGL_MATERIAL_FILTER_NEAREST,
COGL_MATERIAL_FILTER_NEAREST);
cogl_material_set_layer_wrap_mode_s (material, 0, wrap_mode_s);
cogl_material_set_layer_wrap_mode_t (material, 0, wrap_mode_t);
return material;
}
static CoglMaterialWrapMode
test_wrap_modes[] =
{
COGL_MATERIAL_WRAP_MODE_REPEAT,
COGL_MATERIAL_WRAP_MODE_REPEAT,
COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE,
COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE,
COGL_MATERIAL_WRAP_MODE_REPEAT,
COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE,
COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE,
COGL_MATERIAL_WRAP_MODE_REPEAT,
COGL_MATERIAL_WRAP_MODE_AUTOMATIC,
COGL_MATERIAL_WRAP_MODE_AUTOMATIC,
COGL_MATERIAL_WRAP_MODE_AUTOMATIC,
COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE
};
static void
draw_tests (TestState *state)
{
int i;
for (i = 0; i < G_N_ELEMENTS (test_wrap_modes); i += 2)
{
CoglMaterialWrapMode wrap_mode_s, wrap_mode_t;
CoglHandle material;
/* Create a separate material for each pair of wrap modes so
that we can verify whether the batch splitting works */
wrap_mode_s = test_wrap_modes[i];
wrap_mode_t = test_wrap_modes[i + 1];
material = create_material (state, wrap_mode_s, wrap_mode_t);
cogl_set_source (material);
cogl_handle_unref (material);
/* Render the material at four times the size of the texture */
cogl_rectangle_with_texture_coords (i * TEX_SIZE, 0,
(i + 2) * TEX_SIZE, TEX_SIZE * 2,
0, 0, 2, 2);
}
}
static const CoglTextureVertex vertices[4] =
{
{ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, TEX_SIZE * 2, 0.0f, 0.0f, 2.0f },
{ TEX_SIZE * 2, TEX_SIZE * 2, 0.0f, 2.0f, 2.0f },
{ TEX_SIZE * 2, 0.0f, 0.0f, 2.0f, 0.0f }
};
static void
draw_tests_polygon (TestState *state)
{
int i;
for (i = 0; i < G_N_ELEMENTS (test_wrap_modes); i += 2)
{
CoglMaterialWrapMode wrap_mode_s, wrap_mode_t;
CoglHandle material;
wrap_mode_s = test_wrap_modes[i];
wrap_mode_t = test_wrap_modes[i + 1];
material = create_material (state, wrap_mode_s, wrap_mode_t);
cogl_set_source (material);
cogl_handle_unref (material);
cogl_push_matrix ();
cogl_translate (TEX_SIZE * i, 0.0f, 0.0f);
/* Render the material at four times the size of the texture */
cogl_polygon (vertices, G_N_ELEMENTS (vertices), FALSE);
cogl_pop_matrix ();
}
}
static void
draw_tests_vbo (TestState *state)
{
CoglHandle vbo;
int i;
vbo = cogl_vertex_buffer_new (4);
cogl_vertex_buffer_add (vbo, "gl_Vertex", 3,
COGL_ATTRIBUTE_TYPE_FLOAT, FALSE,
sizeof (vertices[0]),
&vertices[0].x);
cogl_vertex_buffer_add (vbo, "gl_MultiTexCoord0", 2,
COGL_ATTRIBUTE_TYPE_FLOAT, FALSE,
sizeof (vertices[0]),
&vertices[0].tx);
cogl_vertex_buffer_submit (vbo);
for (i = 0; i < G_N_ELEMENTS (test_wrap_modes); i += 2)
{
CoglMaterialWrapMode wrap_mode_s, wrap_mode_t;
CoglHandle material;
wrap_mode_s = test_wrap_modes[i];
wrap_mode_t = test_wrap_modes[i + 1];
material = create_material (state, wrap_mode_s, wrap_mode_t);
cogl_set_source (material);
cogl_handle_unref (material);
cogl_push_matrix ();
cogl_translate (TEX_SIZE * i, 0.0f, 0.0f);
/* Render the material at four times the size of the texture */
cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_TRIANGLE_FAN, 0, 4);
cogl_pop_matrix ();
}
cogl_handle_unref (vbo);
}
static void
draw_frame (TestState *state)
{
/* Draw the tests first with a non atlased texture */
state->texture = create_texture (COGL_TEXTURE_NO_ATLAS);
draw_tests (state);
cogl_handle_unref (state->texture);
/* Draw the tests again with a possible atlased texture. This should
end up testing software repeats */
state->texture = create_texture (COGL_TEXTURE_NONE);
cogl_push_matrix ();
cogl_translate (0.0f, TEX_SIZE * 2.0f, 0.0f);
draw_tests (state);
cogl_pop_matrix ();
cogl_handle_unref (state->texture);
/* Draw the tests using cogl_polygon */
state->texture = create_texture (COGL_TEXTURE_NO_ATLAS);
cogl_push_matrix ();
cogl_translate (0.0f, TEX_SIZE * 4.0f, 0.0f);
draw_tests_polygon (state);
cogl_pop_matrix ();
cogl_handle_unref (state->texture);
/* Draw the tests using a vertex buffer */
state->texture = create_texture (COGL_TEXTURE_NO_ATLAS);
cogl_push_matrix ();
cogl_translate (0.0f, TEX_SIZE * 6.0f, 0.0f);
draw_tests_vbo (state);
cogl_pop_matrix ();
cogl_handle_unref (state->texture);
}
static void
validate_set (TestState *state, int offset)
{
guint8 data[TEX_SIZE * 2 * TEX_SIZE * 2 * 4], *p;
int x, y, i;
for (i = 0; i < G_N_ELEMENTS (test_wrap_modes); i += 2)
{
CoglMaterialWrapMode wrap_mode_s, wrap_mode_t;
wrap_mode_s = test_wrap_modes[i];
wrap_mode_t = test_wrap_modes[i + 1];
cogl_read_pixels (i * TEX_SIZE, offset * TEX_SIZE * 2,
TEX_SIZE * 2, TEX_SIZE * 2,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888,
data);
p = data;
for (y = 0; y < TEX_SIZE * 2; y++)
for (x = 0; x < TEX_SIZE * 2; x++)
{
guint8 green, blue;
if (x < TEX_SIZE ||
wrap_mode_s == COGL_MATERIAL_WRAP_MODE_REPEAT ||
wrap_mode_s == COGL_MATERIAL_WRAP_MODE_AUTOMATIC)
green = (x & 1) * 255;
else
green = ((TEX_SIZE - 1) & 1) * 255;
if (y < TEX_SIZE ||
wrap_mode_t == COGL_MATERIAL_WRAP_MODE_REPEAT ||
wrap_mode_t == COGL_MATERIAL_WRAP_MODE_AUTOMATIC)
blue = (y & 1) * 255;
else
blue = ((TEX_SIZE - 1) & 1) * 255;
g_assert_cmpint (p[0], ==, 0);
g_assert_cmpint (p[1], ==, green);
g_assert_cmpint (p[2], ==, blue);
p += 4;
}
}
}
static void
validate_result (TestState *state)
{
validate_set (state, 0); /* non-atlased rectangle */
#if 0 /* this doesn't currently work */
validate_set (state, 1); /* atlased rectangle */
#endif
validate_set (state, 2); /* cogl_polygon */
validate_set (state, 3); /* vertex buffer */
/* Comment this out to see what the test paints */
clutter_main_quit ();
}
static void
on_paint (ClutterActor *actor, TestState *state)
{
draw_frame (state);
validate_result (state);
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
void
test_cogl_wrap_modes (TestUtilsGTestFixture *fixture,
void *data)
{
TestState state;
unsigned int idle_source;
unsigned int paint_handler;
state.stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (state.stage), &stage_color);
/* We force continuous redrawing of the stage, since we need to skip
* the first few frames, and we wont be doing anything else that
* will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, state.stage);
paint_handler = g_signal_connect_after (state.stage, "paint",
G_CALLBACK (on_paint), &state);
clutter_actor_show_all (state.stage);
clutter_main ();
g_source_remove (idle_source);
g_signal_handler_disconnect (state.stage, paint_handler);
if (g_test_verbose ())
g_print ("OK\n");
}

3
tests/data/Makefile.am Normal file
View File

@ -0,0 +1,3 @@
NULL =
EXTRA_DIST = valgrind.suppressions

View File

@ -0,0 +1,173 @@
{
ioctl_1
Memcheck:Param
ioctl(generic)
fun:ioctl
fun:driDrawableInitVBlank
fun:intelMakeCurrent
fun:glXMakeContextCurrent
}
{
ioctl_2
Memcheck:Param
ioctl(generic)
fun:ioctl
fun:driDrawableGetMSC32
fun:clutter_backend_glx_redraw
}
{
ioctl_3
Memcheck:Param
ioctl(generic)
fun:ioctl
fun:driWaitForMSC32
fun:clutter_backend_glx_redraw
}
{
mesa_init_context
Memcheck:Leak
fun:*alloc
...
fun:glXCreateNewContext
}
{
type_register
Memcheck:Leak
fun:*alloc
...
fun:g_type_register_*
}
{
type_ref
Memcheck:Leak
fun:*alloc
...
fun:g_type_class_ref
}
{
type_interface_prereq
Memcheck:Leak
fun:*alloc
...
fun:g_type_interface_add_prerequisite
}
{
get_charset
Memcheck:Leak
fun:*alloc
...
fun:g_get_charset
}
{
cogl_features
Memcheck:Leak
fun:*alloc
...
fun:cogl_get_features
}
{
glx_query_version
Memcheck:Leak
fun:*alloc
...
fun:glXQueryVersion
}
{
glx_create_context
Memcheck:Leak
fun:*alloc
...
fun:glXCreateNewContext
}
{
glx_make_current
Memcheck:Leak
fun:*alloc
...
fun:glXMakeContextCurrent
}
{
gl_draw_arrays
Memcheck:Leak
fun:*malloc
...
fun:glDrawArrays
}
{
cogl_clear
Memcheck:Leak
fun:*alloc
...
fun:cogl_clear
}
{
default_font
Memcheck:Leak
fun:*alloc
...
fun:clutter_backend_get_font_name
}
{
id_pool
Memcheck:Leak
fun:*alloc
...
fun:clutter_id_pool_new
}
{
x_open_display
Memcheck:Leak
fun:*alloc
...
fun:XOpenDisplay
}
# ... and font descriptions from every "sans 12" type string
{
pango_font_description_from_string
Memcheck:Leak
fun:*alloc
...
fun:pango_font_description_from_string
}
# other lib init
{
fontconfig_init
Memcheck:Leak
fun:*alloc
...
fun:FcConfigParseAndLoad
}
{
freetype_init
Memcheck:Leak
fun:*alloc
...
fun:FT_Open_Face
}
{
x_init_ext
Memcheck:Leak
fun:*alloc
...
fun:XInitExtension
}