gl renderer: Move render ops into separate file

This commit is contained in:
Timm Bäder 2017-11-22 21:02:50 +01:00
parent 823369f275
commit a1d3e77347
4 changed files with 487 additions and 426 deletions

View File

@ -12,6 +12,7 @@
#include "gskshaderbuilderprivate.h"
#include "gskglglyphcacheprivate.h"
#include "gdk/gdktextureprivate.h"
#include "gskglrenderopsprivate.h"
#include "gskprivate.h"
@ -26,9 +27,6 @@
#define ORTHO_NEAR_PLANE -10000
#define ORTHO_FAR_PLANE 10000
#define N_VERTICES 6
#define N_PROGRAMS 6
#define HIGHLIGHT_FALLBACK 0
#define DEBUG_OPS 0
@ -54,7 +52,7 @@ dump_framebuffer (const char *filename, int w, int h)
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);
s = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, w, h, stride);
cairo_surface_write_to_png (s, filename);
cairo_surface_destroy (s);
@ -81,102 +79,6 @@ font_has_color_glyphs (const PangoFont *font)
static void
gsk_gl_renderer_setup_render_mode (GskGLRenderer *self);
typedef struct
{
int index; /* Into the renderer's program array */
const char *name; /* For debugging */
int id;
/* Common locations (gl_common)*/
int source_location;
int mask_location;
int uv_location;
int position_location;
int alpha_location;
int blend_mode_location;
int viewport_location;
int projection_location;
int modelview_location;
int clip_location;
int clip_corner_widths_location;
int clip_corner_heights_location;
/* Program-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;
};
struct {
int clip_bounds_location;
int corner_widths_location;
int corner_heights_location;
};
};
} Program;
enum {
MODE_BLIT = 1,
MODE_COLOR,
MODE_COLORING,
MODE_TEXTURE,
MODE_COLOR_MATRIX,
MODE_LINEAR_GRADIENT,
N_MODES
};
enum {
OP_NONE,
OP_CHANGE_OPACITY = 1,
OP_CHANGE_COLOR = 2,
OP_CHANGE_PROJECTION = 3,
OP_CHANGE_MODELVIEW = 4,
OP_CHANGE_PROGRAM = 5,
OP_CHANGE_RENDER_TARGET = 6,
OP_CHANGE_CLIP = 7,
OP_CHANGE_VIEWPORT = 8,
OP_CHANGE_SOURCE_TEXTURE = 9,
OP_CHANGE_VAO = 10,
OP_CHANGE_LINEAR_GRADIENT = 11,
OP_DRAW = 12,
};
typedef struct
{
guint op;
union {
float opacity;
graphene_matrix_t modelview; // TODO: Make both matrix members just "matrix".
graphene_matrix_t projection;
const Program *program;
GdkRGBA color;
gsize vao_offset;
GskQuadVertex vertex_data[N_VERTICES]; // New Quad
int texture_id;
int render_target_id;
GskRoundedRect clip;
graphene_rect_t viewport;
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;
};
} RenderOp;
#ifdef G_ENABLE_DEBUG
typedef struct
{
@ -216,7 +118,7 @@ struct _GskGLRenderer
GskGLProfiler *gl_profiler;
union {
Program programs[N_PROGRAMS];
Program programs[GL_N_PROGRAMS];
struct {
Program blend_program;
Program blit_program;
@ -250,264 +152,6 @@ struct _GskGLRendererClass
G_DEFINE_TYPE (GskGLRenderer, gsk_gl_renderer, GSK_TYPE_RENDERER)
typedef struct
{
/* Per-Program State */
struct {
GskRoundedRect clip;
graphene_matrix_t modelview;
graphene_matrix_t projection;
int source_texture;
graphene_rect_t viewport;
} program_state[N_PROGRAMS];
/* Current global state */
const Program *current_program;
int current_render_target;
int current_vao;
int current_texture;
GskRoundedRect current_clip;
graphene_matrix_t current_modelview;
graphene_matrix_t current_projection;
graphene_rect_t current_viewport;
float current_opacity;
gsize buffer_size;
GskGLRenderer *renderer;
} RenderOpBuilder;
static void
add_program_op (RenderOpBuilder *builder,
const Program *new_program)
{
static const GskRoundedRect empty_clip;
static const graphene_matrix_t empty_matrix;
static const graphene_rect_t empty_rect;
RenderOp op;
if (builder->current_program == new_program)
return;
op.op = OP_CHANGE_PROGRAM;
op.program = new_program;
g_array_append_val (builder->renderer->render_ops, op);
builder->current_program = new_program;
/* If the projection is not yet set for this program, we use the current one. */
if (memcmp (&empty_matrix, &builder->program_state[new_program->index].projection, sizeof (graphene_matrix_t)) == 0 ||
memcmp (&builder->current_projection, &builder->program_state[new_program->index].projection, sizeof (graphene_matrix_t)) != 0)
{
op.op = OP_CHANGE_PROJECTION;
op.projection = builder->current_projection;
g_array_append_val (builder->renderer->render_ops, op);
builder->program_state[new_program->index].projection = builder->current_projection;
}
if (memcmp (&empty_matrix, &builder->program_state[new_program->index].modelview, sizeof (graphene_matrix_t)) == 0 ||
memcmp (&builder->current_modelview, &builder->program_state[new_program->index].modelview, sizeof (graphene_matrix_t)) != 0)
{
op.op = OP_CHANGE_MODELVIEW;
op.modelview = builder->current_modelview;
g_array_append_val (builder->renderer->render_ops, op);
builder->program_state[new_program->index].modelview = builder->current_modelview;
}
if (memcmp (&empty_rect, &builder->program_state[new_program->index].viewport, sizeof (graphene_rect_t)) == 0 ||
memcmp (&builder->current_viewport, &builder->program_state[new_program->index].viewport, sizeof (graphene_rect_t)) != 0)
{
op.op = OP_CHANGE_VIEWPORT;
op.viewport = builder->current_viewport;
g_array_append_val (builder->renderer->render_ops, op);
builder->program_state[new_program->index].viewport = builder->current_viewport;
}
if (memcmp (&empty_clip, &builder->program_state[new_program->index].clip, sizeof (GskRoundedRect)) == 0 ||
memcmp (&builder->current_clip, &builder->program_state[new_program->index].clip, sizeof (GskRoundedRect)) != 0)
{
op.op = OP_CHANGE_CLIP;
op.clip = builder->current_clip;
g_array_append_val (builder->renderer->render_ops, op);
builder->program_state[new_program->index].clip = builder->current_clip;
}
if (graphene_rect_equal (&empty_rect, &builder->program_state[new_program->index].viewport) ||
!graphene_rect_equal (&builder->current_viewport, &builder->program_state[new_program->index].viewport))
{
op.op = OP_CHANGE_VIEWPORT;
op.viewport = builder->current_viewport;
g_array_append_val (builder->renderer->render_ops, op);
builder->program_state[new_program->index].viewport = builder->current_viewport;
}
}
static GskRoundedRect
add_clip_op (RenderOpBuilder *builder,
const GskRoundedRect *new_clip)
{
RenderOp op;
GskRoundedRect prev_clip;
op.op = OP_CHANGE_CLIP;
op.clip = *new_clip;
g_array_append_val (builder->renderer->render_ops, op);
if (builder->current_program != NULL)
builder->program_state[builder->current_program->index].clip = *new_clip;
prev_clip = builder->current_clip;
builder->current_clip = *new_clip;
return prev_clip;
}
static graphene_matrix_t
add_modelview_op (RenderOpBuilder *builder,
const graphene_matrix_t *matrix)
{
RenderOp op;
graphene_matrix_t prev_mv;
RenderOp *last_op;
last_op = &g_array_index (builder->renderer->render_ops, RenderOp, builder->renderer->render_ops->len - 1);
if (last_op->op == OP_CHANGE_MODELVIEW)
{
last_op->modelview = *matrix;
}
else
{
op.op = OP_CHANGE_MODELVIEW;
op.modelview = *matrix;
g_array_append_val (builder->renderer->render_ops, op);
}
if (builder->current_program != NULL)
builder->program_state[builder->current_program->index].modelview = *matrix;
prev_mv = builder->current_modelview;
builder->current_modelview = *matrix;
return prev_mv;
}
static graphene_matrix_t
add_projection_op (RenderOpBuilder *builder,
const graphene_matrix_t *matrix)
{
RenderOp op;
graphene_matrix_t prev_proj;
op.op = OP_CHANGE_PROJECTION;
op.projection = *matrix;
g_array_append_val (builder->renderer->render_ops, op);
if (builder->current_program != NULL)
builder->program_state[builder->current_program->index].projection = *matrix;
prev_proj = builder->current_projection;
builder->current_projection = *matrix;
return prev_proj;
}
static graphene_rect_t
add_viewport_op (RenderOpBuilder *builder,
const graphene_rect_t *viewport)
{
RenderOp op;
graphene_rect_t prev_viewport;
op.op = OP_CHANGE_VIEWPORT;
op.viewport = *viewport;
g_array_append_val (builder->renderer->render_ops, op);
if (builder->current_program != NULL)
builder->program_state[builder->current_program->index].viewport = *viewport;
prev_viewport = builder->current_viewport;
builder->current_viewport = *viewport;
return prev_viewport;
}
static void
add_texture_op (RenderOpBuilder *builder,
int texture_id)
{
RenderOp op;
if (builder->current_texture == texture_id)
return;
op.op = OP_CHANGE_SOURCE_TEXTURE;
op.texture_id = texture_id;
g_array_append_val (builder->renderer->render_ops, op);
builder->current_texture = texture_id;
}
static float
add_opacity_op (RenderOpBuilder *builder,
float opacity)
{
RenderOp op;
float prev_opacity;
if (builder->current_opacity == opacity)
return opacity;
op.op = OP_CHANGE_OPACITY;
op.opacity = opacity;
g_array_append_val (builder->renderer->render_ops, op);
prev_opacity = builder->current_opacity;
builder->current_opacity = opacity;
return prev_opacity;
}
static int
add_render_target_op (RenderOpBuilder *builder,
int render_target_id)
{
RenderOp op;
int prev_render_target;
if (builder->current_render_target == render_target_id)
return render_target_id;
prev_render_target = builder->current_render_target;
op.op = OP_CHANGE_RENDER_TARGET;
op.render_target_id = render_target_id;
g_array_append_val (builder->renderer->render_ops, op);
builder->current_render_target = render_target_id;
return prev_render_target;
}
static void
add_draw_op (RenderOpBuilder *builder,
const GskQuadVertex vertex_data[N_VERTICES])
{
RenderOp op;
gsize offset = builder->buffer_size / sizeof (GskQuadVertex);
op.op = OP_CHANGE_VAO;
memcpy (&op.vertex_data, vertex_data, sizeof(GskQuadVertex) * N_VERTICES);
g_array_append_val (builder->renderer->render_ops, op);
builder->buffer_size += sizeof (GskQuadVertex) * N_VERTICES;
op.op = OP_DRAW;
op.vao_offset = offset;
g_array_append_val (builder->renderer->render_ops, op);
}
static void
add_op (RenderOpBuilder *builder,
const RenderOp *op)
{
g_array_append_val (builder->renderer->render_ops, *op);
}
static void
gsk_gl_renderer_dispose (GObject *gobject)
{
@ -643,6 +287,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
goto out;
}
self->blend_program.index = 0;
self->blend_program.name = "blend";
init_common_locations (self, builder, &self->blend_program);
self->blit_program.id = gsk_shader_builder_create_program (builder,
@ -656,6 +301,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
goto out;
}
self->blit_program.index = 1;
self->blit_program.name = "blit";
init_common_locations (self, builder, &self->blit_program);
self->color_program.id = gsk_shader_builder_create_program (builder,
@ -669,6 +315,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
goto out;
}
self->color_program.index = 2;
self->color_program.name = "color";
init_common_locations (self, builder, &self->color_program);
INIT_PROGRAM_UNIFORM_LOCATION (color_program, color_location, "uColor");
@ -733,7 +380,7 @@ gsk_gl_renderer_realize (GskRenderer *renderer,
GError **error)
{
GskGLRenderer *self = GSK_GL_RENDERER (renderer);
GskQuadVertex vertex_data[N_VERTICES] = {
GskQuadVertex vertex_data[GL_N_VERTICES] = {
{ { 0, 0 }, { 0, 0 }, },
{ { 0, 1 }, { 0, 1 }, },
{ { 1, 0 }, { 1, 0 }, },
@ -771,7 +418,7 @@ gsk_gl_renderer_realize (GskRenderer *renderer,
gsk_gl_glyph_cache_init (&self->glyph_cache, self->gl_driver);
gsk_gl_driver_create_permanent_vao_for_quad (self->gl_driver, N_VERTICES, vertex_data,
gsk_gl_driver_create_permanent_vao_for_quad (self->gl_driver, GL_N_VERTICES, vertex_data,
&self->full_vao_id, &self->full_vao_buffer_id);
return TRUE;
@ -971,7 +618,7 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
float max_y = min_y + node->bounds.size.height;
/* Default vertex data */
GskQuadVertex vertex_data[N_VERTICES] = {
GskQuadVertex vertex_data[GL_N_VERTICES] = {
{ { min_x, min_y }, { 0, 0 }, },
{ { min_x, max_y }, { 0, 1 }, },
{ { max_x, min_y }, { 1, 0 }, },
@ -981,10 +628,11 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
{ { max_x, min_y }, { 1, 0 }, },
};
/*if (gsk_render_node_get_node_type (node) != GSK_CONTAINER_NODE)*/
/*g_message ("Adding ops for node %s with type %u", node->name,*/
/*gsk_render_node_get_node_type (node));*/
#if DEBUG_OPS
if (gsk_render_node_get_node_type (node) != GSK_CONTAINER_NODE)
g_message ("Adding ops for node %s with type %u", node->name,
gsk_render_node_get_node_type (node));
#endif
switch (gsk_render_node_get_node_type (node))
{
@ -1008,11 +656,11 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
{
RenderOp op;
add_program_op (builder, &self->color_program);
ops_set_program (builder, &self->color_program);
op.op = OP_CHANGE_COLOR;
op.color = *gsk_color_node_peek_color (node);
add_op (builder, &op);
add_draw_op (builder, vertex_data);
ops_add (builder, &op);
ops_draw (builder, vertex_data);
}
break;
@ -1028,9 +676,9 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
texture,
gl_min_filter,
gl_mag_filter);
add_program_op (builder, &self->blit_program);
add_texture_op (builder, texture_id);
add_draw_op (builder, vertex_data);
ops_set_program (builder, &self->blit_program);
ops_set_texture (builder, texture_id);
ops_draw (builder, vertex_data);
}
break;
@ -1042,18 +690,18 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
graphene_matrix_init_from_matrix (&transform, gsk_transform_node_peek_transform (node));
graphene_matrix_multiply (&transform, &builder->current_modelview, &transformed_mv);
prev_mv = add_modelview_op (builder, &transformed_mv);
prev_mv = ops_set_modelview (builder, &transformed_mv);
gsk_gl_renderer_add_render_ops (self, child, builder);
add_modelview_op (builder, &prev_mv);
ops_set_modelview (builder, &prev_mv);
}
break;
case GSK_OPACITY_NODE:
{
int render_target;
int texture;
int texture_id;
int prev_render_target;
float prev_opacity;
graphene_matrix_t identity;
@ -1061,7 +709,7 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
graphene_matrix_t prev_modelview;
graphene_rect_t prev_viewport;
graphene_matrix_t item_proj;
GskQuadVertex vertex_data[N_VERTICES] = {
GskQuadVertex vertex_data[GL_N_VERTICES] = {
{ { min_x, min_y }, { 0, 1 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
@ -1071,12 +719,14 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
{ { max_x, min_y }, { 1, 1 }, },
};
texture = gsk_gl_driver_create_texture (self->gl_driver,
node->bounds.size.width,
node->bounds.size.height);
gsk_gl_driver_bind_source_texture (self->gl_driver, texture);
gsk_gl_driver_init_texture_empty (self->gl_driver, texture);
render_target = gsk_gl_driver_create_render_target (self->gl_driver, texture, TRUE, TRUE);
texture_id = gsk_gl_driver_create_texture (self->gl_driver, max_x - min_x, max_y - min_y);
gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id);
gsk_gl_driver_init_texture_empty (self->gl_driver, texture_id);
render_target = gsk_gl_driver_create_render_target (self->gl_driver, texture_id, TRUE, TRUE);
/* Clear the framebuffer now, once */
RenderOp op;
op.op = OP_CLEAR;
graphene_matrix_init_ortho (&item_proj,
min_x, max_x,
@ -1085,23 +735,26 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
graphene_matrix_scale (&item_proj, 1, -1, 1);
graphene_matrix_init_identity (&identity);
prev_render_target = add_render_target_op (builder, render_target);
prev_projection = add_projection_op (builder, &item_proj);
prev_modelview = add_modelview_op (builder, &identity);
prev_viewport = add_viewport_op (builder, &node->bounds);
prev_render_target = ops_set_render_target (builder, render_target);
/* Clear since we use this rendertarget for the first time */
ops_add (builder, &op);
prev_projection = ops_set_projection (builder, &item_proj);
prev_modelview = ops_set_modelview (builder, &identity);
prev_viewport = ops_set_viewport (builder, &node->bounds);
gsk_gl_renderer_add_render_ops (self, gsk_opacity_node_get_child (node), builder);
add_viewport_op (builder, &prev_viewport);
add_modelview_op (builder, &prev_modelview);
add_projection_op (builder, &prev_projection);
add_render_target_op (builder, prev_render_target);
ops_set_viewport (builder, &prev_viewport);
ops_set_modelview (builder, &prev_modelview);
ops_set_projection (builder, &prev_projection);
ops_set_render_target (builder, prev_render_target);
add_program_op (builder, &self->blit_program);
prev_opacity = add_opacity_op (builder, gsk_opacity_node_get_opacity (node));
add_texture_op (builder, texture);
add_draw_op (builder, vertex_data);
add_opacity_op (builder, prev_opacity);
/* Now draw the texture with the node's opacity */
ops_set_program (builder, &self->blit_program);
prev_opacity = ops_set_opacity (builder, gsk_opacity_node_get_opacity (node));
ops_set_texture (builder, texture_id);
ops_draw (builder, vertex_data);
ops_set_opacity (builder, prev_opacity);
}
break;
@ -1125,14 +778,14 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
op.linear_gradient.color_offsets[i] = stop->offset;
}
add_program_op (builder, &self->linear_gradient_program);
ops_set_program (builder, &self->linear_gradient_program);
op.op = OP_CHANGE_LINEAR_GRADIENT;
op.linear_gradient.n_color_stops = n_color_stops;
op.linear_gradient.start_point = *start;
op.linear_gradient.end_point = *end;
add_op (builder, &op);
ops_add (builder, &op);
add_draw_op (builder, vertex_data);
ops_draw (builder, vertex_data);
}
break;
@ -1153,9 +806,9 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
gsk_rounded_rect_init_from_rect (&child_clip, &intersection, 0.0f);
prev_clip = add_clip_op (builder, &child_clip);
prev_clip = ops_set_clip (builder, &child_clip);
gsk_gl_renderer_add_render_ops (self, child, builder);
add_clip_op (builder, &prev_clip);
ops_set_clip (builder, &prev_clip);
}
break;
@ -1179,9 +832,9 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
&rounded_clip->corner[2],
&rounded_clip->corner[3]);
prev_clip = add_clip_op (builder, &child_clip);
prev_clip = ops_set_clip (builder, &child_clip);
gsk_gl_renderer_add_render_ops (self, child, builder);
add_clip_op (builder, &prev_clip);
ops_set_clip (builder, &prev_clip);
}
break;
@ -1228,20 +881,20 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
/* If the font has color glyphs, we don't need to recolor anything */
if (font_has_color_glyphs (font))
{
add_program_op (builder, &self->blit_program);
ops_set_program (builder, &self->blit_program);
}
else
{
RenderOp op;
add_program_op (builder, &self->coloring_program);
ops_set_program (builder, &self->coloring_program);
op.op = OP_CHANGE_COLOR;
op.color = *gsk_text_node_peek_color (node);
add_op (builder, &op);
ops_add (builder, &op);
}
add_texture_op (builder, gsk_gl_glyph_cache_get_glyph_image (&self->glyph_cache,
ops_set_texture (builder, gsk_gl_glyph_cache_get_glyph_image (&self->glyph_cache,
glyph)->texture_id);
{
@ -1255,7 +908,7 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
glyph_w = glyph->draw_width;
glyph_h = glyph->draw_height;
GskQuadVertex vertex_data[N_VERTICES] = {
GskQuadVertex vertex_data[GL_N_VERTICES] = {
{ { glyph_x, glyph_y }, { tx, ty }, },
{ { glyph_x, glyph_y + glyph_h }, { tx, ty2 }, },
{ { glyph_x + glyph_w, glyph_y }, { tx2, ty }, },
@ -1265,7 +918,7 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
{ { glyph_x + glyph_w, glyph_y }, { tx2, ty }, },
};
add_draw_op (builder, vertex_data);
ops_draw (builder, vertex_data);
}
x_position += gi->geometry.width;
@ -1274,7 +927,6 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
}
break;
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_BORDER_NODE:
case GSK_INSET_SHADOW_NODE:
@ -1324,9 +976,9 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
cairo_surface_destroy (surface);
add_program_op (builder, &self->blit_program);
add_texture_op (builder, texture_id);
add_draw_op (builder, vertex_data);
ops_set_program (builder, &self->blit_program);
ops_set_texture (builder, texture_id);
ops_draw (builder, vertex_data);
}
}
}
@ -1360,8 +1012,8 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
if (op->op == OP_CHANGE_VAO)
{
memcpy (vertex_data + buffer_index, &op->vertex_data, sizeof (GskQuadVertex) * N_VERTICES);
buffer_index += sizeof (GskQuadVertex) * N_VERTICES / sizeof (float);
memcpy (vertex_data + buffer_index, &op->vertex_data, sizeof (GskQuadVertex) * GL_N_VERTICES);
buffer_index += sizeof (GskQuadVertex) * GL_N_VERTICES / sizeof (float);
}
}
@ -1410,24 +1062,24 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
case OP_CHANGE_PROGRAM:
program = op->program;
glUseProgram (op->program->id);
OP_PRINT (" -> Program: %d", op->program->id);
OP_PRINT (" -> Program: %d(%s)", op->program->index, op->program->name);
break;
case OP_CHANGE_RENDER_TARGET:
OP_PRINT (" -> Render Target: %d", op->render_target_id);
glBindFramebuffer (GL_FRAMEBUFFER, op->render_target_id);
if (op->render_target_id != 0)
{
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);
}
glDisable (GL_SCISSOR_TEST);
else
{
/* Reset glScissor, etc. */
gsk_gl_renderer_setup_render_mode (self);
}
gsk_gl_renderer_setup_render_mode (self); /* Reset glScissor etc. */
break;
case OP_CLEAR:
glClearColor (0, 0, 0, 0);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
break;
case OP_CHANGE_VIEWPORT:
@ -1439,6 +1091,7 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
break;
case OP_CHANGE_OPACITY:
OP_PRINT (" -> Opacity %f", op->opacity);
glUniform1f (program->alpha_location, op->opacity);
break;
@ -1494,8 +1147,8 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
break;
case OP_DRAW:
OP_PRINT (" -> draw %ld\n", op->vao_offset);
glDrawArrays (GL_TRIANGLES, op->vao_offset, N_VERTICES);
OP_PRINT (" -> draw %ld and program %s\n", op->vao_offset, program->name);
glDrawArrays (GL_TRIANGLES, op->vao_offset, GL_N_VERTICES);
break;
default:
@ -1559,6 +1212,7 @@ gsk_gl_renderer_do_render (GskRenderer *renderer,
render_op_builder.current_viewport = *viewport;
render_op_builder.current_render_target = self->texture_id;
render_op_builder.current_opacity = 1.0f;
render_op_builder.render_ops = self->render_ops;
gsk_rounded_rect_init_from_rect (&render_op_builder.current_clip, &self->viewport, 0.0f);
gsk_gl_renderer_add_render_ops (self, root, &render_op_builder);

244
gsk/gl/gskglrenderops.c Normal file
View File

@ -0,0 +1,244 @@
#include "gskglrenderopsprivate.h"
void
ops_set_program (RenderOpBuilder *builder,
const Program *program)
{
/* The tricky part about this is that we want to initialize all uniforms of a program
* to the current value from the builder, but only once. */
static const GskRoundedRect empty_clip;
static const graphene_matrix_t empty_matrix;
static const graphene_rect_t empty_rect;
RenderOp op;
if (builder->current_program == program)
return;
op.op = OP_CHANGE_PROGRAM;
op.program = program;
g_array_append_val (builder->render_ops, op);
builder->current_program = program;
/* If the projection is not yet set for this program, we use the current one. */
if (memcmp (&empty_matrix, &builder->program_state[program->index].projection, sizeof (graphene_matrix_t)) == 0 ||
memcmp (&builder->current_projection, &builder->program_state[program->index].projection, sizeof (graphene_matrix_t)) != 0)
{
op.op = OP_CHANGE_PROJECTION;
op.projection = builder->current_projection;
g_array_append_val (builder->render_ops, op);
builder->program_state[program->index].projection = builder->current_projection;
}
if (memcmp (&empty_matrix, &builder->program_state[program->index].modelview, sizeof (graphene_matrix_t)) == 0 ||
memcmp (&builder->current_modelview, &builder->program_state[program->index].modelview, sizeof (graphene_matrix_t)) != 0)
{
op.op = OP_CHANGE_MODELVIEW;
op.modelview = builder->current_modelview;
g_array_append_val (builder->render_ops, op);
builder->program_state[program->index].modelview = builder->current_modelview;
}
if (memcmp (&empty_rect, &builder->program_state[program->index].viewport, sizeof (graphene_rect_t)) == 0 ||
memcmp (&builder->current_viewport, &builder->program_state[program->index].viewport, sizeof (graphene_rect_t)) != 0)
{
op.op = OP_CHANGE_VIEWPORT;
op.viewport = builder->current_viewport;
g_array_append_val (builder->render_ops, op);
builder->program_state[program->index].viewport = builder->current_viewport;
}
if (memcmp (&empty_clip, &builder->program_state[program->index].clip, sizeof (GskRoundedRect)) == 0 ||
memcmp (&builder->current_clip, &builder->program_state[program->index].clip, sizeof (GskRoundedRect)) != 0)
{
op.op = OP_CHANGE_CLIP;
op.clip = builder->current_clip;
g_array_append_val (builder->render_ops, op);
builder->program_state[program->index].clip = builder->current_clip;
}
if (graphene_rect_equal (&empty_rect, &builder->program_state[program->index].viewport) ||
!graphene_rect_equal (&builder->current_viewport, &builder->program_state[program->index].viewport))
{
op.op = OP_CHANGE_VIEWPORT;
op.viewport = builder->current_viewport;
g_array_append_val (builder->render_ops, op);
builder->program_state[program->index].viewport = builder->current_viewport;
}
}
GskRoundedRect
ops_set_clip (RenderOpBuilder *builder,
const GskRoundedRect *clip)
{
RenderOp op;
GskRoundedRect prev_clip;
op.op = OP_CHANGE_CLIP;
op.clip = *clip;
g_array_append_val (builder->render_ops, op);
if (builder->current_program != NULL)
builder->program_state[builder->current_program->index].clip = *clip;
prev_clip = builder->current_clip;
builder->current_clip = *clip;
return prev_clip;
}
graphene_matrix_t
ops_set_modelview (RenderOpBuilder *builder,
const graphene_matrix_t *modelview)
{
RenderOp op;
graphene_matrix_t prev_mv;
RenderOp *last_op;
last_op = &g_array_index (builder->render_ops, RenderOp, builder->render_ops->len - 1);
if (last_op->op == OP_CHANGE_MODELVIEW)
{
last_op->modelview = *modelview;
}
else
{
op.op = OP_CHANGE_MODELVIEW;
op.modelview = *modelview;
g_array_append_val (builder->render_ops, op);
}
if (builder->current_program != NULL)
builder->program_state[builder->current_program->index].modelview = *modelview;
prev_mv = builder->current_modelview;
builder->current_modelview = *modelview;
return prev_mv;
}
graphene_matrix_t
ops_set_projection (RenderOpBuilder *builder,
const graphene_matrix_t *projection)
{
RenderOp op;
graphene_matrix_t prev_mv;
RenderOp *last_op;
last_op = &g_array_index (builder->render_ops, RenderOp, builder->render_ops->len - 1);
if (last_op->op == OP_CHANGE_PROJECTION)
{
last_op->projection = *projection;
}
else
{
op.op = OP_CHANGE_PROJECTION;
op.projection = *projection;
g_array_append_val (builder->render_ops, op);
}
if (builder->current_program != NULL)
builder->program_state[builder->current_program->index].projection = *projection;
prev_mv = builder->current_projection;
builder->current_projection = *projection;
return prev_mv;
}
graphene_rect_t
ops_set_viewport (RenderOpBuilder *builder,
const graphene_rect_t *viewport)
{
RenderOp op;
graphene_rect_t prev_viewport;
op.op = OP_CHANGE_VIEWPORT;
op.viewport = *viewport;
g_array_append_val (builder->render_ops, op);
if (builder->current_program != NULL)
builder->program_state[builder->current_program->index].viewport = *viewport;
prev_viewport = builder->current_viewport;
builder->current_viewport = *viewport;
return prev_viewport;
}
void
ops_set_texture (RenderOpBuilder *builder,
int texture_id)
{
RenderOp op;
if (builder->current_texture == texture_id)
return;
op.op = OP_CHANGE_SOURCE_TEXTURE;
op.texture_id = texture_id;
g_array_append_val (builder->render_ops, op);
builder->current_texture = texture_id;
}
int
ops_set_render_target (RenderOpBuilder *builder,
int render_target_id)
{
RenderOp op;
int prev_render_target;
if (builder->current_render_target == render_target_id)
return render_target_id;
prev_render_target = builder->current_render_target;
op.op = OP_CHANGE_RENDER_TARGET;
op.render_target_id = render_target_id;
g_array_append_val (builder->render_ops, op);
builder->current_render_target = render_target_id;
return prev_render_target;
}
float
ops_set_opacity (RenderOpBuilder *builder,
float opacity)
{
RenderOp op;
float prev_opacity;
if (builder->current_opacity == opacity)
return opacity;
op.op = OP_CHANGE_OPACITY;
op.opacity = opacity;
g_array_append_val (builder->render_ops, op);
prev_opacity = builder->current_opacity;
builder->current_opacity = opacity;
return prev_opacity;
}
void
ops_draw (RenderOpBuilder *builder,
const GskQuadVertex vertex_data[GL_N_VERTICES])
{
RenderOp op;
gsize offset = builder->buffer_size / sizeof (GskQuadVertex);
op.op = OP_CHANGE_VAO;
memcpy (&op.vertex_data, vertex_data, sizeof(GskQuadVertex) * GL_N_VERTICES);
g_array_append_val (builder->render_ops, op);
builder->buffer_size += sizeof (GskQuadVertex) * GL_N_VERTICES;
op.op = OP_DRAW;
op.vao_offset = offset;
g_array_append_val (builder->render_ops, op);
}
void
ops_add (RenderOpBuilder *builder,
const RenderOp *op)
{
g_array_append_val (builder->render_ops, *op);
}

View File

@ -0,0 +1,162 @@
#ifndef __GSK_GL_RENDER_OPS_H__
#define __GSK_GL_RENDER_OPS_H__
#include <glib.h>
#include <graphene.h>
#include <gdk/gdk.h>
#include "gskgldriverprivate.h"
#include "gskroundedrectprivate.h"
#include "gskglrendererprivate.h"
#define GL_N_VERTICES 6
#define GL_N_PROGRAMS 6
enum {
OP_NONE,
OP_CHANGE_OPACITY = 1,
OP_CHANGE_COLOR = 2,
OP_CHANGE_PROJECTION = 3,
OP_CHANGE_MODELVIEW = 4,
OP_CHANGE_PROGRAM = 5,
OP_CHANGE_RENDER_TARGET = 6,
OP_CHANGE_CLIP = 7,
OP_CHANGE_VIEWPORT = 8,
OP_CHANGE_SOURCE_TEXTURE = 9,
OP_CHANGE_VAO = 10,
OP_CHANGE_LINEAR_GRADIENT = 11,
OP_CLEAR = 12,
OP_DRAW = 13,
};
typedef struct
{
int index; /* Into the renderer's program array */
const char *name; /* For debugging */
int id;
/* Common locations (gl_common)*/
int source_location;
int mask_location;
int uv_location;
int position_location;
int alpha_location;
int blend_mode_location;
int viewport_location;
int projection_location;
int modelview_location;
int clip_location;
int clip_corner_widths_location;
int clip_corner_heights_location;
/* Program-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;
};
struct {
int clip_bounds_location;
int corner_widths_location;
int corner_heights_location;
};
};
} Program;
typedef struct
{
guint op;
union {
float opacity;
graphene_matrix_t modelview; /* TODO: Make both matrix members just "matrix" */
graphene_matrix_t projection;
const Program *program;
int texture_id;
int render_target_id;
GdkRGBA color;
gsize vao_offset;
GskQuadVertex vertex_data[6];
GskRoundedRect clip;
graphene_rect_t viewport;
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;
};
} RenderOp;
typedef struct
{
/* Per-Program State */
struct {
GskRoundedRect clip;
graphene_matrix_t modelview;
graphene_matrix_t projection;
int source_texture;
graphene_rect_t viewport;
} program_state[GL_N_PROGRAMS];
/* Current global state */
const Program *current_program;
int current_render_target;
int current_vao;
int current_texture;
GskRoundedRect current_clip;
graphene_matrix_t current_modelview;
graphene_matrix_t current_projection;
graphene_rect_t current_viewport;
float current_opacity;
gsize buffer_size;
GArray *render_ops;
GskGLRenderer *renderer;
} RenderOpBuilder;
void ops_set_program (RenderOpBuilder *builder,
const Program *program);
GskRoundedRect ops_set_clip (RenderOpBuilder *builder,
const GskRoundedRect *clip);
graphene_matrix_t ops_set_modelview (RenderOpBuilder *builder,
const graphene_matrix_t *modelview);
graphene_matrix_t ops_set_projection (RenderOpBuilder *builder,
const graphene_matrix_t *projection);
graphene_rect_t ops_set_viewport (RenderOpBuilder *builder,
const graphene_rect_t *viewport);
void ops_set_texture (RenderOpBuilder *builder,
int texture_id);
int ops_set_render_target (RenderOpBuilder *builder,
int render_target_id);
float ops_set_opacity (RenderOpBuilder *builder,
float opacity);
void ops_draw (RenderOpBuilder *builder,
const GskQuadVertex vertex_data[GL_N_VERTICES]);
void ops_add (RenderOpBuilder *builder,
const RenderOp *op);
#endif

View File

@ -34,6 +34,7 @@ gsk_private_sources = files([
'gl/gskglglyphcache.c',
'gl/gskglimage.c',
'gl/gskgldriver.c',
'gl/gskglrenderops.c'
])
gsk_public_headers = files([