Skip to content

Commit

Permalink
Merge branch 'reuseMaterial' into 'main'
Browse files Browse the repository at this point in the history
[REMIX-3800] cache and reuse RtSurfaceMaterial within the same frame

See merge request lightspeedrtx/dxvk-remix-nv!1217
  • Loading branch information
MarkEHenderson committed Dec 17, 2024
2 parents 2ca2a27 + daaffc2 commit 368525a
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 30 deletions.
5 changes: 4 additions & 1 deletion src/dxvk/rtx_render/rtx_material_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,10 @@
m_##name = clamp(m_##name, ranges.Min##name, ranges.Max##name);

#define WRITE_TEXTURE_HASH(name, usd_attr, type, minVal, maxVal, defaultVal) \
h ^= m_##name.getImageHash();
{ \
XXH64_hash_t imageHash = m_##name.getImageHash(); \
h = XXH64(&imageHash, sizeof(imageHash), h); \
}

#define WRITE_CONSTANT_HASH(name, usd_attr, type, minVal, maxVal, defaultVal) \
h = XXH64(&m_##name, sizeof(m_##name), h);
Expand Down
61 changes: 39 additions & 22 deletions src/dxvk/rtx_render/rtx_scene_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ namespace dxvk {
// We still need to clear caches even if the scene wasn't rendered
m_bufferCache.clear();
m_surfaceMaterialCache.clear();
m_preCreationSurfaceMaterialMap.clear();
m_surfaceMaterialExtensionCache.clear();
m_volumeMaterialCache.clear();

Expand Down Expand Up @@ -488,6 +489,9 @@ namespace dxvk {
m_uniqueObjectSearchDistance = RtxOptions::uniqueObjectDistance();
m_drawCallCache.rebuildSpatialMaps();
}

// Not currently safe to cache these across frames (due to texture indices and rtx options potentially changing)
m_preCreationSurfaceMaterialMap.clear();
}

void SceneManager::onFrameEndNoRTX() {
Expand Down Expand Up @@ -517,10 +521,7 @@ namespace dxvk {
if (pFogReplacement->getType() != MaterialDataType::Translucent) {
Logger::warn(str::format("Fog replacement materials must be translucent. Ignoring material for ", std::hex, m_fog.getHash()));
} else {
std::optional<RtSurfaceMaterial> surfaceMaterial {};

createSurfaceMaterial(ctx, surfaceMaterial, *pFogReplacement, input);
m_startInMediumMaterialIndex = m_surfaceMaterialCache.track(*surfaceMaterial);
createSurfaceMaterial(ctx, *pFogReplacement, input);
}
} else if (m_fog.mode == D3DFOG_NONE) {
// render the first unreplaced fog.
Expand Down Expand Up @@ -901,17 +902,8 @@ namespace dxvk {

// 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
const auto renderMaterialDataType = renderMaterialData.getType();
std::optional<RtSurfaceMaterial> surfaceMaterial{};

createSurfaceMaterial(ctx, surfaceMaterial, renderMaterialData, drawCallState);

assert(surfaceMaterial.has_value());
assert(surfaceMaterial->validate());

// Cache this
m_surfaceMaterialCache.track(*surfaceMaterial);

RtInstance* instance = m_instanceManager.processSceneObject(m_cameraManager, m_rayPortalManager, *pBlas, drawCallState, renderMaterialData, *surfaceMaterial);
const RtSurfaceMaterial& surfaceMaterial = createSurfaceMaterial(ctx, renderMaterialData, drawCallState);
RtInstance* instance = m_instanceManager.processSceneObject(m_cameraManager, m_rayPortalManager, *pBlas, drawCallState, renderMaterialData, surfaceMaterial);

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

void SceneManager::createSurfaceMaterial( Rc<DxvkContext> ctx,
std::optional<RtSurfaceMaterial>& surfaceMaterial,
const MaterialData& renderMaterialData,
const DrawCallState& drawCallState) {
const RtSurfaceMaterial& SceneManager::createSurfaceMaterial( Rc<DxvkContext> ctx,
const MaterialData& renderMaterialData,
const DrawCallState& drawCallState) {
ScopedCpuProfileZone();
const bool hasTexcoords = drawCallState.hasTextureCoordinates();
const auto renderMaterialDataType = renderMaterialData.getType();
Expand All @@ -963,7 +954,7 @@ namespace dxvk {
Rc<DxvkSampler> sampler = originalSampler;
// If the original sampler if valid and the new rendering material is not legacy type
// go ahead with patching and maybe merging the sampler states
if(originalSampler != nullptr && renderMaterialDataType != MaterialDataType::Legacy) {
if (originalSampler != nullptr && renderMaterialDataType != MaterialDataType::Legacy) {
DxvkSamplerCreateInfo samplerInfo = originalSampler->info(); // Use sampler create info struct as convenience
renderMaterialData.populateSamplerInfo(samplerInfo);

Expand All @@ -972,6 +963,26 @@ namespace dxvk {
samplerInfo.borderColor);
}
uint32_t samplerIndex = trackSampler(sampler);
uint32_t samplerIndex2 = UINT32_MAX;
if (renderMaterialDataType == MaterialDataType::RayPortal) {
samplerIndex2 = trackSampler(drawCallState.getMaterialData().getSampler2());
}

XXH64_hash_t preCreationHash = renderMaterialData.getHash();
if (renderMaterialDataType == MaterialDataType::Legacy) {
preCreationHash = XXH64(&renderMaterialData.getLegacyMaterialData(), sizeof(LegacyMaterialData), preCreationHash);
}
preCreationHash = XXH64(&samplerIndex, sizeof(samplerIndex), preCreationHash);
preCreationHash = XXH64(&samplerIndex2, sizeof(samplerIndex2), preCreationHash);
preCreationHash = XXH64(&hasTexcoords, sizeof(hasTexcoords), preCreationHash);
preCreationHash = XXH64(&drawCallState.isUsingRaytracedRenderTarget, sizeof(drawCallState.isUsingRaytracedRenderTarget), preCreationHash);

auto iter = m_preCreationSurfaceMaterialMap.find(preCreationHash);
if (iter != m_preCreationSurfaceMaterialMap.end()) {
return m_surfaceMaterialCache.at(iter->second);
}

std::optional<RtSurfaceMaterial> surfaceMaterial;

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

uint32_t samplerIndex2 = trackSampler(drawCallState.getMaterialData().getSampler2());

uint8_t rayPortalIndex = rayPortalMaterialData.getRayPortalIndex();
float rotationSpeed = rayPortalMaterialData.getRotationSpeed();
bool enableEmissive = rayPortalMaterialData.getEnableEmission();
Expand All @@ -1182,6 +1191,14 @@ namespace dxvk {

surfaceMaterial.emplace(rayPortalSurfaceMaterial);
}

assert(surfaceMaterial.has_value());
assert(surfaceMaterial->validate());

// Cache this
const uint32_t index = m_surfaceMaterialCache.track(*surfaceMaterial);
m_preCreationSurfaceMaterialMap[preCreationHash] = index;
return m_surfaceMaterialCache.at(index);
}

std::optional<XXH64_hash_t> SceneManager::findLegacyTextureHashByObjectPickingValue(uint32_t objectPickingValue) {
Expand Down
8 changes: 4 additions & 4 deletions src/dxvk/rtx_render/rtx_scene_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class ResourceCache {
};
SparseUniqueCache<RtSurfaceMaterial, SurfaceMaterialHashFn> m_surfaceMaterialCache;
SparseUniqueCache<RtSurfaceMaterial, SurfaceMaterialHashFn> m_surfaceMaterialExtensionCache;
fast_unordered_cache<uint32_t> m_preCreationSurfaceMaterialMap;

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

void createSurfaceMaterial( Rc<DxvkContext> ctx,
std::optional<RtSurfaceMaterial>& surfaceMaterial,
const MaterialData& renderMaterialData,
const DrawCallState& drawCallState);
const RtSurfaceMaterial& createSurfaceMaterial( Rc<DxvkContext> ctx,
const MaterialData& renderMaterialData,
const DrawCallState& drawCallState);

// Updates ref counts for new buffers
void updateBufferCache(RaytraceGeometry& newGeoData);
Expand Down
16 changes: 13 additions & 3 deletions src/dxvk/rtx_render/rtx_texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,21 @@ namespace dxvk {

XXH64_hash_t getImageHash() const {
const DxvkImageView* resolvedImageView = getImageView();
XXH64_hash_t result = 0;
if (resolvedImageView) {
result = resolvedImageView->image()->getHash();
}

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

return 0;
return result;
}

size_t getUniqueKey() const {
Expand Down

0 comments on commit 368525a

Please sign in to comment.