Merge branch 'development' into Atom/dmcdiar/ATOM-4126

This commit is contained in:
dmcdiar
2021-09-15 18:22:38 -07:00
1231 changed files with 51892 additions and 50685 deletions
@@ -47,7 +47,7 @@ namespace ImageProcessingAtomEditor
protected:
////////////////////////////////////////////////////////////////////////
//EditorInternalNotificationBus
void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform);
void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform) override;
////////////////////////////////////////////////////////////////////////
private:
@@ -70,7 +70,7 @@ namespace ImageProcessingAtomEditor
protected:
////////////////////////////////////////////////////////////////////////
//EditorInternalNotificationBus
void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform);
void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform) override;
////////////////////////////////////////////////////////////////////////
void resizeEvent(QResizeEvent* event) override;
bool eventFilter(QObject* obj, QEvent* event) override;
@@ -52,7 +52,7 @@ namespace ImageProcessingAtomEditor
////////////////////////////////////////////////////////////////////////
//EditorInternalNotificationBus
void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform);
void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform) override;
////////////////////////////////////////////////////////////////////////
bool event(QEvent* event) override;
@@ -63,7 +63,7 @@ namespace ImageProcessingAtom
StepAll
};
const char ProcessStepNames[StepAll][64] =
[[maybe_unused]] const char ProcessStepNames[StepAll][64] =
{
"ValidateInput",
"GenerateColorChart",
@@ -65,6 +65,7 @@ ly_add_target(
AZ::AzFramework
AZ::AzToolsFramework
Gem::Atom_RHI.Edit
Gem::Atom_RPI.Edit
Gem::Atom_RPI.Public
)
@@ -21,7 +21,7 @@ namespace AZ
{
namespace AtomShaderConfig
{
static constexpr char AtomShaderConfigName[] = "AtomShaderConfig";
[[maybe_unused]] static constexpr char AtomShaderConfigName[] = "AtomShaderConfig";
bool MutateToFirstAbsoluteFolderThatExists(AZStd::string& relativeFolder, AZStd::vector<AZStd::string>& watchFolders)
{
@@ -17,6 +17,7 @@
#include <Atom/RHI.Edit/ShaderPlatformInterface.h>
#include <Atom/RHI.Edit/Utils.h>
#include <Atom/RPI.Edit/Common/JsonUtils.h>
#include <Atom/RPI.Reflect/Shader/ShaderOptionGroupLayout.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
@@ -1149,7 +1150,7 @@ namespace AZ
return BuildResult::CompilationFailed;
}
auto readJsonResult = JsonSerializationUtils::ReadJsonFile(outputFile);
auto readJsonResult = JsonSerializationUtils::ReadJsonFile(outputFile, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (readJsonResult.IsSuccess())
{
@@ -1170,7 +1171,7 @@ namespace AZ
AZStd::string outputFile = m_inputFilePath;
AzFramework::StringFunc::Path::ReplaceExtension(outputFile, outputExtension);
auto readJsonResult = JsonSerializationUtils::ReadJsonFile(outputFile);
auto readJsonResult = JsonSerializationUtils::ReadJsonFile(outputFile, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (readJsonResult.IsSuccess())
{
@@ -16,7 +16,7 @@ namespace AZ
{
namespace ShaderBuilder
{
static const char* s_azslShaderCompilerName = "AZSL Compiler";
[[maybe_unused]] static const char* s_azslShaderCompilerName = "AZSL Compiler";
AZ::RHI::Format StringToFormat(const char* format)
{
@@ -14,11 +14,11 @@
#include <AzCore/std/string/regex.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/IO/SystemFile.h>
#include <AzCore/Utils/Utils.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
@@ -56,7 +56,7 @@ namespace AZ
m_predefinedMacros.begin(), m_predefinedMacros.end(),
[&](const AZStd::string& predefinedMacro) {
// Haystack, needle, bCaseSensitive
if (!AzFramework::StringFunc::StartsWith(predefinedMacro, macroName, true))
if (!AZ::StringFunc::StartsWith(predefinedMacro, macroName, true))
{
return false;
}
@@ -117,11 +117,11 @@ namespace AZ
char localBuffer[DefaultFprintfBufferSize];
va_list args;
va_start(args, format);
int count = azvsnprintf(localBuffer, DefaultFprintfBufferSize, format, args);
va_end(args);
char* result = localBuffer;
// @result will be bound to @biggerData in case @localBuffer is not big enough.
@@ -134,7 +134,7 @@ namespace AZ
count++; // vsnprintf returns a size that doesn't include the null character.
biggerData.reset(new char[count]);
result = &biggerData[0];
// Remark: for MacOS & Linux it is important to call va_start again before
// each call to azvsnprintf. Not required for Windows.
va_start(args, format);
@@ -149,7 +149,7 @@ namespace AZ
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/vsnprintf-vsnprintf-vsnprintf-l-vsnwprintf-vsnwprintf-l?view=msvc-160
// In particular: "If the number of characters to write is greater than count,
// these functions return -1 indicating that output has been truncated."
// There wasn't enough space in the local store.
// Remark: for MacOS & Linux it is important to call va_start again before
// each call to azvsnprintf. Not required for Windows.
@@ -157,10 +157,10 @@ namespace AZ
count = azvscprintf(format, args);
count += 1; // vscprintf returns a size that doesn't include the null character.
va_end(args);
biggerData.reset(new char[count]);
result = &biggerData[0];
va_start(args, format);
count = azvsnprintf(result, count, format, args);
va_end(args);
@@ -191,7 +191,7 @@ namespace AZ
// definitions for the linker
AZStd::mutex McppBinder::s_mcppExclusiveProtection;
McppBinder* McppBinder::s_currentInstance = nullptr;
McppBinder* McppBinder::s_currentInstance = nullptr;
// McppBinder ends
///////////////////////////////////////////////////////////////////////
@@ -204,7 +204,7 @@ namespace AZ
// create the argc/argv
const char* processName = "builder";
const char* inputPath = fullPath.c_str();
const char* inputPath = fullPath.c_str();
// let's create the equivalent of that expression but in dynamic form:
//const char* argv[] = { processName, szInPath, "-C", "-+", "-D macro1"..., "-I path"..., NULL };
AZStd::vector< const char* > argv;
@@ -230,7 +230,7 @@ namespace AZ
argv.push_back(nullptr); // usual argv terminator
// output the command line:
AZStd::string stringifiedCommandLine;
AzFramework::StringFunc::Join(stringifiedCommandLine, argv.begin(), argv.end() - 1, " ");
AZ::StringFunc::Join(stringifiedCommandLine, argv.begin(), argv.end() - 1, " ");
AZ_TracePrintf("Preprocessor", "%s", stringifiedCommandLine.c_str());
// when we don't specify an -o outfile, mcpp uses stdout.
// the trick is that since we hijacked putc & puts, stdout will not be written.
@@ -238,17 +238,12 @@ namespace AZ
return result;
}
static void VerifySameFolder(const AZStd::string& path1, const AZStd::string& path2)
static void VerifySameFolder([[maybe_unused]] AZStd::string_view path1, [[maybe_unused]] AZStd::string_view path2)
{
AZStd::string folder1, folder2;
AzFramework::StringFunc::Path::GetFolderPath(path1.c_str(), folder1);
AzFramework::StringFunc::Path::GetFolderPath(path2.c_str(), folder2);
AzFramework::StringFunc::Path::Normalize(folder1);
AzFramework::StringFunc::Path::Normalize(folder2);
AZ_Warning("Preprocessing",
folder1 == folder2,
"The preprocessed file %s is in a different folder than its origin %s. Watch for #include problems with relative paths.",
path1.c_str(), path2.c_str()
AZ::IO::PathView(path1).ParentPath().LexicallyNormal() == AZ::IO::PathView(path2).ParentPath().LexicallyNormal(),
"The preprocessed file %.*s is in a different folder than its origin %.*s. Watch for #include problems with relative paths.",
AZ_STRING_ARG(path1), AZ_STRING_ARG(path2)
);
}
@@ -260,7 +255,7 @@ namespace AZ
// containing file names, to match the ORIGINAL source, and not the actual source in use by azslc.
// That gymnastic is better for error messages anyway, so instead of making the SRG layout builder more intelligent,
// we'll fake the origin of the file, by setting the original source as a filename
// note that it is not possible to build a file in a different folder and fake it to a file eslewhere because relative includes will fail.
// note that it is not possible to build a file in a different folder and fake it to a file elsewhere because relative includes will fail.
void MutateLineDirectivesFileOrigin(
AZStd::string& sourceCode,
AZStd::string newFileOrigin)
@@ -272,11 +267,11 @@ namespace AZ
// we will use that as the information of the source path to mutate.
if (sourceCode.starts_with("#line"))
{
auto firstQuote = sourceCode.find('"');
auto secondQuote = sourceCode.find('"', firstQuote + 1);
auto firstQuote = sourceCode.find('"');
auto secondQuote = firstQuote != AZStd::string::npos ? sourceCode.find('"', firstQuote + 1) : AZStd::string::npos;
auto originalFile = sourceCode.substr(firstQuote + 1, secondQuote - firstQuote - 1); // start +1, count -1 because we don't want the quotes included.
VerifySameFolder(originalFile, newFileOrigin);
[[maybe_unused]] bool didReplace = AzFramework::StringFunc::Replace(sourceCode, originalFile.c_str(), newFileOrigin.c_str(), true /*case sensitive*/);
[[maybe_unused]] bool didReplace = AZ::StringFunc::Replace(sourceCode, originalFile.c_str(), newFileOrigin.c_str(), true /*case sensitive*/);
AZ_Assert(didReplace, "Failed to replace %s for %s in preprocessed source.", originalFile.c_str(), newFileOrigin.c_str());
}
else
@@ -285,26 +280,6 @@ namespace AZ
}
}
namespace
{
template< typename Container1, typename Container2 >
void TransferContent(Container1& destination, Container2&& source)
{
destination.insert(AZStd::end(destination),
AZStd::make_move_iterator(AZStd::begin(source)),
AZStd::make_move_iterator(AZStd::end(source)));
}
void DeleteFromSet(const AZStd::string& string, AZStd::set<AZStd::string>& set)
{
auto iter = set.find(string);
if (iter != set.end())
{
set.erase(iter);
}
}
}
// populate options with scan folders and contents of parsing shader_global_build_options.json
void InitializePreprocessorOptions(
PreprocessorOptions& options, [[maybe_unused]] const char* builderName, const char* optionalIncludeFolder)
@@ -315,44 +290,61 @@ namespace AZ
bool success = true;
AZStd::vector<AZStd::string> scanFoldersVector;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(success,
&AzToolsFramework::AssetSystemRequestBus::Events::GetScanFolders,
scanFoldersVector);
&AzToolsFramework::AssetSystemRequestBus::Events::GetScanFolders,
scanFoldersVector);
AZ_Warning(builderName, success, "Preprocessor option: Could not acquire a list of scan folders from the database.");
// we transfer to a set, to order the folders, uniquify them, and ensure deterministic build behavior
AZStd::set<AZStd::string> scanFoldersSet;
// Add the project path to list of include paths
AZ::IO::FixedMaxPathString projectPath = AZ::Utils::GetProjectPath();
scanFoldersSet.emplace(projectPath.c_str(), projectPath.size());
AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath();
auto FindPath = [](AZ::IO::PathView searchPath)
{
return [searchPath](AZStd::string_view includePathView)
{
return searchPath == AZ::IO::PathView(includePathView);
};
};
if (auto it = AZStd::find_if(options.m_projectIncludePaths.begin(), options.m_projectIncludePaths.end(), FindPath(projectPath));
it == options.m_projectIncludePaths.end())
{
options.m_projectIncludePaths.emplace_back(projectPath.c_str(), projectPath.Native().size());
}
if (optionalIncludeFolder)
{
scanFoldersSet.emplace(optionalIncludeFolder, strnlen(optionalIncludeFolder, AZ::IO::MaxPathLength));
if (auto it = AZStd::find_if(options.m_projectIncludePaths.begin(), options.m_projectIncludePaths.end(), FindPath(optionalIncludeFolder));
it == options.m_projectIncludePaths.end())
{
if (AZ::IO::SystemFile::Exists(optionalIncludeFolder))
{
options.m_projectIncludePaths.emplace_back(AZStd::move(AZ::IO::Path(optionalIncludeFolder).LexicallyNormal().Native()));
}
}
}
// but while we transfer to the set, we're going to keep only folders where +/ShaderLib exists
for (AZStd::string folder : scanFoldersVector)
for (AZ::IO::Path shaderScanFolder : scanFoldersVector)
{
AzFramework::StringFunc::Path::Join(folder.c_str(), "ShaderLib", folder);
if (AZ::IO::SystemFile::Exists(folder.c_str()))
shaderScanFolder /= "ShaderLib";
if (auto it = AZStd::find_if(options.m_projectIncludePaths.begin(), options.m_projectIncludePaths.end(), FindPath(shaderScanFolder));
it == options.m_projectIncludePaths.end())
{
scanFoldersSet.emplace(std::move(folder));
// the folders constructed this fashion constitute the base of automatic include search paths
if (AZ::IO::SystemFile::Exists(shaderScanFolder.c_str()))
{
options.m_projectIncludePaths.emplace_back(AZStd::move(shaderScanFolder.LexicallyNormal().Native()));
}
}
} // the folders constructed this fashion constitute the base of automatic include search paths
// get the engine root:
AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath();
// add optional additional options
for (AZStd::string& path : options.m_projectIncludePaths)
{
path = (engineRoot / path).String();
DeleteFromSet(path, scanFoldersSet); // no need to add a path two times.
}
// back-insert the default paths (after the config-read paths we just read)
TransferContent(/*to:*/options.m_projectIncludePaths, /*from:*/scanFoldersSet);
// finally the <engineroot>/Gems fallback
AZStd::string gemsFolder;
AzFramework::StringFunc::Path::Join(engineRoot.c_str(), "Gems", gemsFolder);
options.m_projectIncludePaths.push_back(gemsFolder);
AZ::IO::Path engineGemsFolder(AZStd::string_view{ AZ::Utils::GetEnginePath() });
engineGemsFolder /= "Gems";
if (auto it = AZStd::find_if(options.m_projectIncludePaths.begin(), options.m_projectIncludePaths.end(), FindPath(engineGemsFolder));
it == options.m_projectIncludePaths.end())
{
if (AZ::IO::SystemFile::Exists(engineGemsFolder.c_str()))
{
options.m_projectIncludePaths.emplace_back(AZStd::move(engineGemsFolder.Native()));
}
}
}
} // namespace ShaderBuilder
@@ -26,7 +26,7 @@ namespace AZ
{
namespace
{
static const char* PrecompiledShaderBuilderName = "PrecompiledShaderBuilder";
[[maybe_unused]] static const char* PrecompiledShaderBuilderName = "PrecompiledShaderBuilder";
static const char* PrecompiledShaderBuilderJobKey = "PrecompiledShader Asset Builder";
static const char* ShaderAssetExtension = "azshader";
}
@@ -20,6 +20,7 @@
#include <Atom/RHI.Edit/ShaderPlatformInterface.h>
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Common/JsonUtils.h>
#include <Atom/RHI.Reflect/ConstantsLayout.h>
#include <Atom/RHI.Reflect/PipelineLayoutDescriptor.h>
#include <Atom/RHI.Reflect/ShaderStageFunction.h>
@@ -60,10 +61,99 @@ namespace AZ
static constexpr char ShaderAssetBuilderName[] = "ShaderAssetBuilder";
static constexpr uint32_t ShaderAssetBuildTimestampParam = 0;
//! The search will start in @currentFolderPath.
//! if the file is not found then it searches in order of appearence in @includeDirectories.
//! If the search yields no existing file it returns an empty string.
static AZStd::string DiscoverFullPath(AZStd::string_view normalizedRelativePath, AZStd::string_view currentFolderPath, const AZStd::vector<AZStd::string>& includeDirectories)
{
AZStd::string fullPath;
AzFramework::StringFunc::Path::Join(currentFolderPath.data(), normalizedRelativePath.data(), fullPath);
if (AZ::IO::SystemFile::Exists(fullPath.c_str()))
{
return fullPath;
}
for (const auto &includeDir : includeDirectories)
{
AzFramework::StringFunc::Path::Join(includeDir.c_str(), normalizedRelativePath.data(), fullPath);
if (AZ::IO::SystemFile::Exists(fullPath.c_str()))
{
return fullPath;
}
}
return "";
}
// Appends to @includedFiles normalized paths of possible future locations of the file @normalizedRelativePath.
// The future locations are each directory listed in @includeDirectories joined with @normalizedRelativePath.
// This function is called when an included file doesn't exist but We need to declare source dependency so a .shader
// asset is rebuilt when the missing file appears in the future.
static void AppendListOfPossibleFutureLocations(AZStd::unordered_set<AZStd::string>& includedFiles, AZStd::string_view normalizedRelativePath, AZStd::string_view currentFolderPath, const AZStd::vector<AZStd::string>& includeDirectories)
{
AZStd::string fullPath;
AzFramework::StringFunc::Path::Join(currentFolderPath.data(), normalizedRelativePath.data(), fullPath);
includedFiles.insert(fullPath);
for (const auto &includeDir : includeDirectories)
{
AzFramework::StringFunc::Path::Join(includeDir.c_str(), normalizedRelativePath.data(), fullPath);
includedFiles.insert(fullPath);
}
}
//! Parses, using depth-first recursive approach, azsl files. Looks for '#include <foo/bar/blah.h>' or '#include "foo/bar/blah.h"' lines
//! and in turn parses the included files.
//! The included files are searched in the directories listed in @includeDirectories. Basically it's a similar approach
//! as how most C-preprocessors would find included files.
static void GetListOfIncludedFiles(AZStd::string_view sourceFilePath, const AZStd::vector<AZStd::string>& includeDirectories,
const ShaderBuilderUtility::IncludedFilesParser& includedFilesParser, AZStd::unordered_set<AZStd::string>& includedFiles)
{
auto outcome = includedFilesParser.ParseFileAndGetIncludedFiles(sourceFilePath);
if (!outcome.IsSuccess())
{
AZ_Warning(ShaderAssetBuilderName, false, outcome.GetError().c_str());
return;
}
// Cache the path of the folder where @sourceFilePath is located.
AZStd::string sourceFileFolderPath;
{
AZStd::string drive;
AzFramework::StringFunc::Path::Split(sourceFilePath.data(), &drive, &sourceFileFolderPath);
if (!drive.empty())
{
AzFramework::StringFunc::Path::Join(drive.c_str(), sourceFileFolderPath.c_str(), sourceFileFolderPath);
}
}
auto listOfRelativePaths = outcome.TakeValue();
for (auto relativePath : listOfRelativePaths)
{
auto fullPath = DiscoverFullPath(relativePath, sourceFileFolderPath, includeDirectories);
if (fullPath.empty())
{
// The file doesn't exist in any of the includeDirectories. It doesn't exist in @sourceFileFolderPath either.
// The file may appear in the future in one of those directories, We must build an exhaustive list
// of full file paths where the file may appear in the future.
AppendListOfPossibleFutureLocations(includedFiles, relativePath, sourceFileFolderPath, includeDirectories);
continue;
}
// Add the file to the list and keep parsing recursively.
if (includedFiles.count(fullPath))
{
continue;
}
includedFiles.insert(fullPath);
GetListOfIncludedFiles(fullPath, includeDirectories, includedFilesParser, includedFiles);
}
}
void ShaderAssetBuilder::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response) const
{
AZStd::string fullPath;
AzFramework::StringFunc::Path::ConstructFull(request.m_watchFolder.data(), request.m_sourceFile.data(), fullPath, true);
ShaderBuilderUtility::IncludedFilesParser includedFilesParser;
AZ_TracePrintf(ShaderAssetBuilderName, "CreateJobs for Shader \"%s\"\n", fullPath.data());
@@ -89,36 +179,6 @@ namespace AZ
AZStd::string azslFullPath;
ShaderBuilderUtility::GetAbsolutePathToAzslFile(fullPath, shaderSourceData.m_source, azslFullPath);
if (!IO::FileIOBase::GetInstance()->Exists(azslFullPath.c_str()))
{
AZ_Error(
ShaderAssetBuilderName, false, "Shader program listed as the source entry does not exist: %s.", azslFullPath.c_str());
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Failed;
return;
}
GlobalBuildOptions buildOptions = ReadBuildOptions(ShaderAssetBuilderName);
// [GFX TODO] [ATOM-14966] In principle, based on macro definitions, included files can change per supervariant.
// So, the list of source asset dependencies must be collected by running MCPP on each supervariant.
// For now, we will run MCPP only once because CreateJobs() should be as light as possible.
//
// Regardless of the PlatformInfo and enabled ShaderPlatformInterfaces, the azsl file will be preprocessed
// with the sole purpose of extracting all included files. For each included file a SourceDependency will be declared.
PreprocessorData output;
buildOptions.m_compilerArguments.Merge(shaderSourceData.m_compiler);
PreprocessFile(azslFullPath, output, buildOptions.m_preprocessorSettings, true, true);
for (auto includePath : output.includedPaths)
{
// m_sourceFileDependencyList does not support paths with "." or ".." for relative lookup, but the preprocessor
// may produce path strings like "C:/a/b/c/../../d/file.azsli" so we have to normalize
AzFramework::StringFunc::Path::Normalize(includePath);
AssetBuilderSDK::SourceFileDependency includeFileDependency;
includeFileDependency.m_sourceFileDependencyPath = includePath;
response.m_sourceFileDependencyList.emplace_back(includeFileDependency);
}
{
// Add the AZSL as source dependency
@@ -127,6 +187,26 @@ namespace AZ
response.m_sourceFileDependencyList.emplace_back(azslFileDependency);
}
if (!IO::FileIOBase::GetInstance()->Exists(azslFullPath.c_str()))
{
AZ_Error(
ShaderAssetBuilderName, false, "Shader program listed as the source entry does not exist: %s.", azslFullPath.c_str());
// Treat as success, so when the azsl file shows up the AP will try to recompile.
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
return;
}
GlobalBuildOptions buildOptions = ReadBuildOptions(ShaderAssetBuilderName);
AZStd::unordered_set<AZStd::string> includedFiles;
GetListOfIncludedFiles(azslFullPath, buildOptions.m_preprocessorSettings.m_projectIncludePaths, includedFilesParser, includedFiles);
for (auto includePath : includedFiles)
{
AssetBuilderSDK::SourceFileDependency includeFileDependency;
includeFileDependency.m_sourceFileDependencyPath = includePath;
response.m_sourceFileDependencyList.emplace_back(includeFileDependency);
}
for (const AssetBuilderSDK::PlatformInfo& platformInfo : request.m_enabledPlatforms)
{
AZ_TraceContext("For platform", platformInfo.m_identifier.data());
@@ -148,6 +228,10 @@ namespace AZ
response.m_createJobOutputs.push_back(jobDescriptor);
} // for all request.m_enabledPlatforms
const AZStd::sys_time_t createJobsEndStamp = AZStd::GetTimeNowMicroSecond();
const u64 createJobDurationMicros = createJobsEndStamp - shaderAssetBuildTimestamp;
AZ_TracePrintf(ShaderAssetBuilderName, "CreateJobs for %s took %llu microseconds", fullPath.c_str(), createJobDurationMicros );
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
}
@@ -285,6 +369,13 @@ namespace AZ
return;
}
}
else
{
// CreateJobs was not successful if there's no timestamp property in m_jobParameters.
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
AZ_Assert(false, "Missing ShaderAssetBuildTimestampParam");
return;
}
auto supervariantList = ShaderBuilderUtility::GetSupervariantListFromShaderSourceData(shaderSourceData);
@@ -555,7 +646,7 @@ namespace AZ
shaderAssetCreator.SetRenderStates(renderStates);
}
Outcome<AZStd::string, AZStd::string> hlslSourceCodeOutcome = Utils::ReadFile(hlslFullPath);
Outcome<AZStd::string, AZStd::string> hlslSourceCodeOutcome = Utils::ReadFile(hlslFullPath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!hlslSourceCodeOutcome.IsSuccess())
{
AZ_Error(
@@ -20,11 +20,13 @@
#include <AzCore/IO/IOUtils.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzCore/std/string/regex.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Common/JsonUtils.h>
#include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
#include <Atom/RPI.Reflect/Shader/ShaderOptionGroup.h>
@@ -45,13 +47,13 @@ namespace AZ
{
namespace ShaderBuilderUtility
{
static constexpr char ShaderBuilderUtilityName[] = "ShaderBuilderUtility";
[[maybe_unused]] static constexpr char ShaderBuilderUtilityName[] = "ShaderBuilderUtility";
Outcome<RPI::ShaderSourceData, AZStd::string> LoadShaderDataJson(const AZStd::string& fullPathToJsonFile)
{
RPI::ShaderSourceData shaderSourceData;
auto document = JsonSerializationUtils::ReadJsonFile(fullPathToJsonFile);
auto document = JsonSerializationUtils::ReadJsonFile(fullPathToJsonFile, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!document.IsSuccess())
{
@@ -127,7 +129,7 @@ namespace AZ
AZStd::unordered_map<int, Outcome<rapidjson::Document, AZStd::string>> outcomes;
for (int i : indicesOfInterest)
{
outcomes[i] = JsonSerializationUtils::ReadJsonFile(pathOfJsonFiles[i]);
outcomes[i] = JsonSerializationUtils::ReadJsonFile(pathOfJsonFiles[i], AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!outcomes[i].IsSuccess())
{
AZ_Error(builderName, false, "%s", outcomes[i].GetError().c_str());
@@ -622,7 +624,7 @@ namespace AZ
StructData inputStruct;
inputStruct.m_id = "";
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(pathToIaJson);
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(pathToIaJson, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!jsonOutcome.IsSuccess())
{
AZ_Error(ShaderBuilderUtilityName, false, "%s", jsonOutcome.GetError().c_str());
@@ -715,7 +717,7 @@ namespace AZ
StructData outputStruct;
outputStruct.m_id = "";
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(pathToOmJson);
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(pathToOmJson, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!jsonOutcome.IsSuccess())
{
AZ_Error(ShaderBuilderUtilityName, false, "%s", jsonOutcome.GetError().c_str());
@@ -813,6 +815,51 @@ namespace AZ
return success;
}
IncludedFilesParser::IncludedFilesParser()
{
AZStd::regex regex(R"(#\s*include\s+[<|"]([\w|/|\\|\.|-]+)[>|"])", AZStd::regex::ECMAScript);
m_includeRegex.swap(regex);
}
AZStd::vector<AZStd::string> IncludedFilesParser::ParseStringAndGetIncludedFiles(AZStd::string_view haystack) const
{
AZStd::vector<AZStd::string> listOfFilePaths;
AZStd::smatch match;
AZStd::string::const_iterator searchStart(haystack.cbegin());
while (AZStd::regex_search(searchStart, haystack.cend(), match, m_includeRegex))
{
if (match.size() > 1)
{
AZStd::string relativeFilePath(match[1].str().c_str());
AzFramework::StringFunc::Path::Normalize(relativeFilePath);
listOfFilePaths.push_back(relativeFilePath);
}
searchStart = match.suffix().first;
}
return listOfFilePaths;
}
AZ::Outcome<AZStd::vector<AZStd::string>, AZStd::string> IncludedFilesParser::ParseFileAndGetIncludedFiles(AZStd::string_view sourceFilePath) const
{
AZ::IO::FileIOStream stream(sourceFilePath.data(), AZ::IO::OpenMode::ModeRead);
if (!stream.IsOpen())
{
return AZ::Failure(AZStd::string::format("\"%s\" source file could not be opened.", sourceFilePath.data()));
}
if (!stream.CanRead())
{
return AZ::Failure(AZStd::string::format("\"%s\" source file could not be read.", sourceFilePath.data()));
}
AZStd::string hayStack;
hayStack.resize_no_construct(stream.GetLength());
stream.Read(stream.GetLength(), hayStack.data());
auto listOfFilePaths = ParseStringAndGetIncludedFiles(hayStack);
return AZ::Success(AZStd::move(listOfFilePaths));
}
} // namespace ShaderBuilderUtility
} // namespace ShaderBuilder
} // AZ
@@ -141,6 +141,29 @@ namespace AZ
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
@@ -478,7 +478,7 @@ namespace AZ
RPI::Ptr<RPI::ShaderOptionGroupLayout> shaderOptionGroupLayout = RPI::ShaderOptionGroupLayout::Create();
// The shader options define what options are available, what are the allowed values/range
// for each option and what is its default value.
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(optionsGroupJsonPath);
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(optionsGroupJsonPath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!jsonOutcome.IsSuccess())
{
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", jsonOutcome.GetError().c_str());
@@ -509,7 +509,7 @@ namespace AZ
}
auto functionsJsonPath = functionsJsonPathOutcome.TakeValue();
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(functionsJsonPath);
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(functionsJsonPath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!jsonOutcome.IsSuccess())
{
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", jsonOutcome.GetError().c_str());
@@ -541,7 +541,7 @@ namespace AZ
}
auto srgJsonPath = srgJsonPathOutcome.TakeValue();
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(srgJsonPath);
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(srgJsonPath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!jsonOutcome.IsSuccess())
{
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", jsonOutcome.GetError().c_str());
@@ -598,7 +598,7 @@ namespace AZ
}
auto bindingsJsonPath = bindingsJsonPathOutcome.TakeValue();
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(bindingsJsonPath);
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(bindingsJsonPath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!jsonOutcome.IsSuccess())
{
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", jsonOutcome.GetError().c_str());
@@ -630,7 +630,7 @@ namespace AZ
}
hlslSourcePath = hlslSourcePathOutcome.TakeValue();
Outcome<AZStd::string, AZStd::string> hlslSourceOutcome = Utils::ReadFile(hlslSourcePath);
Outcome<AZStd::string, AZStd::string> hlslSourceOutcome = Utils::ReadFile(hlslSourcePath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!hlslSourceOutcome.IsSuccess())
{
AZ_Error(
@@ -0,0 +1,86 @@
/*
* 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
*
*/
#include <AzTest/AzTest.h>
#include <AzCore/UnitTest/TestTypes.h>
#include "Common/ShaderBuilderTestFixture.h"
#include <ShaderBuilderUtility.h>
namespace UnitTest
{
using namespace AZ;
// The main purpose of this class is to test ShaderBuilderUtility functions
class ShaderBuilderUtilityTests : public ShaderBuilderTestFixture
{
}; // class ShaderBuilderUtilityTests
TEST_F(ShaderBuilderUtilityTests, IncludedFilesParser_ParseStringAndGetIncludedFiles)
{
AZStd::string haystack(
"Some content to parse\n"
"#include <valid_file1.azsli>\n"
"// #include <valid_file2.azsli>\n"
"blah # include \"valid_file3.azsli\"\n"
"bar include <a\\dire-ctory\\invalid-file4.azsli>\n"
"foo # include \"a/directory/valid-file5.azsli\"\n"
"# include <a\\dire-ctory\\valid-file6.azsli>\n"
"#includ \"a\\dire-ctory\\invalid-file7.azsli\"\n"
);
AZ::ShaderBuilder::ShaderBuilderUtility::IncludedFilesParser includedFilesParser;
auto fileList = includedFilesParser.ParseStringAndGetIncludedFiles(haystack);
EXPECT_EQ(fileList.size(), 5);
auto it = AZStd::find(fileList.begin(), fileList.end(), "valid_file1.azsli");
EXPECT_TRUE(it != fileList.end());
it = AZStd::find(fileList.begin(), fileList.end(), "valid_file2.azsli");
EXPECT_TRUE(it != fileList.end());
it = AZStd::find(fileList.begin(), fileList.end(), "valid_file3.azsli");
EXPECT_TRUE(it != fileList.end());
// Remark: From now on We must normalize because internally AZ::ShaderBuilder::ShaderBuilderUtility::IncludedFilesParser
// always returns normalized paths.
{
AZStd::string fileName("a\\dire-ctory\\invalid-file4.azsli");
AzFramework::StringFunc::Path::Normalize(fileName);
it = AZStd::find(fileList.begin(), fileList.end(), fileName);
EXPECT_TRUE(it == fileList.end());
}
{
AZStd::string fileName("a\\directory\\valid-file5.azsli");
AzFramework::StringFunc::Path::Normalize(fileName);
it = AZStd::find(fileList.begin(), fileList.end(), fileName);
EXPECT_TRUE(it != fileList.end());
}
{
AZStd::string fileName("a\\dire-ctory\\valid-file6.azsli");
AzFramework::StringFunc::Path::Normalize(fileName);
it = AZStd::find(fileList.begin(), fileList.end(), fileName);
EXPECT_TRUE(it != fileList.end());
}
{
AZStd::string fileName("a\\dire-ctory\\invalid-file7.azsli");
AzFramework::StringFunc::Path::Normalize(fileName);
it = AZStd::find(fileList.begin(), fileList.end(), fileName);
EXPECT_TRUE(it == fileList.end());
}
}
} //namespace UnitTest
//AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);
@@ -11,4 +11,5 @@ set(FILES
Tests/Common/ShaderBuilderTestFixture.cpp
Tests/SupervariantCmdArgumentTests.cpp
Tests/McppBinderTests.cpp
Tests/ShaderBuilderUtilityTests.cpp
)
@@ -56,7 +56,8 @@ namespace AZ
//////////////////////////////////////////////////////////////////////////
virtual void OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) = 0;
virtual void OnBootstrapSceneReady([[maybe_unused]]AZ::RPI::Scene* bootstrapScene){}
virtual void OnFrameRateLimitChanged([[maybe_unused]]float fpsLimit){}
};
using NotificationBus = AZ::EBus<Notification>;
} // namespace Bootstrap
@@ -23,6 +23,8 @@ namespace AZ::Render::Bootstrap
virtual AZ::RPI::ScenePtr GetOrCreateAtomSceneFromAzScene(AzFramework::Scene* scene) = 0;
virtual bool EnsureDefaultRenderPipelineInstalledForScene(AZ::RPI::ScenePtr scene, AZ::RPI::ViewportContextPtr viewportContext) = 0;
virtual float GetFrameRateLimit() const = 0;
virtual void SetFrameRateLimit(float fpsLimit) = 0;
protected:
~Request() = default;
@@ -33,6 +33,7 @@
#include <Atom/RPI.Public/ViewportContextBus.h>
#include <Atom/RPI.Public/RPISystemInterface.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <Atom/RPI.Public/Shader/ShaderSystem.h>
#include <Atom/Bootstrap/DefaultWindowBus.h>
#include <Atom/Bootstrap/BootstrapNotificationBus.h>
@@ -41,7 +42,14 @@
#include <AzCore/Console/IConsole.h>
#include <BootstrapSystemComponent_Traits_Platform.h>
static void OnFrameRateLimitChanged(const float& fpsLimit)
{
AZ::Render::Bootstrap::RequestBus::Broadcast(
&AZ::Render::Bootstrap::RequestBus::Events::SetFrameRateLimit, fpsLimit);
}
AZ_CVAR(AZ::CVarFixedString, r_default_pipeline_name, AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Default Render pipeline name");
AZ_CVAR(float, r_fps_limit, 0, OnFrameRateLimitChanged, AZ::ConsoleFunctorFlags::Null, "The maximum framerate to render at, or 0 for unlimited");
namespace AZ
{
@@ -253,34 +261,6 @@ namespace AZ
RPI::SceneDescriptor sceneDesc;
AZ::RPI::ScenePtr atomScene = RPI::Scene::CreateScene(sceneDesc);
atomScene->EnableAllFeatureProcessors();
// Setup scene srg modification callback.
RPI::ShaderResourceGroupCallback callback = [this](RPI::ShaderResourceGroup* srg)
{
if (srg == nullptr)
{
return;
}
bool needCompile = false;
RHI::ShaderInputConstantIndex timeIndex = srg->FindShaderInputConstantIndex(Name{ "m_time" });
if (timeIndex.IsValid())
{
srg->SetConstant(timeIndex, m_simulateTime);
needCompile = true;
}
RHI::ShaderInputConstantIndex deltaTimeIndex = srg->FindShaderInputConstantIndex(Name{ "m_deltaTime" });
if (deltaTimeIndex.IsValid())
{
srg->SetConstant(deltaTimeIndex, m_deltaTime);
needCompile = true;
}
if (needCompile)
{
srg->Compile();
}
};
atomScene->SetShaderResourceGroupCallback(callback);
atomScene->Activate();
// Register scene to RPI system so it will be processed/rendered per tick
@@ -324,6 +304,11 @@ namespace AZ
RPI::RenderPipelineDescriptor renderPipelineDescriptor = *RPI::GetDataFromAnyAsset<RPI::RenderPipelineDescriptor>(pipelineAsset);
renderPipelineDescriptor.m_name = AZStd::string::format("%s_%i", renderPipelineDescriptor.m_name.c_str(), viewportContext->GetId());
// Make sure non-msaa super variant is used for non-msaa pipeline
bool isNonMsaaPipeline = (renderPipelineDescriptor.m_renderSettings.m_multisampleState.m_samples == 1);
const char* supervariantName = isNonMsaaPipeline ? AZ::RPI::NoMsaaSupervariantName : "";
AZ::RPI::ShaderSystemInterface::Get()->SetSupervariantName(AZ::Name(supervariantName));
if (!scene->GetRenderPipeline(AZ::Name(renderPipelineDescriptor.m_name)))
{
RPI::RenderPipelinePtr renderPipeline = RPI::RenderPipeline::CreateRenderPipelineForWindow(renderPipelineDescriptor, *viewportContext->GetWindowContext().get());
@@ -370,6 +355,22 @@ namespace AZ
return true;
}
float BootstrapSystemComponent::GetFrameRateLimit() const
{
return r_fps_limit;
}
void BootstrapSystemComponent::SetFrameRateLimit(float fpsLimit)
{
r_fps_limit = fpsLimit;
if (m_viewportContext)
{
m_viewportContext->SetFpsLimit(r_fps_limit);
}
Render::Bootstrap::NotificationBus::Broadcast(
&Render::Bootstrap::NotificationBus::Events::OnFrameRateLimitChanged, fpsLimit);
}
void BootstrapSystemComponent::CreateDefaultRenderPipeline()
{
EnsureDefaultRenderPipelineInstalledForScene(m_defaultScene, m_viewportContext);
@@ -391,7 +392,7 @@ namespace AZ
// Unbind m_defaultScene to the GameEntityContext's AzFramework::Scene
if (m_defaultFrameworkScene)
{
m_defaultFrameworkScene->UnsetSubsystem<RPI::Scene>();
m_defaultFrameworkScene->UnsetSubsystem(m_defaultScene);
}
m_defaultScene = nullptr;
@@ -408,27 +409,12 @@ namespace AZ
m_renderPipelineId = "";
}
void BootstrapSystemComponent::OnTick(float deltaTime, [[maybe_unused]] ScriptTimePoint time)
{
m_simulateTime += deltaTime;
m_deltaTime = deltaTime;
// Temp: When running in the launcher without the legacy renderer
// we need to call RenderTick on the viewport context each frame.
if (m_viewportContext)
{
AZ::ApplicationTypeQuery appType;
ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationBus::Events::QueryApplicationType, appType);
if (appType.IsGame())
{
m_viewportContext->RenderTick();
}
}
}
void BootstrapSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time)
{ }
int BootstrapSystemComponent::GetTickOrder()
{
return TICK_LAST;
return TICK_PRE_RENDER;
}
void BootstrapSystemComponent::OnWindowClosed()
@@ -69,6 +69,8 @@ namespace AZ
// Render::Bootstrap::RequestBus::Handler overrides ...
AZ::RPI::ScenePtr GetOrCreateAtomSceneFromAzScene(AzFramework::Scene* scene) override;
bool EnsureDefaultRenderPipelineInstalledForScene(AZ::RPI::ScenePtr scene, AZ::RPI::ViewportContextPtr viewportContext) override;
float GetFrameRateLimit() const override;
void SetFrameRateLimit(float fpsLimit) override;
protected:
// Component overrides ...
@@ -105,9 +107,6 @@ namespace AZ
RPI::ScenePtr m_defaultScene = nullptr;
AZStd::shared_ptr<AzFramework::Scene> m_defaultFrameworkScene = nullptr;
float m_simulateTime = 0;
float m_deltaTime = 0.016f;
bool m_isAssetCatalogLoaded = false;
// The id of the render pipeline created by this component
@@ -40,9 +40,11 @@
}
]
},
{
"Name": "HorizontalGaussianFilter",
"TemplateName": "FilterDepthHorizontalTemplate",
"Name": "KawaseBlur0",
"TemplateName": "KawaseShadowBlurTemplate",
"Enabled": true,
"Connections": [
{
"LocalSlot": "Input",
@@ -54,26 +56,27 @@
]
},
{
"Name": "VerticalGaussianFiter",
"TemplateName": "FilterDepthVerticalTemplate",
"Name": "KawaseBlur1",
"TemplateName": "KawaseShadowBlurTemplate",
"Enabled": true,
"Connections": [
{
"LocalSlot": "Input",
"AttachmentRef": {
"Pass": "HorizontalGaussianFilter",
"Pass": "KawaseBlur0",
"Attachment": "Output"
}
}
]
}
}
],
"Connections": [
{
"LocalSlot": "EsmShadowmaps",
"AttachmentRef": {
"Pass": "VerticalGaussianFiter",
"Pass": "KawaseBlur1",
"Attachment": "Output"
}
}
}
]
}
@@ -1,72 +0,0 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PassAsset",
"ClassData": {
"PassTemplate": {
"Name": "FilterDepthHorizontalTemplate",
"PassClass": "ComputePass",
"Slots": [
{
"Name": "Input",
"SlotType": "Input",
"ShaderInputName": "m_inputImage",
"ScopeAttachmentUsage": "Shader",
"LoadStoreAction": {
"LoadAction": "Load",
"StoreAction": "DontCare"
},
"ImageViewDesc": {
"IsArray": 1
}
},
{
"Name": "Output",
"SlotType": "Output",
"ShaderInputName": "m_outputImage",
"ScopeAttachmentUsage": "Shader",
"LoadStoreAction": {
"LoadAction": "DontCare",
"StoreAction": "Store"
},
"ImageViewDesc": {
"IsArray": 1
}
}
],
"PassData": {
"$type": "ComputePassData",
"ShaderAsset": {
"FilePath": "Shaders/Math/GaussianFilterFloatHorizontal.shader"
}
},
"ImageAttachments": [
{
"Name": "HorizontalFiltered",
"SizeSource": {
"Source": {
"Pass": "This",
"Attachment": "Input"
}
},
"ArraySizeSource": {
"Pass": "This",
"Attachment": "Input"
},
"ImageDescriptor": {
"Format": "R32_FLOAT"
}
}
],
"Connections": [
{
"localSlot": "Output",
"AttachmentRef": {
"Pass": "This",
"Attachment": "HorizontalFiltered"
}
}
]
}
}
}
@@ -0,0 +1,215 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PassAsset",
"ClassData": {
"PassTemplate": {
"Name": "HDRColorGradingTemplate",
"PassClass": "FullScreenTriangle",
"Slots": [
{
"Name": "Input",
"SlotType": "Input",
"ShaderInputName": "m_framebuffer",
"ScopeAttachmentUsage": "Shader"
},
{
"Name": "Output",
"SlotType": "Output",
"ScopeAttachmentUsage": "RenderTarget",
"LoadStoreAction": {
"LoadAction": "DontCare"
}
}
],
"ImageAttachments": [
{
"Name": "ColorGradingOutput",
"SizeSource": {
"Source": {
"Pass": "This",
"Attachment": "Input"
}
},
"FormatSource": {
"Pass": "This",
"Attachment": "Input"
}
}
],
"Connections": [
{
"LocalSlot": "Output",
"AttachmentRef": {
"Pass": "This",
"Attachment": "ColorGradingOutput"
}
}
],
"FallbackConnections": [
{
"Input": "Input",
"Output": "Output"
}
],
"PassData": {
"$type": "FullscreenTrianglePassData",
"ShaderAsset": {
"FilePath": "Shaders/PostProcessing/HDRColorGrading.shader"
},
"ShaderDataMappings": {
"FloatMappings": [
{
"Name": "m_colorGradingExposure",
"Value": 0.0 // unconstrained, log2 stops
},
{
"Name": "m_colorGradingContrast",
"Value": 0.0 // -100 ... 100
},
{
"Name": "m_colorGradingHueShift",
"Value": 0.0 // 0 ... 1, can wrap
},
{
"Name": "m_colorGradingPreSaturation",
"Value": 1.0 // -100 ... 100
},
{
"Name": "m_colorFilterIntensity",
"Value": 1.0 // unconstrained, log2 stops
},
{
"Name": "m_colorFilterMultiply",
"Value": 0.0 // modulate, 0 ... 1
},
{
"Name": "m_whiteBalanceKelvin",
"Value": 6500.0 // 1000.0f ... 40000.0f kelvin
},
{
"Name": "m_whiteBalanceTint",
"Value": 0.0 // -100 ... 100
},
{
"Name": "m_splitToneBalance",
"Value": 0.0 // -1 ... 1
},
{
"Name": "m_splitToneMix",
"Value": 0.0 // 0 ... 1
},
{
"Name": "m_colorGradingPostSaturation",
"Value": 1.0 // -100 ... 100
},
{
"Name": "m_smhShadowsStart",
"Value": 0.0 // 0 ... 1
},
{
"Name": "m_smhShadowsEnd",
"Value": 0.3 // 0 ... 1
},
{
"Name": "m_smhHighlightsStart",
"Value": 0.55 // 0 ... 1
},
{
"Name": "m_smhHighlightsEnd",
"Value": 1.0 // 0 ... 1
},
{
"Name": "m_smhMix",
"Value": 0.0 // 0 ... 1
}
],
// The colors defined here are expected to be in linear rgb color space.
// These are converted to ACEScg color space within the HDRColorGrading.azsl shader
"ColorMappings": [
{
"Name": "m_colorFilterSwatch",
"Value": [
1.0,
0.5,
0.5,
1.0
]
},
{
"Name": "m_splitToneShadowsColor",
"Value": [
1.0,
0.1,
0.1,
1.0
]
},
{
"Name": "m_splitToneHighlightsColor",
"Value": [
0.1,
1.0,
0.1,
1.0
]
},
{
"Name": "m_smhShadowsColor",
"Value": [
1.0,
0.25,
0.25,
1.0
]
},
{
"Name": "m_smhMidtonesColor",
"Value": [
0.1,
0.1,
1.0,
1.0
]
},
{
"Name": "m_smhHighlightsColor",
"Value": [
1.0,
0.0,
1.0,
1.0
]
}
],
"Float3Mappings": [
{
"Name": "m_channelMixingRed",
"Value": [
1.0,
0.0,
0.0
]
},
{
"Name": "m_channelMixingGreen",
"Value": [
0.0,
1.0,
0.0
]
},
{
"Name": "m_channelMixingBlue",
"Value": [
0.0,
0.0,
1.0
]
}
]
}
}
}
}
}
@@ -4,7 +4,7 @@
"ClassName": "PassAsset",
"ClassData": {
"PassTemplate": {
"Name": "FilterDepthVerticalTemplate",
"Name": "KawaseShadowBlurTemplate",
"PassClass": "ComputePass",
"Slots": [
{
@@ -28,7 +28,7 @@
"LoadStoreAction": {
"LoadAction": "DontCare",
"StoreAction": "Store"
},
},
"ImageViewDesc": {
"IsArray": 1
}
@@ -37,12 +37,12 @@
"PassData": {
"$type": "ComputePassData",
"ShaderAsset": {
"FilePath": "Shaders/Math/GaussianFilterFloatVertical.shader"
"FilePath": "Shaders/Shadow/KawaseShadowBlur.shader"
}
},
"ImageAttachments": [
{
"Name": "VerticalFiltered",
"Name": "FilteredImage",
"SizeSource": {
"Source": {
"Pass": "This",
@@ -63,7 +63,7 @@
"localSlot": "Output",
"AttachmentRef": {
"Pass": "This",
"Attachment": "VerticalFiltered"
"Attachment": "FilteredImage"
}
}
]
@@ -184,14 +184,6 @@
"Name": "DepthOfFieldWriteFocusDepthFromGpuTemplate",
"Path": "Passes/DepthOfFieldWriteFocusDepthFromGpu.pass"
},
{
"Name": "FilterDepthHorizontalTemplate",
"Path": "Passes/FilterDepthHorizontal.pass"
},
{
"Name": "FilterDepthVerticalTemplate",
"Path": "Passes/FilterDepthVertical.pass"
},
{
"Name": "EsmShadowmapsTemplate",
"Path": "Passes/EsmShadowmaps.pass"
@@ -503,7 +495,15 @@
{
"Name": "LowEndPipelineTemplate",
"Path": "Passes/LowEndPipeline.pass"
}
},
{
"Name": "KawaseShadowBlurTemplate",
"Path": "Passes/KawaseShadowBlur.pass"
},
{
"Name": "HDRColorGradingTemplate",
"Path": "Passes/HDRColorGrading.pass"
}
]
}
}
@@ -22,6 +22,7 @@ local FindMaterialAssignmentTest =
"materials/presets/macbeth/12_orange_yellow_srgb.tif.streamingimage",
"materials/presets/macbeth/17_magenta_srgb.tif.streamingimage"
},
MaterialSlotFilter = ""
},
}
@@ -50,18 +51,6 @@ function FindMaterialAssignmentTest:OnActivate()
self.colors = {}
self.lerpDirs = {}
self.assignmentIds =
{
MaterialComponentRequestBus.Event.FindMaterialAssignmentId(self.entityId, -1, "lambert"),
}
for index = 1, #self.assignmentIds do
local id = self.assignmentIds[index]
if (id ~= nil) then
self.colors[index] = randomColor()
self.lerpDirs[index] = randomDir()
end
end
self.tickBusHandler = TickBus.Connect(self);
end
@@ -144,10 +133,33 @@ function FindMaterialAssignmentTest:lerpColors(deltaTime)
end
function FindMaterialAssignmentTest:OnTick(deltaTime, timePoint)
if(nil == self.assignmentIds) then
local originalAssignments = MaterialComponentRequestBus.Event.GetOriginalMaterialAssignments(self.entityId)
if(nil == originalAssignments or #originalAssignments <= 1) then -- There is always 1 entry for the default assignment; a loaded model will have at least 2 assignments
return
end
self.assignmentIds =
{
MaterialComponentRequestBus.Event.FindMaterialAssignmentId(self.entityId, -1, self.Properties.MaterialSlotFilter),
}
for index = 1, #self.assignmentIds do
local id = self.assignmentIds[index]
if (id ~= nil) then
self.colors[index] = randomColor()
self.lerpDirs[index] = randomDir()
end
end
end
self.timer = self.timer + deltaTime
self.totalTime = self.totalTime + deltaTime
self:lerpColors(deltaTime)
if (self.timer > self.timeUpdate and self.totalTime < self.totalTimeMax) then
self.timer = self.timer - self.timeUpdate
self:UpdateProperties()
@@ -155,6 +167,7 @@ function FindMaterialAssignmentTest:OnTick(deltaTime, timePoint)
self:ClearProperties()
self.tickBusHandler:Disconnect(self);
end
end
return FindMaterialAssignmentTest
return FindMaterialAssignmentTest
@@ -0,0 +1,75 @@
/*
* 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) AND Creative Commons 3.0
*
*/
// Ref: https://www.shadertoy.com/view/lsSXW1
// ported by Renaud Bédard (@renaudbedard) from original code from Tanner Helland
// http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
// color space functions translated from HLSL versions on Chilli Ant (by Ian Taylor)
// http://www.chilliant.com/rgb2hsv.html
// licensed and released under Creative Commons 3.0 Attribution
// https://creativecommons.org/licenses/by/3.0/
float3 HueToRgb(float hue)
{
return saturate(float3(abs(hue * 6.0f - 3.0f) - 1.0f,
2.0f - abs(hue * 6.0f - 2.0f),
2.0f - abs(hue * 6.0f - 4.0f)));
}
float3 RgbToHcv(float3 rgb)
{
// Based on work by Sam Hocevar and Emil Persson
const float4 p = (rgb.g < rgb.b) ? float4(rgb.bg, -1.0f, 2.0f/3.0f) : float4(rgb.gb, 0.0f, -1.0f/3.0f);
const float4 q1 = (rgb.r < p.x) ? float4(p.xyw, rgb.r) : float4(rgb.r, p.yzx);
const float c = q1.x - min(q1.w, q1.y);
const float h = abs((q1.w - q1.y) / (6.0f * c + 0.000001f ) + q1.z);
return float3(h, c, q1.x);
}
float3 RgbToHsl(float3 rgb)
{
rgb.xyz = max(rgb.xyz, 0.000001f);
const float3 hcv = RgbToHcv(rgb);
const float L = hcv.z - hcv.y * 0.5f;
const float S = hcv.y / (1.0f - abs(L * 2.0f - 1.0f) + 0.000001f);
return float3(hcv.x, S, L);
}
float3 HslToRgb(float3 hsl)
{
const float3 rgb = HueToRgb(hsl.x);
const float c = (1.0f - abs(2.0f * hsl.z - 1.0f)) * hsl.y;
return (rgb - 0.5f) * c + hsl.z;
}
// Color temperature
float3 KelvinToRgb(float kelvin)
{
float3 ret;
kelvin = clamp(kelvin, 1000.0f, 40000.0f) / 100.0f;
if(kelvin <= 66.0f)
{
ret.r = 1.0f;
ret.g = saturate(0.39008157876901960784f * log(kelvin) - 0.63184144378862745098f);
}
else
{
float t = max(kelvin - 60.0f, 0.0f);
ret.r = saturate(1.29293618606274509804f * pow(t, -0.1332047592f));
ret.g = saturate(1.12989086089529411765f * pow(t, -0.0755148492f));
}
if(kelvin >= 66.0f)
ret.b = 1.0f;
else if(kelvin < 19.0f)
ret.b = 0.0f;
else
ret.b = saturate(0.54320678911019607843f * log(kelvin - 10.0f) - 1.19625408914f);
return ret;
}
@@ -0,0 +1,177 @@
/*
* 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
*
*/
/*
------------------------------------------------------------------------------
Public Domain
------------------------------------------------------------------------------
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
Source: https://www.ryanjuckett.com/photoshop-blend-modes-in-hlsl/
*/
//******************************************************************************
//******************************************************************************
float Color_GetLuminosity(float3 c)
{
return 0.3*c.r + 0.59*c.g + 0.11*c.b;
}
//******************************************************************************
//******************************************************************************
float3 Color_SetLuminosity(float3 c, float lum)
{
float d = lum - Color_GetLuminosity(c);
c.rgb += float3(d,d,d);
// clip back into legal range
lum = Color_GetLuminosity(c);
float cMin = min(c.r, min(c.g, c.b));
float cMax = max(c.r, max(c.g, c.b));
if(cMin < 0)
c = lerp(float3(lum,lum,lum), c, lum / (lum - cMin));
if(cMax > 1)
c = lerp(float3(lum,lum,lum), c, (1 - lum) / (cMax - lum));
return c;
}
//******************************************************************************
//******************************************************************************
float Color_GetSaturation(float3 c)
{
return max(c.r, max(c.g, c.b)) - min(c.r, min(c.g, c.b));
}
//******************************************************************************
// Set saturation if color components are sorted in ascending order.
//******************************************************************************
float3 Color_SetSaturation_MinMidMax(float3 cSorted, float s)
{
if(cSorted.z > cSorted.x)
{
cSorted.y = (((cSorted.y - cSorted.x) * s) / (cSorted.z - cSorted.x));
cSorted.z = s;
}
else
{
cSorted.y = 0;
cSorted.z = 0;
}
cSorted.x = 0;
return cSorted;
}
//******************************************************************************
//******************************************************************************
float3 Color_SetSaturation(float3 c, float s)
{
if (c.r <= c.g && c.r <= c.b)
{
if (c.g <= c.b)
c.rgb = Color_SetSaturation_MinMidMax(c.rgb, s);
else
c.rbg = Color_SetSaturation_MinMidMax(c.rbg, s);
}
else if (c.g <= c.r && c.g <= c.b)
{
if (c.r <= c.b)
c.grb = Color_SetSaturation_MinMidMax(c.grb, s);
else
c.gbr = Color_SetSaturation_MinMidMax(c.gbr, s);
}
else
{
if (c.r <= c.g)
c.brg = Color_SetSaturation_MinMidMax(c.brg, s);
else
c.bgr = Color_SetSaturation_MinMidMax(c.bgr, s);
}
return c;
}
//******************************************************************************
// Creates a color with the hue of the blend color and the saturation and
// luminosity of the base color.
//******************************************************************************
float3 BlendMode_Hue(float3 base, float3 blend)
{
return Color_SetLuminosity(Color_SetSaturation(blend, Color_GetSaturation(base)), Color_GetLuminosity(base));
}
//******************************************************************************
// Creates a color with the saturation of the blend color and the hue and
// luminosity of the base color.
//******************************************************************************
float3 BlendMode_Saturation(float3 base, float3 blend)
{
return Color_SetLuminosity(Color_SetSaturation(base, Color_GetSaturation(blend)), Color_GetLuminosity(base));
}
//******************************************************************************
// Creates a color with the hue and saturation of the blend color and the
// luminosity of the base color.
//******************************************************************************
float3 BlendMode_Color(float3 base, float3 blend)
{
return Color_SetLuminosity(blend, Color_GetLuminosity(base));
}
//******************************************************************************
// Creates a color with the luminosity of the blend color and the hue and
// saturation of the base color.
//******************************************************************************
float3 BlendMode_Luminosity(float3 base, float3 blend)
{
return Color_SetLuminosity(base, Color_GetLuminosity(blend));
}
//******************************************************************************
// Compares the total of all channel values for the blend and base color and
// displays the lower value color.
//******************************************************************************
float3 BlendMode_DarkerColor(float3 base, float3 blend)
{
return Color_GetLuminosity(base) <= Color_GetLuminosity(blend) ? base : blend;
}
//******************************************************************************
// Compares the total of all channel values for the blend and base color and
// displays the higher value color.
//******************************************************************************
float3 BlendMode_LighterColor(float3 base, float3 blend)
{
return Color_GetLuminosity(base) > Color_GetLuminosity(blend) ? base : blend;
}
@@ -0,0 +1,306 @@
/*
* 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
*
*/
/*
------------------------------------------------------------------------------
Public Domain
------------------------------------------------------------------------------
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
Source: https://www.ryanjuckett.com/photoshop-blend-modes-in-hlsl/
*/
//******************************************************************************
// Selects the blend color, ignoring the base.
//******************************************************************************
float3 BlendMode_Normal(float3 base, float3 blend)
{
return blend;
}
//******************************************************************************
// Looks at the color information in each channel and selects the base or blend
// color—whichever is darker—as the result color.
//******************************************************************************
float3 BlendMode_Darken(float3 base, float3 blend)
{
return min(base, blend);
}
//******************************************************************************
// Looks at the color information in each channel and multiplies the base color
// by the blend color.
//******************************************************************************
float3 BlendMode_Multiply(float3 base, float3 blend)
{
return base*blend;
}
//******************************************************************************
// Looks at the color information in each channel and darkens the base color to
// reflect the blend color by increasing the contrast between the two.
//******************************************************************************
float BlendMode_ColorBurn(float base, float blend)
{
return blend > 0 ? 1 - min(1, (1-base) / blend) : 0;
}
float3 BlendMode_ColorBurn(float3 base, float3 blend)
{
return float3( BlendMode_ColorBurn(base.r, blend.r),
BlendMode_ColorBurn(base.g, blend.g),
BlendMode_ColorBurn(base.b, blend.b) );
}
//******************************************************************************
// Looks at the color information in each channel and darkens the base color to
// reflect the blend color by decreasing the brightness.
//******************************************************************************
float BlendMode_LinearBurn(float base, float blend)
{
return max(0, base + blend - 1);
}
float3 BlendMode_LinearBurn(float3 base, float3 blend)
{
return float3( BlendMode_LinearBurn(base.r, blend.r),
BlendMode_LinearBurn(base.g, blend.g),
BlendMode_LinearBurn(base.b, blend.b) );
}
//******************************************************************************
// Looks at the color information in each channel and selects the base or blend
// color—whichever is lighter—as the result color.
//******************************************************************************
float3 BlendMode_Lighten(float3 base, float3 blend)
{
return max(base, blend);
}
//******************************************************************************
// Looks at each channels color information and multiplies the inverse of the
// blend and base colors.
//******************************************************************************
float3 BlendMode_Screen(float3 base, float3 blend)
{
return base + blend - base*blend;
}
//******************************************************************************
// Looks at the color information in each channel and brightens the base color
// to reflect the blend color by decreasing contrast between the two.
//******************************************************************************
float BlendMode_ColorDodge(float base, float blend)
{
return blend < 1 ? min(1, base / (1-blend)) : 1;
}
float3 BlendMode_ColorDodge(float3 base, float3 blend)
{
return float3( BlendMode_ColorDodge(base.r, blend.r),
BlendMode_ColorDodge(base.g, blend.g),
BlendMode_ColorDodge(base.b, blend.b) );
}
//******************************************************************************
// Looks at the color information in each channel and brightens the base color
// to reflect the blend color by decreasing contrast between the two.
//******************************************************************************
float BlendMode_LinearDodge(float base, float blend)
{
return min(1, base + blend);
}
float3 BlendMode_LinearDodge(float3 base, float3 blend)
{
return float3( BlendMode_LinearDodge(base.r, blend.r),
BlendMode_LinearDodge(base.g, blend.g),
BlendMode_LinearDodge(base.b, blend.b) );
}
//******************************************************************************
// Multiplies or screens the colors, depending on the base color.
//******************************************************************************
float BlendMode_Overlay(float base, float blend)
{
return (base <= 0.5) ? 2*base*blend : 1 - 2*(1-base)*(1-blend);
}
float3 BlendMode_Overlay(float3 base, float3 blend)
{
return float3( BlendMode_Overlay(base.r, blend.r),
BlendMode_Overlay(base.g, blend.g),
BlendMode_Overlay(base.b, blend.b) );
}
//******************************************************************************
// Darkens or lightens the colors, depending on the blend color.
//******************************************************************************
float BlendMode_SoftLight(float base, float blend)
{
if (blend <= 0.5)
{
return base - (1-2*blend)*base*(1-base);
}
else
{
float d = (base <= 0.25) ? ((16*base-12)*base+4)*base : sqrt(base);
return base + (2*blend-1)*(d-base);
}
}
float3 BlendMode_SoftLight(float3 base, float3 blend)
{
return float3( BlendMode_SoftLight(base.r, blend.r),
BlendMode_SoftLight(base.g, blend.g),
BlendMode_SoftLight(base.b, blend.b) );
}
//******************************************************************************
// Multiplies or screens the colors, depending on the blend color.
//******************************************************************************
float BlendMode_HardLight(float base, float blend)
{
return (blend <= 0.5) ? 2*base*blend : 1 - 2*(1-base)*(1-blend);
}
float3 BlendMode_HardLight(float3 base, float3 blend)
{
return float3( BlendMode_HardLight(base.r, blend.r),
BlendMode_HardLight(base.g, blend.g),
BlendMode_HardLight(base.b, blend.b) );
}
//******************************************************************************
// Burns or dodges the colors by increasing or decreasing the contrast,
// depending on the blend color.
//******************************************************************************
float BlendMode_VividLight(float base, float blend)
{
return (blend <= 0.5) ? BlendMode_ColorBurn(base,2*blend) : BlendMode_ColorDodge(base,2*(blend-0.5));
}
float3 BlendMode_VividLight(float3 base, float3 blend)
{
return float3( BlendMode_VividLight(base.r, blend.r),
BlendMode_VividLight(base.g, blend.g),
BlendMode_VividLight(base.b, blend.b) );
}
//******************************************************************************
// Burns or dodges the colors by decreasing or increasing the brightness,
// depending on the blend color.
//******************************************************************************
float BlendMode_LinearLight(float base, float blend)
{
return (blend <= 0.5) ? BlendMode_LinearBurn(base,2*blend) : BlendMode_LinearDodge(base,2*(blend-0.5));
}
float3 BlendMode_LinearLight(float3 base, float3 blend)
{
return float3( BlendMode_LinearLight(base.r, blend.r),
BlendMode_LinearLight(base.g, blend.g),
BlendMode_LinearLight(base.b, blend.b) );
}
//******************************************************************************
// Replaces the colors, depending on the blend color.
//******************************************************************************
float BlendMode_PinLight(float base, float blend)
{
return (blend <= 0.5) ? min(base,2*blend) : max(base,2*(blend-0.5));
}
float3 BlendMode_PinLight(float3 base, float3 blend)
{
return float3( BlendMode_PinLight(base.r, blend.r),
BlendMode_PinLight(base.g, blend.g),
BlendMode_PinLight(base.b, blend.b) );
}
//******************************************************************************
// Adds the red, green and blue channel values of the blend color to the RGB
// values of the base color. If the resulting sum for a channel is 255 or
// greater, it receives a value of 255; if less than 255, a value of 0.
//******************************************************************************
float BlendMode_HardMix(float base, float blend)
{
return (base + blend >= 1.0) ? 1.0 : 0.0;
}
float3 BlendMode_HardMix(float3 base, float3 blend)
{
return float3( BlendMode_HardMix(base.r, blend.r),
BlendMode_HardMix(base.g, blend.g),
BlendMode_HardMix(base.b, blend.b) );
}
//******************************************************************************
// Looks at the color information in each channel and subtracts either the
// blend color from the base color or the base color from the blend color,
// depending on which has the greater brightness value.
//******************************************************************************
float3 BlendMode_Difference(float3 base, float3 blend)
{
return abs(base-blend);
}
//******************************************************************************
// Creates an effect similar to but lower in contrast than the Difference mode.
//******************************************************************************
float3 BlendMode_Exclusion(float3 base, float3 blend)
{
return base + blend - 2*base*blend;
}
//******************************************************************************
// Looks at the color information in each channel and subtracts the blend color
// from the base color.
//******************************************************************************
float3 BlendMode_Subtract(float3 base, float3 blend)
{
return max(0, base - blend);
}
//******************************************************************************
// Looks at the color information in each channel and divides the blend color
// from the base color.
//******************************************************************************
float BlendMode_Divide(float base, float blend)
{
return blend > 0 ? min(1, base / blend) : 1;
}
float3 BlendMode_Divide(float3 base, float3 blend)
{
return float3( BlendMode_Divide(base.r, blend.r),
BlendMode_Divide(base.g, blend.g),
BlendMode_Divide(base.b, blend.b) );
}
@@ -0,0 +1,80 @@
/*
* 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: (MIT OR Apache-2.0) AND LicenseRef-ACES
*
*/
/*
License Terms for Academy Color Encoding System Components
Academy Color Encoding System (ACES) software and tools are provided by the
Academy under the following terms and conditions: A worldwide, royalty-free,
non-exclusive right to copy, modify, create derivatives, and use, in source and
binary forms, is hereby granted, subject to acceptance of this license.
Copyright © 2015 Academy of Motion Picture Arts and Sciences (A.M.P.A.S.).
Portions contributed by others as indicated. All rights reserved.
Performance of any of the aforementioned acts indicates acceptance to be bound
by the following terms and conditions:
* Copies of source code, in whole or in part, must retain the above copyright
notice, this list of conditions and the Disclaimer of Warranty.
* Use in binary form must retain the above copyright notice, this list of
conditions and the Disclaimer of Warranty in the documentation and/or other
materials provided with the distribution.
* Nothing in this license shall be deemed to grant any rights to trademarks,
copyrights, patents, trade secrets or any other intellectual property of
A.M.P.A.S. or any contributors, except as expressly stated herein.
* Neither the name "A.M.P.A.S." nor the name of any other contributors to this
software may be used to endorse or promote products derivative of or based on
this software without express prior written permission of A.M.P.A.S. or the
contributors, as appropriate.
This license shall be construed pursuant to the laws of the State of California,
and any disputes related thereto shall be subject to the jurisdiction of the
courts therein.
Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL A.M.P.A.S., OR ANY
CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, RESITUTIONARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
////////////////////////////////////////////////////////////////////////////////
WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY SPECIFICALLY
DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER RELATED TO PATENT OR
OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY COLOR ENCODING SYSTEM, OR
APPLICATIONS THEREOF, HELD BY PARTIES OTHER THAN A.M.P.A.S.,WHETHER DISCLOSED OR
UNDISCLOSED.
*/
#pragma once
static const float HALF_MAX = 65504.0f;
float AcesCcToLinear(float value)
{
if (value < -0.3013698630) // (9.72-15)/17.52
return (pow( 2., value*17.52-9.72) - pow( 2.,-16.))*2.0;
else if (value < (log2(HALF_MAX)+9.72)/17.52)
return pow( 2., value*17.52-9.72);
else // (value >= (log2(HALF_MAX)+9.72)/17.52)
return HALF_MAX;
}
float3 AcesCcToAcesCg(float3 color)
{
return float3(
AcesCcToLinear(color.r),
AcesCcToLinear(color.g),
AcesCcToLinear(color.b));
}
@@ -0,0 +1,79 @@
/*
* 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: (MIT OR Apache-2.0) AND LicenseRef-ACES
*
*/
/*
License Terms for Academy Color Encoding System Components
Academy Color Encoding System (ACES) software and tools are provided by the
Academy under the following terms and conditions: A worldwide, royalty-free,
non-exclusive right to copy, modify, create derivatives, and use, in source and
binary forms, is hereby granted, subject to acceptance of this license.
Copyright © 2015 Academy of Motion Picture Arts and Sciences (A.M.P.A.S.).
Portions contributed by others as indicated. All rights reserved.
Performance of any of the aforementioned acts indicates acceptance to be bound
by the following terms and conditions:
* Copies of source code, in whole or in part, must retain the above copyright
notice, this list of conditions and the Disclaimer of Warranty.
* Use in binary form must retain the above copyright notice, this list of
conditions and the Disclaimer of Warranty in the documentation and/or other
materials provided with the distribution.
* Nothing in this license shall be deemed to grant any rights to trademarks,
copyrights, patents, trade secrets or any other intellectual property of
A.M.P.A.S. or any contributors, except as expressly stated herein.
* Neither the name "A.M.P.A.S." nor the name of any other contributors to this
software may be used to endorse or promote products derivative of or based on
this software without express prior written permission of A.M.P.A.S. or the
contributors, as appropriate.
This license shall be construed pursuant to the laws of the State of California,
and any disputes related thereto shall be subject to the jurisdiction of the
courts therein.
Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL A.M.P.A.S., OR ANY
CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, RESITUTIONARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
////////////////////////////////////////////////////////////////////////////////
WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY SPECIFICALLY
DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER RELATED TO PATENT OR
OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY COLOR ENCODING SYSTEM, OR
APPLICATIONS THEREOF, HELD BY PARTIES OTHER THAN A.M.P.A.S.,WHETHER DISCLOSED OR
UNDISCLOSED.
*/
#pragma once
float LinearToAcesCc(float value)
{
if (value <= 0)
return -0.3584474886; // =(log2( pow(2.,-16.))+9.72)/17.52
else if (value < pow(2.,-15.))
return (log2( pow(2.,-16.) + value * 0.5) + 9.72) / 17.52;
else // (value >= pow(2.,-15))
return (log2(value) + 9.72) / 17.52;
}
float3 AcesCgToAcesCc(float3 color)
{
return float3(
LinearToAcesCc(color.r),
LinearToAcesCc(color.g),
LinearToAcesCc(color.b)
);
}
@@ -8,11 +8,14 @@
#pragma once
#include <Atom/RPI/Math.azsli>
#include "GeneratedTransforms/LinearSrgb_To_AcesCg.azsli"
#include "GeneratedTransforms/AcesCg_To_LinearSrgb.azsli"
#include "GeneratedTransforms/LinearSrgb_To_Srgb.azsli"
#include "GeneratedTransforms/Srgb_To_LinearSrgb.azsli"
#include "GeneratedTransforms/Aces_To_AcesCg.azsli"
#include "GeneratedTransforms/AcesCcToAcesCg.azsli"
#include "GeneratedTransforms/AcesCgToAcesCc.azsli"
#include "GeneratedTransforms/CalculateLuminance_LinearSrgb.azsli"
#include "GeneratedTransforms/CalculateLuminance_AcesCg.azsli"
@@ -20,6 +23,7 @@ enum class ColorSpaceId
{
SRGB = 0,
LinearSRGB,
ACEScc,
ACEScg,
ACES2065,
XYZ,
@@ -51,15 +55,27 @@ float3 TransformColor(in float3 color, ColorSpaceId fromColorSpace, ColorSpaceId
color = AcesCg_To_LinearSrgb(color);
color = LinearSrgb_To_Srgb(color);
}
else if (fromColorSpace == ColorSpaceId::ACEScg && toColorSpace == ColorSpaceId::LinearSRGB)
{
color = AcesCg_To_LinearSrgb(color);
}
else if (fromColorSpace == ColorSpaceId::ACEScg && toColorSpace == ColorSpaceId::ACEScc)
{
color = AcesCgToAcesCc(color);
}
else if (fromColorSpace == ColorSpaceId::ACES2065 && toColorSpace == ColorSpaceId::ACEScg)
{
color = Aces_To_AcesCg(color);
}
else if (fromColorSpace == ColorSpaceId::ACEScc && toColorSpace == ColorSpaceId::ACEScg)
{
color = AcesCcToAcesCg(color);
}
else
{
color = float3(1, 0, 1);
}
return color;
}
@@ -75,6 +91,7 @@ float CalculateLuminance(in float3 color, ColorSpaceId colorSpace)
luminance = CalculateLuminance_AcesCg(color);
break;
case ColorSpaceId::SRGB:
case ColorSpaceId::ACEScc:
case ColorSpaceId::ACES2065:
case ColorSpaceId::XYZ:
case ColorSpaceId::Invalid:
@@ -83,3 +100,29 @@ float CalculateLuminance(in float3 color, ColorSpaceId colorSpace)
return luminance;
}
float RotateHue(float hue, float low, float hi)
{
return (hue < low)
? hue + hi
: (hue > hi)
? hue - hi
: hue;
}
float3 RgbToHsv(float3 color)
{
const float4 k = float4(0.0f, -1.0f / 3.0f, 2.0f / 3.0f, -1.0f);
const float4 p = lerp(float4(color.bg, k.wz), float4(color.gb, k.xy), step(color.b, color.g));
const float4 q = lerp(float4(p.xyw, color.r), float4(color.r, p.yzx), step(p.x, color.r));
const float d = q.x - min(q.w, q.y);
const float e = EPSILON;
return float3(abs(q.z + (q.w - q.y) / (6.0f * d + e)), d / (q.x + e), q.x);
}
float3 HsvToRgb(float3 color)
{
const float4 k = float4(1.0f, 2.0f / 3.0f, 1.0f / 3.0f, 3.0f);
const float3 p = abs(frac(color.xxx + k.xyz) * 6.0f - k.www);
return color.z * lerp(k.xxx, saturate(p - k.xxx), color.y);
}
@@ -101,7 +101,6 @@ class DirectionalLightShadow
// This outputs visibility ratio (from 0.0 to 1.0) for ESM+PCF.
float GetVisibilityFromLightEsmPcf();
float SamplePcfBicubic();
float SamplePcfBicubic(float3 shadowCoord, uint indexOfCascade);
uint m_lightIndex;
@@ -278,70 +277,26 @@ float DirectionalLightShadow::GetVisibilityFromLightNoFilter()
}
float DirectionalLightShadow::GetVisibilityFromLightPcf()
{
const uint predictionCount = ViewSrg::m_directionalLightShadows[m_lightIndex].m_predictionSampleCount;
{
static const float DepthMargin = 0.01; // avoiding artifact when near depth bounds.
static const float PixelMargin = 1.5; // avoiding artifact between cascade levels.
if (predictionCount <= 1)
const uint size = ViewSrg::m_directionalLightShadows[m_lightIndex].m_shadowmapSize;
const uint cascadeCount = ViewSrg::m_directionalLightShadows[m_lightIndex].m_cascadeCount;
for (uint indexOfCascade = 0; indexOfCascade < cascadeCount; ++indexOfCascade)
{
return GetVisibilityFromLightNoFilter();
}
const float3 shadowCoord = m_shadowCoords[indexOfCascade];
if (ViewSrg::m_directionalLightShadows[m_lightIndex].m_pcfFilterMethod == PcfFilterMethod_Bicubic)
{
return SamplePcfBicubic();
}
const float3 lightDirection =
normalize(SceneSrg::m_directionalLights[m_lightIndex].m_direction);
const float4 jitterUnitVectorDepthDiffBase =
Shadow::GetJitterUnitVectorDepthDiffBase(m_normalVector, lightDirection);
const float3 jitterUnit = jitterUnitVectorDepthDiffBase.xyz;
const float jitterDepthDiffBase = jitterUnitVectorDepthDiffBase.w;
uint shadowedCount = 0;
uint jitterIndex = 0;
// Predicting
for (; jitterIndex < predictionCount; ++jitterIndex)
{
if (IsShadowedWithJitter(
jitterUnit,
jitterDepthDiffBase,
jitterIndex))
if (shadowCoord.x >= 0. && shadowCoord.x * size < size - PixelMargin &&
shadowCoord.y >= 0. && shadowCoord.y * size < size - PixelMargin &&
shadowCoord.z < 1. - DepthMargin)
{
++shadowedCount;
m_debugInfo.m_cascadeIndex = indexOfCascade;
return SamplePcfBicubic(shadowCoord, indexOfCascade);
}
}
if (shadowedCount == 0)
{
return 1.;
}
else if (shadowedCount == predictionCount)
{
return 0.;
}
// Filtering
// When the prediction detects the point on the boundary of shadow,
// i.e., both of a lit point and a a shadowed one exists in the jittering area,
// we calculate the more precious lit ratio in the area.
const uint filteringCount = max(
predictionCount,
ViewSrg::m_directionalLightShadows[m_lightIndex].m_filteringSampleCount);
for (; jitterIndex < filteringCount; ++jitterIndex)
{
if (IsShadowedWithJitter(
jitterUnit,
jitterDepthDiffBase,
jitterIndex))
{
++shadowedCount;
}
}
return (filteringCount - shadowedCount) * 1. / filteringCount;
m_debugInfo.m_cascadeIndex = cascadeCount;
return 1.;
}
float DirectionalLightShadow::GetVisibilityFromLightEsm()
@@ -415,29 +370,6 @@ float DirectionalLightShadow::GetVisibilityFromLightEsmPcf()
return 1.;
}
float DirectionalLightShadow::SamplePcfBicubic()
{
static const float DepthMargin = 0.01; // avoiding artifact when near depth bounds.
static const float PixelMargin = 1.5; // avoiding artifact between cascade levels.
const uint size = ViewSrg::m_directionalLightShadows[m_lightIndex].m_shadowmapSize;
const uint cascadeCount = ViewSrg::m_directionalLightShadows[m_lightIndex].m_cascadeCount;
for (uint indexOfCascade = 0; indexOfCascade < cascadeCount; ++indexOfCascade)
{
const float3 shadowCoord = m_shadowCoords[indexOfCascade];
if (shadowCoord.x >= 0. && shadowCoord.x * size < size - PixelMargin &&
shadowCoord.y >= 0. && shadowCoord.y * size < size - PixelMargin &&
shadowCoord.z < 1. - DepthMargin)
{
m_debugInfo.m_cascadeIndex = indexOfCascade;
return SamplePcfBicubic(shadowCoord, indexOfCascade);
}
}
m_debugInfo.m_cascadeIndex = cascadeCount;
return 1.;
}
float DirectionalLightShadow::SamplePcfBicubic(float3 shadowCoord, uint indexOfCascade)
{
const uint filteringSampleCount = ViewSrg::m_directionalLightShadows[m_lightIndex].m_filteringSampleCount;
@@ -44,8 +44,6 @@ class ProjectedShadow
float GetVisibilityEsmPcf();
float GetThickness();
float SamplePcfBicubic();
bool IsShadowed(float3 shadowPosition);
bool IsShadowedWithJitter(
float3 jitterUnitX,
@@ -87,8 +85,7 @@ float ProjectedShadow::GetVisibility(
shadow.SetShadowPosition();
float visibility = 1.;
// Filter method is stored in top 16 bits.
uint filterMethod = ViewSrg::m_projectedShadows[shadow.m_shadowIndex].m_shadowFilterMethod & 0x0000FFFF;
const uint filterMethod = ViewSrg::m_projectedShadows[shadow.m_shadowIndex].m_shadowFilterMethod;
switch (filterMethod)
{
case ViewSrg::ShadowFilterMethodNone:
@@ -145,72 +142,29 @@ float ProjectedShadow::GetVisibilityNoFilter()
float ProjectedShadow::GetVisibilityPcf()
{
// PCF filter method is stored in bottom 16 bits.
const uint pcfFilterMethod = ViewSrg::m_projectedShadows[m_shadowIndex].m_shadowFilterMethod >> 16;
if (pcfFilterMethod == PcfFilterMethod_Bicubic)
const uint filteringSampleCount = ViewSrg::m_projectedShadows[m_shadowIndex].m_filteringSampleCount;
const float3 atlasPosition = GetAtlasPosition(m_shadowPosition.xy);
SampleShadowMapBicubicParameters param;
param.shadowMap = PassSrg::m_projectedShadowmaps;
param.shadowPos = float3(atlasPosition.xy * ViewSrg::m_invShadowmapAtlasSize, atlasPosition.z);
param.shadowMapSize = ViewSrg::m_shadowmapAtlasSize;
param.invShadowMapSize = ViewSrg::m_invShadowmapAtlasSize;
param.comparisonValue = m_shadowPosition.z - m_bias;
param.samplerState = SceneSrg::m_hwPcfSampler;
if (filteringSampleCount <= 4)
{
return SamplePcfBicubic();
return SampleShadowMapBicubic_4Tap(param);
}
const uint predictionCount = ViewSrg::m_projectedShadows[m_shadowIndex].m_predictionSampleCount;
if (predictionCount <= 1)
else if (filteringSampleCount <= 9)
{
return GetVisibilityNoFilter();
return SampleShadowMapBicubic_9Tap(param);
}
const float4 jitterUnitVectorDepthDiffBase =
Shadow::GetJitterUnitVectorDepthDiffBase(m_normalVector, m_lightDirection);
const float3 jitterUnitY = jitterUnitVectorDepthDiffBase.xyz;
const float3 jitterUnitX = cross(jitterUnitY, m_lightDirection);
const float jitterDepthDiffBase = jitterUnitVectorDepthDiffBase.w;
uint shadowedCount = 0;
uint jitterIndex = 0;
// Predicting
for (; jitterIndex < predictionCount; ++jitterIndex)
else
{
if (IsShadowedWithJitter(
jitterUnitX,
jitterUnitY,
jitterDepthDiffBase,
jitterIndex))
{
++shadowedCount;
}
return SampleShadowMapBicubic_16Tap(param);
}
if (shadowedCount == 0)
{
return 1.;
}
else if (shadowedCount == predictionCount)
{
return 0.;
}
// Filtering
// When the prediction detects the point on the boundary of shadow,
// i.e., both of a lit point and a a shadowed one exists in the jittering area,
// we calculate the more precious lit ratio in the area.
const uint filteringCount = max(
predictionCount,
ViewSrg::m_projectedShadows[m_shadowIndex].m_filteringSampleCount);
for (; jitterIndex < filteringCount; ++jitterIndex)
{
if (IsShadowedWithJitter(
jitterUnitX,
jitterUnitY,
jitterDepthDiffBase,
jitterIndex))
{
++shadowedCount;
}
}
return (filteringCount - shadowedCount) * 1. / filteringCount;
}
float ProjectedShadow::GetVisibilityEsm()
@@ -337,33 +291,6 @@ float ProjectedShadow::GetThickness()
return 0.;
}
float ProjectedShadow::SamplePcfBicubic()
{
const uint filteringSampleCount = ViewSrg::m_projectedShadows[m_shadowIndex].m_filteringSampleCount;
const float3 atlasPosition = GetAtlasPosition(m_shadowPosition.xy);
SampleShadowMapBicubicParameters param;
param.shadowMap = PassSrg::m_projectedShadowmaps;
param.shadowPos = float3(atlasPosition.xy * ViewSrg::m_invShadowmapAtlasSize, atlasPosition.z);
param.shadowMapSize = ViewSrg::m_shadowmapAtlasSize;
param.invShadowMapSize = ViewSrg::m_invShadowmapAtlasSize;
param.comparisonValue = m_shadowPosition.z - m_bias;
param.samplerState = SceneSrg::m_hwPcfSampler;
if (filteringSampleCount <= 4)
{
return SampleShadowMapBicubic_4Tap(param);
}
else if (filteringSampleCount <= 9)
{
return SampleShadowMapBicubic_9Tap(param);
}
else
{
return SampleShadowMapBicubic_16Tap(param);
}
}
bool ProjectedShadow::IsShadowed(float3 shadowPosition)
{
static const float PixelMargin = 1.5; // avoiding artifact between cascade levels.
@@ -35,4 +35,4 @@ float ApplyReceiverPlaneDepthBias(const float2 receiverPlaneDepthBias, const flo
// Clamping this will remove this effect
fragmentDepthBias = min(fragmentDepthBias, 0.0);
return fragmentDepthBias;
}
}
@@ -82,7 +82,7 @@ partial ShaderResourceGroup ViewSrg
{
float4x4 m_depthBiasMatrix;
uint m_shadowmapArraySlice; // array slice who has shadowmap in the atlas.
uint m_shadowFilterMethod; // Includes overall filter method in top 16 bits and pcf method in bottom 16 bits.
uint m_shadowFilterMethod;
float m_boundaryScale;
uint m_predictionSampleCount;
uint m_filteringSampleCount;
@@ -117,8 +117,6 @@ partial ShaderResourceGroup ViewSrg
uint m_debugFlags;
uint m_shadowFilterMethod;
float m_far_minus_near;
uint m_pcfFilterMethod; // Matches with PcfFilterMethod in ShadowConstants.h
uint m_padding[3];
};
enum ShadowFilterMethod
@@ -11,6 +11,6 @@
// Please review README.md to understand how this file is used in SceneSrg.azsrg generation
#ifdef AZ_COLLECTING_PARTIAL_SRGS
#include <Atom/Feature/Common/Assets/ShaderResourceGroups/SceneTimeSrg.azsli>
#include <Atom/RPI/ShaderResourceGroups/DefaultSceneSrg.azsli>
#include <Atom/Feature/Common/Assets/ShaderResourceGroups/SceneSrg.azsli>
#endif
@@ -1,60 +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
*
*/
// [GFX TODO][ATOM-3365] optimization using intermediary results in groupshared memory.
#include <Atom/Features/Math/Filter.azsli>
#include <Atom/Features/Math/FilterPassSrg.azsli>
#include <Atom/Features/Shadow/ShadowmapAtlasLib.azsli>
[numthreads(16,16,1)]
void MainCS(uint3 dispatchId: SV_DispatchThreadID)
{
const float3 inputSize = GetImageSize(FilterPassSrg::m_inputImage);
const float3 outputSize = GetImageSize(FilterPassSrg::m_outputImage);
const uint shadowmapIndex = GetShadowmapIndex(
FilterPassSrg::m_shadowmapIndexTable,
dispatchId,
inputSize.x);
// Early return if thread is outside of shadowmaps.
if (shadowmapIndex == ~0)
{
return;
}
const FilterParameter filterParameter = FilterPassSrg::m_filterParameters[shadowmapIndex];
const uint shadowmapSize = filterParameter.m_shadowmapSize;
// Early return if filter is disabled.
if (!filterParameter.m_isEnabled || shadowmapSize <= 1)
{
return; // early return if filter parameter is empty.
}
const uint sourceMin = filterParameter.m_shadowmapOriginInSlice.x;
const uint sourceMax = sourceMin + shadowmapSize - 1;
uint filterTableSize = 0;
FilterPassSrg::m_filterTable.GetDimensions(filterTableSize);
if (filterTableSize == 0 || filterParameter.m_parameterCount == 0)
{
return; // If filter parameter is empty, early return.
}
// [GFX TODO][ATOM-5676] pass proper source min/max for each shadowmap
const float result = FilteredFloat(
dispatchId,
FilterPassSrg::m_inputImage,
uint2(1, 0), // horizontal
sourceMin,
sourceMax,
FilterPassSrg::m_filterTable,
filterParameter.m_parameterOffset,
filterParameter.m_parameterCount);
FilterPassSrg::m_outputImage[dispatchId].r = result;
}
@@ -1,16 +0,0 @@
{
"Source" : "GaussianFilterFloatHorizontal",
"DrawList" : "shadow",
"ProgramSettings":
{
"EntryPoints":
[
{
"name": "MainCS",
"type": "Compute"
}
]
}
}
@@ -1,60 +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
*
*/
// [GFX TODO][ATOM-3365] optimization using intermediary results in groupshared memory.
#include <Atom/Features/Math/Filter.azsli>
#include <Atom/Features/Math/FilterPassSrg.azsli>
#include <Atom/Features/Shadow/ShadowmapAtlasLib.azsli>
[numthreads(16,16,1)]
void MainCS(uint3 dispatchId: SV_DispatchThreadID)
{
const float3 inputSize = GetImageSize(FilterPassSrg::m_inputImage);
const float3 outputSize = GetImageSize(FilterPassSrg::m_outputImage);
const uint shadowmapIndex = GetShadowmapIndex(
FilterPassSrg::m_shadowmapIndexTable,
dispatchId,
inputSize.x);
// Early return if thread is outside of shadowmaps.
if (shadowmapIndex == ~0)
{
return;
}
const FilterParameter filterParameter = FilterPassSrg::m_filterParameters[shadowmapIndex];
const uint shadowmapSize = filterParameter.m_shadowmapSize;
// Early return if filter is disabled.
if (!filterParameter.m_isEnabled || shadowmapSize <= 1)
{
return; // early return if filter parameter is empty.
}
const uint sourceMin = filterParameter.m_shadowmapOriginInSlice.y;
const uint sourceMax = sourceMin + shadowmapSize - 1;
uint filterTableSize = 0;
FilterPassSrg::m_filterTable.GetDimensions(filterTableSize);
if (filterTableSize == 0 || filterParameter.m_parameterCount == 0)
{
return; // If filter parameter is empty, early return.
}
// [GFX TODO][ATOM-5676] pass proper source min/max for each shadowmap
const float result = FilteredFloat(
dispatchId,
FilterPassSrg::m_inputImage,
uint2(0, 1), // vertical
sourceMin,
sourceMax,
FilterPassSrg::m_filterTable,
filterParameter.m_parameterOffset,
filterParameter.m_parameterCount);
FilterPassSrg::m_outputImage[dispatchId].r = result;
}
@@ -78,10 +78,12 @@ void MainCS(uint3 dispatch_id : SV_DispatchThreadID)
const float speed = exposureDifference > 0.0 ? ViewSrg::m_exposureControl.m_speedUp : ViewSrg::m_exposureControl.m_speedDown;
// Update the adjustment for this frame based on the frame deltaTime and speed
float exposureAdjustment = exposureDifference * SceneSrg::m_deltaTime * speed;
float deltaTime = clamp(SceneSrg::m_time - PassSrg::m_eyeAdaptationData[0].m_setValueTime, 0.0f, 1.0f);
float exposureAdjustment = exposureDifference * deltaTime * speed;
float newExposureLog2 = previousFrameExposureLog2 + exposureAdjustment;
// Store the linear exposure so it can be used by the look modification transform later.
// newExposureLog2 is negated because m_exposureValue is used to correct for a given exposure.
PassSrg::m_eyeAdaptationData[0].m_exposureValue = pow(2.0f, -newExposureLog2);
PassSrg::m_eyeAdaptationData[0].m_setValueTime = SceneSrg::m_time;
}
@@ -8,5 +8,6 @@
struct EyeAdaptation
{
float m_exposureValue; // current frame's exposure value in stops (logarithmic space)
float m_exposureValue; // current frame's exposure value in stops (logarithmic space)
float m_setValueTime; // the time when the m_exposureValue was set
};
@@ -55,7 +55,7 @@ int GetLdsIndex(int2 ldsPosition)
// --- Common file start ---
// #include <Atom/Features/PostProcessing/FastDepthAwareBlurCommon.azsli>
// include <Atom/Features/PostProcessing/FastDepthAwareBlurCommon.azsli> ('#' symbol before 'include' was removed on purpose to avoid parsing this azsli file during ShaderAssetBuilder::CreateJobs)
// This include fails with the asset processor when generating the .shader for this file
// Everything below this is copy pasted from FastDepthAwareBlurCommon.azsli up until the
// "Common file end" marker below
@@ -55,7 +55,7 @@ int GetLdsIndex(int2 ldsPosition)
// --- Common file start ---
// #include <Atom/Features/PostProcessing/FastDepthAwareBlurCommon.azsli>
// include <Atom/Features/PostProcessing/FastDepthAwareBlurCommon.azsli> ('#' symbol before 'include' was removed on purpose to avoid parsing this azsli file during ShaderAssetBuilder::CreateJobs)
// This include fails with the asset processor when generating the .shader for this file
// Everything below this is copy pasted from FastDepthAwareBlurCommon.azsli up until the
// "Common file end" marker below
@@ -0,0 +1,206 @@
/*
* 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
*
*/
#include <Atom/RPI/Math.azsli>
#include <Atom/Features/SrgSemantics.azsli>
#include <Atom/Features/PostProcessing/FullscreenPixelInfo.azsli>
#include <Atom/Features/PostProcessing/FullscreenVertex.azsli>
#include <Atom/Features/ColorManagement/TransformColor.azsli>
#include <Atom/Features/PostProcessing/AcesColorSpaceConversion.azsli>
#include <3rdParty/Features/PostProcessing/PSstyleColorBlends_Separable.azsli>
#include <3rdParty/Features/PostProcessing/PSstyleColorBlends_NonSeparable.azsli>
#include <3rdParty/Features/PostProcessing/KelvinToRgb.azsli>
static const float FloatEpsilon = 1.192092896e-07; // 1.0 + FloatEpsilon != 1.0, smallest positive float
static const float FloatMin = FLOAT_32_MIN; // Min float number that is positive
static const float FloatMax = FLOAT_32_MAX; // Max float number representable
static const float AcesCcMidGrey = 0.4135884;
ShaderResourceGroup PassSrg : SRG_PerPass_WithFallback
{
// get the framebuffer
Texture2D<float4> m_framebuffer;
// framebuffer sampler
Sampler LinearSampler
{
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Clamp;
AddressV = Clamp;
AddressW = Clamp;
};
float m_colorGradingExposure;
float m_colorGradingContrast;
float m_colorGradingHueShift;
float m_colorGradingPreSaturation;
float m_colorFilterIntensity;
float m_colorFilterMultiply;
float m_whiteBalanceKelvin;
float m_whiteBalanceTint;
float m_splitToneBalance;
float m_splitToneMix;
float m_colorGradingPostSaturation;
float m_smhShadowsStart;
float m_smhShadowsEnd;
float m_smhHighlightsStart;
float m_smhHighlightsEnd;
float m_smhMix;
float3 m_channelMixingRed;
float3 m_channelMixingGreen;
float3 m_channelMixingBlue;
float4 m_colorFilterSwatch;
float4 m_splitToneShadowsColor;
float4 m_splitToneHighlightsColor;
float4 m_smhShadowsColor;
float4 m_smhMidtonesColor;
float4 m_smhHighlightsColor;
// my color grading output
float4 m_color;
}
float SaturateWithEpsilon(float value)
{
return clamp(value, FloatEpsilon, 1.0f);
}
// Below are the color grading functions. These expect the frame color to be in ACEScg space.
// Note that some functions may have some quirks in their implementation and is subject to change.
float3 ColorGradePostExposure (float3 frameColor, float exposure)
{
frameColor *= pow(2.0f, exposure);
return frameColor;
}
// The contrast equation is performed in ACEScc (logarithmic) color space.
float3 ColorGradingContrast (float3 frameColor, float midgrey, float amount)
{
const float contrastAdjustment = amount * 0.01f + 1.0f;
frameColor = TransformColor(frameColor.rgb, ColorSpaceId::ACEScg, ColorSpaceId::ACEScc);
frameColor = (frameColor - midgrey) * contrastAdjustment + midgrey;
return frameColor = TransformColor(frameColor.rgb, ColorSpaceId::ACEScc, ColorSpaceId::ACEScg);
}
// The swatchColor param expects a linear RGB value.
float3 ColorGradeColorFilter (float3 frameColor, float3 swatchColor, float alpha)
{
swatchColor = TransformColor(swatchColor, ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
swatchColor *= pow(2.0f, PassSrg::m_colorFilterIntensity);
const float3 frameAdjust = frameColor * swatchColor;
return frameColor = lerp(frameColor, frameAdjust, alpha);
}
float3 ColorGradeHueShift (float3 frameColor, float amount)
{
float3 frameHsv = RgbToHsv(frameColor);
const float hue = frameHsv.x + amount;
frameHsv.x = RotateHue(hue, 0.0, 1.0);
return HsvToRgb(frameHsv);
}
float3 ColorGradeSaturation (float3 frameColor, float control)
{
const float vLuminance = CalculateLuminance(frameColor, ColorSpaceId::ACEScg);
return (frameColor - vLuminance) * control + vLuminance;
}
float3 ColorGradeKelvinColorTemp(float3 frameColor, float kelvin)
{
const float3 kColor = TransformColor(KelvinToRgb(kelvin), ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
const float luminance = CalculateLuminance(frameColor, ColorSpaceId::ACEScg);
const float3 resHsl = RgbToHsl(frameColor.rgb * kColor.rgb); // Apply Kelvin color and convert to HSL
return HslToRgb(float3(resHsl.xy, luminance)); // Preserve luminance
}
// pow(f, e) won't work if f is negative, or may cause inf/NAN.
float3 NoNanPow(float3 base, float3 power)
{
return pow(max(abs(base), float3(FloatEpsilon, FloatEpsilon, FloatEpsilon)), power);
}
float3 ColorGradeSplitTone (float3 frameColor, float balance, float mix)
{
float3 frameSplitTone = NoNanPow(frameColor, 1.0 / 2.2);
const float t = SaturateWithEpsilon(CalculateLuminance(SaturateWithEpsilon(frameSplitTone), ColorSpaceId::ACEScg) + balance);
const float3 shadows = lerp(0.5, PassSrg::m_splitToneShadowsColor.rgb, 1.0 - t);
const float3 highlights = lerp(0.5, PassSrg::m_splitToneHighlightsColor.rgb, t);
frameSplitTone = BlendMode_SoftLight(frameSplitTone, shadows);
frameSplitTone = BlendMode_SoftLight(frameSplitTone, highlights);
frameSplitTone = NoNanPow(frameSplitTone, 2.2);
return lerp(frameColor.rgb, frameSplitTone.rgb, mix);
}
float3 ColorGradeChannelMixer (float3 frameColor)
{
return mul(float3x3(PassSrg::m_channelMixingRed.rgb,
PassSrg::m_channelMixingGreen.rgb,
PassSrg::m_channelMixingBlue.rgb),
frameColor);
}
float3 ColorGradeShadowsMidtonesHighlights (float3 frameColor, float shadowsStart, float shadowsEnd,
float highlightsStart, float highlightsEnd, float mix,
float4 shadowsColor, float4 midtonesColor, float4 highlightsColor)
{
const float3 shadowsColorACEScg = TransformColor(shadowsColor.rgb, ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
const float3 midtonesColorACEScg = TransformColor(midtonesColor.rgb, ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
const float3 highlightsColorACEScg = TransformColor(highlightsColor.rgb, ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
const float cLuminance = CalculateLuminance(frameColor, ColorSpaceId::ACEScg);
const float shadowsWeight = 1.0 - smoothstep(shadowsStart, shadowsEnd, cLuminance);
const float highlightsWeight = smoothstep(highlightsStart, highlightsEnd, cLuminance);
const float midtonesWeight = 1.0 - shadowsWeight - highlightsWeight;
const float3 frameSmh = frameColor * shadowsColorACEScg * shadowsWeight +
frameColor * midtonesColorACEScg * midtonesWeight +
frameColor * highlightsColorACEScg * highlightsWeight;
return lerp(frameColor.rgb, frameSmh.rgb, mix);
}
float3 ColorGrade (float3 frameColor)
{
frameColor = ColorGradePostExposure(frameColor, PassSrg::m_colorGradingExposure);
frameColor = ColorGradeKelvinColorTemp(frameColor, PassSrg::m_whiteBalanceKelvin);
frameColor = ColorGradingContrast(frameColor, AcesCcMidGrey, PassSrg::m_colorGradingContrast);
frameColor = ColorGradeColorFilter(frameColor, PassSrg::m_colorFilterSwatch.rgb,
PassSrg::m_colorFilterMultiply);
frameColor = max(frameColor, 0.0);
frameColor = ColorGradeSaturation(frameColor, PassSrg::m_colorGradingPreSaturation);
frameColor = ColorGradeSplitTone(frameColor, PassSrg::m_splitToneBalance, PassSrg::m_splitToneMix);
frameColor = ColorGradeChannelMixer(frameColor);
frameColor = max(frameColor, 0.0);
frameColor = ColorGradeShadowsMidtonesHighlights(frameColor, PassSrg::m_smhShadowsStart, PassSrg::m_smhShadowsEnd,
PassSrg::m_smhHighlightsStart, PassSrg::m_smhHighlightsEnd, PassSrg::m_smhMix,
PassSrg::m_smhShadowsColor, PassSrg::m_smhMidtonesColor, PassSrg::m_smhHighlightsColor);
frameColor = ColorGradeHueShift(frameColor, PassSrg::m_colorGradingHueShift);
frameColor = ColorGradeSaturation(frameColor, PassSrg::m_colorGradingPostSaturation);
return frameColor.rgb;
}
PSOutput MainPS(VSOutput IN)
{
PSOutput OUT;
// Fetch the pixel color from the input texture
float3 frameColor = PassSrg::m_framebuffer.Sample(PassSrg::LinearSampler, IN.m_texCoord).rgb;
OUT.m_color.rgb = ColorGrade(frameColor);
OUT.m_color.w = 1;
return OUT;
}
@@ -0,0 +1,22 @@
{
"Source" : "HDRColorGrading",
"DepthStencilState" : {
"Depth" : { "Enable" : false }
},
"ProgramSettings":
{
"EntryPoints":
[
{
"name": "MainVS",
"type": "Vertex"
},
{
"name": "MainPS",
"type": "Fragment"
}
]
}
}
@@ -157,7 +157,7 @@
* #define SMAA_RT_METRICS float4(1.0 / 1280.0, 1.0 / 720.0, 1280.0, 720.0)
* #define SMAA_HLSL_4
* #define SMAA_PRESET_HIGH
* #include "SMAA.h"
* include "SMAA.h" ('#' symbol before 'include' was removed on purpose to avoid parsing this azsli file during ShaderAssetBuilder::CreateJobs)
*
* Note that SMAA_RT_METRICS doesn't need to be a macro, it can be a
* uniform variable. The code is designed to minimize the impact of not
@@ -0,0 +1,132 @@
/*
* 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
*
*/
// [GFX TODO][ATOM-3365] optimization using intermediary results in groupshared memory.
// This shader blurs the ESM results using a multi-pass kawase filter.
// It should generally be faster than separable gaussian blur
// https://software.intel.com/content/www/us/en/develop/blogs/an-investigation-of-fast-real-time-gpu-based-image-blur-algorithms.html
#include <Atom/Features/Math/Filter.azsli>
#include <Atom/Features/Shadow/ShadowmapAtlasLib.azsli>
#include <Atom/Features/Shadow/Shadow.azsli>
#include <Atom/Features/SrgSemantics.azsli>
ShaderResourceGroup FilterPassSrg : SRG_PerPass
{
// This shader filters multiple images with distinct filter parameters.
// So, the input and output are arrays of texture2Ds.
Texture2DArray<float> m_inputImage;
RWTexture2DArray<float> m_outputImage;
// This can convert a coordinate in an atlas to
// the shadowmap index.
Buffer<uint2> m_shadowmapIndexTable;
// This contains parameters related to filtering.
StructuredBuffer<FilterParameter> m_filterParameters;
// x and y contain the inverse of the texture map resolution, z contains the kawase iteration
// i.e. a two pass kawase blur passes in 0 for the 1st pass and 1 for the second pass
float4 m_rcpResolutionAndIteration;
Sampler LinearSampler
{
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Clamp;
AddressV = Clamp;
AddressW = Clamp;
};
}
void CalculateBlurBoundaries(const uint shadowmapIndex, out float2 sourceMinTex, out float2 sourceMaxTex)
{
const float2 rcpPixelSize = FilterPassSrg::m_rcpResolutionAndIteration.xy;
const FilterParameter filterParameter = FilterPassSrg::m_filterParameters[shadowmapIndex];
const uint shadowmapSize = filterParameter.m_shadowmapSize;
// location of the shadow bounds in texels
const uint2 sourceMinPixel = filterParameter.m_shadowmapOriginInSlice.xy;
const uint2 sourceMaxPixel = sourceMinPixel + shadowmapSize - 1;
// location of the shadow bounds in uv space
sourceMinTex = (sourceMinPixel + 0.5f) * rcpPixelSize;
sourceMaxTex = (sourceMaxPixel + 0.5f) * rcpPixelSize;
}
float AccumulateShadowSamples(Texture2DArray<float> tex, float3 texCoord, SamplerState s)
{
float4 values = tex.GatherRed(s, texCoord);
float result = values.x + values.y + values.z + values.w;
return result;
}
[numthreads(16,16,1)]
void MainCS(uint3 dispatchId: SV_DispatchThreadID)
{
const float inputSize = GetImageSize(FilterPassSrg::m_inputImage).x;
const uint shadowmapIndex = GetShadowmapIndex(
FilterPassSrg::m_shadowmapIndexTable,
dispatchId,
inputSize);
// Early return if thread is outside of shadowmaps.
if (shadowmapIndex == ~0)
{
return;
}
const FilterParameter filterParameter = FilterPassSrg::m_filterParameters[shadowmapIndex];
const uint shadowmapSize = filterParameter.m_shadowmapSize;
// Early return if filter is disabled.
if (!filterParameter.m_isEnabled || shadowmapSize <= 1)
{
return; // early return if filter parameter is empty.
}
const float2 rcpPixelSize = FilterPassSrg::m_rcpResolutionAndIteration.xy;
const float blurIteration = FilterPassSrg::m_rcpResolutionAndIteration.z;
float2 sourceMinTex, sourceMaxTex;
CalculateBlurBoundaries(shadowmapIndex, sourceMinTex, sourceMaxTex);
const float2 halfRcpPixelSize = rcpPixelSize / 2.0f;
const float2 dUV = rcpPixelSize.xy * blurIteration + halfRcpPixelSize.xy;
const float2 texCoord = (dispatchId.xy + 0.5f) * rcpPixelSize;
const float3 texCoordSamples[4] = {
float3(texCoord.x - dUV.x, texCoord.y - dUV.y, dispatchId.z),
float3(texCoord.x - dUV.x, texCoord.y + dUV.y, dispatchId.z),
float3(texCoord.x + dUV.x, texCoord.y - dUV.y, dispatchId.z),
float3(texCoord.x + dUV.x, texCoord.y + dUV.y, dispatchId.z),
};
float accumulatedBlur = 0;
float numSamplesAccumulated = 0;
for(int i = 0 ; i < 4; ++i)
{
if (texCoordSamples[i].x >= sourceMinTex.x &&
texCoordSamples[i].y >= sourceMinTex.y &&
texCoordSamples[i].x < sourceMaxTex.x &&
texCoordSamples[i].y < sourceMaxTex.y)
{
// we should be tapping the location directly in between 4 adjacent texels
accumulatedBlur += AccumulateShadowSamples(FilterPassSrg::m_inputImage, texCoordSamples[i], FilterPassSrg::LinearSampler);
numSamplesAccumulated += 4;
}
}
if (numSamplesAccumulated > 0)
{
float result = accumulatedBlur / numSamplesAccumulated;
FilterPassSrg::m_outputImage[dispatchId].r = result;
}
}
@@ -1,5 +1,5 @@
{
"Source" : "GaussianFilterFloatVertical",
"Source" : "KawaseShadowBlur",
"DrawList" : "shadow",
@@ -86,6 +86,7 @@ set(FILES
Passes/CascadedShadowmaps.pass
Passes/CheckerboardResolveColor.pass
Passes/CheckerboardResolveDepth.pass
Passes/HDRColorGrading.pass
Passes/ContrastAdaptiveSharpening.pass
Passes/ConvertToAcescg.pass
Passes/DebugOverlayParent.pass
@@ -137,8 +138,6 @@ set(FILES
Passes/FastDepthAwareBlur.pass
Passes/FastDepthAwareBlurHor.pass
Passes/FastDepthAwareBlurVer.pass
Passes/FilterDepthHorizontal.pass
Passes/FilterDepthVertical.pass
Passes/Forward.pass
Passes/ForwardCheckerboard.pass
Passes/ForwardMSAA.pass
@@ -146,6 +145,7 @@ set(FILES
Passes/FullscreenCopy.pass
Passes/FullscreenOutputOnly.pass
Passes/ImGui.pass
Passes/KawaseShadowBlur.pass
Passes/LightAdaptationParent.pass
Passes/LightCulling.pass
Passes/LightCullingHeatmap.pass
@@ -222,6 +222,8 @@ set(FILES
ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/LinearSrgb_To_AcesCg.azsli
ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/LinearSrgb_To_Srgb.azsli
ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/Srgb_To_LinearSrgb.azsli
ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCcToAcesCg.azsli
ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCgToAcesCc.azsli
ShaderLib/Atom/Features/CoreLights/PhotometricValue.azsli
ShaderLib/Atom/Features/Decals/DecalTextureUtil.azsli
ShaderLib/Atom/Features/LightCulling/LightCullingShared.azsli
@@ -287,9 +289,11 @@ set(FILES
ShaderLib/Atom/Features/Shadow/Shadow.azsli
ShaderLib/Atom/Features/Shadow/ShadowmapAtlasLib.azsli
ShaderLib/Atom/Features/Vertex/VertexHelper.azsli
ShaderLib/3rdParty/Features/PostProcessing/KelvinToRgb.azsli
ShaderLib/3rdParty/Features/PostProcessing/PSstyleColorBlends_NonSeparable.azsli
ShaderLib/3rdParty/Features/PostProcessing/PSstyleColorBlends_Separable.azsli
ShaderResourceGroups/SceneSrg.azsli
ShaderResourceGroups/SceneSrgAll.azsli
ShaderResourceGroups/SceneTimeSrg.azsli
ShaderResourceGroups/ViewSrg.azsli
ShaderResourceGroups/ViewSrgAll.azsli
ShaderResourceGroups/CoreLights/SceneSrg.azsli
@@ -332,10 +336,6 @@ set(FILES
Shaders/LightCulling/LightCullingTilePrepare.shader
Shaders/LuxCore/RenderTexture.azsl
Shaders/LuxCore/RenderTexture.shader
Shaders/Math/GaussianFilterFloatHorizontal.azsl
Shaders/Math/GaussianFilterFloatHorizontal.shader
Shaders/Math/GaussianFilterFloatVertical.azsl
Shaders/Math/GaussianFilterFloatVertical.shader
Shaders/MorphTargets/MorphTargetCS.azsl
Shaders/MorphTargets/MorphTargetCS.shader
Shaders/MorphTargets/MorphTargetSRG.azsli
@@ -398,6 +398,8 @@ set(FILES
Shaders/PostProcessing/FastDepthAwareBlurVer.shader
Shaders/PostProcessing/FullscreenCopy.azsl
Shaders/PostProcessing/FullscreenCopy.shader
Shaders/PostProcessing/HDRColorGrading.azsl
Shaders/PostProcessing/HDRColorGrading.shader
Shaders/PostProcessing/LookModificationTransform.azsl
Shaders/PostProcessing/LookModificationTransform.shader
Shaders/PostProcessing/LuminanceHeatmap.azsl
@@ -458,6 +460,8 @@ set(FILES
Shaders/ScreenSpace/DeferredFog.shader
Shaders/Shadow/DepthExponentiation.azsl
Shaders/Shadow/DepthExponentiation.shader
Shaders/Shadow/KawaseShadowBlur.azsl
Shaders/Shadow/KawaseShadowBlur.shader
Shaders/Shadow/Shadowmap.azsl
Shaders/Shadow/Shadowmap.shader
Shaders/SkinnedMesh/LinearSkinningCS.azsl
@@ -149,12 +149,6 @@ namespace AZ
//! @param method filter method.
virtual void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) = 0;
//! This sets sample count to predict boundary of shadow.
//! @param handle the light handle.
//! @param count Sample Count for prediction of whether the pixel is on the boundary (up to 16)
//! The value should be less than or equal to m_filteringSampleCount.
virtual void SetPredictionSampleCount(LightHandle handle, uint16_t count) = 0;
//! This sets sample count for filtering of shadow boundary.
//! @param handle the light handle.
//! @param count Sample Count for filtering (up to 64)
@@ -166,9 +160,6 @@ namespace AZ
//! If width == 0, softening edge is disabled. Units are in meters.
virtual void SetShadowBoundaryWidth(LightHandle handle, float boundaryWidth) = 0;
//! Sets the shadowmap Pcf method.
virtual void SetPcfMethod(LightHandle handle, PcfMethod method) = 0;
//! Sets whether the directional shadowmap should use receiver plane bias.
//! This attempts to reduce shadow acne when using large pcf filters.
virtual void SetShadowReceiverPlaneBiasEnabled(LightHandle handle, bool enable) = 0;
@@ -92,12 +92,8 @@ namespace AZ
virtual void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) = 0;
//! Specifies the width of boundary between shadowed area and lit area in radians. The degree ofshadowed gradually changes on the boundary. 0 disables softening.
virtual void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) = 0;
//! Sets sample count to predict boundary of shadow (up to 16). It will be clamped to be less than or equal to the filtering sample count.
virtual void SetPredictionSampleCount(LightHandle handle, uint16_t count) = 0;
//! Sets sample count for filtering of shadow boundary (up to 64)
virtual void SetFilteringSampleCount(LightHandle handle, uint16_t count) = 0;
//! Sets the shadowmap Pcf (percentage closer filtering) method.
virtual void SetPcfMethod(LightHandle handle, PcfMethod method) = 0;
//! Sets the Esm exponent to use. Higher values produce a steeper falloff in the border areas between light and shadow.
virtual void SetEsmExponent(LightHandle handle, float exponent) = 0;
@@ -73,13 +73,8 @@ namespace AZ
//! Specifies the width of boundary between shadowed area and lit area in radians. The degree ofshadowed gradually changes on
//! the boundary. 0 disables softening.
virtual void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) = 0;
//! Sets sample count to predict boundary of shadow (up to 16). It will be clamped to be less than or equal to the filtering
//! sample count.
virtual void SetPredictionSampleCount(LightHandle handle, uint16_t count) = 0;
//! Sets sample count for filtering of shadow boundary (up to 64)
virtual void SetFilteringSampleCount(LightHandle handle, uint16_t count) = 0;
//! Sets the shadowmap Pcf (percentage closer filtering) method.
virtual void SetPcfMethod(LightHandle handle, PcfMethod method) = 0;
//! Sets the Esm exponent to use. Higher values produce a steeper falloff in the border areas between light and shadow.
virtual void SetEsmExponent(LightHandle handle, float exponent) = 0;
//! Sets all of the the point data for the provided LightHandle.
@@ -37,14 +37,6 @@ namespace AZ
Count
};
enum class PcfMethod : uint16_t
{
BoundarySearch = 0, // Performs a variable number of taps, first to determine if we are on a shadow boundary, then the remaining taps are to find the occlusion amount
Bicubic, // Uses a fixed size Pcf kernel with kernel weights set to approximate bicubic filtering
Count
};
namespace Shadow
{
// [GFX TODO][ATOM-2408] Make the max number of cascade modifiable at runtime.
@@ -0,0 +1,19 @@
/*
* 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
*
*/
// Auto-generates override function declarations for getters and setters of specified parameters and overrides
#define AZ_GFX_COMMON_PARAM(ValueType, Name, MemberName, DefaultValue) \
ValueType Get##Name() const override { return MemberName; } \
void Set##Name(ValueType val) override { MemberName = val; } \
#define AZ_GFX_COMMON_OVERRIDE(ValueType, Name, MemberName, OverrideValueType) \
OverrideValueType Get##Name##Override() const override { return MemberName##Override; } \
void Set##Name##Override(OverrideValueType val) override { MemberName##Override = val; } \
#include <Atom/Feature/ParamMacros/MapAllCommon.inl>
@@ -52,14 +52,10 @@ namespace AZ::Render
virtual void SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size) = 0;
//! Sets the shadow bias
virtual void SetShadowBias(ShadowId id, float bias) = 0;
//! Sets the shadowmap Pcf method.
virtual void SetPcfMethod(ShadowId id, PcfMethod method) = 0;
//! Sets the shadow filter method
virtual void SetShadowFilterMethod(ShadowId id, ShadowFilterMethod method) = 0;
//! Sets the width of boundary between shadowed area and lit area.
virtual void SetSofteningBoundaryWidthAngle(ShadowId id, float boundaryWidthRadians) = 0;
//! Sets the sample count to predict the boundary of the shadow. Max 16, should be less than filtering sample count.
virtual void SetPredictionSampleCount(ShadowId id, uint16_t count) = 0;
//! Sets the sample count for filtering of the shadow boundary, max 64.
virtual void SetFilteringSampleCount(ShadowId id, uint16_t count) = 0;
//! Sets all of the shadow properites in one call
@@ -12,6 +12,7 @@
#include <Atom/RHI/Buffer.h>
#include <Atom/RHI/BufferPool.h>
#include <Atom/RPI.Public/FeatureProcessor.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
namespace AZ
@@ -36,8 +37,6 @@ namespace AZ
void Activate() override;
//! Releases GPU resources.
void Deactivate() override;
//! Binds buffers
void Render(const FeatureProcessor::RenderPacket& packet) override;
// RPI::SceneNotificationBus overrides ...
void OnBeginPrepareRender() override;
@@ -68,11 +67,13 @@ namespace AZ
// Prepare GPU buffers for object transformation matrices
// Create the buffers if they don't exist. Otherwise, resize them if they are not large enough for the matrices
void PrepareBuffers();
Data::Instance<RPI::ShaderResourceGroup> m_sceneSrg;
RHI::ShaderInputBufferIndex m_objectToWorldBufferIndex;
RHI::ShaderInputBufferIndex m_objectToWorldInverseTransposeBufferIndex;
RHI::ShaderInputBufferIndex m_objectToWorldHistoryBufferIndex;
void UpdateSceneSrg(RPI::ShaderResourceGroup *sceneSrg);
RPI::Scene::PrepareSceneSrgEvent::Handler m_updateSceneSrgHandler;
RHI::ShaderInputNameIndex m_objectToWorldBufferIndex = "m_objectToWorldBuffer";
RHI::ShaderInputNameIndex m_objectToWorldInverseTransposeBufferIndex = "m_objectToWorldInverseTransposeBuffer";
RHI::ShaderInputNameIndex m_objectToWorldHistoryBufferIndex = "m_objectToWorldHistoryBuffer";
// Stores transforms that are uploaded to a GPU buffer. Used slots have float12(matrix3x4) values, empty slots
// have a uint32_t that points to the next empty slot like a linked list. m_firstAvailableMeshTransformIndex stores the first
@@ -35,7 +35,7 @@ namespace AZ
protected:
// Pass overrides...
void FrameBeginInternal(FramePrepareParams params);
void FrameBeginInternal(FramePrepareParams params) override;
void BuildInternal() override;
void FrameEndInternal() override;
@@ -571,20 +571,6 @@ namespace AZ
}
}
void DirectionalLightFeatureProcessor::SetPredictionSampleCount(LightHandle handle, uint16_t count)
{
if (count > Shadow::MaxPcfSamplingCount)
{
AZ_Warning(FeatureProcessorName, false, "Sampling count exceed the limit.");
count = Shadow::MaxPcfSamplingCount;
}
for (auto& it : m_shadowData)
{
it.second.GetData(handle.GetIndex()).m_predictionSampleCount = count;
}
m_shadowBufferNeedsUpdate = true;
}
void DirectionalLightFeatureProcessor::SetFilteringSampleCount(LightHandle handle, uint16_t count)
{
if (count > Shadow::MaxPcfSamplingCount)
@@ -608,15 +594,6 @@ namespace AZ
m_shadowBufferNeedsUpdate = true;
}
void DirectionalLightFeatureProcessor::SetPcfMethod(LightHandle handle, PcfMethod method)
{
for (auto& it : m_shadowData)
{
it.second.GetData(handle.GetIndex()).m_pcfMethod = method;
}
m_shadowBufferNeedsUpdate = true;
}
void DirectionalLightFeatureProcessor::SetShadowReceiverPlaneBiasEnabled(LightHandle handle, bool enable)
{
m_shadowProperties.GetData(handle.GetIndex()).m_isReceiverPlaneBiasEnabled = enable;
@@ -102,8 +102,6 @@ namespace AZ
uint32_t m_debugFlags = 0;
uint32_t m_shadowFilterMethod = 0;
float m_far_minus_near = 0;
PcfMethod m_pcfMethod = PcfMethod::BoundarySearch;
uint32_t m_padding[3];
};
class DirectionalLightFeatureProcessor final
@@ -218,10 +216,8 @@ namespace AZ
void SetViewFrustumCorrectionEnabled(LightHandle handle, bool enabled) override;
void SetDebugFlags(LightHandle handle, DebugDrawFlags flags) override;
void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override;
void SetPredictionSampleCount(LightHandle handle, uint16_t count) override;
void SetFilteringSampleCount(LightHandle handle, uint16_t count) override;
void SetShadowBoundaryWidth(LightHandle handle, float boundaryWidth) override;
void SetPcfMethod(LightHandle handle, PcfMethod method) override;
void SetShadowReceiverPlaneBiasEnabled(LightHandle handle, bool enable) override;
const Data::Instance<RPI::Buffer> GetLightBuffer() const;
@@ -329,21 +329,11 @@ namespace AZ
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetSofteningBoundaryWidthAngle, boundaryWidthRadians);
}
void DiskLightFeatureProcessor::SetPredictionSampleCount(LightHandle handle, uint16_t count)
{
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetPredictionSampleCount, count);
}
void DiskLightFeatureProcessor::SetFilteringSampleCount(LightHandle handle, uint16_t count)
{
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetFilteringSampleCount, count);
}
void DiskLightFeatureProcessor::SetPcfMethod(LightHandle handle, PcfMethod method)
{
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetPcfMethod, method);
}
void DiskLightFeatureProcessor::SetEsmExponent(LightHandle handle, float exponent)
{
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetEsmExponent, exponent);
@@ -54,9 +54,7 @@ namespace AZ
void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) override;
void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override;
void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) override;
void SetPredictionSampleCount(LightHandle handle, uint16_t count) override;
void SetFilteringSampleCount(LightHandle handle, uint16_t count) override;
void SetPcfMethod(LightHandle handle, PcfMethod method) override;
void SetEsmExponent(LightHandle handle, float esmExponent) override;
void SetDiskData(LightHandle handle, const DiskLightData& data) override;
@@ -130,32 +130,17 @@ namespace AZ
const AZStd::array_view<RPI::Ptr<RPI::Pass>>& children = GetChildren();
AZ_Assert(children.size() == EsmChildPassKindCount, "[EsmShadowmapsPass '%s'] The count of children is wrong.", GetPathName().GetCStr());
for (uint32_t index = 0; index < EsmChildPassKindCount; ++index)
for (uint32_t childPassIndex = 0; childPassIndex < EsmChildPassKindCount; ++childPassIndex)
{
RPI::ComputePass* child = azrtti_cast<RPI::ComputePass*>(children[index].get());
RPI::ComputePass* child = azrtti_cast<RPI::ComputePass*>(children[childPassIndex].get());
AZ_Assert(child, "[EsmShadowmapsPass '%s'] A child does not compute.", GetPathName().GetCStr());
Data::Instance<RPI::ShaderResourceGroup> srg = child->GetShaderResourceGroup();
if (m_shadowmapIndexTableBufferIndices[index].IsNull())
SetBlurParameters(srg, childPassIndex);
if (childPassIndex >= aznumeric_cast<uint32_t>(EsmChildPassKind::KawaseBlur0))
{
m_shadowmapIndexTableBufferIndices[index] = srg->FindShaderInputBufferIndex(Name("m_shadowmapIndexTable"));
}
srg->SetBuffer(m_shadowmapIndexTableBufferIndices[index], m_shadowmapIndexTableBuffer);
if (m_filterParameterBufferIndices[index].IsNull())
{
m_filterParameterBufferIndices[index] = srg->FindShaderInputBufferIndex(Name("m_filterParameters"));
}
srg->SetBuffer(m_filterParameterBufferIndices[index], m_filterParameterBuffer);
if (index != static_cast<uint32_t>(EsmChildPassKind::Exponentiation))
{
if (m_filterTableBufferIndices[index].IsNull())
{
m_filterTableBufferIndices[index] = srg->FindShaderInputBufferIndex(Name("m_filterTable"));
}
srg->SetBuffer(m_filterTableBufferIndices[index], m_filterTableBuffer);
SetKawaseBlurSpecificParameters(srg, childPassIndex - aznumeric_cast<uint32_t>(EsmChildPassKind::KawaseBlur0));
}
child->SetTargetThreadCounts(
@@ -165,5 +150,32 @@ namespace AZ
}
}
void EsmShadowmapsPass::SetBlurParameters(Data::Instance<RPI::ShaderResourceGroup> srg, const uint32_t childPassIndex)
{
if (m_shadowmapIndexTableBufferIndices[childPassIndex].IsNull())
{
m_shadowmapIndexTableBufferIndices[childPassIndex] = srg->FindShaderInputBufferIndex(Name("m_shadowmapIndexTable"));
}
srg->SetBuffer(m_shadowmapIndexTableBufferIndices[childPassIndex], m_shadowmapIndexTableBuffer);
if (m_filterParameterBufferIndices[childPassIndex].IsNull())
{
m_filterParameterBufferIndices[childPassIndex] = srg->FindShaderInputBufferIndex(Name("m_filterParameters"));
}
srg->SetBuffer(m_filterParameterBufferIndices[childPassIndex], m_filterParameterBuffer);
}
void EsmShadowmapsPass::SetKawaseBlurSpecificParameters(Data::Instance<RPI::ShaderResourceGroup> srg, uint32_t kawaseBlurIndex)
{
if (m_kawaseBlurConstantIndices[kawaseBlurIndex].IsNull())
{
m_kawaseBlurConstantIndices[kawaseBlurIndex] = srg->FindShaderInputConstantIndex(Name("m_rcpResolutionAndIteration"));
}
const AZ::Vector4 data(
1.0f / m_shadowmapImageSize.m_width, 1.0f / m_shadowmapImageSize.m_height, aznumeric_cast<float>(kawaseBlurIndex), 0.0f);
srg->SetConstant(m_kawaseBlurConstantIndices[kawaseBlurIndex], data);
}
} // namespace Render
} // namespace AZ
@@ -21,12 +21,17 @@
namespace AZ
{
namespace RPI
{
class ShaderResourceGroup;
}
namespace Render
{
AZ_ENUM_CLASS_WITH_UNDERLYING_TYPE(EsmChildPassKind, uint32_t,
(Exponentiation, 0),
HorizontalFilter,
VerticalFilter);
KawaseBlur0,
KawaseBlur1);
//! This pass outputs filtered shadowmap images used in ESM.
//! ESM is an abbreviation of Exponential Shadow Maps.
@@ -88,6 +93,9 @@ namespace AZ
void FrameBeginInternal(FramePrepareParams params) override;
void UpdateChildren();
// Parameters for both the depth exponentiation pass along with the kawase blur passes
void SetBlurParameters(Data::Instance<RPI::ShaderResourceGroup> srg, const uint32_t childPassIndex);
void SetKawaseBlurSpecificParameters(Data::Instance<RPI::ShaderResourceGroup> srg, const uint32_t kawaseBlurIndex);
bool m_computationEnabled = false;
Name m_lightTypeName;
@@ -102,6 +110,8 @@ namespace AZ
Data::Instance<RPI::Buffer> m_shadowmapIndexTableBuffer;
AZStd::array<RHI::ShaderInputBufferIndex, EsmChildPassKindCount> m_filterParameterBufferIndices;
Data::Instance<RPI::Buffer> m_filterParameterBuffer;
AZStd::array<RHI::ShaderInputConstantIndex, 2> m_kawaseBlurConstantIndices;
};
} // namespace Render
} // namespace AZ
@@ -298,21 +298,11 @@ namespace AZ
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetSofteningBoundaryWidthAngle, boundaryWidthRadians);
}
void PointLightFeatureProcessor::SetPredictionSampleCount(LightHandle handle, uint16_t count)
{
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetPredictionSampleCount, count);
}
void PointLightFeatureProcessor::SetFilteringSampleCount(LightHandle handle, uint16_t count)
{
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetFilteringSampleCount, count);
}
void PointLightFeatureProcessor::SetPcfMethod(LightHandle handle, PcfMethod method)
{
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetPcfMethod, method);
}
void PointLightFeatureProcessor::SetEsmExponent(LightHandle handle, float esmExponent)
{
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetEsmExponent, esmExponent);
@@ -51,9 +51,7 @@ namespace AZ
void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) override;
void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override;
void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) override;
void SetPredictionSampleCount(LightHandle handle, uint16_t count) override;
void SetFilteringSampleCount(LightHandle handle, uint16_t count) override;
void SetPcfMethod(LightHandle handle, PcfMethod method) override;
void SetEsmExponent(LightHandle handle, float esmExponent) override;
void SetPointData(LightHandle handle, const PointLightData& data) override;
@@ -77,7 +77,7 @@ namespace AZ
void RenderImguiDrawData(const ImDrawData& drawData);
// TickBus::Handler overrides...
void OnTick(float deltaTime, AZ::ScriptTimePoint timePoint);
void OnTick(float deltaTime, AZ::ScriptTimePoint timePoint) override;
// AzFramework::InputTextEventListener overrides...
bool OnInputTextEventFiltered(const AZStd::string& textUTF8) override;
@@ -26,6 +26,7 @@ namespace AZ
static void Reflect(ReflectContext* context);
using RPI::MaterialFunctor::Process;
void Process(RuntimeContext& context) override;
private:
@@ -27,6 +27,7 @@ namespace AZ
static void Reflect(ReflectContext* context);
using RPI::MaterialFunctorSourceData::CreateFunctor;
FunctorResult CreateFunctor(const RuntimeContext& context) const override;
private:
@@ -26,6 +26,7 @@ namespace AZ
static void Reflect(ReflectContext* context);
using RPI::MaterialFunctor::Process;
void Process(RuntimeContext& context) override;
private:
@@ -25,6 +25,7 @@ namespace AZ
static void Reflect(AZ::ReflectContext* context);
using AZ::RPI::MaterialFunctorSourceData::CreateFunctor;
FunctorResult CreateFunctor(const RuntimeContext& context) const override;
private:
@@ -34,6 +34,7 @@ namespace AZ
static void Reflect(ReflectContext* context);
using RPI::MaterialFunctor::Process;
void Process(RuntimeContext& context) override;
private:
@@ -25,6 +25,7 @@ namespace AZ
static void Reflect(AZ::ReflectContext* context);
using AZ::RPI::MaterialFunctorSourceData::CreateFunctor;
FunctorResult CreateFunctor(const RuntimeContext& context) const override;
private:
@@ -479,8 +479,6 @@ namespace AZ
: m_modelAsset(modelAsset)
, m_parent(parent)
{
AZ_PROFILE_FUNCTION(AzRender);
if (!m_modelAsset.GetId().IsValid())
{
AZ_Error("MeshDataInstance::MeshLoader", false, "Invalid model asset Id.");
@@ -508,7 +506,6 @@ namespace AZ
//! AssetBus::Handler overrides...
void MeshDataInstance::MeshLoader::OnAssetReady(Data::Asset<Data::AssetData> asset)
{
AZ_PROFILE_FUNCTION(AzRender);
Data::Asset<RPI::ModelAsset> modelAsset = asset;
// Assign the fully loaded asset back to the mesh handle to not only hold asset id, but the actual data as well.
@@ -580,8 +577,6 @@ namespace AZ
void MeshDataInstance::Init(Data::Instance<RPI::Model> model)
{
AZ_PROFILE_FUNCTION(AzRender);
m_model = model;
const size_t modelLodCount = m_model->GetLodCount();
m_drawPacketListsByLod.resize(modelLodCount);
@@ -612,8 +607,6 @@ namespace AZ
void MeshDataInstance::BuildDrawPacketList(size_t modelLodIndex)
{
AZ_PROFILE_FUNCTION(AzRender);
RPI::ModelLod& modelLod = *m_model->GetLods()[modelLodIndex];
const size_t meshCount = modelLod.GetMeshes().size();
@@ -47,7 +47,7 @@ namespace AZ
void ApplySettingsTo(BloomSettings* target, float alpha) const;
// Generate getters and setters.
#include <Atom/Feature/ParamMacros/StartParamFunctions.inl>
#include <Atom/Feature/ParamMacros/StartParamFunctionsOverrideImpl.inl>
#include <Atom/Feature/PostProcess/Bloom/BloomParams.inl>
#include <Atom/Feature/ParamMacros/EndParams.inl>
@@ -52,7 +52,7 @@ namespace AZ
#undef POST_PROCESS_MEMBER
// Auto-gen getter and setter functions for post process members...
#include <Atom/Feature/ParamMacros/StartParamFunctions.inl>
#include <Atom/Feature/ParamMacros/StartParamFunctionsOverrideImpl.inl>
#include <Atom/Feature/PostProcess/PostProcessParams.inl>
#include <Atom/Feature/ParamMacros/EndParams.inl>
@@ -47,7 +47,7 @@ namespace AZ
void ApplySettingsTo(SsaoSettings* target, float alpha) const;
// Generate getters and setters.
#include <Atom/Feature/ParamMacros/StartParamFunctions.inl>
#include <Atom/Feature/ParamMacros/StartParamFunctionsOverrideImpl.inl>
#include <Atom/Feature/PostProcess/Ssao/SsaoParams.inl>
#include <Atom/Feature/ParamMacros/EndParams.inl>
@@ -36,8 +36,6 @@ namespace AZ
m_viewPtr = view;
m_viewSrg = view->GetShaderResourceGroup();
m_exposureControlBufferInputIndex = m_viewSrg->FindShaderInputBufferIndex(Name("m_exposureControl"));
m_eyeAdaptationBuffer.Init(m_viewSrg, idNumber);
}
@@ -109,14 +107,10 @@ namespace AZ
m_eyeAdaptationBuffer.UpdateSrg();
if (m_exposureControlBufferInputIndex.IsValid())
m_viewSrg->SetBufferView(m_exposureControlBufferInputIndex, m_buffer->GetBufferView());
if (m_viewPtr)
{
m_viewSrg->SetBufferView(m_exposureControlBufferInputIndex, m_buffer->GetBufferView());
if (m_viewPtr)
{
m_viewPtr->InvalidateSrg();
}
m_viewPtr->InvalidateSrg();
}
}
@@ -52,6 +52,7 @@ namespace AZ
struct ExposureCalculationData
{
float m_exposureValue = 1.0f;
float m_setValueTime = 0;
};
void BuildInternal() override;
@@ -367,11 +367,27 @@ namespace AZ
{
// set draw list mask
m_cullable.m_cullData.m_drawListMask.reset();
m_cullable.m_cullData.m_drawListMask =
m_stencilDrawPacket->GetDrawListMask() |
m_blendWeightDrawPacket->GetDrawListMask() |
m_renderOuterDrawPacket->GetDrawListMask() |
m_renderInnerDrawPacket->GetDrawListMask();
// check for draw packets due certain render pipelines such as lowend render pipeline that might not have this feature enabled
if (m_stencilDrawPacket)
{
m_cullable.m_cullData.m_drawListMask |= m_stencilDrawPacket->GetDrawListMask();
}
if (m_blendWeightDrawPacket)
{
m_cullable.m_cullData.m_drawListMask |= m_blendWeightDrawPacket->GetDrawListMask();
}
if (m_renderOuterDrawPacket)
{
m_cullable.m_cullData.m_drawListMask |= m_renderOuterDrawPacket->GetDrawListMask();
}
if (m_renderInnerDrawPacket)
{
m_cullable.m_cullData.m_drawListMask |= m_renderInnerDrawPacket->GetDrawListMask();
}
// setup the Lod entry, using one entry for all four draw packets
m_cullable.m_lodData.m_lods.clear();
@@ -56,7 +56,7 @@ namespace AZ
~DeferredFogSettings() = default;
// DeferredFogSettingsInterface overrides...
void OnSettingsChanged();
void OnSettingsChanged() override;
bool GetSettingsNeedUpdate()
{
return m_needUpdate;
@@ -66,35 +66,35 @@ namespace AZ
m_needUpdate = needUpdate;
}
void SetEnabled(bool value);
virtual bool GetEnabled() const override
void SetEnabled(bool value) override;
bool GetEnabled() const override
{
return m_enabled;
}
virtual void SetInitialized(bool isInitialized) override
void SetInitialized(bool isInitialized) override
{
m_isInitialized = isInitialized;
}
virtual bool IsInitialized() override
bool IsInitialized() override
{
return m_isInitialized;
}
virtual void SetUseNoiseTextureShaderOption(bool value) override
void SetUseNoiseTextureShaderOption(bool value) override
{
m_useNoiseTextureShaderOption = value;
}
virtual bool GetUseNoiseTextureShaderOption() override
bool GetUseNoiseTextureShaderOption() override
{
return m_useNoiseTextureShaderOption;
}
virtual void SetEnableFogLayerShaderOption(bool value) override
void SetEnableFogLayerShaderOption(bool value) override
{
m_enableFogLayerShaderOption = value;
}
virtual bool GetEnableFogLayerShaderOption() override
bool GetEnableFogLayerShaderOption() override
{
return m_enableFogLayerShaderOption;
}
@@ -165,15 +165,6 @@ namespace AZ::Render
m_filterParameterNeedsUpdate = true;
}
void ProjectedShadowFeatureProcessor::SetPcfMethod(ShadowId id, PcfMethod method)
{
AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetPcfMethod().");
ShadowData& shadowData = m_shadowData.GetElement<ShadowDataIndex>(id.GetIndex());
shadowData.m_pcfMethod = method;
m_deviceBufferNeedsUpdate = true;
}
void ProjectedShadowFeatureProcessor::SetEsmExponent(ShadowId id, float exponent)
{
AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetEsmExponent().");
@@ -188,7 +179,7 @@ namespace AZ::Render
ShadowProperty& shadowProperty = GetShadowPropertyFromShadowId(id);
ShadowData& shadowData = m_shadowData.GetElement<ShadowDataIndex>(id.GetIndex());
shadowData.m_shadowFilterMethod = aznumeric_cast<uint16_t>(method);
shadowData.m_shadowFilterMethod = aznumeric_cast<uint32_t>(method);
UpdateShadowView(shadowProperty);
@@ -207,19 +198,6 @@ namespace AZ::Render
m_filterParameterNeedsUpdate = true;
}
void ProjectedShadowFeatureProcessor::SetPredictionSampleCount(ShadowId id, uint16_t count)
{
AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetPredictionSampleCount().");
AZ_Warning("ProjectedShadowFeatureProcessor", count <= Shadow::MaxPcfSamplingCount, "Sampling count exceed the limit.");
count = GetMin(count, Shadow::MaxPcfSamplingCount);
ShadowData& shadowData = m_shadowData.GetElement<ShadowDataIndex>(id.GetIndex());
shadowData.m_predictionSampleCount = count;
m_deviceBufferNeedsUpdate = true;
}
void ProjectedShadowFeatureProcessor::SetFilteringSampleCount(ShadowId id, uint16_t count)
{
AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetFilteringSampleCount().");
@@ -48,15 +48,14 @@ namespace AZ::Render
void SetFieldOfViewY(ShadowId id, float fieldOfViewYRadians) override;
void SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size) override;
void SetShadowBias(ShadowId id, float bias) override;
void SetPcfMethod(ShadowId id, PcfMethod method);
void SetEsmExponent(ShadowId id, float exponent);
void SetShadowFilterMethod(ShadowId id, ShadowFilterMethod method) override;
void SetSofteningBoundaryWidthAngle(ShadowId id, float boundaryWidthRadians) override;
void SetPredictionSampleCount(ShadowId id, uint16_t count) override;
void SetFilteringSampleCount(ShadowId id, uint16_t count) override;
void SetShadowProperties(ShadowId id, const ProjectedShadowDescriptor& descriptor) override;
const ProjectedShadowDescriptor& GetShadowProperties(ShadowId id) override;
void SetEsmExponent(ShadowId id, float exponent);
private:
// GPU data stored in m_projectedShadows.
@@ -64,8 +63,7 @@ namespace AZ::Render
{
Matrix4x4 m_depthBiasMatrix = Matrix4x4::CreateIdentity();
uint32_t m_shadowmapArraySlice = 0; // array slice who has shadowmap in the atlas.
uint16_t m_shadowFilterMethod = 0; // filtering method of shadows.
PcfMethod m_pcfMethod = PcfMethod::BoundarySearch; // method for performing Pcf (uint16_t)
uint32_t m_shadowFilterMethod = 0; // filtering method of shadows.
float m_boundaryScale = 0.f; // the half of boundary of lit/shadowed areas. (in degrees)
uint32_t m_predictionSampleCount = 0; // sample count to judge whether it is on the shadow boundary or not.
uint32_t m_filteringSampleCount = 0;
@@ -36,11 +36,8 @@ namespace AZ
void TransformServiceFeatureProcessor::Activate()
{
m_sceneSrg = GetParentScene()->GetShaderResourceGroup();
m_objectToWorldBufferIndex = m_sceneSrg->FindShaderInputBufferIndex(Name{"m_objectToWorldBuffer"});
m_objectToWorldInverseTransposeBufferIndex = m_sceneSrg->FindShaderInputBufferIndex(Name{"m_objectToWorldInverseTransposeBuffer"});
m_objectToWorldHistoryBufferIndex = m_sceneSrg->FindShaderInputBufferIndex(Name{"m_objectToWorldHistoryBuffer"});
m_updateSceneSrgHandler = RPI::Scene::PrepareSceneSrgEvent::Handler([this](RPI::ShaderResourceGroup *sceneSrg) { this->UpdateSceneSrg(sceneSrg); });
GetParentScene()->ConnectEvent(m_updateSceneSrgHandler);
m_deviceBufferNeedsUpdate = true;
m_objectToWorldTransforms.reserve(BufferReserveCount);
@@ -62,9 +59,14 @@ namespace AZ
m_firstAvailableTransformIndex = NoAvailableTransformIndices;
m_objectToWorldBufferIndex.Reset();
m_objectToWorldInverseTransposeBufferIndex.Reset();
m_objectToWorldHistoryBufferIndex.Reset();
m_isWriteable = false;
RPI::SceneNotificationBus::Handler::BusDisconnect();
m_updateSceneSrgHandler.Disconnect();
}
void TransformServiceFeatureProcessor::PrepareBuffers()
@@ -131,16 +133,11 @@ namespace AZ
}
}
void TransformServiceFeatureProcessor::Render([[maybe_unused]] const FeatureProcessor::RenderPacket& packet)
void TransformServiceFeatureProcessor::UpdateSceneSrg(RPI::ShaderResourceGroup *sceneSrg)
{
AZ_ATOM_PROFILE_FUNCTION("RPI", "TransformServiceFeatureProcessor: Render");
AZ_UNUSED(packet);
AZ_Assert(!m_isWriteable, "Must be called between OnBeginPrepareRender() and OnEndPrepareRender()");
m_sceneSrg->SetBufferView(m_objectToWorldBufferIndex, m_objectToWorldBuffer->GetBufferView());
m_sceneSrg->SetBufferView(m_objectToWorldInverseTransposeBufferIndex, m_objectToWorldInverseTransposeBuffer->GetBufferView());
m_sceneSrg->SetBufferView(m_objectToWorldHistoryBufferIndex, m_objectToWorldHistoryBuffer->GetBufferView());
sceneSrg->SetBufferView(m_objectToWorldBufferIndex, m_objectToWorldBuffer->GetBufferView());
sceneSrg->SetBufferView(m_objectToWorldInverseTransposeBufferIndex, m_objectToWorldInverseTransposeBuffer->GetBufferView());
sceneSrg->SetBufferView(m_objectToWorldHistoryBufferIndex, m_objectToWorldHistoryBuffer->GetBufferView());
}
void TransformServiceFeatureProcessor::OnBeginPrepareRender()
@@ -39,6 +39,7 @@ set(FILES
Include/Atom/Feature/ParamMacros/StartParamCopySettingsTo.inl
Include/Atom/Feature/ParamMacros/StartParamFunctions.inl
Include/Atom/Feature/ParamMacros/StartParamFunctionsOverride.inl
Include/Atom/Feature/ParamMacros/StartParamFunctionsOverrideImpl.inl
Include/Atom/Feature/ParamMacros/StartParamFunctionsVirtual.inl
Include/Atom/Feature/ParamMacros/StartParamMembers.inl
Include/Atom/Feature/ParamMacros/StartParamSerializeContext.inl
@@ -113,7 +113,9 @@ if __name__ == '__main__':
lut_intervals, lut_values = generate_lut_values(image_spec, image_buffer)
write_3DL(args.o, image_spec.height, lut_intervals, lut_values)
write_azasset(args.o, image_spec.height, lut_intervals, lut_values)
# write_azasset(file_path, lut_intervals, lut_values, azasset_json=AZASSET_LUT)
write_azasset(args.o, lut_intervals, lut_values)
# example from command line
# python % DCCSI_COLORGRADING_SCRIPTS %\lut_helper.py - -i C: \Depot\o3de\Gems\Atom\Feature\Common\Tools\ColorGrading\Resources\LUTs\linear_32_LUT.exr - -op pre - grading - -shaper Log2 - 48nits - -o C: \Depot\o3de\Gems\Atom\Feature\Common\Tools\ColorGrading\Resources\LUTs\base_Log2-48nits_32_LUT.exr
@@ -31,11 +31,8 @@ if ColorGrading.initialize.start():
sys.exit(1)
# ------------------------------------------------------------------------
# ------------------------------------------------------------------------
from ColorGrading import AZASSET_LUT
# ------------------------------------------------------------------------
def find_first_line(alist):
for lno, line in enumerate(alist):
@@ -17,6 +17,13 @@ TITLE O3DE Color Grading CMD
:: Use obvious color to prevent confusion (Grey with Yellow Text)
COLOR 8E
echo.
echo _____________________________________________________________________
echo.
echo ~ O3DE Color Grading Python CMD ...
echo _____________________________________________________________________
echo.
%~d0
cd %~dp0
PUSHD %~dp0
@@ -27,16 +34,17 @@ SETLOCAL ENABLEDELAYEDEXPANSION
IF EXIST "%~dp0User_Env.bat" CALL %~dp0User_Env.bat
:: Initialize env
echo
echo ... calling Env_Core.bat
CALL %~dp0\Env_Core.bat
CALL %~dp0\Env_Python.bat
CALL %~dp0\Env_Tools.bat
echo.
echo _____________________________________________________________________
echo.
echo ~ O3DE Color Grading Python CMD ...
echo _____________________________________________________________________
echo.
echo
echo ... calling Env_Python.bat
CALL %~dp0\Env_Python.bat
echo
echo ... calling Env_Tools.bat
CALL %~dp0\Env_Tools.bat
:: Change to root dir
CD /D ..
@@ -93,9 +93,6 @@ popd
set DCCSIG_PATH=%O3DE_DEV%\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface
echo DCCSIG_PATH = %DCCSIG_PATH%
:: Change to DCCsi root dir
CD /D %DCCSIG_PATH%
:: per-dcc sdk path
set DCCSI_SDK_PATH=%DCCSIG_PATH%\SDK
echo DCCSI_SDK_PATH = %DCCSI_SDK_PATH%
@@ -26,7 +26,7 @@ SET DCCSI_GDEBUG=True
SET DCCSI_DEV_MODE=True
:: set the your user name here for windows path
SET TAG_USERNAME=< not set >
SET TAG_USERNAME=NOT_SET
SET DCCSI_PY_REV=rev1
SET DCCSI_PY_PLATFORM=windows
+1 -3
View File
@@ -42,6 +42,7 @@ ly_add_target(
FILES_CMAKE
atom_rhi_public_files.cmake
${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
${pal_source_dir}/platform_private_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source
@@ -55,9 +56,6 @@ ly_add_target(
Gem::Atom_RHI.Reflect
PUBLIC
${RENDERDOC_DEPENDENCY}
COMPILE_DEFINITIONS
PUBLIC
${RENDERDOC_DEFINE}
)
ly_add_target(
+54 -57
View File
@@ -50,24 +50,21 @@ namespace AZ
class RayTracingPipelineState;
class RayTracingShaderTable;
/* Priority of a Factory. The lower the number the higher the priority.
* Used when there's multiple factories available and the user hasn't define
* a priority.
*/
//! Priority of a Factory. The lower the number the higher the priority.
//! Used when there's multiple factories available and the user hasn't define
//! a priority.
using APIPriority = uint32_t;
static const APIPriority APITopPriority = 1;
static const APIPriority APILowPriority = 10;
static const APIPriority APIMiddlePriority = (APILowPriority - APITopPriority) / 2;
/**
* The factory is an interface for creating RHI data structures. The platform system should
* register itself with the factory by calling Register, and unregister on shutdown with
* Unregister.
*
* A call to Get will return the active instance. In the event that it's unclear whether
* a platform instance exists, you must call IsReady to determine whether it's safe to
* call Get. Calling Get without a registered platform will result in an assert.
*/
//! The factory is an interface for creating RHI data structures. The platform system should
//! register itself with the factory by calling Register, and unregister on shutdown with
//! Unregister.
//!
//! A call to Get will return the active instance. In the event that it's unclear whether
//! a platform instance exists, you must call IsReady to determine whether it's safe to
//! call Get. Calling Get without a registered platform will result in an assert.
class Factory
{
public:
@@ -79,78 +76,78 @@ namespace AZ
// Note that you have to delete these for safety reasons, you will trip a static_assert if you do not
AZ_DISABLE_COPY_MOVE(Factory);
/// Returns the component service name CRC used by the platform RHI system component.
//! Returns the component service name CRC used by the platform RHI system component.
static uint32_t GetComponentService();
/// Returns the component service name CRC used by the Factory manager component.
//! Returns the component service name CRC used by the Factory manager component.
static uint32_t GetManagerComponentService();
/// Returns the component service name CRC used by the platform RHI system component.
//! Returns the component service name CRC used by the platform RHI system component.
static uint32_t GetPlatformService();
/// Registers the global factory instance.
//! Registers the global factory instance.
static void Register(Factory* instance);
/// Unregisters the global factory instance.
//! Unregisters the global factory instance.
static void Unregister(Factory* instance);
/// Returns whether the factory is initialized and active in this module.
//! Returns whether the factory is initialized and active in this module.
static bool IsReady();
/// Access the global factory instance.
//! Access the global factory instance.
static Factory& Get();
#if defined(USE_RENDERDOC)
/// Access the RenderDoc API pointer if available.
/// The availability of the render doc API at runtime depends on the following:
/// - You must not be building a packaged game/product (LY_MONOLITHIC_GAME not enabled in CMake)
/// - A valid renderdoc installation was found, either by auto-discovery, or by supplying ATOM_RENDERDOC_PATH as an environment variable
/// - The module loaded successfully at runtime, and the API function pointer was retrieved successfully
//! Access the RenderDoc API pointer if available.
//! The availability of the render doc API at runtime depends on the following:
//! - You must not be building a packaged game/product (LY_MONOLITHIC_GAME not enabled in CMake)
//! - A valid renderdoc installation was found, either by auto-discovery, or by supplying ATOM_RENDERDOC_PATH as an environment variable
//! - The module loaded successfully at runtime, and the API function pointer was retrieved successfully
static RENDERDOC_API_1_1_2* GetRenderDocAPI();
#endif
//! Returns true if RenderDoc dll is loaded
static bool IsRenderDocModuleLoaded();
/// Returns the name of the Factory.
//! Returns true if Pix dll is loaded
static bool IsPixModuleLoaded();
//! Returns the name of the Factory.
virtual Name GetName() = 0;
/// Returns the APIType of the factory.
//! Returns the APIType of the factory.
virtual APIType GetType() = 0;
/// Returns the default priority of the factory in case there's no priorities set in the FactoryManager.
//! Returns the default priority of the factory in case there's no priorities set in the FactoryManager.
virtual APIPriority GetDefaultPriority() = 0;
/**
* Purpose: The API Unique Index will be encoded in the 2 Most Significant Bits of a ShaderVariantAsset ProductSubId (a 32bits integer).
* Returns a number in the range [0..3].
* In theory any given AssetBuilderSdk::PlatformInfo can support several RHI::APITypes.
* In reality "pc" only supports DX12 & Vulkan.
* "ios" supports only Metal.
* "mac" supports only Metal.
* "android" supports only Vulkan.
* So, for all practical purposes, a single PlatformInfo won't support more than 2 ShaderPlatformInterfaces, but for the sake of
* hedging our bets into the future We assume no more than 4 ShaderPlatformInterfaces will ever be supported for any given PlatformInfo.
* REMARK: It is the responsibility of the Factory subclass to return a unique number between 0...3.
* For example DX12 can return 0, while Vulkan should return 1 (Satisfies "pc", "android" and "linux").
* Metal can return 0 because it is the only ShaderPlatformInterface for "ios", "mac" and "appletv".
* See AZ::RHI::Limits::APIType::PerPlatformApiUniqueIndexMax.
*/
//! Purpose: The API Unique Index will be encoded in the 2 Most Significant Bits of a ShaderVariantAsset ProductSubId (a 32bits integer).
//! Returns a number in the range [0..3].
//! In theory any given AssetBuilderSdk::PlatformInfo can support several RHI::APITypes.
//! In reality "pc" only supports DX12 & Vulkan.
//! "ios" supports only Metal.
//! "mac" supports only Metal.
//! "android" supports only Vulkan.
//! So, for all practical purposes, a single PlatformInfo won't support more than 2 ShaderPlatformInterfaces, but for the sake of
//! hedging our bets into the future We assume no more than 4 ShaderPlatformInterfaces will ever be supported for any given PlatformInfo.
//! REMARK: It is the responsibility of the Factory subclass to return a unique number between 0...3.
//! For example DX12 can return 0, while Vulkan should return 1 (Satisfies "pc", "android" and "linux").
//! Metal can return 0 because it is the only ShaderPlatformInterface for "ios", "mac" and "appletv".
//! See AZ::RHI::Limits::APIType::PerPlatformApiUniqueIndexMax.
virtual uint32_t GetAPIUniqueIndex() const = 0;
/**
* Collects the set of physical devices on the system and returns a list of them. Physical
* devices represent the hardware attached to the system. Physical devices can be grouped
* into nodes for linked setups (e.g. SLI / Crossfire). They can also represent software
* reference implementations. Check the PhysicalDeviceType on the descriptor to inspect
* this information.
*/
//! Collects the set of physical devices on the system and returns a list of them. Physical
//! devices represent the hardware attached to the system. Physical devices can be grouped
//! into nodes for linked setups (e.g. SLI / Crossfire). They can also represent software
//! reference implementations. Check the PhysicalDeviceType on the descriptor to inspect
//! this information.
virtual PhysicalDeviceList EnumeratePhysicalDevices() = 0;
/**
* Factory Creation Methods:
*
* Returns the platform-specific derived variant of the RHI type. All instances are created
* in an uninitialized state; the operation simply allocates the memory for the appropriate
* platform type and returns the pointer.
*/
//! Factory Creation Methods:
//!
//! Returns the platform-specific derived variant of the RHI type. All instances are created
//! in an uninitialized state; the operation simply allocates the memory for the appropriate
//! platform type and returns the pointer.
virtual Ptr<Buffer> CreateBuffer() = 0;
@@ -51,7 +51,7 @@ namespace AZ
VirtualAddress Allocate(size_t byteCount, size_t byteAlignment) override;
void DeAllocate(VirtualAddress allocation) override;
void GarbageCollect() override;
void GarbageCollectForce();
void GarbageCollectForce() override;
size_t GetAllocationCount() const override;
size_t GetAllocatedByteCount() const override;
const Descriptor& GetDescriptor() const override;
@@ -44,7 +44,7 @@ namespace AZ
/// Returns the hash of the pipeline state descriptor contents.
virtual HashValue64 GetHash() const = 0;
virtual bool operator == (const PipelineStateDescriptor& rhs) const;
bool operator == (const PipelineStateDescriptor& rhs) const;
/// The pipeline layout describing the shader resource bindings.
ConstPtr<PipelineLayoutDescriptor> m_pipelineLayoutDescriptor = nullptr;
@@ -77,8 +77,7 @@ namespace AZ
/// Computes the hash value for this descriptor.
HashValue64 GetHash() const override;
virtual bool operator == (const PipelineStateDescriptorForDispatch& rhs) const;
bool operator == (const PipelineStateDescriptorForDispatch& rhs) const;
/// The compute function containing byte code to compile.
ConstPtr<ShaderStageFunction> m_computeFunction;
@@ -102,7 +101,7 @@ namespace AZ
/// Computes the hash value for this descriptor.
HashValue64 GetHash() const override;
virtual bool operator == (const PipelineStateDescriptorForDraw& rhs) const;
bool operator == (const PipelineStateDescriptorForDraw& rhs) const;
/// [Required] The vertex function to compile.
ConstPtr<ShaderStageFunction> m_vertexFunction;
@@ -135,7 +134,7 @@ namespace AZ
//! Computes the hash value for this descriptor.
HashValue64 GetHash() const override;
virtual bool operator == (const PipelineStateDescriptorForRayTracing& rhs) const;
bool operator == (const PipelineStateDescriptorForRayTracing& rhs) const;
// The ray tracing shader byte code
ConstPtr<ShaderStageFunction> m_rayTracingFunction;
@@ -51,7 +51,7 @@ namespace AZ
VirtualAddress Allocate(size_t byteCount, size_t byteAlignment) override;
void DeAllocate(VirtualAddress allocation) override;
void GarbageCollect() override;
void GarbageCollectForce();
void GarbageCollectForce() override;
size_t GetAllocationCount() const override;
size_t GetAllocatedByteCount() const override;
const Descriptor& GetDescriptor() const override;
@@ -38,7 +38,7 @@ namespace AZ
ResultCode InitGroup(ShaderResourceGroup& srg);
//! Returns the descriptor passed at initialization time.
const ShaderResourceGroupPoolDescriptor& GetDescriptor() const;
const ShaderResourceGroupPoolDescriptor& GetDescriptor() const override;
//! Returns the SRG layout used when initializing the pool.
const ShaderResourceGroupLayout* GetLayout() const;
@@ -83,11 +83,11 @@ namespace AZ
#if defined(PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB)
// On Linux platforms that uses XCB, a resize may occur in the swap chain but the command queue may still
// reference the original surface. This flag is a temporary fix to make sure that all the swap chains
// have finished their resize events before presenting the command queue.
// reference the original surface. This flag is a temporary fix to make sure the swap chain is ready to present
// We need to remove this work around with
// [GFX TODO][GHI - 2678]
AZStd::atomic_bool m_resized{ false };
AZStd::atomic_bool m_readyToPresent { false };
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
protected:
@@ -0,0 +1,11 @@
#
# 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
#
#
set(FILES
../Common/Unimplemented/Empty_Unimplemented.cpp
)
@@ -0,0 +1,21 @@
/*
* 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
*
*/
#include <AzCore/std/string/string.h>
namespace AZ::RHI::Platform
{
bool IsPixDllInjected([[maybe_unused]] const char* dllName)
{
return false;
}
AZStd::wstring GetLatestWinPixGpuCapturerPath()
{
return L"";
}
}

Some files were not shown because too many files have changed in this diff Show More