From 916b21674e159df65efeec3b90e7ab794eb8553c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Wed, 6 Jul 2022 23:59:46 +0200
Subject: [PATCH] clutter/frame-clock: Pass ClutterFrame via the frame clock
 interface

Let the ClutterFrame live for the whole frame, and be carried as an
argument to the frame clock listener interface functions.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2795>
---
 clutter/clutter/clutter-frame-clock.c         | 15 ++++---
 clutter/clutter/clutter-frame-clock.h         |  4 +-
 clutter/clutter/clutter-frame-private.h       |  4 +-
 clutter/clutter/clutter-frame.c               |  6 +++
 clutter/clutter/clutter-frame.h               |  5 +++
 clutter/clutter/clutter-stage-view.c          | 15 +++----
 .../clutter/conform/frame-clock-timeline.c    |  2 +-
 src/tests/clutter/conform/frame-clock.c       | 39 ++++++++++---------
 8 files changed, 49 insertions(+), 41 deletions(-)

diff --git a/clutter/clutter/clutter-frame-clock.c b/clutter/clutter/clutter-frame-clock.c
index d92201713..3274df986 100644
--- a/clutter/clutter/clutter-frame-clock.c
+++ b/clutter/clutter/clutter-frame-clock.c
@@ -20,6 +20,7 @@
 #include "clutter/clutter-frame-clock.h"
 
 #include "clutter/clutter-debug.h"
+#include "clutter/clutter-frame-private.h"
 #include "clutter/clutter-main.h"
 #include "clutter/clutter-private.h"
 #include "clutter/clutter-timeline-private.h"
