Skip to content

Commit 368525a

Browse files
Merge branch 'reuseMaterial' into 'main'
[REMIX-3800] cache and reuse RtSurfaceMaterial within the same frame See merge request lightspeedrtx/dxvk-remix-nv!1217
2 parents 2ca2a27 + daaffc2 commit 368525a

File tree

4 files changed

+60
-30
lines changed

4 files changed

+60
-30
lines changed

src/dxvk/rtx_render/rtx_material_data.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,10 @@
197197
m_##name = clamp(m_##name, ranges.Min##name, ranges.Max##name);
198198

199199
#define WRITE_TEXTURE_HASH(name, usd_attr, type, minVal, maxVal, defaultVal) \
200-
h ^= m_##name.getImageHash();
200+
{ \
201+
XXH64_hash_t imageHash = m_##name.getImageHash(); \
202+
h = XXH64(&imageHash, sizeof(imageHash), h); \
203+
}
201204

202205
#define WRITE_CONSTANT_HASH(name, usd_attr, type, minVal, maxVal, defaultVal) \
203206
h = XXH64(&m_##name, sizeof(m_##name), h);

src/dxvk/rtx_render/rtx_scene_manager.cpp

+39-22
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ namespace dxvk {
170170
// We still need to clear caches even if the scene wasn't rendered
171171
m_bufferCache.clear();
172172
m_surfaceMaterialCache.clear();
173+
m_preCreationSurfaceMaterialMap.clear();
173174
m_surfaceMaterialExtensionCache.clear();
174175
m_volumeMaterialCache.clear();
175176

@@ -488,6 +489,9 @@ namespace dxvk {
488489
m_uniqueObjectSearchDistance = RtxOptions::uniqueObjectDistance();
489490
m_drawCallCache.rebuildSpatialMaps();
490491
}
492+
493+
// Not currently safe to cache these across frames (due to texture indices and rtx options potentially changing)
494+
m_preCreationSurfaceMaterialMap.clear();
491495
}
492496

493497
void SceneManager::onFrameEndNoRTX() {
@@ -517,10 +521,7 @@ namespace dxvk {
517521
if (pFogReplacement->getType() != MaterialDataType::Translucent) {
518522
Logger::warn(str::format("Fog replacement materials must be translucent. Ignoring material for ", std::hex, m_fog.getHash()));
519523
} else {
520-
std::optional<RtSurfaceMaterial> surfaceMaterial {};
521-
522-
createSurfaceMaterial(ctx, surfaceMaterial, *pFogReplacement, input);
523-
m_startInMediumMaterialIndex = m_surfaceMaterialCache.track(*surfaceMaterial);
524+
createSurfaceMaterial(ctx, *pFogReplacement, input);
524525
}
525526
} else if (m_fog.mode == D3DFOG_NONE) {
526527
// render the first unreplaced fog.
@@ -901,17 +902,8 @@ namespace dxvk {
901902

902903
// Note: Use either the specified override Material Data or the original draw calls state's Material Data to create a Surface Material if no override is specified
903904
const auto renderMaterialDataType = renderMaterialData.getType();
904-
std::optional<RtSurfaceMaterial> surfaceMaterial{};
905-
906-
createSurfaceMaterial(ctx, surfaceMaterial, renderMaterialData, drawCallState);
907-
908-
assert(surfaceMaterial.has_value());
909-
assert(surfaceMaterial->validate());
910-
911-
// Cache this
912-
m_surfaceMaterialCache.track(*surfaceMaterial);
913-
914-
RtInstance* instance = m_instanceManager.processSceneObject(m_cameraManager, m_rayPortalManager, *pBlas, drawCallState, renderMaterialData, *surfaceMaterial);
905+
const RtSurfaceMaterial& surfaceMaterial = createSurfaceMaterial(ctx, renderMaterialData, drawCallState);
906+
RtInstance* instance = m_instanceManager.processSceneObject(m_cameraManager, m_rayPortalManager, *pBlas, drawCallState, renderMaterialData, surfaceMaterial);
915907

916908
// Check if a light should be created for this Material
917909
if (instance && RtxOptions::Get()->shouldConvertToLight(drawCallState.getMaterialData().getHash())) {
@@ -947,10 +939,9 @@ namespace dxvk {
947939
return instance ? instance->getId() : UINT64_MAX;
948940
}
949941

950-
void SceneManager::createSurfaceMaterial( Rc<DxvkContext> ctx,
951-
std::optional<RtSurfaceMaterial>& surfaceMaterial,
952-
const MaterialData& renderMaterialData,
953-
const DrawCallState& drawCallState) {
942+
const RtSurfaceMaterial& SceneManager::createSurfaceMaterial( Rc<DxvkContext> ctx,
943+
const MaterialData& renderMaterialData,
944+
const DrawCallState& drawCallState) {
954945
ScopedCpuProfileZone();
955946
const bool hasTexcoords = drawCallState.hasTextureCoordinates();
956947
const auto renderMaterialDataType = renderMaterialData.getType();
@@ -963,7 +954,7 @@ namespace dxvk {
963954
Rc<DxvkSampler> sampler = originalSampler;
964955
// If the original sampler if valid and the new rendering material is not legacy type
965956
// go ahead with patching and maybe merging the sampler states
966-
if(originalSampler != nullptr && renderMaterialDataType != MaterialDataType::Legacy) {
957+
if (originalSampler != nullptr && renderMaterialDataType != MaterialDataType::Legacy) {
967958
DxvkSamplerCreateInfo samplerInfo = originalSampler->info(); // Use sampler create info struct as convenience
968959
renderMaterialData.populateSamplerInfo(samplerInfo);
969960

@@ -972,6 +963,26 @@ namespace dxvk {
972963
samplerInfo.borderColor);
973964
}
974965
uint32_t samplerIndex = trackSampler(sampler);
966+
uint32_t samplerIndex2 = UINT32_MAX;
967+
if (renderMaterialDataType == MaterialDataType::RayPortal) {
968+
samplerIndex2 = trackSampler(drawCallState.getMaterialData().getSampler2());
969+
}
970+
971+
XXH64_hash_t preCreationHash = renderMaterialData.getHash();
972+
if (renderMaterialDataType == MaterialDataType::Legacy) {
973+
preCreationHash = XXH64(&renderMaterialData.getLegacyMaterialData(), sizeof(LegacyMaterialData), preCreationHash);
974+
}
975+
preCreationHash = XXH64(&samplerIndex, sizeof(samplerIndex), preCreationHash);
976+
preCreationHash = XXH64(&samplerIndex2, sizeof(samplerIndex2), preCreationHash);
977+
preCreationHash = XXH64(&hasTexcoords, sizeof(hasTexcoords), preCreationHash);
978+
preCreationHash = XXH64(&drawCallState.isUsingRaytracedRenderTarget, sizeof(drawCallState.isUsingRaytracedRenderTarget), preCreationHash);
979+
980+
auto iter = m_preCreationSurfaceMaterialMap.find(preCreationHash);
981+
if (iter != m_preCreationSurfaceMaterialMap.end()) {
982+
return m_surfaceMaterialCache.at(iter->second);
983+
}
984+
985+
std::optional<RtSurfaceMaterial> surfaceMaterial;
975986

976987
if (renderMaterialDataType == MaterialDataType::Legacy || renderMaterialDataType == MaterialDataType::Opaque || drawCallState.isUsingRaytracedRenderTarget) {
977988
uint32_t albedoOpacityTextureIndex = kSurfaceMaterialInvalidTextureIndex;
@@ -1168,8 +1179,6 @@ namespace dxvk {
11681179
uint32_t maskTextureIndex2 = kSurfaceMaterialInvalidTextureIndex;
11691180
trackTexture(ctx, rayPortalMaterialData.getMaskTexture2(), maskTextureIndex2, hasTexcoords, false);
11701181

1171-
uint32_t samplerIndex2 = trackSampler(drawCallState.getMaterialData().getSampler2());
1172-
11731182
uint8_t rayPortalIndex = rayPortalMaterialData.getRayPortalIndex();
11741183
float rotationSpeed = rayPortalMaterialData.getRotationSpeed();
11751184
bool enableEmissive = rayPortalMaterialData.getEnableEmission();
@@ -1182,6 +1191,14 @@ namespace dxvk {
11821191

11831192
surfaceMaterial.emplace(rayPortalSurfaceMaterial);
11841193
}
1194+
1195+
assert(surfaceMaterial.has_value());
1196+
assert(surfaceMaterial->validate());
1197+
1198+
// Cache this
1199+
const uint32_t index = m_surfaceMaterialCache.track(*surfaceMaterial);
1200+
m_preCreationSurfaceMaterialMap[preCreationHash] = index;
1201+
return m_surfaceMaterialCache.at(index);
11851202
}
11861203

11871204
std::optional<XXH64_hash_t> SceneManager::findLegacyTextureHashByObjectPickingValue(uint32_t objectPickingValue) {

src/dxvk/rtx_render/rtx_scene_manager.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class ResourceCache {
7676
};
7777
SparseUniqueCache<RtSurfaceMaterial, SurfaceMaterialHashFn> m_surfaceMaterialCache;
7878
SparseUniqueCache<RtSurfaceMaterial, SurfaceMaterialHashFn> m_surfaceMaterialExtensionCache;
79+
fast_unordered_cache<uint32_t> m_preCreationSurfaceMaterialMap;
7980

8081
struct VolumeMaterialHashFn {
8182
size_t operator() (const RtVolumeMaterial& mat) const {
@@ -228,10 +229,9 @@ class SceneManager : public CommonDeviceObject, public ResourceCache {
228229
// Consumes a draw call state and updates the scene state accordingly
229230
uint64_t processDrawCallState(Rc<DxvkContext> ctx, const DrawCallState& blasInput, const MaterialData* replacementMaterialData);
230231

231-
void createSurfaceMaterial( Rc<DxvkContext> ctx,
232-
std::optional<RtSurfaceMaterial>& surfaceMaterial,
233-
const MaterialData& renderMaterialData,
234-
const DrawCallState& drawCallState);
232+
const RtSurfaceMaterial& createSurfaceMaterial( Rc<DxvkContext> ctx,
233+
const MaterialData& renderMaterialData,
234+
const DrawCallState& drawCallState);
235235

236236
// Updates ref counts for new buffers
237237
void updateBufferCache(RaytraceGeometry& newGeoData);

src/dxvk/rtx_render/rtx_texture.h

+13-3
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,21 @@ namespace dxvk {
144144

145145
XXH64_hash_t getImageHash() const {
146146
const DxvkImageView* resolvedImageView = getImageView();
147+
XXH64_hash_t result = 0;
148+
if (resolvedImageView) {
149+
result = resolvedImageView->image()->getHash();
150+
}
147151

148-
if (resolvedImageView)
149-
return resolvedImageView->image()->getHash();
152+
if (result == 0 && m_managedTexture.ptr() != nullptr) {
153+
// NOTE: only replacement textures should have an m_managedTexture pointer. To avoid changing game texture
154+
// hashes, all ImageHash modifications should be inside this block.
155+
const XXH64_hash_t assetDataHash = m_managedTexture->assetData->hash();
156+
result = XXH64(&assetDataHash, sizeof(assetDataHash), result);
157+
// Needed to distinguish materials that load the same file different ways (i.e. raw vs sRGB)
158+
result = XXH64(&m_uniqueKey, sizeof(m_uniqueKey), result);
159+
}
150160

151-
return 0;
161+
return result;
152162
}
153163

154164
size_t getUniqueKey() const {

0 commit comments

Comments
 (0)