You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuilderUtility.h

170 lines
9.0 KiB
C++

/*
* 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/base.h>
#include <AzCore/Preprocessor/Enum.h>
#include <AssetBuilderSDK/AssetBuilderBusses.h>
#include <AssetBuilderSDK/AssetBuilderSDK.h>
#include <Atom/RPI.Edit/Shader/ShaderSourceData.h>
#include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
#include "AzslData.h"
namespace AZ
{
namespace ShaderBuilder
{
class AzslCompiler;
struct ShaderFiles;
struct BindingDependencies;
struct RootConstantData;
using MapOfStringToStageType = AZStd::unordered_map<AZStd::string, RPI::ShaderStageType>;
namespace ShaderBuilderUtility
{
Outcome<RPI::ShaderSourceData, AZStd::string> LoadShaderDataJson(const AZStd::string& fullPathToJsonFile);
void GetAbsolutePathToAzslFile(const AZStd::string& shaderSourceFileFullPath, AZStd::string specifiedShaderPathAndName, AZStd::string& absoluteShaderPath);
//! Opens and read the .shader, returns expanded file paths
AZStd::shared_ptr<ShaderFiles> PrepareSourceInput(
const char* builderName,
const AZStd::string& shaderSourceFileFullPath,
RPI::ShaderSourceData& sourceAsset);
namespace AzslSubProducts
{
AZ_ENUM(SuffixList, azslin, ia, om, srg, options, bindingdep, hlsl);
using SubId = RPI::ShaderAssetSubId;
// product sub id enumerators:
static constexpr SubId SubList[] = {SubId::FlatAzsl,
SubId::IaJson,
SubId::OmJson,
SubId::SrgJson,
SubId::OptionsJson,
SubId::BindingdepJson,
SubId::GeneratedHlslSource};
// in the same order, their file name suffix (they replicate what's in AzslcMain.cpp. and hlsl corresponds to what's in AzslBuilder.cpp)
// a type to declare variables holding the full paths of their files
using Paths = AZStd::fixed_vector<AZStd::string, AZ_ARRAY_SIZE(SubList)>;
};
//! Collects all the JSON files generated during AZSL compilation and loads the data as objects.
//! @azslData must have paths correctly set.
//! @azslData, @srgLayoutList, @shaderOptionGroupLayout, @bindingDependencies and @rootConstantData get the output data.
AssetBuilderSDK::ProcessJobResultCode PopulateAzslDataFromJsonFiles(
const char* builderName, const AzslSubProducts::Paths& pathOfJsonFiles,
const bool platformUsesRegisterSpaces, AzslData& azslData,
RPI::ShaderResourceGroupLayoutList& srgLayoutList, RPI::Ptr<RPI::ShaderOptionGroupLayout> shaderOptionGroupLayout,
BindingDependencies& bindingDependencies, RootConstantData& rootConstantData);
RHI::ShaderHardwareStage ToAssetBuilderShaderType(RPI::ShaderStageType stageType);
//! Must be called before shaderPlatformInterface->CompilePlatformInternal()
//! This function will prune non entry functions from BindingDependencies and use the
//! rest of input data to create a pipeline layout descriptor.
//! The pipeline layout descriptor is returned, but the same data will also be set into the @shaderPlatformInterface
//! object, which is why it is important to call this method before calling shaderPlatformInterface->CompilePlatformInternal().
RHI::Ptr<RHI::PipelineLayoutDescriptor> BuildPipelineLayoutDescriptorForApi(
const char* builderName,
const RPI::ShaderResourceGroupLayoutList& srgLayoutList,
const MapOfStringToStageType& shaderEntryPoints,
const RHI::ShaderCompilerArguments& shaderCompilerArguments,
const RootConstantData& rootConstantData,
RHI::ShaderPlatformInterface* shaderPlatformInterface,
BindingDependencies& bindingDependencies /*inout*/);
bool CreateShaderInputAndOutputContracts(
const AzslData& azslData, const MapOfStringToStageType& shaderEntryPoints,
const RPI::ShaderOptionGroupLayout& shaderOptionGroupLayout, const AZStd::string& pathToOmJson,
const AZStd::string& pathToIaJson, RPI::ShaderInputContract& shaderInputContract,
RPI::ShaderOutputContract& shaderOutputContract, size_t& colorAttachmentCount);
//! Create a file from a string's content.
//! That file will be named filename.api.azslin
//! This is meant to be used at this stage:
//!
//! .azsl source -> common header prepend -> preprocess -> azslc -> dxc -> cross
//! ^here^
AZStd::string DumpPreprocessedCode(
const char* BuilderName,
const AZStd::string& preprocessedCode,
const AZStd::string& tempDirPath,
const AZStd::string& preprocessedFileName,
const AZStd::string& apiTypeString = "");
//! Create a file from a string's content.
//! That file will be named filename.api.azsl.prepend
//! This is meant to be used at this stage:
//!
//! .azsl source -> common header prepend -> preprocess -> azslc -> dxc -> cross
//! ^here^
AZStd::string DumpAzslPrependedCode(
const char* BuilderName,
const AZStd::string& nonPreprocessedYetAzslSource,
const AZStd::string& tempDirPath,
const AZStd::string& stemName,
const AZStd::string& apiTypeString = "");
//! "d:/p/f.e" -> "f"
AZStd::string ExtractStemName(const char* path);
AZStd::vector<RHI::ShaderPlatformInterface*> DiscoverValidShaderPlatformInterfaces(const AssetBuilderSDK::PlatformInfo& info);
AZStd::vector<RHI::ShaderPlatformInterface*> DiscoverEnabledShaderPlatformInterfaces(
const AssetBuilderSDK::PlatformInfo& info, const RPI::ShaderSourceData& shaderSourceData);
// The idea is that the "Supervariants" json property is optional in .shader files,
// For cases when it is not specified, this function will return a vector with one item, the default, nameless, supervariant.
// If "Supervariants" is not empty, then this function will make sure the first supervariant in the list
// is the default, nameless, supervariant.
AZStd::vector<RPI::ShaderSourceData::SupervariantInfo> GetSupervariantListFromShaderSourceData(
const RPI::ShaderSourceData& shaderSourceData);
void LogProfilingData(const char* builderName, AZStd::string_view shaderPath);
//! Returns the asset path of a product artifact produced by ShaderAssetBuilder.
Outcome<AZStd::string, AZStd::string> ObtainBuildArtifactPathFromShaderAssetBuilder(
const uint32_t rhiUniqueIndex, const AZStd::string& platformIdentifier, const AZStd::string& shaderJsonPath,
const uint32_t supervariantIndex, RPI::ShaderAssetSubId shaderAssetSubId);
class IncludedFilesParser
{
public:
IncludedFilesParser();
~IncludedFilesParser() = default;
//! This static function was made public for testability purposes only.
//! Parses the string @haystack, looking for "#include file" lines with a regular expression.
//! Returns the list of relative paths as included by the file.
//! REMARK: The algorithm may over prescribe what files to include because it doesn't discern between comments, etc.
//! Also, a #include line may be protected by #ifdef macros but this algorithm doesn't care.
//! Over prescribing is not a real problem, albeit potential waste in processing. Under prescribing would be a real problem.
AZStd::vector<AZStd::string> ParseStringAndGetIncludedFiles(AZStd::string_view haystack) const;
//! This static function was made public for testability purposes only.
//! Opens the file @sourceFilePath, loads the content into a string and returns ParseStringAndGetIncludedFiles(content)
AZ::Outcome<AZStd::vector<AZStd::string>, AZStd::string> ParseFileAndGetIncludedFiles(AZStd::string_view sourceFilePath) const;
private:
AZStd::regex m_includeRegex;
};
} // ShaderBuilderUtility namespace
} // ShaderBuilder namespace
} // AZ