Now runs in Perl strict mode.
[wine/wine64.git] / dlls / opengl32 / wgl.c
blob94335482c5b6f2e9317ee8418291f76c1b5de464
1 /* Window-specific OpenGL functions implementation.
3 * Copyright (c) 1999 Lionel Ulmer
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "config.h"
22 #include <stdlib.h>
23 #include <string.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winerror.h"
29 #include "wine_gl.h"
30 #include "x11drv.h"
32 #include "wgl.h"
33 #include "opengl_ext.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
38 static GLXContext default_cx = NULL;
39 static Display *default_display; /* display to use for default context */
41 typedef struct wine_glcontext {
42 HDC hdc;
43 Display *display;
44 GLXContext ctx;
45 XVisualInfo *vis;
46 struct wine_glcontext *next;
47 struct wine_glcontext *prev;
48 } Wine_GLContext;
49 static Wine_GLContext *context_list;
51 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
53 Wine_GLContext *ret;
54 for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
55 return ret;
58 static inline void free_context(Wine_GLContext *context)
60 if (context->next != NULL) context->next->prev = context->prev;
61 if (context->prev != NULL) context->prev->next = context->next;
62 else context_list = context->next;
64 HeapFree(GetProcessHeap(), 0, context);
67 static inline Wine_GLContext *alloc_context(void)
69 Wine_GLContext *ret;
71 if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
73 ret->next = context_list;
74 if (context_list) context_list->prev = ret;
75 context_list = ret;
77 return ret;
80 inline static BOOL is_valid_context( Wine_GLContext *ctx )
82 Wine_GLContext *ptr;
83 for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
84 return (ptr != NULL);
87 /* retrieve the X display to use on a given DC */
88 inline static Display *get_display( HDC hdc )
90 Display *display;
91 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
93 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
94 sizeof(display), (LPSTR)&display )) display = NULL;
95 return display;
99 /* retrieve the X drawable to use on a given DC */
100 inline static Drawable get_drawable( HDC hdc )
102 Drawable drawable;
103 enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
105 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
106 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
107 return drawable;
111 /* retrieve the X drawable to use on a given DC */
112 inline static Font get_font( HDC hdc )
114 Font font;
115 enum x11drv_escape_codes escape = X11DRV_GET_FONT;
117 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
118 sizeof(font), (LPSTR)&font )) font = 0;
119 return font;
123 /***********************************************************************
124 * wglCreateContext (OPENGL32.@)
126 HGLRC WINAPI wglCreateContext(HDC hdc)
128 XVisualInfo *vis;
129 Wine_GLContext *ret;
130 int num;
131 XVisualInfo template;
132 Display *display = get_display( hdc );
134 TRACE("(%08x)\n", hdc);
136 /* First, get the visual in use by the X11DRV */
137 if (!display) return 0;
138 template.visualid = GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
139 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
141 if (vis == NULL) {
142 ERR("NULL visual !!!\n");
143 /* Need to set errors here */
144 return NULL;
147 /* The context will be allocated in the wglMakeCurrent call */
148 ENTER_GL();
149 ret = alloc_context();
150 LEAVE_GL();
151 ret->hdc = hdc;
152 ret->display = display;
153 ret->vis = vis;
155 TRACE(" creating context %p (GL context creation delayed)\n", ret);
156 return (HGLRC) ret;
159 /***********************************************************************
160 * wglCreateLayerContext (OPENGL32.@)
162 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
163 int iLayerPlane) {
164 FIXME("(%08x,%d): stub !\n", hdc, iLayerPlane);
166 return NULL;
169 /***********************************************************************
170 * wglCopyContext (OPENGL32.@)
172 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
173 HGLRC hglrcDst,
174 UINT mask) {
175 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
177 return FALSE;
180 /***********************************************************************
181 * wglDeleteContext (OPENGL32.@)
183 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
185 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
186 BOOL ret = TRUE;
188 TRACE("(%p)\n", hglrc);
190 ENTER_GL();
191 /* A game (Half Life not to name it) deletes twice the same context,
192 * so make sure it is valid first */
193 if (is_valid_context( ctx ))
195 if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
196 free_context(ctx);
198 else
200 WARN("Error deleting context !\n");
201 SetLastError(ERROR_INVALID_HANDLE);
202 ret = FALSE;
204 LEAVE_GL();
206 return ret;
209 /***********************************************************************
210 * wglDescribeLayerPlane (OPENGL32.@)
212 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
213 int iPixelFormat,
214 int iLayerPlane,
215 UINT nBytes,
216 LPLAYERPLANEDESCRIPTOR plpd) {
217 FIXME("(%08x,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
219 return FALSE;
222 /***********************************************************************
223 * wglGetCurrentContext (OPENGL32.@)
225 HGLRC WINAPI wglGetCurrentContext(void) {
226 GLXContext gl_ctx;
227 Wine_GLContext *ret;
229 TRACE("()\n");
231 ENTER_GL();
232 gl_ctx = glXGetCurrentContext();
233 ret = get_context_from_GLXContext(gl_ctx);
234 LEAVE_GL();
236 TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
238 return ret;
241 /***********************************************************************
242 * wglGetCurrentDC (OPENGL32.@)
244 HDC WINAPI wglGetCurrentDC(void) {
245 GLXContext gl_ctx;
246 Wine_GLContext *ret;
248 TRACE("()\n");
250 ENTER_GL();
251 gl_ctx = glXGetCurrentContext();
252 ret = get_context_from_GLXContext(gl_ctx);
253 LEAVE_GL();
255 if (ret) {
256 TRACE(" returning %08x (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
257 return ret->hdc;
258 } else {
259 TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
260 return 0;
264 /***********************************************************************
265 * wglGetLayerPaletteEntries (OPENGL32.@)
267 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
268 int iLayerPlane,
269 int iStart,
270 int cEntries,
271 const COLORREF *pcr) {
272 FIXME("(): stub !\n");
274 return 0;
277 /***********************************************************************
278 * wglGetProcAddress (OPENGL32.@)
280 static int compar(const void *elt_a, const void *elt_b) {
281 return strcmp(((OpenGL_extension *) elt_a)->name,
282 ((OpenGL_extension *) elt_b)->name);
285 void* WINAPI wglGetProcAddress(LPCSTR lpszProc) {
286 void *local_func;
287 static HMODULE hm = 0;
288 OpenGL_extension ext;
289 OpenGL_extension *ext_ret;
292 TRACE("(%s)\n", lpszProc);
294 if (hm == 0)
295 hm = GetModuleHandleA("opengl32");
297 /* First, look if it's not already defined in the 'standard' OpenGL functions */
298 if ((local_func = GetProcAddress(hm, lpszProc)) != NULL) {
299 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
300 return local_func;
303 /* After that, search in the thunks to find the real name of the extension */
304 ext.name = (char *) lpszProc;
305 ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
306 extension_registry_size, sizeof(OpenGL_extension), compar);
308 if (ext_ret == NULL) {
309 /* Some sanity checks :-) */
310 if (glXGetProcAddressARB(lpszProc) != NULL) {
311 ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc);
312 return NULL;
315 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
316 return NULL;
317 } else {
318 /* After that, look at the extensions defined in the Linux OpenGL library */
319 if ((local_func = glXGetProcAddressARB(ext_ret->glx_name)) == NULL) {
320 char buf[256];
321 void *ret = NULL;
323 /* Remove the 3 last letters (EXT, ARB, ...).
325 I know that some extensions have more than 3 letters (MESA, NV,
326 INTEL, ...), but this is only a stop-gap measure to fix buggy
327 OpenGL drivers (moreover, it is only useful for old 1.0 apps
328 that query the glBindTextureEXT extension).
330 strncpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
331 buf[strlen(ext_ret->glx_name) - 3] = '\0';
332 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
334 ret = GetProcAddress(hm, buf);
335 if (ret != NULL) {
336 TRACE(" found function in main OpenGL library (%p) !\n", ret);
337 } else {
338 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
341 return ret;
342 } else {
343 TRACE(" returning function (%p)\n", ext_ret->func);
344 *(ext_ret->func_ptr) = local_func;
346 return ext_ret->func;
351 /***********************************************************************
352 * wglMakeCurrent (OPENGL32.@)
354 BOOL WINAPI wglMakeCurrent(HDC hdc,
355 HGLRC hglrc) {
356 BOOL ret;
358 TRACE("(%08x,%p)\n", hdc, hglrc);
360 ENTER_GL();
361 if (hglrc == NULL) {
362 ret = glXMakeCurrent(default_display, None, NULL);
363 } else {
364 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
365 Drawable drawable = get_drawable( hdc );
367 if (ctx->ctx == NULL) {
368 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, True);
369 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
371 ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
373 LEAVE_GL();
374 TRACE(" returning %s\n", (ret ? "True" : "False"));
375 return ret;
378 /***********************************************************************
379 * wglRealizeLayerPalette (OPENGL32.@)
381 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
382 int iLayerPlane,
383 BOOL bRealize) {
384 FIXME("()\n");
386 return FALSE;
389 /***********************************************************************
390 * wglSetLayerPaletteEntries (OPENGL32.@)
392 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
393 int iLayerPlane,
394 int iStart,
395 int cEntries,
396 const COLORREF *pcr) {
397 FIXME("(): stub !\n");
399 return 0;
402 /***********************************************************************
403 * wglShareLists (OPENGL32.@)
405 BOOL WINAPI wglShareLists(HGLRC hglrc1,
406 HGLRC hglrc2) {
407 Wine_GLContext *org = (Wine_GLContext *) hglrc1;
408 Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
410 TRACE("(%p, %p)\n", org, dest);
412 if (dest->ctx != NULL) {
413 ERR("Could not share display lists, context already created !\n");
414 return FALSE;
415 } else {
416 if (org->ctx == NULL) {
417 ENTER_GL();
418 org->ctx = glXCreateContext(org->display, org->vis, NULL, True);
419 LEAVE_GL();
420 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
423 ENTER_GL();
424 /* Create the destination context with display lists shared */
425 dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, True);
426 LEAVE_GL();
427 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
430 return TRUE;
433 /***********************************************************************
434 * wglSwapLayerBuffers (OPENGL32.@)
436 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
437 UINT fuPlanes) {
438 FIXME("(): stub !\n");
440 return FALSE;
443 /***********************************************************************
444 * wglUseFontBitmapsA (OPENGL32.@)
446 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
447 DWORD first,
448 DWORD count,
449 DWORD listBase)
451 Font fid = get_font( hdc );
453 TRACE("(%08x, %ld, %ld, %ld)\n", hdc, first, count, listBase);
455 ENTER_GL();
456 /* I assume that the glyphs are at the same position for X and for Windows */
457 glXUseXFont(fid, first, count, listBase);
458 LEAVE_GL();
459 return TRUE;
462 /***********************************************************************
463 * wglUseFontOutlinesA (OPENGL32.@)
465 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
466 DWORD first,
467 DWORD count,
468 DWORD listBase,
469 FLOAT deviation,
470 FLOAT extrusion,
471 int format,
472 LPGLYPHMETRICSFLOAT lpgmf) {
473 FIXME("(): stub !\n");
475 return FALSE;
479 /* This is for brain-dead applications that use OpenGL functions before even
480 creating a rendering context.... */
481 static BOOL process_attach(void)
483 XWindowAttributes win_attr;
484 Visual *rootVisual;
485 int num;
486 XVisualInfo template;
487 HDC hdc;
488 XVisualInfo *vis = NULL;
489 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
491 if (!root)
493 ERR("X11DRV not loaded. Cannot create default context.\n");
494 return FALSE;
497 hdc = GetDC(0);
498 default_display = get_display( hdc );
499 ReleaseDC( 0, hdc );
500 if (!default_display)
502 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
503 return FALSE;
506 ENTER_GL();
508 /* Try to get the visual from the Root Window. We can't use the standard (presumably
509 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
510 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
511 with mismatched visuals. Note that the Root Window visual may not be double
512 buffered, so apps actually attempting to render this way may flicker */
513 if (XGetWindowAttributes( default_display, root, &win_attr ))
515 rootVisual = win_attr.visual;
517 else
519 /* Get the default visual, since we can't seem to get the attributes from the
520 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
521 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
524 template.visualid = XVisualIDFromVisual(rootVisual);
525 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
526 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
527 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
528 XFree(vis);
529 LEAVE_GL();
531 if (default_cx == NULL) {
532 ERR("Could not create default context.\n");
534 return TRUE;
537 static void process_detach(void)
539 glXDestroyContext(default_display, default_cx);
542 /***********************************************************************
543 * OpenGL initialisation routine
545 BOOL WINAPI OpenGL32_Init( HINSTANCE hinst, DWORD reason, LPVOID reserved )
547 switch(reason)
549 case DLL_PROCESS_ATTACH:
550 return process_attach();
551 case DLL_PROCESS_DETACH:
552 process_detach();
553 break;
555 return TRUE;