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
32 #include "opengl_ext.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
37 void (*wine_tsx11_lock_ptr)(void) = NULL;
38 void (*wine_tsx11_unlock_ptr)(void) = NULL;
40 static GLXContext default_cx = NULL;
41 static Display *default_display; /* display to use for default context */
43 typedef struct wine_glcontext {
48 struct wine_glcontext *next;
49 struct wine_glcontext *prev;
51 static Wine_GLContext *context_list;
53 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
56 for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
60 static inline void free_context(Wine_GLContext *context)
62 if (context->next != NULL) context->next->prev = context->prev;
63 if (context->prev != NULL) context->prev->next = context->next;
64 else context_list = context->next;
66 HeapFree(GetProcessHeap(), 0, context);
69 static inline Wine_GLContext *alloc_context(void)
73 if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
75 ret->next = context_list;
76 if (context_list) context_list->prev = ret;
82 inline static BOOL is_valid_context( Wine_GLContext *ctx )
85 for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
89 /* retrieve the X display to use on a given DC */
90 inline static Display *get_display( HDC hdc )
93 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
95 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
96 sizeof(display), (LPSTR)&display )) display = NULL;
101 /* retrieve the X drawable to use on a given DC */
102 inline static Drawable get_drawable( HDC hdc )
105 enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
107 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
108 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
113 /* retrieve the X drawable to use on a given DC */
114 inline static Font get_font( HDC hdc )
117 enum x11drv_escape_codes escape = X11DRV_GET_FONT;
119 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
120 sizeof(font), (LPSTR)&font )) font = 0;
125 /***********************************************************************
126 * wglCreateContext (OPENGL32.@)
128 HGLRC WINAPI wglCreateContext(HDC hdc)
133 XVisualInfo template;
134 Display *display = get_display( hdc );
136 TRACE("(%p)\n", hdc);
138 /* First, get the visual in use by the X11DRV */
139 if (!display) return 0;
140 template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
141 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
144 ERR("NULL visual !!!\n");
145 /* Need to set errors here */
149 /* The context will be allocated in the wglMakeCurrent call */
151 ret = alloc_context();
154 ret->display = display;
157 TRACE(" creating context %p (GL context creation delayed)\n", ret);
161 /***********************************************************************
162 * wglCreateLayerContext (OPENGL32.@)
164 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
166 FIXME("(%p,%d): stub !\n", hdc, iLayerPlane);
171 /***********************************************************************
172 * wglCopyContext (OPENGL32.@)
174 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
177 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
182 /***********************************************************************
183 * wglDeleteContext (OPENGL32.@)
185 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
187 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
190 TRACE("(%p)\n", hglrc);
193 /* A game (Half Life not to name it) deletes twice the same context,
194 * so make sure it is valid first */
195 if (is_valid_context( ctx ))
197 if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
202 WARN("Error deleting context !\n");
203 SetLastError(ERROR_INVALID_HANDLE);
211 /***********************************************************************
212 * wglDescribeLayerPlane (OPENGL32.@)
214 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
218 LPLAYERPLANEDESCRIPTOR plpd) {
219 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
224 /***********************************************************************
225 * wglGetCurrentContext (OPENGL32.@)
227 HGLRC WINAPI wglGetCurrentContext(void) {
234 gl_ctx = glXGetCurrentContext();
235 ret = get_context_from_GLXContext(gl_ctx);
238 TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
243 /***********************************************************************
244 * wglGetCurrentDC (OPENGL32.@)
246 HDC WINAPI wglGetCurrentDC(void) {
253 gl_ctx = glXGetCurrentContext();
254 ret = get_context_from_GLXContext(gl_ctx);
258 TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
261 TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
266 /***********************************************************************
267 * wglGetLayerPaletteEntries (OPENGL32.@)
269 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
273 const COLORREF *pcr) {
274 FIXME("(): stub !\n");
279 /***********************************************************************
280 * wglGetProcAddress (OPENGL32.@)
282 static int compar(const void *elt_a, const void *elt_b) {
283 return strcmp(((OpenGL_extension *) elt_a)->name,
284 ((OpenGL_extension *) elt_b)->name);
287 void* WINAPI wglGetProcAddress(LPCSTR lpszProc) {
289 static HMODULE hm = 0;
290 OpenGL_extension ext;
291 OpenGL_extension *ext_ret;
294 TRACE("(%s)\n", lpszProc);
297 hm = GetModuleHandleA("opengl32");
299 /* First, look if it's not already defined in the 'standard' OpenGL functions */
300 if ((local_func = GetProcAddress(hm, lpszProc)) != NULL) {
301 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
305 /* After that, search in the thunks to find the real name of the extension */
306 ext.name = (char *) lpszProc;
307 ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
308 extension_registry_size, sizeof(OpenGL_extension), compar);
310 if (ext_ret == NULL) {
311 /* Some sanity checks :-) */
312 if (glXGetProcAddressARB(lpszProc) != NULL) {
313 ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc);
317 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
320 /* After that, look at the extensions defined in the Linux OpenGL library */
321 if ((local_func = glXGetProcAddressARB(ext_ret->glx_name)) == NULL) {
325 /* Remove the 3 last letters (EXT, ARB, ...).
327 I know that some extensions have more than 3 letters (MESA, NV,
328 INTEL, ...), but this is only a stop-gap measure to fix buggy
329 OpenGL drivers (moreover, it is only useful for old 1.0 apps
330 that query the glBindTextureEXT extension).
332 strncpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
333 buf[strlen(ext_ret->glx_name) - 3] = '\0';
334 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
336 ret = GetProcAddress(hm, buf);
338 TRACE(" found function in main OpenGL library (%p) !\n", ret);
340 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
345 TRACE(" returning function (%p)\n", ext_ret->func);
346 *(ext_ret->func_ptr) = local_func;
348 return ext_ret->func;
353 /***********************************************************************
354 * wglMakeCurrent (OPENGL32.@)
356 BOOL WINAPI wglMakeCurrent(HDC hdc,
360 TRACE("(%p,%p)\n", hdc, hglrc);
364 ret = glXMakeCurrent(default_display, None, NULL);
366 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
367 Drawable drawable = get_drawable( hdc );
369 if (ctx->ctx == NULL) {
370 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, True);
371 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
373 ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
376 TRACE(" returning %s\n", (ret ? "True" : "False"));
380 /***********************************************************************
381 * wglRealizeLayerPalette (OPENGL32.@)
383 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
391 /***********************************************************************
392 * wglSetLayerPaletteEntries (OPENGL32.@)
394 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
398 const COLORREF *pcr) {
399 FIXME("(): stub !\n");
404 /***********************************************************************
405 * wglShareLists (OPENGL32.@)
407 BOOL WINAPI wglShareLists(HGLRC hglrc1,
409 Wine_GLContext *org = (Wine_GLContext *) hglrc1;
410 Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
412 TRACE("(%p, %p)\n", org, dest);
414 if (dest->ctx != NULL) {
415 ERR("Could not share display lists, context already created !\n");
418 if (org->ctx == NULL) {
420 org->ctx = glXCreateContext(org->display, org->vis, NULL, True);
422 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
426 /* Create the destination context with display lists shared */
427 dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, True);
429 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
435 /***********************************************************************
436 * wglSwapLayerBuffers (OPENGL32.@)
438 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
440 TRACE("(%p, %08x)\n", hdc, fuPlanes);
442 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
443 if (!SwapBuffers(hdc)) return FALSE;
444 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
448 WARN("Following layers unhandled : %08x\n", fuPlanes);
454 /***********************************************************************
455 * wglUseFontBitmapsA (OPENGL32.@)
457 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
462 Font fid = get_font( hdc );
464 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
467 /* We are running using client-side rendering fonts... */
469 static const MAT2 id = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
472 void *bitmap = NULL, *gl_bitmap = NULL;
476 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
477 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
480 for (glyph = first; glyph < first + count; glyph++) {
481 int needed_size = GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &id);
482 int height, width_int;
484 if (needed_size == GDI_ERROR) goto error;
485 if (needed_size > size) {
487 if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
488 if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
489 bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
490 gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
492 if (GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &id) == GDI_ERROR) goto error;
493 if (TRACE_ON(opengl)) {
494 unsigned int height, width, bitmask;
495 unsigned char *bitmap_ = (unsigned char *) bitmap;
497 DPRINTF("Glyph : %d\n", glyph);
498 DPRINTF(" - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
499 DPRINTF(" - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
500 DPRINTF(" - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
501 DPRINTF(" - size : %d\n", needed_size);
502 DPRINTF(" - bitmap : \n");
503 for (height = 0; height < gm.gmBlackBoxY; height++) {
505 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
510 if (*bitmap_ & bitmask)
515 bitmap_ += (4 - (((unsigned int) bitmap_) & 0x03));
520 /* For some obscure reasons, I seem to need to rotate the glyph for OpenGL to be happy.
521 As Wine does not seem to support the MAT2 field, I need to do it myself.... */
522 width_int = (gm.gmBlackBoxX + 31) / 32;
523 for (height = 0; height < gm.gmBlackBoxY; height++) {
525 for (width = 0; width < width_int; width++) {
526 ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
527 ((int *) bitmap)[height * width_int + width];
532 glNewList(listBase++, GL_COMPILE);
533 glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmptGlyphOrigin.x, gm.gmBlackBoxY - gm.gmptGlyphOrigin.y, gm.gmCellIncX, gm.gmCellIncY, gl_bitmap);
539 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
542 if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
543 if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
548 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
551 if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
552 if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
557 /* I assume that the glyphs are at the same position for X and for Windows */
558 glXUseXFont(fid, first, count, listBase);
563 /***********************************************************************
564 * wglUseFontOutlinesA (OPENGL32.@)
566 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
573 LPGLYPHMETRICSFLOAT lpgmf) {
574 FIXME("(): stub !\n");
580 /* This is for brain-dead applications that use OpenGL functions before even
581 creating a rendering context.... */
582 static BOOL process_attach(void)
584 XWindowAttributes win_attr;
587 XVisualInfo template;
589 XVisualInfo *vis = NULL;
590 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
591 HMODULE mod = GetModuleHandleA( "x11drv.dll" );
595 ERR("X11DRV not loaded. Cannot create default context.\n");
599 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
600 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
603 default_display = get_display( hdc );
605 if (!default_display)
607 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
613 /* Try to get the visual from the Root Window. We can't use the standard (presumably
614 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
615 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
616 with mismatched visuals. Note that the Root Window visual may not be double
617 buffered, so apps actually attempting to render this way may flicker */
618 if (XGetWindowAttributes( default_display, root, &win_attr ))
620 rootVisual = win_attr.visual;
624 /* Get the default visual, since we can't seem to get the attributes from the
625 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
626 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
629 template.visualid = XVisualIDFromVisual(rootVisual);
630 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
631 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
632 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
636 if (default_cx == NULL) {
637 ERR("Could not create default context.\n");
642 static void process_detach(void)
644 glXDestroyContext(default_display, default_cx);
647 /***********************************************************************
648 * OpenGL initialisation routine
650 BOOL WINAPI OpenGL32_Init( HINSTANCE hinst, DWORD reason, LPVOID reserved )
654 case DLL_PROCESS_ATTACH:
655 return process_attach();
656 case DLL_PROCESS_DETACH: