Avoid direct access to the palette structure.
[wine] / dlls / x11drv / opengl.c
1 /*
2  * X11DRV OpenGL functions
3  *
4  * Copyright 2000 Lionel Ulmer
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "gdi.h"
28 #include "x11drv.h"
29 #include "wine/debug.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
32
33 #if defined(HAVE_GL_GL_H) && defined(HAVE_GL_GLX_H)
34
35 #undef APIENTRY
36 #undef CALLBACK
37 #undef WINAPI
38
39 #define XMD_H /* This is to prevent the Xmd.h inclusion bug :-/ */
40 #ifdef HAVE_GL_GL_H
41 # include <GL/gl.h>
42 #endif
43 #ifdef HAVE_GL_GLX_H
44 # include <GL/glx.h>
45 #endif
46 #ifdef HAVE_GL_GLEXT_H
47 # include <GL/glext.h>
48 #endif
49 #undef  XMD_H
50
51 #undef APIENTRY
52 #undef CALLBACK
53 #undef WINAPI
54
55 /* Redefines the constants */
56 #define CALLBACK    __stdcall
57 #define WINAPI      __stdcall
58 #define APIENTRY    WINAPI
59
60
61 static void dump_PIXELFORMATDESCRIPTOR(PIXELFORMATDESCRIPTOR *ppfd) {
62   DPRINTF("  - size / version : %d / %d\n", ppfd->nSize, ppfd->nVersion);
63   DPRINTF("  - dwFlags : ");
64 #define TEST_AND_DUMP(t,tv) if ((t) & (tv)) DPRINTF(#tv " ")
65   TEST_AND_DUMP(ppfd->dwFlags, PFD_DEPTH_DONTCARE);
66   TEST_AND_DUMP(ppfd->dwFlags, PFD_DOUBLEBUFFER);
67   TEST_AND_DUMP(ppfd->dwFlags, PFD_DOUBLEBUFFER_DONTCARE);
68   TEST_AND_DUMP(ppfd->dwFlags, PFD_DRAW_TO_WINDOW);
69   TEST_AND_DUMP(ppfd->dwFlags, PFD_DRAW_TO_BITMAP);
70   TEST_AND_DUMP(ppfd->dwFlags, PFD_GENERIC_ACCELERATED);
71   TEST_AND_DUMP(ppfd->dwFlags, PFD_GENERIC_FORMAT);
72   TEST_AND_DUMP(ppfd->dwFlags, PFD_NEED_PALETTE);
73   TEST_AND_DUMP(ppfd->dwFlags, PFD_NEED_SYSTEM_PALETTE);
74   TEST_AND_DUMP(ppfd->dwFlags, PFD_STEREO);
75   TEST_AND_DUMP(ppfd->dwFlags, PFD_STEREO_DONTCARE);
76   TEST_AND_DUMP(ppfd->dwFlags, PFD_SUPPORT_GDI);
77   TEST_AND_DUMP(ppfd->dwFlags, PFD_SUPPORT_OPENGL);
78   TEST_AND_DUMP(ppfd->dwFlags, PFD_SWAP_COPY);
79   TEST_AND_DUMP(ppfd->dwFlags, PFD_SWAP_EXCHANGE);
80   TEST_AND_DUMP(ppfd->dwFlags, PFD_SWAP_LAYER_BUFFERS);
81 #undef TEST_AND_DUMP
82   DPRINTF("\n");
83
84   DPRINTF("  - iPixelType : ");
85   switch (ppfd->iPixelType) {
86   case PFD_TYPE_RGBA: DPRINTF("PFD_TYPE_RGBA"); break;
87   case PFD_TYPE_COLORINDEX: DPRINTF("PFD_TYPE_COLORINDEX"); break;
88   }
89   DPRINTF("\n");
90
91   DPRINTF("  - Color   : %d\n", ppfd->cColorBits);
92   DPRINTF("  - Alpha   : %d\n", ppfd->cAlphaBits);
93   DPRINTF("  - Accum   : %d\n", ppfd->cAccumBits);
94   DPRINTF("  - Depth   : %d\n", ppfd->cDepthBits);
95   DPRINTF("  - Stencil : %d\n", ppfd->cStencilBits);
96   DPRINTF("  - Aux     : %d\n", ppfd->cAuxBuffers);
97
98   DPRINTF("  - iLayerType : ");
99   switch (ppfd->iLayerType) {
100   case PFD_MAIN_PLANE: DPRINTF("PFD_MAIN_PLANE"); break;
101   case PFD_OVERLAY_PLANE: DPRINTF("PFD_OVERLAY_PLANE"); break;
102   case PFD_UNDERLAY_PLANE: DPRINTF("PFD_UNDERLAY_PLANE"); break;
103   }
104   DPRINTF("\n");
105 }
106
107 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
108    include all dependencies
109 */
110 #ifndef SONAME_LIBGL
111 #define SONAME_LIBGL "libGL.so"
112 #endif
113
114 static void *opengl_handle;
115
116 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
117 MAKE_FUNCPTR(glXChooseVisual)
118 MAKE_FUNCPTR(glXGetConfig)
119 MAKE_FUNCPTR(glXSwapBuffers)
120 MAKE_FUNCPTR(glXQueryExtension)
121 #undef MAKE_FUNCPTR
122
123 void X11DRV_OpenGL_Init(Display *display) {
124     int error_base, event_base;
125
126     opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
127     if (opengl_handle == NULL) return;
128
129 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(opengl_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
130 LOAD_FUNCPTR(glXChooseVisual)
131 LOAD_FUNCPTR(glXGetConfig)
132 LOAD_FUNCPTR(glXSwapBuffers)
133 LOAD_FUNCPTR(glXQueryExtension)
134 #undef LOAD_FUNCPTR
135
136     wine_tsx11_lock();
137     if (pglXQueryExtension(display, &event_base, &error_base) == True) {
138         TRACE("GLX is up and running error_base = %d\n", error_base);
139     } else {
140         wine_dlclose(opengl_handle, NULL, 0);
141         opengl_handle = NULL;
142     }
143     wine_tsx11_unlock();
144     return;
145
146 sym_not_found:
147     wine_dlclose(opengl_handle, NULL, 0);
148     opengl_handle = NULL;
149 }
150
151 /* X11DRV_ChoosePixelFormat
152
153      Equivalent of glXChooseVisual
154 */
155 int X11DRV_ChoosePixelFormat(X11DRV_PDEVICE *physDev,
156                              const PIXELFORMATDESCRIPTOR *ppfd) {
157 #define TEST_AND_ADD1(t,a) if (t) att_list[att_pos++] = a
158 #define TEST_AND_ADD2(t,a,b) if (t) { att_list[att_pos++] = a; att_list[att_pos++] = b; }
159 #define NULL_TEST_AND_ADD2(tv,a,b) att_list[att_pos++] = a; att_list[att_pos++] = ((tv) == 0 ? 0 : b)
160 #define ADD2(a,b) att_list[att_pos++] = a; att_list[att_pos++] = b
161
162   int att_list[64];
163   int att_pos = 0;
164   XVisualInfo *vis;
165   int i;
166
167   if (opengl_handle == NULL) {
168     ERR("No libGL on this box - disabling OpenGL support !\n");
169     return 0;
170   }
171   
172   if (TRACE_ON(opengl)) {
173     TRACE("(%p,%p)\n", physDev, ppfd);
174
175     dump_PIXELFORMATDESCRIPTOR((PIXELFORMATDESCRIPTOR *) ppfd);
176   }
177
178   if (ppfd->dwFlags & PFD_DRAW_TO_BITMAP) {
179     ERR("Flag not supported !\n");
180     /* Should SetError here... */
181     return 0;
182   }
183
184   /* Now, build the request to GLX */
185   TEST_AND_ADD1(ppfd->dwFlags & PFD_DOUBLEBUFFER, GLX_DOUBLEBUFFER);
186   TEST_AND_ADD1(ppfd->dwFlags & PFD_STEREO, GLX_STEREO);
187   TEST_AND_ADD1(ppfd->iPixelType == PFD_TYPE_RGBA, GLX_RGBA);
188   TEST_AND_ADD2(ppfd->iPixelType == PFD_TYPE_COLORINDEX, GLX_BUFFER_SIZE, ppfd->cColorBits);
189
190   NULL_TEST_AND_ADD2(ppfd->cDepthBits, GLX_DEPTH_SIZE, 8);
191   /* These flags are not supported yet...
192
193      NULL_TEST_AND_ADD2(ppfd->cAlphaBits, GLX_ALPHA_SIZE, 8);
194      ADD2(GLX_ACCUM_SIZE, ppfd->cAccumBits); */
195   ADD2(GLX_STENCIL_SIZE, ppfd->cStencilBits); /* now supported */
196   /*   ADD2(GLX_AUX_BUFFERS, ppfd->cAuxBuffers); */
197   att_list[att_pos] = None;
198
199   wine_tsx11_lock(); {
200     /*
201        This command cannot be used as we need to use the default visual...
202        Let's hope it at least contains some OpenGL functionnalities
203
204        vis = glXChooseVisual(gdi_display, DefaultScreen(gdi_display), att_list);
205     */
206     int num;
207     XVisualInfo template;
208
209     template.visualid = XVisualIDFromVisual(visual);
210     vis = XGetVisualInfo(gdi_display, VisualIDMask, &template, &num);
211
212     TRACE("Found visual : %p - returns %d\n", vis, physDev->used_visuals + 1);
213   }
214   wine_tsx11_unlock();
215
216   if (vis == NULL) {
217     ERR("No visual found !\n");
218     /* Should SetError here... */
219     return 0;
220   }
221   /* try to find the visualid in the already created visuals */
222   for( i=0; i<physDev->used_visuals; i++ ) {
223     if ( vis->visualid == physDev->visuals[i]->visualid ) {
224       XFree(vis);
225       return i+1;
226     }
227   }
228   /* now give up, if the maximum is reached */
229   if (physDev->used_visuals == MAX_PIXELFORMATS) {
230     ERR("Maximum number of visuals reached !\n");
231     /* Should SetError here... */
232     return 0;
233   }
234   physDev->visuals[physDev->used_visuals++] = vis;
235
236   return physDev->used_visuals;
237 }
238
239 /* X11DRV_DescribePixelFormat
240
241      Get the pixel-format descriptor associated to the given id
242 */
243 int X11DRV_DescribePixelFormat(X11DRV_PDEVICE *physDev,
244                                int iPixelFormat,
245                                UINT nBytes,
246                                PIXELFORMATDESCRIPTOR *ppfd) {
247   XVisualInfo *vis;
248   int value;
249   int rb,gb,bb,ab;
250
251   if (opengl_handle == NULL) {
252     ERR("No libGL on this box - disabling OpenGL support !\n");
253     return 0;
254   }
255   
256   TRACE("(%p,%d,%d,%p)\n", physDev, iPixelFormat, nBytes, ppfd);
257
258   if (ppfd == NULL) {
259     /* The application is only querying the number of visuals */
260     return MAX_PIXELFORMATS;
261   }
262
263   if (nBytes < sizeof(PIXELFORMATDESCRIPTOR)) {
264     ERR("Wrong structure size !\n");
265     /* Should set error */
266     return 0;
267   }
268   if ((iPixelFormat > MAX_PIXELFORMATS) ||
269       (iPixelFormat > physDev->used_visuals + 1) ||
270       (iPixelFormat <= 0)) {
271     ERR("Wrong pixel format !\n");
272     /* Should set error */
273     return 0;
274   }
275
276   if (iPixelFormat == physDev->used_visuals + 1) {
277     int dblBuf[]={GLX_RGBA,GLX_DEPTH_SIZE,16,GLX_DOUBLEBUFFER,None};
278
279     /* Create a 'standard' X Visual */
280     wine_tsx11_lock();
281     vis = pglXChooseVisual(gdi_display, DefaultScreen(gdi_display), dblBuf);
282     wine_tsx11_unlock();
283
284     WARN("Uninitialized Visual. Creating standard (%p) !\n", vis);
285
286     if (vis == NULL) {
287       ERR("Could not create standard visual !\n");
288       /* Should set error */
289       return 0;
290     }
291
292     physDev->visuals[physDev->used_visuals++] = vis;
293   }
294   vis = physDev->visuals[iPixelFormat - 1];
295
296   memset(ppfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
297   ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
298   ppfd->nVersion = 1;
299
300   /* These flags are always the same... */
301   ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_GENERIC_ACCELERATED;
302   /* Now the flags extraced from the Visual */
303   wine_tsx11_lock();
304   pglXGetConfig(gdi_display, vis, GLX_DOUBLEBUFFER, &value); if (value) ppfd->dwFlags |= PFD_DOUBLEBUFFER;
305   pglXGetConfig(gdi_display, vis, GLX_STEREO, &value); if (value) ppfd->dwFlags |= PFD_STEREO;
306
307   /* Pixel type */
308   pglXGetConfig(gdi_display, vis, GLX_RGBA, &value);
309   if (value)
310     ppfd->iPixelType = PFD_TYPE_RGBA;
311   else
312     ppfd->iPixelType = PFD_TYPE_COLORINDEX;
313
314   /* Color bits */
315   pglXGetConfig(gdi_display, vis, GLX_BUFFER_SIZE, &value);
316   ppfd->cColorBits = value;
317
318   /* Red, green, blue and alpha bits / shifts */
319   if (ppfd->iPixelType == PFD_TYPE_RGBA) {
320     pglXGetConfig(gdi_display, vis, GLX_RED_SIZE, &rb);
321     pglXGetConfig(gdi_display, vis, GLX_GREEN_SIZE, &gb);
322     pglXGetConfig(gdi_display, vis, GLX_BLUE_SIZE, &bb);
323     pglXGetConfig(gdi_display, vis, GLX_ALPHA_SIZE, &ab);
324
325     ppfd->cRedBits = rb;
326     ppfd->cRedShift = gb + bb + ab;
327     ppfd->cBlueBits = bb;
328     ppfd->cBlueShift = ab;
329     ppfd->cGreenBits = gb;
330     ppfd->cGreenShift = bb + ab;
331     ppfd->cAlphaBits = ab;
332     ppfd->cAlphaShift = 0;
333   } else {
334     ppfd->cRedBits = 0;
335     ppfd->cRedShift = 0;
336     ppfd->cBlueBits = 0;
337     ppfd->cBlueShift = 0;
338     ppfd->cGreenBits = 0;
339     ppfd->cGreenShift = 0;
340     ppfd->cAlphaBits = 0;
341     ppfd->cAlphaShift = 0;
342   }
343   /* Accums : to do ... */
344
345   /* Depth bits */
346   pglXGetConfig(gdi_display, vis, GLX_DEPTH_SIZE, &value);
347   ppfd->cDepthBits = value;
348
349   /* stencil bits */
350   pglXGetConfig( gdi_display, vis, GLX_STENCIL_SIZE, &value );
351   ppfd->cStencilBits = value;
352
353   wine_tsx11_unlock();
354
355   /* Aux : to do ... */
356
357   ppfd->iLayerType = PFD_MAIN_PLANE;
358
359   if (TRACE_ON(opengl)) {
360     dump_PIXELFORMATDESCRIPTOR(ppfd);
361   }
362
363   return MAX_PIXELFORMATS;
364 }
365
366 /* X11DRV_GetPixelFormat
367
368      Get the pixel-format id used by this DC
369 */
370 int X11DRV_GetPixelFormat(X11DRV_PDEVICE *physDev) {
371   TRACE("(%p): returns %d\n", physDev, physDev->current_pf);
372
373   return physDev->current_pf;
374 }
375
376 /* X11DRV_SetPixelFormat
377
378      Set the pixel-format id used by this DC
379 */
380 BOOL X11DRV_SetPixelFormat(X11DRV_PDEVICE *physDev,
381                            int iPixelFormat,
382                            const PIXELFORMATDESCRIPTOR *ppfd) {
383   TRACE("(%p,%d,%p)\n", physDev, iPixelFormat, ppfd);
384
385   physDev->current_pf = iPixelFormat;
386
387   return TRUE;
388 }
389
390 /* X11DRV_SwapBuffers
391
392      Swap the buffers of this DC
393 */
394 BOOL X11DRV_SwapBuffers(X11DRV_PDEVICE *physDev) {
395   if (opengl_handle == NULL) {
396     ERR("No libGL on this box - disabling OpenGL support !\n");
397     return 0;
398   }
399   
400   TRACE("(%p)\n", physDev);
401
402   wine_tsx11_lock();
403   pglXSwapBuffers(gdi_display, physDev->drawable);
404   wine_tsx11_unlock();
405
406   return TRUE;
407 }
408
409 /***********************************************************************
410  *              X11DRV_setup_opengl_visual
411  *
412  * Setup the default visual used for OpenGL and Direct3D, and the desktop
413  * window (if it exists).  If OpenGL isn't available, the visual is simply
414  * set to the default visual for the display
415  */
416 XVisualInfo *X11DRV_setup_opengl_visual( Display *display )
417 {
418     XVisualInfo *visual = NULL;
419     int dblBuf[]={GLX_RGBA,GLX_DEPTH_SIZE,16,GLX_DOUBLEBUFFER,None};
420
421     if (opengl_handle == NULL) return NULL;
422     
423     /* In order to support OpenGL or D3D, we require a double-buffered visual */
424     wine_tsx11_lock();
425     visual = pglXChooseVisual(display, DefaultScreen(display), dblBuf);
426     wine_tsx11_unlock();
427     return visual;
428 }
429
430 #else  /* no OpenGL includes */
431
432 void X11DRV_OpenGL_Init(Display *display)
433 {
434 }
435
436 /***********************************************************************
437  *              ChoosePixelFormat (X11DRV.@)
438  */
439 int X11DRV_ChoosePixelFormat(X11DRV_PDEVICE *physDev,
440                              const PIXELFORMATDESCRIPTOR *ppfd) {
441   ERR("No OpenGL support compiled in.\n");
442
443   return 0;
444 }
445
446 /***********************************************************************
447  *              DescribePixelFormat (X11DRV.@)
448  */
449 int X11DRV_DescribePixelFormat(X11DRV_PDEVICE *physDev,
450                                int iPixelFormat,
451                                UINT nBytes,
452                                PIXELFORMATDESCRIPTOR *ppfd) {
453   ERR("No OpenGL support compiled in.\n");
454
455   return 0;
456 }
457
458 /***********************************************************************
459  *              GetPixelFormat (X11DRV.@)
460  */
461 int X11DRV_GetPixelFormat(X11DRV_PDEVICE *physDev) {
462   ERR("No OpenGL support compiled in.\n");
463
464   return 0;
465 }
466
467 /***********************************************************************
468  *              SetPixelFormat (X11DRV.@)
469  */
470 BOOL X11DRV_SetPixelFormat(X11DRV_PDEVICE *physDev,
471                            int iPixelFormat,
472                            const PIXELFORMATDESCRIPTOR *ppfd) {
473   ERR("No OpenGL support compiled in.\n");
474
475   return FALSE;
476 }
477
478 /***********************************************************************
479  *              SwapBuffers (X11DRV.@)
480  */
481 BOOL X11DRV_SwapBuffers(X11DRV_PDEVICE *physDev) {
482   ERR("No OpenGL support compiled in.\n");
483
484   return FALSE;
485 }
486
487 XVisualInfo *X11DRV_setup_opengl_visual( Display *display )
488 {
489   return NULL;
490 }
491
492 #endif /* defined(HAVE_OPENGL) */