Consider all offscreen drawings for the icon cache

This commit is contained in:
Timm Bäder 2019-06-04 17:28:59 +00:00 committed by Matthias Clasen
parent 259bbdcb09
commit ecb353f4af

View File

@ -67,6 +67,26 @@ typedef enum
DUMP_FRAMEBUFFER = 1 << 3
} OffscreenFlags;
typedef struct
{
int texture_id;
float x;
float y;
float x2;
float y2;
} TextureRegion;
static inline void
init_full_texture_region (TextureRegion *r,
int texture_id)
{
r->texture_id = texture_id;
r->x = 0;
r->y = 0;
r->x2 = 1;
r->y2 = 1;
}
static void G_GNUC_UNUSED
print_render_node_tree (GskRenderNode *root, int level)
{
@ -187,15 +207,6 @@ font_has_color_glyphs (const PangoFont *font)
return has_color;
}
static void
get_gl_scaling_filters (GskRenderNode *node,
int *min_filter_r,
int *mag_filter_r)
{
*min_filter_r = GL_LINEAR;
*mag_filter_r = GL_LINEAR;
}
static inline void
rgba_to_float (const GdkRGBA *c,
float *f)
@ -297,7 +308,7 @@ static void add_offscreen_ops (GskGLRenderer *self,
RenderOpBuilder *builder,
const graphene_rect_t *bounds,
GskRenderNode *child_node,
int *texture_id,
TextureRegion *region_out,
gboolean *is_offscreen,
guint flags);
static void gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
@ -789,6 +800,42 @@ render_color_node (GskGLRenderer *self,
ops_draw (builder, vertex_data);
}
static inline void
upload_texture (GskGLRenderer *self,
GdkTexture *texture,
TextureRegion *out_region)
{
int texture_id;
if (texture->width <= 128 &&
texture->height <= 128)
{
graphene_rect_t trect;
gsk_gl_icon_cache_lookup_or_add (self->icon_cache,
texture,
&texture_id,
&trect);
out_region->x = trect.origin.x;
out_region->y = trect.origin.y;
out_region->x2 = out_region->x + trect.size.width;
out_region->y2 = out_region->y + trect.size.height;
}
else
{
texture_id = gsk_gl_driver_get_texture_for_texture (self->gl_driver,
texture,
GL_LINEAR,
GL_LINEAR);
out_region->x = 0;
out_region->y = 0;
out_region->x2 = 1;
out_region->y2 = 1;
}
out_region->texture_id = texture_id;
}
static inline void
render_texture_node (GskGLRenderer *self,
GskRenderNode *node,
@ -836,45 +883,21 @@ render_texture_node (GskGLRenderer *self,
}
else
{
int texture_id;
float tx = 0, ty = 0, tx2 = 1, ty2 = 1;
TextureRegion r;
if (texture->width <= 128 &&
texture->height <= 128)
{
graphene_rect_t trect;
gsk_gl_icon_cache_lookup_or_add (self->icon_cache,
texture,
&texture_id,
&trect);
tx = trect.origin.x;
ty = trect.origin.y;
tx2 = tx + trect.size.width;
ty2 = ty + trect.size.height;
}
else
{
int gl_min_filter = GL_NEAREST, gl_mag_filter = GL_NEAREST;
get_gl_scaling_filters (node, &gl_min_filter, &gl_mag_filter);
texture_id = gsk_gl_driver_get_texture_for_texture (self->gl_driver,
texture,
gl_min_filter,
gl_mag_filter);
}
upload_texture (self, texture, &r);
ops_set_program (builder, &self->blit_program);
ops_set_texture (builder, texture_id);
ops_set_texture (builder, r.texture_id);
ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
{ { min_x, min_y }, { tx, ty }, },
{ { min_x, max_y }, { tx, ty2 }, },
{ { max_x, min_y }, { tx2, ty }, },
{ { min_x, min_y }, { r.x, r.y }, },
{ { min_x, max_y }, { r.x, r.y2 }, },
{ { max_x, min_y }, { r.x2, r.y }, },
{ { max_x, max_y }, { tx2, ty2 }, },
{ { min_x, max_y }, { tx, ty2 }, },
{ { max_x, min_y }, { tx2, ty }, },
{ { max_x, max_y }, { r.x2, r.y2 }, },
{ { min_x, max_y }, { r.x, r.y2 }, },
{ { max_x, min_y }, { r.x2, r.y }, },
});
}
}
@ -935,7 +958,7 @@ render_transform_node (GskGLRenderer *self,
const float min_y = child->bounds.origin.y;
const float max_x = min_x + child->bounds.size.width;
const float max_y = min_y + child->bounds.size.height;
int texture_id;
TextureRegion region;
gboolean is_offscreen;
/* For non-trivial transforms, we draw everything on a texture and then
* draw the texture transformed. */
@ -946,24 +969,24 @@ render_transform_node (GskGLRenderer *self,
add_offscreen_ops (self, builder,
&child->bounds,
child,
&texture_id, &is_offscreen,
&region, &is_offscreen,
RESET_CLIP | RESET_OPACITY);
gsk_transform_to_matrix (node_transform, &mat);
ops_push_modelview (builder, node_transform);
ops_set_texture (builder, texture_id);
ops_set_texture (builder, region.texture_id);
ops_set_program (builder, &self->blit_program);
if (is_offscreen)
{
const GskQuadVertex offscreen_vertex_data[GL_N_VERTICES] = {
{ { min_x, min_y }, { 0, 1 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
{ { min_x, min_y }, { region.x, region.y2 }, },
{ { min_x, max_y }, { region.x, region.y }, },
{ { max_x, min_y }, { region.x2, region.y2 }, },
{ { max_x, max_y }, { 1, 0 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
{ { max_x, max_y }, { region.x2, region.y }, },
{ { min_x, max_y }, { region.x, region.y }, },
{ { max_x, min_y }, { region.x2, region.y2 }, },
};
ops_draw (builder, offscreen_vertex_data);
@ -971,13 +994,13 @@ render_transform_node (GskGLRenderer *self,
else
{
const GskQuadVertex onscreen_vertex_data[GL_N_VERTICES] = {
{ { min_x, min_y }, { 0, 0 }, },
{ { min_x, max_y }, { 0, 1 }, },
{ { max_x, min_y }, { 1, 0 }, },
{ { min_x, min_y }, { region.x, region.y }, },
{ { min_x, max_y }, { region.x, region.y2 }, },
{ { max_x, min_y }, { region.x2, region.y }, },
{ { max_x, max_y }, { 1, 1 }, },
{ { min_x, max_y }, { 0, 1 }, },
{ { max_x, min_y }, { 1, 0 }, },
{ { max_x, max_y }, { region.x2, region.y2 }, },
{ { min_x, max_y }, { region.x, region.y2 }, },
{ { max_x, min_y }, { region.x2, region.y }, },
};
ops_draw (builder, onscreen_vertex_data);
@ -1237,7 +1260,7 @@ render_rounded_clip_node (GskGLRenderer *self,
const float max_y = min_y + node->bounds.size.height;
graphene_matrix_t scale_matrix;
gboolean is_offscreen;
int texture_id;
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.
@ -1258,18 +1281,18 @@ render_rounded_clip_node (GskGLRenderer *self,
ops_push_clip (builder, &child_clip);
add_offscreen_ops (self, builder, &node->bounds,
child,
&texture_id, &is_offscreen,
&region, &is_offscreen,
FORCE_OFFSCREEN | RESET_OPACITY);
ops_pop_clip (builder);
ops_set_program (builder, &self->blit_program);
ops_set_texture (builder, texture_id);
ops_set_texture (builder, region.texture_id);
ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
{ { min_x, min_y }, { 0, 1 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
{ { max_x, max_y }, { 1, 0 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
@ -1289,13 +1312,13 @@ render_color_matrix_node (GskGLRenderer *self,
const float max_x = min_x + node->bounds.size.width;
const float max_y = min_y + node->bounds.size.height;
GskRenderNode *child = gsk_color_matrix_node_get_child (node);
int texture_id;
TextureRegion region;
gboolean is_offscreen;
add_offscreen_ops (self, builder,
&node->bounds,
child,
&texture_id, &is_offscreen,
&region, &is_offscreen,
RESET_CLIP | RESET_OPACITY);
ops_set_program (builder, &self->color_matrix_program);
@ -1303,25 +1326,35 @@ render_color_matrix_node (GskGLRenderer *self,
gsk_color_matrix_node_peek_color_matrix (node),
gsk_color_matrix_node_peek_color_offset (node));
ops_set_texture (builder, texture_id);
ops_set_texture (builder, region.texture_id);
if (is_offscreen)
{
GskQuadVertex offscreen_vertex_data[GL_N_VERTICES] = {
{ { min_x, min_y }, { 0, 1 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
{ { min_x, min_y }, { region.x, region.y2 }, },
{ { min_x, max_y }, { region.x, region.y }, },
{ { max_x, min_y }, { region.x2, region.y2 }, },
{ { max_x, max_y }, { 1, 0 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
{ { max_x, max_y }, { region.x2, region.y }, },
{ { min_x, max_y }, { region.x, region.y }, },
{ { max_x, min_y }, { region.x2, region.y2 }, },
};
ops_draw (builder, offscreen_vertex_data);
}
else
{
ops_draw (builder, vertex_data);
const GskQuadVertex onscreen_vertex_data[GL_N_VERTICES] = {
{ { min_x, min_y }, { region.x, region.y }, },
{ { min_x, max_y }, { region.x, region.y2 }, },
{ { max_x, min_y }, { region.x2, region.y }, },
{ { max_x, max_y }, { region.x2, region.y2 }, },
{ { min_x, max_y }, { region.x, region.y2 }, },
{ { max_x, min_y }, { region.x2, region.y }, },
};
ops_draw (builder, onscreen_vertex_data);
}
}
@ -1336,7 +1369,7 @@ render_blur_node (GskGLRenderer *self,
const float max_x = min_x + node->bounds.size.width;
const float max_y = min_y + node->bounds.size.height;
const float blur_radius = gsk_blur_node_get_radius (node);
int texture_id;
TextureRegion region;
gboolean is_offscreen;
RenderOp op;
@ -1354,7 +1387,7 @@ render_blur_node (GskGLRenderer *self,
add_offscreen_ops (self, builder,
&node->bounds,
gsk_blur_node_get_child (node),
&texture_id, &is_offscreen,
&region, &is_offscreen,
RESET_CLIP | FORCE_OFFSCREEN | RESET_OPACITY);
ops_set_program (builder, &self->blur_program);
@ -1363,7 +1396,7 @@ render_blur_node (GskGLRenderer *self,
op.blur.radius = gsk_blur_node_get_radius (node);
ops_add (builder, &op);
ops_set_texture (builder, texture_id);
ops_set_texture (builder, region.texture_id);
if (is_offscreen)
{
@ -1371,7 +1404,7 @@ render_blur_node (GskGLRenderer *self,
{ { min_x, min_y }, { 0, 1 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
{ { max_x, max_y }, { 1, 0 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
@ -1856,7 +1889,7 @@ render_shadow_node (GskGLRenderer *self,
const GskShadow *shadow = gsk_shadow_node_peek_shadow (node, i);
const float dx = shadow->dx;
const float dy = shadow->dy;
int texture_id;
TextureRegion region;
gboolean is_offscreen;
g_assert (shadow->radius <= 0);
@ -1880,22 +1913,22 @@ render_shadow_node (GskGLRenderer *self,
/* Draw the child offscreen, without the offset. */
add_offscreen_ops (self, builder,
&shadow_child->bounds,
shadow_child, &texture_id, &is_offscreen,
shadow_child, &region, &is_offscreen,
RESET_CLIP | RESET_OPACITY);
ops_set_program (builder, &self->coloring_program);
ops_set_color (builder, &shadow->color);
ops_set_texture (builder, texture_id);
ops_set_texture (builder, region.texture_id);
if (is_offscreen)
{
const GskQuadVertex offscreen_vertex_data[GL_N_VERTICES] = {
{ { dx + min_x, dy + min_y }, { 0, 1 }, },
{ { dx + min_x, dy + max_y }, { 0, 0 }, },
{ { dx + max_x, dy + min_y }, { 1, 1 }, },
{ { dx + min_x, dy + min_y }, { region.x, region.y2 }, },
{ { dx + min_x, dy + max_y }, { region.x, region.y }, },
{ { dx + max_x, dy + min_y }, { region.x2, region.y2 }, },
{ { dx + max_x, dy + max_y }, { 1, 0 }, },
{ { dx + min_x, dy + max_y }, { 0, 0 }, },
{ { dx + max_x, dy + min_y }, { 1, 1 }, },
{ { dx + max_x, dy + max_y }, { region.x2, region.y }, },
{ { dx + min_x, dy + max_y }, { region.x, region.y }, },
{ { dx + max_x, dy + min_y }, { region.x2, region.y2 }, },
};
ops_draw (builder, offscreen_vertex_data);
@ -1903,13 +1936,13 @@ render_shadow_node (GskGLRenderer *self,
else
{
const GskQuadVertex onscreen_vertex_data[GL_N_VERTICES] = {
{ { dx + min_x, dy + min_y }, { 0, 0 }, },
{ { dx + min_x, dy + max_y }, { 0, 1 }, },
{ { dx + max_x, dy + min_y }, { 1, 0 }, },
{ { dx + min_x, dy + min_y }, { region.x, region.y }, },
{ { dx + min_x, dy + max_y }, { region.x, region.y2 }, },
{ { dx + max_x, dy + min_y }, { region.x2, region.y }, },
{ { dx + max_x, dy + max_y }, { 1, 1 }, },
{ { dx + min_x, dy + max_y }, { 0, 1 }, },
{ { dx + max_x, dy + min_y }, { 1, 0 }, },
{ { dx + max_x, dy + max_y }, { region.x2, region.y2 }, },
{ { dx + min_x, dy + max_y }, { region.x, region.y2 }, },
{ { dx + max_x, dy + min_y }, { region.x2, region.y }, },
};
ops_draw (builder, onscreen_vertex_data);
@ -1932,8 +1965,8 @@ 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);
float progress = gsk_cross_fade_node_get_progress (node);
int start_texture_id;
int end_texture_id;
TextureRegion start_region;
TextureRegion end_region;
gboolean is_offscreen1, is_offscreen2;
RenderOp op;
const GskQuadVertex vertex_data[GL_N_VERTICES] = {
@ -1952,21 +1985,21 @@ render_cross_fade_node (GskGLRenderer *self,
add_offscreen_ops (self, builder,
&node->bounds,
start_node,
&start_texture_id, &is_offscreen1,
&start_region, &is_offscreen1,
FORCE_OFFSCREEN | RESET_CLIP | RESET_OPACITY);
add_offscreen_ops (self, builder,
&node->bounds,
end_node,
&end_texture_id, &is_offscreen2,
&end_region, &is_offscreen2,
FORCE_OFFSCREEN | RESET_CLIP | RESET_OPACITY);
ops_set_program (builder, &self->cross_fade_program);
op.op = OP_CHANGE_CROSS_FADE;
op.cross_fade.progress = progress;
op.cross_fade.source2 = end_texture_id;
op.cross_fade.source2 = end_region.texture_id;
ops_add (builder, &op);
ops_set_texture (builder, start_texture_id);
ops_set_texture (builder, start_region.texture_id);
ops_draw (builder, vertex_data);
}
@ -1982,8 +2015,8 @@ render_blend_node (GskGLRenderer *self,
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;
int top_texture_id;
int bottom_texture_id;
TextureRegion top_region;
TextureRegion bottom_region;
gboolean is_offscreen1, is_offscreen2;
RenderOp op;
const GskQuadVertex vertex_data[GL_N_VERTICES] = {
@ -2001,19 +2034,19 @@ render_blend_node (GskGLRenderer *self,
add_offscreen_ops (self, builder,
&node->bounds,
bottom_child,
&bottom_texture_id, &is_offscreen1,
&bottom_region, &is_offscreen1,
FORCE_OFFSCREEN | RESET_CLIP);
add_offscreen_ops (self, builder,
&node->bounds,
top_child,
&top_texture_id, &is_offscreen2,
&top_region, &is_offscreen2,
FORCE_OFFSCREEN | RESET_CLIP);
ops_set_program (builder, &self->blend_program);
ops_set_texture (builder, bottom_texture_id);
ops_set_texture (builder, bottom_region.texture_id);
op.op = OP_CHANGE_BLEND;
op.blend.source2 = top_texture_id;
op.blend.source2 = top_region.texture_id;
op.blend.mode = gsk_blend_node_get_blend_mode (node);
ops_add (builder, &op);
ops_draw (builder, vertex_data);
@ -2814,7 +2847,7 @@ add_offscreen_ops (GskGLRenderer *self,
RenderOpBuilder *builder,
const graphene_rect_t *bounds,
GskRenderNode *child_node,
int *texture_id_out,
TextureRegion *texture_region_out,
gboolean *is_offscreen,
guint flags)
{
@ -2839,14 +2872,8 @@ add_offscreen_ops (GskGLRenderer *self,
(flags & FORCE_OFFSCREEN) == 0)
{
GdkTexture *texture = gsk_texture_node_get_texture (child_node);
int gl_min_filter = GL_NEAREST, gl_mag_filter = GL_NEAREST;
get_gl_scaling_filters (child_node, &gl_min_filter, &gl_mag_filter);
*texture_id_out = gsk_gl_driver_get_texture_for_texture (self->gl_driver,
texture,
gl_min_filter,
gl_mag_filter);
upload_texture (self, texture, texture_region_out);
*is_offscreen = FALSE;
return;
}
@ -2857,7 +2884,7 @@ add_offscreen_ops (GskGLRenderer *self,
if (cached_id != 0)
{
*texture_id_out = cached_id;
init_full_texture_region (texture_region_out, cached_id);
/* We didn't render it offscreen, but hand out an offscreen texture id */
*is_offscreen = TRUE;
return;
@ -2929,7 +2956,7 @@ add_offscreen_ops (GskGLRenderer *self,
ops_set_render_target (builder, prev_render_target);
*is_offscreen = TRUE;
*texture_id_out = texture_id;
init_full_texture_region (texture_region_out, texture_id);
gsk_gl_driver_set_texture_for_pointer (self->gl_driver, child_node, texture_id);
}