mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-27 06:00:22 +00:00
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:
parent
d3c45cb979
commit
58c2bea959
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user