ba7891612e4965620fc9c3c8f27f3546ccc99c14
[mesa.git] / src / mesa / drivers / d3d / D3DInit.cpp
1 /*===========================================================================*/
2 /* */
3 /* Mesa-3.0 DirectX 6 Driver Build 5 */
4 /* */
5 /* By Leigh McRae */
6 /* */
7 /* http://www.altsoftware.com/ */
8 /* */
9 /* Copyright (c) 1999-1998 alt.software inc. All Rights Reserved */
10 /*===========================================================================*/
11 #include "D3DHAL.h"
12 /*===========================================================================*/
13 /* Local function prototypes. */
14 /*===========================================================================*/
15 static void DestroyAllSurfaces( PMESAD3DHAL pHAL );
16 static void DestroyDevice( PMESAD3DHAL pHAL );
17 static void DestroyInterfaces( PMESAD3DHAL pHAL );
18
19 HRESULT WINAPI EnumSurfacesHook( LPDIRECTDRAWSURFACE4 lpDDS, LPDDSURFACEDESC2 lpDDSDesc, LPVOID pVoid );
20 HRESULT CALLBACK EnumZBufferHook( DDPIXELFORMAT* pddpf, VOID *pVoid );
21 HRESULT CALLBACK EnumDeviceHook( GUID FAR* lpGuid, LPSTR lpDesc, LPSTR lpName, LPD3DDEVICEDESC lpD3DHWDesc, LPD3DDEVICEDESC lpD3DHELDesc, void *pVoid );
22 /*===========================================================================*/
23 /* Globals. */
24 /*===========================================================================*/
25 //char *errorMsg;
26 /*===========================================================================*/
27 /* This function is responable for allocating the actual MESAD3DHAL struct. */
28 /* Each Mesa context will have its own MESAD3DHAL struct so its like a mini */
29 /* context to some extent. All one time allocations/operations get done here.*/
30 /*===========================================================================*/
31 /* RETURN: TRUE, FALSE. */
32 /*===========================================================================*/
33 extern "C" PMESAD3DSHARED InitHAL( HWND hwnd )
34 {
35 PMESAD3DHAL pHAL;
36 ULONG rc;
37
38 DPF(( DBG_FUNC, "InitHAL();" ));
39 DPF(( DBG_CNTX_INFO, "hwnd: %d", hwnd ));
40
41 /* Allocate the structure and zero it out. */
42 pHAL = (PMESAD3DHAL)ALLOC( sizeof(MESAD3DHAL) );
43 if ( pHAL == NULL )
44 {
45 RIP( pHAL, "InitHAL->", "Memory Allocation" );
46 return (PMESAD3DSHARED)NULL;
47 }
48 memset( pHAL, 0, sizeof(MESAD3DHAL) );
49
50 /* Get the texture manager going. */
51 rc = InitTMgrHAL( pHAL );
52 if ( rc == FALSE )
53 {
54 RIP( pHAL, "InitTMgrHAL->", "Failed" );
55 return (PMESAD3DSHARED)NULL;
56 }
57
58 /* Fill in the window parameters if we can. */
59 pHAL->shared.hwnd = hwnd;
60
61 /* Parse the user's enviroment variables to generate a debug mask. */
62 ReadDBGEnv();
63
64 return (PMESAD3DSHARED)pHAL;
65 }
66 /*===========================================================================*/
67 /* This function will unload all the resources that the MESAD3DHAL struct */
68 /* has bound to it. The actual structure itself will be freed. */
69 /*===========================================================================*/
70 /* RETURN: */
71 /*===========================================================================*/
72 extern "C" void TermHAL( PMESAD3DSHARED pShared )
73 {
74 PMESAD3DHAL pHAL = (PMESAD3DHAL)pShared;
75
76 DPF(( DBG_FUNC, "TermHAL();" ));
77
78 /* Check for an empty wrapper structure. */
79 if ( pHAL == NULL )
80 return;
81
82 /* Kill this texture manager. */
83 TermTMgrHAL( pHAL );
84
85 /* Kill any DDraw stuff if exists. */
86 DestroyDevice( pHAL );
87 DestroyAllSurfaces( pHAL );
88 DestroyInterfaces( pHAL );
89
90 FREE( pHAL );
91 }
92 /*===========================================================================*/
93 /* This function is used to init and resize the rendering surface as the two*/
94 /* are almost the same. First the device and all the surfaces are destoryed */
95 /* if they already exist. Next we create a OffScreen rendering surface and */
96 /* save some pixelformat info to do color convertions. Next we start to take */
97 /* care of getting the most out of the hardware. I use bHardware to determine*/
98 /* the state of the device we found in the device enumeration. The enum proc*/
99 /* will try for hardware first. I next use a bForceSW to make the enum proc */
100 /* choose a software device. So I will try some combinations with HW first */
101 /* until I feel I have to set the bForceSW and call this function again. If */
102 /* this function is called with no width or height then use the internals. */
103 /* NOTE: The worst case is that all will be in SW (RGBDevice) and really */
104 /* I should forget the whole thing and fall back to a DDraw span type*/
105 /* rendering but what is the point. This way I always know I have a */
106 /* D3DDevice and that makes things easier. I do impliment the span */
107 /* rendering function for stuff that I haven't done support for such */
108 /* as points and lines. */
109 /*===========================================================================*/
110 /* RETURN: TRUE, FALSE */
111 /*===========================================================================*/
112 extern "C" BOOL CreateHAL( PMESAD3DSHARED pShared )
113 {
114 PMESAD3DHAL pHAL = (PMESAD3DHAL)pShared;
115 DDSURFACEDESC2 ddsd2;
116 D3DDEVICEDESC D3DSWDevDesc;
117 DDSCAPS2 ddscaps;
118 DWORD dwCoopFlags,
119 dwWidth,
120 dwHeight;
121 ULONG rc;
122
123 DPF(( DBG_FUNC, "CreateHAL();" ));
124
125 #define InitDDSD2(f) memset( &ddsd2, 0, sizeof(DDSURFACEDESC2) ); \
126 ddsd2.dwSize = sizeof( DDSURFACEDESC2 ); \
127 ddsd2.dwFlags = f;
128
129 if ( pHAL == NULL )
130 return FALSE;
131
132 /* Use the internal rectangle struct. */
133 dwWidth = pShared->rectW.right - pShared->rectW.left;
134 dwHeight = pShared->rectW.bottom - pShared->rectW.top;
135
136 DPF(( DBG_CNTX_INFO, "Width: %d Height: %d", dwWidth, dwHeight ));
137
138 /* The dimensions might still be the same so just leave. */
139 if ( (dwWidth == pShared->dwWidth) && (dwHeight == pShared->dwHeight) )
140 {
141 DPF(( DBG_CNTX_WARN, "Context size hasn't changed" ));
142 return TRUE;
143 }
144
145 /* If one of the dimensions are zero then leave. WM_SIZE should get us back here. */
146 if ( (dwWidth == 0) || (dwHeight == 0) )
147 return TRUE;
148
149 /* Save the renders dimensions. */
150 pShared->dwWidth = dwWidth;
151 pShared->dwHeight = dwHeight;
152
153 DPF(( DBG_CNTX_INFO, "Creating Context:\n cx:%d cy:%d", pShared->dwWidth, pShared->dwHeight ));
154
155 /*=================================*/
156 /* Create all required interfaces. */
157 /*=================================*/
158
159 /* Kill any DDraw stuff if exists. */
160 DestroyDevice( pHAL );
161 DestroyAllSurfaces( pHAL );
162 DestroyInterfaces( pHAL );
163
164 /* Create a instance of DDraw using the Primary display driver. */
165 rc = DirectDrawCreate( NULL, &pHAL->lpDD, NULL );
166 if( FAILED(rc) )
167 {
168 RIP( pHAL, "DirectDrawCreate->", ErrorStringD3D(rc) );
169 return FALSE;
170 }
171
172 /* Get the DDraw4 interface. */
173 rc = pHAL->lpDD->QueryInterface( IID_IDirectDraw4, (void **)&pHAL->lpDD4 );
174 if( FAILED(rc) )
175 {
176 RIP( pHAL, "QueryInterface (IID_IDirectDraw4) ->", ErrorStringD3D(rc) );
177 return FALSE;
178 }
179
180 /* Get the Direct3D3 interface. */
181 rc = pHAL->lpDD4->QueryInterface( IID_IDirect3D3, (void **)&pHAL->lpD3D3 );
182 if( FAILED(rc) )
183 {
184 RIP( pHAL, "QueryInterface (IID_IDirect3D3) ->", ErrorStringD3D(rc) );
185 return FALSE;
186 }
187
188 /* Set the Cooperative level. NOTE: we need to know if we are FS at this point.*/
189 dwCoopFlags = (pShared->bWindow == TRUE) ? DDSCL_NORMAL : (DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
190 rc = pHAL->lpDD4->SetCooperativeLevel( pShared->hwnd, dwCoopFlags );
191 if ( FAILED(rc) )
192 {
193 RIP( pHAL, "SetCooperativeLevel->", ErrorStringD3D(rc) );
194 return FALSE;
195 }
196
197 /*==================================================================*/
198 /* Get the best device we can and note whether its hardware or not. */
199 /*==================================================================*/
200 pShared->bForceSW = FALSE;
201 pHAL->lpD3D3->EnumDevices( EnumDeviceHook, (void *)pHAL );
202 pShared->bHardware = IsEqualIID( pHAL->guid, IID_IDirect3DHALDevice );
203 DPF(( DBG_CNTX_INFO, "bHardware: %s", (pShared->bHardware) ? "TRUE" : "FALSE" ));
204 DPF(( DBG_CNTX_INFO, "bWindowed: %s", (pShared->bWindow) ? "TRUE" : "FALSE" ));
205
206 /*========================================================================*/
207 /* HARDWARE was found. */
208 /*========================================================================*/
209 if ( pShared->bHardware == TRUE )
210 {
211 /*===================================*/
212 /* HARDWARE -> Z-BUFFER. */
213 /*===================================*/
214
215 /* Get a Z-Buffer pixelformat. */
216 memset( &ddsd2, 0, sizeof(DDSURFACEDESC2) );
217 ddsd2.dwSize = sizeof( DDSURFACEDESC2 );
218 rc = pHAL->lpD3D3->EnumZBufferFormats( pHAL->guid, EnumZBufferHook, (VOID*)&ddsd2.ddpfPixelFormat );
219 if ( FAILED(rc) )
220 {
221 RIP( pHAL, "EnumZBufferFormatsl->", ErrorStringD3D(rc) );
222 return FALSE;
223 }
224
225 /* Setup our request structure for the Z-buffer surface. */
226 ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
227 ddsd2.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY;
228 ddsd2.dwWidth = dwWidth;
229 ddsd2.dwHeight = dwHeight;
230 rc = pHAL->lpDD4->CreateSurface( &ddsd2, &pHAL->lpDDSZbuffer, NULL );
231 if ( !FAILED(rc) )
232 {
233 DPF(( DBG_CNTX_INFO, "HW ZBuffer" ));
234
235 /*===================================*/
236 /* HARDWARE -> Z-BUFFER -> FLIPABLE */
237 /*===================================*/
238 if ( pShared->bWindow == FALSE )
239 {
240 InitDDSD2( DDSD_CAPS | DDSD_BACKBUFFERCOUNT );
241 ddsd2.dwBackBufferCount = 1;
242 ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
243 rc = pHAL->lpDD4->CreateSurface( &ddsd2, &pHAL->lpDDSPrimary, NULL );
244 if ( FAILED(rc) )
245 {
246 /* Make sure we try the next fall back. */
247 DPF(( DBG_CNTX_WARN, "HW Flip/Complex not available" ));
248 pHAL->lpDDSPrimary = NULL;
249 }
250 else
251 {
252 /* Get the back buffer that was created. */
253 ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
254 rc = pHAL->lpDDSPrimary->GetAttachedSurface( &ddscaps, &pHAL->lpDDSRender );
255 if ( FAILED(rc) )
256 {
257 DPF(( DBG_CNTX_WARN, "GetAttachedSurface failed -> HW Flip/Complex" ));
258
259 /* Make sure we try the next fall back. */
260 pHAL->lpDDSPrimary->Release();
261 pHAL->lpDDSPrimary = NULL;
262 }
263 else
264 {
265 /* I have had problems when a complex surface comes back */
266 /* with the back buffer being created in SW. Not sure why */
267 /* or how this is possable but I'm checking for it here. */
268 memset( &ddsd2, 0, sizeof(DDSURFACEDESC2) );
269 ddsd2.dwSize = sizeof( DDSURFACEDESC2 );
270 DX_RESTORE( pHAL->lpDDSRender );
271 rc = pHAL->lpDDSRender->GetSurfaceDesc( &ddsd2 );
272 if ( FAILED(rc) )
273 {
274 RIP( pHAL, "GetSurfaceDesc (RENDER) ->", ErrorStringD3D(rc) );
275 return FALSE;
276 }
277
278 /* If the surface is in VID then we are happy with are Flipable. */
279 if ( ddsd2.ddsCaps.dwCaps & DDSCAPS_LOCALVIDMEM )
280 {
281 pShared->bFlipable = TRUE;
282 DPF(( DBG_CNTX_INFO, "HW Flip/Complex!" ));
283 }
284 else
285 {
286 /* Kill this setup. */
287 pHAL->lpDDSPrimary->Release();
288 pHAL->lpDDSPrimary = NULL;
289 }
290 }
291 }
292 }
293
294 /*===================================*/
295 /* HARDWARE -> Z-BUFFER -> BLT */
296 /*===================================*/
297 if ( pHAL->lpDDSPrimary == NULL )
298 {
299 pShared->bFlipable = FALSE;
300
301 /* Create the Primary (front buffer). */
302 InitDDSD2( DDSD_CAPS );
303 ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
304 rc = pHAL->lpDD4->CreateSurface( &ddsd2, &pHAL->lpDDSPrimary, NULL );
305 if ( FAILED(rc) )
306 {
307 /* This is an error as we should be able to do this at minimum. */
308 RIP( pHAL, "CreateSurface (PRIMARY) ->", ErrorStringD3D(rc) );
309 return FALSE;
310 }
311
312 /* Create the Render (back buffer). */
313 InitDDSD2( DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT );
314 ddsd2.dwWidth = dwWidth;
315 ddsd2.dwHeight = dwHeight;
316 ddsd2.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
317 rc = pHAL->lpDD4->CreateSurface( &ddsd2, &pHAL->lpDDSRender, NULL );
318 if ( FAILED(rc) )
319 {
320 DPF(( DBG_CNTX_WARN, "Failed HW Offscreen surface" ));
321
322 /* Make sure we try the next fall back. */
323 pHAL->lpDDSPrimary->Release();
324 pHAL->lpDDSPrimary = NULL;
325 }
326 else
327 {
328 /* Might as well check here too see if this surface is in */
329 /* hardware. If nothing else just to be consistant. */
330 memset( &ddsd2, 0, sizeof(DDSURFACEDESC2) );
331 ddsd2.dwSize = sizeof( DDSURFACEDESC2 );
332 DX_RESTORE( pHAL->lpDDSRender );
333 rc = pHAL->lpDDSRender->GetSurfaceDesc( &ddsd2 );
334 if ( FAILED(rc) )
335 {
336 RIP( pHAL, "GetSurfaceDesc (RENDER) ->", ErrorStringD3D(rc) );
337 return FALSE;
338 }
339
340 /* If the surface is in VID then we are happy. */
341 if ( ddsd2.ddsCaps.dwCaps & DDSCAPS_LOCALVIDMEM )
342 {
343 /* Create a clipper object so that DDraw will be able to blt windows that */
344 /* have been clipped by the screen or other windows. */
345 pHAL->lpDD4->CreateClipper( 0, &pHAL->lpClipper, NULL );
346 pHAL->lpClipper->SetHWnd( 0, pShared->hwnd );
347 pHAL->lpDDSPrimary->SetClipper( pHAL->lpClipper );
348 pHAL->lpClipper->Release();
349 DPF(( DBG_CNTX_INFO, "HW RENDER surface" ));
350 }
351 else
352 {
353 /* Kill this setup. */
354 pHAL->lpDDSRender->Release();
355 pHAL->lpDDSRender = NULL;
356 pHAL->lpDDSPrimary->Release();
357 pHAL->lpDDSPrimary = NULL;
358 }
359 }
360 }
361
362 /*===================================*/
363 /* Create D3DDEVICE -> HARDWARE. */
364 /*===================================*/
365 if ( pHAL->lpDDSZbuffer && pHAL->lpDDSPrimary && pHAL->lpDDSRender )
366 {
367 DX_RESTORE( pHAL->lpDDSRender );
368 DX_RESTORE( pHAL->lpDDSZbuffer );
369
370 rc = pHAL->lpDDSRender->AddAttachedSurface( pHAL->lpDDSZbuffer );
371 if ( FAILED(rc) )
372 {
373 RIP( pHAL, "AddAttachedSurface (ZBUFFER) ->", ErrorStringD3D(rc) );
374 return FALSE;
375 }
376
377 rc = pHAL->lpD3D3->CreateDevice( IID_IDirect3DHALDevice, pHAL->lpDDSRender, &pHAL->lpD3DDevice, NULL );
378 if ( rc != D3D_OK )
379 {
380 DPF(( DBG_CNTX_WARN, "Failed HW Device" ));
381 pHAL->lpD3DDevice = NULL;
382 }
383 else
384 {
385 DPF(( DBG_CNTX_INFO, "HW Device" ));
386 }
387 }
388 }
389 }
390
391 /*========================================================================*/
392 /* SOFTWARE fallback. */
393 /*========================================================================*/
394 if ( pHAL->lpD3DDevice == NULL )
395 {
396 DPF(( DBG_CNTX_INFO, "SW fallback :(" ));
397
398 /* Make sure we have no surfaces allocated. Just incase. */
399 DestroyAllSurfaces( pHAL );
400
401 /* Get a software device. */
402 pShared->bFlipable = FALSE;
403 pShared->bForceSW = TRUE;
404 pHAL->lpD3D3->EnumDevices( EnumDeviceHook, (void *)pHAL );
405 pShared->bHardware = IsEqualIID( pHAL->guid, IID_IDirect3DHALDevice );
406
407 /*===================================*/
408 /* SOFTWARE -> Z-BUFFER. */
409 /*===================================*/
410
411 /*===================================*/
412 /* SOFTWARE -> Z-BUFFER -> FLIPABLE */
413 /*===================================*/
414 if ( pShared->bWindow == FALSE )
415 {
416 InitDDSD2( DDSD_CAPS | DDSD_BACKBUFFERCOUNT );
417 ddsd2.dwBackBufferCount = 1;
418 ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
419 ddsd2.ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT );
420 ddsd2.ddpfPixelFormat.dwFlags = (DDPF_RGB | DDPF_ALPHAPIXELS);
421 rc = pHAL->lpDD4->CreateSurface( &ddsd2, &pHAL->lpDDSPrimary, NULL );
422 if ( FAILED(rc) )
423 {
424 DPF(( DBG_CNTX_WARN, "Failed SW Flip/Complex" ));
425
426 /* Make sure we try the next fall back. */
427 pHAL->lpDDSPrimary = NULL;
428 }
429 else
430 {
431 ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
432 rc = pHAL->lpDDSPrimary->GetAttachedSurface( &ddscaps, &pHAL->lpDDSRender );
433 if ( FAILED(rc) )
434 {
435 /* Make sure we try the next fall back. */
436 DPF(( DBG_CNTX_WARN, "GetAttachedSurface failed -> SW Flip/Complex" ));
437 pHAL->lpDDSPrimary->Release();
438 pHAL->lpDDSPrimary = NULL;
439 }
440 else
441 {
442 DPF(( DBG_CNTX_INFO, "SW Flip/Complex" ));
443 pShared->bFlipable = TRUE;
444 }
445 }
446 }
447
448 /*===================================*/
449 /* SOFTWARE -> Z-BUFFER -> BLT */
450 /*===================================*/
451 if ( pHAL->lpDDSPrimary == NULL )
452 {
453 /* Create the Primary (front buffer). */
454 InitDDSD2( DDSD_CAPS );
455 ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
456 rc = pHAL->lpDD4->CreateSurface( &ddsd2, &pHAL->lpDDSPrimary, NULL );
457 if ( FAILED(rc) )
458 {
459 /* This is an error as we should be able to do this at minimum. */
460 RIP( pHAL, "CreateSurface (PRIMARY) ->", ErrorStringD3D(rc) );
461 return FALSE;
462 }
463
464 /* Create the Render (back buffer). */
465 InitDDSD2( DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT );
466 ddsd2.dwWidth = dwWidth;
467 ddsd2.dwHeight = dwHeight;
468 ddsd2.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
469 ddsd2.ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT );
470 ddsd2.ddpfPixelFormat.dwFlags = (DDPF_RGB | DDPF_ALPHAPIXELS);
471 rc = pHAL->lpDD4->CreateSurface( &ddsd2, &pHAL->lpDDSRender, NULL );
472 if ( FAILED(rc) )
473 {
474 /* That was our last hope. */
475 RIP( pHAL, "CreateSurface (RENDER) ->", ErrorStringD3D(rc) );
476 return FALSE;
477 }
478 else
479 {
480 DPF(( DBG_CNTX_INFO, "SW RENDER surface" ));
481
482 /* Create a clipper object so that DDraw will be able to blt windows that */
483 /* have been clipped by the screen or other windows. */
484 pHAL->lpDD4->CreateClipper( 0, &pHAL->lpClipper, NULL );
485 pHAL->lpClipper->SetHWnd( 0, pShared->hwnd );
486 pHAL->lpDDSPrimary->SetClipper( pHAL->lpClipper );
487 pHAL->lpClipper->Release();
488 }
489 }
490
491 /*===================================*/
492 /* Create D3DDEVICE -> SOFTWARE. */
493 /*===================================*/
494 if ( pHAL->lpDDSPrimary && pHAL->lpDDSRender )
495 {
496 DX_RESTORE( pHAL->lpDDSRender );
497 rc = pHAL->lpD3D3->CreateDevice( IID_IDirect3DRGBDevice, pHAL->lpDDSRender, &pHAL->lpD3DDevice, NULL );
498 if ( rc != D3D_OK )
499 {
500 /* That was our last hope. */
501 RIP( pHAL, "CreateDevice (IID_IDirect3DRGBDevice) ->", ErrorStringD3D(rc) );
502 return FALSE;
503 }
504
505 DPF(( DBG_CNTX_INFO, "SW Device" ));
506 }
507 }
508
509 /*==============================================================================*/
510 /* Get a copy of the render pixelformat so that wgl.c can call GetPixelInfoD3D. */
511 /*==============================================================================*/
512 memset( &pHAL->ddpf, 0, sizeof(DDPIXELFORMAT) );
513 pHAL->ddpf.dwSize = sizeof( DDPIXELFORMAT );
514 rc = pHAL->lpDDSRender->GetPixelFormat( &pHAL->ddpf );
515 if ( FAILED(rc) )
516 {
517 RIP( pHAL, "GetPixelFormat ->", ErrorStringD3D(rc) );
518 return FALSE;
519 }
520 DebugPixelFormat( "Using OFFSCREEN", &pHAL->ddpf );
521 DebugPixelFormat( "Using ZBUFFER", &ddsd2.ddpfPixelFormat );
522
523 /* Get a copy of what the D3DDevice supports for later use. */
524 memset( &D3DSWDevDesc, 0, sizeof(D3DDEVICEDESC) );
525 memset( &pHAL->D3DHWDevDesc, 0, sizeof(D3DDEVICEDESC) );
526 D3DSWDevDesc.dwSize = sizeof( D3DDEVICEDESC );
527 pHAL->D3DHWDevDesc.dwSize = sizeof( D3DDEVICEDESC );
528 rc = pHAL->lpD3DDevice->GetCaps( &pHAL->D3DHWDevDesc, &D3DSWDevDesc );
529 if ( FAILED(rc) )
530 {
531 RIP( pHAL, "GetCaps ->", ErrorStringD3D(rc) );
532 return FALSE;
533 }
534
535 /* Get a copy of the pixel convertion stuff for direct buffer access. */
536 Solve8BitChannelPixelFormat( &pHAL->ddpf, &pShared->pixel );
537 AlphaBlendTableHAL( pHAL );
538
539 /* We must prime the Begin/End scene for SwapBuffers to work. */
540 rc = pHAL->lpD3DDevice->BeginScene();
541 if ( FAILED(rc) )
542 {
543 RIP( pHAL, "BeginScene ->", ErrorStringD3D(rc) );
544 return FALSE;
545 }
546
547 #undef InitDDSD2
548
549 return TRUE;
550 }
551 /*===========================================================================*/
552 /* This function will make sure a viewport is created and set for the device*/
553 /* in the supplied structure. If a rect is supplied then it will be used for*/
554 /* the viewport otherwise the current setting in the strucute will be used. */
555 /* Note that the rect is relative to the window. So left/top must be 0,0 to */
556 /* use the whole window else there is scissoring going down. */
557 /*===========================================================================*/
558 /* RETURN: TRUE, FALSE. */
559 /*===========================================================================*/
560 extern "C" BOOL SetViewportHAL( PMESAD3DSHARED pShared, RECT *pRect, float minZ, float maxZ )
561 {
562 PMESAD3DHAL pHAL = (PMESAD3DHAL)pShared;
563 D3DVIEWPORT2 vdData;
564 ULONG rc;
565 POINT pt;
566
567 DPF(( DBG_FUNC, "SetViewportHAL();" ));
568
569 /* Make sure we have enough info. */
570 if ( !pHAL || !pHAL->lpDDSPrimary || !pHAL->lpD3DDevice )
571 {
572 DPF(( DBG_CNTX_WARN, "SetViewport() -> NULL Pointer" ));
573 return FALSE;
574 }
575
576 /* TODO: this is just a temp fix to stop redundant changes. */
577 if ( pRect &&
578 (pShared->rectV.left == pRect->left) &&
579 (pShared->rectV.right == pRect->right) &&
580 (pShared->rectV.top == pRect->top) &&
581 (pShared->rectV.bottom == pRect->bottom) )
582 {
583 DPF(( DBG_CNTX_WARN, "Redundant viewport" ));
584 return TRUE;
585 }
586
587 DPF(( DBG_CNTX_INFO, "Current Viewport:" ));
588 DPF(( DBG_CNTX_INFO, "x: %d y: %d", pShared->rectV.left, pShared->rectV.top ));
589 DPF(( DBG_CNTX_INFO, "cx: %d cy: %d", (pShared->rectV.right-pShared->rectV.left), (pShared->rectV.bottom-pShared->rectV.top) ));
590 DPF(( DBG_CNTX_INFO, "New Viewport:" ));
591 DPF(( DBG_CNTX_INFO, "x: %d y: %d", pRect->left, pRect->top ));
592 DPF(( DBG_CNTX_INFO, "cx: %d cy: %d", (pRect->right-pRect->left), (pRect->bottom-pRect->top) ));
593
594 /* Update the current viewport rect if one is supplied. */
595 if ( pRect )
596 memcpy( &pShared->rectV, pRect, sizeof(RECT) );
597
598 /* Build the request structure. */
599 memset( &vdData, 0, sizeof(D3DVIEWPORT2) );
600 vdData.dwSize = sizeof(D3DVIEWPORT2);
601 vdData.dwX = pShared->rectV.left;
602 vdData.dwY = pShared->rectV.top;
603 vdData.dwWidth = (pShared->rectV.right - pShared->rectV.left);
604 vdData.dwHeight = (pShared->rectV.bottom - pShared->rectV.top);
605
606 if ( !vdData.dwWidth || !vdData.dwHeight )
607 {
608 GetClientRect( pShared->hwnd, &pShared->rectW );
609 pt.x = pt.y = 0;
610 ClientToScreen( pShared->hwnd, &pt );
611 OffsetRect( &pShared->rectW, pt.x, pt.y);
612 vdData.dwX = pShared->rectW.left;
613 vdData.dwY = pShared->rectW.top;
614 vdData.dwWidth = (pShared->rectW.right - pShared->rectW.left);
615 vdData.dwHeight = (pShared->rectW.bottom - pShared->rectW.top);
616 memcpy( &pShared->rectV, &pShared->rectW, sizeof(RECT) );
617 }
618
619 // The dvClipX, dvClipY, dvClipWidth, dvClipHeight, dvMinZ,
620 // and dvMaxZ members define the non-normalized post-perspective
621 // 3-D view volume which is visible to the viewer. In most cases,
622 // dvClipX is set to -1.0 and dvClipY is set to the inverse of
623 // the viewport's aspect ratio on the target surface, which can be
624 // calculated by dividing the dwHeight member by dwWidth. Similarly,
625 // the dvClipWidth member is typically 2.0 and dvClipHeight is set
626 // to twice the aspect ratio set in dwClipY. The dvMinZ and dvMaxZ
627 // are usually set to 0.0 and 1.0.
628 vdData.dvClipX = -1.0f;
629 vdData.dvClipWidth = 2.0f;
630 vdData.dvClipY = 1.0f;
631 vdData.dvClipHeight = 2.0f;
632 vdData.dvMaxZ = maxZ;
633 vdData.dvMinZ = minZ;
634
635 DPF(( DBG_CNTX_INFO, "zMin: %f zMax: %f", minZ, maxZ ));
636
637 /* I'm going to destroy the viewport everytime as when we size we will */
638 /* have a new D3DDevice. As this area doesn't need to be fast... */
639 if ( pHAL->lpViewport )
640 {
641 DPF(( DBG_CNTX_INFO, "DeleteViewport" ));
642
643 pHAL->lpD3DDevice->DeleteViewport( pHAL->lpViewport );
644 rc = pHAL->lpViewport->Release();
645 pHAL->lpViewport = NULL;
646 }
647
648 rc = pHAL->lpD3D3->CreateViewport( &pHAL->lpViewport, NULL );
649 if ( rc != D3D_OK )
650 {
651 DPF(( DBG_CNTX_ERROR, "CreateViewport Failed" ));
652 return FALSE;
653 }
654
655 /* Update the device with the new viewport. */
656 pHAL->lpD3DDevice->AddViewport( pHAL->lpViewport );
657 pHAL->lpViewport->SetViewport2( &vdData );
658 pHAL->lpD3DDevice->SetCurrentViewport( pHAL->lpViewport );
659
660 return TRUE;
661 }
662 /*===========================================================================*/
663 /* */
664 /* */
665 /*===========================================================================*/
666 /* RETURN: */
667 /*===========================================================================*/
668 HRESULT WINAPI EnumSurfacesHook( LPDIRECTDRAWSURFACE4 lpDDS, LPDDSURFACEDESC2 lpDDSDesc, LPVOID pVoid )
669 {
670 DDSURFACEDESC2 *pddsd2 = (DDSURFACEDESC2 *)pVoid;
671
672 DPF(( DBG_FUNC, "EnumSurfacesHook();" ));
673
674 if ( (lpDDSDesc->ddpfPixelFormat.dwFlags == pddsd2->ddpfPixelFormat.dwFlags) && (lpDDSDesc->ddsCaps.dwCaps == pddsd2->ddsCaps.dwCaps) )
675 {
676 /* Save the pixelformat now so that we know we have one. */
677 memcpy( pddsd2, lpDDSDesc, sizeof(DDSURFACEDESC2) );
678
679 return D3DENUMRET_CANCEL;
680 }
681
682 return D3DENUMRET_OK;
683 }
684 /*===========================================================================*/
685 /* This is the callback proc to get a Z-Buffer. Thats it. */
686 /*===========================================================================*/
687 /* RETURN: */
688 /*===========================================================================*/
689 HRESULT CALLBACK EnumZBufferHook( DDPIXELFORMAT* pddpf, VOID *pVoid )
690 {
691 DDPIXELFORMAT *pddpfChoice = (DDPIXELFORMAT *)pVoid;
692
693 DPF(( DBG_FUNC, "EnumZBufferHook();" ));
694
695 /* If this is ANY type of depth-buffer, stop. */
696 if( pddpf->dwFlags == DDPF_ZBUFFER )
697 {
698 /* Save the pixelformat now so that we know we have one. */
699 memcpy( pddpfChoice, pddpf, sizeof(DDPIXELFORMAT) );
700
701 /* I feel if the hardware supports this low then lets use it. Could get ugly. */
702 if( pddpf->dwZBufferBitDepth >= 8 )
703 {
704 return D3DENUMRET_CANCEL;
705 }
706 }
707
708 return D3DENUMRET_OK;
709 }
710 /*===========================================================================*/
711 /* This function handles the callback for the D3DDevice enumeration. Good */
712 /* god who's idea was this? The D3D wrapper has two variable related to what*/
713 /* kind of device we want and have. First we have a Bool that is set if we */
714 /* have allocated a HW device. We always look for the HW device first. The */
715 /* other variable is used to force SW. If we have run into a case that we */
716 /* want to fallback to SW then we set this. We will fallback if we cannot */
717 /* texture in video memory (among others). */
718 /*===========================================================================*/
719 /* RETURN: */
720 /*===========================================================================*/
721 HRESULT CALLBACK EnumDeviceHook( GUID FAR* lpGuid, LPSTR lpDesc, LPSTR lpName, LPD3DDEVICEDESC lpD3DHWDesc, LPD3DDEVICEDESC lpD3DHELDesc, void *pVoid )
722 {
723 PMESAD3DHAL pHAL = (PMESAD3DHAL)pVoid;
724 LPD3DDEVICEDESC pChoice = lpD3DHWDesc;
725
726 DPF(( DBG_FUNC, "EnumDeviceHook();" ));
727
728 /* Determine if which device description is valid. */
729 if ( pChoice->dcmColorModel == 0 )
730 pChoice = lpD3DHELDesc;
731
732 /* Make sure we always have a GUID. */
733 memcpy( &pHAL->guid, lpGuid, sizeof(GUID) );
734
735 /* This controls whether we will except HW or not. */
736 if ( pHAL->shared.bForceSW == TRUE )
737 {
738 return (pChoice == lpD3DHELDesc) ? D3DENUMRET_CANCEL : D3DENUMRET_OK;
739 }
740
741 /* Always try for hardware. */
742 if ( pChoice == lpD3DHWDesc )
743 {
744 return D3DENUMRET_CANCEL;
745 }
746
747 return D3DENUMRET_OK;
748 }
749 /*===========================================================================*/
750 /* This function will destroy any and all surfaces that this context has */
751 /* allocated. If there is a clipper object then it will also be destoryed as*/
752 /* it is part of the Primary Surface. */
753 /*===========================================================================*/
754 /* RETURN: */
755 /*===========================================================================*/
756 static void DestroyAllSurfaces( PMESAD3DHAL pHAL )
757 {
758 LONG refCount;
759
760 DPF(( DBG_FUNC, "DestroyAllSurfaces();" ));
761
762 DX_RESTORE( pHAL->lpDDSPrimary );
763 DX_RESTORE( pHAL->lpDDSRender );
764 DX_RESTORE( pHAL->lpDDSZbuffer);
765
766 if ( pHAL->lpDDSRender )
767 {
768 pHAL->lpDDSRender->Unlock( NULL );
769
770 /* If this isn't a Flipable surface then we must clean up the render. */
771 if ( pHAL->shared.bFlipable == FALSE)
772 {
773 if ( pHAL->lpDDSZbuffer )
774 {
775 DPF(( DBG_CNTX_INFO, "Remove attached surfaces from RENDER" ));
776 pHAL->lpDDSRender->DeleteAttachedSurface( 0, NULL );
777 }
778
779 DPF(( DBG_CNTX_INFO, "Release RENDER" ));
780 refCount = pHAL->lpDDSRender->Release();
781 pHAL->lpDDSRender = NULL;
782 }
783 }
784
785 if ( pHAL->lpDDSZbuffer )
786 {
787 DPF(( DBG_CNTX_INFO, "Release ZBuffer" ));
788 pHAL->lpDDSZbuffer->Unlock( NULL );
789 refCount = pHAL->lpDDSZbuffer->Release();
790 pHAL->lpDDSZbuffer = NULL;
791 }
792
793 if ( pHAL->lpClipper )
794 {
795 DPF(( DBG_CNTX_INFO, "Release Clipper" ));
796 refCount = pHAL->lpClipper->Release();
797 pHAL->lpClipper = NULL;
798 }
799
800 if ( pHAL->lpDDSPrimary )
801 {
802 pHAL->lpDDSPrimary->Unlock( NULL );
803
804 DPF(( DBG_CNTX_INFO, "Release PRIMARY" ));
805 refCount = pHAL->lpDDSPrimary->Release();
806 pHAL->lpDDSPrimary = NULL;
807 }
808 }
809 /*===========================================================================*/
810 /* This function will destroy the current D3DDevice and any resources that */
811 /* belong to it. */
812 /*===========================================================================*/
813 /* RETURN: */
814 /*===========================================================================*/
815 static void DestroyDevice( PMESAD3DHAL pHAL )
816 {
817 LONG refCount;
818
819 DPF(( DBG_FUNC, "DestroyDevice();" ));
820
821 /* Kill the D3D stuff if exists. */
822 if ( pHAL->lpViewport )
823 {
824 DPF(( DBG_CNTX_INFO, "Delete Viewport" ));
825 pHAL->lpD3DDevice->DeleteViewport( pHAL->lpViewport );
826
827 DPF(( DBG_CNTX_INFO, "Release Viewport" ));
828 refCount = pHAL->lpViewport->Release();
829 pHAL->lpViewport = NULL;
830 }
831
832 if ( pHAL->lpD3DDevice != NULL )
833 {
834 DPF(( DBG_CNTX_INFO, "Release D3DDevice" ));
835 refCount = pHAL->lpD3DDevice->EndScene();
836 refCount = pHAL->lpD3DDevice->Release();
837 pHAL->lpD3DDevice = NULL;
838 }
839 }
840 /*===========================================================================*/
841 /* This function will destroy the current D3DDevice and any resources that */
842 /* belong to it. */
843 /*===========================================================================*/
844 /* RETURN: */
845 /*===========================================================================*/
846 static void DestroyInterfaces( PMESAD3DHAL pHAL )
847 {
848 LONG refCount;
849
850 DPF(( DBG_FUNC, "DestroyInterfaces();" ));
851
852 if ( pHAL->lpD3D3 != NULL )
853 {
854 DPF(( DBG_CNTX_INFO, "Release Direct3D3" ));
855 refCount = pHAL->lpD3D3->Release();
856 pHAL->lpD3D3 = NULL;
857 }
858
859 if ( pHAL->lpDD4 != NULL )
860 {
861 DPF(( DBG_CNTX_INFO, "Release DDraw4" ));
862 refCount = pHAL->lpDD4->Release();
863 pHAL->lpDD4 = NULL;
864 }
865
866 if ( pHAL->lpDD != NULL )
867 {
868 DPF(( DBG_CNTX_INFO, "Release DDraw" ));
869 refCount = pHAL->lpDD->Release();
870 pHAL->lpDD = NULL;
871 }
872 }
873 /*===========================================================================*/
874 /* This function will first send (not post) a message to the client window */
875 /* that this context is using. The client will respond by unbinding itself */
876 /* and binding the 'default' context. This allows the API to be supported */
877 /* until the window can be destroyed. Finally we post the quit message to */
878 /* the client in hopes to end the application. */
879 /*===========================================================================*/
880 /* RETURN: */
881 /*===========================================================================*/
882 void FatalShutDown( PMESAD3DHAL pHAL )
883 {
884 /* Whip this baby in too try and support the API until we die... */
885 if ( pHAL )
886 SendMessage( pHAL->shared.hwnd, UM_FATALSHUTDOWN, 0L, 0L );
887
888 /* Close the client application down. */
889 PostQuitMessage( 0 );
890 }
891