Browse Source

SMC Python script updates and fixes

Added an idle_wait_frames call to shader variant list generation script loops to give the application time to garbage collect graphics resources from creating material instances and SRGs.
Disabled texture loading and function that enumerates shader items from material instances.
Replaced asset browser interactions create new variant list side by side command with python scripts that can create the shader variant list in the shader folder or the project folder.
These scripts will automatically name and save the shader variant list document.
Updated settings to register new scripts with file and asset browser menus.

Signed-off-by: Guthrie Adams <[email protected]>
Guthrie Adams 1 year ago
parent
commit
95b09da524

+ 20 - 39
Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp

@@ -10,6 +10,9 @@
 #include <Atom/RPI.Edit/Common/AssetUtils.h>
 #include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
 #include <Atom/RPI.Public/Material/Material.h>
+#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
+#include <Atom/RPI.Reflect/Image/AttachmentImageAsset.h>
+#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
 #include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h>
 #include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
 #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
@@ -110,39 +113,6 @@ namespace ShaderManagementConsole
 
         m_window.reset(aznew ShaderManagementConsoleWindow(m_toolId));
         m_window->show();
-
-        using namespace AtomToolsFramework;
-        using namespace AzToolsFramework;
-        m_assetBrowserInteractions->RegisterContextMenuActions(
-            [](const AtomToolsAssetBrowserInteractions::AssetBrowserEntryVector& entries)
-            {
-                return entries.front()->GetEntryType() == AssetBrowser::AssetBrowserEntry::AssetEntryType::Source;
-            },
-            [this]([[maybe_unused]] QWidget* caller, QMenu* menu, const AtomToolsAssetBrowserInteractions::AssetBrowserEntryVector& entries)
-            {
-                const auto* entry = entries.empty() ? nullptr : entries.front();
-                if (!entry)
-                {
-                    return;
-                }
-                QFileInfo fileInfo(entry->GetFullPath().c_str());
-                QString extension = fileInfo.completeSuffix();
-                if (extension == "shader")
-                {
-                    AZStd::string savePath = entry->GetFullPath();
-                    AzFramework::StringFunc::Path::ReplaceExtension(savePath, AZ::RPI::ShaderVariantListSourceData::Extension);
-                    menu->addAction(
-                        "Create New Variant List (side by side to source)",
-                        [entry, savePath, this]()
-                        {
-                            AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Event(
-                                m_toolId,
-                                &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Handler::CreateDocumentFromFilePath,
-                                entry->GetFullPath().c_str(),
-                                savePath);
-                        });
-                }
-             });
     }
 
     void ShaderManagementConsoleApplication::Destroy()
