gtk/testsuite/gsk/shader.c
2022-07-15 16:41:05 -04:00

306 lines
11 KiB
C

/*
* Copyright © 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Matthias Clasen <mclasen@redhat.com>
*/
#include <gtk/gtk.h>
/* shader fragment as found in nature */
const char shader0[] =
"// author: bobylito\n"
"// license: MIT\n"
"const float SQRT_2 = 1.414213562373;"
"uniform float dots;// = 20.0;"
"uniform vec2 center; //= vec2(0, 0);"
""
"vec4 transition(vec2 uv) {"
" bool nextImage = distance(fract(uv * dots), vec2(0.5, 0.5)) < ( progress / distance(uv, center));"
" return nextImage ? getToColor(uv) : getFromColor(uv);"
"}";
/* Same shader, with our preamble added, and with newlines
* to make the regex happy. Added a variety of uniforms to
* exercise the parser.
*/
const char shader1[] =
"uniform float progress;\n"
"uniform sampler2D u_texture1;\n"
"uniform sampler2D u_texture2;\n"
""
"vec4 getFromColor (vec2 uv) {\n"
" return GskTexture(u_texture1, uv);\n"
"}\n"
"\n"
"vec4 getToColor (vec2 uv) {\n"
" return GskTexture(u_texture2, uv);\n"
"}\n"
"\n"
"// author: bobylito\n"
"// license: MIT\n"
"const float SQRT_2 = 1.414213562373;\n"
"uniform float dots;// = 20.0;\n"
"uniform vec2 center; //= vec2(0, 0);\n"
"\n"
"uniform int test1 = -2;\n"
"uniform uint test2 = 2; \n"
"uniform bool test3;\n"
"uniform vec3 test4;\n"
"uniform vec4 test5;\n"
"\n"
"vec4 transition(vec2 uv) {\n"
" bool nextImage = distance(fract(uv * dots), vec2(0.5, 0.5)) < ( progress / distance(uv, center));\n"
" return nextImage ? getToColor(uv) : getFromColor(uv);\n"
"}\n"
"\n"
"void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv)\n"
"{\n"
" fragColor = transition(uv);\n"
"}\n";
static void
test_create_simple (void)
{
GBytes *bytes;
GskGLShader *shader;
GBytes *source;
bytes = g_bytes_new_static (shader1, sizeof (shader1));
shader = gsk_gl_shader_new_from_bytes (bytes);
g_assert_nonnull (shader);
g_assert_cmpint (gsk_gl_shader_get_n_textures (shader), ==, 2);
g_assert_cmpint (gsk_gl_shader_get_n_uniforms (shader), ==, 8);
g_assert_cmpstr (gsk_gl_shader_get_uniform_name (shader, 0), ==, "progress");
g_assert_cmpint (gsk_gl_shader_get_uniform_type (shader, 0), ==, GSK_GL_UNIFORM_TYPE_FLOAT);
g_assert_cmpstr (gsk_gl_shader_get_uniform_name (shader, 1), ==, "dots");
g_assert_cmpint (gsk_gl_shader_get_uniform_type (shader, 1), ==, GSK_GL_UNIFORM_TYPE_FLOAT);
g_assert_cmpstr (gsk_gl_shader_get_uniform_name (shader, 2), ==, "center");
g_assert_cmpint (gsk_gl_shader_get_uniform_type (shader, 2), ==, GSK_GL_UNIFORM_TYPE_VEC2);
g_assert_cmpstr (gsk_gl_shader_get_uniform_name (shader, 3), ==, "test1");
g_assert_cmpint (gsk_gl_shader_get_uniform_type (shader, 3), ==, GSK_GL_UNIFORM_TYPE_INT);
g_assert_cmpstr (gsk_gl_shader_get_uniform_name (shader, 4), ==, "test2");
g_assert_cmpint (gsk_gl_shader_get_uniform_type (shader, 4), ==, GSK_GL_UNIFORM_TYPE_UINT);
g_assert_cmpstr (gsk_gl_shader_get_uniform_name (shader, 5), ==, "test3");
g_assert_cmpint (gsk_gl_shader_get_uniform_type (shader, 5), ==, GSK_GL_UNIFORM_TYPE_BOOL);
g_assert_cmpstr (gsk_gl_shader_get_uniform_name (shader, 6), ==, "test4");
g_assert_cmpint (gsk_gl_shader_get_uniform_type (shader, 6), ==, GSK_GL_UNIFORM_TYPE_VEC3);
g_assert_cmpstr (gsk_gl_shader_get_uniform_name (shader, 7), ==, "test5");
g_assert_cmpint (gsk_gl_shader_get_uniform_type (shader, 7), ==, GSK_GL_UNIFORM_TYPE_VEC4);
g_assert_cmpint (gsk_gl_shader_find_uniform_by_name (shader, "progress"), ==, 0);
g_assert_cmpint (gsk_gl_shader_find_uniform_by_name (shader, "dots"), ==, 1);
g_assert_cmpint (gsk_gl_shader_find_uniform_by_name (shader, "center"), ==, 2);
g_assert_cmpint (gsk_gl_shader_find_uniform_by_name (shader, "test1"), ==, 3);
g_assert_cmpint (gsk_gl_shader_find_uniform_by_name (shader, "test2"), ==, 4);
g_assert_cmpint (gsk_gl_shader_find_uniform_by_name (shader, "test3"), ==, 5);
g_assert_cmpint (gsk_gl_shader_find_uniform_by_name (shader, "test4"), ==, 6);
g_assert_cmpint (gsk_gl_shader_find_uniform_by_name (shader, "test5"), ==, 7);
g_assert_cmpint (gsk_gl_shader_find_uniform_by_name (shader, "nosucharg"), ==, -1);
g_assert_cmpint (gsk_gl_shader_get_uniform_offset (shader, 0), ==, 0);
g_assert_cmpint (gsk_gl_shader_get_uniform_offset (shader, 1), >, 0);
g_assert_cmpint (gsk_gl_shader_get_uniform_offset (shader, 2), >, 0);
g_assert_cmpint (gsk_gl_shader_get_uniform_offset (shader, 3), >, 0);
g_assert_cmpint (gsk_gl_shader_get_uniform_offset (shader, 4), >, 0);
g_assert_cmpint (gsk_gl_shader_get_uniform_offset (shader, 5), >, 0);
g_assert_cmpint (gsk_gl_shader_get_uniform_offset (shader, 6), >, 0);
g_assert_cmpint (gsk_gl_shader_get_uniform_offset (shader, 7), >, 0);
g_assert_null (gsk_gl_shader_get_resource (shader));
g_object_get (shader, "source", &source, NULL);
g_assert_true (g_bytes_equal (source, bytes));
g_object_unref (shader);
g_bytes_unref (bytes);
g_bytes_unref (source);
}
static void
test_create_data (void)
{
GBytes *bytes;
GBytes *bytes2;
GskGLShader *shader;
GskShaderArgsBuilder *builder;
GskShaderArgsBuilder *builder2;
graphene_vec2_t v2, vv2;
graphene_vec3_t v3, vv3;
graphene_vec4_t v4, vv4;
GskRenderNode *node;
GskRenderNode *children[2];
bytes = g_bytes_new_static (shader1, sizeof (shader1));
shader = gsk_gl_shader_new_from_bytes (bytes);
g_assert_nonnull (shader);
g_clear_pointer (&bytes, g_bytes_unref);
builder = gsk_shader_args_builder_new (shader, NULL);
g_assert_nonnull (builder);
graphene_vec2_init (&v2, 20, 30);
graphene_vec3_init (&v3, -1, -2, -3);
graphene_vec4_init (&v4, 100, 0, -100, 10);
gsk_shader_args_builder_set_float (builder, 0, 0.5);
gsk_shader_args_builder_set_float (builder, 1, 20.0);
gsk_shader_args_builder_set_vec2 (builder, 2, &v2);
gsk_shader_args_builder_set_int (builder, 3, -99);
gsk_shader_args_builder_set_uint (builder, 4, 99);
gsk_shader_args_builder_set_bool (builder, 5, 1);
gsk_shader_args_builder_set_vec3 (builder, 6, &v3);
gsk_shader_args_builder_set_vec4 (builder, 7, &v4);
bytes = gsk_shader_args_builder_to_args (builder);
g_assert_cmpfloat (gsk_gl_shader_get_arg_float (shader, bytes, 0), ==, 0.5);
g_assert_cmpfloat (gsk_gl_shader_get_arg_float (shader, bytes, 1), ==, 20.0);
gsk_gl_shader_get_arg_vec2 (shader, bytes, 2, &vv2);
g_assert_true (graphene_vec2_equal (&v2, &vv2));
g_assert_cmpint (gsk_gl_shader_get_arg_int (shader, bytes, 3), ==, -99);
g_assert_cmpuint (gsk_gl_shader_get_arg_uint (shader, bytes, 4), ==, 99);
g_assert_cmpint (gsk_gl_shader_get_arg_bool (shader, bytes, 5), ==, 1);
gsk_gl_shader_get_arg_vec3 (shader, bytes, 6, &vv3);
g_assert_true (graphene_vec3_equal (&v3, &vv3));
gsk_gl_shader_get_arg_vec4 (shader, bytes, 7, &vv4);
g_assert_true (graphene_vec4_equal (&v4, &vv4));
children[0] = gsk_color_node_new (&(GdkRGBA){0,0,0,1}, &GRAPHENE_RECT_INIT (0, 0, 50, 50));
children[1] = gsk_color_node_new (&(GdkRGBA){1,0,0,1}, &GRAPHENE_RECT_INIT (0, 0, 50, 50));
node = gsk_gl_shader_node_new (shader,
&GRAPHENE_RECT_INIT (0, 0, 50, 50),
bytes,
children,
2);
g_assert_true (gsk_gl_shader_node_get_shader (node) == shader);
g_assert_cmpuint (gsk_gl_shader_node_get_n_children (node), ==, 2);
g_assert_true (gsk_gl_shader_node_get_child (node, 0) == children[0]);
g_assert_true (gsk_gl_shader_node_get_child (node, 1) == children[1]);
gsk_render_node_unref (children[0]);
gsk_render_node_unref (children[1]);
gsk_render_node_unref (node);
builder2 = gsk_shader_args_builder_new (shader, bytes);
gsk_shader_args_builder_ref (builder2);
bytes2 = gsk_shader_args_builder_free_to_args (builder2);
gsk_shader_args_builder_unref (builder2);
g_assert_true (g_bytes_equal (bytes, bytes2));
g_bytes_unref (bytes2);
g_bytes_unref (bytes);
gsk_shader_args_builder_unref (builder);
g_object_unref (shader);
}
static void
test_format_args (void)
{
GBytes *bytes;
GskGLShader *shader;
graphene_vec2_t v2, vv2;
graphene_vec3_t v3, vv3;
graphene_vec4_t v4, vv4;
float f1, f2;
GBytes *args;
bytes = g_bytes_new_static (shader1, sizeof (shader1));
shader = gsk_gl_shader_new_from_bytes (bytes);
g_assert_nonnull (shader);
g_clear_pointer (&bytes, g_bytes_unref);
graphene_vec2_init (&v2, 20, 30);
graphene_vec3_init (&v3, -1, -2, -3);
graphene_vec4_init (&v4, 100, 0, -100, 10);
f1 = 0.5;
f2 = 20.0;
args = gsk_gl_shader_format_args (shader,
"progress", f1,
"dots", f2,
"center", &v2,
"test4", &v3,
"test5", &v4,
NULL);
g_assert_cmpfloat (gsk_gl_shader_get_arg_float (shader, args, 0), ==, 0.5);
g_assert_cmpfloat (gsk_gl_shader_get_arg_float (shader, args, 1), ==, 20.0);
gsk_gl_shader_get_arg_vec2 (shader, args, 2, &vv2);
g_assert_true (graphene_vec2_equal (&v2, &vv2));
gsk_gl_shader_get_arg_vec3 (shader, args, 6, &vv3);
g_assert_true (graphene_vec3_equal (&v3, &vv3));
gsk_gl_shader_get_arg_vec4 (shader, args, 7, &vv4);
g_assert_true (graphene_vec4_equal (&v4, &vv4));
g_bytes_unref (args);
g_object_unref (shader);
}
static void
test_compile (void)
{
GBytes *bytes;
GskGLShader *shader;
GdkSurface *surface;
GskRenderer *renderer;
GError *error = NULL;
gboolean ret;
bytes = g_bytes_new_static ("blaat", 6);
shader = gsk_gl_shader_new_from_bytes (bytes);
g_assert_nonnull (shader);
surface = gdk_surface_new_toplevel (gdk_display_get_default ());
renderer = gsk_renderer_new_for_surface (surface);
g_assert_nonnull (renderer);
ret = gsk_gl_shader_compile (shader, renderer, &error);
g_assert_false (ret);
g_assert_nonnull (error);
if (g_str_equal (G_OBJECT_TYPE_NAME (renderer), "GskGLRenderer"))
g_assert_nonnull (strstr (error->message, "blaat"));
else
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
g_clear_error (&error);
gsk_renderer_unrealize (renderer);
g_object_unref (renderer);
g_object_unref (surface);
g_bytes_unref (bytes);
}
int
main (int argc,
char *argv[])
{
gtk_test_init (&argc, &argv, NULL);
g_test_add_func ("/shader/create/simple", test_create_simple);
g_test_add_func ("/shader/create/data", test_create_data);
g_test_add_func ("/shader/format-args", test_format_args);
g_test_add_func ("/shader/compile", test_compile);
return g_test_run ();
}