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