2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS ReactX
4 * FILE: dll/directx/d3d9/adapter.c
5 * PURPOSE: d3d9.dll adapter info functions
6 * PROGRAMERS: Gregor Brunmar <gregor (dot) brunmar (at) home (dot) se>
9 #include "d3d9_common.h"
14 #include "d3d9_private.h"
15 #include "d3d9_helpers.h"
18 #define D3D9_CAPS1 (D3DCAPS_READ_SCANLINE)
19 #define D3D9_PRE_XP_CAPS2 (D3DCAPS2_CANAUTOGENMIPMAP | D3DCAPS2_DYNAMICTEXTURES | D3DCAPS2_RESERVED | D3DCAPS2_FULLSCREENGAMMA)
20 #define D3D9_XP_OR_LATER_CAPS2 (D3D9_PRE_XP_CAPS2 | D3DCAPS2_CANMANAGERESOURCE)
21 #define D3D9_CAPS3 (D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD | D3DCAPS3_LINEAR_TO_SRGB_PRESENTATION | D3DCAPS3_COPY_TO_VIDMEM | D3DCAPS3_COPY_TO_SYSTEMMEM)
22 #define D3D9_DEVCAPS (D3DDEVCAPS_EXECUTESYSTEMMEMORY | D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY \
23 | D3DDEVCAPS_TLVERTEXVIDEOMEMORY | D3DDEVCAPS_TEXTURESYSTEMMEMORY | D3DDEVCAPS_TEXTUREVIDEOMEMORY \
24 | D3DDEVCAPS_DRAWPRIMTLVERTEX | D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_TEXTURENONLOCALVIDMEM \
25 | D3DDEVCAPS_DRAWPRIMITIVES2 | D3DDEVCAPS_SEPARATETEXTUREMEMORIES | D3DDEVCAPS_DRAWPRIMITIVES2EX \
26 | D3DDEVCAPS_HWTRANSFORMANDLIGHT | D3DDEVCAPS_CANBLTSYSTONONLOCAL | D3DDEVCAPS_HWRASTERIZATION \
27 | D3DDEVCAPS_PUREDEVICE | D3DDEVCAPS_QUINTICRTPATCHES | D3DDEVCAPS_RTPATCHES | D3DDEVCAPS_RTPATCHHANDLEZERO \
28 | D3DDEVCAPS_NPATCHES)
30 #define D3DCAPS2_PRESENT_INTERVAL_SEVERAL 0x00200000
31 #define D3DCAPS2_PRESENT_INTERVAL_IMMEDIATE 0x00400000
33 #define D3DVTXPCAPS_FOGVERTEX 0x00000004
35 typedef BOOL (WINAPI
*LPFN_ISWOW64PROCESS
) (HANDLE
, PBOOL
);
36 typedef BOOL (WINAPI
*LPFN_DISABLEWOW64FSREDIRECTION
) (PVOID
*);
37 typedef BOOL (WINAPI
*LPFN_REVERTWOW64FSREDIRECTION
) (PVOID
);
40 typedef struct _ADAPTERMONITOR
42 LPCSTR lpszDeviceName
;
44 } ADAPTERMONITOR
, *LPADAPTERMONITOR
;
47 static BOOL
GetDriverName(LPDISPLAY_DEVICEA pDisplayDevice
, D3DADAPTER_IDENTIFIER9
* pIdentifier
)
52 if (ERROR_SUCCESS
== RegOpenKeyExA(HKEY_LOCAL_MACHINE
, pDisplayDevice
->DeviceKey
+ strlen("\\Registry\\Machine\\"), 0, KEY_QUERY_VALUE
, &hKey
))
54 DWORD DriverNameLength
= MAX_DEVICE_IDENTIFIER_STRING
- (DWORD
)strlen(".dll");
57 if (ERROR_SUCCESS
== RegQueryValueExA(hKey
, "InstalledDisplayDrivers", 0, &Type
, (LPBYTE
)pIdentifier
->Driver
, &DriverNameLength
))
59 pIdentifier
->Driver
[DriverNameLength
] = '\0';
60 SafeAppendString(pIdentifier
->Driver
, MAX_DEVICE_IDENTIFIER_STRING
, ".dll");
70 static void GetDriverVersion(LPDISPLAY_DEVICEA pDisplayDevice
, D3DADAPTER_IDENTIFIER9
* pIdentifier
)
73 LPFN_ISWOW64PROCESS fnIsWow64Process
;
74 BOOL bIsWow64
= FALSE
;
75 PVOID OldWow64RedirectValue
;
78 hModule
= GetModuleHandleA("KERNEL32");
79 fnIsWow64Process
= (LPFN_ISWOW64PROCESS
)GetProcAddress(hModule
, "IsWow64Process");
82 fnIsWow64Process(GetCurrentProcess(), &bIsWow64
);
85 LPFN_DISABLEWOW64FSREDIRECTION fnDisableWow64FsRedirection
;
86 fnDisableWow64FsRedirection
= (LPFN_DISABLEWOW64FSREDIRECTION
)GetProcAddress(hModule
, "Wow64DisableWow64FsRedirection");
87 fnDisableWow64FsRedirection(&OldWow64RedirectValue
);
91 DriverFileSize
= GetFileVersionInfoSizeA(pIdentifier
->Driver
, NULL
);
92 if (DriverFileSize
> 0)
94 VS_FIXEDFILEINFO
* FixedFileInfo
= NULL
;
95 LPVOID pBlock
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, DriverFileSize
);
97 if (TRUE
== GetFileVersionInfoA(pIdentifier
->Driver
, 0, DriverFileSize
, pBlock
))
99 if (TRUE
== VerQueryValueA(pBlock
, "\\", (LPVOID
*)&FixedFileInfo
, &DriverFileSize
))
101 pIdentifier
->DriverVersion
.HighPart
= FixedFileInfo
->dwFileVersionMS
;
102 pIdentifier
->DriverVersion
.LowPart
= FixedFileInfo
->dwFileVersionLS
;
106 HeapFree(GetProcessHeap(), 0, pBlock
);
111 LPFN_REVERTWOW64FSREDIRECTION fnRevertWow64FsRedirection
;
112 fnRevertWow64FsRedirection
= (LPFN_REVERTWOW64FSREDIRECTION
)GetProcAddress(hModule
, "Wow64RevertWow64FsRedirection");
113 fnRevertWow64FsRedirection(&OldWow64RedirectValue
);
118 static void ParseField(LPCSTR lpszDeviceKey
, LPDWORD pField
, LPCSTR lpszSubString
)
120 const char* ResultStr
;
121 ResultStr
= strstr(lpszDeviceKey
, lpszSubString
);
122 if (ResultStr
!= NULL
)
124 *pField
= strtol(ResultStr
+ strlen(lpszSubString
), NULL
, 16);
128 static void GetDeviceId(LPCSTR lpszDeviceKey
, D3DADAPTER_IDENTIFIER9
* pIdentifier
)
130 ParseField(lpszDeviceKey
, &pIdentifier
->VendorId
, "VEN_");
131 ParseField(lpszDeviceKey
, &pIdentifier
->DeviceId
, "DEV_");
132 ParseField(lpszDeviceKey
, &pIdentifier
->SubSysId
, "SUBSYS_");
133 ParseField(lpszDeviceKey
, &pIdentifier
->Revision
, "REV_");
136 static void GenerateDeviceIdentifier(D3DADAPTER_IDENTIFIER9
* pIdentifier
)
138 DWORD
* dwIdentifier
= (DWORD
*)&pIdentifier
->DeviceIdentifier
;
140 pIdentifier
->DeviceIdentifier
= CLSID_DirectDraw
;
142 dwIdentifier
[0] ^= pIdentifier
->VendorId
;
143 dwIdentifier
[1] ^= pIdentifier
->DeviceId
;
144 dwIdentifier
[2] ^= pIdentifier
->SubSysId
;
145 dwIdentifier
[3] ^= pIdentifier
->Revision
;
146 dwIdentifier
[2] ^= pIdentifier
->DriverVersion
.LowPart
;
147 dwIdentifier
[3] ^= pIdentifier
->DriverVersion
.HighPart
;
150 BOOL
GetAdapterInfo(LPCSTR lpszDeviceName
, D3DADAPTER_IDENTIFIER9
* pIdentifier
)
152 DISPLAY_DEVICEA DisplayDevice
;
154 BOOL FoundDisplayDevice
;
156 memset(&DisplayDevice
, 0, sizeof(DISPLAY_DEVICEA
));
157 DisplayDevice
.cb
= sizeof(DISPLAY_DEVICEA
);
160 FoundDisplayDevice
= FALSE
;
161 while (EnumDisplayDevicesA(NULL
, AdapterIndex
, &DisplayDevice
, 0) == TRUE
)
163 if (_stricmp(lpszDeviceName
, DisplayDevice
.DeviceName
) == 0)
165 FoundDisplayDevice
= TRUE
;
172 /* No matching display device found? */
173 if (FALSE
== FoundDisplayDevice
)
176 lstrcpynA(pIdentifier
->Description
, DisplayDevice
.DeviceString
, MAX_DEVICE_IDENTIFIER_STRING
);
177 lstrcpynA(pIdentifier
->DeviceName
, DisplayDevice
.DeviceName
, CCHDEVICENAME
);
179 if (GetDriverName(&DisplayDevice
, pIdentifier
) == TRUE
)
180 GetDriverVersion(&DisplayDevice
, pIdentifier
);
182 GetDeviceId(DisplayDevice
.DeviceID
, pIdentifier
);
184 GenerateDeviceIdentifier(pIdentifier
);
191 static BOOL
IsWindowsXPorLaterCompatible()
195 ZeroMemory(&osvi
, sizeof(OSVERSIONINFOA
));
196 osvi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
198 if (GetVersionExA(&osvi
) != 0)
200 return ( (osvi
.dwMajorVersion
> 5) ||
201 ( (osvi
.dwMajorVersion
== 5) && (osvi
.dwMinorVersion
>= 1) ));
207 static void CopyDriverCaps(const D3DCAPS9
* pSrcCaps
, D3DCAPS9
* pDstCaps
)
209 *pDstCaps
= *pSrcCaps
;
211 pDstCaps
->Caps
= pSrcCaps
->Caps
& D3D9_CAPS1
;
213 /* TODO: Fit in D3DCAPS2_CANCALIBRATEGAMMA somewhere here */
214 if (IsWindowsXPorLaterCompatible())
215 pDstCaps
->Caps2
= pSrcCaps
->Caps2
& D3D9_XP_OR_LATER_CAPS2
;
217 pDstCaps
->Caps2
= pSrcCaps
->Caps2
& D3D9_PRE_XP_CAPS2
;
219 pDstCaps
->Caps3
= pSrcCaps
->Caps3
& D3D9_CAPS3
;
220 pDstCaps
->DevCaps
= pSrcCaps
->DevCaps
& D3D9_DEVCAPS
;
222 pDstCaps
->PresentationIntervals
= D3DPRESENT_INTERVAL_ONE
;
223 if (pSrcCaps
->Caps2
& D3DCAPS2_PRESENT_INTERVAL_SEVERAL
)
224 pDstCaps
->PresentationIntervals
|= (D3DPRESENT_INTERVAL_TWO
| D3DPRESENT_INTERVAL_THREE
| D3DPRESENT_INTERVAL_FOUR
);
225 if (pSrcCaps
->Caps2
& D3DCAPS2_PRESENT_INTERVAL_IMMEDIATE
)
226 pDstCaps
->PresentationIntervals
|= D3DPRESENT_INTERVAL_IMMEDIATE
;
228 pDstCaps
->PrimitiveMiscCaps
= pSrcCaps
->PrimitiveMiscCaps
& ~D3DPMISCCAPS_FOGINFVF
;
230 if (pSrcCaps
->VertexProcessingCaps
& D3DVTXPCAPS_FOGVERTEX
)
232 pDstCaps
->RasterCaps
|= D3DPRASTERCAPS_FOGVERTEX
;
233 pDstCaps
->VertexProcessingCaps
&= ~D3DVTXPCAPS_FOGVERTEX
;
236 if (pSrcCaps
->MaxPointSize
< 0.0f
)
237 pDstCaps
->MaxPointSize
= 1.0f
;
240 HRESULT
GetAdapterCaps(const LPDIRECT3D9_DISPLAYADAPTER pDisplayAdapter
, D3DDEVTYPE DeviceType
, D3DCAPS9
* pDstCaps
)
242 HRESULT hResult
= D3DERR_INVALIDDEVICE
;
243 D3DCAPS9
* pDriverCaps
= NULL
;
245 ZeroMemory(pDstCaps
, sizeof(D3DCAPS9
));
250 pDriverCaps
= &pDisplayAdapter
->DriverCaps
.DriverCaps9
;
256 case D3DDEVTYPE_NULLREF
:
262 DPRINT1("Unknown DeviceType argument");
266 if (pDriverCaps
!= NULL
)
268 CopyDriverCaps(pDriverCaps
, pDstCaps
);
271 if (SUCCEEDED(hResult
))
273 pDstCaps
->DeviceType
= DeviceType
;
274 pDstCaps
->MasterAdapterOrdinal
= pDisplayAdapter
->MasterAdapterIndex
;
275 pDstCaps
->AdapterOrdinalInGroup
= pDisplayAdapter
->AdapterIndexInGroup
;
276 pDstCaps
->NumberOfAdaptersInGroup
= pDisplayAdapter
->NumAdaptersInGroup
;
284 static D3DFORMAT
Get16BitD3DFormat(LPCSTR lpszDeviceName
)
288 LPBITMAPINFO pBitmapInfo
;
289 D3DFORMAT Format
= D3DFMT_R5G6B5
;
291 if (NULL
== (hDC
= CreateDCA(NULL
, lpszDeviceName
, NULL
, NULL
)))
296 if (NULL
== (hBitmap
= CreateCompatibleBitmap(hDC
, 1, 1)))
302 pBitmapInfo
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 4 * sizeof(RGBQUAD
));
303 if (NULL
== pBitmapInfo
)
305 DeleteObject(hBitmap
);
310 pBitmapInfo
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
311 if (GetDIBits(hDC
, hBitmap
, 0, 0, NULL
, pBitmapInfo
, DIB_RGB_COLORS
) > 0)
313 if (pBitmapInfo
->bmiHeader
.biCompression
== BI_BITFIELDS
)
315 if (GetDIBits(hDC
, hBitmap
, 0, pBitmapInfo
->bmiHeader
.biHeight
, NULL
, pBitmapInfo
, DIB_RGB_COLORS
) > 0)
317 /* Check if the green field is 6 bits long */
318 if (*(DWORD
*)(&pBitmapInfo
->bmiColors
[1]) == 0x000003E0)
320 Format
= D3DFMT_X1R5G5B5
;
326 HeapFree(GetProcessHeap(), 0, pBitmapInfo
);
327 DeleteObject(hBitmap
);
333 BOOL
GetAdapterMode(LPCSTR lpszDeviceName
, D3DDISPLAYMODE
* pMode
)
337 memset(&DevMode
, 0, sizeof(DEVMODEA
));
338 DevMode
.dmSize
= sizeof(DEVMODEA
);
339 if (FALSE
== EnumDisplaySettingsA(lpszDeviceName
, ENUM_CURRENT_SETTINGS
, &DevMode
))
342 pMode
->Width
= DevMode
.dmPelsWidth
;
343 pMode
->Height
= DevMode
.dmPelsHeight
;
344 pMode
->RefreshRate
= DevMode
.dmDisplayFrequency
;
346 switch (DevMode
.dmBitsPerPel
)
349 pMode
->Format
= D3DFMT_P8
;
353 pMode
->Format
= Get16BitD3DFormat(lpszDeviceName
);
357 pMode
->Format
= D3DFMT_R8G8B8
;
361 pMode
->Format
= D3DFMT_X8R8G8B8
;
365 pMode
->Format
= D3DFMT_UNKNOWN
;
374 static BOOL CALLBACK
AdapterMonitorEnumProc(HMONITOR hMonitor
, HDC hdcMonitor
, LPRECT lprcMonitor
, LPARAM dwData
)
376 MONITORINFOEXA MonitorInfoEx
;
377 LPADAPTERMONITOR lpAdapterMonitor
= (LPADAPTERMONITOR
)dwData
;
379 memset(&MonitorInfoEx
, 0, sizeof(MONITORINFOEXA
));
380 MonitorInfoEx
.cbSize
= sizeof(MONITORINFOEXA
);
382 GetMonitorInfoA(hMonitor
, (LPMONITORINFO
)&MonitorInfoEx
);
384 if (_stricmp(lpAdapterMonitor
->lpszDeviceName
, MonitorInfoEx
.szDevice
) == 0)
386 lpAdapterMonitor
->hMonitor
= hMonitor
;
393 HMONITOR
GetAdapterMonitor(LPCSTR lpszDeviceName
)
395 ADAPTERMONITOR AdapterMonitor
;
396 AdapterMonitor
.lpszDeviceName
= lpszDeviceName
;
397 AdapterMonitor
.hMonitor
= NULL
;
399 EnumDisplayMonitors(NULL
, NULL
, AdapterMonitorEnumProc
, (LPARAM
)&AdapterMonitor
);
401 return AdapterMonitor
.hMonitor
;
406 UINT
GetDisplayFormatCount(D3DFORMAT Format
, const D3DDISPLAYMODE
* pSupportedDisplayModes
, UINT NumDisplayModes
)
408 UINT DisplayModeIndex
;
409 UINT FormatIndex
= 0;
411 for (DisplayModeIndex
= 0; DisplayModeIndex
< NumDisplayModes
; DisplayModeIndex
++)
413 if (pSupportedDisplayModes
[DisplayModeIndex
].Format
== Format
)
422 const D3DDISPLAYMODE
* FindDisplayFormat(D3DFORMAT Format
, UINT ModeIndex
, const D3DDISPLAYMODE
* pSupportedDisplayModes
, UINT NumDisplayModes
)
424 UINT DisplayModeIndex
;
425 UINT FormatIndex
= 0;
427 for (DisplayModeIndex
= 0; DisplayModeIndex
< NumDisplayModes
; DisplayModeIndex
++)
429 if (pSupportedDisplayModes
[DisplayModeIndex
].Format
== Format
)
431 if (ModeIndex
== FormatIndex
)
432 return &pSupportedDisplayModes
[DisplayModeIndex
];
438 if (FormatIndex
== 0)
440 DPRINT1("No modes with the specified format found");
442 else if (FormatIndex
< ModeIndex
)
444 DPRINT1("Invalid mode index");