mirror of
https://github.com/reactos/reactos.git
synced 2024-08-27 13:48:42 +00:00
449 lines
14 KiB
C
449 lines
14 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS ReactX
|
|
* FILE: dll/directx/d3d9/adapter.c
|
|
* PURPOSE: d3d9.dll adapter info functions
|
|
* PROGRAMERS: Gregor Brunmar <gregor (dot) brunmar (at) home (dot) se>
|
|
*/
|
|
|
|
#include "d3d9_common.h"
|
|
#include <d3d9.h>
|
|
#include <ddraw.h>
|
|
#include <debug.h>
|
|
#include <d3dhal.h>
|
|
#include "d3d9_private.h"
|
|
#include "d3d9_helpers.h"
|
|
#include "adapter.h"
|
|
|
|
#define D3D9_CAPS1 (D3DCAPS_READ_SCANLINE)
|
|
#define D3D9_PRE_XP_CAPS2 (D3DCAPS2_CANAUTOGENMIPMAP | D3DCAPS2_DYNAMICTEXTURES | D3DCAPS2_RESERVED | D3DCAPS2_FULLSCREENGAMMA)
|
|
#define D3D9_XP_OR_LATER_CAPS2 (D3D9_PRE_XP_CAPS2 | D3DCAPS2_CANMANAGERESOURCE)
|
|
#define D3D9_CAPS3 (D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD | D3DCAPS3_LINEAR_TO_SRGB_PRESENTATION | D3DCAPS3_COPY_TO_VIDMEM | D3DCAPS3_COPY_TO_SYSTEMMEM)
|
|
#define D3D9_DEVCAPS (D3DDEVCAPS_EXECUTESYSTEMMEMORY | D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY \
|
|
| D3DDEVCAPS_TLVERTEXVIDEOMEMORY | D3DDEVCAPS_TEXTURESYSTEMMEMORY | D3DDEVCAPS_TEXTUREVIDEOMEMORY \
|
|
| D3DDEVCAPS_DRAWPRIMTLVERTEX | D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_TEXTURENONLOCALVIDMEM \
|
|
| D3DDEVCAPS_DRAWPRIMITIVES2 | D3DDEVCAPS_SEPARATETEXTUREMEMORIES | D3DDEVCAPS_DRAWPRIMITIVES2EX \
|
|
| D3DDEVCAPS_HWTRANSFORMANDLIGHT | D3DDEVCAPS_CANBLTSYSTONONLOCAL | D3DDEVCAPS_HWRASTERIZATION \
|
|
| D3DDEVCAPS_PUREDEVICE | D3DDEVCAPS_QUINTICRTPATCHES | D3DDEVCAPS_RTPATCHES | D3DDEVCAPS_RTPATCHHANDLEZERO \
|
|
| D3DDEVCAPS_NPATCHES)
|
|
|
|
#define D3DCAPS2_PRESENT_INTERVAL_SEVERAL 0x00200000
|
|
#define D3DCAPS2_PRESENT_INTERVAL_IMMEDIATE 0x00400000
|
|
|
|
#define D3DVTXPCAPS_FOGVERTEX 0x00000004
|
|
|
|
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
|
|
typedef BOOL (WINAPI *LPFN_DISABLEWOW64FSREDIRECTION) (PVOID*);
|
|
typedef BOOL (WINAPI *LPFN_REVERTWOW64FSREDIRECTION) (PVOID);
|
|
|
|
|
|
typedef struct _ADAPTERMONITOR
|
|
{
|
|
LPCSTR lpszDeviceName;
|
|
HMONITOR hMonitor;
|
|
} ADAPTERMONITOR, *LPADAPTERMONITOR;
|
|
|
|
|
|
static BOOL GetDriverName(LPDISPLAY_DEVICEA pDisplayDevice, D3DADAPTER_IDENTIFIER9* pIdentifier)
|
|
{
|
|
HKEY hKey;
|
|
BOOL bResult = FALSE;
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_LOCAL_MACHINE, pDisplayDevice->DeviceKey + strlen("\\Registry\\Machine\\"), 0, KEY_QUERY_VALUE, &hKey))
|
|
{
|
|
DWORD DriverNameLength = MAX_DEVICE_IDENTIFIER_STRING - (DWORD)strlen(".dll");
|
|
DWORD Type = 0;
|
|
|
|
if (ERROR_SUCCESS == RegQueryValueExA(hKey, "InstalledDisplayDrivers", 0, &Type, (LPBYTE)pIdentifier->Driver, &DriverNameLength))
|
|
{
|
|
pIdentifier->Driver[DriverNameLength] = '\0';
|
|
SafeAppendString(pIdentifier->Driver, MAX_DEVICE_IDENTIFIER_STRING, ".dll");
|
|
bResult = TRUE;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
static void GetDriverVersion(LPDISPLAY_DEVICEA pDisplayDevice, D3DADAPTER_IDENTIFIER9* pIdentifier)
|
|
{
|
|
HMODULE hModule;
|
|
LPFN_ISWOW64PROCESS fnIsWow64Process;
|
|
BOOL bIsWow64 = FALSE;
|
|
PVOID OldWow64RedirectValue;
|
|
UINT DriverFileSize;
|
|
|
|
hModule = GetModuleHandleA("KERNEL32");
|
|
fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(hModule, "IsWow64Process");
|
|
if (fnIsWow64Process)
|
|
{
|
|
fnIsWow64Process(GetCurrentProcess(), &bIsWow64);
|
|
if (bIsWow64)
|
|
{
|
|
LPFN_DISABLEWOW64FSREDIRECTION fnDisableWow64FsRedirection;
|
|
fnDisableWow64FsRedirection = (LPFN_DISABLEWOW64FSREDIRECTION)GetProcAddress(hModule, "Wow64DisableWow64FsRedirection");
|
|
fnDisableWow64FsRedirection(&OldWow64RedirectValue);
|
|
}
|
|
}
|
|
|
|
DriverFileSize = GetFileVersionInfoSizeA(pIdentifier->Driver, NULL);
|
|
if (DriverFileSize > 0)
|
|
{
|
|
VS_FIXEDFILEINFO* FixedFileInfo = NULL;
|
|
LPVOID pBlock = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, DriverFileSize);
|
|
|
|
if (TRUE == GetFileVersionInfoA(pIdentifier->Driver, 0, DriverFileSize, pBlock))
|
|
{
|
|
if (TRUE == VerQueryValueA(pBlock, "\\", (LPVOID*)&FixedFileInfo, &DriverFileSize))
|
|
{
|
|
pIdentifier->DriverVersion.HighPart = FixedFileInfo->dwFileVersionMS;
|
|
pIdentifier->DriverVersion.LowPart = FixedFileInfo->dwFileVersionLS;
|
|
}
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, pBlock);
|
|
}
|
|
|
|
if (bIsWow64)
|
|
{
|
|
LPFN_REVERTWOW64FSREDIRECTION fnRevertWow64FsRedirection;
|
|
fnRevertWow64FsRedirection = (LPFN_REVERTWOW64FSREDIRECTION)GetProcAddress(hModule, "Wow64RevertWow64FsRedirection");
|
|
fnRevertWow64FsRedirection(&OldWow64RedirectValue);
|
|
}
|
|
}
|
|
|
|
|
|
static void ParseField(LPCSTR lpszDeviceKey, LPDWORD pField, LPCSTR lpszSubString)
|
|
{
|
|
const char* ResultStr;
|
|
ResultStr = strstr(lpszDeviceKey, lpszSubString);
|
|
if (ResultStr != NULL)
|
|
{
|
|
*pField = strtol(ResultStr + strlen(lpszSubString), NULL, 16);
|
|
}
|
|
}
|
|
|
|
static void GetDeviceId(LPCSTR lpszDeviceKey, D3DADAPTER_IDENTIFIER9* pIdentifier)
|
|
{
|
|
ParseField(lpszDeviceKey, &pIdentifier->VendorId, "VEN_");
|
|
ParseField(lpszDeviceKey, &pIdentifier->DeviceId, "DEV_");
|
|
ParseField(lpszDeviceKey, &pIdentifier->SubSysId, "SUBSYS_");
|
|
ParseField(lpszDeviceKey, &pIdentifier->Revision, "REV_");
|
|
}
|
|
|
|
static void GenerateDeviceIdentifier(D3DADAPTER_IDENTIFIER9* pIdentifier)
|
|
{
|
|
DWORD* dwIdentifier = (DWORD*)&pIdentifier->DeviceIdentifier;
|
|
|
|
pIdentifier->DeviceIdentifier = CLSID_DirectDraw;
|
|
|
|
dwIdentifier[0] ^= pIdentifier->VendorId;
|
|
dwIdentifier[1] ^= pIdentifier->DeviceId;
|
|
dwIdentifier[2] ^= pIdentifier->SubSysId;
|
|
dwIdentifier[3] ^= pIdentifier->Revision;
|
|
dwIdentifier[2] ^= pIdentifier->DriverVersion.LowPart;
|
|
dwIdentifier[3] ^= pIdentifier->DriverVersion.HighPart;
|
|
}
|
|
|
|
BOOL GetAdapterInfo(LPCSTR lpszDeviceName, D3DADAPTER_IDENTIFIER9* pIdentifier)
|
|
{
|
|
DISPLAY_DEVICEA DisplayDevice;
|
|
DWORD AdapterIndex;
|
|
BOOL FoundDisplayDevice;
|
|
|
|
memset(&DisplayDevice, 0, sizeof(DISPLAY_DEVICEA));
|
|
DisplayDevice.cb = sizeof(DISPLAY_DEVICEA);
|
|
|
|
AdapterIndex = 0;
|
|
FoundDisplayDevice = FALSE;
|
|
while (EnumDisplayDevicesA(NULL, AdapterIndex, &DisplayDevice, 0) != FALSE)
|
|
{
|
|
if (_stricmp(lpszDeviceName, DisplayDevice.DeviceName) == 0)
|
|
{
|
|
FoundDisplayDevice = TRUE;
|
|
break;
|
|
}
|
|
|
|
++AdapterIndex;
|
|
}
|
|
|
|
/* No matching display device found? */
|
|
if (FALSE == FoundDisplayDevice)
|
|
return FALSE;
|
|
|
|
lstrcpynA(pIdentifier->Description, DisplayDevice.DeviceString, MAX_DEVICE_IDENTIFIER_STRING);
|
|
lstrcpynA(pIdentifier->DeviceName, DisplayDevice.DeviceName, CCHDEVICENAME);
|
|
|
|
if (GetDriverName(&DisplayDevice, pIdentifier) != FALSE)
|
|
GetDriverVersion(&DisplayDevice, pIdentifier);
|
|
|
|
GetDeviceId(DisplayDevice.DeviceID, pIdentifier);
|
|
|
|
GenerateDeviceIdentifier(pIdentifier);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
static BOOL IsWindowsXPorLaterCompatible()
|
|
{
|
|
OSVERSIONINFOA osvi;
|
|
|
|
ZeroMemory(&osvi, sizeof(OSVERSIONINFOA));
|
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
|
|
|
|
if (GetVersionExA(&osvi) != 0)
|
|
{
|
|
return ( (osvi.dwMajorVersion > 5) ||
|
|
( (osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion >= 1) ));
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void CopyDriverCaps(const D3DCAPS9* pSrcCaps, D3DCAPS9* pDstCaps)
|
|
{
|
|
*pDstCaps = *pSrcCaps;
|
|
|
|
pDstCaps->Caps = pSrcCaps->Caps & D3D9_CAPS1;
|
|
|
|
/* TODO: Fit in D3DCAPS2_CANCALIBRATEGAMMA somewhere here */
|
|
if (IsWindowsXPorLaterCompatible())
|
|
pDstCaps->Caps2 = pSrcCaps->Caps2 & D3D9_XP_OR_LATER_CAPS2;
|
|
else
|
|
pDstCaps->Caps2 = pSrcCaps->Caps2 & D3D9_PRE_XP_CAPS2;
|
|
|
|
pDstCaps->Caps3 = pSrcCaps->Caps3 & D3D9_CAPS3;
|
|
pDstCaps->DevCaps = pSrcCaps->DevCaps & D3D9_DEVCAPS;
|
|
|
|
pDstCaps->PresentationIntervals = D3DPRESENT_INTERVAL_ONE;
|
|
if (pSrcCaps->Caps2 & D3DCAPS2_PRESENT_INTERVAL_SEVERAL)
|
|
pDstCaps->PresentationIntervals |= (D3DPRESENT_INTERVAL_TWO | D3DPRESENT_INTERVAL_THREE | D3DPRESENT_INTERVAL_FOUR);
|
|
if (pSrcCaps->Caps2 & D3DCAPS2_PRESENT_INTERVAL_IMMEDIATE)
|
|
pDstCaps->PresentationIntervals |= D3DPRESENT_INTERVAL_IMMEDIATE;
|
|
|
|
pDstCaps->PrimitiveMiscCaps = pSrcCaps->PrimitiveMiscCaps & ~D3DPMISCCAPS_FOGINFVF;
|
|
|
|
if (pSrcCaps->VertexProcessingCaps & D3DVTXPCAPS_FOGVERTEX)
|
|
{
|
|
pDstCaps->RasterCaps |= D3DPRASTERCAPS_FOGVERTEX;
|
|
pDstCaps->VertexProcessingCaps &= ~D3DVTXPCAPS_FOGVERTEX;
|
|
}
|
|
|
|
if (pSrcCaps->MaxPointSize < 0.0f)
|
|
pDstCaps->MaxPointSize = 1.0f;
|
|
}
|
|
|
|
HRESULT GetAdapterCaps(const LPDIRECT3D9_DISPLAYADAPTER pDisplayAdapter, D3DDEVTYPE DeviceType, D3DCAPS9* pDstCaps)
|
|
{
|
|
HRESULT hResult = D3DERR_INVALIDDEVICE;
|
|
D3DCAPS9* pDriverCaps = NULL;
|
|
|
|
ZeroMemory(pDstCaps, sizeof(D3DCAPS9));
|
|
|
|
switch (DeviceType)
|
|
{
|
|
case D3DDEVTYPE_HAL:
|
|
pDriverCaps = &pDisplayAdapter->DriverCaps.DriverCaps9;
|
|
hResult = D3D_OK;
|
|
break;
|
|
|
|
case D3DDEVTYPE_REF:
|
|
case D3DDEVTYPE_SW:
|
|
case D3DDEVTYPE_NULLREF:
|
|
UNIMPLEMENTED;
|
|
hResult = D3D_OK;
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("Unknown DeviceType argument");
|
|
break;
|
|
}
|
|
|
|
if (pDriverCaps != NULL)
|
|
{
|
|
CopyDriverCaps(pDriverCaps, pDstCaps);
|
|
}
|
|
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
pDstCaps->DeviceType = DeviceType;
|
|
pDstCaps->MasterAdapterOrdinal = pDisplayAdapter->MasterAdapterIndex;
|
|
pDstCaps->AdapterOrdinalInGroup = pDisplayAdapter->AdapterIndexInGroup;
|
|
pDstCaps->NumberOfAdaptersInGroup = pDisplayAdapter->NumAdaptersInGroup;
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
|
|
static D3DFORMAT Get16BitD3DFormat(LPCSTR lpszDeviceName)
|
|
{
|
|
HDC hDC;
|
|
HBITMAP hBitmap;
|
|
LPBITMAPINFO pBitmapInfo;
|
|
D3DFORMAT Format = D3DFMT_R5G6B5;
|
|
|
|
if (NULL == (hDC = CreateDCA(NULL, lpszDeviceName, NULL, NULL)))
|
|
{
|
|
return Format;
|
|
}
|
|
|
|
if (NULL == (hBitmap = CreateCompatibleBitmap(hDC, 1, 1)))
|
|
{
|
|
DeleteDC(hDC);
|
|
return Format;
|
|
}
|
|
|
|
pBitmapInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 4 * sizeof(RGBQUAD));
|
|
if (NULL == pBitmapInfo)
|
|
{
|
|
DeleteObject(hBitmap);
|
|
DeleteDC(hDC);
|
|
return Format;
|
|
}
|
|
|
|
pBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
if (GetDIBits(hDC, hBitmap, 0, 0, NULL, pBitmapInfo, DIB_RGB_COLORS) > 0)
|
|
{
|
|
if (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS)
|
|
{
|
|
if (GetDIBits(hDC, hBitmap, 0, pBitmapInfo->bmiHeader.biHeight, NULL, pBitmapInfo, DIB_RGB_COLORS) > 0)
|
|
{
|
|
/* Check if the green field is 6 bits long */
|
|
if (*(DWORD*)(&pBitmapInfo->bmiColors[1]) == 0x000003E0)
|
|
{
|
|
Format = D3DFMT_X1R5G5B5;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, pBitmapInfo);
|
|
DeleteObject(hBitmap);
|
|
DeleteDC(hDC);
|
|
|
|
return Format;
|
|
}
|
|
|
|
BOOL GetAdapterMode(LPCSTR lpszDeviceName, D3DDISPLAYMODE* pMode)
|
|
{
|
|
DEVMODEA DevMode;
|
|
|
|
memset(&DevMode, 0, sizeof(DEVMODEA));
|
|
DevMode.dmSize = sizeof(DEVMODEA);
|
|
if (FALSE == EnumDisplaySettingsA(lpszDeviceName, ENUM_CURRENT_SETTINGS, &DevMode))
|
|
return FALSE;
|
|
|
|
pMode->Width = DevMode.dmPelsWidth;
|
|
pMode->Height = DevMode.dmPelsHeight;
|
|
pMode->RefreshRate = DevMode.dmDisplayFrequency;
|
|
|
|
switch (DevMode.dmBitsPerPel)
|
|
{
|
|
case 8:
|
|
pMode->Format = D3DFMT_P8;
|
|
break;
|
|
|
|
case 16:
|
|
pMode->Format = Get16BitD3DFormat(lpszDeviceName);
|
|
break;
|
|
|
|
case 24:
|
|
pMode->Format = D3DFMT_R8G8B8;
|
|
break;
|
|
|
|
case 32:
|
|
pMode->Format = D3DFMT_X8R8G8B8;
|
|
break;
|
|
|
|
default:
|
|
pMode->Format = D3DFMT_UNKNOWN;
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
static BOOL CALLBACK AdapterMonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
|
|
{
|
|
MONITORINFOEXA MonitorInfoEx;
|
|
LPADAPTERMONITOR lpAdapterMonitor = (LPADAPTERMONITOR)dwData;
|
|
|
|
memset(&MonitorInfoEx, 0, sizeof(MONITORINFOEXA));
|
|
MonitorInfoEx.cbSize = sizeof(MONITORINFOEXA);
|
|
|
|
GetMonitorInfoA(hMonitor, (LPMONITORINFO)&MonitorInfoEx);
|
|
|
|
if (_stricmp(lpAdapterMonitor->lpszDeviceName, MonitorInfoEx.szDevice) == 0)
|
|
{
|
|
lpAdapterMonitor->hMonitor = hMonitor;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
HMONITOR GetAdapterMonitor(LPCSTR lpszDeviceName)
|
|
{
|
|
ADAPTERMONITOR AdapterMonitor;
|
|
AdapterMonitor.lpszDeviceName = lpszDeviceName;
|
|
AdapterMonitor.hMonitor = NULL;
|
|
|
|
EnumDisplayMonitors(NULL, NULL, AdapterMonitorEnumProc, (LPARAM)&AdapterMonitor);
|
|
|
|
return AdapterMonitor.hMonitor;
|
|
}
|
|
|
|
|
|
|
|
UINT GetDisplayFormatCount(D3DFORMAT Format, const D3DDISPLAYMODE* pSupportedDisplayModes, UINT NumDisplayModes)
|
|
{
|
|
UINT DisplayModeIndex;
|
|
UINT FormatIndex = 0;
|
|
|
|
for (DisplayModeIndex = 0; DisplayModeIndex < NumDisplayModes; DisplayModeIndex++)
|
|
{
|
|
if (pSupportedDisplayModes[DisplayModeIndex].Format == Format)
|
|
{
|
|
++FormatIndex;
|
|
}
|
|
}
|
|
|
|
return FormatIndex;
|
|
}
|
|
|
|
const D3DDISPLAYMODE* FindDisplayFormat(D3DFORMAT Format, UINT ModeIndex, const D3DDISPLAYMODE* pSupportedDisplayModes, UINT NumDisplayModes)
|
|
{
|
|
UINT DisplayModeIndex;
|
|
UINT FormatIndex = 0;
|
|
|
|
for (DisplayModeIndex = 0; DisplayModeIndex < NumDisplayModes; DisplayModeIndex++)
|
|
{
|
|
if (pSupportedDisplayModes[DisplayModeIndex].Format == Format)
|
|
{
|
|
if (ModeIndex == FormatIndex)
|
|
return &pSupportedDisplayModes[DisplayModeIndex];
|
|
|
|
++FormatIndex;
|
|
}
|
|
}
|
|
|
|
if (FormatIndex == 0)
|
|
{
|
|
DPRINT1("No modes with the specified format found");
|
|
}
|
|
else if (FormatIndex < ModeIndex)
|
|
{
|
|
DPRINT1("Invalid mode index");
|
|
}
|
|
|
|
return NULL;
|
|
}
|