mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-25 21:21:21 +00:00
gpu: Add GskGpuPatternWriter
It's just an object that encapsulates everything needed to create (the data for) a pattern op. It also clarifies which code does what, because now the NodeProcessor and the PatternWriter are 2 different things.
This commit is contained in:
parent
187db92a88
commit
92d1df94fa
@ -65,7 +65,23 @@
|
|||||||
* never uses it, other than to allow the vertex shaders to emit its vertices.
|
* never uses it, other than to allow the vertex shaders to emit its vertices.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
gsk_gpu_shader_image_clear (gpointer data)
|
||||||
|
{
|
||||||
|
GskGpuShaderImage *image = data;
|
||||||
|
g_object_unref (image->image);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GDK_ARRAY_NAME gsk_gpu_pattern_images
|
||||||
|
#define GDK_ARRAY_TYPE_NAME GskGpuPatternImages
|
||||||
|
#define GDK_ARRAY_ELEMENT_TYPE GskGpuShaderImage
|
||||||
|
#define GDK_ARRAY_FREE_FUNC gsk_gpu_shader_image_clear
|
||||||
|
#define GDK_ARRAY_PREALLOC 8
|
||||||
|
#define GDK_ARRAY_BY_VALUE 1
|
||||||
|
#include "gdk/gdkarrayimpl.c"
|
||||||
|
|
||||||
typedef struct _GskGpuNodeProcessor GskGpuNodeProcessor;
|
typedef struct _GskGpuNodeProcessor GskGpuNodeProcessor;
|
||||||
|
typedef struct _GskGpuPatternWriter GskGpuPatternWriter;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GSK_GPU_GLOBAL_MATRIX = (1 << 0),
|
GSK_GPU_GLOBAL_MATRIX = (1 << 0),
|
||||||
@ -87,14 +103,22 @@ struct _GskGpuNodeProcessor
|
|||||||
GskGpuGlobals pending_globals;
|
GskGpuGlobals pending_globals;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct _GskGpuPatternWriter
|
||||||
|
{
|
||||||
|
GskGpuFrame *frame;
|
||||||
|
|
||||||
|
graphene_rect_t bounds;
|
||||||
|
graphene_point_t offset;
|
||||||
|
graphene_vec2_t scale;
|
||||||
|
|
||||||
|
GskGpuBufferWriter writer;
|
||||||
|
GskGpuPatternImages images;
|
||||||
|
};
|
||||||
|
|
||||||
static void gsk_gpu_node_processor_add_node (GskGpuNodeProcessor *self,
|
static void gsk_gpu_node_processor_add_node (GskGpuNodeProcessor *self,
|
||||||
GskRenderNode *node);
|
GskRenderNode *node);
|
||||||
static gboolean gsk_gpu_node_processor_create_node_pattern (GskGpuNodeProcessor *self,
|
static gboolean gsk_gpu_node_processor_create_node_pattern (GskGpuPatternWriter *self,
|
||||||
GskGpuBufferWriter *writer,
|
GskRenderNode *node);
|
||||||
GskRenderNode *node,
|
|
||||||
GskGpuShaderImage *images,
|
|
||||||
gsize n_images,
|
|
||||||
gsize *out_n_images);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gsk_gpu_node_processor_finish (GskGpuNodeProcessor *self)
|
gsk_gpu_node_processor_finish (GskGpuNodeProcessor *self)
|
||||||
@ -186,6 +210,87 @@ gsk_gpu_node_processor_process (GskGpuFrame *frame,
|
|||||||
gsk_gpu_node_processor_finish (&self);
|
gsk_gpu_node_processor_finish (&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gsk_gpu_pattern_writer_init (GskGpuPatternWriter *self,
|
||||||
|
GskGpuFrame *frame,
|
||||||
|
const graphene_vec2_t *scale,
|
||||||
|
const graphene_point_t *offset,
|
||||||
|
const graphene_rect_t *bounds)
|
||||||
|
{
|
||||||
|
self->frame = frame;
|
||||||
|
self->bounds = GRAPHENE_RECT_INIT (bounds->origin.x + offset->x,
|
||||||
|
bounds->origin.y + offset->y,
|
||||||
|
bounds->size.width,
|
||||||
|
bounds->size.height);
|
||||||
|
self->offset = *offset;
|
||||||
|
self->scale = *scale;
|
||||||
|
|
||||||
|
gsk_gpu_frame_write_buffer_memory (frame, &self->writer);
|
||||||
|
gsk_gpu_pattern_images_init (&self->images);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gsk_gpu_pattern_writer_finish (GskGpuPatternWriter *self)
|
||||||
|
{
|
||||||
|
gsk_gpu_pattern_images_clear (&self->images);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gsk_gpu_pattern_writer_abort (GskGpuPatternWriter *self)
|
||||||
|
{
|
||||||
|
gsk_gpu_buffer_writer_abort (&self->writer);
|
||||||
|
|
||||||
|
gsk_gpu_pattern_writer_finish (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gsk_gpu_pattern_writer_commit_op (GskGpuPatternWriter *self,
|
||||||
|
GskGpuShaderClip clip)
|
||||||
|
{
|
||||||
|
guint32 pattern_id;
|
||||||
|
GskGpuShaderImage *images;
|
||||||
|
gsize n_images;
|
||||||
|
|
||||||
|
pattern_id = gsk_gpu_buffer_writer_commit (&self->writer) / sizeof (float);
|
||||||
|
n_images = gsk_gpu_pattern_images_get_size (&self->images);
|
||||||
|
images = gsk_gpu_pattern_images_steal (&self->images);
|
||||||
|
|
||||||
|
{
|
||||||
|
for (gsize i = 0; i < n_images; i++)
|
||||||
|
g_assert (images[i].image);
|
||||||
|
}
|
||||||
|
|
||||||
|
gsk_gpu_uber_op (self->frame,
|
||||||
|
clip,
|
||||||
|
&self->bounds,
|
||||||
|
&self->offset,
|
||||||
|
images,
|
||||||
|
n_images,
|
||||||
|
pattern_id);
|
||||||
|
|
||||||
|
gsk_gpu_pattern_writer_finish (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gsk_gpu_pattern_writer_add_image (GskGpuPatternWriter *self,
|
||||||
|
GskGpuImage *image,
|
||||||
|
GskGpuSampler sampler,
|
||||||
|
guint32 *out_descriptor)
|
||||||
|
{
|
||||||
|
if (gsk_gpu_pattern_images_get_size (&self->images) >= 16)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
*out_descriptor = gsk_gpu_frame_get_image_descriptor (self->frame, image, sampler);
|
||||||
|
gsk_gpu_pattern_images_append (&self->images,
|
||||||
|
&(GskGpuShaderImage) {
|
||||||
|
image,
|
||||||
|
sampler,
|
||||||
|
*out_descriptor
|
||||||
|
});
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
extract_scale_from_transform (GskTransform *transform,
|
extract_scale_from_transform (GskTransform *transform,
|
||||||
float *out_scale_x,
|
float *out_scale_x,
|
||||||
@ -321,7 +426,9 @@ gsk_gpu_node_processor_clip_node_bounds (GskGpuNodeProcessor *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static GskGpuImage *
|
static GskGpuImage *
|
||||||
gsk_gpu_node_procesor_get_node_as_image (GskGpuNodeProcessor *self,
|
gsk_gpu_get_node_as_image (GskGpuFrame *frame,
|
||||||
|
const graphene_rect_t *clip_bounds,
|
||||||
|
const graphene_vec2_t *scale,
|
||||||
GskRenderNode *node,
|
GskRenderNode *node,
|
||||||
graphene_rect_t *out_bounds)
|
graphene_rect_t *out_bounds)
|
||||||
{
|
{
|
||||||
@ -332,13 +439,12 @@ gsk_gpu_node_procesor_get_node_as_image (GskGpuNodeProcessor *self,
|
|||||||
case GSK_TEXTURE_NODE:
|
case GSK_TEXTURE_NODE:
|
||||||
{
|
{
|
||||||
GdkTexture *texture = gsk_texture_node_get_texture (node);
|
GdkTexture *texture = gsk_texture_node_get_texture (node);
|
||||||
GskGpuDevice *device = gsk_gpu_frame_get_device (self->frame);
|
GskGpuDevice *device = gsk_gpu_frame_get_device (frame);
|
||||||
gint64 timestamp = gsk_gpu_frame_get_timestamp (self->frame);
|
gint64 timestamp = gsk_gpu_frame_get_timestamp (frame);
|
||||||
result = gsk_gpu_device_lookup_texture_image (device, texture, timestamp);
|
result = gsk_gpu_device_lookup_texture_image (device, texture, timestamp);
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
{
|
{
|
||||||
result = gsk_gpu_upload_texture_op (self->frame, texture);
|
result = gsk_gpu_upload_texture_op (frame, texture);
|
||||||
g_object_ref (result);
|
|
||||||
gsk_gpu_device_cache_texture_image (device, texture, timestamp, result);
|
gsk_gpu_device_cache_texture_image (device, texture, timestamp, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,15 +456,14 @@ gsk_gpu_node_procesor_get_node_as_image (GskGpuNodeProcessor *self,
|
|||||||
{
|
{
|
||||||
graphene_rect_t clipped;
|
graphene_rect_t clipped;
|
||||||
|
|
||||||
graphene_rect_offset_r (&self->clip.rect.bounds, - self->offset.x, - self->offset.y, &clipped);
|
graphene_rect_intersection (clip_bounds, &node->bounds, &clipped);
|
||||||
graphene_rect_intersection (&clipped, &node->bounds, &clipped);
|
|
||||||
|
|
||||||
if (clipped.size.width == 0 || clipped.size.height == 0)
|
if (clipped.size.width == 0 || clipped.size.height == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
result = gsk_gpu_upload_cairo_op (self->frame,
|
result = gsk_gpu_upload_cairo_op (frame,
|
||||||
node,
|
node,
|
||||||
&self->scale,
|
scale,
|
||||||
&clipped);
|
&clipped);
|
||||||
g_object_ref (result);
|
g_object_ref (result);
|
||||||
|
|
||||||
@ -370,15 +475,14 @@ gsk_gpu_node_procesor_get_node_as_image (GskGpuNodeProcessor *self,
|
|||||||
{
|
{
|
||||||
graphene_rect_t clipped;
|
graphene_rect_t clipped;
|
||||||
|
|
||||||
graphene_rect_offset_r (&self->clip.rect.bounds, - self->offset.x, - self->offset.y, &clipped);
|
graphene_rect_intersection (clip_bounds, &node->bounds, &clipped);
|
||||||
graphene_rect_intersection (&clipped, &node->bounds, &clipped);
|
|
||||||
|
|
||||||
if (clipped.size.width == 0 || clipped.size.height == 0)
|
if (clipped.size.width == 0 || clipped.size.height == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
GSK_DEBUG (FALLBACK, "Offscreening node '%s'", g_type_name_from_instance ((GTypeInstance *) node));
|
GSK_DEBUG (FALLBACK, "Offscreening node '%s'", g_type_name_from_instance ((GTypeInstance *) node));
|
||||||
result = gsk_gpu_render_pass_op_offscreen (self->frame,
|
result = gsk_gpu_render_pass_op_offscreen (frame,
|
||||||
&self->scale,
|
scale,
|
||||||
&clipped,
|
&clipped,
|
||||||
node);
|
node);
|
||||||
|
|
||||||
@ -418,32 +522,26 @@ static void
|
|||||||
gsk_gpu_node_processor_add_node_as_pattern (GskGpuNodeProcessor *self,
|
gsk_gpu_node_processor_add_node_as_pattern (GskGpuNodeProcessor *self,
|
||||||
GskRenderNode *node)
|
GskRenderNode *node)
|
||||||
{
|
{
|
||||||
GskGpuBufferWriter writer;
|
GskGpuPatternWriter writer;
|
||||||
guint32 pattern_id;
|
|
||||||
GskGpuShaderImage images[2];
|
|
||||||
gsize n_images;
|
|
||||||
|
|
||||||
gsk_gpu_frame_write_buffer_memory (self->frame, &writer);
|
gsk_gpu_pattern_writer_init (&writer,
|
||||||
|
self->frame,
|
||||||
|
&self->scale,
|
||||||
|
&self->offset,
|
||||||
|
&node->bounds);
|
||||||
|
|
||||||
if (!gsk_gpu_node_processor_create_node_pattern (self, &writer, node, images, G_N_ELEMENTS (images), &n_images))
|
if (!gsk_gpu_node_processor_create_node_pattern (&writer, node))
|
||||||
{
|
{
|
||||||
gsk_gpu_buffer_writer_abort (&writer);
|
gsk_gpu_pattern_writer_abort (&writer);
|
||||||
GSK_DEBUG (FALLBACK, "Pattern shader for node %s failed", g_type_name_from_instance ((GTypeInstance *) node));
|
GSK_DEBUG (FALLBACK, "Pattern shader for node %s failed", g_type_name_from_instance ((GTypeInstance *) node));
|
||||||
gsk_gpu_node_processor_add_fallback_node (self, node);
|
gsk_gpu_node_processor_add_fallback_node (self, node);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gsk_gpu_buffer_writer_append_uint (&writer, GSK_GPU_PATTERN_DONE);
|
gsk_gpu_buffer_writer_append_uint (&writer.writer, GSK_GPU_PATTERN_DONE);
|
||||||
|
|
||||||
pattern_id = gsk_gpu_buffer_writer_commit (&writer) / sizeof (float);
|
gsk_gpu_pattern_writer_commit_op (&writer,
|
||||||
|
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds));
|
||||||
gsk_gpu_uber_op (self->frame,
|
|
||||||
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds),
|
|
||||||
&node->bounds,
|
|
||||||
&self->offset,
|
|
||||||
g_memdup (images, sizeof (GskGpuShaderImage) * n_images),
|
|
||||||
n_images,
|
|
||||||
pattern_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -532,23 +630,14 @@ gsk_gpu_node_processor_add_clip_node (GskGpuNodeProcessor *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gsk_gpu_node_processor_create_clip_pattern (GskGpuNodeProcessor *self,
|
gsk_gpu_node_processor_create_clip_pattern (GskGpuPatternWriter *self,
|
||||||
GskGpuBufferWriter *writer,
|
GskRenderNode *node)
|
||||||
GskRenderNode *node,
|
|
||||||
GskGpuShaderImage *images,
|
|
||||||
gsize n_images,
|
|
||||||
gsize *out_n_images)
|
|
||||||
{
|
{
|
||||||
if (!gsk_gpu_node_processor_create_node_pattern (self,
|
if (!gsk_gpu_node_processor_create_node_pattern (self, gsk_opacity_node_get_child (node)))
|
||||||
writer,
|
|
||||||
gsk_opacity_node_get_child (node),
|
|
||||||
images,
|
|
||||||
n_images,
|
|
||||||
out_n_images))
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
gsk_gpu_buffer_writer_append_uint (writer, GSK_GPU_PATTERN_CLIP);
|
gsk_gpu_buffer_writer_append_uint (&self->writer, GSK_GPU_PATTERN_CLIP);
|
||||||
gsk_gpu_buffer_writer_append_rect (writer,
|
gsk_gpu_buffer_writer_append_rect (&self->writer,
|
||||||
gsk_clip_node_get_clip (node),
|
gsk_clip_node_get_clip (node),
|
||||||
&self->offset);
|
&self->offset);
|
||||||
|
|
||||||
@ -708,15 +797,11 @@ gsk_gpu_node_processor_add_transform_node (GskGpuNodeProcessor *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gsk_gpu_node_processor_create_color_pattern (GskGpuNodeProcessor *self,
|
gsk_gpu_node_processor_create_color_pattern (GskGpuPatternWriter *self,
|
||||||
GskGpuBufferWriter *writer,
|
GskRenderNode *node)
|
||||||
GskRenderNode *node,
|
|
||||||
GskGpuShaderImage *images,
|
|
||||||
gsize n_images,
|
|
||||||
gsize *out_n_images)
|
|
||||||
{
|
{
|
||||||
gsk_gpu_buffer_writer_append_uint (writer, GSK_GPU_PATTERN_COLOR);
|
gsk_gpu_buffer_writer_append_uint (&self->writer, GSK_GPU_PATTERN_COLOR);
|
||||||
gsk_gpu_buffer_writer_append_rgba (writer, gsk_color_node_get_color (node));
|
gsk_gpu_buffer_writer_append_rgba (&self->writer, gsk_color_node_get_color (node));
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -766,63 +851,52 @@ gsk_gpu_node_processor_add_texture_node (GskGpuNodeProcessor *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gsk_gpu_node_processor_create_texture_pattern (GskGpuNodeProcessor *self,
|
gsk_gpu_node_processor_create_texture_pattern (GskGpuPatternWriter *self,
|
||||||
GskGpuBufferWriter *writer,
|
GskRenderNode *node)
|
||||||
GskRenderNode *node,
|
|
||||||
GskGpuShaderImage *images,
|
|
||||||
gsize n_images,
|
|
||||||
gsize *out_n_images)
|
|
||||||
{
|
{
|
||||||
GskGpuDevice *device;
|
GskGpuDevice *device;
|
||||||
GdkTexture *texture;
|
GdkTexture *texture;
|
||||||
gint64 timestamp;
|
gint64 timestamp;
|
||||||
|
guint32 descriptor;
|
||||||
if (n_images == 0)
|
GskGpuImage *image;
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
device = gsk_gpu_frame_get_device (self->frame);
|
device = gsk_gpu_frame_get_device (self->frame);
|
||||||
texture = gsk_texture_node_get_texture (node);
|
texture = gsk_texture_node_get_texture (node);
|
||||||
timestamp = gsk_gpu_frame_get_timestamp (self->frame);
|
timestamp = gsk_gpu_frame_get_timestamp (self->frame);
|
||||||
|
|
||||||
images[0].image = gsk_gpu_device_lookup_texture_image (device, texture, timestamp);
|
image = gsk_gpu_device_lookup_texture_image (device, texture, timestamp);
|
||||||
if (images[0].image == NULL)
|
if (image == NULL)
|
||||||
{
|
{
|
||||||
images[0].image = gsk_gpu_upload_texture_op (self->frame, texture);
|
image = gsk_gpu_upload_texture_op (self->frame, texture);
|
||||||
gsk_gpu_device_cache_texture_image (device, texture, timestamp, images[0].image);
|
gsk_gpu_device_cache_texture_image (device, texture, timestamp, image);
|
||||||
}
|
}
|
||||||
images[0].sampler = GSK_GPU_SAMPLER_DEFAULT;
|
|
||||||
images[0].descriptor = gsk_gpu_frame_get_image_descriptor (self->frame,
|
|
||||||
images[0].image,
|
|
||||||
images[0].sampler);
|
|
||||||
*out_n_images = 1;
|
|
||||||
|
|
||||||
gsk_gpu_buffer_writer_append_uint (writer, GSK_GPU_PATTERN_TEXTURE);
|
if (!gsk_gpu_pattern_writer_add_image (self, image, GSK_GPU_SAMPLER_DEFAULT, &descriptor))
|
||||||
gsk_gpu_buffer_writer_append_uint (writer, images[0].descriptor);
|
return FALSE;
|
||||||
gsk_gpu_buffer_writer_append_rect (writer, &node->bounds, &self->offset);
|
|
||||||
|
gsk_gpu_buffer_writer_append_uint (&self->writer, GSK_GPU_PATTERN_TEXTURE);
|
||||||
|
gsk_gpu_buffer_writer_append_uint (&self->writer, descriptor);
|
||||||
|
gsk_gpu_buffer_writer_append_rect (&self->writer, &node->bounds, &self->offset);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gsk_gpu_node_processor_create_linear_gradient_pattern (GskGpuNodeProcessor *self,
|
gsk_gpu_node_processor_create_linear_gradient_pattern (GskGpuPatternWriter *self,
|
||||||
GskGpuBufferWriter *writer,
|
GskRenderNode *node)
|
||||||
GskRenderNode *node,
|
|
||||||
GskGpuShaderImage *images,
|
|
||||||
gsize n_images,
|
|
||||||
gsize *out_n_images)
|
|
||||||
{
|
{
|
||||||
if (gsk_render_node_get_node_type (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE)
|
if (gsk_render_node_get_node_type (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE)
|
||||||
gsk_gpu_buffer_writer_append_uint (writer, GSK_GPU_PATTERN_REPEATING_LINEAR_GRADIENT);
|
gsk_gpu_buffer_writer_append_uint (&self->writer, GSK_GPU_PATTERN_REPEATING_LINEAR_GRADIENT);
|
||||||
else
|
else
|
||||||
gsk_gpu_buffer_writer_append_uint (writer, GSK_GPU_PATTERN_LINEAR_GRADIENT);
|
gsk_gpu_buffer_writer_append_uint (&self->writer, GSK_GPU_PATTERN_LINEAR_GRADIENT);
|
||||||
|
|
||||||
gsk_gpu_buffer_writer_append_point (writer,
|
gsk_gpu_buffer_writer_append_point (&self->writer,
|
||||||
gsk_linear_gradient_node_get_start (node),
|
gsk_linear_gradient_node_get_start (node),
|
||||||
&self->offset);
|
&self->offset);
|
||||||
gsk_gpu_buffer_writer_append_point (writer,
|
gsk_gpu_buffer_writer_append_point (&self->writer,
|
||||||
gsk_linear_gradient_node_get_end (node),
|
gsk_linear_gradient_node_get_end (node),
|
||||||
&self->offset);
|
&self->offset);
|
||||||
gsk_gpu_buffer_writer_append_color_stops (writer,
|
gsk_gpu_buffer_writer_append_color_stops (&self->writer,
|
||||||
gsk_linear_gradient_node_get_color_stops (node, NULL),
|
gsk_linear_gradient_node_get_color_stops (node, NULL),
|
||||||
gsk_linear_gradient_node_get_n_color_stops (node));
|
gsk_linear_gradient_node_get_n_color_stops (node));
|
||||||
|
|
||||||
@ -830,26 +904,22 @@ gsk_gpu_node_processor_create_linear_gradient_pattern (GskGpuNodeProcessor *self
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gsk_gpu_node_processor_create_radial_gradient_pattern (GskGpuNodeProcessor *self,
|
gsk_gpu_node_processor_create_radial_gradient_pattern (GskGpuPatternWriter *self,
|
||||||
GskGpuBufferWriter *writer,
|
GskRenderNode *node)
|
||||||
GskRenderNode *node,
|
|
||||||
GskGpuShaderImage *images,
|
|
||||||
gsize n_images,
|
|
||||||
gsize *out_n_images)
|
|
||||||
{
|
{
|
||||||
if (gsk_render_node_get_node_type (node) == GSK_REPEATING_RADIAL_GRADIENT_NODE)
|
if (gsk_render_node_get_node_type (node) == GSK_REPEATING_RADIAL_GRADIENT_NODE)
|
||||||
gsk_gpu_buffer_writer_append_uint (writer, GSK_GPU_PATTERN_REPEATING_RADIAL_GRADIENT);
|
gsk_gpu_buffer_writer_append_uint (&self->writer, GSK_GPU_PATTERN_REPEATING_RADIAL_GRADIENT);
|
||||||
else
|
else
|
||||||
gsk_gpu_buffer_writer_append_uint (writer, GSK_GPU_PATTERN_RADIAL_GRADIENT);
|
gsk_gpu_buffer_writer_append_uint (&self->writer, GSK_GPU_PATTERN_RADIAL_GRADIENT);
|
||||||
|
|
||||||
gsk_gpu_buffer_writer_append_point (writer,
|
gsk_gpu_buffer_writer_append_point (&self->writer,
|
||||||
gsk_radial_gradient_node_get_center (node),
|
gsk_radial_gradient_node_get_center (node),
|
||||||
&self->offset);
|
&self->offset);
|
||||||
gsk_gpu_buffer_writer_append_float (writer, gsk_radial_gradient_node_get_hradius (node));
|
gsk_gpu_buffer_writer_append_float (&self->writer, gsk_radial_gradient_node_get_hradius (node));
|
||||||
gsk_gpu_buffer_writer_append_float (writer, gsk_radial_gradient_node_get_vradius (node));
|
gsk_gpu_buffer_writer_append_float (&self->writer, gsk_radial_gradient_node_get_vradius (node));
|
||||||
gsk_gpu_buffer_writer_append_float (writer, gsk_radial_gradient_node_get_start (node));
|
gsk_gpu_buffer_writer_append_float (&self->writer, gsk_radial_gradient_node_get_start (node));
|
||||||
gsk_gpu_buffer_writer_append_float (writer, gsk_radial_gradient_node_get_end (node));
|
gsk_gpu_buffer_writer_append_float (&self->writer, gsk_radial_gradient_node_get_end (node));
|
||||||
gsk_gpu_buffer_writer_append_color_stops (writer,
|
gsk_gpu_buffer_writer_append_color_stops (&self->writer,
|
||||||
gsk_radial_gradient_node_get_color_stops (node, NULL),
|
gsk_radial_gradient_node_get_color_stops (node, NULL),
|
||||||
gsk_radial_gradient_node_get_n_color_stops (node));
|
gsk_radial_gradient_node_get_n_color_stops (node));
|
||||||
|
|
||||||
@ -857,19 +927,15 @@ gsk_gpu_node_processor_create_radial_gradient_pattern (GskGpuNodeProcessor *self
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gsk_gpu_node_processor_create_conic_gradient_pattern (GskGpuNodeProcessor *self,
|
gsk_gpu_node_processor_create_conic_gradient_pattern (GskGpuPatternWriter *self,
|
||||||
GskGpuBufferWriter *writer,
|
GskRenderNode *node)
|
||||||
GskRenderNode *node,
|
|
||||||
GskGpuShaderImage *images,
|
|
||||||
gsize n_images,
|
|
||||||
gsize *out_n_images)
|
|
||||||
{
|
{
|
||||||
gsk_gpu_buffer_writer_append_uint (writer, GSK_GPU_PATTERN_CONIC_GRADIENT);
|
gsk_gpu_buffer_writer_append_uint (&self->writer, GSK_GPU_PATTERN_CONIC_GRADIENT);
|
||||||
gsk_gpu_buffer_writer_append_point (writer,
|
gsk_gpu_buffer_writer_append_point (&self->writer,
|
||||||
gsk_conic_gradient_node_get_center (node),
|
gsk_conic_gradient_node_get_center (node),
|
||||||
&self->offset);
|
&self->offset);
|
||||||
gsk_gpu_buffer_writer_append_float (writer, gsk_conic_gradient_node_get_angle (node));
|
gsk_gpu_buffer_writer_append_float (&self->writer, gsk_conic_gradient_node_get_angle (node));
|
||||||
gsk_gpu_buffer_writer_append_color_stops (writer,
|
gsk_gpu_buffer_writer_append_color_stops (&self->writer,
|
||||||
gsk_conic_gradient_node_get_color_stops (node, NULL),
|
gsk_conic_gradient_node_get_color_stops (node, NULL),
|
||||||
gsk_conic_gradient_node_get_n_color_stops (node));
|
gsk_conic_gradient_node_get_n_color_stops (node));
|
||||||
|
|
||||||
@ -877,12 +943,8 @@ gsk_gpu_node_processor_create_conic_gradient_pattern (GskGpuNodeProcessor *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gsk_gpu_node_processor_create_glyph_pattern (GskGpuNodeProcessor *self,
|
gsk_gpu_node_processor_create_glyph_pattern (GskGpuPatternWriter *self,
|
||||||
GskGpuBufferWriter *writer,
|
GskRenderNode *node)
|
||||||
GskRenderNode *node,
|
|
||||||
GskGpuShaderImage *images,
|
|
||||||
gsize n_images,
|
|
||||||
gsize *out_n_images)
|
|
||||||
{
|
{
|
||||||
GskGpuDevice *device;
|
GskGpuDevice *device;
|
||||||
const PangoGlyphInfo *glyphs;
|
const PangoGlyphInfo *glyphs;
|
||||||
@ -890,7 +952,6 @@ gsk_gpu_node_processor_create_glyph_pattern (GskGpuNodeProcessor *self,
|
|||||||
guint num_glyphs;
|
guint num_glyphs;
|
||||||
gsize i;
|
gsize i;
|
||||||
float scale, inv_scale;
|
float scale, inv_scale;
|
||||||
guint n_used;
|
|
||||||
guint32 tex_id;
|
guint32 tex_id;
|
||||||
GskGpuImage *last_image;
|
GskGpuImage *last_image;
|
||||||
graphene_point_t offset;
|
graphene_point_t offset;
|
||||||
@ -909,12 +970,11 @@ gsk_gpu_node_processor_create_glyph_pattern (GskGpuNodeProcessor *self,
|
|||||||
scale = MAX (graphene_vec2_get_x (&self->scale), graphene_vec2_get_y (&self->scale));
|
scale = MAX (graphene_vec2_get_x (&self->scale), graphene_vec2_get_y (&self->scale));
|
||||||
inv_scale = 1.f / scale;
|
inv_scale = 1.f / scale;
|
||||||
|
|
||||||
gsk_gpu_buffer_writer_append_uint (writer, GSK_GPU_PATTERN_GLYPHS);
|
gsk_gpu_buffer_writer_append_uint (&self->writer, GSK_GPU_PATTERN_GLYPHS);
|
||||||
gsk_gpu_buffer_writer_append_rgba (writer, gsk_text_node_get_color (node));
|
gsk_gpu_buffer_writer_append_rgba (&self->writer, gsk_text_node_get_color (node));
|
||||||
gsk_gpu_buffer_writer_append_uint (writer, num_glyphs);
|
gsk_gpu_buffer_writer_append_uint (&self->writer, num_glyphs);
|
||||||
|
|
||||||
last_image = NULL;
|
last_image = NULL;
|
||||||
n_used = 0;
|
|
||||||
for (i = 0; i < num_glyphs; i++)
|
for (i = 0; i < num_glyphs; i++)
|
||||||
{
|
{
|
||||||
GskGpuImage *image;
|
GskGpuImage *image;
|
||||||
@ -932,26 +992,21 @@ gsk_gpu_node_processor_create_glyph_pattern (GskGpuNodeProcessor *self,
|
|||||||
|
|
||||||
if (image != last_image)
|
if (image != last_image)
|
||||||
{
|
{
|
||||||
if (n_used >= n_images)
|
if (!gsk_gpu_pattern_writer_add_image (self, g_object_ref (image), GSK_GPU_SAMPLER_DEFAULT, &tex_id))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
tex_id = gsk_gpu_frame_get_image_descriptor (self->frame, image, GSK_GPU_SAMPLER_DEFAULT);
|
|
||||||
images[n_used].image = image;
|
|
||||||
images[n_used].sampler = GSK_GPU_SAMPLER_DEFAULT;
|
|
||||||
images[n_used].descriptor = tex_id;
|
|
||||||
last_image = image;
|
last_image = image;
|
||||||
n_used++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
graphene_rect_scale (&glyph_bounds, inv_scale, inv_scale, &glyph_bounds);
|
graphene_rect_scale (&glyph_bounds, inv_scale, inv_scale, &glyph_bounds);
|
||||||
glyph_offset = GRAPHENE_POINT_INIT (offset.x - glyph_offset.x * inv_scale + (float) glyphs[i].geometry.x_offset / PANGO_SCALE,
|
glyph_offset = GRAPHENE_POINT_INIT (offset.x - glyph_offset.x * inv_scale + (float) glyphs[i].geometry.x_offset / PANGO_SCALE,
|
||||||
offset.y - glyph_offset.y * inv_scale + (float) glyphs[i].geometry.y_offset / PANGO_SCALE);
|
offset.y - glyph_offset.y * inv_scale + (float) glyphs[i].geometry.y_offset / PANGO_SCALE);
|
||||||
|
|
||||||
gsk_gpu_buffer_writer_append_uint (writer, tex_id);
|
gsk_gpu_buffer_writer_append_uint (&self->writer, tex_id);
|
||||||
gsk_gpu_buffer_writer_append_rect (writer,
|
gsk_gpu_buffer_writer_append_rect (&self->writer,
|
||||||
&glyph_bounds,
|
&glyph_bounds,
|
||||||
&glyph_offset);
|
&glyph_offset);
|
||||||
gsk_gpu_buffer_writer_append_rect (writer,
|
gsk_gpu_buffer_writer_append_rect (&self->writer,
|
||||||
&GRAPHENE_RECT_INIT (
|
&GRAPHENE_RECT_INIT (
|
||||||
0, 0,
|
0, 0,
|
||||||
gsk_gpu_image_get_width (image) * inv_scale,
|
gsk_gpu_image_get_width (image) * inv_scale,
|
||||||
@ -962,52 +1017,32 @@ gsk_gpu_node_processor_create_glyph_pattern (GskGpuNodeProcessor *self,
|
|||||||
offset.x += (float) glyphs[i].geometry.width / PANGO_SCALE;
|
offset.x += (float) glyphs[i].geometry.width / PANGO_SCALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_n_images = n_used;
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gsk_gpu_node_processor_create_opacity_pattern (GskGpuPatternWriter *self,
|
||||||
|
GskRenderNode *node)
|
||||||
|
{
|
||||||
|
if (!gsk_gpu_node_processor_create_node_pattern (self, gsk_opacity_node_get_child (node)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
gsk_gpu_buffer_writer_append_uint (&self->writer, GSK_GPU_PATTERN_OPACITY);
|
||||||
|
gsk_gpu_buffer_writer_append_float (&self->writer, gsk_opacity_node_get_opacity (node));
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gsk_gpu_node_processor_create_opacity_pattern (GskGpuNodeProcessor *self,
|
gsk_gpu_node_processor_create_color_matrix_pattern (GskGpuPatternWriter *self,
|
||||||
GskGpuBufferWriter *writer,
|
GskRenderNode *node)
|
||||||
GskRenderNode *node,
|
|
||||||
GskGpuShaderImage *images,
|
|
||||||
gsize n_images,
|
|
||||||
gsize *out_n_images)
|
|
||||||
{
|
{
|
||||||
if (!gsk_gpu_node_processor_create_node_pattern (self,
|
if (!gsk_gpu_node_processor_create_node_pattern (self, gsk_color_matrix_node_get_child (node)))
|
||||||
writer,
|
|
||||||
gsk_opacity_node_get_child (node),
|
|
||||||
images,
|
|
||||||
n_images,
|
|
||||||
out_n_images))
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
gsk_gpu_buffer_writer_append_uint (writer, GSK_GPU_PATTERN_OPACITY);
|
gsk_gpu_buffer_writer_append_uint (&self->writer, GSK_GPU_PATTERN_COLOR_MATRIX);
|
||||||
gsk_gpu_buffer_writer_append_float (writer, gsk_opacity_node_get_opacity (node));
|
gsk_gpu_buffer_writer_append_matrix (&self->writer, gsk_color_matrix_node_get_color_matrix (node));
|
||||||
|
gsk_gpu_buffer_writer_append_vec4 (&self->writer, gsk_color_matrix_node_get_color_offset (node));
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gsk_gpu_node_processor_create_color_matrix_pattern (GskGpuNodeProcessor *self,
|
|
||||||
GskGpuBufferWriter *writer,
|
|
||||||
GskRenderNode *node,
|
|
||||||
GskGpuShaderImage *images,
|
|
||||||
gsize n_images,
|
|
||||||
gsize *out_n_images)
|
|
||||||
{
|
|
||||||
if (!gsk_gpu_node_processor_create_node_pattern (self,
|
|
||||||
writer,
|
|
||||||
gsk_color_matrix_node_get_child (node),
|
|
||||||
images,
|
|
||||||
n_images,
|
|
||||||
out_n_images))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
gsk_gpu_buffer_writer_append_uint (writer, GSK_GPU_PATTERN_COLOR_MATRIX);
|
|
||||||
gsk_gpu_buffer_writer_append_matrix (writer, gsk_color_matrix_node_get_color_matrix (node));
|
|
||||||
gsk_gpu_buffer_writer_append_vec4 (writer, gsk_color_matrix_node_get_color_offset (node));
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -1020,19 +1055,11 @@ gsk_gpu_node_processor_add_subsurface_node (GskGpuNodeProcessor *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gsk_gpu_node_processor_create_subsurface_pattern (GskGpuNodeProcessor *self,
|
gsk_gpu_node_processor_create_subsurface_pattern (GskGpuPatternWriter *self,
|
||||||
GskGpuBufferWriter *writer,
|
GskRenderNode *node)
|
||||||
GskRenderNode *node,
|
|
||||||
GskGpuShaderImage *images,
|
|
||||||
gsize n_images,
|
|
||||||
gsize *out_n_images)
|
|
||||||
{
|
{
|
||||||
return gsk_gpu_node_processor_create_node_pattern (self,
|
return gsk_gpu_node_processor_create_node_pattern (self,
|
||||||
writer,
|
gsk_subsurface_node_get_child (node));
|
||||||
gsk_subsurface_node_get_child (node),
|
|
||||||
images,
|
|
||||||
n_images,
|
|
||||||
out_n_images);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1044,19 +1071,10 @@ gsk_gpu_node_processor_add_container_node (GskGpuNodeProcessor *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gsk_gpu_node_processor_create_debug_pattern (GskGpuNodeProcessor *self,
|
gsk_gpu_node_processor_create_debug_pattern (GskGpuPatternWriter *self,
|
||||||
GskGpuBufferWriter *writer,
|
GskRenderNode *node)
|
||||||
GskRenderNode *node,
|
|
||||||
GskGpuShaderImage *images,
|
|
||||||
gsize n_images,
|
|
||||||
gsize *out_n_images)
|
|
||||||
{
|
{
|
||||||
return gsk_gpu_node_processor_create_node_pattern (self,
|
return gsk_gpu_node_processor_create_node_pattern (self, gsk_debug_node_get_child (node));
|
||||||
writer,
|
|
||||||
gsk_debug_node_get_child (node),
|
|
||||||
images,
|
|
||||||
n_images,
|
|
||||||
out_n_images);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1071,12 +1089,8 @@ static const struct
|
|||||||
GskGpuGlobals ignored_globals;
|
GskGpuGlobals ignored_globals;
|
||||||
void (* process_node) (GskGpuNodeProcessor *self,
|
void (* process_node) (GskGpuNodeProcessor *self,
|
||||||
GskRenderNode *node);
|
GskRenderNode *node);
|
||||||
gboolean (* create_pattern) (GskGpuNodeProcessor *self,
|
gboolean (* create_pattern) (GskGpuPatternWriter *self,
|
||||||
GskGpuBufferWriter *writer,
|
GskRenderNode *node);
|
||||||
GskRenderNode *node,
|
|
||||||
GskGpuShaderImage *images,
|
|
||||||
gsize n_images,
|
|
||||||
gsize *out_n_images);
|
|
||||||
} nodes_vtable[] = {
|
} nodes_vtable[] = {
|
||||||
[GSK_NOT_A_RENDER_NODE] = {
|
[GSK_NOT_A_RENDER_NODE] = {
|
||||||
0,
|
0,
|
||||||
@ -1272,17 +1286,15 @@ gsk_gpu_node_processor_add_node (GskGpuNodeProcessor *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gsk_gpu_node_processor_create_node_pattern (GskGpuNodeProcessor *self,
|
gsk_gpu_node_processor_create_node_pattern (GskGpuPatternWriter *self,
|
||||||
GskGpuBufferWriter *writer,
|
GskRenderNode *node)
|
||||||
GskRenderNode *node,
|
|
||||||
GskGpuShaderImage *images,
|
|
||||||
gsize n_images,
|
|
||||||
gsize *out_n_images)
|
|
||||||
{
|
{
|
||||||
GskRenderNodeType node_type;
|
GskRenderNodeType node_type;
|
||||||
graphene_rect_t bounds;
|
graphene_rect_t bounds;
|
||||||
guchar *tmp_data;
|
guchar *tmp_data;
|
||||||
|
GskGpuImage *image;
|
||||||
gsize tmp_size;
|
gsize tmp_size;
|
||||||
|
guint32 tex_id;
|
||||||
|
|
||||||
node_type = gsk_render_node_get_node_type (node);
|
node_type = gsk_render_node_get_node_type (node);
|
||||||
if (node_type >= G_N_ELEMENTS (nodes_vtable))
|
if (node_type >= G_N_ELEMENTS (nodes_vtable))
|
||||||
@ -1291,38 +1303,49 @@ gsk_gpu_node_processor_create_node_pattern (GskGpuNodeProcessor *self,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_n_images = 0;
|
|
||||||
|
|
||||||
if (nodes_vtable[node_type].create_pattern != NULL)
|
if (nodes_vtable[node_type].create_pattern != NULL)
|
||||||
{
|
{
|
||||||
gsize size_before = gsk_gpu_buffer_writer_get_size (writer);
|
gsize size_before = gsk_gpu_buffer_writer_get_size (&self->writer);
|
||||||
if (nodes_vtable[node_type].create_pattern (self, writer, node, images, n_images, out_n_images))
|
gsize images_before = gsk_gpu_pattern_images_get_size (&self->images);
|
||||||
|
if (nodes_vtable[node_type].create_pattern (self, node))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
gsk_gpu_buffer_writer_rewind (writer, size_before);
|
gsk_gpu_buffer_writer_rewind (&self->writer, size_before);
|
||||||
|
g_assert (gsk_gpu_pattern_images_get_size (&self->images) >= images_before);
|
||||||
|
gsk_gpu_pattern_images_set_size (&self->images, images_before);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n_images == 0)
|
tmp_data = gsk_gpu_buffer_writer_backup (&self->writer, &tmp_size);
|
||||||
return FALSE;
|
gsk_gpu_buffer_writer_abort (&self->writer);
|
||||||
|
image = gsk_gpu_get_node_as_image (self->frame,
|
||||||
|
&GRAPHENE_RECT_INIT (
|
||||||
|
self->bounds.origin.x - self->offset.x,
|
||||||
|
self->bounds.origin.y - self->offset.y,
|
||||||
|
self->bounds.size.width,
|
||||||
|
self->bounds.size.height
|
||||||
|
),
|
||||||
|
&self->scale,
|
||||||
|
node,
|
||||||
|
&bounds);
|
||||||
|
if (image == NULL)
|
||||||
|
{
|
||||||
|
gsk_gpu_buffer_writer_append_uint (&self->writer, GSK_GPU_PATTERN_COLOR);
|
||||||
|
gsk_gpu_buffer_writer_append_rgba (&self->writer, &(GdkRGBA) { 0, 0, 0, 0 });
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
tmp_data = gsk_gpu_buffer_writer_backup (writer, &tmp_size);
|
gsk_gpu_frame_write_buffer_memory (self->frame, &self->writer);
|
||||||
gsk_gpu_buffer_writer_abort (writer);
|
|
||||||
|
|
||||||
images[0].image = gsk_gpu_node_procesor_get_node_as_image (self, node, &bounds);
|
|
||||||
images[0].sampler = GSK_GPU_SAMPLER_DEFAULT;
|
|
||||||
images[0].descriptor = gsk_gpu_frame_get_image_descriptor (self->frame,
|
|
||||||
images[0].image,
|
|
||||||
images[0].sampler);
|
|
||||||
*out_n_images = 1;
|
|
||||||
|
|
||||||
gsk_gpu_frame_write_buffer_memory (self->frame, writer);
|
|
||||||
if (tmp_size)
|
if (tmp_size)
|
||||||
{
|
{
|
||||||
gsk_gpu_buffer_writer_append (writer, sizeof (float), tmp_data, tmp_size);
|
gsk_gpu_buffer_writer_append (&self->writer, sizeof (float), tmp_data, tmp_size);
|
||||||
g_free (tmp_data);
|
g_free (tmp_data);
|
||||||
}
|
}
|
||||||
gsk_gpu_buffer_writer_append_uint (writer, GSK_GPU_PATTERN_TEXTURE);
|
|
||||||
gsk_gpu_buffer_writer_append_uint (writer, images[0].descriptor);
|
if (!gsk_gpu_pattern_writer_add_image (self, image, GSK_GPU_SAMPLER_DEFAULT, &tex_id))
|
||||||
gsk_gpu_buffer_writer_append_rect (writer, &bounds, &self->offset);
|
return FALSE;
|
||||||
|
|
||||||
|
gsk_gpu_buffer_writer_append_uint (&self->writer, GSK_GPU_PATTERN_TEXTURE);
|
||||||
|
gsk_gpu_buffer_writer_append_uint (&self->writer, tex_id);
|
||||||
|
gsk_gpu_buffer_writer_append_rect (&self->writer, &bounds, &self->offset);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user