From 2b16f6860f588888039884cfba74167a34ed2340 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 13 Feb 2022 02:04:14 -0600 Subject: [PATCH] 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 --- .../ShaderManagementConsoleDocument.cpp | 200 ++++++++++++++++-- .../ShaderManagementConsoleDocument.h | 8 +- .../ShaderManagementConsoleApplication.cpp | 124 +---------- .../ShaderManagementConsoleApplication.h | 7 - .../ShaderManagementConsoleRequestBus.h | 38 ---- .../Window/ShaderManagementConsoleWindow.cpp | 29 +-- .../Code/shadermanagementconsole_files.cmake | 1 - .../GenerateShaderVariantListForMaterials.py | 132 ++++-------- 8 files changed, 250 insertions(+), 289 deletions(-) delete mode 100644 Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleRequestBus.h diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.cpp index e7bd6033de..78a6f78d49 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.cpp @@ -6,10 +6,16 @@ * */ +#include +#include #include +#include #include #include +#include #include +#include +#include #include namespace ShaderManagementConsole @@ -32,10 +38,7 @@ namespace ShaderManagementConsole AzFramework::StringFunc::Path::ReplaceExtension(shaderPath, AZ::RPI::ShaderAsset::Extension); m_shaderAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath(shaderPath.c_str()); - if (!m_shaderAsset) - { - AZ_Error("ShaderManagementConsoleDocument", false, "Could not load shader asset: %s.", shaderPath.c_str()); - } + AZ_Error("ShaderManagementConsoleDocument", m_shaderAsset.IsReady(), "Could not load shader asset: %s.", shaderPath.c_str()); AtomToolsFramework::AtomToolsDocumentNotificationBus::Event( m_toolId, &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentModified, m_id); @@ -107,22 +110,98 @@ namespace ShaderManagementConsole 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 + AZ::RPI::ShaderVariantListSourceData sourceData; + if (!AZ::RPI::JsonUtils::LoadObjectFromFile(m_absolutePath, sourceData)) + { + AZ_Error( + "ShaderManagementConsoleDocument", false, "Failed loading shader variant list data: '%s.'", m_absolutePath.c_str()); + return OpenFailed(); + } + + SetShaderVariantListSourceData(sourceData); + return IsOpen() ? OpenSucceeded() : OpenFailed(); } - // Load the shader config data and create a shader config asset from it - AZ::RPI::ShaderVariantListSourceData sourceData; - if (!AZ::RPI::JsonUtils::LoadObjectFromFile(m_absolutePath, sourceData)) + if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), AZ::RPI::ShaderSourceData::Extension)) { - AZ_Error("ShaderManagementConsoleDocument", false, "Failed loading shader variant list data: '%s.'", m_absolutePath.c_str()); - return OpenFailed(); + // 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 shaderVariantIds; + AZStd::vector 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(); } - SetShaderVariantListSourceData(sourceData); - return IsOpen() ? OpenSucceeded() : OpenFailed(); + AZ_Error("ShaderManagementConsoleDocument", false, "Document extension is not supported: '%s.'", m_absolutePath.c_str()); + return OpenFailed(); } bool ShaderManagementConsoleDocument::Save() @@ -173,7 +252,8 @@ namespace ShaderManagementConsole bool ShaderManagementConsoleDocument::IsSavable() const { - return true; + return IsOpen() && + AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), AZ::RPI::ShaderVariantListSourceData::Extension); } void ShaderManagementConsoleDocument::Clear() @@ -195,4 +275,94 @@ namespace ShaderManagementConsole m_absolutePath = m_savePathNormalized; return SaveSucceeded(); } + + AZStd::vector ShaderManagementConsoleDocument::FindMaterialAssetsUsingShader(const AZStd::string& shaderFilePath) + { + // Collect the material types referencing the shader + AZStd::vector 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 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 ShaderManagementConsoleDocument::GetMaterialInstanceShaderItems( + const AZ::Data::AssetId& assetId) + { + auto materialAsset = AZ::RPI::AssetUtils::LoadAssetById(assetId, AZ::RPI::AssetUtils::TraceLevel::Error); + if (!materialAsset.IsReady()) + { + AZ_Error( + "ShaderManagementConsoleDocument", false, "Failed to load material asset from asset id: %s", + assetId.ToString().c_str()); + return AZStd::vector(); + } + + auto materialInstance = AZ::RPI::Material::Create(materialAsset); + if (!materialInstance) + { + AZ_Error( + "ShaderManagementConsoleDocument", false, "Failed to create material instance from asset: %s", + materialAsset.ToString().c_str()); + return AZStd::vector(); + } + + return AZStd::vector( + materialInstance->GetShaderCollection().begin(), materialInstance->GetShaderCollection().end()); + } } // namespace ShaderManagementConsole diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.h index 46002ce1da..c470f5826a 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.h +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.h @@ -8,17 +8,17 @@ #pragma once #include +#include #include #include #include #include +#include #include namespace ShaderManagementConsole { - /** - * ShaderManagementConsoleDocument provides an API for modifying and saving document properties. - */ + //! ShaderManagementConsoleDocument provides an API for modifying and saving document properties. class ShaderManagementConsoleDocument : public AtomToolsFramework::AtomToolsDocument , public ShaderManagementConsoleDocumentRequestBus::Handler @@ -54,6 +54,8 @@ namespace ShaderManagementConsole void Clear() override; bool SaveSourceData(); + AZStd::vector FindMaterialAssetsUsingShader(const AZStd::string& shaderFilePath); + AZStd::vector GetMaterialInstanceShaderItems(const AZ::Data::AssetId& assetId); // Source data for shader variant list AZ::RPI::ShaderVariantListSourceData m_shaderVariantListSourceData; diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp index 43936c59da..dff162b0cb 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp @@ -6,27 +6,17 @@ * */ -#include -#include -#include -#include -#include #include -#include #include #include #include #include #include -#include #include -#include #include -#include #include #include #include -#include #include #include @@ -62,13 +52,11 @@ namespace ShaderManagementConsole QApplication::setApplicationName("O3DE Shader Management Console"); - ShaderManagementConsoleRequestBus::Handler::BusConnect(); AzToolsFramework::EditorWindowRequestBus::Handler::BusConnect(); } ShaderManagementConsoleApplication::~ShaderManagementConsoleApplication() { - ShaderManagementConsoleRequestBus::Handler::BusDisconnect(); AzToolsFramework::EditorWindowRequestBus::Handler::BusDisconnect(); m_window.reset(); } @@ -79,15 +67,6 @@ namespace ShaderManagementConsole if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) { - behaviorContext->EBus("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") ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) ->Attribute(AZ::Script::Attributes::Category, "Editor") @@ -145,8 +124,11 @@ namespace ShaderManagementConsole pythonArgs); }); } - else if (AzFramework::StringFunc::Path::IsExtension( - entries.front()->GetFullPath().c_str(), AZ::RPI::ShaderVariantListSourceData::Extension)) + + 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)) { menu->addAction(QObject::tr("Open"), [entries, this]() { @@ -180,100 +162,4 @@ namespace ShaderManagementConsole { 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 ShaderManagementConsoleApplication::FindMaterialAssetsUsingShader(const AZStd::string& shaderFilePath) - { - // Collect the material types referencing the shader - AZStd::vector 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 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 ShaderManagementConsoleApplication::GetMaterialInstanceShaderItems( - const AZ::Data::AssetId& assetId) - { - auto materialAsset = AZ::RPI::AssetUtils::LoadAssetById(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().c_str()); - - if (materialInstance != nullptr) - { - return AZStd::vector( - materialInstance->GetShaderCollection().begin(), materialInstance->GetShaderCollection().end()); - } - return AZStd::vector(); - } } // namespace ShaderManagementConsole diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.h index 75d1ab83c8..01d0b9e415 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.h +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.h @@ -12,14 +12,12 @@ #include #include #include -#include #include namespace ShaderManagementConsole { class ShaderManagementConsoleApplication : public AtomToolsFramework::AtomToolsDocumentApplication - , private ShaderManagementConsoleRequestBus::Handler , private AzToolsFramework::EditorWindowRequestBus::Handler { public: @@ -42,11 +40,6 @@ namespace ShaderManagementConsole // AzToolsFramework::EditorWindowRequests::Bus::Handler QWidget* GetAppMainWindow() override; - // ShaderManagementConsoleRequestBus::Handler overrides... - AZ::Data::AssetInfo GetSourceAssetInfo(const AZStd::string& sourceAssetFileName) override; - AZStd::vector FindMaterialAssetsUsingShader(const AZStd::string& shaderFilePath) override; - AZStd::vector GetMaterialInstanceShaderItems(const AZ::Data::AssetId& assetId) override; - private: AZStd::unique_ptr m_window; AZStd::unique_ptr m_assetBrowserInteractions; diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleRequestBus.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleRequestBus.h deleted file mode 100644 index 355c51ed54..0000000000 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleRequestBus.h +++ /dev/null @@ -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 -#include -#include -#include -#include - -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 FindMaterialAssetsUsingShader (const AZStd::string& shaderFilePath) = 0; - - //! Returns a list of shader items contained within an instantiated material source's shader collection. - virtual AZStd::vector GetMaterialInstanceShaderItems(const AZ::Data::AssetId& assetId) = 0; - }; - using ShaderManagementConsoleRequestBus = AZ::EBus; -} // namespace ShaderManagementConsole diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp index b1bd906f81..7c1ee29cb2 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp @@ -9,10 +9,10 @@ #include #include #include +#include #include #include #include -#include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT #include @@ -41,15 +41,17 @@ namespace ShaderManagementConsole m_assetBrowser->SetFilterState("", AZ::RPI::ShaderAsset::Group, true); m_assetBrowser->SetOpenHandler([this](const AZStd::string& absolutePath) { - if (AzFramework::StringFunc::Path::IsExtension(absolutePath.c_str(), AZ::RPI::ShaderVariantListSourceData::Extension)) { - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Event( - m_toolId, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument, absolutePath); - return; - } + 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( + m_toolId, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument, absolutePath); + return; + } - QDesktopServices::openUrl(QUrl::fromLocalFile(absolutePath.c_str())); - }); + QDesktopServices::openUrl(QUrl::fromLocalFile(absolutePath.c_str())); + }); // Restore geometry and show the window mainWindowWrapper->showFromSettings(); @@ -66,7 +68,12 @@ namespace ShaderManagementConsole bool ShaderManagementConsoleWindow::GetOpenDocumentParams(AZStd::string& openPath) { 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(); } @@ -83,9 +90,7 @@ namespace ShaderManagementConsole AZ::RPI::ShaderOptionDescriptor shaderOptionDesc; ShaderManagementConsoleDocumentRequestBus::EventResult( shaderOptionDesc, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderOptionDescriptor, optionIndex); - - const char* optionName = shaderOptionDesc.GetName().GetCStr(); - optionNames.insert(optionName); + optionNames.insert(shaderOptionDesc.GetName().GetCStr()); } size_t shaderVariantCount = 0; diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/shadermanagementconsole_files.cmake b/Gems/Atom/Tools/ShaderManagementConsole/Code/shadermanagementconsole_files.cmake index 332cd73b40..b7da8d449a 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/shadermanagementconsole_files.cmake +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/shadermanagementconsole_files.cmake @@ -18,6 +18,5 @@ set(FILES Source/main.cpp Source/ShaderManagementConsoleApplication.cpp Source/ShaderManagementConsoleApplication.h - Source/ShaderManagementConsoleRequestBus.h ../Scripts/GenerateShaderVariantListForMaterials.py ) diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Scripts/GenerateShaderVariantListForMaterials.py b/Gems/Atom/Tools/ShaderManagementConsole/Scripts/GenerateShaderVariantListForMaterials.py index c31047d347..79a0391bf7 100755 --- a/Gems/Atom/Tools/ShaderManagementConsole/Scripts/GenerateShaderVariantListForMaterials.py +++ b/Gems/Atom/Tools/ShaderManagementConsole/Scripts/GenerateShaderVariantListForMaterials.py @@ -38,28 +38,16 @@ def main(): if extension != "shader": print("The input argument for the script is not a valid .shader file") return - - # Get info such as relative path of the file and asset id - 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 - ) - + + # prompt the user to save the file in the project folder or same folder as the shader msgBox = QtWidgets.QMessageBox( QtWidgets.QMessageBox.Question, "Choose Save Location for .shadervariantlist File", "Save .shadervariantlist file in Project folder or in the same folder as shader file?" ) + 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) msgBox.exec() @@ -68,98 +56,54 @@ def main(): is_save_in_project_folder = True elif msgBox.clickedButton() == cancelButton: return - - # This loop collects all uniquely-identified shader items used by the materials based on its shader variant id. - shader_file = os.path.basename(filename) - shaderVariantIds = [] - shaderVariantListShaderOptionGroups = [] - progressDialog = QtWidgets.QProgressDialog(f"Generating .shadervariantlist file for:\n{shader_file}", "Cancel", 0, len(materialAssetIds)) - 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) - options[optionName.ToString()] = valueName.ToString() - - if len(options) != 0: - variantInfo.options = options - shaderVariants.append(variantInfo) - stableId += 1 - - shaderVariantList.shaderVariants = shaderVariants - - # clean previously generated shader variant list file so they don't clash. - pre, ext = os.path.splitext(shaderAssetInfo.relativePath) - projectShaderVariantListFilePath = os.path.join(azlmbr.paths.projectroot, PROJECT_SHADER_VARIANTS_FOLDER, f'{pre}.shadervariantlist') - + + # open the shader file as a document which will generate all of the shader variant list data + documentId = azlmbr.atomtools.AtomToolsDocumentSystemRequestBus( + azlmbr.bus.Broadcast, + 'OpenDocument', + filename + ) + + if documentId.IsNull(): + print("The shader source data file could not be opened") + return + + # get the shader variant list data object which is only needed for the shader file path + shaderVariantList = azlmbr.shadermanagementconsole.ShaderManagementConsoleDocumentRequestBus( + azlmbr.bus.Event, + 'GetShaderVariantListSourceData', + documentId + ) + + # 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. + pre, ext = os.path.splitext(shaderVariantList.shaderFilePath) + projectShaderVariantListFilePath = os.path.join(azlmbr.paths.projectroot, PROJECT_SHADER_VARIANTS_FOLDER, f'{pre}.shadervariantlist') + clean_existing_shadervariantlist_files([ projectShaderVariantListFilePath ]) + # Save the shader variant list file if is_save_in_project_folder: shaderVariantListFilePath = projectShaderVariantListFilePath else: shaderVariantListFilePath = defaultShaderVariantListFilePath - + shaderVariantListFilePath = shaderVariantListFilePath.replace("\\", "/") - azlmbr.shader.SaveShaderVariantListSourceData(shaderVariantListFilePath, shaderVariantList) - - # Open the document in shader management console - result = azlmbr.atomtools.AtomToolsDocumentSystemRequestBus( + + # Save the document in shader management console + saveResult = azlmbr.atomtools.AtomToolsDocumentSystemRequestBus( azlmbr.bus.Broadcast, - 'OpenDocument', + 'SaveDocumentAsChild', + documentId, shaderVariantListFilePath ) - - if not result.IsNull(): + + if saveResult: msgBox = QtWidgets.QMessageBox( QtWidgets.QMessageBox.Information, "Shader Variant List File Successfully Generated", @@ -167,7 +111,7 @@ def main(): QtWidgets.QMessageBox.Ok ) msgBox.exec() - + print("==== End shader variant script ============================================================") if __name__ == "__main__":