1 /* Window-specific OpenGL functions implementation.
3 Copyright (c) 1999 Lionel Ulmer
11 #include "wine/exception.h"
13 #include "debugtools.h"
22 #include "opengl_ext.h"
24 DEFAULT_DEBUG_CHANNEL(opengl);
26 static GLXContext default_cx = NULL;
28 typedef struct wine_glcontext {
32 struct wine_glcontext *next;
33 struct wine_glcontext *prev;
35 static Wine_GLContext *context_array;
37 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx) {
38 Wine_GLContext *ret = context_array;
39 while (ret != NULL) if (ctx == ret->ctx) break; else ret = ret->next;
43 static inline void free_context(Wine_GLContext *context) {
44 if (context->next != NULL) context->next->prev = context->prev;
45 if (context->prev != NULL) context->prev->next = context->next;
46 else context_array = context->next;
48 HeapFree(GetProcessHeap(), 0, context);
51 static inline Wine_GLContext *alloc_context(void) {
54 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext));
55 ret->next = context_array;
56 if (context_array != NULL) context_array->prev = ret;
57 else context_array = ret;
63 static int XGLErrorFlag = 0;
64 static int XGLErrorHandler(Display *dpy, XErrorEvent *event) {
68 /* filter for page-fault exceptions */
69 static WINE_EXCEPTION_FILTER(page_fault)
71 return EXCEPTION_EXECUTE_HANDLER;
74 /***********************************************************************
75 * wglCreateContext (OPENGL32.@)
77 HGLRC WINAPI wglCreateContext(HDC hdc)
84 TRACE("(%08x)\n", hdc);
86 /* First, get the visual in use by the X11DRV */
87 template.visualid = GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
88 vis = XGetVisualInfo(gdi_display, VisualIDMask, &template, &num);
91 ERR("NULL visual !!!\n");
92 /* Need to set errors here */
96 /* The context will be allocated in the wglMakeCurrent call */
98 ret = alloc_context();
103 TRACE(" creating context %p (GL context creation delayed)\n", ret);
107 /***********************************************************************
108 * wglCreateLayerContext (OPENGL32.@)
110 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
112 FIXME("(%08x,%d): stub !\n", hdc, iLayerPlane);
117 /***********************************************************************
118 * wglCopyContext (OPENGL32.@)
120 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
123 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
128 /***********************************************************************
129 * wglDeleteContext (OPENGL32.@)
131 BOOL WINAPI wglDeleteContext(HGLRC hglrc) {
132 int (*WineXHandler)(Display *, XErrorEvent *);
133 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
136 TRACE("(%p)\n", hglrc);
139 /* A game (Half Life not to name it) deletes twice the same context. To prevent
140 crashes, run with our own error function enabled */
141 XSync(gdi_display, False);
143 WineXHandler = XSetErrorHandler(XGLErrorHandler);
145 glXDestroyContext(gdi_display, ctx->ctx);
146 XSync(gdi_display, False);
149 if (XGLErrorHandler == 0) free_context(ctx);
151 __EXCEPT(page_fault) {
157 XSetErrorHandler(WineXHandler);
159 WARN("Error deleting context !\n");
160 SetLastError(ERROR_INVALID_HANDLE);
168 /***********************************************************************
169 * wglDescribeLayerPlane (OPENGL32.@)
171 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
175 LPLAYERPLANEDESCRIPTOR plpd) {
176 FIXME("(%08x,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
181 /***********************************************************************
182 * wglGetCurrentContext (OPENGL32.@)
184 HGLRC WINAPI wglGetCurrentContext(void) {
191 gl_ctx = glXGetCurrentContext();
192 ret = get_context_from_GLXContext(gl_ctx);
195 TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
200 /***********************************************************************
201 * wglGetCurrentDC (OPENGL32.@)
203 HDC WINAPI wglGetCurrentDC(void) {
210 gl_ctx = glXGetCurrentContext();
211 ret = get_context_from_GLXContext(gl_ctx);
215 TRACE(" returning %08x (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
218 TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
223 /***********************************************************************
224 * wglGetLayerPaletteEntries (OPENGL32.@)
226 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
230 const COLORREF *pcr) {
231 FIXME("(): stub !\n");
236 /***********************************************************************
237 * wglGetProcAddress (OPENGL32.@)
239 static int compar(const void *elt_a, const void *elt_b) {
240 return strcmp(((OpenGL_extension *) elt_a)->name,
241 ((OpenGL_extension *) elt_b)->name);
244 void* WINAPI wglGetProcAddress(LPCSTR lpszProc) {
246 static HMODULE hm = 0;
247 OpenGL_extension ext;
248 OpenGL_extension *ext_ret;
251 TRACE("(%s)\n", lpszProc);
254 hm = GetModuleHandleA("opengl32");
256 /* First, look if it's not already defined in the 'standard' OpenGL functions */
257 if ((local_func = GetProcAddress(hm, lpszProc)) != NULL) {
258 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
262 /* After that, search in the thunks to find the real name of the extension */
263 ext.name = (char *) lpszProc;
264 ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
265 extension_registry_size, sizeof(OpenGL_extension), compar);
267 if (ext_ret == NULL) {
268 /* Some sanity checks :-) */
269 if (glXGetProcAddressARB(lpszProc) != NULL) {
270 ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc);
274 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
277 /* After that, look at the extensions defined in the Linux OpenGL library */
278 if ((local_func = glXGetProcAddressARB(ext_ret->glx_name)) == NULL) {
282 /* Remove the 3 last letters (EXT, ARB, ...).
284 I know that some extensions have more than 3 letters (MESA, NV,
285 INTEL, ...), but this is only a stop-gap measure to fix buggy
286 OpenGL drivers (moreover, it is only useful for old 1.0 apps
287 that query the glBindTextureEXT extension).
289 strncpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
290 buf[strlen(ext_ret->glx_name) - 3] = '\0';
291 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
293 ret = GetProcAddress(hm, buf);
295 TRACE(" found function in main OpenGL library (%p) !\n", ret);
297 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
302 TRACE(" returning function (%p)\n", ext_ret->func);
303 *(ext_ret->func_ptr) = local_func;
305 return ext_ret->func;
310 /***********************************************************************
311 * wglMakeCurrent (OPENGL32.@)
313 BOOL WINAPI wglMakeCurrent(HDC hdc,
317 TRACE("(%08x,%p)\n", hdc, hglrc);
321 ret = glXMakeCurrent(gdi_display,
326 DC * dc = DC_GetDCPtr( hdc );
329 ERR("Null DC !!!\n");
332 X11DRV_PDEVICE *physDev;
333 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
335 physDev =(X11DRV_PDEVICE *)dc->physDev;
337 if (ctx->ctx == NULL) {
339 ctx->ctx = glXCreateContext(gdi_display, ctx->vis, NULL, True);
341 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
345 ret = glXMakeCurrent(gdi_display,
349 GDI_ReleaseObj( hdc );
352 TRACE(" returning %s\n", (ret ? "True" : "False"));
356 /***********************************************************************
357 * wglRealizeLayerPalette (OPENGL32.@)
359 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
367 /***********************************************************************
368 * wglSetLayerPaletteEntries (OPENGL32.@)
370 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
374 const COLORREF *pcr) {
375 FIXME("(): stub !\n");
380 /***********************************************************************
381 * wglShareLists (OPENGL32.@)
383 BOOL WINAPI wglShareLists(HGLRC hglrc1,
385 Wine_GLContext *org = (Wine_GLContext *) hglrc1;
386 Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
388 TRACE("(%p, %p)\n", org, dest);
390 if (dest->ctx != NULL) {
391 ERR("Could not share display lists, context already created !\n");
394 if (org->ctx == NULL) {
396 org->ctx = glXCreateContext(gdi_display, org->vis, NULL, True);
398 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
402 /* Create the destination context with display lists shared */
403 dest->ctx = glXCreateContext(gdi_display, dest->vis, org->ctx, True);
405 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
411 /***********************************************************************
412 * wglSwapLayerBuffers (OPENGL32.@)
414 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
416 FIXME("(): stub !\n");
421 /***********************************************************************
422 * wglUseFontBitmapsA (OPENGL32.@)
424 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
428 DC * dc = DC_GetDCPtr( hdc );
429 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
430 fontObject* pfo = XFONT_GetFontObject( physDev->font );
431 Font fid = pfo->fs->fid;
433 TRACE("(%08x, %ld, %ld, %ld)\n", hdc, first, count, listBase);
436 /* I assume that the glyphs are at the same position for X and for Windows */
437 glXUseXFont(fid, first, count, listBase);
439 GDI_ReleaseObj( hdc );
443 /***********************************************************************
444 * wglUseFontOutlinesA (OPENGL32.@)
446 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
453 LPGLYPHMETRICSFLOAT lpgmf) {
454 FIXME("(): stub !\n");
460 /* This is for brain-dead applications that use OpenGL functions before even
461 creating a rendering context.... */
462 static void process_attach(void) {
463 XWindowAttributes win_attr;
466 XVisualInfo template;
467 XVisualInfo *vis = NULL;
468 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
472 ERR("X11DRV not loaded. Cannot create default context.\n");
478 /* Try to get the visual from the Root Window. We can't use the standard (presumably
479 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
480 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
481 with mismatched visuals. Note that the Root Window visual may not be double
482 buffered, so apps actually attempting to render this way may flicker */
483 if (XGetWindowAttributes( gdi_display, root, &win_attr ))
485 rootVisual = win_attr.visual;
489 /* Get the default visual, since we can't seem to get the attributes from the
490 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
491 rootVisual = DefaultVisual( gdi_display, DefaultScreen(gdi_display) );
494 template.visualid = XVisualIDFromVisual(rootVisual);
495 vis = XGetVisualInfo(gdi_display, VisualIDMask, &template, &num);
496 if (vis != NULL) default_cx = glXCreateContext(gdi_display, vis, 0, GL_TRUE);
497 if (default_cx != NULL) glXMakeCurrent(gdi_display, root, default_cx);
501 if (default_cx == NULL) {
502 ERR("Could not create default context.\n");
505 context_array = NULL;
508 static void process_detach(void) {
509 glXDestroyContext(gdi_display, default_cx);
512 /***********************************************************************
513 * OpenGL initialisation routine
515 BOOL WINAPI OpenGL32_Init( HINSTANCE hinst, DWORD reason, LPVOID reserved )
518 case DLL_PROCESS_ATTACH:
521 case DLL_PROCESS_DETACH: