diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/assetpipeline/CMakeLists.txt index f453a38486..f47d57b7bd 100644 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/CMakeLists.txt @@ -13,13 +13,6 @@ add_subdirectory(asset_processor_tests) if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) ## AP Python Tests ## - ly_add_pytest( - NAME AssetPipelineTests.AuxiliaryContent - PATH ${CMAKE_CURRENT_LIST_DIR}/auxiliary_content_tests/auxiliary_content_tests.py - EXCLUDE_TEST_RUN_TARGET_FROM_IDE - TEST_SUITE periodic - ) - ly_add_pytest( NAME AssetPipelineTests.BankInfoParser PATH ${CMAKE_CURRENT_LIST_DIR}/wwise_bank_dependency_tests/bank_info_parser_tests.py diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/auxiliary_content_tests/__init__.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/auxiliary_content_tests/__init__.py deleted file mode 100755 index a6510a297f..0000000000 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/auxiliary_content_tests/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/auxiliary_content_tests/auxiliary_content_tests.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/auxiliary_content_tests/auxiliary_content_tests.py deleted file mode 100755 index 452dc66352..0000000000 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/auxiliary_content_tests/auxiliary_content_tests.py +++ /dev/null @@ -1,96 +0,0 @@ -""" -All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -its licensors. - -For complete copyright and license terms please see the LICENSE at the root of this -distribution (the "License"). All use of this software is governed by the License, -or, if provided, by the license below or the license accompanying this file. Do not -remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -""" -import pytest -import ly_test_tools - -import os -import sys -import shutil -import subprocess -import glob -from ly_test_tools.builtin.helpers import * -from ly_test_tools.environment.process_utils import * -from ly_test_tools.o3de.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP - -logger = logging.getLogger(__name__) - -project_list = ['AutomatedTesting'] - -@pytest.mark.system -@pytest.mark.SUITE_periodic -class TestAuxiliaryContent: - @pytest.fixture(autouse=True) - def setup_teardown(self, request, workspace, project): - path_to_dev = workspace.paths.engine_root() - os.chdir(path_to_dev) - auxiliaryContentDirName = str.lower(project) + f"_{ASSET_PROCESSOR_PLATFORM_MAP[workspace.asset_processor_platform]}_paks" - self.auxiliaryContentPath = os.path.join(path_to_dev, auxiliaryContentDirName) - - def teardown(): - if (os.path.exists(self.auxiliaryContentPath)): - shutil.rmtree(self.auxiliaryContentPath) - - request.addfinalizer(teardown) - - @staticmethod - def scanForLevelPak(path_toscan): - files = glob.glob('{0}/**/level.pak'.format(path_toscan), recursive=True) - return len(files) - - @pytest.mark.parametrize('level', ['alldependencies']) - @pytest.mark.parametrize('project', project_list) - def test_CreateAuxiliaryContent_DontSkipLevelPaks(self, workspace, level): - """ - This test ensure that Auxiliary Content contain level.pak files - - Test Steps: - 1. Run auxiliary content against project under test - 2. Validate auxiliary content exists - 3. Verifies that level.pak exists - """ - - path_to_dev = workspace.paths.engine_root() - bin_path = workspace.paths.build_directory() - - auxiliaryContentScriptPath = os.path.join(path_to_dev, 'BuildReleaseAuxiliaryContent.py') - subprocess.check_call(['python', auxiliaryContentScriptPath, - "--buildFolder={0}".format(bin_path), - "--platforms=pc", - f"--project-path={workspace.project}"]) - - assert os.path.exists(self.auxiliaryContentPath) - assert not self.scanForLevelPak(self.auxiliaryContentPath) == 0 - - @pytest.mark.parametrize('level', ['alldependencies']) - @pytest.mark.parametrize('project', project_list) - def test_CreateAuxiliaryContent_SkipLevelPaks(self, workspace, level): - """ - This test ensure that Auxiliary Content contain no level.pak file - - Test Steps: - 1. Run auxiliary content against project under test with skiplevelPaks flag - 2. Validate auxiliary content exists - 3. Validate level.pak was added to auxiliary content - """ - - path_to_dev = workspace.paths.engine_root() - bin_path = workspace.paths.build_directory() - - auxiliaryContentScriptPath = os.path.join(path_to_dev, 'BuildReleaseAuxiliaryContent.py') - subprocess.check_call(['python', auxiliaryContentScriptPath, - "--buildFolder={0}".format(bin_path), - "--platforms=pc", - "--skiplevelPaks", - f"--project-path={workspace.project}"]) - assert os.path.exists(self.auxiliaryContentPath) - - assert self.scanForLevelPak(self.auxiliaryContentPath) == 0 diff --git a/Code/Sandbox/Editor/CryEdit.cpp b/Code/Sandbox/Editor/CryEdit.cpp index 67e228a3ce..fdeb8ce28e 100644 --- a/Code/Sandbox/Editor/CryEdit.cpp +++ b/Code/Sandbox/Editor/CryEdit.cpp @@ -4060,17 +4060,10 @@ void CCryEditApp::SetEditorWindowTitle(QString sTitleStr, QString sPreTitleStr, { if (MainWindow::instance() || m_pConsoleDialog) { - QString platform = ""; - -#ifdef WIN64 - platform = "[x64]"; -#else - platform = "[x86]"; -#endif //WIN64 if (sTitleStr.isEmpty()) { - sTitleStr = QObject::tr("Open 3D Engine Editor Beta %1 - Build %2").arg(platform).arg(LY_BUILD); + sTitleStr = QObject::tr("O3DE Editor [Developer Preview]"); } if (!sPreTitleStr.isEmpty()) diff --git a/Code/Sandbox/Editor/EditorPreferencesPageAWS.cpp b/Code/Sandbox/Editor/EditorPreferencesPageAWS.cpp index edaf813cd8..4ad4e70be4 100644 --- a/Code/Sandbox/Editor/EditorPreferencesPageAWS.cpp +++ b/Code/Sandbox/Editor/EditorPreferencesPageAWS.cpp @@ -47,8 +47,6 @@ CEditorPreferencesPage_AWS::CEditorPreferencesPage_AWS() { m_settingsRegistry = AZStd::make_unique(); InitializeSettings(); - - // TODO Update with AWS svg. m_icon = QIcon(":/res/AWS_preferences_icon.svg"); } diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp index c8ed3954ac..0e3a4ba95d 100644 --- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp @@ -77,6 +77,7 @@ namespace O3DE::ProjectManager return ProjectManagerScreen::CreateProject; } + // Called when pressing "Create New Project" void CreateProjectCtrl::NotifyCurrentScreen() { ScreenWidget* currentScreen = reinterpret_cast(m_stack->currentWidget()); @@ -84,6 +85,11 @@ namespace O3DE::ProjectManager { currentScreen->NotifyCurrentScreen(); } + + // Gather the gems from the project template. When we will have multiple project templates, we need to re-gather them + // on changing the template and let the user know that any further changes on top of the template will be lost. + QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath(); + m_gemCatalogScreen->ReinitForProject(projectTemplatePath + "/Template", /*isNewProject=*/true); } void CreateProjectCtrl::HandleBackButton() @@ -151,9 +157,6 @@ namespace O3DE::ProjectManager { m_stack->setCurrentIndex(m_stack->currentIndex() + 1); - QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath(); - m_gemCatalogScreen->ReinitForProject(projectTemplatePath + "/Template", /*isNewProject=*/true); - Update(); } else diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp index 65f73accd1..409c51315d 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp @@ -89,17 +89,18 @@ namespace O3DE::ProjectManager return ProjectManagerScreen::UpdateProject; } + // Called when pressing "Edit Project Settings..." void UpdateProjectCtrl::NotifyCurrentScreen() { m_stack->setCurrentIndex(ScreenOrder::Settings); Update(); + + // Gather the available gems that will be shown in the gem catalog. + m_gemCatalogScreen->ReinitForProject(m_projectInfo.m_path, /*isNewProject=*/false); } void UpdateProjectCtrl::HandleGemsButton() { - // The next page is the gem catalog. Gather the available gems that will be shown in the gem catalog. - m_gemCatalogScreen->ReinitForProject(m_projectInfo.m_path, /*isNewProject=*/false); - m_stack->setCurrentWidget(m_gemCatalogScreen); Update(); } diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSAttributionServiceApi.h b/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSAttributionServiceApi.h index d14e51589c..cee3574f4d 100644 --- a/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSAttributionServiceApi.h +++ b/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSAttributionServiceApi.h @@ -43,7 +43,7 @@ namespace AWSCore bool UseAWSCredentials() { - return false; + return true; } //! Request body for the service API request. diff --git a/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp index e7a6828903..d667bfb2cf 100644 --- a/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp +++ b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp @@ -25,20 +25,24 @@ #include #include +#include +#include + namespace AWSCore { - static constexpr const char* EngineVersionJsonKey = "O3DEVersion"; + constexpr const char* EngineVersionJsonKey = "O3DEVersion"; constexpr char EditorAWSPreferencesFileName[] = "editor_aws_preferences.setreg"; constexpr char AWSAttributionSettingsPrefixKey[] = "/Amazon/AWS/Preferences"; constexpr char AWSAttributionEnabledKey[] = "/Amazon/AWS/Preferences/AWSAttributionEnabled"; constexpr char AWSAttributionDelaySecondsKey[] = "/Amazon/AWS/Preferences/AWSAttributionDelaySeconds"; constexpr char AWSAttributionLastTimeStampKey[] = "/Amazon/AWS/Preferences/AWSAttributionLastTimeStamp"; - constexpr char AWSAttributionApiId[] = "xbzx78kvbk"; + constexpr char AWSAttributionApiId[] = "2zxvvmv8d7"; constexpr char AWSAttributionChinaApiId[] = ""; constexpr char AWSAttributionApiStage[] = "prod"; + const int AWSAttributionDefaultDelayInDays = 7; AWSAttributionManager::AWSAttributionManager() { @@ -58,12 +62,11 @@ namespace AWSCore { if (ShouldGenerateMetric()) { - // 1. Gather metadata and assemble metric + // Gather metadata and assemble metric AttributionMetric metric; UpdateMetric(metric); - // 2. Identify region and chose attribution endpoint - // 3. Post metric + // Post metric SubmitMetric(metric); } } @@ -104,8 +107,7 @@ namespace AWSCore AZ::u64 delayInSeconds = 0; if (!m_settingsRegistry->Get(delayInSeconds, AWSAttributionDelaySecondsKey)) { - AZ_Warning("AWSAttributionManager", false, "AWSAttribution delay key not found. Defaulting to delay to day"); - delayInSeconds = 86400; + delayInSeconds = 86400 * AWSAttributionDefaultDelayInDays; m_settingsRegistry->Set(AWSAttributionDelaySecondsKey, delayInSeconds); } @@ -243,7 +245,8 @@ namespace AWSCore metric.SetO3DEVersion(engineVersion); AZStd::string platform = this->GetPlatform(); - metric.SetPlatform(platform, ""); + QString productName = QSysInfo::prettyProductName(); + metric.SetPlatform(platform, productName.toStdString().c_str()); AZStd::vector gemNames; GetActiveAWSGems(gemNames); @@ -256,6 +259,7 @@ namespace AWSCore void AWSAttributionManager::SubmitMetric(AttributionMetric& metric) { AWSCore::ServiceAPI::AWSAttributionRequestJob::Config* config = ServiceAPI::AWSAttributionRequestJob::GetDefaultConfig(); + // Identify region and chose attribution endpoint SetApiEndpointAndRegion(config); ServiceAPI::AWSAttributionRequestJob* requestJob = ServiceAPI::AWSAttributionRequestJob::Create( @@ -266,7 +270,12 @@ namespace AWSCore UpdateLastSend(); AZ_Printf("AWSAttributionManager", "AWSAttribution metric submit success"); - }, {}, config); + }, + [this](ServiceAPI::AWSAttributionRequestJob* failJob) + { + AZ_Error("AWSAttributionManager", false, "Metrics send error: %s", failJob->error.message.c_str()); + }, + config); requestJob->parameters.metric = metric; requestJob->Start(); diff --git a/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionMetric.cpp b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionMetric.cpp index 6ad322995e..683482b8f6 100644 --- a/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionMetric.cpp +++ b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionMetric.cpp @@ -19,14 +19,16 @@ namespace AWSCore { + constexpr char AWSAttributionMetricDefaultO3DEVersion[] = "1.1"; + AttributionMetric::AttributionMetric(const AZStd::string& timestamp) - : m_version("1.1") + : m_version(AWSAttributionMetricDefaultO3DEVersion) , m_timestamp(timestamp) { } AttributionMetric::AttributionMetric() - : m_version("1.1") + : m_version(AWSAttributionMetricDefaultO3DEVersion) { m_timestamp = AttributionMetric::GenerateTimeStamp(); } diff --git a/Gems/AWSCore/Code/Tests/Editor/Attribution/AWSCoreAttributionManagerTest.cpp b/Gems/AWSCore/Code/Tests/Editor/Attribution/AWSCoreAttributionManagerTest.cpp index 298c250086..be6a0a5ae8 100644 --- a/Gems/AWSCore/Code/Tests/Editor/Attribution/AWSCoreAttributionManagerTest.cpp +++ b/Gems/AWSCore/Code/Tests/Editor/Attribution/AWSCoreAttributionManagerTest.cpp @@ -32,6 +32,8 @@ #include #include +#include +#include using namespace AWSCore; @@ -405,6 +407,7 @@ namespace AWSAttributionUnitTest AZStd::string serializedMetricValue = metric.SerializeToJson(); ASSERT_TRUE(serializedMetricValue.find("\"o3de_version\":\"1.0.0.0\"") != AZStd::string::npos); ASSERT_TRUE(serializedMetricValue.find(AZ::GetPlatformName(AZ::g_currentPlatform)) != AZStd::string::npos); + ASSERT_TRUE(serializedMetricValue.find(QSysInfo::prettyProductName().toStdString().c_str()) != AZStd::string::npos); ASSERT_TRUE(serializedMetricValue.find("AWSCore.Editor") != AZStd::string::npos); ASSERT_TRUE(serializedMetricValue.find("AWSClientAuth") != AZStd::string::npos); diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityMode.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityMode.lua index 20d3ee47ae..b90f962f6c 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityMode.lua +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityMode.lua @@ -25,8 +25,6 @@ AlphaSource_Packed = 0 AlphaSource_Split = 1 AlphaSource_None = 2 -ForwardPassIndex = 1 - function ConfigureAlphaBlending(shaderItem) shaderItem:GetRenderStatesOverride():SetDepthEnabled(true) shaderItem:GetRenderStatesOverride():SetDepthWriteMask(DepthWriteMask_Zero) @@ -58,15 +56,17 @@ end function Process(context) local opacityMode = context:GetMaterialPropertyValue_enum("opacity.mode") + local forwardPassEDS = context:GetShaderByTag("ForwardPass_EDS") + if(opacityMode == OpacityMode_Blended) then - ConfigureAlphaBlending(context:GetShader(ForwardPassIndex)) - context:GetShader(ForwardPassIndex):SetDrawListTagOverride("transparent") + ConfigureAlphaBlending(forwardPassEDS) + forwardPassEDS:SetDrawListTagOverride("transparent") elseif(opacityMode == OpacityMode_TintedTransparent) then - ConfigureDualSourceBlending(context:GetShader(ForwardPassIndex)) - context:GetShader(ForwardPassIndex):SetDrawListTagOverride("transparent") + ConfigureDualSourceBlending(forwardPassEDS) + forwardPassEDS:SetDrawListTagOverride("transparent") else - ResetAlphaBlending(context:GetShader(ForwardPassIndex)) - context:GetShader(ForwardPassIndex):SetDrawListTagOverride("") -- reset to default draw list + ResetAlphaBlending(forwardPassEDS) + forwardPassEDS:SetDrawListTagOverride("") -- reset to default draw list end end diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ShaderEnable.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ShaderEnable.lua index b245fde3df..71e5ac7027 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ShaderEnable.lua +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ShaderEnable.lua @@ -74,7 +74,9 @@ function Process(context) shadowMapWithPS:SetEnabled(opacityMode == OpacityMode_Cutout) forwardPass:SetEnabled(opacityMode == OpacityMode_Cutout) - TrySetShaderEnabled(lowEndForwardEDS, (opacityMode == OpacityMode_Opaque) or (opacityMode == OpacityMode_Blended) or (opacityMode == OpacityMode_TintedTransparent)) + -- Only enable lowEndForwardEDS in Opaque mode, Transparent mode will be handled by forwardPassEDS. The transparent pass uses the "transparent" draw tag + -- for both standard and low end pipelines, so this keeps both shaders from rendering to the transparent draw list. + TrySetShaderEnabled(lowEndForwardEDS, opacityMode == OpacityMode_Opaque) TrySetShaderEnabled(lowEndForward, opacityMode == OpacityMode_Cutout) end diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli index e4cb87802a..8668ac10d8 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli @@ -226,7 +226,7 @@ float ProjectedShadow::GetVisibilityEsm() } const float invAtlasSize = ViewSrg::m_invShadowmapAtlasSize; - const Texture2DArray expShadowmap = PassSrg::m_projectedExponentialShadowmap; + const Texture2DArray shadowmap = PassSrg::m_projectedExponentialShadowmap; if (m_shadowPosition.x >= 0 && m_shadowPosition.x * size < size - PixelMargin && m_shadowPosition.y >= 0 && m_shadowPosition.y * size < size - PixelMargin) @@ -243,10 +243,12 @@ float ProjectedShadow::GetVisibilityEsm() const float depth = PerspectiveDepthToLinear( m_shadowPosition.z, coefficients); - const float expDepthInShadowmap = expShadowmap.Sample( + const float occluder = shadowmap.Sample( PassSrg::LinearSampler, float3(atlasPosition.xy * invAtlasSize, atlasPosition.z)).r; - const float ratio = exp(-EsmExponentialShift * depth) * expDepthInShadowmap; + + const float exponent = -ViewSrg::m_projectedShadows[m_shadowIndex].m_esmExponent * (depth - occluder); + const float ratio = exp(exponent); // pow() mitigates light bleeding to shadows from near shadow casters. return saturate( pow(ratio, 8) ); } @@ -265,7 +267,7 @@ float ProjectedShadow::GetVisibilityEsmPcf() } const float invAtlasSize = ViewSrg::m_invShadowmapAtlasSize; - const Texture2DArray expShadowmap = PassSrg::m_projectedExponentialShadowmap; + const Texture2DArray shadowmap = PassSrg::m_projectedExponentialShadowmap; if (m_shadowPosition.x >= 0 && m_shadowPosition.x * size < size - PixelMargin && m_shadowPosition.y >= 0 && m_shadowPosition.y * size < size - PixelMargin) @@ -282,10 +284,12 @@ float ProjectedShadow::GetVisibilityEsmPcf() const float depth = PerspectiveDepthToLinear( m_shadowPosition.z, coefficients); - const float expDepthInShadowmap = expShadowmap.Sample( + const float occluder = shadowmap.Sample( PassSrg::LinearSampler, float3(atlasPosition.xy * invAtlasSize, atlasPosition.z)).r; - float ratio = exp(-EsmExponentialShift * depth) * expDepthInShadowmap; + + const float exponent = -ViewSrg::m_projectedShadows[m_shadowIndex].m_esmExponent * (depth - occluder); + float ratio = exp(exponent); static const float pcfFallbackThreshold = 1.04; if (ratio > pcfFallbackThreshold) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli index 7a51d4c629..37b021e148 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli @@ -92,6 +92,8 @@ partial ShaderResourceGroup ViewSrg uint m_filteringSampleCount; float2 m_unprojectConstants; float m_bias; + float m_esmExponent; + float3 m_padding; }; StructuredBuffer m_projectedShadows; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/DepthExponentiation.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/DepthExponentiation.azsl index bea63c6b0b..1954605656 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/DepthExponentiation.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/DepthExponentiation.azsl @@ -56,7 +56,6 @@ void MainCS(uint3 dispatchId: SV_DispatchThreadID) return; // Early return if filter is disabled. } - float depth = 0.; switch (o_shadowmapLightType) { case ShadowmapLightType::Directional: @@ -68,9 +67,15 @@ void MainCS(uint3 dispatchId: SV_DispatchThreadID) // and it often causes light bleeding with ESM. // So this converts it to "depth" to emphasize the difference // within the frustum. - depth = (depthInClip - distanceMin) / (1. - distanceMin); - } + const float depth = (depthInClip - distanceMin) / (1. - distanceMin); + + // Todo: Expose Esm exponent slider for directional lights + // This would remove the exp calculation below, collapsing it into a subtraction in DirectionalLightShadow.azsli + // ATOM-15775 + const float outValue = exp(EsmExponentialShift * depth); + PassSrg::m_outputShadowmap[dispatchId].r = outValue; break; + } case ShadowmapLightType::Spot: { const float3 coefficients = float3( @@ -84,12 +89,9 @@ void MainCS(uint3 dispatchId: SV_DispatchThreadID) // and it often causes light bleeding with ESM. // So this converts it to a linear depth to emphasize the // difference like a orthogonal depth. - depth = PerspectiveDepthToLinear(depthInClip, coefficients); - } + PassSrg::m_outputShadowmap[dispatchId].r = PerspectiveDepthToLinear(depthInClip, coefficients); break; + } } - - const float outValue = exp(EsmExponentialShift * depth); - PassSrg::m_outputShadowmap[dispatchId].r = outValue; } diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h index ce911fecf7..fc261fb57b 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h @@ -100,10 +100,13 @@ namespace AZ 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 disk data for the provided LightHandle. virtual void SetDiskData(LightHandle handle, const DiskLightData& data) = 0; - + + }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h index 30d88cb839..c781030220 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h @@ -82,6 +82,8 @@ namespace AZ 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. virtual void SetPointData(LightHandle handle, const PointLightData& data) = 0; }; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp index d0fb702d5a..b3a39e8fe3 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp @@ -343,6 +343,11 @@ namespace AZ SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetPcfMethod, method); } + void DiskLightFeatureProcessor::SetEsmExponent(LightHandle handle, float exponent) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetEsmExponent, exponent); + } + void DiskLightFeatureProcessor::UpdateShadow(LightHandle handle) { const DiskLightData& diskLight = m_diskLightData.GetData(handle.GetIndex()); diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h index 8391506f63..1147272204 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h @@ -60,6 +60,7 @@ namespace AZ 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; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.cpp index 4f2a4f0346..7742036171 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.cpp @@ -192,9 +192,7 @@ namespace AZ OnShaderReloaded(); } - void LightCullingTilePreparePass::OnShaderVariantReinitialized( - const AZ::RPI::Shader&, const AZ::RPI::ShaderVariantId&, - AZ::RPI::ShaderVariantStableId) + void LightCullingTilePreparePass::OnShaderVariantReinitialized(const AZ::RPI::ShaderVariant&) { OnShaderReloaded(); } diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.h index 0febb66e3d..674f5d9914 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.h @@ -56,7 +56,7 @@ namespace AZ // ShaderReloadNotificationBus overrides... void OnShaderReinitialized(const AZ::RPI::Shader& shader) override; void OnShaderAssetReinitialized(const Data::Asset& shaderAsset) override; - void OnShaderVariantReinitialized(const AZ::RPI::Shader& shader, const AZ::RPI::ShaderVariantId& shaderVariantId, AZ::RPI::ShaderVariantStableId shaderVariantStableId) override; + void OnShaderVariantReinitialized(const AZ::RPI::ShaderVariant& shaderVariant) override; // Scope producer functions... void CompileResources(const RHI::FrameGraphCompileContext& context) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp index bb81c52b15..a5cb59e73c 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp @@ -312,5 +312,10 @@ namespace AZ SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetPcfMethod, method); } + void PointLightFeatureProcessor::SetEsmExponent(LightHandle handle, float esmExponent) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetEsmExponent, esmExponent); + } + } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h index c0c377e960..897bf6dc3e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h @@ -57,6 +57,7 @@ namespace AZ 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; const Data::Instance GetLightBuffer() const; diff --git a/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.cpp b/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.cpp index 7b3aedd64e..55a6d5d87a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.cpp @@ -199,7 +199,7 @@ namespace AZ } } - void MorphTargetDispatchItem::OnShaderAssetReinitialized([[maybe_unused]] const Data::Asset& shaderAsset) + void MorphTargetDispatchItem::OnShaderAssetReinitialized([[maybe_unused]] const Data::Asset& shaderAsset) { if (!Init()) { @@ -207,7 +207,7 @@ namespace AZ } } - void MorphTargetDispatchItem::OnShaderVariantReinitialized([[maybe_unused]] const RPI::Shader& shader, [[maybe_unused]] const RPI::ShaderVariantId& shaderVariantId, [[maybe_unused]] RPI::ShaderVariantStableId shaderVariantStableId) + void MorphTargetDispatchItem::OnShaderVariantReinitialized(const RPI::ShaderVariant&) { if (!Init()) { diff --git a/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.h b/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.h index ad1fd969a5..e7d78caf5f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.h +++ b/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.h @@ -72,8 +72,8 @@ namespace AZ // ShaderInstanceNotificationBus::Handler overrides void OnShaderReinitialized(const RPI::Shader& shader) override; - void OnShaderAssetReinitialized(const Data::Asset& shaderAsset) override; - void OnShaderVariantReinitialized(const RPI::Shader& shader, const RPI::ShaderVariantId& shaderVariantId, RPI::ShaderVariantStableId shaderVariantStableId) override; + void OnShaderAssetReinitialized(const Data::Asset& shaderAsset) override; + void OnShaderVariantReinitialized(const RPI::ShaderVariant& shaderVariant) override; RHI::DispatchItem m_dispatchItem; diff --git a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp index 9cc98a15ec..295e10a53f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp @@ -458,9 +458,13 @@ namespace AZ bool ProfilingCaptureSystemComponent::CaptureCpuProfilingStatistics(const AZStd::string& outputFilePath) { // Start the cpu profiling - RHI::CpuProfiler::Get()->SetProfilerEnabled(true); + bool wasEnabled = RHI::CpuProfiler::Get()->IsProfilerEnabled(); + if (!wasEnabled) + { + RHI::CpuProfiler::Get()->SetProfilerEnabled(true); + } - const bool captureStarted = m_cpuProfilingStatisticsCapture.StartCapture([this, outputFilePath]() + const bool captureStarted = m_cpuProfilingStatisticsCapture.StartCapture([this, outputFilePath, wasEnabled]() { JsonSerializerSettings serializationSettings; serializationSettings.m_keepDefaults = true; @@ -481,14 +485,22 @@ namespace AZ saveResult.GetError().c_str()); AZ_Warning("ProfilingCaptureSystemComponent", false, captureInfo.c_str()); } + else + { + AZ_Printf("ProfilingCaptureSystemComponent", "Cpu profiling statistics was saved to file [%s]\n", outputFilePath.c_str()); + } // Disable the profiler again - RHI::CpuProfiler::Get()->SetProfilerEnabled(false); + if (!wasEnabled) + { + RHI::CpuProfiler::Get()->SetProfilerEnabled(false); + } // Notify listeners that the pass' PipelineStatistics queries capture has finished. ProfilingCaptureNotificationBus::Broadcast(&ProfilingCaptureNotificationBus::Events::OnCaptureCpuProfilingStatisticsFinished, saveResult.IsSuccess(), captureInfo); + }); // Start the TickBus. diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.cpp b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.cpp index 988870cc0e..6e11ba838b 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.cpp @@ -354,9 +354,9 @@ namespace AZ Init(); } - void RayTracingPass::OnShaderVariantReinitialized([[maybe_unused]] const RPI::Shader& shader, [[maybe_unused]] const RPI::ShaderVariantId& shaderVariantId, [[maybe_unused]] RPI::ShaderVariantStableId shaderVariantStableId) + void RayTracingPass::OnShaderVariantReinitialized(const RPI::ShaderVariant&) { Init(); } - } // namespace RPI + } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.h b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.h index 6ad082e894..92da052d09 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.h @@ -53,7 +53,7 @@ namespace AZ // ShaderReloadNotificationBus::Handler overrides void OnShaderReinitialized(const RPI::Shader& shader) override; void OnShaderAssetReinitialized(const Data::Asset& shaderAsset) override; - void OnShaderVariantReinitialized(const RPI::Shader& shader, const RPI::ShaderVariantId& shaderVariantId, RPI::ShaderVariantStableId shaderVariantStableId) override; + void OnShaderVariantReinitialized(const RPI::ShaderVariant& shaderVariant) override; // load the raytracing shaders and setup pipeline states void Init(); diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp index da174ab0d5..ac723508c0 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp @@ -162,12 +162,21 @@ namespace AZ::Render void ProjectedShadowFeatureProcessor::SetPcfMethod(ShadowId id, PcfMethod method) { + AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetPcfMethod()."); ShadowData& shadowData = m_shadowData.GetElement(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()."); + ShadowData& shadowData = m_shadowData.GetElement(id.GetIndex()); + shadowData.m_esmExponent = exponent; + m_deviceBufferNeedsUpdate = true; + } + void ProjectedShadowFeatureProcessor::SetShadowFilterMethod(ShadowId id, ShadowFilterMethod method) { AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetShadowFilterMethod()."); diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h index a131c914f2..bf03e490a6 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h @@ -52,6 +52,7 @@ namespace AZ::Render void SetFieldOfViewY(ShadowId id, float fieldOfViewYRadians) override; void SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size) 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; @@ -73,6 +74,8 @@ namespace AZ::Render uint32_t m_filteringSampleCount = 0; AZStd::array m_unprojectConstants = { {0, 0} }; float m_bias; + float m_esmExponent = 87.0f; + float m_padding[3]; }; // CPU data used for constructing & updating ShadowData diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshComputePass.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshComputePass.cpp index a3feddb0b6..b0d08314b1 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshComputePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshComputePass.cpp @@ -65,9 +65,13 @@ namespace AZ } } - void SkinnedMeshComputePass::OnShaderVariantReinitialized(const RPI::Shader& shader, const RPI::ShaderVariantId&, RPI::ShaderVariantStableId) + void SkinnedMeshComputePass::OnShaderVariantReinitialized(const RPI::ShaderVariant& shaderVariant) { - OnShaderReinitialized(shader); + ComputePass::OnShaderVariantReinitialized(shaderVariant); + if (m_skinnedMeshFeatureProcessor) + { + m_skinnedMeshFeatureProcessor->OnSkinningShaderReinitialized(m_shader); + } } } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshComputePass.h b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshComputePass.h index 5f7ff08e47..dbd8704c54 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshComputePass.h +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshComputePass.h @@ -44,7 +44,7 @@ namespace AZ // ShaderReloadNotificationBus::Handler overrides... void OnShaderReinitialized(const RPI::Shader& shader) override; - void OnShaderVariantReinitialized(const RPI::Shader& shader, const RPI::ShaderVariantId& shaderVariantId, RPI::ShaderVariantStableId shaderVariantStableId) override; + void OnShaderVariantReinitialized(const RPI::ShaderVariant& shaderVariant) override; SkinnedMeshFeatureProcessor* m_skinnedMeshFeatureProcessor = nullptr; }; diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfiler.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfiler.h index cf3a31adf6..b5c8f144ba 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfiler.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfiler.h @@ -12,6 +12,7 @@ #pragma once +#include #include #include #include @@ -87,6 +88,8 @@ namespace AZ //! Enable/Disable the CpuProfiler virtual void SetProfilerEnabled(bool enabled) = 0; + + virtual bool IsProfilerEnabled() const = 0 ; }; } // namespace RPI diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h index 30523194b6..9685f9be98 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h @@ -102,6 +102,7 @@ namespace AZ void EndTimeRegion() final; void FlushTimeRegionMap(TimeRegionMap& timeRegionMap) final; void SetProfilerEnabled(bool enabled) final; + bool IsProfilerEnabled() const final; private: // Lazily create and register the local thread data diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/MemorySubAllocator.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/MemorySubAllocator.h index 47abf5409d..75fd3035bf 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/MemorySubAllocator.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/MemorySubAllocator.h @@ -11,6 +11,7 @@ */ #pragma once +#include #include #include #include @@ -160,6 +161,7 @@ namespace AZ template void MemorySubAllocator::GarbageCollect() { + AZ_ATOM_PROFILE_FUNCTION("RHI", "MemorySubAllocator: GarbageCollect"); for (PageContext& pageContext : m_pageContexts) { pageContext.m_allocator.GarbageCollect(); diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/ObjectCollector.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/ObjectCollector.h index 98d63accc9..a3a07c1533 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/ObjectCollector.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/ObjectCollector.h @@ -11,6 +11,7 @@ */ #pragma once +#include #include #include #include @@ -169,6 +170,7 @@ namespace AZ template void ObjectCollector::Collect(bool forceFlush) { + AZ_ATOM_PROFILE_FUNCTION("DX12", "ObjectCollector: Collect"); m_mutex.lock(); if (m_pendingObjects.size()) { diff --git a/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp b/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp index 700d09d7bf..57a2b541f1 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp @@ -11,6 +11,7 @@ */ #include +#include #include namespace AZ @@ -86,6 +87,7 @@ namespace AZ void CommandQueue::FlushCommands() { + AZ_ATOM_PROFILE_FUNCTION("RHI", "CommandQueue: FlushCommands"); while (!m_isWorkQueueEmpty && !m_isQuitting) { AZStd::this_thread::yield(); diff --git a/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp b/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp index 8242c89886..9b77e7566f 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp @@ -186,6 +186,12 @@ namespace AZ } } + bool CpuProfilerImpl::IsProfilerEnabled() const + { + return m_enabled; + } + + void CpuProfilerImpl::RegisterThreadStorage() { AZStd::unique_lock lock(m_threadRegisterMutex); diff --git a/Gems/Atom/RHI/Code/Source/RHI/Device.cpp b/Gems/Atom/RHI/Code/Source/RHI/Device.cpp index 4c54ce3237..7b7dc2de8c 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/Device.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/Device.cpp @@ -10,6 +10,7 @@ * */ +#include #include #include @@ -151,6 +152,7 @@ namespace AZ { if (ValidateIsInitialized() && ValidateIsInFrame()) { + AZ_ATOM_PROFILE_FUNCTION("RHI", "Device: EndFrame"); EndFrameInternal(); m_isInFrame = false; return ResultCode::Success; @@ -172,6 +174,7 @@ namespace AZ { if (ValidateIsInitialized() && ValidateIsNotInFrame()) { + AZ_ATOM_PROFILE_FUNCTION("RHI", "Device: CompileMemoryStatistics"); MemoryStatisticsBuilder builder; builder.Begin(memoryStatistics, reportFlags); CompileMemoryStatisticsInternal(builder); diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp index 767ab83c47..1788d0e85c 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp @@ -9,18 +9,19 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ -#include -#include #include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include #include +#include #include +#include #include +#include +#include #include #include @@ -76,6 +77,7 @@ namespace AZ void FrameGraph::Clear() { + AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraph: Clear"); for (Scope* scope : m_scopes) { scope->Deactivate(); diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp index dff49a9086..06c8791655 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp @@ -9,10 +9,11 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ -#include #include -#include +#include #include +#include +#include #include #include @@ -80,7 +81,7 @@ namespace AZ void FrameGraphExecuter::End() { - AZ_TRACE_METHOD(); + AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraphExecuter: End"); AZ_Assert(m_pendingGroups.empty(), "Pending contexts in queue."); m_groups.clear(); EndInternal(); diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp index 67cad6c4dc..cf8f3aa2ed 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp @@ -181,7 +181,10 @@ namespace AZ m_compileRequest = compileRequest; - FrameEventBus::Broadcast(&FrameEventBus::Events::OnFrameCompile); + { + AZ_ATOM_PROFILE_TIME_GROUP_REGION("RHI", "FrameScheduler: Compile: OnFrameCompile"); + FrameEventBus::Broadcast(&FrameEventBus::Events::OnFrameCompile); + } FrameGraphCompileRequest frameGraphCompileRequest; frameGraphCompileRequest.m_frameGraph = m_frameGraph.get(); @@ -193,7 +196,10 @@ namespace AZ const MessageOutcome outcome = m_frameGraphCompiler->Compile(frameGraphCompileRequest); if (outcome.IsSuccess()) { - FrameEventBus::Broadcast(&FrameEventBus::Events::OnFrameCompileEnd, *m_frameGraph); + { + AZ_ATOM_PROFILE_TIME_GROUP_REGION("RHI", "FrameScheduler: Compile: OnFrameCompileEnd"); + FrameEventBus::Broadcast(&FrameEventBus::Events::OnFrameCompileEnd, *m_frameGraph); + } FrameGraphLogger::Log(*m_frameGraph, compileRequest.m_logVerbosity); @@ -400,7 +406,11 @@ namespace AZ m_scopeProducers.clear(); m_scopeProducerLookup.clear(); - FrameEventBus::Event(m_device, &FrameEventBus::Events::OnFrameEnd); + + { + AZ_ATOM_PROFILE_TIME_GROUP_REGION("RHI", "FrameScheduler: EndFrame: OnFrameEnd"); + FrameEventBus::Event(m_device, &FrameEventBus::Events::OnFrameEnd); + } const AZStd::sys_time_t timeNowTicks = AZStd::GetTimeNowTicks(); m_cpuTimingStatistics.m_frameToFrameTime = timeNowTicks - m_lastFrameEndTime; diff --git a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp index 81409e2c18..e1666549c9 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp @@ -10,6 +10,7 @@ * */ +#include #include #include #include @@ -213,19 +214,23 @@ namespace AZ void RHISystem::FrameUpdate(FrameGraphCallback frameGraphCallback) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender); + AZ_ATOM_PROFILE_FUNCTION("RHI", "RHISystem: FrameUpdate"); { AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::AzRender, "main per-frame work"); m_frameScheduler.BeginFrame(); - + frameGraphCallback(m_frameScheduler); /** * This exists as a hook to enable RHI sample tests, which are allowed to queue their * own RHI scopes to the frame scheduler. This happens prior to the RPI pass graph registration. */ - RHISystemNotificationBus::Broadcast(&RHISystemNotificationBus::Events::OnFramePrepare, m_frameScheduler); - + { + AZ_ATOM_PROFILE_TIME_GROUP_REGION("RHI", "RHISystem :FrameUpdate: OnFramePrepare"); + RHISystemNotificationBus::Broadcast(&RHISystemNotificationBus::Events::OnFramePrepare, m_frameScheduler); + } + RHI::MessageOutcome outcome = m_frameScheduler.Compile(m_compileRequest); if (outcome.IsSuccess()) { diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListPool.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListPool.cpp index d43129a626..5510b4e924 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListPool.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListPool.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include namespace AZ @@ -179,6 +180,7 @@ namespace AZ void CommandListAllocator::Collect() { + AZ_ATOM_PROFILE_FUNCTION("DX12", "CommandListAllocator: Collect"); for (uint32_t queueIdx = 0; queueIdx < RHI::HardwareQueueClassCount; ++queueIdx) { m_commandListSubAllocators[queueIdx].ForEach([](Internal::CommandListSubAllocator& commandListSubAllocator) diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp index a31e105b19..5bf0a84700 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp @@ -137,6 +137,7 @@ namespace AZ void CommandQueueContext::End() { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender); + AZ_ATOM_PROFILE_FUNCTION("DX12", "CommandQueueContext: End"); QueueGpuSignals(m_frameFences[m_currentFrameIndex]); @@ -150,7 +151,7 @@ namespace AZ { AZ_PROFILE_SCOPE_IDLE(AZ::Debug::ProfileCategory::AzRender, "Wait and Reset Fence"); - AZ_ATOM_PROFILE_FUNCTION("RHI", "CommandQueueContext: Wait on Fences"); + AZ_ATOM_PROFILE_TIME_GROUP_REGION("DX12", "CommandQueueContext: Wait on Fences"); FenceEvent event("FrameFence"); m_frameFences[m_currentFrameIndex].Wait(event); diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.cpp index e11817a7d8..f83f169f2f 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace AZ @@ -345,6 +346,7 @@ namespace AZ void DescriptorContext::GarbageCollect() { + AZ_ATOM_PROFILE_FUNCTION("DX12", "DescriptorContext: GarbageCollect"); for (const auto& itr : m_platformLimitsDescriptor->m_descriptorHeapLimits) { for (uint32_t shaderVisibleIdx = 0; shaderVisibleIdx < PlatformLimitsDescriptor::NumHeapFlags; ++shaderVisibleIdx) diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/StagingMemoryAllocator.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/StagingMemoryAllocator.cpp index 47ae24f487..df5fc53468 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/StagingMemoryAllocator.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/StagingMemoryAllocator.cpp @@ -60,6 +60,7 @@ namespace AZ void StagingMemoryAllocator::GarbageCollect() { + AZ_ATOM_PROFILE_FUNCTION("DX12", "StagingMemoryAllocator: GarbageCollect"); m_mediumBlockAllocators.ForEach([](MemoryLinearSubAllocator& subAllocator) { subAllocator.GarbageCollect(); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h index d93f7acc85..fa1bb57166 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h @@ -145,7 +145,7 @@ namespace AZ // ShaderReloadNotificationBus overrides... void OnShaderReinitialized(const Shader& shader) override; void OnShaderAssetReinitialized(const Data::Asset& shaderAsset) override; - void OnShaderVariantReinitialized(const Shader& shader, const ShaderVariantId& shaderVariantId, ShaderVariantStableId shaderVariantStableId) override; + void OnShaderVariantReinitialized(const ShaderVariant& shaderVariant) override; /////////////////////////////////////////////////////////////////// template diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/MaterialReloadNotificationBus.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/MaterialReloadNotificationBus.h index c28f6a3233..881b40b785 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/MaterialReloadNotificationBus.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/MaterialReloadNotificationBus.h @@ -24,6 +24,11 @@ namespace AZ //! Connect to this EBus to get notifications whenever material objects reload. //! The bus address is the AssetId of the MaterialAsset or MaterialTypeAsset. + //! + //! Be careful when using the parameters provided by these functions. The bus ID is an AssetId, and it's possible for the system to have + //! both *old* versions and *new reloaded* versions of the asset in memory at the same time, and they will have the same AssetId. Therefore + //! your bus Handlers could receive Reinitialized messages from multiple sources. It may be necessary to check the memory addresses of these + //! parameters against local members before using this data. class MaterialReloadNotifications : public EBusTraits { diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ComputePass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ComputePass.h index a4130deed1..450a9ce834 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ComputePass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ComputePass.h @@ -78,7 +78,7 @@ namespace AZ // ShaderReloadNotificationBus::Handler overrides... void OnShaderReinitialized(const Shader& shader) override; void OnShaderAssetReinitialized(const Data::Asset& shaderAsset) override; - void OnShaderVariantReinitialized(const Shader& shader, const ShaderVariantId& shaderVariantId, ShaderVariantStableId shaderVariantStableId) override; + void OnShaderVariantReinitialized(const ShaderVariant& shaderVariant) override; void LoadShader(); PassDescriptor m_passDescriptor; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/FullscreenTrianglePass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/FullscreenTrianglePass.h index 616fc4639a..e168a07f08 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/FullscreenTrianglePass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/FullscreenTrianglePass.h @@ -78,7 +78,7 @@ namespace AZ // ShaderReloadNotificationBus overrides... void OnShaderReinitialized(const Shader& shader) override; void OnShaderAssetReinitialized(const Data::Asset& shaderAsset) override; - void OnShaderVariantReinitialized(const Shader& shader, const ShaderVariantId& shaderVariantId, ShaderVariantStableId shaderVariantStableId) override; + void OnShaderVariantReinitialized(const ShaderVariant& shaderVariant) override; /////////////////////////////////////////////////////////////////// void LoadShader(); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/PipelineState.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/PipelineState.h index f0fa39d20f..815fc28cb6 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/PipelineState.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/PipelineState.h @@ -88,7 +88,7 @@ namespace AZ // ShaderReloadNotificationBus overrides... void OnShaderReinitialized(const AZ::RPI::Shader& shader) override; void OnShaderAssetReinitialized(const Data::Asset& shaderAsset) override; - void OnShaderVariantReinitialized(const Shader& shader, const ShaderVariantId& shaderVariantId, ShaderVariantStableId shaderVariantStableId) override; + void OnShaderVariantReinitialized(const ShaderVariant& shaderVariant) override; /////////////////////////////////////////////////////////////////// // Update shader variant from m_shader. It's called whenever shader, shader asset or shader variant were changed. diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderReloadNotificationBus.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderReloadNotificationBus.h index 58b9809e2b..8ea34187ff 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderReloadNotificationBus.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderReloadNotificationBus.h @@ -22,10 +22,16 @@ namespace AZ { class Shader; class ShaderAsset; + class ShaderVariant; /** - * Connect to this EBus to get notifications whenever a Data::Instance reloads its ShaderAsset. - * The bus address is the AssetId of the ShaderAsset. + * Connect to this EBus to get notifications whenever a shader system class reinitializes itself. + * The bus address is the AssetId of the ShaderAsset, even when the thing being reinitialized is a ShaderVariant or other shader related class. + * + * Be careful when using the parameters provided by these functions. The bus ID is an AssetId, and it's possible for the system to have + * both *old* versions and *new reloaded* versions of the asset in memory at the same time, and they will have the same AssetId. Therefore + * your bus Handlers could receive Reinitialized messages from multiple sources. It may be necessary to check the memory addresses of these + * parameters against local members before using this data. */ class ShaderReloadNotifications : public EBusTraits @@ -35,7 +41,7 @@ namespace AZ ////////////////////////////////////////////////////////////////////////// // EBusTraits overrides static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; - typedef Data::AssetId BusIdType; + typedef Data::AssetId BusIdType; ////////////////////////////////////////////////////////////////////////// virtual ~ShaderReloadNotifications() {} @@ -47,7 +53,7 @@ namespace AZ virtual void OnShaderReinitialized(const Shader& shader) { AZ_UNUSED(shader); } //! Called when a particular shader variant is reinitialized. - virtual void OnShaderVariantReinitialized(const Shader& shader, const ShaderVariantId& shaderVariantId, ShaderVariantStableId shaderVariantStableId) { AZ_UNUSED(shader); AZ_UNUSED(shaderVariantId); AZ_UNUSED(shaderVariantStableId); } + virtual void OnShaderVariantReinitialized(const ShaderVariant& shaderVariant) { AZ_UNUSED(shaderVariant); } }; typedef EBus ShaderReloadNotificationBus; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderVariant.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderVariant.h index d189d26b13..7363ab4d1a 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderVariant.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderVariant.h @@ -23,10 +23,12 @@ namespace AZ //! the RHI::PipelineStateType of the parent Shader instance. For shaders on the raster //! pipeline, the RHI::DrawFilterTag is also provided. class ShaderVariant final + : public Data::AssetBus::MultiHandler { friend class Shader; public: ShaderVariant() = default; + virtual ~ShaderVariant(); AZ_DEFAULT_COPY_MOVE(ShaderVariant); //! Fills a pipeline state descriptor with settings provided by the ShaderVariant. (Note that @@ -54,12 +56,21 @@ namespace AZ bool IsRootVariant() const { return m_shaderVariantAsset->IsRootVariant(); } ShaderVariantStableId GetStableId() const { return m_shaderVariantAsset->GetStableId(); } + + const Data::Asset& GetShaderAsset() const { return m_shaderAsset; } + const Data::Asset& GetShaderVariantAsset() const { return m_shaderVariantAsset; } private: // Called by Shader. Initializes runtime data from asset data. Returns whether the call succeeded. bool Init( - const ShaderAsset& shaderAsset, - Data::Asset shaderVariantAsset); + const Data::Asset& shaderAsset, + const Data::Asset& shaderVariantAsset); + + // AssetBus overrides... + void OnAssetReloaded(Data::Asset asset) override; + + //! A reference to the shader asset that this is a variant of. + Data::Asset m_shaderAsset; // Cached state from the asset to avoid an indirection. RHI::PipelineStateType m_pipelineStateType = RHI::PipelineStateType::Count; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/GpuQuerySystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/GpuQuerySystem.cpp index 2c9c1faf4a..e6d7aa01c9 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/GpuQuerySystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/GpuQuerySystem.cpp @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -78,6 +79,7 @@ namespace AZ void GpuQuerySystem::Update() { + AZ_ATOM_PROFILE_FUNCTION("RPI", "GpuQuerySystem: Update"); for (auto& queryPool : m_queryPoolArray) { if (queryPool) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp index d9691ca175..3302190156 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp @@ -242,8 +242,16 @@ namespace AZ // MaterialReloadNotificationBus overrides... void Material::OnMaterialAssetReinitialized(const Data::Asset& materialAsset) { - ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Material::OnMaterialAssetReinitialized %s", this, materialAsset.GetHint().c_str()); - OnAssetReloaded(materialAsset); + // It's important that we don't just pass materialAsset to Init() because when reloads occur, + // it's possible for old Asset objects to hang around and report reinitialization, so materialAsset + // might be stale data. + + if (materialAsset.Get() == m_materialAsset.Get()) + { + ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Material::OnMaterialAssetReinitialized %s", this, materialAsset.GetHint().c_str()); + + OnAssetReloaded(m_materialAsset); + } } /////////////////////////////////////////////////////////////////// @@ -259,8 +267,6 @@ namespace AZ void Material::OnShaderAssetReinitialized(const Data::Asset& shaderAsset) { - // TODO: I think we should make Shader handle OnShaderAssetReinitialized and treat it just like the shader reloaded. - ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Material::OnShaderAssetReinitialized %s", this, shaderAsset.GetHint().c_str()); // Note that it might not be strictly necessary to reinitialize the entire material, we might be able to get away with // just bumping the m_currentChangeId or some other minor updates. But it's pretty hard to know what exactly needs to be @@ -268,9 +274,9 @@ namespace AZ OnAssetReloaded(m_materialAsset); } - void Material::OnShaderVariantReinitialized(const Shader& shader, const ShaderVariantId& /*shaderVariantId*/, ShaderVariantStableId shaderVariantStableId) + void Material::OnShaderVariantReinitialized(const ShaderVariant& shaderVariant) { - ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Material::OnShaderVariantReinitialized %s variant %u", this, shader.GetAsset().GetHint().c_str(), shaderVariantStableId.GetIndex()); + ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Material::OnShaderVariantReinitialized %s", this, shaderVariant.GetShaderVariantAsset().GetHint().c_str()); // Note that it would be better to check the shaderVariantId to see if that variant is relevant to this particular material before reinitializing it. // There could be hundreds or even thousands of variants for a shader, but only one of those variants will be used by any given material. So we could diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp index 5077ccaa51..5902c208c6 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp @@ -241,9 +241,8 @@ namespace AZ LoadShader(); } - void ComputePass::OnShaderVariantReinitialized(const Shader& shader, const ShaderVariantId& shaderVariantId, ShaderVariantStableId shaderVariantStableId) + void ComputePass::OnShaderVariantReinitialized(const ShaderVariant&) { - AZ_UNUSED(shader); AZ_UNUSED(shaderVariantId); AZ_UNUSED(shaderVariantStableId); LoadShader(); } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp index a854867998..aee4fc4f48 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp @@ -57,7 +57,7 @@ namespace AZ LoadShader(); } - void FullscreenTrianglePass::OnShaderVariantReinitialized(const Shader&, const ShaderVariantId&, ShaderVariantStableId) + void FullscreenTrianglePass::OnShaderVariantReinitialized(const ShaderVariant&) { LoadShader(); } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp index 3e52130f6f..fa10e1a454 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp @@ -61,6 +61,11 @@ namespace AZ { const PassAttachmentBinding& binding = m_attachmentBindings[slotIndex]; + if (!binding.m_attachment) + { + continue; + } + // Handle the depth-stencil attachment. There should be only one. if (binding.m_scopeAttachmentUsage == RHI::ScopeAttachmentUsage::DepthStencil) { @@ -98,6 +103,10 @@ namespace AZ { continue; } + if (!binding.m_attachment) + { + continue; + } if (binding.m_scopeAttachmentUsage == RHI::ScopeAttachmentUsage::RenderTarget || binding.m_scopeAttachmentUsage == RHI::ScopeAttachmentUsage::DepthStencil) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/PipelineState.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/PipelineState.cpp index 545e71e117..8b13817897 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/PipelineState.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/PipelineState.cpp @@ -124,12 +124,9 @@ namespace AZ RefreshShaderVariant(); } - void PipelineStateForDraw::OnShaderVariantReinitialized( - [[maybe_unused]] const Shader& shader, - const ShaderVariantId& shaderVariantId, - [[maybe_unused]] ShaderVariantStableId shaderVariantStableId) + void PipelineStateForDraw::OnShaderVariantReinitialized(const ShaderVariant& shaderVariant) { - if(shaderVariantId == m_shaderVariantId) + if(shaderVariant.GetShaderVariantId() == m_shaderVariantId) { RefreshShaderVariant(); } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp index 87b6f5d92e..1db209e17a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp @@ -282,24 +282,27 @@ namespace AZ m_rhiSystem.FrameUpdate( [this](RHI::FrameGraphBuilder& frameGraphBuilder) - { - // Pass system's frame update, which includes the logic of adding scope producers, has to be added here since the scope producers only can be added to the frame - // when frame started which cleans up previous scope producers. - m_passSystem.FrameUpdate(frameGraphBuilder); + { + // Pass system's frame update, which includes the logic of adding scope producers, has to be added here since the + // scope producers only can be added to the frame when frame started which cleans up previous scope producers. + m_passSystem.FrameUpdate(frameGraphBuilder); + + // Update View Srgs + for (auto& scenePtr : m_scenes) + { + scenePtr->UpdateSrgs(); + } + }); + + { + AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "RPISystem: FrameEnd"); + m_dynamicDraw.FrameEnd(); + m_passSystem.FrameEnd(); - // Update View Srgs for (auto& scenePtr : m_scenes) { - scenePtr->UpdateSrgs(); + scenePtr->OnFrameEnd(); } - }); - - m_dynamicDraw.FrameEnd(); - m_passSystem.FrameEnd(); - - for (auto& scenePtr : m_scenes) - { - scenePtr->OnFrameEnd(); } m_renderTick++; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index 62efc3dccb..2ecbdde417 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -404,6 +404,7 @@ namespace AZ { AZ_PROFILE_SCOPE(Debug::ProfileCategory::AzRender, "WaitForSimulationCompletion"); + AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "WaitForSimulationCompletion"); WaitAndCleanCompletionJob(m_simulationCompletion); } @@ -420,12 +421,15 @@ namespace AZ // Get active pipelines which need to be rendered and notify them frame started AZStd::vector activePipelines; - for (auto& pipeline : m_pipelines) { - if (pipeline->NeedsRender()) + AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "OnStartFrame"); + for (auto& pipeline : m_pipelines) { - activePipelines.push_back(pipeline); - pipeline->OnStartFrame(tickInfo); + if (pipeline->NeedsRender()) + { + activePipelines.push_back(pipeline); + pipeline->OnStartFrame(tickInfo); + } } } @@ -444,7 +448,7 @@ namespace AZ { - AZ_PROFILE_SCOPE(Debug::ProfileCategory::AzRender, "Setup Views"); + AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "Setup Views"); // Collect persistent views from all pipelines to be rendered AZStd::map persistentViews; @@ -490,7 +494,6 @@ namespace AZ { const auto renderLambda = [this, &fp]() { - AZ_PROFILE_SCOPE_DYNAMIC(Debug::ProfileCategory::AzRender, "renderJob - fp:%s", fp->RTTI_GetTypeName()); fp->Render(m_renderPacket); }; @@ -526,12 +529,14 @@ namespace AZ // Add dynamic draw data for all the views if (m_dynamicDrawSystem) { + AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "DynamicDraw SubmitDrawData"); m_dynamicDrawSystem->SubmitDrawData(this, m_renderPacket.m_views); } } { AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::AzRender, "FinalizeDrawLists"); + AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "FinalizeDrawLists"); if (jobPolicy == RHI::JobPolicy::Serial) { for (auto& view : m_renderPacket.m_views) @@ -542,7 +547,6 @@ namespace AZ else { AZ::JobCompletion* finalizeDrawListsCompletion = aznew AZ::JobCompletion(); - AZ_PROFILE_EVENT_BEGIN(Debug::ProfileCategory::AzRender, "StartFinalizeDrawListsJobs"); for (auto& view : m_renderPacket.m_views) { const auto finalizeDrawListsLambda = [view]() @@ -559,11 +563,15 @@ namespace AZ } } - SceneNotificationBus::Event(GetId(), &SceneNotification::OnEndPrepareRender); + { + AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "Scene OnEndPrepareRender"); + SceneNotificationBus::Event(GetId(), &SceneNotification::OnEndPrepareRender); + } } void Scene::OnFrameEnd() { + AZ_ATOM_PROFILE_FUNCTION("RPI", "Scene: OnFrameEnd"); for (auto& pipeline : m_pipelines) { if (pipeline->NeedsRender()) @@ -702,6 +710,7 @@ namespace AZ void Scene::RebuildPipelineStatesLookup() { + AZ_ATOM_PROFILE_FUNCTION("RPI", "Scene: RebuildPipelineStatesLookup"); m_pipelineStatesLookup.clear(); AZStd::queue parents; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp index 3a79f32b05..f451064450 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp @@ -68,7 +68,7 @@ namespace AZ AZStd::unique_lock lock(m_variantCacheMutex); m_shaderVariants.clear(); } - m_rootVariant.Init(shaderAsset, shaderAsset.GetRootVariant()); + m_rootVariant.Init(Data::Asset{&shaderAsset, AZ::Data::AssetLoadBehavior::PreLoad}, shaderAsset.GetRootVariant()); if (m_pipelineLibraryHandle.IsNull()) { @@ -154,7 +154,14 @@ namespace AZ { AZ_Assert(shaderVariantAsset, "Reloaded ShaderVariantAsset is null"); const ShaderVariantStableId stableId = shaderVariantAsset->GetStableId(); - const ShaderVariantId& shaderVariantId = shaderVariantAsset->GetShaderVariantId(); + + // We make a copy of the updated variant because OnShaderVariantReinitialized must not be called inside + // m_variantCacheMutex or deadlocks may occur. + // Or if there is an error, we leave this object in its default state to indicate there was an error. + // [GFX TODO] We really should have a dedicated message/event for this, but that will be covered by a future task where + // we will merge ShaderReloadNotificationBus messages into one. For now, we just indicate the error by passing an empty ShaderVariant, + // all our call sites don't use this data anyway. + ShaderVariant updatedVariant; if (isError) { @@ -165,7 +172,7 @@ namespace AZ return; } AZStd::unique_lock lock(m_variantCacheMutex); - m_shaderVariants.erase(stableId); + m_shaderVariants.erase(stableId); } else { @@ -178,23 +185,26 @@ namespace AZ { ShaderVariant& shaderVariant = iter->second; - if (!shaderVariant.Init(*m_asset.Get(), shaderVariantAsset)) + if (!shaderVariant.Init(m_asset, shaderVariantAsset)) { AZ_Error("Shader", false, "Failed to init shaderVariant with StableId=%u", shaderVariantAsset->GetStableId()); m_shaderVariants.erase(stableId); } + else + { + updatedVariant = shaderVariant; + } } else { //This is the first time the shader variant asset comes to life. - ShaderVariant newVariant; - newVariant.Init(*m_asset, shaderVariantAsset); - m_shaderVariants.emplace(stableId, newVariant); + updatedVariant.Init(m_asset, shaderVariantAsset); + m_shaderVariants.emplace(stableId, updatedVariant); } } - //Even if there was an error, the interested parties should be notified. - ShaderReloadNotificationBus::Event(m_asset.GetId(), &ShaderReloadNotificationBus::Events::OnShaderVariantReinitialized, *this, shaderVariantId, stableId); + // [GFX TODO] It might make more sense to call OnShaderReinitialized here + ShaderReloadNotificationBus::Event(m_asset.GetId(), &ShaderReloadNotificationBus::Events::OnShaderVariantReinitialized, updatedVariant); } /////////////////////////////////////////////////////////////////// @@ -203,10 +213,15 @@ namespace AZ // ShaderReloadNotificationBus overrides... void Shader::OnShaderAssetReinitialized(const Data::Asset& shaderAsset) { - ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Shader::OnShaderAssetReinitialized %s", this, shaderAsset.GetHint().c_str()); + // When reloads occur, it's possible for old Asset objects to hang around and report reinitialization, + // so we can reduce unnecessary reinitialization in that case. + if (shaderAsset.Get() == m_asset.Get()) + { + ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Shader::OnShaderAssetReinitialized %s", this, shaderAsset.GetHint().c_str()); - Init(*m_asset.Get()); - ShaderReloadNotificationBus::Event(shaderAsset.GetId(), &ShaderReloadNotificationBus::Events::OnShaderReinitialized, *this); + Init(*m_asset.Get()); + ShaderReloadNotificationBus::Event(shaderAsset.GetId(), &ShaderReloadNotificationBus::Events::OnShaderReinitialized, *this); + } } /////////////////////////////////////////////////////////////////// @@ -340,7 +355,7 @@ namespace AZ } ShaderVariant newVariant; - newVariant.Init(*m_asset, shaderVariantAsset); + newVariant.Init(m_asset, shaderVariantAsset); m_shaderVariants.emplace(shaderVariantStableId, newVariant); return m_shaderVariants.at(shaderVariantStableId); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariant.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariant.cpp index 4d50f10c9c..acd9922b68 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariant.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariant.cpp @@ -9,11 +9,13 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ + #include +#include +#include #include #include - #include namespace AZ @@ -21,15 +23,26 @@ namespace AZ namespace RPI { bool ShaderVariant::Init( - const ShaderAsset& shaderAsset, - Data::Asset shaderVariantAsset) - { - m_pipelineStateType = shaderAsset.GetPipelineStateType(); - m_pipelineLayoutDescriptor = shaderAsset.GetPipelineLayoutDescriptor(); + const Data::Asset& shaderAsset, + const Data::Asset& shaderVariantAsset) + { + Data::AssetBus::MultiHandler::BusDisconnect(); + Data::AssetBus::MultiHandler::BusConnect(shaderAsset.GetId()); + Data::AssetBus::MultiHandler::BusConnect(shaderVariantAsset.GetId()); + + m_shaderAsset = shaderAsset; + m_pipelineStateType = shaderAsset->GetPipelineStateType(); + m_pipelineLayoutDescriptor = shaderAsset->GetPipelineLayoutDescriptor(); m_shaderVariantAsset = shaderVariantAsset; + return true; } + ShaderVariant::~ShaderVariant() + { + Data::AssetBus::MultiHandler::BusDisconnect(); + } + void ShaderVariant::ConfigurePipelineState(RHI::PipelineStateDescriptor& descriptor) const { descriptor.m_pipelineLayoutDescriptor = m_pipelineLayoutDescriptor; @@ -78,5 +91,25 @@ namespace AZ { return m_shaderVariantAsset->GetOutputContract(); } + + void ShaderVariant::OnAssetReloaded(Data::Asset asset) + { + ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->ShaderVariant::OnAssetReloaded %s", this, asset.GetHint().c_str()); + + if (asset.GetAs()) + { + Data::Asset shaderVariantAsset = { asset.GetAs(), AZ::Data::AssetLoadBehavior::PreLoad }; + Init(m_shaderAsset, shaderVariantAsset); + ShaderReloadNotificationBus::Event(m_shaderAsset.GetId(), &ShaderReloadNotificationBus::Events::OnShaderVariantReinitialized, *this); + } + + if (asset.GetAs()) + { + Data::Asset shaderAsset = { asset.GetAs(), AZ::Data::AssetLoadBehavior::PreLoad }; + Init(shaderAsset, m_shaderVariantAsset); + ShaderReloadNotificationBus::Event(m_shaderAsset.GetId(), &ShaderReloadNotificationBus::Events::OnShaderVariantReinitialized, *this); + } + } + } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariantAsyncLoader.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariantAsyncLoader.cpp index 3fc2bbd197..24f6fa60fa 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariantAsyncLoader.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariantAsyncLoader.cpp @@ -323,9 +323,8 @@ namespace AZ void ShaderVariantAsyncLoader::Reset() { - // [GFX TODO ATOM-14544] Idealy we want to be able to reset the ShaderVariantAsyncLoader but this is causing some problems that need to be worked out first. - //Shutdown(); - //Init(); + Shutdown(); + Init(); } /////////////////////////////////////////////////////////////////// diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp index b8567b12c5..7446c498cd 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp @@ -115,12 +115,19 @@ namespace AZ } } - void MaterialAsset::OnMaterialTypeAssetReinitialized(const Data::Asset&) + void MaterialAsset::OnMaterialTypeAssetReinitialized(const Data::Asset& materialTypeAsset) { - // MaterialAsset doesn't need to reinitialize any of its own data when MaterialTypeAsset reinitializes, - // because all it depends on is the MaterialTypeAsset reference, rather than the data inside it. - // Ultimately it's the Material that cares about these changes, so we just forward any signal we get. - MaterialReloadNotificationBus::Event(GetId(), &MaterialReloadNotifications::OnMaterialAssetReinitialized, Data::Asset{this, AZ::Data::AssetLoadBehavior::PreLoad}); + // When reloads occur, it's possible for old Asset objects to hang around and report reinitialization, + // so we can reduce unnecessary reinitialization in that case. + if (materialTypeAsset.Get() == m_materialTypeAsset.Get()) + { + ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->MaterialAsset::OnMaterialTypeAssetReinitialized %s", this, materialTypeAsset.GetHint().c_str()); + + // MaterialAsset doesn't need to reinitialize any of its own data when MaterialTypeAsset reinitializes, + // because all it depends on is the MaterialTypeAsset reference, rather than the data inside it. + // Ultimately it's the Material that cares about these changes, so we just forward any signal we get. + MaterialReloadNotificationBus::Event(GetId(), &MaterialReloadNotifications::OnMaterialAssetReinitialized, Data::Asset{this, AZ::Data::AssetLoadBehavior::PreLoad}); + } } void MaterialAsset::ReinitializeMaterialTypeAsset(Data::Asset asset) diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h index 4c9ddbe50a..a9ed5b7008 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h @@ -13,6 +13,7 @@ #pragma once #include +#include namespace AZ { @@ -56,6 +57,16 @@ namespace AZ ImGuiTextFilter m_timedRegionFilter; GroupRegionMap m_groupRegionMap; + + // Pause cpu profiling. The profiler will show the statistics of the last frame before pause + bool m_paused = false; + + // Total frames need to be saved + int m_captureFrameCount = 1; + + AZ::RHI::CpuTimingStatistics m_cpuTimingStatisticsWhenPause; + + AZStd::string m_lastCapturedFilePath; }; } // namespace Render } diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl index 7a453b4597..50ef1a8e66 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl @@ -10,7 +10,10 @@ * */ -#include +#include +#include +#include // For AZ_MAX_PATH_LEN +#include namespace AZ { @@ -34,16 +37,42 @@ namespace AZ } } - inline void ImGuiCpuProfiler::Draw(bool& keepDrawing, const AZ::RHI::CpuTimingStatistics& cpuTimingStatistics) + inline void ImGuiCpuProfiler::Draw(bool& keepDrawing, const AZ::RHI::CpuTimingStatistics& currentCpuTimingStatistics) { // Cache the value to detect if it was changed by ImGui(user pressed 'x') const bool cachedShowCpuProfiler = keepDrawing; const ImVec2 windowSize(640.0f, 480.0f); ImGui::SetNextWindowSize(windowSize, ImGuiCond_Once); + bool captureToFile = false; if (ImGui::Begin("Cpu Profiler", &keepDrawing, ImGuiWindowFlags_None)) { - UpdateGroupRegionMap(); + m_paused = !AZ::RHI::CpuProfiler::Get()->IsProfilerEnabled(); + if (ImGui::Button(m_paused?"Resume":"Pause")) + { + m_paused = !m_paused; + AZ::RHI::CpuProfiler::Get()->SetProfilerEnabled(!m_paused); + } + + // Update region map and cache the input cpu timing statistics when the profiling is not paused + if (!m_paused) + { + UpdateGroupRegionMap(); + m_cpuTimingStatisticsWhenPause = currentCpuTimingStatistics; + } + + if (ImGui::Button("Capture")) + { + captureToFile = true; + } + + if (!m_lastCapturedFilePath.empty()) + { + ImGui::SameLine(); + ImGui::Text(m_lastCapturedFilePath.c_str()); + } + + const AZ::RHI::CpuTimingStatistics& cpuTimingStatistics = m_cpuTimingStatisticsWhenPause; const AZStd::sys_time_t ticksPerSecond = AZStd::GetTimeTicksPerSecond(); @@ -51,7 +80,7 @@ namespace AZ { // Note: converting to microseconds integer before converting to milliseconds float const float timeInMs = static_cast((duration * 1000) / (ticksPerSecond / 1000)) / 1000.0f; - ImGui::Text("%.1f ms", timeInMs); + ImGui::Text("%.2f ms", timeInMs); }; const auto ShowRow = [ticksPerSecond, &ShowTimeInMs](const char* regionLabel, AZStd::sys_time_t duration) @@ -158,6 +187,20 @@ namespace AZ } ImGui::End(); + if (captureToFile) + { + AZStd::sys_time_t timeNow = AZStd::GetTimeNowSecond(); + AZStd::string timeString; + AZStd::to_string(timeString, timeNow); + u64 currentTick = AZ::RPI::RPISystemInterface::Get()->GetCurrentTick(); + AZStd::string frameDataFilePath = AZStd::string::format("@user@/CpuProfiler/%s_%llu.json", timeString.c_str(), currentTick); + char resolvedPath[AZ_MAX_PATH_LEN]; + AZ::IO::FileIOBase::GetInstance()->ResolvePath(frameDataFilePath.c_str(), resolvedPath, AZ_MAX_PATH_LEN); + m_lastCapturedFilePath = resolvedPath; + AZ::Render::ProfilingCaptureRequestBus::Broadcast(&AZ::Render::ProfilingCaptureRequestBus::Events::CaptureCpuProfilingStatistics, + frameDataFilePath); + } + // Toggle if the bool isn't the same as the cached value if (cachedShowCpuProfiler != keepDrawing) { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h index f4cb319c2f..9279326333 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h @@ -143,6 +143,13 @@ namespace AZ //! Sets the type of Pcf (percentage-closer filtering) to use. virtual void SetPcfMethod(PcfMethod method) = 0; + + //! Gets the Esm exponent. Higher values produce a steeper falloff between light and shadow. + virtual float GetEsmExponent() const = 0; + + //! Sets the Esm exponent. Higher values produce a steeper falloff between light and shadow. + virtual void SetEsmExponent(float exponent) = 0; + }; //! The EBus for requests to for setting and getting light component properties. diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h index 31cdb34ddd..e003d6a178 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h @@ -66,6 +66,7 @@ namespace AZ float m_boundaryWidthInDegrees = 0.25f; uint16_t m_predictionSampleCount = 4; uint16_t m_filteringSampleCount = 12; + float m_esmExponent = 87.0f; // The following functions provide information to an EditContext... @@ -124,6 +125,8 @@ namespace AZ //! Returns true if pcf boundary search is disabled. bool IsPcfBoundarySearchDisabled() const; + //! Returns true if exponential shadow maps are disabled. + bool IsEsmDisabled() const; }; } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp index 8f10204ae9..c9211e87a0 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp @@ -21,7 +21,7 @@ namespace AZ if (auto serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(5) // ATOM-14637 + ->Version(6) // ATOM-15654 ->Field("LightType", &AreaLightComponentConfig::m_lightType) ->Field("Color", &AreaLightComponentConfig::m_color) ->Field("IntensityMode", &AreaLightComponentConfig::m_intensityMode) @@ -41,7 +41,8 @@ namespace AZ ->Field("Softening Boundary Width", &AreaLightComponentConfig::m_boundaryWidthInDegrees) ->Field("Prediction Sample Count", &AreaLightComponentConfig::m_predictionSampleCount) ->Field("Filtering Sample Count", &AreaLightComponentConfig::m_filteringSampleCount) - ->Field("Pcf Method", &AreaLightComponentConfig::m_pcfMethod); + ->Field("Pcf Method", &AreaLightComponentConfig::m_pcfMethod) + ->Field("Esm Exponent", &AreaLightComponentConfig::m_esmExponent) ; } } @@ -200,5 +201,11 @@ namespace AZ return m_pcfMethod != PcfMethod::BoundarySearch; } + + bool AreaLightComponentConfig::IsEsmDisabled() const + { + return !(m_shadowFilterMethod == ShadowFilterMethod::Esm || m_shadowFilterMethod == ShadowFilterMethod::EsmPcf); + } + } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp index c1c957ed4c..f7e0d15c92 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp @@ -84,7 +84,9 @@ namespace AZ::Render ->Event("SetFilteringSampleCount", &AreaLightRequestBus::Events::SetFilteringSampleCount) ->Event("GetPcfMethod", &AreaLightRequestBus::Events::GetPcfMethod) ->Event("SetPcfMethod", &AreaLightRequestBus::Events::SetPcfMethod) - + ->Event("GetEsmExponent", &AreaLightRequestBus::Events::GetEsmExponent) + ->Event("SetEsmExponent", &AreaLightRequestBus::Events::SetEsmExponent) + ->VirtualProperty("AttenuationRadius", "GetAttenuationRadius", "SetAttenuationRadius") ->VirtualProperty("Color", "GetColor", "SetColor") ->VirtualProperty("EmitsLightBothDirections", "GetEmitsLightBothDirections", "SetEmitsLightBothDirections") @@ -101,8 +103,9 @@ namespace AZ::Render ->VirtualProperty("SofteningBoundaryWidthAngle", "GetSofteningBoundaryWidthAngle", "SetSofteningBoundaryWidthAngle") ->VirtualProperty("PredictionSampleCount", "GetPredictionSampleCount", "SetPredictionSampleCount") ->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount") - ->VirtualProperty("PcfMethod", "GetPcfMethod", "SetPcfMethod"); - ; + ->VirtualProperty("PcfMethod", "GetPcfMethod", "SetPcfMethod") + ->VirtualProperty("EsmExponent", "GetEsmExponent", "SetEsmExponent"); + ; } } @@ -314,6 +317,7 @@ namespace AZ::Render m_lightShapeDelegate->SetPredictionSampleCount(m_configuration.m_predictionSampleCount); m_lightShapeDelegate->SetFilteringSampleCount(m_configuration.m_filteringSampleCount); m_lightShapeDelegate->SetPcfMethod(m_configuration.m_pcfMethod); + m_lightShapeDelegate->SetEsmExponent(m_configuration.m_esmExponent); } } } @@ -565,6 +569,20 @@ namespace AZ::Render } } + float AreaLightComponentController::GetEsmExponent() const + { + return m_configuration.m_esmExponent; + } + + void AreaLightComponentController::SetEsmExponent(float esmExponent) + { + m_configuration.m_esmExponent = esmExponent; + if (m_lightShapeDelegate) + { + m_lightShapeDelegate->SetEsmExponent(esmExponent); + } + } + void AreaLightComponentController::CreateLightShapeDelegate() { switch (m_configuration.m_lightType) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h index b5f342a522..a65f0be45f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h @@ -92,6 +92,8 @@ namespace AZ void SetFilteringSampleCount(uint32_t count) override; PcfMethod GetPcfMethod() const override; void SetPcfMethod(PcfMethod method) override; + float GetEsmExponent() const override; + void SetEsmExponent(float exponent) override; void HandleDisplayEntityViewport( const AzFramework::ViewportInfo& viewportInfo, diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp index 8abc790ada..b8b82bc8bb 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp @@ -175,5 +175,13 @@ namespace AZ::Render } } + void DiskLightDelegate::SetEsmExponent(float exponent) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetEsmExponent(GetLightHandle(), exponent); + } + } + } // namespace AZ::Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h index 5511b435d4..3e2704fd61 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h @@ -51,6 +51,7 @@ namespace AZ void SetPredictionSampleCount(uint32_t count) override; void SetFilteringSampleCount(uint32_t count) override; void SetPcfMethod(PcfMethod method) override; + void SetEsmExponent(float exponent) override; private: diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp index 992b6319d8..91a909e809 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp @@ -179,8 +179,19 @@ namespace AZ ->EnumAttribute(PcfMethod::BoundarySearch, "Boundary search") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) - ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsShadowPcfDisabled); - ; + ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsShadowPcfDisabled) + ->DataElement( + Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_esmExponent, "Esm Exponent", + "Exponent used by Esm shadows. " + "Larger values increase the sharpness of the border between lit and unlit areas.") + ->Attribute(Edit::Attributes::Min, 50.0f) + ->Attribute(Edit::Attributes::Max, 5000.0f) + ->Attribute(AZ::Edit::Attributes::Decimals, 0) + ->Attribute(AZ::Edit::Attributes::SliderCurveMidpoint, 0.05f) + ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) + ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsEsmDisabled) + ; } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h index da221341c3..d106a13c07 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h @@ -63,6 +63,7 @@ namespace AZ void SetPredictionSampleCount([[maybe_unused]] uint32_t count) override {}; void SetFilteringSampleCount([[maybe_unused]] uint32_t count) override {}; void SetPcfMethod([[maybe_unused]] PcfMethod method) override {}; + void SetEsmExponent([[maybe_unused]] float esmExponent) override{}; protected: void InitBase(EntityId entityId); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h index b3f5fb6014..3ebf3802fa 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h @@ -85,6 +85,8 @@ namespace AZ virtual void SetFilteringSampleCount(uint32_t count) = 0; //! Sets the Pcf (Percentage closer filtering) method to use. virtual void SetPcfMethod(PcfMethod method) = 0; + //! Sets the Esm exponent to use. Higher values produce a steeper falloff between light and shadow. + virtual void SetEsmExponent(float exponent) = 0; }; } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp index afb63dce9b..e701e3c22a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp @@ -122,5 +122,14 @@ namespace AZ } } + void SphereLightDelegate::SetEsmExponent(float esmExponent) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetEsmExponent(GetLightHandle(), esmExponent); + } + } + + } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h index 178540fd01..f964254d76 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h @@ -41,6 +41,7 @@ namespace AZ void SetPredictionSampleCount(uint32_t count) override; void SetFilteringSampleCount(uint32_t count) override; void SetPcfMethod(PcfMethod method) override; + void SetEsmExponent(float esmExponent) override; private: diff --git a/Gems/Blast/Code/Source/Components/BlastFamilyComponent.cpp b/Gems/Blast/Code/Source/Components/BlastFamilyComponent.cpp index 1da9663b8f..bf1f3bc5af 100644 --- a/Gems/Blast/Code/Source/Components/BlastFamilyComponent.cpp +++ b/Gems/Blast/Code/Source/Components/BlastFamilyComponent.cpp @@ -286,9 +286,13 @@ namespace Blast // Create damage and actor render managers m_damageManager = AZStd::make_unique(blastMaterial, m_family->GetActorTracker()); - m_actorRenderManager = AZStd::make_unique( - AZ::RPI::Scene::GetFeatureProcessorForEntity(GetEntityId()), - m_meshDataComponent, GetEntityId(), m_blastAsset->GetPxAsset()->getChunkCount(), AZ::Vector3(transform.GetUniformScale())); + + if (m_meshDataComponent) + { + m_actorRenderManager = AZStd::make_unique( + AZ::RPI::Scene::GetFeatureProcessorForEntity(GetEntityId()), + m_meshDataComponent, GetEntityId(), m_blastAsset->GetPxAsset()->getChunkCount(), AZ::Vector3(transform.GetUniformScale())); + } // Spawn the family m_family->Spawn(transform); @@ -540,7 +544,11 @@ namespace Blast void BlastFamilyComponent::OnActorCreated([[maybe_unused]] const BlastFamily& family, const BlastActor& actor) { - m_actorRenderManager->OnActorCreated(actor); + if (m_actorRenderManager) + { + m_actorRenderManager->OnActorCreated(actor); + } + m_solver->notifyActorCreated(*actor.GetTkActor().getActorLL()); if (auto* physicsSystem = AZ::Interface::Get()) @@ -576,7 +584,11 @@ namespace Blast } m_solver->notifyActorDestroyed(*actor.GetTkActor().getActorLL()); - m_actorRenderManager->OnActorDestroyed(actor); + + if (m_actorRenderManager) + { + m_actorRenderManager->OnActorDestroyed(actor); + } } // Update positions of entities with render meshes corresponding to their right dynamic bodies. diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index 21bf6ab69b..92ad524711 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -826,7 +826,7 @@ enum class NetworkProperties #} {% macro DefineNetworkPropertyBehaviorReflection(Component, ReplicateFrom, ReplicateTo, ClassName) %} {% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, ReplicateFrom, ReplicateTo) %} -{% if (Property.attrib['IsPublic'] | booleanTrue == true) and (Property.attrib['GenerateEventBindings'] | booleanTrue == true) -%} +{% if (Property.attrib['IsPublic'] | booleanTrue == true) and (Property.attrib['ExposeToScript'] | booleanTrue == true) -%} // {{ UpperFirst(Property.attrib['Name']) }}: Replicate from {{ ReplicateFrom }} to {{ ReplicateTo }} {% if Property.attrib['Container'] == 'Vector' or Property.attrib['Container'] == 'Array' %} ->Method("Get{{ UpperFirst(Property.attrib['Name']) }}", [](AZ::EntityId id, int32_t index) -> {{ Property.attrib['Type'] }} diff --git a/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml b/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml index b6edd0e3be..0c799a7b3f 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml +++ b/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml @@ -17,7 +17,7 @@ - + diff --git a/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml b/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml index a112cde4e6..8abc874aa6 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml +++ b/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml @@ -12,12 +12,12 @@ - - - - - - + + + + + +