@@ -236,23 +206,34 @@ namespace ShaderManagementConsole
     AZStd::vector<AZ::RPI::ShaderCollection::Item> ShaderManagementConsoleApplication::GetMaterialInstanceShaderItems(
         const AZ::Data::AssetId& materialAssetId)
     {
-        auto materialAsset =
-            AZ::RPI::AssetUtils::LoadAssetById<AZ::RPI::MaterialAsset>(materialAssetId, AZ::RPI::AssetUtils::TraceLevel::Error);
-        if (!materialAsset.IsReady())
+        const AZ::Data::AssetLoadParameters dontLoadImageAssets{
+            [](const AZ::Data::AssetFilterInfo& filterInfo)
+            {
+                return
+                    filterInfo.m_assetType != AZ::AzTypeInfo<AZ::RPI::StreamingImageAsset>::Uuid() &&
+                    filterInfo.m_assetType != AZ::AzTypeInfo<AZ::RPI::AttachmentImageAsset>::Uuid() &&
+                    filterInfo.m_assetType != AZ::AzTypeInfo<AZ::RPI::ImageAsset>::Uuid();
+            }
+        };
+
+        const auto materialAssetOutcome = AZ::RPI::AssetUtils::LoadAsset<AZ::RPI::MaterialAsset>(
+            materialAssetId, AZ::RPI::AssetUtils::TraceLevel::Error, dontLoadImageAssets);
+        if (!materialAssetOutcome)
         {
             AZ_Error(
                 "ShaderManagementConsole", false, "Failed to load material asset from asset id: %s",
                 materialAssetId.ToFixedString().c_str());
-            return AZStd::vector<AZ::RPI::ShaderCollection::Item>();
+            return {};
         }
 
-        auto materialInstance = AZ::RPI::Material::Create(materialAsset);
+        const auto materialAsset = materialAssetOutcome.GetValue();
+        const auto materialInstance = AZ::RPI::Material::FindOrCreate(materialAsset);
         if (!materialInstance)
         {
             AZ_Error(
                 "ShaderManagementConsole", 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> shaderItems;

+ 5 - 1
Gems/Atom/Tools/ShaderManagementConsole/Registry/scripts.shadermanagementconsole.setreg

@@ -8,7 +8,11 @@
             },
             "AssetBrowser": {
                 "ContextMenuScripts": {
-                    "": [ "@gemroot:ShaderManagementConsole@/Scripts/CreateShaderVariantListDocumentFromShader.py" ]
+                    "": [
+                        "@gemroot:ShaderManagementConsole@/Scripts/CreateShaderVariantListDocumentFromShader.py",
+                        "@gemroot:ShaderManagementConsole@/Scripts/CreateShaderVariantListDocumentFromShaderInProjectFolder.py",
+                        "@gemroot:ShaderManagementConsole@/Scripts/CreateShaderVariantListDocumentFromShaderInSameFolder.py"
+                    ]
                 }
             }
         },

+ 5 - 6
Gems/Atom/Tools/ShaderManagementConsole/Scripts/CreateShaderVariantListDocumentFromShader.py

@@ -15,29 +15,28 @@ def main():
         print("The script requires a .shader file as input argument")
         return
 
-    filename = sys.argv[1]
-    suffix, extension = filename.split(".", 1)
+    inputPath = sys.argv[1]
+    suffix, extension = inputPath.split(".", 1)
 
     if extension != "shader":
         print("The input argument for the script is not a valid .shader file")
         return
 
-    shaderVariantList = GenerateShaderVariantListUtil.create_shadervariantlist_for_shader(filename)
-
     # Create shader variant list document
     documentId = azlmbr.atomtools.AtomToolsDocumentSystemRequestBus(
         azlmbr.bus.Broadcast,
         'CreateDocumentFromTypeName',
         'Shader Variant List'
     )
+
     # Update shader variant list
     azlmbr.shadermanagementconsole.ShaderManagementConsoleDocumentRequestBus(
         azlmbr.bus.Event,
         'SetShaderVariantListSourceData',
         documentId,
-        shaderVariantList
+        GenerateShaderVariantListUtil.create_shadervariantlist_for_shader(inputPath)
     )
-    
+
     print("==== End shader variant script ============================================================")
 
 if __name__ == "__main__":

+ 60 - 0
Gems/Atom/Tools/ShaderManagementConsole/Scripts/CreateShaderVariantListDocumentFromShaderInProjectFolder.py

@@ -0,0 +1,60 @@
+"""
+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
+"""
+
+import os
+import sys
+
+import azlmbr.bus
+import azlmbr.paths
+import GenerateShaderVariantListUtil
+
+def main():
+    print("==== Begin shader variant script ==========================================================")
+
+    if len(sys.argv) != 2:
+        print("The script requires a .shader file as input argument")
+        return
+
+    inputPath = sys.argv[1]
+    rootPath, extension = inputPath.split(".", 1)
+
+    if extension != "shader":
+        print("The input argument for the script is not a valid .shader file")
+        return
+
+    projectShaderVariantListFolder = os.path.join(azlmbr.paths.projectroot, "ShaderVariants")
+    outputPath = rootPath + ".shadervariantlist"
+    outputPath = azlmbr.shadermanagementconsole.ShaderManagementConsoleRequestBus(azlmbr.bus.Broadcast, 'GenerateRelativeSourcePath', outputPath)
+    outputPath = os.path.join(projectShaderVariantListFolder, outputPath)
+
+    # Create shader variant list document
+    documentId = azlmbr.atomtools.AtomToolsDocumentSystemRequestBus(
+        azlmbr.bus.Broadcast,
+        'CreateDocumentFromTypeName',
+        'Shader Variant List'
+    )
+
+    # Update shader variant list
+    azlmbr.shadermanagementconsole.ShaderManagementConsoleDocumentRequestBus(
+        azlmbr.bus.Event,
+        'SetShaderVariantListSourceData',
+        documentId,
+        GenerateShaderVariantListUtil.create_shadervariantlist_for_shader(inputPath)
+    )
+
+    # Save the shader variant list
+    documentId = azlmbr.atomtools.AtomToolsDocumentSystemRequestBus(
+        azlmbr.bus.Broadcast,
+        'SaveDocumentAsCopy',
+        documentId,
+        outputPath
+    )
+
+    print("==== End shader variant script ============================================================")
+
+if __name__ == "__main__":
+    main()

+ 61 - 0
Gems/Atom/Tools/ShaderManagementConsole/Scripts/CreateShaderVariantListDocumentFromShaderInSameFolder.py

@@ -0,0 +1,61 @@
+"""
+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
+"""
+
+import os
+import sys
+
+import azlmbr.bus
+import azlmbr.paths
+import GenerateShaderVariantListUtil
+
+def main():
+    print("==== Begin shader variant script ==========================================================")
+
+    if len(sys.argv) != 2:
+        print("The script requires a .shader file as input argument")
+        return
+
+    inputPath = sys.argv[1]
+    rootPath, extension = inputPath.split(".", 1)
+
+    if extension != "shader":
+        print("The input argument for the script is not a valid .shader file")
+        return
+
+    if not azlmbr.atomtools.util.IsDocumentPathEditable(inputPath):
+        print("Cannot create shader variant list in same folder as input file")
+        return
+
+    outputPath = rootPath + ".shadervariantlist"
+
+    # Create shader variant list document
+    documentId = azlmbr.atomtools.AtomToolsDocumentSystemRequestBus(
+        azlmbr.bus.Broadcast,
+        'CreateDocumentFromTypeName',
+        'Shader Variant List'
+    )
+
+    # Update shader variant list
+    azlmbr.shadermanagementconsole.ShaderManagementConsoleDocumentRequestBus(
+        azlmbr.bus.Event,
+        'SetShaderVariantListSourceData',
+        documentId,
+        GenerateShaderVariantListUtil.create_shadervariantlist_for_shader(inputPath)
+    )
+
+    # Save the shader variant list
+    documentId = azlmbr.atomtools.AtomToolsDocumentSystemRequestBus(
+        azlmbr.bus.Broadcast,
+        'SaveDocumentAsCopy',
+        documentId,
+        outputPath
+    )
+
+    print("==== End shader variant script ============================================================")
+
+if __name__ == "__main__":
+    main()

+ 6 - 0
Gems/Atom/Tools/ShaderManagementConsole/Scripts/GenerateShaderVariantListForAllShaders.py

@@ -57,6 +57,12 @@ def main():
         azlmbr.shader.SaveShaderVariantListSourceData(savePath, shaderVariantList)
 
         progressDialog.setValue(i)
+
+        # processing events to update UI after progress bar changes
+        QtWidgets.QApplication.processEvents()
+
+        # Allowing the application to process idle events for one frame to update systems and garbage collect graphics resources
+        azlmbr.atomtools.general.idle_wait_frames(1)
         if progressDialog.wasCanceled():
             return
     progressDialog.close()

+ 9 - 4
Gems/Atom/Tools/ShaderManagementConsole/Scripts/GenerateShaderVariantListUtil.py

@@ -5,17 +5,17 @@ For complete copyright and license terms please see the LICENSE at the root of t
 SPDX-License-Identifier: Apache-2.0 OR MIT
 """
 
-import os
+from PySide2 import QtWidgets
 import azlmbr.asset as asset
 import azlmbr.atom
 import azlmbr.bus
 import azlmbr.math as math
 import azlmbr.name
 import azlmbr.paths
-import azlmbr.shadermanagementconsole
 import azlmbr.shader
-from PySide2 import QtWidgets
+import azlmbr.shadermanagementconsole
 import json
+import os
 
 # Make a copy of shaderVariants, update target option value and return copy, accumulate stableId
 def updateOptionValue(shaderVariants, targetOptionName, targetValue, stableId):
@@ -109,9 +109,14 @@ def create_shadervariantlist_for_shader(filename):
                     # clear the group from spuriously defaulted options by reducing it to a lean set:
                     clearOptions(optionGroup, lambda optName_Query: not shaderItem.MaterialOwnsShaderOption(optName_Query))
                     shaderOptionGroups.append(optionGroup)
-                    
 
         progressDialog.setValue(i)
+
+        # processing events to update UI after progress bar changes
+        QtWidgets.QApplication.processEvents()
+
+        # Allowing the application to process idle events for one frame to update systems and garbage collect graphics resources
+        azlmbr.atomtools.general.idle_wait_frames(1)
         if progressDialog.wasCanceled():
             return