Skip to content

Commit

Permalink
Use reference counting to manage the lifetime of HdVP2TextureInfo. Th…
Browse files Browse the repository at this point in the history
…is allows textures to be deleted when all materials using that texture are destroyed.
  • Loading branch information
krickw committed Feb 28, 2022
1 parent 7e550af commit 36685b9
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 29 deletions.
62 changes: 38 additions & 24 deletions lib/mayaUsd/render/vp2RenderDelegate/material.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1318,7 +1318,7 @@ class HdVP2Material::TextureLoadingTask
std::mutex HdVP2Material::_refreshMutex;
std::chrono::steady_clock::time_point HdVP2Material::_startTime;
std::atomic_size_t HdVP2Material::_runningTasksCounter;
HdVP2TextureMap HdVP2Material::_textureMap;
HdVP2GlobalTextureMap HdVP2Material::_globalTextureMap;

/*! \brief Releases the reference to the texture owned by a smart pointer.
*/
Expand Down Expand Up @@ -2492,9 +2492,16 @@ const HdVP2TextureInfo& HdVP2Material::_AcquireTexture(
const std::string& path,
const HdMaterialNode& node)
{
const auto it = _textureMap.find(path);
if (it != _textureMap.end()) {
return it->second;
// see if we already have the texture loaded.
const auto it = _globalTextureMap.find(path);
if (it != _globalTextureMap.end()) {
HdVP2TextureInfoSharedPtr cacheEntry = it->second.lock();
if (cacheEntry) {
_localTextureMap[path] = cacheEntry;
return *cacheEntry;
}
// if cacheEntry is nullptr then there is a stale entry in the _globalTextureMap. No need
// to erase it because we're going to re-fill that entry right now.
}

// Get fallback color if defined
Expand All @@ -2513,18 +2520,22 @@ const HdVP2TextureInfo& HdVP2Material::_AcquireTexture(
MHWRender::MTexture* texture
= _LoadTexture(path, hasFallbackColor, fallbackColor, isSRGB, uvScaleOffset);

HdVP2TextureInfo& info = _textureMap[path];
info._texture.reset(texture);
info._isColorSpaceSRGB = isSRGB;
HdVP2TextureInfoSharedPtr info = std::make_shared<HdVP2TextureInfo>();
_localTextureMap.insert_or_assign(
path, info); // should never have already been in _localTextureMap, because if it was
// we'd have found it in _globalTextureMap
_globalTextureMap.insert_or_assign(path, info);
info->_texture.reset(texture);
info->_isColorSpaceSRGB = isSRGB;
if (uvScaleOffset.length() > 0) {
TF_VERIFY(uvScaleOffset.length() == 4);
info._stScale.Set(
info->_stScale.Set(
uvScaleOffset[0], uvScaleOffset[1]); // The first 2 elements are the scale
info._stOffset.Set(
info->_stOffset.Set(
uvScaleOffset[2], uvScaleOffset[3]); // The next two elements are the offset
}

return info;
return *info;
}

auto* task = new TextureLoadingTask(this, sceneDelegate, path, hasFallbackColor, fallbackColor);
Expand Down Expand Up @@ -2581,20 +2592,23 @@ void HdVP2Material::_UpdateLoadedTexture(
// function on idle to delete the task object.
_textureLoadingTasks.erase(path);

// Check the local cache again, do not overwrite if same texture has
// been loaded asynchronously
if (_textureMap.find(path) != _textureMap.end()) {
return;
}

HdVP2TextureInfo& info = _textureMap[path];
info._texture.reset(texture);
info._isColorSpaceSRGB = isColorSpaceSRGB;
if (uvScaleOffset.length() > 0) {
TF_VERIFY(uvScaleOffset.length() == 4);
info._stScale.Set(uvScaleOffset[0], uvScaleOffset[1]); // The first 2 elements are the scale
info._stOffset.Set(
uvScaleOffset[2], uvScaleOffset[3]); // The next two elements are the offset
// Check the cache again. If the texture is not in the cache
// the add it.
if (_globalTextureMap.find(path) == _globalTextureMap.end()) {
HdVP2TextureInfoSharedPtr info = std::make_shared<HdVP2TextureInfo>();
_localTextureMap.insert_or_assign(
path, info); // should never have already been in _localTextureMap, because if it was
// we'd have found it in _globalTextureMap
_globalTextureMap.insert_or_assign(path, info);
info->_texture.reset(texture);
info->_isColorSpaceSRGB = isColorSpaceSRGB;
if (uvScaleOffset.length() > 0) {
TF_VERIFY(uvScaleOffset.length() == 4);
info->_stScale.Set(
uvScaleOffset[0], uvScaleOffset[1]); // The first 2 elements are the scale
info->_stOffset.Set(
uvScaleOffset[2], uvScaleOffset[3]); // The next two elements are the offset
}
}

// Mark sprim dirty
Expand Down
23 changes: 18 additions & 5 deletions lib/mayaUsd/render/vp2RenderDelegate/material.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,21 @@ struct HdVP2TextureInfo
bool _isColorSpaceSRGB { false }; //!< Whether sRGB linearization is needed
};

using HdVP2TextureInfoSharedPtr = std::shared_ptr<HdVP2TextureInfo>;
using HdVP2TextureInfoWeakPtr = std::weak_ptr<HdVP2TextureInfo>;

/*! \brief An unordered string-indexed map to cache texture information.
Maya has a global internal texture map but we can't rely on it here, because we miss out
on the extra information we store, such as _isColorSpaceSRGB. In HdVP2GlobalTextureMap we
have that additional information.
In order to correctly delete textures when they are no longer in use the global texture map
holds only a weak_ptr to the HdVP2TextureInfo. The individual materials hold shared_ptrs to
the textures they are using, so that when no materials are using a texture it'll be deleted.
*/
using HdVP2TextureMap = std::unordered_map<std::string, HdVP2TextureInfo>;
using HdVP2LocalTextureMap = std::unordered_map<std::string, HdVP2TextureInfoSharedPtr>;
using HdVP2GlobalTextureMap = std::unordered_map<std::string, HdVP2TextureInfoWeakPtr>;

/*! \brief A VP2-specific implementation for a Hydra material prim.
\class HdVP2Material
Expand Down Expand Up @@ -147,10 +159,11 @@ class HdVP2Material final : public HdMaterial

TfToken _surfaceNetworkToken; //!< Generated token to uniquely identify a material network

HdVP2ShaderUniquePtr _surfaceShader; //!< VP2 surface shader instance
SdfPath _surfaceShaderId; //!< Path of the surface shader
static HdVP2TextureMap _textureMap; //!< Textures used by this material
TfTokenVector _requiredPrimvars; //!< primvars required by this material
HdVP2ShaderUniquePtr _surfaceShader; //!< VP2 surface shader instance
SdfPath _surfaceShaderId; //!< Path of the surface shader
static HdVP2GlobalTextureMap _globalTextureMap; //!< Texture in use by all materials in MayaUSD
HdVP2LocalTextureMap _localTextureMap; //!< Textures used by this material
TfTokenVector _requiredPrimvars; //!< primvars required by this material

std::unordered_map<std::string, TextureLoadingTask*> _textureLoadingTasks;

Expand Down

0 comments on commit 36685b9

Please sign in to comment.