clutter: Add ability to scale stage views

This commit adds the ability to set a scale on a scale view. This will
cause the content in the stage view to be painted with the given scale,
while still keeping the configured layout on the stage. In effect, for
a stage view with scale 'n', this means the framebuffer of a given stage
will 'n' times larger, keeping the same size on the stage.

https://bugzilla.gnome.org/show_bug.cgi?id=777732
This commit is contained in:
Jonas Ådahl 2017-02-24 17:38:47 +08:00
parent 0952409de4
commit 63450d69d3
4 changed files with 78 additions and 41 deletions

View File

@ -28,6 +28,7 @@ enum
PROP_LAYOUT, PROP_LAYOUT,
PROP_FRAMEBUFFER, PROP_FRAMEBUFFER,
PROP_OFFSCREEN, PROP_OFFSCREEN,
PROP_SCALE,
PROP_LAST PROP_LAST
}; };
@ -37,6 +38,7 @@ static GParamSpec *obj_props[PROP_LAST];
typedef struct _ClutterStageViewPrivate typedef struct _ClutterStageViewPrivate
{ {
cairo_rectangle_int_t layout; cairo_rectangle_int_t layout;
int scale;
CoglFramebuffer *framebuffer; CoglFramebuffer *framebuffer;
CoglOffscreen *offscreen; CoglOffscreen *offscreen;
@ -141,6 +143,15 @@ clutter_stage_view_blit_offscreen (ClutterStageView *view,
cogl_framebuffer_pop_matrix (priv->framebuffer); cogl_framebuffer_pop_matrix (priv->framebuffer);
} }
int
clutter_stage_view_get_scale (ClutterStageView *view)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
return priv->scale;
}
gboolean gboolean
clutter_stage_view_is_dirty_viewport (ClutterStageView *view) clutter_stage_view_is_dirty_viewport (ClutterStageView *view)
{ {
@ -229,6 +240,9 @@ clutter_stage_view_get_property (GObject *object,
case PROP_OFFSCREEN: case PROP_OFFSCREEN:
g_value_set_boxed (value, priv->offscreen); g_value_set_boxed (value, priv->offscreen);
break; break;
case PROP_SCALE:
g_value_set_int (value, priv->scale);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} }
@ -257,6 +271,9 @@ clutter_stage_view_set_property (GObject *object,
case PROP_OFFSCREEN: case PROP_OFFSCREEN:
priv->offscreen = g_value_dup_boxed (value); priv->offscreen = g_value_dup_boxed (value);
break; break;
case PROP_SCALE:
priv->scale = g_value_get_int (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} }
@ -284,6 +301,7 @@ clutter_stage_view_init (ClutterStageView *view)
priv->dirty_viewport = TRUE; priv->dirty_viewport = TRUE;
priv->dirty_projection = TRUE; priv->dirty_projection = TRUE;
priv->scale = 1;
} }
static void static void
@ -323,5 +341,13 @@ clutter_stage_view_class_init (ClutterStageViewClass *klass)
G_PARAM_CONSTRUCT_ONLY | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS); G_PARAM_STATIC_STRINGS);
obj_props[PROP_SCALE] =
g_param_spec_int ("scale",
"View scale",
"The view scale",
1, G_MAXINT, 1,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, PROP_LAST, obj_props); g_object_class_install_properties (object_class, PROP_LAST, obj_props);
} }

View File

