Skip to content

Commit 8486e99

Browse files
committed
[d3d9] Simplify and fix light enablement
There was a bug somewhere in the state block code since it would lose information about enabled and disabled lights somehow.
1 parent cd786f4 commit 8486e99

5 files changed

Lines changed: 66 additions & 75 deletions

File tree

src/d3d9/d3d9_device.cpp

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2171,9 +2171,11 @@ namespace dxvk {
21712171
if (Index >= m_state.lights.size())
21722172
m_state.lights.resize(Index + 1);
21732173

2174-
m_state.lights[Index] = *pLight;
2174+
auto& light = m_state.lights[Index];
2175+
light.isValid = true;
2176+
light.light = *pLight;
21752177

2176-
if (m_state.IsLightEnabled(Index))
2178+
if (light.isEnabled)
21772179
m_dirty.set(D3D9DeviceDirtyFlag::FFVertexData);
21782180

21792181
return D3D_OK;
@@ -2186,11 +2188,15 @@ namespace dxvk {
21862188
if (unlikely(pLight == nullptr))
21872189
return D3DERR_INVALIDCALL;
21882190

2189-
if (unlikely(Index >= m_state.lights.size() || !m_state.lights[Index]))
2191+
if (unlikely(Index >= m_state.lights.size()))
21902192
return D3DERR_INVALIDCALL;
21912193

2192-
*pLight = m_state.lights[Index].value();
2194+
auto& light = m_state.lights[Index];
2195+
2196+
if (unlikely(!light.isValid))
2197+
return D3DERR_INVALIDCALL;
21932198

2199+
*pLight = m_state.lights[Index].light;
21942200
return D3D_OK;
21952201
}
21962202

@@ -2206,27 +2212,16 @@ namespace dxvk {
22062212
if (unlikely(Index >= m_state.lights.size()))
22072213
m_state.lights.resize(Index + 1);
22082214

2209-
if (unlikely(!m_state.lights[Index]))
2210-
m_state.lights[Index] = DefaultLight;
2215+
auto& light = m_state.lights[Index];
22112216

2212-
if (m_state.IsLightEnabled(Index) == !!Enable)
2217+
if (light.isEnabled == bool(Enable))
22132218
return D3D_OK;
22142219

2215-
uint32_t searchIndex = std::numeric_limits<uint32_t>::max();
2216-
uint32_t setIndex = Index;
2217-
2218-
if (!Enable)
2219-
std::swap(searchIndex, setIndex);
2220-
2221-
for (auto& idx : m_state.enabledLightIndices) {
2222-
if (idx == searchIndex) {
2223-
idx = setIndex;
2224-
m_dirty.set(D3D9DeviceDirtyFlag::FFVertexData);
2225-
m_dirty.set(D3D9DeviceDirtyFlag::FFVertexShader);
2226-
break;
2227-
}
2228-
}
2220+
light.isValid = true;
2221+
light.isEnabled = bool(Enable);
22292222

2223+
m_dirty.set(D3D9DeviceDirtyFlag::FFVertexData,
2224+
D3D9DeviceDirtyFlag::FFVertexShader);
22302225
return D3D_OK;
22312226
}
22322227

@@ -2237,11 +2232,15 @@ namespace dxvk {
22372232
if (unlikely(pEnable == nullptr))
22382233
return D3DERR_INVALIDCALL;
22392234

2240-
if (unlikely(Index >= m_state.lights.size() || !m_state.lights[Index]))
2235+
if (unlikely(Index >= m_state.lights.size()))
22412236
return D3DERR_INVALIDCALL;
22422237

2243-
*pEnable = m_state.IsLightEnabled(Index) ? 128 : 0; // Weird quirk but OK.
2238+
auto& light = m_state.lights[Index];
2239+
2240+
if (unlikely(!light.isValid))
2241+
return D3DERR_INVALIDCALL;
22442242

2243+
*pEnable = light.isEnabled ? 128 : 0; // Weird quirk but OK.
22452244
return D3D_OK;
22462245
}
22472246

@@ -8169,18 +8168,20 @@ namespace dxvk {
81698168
DecodeD3DCOLOR(m_state.renderStates[D3DRS_AMBIENT], data->GlobalAmbient.data);
81708169

81718170
uint32_t lightIdx = 0;
8172-
for (uint32_t i = 0; i < caps::MaxEnabledLights; i++) {
8173-
auto idx = m_state.enabledLightIndices[i];
8174-
if (idx == std::numeric_limits<uint32_t>::max())
8171+
8172+
for (auto& light : m_state.lights) {
8173+
if (!light.isEnabled)
81758174
continue;
81768175

81778176
// D3D8/9 will allow lights with invalid types to be set and retrieved,
81788177
// and even enabled, however they won't affect overall lighting
8179-
const D3DLIGHT9& light = m_state.lights[idx].value();
8180-
if (unlikely(light.Type == 0 || light.Type > D3DLIGHT_DIRECTIONAL))
8178+
if (unlikely(!light.light.Type || light.light.Type > D3DLIGHT_DIRECTIONAL))
81818179
continue;
81828180

8183-
data->Lights[lightIdx++] = D3D9Light(light, m_state.transforms[GetTransformIndex(D3DTS_VIEW)]);
8181+
data->Lights[lightIdx++] = D3D9Light(light.light, m_state.transforms[GetTransformIndex(D3DTS_VIEW)]);
8182+
8183+
if (lightIdx == caps::MaxEnabledLights)
8184+
break;
81848185
}
81858186

81868187
data->Material = m_state.material;

src/d3d9/d3d9_state.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@ namespace dxvk {
88
D3D9State<ItemType>::D3D9State() {
99
for (uint32_t i = 0; i < streamFreq.size(); i++)
1010
streamFreq[i] = 1;
11-
12-
for (uint32_t i = 0; i < enabledLightIndices.size(); i++)
13-
enabledLightIndices[i] = std::numeric_limits<uint32_t>::max();
1411
}
1512

1613

@@ -25,4 +22,4 @@ namespace dxvk {
2522
template struct D3D9State<dynamic_item>;
2623
template struct D3D9State<static_item>;
2724

28-
}
25+
}

src/d3d9/d3d9_state.h

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,26 @@ namespace dxvk {
373373
float Phi;
374374
};
375375

376+
constexpr D3DLIGHT9 DefaultLight = {
377+
D3DLIGHT_DIRECTIONAL, // Type
378+
{1.0f, 1.0f, 1.0f, 0.0f}, // Diffuse
379+
{0.0f, 0.0f, 0.0f, 0.0f}, // Specular
380+
{0.0f, 0.0f, 0.0f, 0.0f}, // Ambient
381+
{0.0f, 0.0f, 0.0f}, // Position
382+
{0.0f, 0.0f, 1.0f}, // Direction
383+
0.0f, // Range
384+
0.0f, // Falloff
385+
0.0f, 0.0f, 0.0f, // Attenuations [constant, linear, quadratic]
386+
0.0f, // Theta
387+
0.0f // Phi
388+
};
389+
390+
struct D3D9LightState {
391+
bool isValid = false;
392+
bool isEnabled = false;
393+
D3DLIGHT9 light = DefaultLight;
394+
};
395+
376396
struct D3D9FixedFunctionVS {
377397
Matrix4 WorldView;
378398
Matrix4 NormalMatrix;
@@ -454,20 +474,6 @@ namespace dxvk {
454474
UINT stride = 0;
455475
};
456476

457-
constexpr D3DLIGHT9 DefaultLight = {
458-
D3DLIGHT_DIRECTIONAL, // Type
459-
{1.0f, 1.0f, 1.0f, 0.0f}, // Diffuse
460-
{0.0f, 0.0f, 0.0f, 0.0f}, // Specular
461-
{0.0f, 0.0f, 0.0f, 0.0f}, // Ambient
462-
{0.0f, 0.0f, 0.0f}, // Position
463-
{0.0f, 0.0f, 1.0f}, // Direction
464-
0.0f, // Range
465-
0.0f, // Falloff
466-
0.0f, 0.0f, 0.0f, // Attenuations [constant, linear, quadratic]
467-
0.0f, // Theta
468-
0.0f // Phi
469-
};
470-
471477
template <typename T>
472478
class dynamic_item {
473479
public:
@@ -589,15 +595,9 @@ namespace dxvk {
589595

590596
ItemType<D3DMATERIAL9> material = {};
591597

592-
std::vector<std::optional<D3DLIGHT9>> lights;
593-
std::array<DWORD, caps::MaxEnabledLights> enabledLightIndices;
598+
std::vector<D3D9LightState> lights;
594599

595600
float nPatchSegments = 0.0f;
596-
597-
bool IsLightEnabled(DWORD Index) const {
598-
const auto& enabledIndices = enabledLightIndices;
599-
return std::find(enabledIndices.begin(), enabledIndices.end(), Index) != enabledIndices.end();
600-
}
601601
};
602602

603603
using D3D9CapturableState = D3D9State<dynamic_item>;

src/d3d9/d3d9_stateblock.cpp

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,9 @@ namespace dxvk {
191191
if (Index >= m_state.lights.size())
192192
m_state.lights.resize(Index + 1);
193193

194-
m_state.lights[Index] = *pLight;
194+
auto& light = m_state.lights[Index];
195+
light.isValid = true;
196+
light.light = *pLight;
195197

196198
m_captures.flags.set(D3D9CapturedStateFlag::Lights);
197199
return D3D_OK;
@@ -202,24 +204,13 @@ namespace dxvk {
202204
if (unlikely(Index >= m_state.lights.size()))
203205
m_state.lights.resize(Index + 1);
204206

205-
if (unlikely(!m_state.lights[Index]))
206-
m_state.lights[Index] = DefaultLight;
207+
// Apply default light on enable, but not disable.
208+
// No idea if this is correct, but matches the old logic.
209+
auto& light = m_state.lights[Index];
210+
light.isEnabled = bool(Enable);
207211

208-
if (m_state.IsLightEnabled(Index) == !!Enable)
209-
return D3D_OK;
210-
211-
uint32_t searchIndex = std::numeric_limits<uint32_t>::max();
212-
uint32_t setIndex = Index;
213-
214-
if (!Enable)
215-
std::swap(searchIndex, setIndex);
216-
217-
for (auto& idx : m_state.enabledLightIndices) {
218-
if (idx == searchIndex) {
219-
idx = setIndex;
220-
break;
221-
}
222-
}
212+
if (Enable)
213+
light.isValid = true;
223214

224215
m_captures.lightEnabledChanges.set(Index, true);
225216
m_captures.flags.set(D3D9CapturedStateFlag::Lights);

src/d3d9/d3d9_stateblock.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -321,16 +321,18 @@ namespace dxvk {
321321

322322
if (m_captures.flags.test(D3D9CapturedStateFlag::Lights)) {
323323
for (uint32_t i = 0; i < src->lights.size(); i++) {
324-
if (!src->lights[i].has_value())
324+
if (!src->lights[i].isValid)
325325
continue;
326326

327-
dst->SetLight(i, &src->lights[i].value());
327+
dst->SetLight(i, &src->lights[i].light);
328328
}
329+
329330
for (uint32_t i = 0; i < m_captures.lightEnabledChanges.dwordCount(); i++) {
330331
for (uint32_t consts : bit::BitMask(m_captures.lightEnabledChanges.dword(i))) {
331332
uint32_t idx = i * 32 + consts;
332333

333-
dst->LightEnable(idx, src->IsLightEnabled(idx));
334+
if (idx < src->lights.size())
335+
dst->LightEnable(idx, src->lights[idx].isEnabled);
334336
}
335337
}
336338
}

0 commit comments

Comments
 (0)