Instrumented support for the JSON importer for material type files.

I also noticed that JsonFileLoadContext was no longer used (see https://github.com/o3de/o3de/pull/7010) so I was able to remove all that code.

Signed-off-by: santorac <55155825+santorac@users.noreply.github.com>
This commit is contained in:
santorac
2022-01-28 13:45:58 -08:00
parent fa037d5d7d
commit d9c646062b
11 changed files with 84 additions and 115 deletions
@@ -1,36 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/RTTI/TypeInfo.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/string/string_view.h>
#include <AzCore/std/containers/vector.h>
namespace AZ
{
namespace RPI
{
//! Settings for custom JSON serializers to get context about loading a file
class JsonFileLoadContext final
{
public:
AZ_TYPE_INFO(JsonFileLoadContext, "{314942B3-A74A-49D2-822D-CD56F8E3C0F8}");
void PushFilePath(AZStd::string path);
AZStd::string_view GetFilePath() const;
void PopFilePath();
private:
// Using vector instead of stack because stack doesn't have a copy constructor
AZStd::vector<AZStd::string> m_thisFilePath;
};
} // namespace RPI
} // namespace AZ
@@ -11,7 +11,6 @@
#include <AzCore/JSON/document.h>
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
namespace AZ
@@ -52,13 +51,9 @@ namespace AZ
rapidjson::Document& document = loadOutcome.GetValue();
AZ::RPI::JsonFileLoadContext fileLoadContext;
fileLoadContext.PushFilePath(path);
AZ::JsonDeserializerSettings jsonSettings;
AZ::RPI::JsonReportingHelper reportingHelper;
reportingHelper.Attach(jsonSettings);
jsonSettings.m_metadata.Add(AZStd::move(fileLoadContext));
AZ::JsonSerialization::Load(objectData, document, jsonSettings);
if (reportingHelper.ErrorsReported())
@@ -48,11 +48,11 @@ namespace AZ
//! @return if resolving is successful. An error will be reported if it fails.
bool ResolveMaterialPropertyEnumValue(const MaterialPropertyDescriptor* propertyDescriptor, const AZ::Name& enumName, MaterialPropertyValue& outResolvedValue);
//! Load material type from a json file. If the file path is relative, the loaded json document must be provided.
//! Load material type from a json file or document.
//! Otherwise, it will use the passed in document first if not null, or load the json document from the path.
//! @param filePath a relative path if document is provided, an absolute path if document is not provided.
//! @param document the loaded json document.
AZ::Outcome<MaterialTypeSourceData> LoadMaterialTypeSourceData(const AZStd::string& filePath, const rapidjson::Value* document = nullptr);
//! @param filePath path to the JSON file to load, unless the @document is already provided. In either case, this path will be used to resolve any relative file references.
//! @param document an optional already loaded json document.
AZ::Outcome<MaterialTypeSourceData> LoadMaterialTypeSourceData(const AZStd::string& filePath, rapidjson::Document* document = nullptr);
//! Utility function for custom JSON serializers to report results as "Skipped" when encountering keys that aren't recognized
//! as part of the custom format.
@@ -11,7 +11,6 @@
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
#include <Atom/RPI.Edit/Material/MaterialUtils.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
#include <Atom/RPI.Edit/Common/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
@@ -139,11 +138,6 @@ namespace AZ
JsonReportingHelper reportingHelper;
reportingHelper.Attach(settings);
// This is required by some custom material serializers to support relative path references.
JsonFileLoadContext fileLoadContext;
fileLoadContext.PushFilePath(filePath);
settings.m_metadata.Add(fileLoadContext);
JsonSerialization::Load(material, value, settings);
if (reportingHelper.ErrorsReported())
@@ -1,39 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
namespace AZ
{
namespace RPI
{
// Note, we use string not string_view on purpose because m_thisFilePath.push_back() will make a new string anyway.
void JsonFileLoadContext::PushFilePath(AZStd::string path)
{
m_thisFilePath.push_back(AZStd::move(path));
}
AZStd::string_view JsonFileLoadContext::GetFilePath() const
{
if (m_thisFilePath.empty())
{
return "";
}
else
{
return m_thisFilePath.back();
}
}
void JsonFileLoadContext::PopFilePath()
{
m_thisFilePath.pop_back();
}
} // namespace RPI
} // namespace AZ
@@ -9,7 +9,6 @@
#include <Atom/RPI.Edit/Material/MaterialFunctorSourceDataSerializer.h>
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
#include <Atom/RPI.Edit/Material/MaterialFunctorSourceDataRegistration.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
@@ -14,7 +14,6 @@
#include <Atom/RPI.Edit/Material/MaterialConverterBus.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
#include <Atom/RPI.Edit/Common/JsonUtils.h>
@@ -14,11 +14,11 @@
#include <Atom/RPI.Reflect/Material/MaterialTypeAsset.h>
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
#include <Atom/RPI.Edit/Common/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
#include <AzCore/Serialization/Json/JsonSerializationResult.h>
#include <AzCore/Serialization/Json/JsonImporter.h>
#include <AzCore/Settings/SettingsRegistry.h>
#include <AzCore/std/string/string.h>
@@ -73,21 +73,29 @@ namespace AZ
outResolvedValue = enumValue;
return true;
}
AZ::Outcome<MaterialTypeSourceData> LoadMaterialTypeSourceData(const AZStd::string& filePath, const rapidjson::Value* document)
AZ::Outcome<MaterialTypeSourceData> LoadMaterialTypeSourceData(const AZStd::string& filePath, rapidjson::Document* document)
{
AZ::Outcome<rapidjson::Document, AZStd::string> loadOutcome;
rapidjson::Document localDocument;
if (document == nullptr)
{
loadOutcome = AZ::JsonSerializationUtils::ReadJsonFile(filePath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
AZ::Outcome<rapidjson::Document, AZStd::string> loadOutcome = AZ::JsonSerializationUtils::ReadJsonFile(filePath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!loadOutcome.IsSuccess())
{
AZ_Error("AZ::RPI::JsonUtils", false, "%s", loadOutcome.GetError().c_str());
return AZ::Failure();
}
document = &loadOutcome.GetValue();
localDocument = loadOutcome.TakeValue();
document = &localDocument;
}
AZ::BaseJsonImporter jsonImporter;
AZ::JsonImportSettings importSettings;
importSettings.m_importer = &jsonImporter;
importSettings.m_loadedJsonPath = filePath;
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::ResolveImports(document->GetObject(), document->GetAllocator(), importSettings);
MaterialTypeSourceData materialType;
@@ -96,11 +104,6 @@ namespace AZ
JsonReportingHelper reportingHelper;
reportingHelper.Attach(settings);
// This is required by some custom material serializers to support relative path references.
JsonFileLoadContext fileLoadContext;
fileLoadContext.PushFilePath(filePath);
settings.m_metadata.Add(fileLoadContext);
JsonSerialization::Load(materialType, *document, settings);
materialType.ConvertToNewDataFormat();
materialType.ResolveUvEnums();
@@ -16,7 +16,6 @@
#include <AzCore/IO/ByteContainerStream.h>
#include <AzCore/JSON/prettywriter.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
namespace UnitTest
{
@@ -46,17 +45,12 @@ namespace UnitTest
//! Uses JsonSerialization to load JSON data into a reflected object
template<typename T>
JsonTestResult LoadTestDataFromJson(T& object, rapidjson::Value& json, AZ::RPI::JsonFileLoadContext* jsonFileLoadContext = nullptr)
JsonTestResult LoadTestDataFromJson(T& object, rapidjson::Value& json)
{
JsonTestResult result;
AZ::JsonDeserializerSettings settings;
if (jsonFileLoadContext)
{
settings.m_metadata.Add(*jsonFileLoadContext);
}
settings.m_reporting = [&result](AZStd::string_view message, AZ::JsonSerializationResult::ResultCode resultCode, AZStd::string_view path)
{
JsonTestResult::Report report;
@@ -74,14 +68,14 @@ namespace UnitTest
//! Uses JsonSerialization to load JSON data from a string into a reflected object
template<typename T>
JsonTestResult LoadTestDataFromJson(T& object, AZStd::string_view jsonText, AZ::RPI::JsonFileLoadContext* jsonFileLoadContext = nullptr)
JsonTestResult LoadTestDataFromJson(T& object, AZStd::string_view jsonText)
{
auto parseResult = AZ::JsonSerializationUtils::ReadJsonString(jsonText);
EXPECT_TRUE(parseResult.IsSuccess()) << parseResult.GetError().c_str();
if (parseResult.IsSuccess())
{
return LoadTestDataFromJson(object, parseResult.GetValue(), jsonFileLoadContext);
return LoadTestDataFromJson(object, parseResult.GetValue());
}
else
{
@@ -16,11 +16,13 @@
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Material/MaterialFunctorSourceDataRegistration.h>
#include <Atom/RPI.Edit/Material/MaterialUtils.h>
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
#include <Atom/RPI.Reflect/Shader/ShaderOptionGroup.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <Atom/RPI.Public/Material/Material.h>
#include <AzCore/Utils/Utils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <AzFramework/StringFunc/StringFunc.h>
@@ -35,6 +37,7 @@ namespace UnitTest
{
protected:
AZ::IO::FixedMaxPath m_tempFolder;
RHI::Ptr<RHI::ShaderResourceGroupLayout> m_testMaterialSrgLayout;
Data::Asset<ShaderAsset> m_testShaderAsset;
Data::Asset<ShaderAsset> m_testShaderAsset2;
@@ -329,6 +332,9 @@ namespace UnitTest
AZStd::string testImageFilepathAbsolute(TestImageFilepathAbsolute);
AzFramework::StringFunc::Path::Normalize(testImageFilepathAbsolute);
m_assetSystemStub.RegisterSourceInfo(testImageFilepathAbsolute.c_str(), testImageAssetInfo2, "");
m_tempFolder = AZ::Utils::GetExecutableDirectory();
m_tempFolder = m_tempFolder/"temp"/"MaterialTypeSourceDataTest";
}
void TearDown() override
@@ -1473,6 +1479,8 @@ namespace UnitTest
{
// Note that serialization of individual fields within material properties is thoroughly tested in
// MaterialPropertySerializerTests, so the sample property data used here is cursory.
// We also don't cover fields related to providing name contexts for nested property groups, like
// "shaderInputPrefix" and "shaderOptionPrefix" as those are covered in CreateMaterialTypeAsset_NestedGroups*.
const AZStd::string inputJson = R"(
{
@@ -1701,7 +1709,7 @@ namespace UnitTest
JsonTestResult storeResult = StoreTestDataToJson(material, outputJson);
ExpectSimilarJson(inputJson, outputJson);
}
TEST_F(MaterialTypeSourceDataTests, LoadAllFieldsUsingOldFormat)
{
// The content of this test was copied from LoadAndStoreJson_AllFields to prove backward compatibility.
@@ -1963,4 +1971,58 @@ namespace UnitTest
errorMessageFinder.CheckExpectedErrorsFound();
}
TEST_F(MaterialTypeSourceDataTests, LoadWithImportedJson)
{
const AZStd::string propertyGroupJson = R"(
{
"name": "myGroup",
"displayName": "My Group",
"description": "This group is defined in a separate JSON file",
"properties": [
{
"name": "foo",
"type": "Bool"
},
{
"name": "bar",
"type": "Float"
}
]
}
)";
IO::FixedMaxPath propertyGroupJsonFilePath = m_tempFolder/"MyPropertyGroup.json";
AZ::Utils::WriteFile(propertyGroupJson, propertyGroupJsonFilePath.c_str());
const AZStd::string materialTypeJson = R"(
{
"propertyLayout": {
"propertyGroups": [
{ "$import": "MyPropertyGroup.json" }
]
}
}
)";
IO::FixedMaxPath materialTypeJsonFilePath = m_tempFolder/"TestImport.materialtype";
AZ::Utils::WriteFile(materialTypeJson, materialTypeJsonFilePath.c_str());
auto loadMaterialTypeResult = MaterialUtils::LoadMaterialTypeSourceData(materialTypeJsonFilePath.c_str());
EXPECT_TRUE(loadMaterialTypeResult);
MaterialTypeSourceData materialType = loadMaterialTypeResult.TakeValue();
EXPECT_EQ(materialType.GetPropertyLayout().m_propertyGroups.size(), 1);
EXPECT_TRUE(materialType.FindPropertyGroup("myGroup") != nullptr);
EXPECT_EQ(materialType.FindPropertyGroup("myGroup")->GetDisplayName(), "My Group");
EXPECT_EQ(materialType.FindPropertyGroup("myGroup")->GetDescription(), "This group is defined in a separate JSON file");
EXPECT_EQ(materialType.FindPropertyGroup("myGroup")->GetProperties().size(), 2);
EXPECT_NE(materialType.FindProperty("myGroup.foo"), nullptr);
EXPECT_NE(materialType.FindProperty("myGroup.bar"), nullptr);
EXPECT_EQ(materialType.FindProperty("myGroup.foo")->GetName(), "foo");
EXPECT_EQ(materialType.FindProperty("myGroup.bar")->GetName(), "bar");
EXPECT_EQ(materialType.FindProperty("myGroup.foo")->m_dataType, MaterialPropertyDataType::Bool);
EXPECT_EQ(materialType.FindProperty("myGroup.bar")->m_dataType, MaterialPropertyDataType::Float);
}
}
@@ -11,7 +11,6 @@ set(FILES
Include/Atom/RPI.Edit/Common/AssetAliasesSourceData.h
Include/Atom/RPI.Edit/Common/ColorUtils.h
Include/Atom/RPI.Edit/Common/ConvertibleSource.h
Include/Atom/RPI.Edit/Common/JsonFileLoadContext.h
Include/Atom/RPI.Edit/Common/JsonReportingHelper.h
Include/Atom/RPI.Edit/Common/JsonUtils.h
Include/Atom/RPI.Edit/Material/LuaMaterialFunctorSourceData.h
@@ -56,7 +55,6 @@ set(FILES
Source/RPI.Edit/Common/AssetAliasesSourceData.cpp
Source/RPI.Edit/Common/ColorUtils.cpp
Source/RPI.Edit/Common/ConvertibleSource.cpp
Source/RPI.Edit/Common/JsonFileLoadContext.cpp
Source/RPI.Edit/Common/JsonReportingHelper.cpp
Source/RPI.Edit/Common/JsonUtils.cpp
)