Merge branch 'origin' into glsl-compiler-1
[mesa.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(GLcontext *, char *);
46 extern void _gld_mesa_fatal(GLcontext *, 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 GL_TRUE, // RGB mode
1381 bDouble, /* double buffer */
1382 GL_FALSE, // stereo
1383 lpPFD->cRedBits,
1384 lpPFD->cGreenBits,
1385 lpPFD->cBlueBits,
1386 dwAlphaBits,
1387 0, // index bits
1388 dwDepthBits,
1389 dwStencilBits,
1390 lpPFD->cAccumRedBits, // accum bits
1391 lpPFD->cAccumGreenBits, // accum bits
1392 lpPFD->cAccumBlueBits, // accum bits
1393 lpPFD->cAccumAlphaBits, // accum alpha bits
1394 1 // num samples
1395 );
1396 #else // _USE_GLD3_WGL
1397 lpCtx->glVis = (*mesaFuncs.gl_create_visual)(
1398 GL_TRUE, // RGB mode
1399 bAlphaSW, // Is an alpha buffer required?
1400 bDouble, // Is an double-buffering required?
1401 GL_FALSE, // stereo
1402 dwDepthBits, // depth_size
1403 dwStencilBits, // stencil_size
1404 lpPFD->cAccumBits, // accum_size
1405 0, // colour-index bits
1406 lpPFD->cRedBits, // Red bit count
1407 lpPFD->cGreenBits, // Green bit count
1408 lpPFD->cBlueBits, // Blue bit count
1409 dwAlphaBits // Alpha bit count
1410 );
1411 #endif // _USE_GLD3_WGL
1412
1413 if (lpCtx->glVis == NULL) {
1414 ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_visual failed\n");
1415 goto return_with_error;
1416 }
1417
1418 #ifdef _USE_GLD3_WGL
1419 lpCtx->glCtx = _mesa_create_context(lpCtx->glVis, NULL, (void *)lpCtx, GL_TRUE);
1420 #else
1421 // Create the Mesa context
1422 lpCtx->glCtx = (*mesaFuncs.gl_create_context)(
1423 lpCtx->glVis, // Mesa visual
1424 NULL, // share list context
1425 (void *)lpCtx, // Pointer to our driver context
1426 GL_TRUE // Direct context flag
1427 );
1428 #endif // _USE_GLD3_WGL
1429
1430 if (lpCtx->glCtx == NULL) {
1431 ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_context failed\n");
1432 goto return_with_error;
1433 }
1434
1435 // Create the Mesa framebuffer
1436 #ifdef _USE_GLD3_WGL
1437 lpCtx->glBuffer = _mesa_create_framebuffer(
1438 lpCtx->glVis,
1439 lpCtx->glVis->depthBits > 0,
1440 lpCtx->glVis->stencilBits > 0,
1441 lpCtx->glVis->accumRedBits > 0,
1442 GL_FALSE //swalpha
1443 );
1444 #else
1445 lpCtx->glBuffer = (*mesaFuncs.gl_create_framebuffer)(lpCtx->glVis);
1446 #endif // _USE_GLD3_WGL
1447
1448 if (lpCtx->glBuffer == NULL) {
1449 ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_framebuffer failed\n");
1450 goto return_with_error;
1451 }
1452
1453 #ifdef _USE_GLD3_WGL
1454 // Init Mesa internals
1455 _swrast_CreateContext( lpCtx->glCtx );
1456 _vbo_CreateContext( lpCtx->glCtx );
1457 _tnl_CreateContext( lpCtx->glCtx );
1458 _swsetup_CreateContext( lpCtx->glCtx );
1459
1460 _gldDriver.InitialiseMesa(lpCtx);
1461
1462 lpCtx->glCtx->imports.warning = _gld_mesa_warning;
1463 lpCtx->glCtx->imports.fatal = _gld_mesa_fatal;
1464
1465 #else
1466 // Tell Mesa how many texture stages we have
1467 glb.wMaxSimultaneousTextures = lpCtx->D3DDevDesc.wMaxSimultaneousTextures;
1468 // Only use as many Units as the spec requires
1469 if (glb.wMaxSimultaneousTextures > MAX_TEXTURE_UNITS)
1470 glb.wMaxSimultaneousTextures = MAX_TEXTURE_UNITS;
1471 lpCtx->glCtx->Const.MaxTextureUnits = glb.wMaxSimultaneousTextures;
1472 ddlogPrintf(DDLOG_INFO, "Texture stages : %d", glb.wMaxSimultaneousTextures);
1473
1474 // Set the max texture size.
1475 // NOTE: clamped to a max of 1024 for extra performance!
1476 lpCtx->dwMaxTextureSize = (lpCtx->D3DDevDesc.dwMaxTextureWidth <= 1024) ? lpCtx->D3DDevDesc.dwMaxTextureWidth : 1024;
1477
1478 // Texture resize takes place elsewhere. KH
1479 // NOTE: This was added to workaround an issue with the Intel app.
1480 #if 0
1481 lpCtx->glCtx->Const.MaxTextureSize = lpCtx->dwMaxTextureSize;
1482 #else
1483 lpCtx->glCtx->Const.MaxTextureSize = 1024;
1484 #endif
1485
1486 // Setup the Display Driver pointers
1487 dglSetupDDPointers(lpCtx->glCtx);
1488
1489 // Initialise all the Direct3D renderstates
1490 dglInitStateD3D(lpCtx->glCtx);
1491
1492 #if 0
1493 // Signal a reload of texture state on next glBegin
1494 lpCtx->m_texHandleValid = FALSE;
1495 lpCtx->m_mtex = FALSE;
1496 lpCtx->m_texturing = FALSE;
1497 #else
1498 // Set default texture unit state
1499 // dglSetTexture(lpCtx, 0, NULL);
1500 // dglSetTexture(lpCtx, 1, NULL);
1501 #endif
1502
1503 //
1504 // Set the global texture palette to default values.
1505 //
1506
1507 // Clear the entire palette
1508 ZeroMemory(ppe, sizeof(PALETTEENTRY) * 256);
1509
1510 // Fill the palette with a default colour.
1511 // A garish colour is used to catch bugs. Here Magenta is used.
1512 for (i=0; i < 256; i++) {
1513 ppe[i].peRed = 255;
1514 ppe[i].peGreen = 0;
1515 ppe[i].peBlue = 255;
1516 }
1517
1518 RELEASE(lpCtx->lpGlobalPalette);
1519
1520 if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpGlobalPalette)
1521 hResult = IDirectDrawPalette_AddRef(lpCtx->lpGlobalPalette = glb.lpGlobalPalette);
1522 else
1523 hResult = IDirectDraw4_CreatePalette(
1524 lpCtx->lpDD4,
1525 DDPCAPS_INITIALIZE | DDPCAPS_8BIT | DDPCAPS_ALLOW256,
1526 ppe,
1527 &(lpCtx->lpGlobalPalette),
1528 NULL);
1529 if (FAILED(hResult)) {
1530 ddlogError(DDLOG_ERROR, "Default CreatePalette failed\n", hResult);
1531 lpCtx->lpGlobalPalette = NULL;
1532 goto return_with_error;
1533 }
1534 if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpGlobalPalette)
1535 IDirectDrawPalette_AddRef(glb.lpGlobalPalette = lpCtx->lpGlobalPalette);
1536
1537 #endif // _USE_GLD3_WGL
1538
1539 // ** If we have made it to here then we can enable rendering **
1540 lpCtx->bCanRender = TRUE;
1541
1542 // ddlogMessage(DDLOG_SYSTEM, "dglCreateContextBuffers succeded\n");
1543
1544 #ifdef GLD_THREADS
1545 // Release serialized access
1546 if (glb.bMultiThreaded)
1547 LeaveCriticalSection(&CriticalSection);
1548 #endif
1549
1550 return TRUE;
1551
1552 return_with_error:
1553 // Clean up before returning.
1554 // This is critical for secondary devices.
1555
1556 lpCtx->bCanRender = FALSE;
1557
1558 #ifdef _USE_GLD3_WGL
1559 // Destroy the Mesa context
1560 if (lpCtx->glBuffer)
1561 _mesa_destroy_framebuffer(lpCtx->glBuffer);
1562 if (lpCtx->glCtx)
1563 _mesa_destroy_context(lpCtx->glCtx);
1564 if (lpCtx->glVis)
1565 _mesa_destroy_visual(lpCtx->glVis);
1566
1567 // Destroy driver data
1568 _gldDriver.DestroyDrawable(lpCtx);
1569 #else
1570 // Destroy the Mesa context
1571 if (lpCtx->glBuffer)
1572 (*mesaFuncs.gl_destroy_framebuffer)(lpCtx->glBuffer);
1573 if (lpCtx->glCtx)
1574 (*mesaFuncs.gl_destroy_context)(lpCtx->glCtx);
1575 if (lpCtx->glVis)
1576 (*mesaFuncs.gl_destroy_visual)(lpCtx->glVis);
1577
1578 RELEASE(lpCtx->m_pvbuf); // Release D3D vertex buffer
1579 RELEASE(lpCtx->m_vbuf); // Release D3D vertex buffer
1580
1581 if (lpCtx->lpViewport3) {
1582 if (lpCtx->lpDev3) IDirect3DDevice3_DeleteViewport(lpCtx->lpDev3, lpCtx->lpViewport3);
1583 RELEASE(lpCtx->lpViewport3);
1584 lpCtx->lpViewport3 = NULL;
1585 }
1586
1587 RELEASE(lpCtx->lpDev3);
1588 if (lpCtx->lpDepth4) {
1589 if (lpCtx->lpBack4)
1590 IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpBack4, 0L, lpCtx->lpDepth4);
1591 else
1592 IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpFront4, 0L, lpCtx->lpDepth4);
1593 RELEASE(lpCtx->lpDepth4);
1594 lpCtx->lpDepth4 = NULL;
1595 }
1596 RELEASE(lpCtx->lpBack4);
1597 RELEASE(lpCtx->lpFront4);
1598 else
1599 if (lpCtx->bFullscreen) {
1600 IDirectDraw4_RestoreDisplayMode(lpCtx->lpDD4);
1601 IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, NULL, DDSCL_NORMAL);
1602 }
1603 RELEASE(lpCtx->lpD3D3);
1604 RELEASE(lpCtx->lpDD4);
1605 RELEASE(lpCtx->lpDD1);
1606 #endif // _USE_GLD3_WGL
1607
1608 lpCtx->bAllocated = FALSE;
1609
1610 #ifdef GLD_THREADS
1611 // Release serialized access
1612 if (glb.bMultiThreaded)
1613 LeaveCriticalSection(&CriticalSection);
1614 #endif
1615
1616 return FALSE;
1617
1618 #undef DDLOG_CRITICAL_OR_WARN
1619 }
1620
1621 // ***********************************************************************
1622
1623 HGLRC dglCreateContext(
1624 HDC a,
1625 const DGL_pixelFormat *lpPF)
1626 {
1627 int i;
1628 HGLRC hGLRC;
1629 DGL_ctx* lpCtx;
1630 static BOOL bWarnOnce = TRUE;
1631 DWORD dwThreadId = GetCurrentThreadId();
1632 char szMsg[256];
1633 HWND hWnd;
1634 LONG lpfnWndProc;
1635
1636 // Validate license
1637 if (!dglValidate())
1638 return NULL;
1639
1640 // Is context state ready ?
1641 if (!bContextReady)
1642 return NULL;
1643
1644 ddlogPrintf(DDLOG_SYSTEM, "dglCreateContext for HDC=%X, ThreadId=%X", a, dwThreadId);
1645
1646 // Find next free context.
1647 // Also ensure that only one Fullscreen context is created at any one time.
1648 hGLRC = 0; // Default to Not Found
1649 for (i=0; i<DGL_MAX_CONTEXTS; i++) {
1650 if (ctxlist[i].bAllocated) {
1651 if (/*glb.bFullscreen && */ctxlist[i].bFullscreen)
1652 break;
1653 } else {
1654 hGLRC = (HGLRC)(i+1);
1655 break;
1656 }
1657 }
1658
1659 // Bail if no GLRC was found
1660 if (!hGLRC)
1661 return NULL;
1662
1663 // Set the context pointer
1664 lpCtx = dglGetContextAddress(hGLRC);
1665 // Make sure that context is zeroed before we do anything.
1666 // MFC and C++ apps call wglCreateContext() and wglDeleteContext() multiple times,
1667 // even though only one context is ever used by the app, so keep it clean. (DaveM)
1668 ZeroMemory(lpCtx, sizeof(DGL_ctx));
1669 lpCtx->bAllocated = TRUE;
1670 // Flag that buffers need creating on next wglMakeCurrent call.
1671 lpCtx->bHasBeenCurrent = FALSE;
1672 lpCtx->lpPF = (DGL_pixelFormat *)lpPF; // cache pixel format
1673 lpCtx->bCanRender = FALSE;
1674
1675 // Create all the internal resources here, not in dglMakeCurrent().
1676 // We do a re-size check in dglMakeCurrent in case of re-allocations. (DaveM)
1677 // We now try context allocations twice, first with video memory,
1678 // then again with system memory. This is similar to technique
1679 // used for dglWglResizeBuffers(). (DaveM)
1680 if (lpCtx->bHasBeenCurrent == FALSE) {
1681 if (!dglCreateContextBuffers(a, lpCtx, FALSE)) {
1682 if (glb.bMessageBoxWarnings && bWarnOnce && dwLogging) {
1683 bWarnOnce = FALSE;
1684 switch (nContextError) {
1685 case GLDERR_DDRAW: strcpy(szMsg, szDDrawWarning); break;
1686 case GLDERR_D3D: strcpy(szMsg, szD3DWarning); break;
1687 case GLDERR_MEM: strcpy(szMsg, szResourceWarning); break;
1688 case GLDERR_BPP: strcpy(szMsg, szBPPWarning); break;
1689 default: strcpy(szMsg, "");
1690 }
1691 if (strlen(szMsg))
1692 MessageBox(NULL, szMsg, "GLDirect", MB_OK | MB_ICONWARNING);
1693 }
1694 // Only need to try again if memory error
1695 if (nContextError == GLDERR_MEM) {
1696 ddlogPrintf(DDLOG_WARN, "dglCreateContext failed 1st time with video memory");
1697 }
1698 else {
1699 ddlogPrintf(DDLOG_ERROR, "dglCreateContext failed");
1700 return NULL;
1701 }
1702 }
1703 }
1704
1705 // Now that we have a hWnd, we can intercept the WindowProc.
1706 hWnd = lpCtx->hWnd;
1707 if (hWnd) {
1708 // Only hook individual window handler once if not hooked before.
1709 lpfnWndProc = GetWindowLong(hWnd, GWL_WNDPROC);
1710 if (lpfnWndProc != (LONG)dglWndProc) {
1711 lpCtx->lpfnWndProc = lpfnWndProc;
1712 SetWindowLong(hWnd, GWL_WNDPROC, (LONG)dglWndProc);
1713 }
1714 // Find the parent window of the app too.
1715 if (glb.hWndActive == NULL) {
1716 while (hWnd != NULL) {
1717 glb.hWndActive = hWnd;
1718 hWnd = GetParent(hWnd);
1719 }
1720 // Hook the parent window too.
1721 lpfnWndProc = GetWindowLong(glb.hWndActive, GWL_WNDPROC);
1722 if (glb.hWndActive == lpCtx->hWnd)
1723 glb.lpfnWndProc = lpCtx->lpfnWndProc;
1724 else if (lpfnWndProc != (LONG)dglWndProc)
1725 glb.lpfnWndProc = lpfnWndProc;
1726 if (glb.lpfnWndProc)
1727 SetWindowLong(glb.hWndActive, GWL_WNDPROC, (LONG)dglWndProc);
1728 }
1729 }
1730
1731 ddlogPrintf(DDLOG_SYSTEM, "dglCreateContext succeeded for HGLRC=%d", (int)hGLRC);
1732
1733 return hGLRC;
1734 }
1735
1736 // ***********************************************************************
1737 // Make a DirectGL context current
1738 // Used by wgl functions and dgl functions
1739 BOOL dglMakeCurrent(
1740 HDC a,
1741 HGLRC b)
1742 {
1743 int context;
1744 DGL_ctx* lpCtx;
1745 HWND hWnd;
1746 BOOL bNeedResize = FALSE;
1747 BOOL bWindowChanged, bContextChanged;
1748 LPDIRECTDRAWCLIPPER lpddClipper;
1749 DWORD dwThreadId = GetCurrentThreadId();
1750 LONG lpfnWndProc;
1751
1752 // Validate license
1753 if (!dglValidate())
1754 return FALSE;
1755
1756 // Is context state ready ?
1757 if (!bContextReady)
1758 return FALSE;
1759
1760 context = (int)b; // This is as a result of STRICT!
1761 ddlogPrintf(DDLOG_SYSTEM, "dglMakeCurrent: HDC=%X, HGLRC=%d, ThreadId=%X", a, context, dwThreadId);
1762
1763 // If the HGLRC is NULL then make no context current;
1764 // Ditto if the HDC is NULL either. (DaveM)
1765 if (context == 0 || a == 0) {
1766 // Corresponding Mesa operation
1767 #ifdef _USE_GLD3_WGL
1768 _mesa_make_current(NULL, NULL);
1769 #else
1770 (*mesaFuncs.gl_make_current)(NULL, NULL);
1771 #endif
1772 dglSetCurrentContext(0);
1773 return TRUE;
1774 }
1775
1776 // Make sure the HGLRC is in range
1777 if ((context > DGL_MAX_CONTEXTS) || (context < 0)) {
1778 ddlogMessage(DDLOG_ERROR, "dglMakeCurrent: HGLRC out of range\n");
1779 return FALSE;
1780 }
1781
1782 // Find address of context and make sure that it has been allocated
1783 lpCtx = dglGetContextAddress(b);
1784 if (!lpCtx->bAllocated) {
1785 ddlogMessage(DDLOG_ERROR, "dglMakeCurrent: Context not allocated\n");
1786 // return FALSE;
1787 return TRUE; // HACK: Shuts up "WebLab Viewer Pro". KeithH
1788 }
1789
1790 #ifdef GLD_THREADS
1791 // Serialize access to DirectDraw or DDS operations
1792 if (glb.bMultiThreaded)
1793 EnterCriticalSection(&CriticalSection);
1794 #endif
1795
1796 // Check if window has changed
1797 hWnd = (a != lpCtx->hDC) ? WindowFromDC(a) : lpCtx->hWnd;
1798 bWindowChanged = (hWnd != lpCtx->hWnd) ? TRUE : FALSE;
1799 bContextChanged = (b != dglGetCurrentContext()) ? TRUE : FALSE;
1800
1801 // If the window has changed, make sure the clipper is updated. (DaveM)
1802 if (glb.bDirectDrawPersistant && !lpCtx->bFullscreen && (bWindowChanged || bContextChanged)) {
1803 lpCtx->hWnd = hWnd;
1804 #ifndef _USE_GLD3_WGL
1805 IDirectDrawSurface4_GetClipper(lpCtx->lpFront4, &lpddClipper);
1806 IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd);
1807 IDirectDrawClipper_Release(lpddClipper);
1808 #endif // _USE_GLD3_WGL
1809 }
1810
1811 // Make sure hDC and hWnd is current. (DaveM)
1812 // Obtain the dimensions of the rendering window
1813 lpCtx->hDC = a; // Cache DC
1814 lpCtx->hWnd = hWnd;
1815 hWndLastActive = hWnd;
1816
1817 // Check for non-window DC = memory DC ?
1818 if (hWnd == NULL) {
1819 if (GetClipBox(a, &lpCtx->rcScreenRect) == ERROR) {
1820 ddlogMessage(DDLOG_WARN, "GetClipBox failed in dglMakeCurrent\n");
1821 SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0);
1822 }
1823 }
1824 else if (!GetClientRect(lpCtx->hWnd, &lpCtx->rcScreenRect)) {
1825 ddlogMessage(DDLOG_WARN, "GetClientRect failed in dglMakeCurrent\n");
1826 SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0);
1827 }
1828 // Check if buffers need to be re-sized;
1829 // If so, wait until Mesa GL stuff is setup before re-sizing;
1830 if (lpCtx->dwWidth != lpCtx->rcScreenRect.right - lpCtx->rcScreenRect.left ||
1831 lpCtx->dwHeight != lpCtx->rcScreenRect.bottom - lpCtx->rcScreenRect.top)
1832 bNeedResize = TRUE;
1833
1834 // Now we can update our globals
1835 dglSetCurrentContext(b);
1836
1837 // Corresponding Mesa operation
1838 #ifdef _USE_GLD3_WGL
1839 _mesa_make_current(lpCtx->glCtx, lpCtx->glBuffer);
1840 lpCtx->glCtx->Driver.UpdateState(lpCtx->glCtx, _NEW_ALL);
1841 if (bNeedResize) {
1842 // Resize buffers (Note Mesa GL needs to be setup beforehand);
1843 // Resize Mesa internal buffer too via glViewport() command,
1844 // which subsequently calls dglWglResizeBuffers() too.
1845 lpCtx->glCtx->Driver.Viewport(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
1846 lpCtx->bHasBeenCurrent = TRUE;
1847 }
1848 #else
1849 (*mesaFuncs.gl_make_current)(lpCtx->glCtx, lpCtx->glBuffer);
1850
1851 dglSetupDDPointers(lpCtx->glCtx);
1852
1853 // Insure DirectDraw surfaces fit current window DC
1854 if (bNeedResize) {
1855 // Resize buffers (Note Mesa GL needs to be setup beforehand);
1856 // Resize Mesa internal buffer too via glViewport() command,
1857 // which subsequently calls dglWglResizeBuffers() too.
1858 (*mesaFuncs.gl_Viewport)(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
1859 lpCtx->bHasBeenCurrent = TRUE;
1860 }
1861 #endif // _USE_GLD3_WGL
1862 ddlogPrintf(DDLOG_SYSTEM, "dglMakeCurrent: width = %d, height = %d", lpCtx->dwWidth, lpCtx->dwHeight);
1863
1864 // We have to clear D3D back buffer and render state if emulated front buffering
1865 // for different window (but not context) like in Solid Edge.
1866 if (glb.bDirectDrawPersistant && glb.bPersistantBuffers
1867 && (bWindowChanged /* || bContextChanged */) && lpCtx->EmulateSingle) {
1868 #ifdef _USE_GLD3_WGL
1869 // IDirect3DDevice8_EndScene(lpCtx->pDev);
1870 // lpCtx->bSceneStarted = FALSE;
1871 lpCtx->glCtx->Driver.Clear(lpCtx->glCtx, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
1872 GL_TRUE, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
1873 #else
1874 IDirect3DDevice3_EndScene(lpCtx->lpDev3);
1875 lpCtx->bSceneStarted = FALSE;
1876 dglClearD3D(lpCtx->glCtx, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
1877 GL_TRUE, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
1878 #endif // _USE_GLD3_WGL
1879 }
1880
1881 // The first time we call MakeCurrent we set the initial viewport size
1882 if (lpCtx->bHasBeenCurrent == FALSE)
1883 #ifdef _USE_GLD3_WGL
1884 lpCtx->glCtx->Driver.Viewport(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
1885 #else
1886 (*mesaFuncs.gl_Viewport)(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
1887 #endif // _USE_GLD3_WGL
1888 lpCtx->bHasBeenCurrent = TRUE;
1889
1890 #ifdef GLD_THREADS
1891 // Release serialized access
1892 if (glb.bMultiThreaded)
1893 LeaveCriticalSection(&CriticalSection);
1894 #endif
1895
1896 return TRUE;
1897 }
1898
1899 // ***********************************************************************
1900
1901 BOOL dglDeleteContext(
1902 HGLRC a)
1903 {
1904 DGL_ctx* lpCtx;
1905 DWORD dwThreadId = GetCurrentThreadId();
1906 char argstr[256];
1907
1908 #if 0 // We have enough trouble throwing exceptions as it is... (DaveM)
1909 // Validate license
1910 if (!dglValidate())
1911 return FALSE;
1912 #endif
1913
1914 // Is context state ready ?
1915 if (!bContextReady)
1916 return FALSE;
1917
1918 ddlogPrintf(DDLOG_SYSTEM, "dglDeleteContext: Deleting context HGLRC=%d, ThreadId=%X", (int)a, dwThreadId);
1919
1920 // Make sure the HGLRC is in range
1921 if (((int) a> DGL_MAX_CONTEXTS) || ((int)a < 0)) {
1922 ddlogMessage(DDLOG_ERROR, "dglDeleteCurrent: HGLRC out of range\n");
1923 return FALSE;
1924 }
1925
1926 // Make sure context is valid
1927 lpCtx = dglGetContextAddress(a);
1928 if (!lpCtx->bAllocated) {
1929 ddlogPrintf(DDLOG_WARN, "Tried to delete unallocated context HGLRC=%d", (int)a);
1930 // return FALSE;
1931 return TRUE; // HACK: Shuts up "WebLab Viewer Pro". KeithH
1932 }
1933
1934 // Make sure context is de-activated
1935 if (a == dglGetCurrentContext()) {
1936 ddlogPrintf(DDLOG_WARN, "dglDeleteContext: context HGLRC=%d still active", (int)a);
1937 dglMakeCurrent(NULL, NULL);
1938 }
1939
1940 #ifdef GLD_THREADS
1941 // Serialize access to DirectDraw or DDS operations
1942 if (glb.bMultiThreaded)
1943 EnterCriticalSection(&CriticalSection);
1944 #endif
1945
1946 // We are about to destroy all Direct3D objects.
1947 // Therefore we must disable rendering
1948 lpCtx->bCanRender = FALSE;
1949
1950 // This exception handler was installed to catch some
1951 // particularly nasty apps. Console apps that call exit()
1952 // fall into this catagory (i.e. Win32 Glut).
1953
1954 // VC cannot successfully implement multiple exception handlers
1955 // if more than one exception occurs. Therefore reverting back to
1956 // single exception handler as Keith originally had it. (DaveM)
1957
1958 #define WARN_MESSAGE(p) strcpy(argstr, (#p));
1959 #define SAFE_RELEASE(p) WARN_MESSAGE(p); RELEASE(p);
1960
1961 __try {
1962 #ifdef _USE_GLD3_WGL
1963 WARN_MESSAGE(gl_destroy_framebuffer);
1964 if (lpCtx->glBuffer)
1965 _mesa_destroy_framebuffer(lpCtx->glBuffer);
1966 WARN_MESSAGE(gl_destroy_context);
1967 if (lpCtx->glCtx)
1968 _mesa_destroy_context(lpCtx->glCtx);
1969 WARN_MESSAGE(gl_destroy_visual);
1970 if (lpCtx->glVis)
1971 _mesa_destroy_visual(lpCtx->glVis);
1972
1973 _gldDriver.DestroyDrawable(lpCtx);
1974 #else
1975 // Destroy the Mesa context
1976 WARN_MESSAGE(gl_destroy_framebuffer);
1977 if (lpCtx->glBuffer)
1978 (*mesaFuncs.gl_destroy_framebuffer)(lpCtx->glBuffer);
1979 WARN_MESSAGE(gl_destroy_context);
1980 if (lpCtx->glCtx)
1981 (*mesaFuncs.gl_destroy_context)(lpCtx->glCtx);
1982 WARN_MESSAGE(gl_destroy_visual);
1983 if (lpCtx->glVis)
1984 (*mesaFuncs.gl_destroy_visual)(lpCtx->glVis);
1985
1986 SAFE_RELEASE(lpCtx->m_pvbuf); // release D3D vertex buffer
1987 SAFE_RELEASE(lpCtx->m_vbuf); // release D3D vertex buffer
1988
1989 // Delete the global palette
1990 SAFE_RELEASE(lpCtx->lpGlobalPalette);
1991
1992 // Clean up.
1993 if (lpCtx->lpViewport3) {
1994 if (lpCtx->lpDev3) IDirect3DDevice3_DeleteViewport(lpCtx->lpDev3, lpCtx->lpViewport3);
1995 SAFE_RELEASE(lpCtx->lpViewport3);
1996 lpCtx->lpViewport3 = NULL;
1997 }
1998
1999 SAFE_RELEASE(lpCtx->lpDev3);
2000 if (lpCtx->lpDepth4) {
2001 if (lpCtx->lpBack4)
2002 IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpBack4, 0L, lpCtx->lpDepth4);
2003 else
2004 IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpFront4, 0L, lpCtx->lpDepth4);
2005 SAFE_RELEASE(lpCtx->lpDepth4);
2006 lpCtx->lpDepth4 = NULL;
2007 }
2008 SAFE_RELEASE(lpCtx->lpBack4);
2009 SAFE_RELEASE(lpCtx->lpFront4);
2010 if (lpCtx->bFullscreen) {
2011 IDirectDraw4_RestoreDisplayMode(lpCtx->lpDD4);
2012 IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, NULL, DDSCL_NORMAL);
2013 }
2014 SAFE_RELEASE(lpCtx->lpD3D3);
2015 SAFE_RELEASE(lpCtx->lpDD4);
2016 SAFE_RELEASE(lpCtx->lpDD1);
2017 #endif // _ULSE_GLD3_WGL
2018
2019 }
2020 __except(EXCEPTION_EXECUTE_HANDLER) {
2021 ddlogPrintf(DDLOG_WARN, "Exception raised in dglDeleteContext: %s", argstr);
2022 }
2023
2024 // Restore the window message handler because this context may be used
2025 // again by another window with a *different* message handler. (DaveM)
2026 if (lpCtx->lpfnWndProc) {
2027 SetWindowLong(lpCtx->hWnd, GWL_WNDPROC, (LONG)lpCtx->lpfnWndProc);
2028 lpCtx->lpfnWndProc = (LONG)NULL;
2029 }
2030
2031 lpCtx->bAllocated = FALSE; // This context is now free for use
2032
2033 #ifdef GLD_THREADS
2034 // Release serialized access
2035 if (glb.bMultiThreaded)
2036 LeaveCriticalSection(&CriticalSection);
2037 #endif
2038
2039 return TRUE;
2040 }
2041
2042 // ***********************************************************************
2043
2044 BOOL dglSwapBuffers(
2045 HDC hDC)
2046 {
2047 RECT rSrcRect; // Source rectangle
2048 RECT rDstRect; // Destination rectangle
2049 POINT pt;
2050 HRESULT hResult;
2051
2052 DDBLTFX bltFX;
2053 DWORD dwBlitFlags;
2054 DDBLTFX *lpBltFX;
2055
2056 // DWORD dwThreadId = GetCurrentThreadId();
2057 HGLRC hGLRC = dglGetCurrentContext();
2058 DGL_ctx *lpCtx = dglGetContextAddress(hGLRC);
2059 HWND hWnd;
2060
2061 HDC hDCAux; // for memory DC
2062 int x,y,w,h; // for memory DC BitBlt
2063
2064 #if 0 // Perhaps not a good idea. Called too often. KH
2065 // Validate license
2066 if (!dglValidate())
2067 return FALSE;
2068 #endif
2069
2070 if (!lpCtx) {
2071 return TRUE; //FALSE; // No current context
2072 }
2073
2074 if (!lpCtx->bCanRender) {
2075 // Don't return false else some apps will bail.
2076 return TRUE;
2077 }
2078
2079 hWnd = lpCtx->hWnd;
2080 if (hDC != lpCtx->hDC) {
2081 ddlogPrintf(DDLOG_WARN, "dglSwapBuffers: HDC=%X does not match HDC=%X for HGLRC=%d", hDC, lpCtx->hDC, hGLRC);
2082 hWnd = WindowFromDC(hDC);
2083 }
2084
2085 #ifndef _USE_GLD3_WGL
2086 // Ensure that the surfaces exist before we tell
2087 // the device to render to them.
2088 IDirectDraw4_RestoreAllSurfaces(lpCtx->lpDD4);
2089
2090 // Make sure that the vertex caches have been emptied
2091 // dglStateChange(lpCtx);
2092
2093 // Some OpenGL programs don't issue a glFinish - check for it here.
2094 if (lpCtx->bSceneStarted) {
2095 IDirect3DDevice3_EndScene(lpCtx->lpDev3);
2096 lpCtx->bSceneStarted = FALSE;
2097 }
2098 #endif
2099
2100 #if 0
2101 // If the calling app is not active then we don't need to Blit/Flip.
2102 // We can therefore simply return TRUE.
2103 if (!glb.bAppActive)
2104 return TRUE;
2105 // Addendum: This is WRONG! We should bail if the app is *minimized*,
2106 // not merely if the app is just plain 'not active'.
2107 // KeithH, 27/May/2000.
2108 #endif
2109
2110 // Check for non-window DC = memory DC ?
2111 if (hWnd == NULL) {
2112 if (GetClipBox(hDC, &rSrcRect) == ERROR)
2113 return TRUE;
2114 // Use GDI BitBlt instead from compatible DirectDraw DC
2115 x = rSrcRect.left;
2116 y = rSrcRect.top;
2117 w = rSrcRect.right - rSrcRect.left;
2118 h = rSrcRect.bottom - rSrcRect.top;
2119
2120 // Ack. DX8 does not have a GetDC() function...
2121 // TODO: Defer to DX7 or DX9 drivers... (DaveM)
2122 return TRUE;
2123 }
2124
2125 // Bail if window client region is not drawable, like in Solid Edge
2126 if (!IsWindow(hWnd) /* || !IsWindowVisible(hWnd) */ || !GetClientRect(hWnd, &rSrcRect))
2127 return TRUE;
2128
2129 #ifdef GLD_THREADS
2130 // Serialize access to DirectDraw or DDS operations
2131 if (glb.bMultiThreaded)
2132 EnterCriticalSection(&CriticalSection);
2133 #endif
2134
2135 #ifdef _USE_GLD3_WGL
2136 // Notify Mesa of impending swap, so Mesa can flush internal buffers.
2137 _mesa_notifySwapBuffers(lpCtx->glCtx);
2138 // Now perform driver buffer swap
2139 _gldDriver.SwapBuffers(lpCtx, hDC, hWnd);
2140 #else
2141 if (lpCtx->bFullscreen) {
2142 // Sync with retrace if required
2143 if (glb.bWaitForRetrace) {
2144 IDirectDraw4_WaitForVerticalBlank(
2145 lpCtx->lpDD4,
2146 DDWAITVB_BLOCKBEGIN,
2147 0);
2148 }
2149
2150 // Perform the fullscreen flip
2151 TRY(IDirectDrawSurface4_Flip(
2152 lpCtx->lpFront4,
2153 NULL,
2154 DDFLIP_WAIT),
2155 "dglSwapBuffers: Flip");
2156 } else {
2157 // Calculate current window position and size
2158 pt.x = pt.y = 0;
2159 ClientToScreen(hWnd, &pt);
2160 GetClientRect(hWnd, &rDstRect);
2161 if (rDstRect.right > lpCtx->dwModeWidth)
2162 rDstRect.right = lpCtx->dwModeWidth;
2163 if (rDstRect.bottom > lpCtx->dwModeHeight)
2164 rDstRect.bottom = lpCtx->dwModeHeight;
2165 OffsetRect(&rDstRect, pt.x, pt.y);
2166 rSrcRect.left = rSrcRect.top = 0;
2167 rSrcRect.right = lpCtx->dwWidth;
2168 rSrcRect.bottom = lpCtx->dwHeight;
2169 if (rSrcRect.right > lpCtx->dwModeWidth)
2170 rSrcRect.right = lpCtx->dwModeWidth;
2171 if (rSrcRect.bottom > lpCtx->dwModeHeight)
2172 rSrcRect.bottom = lpCtx->dwModeHeight;
2173
2174 if (glb.bWaitForRetrace) {
2175 // Sync the blit to the vertical retrace
2176 ZeroMemory(&bltFX, sizeof(bltFX));
2177 bltFX.dwSize = sizeof(bltFX);
2178 bltFX.dwDDFX = DDBLTFX_NOTEARING;
2179 dwBlitFlags = DDBLT_WAIT | DDBLT_DDFX;
2180 lpBltFX = &bltFX;
2181 } else {
2182 dwBlitFlags = DDBLT_WAIT;
2183 lpBltFX = NULL;
2184 }
2185
2186 // Perform the actual blit
2187 TRY(IDirectDrawSurface4_Blt(
2188 lpCtx->lpFront4,
2189 &rDstRect,
2190 lpCtx->lpBack4, // Blit source
2191 &rSrcRect,
2192 dwBlitFlags,
2193 lpBltFX),
2194 "dglSwapBuffers: Blt");
2195 }
2196 #endif // _USE_GLD3_WGL
2197
2198 #ifdef GLD_THREADS
2199 // Release serialized access
2200 if (glb.bMultiThreaded)
2201 LeaveCriticalSection(&CriticalSection);
2202 #endif
2203
2204 // TODO: Re-instate rendering bitmap snapshot feature??? (DaveM)
2205
2206 // Render frame is completed
2207 ValidateRect(hWnd, NULL);
2208 lpCtx->bFrameStarted = FALSE;
2209
2210 return TRUE;
2211 }
2212
2213 // ***********************************************************************