d62d97b3a4035d7b7b2f98e4b38678a98bcec49b
[reactos.git] / reactos / dll / directx / d3d9 / adapter.c
1 /*
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>
7 */
8
9 #include "d3d9_common.h"
10 #include <d3d9.h>
11 #include <ddraw.h>
12 #include <debug.h>
13 #include <d3dhal.h>
14 #include "d3d9_private.h"
15 #include "d3d9_helpers.h"
16 #include "adapter.h"
17
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)
29
30 #define D3DCAPS2_PRESENT_INTERVAL_SEVERAL 0x00200000
31 #define D3DCAPS2_PRESENT_INTERVAL_IMMEDIATE 0x00400000
32
33 #define D3DVTXPCAPS_FOGVERTEX 0x00000004
34
35 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
36 typedef BOOL (WINAPI *LPFN_DISABLEWOW64FSREDIRECTION) (PVOID*);
37 typedef BOOL (WINAPI *LPFN_REVERTWOW64FSREDIRECTION) (PVOID);
38
39
40 typedef struct _ADAPTERMONITOR
41 {
42 LPCSTR lpszDeviceName;
43 HMONITOR hMonitor;
44 } ADAPTERMONITOR, *LPADAPTERMONITOR;
45
46
47 static BOOL GetDriverName(LPDISPLAY_DEVICEA pDisplayDevice, D3DADAPTER_IDENTIFIER9* pIdentifier)
48 {
49 HKEY hKey;
50 BOOL bResult = FALSE;
51
52 if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_LOCAL_MACHINE, pDisplayDevice->DeviceKey + strlen("\\Registry\\Machine\\"), 0, KEY_QUERY_VALUE, &hKey))
53 {
54 DWORD DriverNameLength = MAX_DEVICE_IDENTIFIER_STRING - (DWORD)strlen(".dll");
55 DWORD Type = 0;
56
57 if (ERROR_SUCCESS == RegQueryValueExA(hKey, "InstalledDisplayDrivers", 0, &Type, (LPBYTE)pIdentifier->Driver, &DriverNameLength))
58 {
59 pIdentifier->Driver[DriverNameLength] = '\0';
60 SafeAppendString(pIdentifier->Driver, MAX_DEVICE_IDENTIFIER_STRING, ".dll");
61 bResult = TRUE;
62 }
63
64 RegCloseKey(hKey);
65 }
66
67 return bResult;
68 }
69
70 static void GetDriverVersion(LPDISPLAY_DEVICEA pDisplayDevice, D3DADAPTER_IDENTIFIER9* pIdentifier)
71 {
72 HMODULE hModule;
73 LPFN_ISWOW64PROCESS fnIsWow64Process;
74 BOOL bIsWow64 = FALSE;
75 PVOID OldWow64RedirectValue;
76 UINT DriverFileSize;
77
78 hModule = GetModuleHandleA("KERNEL32");
79 fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(hModule, "IsWow64Process");
80 if (fnIsWow64Process)
81 {
82 fnIsWow64Process(GetCurrentProcess(), &bIsWow64);
83 if (bIsWow64)
84 {
85 LPFN_DISABLEWOW64FSREDIRECTION fnDisableWow64FsRedirection;
86 fnDisableWow64FsRedirection = (LPFN_DISABLEWOW64FSREDIRECTION)GetProcAddress(hModule, "Wow64DisableWow64FsRedirection");
87 fnDisableWow64FsRedirection(&OldWow64RedirectValue);
88 }
89 }
90
91 DriverFileSize = GetFileVersionInfoSizeA(pIdentifier->Driver, NULL);
92 if (DriverFileSize > 0)
93 {
94 VS_FIXEDFILEINFO* FixedFileInfo = NULL;
95 LPVOID pBlock = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, DriverFileSize);
96
97 if (TRUE == GetFileVersionInfoA(pIdentifier->Driver, 0, DriverFileSize, pBlock))
98 {
99 if (TRUE == VerQueryValueA(pBlock, "\\", (LPVOID*)&FixedFileInfo, &DriverFileSize))
100 {
101 pIdentifier->DriverVersion.HighPart = FixedFileInfo->dwFileVersionMS;
102 pIdentifier->DriverVersion.LowPart = FixedFileInfo->dwFileVersionLS;
103 }
104 }
105
106 HeapFree(GetProcessHeap(), 0, pBlock);
107 }
108
109 if (bIsWow64)
110 {
111 LPFN_REVERTWOW64FSREDIRECTION fnRevertWow64FsRedirection;
112 fnRevertWow64FsRedirection = (LPFN_REVERTWOW64FSREDIRECTION)GetProcAddress(hModule, "Wow64RevertWow64FsRedirection");
113 fnRevertWow64FsRedirection(&OldWow64RedirectValue);
114 }
115 }
116
117
118 static void ParseField(LPCSTR lpszDeviceKey, LPDWORD pField, LPCSTR lpszSubString)
119 {
120 const char* ResultStr;
121 ResultStr = strstr(lpszDeviceKey, lpszSubString);
122 if (ResultStr != NULL)
123 {
124 *pField = strtol(ResultStr + strlen(lpszSubString), NULL, 16);
125 }
126 }
127
128 static void GetDeviceId(LPCSTR lpszDeviceKey, D3DADAPTER_IDENTIFIER9* pIdentifier)
129 {
130 ParseField(lpszDeviceKey, &pIdentifier->VendorId, "VEN_");
131 ParseField(lpszDeviceKey, &pIdentifier->DeviceId, "DEV_");
132 ParseField(lpszDeviceKey, &pIdentifier->SubSysId, "SUBSYS_");
133 ParseField(lpszDeviceKey, &pIdentifier->Revision, "REV_");
134 }
135
136 static void GenerateDeviceIdentifier(D3DADAPTER_IDENTIFIER9* pIdentifier)
137 {
138 DWORD* dwIdentifier = (DWORD*)&pIdentifier->DeviceIdentifier;
139
140 pIdentifier->DeviceIdentifier = CLSID_DirectDraw;
141
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;
148 }
149
150 BOOL GetAdapterInfo(LPCSTR lpszDeviceName, D3DADAPTER_IDENTIFIER9* pIdentifier)
151 {
152 DISPLAY_DEVICEA DisplayDevice;
153 DWORD AdapterIndex;
154 BOOL FoundDisplayDevice;
155
156 memset(&DisplayDevice, 0, sizeof(DISPLAY_DEVICEA));
157 DisplayDevice.cb = sizeof(DISPLAY_DEVICEA);
158
159 AdapterIndex = 0;
160 FoundDisplayDevice = FALSE;
161 while (EnumDisplayDevicesA(NULL, AdapterIndex, &DisplayDevice, 0) == TRUE)
162 {
163 if (_stricmp(lpszDeviceName, DisplayDevice.DeviceName) == 0)
164 {
165 FoundDisplayDevice = TRUE;
166 break;
167 }
168
169 ++AdapterIndex;
170 }
171
172 /* No matching display device found? */
173 if (FALSE == FoundDisplayDevice)
174 return FALSE;
175
176 lstrcpynA(pIdentifier->Description, DisplayDevice.DeviceString, MAX_DEVICE_IDENTIFIER_STRING);
177 lstrcpynA(pIdentifier->DeviceName, DisplayDevice.DeviceName, CCHDEVICENAME);
178
179 if (GetDriverName(&DisplayDevice, pIdentifier) == TRUE)
180 GetDriverVersion(&DisplayDevice, pIdentifier);
181
182 GetDeviceId(DisplayDevice.DeviceID, pIdentifier);
183
184 GenerateDeviceIdentifier(pIdentifier);
185
186 return TRUE;
187 }
188
189
190
191 static BOOL IsWindowsXPorLaterCompatible()
192 {
193 OSVERSIONINFOA osvi;
194
195 ZeroMemory(&osvi, sizeof(OSVERSIONINFOA));
196 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
197
198 if (GetVersionExA(&osvi) != 0)
199 {
200 return ( (osvi.dwMajorVersion > 5) ||
201 ( (osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion >= 1) ));
202 }
203
204 return FALSE;
205 }
206
207 static void CopyDriverCaps(const D3DCAPS9* pSrcCaps, D3DCAPS9* pDstCaps)
208 {
209 *pDstCaps = *pSrcCaps;
210
211 pDstCaps->Caps = pSrcCaps->Caps & D3D9_CAPS1;
212
213 /* TODO: Fit in D3DCAPS2_CANCALIBRATEGAMMA somewhere here */
214 if (IsWindowsXPorLaterCompatible())
215 pDstCaps->Caps2 = pSrcCaps->Caps2 & D3D9_XP_OR_LATER_CAPS2;
216 else
217 pDstCaps->Caps2 = pSrcCaps->Caps2 & D3D9_PRE_XP_CAPS2;
218
219 pDstCaps->Caps3 = pSrcCaps->Caps3 & D3D9_CAPS3;
220 pDstCaps->DevCaps = pSrcCaps->DevCaps & D3D9_DEVCAPS;
221
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;
227
228 pDstCaps->PrimitiveMiscCaps = pSrcCaps->PrimitiveMiscCaps & ~D3DPMISCCAPS_FOGINFVF;
229
230 if (pSrcCaps->VertexProcessingCaps & D3DVTXPCAPS_FOGVERTEX)
231 {
232 pDstCaps->RasterCaps |= D3DPRASTERCAPS_FOGVERTEX;
233 pDstCaps->VertexProcessingCaps &= ~D3DVTXPCAPS_FOGVERTEX;
234 }
235
236 if (pSrcCaps->MaxPointSize < 0.0f)
237 pDstCaps->MaxPointSize = 1.0f;
238 }
239
240 HRESULT GetAdapterCaps(const LPDIRECT3D9_DISPLAYADAPTER pDisplayAdapter, D3DDEVTYPE DeviceType, D3DCAPS9* pDstCaps)
241 {
242 HRESULT hResult = D3DERR_INVALIDDEVICE;
243 D3DCAPS9* pDriverCaps = NULL;
244
245 ZeroMemory(pDstCaps, sizeof(D3DCAPS9));
246
247 switch (DeviceType)
248 {
249 case D3DDEVTYPE_HAL:
250 pDriverCaps = &pDisplayAdapter->DriverCaps.DriverCaps9;
251 hResult = D3D_OK;
252 break;
253
254 case D3DDEVTYPE_REF:
255 case D3DDEVTYPE_SW:
256 case D3DDEVTYPE_NULLREF:
257 UNIMPLEMENTED;
258 hResult = D3D_OK;
259 break;
260
261 default:
262 DPRINT1("Unknown DeviceType argument");
263 break;
264 }
265
266 if (pDriverCaps != NULL)
267 {
268 CopyDriverCaps(pDriverCaps, pDstCaps);
269 }
270
271 if (SUCCEEDED(hResult))
272 {
273 pDstCaps->DeviceType = DeviceType;
274 pDstCaps->MasterAdapterOrdinal = pDisplayAdapter->MasterAdapterIndex;
275 pDstCaps->AdapterOrdinalInGroup = pDisplayAdapter->AdapterIndexInGroup;
276 pDstCaps->NumberOfAdaptersInGroup = pDisplayAdapter->NumAdaptersInGroup;
277 }
278
279 return hResult;
280 }
281
282
283
284 static D3DFORMAT Get16BitD3DFormat(LPCSTR lpszDeviceName)
285 {
286 HDC hDC;
287 HBITMAP hBitmap;
288 LPBITMAPINFO pBitmapInfo;
289 D3DFORMAT Format = D3DFMT_R5G6B5;
290
291 if (NULL == (hDC = CreateDCA(NULL, lpszDeviceName, NULL, NULL)))
292 {
293 return Format;
294 }
295
296 if (NULL == (hBitmap = CreateCompatibleBitmap(hDC, 1, 1)))
297 {
298 DeleteDC(hDC);
299 return Format;
300 }
301
302 pBitmapInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 4 * sizeof(RGBQUAD));
303 if (NULL == pBitmapInfo)
304 {
305 DeleteObject(hBitmap);
306 DeleteDC(hDC);
307 return Format;
308 }
309
310 pBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
311 if (GetDIBits(hDC, hBitmap, 0, 0, NULL, pBitmapInfo, DIB_RGB_COLORS) > 0)
312 {
313 if (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS)
314 {
315 if (GetDIBits(hDC, hBitmap, 0, pBitmapInfo->bmiHeader.biHeight, NULL, pBitmapInfo, DIB_RGB_COLORS) > 0)
316 {
317 /* Check if the green field is 6 bits long */
318 if (*(DWORD*)(&pBitmapInfo->bmiColors[1]) == 0x000003E0)
319 {
320 Format = D3DFMT_X1R5G5B5;
321 }
322 }
323 }
324 }
325
326 HeapFree(GetProcessHeap(), 0, pBitmapInfo);
327 DeleteObject(hBitmap);
328 DeleteDC(hDC);
329
330 return Format;
331 }
332
333 BOOL GetAdapterMode(LPCSTR lpszDeviceName, D3DDISPLAYMODE* pMode)
334 {
335 DEVMODEA DevMode;
336
337 memset(&DevMode, 0, sizeof(DEVMODEA));
338 DevMode.dmSize = sizeof(DEVMODEA);
339 if (FALSE == EnumDisplaySettingsA(lpszDeviceName, ENUM_CURRENT_SETTINGS, &DevMode))
340 return FALSE;
341
342 pMode->Width = DevMode.dmPelsWidth;
343 pMode->Height = DevMode.dmPelsHeight;
344 pMode->RefreshRate = DevMode.dmDisplayFrequency;
345
346 switch (DevMode.dmBitsPerPel)
347 {
348 case 8:
349 pMode->Format = D3DFMT_P8;
350 break;
351
352 case 16:
353 pMode->Format = Get16BitD3DFormat(lpszDeviceName);
354 break;
355
356 case 24:
357 pMode->Format = D3DFMT_R8G8B8;
358 break;
359
360 case 32:
361 pMode->Format = D3DFMT_X8R8G8B8;
362 break;
363
364 default:
365 pMode->Format = D3DFMT_UNKNOWN;
366 break;
367 }
368
369 return TRUE;
370 }
371
372
373
374 static BOOL CALLBACK AdapterMonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
375 {
376 MONITORINFOEXA MonitorInfoEx;
377 LPADAPTERMONITOR lpAdapterMonitor = (LPADAPTERMONITOR)dwData;
378
379 memset(&MonitorInfoEx, 0, sizeof(MONITORINFOEXA));
380 MonitorInfoEx.cbSize = sizeof(MONITORINFOEXA);
381
382 GetMonitorInfoA(hMonitor, (LPMONITORINFO)&MonitorInfoEx);
383
384 if (_stricmp(lpAdapterMonitor->lpszDeviceName, MonitorInfoEx.szDevice) == 0)
385 {
386 lpAdapterMonitor->hMonitor = hMonitor;
387 return FALSE;
388 }
389
390 return TRUE;
391 }
392
393 HMONITOR GetAdapterMonitor(LPCSTR lpszDeviceName)
394 {
395 ADAPTERMONITOR AdapterMonitor;
396 AdapterMonitor.lpszDeviceName = lpszDeviceName;
397 AdapterMonitor.hMonitor = NULL;
398
399 EnumDisplayMonitors(NULL, NULL, AdapterMonitorEnumProc, (LPARAM)&AdapterMonitor);
400
401 return AdapterMonitor.hMonitor;
402 }
403
404
405
406 UINT GetDisplayFormatCount(D3DFORMAT Format, const D3DDISPLAYMODE* pSupportedDisplayModes, UINT NumDisplayModes)
407 {
408 UINT DisplayModeIndex;
409 UINT FormatIndex = 0;
410
411 for (DisplayModeIndex = 0; DisplayModeIndex < NumDisplayModes; DisplayModeIndex++)
412 {
413 if (pSupportedDisplayModes[DisplayModeIndex].Format == Format)
414 {
415 ++FormatIndex;
416 }
417 }
418
419 return FormatIndex;
420 }
421
422 const D3DDISPLAYMODE* FindDisplayFormat(D3DFORMAT Format, UINT ModeIndex, const D3DDISPLAYMODE* pSupportedDisplayModes, UINT NumDisplayModes)
423 {
424 UINT DisplayModeIndex;
425 UINT FormatIndex = 0;
426
427 for (DisplayModeIndex = 0; DisplayModeIndex < NumDisplayModes; DisplayModeIndex++)
428 {
429 if (pSupportedDisplayModes[DisplayModeIndex].Format == Format)
430 {
431 if (ModeIndex == FormatIndex)
432 return &pSupportedDisplayModes[DisplayModeIndex];
433
434 ++FormatIndex;
435 }
436 }
437
438 if (FormatIndex == 0)
439 {
440 DPRINT1("No modes with the specified format found");
441 }
442 else if (FormatIndex < ModeIndex)
443 {
444 DPRINT1("Invalid mode index");
445 }
446
447 return NULL;
448 }