xref: /reactos/dll/directx/d3d9/d3d9_impl.c (revision 40462c92)
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 */
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 */
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 
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 
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 
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 */
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 */
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 */
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 */
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 */
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