From b69d2aa6a0e0e8d69354f6eda0bb9ab68a76f2ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 19 Sep 2019 11:27:50 +0200 Subject: [PATCH] stage: Compute view perspective when parameters changed Clutter stage used to compute the initial projection using a fixed z translation which wasn't matching the one we computed in calculate_z_translation(). This caused to have a wrong initial projection on startup which was then correctly recomputed only at the first paint. However, since this calculation doesn't depend on view, but only on viewport size, perspective's fovy and z_near we can safely do this at startup and only when any of those parameters change. Then we can move the computation out _clutter_stage_maybe_setup_viewport() since the cogl framebuffer viewport sizes aren't affecting this. Fixes https://gitlab.gnome.org/GNOME/gnome-shell/issues/1639 https://gitlab.gnome.org/GNOME/mutter/merge_requests/803 --- clutter/clutter/clutter-stage.c | 104 +++++++++++++++----------------- 1 file changed, 47 insertions(+), 57 deletions(-) diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c index 85dc406a8..245cb8997 100644 --- a/clutter/clutter/clutter-stage.c +++ b/clutter/clutter/clutter-stage.c @@ -226,6 +226,7 @@ static void capture_view_into (ClutterStage *stage, cairo_rectangle_int_t *rect, uint8_t *data, int stride); +static void clutter_stage_update_view_perspective (ClutterStage *stage); static void clutter_container_iface_init (ClutterContainerIface *iface); @@ -2354,29 +2355,6 @@ clutter_stage_init (ClutterStage *self) clutter_actor_set_background_color (CLUTTER_ACTOR (self), &default_stage_color); - priv->perspective.fovy = 60.0; /* 60 Degrees */ - priv->perspective.aspect = (float) geom.width / (float) geom.height; - priv->perspective.z_near = 0.1; - priv->perspective.z_far = 100.0; - - cogl_matrix_init_identity (&priv->projection); - cogl_matrix_perspective (&priv->projection, - priv->perspective.fovy, - priv->perspective.aspect, - priv->perspective.z_near, - priv->perspective.z_far); - cogl_matrix_get_inverse (&priv->projection, - &priv->inverse_projection); - cogl_matrix_init_identity (&priv->view); - cogl_matrix_view_2d_in_perspective (&priv->view, - priv->perspective.fovy, - priv->perspective.aspect, - priv->perspective.z_near, - 50, /* distance to 2d plane */ - geom.width, - geom.height); - - /* FIXME - remove for 2.0 */ priv->fog.z_near = 1.0; priv->fog.z_far = 2.0; @@ -2544,6 +2522,7 @@ clutter_stage_set_perspective (ClutterStage *stage, priv->has_custom_perspective = TRUE; clutter_stage_set_perspective_internal (stage, perspective); + clutter_stage_update_view_perspective (stage); } /** @@ -2670,6 +2649,7 @@ _clutter_stage_set_viewport (ClutterStage *stage, priv->viewport[2] = width; priv->viewport[3] = height; + clutter_stage_update_view_perspective (stage); _clutter_stage_dirty_viewport (stage); queue_full_redraw (stage); @@ -3506,6 +3486,50 @@ calculate_z_translation (float z_near) + z_near; } +static void +clutter_stage_update_view_perspective (ClutterStage *stage) +{ + ClutterStagePrivate *priv = stage->priv; + ClutterPerspective perspective; + float z_2d; + + perspective = priv->perspective; + + /* Ideally we want to regenerate the perspective matrix whenever + * the size changes but if the user has provided a custom matrix + * then we don't want to override it */ + if (!priv->has_custom_perspective) + { + perspective.fovy = 60.0; /* 60 Degrees */ + perspective.z_near = 0.1; + perspective.aspect = priv->viewport[2] / priv->viewport[3]; + z_2d = calculate_z_translation (perspective.z_near); + + /* NB: z_2d is only enough room for 85% of the stage_height between + * the stage and the z_near plane. For behind the stage plane we + * want a more consistent gap of 10 times the stage_height before + * hitting the far plane so we calculate that relative to the final + * height of the stage plane at the z_2d_distance we got... */ + perspective.z_far = z_2d + + tanf (_DEG_TO_RAD (perspective.fovy / 2.0f)) * z_2d * 20.0f; + + clutter_stage_set_perspective_internal (stage, &perspective); + } + else + { + z_2d = calculate_z_translation (perspective.z_near); + } + + cogl_matrix_init_identity (&priv->view); + cogl_matrix_view_2d_in_perspective (&priv->view, + perspective.fovy, + perspective.aspect, + perspective.z_near, + z_2d, + priv->viewport[2], + priv->viewport[3]); +} + void _clutter_stage_maybe_setup_viewport (ClutterStage *stage, ClutterStageView *view) @@ -3516,7 +3540,6 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage, if (clutter_stage_view_is_dirty_viewport (view)) { cairo_rectangle_int_t view_layout; - ClutterPerspective perspective; float fb_scale; float viewport_offset_x; float viewport_offset_y; @@ -3524,7 +3547,6 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage, float viewport_y; float viewport_width; float viewport_height; - float z_2d; CLUTTER_NOTE (PAINT, "Setting up the viewport { w:%f, h:%f }", @@ -3544,38 +3566,6 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage, viewport_x, viewport_y, viewport_width, viewport_height); - perspective = priv->perspective; - - /* Ideally we want to regenerate the perspective matrix whenever - * the size changes but if the user has provided a custom matrix - * then we don't want to override it */ - if (!priv->has_custom_perspective) - { - perspective.aspect = priv->viewport[2] / priv->viewport[3]; - z_2d = calculate_z_translation (perspective.z_near); - - /* NB: z_2d is only enough room for 85% of the stage_height between - * the stage and the z_near plane. For behind the stage plane we - * want a more consistent gap of 10 times the stage_height before - * hitting the far plane so we calculate that relative to the final - * height of the stage plane at the z_2d_distance we got... */ - perspective.z_far = z_2d + - tanf (_DEG_TO_RAD (perspective.fovy / 2.0f)) * z_2d * 20.0f; - - clutter_stage_set_perspective_internal (stage, &perspective); - } - else - z_2d = calculate_z_translation (perspective.z_near); - - cogl_matrix_init_identity (&priv->view); - cogl_matrix_view_2d_in_perspective (&priv->view, - perspective.fovy, - perspective.aspect, - perspective.z_near, - z_2d, - priv->viewport[2], - priv->viewport[3]); - clutter_stage_view_set_dirty_viewport (view, FALSE); }