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