1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-14 00:48:44 +01:00
dxvk/src/d3d9/d3d9_adapter.cpp

822 lines
34 KiB
C++
Raw Normal View History

#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)
: m_parent (pParent)
, m_adapter (Adapter)
, m_ordinal (Ordinal)
, m_modeCacheFormat (D3D9Format::Unknown)
, m_d3d9Formats (Adapter, m_parent->GetOptions()) {
m_adapter->logAdapterInfo();
}
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();
::MONITORINFOEXA monInfo;
monInfo.cbSize = sizeof(monInfo);
if (!::GetMonitorInfoA(GetDefaultMonitor(), reinterpret_cast<MONITORINFO*>(&monInfo))) {
Logger::err("D3D9Adapter::GetAdapterIdentifier: Failed to query monitor info");
return D3DERR_INVALIDCALL;
}
GUID guid = bit::cast<GUID>(m_adapter->devicePropertiesExt().coreDeviceId.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));
std::strncpy(pIdentifier->Description, desc, countof(pIdentifier->Description));
std::strncpy(pIdentifier->DeviceName, monInfo.szDevice, countof(pIdentifier->DeviceName)); // The GDI device name. Not the actual device name.
std::strncpy(pIdentifier->Driver, driver, countof(pIdentifier->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 (!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, false))
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 (m_adapter->features().core.features.depthBounds) {
if (CheckFormat == D3D9Format::NVDB && surface)
return D3D_OK;
}
// 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 = !IsDepthFormat(SurfaceFormat)
? 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 (!IsSupportedAdapterFormat(AdapterFormat, false))
return D3DERR_NOTAVAILABLE;
if (!IsDepthFormat(DepthStencilFormat))
return D3DERR_NOTAVAILABLE;
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 = IsSupportedBackBufferFormat(SourceFormat, FALSE);
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;
MONITORINFOEXW monInfo = { };
monInfo.cbSize = sizeof(monInfo);
if (!::GetMonitorInfoW(GetDefaultMonitor(), reinterpret_cast<MONITORINFO*>(&monInfo)))
throw DxvkError("D3D9Adapter::GetAdapterDisplayModeEx: Failed to query monitor info");
DEVMODEW devMode = DEVMODEW();
devMode.dmSize = sizeof(devMode);
if (!::EnumDisplaySettingsW(monInfo.szDevice, 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.
::MONITORINFOEXW monInfo;
monInfo.cbSize = sizeof(monInfo);
if (!::GetMonitorInfoW(GetDefaultMonitor(), reinterpret_cast<MONITORINFO*>(&monInfo))) {
Logger::err("D3D9Adapter::CacheModes: failed to query monitor info");
return;
}
m_modes.clear();
m_modeCacheFormat = Format;
// Skip unsupported formats
if (!IsSupportedAdapterFormat(Format, false))
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 (::EnumDisplaySettingsW(monInfo.szDevice, 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;
});
}
}