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) != 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 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 } 449