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 <string.h>
20 
21 #include "gdkglx.h"
22 #include "gdkglprivate-x11.h"
23 #include "gdkglconfig-x11.h"
24 #include "gdkglcontext-x11.h"
25 #include "gdkglpixmap-x11.h"
26 
27 static gboolean     gdk_gl_pixmap_impl_x11_make_context_current (GdkGLDrawable *draw,
28                                                                  GdkGLDrawable *read,
29                                                                  GdkGLContext  *glcontext);
30 static gboolean     gdk_gl_pixmap_impl_x11_is_double_buffered   (GdkGLDrawable *gldrawable);
31 static void         gdk_gl_pixmap_impl_x11_swap_buffers         (GdkGLDrawable *gldrawable);
32 /*
33 static gboolean     gdk_gl_pixmap_impl_x11_gl_begin             (GdkGLDrawable *draw,
34                                                                  GdkGLDrawable *read,
35                                                                  GdkGLContext  *glcontext);
36 */
37 static void         gdk_gl_pixmap_impl_x11_gl_end               (GdkGLDrawable *gldrawable);
38 static GdkGLConfig *gdk_gl_pixmap_impl_x11_get_gl_config        (GdkGLDrawable *gldrawable);
39 
40 static void gdk_gl_pixmap_impl_x11_class_init (GdkGLPixmapImplX11Class *klass);
41 static void gdk_gl_pixmap_impl_x11_finalize   (GObject                 *object);
42 static void gdk_gl_pixmap_impl_x11_gl_drawable_interface_init (GdkGLDrawableClass *iface);
43 
44 static gpointer parent_class = NULL;
45 
46 GType
gdk_gl_pixmap_impl_x11_get_type(void)47 gdk_gl_pixmap_impl_x11_get_type (void)
48 {
49   static GType type = 0;
50 
51   if (!type)
52     {
53       static const GTypeInfo type_info = {
54         sizeof (GdkGLPixmapImplX11Class),
55         (GBaseInitFunc) NULL,
56         (GBaseFinalizeFunc) NULL,
57         (GClassInitFunc) gdk_gl_pixmap_impl_x11_class_init,
58         (GClassFinalizeFunc) NULL,
59         NULL,                   /* class_data */
60         sizeof (GdkGLPixmapImplX11),
61         0,                      /* n_preallocs */
62         (GInstanceInitFunc) NULL
63       };
64       static const GInterfaceInfo gl_drawable_interface_info = {
65         (GInterfaceInitFunc) gdk_gl_pixmap_impl_x11_gl_drawable_interface_init,
66         (GInterfaceFinalizeFunc) NULL,
67         NULL                    /* interface_data */
68       };
69 
70       type = g_type_register_static (GDK_TYPE_GL_PIXMAP,
71                                      "GdkGLPixmapImplX11",
72                                      &type_info, 0);
73       g_type_add_interface_static (type,
74                                    GDK_TYPE_GL_DRAWABLE,
75                                    &gl_drawable_interface_info);
76     }
77 
78   return type;
79 }
80 
81 static void
gdk_gl_pixmap_impl_x11_class_init(GdkGLPixmapImplX11Class * klass)82 gdk_gl_pixmap_impl_x11_class_init (GdkGLPixmapImplX11Class *klass)
83 {
84   GObjectClass *object_class = G_OBJECT_CLASS (klass);
85 
86   GDK_GL_NOTE_FUNC_PRIVATE ();
87 
88   parent_class = g_type_class_peek_parent (klass);
89 
90   object_class->finalize = gdk_gl_pixmap_impl_x11_finalize;
91 }
92 
93 void
_gdk_gl_pixmap_destroy(GdkGLPixmap * glpixmap)94 _gdk_gl_pixmap_destroy (GdkGLPixmap *glpixmap)
95 {
96   GdkGLPixmapImplX11 *impl = GDK_GL_PIXMAP_IMPL_X11 (glpixmap);
97   Display *xdisplay;
98 
99   GDK_GL_NOTE_FUNC_PRIVATE ();
100 
101   if (impl->is_destroyed)
102     return;
103 
104   xdisplay = GDK_GL_CONFIG_XDISPLAY (impl->glconfig);
105 
106   if (impl->glxpixmap == glXGetCurrentDrawable ())
107     {
108       glXWaitGL ();
109 
110       GDK_GL_NOTE_FUNC_IMPL ("glXMakeCurrent");
111       glXMakeCurrent (xdisplay, None, NULL);
112     }
113 
114   GDK_GL_NOTE_FUNC_IMPL ("glXDestroyGLXPixmap");
115   glXDestroyGLXPixmap (xdisplay, impl->glxpixmap);
116 
117   impl->glxpixmap = None;
118 
119   impl->is_destroyed = TRUE;
120 }
121 
122 static void
gdk_gl_pixmap_impl_x11_finalize(GObject * object)123 gdk_gl_pixmap_impl_x11_finalize (GObject *object)
124 {
125   GdkGLPixmapImplX11 *impl = GDK_GL_PIXMAP_IMPL_X11 (object);
126 
127   GDK_GL_NOTE_FUNC_PRIVATE ();
128 
129   _gdk_gl_pixmap_destroy (GDK_GL_PIXMAP (object));
130 
131   g_object_unref (G_OBJECT (impl->glconfig));
132 
133   G_OBJECT_CLASS (parent_class)->finalize (object);
134 }
135 
136 static void
gdk_gl_pixmap_impl_x11_gl_drawable_interface_init(GdkGLDrawableClass * iface)137 gdk_gl_pixmap_impl_x11_gl_drawable_interface_init (GdkGLDrawableClass *iface)
138 {
139   GDK_GL_NOTE_FUNC_PRIVATE ();
140 
141   iface->create_new_context   = _gdk_x11_gl_context_new;
142   iface->make_context_current =  gdk_gl_pixmap_impl_x11_make_context_current;
143   iface->is_double_buffered   =  gdk_gl_pixmap_impl_x11_is_double_buffered;
144   iface->swap_buffers         =  gdk_gl_pixmap_impl_x11_swap_buffers;
145   iface->wait_gl              = _gdk_gl_drawable_impl_x11_wait_gl;
146   iface->wait_gdk             = _gdk_gl_drawable_impl_x11_wait_gdk;
147   iface->gl_begin             =  gdk_gl_pixmap_impl_x11_make_context_current;
148   iface->gl_end               =  gdk_gl_pixmap_impl_x11_gl_end;
149   iface->get_gl_config        =  gdk_gl_pixmap_impl_x11_get_gl_config;
150   iface->get_size             = _gdk_gl_pixmap_get_size;
151 }
152 
153 /**
154  * gdk_gl_pixmap_new:
155  * @glconfig: a #GdkGLConfig.
156  * @pixmap: the #GdkPixmap to be used as the rendering area.
157  * @attrib_list: this must be set to NULL or empty (first attribute of None).
158  *
159  * Creates an off-screen rendering area.
160  * attrib_list is currently unused. This must be set to NULL or empty
161  * (first attribute of None). See GLX 1.3 spec.
162  *
163  * Return value: the new #GdkGLPixmap.
164  **/
165 GdkGLPixmap *
gdk_gl_pixmap_new(GdkGLConfig * glconfig,GdkPixmap * pixmap,const int * attrib_list)166 gdk_gl_pixmap_new (GdkGLConfig *glconfig,
167                    GdkPixmap   *pixmap,
168                    const int   *attrib_list)
169 {
170   GdkGLPixmap *glpixmap;
171   GdkGLPixmapImplX11 *impl;
172 
173   Display *xdisplay;
174   XVisualInfo *xvinfo;
175   Pixmap xpixmap;
176   GLXPixmap glxpixmap;
177 
178   Window root_return;
179   int x_return, y_return;
180   unsigned int width_return, height_return;
181   unsigned int border_width_return;
182   unsigned int depth_return;
183 
184   GdkGL_GLX_MESA_pixmap_colormap *mesa_ext;
185 
186   GDK_GL_NOTE_FUNC ();
187 
188   g_return_val_if_fail (GDK_IS_GL_CONFIG_IMPL_X11 (glconfig), NULL);
189   g_return_val_if_fail (GDK_IS_PIXMAP (pixmap), NULL);
190 
191   xdisplay = GDK_GL_CONFIG_XDISPLAY (glconfig);
192   xvinfo = GDK_GL_CONFIG_XVINFO (glconfig);
193 
194   /*
195    * Get X Pixmap.
196    */
197 
198   xpixmap = GDK_DRAWABLE_XID (GDK_DRAWABLE (pixmap));
199 
200   /*
201    * Check depth of the X pixmap.
202    */
203 
204   if (!XGetGeometry (xdisplay, xpixmap,
205                      &root_return,
206                      &x_return, &y_return,
207                      &width_return, &height_return,
208                      &border_width_return,
209                      &depth_return))
210     return NULL;
211 
212   if (depth_return != (unsigned int) xvinfo->depth)
213     return NULL;
214 
215   /*
216    * Create GLXPixmap.
217    */
218 
219   mesa_ext = gdk_gl_get_GLX_MESA_pixmap_colormap (glconfig);
220   if (mesa_ext)
221     {
222       /* If GLX_MESA_pixmap_colormap is supported. */
223 
224       GDK_GL_NOTE_FUNC_IMPL ("glXCreateGLXPixmapMESA");
225 
226       glxpixmap = mesa_ext->glXCreateGLXPixmapMESA (xdisplay,
227                                                     xvinfo,
228                                                     xpixmap,
229                                                     GDK_GL_CONFIG_XCOLORMAP (glconfig));
230     }
231   else
232     {
233       GDK_GL_NOTE_FUNC_IMPL ("glXCreateGLXPixmap");
234 
235       glxpixmap = glXCreateGLXPixmap (xdisplay,
236                                       xvinfo,
237                                       xpixmap);
238     }
239 
240   if (glxpixmap == None)
241     return NULL;
242 
243   /*
244    * Instantiate the GdkGLPixmapImplX11 object.
245    */
246 
247   glpixmap = g_object_new (GDK_TYPE_GL_PIXMAP_IMPL_X11, NULL);
248   impl = GDK_GL_PIXMAP_IMPL_X11 (glpixmap);
249 
250   glpixmap->drawable = GDK_DRAWABLE (pixmap);
251   g_object_add_weak_pointer (G_OBJECT (glpixmap->drawable),
252                              (gpointer *) &(glpixmap->drawable));
253 
254   impl->glxpixmap = glxpixmap;
255 
256   impl->glconfig = glconfig;
257   g_object_ref (G_OBJECT (impl->glconfig));
258 
259   impl->is_destroyed = FALSE;
260 
261   return glpixmap;
262 }
263 
264 static gboolean
gdk_gl_pixmap_impl_x11_make_context_current(GdkGLDrawable * draw,GdkGLDrawable * read,GdkGLContext * glcontext)265 gdk_gl_pixmap_impl_x11_make_context_current (GdkGLDrawable *draw,
266                                              GdkGLDrawable *read,
267                                              GdkGLContext  *glcontext)
268 {
269   GdkGLConfig *glconfig;
270   GLXPixmap glxpixmap;
271   GLXContext glxcontext;
272 
273   g_return_val_if_fail (GDK_IS_GL_PIXMAP_IMPL_X11 (draw), FALSE);
274   g_return_val_if_fail (GDK_IS_GL_CONTEXT_IMPL_X11 (glcontext), FALSE);
275 
276   glconfig = GDK_GL_PIXMAP_IMPL_X11 (draw)->glconfig;
277   glxpixmap = GDK_GL_PIXMAP_IMPL_X11 (draw)->glxpixmap;
278   glxcontext = GDK_GL_CONTEXT_GLXCONTEXT (glcontext);
279 
280   if (glxpixmap == None || glxcontext == NULL)
281     return FALSE;
282 
283 #ifdef GDKGLEXT_MULTIHEAD_SUPPORT
284   GDK_GL_NOTE (MISC,
285     g_message (" -- Pixmap: screen number = %d",
286       GDK_SCREEN_XNUMBER (gdk_drawable_get_screen (GDK_DRAWABLE (draw)))));
287 #endif /* GDKGLEXT_MULTIHEAD_SUPPORT */
288   GDK_GL_NOTE (MISC,
289     g_message (" -- Pixmap: visual id = 0x%lx",
290       GDK_VISUAL_XVISUAL (gdk_drawable_get_visual (GDK_DRAWABLE (draw)))->visualid));
291 
292   GDK_GL_NOTE_FUNC_IMPL ("glXMakeCurrent");
293 
294   if (!glXMakeCurrent (GDK_GL_CONFIG_XDISPLAY (glconfig), glxpixmap, glxcontext))
295     {
296       g_warning ("glXMakeCurrent() failed");
297       _gdk_gl_context_set_gl_drawable (glcontext, NULL);
298       /* currently unused. */
299       /* _gdk_gl_context_set_gl_drawable_read (glcontext, NULL); */
300       return FALSE;
301     }
302 
303   _gdk_gl_context_set_gl_drawable (glcontext, draw);
304   /* currently unused. */
305   /* _gdk_gl_context_set_gl_drawable_read (glcontext, read); */
306 
307   if (_GDK_GL_CONFIG_AS_SINGLE_MODE (glconfig))
308     {
309       /* We do this because we are treating a double-buffered frame
310          buffer as a single-buffered frame buffer because the system
311          does not appear to export any suitable single-buffered
312          visuals (in which the following are necessary). */
313       glDrawBuffer (GL_FRONT);
314       glReadBuffer (GL_FRONT);
315     }
316 
317   GDK_GL_NOTE (MISC, _gdk_gl_print_gl_info ());
318 
319   return TRUE;
320 }
321 
322 static gboolean
gdk_gl_pixmap_impl_x11_is_double_buffered(GdkGLDrawable * gldrawable)323 gdk_gl_pixmap_impl_x11_is_double_buffered (GdkGLDrawable *gldrawable)
324 {
325   g_return_val_if_fail (GDK_IS_GL_PIXMAP_IMPL_X11 (gldrawable), FALSE);
326 
327   return gdk_gl_config_is_double_buffered (GDK_GL_PIXMAP_IMPL_X11 (gldrawable)->glconfig);
328 }
329 
330 static void
gdk_gl_pixmap_impl_x11_swap_buffers(GdkGLDrawable * gldrawable)331 gdk_gl_pixmap_impl_x11_swap_buffers (GdkGLDrawable *gldrawable)
332 {
333   Display *xdisplay;
334   GLXPixmap glxpixmap;
335 
336   g_return_if_fail (GDK_IS_GL_PIXMAP_IMPL_X11 (gldrawable));
337 
338   xdisplay = GDK_GL_CONFIG_XDISPLAY (GDK_GL_PIXMAP_IMPL_X11 (gldrawable)->glconfig);
339   glxpixmap = GDK_GL_PIXMAP_IMPL_X11 (gldrawable)->glxpixmap;
340 
341   if (glxpixmap == None)
342     return;
343 
344   GDK_GL_NOTE_FUNC_IMPL ("glXSwapBuffers");
345 
346   glXSwapBuffers (xdisplay, glxpixmap);
347 }
348 
349 /*
350 static gboolean
351 gdk_gl_pixmap_impl_x11_gl_begin (GdkGLDrawable *draw,
352                                  GdkGLDrawable *read,
353                                  GdkGLContext  *glcontext)
354 {
355   return gdk_gl_pixmap_impl_x11_make_context_current (draw, read, glcontext);
356 }
357 */
358 
359 static void
gdk_gl_pixmap_impl_x11_gl_end(GdkGLDrawable * gldrawable)360 gdk_gl_pixmap_impl_x11_gl_end (GdkGLDrawable *gldrawable)
361 {
362   /* do nothing */
363 }
364 
365 static GdkGLConfig *
gdk_gl_pixmap_impl_x11_get_gl_config(GdkGLDrawable * gldrawable)366 gdk_gl_pixmap_impl_x11_get_gl_config (GdkGLDrawable *gldrawable)
367 {
368   g_return_val_if_fail (GDK_IS_GL_PIXMAP_IMPL_X11 (gldrawable), NULL);
369 
370   return GDK_GL_PIXMAP_IMPL_X11 (gldrawable)->glconfig;
371 }
372 
373 /**
374  * gdk_x11_gl_pixmap_get_glxpixmap:
375  * @glpixmap: a #GdkGLPixmap.
376  *
377  * Gets GLXPixmap.
378  *
379  * Return value: the GLXPixmap.
380  **/
381 GLXPixmap
gdk_x11_gl_pixmap_get_glxpixmap(GdkGLPixmap * glpixmap)382 gdk_x11_gl_pixmap_get_glxpixmap (GdkGLPixmap *glpixmap)
383 {
384   g_return_val_if_fail (GDK_IS_GL_PIXMAP_IMPL_X11 (glpixmap), None);
385 
386   return GDK_GL_PIXMAP_IMPL_X11 (glpixmap)->glxpixmap;
387 }
388