1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-13 16:08:50 +01:00
dxvk/src/d3d9/d3d9_adapter.cpp
Philip Rebohle 6c5f73ac26
[dxvk] Reintroduce VkPhysicalDeviceIDProperties
We need this to get the device LUID. Wine does not fill in the
LUID properties in VkPhysicalDeviceVulkan11Properties right now.

Fixes DLSS not working, as well as other potential issues.
2022-07-26 22:38:33 +02:00

816 lines
34 KiB
C++

#include "d3d9_adapter.h"
#include "d3d9_interface.h"
#include "d3d9_monitor.h"
#include "d3d9_caps.h"
#include "d3d9_util.h"
#include "../util/util_bit.h"
#include "../util/util_luid.h"
#include "../util/util_ratio.h"
#include <cfloat>
namespace dxvk {
const char* GetDriverDLL(DxvkGpuVendor vendor) {
switch (vendor) {
default:
case DxvkGpuVendor::Nvidia: return "nvd3dum.dll";
#if defined(__x86_64__) || defined(_M_X64)
case DxvkGpuVendor::Amd: return "aticfx64.dll";
case DxvkGpuVendor::Intel: return "igdumd64.dll";
#else
case DxvkGpuVendor::Amd: return "aticfx32.dll";
case DxvkGpuVendor::Intel: return "igdumd32.dll";
#endif
}
}
D3D9Adapter::D3D9Adapter(
D3D9InterfaceEx* pParent,
Rc<DxvkAdapter> Adapter,
UINT Ordinal,
UINT DisplayIndex)
: m_parent (pParent),
m_adapter (Adapter),
m_ordinal (Ordinal),
m_displayIndex (DisplayIndex),
m_modeCacheFormat (D3D9Format::Unknown),
m_d3d9Formats (Adapter, m_parent->GetOptions()) {
m_adapter->logAdapterInfo();
}
template <size_t N>
static void copyToStringArray(char (&dst)[N], const char* src) {
dxvk::str::strlcpy(dst, src, N);
}
HRESULT D3D9Adapter::GetAdapterIdentifier(
DWORD Flags,
D3DADAPTER_IDENTIFIER9* pIdentifier) {
if (unlikely(pIdentifier == nullptr))
return D3DERR_INVALIDCALL;
auto& options = m_parent->GetOptions();
const auto& props = m_adapter->deviceProperties();
DISPLAY_DEVICEA device = { };
device.cb = sizeof(device);
if (!::EnumDisplayDevicesA(nullptr, m_displayIndex, &device, 0)) {
Logger::err("D3D9Adapter::GetAdapterIdentifier: Failed to query display info");
return D3DERR_INVALIDCALL;
}
GUID guid = bit::cast<GUID>(m_adapter->devicePropertiesExt().vk11.deviceUUID);
uint32_t vendorId = options.customVendorId == -1 ? props.vendorID : uint32_t(options.customVendorId);
uint32_t deviceId = options.customDeviceId == -1 ? props.deviceID : uint32_t(options.customDeviceId);
const char* desc = options.customDeviceDesc.empty() ? props.deviceName : options.customDeviceDesc.c_str();
const char* driver = GetDriverDLL(DxvkGpuVendor(vendorId));
copyToStringArray(pIdentifier->Description, desc);
copyToStringArray(pIdentifier->DeviceName, device.DeviceName); // The GDI device name. Not the actual device name.
copyToStringArray(pIdentifier->Driver, driver); // This is the driver's dll.
pIdentifier->DeviceIdentifier = guid;
pIdentifier->DeviceId = deviceId;
pIdentifier->VendorId = vendorId;
pIdentifier->Revision = 0;
pIdentifier->SubSysId = 0;
pIdentifier->WHQLLevel = m_parent->IsExtended() ? 1 : 0; // This doesn't check with the driver on Direct3D9Ex and is always 1.
pIdentifier->DriverVersion.QuadPart = INT64_MAX;
return D3D_OK;
}
HRESULT D3D9Adapter::CheckDeviceType(
D3DDEVTYPE DevType,
D3D9Format AdapterFormat,
D3D9Format BackBufferFormat,
BOOL bWindowed) {
if (!IsSupportedAdapterFormat(AdapterFormat))
return D3DERR_NOTAVAILABLE;
if (!IsSupportedBackBufferFormat(AdapterFormat, BackBufferFormat, bWindowed))
return D3DERR_NOTAVAILABLE;
return D3D_OK;
}
HRESULT D3D9Adapter::CheckDeviceFormat(
D3DDEVTYPE DeviceType,
D3D9Format AdapterFormat,
DWORD Usage,
D3DRESOURCETYPE RType,
D3D9Format CheckFormat) {
if (!IsSupportedAdapterFormat(AdapterFormat))
return D3DERR_NOTAVAILABLE;
const bool dmap = Usage & D3DUSAGE_DMAP;
const bool rt = Usage & D3DUSAGE_RENDERTARGET;
const bool ds = Usage & D3DUSAGE_DEPTHSTENCIL;
const bool surface = RType == D3DRTYPE_SURFACE;
const bool texture = RType == D3DRTYPE_TEXTURE;
const bool twoDimensional = surface || texture;
const bool srgb = (Usage & (D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE)) != 0;
if (CheckFormat == D3D9Format::INST)
return D3D_OK;
if (rt && CheckFormat == D3D9Format::A8 && m_parent->GetOptions().disableA8RT)
return D3DERR_NOTAVAILABLE;
if (ds && !IsDepthFormat(CheckFormat))
return D3DERR_NOTAVAILABLE;
if (rt && CheckFormat == D3D9Format::NULL_FORMAT && twoDimensional)
return D3D_OK;
if (rt && CheckFormat == D3D9Format::RESZ && surface)
return D3D_OK;
if (CheckFormat == D3D9Format::ATOC && surface)
return D3D_OK;
if (CheckFormat == D3D9Format::NVDB && surface)
return m_adapter->features().core.features.depthBounds
? D3D_OK
: D3DERR_NOTAVAILABLE;
// I really don't want to support this...
if (dmap)
return D3DERR_NOTAVAILABLE;
auto mapping = m_d3d9Formats.GetFormatMapping(CheckFormat);
if (mapping.FormatColor == VK_FORMAT_UNDEFINED)
return D3DERR_NOTAVAILABLE;
if (mapping.FormatSrgb == VK_FORMAT_UNDEFINED && srgb)
return D3DERR_NOTAVAILABLE;
if (RType == D3DRTYPE_VERTEXBUFFER || RType == D3DRTYPE_INDEXBUFFER)
return D3D_OK;
// Let's actually ask Vulkan now that we got some quirks out the way!
return CheckDeviceVkFormat(mapping.FormatColor, Usage, RType);
}
HRESULT D3D9Adapter::CheckDeviceMultiSampleType(
D3DDEVTYPE DeviceType,
D3D9Format SurfaceFormat,
BOOL Windowed,
D3DMULTISAMPLE_TYPE MultiSampleType,
DWORD* pQualityLevels) {
if (pQualityLevels != nullptr)
*pQualityLevels = 1;
auto dst = ConvertFormatUnfixed(SurfaceFormat);
if (dst.FormatColor == VK_FORMAT_UNDEFINED)
return D3DERR_NOTAVAILABLE;
if (MultiSampleType != D3DMULTISAMPLE_NONE
&& (SurfaceFormat == D3D9Format::D32_LOCKABLE
|| SurfaceFormat == D3D9Format::D32F_LOCKABLE
|| SurfaceFormat == D3D9Format::D16_LOCKABLE))
return D3DERR_NOTAVAILABLE;
uint32_t sampleCount = std::max<uint32_t>(MultiSampleType, 1u);
// Check if this is a power of two...
if (sampleCount & (sampleCount - 1))
return D3DERR_NOTAVAILABLE;
// Therefore...
VkSampleCountFlags sampleFlags = VkSampleCountFlags(sampleCount);
auto availableFlags = m_adapter->deviceProperties().limits.framebufferColorSampleCounts
& m_adapter->deviceProperties().limits.framebufferDepthSampleCounts;
if (!(availableFlags & sampleFlags))
return D3DERR_NOTAVAILABLE;
if (pQualityLevels != nullptr) {
if (MultiSampleType == D3DMULTISAMPLE_NONMASKABLE)
*pQualityLevels = 32 - bit::lzcnt(availableFlags);
else
*pQualityLevels = 1;
}
return D3D_OK;
}
HRESULT D3D9Adapter::CheckDepthStencilMatch(
D3DDEVTYPE DeviceType,
D3D9Format AdapterFormat,
D3D9Format RenderTargetFormat,
D3D9Format DepthStencilFormat) {
if (!IsDepthFormat(DepthStencilFormat))
return D3DERR_NOTAVAILABLE;
if (RenderTargetFormat == dxvk::D3D9Format::NULL_FORMAT)
return D3D_OK;
auto mapping = ConvertFormatUnfixed(RenderTargetFormat);
if (mapping.FormatColor == VK_FORMAT_UNDEFINED)
return D3DERR_NOTAVAILABLE;
return D3D_OK;
}
HRESULT D3D9Adapter::CheckDeviceFormatConversion(
D3DDEVTYPE DeviceType,
D3D9Format SourceFormat,
D3D9Format TargetFormat) {
bool sourceSupported = SourceFormat != D3D9Format::Unknown
&& IsSupportedBackBufferFormat(SourceFormat);
bool targetSupported = TargetFormat == D3D9Format::X1R5G5B5
|| TargetFormat == D3D9Format::A1R5G5B5
|| TargetFormat == D3D9Format::R5G6B5
// || TargetFormat == D3D9Format::R8G8B8 <-- We don't support R8G8B8
|| TargetFormat == D3D9Format::X8R8G8B8
|| TargetFormat == D3D9Format::A8R8G8B8
|| TargetFormat == D3D9Format::A2R10G10B10
|| TargetFormat == D3D9Format::A16B16G16R16
|| TargetFormat == D3D9Format::A2B10G10R10
|| TargetFormat == D3D9Format::A8B8G8R8
|| TargetFormat == D3D9Format::X8B8G8R8
|| TargetFormat == D3D9Format::A16B16G16R16F
|| TargetFormat == D3D9Format::A32B32G32R32F;
return (sourceSupported && targetSupported)
? D3D_OK
: D3DERR_NOTAVAILABLE;
}
HRESULT D3D9Adapter::GetDeviceCaps(
D3DDEVTYPE DeviceType,
D3DCAPS9* pCaps) {
using namespace dxvk::caps;
if (pCaps == nullptr)
return D3DERR_INVALIDCALL;
auto& options = m_parent->GetOptions();
// TODO: Actually care about what the adapter supports here.
// ^ For Intel and older cards most likely here.
// Device Type
pCaps->DeviceType = DeviceType;
// Adapter Id
pCaps->AdapterOrdinal = m_ordinal;
// Caps 1
pCaps->Caps = D3DCAPS_READ_SCANLINE;
// Caps 2
pCaps->Caps2 = D3DCAPS2_FULLSCREENGAMMA
/* | D3DCAPS2_CANCALIBRATEGAMMA */
/* | D3DCAPS2_RESERVED */
/* | D3DCAPS2_CANMANAGERESOURCE */
| D3DCAPS2_DYNAMICTEXTURES
| D3DCAPS2_CANAUTOGENMIPMAP
/* | D3DCAPS2_CANSHARERESOURCE */;
// Caps 3
pCaps->Caps3 = D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD
| D3DCAPS3_LINEAR_TO_SRGB_PRESENTATION
| D3DCAPS3_COPY_TO_VIDMEM
| D3DCAPS3_COPY_TO_SYSTEMMEM
/* | D3DCAPS3_DXVAHD */
/* | D3DCAPS3_DXVAHD_LIMITED */;
// Presentation Intervals
pCaps->PresentationIntervals = D3DPRESENT_INTERVAL_DEFAULT
| D3DPRESENT_INTERVAL_ONE
| D3DPRESENT_INTERVAL_TWO
| D3DPRESENT_INTERVAL_THREE
| D3DPRESENT_INTERVAL_FOUR
| D3DPRESENT_INTERVAL_IMMEDIATE;
// Cursor
pCaps->CursorCaps = D3DCURSORCAPS_COLOR; // I do not support Cursor yet, but I don't want to say I don't support it for compatibility reasons.
// Dev Caps
pCaps->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 */;
// Primitive Misc. Caps
pCaps->PrimitiveMiscCaps = D3DPMISCCAPS_MASKZ
| D3DPMISCCAPS_CULLNONE
| D3DPMISCCAPS_CULLCW
| D3DPMISCCAPS_CULLCCW
| D3DPMISCCAPS_COLORWRITEENABLE
| D3DPMISCCAPS_CLIPPLANESCALEDPOINTS
| D3DPMISCCAPS_CLIPTLVERTS
| D3DPMISCCAPS_TSSARGTEMP
| D3DPMISCCAPS_BLENDOP
/* | D3DPMISCCAPS_NULLREFERENCE */
| D3DPMISCCAPS_INDEPENDENTWRITEMASKS
| D3DPMISCCAPS_PERSTAGECONSTANT
| D3DPMISCCAPS_FOGANDSPECULARALPHA
| D3DPMISCCAPS_SEPARATEALPHABLEND
| D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS
| D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING
| D3DPMISCCAPS_FOGVERTEXCLAMPED
| D3DPMISCCAPS_POSTBLENDSRGBCONVERT;
// Raster Caps
pCaps->RasterCaps = D3DPRASTERCAPS_DITHER
| D3DPRASTERCAPS_ZTEST
| D3DPRASTERCAPS_FOGVERTEX
| D3DPRASTERCAPS_FOGTABLE
| D3DPRASTERCAPS_MIPMAPLODBIAS
/* | D3DPRASTERCAPS_ZBUFFERLESSHSR */
| D3DPRASTERCAPS_FOGRANGE
| D3DPRASTERCAPS_ANISOTROPY
/* | D3DPRASTERCAPS_WBUFFER */
| D3DPRASTERCAPS_WFOG
| D3DPRASTERCAPS_ZFOG
| D3DPRASTERCAPS_COLORPERSPECTIVE
| D3DPRASTERCAPS_SCISSORTEST
| D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS
| D3DPRASTERCAPS_DEPTHBIAS
| D3DPRASTERCAPS_MULTISAMPLE_TOGGLE; // <-- TODO! (but difficult in Vk)
// Z Comparison Caps
pCaps->ZCmpCaps = D3DPCMPCAPS_NEVER
| D3DPCMPCAPS_LESS
| D3DPCMPCAPS_EQUAL
| D3DPCMPCAPS_LESSEQUAL
| D3DPCMPCAPS_GREATER
| D3DPCMPCAPS_NOTEQUAL
| D3DPCMPCAPS_GREATEREQUAL
| D3DPCMPCAPS_ALWAYS;
// Source Blend Caps
pCaps->SrcBlendCaps = D3DPBLENDCAPS_ZERO
| D3DPBLENDCAPS_ONE
| D3DPBLENDCAPS_SRCCOLOR
| D3DPBLENDCAPS_INVSRCCOLOR
| D3DPBLENDCAPS_SRCALPHA
| D3DPBLENDCAPS_INVSRCALPHA
| D3DPBLENDCAPS_DESTALPHA
| D3DPBLENDCAPS_INVDESTALPHA
| D3DPBLENDCAPS_DESTCOLOR
| D3DPBLENDCAPS_INVDESTCOLOR
| D3DPBLENDCAPS_SRCALPHASAT
| D3DPBLENDCAPS_BOTHSRCALPHA
| D3DPBLENDCAPS_BOTHINVSRCALPHA
| D3DPBLENDCAPS_BLENDFACTOR
| D3DPBLENDCAPS_INVSRCCOLOR2
| D3DPBLENDCAPS_SRCCOLOR2;
// Destination Blend Caps
pCaps->DestBlendCaps = pCaps->SrcBlendCaps;
// Alpha Comparison Caps
pCaps->AlphaCmpCaps = pCaps->ZCmpCaps;
// Shade Caps
pCaps->ShadeCaps = D3DPSHADECAPS_COLORGOURAUDRGB
| D3DPSHADECAPS_SPECULARGOURAUDRGB
| D3DPSHADECAPS_ALPHAGOURAUDBLEND
| D3DPSHADECAPS_FOGGOURAUD;
// Texture Caps
pCaps->TextureCaps = D3DPTEXTURECAPS_PERSPECTIVE
/* | D3DPTEXTURECAPS_POW2 */
| D3DPTEXTURECAPS_ALPHA
/* | D3DPTEXTURECAPS_SQUAREONLY */
| D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE
| D3DPTEXTURECAPS_ALPHAPALETTE
/* | D3DPTEXTURECAPS_NONPOW2CONDITIONAL */
| D3DPTEXTURECAPS_PROJECTED
| D3DPTEXTURECAPS_CUBEMAP
| D3DPTEXTURECAPS_VOLUMEMAP
| D3DPTEXTURECAPS_MIPMAP
| D3DPTEXTURECAPS_MIPVOLUMEMAP
| D3DPTEXTURECAPS_MIPCUBEMAP
/* | D3DPTEXTURECAPS_CUBEMAP_POW2 */
/* | D3DPTEXTURECAPS_VOLUMEMAP_POW2 */
/* | D3DPTEXTURECAPS_NOPROJECTEDBUMPENV */;
// Texture Filter Caps
pCaps->TextureFilterCaps = D3DPTFILTERCAPS_MINFPOINT
| D3DPTFILTERCAPS_MINFLINEAR
| D3DPTFILTERCAPS_MINFANISOTROPIC
/* | D3DPTFILTERCAPS_MINFPYRAMIDALQUAD */
/* | D3DPTFILTERCAPS_MINFGAUSSIANQUAD */
| D3DPTFILTERCAPS_MIPFPOINT
| D3DPTFILTERCAPS_MIPFLINEAR
/* | D3DPTFILTERCAPS_CONVOLUTIONMONO */
| D3DPTFILTERCAPS_MAGFPOINT
| D3DPTFILTERCAPS_MAGFLINEAR
| D3DPTFILTERCAPS_MAGFANISOTROPIC
/* | D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD */
/* | D3DPTFILTERCAPS_MAGFGAUSSIANQUAD */;
// Cube Texture Filter Caps
pCaps->CubeTextureFilterCaps = pCaps->TextureFilterCaps;
// Volume Texture Filter Caps
pCaps->VolumeTextureFilterCaps = pCaps->TextureFilterCaps;
// Texture Address Caps
pCaps->TextureAddressCaps = D3DPTADDRESSCAPS_WRAP
| D3DPTADDRESSCAPS_MIRROR
| D3DPTADDRESSCAPS_CLAMP
| D3DPTADDRESSCAPS_BORDER
| D3DPTADDRESSCAPS_INDEPENDENTUV
| D3DPTADDRESSCAPS_MIRRORONCE;
// Volume Texture Address Caps
pCaps->VolumeTextureAddressCaps = pCaps->TextureAddressCaps;
// Line Caps
pCaps->LineCaps = D3DLINECAPS_TEXTURE
| D3DLINECAPS_ZTEST
| D3DLINECAPS_BLEND
| D3DLINECAPS_ALPHACMP
| D3DLINECAPS_FOG
| D3DLINECAPS_ANTIALIAS; //<-- Lying about doing AA lines here, we don't *fully* support that.
// Max Texture Width
pCaps->MaxTextureWidth = MaxTextureDimension;
// Max Texture Height
pCaps->MaxTextureHeight = MaxTextureDimension;
// Max Volume Extent
pCaps->MaxVolumeExtent = 8192;
// Max Texture Repeat
pCaps->MaxTextureRepeat = 8192;
// Max Texture Aspect Ratio
pCaps->MaxTextureAspectRatio = 8192;
// Max Anisotropy
pCaps->MaxAnisotropy = 16;
// Max Vertex W
pCaps->MaxVertexW = 1e10f;
// Guard Bands
pCaps->GuardBandLeft = -32768.0f;
pCaps->GuardBandTop = -32768.0f;
pCaps->GuardBandRight = 32768.0f;
pCaps->GuardBandBottom = 32768.0f;
// Extents Adjust
pCaps->ExtentsAdjust = 0.0f;
// Stencil Caps
pCaps->StencilCaps = D3DSTENCILCAPS_KEEP
| D3DSTENCILCAPS_ZERO
| D3DSTENCILCAPS_REPLACE
| D3DSTENCILCAPS_INCRSAT
| D3DSTENCILCAPS_DECRSAT
| D3DSTENCILCAPS_INVERT
| D3DSTENCILCAPS_INCR
| D3DSTENCILCAPS_DECR
| D3DSTENCILCAPS_TWOSIDED;
// FVF Caps
pCaps->FVFCaps = (MaxSimultaneousTextures & D3DFVFCAPS_TEXCOORDCOUNTMASK)
/* | D3DFVFCAPS_DONOTSTRIPELEMENTS */
| D3DFVFCAPS_PSIZE;
// Texture Op Caps
pCaps->TextureOpCaps = D3DTEXOPCAPS_DISABLE
| D3DTEXOPCAPS_SELECTARG1
| D3DTEXOPCAPS_SELECTARG2
| D3DTEXOPCAPS_MODULATE
| D3DTEXOPCAPS_MODULATE2X
| D3DTEXOPCAPS_MODULATE4X
| D3DTEXOPCAPS_ADD
| D3DTEXOPCAPS_ADDSIGNED
| D3DTEXOPCAPS_ADDSIGNED2X
| D3DTEXOPCAPS_SUBTRACT
| D3DTEXOPCAPS_ADDSMOOTH
| D3DTEXOPCAPS_BLENDDIFFUSEALPHA
| D3DTEXOPCAPS_BLENDTEXTUREALPHA
| D3DTEXOPCAPS_BLENDFACTORALPHA
| D3DTEXOPCAPS_BLENDTEXTUREALPHAPM
| D3DTEXOPCAPS_BLENDCURRENTALPHA
| D3DTEXOPCAPS_PREMODULATE
| D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR
| D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA
| D3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR
| D3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA
| D3DTEXOPCAPS_BUMPENVMAP
| D3DTEXOPCAPS_BUMPENVMAPLUMINANCE
| D3DTEXOPCAPS_DOTPRODUCT3
| D3DTEXOPCAPS_MULTIPLYADD
| D3DTEXOPCAPS_LERP;
// Max Texture Blend Stages
pCaps->MaxTextureBlendStages = MaxTextureBlendStages;
// Max Simultaneous Textures
pCaps->MaxSimultaneousTextures = MaxSimultaneousTextures;
// Vertex Processing Caps
pCaps->VertexProcessingCaps = D3DVTXPCAPS_TEXGEN
| D3DVTXPCAPS_MATERIALSOURCE7
| D3DVTXPCAPS_DIRECTIONALLIGHTS
| D3DVTXPCAPS_POSITIONALLIGHTS
| D3DVTXPCAPS_LOCALVIEWER
| D3DVTXPCAPS_TWEENING
| D3DVTXPCAPS_TEXGEN_SPHEREMAP
/* | D3DVTXPCAPS_NO_TEXGEN_NONLOCALVIEWER*/;
// Max Active Lights
pCaps->MaxActiveLights = caps::MaxEnabledLights;
// Max User Clip Planes
pCaps->MaxUserClipPlanes = MaxClipPlanes;
// Max Vertex Blend Matrices
pCaps->MaxVertexBlendMatrices = 4;
// Max Vertex Blend Matrix Index
pCaps->MaxVertexBlendMatrixIndex = 8;
// Max Point Size
pCaps->MaxPointSize = 256.0f;
// Max Primitive Count
pCaps->MaxPrimitiveCount = 0x00555555;
// Max Vertex Index
pCaps->MaxVertexIndex = 0x00ffffff;
// Max Streams
pCaps->MaxStreams = MaxStreams;
// Max Stream Stride
pCaps->MaxStreamStride = 508; // bytes
const uint32_t majorVersion = options.shaderModel;
const uint32_t minorVersion = options.shaderModel != 1 ? 0 : 4;
// Shader Versions
pCaps->VertexShaderVersion = D3DVS_VERSION(majorVersion, minorVersion);
pCaps->PixelShaderVersion = D3DPS_VERSION(majorVersion, minorVersion);
// Max Vertex Shader Const
pCaps->MaxVertexShaderConst = MaxFloatConstantsVS;
// Max PS1 Value
pCaps->PixelShader1xMaxValue = FLT_MAX;
// Dev Caps 2
pCaps->DevCaps2 = D3DDEVCAPS2_STREAMOFFSET
/* | D3DDEVCAPS2_DMAPNPATCH */
/* | D3DDEVCAPS2_ADAPTIVETESSRTPATCH */
/* | D3DDEVCAPS2_ADAPTIVETESSNPATCH */
| D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES
/* | D3DDEVCAPS2_PRESAMPLEDDMAPNPATCH */
| D3DDEVCAPS2_VERTEXELEMENTSCANSHARESTREAMOFFSET;
// Max N Patch Tesselation Level
pCaps->MaxNpatchTessellationLevel = 0.0f;
// Reserved for... something
pCaps->Reserved5 = 0;
// Master adapter for us is adapter 0, atm...
pCaps->MasterAdapterOrdinal = 0;
// The group of adapters this one is in
pCaps->AdapterOrdinalInGroup = 0;
// Number of adapters in current group
pCaps->NumberOfAdaptersInGroup = 1;
// Decl Type Caps
pCaps->DeclTypes = D3DDTCAPS_UBYTE4
| D3DDTCAPS_UBYTE4N
| D3DDTCAPS_SHORT2N
| D3DDTCAPS_SHORT4N
| D3DDTCAPS_USHORT2N
| D3DDTCAPS_USHORT4N
| D3DDTCAPS_UDEC3
| D3DDTCAPS_DEC3N
| D3DDTCAPS_FLOAT16_2
| D3DDTCAPS_FLOAT16_4;
// Number of simultaneous RTs
pCaps->NumSimultaneousRTs = MaxSimultaneousRenderTargets;
// Possible StretchRect filters
pCaps->StretchRectFilterCaps = D3DPTFILTERCAPS_MINFPOINT
| D3DPTFILTERCAPS_MINFLINEAR
/* | D3DPTFILTERCAPS_MINFANISOTROPIC */
/* | D3DPTFILTERCAPS_MINFPYRAMIDALQUAD */
/* | D3DPTFILTERCAPS_MINFGAUSSIANQUAD */
/* | D3DPTFILTERCAPS_MIPFPOINT */
/* | D3DPTFILTERCAPS_MIPFLINEAR */
/* | D3DPTFILTERCAPS_CONVOLUTIONMONO */
| D3DPTFILTERCAPS_MAGFPOINT
| D3DPTFILTERCAPS_MAGFLINEAR
/* | D3DPTFILTERCAPS_MAGFANISOTROPIC */
/* | D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD */
/* | D3DPTFILTERCAPS_MAGFGAUSSIANQUAD */;
// Not too bothered about doing these longhand
// We should match whatever my AMD hardware reports here
// methinks for the best chance of stuff working.
pCaps->VS20Caps.Caps = 1;
pCaps->VS20Caps.DynamicFlowControlDepth = 24;
pCaps->VS20Caps.NumTemps = 32;
pCaps->VS20Caps.StaticFlowControlDepth = 4;
pCaps->PS20Caps.Caps = 31;
pCaps->PS20Caps.DynamicFlowControlDepth = 24;
pCaps->PS20Caps.NumTemps = 32;
pCaps->PS20Caps.StaticFlowControlDepth = 4;
pCaps->PS20Caps.NumInstructionSlots = options.shaderModel >= 2 ? 512 : 256;
pCaps->VertexTextureFilterCaps = 50332416;
pCaps->MaxVShaderInstructionsExecuted = 4294967295;
pCaps->MaxPShaderInstructionsExecuted = 4294967295;
pCaps->MaxVertexShader30InstructionSlots = options.shaderModel == 3 ? 32768 : 0;
pCaps->MaxPixelShader30InstructionSlots = options.shaderModel == 3 ? 32768 : 0;
return D3D_OK;
}
HMONITOR D3D9Adapter::GetMonitor() {
return GetDefaultMonitor();
}
UINT D3D9Adapter::GetAdapterModeCountEx(const D3DDISPLAYMODEFILTER* pFilter) {
if (pFilter == nullptr)
return 0;
// We don't offer any interlaced formats here so early out and avoid destroying mode cache.
if (pFilter->ScanLineOrdering == D3DSCANLINEORDERING_INTERLACED)
return 0;
CacheModes(EnumerateFormat(pFilter->Format));
return m_modes.size();
}
HRESULT D3D9Adapter::EnumAdapterModesEx(
const D3DDISPLAYMODEFILTER* pFilter,
UINT Mode,
D3DDISPLAYMODEEX* pMode) {
if (pMode == nullptr || pFilter == nullptr)
return D3DERR_INVALIDCALL;
const D3D9Format format =
EnumerateFormat(pFilter->Format);
if (FAILED(CheckDeviceFormat(
D3DDEVTYPE_HAL, EnumerateFormat(pFilter->Format),
D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE,
EnumerateFormat(pFilter->Format))))
return D3DERR_INVALIDCALL;
CacheModes(format);
// We don't return any scanline orderings that aren't progressive,
// The format filtering is already handled for us by cache modes
// So we can early out here and then just index.
if (pFilter->ScanLineOrdering == D3DSCANLINEORDERING_INTERLACED)
return D3DERR_INVALIDCALL;
if (Mode >= m_modes.size())
return D3DERR_INVALIDCALL;
*pMode = m_modes[Mode];
return D3D_OK;
}
HRESULT D3D9Adapter::GetAdapterDisplayModeEx(
D3DDISPLAYMODEEX* pMode,
D3DDISPLAYROTATION* pRotation) {
if (pMode == nullptr)
return D3DERR_INVALIDCALL;
if (pRotation != nullptr)
*pRotation = D3DDISPLAYROTATION_IDENTITY;
DEVMODEW devMode = DEVMODEW();
devMode.dmSize = sizeof(devMode);
if (!GetMonitorDisplayMode(GetDefaultMonitor(), ENUM_CURRENT_SETTINGS, &devMode)) {
Logger::err("D3D9Adapter::GetAdapterDisplayModeEx: Failed to enum display settings");
return D3DERR_INVALIDCALL;
}
pMode->Size = sizeof(D3DDISPLAYMODEEX);
pMode->Width = devMode.dmPelsWidth;
pMode->Height = devMode.dmPelsHeight;
pMode->RefreshRate = devMode.dmDisplayFrequency;
pMode->Format = D3DFMT_X8R8G8B8;
pMode->ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE;
return D3D_OK;
}
HRESULT D3D9Adapter::GetAdapterLUID(LUID* pLUID) {
if (pLUID == nullptr)
return D3DERR_INVALIDCALL;
auto& deviceId = m_adapter->devicePropertiesExt().coreDeviceId;
if (deviceId.deviceLUIDValid)
*pLUID = bit::cast<LUID>(deviceId.deviceLUID);
else
*pLUID = dxvk::GetAdapterLUID(m_ordinal);
return D3D_OK;
}
HRESULT D3D9Adapter::CheckDeviceVkFormat(
VkFormat Format,
DWORD Usage,
D3DRESOURCETYPE RType) {
VkFormatFeatureFlags checkFlags = 0;
if (RType != D3DRTYPE_SURFACE)
checkFlags |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
if (Usage & D3DUSAGE_RENDERTARGET) {
checkFlags |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
if (Usage & D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING)
checkFlags |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT;
}
if (Usage & D3DUSAGE_DEPTHSTENCIL)
checkFlags |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
else
checkFlags |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
VkFormatFeatureFlags checkFlagsMipGen = checkFlags;
if (Usage & D3DUSAGE_AUTOGENMIPMAP) {
checkFlagsMipGen |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
checkFlagsMipGen |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
}
VkFormatProperties fmtSupport = m_adapter->formatProperties(Format);
VkFormatFeatureFlags imgFeatures = fmtSupport.optimalTilingFeatures | fmtSupport.linearTilingFeatures;
if ((imgFeatures & checkFlags) != checkFlags)
return D3DERR_NOTAVAILABLE;
return ((imgFeatures & checkFlagsMipGen) != checkFlagsMipGen)
? D3DOK_NOAUTOGEN
: D3D_OK;
}
void D3D9Adapter::CacheModes(D3D9Format Format) {
if (!m_modes.empty() && m_modeCacheFormat == Format)
return; // We already cached the modes for this format. No need to do it again.
m_modes.clear();
m_modeCacheFormat = Format;
// Skip unsupported formats
if (!IsSupportedAdapterFormat(Format))
return;
auto& options = m_parent->GetOptions();
// Walk over all modes that the display supports and
// return those that match the requested format etc.
DEVMODEW devMode = { };
devMode.dmSize = sizeof(DEVMODEW);
uint32_t modeIndex = 0;
const auto forcedRatio = Ratio<DWORD>(options.forceAspectRatio);
while (GetMonitorDisplayMode(GetDefaultMonitor(), modeIndex++, &devMode)) {
// Skip interlaced modes altogether
if (devMode.dmDisplayFlags & DM_INTERLACED)
continue;
// Skip modes with incompatible formats
if (devMode.dmBitsPerPel != GetMonitorFormatBpp(Format))
continue;
if (!forcedRatio.undefined() && Ratio<DWORD>(devMode.dmPelsWidth, devMode.dmPelsHeight) != forcedRatio)
continue;
D3DDISPLAYMODEEX mode;
mode.Size = sizeof(D3DDISPLAYMODEEX);
mode.Width = devMode.dmPelsWidth;
mode.Height = devMode.dmPelsHeight;
mode.RefreshRate = devMode.dmDisplayFrequency;
mode.Format = static_cast<D3DFORMAT>(Format);
mode.ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE;
m_modes.push_back(mode);
}
// Sort display modes by width, height and refresh rate,
// in that order. Some games rely on correct ordering.
std::sort(m_modes.begin(), m_modes.end(),
[](const D3DDISPLAYMODEEX& a, const D3DDISPLAYMODEEX& b) {
if (a.Width < b.Width) return true;
if (a.Width > b.Width) return false;
if (a.Height < b.Height) return true;
if (a.Height > b.Height) return false;
return a.RefreshRate < b.RefreshRate;
});
}
}