Merge branch 'gles-texture-colors' into 'master'

Fix uploads of textures in GLES (and make texture uploads better)

See merge request GNOME/gtk!2616
This commit is contained in:
Matthias Clasen 2020-09-25 14:53:19 +00:00
commit c9f6a9f7c5
16 changed files with 255 additions and 185 deletions

View File

@ -300,7 +300,6 @@ gdk_cairo_rectangle
gdk_cairo_region gdk_cairo_region
gdk_cairo_region_create_from_surface gdk_cairo_region_create_from_surface
gdk_cairo_draw_from_gl gdk_cairo_draw_from_gl
gdk_cairo_surface_upload_to_gl
</SECTION> </SECTION>
<SECTION> <SECTION>

View File

@ -61,13 +61,6 @@ void gdk_cairo_draw_from_gl (cairo_t *cr,
int width, int width,
int height); 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 G_END_DECLS
#endif /* __GDK_CAIRO_H__ */ #endif /* __GDK_CAIRO_H__ */

View File

@ -438,51 +438,3 @@ out:
if (clip_region) if (clip_region)
cairo_region_destroy (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);
}

View File

@ -87,6 +87,7 @@
#include "gdkglcontextprivate.h" #include "gdkglcontextprivate.h"
#include "gdkdisplayprivate.h" #include "gdkdisplayprivate.h"
#include "gdkmemorytextureprivate.h"
#include "gdkinternals.h" #include "gdkinternals.h"
#include "gdkintl.h" #include "gdkintl.h"
@ -227,49 +228,90 @@ gdk_gl_context_upload_texture (GdkGLContext *context,
int width, int width,
int height, int height,
int stride, int stride,
GdkMemoryFormat data_format,
guint texture_target) guint texture_target)
{ {
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context); 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)); 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 /* 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 * the GL_EXT_unpack_subimage extension for OpenGL ES 2.0 is available
*/ */
if (!priv->use_es || if (stride == width * bpp)
(priv->use_es && (priv->gl_version >= 30 || priv->has_unpack_subimage)))
{ {
glPixelStorei (GL_UNPACK_ALIGNMENT, 4); glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, data);
glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / 4); }
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_format, gl_type, data);
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);
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
} }
else else
{ {
int i; int i;
glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, NULL);
if (priv->use_es) for (i = 0; i < height; i++)
{ glTexSubImage2D (texture_target, 0, 0, i, width, 1, gl_format, gl_type, data + (i * stride));
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));
}
} }
g_free (copy);
} }
static gboolean static gboolean

View File

@ -23,6 +23,7 @@
#include "gdkglcontext.h" #include "gdkglcontext.h"
#include "gdkdrawcontextprivate.h" #include "gdkdrawcontextprivate.h"
#include "gdkmemorytexture.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -84,6 +85,7 @@ void gdk_gl_context_upload_texture (GdkGLContext
int width, int width,
int height, int height,
int stride, int stride,
GdkMemoryFormat data_format,
guint texture_target); guint texture_target);
GdkGLContextPaintData * gdk_gl_context_get_paint_data (GdkGLContext *context); GdkGLContextPaintData * gdk_gl_context_get_paint_data (GdkGLContext *context);
gboolean gdk_gl_context_use_texture_rectangle (GdkGLContext *context); gboolean gdk_gl_context_use_texture_rectangle (GdkGLContext *context);

View File

