Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / drivers / windows / gldirect / dglcontext.c
1 /****************************************************************************
2 *
3 *                        Mesa 3-D graphics library
4 *                        Direct3D Driver Interface
5 *
6 *  ========================================================================
7 *
8 *   Copyright (C) 1991-2004 SciTech Software, Inc. All rights reserved.
9 *
10 *   Permission is hereby granted, free of charge, to any person obtaining a
11 *   copy of this software and associated documentation files (the "Software"),
12 *   to deal in the Software without restriction, including without limitation
13 *   the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 *   and/or sell copies of the Software, and to permit persons to whom the
15 *   Software is furnished to do so, subject to the following conditions:
16 *
17 *   The above copyright notice and this permission notice shall be included
18 *   in all copies or substantial portions of the Software.
19 *
20 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 *   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23 *   SCITECH SOFTWARE INC BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
25 *   OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 *   SOFTWARE.
27 *
28 *  ======================================================================
29 *
30 * Language:     ANSI C
31 * Environment:  Windows 9x (Win32)
32 *
33 * Description:  Context handling.
34 *
35 ****************************************************************************/
36
37 #include "dglcontext.h"
38
39 // Get compile errors without this. KeithH
40 //#include "scitech.h"  // ibool, etc.
41
42 #ifdef _USE_GLD3_WGL
43 #include "gld_driver.h"
44
45 extern void _gld_mesa_warning(struct gl_context *, char *);
46 extern void _gld_mesa_fatal(struct gl_context *, char *);
47 #endif // _USE_GLD3_WGL
48
49 // TODO: Clean out old DX6-specific code from GLD 2.x CAD driver
50 // if it is no longer being built as part of GLDirect. (DaveM)
51
52 // ***********************************************************************
53
54 #define GLDERR_NONE     0
55 #define GLDERR_MEM      1
56 #define GLDERR_DDRAW    2
57 #define GLDERR_D3D      3
58 #define GLDERR_BPP      4
59
60 char szResourceWarning[] =
61 "GLDirect does not have enough video memory resources\n"
62 "to support the requested OpenGL rendering context.\n\n"
63 "You may have to reduce the current display resolution\n"
64 "to obtain satisfactory OpenGL performance.\n";
65
66 char szDDrawWarning[] =
67 "GLDirect is unable to initialize DirectDraw for the\n"
68 "requested OpenGL rendering context.\n\n"
69 "You will have to check the DirectX control panel\n"
70 "for further information.\n";
71
72 char szD3DWarning[] =
73 "GLDirect is unable to initialize Direct3D for the\n"
74 "requested OpenGL rendering context.\n\n"
75 "You may have to change the display mode resolution\n"
76 "color depth or check the DirectX control panel for\n"
77 "further information.\n";
78
79 char szBPPWarning[] =
80 "GLDirect is unable to use the selected color depth for\n"
81 "the requested OpenGL rendering context.\n\n"
82 "You will have to change the display mode resolution\n"
83 "color depth with the Display Settings control panel.\n";
84
85 int nContextError = GLDERR_NONE;
86
87 // ***********************************************************************
88
89 #define VENDORID_ATI 0x1002
90
91 static DWORD devATIRagePro[] = {
92         0x4742, // 3D RAGE PRO BGA AGP 1X/2X
93         0x4744, // 3D RAGE PRO BGA AGP 1X only
94         0x4749, // 3D RAGE PRO BGA PCI 33 MHz
95         0x4750, // 3D RAGE PRO PQFP PCI 33 MHz
96         0x4751, // 3D RAGE PRO PQFP PCI 33 MHz limited 3D
97         0x4C42, // 3D RAGE LT PRO BGA-312 AGP 133 MHz
98         0x4C44, // 3D RAGE LT PRO BGA-312 AGP 66 MHz
99         0x4C49, // 3D RAGE LT PRO BGA-312 PCI 33 MHz
100         0x4C50, // 3D RAGE LT PRO BGA-256 PCI 33 MHz
101         0x4C51, // 3D RAGE LT PRO BGA-256 PCI 33 MHz limited 3D
102 };
103
104 static DWORD devATIRageIIplus[] = {
105         0x4755, // 3D RAGE II+
106         0x4756, // 3D RAGE IIC PQFP PCI
107         0x4757, // 3D RAGE IIC BGA AGP
108         0x475A, // 3D RAGE IIC PQFP AGP
109         0x4C47, // 3D RAGE LT-G
110 };
111
112 // ***********************************************************************
113
114 #ifndef _USE_GLD3_WGL
115 extern DGL_mesaFuncs mesaFuncs;
116 #endif
117
118 extern DWORD dwLogging;
119
120 #ifdef GLD_THREADS
121 #pragma message("compiling DGLCONTEXT.C vars for multi-threaded support")
122 CRITICAL_SECTION CriticalSection;               // for serialized access
123 DWORD           dwTLSCurrentContext = 0xFFFFFFFF;       // TLS index for current context
124 DWORD           dwTLSPixelFormat = 0xFFFFFFFF;          // TLS index for current pixel format
125 #endif
126 HGLRC           iCurrentContext = 0;            // Index of current context (static)
127 BOOL            bContextReady = FALSE;          // Context state ready ?
128
129 DGL_ctx         ctxlist[DGL_MAX_CONTEXTS];      // Context list
130
131 // ***********************************************************************
132
133 static BOOL bHaveWin95 = FALSE;
134 static BOOL bHaveWinNT = FALSE;
135 static BOOL bHaveWin2K = FALSE;
136
137 /****************************************************************************
138 REMARKS:
139 Detect the installed OS type.
140 ****************************************************************************/
141 static void DetectOS(void)
142 {
143     OSVERSIONINFO VersionInformation;
144     LPOSVERSIONINFO lpVersionInformation = &VersionInformation;
145
146     VersionInformation.dwOSVersionInfoSize = sizeof(VersionInformation);
147
148         GetVersionEx(lpVersionInformation);
149
150     switch (VersionInformation.dwPlatformId) {
151         case VER_PLATFORM_WIN32_WINDOWS:
152                         bHaveWin95 = TRUE;
153                         bHaveWinNT = FALSE;
154                         bHaveWin2K = FALSE;
155             break;
156         case VER_PLATFORM_WIN32_NT:
157                         bHaveWin95 = FALSE;
158                         if (VersionInformation.dwMajorVersion <= 4) {
159                                 bHaveWinNT = TRUE;
160                                 bHaveWin2K = FALSE;
161                 }
162             else {
163                                 bHaveWinNT = FALSE;
164                                 bHaveWin2K = TRUE;
165                 }
166                         break;
167                 case VER_PLATFORM_WIN32s:
168                         bHaveWin95 = FALSE;
169                         bHaveWinNT = FALSE;
170                         bHaveWin2K = FALSE;
171                         break;
172         }
173 }
174
175 // ***********************************************************************
176
177 HWND hWndEvent = NULL;                                  // event monitor window
178 HWND hWndLastActive = NULL;                             // last active client window
179 LONG __stdcall GLD_EventWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);
180
181 // ***********************************************************************
182
183 // Checks if the HGLRC is valid in range of context list.
184 BOOL dglIsValidContext(
185         HGLRC a)
186 {
187         return ((int)a > 0 && (int)a <= DGL_MAX_CONTEXTS);
188 }
189
190 // ***********************************************************************
191
192 // Convert a HGLRC to a pointer into the context list.
193 DGL_ctx* dglGetContextAddress(
194         const HGLRC a)
195 {
196         if (dglIsValidContext(a))
197                 return &ctxlist[(int)a-1];
198         return NULL;
199 }
200
201 // ***********************************************************************
202
203 // Return the current HGLRC (however it may be stored for multi-threading).
204 HGLRC dglGetCurrentContext(void)
205 {
206 #ifdef GLD_THREADS
207         HGLRC hGLRC;
208         // load from thread-specific instance
209         if (glb.bMultiThreaded) {
210                 // protect against calls from arbitrary threads
211                 __try {
212                         hGLRC = (HGLRC)TlsGetValue(dwTLSCurrentContext);
213                 }
214                 __except(EXCEPTION_EXECUTE_HANDLER) {
215                         hGLRC = iCurrentContext;
216                 }
217         }
218         // load from global static var
219         else {
220                 hGLRC = iCurrentContext;
221         }
222         return hGLRC;
223 #else
224         return iCurrentContext;
225 #endif
226 }
227
228 // ***********************************************************************
229
230 // Set the current HGLRC (however it may be stored for multi-threading).
231 void dglSetCurrentContext(HGLRC hGLRC)
232 {
233 #ifdef GLD_THREADS
234         // store in thread-specific instance
235         if (glb.bMultiThreaded) {
236                 // protect against calls from arbitrary threads
237                 __try {
238                         TlsSetValue(dwTLSCurrentContext, (LPVOID)hGLRC);
239                 }
240                 __except(EXCEPTION_EXECUTE_HANDLER) {
241                         iCurrentContext = hGLRC;
242                 }
243         }
244         // store in global static var
245         else {
246                 iCurrentContext = hGLRC;
247         }
248 #else
249         iCurrentContext = hGLRC;
250 #endif
251 }
252
253 // ***********************************************************************
254
255 // Return the current HDC only for a currently active HGLRC.
256 HDC dglGetCurrentDC(void)
257 {
258         HGLRC hGLRC;
259         DGL_ctx* lpCtx;
260
261         hGLRC = dglGetCurrentContext();
262         if (hGLRC) {
263                 lpCtx = dglGetContextAddress(hGLRC);
264                 return lpCtx->hDC;
265         }
266         return 0;
267 }
268
269 // ***********************************************************************
270
271 void dglInitContextState()
272 {
273         int i;
274         WNDCLASS wc;
275
276 #ifdef GLD_THREADS
277         // Allocate thread local storage indexes for current context and pixel format
278         dwTLSCurrentContext = TlsAlloc();
279         dwTLSPixelFormat = TlsAlloc();
280 #endif
281
282         dglSetCurrentContext(NULL); // No current rendering context
283
284          // Clear all context data
285         ZeroMemory(ctxlist, sizeof(ctxlist[0]) * DGL_MAX_CONTEXTS);
286
287         for (i=0; i<DGL_MAX_CONTEXTS; i++)
288                 ctxlist[i].bAllocated = FALSE; // Flag context as unused
289
290         // This section of code crashes the dll in circumstances where the app
291         // creates and destroys contexts.
292 /*
293         // Register the class for our event monitor window
294         wc.style = 0;
295         wc.lpfnWndProc = GLD_EventWndProc;
296         wc.cbClsExtra = 0;
297         wc.cbWndExtra = 0;
298         wc.hInstance = GetModuleHandle(NULL);
299         wc.hIcon = LoadIcon(GetModuleHandle(NULL), IDI_APPLICATION);
300         wc.hCursor = LoadCursor(NULL, IDC_ARROW);
301         wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
302         wc.lpszMenuName = NULL;
303         wc.lpszClassName = "GLDIRECT";
304         RegisterClass(&wc);
305
306         // Create the non-visible window to monitor all broadcast messages
307         hWndEvent = CreateWindowEx(
308                 WS_EX_TOOLWINDOW,"GLDIRECT","GLDIRECT",WS_POPUP,
309                 0,0,0,0,
310                 NULL,NULL,GetModuleHandle(NULL),NULL);
311 */
312
313 #ifdef GLD_THREADS
314         // Create a critical section object for serializing access to
315         // DirectDraw and DDStereo create/destroy functions in multiple threads
316         if (glb.bMultiThreaded)
317                 InitializeCriticalSection(&CriticalSection);
318 #endif
319
320         // Context state is now initialized and ready
321         bContextReady = TRUE;
322 }
323
324 // ***********************************************************************
325
326 void dglDeleteContextState()
327 {
328         int i;
329         static BOOL bOnceIsEnough = FALSE;
330
331         // Only call once, from either DGL_exitDriver(), or DLL_PROCESS_DETACH
332         if (bOnceIsEnough)
333                 return;
334         bOnceIsEnough = TRUE;
335
336         for (i=0; i<DGL_MAX_CONTEXTS; i++) {
337                 if (ctxlist[i].bAllocated == TRUE) {
338                         ddlogPrintf(DDLOG_WARN, "** Context %i not deleted - cleaning up.", (i+1));
339                         dglDeleteContext((HGLRC)(i+1));
340                 }
341         }
342
343         // Context state is no longer ready
344         bContextReady = FALSE;
345
346     // If executed when DLL unloads, DDraw objects may be invalid.
347     // So catch any page faults with this exception handler.
348 __try {
349
350         // Release final DirectDraw interfaces
351         if (glb.bDirectDrawPersistant) {
352 //              RELEASE(glb.lpGlobalPalette);
353 //              RELEASE(glb.lpDepth4);
354 //              RELEASE(glb.lpBack4);
355 //              RELEASE(glb.lpPrimary4);
356 //          RELEASE(glb.lpDD4);
357     }
358 }
359 __except(EXCEPTION_EXECUTE_HANDLER) {
360     ddlogPrintf(DDLOG_WARN, "Exception raised in dglDeleteContextState.");
361 }
362
363         // Destroy our event monitor window
364         if (hWndEvent) {
365                 DestroyWindow(hWndEvent);
366                 hWndEvent = hWndLastActive = NULL;
367         }
368
369 #ifdef GLD_THREADS
370         // Destroy the critical section object
371         if (glb.bMultiThreaded)
372                 DeleteCriticalSection(&CriticalSection);
373
374         // Release thread local storage indexes for current HGLRC and pixel format
375         TlsFree(dwTLSPixelFormat);
376         TlsFree(dwTLSCurrentContext);
377 #endif
378 }
379
380 // ***********************************************************************
381
382 // Application Window message handler interception
383 static LONG __stdcall dglWndProc(
384         HWND hwnd,
385         UINT msg,
386         WPARAM wParam,
387         LPARAM lParam)
388 {
389         DGL_ctx*        lpCtx = NULL;
390         LONG            lpfnWndProc = 0L;
391         int             i;
392         HGLRC           hGLRC;
393         RECT            rect;
394         PAINTSTRUCT     ps;
395     BOOL        bQuit = FALSE;
396     BOOL        bMain = FALSE;
397     LONG        rc;
398
399     // Get the window's message handler *before* it is unhooked in WM_DESTROY
400
401     // Is this the main window?
402     if (hwnd == glb.hWndActive) {
403         bMain = TRUE;
404         lpfnWndProc = glb.lpfnWndProc;
405     }
406     // Search for DGL context matching window handle
407     for (i=0; i<DGL_MAX_CONTEXTS; i++) {
408             if (ctxlist[i].hWnd == hwnd) {
409                 lpCtx = &ctxlist[i];
410                 lpfnWndProc = lpCtx->lpfnWndProc;
411                     break;
412         }
413     }
414         // Not one of ours...
415         if (!lpfnWndProc)
416             return DefWindowProc(hwnd, msg, wParam, lParam);
417
418     // Intercept messages amd process *before* passing on to window
419         switch (msg) {
420 #ifdef _USE_GLD3_WGL
421         case WM_DISPLAYCHANGE:
422                 glb.bPixelformatsDirty = TRUE;
423                 break;
424 #endif
425         case WM_ACTIVATEAPP:
426                 glb.bAppActive = (BOOL)wParam;
427                 ddlogPrintf(DDLOG_INFO, "Calling app has been %s", glb.bAppActive ? "activated" : "de-activated");
428                 break;
429         case WM_ERASEBKGND:
430                 // Eat the GDI erase event for the GL window
431         if (!lpCtx || !lpCtx->bHasBeenCurrent)
432             break;
433                 lpCtx->bGDIEraseBkgnd = TRUE;
434                 return TRUE;
435         case WM_PAINT:
436                 // Eat the invalidated update region if render scene is in progress
437         if (!lpCtx || !lpCtx->bHasBeenCurrent)
438             break;
439                 if (lpCtx->bFrameStarted) {
440                         if (GetUpdateRect(hwnd, &rect, FALSE)) {
441                                 BeginPaint(hwnd, &ps);
442                                 EndPaint(hwnd, &ps);
443                                 ValidateRect(hwnd, &rect);
444                                 return TRUE;
445                                 }
446                         }
447                 break;
448         }
449         // Call the appropriate window message handler
450         rc = CallWindowProc((WNDPROC)lpfnWndProc, hwnd, msg, wParam, lParam);
451
452     // Intercept messages and process *after* passing on to window
453         switch (msg) {
454     case WM_QUIT:
455         case WM_DESTROY:
456         bQuit = TRUE;
457                 if (lpCtx && lpCtx->bAllocated) {
458                         ddlogPrintf(DDLOG_WARN, "WM_DESTROY detected for HWND=%X, HDC=%X, HGLRC=%d", hwnd, lpCtx->hDC, i+1);
459                         dglDeleteContext((HGLRC)(i+1));
460                 }
461                 break;
462 #if 0
463         case WM_SIZE:
464                 // Resize surfaces to fit window but not viewport (in case app did not bother)
465         if (!lpCtx || !lpCtx->bHasBeenCurrent)
466             break;
467                 w = LOWORD(lParam);
468                 h = HIWORD(lParam);
469                 if (lpCtx->dwWidth < w || lpCtx->dwHeight < h) {
470                         if (!dglWglResizeBuffers(lpCtx->glCtx, TRUE))
471                  dglWglResizeBuffers(lpCtx->glCtx, FALSE);
472         }
473                 break;
474 #endif
475     }
476
477     // If the main window is quitting, then so should we...
478     if (bMain && bQuit) {
479                 ddlogPrintf(DDLOG_SYSTEM, "shutting down after WM_DESTROY detected for main HWND=%X", hwnd);
480         dglDeleteContextState();
481         dglExitDriver();
482     }
483
484     return rc;
485 }
486
487 // ***********************************************************************
488
489 // Driver Window message handler
490 static LONG __stdcall GLD_EventWndProc(
491         HWND hwnd,
492         UINT msg,
493         WPARAM wParam,
494         LPARAM lParam)
495 {
496         switch (msg) {
497         // May be sent by splash screen dialog on exit
498         case WM_ACTIVATE:
499             if (LOWORD(wParam) == WA_ACTIVE && glb.hWndActive) {
500                 SetForegroundWindow(glb.hWndActive);
501                 return 0;
502                 }
503             break;
504         }
505         return DefWindowProc(hwnd, msg, wParam, lParam);
506 }
507
508 // ***********************************************************************
509
510 // Intercepted Keyboard handler for detecting hot keys.
511 LRESULT CALLBACK dglKeyProc(
512         int code,
513         WPARAM wParam,
514         LPARAM lParam)
515 {
516         HWND hWnd, hWndFrame;
517         HGLRC hGLRC = NULL;
518         DGL_ctx* lpCtx = NULL;
519         int cmd = 0, dx1 = 0, dx2 = 0, i;
520         static BOOL bAltPressed = FALSE;
521         static BOOL bCtrlPressed = FALSE;
522         static BOOL bShiftPressed = FALSE;
523     RECT r, rf, rc;
524     POINT pt;
525     BOOL bForceReshape = FALSE;
526
527         return CallNextHookEx(hKeyHook, code, wParam, lParam);
528 }
529
530 // ***********************************************************************
531
532 HWND hWndMatch;
533
534 // Window handle enumeration procedure.
535 BOOL CALLBACK dglEnumChildProc(
536     HWND hWnd,
537     LPARAM lParam)
538 {
539     RECT rect;
540
541     // Find window handle with matching client rect.
542     GetClientRect(hWnd, &rect);
543     if (EqualRect(&rect, (RECT*)lParam)) {
544         hWndMatch = hWnd;
545         return FALSE;
546         }
547     // Continue with next child window.
548     return TRUE;
549 }
550
551 // ***********************************************************************
552
553 // Find window handle with matching client rect.
554 HWND dglFindWindowRect(
555     RECT* pRect)
556 {
557     hWndMatch = NULL;
558     EnumChildWindows(GetForegroundWindow(), dglEnumChildProc, (LPARAM)pRect);
559     return hWndMatch;
560 }
561
562 // ***********************************************************************
563 #ifndef _USE_GLD3_WGL
564 void dglChooseDisplayMode(
565         DGL_ctx *lpCtx)
566 {
567         // Note: Choose an exact match if possible.
568
569         int                             i;
570         DWORD                   area;
571         DWORD                   bestarea;
572         DDSURFACEDESC2  *lpDDSD         = NULL; // Mode list pointer
573         DDSURFACEDESC2  *lpBestDDSD = NULL;     // Pointer to best
574
575         lpDDSD = glb.lpDisplayModes;
576         for (i=0; i<glb.nDisplayModeCount; i++, lpDDSD++) {
577                 if ((lpDDSD->dwWidth == lpCtx->dwWidth) &&
578                         (lpDDSD->dwHeight == lpCtx->dwHeight))
579                         goto matched; // Mode has been exactly matched
580                 // Choose modes that are larger in both dimensions than
581                 // the window, but smaller in area than the current best.
582                 if ( (lpDDSD->dwWidth >= lpCtx->dwWidth) &&
583                          (lpDDSD->dwHeight >= lpCtx->dwHeight))
584                 {
585                         if (lpBestDDSD == NULL) {
586                                 lpBestDDSD = lpDDSD;
587                                 bestarea = lpDDSD->dwWidth * lpDDSD->dwHeight;
588                                 continue;
589                         }
590                         area = lpDDSD->dwWidth * lpDDSD->dwHeight;
591                         if (area < bestarea) {
592                                 lpBestDDSD = lpDDSD;
593                                 bestarea = area;
594                         }
595                 }
596         }
597
598         // Safety check
599         if (lpBestDDSD == NULL) {
600                 ddlogMessage(DDLOG_CRITICAL, "dglChooseDisplayMode");
601                 return;
602         }
603
604         lpCtx->dwModeWidth = lpBestDDSD->dwWidth;
605         lpCtx->dwModeHeight = lpBestDDSD->dwHeight;
606 matched:
607         ddlogPrintf(DDLOG_INFO, "Matched (%ldx%ld) to (%ldx%ld)",
608                 lpCtx->dwWidth, lpCtx->dwHeight, lpCtx->dwModeWidth, lpCtx->dwModeHeight);
609 }
610 #endif // _USE_GLD3_WGL
611 // ***********************************************************************
612
613 static BOOL IsDevice(
614         DWORD *lpDeviceIdList,
615         DWORD dwDeviceId,
616         int count)
617 {
618         int i;
619
620         for (i=0; i<count; i++)
621                 if (dwDeviceId == lpDeviceIdList[i])
622                         return TRUE;
623
624         return FALSE;
625 }
626
627 // ***********************************************************************
628
629 void dglTestForBrokenCards(
630         DGL_ctx *lpCtx)
631 {
632 #ifndef _GLD3
633         DDDEVICEIDENTIFIER      dddi; // DX6 device identifier
634
635         // Sanity check.
636         if (lpCtx == NULL) {
637                 // Testing for broken cards is sensitive area, so we don't want
638                 // anything saying "broken cards" in the error message. ;)
639                 ddlogMessage(DDLOG_ERROR, "Null context passed to TFBC\n");
640                 return;
641         }
642
643         if (lpCtx->lpDD4 == NULL) {
644                 // Testing for broken cards is sensitive area, so we don't want
645                 // anything saying "broken cards" in the error message. ;)
646                 ddlogMessage(DDLOG_ERROR, "Null DD4 passed to TFBC\n");
647                 return;
648         }
649
650         // Microsoft really fucked up with the GetDeviceIdentifier function
651         // on Windows 2000, since it locks up on stock driers on the CD. Updated
652         // drivers from vendors appear to work, but we can't identify the drivers
653         // without this function!!! For now we skip these tests on Windows 2000.
654         if ((GetVersion() & 0x80000000UL) == 0)
655                 return;
656
657         // Obtain device info
658         if (FAILED(IDirectDraw4_GetDeviceIdentifier(lpCtx->lpDD4, &dddi, 0)))
659                 return;
660
661         // Useful info. Log it.
662         ddlogPrintf(DDLOG_INFO, "DirectDraw: VendorId=0x%x, DeviceId=0x%x", dddi.dwVendorId, dddi.dwDeviceId);
663
664         // Vendor 1: ATI
665         if (dddi.dwVendorId == VENDORID_ATI) {
666                 // Test A: ATI Rage PRO
667                 if (IsDevice(devATIRagePro, dddi.dwDeviceId, sizeof(devATIRagePro)))
668                         glb.bUseMipmaps = FALSE;
669                 // Test B: ATI Rage II+
670                 if (IsDevice(devATIRageIIplus, dddi.dwDeviceId, sizeof(devATIRageIIplus)))
671                         glb.bEmulateAlphaTest = TRUE;
672         }
673
674         // Vendor 2: Matrox
675         if (dddi.dwVendorId == 0x102B) {
676                 // Test: Matrox G400 stencil buffer support does not work for AutoCAD
677                 if (dddi.dwDeviceId == 0x0525) {
678                         lpCtx->lpPF->pfd.cStencilBits = 0;
679                         if (lpCtx->lpPF->iZBufferPF != -1) {
680                                 glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwStencilBitDepth = 0;
681                                 glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwStencilBitMask = 0;
682                                 glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwFlags &= ~DDPF_STENCILBUFFER;
683                         }
684                 }
685         }
686 #endif // _GLD3
687 }
688
689 // ***********************************************************************
690
691 BOOL dglCreateContextBuffers(
692         HDC a,
693         DGL_ctx *lpCtx,
694         BOOL bFallback)
695 {
696         HRESULT                         hResult;
697
698         int                                     i;
699 //      HGLRC                           hGLRC;
700 //      DGL_ctx*                        lpCtx;
701
702 #ifndef _USE_GLD3_WGL
703         DWORD                           dwFlags;
704         DDSURFACEDESC2          ddsd2;
705         DDSCAPS2                        ddscaps2;
706         LPDIRECTDRAWCLIPPER     lpddClipper;
707         D3DDEVICEDESC           D3DHWDevDesc;   // Direct3D Hardware description
708         D3DDEVICEDESC           D3DHELDevDesc;  // Direct3D Hardware Emulation Layer
709 #endif // _USE_GLD3_WGL
710
711         float                           inv_aspect;
712
713         GLenum                          bDoubleBuffer;  // TRUE if double buffer required
714         GLenum                          bDepthBuffer;   // TRUE if depth buffer required
715
716         const PIXELFORMATDESCRIPTOR     *lpPFD = &lpCtx->lpPF->pfd;
717
718         // Vars for Mesa visual
719         DWORD                           dwDepthBits             = 0;
720         DWORD                           dwStencilBits   = 0;
721         DWORD                           dwAlphaBits             = 0;
722         DWORD                           bAlphaSW                = GL_FALSE;
723         DWORD                           bDouble                 = GL_FALSE;
724
725         DDSURFACEDESC2          ddsd2DisplayMode;
726         BOOL                            bFullScrnWin    = FALSE;        // fullscreen-size window ?
727         DDBLTFX                         ddbltfx;
728         DWORD                           dwMemoryType    = (bFallback) ? DDSCAPS_SYSTEMMEMORY : glb.dwMemoryType;
729         BOOL                            bBogusWindow    = FALSE;        // non-drawable window ?
730         DWORD               dwColorRef      = 0;        // GDI background color
731         RECT                            rcDst;                                          // GDI window rect
732         POINT                           pt;                                                     // GDI window point
733
734         // Palette used for creating default global palette
735         PALETTEENTRY    ppe[256];
736
737 #ifndef _USE_GLD3_WGL
738         // Vertex buffer description. Used for creation of vertex buffers
739         D3DVERTEXBUFFERDESC vbufdesc;
740 #endif // _USE_GLD3_WGL
741
742 #define DDLOG_CRITICAL_OR_WARN  (bFallback ? DDLOG_CRITICAL : DDLOG_WARN)
743
744         ddlogPrintf(DDLOG_SYSTEM, "dglCreateContextBuffers for HDC=%X", a);
745     nContextError = GLDERR_NONE;
746
747 #ifdef GLD_THREADS
748         // Serialize access to DirectDraw object creation or DDS start
749         if (glb.bMultiThreaded)
750                 EnterCriticalSection(&CriticalSection);
751 #endif
752
753         // Check for back buffer
754         bDoubleBuffer = GL_TRUE; //(lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? GL_TRUE : GL_FALSE;
755         // Since we always do back buffering, check if we emulate front buffering
756         lpCtx->EmulateSingle =
757                 (lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? FALSE : TRUE;
758 #if 0   // Don't have to mimic MS OpenGL behavior for front-buffering (DaveM)
759         lpCtx->EmulateSingle |=
760                 (lpPFD->dwFlags & PFD_SUPPORT_GDI) ? TRUE : FALSE;
761 #endif
762
763         // Check for depth buffer
764         bDepthBuffer = (lpPFD->cDepthBits) ? GL_TRUE : GL_FALSE;
765
766         lpCtx->bDoubleBuffer = bDoubleBuffer;
767         lpCtx->bDepthBuffer = bDepthBuffer;
768
769         // Set the Fullscreen flag for the context.
770 //      lpCtx->bFullscreen = glb.bFullscreen;
771
772         // Obtain the dimensions of the rendering window
773         lpCtx->hDC = a; // Cache DC
774         lpCtx->hWnd = WindowFromDC(lpCtx->hDC);
775         // Check for non-window DC = memory DC ?
776         if (lpCtx->hWnd == NULL) {
777         // bitmap memory contexts are always single-buffered
778         lpCtx->EmulateSingle = TRUE;
779                 bBogusWindow = TRUE;
780                 ddlogPrintf(DDLOG_INFO, "Non-Window Memory Device Context");
781                 if (GetClipBox(lpCtx->hDC, &lpCtx->rcScreenRect) == ERROR) {
782                         ddlogMessage(DDLOG_WARN, "GetClipBox failed in dglCreateContext\n");
783                         SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0);
784                 }
785         }
786         else if (!GetClientRect(lpCtx->hWnd, &lpCtx->rcScreenRect)) {
787                 bBogusWindow = TRUE;
788                 ddlogMessage(DDLOG_WARN, "GetClientRect failed in dglCreateContext\n");
789                 SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0);
790         }
791         lpCtx->dwWidth = lpCtx->rcScreenRect.right - lpCtx->rcScreenRect.left;
792         lpCtx->dwHeight = lpCtx->rcScreenRect.bottom - lpCtx->rcScreenRect.top;
793
794         ddlogPrintf(DDLOG_INFO, "Input window %X: w=%i, h=%i",
795                                                         lpCtx->hWnd, lpCtx->dwWidth, lpCtx->dwHeight);
796
797         // What if app only zeroes one dimension instead of both? (DaveM)
798         if ( (lpCtx->dwWidth == 0) || (lpCtx->dwHeight == 0) ) {
799                 // Make the buffer size something sensible
800                 lpCtx->dwWidth = 8;
801                 lpCtx->dwHeight = 8;
802         }
803
804         // Set defaults
805         lpCtx->dwModeWidth = lpCtx->dwWidth;
806         lpCtx->dwModeHeight = lpCtx->dwHeight;
807 /*
808         // Find best display mode for fullscreen
809         if (glb.bFullscreen || !glb.bPrimary) {
810                 dglChooseDisplayMode(lpCtx);
811         }
812 */
813         // Misc initialisation
814         lpCtx->bCanRender = FALSE; // No rendering allowed yet
815         lpCtx->bSceneStarted = FALSE;
816         lpCtx->bFrameStarted = FALSE;
817
818         // Detect OS (specifically 'Windows 2000' or 'Windows XP')
819         DetectOS();
820
821         // NOTE: WinNT not supported
822         ddlogPrintf(DDLOG_INFO, "OS: %s", bHaveWin95 ? "Win9x" : (bHaveWin2K ? "Win2000/XP" : "Unsupported") );
823
824         // Test for Fullscreen
825         if (bHaveWin95) { // Problems with fullscreen on Win2K/XP
826                 if ((GetSystemMetrics(SM_CXSCREEN) == lpCtx->dwWidth) && 
827                         (GetSystemMetrics(SM_CYSCREEN) == lpCtx->dwHeight))
828                 {
829                         // Workaround for some apps that crash when going fullscreen.
830                         //lpCtx->bFullscreen = TRUE;
831                 }
832                 
833         }
834
835 #ifdef _USE_GLD3_WGL
836         _gldDriver.CreateDrawable(lpCtx, glb.bDirectDrawPersistant, glb.bPersistantBuffers);
837 #else
838         // Check if DirectDraw has already been created by original GLRC (DaveM)
839         if (glb.bDirectDrawPersistant && glb.bDirectDraw) {
840                 lpCtx->lpDD4 = glb.lpDD4;
841                 IDirectDraw4_AddRef(lpCtx->lpDD4);
842                 goto SkipDirectDrawCreate;
843         }
844
845         // Create DirectDraw object
846         if (glb.bPrimary)
847                 hResult = DirectDrawCreate(NULL, &lpCtx->lpDD1, NULL);
848         else {
849                 // A non-primary device is to be used.
850                 // Force context to be Fullscreen, secondary adaptors can not
851                 // be used in a window.
852                 hResult = DirectDrawCreate(&glb.ddGuid, &lpCtx->lpDD1, NULL);
853                 lpCtx->bFullscreen = TRUE;
854         }
855         if (FAILED(hResult)) {
856                 MessageBox(NULL, "Unable to initialize DirectDraw", "GLDirect", MB_OK);
857                 ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create DirectDraw interface", hResult);
858         nContextError = GLDERR_DDRAW;
859                 goto return_with_error;
860         }
861
862         // Query for DX6 IDirectDraw4.
863         hResult = IDirectDraw_QueryInterface(lpCtx->lpDD1,
864                                                                                  &IID_IDirectDraw4,
865                                                                                  (void**)&lpCtx->lpDD4);
866         if (FAILED(hResult)) {
867                 MessageBox(NULL, "GLDirect requires DirectX 6.0 or above", "GLDirect", MB_OK);
868                 ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create DirectDraw4 interface", hResult);
869         nContextError = GLDERR_DDRAW;
870                 goto return_with_error;
871         }
872
873         // Cache DirectDraw interface for subsequent GLRCs
874         if (glb.bDirectDrawPersistant && !glb.bDirectDraw) {
875                 glb.lpDD4 = lpCtx->lpDD4;
876                 IDirectDraw4_AddRef(glb.lpDD4);
877                 glb.bDirectDraw = TRUE;
878         }
879 SkipDirectDrawCreate:
880
881         // Now we have a DD4 interface we can check for broken cards
882         dglTestForBrokenCards(lpCtx);
883
884         // Test if primary device can use flipping instead of blitting
885         ZeroMemory(&ddsd2DisplayMode, sizeof(ddsd2DisplayMode));
886         ddsd2DisplayMode.dwSize = sizeof(ddsd2DisplayMode);
887         hResult = IDirectDraw4_GetDisplayMode(
888                                         lpCtx->lpDD4,
889                                         &ddsd2DisplayMode);
890         if (SUCCEEDED(hResult)) {
891                 if ( (lpCtx->dwWidth == ddsd2DisplayMode.dwWidth) &&
892                                  (lpCtx->dwHeight == ddsd2DisplayMode.dwHeight) ) {
893                         // We have a fullscreen-size window
894                         bFullScrnWin = TRUE;
895                         // OK to use DirectDraw fullscreen mode ?
896                         if (glb.bPrimary && !glb.bFullscreenBlit && !lpCtx->EmulateSingle && !glb.bDirectDrawPersistant) {
897                                 lpCtx->bFullscreen = TRUE;
898                                 ddlogMessage(DDLOG_INFO, "Primary upgraded to page flipping.\n");
899                         }
900                 }
901                 // Cache the display mode dimensions
902                 lpCtx->dwModeWidth = ddsd2DisplayMode.dwWidth;
903                 lpCtx->dwModeHeight = ddsd2DisplayMode.dwHeight;
904         }
905
906         // Clamp the effective window dimensions to primary surface.
907         // We need to do this for D3D viewport dimensions even if wide
908         // surfaces are supported. This also is a good idea for handling
909         // whacked-out window dimensions passed for non-drawable windows
910         // like Solid Edge. (DaveM)
911         if (lpCtx->dwWidth > ddsd2DisplayMode.dwWidth)
912                 lpCtx->dwWidth = ddsd2DisplayMode.dwWidth;
913         if (lpCtx->dwHeight > ddsd2DisplayMode.dwHeight)
914                 lpCtx->dwHeight = ddsd2DisplayMode.dwHeight;
915
916         // Check for non-RGB desktop resolution
917         if (!lpCtx->bFullscreen && ddsd2DisplayMode.ddpfPixelFormat.dwRGBBitCount <= 8) {
918                 ddlogPrintf(DDLOG_CRITICAL_OR_WARN, "Desktop color depth %d bpp not supported",
919                         ddsd2DisplayMode.ddpfPixelFormat.dwRGBBitCount);
920         nContextError = GLDERR_BPP;
921                 goto return_with_error;
922         }
923 #endif // _USE_GLD3_WGL
924
925         ddlogPrintf(DDLOG_INFO, "Window: w=%i, h=%i (%s)",
926                                                         lpCtx->dwWidth,
927                                                         lpCtx->dwHeight,
928                                                         lpCtx->bFullscreen ? "fullscreen" : "windowed");
929
930 #ifndef _USE_GLD3_WGL
931         // Obtain ddraw caps
932     ZeroMemory(&lpCtx->ddCaps, sizeof(DDCAPS));
933         lpCtx->ddCaps.dwSize = sizeof(DDCAPS);
934         if (glb.bHardware) {
935                 // Get HAL caps
936                 IDirectDraw4_GetCaps(lpCtx->lpDD4, &lpCtx->ddCaps, NULL);
937         } else {
938                 // Get HEL caps
939                 IDirectDraw4_GetCaps(lpCtx->lpDD4, NULL, &lpCtx->ddCaps);
940         }
941
942         // If this flag is present then we can't default to Mesa
943         // SW rendering between BeginScene() and EndScene().
944         if (lpCtx->ddCaps.dwCaps2 & DDCAPS2_NO2DDURING3DSCENE) {
945                 ddlogMessage(DDLOG_INFO,
946                         "Warning          : No 2D allowed during 3D scene.\n");
947         }
948
949         // Query for DX6 Direct3D3 interface
950         hResult = IDirectDraw4_QueryInterface(lpCtx->lpDD4,
951                                                                                   &IID_IDirect3D3,
952                                                                                   (void**)&lpCtx->lpD3D3);
953         if (FAILED(hResult)) {
954                 MessageBox(NULL, "Unable to initialize Direct3D", "GLDirect", MB_OK);
955                 ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create Direct3D interface", hResult);
956         nContextError = GLDERR_D3D;
957                 goto return_with_error;
958         }
959
960         // Context creation
961         if (lpCtx->bFullscreen) {
962                 // FULLSCREEN
963
964         // Disable warning popups when in fullscreen mode
965         ddlogWarnOption(FALSE);
966
967                 // Have to release persistant primary surface if fullscreen mode
968                 if (glb.bDirectDrawPersistant && glb.bDirectDrawPrimary) {
969                         RELEASE(glb.lpPrimary4);
970                         glb.bDirectDrawPrimary = FALSE;
971                 }
972
973                 dwFlags = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT;
974                 if (glb.bFastFPU)
975                         dwFlags |= DDSCL_FPUSETUP;      // fast FPU setup optional (DaveM)
976                 hResult = IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, lpCtx->hWnd, dwFlags);
977                 if (FAILED(hResult)) {
978                         ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to set Exclusive Fullscreen mode", hResult);
979                         goto return_with_error;
980                 }
981
982                 hResult = IDirectDraw4_SetDisplayMode(lpCtx->lpDD4,
983                                                                                           lpCtx->dwModeWidth,
984                                                                                           lpCtx->dwModeHeight,
985                                                                                           lpPFD->cColorBits,
986                                                                                           0,
987                                                                                           0);
988                 if (FAILED(hResult)) {
989                         ddlogError(DDLOG_CRITICAL_OR_WARN, "SetDisplayMode failed", hResult);
990                         goto return_with_error;
991                 }
992
993                 // ** The display mode has changed, so dont use MessageBox! **
994
995                 ZeroMemory(&ddsd2, sizeof(ddsd2));
996                 ddsd2.dwSize = sizeof(ddsd2);
997
998                 if (bDoubleBuffer) {
999                         // Double buffered
1000                         // Primary surface
1001                         ddsd2.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
1002                         ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
1003                                                                    DDSCAPS_FLIP |
1004                                                                    DDSCAPS_COMPLEX |
1005                                                                    DDSCAPS_3DDEVICE |
1006                                                                    dwMemoryType;
1007                         ddsd2.dwBackBufferCount = 1;
1008
1009                         hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL);
1010                         if (FAILED(hResult)) {
1011                                 ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult);
1012                 nContextError = GLDERR_MEM;
1013                                 goto return_with_error;
1014                         }
1015
1016                         // Render target surface
1017                         ZeroMemory(&ddscaps2, sizeof(ddscaps2)); // Clear the entire struct.
1018                         ddscaps2.dwCaps = DDSCAPS_BACKBUFFER;
1019                         hResult = IDirectDrawSurface4_GetAttachedSurface(lpCtx->lpFront4, &ddscaps2, &lpCtx->lpBack4);
1020                         if (FAILED(hResult)) {
1021                                 ddlogError(DDLOG_CRITICAL_OR_WARN, "GetAttachedSurface failed", hResult);
1022                 nContextError = GLDERR_MEM;
1023                                 goto return_with_error;
1024                         }
1025                 } else {
1026                         // Single buffered
1027                         // Primary surface
1028                         ddsd2.dwFlags = DDSD_CAPS;
1029                         ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
1030                                                                    //DDSCAPS_3DDEVICE |
1031                                                                    dwMemoryType;
1032
1033                         hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL);
1034                         if (FAILED(hResult)) {
1035                                 ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult);
1036                 nContextError = GLDERR_MEM;
1037                                 goto return_with_error;
1038                         }
1039
1040                         lpCtx->lpBack4 = NULL;
1041                 }
1042         } else {
1043                 // WINDOWED
1044
1045         // OK to enable warning popups in windowed mode
1046         ddlogWarnOption(glb.bMessageBoxWarnings);
1047
1048                 dwFlags = DDSCL_NORMAL;
1049                 if (glb.bMultiThreaded)
1050                         dwFlags |= DDSCL_MULTITHREADED;
1051                 if (glb.bFastFPU)
1052                         dwFlags |= DDSCL_FPUSETUP;      // fast FPU setup optional (DaveM)
1053                 hResult = IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4,
1054                                                                                                   lpCtx->hWnd,
1055                                                                                                   dwFlags);
1056                 if (FAILED(hResult)) {
1057                         ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to set Normal coop level", hResult);
1058                         goto return_with_error;
1059                 }
1060                 // Has Primary surface already been created for original GLRC ?
1061                 // Note this can only be applicable for windowed modes
1062                 if (glb.bDirectDrawPersistant && glb.bDirectDrawPrimary) {
1063                         lpCtx->lpFront4 = glb.lpPrimary4;
1064                         IDirectDrawSurface4_AddRef(lpCtx->lpFront4);
1065                         // Update the window on the default clipper
1066                         IDirectDrawSurface4_GetClipper(lpCtx->lpFront4, &lpddClipper);
1067                         IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd);
1068                         IDirectDrawClipper_Release(lpddClipper);
1069                         goto SkipPrimaryCreate;
1070                 }
1071
1072                 // Primary surface
1073                 ZeroMemory(&ddsd2, sizeof(ddsd2));
1074                 ddsd2.dwSize = sizeof(ddsd2);
1075                 ddsd2.dwFlags = DDSD_CAPS;
1076                 ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
1077                 hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL);
1078                 if (FAILED(hResult)) {
1079                         ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult);
1080             nContextError = GLDERR_MEM;
1081                         goto return_with_error;
1082                 }
1083
1084                 // Cache Primary surface for subsequent GLRCs
1085                 // Note this can only be applicable to subsequent windowed modes
1086                 if (glb.bDirectDrawPersistant && !glb.bDirectDrawPrimary) {
1087                         glb.lpPrimary4 = lpCtx->lpFront4;
1088                         IDirectDrawSurface4_AddRef(glb.lpPrimary4);
1089                         glb.bDirectDrawPrimary = TRUE;
1090                 }
1091
1092                 // Clipper object
1093                 hResult = DirectDrawCreateClipper(0, &lpddClipper, NULL);
1094                 if (FAILED(hResult)) {
1095                         ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateClipper failed", hResult);
1096                         goto return_with_error;
1097                 }
1098                 hResult = IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd);
1099                 if (FAILED(hResult)) {
1100                         RELEASE(lpddClipper);
1101                         ddlogError(DDLOG_CRITICAL_OR_WARN, "SetHWnd failed", hResult);
1102                         goto return_with_error;
1103                 }
1104                 hResult = IDirectDrawSurface4_SetClipper(lpCtx->lpFront4, lpddClipper);
1105                 RELEASE(lpddClipper); // We have finished with it.
1106                 if (FAILED(hResult)) {
1107                         ddlogError(DDLOG_CRITICAL_OR_WARN, "SetClipper failed", hResult);
1108                         goto return_with_error;
1109                 }
1110 SkipPrimaryCreate:
1111
1112                 if (bDoubleBuffer) {
1113                         // Render target surface
1114                         ZeroMemory(&ddsd2, sizeof(ddsd2));
1115                         ddsd2.dwSize = sizeof(ddsd2);
1116                         ddsd2.dwFlags        = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
1117                         ddsd2.dwWidth        = lpCtx->dwWidth;
1118                         ddsd2.dwHeight       = lpCtx->dwHeight;
1119                         ddsd2.ddsCaps.dwCaps = DDSCAPS_3DDEVICE |
1120                                                                    DDSCAPS_OFFSCREENPLAIN |
1121                                                                    dwMemoryType;
1122
1123                         // Reserve the entire desktop size for persistant buffers option
1124                         if (glb.bDirectDrawPersistant && glb.bPersistantBuffers) {
1125                                 ddsd2.dwWidth = ddsd2DisplayMode.dwWidth;
1126                                 ddsd2.dwHeight = ddsd2DisplayMode.dwHeight;
1127                         }
1128                         // Re-use original back buffer if persistant buffers exist
1129                         if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpBack4)
1130                                 hResult = IDirectDrawSurface4_AddRef(lpCtx->lpBack4 = glb.lpBack4);
1131                         else
1132                                 hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpBack4, NULL);
1133                         if (FAILED(hResult)) {
1134                                 ddlogError(DDLOG_CRITICAL_OR_WARN, "Create Backbuffer failed", hResult);
1135                 nContextError = GLDERR_MEM;
1136                                 goto return_with_error;
1137                         }
1138                         if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpBack4)
1139                                 IDirectDrawSurface4_AddRef(glb.lpBack4 = lpCtx->lpBack4);
1140                 } else {
1141                         lpCtx->lpBack4 = NULL;
1142                 }
1143         }
1144
1145         //
1146         // Now create the Z-buffer
1147         //
1148         lpCtx->bStencil = FALSE; // Default to no stencil buffer
1149         if (bDepthBuffer && (lpCtx->lpPF->iZBufferPF != -1)) {
1150                 // Get z-buffer dimensions from the render target
1151                 // Setup the surface desc for the z-buffer.
1152                 ZeroMemory(&ddsd2, sizeof(ddsd2));
1153                 ddsd2.dwSize = sizeof(ddsd2);
1154                 ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
1155                 ddsd2.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | dwMemoryType;
1156                 ddsd2.dwWidth = lpCtx->dwWidth;
1157                 ddsd2.dwHeight = lpCtx->dwHeight;
1158                 memcpy(&ddsd2.ddpfPixelFormat,
1159                         &glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF],
1160                         sizeof(DDPIXELFORMAT) );
1161
1162                 // Reserve the entire desktop size for persistant buffers option
1163                 if (glb.bDirectDrawPersistant && glb.bPersistantBuffers) {
1164                         ddsd2.dwWidth = ddsd2DisplayMode.dwWidth;
1165                         ddsd2.dwHeight = ddsd2DisplayMode.dwHeight;
1166                 }
1167
1168                 // Create a z-buffer
1169                 if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpDepth4)
1170                         hResult = IDirectDrawSurface4_AddRef(lpCtx->lpDepth4 = glb.lpDepth4);
1171                 else
1172                         hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpDepth4, NULL);
1173                 if (FAILED(hResult)) {
1174                         ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (ZBuffer) failed", hResult);
1175             nContextError = GLDERR_MEM;
1176                         goto return_with_error;
1177                 }
1178                 if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpDepth4)
1179                         IDirectDrawSurface4_AddRef(glb.lpDepth4 = lpCtx->lpDepth4);
1180                 else if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpDepth4 && glb.lpBack4)
1181                         IDirectDrawSurface4_DeleteAttachedSurface(glb.lpBack4, 0, glb.lpDepth4);
1182
1183                 // Attach Zbuffer to render target
1184                 TRY(IDirectDrawSurface4_AddAttachedSurface(
1185                         bDoubleBuffer ? lpCtx->lpBack4 : lpCtx->lpFront4,
1186                         lpCtx->lpDepth4),
1187                         "dglCreateContext: Attach Zbuffer");
1188                 if (glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwFlags & DDPF_STENCILBUFFER) {
1189                         lpCtx->bStencil = TRUE;
1190                         ddlogMessage(DDLOG_INFO, "Depth buffer has stencil\n");
1191                 }
1192         }
1193
1194         // Clear all back buffers and Z-buffers in case of memory recycling.
1195         ZeroMemory(&ddbltfx, sizeof(ddbltfx));
1196         ddbltfx.dwSize = sizeof(ddbltfx);
1197         IDirectDrawSurface4_Blt(lpCtx->lpBack4, NULL, NULL, NULL,
1198                 DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
1199         if (lpCtx->lpDepth4)
1200                 IDirectDrawSurface4_Blt(lpCtx->lpDepth4, NULL, NULL, NULL,
1201                         DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
1202
1203         // Now that we have a Z-buffer we can create the 3D device
1204         hResult = IDirect3D3_CreateDevice(lpCtx->lpD3D3,
1205                                                                           &glb.d3dGuid,
1206                                                                           bDoubleBuffer ? lpCtx->lpBack4 : lpCtx->lpFront4,
1207                                                                           &lpCtx->lpDev3,
1208                                                                           NULL);
1209         if (FAILED(hResult)) {
1210                 ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create Direct3D device", hResult);
1211         nContextError = GLDERR_D3D;
1212                 goto return_with_error;
1213         }
1214
1215         // We must do this as soon as the device is created
1216         dglInitStateCaches(lpCtx);
1217
1218         // Obtain the D3D Device Description
1219         D3DHWDevDesc.dwSize = D3DHELDevDesc.dwSize = sizeof(D3DDEVICEDESC);
1220         TRY(IDirect3DDevice3_GetCaps(lpCtx->lpDev3,
1221                                                                  &D3DHWDevDesc,
1222                                                                  &D3DHELDevDesc),
1223                                                                  "dglCreateContext: GetCaps failed");
1224
1225         // Choose the relevant description and cache it in the context.
1226         // We will use this description later for caps checking
1227         memcpy( &lpCtx->D3DDevDesc,
1228                         glb.bHardware ? &D3DHWDevDesc : &D3DHELDevDesc,
1229                         sizeof(D3DDEVICEDESC));
1230
1231         // Now we can examine the texture formats
1232         if (!dglBuildTextureFormatList(lpCtx->lpDev3)) {
1233                 ddlogMessage(DDLOG_CRITICAL_OR_WARN, "dglBuildTextureFormatList failed\n");
1234                 goto return_with_error;
1235         }
1236
1237         // Get the pixel format of the back buffer
1238         lpCtx->ddpfRender.dwSize = sizeof(lpCtx->ddpfRender);
1239         if (bDoubleBuffer)
1240                 hResult = IDirectDrawSurface4_GetPixelFormat(
1241                                         lpCtx->lpBack4,
1242                                         &lpCtx->ddpfRender);
1243         else
1244                 hResult = IDirectDrawSurface4_GetPixelFormat(
1245                                         lpCtx->lpFront4,
1246                                         &lpCtx->ddpfRender);
1247
1248         if (FAILED(hResult)) {
1249                 ddlogError(DDLOG_CRITICAL_OR_WARN, "GetPixelFormat failed", hResult);
1250                 goto return_with_error;
1251         }
1252         // Find a pixel packing function suitable for this surface
1253         pxClassifyPixelFormat(&lpCtx->ddpfRender,
1254                                                   &lpCtx->fnPackFunc,
1255                                                   &lpCtx->fnUnpackFunc,
1256                                                   &lpCtx->fnPackSpanFunc);
1257
1258         // Viewport
1259         hResult = IDirect3D3_CreateViewport(lpCtx->lpD3D3, &lpCtx->lpViewport3, NULL);
1260         if (FAILED(hResult)) {
1261                 ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateViewport failed", hResult);
1262                 goto return_with_error;
1263         }
1264
1265         hResult = IDirect3DDevice3_AddViewport(lpCtx->lpDev3, lpCtx->lpViewport3);
1266         if (FAILED(hResult)) {
1267                 ddlogError(DDLOG_CRITICAL_OR_WARN, "AddViewport failed", hResult);
1268                 goto return_with_error;
1269         }
1270
1271         // Initialise the viewport
1272         // Note screen coordinates are used for viewport clipping since D3D
1273         // transform operations are not used in the GLD CAD driver. (DaveM)
1274         inv_aspect = (float)lpCtx->dwHeight/(float)lpCtx->dwWidth;
1275
1276         lpCtx->d3dViewport.dwSize = sizeof(lpCtx->d3dViewport);
1277         lpCtx->d3dViewport.dwX = 0;
1278         lpCtx->d3dViewport.dwY = 0;
1279         lpCtx->d3dViewport.dwWidth = lpCtx->dwWidth;
1280         lpCtx->d3dViewport.dwHeight = lpCtx->dwHeight;
1281         lpCtx->d3dViewport.dvClipX = 0; // -1.0f;
1282         lpCtx->d3dViewport.dvClipY = 0; // inv_aspect;
1283         lpCtx->d3dViewport.dvClipWidth = lpCtx->dwWidth; // 2.0f;
1284         lpCtx->d3dViewport.dvClipHeight = lpCtx->dwHeight; // 2.0f * inv_aspect;
1285         lpCtx->d3dViewport.dvMinZ = 0.0f;
1286         lpCtx->d3dViewport.dvMaxZ = 1.0f;
1287         TRY(IDirect3DViewport3_SetViewport2(lpCtx->lpViewport3, &lpCtx->d3dViewport), "dglCreateContext: SetViewport2");
1288
1289         hResult = IDirect3DDevice3_SetCurrentViewport(lpCtx->lpDev3, lpCtx->lpViewport3);
1290         if (FAILED(hResult)) {
1291                 ddlogError(DDLOG_CRITICAL_OR_WARN, "SetCurrentViewport failed", hResult);
1292                 goto return_with_error;
1293         }
1294
1295         lpCtx->dwBPP = lpPFD->cColorBits;
1296         lpCtx->iZBufferPF = lpCtx->lpPF->iZBufferPF;
1297
1298         // Set last texture to NULL
1299         for (i=0; i<MAX_TEXTURE_UNITS; i++) {
1300                 lpCtx->ColorOp[i] = D3DTOP_DISABLE;
1301                 lpCtx->AlphaOp[i] = D3DTOP_DISABLE;
1302                 lpCtx->tObj[i] = NULL;
1303         }
1304
1305         // Default to perspective correct texture mapping
1306         dglSetRenderState(lpCtx, D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE, "TexturePersp");
1307
1308         // Set the default culling mode
1309         lpCtx->cullmode = D3DCULL_NONE;
1310         dglSetRenderState(lpCtx, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE, "CullMode");
1311
1312         // Disable specular
1313         dglSetRenderState(lpCtx, D3DRENDERSTATE_SPECULARENABLE, FALSE, "SpecularEnable");
1314         // Disable subpixel correction
1315 //      dglSetRenderState(lpCtx, D3DRENDERSTATE_SUBPIXEL, FALSE, "SubpixelEnable");
1316         // Disable dithering
1317         dglSetRenderState(lpCtx, D3DRENDERSTATE_DITHERENABLE, FALSE, "DitherEnable");
1318
1319         // Initialise the primitive caches
1320 //      lpCtx->dwNextLineVert   = 0;
1321 //      lpCtx->dwNextTriVert    = 0;
1322
1323         // Init the global texture palette
1324         lpCtx->lpGlobalPalette = NULL;
1325
1326         // Init the HW/SW usage counters
1327 //      lpCtx->dwHWUsageCount = lpCtx->dwSWUsageCount = 0L;
1328
1329         //
1330         // Create two D3D vertex buffers.
1331         // One will hold the pre-transformed data with the other one
1332         // being used to hold the post-transformed & clipped verts.
1333         //
1334 #if 0  // never used (DaveM)
1335         vbufdesc.dwSize = sizeof(D3DVERTEXBUFFERDESC);
1336         vbufdesc.dwCaps = D3DVBCAPS_WRITEONLY;
1337         if (glb.bHardware == FALSE)
1338                 vbufdesc.dwCaps = D3DVBCAPS_SYSTEMMEMORY;
1339         vbufdesc.dwNumVertices = 32768; // For the time being
1340
1341         // Source vertex buffer
1342         vbufdesc.dwFVF = DGL_LVERTEX;
1343         hResult = IDirect3D3_CreateVertexBuffer(lpCtx->lpD3D3, &vbufdesc, &lpCtx->m_vbuf, 0, NULL);
1344         if (FAILED(hResult)) {
1345                 ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateVertexBuffer(src) failed", hResult);
1346                 goto return_with_error;
1347         }
1348
1349         // Destination vertex buffer
1350         vbufdesc.dwFVF = (glb.bMultitexture == FALSE) ? D3DFVF_TLVERTEX : (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX2);
1351         hResult = IDirect3D3_CreateVertexBuffer(lpCtx->lpD3D3, &vbufdesc, &lpCtx->m_pvbuf, 0, NULL);
1352         if(FAILED(hResult)) {
1353                 ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateVertexBuffer(dst) failed", hResult);
1354                 goto return_with_error;
1355         }
1356 #endif
1357
1358 #endif _USE_GLD3_WGL
1359
1360         //
1361         //      Now create the Mesa context
1362         //
1363
1364         // Create the Mesa visual
1365         if (lpPFD->cDepthBits)
1366                 dwDepthBits = 16;
1367         if (lpPFD->cStencilBits)
1368                 dwStencilBits = 8;
1369         if (lpPFD->cAlphaBits) {
1370                 dwAlphaBits = 8;
1371                 bAlphaSW = GL_TRUE;
1372         }
1373         if (lpPFD->dwFlags & PFD_DOUBLEBUFFER)
1374                 bDouble = GL_TRUE;
1375 //      lpCtx->EmulateSingle =
1376 //              (lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? FALSE : TRUE;
1377
1378 #ifdef _USE_GLD3_WGL
1379         lpCtx->glVis = _mesa_create_visual(
1380                 bDouble,    /* double buffer */
1381                 GL_FALSE,                       // stereo
1382                 lpPFD->cRedBits,
1383                 lpPFD->cGreenBits,
1384                 lpPFD->cBlueBits,
1385                 dwAlphaBits,
1386                 dwDepthBits,
1387                 dwStencilBits,
1388                 lpPFD->cAccumRedBits,   // accum bits
1389                 lpPFD->cAccumGreenBits, // accum bits
1390                 lpPFD->cAccumBlueBits,  // accum bits
1391                 lpPFD->cAccumAlphaBits, // accum alpha bits
1392                 1                               // num samples
1393                 );
1394 #else // _USE_GLD3_WGL
1395         lpCtx->glVis = (*mesaFuncs.gl_create_visual)(
1396                 GL_TRUE,                        // RGB mode
1397                 bAlphaSW,                       // Is an alpha buffer required?
1398                 bDouble,                        // Is an double-buffering required?
1399                 GL_FALSE,                       // stereo
1400                 dwDepthBits,            // depth_size
1401                 dwStencilBits,          // stencil_size
1402                 lpPFD->cAccumBits,      // accum_size
1403                 0,                                      // colour-index bits
1404                 lpPFD->cRedBits,        // Red bit count
1405                 lpPFD->cGreenBits,      // Green bit count
1406                 lpPFD->cBlueBits,       // Blue bit count
1407                 dwAlphaBits                     // Alpha bit count
1408                 );
1409 #endif // _USE_GLD3_WGL
1410
1411         if (lpCtx->glVis == NULL) {
1412                 ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_visual failed\n");
1413                 goto return_with_error;
1414         }
1415
1416 #ifdef _USE_GLD3_WGL
1417         lpCtx->glCtx = _mesa_create_context(API_OPENGL, lpCtx->glVis, NULL, (void *)lpCtx, GL_TRUE);
1418 #else
1419         // Create the Mesa context
1420         lpCtx->glCtx = (*mesaFuncs.gl_create_context)(
1421                                         lpCtx->glVis,   // Mesa visual
1422                                         NULL,                   // share list context
1423                                         (void *)lpCtx,  // Pointer to our driver context
1424                                         GL_TRUE                 // Direct context flag
1425                                    );
1426 #endif // _USE_GLD3_WGL
1427
1428         if (lpCtx->glCtx == NULL) {
1429                 ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_context failed\n");
1430                 goto return_with_error;
1431         }
1432
1433         // Create the Mesa framebuffer
1434 #ifdef _USE_GLD3_WGL
1435         lpCtx->glBuffer = _mesa_create_framebuffer(
1436                 lpCtx->glVis,
1437                 lpCtx->glVis->depthBits > 0,
1438                 lpCtx->glVis->stencilBits > 0,
1439                 lpCtx->glVis->accumRedBits > 0,
1440                 GL_FALSE //swalpha
1441                 );
1442 #else
1443         lpCtx->glBuffer = (*mesaFuncs.gl_create_framebuffer)(lpCtx->glVis);
1444 #endif // _USE_GLD3_WGL
1445
1446         if (lpCtx->glBuffer == NULL) {
1447                 ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_framebuffer failed\n");
1448                 goto return_with_error;
1449         }
1450
1451 #ifdef _USE_GLD3_WGL
1452         // Init Mesa internals
1453         _swrast_CreateContext( lpCtx->glCtx );
1454         _vbo_CreateContext( lpCtx->glCtx );
1455         _tnl_CreateContext( lpCtx->glCtx );
1456         _swsetup_CreateContext( lpCtx->glCtx );
1457
1458         _gldDriver.InitialiseMesa(lpCtx);
1459         
1460         lpCtx->glCtx->imports.warning   = _gld_mesa_warning;
1461         lpCtx->glCtx->imports.fatal             = _gld_mesa_fatal;
1462
1463 #else
1464         // Tell Mesa how many texture stages we have
1465         glb.wMaxSimultaneousTextures = lpCtx->D3DDevDesc.wMaxSimultaneousTextures;
1466         // Only use as many Units as the spec requires
1467         if (glb.wMaxSimultaneousTextures > MAX_TEXTURE_UNITS)
1468                 glb.wMaxSimultaneousTextures = MAX_TEXTURE_UNITS;
1469         lpCtx->glCtx->Const.MaxTextureUnits = glb.wMaxSimultaneousTextures;
1470         ddlogPrintf(DDLOG_INFO, "Texture stages   : %d", glb.wMaxSimultaneousTextures);
1471
1472         // Set the max texture size.
1473         // NOTE: clamped to a max of 1024 for extra performance!
1474         lpCtx->dwMaxTextureSize = (lpCtx->D3DDevDesc.dwMaxTextureWidth <= 1024) ? lpCtx->D3DDevDesc.dwMaxTextureWidth : 1024;
1475
1476 // Texture resize takes place elsewhere. KH
1477 // NOTE: This was added to workaround an issue with the Intel app.
1478 #if 0
1479         lpCtx->glCtx->Const.MaxTextureSize = lpCtx->dwMaxTextureSize;
1480 #else
1481         lpCtx->glCtx->Const.MaxTextureSize = 1024;
1482 #endif
1483         lpCtx->glCtx->Const.MaxDrawBuffers = 1;
1484
1485         // Setup the Display Driver pointers
1486         dglSetupDDPointers(lpCtx->glCtx);
1487
1488         // Initialise all the Direct3D renderstates
1489         dglInitStateD3D(lpCtx->glCtx);
1490
1491 #if 0
1492         // Signal a reload of texture state on next glBegin
1493         lpCtx->m_texHandleValid = FALSE;
1494         lpCtx->m_mtex = FALSE;
1495         lpCtx->m_texturing = FALSE;
1496 #else
1497         // Set default texture unit state
1498 //      dglSetTexture(lpCtx, 0, NULL);
1499 //      dglSetTexture(lpCtx, 1, NULL);
1500 #endif
1501
1502         //
1503         // Set the global texture palette to default values.
1504         //
1505
1506         // Clear the entire palette
1507         ZeroMemory(ppe, sizeof(PALETTEENTRY) * 256);
1508
1509         // Fill the palette with a default colour.
1510         // A garish colour is used to catch bugs. Here Magenta is used.
1511         for (i=0; i < 256; i++) {
1512                 ppe[i].peRed    = 255;
1513                 ppe[i].peGreen  = 0;
1514                 ppe[i].peBlue   = 255;
1515         }
1516
1517         RELEASE(lpCtx->lpGlobalPalette);
1518
1519         if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpGlobalPalette)
1520                 hResult = IDirectDrawPalette_AddRef(lpCtx->lpGlobalPalette = glb.lpGlobalPalette);
1521         else
1522                 hResult = IDirectDraw4_CreatePalette(
1523                                 lpCtx->lpDD4,
1524                                 DDPCAPS_INITIALIZE | DDPCAPS_8BIT | DDPCAPS_ALLOW256,
1525                                 ppe,
1526                                 &(lpCtx->lpGlobalPalette),
1527                                 NULL);
1528         if (FAILED(hResult)) {
1529                 ddlogError(DDLOG_ERROR, "Default CreatePalette failed\n", hResult);
1530                 lpCtx->lpGlobalPalette = NULL;
1531                 goto return_with_error;
1532         }
1533         if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpGlobalPalette)
1534                 IDirectDrawPalette_AddRef(glb.lpGlobalPalette = lpCtx->lpGlobalPalette);
1535
1536 #endif // _USE_GLD3_WGL
1537
1538         // ** If we have made it to here then we can enable rendering **
1539         lpCtx->bCanRender = TRUE;
1540
1541 //      ddlogMessage(DDLOG_SYSTEM, "dglCreateContextBuffers succeded\n");
1542
1543 #ifdef GLD_THREADS
1544         // Release serialized access
1545         if (glb.bMultiThreaded)
1546                 LeaveCriticalSection(&CriticalSection);
1547 #endif
1548
1549         return TRUE;
1550
1551 return_with_error:
1552         // Clean up before returning.
1553         // This is critical for secondary devices.
1554
1555         lpCtx->bCanRender = FALSE;
1556
1557 #ifdef _USE_GLD3_WGL
1558         // Destroy the Mesa context
1559         if (lpCtx->glBuffer)
1560                 _mesa_destroy_framebuffer(lpCtx->glBuffer);
1561         if (lpCtx->glCtx)
1562                 _mesa_destroy_context(lpCtx->glCtx);
1563         if (lpCtx->glVis)
1564                 _mesa_destroy_visual(lpCtx->glVis);
1565
1566         // Destroy driver data
1567         _gldDriver.DestroyDrawable(lpCtx);
1568 #else
1569         // Destroy the Mesa context
1570         if (lpCtx->glBuffer)
1571                 (*mesaFuncs.gl_destroy_framebuffer)(lpCtx->glBuffer);
1572         if (lpCtx->glCtx)
1573                 (*mesaFuncs.gl_destroy_context)(lpCtx->glCtx);
1574         if (lpCtx->glVis)
1575                 (*mesaFuncs.gl_destroy_visual)(lpCtx->glVis);
1576
1577         RELEASE(lpCtx->m_pvbuf); // Release D3D vertex buffer
1578         RELEASE(lpCtx->m_vbuf); // Release D3D vertex buffer
1579
1580         if (lpCtx->lpViewport3) {
1581                 if (lpCtx->lpDev3) IDirect3DDevice3_DeleteViewport(lpCtx->lpDev3, lpCtx->lpViewport3);
1582                 RELEASE(lpCtx->lpViewport3);
1583                 lpCtx->lpViewport3 = NULL;
1584         }
1585
1586         RELEASE(lpCtx->lpDev3);
1587         if (lpCtx->lpDepth4) {
1588                 if (lpCtx->lpBack4)
1589                         IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpBack4, 0L, lpCtx->lpDepth4);
1590                 else
1591                         IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpFront4, 0L, lpCtx->lpDepth4);
1592                 RELEASE(lpCtx->lpDepth4);
1593                 lpCtx->lpDepth4 = NULL;
1594         }
1595         RELEASE(lpCtx->lpBack4);
1596         RELEASE(lpCtx->lpFront4);
1597         else
1598         if (lpCtx->bFullscreen) {
1599                 IDirectDraw4_RestoreDisplayMode(lpCtx->lpDD4);
1600                 IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, NULL, DDSCL_NORMAL);
1601         }
1602         RELEASE(lpCtx->lpD3D3);
1603         RELEASE(lpCtx->lpDD4);
1604         RELEASE(lpCtx->lpDD1);
1605 #endif // _USE_GLD3_WGL
1606
1607         lpCtx->bAllocated = FALSE;
1608
1609 #ifdef GLD_THREADS
1610         // Release serialized access
1611         if (glb.bMultiThreaded)
1612                 LeaveCriticalSection(&CriticalSection);
1613 #endif
1614
1615         return FALSE;
1616
1617 #undef DDLOG_CRITICAL_OR_WARN
1618 }
1619
1620 // ***********************************************************************
1621
1622 HGLRC dglCreateContext(
1623         HDC a,
1624         const DGL_pixelFormat *lpPF)
1625 {
1626         int i;
1627         HGLRC                           hGLRC;
1628         DGL_ctx*                        lpCtx;
1629         static BOOL                     bWarnOnce = TRUE;
1630         DWORD                           dwThreadId = GetCurrentThreadId();
1631     char                szMsg[256];
1632     HWND                hWnd;
1633     LONG                lpfnWndProc;
1634
1635         // Validate license
1636         if (!dglValidate())
1637                 return NULL;
1638
1639         // Is context state ready ?
1640         if (!bContextReady)
1641                 return NULL;
1642
1643         ddlogPrintf(DDLOG_SYSTEM, "dglCreateContext for HDC=%X, ThreadId=%X", a, dwThreadId);
1644
1645         // Find next free context.
1646         // Also ensure that only one Fullscreen context is created at any one time.
1647         hGLRC = 0; // Default to Not Found
1648         for (i=0; i<DGL_MAX_CONTEXTS; i++) {
1649                 if (ctxlist[i].bAllocated) {
1650                         if (/*glb.bFullscreen && */ctxlist[i].bFullscreen)
1651                                 break;
1652                 } else {
1653                         hGLRC = (HGLRC)(i+1);
1654                         break;
1655                 }
1656         }
1657
1658         // Bail if no GLRC was found
1659         if (!hGLRC)
1660                 return NULL;
1661
1662         // Set the context pointer
1663         lpCtx = dglGetContextAddress(hGLRC);
1664         // Make sure that context is zeroed before we do anything.
1665         // MFC and C++ apps call wglCreateContext() and wglDeleteContext() multiple times,
1666         // even though only one context is ever used by the app, so keep it clean. (DaveM)
1667         ZeroMemory(lpCtx, sizeof(DGL_ctx));
1668         lpCtx->bAllocated = TRUE;
1669         // Flag that buffers need creating on next wglMakeCurrent call.
1670         lpCtx->bHasBeenCurrent = FALSE;
1671         lpCtx->lpPF = (DGL_pixelFormat *)lpPF;  // cache pixel format
1672         lpCtx->bCanRender = FALSE;
1673
1674         // Create all the internal resources here, not in dglMakeCurrent().
1675         // We do a re-size check in dglMakeCurrent in case of re-allocations. (DaveM)
1676         // We now try context allocations twice, first with video memory,
1677         // then again with system memory. This is similar to technique
1678         // used for dglWglResizeBuffers(). (DaveM)
1679         if (lpCtx->bHasBeenCurrent == FALSE) {
1680                 if (!dglCreateContextBuffers(a, lpCtx, FALSE)) {
1681                         if (glb.bMessageBoxWarnings && bWarnOnce && dwLogging) {
1682                                 bWarnOnce = FALSE;
1683                 switch (nContextError) {
1684                    case GLDERR_DDRAW: strcpy(szMsg, szDDrawWarning); break;
1685                    case GLDERR_D3D: strcpy(szMsg, szD3DWarning); break;
1686                    case GLDERR_MEM: strcpy(szMsg, szResourceWarning); break;
1687                    case GLDERR_BPP: strcpy(szMsg, szBPPWarning); break;
1688                    default: strcpy(szMsg, "");
1689                 }
1690                 if (strlen(szMsg))
1691                     MessageBox(NULL, szMsg, "GLDirect", MB_OK | MB_ICONWARNING);
1692                         }
1693             // Only need to try again if memory error
1694             if (nContextError == GLDERR_MEM) {
1695                             ddlogPrintf(DDLOG_WARN, "dglCreateContext failed 1st time with video memory");
1696             }
1697             else {
1698                             ddlogPrintf(DDLOG_ERROR, "dglCreateContext failed");
1699                 return NULL;
1700             }
1701                 }
1702         }
1703
1704         // Now that we have a hWnd, we can intercept the WindowProc.
1705     hWnd = lpCtx->hWnd;
1706     if (hWnd) {
1707                 // Only hook individual window handler once if not hooked before.
1708                 lpfnWndProc = GetWindowLong(hWnd, GWL_WNDPROC);
1709                 if (lpfnWndProc != (LONG)dglWndProc) {
1710                         lpCtx->lpfnWndProc = lpfnWndProc;
1711                         SetWindowLong(hWnd, GWL_WNDPROC, (LONG)dglWndProc);
1712                         }
1713         // Find the parent window of the app too.
1714         if (glb.hWndActive == NULL) {
1715             while (hWnd != NULL) {
1716                 glb.hWndActive = hWnd;
1717                 hWnd = GetParent(hWnd);
1718             }
1719             // Hook the parent window too.
1720             lpfnWndProc = GetWindowLong(glb.hWndActive, GWL_WNDPROC);
1721             if (glb.hWndActive == lpCtx->hWnd)
1722                 glb.lpfnWndProc = lpCtx->lpfnWndProc;
1723             else if (lpfnWndProc != (LONG)dglWndProc)
1724                 glb.lpfnWndProc = lpfnWndProc;
1725             if (glb.lpfnWndProc)
1726                 SetWindowLong(glb.hWndActive, GWL_WNDPROC, (LONG)dglWndProc);
1727         }
1728     }
1729
1730         ddlogPrintf(DDLOG_SYSTEM, "dglCreateContext succeeded for HGLRC=%d", (int)hGLRC);
1731
1732         return hGLRC;
1733 }
1734
1735 // ***********************************************************************
1736 // Make a DirectGL context current
1737 // Used by wgl functions and dgl functions
1738 BOOL dglMakeCurrent(
1739         HDC a,
1740         HGLRC b)
1741 {
1742         int context;
1743         DGL_ctx* lpCtx;
1744         HWND hWnd;
1745         BOOL bNeedResize = FALSE;
1746         BOOL bWindowChanged, bContextChanged;
1747         LPDIRECTDRAWCLIPPER     lpddClipper;
1748         DWORD dwThreadId = GetCurrentThreadId();
1749         LONG lpfnWndProc;
1750
1751         // Validate license
1752         if (!dglValidate())
1753                 return FALSE;
1754
1755         // Is context state ready ?
1756         if (!bContextReady)
1757                 return FALSE;
1758
1759         context = (int)b; // This is as a result of STRICT!
1760         ddlogPrintf(DDLOG_SYSTEM, "dglMakeCurrent: HDC=%X, HGLRC=%d, ThreadId=%X", a, context, dwThreadId);
1761
1762         // If the HGLRC is NULL then make no context current;
1763         // Ditto if the HDC is NULL either. (DaveM)
1764         if (context == 0 || a == 0) {
1765                 // Corresponding Mesa operation
1766 #ifdef _USE_GLD3_WGL
1767                 _mesa_make_current(NULL, NULL);
1768 #else
1769                 (*mesaFuncs.gl_make_current)(NULL, NULL);
1770 #endif
1771                 dglSetCurrentContext(0);
1772                 return TRUE;
1773         }
1774
1775         // Make sure the HGLRC is in range
1776         if ((context > DGL_MAX_CONTEXTS) || (context < 0)) {
1777                 ddlogMessage(DDLOG_ERROR, "dglMakeCurrent: HGLRC out of range\n");
1778                 return FALSE;
1779         }
1780
1781         // Find address of context and make sure that it has been allocated
1782         lpCtx = dglGetContextAddress(b);
1783         if (!lpCtx->bAllocated) {
1784                 ddlogMessage(DDLOG_ERROR, "dglMakeCurrent: Context not allocated\n");
1785 //              return FALSE;
1786                 return TRUE; // HACK: Shuts up "WebLab Viewer Pro". KeithH
1787         }
1788
1789 #ifdef GLD_THREADS
1790         // Serialize access to DirectDraw or DDS operations
1791         if (glb.bMultiThreaded)
1792                 EnterCriticalSection(&CriticalSection);
1793 #endif
1794
1795         // Check if window has changed
1796         hWnd = (a != lpCtx->hDC) ? WindowFromDC(a) : lpCtx->hWnd;
1797         bWindowChanged = (hWnd != lpCtx->hWnd) ? TRUE : FALSE;
1798         bContextChanged = (b != dglGetCurrentContext()) ? TRUE : FALSE;
1799
1800         // If the window has changed, make sure the clipper is updated. (DaveM)
1801         if (glb.bDirectDrawPersistant && !lpCtx->bFullscreen && (bWindowChanged || bContextChanged)) {
1802                 lpCtx->hWnd = hWnd;
1803 #ifndef _USE_GLD3_WGL
1804                 IDirectDrawSurface4_GetClipper(lpCtx->lpFront4, &lpddClipper);
1805                 IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd);
1806                 IDirectDrawClipper_Release(lpddClipper);
1807 #endif // _USE_GLD3_WGL
1808         }
1809
1810         // Make sure hDC and hWnd is current. (DaveM)
1811         // Obtain the dimensions of the rendering window
1812         lpCtx->hDC = a; // Cache DC
1813         lpCtx->hWnd = hWnd;
1814         hWndLastActive = hWnd;
1815
1816         // Check for non-window DC = memory DC ?
1817         if (hWnd == NULL) {
1818                 if (GetClipBox(a, &lpCtx->rcScreenRect) == ERROR) {
1819                         ddlogMessage(DDLOG_WARN, "GetClipBox failed in dglMakeCurrent\n");
1820                         SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0);
1821                 }
1822         }
1823         else if (!GetClientRect(lpCtx->hWnd, &lpCtx->rcScreenRect)) {
1824                 ddlogMessage(DDLOG_WARN, "GetClientRect failed in dglMakeCurrent\n");
1825                 SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0);
1826         }
1827         // Check if buffers need to be re-sized;
1828         // If so, wait until Mesa GL stuff is setup before re-sizing;
1829         if (lpCtx->dwWidth != lpCtx->rcScreenRect.right - lpCtx->rcScreenRect.left ||
1830                 lpCtx->dwHeight != lpCtx->rcScreenRect.bottom - lpCtx->rcScreenRect.top)
1831                 bNeedResize = TRUE;
1832
1833         // Now we can update our globals
1834         dglSetCurrentContext(b);
1835
1836         // Corresponding Mesa operation
1837 #ifdef _USE_GLD3_WGL
1838         _mesa_make_current(lpCtx->glCtx, lpCtx->glBuffer);
1839         lpCtx->glCtx->Driver.UpdateState(lpCtx->glCtx, _NEW_ALL);
1840         if (bNeedResize) {
1841                 // Resize buffers (Note Mesa GL needs to be setup beforehand);
1842                 // Resize Mesa internal buffer too via glViewport() command,
1843                 // which subsequently calls dglWglResizeBuffers() too.
1844                 lpCtx->glCtx->Driver.Viewport(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
1845                 lpCtx->bHasBeenCurrent = TRUE;
1846         }
1847 #else
1848         (*mesaFuncs.gl_make_current)(lpCtx->glCtx, lpCtx->glBuffer);
1849
1850         dglSetupDDPointers(lpCtx->glCtx);
1851
1852         // Insure DirectDraw surfaces fit current window DC
1853         if (bNeedResize) {
1854                 // Resize buffers (Note Mesa GL needs to be setup beforehand);
1855                 // Resize Mesa internal buffer too via glViewport() command,
1856                 // which subsequently calls dglWglResizeBuffers() too.
1857                 (*mesaFuncs.gl_Viewport)(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
1858                 lpCtx->bHasBeenCurrent = TRUE;
1859         }
1860 #endif // _USE_GLD3_WGL
1861         ddlogPrintf(DDLOG_SYSTEM, "dglMakeCurrent: width = %d, height = %d", lpCtx->dwWidth, lpCtx->dwHeight);
1862
1863         // We have to clear D3D back buffer and render state if emulated front buffering
1864         // for different window (but not context) like in Solid Edge.
1865         if (glb.bDirectDrawPersistant && glb.bPersistantBuffers
1866                 && (bWindowChanged /* || bContextChanged */) && lpCtx->EmulateSingle) {
1867 #ifdef _USE_GLD3_WGL
1868 //              IDirect3DDevice8_EndScene(lpCtx->pDev);
1869 //              lpCtx->bSceneStarted = FALSE;
1870                 lpCtx->glCtx->Driver.Clear(lpCtx->glCtx, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
1871                         GL_TRUE, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
1872 #else
1873                 IDirect3DDevice3_EndScene(lpCtx->lpDev3);
1874                 lpCtx->bSceneStarted = FALSE;
1875                 dglClearD3D(lpCtx->glCtx, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
1876                         GL_TRUE, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
1877 #endif // _USE_GLD3_WGL
1878         }
1879
1880         // The first time we call MakeCurrent we set the initial viewport size
1881         if (lpCtx->bHasBeenCurrent == FALSE)
1882 #ifdef _USE_GLD3_WGL
1883                 lpCtx->glCtx->Driver.Viewport(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
1884 #else
1885                 (*mesaFuncs.gl_Viewport)(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
1886 #endif // _USE_GLD3_WGL
1887         lpCtx->bHasBeenCurrent = TRUE;
1888
1889 #ifdef GLD_THREADS
1890         // Release serialized access
1891         if (glb.bMultiThreaded)
1892                 LeaveCriticalSection(&CriticalSection);
1893 #endif
1894
1895         return TRUE;
1896 }
1897
1898 // ***********************************************************************
1899
1900 BOOL dglDeleteContext(
1901         HGLRC a)
1902 {
1903         DGL_ctx* lpCtx;
1904         DWORD dwThreadId = GetCurrentThreadId();
1905     char argstr[256];
1906
1907 #if 0   // We have enough trouble throwing exceptions as it is... (DaveM)
1908         // Validate license
1909         if (!dglValidate())
1910                 return FALSE;
1911 #endif
1912
1913         // Is context state ready ?
1914         if (!bContextReady)
1915                 return FALSE;
1916
1917         ddlogPrintf(DDLOG_SYSTEM, "dglDeleteContext: Deleting context HGLRC=%d, ThreadId=%X", (int)a, dwThreadId);
1918
1919         // Make sure the HGLRC is in range
1920         if (((int) a> DGL_MAX_CONTEXTS) || ((int)a < 0)) {
1921                 ddlogMessage(DDLOG_ERROR, "dglDeleteCurrent: HGLRC out of range\n");
1922                 return FALSE;
1923         }
1924
1925         // Make sure context is valid
1926         lpCtx = dglGetContextAddress(a);
1927         if (!lpCtx->bAllocated) {
1928                 ddlogPrintf(DDLOG_WARN, "Tried to delete unallocated context HGLRC=%d", (int)a);
1929 //              return FALSE;
1930                 return TRUE; // HACK: Shuts up "WebLab Viewer Pro". KeithH
1931         }
1932
1933         // Make sure context is de-activated
1934         if (a == dglGetCurrentContext()) {
1935                 ddlogPrintf(DDLOG_WARN, "dglDeleteContext: context HGLRC=%d still active", (int)a);
1936                 dglMakeCurrent(NULL, NULL);
1937         }
1938
1939 #ifdef GLD_THREADS
1940         // Serialize access to DirectDraw or DDS operations
1941         if (glb.bMultiThreaded)
1942                 EnterCriticalSection(&CriticalSection);
1943 #endif
1944
1945         // We are about to destroy all Direct3D objects.
1946         // Therefore we must disable rendering
1947         lpCtx->bCanRender = FALSE;
1948
1949         // This exception handler was installed to catch some
1950         // particularly nasty apps. Console apps that call exit()
1951         // fall into this catagory (i.e. Win32 Glut).
1952
1953     // VC cannot successfully implement multiple exception handlers
1954     // if more than one exception occurs. Therefore reverting back to
1955     // single exception handler as Keith originally had it. (DaveM)
1956
1957 #define WARN_MESSAGE(p) strcpy(argstr, (#p));
1958 #define SAFE_RELEASE(p) WARN_MESSAGE(p); RELEASE(p);
1959
1960 __try {
1961 #ifdef _USE_GLD3_WGL
1962     WARN_MESSAGE(gl_destroy_framebuffer);
1963         if (lpCtx->glBuffer)
1964                 _mesa_destroy_framebuffer(lpCtx->glBuffer);
1965     WARN_MESSAGE(gl_destroy_context);
1966         if (lpCtx->glCtx)
1967                 _mesa_destroy_context(lpCtx->glCtx);
1968     WARN_MESSAGE(gl_destroy_visual);
1969         if (lpCtx->glVis)
1970                 _mesa_destroy_visual(lpCtx->glVis);
1971
1972         _gldDriver.DestroyDrawable(lpCtx);
1973 #else
1974         // Destroy the Mesa context
1975     WARN_MESSAGE(gl_destroy_framebuffer);
1976         if (lpCtx->glBuffer)
1977                 (*mesaFuncs.gl_destroy_framebuffer)(lpCtx->glBuffer);
1978     WARN_MESSAGE(gl_destroy_context);
1979         if (lpCtx->glCtx)
1980                 (*mesaFuncs.gl_destroy_context)(lpCtx->glCtx);
1981     WARN_MESSAGE(gl_destroy_visual);
1982         if (lpCtx->glVis)
1983                 (*mesaFuncs.gl_destroy_visual)(lpCtx->glVis);
1984
1985         SAFE_RELEASE(lpCtx->m_pvbuf); // release D3D vertex buffer
1986         SAFE_RELEASE(lpCtx->m_vbuf); // release D3D vertex buffer
1987
1988         // Delete the global palette
1989         SAFE_RELEASE(lpCtx->lpGlobalPalette);
1990
1991         // Clean up.
1992         if (lpCtx->lpViewport3) {
1993                 if (lpCtx->lpDev3) IDirect3DDevice3_DeleteViewport(lpCtx->lpDev3, lpCtx->lpViewport3);
1994                 SAFE_RELEASE(lpCtx->lpViewport3);
1995                 lpCtx->lpViewport3 = NULL;
1996         }
1997
1998         SAFE_RELEASE(lpCtx->lpDev3);
1999         if (lpCtx->lpDepth4) {
2000                 if (lpCtx->lpBack4)
2001                         IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpBack4, 0L, lpCtx->lpDepth4);
2002                 else
2003                         IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpFront4, 0L, lpCtx->lpDepth4);
2004                 SAFE_RELEASE(lpCtx->lpDepth4);
2005                 lpCtx->lpDepth4 = NULL;
2006         }
2007         SAFE_RELEASE(lpCtx->lpBack4);
2008         SAFE_RELEASE(lpCtx->lpFront4);
2009         if (lpCtx->bFullscreen) {
2010                 IDirectDraw4_RestoreDisplayMode(lpCtx->lpDD4);
2011                 IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, NULL, DDSCL_NORMAL);
2012         }
2013         SAFE_RELEASE(lpCtx->lpD3D3);
2014         SAFE_RELEASE(lpCtx->lpDD4);
2015         SAFE_RELEASE(lpCtx->lpDD1);
2016 #endif // _ULSE_GLD3_WGL
2017
2018 }
2019 __except(EXCEPTION_EXECUTE_HANDLER) {
2020     ddlogPrintf(DDLOG_WARN, "Exception raised in dglDeleteContext: %s", argstr);
2021 }
2022
2023         // Restore the window message handler because this context may be used
2024         // again by another window with a *different* message handler. (DaveM)
2025         if (lpCtx->lpfnWndProc) {
2026                 SetWindowLong(lpCtx->hWnd, GWL_WNDPROC, (LONG)lpCtx->lpfnWndProc);
2027                 lpCtx->lpfnWndProc = (LONG)NULL;
2028                 }
2029
2030         lpCtx->bAllocated = FALSE; // This context is now free for use
2031
2032 #ifdef GLD_THREADS
2033         // Release serialized access
2034         if (glb.bMultiThreaded)
2035                 LeaveCriticalSection(&CriticalSection);
2036 #endif
2037
2038         return TRUE;
2039 }
2040
2041 // ***********************************************************************
2042
2043 BOOL dglSwapBuffers(
2044         HDC hDC)
2045 {
2046         RECT            rSrcRect;       // Source rectangle
2047         RECT            rDstRect;       // Destination rectangle
2048         POINT           pt;
2049         HRESULT         hResult;
2050
2051         DDBLTFX         bltFX;
2052         DWORD           dwBlitFlags;
2053         DDBLTFX         *lpBltFX;
2054
2055 //      DWORD           dwThreadId = GetCurrentThreadId();
2056         HGLRC           hGLRC = dglGetCurrentContext();
2057         DGL_ctx         *lpCtx = dglGetContextAddress(hGLRC);
2058         HWND            hWnd;
2059
2060         HDC             hDCAux;         // for memory DC
2061         int             x,y,w,h;        // for memory DC BitBlt
2062
2063 #if 0   // Perhaps not a good idea. Called too often. KH
2064         // Validate license
2065         if (!dglValidate())
2066                 return FALSE;
2067 #endif
2068
2069         if (!lpCtx) {
2070                 return TRUE; //FALSE; // No current context
2071         }
2072
2073         if (!lpCtx->bCanRender) {
2074                 // Don't return false else some apps will bail.
2075                 return TRUE;
2076         }
2077
2078         hWnd = lpCtx->hWnd;
2079         if (hDC != lpCtx->hDC) {
2080                 ddlogPrintf(DDLOG_WARN, "dglSwapBuffers: HDC=%X does not match HDC=%X for HGLRC=%d", hDC, lpCtx->hDC, hGLRC);
2081                 hWnd = WindowFromDC(hDC);
2082         }
2083
2084 #ifndef _USE_GLD3_WGL
2085         // Ensure that the surfaces exist before we tell
2086         // the device to render to them.
2087         IDirectDraw4_RestoreAllSurfaces(lpCtx->lpDD4);
2088
2089         // Make sure that the vertex caches have been emptied
2090 //      dglStateChange(lpCtx);
2091
2092         // Some OpenGL programs don't issue a glFinish - check for it here.
2093         if (lpCtx->bSceneStarted) {
2094                 IDirect3DDevice3_EndScene(lpCtx->lpDev3);
2095                 lpCtx->bSceneStarted = FALSE;
2096         }
2097 #endif
2098
2099 #if 0
2100         // If the calling app is not active then we don't need to Blit/Flip.
2101         // We can therefore simply return TRUE.
2102         if (!glb.bAppActive)
2103                 return TRUE;
2104         // Addendum: This is WRONG! We should bail if the app is *minimized*,
2105         //           not merely if the app is just plain 'not active'.
2106         //           KeithH, 27/May/2000.
2107 #endif
2108
2109         // Check for non-window DC = memory DC ?
2110         if (hWnd == NULL) {
2111                 if (GetClipBox(hDC, &rSrcRect) == ERROR)
2112                         return TRUE;
2113                 // Use GDI BitBlt instead from compatible DirectDraw DC
2114                 x = rSrcRect.left;
2115                 y = rSrcRect.top;
2116                 w = rSrcRect.right - rSrcRect.left;
2117                 h = rSrcRect.bottom - rSrcRect.top;
2118
2119                 // Ack. DX8 does not have a GetDC() function...
2120                 // TODO: Defer to DX7 or DX9 drivers... (DaveM)
2121                 return TRUE;
2122         }
2123
2124         // Bail if window client region is not drawable, like in Solid Edge
2125         if (!IsWindow(hWnd) /* || !IsWindowVisible(hWnd) */ || !GetClientRect(hWnd, &rSrcRect))
2126                 return TRUE;
2127
2128 #ifdef GLD_THREADS
2129         // Serialize access to DirectDraw or DDS operations
2130         if (glb.bMultiThreaded)
2131                 EnterCriticalSection(&CriticalSection);
2132 #endif
2133
2134 #ifdef _USE_GLD3_WGL
2135         // Notify Mesa of impending swap, so Mesa can flush internal buffers.
2136         _mesa_notifySwapBuffers(lpCtx->glCtx);
2137         // Now perform driver buffer swap
2138         _gldDriver.SwapBuffers(lpCtx, hDC, hWnd);
2139 #else
2140         if (lpCtx->bFullscreen) {
2141                 // Sync with retrace if required
2142                 if (glb.bWaitForRetrace) {
2143                         IDirectDraw4_WaitForVerticalBlank(
2144                                 lpCtx->lpDD4,
2145                                 DDWAITVB_BLOCKBEGIN,
2146                                 0);
2147                 }
2148
2149                 // Perform the fullscreen flip
2150                 TRY(IDirectDrawSurface4_Flip(
2151                         lpCtx->lpFront4,
2152                         NULL,
2153                         DDFLIP_WAIT),
2154                         "dglSwapBuffers: Flip");
2155         } else {
2156                 // Calculate current window position and size
2157                 pt.x = pt.y = 0;
2158                 ClientToScreen(hWnd, &pt);
2159                 GetClientRect(hWnd, &rDstRect);
2160                 if (rDstRect.right > lpCtx->dwModeWidth)
2161                         rDstRect.right = lpCtx->dwModeWidth;
2162                 if (rDstRect.bottom > lpCtx->dwModeHeight)
2163                         rDstRect.bottom = lpCtx->dwModeHeight;
2164                 OffsetRect(&rDstRect, pt.x, pt.y);
2165                 rSrcRect.left = rSrcRect.top = 0;
2166                 rSrcRect.right = lpCtx->dwWidth;
2167                 rSrcRect.bottom = lpCtx->dwHeight;
2168                 if (rSrcRect.right > lpCtx->dwModeWidth)
2169                         rSrcRect.right = lpCtx->dwModeWidth;
2170                 if (rSrcRect.bottom > lpCtx->dwModeHeight)
2171                         rSrcRect.bottom = lpCtx->dwModeHeight;
2172
2173                 if (glb.bWaitForRetrace) {
2174                         // Sync the blit to the vertical retrace
2175                         ZeroMemory(&bltFX, sizeof(bltFX));
2176                         bltFX.dwSize = sizeof(bltFX);
2177                         bltFX.dwDDFX = DDBLTFX_NOTEARING;
2178                         dwBlitFlags = DDBLT_WAIT | DDBLT_DDFX;
2179                         lpBltFX = &bltFX;
2180                 } else {
2181                         dwBlitFlags = DDBLT_WAIT;
2182                         lpBltFX = NULL;
2183                 }
2184
2185                 // Perform the actual blit
2186                 TRY(IDirectDrawSurface4_Blt(
2187                         lpCtx->lpFront4,
2188                         &rDstRect,
2189                         lpCtx->lpBack4, // Blit source
2190                         &rSrcRect,
2191                         dwBlitFlags,
2192                         lpBltFX),
2193                         "dglSwapBuffers: Blt");
2194         }
2195 #endif // _USE_GLD3_WGL
2196
2197 #ifdef GLD_THREADS
2198         // Release serialized access
2199         if (glb.bMultiThreaded)
2200                 LeaveCriticalSection(&CriticalSection);
2201 #endif
2202
2203     // TODO: Re-instate rendering bitmap snapshot feature??? (DaveM)
2204
2205         // Render frame is completed
2206         ValidateRect(hWnd, NULL);
2207         lpCtx->bFrameStarted = FALSE;
2208
2209         return TRUE;
2210 }
2211
2212 // ***********************************************************************