| /* |
| * 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> |
| |
| G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
| |
| /* 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); |
| gdk_surface_destroy (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 (); |
| } |
| |
| G_GNUC_END_IGNORE_DEPRECATIONS |