diff --git a/gsk/gskglrenderer.c b/gsk/gskglrenderer.c index 776b985606..2b919a3c4e 100644 --- a/gsk/gskglrenderer.c +++ b/gsk/gskglrenderer.c @@ -12,6 +12,12 @@ #include +typedef enum { + GSK_BLEND_MODE_NONE, + + GSK_BLEND_MODE_MULTIPLY +} GskBlendMode; + typedef struct { guint vao_id; guint buffer_id; @@ -20,9 +26,11 @@ typedef struct { guint mvp_location; guint map_location; + guint parentMap_location; guint uv_location; guint position_location; guint alpha_location; + guint blendMode_location; } RenderData; typedef struct { @@ -42,7 +50,10 @@ typedef struct { const char *name; + GskBlendMode blend_mode; + RenderData render_data; + RenderData *parent_data; } RenderItem; struct _GskGLRenderer @@ -62,9 +73,11 @@ struct _GskGLRenderer guint program_id; guint mvp_location; guint map_location; + guint parentMap_location; guint uv_location; guint position_location; guint alpha_location; + guint blendMode_location; guint vao_id; @@ -366,9 +379,11 @@ gsk_gl_renderer_create_program (GskGLRenderer *self) */ self->mvp_location = glGetUniformLocation (self->program_id, "mvp"); self->map_location = glGetUniformLocation (self->program_id, "map"); + self->parentMap_location = glGetUniformLocation (self->program_id, "parentMap"); self->alpha_location = glGetUniformLocation (self->program_id, "alpha"); self->position_location = glGetAttribLocation (self->program_id, "position"); self->uv_location = glGetAttribLocation (self->program_id, "uv"); + self->blendMode_location = glGetAttribLocation (self->program_id, "blendMode"); GSK_NOTE (OPENGL, g_print ("Program [%d] { mvp:%u, map:%u, alpha:%u, position:%u, uv:%u }\n", self->program_id, @@ -482,9 +497,12 @@ gsk_gl_renderer_update_frustum (GskGLRenderer *self, { GSK_NOTE (OPENGL, g_print ("Updating the modelview/projection\n")); - graphene_matrix_multiply (modelview, projection, &self->mvp); + graphene_matrix_multiply (projection, modelview, &self->mvp); graphene_frustum_init_from_matrix (&self->frustum, &self->mvp); + + GSK_NOTE (OPENGL, g_print ("Renderer MVP:\n")); + GSK_NOTE (OPENGL, graphene_matrix_print (&self->mvp)); } static void @@ -568,6 +586,18 @@ render_item (RenderItem *item) glBindTexture (GL_TEXTURE_2D, item->render_data.texture_id); glUniform1i (item->render_data.map_location, 0); + if (item->parent_data != NULL) + { + if (item->parent_data->texture_id != 0) + { + glActiveTexture (GL_TEXTURE1); + glBindTexture (GL_TEXTURE_2D, item->parent_data->texture_id); + glUniform1i (item->render_data.parentMap_location, 1); + } + + glUniform1i (item->render_data.blendMode_location, item->blend_mode); + } + /* Pass the opacity component */ glUniform1f (item->render_data.alpha_location, item->opaque ? 1 : item->opacity); @@ -692,7 +722,8 @@ project_item (const graphene_matrix_t *projection, static void gsk_gl_renderer_add_render_item (GskGLRenderer *self, - GskRenderNode *node) + GskRenderNode *node, + RenderItem *parent) { graphene_rect_t viewport; int gl_min_filter, gl_mag_filter; @@ -711,6 +742,8 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self, return; } + memset (&item, 0, sizeof (RenderItem)); + gsk_renderer_get_viewport (GSK_RENDERER (self), &viewport); gsk_render_node_get_bounds (node, &bounds); @@ -724,30 +757,39 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self, /* Each render item is an axis-aligned bounding box that we * transform using the given transformation matrix */ - item.min.x = (bounds.origin.x * 2) / bounds.size.width - 1; - item.min.y = (bounds.origin.y * 2) / bounds.size.height - 1; + item.min.x = bounds.origin.x; + item.min.y = bounds.origin.y; item.min.z = 0.f; - item.max.x = (bounds.origin.x + bounds.size.width) * 2 / bounds.size.width - 1; - item.max.y = (bounds.origin.y + bounds.size.height) * 2 / bounds.size.height - 1; + item.max.x = bounds.origin.x + bounds.size.width; + item.max.y = bounds.origin.y + bounds.size.height; item.max.z = 0.f; /* The location of the item, in normalized world coordinates */ gsk_render_node_get_world_matrix (node, &mv); - item.mvp = mv; + graphene_matrix_multiply (&mv, &self->mvp, &item.mvp); item.opaque = gsk_render_node_is_opaque (node); item.opacity = gsk_render_node_get_opacity (node); + item.blend_mode = parent != NULL ? GSK_BLEND_MODE_MULTIPLY : GSK_BLEND_MODE_NONE; + /* GL objects */ item.render_data.vao_id = self->vao_id; item.render_data.buffer_id = 0; item.render_data.program_id = self->program_id; item.render_data.map_location = self->map_location; + item.render_data.parentMap_location = self->parentMap_location; item.render_data.mvp_location = self->mvp_location; item.render_data.uv_location = self->uv_location; item.render_data.position_location = self->position_location; item.render_data.alpha_location = self->alpha_location; + item.render_data.blendMode_location = self->blendMode_location; + + if (parent != NULL) + item.parent_data = &(parent->render_data); + else + item.parent_data = NULL; gsk_renderer_get_projection (GSK_RENDERER (self), &projection); item.z = project_item (&projection, &mv); @@ -783,35 +825,37 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self, recurse_children: gsk_render_node_iter_init (&iter, node); while (gsk_render_node_iter_next (&iter, &child)) - gsk_gl_renderer_add_render_item (self, child); + gsk_gl_renderer_add_render_item (self, child, &item); } static gboolean gsk_gl_renderer_validate_tree (GskGLRenderer *self, GskRenderNode *root) { - int n_children; + int n_nodes; if (self->context == NULL) - return FALSE; + { + GSK_NOTE (OPENGL, g_print ("No valid GL context associated to the renderer")); + return FALSE; + } - n_children = gsk_render_node_get_n_children (root); - if (n_children == 0) - return FALSE; + n_nodes = gsk_render_node_get_size (root); gdk_gl_context_make_current (self->context); - self->opaque_render_items = g_array_sized_new (FALSE, FALSE, sizeof (RenderItem), n_children); - self->transparent_render_items = g_array_sized_new (FALSE, FALSE, sizeof (RenderItem), n_children); + self->opaque_render_items = g_array_sized_new (FALSE, FALSE, sizeof (RenderItem), n_nodes); + self->transparent_render_items = g_array_sized_new (FALSE, FALSE, sizeof (RenderItem), n_nodes); g_array_set_clear_func (self->opaque_render_items, render_item_clear); g_array_set_clear_func (self->transparent_render_items, render_item_clear); GSK_NOTE (OPENGL, g_print ("RenderNode -> RenderItem\n")); - gsk_gl_renderer_add_render_item (self, root); + gsk_gl_renderer_add_render_item (self, root, NULL); - GSK_NOTE (OPENGL, g_print ("Total render items: %d (opaque:%d, transparent:%d)\n", + GSK_NOTE (OPENGL, g_print ("Total render items: %d of %d (opaque:%d, transparent:%d)\n", self->opaque_render_items->len + self->transparent_render_items->len, + n_nodes, self->opaque_render_items->len, self->transparent_render_items->len)); @@ -851,6 +895,7 @@ gsk_gl_renderer_render (GskRenderer *renderer, GskGLRenderer *self = GSK_GL_RENDERER (renderer); graphene_matrix_t modelview, projection; graphene_rect_t viewport; + gboolean use_alpha; int status; guint i; @@ -911,10 +956,12 @@ gsk_gl_renderer_render (GskRenderer *renderer, self->texture_id != 0 ? "texture" : "renderbuffer")); out: + use_alpha = gsk_renderer_get_use_alpha (renderer); + gdk_cairo_draw_from_gl (gdk_drawing_context_get_cairo_context (context), gdk_drawing_context_get_window (context), - self->texture_id != 0 ? self->texture_id : self->render_buffer, - self->texture_id != 0 ? GL_TEXTURE : GL_RENDERBUFFER, + use_alpha ? self->texture_id : self->render_buffer, + use_alpha ? GL_TEXTURE : GL_RENDERBUFFER, gsk_renderer_get_scale_factor (renderer), 0, 0, viewport.size.width, viewport.size.height); diff --git a/gsk/gskrendernode.c b/gsk/gskrendernode.c index 4618c5a81b..2de6506e38 100644 --- a/gsk/gskrendernode.c +++ b/gsk/gskrendernode.c @@ -157,6 +157,7 @@ gsk_render_node_init (GskRenderNode *self) self->opacity = 1.0; self->is_mutable = TRUE; + self->needs_world_matrix_update = TRUE; } GType @@ -1277,6 +1278,23 @@ gsk_render_node_make_immutable (GskRenderNode *node) gsk_render_node_make_immutable (child); } +int +gsk_render_node_get_size (GskRenderNode *root) +{ + GskRenderNodeIter iter; + GskRenderNode *child; + int res; + + g_return_val_if_fail (GSK_IS_RENDER_NODE (root), 0); + + res = 1; + gsk_render_node_iter_init (&iter, root); + while (gsk_render_node_iter_next (&iter, &child)) + res += gsk_render_node_get_size (child); + + return res; +} + void gsk_value_set_render_node (GValue *value, GskRenderNode *node) diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h index 16b7cf9c64..7aa100b986 100644 --- a/gsk/gskrendernodeprivate.h +++ b/gsk/gskrendernodeprivate.h @@ -83,6 +83,8 @@ void gsk_render_node_update_world_matrix (GskRenderNode *node, void gsk_render_node_get_world_matrix (GskRenderNode *node, graphene_matrix_t *mv); +int gsk_render_node_get_size (GskRenderNode *root); + G_END_DECLS #endif /* __GSK_RENDER_NODE_PRIVATE_H__ */ diff --git a/gsk/resources/glsl/gl3-base.fs.glsl b/gsk/resources/glsl/gl3-base.fs.glsl index 07458db527..0127556e18 100644 --- a/gsk/resources/glsl/gl3-base.fs.glsl +++ b/gsk/resources/glsl/gl3-base.fs.glsl @@ -6,8 +6,29 @@ out vec4 outputColor; uniform mat4 mvp; uniform sampler2D map; +uniform sampler2D parentMap; uniform float alpha; +uniform int blendMode; + +vec3 BlendMultiply(vec3 Csrc, vec3 Cdst) { + return Csrc * Cdst; +} + void main() { - outputColor = texture2D(map, vUv) * vec4(alpha); + vec4 src = texture2D(map, vUv); + vec4 dst = texture2D(parentMap, vUv); + vec3 res; + + if (blendMode == 0) { + res = src.xyz; + } + else if (blendMode == 1) { + res = BlendMultiply(src.xyz, dst.xyz); + } + else { + res = vec3(1.0, 1.0, 0.0); + } + + outputColor = vec4(res, src.a * alpha); }