From 0d0cb13c8d54499d6a4a74e7cfe0db3190d04501 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 14 Aug 2013 11:19:22 +0100 Subject: [PATCH] stage: Adjust drawing to include the window scaling factor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to transparently support high DPI density displays, we must maintain all coordinates and sizes exactly as they are now — but draw them on a surface that is scaled up by a certain factor. In order to do that we have to change the viewport and initial transformation matrix so that they are scaled up by the same factor. https://bugzilla.gnome.org/show_bug.cgi?id=705915 --- clutter/clutter-stage-private.h | 3 + clutter/clutter-stage.c | 122 ++++++++++++++++++++++++-------- 2 files changed, 94 insertions(+), 31 deletions(-) diff --git a/clutter/clutter-stage-private.h b/clutter/clutter-stage-private.h index 9ccba3f5b..890fcdccc 100644 --- a/clutter/clutter-stage-private.h +++ b/clutter/clutter-stage-private.h @@ -119,6 +119,9 @@ gboolean _clutter_stage_update_state (ClutterStage *stag ClutterStageState unset_state, ClutterStageState set_state); +void _clutter_stage_set_scale_factor (ClutterStage *stage, + int factor); + G_END_DECLS #endif /* __CLUTTER_STAGE_PRIVATE_H__ */ diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index 984c1d792..a7eba200e 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -371,6 +371,7 @@ clutter_stage_allocate (ClutterActor *self, float new_width, new_height; float width, height; cairo_rectangle_int_t window_size; + int scale_factor; if (priv->impl == NULL) return; @@ -471,6 +472,12 @@ clutter_stage_allocate (ClutterActor *self, * allocation. */ _clutter_stage_window_get_geometry (priv->impl, &window_size); + + scale_factor = _clutter_stage_window_get_scale_factor (priv->impl); + + window_size.width *= scale_factor; + window_size.height *= scale_factor; + cogl_onscreen_clutter_backend_set_size (window_size.width, window_size.height); @@ -481,10 +488,13 @@ clutter_stage_allocate (ClutterActor *self, if (CLUTTER_NEARBYINT (old_width) != CLUTTER_NEARBYINT (new_width) || CLUTTER_NEARBYINT (old_height) != CLUTTER_NEARBYINT (new_height)) { + int real_width = CLUTTER_NEARBYINT (new_width); + int real_height = CLUTTER_NEARBYINT (new_height); + _clutter_stage_set_viewport (CLUTTER_STAGE (self), 0, 0, - CLUTTER_NEARBYINT (new_width), - CLUTTER_NEARBYINT (new_height)); + real_width, + real_height); /* Note: we don't assume that set_viewport will queue a full redraw * since it may bail-out early if something preemptively set the @@ -629,21 +639,29 @@ _clutter_stage_do_paint (ClutterStage *stage, { ClutterStagePrivate *priv = stage->priv; float clip_poly[8]; + float viewport[4]; cairo_rectangle_int_t geom; + int window_scale; if (priv->impl == NULL) return; _clutter_stage_window_get_geometry (priv->impl, &geom); + window_scale = _clutter_stage_window_get_scale_factor (priv->impl); + + viewport[0] = priv->viewport[0] * window_scale; + viewport[1] = priv->viewport[1] * window_scale; + viewport[2] = priv->viewport[2] * window_scale; + viewport[3] = priv->viewport[3] * window_scale; if (clip) { - clip_poly[0] = MAX (clip->x, 0); - clip_poly[1] = MAX (clip->y, 0); - clip_poly[2] = MIN (clip->x + clip->width, geom.width); + clip_poly[0] = MAX (clip->x * window_scale, 0); + clip_poly[1] = MAX (clip->y * window_scale, 0); + clip_poly[2] = MIN ((clip->x + clip->width) * window_scale, geom.width * window_scale); clip_poly[3] = clip_poly[1]; clip_poly[4] = clip_poly[2]; - clip_poly[5] = MIN (clip->y + clip->height, geom.height); + clip_poly[5] = MIN ((clip->y + clip->height) * window_scale, geom.height * window_scale); clip_poly[6] = clip_poly[0]; clip_poly[7] = clip_poly[5]; } @@ -651,12 +669,12 @@ _clutter_stage_do_paint (ClutterStage *stage, { clip_poly[0] = 0; clip_poly[1] = 0; - clip_poly[2] = geom.width; + clip_poly[2] = geom.width * window_scale; clip_poly[3] = 0; - clip_poly[4] = geom.width; - clip_poly[5] = geom.height; + clip_poly[4] = geom.width * window_scale; + clip_poly[5] = geom.height * window_scale; clip_poly[6] = 0; - clip_poly[7] = geom.height; + clip_poly[7] = geom.height * window_scale; } CLUTTER_NOTE (CLIPPING, "Setting stage clip too: " @@ -667,7 +685,7 @@ _clutter_stage_do_paint (ClutterStage *stage, _cogl_util_get_eye_planes_for_screen_poly (clip_poly, 4, - priv->viewport, + viewport, &priv->projection, &priv->inverse_projection, priv->current_clip_planes); @@ -1437,6 +1455,7 @@ _clutter_stage_do_pick (ClutterStage *stage, gboolean is_clipped; gint read_x; gint read_y; + int window_scale; CLUTTER_STATIC_COUNTER (do_pick_counter, "_clutter_stage_do_pick counter", @@ -1486,6 +1505,7 @@ _clutter_stage_do_pick (ClutterStage *stage, context = _clutter_context_get_default (); clutter_stage_ensure_current (stage); + window_scale = _clutter_stage_window_get_scale_factor (priv->impl); /* It's possible that we currently have a static scene and have renderered a * full, unclipped pick buffer. If so we can simply continue to read from @@ -1493,7 +1513,9 @@ _clutter_stage_do_pick (ClutterStage *stage, if (_clutter_stage_get_pick_buffer_valid (stage, mode)) { CLUTTER_TIMER_START (_clutter_uprof_context, pick_read); - cogl_read_pixels (x, y, 1, 1, + cogl_read_pixels (x * window_scale, + y * window_scale, + 1, 1, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_RGBA_8888_PRE, pixel); @@ -1523,21 +1545,21 @@ _clutter_stage_do_pick (ClutterStage *stage, _clutter_stage_window_get_dirty_pixel (priv->impl, &dirty_x, &dirty_y); if (G_LIKELY (!(clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS))) - cogl_clip_push_window_rectangle (dirty_x, dirty_y, 1, 1); + cogl_clip_push_window_rectangle (dirty_x * window_scale, dirty_y * window_scale, 1, 1); - cogl_set_viewport (priv->viewport[0] - x + dirty_x, - priv->viewport[1] - y + dirty_y, - priv->viewport[2], - priv->viewport[3]); + cogl_set_viewport (priv->viewport[0] * window_scale - x * window_scale + dirty_x * window_scale, + priv->viewport[1] * window_scale - y * window_scale + dirty_y * window_scale, + priv->viewport[2] * window_scale, + priv->viewport[3] * window_scale); - read_x = dirty_x; - read_y = dirty_y; + read_x = dirty_x * window_scale; + read_y = dirty_y * window_scale; is_clipped = TRUE; } else { - read_x = x; - read_y = y; + read_x = x * window_scale; + read_y = y * window_scale; is_clipped = FALSE; } @@ -2259,6 +2281,7 @@ clutter_stage_init (ClutterStage *self) ClutterStagePrivate *priv; ClutterStageWindow *impl; ClutterBackend *backend; + int window_scale = 1; GError *error; /* a stage is a top-level object */ @@ -2276,6 +2299,7 @@ clutter_stage_init (ClutterStage *self) { _clutter_stage_set_window (self, impl); _clutter_stage_window_get_geometry (priv->impl, &geom); + window_scale = _clutter_stage_window_get_scale_factor (priv->impl); } else { @@ -2329,8 +2353,8 @@ clutter_stage_init (ClutterStage *self) priv->perspective.aspect, priv->perspective.z_near, 50, /* distance to 2d plane */ - geom.width, - geom.height); + geom.width * window_scale, + geom.height * window_scale); /* FIXME - remove for 2.0 */ @@ -2348,7 +2372,10 @@ clutter_stage_init (ClutterStage *self) g_signal_connect (self, "notify::min-height", G_CALLBACK (clutter_stage_notify_min_size), NULL); - _clutter_stage_set_viewport (self, 0, 0, geom.width, geom.height); + _clutter_stage_set_viewport (self, + 0, 0, + geom.width, + geom.height); _clutter_stage_set_pick_buffer_valid (self, FALSE, CLUTTER_PICK_ALL); priv->picks_per_frame = 0; @@ -3403,6 +3430,16 @@ clutter_stage_ensure_viewport (ClutterStage *stage) clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); } +static void +clutter_stage_apply_scale (ClutterStage *stage) +{ + int factor; + + factor = _clutter_stage_window_get_scale_factor (stage->priv->impl); + if (factor != 1) + cogl_matrix_scale (&stage->priv->view, factor, factor, 1.f); +} + # define _DEG_TO_RAD(d) ((d) * ((float) G_PI / 180.0f)) /* This calculates a distance into the view frustum to position the @@ -3547,16 +3584,20 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage) if (priv->dirty_viewport) { ClutterPerspective perspective; + int window_scale; float z_2d; CLUTTER_NOTE (PAINT, "Setting up the viewport { w:%f, h:%f }", - priv->viewport[2], priv->viewport[3]); + priv->viewport[2], + priv->viewport[3]); - cogl_set_viewport (priv->viewport[0], - priv->viewport[1], - priv->viewport[2], - priv->viewport[3]); + window_scale = _clutter_stage_window_get_scale_factor (priv->impl); + + cogl_set_viewport (priv->viewport[0] * window_scale, + priv->viewport[1] * window_scale, + priv->viewport[2] * window_scale, + priv->viewport[3] * window_scale); perspective = priv->perspective; @@ -3587,8 +3628,10 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage) perspective.aspect, perspective.z_near, z_2d, - priv->viewport[2], - priv->viewport[3]); + priv->viewport[2] * window_scale, + priv->viewport[3] * window_scale); + + clutter_stage_apply_scale (stage); priv->dirty_viewport = FALSE; } @@ -4652,3 +4695,20 @@ clutter_stage_invoke_paint_callback (ClutterStage *stage) if (stage->priv->paint_callback != NULL) stage->priv->paint_callback (stage, stage->priv->paint_data); } + +void +_clutter_stage_set_scale_factor (ClutterStage *stage, + int factor) +{ + ClutterStagePrivate *priv = stage->priv; + + if (CLUTTER_ACTOR_IN_DESTRUCTION (stage)) + return; + + if (priv->impl == NULL) + return; + + _clutter_stage_window_set_scale_factor (priv->impl, factor); + + clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); +}