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