Skip to content

Commit 1715ec2

Browse files
Merge branch 'private/ddrivergomm/REMIX-3611' into 'main'
[REMIX-3611] Fix use-after-free crash in ViewModel instance processing on alt+tab Closes REMIX-3611 See merge request lightspeedrtx/dxvk-remix-nv!2008
2 parents 187cb18 + a330c61 commit 1715ec2

2 files changed

Lines changed: 33 additions & 13 deletions

File tree

src/dxvk/rtx_render/rtx_instance_manager.cpp

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ namespace dxvk {
158158
namespace {
159159
template<int RtInstanceSize> struct CheckRtInstanceSize {
160160
// The second line of the build error should contain the new size of RtInstance in the template argument, i.e. `dxvk::CheckRtInstanceSize<newSize>`
161-
static_assert(RtInstanceSize == 768, "RtInstance size has changed. Fix the copy constructor above this message, then update the expected size.");
161+
static_assert(RtInstanceSize == 752, "RtInstance size has changed. Fix the copy constructor above this message, then update the expected size.");
162162
};
163163
CheckRtInstanceSize<sizeof(RtInstance)> _rtInstanceSizeTest;
164164
}
@@ -262,7 +262,7 @@ namespace dxvk {
262262
// Returns true if this is the first update this frame
263263
bool RtInstance::setFrameLastUpdated(const uint32_t frameIndex) {
264264
if (m_frameLastUpdated != frameIndex) {
265-
m_seenCameraTypes.clear();
265+
m_seenCameraTypes.clrAll();
266266

267267
m_frameLastUpdated = frameIndex;
268268

@@ -289,16 +289,16 @@ namespace dxvk {
289289
}
290290

291291
bool RtInstance::registerCamera(CameraType::Enum cameraType, uint32_t frameIndex) {
292-
bool settingNewCameraType = std::find(m_seenCameraTypes.begin(), m_seenCameraTypes.end(), cameraType) == m_seenCameraTypes.end();
292+
const bool settingNewCameraType = !m_seenCameraTypes.test(cameraType);
293293

294-
if (settingNewCameraType)
295-
m_seenCameraTypes.push_back(cameraType);
294+
if (settingNewCameraType)
295+
m_seenCameraTypes.set(cameraType);
296296

297297
return settingNewCameraType;
298298
}
299299

300300
bool RtInstance::isCameraRegistered(CameraType::Enum cameraType) const {
301-
return std::find(m_seenCameraTypes.begin(), m_seenCameraTypes.end(), cameraType) != m_seenCameraTypes.end();
301+
return m_seenCameraTypes.test(cameraType);
302302
}
303303

304304
void RtInstance::setCustomIndexBit(uint32_t oneBitMask, bool value) {
@@ -424,10 +424,12 @@ namespace dxvk {
424424
"Category Flags: ", m_categoryFlags.raw(), "\n",
425425
"\n",
426426
"=== Camera Types ===\n",
427-
"Seen Camera Types Count: ", m_seenCameraTypes.size()));
428-
429-
for (size_t i = 0; i < m_seenCameraTypes.size(); ++i) {
430-
Logger::warn(str::format(" Camera Type ", i, ": ", static_cast<int>(m_seenCameraTypes[i])));
427+
"Seen Camera Types Mask: ", m_seenCameraTypes.raw()));
428+
429+
for (uint32_t type = 0; type < CameraType::Count; ++type) {
430+
if (m_seenCameraTypes.test(static_cast<CameraType::Enum>(type))) {
431+
Logger::warn(str::format(" Camera Type: ", type));
432+
}
431433
}
432434

433435
Logger::warn(str::format(
@@ -1247,6 +1249,12 @@ namespace dxvk {
12471249

12481250
if (currentInstance.m_isPlayerModel && drawCall.cameraType != CameraType::ViewModel) {
12491251
mask |= OBJECT_MASK_PLAYER_MODEL;
1252+
// Lazy-clear stale instances if onFrameEnd() was skipped last frame (e.g. device loss on alt+tab)
1253+
const uint32_t currentFrameId = m_device->getCurrentFrameId();
1254+
if (m_playerModelInstancesFrameId != currentFrameId) {
1255+
m_playerModelInstances.clear();
1256+
m_playerModelInstancesFrameId = currentFrameId;
1257+
}
12501258
m_playerModelInstances.push_back(&currentInstance);
12511259
} else {
12521260
currentInstance.m_isPlayerModel = false;
@@ -1291,8 +1299,15 @@ namespace dxvk {
12911299
bool billboardsGotGenerated = false;
12921300
currentInstance.m_billboardCount = 0;
12931301

1294-
if (drawCall.cameraType == CameraType::ViewModel && !currentInstance.m_isHidden && isFirstUpdateThisFrame)
1302+
if (drawCall.cameraType == CameraType::ViewModel && !currentInstance.m_isHidden && isFirstUpdateThisFrame) {
1303+
// Lazy-clear stale candidates if onFrameEnd() was skipped last frame (e.g. device loss on alt+tab)
1304+
const uint32_t currentFrameId = m_device->getCurrentFrameId();
1305+
if (m_viewModelCandidatesFrameId != currentFrameId) {
1306+
m_viewModelCandidates.clear();
1307+
m_viewModelCandidatesFrameId = currentFrameId;
1308+
}
12951309
m_viewModelCandidates.push_back(&currentInstance);
1310+
}
12961311

12971312
if (RtxOptions::enableSeparateUnorderedApproximations() &&
12981313
(drawCall.cameraType == CameraType::Main || drawCall.cameraType == CameraType::ViewModel) &&
@@ -1456,7 +1471,9 @@ namespace dxvk {
14561471
for (auto* candidateInstance : m_viewModelCandidates) {
14571472

14581473
// Valid view model instances must be associated only with the view model camera
1459-
if (candidateInstance->m_seenCameraTypes.size() != 1)
1474+
// Check: exactly one bit set (power-of-two check via raw bitmask)
1475+
const auto seenMask = candidateInstance->m_seenCameraTypes.raw();
1476+
if (seenMask == 0 || (seenMask & (seenMask - 1)) != 0)
14601477
continue;
14611478

14621479
// Hide the reference instance since we'll create a separate instance for the view model

src/dxvk/rtx_render/rtx_instance_manager.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "../util/rc/util_rc_ptr.h"
2929
#include "rtx_types.h"
3030
#include "../util/util_vector.h"
31+
#include "../util/util_flags.h"
3132
#include "../util/util_matrix.h"
3233
#include "rtx_camera_manager.h"
3334
#include "dxvk_cmdlist.h"
@@ -181,7 +182,7 @@ uint32_t getFirstBillboardIndex() const { return m_firstBillboard; }
181182
mutable uint32_t m_frameLastUpdated = kInvalidFrameIndex;
182183
mutable uint32_t m_frameCreated = kInvalidFrameIndex;
183184

184-
std::vector<CameraType::Enum> m_seenCameraTypes; // Camera types with which the instance has been originally rendered with
185+
Flags<CameraType::Enum> m_seenCameraTypes; // Camera types with which the instance has been originally rendered with
185186

186187
MaterialDataType m_materialType = MaterialDataType::Invalid;
187188
uint32_t m_albedoOpacityTextureIndex = kSurfaceMaterialInvalidTextureIndex;
@@ -337,7 +338,9 @@ class InstanceManager : public CommonDeviceObject {
337338

338339
std::vector<RtInstance*> m_instances;
339340
std::vector<RtInstance*> m_viewModelCandidates;
341+
uint32_t m_viewModelCandidatesFrameId = kInvalidFrameIndex;
340342
std::vector<RtInstance*> m_playerModelInstances;
343+
uint32_t m_playerModelInstancesFrameId = kInvalidFrameIndex;
341344
std::vector<IntersectionBillboard> m_billboards;
342345

343346
bool m_previousViewModelState = false;

0 commit comments

Comments
 (0)