[gtk/wip/baedert/for-master: 3/11] gl renderer: Implement a subset of repeat nodes
- From: Timm Bäder <baedert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/baedert/for-master: 3/11] gl renderer: Implement a subset of repeat nodes
- Date: Sun, 11 Aug 2019 06:36:03 +0000 (UTC)
commit a0ba1735f7448ceffa5d7ab8c7fb0a9b492b705f
Author: Timm Bäder <mail baedert org>
Date: Sat Aug 10 14:45:45 2019 +0200
gl renderer: Implement a subset of repeat nodes
gsk/gl/gskglrenderer.c | 126 +++++++++++++++++++++++++++++++++-----
gsk/gl/gskglrenderopsprivate.h | 13 +++-
gsk/gl/gskshaderbuilder.c | 12 +++-
gsk/gl/gskshaderbuilderprivate.h | 1 +
gsk/meson.build | 1 +
gsk/resources/glsl/repeat.fs.glsl | 34 ++++++++++
6 files changed, 170 insertions(+), 17 deletions(-)
---
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index cced23aa9b..02573153fe 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -340,6 +340,7 @@ struct _GskGLRenderer
Program border_program;
Program cross_fade_program;
Program blend_program;
+ Program repeat_program;
};
};
@@ -2082,6 +2083,81 @@ 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,
+ ®ion, &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[1] = region.y;
+ op.repeat.texture_rect[2] = region.x2;
+ 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 +2444,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 +2473,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 +2540,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 +2548,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 +2623,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 +2954,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 +3245,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);
diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h
index ff8fe642be..60e9317f7c 100644
--- a/gsk/gl/gskglrenderopsprivate.h
+++ b/gsk/gl/gskglrenderopsprivate.h
@@ -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;
diff --git a/gsk/gl/gskshaderbuilder.c b/gsk/gl/gskshaderbuilder.c
index dc00371889..c057fcb3dc 100644
--- a/gsk/gl/gskshaderbuilder.c
+++ b/gsk/gl/gskshaderbuilder.c
@@ -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,
diff --git a/gsk/gl/gskshaderbuilderprivate.h b/gsk/gl/gskshaderbuilderprivate.h
index 025d7a2028..b91af84ea6 100644
--- a/gsk/gl/gskshaderbuilderprivate.h
+++ b/gsk/gl/gskshaderbuilderprivate.h
@@ -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
diff --git a/gsk/meson.build b/gsk/meson.build
index dd8a4c967b..6819ac5426 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -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',
diff --git a/gsk/resources/glsl/repeat.fs.glsl b/gsk/resources/glsl/repeat.fs.glsl
new file mode 100644
index 0000000000..a58047335e
--- /dev/null
+++ b/gsk/resources/glsl/repeat.fs.glsl
@@ -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);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]