[gtk+/wip/baedert/gl: 13/94] Rework the GL renderer
- From: Timm Bäder <baedert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/baedert/gl: 13/94] Rework the GL renderer
- Date: Mon, 11 Dec 2017 07:23:34 +0000 (UTC)
commit 02e89a2a818faefcaaf2d28e42e7ba11e7d481bf
Author: Timm Bäder <mail baedert org>
Date: Fri Nov 3 13:09:02 2017 +0100
Rework the GL renderer
gsk/gskgldriver.c | 42 +-
gsk/gskglrenderer.c | 900 ++++++++++++++++------------
gsk/gskshaderbuilder.c | 2 -
gsk/meson.build | 4 +
gsk/resources/glsl/blend.fs.glsl | 3 +-
gsk/resources/glsl/blend.vs.glsl | 1 -
gsk/resources/glsl/blit.fs.glsl | 2 +-
gsk/resources/glsl/color.fs.glsl | 6 +-
gsk/resources/glsl/color_matrix.fs.glsl | 20 +
gsk/resources/glsl/color_matrix.vs.glsl | 6 +
gsk/resources/glsl/gl3_common.fs.glsl | 3 +-
gsk/resources/glsl/gl3_common.vs.glsl | 1 +
gsk/resources/glsl/linear_gradient.fs.glsl | 43 ++
gsk/resources/glsl/linear_gradient.vs.glsl | 5 +
14 files changed, 633 insertions(+), 405 deletions(-)
---
diff --git a/gsk/gskgldriver.c b/gsk/gskgldriver.c
index dbc3977..68c9148 100644
--- a/gsk/gskgldriver.c
+++ b/gsk/gskgldriver.c
@@ -520,7 +520,7 @@ int
gsk_gl_driver_create_vao_for_quad (GskGLDriver *driver,
int position_id,
int uv_id,
- int n_quads,
+ int n_vertices,
GskQuadVertex *quads)
{
@@ -530,7 +530,7 @@ gsk_gl_driver_create_vao_for_quad (GskGLDriver *driver,
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), -1);
g_return_val_if_fail (driver->in_frame, -1);
- v = find_vao (driver->vaos, position_id, uv_id, n_quads, quads);
+ v = find_vao (driver->vaos, position_id, uv_id, n_vertices, quads);
if (v != NULL && !v->in_use)
{
GSK_NOTE (OPENGL, g_print ("Reusing VAO(%d)\n", v->vao_id));
@@ -543,17 +543,20 @@ gsk_gl_driver_create_vao_for_quad (GskGLDriver *driver,
glGenBuffers (1, &buffer_id);
glBindBuffer (GL_ARRAY_BUFFER, buffer_id);
- glBufferData (GL_ARRAY_BUFFER, sizeof (GskQuadVertex) * n_quads, quads, GL_STATIC_DRAW);
+ glBufferData (GL_ARRAY_BUFFER, sizeof (GskQuadVertex) * n_vertices, quads, GL_STATIC_DRAW);
glEnableVertexAttribArray (position_id);
glVertexAttribPointer (position_id, 2, GL_FLOAT, GL_FALSE,
sizeof (GskQuadVertex),
(void *) G_STRUCT_OFFSET (GskQuadVertex, position));
- glEnableVertexAttribArray (uv_id);
- glVertexAttribPointer (uv_id, 2, GL_FLOAT, GL_FALSE,
- sizeof (GskQuadVertex),
- (void *) G_STRUCT_OFFSET (GskQuadVertex, uv));
+ if (uv_id != -1)
+ {
+ glEnableVertexAttribArray (uv_id);
+ glVertexAttribPointer (uv_id, 2, GL_FLOAT, GL_FALSE,
+ sizeof (GskQuadVertex),
+ (void *) G_STRUCT_OFFSET (GskQuadVertex, uv));
+ }
glBindBuffer (GL_ARRAY_BUFFER, 0);
glBindVertexArray (0);
@@ -563,8 +566,8 @@ gsk_gl_driver_create_vao_for_quad (GskGLDriver *driver,
v->buffer_id = buffer_id;
v->position_id = position_id;
v->uv_id = uv_id;
- v->n_quads = n_quads;
- v->quads = g_memdup (quads, sizeof (GskQuadVertex) * n_quads);
+ v->n_quads = n_vertices;
+ v->quads = g_memdup (quads, sizeof (GskQuadVertex) * n_vertices);
v->in_use = TRUE;
g_hash_table_insert (driver->vaos, GINT_TO_POINTER (vao_id), v);
@@ -572,8 +575,8 @@ gsk_gl_driver_create_vao_for_quad (GskGLDriver *driver,
if (GSK_DEBUG_CHECK (OPENGL))
{
int i;
- g_print ("New VAO(%d) for quad[%d] : {\n", v->vao_id, n_quads);
- for (i = 0; i < n_quads; i++)
+ g_print ("New VAO(%d) for quad[%d] : {\n", v->vao_id, n_vertices);
+ for (i = 0; i < n_vertices; i++)
{
g_print (" { x:%.2f, y:%.2f } { u:%.2f, v:%.2f }\n",
quads[i].position[0], quads[i].position[1],
@@ -641,6 +644,8 @@ gsk_gl_driver_create_render_target (GskGLDriver *driver,
g_array_append_val (t->fbos, f);
+ g_assert (glCheckFramebufferStatus (GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
+
glBindFramebuffer (GL_FRAMEBUFFER, driver->default_fbo.fbo_id);
return fbo_id;
@@ -719,7 +724,9 @@ gsk_gl_driver_bind_vao (GskGLDriver *driver,
glBindVertexArray (v->vao_id);
glBindBuffer (GL_ARRAY_BUFFER, v->buffer_id);
glEnableVertexAttribArray (v->position_id);
- glEnableVertexAttribArray (v->uv_id);
+
+ if (v->uv_id != -1)
+ glEnableVertexAttribArray (v->uv_id);
driver->bound_vao = v;
}
@@ -757,9 +764,14 @@ gsk_gl_driver_bind_render_target (GskGLDriver *driver,
}
out:
- status = glCheckFramebufferStatus (GL_FRAMEBUFFER);
- return status == GL_FRAMEBUFFER_COMPLETE;
+ if (texture_id != 0)
+ {
+ status = glCheckFramebufferStatus (GL_FRAMEBUFFER);
+ g_assert_cmpint (status, ==, GL_FRAMEBUFFER_COMPLETE);
+ }
+
+ return TRUE;
}
void
@@ -856,6 +868,4 @@ gsk_gl_driver_init_texture_with_surface (GskGLDriver *driver,
if (t->min_filter != GL_NEAREST)
glGenerateMipmap (GL_TEXTURE_2D);
-
- glBindTexture (GL_TEXTURE_2D, 0);
}
diff --git a/gsk/gskglrenderer.c b/gsk/gskglrenderer.c
index e1c3154..88ee17b 100644
--- a/gsk/gskglrenderer.c
+++ b/gsk/gskglrenderer.c
@@ -21,6 +21,29 @@
#define SHADER_VERSION_GL3_LEGACY 130
#define SHADER_VERSION_GL3 150
+#define ORTHO_NEAR_PLANE -10000
+#define ORTHO_FAR_PLANE 10000
+
+#define HIGHLIGHT_FALLBACK 0
+
+static void G_GNUC_UNUSED
+dump_framebuffer (const char *filename, int w, int h)
+{
+ int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, w);
+ guchar *data = g_malloc (h * stride);
+ cairo_surface_t *s;
+
+ glReadPixels (0, 0, w, h, GL_BGRA, GL_UNSIGNED_BYTE, data);
+ s = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_RGB24, w, h, stride);
+ cairo_surface_write_to_png (s, filename);
+
+ cairo_surface_destroy (s);
+ g_free (data);
+}
+
+
+static void
+gsk_gl_renderer_setup_render_mode (GskGLRenderer *self);
typedef struct {
int id;
/* Common locations (gl_common)*/
@@ -31,28 +54,40 @@ typedef struct {
int position_location;
int alpha_location;
int blendMode_location;
+ int viewport_location;
+ int projection_location;
/* Shader-specific locations */
union {
struct {
int color_location;
};
+ struct {
+ int color_matrix_location;
+ int color_offset_location;
+ };
+ struct {
+ int n_color_stops_location;
+ int color_stops_location;
+ int color_offsets_location;
+ int start_point_location;
+ int end_point_location;
+ };
};
} Program;
-typedef struct {
- int render_target_id;
- int vao_id;
- int buffer_id;
- int texture_id;
- int program_id;
-
- Program *program;
-} RenderData;
+#define INIT_PROGRAM_UNIFORM_LOCATION(program_name, location_name, uniform_name) \
+ G_STMT_START{\
+ self->program_name.location_name = glGetUniformLocation(self->program_name.id,
uniform_name);\
+ g_assert (self->program_name.location_name != 0); \
+ }G_STMT_END
enum {
- MODE_COLOR = 1,
+ MODE_BLIT = 1,
+ MODE_COLOR,
MODE_TEXTURE,
+ MODE_COLOR_MATRIX,
+ MODE_LINEAR_GRADIENT,
N_MODES
};
@@ -65,6 +100,7 @@ typedef struct {
graphene_size_t size;
graphene_matrix_t mvp;
+ graphene_matrix_t projection;
float opacity;
float z;
@@ -73,18 +109,40 @@ typedef struct {
struct {
GdkRGBA color;
} color_data;
+ struct {
+ graphene_matrix_t color_matrix;
+ graphene_vec4_t color_offset;
+ } color_matrix_data;
+ struct {
+ int n_color_stops;
+ float color_offsets[8];
+ float color_stops[4 * 8];
+ graphene_point_t start_point;
+ graphene_point_t end_point;
+ } linear_gradient_data;
};
const char *name;
GskBlendMode blend_mode;
- RenderData render_data;
- RenderData *parent_data;
+ /* The render target this item will draw itself on */
+ int parent_render_target;
+ /* In case this item creates a new render target, this is its id */
+ int render_target;
+ int vao_id;
+ int texture_id;
+ const Program *program;
GArray *children;
} RenderItem;
+static void
+destroy_render_item (RenderItem *item)
+{
+ if (item->children)
+ g_array_unref (item->children);
+}
enum {
@@ -93,6 +151,8 @@ enum {
MASK,
ALPHA,
BLEND_MODE,
+ VIEWPORT,
+ PROJECTION,
N_UNIFORMS
};
@@ -123,8 +183,10 @@ struct _GskGLRenderer
{
GskRenderer parent_instance;
+ int scale_factor;
+
graphene_matrix_t mvp;
- graphene_frustum_t frustum;
+ graphene_rect_t viewport;
guint frame_buffer;
guint depth_stencil_buffer;
@@ -136,11 +198,12 @@ struct _GskGLRenderer
GdkGLContext *gl_context;
GskGLDriver *gl_driver;
GskGLProfiler *gl_profiler;
- GskShaderBuilder *shader_builder;
Program blend_program;
Program blit_program;
Program color_program;
+ Program color_matrix_program;
+ Program linear_gradient_program;
GArray *render_items;
@@ -192,6 +255,7 @@ gsk_gl_renderer_create_buffers (GskGLRenderer *self,
}
gsk_gl_driver_create_render_target (self->gl_driver, self->texture_id, TRUE, TRUE);
+ gsk_gl_driver_bind_render_target (self->gl_driver, self->texture_id);
self->has_buffers = TRUE;
}
@@ -219,24 +283,29 @@ gsk_gl_renderer_destroy_buffers (GskGLRenderer *self)
}
static void
-init_common_locations (GskGLRenderer *self,
- Program *prog)
+init_common_locations (GskGLRenderer *self,
+ GskShaderBuilder *builder,
+ Program *prog)
{
prog->source_location =
- gsk_shader_builder_get_uniform_location (self->shader_builder, prog->id, self->uniforms[SOURCE]);
+ gsk_shader_builder_get_uniform_location (builder, prog->id, self->uniforms[SOURCE]);
prog->mask_location =
- gsk_shader_builder_get_uniform_location (self->shader_builder, prog->id, self->uniforms[MASK]);
+ gsk_shader_builder_get_uniform_location (builder, prog->id, self->uniforms[MASK]);
prog->mvp_location =
- gsk_shader_builder_get_uniform_location (self->shader_builder, prog->id, self->uniforms[MVP]);
+ gsk_shader_builder_get_uniform_location (builder, prog->id, self->uniforms[MVP]);
prog->alpha_location =
- gsk_shader_builder_get_uniform_location (self->shader_builder, prog->id, self->uniforms[ALPHA]);
+ gsk_shader_builder_get_uniform_location (builder, prog->id, self->uniforms[ALPHA]);
prog->blendMode_location =
- gsk_shader_builder_get_uniform_location (self->shader_builder, prog->id, self->uniforms[BLEND_MODE]);
+ gsk_shader_builder_get_uniform_location (builder, prog->id, self->uniforms[BLEND_MODE]);
+ prog->viewport_location = gsk_shader_builder_get_uniform_location (builder, prog->id,
+ self->uniforms[VIEWPORT]);
+ prog->projection_location = gsk_shader_builder_get_uniform_location (builder, prog->id,
+ self->uniforms[PROJECTION]);
prog->position_location =
- gsk_shader_builder_get_attribute_location (self->shader_builder, prog->id, self->attributes[POSITION]);
+ gsk_shader_builder_get_attribute_location (builder, prog->id, self->attributes[POSITION]);
prog->uv_location =
- gsk_shader_builder_get_attribute_location (self->shader_builder, prog->id, self->attributes[UV]);
+ gsk_shader_builder_get_attribute_location (builder, prog->id, self->attributes[UV]);
}
static gboolean
@@ -256,7 +325,9 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
self->uniforms[MASK] = gsk_shader_builder_add_uniform (builder, "uMask");
self->uniforms[ALPHA] = gsk_shader_builder_add_uniform (builder, "uAlpha");
self->uniforms[BLEND_MODE] = gsk_shader_builder_add_uniform (builder, "uBlendMode");
-
+ self->uniforms[VIEWPORT] = gsk_shader_builder_add_uniform (builder, "uViewport");
+ self->uniforms[PROJECTION] = gsk_shader_builder_add_uniform (builder, "uProjection");
+
self->attributes[POSITION] = gsk_shader_builder_add_attribute (builder, "aPosition");
self->attributes[UV] = gsk_shader_builder_add_attribute (builder, "aUv");
@@ -293,10 +364,6 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
if (GSK_RENDER_MODE_CHECK (SHADERS))
gsk_shader_builder_add_define (builder, "GSK_DEBUG", "1");
#endif
- /* Keep a pointer to query for the uniform and attribute locations
- * when rendering the scene
- */
- self->shader_builder = builder;
self->blend_program.id =
gsk_shader_builder_create_program (builder, "blend.vs.glsl", "blend.fs.glsl", &shader_error);
@@ -305,10 +372,9 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
g_propagate_prefixed_error (error,
shader_error,
"Unable to create 'blend' program: ");
- g_object_unref (builder);
goto out;
}
- init_common_locations (self, &self->blend_program);
+ init_common_locations (self, builder, &self->blend_program);
self->blit_program.id =
gsk_shader_builder_create_program (builder, "blit.vs.glsl", "blit.fs.glsl", &shader_error);
@@ -317,10 +383,9 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
g_propagate_prefixed_error (error,
shader_error,
"Unable to create 'blit' program: ");
- g_object_unref (builder);
goto out;
}
- init_common_locations (self, &self->blit_program);
+ init_common_locations (self, builder, &self->blit_program);
self->color_program.id =
gsk_shader_builder_create_program (builder, "color.vs.glsl", "color.fs.glsl", &shader_error);
@@ -329,26 +394,50 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
g_propagate_prefixed_error (error,
shader_error,
"Unable to create 'color' program: ");
- g_object_unref (builder);
goto out;
}
- init_common_locations (self, &self->color_program);
- self->color_program.color_location = gsk_shader_builder_get_uniform_location (self->shader_builder,
- self->color_program.id,
-
g_quark_from_string("uColor"));
- self->color_program.color_location = glGetUniformLocation(self->color_program.id, "uColor");
- g_assert(self->color_program.color_location >= 0);
+ init_common_locations (self, builder, &self->color_program);
+ INIT_PROGRAM_UNIFORM_LOCATION (color_program, color_location, "uColor");
+
+ self->color_matrix_program.id = gsk_shader_builder_create_program (builder,
+ "color_matrix.vs.glsl",
+ "color_matrix.fs.glsl",
+ &shader_error);
+ if (shader_error != NULL)
+ {
+ g_propagate_prefixed_error (error,
+ shader_error,
+ "Unable to create 'color_matrix' program: ");
+ goto out;
+ }
+ init_common_locations (self, builder, &self->color_matrix_program);
+ INIT_PROGRAM_UNIFORM_LOCATION (color_matrix_program, color_matrix_location, "uColorMatrix");
+ INIT_PROGRAM_UNIFORM_LOCATION (color_matrix_program, color_offset_location, "uColorOffset");
+
+ self->linear_gradient_program.id = gsk_shader_builder_create_program (builder,
+ "linear_gradient.vs.glsl",
+ "linear_gradient.fs.glsl",
+ &shader_error);
+ if (shader_error != NULL)
+ {
+ g_propagate_prefixed_error (error,
+ shader_error,
+ "Unable to create 'linear_gradient' program: ");
+ goto out;
+ }
+ init_common_locations (self, builder, &self->linear_gradient_program);
+ INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient_program, color_stops_location, "uColorStops");
+ INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient_program, color_offsets_location, "uColorOffsets");
+ INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient_program, n_color_stops_location, "uNumColorStops");
+ INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient_program, start_point_location, "uStartPoint");
+ INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient_program, end_point_location, "uEndPoint");
res = TRUE;
out:
- return res;
-}
-static void
-gsk_gl_renderer_destroy_programs (GskGLRenderer *self)
-{
- g_clear_object (&self->shader_builder);
+ g_object_unref (builder);
+ return res;
}
static gboolean
@@ -358,6 +447,8 @@ gsk_gl_renderer_realize (GskRenderer *renderer,
{
GskGLRenderer *self = GSK_GL_RENDERER (renderer);
+ self->scale_factor = gdk_window_get_scale_factor (window);
+
/* If we didn't get a GdkGLContext before realization, try creating
* one now, for our exclusive use.
*/
@@ -374,8 +465,8 @@ gsk_gl_renderer_realize (GskRenderer *renderer,
gdk_gl_context_make_current (self->gl_context);
g_assert (self->gl_driver == NULL);
- self->gl_driver = gsk_gl_driver_new (self->gl_context);
self->gl_profiler = gsk_gl_profiler_new (self->gl_context);
+ self->gl_driver = gsk_gl_driver_new (self->gl_context);
GSK_NOTE (OPENGL, g_print ("Creating buffers and programs\n"));
if (!gsk_gl_renderer_create_programs (self, error))
@@ -399,8 +490,14 @@ gsk_gl_renderer_unrealize (GskRenderer *renderer)
*/
g_array_set_size (self->render_items, 0);
+
+ glDeleteProgram (self->blend_program.id);
+ glDeleteProgram (self->blit_program.id);
+ glDeleteProgram (self->color_program.id);
+ glDeleteProgram (self->color_matrix_program.id);
+ glDeleteProgram (self->linear_gradient_program.id);
+
gsk_gl_renderer_destroy_buffers (self);
- gsk_gl_renderer_destroy_programs (self);
g_clear_object (&self->gl_profiler);
g_clear_object (&self->gl_driver);
@@ -424,12 +521,12 @@ gsk_gl_renderer_begin_draw_frame (GskRenderer *renderer,
window = gsk_renderer_get_window (renderer);
whole_window = (GdkRectangle) {
0, 0,
- gdk_window_get_width (window),
- gdk_window_get_height (window)
+ gdk_window_get_width (window) * self->scale_factor,
+ gdk_window_get_height (window) * self->scale_factor
};
damage = gdk_gl_context_get_damage (self->gl_context);
cairo_region_union (damage, update_area);
-
+
if (cairo_region_contains_rectangle (damage, &whole_window) == CAIRO_REGION_OVERLAP_IN)
{
self->render_mode = RENDER_FULL;
@@ -458,66 +555,80 @@ gsk_gl_renderer_begin_draw_frame (GskRenderer *renderer,
static void
gsk_gl_renderer_resize_viewport (GskGLRenderer *self,
- const graphene_rect_t *viewport,
- int scale_factor)
+ const graphene_rect_t *viewport)
{
- int width = viewport->size.width * scale_factor;
- int height = viewport->size.height * scale_factor;
+ int width = viewport->size.width;
+ int height = viewport->size.height;
GSK_NOTE (OPENGL, g_print ("glViewport(0, 0, %d, %d) [scale:%d]\n",
width,
height,
- scale_factor));
+ self->scale_factor));
+ graphene_rect_init (&self->viewport, 0, 0, width, height);
glViewport (0, 0, width, height);
}
-static void
-gsk_gl_renderer_update_frustum (GskGLRenderer *self,
- const graphene_matrix_t *modelview,
- const graphene_matrix_t *projection)
-{
- GSK_NOTE (TRANSFORMS, g_print ("Updating the modelview/projection\n"));
-
- graphene_matrix_multiply (modelview, projection, &self->mvp);
-
- graphene_frustum_init_from_matrix (&self->frustum, &self->mvp);
-
- GSK_NOTE (TRANSFORMS,
- g_print ("Renderer MVP:\n");
- graphene_matrix_print (&self->mvp);
- g_print ("\n"));
-}
-
#define N_VERTICES 6
static void
-render_item (GskGLRenderer *self,
- RenderItem *item)
+render_item (GskGLRenderer *self,
+ const RenderItem *item)
{
- float mvp[16];
- float opacity;
+ float mat[16];
+ const gboolean draw_children = item->children != NULL &&
+ item->children->len > 0;
+ const gboolean drawing_offscreen = item->parent_render_target != 0;
+
+ /*g_message ("Rendering %s with %u children and parent render target %d", item->name, item->children ?
item->children->len : 0, item->parent_render_target);*/
- if (item->children != NULL)
+ if (draw_children)
{
- if (gsk_gl_driver_bind_render_target (self->gl_driver, item->render_data.render_target_id))
+ guint i;
+ guint p;
+ graphene_rect_t prev_viewport;
+
+ prev_viewport = self->viewport;
+
+ gsk_gl_driver_bind_render_target (self->gl_driver, item->render_target);
+ glDisable (GL_SCISSOR_TEST);
+ glClearColor (0.0, 0.0, 0.0, 0.0);
+ glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ graphene_rect_init (&self->viewport,
+ item->min.x, item->min.y, item->size.width * self->scale_factor, item->size.height
* self->scale_factor);
+ glViewport (0, 0, item->size.width * self->scale_factor, item->size.height * self->scale_factor);
+
+ p = item->children->len;
+ for (i = 0; i < p; i ++)
{
- glViewport (0, 0, item->size.width, item->size.height);
+ const RenderItem *child = &g_array_index (item->children, RenderItem, i);
- glClearColor (0.0, 0.0, 0.0, 0.0);
- glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ g_assert (child->parent_render_target == item->render_target);
+ render_item (self, child);
}
+
+ /* At this point, all the child items should've been drawn */
+ gsk_gl_driver_bind_render_target (self->gl_driver, 0);
+ /* TODO: Manage pre-/post-framebuffer-state in the driver? */
+ /* Resets the scissor test, etc. */
+ if (!drawing_offscreen)
+ gsk_gl_renderer_setup_render_mode (self);
+
+ graphene_rect_init_from_rect (&self->viewport, &prev_viewport);
+ glViewport (0, 0, self->viewport.size.width, self->viewport.size.height);
}
- gsk_gl_driver_bind_vao (self->gl_driver, item->render_data.vao_id);
- glUseProgram (item->render_data.program->id);
+ if (drawing_offscreen)
+ g_assert (gsk_gl_driver_bind_render_target (self->gl_driver, item->parent_render_target));
+
+ glUseProgram (item->program->id);
switch(item->mode)
{
case MODE_COLOR:
{
- glUniform4f (item->render_data.program->color_location,
+ glUniform4f (item->program->color_location,
item->color_data.color.red,
item->color_data.color.green,
item->color_data.color.blue,
@@ -527,108 +638,67 @@ render_item (GskGLRenderer *self,
case MODE_TEXTURE:
{
- g_assert(item->render_data.texture_id != 0);
+ g_assert(item->texture_id != 0);
/* Use texture unit 0 for the source */
- glUniform1i (item->render_data.program->source_location, 0);
- gsk_gl_driver_bind_source_texture (self->gl_driver, item->render_data.texture_id);
-
- if (item->parent_data != NULL)
- {
- glUniform1i (item->render_data.program->blendMode_location, item->blend_mode);
-
- /* Use texture unit 1 for the mask */
- if (item->parent_data->texture_id != 0)
- {
- glUniform1i (item->render_data.program->mask_location, 1);
- gsk_gl_driver_bind_mask_texture (self->gl_driver, item->parent_data->texture_id);
- }
- }
+ glUniform1i (item->program->source_location, 0);
+ gsk_gl_driver_bind_source_texture (self->gl_driver, item->texture_id);
}
break;
- default:
- g_assert_not_reached ();
- }
-
- /* Pass the opacity component */
- if (item->children != NULL)
- opacity = 1.0;
- else
- opacity = item->opacity;
-
- glUniform1f (item->render_data.program->alpha_location, opacity);
-
- /* Pass the mvp to the vertex shader */
- GSK_NOTE (TRANSFORMS, graphene_matrix_print (&item->mvp));
- graphene_matrix_to_float (&item->mvp, mvp);
- glUniformMatrix4fv (item->render_data.program->mvp_location, 1, GL_FALSE, mvp);
+ case MODE_BLIT:
+ g_assert (item->program == &self->blit_program);
+ glUniform1i (item->program->source_location, 0);
+ gsk_gl_driver_bind_source_texture (self->gl_driver, item->render_target);
+ break;
- /* Draw the quad */
- GSK_NOTE2 (OPENGL, TRANSFORMS,
- g_print ("Drawing item <%s>[%p] (w:%g, h:%g) with opacity: %g blend mode: %d\n",
- item->name,
- item,
- item->size.width, item->size.height,
- item->opacity,
- item->blend_mode));
+ case MODE_COLOR_MATRIX:
+ {
+ float vec[4];
- glDrawArrays (GL_TRIANGLES, 0, N_VERTICES);
+ glUniform1i (item->program->source_location, 0);
+ gsk_gl_driver_bind_source_texture (self->gl_driver, item->render_target);
-#ifdef G_ENABLE_DEBUG
- gsk_profiler_counter_inc (gsk_renderer_get_profiler (GSK_RENDERER (self)),
- self->profile_counters.draw_calls);
-#endif
+ graphene_matrix_to_float (&item->color_matrix_data.color_matrix, mat);
+ glUniformMatrix4fv (item->program->color_matrix_location, 1, GL_FALSE, mat);
- /* Render all children items, so we can take the result
- * render target texture during the compositing
- */
- if (item->children != NULL)
- {
- int i;
+ graphene_vec4_to_float (&item->color_matrix_data.color_offset, vec);
+ glUniform4fv (item->program->color_offset_location, 1, vec);
+ }
+ break;
- for (i = 0; i < item->children->len; i++)
+ case MODE_LINEAR_GRADIENT:
{
- RenderItem *child = &g_array_index (item->children, RenderItem, i);
-
- render_item (self, child);
+ glUniform1i (item->program->n_color_stops_location,
+ item->linear_gradient_data.n_color_stops);
+ glUniform4fv (item->program->color_stops_location,
+ item->linear_gradient_data.n_color_stops,
+ item->linear_gradient_data.color_stops);
+ glUniform1fv (item->program->color_offsets_location,
+ item->linear_gradient_data.n_color_stops,
+ item->linear_gradient_data.color_offsets);
+ glUniform2f (item->program->start_point_location,
+ item->linear_gradient_data.start_point.x, item->linear_gradient_data.start_point.y);
+ glUniform2f (item->program->end_point_location,
+ item->linear_gradient_data.end_point.x, item->linear_gradient_data.end_point.y);
}
+ break;
- /* Bind the parent render target */
- if (item->parent_data != NULL)
- gsk_gl_driver_bind_render_target (self->gl_driver, item->parent_data->render_target_id);
-
- /* Bind the same VAO, as the render target is created with the same size
- * and vertices as the texture target
- */
- gsk_gl_driver_bind_vao (self->gl_driver, item->render_data.vao_id);
-
- /* Since we're rendering the target texture, we only need the blit program */
- glUseProgram (self->blit_program.id);
-
- /* Use texture unit 0 for the render target */
- glUniform1i (item->render_data.program->source_location, 0);
- gsk_gl_driver_bind_source_texture (self->gl_driver, item->render_data.render_target_id);
-
- /* Pass the opacity component; if we got here, we know that the original render
- * target is neither fully opaque nor at full opacity
- */
- glUniform1f (item->render_data.program->alpha_location, item->opacity);
-
- /* Pass the mvp to the vertex shader */
- GSK_NOTE (TRANSFORMS, graphene_matrix_print (&item->mvp));
- graphene_matrix_to_float (&item->mvp, mvp);
- glUniformMatrix4fv (item->render_data.program->mvp_location, 1, GL_FALSE, mvp);
-
- /* Draw the quad */
- GSK_NOTE2 (OPENGL, TRANSFORMS,
- g_print ("Drawing offscreen item <%s>[%p] (w:%g, h:%g) with opacity: %g\n",
- item->name,
- item,
- item->size.width, item->size.height,
- item->opacity));
-
- glDrawArrays (GL_TRIANGLES, 0, N_VERTICES);
+ default:
+ g_assert_not_reached ();
}
+
+ /* Common uniforms */
+ graphene_matrix_to_float (&item->mvp, mat);
+ glUniformMatrix4fv (item->program->mvp_location, 1, GL_FALSE, mat);
+ graphene_matrix_to_float (&item->projection, mat);
+ glUniformMatrix4fv (item->program->projection_location, 1, GL_FALSE, mat);
+ glUniform1f (item->program->alpha_location, item->opacity);
+ glUniform4f (item->program->viewport_location,
+ self->viewport.origin.x, self->viewport.origin.y,
+ self->viewport.size.width, self->viewport.size.height);
+
+ gsk_gl_driver_bind_vao (self->gl_driver, item->vao_id);
+ glDrawArrays (GL_TRIANGLES, 0, N_VERTICES);
}
static void
@@ -652,10 +722,31 @@ project_item (const graphene_matrix_t *projection,
return graphene_vec4_get_z (&vec) / graphene_vec4_get_w (&vec);
}
-static gboolean
-render_node_needs_render_target (GskRenderNode *node)
+static void
+init_framebuffer_for_node (GskGLRenderer *self,
+ RenderItem *item,
+ GskRenderNode *node,
+ const graphene_matrix_t *projection,
+ graphene_matrix_t *out_projection)
{
- return FALSE;
+ item->render_target = gsk_gl_driver_create_texture (self->gl_driver,
+ item->size.width * self->scale_factor,
+ item->size.height * self->scale_factor);
+ gsk_gl_driver_bind_source_texture (self->gl_driver, item->render_target);
+ gsk_gl_driver_init_texture_empty (self->gl_driver, item->render_target);
+ gsk_gl_driver_create_render_target (self->gl_driver, item->render_target, TRUE, TRUE);
+
+ item->children = g_array_new (FALSE, FALSE, sizeof (RenderItem));
+ g_array_set_clear_func (item->children, (GDestroyNotify)destroy_render_item);
+
+ g_assert (projection != NULL);
+ graphene_matrix_init_ortho (out_projection,
+ item->min.x,
+ item->min.x + item->size.width * self->scale_factor,
+ item->min.y,
+ item->min.y + item->size.height * self->scale_factor,
+ ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE);
+ graphene_matrix_scale (out_projection, 1, -1, 1);
}
static void
@@ -664,75 +755,121 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
const graphene_matrix_t *modelview,
GArray *render_items,
GskRenderNode *node,
- RenderItem *parent)
+ int render_target)
{
RenderItem item;
- RenderItem *ritem = NULL;
- int program_id;
- int scale_factor;
+
+ /* We handle container nodes here directly */
+ if (gsk_render_node_get_node_type (node) == GSK_CONTAINER_NODE)
+ {
+ guint i, p;
+
+ for (i = 0, p = gsk_container_node_get_n_children (node); i < p; i++)
+ {
+ GskRenderNode *child = gsk_container_node_get_child (node, i);
+ gsk_gl_renderer_add_render_item (self, projection, modelview, render_items, child, render_target);
+ }
+ return;
+ }
memset (&item, 0, sizeof (RenderItem));
item.name = node->name != NULL ? node->name : "unnamed";
- /* The texture size */
- item.size.width = node->bounds.size.width * scale_factor;
- item.size.height = node->bounds.size.height * scale_factor;
+ /*g_message ("%s: %s", __FUNCTION__, item.name);*/
+ item.size.width = node->bounds.size.width;
+ item.size.height = node->bounds.size.height;
/* Each render item is an axis-aligned bounding box that we
* transform using the given transformation matrix
*/
item.min.x = node->bounds.origin.x;
item.min.y = node->bounds.origin.y;
- item.min.z = 0.f;
+
+ /*g_message ("%s: %f, %f", item.name, item.min.x, item.min.y);*/
item.max.x = item.min.x + node->bounds.size.width;
item.max.y = item.min.y + node->bounds.size.height;
- item.max.z = 0.f;
/* The location of the item, in normalized world coordinates */
- graphene_matrix_multiply (modelview, &self->mvp, &item.mvp);
+ graphene_matrix_multiply (modelview, projection, &item.mvp);
item.z = project_item (projection, modelview);
item.opacity = 1.0;
+ item.projection = *projection;
item.blend_mode = GSK_BLEND_MODE_DEFAULT;
- /* Back-pointer to the parent node */
- if (parent != NULL)
- item.parent_data = &(parent->render_data);
- else
- item.parent_data = NULL;
+ item.parent_render_target = render_target;
- /* Select the program to use */
- if (parent != NULL)
- {
- item.render_data.program = &self->blend_program;
- program_id = self->blend_program.id;
- }
- else
- {
- item.render_data.program = &self->blit_program;
- program_id = self->blit_program.id;
- }
+ item.mode = MODE_BLIT;
+ item.program = &self->blit_program;
+ item.render_target = 0;
+ item.children = NULL;
- if (render_node_needs_render_target (node))
+ switch (gsk_render_node_get_node_type (node))
{
- item.render_data.render_target_id =
- gsk_gl_driver_create_texture (self->gl_driver, item.size.width, item.size.height);
- gsk_gl_driver_init_texture_empty (self->gl_driver, item.render_data.render_target_id);
- gsk_gl_driver_create_render_target (self->gl_driver, item.render_data.render_target_id, TRUE, TRUE);
+ case GSK_OPACITY_NODE:
+ {
+ GskRenderNode *child = gsk_opacity_node_get_child (node);
+ graphene_matrix_t p;
+ graphene_matrix_t identity;
+
+ graphene_matrix_init_identity (&identity);
+ init_framebuffer_for_node (self, &item, node, projection, &p);
+ gsk_gl_renderer_add_render_item (self, &p, &identity, item.children, child,
+ item.render_target);
+ item.mode = MODE_BLIT;
+ item.opacity = gsk_opacity_node_get_opacity (node);
+ }
+ break;
- item.children = g_array_new (FALSE, FALSE, sizeof (RenderItem));
- }
- else
- {
- item.render_data.render_target_id = self->texture_id;
- item.children = NULL;
- }
+ case GSK_CLIP_NODE:
+ {
+ GskRenderNode *child = gsk_clip_node_get_child (node);
+ graphene_matrix_t p;
+ graphene_matrix_t identity;
+
+ graphene_matrix_init_identity (&identity);
+ init_framebuffer_for_node (self, &item, node, projection, &p);
+ gsk_gl_renderer_add_render_item (self, &p, &identity, item.children, child,
+ item.render_target);
+ item.mode = MODE_BLIT;
+ }
+ break;
+
+ case GSK_ROUNDED_CLIP_NODE:
+ {
+ GskRenderNode *child = gsk_rounded_clip_node_get_child (node);
+ graphene_matrix_t p;
+ graphene_matrix_t identity;
+
+ graphene_matrix_init_identity (&identity);
+ init_framebuffer_for_node (self, &item, node, projection, &p);
+ gsk_gl_renderer_add_render_item (self, &p, &identity, item.children, child,
+ item.render_target);
+ item.mode = MODE_BLIT;
+ }
+ break;
+
+ case GSK_COLOR_MATRIX_NODE:
+ {
+ GskRenderNode *child = gsk_color_matrix_node_get_child (node);
+ graphene_matrix_t p;
+ graphene_matrix_t identity;
+
+ graphene_matrix_init_identity (&identity);
+ init_framebuffer_for_node (self, &item, node, projection, &p);
+ gsk_gl_renderer_add_render_item (self, &p, &identity, item.children, child,
+ item.render_target);
+
+ item.mode = MODE_COLOR_MATRIX;
+ item.program = &self->color_matrix_program;
+ item.color_matrix_data.color_matrix = *gsk_color_matrix_node_peek_color_matrix (node);
+ item.color_matrix_data.color_offset = *gsk_color_matrix_node_peek_color_offset (node);
+ }
+ break;
- switch (gsk_render_node_get_node_type (node))
- {
case GSK_TEXTURE_NODE:
{
GdkTexture *texture = gsk_texture_node_get_texture (node);
@@ -740,10 +877,10 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
get_gl_scaling_filters (node, &gl_min_filter, &gl_mag_filter);
- item.render_data.texture_id = gsk_gl_driver_get_texture_for_texture (self->gl_driver,
- texture,
- gl_min_filter,
- gl_mag_filter);
+ item.texture_id = gsk_gl_driver_get_texture_for_texture (self->gl_driver,
+ texture,
+ gl_min_filter,
+ gl_mag_filter);
item.mode = MODE_TEXTURE;
}
break;
@@ -758,13 +895,12 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
get_gl_scaling_filters (node, &gl_min_filter, &gl_mag_filter);
- /* Upload the Cairo surface to a GL texture */
- item.render_data.texture_id = gsk_gl_driver_create_texture (self->gl_driver,
- item.size.width,
- item.size.height);
- gsk_gl_driver_bind_source_texture (self->gl_driver, item.render_data.texture_id);
+ item.texture_id = gsk_gl_driver_create_texture (self->gl_driver,
+ item.size.width,
+ item.size.height);
+ gsk_gl_driver_bind_source_texture (self->gl_driver, item.texture_id);
gsk_gl_driver_init_texture_with_surface (self->gl_driver,
- item.render_data.texture_id,
+ item.texture_id,
(cairo_surface_t *)surface,
gl_min_filter,
gl_mag_filter);
@@ -774,71 +910,39 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
case GSK_COLOR_NODE:
{
- const GdkRGBA *c = gsk_color_node_peek_color(node);
- program_id = self->color_program.id;
- item.render_data.program = &self->color_program;
item.mode = MODE_COLOR;
- item.color_data.color= *c;
+ item.program = &self->color_program;
+ item.color_data.color= *gsk_color_node_peek_color (node);
}
break;
- case GSK_COLOR_MATRIX_NODE:
- {
- GskRenderNode *child = gsk_color_matrix_node_get_child (node);
-
- gsk_gl_renderer_add_render_item (self, projection, modelview, render_items, child, ritem);
- }
- return;
-
- case GSK_SHADOW_NODE:
- {
- GskRenderNode *child = gsk_shadow_node_get_child (node);
-
- gsk_gl_renderer_add_render_item (self, projection, modelview, render_items, child, ritem);
- }
- return;
-
- case GSK_REPEAT_NODE:
- {
- GskRenderNode *child = gsk_repeat_node_get_child (node);
-
- gsk_gl_renderer_add_render_item (self, projection, modelview, render_items, child, ritem);
- }
- return;
-
- case GSK_BLEND_NODE:
- {
- GskRenderNode *child = gsk_blend_node_get_bottom_child (node);
-
- gsk_gl_renderer_add_render_item (self, projection, modelview, render_items, child, ritem);
-
- child = gsk_blend_node_get_top_child (node);
- gsk_gl_renderer_add_render_item (self, projection, modelview, render_items, child, ritem);
- }
- return;
-
- case GSK_CROSS_FADE_NODE:
+ case GSK_LINEAR_GRADIENT_NODE:
{
- GskRenderNode *child = gsk_cross_fade_node_get_start_child (node);
-
- gsk_gl_renderer_add_render_item (self, projection, modelview, render_items, child, ritem);
-
- child = gsk_cross_fade_node_get_end_child (node);
- gsk_gl_renderer_add_render_item (self, projection, modelview, render_items, child, ritem);
- }
- return;
+ int n_color_stops = MIN (8, gsk_linear_gradient_node_get_n_color_stops (node));
+ const GskColorStop *stops = gsk_linear_gradient_node_peek_color_stops (node);
+ const graphene_point_t *start = gsk_linear_gradient_node_peek_start (node);
+ const graphene_point_t *end = gsk_linear_gradient_node_peek_end (node);
+ int i;
- case GSK_CONTAINER_NODE:
- {
- guint i, p;
+ item.mode = MODE_LINEAR_GRADIENT;
+ item.program = &self->linear_gradient_program;
- for (i = 0, p = gsk_container_node_get_n_children (node); i < p; i++)
+ for (i = 0; i < n_color_stops; i ++)
{
- GskRenderNode *child = gsk_container_node_get_child (node, i);
- gsk_gl_renderer_add_render_item (self, projection, modelview, render_items, child, ritem);
+ const GskColorStop *stop = stops + i;
+
+ item.linear_gradient_data.color_stops[(i * 4) + 0] = stop->color.red;
+ item.linear_gradient_data.color_stops[(i * 4) + 1] = stop->color.green;
+ item.linear_gradient_data.color_stops[(i * 4) + 2] = stop->color.blue;
+ item.linear_gradient_data.color_stops[(i * 4) + 3] = stop->color.alpha;
+ item.linear_gradient_data.color_offsets[i] = stop->offset;
}
+
+ item.linear_gradient_data.n_color_stops = n_color_stops;
+ item.linear_gradient_data.start_point = *start;
+ item.linear_gradient_data.end_point = *end;
}
- return;
+ break;
case GSK_TRANSFORM_NODE:
{
@@ -850,47 +954,57 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
projection, &transformed_mv,
render_items,
gsk_transform_node_get_child (node),
- ritem);
+ render_target);
}
return;
case GSK_NOT_A_RENDER_NODE:
+ case GSK_CONTAINER_NODE:
g_assert_not_reached ();
return;
- case GSK_LINEAR_GRADIENT_NODE:
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_BORDER_NODE:
case GSK_INSET_SHADOW_NODE:
case GSK_OUTSET_SHADOW_NODE:
- case GSK_OPACITY_NODE:
- case GSK_CLIP_NODE:
- case GSK_ROUNDED_CLIP_NODE:
case GSK_TEXT_NODE:
case GSK_BLUR_NODE:
+ case GSK_SHADOW_NODE:
+ case GSK_CROSS_FADE_NODE:
+ case GSK_BLEND_NODE:
+ case GSK_REPEAT_NODE:
default:
{
cairo_surface_t *surface;
cairo_t *cr;
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
- item.size.width,
- item.size.height);
- cairo_surface_set_device_scale (surface, scale_factor, scale_factor);
+ item.size.width * self->scale_factor,
+ item.size.height * self->scale_factor);
+ cairo_surface_set_device_scale (surface, self->scale_factor, self->scale_factor);
cr = cairo_create (surface);
- cairo_translate (cr, -node->bounds.origin.x, -node->bounds.origin.y);
+ cairo_save (cr);
+ cairo_translate (cr, -node->bounds.origin.x, -node->bounds.origin.y);
gsk_render_node_draw (node, cr);
+ cairo_restore (cr);
+
+#if HIGHLIGHT_FALLBACK
+ cairo_move_to (cr, 0, 0);
+ cairo_rectangle (cr, 0, 0, item.size.width, item.size.height);
+ cairo_set_source_rgba (cr, 1, 0, 0, 1);
+ cairo_stroke (cr);
+#endif
cairo_destroy (cr);
/* Upload the Cairo surface to a GL texture */
- item.render_data.texture_id = gsk_gl_driver_create_texture (self->gl_driver,
- item.size.width,
- item.size.height);
- gsk_gl_driver_bind_source_texture (self->gl_driver, item.render_data.texture_id);
+ item.texture_id = gsk_gl_driver_create_texture (self->gl_driver,
+ item.size.width * self->scale_factor,
+ item.size.height * self->scale_factor);
+ gsk_gl_driver_bind_source_texture (self->gl_driver, item.texture_id);
gsk_gl_driver_init_texture_with_surface (self->gl_driver,
- item.render_data.texture_id,
+ item.texture_id,
surface,
GL_NEAREST, GL_NEAREST);
@@ -900,66 +1014,62 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
break;
}
- item.render_data.program_id = program_id;
-
/* Create the vertex buffers holding the geometry of the quad */
- {
- GskQuadVertex vertex_data[N_VERTICES] = {
- { { item.min.x, item.min.y }, { 0, 0 }, },
- { { item.min.x, item.max.y }, { 0, 1 }, },
- { { item.max.x, item.min.y }, { 1, 0 }, },
-
- { { item.max.x, item.max.y }, { 1, 1 }, },
- { { item.min.x, item.max.y }, { 0, 1 }, },
- { { item.max.x, item.min.y }, { 1, 0 }, },
- };
-
- item.render_data.vao_id =
- gsk_gl_driver_create_vao_for_quad (self->gl_driver,
- item.render_data.program->position_location,
- item.render_data.program->uv_location,
- N_VERTICES,
- vertex_data);
- }
+ if (item.render_target == 0)
+ {
+ GskQuadVertex vertex_data[N_VERTICES] = {
+ { { item.min.x, item.min.y }, { 0, 0 }, },
+ { { item.min.x, item.max.y }, { 0, 1 }, },
+ { { item.max.x, item.min.y }, { 1, 0 }, },
+
+ { { item.max.x, item.max.y }, { 1, 1 }, },
+ { { item.min.x, item.max.y }, { 0, 1 }, },
+ { { item.max.x, item.min.y }, { 1, 0 }, },
+ };
+
+ item.vao_id = gsk_gl_driver_create_vao_for_quad (self->gl_driver,
+ item.program->position_location,
+ item.program->uv_location,
+ N_VERTICES,
+ vertex_data);
+ }
+ else
+ {
+ GskQuadVertex vertex_data[N_VERTICES] = {
+ { { item.min.x, item.min.y }, { 0, 1 }, },
+ { { item.min.x, item.max.y }, { 0, 0 }, },
+ { { item.max.x, item.min.y }, { 1, 1 }, },
+
+ { { item.max.x, item.max.y }, { 1, 0 }, },
+ { { item.min.x, item.max.y }, { 0, 0 }, },
+ { { item.max.x, item.min.y }, { 1, 1 }, },
+ };
+
+ item.vao_id = gsk_gl_driver_create_vao_for_quad (self->gl_driver,
+ item.program->position_location,
+ item.program->uv_location,
+ N_VERTICES,
+ vertex_data);
+ }
GSK_NOTE (OPENGL, g_print ("Adding node <%s>[%p] to render items\n",
node->name != NULL ? node->name : "unnamed",
node));
g_array_append_val (render_items, item);
- ritem = &g_array_index (render_items, RenderItem, render_items->len - 1);
-
- if (item.children != NULL)
- render_items = item.children;
}
-static gboolean
+static void
gsk_gl_renderer_validate_tree (GskGLRenderer *self,
GskRenderNode *root,
const graphene_matrix_t *projection)
{
- graphene_matrix_t identity;
-
- if (self->gl_context == NULL)
- {
- GSK_NOTE (OPENGL, g_print ("No valid GL context associated to the renderer"));
- return FALSE;
- }
-
- graphene_matrix_init_identity (&identity);
+ graphene_matrix_t modelview;
+ graphene_matrix_init_scale (&modelview, self->scale_factor, self->scale_factor, 1.0f);
gdk_gl_context_make_current (self->gl_context);
- gsk_gl_driver_begin_frame (self->gl_driver);
-
- GSK_NOTE (OPENGL, g_print ("RenderNode -> RenderItem\n"));
- gsk_gl_renderer_add_render_item (self, projection, &identity, self->render_items, root, NULL);
-
- GSK_NOTE (OPENGL, g_print ("Total render items: %d\n",
- self->render_items->len));
-
- gsk_gl_driver_end_frame (self->gl_driver);
-
- return TRUE;
+ gsk_gl_renderer_add_render_item (self, projection, &modelview, self->render_items, root,
+ self->texture_id);
}
static void
@@ -1003,15 +1113,31 @@ gsk_gl_renderer_setup_render_mode (GskGLRenderer *self)
{
GdkDrawingContext *context = gsk_renderer_get_drawing_context (GSK_RENDERER (self));
GdkWindow *window = gsk_renderer_get_window (GSK_RENDERER (self));
- GdkRectangle extents;
- int scale_factor = gdk_window_get_scale_factor (window);
+ cairo_region_t *clip = gdk_drawing_context_get_clip (context);
+ cairo_rectangle_int_t extents;
+ int window_height;
+
+ /* Fall back to RENDER_FULL */
+ if (clip == NULL)
+ {
+ glDisable (GL_SCISSOR_TEST);
+ return;
+ }
- cairo_region_get_extents (gdk_drawing_context_get_clip (context), &extents);
+ g_assert (cairo_region_num_rectangles (clip) == 1);
+
+ window_height = gdk_window_get_height (window) * self->scale_factor;
+
+ cairo_region_get_extents (clip, &extents);
+ /*cairo_region_get_rectangle (clip, 0, &extents);*/
- glScissor (extents.x * scale_factor,
- (gdk_window_get_height (window) - extents.height - extents.y) * scale_factor,
- extents.width * scale_factor, extents.height * scale_factor);
glEnable (GL_SCISSOR_TEST);
+ glScissor (extents.x * self->scale_factor,
+ window_height - (extents.height * self->scale_factor) - (extents.y * self->scale_factor),
+ extents.width * self->scale_factor,
+ extents.height * self->scale_factor);
+
+ cairo_region_destroy (clip);
break;
}
@@ -1021,8 +1147,6 @@ gsk_gl_renderer_setup_render_mode (GskGLRenderer *self)
}
}
-#define ORTHO_NEAR_PLANE -10000
-#define ORTHO_FAR_PLANE 10000
static void
gsk_gl_renderer_do_render (GskRenderer *renderer,
@@ -1042,22 +1166,29 @@ gsk_gl_renderer_do_render (GskRenderer *renderer,
profiler = gsk_renderer_get_profiler (renderer);
#endif
+ if (self->gl_context == NULL)
+ {
+ GSK_NOTE (OPENGL, g_print ("No valid GL context associated to the renderer"));
+ return;
+ }
+
+ self->viewport = *viewport;
+
/* Set up the modelview and projection matrices to fit our viewport */
graphene_matrix_init_scale (&modelview, scale_factor, scale_factor, 1.0);
graphene_matrix_init_ortho (&projection,
viewport->origin.x,
- viewport->origin.x + viewport->size.width * scale_factor,
- viewport->origin.y + viewport->size.height * scale_factor,
+ viewport->origin.x + viewport->size.width,
viewport->origin.y,
+ viewport->origin.y + viewport->size.height,
ORTHO_NEAR_PLANE,
ORTHO_FAR_PLANE);
- gsk_gl_renderer_update_frustum (self, &modelview, &projection);
-
- if (!gsk_gl_renderer_validate_tree (self, root, &projection))
- return;
+ if (self->texture_id == 0)
+ graphene_matrix_scale (&projection, 1, -1, 1);
gsk_gl_driver_begin_frame (self->gl_driver);
+ gsk_gl_renderer_validate_tree (self, root, &projection);
#ifdef G_ENABLE_DEBUG
gsk_gl_profiler_begin_gpu_region (self->gl_profiler);
@@ -1065,8 +1196,8 @@ gsk_gl_renderer_do_render (GskRenderer *renderer,
#endif
/* Ensure that the viewport is up to date */
- if (gsk_gl_driver_bind_render_target (self->gl_driver, self->texture_id))
- gsk_gl_renderer_resize_viewport (self, viewport, scale_factor);
+ gsk_gl_driver_bind_render_target (self->gl_driver, self->texture_id);
+ gsk_gl_renderer_resize_viewport (self, viewport);
gsk_gl_renderer_setup_render_mode (self);
@@ -1076,12 +1207,13 @@ gsk_gl_renderer_do_render (GskRenderer *renderer,
glDepthFunc (GL_LEQUAL);
glEnable (GL_BLEND);
+ /* Pre-multiplied alpha! */
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glBlendEquation (GL_FUNC_ADD);
- GSK_NOTE (OPENGL, g_print ("Rendering %u items\n", self->render_items->len));
for (i = 0; i < self->render_items->len; i++)
{
- RenderItem *item = &g_array_index (self->render_items, RenderItem, i);
+ const RenderItem *item = &g_array_index (self->render_items, RenderItem, i);
render_item (self, item);
}
@@ -1109,37 +1241,39 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer,
{
GskGLRenderer *self = GSK_GL_RENDERER (renderer);
GdkTexture *texture;
- cairo_surface_t *surface;
- cairo_t *cr;
+ int stride;
+ guchar *data;
+ int width, height;
g_return_val_if_fail (self->gl_context != NULL, NULL);
self->render_mode = RENDER_FULL;
+ width = ceilf (viewport->size.width);
+ height = ceilf (viewport->size.height);
gdk_gl_context_make_current (self->gl_context);
+ /* Prepare our framebuffer */
gsk_gl_driver_begin_frame (self->gl_driver);
- gsk_gl_renderer_create_buffers (self, ceilf (viewport->size.width), ceilf (viewport->size.height), 1);
+ gsk_gl_renderer_create_buffers (self, width, height, 1);
+ gsk_gl_renderer_clear (self);
gsk_gl_driver_end_frame (self->gl_driver);
+ /* Render the actual scene */
gsk_gl_renderer_do_render (renderer, root, viewport, 1);
- surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
- ceilf (viewport->size.width),
- ceilf (viewport->size.height));
- cr = cairo_create (surface);
- gdk_cairo_draw_from_gl (cr,
- gsk_renderer_get_window (renderer),
- self->texture_id,
- GL_TEXTURE,
- 1.0,
- 0, 0,
- viewport->size.width,
- viewport->size.height);
- cairo_destroy (cr);
-
- texture = gdk_texture_new_for_surface (surface);
- cairo_surface_destroy (surface);
+ /* Prepare memory for the glReadPixels call */
+ stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, width);
+ data = g_malloc (height * stride);
+
+ /* Bind our framebuffer again and read from it */
+ gsk_gl_driver_begin_frame (self->gl_driver);
+ gsk_gl_driver_bind_render_target (self->gl_driver, self->texture_id);
+ glReadPixels (0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
+ gsk_gl_driver_end_frame (self->gl_driver);
+
+ /* Create texture from the downloaded data */
+ texture = gdk_texture_new_for_data (data, width, height, stride);
return texture;
}
@@ -1149,18 +1283,20 @@ gsk_gl_renderer_render (GskRenderer *renderer,
GskRenderNode *root)
{
GskGLRenderer *self = GSK_GL_RENDERER (renderer);
+ GdkWindow *window = gsk_renderer_get_window (renderer);
graphene_rect_t viewport;
- int scale_factor;
if (self->gl_context == NULL)
return;
gdk_gl_context_make_current (self->gl_context);
- gsk_renderer_get_viewport (renderer, &viewport);
- scale_factor = gdk_window_get_scale_factor (gsk_renderer_get_window (renderer));
+ viewport.origin.x = 0;
+ viewport.origin.y = 0;
+ viewport.size.width = gdk_window_get_width (window) * self->scale_factor;
+ viewport.size.height = gdk_window_get_height (window) * self->scale_factor;
- gsk_gl_renderer_do_render (renderer, root, &viewport, scale_factor);
+ gsk_gl_renderer_do_render (renderer, root, &viewport, self->scale_factor);
gdk_gl_context_make_current (self->gl_context);
gsk_gl_renderer_clear_tree (self);
@@ -1190,6 +1326,8 @@ gsk_gl_renderer_init (GskGLRenderer *self)
graphene_matrix_init_identity (&self->mvp);
self->render_items = g_array_new (FALSE, FALSE, sizeof (RenderItem));
+ g_array_set_clear_func (self->render_items, (GDestroyNotify)destroy_render_item);
+ self->scale_factor = 1;
#ifdef G_ENABLE_DEBUG
{
diff --git a/gsk/gskshaderbuilder.c b/gsk/gskshaderbuilder.c
index 7085c41..d34360c 100644
--- a/gsk/gskshaderbuilder.c
+++ b/gsk/gskshaderbuilder.c
@@ -41,8 +41,6 @@ shader_program_free (gpointer data)
g_clear_pointer (&p->uniform_locations, g_hash_table_unref);
g_clear_pointer (&p->attribute_locations, g_hash_table_unref);
- glDeleteProgram (p->program_id);
-
g_slice_free (ShaderProgram, data);
}
diff --git a/gsk/meson.build b/gsk/meson.build
index f51eff5..95b093b 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -5,6 +5,10 @@ gsk_private_source_shaders = [
'resources/glsl/blit.vs.glsl',
'resources/glsl/color.fs.glsl',
'resources/glsl/color.vs.glsl',
+ 'resources/glsl/color_matrix.fs.glsl',
+ 'resources/glsl/color_matrix.vs.glsl',
+ 'resources/glsl/linear_gradient.fs.glsl',
+ 'resources/glsl/linear_gradient.vs.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/blend.fs.glsl b/gsk/resources/glsl/blend.fs.glsl
index 39b3e4c..1473d05 100644
--- a/gsk/resources/glsl/blend.fs.glsl
+++ b/gsk/resources/glsl/blend.fs.glsl
@@ -57,6 +57,5 @@ void main() {
// Use red for debugging missing blend modes
res = vec3(1.0, 0.0, 0.0);
}
-
- setOutputColor(vec4(res, Cs.a * uAlpha));
+ setOutputColor(vec4(res, Cs.a) * uAlpha);
}
diff --git a/gsk/resources/glsl/blend.vs.glsl b/gsk/resources/glsl/blend.vs.glsl
index 1208513..a453e32 100644
--- a/gsk/resources/glsl/blend.vs.glsl
+++ b/gsk/resources/glsl/blend.vs.glsl
@@ -1,6 +1,5 @@
void main() {
gl_Position = uMVP * vec4(aPosition, 0.0, 1.0);
- // Flip the sampling
vUv = vec2(aUv.x, aUv.y);
}
diff --git a/gsk/resources/glsl/blit.fs.glsl b/gsk/resources/glsl/blit.fs.glsl
index ceb88ef..9f2eb4c 100644
--- a/gsk/resources/glsl/blit.fs.glsl
+++ b/gsk/resources/glsl/blit.fs.glsl
@@ -1,5 +1,5 @@
void main() {
vec4 diffuse = Texture(uSource, vUv);
- setOutputColor(vec4(diffuse.xyz, diffuse.a * uAlpha));
+ setOutputColor(diffuse * uAlpha);
}
diff --git a/gsk/resources/glsl/color.fs.glsl b/gsk/resources/glsl/color.fs.glsl
index 62d4ba0..6b7e34d 100644
--- a/gsk/resources/glsl/color.fs.glsl
+++ b/gsk/resources/glsl/color.fs.glsl
@@ -1,5 +1,9 @@
uniform vec4 uColor;
void main() {
- setOutputColor(uColor);
+ vec4 color = uColor;
+
+ // Pre-multiply alpha
+ color.rgb *= color.a;
+ setOutputColor(color * uAlpha);
}
diff --git a/gsk/resources/glsl/color_matrix.fs.glsl b/gsk/resources/glsl/color_matrix.fs.glsl
new file mode 100644
index 0000000..9025bfb
--- /dev/null
+++ b/gsk/resources/glsl/color_matrix.fs.glsl
@@ -0,0 +1,20 @@
+uniform mat4 uColorMatrix;
+uniform vec4 uColorOffset;
+
+void main() {
+ vec4 diffuse = Texture(uSource, vUv);
+ vec4 color;
+
+ color = diffuse;
+
+ // Un-premultilpy
+ if (color.a != 0.0)
+ color.rgb /= color.a;
+
+ color = uColorMatrix * diffuse + uColorOffset;
+ color = clamp(color, 0.0f, 1.0f);
+
+ color.rgb *= color.a;
+
+ setOutputColor(color * uAlpha);
+}
diff --git a/gsk/resources/glsl/color_matrix.vs.glsl b/gsk/resources/glsl/color_matrix.vs.glsl
new file mode 100644
index 0000000..1208513
--- /dev/null
+++ b/gsk/resources/glsl/color_matrix.vs.glsl
@@ -0,0 +1,6 @@
+void main() {
+ gl_Position = uMVP * vec4(aPosition, 0.0, 1.0);
+
+ // Flip the sampling
+ vUv = vec2(aUv.x, aUv.y);
+}
diff --git a/gsk/resources/glsl/gl3_common.fs.glsl b/gsk/resources/glsl/gl3_common.fs.glsl
index 50f72f5..8ee5a14 100644
--- a/gsk/resources/glsl/gl3_common.fs.glsl
+++ b/gsk/resources/glsl/gl3_common.fs.glsl
@@ -3,8 +3,9 @@ precision highp float;
uniform sampler2D uSource;
uniform sampler2D uMask;
uniform mat4 uMVP;
-uniform float uAlpha;
+uniform float uAlpha = 1.0;
uniform int uBlendMode;
+uniform vec4 uViewport;
in vec2 vUv;
diff --git a/gsk/resources/glsl/gl3_common.vs.glsl b/gsk/resources/glsl/gl3_common.vs.glsl
index b90c2fe..f82f99c 100644
--- a/gsk/resources/glsl/gl3_common.vs.glsl
+++ b/gsk/resources/glsl/gl3_common.vs.glsl
@@ -1,4 +1,5 @@
uniform mat4 uMVP;
+uniform mat4 uProjection;
in vec2 aPosition;
in vec2 aUv;
diff --git a/gsk/resources/glsl/linear_gradient.fs.glsl b/gsk/resources/glsl/linear_gradient.fs.glsl
new file mode 100644
index 0000000..cbbc71c
--- /dev/null
+++ b/gsk/resources/glsl/linear_gradient.fs.glsl
@@ -0,0 +1,43 @@
+uniform vec4 uColorStops[8];
+uniform float uColorOffsets[8];
+uniform int uNumColorStops;
+uniform vec2 uStartPoint;
+uniform vec2 uEndPoint;
+
+vec4 fragCoord() {
+ vec4 f = gl_FragCoord;
+ f.x += uViewport.x;
+ f.y = (uViewport.y + uViewport.w) - f.y;
+ return f;
+}
+
+void main() {
+ float maxDist = length(uEndPoint - uStartPoint);
+
+ // Position relative to startPoint
+ vec2 pos = fragCoord().xy - uStartPoint;
+
+ // Gradient direction
+ vec2 gradient = uEndPoint - uStartPoint;
+ float gradientLength = length(gradient);
+
+ // Current pixel, projected onto the line between the start point and the end point
+ // The projection will be relative to the start point!
+ vec2 proj = (dot(gradient, pos) / (gradientLength * gradientLength)) * gradient;
+
+ // Offset of the current pixel
+ float offset = length(proj) / maxDist;
+
+ vec4 color = uColorStops[0];
+ for (int i = 1; i < uNumColorStops; i ++) {
+ if (offset >= uColorOffsets[i - 1]) {
+ float o = (offset - uColorOffsets[i - 1]) / (uColorOffsets[i] - uColorOffsets[i - 1]);
+ color = mix(uColorStops[i - 1], uColorStops[i], o);
+ }
+ }
+
+ /* Pre-multiply */
+ color.rgb *= color.a;
+
+ setOutputColor(color * uAlpha);
+}
diff --git a/gsk/resources/glsl/linear_gradient.vs.glsl b/gsk/resources/glsl/linear_gradient.vs.glsl
new file mode 100644
index 0000000..a453e32
--- /dev/null
+++ b/gsk/resources/glsl/linear_gradient.vs.glsl
@@ -0,0 +1,5 @@
+void main() {
+ gl_Position = uMVP * vec4(aPosition, 0.0, 1.0);
+
+ vUv = vec2(aUv.x, aUv.y);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]