1818
1919struct frame_scheduler {
2020 refcount_t n_refs ;
21+ mutex_t mutex ;
2122
2223 bool uses_frame_requests ;
2324 enum present_mode present_mode ;
2425 fl_vsync_callback_t vsync_cb ;
2526 void * userdata ;
2627
27- pthread_mutex_t mutex ;
28+ bool waiting_for_scanout ;
29+
30+ bool has_scheduled_frame ;
31+ struct {
32+ void_callback_t present_cb ;
33+ void_callback_t cancel_cb ;
34+ void * userdata ;
35+ } scheduled_frame ;
2836};
2937
3038DEFINE_REF_OPS (frame_scheduler , n_refs )
@@ -43,10 +51,15 @@ frame_scheduler_new(bool uses_frame_requests, enum present_mode present_mode, fl
4351 }
4452
4553 scheduler -> n_refs = REFCOUNT_INIT_1 ;
54+ mutex_init (& scheduler -> mutex );
55+
4656 scheduler -> uses_frame_requests = uses_frame_requests ;
4757 scheduler -> present_mode = present_mode ;
4858 scheduler -> vsync_cb = vsync_cb ;
4959 scheduler -> userdata = userdata ;
60+
61+ scheduler -> waiting_for_scanout = false;
62+ scheduler -> has_scheduled_frame = false;
5063 return scheduler ;
5164}
5265
@@ -118,14 +131,44 @@ void frame_scheduler_request_fb(struct frame_scheduler *scheduler, uint64_t scan
118131 UNIMPLEMENTED ();
119132}
120133
121- void frame_scheduler_present_frame (struct frame_scheduler * scheduler , void_callback_t present_cb , void * userdata , void_callback_t cancel_cb ) {
134+ void frame_scheduler_present_frame (struct frame_scheduler * scheduler , void_callback_t present_cb , void * userdata , void_callback_t cancel_cb ) {
122135 ASSERT_NOT_NULL (scheduler );
123136 ASSERT_NOT_NULL (present_cb );
124- ( void ) scheduler ;
125- ( void ) cancel_cb ;
137+
138+ frame_scheduler_lock ( scheduler ) ;
126139
127- /// TODO: Implement
128- present_cb (userdata );
140+ if (scheduler -> waiting_for_scanout ) {
141+ void_callback_t cancel_prev_sched_frame = NULL ;
142+ void * prev_sched_frame_userdata = NULL ;
143+
144+ // We're already waiting for a scanout, so we can't present a frame right now.
145+ // Wait till the previous frame is scanned out, and then present.
146+
147+ if (scheduler -> has_scheduled_frame ) {
148+ // If we already have a frame scheduled, cancel it.
149+ cancel_prev_sched_frame = scheduler -> scheduled_frame .cancel_cb ;
150+ prev_sched_frame_userdata = scheduler -> scheduled_frame .userdata ;
151+
152+ memset (& scheduler -> scheduled_frame , 0 , sizeof scheduler -> scheduled_frame );
153+ }
154+
155+ scheduler -> has_scheduled_frame = true;
156+ scheduler -> scheduled_frame .present_cb = present_cb ;
157+ scheduler -> scheduled_frame .cancel_cb = cancel_cb ;
158+ scheduler -> scheduled_frame .userdata = userdata ;
159+
160+ frame_scheduler_unlock (scheduler );
161+
162+ if (cancel_prev_sched_frame != NULL ) {
163+ cancel_prev_sched_frame (prev_sched_frame_userdata );
164+ }
165+ } else {
166+ // We're not waiting for a scanout right now.
167+ scheduler -> waiting_for_scanout = true;
168+ frame_scheduler_unlock (scheduler );
169+
170+ present_cb (userdata );
171+ }
129172}
130173
131174void frame_scheduler_on_scanout (struct frame_scheduler * scheduler , bool has_timestamp , uint64_t timestamp_ns ) {
@@ -135,6 +178,27 @@ void frame_scheduler_on_scanout(struct frame_scheduler *scheduler, bool has_time
135178 (void ) has_timestamp ;
136179 (void ) timestamp_ns ;
137180
138- /// TODO: Implement
139- UNIMPLEMENTED ();
181+ void_callback_t present_cb = NULL ;
182+ void * userdata = NULL ;
183+
184+ frame_scheduler_lock (scheduler );
185+
186+ if (scheduler -> waiting_for_scanout ) {
187+ scheduler -> waiting_for_scanout = false;
188+
189+ if (scheduler -> has_scheduled_frame ) {
190+ present_cb = scheduler -> scheduled_frame .present_cb ;
191+ userdata = scheduler -> scheduled_frame .userdata ;
192+
193+ memset (& scheduler -> scheduled_frame , 0 , sizeof scheduler -> scheduled_frame );
194+
195+ scheduler -> has_scheduled_frame = false;
196+ }
197+ }
198+
199+ frame_scheduler_unlock (scheduler );
200+
201+ if (present_cb != NULL ) {
202+ present_cb (userdata );
203+ }
140204}
0 commit comments