stage: Adjust drawing to include the window scaling factor
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
This commit is contained in:
parent
b9072a5e21
commit
0d0cb13c8d
@ -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__ */
|
||||
|
@ -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,17 +3584,21 @@ _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]);
|
||||
|
||||
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;
|
||||
|
||||
/* Ideally we want to regenerate the perspective matrix whenever
|
||||
@ -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));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user