1 /*
2  * Cogl
3  *
4  * A Low Level GPU Graphics and Utilities API
5  *
6  * Copyright (C) 2011, 2013 Intel Corporation.
7  *
8  * Permission is hereby granted, free of charge, to any person
9  * obtaining a copy of this software and associated documentation
10  * files (the "Software"), to deal in the Software without
11  * restriction, including without limitation the rights to use, copy,
12  * modify, merge, publish, distribute, sublicense, and/or sell copies
13  * of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be
17  * included in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26  * SOFTWARE.
27  *
28  *
29  */
30 
31 #ifdef HAVE_CONFIG_H
32 #include "cogl-config.h"
33 #endif
34 
35 #include "cogl-util.h"
36 #include "cogl-onscreen-private.h"
37 #include "cogl-frame-info-private.h"
38 #include "cogl-framebuffer-private.h"
39 #include "cogl-onscreen-template-private.h"
40 #include "cogl-context-private.h"
41 #include "cogl-object-private.h"
42 #include "cogl1-context.h"
43 #include "cogl-closure-list-private.h"
44 #include "cogl-poll-private.h"
45 #include "cogl-gtype-private.h"
46 
47 #ifdef COGL_HAS_X11_SUPPORT
48 #include "cogl-xlib-renderer.h"
49 #endif
50 
51 static void _cogl_onscreen_free (CoglOnscreen *onscreen);
52 
53 COGL_OBJECT_DEFINE_WITH_CODE_GTYPE (Onscreen, onscreen,
54                                     _cogl_onscreen_class.virt_unref =
55                                     _cogl_framebuffer_unref);
56 COGL_GTYPE_DEFINE_CLASS (Onscreen, onscreen,
57                          COGL_GTYPE_IMPLEMENT_INTERFACE (framebuffer));
58 
59 static gpointer
cogl_dummy_copy(gpointer data)60 cogl_dummy_copy (gpointer data)
61 {
62   return data;
63 }
64 
65 static void
cogl_dummy_free(gpointer data)66 cogl_dummy_free (gpointer data)
67 {
68 }
69 
70 COGL_GTYPE_DEFINE_BOXED (FrameClosure, frame_closure,
71                          cogl_dummy_copy,
72                          cogl_dummy_free);
73 COGL_GTYPE_DEFINE_BOXED (OnscreenResizeClosure,
74                          onscreen_resize_closure,
75                          cogl_dummy_copy,
76                          cogl_dummy_free);
77 COGL_GTYPE_DEFINE_BOXED (OnscreenDirtyClosure,
78                          onscreen_dirty_closure,
79                          cogl_dummy_copy,
80                          cogl_dummy_free);
81 
82 static void
_cogl_onscreen_init_from_template(CoglOnscreen * onscreen,CoglOnscreenTemplate * onscreen_template)83 _cogl_onscreen_init_from_template (CoglOnscreen *onscreen,
84                                    CoglOnscreenTemplate *onscreen_template)
85 {
86   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
87 
88   _cogl_list_init (&onscreen->frame_closures);
89   _cogl_list_init (&onscreen->resize_closures);
90   _cogl_list_init (&onscreen->dirty_closures);
91 
92   framebuffer->config = onscreen_template->config;
93   cogl_object_ref (framebuffer->config.swap_chain);
94 }
95 
96 /* XXX: While we still have backend in Clutter we need a dummy object
97  * to represent the CoglOnscreen framebuffer that the backend
98  * creates... */
99 CoglOnscreen *
_cogl_onscreen_new(void)100 _cogl_onscreen_new (void)
101 {
102   CoglOnscreen *onscreen = g_new0 (CoglOnscreen, 1);
103 
104   _COGL_GET_CONTEXT (ctx, NULL);
105 
106   _cogl_framebuffer_init (COGL_FRAMEBUFFER (onscreen),
107                           ctx,
108                           COGL_FRAMEBUFFER_TYPE_ONSCREEN,
109                           0x1eadbeef, /* width */
110                           0x1eadbeef); /* height */
111   /* NB: make sure to pass positive width/height numbers here
112    * because otherwise we'll hit input validation assertions!*/
113 
114   _cogl_onscreen_init_from_template (onscreen, ctx->display->onscreen_template);
115 
116   COGL_FRAMEBUFFER (onscreen)->allocated = TRUE;
117 
118   /* XXX: Note we don't initialize onscreen->winsys in this case. */
119 
120   return _cogl_onscreen_object_new (onscreen);
121 }
122 
123 CoglOnscreen *
cogl_onscreen_new(CoglContext * ctx,int width,int height)124 cogl_onscreen_new (CoglContext *ctx, int width, int height)
125 {
126   CoglOnscreen *onscreen;
127 
128   /* FIXME: We are assuming onscreen buffers will always be
129      premultiplied so we'll set the premult flag on the bitmap
130      format. This will usually be correct because the result of the
131      default blending operations for Cogl ends up with premultiplied
132      data in the framebuffer. However it is possible for the
133      framebuffer to be in whatever format depending on what
134      CoglPipeline is used to render to it. Eventually we may want to
135      add a way for an application to inform Cogl that the framebuffer
136      is not premultiplied in case it is being used for some special
137      purpose. */
138 
139   onscreen = g_new0 (CoglOnscreen, 1);
140   _cogl_framebuffer_init (COGL_FRAMEBUFFER (onscreen),
141                           ctx,
142                           COGL_FRAMEBUFFER_TYPE_ONSCREEN,
143                           width, /* width */
144                           height); /* height */
145 
146   _cogl_onscreen_init_from_template (onscreen, ctx->display->onscreen_template);
147 
148   return _cogl_onscreen_object_new (onscreen);
149 }
150 
151 static void
_cogl_onscreen_free(CoglOnscreen * onscreen)152 _cogl_onscreen_free (CoglOnscreen *onscreen)
153 {
154   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
155   const CoglWinsysVtable *winsys = _cogl_framebuffer_get_winsys (framebuffer);
156   CoglFrameInfo *frame_info;
157 
158   _cogl_closure_list_disconnect_all (&onscreen->resize_closures);
159   _cogl_closure_list_disconnect_all (&onscreen->frame_closures);
160   _cogl_closure_list_disconnect_all (&onscreen->dirty_closures);
161 
162   while ((frame_info = g_queue_pop_tail (&onscreen->pending_frame_infos)))
163     cogl_object_unref (frame_info);
164   g_queue_clear (&onscreen->pending_frame_infos);
165 
166   if (framebuffer->context->window_buffer == COGL_FRAMEBUFFER (onscreen))
167     framebuffer->context->window_buffer = NULL;
168 
169   winsys->onscreen_deinit (onscreen);
170   _COGL_RETURN_IF_FAIL (onscreen->winsys == NULL);
171 
172   /* Chain up to parent */
173   _cogl_framebuffer_free (framebuffer);
174 
175   free (onscreen);
176 }
177 
178 static void
notify_event(CoglOnscreen * onscreen,CoglFrameEvent event,CoglFrameInfo * info)179 notify_event (CoglOnscreen *onscreen,
180               CoglFrameEvent event,
181               CoglFrameInfo *info)
182 {
183   _cogl_closure_list_invoke (&onscreen->frame_closures,
184                              CoglFrameCallback,
185                              onscreen, event, info);
186 }
187 
188 static void
_cogl_dispatch_onscreen_cb(CoglContext * context)189 _cogl_dispatch_onscreen_cb (CoglContext *context)
190 {
191   CoglOnscreenEvent *event, *tmp;
192   CoglList queue;
193 
194   /* Dispatching the event callback may cause another frame to be
195    * drawn which in may cause another event to be queued immediately.
196    * To make sure this loop will only dispatch one set of events we'll
197    * steal the queue and iterate that separately */
198   _cogl_list_init (&queue);
199   _cogl_list_insert_list (&queue, &context->onscreen_events_queue);
200   _cogl_list_init (&context->onscreen_events_queue);
201 
202   _cogl_closure_disconnect (context->onscreen_dispatch_idle);
203   context->onscreen_dispatch_idle = NULL;
204 
205   _cogl_list_for_each_safe (event, tmp, &queue, link)
206     {
207       CoglOnscreen *onscreen = event->onscreen;
208       CoglFrameInfo *info = event->info;
209 
210       notify_event (onscreen, event->type, info);
211 
212       cogl_object_unref (onscreen);
213       cogl_object_unref (info);
214 
215       g_slice_free (CoglOnscreenEvent, event);
216     }
217 
218   while (!_cogl_list_empty (&context->onscreen_dirty_queue))
219     {
220       CoglOnscreenQueuedDirty *qe =
221         _cogl_container_of (context->onscreen_dirty_queue.next,
222                             CoglOnscreenQueuedDirty,
223                             link);
224 
225       _cogl_list_remove (&qe->link);
226 
227       _cogl_closure_list_invoke (&qe->onscreen->dirty_closures,
228                                  CoglOnscreenDirtyCallback,
229                                  qe->onscreen,
230                                  &qe->info);
231 
232       cogl_object_unref (qe->onscreen);
233 
234       g_slice_free (CoglOnscreenQueuedDirty, qe);
235     }
236 }
237 
238 static void
_cogl_onscreen_queue_dispatch_idle(CoglOnscreen * onscreen)239 _cogl_onscreen_queue_dispatch_idle (CoglOnscreen *onscreen)
240 {
241   CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context;
242 
243   if (!ctx->onscreen_dispatch_idle)
244     {
245       ctx->onscreen_dispatch_idle =
246         _cogl_poll_renderer_add_idle (ctx->display->renderer,
247                                       (CoglIdleCallback)
248                                       _cogl_dispatch_onscreen_cb,
249                                       ctx,
250                                       NULL);
251     }
252 }
253 
254 void
_cogl_onscreen_queue_dirty(CoglOnscreen * onscreen,const CoglOnscreenDirtyInfo * info)255 _cogl_onscreen_queue_dirty (CoglOnscreen *onscreen,
256                             const CoglOnscreenDirtyInfo *info)
257 {
258   CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context;
259   CoglOnscreenQueuedDirty *qe = g_slice_new (CoglOnscreenQueuedDirty);
260 
261   qe->onscreen = cogl_object_ref (onscreen);
262   qe->info = *info;
263   _cogl_list_insert (ctx->onscreen_dirty_queue.prev, &qe->link);
264 
265   _cogl_onscreen_queue_dispatch_idle (onscreen);
266 }
267 
268 void
_cogl_onscreen_queue_full_dirty(CoglOnscreen * onscreen)269 _cogl_onscreen_queue_full_dirty (CoglOnscreen *onscreen)
270 {
271   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
272   CoglOnscreenDirtyInfo info;
273 
274   info.x = 0;
275   info.y = 0;
276   info.width = framebuffer->width;
277   info.height = framebuffer->height;
278 
279   _cogl_onscreen_queue_dirty (onscreen, &info);
280 }
281 
282 void
_cogl_onscreen_queue_event(CoglOnscreen * onscreen,CoglFrameEvent type,CoglFrameInfo * info)283 _cogl_onscreen_queue_event (CoglOnscreen *onscreen,
284                             CoglFrameEvent type,
285                             CoglFrameInfo *info)
286 {
287   CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context;
288 
289   CoglOnscreenEvent *event = g_slice_new (CoglOnscreenEvent);
290 
291   event->onscreen = cogl_object_ref (onscreen);
292   event->info = cogl_object_ref (info);
293   event->type = type;
294 
295   _cogl_list_insert (ctx->onscreen_events_queue.prev, &event->link);
296 
297   _cogl_onscreen_queue_dispatch_idle (onscreen);
298 }
299 
300 void
cogl_onscreen_swap_buffers_with_damage(CoglOnscreen * onscreen,const int * rectangles,int n_rectangles)301 cogl_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
302                                         const int *rectangles,
303                                         int n_rectangles)
304 {
305   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
306   const CoglWinsysVtable *winsys;
307   CoglFrameInfo *info;
308 
309   _COGL_RETURN_IF_FAIL  (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN);
310 
311   info = _cogl_frame_info_new ();
312   info->frame_counter = onscreen->frame_counter;
313   g_queue_push_tail (&onscreen->pending_frame_infos, info);
314 
315   /* FIXME: we shouldn't need to flush *all* journals here! */
316   cogl_flush ();
317 
318   winsys = _cogl_framebuffer_get_winsys (framebuffer);
319   winsys->onscreen_swap_buffers_with_damage (onscreen,
320                                              rectangles, n_rectangles);
321   cogl_framebuffer_discard_buffers (framebuffer,
322                                     COGL_BUFFER_BIT_COLOR |
323                                     COGL_BUFFER_BIT_DEPTH |
324                                     COGL_BUFFER_BIT_STENCIL);
325 
326   if (!_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT))
327     {
328       CoglFrameInfo *info;
329 
330       g_warn_if_fail (onscreen->pending_frame_infos.length == 1);
331 
332       info = g_queue_pop_tail (&onscreen->pending_frame_infos);
333 
334       _cogl_onscreen_queue_event (onscreen, COGL_FRAME_EVENT_SYNC, info);
335       _cogl_onscreen_queue_event (onscreen, COGL_FRAME_EVENT_COMPLETE, info);
336 
337       cogl_object_unref (info);
338     }
339 
340   onscreen->frame_counter++;
341   framebuffer->mid_scene = FALSE;
342 }
343 
344 void
cogl_onscreen_swap_buffers(CoglOnscreen * onscreen)345 cogl_onscreen_swap_buffers (CoglOnscreen *onscreen)
346 {
347   cogl_onscreen_swap_buffers_with_damage (onscreen, NULL, 0);
348 }
349 
350 void
cogl_onscreen_swap_region(CoglOnscreen * onscreen,const int * rectangles,int n_rectangles)351 cogl_onscreen_swap_region (CoglOnscreen *onscreen,
352                            const int *rectangles,
353                            int n_rectangles)
354 {
355   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
356   const CoglWinsysVtable *winsys;
357   CoglFrameInfo *info;
358 
359   _COGL_RETURN_IF_FAIL  (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN);
360 
361   info = _cogl_frame_info_new ();
362   info->frame_counter = onscreen->frame_counter;
363   g_queue_push_tail (&onscreen->pending_frame_infos, info);
364 
365   /* FIXME: we shouldn't need to flush *all* journals here! */
366   cogl_flush ();
367 
368   winsys = _cogl_framebuffer_get_winsys (framebuffer);
369 
370   /* This should only be called if the winsys advertises
371      COGL_WINSYS_FEATURE_SWAP_REGION */
372   _COGL_RETURN_IF_FAIL (winsys->onscreen_swap_region != NULL);
373 
374   winsys->onscreen_swap_region (COGL_ONSCREEN (framebuffer),
375                                 rectangles,
376                                 n_rectangles);
377 
378   cogl_framebuffer_discard_buffers (framebuffer,
379                                     COGL_BUFFER_BIT_COLOR |
380                                     COGL_BUFFER_BIT_DEPTH |
381                                     COGL_BUFFER_BIT_STENCIL);
382 
383   if (!_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT))
384     {
385       CoglFrameInfo *info;
386 
387       g_warn_if_fail (onscreen->pending_frame_infos.length == 1);
388 
389       info = g_queue_pop_tail (&onscreen->pending_frame_infos);
390 
391       _cogl_onscreen_queue_event (onscreen, COGL_FRAME_EVENT_SYNC, info);
392       _cogl_onscreen_queue_event (onscreen, COGL_FRAME_EVENT_COMPLETE, info);
393 
394       cogl_object_unref (info);
395     }
396 
397   onscreen->frame_counter++;
398   framebuffer->mid_scene = FALSE;
399 }
400 
401 int
cogl_onscreen_get_buffer_age(CoglOnscreen * onscreen)402 cogl_onscreen_get_buffer_age (CoglOnscreen *onscreen)
403 {
404   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
405   const CoglWinsysVtable *winsys;
406 
407   _COGL_RETURN_VAL_IF_FAIL  (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN, 0);
408 
409   winsys = _cogl_framebuffer_get_winsys (framebuffer);
410 
411   if (!winsys->onscreen_get_buffer_age)
412     return 0;
413 
414   return winsys->onscreen_get_buffer_age (onscreen);
415 }
416 
417 #ifdef COGL_HAS_X11_SUPPORT
418 void
cogl_x11_onscreen_set_foreign_window_xid(CoglOnscreen * onscreen,uint32_t xid,CoglOnscreenX11MaskCallback update,void * user_data)419 cogl_x11_onscreen_set_foreign_window_xid (CoglOnscreen *onscreen,
420                                           uint32_t xid,
421                                           CoglOnscreenX11MaskCallback update,
422                                           void *user_data)
423 {
424   /* We don't wan't applications to get away with being lazy here and not
425    * passing an update callback... */
426   _COGL_RETURN_IF_FAIL (update);
427 
428   onscreen->foreign_xid = xid;
429   onscreen->foreign_update_mask_callback = update;
430   onscreen->foreign_update_mask_data = user_data;
431 }
432 
433 uint32_t
cogl_x11_onscreen_get_window_xid(CoglOnscreen * onscreen)434 cogl_x11_onscreen_get_window_xid (CoglOnscreen *onscreen)
435 {
436   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
437 
438   if (onscreen->foreign_xid)
439     return onscreen->foreign_xid;
440   else
441     {
442       const CoglWinsysVtable *winsys = _cogl_framebuffer_get_winsys (framebuffer);
443 
444       /* This should only be called for x11 onscreens */
445       _COGL_RETURN_VAL_IF_FAIL (winsys->onscreen_x11_get_window_xid != NULL, 0);
446 
447       return winsys->onscreen_x11_get_window_xid (onscreen);
448     }
449 }
450 
451 uint32_t
cogl_x11_onscreen_get_visual_xid(CoglOnscreen * onscreen)452 cogl_x11_onscreen_get_visual_xid (CoglOnscreen *onscreen)
453 {
454   CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context;
455   XVisualInfo *visinfo;
456   uint32_t id;
457 
458   /* This should only be called for xlib based onscreens */
459   visinfo = cogl_xlib_renderer_get_visual_info (ctx->display->renderer);
460   if (visinfo == NULL)
461     return 0;
462 
463   id = (uint32_t)visinfo->visualid;
464 
465   return id;
466 }
467 #endif /* COGL_HAS_X11_SUPPORT */
468 
469 CoglFrameClosure *
cogl_onscreen_add_frame_callback(CoglOnscreen * onscreen,CoglFrameCallback callback,void * user_data,CoglUserDataDestroyCallback destroy)470 cogl_onscreen_add_frame_callback (CoglOnscreen *onscreen,
471                                   CoglFrameCallback callback,
472                                   void *user_data,
473                                   CoglUserDataDestroyCallback destroy)
474 {
475   return _cogl_closure_list_add (&onscreen->frame_closures,
476                                  callback,
477                                  user_data,
478                                  destroy);
479 }
480 
481 void
cogl_onscreen_remove_frame_callback(CoglOnscreen * onscreen,CoglFrameClosure * closure)482 cogl_onscreen_remove_frame_callback (CoglOnscreen *onscreen,
483                                      CoglFrameClosure *closure)
484 {
485   _COGL_RETURN_IF_FAIL (closure);
486 
487   _cogl_closure_disconnect (closure);
488 }
489 
490 typedef struct _SwapBufferCallbackState
491 {
492   CoglSwapBuffersNotify callback;
493   void *user_data;
494 } SwapBufferCallbackState;
495 
496 static void
destroy_swap_buffers_callback_state(void * user_data)497 destroy_swap_buffers_callback_state (void *user_data)
498 {
499   g_slice_free (SwapBufferCallbackState, user_data);
500 }
501 
502 static void
shim_swap_buffers_callback(CoglOnscreen * onscreen,CoglFrameEvent event,CoglFrameInfo * info,void * user_data)503 shim_swap_buffers_callback (CoglOnscreen *onscreen,
504                             CoglFrameEvent event,
505                             CoglFrameInfo *info,
506                             void *user_data)
507 {
508   SwapBufferCallbackState *state = user_data;
509 
510   /* XXX: Note that technically it is a change in semantics for this
511    * interface to forward _SYNC events here and also makes the api
512    * name somewhat missleading.
513    *
514    * In practice though this interface is currently used by
515    * applications for throttling, not because they are strictly
516    * interested in knowing when a frame has been presented and so
517    * forwarding _SYNC events should serve them better.
518    */
519   if (event == COGL_FRAME_EVENT_SYNC)
520     state->callback (COGL_FRAMEBUFFER (onscreen), state->user_data);
521 }
522 
523 unsigned int
cogl_onscreen_add_swap_buffers_callback(CoglOnscreen * onscreen,CoglSwapBuffersNotify callback,void * user_data)524 cogl_onscreen_add_swap_buffers_callback (CoglOnscreen *onscreen,
525                                          CoglSwapBuffersNotify callback,
526                                          void *user_data)
527 {
528   CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context;
529   SwapBufferCallbackState *state = g_slice_new (SwapBufferCallbackState);
530   CoglFrameClosure *closure;
531   unsigned int id = ctx->next_swap_callback_id++;
532 
533   state->callback = callback;
534   state->user_data = user_data;
535 
536   closure =
537     cogl_onscreen_add_frame_callback (onscreen,
538                                       shim_swap_buffers_callback,
539                                       state,
540                                       destroy_swap_buffers_callback_state);
541 
542   g_hash_table_insert (ctx->swap_callback_closures,
543                        GINT_TO_POINTER (id),
544                        closure);
545 
546   return id;
547 }
548 
549 void
cogl_onscreen_remove_swap_buffers_callback(CoglOnscreen * onscreen,unsigned int id)550 cogl_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen,
551                                             unsigned int id)
552 {
553   CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context;
554   CoglFrameClosure *closure = g_hash_table_lookup (ctx->swap_callback_closures,
555                                                    GINT_TO_POINTER (id));
556 
557   _COGL_RETURN_IF_FAIL (closure);
558 
559   cogl_onscreen_remove_frame_callback (onscreen, closure);
560 }
561 
562 void
cogl_onscreen_set_swap_throttled(CoglOnscreen * onscreen,CoglBool throttled)563 cogl_onscreen_set_swap_throttled (CoglOnscreen *onscreen,
564                                   CoglBool throttled)
565 {
566   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
567   framebuffer->config.swap_throttled = throttled;
568   if (framebuffer->allocated)
569     {
570       const CoglWinsysVtable *winsys =
571         _cogl_framebuffer_get_winsys (framebuffer);
572       winsys->onscreen_update_swap_throttled (onscreen);
573     }
574 }
575 
576 void
cogl_onscreen_show(CoglOnscreen * onscreen)577 cogl_onscreen_show (CoglOnscreen *onscreen)
578 {
579   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
580   const CoglWinsysVtable *winsys;
581 
582   if (!framebuffer->allocated)
583     {
584       if (!cogl_framebuffer_allocate (framebuffer, NULL))
585         return;
586     }
587 
588   winsys = _cogl_framebuffer_get_winsys (framebuffer);
589   if (winsys->onscreen_set_visibility)
590     winsys->onscreen_set_visibility (onscreen, TRUE);
591 }
592 
593 void
cogl_onscreen_hide(CoglOnscreen * onscreen)594 cogl_onscreen_hide (CoglOnscreen *onscreen)
595 {
596   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
597 
598   if (framebuffer->allocated)
599     {
600       const CoglWinsysVtable *winsys =
601         _cogl_framebuffer_get_winsys (framebuffer);
602       if (winsys->onscreen_set_visibility)
603         winsys->onscreen_set_visibility (onscreen, FALSE);
604     }
605 }
606 
607 void
_cogl_onscreen_notify_frame_sync(CoglOnscreen * onscreen,CoglFrameInfo * info)608 _cogl_onscreen_notify_frame_sync (CoglOnscreen *onscreen, CoglFrameInfo *info)
609 {
610   notify_event (onscreen, COGL_FRAME_EVENT_SYNC, info);
611 }
612 
613 void
_cogl_onscreen_notify_complete(CoglOnscreen * onscreen,CoglFrameInfo * info)614 _cogl_onscreen_notify_complete (CoglOnscreen *onscreen, CoglFrameInfo *info)
615 {
616   notify_event (onscreen, COGL_FRAME_EVENT_COMPLETE, info);
617 }
618 
619 void
_cogl_onscreen_notify_resize(CoglOnscreen * onscreen)620 _cogl_onscreen_notify_resize (CoglOnscreen *onscreen)
621 {
622   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
623 
624   _cogl_closure_list_invoke (&onscreen->resize_closures,
625                              CoglOnscreenResizeCallback,
626                              onscreen,
627                              framebuffer->width,
628                              framebuffer->height);
629 }
630 
631 void
_cogl_framebuffer_winsys_update_size(CoglFramebuffer * framebuffer,int width,int height)632 _cogl_framebuffer_winsys_update_size (CoglFramebuffer *framebuffer,
633                                       int width, int height)
634 {
635   if (framebuffer->width == width && framebuffer->height == height)
636     return;
637 
638   framebuffer->width = width;
639   framebuffer->height = height;
640 
641   cogl_framebuffer_set_viewport (framebuffer, 0, 0, width, height);
642 
643   if (!_cogl_has_private_feature (framebuffer->context,
644                                   COGL_PRIVATE_FEATURE_DIRTY_EVENTS))
645     _cogl_onscreen_queue_full_dirty (COGL_ONSCREEN (framebuffer));
646 }
647 
648 void
cogl_onscreen_set_resizable(CoglOnscreen * onscreen,CoglBool resizable)649 cogl_onscreen_set_resizable (CoglOnscreen *onscreen,
650                              CoglBool resizable)
651 {
652   CoglFramebuffer *framebuffer;
653   const CoglWinsysVtable *winsys;
654 
655   if (onscreen->resizable == resizable)
656     return;
657 
658   onscreen->resizable = resizable;
659 
660   framebuffer = COGL_FRAMEBUFFER (onscreen);
661   if (framebuffer->allocated)
662     {
663       winsys = _cogl_framebuffer_get_winsys (COGL_FRAMEBUFFER (onscreen));
664 
665       if (winsys->onscreen_set_resizable)
666         winsys->onscreen_set_resizable (onscreen, resizable);
667     }
668 }
669 
670 CoglBool
cogl_onscreen_get_resizable(CoglOnscreen * onscreen)671 cogl_onscreen_get_resizable (CoglOnscreen *onscreen)
672 {
673   return onscreen->resizable;
674 }
675 
676 CoglOnscreenResizeClosure *
cogl_onscreen_add_resize_callback(CoglOnscreen * onscreen,CoglOnscreenResizeCallback callback,void * user_data,CoglUserDataDestroyCallback destroy)677 cogl_onscreen_add_resize_callback (CoglOnscreen *onscreen,
678                                    CoglOnscreenResizeCallback callback,
679                                    void *user_data,
680                                    CoglUserDataDestroyCallback destroy)
681 {
682   return _cogl_closure_list_add (&onscreen->resize_closures,
683                                  callback,
684                                  user_data,
685                                  destroy);
686 }
687 
688 void
cogl_onscreen_remove_resize_callback(CoglOnscreen * onscreen,CoglOnscreenResizeClosure * closure)689 cogl_onscreen_remove_resize_callback (CoglOnscreen *onscreen,
690                                       CoglOnscreenResizeClosure *closure)
691 {
692   _cogl_closure_disconnect (closure);
693 }
694 
695 CoglOnscreenDirtyClosure *
cogl_onscreen_add_dirty_callback(CoglOnscreen * onscreen,CoglOnscreenDirtyCallback callback,void * user_data,CoglUserDataDestroyCallback destroy)696 cogl_onscreen_add_dirty_callback (CoglOnscreen *onscreen,
697                                   CoglOnscreenDirtyCallback callback,
698                                   void *user_data,
699                                   CoglUserDataDestroyCallback destroy)
700 {
701   return _cogl_closure_list_add (&onscreen->dirty_closures,
702                                  callback,
703                                  user_data,
704                                  destroy);
705 }
706 
707 void
cogl_onscreen_remove_dirty_callback(CoglOnscreen * onscreen,CoglOnscreenDirtyClosure * closure)708 cogl_onscreen_remove_dirty_callback (CoglOnscreen *onscreen,
709                                      CoglOnscreenDirtyClosure *closure)
710 {
711   _COGL_RETURN_IF_FAIL (closure);
712 
713   _cogl_closure_disconnect (closure);
714 }
715 
716 int64_t
cogl_onscreen_get_frame_counter(CoglOnscreen * onscreen)717 cogl_onscreen_get_frame_counter (CoglOnscreen *onscreen)
718 {
719   return onscreen->frame_counter;
720 }
721