Skip to content

Commit

Permalink
Merge branch 'xbei/anti_culling' into 'main'
Browse files Browse the repository at this point in the history
[REMIX-2179] Fix instance removal issue and refactoring duplication check hash generation

See merge request lightspeedrtx/dxvk-remix-nv!504
  • Loading branch information
xbei-nv committed Oct 4, 2023
2 parents d311ba2 + e4c0943 commit 22c2e9d
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 22 deletions.
3 changes: 2 additions & 1 deletion RtxOptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ Tables below enumerate all the options and their defaults set by RTX Remix. Note
|rtx.antiCulling.object.enableInfinityFarFrustum|bool|False|Enable infinity far plane frustum for anti\-culling\.|
|rtx.antiCulling.object.farPlaneScale|float|10|Scale applied to the far plane for Anti\-Culling Frustum for matching the culling frustum in the original game\.|
|rtx.antiCulling.object.fovScale|float|1|Scale applied to the FOV of Anti\-Culling Frustum for matching the culling frustum in the original game\.|
|rtx.antiCulling.object.numObjectsToKeep|int|1000|The maximum number of RayTracing instances to keep when Anti\-Culling is enabled\.|
|rtx.antiCulling.object.hashInstanceWithBoundingBoxHash|bool|True|Hash instances with bounding box hash for object duplication check\.<br> Disable this when the game using primitive culling which may cause flickering\.|
|rtx.antiCulling.object.numObjectsToKeep|int|10000|The maximum number of RayTracing instances to keep when Anti\-Culling is enabled\.|
|rtx.applicationId|int|102100511|Used to uniquely identify the application to DLSS\. Generally should not be changed without good reason\.|
|rtx.asyncTextureUploadPreloadMips|int|8||
|rtx.autoExposure.autoExposureSpeed|float|5|Average exposure changing speed when the image changes\.|
Expand Down
1 change: 1 addition & 0 deletions src/dxvk/imgui/dxvk_imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2848,6 +2848,7 @@ namespace dxvk {
if (RtxOptions::AntiCulling::Object::enableHighPrecisionAntiCulling()) {
ImGui::Checkbox("Infinity Far Frustum", &RtxOptions::AntiCulling::Object::enableInfinityFarFrustumObject());
}
ImGui::Checkbox("Enable Bounding Box Hash For Duplication Check", &RtxOptions::AntiCulling::Object::hashInstanceWithBoundingBoxHashObject());
ImGui::InputInt("Instance Max Size", &RtxOptions::AntiCulling::Object::numObjectsToKeepObject(), 1, 1, 0);
ImGui::DragFloat("Anti-Culling Fov Scale", &RtxOptions::AntiCulling::Object::fovScaleObject(), 0.01f, 0.1f, 2.0f);
ImGui::DragFloat("Anti-Culling Far Plane Scale", &RtxOptions::AntiCulling::Object::farPlaneScaleObject(), 0.1f, 0.1f, 10000.0f);
Expand Down
27 changes: 20 additions & 7 deletions src/dxvk/rtx_render/rtx_instance_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1103,14 +1103,9 @@ namespace dxvk {

void InstanceManager::removeInstance(RtInstance* instance) {
// In these cases we skip calling onInstanceDestroyed:
// 1. Some view model and player instances are created in the renderer and don't have onInstanceAdded called,
// Some view model and player instances are created in the renderer and don't have onInstanceAdded called,
// so not call onInstanceDestroyed either.
//
// 2. Some BLAS were cleared in the SceneManager::garbageCollection().
// When a BLAS is destroyed, all instances that linked to it will be automatically unlinked. In such case we don't need to
// call onInstanceDestroyed to double unlink the instances.
// Note: This case often happens when BLAS are destroyed faster than instances. (e.g. numFramesToKeepGeometryData >= numFramesToKeepInstances)
if (instance->m_isCreatedByRenderer || instance->m_isUnlinkedForGC) {
if (instance->m_isCreatedByRenderer) {
return;
}

Expand Down Expand Up @@ -2155,4 +2150,22 @@ namespace dxvk {
// - Beams should not be split into quads for OMM reuse.
instance.m_billboardCount = 0;
}

const XXH64_hash_t RtInstance::calculateAntiCullingHash() const {
if (RtxOptions::AntiCulling::Object::enable()) {
const Vector3 pos = getWorldPosition();
const XXH64_hash_t posHash = XXH3_64bits(&pos, sizeof(pos));
XXH64_hash_t antiCullingHash = XXH3_64bits_withSeed(&m_materialDataHash, sizeof(XXH64_hash_t), posHash);

if (RtxOptions::AntiCulling::Object::hashInstanceWithBoundingBoxHash() &&
RtxOptions::Get()->needsMeshBoundingBox()) {
const AxisAlignedBoundingBox& boundingBox = getBlas()->input.getGeometryData().boundingBox;
const XXH64_hash_t bboxHash = boundingBox.calculateHash();
antiCullingHash = XXH3_64bits_withSeed(&bboxHash, sizeof(antiCullingHash), antiCullingHash);
}
return antiCullingHash;
}

return XXH64_hash_t();
}
} // namespace dxvk
3 changes: 3 additions & 0 deletions src/dxvk/rtx_render/rtx_instance_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class RtInstance {
const XXH64_hash_t& getMaterialDataHash() const { return m_materialDataHash; }
const XXH64_hash_t& getTexcoordHash() const { return m_texcoordHash; }
const XXH64_hash_t& getIndexHash() const { return m_indexHash; }
const XXH64_hash_t calculateAntiCullingHash() const;
Matrix4 getTransform() const { return transpose(dxvk::Matrix4(m_vkInstance.transform)); }
const Matrix4& getPrevTransform() const { return surface.prevObjectToWorld; }
Vector3 getWorldPosition() const { return { m_vkInstance.transform.matrix[0][3], m_vkInstance.transform.matrix[1][3], m_vkInstance.transform.matrix[2][3] }; }
Expand Down Expand Up @@ -130,6 +131,8 @@ class RtInstance {
bool isViewModelNonReference() const;
bool isViewModelReference() const;
bool isViewModelVirtual() const;

bool isUnlinkedForGC() const { return m_isUnlinkedForGC; }
private:
friend class InstanceManager;

Expand Down
3 changes: 2 additions & 1 deletion src/dxvk/rtx_render/rtx_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -395,8 +395,9 @@ namespace dxvk {
"This method is slightly expensive but it effectively addresses object flickering issues that arise from corner cases in the fast intersection check method.\n"
"Typically, it's advisable to enable this option unless it results in a notable performance drop; otherwise, the presence of flickering artifacts could significantly diminish the overall image quality.");
RTX_OPTION("rtx.antiCulling.object", bool, enableInfinityFarFrustum, false, "Enable infinity far plane frustum for anti-culling.");
RTX_OPTION("rtx.antiCulling.object", bool, hashInstanceWithBoundingBoxHash, true, "Hash instances with bounding box hash for object duplication check.\n Disable this when the game using primitive culling which may cause flickering.");
// TODO: This should be a threshold of memory size
RTX_OPTION("rtx.antiCulling.object", uint32_t, numObjectsToKeep, 1000, "The maximum number of RayTracing instances to keep when Anti-Culling is enabled.");
RTX_OPTION("rtx.antiCulling.object", uint32_t, numObjectsToKeep, 10000, "The maximum number of RayTracing instances to keep when Anti-Culling is enabled.");
RTX_OPTION("rtx.antiCulling.object", float, fovScale, 1.0f, "Scale applied to the FOV of Anti-Culling Frustum for matching the culling frustum in the original game.");
RTX_OPTION("rtx.antiCulling.object", float, farPlaneScale, 10.0f, "Scale applied to the far plane for Anti-Culling Frustum for matching the culling frustum in the original game.");
};
Expand Down
23 changes: 10 additions & 13 deletions src/dxvk/rtx_render/rtx_scene_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,20 +232,13 @@ namespace dxvk {
// This is used to handle cases:
// 1. The game frustum is different to our frustum
// 2. The game culling method is NOT frustum culling
const AxisAlignedBoundingBox& boundingBox = instance->getBlas()->input.getGeometryData().boundingBox;
const XXH64_hash_t materialHash = instance->getMaterialDataHash();
const Vector3 pos = instance->getWorldPosition();
const XXH64_hash_t posHash = XXH3_64bits(&pos, sizeof(pos));
const XXH64_hash_t bboxMinHash = XXH3_64bits(&boundingBox.minPos, sizeof(boundingBox.minPos));
const XXH64_hash_t bboxMaxHash = XXH3_64bits(&boundingBox.maxPos, sizeof(boundingBox.maxPos));
XXH64_hash_t cacheHash = XXH64(&materialHash, sizeof(XXH64_hash_t), posHash);
cacheHash = XXH64(&bboxMinHash, sizeof(XXH64_hash_t), cacheHash);
cacheHash = XXH64(&bboxMaxHash, sizeof(XXH64_hash_t), cacheHash);

auto it = outsideFrustumInstancesCache.find(cacheHash);

const XXH64_hash_t antiCullingHash = instance->calculateAntiCullingHash();

auto it = outsideFrustumInstancesCache.find(antiCullingHash);
if (it == outsideFrustumInstancesCache.end()) {
// No duplication, just cache the current instance
outsideFrustumInstancesCache[cacheHash] = instance;
outsideFrustumInstancesCache[antiCullingHash] = instance;
} else {
const RtInstance* cachedInstance = it->second;
if (instance->getId() != cachedInstance->getId()) {
Expand Down Expand Up @@ -809,7 +802,11 @@ namespace dxvk {

void SceneManager::onInstanceDestroyed(const RtInstance& instance) {
BlasEntry* pBlas = instance.getBlas();
if (pBlas != nullptr) {
// Some BLAS were cleared in the SceneManager::garbageCollection().
// When a BLAS is destroyed, all instances that linked to it will be automatically unlinked. In such case we don't need to
// call onInstanceDestroyed to double unlink the instances.
// Note: This case often happens when BLAS are destroyed faster than instances. (e.g. numFramesToKeepGeometryData >= numFramesToKeepInstances)
if (pBlas != nullptr && !instance.isUnlinkedForGC()) {
pBlas->unlinkInstance(&instance);
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/dxvk/rtx_render/rtx_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ struct AxisAlignedBoundingBox {
maxPos[i] = std::max(maxPos[i], other.maxPos[i]);
}
}

const XXH64_hash_t calculateHash() const {
return XXH3_64bits(this, sizeof(AxisAlignedBoundingBox));
}
};

// Stores a snapshot of the geometry state for a draw call.
Expand Down

0 comments on commit 22c2e9d

Please sign in to comment.