1818
1919struct frame_scheduler {
2020 refcount_t n_refs ;
21+ pthread_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,16 @@ frame_scheduler_new(bool uses_frame_requests, enum present_mode present_mode, fl
4351 }
4452
4553 scheduler -> n_refs = REFCOUNT_INIT_1 ;
54+ ASSERTED int ok = pthread_mutex_init (& scheduler -> mutex , get_default_mutex_attrs ());
55+ ASSERT_ZERO (ok );
56+
4657 scheduler -> uses_frame_requests = uses_frame_requests ;
4758 scheduler -> present_mode = present_mode ;
4859 scheduler -> vsync_cb = vsync_cb ;
4960 scheduler -> userdata = userdata ;
61+
62+ scheduler -> waiting_for_scanout = false;
63+ scheduler -> has_scheduled_frame = false;
5064 return scheduler ;
5165}
5266
@@ -118,14 +132,44 @@ void frame_scheduler_request_fb(struct frame_scheduler *scheduler, uint64_t scan
118132 UNIMPLEMENTED ();
119133}
120134
121- void frame_scheduler_present_frame (struct frame_scheduler * scheduler , void_callback_t present_cb , void * userdata , void_callback_t cancel_cb ) {
135+ void frame_scheduler_present_frame (struct frame_scheduler * scheduler , void_callback_t present_cb , void * userdata , void_callback_t cancel_cb ) {
122136 ASSERT_NOT_NULL (scheduler );
123137 ASSERT_NOT_NULL (present_cb );
124- ( void ) scheduler ;
125- ( void ) cancel_cb ;
138+
139+ frame_scheduler_lock ( scheduler ) ;
126140
127- /// TODO: Implement
128- present_cb (userdata );
141+ if (scheduler -> waiting_for_scanout ) {
142+ void_callback_t cancel_prev_sched_frame = NULL ;
143+ void * prev_sched_frame_userdata = NULL ;
144+
145+ // We're already waiting for a scanout, so we can't present a frame right now.
146+ // Wait till the previous frame is scanned out, and then present.
147+
148+ if (scheduler -> has_scheduled_frame ) {
149+ // If we already have a frame scheduled, cancel it.
150+ cancel_prev_sched_frame = scheduler -> scheduled_frame .cancel_cb ;
151+ prev_sched_frame_userdata = scheduler -> scheduled_frame .userdata ;
152+
153+ memset (& scheduler -> scheduled_frame , 0 , sizeof scheduler -> scheduled_frame );
154+ }
155+
156+ scheduler -> has_scheduled_frame = true;
157+ scheduler -> scheduled_frame .present_cb = present_cb ;
158+ scheduler -> scheduled_frame .cancel_cb = cancel_cb ;
159+ scheduler -> scheduled_frame .userdata = userdata ;
160+
161+ frame_scheduler_unlock (scheduler );
162+
163+ if (cancel_prev_sched_frame != NULL ) {
164+ cancel_prev_sched_frame (prev_sched_frame_userdata );
165+ }
166+ } else {
167+ // We're not waiting for a scanout right now.
168+ scheduler -> waiting_for_scanout = true;
169+ frame_scheduler_unlock (scheduler );
170+
171+ present_cb (userdata );
172+ }
129173}
130174
131175void frame_scheduler_on_scanout (struct frame_scheduler * scheduler , bool has_timestamp , uint64_t timestamp_ns ) {
@@ -135,6 +179,27 @@ void frame_scheduler_on_scanout(struct frame_scheduler *scheduler, bool has_time
135179 (void ) has_timestamp ;
136180 (void ) timestamp_ns ;
137181
138- /// TODO: Implement
139- UNIMPLEMENTED ();
182+ void_callback_t present_cb = NULL ;
183+ void * userdata = NULL ;
184+
185+ frame_scheduler_lock (scheduler );
186+
187+ if (scheduler -> waiting_for_scanout ) {
188+ scheduler -> waiting_for_scanout = false;
189+
190+ if (scheduler -> has_scheduled_frame ) {
191+ present_cb = scheduler -> scheduled_frame .present_cb ;
192+ userdata = scheduler -> scheduled_frame .userdata ;
193+
194+ memset (& scheduler -> scheduled_frame , 0 , sizeof scheduler -> scheduled_frame );
195+
196+ scheduler -> has_scheduled_frame = false;
197+ }
198+ }
199+
200+ frame_scheduler_unlock (scheduler );
201+
202+ if (present_cb != NULL ) {
203+ present_cb (userdata );
204+ }
140205}
0 commit comments