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