e8e5817dae
Signed-off-by: Sung Mingi <FiestaLake@protonmail.com>
2648 lines
92 KiB
Diff
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);
|