Atom Tools: Moving shader management console file operations into document class

Standardizing how document classes are implemented between atom tools.
Moved several functions that were added to allow shader variant lists to be built from a Python script into the tools document class.
Reimplemented the portion of the script that generated a shader variant list from a shader asset into the document class. Opening a shader management console document from a shader asset will automatically generate this shader variant list data inside the document. Description now just opens and saves the documents to a new location.

Signed-off-by: Guthrie Adams <guthadam@amazon.com>
monroegm-disable-blank-issue-2
Guthrie Adams 4 years ago
parent 49cd9584f2
commit 2b16f6860f

@ -6,10 +6,16 @@
* *
*/ */
#include <AssetDatabase/AssetDatabaseConnection.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Common/JsonUtils.h> #include <Atom/RPI.Edit/Common/JsonUtils.h>
#include <Atom/RPI.Public/Material/Material.h>
#include <Atom/RPI.Reflect/Asset/AssetUtils.h> #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h> #include <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h>
#include <AzCore/Utils/Utils.h>
#include <AzFramework/StringFunc/StringFunc.h> #include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <Document/ShaderManagementConsoleDocument.h> #include <Document/ShaderManagementConsoleDocument.h>
namespace ShaderManagementConsole namespace ShaderManagementConsole
@ -32,10 +38,7 @@ namespace ShaderManagementConsole
AzFramework::StringFunc::Path::ReplaceExtension(shaderPath, AZ::RPI::ShaderAsset::Extension); AzFramework::StringFunc::Path::ReplaceExtension(shaderPath, AZ::RPI::ShaderAsset::Extension);
m_shaderAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath<AZ::RPI::ShaderAsset>(shaderPath.c_str()); m_shaderAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath<AZ::RPI::ShaderAsset>(shaderPath.c_str());
if (!m_shaderAsset) AZ_Error("ShaderManagementConsoleDocument", m_shaderAsset.IsReady(), "Could not load shader asset: %s.", shaderPath.c_str());
{
AZ_Error("ShaderManagementConsoleDocument", false, "Could not load shader asset: %s.", shaderPath.c_str());
}
AtomToolsFramework::AtomToolsDocumentNotificationBus::Event( AtomToolsFramework::AtomToolsDocumentNotificationBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentModified, m_id); m_toolId, &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentModified, m_id);
@ -107,17 +110,14 @@ namespace ShaderManagementConsole
return false; return false;
} }
if (!AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), AZ::RPI::ShaderVariantListSourceData::Extension)) if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), AZ::RPI::ShaderVariantListSourceData::Extension))
{ {
AZ_Error("ShaderManagementConsoleDocument", false, "Document extension is not supported: '%s.'", m_absolutePath.c_str());
return OpenFailed();
}
// Load the shader config data and create a shader config asset from it // Load the shader config data and create a shader config asset from it
AZ::RPI::ShaderVariantListSourceData sourceData; AZ::RPI::ShaderVariantListSourceData sourceData;
if (!AZ::RPI::JsonUtils::LoadObjectFromFile(m_absolutePath, sourceData)) if (!AZ::RPI::JsonUtils::LoadObjectFromFile(m_absolutePath, sourceData))
{ {
AZ_Error("ShaderManagementConsoleDocument", false, "Failed loading shader variant list data: '%s.'", m_absolutePath.c_str()); AZ_Error(
"ShaderManagementConsoleDocument", false, "Failed loading shader variant list data: '%s.'", m_absolutePath.c_str());
return OpenFailed(); return OpenFailed();
} }
@ -125,6 +125,85 @@ namespace ShaderManagementConsole
return IsOpen() ? OpenSucceeded() : OpenFailed(); return IsOpen() ? OpenSucceeded() : OpenFailed();
} }
if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), AZ::RPI::ShaderSourceData::Extension))
{
// Get info such as relative path of the file and asset id
bool result = false;
AZ::Data::AssetInfo shaderAssetInfo;
AZStd::string watchFolder;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
result, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, m_absolutePath.c_str(),
shaderAssetInfo, watchFolder);
if (!result)
{
AZ_Error(
"ShaderManagementConsoleDocument", false, "Failed to get the asset info for the file: %s.", m_absolutePath.c_str());
return OpenFailed();
}
// retrieves a list of all material source files that use the shader. Note that materials inherit from materialtype files, which
// are actual files that refer to shader files.
const auto& materialAssetIds = FindMaterialAssetsUsingShader(shaderAssetInfo.m_relativePath);
// This loop collects all uniquely-identified shader items used by the materials based on its shader variant id.
AZStd::set<AZ::RPI::ShaderVariantId> shaderVariantIds;
AZStd::vector<AZ::RPI::ShaderOptionGroup> shaderVariantListShaderOptionGroups;
for (const auto& materialAssetId : materialAssetIds)
{
const auto& materialInstanceShaderItems = GetMaterialInstanceShaderItems(materialAssetId);
for (const auto& shaderItem : materialInstanceShaderItems)
{
const auto& shaderAssetId = shaderItem.GetShaderAsset().GetId();
if (shaderAssetInfo.m_assetId == shaderAssetId)
{
const auto& shaderVariantId = shaderItem.GetShaderVariantId();
if (!shaderVariantId.IsEmpty() && shaderVariantIds.insert(shaderVariantId).second)
{
shaderVariantListShaderOptionGroups.push_back(shaderItem.GetShaderOptionGroup());
}
}
}
}
// Generate the shader variant list data by collecting shader option name-value pairs.s
AZ::RPI::ShaderVariantListSourceData shaderVariantList;
shaderVariantList.m_shaderFilePath = shaderAssetInfo.m_relativePath;
int stableId = 1;
for (const auto& shaderOptionGroup : shaderVariantListShaderOptionGroups)
{
AZ::RPI::ShaderVariantListSourceData::VariantInfo variantInfo;
variantInfo.m_stableId = stableId;
const auto& shaderOptionDescriptors = shaderOptionGroup.GetShaderOptionDescriptors();
for (const auto& shaderOptionDescriptor : shaderOptionDescriptors)
{
const auto& optionName = shaderOptionDescriptor.GetName();
const auto& optionValue = shaderOptionGroup.GetValue(optionName);
if (!optionValue.IsValid())
{
continue;
}
const auto& valueName = shaderOptionDescriptor.GetValueName(optionValue);
variantInfo.m_options[optionName.GetStringView()] = valueName.GetStringView();
}
if (!variantInfo.m_options.empty())
{
shaderVariantList.m_shaderVariants.push_back(variantInfo);
stableId++;
}
}
SetShaderVariantListSourceData(shaderVariantList);
return IsOpen() ? OpenSucceeded() : OpenFailed();
}
AZ_Error("ShaderManagementConsoleDocument", false, "Document extension is not supported: '%s.'", m_absolutePath.c_str());
return OpenFailed();
}
bool ShaderManagementConsoleDocument::Save() bool ShaderManagementConsoleDocument::Save()
{ {
if (!AtomToolsDocument::Save()) if (!AtomToolsDocument::Save())
@ -173,7 +252,8 @@ namespace ShaderManagementConsole
bool ShaderManagementConsoleDocument::IsSavable() const bool ShaderManagementConsoleDocument::IsSavable() const
{ {
return true; return IsOpen() &&
AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), AZ::RPI::ShaderVariantListSourceData::Extension);
} }
void ShaderManagementConsoleDocument::Clear() void ShaderManagementConsoleDocument::Clear()
@ -195,4 +275,94 @@ namespace ShaderManagementConsole
m_absolutePath = m_savePathNormalized; m_absolutePath = m_savePathNormalized;
return SaveSucceeded(); return SaveSucceeded();
} }
AZStd::vector<AZ::Data::AssetId> ShaderManagementConsoleDocument::FindMaterialAssetsUsingShader(const AZStd::string& shaderFilePath)
{
// Collect the material types referencing the shader
AZStd::vector<AZStd::string> materialTypeSources;
AzToolsFramework::AssetDatabase::AssetDatabaseConnection assetDatabaseConnection;
assetDatabaseConnection.OpenDatabase();
assetDatabaseConnection.QuerySourceDependencyByDependsOnSource(
shaderFilePath.c_str(), nullptr, AzToolsFramework::AssetDatabase::SourceFileDependencyEntry::DEP_Any,
[&](AzToolsFramework::AssetDatabase::SourceFileDependencyEntry& sourceFileDependencyEntry)
{
AZStd::string assetExtension;
if (AzFramework::StringFunc::Path::GetExtension(sourceFileDependencyEntry.m_source.c_str(), assetExtension, false))
{
if (assetExtension == "materialtype")
{
materialTypeSources.push_back(sourceFileDependencyEntry.m_source);
}
}
return true;
});
AzToolsFramework::AssetDatabase::ProductDatabaseEntryContainer productDependencies;
for (const auto& materialTypeSource : materialTypeSources)
{
bool result = false;
AZ::Data::AssetInfo materialTypeSourceAssetInfo;
AZStd::string watchFolder;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
result, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, materialTypeSource.c_str(),
materialTypeSourceAssetInfo, watchFolder);
assetDatabaseConnection.QueryDirectReverseProductDependenciesBySourceGuidSubId(
materialTypeSourceAssetInfo.m_assetId.m_guid, materialTypeSourceAssetInfo.m_assetId.m_subId,
[&](AzToolsFramework::AssetDatabase::ProductDatabaseEntry& entry)
{
AZStd::string assetExtension;
if (AzFramework::StringFunc::Path::GetExtension(entry.m_productName.c_str(), assetExtension, false))
{
if (assetExtension == "azmaterial")
{
productDependencies.push_back(entry);
}
}
return true;
});
}
AZStd::vector<AZ::Data::AssetId> results;
results.reserve(productDependencies.size());
for (auto product : productDependencies)
{
assetDatabaseConnection.QueryCombinedByProductID(
product.m_productID,
[&](AzToolsFramework::AssetDatabase::CombinedDatabaseEntry& combined)
{
results.push_back({ combined.m_sourceGuid, combined.m_subID });
return false;
},
nullptr);
}
return results;
}
AZStd::vector<AZ::RPI::ShaderCollection::Item> ShaderManagementConsoleDocument::GetMaterialInstanceShaderItems(
const AZ::Data::AssetId& assetId)
{
auto materialAsset = AZ::RPI::AssetUtils::LoadAssetById<AZ::RPI::MaterialAsset>(assetId, AZ::RPI::AssetUtils::TraceLevel::Error);
if (!materialAsset.IsReady())
{
AZ_Error(
"ShaderManagementConsoleDocument", false, "Failed to load material asset from asset id: %s",
assetId.ToString<AZStd::string>().c_str());
return AZStd::vector<AZ::RPI::ShaderCollection::Item>();
}
auto materialInstance = AZ::RPI::Material::Create(materialAsset);
if (!materialInstance)
{
AZ_Error(
"ShaderManagementConsoleDocument", false, "Failed to create material instance from asset: %s",
materialAsset.ToString<AZStd::string>().c_str());
return AZStd::vector<AZ::RPI::ShaderCollection::Item>();
}
return AZStd::vector<AZ::RPI::ShaderCollection::Item>(
materialInstance->GetShaderCollection().begin(), materialInstance->GetShaderCollection().end());
}
} // namespace ShaderManagementConsole } // namespace ShaderManagementConsole

