forked from AuroraMiddleware/gtk
Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master See merge request GNOME/gtk!2978
This commit is contained in:
commit
bb8a459fe2
@ -81,13 +81,6 @@ typedef enum
|
||||
LINEAR_FILTER = 1 << 6,
|
||||
} OffscreenFlags;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool is_offscreen;
|
||||
TextureRegion region;
|
||||
graphene_rect_t screen_rect;
|
||||
} OffscreenResult;
|
||||
|
||||
static inline void
|
||||
init_full_texture_region (TextureRegion *r,
|
||||
int texture_id)
|
||||
@ -466,15 +459,12 @@ load_vertex_data (GskQuadVertex vertex_data[GL_N_VERTICES],
|
||||
}
|
||||
|
||||
static void
|
||||
load_offscreen_vertex_data (GskQuadVertex vertex_data[GL_N_VERTICES],
|
||||
const graphene_rect_t *bounds,
|
||||
RenderOpBuilder *builder)
|
||||
fill_vertex_data (GskQuadVertex vertex_data[GL_N_VERTICES],
|
||||
const float min_x,
|
||||
const float min_y,
|
||||
const float max_x,
|
||||
const float max_y)
|
||||
{
|
||||
const float min_x = builder->dx + bounds->origin.x;
|
||||
const float min_y = builder->dy + bounds->origin.y;
|
||||
const float max_x = min_x + bounds->size.width;
|
||||
const float max_y = min_y + bounds->size.height;
|
||||
|
||||
vertex_data[0].position[0] = min_x;
|
||||
vertex_data[0].position[1] = min_y;
|
||||
vertex_data[0].uv[0] = 0;
|
||||
@ -506,15 +496,30 @@ load_offscreen_vertex_data (GskQuadVertex vertex_data[GL_N_VERTICES],
|
||||
vertex_data[5].uv[1] = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
load_offscreen_vertex_data (GskQuadVertex vertex_data[GL_N_VERTICES],
|
||||
GskRenderNode *node,
|
||||
RenderOpBuilder *builder)
|
||||
{
|
||||
const float min_x = builder->dx + node->bounds.origin.x;
|
||||
const float min_y = builder->dy + node->bounds.origin.y;
|
||||
const float max_x = min_x + node->bounds.size.width;
|
||||
const float max_y = min_y + node->bounds.size.height;
|
||||
|
||||
fill_vertex_data (vertex_data,
|
||||
min_x, min_y,
|
||||
max_x, max_y);
|
||||
}
|
||||
|
||||
|
||||
static void gsk_gl_renderer_setup_render_mode (GskGLRenderer *self);
|
||||
static bool add_offscreen_ops (GskGLRenderer *self,
|
||||
static gboolean add_offscreen_ops (GskGLRenderer *self,
|
||||
RenderOpBuilder *builder,
|
||||
const graphene_rect_t *bounds,
|
||||
GskRenderNode *child_node,
|
||||
guint flags,
|
||||
OffscreenResult *out_result) G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
|
||||
TextureRegion *region_out,
|
||||
gboolean *is_offscreen,
|
||||
guint flags) G_GNUC_WARN_UNUSED_RESULT;
|
||||
static void gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
|
||||
GskRenderNode *node,
|
||||
RenderOpBuilder *builder);
|
||||
@ -669,7 +674,7 @@ render_fallback_node (GskGLRenderer *self,
|
||||
{
|
||||
ops_set_program (builder, &self->programs->blit_program);
|
||||
ops_set_texture (builder, cached_id);
|
||||
load_offscreen_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
|
||||
load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -753,7 +758,7 @@ render_fallback_node (GskGLRenderer *self,
|
||||
|
||||
ops_set_program (builder, &self->programs->blit_program);
|
||||
ops_set_texture (builder, texture_id);
|
||||
load_offscreen_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
|
||||
load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -1226,12 +1231,16 @@ render_gl_shader_node (GskGLRenderer *self,
|
||||
if (program->id >= 0 && n_children <= G_N_ELEMENTS (program->glshader.texture_locations))
|
||||
{
|
||||
GBytes *args;
|
||||
OffscreenResult results[4];
|
||||
TextureRegion regions[4];
|
||||
gboolean is_offscreen[4];
|
||||
for (guint i = 0; i < n_children; i++)
|
||||
{
|
||||
GskRenderNode *child = gsk_gl_shader_node_get_child (node, i);
|
||||
if (!add_offscreen_ops (self, builder, &node->bounds, child,
|
||||
FORCE_OFFSCREEN | RESET_CLIP, &results[i]))
|
||||
if (!add_offscreen_ops (self, builder,
|
||||
&node->bounds,
|
||||
child,
|
||||
®ions[i], &is_offscreen[i],
|
||||
FORCE_OFFSCREEN | RESET_CLIP))
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1242,12 +1251,12 @@ render_gl_shader_node (GskGLRenderer *self,
|
||||
for (guint i = 0; i < n_children; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
ops_set_texture (builder, results[i].region.texture_id);
|
||||
ops_set_texture (builder, regions[i].texture_id);
|
||||
else
|
||||
ops_set_extra_texture (builder, results[i].region.texture_id, i);
|
||||
ops_set_extra_texture (builder, regions[i].texture_id, i);
|
||||
}
|
||||
|
||||
load_offscreen_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
|
||||
load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1330,6 +1339,9 @@ render_transform_node (GskGLRenderer *self,
|
||||
case GSK_TRANSFORM_CATEGORY_ANY:
|
||||
case GSK_TRANSFORM_CATEGORY_UNKNOWN:
|
||||
{
|
||||
TextureRegion region;
|
||||
gboolean is_offscreen;
|
||||
|
||||
if (node_supports_transform (child))
|
||||
{
|
||||
ops_push_modelview (builder, node_transform);
|
||||
@ -1338,14 +1350,16 @@ render_transform_node (GskGLRenderer *self,
|
||||
}
|
||||
else
|
||||
{
|
||||
OffscreenResult result;
|
||||
int filter_flag = 0;
|
||||
|
||||
if (!result_is_axis_aligned (node_transform, &child->bounds))
|
||||
filter_flag = LINEAR_FILTER;
|
||||
|
||||
if (add_offscreen_ops (self, builder, &child->bounds, child,
|
||||
RESET_CLIP | filter_flag, &result))
|
||||
if (add_offscreen_ops (self, builder,
|
||||
&child->bounds,
|
||||
child,
|
||||
®ion, &is_offscreen,
|
||||
RESET_CLIP | filter_flag))
|
||||
{
|
||||
/* For non-trivial transforms, we draw everything on a texture and then
|
||||
* draw the texture transformed. */
|
||||
@ -1354,13 +1368,13 @@ render_transform_node (GskGLRenderer *self,
|
||||
* for the texture.
|
||||
*/
|
||||
ops_push_modelview (builder, node_transform);
|
||||
ops_set_texture (builder, result.region.texture_id);
|
||||
ops_set_texture (builder, region.texture_id);
|
||||
ops_set_program (builder, &self->programs->blit_program);
|
||||
|
||||
load_vertex_data_with_region (ops_draw (builder, NULL),
|
||||
&child->bounds, builder,
|
||||
&result.region,
|
||||
result.is_offscreen);
|
||||
®ion,
|
||||
is_offscreen);
|
||||
ops_pop_modelview (builder);
|
||||
}
|
||||
}
|
||||
@ -1384,12 +1398,15 @@ render_opacity_node (GskGLRenderer *self,
|
||||
|
||||
if (gsk_render_node_get_node_type (child) == GSK_CONTAINER_NODE)
|
||||
{
|
||||
OffscreenResult result;
|
||||
gboolean is_offscreen;
|
||||
TextureRegion region;
|
||||
|
||||
/* The semantics of an opacity node mandate that when, e.g., two color nodes overlap,
|
||||
* there may not be any blending between them */
|
||||
if (!add_offscreen_ops (self, builder, &child->bounds, child,
|
||||
FORCE_OFFSCREEN | RESET_CLIP, &result))
|
||||
if (!add_offscreen_ops (self, builder, &child->bounds,
|
||||
child,
|
||||
®ion, &is_offscreen,
|
||||
FORCE_OFFSCREEN | RESET_CLIP))
|
||||
return;
|
||||
|
||||
prev_opacity = ops_set_opacity (builder,
|
||||
@ -1398,11 +1415,12 @@ render_opacity_node (GskGLRenderer *self,
|
||||
if (builder->current_opacity >= ((float) 0x00ff / (float) 0xffff))
|
||||
{
|
||||
ops_set_program (builder, &self->programs->blit_program);
|
||||
ops_set_texture (builder, result.region.texture_id);
|
||||
ops_set_texture (builder, region.texture_id);
|
||||
|
||||
load_vertex_data_with_region (ops_draw (builder, NULL),
|
||||
&node->bounds, builder,
|
||||
&result.region, result.is_offscreen);
|
||||
®ion,
|
||||
is_offscreen);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1624,23 +1642,27 @@ render_clipped_child (GskGLRenderer *self,
|
||||
else
|
||||
{
|
||||
/* well fuck */
|
||||
const GskRoundedRect scaled_clip = GSK_ROUNDED_RECT_INIT_FROM_RECT (transformed_clip);
|
||||
OffscreenResult result;
|
||||
const float scale_x = builder->scale_x;
|
||||
const float scale_y = builder->scale_y;
|
||||
const GskRoundedRect scaled_clip = GSK_ROUNDED_RECT_INIT (clip->origin.x * scale_x,
|
||||
clip->origin.y * scale_y,
|
||||
clip->size.width * scale_x,
|
||||
clip->size.height * scale_y);
|
||||
gboolean is_offscreen;
|
||||
TextureRegion region;
|
||||
|
||||
ops_push_clip (builder, &scaled_clip);
|
||||
if (!add_offscreen_ops (self, builder, &child->bounds,
|
||||
child, FORCE_OFFSCREEN,
|
||||
&result))
|
||||
child,
|
||||
®ion, &is_offscreen,
|
||||
FORCE_OFFSCREEN))
|
||||
g_assert_not_reached ();
|
||||
ops_pop_clip (builder);
|
||||
|
||||
ops_set_program (builder, &self->programs->blit_program);
|
||||
ops_set_texture (builder, result.region.texture_id);
|
||||
ops_set_texture (builder, region.texture_id);
|
||||
|
||||
load_vertex_data_with_region (ops_draw (builder, NULL),
|
||||
&result.screen_rect, builder,
|
||||
&result.region,
|
||||
result.is_offscreen);
|
||||
load_offscreen_vertex_data (ops_draw (builder, NULL), child, builder);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1724,18 +1746,40 @@ render_rounded_clip_node (GskGLRenderer *self,
|
||||
}
|
||||
else
|
||||
{
|
||||
OffscreenResult result;
|
||||
GskRoundedRect scaled_clip;
|
||||
gboolean is_offscreen;
|
||||
TextureRegion region;
|
||||
/* NOTE: We are *not* transforming the clip by the current modelview here.
|
||||
* We instead draw the untransformed clip to a texture and then transform
|
||||
* that texture.
|
||||
*
|
||||
* We do, however, apply the scale factor to the child clip of course.
|
||||
*/
|
||||
scaled_clip.bounds.origin.x = clip->bounds.origin.x * scale_x;
|
||||
scaled_clip.bounds.origin.y = clip->bounds.origin.y * scale_y;
|
||||
scaled_clip.bounds.size.width = clip->bounds.size.width * scale_x;
|
||||
scaled_clip.bounds.size.height = clip->bounds.size.height * scale_y;
|
||||
|
||||
ops_push_clip (builder, &transformed_clip);
|
||||
if (!add_offscreen_ops (self, builder, &node->bounds, child, 0, &result))
|
||||
/* Increase corner radius size by scale factor */
|
||||
for (i = 0; i < 4; i ++)
|
||||
{
|
||||
scaled_clip.corner[i].width = clip->corner[i].width * scale_x;
|
||||
scaled_clip.corner[i].height = clip->corner[i].height * scale_y;
|
||||
}
|
||||
|
||||
ops_push_clip (builder, &scaled_clip);
|
||||
if (!add_offscreen_ops (self, builder, &node->bounds,
|
||||
child,
|
||||
®ion, &is_offscreen,
|
||||
0))
|
||||
g_assert_not_reached ();
|
||||
|
||||
ops_pop_clip (builder);
|
||||
|
||||
|
||||
ops_set_program (builder, &self->programs->blit_program);
|
||||
ops_set_texture (builder, result.region.texture_id);
|
||||
ops_set_texture (builder, region.texture_id);
|
||||
|
||||
load_offscreen_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
|
||||
load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1745,13 +1789,17 @@ render_color_matrix_node (GskGLRenderer *self,
|
||||
RenderOpBuilder *builder)
|
||||
{
|
||||
GskRenderNode *child = gsk_color_matrix_node_get_child (node);
|
||||
OffscreenResult result;
|
||||
TextureRegion region;
|
||||
gboolean is_offscreen;
|
||||
|
||||
if (node_is_invisible (child))
|
||||
return;
|
||||
|
||||
if (!add_offscreen_ops (self, builder, &node->bounds, child,
|
||||
RESET_CLIP, &result))
|
||||
if (!add_offscreen_ops (self, builder,
|
||||
&node->bounds,
|
||||
child,
|
||||
®ion, &is_offscreen,
|
||||
RESET_CLIP))
|
||||
g_assert_not_reached ();
|
||||
|
||||
ops_set_program (builder, &self->programs->color_matrix_program);
|
||||
@ -1759,12 +1807,12 @@ render_color_matrix_node (GskGLRenderer *self,
|
||||
gsk_color_matrix_node_get_color_matrix (node),
|
||||
gsk_color_matrix_node_get_color_offset (node));
|
||||
|
||||
ops_set_texture (builder, result.region.texture_id);
|
||||
ops_set_texture (builder, region.texture_id);
|
||||
|
||||
load_vertex_data_with_region (ops_draw (builder, NULL),
|
||||
&result.screen_rect, builder,
|
||||
&result.region,
|
||||
result.is_offscreen);
|
||||
&node->bounds, builder,
|
||||
®ion,
|
||||
is_offscreen);
|
||||
}
|
||||
|
||||
static inline int
|
||||
@ -1875,16 +1923,17 @@ blur_node (GskGLRenderer *self,
|
||||
float blur_radius,
|
||||
guint extra_flags,
|
||||
TextureRegion *out_region,
|
||||
graphene_rect_t *out_rect)
|
||||
float *out_vertex_data[4]) /* min, max, min, max */
|
||||
{
|
||||
const float scale_x = builder->scale_x;
|
||||
const float scale_y = builder->scale_y;
|
||||
const float blur_extra = blur_radius * 2.0; /* 2.0 = shader radius_multiplier */
|
||||
float texture_width, texture_height;
|
||||
gboolean is_offscreen;
|
||||
TextureRegion region;
|
||||
int blurred_texture_id;
|
||||
|
||||
g_assert (blur_radius > 0);
|
||||
g_assert (out_rect);
|
||||
|
||||
/* Increase texture size for the given blur radius and scale it */
|
||||
texture_width = ceilf ((node->bounds.size.width + blur_extra));
|
||||
@ -1893,27 +1942,30 @@ blur_node (GskGLRenderer *self,
|
||||
/* Only blur this if the out region has no texture id yet */
|
||||
if (out_region->texture_id == 0)
|
||||
{
|
||||
OffscreenResult result;
|
||||
if (!add_offscreen_ops (self, builder,
|
||||
&GRAPHENE_RECT_INIT (node->bounds.origin.x - (blur_extra / 2.0),
|
||||
node->bounds.origin.y - (blur_extra / 2.0),
|
||||
texture_width, texture_height),
|
||||
node,
|
||||
RESET_CLIP | FORCE_OFFSCREEN | extra_flags, &result))
|
||||
®ion, &is_offscreen,
|
||||
RESET_CLIP | FORCE_OFFSCREEN | extra_flags))
|
||||
g_assert_not_reached ();
|
||||
|
||||
blurred_texture_id = blur_texture (self, builder,
|
||||
&result.region,
|
||||
®ion,
|
||||
texture_width * scale_x, texture_height * scale_y,
|
||||
blur_radius * scale_x,
|
||||
blur_radius * scale_y);
|
||||
init_full_texture_region (out_region, blurred_texture_id);
|
||||
}
|
||||
|
||||
out_rect->origin.x = node->bounds.origin.x - (blur_extra / 2.0f);
|
||||
out_rect->origin.y = node->bounds.origin.y - (blur_extra / 2.0f);
|
||||
out_rect->size.width = node->bounds.size.width + (blur_extra / 2.0f);
|
||||
out_rect->size.height = node->bounds.size.height + (blur_extra / 2.0f);
|
||||
if (out_vertex_data)
|
||||
{
|
||||
*out_vertex_data[0] = builder->dx + node->bounds.origin.x - (blur_extra / 2.0);
|
||||
*out_vertex_data[1] = builder->dx + node->bounds.origin.x + node->bounds.size.width + (blur_extra / 2.0);
|
||||
*out_vertex_data[2] = builder->dy + node->bounds.origin.y - (blur_extra / 2.0);
|
||||
*out_vertex_data[3] = builder->dy + node->bounds.origin.y + node->bounds.size.height + (blur_extra / 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -1925,7 +1977,7 @@ render_blur_node (GskGLRenderer *self,
|
||||
GskRenderNode *child = gsk_blur_node_get_child (node);
|
||||
TextureRegion blurred_region;
|
||||
GskTextureKey key;
|
||||
graphene_rect_t result_rect;
|
||||
float min_x, max_x, min_y, max_y;
|
||||
|
||||
if (node_is_invisible (child))
|
||||
return;
|
||||
@ -1942,14 +1994,16 @@ render_blur_node (GskGLRenderer *self,
|
||||
key.scale_y = builder->scale_y;
|
||||
key.filter = GL_NEAREST;
|
||||
blurred_region.texture_id = gsk_gl_driver_get_texture_for_key (self->gl_driver, &key);
|
||||
blur_node (self, child, builder, blur_radius, 0, &blurred_region, &result_rect);
|
||||
blur_node (self, child, builder, blur_radius, 0, &blurred_region,
|
||||
(float*[4]){&min_x, &max_x, &min_y, &max_y});
|
||||
|
||||
g_assert (blurred_region.texture_id != 0);
|
||||
|
||||
/* Draw the result */
|
||||
ops_set_program (builder, &self->programs->blit_program);
|
||||
ops_set_texture (builder, blurred_region.texture_id);
|
||||
load_offscreen_vertex_data (ops_draw (builder, NULL), &result_rect, builder);
|
||||
fill_vertex_data (ops_draw (builder, NULL), min_x, min_y, max_x, max_y);
|
||||
|
||||
|
||||
/* Add to cache for the blur node */
|
||||
gsk_gl_driver_set_texture_for_key (self->gl_driver, &key, blurred_region.texture_id);
|
||||
@ -2529,8 +2583,9 @@ render_shadow_node (GskGLRenderer *self,
|
||||
const GskShadow *shadow = gsk_shadow_node_get_shadow (node, i);
|
||||
const float dx = shadow->dx;
|
||||
const float dy = shadow->dy;
|
||||
TextureRegion region;
|
||||
gboolean is_offscreen;
|
||||
graphene_rect_t bounds;
|
||||
OffscreenResult result;
|
||||
|
||||
if (shadow->radius == 0 &&
|
||||
gsk_render_node_get_node_type (shadow_child) == GSK_TEXT_NODE)
|
||||
@ -2549,10 +2604,19 @@ render_shadow_node (GskGLRenderer *self,
|
||||
|
||||
if (shadow->radius > 0)
|
||||
{
|
||||
result.region.texture_id = 0;
|
||||
blur_node (self, shadow_child, builder, shadow->radius, NO_CACHE_PLZ, &result.region,
|
||||
&bounds);
|
||||
result.is_offscreen = true;
|
||||
float min_x;
|
||||
float min_y;
|
||||
float max_x;
|
||||
float max_y;
|
||||
|
||||
region.texture_id = 0;
|
||||
blur_node (self, shadow_child, builder, shadow->radius, NO_CACHE_PLZ, ®ion,
|
||||
(float*[4]){&min_x, &max_x, &min_y, &max_y});
|
||||
bounds.origin.x = min_x - builder->dx;
|
||||
bounds.origin.y = min_y - builder->dy;
|
||||
bounds.size.width = max_x - min_x;
|
||||
bounds.size.height = max_y - min_y;
|
||||
is_offscreen = TRUE;
|
||||
}
|
||||
else if (dx == 0 && dy == 0)
|
||||
{
|
||||
@ -2560,8 +2624,10 @@ render_shadow_node (GskGLRenderer *self,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!add_offscreen_ops (self, builder, &shadow_child->bounds, shadow_child,
|
||||
RESET_CLIP | NO_CACHE_PLZ, &result))
|
||||
if (!add_offscreen_ops (self, builder,
|
||||
&shadow_child->bounds,
|
||||
shadow_child, ®ion, &is_offscreen,
|
||||
RESET_CLIP | NO_CACHE_PLZ))
|
||||
g_assert_not_reached ();
|
||||
|
||||
bounds = shadow_child->bounds;
|
||||
@ -2569,13 +2635,13 @@ render_shadow_node (GskGLRenderer *self,
|
||||
|
||||
ops_set_program (builder, &self->programs->coloring_program);
|
||||
ops_set_color (builder, &shadow->color);
|
||||
ops_set_texture (builder, result.region.texture_id);
|
||||
ops_set_texture (builder, region.texture_id);
|
||||
|
||||
ops_offset (builder, dx, dy);
|
||||
load_vertex_data_with_region (ops_draw (builder, NULL),
|
||||
&bounds, builder,
|
||||
&result.region,
|
||||
result.is_offscreen);
|
||||
®ion,
|
||||
is_offscreen);
|
||||
ops_offset (builder, -dx, -dy);
|
||||
}
|
||||
|
||||
@ -2591,8 +2657,9 @@ render_cross_fade_node (GskGLRenderer *self,
|
||||
GskRenderNode *start_node = gsk_cross_fade_node_get_start_child (node);
|
||||
GskRenderNode *end_node = gsk_cross_fade_node_get_end_child (node);
|
||||
const float progress = gsk_cross_fade_node_get_progress (node);
|
||||
OffscreenResult start_result;
|
||||
OffscreenResult end_result;
|
||||
TextureRegion start_region;
|
||||
TextureRegion end_region;
|
||||
gboolean is_offscreen1, is_offscreen2;
|
||||
OpCrossFade *op;
|
||||
|
||||
if (progress <= 0)
|
||||
@ -2615,15 +2682,21 @@ render_cross_fade_node (GskGLRenderer *self,
|
||||
/* TODO: We create 2 textures here as big as the cross-fade node, but both the
|
||||
* start and the end node might be a lot smaller than that. */
|
||||
|
||||
if (!add_offscreen_ops (self, builder, &node->bounds, start_node,
|
||||
FORCE_OFFSCREEN | RESET_CLIP, &start_result))
|
||||
if (!add_offscreen_ops (self, builder,
|
||||
&node->bounds,
|
||||
start_node,
|
||||
&start_region, &is_offscreen1,
|
||||
FORCE_OFFSCREEN | RESET_CLIP))
|
||||
{
|
||||
gsk_gl_renderer_add_render_ops (self, end_node, builder);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!add_offscreen_ops (self, builder, &node->bounds, end_node,
|
||||
FORCE_OFFSCREEN | RESET_CLIP, &end_result))
|
||||
if (!add_offscreen_ops (self, builder,
|
||||
&node->bounds,
|
||||
end_node,
|
||||
&end_region, &is_offscreen2,
|
||||
FORCE_OFFSCREEN | RESET_CLIP))
|
||||
{
|
||||
const float prev_opacity = ops_set_opacity (builder, builder->current_opacity * progress);
|
||||
gsk_gl_renderer_add_render_ops (self, start_node, builder);
|
||||
@ -2636,11 +2709,11 @@ render_cross_fade_node (GskGLRenderer *self,
|
||||
|
||||
op = ops_begin (builder, OP_CHANGE_CROSS_FADE);
|
||||
op->progress = progress;
|
||||
op->source2 = end_result.region.texture_id;
|
||||
op->source2 = end_region.texture_id;
|
||||
|
||||
ops_set_texture (builder, start_result.region.texture_id);
|
||||
ops_set_texture (builder, start_region.texture_id);
|
||||
|
||||
load_offscreen_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
|
||||
load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -2650,38 +2723,45 @@ render_blend_node (GskGLRenderer *self,
|
||||
{
|
||||
GskRenderNode *top_child = gsk_blend_node_get_top_child (node);
|
||||
GskRenderNode *bottom_child = gsk_blend_node_get_bottom_child (node);
|
||||
OffscreenResult top_result;
|
||||
OffscreenResult bottom_result;
|
||||
TextureRegion top_region;
|
||||
TextureRegion bottom_region;
|
||||
gboolean is_offscreen1, is_offscreen2;
|
||||
OpBlend *op;
|
||||
|
||||
/* TODO: We create 2 textures here as big as the blend node, but both the
|
||||
* start and the end node might be a lot smaller than that. */
|
||||
if (!add_offscreen_ops (self, builder, &node->bounds, bottom_child,
|
||||
FORCE_OFFSCREEN | RESET_CLIP, &bottom_result))
|
||||
if (!add_offscreen_ops (self, builder,
|
||||
&node->bounds,
|
||||
bottom_child,
|
||||
&bottom_region, &is_offscreen1,
|
||||
FORCE_OFFSCREEN | RESET_CLIP))
|
||||
{
|
||||
gsk_gl_renderer_add_render_ops (self, top_child, builder);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!add_offscreen_ops (self, builder, &node->bounds, top_child,
|
||||
FORCE_OFFSCREEN | RESET_CLIP, &top_result))
|
||||
if (!add_offscreen_ops (self, builder,
|
||||
&node->bounds,
|
||||
top_child,
|
||||
&top_region, &is_offscreen2,
|
||||
FORCE_OFFSCREEN | RESET_CLIP))
|
||||
{
|
||||
load_vertex_data_with_region (ops_draw (builder, NULL),
|
||||
&node->bounds,
|
||||
builder,
|
||||
&bottom_result.region,
|
||||
&bottom_region,
|
||||
TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
ops_set_program (builder, &self->programs->blend_program);
|
||||
ops_set_texture (builder, bottom_result.region.texture_id);
|
||||
ops_set_texture (builder, bottom_region.texture_id);
|
||||
|
||||
op = ops_begin (builder, OP_CHANGE_BLEND);
|
||||
op->source2 = top_result.region.texture_id;
|
||||
op->source2 = top_region.texture_id;
|
||||
op->mode = gsk_blend_node_get_blend_mode (node);
|
||||
|
||||
load_offscreen_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
|
||||
load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -2691,7 +2771,8 @@ render_repeat_node (GskGLRenderer *self,
|
||||
{
|
||||
GskRenderNode *child = gsk_repeat_node_get_child (node);
|
||||
const graphene_rect_t *child_bounds = gsk_repeat_node_get_child_bounds (node);
|
||||
OffscreenResult result;
|
||||
TextureRegion region;
|
||||
gboolean is_offscreen;
|
||||
OpRepeat *op;
|
||||
|
||||
if (node_is_invisible (child))
|
||||
@ -2714,12 +2795,15 @@ render_repeat_node (GskGLRenderer *self,
|
||||
}
|
||||
|
||||
/* Draw the entire child on a texture */
|
||||
if (!add_offscreen_ops (self, builder, &child->bounds, child,
|
||||
RESET_CLIP, &result))
|
||||
if (!add_offscreen_ops (self, builder,
|
||||
&child->bounds,
|
||||
child,
|
||||
®ion, &is_offscreen,
|
||||
RESET_CLIP))
|
||||
g_assert_not_reached ();
|
||||
|
||||
ops_set_program (builder, &self->programs->repeat_program);
|
||||
ops_set_texture (builder, result.region.texture_id);
|
||||
ops_set_texture (builder, region.texture_id);
|
||||
|
||||
op = ops_begin (builder, OP_CHANGE_REPEAT);
|
||||
op->child_bounds[0] = (node->bounds.origin.x - child_bounds->origin.x) / child_bounds->size.width;
|
||||
@ -2727,24 +2811,24 @@ render_repeat_node (GskGLRenderer *self,
|
||||
op->child_bounds[2] = node->bounds.size.width / child_bounds->size.width;
|
||||
op->child_bounds[3] = node->bounds.size.height / child_bounds->size.height;
|
||||
|
||||
op->texture_rect[0] = result.region.x;
|
||||
op->texture_rect[2] = result.region.x2;
|
||||
op->texture_rect[0] = region.x;
|
||||
op->texture_rect[2] = region.x2;
|
||||
|
||||
if (result.is_offscreen)
|
||||
if (is_offscreen)
|
||||
{
|
||||
op->texture_rect[1] = result.region.y2;
|
||||
op->texture_rect[3] = result.region.y;
|
||||
op->texture_rect[1] = region.y2;
|
||||
op->texture_rect[3] = region.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
op->texture_rect[1] = result.region.y;
|
||||
op->texture_rect[3] = result.region.y2;
|
||||
op->texture_rect[1] = region.y;
|
||||
op->texture_rect[3] = region.y2;
|
||||
}
|
||||
|
||||
load_vertex_data_with_region (ops_draw (builder, NULL),
|
||||
&node->bounds, builder,
|
||||
&result.region,
|
||||
result.is_offscreen);
|
||||
®ion,
|
||||
is_offscreen);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -3731,17 +3815,18 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
static gboolean
|
||||
add_offscreen_ops (GskGLRenderer *self,
|
||||
RenderOpBuilder *builder,
|
||||
const graphene_rect_t *bounds,
|
||||
GskRenderNode *child_node,
|
||||
guint flags,
|
||||
OffscreenResult *result)
|
||||
TextureRegion *texture_region_out,
|
||||
gboolean *is_offscreen,
|
||||
guint flags)
|
||||
{
|
||||
float width, height;
|
||||
const float dx = builder->dx;
|
||||
const float dy = builder->dy;
|
||||
float width, height;
|
||||
float scale_x;
|
||||
float scale_y;
|
||||
int render_target;
|
||||
@ -3754,20 +3839,14 @@ add_offscreen_ops (GskGLRenderer *self,
|
||||
int filter;
|
||||
GskTextureKey key;
|
||||
int cached_id;
|
||||
graphene_rect_t screen_rect;
|
||||
int max_texture_size;
|
||||
GskRoundedRect new_clip;
|
||||
bool add_to_cache = false;
|
||||
|
||||
g_assert (result);
|
||||
graphene_rect_t viewport;
|
||||
|
||||
if (node_is_invisible (child_node))
|
||||
{
|
||||
/* Just to be safe */
|
||||
result->is_offscreen = false;
|
||||
result->screen_rect = *bounds;
|
||||
init_full_texture_region (&result->region, 0);
|
||||
return false;
|
||||
*is_offscreen = FALSE;
|
||||
init_full_texture_region (texture_region_out, 0);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* We need the child node as a texture. If it already is one, we don't need to draw
|
||||
@ -3776,11 +3855,9 @@ add_offscreen_ops (GskGLRenderer *self,
|
||||
(flags & FORCE_OFFSCREEN) == 0)
|
||||
{
|
||||
GdkTexture *texture = gsk_texture_node_get_texture (child_node);
|
||||
|
||||
result->is_offscreen = false;
|
||||
result->screen_rect = *bounds;
|
||||
upload_texture (self, texture, &result->region);
|
||||
return true;
|
||||
upload_texture (self, texture, texture_region_out);
|
||||
*is_offscreen = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (flags & LINEAR_FILTER)
|
||||
@ -3799,76 +3876,38 @@ add_offscreen_ops (GskGLRenderer *self,
|
||||
|
||||
if (cached_id != 0)
|
||||
{
|
||||
init_full_texture_region (texture_region_out, cached_id);
|
||||
/* We didn't render it offscreen, but hand out an offscreen texture id */
|
||||
result->is_offscreen = true;
|
||||
result->screen_rect = *bounds;
|
||||
|
||||
init_full_texture_region (&result->region, cached_id);
|
||||
return true;
|
||||
*is_offscreen = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
width = bounds->size.width;
|
||||
height = bounds->size.height;
|
||||
scale_x = builder->scale_x;
|
||||
scale_y = builder->scale_y;
|
||||
width = ceilf (bounds->size.width * scale_x);
|
||||
height = ceilf (bounds->size.height * scale_y);
|
||||
|
||||
/* We usually return a texture exactly as big as the node we draw, and at the
|
||||
* same position. Sometimes we don't though, and so we need to adjust the screen_rect,
|
||||
* which will be used to draw the rendered texture. */
|
||||
screen_rect = *bounds;
|
||||
/* Tweak the scale factor so that the required texture doesn't
|
||||
* exceed the max texture limit. This will render with a lower
|
||||
* resolution, but this is better than clipping.
|
||||
*/
|
||||
{
|
||||
const int max_texture_size = gsk_gl_driver_get_max_texture_size (self->gl_driver);
|
||||
|
||||
new_clip = GSK_ROUNDED_RECT_INIT ((bounds->origin.x + dx) * scale_x,
|
||||
(bounds->origin.y + dy) * scale_y,
|
||||
width, height);
|
||||
width = ceilf (width * scale_x);
|
||||
if (width > max_texture_size)
|
||||
{
|
||||
scale_x *= (float)max_texture_size / width;
|
||||
width = max_texture_size;
|
||||
}
|
||||
|
||||
max_texture_size = gsk_gl_driver_get_max_texture_size (self->gl_driver);
|
||||
if (!(flags & RESET_CLIP) &&
|
||||
G_UNLIKELY (width > max_texture_size || height > max_texture_size))
|
||||
{
|
||||
/* If we are clipped to an acceptable size (lower than the texture max), then
|
||||
* only draw that part. If not, scale the result down. */
|
||||
if (ops_has_clip (builder))
|
||||
{
|
||||
graphene_rect_t transformed_bounds;
|
||||
|
||||
flags |= RESET_CLIP; /* XXX HACK */
|
||||
|
||||
/* New clip is the intersection between the clip and the node bounds */
|
||||
ops_transform_bounds_modelview (builder, bounds, &transformed_bounds);
|
||||
graphene_rect_intersection (&transformed_bounds, &builder->current_clip->bounds, &new_clip.bounds);
|
||||
|
||||
width = new_clip.bounds.size.width;
|
||||
height = new_clip.bounds.size.height;
|
||||
|
||||
/* Un-transform sceen_rect as it will be transformed automatically later */
|
||||
screen_rect = new_clip.bounds;
|
||||
screen_rect.origin.x -= (dx * scale_x);
|
||||
screen_rect.origin.y -= (dy * scale_y);
|
||||
screen_rect.origin.x /= scale_x;
|
||||
screen_rect.origin.y /= scale_y;
|
||||
screen_rect.size.width /= scale_x;
|
||||
screen_rect.size.height /= scale_y;
|
||||
|
||||
/* We do not add this to the cache as it is likely to quickly change in the
|
||||
* future */
|
||||
add_to_cache = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* As a last resort, scale everything down */
|
||||
if (width > max_texture_size)
|
||||
{
|
||||
scale_x *= (float)max_texture_size / width;
|
||||
width = max_texture_size;
|
||||
}
|
||||
|
||||
if (height > max_texture_size)
|
||||
{
|
||||
scale_y *= (float)max_texture_size / height;
|
||||
height = max_texture_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
height = ceilf (height * scale_y);
|
||||
if (height > max_texture_size)
|
||||
{
|
||||
scale_y *= (float)max_texture_size / height;
|
||||
height = max_texture_size;
|
||||
}
|
||||
}
|
||||
|
||||
gsk_gl_driver_create_render_target (self->gl_driver,
|
||||
width, height,
|
||||
@ -3886,20 +3925,22 @@ add_offscreen_ops (GskGLRenderer *self,
|
||||
render_target);
|
||||
}
|
||||
|
||||
init_projection_matrix (&item_proj, &new_clip.bounds);
|
||||
viewport = GRAPHENE_RECT_INIT (bounds->origin.x * scale_x,
|
||||
bounds->origin.y * scale_y,
|
||||
width, height);
|
||||
|
||||
init_projection_matrix (&item_proj, &viewport);
|
||||
prev_render_target = ops_set_render_target (builder, render_target);
|
||||
/* Clear since we use this rendertarget for the first time */
|
||||
ops_begin (builder, OP_CLEAR);
|
||||
prev_projection = ops_set_projection (builder, &item_proj);
|
||||
ops_set_modelview (builder, gsk_transform_scale (NULL, scale_x, scale_y));
|
||||
prev_viewport = ops_set_viewport (builder, &new_clip.bounds);
|
||||
prev_viewport = ops_set_viewport (builder, &viewport);
|
||||
if (flags & RESET_CLIP)
|
||||
ops_push_clip (builder, &new_clip);
|
||||
ops_push_clip (builder, &GSK_ROUNDED_RECT_INIT_FROM_RECT (viewport));
|
||||
|
||||
/* ops_set_modelview() resets the offset to 0, so restore it here. */
|
||||
builder->dx = dx;
|
||||
builder->dy = dy;
|
||||
builder->dx = 0;
|
||||
builder->dy = 0;
|
||||
|
||||
prev_opacity = ops_set_opacity (builder, 1.0);
|
||||
|
||||
@ -3910,16 +3951,19 @@ add_offscreen_ops (GskGLRenderer *self,
|
||||
{
|
||||
static int k;
|
||||
ops_dump_framebuffer (builder,
|
||||
g_strdup_printf ("%d_%s_%p.png",
|
||||
k++,
|
||||
g_strdup_printf ("%s_%p_%d.png",
|
||||
g_type_name_from_instance ((GTypeInstance *) child_node),
|
||||
child_node),
|
||||
child_node,
|
||||
k ++),
|
||||
width, height);
|
||||
}
|
||||
#endif
|
||||
|
||||
ops_set_opacity (builder, prev_opacity);
|
||||
|
||||
builder->dx = dx;
|
||||
builder->dy = dy;
|
||||
|
||||
if (flags & RESET_CLIP)
|
||||
ops_pop_clip (builder);
|
||||
|
||||
@ -3928,16 +3972,13 @@ add_offscreen_ops (GskGLRenderer *self,
|
||||
ops_set_projection (builder, &prev_projection);
|
||||
ops_set_render_target (builder, prev_render_target);
|
||||
|
||||
/*g_message ("offset after: %f, %f", builder->dx, builder->dy);*/
|
||||
*is_offscreen = TRUE;
|
||||
init_full_texture_region (texture_region_out, texture_id);
|
||||
|
||||
result->is_offscreen = true;
|
||||
result->screen_rect = screen_rect;
|
||||
init_full_texture_region (&result->region, texture_id);
|
||||
|
||||
if ((flags & NO_CACHE_PLZ) == 0 && add_to_cache)
|
||||
if ((flags & NO_CACHE_PLZ) == 0)
|
||||
gsk_gl_driver_set_texture_for_key (self->gl_driver, &key, texture_id);
|
||||
|
||||
return true;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -4377,11 +4418,8 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer,
|
||||
graphene_matrix_scale (&m, 1, -1, 1); /* Undo the scale init_projection_matrix() does again */
|
||||
ops_set_projection (&self->op_builder, &m);
|
||||
|
||||
g_assert (self->op_builder.dx == 0);
|
||||
g_assert (self->op_builder.dy == 0);
|
||||
|
||||
load_offscreen_vertex_data (ops_draw (&self->op_builder, NULL),
|
||||
&GRAPHENE_RECT_INIT (0, 0, width, height), &self->op_builder);
|
||||
fill_vertex_data (ops_draw (&self->op_builder, NULL),
|
||||
0, 0, width, height);
|
||||
ops_pop_clip (&self->op_builder);
|
||||
gsk_gl_renderer_render_ops (self);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user