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