Skip to content

Commit

Permalink
[d3d8/9] Properly disable programmable shaders with d3d9.shaderModel
Browse files Browse the repository at this point in the history
  • Loading branch information
WinterSnowfall committed Jan 21, 2025
1 parent c52a68a commit e300bfb
Show file tree
Hide file tree
Showing 10 changed files with 58 additions and 13 deletions.
1 change: 1 addition & 0 deletions dxvk.conf
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@
# capabilities that the applicatation queries.
#
# Supported values:
# - 0: Disables support for programmable shaders
# - 1: Shader Model 1
# - 2: Shader Model 2
# - 3: Shader Model 3
Expand Down
7 changes: 5 additions & 2 deletions src/d3d8/d3d8_d3d9_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ namespace dxvk {
// should be aligned
std::memcpy(pCaps8, &caps9, sizeof(D3DCAPS8));

// Max supported shader model is PS 1.4 and VS 1.1
// 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 advertize VS 1.1
// support, but will not advertize any support for PS.
if (likely(caps9.PixelShaderVersion != D3DPS_VERSION(0, 0)))
pCaps8->PixelShaderVersion = D3DPS_VERSION(1, 4);

// This was removed by D3D9. We can probably render windowed.
pCaps8->Caps2 |= D3DCAPS2_CANRENDERWINDOWED;
Expand Down
11 changes: 10 additions & 1 deletion src/d3d8/d3d8_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ 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.VertexShaderVersion == D3DVS_VERSION(1, 1)
&& caps9.PixelShaderVersion == D3DPS_VERSION(0, 0))) {
m_isD3D7Compatible = true;
}
}

D3D8Device::~D3D8Device() {
Expand Down Expand Up @@ -1940,7 +1949,7 @@ namespace dxvk {
uint32_t majorVersion = (pFunction[0] >> 8) & 0xff;
uint32_t minorVersion = pFunction[0] & 0xff;

if (unlikely(majorVersion != 1 || minorVersion > 4)) {
if (unlikely(m_isD3D7Compatible || majorVersion != 1 || minorVersion > 4)) {
Logger::err(str::format("D3D8Device::CreatePixelShader: Unsupported PS version ", majorVersion, ".", minorVersion));
return D3DERR_INVALIDCALL;
}
Expand Down
3 changes: 3 additions & 0 deletions src/d3d8/d3d8_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,9 @@ namespace dxvk {

D3DPRESENT_PARAMETERS m_presentParams;

// Controls whether we expose programmable shader support
bool m_isD3D7Compatible = false;

D3D8StateBlock* m_recorder = nullptr;
DWORD m_recorderToken = 0;
DWORD m_token = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/d3d8/d3d8_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
20 changes: 13 additions & 7 deletions src/d3d9/d3d9_adapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -573,17 +573,23 @@ namespace dxvk {
// Max Stream Stride
pCaps->MaxStreamStride = 508; // bytes

const uint32_t majorVersion = options.shaderModel;
const uint32_t minorVersion = options.shaderModel != 1 ? 0 : 4;
// Later HW T&L only cards, such as the GeForce 4 MX series, actually
// 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;
// VS 1.1 is supported as part of SM1
const uint32_t minorVersionVS = majorVersionVS != 1 ? 0 : 1;
// PS 1.4 is supported as part of SM1
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 */
Expand Down Expand Up @@ -646,8 +652,8 @@ namespace dxvk {
pCaps->PS20Caps.NumInstructionSlots = options.shaderModel >= 2 ? 512 : 256;

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

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

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

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

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

DxsoModuleInfo moduleInfo;
moduleInfo.options = m_dxsoOptions;

Expand Down Expand Up @@ -3678,6 +3689,14 @@ namespace dxvk {
if (unlikely(ppShader == nullptr))
return D3DERR_INVALIDCALL;

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

if (unlikely(majorVersion > m_d3d9Options.shaderModel)) {
Logger::err(str::format("D3D9DeviceEx::CreatePixelShader: Unsupported PS version ", majorVersion, ".", minorVersion));
return D3DERR_INVALIDCALL;
}

DxsoModuleInfo moduleInfo;
moduleInfo.options = m_dxsoOptions;

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

if (unlikely(m_d3d9Options.shaderModel == 0))
Logger::warn("D3D9InterfaceEx: WARNING! Programmable shader support is disabled.");
}


Expand Down
2 changes: 1 addition & 1 deletion src/d3d9/d3d9_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion src/dxso/dxso_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ namespace dxvk {
strictPow = options.strictPow;
d3d9FloatEmulation = options.d3d9FloatEmulation;

shaderModel = options.shaderModel;
// Late fixed function capable hardware actually exposed support for VS 1.1, while lacking PS support
shaderModel = options.shaderModel == 0 ? 1 : options.shaderModel;

invariantPosition = options.invariantPosition;

Expand Down

0 comments on commit e300bfb

Please sign in to comment.