xref: /reactos/dll/directx/d3d9/adapter.c (revision 9393fc32)
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 
GetDriverName(LPDISPLAY_DEVICEA pDisplayDevice,D3DADAPTER_IDENTIFIER9 * pIdentifier)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 
GetDriverVersion(LPDISPLAY_DEVICEA pDisplayDevice,D3DADAPTER_IDENTIFIER9 * pIdentifier)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 
ParseField(LPCSTR lpszDeviceKey,LPDWORD pField,LPCSTR lpszSubString)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 
GetDeviceId(LPCSTR lpszDeviceKey,D3DADAPTER_IDENTIFIER9 * pIdentifier)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 
GenerateDeviceIdentifier(D3DADAPTER_IDENTIFIER9 * pIdentifier)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 
GetAdapterInfo(LPCSTR lpszDeviceName,D3DADAPTER_IDENTIFIER9 * pIdentifier)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) != FALSE)
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) != FALSE)
180         GetDriverVersion(&DisplayDevice, pIdentifier);
181 
182     GetDeviceId(DisplayDevice.DeviceID, pIdentifier);
183 
184     GenerateDeviceIdentifier(pIdentifier);
185 
186     return TRUE;
187 }
188 
189 
190 
IsWindowsXPorLaterCompatible()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 
CopyDriverCaps(const D3DCAPS9 * pSrcCaps,D3DCAPS9 * pDstCaps)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 
GetAdapterCaps(const LPDIRECT3D9_DISPLAYADAPTER pDisplayAdapter,D3DDEVTYPE DeviceType,D3DCAPS9 * pDstCaps)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 
Get16BitD3DFormat(LPCSTR lpszDeviceName)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 
GetAdapterMode(LPCSTR lpszDeviceName,D3DDISPLAYMODE * pMode)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 
AdapterMonitorEnumProc(HMONITOR hMonitor,HDC hdcMonitor,LPRECT lprcMonitor,LPARAM dwData)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 
GetAdapterMonitor(LPCSTR lpszDeviceName)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 
GetDisplayFormatCount(D3DFORMAT Format,const D3DDISPLAYMODE * pSupportedDisplayModes,UINT NumDisplayModes)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 
FindDisplayFormat(D3DFORMAT Format,UINT ModeIndex,const D3DDISPLAYMODE * pSupportedDisplayModes,UINT NumDisplayModes)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 }
449