1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS ReactX
4 * FILE: dll/directx/d3d9/d3d9_impl.c
5 * PURPOSE: IDirect3D9 implementation
6 * PROGRAMERS: Gregor Brunmar <gregor (dot) brunmar (at) home (dot) se>
7 */
8
9 #include "d3d9_common.h"
10 #include <d3d9.h>
11 #include <debug.h>
12 #include "d3d9_helpers.h"
13 #include "adapter.h"
14 #include "device.h"
15 #include "format.h"
16
17 #define LOCK_D3D9() EnterCriticalSection(&This->d3d9_cs);
18 #define UNLOCK_D3D9() LeaveCriticalSection(&This->d3d9_cs);
19
20 /* Convert a IDirect3D9 pointer safely to the internal implementation struct */
IDirect3D9ToImpl(LPDIRECT3D9 iface)21 static LPDIRECT3D9_INT IDirect3D9ToImpl(LPDIRECT3D9 iface)
22 {
23 if (NULL == iface)
24 return NULL;
25
26 return (LPDIRECT3D9_INT)((ULONG_PTR)iface - FIELD_OFFSET(DIRECT3D9_INT, lpVtbl));
27 }
28
29 /* IDirect3D9: IUnknown implementation */
IDirect3D9Impl_QueryInterface(LPDIRECT3D9 iface,REFIID riid,LPVOID * ppvObject)30 static HRESULT WINAPI IDirect3D9Impl_QueryInterface(LPDIRECT3D9 iface, REFIID riid, LPVOID* ppvObject)
31 {
32 LPDIRECT3D9_INT This = IDirect3D9ToImpl(iface);
33
34 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDirect3D9))
35 {
36 IUnknown_AddRef(iface);
37 *ppvObject = &This->lpVtbl;
38 return S_OK;
39 }
40
41 *ppvObject = NULL;
42 return E_NOINTERFACE;
43 }
44
IDirect3D9Impl_AddRef(LPDIRECT3D9 iface)45 static ULONG WINAPI IDirect3D9Impl_AddRef(LPDIRECT3D9 iface)
46 {
47 LPDIRECT3D9_INT This = IDirect3D9ToImpl(iface);
48 ULONG ref = InterlockedIncrement(&This->lRefCnt);
49
50 return ref;
51 }
52
IDirect3D9Impl_Release(LPDIRECT3D9 iface)53 static ULONG WINAPI IDirect3D9Impl_Release(LPDIRECT3D9 iface)
54 {
55 LPDIRECT3D9_INT This = IDirect3D9ToImpl(iface);
56 ULONG ref = InterlockedDecrement(&This->lRefCnt);
57
58 if (ref == 0)
59 {
60 EnterCriticalSection(&This->d3d9_cs);
61 /* TODO: Free resources here */
62 LeaveCriticalSection(&This->d3d9_cs);
63 AlignedFree(This);
64 }
65
66 return ref;
67 }
68
69 /* IDirect3D9 interface */
IDirect3D9Impl_RegisterSoftwareDevice(LPDIRECT3D9 iface,void * pInitializeFunction)70 static HRESULT WINAPI IDirect3D9Impl_RegisterSoftwareDevice(LPDIRECT3D9 iface, void* pInitializeFunction)
71 {
72 UNIMPLEMENTED
73
74 return D3D_OK;
75 }
76
77 /*++
78 * @name IDirect3D9::GetAdapterCount
79 * @implemented
80 *
81 * The function IDirect3D9Impl_GetAdapterCount returns the number of adapters
82 *
83 * @param LPDIRECT3D iface
84 * Pointer to the IDirect3D9 object returned from Direct3DCreate9()
85 *
86 * @return UINT
87 * The number of display adapters on the system when Direct3DCreate9() was called.
88 *
89 */
IDirect3D9Impl_GetAdapterCount(LPDIRECT3D9 iface)90 static UINT WINAPI IDirect3D9Impl_GetAdapterCount(LPDIRECT3D9 iface)
91 {
92 UINT NumDisplayAdapters;
93
94 LPDIRECT3D9_INT This = IDirect3D9ToImpl(iface);
95 LOCK_D3D9();
96
97 NumDisplayAdapters = This->NumDisplayAdapters;
98
99 UNLOCK_D3D9();
100 return NumDisplayAdapters;
101 }
102
103 /*++
104 * @name IDirect3D9::GetAdapterIdentifier
105 * @implemented
106 *
107 * The function IDirect3D9Impl_GetAdapterIdentifier gathers information about
108 * a specified display adapter and fills the pIdentifier argument with the available information.
109 *
110 * @param LPDIRECT3D iface
111 * Pointer to the IDirect3D9 object returned from Direct3DCreate9()
112 *
113 * @param UINT Adapter
114 * Adapter index to get information about. D3DADAPTER_DEFAULT is the primary display.
115 * The maximum value for this is the value returned by IDirect3D::GetAdapterCount() - 1.
116 *
117 * @param DWORD Flags
118 * Ignored at the moment, but the only valid flag is D3DENUM_WHQL_LEVEL
119 *
120 * @param D3DADAPTER_IDENTIFIER9* pIdentifier
121 * Pointer to a D3DADAPTER_IDENTIFIER9 structure to be filled with the available information
122 * about the display adapter.
123 *
124 * @return HRESULT
125 * If the method successfully fills the pIdentified structure, the return value is D3D_OK.
126 * If Adapter is out of range, Flags is invalid or pIdentifier is a bad pointer, the return value
127 * will be D3DERR_INVALIDCALL.
128 *
129 */
IDirect3D9Impl_GetAdapterIdentifier(LPDIRECT3D9 iface,UINT Adapter,DWORD Flags,D3DADAPTER_IDENTIFIER9 * pIdentifier)130 HRESULT WINAPI IDirect3D9Impl_GetAdapterIdentifier(LPDIRECT3D9 iface, UINT Adapter, DWORD Flags,
131 D3DADAPTER_IDENTIFIER9* pIdentifier)
132 {
133 LPDIRECT3D9_INT This = IDirect3D9ToImpl(iface);
134 LOCK_D3D9();
135
136 if (Adapter >= This->NumDisplayAdapters)
137 {
138 DPRINT1("Invalid Adapter number specified");
139 UNLOCK_D3D9();
140 return D3DERR_INVALIDCALL;
141 }
142
143 if (Flags & ~D3DENUM_WHQL_LEVEL)
144 {
145 DPRINT1("Invalid Flags specified");
146 UNLOCK_D3D9();
147 return D3DERR_INVALIDCALL;
148 }
149
150 if (NULL == pIdentifier)
151 {
152 DPRINT1("Invalid pIdentifier parameter specified");
153 UNLOCK_D3D9();
154 return D3DERR_INVALIDCALL;
155 }
156
157 memset(pIdentifier, 0, sizeof(D3DADAPTER_IDENTIFIER9));
158
159 if (FALSE == GetAdapterInfo(This->DisplayAdapters[Adapter].szDeviceName, pIdentifier))
160 {
161 DPRINT1("Internal error: Couldn't get the adapter info for device (%d): %s", Adapter, This->DisplayAdapters[Adapter].szDeviceName);
162 UNLOCK_D3D9();
163 return D3DERR_INVALIDCALL;
164 }
165
166 UNLOCK_D3D9();
167 return D3D_OK;
168 }
169
170 /*++
171 * @name IDirect3D9::GetAdapterModeCount
172 * @implemented
173 *
174 * The function IDirect3D9Impl_GetAdapterModeCount looks if the specified display adapter supports
175 * a specific pixel format and counts the available display modes for that format.
176 *
177 * @param LPDIRECT3D iface
178 * Pointer to the IDirect3D9 object returned from Direct3DCreate9()
179 *
180 * @param UINT Adapter
181 * Adapter index to get information about. D3DADAPTER_DEFAULT is the primary display.
182 * The maximum value for this is the value returned by IDirect3D9::GetAdapterCount() - 1.
183 *
184 * @param D3DFORMAT Format
185 * The pixel format to search for
186 *
187 * @return HRESULT
188 * If the method is successful it returns the number of display modes with the specified Format.
189 * If Adapter is out of range, the return value will be 0.
190 *
191 */
IDirect3D9Impl_GetAdapterModeCount(LPDIRECT3D9 iface,UINT Adapter,D3DFORMAT Format)192 static UINT WINAPI IDirect3D9Impl_GetAdapterModeCount(LPDIRECT3D9 iface, UINT Adapter, D3DFORMAT Format)
193 {
194 UINT AdapterModeCount;
195
196 LPDIRECT3D9_INT This = IDirect3D9ToImpl(iface);
197 LOCK_D3D9();
198
199 if (Adapter >= This->NumDisplayAdapters)
200 {
201 DPRINT1("Invalid Adapter number specified");
202 UNLOCK_D3D9();
203 return D3DERR_INVALIDCALL;
204 }
205
206 if (Format != D3DFMT_A2R10G10B10)
207 {
208 AdapterModeCount = GetDisplayFormatCount(
209 Format,
210 This->DisplayAdapters[Adapter].pSupportedD3DFormats,
211 This->DisplayAdapters[Adapter].NumSupportedD3DFormats);
212 }
213 else
214 {
215 AdapterModeCount = GetDisplayFormatCount(
216 Format,
217 This->DisplayAdapters[Adapter].pSupportedD3DExtendedFormats,
218 This->DisplayAdapters[Adapter].NumSupportedD3DExtendedFormats);
219 }
220
221 UNLOCK_D3D9();
222 return AdapterModeCount;
223 }
224
225 /*++
226 * @name IDirect3D9::EnumAdapterModes
227 * @implemented
228 *
229 * The function IDirect3D9Impl_EnumAdapterModes looks if the specified display adapter supports
230 * a specific pixel format and fills the pMode argument with the available display modes for that format.
231 * This function is often used in a loop to enumerate all the display modes the adapter supports.
232 *
233 * @param LPDIRECT3D iface
234 * Pointer to the IDirect3D9 object returned from Direct3DCreate9()
235 *
236 * @param UINT Adapter
237 * Adapter index to get information about. D3DADAPTER_DEFAULT is the primary display.
238 * The maximum value for this is the value returned by IDirect3D9::GetAdapterCount() - 1.
239 *
240 * @param D3DFORMAT Format
241 * The pixel format to search for
242 *
243 * @param UINT Mode
244 * Index within the pixel format to be returned.
245 * The maximum value for this is the value returned by IDirect3D9::GetAdapterModeCount() - 1.
246 *
247 * @param D3DDISPLAYMODE* pMode
248 * Pointer to a D3DDISPLAYMODE structure to be filled with the display mode information
249 * for the specified format.
250 *
251 * @return HRESULT
252 * If the method successfully fills the pMode structure, the return value is D3D_OK.
253 * If Adapter is out of range, pMode is a bad pointer or, no modes for the specified
254 * format was found or the mode parameter was invalid - the return value will be D3DERR_INVALIDCALL.
255 *
256 */
IDirect3D9Impl_EnumAdapterModes(LPDIRECT3D9 iface,UINT Adapter,D3DFORMAT Format,UINT Mode,D3DDISPLAYMODE * pMode)257 static HRESULT WINAPI IDirect3D9Impl_EnumAdapterModes(LPDIRECT3D9 iface, UINT Adapter, D3DFORMAT Format,
258 UINT Mode, D3DDISPLAYMODE* pMode)
259 {
260 const D3DDISPLAYMODE* pMatchingDisplayFormat;
261 LPDIRECT3D9_INT This = IDirect3D9ToImpl(iface);
262 LOCK_D3D9();
263
264 if (Adapter >= This->NumDisplayAdapters)
265 {
266 DPRINT1("Invalid Adapter number specified");
267 UNLOCK_D3D9();
268 return D3DERR_INVALIDCALL;
269 }
270
271 if (NULL == pMode)
272 {
273 DPRINT1("Invalid pMode parameter specified");
274 UNLOCK_D3D9();
275 return D3DERR_INVALIDCALL;
276 }
277
278 if (Format != D3DFMT_A2R10G10B10)
279 {
280 pMatchingDisplayFormat = FindDisplayFormat(
281 Format,
282 Mode,
283 This->DisplayAdapters[Adapter].pSupportedD3DFormats,
284 This->DisplayAdapters[Adapter].NumSupportedD3DFormats);
285 }
286 else
287 {
288 pMatchingDisplayFormat = FindDisplayFormat(
289 Format,
290 Mode,
291 This->DisplayAdapters[Adapter].pSupportedD3DExtendedFormats,
292 This->DisplayAdapters[Adapter].NumSupportedD3DExtendedFormats);
293 }
294
295 if (pMatchingDisplayFormat != NULL)
296 {
297 *pMode = *pMatchingDisplayFormat;
298 }
299 UNLOCK_D3D9();
300
301
302 if (pMatchingDisplayFormat == NULL)
303 return D3DERR_INVALIDCALL;
304
305 return D3D_OK;
306 }
307
308 /*++
309 * @name IDirect3D9::GetAdapterDisplayMode
310 * @implemented
311 *
312 * The function IDirect3D9Impl_GetAdapterDisplayMode fills the pMode argument with the
313 * currently set display mode.
314 *
315 * @param LPDIRECT3D iface
316 * Pointer to the IDirect3D9 object returned from Direct3DCreate9()
317 *
318 * @param UINT Adapter
319 * Adapter index to get information about. D3DADAPTER_DEFAULT is the primary display.
320 * The maximum value for this is the value returned by IDirect3D9::GetAdapterCount() - 1.
321 *
322 * @param D3DDISPLAYMODE* pMode
323 * Pointer to a D3DDISPLAYMODE structure to be filled with the current display mode information.
324 *
325 * @return HRESULT
326 * If the method successfully fills the pMode structure, the return value is D3D_OK.
327 * If Adapter is out of range or pMode is a bad pointer, the return value will be D3DERR_INVALIDCALL.
328 *
329 */
IDirect3D9Impl_GetAdapterDisplayMode(LPDIRECT3D9 iface,UINT Adapter,D3DDISPLAYMODE * pMode)330 static HRESULT WINAPI IDirect3D9Impl_GetAdapterDisplayMode(LPDIRECT3D9 iface, UINT Adapter, D3DDISPLAYMODE* pMode)
331 {
332 LPDIRECT3D9_INT This = IDirect3D9ToImpl(iface);
333 LOCK_D3D9();
334
335 if (Adapter >= This->NumDisplayAdapters)
336 {
337 DPRINT1("Invalid Adapter number specified");
338 UNLOCK_D3D9();
339 return D3DERR_INVALIDCALL;
340 }
341
342 if (NULL == pMode)
343 {
344 DPRINT1("Invalid pMode parameter specified");
345 UNLOCK_D3D9();
346 return D3DERR_INVALIDCALL;
347 }
348
349 /* TODO: Handle (This->DisplayAdapters[Adapter].bInUseFlag == FALSE) */
350 if (FALSE == GetAdapterMode(This->DisplayAdapters[Adapter].szDeviceName, pMode))
351 DPRINT1("Internal error, GetAdapterMode() failed.");
352
353 UNLOCK_D3D9();
354 return D3D_OK;
355 }
356
357
358 /*++
359 * @name IDirect3D9::CheckDeviceType
360 * @implemented
361 *
362 * The function IDirect3D9Impl_CheckDeviceType checks if a specific D3DFORMAT is hardware accelerated
363 * on the specified display adapter.
364 *
365 * @param LPDIRECT3D iface
366 * Pointer to the IDirect3D9 object returned from Direct3DCreate9()
367 *
368 * @param UINT Adapter
369 * Adapter index to get information about. D3DADAPTER_DEFAULT is the primary display.
370 * The maximum value for this is the value returned by IDirect3D9::GetAdapterCount() - 1.
371 *
372 * @param D3DDEVTYPE DeviceType
373 * One of the D3DDEVTYPE enum members.
374 *
375 * @param D3DFORMAT DisplayFormat
376 * One of the D3DFORMAT enum members except D3DFMT_UNKNOWN for the display adapter mode to be checked.
377 *
378 * @param D3DFORMAT BackBufferFormat
379 * One of the D3DFORMAT enum members for the render target mode to be checked. D3DFMT_UNKNOWN is only allowed in windowed mode.
380 *
381 * @param BOOL Windowed
382 * If this value is TRUE, the D3DFORMAT check will be done for windowed mode and FALSE equals fullscreen mode.
383 *
384 * @return HRESULT
385 * If the format is hardware accelerated, the method returns D3D_OK.
386 * If the format isn't hardware accelerated or unsupported - the return value will be D3DERR_NOTAVAILABLE.
387 * If Adapter is out of range, DeviceType is invalid,
388 * DisplayFormat or BackBufferFormat is invalid - the return value will be D3DERR_INVALIDCALL.
389 *
390 */
IDirect3D9Impl_CheckDeviceType(LPDIRECT3D9 iface,UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT DisplayFormat,D3DFORMAT BackBufferFormat,BOOL Windowed)391 static HRESULT WINAPI IDirect3D9Impl_CheckDeviceType(LPDIRECT3D9 iface, UINT Adapter, D3DDEVTYPE DeviceType,
392 D3DFORMAT DisplayFormat, D3DFORMAT BackBufferFormat, BOOL Windowed)
393 {
394 HRESULT hResult;
395
396 LPDIRECT3D9_INT This = IDirect3D9ToImpl(iface);
397 LOCK_D3D9();
398
399 if (Adapter >= This->NumDisplayAdapters)
400 {
401 DPRINT1("Invalid Adapter number specified");
402 UNLOCK_D3D9();
403 return D3DERR_INVALIDCALL;
404 }
405
406 if (DeviceType != D3DDEVTYPE_HAL &&
407 DeviceType != D3DDEVTYPE_REF &&
408 DeviceType != D3DDEVTYPE_SW)
409 {
410 DPRINT1("Invalid DeviceType specified");
411 UNLOCK_D3D9();
412 return D3DERR_INVALIDCALL;
413 }
414
415 if ((BackBufferFormat == D3DFMT_UNKNOWN) &&
416 (Windowed != FALSE))
417 {
418 BackBufferFormat = DisplayFormat;
419 }
420
421 if (DisplayFormat == D3DFMT_UNKNOWN && BackBufferFormat == D3DFMT_UNKNOWN)
422 {
423 DPRINT1("Invalid D3DFORMAT specified");
424 UNLOCK_D3D9();
425 return D3DERR_INVALIDCALL;
426 }
427
428 if (FALSE == IsBackBufferFormat(BackBufferFormat))
429 {
430 DPRINT1("Invalid D3DFORMAT specified");
431 UNLOCK_D3D9();
432 return D3DERR_NOTAVAILABLE;
433 }
434
435 if (TRUE == Windowed && TRUE == IsExtendedFormat(DisplayFormat))
436 {
437 DPRINT1("Extended display modes can only be used in fullscreen mode");
438 UNLOCK_D3D9();
439 return D3DERR_NOTAVAILABLE;
440 }
441
442 hResult = CheckDeviceType(&This->DisplayAdapters[Adapter].DriverCaps, DisplayFormat, BackBufferFormat, Windowed);
443
444 UNLOCK_D3D9();
445 return hResult;
446 }
447
448
449 /*++
450 * @name IDirect3D9::CheckDeviceFormat
451 * @implemented
452 *
453 * The function IDirect3D9Impl_CheckDeviceFormat checks if a specific D3DFORMAT
454 * can be used for a specific purpose like texture, depth/stencil buffer or as a render target
455 * on the specified display adapter.
456 *
457 * @param LPDIRECT3D iface
458 * Pointer to the IDirect3D9 object returned from Direct3DCreate9()
459 *
460 * @param UINT Adapter
461 * Adapter index to get information about. D3DADAPTER_DEFAULT is the primary display.
462 * The maximum value for this is the value returned by IDirect3D9::GetAdapterCount() - 1.
463 *
464 * @param D3DDEVTYPE DeviceType
465 * One of the D3DDEVTYPE enum members.
466 *
467 * @param D3DFORMAT AdapterFormat
468 * One of the D3DFORMAT enum members except D3DFMT_UNKNOWN for the display adapter mode to be checked.
469 *
470 * @param DWORD Usage
471 * Valid values are any of the D3DUSAGE_QUERY constants or any of these D3DUSAGE constants:
472 * D3DUSAGE_AUTOGENMIPMAP, D3DUSAGE_DEPTHSTENCIL, D3DUSAGE_DMAP, D3DUSAGE_DYNAMIC,
473 * D3DUSAGE_NONSECURE, D3DUSAGE_RENDERTARGET and D3DUSAGE_SOFTWAREPROCESSING.
474 *
475 * @param D3DRESOURCETYPE RType
476 * One of the D3DRESOURCETYPE enum members. Specifies what format will be used for.
477 *
478 * @param D3DFORMAT CheckFormat
479 * One of the D3DFORMAT enum members for the surface format to be checked.
480 *
481 * @return HRESULT
482 * If the format is compatible with the specified usage and resource type, the method returns D3D_OK.
483 * If the format isn't compatible with the specified usage and resource type - the return value will be D3DERR_NOTAVAILABLE.
484 * If Adapter is out of range, DeviceType is invalid, AdapterFormat or CheckFormat is invalid,
485 * Usage and RType isn't compatible - the return value will be D3DERR_INVALIDCALL.
486 *
487 */
IDirect3D9Impl_CheckDeviceFormat(LPDIRECT3D9 iface,UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,DWORD Usage,D3DRESOURCETYPE RType,D3DFORMAT CheckFormat)488 static HRESULT WINAPI IDirect3D9Impl_CheckDeviceFormat(LPDIRECT3D9 iface, UINT Adapter, D3DDEVTYPE DeviceType,
489 D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType,
490 D3DFORMAT CheckFormat)
491 {
492 LPD3D9_DRIVERCAPS pDriverCaps;
493 BOOL bIsTextureRType = FALSE;
494 HRESULT hResult;
495
496 LPDIRECT3D9_INT This = IDirect3D9ToImpl(iface);
497 LOCK_D3D9();
498
499 if (Adapter >= This->NumDisplayAdapters)
500 {
501 DPRINT1("Invalid Adapter number specified");
502 UNLOCK_D3D9();
503 return D3DERR_INVALIDCALL;
504 }
505
506 if (DeviceType != D3DDEVTYPE_HAL &&
507 DeviceType != D3DDEVTYPE_REF &&
508 DeviceType != D3DDEVTYPE_SW)
509 {
510 DPRINT1("Invalid DeviceType specified");
511 UNLOCK_D3D9();
512 return D3DERR_INVALIDCALL;
513 }
514
515 if (AdapterFormat == D3DFMT_UNKNOWN ||
516 CheckFormat == D3DFMT_UNKNOWN)
517 {
518 DPRINT1("Invalid D3DFORMAT specified");
519 UNLOCK_D3D9();
520 return D3DERR_INVALIDCALL;
521 }
522
523 if ((Usage & (D3DUSAGE_DONOTCLIP | D3DUSAGE_NPATCHES | D3DUSAGE_POINTS | D3DUSAGE_RTPATCHES | D3DUSAGE_TEXTAPI | D3DUSAGE_WRITEONLY)) != 0)
524 {
525 DPRINT1("Invalid Usage specified");
526 UNLOCK_D3D9();
527 return D3DERR_INVALIDCALL;
528 }
529
530 if (RType == D3DRTYPE_TEXTURE ||
531 RType == D3DRTYPE_VOLUMETEXTURE ||
532 RType == D3DRTYPE_CUBETEXTURE)
533 {
534 bIsTextureRType = TRUE;
535 }
536 else if (RType == D3DRTYPE_SURFACE &&
537 (Usage & (D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_RENDERTARGET)) == 0 &&
538 Usage != 0)
539 {
540 DPRINT1("When RType is set to D3DRTYPE_SURFACE, Usage must be 0 or have set D3DUSAGE_DEPTHSTENCIL or D3DUSAGE_RENDERTARGET");
541 UNLOCK_D3D9();
542 return D3DERR_INVALIDCALL;
543 }
544
545 if ((Usage & D3DUSAGE_DEPTHSTENCIL) != 0)
546 {
547 if (FALSE == IsZBufferFormat(CheckFormat))
548 {
549 DPRINT1("Invalid CheckFormat Z-Buffer format");
550 UNLOCK_D3D9();
551 return D3DERR_INVALIDCALL;
552 }
553
554 if ((Usage & D3DUSAGE_AUTOGENMIPMAP) != 0)
555 {
556 DPRINT1("Invalid Usage specified, D3DUSAGE_DEPTHSTENCIL and D3DUSAGE_AUTOGENMIPMAP can't be combined.");
557 UNLOCK_D3D9();
558 return D3DERR_INVALIDCALL;
559 }
560 }
561
562 if (FALSE == bIsTextureRType &&
563 RType != D3DRTYPE_SURFACE &&
564 RType != D3DRTYPE_VOLUME)
565 {
566 DPRINT1("Invalid RType specified");
567 UNLOCK_D3D9();
568 return D3DERR_INVALIDCALL;
569 }
570
571 if ((Usage & (D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_RENDERTARGET)) != 0)
572 {
573 if (RType == D3DRTYPE_VOLUME || RType == D3DRTYPE_VOLUMETEXTURE)
574 {
575 DPRINT1("Invalid Usage specified, D3DUSAGE_AUTOGENMIPMAP, D3DUSAGE_DEPTHSTENCIL and D3DUSAGE_RENDERTARGET can't be combined with RType D3DRTYPE_VOLUME or D3DRTYPE_VOLUMETEXTURE");
576 UNLOCK_D3D9();
577 return D3DERR_INVALIDCALL;
578 }
579 }
580
581 if (FALSE == bIsTextureRType &&
582 (Usage & D3DUSAGE_QUERY_VERTEXTEXTURE) != 0)
583 {
584 DPRINT1("Invalid Usage specified, D3DUSAGE_QUERY_VERTEXTEXTURE can only be used with a texture RType");
585 UNLOCK_D3D9();
586 return D3DERR_INVALIDCALL;
587 }
588
589 if ((Usage & D3DUSAGE_AUTOGENMIPMAP) != 0 &&
590 TRUE == IsMultiElementFormat(CheckFormat))
591 {
592 DPRINT1("Invalid Usage specified, D3DUSAGE_AUTOGENMIPMAP can't be used with a multi-element format");
593 UNLOCK_D3D9();
594 return D3DERR_INVALIDCALL;
595 }
596
597 pDriverCaps = &This->DisplayAdapters[Adapter].DriverCaps;
598 if (((Usage & D3DUSAGE_DYNAMIC) != 0) && (bIsTextureRType != FALSE))
599 {
600 if ((pDriverCaps->DriverCaps9.Caps2 & D3DCAPS2_DYNAMICTEXTURES) == 0)
601 {
602 DPRINT1("Driver doesn't support dynamic textures");
603 UNLOCK_D3D9();
604 return D3DERR_NOTAVAILABLE;
605 }
606
607 if ((Usage & (D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_RENDERTARGET)) != 0)
608 {
609 DPRINT1("Invalid Usage specified, D3DUSAGE_DEPTHSTENCIL and D3DUSAGE_RENDERTARGET can't be combined with D3DUSAGE_DYNAMIC and a texture RType");
610 UNLOCK_D3D9();
611 return D3DERR_INVALIDCALL;
612 }
613 }
614
615 if ((Usage & D3DUSAGE_DMAP) != 0)
616 {
617 if ((pDriverCaps->DriverCaps9.DevCaps2 & (D3DDEVCAPS2_PRESAMPLEDDMAPNPATCH | D3DDEVCAPS2_DMAPNPATCH)) == 0)
618 {
619 DPRINT1("Driver doesn't support displacement mapping");
620 UNLOCK_D3D9();
621 return D3DERR_NOTAVAILABLE;
622 }
623
624 if (RType != D3DRTYPE_TEXTURE)
625 {
626 DPRINT1("Invalid Usage specified, D3DUSAGE_DMAP must be combined with RType D3DRTYPE_TEXTURE");
627 UNLOCK_D3D9();
628 return D3DERR_INVALIDCALL;
629 }
630 }
631
632 hResult = CheckDeviceFormat(pDriverCaps, AdapterFormat, Usage, RType, CheckFormat);
633
634 UNLOCK_D3D9();
635 return hResult;
636 }
637
IDirect3D9Impl_CheckDeviceMultiSampleType(LPDIRECT3D9 iface,UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SurfaceFormat,BOOL Windowed,D3DMULTISAMPLE_TYPE MultiSampleType,DWORD * pQualityLevels)638 static HRESULT WINAPI IDirect3D9Impl_CheckDeviceMultiSampleType(LPDIRECT3D9 iface, UINT Adapter, D3DDEVTYPE DeviceType,
639 D3DFORMAT SurfaceFormat, BOOL Windowed,
640 D3DMULTISAMPLE_TYPE MultiSampleType, DWORD* pQualityLevels)
641 {
642 UNIMPLEMENTED
643
644 return D3D_OK;
645 }
646
647
648 /*++
649 * @name IDirect3D9::CheckDepthStencilMatch
650 * @implemented
651 *
652 * The function IDirect3D9Impl_CheckDepthStencilMatch checks if a specific combination
653 * of a render target D3DFORMAT and a depth-stencil D3DFORMAT can be used with a specified
654 * D3DFORMAT on the specified display adapter.
655 *
656 * @param LPDIRECT3D iface
657 * Pointer to the IDirect3D9 object returned from Direct3DCreate9()
658 *
659 * @param UINT Adapter
660 * Adapter index to get information about. D3DADAPTER_DEFAULT is the primary display.
661 * The maximum value for this is the value returned by IDirect3D9::GetAdapterCount() - 1.
662 *
663 * @param D3DDEVTYPE DeviceType
664 * One of the D3DDEVTYPE enum members.
665 *
666 * @param D3DFORMAT AdapterFormat
667 * One of the D3DFORMAT enum members except D3DFMT_UNKNOWN that the display adapter mode where the test should occur.
668 *
669 * @param D3DFORMAT RenderTargetFormat
670 * One of the D3DFORMAT enum members except D3DFMT_UNKNOWN for the display adapter mode's render target format to be tested.
671 *
672 * @param D3DFORMAT DepthStencilFormat
673 * One of the D3DFORMAT enum members except D3DFMT_UNKNOWN for the display adapter mode's depth-stencil format to be tested.
674 *
675 * @return HRESULT
676 * If the DepthStencilFormat can be used with the RenderTargetFormat under the specified AdapterFormat,
677 * the method returns D3D_OK.
678 * If the DepthStencilFormat can NOT used with the RenderTargetFormat under the specified AdapterFormat,
679 * the method returns D3DERR_NOTAVAILABLE.
680 * If Adapter is out of range, DeviceType is invalid,
681 * AdapterFormat, RenderTargetFormat or DepthStencilFormat is invalid, the method returns D3DERR_INVALIDCALL.
682 *
683 */
IDirect3D9Impl_CheckDepthStencilMatch(LPDIRECT3D9 iface,UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat)684 static HRESULT WINAPI IDirect3D9Impl_CheckDepthStencilMatch(LPDIRECT3D9 iface, UINT Adapter, D3DDEVTYPE DeviceType,
685 D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat,
686 D3DFORMAT DepthStencilFormat)
687 {
688 HRESULT hResult;
689
690 LPDIRECT3D9_INT This = IDirect3D9ToImpl(iface);
691 LOCK_D3D9();
692
693 if (Adapter >= This->NumDisplayAdapters)
694 {
695 DPRINT1("Invalid Adapter number specified");
696 UNLOCK_D3D9();
697 return D3DERR_INVALIDCALL;
698 }
699
700 if (DeviceType != D3DDEVTYPE_HAL &&
701 DeviceType != D3DDEVTYPE_REF &&
702 DeviceType != D3DDEVTYPE_SW)
703 {
704 DPRINT1("Invalid DeviceType specified");
705 UNLOCK_D3D9();
706 return D3DERR_INVALIDCALL;
707 }
708
709 if (AdapterFormat == D3DFMT_UNKNOWN ||
710 RenderTargetFormat == D3DFMT_UNKNOWN ||
711 DepthStencilFormat == D3DFMT_UNKNOWN)
712 {
713 DPRINT1("Invalid D3DFORMAT specified");
714 UNLOCK_D3D9();
715 return D3DERR_INVALIDCALL;
716 }
717
718 hResult = CheckDepthStencilMatch(&This->DisplayAdapters[Adapter].DriverCaps, AdapterFormat, RenderTargetFormat, DepthStencilFormat);
719
720 UNLOCK_D3D9();
721 return hResult;
722 }
723
724
725 /*++
726 * @name IDirect3D9::CheckDeviceFormatConversion
727 * @implemented
728 *
729 * The function IDirect3D9Impl_CheckDeviceFormatConversion checks if a specific D3DFORMAT
730 * can be converted to another on the specified display adapter.
731 *
732 * @param LPDIRECT3D iface
733 * Pointer to the IDirect3D9 object returned from Direct3DCreate9()
734 *
735 * @param UINT Adapter
736 * Adapter index to get information about. D3DADAPTER_DEFAULT is the primary display.
737 * The maximum value for this is the value returned by IDirect3D9::GetAdapterCount() - 1.
738 *
739 * @param D3DDEVTYPE DeviceType
740 * One of the D3DDEVTYPE enum members. Only D3DDEVTYPE_HAL can potentially return D3D_OK.
741 *
742 * @param D3DFORMAT SourceFormat
743 * One of the D3DFORMAT enum members except D3DFMT_UNKNOWN for the display adapter mode to be converted from.
744 *
745 * @param D3DFORMAT TargetFormat
746 * One of the D3DFORMAT enum members except D3DFMT_UNKNOWN for the display adapter mode to be converted to.
747 *
748 * @return HRESULT
749 * If the SourceFormat can be converted to the TargetFormat, the method returns D3D_OK.
750 * If the SourceFormat can NOT be converted to the TargetFormat, the method returns D3DERR_NOTAVAILABLE.
751 * If Adapter is out of range, DeviceType is invalid,
752 * SourceFormat or TargetFormat is invalid, the method returns D3DERR_INVALIDCALL.
753 *
754 */
IDirect3D9Impl_CheckDeviceFormatConversion(LPDIRECT3D9 iface,UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SourceFormat,D3DFORMAT TargetFormat)755 static HRESULT WINAPI IDirect3D9Impl_CheckDeviceFormatConversion(LPDIRECT3D9 iface, UINT Adapter, D3DDEVTYPE DeviceType,
756 D3DFORMAT SourceFormat, D3DFORMAT TargetFormat)
757 {
758 HRESULT hResult;
759 LPDIRECT3D9_INT This = IDirect3D9ToImpl(iface);
760 LOCK_D3D9();
761
762 if (Adapter >= This->NumDisplayAdapters)
763 {
764 DPRINT1("Invalid Adapter number specified");
765 UNLOCK_D3D9();
766 return D3DERR_INVALIDCALL;
767 }
768
769 if (DeviceType != D3DDEVTYPE_HAL &&
770 DeviceType != D3DDEVTYPE_REF &&
771 DeviceType != D3DDEVTYPE_SW)
772 {
773 DPRINT1("Invalid DeviceType specified");
774 UNLOCK_D3D9();
775 return D3DERR_INVALIDCALL;
776 }
777
778 if (SourceFormat == D3DFMT_UNKNOWN ||
779 TargetFormat == D3DFMT_UNKNOWN)
780 {
781 DPRINT1("Invalid D3DFORMAT specified");
782 UNLOCK_D3D9();
783 return D3DERR_NOTAVAILABLE;
784 }
785
786 if (DeviceType == D3DDEVTYPE_HAL)
787 {
788 hResult = CheckDeviceFormatConversion(&This->DisplayAdapters[Adapter].DriverCaps, SourceFormat, TargetFormat);
789 }
790 else
791 {
792 hResult = D3DERR_NOTAVAILABLE;
793 }
794
795 UNLOCK_D3D9();
796 return hResult;
797 }
798
799
800 /*++
801 * @name IDirect3D9::GetDeviceCaps
802 * @implemented
803 *
804 * The function IDirect3D9Impl_GetDeviceCaps fills the pCaps argument with the
805 * capabilities of the specified adapter and device type.
806 *
807 * @param LPDIRECT3D iface
808 * Pointer to the IDirect3D9 object returned from Direct3DCreate9()
809 *
810 * @param UINT Adapter
811 * Adapter index to get information about. D3DADAPTER_DEFAULT is the primary display.
812 * The maximum value for this is the value returned by IDirect3D9::GetAdapterCount() - 1.
813 *
814 * @param D3DDEVTYPE DeviceType
815 * One of the D3DDEVTYPE enum members.
816 * NOTE: Currently only D3DDEVTYPE_HAL is implemented.
817 *
818 * @param D3DCAPS9* pCaps
819 * Pointer to a D3DCAPS9 structure to be filled with the adapter's device type capabilities.
820 *
821 * @return HRESULT
822 * If the method successfully fills the pCaps structure, the return value is D3D_OK.
823 * If Adapter is out of range or pCaps is a bad pointer, the return value will be D3DERR_INVALIDCALL.
824 * If DeviceType is invalid, the return value will be D3DERR_INVALIDDEVICE.
825 *
826 */
IDirect3D9Impl_GetDeviceCaps(LPDIRECT3D9 iface,UINT Adapter,D3DDEVTYPE DeviceType,D3DCAPS9 * pCaps)827 static HRESULT WINAPI IDirect3D9Impl_GetDeviceCaps(LPDIRECT3D9 iface, UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS9* pCaps)
828 {
829 HRESULT hResult;
830 LPDIRECT3D9_INT This = IDirect3D9ToImpl(iface);
831 LOCK_D3D9();
832
833 if (Adapter >= This->NumDisplayAdapters)
834 {
835 DPRINT1("Invalid Adapter number specified");
836 UNLOCK_D3D9();
837 return D3DERR_INVALIDCALL;
838 }
839
840 if (NULL == pCaps)
841 {
842 DPRINT1("Invalid pCaps parameter specified");
843 UNLOCK_D3D9();
844 return D3DERR_INVALIDCALL;
845 }
846
847 hResult = GetAdapterCaps(&This->DisplayAdapters[Adapter], DeviceType, pCaps);
848
849 UNLOCK_D3D9();
850 return hResult;
851 }
852
853 /*++
854 * @name IDirect3D9::GetAdapterMonitor
855 * @implemented
856 *
857 * The function IDirect3D9Impl_GetAdapterMonitor returns the monitor associated
858 * with the specified display adapter.
859 *
860 * @param LPDIRECT3D iface
861 * Pointer to the IDirect3D9 object returned from Direct3DCreate9()
862 *
863 * @param UINT Adapter
864 * Adapter index to get information about. D3DADAPTER_DEFAULT is the primary display.
865 * The maximum value for this is the value returned by IDirect3D9::GetAdapterCount() - 1.
866 *
867 * @return HMONITOR
868 * If the method successfully it returns the HMONITOR belonging to the specified adapter.
869 * If the method fails, the return value is NULL.
870 *
871 */
IDirect3D9Impl_GetAdapterMonitor(LPDIRECT3D9 iface,UINT Adapter)872 static HMONITOR WINAPI IDirect3D9Impl_GetAdapterMonitor(LPDIRECT3D9 iface, UINT Adapter)
873 {
874 HMONITOR hAdapterMonitor = NULL;
875
876 LPDIRECT3D9_INT This = IDirect3D9ToImpl(iface);
877 LOCK_D3D9();
878
879 if (Adapter < This->NumDisplayAdapters)
880 {
881 hAdapterMonitor = GetAdapterMonitor(This->DisplayAdapters[Adapter].szDeviceName);
882 }
883 else
884 {
885 DPRINT1("Invalid Adapter number specified");
886 }
887
888 UNLOCK_D3D9();
889 return hAdapterMonitor;
890 }
891
892 /*++
893 * @name IDirect3D9::CreateDevice
894 * @implemented
895 *
896 * The function IDirect3D9Impl_CreateDevice creates an IDirect3DDevice9 object
897 * that represents the display adapter.
898 *
899 * @param LPDIRECT3D iface
900 * Pointer to the IDirect3D9 object returned from Direct3DCreate9()
901 *
902 * @param UINT Adapter
903 * Adapter index to get information about. D3DADAPTER_DEFAULT is the primary display.
904 * The maximum value for this is the value returned by IDirect3D::GetAdapterCount() - 1.
905 *
906 * @param D3DDEVTYPE DeviceType
907 * One of the D3DDEVTYPE enum members.
908 *
909 * @param HWND hFocusWindow
910 * A window handle that is used as a reference when Direct3D should switch between
911 * foreground mode and background mode.
912 *
913 * @param DWORD BehaviourFlags
914 * Any valid combination of the D3DCREATE constants.
915 *
916 * @param D3DPRESENT_PARAMETERS* pPresentationParameters
917 * Pointer to a D3DPRESENT_PARAMETERS structure describing the parameters for the device
918 * to be created. If D3DCREATE_ADAPTERGROUP_DEVICE is specified in the BehaviourFlags parameter,
919 * the pPresentationParameters is treated as an array.
920 *
921 * @param IDirect3DDevice9** ppReturnedDeviceInterface
922 * Return object that represents the created device.
923 *
924 * @return HRESULT
925 * If the method successfully creates a device and returns a valid ppReturnedDeviceInterface object,
926 * the return value is D3D_OK.
927 * If Adapter is out of range, DeviceType is invalid, hFocusWindow is not a valid, BehaviourFlags is invalid
928 * pPresentationParameters is invalid or ppReturnedDeviceInterface is a bad pointer, the return value
929 * will be D3DERR_INVALIDCALL.
930 *
931 */
IDirect3D9Impl_CreateDevice(LPDIRECT3D9 iface,UINT Adapter,D3DDEVTYPE DeviceType,HWND hFocusWindow,DWORD BehaviourFlags,D3DPRESENT_PARAMETERS * pPresentationParameters,struct IDirect3DDevice9 ** ppReturnedDeviceInterface)932 static HRESULT WINAPI IDirect3D9Impl_CreateDevice(LPDIRECT3D9 iface, UINT Adapter, D3DDEVTYPE DeviceType,
933 HWND hFocusWindow, DWORD BehaviourFlags,
934 D3DPRESENT_PARAMETERS* pPresentationParameters,
935 struct IDirect3DDevice9** ppReturnedDeviceInterface)
936 {
937 DWORD NumAdaptersToCreate;
938 HRESULT Ret;
939
940 LPDIRECT3D9_INT This = IDirect3D9ToImpl(iface);
941 LOCK_D3D9();
942
943 if (Adapter >= This->NumDisplayAdapters)
944 {
945 DPRINT1("Invalid Adapter number specified");
946 UNLOCK_D3D9();
947 return D3DERR_INVALIDCALL;
948 }
949
950 if (DeviceType != D3DDEVTYPE_HAL &&
951 DeviceType != D3DDEVTYPE_REF &&
952 DeviceType != D3DDEVTYPE_SW)
953 {
954 DPRINT1("Invalid DeviceType specified");
955 UNLOCK_D3D9();
956 return D3DERR_INVALIDCALL;
957 }
958
959 if (DeviceType != D3DDEVTYPE_HAL)
960 {
961 UNIMPLEMENTED
962 DPRINT1("Sorry, only D3DDEVTYPE_HAL is implemented at this time...");
963 return D3DERR_INVALIDCALL;
964 }
965
966 if (hFocusWindow != NULL && FALSE == IsWindow(hFocusWindow))
967 {
968 DPRINT1("Invalid hFocusWindow parameter specified, expected NULL or a valid HWND");
969 UNLOCK_D3D9();
970 return D3DERR_INVALIDCALL;
971 }
972
973 if (NULL == pPresentationParameters)
974 {
975 DPRINT1("Invalid pPresentationParameters parameter specified");
976 UNLOCK_D3D9();
977 return D3DERR_INVALIDCALL;
978 }
979
980 if (pPresentationParameters->hDeviceWindow != NULL && FALSE == IsWindow(pPresentationParameters->hDeviceWindow))
981 {
982 DPRINT1("Invalid pPresentationParameters->hDeviceWindow parameter specified, expected NULL or a valid HWND");
983 UNLOCK_D3D9();
984 return D3DERR_INVALIDCALL;
985 }
986
987 if (FALSE == pPresentationParameters->Windowed && hFocusWindow == NULL)
988 {
989 DPRINT1("When pPresentationParameters->Windowed is not set, hFocusWindow must be a valid HWND");
990 UNLOCK_D3D9();
991 return D3DERR_INVALIDCALL;
992 }
993
994 if (NULL == hFocusWindow && NULL == pPresentationParameters->hDeviceWindow)
995 {
996 DPRINT1("Any of pPresentationParameters->Windowed and hFocusWindow must be set to a valid HWND");
997 UNLOCK_D3D9();
998 return D3DERR_INVALIDCALL;
999 }
1000
1001 if (Adapter > 0 && NULL == pPresentationParameters->hDeviceWindow)
1002 {
1003 DPRINT1("Invalid pPresentationParameters->hDeviceWindow, must be set to a valid unique HWND when Adapter is greater than 0");
1004 UNLOCK_D3D9();
1005 return D3DERR_INVALIDCALL;
1006 }
1007
1008 if (NULL == ppReturnedDeviceInterface)
1009 {
1010 DPRINT1("Invalid ppReturnedDeviceInterface parameter specified");
1011 UNLOCK_D3D9();
1012 return D3DERR_INVALIDCALL;
1013 }
1014
1015 if ((BehaviourFlags & D3DCREATE_ADAPTERGROUP_DEVICE) != 0)
1016 NumAdaptersToCreate = This->DisplayAdapters[Adapter].NumAdaptersInGroup;
1017 else
1018 NumAdaptersToCreate = 1;
1019
1020 *ppReturnedDeviceInterface = 0;
1021
1022 Ret = CreateD3D9HalDevice(This, Adapter, hFocusWindow, BehaviourFlags, pPresentationParameters, NumAdaptersToCreate, ppReturnedDeviceInterface);
1023
1024 UNLOCK_D3D9();
1025 return Ret;
1026 }
1027
1028 IDirect3D9Vtbl Direct3D9_Vtbl =
1029 {
1030 /* IUnknown */
1031 IDirect3D9Impl_QueryInterface,
1032 IDirect3D9Impl_AddRef,
1033 IDirect3D9Impl_Release,
1034
1035 /* IDirect3D9 */
1036 IDirect3D9Impl_RegisterSoftwareDevice,
1037 IDirect3D9Impl_GetAdapterCount,
1038 IDirect3D9Impl_GetAdapterIdentifier,
1039 IDirect3D9Impl_GetAdapterModeCount,
1040 IDirect3D9Impl_EnumAdapterModes,
1041 IDirect3D9Impl_GetAdapterDisplayMode,
1042 IDirect3D9Impl_CheckDeviceType,
1043 IDirect3D9Impl_CheckDeviceFormat,
1044 IDirect3D9Impl_CheckDeviceMultiSampleType,
1045 IDirect3D9Impl_CheckDepthStencilMatch,
1046 IDirect3D9Impl_CheckDeviceFormatConversion,
1047 IDirect3D9Impl_GetDeviceCaps,
1048 IDirect3D9Impl_GetAdapterMonitor,
1049 IDirect3D9Impl_CreateDevice
1050 };
1051