@ -38,13 +38,14 @@ struct _GdkMemoryTextureClass
G_DEFINE_TYPE (GdkMemoryTexture, gdk_memory_texture, GDK_TYPE_TEXTURE) G_DEFINE_TYPE (GdkMemoryTexture, gdk_memory_texture, GDK_TYPE_TEXTURE)
static gsize gsize
gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
{ {
switch (format) switch (format)
{ {
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED: case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
case GDK_MEMORY_B8G8R8A8: case GDK_MEMORY_B8G8R8A8:
case GDK_MEMORY_A8R8G8B8: case GDK_MEMORY_A8R8G8B8:
case GDK_MEMORY_R8G8B8A8: case GDK_MEMORY_R8G8B8A8:
@ -199,6 +200,9 @@ convert_swizzle ## A ## R ## G ## B (guchar *dest_data, \
} }
SWIZZLE(3,2,1,0) 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) \ #define SWIZZLE_OPAQUE(A,R,G,B) \
static void \ 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 (0,1,2,3, 3,0,1,2)
SWIZZLE_PREMULTIPLY (3,2,1,0, 0,3,2,1) SWIZZLE_PREMULTIPLY (3,2,1,0, 0,3,2,1)
SWIZZLE_PREMULTIPLY (0,1,2,3, 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, typedef void (* ConversionFunc) (guchar *dest_data,
gsize dest_stride, gsize dest_stride,
@ -275,16 +283,17 @@ typedef void (* ConversionFunc) (guchar *dest_data,
gsize width, gsize width,
gsize height); gsize height);
static ConversionFunc converters[GDK_MEMORY_N_FORMATS][2] = static ConversionFunc converters[GDK_MEMORY_N_FORMATS][3] =
{ {
{ convert_memcpy, convert_swizzle3210 }, { convert_memcpy, convert_swizzle3210, convert_swizzle2103 },
{ convert_swizzle3210, convert_memcpy }, { convert_swizzle3210, convert_memcpy, convert_swizzle3012 },
{ convert_swizzle_premultiply_3210_3210, convert_swizzle_premultiply_0123_3210 }, { convert_swizzle2103, convert_swizzle1230, convert_memcpy },
{ convert_swizzle_premultiply_3210_0123, convert_swizzle_premultiply_0123_0123 }, { convert_swizzle_premultiply_3210_3210, convert_swizzle_premultiply_0123_3210, convert_swizzle_premultiply_3012_3210, },
{ convert_swizzle_premultiply_3210_3012, convert_swizzle_premultiply_0123_3012 }, { convert_swizzle_premultiply_3210_0123, convert_swizzle_premultiply_0123_0123, convert_swizzle_premultiply_3012_0123 },
{ convert_swizzle_premultiply_3210_0321, convert_swizzle_premultiply_0123_0321 }, { convert_swizzle_premultiply_3210_3012, convert_swizzle_premultiply_0123_3012, convert_swizzle_premultiply_3012_3012 },
{ convert_swizzle_opaque_3210, convert_swizzle_opaque_0123 }, { convert_swizzle_premultiply_3210_0321, convert_swizzle_premultiply_0123_0321, convert_swizzle_premultiply_3012_0321 },
{ convert_swizzle_opaque_3012, convert_swizzle_opaque_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 void
@ -297,7 +306,7 @@ gdk_memory_convert (guchar *dest_data,
gsize width, gsize width,
gsize height) gsize height)
{ {
g_assert (dest_format < 2); g_assert (dest_format < 3);
g_assert (src_format < GDK_MEMORY_N_FORMATS); g_assert (src_format < GDK_MEMORY_N_FORMATS);
converters[src_format][dest_format] (dest_data, dest_stride, src_data, src_stride, width, height); converters[src_format][dest_format] (dest_data, dest_stride, src_data, src_stride, width, height);

View File

@ -34,6 +34,8 @@ G_BEGIN_DECLS
* The color values are premultiplied with the alpha value. * The color values are premultiplied with the alpha value.
* @GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: 4 bytes; for alpha, red, green, blue. * @GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: 4 bytes; for alpha, red, green, blue.
* The color values are premultiplied with the alpha value. * 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_B8G8R8A8: 4 bytes; for blue, green, red, alpha.
* @GDK_MEMORY_A8R8G8B8: 4 bytes; for alpha, red, green, blue. * @GDK_MEMORY_A8R8G8B8: 4 bytes; for alpha, red, green, blue.
* @GDK_MEMORY_R8G8B8A8: 4 bytes; for red, green, blue, alpha. * @GDK_MEMORY_R8G8B8A8: 4 bytes; for red, green, blue, alpha.
@ -58,6 +60,7 @@ G_BEGIN_DECLS
typedef enum { typedef enum {
GDK_MEMORY_B8G8R8A8_PREMULTIPLIED, GDK_MEMORY_B8G8R8A8_PREMULTIPLIED,
GDK_MEMORY_A8R8G8B8_PREMULTIPLIED, GDK_MEMORY_A8R8G8B8_PREMULTIPLIED,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
GDK_MEMORY_B8G8R8A8, GDK_MEMORY_B8G8R8A8,
GDK_MEMORY_A8R8G8B8, GDK_MEMORY_A8R8G8B8,
GDK_MEMORY_R8G8B8A8, GDK_MEMORY_R8G8B8A8,

View File

@ -31,6 +31,8 @@ G_BEGIN_DECLS
#define GDK_MEMORY_CAIRO_FORMAT_ARGB32 GDK_MEMORY_DEFAULT #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); GdkMemoryFormat gdk_memory_texture_get_format (GdkMemoryTexture *self);
const guchar * gdk_memory_texture_get_data (GdkMemoryTexture *self); const guchar * gdk_memory_texture_get_data (GdkMemoryTexture *self);
gsize gdk_memory_texture_get_stride (GdkMemoryTexture *self); gsize gdk_memory_texture_get_stride (GdkMemoryTexture *self);

View File

@ -130,28 +130,6 @@ gdk_texture_real_download (GdkTexture *self,
GDK_TEXTURE_WARN_NOT_IMPLEMENTED_METHOD (self, download); 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 static void
gdk_texture_set_property (GObject *gobject, gdk_texture_set_property (GObject *gobject,
guint prop_id, guint prop_id,
@ -216,7 +194,6 @@ gdk_texture_class_init (GdkTextureClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
klass->download = gdk_texture_real_download; klass->download = gdk_texture_real_download;
klass->download_surface = gdk_texture_real_download_surface;
gobject_class->set_property = gdk_texture_set_property; gobject_class->set_property = gdk_texture_set_property;
gobject_class->get_property = gdk_texture_get_property; gobject_class->get_property = gdk_texture_get_property;
@ -438,7 +415,23 @@ gdk_texture_get_height (GdkTexture *texture)
cairo_surface_t * cairo_surface_t *
gdk_texture_download_surface (GdkTexture *texture) 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 void

View File

@ -28,7 +28,6 @@ struct _GdkTextureClass {
const GdkRectangle *area, const GdkRectangle *area,
guchar *data, guchar *data,
gsize stride); gsize stride);
cairo_surface_t * (* download_surface) (GdkTexture *texture);
}; };
gpointer gdk_texture_new (const GdkTextureClass *klass, gpointer gdk_texture_new (const GdkTextureClass *klass,

View File

@ -7,6 +7,7 @@
#include "gdk/gdkglcontextprivate.h" #include "gdk/gdkglcontextprivate.h"
#include "gdk/gdktextureprivate.h" #include "gdk/gdktextureprivate.h"
#include "gdk/gdkgltextureprivate.h" #include "gdk/gdkgltextureprivate.h"
#include "gdkmemorytextureprivate.h"
#include <gdk/gdk.h> #include <gdk/gdk.h>
#include <epoxy/gl.h> #include <epoxy/gl.h>
@ -58,6 +59,54 @@ struct _GskGLDriver
G_DEFINE_TYPE (GskGLDriver, gsk_gl_driver, G_TYPE_OBJECT) 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 * static Texture *
texture_new (void) texture_new (void)
{ {
@ -408,32 +457,15 @@ gsk_gl_driver_slice_texture (GskGLDriver *self,
slices = g_new0 (TextureSlice, cols * rows); 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 ++) for (col = 0; col < cols; col ++)
{ {
const int slice_width = MIN (max_texture_size, texture->width - x); const int slice_width = MIN (max_texture_size, texture->width - x);
const int stride = slice_width * 4;
for (row = 0; row < rows; row ++) for (row = 0; row < rows; row ++)
{ {
const int slice_height = MIN (max_texture_size, texture->height - y); const int slice_height = MIN (max_texture_size, texture->height - y);
const int slice_index = (col * rows) + row; const int slice_index = (col * rows) + row;
guchar *data;
guint texture_id; 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); glGenTextures (1, &texture_id);
@ -442,7 +474,7 @@ gsk_gl_driver_slice_texture (GskGLDriver *self,
#endif #endif
glBindTexture (GL_TEXTURE_2D, texture_id); glBindTexture (GL_TEXTURE_2D, texture_id);
gsk_gl_driver_set_texture_parameters (self, GL_NEAREST, GL_NEAREST); 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 #ifdef G_ENABLE_DEBUG
gsk_profiler_counter_inc (self->profiler, self->counters.surface_uploads); 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].rect = (GdkRectangle){x, y, slice_width, slice_height};
slices[slice_index].texture_id = texture_id; slices[slice_index].texture_id = texture_id;
g_free (data);
cairo_surface_destroy (surface);
y += slice_height; y += slice_height;
} }
@ -486,7 +515,8 @@ gsk_gl_driver_get_texture_for_texture (GskGLDriver *self,
int mag_filter) int mag_filter)
{ {
Texture *t; Texture *t;
cairo_surface_t *surface; GdkTexture *downloaded_texture = NULL;
GdkTexture *source_texture;
if (GDK_IS_GL_TEXTURE (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) 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, /* 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. */ * download its data into our context and then create a texture from it. */
if (texture_context) if (texture_context)
gdk_gl_context_make_current (texture_context); gdk_gl_context_make_current (texture_context);
surface = gdk_texture_download_surface (texture); 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); gdk_gl_context_make_current (self->gl_context);
source_texture = downloaded_texture;
} }
else else
{ {
@ -519,7 +555,7 @@ gsk_gl_driver_get_texture_for_texture (GskGLDriver *self,
return t->texture_id; 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)); 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; t->user = texture;
gsk_gl_driver_bind_source_texture (self, t->texture_id); gsk_gl_driver_bind_source_texture (self, t->texture_id);
gsk_gl_driver_init_texture_with_surface (self, gsk_gl_driver_init_texture (self,
t->texture_id, t->texture_id,
surface, source_texture,
min_filter, min_filter,
mag_filter); mag_filter);
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, t->texture_id, gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, t->texture_id,
"GdkTexture<%p> %d", 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; return t->texture_id;
} }
@ -769,11 +806,11 @@ filter_uses_mipmaps (int filter)
} }
void void
gsk_gl_driver_init_texture_with_surface (GskGLDriver *self, gsk_gl_driver_init_texture (GskGLDriver *self,
int texture_id, int texture_id,
cairo_surface_t *surface, GdkTexture *texture,
int min_filter, int min_filter,
int mag_filter) int mag_filter)
{ {
Texture *t; 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); 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 #ifdef G_ENABLE_DEBUG
gsk_profiler_counter_inc (self->profiler, self->counters.surface_uploads); gsk_profiler_counter_inc (self->profiler, self->counters.surface_uploads);

View File

@ -63,9 +63,9 @@ void gsk_gl_driver_init_texture_empty (GskGLDriver *driver
int texture_id, int texture_id,
int min_filter, int min_filter,
int max_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, int texture_id,
cairo_surface_t *surface, GdkTexture *texture,
int min_filter, int min_filter,
int mag_filter); int mag_filter);

View File

@ -7,6 +7,7 @@
#include "gskgltextureatlasprivate.h" #include "gskgltextureatlasprivate.h"
#include "gdk/gdkglcontextprivate.h" #include "gdk/gdkglcontextprivate.h"
#include "gdk/gdkmemorytextureprivate.h"
#include <graphene.h> #include <graphene.h>
#include <cairo.h> #include <cairo.h>
@ -186,6 +187,10 @@ upload_glyph (GlyphCacheKey *key,
GskGLCachedGlyph *value) GskGLCachedGlyph *value)
{ {
GskImageRegion r; 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 (), gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (),
"Uploading glyph %d", "Uploading glyph %d",
@ -197,15 +202,27 @@ upload_glyph (GlyphCacheKey *key,
glBindTexture (GL_TEXTURE_2D, value->texture_id); glBindTexture (GL_TEXTURE_2D, value->texture_id);
if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ())) 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, pixel_data = free_data = g_malloc (r.width * r.height * 4);
r.data); 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 else
glTexSubImage2D (GL_TEXTURE_2D, 0, r.x, r.y, r.width, r.height, {
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixel_data = r.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); glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
g_free (r.data); g_free (r.data);
g_free (free_data);
} }
gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ()); gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ());

View File

@ -1,6 +1,7 @@
#include "gskgliconcacheprivate.h" #include "gskgliconcacheprivate.h"
#include "gskgltextureatlasprivate.h" #include "gskgltextureatlasprivate.h"
#include "gdk/gdktextureprivate.h" #include "gdk/gdktextureprivate.h"
#include "gdk/gdkmemorytextureprivate.h"
#include "gdk/gdkglcontextprivate.h" #include "gdk/gdkglcontextprivate.h"
#include <epoxy/gl.h> #include <epoxy/gl.h>
@ -134,7 +135,10 @@ gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self,
int packed_y = 0; int packed_y = 0;
cairo_surface_t *surface; cairo_surface_t *surface;
unsigned char *surface_data; unsigned char *surface_data;
unsigned char *pixel_data;
guchar *free_data = NULL;
guint gl_format; guint gl_format;
guint gl_type;
gsk_gl_texture_atlases_pack (self->atlases, width + 2, height + 2, &atlas, &packed_x, &packed_y); 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"); "Uploading texture");
if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ())) 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 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); glBindTexture (GL_TEXTURE_2D, atlas->texture_id);
glTexSubImage2D (GL_TEXTURE_2D, 0, glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x + 1, packed_y + 1, packed_x + 1, packed_y + 1,
width, height, width, height,
gl_format, gl_format, gl_type,
GL_UNSIGNED_BYTE, pixel_data);
surface_data);
/* Padding top */ /* Padding top */
glTexSubImage2D (GL_TEXTURE_2D, 0, glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x + 1, packed_y, packed_x + 1, packed_y,
width, 1, width, 1,
gl_format, GL_UNSIGNED_BYTE, gl_format, gl_type,
surface_data); pixel_data);
/* Padding left */ /* Padding left */
glTexSubImage2D (GL_TEXTURE_2D, 0, glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x, packed_y + 1, packed_x, packed_y + 1,
1, height, 1, height,
gl_format, GL_UNSIGNED_BYTE, gl_format, gl_type,
surface_data); pixel_data);
/* Padding top left */ /* Padding top left */
glTexSubImage2D (GL_TEXTURE_2D, 0, glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x, packed_y, packed_x, packed_y,
1, 1, 1, 1,
gl_format, GL_UNSIGNED_BYTE, gl_format, gl_type,
surface_data); pixel_data);
/* Padding right */ /* Padding right */
glPixelStorei (GL_UNPACK_ROW_LENGTH, width); glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
@ -195,14 +210,14 @@ gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self,
glTexSubImage2D (GL_TEXTURE_2D, 0, glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x + width + 1, packed_y + 1, packed_x + width + 1, packed_y + 1,
1, height, 1, height,
gl_format, GL_UNSIGNED_BYTE, gl_format, gl_type,
surface_data); pixel_data);
/* Padding top right */ /* Padding top right */
glTexSubImage2D (GL_TEXTURE_2D, 0, glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x + width + 1, packed_y, packed_x + width + 1, packed_y,
1, 1, 1, 1,
gl_format, GL_UNSIGNED_BYTE, gl_format, gl_type,
surface_data); pixel_data);
/* Padding bottom */ /* Padding bottom */
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei (GL_UNPACK_ROW_LENGTH, 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, glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x + 1, packed_y + 1 + height, packed_x + 1, packed_y + 1 + height,
width, 1, width, 1,
gl_format, GL_UNSIGNED_BYTE, gl_format, gl_type,
surface_data); pixel_data);
/* Padding bottom left */ /* Padding bottom left */
glTexSubImage2D (GL_TEXTURE_2D, 0, glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x, packed_y + 1 + height, packed_x, packed_y + 1 + height,
1, 1, 1, 1,
gl_format, GL_UNSIGNED_BYTE, gl_format, gl_type,
surface_data); pixel_data);
/* Padding bottom right */ /* Padding bottom right */
glPixelStorei (GL_UNPACK_ROW_LENGTH, width); glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
glPixelStorei (GL_UNPACK_SKIP_PIXELS, width - 1); glPixelStorei (GL_UNPACK_SKIP_PIXELS, width - 1);
glTexSubImage2D (GL_TEXTURE_2D, 0, glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x + 1 + width, packed_y + 1 + height, packed_x + 1 + width, packed_y + 1 + height,
1, 1, 1, 1,
gl_format, GL_UNSIGNED_BYTE, gl_format, gl_type,
surface_data); pixel_data);
/* Reset this */ /* Reset this */
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei (GL_UNPACK_ROW_LENGTH, 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; *out_icon_data = icon_data;
cairo_surface_destroy (surface); cairo_surface_destroy (surface);
g_free (free_data);
#if 0 #if 0
{ {

View File

@ -564,6 +564,7 @@ render_fallback_node (GskGLRenderer *self,
GskRenderNode *node, GskRenderNode *node,
RenderOpBuilder *builder) RenderOpBuilder *builder)
{ {
GdkTexture *texture;
const float scale = ops_get_scale (builder); const float scale = ops_get_scale (builder);
const int surface_width = ceilf (node->bounds.size.width * scale); const int surface_width = ceilf (node->bounds.size.width * scale);
const int surface_height = ceilf (node->bounds.size.height * scale); const int surface_height = ceilf (node->bounds.size.height * scale);
@ -645,15 +646,18 @@ render_fallback_node (GskGLRenderer *self,
#endif #endif
cairo_destroy (cr); cairo_destroy (cr);
/* Upload the Cairo surface to a GL texture */ /* Upload the Cairo surface to a GL texture */
texture_id = gsk_gl_driver_create_texture (self->gl_driver, texture_id = gsk_gl_driver_create_texture (self->gl_driver,
surface_width, surface_width,
surface_height); surface_height);
gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id); gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id);
gsk_gl_driver_init_texture_with_surface (self->gl_driver,
texture_id, texture = gdk_texture_new_for_surface (surface);
surface, gsk_gl_driver_init_texture (self->gl_driver,
GL_NEAREST, GL_NEAREST); texture_id,
texture,
GL_NEAREST, GL_NEAREST);
if (gdk_gl_context_has_debug (self->gl_context)) if (gdk_gl_context_has_debug (self->gl_context))
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, texture_id, 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), g_type_name_from_instance ((GTypeInstance *) node),
texture_id); texture_id);
g_object_unref (texture);
cairo_surface_destroy (surface); cairo_surface_destroy (surface);
cairo_surface_destroy (rendered_surface); cairo_surface_destroy (rendered_surface);

View File

@ -37,6 +37,7 @@ typedef struct _TestData {
static MemoryData tests[GDK_MEMORY_N_FORMATS] = { 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(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(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(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(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) } }, { 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) } },