Skip to content

Commit 235ab61

Browse files
committed
Merge pull request #29 from WinterSnowfall/d3d8-backport
1 parent 8a0ec02 commit 235ab61

10 files changed

Lines changed: 282 additions & 178 deletions

src/d3d8/d3d8_device.cpp

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ namespace dxvk {
4747
, m_behaviorFlags(BehaviorFlags)
4848
, m_multithread(BehaviorFlags & D3DCREATE_MULTITHREADED) {
4949
// Get the bridge interface to D3D9.
50-
if (FAILED(GetD3D9()->QueryInterface(__uuidof(IDxvkD3D8Bridge), reinterpret_cast<void**>(&m_bridge)))) {
50+
if (unlikely(FAILED(GetD3D9()->QueryInterface(__uuidof(IDxvkD3D8Bridge), reinterpret_cast<void**>(&m_bridge))))) {
5151
throw DxvkError("D3D8Device: ERROR! Failed to get D3D9 Bridge. d3d9.dll might not be DXVK!");
5252
}
5353

@@ -1141,31 +1141,34 @@ namespace dxvk {
11411141
HRESULT STDMETHODCALLTYPE D3D8Device::SetViewport(const D3DVIEWPORT8* pViewport) {
11421142
D3D8DeviceLock lock = LockDevice();
11431143

1144-
if (likely(pViewport != nullptr)) {
1145-
// We need a valid render target to validate the viewport
1146-
if (unlikely(m_renderTarget == nullptr))
1147-
return D3DERR_INVALIDCALL;
1144+
// Outright crashes on native, but let's be
1145+
// somewhat more elegant about it.
1146+
if (unlikely(pViewport == nullptr))
1147+
return D3DERR_INVALIDCALL;
11481148

1149-
D3DSURFACE_DESC rtDesc;
1150-
HRESULT res = m_renderTarget->GetDesc(&rtDesc);
1151-
1152-
// D3D8 will fail when setting a viewport that's outside of the
1153-
// current render target, although this apparently works in D3D9
1154-
if (likely(SUCCEEDED(res)) &&
1155-
unlikely(pViewport->X + pViewport->Width > rtDesc.Width ||
1156-
pViewport->Y + pViewport->Height > rtDesc.Height)) {
1157-
// On Linux/Wine and in windowed mode, we can get in situations
1158-
// where the actual render target dimensions are off by one
1159-
// pixel to what the game sets them to. Allow this corner case
1160-
// to skip the validation, in order to prevent issues.
1161-
const bool isOnePixelWider = pViewport->X + pViewport->Width == rtDesc.Width + 1;
1162-
const bool isOnePixelTaller = pViewport->Y + pViewport->Height == rtDesc.Height + 1;
1163-
1164-
if (m_presentParams.Windowed && (isOnePixelWider || isOnePixelTaller)) {
1165-
Logger::debug("D3D8Device::SetViewport: Viewport exceeds render target dimensions by one pixel");
1166-
} else {
1167-
return D3DERR_INVALIDCALL;
1168-
}
1149+
// We need a valid render target to validate the viewport
1150+
if (unlikely(m_renderTarget == nullptr))
1151+
return D3DERR_INVALIDCALL;
1152+
1153+
D3DSURFACE_DESC rtDesc;
1154+
HRESULT res = m_renderTarget->GetDesc(&rtDesc);
1155+
1156+
// D3D8 will fail when setting a viewport that's outside of the
1157+
// current render target, although this apparently works in D3D9
1158+
if (likely(SUCCEEDED(res)) &&
1159+
unlikely(pViewport->X + pViewport->Width > rtDesc.Width ||
1160+
pViewport->Y + pViewport->Height > rtDesc.Height)) {
1161+
// On Linux/Wine and in windowed mode, we can get in situations
1162+
// where the actual render target dimensions are off by one
1163+
// pixel to what the game sets them to. Allow this corner case
1164+
// to skip the validation, in order to prevent issues.
1165+
const bool isOnePixelWider = pViewport->X + pViewport->Width == rtDesc.Width + 1;
1166+
const bool isOnePixelTaller = pViewport->Y + pViewport->Height == rtDesc.Height + 1;
1167+
1168+
if (unlikely(m_presentParams.Windowed && (isOnePixelWider || isOnePixelTaller))) {
1169+
Logger::debug("D3D8Device::SetViewport: Viewport exceeds render target dimensions by one pixel");
1170+
} else {
1171+
return D3DERR_INVALIDCALL;
11691172
}
11701173
}
11711174

@@ -1226,18 +1229,22 @@ namespace dxvk {
12261229
if (unlikely(ShouldRecord()))
12271230
return D3DERR_INVALIDCALL;
12281231

1232+
D3D8StateBlockType stateBlockType = ConvertStateBlockType(Type);
1233+
1234+
if (unlikely(stateBlockType == D3D8StateBlockType::Unknown)) {
1235+
Logger::warn(str::format("D3D8Device::CreateStateBlock: Invalid state block type: ", Type));
1236+
return D3DERR_INVALIDCALL;
1237+
}
1238+
12291239
Com<d3d9::IDirect3DStateBlock9> pStateBlock9;
12301240
HRESULT res = GetD3D9()->CreateStateBlock(d3d9::D3DSTATEBLOCKTYPE(Type), &pStateBlock9);
12311241

12321242
if (likely(SUCCEEDED(res))) {
12331243
m_token++;
1234-
auto stateBlockIterPair = m_stateBlocks.emplace(std::piecewise_construct,
1235-
std::forward_as_tuple(m_token),
1236-
std::forward_as_tuple(this, Type, pStateBlock9.ptr()));
1244+
m_stateBlocks.emplace(std::piecewise_construct,
1245+
std::forward_as_tuple(m_token),
1246+
std::forward_as_tuple(this, stateBlockType, pStateBlock9.ptr()));
12371247
*pToken = m_token;
1238-
1239-
// D3D8 state blocks automatically capture state on creation.
1240-
stateBlockIterPair.first->second.Capture();
12411248
}
12421249

12431250
return res;

src/d3d8/d3d8_interface.cpp

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace dxvk {
1010
D3D8Interface::D3D8Interface()
1111
: m_d3d9(d3d9::Direct3DCreate9(D3D_SDK_VERSION)) {
1212
// Get the bridge interface to D3D9.
13-
if (FAILED(m_d3d9->QueryInterface(__uuidof(IDxvkD3D8InterfaceBridge), reinterpret_cast<void**>(&m_bridge)))) {
13+
if (unlikely(FAILED(m_d3d9->QueryInterface(__uuidof(IDxvkD3D8InterfaceBridge), reinterpret_cast<void**>(&m_bridge))))) {
1414
throw DxvkError("D3D8Interface: ERROR! Failed to get D3D9 Bridge. d3d9.dll might not be DXVK!");
1515
}
1616

@@ -75,21 +75,22 @@ namespace dxvk {
7575
d3d9::D3DADAPTER_IDENTIFIER9 identifier9;
7676
HRESULT res = m_d3d9->GetAdapterIdentifier(Adapter, Flags, &identifier9);
7777

78-
if (likely(SUCCEEDED(res))) {
79-
strncpy(pIdentifier->Driver, identifier9.Driver, MAX_DEVICE_IDENTIFIER_STRING);
80-
strncpy(pIdentifier->Description, identifier9.Description, MAX_DEVICE_IDENTIFIER_STRING);
78+
if (unlikely(FAILED(res)))
79+
return res;
8180

82-
pIdentifier->DriverVersion = identifier9.DriverVersion;
83-
pIdentifier->VendorId = identifier9.VendorId;
84-
pIdentifier->DeviceId = identifier9.DeviceId;
85-
pIdentifier->SubSysId = identifier9.SubSysId;
86-
pIdentifier->Revision = identifier9.Revision;
87-
pIdentifier->DeviceIdentifier = identifier9.DeviceIdentifier;
81+
strncpy(pIdentifier->Driver, identifier9.Driver, MAX_DEVICE_IDENTIFIER_STRING);
82+
strncpy(pIdentifier->Description, identifier9.Description, MAX_DEVICE_IDENTIFIER_STRING);
8883

89-
pIdentifier->WHQLLevel = identifier9.WHQLLevel;
90-
}
84+
pIdentifier->DriverVersion = identifier9.DriverVersion;
85+
pIdentifier->VendorId = identifier9.VendorId;
86+
pIdentifier->DeviceId = identifier9.DeviceId;
87+
pIdentifier->SubSysId = identifier9.SubSysId;
88+
pIdentifier->Revision = identifier9.Revision;
89+
pIdentifier->DeviceIdentifier = identifier9.DeviceIdentifier;
9190

92-
return res;
91+
pIdentifier->WHQLLevel = identifier9.WHQLLevel;
92+
93+
return D3D_OK;
9394
}
9495

9596
HRESULT __stdcall D3D8Interface::EnumAdapterModes(
@@ -136,14 +137,21 @@ namespace dxvk {
136137
&pDevice9
137138
);
138139

139-
if (likely(SUCCEEDED(res)))
140+
if (unlikely(FAILED(res)))
141+
return res;
142+
143+
try {
140144
*ppReturnedDeviceInterface = ref(new D3D8Device(
141145
this, std::move(pDevice9),
142146
DeviceType, hFocusWindow, BehaviorFlags,
143147
pPresentationParameters
144148
));
149+
} catch (const DxvkError& e) {
150+
Logger::err(e.message());
151+
return D3DERR_NOTAVAILABLE;
152+
}
145153

146-
return res;
154+
return D3D_OK;
147155
}
148156

149157
HRESULT D3D8Interface::ValidatePresentationParameters(

src/d3d8/d3d8_main.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,14 @@ namespace dxvk {
88
if (!ppDirect3D8)
99
return D3DERR_INVALIDCALL;
1010

11-
*ppDirect3D8 = ref(new D3D8Interface());
11+
try {
12+
*ppDirect3D8 = ref(new D3D8Interface());
13+
} catch (const DxvkError& e) {
14+
Logger::err(e.message());
15+
*ppDirect3D8 = nullptr;
16+
return D3DERR_NOTAVAILABLE;
17+
}
18+
1219
return D3D_OK;
1320
}
1421

src/d3d8/d3d8_state_block.cpp

Lines changed: 67 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,43 @@ namespace dxvk {
55

66
D3D8StateBlock::D3D8StateBlock(
77
D3D8Device* pDevice,
8-
D3DSTATEBLOCKTYPE Type,
8+
D3D8StateBlockType Type,
99
Com<d3d9::IDirect3DStateBlock9>&& pStateBlock)
1010
: m_device(pDevice)
11-
, m_stateBlock(std::move(pStateBlock))
12-
, m_type(Type)
13-
, m_isSWVP(pDevice->GetD3D9()->GetSoftwareVertexProcessing()) {
14-
if (Type == D3DSBT_VERTEXSTATE || Type == D3DSBT_ALL) {
11+
, m_stateBlock(std::move(pStateBlock)) {
12+
if (Type == D3D8StateBlockType::All) {
13+
m_captures.flags.set(D3D8CapturedStateFlag::Indices);
14+
m_captures.flags.set(D3D8CapturedStateFlag::SWVP);
15+
16+
m_captures.flags.set(D3D8CapturedStateFlag::VertexBuffers);
17+
m_captures.streams.setAll();
18+
19+
m_captures.flags.set(D3D8CapturedStateFlag::Textures);
20+
m_captures.textures.setAll();
21+
}
22+
23+
if (Type == D3D8StateBlockType::VertexState || Type == D3D8StateBlockType::All) {
1524
// Lights, D3DTSS_TEXCOORDINDEX and D3DTSS_TEXTURETRANSFORMFLAGS,
1625
// vertex shader, VS constants, and various render states.
17-
m_capture.vs = true;
26+
m_captures.flags.set(D3D8CapturedStateFlag::VertexShader);
1827
}
1928

20-
if (Type == D3DSBT_PIXELSTATE || Type == D3DSBT_ALL) {
29+
if (Type == D3D8StateBlockType::PixelState || Type == D3D8StateBlockType::All) {
2130
// Pixel shader, PS constants, and various RS/TSS states.
22-
m_capture.ps = true;
31+
m_captures.flags.set(D3D8CapturedStateFlag::PixelShader);
2332
}
2433

25-
if (Type == D3DSBT_ALL) {
26-
m_capture.indices = true;
27-
m_capture.swvp = true;
28-
m_capture.textures.setAll();
29-
m_capture.streams.setAll();
30-
}
34+
m_state.textures.fill(nullptr);
35+
m_state.streams.fill(D3D8VBOP());
3136

32-
m_textures.fill(nullptr);
33-
m_streams.fill(D3D8VBOP());
37+
// Automatically capture state on creation via D3D8Device::CreateStateBlock.
38+
if (Type != D3D8StateBlockType::None)
39+
Capture();
3440
}
3541

3642
// Construct a state block without a D3D9 object
3743
D3D8StateBlock::D3D8StateBlock(D3D8Device* pDevice)
38-
: D3D8StateBlock(pDevice, D3DSTATEBLOCKTYPE(0), nullptr) {
44+
: D3D8StateBlock(pDevice, D3D8StateBlockType::None, nullptr) {
3945
}
4046

4147
// Attach a D3D9 object to a state block that doesn't have one yet
@@ -51,31 +57,38 @@ namespace dxvk {
5157
if (unlikely(m_stateBlock == nullptr))
5258
return D3DERR_INVALIDCALL;
5359

54-
if (m_capture.vs) m_device->GetVertexShader(&m_vertexShader);
55-
if (m_capture.ps) m_device->GetPixelShader(&m_pixelShader);
60+
if (m_captures.flags.test(D3D8CapturedStateFlag::Indices)) {
61+
m_state.baseVertexIndex = m_device->m_baseVertexIndex;
62+
m_state.indices = m_device->m_indices.ptr();
63+
}
5664

57-
for (DWORD stage = 0; stage < m_textures.size(); stage++) {
58-
if (m_capture.textures.get(stage))
59-
m_textures[stage] = m_device->m_textures[stage].ptr();
65+
if (m_captures.flags.test(D3D8CapturedStateFlag::SWVP)) {
66+
DWORD swvpState;
67+
m_device->GetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, &swvpState);
68+
m_state.isSWVP = static_cast<bool>(swvpState);
6069
}
6170

62-
for (DWORD stream = 0; stream < m_streams.size(); stream++) {
63-
if (m_capture.streams.get(stream)) {
64-
m_streams[stream].buffer = m_device->m_streams[stream].buffer.ptr();
65-
m_streams[stream].stride = m_device->m_streams[stream].stride;
71+
if (m_captures.flags.test(D3D8CapturedStateFlag::VertexBuffers)) {
72+
for (DWORD stream = 0; stream < m_state.streams.size(); stream++) {
73+
if (m_captures.streams.get(stream)) {
74+
m_state.streams[stream].buffer = m_device->m_streams[stream].buffer.ptr();
75+
m_state.streams[stream].stride = m_device->m_streams[stream].stride;
76+
}
6677
}
6778
}
6879

69-
if (m_capture.indices) {
70-
m_baseVertexIndex = m_device->m_baseVertexIndex;
71-
m_indices = m_device->m_indices.ptr();
80+
if (m_captures.flags.test(D3D8CapturedStateFlag::Textures)) {
81+
for (DWORD stage = 0; stage < m_state.textures.size(); stage++) {
82+
if (m_captures.textures.get(stage))
83+
m_state.textures[stage] = m_device->m_textures[stage].ptr();
84+
}
7285
}
7386

74-
if (m_capture.swvp) {
75-
DWORD swvpState;
76-
m_device->GetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, &swvpState);
77-
m_isSWVP = static_cast<bool>(swvpState);
78-
}
87+
if (m_captures.flags.test(D3D8CapturedStateFlag::VertexShader))
88+
m_device->GetVertexShader(&m_state.vertexShaderHandle);
89+
90+
if (m_captures.flags.test(D3D8CapturedStateFlag::PixelShader))
91+
m_device->GetPixelShader(&m_state.pixelShaderHandle);
7992

8093
return m_stateBlock->Capture();
8194
}
@@ -86,25 +99,32 @@ namespace dxvk {
8699

87100
HRESULT res = m_stateBlock->Apply();
88101

89-
if (m_capture.vs) m_device->SetVertexShader(m_vertexShader);
90-
if (m_capture.ps) m_device->SetPixelShader(m_pixelShader);
102+
if (m_captures.flags.test(D3D8CapturedStateFlag::Indices))
103+
m_device->SetIndices(m_state.indices, m_state.baseVertexIndex);
91104

92-
for (DWORD stage = 0; stage < m_textures.size(); stage++) {
93-
if (m_capture.textures.get(stage))
94-
m_device->SetTexture(stage, m_textures[stage]);
105+
// This was a very easy footgun for D3D8 applications.
106+
if (m_captures.flags.test(D3D8CapturedStateFlag::SWVP))
107+
m_device->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, static_cast<DWORD>(m_state.isSWVP));
108+
109+
if (m_captures.flags.test(D3D8CapturedStateFlag::VertexBuffers)) {
110+
for (DWORD stream = 0; stream < m_state.streams.size(); stream++) {
111+
if (m_captures.streams.get(stream))
112+
m_device->SetStreamSource(stream, m_state.streams[stream].buffer, m_state.streams[stream].stride);
113+
}
95114
}
96115

97-
for (DWORD stream = 0; stream < m_streams.size(); stream++) {
98-
if (m_capture.streams.get(stream))
99-
m_device->SetStreamSource(stream, m_streams[stream].buffer, m_streams[stream].stride);
116+
if (m_captures.flags.test(D3D8CapturedStateFlag::Textures)) {
117+
for (DWORD stage = 0; stage < m_state.textures.size(); stage++) {
118+
if (m_captures.textures.get(stage))
119+
m_device->SetTexture(stage, m_state.textures[stage]);
120+
}
100121
}
101122

102-
if (m_capture.indices)
103-
m_device->SetIndices(m_indices, m_baseVertexIndex);
123+
if (m_captures.flags.test(D3D8CapturedStateFlag::VertexShader))
124+
m_device->SetVertexShader(m_state.vertexShaderHandle);
104125

105-
// This was a very easy footgun for D3D8 applications.
106-
if (m_capture.swvp)
107-
m_device->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, static_cast<DWORD>(m_isSWVP));
126+
if (m_captures.flags.test(D3D8CapturedStateFlag::PixelShader))
127+
m_device->SetPixelShader(m_state.pixelShaderHandle);
108128

109129
return res;
110130
}

0 commit comments

Comments
 (0)