Skip to content

Commit

Permalink
Avoid calling ArResolver::OpenAsset multiple times when
Browse files Browse the repository at this point in the history
opening a .usd layer.

This change adds private API to the .usda and .usdc file
formats to read from a given ArAsset. The .usd file format
now calls OpenAsset itself to retrieve the ArAsset and
then passes it directly to the file formats.

Fixes #1613

(Internal change: 2190915)
  • Loading branch information
sunyab authored and pixar-oss committed Sep 29, 2021
1 parent f482550 commit 2edb141
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 40 deletions.
18 changes: 18 additions & 0 deletions pxr/usd/sdf/textFileFormat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,14 @@ SdfTextFileFormat::CanRead(const string& filePath) const
return asset && _CanReadImpl(asset, GetFileCookie());
}

bool
SdfTextFileFormat::_CanReadFromAsset(
const std::string& resolvedPath,
const std::shared_ptr<ArAsset>& asset) const
{
return _CanReadImpl(asset, GetFileCookie());
}

bool
SdfTextFileFormat::Read(
SdfLayer* layer,
Expand All @@ -159,6 +167,16 @@ SdfTextFileFormat::Read(
return false;
}

return _ReadFromAsset(layer, resolvedPath, asset, metadataOnly);
}

bool
SdfTextFileFormat::_ReadFromAsset(
SdfLayer* layer,
const string& resolvedPath,
const std::shared_ptr<ArAsset>& asset,
bool metadataOnly) const
{
// Quick check to see if the file has the magic cookie before spinning up
// the parser.
if (!_CanReadImpl(asset, GetFileCookie())) {
Expand Down
16 changes: 16 additions & 0 deletions pxr/usd/sdf/textFileFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ TF_DECLARE_WEAK_AND_REF_PTRS(SdfTextFileFormat);

SDF_DECLARE_HANDLES(SdfSpec);

class ArAsset;

/// \class SdfTextFileFormat
///
/// Sdf text file format
Expand Down Expand Up @@ -111,6 +113,20 @@ class SdfTextFileFormat : public SdfFileFormat
const TfToken& versionString = TfToken(),
const TfToken& target = TfToken());

/// Return true if layer can be read from \p asset at \p resolvedPath.
SDF_API
bool _CanReadFromAsset(
const std::string& resolvedPath,
const std::shared_ptr<ArAsset>& asset) const;

/// Read layer from \p asset at \p resolvedPath into \p layer.
SDF_API
bool _ReadFromAsset(
SdfLayer* layer,
const std::string& resolvedPath,
const std::shared_ptr<ArAsset>& asset,
bool metadataOnly) const;

private:
// Override to return false. Reloading anonymous text layers clears their
// content.
Expand Down
21 changes: 19 additions & 2 deletions pxr/usd/usd/crateData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,14 @@ class Usd_CrateDataImpl
return false;
}

