diff --git a/docs/reference/gdk/gdk4-sections.txt b/docs/reference/gdk/gdk4-sections.txt index 0bfe140b17..4c2b0dc3b2 100644 --- a/docs/reference/gdk/gdk4-sections.txt +++ b/docs/reference/gdk/gdk4-sections.txt @@ -300,7 +300,6 @@ gdk_cairo_rectangle gdk_cairo_region gdk_cairo_region_create_from_surface gdk_cairo_draw_from_gl -gdk_cairo_surface_upload_to_gl
diff --git a/gdk/gdkcairo.h b/gdk/gdkcairo.h index e2dc85c41c..40ab46baf6 100644 --- a/gdk/gdkcairo.h +++ b/gdk/gdkcairo.h @@ -61,13 +61,6 @@ void gdk_cairo_draw_from_gl (cairo_t *cr, int width, int height); -GDK_AVAILABLE_IN_ALL -void gdk_cairo_surface_upload_to_gl (cairo_surface_t *surface, - int target, - int width, - int height, - GdkGLContext *context); - G_END_DECLS #endif /* __GDK_CAIRO_H__ */ diff --git a/gdk/gdkgl.c b/gdk/gdkgl.c index 309f792613..7ae8decfed 100644 --- a/gdk/gdkgl.c +++ b/gdk/gdkgl.c @@ -438,51 +438,3 @@ out: if (clip_region) cairo_region_destroy (clip_region); } - -/** - * gdk_cairo_surface_upload_to_gl: - * @surface: a Cairo surface - * @target: a GL texture target - * @width: the width of the texture @target - * @height: the height of the texture @target - * @context: (nullable): a #GdkGLContext, or %NULL to use the currently - * bound context - * - * Uploads the contents of a Cairo @surface to a GL texture @target. - */ -void -gdk_cairo_surface_upload_to_gl (cairo_surface_t *surface, - int target, - int width, - int height, - GdkGLContext *context) -{ - cairo_rectangle_int_t rect; - cairo_surface_t *tmp; - double device_x_offset, device_y_offset; - - g_return_if_fail (surface != NULL); - g_return_if_fail (context == NULL || GDK_IS_GL_CONTEXT (context)); - - if (context == NULL) - context = gdk_gl_context_get_current (); - - cairo_surface_flush (surface); - - cairo_surface_get_device_offset (surface, &device_x_offset, &device_y_offset); - - rect.x = (int) device_x_offset; - rect.y = (int) device_y_offset; - rect.width = width; - rect.height = height; - tmp = cairo_surface_map_to_image (surface, &rect); - - gdk_gl_context_upload_texture (context, - cairo_image_surface_get_data (tmp), - rect.width, - rect.height, - cairo_image_surface_get_stride (tmp), - target); - - cairo_surface_unmap_image (surface, tmp); -} diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c index 2843ef05f5..f9512b0343 100644 --- a/gdk/gdkglcontext.c +++ b/gdk/gdkglcontext.c @@ -87,6 +87,7 @@ #include "gdkglcontextprivate.h" #include "gdkdisplayprivate.h" +#include "gdkmemorytextureprivate.h" #include "gdkinternals.h" #include "gdkintl.h" @@ -227,49 +228,90 @@ gdk_gl_context_upload_texture (GdkGLContext *context, int width, int height, int stride, + GdkMemoryFormat data_format, guint texture_target) { GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context); + guchar *copy = NULL; + guint gl_format; + guint gl_type; + guint bpp; g_return_if_fail (GDK_IS_GL_CONTEXT (context)); + if (priv->use_es) + { + /* GLES only supports rgba, so convert if necessary */ + if (data_format != GDK_MEMORY_R8G8B8A8_PREMULTIPLIED) + { + copy = g_malloc (width * height * 4); + gdk_memory_convert (copy, width * 4, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + data, stride, data_format, + width, height); + stride = width * 4; + data = copy; + } + + bpp = 4; + gl_format = GL_RGBA; + gl_type = GL_UNSIGNED_BYTE; + } + else + { + if (data_format == GDK_MEMORY_DEFAULT) /* Cairo surface format */ + { + gl_format = GL_BGRA; + gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; + bpp = 4; + } + else if (data_format == GDK_MEMORY_R8G8B8) /* Pixmap non-alpha data */ + { + gl_format = GL_RGB; + gl_type = GL_UNSIGNED_BYTE; + bpp = 3; + } + else /* Fall-back, convert to cairo-surface-format */ + { + copy = g_malloc (width * height * 4); + gdk_memory_convert (copy, width * 4, + GDK_MEMORY_DEFAULT, + data, stride, data_format, + width, height); + stride = width * 4; + bpp = 4; + data = copy; + gl_format = GL_BGRA; + gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; + } + } + /* GL_UNPACK_ROW_LENGTH is available on desktop GL, OpenGL ES >= 3.0, or if * the GL_EXT_unpack_subimage extension for OpenGL ES 2.0 is available */ - if (!priv->use_es || - (priv->use_es && (priv->gl_version >= 30 || priv->has_unpack_subimage))) + if (stride == width * bpp) { - glPixelStorei (GL_UNPACK_ALIGNMENT, 4); - glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / 4); + glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, data); + } + else if ((!priv->use_es || + (priv->use_es && (priv->gl_version >= 30 || priv->has_unpack_subimage)))) + { + glPixelStorei (GL_UNPACK_ALIGNMENT, bpp); + glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / bpp); - if (priv->use_es) - glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, - data); - else - glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, - data); + glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, data); glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); } else { int i; - - if (priv->use_es) - { - glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - - for (i = 0; i < height; i++) - glTexSubImage2D (texture_target, 0, 0, i, width, 1, GL_RGBA, GL_UNSIGNED_BYTE, data + (i * stride)); - } - else - { - glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); - - for (i = 0; i < height; i++) - glTexSubImage2D (texture_target, 0, 0, i, width, 1, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data + (i * stride)); - } + glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, NULL); + for (i = 0; i < height; i++) + glTexSubImage2D (texture_target, 0, 0, i, width, 1, gl_format, gl_type, data + (i * stride)); } + + g_free (copy); } static gboolean diff --git a/gdk/gdkglcontextprivate.h b/gdk/gdkglcontextprivate.h index 8991332b56..e785fbc63d 100644 --- a/gdk/gdkglcontextprivate.h +++ b/gdk/gdkglcontextprivate.h @@ -23,6 +23,7 @@ #include "gdkglcontext.h" #include "gdkdrawcontextprivate.h" +#include "gdkmemorytexture.h" G_BEGIN_DECLS @@ -84,6 +85,7 @@ void gdk_gl_context_upload_texture (GdkGLContext int width, int height, int stride, + GdkMemoryFormat data_format, guint texture_target); GdkGLContextPaintData * gdk_gl_context_get_paint_data (GdkGLContext *context); gboolean gdk_gl_context_use_texture_rectangle (GdkGLContext *context); diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c index 08215820b5..663d0409f9 100644 --- a/gdk/gdkmemorytexture.c +++ b/gdk/gdkmemorytexture.c @@ -38,13 +38,14 @@ struct _GdkMemoryTextureClass G_DEFINE_TYPE (GdkMemoryTexture, gdk_memory_texture, GDK_TYPE_TEXTURE) -static gsize +gsize gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) { switch (format) { case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED: case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: + case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED: case GDK_MEMORY_B8G8R8A8: case GDK_MEMORY_A8R8G8B8: case GDK_MEMORY_R8G8B8A8: @@ -199,6 +200,9 @@ convert_swizzle ## A ## R ## G ## B (guchar *dest_data, \ } SWIZZLE(3,2,1,0) +SWIZZLE(2,1,0,3) +SWIZZLE(3,0,1,2) +SWIZZLE(1,2,3,0) #define SWIZZLE_OPAQUE(A,R,G,B) \ static void \ @@ -267,6 +271,10 @@ SWIZZLE_PREMULTIPLY (3,2,1,0, 3,0,1,2) SWIZZLE_PREMULTIPLY (0,1,2,3, 3,0,1,2) SWIZZLE_PREMULTIPLY (3,2,1,0, 0,3,2,1) SWIZZLE_PREMULTIPLY (0,1,2,3, 0,3,2,1) +SWIZZLE_PREMULTIPLY (3,0,1,2, 3,2,1,0) +SWIZZLE_PREMULTIPLY (3,0,1,2, 0,1,2,3) +SWIZZLE_PREMULTIPLY (3,0,1,2, 3,0,1,2) +SWIZZLE_PREMULTIPLY (3,0,1,2, 0,3,2,1) typedef void (* ConversionFunc) (guchar *dest_data, gsize dest_stride, @@ -275,16 +283,17 @@ typedef void (* ConversionFunc) (guchar *dest_data, gsize width, gsize height); -static ConversionFunc converters[GDK_MEMORY_N_FORMATS][2] = +static ConversionFunc converters[GDK_MEMORY_N_FORMATS][3] = { - { convert_memcpy, convert_swizzle3210 }, - { convert_swizzle3210, convert_memcpy }, - { convert_swizzle_premultiply_3210_3210, convert_swizzle_premultiply_0123_3210 }, - { convert_swizzle_premultiply_3210_0123, convert_swizzle_premultiply_0123_0123 }, - { convert_swizzle_premultiply_3210_3012, convert_swizzle_premultiply_0123_3012 }, - { convert_swizzle_premultiply_3210_0321, convert_swizzle_premultiply_0123_0321 }, - { convert_swizzle_opaque_3210, convert_swizzle_opaque_0123 }, - { convert_swizzle_opaque_3012, convert_swizzle_opaque_0321 } + { convert_memcpy, convert_swizzle3210, convert_swizzle2103 }, + { convert_swizzle3210, convert_memcpy, convert_swizzle3012 }, + { convert_swizzle2103, convert_swizzle1230, convert_memcpy }, + { convert_swizzle_premultiply_3210_3210, convert_swizzle_premultiply_0123_3210, convert_swizzle_premultiply_3012_3210, }, + { convert_swizzle_premultiply_3210_0123, convert_swizzle_premultiply_0123_0123, convert_swizzle_premultiply_3012_0123 }, + { convert_swizzle_premultiply_3210_3012, convert_swizzle_premultiply_0123_3012, convert_swizzle_premultiply_3012_3012 }, + { convert_swizzle_premultiply_3210_0321, convert_swizzle_premultiply_0123_0321, convert_swizzle_premultiply_3012_0321 }, + { convert_swizzle_opaque_3210, convert_swizzle_opaque_0123, convert_swizzle_opaque_3012 }, + { convert_swizzle_opaque_3012, convert_swizzle_opaque_0321, convert_swizzle_opaque_3210 } }; void @@ -297,7 +306,7 @@ gdk_memory_convert (guchar *dest_data, gsize width, gsize height) { - g_assert (dest_format < 2); + g_assert (dest_format < 3); g_assert (src_format < GDK_MEMORY_N_FORMATS); converters[src_format][dest_format] (dest_data, dest_stride, src_data, src_stride, width, height); diff --git a/gdk/gdkmemorytexture.h b/gdk/gdkmemorytexture.h index eea2fda324..b24e8c6796 100644 --- a/gdk/gdkmemorytexture.h +++ b/gdk/gdkmemorytexture.h @@ -34,6 +34,8 @@ G_BEGIN_DECLS * The color values are premultiplied with the alpha value. * @GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: 4 bytes; for alpha, red, green, blue. * The color values are premultiplied with the alpha value. + * @GDK_MEMORY_R8G8B8A8_PREMULTIPLIED: 4 bytes; for red, green, blue, alpha + * The color values are premultiplied with the alpha value. * @GDK_MEMORY_B8G8R8A8: 4 bytes; for blue, green, red, alpha. * @GDK_MEMORY_A8R8G8B8: 4 bytes; for alpha, red, green, blue. * @GDK_MEMORY_R8G8B8A8: 4 bytes; for red, green, blue, alpha. @@ -58,6 +60,7 @@ G_BEGIN_DECLS typedef enum { GDK_MEMORY_B8G8R8A8_PREMULTIPLIED, GDK_MEMORY_A8R8G8B8_PREMULTIPLIED, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, GDK_MEMORY_B8G8R8A8, GDK_MEMORY_A8R8G8B8, GDK_MEMORY_R8G8B8A8, diff --git a/gdk/gdkmemorytextureprivate.h b/gdk/gdkmemorytextureprivate.h index caa4b2014c..740a59da6e 100644 --- a/gdk/gdkmemorytextureprivate.h +++ b/gdk/gdkmemorytextureprivate.h @@ -31,6 +31,8 @@ G_BEGIN_DECLS #define GDK_MEMORY_CAIRO_FORMAT_ARGB32 GDK_MEMORY_DEFAULT +gsize gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format); + GdkMemoryFormat gdk_memory_texture_get_format (GdkMemoryTexture *self); const guchar * gdk_memory_texture_get_data (GdkMemoryTexture *self); gsize gdk_memory_texture_get_stride (GdkMemoryTexture *self); diff --git a/gdk/gdktexture.c b/gdk/gdktexture.c index a6db7d5e17..c28bd9575f 100644 --- a/gdk/gdktexture.c +++ b/gdk/gdktexture.c @@ -130,28 +130,6 @@ gdk_texture_real_download (GdkTexture *self, GDK_TEXTURE_WARN_NOT_IMPLEMENTED_METHOD (self, download); } -static cairo_surface_t * -gdk_texture_real_download_surface (GdkTexture *texture) -{ - cairo_surface_t *surface; - cairo_status_t surface_status; - - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, - texture->width, texture->height); - - surface_status = cairo_surface_status (surface); - if (surface_status != CAIRO_STATUS_SUCCESS) - g_warning ("%s: surface error: %s", __FUNCTION__, - cairo_status_to_string (surface_status)); - - gdk_texture_download (texture, - cairo_image_surface_get_data (surface), - cairo_image_surface_get_stride (surface)); - cairo_surface_mark_dirty (surface); - - return surface; -} - static void gdk_texture_set_property (GObject *gobject, guint prop_id, @@ -216,7 +194,6 @@ gdk_texture_class_init (GdkTextureClass *klass) GObjectClass *gobject_class = G_OBJECT_CLASS (klass); klass->download = gdk_texture_real_download; - klass->download_surface = gdk_texture_real_download_surface; gobject_class->set_property = gdk_texture_set_property; gobject_class->get_property = gdk_texture_get_property; @@ -438,7 +415,23 @@ gdk_texture_get_height (GdkTexture *texture) cairo_surface_t * gdk_texture_download_surface (GdkTexture *texture) { - return GDK_TEXTURE_GET_CLASS (texture)->download_surface (texture); + cairo_surface_t *surface; + cairo_status_t surface_status; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + texture->width, texture->height); + + surface_status = cairo_surface_status (surface); + if (surface_status != CAIRO_STATUS_SUCCESS) + g_warning ("%s: surface error: %s", __FUNCTION__, + cairo_status_to_string (surface_status)); + + gdk_texture_download (texture, + cairo_image_surface_get_data (surface), + cairo_image_surface_get_stride (surface)); + cairo_surface_mark_dirty (surface); + + return surface; } void diff --git a/gdk/gdktextureprivate.h b/gdk/gdktextureprivate.h index 07cb5436a3..3e2e9f3a49 100644 --- a/gdk/gdktextureprivate.h +++ b/gdk/gdktextureprivate.h @@ -28,7 +28,6 @@ struct _GdkTextureClass { const GdkRectangle *area, guchar *data, gsize stride); - cairo_surface_t * (* download_surface) (GdkTexture *texture); }; gpointer gdk_texture_new (const GdkTextureClass *klass, diff --git a/gsk/gl/gskgldriver.c b/gsk/gl/gskgldriver.c index 8d101b93df..a383344eae 100644 --- a/gsk/gl/gskgldriver.c +++ b/gsk/gl/gskgldriver.c @@ -7,6 +7,7 @@ #include "gdk/gdkglcontextprivate.h" #include "gdk/gdktextureprivate.h" #include "gdk/gdkgltextureprivate.h" +#include "gdkmemorytextureprivate.h" #include #include @@ -58,6 +59,54 @@ struct _GskGLDriver G_DEFINE_TYPE (GskGLDriver, gsk_gl_driver, G_TYPE_OBJECT) +static void +upload_gdk_texture (GdkTexture *source_texture, + int target, + int x_offset, + int y_offset, + int width, + int height) +{ + cairo_surface_t *surface = NULL; + GdkMemoryFormat data_format; + const guchar *data; + gsize data_stride; + gsize bpp; + + g_return_if_fail (source_texture != NULL); + g_return_if_fail (x_offset + width <= gdk_texture_get_width (source_texture)); + g_return_if_fail (y_offset + height <= gdk_texture_get_height (source_texture)); + + /* Note: GdkGLTextures are already handled before we reach this and reused as-is */ + + if (GDK_IS_MEMORY_TEXTURE (source_texture)) + { + GdkMemoryTexture *memory_texture = GDK_MEMORY_TEXTURE (source_texture); + data = gdk_memory_texture_get_data (memory_texture); + data_format = gdk_memory_texture_get_format (memory_texture); + data_stride = gdk_memory_texture_get_stride (memory_texture); + } + else + { + /* Fall back to downloading to a surface */ + surface = gdk_texture_download_surface (source_texture); + cairo_surface_flush (surface); + data = cairo_image_surface_get_data (surface); + data_format = GDK_MEMORY_DEFAULT; + data_stride = cairo_image_surface_get_stride (surface); + } + + bpp = gdk_memory_format_bytes_per_pixel (data_format); + + gdk_gl_context_upload_texture (gdk_gl_context_get_current (), + data + x_offset * bpp + y_offset * data_stride, + width, height, data_stride, + data_format, target); + + if (surface) + cairo_surface_destroy (surface); +} + static Texture * texture_new (void) { @@ -408,32 +457,15 @@ gsk_gl_driver_slice_texture (GskGLDriver *self, slices = g_new0 (TextureSlice, cols * rows); - /* TODO: (Perf): - * We still create a surface here, which should obviously be unnecessary - * and we should eventually remove it and upload the data directly. - */ for (col = 0; col < cols; col ++) { const int slice_width = MIN (max_texture_size, texture->width - x); - const int stride = slice_width * 4; for (row = 0; row < rows; row ++) { const int slice_height = MIN (max_texture_size, texture->height - y); const int slice_index = (col * rows) + row; - guchar *data; guint texture_id; - cairo_surface_t *surface; - - data = g_malloc (sizeof (guchar) * stride * slice_height); - - gdk_texture_download_area (texture, - &(GdkRectangle){x, y, slice_width, slice_height}, - data, stride); - surface = cairo_image_surface_create_for_data (data, - CAIRO_FORMAT_ARGB32, - slice_width, slice_height, - stride); glGenTextures (1, &texture_id); @@ -442,7 +474,7 @@ gsk_gl_driver_slice_texture (GskGLDriver *self, #endif glBindTexture (GL_TEXTURE_2D, texture_id); gsk_gl_driver_set_texture_parameters (self, GL_NEAREST, GL_NEAREST); - gdk_cairo_surface_upload_to_gl (surface, GL_TEXTURE_2D, slice_width, slice_height, NULL); + upload_gdk_texture (texture, GL_TEXTURE_2D, x, y, slice_width, slice_height); #ifdef G_ENABLE_DEBUG gsk_profiler_counter_inc (self->profiler, self->counters.surface_uploads); @@ -451,9 +483,6 @@ gsk_gl_driver_slice_texture (GskGLDriver *self, slices[slice_index].rect = (GdkRectangle){x, y, slice_width, slice_height}; slices[slice_index].texture_id = texture_id; - g_free (data); - cairo_surface_destroy (surface); - y += slice_height; } @@ -486,7 +515,8 @@ gsk_gl_driver_get_texture_for_texture (GskGLDriver *self, int mag_filter) { Texture *t; - cairo_surface_t *surface; + GdkTexture *downloaded_texture = NULL; + GdkTexture *source_texture; if (GDK_IS_GL_TEXTURE (texture)) { @@ -494,14 +524,20 @@ gsk_gl_driver_get_texture_for_texture (GskGLDriver *self, if (texture_context != self->gl_context) { + cairo_surface_t *surface; + /* In this case, we have to temporarily make the texture's context the current one, * download its data into our context and then create a texture from it. */ if (texture_context) gdk_gl_context_make_current (texture_context); surface = gdk_texture_download_surface (texture); + downloaded_texture = gdk_texture_new_for_surface (surface); + cairo_surface_destroy (surface); gdk_gl_context_make_current (self->gl_context); + + source_texture = downloaded_texture; } else { @@ -519,7 +555,7 @@ gsk_gl_driver_get_texture_for_texture (GskGLDriver *self, return t->texture_id; } - surface = gdk_texture_download_surface (texture); + source_texture = texture; } t = create_texture (self, gdk_texture_get_width (texture), gdk_texture_get_height (texture)); @@ -528,15 +564,16 @@ gsk_gl_driver_get_texture_for_texture (GskGLDriver *self, t->user = texture; gsk_gl_driver_bind_source_texture (self, t->texture_id); - gsk_gl_driver_init_texture_with_surface (self, - t->texture_id, - surface, - min_filter, - mag_filter); + gsk_gl_driver_init_texture (self, + t->texture_id, + source_texture, + min_filter, + mag_filter); gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, t->texture_id, "GdkTexture<%p> %d", texture, t->texture_id); - cairo_surface_destroy (surface); + if (downloaded_texture) + g_object_unref (downloaded_texture); return t->texture_id; } @@ -769,11 +806,11 @@ filter_uses_mipmaps (int filter) } void -gsk_gl_driver_init_texture_with_surface (GskGLDriver *self, - int texture_id, - cairo_surface_t *surface, - int min_filter, - int mag_filter) +gsk_gl_driver_init_texture (GskGLDriver *self, + int texture_id, + GdkTexture *texture, + int min_filter, + int mag_filter) { Texture *t; @@ -794,7 +831,7 @@ gsk_gl_driver_init_texture_with_surface (GskGLDriver *self, gsk_gl_driver_set_texture_parameters (self, min_filter, mag_filter); - gdk_cairo_surface_upload_to_gl (surface, GL_TEXTURE_2D, t->width, t->height, NULL); + upload_gdk_texture (texture, GL_TEXTURE_2D, 0, 0, t->width, t->height); #ifdef G_ENABLE_DEBUG gsk_profiler_counter_inc (self->profiler, self->counters.surface_uploads); diff --git a/gsk/gl/gskgldriverprivate.h b/gsk/gl/gskgldriverprivate.h index 406b959372..0bf9ca89d2 100644 --- a/gsk/gl/gskgldriverprivate.h +++ b/gsk/gl/gskgldriverprivate.h @@ -63,9 +63,9 @@ void gsk_gl_driver_init_texture_empty (GskGLDriver *driver int texture_id, int min_filter, int max_filter); -void gsk_gl_driver_init_texture_with_surface (GskGLDriver *driver, +void gsk_gl_driver_init_texture (GskGLDriver *driver, int texture_id, - cairo_surface_t *surface, + GdkTexture *texture, int min_filter, int mag_filter); diff --git a/gsk/gl/gskglglyphcache.c b/gsk/gl/gskglglyphcache.c index 4d23eb60be..b147dcef21 100644 --- a/gsk/gl/gskglglyphcache.c +++ b/gsk/gl/gskglglyphcache.c @@ -7,6 +7,7 @@ #include "gskgltextureatlasprivate.h" #include "gdk/gdkglcontextprivate.h" +#include "gdk/gdkmemorytextureprivate.h" #include #include @@ -186,6 +187,10 @@ upload_glyph (GlyphCacheKey *key, GskGLCachedGlyph *value) { GskImageRegion r; + guchar *pixel_data; + guchar *free_data = NULL; + guint gl_format; + guint gl_type; gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (), "Uploading glyph %d", @@ -197,15 +202,27 @@ upload_glyph (GlyphCacheKey *key, glBindTexture (GL_TEXTURE_2D, value->texture_id); if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ())) - glTexSubImage2D (GL_TEXTURE_2D, 0, r.x, r.y, r.width, r.height, - GL_RGBA, GL_UNSIGNED_BYTE, - r.data); + { + pixel_data = free_data = g_malloc (r.width * r.height * 4); + gdk_memory_convert (pixel_data, r.width * 4, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + r.data, r.width * 4, + GDK_MEMORY_DEFAULT, r.width, r.height); + gl_format = GL_RGBA; + gl_type = GL_UNSIGNED_BYTE; + } else - glTexSubImage2D (GL_TEXTURE_2D, 0, r.x, r.y, r.width, r.height, - GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, - r.data); + { + pixel_data = r.data; + gl_format = GL_BGRA; + gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; + } + + glTexSubImage2D (GL_TEXTURE_2D, 0, r.x, r.y, r.width, r.height, + gl_format, gl_type, pixel_data); glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); g_free (r.data); + g_free (free_data); } gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ()); diff --git a/gsk/gl/gskgliconcache.c b/gsk/gl/gskgliconcache.c index 5097ae597e..4bbbdbb4da 100644 --- a/gsk/gl/gskgliconcache.c +++ b/gsk/gl/gskgliconcache.c @@ -1,6 +1,7 @@ #include "gskgliconcacheprivate.h" #include "gskgltextureatlasprivate.h" #include "gdk/gdktextureprivate.h" +#include "gdk/gdkmemorytextureprivate.h" #include "gdk/gdkglcontextprivate.h" #include @@ -134,7 +135,10 @@ gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self, int packed_y = 0; cairo_surface_t *surface; unsigned char *surface_data; + unsigned char *pixel_data; + guchar *free_data = NULL; guint gl_format; + guint gl_type; gsk_gl_texture_atlases_pack (self->atlases, width + 2, height + 2, &atlas, &packed_x, &packed_y); @@ -158,36 +162,47 @@ gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self, "Uploading texture"); if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ())) - gl_format = GL_RGBA; + { + pixel_data = free_data = g_malloc (width * height * 4); + gdk_memory_convert (pixel_data, width * 4, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + surface_data, cairo_image_surface_get_stride (surface), + GDK_MEMORY_DEFAULT, width, height); + gl_format = GL_RGBA; + gl_type = GL_UNSIGNED_BYTE; + } else - gl_format = GL_BGRA; + { + pixel_data = surface_data; + gl_format = GL_BGRA; + gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; + } glBindTexture (GL_TEXTURE_2D, atlas->texture_id); glTexSubImage2D (GL_TEXTURE_2D, 0, packed_x + 1, packed_y + 1, width, height, - gl_format, - GL_UNSIGNED_BYTE, - surface_data); + gl_format, gl_type, + pixel_data); /* Padding top */ glTexSubImage2D (GL_TEXTURE_2D, 0, packed_x + 1, packed_y, width, 1, - gl_format, GL_UNSIGNED_BYTE, - surface_data); + gl_format, gl_type, + pixel_data); /* Padding left */ glTexSubImage2D (GL_TEXTURE_2D, 0, packed_x, packed_y + 1, 1, height, - gl_format, GL_UNSIGNED_BYTE, - surface_data); + gl_format, gl_type, + pixel_data); /* Padding top left */ glTexSubImage2D (GL_TEXTURE_2D, 0, packed_x, packed_y, 1, 1, - gl_format, GL_UNSIGNED_BYTE, - surface_data); + gl_format, gl_type, + pixel_data); /* Padding right */ glPixelStorei (GL_UNPACK_ROW_LENGTH, width); @@ -195,14 +210,14 @@ gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self, glTexSubImage2D (GL_TEXTURE_2D, 0, packed_x + width + 1, packed_y + 1, 1, height, - gl_format, GL_UNSIGNED_BYTE, - surface_data); + gl_format, gl_type, + pixel_data); /* Padding top right */ glTexSubImage2D (GL_TEXTURE_2D, 0, packed_x + width + 1, packed_y, 1, 1, - gl_format, GL_UNSIGNED_BYTE, - surface_data); + gl_format, gl_type, + pixel_data); /* Padding bottom */ glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); @@ -210,22 +225,22 @@ gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self, glTexSubImage2D (GL_TEXTURE_2D, 0, packed_x + 1, packed_y + 1 + height, width, 1, - gl_format, GL_UNSIGNED_BYTE, - surface_data); + gl_format, gl_type, + pixel_data); /* Padding bottom left */ glTexSubImage2D (GL_TEXTURE_2D, 0, packed_x, packed_y + 1 + height, 1, 1, - gl_format, GL_UNSIGNED_BYTE, - surface_data); + gl_format, gl_type, + pixel_data); /* Padding bottom right */ glPixelStorei (GL_UNPACK_ROW_LENGTH, width); glPixelStorei (GL_UNPACK_SKIP_PIXELS, width - 1); glTexSubImage2D (GL_TEXTURE_2D, 0, packed_x + 1 + width, packed_y + 1 + height, 1, 1, - gl_format, GL_UNSIGNED_BYTE, - surface_data); + gl_format, gl_type, + pixel_data); /* Reset this */ glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); @@ -236,6 +251,7 @@ gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self, *out_icon_data = icon_data; cairo_surface_destroy (surface); + g_free (free_data); #if 0 { diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index 501daeb45c..1181ca0609 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -564,6 +564,7 @@ render_fallback_node (GskGLRenderer *self, GskRenderNode *node, RenderOpBuilder *builder) { + GdkTexture *texture; const float scale = ops_get_scale (builder); const int surface_width = ceilf (node->bounds.size.width * scale); const int surface_height = ceilf (node->bounds.size.height * scale); @@ -645,15 +646,18 @@ render_fallback_node (GskGLRenderer *self, #endif cairo_destroy (cr); + /* Upload the Cairo surface to a GL texture */ texture_id = gsk_gl_driver_create_texture (self->gl_driver, surface_width, surface_height); gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id); - gsk_gl_driver_init_texture_with_surface (self->gl_driver, - texture_id, - surface, - GL_NEAREST, GL_NEAREST); + + texture = gdk_texture_new_for_surface (surface); + gsk_gl_driver_init_texture (self->gl_driver, + texture_id, + texture, + GL_NEAREST, GL_NEAREST); if (gdk_gl_context_has_debug (self->gl_context)) gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, texture_id, @@ -661,6 +665,7 @@ render_fallback_node (GskGLRenderer *self, g_type_name_from_instance ((GTypeInstance *) node), texture_id); + g_object_unref (texture); cairo_surface_destroy (surface); cairo_surface_destroy (rendered_surface); diff --git a/testsuite/gdk/memorytexture.c b/testsuite/gdk/memorytexture.c index 381d61aac7..950de41b0a 100644 --- a/testsuite/gdk/memorytexture.c +++ b/testsuite/gdk/memorytexture.c @@ -37,6 +37,7 @@ typedef struct _TestData { static MemoryData tests[GDK_MEMORY_N_FORMATS] = { { 4, FALSE, { RGBA(FF,00,00,FF), RGBA(00,FF,00,FF), RGBA(00,00,FF,FF), RGBA(00,00,00,00), RGBA(66,22,44,AA) } }, { 4, FALSE, { RGBA(FF,00,00,FF), RGBA(FF,00,FF,00), RGBA(FF,FF,00,00), RGBA(00,00,00,00), RGBA(AA,44,22,66) } }, + { 4, FALSE, { RGBA(00,00,FF,FF), RGBA(00,FF,00,FF), RGBA(FF,00,00,FF), RGBA(00,00,00,00), RGBA(44,22,66,AA) } }, { 4, FALSE, { RGBA(FF,00,00,FF), RGBA(00,FF,00,FF), RGBA(00,00,FF,FF), RGBA(00,00,00,00), RGBA(99,33,66,AA) } }, { 4, FALSE, { RGBA(FF,00,00,FF), RGBA(FF,00,FF,00), RGBA(FF,FF,00,00), RGBA(00,00,00,00), RGBA(AA,66,33,99) } }, { 4, FALSE, { RGBA(00,00,FF,FF), RGBA(00,FF,00,FF), RGBA(FF,00,00,FF), RGBA(00,00,00,00), RGBA(66,33,99,AA) } },