Added an unknown VxD error code.
[wine] / dlls / opengl32 / wgl.c
1 /* Window-specific OpenGL functions implementation.
2
3      Copyright (c) 1999 Lionel Ulmer
4 */
5
6 #include <stdlib.h>
7 #include <string.h>
8
9 #include "wine/exception.h"
10
11 #include "config.h"
12 #include "debugtools.h"
13 #include "gdi.h"
14 #include "windef.h"
15 #include "winerror.h"
16 #include "wine_gl.h"
17 #include "x11drv.h"
18 #include "x11font.h"
19
20 #include "wgl.h"
21 #include "opengl_ext.h"
22
23 DEFAULT_DEBUG_CHANNEL(opengl);
24
25 static GLXContext default_cx = NULL;
26
27 typedef struct wine_glcontext {
28   HDC hdc;
29   GLXContext ctx;
30   XVisualInfo *vis;
31   struct wine_glcontext *next;
32   struct wine_glcontext *prev;
33 } Wine_GLContext;
34 static Wine_GLContext *context_array;
35
36 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx) {
37   Wine_GLContext *ret = context_array;
38   while (ret != NULL) if (ctx == ret->ctx) break; else ret = ret->next;
39   return ret;
40 }
41   
42 static inline void free_context(Wine_GLContext *context) {
43   if (context->next != NULL) context->next->prev = context->prev;
44   if (context->prev != NULL) context->prev->next = context->next;
45   else                       context_array = context->next;
46
47   HeapFree(GetProcessHeap(), 0, context);
48 }
49
50 static inline Wine_GLContext *alloc_context(void) {
51   Wine_GLContext *ret;
52
53   ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext));
54   ret->next = context_array;
55   if (context_array != NULL) context_array->prev = ret;
56   else                       context_array = ret;
57   
58   return ret;
59 }
60
61
62 static int XGLErrorFlag = 0;
63 static int XGLErrorHandler(Display *dpy, XErrorEvent *event) {
64     XGLErrorFlag = 1;
65     return 0;
66 }
67 /* filter for page-fault exceptions */
68 static WINE_EXCEPTION_FILTER(page_fault)
69 {
70   return EXCEPTION_EXECUTE_HANDLER;
71 }
72
73 /***********************************************************************
74  *              wglCreateContext
75  */
76 HGLRC WINAPI wglCreateContext(HDC hdc)
77 {
78   XVisualInfo *vis;
79   Wine_GLContext *ret;
80   int num;
81   XVisualInfo template;
82
83   TRACE("(%08x)\n", hdc);
84
85   /* First, get the visual in use by the X11DRV */
86   template.visualid = XVisualIDFromVisual(X11DRV_GetVisual());
87   vis = XGetVisualInfo(gdi_display, VisualIDMask, &template, &num);
88
89   if (vis == NULL) {
90     ERR("NULL visual !!!\n");
91     /* Need to set errors here */
92     return NULL;
93   }
94
95   /* The context will be allocated in the wglMakeCurrent call */
96   ENTER_GL();
97   ret = alloc_context();
98   LEAVE_GL();
99   ret->hdc = hdc;
100   ret->vis = vis;
101
102   TRACE(" creating context %p (GL context creation delayed)\n", ret);
103   return (HGLRC) ret;
104 }
105
106 /***********************************************************************
107  *              wglCreateLayerContext
108  */
109 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
110                                    int iLayerPlane) {
111   FIXME("(%08x,%d): stub !\n", hdc, iLayerPlane);
112
113   return NULL;
114 }
115
116 /***********************************************************************
117  *              wglCopyContext
118  */
119 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
120                            HGLRC hglrcDst,
121                            UINT mask) {
122   FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
123
124   return FALSE;
125 }
126
127 /***********************************************************************
128  *              wglDeleteContext
129  */
130 BOOL WINAPI wglDeleteContext(HGLRC hglrc) {
131   int (*WineXHandler)(Display *, XErrorEvent *);
132   Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
133   BOOL ret;
134   
135   TRACE("(%p)\n", hglrc);
136   
137   ENTER_GL();
138   /* A game (Half Life not to name it) deletes twice the same context. To prevent
139      crashes, run with our own error function enabled */
140   XSync(gdi_display, False);
141   XGLErrorFlag = 0;
142   WineXHandler = XSetErrorHandler(XGLErrorHandler);
143   __TRY {
144     glXDestroyContext(gdi_display, ctx->ctx);
145     XSync(gdi_display, False);
146     XFlush(gdi_display);
147
148     if (XGLErrorHandler == 0) free_context(ctx);
149   }
150   __EXCEPT(page_fault) {
151     XGLErrorFlag = 1;
152   }
153   __ENDTRY
154
155   ret = TRUE;
156   XSetErrorHandler(WineXHandler);
157   if (XGLErrorFlag) {
158     WARN("Error deleting context !\n");
159     SetLastError(ERROR_INVALID_HANDLE);
160     ret = FALSE;
161   }
162   LEAVE_GL();
163   
164   return ret;
165 }
166
167 /***********************************************************************
168  *              wglDescribeLayerPlane
169  */
170 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
171                                   int iPixelFormat,
172                                   int iLayerPlane,
173                                   UINT nBytes,
174                                   LPLAYERPLANEDESCRIPTOR plpd) {
175   FIXME("(%08x,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
176
177   return FALSE;
178 }
179
180 /***********************************************************************
181  *              wglGetCurrentContext
182  */
183 HGLRC WINAPI wglGetCurrentContext(void) {
184   GLXContext gl_ctx;
185   Wine_GLContext *ret;
186
187   TRACE("()\n");
188
189   ENTER_GL();
190   gl_ctx = glXGetCurrentContext();
191   ret = get_context_from_GLXContext(gl_ctx);
192   LEAVE_GL();
193
194   TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
195   
196   return ret;
197 }
198
199 /***********************************************************************
200  *              wglGetCurrentDC
201  */
202 HDC WINAPI wglGetCurrentDC(void) {
203   GLXContext gl_ctx;
204   Wine_GLContext *ret;
205
206   TRACE("()\n");
207   
208   ENTER_GL();
209   gl_ctx = glXGetCurrentContext();
210   ret = get_context_from_GLXContext(gl_ctx);
211   LEAVE_GL();
212
213   if (ret) {
214     TRACE(" returning %08x (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
215     return ret->hdc;
216   } else {
217     TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
218     return 0;
219   }
220 }
221
222 /***********************************************************************
223  *              wglGetLayerPaletteEntries
224  */
225 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
226                                      int iLayerPlane,
227                                      int iStart,
228                                      int cEntries,
229                                      const COLORREF *pcr) {
230   FIXME("(): stub !\n");
231
232   return 0;
233 }
234
235 static int compar(const void *elt_a, const void *elt_b) {
236   return strcmp(((OpenGL_extension *) elt_a)->name,
237                 ((OpenGL_extension *) elt_b)->name);
238 }
239
240 /***********************************************************************
241  *              wglGetProcAddress
242  */
243 void* WINAPI wglGetProcAddress(LPCSTR  lpszProc) {
244   void *local_func;
245   static HMODULE hm = 0;
246
247   TRACE("(%s)\n", lpszProc);
248
249   if (hm == 0)
250       hm = GetModuleHandleA("opengl32");
251
252   /* First, look if it's not already defined in the 'standard' OpenGL functions */
253   if ((local_func = GetProcAddress(hm, lpszProc)) != NULL) {
254     TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
255     return local_func;
256   }
257
258   /* After that, look at the extensions defined in the Linux OpenGL library */
259   if ((local_func = glXGetProcAddressARB(lpszProc)) == NULL) {
260     char buf[256];
261     void *ret = NULL;
262     
263     /* Remove the 3 last letters (EXT, ARB, ...).
264        
265        I know that some extensions have more than 3 letters (MESA, NV,
266        INTEL, ...), but this is only a stop-gap measure to fix buggy
267        OpenGL drivers (moreover, it is only useful for old 1.0 apps
268        that query the glBindTextureEXT extension).
269     */
270     strncpy(buf, lpszProc, strlen(lpszProc) - 3);
271     buf[strlen(lpszProc) - 3] = '\0';
272     TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
273     
274     ret = GetProcAddress(hm, buf);
275     if (ret != NULL) {
276       TRACE(" found function in main OpenGL library (%p) !\n", ret);
277     }
278
279     return ret;
280   } else {
281     OpenGL_extension  ext;
282     OpenGL_extension *ret;
283
284     ext.name = (char *) lpszProc;
285     ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
286                                        extension_registry_size, sizeof(OpenGL_extension), compar);
287
288     if (ret != NULL) {
289       TRACE(" returning function  (%p)\n", ret->func);
290       *(ret->func_ptr) = local_func;
291
292       return ret->func;
293     } else {
294       ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc);
295       return NULL;
296     }
297   }
298 }
299
300 /***********************************************************************
301  *              wglMakeCurrent
302  */
303 BOOL WINAPI wglMakeCurrent(HDC hdc,
304                            HGLRC hglrc) {
305   BOOL ret;
306
307   TRACE("(%08x,%p)\n", hdc, hglrc);
308   
309   if (hglrc == NULL) {
310     ENTER_GL();
311     ret = glXMakeCurrent(gdi_display,
312                          None,
313                          NULL);
314     LEAVE_GL();
315   } else {
316     DC * dc = DC_GetDCPtr( hdc );
317     
318     if (dc == NULL) {
319       ERR("Null DC !!!\n");
320       ret = FALSE;
321     } else {
322       X11DRV_PDEVICE *physDev;
323       Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
324       
325       physDev =(X11DRV_PDEVICE *)dc->physDev;
326
327       if (ctx->ctx == NULL) {
328         ENTER_GL();
329         ctx->ctx = glXCreateContext(gdi_display, ctx->vis, NULL, True);
330         LEAVE_GL();
331         TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
332       }
333       
334       ENTER_GL();
335       ret = glXMakeCurrent(gdi_display,
336                            physDev->drawable,
337                            ctx->ctx);
338       LEAVE_GL();
339       GDI_ReleaseObj( hdc );
340     }
341   }
342   TRACE(" returning %s\n", (ret ? "True" : "False"));
343   return ret;
344 }
345
346 /***********************************************************************
347  *              wglRealizeLayerPalette
348  */
349 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
350                                    int iLayerPlane,
351                                    BOOL bRealize) {
352   FIXME("()\n");
353
354   return FALSE;
355 }
356
357 /***********************************************************************
358  *              wglSetLayerPaletteEntries
359  */
360 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
361                                      int iLayerPlane,
362                                      int iStart,
363                                      int cEntries,
364                                      const COLORREF *pcr) {
365   FIXME("(): stub !\n");
366
367   return 0;
368 }
369
370 /***********************************************************************
371  *              wglShareLists
372  */
373 BOOL WINAPI wglShareLists(HGLRC hglrc1,
374                           HGLRC hglrc2) {
375   Wine_GLContext *org  = (Wine_GLContext *) hglrc1;
376   Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
377   
378   TRACE("(%p, %p)\n", org, dest);
379
380   if (dest->ctx != NULL) {
381     ERR("Could not share display lists, context already created !\n");
382     return FALSE;
383   } else {
384     if (org->ctx == NULL) {
385       ENTER_GL();
386       org->ctx = glXCreateContext(gdi_display, org->vis, NULL, True);
387       LEAVE_GL();
388       TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
389     }
390
391     ENTER_GL();
392     /* Create the destination context with display lists shared */
393     dest->ctx = glXCreateContext(gdi_display, dest->vis, org->ctx, True);
394     LEAVE_GL();
395     TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
396   }
397   
398   return TRUE;
399 }
400
401 /***********************************************************************
402  *              wglSwapLayerBuffers
403  */
404 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
405                                 UINT fuPlanes) {
406   FIXME("(): stub !\n");
407
408   return FALSE;
409 }
410
411 /***********************************************************************
412  *              wglUseFontBitmapsA
413  */
414 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
415                                DWORD first,
416                                DWORD count,
417                                DWORD listBase) {
418   DC * dc = DC_GetDCPtr( hdc );
419   X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
420   fontObject* pfo = XFONT_GetFontObject( physDev->font );
421   Font fid = pfo->fs->fid;
422
423   TRACE("(%08x, %ld, %ld, %ld)\n", hdc, first, count, listBase);
424
425   ENTER_GL();
426   /* I assume that the glyphs are at the same position for X and for Windows */
427   glXUseXFont(fid, first, count, listBase);
428   LEAVE_GL();
429   GDI_ReleaseObj( hdc );
430   return TRUE;
431 }
432  
433 /***********************************************************************
434  *              wglUseFontOutlinesA
435  */
436 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
437                                 DWORD first,
438                                 DWORD count,
439                                 DWORD listBase,
440                                 FLOAT deviation,
441                                 FLOAT extrusion,
442                                 int format,
443                                 LPGLYPHMETRICSFLOAT lpgmf) {
444   FIXME("(): stub !\n");
445
446   return FALSE;
447 }
448
449
450 /* This is for brain-dead applications that use OpenGL functions before even
451    creating a rendering context.... */
452 static void process_attach(void) {
453   XWindowAttributes win_attr;
454   Visual *rootVisual;
455   int num;
456   XVisualInfo template;
457   XVisualInfo *vis = NULL;
458
459   if (!visual) {
460     ERR("X11DRV not loaded yet. Cannot create default context.\n");
461     return;
462   }
463   
464   ENTER_GL();
465
466   /* Try to get the visual from the Root Window.  We can't use the standard (presumably
467      double buffered) X11DRV visual with the Root Window, since we don't know if the Root
468      Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal 
469      with mismatched visuals.  Note that the Root Window visual may not be double 
470      buffered, so apps actually attempting to render this way may flicker */
471   if (TSXGetWindowAttributes( gdi_display, X11DRV_GetXRootWindow(), &win_attr ))
472   {
473     rootVisual = win_attr.visual; 
474   }
475   else
476   {
477     /* Get the default visual, since we can't seem to get the attributes from the 
478        Root Window.  Let's hope that the Root Window Visual matches the DefaultVisual */
479     rootVisual = DefaultVisual( gdi_display, DefaultScreen(gdi_display) );
480   }
481
482   template.visualid = XVisualIDFromVisual(rootVisual);
483   vis = XGetVisualInfo(gdi_display, VisualIDMask, &template, &num);
484   if (vis != NULL)        default_cx = glXCreateContext(gdi_display, vis, 0, GL_TRUE);
485   if (default_cx != NULL) glXMakeCurrent(gdi_display, X11DRV_GetXRootWindow(), default_cx);
486   XFree(vis);
487   LEAVE_GL();
488
489   if (default_cx == NULL) {
490     ERR("Could not create default context.\n");
491   }
492   
493   context_array = NULL;
494 }
495
496 static void process_detach(void) {
497   glXDestroyContext(gdi_display, default_cx);
498 }
499
500 /***********************************************************************
501  *           OpenGL initialisation routine
502  */
503 BOOL WINAPI OpenGL32_Init( HINSTANCE hinst, DWORD reason, LPVOID reserved )
504 {
505   switch(reason) {
506   case DLL_PROCESS_ATTACH:
507     process_attach();
508     break;
509   case DLL_PROCESS_DETACH:
510     process_detach();
511     break;
512   }
513   return TRUE;
514 }