@ -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.Public/Material/Material.h>
# include <Atom/RPI.Reflect/Asset/AssetUtils.h>
# include <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h>
# include <AzCore/Utils/Utils.h>
# include <AzFramework/StringFunc/StringFunc.h>
# include <AzToolsFramework/API/EditorAssetSystemAPI.h>
# include <AzToolsFramework/API/ToolsApplicationAPI.h>
# include <Document/ShaderManagementConsoleDocument.h>
namespace ShaderManagementConsole
@ -32,10 +38,7 @@ namespace ShaderManagementConsole
AzFramework : : StringFunc : : Path : : ReplaceExtension ( shaderPath , AZ : : RPI : : ShaderAsset : : Extension ) ;
m_shaderAsset = AZ : : RPI : : AssetUtils : : LoadAssetByProductPath < AZ : : RPI : : ShaderAsset > ( 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 < 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 ( ) ;
}
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 < 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