|
1 | 1 | /* |
2 | | -* Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. |
| 2 | +* Copyright (c) 2021-2026, NVIDIA CORPORATION. All rights reserved. |
3 | 3 | * |
4 | 4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | 5 | * copy of this software and associated documentation files (the "Software"), |
@@ -164,6 +164,30 @@ namespace dxvk { |
164 | 164 |
|
165 | 165 | void RtInstance::setBlas(BlasEntry& blas) { |
166 | 166 | m_linkedBlas = &blas; |
| 167 | + syncBufferIndicesFromBlas(); |
| 168 | + } |
| 169 | + |
| 170 | + void RtInstance::syncBufferIndicesFromBlas() { |
| 171 | + if (m_linkedBlas == nullptr) { |
| 172 | + return; |
| 173 | + } |
| 174 | + const RaytraceGeometry& geo = m_linkedBlas->modifiedGeometryData; |
| 175 | + surface.positionBufferIndex = geo.positionBufferIndex; |
| 176 | + surface.positionOffset = geo.positionBuffer.offsetFromSlice(); |
| 177 | + surface.positionStride = geo.positionBuffer.stride(); |
| 178 | + surface.normalBufferIndex = geo.normalBufferIndex; |
| 179 | + surface.normalOffset = geo.normalBuffer.offsetFromSlice(); |
| 180 | + surface.normalStride = geo.normalBuffer.stride(); |
| 181 | + surface.normalFormat = geo.normalBuffer.vertexFormat(); |
| 182 | + surface.color0BufferIndex = geo.color0BufferIndex; |
| 183 | + surface.color0Offset = geo.color0Buffer.offsetFromSlice(); |
| 184 | + surface.color0Stride = geo.color0Buffer.stride(); |
| 185 | + surface.texcoordBufferIndex = geo.texcoordBufferIndex; |
| 186 | + surface.texcoordOffset = geo.texcoordBuffer.offsetFromSlice(); |
| 187 | + surface.texcoordStride = geo.texcoordBuffer.stride(); |
| 188 | + surface.previousPositionBufferIndex = geo.previousPositionBufferIndex; |
| 189 | + surface.indexBufferIndex = geo.indexBufferIndex; |
| 190 | + surface.indexStride = geo.indexBuffer.stride(); |
167 | 191 | } |
168 | 192 |
|
169 | 193 | void RtInstance::copyInstanceDataFrom(const RtInstance& src) { |
@@ -228,10 +252,14 @@ namespace dxvk { |
228 | 252 | m_vkInstance.transform = savedVkTransform; |
229 | 253 | } |
230 | 254 |
|
| 255 | + // Clones are not linked into BlasEntry::m_linkedInstances (see createInstanceCopy), so |
| 256 | + // updateBufferCache's push never reaches them. Re-derive from the BLAS rather than relying on |
| 257 | + // the reference instance having been refreshed first. |
| 258 | + syncBufferIndicesFromBlas(); |
| 259 | + |
231 | 260 | // Mark dirty so the incremental BLAS cache treats this instance as changed. |
232 | 261 | m_blasDirty = true; |
233 | 262 | m_billboardGeometryDirty = true; |
234 | | - |
235 | 263 | } |
236 | 264 |
|
237 | 265 | void RtInstance::onTransformChanged() { |
@@ -922,26 +950,13 @@ namespace dxvk { |
922 | 950 | m_instances.push_back(newInstance); |
923 | 951 | notifySceneChanged(); |
924 | 952 |
|
925 | | - return newInstance; |
926 | | - } |
| 953 | + // Renderer-created clones (view model, player model, ray-portal virtual instances) deliberately |
| 954 | + // skip onInstanceAdded, so BlasEntry::linkInstance is never called for them and |
| 955 | + // updateBufferCache's propagation will not reach them. Derive the indices straight from the BLAS |
| 956 | + // instead of trusting the indices copied from the reference instance. |
| 957 | + newInstance->syncBufferIndicesFromBlas(); |
927 | 958 |
|
928 | | - void InstanceManager::processInstanceBuffers(const BlasEntry& blas, RtInstance& currentInstance) const { |
929 | | - currentInstance.surface.positionBufferIndex = blas.modifiedGeometryData.positionBufferIndex; |
930 | | - currentInstance.surface.positionOffset = blas.modifiedGeometryData.positionBuffer.offsetFromSlice(); |
931 | | - currentInstance.surface.positionStride = blas.modifiedGeometryData.positionBuffer.stride(); |
932 | | - currentInstance.surface.normalBufferIndex = blas.modifiedGeometryData.normalBufferIndex; |
933 | | - currentInstance.surface.normalOffset = blas.modifiedGeometryData.normalBuffer.offsetFromSlice(); |
934 | | - currentInstance.surface.normalStride = blas.modifiedGeometryData.normalBuffer.stride(); |
935 | | - currentInstance.surface.normalFormat = blas.modifiedGeometryData.normalBuffer.vertexFormat(); |
936 | | - currentInstance.surface.color0BufferIndex = blas.modifiedGeometryData.color0BufferIndex; |
937 | | - currentInstance.surface.color0Offset = blas.modifiedGeometryData.color0Buffer.offsetFromSlice(); |
938 | | - currentInstance.surface.color0Stride = blas.modifiedGeometryData.color0Buffer.stride(); |
939 | | - currentInstance.surface.texcoordBufferIndex = blas.modifiedGeometryData.texcoordBufferIndex; |
940 | | - currentInstance.surface.texcoordOffset = blas.modifiedGeometryData.texcoordBuffer.offsetFromSlice(); |
941 | | - currentInstance.surface.texcoordStride = blas.modifiedGeometryData.texcoordBuffer.stride(); |
942 | | - currentInstance.surface.previousPositionBufferIndex = blas.modifiedGeometryData.previousPositionBufferIndex; |
943 | | - currentInstance.surface.indexBufferIndex = blas.modifiedGeometryData.indexBufferIndex; |
944 | | - currentInstance.surface.indexStride = blas.modifiedGeometryData.indexBuffer.stride(); |
| 959 | + return newInstance; |
945 | 960 | } |
946 | 961 |
|
947 | 962 | // Returns true if the instance was modified |
@@ -1048,8 +1063,6 @@ namespace dxvk { |
1048 | 1063 | if (isFirstUpdateThisFrame || overridePreviousCameraUpdate) { |
1049 | 1064 |
|
1050 | 1065 | if (isFirstUpdateThisFrame) { |
1051 | | - processInstanceBuffers(blas, currentInstance); |
1052 | | - |
1053 | 1066 | currentInstance.m_materialType = materialData->getType(); |
1054 | 1067 |
|
1055 | 1068 | const XXH64_hash_t materialInstanceHash = materialData->getHash(); |
@@ -1139,7 +1152,14 @@ namespace dxvk { |
1139 | 1152 | || currentInstance.testCategoryFlags(InstanceCategories::Particle) |
1140 | 1153 | || currentInstance.testCategoryFlags(InstanceCategories::WorldUI); |
1141 | 1154 |
|
1142 | | - hasPreviousPositions = blas.modifiedGeometryData.previousPositionBuffer.defined() && !isMotionUnstable; |
| 1155 | + // previousPositionBuffer is only re-pointed at historyBuffer[1] by processGeometryInfo on a |
| 1156 | + // kUpdateBVH frame. On any later frame it still holds that older slice - e.g. a preserved |
| 1157 | + // BLAS, or the kUpdateInstance early-out in onSceneObjectUpdated when a sibling draw already |
| 1158 | + // touched this BlasEntry. Gate on frameLastUpdated so stale vertices never feed motion vectors. |
| 1159 | + const bool previousPositionsValidThisFrame = blas.frameLastUpdated == m_device->getCurrentFrameId(); |
| 1160 | + hasPreviousPositions = previousPositionsValidThisFrame |
| 1161 | + && blas.modifiedGeometryData.previousPositionBuffer.defined() |
| 1162 | + && !isMotionUnstable; |
1143 | 1163 | const bool isFirstUpdateAfterCreation = currentInstance.isCreatedThisFrame(m_device->getCurrentFrameId()) && isFirstUpdateThisFrame; |
1144 | 1164 |
|
1145 | 1165 | // Note: objectToView is aliased on updates, since findSimilarInstance() doesn't discern it |
|
0 commit comments