@ -60,6 +60,9 @@ void clutter_stage_view_transform_to_onscreen (ClutterStageView *vie
void clutter_stage_view_blit_offscreen (ClutterStageView *view, void clutter_stage_view_blit_offscreen (ClutterStageView *view,
const cairo_rectangle_int_t *clip); const cairo_rectangle_int_t *clip);
CLUTTER_AVAILABLE_IN_MUTTER
int clutter_stage_view_get_scale (ClutterStageView *view);
gboolean clutter_stage_view_is_dirty_viewport (ClutterStageView *view); gboolean clutter_stage_view_is_dirty_viewport (ClutterStageView *view);
void clutter_stage_view_set_dirty_viewport (ClutterStageView *view, void clutter_stage_view_set_dirty_viewport (ClutterStageView *view,

View File

@ -1380,6 +1380,8 @@ _clutter_stage_do_pick_on_view (ClutterStage *stage,
gint read_y; gint read_y;
int window_scale; int window_scale;
float fb_width, fb_height; float fb_width, fb_height;
int view_scale;
int fb_scale;
int viewport_offset_x; int viewport_offset_x;
int viewport_offset_y; int viewport_offset_y;
@ -1387,10 +1389,12 @@ _clutter_stage_do_pick_on_view (ClutterStage *stage,
context = _clutter_context_get_default (); context = _clutter_context_get_default ();
window_scale = _clutter_stage_window_get_scale_factor (priv->impl); window_scale = _clutter_stage_window_get_scale_factor (priv->impl);
view_scale = clutter_stage_view_get_scale (view);
fb_scale = window_scale * view_scale;
clutter_stage_view_get_layout (view, &view_layout); clutter_stage_view_get_layout (view, &view_layout);
fb_width = view_layout.width; fb_width = view_layout.width * view_scale;
fb_height = view_layout.height; fb_height = view_layout.height * view_scale;
cogl_push_framebuffer (fb); cogl_push_framebuffer (fb);
/* needed for when a context switch happens */ /* needed for when a context switch happens */
@ -1400,38 +1404,38 @@ _clutter_stage_do_pick_on_view (ClutterStage *stage,
* picking to not work at all, so setting it the whole framebuffer content * picking to not work at all, so setting it the whole framebuffer content
* for now. */ * for now. */
cogl_framebuffer_push_scissor_clip (fb, 0, 0, cogl_framebuffer_push_scissor_clip (fb, 0, 0,
view_layout.width, view_layout.width * view_scale,
view_layout.height); view_layout.height * view_scale);
_clutter_stage_window_get_dirty_pixel (priv->impl, view, &dirty_x, &dirty_y); _clutter_stage_window_get_dirty_pixel (priv->impl, view, &dirty_x, &dirty_y);
if (G_LIKELY (!(clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS))) if (G_LIKELY (!(clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
{ {
CLUTTER_NOTE (PICK, "Pushing pick scissor clip x: %d, y: %d, 1x1", CLUTTER_NOTE (PICK, "Pushing pick scissor clip x: %d, y: %d, 1x1",
dirty_x * window_scale, dirty_x * fb_scale,
dirty_y * window_scale); dirty_y * fb_scale);
cogl_framebuffer_push_scissor_clip (fb, dirty_x * window_scale, dirty_y * window_scale, 1, 1); cogl_framebuffer_push_scissor_clip (fb, dirty_x * fb_scale, dirty_y * fb_scale, 1, 1);
} }
viewport_offset_x = x * window_scale - dirty_x * window_scale; viewport_offset_x = x * fb_scale - dirty_x * fb_scale;
viewport_offset_y = y * window_scale - dirty_y * window_scale; viewport_offset_y = y * fb_scale - dirty_y * fb_scale;
CLUTTER_NOTE (PICK, "Setting viewport to %f, %f, %f, %f", CLUTTER_NOTE (PICK, "Setting viewport to %f, %f, %f, %f",
priv->viewport[0] * window_scale - viewport_offset_x, priv->viewport[0] * fb_scale - viewport_offset_x,
priv->viewport[1] * window_scale - viewport_offset_y, priv->viewport[1] * fb_scale - viewport_offset_y,
priv->viewport[2] * window_scale, priv->viewport[2] * fb_scale,
priv->viewport[3] * window_scale); priv->viewport[3] * fb_scale);
cogl_set_viewport (priv->viewport[0] * window_scale - viewport_offset_x, cogl_set_viewport (priv->viewport[0] * fb_scale - viewport_offset_x,
priv->viewport[1] * window_scale - viewport_offset_y, priv->viewport[1] * fb_scale - viewport_offset_y,
priv->viewport[2] * window_scale, priv->viewport[2] * fb_scale,
priv->viewport[3] * window_scale); priv->viewport[3] * fb_scale);
read_x = dirty_x * window_scale; read_x = dirty_x * fb_scale;
read_y = dirty_y * window_scale; read_y = dirty_y * fb_scale;
CLUTTER_NOTE (PICK, "Performing pick at %i,%i on view %dx%d+%d+%d", CLUTTER_NOTE (PICK, "Performing pick at %i,%i on view %dx%d+%d+%d s: %d",
x, y, x, y,
view_layout.width, view_layout.height, view_layout.width, view_layout.height,
view_layout.x, view_layout.y); view_layout.x, view_layout.y, view_scale);
cogl_color_init_from_4ub (&stage_pick_id, 255, 255, 255, 255); cogl_color_init_from_4ub (&stage_pick_id, 255, 255, 255, 255);
cogl_clear (&stage_pick_id, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH); cogl_clear (&stage_pick_id, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH);
@ -3569,6 +3573,7 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage,
cairo_rectangle_int_t view_layout; cairo_rectangle_int_t view_layout;
ClutterPerspective perspective; ClutterPerspective perspective;
int window_scale; int window_scale;
int fb_scale;
int viewport_offset_x; int viewport_offset_x;
int viewport_offset_y; int viewport_offset_y;
float z_2d; float z_2d;
@ -3579,14 +3584,15 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage,
priv->viewport[3]); priv->viewport[3]);
window_scale = _clutter_stage_window_get_scale_factor (priv->impl); window_scale = _clutter_stage_window_get_scale_factor (priv->impl);
fb_scale = window_scale * clutter_stage_view_get_scale (view);
clutter_stage_view_get_layout (view, &view_layout); clutter_stage_view_get_layout (view, &view_layout);
viewport_offset_x = view_layout.x * window_scale; viewport_offset_x = view_layout.x * fb_scale;
viewport_offset_y = view_layout.y * window_scale; viewport_offset_y = view_layout.y * fb_scale;
cogl_set_viewport (priv->viewport[0] * window_scale - viewport_offset_x, cogl_set_viewport (priv->viewport[0] * fb_scale - viewport_offset_x,
priv->viewport[1] * window_scale - viewport_offset_y, priv->viewport[1] * fb_scale - viewport_offset_y,
priv->viewport[2] * window_scale, priv->viewport[2] * fb_scale,
priv->viewport[3] * window_scale); priv->viewport[3] * fb_scale);
perspective = priv->perspective; perspective = priv->perspective;

View File

@ -504,6 +504,7 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
cairo_rectangle_int_t clip_region; cairo_rectangle_int_t clip_region;
gboolean clip_region_empty; gboolean clip_region_empty;
int window_scale; int window_scale;
int fb_scale;
wrapper = CLUTTER_ACTOR (stage_cogl->wrapper); wrapper = CLUTTER_ACTOR (stage_cogl->wrapper);
@ -558,6 +559,7 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
clip_region_empty = may_use_clipped_redraw && clip_region.width == 0; clip_region_empty = may_use_clipped_redraw && clip_region.width == 0;
window_scale = _clutter_stage_window_get_scale_factor (stage_window); window_scale = _clutter_stage_window_get_scale_factor (stage_window);
fb_scale = window_scale * clutter_stage_view_get_scale (view);
swap_with_damage = FALSE; swap_with_damage = FALSE;
if (has_buffer_age) if (has_buffer_age)
@ -628,13 +630,13 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
stage_cogl->using_clipped_redraw = TRUE; stage_cogl->using_clipped_redraw = TRUE;
scissor_x = (clip_region.x - view_rect.x) * window_scale; scissor_x = (clip_region.x - view_rect.x) * fb_scale;
scissor_y = (clip_region.y - view_rect.y) * window_scale; scissor_y = (clip_region.y - view_rect.y) * fb_scale;
cogl_framebuffer_push_scissor_clip (fb, cogl_framebuffer_push_scissor_clip (fb,
scissor_x, scissor_x,
scissor_y, scissor_y,
clip_region.width * window_scale, clip_region.width * fb_scale,
clip_region.height * window_scale); clip_region.height * fb_scale);
paint_stage (stage_cogl, view, &clip_region); paint_stage (stage_cogl, view, &clip_region);
cogl_framebuffer_pop_clip (fb); cogl_framebuffer_pop_clip (fb);
@ -653,13 +655,13 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
int scissor_x; int scissor_x;
int scissor_y; int scissor_y;
scissor_x = (clip_region.x - view_rect.x) * window_scale;; scissor_x = (clip_region.x - view_rect.x) * fb_scale;;
scissor_y = (clip_region.y - view_rect.y) * window_scale; scissor_y = (clip_region.y - view_rect.y) * fb_scale;
cogl_framebuffer_push_scissor_clip (fb, cogl_framebuffer_push_scissor_clip (fb,
scissor_x, scissor_x,
scissor_y, scissor_y,
clip_region.width * window_scale, clip_region.width * fb_scale,
clip_region.height * window_scale); clip_region.height * fb_scale);
paint_stage (stage_cogl, view, &clip_region); paint_stage (stage_cogl, view, &clip_region);
cogl_framebuffer_pop_clip (fb); cogl_framebuffer_pop_clip (fb);
} }
@ -724,10 +726,10 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
else if (use_clipped_redraw) else if (use_clipped_redraw)
{ {
swap_region = (cairo_rectangle_int_t) { swap_region = (cairo_rectangle_int_t) {
.x = (clip_region.x - view_rect.x) * window_scale, .x = (clip_region.x - view_rect.x) * fb_scale,
.y = (clip_region.y - view_rect.y) * window_scale, .y = (clip_region.y - view_rect.y) * fb_scale,
.width = clip_region.width * window_scale, .width = clip_region.width * fb_scale,
.height = clip_region.height * window_scale, .height = clip_region.height * fb_scale,
}; };
g_assert (swap_region.width > 0); g_assert (swap_region.width > 0);
do_swap_buffer = TRUE; do_swap_buffer = TRUE;
@ -737,8 +739,8 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
swap_region = (cairo_rectangle_int_t) { swap_region = (cairo_rectangle_int_t) {
.x = 0, .x = 0,
.y = 0, .y = 0,
.width = view_rect.width * window_scale, .width = view_rect.width * fb_scale,
.height = view_rect.height * window_scale, .height = view_rect.height * fb_scale,
}; };
do_swap_buffer = TRUE; do_swap_buffer = TRUE;
} }