1
0
Fork 0
mutter-performance-pkgbuild/mr1154.patch
Sung Mingi e8e5817dae
Add mr1154
Signed-off-by: Sung Mingi <FiestaLake@protonmail.com>
2022-06-14 23:11:39 +09:00

2648 lines
92 KiB
Diff

Author: Dor Askayo <dor.askayo@gmail.com>
Source: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1154
Editor: Sung Mingi <FiestaLake@protonmail.com>
Commit: 9bdf960b437d5a3f864a44c85c2f6f1d350f9224
Last Updated: 06/14/22 (Mutter 42.2+r11+gcd52c57bc-3)
---
This MR adds the logic required to detect monitors that are capable of VRR and the ability to activate it using KMS properties.
It also adds the ability to enable or disable VRR on capable monitors using the DisplayConfig DBus API, and makes this configuration persist via monitors.xml.
Finally, once configured to be enabled, VRR is actually activated on a monitor when a window that supports it covers the entire monitor on the visible workspace, doesn't have any transitions or animations, and isn't covered by any shell UI elements.
---
diff --git a/clutter/clutter/clutter-frame-clock.c b/clutter/clutter/clutter-frame-clock.c
index 6fa2b2588..36c388db9 100644
--- a/clutter/clutter/clutter-frame-clock.c
+++ b/clutter/clutter/clutter-frame-clock.c
@@ -47,6 +47,9 @@ typedef struct _EstimateQueue
#define SYNC_DELAY_FALLBACK_FRACTION 0.875
+#define PRESENTATION_TIME_INVALID -1
+#define MINIMUM_REFRESH_RATE 30
+
typedef struct _ClutterFrameListener
{
const ClutterFrameListenerIface *iface;
@@ -62,8 +65,8 @@ typedef struct _ClutterClockSource
typedef enum _ClutterFrameClockState
{
- CLUTTER_FRAME_CLOCK_STATE_INIT,
CLUTTER_FRAME_CLOCK_STATE_IDLE,
+ CLUTTER_FRAME_CLOCK_STATE_IDLE_TIMEOUT,
CLUTTER_FRAME_CLOCK_STATE_SCHEDULED,
CLUTTER_FRAME_CLOCK_STATE_DISPATCHING,
CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED,
@@ -75,6 +78,8 @@ struct _ClutterFrameClock
float refresh_rate;
int64_t refresh_interval_us;
+ int64_t minimum_refresh_interval_us;
+
ClutterFrameListener listener;
GSource *source;
@@ -82,11 +87,12 @@ struct _ClutterFrameClock
int64_t frame_count;
ClutterFrameClockState state;
+ ClutterFrameClockMode mode;
+
int64_t last_dispatch_time_us;
int64_t last_dispatch_lateness_us;
- int64_t last_presentation_time_us;
- gboolean is_next_presentation_time_valid;
+ int64_t last_presentation_time_us;
int64_t next_presentation_time_us;
/* Buffer must be submitted to KMS and GPU rendering must be finished
@@ -270,7 +276,10 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
}
#endif
- frame_clock->last_presentation_time_us = frame_info->presentation_time;
+ if (frame_info->presentation_time > 0)
+ frame_clock->last_presentation_time_us = frame_info->presentation_time;
+ else
+ frame_clock->last_presentation_time_us = PRESENTATION_TIME_INVALID;
frame_clock->got_measurements_last_frame = FALSE;
@@ -312,8 +321,8 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
switch (frame_clock->state)
{
- case CLUTTER_FRAME_CLOCK_STATE_INIT:
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
+ case CLUTTER_FRAME_CLOCK_STATE_IDLE_TIMEOUT:
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
g_warn_if_reached ();
break;
@@ -332,8 +341,8 @@ clutter_frame_clock_notify_ready (ClutterFrameClock *frame_clock)
switch (frame_clock->state)
{
- case CLUTTER_FRAME_CLOCK_STATE_INIT:
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
+ case CLUTTER_FRAME_CLOCK_STATE_IDLE_TIMEOUT:
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
g_warn_if_reached ();
break;
@@ -398,24 +407,22 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
static void
calculate_next_update_time_us (ClutterFrameClock *frame_clock,
+ int64_t refresh_interval_us,
int64_t *out_next_update_time_us,
int64_t *out_next_presentation_time_us)
{
int64_t last_presentation_time_us;
int64_t now_us;
- int64_t refresh_interval_us;
int64_t min_render_time_allowed_us;
int64_t max_render_time_allowed_us;
- int64_t last_next_presentation_time_us;
- int64_t time_since_last_next_presentation_time_us;
int64_t next_presentation_time_us;
int64_t next_update_time_us;
now_us = g_get_monotonic_time ();
- refresh_interval_us = frame_clock->refresh_interval_us;
+ last_presentation_time_us = frame_clock->last_presentation_time_us;
- if (frame_clock->last_presentation_time_us == 0)
+ if (last_presentation_time_us == PRESENTATION_TIME_INVALID)
{
*out_next_update_time_us =
frame_clock->last_dispatch_time_us ?
@@ -423,7 +430,7 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
frame_clock->last_dispatch_lateness_us) + refresh_interval_us) :
now_us;
- *out_next_presentation_time_us = 0;
+ *out_next_presentation_time_us = PRESENTATION_TIME_INVALID;
return;
}
@@ -451,7 +458,6 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
* 0
*
*/
- last_presentation_time_us = frame_clock->last_presentation_time_us;
next_presentation_time_us = last_presentation_time_us + refresh_interval_us;
/*
@@ -509,28 +515,30 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
refresh_interval_us;
}
- /*
- * Skip one interval if we got an early presented event.
- *
- * last frame this was last_presentation_time
- * / frame_clock->next_presentation_time_us
- * / /
- * |---|-o-----|-x----->
- * | \
- * \ next_presentation_time_us is thus right after the last one
- * but got an unexpected early presentation
- * \_/
- * time_since_last_next_presentation_time_us
- *
- */
- last_next_presentation_time_us = frame_clock->next_presentation_time_us;
- time_since_last_next_presentation_time_us =
- next_presentation_time_us - last_next_presentation_time_us;
- if (frame_clock->is_next_presentation_time_valid &&
- time_since_last_next_presentation_time_us < (refresh_interval_us / 2))
+ if (G_LIKELY (frame_clock->next_presentation_time_us != PRESENTATION_TIME_INVALID))
{
- next_presentation_time_us =
- frame_clock->next_presentation_time_us + refresh_interval_us;
+ int64_t time_since_last_next_presentation_time_us =
+ next_presentation_time_us - frame_clock->next_presentation_time_us;
+
+ /*
+ * Skip one interval if we got an early presented event.
+ *
+ * last frame this was last_presentation_time
+ * / frame_clock->next_presentation_time_us
+ * / /
+ * |---|-o-----|-x----->
+ * | \
+ * \ next_presentation_time_us is thus right after the last one
+ * but got an unexpected early presentation
+ * \_/
+ * time_since_last_next_presentation_time_us
+ *
+ */
+ if (time_since_last_next_presentation_time_us < (refresh_interval_us / 2))
+ {
+ next_presentation_time_us =
+ frame_clock->next_presentation_time_us + refresh_interval_us;
+ }
}
while (next_presentation_time_us < now_us + min_render_time_allowed_us)
@@ -542,6 +550,37 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
*out_next_presentation_time_us = next_presentation_time_us;
}
+static void
+calculate_timeout_update_time_us (ClutterFrameClock *frame_clock,
+ int64_t timeout_us,
+ int64_t *out_next_update_time_us)
+{
+ int64_t now_us;
+ int64_t last_presentation_time_us;
+ int64_t next_update_time_us;
+
+ now_us = g_get_monotonic_time ();
+
+ last_presentation_time_us = frame_clock->last_presentation_time_us;
+
+ if (last_presentation_time_us == PRESENTATION_TIME_INVALID)
+ {
+ *out_next_update_time_us =
+ frame_clock->last_dispatch_time_us ?
+ ((frame_clock->last_dispatch_time_us -
+ frame_clock->last_dispatch_lateness_us) + timeout_us) :
+ now_us;
+ return;
+ }
+
+ next_update_time_us = last_presentation_time_us + timeout_us;
+
+ while (next_update_time_us < now_us)
+ next_update_time_us += timeout_us;
+
+ *out_next_update_time_us = next_update_time_us;
+}
+
void
clutter_frame_clock_inhibit (ClutterFrameClock *frame_clock)
{
@@ -551,9 +590,9 @@ clutter_frame_clock_inhibit (ClutterFrameClock *frame_clock)
{
switch (frame_clock->state)
{
- case CLUTTER_FRAME_CLOCK_STATE_INIT:
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
break;
+ case CLUTTER_FRAME_CLOCK_STATE_IDLE_TIMEOUT:
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
frame_clock->pending_reschedule = TRUE;
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
@@ -581,8 +620,6 @@ clutter_frame_clock_uninhibit (ClutterFrameClock *frame_clock)
void
clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
{
- int64_t next_update_time_us = -1;
-
if (frame_clock->inhibit_count > 0)
{
frame_clock->pending_reschedule = TRUE;
@@ -592,9 +629,8 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
switch (frame_clock->state)
{
- case CLUTTER_FRAME_CLOCK_STATE_INIT:
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
- next_update_time_us = g_get_monotonic_time ();
+ case CLUTTER_FRAME_CLOCK_STATE_IDLE_TIMEOUT:
break;
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
return;
@@ -605,11 +641,9 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
return;
}
- g_warn_if_fail (next_update_time_us != -1);
-
- g_source_set_ready_time (frame_clock->source, next_update_time_us);
+ g_source_set_ready_time (frame_clock->source, 0);
+ frame_clock->next_presentation_time_us = PRESENTATION_TIME_INVALID;
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
- frame_clock->is_next_presentation_time_valid = FALSE;
}
void
@@ -625,16 +659,9 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
switch (frame_clock->state)
{
- case CLUTTER_FRAME_CLOCK_STATE_INIT:
- next_update_time_us = g_get_monotonic_time ();
- break;
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
- calculate_next_update_time_us (frame_clock,
- &next_update_time_us,
- &frame_clock->next_presentation_time_us);
- frame_clock->is_next_presentation_time_valid =
- (frame_clock->next_presentation_time_us != 0);
break;
+ case CLUTTER_FRAME_CLOCK_STATE_IDLE_TIMEOUT:
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
return;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
@@ -643,10 +670,53 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
return;
}
+ switch (frame_clock->mode)
+ {
+ case CLUTTER_FRAME_CLOCK_MODE_FIXED:
+ calculate_next_update_time_us (frame_clock,
+ frame_clock->refresh_interval_us,
+ &next_update_time_us,
+ &frame_clock->next_presentation_time_us);
+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
+ break;
+ case CLUTTER_FRAME_CLOCK_MODE_VARIABLE:
+ calculate_timeout_update_time_us (frame_clock,
+ frame_clock->minimum_refresh_interval_us,
+ &next_update_time_us);
+ frame_clock->next_presentation_time_us = PRESENTATION_TIME_INVALID;
+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE_TIMEOUT;
+ break;
+ }
+
g_warn_if_fail (next_update_time_us != -1);
g_source_set_ready_time (frame_clock->source, next_update_time_us);
- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
+}
+
+void
+clutter_frame_clock_set_mode (ClutterFrameClock *frame_clock,
+ ClutterFrameClockMode mode)
+{
+ if (frame_clock->mode == mode)
+ return;
+
+ frame_clock->mode = mode;
+
+ switch (frame_clock->state)
+ {
+ case CLUTTER_FRAME_CLOCK_STATE_IDLE:
+ break;
+ case CLUTTER_FRAME_CLOCK_STATE_IDLE_TIMEOUT:
+ case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
+ frame_clock->pending_reschedule = TRUE;
+ break;
+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
+ case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
+ break;
+ }
+
+ maybe_reschedule_update (frame_clock);
}
static void
@@ -692,7 +762,7 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
COGL_TRACE_END (ClutterFrameClockEvents);
COGL_TRACE_BEGIN (ClutterFrameClockTimelines, "Frame Clock (timelines)");
- if (frame_clock->is_next_presentation_time_valid)
+ if (frame_clock->next_presentation_time_us != PRESENTATION_TIME_INVALID)
time_us = frame_clock->next_presentation_time_us;
advance_timelines (frame_clock, time_us);
COGL_TRACE_END (ClutterFrameClockTimelines);
@@ -705,11 +775,11 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
switch (frame_clock->state)
{
- case CLUTTER_FRAME_CLOCK_STATE_INIT:
case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
g_warn_if_reached ();
break;
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
+ case CLUTTER_FRAME_CLOCK_STATE_IDLE_TIMEOUT:
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
break;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
@@ -850,6 +920,10 @@ clutter_frame_clock_new (float refresh_rate,
init_frame_clock_source (frame_clock);
clutter_frame_clock_set_refresh_rate (frame_clock, refresh_rate);
+
+ frame_clock->minimum_refresh_interval_us =
+ (int64_t) (0.5 + G_USEC_PER_SEC / MINIMUM_REFRESH_RATE);
+
frame_clock->vblank_duration_us = vblank_duration_us;
return frame_clock;
@@ -880,7 +954,10 @@ clutter_frame_clock_dispose (GObject *object)
static void
clutter_frame_clock_init (ClutterFrameClock *frame_clock)
{
- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_INIT;
+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
+ frame_clock->mode = CLUTTER_FRAME_CLOCK_MODE_FIXED;
+ frame_clock->last_presentation_time_us = PRESENTATION_TIME_INVALID;
+ frame_clock->next_presentation_time_us = PRESENTATION_TIME_INVALID;
}
static void
diff --git a/clutter/clutter/clutter-frame-clock.h b/clutter/clutter/clutter-frame-clock.h
index 91e6b3a13..0b2325a56 100644
--- a/clutter/clutter/clutter-frame-clock.h
+++ b/clutter/clutter/clutter-frame-clock.h
@@ -53,6 +53,12 @@ typedef struct _ClutterFrameListenerIface
gpointer user_data);
} ClutterFrameListenerIface;
+typedef enum _ClutterFrameClockMode
+{
+ CLUTTER_FRAME_CLOCK_MODE_FIXED,
+ CLUTTER_FRAME_CLOCK_MODE_VARIABLE
+} ClutterFrameClockMode;
+
CLUTTER_EXPORT
ClutterFrameClock * clutter_frame_clock_new (float refresh_rate,
int64_t vblank_duration_us,
@@ -62,6 +68,10 @@ ClutterFrameClock * clutter_frame_clock_new (float re
CLUTTER_EXPORT
void clutter_frame_clock_destroy (ClutterFrameClock *frame_clock);
+CLUTTER_EXPORT
+void clutter_frame_clock_set_mode (ClutterFrameClock *frame_clock,
+ ClutterFrameClockMode mode);
+
CLUTTER_EXPORT
void clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
ClutterFrameInfo *frame_info);
diff --git a/clutter/clutter/clutter-stage-view-private.h b/clutter/clutter/clutter-stage-view-private.h
index 39d8601ea..5c1ce9645 100644
--- a/clutter/clutter/clutter-stage-view-private.h
+++ b/clutter/clutter/clutter-stage-view-private.h
@@ -72,6 +72,10 @@ void clutter_stage_view_transform_rect_to_onscreen (ClutterStageView
CLUTTER_EXPORT
void clutter_stage_view_schedule_update (ClutterStageView *view);
+CLUTTER_EXPORT
+void clutter_stage_view_schedule_actor_update (ClutterStageView *view,
+ ClutterActor *actor);
+
CLUTTER_EXPORT
void clutter_stage_view_notify_presented (ClutterStageView *view,
ClutterFrameInfo *frame_info);
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
index 2e47237f0..55d4368bc 100644
--- a/clutter/clutter/clutter-stage-view.c
+++ b/clutter/clutter/clutter-stage-view.c
@@ -1047,6 +1047,22 @@ clutter_stage_view_schedule_update (ClutterStageView *view)
clutter_frame_clock_schedule_update (priv->frame_clock);
}
+void
+clutter_stage_view_schedule_actor_update (ClutterStageView *view,
+ ClutterActor *actor)
+{
+ ClutterStageViewClass *view_class = CLUTTER_STAGE_VIEW_GET_CLASS (view);
+
+ view_class->schedule_actor_update (view, actor);
+}
+
+static void
+clutter_stage_view_real_schedule_actor_update (ClutterStageView *view,
+ ClutterActor *actor)
+{
+ clutter_stage_view_schedule_update (view);
+}
+
float
clutter_stage_view_get_refresh_rate (ClutterStageView *view)
{
@@ -1443,6 +1459,8 @@ clutter_stage_view_class_init (ClutterStageViewClass *klass)
object_class->dispose = clutter_stage_view_dispose;
object_class->finalize = clutter_stage_view_finalize;
+ klass->schedule_actor_update = clutter_stage_view_real_schedule_actor_update;
+
obj_props[PROP_NAME] =
g_param_spec_string ("name",
"Name",
diff --git a/clutter/clutter/clutter-stage-view.h b/clutter/clutter/clutter-stage-view.h
index c2cf76abf..0f34cf5b8 100644
--- a/clutter/clutter/clutter-stage-view.h
+++ b/clutter/clutter/clutter-stage-view.h
@@ -50,6 +50,9 @@ struct _ClutterStageViewClass
int dst_width,
int dst_height,
cairo_rectangle_int_t *dst_rect);
+
+ void (* schedule_actor_update) (ClutterStageView *view,
+ ClutterActor *actor);
};
CLUTTER_EXPORT
diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
index e97cd54a3..f40df1017 100644
--- a/clutter/clutter/clutter-stage.c
+++ b/clutter/clutter/clutter-stage.c
@@ -127,8 +127,6 @@ struct _ClutterStagePrivate
int update_freeze_count;
- gboolean pending_finish_queue_redraws;
-
GHashTable *pointer_devices;
GHashTable *touch_sequences;
@@ -2467,6 +2465,36 @@ clutter_stage_schedule_update (ClutterStage *stage)
}
}
+/**
+ * clutter_stage_schedule_actor_update:
+ * @stage: a #ClutterStage actor
+ * @actor: a #ClutterActor which requires an update
+ *
+ * Schedules a redraw of the #ClutterStage at the next optimal timestamp
+ * for the specified actor.
+ */
+void
+clutter_stage_schedule_actor_update (ClutterStage *stage,
+ ClutterActor *actor)
+{
+ ClutterStageWindow *stage_window;
+ GList *l;
+
+ if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
+ return;
+
+ stage_window = _clutter_stage_get_window (stage);
+ if (stage_window == NULL)
+ return;
+
+ for (l = clutter_stage_peek_stage_views (stage); l; l = l->next)
+ {
+ ClutterStageView *view = l->data;
+
+ clutter_stage_view_schedule_actor_update (view, actor);
+ }
+}
+
ClutterPaintVolume *
_clutter_stage_paint_volume_stack_allocate (ClutterStage *stage)
{
@@ -2518,19 +2546,7 @@ clutter_stage_queue_actor_redraw (ClutterStage *stage,
CLUTTER_NOTE (CLIPPING, "stage_queue_actor_redraw (actor=%s, clip=%p): ",
_clutter_actor_get_debug_name (actor), clip);
- if (!priv->pending_finish_queue_redraws)
- {
- GList *l;
-
- for (l = clutter_stage_peek_stage_views (stage); l; l = l->next)
- {
- ClutterStageView *view = l->data;
-
- clutter_stage_view_schedule_update (view);
- }
-
- priv->pending_finish_queue_redraws = TRUE;
- }
+ clutter_stage_schedule_actor_update (stage, actor);
entry = g_hash_table_lookup (priv->pending_queue_redraws, actor);
@@ -2654,11 +2670,6 @@ clutter_stage_maybe_finish_queue_redraws (ClutterStage *stage)
COGL_TRACE_BEGIN_SCOPED (ClutterStageFinishQueueRedraws, "FinishQueueRedraws");
- if (!priv->pending_finish_queue_redraws)
- return;
-
- priv->pending_finish_queue_redraws = FALSE;
-
g_hash_table_iter_init (&iter, priv->pending_queue_redraws);
while (g_hash_table_iter_next (&iter, &key, &value))
{
diff --git a/clutter/clutter/clutter-stage.h b/clutter/clutter/clutter-stage.h
index 5412c4d72..a579820a4 100644
--- a/clutter/clutter/clutter-stage.h
+++ b/clutter/clutter/clutter-stage.h
@@ -210,6 +210,10 @@ gboolean clutter_stage_is_redraw_queued_on_view (ClutterStage
CLUTTER_EXPORT
void clutter_stage_schedule_update (ClutterStage *stage);
+CLUTTER_EXPORT
+void clutter_stage_schedule_actor_update (ClutterStage *stage,
+ ClutterActor *actor);
+
CLUTTER_EXPORT
gboolean clutter_stage_get_capture_final_size (ClutterStage *stage,
cairo_rectangle_int_t *rect,
diff --git a/data/dbus-interfaces/org.gnome.Mutter.DisplayConfig.xml b/data/dbus-interfaces/org.gnome.Mutter.DisplayConfig.xml
index af7cd6472..40f666793 100644
--- a/data/dbus-interfaces/org.gnome.Mutter.DisplayConfig.xml
+++ b/data/dbus-interfaces/org.gnome.Mutter.DisplayConfig.xml
@@ -336,6 +336,10 @@
- "is-underscanning" (b): whether underscanning is enabled
(absence of this means underscanning
not being supported)
+ - "is-vrr-enabled" (b): whether variable refresh rate is enabled
+ (absence of this means variable refresh
+ rate not being supported)
+
- "max-screen-size" (ii): the maximum size a screen may have
(absence of this means unlimited screen
size)
@@ -454,6 +458,9 @@
- "enable_underscanning" (b): enable monitor underscanning;
may only be set when underscanning
is supported (see GetCurrentState).
+ - "enable_vrr" (b): enable variable refresh rate; may only be set
+ when variable refresh rate is supported (see
+ GetCurrentState).
@properties may effect the global monitor configuration state. Possible
properties are:
diff --git a/meson.build b/meson.build
index 78f94b112..fa0cc23f0 100644
--- a/meson.build
+++ b/meson.build
@@ -427,6 +427,7 @@ if buildtype != 'plain'
'-Werror=pointer-to-int-cast',
'-Werror=empty-body',
'-Werror=write-strings',
+ '-Werror=strict-aliasing',
'-Wno-sign-compare',
'-Wno-cast-function-type',
'-Wno-unused-parameter',
diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c
index da3f1dd54..0fb36ef93 100644
--- a/src/backends/meta-monitor-config-manager.c
+++ b/src/backends/meta-monitor-config-manager.c
@@ -286,7 +286,8 @@ assign_monitor_crtc (MetaMonitor *monitor,
.output = output,
.is_primary = assign_output_as_primary,
.is_presentation = assign_output_as_presentation,
- .is_underscanning = data->monitor_config->enable_underscanning
+ .is_underscanning = data->monitor_config->enable_underscanning,
+ .is_vrr_enabled = data->monitor_config->enable_vrr
};
g_ptr_array_add (data->crtc_assignments, crtc_assignment);
@@ -691,7 +692,8 @@ create_monitor_config (MetaMonitor *monitor,
*monitor_config = (MetaMonitorConfig) {
.monitor_spec = meta_monitor_spec_clone (monitor_spec),
.mode_spec = g_memdup2 (mode_spec, sizeof (MetaMonitorModeSpec)),
- .enable_underscanning = meta_monitor_is_underscanning (monitor)
+ .enable_underscanning = meta_monitor_is_underscanning (monitor),
+ .enable_vrr = meta_monitor_is_vrr_enabled (monitor)
};
return monitor_config;
@@ -953,7 +955,8 @@ clone_monitor_config_list (GList *monitor_configs_in)
.monitor_spec = meta_monitor_spec_clone (monitor_config_in->monitor_spec),
.mode_spec = g_memdup2 (monitor_config_in->mode_spec,
sizeof (MetaMonitorModeSpec)),
- .enable_underscanning = monitor_config_in->enable_underscanning
+ .enable_underscanning = monitor_config_in->enable_underscanning,
+ .enable_vrr = monitor_config_in->enable_vrr
};
monitor_configs_out =
g_list_append (monitor_configs_out, monitor_config_out);
diff --git a/src/backends/meta-monitor-config-manager.h b/src/backends/meta-monitor-config-manager.h
index a789e2f08..adbc3e575 100644
--- a/src/backends/meta-monitor-config-manager.h
+++ b/src/backends/meta-monitor-config-manager.h
@@ -34,6 +34,7 @@ typedef struct _MetaMonitorConfig
MetaMonitorSpec *monitor_spec;
MetaMonitorModeSpec *mode_spec;
gboolean enable_underscanning;
+ gboolean enable_vrr;
} MetaMonitorConfig;
typedef struct _MetaLogicalMonitorConfig
diff --git a/src/backends/meta-monitor-config-migration.c b/src/backends/meta-monitor-config-migration.c
index 69c426cd7..10c26c4f0 100644
--- a/src/backends/meta-monitor-config-migration.c
+++ b/src/backends/meta-monitor-config-migration.c
@@ -74,6 +74,7 @@ typedef struct
gboolean is_primary;
gboolean is_presentation;
gboolean is_underscanning;
+ gboolean is_vrr_enabled;
} MetaOutputConfig;
typedef struct _MetaLegacyMonitorsConfig
@@ -605,6 +606,8 @@ handle_text (GMarkupParseContext *context,
parser->output.is_presentation = read_bool (text, text_len, error);
else if (strcmp (parser->output_field, "underscanning") == 0)
parser->output.is_underscanning = read_bool (text, text_len, error);
+ else if (strcmp (parser->output_field, "enable_vrr") == 0)
+ parser->output.is_vrr_enabled = read_bool (text, text_len, error);
else
g_assert_not_reached ();
return;
@@ -697,7 +700,8 @@ create_monitor_config (MetaOutputKey *output_key,
*monitor_config = (MetaMonitorConfig) {
.monitor_spec = monitor_spec,
.mode_spec = mode_spec,
- .enable_underscanning = output_config->is_underscanning
+ .enable_underscanning = output_config->is_underscanning,
+ .enable_vrr = output_config->is_vrr_enabled
};
if (!meta_verify_monitor_config (monitor_config, error))
diff --git a/src/backends/meta-monitor-config-store.c b/src/backends/meta-monitor-config-store.c
index 5d48ec2ea..946d4ed5d 100644
--- a/src/backends/meta-monitor-config-store.c
+++ b/src/backends/meta-monitor-config-store.c
@@ -167,6 +167,7 @@ typedef enum
STATE_MONITOR_MODE_RATE,
STATE_MONITOR_MODE_FLAG,
STATE_MONITOR_UNDERSCANNING,
+ STATE_MONITOR_ENABLE_VRR,
STATE_DISABLED,
STATE_POLICY,
STATE_STORES,
@@ -451,6 +452,10 @@ handle_start_element (GMarkupParseContext *context,
{
parser->state = STATE_MONITOR_UNDERSCANNING;
}
+ else if (g_str_equal (element_name, "enable-vrr"))
+ {
+ parser->state = STATE_MONITOR_ENABLE_VRR;
+ }
else
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
@@ -544,6 +549,13 @@ handle_start_element (GMarkupParseContext *context,
return;
}
+ case STATE_MONITOR_ENABLE_VRR:
+ {
+ g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ "Invalid element '%s' under enable-vrr", element_name);
+ return;
+ }
+
case STATE_DISABLED:
{
if (!g_str_equal (element_name, "monitorspec"))
@@ -818,6 +830,14 @@ handle_end_element (GMarkupParseContext *context,
return;
}
+ case STATE_MONITOR_ENABLE_VRR:
+ {
+ g_assert (g_str_equal (element_name, "enable-vrr"));
+
+ parser->state = STATE_MONITOR;
+ return;
+ }
+
case STATE_MONITOR:
{
MetaLogicalMonitorConfig *logical_monitor_config;
@@ -1301,6 +1321,14 @@ handle_text (GMarkupParseContext *context,
return;
}
+ case STATE_MONITOR_ENABLE_VRR:
+ {
+ read_bool (text, text_len,
+ &parser->current_monitor_config->enable_vrr,
+ error);
+ return;
+ }
+
case STATE_STORE:
{
MetaConfigStore store;
@@ -1476,6 +1504,8 @@ append_monitors (GString *buffer,
g_string_append (buffer, " </mode>\n");
if (monitor_config->enable_underscanning)
g_string_append (buffer, " <underscanning>yes</underscanning>\n");
+ if (monitor_config->enable_vrr)
+ g_string_append (buffer, " <enable-vrr>yes</enable-vrr>\n");
g_string_append (buffer, " </monitor>\n");
}
}
diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h
index edf7e4501..dc0d27de5 100644
--- a/src/backends/meta-monitor-manager-private.h
+++ b/src/backends/meta-monitor-manager-private.h
@@ -102,6 +102,7 @@ struct _MetaOutputAssignment
gboolean is_primary;
gboolean is_presentation;
gboolean is_underscanning;
+ gboolean is_vrr_enabled;
};
/*
diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c
index be99b4664..c4b9c2e05 100644
--- a/src/backends/meta-monitor-manager.c
+++ b/src/backends/meta-monitor-manager.c
@@ -1977,6 +1977,15 @@ meta_monitor_manager_handle_get_current_state (MetaDBusDisplayConfig *skeleton,
g_variant_new_boolean (is_underscanning));
}
+ if (meta_monitor_is_vrr_capable (monitor))
+ {
+ gboolean vrr_enabled = meta_monitor_is_vrr_enabled (monitor);
+
+ g_variant_builder_add (&monitor_properties_builder, "{sv}",
+ "is-vrr-enabled",
+ g_variant_new_boolean (vrr_enabled));
+ }
+
is_builtin = meta_monitor_is_laptop_panel (monitor);
g_variant_builder_add (&monitor_properties_builder, "{sv}",
"is-builtin",
@@ -2296,6 +2305,8 @@ create_monitor_config_from_variant (MetaMonitorManager *manager,
g_autoptr (GVariant) properties_variant = NULL;
gboolean enable_underscanning = FALSE;
gboolean set_underscanning = FALSE;
+ gboolean enable_vrr = FALSE;
+ gboolean set_enable_vrr = FALSE;
g_variant_get (monitor_config_variant, "(ss@a{sv})",
&connector,
@@ -2331,6 +2342,19 @@ create_monitor_config_from_variant (MetaMonitorManager *manager,
}
}
+ set_enable_vrr =
+ g_variant_lookup (properties_variant, "enable_vrr", "b",
+ &enable_vrr);
+ if (set_enable_vrr)
+ {
+ if (enable_vrr && !meta_monitor_is_vrr_capable (monitor))
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Variable refresh rate requested but unsupported");
+ return NULL;
+ }
+ }
+
monitor_spec = meta_monitor_spec_clone (meta_monitor_get_spec (monitor));
monitor_mode_spec = g_new0 (MetaMonitorModeSpec, 1);
@@ -2340,7 +2364,8 @@ create_monitor_config_from_variant (MetaMonitorManager *manager,
*monitor_config = (MetaMonitorConfig) {
.monitor_spec = monitor_spec,
.mode_spec = monitor_mode_spec,
- .enable_underscanning = enable_underscanning
+ .enable_underscanning = enable_underscanning,
+ .enable_vrr = enable_vrr
};
return monitor_config;
diff --git a/src/backends/meta-monitor.c b/src/backends/meta-monitor.c
index 46cb05a66..2abfb3ea6 100644
--- a/src/backends/meta-monitor.c
+++ b/src/backends/meta-monitor.c
@@ -358,6 +358,25 @@ meta_monitor_is_underscanning (MetaMonitor *monitor)
return meta_output_is_underscanning (output);
}
+gboolean
+meta_monitor_is_vrr_capable (MetaMonitor *monitor)
+{
+ const MetaOutputInfo *output_info =
+ meta_monitor_get_main_output_info (monitor);
+
+ return output_info->vrr_capable;
+}
+
+gboolean
+meta_monitor_is_vrr_enabled (MetaMonitor *monitor)
+{
+ MetaOutput *output;
+
+ output = meta_monitor_get_main_output (monitor);
+
+ return meta_output_is_vrr_enabled (output);
+}
+
gboolean
meta_monitor_is_laptop_panel (MetaMonitor *monitor)
{
diff --git a/src/backends/meta-monitor.h b/src/backends/meta-monitor.h
index 066caa7f4..a63300cd0 100644
--- a/src/backends/meta-monitor.h
+++ b/src/backends/meta-monitor.h
@@ -118,6 +118,10 @@ gboolean meta_monitor_supports_underscanning (MetaMonitor *monitor);
gboolean meta_monitor_is_underscanning (MetaMonitor *monitor);
+gboolean meta_monitor_is_vrr_capable (MetaMonitor *monitor);
+
+gboolean meta_monitor_is_vrr_enabled (MetaMonitor *monitor);
+
gboolean meta_monitor_is_laptop_panel (MetaMonitor *monitor);
gboolean meta_monitor_is_same_as (MetaMonitor *monitor,
diff --git a/src/backends/meta-output.c b/src/backends/meta-output.c
index ed4807507..1d01a964e 100644
--- a/src/backends/meta-output.c
+++ b/src/backends/meta-output.c
@@ -55,6 +55,8 @@ typedef struct _MetaOutputPrivate
gboolean is_underscanning;
+ gboolean is_vrr_enabled;
+
int backlight;
} MetaOutputPrivate;
@@ -177,6 +179,22 @@ meta_output_is_underscanning (MetaOutput *output)
return priv->is_underscanning;
}
+gboolean
+meta_output_is_vrr_capable (MetaOutput *output)
+{
+ const MetaOutputInfo *output_info = meta_output_get_info (output);
+
+ return output_info->vrr_capable;
+}
+
+gboolean
+meta_output_is_vrr_enabled (MetaOutput *output)
+{
+ MetaOutputPrivate *priv = meta_output_get_instance_private (output);
+
+ return priv->is_vrr_enabled;
+}
+
void
meta_output_set_backlight (MetaOutput *output,
int backlight)
@@ -235,6 +253,7 @@ meta_output_assign_crtc (MetaOutput *output,
priv->is_primary = output_assignment->is_primary;
priv->is_presentation = output_assignment->is_presentation;
priv->is_underscanning = output_assignment->is_underscanning;
+ priv->is_vrr_enabled = output_assignment->is_vrr_enabled;
}
void
diff --git a/src/backends/meta-output.h b/src/backends/meta-output.h
index 6c90d7e69..43477c4a4 100644
--- a/src/backends/meta-output.h
+++ b/src/backends/meta-output.h
@@ -103,6 +103,8 @@ typedef struct _MetaOutputInfo
gboolean supports_underscanning;
gboolean supports_color_transform;
+ gboolean vrr_capable;
+
/*
* Get a new preferred mode on hotplug events, to handle dynamic guest
* resizing.
@@ -178,6 +180,10 @@ gboolean meta_output_is_presentation (MetaOutput *output);
META_EXPORT_TEST
gboolean meta_output_is_underscanning (MetaOutput *output);
+gboolean meta_output_is_vrr_capable (MetaOutput *output);
+
+gboolean meta_output_is_vrr_enabled (MetaOutput *output);
+
void meta_output_set_backlight (MetaOutput *output,
int backlight);
diff --git a/src/backends/meta-renderer-view.c b/src/backends/meta-renderer-view.c
index 55617fc68..348ce0fb8 100644
--- a/src/backends/meta-renderer-view.c
+++ b/src/backends/meta-renderer-view.c
@@ -33,6 +33,7 @@
#include "backends/meta-renderer-view.h"
#include "backends/meta-crtc.h"
+#include "backends/meta-output.h"
#include "backends/meta-renderer.h"
#include "clutter/clutter-mutter.h"
#include "compositor/region-utils.h"
@@ -43,34 +44,49 @@ enum
PROP_TRANSFORM,
PROP_CRTC,
+ PROP_OUTPUT,
PROP_LAST
};
static GParamSpec *obj_props[PROP_LAST];
-struct _MetaRendererView
+typedef struct _MetaRendererViewPrivate
{
- MetaStageView parent;
-
MetaMonitorTransform transform;
MetaCrtc *crtc;
-};
+ MetaOutput *output;
+} MetaRendererViewPrivate;
-G_DEFINE_TYPE (MetaRendererView, meta_renderer_view,
- META_TYPE_STAGE_VIEW)
+G_DEFINE_TYPE_WITH_PRIVATE (MetaRendererView, meta_renderer_view,
+ META_TYPE_STAGE_VIEW)
MetaMonitorTransform
meta_renderer_view_get_transform (MetaRendererView *view)
{
- return view->transform;
+ MetaRendererViewPrivate *priv =
+ meta_renderer_view_get_instance_private (view);
+
+ return priv->transform;
}
MetaCrtc *
meta_renderer_view_get_crtc (MetaRendererView *view)
{
- return view->crtc;
+ MetaRendererViewPrivate *priv =
+ meta_renderer_view_get_instance_private (view);
+
+ return priv->crtc;
+}
+
+MetaOutput *
+meta_renderer_view_get_output (MetaRendererView *view)
+{
+ MetaRendererViewPrivate *priv =
+ meta_renderer_view_get_instance_private (view);
+
+ return priv->output;
}
static void
@@ -78,10 +94,12 @@ meta_renderer_view_get_offscreen_transformation_matrix (ClutterStageView *view,
graphene_matrix_t *matrix)
{
MetaRendererView *renderer_view = META_RENDERER_VIEW (view);
+ MetaRendererViewPrivate *priv =
+ meta_renderer_view_get_instance_private (renderer_view);
graphene_matrix_init_identity (matrix);
- switch (renderer_view->transform)
+ switch (priv->transform)
{
case META_MONITOR_TRANSFORM_NORMAL:
break;
@@ -136,10 +154,12 @@ meta_renderer_view_transform_rect_to_onscreen (ClutterStageView *view
cairo_rectangle_int_t *dst_rect)
{
MetaRendererView *renderer_view = META_RENDERER_VIEW (view);
+ MetaRendererViewPrivate *priv =
+ meta_renderer_view_get_instance_private (renderer_view);
MetaMonitorTransform inverted_transform;
inverted_transform =
- meta_monitor_transform_invert (renderer_view->transform);
+ meta_monitor_transform_invert (priv->transform);
return meta_rectangle_transform (src_rect,
inverted_transform,
dst_width,
@@ -151,10 +171,13 @@ static void
meta_renderer_view_set_transform (MetaRendererView *view,
MetaMonitorTransform transform)
{
- if (view->transform == transform)
+ MetaRendererViewPrivate *priv =
+ meta_renderer_view_get_instance_private (view);
+
+ if (priv->transform == transform)
return;
- view->transform = transform;
+ priv->transform = transform;
clutter_stage_view_invalidate_offscreen_blit_pipeline (CLUTTER_STAGE_VIEW (view));
}
@@ -165,14 +188,19 @@ meta_renderer_view_get_property (GObject *object,
GParamSpec *pspec)
{
MetaRendererView *view = META_RENDERER_VIEW (object);
+ MetaRendererViewPrivate *priv =
+ meta_renderer_view_get_instance_private (view);
switch (prop_id)
{
case PROP_TRANSFORM:
- g_value_set_uint (value, view->transform);
+ g_value_set_uint (value, priv->transform);
break;
case PROP_CRTC:
- g_value_set_object (value, view->crtc);
+ g_value_set_object (value, priv->crtc);
+ break;
+ case PROP_OUTPUT:
+ g_value_set_object (value, priv->output);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -187,6 +215,8 @@ meta_renderer_view_set_property (GObject *object,
GParamSpec *pspec)
{
MetaRendererView *view = META_RENDERER_VIEW (object);
+ MetaRendererViewPrivate *priv =
+ meta_renderer_view_get_instance_private (view);
switch (prop_id)
{
@@ -194,7 +224,10 @@ meta_renderer_view_set_property (GObject *object,
meta_renderer_view_set_transform (view, g_value_get_uint (value));
break;
case PROP_CRTC:
- view->crtc = g_value_get_object (value);
+ priv->crtc = g_value_get_object (value);
+ break;
+ case PROP_OUTPUT:
+ priv->output = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -243,5 +276,14 @@ meta_renderer_view_class_init (MetaRendererViewClass *klass)
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
+ obj_props[PROP_OUTPUT] =
+ g_param_spec_object ("output",
+ "MetaOutput",
+ "MetaOutput",
+ META_TYPE_OUTPUT,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
g_object_class_install_properties (object_class, PROP_LAST, obj_props);
}
diff --git a/src/backends/meta-renderer-view.h b/src/backends/meta-renderer-view.h
index 3f21c7c48..d0a516661 100644
--- a/src/backends/meta-renderer-view.h
+++ b/src/backends/meta-renderer-view.h
@@ -23,12 +23,19 @@
#include "backends/meta-stage-view-private.h"
#define META_TYPE_RENDERER_VIEW (meta_renderer_view_get_type ())
-G_DECLARE_FINAL_TYPE (MetaRendererView, meta_renderer_view,
- META, RENDERER_VIEW,
- MetaStageView)
+G_DECLARE_DERIVABLE_TYPE (MetaRendererView, meta_renderer_view,
+ META, RENDERER_VIEW,
+ MetaStageView)
+
+struct _MetaRendererViewClass
+{
+ MetaStageViewClass parent_class;
+};
MetaMonitorTransform meta_renderer_view_get_transform (MetaRendererView *view);
MetaCrtc *meta_renderer_view_get_crtc (MetaRendererView *view);
+MetaOutput *meta_renderer_view_get_output (MetaRendererView *view);
+
#endif /* META_RENDERER_VIEW_H */
diff --git a/src/backends/meta-screen-cast-stream-src.c b/src/backends/meta-screen-cast-stream-src.c
index 1e009070c..0d8bc1751 100644
--- a/src/backends/meta-screen-cast-stream-src.c
+++ b/src/backends/meta-screen-cast-stream-src.c
@@ -78,7 +78,7 @@ static guint signals[N_SIGNALS];
typedef struct _MetaPipeWireSource
{
- GSource base;
+ GSource source;
MetaScreenCastStreamSrc *src;
struct pw_loop *pipewire_loop;
@@ -90,7 +90,7 @@ typedef struct _MetaScreenCastStreamSrcPrivate
struct pw_context *pipewire_context;
struct pw_core *pipewire_core;
- MetaPipeWireSource *pipewire_source;
+ GSource *pipewire_source;
struct spa_hook pipewire_core_listener;
gboolean is_enabled;
@@ -1145,7 +1145,7 @@ on_core_error (void *data,
}
static gboolean
-pipewire_loop_source_prepare (GSource *base,
+pipewire_loop_source_prepare (GSource *source,
int *timeout)
{
*timeout = -1;
@@ -1190,24 +1190,21 @@ static GSourceFuncs pipewire_source_funcs =
pipewire_loop_source_finalize
};
-static MetaPipeWireSource *
-create_pipewire_source (MetaScreenCastStreamSrc *src)
+static GSource *
+create_pipewire_source (MetaScreenCastStreamSrc *src,
+ struct pw_loop *pipewire_loop)
{
GSource *source;
MetaPipeWireSource *pipewire_source;
source = g_source_new (&pipewire_source_funcs, sizeof (MetaPipeWireSource));
g_source_set_name (source, "[mutter] PipeWire");
+
pipewire_source = (MetaPipeWireSource *) source;
pipewire_source->src = src;
- pipewire_source->pipewire_loop = pw_loop_new (NULL);
- if (!pipewire_source->pipewire_loop)
- {
- g_source_unref ((GSource *) pipewire_source);
- return NULL;
- }
+ pipewire_source->pipewire_loop = pipewire_loop;
- g_source_add_unix_fd (&pipewire_source->base,
+ g_source_add_unix_fd (source,
pw_loop_get_fd (pipewire_source->pipewire_loop),
G_IO_IN | G_IO_ERR);
@@ -1215,7 +1212,7 @@ create_pipewire_source (MetaScreenCastStreamSrc *src)
g_source_attach (source, NULL);
g_source_unref (source);
- return pipewire_source;
+ return source;
}
static const struct pw_core_events core_events = {
@@ -1231,8 +1228,17 @@ meta_screen_cast_stream_src_initable_init (GInitable *initable,
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (initable);
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
+ struct pw_loop *pipewire_loop;
+
+ pipewire_loop = pw_loop_new (NULL);
+ if (!pipewire_loop)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Failed to create PipeWire loop");
+ return FALSE;
+ }
- priv->pipewire_source = create_pipewire_source (src);
+ priv->pipewire_source = create_pipewire_source (src, pipewire_loop);
if (!priv->pipewire_source)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
@@ -1240,7 +1246,7 @@ meta_screen_cast_stream_src_initable_init (GInitable *initable,
return FALSE;
}
- priv->pipewire_context = pw_context_new (priv->pipewire_source->pipewire_loop,
+ priv->pipewire_context = pw_context_new (pipewire_loop,
NULL, 0);
if (!priv->pipewire_context)
{
@@ -1298,7 +1304,7 @@ meta_screen_cast_stream_src_dispose (GObject *object)
g_clear_pointer (&priv->dmabuf_handles, g_hash_table_destroy);
g_clear_pointer (&priv->pipewire_core, pw_core_disconnect);
g_clear_pointer (&priv->pipewire_context, pw_context_destroy);
- g_clear_pointer ((GSource **) &priv->pipewire_source, g_source_destroy);
+ g_clear_pointer (&priv->pipewire_source, g_source_destroy);
G_OBJECT_CLASS (meta_screen_cast_stream_src_parent_class)->dispose (object);
}
diff --git a/src/backends/native/meta-kms-connector.c b/src/backends/native/meta-kms-connector.c
index b7550e12e..dc906035b 100644
--- a/src/backends/native/meta-kms-connector.c
+++ b/src/backends/native/meta-kms-connector.c
@@ -298,6 +298,9 @@ state_set_properties (MetaKmsConnectorState *state,
META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_HW_STATE))
set_privacy_screen (state, connector, prop,
drm_connector->prop_values[i]);
+ else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
+ strcmp (prop->name, "vrr_capable") == 0)
+ state->vrr_capable = drm_connector->prop_values[i];
drmModeFreeProperty (prop);
}
@@ -541,6 +544,7 @@ meta_kms_connector_state_new (void)
state = g_new0 (MetaKmsConnectorState, 1);
state->suggested_x = -1;
state->suggested_y = -1;
+ state->vrr_capable = FALSE;
return state;
}
@@ -636,6 +640,9 @@ meta_kms_connector_state_changes (MetaKmsConnectorState *state,
if (!kms_modes_equal (state->modes, new_state->modes))
return META_KMS_UPDATE_CHANGE_FULL;
+ if (state->vrr_capable != new_state->vrr_capable)
+ return META_KMS_UPDATE_CHANGE_FULL;
+
if (state->privacy_screen_state != new_state->privacy_screen_state)
return META_KMS_UPDATE_CHANGE_PRIVACY_SCREEN;
diff --git a/src/backends/native/meta-kms-connector.h b/src/backends/native/meta-kms-connector.h
index c2b763548..381edca97 100644
--- a/src/backends/native/meta-kms-connector.h
+++ b/src/backends/native/meta-kms-connector.h
@@ -59,6 +59,8 @@ typedef struct _MetaKmsConnectorState
gboolean hotplug_mode_update;
MetaMonitorTransform panel_orientation_transform;
+
+ gboolean vrr_capable;
} MetaKmsConnectorState;
META_EXPORT_TEST
diff --git a/src/backends/native/meta-kms-crtc-private.h b/src/backends/native/meta-kms-crtc-private.h
index 65bda3f10..0742c1e89 100644
--- a/src/backends/native/meta-kms-crtc-private.h
+++ b/src/backends/native/meta-kms-crtc-private.h
@@ -30,6 +30,7 @@ typedef enum _MetaKmsCrtcProp
META_KMS_CRTC_PROP_MODE_ID = 0,
META_KMS_CRTC_PROP_ACTIVE,
META_KMS_CRTC_PROP_GAMMA_LUT,
+ META_KMS_CRTC_PROP_VRR_ENABLED,
META_KMS_CRTC_N_PROPS
} MetaKmsCrtcProp;
diff --git a/src/backends/native/meta-kms-crtc.c b/src/backends/native/meta-kms-crtc.c
index e9bd9308b..b00ccca71 100644
--- a/src/backends/native/meta-kms-crtc.c
+++ b/src/backends/native/meta-kms-crtc.c
@@ -390,6 +390,11 @@ init_properties (MetaKmsCrtc *crtc,
.name = "GAMMA_LUT",
.type = DRM_MODE_PROP_BLOB,
},
+ [META_KMS_CRTC_PROP_VRR_ENABLED] =
+ {
+ .name = "VRR_ENABLED",
+ .type = DRM_MODE_PROP_RANGE,
+ },
}
};
diff --git a/src/backends/native/meta-kms-impl-device-atomic.c b/src/backends/native/meta-kms-impl-device-atomic.c
index 73dd8e697..c1ff8b2e5 100644
--- a/src/backends/native/meta-kms-impl-device-atomic.c
+++ b/src/backends/native/meta-kms-impl-device-atomic.c
@@ -261,6 +261,51 @@ add_crtc_property (MetaKmsImplDevice *impl_device,
return TRUE;
}
+static gboolean
+process_crtc_update (MetaKmsImplDevice *impl_device,
+ MetaKmsUpdate *update,
+ drmModeAtomicReq *req,
+ GArray *blob_ids,
+ gpointer update_entry,
+ gpointer user_data,
+ GError **error)
+{
+ MetaKmsCrtcUpdate *crtc_update = update_entry;
+ MetaKmsCrtc *crtc = crtc_update->crtc;
+
+ if (crtc_update->vrr_mode.has_update &&
+ crtc_update->vrr_mode.is_active)
+ {
+ meta_topic (META_DEBUG_KMS,
+ "[atomic] Setting VRR mode on CRTC %u (%s)",
+ meta_kms_crtc_get_id (crtc),
+ meta_kms_impl_device_get_path (impl_device));
+
+ if (!add_crtc_property (impl_device,
+ crtc, req,
+ META_KMS_CRTC_PROP_VRR_ENABLED,
+ 1,
+ error))
+ return FALSE;
+ }
+ else if (crtc_update->vrr_mode.has_update)
+ {
+ meta_topic (META_DEBUG_KMS,
+ "[atomic] Unsetting VRR mode on CRTC %u (%s)",
+ meta_kms_crtc_get_id (crtc),
+ meta_kms_impl_device_get_path (impl_device));
+
+ if (!add_crtc_property (impl_device,
+ crtc, req,
+ META_KMS_CRTC_PROP_VRR_ENABLED,
+ 0,
+ error))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static gboolean
process_mode_set (MetaKmsImplDevice *impl_device,
MetaKmsUpdate *update,
@@ -948,6 +993,16 @@ meta_kms_impl_device_atomic_process_update (MetaKmsImplDevice *impl_device,
&error))
goto err;
+ if (!process_entries (impl_device,
+ update,
+ req,
+ blob_ids,
+ meta_kms_update_get_crtc_updates (update),
+ NULL,
+ process_crtc_update,
+ &error))
+ goto err;
+
if (!process_entries (impl_device,
update,
req,
@@ -978,7 +1033,7 @@ meta_kms_impl_device_atomic_process_update (MetaKmsImplDevice *impl_device,
&error))
goto err;
- if (meta_kms_update_get_mode_sets (update))
+ if (meta_kms_update_needs_allow_modeset (update))
commit_flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
else
commit_flags |= DRM_MODE_ATOMIC_NONBLOCK;
diff --git a/src/backends/native/meta-kms-impl-device-simple.c b/src/backends/native/meta-kms-impl-device-simple.c
index ca4ffe245..ece02d56e 100644
--- a/src/backends/native/meta-kms-impl-device-simple.c
+++ b/src/backends/native/meta-kms-impl-device-simple.c
@@ -180,6 +180,47 @@ set_connector_property (MetaKmsImplDevice *impl_device,
return TRUE;
}
+static gboolean
+set_crtc_property (MetaKmsImplDevice *impl_device,
+ MetaKmsCrtc *crtc,
+ MetaKmsCrtcProp prop,
+ uint64_t value,
+ GError **error)
+{
+ uint32_t prop_id;
+ int fd;
+ int ret;
+
+ prop_id = meta_kms_crtc_get_prop_id (crtc, prop);
+ if (!prop_id)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ "Property (%s) not found on CRTC %u",
+ meta_kms_crtc_get_prop_name (crtc, prop),
+ meta_kms_crtc_get_id (crtc));
+ return FALSE;
+ }
+
+ fd = meta_kms_impl_device_get_fd (impl_device);
+
+ ret = drmModeObjectSetProperty (fd,
+ meta_kms_crtc_get_id (crtc),
+ DRM_MODE_OBJECT_CRTC,
+ prop_id,
+ value);
+ if (ret != 0)
+ {
+ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret),
+ "Failed to set CRTC %u property %u: %s",
+ meta_kms_crtc_get_id (crtc),
+ prop_id,
+ g_strerror (-ret));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static gboolean
process_connector_update (MetaKmsImplDevice *impl_device,
MetaKmsUpdate *update,
@@ -253,6 +294,48 @@ process_connector_update (MetaKmsImplDevice *impl_device,
return TRUE;
}
+static gboolean
+process_crtc_update (MetaKmsImplDevice *impl_device,
+ MetaKmsUpdate *update,
+ gpointer update_entry,
+ GError **error)
+{
+ MetaKmsCrtcUpdate *crtc_update = update_entry;
+ MetaKmsCrtc *crtc = crtc_update->crtc;
+
+ if (crtc_update->vrr_mode.has_update &&
+ crtc_update->vrr_mode.is_active)
+ {
+ meta_topic (META_DEBUG_KMS,
+ "[simple] Setting VRR mode on CRTC %u (%s)",
+ meta_kms_crtc_get_id (crtc),
+ meta_kms_impl_device_get_path (impl_device));
+
+ if (!set_crtc_property (impl_device,
+ crtc,
+ META_KMS_CRTC_PROP_VRR_ENABLED,
+ 1,
+ error))
+ return FALSE;
+ }
+ else if (crtc_update->vrr_mode.has_update)
+ {
+ meta_topic (META_DEBUG_KMS,
+ "[simple] Unsetting VRR mode on CRTC %u (%s)",
+ meta_kms_crtc_get_id (crtc),
+ meta_kms_impl_device_get_path (impl_device));
+
+ if (!set_crtc_property (impl_device,
+ crtc,
+ META_KMS_CRTC_PROP_VRR_ENABLED,
+ 0,
+ error))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static CachedModeSet *
cached_mode_set_new (GList *connectors,
const drmModeModeInfo *drm_mode,
@@ -1492,6 +1575,13 @@ meta_kms_impl_device_simple_process_update (MetaKmsImplDevice *impl_device,
&error))
goto err;
+ if (!process_entries (impl_device,
+ update,
+ meta_kms_update_get_crtc_updates (update),
+ process_crtc_update,
+ &error))
+ goto err;
+
if (!process_entries (impl_device,
update,
meta_kms_update_get_crtc_gammas (update),
diff --git a/src/backends/native/meta-kms-update-private.h b/src/backends/native/meta-kms-update-private.h
index a613cbc5d..d9915afc0 100644
--- a/src/backends/native/meta-kms-update-private.h
+++ b/src/backends/native/meta-kms-update-private.h
@@ -84,6 +84,16 @@ typedef struct _MetaKmsConnectorUpdate
} privacy_screen;
} MetaKmsConnectorUpdate;
+typedef struct _MetaKmsCrtcUpdate
+{
+ MetaKmsCrtc *crtc;
+
+ struct {
+ gboolean has_update;
+ gboolean is_active;
+ } vrr_mode;
+} MetaKmsCrtcUpdate;
+
typedef struct _MetaKmsPageFlipListener
{
MetaKmsCrtc *crtc;
@@ -157,9 +167,15 @@ void meta_kms_update_drop_defunct_page_flip_listeners (MetaKmsUpdate *update);
META_EXPORT_TEST
GList * meta_kms_update_get_connector_updates (MetaKmsUpdate *update);
+META_EXPORT_TEST
+GList * meta_kms_update_get_crtc_updates (MetaKmsUpdate *update);
+
META_EXPORT_TEST
GList * meta_kms_update_get_crtc_gammas (MetaKmsUpdate *update);
+META_EXPORT_TEST
+gboolean meta_kms_update_needs_allow_modeset (MetaKmsUpdate *update);
+
MetaKmsCustomPageFlip * meta_kms_update_take_custom_page_flip_func (MetaKmsUpdate *update);
void meta_kms_update_drop_plane_assignment (MetaKmsUpdate *update,
diff --git a/src/backends/native/meta-kms-update.c b/src/backends/native/meta-kms-update.c
index 53fc92eb8..85c77e80b 100644
--- a/src/backends/native/meta-kms-update.c
+++ b/src/backends/native/meta-kms-update.c
@@ -38,8 +38,11 @@ struct _MetaKmsUpdate
GList *mode_sets;
GList *plane_assignments;
GList *connector_updates;
+ GList *crtc_updates;
GList *crtc_gammas;
+ gboolean needs_allow_modeset;
+
MetaKmsCustomPageFlip *custom_page_flip;
GList *page_flip_listeners;
@@ -284,6 +287,8 @@ meta_kms_update_mode_set (MetaKmsUpdate *update,
};
update->mode_sets = g_list_prepend (update->mode_sets, mode_set);
+
+ update->needs_allow_modeset = TRUE;
}
static MetaKmsConnectorUpdate *
@@ -404,6 +409,47 @@ meta_kms_update_set_crtc_gamma (MetaKmsUpdate *update,
update->crtc_gammas = g_list_prepend (update->crtc_gammas, gamma);
}
+static MetaKmsCrtcUpdate *
+ensure_crtc_update (MetaKmsUpdate *update,
+ MetaKmsCrtc *crtc)
+{
+ GList *l;
+ MetaKmsCrtcUpdate *crtc_update;
+
+ for (l = update->crtc_updates; l; l = l->next)
+ {
+ crtc_update = l->data;
+
+ if (crtc_update->crtc == crtc)
+ return crtc_update;
+ }
+
+ crtc_update = g_new0 (MetaKmsCrtcUpdate, 1);
+ crtc_update->crtc = crtc;
+
+ update->crtc_updates = g_list_prepend (update->crtc_updates,
+ crtc_update);
+
+ return crtc_update;
+}
+
+void
+meta_kms_update_set_vrr_mode (MetaKmsUpdate *update,
+ MetaKmsCrtc *crtc,
+ gboolean is_active)
+{
+ MetaKmsCrtcUpdate *crtc_update;
+
+ g_assert (!meta_kms_update_is_locked (update));
+ g_assert (meta_kms_crtc_get_device (crtc) == update->device);
+
+ crtc_update = ensure_crtc_update (update, crtc);
+ crtc_update->vrr_mode.has_update = TRUE;
+ crtc_update->vrr_mode.is_active = is_active;
+
+ update->needs_allow_modeset = TRUE;
+}
+
void
meta_kms_update_add_page_flip_listener (MetaKmsUpdate *update,
MetaKmsCrtc *crtc,
@@ -635,12 +681,24 @@ meta_kms_update_get_connector_updates (MetaKmsUpdate *update)
return update->connector_updates;
}
+GList *
+meta_kms_update_get_crtc_updates (MetaKmsUpdate *update)
+{
+ return update->crtc_updates;
+}
+
GList *
meta_kms_update_get_crtc_gammas (MetaKmsUpdate *update)
{
return update->crtc_gammas;
}
+gboolean
+meta_kms_update_needs_allow_modeset (MetaKmsUpdate *update)
+{
+ return update->needs_allow_modeset;
+}
+
void
meta_kms_update_lock (MetaKmsUpdate *update)
{
@@ -692,6 +750,7 @@ meta_kms_update_new (MetaKmsDevice *device)
update = g_new0 (MetaKmsUpdate, 1);
update->device = device;
update->sequence_number = sequence_number++;
+ update->needs_allow_modeset = FALSE;
return update;
}
@@ -708,6 +767,7 @@ meta_kms_update_free (MetaKmsUpdate *update)
g_list_free_full (update->page_flip_listeners,
(GDestroyNotify) meta_kms_page_flip_listener_free);
g_list_free_full (update->connector_updates, g_free);
+ g_list_free_full (update->crtc_updates, g_free);
g_list_free_full (update->crtc_gammas, (GDestroyNotify) meta_kms_crtc_gamma_free);
g_clear_pointer (&update->custom_page_flip, meta_kms_custom_page_flip_free);
diff --git a/src/backends/native/meta-kms-update.h b/src/backends/native/meta-kms-update.h
index f31e36aad..2f69c754b 100644
--- a/src/backends/native/meta-kms-update.h
+++ b/src/backends/native/meta-kms-update.h
@@ -123,6 +123,10 @@ void meta_kms_update_set_crtc_gamma (MetaKmsUpdate *update,
const uint16_t *green,
const uint16_t *blue);
+void meta_kms_update_set_vrr_mode (MetaKmsUpdate *update,
+ MetaKmsCrtc *crtc,
+ gboolean is_active);
+
void meta_kms_plane_assignment_set_fb_damage (MetaKmsPlaneAssignment *plane_assignment,
const int *rectangles,
int n_rectangles);
diff --git a/src/backends/native/meta-output-kms.c b/src/backends/native/meta-output-kms.c
index fb658f29d..6b107dab9 100644
--- a/src/backends/native/meta-output-kms.c
+++ b/src/backends/native/meta-output-kms.c
@@ -97,6 +97,32 @@ meta_output_kms_set_underscan (MetaOutputKms *output_kms,
}
}
+void
+meta_output_kms_set_vrr_mode (MetaOutputKms *output_kms,
+ gboolean enabled)
+{
+ MetaOutput *output = META_OUTPUT (output_kms);
+ const MetaOutputInfo *output_info = meta_output_get_info (output);
+ MetaCrtc *crtc;
+ MetaKmsCrtc *kms_crtc;
+ MetaKmsDevice *kms_device;
+ MetaKms *kms;
+ MetaKmsUpdate *kms_update;
+
+ g_assert (output_info->vrr_capable);
+
+ crtc = meta_output_get_assigned_crtc (output);
+ kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc));
+ kms_device = meta_kms_crtc_get_device (kms_crtc);
+ kms = meta_kms_device_get_kms (kms_device);
+
+ kms_update = meta_kms_ensure_pending_update (kms, kms_device);
+
+ meta_kms_update_set_vrr_mode (kms_update,
+ kms_crtc,
+ enabled);
+}
+
static MetaPrivacyScreenState
meta_output_kms_get_privacy_screen_state (MetaOutput *output)
{
@@ -405,6 +431,8 @@ meta_output_kms_new (MetaGpuKms *gpu_kms,
output_info->supports_underscanning =
meta_kms_connector_is_underscanning_supported (kms_connector);
+ output_info->vrr_capable = connector_state->vrr_capable;
+
meta_output_info_parse_edid (output_info, connector_state->edid_data);
drm_connector_type = meta_kms_connector_get_connector_type (kms_connector);
diff --git a/src/backends/native/meta-output-kms.h b/src/backends/native/meta-output-kms.h
index 52acc6032..54b1721a4 100644
--- a/src/backends/native/meta-output-kms.h
+++ b/src/backends/native/meta-output-kms.h
@@ -40,6 +40,9 @@ void meta_output_kms_set_power_save_mode (MetaOutputKms *output_kms,
void meta_output_kms_set_underscan (MetaOutputKms *output_kms,
MetaKmsUpdate *kms_update);
+void meta_output_kms_set_vrr_mode (MetaOutputKms *output_kms,
+ gboolean enabled);
+
gboolean meta_output_kms_can_clone (MetaOutputKms *output_kms,
MetaOutputKms *other_output_kms);
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
index d538cc25a..8fc365ea0 100644
--- a/src/backends/native/meta-renderer-native.c
+++ b/src/backends/native/meta-renderer-native.c
@@ -61,6 +61,7 @@
#include "backends/native/meta-output-kms.h"
#include "backends/native/meta-render-device-gbm.h"
#include "backends/native/meta-render-device-surfaceless.h"
+#include "backends/native/meta-renderer-view-native.h"
#include "backends/native/meta-renderer-native-private.h"
#include "cogl/cogl.h"
#include "core/boxes-private.h"
@@ -1240,7 +1241,7 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
int onscreen_width;
int onscreen_height;
MetaRectangle view_layout;
- MetaRendererView *view;
+ MetaRendererViewNative *view_native;
EGLSurface egl_surface;
GError *error = NULL;
@@ -1352,26 +1353,28 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
meta_rectangle_from_graphene_rect (&crtc_config->layout,
META_ROUNDING_STRATEGY_ROUND,
&view_layout);
- view = g_object_new (META_TYPE_RENDERER_VIEW,
- "name", meta_output_get_name (output),
- "stage", meta_backend_get_stage (backend),
- "layout", &view_layout,
- "crtc", crtc,
- "scale", scale,
- "framebuffer", framebuffer,
- "offscreen", offscreen,
- "use-shadowfb", use_shadowfb,
- "transform", view_transform,
- "refresh-rate", crtc_mode_info->refresh_rate,
- "vblank-duration-us", crtc_mode_info->vblank_duration_us,
- NULL);
+ view_native = g_object_new (META_TYPE_RENDERER_VIEW_NATIVE,
+ "name", meta_output_get_name (output),
+ "stage", meta_backend_get_stage (backend),
+ "layout", &view_layout,
+ "crtc", crtc,
+ "output", output,
+ "scale", scale,
+ "framebuffer", framebuffer,
+ "offscreen", offscreen,
+ "use-shadowfb", use_shadowfb,
+ "transform", view_transform,
+ "refresh-rate", crtc_mode_info->refresh_rate,
+ "vblank-duration-us", crtc_mode_info->vblank_duration_us,
+ NULL);
if (META_IS_ONSCREEN_NATIVE (framebuffer))
{
CoglDisplayEGL *cogl_display_egl;
CoglOnscreenEgl *onscreen_egl;
- meta_onscreen_native_set_view (COGL_ONSCREEN (framebuffer), view);
+ meta_onscreen_native_set_view (COGL_ONSCREEN (framebuffer),
+ META_RENDERER_VIEW (view_native));
/* Ensure we don't point to stale surfaces when creating the offscreen */
cogl_display_egl = cogl_display->winsys;
@@ -1383,7 +1386,7 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
cogl_display_egl->egl_context);
}
- return view;
+ return META_RENDERER_VIEW (view_native);
}
static void
@@ -1451,6 +1454,7 @@ meta_renderer_native_prepare_frame (MetaRendererNative *renderer_native,
kms_device = meta_kms_crtc_get_device (kms_crtc);
meta_crtc_kms_maybe_set_gamma (crtc_kms, kms_device);
+ meta_renderer_view_native_maybe_set_frame_sync (META_RENDERER_VIEW_NATIVE (view));
}
void
diff --git a/src/backends/native/meta-renderer-view-native.c b/src/backends/native/meta-renderer-view-native.c
new file mode 100644
index 000000000..677b975bc
--- /dev/null
+++ b/src/backends/native/meta-renderer-view-native.c
@@ -0,0 +1,226 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/*
+ * Copyright (C) 2020 Dor Askayo
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written by:
+ * Dor Askayo <dor.askayo@gmail.com>
+ */
+
+#include "backends/native/meta-renderer-view-native.h"
+
+#include "clutter/clutter.h"
+#include "backends/meta-output.h"
+#include "backends/native/meta-crtc-kms.h"
+#include "backends/native/meta-kms.h"
+#include "backends/native/meta-kms-device.h"
+#include "backends/native/meta-output-kms.h"
+
+typedef enum _MetaFrameSyncMode
+{
+ META_FRAME_SYNC_MODE_INIT,
+ META_FRAME_SYNC_MODE_ENABLED,
+ META_FRAME_SYNC_MODE_DISABLED
+} MetaFrameSyncMode;
+
+struct _MetaRendererViewNative
+{
+ MetaRendererView parent;
+
+ gboolean frame_sync_mode_update_queued;
+
+ MetaFrameSyncMode frame_sync_mode;
+ ClutterActor *frame_sync_actor;
+
+ gulong frame_sync_actor_frozen_id;
+ gulong frame_sync_actor_destroy_id;
+};
+
+G_DEFINE_TYPE (MetaRendererViewNative, meta_renderer_view_native,
+ META_TYPE_RENDERER_VIEW);
+
+static void
+on_frame_sync_actor_frozen (ClutterActor *actor,
+ MetaRendererViewNative *view_native)
+{
+ meta_renderer_view_native_set_frame_sync_actor (view_native, NULL);
+}
+
+static void
+on_frame_sync_actor_destroyed (ClutterActor *actor,
+ MetaRendererViewNative *view_native)
+{
+ meta_renderer_view_native_set_frame_sync_actor (view_native, NULL);
+}
+
+static void
+meta_renderer_view_native_schedule_actor_update (ClutterStageView *stage_view,
+ ClutterActor *actor)
+{
+ MetaRendererViewNative *view_native = META_RENDERER_VIEW_NATIVE (stage_view);
+ ClutterFrameClock *frame_clock;
+
+ g_return_if_fail (actor != NULL);
+
+ frame_clock = clutter_stage_view_get_frame_clock (stage_view);
+
+ if (view_native->frame_sync_mode == META_FRAME_SYNC_MODE_ENABLED &&
+ actor == view_native->frame_sync_actor)
+ clutter_frame_clock_schedule_update_now (frame_clock);
+ else
+ clutter_frame_clock_schedule_update (frame_clock);
+}
+
+void
+meta_renderer_view_native_set_frame_sync_actor (MetaRendererViewNative *view_native,
+ ClutterActor *actor)
+{
+ if (G_LIKELY (actor == view_native->frame_sync_actor))
+ return;
+
+ if (view_native->frame_sync_actor)
+ {
+ g_clear_signal_handler (&view_native->frame_sync_actor_frozen_id,
+ view_native->frame_sync_actor);
+ g_clear_signal_handler (&view_native->frame_sync_actor_destroy_id,
+ view_native->frame_sync_actor);
+ }
+
+ if (actor)
+ {
+ view_native->frame_sync_actor_frozen_id =
+ g_signal_connect (actor, "frozen",
+ G_CALLBACK (on_frame_sync_actor_frozen),
+ view_native);
+ view_native->frame_sync_actor_destroy_id =
+ g_signal_connect (actor, "destroy",
+ G_CALLBACK (on_frame_sync_actor_destroyed),
+ view_native);
+ }
+
+ view_native->frame_sync_actor = actor;
+
+ view_native->frame_sync_mode_update_queued = TRUE;
+}
+
+static void
+meta_renderer_view_native_set_frame_sync (MetaRendererViewNative *view_native,
+ MetaOutput *output,
+ MetaFrameSyncMode sync_mode)
+{
+ ClutterFrameClock *frame_clock =
+ clutter_stage_view_get_frame_clock (CLUTTER_STAGE_VIEW (view_native));
+ MetaOutputKms *output_kms = META_OUTPUT_KMS (output);
+
+ switch (sync_mode)
+ {
+ case META_FRAME_SYNC_MODE_ENABLED:
+ clutter_frame_clock_set_mode (frame_clock,
+ CLUTTER_FRAME_CLOCK_MODE_VARIABLE);
+ meta_output_kms_set_vrr_mode (output_kms, TRUE);
+ break;
+ case META_FRAME_SYNC_MODE_DISABLED:
+ clutter_frame_clock_set_mode (frame_clock,
+ CLUTTER_FRAME_CLOCK_MODE_FIXED);
+ meta_output_kms_set_vrr_mode (output_kms, FALSE);
+ break;
+ case META_FRAME_SYNC_MODE_INIT:
+ g_assert_not_reached ();
+ }
+
+ view_native->frame_sync_mode = sync_mode;
+}
+
+static MetaFrameSyncMode
+meta_renderer_view_native_get_applicable_sync_mode (MetaRendererViewNative *view_native)
+{
+ MetaRendererView *view = META_RENDERER_VIEW (view_native);
+ MetaOutput *output = meta_renderer_view_get_output (view);
+
+ if (view_native->frame_sync_actor != NULL &&
+ meta_output_is_vrr_enabled (output))
+ return META_FRAME_SYNC_MODE_ENABLED;
+ else
+ return META_FRAME_SYNC_MODE_DISABLED;
+}
+
+void
+meta_renderer_view_native_maybe_set_frame_sync (MetaRendererViewNative *view_native)
+{
+ MetaRendererView *view;
+ MetaOutput *output;
+ MetaFrameSyncMode applicable_sync_mode;
+
+ if (G_LIKELY (!view_native->frame_sync_mode_update_queued))
+ return;
+
+ view_native->frame_sync_mode_update_queued = FALSE;
+
+ view = META_RENDERER_VIEW (view_native);
+ output = meta_renderer_view_get_output (view);
+
+ if (!meta_output_is_vrr_capable (output))
+ return;
+
+ applicable_sync_mode =
+ meta_renderer_view_native_get_applicable_sync_mode (view_native);
+
+ if (applicable_sync_mode != view_native->frame_sync_mode)
+ {
+ meta_renderer_view_native_set_frame_sync (view_native,
+ output,
+ applicable_sync_mode);
+ }
+}
+
+static void
+meta_renderer_view_native_dispose (GObject *object)
+{
+ MetaRendererViewNative *view_native = META_RENDERER_VIEW_NATIVE (object);
+
+ if (view_native->frame_sync_actor)
+ {
+ g_clear_signal_handler (&view_native->frame_sync_actor_destroy_id,
+ view_native->frame_sync_actor);
+ g_clear_signal_handler (&view_native->frame_sync_actor_frozen_id,
+ view_native->frame_sync_actor);
+ }
+
+ G_OBJECT_CLASS (meta_renderer_view_native_parent_class)->dispose (object);
+}
+
+static void
+meta_renderer_view_native_init (MetaRendererViewNative *view_native)
+{
+ view_native->frame_sync_mode_update_queued = TRUE;
+ view_native->frame_sync_mode = META_FRAME_SYNC_MODE_INIT;
+ view_native->frame_sync_actor = NULL;
+ view_native->frame_sync_actor_frozen_id = 0;
+ view_native->frame_sync_actor_destroy_id = 0;
+}
+
+static void
+meta_renderer_view_native_class_init (MetaRendererViewNativeClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ ClutterStageViewClass *clutter_stage_view_class = CLUTTER_STAGE_VIEW_CLASS (klass);
+
+ object_class->dispose = meta_renderer_view_native_dispose;
+
+ clutter_stage_view_class->schedule_actor_update = meta_renderer_view_native_schedule_actor_update;
+}
diff --git a/src/backends/native/meta-renderer-view-native.h b/src/backends/native/meta-renderer-view-native.h
new file mode 100644
index 000000000..07f90ffb7
--- /dev/null
+++ b/src/backends/native/meta-renderer-view-native.h
@@ -0,0 +1,39 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/*
+ * Copyright (C) 2020 Dor Askayo
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written by:
+ * Dor Askayo <dor.askayo@gmail.com>
+ */
+
+#ifndef META_RENDERER_VIEW_NATIVE_H
+#define META_RENDERER_VIEW_NATIVE_H
+
+#include "backends/meta-renderer-view.h"
+
+#define META_TYPE_RENDERER_VIEW_NATIVE (meta_renderer_view_native_get_type ())
+G_DECLARE_FINAL_TYPE (MetaRendererViewNative, meta_renderer_view_native,
+ META, RENDERER_VIEW_NATIVE, MetaRendererView)
+
+void meta_renderer_view_native_set_frame_sync_actor (MetaRendererViewNative *view_native,
+ ClutterActor *actor);
+
+void meta_renderer_view_native_maybe_set_frame_sync (MetaRendererViewNative *view_native);
+
+#endif /* META_RENDERER_VIEW_NATIVE_H */
diff --git a/src/backends/x11/nested/meta-renderer-x11-nested.c b/src/backends/x11/nested/meta-renderer-x11-nested.c
index 7c1a4facf..2f9eca5ba 100644
--- a/src/backends/x11/nested/meta-renderer-x11-nested.c
+++ b/src/backends/x11/nested/meta-renderer-x11-nested.c
@@ -223,6 +223,7 @@ meta_renderer_x11_nested_create_view (MetaRenderer *renderer,
"stage", meta_backend_get_stage (backend),
"layout", &view_layout,
"crtc", crtc,
+ "output", output,
"refresh-rate", mode_info->refresh_rate,
"framebuffer", COGL_FRAMEBUFFER (fake_onscreen),
"offscreen", COGL_FRAMEBUFFER (offscreen),
diff --git a/src/compositor/meta-compositor-native.c b/src/compositor/meta-compositor-native.c
index bc17704e1..8c4c419d6 100644
--- a/src/compositor/meta-compositor-native.c
+++ b/src/compositor/meta-compositor-native.c
@@ -22,8 +22,10 @@
#include "compositor/meta-compositor-native.h"
-#include "backends/meta-logical-monitor.h"
+#include "clutter/clutter.h"
+#include "backends/meta-output.h"
#include "backends/native/meta-crtc-kms.h"
+#include "backends/native/meta-renderer-view-native.h"
#include "compositor/meta-surface-actor-wayland.h"
struct _MetaCompositorNative
@@ -31,6 +33,8 @@ struct _MetaCompositorNative
MetaCompositorServer parent;
MetaWaylandSurface *current_scanout_candidate;
+
+ MetaSurfaceActor *frame_sync_surface_actor;
};
G_DEFINE_TYPE (MetaCompositorNative, meta_compositor_native,
@@ -155,18 +159,32 @@ done:
}
#endif /* HAVE_WAYLAND */
+void
+meta_compositor_native_request_frame_sync (MetaCompositorNative *compositor_native,
+ MetaSurfaceActor *surface_actor)
+{
+ compositor_native->frame_sync_surface_actor = surface_actor;
+}
+
static void
meta_compositor_native_before_paint (MetaCompositor *compositor,
ClutterStageView *stage_view)
{
+ MetaCompositorNative *compositor_native = META_COMPOSITOR_NATIVE (compositor);
+ MetaRendererViewNative *view_native = META_RENDERER_VIEW_NATIVE (stage_view);
MetaCompositorClass *parent_class;
#ifdef HAVE_WAYLAND
maybe_assign_primary_plane (compositor);
#endif
+ compositor_native->frame_sync_surface_actor = NULL;
+
parent_class = META_COMPOSITOR_CLASS (meta_compositor_native_parent_class);
parent_class->before_paint (compositor, stage_view);
+
+ meta_renderer_view_native_set_frame_sync_actor (view_native,
+ CLUTTER_ACTOR (compositor_native->frame_sync_surface_actor));
}
MetaCompositorNative *
diff --git a/src/compositor/meta-compositor-native.h b/src/compositor/meta-compositor-native.h
index 2b1c65208..dcb9c7dc1 100644
--- a/src/compositor/meta-compositor-native.h
+++ b/src/compositor/meta-compositor-native.h
@@ -27,6 +27,9 @@
G_DECLARE_FINAL_TYPE (MetaCompositorNative, meta_compositor_native,
META, COMPOSITOR_NATIVE, MetaCompositor)
+void meta_compositor_native_request_frame_sync (MetaCompositorNative *compositor_native,
+ MetaSurfaceActor *surface_actor);
+
MetaCompositorNative * meta_compositor_native_new (MetaDisplay *display,
MetaBackend *backend);
diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c
index c2bf6696a..883eb7c39 100644
--- a/src/compositor/meta-surface-actor.c
+++ b/src/compositor/meta-surface-actor.c
@@ -51,6 +51,7 @@ enum
{
REPAINT_SCHEDULED,
SIZE_CHANGED,
+ FROZEN,
LAST_SIGNAL,
};
@@ -269,6 +270,13 @@ meta_surface_actor_class_init (MetaSurfaceActorClass *klass)
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
+
+ signals[FROZEN] = g_signal_new ("frozen",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
}
gboolean
@@ -513,6 +521,26 @@ meta_surface_actor_is_obscured_on_stage_view (MetaSurfaceActor *self,
stage_view);
}
+gboolean
+meta_surface_actor_contains_rect (MetaSurfaceActor *surface_actor,
+ MetaRectangle *rect)
+{
+ ClutterActor *actor = CLUTTER_ACTOR (surface_actor);
+ MetaRectangle surface_rect;
+ float x, y, width, height;
+
+ clutter_actor_get_position (actor, &x, &y);
+ clutter_actor_get_size (actor, &width, &height);
+
+ surface_rect = META_RECTANGLE_INIT (ceilf (x),
+ ceilf (y),
+ ceilf (width),
+ ceilf (height));
+
+ return meta_rectangle_contains_rect (&surface_rect,
+ rect);
+}
+
void
meta_surface_actor_set_input_region (MetaSurfaceActor *self,
cairo_region_t *region)
@@ -594,6 +622,9 @@ meta_surface_actor_set_frozen (MetaSurfaceActor *self,
priv->frozen = frozen;
+ if (frozen)
+ g_signal_emit (self, signals[FROZEN], 0);
+
if (!frozen && priv->pending_damage)
{
int i, n_rects = cairo_region_num_rectangles (priv->pending_damage);
diff --git a/src/compositor/meta-surface-actor.h b/src/compositor/meta-surface-actor.h
index f69cb1527..3128f513c 100644
--- a/src/compositor/meta-surface-actor.h
+++ b/src/compositor/meta-surface-actor.h
@@ -40,6 +40,9 @@ gboolean meta_surface_actor_is_obscured_on_stage_view (MetaSurfaceActor *self,
ClutterStageView *stage_view,
float *unobscurred_fraction);
+gboolean meta_surface_actor_contains_rect (MetaSurfaceActor *surface_actor,
+ MetaRectangle *rect);
+
void meta_surface_actor_set_input_region (MetaSurfaceActor *self,
cairo_region_t *region);
void meta_surface_actor_set_opaque_region (MetaSurfaceActor *self,
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index ae1fa4d90..69219d19f 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -34,6 +34,7 @@
#include "compositor/meta-window-actor-private.h"
#include "core/boxes-private.h"
#include "core/window-private.h"
+#include "core/workspace-private.h"
#include "meta/window.h"
#ifdef HAVE_WAYLAND
@@ -41,6 +42,11 @@
#include "wayland/meta-wayland-surface.h"
#endif
+#ifdef HAVE_NATIVE_BACKEND
+#include "backends/native/meta-backend-native.h"
+#include "compositor/meta-compositor-native.h"
+#endif
+
typedef enum
{
INITIALLY_FROZEN,
@@ -1053,6 +1059,81 @@ meta_window_actor_sync_visibility (MetaWindowActor *self)
}
}
+#ifdef HAVE_NATIVE_BACKEND
+static MetaSurfaceActor *
+meta_window_actor_get_topmost_surface (MetaWindowActor *actor)
+{
+ ClutterActor *topmost_actor;
+
+ topmost_actor = clutter_actor_get_last_child (CLUTTER_ACTOR (actor));
+ if (!topmost_actor || !META_IS_SURFACE_ACTOR (topmost_actor))
+ return NULL;
+
+ return META_SURFACE_ACTOR (topmost_actor);
+}
+
+static void
+meta_window_actor_maybe_request_frame_sync (MetaWindowActor *window_actor,
+ ClutterStageView *stage_view)
+{
+ MetaWindowActorPrivate *priv =
+ meta_window_actor_get_instance_private (window_actor);
+ MetaCompositor *compositor = priv->compositor;
+ MetaCompositorNative *compositor_native =
+ META_COMPOSITOR_NATIVE (compositor);
+ MetaWindow *window;
+ MetaRectangle view_layout;
+ MetaWorkspace *workspace;
+ MetaSurfaceActor *surface_actor;
+
+ if (meta_compositor_is_unredirect_inhibited (compositor))
+ return;
+
+ if (meta_window_actor_is_frozen (window_actor))
+ return;
+
+ if (meta_window_actor_effect_in_progress (window_actor))
+ return;
+
+ if (clutter_actor_has_transitions (CLUTTER_ACTOR (window_actor)))
+ return;
+
+ window = meta_window_actor_get_meta_window (window_actor);
+ if (!window)
+ return;
+
+ //if (!meta_window_get_vrr_supported (window))
+ // return;
+
+ if (!meta_window_should_be_showing (window))
+ return;
+
+ clutter_stage_view_get_layout (stage_view, &view_layout);
+
+ if (!meta_window_contains_rect (window, &view_layout))
+ return;
+
+ workspace = meta_window_get_workspace (window);
+ if (workspace == NULL)
+ return;
+
+ if (window != meta_workspace_topmost_window_on_rect (workspace,
+ &view_layout))
+ return;
+
+ surface_actor = meta_window_actor_get_topmost_surface (window_actor);
+ if (!surface_actor)
+ return;
+
+ if (!meta_surface_actor_contains_rect (surface_actor,
+ &view_layout))
+ return;
+
+ meta_compositor_native_request_frame_sync (compositor_native,
+ surface_actor);
+}
+#endif /* HAVE_NATIVE_BACKEND */
+
void
meta_window_actor_before_paint (MetaWindowActor *self,
ClutterStageView *stage_view)
@@ -1061,6 +1142,11 @@ meta_window_actor_before_paint (MetaWindowActor *self,
return;
META_WINDOW_ACTOR_GET_CLASS (self)->before_paint (self, stage_view);
+
+#ifdef HAVE_NATIVE_BACKEND
+ if (META_IS_BACKEND_NATIVE (meta_get_backend ()))
+ meta_window_actor_maybe_request_frame_sync (self, stage_view);
+#endif
}
void
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 8d2d4a020..6c6b483c6 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -562,6 +562,8 @@ struct _MetaWindow
GFile *cgroup_path;
unsigned int events_during_ping;
+
+ gboolean vrr_supported;
};
struct _MetaWindowClass
@@ -716,6 +718,9 @@ void meta_window_get_session_geometry (MetaWindow *window,
int *width,
int *height);
+gboolean meta_window_contains_rect (MetaWindow *window,
+ MetaRectangle *rect);
+
void meta_window_update_unfocused_button_grabs (MetaWindow *window);
void meta_window_update_appears_focused (MetaWindow *window);
@@ -826,6 +831,11 @@ void meta_window_set_transient_for (MetaWindow *window,
void meta_window_set_opacity (MetaWindow *window,
guint8 opacity);
+void meta_window_set_vrr_supported (MetaWindow *window,
+ gboolean vrr_supported);
+
+gboolean meta_window_get_vrr_supported (MetaWindow *window);
+
void meta_window_handle_enter (MetaWindow *window,
guint32 timestamp,
guint root_x,
diff --git a/src/core/window.c b/src/core/window.c
index 95a8e33e0..fed841ed4 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -2784,6 +2784,30 @@ meta_window_is_on_primary_monitor (MetaWindow *window)
return window->monitor->is_primary;
}
+/**
+ * meta_window_set_vrr_supported:
+ * @window: a #MetaWindow
+ * @vrr_supported: whether the window supports variable refresh rate
+ */
+void
+meta_window_set_vrr_supported (MetaWindow *window,
+ gboolean vrr_supported)
+{
+ window->vrr_supported = vrr_supported;
+}
+
+/**
+ * meta_window_get_vrr_supported:
+ * @window: a #MetaWindow
+ *
+ * Return value: %TRUE if the window supports variable refresh rate
+ */
+gboolean
+meta_window_get_vrr_supported (MetaWindow *window)
+{
+ return window->vrr_supported;
+}
+
static void
meta_window_get_tile_fraction (MetaWindow *window,
MetaTileMode tile_mode,
@@ -4250,6 +4274,14 @@ meta_window_get_session_geometry (MetaWindow *window,
window->size_hints.height_inc;
}
+gboolean
+meta_window_contains_rect (MetaWindow *window,
+ MetaRectangle *rect)
+{
+ return meta_rectangle_contains_rect (&window->buffer_rect,
+ rect);
+}
+
/**
* meta_window_get_buffer_rect:
* @window: a #MetaWindow
diff --git a/src/core/workspace-private.h b/src/core/workspace-private.h
index f0d896f6c..67abc89df 100644
--- a/src/core/workspace-private.h
+++ b/src/core/workspace-private.h
@@ -92,6 +92,9 @@ GList* meta_workspace_get_onscreen_region (MetaWorkspace *workspace);
GList * meta_workspace_get_onmonitor_region (MetaWorkspace *workspace,
MetaLogicalMonitor *logical_monitor);
+MetaWindow * meta_workspace_topmost_window_on_rect (MetaWorkspace *workspace,
+ MetaRectangle *rect);
+
MetaWindow * meta_workspace_get_default_focus_window (MetaWorkspace *workspace);
void meta_workspace_focus_default_window (MetaWorkspace *workspace,
MetaWindow *not_this_one,
diff --git a/src/core/workspace.c b/src/core/workspace.c
index 3bd517fca..dd2feb5fe 100644
--- a/src/core/workspace.c
+++ b/src/core/workspace.c
@@ -1327,6 +1327,28 @@ meta_workspace_get_default_focus_window (MetaWorkspace *workspace)
}
}
+MetaWindow *
+meta_workspace_topmost_window_on_rect (MetaWorkspace *workspace,
+ MetaRectangle *rect)
+{
+ GList *stack = workspace->display->stack->sorted;
+ GList *l;
+
+ for (l = stack; l != NULL; l = l->next)
+ {
+ MetaWindow *window = l->data;
+ MetaRectangle *window_frame_rect = &window->rect;
+
+ if (!meta_window_located_on_workspace (window, workspace))
+ continue;
+
+ if (meta_rectangle_overlap (window_frame_rect, rect))
+ return window;
+ }
+
+ return NULL;
+}
+
void
meta_workspace_focus_default_window (MetaWorkspace *workspace,
MetaWindow *not_this_one,
diff --git a/src/meson.build b/src/meson.build
index 13a69c1a6..0d1a78fc9 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -769,6 +769,8 @@ if have_native_backend
'backends/native/meta-renderer-native-private.h',
'backends/native/meta-renderer-native.c',
'backends/native/meta-renderer-native.h',
+ 'backends/native/meta-renderer-view-native.c',
+ 'backends/native/meta-renderer-view-native.h',
'backends/native/meta-seat-impl.c',
'backends/native/meta-seat-impl.h',
'backends/native/meta-seat-native.c',
diff --git a/src/tests/screen-cast-client.c b/src/tests/screen-cast-client.c
index cdf0d7dcf..afd6f17b0 100644
--- a/src/tests/screen-cast-client.c
+++ b/src/tests/screen-cast-client.c
@@ -83,18 +83,18 @@ typedef struct _ScreenCast
typedef struct _PipeWireSource
{
- GSource base;
+ GSource source;
struct pw_loop *pipewire_loop;
} PipeWireSource;
-static PipeWireSource *_pipewire_source;
+static GSource *_pipewire_source;
static struct pw_context *_pipewire_context;
static struct pw_core *_pipewire_core;
static struct spa_hook _pipewire_core_listener;
static gboolean
-pipewire_loop_source_prepare (GSource *base,
+pipewire_loop_source_prepare (GSource *source,
int *timeout)
{
*timeout = -1;
@@ -133,24 +133,26 @@ static GSourceFuncs pipewire_source_funcs =
pipewire_loop_source_finalize
};
-static PipeWireSource *
-create_pipewire_source (void)
+static GSource *
+create_pipewire_source (struct pw_loop *pipewire_loop)
{
+ GSource *source;
PipeWireSource *pipewire_source;
- pipewire_source =
- (PipeWireSource *) g_source_new (&pipewire_source_funcs,
- sizeof (PipeWireSource));
- pipewire_source->pipewire_loop = pw_loop_new (NULL);
- g_assert_nonnull (pipewire_source->pipewire_loop);
- g_source_add_unix_fd (&pipewire_source->base,
+ source = g_source_new (&pipewire_source_funcs,
+ sizeof (PipeWireSource));
+
+ pipewire_source = (PipeWireSource *) source;
+ pipewire_source->pipewire_loop = pipewire_loop;
+
+ g_source_add_unix_fd (source,
pw_loop_get_fd (pipewire_source->pipewire_loop),
G_IO_IN | G_IO_ERR);
pw_loop_enter (pipewire_source->pipewire_loop);
- g_source_attach (&pipewire_source->base, NULL);
+ g_source_attach (source, NULL);
- return pipewire_source;
+ return source;
}
static void
@@ -171,9 +173,15 @@ static const struct pw_core_events core_events = {
static void
init_pipewire (void)
{
+ struct pw_loop *pipewire_loop;
+
pw_init (NULL, NULL);
- _pipewire_source = create_pipewire_source ();
- _pipewire_context = pw_context_new (_pipewire_source->pipewire_loop,
+
+ pipewire_loop = pw_loop_new (NULL);
+ g_assert_nonnull (pipewire_loop);
+
+ _pipewire_source = create_pipewire_source (pipewire_loop);
+ _pipewire_context = pw_context_new (pipewire_loop,
NULL, 0);
g_assert_nonnull (_pipewire_context);
_pipewire_core = pw_context_connect (_pipewire_context, NULL, 0);
@@ -192,8 +200,8 @@ release_pipewire (void)
g_clear_pointer (&_pipewire_context, pw_context_destroy);
if (_pipewire_source)
{
- g_source_destroy ((GSource *) _pipewire_source);
- g_source_unref ((GSource *) _pipewire_source);
+ g_source_destroy (_pipewire_source);
+ g_source_unref (_pipewire_source);
_pipewire_source = NULL;
}
}
diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c
index b6d26fdc1..096b46aa2 100644
--- a/src/wayland/meta-wayland-actor-surface.c
+++ b/src/wayland/meta-wayland-actor-surface.c
@@ -307,7 +307,8 @@ meta_wayland_actor_surface_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaBackend *backend = meta_get_backend ();
ClutterActor *stage = meta_backend_get_stage (backend);
- clutter_stage_schedule_update (CLUTTER_STAGE (stage));
+ clutter_stage_schedule_actor_update (CLUTTER_STAGE (stage),
+ CLUTTER_ACTOR (priv->actor));
}
meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending);