gl renderer: Stop determining the matrix category ourselves

Use the category we get from transform nodes and add ops_ API to supply
one when we set a graphene_matrix_t directly.
This commit is contained in:
Timm Bäder 2019-02-23 07:50:51 +01:00
parent d3c45cb979
commit 58c2bea959
3 changed files with 186 additions and 137 deletions

View File

@ -249,6 +249,8 @@ node_supports_transform (GskRenderNode *node)
case GSK_OPACITY_NODE:
case GSK_COLOR_MATRIX_NODE:
case GSK_TEXTURE_NODE:
case GSK_TRANSFORM_NODE:
case GSK_CROSS_FADE_NODE:
return TRUE;
default:
@ -769,7 +771,6 @@ render_transform_node (GskGLRenderer *self,
const graphene_matrix_t *node_transform = gsk_transform_node_peek_transform (node);
GskRenderNode *child = gsk_transform_node_get_child (node);
switch (category)
{
case GSK_MATRIX_CATEGORY_IDENTITY:
@ -789,23 +790,9 @@ render_transform_node (GskGLRenderer *self,
case GSK_MATRIX_CATEGORY_2D_AFFINE:
{
const float scale = ops_get_scale (builder);
graphene_matrix_t transform, transformed_mv;
const float dx = builder->dx;
const float dy = builder->dy;
graphene_matrix_init_from_matrix (&transform, node_transform);
graphene_matrix_multiply (&transform, builder->current_modelview, &transformed_mv);
graphene_matrix_translate (&transformed_mv,
&(graphene_point3d_t) { builder->dx * scale, builder->dy * scale, 0});
builder->dx = 0;
builder->dy = 0;
ops_push_modelview (builder, &transformed_mv);
ops_push_modelview (builder, node_transform, category);
gsk_gl_renderer_add_render_ops (self, child, builder);
ops_pop_modelview (builder);
builder->dx = dx;
builder->dy = dy;
}
break;
@ -814,8 +801,6 @@ render_transform_node (GskGLRenderer *self,
case GSK_MATRIX_CATEGORY_INVERTIBLE:
default:
{
const float scale = ops_get_scale (builder);
graphene_matrix_t transform, transformed_mv;
const float min_x = child->bounds.origin.x;
const float min_y = child->bounds.origin.y;
const float max_x = min_x + child->bounds.size.width;
@ -823,53 +808,56 @@ render_transform_node (GskGLRenderer *self,
int texture_id;
gboolean is_offscreen;
graphene_matrix_init_from_matrix (&transform, node_transform);
graphene_matrix_multiply (&transform, builder->current_modelview, &transformed_mv);
graphene_matrix_translate (&transformed_mv,
&(graphene_point3d_t) { builder->dx * scale, builder->dy * scale, 0});
ops_push_modelview (builder, node_transform, category);
ops_push_modelview (builder, &transformed_mv);
/* For non-trivial transforms, we draw everything on a texture and then
* draw the texture transformed. */
/* TODO: We should compute a modelview containing only the "non-trivial"
* part (e.g. the rotation) and use that. We want to keep the scale
* for the texture.
*/
add_offscreen_ops (self, builder,
&child->bounds,
child,
&texture_id, &is_offscreen,
RESET_CLIP | RESET_OPACITY);
ops_set_texture (builder, texture_id);
ops_set_program (builder, &self->blit_program);
if (is_offscreen)
if (node_supports_transform (child))
{
const GskQuadVertex offscreen_vertex_data[GL_N_VERTICES] = {
{ { min_x, min_y }, { 0, 1 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
{ { max_x, max_y }, { 1, 0 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
};
ops_draw (builder, offscreen_vertex_data);
gsk_gl_renderer_add_render_ops (self, child, builder);
}
else
{
const GskQuadVertex onscreen_vertex_data[GL_N_VERTICES] = {
{ { min_x, min_y }, { 0, 0 }, },
{ { min_x, max_y }, { 0, 1 }, },
{ { max_x, min_y }, { 1, 0 }, },
/* For non-trivial transforms, we draw everything on a texture and then
* draw the texture transformed. */
/* TODO: We should compute a modelview containing only the "non-trivial"
* part (e.g. the rotation) and use that. We want to keep the scale
* for the texture.
*/
add_offscreen_ops (self, builder,
&child->bounds,
child,
&texture_id, &is_offscreen,
RESET_CLIP | RESET_OPACITY);
ops_set_texture (builder, texture_id);
ops_set_program (builder, &self->blit_program);
{ { max_x, max_y }, { 1, 1 }, },
{ { min_x, max_y }, { 0, 1 }, },
{ { max_x, min_y }, { 1, 0 }, },
};
if (is_offscreen)
{
const GskQuadVertex offscreen_vertex_data[GL_N_VERTICES] = {
{ { min_x, min_y }, { 0, 1 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
ops_draw (builder, onscreen_vertex_data);
{ { max_x, max_y }, { 1, 0 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
};
ops_draw (builder, offscreen_vertex_data);
}
else
{
const GskQuadVertex onscreen_vertex_data[GL_N_VERTICES] = {
{ { min_x, min_y }, { 0, 0 }, },
{ { min_x, max_y }, { 0, 1 }, },
{ { max_x, min_y }, { 1, 0 }, },
{ { max_x, max_y }, { 1, 1 }, },
{ { min_x, max_y }, { 0, 1 }, },
{ { max_x, min_y }, { 1, 0 }, },
};
ops_draw (builder, onscreen_vertex_data);
}
}
ops_pop_modelview (builder);
@ -1306,7 +1294,7 @@ render_outset_shadow_node (GskGLRenderer *self,
op.op = OP_CLEAR;
ops_add (builder, &op);
prev_projection = ops_set_projection (builder, &item_proj);
ops_push_modelview (builder, &identity);
ops_set_modelview (builder, &identity, GSK_MATRIX_CATEGORY_IDENTITY);
prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height));
/* Draw outline */
@ -2368,7 +2356,7 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
break;
case GSK_DEBUG_NODE:
gsk_gl_renderer_add_render_ops (self,
gsk_gl_renderer_add_render_ops (self,
gsk_debug_node_get_child (node),
builder);
break;
@ -2523,7 +2511,7 @@ add_offscreen_ops (GskGLRenderer *self,
op.op = OP_CLEAR;
ops_add (builder, &op);
prev_projection = ops_set_projection (builder, &item_proj);
ops_push_modelview (builder, &identity);
ops_set_modelview (builder, &identity, GSK_MATRIX_CATEGORY_IDENTITY);
prev_viewport = ops_set_viewport (builder,
&GRAPHENE_RECT_INIT (bounds->origin.x * scale,
bounds->origin.y * scale,
@ -2783,7 +2771,8 @@ gsk_gl_renderer_do_render (GskRenderer *renderer,
render_op_builder.current_viewport = *viewport;
render_op_builder.current_opacity = 1.0f;
render_op_builder.render_ops = self->render_ops;
ops_push_modelview (&render_op_builder, &modelview);
ops_set_modelview (&render_op_builder, &modelview,
scale_factor == 1 ? GSK_MATRIX_CATEGORY_IDENTITY : GSK_MATRIX_CATEGORY_2D_AFFINE);
/* Initial clip is self->render_region! */
if (self->render_region != NULL)

View File

@ -63,63 +63,55 @@ static void
extract_matrix_metadata (const graphene_matrix_t *m,
OpsMatrixMetadata *md)
{
graphene_vec3_t col1;
graphene_vec3_t col2;
switch (md->category)
{
case GSK_MATRIX_CATEGORY_IDENTITY:
md->scale_x = 1;
md->scale_y = 1;
break;
/* Translate */
md->translate_x = graphene_matrix_get_value (m, 3, 0);
md->translate_y = graphene_matrix_get_value (m, 3, 1);
case GSK_MATRIX_CATEGORY_2D_TRANSLATE:
md->translate_x = graphene_matrix_get_value (m, 3, 0);
md->translate_y = graphene_matrix_get_value (m, 3, 1);
md->scale_x = 1;
md->scale_y = 1;
break;
/* Scale */
graphene_vec3_init (&col1,
graphene_matrix_get_value (m, 0, 0),
graphene_matrix_get_value (m, 1, 0),
graphene_matrix_get_value (m, 2, 0));
case GSK_MATRIX_CATEGORY_UNKNOWN:
case GSK_MATRIX_CATEGORY_ANY:
case GSK_MATRIX_CATEGORY_INVERTIBLE:
case GSK_MATRIX_CATEGORY_2D_AFFINE:
{
graphene_vec3_t col1;
graphene_vec3_t col2;
graphene_vec3_init (&col2,
graphene_matrix_get_value (m, 0, 1),
graphene_matrix_get_value (m, 1, 1),
graphene_matrix_get_value (m, 2, 1));
md->translate_x = graphene_matrix_get_value (m, 3, 0);
md->translate_y = graphene_matrix_get_value (m, 3, 1);
md->scale_x = graphene_vec3_length (&col1);
md->scale_y = graphene_vec3_length (&col2);
graphene_vec3_init (&col1,
graphene_matrix_get_value (m, 0, 0),
graphene_matrix_get_value (m, 1, 0),
graphene_matrix_get_value (m, 2, 0));
/* A simple matrix (in our case) is one that doesn't do anything but scale
* and/or translate.
*
* For orher matrices, we fall back to offscreen drawing.
*/
md->simple = TRUE;
{
static const guchar check_zero[4][4] = {
{ 0, 1, 0, 1 }, /* If any of the values marked as '1' here is non-zero, */
{ 1, 0, 0, 1 }, /* We have to resort to offscreen drawing later on. */
{ 1, 1, 0, 1 },
{ 0, 0, 0, 0 },
};
int x, y;
graphene_vec3_init (&col2,
graphene_matrix_get_value (m, 0, 1),
graphene_matrix_get_value (m, 1, 1),
graphene_matrix_get_value (m, 2, 1));
for (x = 0; x < 4; x ++)
for (y = 0; y < 4; y ++)
if (check_zero[y][x] &&
graphene_matrix_get_value (m, y, x) != 0.0f)
{
md->simple = FALSE;
goto out;
}
}
out:
md->only_translation = (md->simple && md->scale_x == 1 && md->scale_y == 1);
md->scale_x = graphene_vec3_length (&col1);
md->scale_y = graphene_vec3_length (&col2);
}
break;
default:
{}
}
}
void
ops_transform_bounds_modelview (const RenderOpBuilder *builder,
const graphene_rect_t *src,
graphene_rect_t *dst)
{
const float scale = ops_get_scale (builder);
const MatrixStackEntry *head;
g_assert (builder->mv_stack != NULL);
@ -127,34 +119,32 @@ ops_transform_bounds_modelview (const RenderOpBuilder *builder,
head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
if (head->metadata.only_translation)
switch (head->metadata.category)
{
case GSK_MATRIX_CATEGORY_IDENTITY:
*dst = *src;
graphene_rect_offset (dst,
head->metadata.translate_x,
head->metadata.translate_y);
}
else
{
break;
case GSK_MATRIX_CATEGORY_2D_TRANSLATE:
*dst = *src;
dst->origin.x += head->metadata.translate_x;
dst->origin.y += head->metadata.translate_y;
break;
/* TODO: Handle scale */
case GSK_MATRIX_CATEGORY_2D_AFFINE:
case GSK_MATRIX_CATEGORY_UNKNOWN:
case GSK_MATRIX_CATEGORY_ANY:
case GSK_MATRIX_CATEGORY_INVERTIBLE:
default:
graphene_matrix_transform_bounds (builder->current_modelview,
src,
dst);
}
graphene_rect_offset (dst, builder->dx * scale, builder->dy * scale);
}
gboolean
ops_modelview_is_simple (const RenderOpBuilder *builder)
{
const MatrixStackEntry *head;
g_assert (builder->mv_stack != NULL);
g_assert (builder->mv_stack->len >= 1);
head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
return head->metadata.simple;
dst->origin.x += builder->dx * head->metadata.scale_x;
dst->origin.y += builder->dy * head->metadata.scale_y;
}
void
@ -303,8 +293,8 @@ ops_has_clip (RenderOpBuilder *self)
}
static void
ops_set_modelview (RenderOpBuilder *builder,
const graphene_matrix_t *modelview)
ops_set_modelview_internal (RenderOpBuilder *builder,
const graphene_matrix_t *modelview)
{
RenderOp op;
@ -338,9 +328,12 @@ ops_set_modelview (RenderOpBuilder *builder,
builder->current_program_state->modelview = *modelview;
}
/* This sets the modelview to the given one without looking at the
* one that's currently set */
void
ops_push_modelview (RenderOpBuilder *builder,
const graphene_matrix_t *mv)
ops_set_modelview (RenderOpBuilder *builder,
const graphene_matrix_t *mv,
GskMatrixCategory mv_category)
{
MatrixStackEntry *entry;
@ -353,10 +346,64 @@ ops_push_modelview (RenderOpBuilder *builder,
entry = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
entry->matrix = *mv;
entry->metadata.category = mv_category;
entry->metadata.dx_before = builder->dx;
entry->metadata.dy_before = builder->dy;
extract_matrix_metadata (mv, &entry->metadata);
builder->dx = 0;
builder->dy = 0;
builder->current_modelview = &entry->matrix;
ops_set_modelview (builder, mv);
ops_set_modelview_internal (builder, &entry->matrix);
}
/* This sets the given modelview to the one we get when multiplying
* the given modelview with the current one. */
void
ops_push_modelview (RenderOpBuilder *builder,
const graphene_matrix_t *mv,
GskMatrixCategory mv_category)
{
float scale = ops_get_scale (builder);
MatrixStackEntry *entry;
if (G_UNLIKELY (builder->mv_stack == NULL))
builder->mv_stack = g_array_new (FALSE, TRUE, sizeof (MatrixStackEntry));
g_assert (builder->mv_stack != NULL);
g_array_set_size (builder->mv_stack, builder->mv_stack->len + 1);
entry = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
if (G_LIKELY (builder->mv_stack->len >= 2))
{
const MatrixStackEntry *cur;
cur = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 2);
/* Multiply given matrix with current modelview */
graphene_matrix_multiply (mv, &cur->matrix, &entry->matrix);
graphene_matrix_translate (&entry->matrix,
&(graphene_point3d_t) { builder->dx * scale, builder->dy * scale, 0});
entry->metadata.category = MIN (mv_category, cur->metadata.category);
}
else
{
entry->matrix = *mv;
entry->metadata.category = mv_category;
}
entry->metadata.dx_before = builder->dx;
entry->metadata.dy_before = builder->dy;
extract_matrix_metadata (mv, &entry->metadata);
builder->dx = 0;
builder->dy = 0;
builder->current_modelview = &entry->matrix;
ops_set_modelview_internal (builder, &entry->matrix);
}
void
@ -368,6 +415,10 @@ ops_pop_modelview (RenderOpBuilder *builder)
g_assert (builder->mv_stack);
g_assert (builder->mv_stack->len >= 1);
head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
builder->dx = head->metadata.dx_before;
builder->dy = head->metadata.dy_before;
builder->mv_stack->len --;
head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
m = &head->matrix;
@ -375,7 +426,7 @@ ops_pop_modelview (RenderOpBuilder *builder)
if (builder->mv_stack->len >= 1)
{
builder->current_modelview = m;
ops_set_modelview (builder, m);
ops_set_modelview_internal (builder, m);
}
else
{
@ -684,6 +735,9 @@ ops_draw (RenderOpBuilder *builder,
builder->buffer_size += sizeof (GskQuadVertex) * GL_N_VERTICES;
}
/* The offset is only valid for the current modelview.
* Setting a new modelview will add the offset to that matrix
* and reset the internal offset to 0. */
void
ops_offset (RenderOpBuilder *builder,
float x,

View File

@ -8,6 +8,7 @@
#include "gskgldriverprivate.h"
#include "gskroundedrectprivate.h"
#include "gskglrendererprivate.h"
#include "gskrendernodeprivate.h"
#define GL_N_VERTICES 6
#define GL_N_PROGRAMS 11
@ -21,8 +22,10 @@ typedef struct
float scale_x;
float scale_y;
guint simple : 1;
guint only_translation : 1;
float dx_before;
float dy_before;
GskMatrixCategory category;
} OpsMatrixMetadata;
typedef struct
@ -277,9 +280,12 @@ void ops_dump_framebuffer (RenderOpBuilder *builder,
void ops_finish (RenderOpBuilder *builder);
void ops_push_modelview (RenderOpBuilder *builder,
const graphene_matrix_t *mv);
const graphene_matrix_t *mv,
GskMatrixCategory mv_category);
void ops_set_modelview (RenderOpBuilder *builder,
const graphene_matrix_t *mv,
GskMatrixCategory mv_category);
void ops_pop_modelview (RenderOpBuilder *builder);
gboolean ops_modelview_is_simple (const RenderOpBuilder *builder);
float ops_get_scale (const RenderOpBuilder *builder);
void ops_set_program (RenderOpBuilder *builder,