bool Open(string const &assetPath) {
template <class ...Args>
bool Open(string const& assetPath, Args&&... args) {
TfAutoMallocTag tag("Usd_CrateDataImpl::Open");

TF_DESCRIBE_SCOPE("Opening usd binary asset @%s@", assetPath.c_str());

if (auto newData = CrateFile::Open(assetPath)) {
if (auto newData =
CrateFile::Open(assetPath, std::forward<Args>(args)...)) {
_crateFile = std::move(newData);
return _PopulateFromCrateFile();
}
Expand Down Expand Up @@ -1278,6 +1280,14 @@ Usd_CrateData::CanRead(string const &assetPath)
return CrateFile::CanRead(assetPath);
}

/* static */
bool
Usd_CrateData::CanRead(string const &assetPath,
std::shared_ptr<ArAsset> const &asset)
{
return CrateFile::CanRead(assetPath, asset);
}

bool
Usd_CrateData::Save(string const &fileName)
{
Expand All @@ -1303,6 +1313,13 @@ Usd_CrateData::Open(const std::string &assetPath)
return _impl->Open(assetPath);
}

bool
Usd_CrateData::Open(const std::string &assetPath,
const std::shared_ptr<ArAsset> &asset)
{
return _impl->Open(assetPath, asset);
}

// ------------------------------------------------------------------------- //
// Abstract Data Implementation.
//
Expand Down
7 changes: 7 additions & 0 deletions pxr/usd/usd/crateData.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

PXR_NAMESPACE_OPEN_SCOPE

class ArAsset;

/// \class Usd_CrateData
///
Expand All @@ -50,8 +51,14 @@ class Usd_CrateData : public SdfAbstractData
static TfToken const &GetSoftwareVersionToken();

static bool CanRead(const std::string &assetPath);
static bool CanRead(const std::string &assetPath,
const std::shared_ptr<ArAsset> &asset);

bool Save(const std::string &fileName);

bool Open(const std::string &assetPath);
bool Open(const std::string &assetPath,
const std::shared_ptr<ArAsset> &asset);

virtual bool StreamsData() const;
virtual void CreateSpec(const SdfPath &path,
Expand Down
25 changes: 18 additions & 7 deletions pxr/usd/usd/crateFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2102,14 +2102,19 @@ struct CrateFile::_ValueHandler : public _ArrayValueHandlerBase<T> {};
////////////////////////////////////////////////////////////////////////
// CrateFile

/*static*/ bool
CrateFile::CanRead(string const &assetPath) {
/*static*/
bool
CrateFile::CanRead(string const &assetPath)
{
// Fetch the asset from Ar.
auto asset = ArGetResolver().OpenAsset(ArResolvedPath(assetPath));
if (!asset) {
return false;
}
return asset && CanRead(assetPath, asset);
}

/*static*/
bool
CrateFile::CanRead(string const &assetPath, ArAssetSharedPtr const &asset)
{
// If the asset has a file, mark it random access to avoid prefetch.
FILE *file; size_t offset;
std::tie(file, offset) = asset->GetFileUnsafe();
Expand Down Expand Up @@ -2181,13 +2186,19 @@ CrateFile::_MmapFile(char const *fileName, FILE *file)
/* static */
std::unique_ptr<CrateFile>
CrateFile::Open(string const &assetPath)
{
TfAutoMallocTag tag2("Usd_CrateFile::CrateFile::Open");
return Open(
assetPath, ArGetResolver().OpenAsset(ArResolvedPath(assetPath)));
}

std::unique_ptr<CrateFile>
CrateFile::Open(string const &assetPath, ArAssetSharedPtr const &asset)
{
TfAutoMallocTag tag2("Usd_CrateFile::CrateFile::Open");

std::unique_ptr<CrateFile> result;

// Fetch the asset from Ar.
auto asset = ArGetResolver().OpenAsset(ArResolvedPath(assetPath));
if (!asset) {
TF_RUNTIME_ERROR("Failed to open asset '%s'", assetPath.c_str());
return result;
Expand Down
4 changes: 4 additions & 0 deletions pxr/usd/usd/crateFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -574,13 +574,17 @@ class CrateFile
~CrateFile();

static bool CanRead(string const &assetPath);
static bool CanRead(string const &assetPath, ArAssetSharedPtr const &asset);

static TfToken const &GetSoftwareVersionToken();
TfToken GetFileVersionToken() const;

static std::unique_ptr<CrateFile> CreateNew();

// Return nullptr on failure.
static std::unique_ptr<CrateFile> Open(string const &assetPath);
static std::unique_ptr<CrateFile> Open(string const &assetPath,
ArAssetSharedPtr const &asset);

// Helper for saving to a file.
struct Packer {
Expand Down
81 changes: 54 additions & 27 deletions pxr/usd/usd/usdFileFormat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "pxr/usd/usd/usdaFileFormat.h"
#include "pxr/usd/usd/usdcFileFormat.h"

#include "pxr/usd/ar/resolver.h"
#include "pxr/usd/sdf/layer.h"

#include "pxr/base/trace/trace.h"
Expand Down Expand Up @@ -62,26 +63,27 @@ _GetFileFormat(const TfToken& formatId)
return fileFormat;
}

// A .usd file may actually be either a text .usda file or a binary crate
// .usdc file. These functions returns the appropriate file format for a
// given file or data object.
static
SdfFileFormatConstPtr
_GetUnderlyingFileFormat(const string& filePath)
const UsdUsdcFileFormatConstPtr&
_GetUsdcFileFormat()
{
auto usdcFormat = _GetFileFormat(UsdUsdcFileFormatTokens->Id);
if (usdcFormat->CanRead(filePath)) {
return usdcFormat;
}

auto usdaFormat = _GetFileFormat(UsdUsdaFileFormatTokens->Id);
if (usdaFormat->CanRead(filePath)) {
return usdaFormat;
}
static const auto usdcFormat = TfDynamic_cast<UsdUsdcFileFormatConstPtr>(
_GetFileFormat(UsdUsdcFileFormatTokens->Id));
return usdcFormat;
}

return SdfFileFormatConstPtr();
static
const UsdUsdaFileFormatConstPtr&
_GetUsdaFileFormat()
{
static const auto usdaFormat = TfDynamic_cast<UsdUsdaFileFormatConstPtr>(
_GetFileFormat(UsdUsdaFileFormatTokens->Id));
return usdaFormat;
}

// A .usd file may actually be either a text .usda file or a binary crate
// .usdc file. This function returns the appropriate file format for a
// given data object.
static
SdfFileFormatConstPtr
_GetUnderlyingFileFormat(const SdfAbstractDataConstPtr& data)
Expand Down Expand Up @@ -191,7 +193,10 @@ UsdUsdFileFormat::InitData(const FileFormatArguments& args) const
bool
UsdUsdFileFormat::CanRead(const string& filePath) const
{
return _GetUnderlyingFileFormat(filePath) != SdfFileFormatConstPtr();
auto asset = ArGetResolver().OpenAsset(ArResolvedPath(filePath));
return asset &&
(_GetUsdcFileFormat()->_CanReadFromAsset(filePath, asset) ||
_GetUsdaFileFormat()->_CanReadFromAsset(filePath, asset));
}

bool
Expand All @@ -202,26 +207,48 @@ UsdUsdFileFormat::Read(
{
TRACE_FUNCTION();

// Try binary usdc format first, since that's most common, then usda text.
static auto formats = {
_GetFileFormat(UsdUsdcFileFormatTokens->Id),
_GetFileFormat(UsdUsdaFileFormatTokens->Id),
};
// Fetch the asset from Ar.
auto asset = ArGetResolver().OpenAsset(ArResolvedPath(resolvedPath));
if (!asset) {
return false;
}

const auto& usdcFileFormat = _GetUsdcFileFormat();
const auto& usdaFileFormat = _GetUsdaFileFormat();

// Network-friendly path -- just try to read the file and if we get one that
// works we're good.
for (auto const &fmt: formats) {
//
// Try binary usdc format first, since that's most common, then usda text.
{
TfErrorMark m;
if (fmt && fmt->Read(layer, resolvedPath, metadataOnly))
if (usdcFileFormat->_ReadFromAsset(
layer, resolvedPath, asset, metadataOnly)) {
return true;
}
m.Clear();

if (usdaFileFormat->_ReadFromAsset(
layer, resolvedPath, asset, metadataOnly)) {
return true;
}
m.Clear();
}

// Failed to load. Do the slower (for the network) version where we attempt
// to determine the underlying format first, and then load using it.
auto underlyingFormat = _GetUnderlyingFileFormat(resolvedPath);
return underlyingFormat &&
underlyingFormat->Read(layer, resolvedPath, metadataOnly);
// to determine the underlying format first, and then load using it. This
// gives us better diagnostic messages.
if (usdcFileFormat->_CanReadFromAsset(resolvedPath, asset)) {
return usdcFileFormat->_ReadFromAsset(
layer, resolvedPath, asset, metadataOnly);
}

if (usdaFileFormat->_CanReadFromAsset(resolvedPath, asset)) {
return usdaFileFormat->_ReadFromAsset(
layer, resolvedPath, asset, metadataOnly);
}

return false;
}

SdfFileFormatConstPtr
Expand Down
5 changes: 2 additions & 3 deletions pxr/usd/usd/usdaFileFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@

PXR_NAMESPACE_OPEN_SCOPE


#define USD_USDA_FILE_FORMAT_TOKENS \
((Id, "usda")) \
((Version, "1.0"))
Expand All @@ -51,10 +50,10 @@ class UsdUsdaFileFormat : public SdfTextFileFormat
SDF_FILE_FORMAT_FACTORY_ACCESS;

UsdUsdaFileFormat();

virtual ~UsdUsdaFileFormat();
};

friend class UsdUsdFileFormat;
};

PXR_NAMESPACE_CLOSE_SCOPE

Expand Down
31 changes: 30 additions & 1 deletion pxr/usd/usd/usdcFileFormat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,18 +82,47 @@ UsdUsdcFileFormat::CanRead(const string& filePath) const
return Usd_CrateData::CanRead(filePath);
}

bool
UsdUsdcFileFormat::_CanReadFromAsset(const string& filePath,
const std::shared_ptr<ArAsset>& asset) const
{
return Usd_CrateData::CanRead(filePath, asset);
}

bool
UsdUsdcFileFormat::Read(SdfLayer* layer,
const string& resolvedPath,
bool metadataOnly) const
{
TRACE_FUNCTION();
return _ReadHelper(layer, resolvedPath, metadataOnly);
}

bool
UsdUsdcFileFormat::_ReadFromAsset(SdfLayer* layer,
const string& resolvedPath,
const std::shared_ptr<ArAsset>& asset,
bool metadataOnly) const
{
TRACE_FUNCTION();
return _ReadHelper(layer, resolvedPath, metadataOnly, asset);
}

template <class ...Args>
bool
UsdUsdcFileFormat::_ReadHelper(
SdfLayer* layer,
const std::string& resolvedPath,
bool metadataOnly,
Args&&... args) const
{
SdfAbstractDataRefPtr data = InitData(layer->GetFileFormatArguments());
auto crateData = TfDynamic_cast<Usd_CrateDataRefPtr>(data);

if (!crateData || !crateData->Open(resolvedPath))
if (!crateData ||
!crateData->Open(resolvedPath, std::forward<Args>(args)...)) {
return false;
}

_SetLayerData(layer, data);
return true;
Expand Down
Loading

0 comments on commit 2edb141

Please sign in to comment.