1 /*
2  * Cogl
3  *
4  * A Low Level GPU Graphics and Utilities API
5  *
6  * Copyright (C) 2007,2008,2009,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 #include "cogl-config.h"
32 
33 #include "cogl-mutter.h"
34 #include "cogl-object.h"
35 #include "cogl-private.h"
36 #include "cogl-profile.h"
37 #include "cogl-util.h"
38 #include "cogl-context-private.h"
39 #include "cogl-display-private.h"
40 #include "cogl-renderer-private.h"
41 #include "cogl-journal-private.h"
42 #include "cogl-texture-private.h"
43 #include "cogl-texture-2d-private.h"
44 #include "cogl-pipeline-private.h"
45 #include "cogl-framebuffer-private.h"
46 #include "cogl-onscreen-private.h"
47 #include "cogl-attribute-private.h"
48 #include "cogl1-context.h"
49 #include "cogl-gtype-private.h"
50 #include "winsys/cogl-winsys-private.h"
51 
52 #include <gio/gio.h>
53 #include <string.h>
54 #include <stdlib.h>
55 
56 static void _cogl_context_free (CoglContext *context);
57 
58 COGL_OBJECT_DEFINE (Context, context);
59 COGL_GTYPE_DEFINE_CLASS (Context, context);
60 
61 extern void
62 _cogl_create_context_driver (CoglContext *context);
63 
64 static CoglContext *_cogl_context = NULL;
65 
66 static void
_cogl_init_feature_overrides(CoglContext * ctx)67 _cogl_init_feature_overrides (CoglContext *ctx)
68 {
69   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PBOS)))
70     COGL_FLAGS_SET (ctx->private_features, COGL_PRIVATE_FEATURE_PBOS, FALSE);
71 }
72 
73 const CoglWinsysVtable *
_cogl_context_get_winsys(CoglContext * context)74 _cogl_context_get_winsys (CoglContext *context)
75 {
76   return context->display->renderer->winsys_vtable;
77 }
78 
79 static const CoglDriverVtable *
_cogl_context_get_driver(CoglContext * context)80 _cogl_context_get_driver (CoglContext *context)
81 {
82   return context->driver_vtable;
83 }
84 
85 /* For reference: There was some deliberation over whether to have a
86  * constructor that could throw an exception but looking at standard
87  * practices with several high level OO languages including python, C++,
88  * C# Java and Ruby they all support exceptions in constructors and the
89  * general consensus appears to be that throwing an exception is neater
90  * than successfully constructing with an internal error status that
91  * would then have to be explicitly checked via some form of ::is_ok()
92  * method.
93  */
94 CoglContext *
cogl_context_new(CoglDisplay * display,GError ** error)95 cogl_context_new (CoglDisplay *display,
96                   GError **error)
97 {
98   CoglContext *context;
99   uint8_t white_pixel[] = { 0xff, 0xff, 0xff, 0xff };
100   const CoglWinsysVtable *winsys;
101   int i;
102   GError *local_error = NULL;
103 
104   _cogl_init ();
105 
106 #ifdef COGL_ENABLE_PROFILE
107   /* We need to be absolutely sure that uprof has been initialized
108    * before calling _cogl_uprof_init. uprof_init (NULL, NULL)
109    * will be a NOP if it has been initialized but it will also
110    * mean subsequent parsing of the UProf GOptionGroup will have no
111    * affect.
112    *
113    * Sadly GOptionGroup based library initialization is extremely
114    * fragile by design because GOptionGroups have no notion of
115    * dependencies and so the order things are initialized isn't
116    * currently under tight control.
117    */
118   uprof_init (NULL, NULL);
119   _cogl_uprof_init ();
120 #endif
121 
122   /* Allocate context memory */
123   context = g_malloc0 (sizeof (CoglContext));
124 
125   /* Convert the context into an object immediately in case any of the
126      code below wants to verify that the context pointer is a valid
127      object */
128   _cogl_context_object_new (context);
129 
130   /* XXX: Gross hack!
131    * Currently everything in Cogl just assumes there is a default
132    * context which it can access via _COGL_GET_CONTEXT() including
133    * code used to construct a CoglContext. Until all of that code
134    * has been updated to take an explicit context argument we have
135    * to immediately make our pointer the default context.
136    */
137   _cogl_context = context;
138 
139   /* Init default values */
140   memset (context->features, 0, sizeof (context->features));
141   memset (context->private_features, 0, sizeof (context->private_features));
142   memset (context->winsys_features, 0, sizeof (context->winsys_features));
143 
144   if (!display)
145     {
146       CoglRenderer *renderer = cogl_renderer_new ();
147       if (!cogl_renderer_connect (renderer, error))
148         {
149           g_free (context);
150           return NULL;
151         }
152 
153       display = cogl_display_new (renderer, NULL);
154       cogl_object_unref(renderer);
155     }
156   else
157     cogl_object_ref (display);
158 
159   if (!cogl_display_setup (display, error))
160     {
161       cogl_object_unref (display);
162       g_free (context);
163       return NULL;
164     }
165 
166   context->display = display;
167 
168   /* This is duplicated data, but it's much more convenient to have
169      the driver attached to the context and the value is accessed a
170      lot throughout Cogl */
171   context->driver = display->renderer->driver;
172 
173   /* Again this is duplicated data, but it convenient to be able
174    * access these from the context. */
175   context->driver_vtable = display->renderer->driver_vtable;
176   context->texture_driver = display->renderer->texture_driver;
177 
178   for (i = 0; i < G_N_ELEMENTS (context->private_features); i++)
179     context->private_features[i] |= display->renderer->private_features[i];
180 
181   winsys = _cogl_context_get_winsys (context);
182   if (!winsys->context_init (context, error))
183     {
184       cogl_object_unref (display);
185       g_free (context);
186       return NULL;
187     }
188 
189   if (!context->driver_vtable->context_init (context))
190     {
191       cogl_object_unref (display);
192       g_free (context);
193       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
194                    "Failed to initialize context");
195       return NULL;
196     }
197 
198   context->attribute_name_states_hash =
199     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
200   context->attribute_name_index_map = NULL;
201   context->n_attribute_names = 0;
202 
203   /* The "cogl_color_in" attribute needs a deterministic name_index
204    * so we make sure it's the first attribute name we register */
205   _cogl_attribute_register_attribute_name (context, "cogl_color_in");
206 
207 
208   context->uniform_names =
209     g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
210   context->uniform_name_hash = g_hash_table_new (g_str_hash, g_str_equal);
211   context->n_uniform_names = 0;
212 
213   /* Initialise the driver specific state */
214   _cogl_init_feature_overrides (context);
215 
216   context->sampler_cache = _cogl_sampler_cache_new (context);
217 
218   _cogl_pipeline_init_default_pipeline ();
219   _cogl_pipeline_init_default_layers ();
220   _cogl_pipeline_init_state_hash_functions ();
221   _cogl_pipeline_init_layer_state_hash_functions ();
222 
223   context->current_clip_stack_valid = FALSE;
224   context->current_clip_stack = NULL;
225 
226   context->legacy_backface_culling_enabled = FALSE;
227 
228   graphene_matrix_init_identity (&context->identity_matrix);
229   graphene_matrix_init_identity (&context->y_flip_matrix);
230   graphene_matrix_scale (&context->y_flip_matrix, 1, -1, 1);
231 
232   context->opaque_color_pipeline = cogl_pipeline_new (context);
233 
234   context->codegen_header_buffer = g_string_new ("");
235   context->codegen_source_buffer = g_string_new ("");
236   context->codegen_boilerplate_buffer = g_string_new ("");
237 
238   context->default_gl_texture_2d_tex = NULL;
239 
240   context->framebuffers = NULL;
241   context->current_draw_buffer = NULL;
242   context->current_read_buffer = NULL;
243   context->current_draw_buffer_state_flushed = 0;
244   context->current_draw_buffer_changes = COGL_FRAMEBUFFER_STATE_ALL;
245 
246   context->swap_callback_closures =
247     g_hash_table_new (g_direct_hash, g_direct_equal);
248 
249   _cogl_list_init (&context->onscreen_events_queue);
250   _cogl_list_init (&context->onscreen_dirty_queue);
251 
252   context->journal_flush_attributes_array =
253     g_array_new (TRUE, FALSE, sizeof (CoglAttribute *));
254   context->journal_clip_bounds = NULL;
255 
256   context->current_pipeline = NULL;
257   context->current_pipeline_changes_since_flush = 0;
258   context->current_pipeline_with_color_attrib = FALSE;
259 
260   _cogl_bitmask_init (&context->enabled_custom_attributes);
261   _cogl_bitmask_init (&context->enable_custom_attributes_tmp);
262   _cogl_bitmask_init (&context->changed_bits_tmp);
263 
264   context->max_texture_units = -1;
265   context->max_activateable_texture_units = -1;
266 
267   context->current_gl_program = 0;
268 
269   context->current_gl_dither_enabled = TRUE;
270 
271   context->gl_blend_enable_cache = FALSE;
272 
273   context->depth_test_enabled_cache = FALSE;
274   context->depth_test_function_cache = COGL_DEPTH_TEST_FUNCTION_LESS;
275   context->depth_writing_enabled_cache = TRUE;
276   context->depth_range_near_cache = 0;
277   context->depth_range_far_cache = 1;
278 
279   context->legacy_depth_test_enabled = FALSE;
280 
281   context->pipeline_cache = _cogl_pipeline_cache_new ();
282 
283   for (i = 0; i < COGL_BUFFER_BIND_TARGET_COUNT; i++)
284     context->current_buffer[i] = NULL;
285 
286   context->stencil_pipeline = cogl_pipeline_new (context);
287 
288   context->rectangle_byte_indices = NULL;
289   context->rectangle_short_indices = NULL;
290   context->rectangle_short_indices_len = 0;
291 
292   context->blit_texture_pipeline = NULL;
293 
294   context->current_modelview_entry = NULL;
295   context->current_projection_entry = NULL;
296   _cogl_matrix_entry_identity_init (&context->identity_entry);
297 
298   /* Create default textures used for fall backs */
299   context->default_gl_texture_2d_tex =
300     cogl_texture_2d_new_from_data (context,
301                                    1, 1,
302                                    COGL_PIXEL_FORMAT_RGBA_8888_PRE,
303                                    0, /* rowstride */
304                                    white_pixel,
305                                    &local_error);
306   if (!context->default_gl_texture_2d_tex)
307     {
308       cogl_object_unref (display);
309       g_free (context);
310       g_propagate_prefixed_error (error, local_error,
311                                   "Failed to create 1x1 fallback texture: ");
312       return NULL;
313     }
314 
315   context->atlases = NULL;
316   g_hook_list_init (&context->atlas_reorganize_callbacks, sizeof (GHook));
317 
318   context->buffer_map_fallback_array = g_byte_array_new ();
319   context->buffer_map_fallback_in_use = FALSE;
320 
321   _cogl_list_init (&context->fences);
322 
323   context->named_pipelines =
324     g_hash_table_new_full (NULL, NULL, NULL, cogl_object_unref);
325 
326   return context;
327 }
328 
329 static void
_cogl_context_free(CoglContext * context)330 _cogl_context_free (CoglContext *context)
331 {
332   const CoglWinsysVtable *winsys = _cogl_context_get_winsys (context);
333   const CoglDriverVtable *driver = _cogl_context_get_driver (context);
334 
335   winsys->context_deinit (context);
336 
337   if (context->default_gl_texture_2d_tex)
338     cogl_object_unref (context->default_gl_texture_2d_tex);
339 
340   if (context->opaque_color_pipeline)
341     cogl_object_unref (context->opaque_color_pipeline);
342 
343   if (context->blit_texture_pipeline)
344     cogl_object_unref (context->blit_texture_pipeline);
345 
346   if (context->swap_callback_closures)
347     g_hash_table_destroy (context->swap_callback_closures);
348 
349   if (context->journal_flush_attributes_array)
350     g_array_free (context->journal_flush_attributes_array, TRUE);
351   if (context->journal_clip_bounds)
352     g_array_free (context->journal_clip_bounds, TRUE);
353 
354   if (context->rectangle_byte_indices)
355     cogl_object_unref (context->rectangle_byte_indices);
356   if (context->rectangle_short_indices)
357     cogl_object_unref (context->rectangle_short_indices);
358 
359   if (context->default_pipeline)
360     cogl_object_unref (context->default_pipeline);
361 
362   if (context->dummy_layer_dependant)
363     cogl_object_unref (context->dummy_layer_dependant);
364   if (context->default_layer_n)
365     cogl_object_unref (context->default_layer_n);
366   if (context->default_layer_0)
367     cogl_object_unref (context->default_layer_0);
368 
369   if (context->current_clip_stack_valid)
370     _cogl_clip_stack_unref (context->current_clip_stack);
371 
372   g_slist_free (context->atlases);
373   g_hook_list_clear (&context->atlas_reorganize_callbacks);
374 
375   _cogl_bitmask_destroy (&context->enabled_custom_attributes);
376   _cogl_bitmask_destroy (&context->enable_custom_attributes_tmp);
377   _cogl_bitmask_destroy (&context->changed_bits_tmp);
378 
379   if (context->current_modelview_entry)
380     cogl_matrix_entry_unref (context->current_modelview_entry);
381   if (context->current_projection_entry)
382     cogl_matrix_entry_unref (context->current_projection_entry);
383 
384   _cogl_pipeline_cache_free (context->pipeline_cache);
385 
386   _cogl_sampler_cache_free (context->sampler_cache);
387 
388   g_ptr_array_free (context->uniform_names, TRUE);
389   g_hash_table_destroy (context->uniform_name_hash);
390 
391   g_hash_table_destroy (context->attribute_name_states_hash);
392   g_array_free (context->attribute_name_index_map, TRUE);
393 
394   g_byte_array_free (context->buffer_map_fallback_array, TRUE);
395 
396   driver->context_deinit (context);
397 
398   cogl_object_unref (context->display);
399 
400   g_hash_table_remove_all (context->named_pipelines);
401   g_hash_table_destroy (context->named_pipelines);
402 
403   g_free (context);
404 }
405 
406 CoglContext *
_cogl_context_get_default(void)407 _cogl_context_get_default (void)
408 {
409   GError *error = NULL;
410   /* Create if doesn't exist yet */
411   if (_cogl_context == NULL)
412     {
413       _cogl_context = cogl_context_new (NULL, &error);
414       if (!_cogl_context)
415         {
416           g_warning ("Failed to create default context: %s",
417                      error->message);
418           g_error_free (error);
419         }
420     }
421 
422   return _cogl_context;
423 }
424 
425 CoglDisplay *
cogl_context_get_display(CoglContext * context)426 cogl_context_get_display (CoglContext *context)
427 {
428   return context->display;
429 }
430 
431 CoglRenderer *
cogl_context_get_renderer(CoglContext * context)432 cogl_context_get_renderer (CoglContext *context)
433 {
434   return context->display->renderer;
435 }
436 
437 gboolean
_cogl_context_update_features(CoglContext * context,GError ** error)438 _cogl_context_update_features (CoglContext *context,
439                                GError **error)
440 {
441   return context->driver_vtable->update_features (context, error);
442 }
443 
444 void
_cogl_context_set_current_projection_entry(CoglContext * context,CoglMatrixEntry * entry)445 _cogl_context_set_current_projection_entry (CoglContext *context,
446                                             CoglMatrixEntry *entry)
447 {
448   cogl_matrix_entry_ref (entry);
449   if (context->current_projection_entry)
450     cogl_matrix_entry_unref (context->current_projection_entry);
451   context->current_projection_entry = entry;
452 }
453 
454 void
_cogl_context_set_current_modelview_entry(CoglContext * context,CoglMatrixEntry * entry)455 _cogl_context_set_current_modelview_entry (CoglContext *context,
456                                            CoglMatrixEntry *entry)
457 {
458   cogl_matrix_entry_ref (entry);
459   if (context->current_modelview_entry)
460     cogl_matrix_entry_unref (context->current_modelview_entry);
461   context->current_modelview_entry = entry;
462 }
463 
464 CoglGraphicsResetStatus
cogl_get_graphics_reset_status(CoglContext * context)465 cogl_get_graphics_reset_status (CoglContext *context)
466 {
467   return context->driver_vtable->get_graphics_reset_status (context);
468 }
469 
470 gboolean
cogl_context_is_hardware_accelerated(CoglContext * context)471 cogl_context_is_hardware_accelerated (CoglContext *context)
472 {
473   return context->driver_vtable->is_hardware_accelerated (context);
474 }
475 
476 gboolean
cogl_context_format_supports_upload(CoglContext * ctx,CoglPixelFormat format)477 cogl_context_format_supports_upload (CoglContext *ctx,
478                                      CoglPixelFormat format)
479 {
480   return ctx->texture_driver->format_supports_upload (ctx, format);
481 }
482 
483 void
cogl_context_set_named_pipeline(CoglContext * context,CoglPipelineKey * key,CoglPipeline * pipeline)484 cogl_context_set_named_pipeline (CoglContext     *context,
485                                  CoglPipelineKey *key,
486                                  CoglPipeline    *pipeline)
487 {
488   if (pipeline)
489     {
490       g_debug ("Adding named pipeline %s", *key);
491       g_hash_table_insert (context->named_pipelines, (gpointer) key, pipeline);
492     }
493   else
494     {
495       g_debug ("Removing named pipeline %s", *key);
496       g_hash_table_remove (context->named_pipelines, (gpointer) key);
497     }
498 }
499 
500 CoglPipeline *
cogl_context_get_named_pipeline(CoglContext * context,CoglPipelineKey * key)501 cogl_context_get_named_pipeline (CoglContext     *context,
502                                  CoglPipelineKey *key)
503 {
504   return g_hash_table_lookup (context->named_pipelines, key);
505 }
506 
507 void
cogl_context_free_timestamp_query(CoglContext * context,CoglTimestampQuery * query)508 cogl_context_free_timestamp_query (CoglContext        *context,
509                                    CoglTimestampQuery *query)
510 {
511   context->driver_vtable->free_timestamp_query (context, query);
512 }
513 
514 int64_t
cogl_context_timestamp_query_get_time_ns(CoglContext * context,CoglTimestampQuery * query)515 cogl_context_timestamp_query_get_time_ns (CoglContext        *context,
516                                           CoglTimestampQuery *query)
517 {
518   return context->driver_vtable->timestamp_query_get_time_ns (context, query);
519 }
520 
521 int64_t
cogl_context_get_gpu_time_ns(CoglContext * context)522 cogl_context_get_gpu_time_ns (CoglContext *context)
523 {
524   g_return_val_if_fail (cogl_has_feature (context,
525                                           COGL_FEATURE_ID_GET_GPU_TIME),
526                         0);
527 
528   return context->driver_vtable->get_gpu_time_ns (context);
529 }
530