mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-14 14:20:21 +00:00
Merge branch 'wip/otte/rendernode-opaque' into 'main'
Implement occlusion culling See merge request GNOME/gtk!7425
This commit is contained in:
commit
8a61b01c06
@ -10,7 +10,6 @@
|
||||
#include "gskgpunodeprocessorprivate.h"
|
||||
#include "gskgpuopprivate.h"
|
||||
#include "gskgpurendererprivate.h"
|
||||
#include "gskgpurenderpassopprivate.h"
|
||||
#include "gskgpuuploadopprivate.h"
|
||||
|
||||
#include "gskdebugprivate.h"
|
||||
@ -559,29 +558,6 @@ copy_texture (gpointer user_data,
|
||||
*target = g_object_ref (texture);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gpu_frame_record_rect (GskGpuFrame *self,
|
||||
GskGpuImage *target,
|
||||
const cairo_rectangle_int_t *clip,
|
||||
GskRenderNode *node,
|
||||
const graphene_rect_t *viewport)
|
||||
{
|
||||
gsk_gpu_render_pass_begin_op (self,
|
||||
target,
|
||||
clip,
|
||||
GSK_RENDER_PASS_PRESENT);
|
||||
|
||||
gsk_gpu_node_processor_process (self,
|
||||
target,
|
||||
clip,
|
||||
node,
|
||||
viewport);
|
||||
|
||||
gsk_gpu_render_pass_end_op (self,
|
||||
target,
|
||||
GSK_RENDER_PASS_PRESENT);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gpu_frame_record (GskGpuFrame *self,
|
||||
gint64 timestamp,
|
||||
@ -604,20 +580,20 @@ gsk_gpu_frame_record (GskGpuFrame *self,
|
||||
cairo_rectangle_int_t rect;
|
||||
|
||||
cairo_region_get_rectangle (clip, i, &rect);
|
||||
gsk_gpu_frame_record_rect (self, target, &rect, node, viewport);
|
||||
gsk_gpu_node_processor_process (self, target, &rect, node, viewport);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gsk_gpu_frame_record_rect (self,
|
||||
target,
|
||||
&(cairo_rectangle_int_t) {
|
||||
0, 0,
|
||||
gsk_gpu_image_get_width (target),
|
||||
gsk_gpu_image_get_height (target)
|
||||
},
|
||||
node,
|
||||
viewport);
|
||||
gsk_gpu_node_processor_process (self,
|
||||
target,
|
||||
&(cairo_rectangle_int_t) {
|
||||
0, 0,
|
||||
gsk_gpu_image_get_width (target),
|
||||
gsk_gpu_image_get_height (target)
|
||||
},
|
||||
node,
|
||||
viewport);
|
||||
}
|
||||
|
||||
if (texture)
|
||||
|
@ -123,6 +123,11 @@ struct _GskGpuNodeProcessor
|
||||
|
||||
static void gsk_gpu_node_processor_add_node (GskGpuNodeProcessor *self,
|
||||
GskRenderNode *node);
|
||||
static gboolean gsk_gpu_node_processor_add_first_node (GskGpuNodeProcessor *self,
|
||||
GskGpuImage *target,
|
||||
const cairo_rectangle_int_t *clip,
|
||||
GskRenderPassType pass_type,
|
||||
GskRenderNode *node);
|
||||
static GskGpuImage * gsk_gpu_get_node_as_image (GskGpuFrame *frame,
|
||||
const graphene_rect_t *clip_bounds,
|
||||
const graphene_vec2_t *scale,
|
||||
@ -346,6 +351,7 @@ gsk_gpu_node_processor_init_draw (GskGpuNodeProcessor *self,
|
||||
gsk_gpu_render_pass_begin_op (frame,
|
||||
image,
|
||||
&area,
|
||||
&GDK_RGBA_TRANSPARENT,
|
||||
GSK_RENDER_PASS_OFFSCREEN);
|
||||
|
||||
return image;
|
||||
@ -378,7 +384,25 @@ gsk_gpu_node_processor_process (GskGpuFrame *frame,
|
||||
clip,
|
||||
viewport);
|
||||
|
||||
gsk_gpu_node_processor_add_node (&self, node);
|
||||
if (!gsk_gpu_frame_should_optimize (frame, GSK_GPU_OPTIMIZE_OCCLUSION_CULLING) ||
|
||||
!gsk_gpu_node_processor_add_first_node (&self,
|
||||
target,
|
||||
clip,
|
||||
GSK_RENDER_PASS_PRESENT,
|
||||
node))
|
||||
{
|
||||
gsk_gpu_render_pass_begin_op (frame,
|
||||
target,
|
||||
clip,
|
||||
&GDK_RGBA_TRANSPARENT,
|
||||
GSK_RENDER_PASS_PRESENT);
|
||||
|
||||
gsk_gpu_node_processor_add_node (&self, node);
|
||||
}
|
||||
|
||||
gsk_gpu_render_pass_end_op (frame,
|
||||
target,
|
||||
GSK_RENDER_PASS_PRESENT);
|
||||
|
||||
gsk_gpu_node_processor_finish (&self);
|
||||
}
|
||||
@ -660,6 +684,7 @@ gsk_gpu_copy_image (GskGpuFrame *frame,
|
||||
gsk_gpu_render_pass_begin_op (other.frame,
|
||||
copy,
|
||||
&(cairo_rectangle_int_t) { 0, 0, width, height },
|
||||
&GDK_RGBA_TRANSPARENT,
|
||||
GSK_RENDER_PASS_OFFSCREEN);
|
||||
|
||||
gsk_gpu_node_processor_sync_globals (&other, 0);
|
||||
@ -983,6 +1008,20 @@ gsk_gpu_node_processor_add_clip_node (GskGpuNodeProcessor *self,
|
||||
gsk_clip_node_get_clip (node));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gpu_node_processor_add_first_clip_node (GskGpuNodeProcessor *self,
|
||||
GskGpuImage *target,
|
||||
const cairo_rectangle_int_t *clip,
|
||||
GskRenderPassType pass_type,
|
||||
GskRenderNode *node)
|
||||
{
|
||||
return gsk_gpu_node_processor_add_first_node (self,
|
||||
target,
|
||||
clip,
|
||||
pass_type,
|
||||
gsk_clip_node_get_child (node));
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gpu_node_processor_add_rounded_clip_node_with_mask (GskGpuNodeProcessor *self,
|
||||
GskRenderNode *node)
|
||||
@ -1092,6 +1131,27 @@ gsk_gpu_node_processor_add_rounded_clip_node (GskGpuNodeProcessor *self,
|
||||
self->pending_globals |= GSK_GPU_GLOBAL_CLIP;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gpu_node_processor_add_first_rounded_clip_node (GskGpuNodeProcessor *self,
|
||||
GskGpuImage *target,
|
||||
const cairo_rectangle_int_t *clip,
|
||||
GskRenderPassType pass_type,
|
||||
GskRenderNode *node)
|
||||
{
|
||||
GskRoundedRect node_clip;
|
||||
|
||||
node_clip = *gsk_rounded_clip_node_get_clip (node);
|
||||
gsk_rounded_rect_offset (&node_clip, self->offset.x, self->offset.y);
|
||||
if (!gsk_rounded_rect_contains_rect (&node_clip, &self->clip.rect.bounds))
|
||||
return FALSE;
|
||||
|
||||
return gsk_gpu_node_processor_add_first_node (self,
|
||||
target,
|
||||
clip,
|
||||
pass_type,
|
||||
gsk_rounded_clip_node_get_child (node));
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gpu_node_processor_add_transform_node (GskGpuNodeProcessor *self,
|
||||
GskRenderNode *node)
|
||||
@ -1236,6 +1296,81 @@ gsk_gpu_node_processor_add_transform_node (GskGpuNodeProcessor *self,
|
||||
self->pending_globals |= GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gpu_node_processor_add_first_transform_node (GskGpuNodeProcessor *self,
|
||||
GskGpuImage *target,
|
||||
const cairo_rectangle_int_t *clip,
|
||||
GskRenderPassType pass_type,
|
||||
GskRenderNode *node)
|
||||
{
|
||||
GskTransform *transform;
|
||||
float dx, dy, scale_x, scale_y;
|
||||
GskGpuClip old_clip;
|
||||
graphene_point_t old_offset;
|
||||
graphene_vec2_t old_scale;
|
||||
gboolean result;
|
||||
|
||||
transform = gsk_transform_node_get_transform (node);
|
||||
|
||||
switch (gsk_transform_get_category (transform))
|
||||
{
|
||||
case GSK_TRANSFORM_CATEGORY_IDENTITY:
|
||||
case GSK_TRANSFORM_CATEGORY_2D_TRANSLATE:
|
||||
gsk_transform_to_translate (transform, &dx, &dy);
|
||||
old_offset = self->offset;
|
||||
self->offset.x += dx;
|
||||
self->offset.y += dy;
|
||||
result = gsk_gpu_node_processor_add_first_node (self,
|
||||
target,
|
||||
clip,
|
||||
pass_type,
|
||||
gsk_transform_node_get_child (node));
|
||||
self->offset = old_offset;
|
||||
return result;
|
||||
|
||||
case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
|
||||
gsk_transform_to_affine (transform, &scale_x, &scale_y, &dx, &dy);
|
||||
if (scale_x <= 0 || scale_y <= 0)
|
||||
return FALSE;
|
||||
|
||||
gsk_gpu_clip_init_copy (&old_clip, &self->clip);
|
||||
old_offset = self->offset;
|
||||
old_scale = self->scale;
|
||||
|
||||
gsk_gpu_clip_scale (&self->clip, &old_clip, scale_x, scale_y);
|
||||
self->offset.x = (self->offset.x + dx) / scale_x;
|
||||
self->offset.y = (self->offset.y + dy) / scale_y;
|
||||
graphene_vec2_init (&self->scale, fabs (scale_x), fabs (scale_y));
|
||||
graphene_vec2_multiply (&self->scale, &old_scale, &self->scale);
|
||||
|
||||
self->pending_globals |= GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP;
|
||||
|
||||
result = gsk_gpu_node_processor_add_first_node (self,
|
||||
target,
|
||||
clip,
|
||||
pass_type,
|
||||
gsk_transform_node_get_child (node));
|
||||
|
||||
self->offset = old_offset;
|
||||
self->scale = old_scale;
|
||||
gsk_gpu_clip_init_copy (&self->clip, &old_clip);
|
||||
|
||||
self->pending_globals |= GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP;
|
||||
|
||||
return result;
|
||||
|
||||
case GSK_TRANSFORM_CATEGORY_2D:
|
||||
case GSK_TRANSFORM_CATEGORY_UNKNOWN:
|
||||
case GSK_TRANSFORM_CATEGORY_ANY:
|
||||
case GSK_TRANSFORM_CATEGORY_3D:
|
||||
return FALSE;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gpu_node_processor_add_opacity_node (GskGpuNodeProcessor *self,
|
||||
GskRenderNode *node)
|
||||
@ -1360,6 +1495,31 @@ gsk_gpu_node_processor_add_color_node (GskGpuNodeProcessor *self,
|
||||
&GDK_RGBA_INIT_ALPHA (color, self->opacity));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gpu_node_processor_add_first_color_node (GskGpuNodeProcessor *self,
|
||||
GskGpuImage *target,
|
||||
const cairo_rectangle_int_t *clip,
|
||||
GskRenderPassType pass_type,
|
||||
GskRenderNode *node)
|
||||
{
|
||||
graphene_rect_t clip_bounds;
|
||||
|
||||
if (!node->fully_opaque)
|
||||
return FALSE;
|
||||
|
||||
gsk_gpu_node_processor_get_clip_bounds (self, &clip_bounds);
|
||||
if (!gsk_rect_contains_rect (&node->bounds, &clip_bounds))
|
||||
return FALSE;
|
||||
|
||||
gsk_gpu_render_pass_begin_op (self->frame,
|
||||
target,
|
||||
clip,
|
||||
gsk_color_node_get_color (node),
|
||||
pass_type);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gpu_node_processor_add_border_node (GskGpuNodeProcessor *self,
|
||||
GskRenderNode *node)
|
||||
@ -2857,16 +3017,50 @@ static void
|
||||
gsk_gpu_node_processor_add_container_node (GskGpuNodeProcessor *self,
|
||||
GskRenderNode *node)
|
||||
{
|
||||
gsize i;
|
||||
|
||||
if (self->opacity < 1.0 && !gsk_container_node_is_disjoint (node))
|
||||
{
|
||||
gsk_gpu_node_processor_add_without_opacity (self, node);
|
||||
return;
|
||||
}
|
||||
|
||||
for (guint i = 0; i < gsk_container_node_get_n_children (node); i++)
|
||||
for (i = 0; i < gsk_container_node_get_n_children (node); i++)
|
||||
gsk_gpu_node_processor_add_node (self, gsk_container_node_get_child (node, i));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gpu_node_processor_add_first_container_node (GskGpuNodeProcessor *self,
|
||||
GskGpuImage *target,
|
||||
const cairo_rectangle_int_t *clip,
|
||||
GskRenderPassType pass_type,
|
||||
GskRenderNode *node)
|
||||
{
|
||||
gsize i, n;
|
||||
|
||||
n = gsk_container_node_get_n_children (node);
|
||||
if (n == 0)
|
||||
return FALSE;
|
||||
|
||||
for (i = n - 1; ; i--)
|
||||
{
|
||||
if (gsk_gpu_node_processor_add_first_node (self,
|
||||
target,
|
||||
clip,
|
||||
pass_type,
|
||||
gsk_container_node_get_child (node, i)))
|
||||
break;
|
||||
|
||||
if (i == 0)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (i = i + 1; i < n; i++)
|
||||
gsk_gpu_node_processor_add_node (self, gsk_container_node_get_child (node, i));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gpu_node_processor_add_debug_node (GskGpuNodeProcessor *self,
|
||||
GskRenderNode *node)
|
||||
@ -2898,6 +3092,11 @@ static const struct
|
||||
GskGpuNodeFeatures features;
|
||||
void (* process_node) (GskGpuNodeProcessor *self,
|
||||
GskRenderNode *node);
|
||||
gboolean (* process_first_node) (GskGpuNodeProcessor *self,
|
||||
GskGpuImage *target,
|
||||
const cairo_rectangle_int_t *clip,
|
||||
GskRenderPassType pass_type,
|
||||
GskRenderNode *node);
|
||||
GskGpuImage * (* get_node_as_image) (GskGpuFrame *self,
|
||||
const graphene_rect_t *clip_bounds,
|
||||
const graphene_vec2_t *scale,
|
||||
@ -2909,23 +3108,27 @@ static const struct
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_CONTAINER_NODE] = {
|
||||
GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_container_node,
|
||||
gsk_gpu_node_processor_add_first_container_node,
|
||||
NULL,
|
||||
},
|
||||
[GSK_CAIRO_NODE] = {
|
||||
0,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
NULL,
|
||||
NULL,
|
||||
gsk_gpu_get_cairo_node_as_image,
|
||||
},
|
||||
[GSK_COLOR_NODE] = {
|
||||
0,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_color_node,
|
||||
gsk_gpu_node_processor_add_first_color_node,
|
||||
NULL,
|
||||
},
|
||||
[GSK_LINEAR_GRADIENT_NODE] = {
|
||||
@ -2933,41 +3136,48 @@ static const struct
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_linear_gradient_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_REPEATING_LINEAR_GRADIENT_NODE] = {
|
||||
0,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_linear_gradient_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_RADIAL_GRADIENT_NODE] = {
|
||||
0,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_radial_gradient_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_REPEATING_RADIAL_GRADIENT_NODE] = {
|
||||
0,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_radial_gradient_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_CONIC_GRADIENT_NODE] = {
|
||||
0,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_conic_gradient_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_BORDER_NODE] = {
|
||||
0,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_border_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_TEXTURE_NODE] = {
|
||||
0,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_texture_node,
|
||||
NULL,
|
||||
gsk_gpu_get_texture_node_as_image,
|
||||
},
|
||||
[GSK_INSET_SHADOW_NODE] = {
|
||||
@ -2975,17 +3185,20 @@ static const struct
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_inset_shadow_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_OUTSET_SHADOW_NODE] = {
|
||||
0,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_outset_shadow_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_TRANSFORM_NODE] = {
|
||||
GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR | GSK_GPU_GLOBAL_BLEND,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_transform_node,
|
||||
gsk_gpu_node_processor_add_first_transform_node,
|
||||
NULL,
|
||||
},
|
||||
[GSK_OPACITY_NODE] = {
|
||||
@ -2993,29 +3206,34 @@ static const struct
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_opacity_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_COLOR_MATRIX_NODE] = {
|
||||
0,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_color_matrix_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_REPEAT_NODE] = {
|
||||
0,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_repeat_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_CLIP_NODE] = {
|
||||
GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR | GSK_GPU_GLOBAL_BLEND,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_clip_node,
|
||||
gsk_gpu_node_processor_add_first_clip_node,
|
||||
NULL,
|
||||
},
|
||||
[GSK_ROUNDED_CLIP_NODE] = {
|
||||
GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR | GSK_GPU_GLOBAL_BLEND,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_rounded_clip_node,
|
||||
gsk_gpu_node_processor_add_first_rounded_clip_node,
|
||||
NULL,
|
||||
},
|
||||
[GSK_SHADOW_NODE] = {
|
||||
@ -3023,35 +3241,41 @@ static const struct
|
||||
0,
|
||||
gsk_gpu_node_processor_add_shadow_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_BLEND_NODE] = {
|
||||
0,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_blend_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_CROSS_FADE_NODE] = {
|
||||
0,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_cross_fade_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_TEXT_NODE] = {
|
||||
0,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_glyph_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_BLUR_NODE] = {
|
||||
0,
|
||||
0,
|
||||
gsk_gpu_node_processor_add_blur_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_DEBUG_NODE] = {
|
||||
GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR | GSK_GPU_GLOBAL_BLEND,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_debug_node,
|
||||
NULL,
|
||||
gsk_gpu_get_debug_node_as_image,
|
||||
},
|
||||
[GSK_GL_SHADER_NODE] = {
|
||||
@ -3059,35 +3283,41 @@ static const struct
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_TEXTURE_SCALE_NODE] = {
|
||||
0,
|
||||
0,
|
||||
gsk_gpu_node_processor_add_texture_scale_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_MASK_NODE] = {
|
||||
0,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_mask_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_FILL_NODE] = {
|
||||
0,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_fill_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_STROKE_NODE] = {
|
||||
0,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_stroke_node,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GSK_SUBSURFACE_NODE] = {
|
||||
GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR | GSK_GPU_GLOBAL_BLEND,
|
||||
GSK_GPU_HANDLE_OPACITY,
|
||||
gsk_gpu_node_processor_add_subsurface_node,
|
||||
NULL,
|
||||
gsk_gpu_get_subsurface_node_as_image,
|
||||
},
|
||||
};
|
||||
@ -3136,6 +3366,65 @@ gsk_gpu_node_processor_add_node (GskGpuNodeProcessor *self,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clip_covered_by_rect (const GskGpuClip *self,
|
||||
const graphene_point_t *offset,
|
||||
const graphene_rect_t *rect)
|
||||
{
|
||||
graphene_rect_t r = *rect;
|
||||
r.origin.x += offset->x;
|
||||
r.origin.y += offset->y;
|
||||
|
||||
return gsk_rect_contains_rect (&r, &self->rect.bounds);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gpu_node_processor_add_first_node (GskGpuNodeProcessor *self,
|
||||
GskGpuImage *target,
|
||||
const cairo_rectangle_int_t *clip,
|
||||
GskRenderPassType pass_type,
|
||||
GskRenderNode *node)
|
||||
{
|
||||
GskRenderNodeType node_type;
|
||||
graphene_rect_t opaque, clip_bounds;
|
||||
|
||||
/* This catches the corner cases of empty nodes, so after this check
|
||||
* there's quaranteed to be at least 1 pixel that needs to be drawn
|
||||
*/
|
||||
if (node->bounds.size.width == 0 || node->bounds.size.height == 0 ||
|
||||
!clip_covered_by_rect (&self->clip, &self->offset, &node->bounds))
|
||||
return FALSE;
|
||||
|
||||
node_type = gsk_render_node_get_node_type (node);
|
||||
if (node_type >= G_N_ELEMENTS (nodes_vtable))
|
||||
{
|
||||
g_critical ("unknown node type %u for %s", node_type, g_type_name_from_instance ((GTypeInstance *) node));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (nodes_vtable[node_type].process_first_node)
|
||||
return nodes_vtable[node_type].process_first_node (self, target, clip, pass_type, node);
|
||||
|
||||
/* fallback starts here */
|
||||
|
||||
if (!gsk_render_node_get_opaque_rect (node, &opaque))
|
||||
return FALSE;
|
||||
|
||||
gsk_gpu_node_processor_get_clip_bounds (self, &clip_bounds);
|
||||
if (!gsk_rect_contains_rect (&clip_bounds, &opaque))
|
||||
return FALSE;
|
||||
|
||||
gsk_gpu_render_pass_begin_op (self->frame,
|
||||
target,
|
||||
clip,
|
||||
&GDK_RGBA_TRANSPARENT,
|
||||
pass_type);
|
||||
|
||||
gsk_gpu_node_processor_add_node (self, node);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* gsk_gpu_get_node_as_image:
|
||||
* @frame: frame to render in
|
||||
|
@ -24,12 +24,13 @@
|
||||
#define GSK_GPU_MAX_FRAMES 4
|
||||
|
||||
static const GdkDebugKey gsk_gpu_optimization_keys[] = {
|
||||
{ "clear", GSK_GPU_OPTIMIZE_CLEAR, "Use shaders instead of vkCmdClearAttachment()/glClear()" },
|
||||
{ "merge", GSK_GPU_OPTIMIZE_MERGE, "Use one vkCmdDraw()/glDrawArrays() per operation" },
|
||||
{ "blit", GSK_GPU_OPTIMIZE_BLIT, "Use shaders instead of vkCmdBlit()/glBlitFramebuffer()" },
|
||||
{ "gradients", GSK_GPU_OPTIMIZE_GRADIENTS, "Don't supersample gradients" },
|
||||
{ "mipmap", GSK_GPU_OPTIMIZE_MIPMAP, "Avoid creating mipmaps" },
|
||||
{ "to-image", GSK_GPU_OPTIMIZE_TO_IMAGE, "Don't fast-path creation of images for nodes" },
|
||||
{ "clear", GSK_GPU_OPTIMIZE_CLEAR, "Use shaders instead of vkCmdClearAttachment()/glClear()" },
|
||||
{ "merge", GSK_GPU_OPTIMIZE_MERGE, "Use one vkCmdDraw()/glDrawArrays() per operation" },
|
||||
{ "blit", GSK_GPU_OPTIMIZE_BLIT, "Use shaders instead of vkCmdBlit()/glBlitFramebuffer()" },
|
||||
{ "gradients", GSK_GPU_OPTIMIZE_GRADIENTS, "Don't supersample gradients" },
|
||||
{ "mipmap", GSK_GPU_OPTIMIZE_MIPMAP, "Avoid creating mipmaps" },
|
||||
{ "to-image", GSK_GPU_OPTIMIZE_TO_IMAGE, "Don't fast-path creation of images for nodes" },
|
||||
{ "occlusion", GSK_GPU_OPTIMIZE_OCCLUSION_CULLING, "Disable occlusion culling via opaque node tracking" },
|
||||
};
|
||||
|
||||
typedef struct _GskGpuRendererPrivate GskGpuRendererPrivate;
|
||||
|
@ -22,6 +22,7 @@ struct _GskGpuRenderPassOp
|
||||
|
||||
GskGpuImage *target;
|
||||
cairo_rectangle_int_t area;
|
||||
float background[4];
|
||||
GskRenderPassType pass_type;
|
||||
};
|
||||
|
||||
@ -43,6 +44,9 @@ gsk_gpu_render_pass_op_print (GskGpuOp *op,
|
||||
|
||||
gsk_gpu_print_op (string, indent, "begin-render-pass");
|
||||
gsk_gpu_print_image (string, self->target);
|
||||
gsk_gpu_print_int_rect (string, &self->area);
|
||||
if (self->background[3] > 0)
|
||||
gsk_gpu_print_rgba (string, self->background);
|
||||
gsk_gpu_print_newline (string);
|
||||
}
|
||||
|
||||
@ -137,7 +141,16 @@ gsk_gpu_render_pass_op_vk_command (GskGpuOp *op,
|
||||
},
|
||||
.clearValueCount = 1,
|
||||
.pClearValues = (VkClearValue [1]) {
|
||||
{ .color = { .float32 = { 0.f, 0.f, 0.f, 0.f } } }
|
||||
{
|
||||
.color = {
|
||||
.float32 = {
|
||||
self->background[0],
|
||||
self->background[1],
|
||||
self->background[2],
|
||||
self->background[3]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
VK_SUBPASS_CONTENTS_INLINE);
|
||||
@ -179,7 +192,7 @@ gsk_gpu_render_pass_op_gl_command (GskGpuOp *op,
|
||||
glScissor (self->area.x, state->flip_y - self->area.y - self->area.height, self->area.width, self->area.height);
|
||||
else
|
||||
glScissor (self->area.x, self->area.y, self->area.width, self->area.height);
|
||||
glClearColor (0, 0, 0, 0);
|
||||
glClearColor (self->background[0], self->background[1], self->background[2], self->background[3]);
|
||||
glClear (GL_COLOR_BUFFER_BIT);
|
||||
|
||||
op = op->next;
|
||||
@ -311,6 +324,7 @@ void
|
||||
gsk_gpu_render_pass_begin_op (GskGpuFrame *frame,
|
||||
GskGpuImage *image,
|
||||
const cairo_rectangle_int_t *area,
|
||||
const GdkRGBA *background,
|
||||
GskRenderPassType pass_type)
|
||||
{
|
||||
GskGpuRenderPassOp *self;
|
||||
@ -319,6 +333,7 @@ gsk_gpu_render_pass_begin_op (GskGpuFrame *frame,
|
||||
|
||||
self->target = g_object_ref (image);
|
||||
self->area = *area;
|
||||
gsk_gpu_rgba_to_float (background, self->background);
|
||||
self->pass_type = pass_type;
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ typedef enum
|
||||
void gsk_gpu_render_pass_begin_op (GskGpuFrame *frame,
|
||||
GskGpuImage *image,
|
||||
const cairo_rectangle_int_t *area,
|
||||
const GdkRGBA *background,
|
||||
GskRenderPassType pass_type);
|
||||
void gsk_gpu_render_pass_end_op (GskGpuFrame *frame,
|
||||
GskGpuImage *image,
|
||||
|
@ -119,5 +119,6 @@ typedef enum {
|
||||
GSK_GPU_OPTIMIZE_GRADIENTS = 1 << 3,
|
||||
GSK_GPU_OPTIMIZE_MIPMAP = 1 << 4,
|
||||
GSK_GPU_OPTIMIZE_TO_IMAGE = 1 << 5,
|
||||
GSK_GPU_OPTIMIZE_OCCLUSION_CULLING = 1 << 6,
|
||||
} GskGpuOptimizations;
|
||||
|
||||
|
@ -85,6 +85,81 @@ gsk_rect_intersection (const graphene_rect_t *r1,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_rect_coverage:
|
||||
* @r1: a valid rectangle
|
||||
* @r2: another valid rectangle
|
||||
* @res: The result, may be one of r1/r2
|
||||
*
|
||||
* Computes the largest rectangle that is fully covered by
|
||||
* r1 and r2.
|
||||
*
|
||||
* Note that this is different from a union, which is the smallest
|
||||
* rectangle that covers the rectangles.
|
||||
*
|
||||
* The use case for this function is joining opaque rectangles.
|
||||
**/
|
||||
static inline void
|
||||
gsk_rect_coverage (const graphene_rect_t *r1,
|
||||
const graphene_rect_t *r2,
|
||||
graphene_rect_t *res)
|
||||
{
|
||||
float x1min, y1min, x2min, y2min;
|
||||
float x1max, y1max, x2max, y2max;
|
||||
float size, size2;
|
||||
graphene_rect_t r;
|
||||
|
||||
/* Assumes both rects are already normalized, as they usually are */
|
||||
size = r1->size.width * r1->size.height;
|
||||
size2 = r2->size.width * r2->size.height;
|
||||
if (size >= size2)
|
||||
{
|
||||
r = *r1;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = *r2;
|
||||
size = size2;
|
||||
}
|
||||
|
||||
x1min = MIN (r1->origin.x, r2->origin.x);
|
||||
y1min = MIN (r1->origin.y, r2->origin.y);
|
||||
x1max = MAX (r1->origin.x, r2->origin.x);
|
||||
y1max = MAX (r1->origin.y, r2->origin.y);
|
||||
x2min = MIN (r1->origin.x + r1->size.width, r2->origin.x + r2->size.width);
|
||||
y2min = MIN (r1->origin.y + r1->size.height, r2->origin.y + r2->size.height);
|
||||
x2max = MAX (r1->origin.x + r1->size.width, r2->origin.x + r2->size.width);
|
||||
y2max = MAX (r1->origin.y + r1->size.height, r2->origin.y + r2->size.height);
|
||||
|
||||
if (x2min >= x1max)
|
||||
{
|
||||
float w, h;
|
||||
w = x2min - x1max;
|
||||
h = y2max - y1min;
|
||||
size2 = w * h;
|
||||
if (size2 > size)
|
||||
{
|
||||
r = GRAPHENE_RECT_INIT (x1max, y1min, w, h);
|
||||
size = size2;
|
||||
}
|
||||
}
|
||||
|
||||
if (y2min >= y1max)
|
||||
{
|
||||
float w, h;
|
||||
w = x2max - x1min;
|
||||
h = y2min - y1max;
|
||||
size2 = w * h;
|
||||
if (size2 > size)
|
||||
{
|
||||
r = GRAPHENE_RECT_INIT (x1min, y1max, w, h);
|
||||
size = size2;
|
||||
}
|
||||
}
|
||||
|
||||
*res = r;
|
||||
}
|
||||
|
||||
static inline gboolean G_GNUC_PURE
|
||||
gsk_rect_is_empty (const graphene_rect_t *rect)
|
||||
{
|
||||
|
@ -160,6 +160,13 @@ gsk_render_node_real_diff (GskRenderNode *node1,
|
||||
gsk_render_node_diff_impossible (node1, node2, data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_render_node_real_get_opaque_rect (GskRenderNode *node,
|
||||
graphene_rect_t *out_opaque)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_render_node_class_init (GskRenderNodeClass *klass)
|
||||
{
|
||||
@ -167,6 +174,7 @@ gsk_render_node_class_init (GskRenderNodeClass *klass)
|
||||
klass->finalize = gsk_render_node_finalize;
|
||||
klass->can_diff = gsk_render_node_real_can_diff;
|
||||
klass->diff = gsk_render_node_real_diff;
|
||||
klass->get_opaque_rect = gsk_render_node_real_get_opaque_rect;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -559,6 +567,41 @@ gsk_render_node_diff (GskRenderNode *node1,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_render_node_get_opaque_rect:
|
||||
* @self: a `GskRenderNode`
|
||||
* @out_opaque: (out):
|
||||
*
|
||||
* Gets an opaque rectangle inside the node that GTK can determine to
|
||||
* be fully opaque.
|
||||
*
|
||||
* There is no guarantee that this is indeed the largest opaque rectangle or
|
||||
* that regions outside the rectangle are not opaque. This function is a best
|
||||
* effort with that goal.
|
||||
*
|
||||
* The rectangle will be fully contained in the bounds of the node.
|
||||
*
|
||||
* Returns: %TRUE if part or all of the rendernode is opaque, %FALSE if no
|
||||
* opaque region could be found.
|
||||
*
|
||||
* Since: 4.16
|
||||
**/
|
||||
gboolean
|
||||
gsk_render_node_get_opaque_rect (GskRenderNode *self,
|
||||
graphene_rect_t *out_opaque)
|
||||
{
|
||||
g_return_val_if_fail (GSK_IS_RENDER_NODE (self), FALSE);
|
||||
g_return_val_if_fail (out_opaque != NULL, FALSE);
|
||||
|
||||
if (self->fully_opaque)
|
||||
{
|
||||
*out_opaque = self->bounds;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return GSK_RENDER_NODE_GET_CLASS (self)->get_opaque_rect (self, out_opaque);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_render_node_write_to_file:
|
||||
* @node: a `GskRenderNode`
|
||||
|
@ -122,6 +122,10 @@ GDK_AVAILABLE_IN_ALL
|
||||
void gsk_render_node_get_bounds (GskRenderNode *node,
|
||||
graphene_rect_t *bounds);
|
||||
|
||||
GDK_AVAILABLE_IN_4_16
|
||||
gboolean gsk_render_node_get_opaque_rect (GskRenderNode *self,
|
||||
graphene_rect_t *out_opaque);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_render_node_draw (GskRenderNode *node,
|
||||
cairo_t *cr);
|
||||
|
@ -58,6 +58,21 @@
|
||||
*/
|
||||
#define MAX_RECTS_IN_DIFF 30
|
||||
|
||||
static gboolean
|
||||
gsk_color_stops_are_opaque (const GskColorStop *stops,
|
||||
gsize n_stops)
|
||||
{
|
||||
gsize i;
|
||||
|
||||
for (i = 0; i < n_stops; i++)
|
||||
{
|
||||
if (!gdk_rgba_is_opaque (&stops[i].color))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline void
|
||||
gsk_cairo_rectangle (cairo_t *cr,
|
||||
const graphene_rect_t *rect)
|
||||
@ -233,6 +248,7 @@ gsk_color_node_new (const GdkRGBA *rgba,
|
||||
self = gsk_render_node_alloc (GSK_COLOR_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
node->offscreen_for_opacity = FALSE;
|
||||
node->fully_opaque = gdk_rgba_is_opaque (rgba);
|
||||
|
||||
self->color = *rgba;
|
||||
gsk_rect_init_from_rect (&node->bounds, bounds);
|
||||
@ -421,6 +437,7 @@ gsk_linear_gradient_node_new (const graphene_rect_t *bounds,
|
||||
self = gsk_render_node_alloc (GSK_LINEAR_GRADIENT_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
node->offscreen_for_opacity = FALSE;
|
||||
node->fully_opaque = gsk_color_stops_are_opaque (color_stops, n_color_stops);
|
||||
|
||||
gsk_rect_init_from_rect (&node->bounds, bounds);
|
||||
gsk_rect_normalize (&node->bounds);
|
||||
@ -475,6 +492,7 @@ gsk_repeating_linear_gradient_node_new (const graphene_rect_t *bounds,
|
||||
self = gsk_render_node_alloc (GSK_REPEATING_LINEAR_GRADIENT_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
node->offscreen_for_opacity = FALSE;
|
||||
node->fully_opaque = gsk_color_stops_are_opaque (color_stops, n_color_stops);
|
||||
|
||||
gsk_rect_init_from_rect (&node->bounds, bounds);
|
||||
gsk_rect_normalize (&node->bounds);
|
||||
@ -768,6 +786,7 @@ gsk_radial_gradient_node_new (const graphene_rect_t *bounds,
|
||||
self = gsk_render_node_alloc (GSK_RADIAL_GRADIENT_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
node->offscreen_for_opacity = FALSE;
|
||||
node->fully_opaque = gsk_color_stops_are_opaque (color_stops, n_color_stops);
|
||||
|
||||
gsk_rect_init_from_rect (&node->bounds, bounds);
|
||||
gsk_rect_normalize (&node->bounds);
|
||||
@ -838,6 +857,7 @@ gsk_repeating_radial_gradient_node_new (const graphene_rect_t *bounds,
|
||||
self = gsk_render_node_alloc (GSK_REPEATING_RADIAL_GRADIENT_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
node->offscreen_for_opacity = FALSE;
|
||||
node->fully_opaque = gsk_color_stops_are_opaque (color_stops, n_color_stops);
|
||||
|
||||
gsk_rect_init_from_rect (&node->bounds, bounds);
|
||||
gsk_rect_normalize (&node->bounds);
|
||||
@ -1232,6 +1252,7 @@ gsk_conic_gradient_node_new (const graphene_rect_t *bounds,
|
||||
self = gsk_render_node_alloc (GSK_CONIC_GRADIENT_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
node->offscreen_for_opacity = FALSE;
|
||||
node->fully_opaque = gsk_color_stops_are_opaque (color_stops, n_color_stops);
|
||||
|
||||
gsk_rect_init_from_rect (&node->bounds, bounds);
|
||||
gsk_rect_normalize (&node->bounds);
|
||||
@ -1877,6 +1898,7 @@ gsk_texture_node_new (GdkTexture *texture,
|
||||
self = gsk_render_node_alloc (GSK_TEXTURE_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
node->offscreen_for_opacity = FALSE;
|
||||
node->fully_opaque = gdk_memory_format_alpha (gdk_texture_get_format (texture)) == GDK_MEMORY_ALPHA_OPAQUE;
|
||||
|
||||
self->texture = g_object_ref (texture);
|
||||
gsk_rect_init_from_rect (&node->bounds, bounds);
|
||||
@ -2095,6 +2117,9 @@ gsk_texture_scale_node_new (GdkTexture *texture,
|
||||
self = gsk_render_node_alloc (GSK_TEXTURE_SCALE_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
node->offscreen_for_opacity = FALSE;
|
||||
node->fully_opaque = gdk_memory_format_alpha (gdk_texture_get_format (texture)) == GDK_MEMORY_ALPHA_OPAQUE &&
|
||||
bounds->size.width == floor (bounds->size.width) &&
|
||||
bounds->size.height == floor (bounds->size.height);
|
||||
|
||||
self->texture = g_object_ref (texture);
|
||||
gsk_rect_init_from_rect (&node->bounds, bounds);
|
||||
@ -3158,6 +3183,7 @@ struct _GskContainerNode
|
||||
GskRenderNode render_node;
|
||||
|
||||
gboolean disjoint;
|
||||
graphene_rect_t opaque; /* Can be 0 0 0 0 to mean no opacity */
|
||||
guint n_children;
|
||||
GskRenderNode **children;
|
||||
};
|
||||
@ -3286,6 +3312,19 @@ gsk_container_node_diff (GskRenderNode *node1,
|
||||
gsk_render_node_diff_impossible (node1, node2, data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_container_node_get_opaque_rect (GskRenderNode *node,
|
||||
graphene_rect_t *opaque)
|
||||
{
|
||||
GskContainerNode *self = (GskContainerNode *) node;
|
||||
|
||||
if (self->opaque.size.width <= 0 && self->opaque.size.height <= 0)
|
||||
return FALSE;
|
||||
|
||||
*opaque = self->opaque;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_container_node_class_init (gpointer g_class,
|
||||
gpointer class_data)
|
||||
@ -3297,6 +3336,7 @@ gsk_container_node_class_init (gpointer g_class,
|
||||
node_class->finalize = gsk_container_node_finalize;
|
||||
node_class->draw = gsk_container_node_draw;
|
||||
node_class->diff = gsk_container_node_diff;
|
||||
node_class->get_opaque_rect = gsk_container_node_get_opaque_rect;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3329,25 +3369,36 @@ gsk_container_node_new (GskRenderNode **children,
|
||||
}
|
||||
else
|
||||
{
|
||||
graphene_rect_t bounds;
|
||||
graphene_rect_t child_opaque;
|
||||
gboolean have_opaque;
|
||||
|
||||
self->children = g_malloc_n (n_children, sizeof (GskRenderNode *));
|
||||
|
||||
self->children[0] = gsk_render_node_ref (children[0]);
|
||||
node->offscreen_for_opacity = children[0]->offscreen_for_opacity;
|
||||
node->preferred_depth = children[0]->preferred_depth;
|
||||
gsk_rect_init_from_rect (&bounds, &(children[0]->bounds));
|
||||
gsk_rect_init_from_rect (&node->bounds, &(children[0]->bounds));
|
||||
have_opaque = gsk_render_node_get_opaque_rect (self->children[0], &self->opaque);
|
||||
|
||||
for (guint i = 1; i < n_children; i++)
|
||||
{
|
||||
self->children[i] = gsk_render_node_ref (children[i]);
|
||||
self->disjoint = self->disjoint && !gsk_rect_intersects (&bounds, &(children[i]->bounds));
|
||||
graphene_rect_union (&bounds, &(children[i]->bounds), &bounds);
|
||||
self->disjoint = self->disjoint && !gsk_rect_intersects (&node->bounds, &(children[i]->bounds));
|
||||
graphene_rect_union (&node->bounds, &(children[i]->bounds), &node->bounds);
|
||||
node->preferred_depth = gdk_memory_depth_merge (node->preferred_depth, children[i]->preferred_depth);
|
||||
node->offscreen_for_opacity = node->offscreen_for_opacity || children[i]->offscreen_for_opacity;
|
||||
if (gsk_render_node_get_opaque_rect (self->children[i], &child_opaque))
|
||||
{
|
||||
if (have_opaque)
|
||||
gsk_rect_coverage (&self->opaque, &child_opaque, &self->opaque);
|
||||
else
|
||||
{
|
||||
self->opaque = child_opaque;
|
||||
have_opaque = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gsk_rect_init_from_rect (&node->bounds, &bounds);
|
||||
node->offscreen_for_opacity = node->offscreen_for_opacity || !self->disjoint;
|
||||
}
|
||||
|
||||
@ -3567,6 +3618,25 @@ gsk_transform_node_diff (GskRenderNode *node1,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_transform_node_get_opaque_rect (GskRenderNode *node,
|
||||
graphene_rect_t *opaque)
|
||||
{
|
||||
GskTransformNode *self = (GskTransformNode *) node;
|
||||
graphene_rect_t child_opaque;
|
||||
|
||||
if (gsk_transform_get_category (self->transform) < GSK_TRANSFORM_CATEGORY_2D_AFFINE)
|
||||
return FALSE;
|
||||
|
||||
if (!gsk_render_node_get_opaque_rect (self->child, &child_opaque))
|
||||
return FALSE;
|
||||
|
||||
gsk_transform_transform_bounds (self->transform,
|
||||
&child_opaque,
|
||||
opaque);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_transform_node_class_init (gpointer g_class,
|
||||
gpointer class_data)
|
||||
@ -3579,6 +3649,7 @@ gsk_transform_node_class_init (gpointer g_class,
|
||||
node_class->draw = gsk_transform_node_draw;
|
||||
node_class->can_diff = gsk_transform_node_can_diff;
|
||||
node_class->diff = gsk_transform_node_diff;
|
||||
node_class->get_opaque_rect = gsk_transform_node_get_opaque_rect;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3597,18 +3668,22 @@ gsk_transform_node_new (GskRenderNode *child,
|
||||
{
|
||||
GskTransformNode *self;
|
||||
GskRenderNode *node;
|
||||
GskTransformCategory category;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
|
||||
g_return_val_if_fail (transform != NULL, NULL);
|
||||
|
||||
category = gsk_transform_get_category (transform);
|
||||
|
||||
self = gsk_render_node_alloc (GSK_TRANSFORM_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
node->offscreen_for_opacity = child->offscreen_for_opacity;
|
||||
node->fully_opaque = child->fully_opaque && category >= GSK_TRANSFORM_CATEGORY_2D_AFFINE;
|
||||
|
||||
self->child = gsk_render_node_ref (child);
|
||||
self->transform = gsk_transform_ref (transform);
|
||||
|
||||
if (gsk_transform_get_category (transform) >= GSK_TRANSFORM_CATEGORY_2D_TRANSLATE)
|
||||
if (category >= GSK_TRANSFORM_CATEGORY_2D_TRANSLATE)
|
||||
gsk_transform_to_translate (transform, &self->dx, &self->dy);
|
||||
else
|
||||
self->dx = self->dy = 0;
|
||||
@ -4303,6 +4378,7 @@ gsk_repeat_node_new (const graphene_rect_t *bounds,
|
||||
}
|
||||
|
||||
node->preferred_depth = gsk_render_node_get_preferred_depth (child);
|
||||
node->fully_opaque = child->fully_opaque && gsk_rect_contains_rect (&child->bounds, &self->child_bounds);
|
||||
|
||||
return node;
|
||||
}
|
||||
@ -4407,10 +4483,23 @@ gsk_clip_node_diff (GskRenderNode *node1,
|
||||
gsk_render_node_diff_impossible (node1, node2, data);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_clip_node_get_opaque_rect (GskRenderNode *node,
|
||||
graphene_rect_t *opaque)
|
||||
{
|
||||
GskClipNode *self = (GskClipNode *) node;
|
||||
graphene_rect_t child_opaque;
|
||||
|
||||
if (!gsk_render_node_get_opaque_rect (self->child, &child_opaque))
|
||||
return FALSE;
|
||||
|
||||
return graphene_rect_intersection (&self->clip, &child_opaque, opaque);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_clip_node_class_init (gpointer g_class,
|
||||
gpointer class_data)
|
||||
gpointer class_data)
|
||||
{
|
||||
GskRenderNodeClass *node_class = g_class;
|
||||
|
||||
@ -4419,6 +4508,7 @@ gsk_clip_node_class_init (gpointer g_class,
|
||||
node_class->finalize = gsk_clip_node_finalize;
|
||||
node_class->draw = gsk_clip_node_draw;
|
||||
node_class->diff = gsk_clip_node_diff;
|
||||
node_class->get_opaque_rect = gsk_clip_node_get_opaque_rect;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4444,6 +4534,8 @@ gsk_clip_node_new (GskRenderNode *child,
|
||||
self = gsk_render_node_alloc (GSK_CLIP_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
node->offscreen_for_opacity = child->offscreen_for_opacity;
|
||||
/* because of the intersection when computing bounds */
|
||||
node->fully_opaque = child->fully_opaque;
|
||||
|
||||
self->child = gsk_render_node_ref (child);
|
||||
gsk_rect_init_from_rect (&self->clip, clip);
|
||||
@ -4557,6 +4649,39 @@ gsk_rounded_clip_node_diff (GskRenderNode *node1,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_rounded_clip_node_get_opaque_rect (GskRenderNode *node,
|
||||
graphene_rect_t *opaque)
|
||||
{
|
||||
GskRoundedClipNode *self = (GskRoundedClipNode *) node;
|
||||
graphene_rect_t child_opaque, wide_opaque, high_opaque;
|
||||
double start, end;
|
||||
|
||||
if (!gsk_render_node_get_opaque_rect (self->child, &child_opaque))
|
||||
return FALSE;
|
||||
|
||||
wide_opaque = self->clip.bounds;
|
||||
start = MAX(self->clip.corner[GSK_CORNER_TOP_LEFT].height, self->clip.corner[GSK_CORNER_TOP_RIGHT].height);
|
||||
end = MAX(self->clip.corner[GSK_CORNER_BOTTOM_LEFT].height, self->clip.corner[GSK_CORNER_BOTTOM_RIGHT].height);
|
||||
wide_opaque.size.height -= MIN (wide_opaque.size.height, start + end);
|
||||
wide_opaque.origin.y += start;
|
||||
graphene_rect_intersection (&wide_opaque, &child_opaque, &wide_opaque);
|
||||
|
||||
high_opaque = self->clip.bounds;
|
||||
start = MAX(self->clip.corner[GSK_CORNER_TOP_LEFT].width, self->clip.corner[GSK_CORNER_BOTTOM_LEFT].width);
|
||||
end = MAX(self->clip.corner[GSK_CORNER_TOP_RIGHT].width, self->clip.corner[GSK_CORNER_BOTTOM_RIGHT].width);
|
||||
high_opaque.size.width -= MIN (high_opaque.size.width, start + end);
|
||||
high_opaque.origin.x += start;
|
||||
graphene_rect_intersection (&high_opaque, &child_opaque, &high_opaque);
|
||||
|
||||
if (wide_opaque.size.width * wide_opaque.size.height > high_opaque.size.width * high_opaque.size.height)
|
||||
*opaque = wide_opaque;
|
||||
else
|
||||
*opaque = high_opaque;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_rounded_clip_node_class_init (gpointer g_class,
|
||||
gpointer class_data)
|
||||
@ -4568,6 +4693,7 @@ gsk_rounded_clip_node_class_init (gpointer g_class,
|
||||
node_class->finalize = gsk_rounded_clip_node_finalize;
|
||||
node_class->draw = gsk_rounded_clip_node_draw;
|
||||
node_class->diff = gsk_rounded_clip_node_diff;
|
||||
node_class->get_opaque_rect = gsk_rounded_clip_node_get_opaque_rect;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -5589,6 +5715,20 @@ gsk_cross_fade_node_diff (GskRenderNode *node1,
|
||||
gsk_render_node_diff_impossible (node1, node2, data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_cross_fade_node_get_opaque_rect (GskRenderNode *node,
|
||||
graphene_rect_t *opaque)
|
||||
{
|
||||
GskCrossFadeNode *self = (GskCrossFadeNode *) node;
|
||||
graphene_rect_t start_opaque, end_opaque;
|
||||
|
||||
if (!gsk_render_node_get_opaque_rect (self->start, &start_opaque) ||
|
||||
!gsk_render_node_get_opaque_rect (self->end, &end_opaque))
|
||||
return FALSE;
|
||||
|
||||
return graphene_rect_intersection (&start_opaque, &end_opaque, opaque);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_cross_fade_node_class_init (gpointer g_class,
|
||||
gpointer class_data)
|
||||
@ -5600,6 +5740,7 @@ gsk_cross_fade_node_class_init (gpointer g_class,
|
||||
node_class->finalize = gsk_cross_fade_node_finalize;
|
||||
node_class->draw = gsk_cross_fade_node_draw;
|
||||
node_class->diff = gsk_cross_fade_node_diff;
|
||||
node_class->get_opaque_rect = gsk_cross_fade_node_get_opaque_rect;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -5627,6 +5768,8 @@ gsk_cross_fade_node_new (GskRenderNode *start,
|
||||
self = gsk_render_node_alloc (GSK_CROSS_FADE_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
node->offscreen_for_opacity = TRUE;
|
||||
node->fully_opaque = start->fully_opaque && end->fully_opaque &&
|
||||
gsk_rect_equal (&start->bounds, &end->bounds);
|
||||
|
||||
self->start = gsk_render_node_ref (start);
|
||||
self->end = gsk_render_node_ref (end);
|
||||
@ -6633,6 +6776,15 @@ gsk_debug_node_diff (GskRenderNode *node1,
|
||||
gsk_render_node_diff (self1->child, self2->child, data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_debug_node_get_opaque_rect (GskRenderNode *node,
|
||||
graphene_rect_t *out_opaque)
|
||||
{
|
||||
GskDebugNode *self = (GskDebugNode *) node;
|
||||
|
||||
return gsk_render_node_get_opaque_rect (self->child, out_opaque);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_debug_node_class_init (gpointer g_class,
|
||||
gpointer class_data)
|
||||
@ -6645,6 +6797,7 @@ gsk_debug_node_class_init (gpointer g_class,
|
||||
node_class->draw = gsk_debug_node_draw;
|
||||
node_class->can_diff = gsk_debug_node_can_diff;
|
||||
node_class->diff = gsk_debug_node_diff;
|
||||
node_class->get_opaque_rect = gsk_debug_node_get_opaque_rect;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -6671,6 +6824,7 @@ gsk_debug_node_new (GskRenderNode *child,
|
||||
self = gsk_render_node_alloc (GSK_DEBUG_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
node->offscreen_for_opacity = child->offscreen_for_opacity;
|
||||
node->fully_opaque = child->fully_opaque;
|
||||
|
||||
self->child = gsk_render_node_ref (child);
|
||||
self->message = message;
|
||||
@ -7032,6 +7186,15 @@ gsk_subsurface_node_diff (GskRenderNode *node1,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_subsurface_node_get_opaque_rect (GskRenderNode *node,
|
||||
graphene_rect_t *out_opaque)
|
||||
{
|
||||
GskSubsurfaceNode *self = (GskSubsurfaceNode *) node;
|
||||
|
||||
return gsk_render_node_get_opaque_rect (self->child, out_opaque);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_subsurface_node_class_init (gpointer g_class,
|
||||
gpointer class_data)
|
||||
@ -7044,6 +7207,7 @@ gsk_subsurface_node_class_init (gpointer g_class,
|
||||
node_class->draw = gsk_subsurface_node_draw;
|
||||
node_class->can_diff = gsk_subsurface_node_can_diff;
|
||||
node_class->diff = gsk_subsurface_node_diff;
|
||||
node_class->get_opaque_rect = gsk_subsurface_node_get_opaque_rect;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -7074,6 +7238,7 @@ gsk_subsurface_node_new (GskRenderNode *child,
|
||||
self = gsk_render_node_alloc (GSK_SUBSURFACE_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
node->offscreen_for_opacity = child->offscreen_for_opacity;
|
||||
node->fully_opaque = child->fully_opaque;
|
||||
|
||||
self->child = gsk_render_node_ref (child);
|
||||
if (subsurface)
|
||||
|
@ -34,6 +34,7 @@ struct _GskRenderNode
|
||||
|
||||
guint preferred_depth : GDK_MEMORY_DEPTH_BITS;
|
||||
guint offscreen_for_opacity : 1;
|
||||
guint fully_opaque : 1;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
@ -48,14 +49,16 @@ struct _GskRenderNodeClass
|
||||
|
||||
GskRenderNodeType node_type;
|
||||
|
||||
void (* finalize) (GskRenderNode *node);
|
||||
void (* draw) (GskRenderNode *node,
|
||||
cairo_t *cr);
|
||||
gboolean (* can_diff) (const GskRenderNode *node1,
|
||||
const GskRenderNode *node2);
|
||||
void (* diff) (GskRenderNode *node1,
|
||||
GskRenderNode *node2,
|
||||
GskDiffData *data);
|
||||
void (* finalize) (GskRenderNode *node);
|
||||
void (* draw) (GskRenderNode *node,
|
||||
cairo_t *cr);
|
||||
gboolean (* can_diff) (const GskRenderNode *node1,
|
||||
const GskRenderNode *node2);
|
||||
void (* diff) (GskRenderNode *node1,
|
||||
GskRenderNode *node2,
|
||||
GskDiffData *data);
|
||||
gboolean (* get_opaque_rect) (GskRenderNode *node,
|
||||
graphene_rect_t *out_opaque);
|
||||
};
|
||||
|
||||
void gsk_render_node_init_types (void);
|
||||
|
@ -511,6 +511,7 @@ tests = [
|
||||
[ 'normalize', [ 'normalize.c', '../reftests/reftest-compare.c' ] ],
|
||||
[ 'transform' ],
|
||||
[ 'shader' ],
|
||||
[ 'opaque' ],
|
||||
[ 'path', [ 'path-utils.c' ], [ 'flaky'] ],
|
||||
[ 'path-special-cases' ],
|
||||
[ 'scaling' ],
|
||||
|
281
testsuite/gsk/opaque.c
Normal file
281
testsuite/gsk/opaque.c
Normal file
@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Red Hat Inc.
|
||||
*
|
||||
* Author:
|
||||
* Benjamin Otte <otte@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
static gboolean using_tap;
|
||||
|
||||
static gboolean
|
||||
parse_float (const char *input,
|
||||
float *out)
|
||||
{
|
||||
char *s;
|
||||
float f;
|
||||
|
||||
f = g_ascii_strtod (input, &s);
|
||||
|
||||
if (errno == ERANGE || s == input || *s != 0 ||
|
||||
isinf (f) || isnan (f))
|
||||
return FALSE;
|
||||
|
||||
*out = f;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_rect_from_filename (const char *filename,
|
||||
graphene_rect_t *out_rect)
|
||||
{
|
||||
char **parts;
|
||||
gsize n;
|
||||
gboolean result;
|
||||
|
||||
parts = g_strsplit (filename, "-", -1);
|
||||
n = g_strv_length (parts);
|
||||
if (g_str_has_suffix (parts[n-1], ".node"))
|
||||
parts[n-1][strlen(parts[n-1])-5] = 0;
|
||||
|
||||
result = n > 4 &&
|
||||
parse_float (parts[n-4], &out_rect->origin.x) &&
|
||||
parse_float (parts[n-3], &out_rect->origin.y) &&
|
||||
parse_float (parts[n-2], &out_rect->size.width) &&
|
||||
parse_float (parts[n-1], &out_rect->size.height);
|
||||
|
||||
g_strfreev (parts);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
deserialize_error_func (const GskParseLocation *start,
|
||||
const GskParseLocation *end,
|
||||
const GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
GString *string = g_string_new (user_data);
|
||||
|
||||
g_string_append_printf (string, ":%zu:%zu",
|
||||
start->lines + 1, start->line_chars + 1);
|
||||
if (start->lines != end->lines || start->line_chars != end->line_chars)
|
||||
{
|
||||
g_string_append (string, "-");
|
||||
if (start->lines != end->lines)
|
||||
g_string_append_printf (string, "%zu:", end->lines + 1);
|
||||
g_string_append_printf (string, "%zu", end->line_chars + 1);
|
||||
}
|
||||
|
||||
g_test_message ("%s", string->str);
|
||||
g_string_free (string, TRUE);
|
||||
|
||||
g_test_fail ();
|
||||
}
|
||||
|
||||
static void
|
||||
test_opaqueness (GFile *file)
|
||||
{
|
||||
GskRenderNode *node;
|
||||
char *node_file;
|
||||
GBytes *bytes;
|
||||
GError *error = NULL;
|
||||
graphene_rect_t opaque, expected;
|
||||
gboolean is_opaque;
|
||||
|
||||
bytes = g_file_load_bytes (file, NULL, NULL, &error);
|
||||
if (error)
|
||||
{
|
||||
g_test_message ("Failed to load file: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
g_test_fail ();
|
||||
return;
|
||||
}
|
||||
g_assert_nonnull (bytes);
|
||||
|
||||
node = gsk_render_node_deserialize (bytes, deserialize_error_func, file);
|
||||
g_bytes_unref (bytes);
|
||||
is_opaque = gsk_render_node_get_opaque_rect (node, &opaque);
|
||||
|
||||
node_file = g_file_get_path (file);
|
||||
if (parse_rect_from_filename (node_file, &expected))
|
||||
{
|
||||
if (is_opaque)
|
||||
{
|
||||
if (!graphene_rect_equal (&opaque, &expected))
|
||||
{
|
||||
g_test_message ("Should be %g %g %g %g but is %g %g %g %g",
|
||||
expected.origin.x, expected.origin.y,
|
||||
expected.size.width, expected.size.height,
|
||||
opaque.origin.x, opaque.origin.y,
|
||||
opaque.size.width, opaque.size.height);
|
||||
g_test_fail ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_test_message ("Should be %g %g %g %g but is not opaque",
|
||||
expected.origin.x, expected.origin.y,
|
||||
expected.size.width, expected.size.height);
|
||||
g_test_fail ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_opaque)
|
||||
{
|
||||
g_test_message ("Should not be opaque, but is %g %g %g %g",
|
||||
opaque.origin.x, opaque.origin.y,
|
||||
opaque.size.width, opaque.size.height);
|
||||
g_test_fail ();
|
||||
}
|
||||
}
|
||||
|
||||
gsk_render_node_unref (node);
|
||||
g_free (node_file);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_files (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
GFile *file1 = G_FILE (a);
|
||||
GFile *file2 = G_FILE (b);
|
||||
char *path1, *path2;
|
||||
int result;
|
||||
|
||||
path1 = g_file_get_path (file1);
|
||||
path2 = g_file_get_path (file2);
|
||||
|
||||
result = strcmp (path1, path2);
|
||||
|
||||
g_free (path1);
|
||||
g_free (path2);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
add_test_for_file (GFile *file)
|
||||
{
|
||||
GFileEnumerator *enumerator;
|
||||
GFileInfo *info;
|
||||
GList *files;
|
||||
GError *error = NULL;
|
||||
|
||||
if (g_file_query_file_type (file, 0, NULL) != G_FILE_TYPE_DIRECTORY)
|
||||
{
|
||||
g_test_add_vtable (g_file_peek_path (file),
|
||||
0,
|
||||
g_object_ref (file),
|
||||
NULL,
|
||||
(GTestFixtureFunc) test_opaqueness,
|
||||
(GTestFixtureFunc) g_object_unref);
|
||||
return;
|
||||
}
|
||||
|
||||
enumerator = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
files = NULL;
|
||||
|
||||
while ((info = g_file_enumerator_next_file (enumerator, NULL, &error)))
|
||||
{
|
||||
const char *filename;
|
||||
|
||||
filename = g_file_info_get_name (info);
|
||||
|
||||
if (!g_str_has_suffix (filename, ".node"))
|
||||
{
|
||||
g_object_unref (info);
|
||||
continue;
|
||||
}
|
||||
|
||||
files = g_list_prepend (files, g_file_get_child (file, filename));
|
||||
|
||||
g_object_unref (info);
|
||||
}
|
||||
|
||||
g_assert_no_error (error);
|
||||
g_object_unref (enumerator);
|
||||
|
||||
files = g_list_sort (files, compare_files);
|
||||
g_list_foreach (files, (GFunc) add_test_for_file, NULL);
|
||||
g_list_free_full (files, g_object_unref);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_command_line (int *argc, char ***argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < *argc; i++)
|
||||
{
|
||||
if (strcmp ((*argv)[i], "--tap") == 0)
|
||||
using_tap = TRUE;
|
||||
}
|
||||
|
||||
gtk_test_init (argc, argv);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (!parse_command_line (&argc, &argv))
|
||||
return 1;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
char *dirname;
|
||||
GFile *dir;
|
||||
|
||||
dirname = g_build_filename (g_test_get_dir (G_TEST_DIST), "opaque", NULL);
|
||||
dir = g_file_new_for_path (dirname);
|
||||
g_free (dirname);
|
||||
|
||||
add_test_for_file (dir);
|
||||
|
||||
g_object_unref (dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
GFile *file = g_file_new_for_commandline_arg (argv[i]);
|
||||
|
||||
add_test_for_file (file);
|
||||
|
||||
g_object_unref (file);
|
||||
}
|
||||
}
|
||||
|
||||
result = g_test_run ();
|
||||
|
||||
if (using_tap)
|
||||
return 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
1
testsuite/gsk/opaque/empty-color-0-0-50-50.node
Normal file
1
testsuite/gsk/opaque/empty-color-0-0-50-50.node
Normal file
@ -0,0 +1 @@
|
||||
color { }
|
1
testsuite/gsk/opaque/empty-conic-gradient-0-0-50-50.node
Normal file
1
testsuite/gsk/opaque/empty-conic-gradient-0-0-50-50.node
Normal file
@ -0,0 +1 @@
|
||||
conic-gradient { }
|
@ -0,0 +1 @@
|
||||
linear-gradient { }
|
@ -0,0 +1 @@
|
||||
radial-gradient { }
|
1
testsuite/gsk/opaque/empty-texture-scale.node
Normal file
1
testsuite/gsk/opaque/empty-texture-scale.node
Normal file
@ -0,0 +1 @@
|
||||
texture-scale { }
|
1
testsuite/gsk/opaque/empty-texture.node
Normal file
1
testsuite/gsk/opaque/empty-texture.node
Normal file
@ -0,0 +1 @@
|
||||
texture { }
|
0
testsuite/gsk/opaque/empty.node
Normal file
0
testsuite/gsk/opaque/empty.node
Normal file
26
testsuite/gsk/opaque/grid-0-0-100-100.node
Normal file
26
testsuite/gsk/opaque/grid-0-0-100-100.node
Normal file
@ -0,0 +1,26 @@
|
||||
/* the covered node */
|
||||
color {
|
||||
bounds: 30 30 40 40;
|
||||
color: black;
|
||||
}
|
||||
|
||||
container {
|
||||
color {
|
||||
bounds: 0 0 50 50;
|
||||
color: lime;
|
||||
}
|
||||
color {
|
||||
bounds: 50 0 50 50;
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
container {
|
||||
color {
|
||||
bounds: 0 50 50 50;
|
||||
color: blue;
|
||||
}
|
||||
color {
|
||||
bounds: 50 50 50 50;
|
||||
color: yellow;
|
||||
}
|
||||
}
|
12
testsuite/gsk/opaque/horizontal-merge-0-0-100-50.node
Normal file
12
testsuite/gsk/opaque/horizontal-merge-0-0-100-50.node
Normal file
@ -0,0 +1,12 @@
|
||||
color {
|
||||
bounds: 0 0 25 50;
|
||||
}
|
||||
color {
|
||||
bounds: 25 0 25 50;
|
||||
}
|
||||
color {
|
||||
bounds: 50 0 25 50;
|
||||
}
|
||||
color {
|
||||
bounds: 75 0 25 50;
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
color {
|
||||
bounds: 75 0 25 50;
|
||||
}
|
||||
color {
|
||||
bounds: 50 0 25 50;
|
||||
}
|
||||
color {
|
||||
bounds: 25 0 25 50;
|
||||
}
|
||||
color {
|
||||
bounds: 0 0 25 50;
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
color {
|
||||
bounds: 75 0 50 50;
|
||||
}
|
||||
color {
|
||||
bounds: 50 0 50 50;
|
||||
}
|
||||
color {
|
||||
bounds: 25 0 50 50;
|
||||
}
|
||||
color {
|
||||
bounds: 0 0 50 50;
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
color {
|
||||
bounds: 0 0 50 50;
|
||||
}
|
||||
color {
|
||||
bounds: 25 0 50 50;
|
||||
}
|
||||
color {
|
||||
bounds: 50 0 50 50;
|
||||
}
|
||||
color {
|
||||
bounds: 75 0 50 50;
|
||||
}
|
8
testsuite/gsk/opaque/horizontal-overlap-0-10-90-40.node
Normal file
8
testsuite/gsk/opaque/horizontal-overlap-0-10-90-40.node
Normal file
@ -0,0 +1,8 @@
|
||||
color {
|
||||
bounds: 0 0 50 50;
|
||||
color: lime;
|
||||
}
|
||||
color {
|
||||
bounds: 40 10 50 50;
|
||||
color: red;
|
||||
}
|
7
testsuite/gsk/opaque/texture-scale-noninteger.node
Normal file
7
testsuite/gsk/opaque/texture-scale-noninteger.node
Normal file
@ -0,0 +1,7 @@
|
||||
texture-scale {
|
||||
bounds: 3 0 1.5 1;
|
||||
}
|
||||
|
||||
texture-scale {
|
||||
bounds: 0 3 1 1.5;
|
||||
}
|
12
testsuite/gsk/opaque/vertical-merge-0-0-50-100.node
Normal file
12
testsuite/gsk/opaque/vertical-merge-0-0-50-100.node
Normal file
@ -0,0 +1,12 @@
|
||||
color {
|
||||
bounds: 0 0 50 25;
|
||||
}
|
||||
color {
|
||||
bounds: 0 25 50 25;
|
||||
}
|
||||
color {
|
||||
bounds: 0 50 50 25;
|
||||
}
|
||||
color {
|
||||
bounds: 0 75 50 25;
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
color {
|
||||
bounds: 0 75 50 25;
|
||||
}
|
||||
color {
|
||||
bounds: 0 50 50 25;
|
||||
}
|
||||
color {
|
||||
bounds: 0 25 50 25;
|
||||
}
|
||||
color {
|
||||
bounds: 0 0 50 25;
|
||||
}
|
12
testsuite/gsk/opaque/vertical-merge-overlap-0-0-50-125.node
Normal file
12
testsuite/gsk/opaque/vertical-merge-overlap-0-0-50-125.node
Normal file
@ -0,0 +1,12 @@
|
||||
color {
|
||||
bounds: 0 0 50 50;
|
||||
}
|
||||
color {
|
||||
bounds: 0 25 50 50;
|
||||
}
|
||||
color {
|
||||
bounds: 0 50 50 50;
|
||||
}
|
||||
color {
|
||||
bounds: 0 75 50 50;
|
||||
}
|
8
testsuite/gsk/opaque/vertical-overlap-10-0-40-90.node
Normal file
8
testsuite/gsk/opaque/vertical-overlap-10-0-40-90.node
Normal file
@ -0,0 +1,8 @@
|
||||
color {
|
||||
bounds: 0 0 50 50;
|
||||
color: lime;
|
||||
}
|
||||
color {
|
||||
bounds: 10 40 50 50;
|
||||
color: red;
|
||||
}
|
@ -177,7 +177,7 @@ file_info (const char *filename)
|
||||
unsigned int total = 0;
|
||||
unsigned int namelen = 0;
|
||||
unsigned int depth = 0;
|
||||
graphene_rect_t bounds;
|
||||
graphene_rect_t bounds, opaque;
|
||||
|
||||
node = load_node_file (filename);
|
||||
|
||||
@ -202,6 +202,15 @@ file_info (const char *filename)
|
||||
gsk_render_node_get_bounds (node, &bounds);
|
||||
g_print (_("Bounds: %g x %g\n"), bounds.size.width, bounds.size.height);
|
||||
g_print (_("Origin: %g %g\n"), bounds.origin.x, bounds.origin.y);
|
||||
if (gsk_render_node_get_opaque_rect (node, &opaque))
|
||||
{
|
||||
g_print (_("Opaque part: %g %g, %g x %g (%.0f%%)\n"),
|
||||
opaque.origin.x, opaque.origin.y,
|
||||
opaque.size.width, opaque.size.height,
|
||||
100 * (opaque.size.width * opaque.size.height) / (bounds.size.width * bounds.size.height));
|
||||
}
|
||||
else
|
||||
g_print (_("Opaque part: none\n"));
|
||||
|
||||
gsk_render_node_unref (node);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user