Skip to content

Commit

Permalink
[d3d8/9] Proper (and age accurate) handling of d3d9.shaderModel = 0
Browse files Browse the repository at this point in the history
WinterSnowfall authored and K0bin committed Jan 26, 2025
1 parent 48d2489 commit c6dc7e0
Showing 13 changed files with 63 additions and 27 deletions.
1 change: 1 addition & 0 deletions dxvk.conf
Original file line number Diff line number Diff line change
@@ -464,6 +464,7 @@
# capabilities that the applicatation queries.
#
# Supported values:
# - 0: Fixed-function only
# - 1: Shader Model 1
# - 2: Shader Model 2
# - 3: Shader Model 3
5 changes: 4 additions & 1 deletion src/d3d8/d3d8_d3d9_util.h
Original file line number Diff line number Diff line change
@@ -19,7 +19,10 @@ namespace dxvk {

// Max supported shader model is PS 1.4 and VS 1.1
pCaps8->VertexShaderVersion = D3DVS_VERSION(1, 1);
pCaps8->PixelShaderVersion = D3DPS_VERSION(1, 4);
// Late fixed-function capable hardware will advertise VS 1.1
// support, but will not advertise any support for PS
if (likely(caps9.PixelShaderVersion != D3DPS_VERSION(0, 0)))
pCaps8->PixelShaderVersion = D3DPS_VERSION(1, 4);

// Remove D3D9-specific caps:

16 changes: 11 additions & 5 deletions src/d3d8/d3d8_device.cpp
Original file line number Diff line number Diff line change
@@ -58,6 +58,12 @@ namespace dxvk {

if (m_d3d8Options.batching)
m_batcher = new D3D8Batcher(this, GetD3D9());

d3d9::D3DCAPS9 caps9;
HRESULT res = GetD3D9()->GetDeviceCaps(&caps9);

if (unlikely(SUCCEEDED(res) && caps9.PixelShaderVersion == D3DPS_VERSION(0, 0)))
m_isFixedFunctionOnly = true;
}

D3D8Device::~D3D8Device() {
@@ -1784,8 +1790,8 @@ namespace dxvk {

// Validate VS version for non-FF shaders
if (pFunction != nullptr) {
uint32_t majorVersion = (pFunction[0] >> 8) & 0xff;
uint32_t minorVersion = pFunction[0] & 0xff;
const uint32_t majorVersion = (pFunction[0] >> 8) & 0xff;
const uint32_t minorVersion = pFunction[0] & 0xff;

if (unlikely(majorVersion != 1 || minorVersion > 1)) {
Logger::err(str::format("D3D8Device::CreateVertexShader: Unsupported VS version ", majorVersion, ".", minorVersion));
@@ -2023,10 +2029,10 @@ namespace dxvk {
if (unlikely(pFunction == nullptr || pHandle == nullptr))
return D3DERR_INVALIDCALL;

uint32_t majorVersion = (pFunction[0] >> 8) & 0xff;
uint32_t minorVersion = pFunction[0] & 0xff;
const uint32_t majorVersion = (pFunction[0] >> 8) & 0xff;
const uint32_t minorVersion = pFunction[0] & 0xff;

if (unlikely(majorVersion != 1 || minorVersion > 4)) {
if (unlikely(m_isFixedFunctionOnly || majorVersion != 1 || minorVersion > 4)) {
Logger::err(str::format("D3D8Device::CreatePixelShader: Unsupported PS version ", majorVersion, ".", minorVersion));
return D3DERR_INVALIDCALL;
}
3 changes: 3 additions & 0 deletions src/d3d8/d3d8_device.h
Original file line number Diff line number Diff line change
@@ -429,6 +429,9 @@ namespace dxvk {
// Value of D3DRS_PATCHSEGMENTS
float m_patchSegments = 1.0f;

// Controls fixed-function exclusive mode (no PS support)
bool m_isFixedFunctionOnly = false;

D3D8StateBlock* m_recorder = nullptr;
DWORD m_recorderToken = 0;
DWORD m_token = 0;
2 changes: 1 addition & 1 deletion src/d3d8/d3d8_interface.cpp
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ namespace dxvk {

// Get the bridge interface to D3D9.
if (FAILED(m_d3d9->QueryInterface(__uuidof(IDxvkD3D8InterfaceBridge), (void**)&m_bridge))) {
throw DxvkError("D3D8Device: ERROR! Failed to get D3D9 Bridge. d3d9.dll might not be DXVK!");
throw DxvkError("D3D8Interface: ERROR! Failed to get D3D9 Bridge. d3d9.dll might not be DXVK!");
}

m_bridge->SetD3D8CompatibilityMode(true);
8 changes: 4 additions & 4 deletions src/d3d8/d3d8_main.cpp
Original file line number Diff line number Diff line change
@@ -26,8 +26,8 @@ extern "C" {
if (unlikely(pPixelShader == nullptr)) {
errorMessage = "D3D8: ValidatePixelShader: Null pPixelShader";
} else {
uint32_t majorVersion = (pPixelShader[0] >> 8) & 0xff;
uint32_t minorVersion = pPixelShader[0] & 0xff;
const uint32_t majorVersion = (pPixelShader[0] >> 8) & 0xff;
const uint32_t minorVersion = pPixelShader[0] & 0xff;

if (unlikely(majorVersion != 1 || minorVersion > 4)) {
errorMessage = dxvk::str::format("D3D8: ValidatePixelShader: Unsupported PS version ",
@@ -69,8 +69,8 @@ extern "C" {
if (unlikely(pVertexShader == nullptr)) {
errorMessage = "D3D8: ValidateVertexShader: Null pVertexShader";
} else {
uint32_t majorVersion = (pVertexShader[0] >> 8) & 0xff;
uint32_t minorVersion = pVertexShader[0] & 0xff;
const uint32_t majorVersion = (pVertexShader[0] >> 8) & 0xff;
const uint32_t minorVersion = pVertexShader[0] & 0xff;

if (unlikely(majorVersion != 1 || minorVersion > 1)) {
errorMessage = dxvk::str::format("D3D8: ValidateVertexShader: Unsupported VS version ",
19 changes: 12 additions & 7 deletions src/d3d9/d3d9_adapter.cpp
Original file line number Diff line number Diff line change
@@ -573,17 +573,22 @@ namespace dxvk {
// Max Stream Stride
pCaps->MaxStreamStride = 508; // bytes

const uint32_t majorVersion = options.shaderModel;
const uint32_t minorVersion = options.shaderModel != 1 ? 0 : 4;
// Late fixed-function capable cards, such as the GeForce 4 MX series,
// expose support for VS 1.1, while not advertising any PS support
const uint32_t majorVersionVS = options.shaderModel == 0 ? 1 : options.shaderModel;
const uint32_t majorVersionPS = options.shaderModel;
// Max supported SM1 is VS 1.1 and PS 1.4
const uint32_t minorVersionVS = majorVersionVS != 1 ? 0 : 1;
const uint32_t minorVersionPS = majorVersionPS != 1 ? 0 : 4;

// Shader Versions
pCaps->VertexShaderVersion = D3DVS_VERSION(majorVersion, minorVersion);
pCaps->PixelShaderVersion = D3DPS_VERSION(majorVersion, minorVersion);
pCaps->VertexShaderVersion = D3DVS_VERSION(majorVersionVS, minorVersionVS);
pCaps->PixelShaderVersion = D3DPS_VERSION(majorVersionPS, minorVersionPS);

// Max Vertex Shader Const
pCaps->MaxVertexShaderConst = MaxFloatConstantsVS;
// Max PS1 Value
pCaps->PixelShader1xMaxValue = FLT_MAX;
pCaps->PixelShader1xMaxValue = options.shaderModel > 0 ? FLT_MAX : 0.0f;
// Dev Caps 2
pCaps->DevCaps2 = D3DDEVCAPS2_STREAMOFFSET
/* | D3DDEVCAPS2_DMAPNPATCH */
@@ -646,8 +651,8 @@ namespace dxvk {
pCaps->PS20Caps.NumInstructionSlots = options.shaderModel >= 2 ? 512 : 256;

pCaps->VertexTextureFilterCaps = 50332416;
pCaps->MaxVShaderInstructionsExecuted = 4294967295;
pCaps->MaxPShaderInstructionsExecuted = 4294967295;
pCaps->MaxVShaderInstructionsExecuted = options.shaderModel >= 2 ? 4294967295 : 0;
pCaps->MaxPShaderInstructionsExecuted = options.shaderModel >= 2 ? 4294967295 : 0;

pCaps->MaxVertexShader30InstructionSlots = options.shaderModel == 3 ? 32768 : 0;
pCaps->MaxPixelShader30InstructionSlots = options.shaderModel == 3 ? 32768 : 0;
23 changes: 23 additions & 0 deletions src/d3d9/d3d9_device.cpp
Original file line number Diff line number Diff line change
@@ -3314,6 +3314,19 @@ namespace dxvk {
if (unlikely(ppShader == nullptr))
return D3DERR_INVALIDCALL;

const uint32_t majorVersion = (pFunction[0] >> 8) & 0xff;
const uint32_t minorVersion = pFunction[0] & 0xff;

// Late fixed-function capable hardware exposed support for VS 1.1
const uint32_t shaderModelVS = m_d3d9Options.shaderModel == 0 ? 1 : m_d3d9Options.shaderModel;

if (unlikely(majorVersion > shaderModelVS
|| (majorVersion == 1 && minorVersion > 1)
|| (majorVersion > 1 && minorVersion != 0))) {
Logger::err(str::format("D3D9DeviceEx::CreateVertexShader: Unsupported VS version ", majorVersion, ".", minorVersion));
return D3DERR_INVALIDCALL;
}

DxsoModuleInfo moduleInfo;
moduleInfo.options = m_dxsoOptions;

@@ -3678,6 +3691,16 @@ namespace dxvk {
if (unlikely(ppShader == nullptr))
return D3DERR_INVALIDCALL;

const uint32_t majorVersion = (pFunction[0] >> 8) & 0xff;
const uint32_t minorVersion = pFunction[0] & 0xff;

if (unlikely(majorVersion > m_d3d9Options.shaderModel
|| (majorVersion == 1 && minorVersion > 4)
|| (majorVersion > 1 && minorVersion != 0))) {
Logger::err(str::format("D3D9DeviceEx::CreatePixelShader: Unsupported PS version ", majorVersion, ".", minorVersion));
return D3DERR_INVALIDCALL;
}

DxsoModuleInfo moduleInfo;
moduleInfo.options = m_dxsoOptions;

3 changes: 3 additions & 0 deletions src/d3d9/d3d9_interface.cpp
Original file line number Diff line number Diff line change
@@ -67,6 +67,9 @@ namespace dxvk {
SetProcessDPIAware();
}
#endif

if (unlikely(m_d3d9Options.shaderModel == 0))
Logger::warn("D3D9InterfaceEx: WARNING! Fixed-function exclusive mode is enabled.");
}


2 changes: 1 addition & 1 deletion src/d3d9/d3d9_options.h
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ namespace dxvk {
int32_t maxFrameRate;

/// Set the max shader model the device can support in the caps.
int32_t shaderModel;
uint32_t shaderModel;

/// Whether or not to set the process as DPI aware in Windows when the API interface is created.
bool dpiAware;
3 changes: 0 additions & 3 deletions src/d3d9/d3d9_shader.cpp
Original file line number Diff line number Diff line change
@@ -98,9 +98,6 @@ namespace dxvk {

DxsoModule module(reader);

if (module.info().majorVersion() > pDxbcModuleInfo->options.shaderModel)
throw DxvkError("GetShaderModule: Out of range of supported shader model");

if (module.info().shaderStage() != ShaderStage)
throw DxvkError("GetShaderModule: Bytecode does not match shader stage");

2 changes: 0 additions & 2 deletions src/dxso/dxso_options.cpp
Original file line number Diff line number Diff line change
@@ -20,8 +20,6 @@ namespace dxvk {
strictPow = options.strictPow;
d3d9FloatEmulation = options.d3d9FloatEmulation;

shaderModel = options.shaderModel;

invariantPosition = options.invariantPosition;

forceSamplerTypeSpecConstants = options.forceSamplerTypeSpecConstants;
3 changes: 0 additions & 3 deletions src/dxso/dxso_options.h
Original file line number Diff line number Diff line change
@@ -25,9 +25,6 @@ namespace dxvk {
/// Whether or not we should care about pow(0, 0) = 1
bool strictPow;

/// Max version of shader to support
uint32_t shaderModel;

/// Work around a NV driver quirk
/// Fixes flickering/z-fighting in some games.
bool invariantPosition;

0 comments on commit c6dc7e0

Please sign in to comment.