@ -8,17 +8,17 @@
#pragma once #pragma once
#include <Atom/RPI.Edit/Shader/ShaderVariantListSourceData.h> #include <Atom/RPI.Edit/Shader/ShaderVariantListSourceData.h>
#include <Atom/RPI.Reflect/Material/ShaderCollection.h>
#include <Atom/RPI.Reflect/Shader/ShaderAsset.h> #include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
#include <AtomToolsFramework/Document/AtomToolsDocument.h> #include <AtomToolsFramework/Document/AtomToolsDocument.h>
#include <AzCore/Asset/AssetCommon.h> #include <AzCore/Asset/AssetCommon.h>
#include <AzCore/RTTI/RTTI.h> #include <AzCore/RTTI/RTTI.h>
#include <AzCore/std/containers/vector.h>
#include <Document/ShaderManagementConsoleDocumentRequestBus.h> #include <Document/ShaderManagementConsoleDocumentRequestBus.h>
namespace ShaderManagementConsole namespace ShaderManagementConsole
{ {
/** //! ShaderManagementConsoleDocument provides an API for modifying and saving document properties.
* ShaderManagementConsoleDocument provides an API for modifying and saving document properties.
*/
class ShaderManagementConsoleDocument class ShaderManagementConsoleDocument
: public AtomToolsFramework::AtomToolsDocument : public AtomToolsFramework::AtomToolsDocument
, public ShaderManagementConsoleDocumentRequestBus::Handler , public ShaderManagementConsoleDocumentRequestBus::Handler
@ -54,6 +54,8 @@ namespace ShaderManagementConsole
void Clear() override; void Clear() override;
bool SaveSourceData(); bool SaveSourceData();
AZStd::vector<AZ::Data::AssetId> FindMaterialAssetsUsingShader(const AZStd::string& shaderFilePath);
AZStd::vector<AZ::RPI::ShaderCollection::Item> GetMaterialInstanceShaderItems(const AZ::Data::AssetId& assetId);
// Source data for shader variant list // Source data for shader variant list
AZ::RPI::ShaderVariantListSourceData m_shaderVariantListSourceData; AZ::RPI::ShaderVariantListSourceData m_shaderVariantListSourceData;

@ -6,27 +6,17 @@
* *
*/ */
#include <AssetDatabase/AssetDatabaseConnection.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Common/JsonUtils.h>
#include <Atom/RPI.Public/Material/Material.h>
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h> #include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h>
#include <AtomToolsFramework/Util/Util.h>
#include <AzCore/RTTI/BehaviorContext.h> #include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h> #include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h> #include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h> #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzCore/Utils/Utils.h> #include <AzCore/Utils/Utils.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/EditorPythonRunnerRequestsBus.h> #include <AzToolsFramework/API/EditorPythonRunnerRequestsBus.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h> #include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
#include <AzToolsFramework/UI/UICore/QWidgetSavedState.h>
#include <Document/ShaderManagementConsoleDocument.h> #include <Document/ShaderManagementConsoleDocument.h>
#include <Document/ShaderManagementConsoleDocumentRequestBus.h> #include <Document/ShaderManagementConsoleDocumentRequestBus.h>
#include <ShaderManagementConsoleApplication.h> #include <ShaderManagementConsoleApplication.h>
#include <ShaderManagementConsoleRequestBus.h>
#include <ShaderManagementConsole_Traits_Platform.h> #include <ShaderManagementConsole_Traits_Platform.h>
#include <QDesktopServices> #include <QDesktopServices>
@ -62,13 +52,11 @@ namespace ShaderManagementConsole
QApplication::setApplicationName("O3DE Shader Management Console"); QApplication::setApplicationName("O3DE Shader Management Console");
ShaderManagementConsoleRequestBus::Handler::BusConnect();
AzToolsFramework::EditorWindowRequestBus::Handler::BusConnect(); AzToolsFramework::EditorWindowRequestBus::Handler::BusConnect();
} }
ShaderManagementConsoleApplication::~ShaderManagementConsoleApplication() ShaderManagementConsoleApplication::~ShaderManagementConsoleApplication()
{ {
ShaderManagementConsoleRequestBus::Handler::BusDisconnect();
AzToolsFramework::EditorWindowRequestBus::Handler::BusDisconnect(); AzToolsFramework::EditorWindowRequestBus::Handler::BusDisconnect();
m_window.reset(); m_window.reset();
} }
@ -79,15 +67,6 @@ namespace ShaderManagementConsole
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context)) if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{ {
behaviorContext->EBus<ShaderManagementConsoleRequestBus>("ShaderManagementConsoleRequestBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
->Attribute(AZ::Script::Attributes::Category, "Editor")
->Attribute(AZ::Script::Attributes::Module, "shadermanagementconsole")
->Event("GetSourceAssetInfo", &ShaderManagementConsoleRequestBus::Events::GetSourceAssetInfo)
->Event("FindMaterialAssetsUsingShader", &ShaderManagementConsoleRequestBus::Events::FindMaterialAssetsUsingShader )
->Event("GetMaterialInstanceShaderItems", &ShaderManagementConsoleRequestBus::Events::GetMaterialInstanceShaderItems)
;
behaviorContext->EBus<ShaderManagementConsoleDocumentRequestBus>("ShaderManagementConsoleDocumentRequestBus") behaviorContext->EBus<ShaderManagementConsoleDocumentRequestBus>("ShaderManagementConsoleDocumentRequestBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "Editor") ->Attribute(AZ::Script::Attributes::Category, "Editor")
@ -145,7 +124,10 @@ namespace ShaderManagementConsole
pythonArgs); pythonArgs);
}); });
} }
else if (AzFramework::StringFunc::Path::IsExtension(
if (AzFramework::StringFunc::Path::IsExtension(
entries.front()->GetFullPath().c_str(), AZ::RPI::ShaderSourceData::Extension) ||
AzFramework::StringFunc::Path::IsExtension(
entries.front()->GetFullPath().c_str(), AZ::RPI::ShaderVariantListSourceData::Extension)) entries.front()->GetFullPath().c_str(), AZ::RPI::ShaderVariantListSourceData::Extension))
{ {
menu->addAction(QObject::tr("Open"), [entries, this]() menu->addAction(QObject::tr("Open"), [entries, this]()
@ -180,100 +162,4 @@ namespace ShaderManagementConsole
{ {
return m_window.get(); return m_window.get();
} }
AZ::Data::AssetInfo ShaderManagementConsoleApplication::GetSourceAssetInfo(const AZStd::string& sourceAssetFileName)
{
bool result = false;
AZ::Data::AssetInfo assetInfo;
AZStd::string watchFolder;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
result, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, sourceAssetFileName.c_str(), assetInfo,
watchFolder);
AZ_Error(nullptr, result, "Failed to get the asset info for the file: %s.", sourceAssetFileName.c_str());
return assetInfo;
}
AZStd::vector<AZ::Data::AssetId> ShaderManagementConsoleApplication::FindMaterialAssetsUsingShader(const AZStd::string& shaderFilePath)
{
// Collect the material types referencing the shader
AZStd::vector<AZStd::string> materialTypeSources;
AzToolsFramework::AssetDatabase::AssetDatabaseConnection assetDatabaseConnection;
assetDatabaseConnection.OpenDatabase();
assetDatabaseConnection.QuerySourceDependencyByDependsOnSource(
shaderFilePath.c_str(), nullptr, AzToolsFramework::AssetDatabase::SourceFileDependencyEntry::DEP_Any,
[&](AzToolsFramework::AssetDatabase::SourceFileDependencyEntry& sourceFileDependencyEntry)
{
AZStd::string assetExtension;
if (AzFramework::StringFunc::Path::GetExtension(sourceFileDependencyEntry.m_source.c_str(), assetExtension, false))
{
if (assetExtension == "materialtype")
{
materialTypeSources.push_back(sourceFileDependencyEntry.m_source);
}
}
return true;
});
AzToolsFramework::AssetDatabase::ProductDatabaseEntryContainer productDependencies;
for (const auto& materialTypeSource : materialTypeSources)
{
bool result = false;
AZ::Data::AssetInfo materialTypeSourceAssetInfo;
AZStd::string watchFolder;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
result, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, materialTypeSource.c_str(),
materialTypeSourceAssetInfo, watchFolder);
assetDatabaseConnection.QueryDirectReverseProductDependenciesBySourceGuidSubId(
materialTypeSourceAssetInfo.m_assetId.m_guid, materialTypeSourceAssetInfo.m_assetId.m_subId,
[&](AzToolsFramework::AssetDatabase::ProductDatabaseEntry& entry)
{
AZStd::string assetExtension;
if (AzFramework::StringFunc::Path::GetExtension(entry.m_productName.c_str(), assetExtension, false))
{
if (assetExtension == "azmaterial")
{
productDependencies.push_back(entry);
}
}
return true;
});
}
AZStd::vector<AZ::Data::AssetId> results;
results.reserve(productDependencies.size());
for (auto product : productDependencies)
{
assetDatabaseConnection.QueryCombinedByProductID(
product.m_productID,
[&](AzToolsFramework::AssetDatabase::CombinedDatabaseEntry& combined)
{
results.push_back({ combined.m_sourceGuid, combined.m_subID });
return false;
},
nullptr);
}
return results;
}
AZStd::vector<AZ::RPI::ShaderCollection::Item> ShaderManagementConsoleApplication::GetMaterialInstanceShaderItems(
const AZ::Data::AssetId& assetId)
{
auto materialAsset = AZ::RPI::AssetUtils::LoadAssetById<AZ::RPI::MaterialAsset>(assetId, AZ::RPI::AssetUtils::TraceLevel::Error);
auto materialInstance = AZ::RPI::Material::Create(materialAsset);
AZ_Error(
nullptr, materialAsset, "Failed to get a material instance from product asset id: %s",
assetId.ToString<AZStd::string>().c_str());
if (materialInstance != nullptr)
{
return AZStd::vector<AZ::RPI::ShaderCollection::Item>(
materialInstance->GetShaderCollection().begin(), materialInstance->GetShaderCollection().end());
}
return AZStd::vector<AZ::RPI::ShaderCollection::Item>();
}
} // namespace ShaderManagementConsole } // namespace ShaderManagementConsole

@ -12,14 +12,12 @@
#include <AtomToolsFramework/AssetBrowser/AtomToolsAssetBrowserInteractions.h> #include <AtomToolsFramework/AssetBrowser/AtomToolsAssetBrowserInteractions.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentApplication.h> #include <AtomToolsFramework/Document/AtomToolsDocumentApplication.h>
#include <AzToolsFramework/API/EditorWindowRequestBus.h> #include <AzToolsFramework/API/EditorWindowRequestBus.h>
#include <ShaderManagementConsoleRequestBus.h>
#include <Window/ShaderManagementConsoleWindow.h> #include <Window/ShaderManagementConsoleWindow.h>
namespace ShaderManagementConsole namespace ShaderManagementConsole
{ {
class ShaderManagementConsoleApplication class ShaderManagementConsoleApplication
: public AtomToolsFramework::AtomToolsDocumentApplication : public AtomToolsFramework::AtomToolsDocumentApplication
, private ShaderManagementConsoleRequestBus::Handler
, private AzToolsFramework::EditorWindowRequestBus::Handler , private AzToolsFramework::EditorWindowRequestBus::Handler
{ {
public: public:
@ -42,11 +40,6 @@ namespace ShaderManagementConsole
// AzToolsFramework::EditorWindowRequests::Bus::Handler // AzToolsFramework::EditorWindowRequests::Bus::Handler
QWidget* GetAppMainWindow() override; QWidget* GetAppMainWindow() override;
// ShaderManagementConsoleRequestBus::Handler overrides...
AZ::Data::AssetInfo GetSourceAssetInfo(const AZStd::string& sourceAssetFileName) override;
AZStd::vector<AZ::Data::AssetId> FindMaterialAssetsUsingShader(const AZStd::string& shaderFilePath) override;
AZStd::vector<AZ::RPI::ShaderCollection::Item> GetMaterialInstanceShaderItems(const AZ::Data::AssetId& assetId) override;
private: private:
AZStd::unique_ptr<ShaderManagementConsoleWindow> m_window; AZStd::unique_ptr<ShaderManagementConsoleWindow> m_window;
AZStd::unique_ptr<AtomToolsFramework::AtomToolsAssetBrowserInteractions> m_assetBrowserInteractions; AZStd::unique_ptr<AtomToolsFramework::AtomToolsAssetBrowserInteractions> m_assetBrowserInteractions;

@ -1,38 +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/std/containers/vector.h>
#include <AzCore/EBus/EBus.h>
#include <AzCore/Asset/AssetCommon.h>
#include <Atom/RPI.Edit/Shader/ShaderVariantListSourceData.h>
#include <Atom/RPI.Reflect/Material/ShaderCollection.h>
namespace ShaderManagementConsole
{
//! ShaderManagementConsoleRequestBus provides
class ShaderManagementConsoleRequests
: public AZ::EBusTraits
{
public:
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
//! Returns a shader file's asset id and relative filepath
virtual AZ::Data::AssetInfo GetSourceAssetInfo(const AZStd::string& sourceAssetFileName) = 0;
// [GFX TODO][ATOM-14857] Generalize this API
//! Returns a list of material AssetIds that use the shader file.
virtual AZStd::vector<AZ::Data::AssetId> FindMaterialAssetsUsingShader (const AZStd::string& shaderFilePath) = 0;
//! Returns a list of shader items contained within an instantiated material source's shader collection.
virtual AZStd::vector<AZ::RPI::ShaderCollection::Item> GetMaterialInstanceShaderItems(const AZ::Data::AssetId& assetId) = 0;
};
using ShaderManagementConsoleRequestBus = AZ::EBus<ShaderManagementConsoleRequests>;
} // namespace ShaderManagementConsole

@ -9,10 +9,10 @@
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h> #include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h>
#include <AtomToolsFramework/Util/Util.h> #include <AtomToolsFramework/Util/Util.h>
#include <AzCore/Name/Name.h> #include <AzCore/Name/Name.h>
#include <AzCore/Utils/Utils.h>
#include <AzQtComponents/Components/WindowDecorationWrapper.h> #include <AzQtComponents/Components/WindowDecorationWrapper.h>
#include <Document/ShaderManagementConsoleDocumentRequestBus.h> #include <Document/ShaderManagementConsoleDocumentRequestBus.h>
#include <Window/ShaderManagementConsoleWindow.h> #include <Window/ShaderManagementConsoleWindow.h>
#include <AzCore/Utils/Utils.h>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
#include <QDesktopServices> #include <QDesktopServices>
@ -41,7 +41,9 @@ namespace ShaderManagementConsole
m_assetBrowser->SetFilterState("", AZ::RPI::ShaderAsset::Group, true); m_assetBrowser->SetFilterState("", AZ::RPI::ShaderAsset::Group, true);
m_assetBrowser->SetOpenHandler([this](const AZStd::string& absolutePath) { m_assetBrowser->SetOpenHandler([this](const AZStd::string& absolutePath) {
if (AzFramework::StringFunc::Path::IsExtension(absolutePath.c_str(), AZ::RPI::ShaderVariantListSourceData::Extension)) {
if (AzFramework::StringFunc::Path::IsExtension(absolutePath.c_str(), AZ::RPI::ShaderSourceData::Extension) ||
AzFramework::StringFunc::Path::IsExtension(absolutePath.c_str(), AZ::RPI::ShaderVariantListSourceData::Extension))
{ {
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Event( AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument, absolutePath); m_toolId, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument, absolutePath);
@ -66,7 +68,12 @@ namespace ShaderManagementConsole
bool ShaderManagementConsoleWindow::GetOpenDocumentParams(AZStd::string& openPath) bool ShaderManagementConsoleWindow::GetOpenDocumentParams(AZStd::string& openPath)
{ {
openPath = QFileDialog::getOpenFileName( openPath = QFileDialog::getOpenFileName(
this, tr("Open Document"), AZ::Utils::GetProjectPath().c_str(), tr("Files (*.%1)").arg(AZ::RPI::ShaderVariantListSourceData::Extension)).toUtf8().constData(); this, tr("Open Document"), AZ::Utils::GetProjectPath().c_str(),
tr("Shader Files (*.%1);;Shader Variant List Files (*.%2)")
.arg(AZ::RPI::ShaderSourceData::Extension)
.arg(AZ::RPI::ShaderVariantListSourceData::Extension))
.toUtf8()
.constData();
return !openPath.empty(); return !openPath.empty();
} }
@ -83,9 +90,7 @@ namespace ShaderManagementConsole
AZ::RPI::ShaderOptionDescriptor shaderOptionDesc; AZ::RPI::ShaderOptionDescriptor shaderOptionDesc;
ShaderManagementConsoleDocumentRequestBus::EventResult( ShaderManagementConsoleDocumentRequestBus::EventResult(
shaderOptionDesc, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderOptionDescriptor, optionIndex); shaderOptionDesc, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderOptionDescriptor, optionIndex);
optionNames.insert(shaderOptionDesc.GetName().GetCStr());
const char* optionName = shaderOptionDesc.GetName().GetCStr();
optionNames.insert(optionName);
} }
size_t shaderVariantCount = 0; size_t shaderVariantCount = 0;

@ -18,6 +18,5 @@ set(FILES
Source/main.cpp Source/main.cpp
Source/ShaderManagementConsoleApplication.cpp Source/ShaderManagementConsoleApplication.cpp
Source/ShaderManagementConsoleApplication.h Source/ShaderManagementConsoleApplication.h
Source/ShaderManagementConsoleRequestBus.h
../Scripts/GenerateShaderVariantListForMaterials.py ../Scripts/GenerateShaderVariantListForMaterials.py
) )

@ -39,27 +39,15 @@ def main():
print("The input argument for the script is not a valid .shader file") print("The input argument for the script is not a valid .shader file")
return return
# Get info such as relative path of the file and asset id # prompt the user to save the file in the project folder or same folder as the shader
shaderAssetInfo = azlmbr.shadermanagementconsole.ShaderManagementConsoleRequestBus(
azlmbr.bus.Broadcast,
'GetSourceAssetInfo',
filename
)
# retrieves a list of all material source files that use the shader. Note that materials inherit from materialtype files, which are actual files that refer to shader files.
materialAssetIds = azlmbr.shadermanagementconsole.ShaderManagementConsoleRequestBus(
azlmbr.bus.Broadcast,
'FindMaterialAssetsUsingShader',
shaderAssetInfo.relativePath
)
msgBox = QtWidgets.QMessageBox( msgBox = QtWidgets.QMessageBox(
QtWidgets.QMessageBox.Question, QtWidgets.QMessageBox.Question,
"Choose Save Location for .shadervariantlist File", "Choose Save Location for .shadervariantlist File",
"Save .shadervariantlist file in Project folder or in the same folder as shader file?" "Save .shadervariantlist file in Project folder or in the same folder as shader file?"
) )
projectButton = msgBox.addButton("Project Folder", QtWidgets.QMessageBox.AcceptRole) projectButton = msgBox.addButton("Project Folder", QtWidgets.QMessageBox.AcceptRole)
msgBox.addButton("Same Folder as Shader", QtWidgets.QMessageBox.AcceptRole) shaderButton = msgBox.addButton("Same Folder as Shader", QtWidgets.QMessageBox.AcceptRole)
cancelButton = msgBox.addButton("Cancel", QtWidgets.QMessageBox.RejectRole) cancelButton = msgBox.addButton("Cancel", QtWidgets.QMessageBox.RejectRole)
msgBox.exec() msgBox.exec()
@ -69,80 +57,36 @@ def main():
elif msgBox.clickedButton() == cancelButton: elif msgBox.clickedButton() == cancelButton:
return return
# This loop collects all uniquely-identified shader items used by the materials based on its shader variant id. # open the shader file as a document which will generate all of the shader variant list data
shader_file = os.path.basename(filename) documentId = azlmbr.atomtools.AtomToolsDocumentSystemRequestBus(
shaderVariantIds = [] azlmbr.bus.Broadcast,
shaderVariantListShaderOptionGroups = [] 'OpenDocument',
progressDialog = QtWidgets.QProgressDialog(f"Generating .shadervariantlist file for:\n{shader_file}", "Cancel", 0, len(materialAssetIds)) filename
progressDialog.setMaximumWidth(400) )
progressDialog.setMaximumHeight(100)
progressDialog.setModal(True)
progressDialog.setWindowTitle("Generating Shader Variant List")
for i, materialAssetId in enumerate(materialAssetIds):
materialInstanceShaderItems = azlmbr.shadermanagementconsole.ShaderManagementConsoleRequestBus(azlmbr.bus.Broadcast, 'GetMaterialInstanceShaderItems', materialAssetId)
for shaderItem in materialInstanceShaderItems:
shaderAssetId = shaderItem.GetShaderAsset().get_id()
if shaderAssetInfo.assetId == shaderAssetId:
shaderVariantId = shaderItem.GetShaderVariantId()
if not shaderVariantId.IsEmpty():
# Check for repeat shader variant ids. We are using a list here
# instead of a set to check for duplicates on shaderVariantIds because
# shaderVariantId is not hashed by the ID like it is in the C++ side.
has_repeat = False
for variantId in shaderVariantIds:
if shaderVariantId == variantId:
has_repeat = True
break
if has_repeat:
continue
shaderVariantIds.append(shaderVariantId)
shaderVariantListShaderOptionGroups.append(shaderItem.GetShaderOptionGroup())
progressDialog.setValue(i)
if progressDialog.wasCanceled():
return
progressDialog.close()
# Generate the shader variant list data by collecting shader option name-value pairs.s
shaderVariantList = azlmbr.shader.ShaderVariantListSourceData()
shaderVariantList.shaderFilePath = shaderAssetInfo.relativePath
shaderVariants = []
stableId = 1
for shaderOptionGroup in shaderVariantListShaderOptionGroups:
variantInfo = azlmbr.shader.ShaderVariantInfo()
variantInfo.stableId = stableId
options = {}
shaderOptionDescriptors = shaderOptionGroup.GetShaderOptionDescriptors()
for shaderOptionDescriptor in shaderOptionDescriptors:
optionName = shaderOptionDescriptor.GetName()
optionValue = shaderOptionGroup.GetValueByOptionName(optionName)
if not optionValue.IsValid():
continue
valueName = shaderOptionDescriptor.GetValueName(optionValue) if documentId.IsNull():
options[optionName.ToString()] = valueName.ToString() print("The shader source data file could not be opened")
return
if len(options) != 0: # get the shader variant list data object which is only needed for the shader file path
variantInfo.options = options shaderVariantList = azlmbr.shadermanagementconsole.ShaderManagementConsoleDocumentRequestBus(
shaderVariants.append(variantInfo) azlmbr.bus.Event,
stableId += 1 'GetShaderVariantListSourceData',
documentId
)
shaderVariantList.shaderVariants = shaderVariants # generate the default save file path by replacing the extension of the open shader file
pre, ext = os.path.splitext(filename)
defaultShaderVariantListFilePath = f'{pre}.shadervariantlist'
# clean previously generated shader variant list file so they don't clash. # clean previously generated shader variant list file so they don't clash.
pre, ext = os.path.splitext(shaderAssetInfo.relativePath) pre, ext = os.path.splitext(shaderVariantList.shaderFilePath)
projectShaderVariantListFilePath = os.path.join(azlmbr.paths.projectroot, PROJECT_SHADER_VARIANTS_FOLDER, f'{pre}.shadervariantlist') projectShaderVariantListFilePath = os.path.join(azlmbr.paths.projectroot, PROJECT_SHADER_VARIANTS_FOLDER, f'{pre}.shadervariantlist')
pre, ext = os.path.splitext(filename)
defaultShaderVariantListFilePath = f'{pre}.shadervariantlist'
clean_existing_shadervariantlist_files([ clean_existing_shadervariantlist_files([
projectShaderVariantListFilePath projectShaderVariantListFilePath
]) ])
# Save the shader variant list file # Save the shader variant list file
if is_save_in_project_folder: if is_save_in_project_folder:
shaderVariantListFilePath = projectShaderVariantListFilePath shaderVariantListFilePath = projectShaderVariantListFilePath
@ -150,16 +94,16 @@ def main():
shaderVariantListFilePath = defaultShaderVariantListFilePath shaderVariantListFilePath = defaultShaderVariantListFilePath
shaderVariantListFilePath = shaderVariantListFilePath.replace("\\", "/") shaderVariantListFilePath = shaderVariantListFilePath.replace("\\", "/")
azlmbr.shader.SaveShaderVariantListSourceData(shaderVariantListFilePath, shaderVariantList)
# Open the document in shader management console # Save the document in shader management console
result = azlmbr.atomtools.AtomToolsDocumentSystemRequestBus( saveResult = azlmbr.atomtools.AtomToolsDocumentSystemRequestBus(
azlmbr.bus.Broadcast, azlmbr.bus.Broadcast,
'OpenDocument', 'SaveDocumentAsChild',
documentId,
shaderVariantListFilePath shaderVariantListFilePath
) )
if not result.IsNull(): if saveResult:
msgBox = QtWidgets.QMessageBox( msgBox = QtWidgets.QMessageBox(
QtWidgets.QMessageBox.Information, QtWidgets.QMessageBox.Information,
"Shader Variant List File Successfully Generated", "Shader Variant List File Successfully Generated",

Loading…
Cancel
Save