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 "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   g_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 #ifdef COGL_HAS_WIN32_SUPPORT
470 
471 void
cogl_win32_onscreen_set_foreign_window(CoglOnscreen * onscreen,HWND hwnd)472 cogl_win32_onscreen_set_foreign_window (CoglOnscreen *onscreen,
473                                         HWND hwnd)
474 {
475   onscreen->foreign_hwnd = hwnd;
476 }
477 
478 HWND
cogl_win32_onscreen_get_window(CoglOnscreen * onscreen)479 cogl_win32_onscreen_get_window (CoglOnscreen *onscreen)
480 {
481   if (onscreen->foreign_hwnd)
482     return onscreen->foreign_hwnd;
483   else
484     {
485       CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
486       const CoglWinsysVtable *winsys =
487         _cogl_framebuffer_get_winsys (framebuffer);
488 
489       /* This should only be called for win32 onscreens */
490       _COGL_RETURN_VAL_IF_FAIL (winsys->onscreen_win32_get_window != NULL, 0);
491 
492       return winsys->onscreen_win32_get_window (onscreen);
493     }
494 }
495 
496 #endif /* COGL_HAS_WIN32_SUPPORT */
497 
498 CoglFrameClosure *
cogl_onscreen_add_frame_callback(CoglOnscreen * onscreen,CoglFrameCallback callback,void * user_data,CoglUserDataDestroyCallback destroy)499 cogl_onscreen_add_frame_callback (CoglOnscreen *onscreen,
500                                   CoglFrameCallback callback,
501                                   void *user_data,
502                                   CoglUserDataDestroyCallback destroy)
503 {
504   return _cogl_closure_list_add (&onscreen->frame_closures,
505                                  callback,
506                                  user_data,
507                                  destroy);
508 }
509 
510 void
cogl_onscreen_remove_frame_callback(CoglOnscreen * onscreen,CoglFrameClosure * closure)511 cogl_onscreen_remove_frame_callback (CoglOnscreen *onscreen,
512                                      CoglFrameClosure *closure)
513 {
514   _COGL_RETURN_IF_FAIL (closure);
515 
516   _cogl_closure_disconnect (closure);
517 }
518 
519 typedef struct _SwapBufferCallbackState
520 {
521   CoglSwapBuffersNotify callback;
522   void *user_data;
523 } SwapBufferCallbackState;
524 
525 static void
destroy_swap_buffers_callback_state(void * user_data)526 destroy_swap_buffers_callback_state (void *user_data)
527 {
528   g_slice_free (SwapBufferCallbackState, user_data);
529 }
530 
531 static void
shim_swap_buffers_callback(CoglOnscreen * onscreen,CoglFrameEvent event,CoglFrameInfo * info,void * user_data)532 shim_swap_buffers_callback (CoglOnscreen *onscreen,
533                             CoglFrameEvent event,
534                             CoglFrameInfo *info,
535                             void *user_data)
536 {
537   SwapBufferCallbackState *state = user_data;
538 
539   /* XXX: Note that technically it is a change in semantics for this
540    * interface to forward _SYNC events here and also makes the api
541    * name somewhat missleading.
542    *
543    * In practice though this interface is currently used by
544    * applications for throttling, not because they are strictly
545    * interested in knowing when a frame has been presented and so
546    * forwarding _SYNC events should serve them better.
547    */
548   if (event == COGL_FRAME_EVENT_SYNC)
549     state->callback (COGL_FRAMEBUFFER (onscreen), state->user_data);
550 }
551 
552 unsigned int
cogl_onscreen_add_swap_buffers_callback(CoglOnscreen * onscreen,CoglSwapBuffersNotify callback,void * user_data)553 cogl_onscreen_add_swap_buffers_callback (CoglOnscreen *onscreen,
554                                          CoglSwapBuffersNotify callback,
555                                          void *user_data)
556 {
557   CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context;
558   SwapBufferCallbackState *state = g_slice_new (SwapBufferCallbackState);
559   CoglFrameClosure *closure;
560   unsigned int id = ctx->next_swap_callback_id++;
561 
562   state->callback = callback;
563   state->user_data = user_data;
564 
565   closure =
566     cogl_onscreen_add_frame_callback (onscreen,
567                                       shim_swap_buffers_callback,
568                                       state,
569                                       destroy_swap_buffers_callback_state);
570 
571   g_hash_table_insert (ctx->swap_callback_closures,
572                        GINT_TO_POINTER (id),
573                        closure);
574 
575   return id;
576 }
577 
578 void
cogl_onscreen_remove_swap_buffers_callback(CoglOnscreen * onscreen,unsigned int id)579 cogl_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen,
580                                             unsigned int id)
581 {
582   CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context;
583   CoglFrameClosure *closure = g_hash_table_lookup (ctx->swap_callback_closures,
584                                                    GINT_TO_POINTER (id));
585 
586   _COGL_RETURN_IF_FAIL (closure);
587 
588   cogl_onscreen_remove_frame_callback (onscreen, closure);
589 }
590 
591 void
cogl_onscreen_set_swap_throttled(CoglOnscreen * onscreen,CoglBool throttled)592 cogl_onscreen_set_swap_throttled (CoglOnscreen *onscreen,
593                                   CoglBool throttled)
594 {
595   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
596   framebuffer->config.swap_throttled = throttled;
597   if (framebuffer->allocated)
598     {
599       const CoglWinsysVtable *winsys =
600         _cogl_framebuffer_get_winsys (framebuffer);
601       winsys->onscreen_update_swap_throttled (onscreen);
602     }
603 }
604 
605 void
cogl_onscreen_show(CoglOnscreen * onscreen)606 cogl_onscreen_show (CoglOnscreen *onscreen)
607 {
608   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
609   const CoglWinsysVtable *winsys;
610 
611   if (!framebuffer->allocated)
612     {
613       if (!cogl_framebuffer_allocate (framebuffer, NULL))
614         return;
615     }
616 
617   winsys = _cogl_framebuffer_get_winsys (framebuffer);
618   if (winsys->onscreen_set_visibility)
619     winsys->onscreen_set_visibility (onscreen, TRUE);
620 }
621 
622 void
cogl_onscreen_hide(CoglOnscreen * onscreen)623 cogl_onscreen_hide (CoglOnscreen *onscreen)
624 {
625   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
626 
627   if (framebuffer->allocated)
628     {
629       const CoglWinsysVtable *winsys =
630         _cogl_framebuffer_get_winsys (framebuffer);
631       if (winsys->onscreen_set_visibility)
632         winsys->onscreen_set_visibility (onscreen, FALSE);
633     }
634 }
635 
636 void
_cogl_onscreen_notify_frame_sync(CoglOnscreen * onscreen,CoglFrameInfo * info)637 _cogl_onscreen_notify_frame_sync (CoglOnscreen *onscreen, CoglFrameInfo *info)
638 {
639   notify_event (onscreen, COGL_FRAME_EVENT_SYNC, info);
640 }
641 
642 void
_cogl_onscreen_notify_complete(CoglOnscreen * onscreen,CoglFrameInfo * info)643 _cogl_onscreen_notify_complete (CoglOnscreen *onscreen, CoglFrameInfo *info)
644 {
645   notify_event (onscreen, COGL_FRAME_EVENT_COMPLETE, info);
646 }
647 
648 void
_cogl_onscreen_notify_resize(CoglOnscreen * onscreen)649 _cogl_onscreen_notify_resize (CoglOnscreen *onscreen)
650 {
651   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
652 
653   _cogl_closure_list_invoke (&onscreen->resize_closures,
654                              CoglOnscreenResizeCallback,
655                              onscreen,
656                              framebuffer->width,
657                              framebuffer->height);
658 }
659 
660 void
_cogl_framebuffer_winsys_update_size(CoglFramebuffer * framebuffer,int width,int height)661 _cogl_framebuffer_winsys_update_size (CoglFramebuffer *framebuffer,
662                                       int width, int height)
663 {
664   if (framebuffer->width == width && framebuffer->height == height)
665     return;
666 
667   framebuffer->width = width;
668   framebuffer->height = height;
669 
670   cogl_framebuffer_set_viewport (framebuffer, 0, 0, width, height);
671 
672   if (!_cogl_has_private_feature (framebuffer->context,
673                                   COGL_PRIVATE_FEATURE_DIRTY_EVENTS))
674     _cogl_onscreen_queue_full_dirty (COGL_ONSCREEN (framebuffer));
675 }
676 
677 void
cogl_onscreen_set_resizable(CoglOnscreen * onscreen,CoglBool resizable)678 cogl_onscreen_set_resizable (CoglOnscreen *onscreen,
679                              CoglBool resizable)
680 {
681   CoglFramebuffer *framebuffer;
682   const CoglWinsysVtable *winsys;
683 
684   if (onscreen->resizable == resizable)
685     return;
686 
687   onscreen->resizable = resizable;
688 
689   framebuffer = COGL_FRAMEBUFFER (onscreen);
690   if (framebuffer->allocated)
691     {
692       winsys = _cogl_framebuffer_get_winsys (COGL_FRAMEBUFFER (onscreen));
693 
694       if (winsys->onscreen_set_resizable)
695         winsys->onscreen_set_resizable (onscreen, resizable);
696     }
697 }
698 
699 CoglBool
cogl_onscreen_get_resizable(CoglOnscreen * onscreen)700 cogl_onscreen_get_resizable (CoglOnscreen *onscreen)
701 {
702   return onscreen->resizable;
703 }
704 
705 CoglOnscreenResizeClosure *
cogl_onscreen_add_resize_callback(CoglOnscreen * onscreen,CoglOnscreenResizeCallback callback,void * user_data,CoglUserDataDestroyCallback destroy)706 cogl_onscreen_add_resize_callback (CoglOnscreen *onscreen,
707                                    CoglOnscreenResizeCallback callback,
708                                    void *user_data,
709                                    CoglUserDataDestroyCallback destroy)
710 {
711   return _cogl_closure_list_add (&onscreen->resize_closures,
712                                  callback,
713                                  user_data,
714                                  destroy);
715 }
716 
717 void
cogl_onscreen_remove_resize_callback(CoglOnscreen * onscreen,CoglOnscreenResizeClosure * closure)718 cogl_onscreen_remove_resize_callback (CoglOnscreen *onscreen,
719                                       CoglOnscreenResizeClosure *closure)
720 {
721   _cogl_closure_disconnect (closure);
722 }
723 
724 CoglOnscreenDirtyClosure *
cogl_onscreen_add_dirty_callback(CoglOnscreen * onscreen,CoglOnscreenDirtyCallback callback,void * user_data,CoglUserDataDestroyCallback destroy)725 cogl_onscreen_add_dirty_callback (CoglOnscreen *onscreen,
726                                   CoglOnscreenDirtyCallback callback,
727                                   void *user_data,
728                                   CoglUserDataDestroyCallback destroy)
729 {
730   return _cogl_closure_list_add (&onscreen->dirty_closures,
731                                  callback,
732                                  user_data,
733                                  destroy);
734 }
735 
736 void
cogl_onscreen_remove_dirty_callback(CoglOnscreen * onscreen,CoglOnscreenDirtyClosure * closure)737 cogl_onscreen_remove_dirty_callback (CoglOnscreen *onscreen,
738                                      CoglOnscreenDirtyClosure *closure)
739 {
740   _COGL_RETURN_IF_FAIL (closure);
741 
742   _cogl_closure_disconnect (closure);
743 }
744 
745 int64_t
cogl_onscreen_get_frame_counter(CoglOnscreen * onscreen)746 cogl_onscreen_get_frame_counter (CoglOnscreen *onscreen)
747 {
748   return onscreen->frame_counter;
749 }
750