indirect.c revision 1b5d61b8
1/*
2 * File: indirect.c
3 * Purpose: A GLX implementation that uses Windows OpenGL library
4 *
5 * Authors: Alexander Gottwald
6 *          Jon TURNEY
7 *
8 * Copyright (c) Jon TURNEY 2009
9 * Copyright (c) Alexander Gottwald 2004
10 *
11 * Portions of this file are copied from GL/apple/indirect.c,
12 * which contains the following copyright:
13 *
14 * Copyright (c) 2007, 2008, 2009 Apple Inc.
15 * Copyright (c) 2004 Torrey T. Lyons. All Rights Reserved.
16 * Copyright (c) 2002 Greg Parker. All Rights Reserved.
17 *
18 * Portions of this file are copied from Mesa's xf86glx.c,
19 * which contains the following copyright:
20 *
21 * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
22 * All Rights Reserved.
23 *
24 *
25 * Permission is hereby granted, free of charge, to any person obtaining a
26 * copy of this software and associated documentation files (the "Software"),
27 * to deal in the Software without restriction, including without limitation
28 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
29 * and/or sell copies of the Software, and to permit persons to whom the
30 * Software is furnished to do so, subject to the following conditions:
31 *
32 * The above copyright notice and this permission notice shall be included in
33 * all copies or substantial portions of the Software.
34 *
35 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
38 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
39 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
40 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
41 * DEALINGS IN THE SOFTWARE.
42 */
43
44/*
45  TODO:
46  - hook up remaining unimplemented extensions
47  - research what guarantees glXWaitX, glXWaitGL are supposed to offer, and implement then
48    using GdiFlush and/or glFinish
49  - pbuffer clobbering: we don't get async notification, but can we arrange to emit the
50    event when we notice it's been clobbered? at the very least, check if it's been clobbered
51    before using it?
52  - XGetImage() doesn't work on pixmaps; need to do more work to make the format and location
53    of the native pixmap compatible
54  - implement GLX_EXT_texture_from_pixmap in terms of WGL_ARB_render_texture
55    (not quite straightforward as we will have to create a pbuffer and copy the pixmap texture
56     into it)
57*/
58
59/*
60  Assumptions:
61  - the __GLXConfig * we get handed back ones we are made (so we can extend the structure
62    with privates) and never get created inside the GLX core
63*/
64
65/*
66  MSDN clarifications:
67
68  It says SetPixelFormat()'s PIXELFORMATDESCRIPTOR pointer argument has no effect
69  except on metafiles, this seems to mean that as it's ok to supply NULL if the DC
70  is not for a metafile
71
72  wglMakeCurrent ignores the hdc if hglrc is NULL, so wglMakeCurrent(NULL, NULL)
73  is used to make no context current
74
75*/
76
77#ifdef HAVE_XWIN_CONFIG_H
78#include <xwin-config.h>
79#endif
80
81#include "glwindows.h"
82#include <glx/glxserver.h>
83#include <glx/glxutil.h>
84#include <GL/glxtokens.h>
85
86#include <winpriv.h>
87#include <wgl_ext_api.h>
88#include <winglobals.h>
89#include <indirect.h>
90
91/* Not yet in w32api */
92#ifndef PFD_SUPPORT_DIRECTDRAW
93#define PFD_SUPPORT_DIRECTDRAW   0x00002000
94#endif
95#ifndef PFD_DIRECT3D_ACCELERATED
96#define PFD_DIRECT3D_ACCELERATED 0x00004000
97#endif
98#ifndef PFD_SUPPORT_COMPOSITION
99#define PFD_SUPPORT_COMPOSITION  0x00008000
100#endif
101
102
103/* ---------------------------------------------------------------------- */
104/*
105 * Various debug helpers
106 */
107
108#define GLWIN_DEBUG_HWND(hwnd)  \
109    if (glxWinDebugSettings.dumpHWND) { \
110        char buffer[1024]; \
111        if (GetWindowText(hwnd, buffer, sizeof(buffer))==0) *buffer=0; \
112        GLWIN_DEBUG_MSG("Got HWND %p for window '%s'", hwnd, buffer); \
113    }
114
115glxWinDebugSettingsRec glxWinDebugSettings = { 0, 0, 0, 0, 0, 0 };
116
117static void
118glxWinInitDebugSettings(void)
119{
120    char *envptr;
121
122    envptr = getenv("GLWIN_ENABLE_DEBUG");
123    if (envptr != NULL)
124        glxWinDebugSettings.enableDebug = (atoi(envptr) == 1);
125
126    envptr = getenv("GLWIN_ENABLE_TRACE");
127    if (envptr != NULL)
128        glxWinDebugSettings.enableTrace = (atoi(envptr) == 1);
129
130    envptr = getenv("GLWIN_DUMP_PFD");
131    if (envptr != NULL)
132        glxWinDebugSettings.dumpPFD = (atoi(envptr) == 1);
133
134    envptr = getenv("GLWIN_DUMP_HWND");
135    if (envptr != NULL)
136        glxWinDebugSettings.dumpHWND = (atoi(envptr) == 1);
137
138    envptr = getenv("GLWIN_DUMP_DC");
139    if (envptr != NULL)
140        glxWinDebugSettings.dumpDC = (atoi(envptr) == 1);
141
142    envptr = getenv("GLWIN_ENABLE_GLCALL_TRACE");
143    if (envptr != NULL)
144        glxWinDebugSettings.enableGLcallTrace = (atoi(envptr) == 1);
145
146    envptr = getenv("GLWIN_ENABLE_WGLCALL_TRACE");
147    if (envptr != NULL)
148        glxWinDebugSettings.enableWGLcallTrace = (atoi(envptr) == 1);
149
150    envptr = getenv("GLWIN_DEBUG_ALL");
151    if (envptr != NULL) {
152        glxWinDebugSettings.enableDebug = 1;
153        glxWinDebugSettings.enableTrace = 1;
154        glxWinDebugSettings.dumpPFD = 1;
155        glxWinDebugSettings.dumpHWND = 1;
156        glxWinDebugSettings.dumpDC = 1;
157        glxWinDebugSettings.enableGLcallTrace = 1;
158        glxWinDebugSettings.enableWGLcallTrace = 1;
159    }
160}
161
162static
163const char *
164glxWinErrorMessage(void)
165{
166    static char errorbuffer[1024];
167    unsigned int last_error = GetLastError();
168
169    if (!FormatMessage
170        (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
171         FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, last_error, 0,
172         (LPTSTR) &errorbuffer, sizeof(errorbuffer), NULL)) {
173        snprintf(errorbuffer, sizeof(errorbuffer), "Unknown error");
174    }
175
176    if ((errorbuffer[strlen(errorbuffer) - 1] == '\n') ||
177        (errorbuffer[strlen(errorbuffer) - 1] == '\r'))
178        errorbuffer[strlen(errorbuffer) - 1] = 0;
179
180    sprintf(errorbuffer + strlen(errorbuffer), " (%08x)", last_error);
181
182    return errorbuffer;
183}
184
185static void pfdOut(const PIXELFORMATDESCRIPTOR * pfd);
186
187#define DUMP_PFD_FLAG(flag) \
188    if (pfd->dwFlags & flag) { \
189        ErrorF("%s%s", pipesym, #flag); \
190        pipesym = " | "; \
191    }
192
193static void
194pfdOut(const PIXELFORMATDESCRIPTOR * pfd)
195{
196    const char *pipesym = "";   /* will be set after first flag dump */
197
198    ErrorF("PIXELFORMATDESCRIPTOR:\n");
199    ErrorF("nSize = %u\n", pfd->nSize);
200    ErrorF("nVersion = %u\n", pfd->nVersion);
201    ErrorF("dwFlags = %u = {", (unsigned int)pfd->dwFlags);
202    DUMP_PFD_FLAG(PFD_DOUBLEBUFFER);
203    DUMP_PFD_FLAG(PFD_STEREO);
204    DUMP_PFD_FLAG(PFD_DRAW_TO_WINDOW);
205    DUMP_PFD_FLAG(PFD_DRAW_TO_BITMAP);
206    DUMP_PFD_FLAG(PFD_SUPPORT_GDI);
207    DUMP_PFD_FLAG(PFD_SUPPORT_OPENGL);
208    DUMP_PFD_FLAG(PFD_GENERIC_FORMAT);
209    DUMP_PFD_FLAG(PFD_NEED_PALETTE);
210    DUMP_PFD_FLAG(PFD_NEED_SYSTEM_PALETTE);
211    DUMP_PFD_FLAG(PFD_SWAP_EXCHANGE);
212    DUMP_PFD_FLAG(PFD_SWAP_COPY);
213    DUMP_PFD_FLAG(PFD_SWAP_LAYER_BUFFERS);
214    DUMP_PFD_FLAG(PFD_GENERIC_ACCELERATED);
215    DUMP_PFD_FLAG(PFD_SUPPORT_DIRECTDRAW);
216    DUMP_PFD_FLAG(PFD_DIRECT3D_ACCELERATED);
217    DUMP_PFD_FLAG(PFD_SUPPORT_COMPOSITION);
218    DUMP_PFD_FLAG(PFD_DEPTH_DONTCARE);
219    DUMP_PFD_FLAG(PFD_DOUBLEBUFFER_DONTCARE);
220    DUMP_PFD_FLAG(PFD_STEREO_DONTCARE);
221    ErrorF("}\n");
222
223    ErrorF("iPixelType = %hu = %s\n", pfd->iPixelType,
224           (pfd->iPixelType ==
225            PFD_TYPE_RGBA ? "PFD_TYPE_RGBA" : "PFD_TYPE_COLORINDEX"));
226    ErrorF("cColorBits = %hhu\n", pfd->cColorBits);
227    ErrorF("cRedBits = %hhu\n", pfd->cRedBits);
228    ErrorF("cRedShift = %hhu\n", pfd->cRedShift);
229    ErrorF("cGreenBits = %hhu\n", pfd->cGreenBits);
230    ErrorF("cGreenShift = %hhu\n", pfd->cGreenShift);
231    ErrorF("cBlueBits = %hhu\n", pfd->cBlueBits);
232    ErrorF("cBlueShift = %hhu\n", pfd->cBlueShift);
233    ErrorF("cAlphaBits = %hhu\n", pfd->cAlphaBits);
234    ErrorF("cAlphaShift = %hhu\n", pfd->cAlphaShift);
235    ErrorF("cAccumBits = %hhu\n", pfd->cAccumBits);
236    ErrorF("cAccumRedBits = %hhu\n", pfd->cAccumRedBits);
237    ErrorF("cAccumGreenBits = %hhu\n", pfd->cAccumGreenBits);
238    ErrorF("cAccumBlueBits = %hhu\n", pfd->cAccumBlueBits);
239    ErrorF("cAccumAlphaBits = %hhu\n", pfd->cAccumAlphaBits);
240    ErrorF("cDepthBits = %hhu\n", pfd->cDepthBits);
241    ErrorF("cStencilBits = %hhu\n", pfd->cStencilBits);
242    ErrorF("cAuxBuffers = %hhu\n", pfd->cAuxBuffers);
243    ErrorF("iLayerType = %hhu\n", pfd->iLayerType);
244    ErrorF("bReserved = %hhu\n", pfd->bReserved);
245    ErrorF("dwLayerMask = %u\n", (unsigned int)pfd->dwLayerMask);
246    ErrorF("dwVisibleMask = %u\n", (unsigned int)pfd->dwVisibleMask);
247    ErrorF("dwDamageMask = %u\n", (unsigned int)pfd->dwDamageMask);
248    ErrorF("\n");
249}
250
251static const char *
252visual_class_name(int cls)
253{
254    switch (cls) {
255    case GLX_STATIC_COLOR:
256        return "StaticColor";
257    case GLX_PSEUDO_COLOR:
258        return "PseudoColor";
259    case GLX_STATIC_GRAY:
260        return "StaticGray";
261    case GLX_GRAY_SCALE:
262        return "GrayScale";
263    case GLX_TRUE_COLOR:
264        return "TrueColor";
265    case GLX_DIRECT_COLOR:
266        return "DirectColor";
267    default:
268        return "-none-";
269    }
270}
271
272static const char *
273swap_method_name(int mthd)
274{
275    switch (mthd) {
276    case GLX_SWAP_EXCHANGE_OML:
277        return "xchg";
278    case GLX_SWAP_COPY_OML:
279        return "copy";
280    case GLX_SWAP_UNDEFINED_OML:
281        return "    ";
282    default:
283        return "????";
284    }
285}
286
287static void
288fbConfigsDump(unsigned int n, __GLXconfig * c)
289{
290    LogMessage(X_INFO, "%d fbConfigs\n", n);
291
292    if (g_iLogVerbose < 3)
293        return;
294    ErrorF("%d fbConfigs\n", n);
295    ErrorF
296        ("pxf vis  fb                      render         Ste                     aux    accum        MS    drawable             Group/\n");
297    ErrorF
298        ("idx  ID  ID VisualType Depth Lvl RGB CI DB Swap reo  R  G  B  A   Z  S  buf AR AG AB AA  bufs num  W P Pb  Float Trans Caveat\n");
299    ErrorF
300        ("-----------------------------------------------------------------------------------------------------------------------------\n");
301
302    while (c != NULL) {
303        unsigned int i = ((GLXWinConfig *) c)->pixelFormatIndex;
304
305        ErrorF("%3d %3x %3x "
306               "%-11s"
307               " %3d %3d   %s   %s  %s %s  %s  "
308               "%2d %2d %2d %2d  "
309               "%2d %2d  "
310               "%2d  "
311               "%2d %2d %2d %2d"
312               "   %2d   %2d"
313               "  %s %s %s "
314               "    %s   "
315               "  %s   "
316               "  %d %s"
317               "\n",
318               i, c->visualID, c->fbconfigID,
319               visual_class_name(c->visualType),
320               c->rgbBits ? c->rgbBits : c->indexBits,
321               c->level,
322               (c->renderType & GLX_RGBA_BIT) ? "y" : ".",
323               (c->renderType & GLX_COLOR_INDEX_BIT) ? "y" : ".",
324               c->doubleBufferMode ? "y" : ".",
325               swap_method_name(c->swapMethod),
326               c->stereoMode ? "y" : ".",
327               c->redBits, c->greenBits, c->blueBits, c->alphaBits,
328               c->depthBits, c->stencilBits,
329               c->numAuxBuffers,
330               c->accumRedBits, c->accumGreenBits, c->accumBlueBits,
331               c->accumAlphaBits, c->sampleBuffers, c->samples,
332               (c->drawableType & GLX_WINDOW_BIT) ? "y" : ".",
333               (c->drawableType & GLX_PIXMAP_BIT) ? "y" : ".",
334               (c->drawableType & GLX_PBUFFER_BIT) ? "y" : ".",
335               (c->renderType & (GLX_RGBA_FLOAT_BIT_ARB |
336                   GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT)) ? "y" : ".",
337               (c->transparentPixel != GLX_NONE_EXT) ? "y" : ".",
338               c->visualSelectGroup,
339               (c->visualRating == GLX_SLOW_VISUAL_EXT) ? "*" : " ");
340
341        c = c->next;
342    }
343}
344
345/* ---------------------------------------------------------------------- */
346/*
347 * Forward declarations
348 */
349
350static __GLXscreen *glxWinScreenProbe(ScreenPtr pScreen);
351static __GLXcontext *glxWinCreateContext(__GLXscreen * screen,
352                                         __GLXconfig * modes,
353                                         __GLXcontext * baseShareContext,
354                                         unsigned num_attribs,
355                                         const uint32_t * attribs, int *error);
356static __GLXdrawable *glxWinCreateDrawable(ClientPtr client,
357                                           __GLXscreen * screen,
358                                           DrawablePtr pDraw,
359                                           XID drawId,
360                                           int type,
361                                           XID glxDrawId, __GLXconfig * conf);
362
363static Bool glxWinRealizeWindow(WindowPtr pWin);
364static Bool glxWinUnrealizeWindow(WindowPtr pWin);
365static void glxWinCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg,
366                             RegionPtr prgnSrc);
367static Bool glxWinSetPixelFormat(HDC hdc, int bppOverride, int drawableTypeOverride,
368                                 __GLXscreen *screen, __GLXconfig *config);
369static HDC glxWinMakeDC(__GLXWinContext * gc, __GLXWinDrawable * draw,
370                        HDC * hdc, HWND * hwnd);
371static void glxWinReleaseDC(HWND hwnd, HDC hdc, __GLXWinDrawable * draw);
372
373static void glxWinCreateConfigs(HDC dc, glxWinScreen * screen);
374static void glxWinCreateConfigsExt(HDC hdc, glxWinScreen * screen);
375static int fbConfigToPixelFormat(__GLXconfig * mode,
376                                 PIXELFORMATDESCRIPTOR * pfdret,
377                                 int drawableTypeOverride);
378static int fbConfigToPixelFormatIndex(HDC hdc, __GLXconfig * mode,
379                                      int drawableTypeOverride,
380                                      glxWinScreen * winScreen);
381
382/* ---------------------------------------------------------------------- */
383/*
384 * The GLX provider
385 */
386
387__GLXprovider __glXWGLProvider = {
388    glxWinScreenProbe,
389    "Win32 native WGL",
390    NULL
391};
392
393void
394glxWinPushNativeProvider(void)
395{
396    GlxPushProvider(&__glXWGLProvider);
397}
398
399/* ---------------------------------------------------------------------- */
400/*
401 * Screen functions
402 */
403
404static void
405glxWinScreenDestroy(__GLXscreen * screen)
406{
407    GLWIN_DEBUG_MSG("glxWinScreenDestroy(%p)", screen);
408    __glXScreenDestroy(screen);
409    free(screen);
410}
411
412static int
413glxWinScreenSwapInterval(__GLXdrawable * drawable, int interval)
414{
415    BOOL ret = wglSwapIntervalEXTWrapper(interval);
416
417    if (!ret) {
418        ErrorF("wglSwapIntervalEXT interval %d failed:%s\n", interval,
419               glxWinErrorMessage());
420    }
421    return ret;
422}
423
424/*
425  Report the extensions split and formatted to avoid overflowing a line
426 */
427static void
428glxLogExtensions(const char *prefix, const char *extensions)
429{
430    int length = 0;
431    const char *strl;
432    char *str = strdup(extensions);
433
434    if (str == NULL) {
435        ErrorF("glxLogExtensions: xalloc error\n");
436        return;
437    }
438
439    strl = strtok(str, " ");
440    if (strl == NULL)
441        strl = "";
442    ErrorF("%s%s", prefix, strl);
443    length = strlen(prefix) + strlen(strl);
444
445    while (1) {
446        strl = strtok(NULL, " ");
447        if (strl == NULL)
448            break;
449
450        if (length + strlen(strl) + 1 > 120) {
451            ErrorF("\n");
452            ErrorF("%s", prefix);
453            length = strlen(prefix);
454        }
455        else {
456            ErrorF(" ");
457            length++;
458        }
459
460        ErrorF("%s", strl);
461        length = length + strlen(strl);
462    }
463
464    ErrorF("\n");
465
466    free(str);
467}
468
469/* This is called by GlxExtensionInit() asking the GLX provider if it can handle the screen... */
470static __GLXscreen *
471glxWinScreenProbe(ScreenPtr pScreen)
472{
473    glxWinScreen *screen;
474    const char *gl_extensions;
475    const char *gl_renderer;
476    const char *wgl_extensions;
477    HWND hwnd;
478    HDC hdc;
479    HGLRC hglrc;
480
481    GLWIN_DEBUG_MSG("glxWinScreenProbe");
482
483    glxWinInitDebugSettings();
484
485    if (pScreen == NULL)
486        return NULL;
487
488    if (!winCheckScreenAiglxIsSupported(pScreen)) {
489        LogMessage(X_ERROR,
490                   "AIGLX: No native OpenGL in modes with a root window\n");
491        return NULL;
492    }
493
494    screen = calloc(1, sizeof(glxWinScreen));
495
496    if (NULL == screen)
497        return NULL;
498
499    // Select the native GL implementation (WGL)
500    if (glWinSelectImplementation(1))
501        return NULL;
502
503    // create window class
504#define WIN_GL_TEST_WINDOW_CLASS "XWinGLTest"
505    {
506        static wATOM glTestWndClass = 0;
507
508        if (glTestWndClass == 0) {
509            WNDCLASSEX wc;
510
511            wc.cbSize = sizeof(WNDCLASSEX);
512            wc.style = CS_HREDRAW | CS_VREDRAW;
513            wc.lpfnWndProc = DefWindowProc;
514            wc.cbClsExtra = 0;
515            wc.cbWndExtra = 0;
516            wc.hInstance = GetModuleHandle(NULL);
517            wc.hIcon = 0;
518            wc.hCursor = 0;
519            wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
520            wc.lpszMenuName = NULL;
521            wc.lpszClassName = WIN_GL_TEST_WINDOW_CLASS;
522            wc.hIconSm = 0;
523            RegisterClassEx(&wc);
524        }
525    }
526
527    // create an invisible window for a scratch DC
528    hwnd = CreateWindowExA(0,
529                           WIN_GL_TEST_WINDOW_CLASS,
530                           "XWin GL Renderer Capabilities Test Window",
531                           0, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL),
532                           NULL);
533    if (hwnd == NULL)
534        LogMessage(X_ERROR,
535                   "AIGLX: Couldn't create a window for render capabilities testing\n");
536
537    hdc = GetDC(hwnd);
538
539    // we must set a pixel format before we can create a context, just use the first one...
540    SetPixelFormat(hdc, 1, NULL);
541    hglrc = wglCreateContext(hdc);
542    wglMakeCurrent(hdc, hglrc);
543
544    // initialize wgl extension proc pointers (don't call them before here...)
545    // (but we need to have a current context for them to be resolvable)
546    wglResolveExtensionProcs();
547
548    /* Dump out some useful information about the native renderer */
549    ErrorF("GL_VERSION:     %s\n", glGetString(GL_VERSION));
550    ErrorF("GL_VENDOR:      %s\n", glGetString(GL_VENDOR));
551    gl_renderer = (const char *) glGetString(GL_RENDERER);
552    ErrorF("GL_RENDERER:    %s\n", gl_renderer);
553    gl_extensions = (const char *) glGetString(GL_EXTENSIONS);
554    wgl_extensions = wglGetExtensionsStringARBWrapper(hdc);
555    if (!wgl_extensions)
556        wgl_extensions = "";
557
558    if (g_iLogVerbose >= 3) {
559        glxLogExtensions("GL_EXTENSIONS:  ", gl_extensions);
560        glxLogExtensions("WGL_EXTENSIONS: ", wgl_extensions);
561    }
562
563    if (strcasecmp(gl_renderer, "GDI Generic") == 0) {
564        free(screen);
565        LogMessage(X_ERROR,
566                   "AIGLX: Won't use generic native renderer as it is not accelerated\n");
567        goto error;
568    }
569
570    // Can you see the problem here?  The extensions string is DC specific
571    // Different DCs for windows on a multimonitor system driven by multiple cards
572    // might have completely different capabilities.  Of course, good luck getting
573    // those screens to be accelerated in XP and earlier...
574
575    {
576        //
577        // Based on the WGL extensions available, enable various GLX extensions
578        // XXX: make this table-driven ?
579        //
580        __glXInitExtensionEnableBits(screen->base.glx_enable_bits);
581
582        if (strstr(wgl_extensions, "WGL_ARB_make_current_read"))
583            screen->has_WGL_ARB_make_current_read = TRUE;
584        else
585            LogMessage(X_WARNING, "AIGLX: missing WGL_ARB_make_current_read\n");
586
587        if (strstr(gl_extensions, "GL_WIN_swap_hint")) {
588            __glXEnableExtension(screen->base.glx_enable_bits,
589                                 "GLX_MESA_copy_sub_buffer");
590            LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n");
591        }
592
593        if (strstr(wgl_extensions, "WGL_EXT_swap_control")) {
594            __glXEnableExtension(screen->base.glx_enable_bits,
595                                 "GLX_SGI_swap_control");
596            LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_swap_control\n");
597        }
598
599/*       // Hmm?  screen->texOffset */
600/*       if (strstr(wgl_extensions, "WGL_ARB_render_texture")) */
601/*         { */
602/*           __glXEnableExtension(screen->base.glx_enable_bits, "GLX_EXT_texture_from_pixmap"); */
603/*           LogMessage(X_INFO, "AIGLX: GLX_EXT_texture_from_pixmap backed by buffer objects\n"); */
604/*           screen->has_WGL_ARB_render_texture = TRUE; */
605/*         } */
606
607        if (strstr(wgl_extensions, "WGL_ARB_pbuffer"))
608            screen->has_WGL_ARB_pbuffer = TRUE;
609        else
610            LogMessage(X_WARNING, "AIGLX: missing WGL_ARB_pbuffer\n");
611
612        if (strstr(wgl_extensions, "WGL_ARB_multisample"))
613            screen->has_WGL_ARB_multisample = TRUE;
614        else
615            LogMessage(X_WARNING, "AIGLX: missing WGL_ARB_multisample\n");
616
617        screen->base.destroy = glxWinScreenDestroy;
618        screen->base.createContext = glxWinCreateContext;
619        screen->base.createDrawable = glxWinCreateDrawable;
620        screen->base.swapInterval = glxWinScreenSwapInterval;
621        screen->base.pScreen = pScreen;
622
623        // Creating the fbConfigs initializes screen->base.fbconfigs and screen->base.numFBConfigs
624        if (strstr(wgl_extensions, "WGL_ARB_pixel_format")) {
625            glxWinCreateConfigsExt(hdc, screen);
626
627            /*
628               Some graphics drivers appear to advertise WGL_ARB_pixel_format,
629               but it doesn't work usefully, so we have to be prepared for it
630               to fail and fall back to using DescribePixelFormat()
631             */
632            if (screen->base.numFBConfigs > 0) {
633                screen->has_WGL_ARB_pixel_format = TRUE;
634            }
635        }
636
637        if (screen->base.numFBConfigs <= 0) {
638            glxWinCreateConfigs(hdc, screen);
639            screen->has_WGL_ARB_pixel_format = FALSE;
640        }
641
642        /*
643           If we still didn't get any fbConfigs, we can't provide GLX for this screen
644         */
645        if (screen->base.numFBConfigs <= 0) {
646            free(screen);
647            LogMessage(X_ERROR,
648                       "AIGLX: No fbConfigs could be made from native OpenGL pixel formats\n");
649            goto error;
650        }
651
652        /* These will be set by __glXScreenInit */
653        screen->base.visuals = NULL;
654        screen->base.numVisuals = 0;
655
656        __glXScreenInit(&screen->base, pScreen);
657    }
658
659    wglMakeCurrent(NULL, NULL);
660    wglDeleteContext(hglrc);
661    ReleaseDC(hwnd, hdc);
662    DestroyWindow(hwnd);
663
664    // dump out fbConfigs now fbConfigIds and visualIDs have been assigned
665    fbConfigsDump(screen->base.numFBConfigs, screen->base.fbconfigs);
666
667    /* Wrap RealizeWindow, UnrealizeWindow and CopyWindow on this screen */
668    screen->RealizeWindow = pScreen->RealizeWindow;
669    pScreen->RealizeWindow = glxWinRealizeWindow;
670    screen->UnrealizeWindow = pScreen->UnrealizeWindow;
671    pScreen->UnrealizeWindow = glxWinUnrealizeWindow;
672    screen->CopyWindow = pScreen->CopyWindow;
673    pScreen->CopyWindow = glxWinCopyWindow;
674
675    // Note that WGL is active on this screen
676    winSetScreenAiglxIsActive(pScreen);
677
678    return &screen->base;
679
680 error:
681    // Something went wrong and we can't use the native GL implementation
682    // so make sure the mesa GL implementation is selected instead
683    glWinSelectImplementation(0);
684
685    return NULL;
686}
687
688/* ---------------------------------------------------------------------- */
689/*
690 * Window functions
691 */
692
693static Bool
694glxWinRealizeWindow(WindowPtr pWin)
695{
696    Bool result;
697    ScreenPtr pScreen = pWin->drawable.pScreen;
698    glxWinScreen *screenPriv = (glxWinScreen *) glxGetScreen(pScreen);
699
700    GLWIN_DEBUG_MSG("glxWinRealizeWindow");
701
702    /* Allow the window to be created (RootlessRealizeWindow is inside our wrap) */
703    pScreen->RealizeWindow = screenPriv->RealizeWindow;
704    result = pScreen->RealizeWindow(pWin);
705    pScreen->RealizeWindow = glxWinRealizeWindow;
706
707    return result;
708}
709
710static void
711glxWinCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
712{
713    __GLXWinDrawable *pGlxDraw;
714    ScreenPtr pScreen = pWindow->drawable.pScreen;
715    glxWinScreen *screenPriv = (glxWinScreen *) glxGetScreen(pScreen);
716
717    GLWIN_TRACE_MSG("glxWinCopyWindow pWindow %p", pWindow);
718
719    dixLookupResourceByType((void *) &pGlxDraw, pWindow->drawable.id,
720                            __glXDrawableRes, NullClient, DixUnknownAccess);
721
722    /*
723       Discard any CopyWindow requests if a GL drawing context is pointing at the window
724
725       For regions which are being drawn by GL, the shadow framebuffer doesn't have the
726       correct bits, so we wish to avoid shadow framebuffer damage occuring, which will
727       cause those incorrect bits to be transferred to the display....
728     */
729    if (pGlxDraw && pGlxDraw->drawContext) {
730        GLWIN_DEBUG_MSG("glxWinCopyWindow: discarding");
731        return;
732    }
733
734    GLWIN_DEBUG_MSG("glxWinCopyWindow - passing to hw layer");
735
736    pScreen->CopyWindow = screenPriv->CopyWindow;
737    pScreen->CopyWindow(pWindow, ptOldOrg, prgnSrc);
738    pScreen->CopyWindow = glxWinCopyWindow;
739}
740
741static Bool
742glxWinUnrealizeWindow(WindowPtr pWin)
743{
744    Bool result;
745    ScreenPtr pScreen = pWin->drawable.pScreen;
746    glxWinScreen *screenPriv = (glxWinScreen *) glxGetScreen(pScreen);
747
748    GLWIN_DEBUG_MSG("glxWinUnrealizeWindow");
749
750    pScreen->UnrealizeWindow = screenPriv->UnrealizeWindow;
751    result = pScreen->UnrealizeWindow(pWin);
752    pScreen->UnrealizeWindow = glxWinUnrealizeWindow;
753
754    return result;
755}
756
757/* ---------------------------------------------------------------------- */
758/*
759 * Drawable functions
760 */
761
762static GLboolean
763glxWinDrawableSwapBuffers(ClientPtr client, __GLXdrawable * base)
764{
765    HDC dc;
766    HWND hwnd;
767    BOOL ret;
768    __GLXWinDrawable *draw = (__GLXWinDrawable *) base;
769
770    /* Swap buffers on the last active context for drawing on the drawable */
771    if (draw->drawContext == NULL) {
772        GLWIN_TRACE_MSG("glxWinSwapBuffers - no context for drawable");
773        return GL_FALSE;
774    }
775
776    GLWIN_TRACE_MSG
777        ("glxWinSwapBuffers on drawable %p, last context %p (native ctx %p)",
778         base, draw->drawContext, draw->drawContext->ctx);
779
780    dc = glxWinMakeDC(draw->drawContext, draw, &dc, &hwnd);
781    if (dc == NULL)
782        return GL_FALSE;
783
784    ret = wglSwapLayerBuffers(dc, WGL_SWAP_MAIN_PLANE);
785
786    glxWinReleaseDC(hwnd, dc, draw);
787
788    if (!ret) {
789        ErrorF("wglSwapBuffers failed: %s\n", glxWinErrorMessage());
790        return GL_FALSE;
791    }
792
793    return GL_TRUE;
794}
795
796static void
797glxWinDrawableCopySubBuffer(__GLXdrawable * drawable,
798                            int x, int y, int w, int h)
799{
800    glAddSwapHintRectWINWrapper(x, y, w, h);
801    glxWinDrawableSwapBuffers(NULL, drawable);
802}
803
804static void
805glxWinDrawableDestroy(__GLXdrawable * base)
806{
807    __GLXWinDrawable *glxPriv = (__GLXWinDrawable *) base;
808
809    if (glxPriv->hPbuffer)
810        if (!wglDestroyPbufferARBWrapper(glxPriv->hPbuffer)) {
811            ErrorF("wglDestroyPbufferARB failed: %s\n", glxWinErrorMessage());
812        }
813
814    if (glxPriv->dibDC) {
815        // restore the default DIB
816        SelectObject(glxPriv->dibDC, glxPriv->hOldDIB);
817
818        if (!DeleteDC(glxPriv->dibDC)) {
819            ErrorF("DeleteDC failed: %s\n", glxWinErrorMessage());
820        }
821    }
822
823    if (glxPriv->hDIB) {
824        if (!CloseHandle(glxPriv->hSection)) {
825            ErrorF("CloseHandle failed: %s\n", glxWinErrorMessage());
826        }
827
828        if (!DeleteObject(glxPriv->hDIB)) {
829            ErrorF("DeleteObject failed: %s\n", glxWinErrorMessage());
830        }
831
832        ((PixmapPtr) glxPriv->base.pDraw)->devPrivate.ptr = glxPriv->pOldBits;
833    }
834
835    GLWIN_DEBUG_MSG("glxWinDestroyDrawable");
836    free(glxPriv);
837}
838
839static __GLXdrawable *
840glxWinCreateDrawable(ClientPtr client,
841                     __GLXscreen * screen,
842                     DrawablePtr pDraw,
843                     XID drawId, int type, XID glxDrawId, __GLXconfig * conf)
844{
845    __GLXWinDrawable *glxPriv;
846
847    glxPriv = malloc(sizeof *glxPriv);
848
849    if (glxPriv == NULL)
850        return NULL;
851
852    memset(glxPriv, 0, sizeof *glxPriv);
853
854    if (!__glXDrawableInit
855        (&glxPriv->base, screen, pDraw, type, glxDrawId, conf)) {
856        free(glxPriv);
857        return NULL;
858    }
859
860    glxPriv->base.destroy = glxWinDrawableDestroy;
861    glxPriv->base.swapBuffers = glxWinDrawableSwapBuffers;
862    glxPriv->base.copySubBuffer = glxWinDrawableCopySubBuffer;
863    // glxPriv->base.waitX  what are these for?
864    // glxPriv->base.waitGL
865
866    GLWIN_DEBUG_MSG("glxWinCreateDrawable %p", glxPriv);
867
868    return &glxPriv->base;
869}
870
871void
872glxWinDeferredCreateDrawable(__GLXWinDrawable *draw, __GLXconfig *config)
873{
874    switch (draw->base.type) {
875    case GLX_DRAWABLE_WINDOW:
876    {
877        WindowPtr pWin = (WindowPtr) draw->base.pDraw;
878
879        if (!(config->drawableType & GLX_WINDOW_BIT)) {
880            ErrorF
881                ("glxWinDeferredCreateDrawable: tried to create a GLX_DRAWABLE_WINDOW drawable with a fbConfig which doesn't have drawableType GLX_WINDOW_BIT\n");
882        }
883
884        if (pWin == NULL) {
885            GLWIN_DEBUG_MSG("Deferring until X window is created");
886            return;
887        }
888
889        GLWIN_DEBUG_MSG("glxWinDeferredCreateDrawable: pWin %p", pWin);
890
891        if (winGetWindowInfo(pWin) == NULL) {
892            GLWIN_DEBUG_MSG("Deferring until native window is created");
893            return;
894        }
895    }
896    break;
897
898    case GLX_DRAWABLE_PBUFFER:
899    {
900        if (draw->hPbuffer == NULL) {
901            __GLXscreen *screen;
902            glxWinScreen *winScreen;
903            int pixelFormat;
904
905            // XXX: which DC are we supposed to use???
906            HDC screenDC = GetDC(NULL);
907
908            if (!(config->drawableType & GLX_PBUFFER_BIT)) {
909                ErrorF
910                    ("glxWinDeferredCreateDrawable: tried to create a GLX_DRAWABLE_PBUFFER drawable with a fbConfig which doesn't have drawableType GLX_PBUFFER_BIT\n");
911            }
912
913            screen = glxGetScreen(screenInfo.screens[draw->base.pDraw->pScreen->myNum]);
914            winScreen = (glxWinScreen *) screen;
915
916            pixelFormat =
917                fbConfigToPixelFormatIndex(screenDC, config,
918                                           GLX_PBUFFER_BIT, winScreen);
919            if (pixelFormat == 0) {
920                return;
921            }
922
923            draw->hPbuffer =
924                wglCreatePbufferARBWrapper(screenDC, pixelFormat,
925                                           draw->base.pDraw->width,
926                                           draw->base.pDraw->height, NULL);
927            ReleaseDC(NULL, screenDC);
928
929            if (draw->hPbuffer == NULL) {
930                ErrorF("wglCreatePbufferARBWrapper error: %s\n",
931                       glxWinErrorMessage());
932                return;
933            }
934
935            GLWIN_DEBUG_MSG
936                ("glxWinDeferredCreateDrawable: pBuffer %p created for drawable %p",
937                 draw->hPbuffer, draw);
938        }
939    }
940    break;
941
942    case GLX_DRAWABLE_PIXMAP:
943    {
944        if (draw->dibDC == NULL) {
945            BITMAPINFOHEADER bmpHeader;
946            void *pBits;
947            __GLXscreen *screen;
948            DWORD size;
949            char name[MAX_PATH];
950
951            memset(&bmpHeader, 0, sizeof(BITMAPINFOHEADER));
952            bmpHeader.biSize = sizeof(BITMAPINFOHEADER);
953            bmpHeader.biWidth = draw->base.pDraw->width;
954            bmpHeader.biHeight = draw->base.pDraw->height;
955            bmpHeader.biPlanes = 1;
956            bmpHeader.biBitCount = draw->base.pDraw->bitsPerPixel;
957            bmpHeader.biCompression = BI_RGB;
958
959            if (!(config->drawableType & GLX_PIXMAP_BIT)) {
960                ErrorF
961                    ("glxWinDeferredCreateDrawable: tried to create a GLX_DRAWABLE_PIXMAP drawable with a fbConfig which doesn't have drawableType GLX_PIXMAP_BIT\n");
962            }
963
964            draw->dibDC = CreateCompatibleDC(NULL);
965            if (draw->dibDC == NULL) {
966                ErrorF("CreateCompatibleDC error: %s\n", glxWinErrorMessage());
967                return;
968            }
969
970#define RASTERWIDTHBYTES(bmi) (((((bmi)->biWidth*(bmi)->biBitCount)+31)&~31)>>3)
971            size = bmpHeader.biHeight * RASTERWIDTHBYTES(&bmpHeader);
972            GLWIN_DEBUG_MSG("shared memory region size %zu + %u\n", sizeof(BITMAPINFOHEADER), (unsigned int)size);
973
974            // Create unique name for mapping based on XID
975            //
976            // XXX: not quite unique as potentially this name could be used in
977            // another server instance.  Not sure how to deal with that.
978            snprintf(name, sizeof(name), "Local\\CYGWINX_WINDOWSDRI_%08x", (unsigned int)draw->base.pDraw->id);
979            GLWIN_DEBUG_MSG("shared memory region name %s\n", name);
980
981            // Create a file mapping backed by the pagefile
982            draw->hSection = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
983                                               PAGE_READWRITE, 0, sizeof(BITMAPINFOHEADER) + size, name);
984            if (draw->hSection == NULL) {
985                ErrorF("CreateFileMapping error: %s\n", glxWinErrorMessage());
986                return;
987                }
988
989            draw->hDIB =
990                CreateDIBSection(draw->dibDC, (BITMAPINFO *) &bmpHeader,
991                                 DIB_RGB_COLORS, &pBits, draw->hSection, sizeof(BITMAPINFOHEADER));
992            if (draw->dibDC == NULL) {
993                ErrorF("CreateDIBSection error: %s\n", glxWinErrorMessage());
994                return;
995            }
996
997            // Store a copy of the BITMAPINFOHEADER at the start of the shared
998            // memory for the information of the receiving process
999            {
1000                LPVOID pData = MapViewOfFile(draw->hSection, FILE_MAP_WRITE, 0, 0, 0);
1001                memcpy(pData, (void *)&bmpHeader, sizeof(BITMAPINFOHEADER));
1002                UnmapViewOfFile(pData);
1003            }
1004
1005            // XXX: CreateDIBSection insists on allocating the bitmap memory for us, so we're going to
1006            // need some jiggery pokery to point the underlying X Drawable's bitmap at the same set of bits
1007            // so that they can be read with XGetImage as well as glReadPixels, assuming the formats are
1008            // even compatible ...
1009            draw->pOldBits = ((PixmapPtr) draw->base.pDraw)->devPrivate.ptr;
1010            ((PixmapPtr) draw->base.pDraw)->devPrivate.ptr = pBits;
1011
1012            // Select the DIB into the DC
1013            draw->hOldDIB = SelectObject(draw->dibDC, draw->hDIB);
1014            if (!draw->hOldDIB) {
1015                ErrorF("SelectObject error: %s\n", glxWinErrorMessage());
1016            }
1017
1018            screen = glxGetScreen(screenInfo.screens[draw->base.pDraw->pScreen->myNum]);
1019
1020            // Set the pixel format of the bitmap
1021            glxWinSetPixelFormat(draw->dibDC,
1022                                 draw->base.pDraw->bitsPerPixel,
1023                                 GLX_PIXMAP_BIT,
1024                                 screen,
1025                                 config);
1026
1027            GLWIN_DEBUG_MSG
1028                ("glxWinDeferredCreateDrawable: DIB bitmap %p created for drawable %p",
1029                 draw->hDIB, draw);
1030        }
1031    }
1032    break;
1033
1034    default:
1035    {
1036        ErrorF
1037            ("glxWinDeferredCreateDrawable: tried to attach unhandled drawable type %d\n",
1038             draw->base.type);
1039        return;
1040    }
1041    }
1042}
1043
1044/* ---------------------------------------------------------------------- */
1045/*
1046 * Texture functions
1047 */
1048
1049static
1050    int
1051glxWinBindTexImage(__GLXcontext * baseContext,
1052                   int buffer, __GLXdrawable * pixmap)
1053{
1054    ErrorF("glxWinBindTexImage: not implemented\n");
1055    return FALSE;
1056}
1057
1058static
1059    int
1060glxWinReleaseTexImage(__GLXcontext * baseContext,
1061                      int buffer, __GLXdrawable * pixmap)
1062{
1063    ErrorF(" glxWinReleaseTexImage: not implemented\n");
1064    return FALSE;
1065}
1066
1067/* ---------------------------------------------------------------------- */
1068/*
1069 * Lazy update context implementation
1070 *
1071 * WGL contexts are created for a specific HDC, so we cannot create the WGL
1072 * context in glxWinCreateContext(), we must defer creation until the context
1073 * is actually used on a specifc drawable which is connected to a native window,
1074 * pbuffer or DIB
1075 *
1076 * The WGL context may be used on other, compatible HDCs, so we don't need to
1077 * recreate it for every new native window
1078 *
1079 * XXX: I wonder why we can't create the WGL context on the screen HDC ?
1080 * Basically we assume all HDCs are compatible at the moment: if they are not
1081 * we are in a muddle, there was some code in the old implementation to attempt
1082 * to transparently migrate a context to a new DC by copying state and sharing
1083 * lists with the old one...
1084 */
1085
1086static Bool
1087glxWinSetPixelFormat(HDC hdc, int bppOverride, int drawableTypeOverride,
1088                     __GLXscreen *screen, __GLXconfig *config)
1089{
1090    glxWinScreen *winScreen = (glxWinScreen *) screen;
1091    GLXWinConfig *winConfig = (GLXWinConfig *) config;
1092
1093    GLWIN_DEBUG_MSG("glxWinSetPixelFormat: pixelFormatIndex %d",
1094                    winConfig->pixelFormatIndex);
1095
1096    /*
1097       Normally, we can just use the the pixelFormatIndex corresponding
1098       to the fbconfig which has been specified by the client
1099     */
1100
1101    if (!
1102        ((bppOverride &&
1103          (bppOverride !=
1104           (config->redBits + config->greenBits + config->blueBits)))
1105         || ((config->drawableType & drawableTypeOverride) == 0))) {
1106        if (!SetPixelFormat(hdc, winConfig->pixelFormatIndex, NULL)) {
1107            ErrorF("SetPixelFormat error: %s\n", glxWinErrorMessage());
1108            return FALSE;
1109        }
1110
1111        return TRUE;
1112    }
1113
1114    /*
1115       However, in certain special cases this pixel format will be incompatible with the
1116       use we are going to put it to, so we need to re-evaluate the pixel format to use:
1117
1118       1) When PFD_DRAW_TO_BITMAP is set, ChoosePixelFormat() always returns a format with
1119       the cColorBits we asked for, so we need to ensure it matches the bpp of the bitmap
1120
1121       2) Applications may assume that visuals selected with glXChooseVisual() work with
1122       pixmap drawables (there is no attribute to explicitly query for pixmap drawable
1123       support as there is for glXChooseFBConfig())
1124       (it's arguable this is an error in the application, but we try to make it work)
1125
1126       pixmap rendering is always slow for us, so we don't want to choose those visuals
1127       by default, but if the actual drawable type we're trying to select the context
1128       on (drawableTypeOverride) isn't supported by the selected fbConfig, reconsider
1129       and see if we can find a suitable one...
1130     */
1131    ErrorF
1132        ("glxWinSetPixelFormat: having second thoughts: cColorbits %d, bppOveride %d; config->drawableType %d, drawableTypeOverride %d\n",
1133         (config->redBits + config->greenBits + config->blueBits), bppOverride,
1134         config->drawableType, drawableTypeOverride);
1135
1136    if (!winScreen->has_WGL_ARB_pixel_format) {
1137        PIXELFORMATDESCRIPTOR pfd;
1138        int pixelFormat;
1139
1140        /* convert fbConfig to PFD */
1141        if (fbConfigToPixelFormat(config, &pfd, drawableTypeOverride)) {
1142            ErrorF("glxWinSetPixelFormat: fbConfigToPixelFormat failed\n");
1143            return FALSE;
1144        }
1145
1146        if (glxWinDebugSettings.dumpPFD)
1147            pfdOut(&pfd);
1148
1149        if (bppOverride) {
1150            GLWIN_DEBUG_MSG("glxWinSetPixelFormat: Forcing bpp from %d to %d\n",
1151                            pfd.cColorBits, bppOverride);
1152            pfd.cColorBits = bppOverride;
1153        }
1154
1155        pixelFormat = ChoosePixelFormat(hdc, &pfd);
1156        if (pixelFormat == 0) {
1157            ErrorF("ChoosePixelFormat error: %s\n", glxWinErrorMessage());
1158            return FALSE;
1159        }
1160
1161        GLWIN_DEBUG_MSG("ChoosePixelFormat: chose pixelFormatIndex %d",
1162                        pixelFormat);
1163        ErrorF
1164            ("ChoosePixelFormat: chose pixelFormatIndex %d (rather than %d as originally planned)\n",
1165             pixelFormat, winConfig->pixelFormatIndex);
1166
1167        if (!SetPixelFormat(hdc, pixelFormat, &pfd)) {
1168            ErrorF("SetPixelFormat error: %s\n", glxWinErrorMessage());
1169            return FALSE;
1170        }
1171    }
1172    else {
1173        int pixelFormat = fbConfigToPixelFormatIndex(hdc, config,
1174                                                     drawableTypeOverride,
1175                                                     winScreen);
1176        if (pixelFormat == 0) {
1177            return FALSE;
1178        }
1179
1180        GLWIN_DEBUG_MSG("wglChoosePixelFormat: chose pixelFormatIndex %d",
1181                        pixelFormat);
1182        ErrorF
1183            ("wglChoosePixelFormat: chose pixelFormatIndex %d (rather than %d as originally planned)\n",
1184             pixelFormat, winConfig->pixelFormatIndex);
1185
1186        if (!SetPixelFormat(hdc, pixelFormat, NULL)) {
1187            ErrorF("SetPixelFormat error: %s\n", glxWinErrorMessage());
1188            return FALSE;
1189        }
1190    }
1191
1192    return TRUE;
1193}
1194
1195static HDC
1196glxWinMakeDC(__GLXWinContext * gc, __GLXWinDrawable * draw, HDC * hdc,
1197             HWND * hwnd)
1198{
1199    *hdc = NULL;
1200    *hwnd = NULL;
1201
1202    if (draw == NULL) {
1203        GLWIN_TRACE_MSG("No drawable for context %p (native ctx %p)", gc,
1204                        gc->ctx);
1205        return NULL;
1206    }
1207
1208    switch (draw->base.type) {
1209    case GLX_DRAWABLE_WINDOW:
1210    {
1211        WindowPtr pWin;
1212
1213        pWin = (WindowPtr) draw->base.pDraw;
1214        if (pWin == NULL) {
1215            GLWIN_TRACE_MSG("for drawable %p, no WindowPtr", pWin);
1216            return NULL;
1217        }
1218
1219        *hwnd = winGetWindowInfo(pWin);
1220
1221        if (*hwnd == NULL) {
1222            ErrorF("No HWND error: %s\n", glxWinErrorMessage());
1223            return NULL;
1224        }
1225
1226        *hdc = GetDC(*hwnd);
1227
1228        if (*hdc == NULL)
1229            ErrorF("GetDC error: %s\n", glxWinErrorMessage());
1230
1231        /* Check if the hwnd has changed... */
1232        if (*hwnd != gc->hwnd) {
1233            if (glxWinDebugSettings.enableTrace)
1234                GLWIN_DEBUG_HWND(*hwnd);
1235
1236            GLWIN_TRACE_MSG
1237                ("for context %p (native ctx %p), hWnd changed from %p to %p",
1238                 gc, gc->ctx, gc->hwnd, *hwnd);
1239            gc->hwnd = *hwnd;
1240
1241            /* We must select a pixelformat, but SetPixelFormat can only be called once for a window... */
1242            if (!glxWinSetPixelFormat(*hdc, 0, GLX_WINDOW_BIT, gc->base.pGlxScreen, gc->base.config)) {
1243                ErrorF("glxWinSetPixelFormat error: %s\n",
1244                       glxWinErrorMessage());
1245                ReleaseDC(*hwnd, *hdc);
1246                *hdc = NULL;
1247                return NULL;
1248            }
1249        }
1250    }
1251        break;
1252
1253    case GLX_DRAWABLE_PBUFFER:
1254    {
1255        *hdc = wglGetPbufferDCARBWrapper(draw->hPbuffer);
1256
1257        if (*hdc == NULL)
1258            ErrorF("GetDC (pbuffer) error: %s\n", glxWinErrorMessage());
1259    }
1260        break;
1261
1262    case GLX_DRAWABLE_PIXMAP:
1263    {
1264        *hdc = draw->dibDC;
1265    }
1266        break;
1267
1268    default:
1269    {
1270        ErrorF("glxWinMakeDC: tried to makeDC for unhandled drawable type %d\n",
1271               draw->base.type);
1272    }
1273    }
1274
1275    if (glxWinDebugSettings.dumpDC)
1276        GLWIN_DEBUG_MSG("Got HDC %p", *hdc);
1277
1278    return *hdc;
1279}
1280
1281static void
1282glxWinReleaseDC(HWND hwnd, HDC hdc, __GLXWinDrawable * draw)
1283{
1284    switch (draw->base.type) {
1285    case GLX_DRAWABLE_WINDOW:
1286    {
1287        ReleaseDC(hwnd, hdc);
1288    }
1289        break;
1290
1291    case GLX_DRAWABLE_PBUFFER:
1292    {
1293        if (!wglReleasePbufferDCARBWrapper(draw->hPbuffer, hdc)) {
1294            ErrorF("wglReleasePbufferDCARB error: %s\n", glxWinErrorMessage());
1295        }
1296    }
1297        break;
1298
1299    case GLX_DRAWABLE_PIXMAP:
1300    {
1301        // don't release DC, the memory DC lives as long as the bitmap
1302
1303        // We must ensure that all GDI drawing into the bitmap has completed
1304        // in case we subsequently access the bits from it
1305        GdiFlush();
1306    }
1307        break;
1308
1309    default:
1310    {
1311        ErrorF
1312            ("glxWinReleaseDC: tried to releaseDC for unhandled drawable type %d\n",
1313             draw->base.type);
1314    }
1315    }
1316}
1317
1318static void
1319glxWinDeferredCreateContext(__GLXWinContext * gc, __GLXWinDrawable * draw)
1320{
1321    HDC dc;
1322    HWND hwnd;
1323
1324    GLWIN_DEBUG_MSG
1325        ("glxWinDeferredCreateContext: attach context %p to drawable %p", gc,
1326         draw);
1327
1328    glxWinDeferredCreateDrawable(draw, gc->base.config);
1329
1330    dc = glxWinMakeDC(gc, draw, &dc, &hwnd);
1331    gc->ctx = wglCreateContext(dc);
1332    glxWinReleaseDC(hwnd, dc, draw);
1333
1334    if (gc->ctx == NULL) {
1335        ErrorF("wglCreateContext error: %s\n", glxWinErrorMessage());
1336        return;
1337    }
1338
1339    GLWIN_DEBUG_MSG
1340        ("glxWinDeferredCreateContext: attached context %p to native context %p drawable %p",
1341         gc, gc->ctx, draw);
1342
1343    // if the native context was created successfully, shareLists if needed
1344    if (gc->ctx && gc->shareContext) {
1345        GLWIN_DEBUG_MSG
1346            ("glxWinCreateContextReal shareLists with context %p (native ctx %p)",
1347             gc->shareContext, gc->shareContext->ctx);
1348
1349        if (!wglShareLists(gc->shareContext->ctx, gc->ctx)) {
1350            ErrorF("wglShareLists error: %s\n", glxWinErrorMessage());
1351        }
1352    }
1353}
1354
1355/* ---------------------------------------------------------------------- */
1356/*
1357 * Context functions
1358 */
1359
1360/* Context manipulation routines should return TRUE on success, FALSE on failure */
1361static int
1362glxWinContextMakeCurrent(__GLXcontext * base)
1363{
1364    __GLXWinContext *gc = (__GLXWinContext *) base;
1365    glxWinScreen *scr = (glxWinScreen *)base->pGlxScreen;
1366    BOOL ret;
1367    HDC drawDC;
1368    HDC readDC = NULL;
1369    __GLXdrawable *drawPriv;
1370    __GLXdrawable *readPriv = NULL;
1371    HWND hDrawWnd;
1372    HWND hReadWnd;
1373
1374    GLWIN_TRACE_MSG("glxWinContextMakeCurrent context %p (native ctx %p)", gc,
1375                    gc->ctx);
1376
1377    /* Keep a note of the last active context in the drawable */
1378    drawPriv = gc->base.drawPriv;
1379    ((__GLXWinDrawable *) drawPriv)->drawContext = gc;
1380
1381    if (gc->ctx == NULL) {
1382        glxWinDeferredCreateContext(gc, (__GLXWinDrawable *) drawPriv);
1383    }
1384
1385    if (gc->ctx == NULL) {
1386        ErrorF("glxWinContextMakeCurrent: Native context is NULL\n");
1387        return FALSE;
1388    }
1389
1390    drawDC =
1391        glxWinMakeDC(gc, (__GLXWinDrawable *) drawPriv, &drawDC, &hDrawWnd);
1392    if (drawDC == NULL) {
1393        ErrorF("glxWinMakeDC failed for drawDC\n");
1394        return FALSE;
1395    }
1396
1397    if ((gc->base.readPriv != NULL) && (gc->base.readPriv != gc->base.drawPriv)) {
1398        /*
1399         * We enable GLX_SGI_make_current_read unconditionally, but the
1400         * renderer might not support it. It's fairly rare to use this
1401         * feature so just error out if it can't work.
1402         */
1403        if (!scr->has_WGL_ARB_make_current_read)
1404            return FALSE;
1405
1406        /*
1407           If there is a separate read drawable, create a separate read DC, and
1408           use the wglMakeContextCurrent extension to make the context current drawing
1409           to one DC and reading from the other
1410         */
1411        readPriv = gc->base.readPriv;
1412        readDC =
1413            glxWinMakeDC(gc, (__GLXWinDrawable *) readPriv, &readDC, &hReadWnd);
1414        if (readDC == NULL) {
1415            ErrorF("glxWinMakeDC failed for readDC\n");
1416            glxWinReleaseDC(hDrawWnd, drawDC, (__GLXWinDrawable *) drawPriv);
1417            return FALSE;
1418        }
1419
1420        ret = wglMakeContextCurrentARBWrapper(drawDC, readDC, gc->ctx);
1421        if (!ret) {
1422            ErrorF("wglMakeContextCurrentARBWrapper error: %s\n",
1423                   glxWinErrorMessage());
1424        }
1425    }
1426    else {
1427        /* Otherwise, just use wglMakeCurrent */
1428        ret = wglMakeCurrent(drawDC, gc->ctx);
1429        if (!ret) {
1430            ErrorF("wglMakeCurrent error: %s\n", glxWinErrorMessage());
1431        }
1432    }
1433
1434    // apparently make current could fail if the context is current in a different thread,
1435    // but that shouldn't be able to happen in the current server...
1436
1437    glxWinReleaseDC(hDrawWnd, drawDC, (__GLXWinDrawable *) drawPriv);
1438    if (readDC)
1439        glxWinReleaseDC(hReadWnd, readDC, (__GLXWinDrawable *) readPriv);
1440
1441    return ret;
1442}
1443
1444static int
1445glxWinContextLoseCurrent(__GLXcontext * base)
1446{
1447    BOOL ret;
1448    __GLXWinContext *gc = (__GLXWinContext *) base;
1449
1450    GLWIN_TRACE_MSG("glxWinContextLoseCurrent context %p (native ctx %p)", gc,
1451                    gc->ctx);
1452
1453    /*
1454       An error seems to be reported if we try to make no context current
1455       if there is already no current context, so avoid doing that...
1456     */
1457    if (wglGetCurrentContext() != NULL) {
1458        ret = wglMakeCurrent(NULL, NULL);       /* We don't need a DC when setting no current context */
1459        if (!ret)
1460            ErrorF("glxWinContextLoseCurrent error: %s\n",
1461                   glxWinErrorMessage());
1462    }
1463
1464    return TRUE;
1465}
1466
1467static int
1468glxWinContextCopy(__GLXcontext * dst_base, __GLXcontext * src_base,
1469                  unsigned long mask)
1470{
1471    __GLXWinContext *dst = (__GLXWinContext *) dst_base;
1472    __GLXWinContext *src = (__GLXWinContext *) src_base;
1473    BOOL ret;
1474
1475    GLWIN_DEBUG_MSG("glxWinContextCopy");
1476
1477    ret = wglCopyContext(src->ctx, dst->ctx, mask);
1478    if (!ret) {
1479        ErrorF("wglCopyContext error: %s\n", glxWinErrorMessage());
1480    }
1481
1482    return ret;
1483}
1484
1485static void
1486glxWinContextDestroy(__GLXcontext * base)
1487{
1488    __GLXWinContext *gc = (__GLXWinContext *) base;
1489
1490    if (gc != NULL) {
1491        GLWIN_DEBUG_MSG("GLXcontext %p destroyed (native ctx %p)", base,
1492                        gc->ctx);
1493
1494        if (gc->ctx) {
1495            /* It's bad style to delete the context while it's still current */
1496            if (wglGetCurrentContext() == gc->ctx) {
1497                wglMakeCurrent(NULL, NULL);
1498            }
1499
1500            {
1501                BOOL ret = wglDeleteContext(gc->ctx);
1502
1503                if (!ret)
1504                    ErrorF("wglDeleteContext error: %s\n",
1505                           glxWinErrorMessage());
1506            }
1507
1508            gc->ctx = NULL;
1509        }
1510
1511        free(gc);
1512    }
1513}
1514
1515static __GLXcontext *
1516glxWinCreateContext(__GLXscreen * screen,
1517                    __GLXconfig * modes, __GLXcontext * baseShareContext,
1518                    unsigned num_attribs, const uint32_t * attribs, int *error)
1519{
1520    __GLXWinContext *context;
1521    __GLXWinContext *shareContext = (__GLXWinContext *) baseShareContext;
1522
1523    context = calloc(1, sizeof(__GLXWinContext));
1524
1525    if (!context)
1526        return NULL;
1527
1528    memset(context, 0, sizeof *context);
1529    context->base.destroy = glxWinContextDestroy;
1530    context->base.makeCurrent = glxWinContextMakeCurrent;
1531    context->base.loseCurrent = glxWinContextLoseCurrent;
1532    context->base.copy = glxWinContextCopy;
1533    context->base.bindTexImage = glxWinBindTexImage;
1534    context->base.releaseTexImage = glxWinReleaseTexImage;
1535    context->base.config = modes;
1536    context->base.pGlxScreen = screen;
1537
1538    // actual native GL context creation is deferred until attach()
1539    context->ctx = NULL;
1540    context->shareContext = shareContext;
1541
1542    GLWIN_DEBUG_MSG("GLXcontext %p created", context);
1543
1544    return &(context->base);
1545}
1546
1547/* ---------------------------------------------------------------------- */
1548/*
1549 * Utility functions
1550 */
1551
1552static int
1553GetShift(int mask)
1554{
1555    int shift = 0;
1556
1557    while ((mask &1) == 0) {
1558        shift++;
1559        mask >>=1;
1560    }
1561    return shift;
1562}
1563
1564static int
1565fbConfigToPixelFormat(__GLXconfig * mode, PIXELFORMATDESCRIPTOR * pfdret,
1566                      int drawableTypeOverride)
1567{
1568    PIXELFORMATDESCRIPTOR pfd = {
1569        sizeof(PIXELFORMATDESCRIPTOR),  /* size of this pfd */
1570        1,                      /* version number */
1571        PFD_SUPPORT_OPENGL,     /* support OpenGL */
1572        PFD_TYPE_RGBA,          /* RGBA type */
1573        24,                     /* 24-bit color depth */
1574        0, 0, 0, 0, 0, 0,       /* color bits ignored */
1575        0,                      /* no alpha buffer */
1576        0,                      /* shift bit ignored */
1577        0,                      /* no accumulation buffer */
1578        0, 0, 0, 0,             /* accum bits ignored */
1579        32,                     /* 32-bit z-buffer */
1580        0,                      /* no stencil buffer */
1581        0,                      /* no auxiliary buffer */
1582        PFD_MAIN_PLANE,         /* main layer */
1583        0,                      /* reserved */
1584        0, 0, 0                 /* layer masks ignored */
1585    };
1586
1587    if ((mode->drawableType | drawableTypeOverride) & GLX_WINDOW_BIT)
1588        pfd.dwFlags |= PFD_DRAW_TO_WINDOW;      /* support window */
1589
1590    if ((mode->drawableType | drawableTypeOverride) & GLX_PIXMAP_BIT)
1591        pfd.dwFlags |= (PFD_DRAW_TO_BITMAP | PFD_SUPPORT_GDI);  /* supports software rendering to bitmap */
1592
1593    if (mode->stereoMode) {
1594        pfd.dwFlags |= PFD_STEREO;
1595    }
1596    if (mode->doubleBufferMode) {
1597        pfd.dwFlags |= PFD_DOUBLEBUFFER;
1598    }
1599
1600    pfd.cColorBits = mode->redBits + mode->greenBits + mode->blueBits;
1601    pfd.cRedBits = mode->redBits;
1602    pfd.cRedShift = GetShift(mode->redMask);
1603    pfd.cGreenBits = mode->greenBits;
1604    pfd.cGreenShift = GetShift(mode->greenMask);
1605    pfd.cBlueBits = mode->blueBits;
1606    pfd.cBlueShift = GetShift(mode->blueMask);
1607    pfd.cAlphaBits = mode->alphaBits;
1608    pfd.cAlphaShift = GetShift(mode->alphaMask);
1609
1610    if (mode->visualType == GLX_TRUE_COLOR) {
1611        pfd.iPixelType = PFD_TYPE_RGBA;
1612        pfd.dwVisibleMask =
1613            (pfd.cRedBits << pfd.cRedShift) | (pfd.cGreenBits << pfd.cGreenShift) |
1614            (pfd.cBlueBits << pfd.cBlueShift) | (pfd.cAlphaBits << pfd.cAlphaShift);
1615    }
1616    else {
1617        pfd.iPixelType = PFD_TYPE_COLORINDEX;
1618        pfd.dwVisibleMask = mode->transparentIndex;
1619    }
1620
1621    pfd.cAccumBits =
1622        mode->accumRedBits + mode->accumGreenBits + mode->accumBlueBits +
1623        mode->accumAlphaBits;
1624    pfd.cAccumRedBits = mode->accumRedBits;
1625    pfd.cAccumGreenBits = mode->accumGreenBits;
1626    pfd.cAccumBlueBits = mode->accumBlueBits;
1627    pfd.cAccumAlphaBits = mode->accumAlphaBits;
1628
1629    pfd.cDepthBits = mode->depthBits;
1630    pfd.cStencilBits = mode->stencilBits;
1631    pfd.cAuxBuffers = mode->numAuxBuffers;
1632
1633    /* mode->level ? */
1634
1635    *pfdret = pfd;
1636
1637    return 0;
1638}
1639
1640#define SET_ATTR_VALUE(attr, value) { attribList[i++] = attr; attribList[i++] = value; assert(i < ARRAY_SIZE(attribList)); }
1641
1642static int
1643fbConfigToPixelFormatIndex(HDC hdc, __GLXconfig * mode,
1644                           int drawableTypeOverride, glxWinScreen * winScreen)
1645{
1646    UINT numFormats;
1647    unsigned int i = 0;
1648
1649    /* convert fbConfig to attr-value list  */
1650    int attribList[60];
1651
1652    SET_ATTR_VALUE(WGL_SUPPORT_OPENGL_ARB, TRUE);
1653    SET_ATTR_VALUE(WGL_PIXEL_TYPE_ARB,
1654                   (mode->visualType ==
1655                    GLX_TRUE_COLOR) ? WGL_TYPE_RGBA_ARB :
1656                   WGL_TYPE_COLORINDEX_ARB);
1657    SET_ATTR_VALUE(WGL_COLOR_BITS_ARB,
1658                   (mode->visualType ==
1659                    GLX_TRUE_COLOR) ? mode->rgbBits : mode->indexBits);
1660    SET_ATTR_VALUE(WGL_RED_BITS_ARB, mode->redBits);
1661    SET_ATTR_VALUE(WGL_GREEN_BITS_ARB, mode->greenBits);
1662    SET_ATTR_VALUE(WGL_BLUE_BITS_ARB, mode->blueBits);
1663    SET_ATTR_VALUE(WGL_ALPHA_BITS_ARB, mode->alphaBits);
1664    SET_ATTR_VALUE(WGL_ACCUM_RED_BITS_ARB, mode->accumRedBits);
1665    SET_ATTR_VALUE(WGL_ACCUM_GREEN_BITS_ARB, mode->accumGreenBits);
1666    SET_ATTR_VALUE(WGL_ACCUM_BLUE_BITS_ARB, mode->accumBlueBits);
1667    SET_ATTR_VALUE(WGL_ACCUM_ALPHA_BITS_ARB, mode->accumAlphaBits);
1668    SET_ATTR_VALUE(WGL_DEPTH_BITS_ARB, mode->depthBits);
1669    SET_ATTR_VALUE(WGL_STENCIL_BITS_ARB, mode->stencilBits);
1670    SET_ATTR_VALUE(WGL_AUX_BUFFERS_ARB, mode->numAuxBuffers);
1671
1672    if (mode->doubleBufferMode)
1673        SET_ATTR_VALUE(WGL_DOUBLE_BUFFER_ARB, TRUE);
1674
1675    if (mode->stereoMode)
1676        SET_ATTR_VALUE(WGL_STEREO_ARB, TRUE);
1677
1678    // Some attributes are only added to the list if the value requested is not 'don't care', as exactly matching that is daft..
1679    if (mode->swapMethod == GLX_SWAP_EXCHANGE_OML)
1680        SET_ATTR_VALUE(WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB);
1681
1682    if (mode->swapMethod == GLX_SWAP_COPY_OML)
1683        SET_ATTR_VALUE(WGL_SWAP_METHOD_ARB, WGL_SWAP_COPY_ARB);
1684
1685    // XXX: this should probably be the other way around, but that messes up drawableTypeOverride
1686    if (mode->visualRating == GLX_SLOW_VISUAL_EXT)
1687        SET_ATTR_VALUE(WGL_ACCELERATION_ARB, WGL_NO_ACCELERATION_ARB);
1688
1689    // must support all the drawable types the mode supports
1690    if ((mode->drawableType | drawableTypeOverride) & GLX_WINDOW_BIT)
1691        SET_ATTR_VALUE(WGL_DRAW_TO_WINDOW_ARB, TRUE);
1692
1693    // XXX: this is a horrible hacky heuristic, in fact this whole drawableTypeOverride thing is a bad idea
1694    // try to avoid asking for formats which don't exist (by not asking for all when adjusting the config to include the drawableTypeOverride)
1695    if (drawableTypeOverride == GLX_WINDOW_BIT) {
1696        if (mode->drawableType & GLX_PIXMAP_BIT)
1697            SET_ATTR_VALUE(WGL_DRAW_TO_BITMAP_ARB, TRUE);
1698
1699        if (mode->drawableType & GLX_PBUFFER_BIT)
1700            if (winScreen->has_WGL_ARB_pbuffer)
1701                SET_ATTR_VALUE(WGL_DRAW_TO_PBUFFER_ARB, TRUE);
1702    }
1703    else {
1704        if (drawableTypeOverride & GLX_PIXMAP_BIT)
1705            SET_ATTR_VALUE(WGL_DRAW_TO_BITMAP_ARB, TRUE);
1706
1707        if (drawableTypeOverride & GLX_PBUFFER_BIT)
1708            if (winScreen->has_WGL_ARB_pbuffer)
1709                SET_ATTR_VALUE(WGL_DRAW_TO_PBUFFER_ARB, TRUE);
1710    }
1711
1712    SET_ATTR_VALUE(0, 0);       // terminator
1713
1714    /* choose the first match */
1715    {
1716        int pixelFormatIndex;
1717
1718        if (!wglChoosePixelFormatARBWrapper
1719            (hdc, attribList, NULL, 1, &pixelFormatIndex, &numFormats)) {
1720            ErrorF("wglChoosePixelFormat error: %s\n", glxWinErrorMessage());
1721        }
1722        else {
1723            if (numFormats > 0) {
1724                GLWIN_DEBUG_MSG
1725                    ("wglChoosePixelFormat: chose pixelFormatIndex %d)",
1726                     pixelFormatIndex);
1727                return pixelFormatIndex;
1728            }
1729            else
1730                ErrorF("wglChoosePixelFormat couldn't decide\n");
1731        }
1732    }
1733
1734    return 0;
1735}
1736
1737/* ---------------------------------------------------------------------- */
1738
1739#define BITS_AND_SHIFT_TO_MASK(bits,mask) (((1<<(bits))-1) << (mask))
1740
1741//
1742// Create the GLXconfigs using DescribePixelFormat()
1743//
1744static void
1745glxWinCreateConfigs(HDC hdc, glxWinScreen * screen)
1746{
1747    GLXWinConfig *first = NULL, *prev = NULL;
1748    int numConfigs = 0;
1749    int i = 0;
1750    int n = 0;
1751    PIXELFORMATDESCRIPTOR pfd;
1752
1753    GLWIN_DEBUG_MSG("glxWinCreateConfigs");
1754
1755    screen->base.numFBConfigs = 0;
1756    screen->base.fbconfigs = NULL;
1757
1758    // get the number of pixelformats
1759    numConfigs =
1760        DescribePixelFormat(hdc, 1, sizeof(PIXELFORMATDESCRIPTOR), NULL);
1761    LogMessage(X_INFO, "%d pixel formats reported by DescribePixelFormat\n",
1762               numConfigs);
1763
1764    n = 0;
1765
1766    /* fill in configs */
1767    for (i = 0; i < numConfigs; i++) {
1768        int rc;
1769        GLXWinConfig temp;
1770        GLXWinConfig *c = &temp;
1771        GLXWinConfig *work;
1772        memset(c, 0, sizeof(GLXWinConfig));
1773
1774        c->pixelFormatIndex = i + 1;
1775
1776        rc = DescribePixelFormat(hdc, i + 1, sizeof(PIXELFORMATDESCRIPTOR),
1777                                 &pfd);
1778
1779        if (!rc) {
1780            ErrorF("DescribePixelFormat failed for index %d, error %s\n", i + 1,
1781                   glxWinErrorMessage());
1782            break;
1783        }
1784
1785        if (glxWinDebugSettings.dumpPFD)
1786            pfdOut(&pfd);
1787
1788        if (!(pfd.dwFlags & (PFD_DRAW_TO_WINDOW | PFD_DRAW_TO_BITMAP)) ||
1789            !(pfd.dwFlags & PFD_SUPPORT_OPENGL)) {
1790            GLWIN_DEBUG_MSG
1791                ("pixelFormat %d has unsuitable flags 0x%08x, skipping", i + 1,
1792                 (unsigned int)pfd.dwFlags);
1793            continue;
1794        }
1795
1796        c->base.doubleBufferMode =
1797            (pfd.dwFlags & PFD_DOUBLEBUFFER) ? GL_TRUE : GL_FALSE;
1798        c->base.stereoMode = (pfd.dwFlags & PFD_STEREO) ? GL_TRUE : GL_FALSE;
1799
1800        c->base.redBits = pfd.cRedBits;
1801        c->base.greenBits = pfd.cGreenBits;
1802        c->base.blueBits = pfd.cBlueBits;
1803        c->base.alphaBits = pfd.cAlphaBits;
1804
1805        c->base.redMask = BITS_AND_SHIFT_TO_MASK(pfd.cRedBits, pfd.cRedShift);
1806        c->base.greenMask =
1807            BITS_AND_SHIFT_TO_MASK(pfd.cGreenBits, pfd.cGreenShift);
1808        c->base.blueMask =
1809            BITS_AND_SHIFT_TO_MASK(pfd.cBlueBits, pfd.cBlueShift);
1810        c->base.alphaMask =
1811            BITS_AND_SHIFT_TO_MASK(pfd.cAlphaBits, pfd.cAlphaShift);
1812
1813        c->base.rgbBits = pfd.cColorBits;
1814
1815        if (pfd.iPixelType == PFD_TYPE_COLORINDEX) {
1816            c->base.indexBits = pfd.cColorBits;
1817        }
1818        else {
1819            c->base.indexBits = 0;
1820        }
1821
1822        c->base.accumRedBits = pfd.cAccumRedBits;
1823        c->base.accumGreenBits = pfd.cAccumGreenBits;
1824        c->base.accumBlueBits = pfd.cAccumBlueBits;
1825        c->base.accumAlphaBits = pfd.cAccumAlphaBits;
1826        //  pfd.cAccumBits;
1827
1828        c->base.depthBits = pfd.cDepthBits;
1829        c->base.stencilBits = pfd.cStencilBits;
1830        c->base.numAuxBuffers = pfd.cAuxBuffers;
1831
1832        // pfd.iLayerType; // ignored
1833        c->base.level = 0;
1834        // pfd.dwLayerMask; // ignored
1835        // pfd.dwDamageMask;  // ignored
1836
1837        c->base.visualID = -1;  // will be set by __glXScreenInit()
1838
1839        /* EXT_visual_rating / GLX 1.2 */
1840        if (pfd.dwFlags & PFD_GENERIC_FORMAT) {
1841            c->base.visualRating = GLX_SLOW_VISUAL_EXT;
1842        }
1843        else {
1844            // PFD_GENERIC_ACCELERATED is not considered, so this may be MCD or ICD acclerated...
1845            c->base.visualRating = GLX_NONE_EXT;
1846        }
1847
1848        /* EXT_visual_info / GLX 1.2 */
1849        if (pfd.iPixelType == PFD_TYPE_COLORINDEX) {
1850            c->base.visualType = GLX_STATIC_COLOR;
1851            c->base.transparentRed = GLX_NONE;
1852            c->base.transparentGreen = GLX_NONE;
1853            c->base.transparentBlue = GLX_NONE;
1854            c->base.transparentAlpha = GLX_NONE;
1855            c->base.transparentIndex = pfd.dwVisibleMask;
1856            c->base.transparentPixel = GLX_TRANSPARENT_INDEX;
1857        }
1858        else {
1859            c->base.visualType = GLX_TRUE_COLOR;
1860            c->base.transparentRed =
1861                (pfd.dwVisibleMask & c->base.redMask) >> pfd.cRedShift;
1862            c->base.transparentGreen =
1863                (pfd.dwVisibleMask & c->base.greenMask) >> pfd.cGreenShift;
1864            c->base.transparentBlue =
1865                (pfd.dwVisibleMask & c->base.blueMask) >> pfd.cBlueShift;
1866            c->base.transparentAlpha =
1867                (pfd.dwVisibleMask & c->base.alphaMask) >> pfd.cAlphaShift;
1868            c->base.transparentIndex = GLX_NONE;
1869            c->base.transparentPixel = GLX_TRANSPARENT_RGB;
1870        }
1871
1872        /* ARB_multisample / SGIS_multisample */
1873        c->base.sampleBuffers = 0;
1874        c->base.samples = 0;
1875
1876        /* SGIX_fbconfig / GLX 1.3 */
1877        c->base.drawableType =
1878            (((pfd.dwFlags & PFD_DRAW_TO_WINDOW) ? GLX_WINDOW_BIT : 0)
1879             | ((pfd.dwFlags & PFD_DRAW_TO_BITMAP) ? GLX_PIXMAP_BIT : 0));
1880
1881        if (pfd.iPixelType == PFD_TYPE_COLORINDEX) {
1882            c->base.renderType = GLX_RGBA_BIT | GLX_COLOR_INDEX_BIT;
1883        }
1884        else {
1885            c->base.renderType = GLX_RGBA_BIT;
1886        }
1887
1888        c->base.fbconfigID = -1;        // will be set by __glXScreenInit()
1889
1890        /* SGIX_pbuffer / GLX 1.3 */
1891        // XXX: How can we find these values out ???
1892        c->base.maxPbufferWidth = -1;
1893        c->base.maxPbufferHeight = -1;
1894        c->base.maxPbufferPixels = -1;
1895        c->base.optimalPbufferWidth = 0;        // there is no optimal value
1896        c->base.optimalPbufferHeight = 0;
1897
1898        /* SGIX_visual_select_group */
1899        // arrange for visuals with the best acceleration to be preferred in selection
1900        switch (pfd.dwFlags & (PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED)) {
1901        case 0:
1902            c->base.visualSelectGroup = 2;
1903            break;
1904
1905        case PFD_GENERIC_ACCELERATED:
1906            c->base.visualSelectGroup = 1;
1907            break;
1908
1909        case PFD_GENERIC_FORMAT:
1910            c->base.visualSelectGroup = 0;
1911            break;
1912
1913        default:
1914            ;
1915            // "can't happen"
1916        }
1917
1918        /* OML_swap_method */
1919        if (pfd.dwFlags & PFD_SWAP_EXCHANGE)
1920            c->base.swapMethod = GLX_SWAP_EXCHANGE_OML;
1921        else if (pfd.dwFlags & PFD_SWAP_COPY)
1922            c->base.swapMethod = GLX_SWAP_COPY_OML;
1923        else
1924            c->base.swapMethod = GLX_SWAP_UNDEFINED_OML;
1925
1926        /* EXT_texture_from_pixmap */
1927        c->base.bindToTextureRgb = -1;
1928        c->base.bindToTextureRgba = -1;
1929        c->base.bindToMipmapTexture = -1;
1930        c->base.bindToTextureTargets = -1;
1931        c->base.yInverted = -1;
1932        c->base.sRGBCapable = 0;
1933
1934        n++;
1935
1936        // allocate and save
1937        work = malloc(sizeof(GLXWinConfig));
1938        if (NULL == work) {
1939            ErrorF("Failed to allocate GLXWinConfig\n");
1940            break;
1941        }
1942        *work = temp;
1943
1944        // note the first config
1945        if (!first)
1946            first = work;
1947
1948        // update previous config to point to this config
1949        if (prev)
1950            prev->base.next = &(work->base);
1951        prev = work;
1952    }
1953
1954    GLWIN_DEBUG_MSG
1955        ("found %d pixelFormats suitable for conversion to fbConfigs", n);
1956
1957    screen->base.numFBConfigs = n;
1958    screen->base.fbconfigs = first ? &(first->base) : NULL;
1959}
1960
1961// helper function to access an attribute value from an attribute value array by attribute
1962static
1963    int
1964getAttrValue(const int attrs[], int values[], unsigned int num, int attr,
1965             int fallback)
1966{
1967    unsigned int i;
1968
1969    for (i = 0; i < num; i++) {
1970        if (attrs[i] == attr) {
1971            GLWIN_TRACE_MSG("getAttrValue attr 0x%x, value %d", attr,
1972                            values[i]);
1973            return values[i];
1974        }
1975    }
1976
1977    ErrorF("getAttrValue failed to find attr 0x%x, using default value %d\n",
1978           attr, fallback);
1979    return fallback;
1980}
1981
1982//
1983// Create the GLXconfigs using wglGetPixelFormatAttribfvARB() extension
1984//
1985static void
1986glxWinCreateConfigsExt(HDC hdc, glxWinScreen * screen)
1987{
1988    GLXWinConfig *first = NULL, *prev = NULL;
1989    int i = 0;
1990    int n = 0;
1991
1992    const int attr = WGL_NUMBER_PIXEL_FORMATS_ARB;
1993    int numConfigs;
1994
1995    int attrs[50];
1996    unsigned int num_attrs = 0;
1997
1998    GLWIN_DEBUG_MSG("glxWinCreateConfigsExt");
1999
2000    screen->base.numFBConfigs = 0;
2001    screen->base.fbconfigs = NULL;
2002
2003    if (!wglGetPixelFormatAttribivARBWrapper(hdc, 0, 0, 1, &attr, &numConfigs)) {
2004        ErrorF
2005            ("wglGetPixelFormatAttribivARB failed for WGL_NUMBER_PIXEL_FORMATS_ARB: %s\n",
2006             glxWinErrorMessage());
2007        return;
2008    }
2009
2010    LogMessage(X_INFO,
2011               "%d pixel formats reported by wglGetPixelFormatAttribivARB\n",
2012               numConfigs);
2013
2014    n = 0;
2015
2016#define ADD_ATTR(a) { attrs[num_attrs++] = a; assert(num_attrs < ARRAY_SIZE(attrs)); }
2017
2018    ADD_ATTR(WGL_DRAW_TO_WINDOW_ARB);
2019    ADD_ATTR(WGL_DRAW_TO_BITMAP_ARB);
2020    ADD_ATTR(WGL_ACCELERATION_ARB);
2021    ADD_ATTR(WGL_SWAP_LAYER_BUFFERS_ARB);
2022    ADD_ATTR(WGL_NUMBER_OVERLAYS_ARB);
2023    ADD_ATTR(WGL_NUMBER_UNDERLAYS_ARB);
2024    ADD_ATTR(WGL_TRANSPARENT_ARB);
2025    ADD_ATTR(WGL_TRANSPARENT_RED_VALUE_ARB);
2026    ADD_ATTR(WGL_TRANSPARENT_GREEN_VALUE_ARB);
2027    ADD_ATTR(WGL_TRANSPARENT_GREEN_VALUE_ARB);
2028    ADD_ATTR(WGL_TRANSPARENT_ALPHA_VALUE_ARB);
2029    ADD_ATTR(WGL_SUPPORT_OPENGL_ARB);
2030    ADD_ATTR(WGL_DOUBLE_BUFFER_ARB);
2031    ADD_ATTR(WGL_STEREO_ARB);
2032    ADD_ATTR(WGL_PIXEL_TYPE_ARB);
2033    ADD_ATTR(WGL_COLOR_BITS_ARB);
2034    ADD_ATTR(WGL_RED_BITS_ARB);
2035    ADD_ATTR(WGL_RED_SHIFT_ARB);
2036    ADD_ATTR(WGL_GREEN_BITS_ARB);
2037    ADD_ATTR(WGL_GREEN_SHIFT_ARB);
2038    ADD_ATTR(WGL_BLUE_BITS_ARB);
2039    ADD_ATTR(WGL_BLUE_SHIFT_ARB);
2040    ADD_ATTR(WGL_ALPHA_BITS_ARB);
2041    ADD_ATTR(WGL_ALPHA_SHIFT_ARB);
2042    ADD_ATTR(WGL_ACCUM_RED_BITS_ARB);
2043    ADD_ATTR(WGL_ACCUM_GREEN_BITS_ARB);
2044    ADD_ATTR(WGL_ACCUM_BLUE_BITS_ARB);
2045    ADD_ATTR(WGL_ACCUM_ALPHA_BITS_ARB);
2046    ADD_ATTR(WGL_DEPTH_BITS_ARB);
2047    ADD_ATTR(WGL_STENCIL_BITS_ARB);
2048    ADD_ATTR(WGL_AUX_BUFFERS_ARB);
2049    ADD_ATTR(WGL_SWAP_METHOD_ARB);
2050
2051    if (screen->has_WGL_ARB_multisample) {
2052        // we may not query these attrs if WGL_ARB_multisample is not offered
2053        ADD_ATTR(WGL_SAMPLE_BUFFERS_ARB);
2054        ADD_ATTR(WGL_SAMPLES_ARB);
2055    }
2056
2057    if (screen->has_WGL_ARB_render_texture) {
2058        // we may not query these attrs if WGL_ARB_render_texture is not offered
2059        ADD_ATTR(WGL_BIND_TO_TEXTURE_RGB_ARB);
2060        ADD_ATTR(WGL_BIND_TO_TEXTURE_RGBA_ARB);
2061    }
2062
2063    if (screen->has_WGL_ARB_pbuffer) {
2064        // we may not query these attrs if WGL_ARB_pbuffer is not offered
2065        ADD_ATTR(WGL_DRAW_TO_PBUFFER_ARB);
2066        ADD_ATTR(WGL_MAX_PBUFFER_PIXELS_ARB);
2067        ADD_ATTR(WGL_MAX_PBUFFER_WIDTH_ARB);
2068        ADD_ATTR(WGL_MAX_PBUFFER_HEIGHT_ARB);
2069    }
2070
2071    /* fill in configs */
2072    for (i = 0; i < numConfigs; i++) {
2073        int values[num_attrs];
2074        GLXWinConfig temp;
2075        GLXWinConfig *c = &temp;
2076        GLXWinConfig *work;
2077        memset(c, 0, sizeof(GLXWinConfig));
2078
2079        c->pixelFormatIndex = i + 1;
2080
2081        if (!wglGetPixelFormatAttribivARBWrapper
2082            (hdc, i + 1, 0, num_attrs, attrs, values)) {
2083            ErrorF
2084                ("wglGetPixelFormatAttribivARB failed for index %d, error %s\n",
2085                 i + 1, glxWinErrorMessage());
2086            break;
2087        }
2088
2089#define ATTR_VALUE(a, d) getAttrValue(attrs, values, num_attrs, (a), (d))
2090
2091        if (!ATTR_VALUE(WGL_SUPPORT_OPENGL_ARB, 0)) {
2092            GLWIN_DEBUG_MSG
2093                ("pixelFormat %d isn't WGL_SUPPORT_OPENGL_ARB, skipping",
2094                 i + 1);
2095            continue;
2096        }
2097
2098        c->base.doubleBufferMode =
2099            ATTR_VALUE(WGL_DOUBLE_BUFFER_ARB, 0) ? GL_TRUE : GL_FALSE;
2100        c->base.stereoMode = ATTR_VALUE(WGL_STEREO_ARB, 0) ? GL_TRUE : GL_FALSE;
2101
2102        c->base.redBits = ATTR_VALUE(WGL_RED_BITS_ARB, 0);
2103        c->base.greenBits = ATTR_VALUE(WGL_GREEN_BITS_ARB, 0);
2104        c->base.blueBits = ATTR_VALUE(WGL_BLUE_BITS_ARB, 0);
2105        c->base.alphaBits = ATTR_VALUE(WGL_ALPHA_BITS_ARB, 0);
2106
2107        c->base.redMask =
2108            BITS_AND_SHIFT_TO_MASK(c->base.redBits,
2109                                   ATTR_VALUE(WGL_RED_SHIFT_ARB, 0));
2110        c->base.greenMask =
2111            BITS_AND_SHIFT_TO_MASK(c->base.greenBits,
2112                                   ATTR_VALUE(WGL_GREEN_SHIFT_ARB, 0));
2113        c->base.blueMask =
2114            BITS_AND_SHIFT_TO_MASK(c->base.blueBits,
2115                                   ATTR_VALUE(WGL_BLUE_SHIFT_ARB, 0));
2116        c->base.alphaMask =
2117            BITS_AND_SHIFT_TO_MASK(c->base.alphaBits,
2118                                   ATTR_VALUE(WGL_ALPHA_SHIFT_ARB, 0));
2119
2120        switch (ATTR_VALUE(WGL_PIXEL_TYPE_ARB, 0)) {
2121        case WGL_TYPE_COLORINDEX_ARB:
2122            c->base.indexBits = ATTR_VALUE(WGL_COLOR_BITS_ARB, 0);
2123            c->base.rgbBits = 0;
2124            c->base.visualType = GLX_STATIC_COLOR;
2125            break;
2126
2127        case WGL_TYPE_RGBA_FLOAT_ARB:
2128            GLWIN_DEBUG_MSG
2129                ("pixelFormat %d is WGL_TYPE_RGBA_FLOAT_ARB, skipping", i + 1);
2130            continue;
2131
2132        case WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT:
2133            GLWIN_DEBUG_MSG
2134                ("pixelFormat %d is WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT, skipping",
2135                 i + 1);
2136            continue;
2137
2138        case WGL_TYPE_RGBA_ARB:
2139            c->base.indexBits = 0;
2140            c->base.rgbBits = ATTR_VALUE(WGL_COLOR_BITS_ARB, 0);
2141            c->base.visualType = GLX_TRUE_COLOR;
2142            break;
2143
2144        default:
2145            ErrorF
2146                ("wglGetPixelFormatAttribivARB returned unknown value 0x%x for WGL_PIXEL_TYPE_ARB\n",
2147                 ATTR_VALUE(WGL_PIXEL_TYPE_ARB, 0));
2148            continue;
2149        }
2150
2151        c->base.accumRedBits = ATTR_VALUE(WGL_ACCUM_RED_BITS_ARB, 0);
2152        c->base.accumGreenBits = ATTR_VALUE(WGL_ACCUM_GREEN_BITS_ARB, 0);
2153        c->base.accumBlueBits = ATTR_VALUE(WGL_ACCUM_BLUE_BITS_ARB, 0);
2154        c->base.accumAlphaBits = ATTR_VALUE(WGL_ACCUM_ALPHA_BITS_ARB, 0);
2155
2156        c->base.depthBits = ATTR_VALUE(WGL_DEPTH_BITS_ARB, 0);
2157        c->base.stencilBits = ATTR_VALUE(WGL_STENCIL_BITS_ARB, 0);
2158        c->base.numAuxBuffers = ATTR_VALUE(WGL_AUX_BUFFERS_ARB, 0);
2159
2160        {
2161            int layers =
2162                ATTR_VALUE(WGL_NUMBER_OVERLAYS_ARB,
2163                           0) + ATTR_VALUE(WGL_NUMBER_UNDERLAYS_ARB, 0);
2164
2165            if (layers > 0) {
2166                ErrorF
2167                    ("pixelFormat %d: has %d overlay, %d underlays which aren't currently handled",
2168                     i, ATTR_VALUE(WGL_NUMBER_OVERLAYS_ARB, 0),
2169                     ATTR_VALUE(WGL_NUMBER_UNDERLAYS_ARB, 0));
2170                // XXX: need to iterate over layers?
2171            }
2172        }
2173        c->base.level = 0;
2174
2175        c->base.visualID = -1;  // will be set by __glXScreenInit()
2176
2177        /* EXT_visual_rating / GLX 1.2 */
2178        switch (ATTR_VALUE(WGL_ACCELERATION_ARB, 0)) {
2179        default:
2180            ErrorF
2181                ("wglGetPixelFormatAttribivARB returned unknown value 0x%x for WGL_ACCELERATION_ARB\n",
2182                 ATTR_VALUE(WGL_ACCELERATION_ARB, 0));
2183
2184        case WGL_NO_ACCELERATION_ARB:
2185            c->base.visualRating = GLX_SLOW_VISUAL_EXT;
2186            break;
2187
2188        case WGL_GENERIC_ACCELERATION_ARB:
2189        case WGL_FULL_ACCELERATION_ARB:
2190            c->base.visualRating = GLX_NONE_EXT;
2191            break;
2192        }
2193
2194        /* EXT_visual_info / GLX 1.2 */
2195        // c->base.visualType is set above
2196        if (ATTR_VALUE(WGL_TRANSPARENT_ARB, 0)) {
2197            c->base.transparentPixel =
2198                (c->base.visualType ==
2199                 GLX_TRUE_COLOR) ? GLX_TRANSPARENT_RGB_EXT :
2200                GLX_TRANSPARENT_INDEX_EXT;
2201            c->base.transparentRed =
2202                ATTR_VALUE(WGL_TRANSPARENT_RED_VALUE_ARB, 0);
2203            c->base.transparentGreen =
2204                ATTR_VALUE(WGL_TRANSPARENT_GREEN_VALUE_ARB, 0);
2205            c->base.transparentBlue =
2206                ATTR_VALUE(WGL_TRANSPARENT_BLUE_VALUE_ARB, 0);
2207            c->base.transparentAlpha =
2208                ATTR_VALUE(WGL_TRANSPARENT_ALPHA_VALUE_ARB, 0);
2209            c->base.transparentIndex =
2210                ATTR_VALUE(WGL_TRANSPARENT_INDEX_VALUE_ARB, 0);
2211        }
2212        else {
2213            c->base.transparentPixel = GLX_NONE_EXT;
2214            c->base.transparentRed = GLX_NONE;
2215            c->base.transparentGreen = GLX_NONE;
2216            c->base.transparentBlue = GLX_NONE;
2217            c->base.transparentAlpha = GLX_NONE;
2218            c->base.transparentIndex = GLX_NONE;
2219        }
2220
2221        /* ARB_multisample / SGIS_multisample */
2222        if (screen->has_WGL_ARB_multisample) {
2223            c->base.sampleBuffers = ATTR_VALUE(WGL_SAMPLE_BUFFERS_ARB, 0);
2224            c->base.samples = ATTR_VALUE(WGL_SAMPLES_ARB, 0);
2225        }
2226        else {
2227            c->base.sampleBuffers = 0;
2228            c->base.samples = 0;
2229        }
2230
2231        /* SGIX_fbconfig / GLX 1.3 */
2232        c->base.drawableType =
2233            ((ATTR_VALUE(WGL_DRAW_TO_WINDOW_ARB, 0) ? GLX_WINDOW_BIT : 0)
2234             | (ATTR_VALUE(WGL_DRAW_TO_BITMAP_ARB, 0) ? GLX_PIXMAP_BIT : 0)
2235             | (ATTR_VALUE(WGL_DRAW_TO_PBUFFER_ARB, 0) ? GLX_PBUFFER_BIT : 0));
2236
2237        /*
2238           Assume OpenGL RGBA rendering is available on all visuals
2239           (it is specified to render to red component in single-channel visuals,
2240           if supported, but there doesn't seem to be any mechanism to check if it
2241           is supported)
2242
2243           Color index rendering is only supported on single-channel visuals
2244         */
2245        if (c->base.visualType == GLX_STATIC_COLOR) {
2246            c->base.renderType = GLX_RGBA_BIT | GLX_COLOR_INDEX_BIT;
2247        }
2248        else {
2249            c->base.renderType = GLX_RGBA_BIT;
2250        }
2251
2252        c->base.fbconfigID = -1;        // will be set by __glXScreenInit()
2253
2254        /* SGIX_pbuffer / GLX 1.3 */
2255        if (screen->has_WGL_ARB_pbuffer) {
2256            c->base.maxPbufferWidth = ATTR_VALUE(WGL_MAX_PBUFFER_WIDTH_ARB, -1);
2257            c->base.maxPbufferHeight =
2258                ATTR_VALUE(WGL_MAX_PBUFFER_HEIGHT_ARB, -1);
2259            c->base.maxPbufferPixels =
2260                ATTR_VALUE(WGL_MAX_PBUFFER_PIXELS_ARB, -1);
2261        }
2262        else {
2263            c->base.maxPbufferWidth = -1;
2264            c->base.maxPbufferHeight = -1;
2265            c->base.maxPbufferPixels = -1;
2266        }
2267        c->base.optimalPbufferWidth = 0;        // there is no optimal value
2268        c->base.optimalPbufferHeight = 0;
2269
2270        /* SGIX_visual_select_group */
2271        // arrange for visuals with the best acceleration to be preferred in selection
2272        switch (ATTR_VALUE(WGL_ACCELERATION_ARB, 0)) {
2273        case WGL_FULL_ACCELERATION_ARB:
2274            c->base.visualSelectGroup = 2;
2275            break;
2276
2277        case WGL_GENERIC_ACCELERATION_ARB:
2278            c->base.visualSelectGroup = 1;
2279            break;
2280
2281        default:
2282        case WGL_NO_ACCELERATION_ARB:
2283            c->base.visualSelectGroup = 0;
2284            break;
2285        }
2286
2287        /* OML_swap_method */
2288        switch (ATTR_VALUE(WGL_SWAP_METHOD_ARB, 0)) {
2289        case WGL_SWAP_EXCHANGE_ARB:
2290            c->base.swapMethod = GLX_SWAP_EXCHANGE_OML;
2291            break;
2292
2293        case WGL_SWAP_COPY_ARB:
2294            c->base.swapMethod = GLX_SWAP_COPY_OML;
2295            break;
2296
2297        default:
2298            ErrorF
2299                ("wglGetPixelFormatAttribivARB returned unknown value 0x%x for WGL_SWAP_METHOD_ARB\n",
2300                 ATTR_VALUE(WGL_SWAP_METHOD_ARB, 0));
2301
2302        case WGL_SWAP_UNDEFINED_ARB:
2303            c->base.swapMethod = GLX_SWAP_UNDEFINED_OML;
2304        }
2305
2306        /* EXT_texture_from_pixmap */
2307        /*
2308           Mesa's DRI configs always have bindToTextureRgb/Rgba TRUE (see driCreateConfigs(), so setting
2309           bindToTextureRgb/bindToTextureRgba to FALSE means that swrast can't find any fbConfigs to use,
2310           so setting these to 0, even if we know bindToTexture isn't available, isn't a good idea...
2311         */
2312        if (screen->has_WGL_ARB_render_texture) {
2313            c->base.bindToTextureRgb =
2314                ATTR_VALUE(WGL_BIND_TO_TEXTURE_RGB_ARB, -1);
2315            c->base.bindToTextureRgba =
2316                ATTR_VALUE(WGL_BIND_TO_TEXTURE_RGBA_ARB, -1);
2317        }
2318        else {
2319            c->base.bindToTextureRgb = -1;
2320            c->base.bindToTextureRgba = -1;
2321        }
2322        c->base.bindToMipmapTexture = -1;
2323        c->base.bindToTextureTargets =
2324            GLX_TEXTURE_1D_BIT_EXT | GLX_TEXTURE_2D_BIT_EXT |
2325            GLX_TEXTURE_RECTANGLE_BIT_EXT;
2326        c->base.yInverted = -1;
2327        c->base.sRGBCapable = 0;
2328
2329        n++;
2330
2331        // allocate and save
2332        work = malloc(sizeof(GLXWinConfig));
2333        if (NULL == work) {
2334            ErrorF("Failed to allocate GLXWinConfig\n");
2335            break;
2336        }
2337        *work = temp;
2338
2339        // note the first config
2340        if (!first)
2341            first = work;
2342
2343        // update previous config to point to this config
2344        if (prev)
2345            prev->base.next = &(work->base);
2346        prev = work;
2347    }
2348
2349    screen->base.numFBConfigs = n;
2350    screen->base.fbconfigs = first ? &(first->base) : NULL;
2351}
2352