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