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