forked from AuroraMiddleware/gtk
13d943f763
A problem with textures is that they can become too big for GPU memory, which would require tiling. But for tiling we only need to download the pixels needed by the tile. Similarly, there might be interest to not upload full textures if a renderer knows it only needs a small part. Both of these methods require the ability to specify an area of the texture to be downloaded. So change the download vfunc to include this parameter now before we add even more textures later. A private gdk_texture_download_area() function has also been added, but nobody is using it yet.
291 lines
8.8 KiB
C
291 lines
8.8 KiB
C
/*
|
|
* Copyright © 2018 Benjamin Otte
|
|
*
|
|
* 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: Benjamin Otte <otte@gnome.org>
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "gdkmemorytextureprivate.h"
|
|
|
|
struct _GdkMemoryTexture
|
|
{
|
|
GdkTexture parent_instance;
|
|
|
|
GdkMemoryFormat format;
|
|
|
|
GBytes *bytes;
|
|
gsize stride;
|
|
};
|
|
|
|
struct _GdkMemoryTextureClass
|
|
{
|
|
GdkTextureClass parent_class;
|
|
};
|
|
|
|
G_DEFINE_TYPE (GdkMemoryTexture, gdk_memory_texture, GDK_TYPE_TEXTURE)
|
|
|
|
static gsize
|
|
gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
|
|
{
|
|
switch (format)
|
|
{
|
|
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
|
|
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
|
|
case GDK_MEMORY_B8G8R8A8:
|
|
case GDK_MEMORY_A8R8G8B8:
|
|
case GDK_MEMORY_R8G8B8A8:
|
|
case GDK_MEMORY_A8B8G8R8:
|
|
return 4;
|
|
|
|
case GDK_MEMORY_R8G8B8:
|
|
case GDK_MEMORY_B8G8R8:
|
|
return 3;
|
|
|
|
case GDK_MEMORY_N_FORMATS:
|
|
default:
|
|
g_assert_not_reached ();
|
|
return 4;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gdk_memory_texture_dispose (GObject *object)
|
|
{
|
|
GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (object);
|
|
|
|
g_clear_pointer (&self->bytes, g_bytes_unref);
|
|
|
|
G_OBJECT_CLASS (gdk_memory_texture_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
gdk_memory_texture_download (GdkTexture *texture,
|
|
const GdkRectangle *area,
|
|
guchar *data,
|
|
gsize stride)
|
|
{
|
|
GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture);
|
|
|
|
gdk_memory_convert (data, stride,
|
|
GDK_MEMORY_CAIRO_FORMAT_ARGB32,
|
|
(guchar *) g_bytes_get_data (self->bytes, NULL)
|
|
+ area->x * gdk_memory_format_bytes_per_pixel (self->format)
|
|
+ area->y * self->stride,
|
|
self->stride,
|
|
self->format,
|
|
area->width, area->height);
|
|
}
|
|
|
|
static void
|
|
gdk_memory_texture_class_init (GdkMemoryTextureClass *klass)
|
|
{
|
|
GdkTextureClass *texture_class = GDK_TEXTURE_CLASS (klass);
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
texture_class->download = gdk_memory_texture_download;
|
|
gobject_class->dispose = gdk_memory_texture_dispose;
|
|
}
|
|
|
|
static void
|
|
gdk_memory_texture_init (GdkMemoryTexture *self)
|
|
{
|
|
}
|
|
|
|
GdkTexture *
|
|
gdk_memory_texture_new (int width,
|
|
int height,
|
|
GdkMemoryFormat format,
|
|
GBytes *bytes,
|
|
gsize stride)
|
|
{
|
|
GdkMemoryTexture *self;
|
|
|
|
self = g_object_new (GDK_TYPE_MEMORY_TEXTURE,
|
|
"width", width,
|
|
"height", height,
|
|
NULL);
|
|
|
|
self->format = format;
|
|
self->bytes = g_bytes_ref (bytes);
|
|
self->stride = stride;
|
|
|
|
return GDK_TEXTURE (self);
|
|
}
|
|
|
|
GdkMemoryFormat
|
|
gdk_memory_texture_get_format (GdkMemoryTexture *self)
|
|
{
|
|
return self->format;
|
|
}
|
|
|
|
const guchar *
|
|
gdk_memory_texture_get_data (GdkMemoryTexture *self)
|
|
{
|
|
return g_bytes_get_data (self->bytes, NULL);
|
|
}
|
|
|
|
gsize
|
|
gdk_memory_texture_get_stride (GdkMemoryTexture *self)
|
|
{
|
|
return self->stride;
|
|
}
|
|
|
|
static void
|
|
convert_memcpy (guchar *dest_data,
|
|
gsize dest_stride,
|
|
const guchar *src_data,
|
|
gsize src_stride,
|
|
gsize width,
|
|
gsize height)
|
|
{
|
|
gsize y;
|
|
|
|
for (y = 0; y < height; y++)
|
|
memcpy (dest_data + y * dest_stride, src_data + y * src_stride, 4 * width);
|
|
}
|
|
|
|
#define SWIZZLE(A,R,G,B) \
|
|
static void \
|
|
convert_swizzle ## A ## R ## G ## B (guchar *dest_data, \
|
|
gsize dest_stride, \
|
|
const guchar *src_data, \
|
|
gsize src_stride, \
|
|
gsize width, \
|
|
gsize height) \
|
|
{ \
|
|
gsize x, y; \
|
|
\
|
|
for (y = 0; y < height; y++) \
|
|
{ \
|
|
for (x = 0; x < width; x++) \
|
|
{ \
|
|
dest_data[4 * x + A] = src_data[4 * x + 0]; \
|
|
dest_data[4 * x + R] = src_data[4 * x + 1]; \
|
|
dest_data[4 * x + G] = src_data[4 * x + 2]; \
|
|
dest_data[4 * x + B] = src_data[4 * x + 3]; \
|
|
} \
|
|
\
|
|
dest_data += dest_stride; \
|
|
src_data += src_stride; \
|
|
} \
|
|
}
|
|
|
|
SWIZZLE(3,2,1,0)
|
|
|
|
#define SWIZZLE_OPAQUE(A,R,G,B) \
|
|
static void \
|
|
convert_swizzle_opaque_## A ## R ## G ## B (guchar *dest_data, \
|
|
gsize dest_stride, \
|
|
const guchar *src_data, \
|
|
gsize src_stride, \
|
|
gsize width, \
|
|
gsize height) \
|
|
{ \
|
|
gsize x, y; \
|
|
\
|
|
for (y = 0; y < height; y++) \
|
|
{ \
|
|
for (x = 0; x < width; x++) \
|
|
{ \
|
|
dest_data[4 * x + A] = 0xFF; \
|
|
dest_data[4 * x + R] = src_data[3 * x + 0]; \
|
|
dest_data[4 * x + G] = src_data[3 * x + 1]; \
|
|
dest_data[4 * x + B] = src_data[3 * x + 2]; \
|
|
} \
|
|
\
|
|
dest_data += dest_stride; \
|
|
src_data += src_stride; \
|
|
} \
|
|
}
|
|
|
|
SWIZZLE_OPAQUE(3,2,1,0)
|
|
SWIZZLE_OPAQUE(3,0,1,2)
|
|
SWIZZLE_OPAQUE(0,1,2,3)
|
|
SWIZZLE_OPAQUE(0,3,2,1)
|
|
|
|
#define PREMULTIPLY(d,c,a) G_STMT_START { guint t = c * a + 0x80; d = ((t >> 8) + t) >> 8; } G_STMT_END
|
|
#define SWIZZLE_PREMULTIPLY(A,R,G,B, A2,R2,G2,B2) \
|
|
static void \
|
|
convert_swizzle_premultiply_ ## A ## R ## G ## B ## _ ## A2 ## R2 ## G2 ## B2 \
|
|
(guchar *dest_data, \
|
|
gsize dest_stride, \
|
|
const guchar *src_data, \
|
|
gsize src_stride, \
|
|
gsize width, \
|
|
gsize height) \
|
|
{ \
|
|
gsize x, y; \
|
|
\
|
|
for (y = 0; y < height; y++) \
|
|
{ \
|
|
for (x = 0; x < width; x++) \
|
|
{ \
|
|
dest_data[4 * x + A] = src_data[4 * x + A2]; \
|
|
PREMULTIPLY(dest_data[4 * x + R], src_data[4 * x + R2], src_data[4 * x + A2]); \
|
|
PREMULTIPLY(dest_data[4 * x + G], src_data[4 * x + G2], src_data[4 * x + A2]); \
|
|
PREMULTIPLY(dest_data[4 * x + B], src_data[4 * x + B2], src_data[4 * x + A2]); \
|
|
} \
|
|
\
|
|
dest_data += dest_stride; \
|
|
src_data += src_stride; \
|
|
} \
|
|
}
|
|
|
|
SWIZZLE_PREMULTIPLY (3,2,1,0, 3,2,1,0)
|
|
SWIZZLE_PREMULTIPLY (0,1,2,3, 3,2,1,0)
|
|
SWIZZLE_PREMULTIPLY (3,2,1,0, 0,1,2,3)
|
|
SWIZZLE_PREMULTIPLY (0,1,2,3, 0,1,2,3)
|
|
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)
|
|
|
|
typedef void (* ConversionFunc) (guchar *dest_data,
|
|
gsize dest_stride,
|
|
const guchar *src_data,
|
|
gsize src_stride,
|
|
gsize width,
|
|
gsize height);
|
|
|
|
static ConversionFunc converters[GDK_MEMORY_N_FORMATS][2] =
|
|
{
|
|
{ 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 }
|
|
};
|
|
|
|
void
|
|
gdk_memory_convert (guchar *dest_data,
|
|
gsize dest_stride,
|
|
GdkMemoryFormat dest_format,
|
|
const guchar *src_data,
|
|
gsize src_stride,
|
|
GdkMemoryFormat src_format,
|
|
gsize width,
|
|
gsize height)
|
|
{
|
|
g_assert (dest_format < 2);
|
|
g_assert (src_format < GDK_MEMORY_N_FORMATS);
|
|
|
|
converters[src_format][dest_format] (dest_data, dest_stride, src_data, src_stride, width, height);
|
|
}
|