gl renderer: Implement a subset of repeat nodes

This commit is contained in:
Timm Bäder 2019-08-10 14:45:45 +02:00
parent 8d1a2247e0
commit 2914c360a9
6 changed files with 179 additions and 17 deletions

View File

@ -340,6 +340,7 @@ struct _GskGLRenderer
Program border_program;
Program cross_fade_program;
Program blend_program;
Program repeat_program;
};
};
@ -2082,6 +2083,90 @@ render_blend_node (GskGLRenderer *self,
ops_draw (builder, vertex_data);
}
static inline void
render_repeat_node (GskGLRenderer *self,
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;
GskRenderNode *child = gsk_repeat_node_get_child (node);
const graphene_rect_t *child_bounds = gsk_repeat_node_peek_child_bounds (node);
TextureRegion region;
gboolean is_offscreen;
RenderOp op;
if (child_bounds != NULL &&
!graphene_rect_equal (child_bounds, &child->bounds))
{
/* TODO: Implement these repeat nodes. */
render_fallback_node (self, node, builder);
return;
}
/* Draw the entire child on a texture */
add_offscreen_ops (self, builder,
&child->bounds,
child,
&region, &is_offscreen,
RESET_CLIP | RESET_OPACITY);
ops_set_program (builder, &self->repeat_program);
ops_set_texture (builder, region.texture_id);
op.op = OP_CHANGE_REPEAT;
op.repeat.child_bounds[0] = 0; /* Both currently unused */
op.repeat.child_bounds[1] = 0;
op.repeat.child_bounds[2] = node->bounds.size.width / child_bounds->size.width;
op.repeat.child_bounds[3] = node->bounds.size.height / child_bounds->size.height;
op.repeat.texture_rect[0] = region.x;
op.repeat.texture_rect[2] = region.x2;
if (is_offscreen)
{
op.repeat.texture_rect[1] = region.y2;
op.repeat.texture_rect[3] = region.y;
}
else
{
op.repeat.texture_rect[1] = region.y;
op.repeat.texture_rect[3] = region.y2;
}
ops_add (builder, &op);
if (is_offscreen)
{
const GskQuadVertex offscreen_vertex_data[GL_N_VERTICES] = {
{ { 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 }, { 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
{
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);
}
}
static inline void
apply_viewport_op (const Program *program,
const RenderOp *op)
@ -2368,6 +2453,14 @@ apply_blend_op (const Program *program,
glUniform1i (program->blend.mode_location, op->blend.mode);
}
static inline void
apply_repeat_op (const Program *program,
const RenderOp *op)
{
glUniform4fv (program->repeat.child_bounds_location, 1, op->repeat.child_bounds);
glUniform4fv (program->repeat.texture_rect_location, 1, op->repeat.texture_rect);
}
static void
gsk_gl_renderer_dispose (GObject *gobject)
{
@ -2389,19 +2482,21 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
static const struct {
const char *name;
const char *fs;
const char *vs;
} program_definitions[] = {
{ "blit", "blit.fs.glsl" },
{ "color", "color.fs.glsl" },
{ "coloring", "coloring.fs.glsl" },
{ "color matrix", "color_matrix.fs.glsl" },
{ "linear gradient", "linear_gradient.fs.glsl" },
{ "blur", "blur.fs.glsl" },
{ "inset shadow", "inset_shadow.fs.glsl" },
{ "outset shadow", "outset_shadow.fs.glsl" },
{ "blit", "blit.fs.glsl" },
{ "color", "color.fs.glsl" },
{ "coloring", "coloring.fs.glsl" },
{ "color matrix", "color_matrix.fs.glsl" },
{ "linear gradient", "linear_gradient.fs.glsl" },
{ "blur", "blur.fs.glsl" },
{ "inset shadow", "inset_shadow.fs.glsl" },
{ "outset shadow", "outset_shadow.fs.glsl" },
{ "unblurred outset shadow", "unblurred_outset_shadow.fs.glsl" },
{ "border", "border.fs.glsl" },
{ "cross fade", "cross_fade.fs.glsl" },
{ "blend", "blend.fs.glsl" },
{ "border", "border.fs.glsl" },
{ "cross fade", "cross_fade.fs.glsl" },
{ "blend", "blend.fs.glsl" },
{ "repeat", "repeat.fs.glsl" },
};
builder = gsk_shader_builder_new ();
@ -2454,6 +2549,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
prog->index = i;
prog->id = gsk_shader_builder_create_program (builder,
program_definitions[i].fs,
program_definitions[i].vs,
&shader_error);
if (shader_error != NULL)
@ -2461,8 +2557,8 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
g_propagate_prefixed_error (error, shader_error,
"Unable to create '%s' program (from %s and %s):\n",
program_definitions[i].name,
"blit.vs.glsl",
program_definitions[i].fs);
program_definitions[i].fs,
program_definitions[i].vs);
g_object_unref (builder);
return FALSE;
@ -2536,6 +2632,10 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
INIT_PROGRAM_UNIFORM_LOCATION (blend, source2);
INIT_PROGRAM_UNIFORM_LOCATION (blend, mode);
/* repeat */
INIT_PROGRAM_UNIFORM_LOCATION (repeat, child_bounds);
INIT_PROGRAM_UNIFORM_LOCATION (repeat, texture_rect);
g_object_unref (builder);
return TRUE;
}
@ -2863,8 +2963,11 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
render_blend_node (self, node, builder);
break;
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_REPEAT_NODE:
render_repeat_node (self, node, builder);
break;
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_CAIRO_NODE:
default:
{
@ -3151,6 +3254,10 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
apply_unblurred_outset_shadow_op (program, op);
break;
case OP_CHANGE_REPEAT:
apply_repeat_op (program, op);
break;
case OP_DRAW:
OP_PRINT (" -> draw %ld, size %ld and program %d\n",
op->draw.vao_offset, op->draw.vao_size, program->index);

View File

@ -11,7 +11,7 @@
#include "gskrendernodeprivate.h"
#define GL_N_VERTICES 6
#define GL_N_PROGRAMS 12
#define GL_N_PROGRAMS 13
@ -60,6 +60,7 @@ enum {
OP_PUSH_DEBUG_GROUP = 24,
OP_POP_DEBUG_GROUP = 25,
OP_CHANGE_BLEND = 26,
OP_CHANGE_REPEAT = 27,
};
typedef struct
@ -139,6 +140,10 @@ typedef struct
int source2_location;
int mode_location;
} blend;
struct {
int child_bounds_location;
int texture_rect_location;
} repeat;
};
} Program;
@ -149,7 +154,7 @@ typedef struct
union {
float opacity;
graphene_matrix_t modelview; /* TODO: Make both matrix members just "matrix" */
graphene_matrix_t modelview;
graphene_matrix_t projection;
const Program *program;
int texture_id;
@ -221,6 +226,10 @@ typedef struct
int source2;
int mode;
} blend;
struct {
float child_bounds[4];
float texture_rect[4];
} repeat;
struct {
char *filename;
int width;

View File

@ -257,6 +257,7 @@ gsk_shader_builder_set_common_vertex_shader (GskShaderBuilder *self,
int
gsk_shader_builder_create_program (GskShaderBuilder *builder,
const char *fragment_shader,
const char *vertex_shader,
GError **error)
{
int vertex_id;
@ -268,7 +269,16 @@ gsk_shader_builder_create_program (GskShaderBuilder *builder,
g_return_val_if_fail (fragment_shader != NULL, -1);
g_return_val_if_fail (builder->common_vertex_shader_id != 0, -1);
vertex_id = builder->common_vertex_shader_id;
if (vertex_shader == NULL)
vertex_id = builder->common_vertex_shader_id;
else
vertex_id = gsk_shader_builder_compile_shader (builder, GL_VERTEX_SHADER,
builder->vertex_preamble,
vertex_shader,
error);
if (vertex_id < 0)
return -1;
fragment_id = gsk_shader_builder_compile_shader (builder, GL_FRAGMENT_SHADER,
builder->fragment_preamble,
fragment_shader,

View File

@ -31,6 +31,7 @@ void gsk_shader_builder_set_common_vertex_shader (GskShad
int gsk_shader_builder_create_program (GskShaderBuilder *builder,
const char *fragment_shader,
const char *vertex_shader,
GError **error);
G_END_DECLS

View File

@ -12,6 +12,7 @@ gsk_private_gl_shaders = [
'resources/glsl/border.fs.glsl',
'resources/glsl/cross_fade.fs.glsl',
'resources/glsl/blend.fs.glsl',
'resources/glsl/repeat.fs.glsl',
'resources/glsl/es2_common.fs.glsl',
'resources/glsl/es2_common.vs.glsl',
'resources/glsl/gl3_common.fs.glsl',

View File

@ -0,0 +1,34 @@
uniform vec4 u_child_bounds;
uniform vec4 u_texture_rect;
float wrap(float f, float wrap_for) {
return mod(f, wrap_for);
}
/* We get the texture coordinates via vUv,
* but that might be on a texture atlas, so we need to do the
* wrapping ourselves.
*/
void main() {
/* We map the texture coordinate to [1;0], then wrap it and scale the result again */
float tw = u_texture_rect.z - u_texture_rect.x;
float th = u_texture_rect.w - u_texture_rect.y;
float mapped_x = (vUv.x - u_texture_rect.x) / tw;
float mapped_y = (vUv.y - u_texture_rect.y) / th;
float wrapped_x = wrap(mapped_x * u_child_bounds.z, 1.0);
float wrapped_y = wrap(mapped_y * u_child_bounds.w, 1.0);
vec2 tp;
tp.x = u_texture_rect.x + (wrapped_x * tw);
tp.y = u_texture_rect.y + (wrapped_y * th);
vec4 diffuse = Texture(u_source, tp);
setOutputColor(diffuse * u_alpha);
}