| #include <gtk/gtk.h> |
| #ifdef GDK_WINDOWING_WIN32 |
| /* epoxy needs this, see https://github.com/anholt/libepoxy/issues/299 */ |
| #include <windows.h> |
| #endif |
| #include <epoxy/gl.h> |
| #include "gdk/gdktextureprivate.h" |
| #include "gdk/gdkglcontextprivate.h" |
| #include "gdk/gdkgltextureprivate.h" |
| |
| static cairo_surface_t * |
| make_surface (void) |
| { |
| cairo_surface_t *surface; |
| cairo_t *cr; |
| guchar *data; |
| |
| data = g_malloc (64 * 64 * 4); |
| surface = cairo_image_surface_create_for_data (data, |
| CAIRO_FORMAT_ARGB32, |
| 64, 64, 64 * 4); |
| cr = cairo_create (surface); |
| cairo_set_source_rgb (cr, 1, 0, 0); |
| cairo_paint (cr); |
| cairo_destroy (cr); |
| |
| return surface; |
| } |
| |
| static unsigned int |
| make_gl_texture (GdkGLContext *context, |
| cairo_surface_t *surface) |
| { |
| unsigned int id; |
| |
| glGenTextures (1, &id); |
| glActiveTexture (GL_TEXTURE0); |
| glBindTexture (GL_TEXTURE_2D, id); |
| glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, 64, 64, 0, GL_BGRA, GL_UNSIGNED_BYTE, |
| cairo_image_surface_get_data (surface)); |
| |
| g_assert_true (glGetError () == GL_NO_ERROR); |
| |
| return id; |
| } |
| |
| enum { |
| SAME_CONTEXT, |
| NO_CONTEXT, |
| SHARED_CONTEXT |
| }; |
| |
| static void |
| test_gltexture (int test) |
| { |
| GdkDisplay *display; |
| GdkGLContext *context; |
| GdkGLContext *context2 = NULL; |
| GdkGLTextureBuilder *builder; |
| GdkTexture *texture; |
| cairo_surface_t *surface; |
| GError *error = NULL; |
| unsigned int id; |
| guchar *data; |
| |
| display = gdk_display_get_default (); |
| if (!gdk_display_prepare_gl (display, &error)) |
| { |
| g_test_message ("no GL support: %s", error->message); |
| g_test_skip ("no GL support"); |
| g_clear_error (&error); |
| return; |
| } |
| |
| context = gdk_display_create_gl_context (display, &error); |
| g_assert_nonnull (context); |
| g_assert_no_error (error); |
| |
| gdk_gl_context_realize (context, &error); |
| g_assert_no_error (error); |
| |
| surface = make_surface (); |
| |
| gdk_gl_context_make_current (context); |
| |
| id = make_gl_texture (context, surface); |
| |
| if (test == NO_CONTEXT) |
| gdk_gl_context_clear_current (); |
| else if (test == SHARED_CONTEXT) |
| { |
| context2 = gdk_display_create_gl_context (display, &error); |
| g_assert_nonnull (context2); |
| g_assert_no_error (error); |
| |
| gdk_gl_context_realize (context2, &error); |
| g_assert_no_error (error); |
| |
| gdk_gl_context_make_current (context2); |
| } |
| |
| builder = gdk_gl_texture_builder_new (); |
| gdk_gl_texture_builder_set_id (builder, id); |
| gdk_gl_texture_builder_set_context (builder, context); |
| gdk_gl_texture_builder_set_width (builder, 64); |
| gdk_gl_texture_builder_set_height (builder, 64); |
| texture = gdk_gl_texture_builder_build (builder, NULL, NULL); |
| |
| data = g_malloc0 (64 * 64 * 4); |
| gdk_texture_download (texture, data, 64 * 4); |
| |
| g_assert_true (memcmp (data, cairo_image_surface_get_data (surface), 64 * 64 * 4) == 0); |
| |
| g_free (data); |
| g_object_unref (texture); |
| g_object_unref (builder); |
| |
| cairo_surface_destroy (surface); |
| |
| g_object_unref (context); |
| |
| g_clear_object (&context2); |
| } |
| |
| static void |
| test_gltexture_same_context (void) |
| { |
| test_gltexture (SAME_CONTEXT); |
| } |
| |
| static void |
| test_gltexture_no_context (void) |
| { |
| test_gltexture (NO_CONTEXT); |
| } |
| |
| static void |
| test_gltexture_shared_context (void) |
| { |
| test_gltexture (SHARED_CONTEXT); |
| } |
| |
| static void |
| test_gltexture_updates (void) |
| { |
| GdkDisplay *display; |
| GdkGLContext *context; |
| GdkGLTextureBuilder *builder; |
| cairo_surface_t *surface; |
| GError *error = NULL; |
| unsigned int id; |
| guchar *data; |
| gpointer sync; |
| GdkTexture *old_texture; |
| GdkTexture *texture; |
| cairo_region_t *update_region, *diff; |
| |
| display = gdk_display_get_default (); |
| if (!gdk_display_prepare_gl (display, &error)) |
| { |
| g_test_message ("no GL support: %s", error->message); |
| g_test_skip ("no GL support"); |
| g_clear_error (&error); |
| return; |
| } |
| |
| context = gdk_display_create_gl_context (display, &error); |
| g_assert_nonnull (context); |
| g_assert_no_error (error); |
| |
| builder = gdk_gl_texture_builder_new (); |
| gdk_gl_texture_builder_set_id (builder, 10); |
| |
| surface = make_surface (); |
| |
| gdk_gl_context_make_current (context); |
| |
| id = make_gl_texture (context, surface); |
| |
| G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
| old_texture = gdk_gl_texture_new (context, id, 64, 64, NULL, NULL); |
| G_GNUC_END_IGNORE_DEPRECATIONS |
| |
| id = make_gl_texture (context, surface); |
| |
| sync = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0); |
| |
| update_region = cairo_region_create_rectangle (&(cairo_rectangle_int_t) { 10, 10, 32, 32 }); |
| |
| builder = gdk_gl_texture_builder_new (); |
| g_object_set (builder, |
| "context", context, |
| "id", id, |
| "width", 64, |
| "height", 64, |
| "sync", sync, |
| "update-texture", old_texture, |
| "update-region", update_region, |
| NULL); |
| |
| g_assert_true (gdk_gl_texture_builder_get_sync (builder) == sync); |
| g_assert_true (gdk_gl_texture_builder_get_update_texture (builder) == old_texture); |
| g_assert_true (cairo_region_equal (gdk_gl_texture_builder_get_update_region (builder), update_region)); |
| |
| texture = gdk_gl_texture_builder_build (builder, NULL, NULL); |
| |
| g_assert_true (gdk_gl_texture_get_context (GDK_GL_TEXTURE (texture)) == context); |
| g_assert_true (gdk_gl_texture_get_id (GDK_GL_TEXTURE (texture)) == id); |
| g_assert_false (gdk_gl_texture_has_mipmap (GDK_GL_TEXTURE (texture))); |
| g_assert_true (gdk_gl_texture_get_sync (GDK_GL_TEXTURE (texture)) == sync); |
| |
| data = g_malloc0 (64 * 64 * 4); |
| gdk_texture_download (texture, data, 64 * 4); |
| |
| g_assert_true (memcmp (data, cairo_image_surface_get_data (surface), 64 * 64 * 4) == 0); |
| |
| diff = cairo_region_create (); |
| gdk_texture_diff (texture, old_texture, diff); |
| g_assert_true (cairo_region_equal (diff, update_region)); |
| cairo_region_destroy (diff); |
| |
| diff = cairo_region_create (); |
| gdk_texture_diff (old_texture, texture, diff); |
| g_assert_true (cairo_region_equal (diff, update_region)); |
| cairo_region_destroy (diff); |
| |
| g_free (data); |
| g_object_unref (texture); |
| g_object_unref (builder); |
| |
| cairo_surface_destroy (surface); |
| |
| if (sync) |
| glDeleteSync (sync); |
| cairo_region_destroy (update_region); |
| g_object_unref (old_texture); |
| |
| g_object_unref (context); |
| } |
| |
| int |
| main (int argc, char *argv[]) |
| { |
| gtk_test_init (&argc, &argv, NULL); |
| |
| g_test_add_func ("/gltexture/same-context", test_gltexture_same_context); |
| g_test_add_func ("/gltexture/no-context", test_gltexture_no_context); |
| g_test_add_func ("/gltexture/shared-context", test_gltexture_shared_context); |
| g_test_add_func ("/gltexture/updates", test_gltexture_updates); |
| |
| return g_test_run (); |
| } |