Newer
Older
* X11DRV OpenGL functions
*
* Copyright 2000 Lionel Ulmer
* Copyright 2005 Alex Woods
* Copyright 2005 Raphael Junqueira
* Copyright 2006 Roderick Colenbrander
* Copyright 2006 Tomas Carnecky
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "x11drv.h"
#include "winternl.h"
#include "wine/library.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(wgl);
WINE_DECLARE_DEBUG_CHANNEL(opengl);
#ifdef SONAME_LIBGL
#undef APIENTRY
#undef CALLBACK
#undef WINAPI
#ifdef HAVE_GL_GL_H
# include <GL/gl.h>
#endif
#ifdef HAVE_GL_GLX_H
# include <GL/glx.h>
#endif
#ifdef HAVE_GL_GLEXT_H
# include <GL/glext.h>
#endif
#include "wine/wgl.h"
#undef APIENTRY
#undef CALLBACK
#undef WINAPI
/* Redefines the constants */
#define CALLBACK __stdcall
#define WINAPI __stdcall
#define APIENTRY WINAPI
WINE_DECLARE_DEBUG_CHANNEL(fps);
typedef struct wine_glcontext {
HDC hdc;
XVisualInfo *vis;
GLXFBConfig fb_conf;
GLXContext ctx;
BOOL do_escape;
X11DRV_PDEVICE *physDev;
RECT viewport;
RECT scissor;
BOOL scissor_enabled;
struct wine_glcontext *next;
struct wine_glcontext *prev;
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
typedef struct wine_glpbuffer {
Drawable drawable;
Display* display;
int pixelFormat;
int width;
int height;
int* attribList;
HDC hdc;
int use_render_texture;
GLuint texture_target;
GLuint texture_bind_target;
GLuint texture;
int texture_level;
HDC prev_hdc;
HGLRC prev_ctx;
HDC render_hdc;
HGLRC render_ctx;
} Wine_GLPBuffer;
typedef struct wine_glextension {
const char *extName;
struct {
const char *funcName;
void *funcAddress;
} extEntryPoints[8];
} WineGLExtension;
struct WineGLInfo {
const char *glVersion;
const char *glExtensions;
int glxVersion[2];
const char *glxServerVersion;
const char *glxServerExtensions;
const char *glxClientVersion;
const char *glxClientExtensions;
const char *glxExtensions;
BOOL glxDirect;
char wglExtensions[4096];
};
typedef struct wine_glpixelformat {
int iPixelFormat;
int fbconfig;
int fmt_index;
} WineGLPixelFormat;
static Wine_GLContext *context_list;
static struct WineGLInfo WineGLInfo = { 0 };
static int use_render_texture_emulation = 0;
static int use_render_texture_ati = 0;
static int swap_interval = 1;
#define MAX_EXTENSIONS 16
static const WineGLExtension *WineGLExtensionList[MAX_EXTENSIONS];
static int WineGLExtensionListSize;
#define MAX_GLPIXELFORMATS 32
static WineGLPixelFormat WineGLPixelFormatList[MAX_GLPIXELFORMATS];
static int WineGLPixelFormatListSize = 0;
static void X11DRV_WineGL_LoadExtensions(void);
static void dump_PIXELFORMATDESCRIPTOR(const PIXELFORMATDESCRIPTOR *ppfd) {
TRACE(" - size / version : %d / %d\n", ppfd->nSize, ppfd->nVersion);
TRACE(" - dwFlags : ");
#define TEST_AND_DUMP(t,tv) if ((t) & (tv)) TRACE(#tv " ")
TEST_AND_DUMP(ppfd->dwFlags, PFD_DEPTH_DONTCARE);
TEST_AND_DUMP(ppfd->dwFlags, PFD_DOUBLEBUFFER);
TEST_AND_DUMP(ppfd->dwFlags, PFD_DOUBLEBUFFER_DONTCARE);
TEST_AND_DUMP(ppfd->dwFlags, PFD_DRAW_TO_WINDOW);
TEST_AND_DUMP(ppfd->dwFlags, PFD_DRAW_TO_BITMAP);
TEST_AND_DUMP(ppfd->dwFlags, PFD_GENERIC_ACCELERATED);
TEST_AND_DUMP(ppfd->dwFlags, PFD_GENERIC_FORMAT);
TEST_AND_DUMP(ppfd->dwFlags, PFD_NEED_PALETTE);
TEST_AND_DUMP(ppfd->dwFlags, PFD_NEED_SYSTEM_PALETTE);
TEST_AND_DUMP(ppfd->dwFlags, PFD_STEREO);
TEST_AND_DUMP(ppfd->dwFlags, PFD_STEREO_DONTCARE);
TEST_AND_DUMP(ppfd->dwFlags, PFD_SUPPORT_GDI);
TEST_AND_DUMP(ppfd->dwFlags, PFD_SUPPORT_OPENGL);
TEST_AND_DUMP(ppfd->dwFlags, PFD_SWAP_COPY);
TEST_AND_DUMP(ppfd->dwFlags, PFD_SWAP_EXCHANGE);
TEST_AND_DUMP(ppfd->dwFlags, PFD_SWAP_LAYER_BUFFERS);
#undef TEST_AND_DUMP
TRACE(" - iPixelType : ");
case PFD_TYPE_RGBA: TRACE("PFD_TYPE_RGBA"); break;
case PFD_TYPE_COLORINDEX: TRACE("PFD_TYPE_COLORINDEX"); break;
TRACE(" - Color : %d\n", ppfd->cColorBits);
TRACE(" - Red : %d\n", ppfd->cRedBits);
TRACE(" - Green : %d\n", ppfd->cGreenBits);
TRACE(" - Blue : %d\n", ppfd->cBlueBits);
TRACE(" - Alpha : %d\n", ppfd->cAlphaBits);
TRACE(" - Accum : %d\n", ppfd->cAccumBits);
TRACE(" - Depth : %d\n", ppfd->cDepthBits);
TRACE(" - Stencil : %d\n", ppfd->cStencilBits);
TRACE(" - Aux : %d\n", ppfd->cAuxBuffers);
TRACE(" - iLayerType : ");
case PFD_MAIN_PLANE: TRACE("PFD_MAIN_PLANE"); break;
case PFD_OVERLAY_PLANE: TRACE("PFD_OVERLAY_PLANE"); break;
case (BYTE)PFD_UNDERLAY_PLANE: TRACE("PFD_UNDERLAY_PLANE"); break;
#define PUSH1(attribs,att) do { attribs[nAttribs++] = (att); } while (0)
#define PUSH2(attribs,att,value) do { attribs[nAttribs++] = (att); attribs[nAttribs++] = (value); } while(0)
#define MAKE_FUNCPTR(f) static typeof(f) * p##f;
/* GLX 1.0 */
MAKE_FUNCPTR(glXChooseVisual)
MAKE_FUNCPTR(glXCreateContext)
MAKE_FUNCPTR(glXCreateGLXPixmap)
MAKE_FUNCPTR(glXGetCurrentContext)
MAKE_FUNCPTR(glXDestroyContext)
MAKE_FUNCPTR(glXDestroyGLXPixmap)
MAKE_FUNCPTR(glXIsDirect)
MAKE_FUNCPTR(glXMakeCurrent)
MAKE_FUNCPTR(glXSwapBuffers)
MAKE_FUNCPTR(glXQueryExtension)
MAKE_FUNCPTR(glXQueryVersion)
MAKE_FUNCPTR(glXUseXFont)
/* GLX 1.1 */
MAKE_FUNCPTR(glXGetClientString)
MAKE_FUNCPTR(glXQueryExtensionsString)
MAKE_FUNCPTR(glXQueryServerString)
/* GLX 1.3 */
MAKE_FUNCPTR(glXGetFBConfigs)
MAKE_FUNCPTR(glXChooseFBConfig)
MAKE_FUNCPTR(glXCreatePbuffer)
MAKE_FUNCPTR(glXDestroyPbuffer)
MAKE_FUNCPTR(glXGetFBConfigAttrib)
MAKE_FUNCPTR(glXGetVisualFromFBConfig)
MAKE_FUNCPTR(glXMakeContextCurrent)
MAKE_FUNCPTR(glXQueryDrawable)
MAKE_FUNCPTR(glXGetCurrentReadDrawable)
/* GLX Extensions */
static void* (*pglXGetProcAddressARB)(const GLubyte *);
static BOOL (*pglXBindTexImageARB)(Display *dpy, GLXPbuffer pbuffer, int buffer);
static BOOL (*pglXReleaseTexImageARB)(Display *dpy, GLXPbuffer pbuffer, int buffer);
static BOOL (*pglXDrawableAttribARB)(Display *dpy, GLXDrawable draw, const int *attribList);
static int (*pglXSwapIntervalSGI)(int);
/* NV GLX Extension */
static void* (*pglXAllocateMemoryNV)(GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority);
static void (*pglXFreeMemoryNV)(GLvoid *pointer);
/* Standard OpenGL */
MAKE_FUNCPTR(glBindTexture)
MAKE_FUNCPTR(glBitmap)
MAKE_FUNCPTR(glCopyTexSubImage1D)
MAKE_FUNCPTR(glCopyTexSubImage2D)
MAKE_FUNCPTR(glDisable)
MAKE_FUNCPTR(glDrawBuffer)
MAKE_FUNCPTR(glEnable)
MAKE_FUNCPTR(glEndList)
MAKE_FUNCPTR(glGetError)
MAKE_FUNCPTR(glGetIntegerv)
MAKE_FUNCPTR(glGetString)
MAKE_FUNCPTR(glIsEnabled)
MAKE_FUNCPTR(glNewList)
MAKE_FUNCPTR(glPixelStorei)
MAKE_FUNCPTR(glScissor)
MAKE_FUNCPTR(glViewport)
static BOOL X11DRV_WineGL_InitOpenglInfo(void)
{
static BOOL infoInitialized = FALSE;
int screen = DefaultScreen(gdi_display);
Window win = RootWindow(gdi_display, screen);
Visual *visual;
XVisualInfo template;
XVisualInfo *vis;
int num;
GLXContext ctx = NULL;
if (infoInitialized)
return TRUE;
infoInitialized = TRUE;
wine_tsx11_lock();
visual = DefaultVisual(gdi_display, screen);
template.visualid = XVisualIDFromVisual(visual);
vis = XGetVisualInfo(gdi_display, VisualIDMask, &template, &num);
if (vis) {
WORD old_fs = wine_get_fs();
/* Create a GLX Context. Without one we can't query GL information */
ctx = pglXCreateContext(gdi_display, vis, None, GL_TRUE);
if (wine_get_fs() != old_fs)
{
wine_set_fs( old_fs );
wine_tsx11_unlock();
ERR( "%%fs register corrupted, probably broken ATI driver, disabling OpenGL.\n" );
ERR( "You need to set the \"UseFastTls\" option to \"2\" in your X config file.\n" );
return FALSE;
}
}
if (ctx) {
pglXMakeCurrent(gdi_display, win, ctx);
} else {
ERR(" couldn't initialize OpenGL, expect problems\n");
return FALSE;
}
WineGLInfo.glVersion = (const char *) pglGetString(GL_VERSION);
WineGLInfo.glExtensions = strdup((const char *) pglGetString(GL_EXTENSIONS));
/* Get the common GLX version supported by GLX client and server ( major/minor) */
pglXQueryVersion(gdi_display, &WineGLInfo.glxVersion[0], &WineGLInfo.glxVersion[1]);
WineGLInfo.glxServerVersion = pglXQueryServerString(gdi_display, screen, GLX_VERSION);
WineGLInfo.glxServerExtensions = pglXQueryServerString(gdi_display, screen, GLX_EXTENSIONS);
WineGLInfo.glxClientVersion = pglXGetClientString(gdi_display, GLX_VERSION);
WineGLInfo.glxClientExtensions = pglXGetClientString(gdi_display, GLX_EXTENSIONS);
WineGLInfo.glxExtensions = pglXQueryExtensionsString(gdi_display, screen);
WineGLInfo.glxDirect = pglXIsDirect(gdi_display, ctx);
TRACE("GL version : %s.\n", WineGLInfo.glVersion);
TRACE("GLX version : %d.%d.\n", WineGLInfo.glxVersion[0], WineGLInfo.glxVersion[1]);
TRACE("Server GLX version : %s.\n", WineGLInfo.glxServerVersion);
TRACE("Client GLX version : %s.\n", WineGLInfo.glxClientVersion);
TRACE("Direct rendering enabled: %s\n", WineGLInfo.glxDirect ? "True" : "False");
if(vis) XFree(vis);
if(ctx) {
pglXMakeCurrent(gdi_display, None, NULL);
pglXDestroyContext(gdi_display, ctx);
}
return TRUE;
}
static BOOL has_opengl(void)
{
static int init_done;
static void *opengl_handle;
const char *glx_extensions;
int error_base, event_base;
if (init_done) return (opengl_handle != NULL);
init_done = 1;
/* No need to load any other libraries as according to the ABI, libGL should be self-sufficient
and include all dependencies */
opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
if (opengl_handle == NULL) return FALSE;
pglXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
if (pglXGetProcAddressARB == NULL) {
ERR("could not find glXGetProcAddressARB in libGL.\n");
return FALSE;
}
#define LOAD_FUNCPTR(f) if((p##f = (void*)pglXGetProcAddressARB((const unsigned char*)#f)) == NULL) goto sym_not_found;
/* GLX 1.0 */
LOAD_FUNCPTR(glXChooseVisual)
LOAD_FUNCPTR(glXCreateContext)
LOAD_FUNCPTR(glXCreateGLXPixmap)
LOAD_FUNCPTR(glXGetCurrentContext)
LOAD_FUNCPTR(glXDestroyContext)
LOAD_FUNCPTR(glXDestroyGLXPixmap)
LOAD_FUNCPTR(glXIsDirect)
LOAD_FUNCPTR(glXMakeCurrent)
LOAD_FUNCPTR(glXSwapBuffers)
LOAD_FUNCPTR(glXQueryExtension)
LOAD_FUNCPTR(glXQueryVersion)
LOAD_FUNCPTR(glXUseXFont)
/* GLX 1.1 */
LOAD_FUNCPTR(glXGetClientString)
LOAD_FUNCPTR(glXQueryExtensionsString)
LOAD_FUNCPTR(glXQueryServerString)
/* GLX 1.3 */
LOAD_FUNCPTR(glXCreatePbuffer)
LOAD_FUNCPTR(glXDestroyPbuffer)
LOAD_FUNCPTR(glXMakeContextCurrent)
LOAD_FUNCPTR(glXGetCurrentReadDrawable)
LOAD_FUNCPTR(glXGetFBConfigs)
/* Standard OpenGL calls */
LOAD_FUNCPTR(glBindTexture)
LOAD_FUNCPTR(glBitmap)
LOAD_FUNCPTR(glCopyTexSubImage1D)
LOAD_FUNCPTR(glCopyTexSubImage2D)
LOAD_FUNCPTR(glDisable)
LOAD_FUNCPTR(glDrawBuffer)
LOAD_FUNCPTR(glEnable)
LOAD_FUNCPTR(glEndList)
LOAD_FUNCPTR(glGetError)
LOAD_FUNCPTR(glGetIntegerv)
LOAD_FUNCPTR(glGetString)
LOAD_FUNCPTR(glIsEnabled)
LOAD_FUNCPTR(glNewList)
LOAD_FUNCPTR(glPixelStorei)
LOAD_FUNCPTR(glScissor)
LOAD_FUNCPTR(glViewport)
#undef LOAD_FUNCPTR
/* It doesn't matter if these fail. They'll only be used if the driver reports
the associated extension is available (and if a driver reports the extension
is available but fails to provide the functions, it's quite broken) */
#define LOAD_FUNCPTR(f) p##f = (void*)pglXGetProcAddressARB((const unsigned char*)#f);
/* NV GLX Extension */
LOAD_FUNCPTR(glXAllocateMemoryNV)
LOAD_FUNCPTR(glXFreeMemoryNV)
if(!X11DRV_WineGL_InitOpenglInfo()) {
wine_dlclose(opengl_handle, NULL, 0);
opengl_handle = NULL;
return FALSE;
}
if (pglXQueryExtension(gdi_display, &error_base, &event_base) == True) {
TRACE("GLX is up and running error_base = %d\n", error_base);
} else {
wine_dlclose(opengl_handle, NULL, 0);
opengl_handle = NULL;
/* In case of GLX you have direct and indirect rendering. Most of the time direct rendering is used
* as in general only that is hardware accelerated. In some cases like in case of remote X indirect
* rendering is used.
*
* The main problem for our OpenGL code is that we need certain GLX calls but their presence
* depends on the reported GLX client / server version and on the client / server extension list.
* Those don't have to be the same.
*
* In general the server GLX information should be used in case of indirect rendering. When direct
* rendering is used, the OpenGL client library is responsible for which GLX calls are available.
* Nvidia's OpenGL drivers are the best in terms of GLX features. At the moment of writing their
* 8762 drivers support 1.3 for the server and 1.4 for the client and they support lots of extensions.
* Unfortunately it is much more complicated for Mesa/DRI-based drivers and ATI's drivers.
* Both sets of drivers report a server version of 1.2 and the client version can be 1.3 or 1.4.
* Further, in case of at least ATI's drivers, one crucial extension needed for our pixel format code
* is only available in the list of server extensions and not in the client list.
*
* The versioning checks below try to take into account the comments from above.
*/
/* Depending on the use of direct or indirect rendering we need either the list of extensions
* exported by the client or by the server.
*/
if(WineGLInfo.glxDirect)
glx_extensions = WineGLInfo.glxClientExtensions;
else
glx_extensions = WineGLInfo.glxServerExtensions;
/* Based on the default opengl context we decide whether direct or indirect rendering is used.
* In case of indirect rendering we check if the GLX version of the server is 1.2 and else
* the client version is checked.
*/
if ((!WineGLInfo.glxDirect && !strcmp("1.2", WineGLInfo.glxServerVersion)) ||
(WineGLInfo.glxDirect && !strcmp("1.2", WineGLInfo.glxClientVersion)))
{
if (NULL != strstr(glx_extensions, "GLX_SGIX_fbconfig")) {
pglXChooseFBConfig = (void*)pglXGetProcAddressARB((const GLubyte *) "glXChooseFBConfigSGIX");
pglXGetFBConfigAttrib = (void*)pglXGetProcAddressARB((const GLubyte *) "glXGetFBConfigAttribSGIX");
pglXGetVisualFromFBConfig = (void*)pglXGetProcAddressARB((const GLubyte *) "glXGetVisualFromFBConfigSGIX");
} else {
ERR(" glx_version is %s and GLX_SGIX_fbconfig extension is unsupported. Expect problems.\n", WineGLInfo.glxClientVersion);
} else {
pglXChooseFBConfig = (void*)pglXGetProcAddressARB((const GLubyte *) "glXChooseFBConfig");
pglXGetFBConfigAttrib = (void*)pglXGetProcAddressARB((const GLubyte *) "glXGetFBConfigAttrib");
pglXGetVisualFromFBConfig = (void*)pglXGetProcAddressARB((const GLubyte *) "glXGetVisualFromFBConfig");
/* The mesa libGL client library seems to forward glXQueryDrawable to the Xserver, so only
* enable this function when the Xserver understand GLX 1.3 or newer
*/
if (!strcmp("1.2", WineGLInfo.glxServerVersion))
pglXQueryDrawable = NULL;
else
pglXQueryDrawable = wine_dlsym(RTLD_DEFAULT, "glXQueryDrawable", NULL, 0);
if (NULL != strstr(glx_extensions, "GLX_ATI_render_texture")) {
pglXBindTexImageARB = (void*)pglXGetProcAddressARB((const GLubyte *) "glXBindTexImageARB");
pglXReleaseTexImageARB = (void*)pglXGetProcAddressARB((const GLubyte *) "glXReleaseTexImageARB");
pglXDrawableAttribARB = (void*)pglXGetProcAddressARB((const GLubyte *) "glXDrawableAttribARB");
}
X11DRV_WineGL_LoadExtensions();
return (opengl_handle != NULL);
sym_not_found:
wine_dlclose(opengl_handle, NULL, 0);
opengl_handle = NULL;
return FALSE;
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
static inline Wine_GLContext *alloc_context(void)
{
Wine_GLContext *ret;
if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
{
ret->next = context_list;
if (context_list) context_list->prev = ret;
context_list = ret;
}
return ret;
}
static inline void free_context(Wine_GLContext *context)
{
if (context->next != NULL) context->next->prev = context->prev;
if (context->prev != NULL) context->prev->next = context->next;
else context_list = context->next;
HeapFree(GetProcessHeap(), 0, context);
}
static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
{
Wine_GLContext *ret;
if (!ctx) return NULL;
for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
return ret;
}
Francois Gouget
committed
/**
* get_hdc_from_Drawable (internal)
*
* For use by wglGetCurrentReadDCARB.
*/
static inline HDC get_hdc_from_Drawable(GLXDrawable d)
{
Wine_GLContext *ret;
for (ret = context_list; ret; ret = ret->next) {
if (d == ret->physDev->drawable) {
return ret->hdc;
}
}
return NULL;
}
static inline BOOL is_valid_context( Wine_GLContext *ctx )
{
Wine_GLContext *ptr;
for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
return (ptr != NULL);
}
static int describeContext(Wine_GLContext* ctx) {
int tmp;
int ctx_vis_id;
TRACE(" Context %p have (vis:%p):\n", ctx, ctx->vis);
pglXGetFBConfigAttrib(gdi_display, ctx->fb_conf, GLX_FBCONFIG_ID, &tmp);
TRACE(" - FBCONFIG_ID 0x%x\n", tmp);
pglXGetFBConfigAttrib(gdi_display, ctx->fb_conf, GLX_VISUAL_ID, &tmp);
TRACE(" - VISUAL_ID 0x%x\n", tmp);
ctx_vis_id = tmp;
return ctx_vis_id;
}
static int describeDrawable(Wine_GLContext* ctx, Drawable drawable) {
int tmp;
int nElements;
int attribList[3] = { GLX_FBCONFIG_ID, 0, None };
GLXFBConfig *fbCfgs;
if (pglXQueryDrawable == NULL) {
/** glXQueryDrawable not available so returns not supported */
return -1;
}
TRACE(" Drawable %p have :\n", (void*) drawable);
pglXQueryDrawable(gdi_display, drawable, GLX_WIDTH, (unsigned int*) &tmp);
TRACE(" - WIDTH as %d\n", tmp);
pglXQueryDrawable(gdi_display, drawable, GLX_HEIGHT, (unsigned int*) &tmp);
TRACE(" - HEIGHT as %d\n", tmp);
pglXQueryDrawable(gdi_display, drawable, GLX_FBCONFIG_ID, (unsigned int*) &tmp);
TRACE(" - FBCONFIG_ID as 0x%x\n", tmp);
attribList[1] = tmp;
fbCfgs = pglXChooseFBConfig(gdi_display, DefaultScreen(gdi_display), attribList, &nElements);
if (fbCfgs == NULL) {
return -1;
}
pglXGetFBConfigAttrib(gdi_display, fbCfgs[0], GLX_VISUAL_ID, &tmp);
TRACE(" - VISUAL_ID as 0x%x\n", tmp);
XFree(fbCfgs);
return tmp;
}
static int ConvertAttribWGLtoGLX(const int* iWGLAttr, int* oGLXAttr, Wine_GLPBuffer* pbuf) {
int nAttribs = 0;
unsigned cur = 0;
int pop;
int isColor = 0;
int wantColorBits = 0;
int sz_alpha = 0;
/* The list of WGL attributes is allowed to be NULL, so don't return -1 (error) but just 0 */
if(iWGLAttr == NULL)
return 0;
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
while (0 != iWGLAttr[cur]) {
TRACE("pAttr[%d] = %x\n", cur, iWGLAttr[cur]);
switch (iWGLAttr[cur]) {
case WGL_COLOR_BITS_ARB:
pop = iWGLAttr[++cur];
wantColorBits = pop; /** see end */
break;
case WGL_BLUE_BITS_ARB:
pop = iWGLAttr[++cur];
PUSH2(oGLXAttr, GLX_BLUE_SIZE, pop);
TRACE("pAttr[%d] = GLX_BLUE_SIZE: %d\n", cur, pop);
break;
case WGL_RED_BITS_ARB:
pop = iWGLAttr[++cur];
PUSH2(oGLXAttr, GLX_RED_SIZE, pop);
TRACE("pAttr[%d] = GLX_RED_SIZE: %d\n", cur, pop);
break;
case WGL_GREEN_BITS_ARB:
pop = iWGLAttr[++cur];
PUSH2(oGLXAttr, GLX_GREEN_SIZE, pop);
TRACE("pAttr[%d] = GLX_GREEN_SIZE: %d\n", cur, pop);
break;
case WGL_ALPHA_BITS_ARB:
pop = iWGLAttr[++cur];
sz_alpha = pop;
PUSH2(oGLXAttr, GLX_ALPHA_SIZE, pop);
TRACE("pAttr[%d] = GLX_ALPHA_SIZE: %d\n", cur, pop);
break;
case WGL_DEPTH_BITS_ARB:
pop = iWGLAttr[++cur];
PUSH2(oGLXAttr, GLX_DEPTH_SIZE, pop);
TRACE("pAttr[%d] = GLX_DEPTH_SIZE: %d\n", cur, pop);
break;
case WGL_STENCIL_BITS_ARB:
pop = iWGLAttr[++cur];
PUSH2(oGLXAttr, GLX_STENCIL_SIZE, pop);
TRACE("pAttr[%d] = GLX_STENCIL_SIZE: %d\n", cur, pop);
break;
case WGL_DOUBLE_BUFFER_ARB:
pop = iWGLAttr[++cur];
PUSH2(oGLXAttr, GLX_DOUBLEBUFFER, pop);
TRACE("pAttr[%d] = GLX_DOUBLEBUFFER: %d\n", cur, pop);
break;
case WGL_PIXEL_TYPE_ARB:
pop = iWGLAttr[++cur];
switch (pop) {
case WGL_TYPE_COLORINDEX_ARB: pop = GLX_COLOR_INDEX_BIT; isColor = 1; break ;
case WGL_TYPE_RGBA_ARB: pop = GLX_RGBA_BIT; break ;
case WGL_TYPE_RGBA_FLOAT_ATI: pop = GLX_RGBA_FLOAT_ATI_BIT; break ;
default:
ERR("unexpected PixelType(%x)\n", pop);
pop = 0;
}
PUSH2(oGLXAttr, GLX_RENDER_TYPE, pop);
TRACE("pAttr[%d] = GLX_RENDER_TYPE: %d\n", cur, pop);
break;
case WGL_SUPPORT_GDI_ARB:
pop = iWGLAttr[++cur];
/* We only support a limited number of formats which are all renderable by X (similar to GDI).
* Ignore this attribute to prevent us from not finding a match due to the limited
* amount of formats supported right now. This option could be matched to GLX_X_RENDERABLE
* but the issue is that when a program asks for no GDI support, there's no format we can return
* as all our supported formats are renderable by X.
*/
TRACE("pAttr[%d] = WGL_SUPPORT_GDI_ARB: %d\n", cur, pop);
break;
case WGL_DRAW_TO_BITMAP_ARB:
pop = iWGLAttr[++cur];
TRACE("pAttr[%d] = WGL_DRAW_TO_BITMAP_ARB: %d\n", cur, pop);
/* GLX_DRAWABLE_TYPE flags need to be OR'd together. See below. */
drawattrib |= GLX_PIXMAP_BIT;
}
break;
case WGL_DRAW_TO_WINDOW_ARB:
pop = iWGLAttr[++cur];
TRACE("pAttr[%d] = WGL_DRAW_TO_WINDOW_ARB: %d\n", cur, pop);
/* GLX_DRAWABLE_TYPE flags need to be OR'd together. See below. */
drawattrib |= GLX_WINDOW_BIT;
}
break;
case WGL_DRAW_TO_PBUFFER_ARB:
pop = iWGLAttr[++cur];
TRACE("pAttr[%d] = WGL_DRAW_TO_PBUFFER_ARB: %d\n", cur, pop);
/* GLX_DRAWABLE_TYPE flags need to be OR'd together. See below. */
drawattrib |= GLX_PBUFFER_BIT;
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
}
break;
case WGL_ACCELERATION_ARB:
case WGL_SUPPORT_OPENGL_ARB:
pop = iWGLAttr[++cur];
/** nothing to do, if we are here, supposing support Accelerated OpenGL */
TRACE("pAttr[%d] = WGL_SUPPORT_OPENGL_ARB: %d\n", cur, pop);
break;
case WGL_PBUFFER_LARGEST_ARB:
pop = iWGLAttr[++cur];
PUSH2(oGLXAttr, GLX_LARGEST_PBUFFER, pop);
TRACE("pAttr[%d] = GLX_LARGEST_PBUFFER: %x\n", cur, pop);
break;
case WGL_SAMPLE_BUFFERS_ARB:
pop = iWGLAttr[++cur];
PUSH2(oGLXAttr, GLX_SAMPLE_BUFFERS_ARB, pop);
TRACE("pAttr[%d] = GLX_SAMPLE_BUFFERS_ARB: %x\n", cur, pop);
break;
case WGL_SAMPLES_ARB:
pop = iWGLAttr[++cur];
PUSH2(oGLXAttr, GLX_SAMPLES_ARB, pop);
TRACE("pAttr[%d] = GLX_SAMPLES_ARB: %x\n", cur, pop);
break;
case WGL_TEXTURE_FORMAT_ARB:
case WGL_TEXTURE_TARGET_ARB:
case WGL_MIPMAP_TEXTURE_ARB:
TRACE("WGL_render_texture Attributes: %x as %x\n", iWGLAttr[cur], iWGLAttr[cur + 1]);
pop = iWGLAttr[++cur];
if (NULL == pbuf) {
ERR("trying to use GLX_Pbuffer Attributes without Pbuffer (was %x)\n", iWGLAttr[cur]);
}
if (use_render_texture_ati) {
/** nothing to do here */
}
else if (!use_render_texture_emulation) {
if (WGL_NO_TEXTURE_ARB != pop) {
ERR("trying to use WGL_render_texture Attributes without support (was %x)\n", iWGLAttr[cur]);
return -1; /** error: don't support it */
} else {
PUSH2(oGLXAttr, GLX_X_RENDERABLE, pop);
drawattrib |= GLX_PBUFFER_BIT;
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
}
}
break ;
case WGL_BIND_TO_TEXTURE_RGB_ARB:
case WGL_BIND_TO_TEXTURE_RGBA_ARB:
pop = iWGLAttr[++cur];
/** cannot be converted, see direct handling on
* - wglGetPixelFormatAttribivARB
* TODO: wglChoosePixelFormat
*/
break ;
default:
FIXME("unsupported %x WGL Attribute\n", iWGLAttr[cur]);
break;
}
++cur;
}
/**
* Trick as WGL_COLOR_BITS_ARB != GLX_BUFFER_SIZE
* WGL_COLOR_BITS_ARB + WGL_ALPHA_BITS_ARB == GLX_BUFFER_SIZE
*
* WGL_COLOR_BITS_ARB
* The number of color bitplanes in each color buffer. For RGBA
* pixel types, it is the size of the color buffer, excluding the
* alpha bitplanes. For color-index pixels, it is the size of the
* color index buffer.
*
* GLX_BUFFER_SIZE
* This attribute defines the number of bits per color buffer.
* For GLX FBConfigs that correspond to a PseudoColor or StaticColor visual,
* this is equal to the depth value reported in the X11 visual.
* For GLX FBConfigs that correspond to TrueColor or DirectColor visual,
* this is the sum of GLX_RED_SIZE, GLX_GREEN_SIZE, GLX_BLUE_SIZE, and GLX_ALPHA_SIZE.
*
*/
if (0 < wantColorBits) {
if (!isColor) {
wantColorBits += sz_alpha;
}
if (32 < wantColorBits) {
ERR("buggy %d GLX_BUFFER_SIZE default to 32\n", wantColorBits);
wantColorBits = 32;
}
PUSH2(oGLXAttr, GLX_BUFFER_SIZE, wantColorBits);
TRACE("pAttr[%d] = WGL_COLOR_BITS_ARB: %d\n", cur, wantColorBits);
}
/* Apply the OR'd drawable type bitmask now. */
if (drawattrib) {
PUSH2(oGLXAttr, GLX_DRAWABLE_TYPE, drawattrib);
TRACE("pAttr[?] = GLX_DRAWABLE_TYPE: %#x\n", drawattrib);
}
return nAttribs;
}
static BOOL get_fbconfig_from_visualid(Display *display, Visual *visual, int *fmt_id, int *fmt_index)
{
GLXFBConfig* cfgs = NULL;
int i;
int nCfgs;
int tmp_fmt_id;
int tmp_vis_id;
VisualID visualid;
ERR("Invalid display or visual\n");
}
visualid = XVisualIDFromVisual(visual);
/* Get a list of all available framebuffer configurations */
cfgs = pglXGetFBConfigs(display, DefaultScreen(display), &nCfgs);
if (NULL == cfgs || 0 == nCfgs) {
ERR("glXChooseFBConfig returns NULL\n");
if(cfgs != NULL) XFree(cfgs);
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
}
/* Find the requested offscreen format and count the number of offscreen formats */
for(i=0; i<nCfgs; i++) {
pglXGetFBConfigAttrib(display, cfgs[i], GLX_VISUAL_ID, &tmp_vis_id);
pglXGetFBConfigAttrib(display, cfgs[i], GLX_FBCONFIG_ID, &tmp_fmt_id);
/* We are looking up the GLX index of our main visual and have found it :) */
if(visualid == tmp_vis_id) {
TRACE("Found FBCONFIG_ID 0x%x at index %d for VISUAL_ID 0x%x\n", tmp_fmt_id, i, tmp_vis_id);
XFree(cfgs);
*fmt_id = tmp_fmt_id;
*fmt_index = i;
return TRUE;
}
}
ERR("No fbconfig found for Wine's main visual (0x%lx), expect problems!\n", visualid);
XFree(cfgs);
return FALSE;
}
static BOOL init_formats(Display *display, int screen, Visual *visual)
{
int fmt_id, fmt_index;
/* Locate the fbconfig correspondig to our main visual */
if(!get_fbconfig_from_visualid(display, visual, &fmt_id, &fmt_index)) {
ERR("Can't get the FBCONFIG_ID for the main visual, expect problems!\n");
return FALSE;
}
/* Put Wine's internal format at the first index */
WineGLPixelFormatList[0].iPixelFormat = 1;
WineGLPixelFormatList[0].fbconfig = fmt_id;
WineGLPixelFormatList[0].fmt_index = fmt_index;
WineGLPixelFormatListSize = 1;
/* In the future test for compatible formats here */
return TRUE;
}
/* GLX can advertise dozens of different pixelformats including offscreen and onscreen ones.
* In our WGL implementation we only support a subset of these formats namely the format of
* Wine's main visual and offscreen formats (if they are available).
* This function converts a WGL format to its corresponding GLX one. It returns the index (zero-based)
* into the GLX FB config table and it returns the number of supported WGL formats in fmt_count.
*/
static BOOL ConvertPixelFormatWGLtoGLX(Display *display, int iPixelFormat, int *fmt_index, int *fmt_count)
Chris Robinson
committed
int ret;
/* Init the list of pixel formats when we need it */
if(!WineGLPixelFormatListSize)
init_formats(display, DefaultScreen(display), visual);
if((iPixelFormat <= 0) || (iPixelFormat > WineGLPixelFormatListSize)) {
ERR("invalid iPixelFormat %d\n", iPixelFormat);
Chris Robinson
committed
ret = FALSE;
*fmt_index = -1;
}
else {
ret = TRUE;
*fmt_index = WineGLPixelFormatList[iPixelFormat-1].fmt_index;
*fmt_count = WineGLPixelFormatListSize;
TRACE("Returning fmt_index=%d, fmt_count=%d for iPixelFormat=%d\n", *fmt_index, *fmt_count, iPixelFormat);
Chris Robinson
committed
return ret;
}
/* Search our internal pixelformat list for the WGL format corresponding to the given fbconfig */
static int ConvertPixelFormatGLXtoWGL(Display *display, int fbconfig)
{
int i;
/* Init the list of pixel formats when we need it */
if(!WineGLPixelFormatListSize)
init_formats(display, DefaultScreen(display), visual);
for(i=0; i<WineGLPixelFormatListSize; i++) {
if(WineGLPixelFormatList[i].fbconfig == fbconfig) {
TRACE("Returning iPixelFormat %d for fbconfig 0x%x\n", WineGLPixelFormatList[i].iPixelFormat, fbconfig);
return WineGLPixelFormatList[i].iPixelFormat;
}
}
TRACE("No compatible format found for FBCONFIG_ID=0x%x\n", fbconfig);
return 0;
/**
* X11DRV_ChoosePixelFormat
*
Francois Gouget
committed
* Equivalent to glXChooseVisual.
*/
int X11DRV_ChoosePixelFormat(X11DRV_PDEVICE *physDev,
GLXFBConfig* cfgs = NULL;
int ret = 0;
int value = 0;
if (!has_opengl()) {
ERR("No libGL on this box - disabling OpenGL support !\n");
return 0;
}
TRACE("(%p,%p)\n", physDev, ppfd);
dump_PIXELFORMATDESCRIPTOR((const PIXELFORMATDESCRIPTOR *) ppfd);
wine_tsx11_lock();
if(!visual) {
ERR("Can't get an opengl visual!\n");
goto choose_exit;
}
/* Get a list containing all supported FB configurations */
cfgs = pglXGetFBConfigs(gdi_display, DefaultScreen(gdi_display), &nCfgs);
if (NULL == cfgs || 0 == nCfgs) {
ERR("glXGetFBConfigs returns NULL (glError: %d)\n", pglGetError());
/* In case an fbconfig was found, check if it matches to the requirements of the ppfd */
if(!ConvertPixelFormatWGLtoGLX(gdi_display, 1 /* main visual */, &fmt_index, &value)) {
ERR("Can't find a matching FBCONFIG_ID for VISUAL_ID 0x%lx!\n", visual->visualid);
int dwFlags = 0;
int iPixelType = 0;
int value = 0;
/* Pixel type */
pglXGetFBConfigAttrib(gdi_display, cfgs[fmt_index], GLX_RENDER_TYPE, &value);
if (value & GLX_RGBA_BIT)
iPixelType = PFD_TYPE_RGBA;
else
iPixelType = PFD_TYPE_COLORINDEX;
if (ppfd->iPixelType != iPixelType) {
TRACE("pixel type mismatch\n");
pglXGetFBConfigAttrib(gdi_display, cfgs[fmt_index], GLX_DOUBLEBUFFER, &value); if (value) dwFlags |= PFD_DOUBLEBUFFER;
if (!(ppfd->dwFlags & PFD_DOUBLEBUFFER_DONTCARE) && (ppfd->dwFlags & PFD_DOUBLEBUFFER)) {
if (!(dwFlags & PFD_DOUBLEBUFFER)) {
TRACE("dbl buffer mismatch\n");
goto choose_exit;
}
}
pglXGetFBConfigAttrib(gdi_display, cfgs[fmt_index], GLX_STEREO, &value); if (value) dwFlags |= PFD_STEREO;
if (!(ppfd->dwFlags & PFD_STEREO_DONTCARE) && (ppfd->dwFlags & PFD_STEREO)) {
if (!(dwFlags & PFD_STEREO)) {
TRACE("stereo mismatch\n");