1 /* GdkGLExt - OpenGL Extension to GDK
2  * Copyright (C) 2002-2004  Naofumi Yasufuku
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA.
17  */
18 
19 #include <gdk/gdk.h>            /* for gdk_error_trap_(push|pop) () */
20 
21 #include "gdkglx.h"
22 #include "gdkglprivate-x11.h"
23 #include "gdkgldrawable.h"
24 #include "gdkglconfig-x11.h"
25 #include "gdkglcontext-x11.h"
26 
27 static void          gdk_gl_context_insert (GdkGLContext *glcontext);
28 static void          gdk_gl_context_remove (GdkGLContext *glcontext);
29 static GdkGLContext *gdk_gl_context_lookup (GLXContext    glxcontext);
30 static guint         gdk_gl_context_hash   (GLXContext   *glxcontext);
31 static gboolean      gdk_gl_context_equal  (GLXContext   *a,
32                                             GLXContext   *b);
33 
34 static void gdk_gl_context_impl_x11_class_init (GdkGLContextImplX11Class *klass);
35 static void gdk_gl_context_impl_x11_finalize   (GObject                  *object);
36 
37 static gpointer parent_class = NULL;
38 
39 GType
gdk_gl_context_impl_x11_get_type(void)40 gdk_gl_context_impl_x11_get_type (void)
41 {
42   static GType type = 0;
43 
44   if (!type)
45     {
46       static const GTypeInfo type_info = {
47         sizeof (GdkGLContextImplX11Class),
48         (GBaseInitFunc) NULL,
49         (GBaseFinalizeFunc) NULL,
50         (GClassInitFunc) gdk_gl_context_impl_x11_class_init,
51         (GClassFinalizeFunc) NULL,
52         NULL,                   /* class_data */
53         sizeof (GdkGLContextImplX11),
54         0,                      /* n_preallocs */
55         (GInstanceInitFunc) NULL
56       };
57 
58       type = g_type_register_static (GDK_TYPE_GL_CONTEXT,
59                                      "GdkGLContextImplX11",
60                                      &type_info, 0);
61     }
62 
63   return type;
64 }
65 
66 static void
gdk_gl_context_impl_x11_class_init(GdkGLContextImplX11Class * klass)67 gdk_gl_context_impl_x11_class_init (GdkGLContextImplX11Class *klass)
68 {
69   GObjectClass *object_class = G_OBJECT_CLASS (klass);
70 
71   GDK_GL_NOTE_FUNC_PRIVATE ();
72 
73   parent_class = g_type_class_peek_parent (klass);
74 
75   object_class->finalize = gdk_gl_context_impl_x11_finalize;
76 }
77 
78 void
_gdk_gl_context_destroy(GdkGLContext * glcontext)79 _gdk_gl_context_destroy (GdkGLContext *glcontext)
80 {
81   GdkGLContextImplX11 *impl = GDK_GL_CONTEXT_IMPL_X11 (glcontext);
82   Display *xdisplay;
83 
84   GDK_GL_NOTE_FUNC_PRIVATE ();
85 
86   if (impl->is_destroyed)
87     return;
88 
89   gdk_gl_context_remove (glcontext);
90 
91   xdisplay = GDK_GL_CONFIG_XDISPLAY (impl->glconfig);
92 
93   if (impl->glxcontext == glXGetCurrentContext ())
94     {
95       glXWaitGL ();
96 
97       GDK_GL_NOTE_FUNC_IMPL ("glXMakeCurrent");
98       glXMakeCurrent (xdisplay, None, NULL);
99     }
100 
101   if (!impl->is_foreign)
102     {
103       GDK_GL_NOTE_FUNC_IMPL ("glXDestroyContext");
104       glXDestroyContext (xdisplay, impl->glxcontext);
105       impl->glxcontext = NULL;
106     }
107 
108   if (impl->gldrawable != NULL)
109     {
110       g_object_remove_weak_pointer (G_OBJECT (impl->gldrawable),
111                                     (gpointer *) &(impl->gldrawable));
112       impl->gldrawable = NULL;
113     }
114 
115   /* currently unused. */
116   /*
117   if (impl->gldrawable_read != NULL)
118     {
119       g_object_remove_weak_pointer (G_OBJECT (impl->gldrawable_read),
120                                     (gpointer *) &(impl->gldrawable_read));
121       impl->gldrawable_read = NULL;
122     }
123   */
124 
125   impl->is_destroyed = TRUE;
126 }
127 
128 static void
gdk_gl_context_impl_x11_finalize(GObject * object)129 gdk_gl_context_impl_x11_finalize (GObject *object)
130 {
131   GdkGLContextImplX11 *impl = GDK_GL_CONTEXT_IMPL_X11 (object);
132 
133   GDK_GL_NOTE_FUNC_PRIVATE ();
134 
135   _gdk_gl_context_destroy (GDK_GL_CONTEXT (object));
136 
137   g_object_unref (G_OBJECT (impl->glconfig));
138 
139   if (impl->share_list != NULL)
140     g_object_unref (G_OBJECT (impl->share_list));
141 
142   G_OBJECT_CLASS (parent_class)->finalize (object);
143 }
144 
145 static GdkGLContext *
gdk_gl_context_new_common(GdkGLConfig * glconfig,GdkGLContext * share_list,int render_type,GLXContext glxcontext,gboolean is_foreign)146 gdk_gl_context_new_common (GdkGLConfig   *glconfig,
147                            GdkGLContext  *share_list,
148                            int            render_type,
149                            GLXContext     glxcontext,
150                            gboolean       is_foreign)
151 {
152   GdkGLContext *glcontext;
153   GdkGLContextImplX11 *impl;
154 
155   Display *xdisplay;
156 
157   GDK_GL_NOTE_FUNC_PRIVATE ();
158 
159   /*
160    * Instantiate the GdkGLContextImplX11 object.
161    */
162 
163   glcontext = g_object_new (GDK_TYPE_GL_CONTEXT_IMPL_X11, NULL);
164   impl = GDK_GL_CONTEXT_IMPL_X11 (glcontext);
165 
166   impl->glxcontext = glxcontext;
167 
168   if (share_list != NULL && GDK_IS_GL_CONTEXT (share_list))
169     {
170       impl->share_list = share_list;
171       g_object_ref (G_OBJECT (impl->share_list));
172     }
173   else
174     {
175       impl->share_list = NULL;
176     }
177 
178   xdisplay = GDK_GL_CONFIG_XDISPLAY (glconfig);
179   impl->is_direct = glXIsDirect (xdisplay, glxcontext) ? TRUE : FALSE;
180 
181   impl->render_type = render_type;
182 
183   impl->glconfig = glconfig;
184   g_object_ref (G_OBJECT (impl->glconfig));
185 
186   impl->gldrawable = NULL;
187   impl->gldrawable_read = NULL;
188 
189   impl->is_foreign = is_foreign;
190 
191   impl->is_destroyed = FALSE;
192 
193   /*
194    * Insert into the GL context hash table.
195    */
196 
197   gdk_gl_context_insert (glcontext);
198 
199   return glcontext;
200 }
201 
202 /*< private >*/
203 GdkGLContext *
_gdk_x11_gl_context_new(GdkGLDrawable * gldrawable,GdkGLContext * share_list,gboolean direct,int render_type)204 _gdk_x11_gl_context_new (GdkGLDrawable *gldrawable,
205                          GdkGLContext  *share_list,
206                          gboolean       direct,
207                          int            render_type)
208 {
209   GdkGLConfig *glconfig;
210   GdkGLContextImplX11 *share_impl = NULL;
211   GLXContext share_glxcontext = NULL;
212 
213   Display *xdisplay;
214   XVisualInfo *xvinfo;
215   GLXContext glxcontext;
216 
217   GDK_GL_NOTE_FUNC_PRIVATE ();
218 
219   /*
220    * Create an OpenGL rendering context.
221    */
222 
223   glconfig = gdk_gl_drawable_get_gl_config (gldrawable);
224 
225   xdisplay = GDK_GL_CONFIG_XDISPLAY (glconfig);
226   xvinfo = GDK_GL_CONFIG_XVINFO (glconfig);
227 
228   if (share_list != NULL && GDK_IS_GL_CONTEXT (share_list))
229     {
230       share_impl = GDK_GL_CONTEXT_IMPL_X11 (share_list);
231       share_glxcontext = share_impl->glxcontext;
232     }
233 
234   GDK_GL_NOTE_FUNC_IMPL ("glXCreateContext");
235 
236   if (_gdk_gl_context_force_indirect)
237     {
238       GDK_GL_NOTE (MISC, g_message (" -- Force indirect"));
239 
240       glxcontext = glXCreateContext (xdisplay,
241                                      xvinfo,
242                                      share_glxcontext,
243                                      False);
244     }
245   else
246     {
247       glxcontext = glXCreateContext (xdisplay,
248                                      xvinfo,
249                                      share_glxcontext,
250                                      (direct == TRUE) ? True : False);
251     }
252   if (glxcontext == NULL)
253     return NULL;
254 
255   GDK_GL_NOTE (MISC,
256     g_message (" -- Context: screen number = %d", xvinfo->screen));
257   GDK_GL_NOTE (MISC,
258     g_message (" -- Context: visual id = 0x%lx", xvinfo->visualid));
259 
260   /*
261    * Instantiate the GdkGLContextImplX11 object.
262    */
263 
264   return gdk_gl_context_new_common (glconfig,
265                                     share_list,
266                                     render_type,
267                                     glxcontext,
268                                     FALSE);
269 }
270 
271 /**
272  * gdk_x11_gl_context_foreign_new:
273  * @glconfig: #GdkGLConfig that represents the visual the GLXContext uses.
274  * @share_list: the #GdkGLContext which shares display lists with the
275  *              GLXContext, or NULL.
276  * @glxcontext: exsisting GLXContext.
277  *
278  * Creates #GdkGLContext from existing GLXContext.
279  *
280  * Return value: the newly-created #GdkGLContext wrapper.
281  **/
282 GdkGLContext *
gdk_x11_gl_context_foreign_new(GdkGLConfig * glconfig,GdkGLContext * share_list,GLXContext glxcontext)283 gdk_x11_gl_context_foreign_new (GdkGLConfig  *glconfig,
284                                 GdkGLContext *share_list,
285                                 GLXContext    glxcontext)
286 {
287   GDK_GL_NOTE_FUNC ();
288 
289   g_return_val_if_fail (GDK_IS_GL_CONFIG_IMPL_X11 (glconfig), NULL);
290   g_return_val_if_fail (glxcontext != NULL, NULL);
291 
292   /*
293    * Instantiate the GdkGLContextImplX11 object.
294    */
295 
296   return gdk_gl_context_new_common (glconfig,
297                                     share_list,
298                                     (glconfig->is_rgba) ? GDK_GL_RGBA_TYPE : GDK_GL_COLOR_INDEX_TYPE,
299                                     glxcontext,
300                                     TRUE);
301 }
302 
303 /**
304  * gdk_gl_context_copy:
305  * @glcontext: a #GdkGLContext.
306  * @src: the source context.
307  * @mask: which portions of @src state are to be copied to @glcontext.
308  *
309  * Copy state from @src rendering context to @glcontext.
310  *
311  * @mask contains the bitwise-OR of the same symbolic names that are passed to
312  * the glPushAttrib() function. You can use GL_ALL_ATTRIB_BITS to copy all the
313  * rendering state information.
314  *
315  * Return value: FALSE if it fails, TRUE otherwise.
316  **/
317 gboolean
gdk_gl_context_copy(GdkGLContext * glcontext,GdkGLContext * src,unsigned long mask)318 gdk_gl_context_copy (GdkGLContext  *glcontext,
319                      GdkGLContext  *src,
320                      unsigned long  mask)
321 {
322   GLXContext dst_glxcontext, src_glxcontext;
323   GdkGLConfig *glconfig;
324 
325   GDK_GL_NOTE_FUNC ();
326 
327   g_return_val_if_fail (GDK_IS_GL_CONTEXT_IMPL_X11 (glcontext), FALSE);
328   g_return_val_if_fail (GDK_IS_GL_CONTEXT_IMPL_X11 (src), FALSE);
329 
330   dst_glxcontext = GDK_GL_CONTEXT_GLXCONTEXT (glcontext);
331   if (dst_glxcontext == NULL)
332     return FALSE;
333 
334   src_glxcontext = GDK_GL_CONTEXT_GLXCONTEXT (src);
335   if (src_glxcontext == NULL)
336     return FALSE;
337 
338   glconfig = GDK_GL_CONTEXT_IMPL_X11 (glcontext)->glconfig;
339 
340   gdk_error_trap_push ();
341 
342   glXCopyContext (GDK_GL_CONFIG_XDISPLAY (glconfig),
343                   src_glxcontext, dst_glxcontext,
344                   mask);
345 
346   return gdk_error_trap_pop () == Success;
347 }
348 
349 /*< private >*/
350 void
_gdk_gl_context_set_gl_drawable(GdkGLContext * glcontext,GdkGLDrawable * gldrawable)351 _gdk_gl_context_set_gl_drawable (GdkGLContext  *glcontext,
352                                  GdkGLDrawable *gldrawable)
353 {
354   GdkGLContextImplX11 *impl = GDK_GL_CONTEXT_IMPL_X11 (glcontext);
355 
356   GDK_GL_NOTE_FUNC_PRIVATE ();
357 
358   if (impl->gldrawable == gldrawable)
359     return;
360 
361   if (impl->gldrawable != NULL)
362     {
363       g_object_remove_weak_pointer (G_OBJECT (impl->gldrawable),
364                                     (gpointer *) &(impl->gldrawable));
365       impl->gldrawable = NULL;
366     }
367 
368   if (gldrawable != NULL && GDK_IS_GL_DRAWABLE (gldrawable))
369     {
370       impl->gldrawable = gldrawable;
371       g_object_add_weak_pointer (G_OBJECT (impl->gldrawable),
372                                  (gpointer *) &(impl->gldrawable));
373     }
374 }
375 
376 /*< private >*/
377 /* currently unused. */
378 /*
379 void
380 _gdk_gl_context_set_gl_drawable_read (GdkGLContext  *glcontext,
381                                       GdkGLDrawable *gldrawable_read)
382 {
383   GdkGLContextImplX11 *impl = GDK_GL_CONTEXT_IMPL_X11 (glcontext);
384 
385   GDK_GL_NOTE_FUNC_PRIVATE ();
386 
387   if (impl->gldrawable_read == gldrawable_read)
388     return;
389 
390   if (impl->gldrawable_read != NULL)
391     {
392       g_object_remove_weak_pointer (G_OBJECT (impl->gldrawable_read),
393                                     (gpointer *) &(impl->gldrawable_read));
394       impl->gldrawable_read = NULL;
395     }
396 
397   if (gldrawable_read != NULL && GDK_IS_GL_DRAWABLE (gldrawable_read))
398     {
399       impl->gldrawable_read = gldrawable_read;
400       g_object_add_weak_pointer (G_OBJECT (impl->gldrawable_read),
401                                  (gpointer *) &(impl->gldrawable_read));
402     }
403 }
404 */
405 
406 /**
407  * gdk_gl_context_get_gl_drawable:
408  * @glcontext: a #GdkGLContext.
409  *
410  * Gets #GdkGLDrawable to which the @glcontext is bound.
411  *
412  * Return value: the #GdkGLDrawable or NULL if no #GdkGLDrawable is bound.
413  **/
414 GdkGLDrawable *
gdk_gl_context_get_gl_drawable(GdkGLContext * glcontext)415 gdk_gl_context_get_gl_drawable (GdkGLContext *glcontext)
416 {
417   g_return_val_if_fail (GDK_IS_GL_CONTEXT_IMPL_X11 (glcontext), NULL);
418 
419   return GDK_GL_CONTEXT_IMPL_X11 (glcontext)->gldrawable;
420 }
421 
422 /**
423  * gdk_gl_context_get_gl_config:
424  * @glcontext: a #GdkGLContext.
425  *
426  * Gets #GdkGLConfig with which the @glcontext is configured.
427  *
428  * Return value: the #GdkGLConfig.
429  **/
430 GdkGLConfig *
gdk_gl_context_get_gl_config(GdkGLContext * glcontext)431 gdk_gl_context_get_gl_config (GdkGLContext *glcontext)
432 {
433   g_return_val_if_fail (GDK_IS_GL_CONTEXT_IMPL_X11 (glcontext), NULL);
434 
435   return GDK_GL_CONTEXT_IMPL_X11 (glcontext)->glconfig;
436 }
437 
438 /**
439  * gdk_gl_context_get_share_list:
440  * @glcontext: a #GdkGLContext.
441  *
442  * Gets #GdkGLContext with which the @glcontext shares the display lists and
443  * texture objects.
444  *
445  * Return value: the #GdkGLContext.
446  **/
447 GdkGLContext *
gdk_gl_context_get_share_list(GdkGLContext * glcontext)448 gdk_gl_context_get_share_list (GdkGLContext *glcontext)
449 {
450   g_return_val_if_fail (GDK_IS_GL_CONTEXT_IMPL_X11 (glcontext), NULL);
451 
452   return GDK_GL_CONTEXT_IMPL_X11 (glcontext)->share_list;
453 }
454 
455 /**
456  * gdk_gl_context_is_direct:
457  * @glcontext: a #GdkGLContext.
458  *
459  * Returns whether the @glcontext is a direct rendering context.
460  *
461  * Return value: TRUE if the @glcontext is a direct rendering contest.
462  **/
463 gboolean
gdk_gl_context_is_direct(GdkGLContext * glcontext)464 gdk_gl_context_is_direct (GdkGLContext *glcontext)
465 {
466   g_return_val_if_fail (GDK_IS_GL_CONTEXT_IMPL_X11 (glcontext), FALSE);
467 
468   return GDK_GL_CONTEXT_IMPL_X11 (glcontext)->is_direct;
469 }
470 
471 /**
472  * gdk_gl_context_get_render_type:
473  * @glcontext: a #GdkGLContext.
474  *
475  * Gets render_type of the @glcontext.
476  *
477  * Return value: GDK_GL_RGBA_TYPE or GDK_GL_COLOR_INDEX_TYPE.
478  **/
479 int
gdk_gl_context_get_render_type(GdkGLContext * glcontext)480 gdk_gl_context_get_render_type (GdkGLContext *glcontext)
481 {
482   g_return_val_if_fail (GDK_IS_GL_CONTEXT_IMPL_X11 (glcontext), 0);
483 
484   return GDK_GL_CONTEXT_IMPL_X11 (glcontext)->render_type;
485 }
486 
487 /**
488  * gdk_gl_context_get_current:
489  *
490  * Returns the current #GdkGLContext.
491  *
492  * Return value: the current #GdkGLContext or NULL if there is no current
493  *               context.
494  **/
495 GdkGLContext *
gdk_gl_context_get_current(void)496 gdk_gl_context_get_current (void)
497 {
498   static GdkGLContext *current = NULL;
499   GLXContext glxcontext;
500 
501   GDK_GL_NOTE_FUNC ();
502 
503   glxcontext = glXGetCurrentContext ();
504 
505   if (glxcontext == NULL)
506     return NULL;
507 
508   if (current && GDK_GL_CONTEXT_GLXCONTEXT (current) == glxcontext)
509     return current;
510 
511   current = gdk_gl_context_lookup (glxcontext);
512 
513   return current;
514 }
515 
516 /**
517  * gdk_x11_gl_context_get_glxcontext:
518  * @glcontext: a #GdkGLContext.
519  *
520  * Gets GLXContext.
521  *
522  * Return value: the GLXContext.
523  **/
524 GLXContext
gdk_x11_gl_context_get_glxcontext(GdkGLContext * glcontext)525 gdk_x11_gl_context_get_glxcontext (GdkGLContext *glcontext)
526 {
527   g_return_val_if_fail (GDK_IS_GL_CONTEXT_IMPL_X11 (glcontext), NULL);
528 
529   return GDK_GL_CONTEXT_IMPL_X11 (glcontext)->glxcontext;
530 }
531 
532 /*
533  * GdkGLContext hash table.
534  */
535 
536 static GHashTable *gl_context_ht = NULL;
537 
538 static void
gdk_gl_context_insert(GdkGLContext * glcontext)539 gdk_gl_context_insert (GdkGLContext *glcontext)
540 {
541   GdkGLContextImplX11 *impl;
542 
543   GDK_GL_NOTE_FUNC_PRIVATE ();
544 
545   if (gl_context_ht == NULL)
546     {
547       GDK_GL_NOTE (MISC, g_message (" -- Create GL context hash table."));
548       gl_context_ht = g_hash_table_new ((GHashFunc) gdk_gl_context_hash,
549                                         (GEqualFunc) gdk_gl_context_equal);
550     }
551 
552   impl = GDK_GL_CONTEXT_IMPL_X11 (glcontext);
553 
554   g_hash_table_insert (gl_context_ht, &(impl->glxcontext), glcontext);
555 }
556 
557 static void
gdk_gl_context_remove(GdkGLContext * glcontext)558 gdk_gl_context_remove (GdkGLContext *glcontext)
559 {
560   GdkGLContextImplX11 *impl;
561 
562   GDK_GL_NOTE_FUNC_PRIVATE ();
563 
564   if (gl_context_ht == NULL)
565     return;
566 
567   impl = GDK_GL_CONTEXT_IMPL_X11 (glcontext);
568 
569   g_hash_table_remove (gl_context_ht, &(impl->glxcontext));
570 
571   if (g_hash_table_size (gl_context_ht) == 0)
572     {
573       GDK_GL_NOTE (MISC, g_message (" -- Destroy GL context hash table."));
574       g_hash_table_destroy (gl_context_ht);
575       gl_context_ht = NULL;
576     }
577 }
578 
579 static GdkGLContext *
gdk_gl_context_lookup(GLXContext glxcontext)580 gdk_gl_context_lookup (GLXContext glxcontext)
581 {
582   GDK_GL_NOTE_FUNC_PRIVATE ();
583 
584   if (gl_context_ht == NULL)
585     return NULL;
586 
587   return g_hash_table_lookup (gl_context_ht, &glxcontext);
588 }
589 
590 static guint
gdk_gl_context_hash(GLXContext * glxcontext)591 gdk_gl_context_hash (GLXContext *glxcontext)
592 {
593   return (guint) *glxcontext;
594 }
595 
596 static gboolean
gdk_gl_context_equal(GLXContext * a,GLXContext * b)597 gdk_gl_context_equal (GLXContext *a,
598                       GLXContext *b)
599 {
600   return (*a == *b);
601 }
602