@@ -691,6 +692,7 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
                               int64_t            time_us)
 {
   const ClutterFrameListenerIface *iface = frame_clock->listener.iface;
+  g_autoptr (ClutterFrame) frame = NULL;
   int64_t frame_count;
   ClutterFrameResult result;
   int64_t ideal_dispatch_time_us, lateness_us;
@@ -729,13 +731,12 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
 
   frame_count = frame_clock->frame_count++;
 
+  frame = g_new0 (ClutterFrame, 1);
+  frame->frame_count = frame_count;
+
   COGL_TRACE_BEGIN (ClutterFrameClockEvents, "Frame Clock (before frame)");
   if (iface->before_frame)
-    {
-      iface->before_frame (frame_clock,
-                           frame_count,
-                           frame_clock->listener.user_data);
-    }
+    iface->before_frame (frame_clock, frame, frame_clock->listener.user_data);
   COGL_TRACE_END (ClutterFrameClockEvents);
 
   COGL_TRACE_BEGIN (ClutterFrameClockTimelines, "Frame Clock (timelines)");
@@ -745,9 +746,7 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
   COGL_TRACE_END (ClutterFrameClockTimelines);
 
   COGL_TRACE_BEGIN (ClutterFrameClockFrame, "Frame Clock (frame)");
-  result = iface->frame (frame_clock,
-                         frame_count,
-                         frame_clock->listener.user_data);
+  result = iface->frame (frame_clock, frame, frame_clock->listener.user_data);
   COGL_TRACE_END (ClutterFrameClockFrame);
 
   switch (frame_clock->state)
diff --git a/clutter/clutter/clutter-frame-clock.h b/clutter/clutter/clutter-frame-clock.h
index 91e6b3a13..9dfc8dc28 100644
--- a/clutter/clutter/clutter-frame-clock.h
+++ b/clutter/clutter/clutter-frame-clock.h
@@ -46,10 +46,10 @@ G_DECLARE_FINAL_TYPE (ClutterFrameClock, clutter_frame_clock,
 typedef struct _ClutterFrameListenerIface
 {
   void (* before_frame) (ClutterFrameClock *frame_clock,
-                         int64_t            frame_count,
+                         ClutterFrame      *frame,
                          gpointer           user_data);
   ClutterFrameResult (* frame) (ClutterFrameClock *frame_clock,
-                                int64_t            frame_count,
+                                ClutterFrame      *frame,
                                 gpointer           user_data);
 } ClutterFrameListenerIface;
 
diff --git a/clutter/clutter/clutter-frame-private.h b/clutter/clutter/clutter-frame-private.h
index e0088564f..f2f0a58a4 100644
--- a/clutter/clutter/clutter-frame-private.h
+++ b/clutter/clutter/clutter-frame-private.h
@@ -22,12 +22,12 @@
 
 struct _ClutterFrame
 {
+  int64_t frame_count;
+
   gboolean has_result;
   ClutterFrameResult result;
 };
 
-#define CLUTTER_FRAME_INIT ((ClutterFrame) { 0 })
-
 ClutterFrameResult clutter_frame_get_result (ClutterFrame *frame);
 
 #endif /* CLUTTER_FRAME_PRIVATE_H */
diff --git a/clutter/clutter/clutter-frame.c b/clutter/clutter/clutter-frame.c
index 3c708da9d..396287e95 100644
--- a/clutter/clutter/clutter-frame.c
+++ b/clutter/clutter/clutter-frame.c
@@ -17,6 +17,12 @@
 
 #include "clutter/clutter-frame-private.h"
 
+int64_t
+clutter_frame_get_count (ClutterFrame *frame)
+{
+  return frame->frame_count;
+}
+
 ClutterFrameResult
 clutter_frame_get_result (ClutterFrame *frame)
 {
diff --git a/clutter/clutter/clutter-frame.h b/clutter/clutter/clutter-frame.h
index d3608e81c..716cc219f 100644
--- a/clutter/clutter/clutter-frame.h
+++ b/clutter/clutter/clutter-frame.h
@@ -26,6 +26,9 @@
 
 typedef struct _ClutterFrame ClutterFrame;
 
+CLUTTER_EXPORT
+int64_t clutter_frame_get_count (ClutterFrame *frame);
+
 CLUTTER_EXPORT
 void clutter_frame_set_result (ClutterFrame       *frame,
                                ClutterFrameResult  result);
@@ -33,4 +36,6 @@ void clutter_frame_set_result (ClutterFrame       *frame,
 CLUTTER_EXPORT
 gboolean clutter_frame_has_result (ClutterFrame *frame);
 
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterFrame, g_free)
+
 #endif /* CLUTTER_FRAME_H */
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
index 14f21024c..f4515dee0 100644
--- a/clutter/clutter/clutter-stage-view.c
+++ b/clutter/clutter/clutter-stage-view.c
@@ -1131,7 +1131,7 @@ clutter_stage_view_has_shadowfb (ClutterStageView *view)
 
 static void
 handle_frame_clock_before_frame (ClutterFrameClock *frame_clock,
-                                 int64_t            frame_count,
+                                 ClutterFrame      *frame,
                                  gpointer           user_data)
 {
   ClutterStageView *view = user_data;
@@ -1207,7 +1207,7 @@ end_frame_timing_measurement (ClutterStageView *view)
 
 static ClutterFrameResult
 handle_frame_clock_frame (ClutterFrameClock *frame_clock,
-                          int64_t            frame_count,
+                          ClutterFrame      *frame,
                           gpointer           user_data)
 {
   ClutterStageView *view = user_data;
@@ -1216,7 +1216,6 @@ handle_frame_clock_frame (ClutterFrameClock *frame_clock,
   ClutterStage *stage = priv->stage;
   ClutterStageWindow *stage_window = _clutter_stage_get_window (stage);
   g_autoptr (GSList) devices = NULL;
-  ClutterFrame frame;
 
   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
     return CLUTTER_FRAME_RESULT_IDLE;
@@ -1241,16 +1240,14 @@ handle_frame_clock_frame (ClutterFrameClock *frame_clock,
   if (priv->needs_update_devices)
     devices = clutter_stage_find_updated_devices (stage, view);
 
-  frame = CLUTTER_FRAME_INIT;
-
-  _clutter_stage_window_prepare_frame (stage_window, view, &frame);
+  _clutter_stage_window_prepare_frame (stage_window, view, frame);
   clutter_stage_emit_prepare_frame (stage, view);
 
   if (clutter_stage_view_has_redraw_clip (view))
     {
       clutter_stage_emit_before_paint (stage, view);
 
-      _clutter_stage_window_redraw_view (stage_window, view, &frame);
+      _clutter_stage_window_redraw_view (stage_window, view, frame);
 
       clutter_frame_clock_record_flip_time (frame_clock,
                                             g_get_monotonic_time ());
@@ -1261,7 +1258,7 @@ handle_frame_clock_frame (ClutterFrameClock *frame_clock,
         end_frame_timing_measurement (view);
     }
 
-  _clutter_stage_window_finish_frame (stage_window, view, &frame);
+  _clutter_stage_window_finish_frame (stage_window, view, frame);
 
   clutter_stage_update_devices (stage, devices);
   priv->needs_update_devices = FALSE;
@@ -1269,7 +1266,7 @@ handle_frame_clock_frame (ClutterFrameClock *frame_clock,
   _clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_POST_PAINT);
   clutter_stage_emit_after_update (stage, view);
 
-  return clutter_frame_get_result (&frame);
+  return clutter_frame_get_result (frame);
 }
 
 static const ClutterFrameListenerIface frame_clock_listener_iface = {
diff --git a/src/tests/clutter/conform/frame-clock-timeline.c b/src/tests/clutter/conform/frame-clock-timeline.c
index fe001b55c..175680327 100644
--- a/src/tests/clutter/conform/frame-clock-timeline.c
+++ b/src/tests/clutter/conform/frame-clock-timeline.c
@@ -6,7 +6,7 @@ static const int64_t refresh_interval_us = G_USEC_PER_SEC / refresh_rate;
 
 static ClutterFrameResult
 timeline_frame_clock_frame (ClutterFrameClock *frame_clock,
-                            int64_t            frame_count,
+                            ClutterFrame      *frame,
                             gpointer           user_data)
 {
   ClutterFrameInfo frame_info;
diff --git a/src/tests/clutter/conform/frame-clock.c b/src/tests/clutter/conform/frame-clock.c
index cf118de1b..e5b58f182 100644
--- a/src/tests/clutter/conform/frame-clock.c
+++ b/src/tests/clutter/conform/frame-clock.c
@@ -1,4 +1,5 @@
 #include "clutter/clutter.h"
+#include "clutter/clutter-frame.h"
 #include "tests/clutter-test-utils.h"
 
 static const float refresh_rate = 60.0;
@@ -91,13 +92,13 @@ fake_hw_clock_new (ClutterFrameClock *frame_clock,
 
 static ClutterFrameResult
 frame_clock_frame (ClutterFrameClock *frame_clock,
-                   int64_t            frame_count,
+                   ClutterFrame      *frame,
                    gpointer           user_data)
 {
   FrameClockTest *test = user_data;
   GMainLoop *main_loop = test->main_loop;
 
-  g_assert_cmpint (frame_count, ==, expected_frame_count);
+  g_assert_cmpint (clutter_frame_get_count (frame), ==, expected_frame_count);
 
   expected_frame_count++;
 
@@ -185,13 +186,13 @@ schedule_update_idle (gpointer user_data)
 
 static ClutterFrameResult
 immediate_frame_clock_frame (ClutterFrameClock *frame_clock,
-                             int64_t            frame_count,
+                             ClutterFrame      *frame,
                              gpointer           user_data)
 {
   GMainLoop *main_loop = user_data;
   ClutterFrameInfo frame_info;
 
-  g_assert_cmpint (frame_count, ==, expected_frame_count);
+  g_assert_cmpint (clutter_frame_get_count (frame), ==, expected_frame_count);
 
   expected_frame_count++;
 
@@ -259,13 +260,13 @@ schedule_update_timeout (gpointer user_data)
 
 static ClutterFrameResult
 delayed_damage_frame_clock_frame (ClutterFrameClock *frame_clock,
-                                  int64_t            frame_count,
+                                  ClutterFrame      *frame,
                                   gpointer           user_data)
 {
   FrameClockTest *test = user_data;
   GMainLoop *main_loop = test->main_loop;
 
-  g_assert_cmpint (frame_count, ==, expected_frame_count);
+  g_assert_cmpint (clutter_frame_get_count (frame), ==, expected_frame_count);
 
   expected_frame_count++;
 
@@ -332,7 +333,7 @@ frame_clock_delayed_damage (void)
 
 static ClutterFrameResult
 no_damage_frame_clock_frame (ClutterFrameClock *frame_clock,
-                             int64_t            frame_count,
+                             ClutterFrame      *frame,
                              gpointer           user_data)
 {
   g_assert_not_reached ();
@@ -385,13 +386,13 @@ typedef struct _UpdateNowFrameClockTest
 
 static ClutterFrameResult
 update_now_frame_clock_frame (ClutterFrameClock *frame_clock,
-                              int64_t            frame_count,
+                              ClutterFrame      *frame,
                               gpointer           user_data)
 {
   UpdateNowFrameClockTest *test = user_data;
   GMainLoop *main_loop = test->base.main_loop;
 
-  g_assert_cmpint (frame_count, ==, expected_frame_count);
+  g_assert_cmpint (clutter_frame_get_count (frame), ==, expected_frame_count);
 
   expected_frame_count++;
 
@@ -481,23 +482,23 @@ frame_clock_schedule_update_now (void)
 
 static void
 before_frame_frame_clock_before_frame (ClutterFrameClock *frame_clock,
-                                       int64_t            frame_count,
+                                       ClutterFrame      *frame,
                                        gpointer           user_data)
 {
   int64_t *expected_frame_count = user_data;
 
-  g_assert_cmpint (*expected_frame_count, ==, frame_count);
+  g_assert_cmpint (*expected_frame_count, ==, clutter_frame_get_count (frame));
 }
 
 static ClutterFrameResult
 before_frame_frame_clock_frame (ClutterFrameClock *frame_clock,
-                                int64_t            frame_count,
+                                ClutterFrame      *frame,
                                 gpointer           user_data)
 {
   int64_t *expected_frame_count = user_data;
   ClutterFrameInfo frame_info;
 
-  g_assert_cmpint (*expected_frame_count, ==, frame_count);
+  g_assert_cmpint (*expected_frame_count, ==, clutter_frame_get_count (frame));
 
   (*expected_frame_count)++;
 
@@ -560,13 +561,13 @@ typedef struct _InhibitTest
 
 static ClutterFrameResult
 inhibit_frame_clock_frame (ClutterFrameClock *frame_clock,
-                           int64_t            frame_count,
+                           ClutterFrame      *frame,
                            gpointer           user_data)
 {
   InhibitTest *test = user_data;
   ClutterFrameInfo frame_info;
 
-  g_assert_cmpint (frame_count, ==, test->frame_count);
+  g_assert_cmpint (clutter_frame_get_count (frame), ==, test->frame_count);
 
   test->frame_count++;
 
@@ -637,13 +638,13 @@ typedef struct _RescheduleOnIdleFrameClockTest
 
 static ClutterFrameResult
 reschedule_on_idle_clock_frame (ClutterFrameClock *frame_clock,
-                                int64_t            frame_count,
+                                ClutterFrame      *frame,
                                 gpointer           user_data)
 {
   RescheduleOnIdleFrameClockTest *test = user_data;
   GMainLoop *main_loop = test->base.main_loop;
 
-  g_assert_cmpint (frame_count, ==, expected_frame_count);
+  g_assert_cmpint (clutter_frame_get_count (frame), ==, expected_frame_count);
 
   expected_frame_count++;
 
@@ -764,12 +765,12 @@ notify_ready_and_schedule_update_idle (gpointer user_data)
 
 static ClutterFrameResult
 frame_clock_ready_frame (ClutterFrameClock *frame_clock,
-                         int64_t            frame_count,
+                         ClutterFrame      *frame,
                          gpointer           user_data)
 {
   GMainLoop *main_loop = user_data;
 
-  g_assert_cmpint (frame_count, ==, expected_frame_count);
+  g_assert_cmpint (clutter_frame_get_count (frame), ==, expected_frame_count);
 
   expected_frame_count++;