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

This commit is contained in:
dmcdiar
2021-09-15 18:22:38 -07:00
1231 changed files with 51892 additions and 50685 deletions
@@ -0,0 +1,17 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef AZ_COLLECTING_PARTIAL_SRGS
#error Do not include this file directly. Include the main .srgi file instead.
#endif
partial ShaderResourceGroup SceneSrg
{
float m_time;
}
@@ -20,6 +20,10 @@ namespace AZ
{
namespace JsonUtils
{
//! Protects from allocating too much memory. The choice of a 1MB threshold is arbitrary.
//! If you need to work with larger files, please use AZ::IO directly instead of these utility functions.
inline constexpr size_t DefaultMaxFileSize = 1024 * 1024;
// Declarations...
//! Loads serialized object data from a json file at the specified path
@@ -39,7 +43,7 @@ namespace AZ
{
objectData = ObjectType();
auto loadOutcome = AZ::JsonSerializationUtils::ReadJsonFile(path);
auto loadOutcome = AZ::JsonSerializationUtils::ReadJsonFile(path, DefaultMaxFileSize);
if (!loadOutcome.IsSuccess())
{
AZ_Error("AZ::RPI::JsonUtils", false, "%s", loadOutcome.GetError().c_str());
@@ -74,6 +74,7 @@ namespace AZ
MaterialPropertyIndex FindPropertyIndex(const Name& name) const;
//! Sets the value of a material property. The template data type must match the property's data type.
//! @return true if property value was changed
template<typename Type>
bool SetPropertyValue(MaterialPropertyIndex index, const Type& value);
@@ -81,12 +82,15 @@ namespace AZ
template<typename Type>
const Type& GetPropertyValue(MaterialPropertyIndex index) const;
//! Gets flags indicating which properties have been modified.
const MaterialPropertyFlags& GetPropertyDirtyFlags() const;
//! Sets the value of a material property. The @value data type must match the property's data type.
//! @return true if property value was changed
bool SetPropertyValue(MaterialPropertyIndex index, const MaterialPropertyValue& value);
const MaterialPropertyValue& GetPropertyValue(MaterialPropertyIndex index) const;
const AZStd::vector<MaterialPropertyValue>& GetPropertyValues() const;
//! Gets flags indicating which properties have been modified.
const MaterialPropertyFlags& GetPropertyDirtyFlags() const;
//! Gets the material properties layout.
RHI::ConstPtr<MaterialPropertiesLayout> GetMaterialPropertiesLayout() const;
@@ -111,6 +115,12 @@ namespace AZ
//! @param return the number of shader options that were updated, or Failure if the material owns the indicated shader option.
AZ::Outcome<uint32_t> SetSystemShaderOption(const Name& shaderOptionName, RPI::ShaderOptionValue value);
//! Override the material's default PSO handling setting.
//! This is normally used in tools like Asset Processor or Material Editor to allow changes that impact
//! Pipeline State Objects which is not allowed at runtime. See MaterialPropertyPsoHandling for more details.
//! Do not set this in the shipping runtime unless you know what you are doing.
void SetPsoHandlingOverride(MaterialPropertyPsoHandling psoHandlingOverride);
const RHI::ShaderResourceGroup* GetRHIShaderResourceGroup() const;
const Data::Asset<MaterialAsset>& GetAsset() const;
@@ -189,6 +199,10 @@ namespace AZ
//! Records the m_currentChangeId when the material was last compiled.
ChangeId m_compiledChangeId = DEFAULT_CHANGE_ID;
bool m_isInitializing = false;
MaterialPropertyPsoHandling m_psoHandling = MaterialPropertyPsoHandling::Warning;
};
} // namespace RPI
@@ -53,6 +53,8 @@ namespace AZ
//! Construct filter with only pass name.
PassHierarchyFilter(const Name& passName);
virtual ~PassHierarchyFilter() = default;
//! Construct filter with pass name and its parents' names in the order of the hierarchy
//! This means k-th element is always an ancestor of the (k-1)-th element.
//! And the last element is the pass name.
@@ -161,19 +161,25 @@ namespace AZ
//! Add this RenderPipeline to RPI system's RenderTick and it will be rendered whenever
//! the RPI system's RenderTick is called.
//! The RenderPipeline is rendered per RenderTick by default unless AddToRenderTickOnce() was called.
//! The RenderPipeline is rendered per RenderTick by default.
void AddToRenderTick();
//! Add this RenderPipeline to RPI system's RenderTick and it will be rendered every RenderTick
//! after the specified interval has elapsed since the last rendered frame.
//! @param renderInterval The desired time between rendered frames, in seconds.
void AddToRenderTickAtInterval(AZStd::chrono::duration<float> renderInterval);
//! Disable render for this RenderPipeline
void RemoveFromRenderTick();
~RenderPipeline();
enum class RenderMode : uint8_t
{
RenderEveryTick, // Render at each RPI system render tick
RenderOnce, // Render once in next RPI system render tick
NoRender // Render disabled.
RenderEveryTick, //!< Render at each RPI system render tick.
RenderAtTargetRate, //!< Render on RPI system render tick after a target refresh rate interval has passed.
RenderOnce, //!< Render once in next RPI system render tick.
NoRender //!< Render disabled.
};
//! Get current render mode
@@ -185,6 +191,12 @@ namespace AZ
//! Get draw filter mask
RHI::DrawFilterMask GetDrawFilterMask() const;
using FrameNotificationEvent = AZ::Event<>;
//! Notifies a listener when a frame is about to be prepared for render, before SRGs are bound.
void ConnectPrepareFrameHandler(FrameNotificationEvent::Handler& handler);
//! Notifies a listener when the rendering of a frame has finished
void ConnectEndFrameHandler(FrameNotificationEvent::Handler& handler);
private:
RenderPipeline() = default;
@@ -202,8 +214,11 @@ namespace AZ
void OnAddedToScene(Scene* scene);
void OnRemovedFromScene(Scene* scene);
// Called before this pipeline is about to be rendered and before SRGs are bound.
void OnPrepareFrame();
// Called when this pipeline is about to be rendered
void OnStartFrame(const TickTimeInfo& tick);
void OnStartFrame();
// Called when the rendering of current frame is finished.
void OnFrameEnd();
@@ -228,8 +243,14 @@ namespace AZ
PipelineViewMap m_pipelineViewsByTag;
/// The system time when the last time this pipeline render was started
float m_lastRenderStartTime = 0;
// The system time when the last time this pipeline render was started
AZStd::chrono::system_clock::time_point m_lastRenderStartTime;
// The current system time, as of OnPrepareFrame's execution.
AZStd::chrono::system_clock::time_point m_lastRenderRequestTime;
// The target time between renders when m_renderMode is RenderMode::RenderAtTargetRate
AZStd::chrono::duration<float> m_targetRefreshRate;
// RenderPipeline's name id, it will be used to identify the render pipeline when it's added to a Scene
RenderPipelineId m_nameId;
@@ -259,7 +280,11 @@ namespace AZ
RHI::DrawFilterTag m_drawFilterTag;
// A mask to filter draw items submitted by passes of this render pipeline.
// This mask is created from the value of m_drawFilterTag.
RHI::DrawFilterMask m_drawFilterMask = 0;
RHI::DrawFilterMask m_drawFilterMask = 0;
// Events for notification on render state
FrameNotificationEvent m_prepareFrameEvent;
FrameNotificationEvent m_endFrameEvent;
};
} // namespace RPI
@@ -129,10 +129,6 @@ namespace AZ
void RemoveRenderPipeline(const RenderPipelineId& pipelineId);
//! Set a callback function to set values for scene's srg.
//! The callback function is usually defined by the one who create the scene since it knows how the layout look like.
void SetShaderResourceGroupCallback(ShaderResourceGroupCallback callback);
const RHI::ShaderResourceGroup* GetRHIShaderResourceGroup() const;
Data::Instance<ShaderResourceGroup> GetShaderResourceGroup() const;
@@ -166,9 +162,13 @@ namespace AZ
RenderPipelinePtr FindRenderPipelineForWindow(AzFramework::NativeWindowHandle windowHandle);
using PrepareSceneSrgEvent = AZ::Event<RPI::ShaderResourceGroup*>;
//! Connect a handler to listen to the event that the Scene is ready to update and compile its scene srg
//! User should use this event to update the part scene srg they know of
void ConnectEvent(PrepareSceneSrgEvent::Handler& handler);
protected:
// SceneFinder overrides...
Scene* FindSelf();
void OnSceneNotifictaionHandlerConnected(SceneNotification* handler);
// Cpu simulation which runs all active FeatureProcessor Simulate() functions.
@@ -183,7 +183,7 @@ namespace AZ
// Function called when the current frame is finished rendering.
void OnFrameEnd();
// Update and compile view srgs
// Update and compile scene and view srgs
// This is called after PassSystem's FramePrepare so passes can still modify view srgs in its FramePrepareIntenal function before they are submitted to command list
void UpdateSrgs();
@@ -200,6 +200,10 @@ namespace AZ
// Add a created feature processor to this scene
void AddFeatureProcessor(FeatureProcessorPtr fp);
// Send out event to PrepareSceneSrgEvent::Handlers so they can update scene srg as needed
// This happens in UpdateSrgs()
void PrepareSceneSrg();
// List of feature processors that are active for this scene
AZStd::vector<FeatureProcessorPtr> m_featureProcessors;
@@ -215,9 +219,10 @@ namespace AZ
AZ::RPI::FeatureProcessor::SimulatePacket m_simulatePacket;
AZ::RPI::FeatureProcessor::RenderPacket m_renderPacket;
// Scene's srg and its set function
// Scene's srg
Data::Instance<ShaderResourceGroup> m_srg;
ShaderResourceGroupCallback m_srgCallback;
// Event to for prepare scene srg
PrepareSceneSrgEvent m_prepareSrgEvent;
// The uuid to identify this scene.
SceneId m_id;
@@ -234,6 +239,8 @@ namespace AZ
// Registry which allocates draw filter tag for RenderPipeline
RHI::Ptr<RHI::DrawFilterTagRegistry> m_drawFilterTagRegistry;
float m_simulationTime;
};
// --- Template functions ---
@@ -67,6 +67,9 @@ namespace AZ
//! Notifies when the PrepareRender phase is ending
virtual void OnEndPrepareRender() {}
//! Notifies when the render tick for a given frame has finished.
virtual void OnFrameEnd() {}
};
using SceneNotificationBus = AZ::EBus<SceneNotification>;
@@ -80,7 +83,6 @@ namespace AZ
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = SceneId;
virtual Scene* FindSelf() = 0;
virtual void OnSceneNotifictaionHandlerConnected(SceneNotification* handler) = 0;
};
@@ -51,9 +51,21 @@ namespace AZ
//! Sets the root scene associated with this viewport.
//! This does not provide a default render pipeline, one must be provided to enable rendering.
void SetRenderScene(ScenePtr scene);
//! Runs one simulation and render tick and renders a frame to this viewport's window.
//! @note This is likely to be replaced by a tick management system in the RPI.
void RenderTick();
//! Gets the maximum frame rate this viewport context's pipeline can render at, 0 for unlimited.
//! The target framerate for the pipeline will be determined by this frame limit and the
//! vsync settings for the current window.
float GetFpsLimit() const;
//! Sets the maximum frame rate this viewport context's pipeline can render at, 0 for unlimited.
//! The target framerate for the pipeline will be determined by this frame limit and the
//! vsync settings for the current window.
void SetFpsLimit(float fpsLimit);
//! Gets the target frame rate for this viewport context.
//! This returns the lowest of either the current VSync refresh rate
//! or 0 for an unlimited frame rate (if there's no FPS limit and vsync is off).
float GetTargetFrameRate() const;
//! Gets the current name of this ViewportContext.
//! This name is used to tie this ViewportContext to its View stack, and ViewportContexts may be
@@ -74,19 +86,28 @@ namespace AZ
//! \see AzFramework::WindowRequests::GetDpiScaleFactor
float GetDpiScalingFactor() const;
//! Gets the current vsync interval, as a divisor of the current refresh rate.
//! A value of 0 indicates that vsync is disabled.
uint32_t GetVsyncInterval() const;
//! Gets the current display refresh rate, in frames per second.
uint32_t GetRefreshRate() const;
// SceneNotificationBus interface overrides...
//! Ensures our default view remains set when our scene's render pipelines are modified.
void OnRenderPipelineAdded(RenderPipelinePtr pipeline) override;
//! Ensures our default view remains set when our scene's render pipelines are modified.
void OnRenderPipelineRemoved(RenderPipeline* pipeline) override;
//! OnBeginPrepareRender is forwarded to our RenderTick notification to allow subscribers to do rendering.
void OnBeginPrepareRender() override;
// WindowNotificationBus interface overrides...
//! Used to fire a notification when our window resizes.
void OnWindowResized(uint32_t width, uint32_t height) override;
//! Used to fire a notification when our window DPI changes.
void OnDpiScaleFactorChanged(float dpiScaleFactor) override;
//! Used to fire a notification when our vsync interval changes.
void OnVsyncIntervalChanged(uint32_t interval) override;
//! Used to fire a notification when our refresh rate changes.
void OnRefreshRateChanged(uint32_t refreshRate) override;
using SizeChangedEvent = AZ::Event<AzFramework::WindowSize>;
//! Notifies consumers when the viewport size has changed.
@@ -98,6 +119,12 @@ namespace AZ
//! Alternatively, connect to ViewportContextNotificationsBus and listen to ViewportContextNotifications::OnViewportDpiScalingChanged.
void ConnectDpiScalingFactorChangedHandler(ScalarChangedEvent::Handler& handler);
using UintChangedEvent = AZ::Event<uint32_t>;
//! Notifies consumers when the vsync interval has changed.
void ConnectVsyncIntervalChangedHandler(UintChangedEvent::Handler& handler);
//! Notifies consumers when the refresh rate has changed.
void ConnectRefreshRateChangedHandler(UintChangedEvent::Handler& handler);
using MatrixChangedEvent = AZ::Event<const AZ::Matrix4x4&>;
//! Notifies consumers when the view matrix has changed.
void ConnectViewMatrixChangedHandler(MatrixChangedEvent::Handler& handler);
@@ -139,15 +166,24 @@ namespace AZ
void SetDefaultView(ViewPtr view);
// Ensures our render pipeline's default camera matches ours.
void UpdatePipelineView();
// Ensures our render pipeline refresh rate matches our refresh rate.
void UpdatePipelineRefreshRate();
// Resets the current pipeline reference and ensures pipeline events are disconnected.
void ResetCurrentPipeline();
ScenePtr m_rootScene;
WindowContextSharedPtr m_windowContext;
ViewPtr m_defaultView;
AzFramework::WindowSize m_viewportSize;
float m_viewportDpiScaleFactor = 1.0f;
uint32_t m_vsyncInterval = 1;
uint32_t m_refreshRate = 60;
float m_fpsLimit = 0.f;
SizeChangedEvent m_sizeChangedEvent;
ScalarChangedEvent m_dpiScalingFactorChangedEvent;
UintChangedEvent m_vsyncIntervalChangedEvent;
UintChangedEvent m_refreshRateChangedEvent;
MatrixChangedEvent m_viewMatrixChangedEvent;
MatrixChangedEvent::Handler m_onViewMatrixChangedHandler;
MatrixChangedEvent m_projectionMatrixChangedEvent;
@@ -157,6 +193,9 @@ namespace AZ
ViewChangedEvent m_defaultViewChangedEvent;
ViewportIdEvent m_aboutToBeDestroyedEvent;
AZ::Event<>::Handler m_prepareFrameHandler;
AZ::Event<>::Handler m_endFrameHandler;
ViewportContextManager* m_manager;
RenderPipelinePtr m_currentPipeline;
Name m_name;
@@ -110,11 +110,13 @@ namespace AZ
virtual void OnViewportSizeChanged(AzFramework::WindowSize size){AZ_UNUSED(size);}
//! Called when the window DPI scaling changes for a given viewport context.
virtual void OnViewportDpiScalingChanged(float dpiScale){AZ_UNUSED(dpiScale);}
//! Called when the active view for a given viewport context name changes.
//! Called when the active view changes for a given viewport context.
virtual void OnViewportDefaultViewChanged(AZ::RPI::ViewPtr view){AZ_UNUSED(view);}
//! Called when the viewport is to be rendered.
//! Add draws to this functions if they only need to be rendered to this viewport.
virtual void OnRenderTick(){};
//! Add draws to this function if they only need to be rendered to this viewport.
virtual void OnRenderTick(){}
//! Called when the viewport finishes rendering a frame.
virtual void OnFrameEnd(){}
protected:
~ViewportContextNotifications() = default;
@@ -153,7 +153,9 @@ namespace AZ
void AssetCreator<AssetDataT>::ReportError([[maybe_unused]] const char* format, [[maybe_unused]] Args... args)
{
++m_errorCount;
#if defined(AZ_ENABLE_TRACING) // disabling since it requires argument expansion in this context
AZ_Error(m_assetClassName, false, format, args...);
#endif
}
template<typename AssetDataT>
@@ -161,7 +163,9 @@ namespace AZ
void AssetCreator<AssetDataT>::ReportWarning([[maybe_unused]] const char* format, [[maybe_unused]] Args... args)
{
++m_warningCount;
#if defined(AZ_ENABLE_TRACING) // disabling since it requires argument expansion in this context
AZ_Warning(m_assetClassName, false, format, args...);
#endif
}
template<typename AssetDataT>
@@ -83,14 +83,19 @@ namespace AZ
AZ_TYPE_INFO(AZ::RPI::LuaMaterialFunctorCommonContext, "{2CCCB9A9-AD4F-447C-B587-E7A91CEA8088}");
explicit LuaMaterialFunctorCommonContext(MaterialFunctor::RuntimeContext* runtimeContextImpl,
const MaterialPropertyFlags* materialPropertyDependencies,
const AZStd::string& propertyNamePrefix,
const AZStd::string& srgNamePrefix,
const AZStd::string& optionsNamePrefix);
explicit LuaMaterialFunctorCommonContext(MaterialFunctor::EditorContext* editorContextImpl,
const MaterialPropertyFlags* materialPropertyDependencies,
const AZStd::string& propertyNamePrefix,
const AZStd::string& srgNamePrefix,
const AZStd::string& optionsNamePrefix);
//! Returns false if PSO changes are not allowed, and may report errors or warnings
bool CheckPsoChangesAllowed();
protected:
@@ -100,6 +105,12 @@ namespace AZ
MaterialPropertyIndex GetMaterialPropertyIndex(const char* name, const char* functionName) const;
const MaterialPropertyValue& GetMaterialPropertyValue(MaterialPropertyIndex propertyIndex) const;
MaterialPropertyPsoHandling GetMaterialPropertyPsoHandling() const;
RHI::ConstPtr<MaterialPropertiesLayout> GetMaterialPropertiesLayout() const;
AZStd::string GetMaterialPropertyDependenciesString() const;
// These are prefix strings that will be applied to every name lookup in the lua functor.
// This allows the lua script to be reused in different contexts.
@@ -112,6 +123,8 @@ namespace AZ
// Only one of these will be valid
MaterialFunctor::RuntimeContext* m_runtimeContextImpl = nullptr;
MaterialFunctor::EditorContext* m_editorContextImpl = nullptr;
const MaterialPropertyFlags* m_materialPropertyDependencies = nullptr;
bool m_psoChangesReported = false; //!< errors/warnings about PSO changes will only be reported once per execution of the functor
};
//! Wraps RHI::RenderStates for LuaMaterialFunctor access
@@ -241,7 +254,11 @@ namespace AZ
static void Reflect(BehaviorContext* behaviorContext);
explicit LuaMaterialFunctorShaderItem(ShaderCollection::Item* shaderItem) : m_shaderItem(shaderItem) {}
LuaMaterialFunctorShaderItem() :
m_context(nullptr), m_shaderItem(nullptr) {}
explicit LuaMaterialFunctorShaderItem(LuaMaterialFunctorCommonContext* context, ShaderCollection::Item* shaderItem) :
m_context(context), m_shaderItem(shaderItem) {}
LuaMaterialFunctorRenderStates GetRenderStatesOverride();
void SetEnabled(bool enable);
@@ -253,6 +270,7 @@ namespace AZ
private:
void SetShaderOptionValue(const Name& name, AZStd::function<bool(ShaderOptionGroup*, ShaderOptionIndex)> setValueCommand);
LuaMaterialFunctorCommonContext* m_context = nullptr;
ShaderCollection::Item* m_shaderItem = nullptr;
};
@@ -265,6 +283,7 @@ namespace AZ
static void Reflect(BehaviorContext* behaviorContext);
explicit LuaMaterialFunctorRuntimeContext(MaterialFunctor::RuntimeContext* runtimeContextImpl,
const MaterialPropertyFlags* materialPropertyDependencies,
const AZStd::string& propertyNamePrefix,
const AZStd::string& srgNamePrefix,
const AZStd::string& optionsNamePrefix);
@@ -304,6 +323,7 @@ namespace AZ
static void Reflect(BehaviorContext* behaviorContext);
explicit LuaMaterialFunctorEditorContext(MaterialFunctor::EditorContext* editorContextImpl,
const MaterialPropertyFlags* materialPropertyDependencies,
const AZStd::string& propertyNamePrefix,
const AZStd::string& srgNamePrefix,
const AZStd::string& optionsNamePrefix);
@@ -28,6 +28,24 @@ namespace AZ
class MaterialPropertiesLayout;
using MaterialPropertyFlags = AZStd::bitset<Limits::Material::PropertyCountMax>;
//! Indicates how the material system should respond to any material property changes that
//! impact Pipeline State Object configuration. This is significant because some platforms
//! require that PSOs be pre-compiled and shipped with the game.
enum class MaterialPropertyPsoHandling
{
//! PSO-impacting property changes are not allowed, are ignored, and will report an error.
//! This should be used at runtime. It is recommended to do this on all platforms, not just the restricted ones,
//! to encourage best-practices. However, if a game project is not shipping on any restricted platforms,
//! then the team could decide to allow PSO changes.
Error,
//! PSO-impacting property changes are allowed, but produce a warning message.
Warning,
//! PSO-impacting property changes are allowed. This can be used during asset processing, in developer tools, or on platforms that don't restrict PSO changes.
Allowed
};
//! MaterialFunctor objects provide custom logic and calculations to configure shaders, render states,
//! editor metadata, and more.
@@ -81,6 +99,8 @@ namespace AZ
const MaterialPropertyValue& GetMaterialPropertyValue(const MaterialPropertyIndex& index) const;
const MaterialPropertiesLayout* GetMaterialPropertiesLayout() const { return m_materialPropertiesLayout.get(); }
MaterialPropertyPsoHandling GetMaterialPropertyPsoHandling() const { return m_psoHandling; }
//! Set the value of a shader option
//! @param shaderIndex the index of a shader in the material's ShaderCollection
@@ -126,16 +146,18 @@ namespace AZ
RHI::ConstPtr<MaterialPropertiesLayout> materialPropertiesLayout,
ShaderCollection* shaderCollection,
ShaderResourceGroup* shaderResourceGroup,
const MaterialPropertyFlags* materialPropertyDependencies
const MaterialPropertyFlags* materialPropertyDependencies,
MaterialPropertyPsoHandling psoHandling
);
private:
bool SetShaderOptionValue(ShaderCollection::Item& shaderItem, ShaderOptionIndex optionIndex, ShaderOptionValue value);
const AZStd::vector<MaterialPropertyValue>& m_materialPropertyValues;
RHI::ConstPtr<MaterialPropertiesLayout> m_materialPropertiesLayout;
ShaderCollection* m_shaderCollection;
ShaderResourceGroup* m_shaderResourceGroup;
ShaderCollection* m_shaderCollection;
ShaderResourceGroup* m_shaderResourceGroup;
const MaterialPropertyFlags* m_materialPropertyDependencies = nullptr;
MaterialPropertyPsoHandling m_psoHandling = MaterialPropertyPsoHandling::Error;
};
class EditorContext
@@ -144,7 +166,7 @@ namespace AZ
public:
const MaterialPropertyDynamicMetadata* GetMaterialPropertyMetadata(const Name& propertyName) const;
const MaterialPropertyDynamicMetadata* GetMaterialPropertyMetadata(const MaterialPropertyIndex& index) const;
const MaterialPropertyGroupDynamicMetadata* GetMaterialPropertyGroupMetadata(const Name& propertyName) const;
//! Get the property value. The type must be one of those in MaterialPropertyValue.
@@ -158,6 +180,8 @@ namespace AZ
const MaterialPropertyValue& GetMaterialPropertyValue(const MaterialPropertyIndex& index) const;
const MaterialPropertiesLayout* GetMaterialPropertiesLayout() const { return m_materialPropertiesLayout.get(); }
MaterialPropertyPsoHandling GetMaterialPropertyPsoHandling() const { return MaterialPropertyPsoHandling::Allowed; }
//! Set the visibility dynamic metadata of a material property.
bool SetMaterialPropertyVisibility(const Name& propertyName, MaterialPropertyVisibility visibility);
@@ -177,7 +201,7 @@ namespace AZ
bool SetMaterialPropertySoftMaxValue(const Name& propertyName, const MaterialPropertyValue& max);
bool SetMaterialPropertySoftMaxValue(const MaterialPropertyIndex& index, const MaterialPropertyValue& max);
bool SetMaterialPropertyGroupVisibility(const Name& propertyGroupName, MaterialPropertyGroupVisibility visibility);
// [GFX TODO][ATOM-4168] Replace the workaround for unlink-able RPI.Public classes in MaterialFunctor
@@ -30,7 +30,7 @@ namespace AZ
{
namespace
{
const char* AnyAssetBuilderName = "AnyAssetBuilder";
[[maybe_unused]] const char* AnyAssetBuilderName = "AnyAssetBuilder";
const char* AnyAssetBuilderJobKey = "Any Asset Builder";
const char* AnyAssetBuilderDefaultExtension = "azasset";
const char* AnyAssetSourceExtensions[] =
@@ -13,6 +13,7 @@
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
#include <Atom/RPI.Edit/Common/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
@@ -36,7 +37,7 @@ namespace AZ
{
namespace
{
static constexpr char const MaterialBuilderName[] = "MaterialBuilder";
[[maybe_unused]] static constexpr char const MaterialBuilderName[] = "MaterialBuilder";
}
const char* MaterialBuilder::JobKey = "Atom Material Builder";
@@ -151,7 +152,7 @@ namespace AZ
AZStd::string fullSourcePath;
AzFramework::StringFunc::Path::ConstructFull(request.m_watchFolder.data(), request.m_sourceFile.data(), fullSourcePath, true);
auto loadOutcome = JsonSerializationUtils::ReadJsonFile(fullSourcePath);
auto loadOutcome = JsonSerializationUtils::ReadJsonFile(fullSourcePath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!loadOutcome.IsSuccess())
{
AZ_Error(MaterialBuilderName, false, "%s", loadOutcome.GetError().c_str());
@@ -298,7 +299,7 @@ namespace AZ
AZStd::string fullSourcePath;
AzFramework::StringFunc::Path::ConstructFull(request.m_watchFolder.data(), request.m_sourceFile.data(), fullSourcePath, true);
auto loadOutcome = JsonSerializationUtils::ReadJsonFile(fullSourcePath);
auto loadOutcome = JsonSerializationUtils::ReadJsonFile(fullSourcePath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!loadOutcome.IsSuccess())
{
AZ_Error(MaterialBuilderName, false, "Failed to load material file: %s", loadOutcome.GetError().c_str());
@@ -37,7 +37,7 @@ namespace AZ
{
namespace RPI
{
static const char* MaterialExporterName = "Scene Material Builder";
[[maybe_unused]] static const char* MaterialExporterName = "Scene Material Builder";
void MaterialAssetDependenciesComponent::Reflect(ReflectContext* context)
{
@@ -1078,9 +1078,7 @@ namespace AZ
template<typename T>
void ModelAssetBuilderComponent::ValidateStreamSize([[maybe_unused]] size_t expectedVertexCount, [[maybe_unused]] const AZStd::vector<T>& bufferData, [[maybe_unused]] AZ::RHI::Format format, [[maybe_unused]] const char* streamName) const
{
#if defined(AZ_ENABLE_TRACING)
size_t actualVertexCount = (bufferData.size() * sizeof(T)) / RHI::GetFormatSize(format);
#endif
AZ_Error(s_builderName, expectedVertexCount == actualVertexCount, "VertexStream '%s' does not match the expected vertex count. This typically means multiple sub-meshes have mis-matched vertex stream layouts (such as one having more uv sets than the other) but are assigned the same material in the dcc tool so they were merged.", streamName);
}
@@ -37,7 +37,7 @@ namespace AZ
{
namespace RPI
{
static const char* s_exporterName = "Atom Model Builder";
[[maybe_unused]] static const char* s_exporterName = "Atom Model Builder";
ModelExporterComponent::ModelExporterComponent()
{
@@ -70,11 +70,9 @@ namespace AZ::RPI
{
const Containers::SceneGraph& sceneGraph = scene.GetGraph();
#if defined(AZ_ENABLE_TRACING)
const auto baseMeshIt = AZStd::find(sceneGraph.GetContentStorage().cbegin(), sceneGraph.GetContentStorage().cend(), sourceMesh.m_meshData);
const Containers::SceneGraph::NodeIndex baseMeshIndex = sceneGraph.ConvertToNodeIndex(baseMeshIt);
const AZStd::string_view baseMeshName{sceneGraph.GetNodeName(baseMeshIndex).GetName(), sceneGraph.GetNodeName(baseMeshIndex).GetNameLength()};
#endif
// Get the blend shapes for the given mesh
AZStd::unordered_map<AZStd::string, SourceBlendShapeInfo> blendShapeInfos = GetBlendShapeInfos(scene, sourceMesh.m_meshData.get());
@@ -90,10 +88,8 @@ namespace AZ::RPI
AZ_Assert(blendShapeData, "Node is expected to be a blend shape.");
if (blendShapeData)
{
#if defined(AZ_ENABLE_TRACING)
const Containers::SceneGraph::NodeIndex morphMeshParentIndex = sceneGraph.GetNodeParent(sceneNodeIndex);
const AZStd::string_view sourceMeshName{sceneGraph.GetNodeName(morphMeshParentIndex).GetName(), sceneGraph.GetNodeName(morphMeshParentIndex).GetNameLength()};
#endif
AZ_Assert(AZ::StringFunc::Equal(baseMeshName, sourceMeshName, /*bCaseSensitive=*/true),
"Scene graph mesh node (%.*s) has a different name than the product mesh (%.*s).",
@@ -28,7 +28,7 @@ namespace AZ
{
namespace
{
static const char* PassBuilderName = "PassBuilder";
[[maybe_unused]] static const char* PassBuilderName = "PassBuilder";
static const char* PassBuilderJobKey = "Pass Asset Builder";
static const char* PassAssetExtension = "pass";
}
@@ -10,6 +10,7 @@
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
#include <Atom/RPI.Edit/Common/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
@@ -67,7 +68,7 @@ namespace AZ
{
AZStd::string materialTypePath = AssetUtils::ResolvePathReference(jsonFileLoadContext->GetFilePath(), materialSourceData->m_materialType);
auto materialTypeJson = JsonSerializationUtils::ReadJsonFile(materialTypePath);
auto materialTypeJson = JsonSerializationUtils::ReadJsonFile(materialTypePath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!materialTypeJson.IsSuccess())
{
AZStd::string failureMessage;
@@ -15,6 +15,7 @@
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
#include <Atom/RPI.Edit/Common/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzCore/std/string/string.h>
@@ -64,7 +65,7 @@ namespace AZ
AZ::Outcome<rapidjson::Document, AZStd::string> loadOutcome;
if (document == nullptr)
{
loadOutcome = AZ::JsonSerializationUtils::ReadJsonFile(filePath);
loadOutcome = AZ::JsonSerializationUtils::ReadJsonFile(filePath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!loadOutcome.IsSuccess())
{
AZ_Error("AZ::RPI::JsonUtils", false, "%s", loadOutcome.GetError().c_str());
@@ -14,6 +14,9 @@
#include <RPI.Private/RPISystemComponent.h>
#include <Atom/RHI/Factory.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
#include <Atom/RPI.Public/ViewportContext.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/IO/IOUtils.h>
@@ -93,20 +96,29 @@ namespace AZ
}
m_rpiSystem.Initialize(m_rpiDescriptor);
AZ::SystemTickBus::Handler::BusConnect();
AZ::TickBus::Handler::BusConnect();
}
void RPISystemComponent::Deactivate()
{
AZ::SystemTickBus::Handler::BusDisconnect();
AZ::TickBus::Handler::BusDisconnect();
m_rpiSystem.Shutdown();
}
void RPISystemComponent::OnSystemTick()
void RPISystemComponent::OnTick([[maybe_unused]]float deltaTime, [[maybe_unused]]ScriptTimePoint time)
{
if (deltaTime == 0.f)
{
return;
}
m_rpiSystem.SimulationTick();
m_rpiSystem.RenderTick();
}
int RPISystemComponent::GetTickOrder()
{
return AZ::ComponentTickBus::TICK_RENDER;
}
} // namespace RPI
} // namespace AZ
@@ -32,7 +32,7 @@ namespace AZ
*/
class RPISystemComponent final
: public AZ::Component
, public AZ::SystemTickBus::Handler
, private AZ::TickBus::Handler
{
public:
AZ_COMPONENT(RPISystemComponent, "{83E301F3-7A0C-4099-B530-9342B91B1BC0}");
@@ -50,8 +50,9 @@ namespace AZ
private:
RPISystemComponent(const RPISystemComponent&) = delete;
// SystemTickBus overrides...
void OnSystemTick() override;
// TickBus overrides...
void OnTick(float deltaTime, ScriptTimePoint time) override;
int GetTickOrder() override;
RPISystem m_rpiSystem;
@@ -20,6 +20,7 @@
#include <AzCore/Debug/EventTrace.h>
#include <AtomCore/Instance/InstanceDatabase.h>
#include <AtomCore/Utils/ScopedValue.h>
namespace AZ
{
@@ -58,6 +59,8 @@ namespace AZ
{
AZ_TRACE_METHOD();
ScopedValue isInitializing(&m_isInitializing, true, false);
m_materialAsset = { &materialAsset, AZ::Data::AssetLoadBehavior::PreLoad };
// Cache off pointers to some key data structures from the material type...
@@ -198,6 +201,11 @@ namespace AZ
return AZ::Success(appliedCount);
}
void Material::SetPsoHandlingOverride(MaterialPropertyPsoHandling psoHandlingOverride)
{
m_psoHandling = psoHandlingOverride;
}
const RHI::ShaderResourceGroup* Material::GetRHIShaderResourceGroup() const
{
return m_rhiShaderResourceGroup;
@@ -310,6 +318,16 @@ namespace AZ
if (NeedsCompile() && CanCompile())
{
// On some platforms, PipelineStateObjects must be pre-compiled and shipped with the game; they cannot be compiled at runtime. So at some
// point the material system needs to be smart about when it allows PSO changes and when it doesn't. There is a task scheduled to
// thoroughly address this in 2022, but for now we just report a warning to alert users who are using the engine in a way that might
// not be supported for much longer. PSO changes should only be allowed in developer tools (though we could also expose a way for users to
// enable dynamic PSO changes if their project only targets platforms that support this).
// PSO modifications are allowed during initialization because that's using the stored asset data, which the asset system can
// access to pre-compile the necessary PSOs.
MaterialPropertyPsoHandling psoHandling = m_isInitializing ? MaterialPropertyPsoHandling::Allowed : m_psoHandling;
AZ_PROFILE_BEGIN(RPI, "Material::Compile() Processing Functors");
for (const Ptr<MaterialFunctor>& functor : m_materialAsset->GetMaterialFunctors())
{
@@ -325,7 +343,8 @@ namespace AZ
m_layout,
&m_shaderCollection,
m_shaderResourceGroup.get(),
&materialPropertyDependencies
&materialPropertyDependencies,
psoHandling
);
@@ -484,6 +503,13 @@ namespace AZ
}
MaterialPropertyValue& savedPropertyValue = m_propertyValues[index.GetIndex()];
// If the property value didn't actually change, don't waste time running functors and compiling the changes
if (savedPropertyValue == value)
{
return false;
}
savedPropertyValue = value;
m_propertyDirtyFlags.set(index.GetIndex());
m_propertyOverrideFlags.set(index.GetIndex());
@@ -124,7 +124,6 @@ namespace AZ
bool MeshDrawPacket::DoUpdate(const Scene& parentScene)
{
AZ_PROFILE_FUNCTION(RPI);
const ModelLod::Mesh& mesh = m_modelLod->GetMeshes()[m_modelLodMeshIndex];
if (!m_material)
@@ -155,8 +154,6 @@ namespace AZ
auto appendShader = [&](const ShaderCollection::Item& shaderItem)
{
AZ_PROFILE_SCOPE(RPI, "appendShader()");
// Skip the shader item without creating the shader instance
// if the mesh is not going to be rendered based on the draw tag
RHI::RHISystemInterface* rhiSystem = RHI::RHISystemInterface::Get();
@@ -256,7 +253,6 @@ namespace AZ
Data::Instance<ShaderResourceGroup> drawSrg;
if (drawSrgLayout)
{
AZ_PROFILE_SCOPE(RPI, "create drawSrg");
// If the DrawSrg exists we must create and bind it, otherwise the CommandList will fail validation for SRG being null
drawSrg = RPI::ShaderResourceGroup::Create(shader->GetAsset(), shader->GetSupervariantIndex(), drawSrgLayout->GetName());
@@ -264,8 +264,6 @@ namespace AZ
const MaterialModelUvOverrideMap& materialModelUvMap,
const MaterialUvNameMap& materialUvNameMap) const
{
AZ_PROFILE_FUNCTION(RPI);
streamBufferViewsOut.clear();
RHI::InputStreamLayoutBuilder layoutBuilder;
@@ -366,8 +364,6 @@ namespace AZ
const MaterialModelUvOverrideMap& materialModelUvMap,
const MaterialUvNameMap& materialUvNameMap) const
{
AZ_PROFILE_FUNCTION(RPI);
const Mesh& mesh = m_meshes[meshIndex];
auto defaultUv = FindDefaultUvStream(meshIndex, materialUvNameMap);
@@ -308,10 +308,10 @@ namespace AZ
// The fix is to clear the buffer outside of the callback.
for (int32_t i = 0; i < RHI::Limits::Device::FrameCountMax; i++)
{
if (m_isReadbackComplete[m_readbackBufferCurrentIndex])
if (m_isReadbackComplete[i])
{
m_isReadbackComplete[m_readbackBufferCurrentIndex] = false;
m_readbackBufferArray[m_readbackBufferCurrentIndex] = nullptr;
m_isReadbackComplete[i] = false;
m_readbackBufferArray[i] = nullptr;
}
}
// Loop the triple buffer index and cache the current index to the callback.
@@ -93,8 +93,11 @@ namespace AZ
void Pass::SetEnabled(bool enabled)
{
m_flags.m_enabled = enabled;
OnHierarchyChange();
if (m_flags.m_enabled != enabled)
{
m_flags.m_enabled = enabled;
OnHierarchyChange();
}
}
bool Pass::IsEnabled() const
@@ -230,8 +230,6 @@ namespace AZ
void RasterPass::BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context)
{
AZ_PROFILE_FUNCTION(RPI);
RHI::CommandList* commandList = context.GetCommandList();
const RHI::DrawListView drawListViewPartition = RHI::GetDrawListPartition(m_drawListView, context.GetCommandListIndex(), context.GetCommandListCount());
@@ -293,7 +293,7 @@ namespace AZ
// 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
// Update Scene and View Srgs
for (auto& scenePtr : m_scenes)
{
scenePtr->UpdateSrgs();
@@ -301,6 +301,26 @@ namespace AZ
m_drawFilterMask = 0;
}
void RenderPipeline::OnPrepareFrame()
{
m_lastRenderRequestTime = AZStd::chrono::system_clock::now();
// If we're attempting to render at a target interval, check to see if we're within
// 1ms of that interval, enabling rendering only if we are.
if (m_renderMode == RenderMode::RenderAtTargetRate)
{
constexpr AZStd::chrono::duration<float> updateThresholdMs(0.001f);
const bool shouldRender =
m_lastRenderRequestTime - m_lastRenderStartTime + updateThresholdMs >= m_targetRefreshRate;
m_rootPass->SetEnabled(shouldRender);
}
if (NeedsRender())
{
m_prepareFrameEvent.Signal();
}
}
void RenderPipeline::OnPassModified()
{
if (m_needsPassRecreate)
@@ -375,11 +395,11 @@ namespace AZ
m_scene->RemoveRenderPipeline(m_nameId);
}
void RenderPipeline::OnStartFrame(const TickTimeInfo& tick)
void RenderPipeline::OnStartFrame()
{
AZ_PROFILE_FUNCTION(RPI);
m_lastRenderStartTime = tick.m_currentGameTime;
m_lastRenderStartTime = m_lastRenderRequestTime;
OnPassModified();
@@ -407,6 +427,7 @@ namespace AZ
{
RemoveFromRenderTick();
}
m_endFrameEvent.Signal();
}
void RenderPipeline::CollectPersistentViews(AZStd::map<ViewPtr, RHI::DrawListMask>& outViewMasks) const
@@ -489,6 +510,13 @@ namespace AZ
m_renderMode = RenderMode::RenderEveryTick;
}
void RenderPipeline::AddToRenderTickAtInterval(AZStd::chrono::duration<float> renderInterval)
{
m_rootPass->SetEnabled(false);
m_renderMode = RenderMode::RenderAtTargetRate;
m_targetRefreshRate = renderInterval;
}
void RenderPipeline::RemoveFromRenderTick()
{
m_renderMode = RenderMode::NoRender;
@@ -502,7 +530,7 @@ namespace AZ
bool RenderPipeline::NeedsRender() const
{
return m_renderMode != RenderMode::NoRender;
return m_rootPass->IsEnabled();
}
RHI::DrawFilterTag RenderPipeline::GetDrawFilterTag() const
@@ -515,6 +543,16 @@ namespace AZ
return m_drawFilterMask;
}
void RenderPipeline::ConnectPrepareFrameHandler(FrameNotificationEvent::Handler& handler)
{
handler.Connect(m_prepareFrameEvent);
}
void RenderPipeline::ConnectEndFrameHandler(FrameNotificationEvent::Handler& handler)
{
handler.Connect(m_endFrameEvent);
}
void RenderPipeline::SetDrawFilterTag(RHI::DrawFilterTag tag)
{
m_drawFilterTag = tag;
+45 -25
View File
@@ -352,6 +352,8 @@ namespace AZ
{
AZ_ATOM_PROFILE_FUNCTION("RPI", "Scene: Simulate");
m_simulationTime = tickInfo.m_currentGameTime;
// If previous simulation job wasn't done, wait for it to finish.
WaitAndCleanCompletionJob(m_simulationCompletion);
@@ -395,7 +397,30 @@ namespace AZ
}
}
void Scene::PrepareRender(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy)
void Scene::ConnectEvent(PrepareSceneSrgEvent::Handler& handler)
{
handler.Connect(m_prepareSrgEvent);
}
void Scene::PrepareSceneSrg()
{
if (m_srg)
{
// Set value for constants defined in SceneTimeSrg.azsli
RHI::ShaderInputConstantIndex timeIndex = m_srg->FindShaderInputConstantIndex(Name{ "m_time" });
if (timeIndex.IsValid())
{
m_srg->SetConstant(timeIndex, m_simulationTime);
}
// signal any handlers to update values for their partial scene srg
m_prepareSrgEvent.Signal(m_srg.get());
m_srg->Compile();
}
}
void Scene::PrepareRender([[maybe_unused]]const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy)
{
AZ_ATOM_PROFILE_FUNCTION("RPI", "Scene: PrepareRender");
@@ -407,28 +432,25 @@ namespace AZ
SceneNotificationBus::Event(GetId(), &SceneNotification::OnBeginPrepareRender);
// Get active pipelines which need to be rendered and notify them of an impending frame.
AZStd::vector<RenderPipelinePtr> activePipelines;
{
AZ_PROFILE_SCOPE(RPI, "m_srgCallback");
AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "ShaderResourceGroupCallback: SrgCallback");
// Set values for scene srg
if (m_srg && m_srgCallback)
AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "Scene: OnPrepareFrame");
for (auto& pipeline : m_pipelines)
{
m_srgCallback(m_srg.get());
pipeline->OnPrepareFrame();
if (pipeline->NeedsRender())
{
activePipelines.push_back(pipeline);
}
}
}
// Get active pipelines which need to be rendered and notify them frame started
AZStd::vector<RenderPipelinePtr> activePipelines;
for (const auto& pipeline : activePipelines)
{
AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "Scene: OnStartFrame");
for (auto& pipeline : m_pipelines)
{
if (pipeline->NeedsRender())
{
activePipelines.push_back(pipeline);
pipeline->OnStartFrame(tickInfo);
}
}
pipeline->OnStartFrame();
}
// Return if there is no active render pipeline
@@ -572,10 +594,12 @@ namespace AZ
void Scene::OnFrameEnd()
{
AZ_ATOM_PROFILE_FUNCTION("RPI", "Scene: OnFrameEnd");
bool didRender = false;
for (auto& pipeline : m_pipelines)
{
if (pipeline->NeedsRender())
{
didRender = true;
pipeline->OnFrameEnd();
}
}
@@ -583,21 +607,22 @@ namespace AZ
{
fp->OnRenderEnd();
}
if (didRender)
{
SceneNotificationBus::Event(GetId(), &SceneNotification::OnFrameEnd);
}
}
void Scene::UpdateSrgs()
{
PrepareSceneSrg();
for (auto& view : m_renderPacket.m_views)
{
view->UpdateSrg();
}
}
void Scene::SetShaderResourceGroupCallback(ShaderResourceGroupCallback callback)
{
m_srgCallback = callback;
}
const RHI::ShaderResourceGroup* Scene::GetRHIShaderResourceGroup() const
{
if (m_srg.get())
@@ -641,11 +666,6 @@ namespace AZ
return m_pipelines;
}
Scene* Scene::FindSelf()
{
return this;
}
void Scene::OnSceneNotifictaionHandlerConnected(SceneNotification* handler)
{
for (auto renderPipeline : m_pipelines)
@@ -299,7 +299,6 @@ namespace AZ
const ShaderVariant& Shader::GetVariant(const ShaderVariantId& shaderVariantId)
{
AZ_PROFILE_FUNCTION(RPI);
Data::Asset<ShaderVariantAsset> shaderVariantAsset = m_asset->GetVariant(shaderVariantId, m_supervariantIndex);
if (!shaderVariantAsset || shaderVariantAsset->IsRootVariant())
{
@@ -316,15 +315,12 @@ namespace AZ
ShaderVariantSearchResult Shader::FindVariantStableId(const ShaderVariantId& shaderVariantId) const
{
AZ_PROFILE_FUNCTION(RPI);
ShaderVariantSearchResult variantSearchResult = m_asset->FindVariantStableId(shaderVariantId);
return variantSearchResult;
}
const ShaderVariant& Shader::GetVariant(ShaderVariantStableId shaderVariantStableId)
{
AZ_PROFILE_FUNCTION(RPI);
if (!shaderVariantStableId.IsValid() || shaderVariantStableId == ShaderAsset::RootShaderVariantStableId)
{
return m_rootVariant;
@@ -241,7 +241,10 @@ namespace AZ
{
AZ_PROFILE_FUNCTION(RPI);
m_drawListContext.FinalizeLists();
SortFinalizedDrawLists();
if (m_passesByDrawList)
{
SortFinalizedDrawLists();
}
}
void View::SortFinalizedDrawLists()
@@ -25,14 +25,13 @@ namespace AZ
, m_viewportSize(1, 1)
{
m_windowContext->Initialize(device, nativeWindow);
AzFramework::WindowRequestBus::EventResult(
m_viewportSize,
nativeWindow,
&AzFramework::WindowRequestBus::Events::GetClientAreaSize);
AzFramework::WindowRequestBus::EventResult(
m_viewportDpiScaleFactor,
nativeWindow,
&AzFramework::WindowRequestBus::Events::GetDpiScaleFactor);
AzFramework::WindowRequestBus::Event(nativeWindow, [this](AzFramework::WindowRequestBus::Events* window)
{
m_viewportSize = window->GetClientAreaSize();
m_viewportDpiScaleFactor = window->GetDpiScaleFactor();
m_vsyncInterval = window->GetSyncInterval();
m_refreshRate = window->GetDisplayRefreshRate();
});
AzFramework::WindowNotificationBus::Handler::BusConnect(nativeWindow);
AzFramework::ViewportRequestBus::Handler::BusConnect(id);
@@ -46,6 +45,20 @@ namespace AZ
m_viewMatrixChangedEvent.Signal(matrix);
});
m_prepareFrameHandler = RenderPipeline::FrameNotificationEvent::Handler(
[this]()
{
ViewportContextNotificationBus::Event(GetName(), &ViewportContextNotificationBus::Events::OnRenderTick);
ViewportContextIdNotificationBus::Event(GetId(), &ViewportContextIdNotificationBus::Events::OnRenderTick);
});
m_endFrameHandler = RenderPipeline::FrameNotificationEvent::Handler(
[this]()
{
ViewportContextNotificationBus::Event(GetName(), &ViewportContextNotificationBus::Events::OnFrameEnd);
ViewportContextIdNotificationBus::Event(GetId(), &ViewportContextIdNotificationBus::Events::OnFrameEnd);
});
SetRenderScene(renderScene);
}
@@ -111,26 +124,38 @@ namespace AZ
{
SceneNotificationBus::Handler::BusConnect(m_rootScene->GetId());
}
m_currentPipeline.reset();
ResetCurrentPipeline();
UpdatePipelineView();
UpdatePipelineRefreshRate();
}
m_sceneChangedEvent.Signal(scene);
}
void ViewportContext::RenderTick()
float ViewportContext::GetFpsLimit() const
{
// add the current pipeline to next render tick if it's not already added.
if (m_currentPipeline && m_currentPipeline->GetRenderMode() != RenderPipeline::RenderMode::RenderOnce)
{
m_currentPipeline->AddToRenderTickOnce();
}
return m_fpsLimit;
}
void ViewportContext::OnBeginPrepareRender()
void ViewportContext::SetFpsLimit(float fpsLimit)
{
ViewportContextNotificationBus::Event(GetName(), &ViewportContextNotificationBus::Events::OnRenderTick);
ViewportContextIdNotificationBus::Event(GetId(), &ViewportContextIdNotificationBus::Events::OnRenderTick);
m_fpsLimit = fpsLimit;
UpdatePipelineRefreshRate();
}
float ViewportContext::GetTargetFrameRate() const
{
float targetFrameRate = GetFpsLimit();
const AZ::u32 vsyncInterval = GetVsyncInterval();
if (vsyncInterval != 0)
{
const float vsyncFrameRate = static_cast<float>(GetRefreshRate()) / static_cast<float>(vsyncInterval);
if (targetFrameRate == 0.f || vsyncFrameRate < targetFrameRate)
{
targetFrameRate = vsyncFrameRate;
}
}
return targetFrameRate;
}
AZ::Name ViewportContext::GetName() const
@@ -158,6 +183,16 @@ namespace AZ
return m_viewportDpiScaleFactor;
}
uint32_t ViewportContext::GetVsyncInterval() const
{
return m_vsyncInterval;
}
uint32_t ViewportContext::GetRefreshRate() const
{
return m_refreshRate;
}
void ViewportContext::ConnectSizeChangedHandler(SizeChangedEvent::Handler& handler)
{
handler.Connect(m_sizeChangedEvent);
@@ -168,6 +203,16 @@ namespace AZ
handler.Connect(m_dpiScalingFactorChangedEvent);
}
void ViewportContext::ConnectVsyncIntervalChangedHandler(UintChangedEvent::Handler& handler)
{
handler.Connect(m_vsyncIntervalChangedEvent);
}
void ViewportContext::ConnectRefreshRateChangedHandler(UintChangedEvent::Handler& handler)
{
handler.Connect(m_refreshRateChangedEvent);
}
void ViewportContext::ConnectViewMatrixChangedHandler(MatrixChangedEvent::Handler& handler)
{
handler.Connect(m_viewMatrixChangedEvent);
@@ -263,12 +308,43 @@ namespace AZ
m_currentPipelineChangedEvent.Signal(m_currentPipeline);
}
if (auto pipeline = GetCurrentPipeline())
if (m_currentPipeline)
{
pipeline->SetDefaultView(m_defaultView);
if (!m_prepareFrameHandler.IsConnected())
{
m_currentPipeline->ConnectPrepareFrameHandler(m_prepareFrameHandler);
m_currentPipeline->ConnectEndFrameHandler(m_endFrameHandler);
}
m_currentPipeline->SetDefaultView(m_defaultView);
}
}
void ViewportContext::UpdatePipelineRefreshRate()
{
if (!m_currentPipeline)
{
return;
}
const float refreshRate = GetTargetFrameRate();
// If we have a truly unlimited framerate, just render every tick
if (refreshRate == 0.f)
{
m_currentPipeline->AddToRenderTick();
}
else
{
m_currentPipeline->AddToRenderTickAtInterval(AZStd::chrono::duration<float>(1.f / refreshRate));
}
}
void ViewportContext::ResetCurrentPipeline()
{
m_prepareFrameHandler.Disconnect();
m_endFrameHandler.Disconnect();
m_currentPipeline.reset();
}
RenderPipelinePtr ViewportContext::GetCurrentPipeline()
{
return m_currentPipeline;
@@ -281,8 +357,9 @@ namespace AZ
// in the event prioritization is added later
if (pipeline->GetWindowHandle() == m_windowContext->GetWindowHandle())
{
m_currentPipeline.reset();
ResetCurrentPipeline();
UpdatePipelineView();
UpdatePipelineRefreshRate();
}
}
@@ -290,8 +367,9 @@ namespace AZ
{
if (m_currentPipeline.get() == pipeline)
{
m_currentPipeline.reset();
ResetCurrentPipeline();
UpdatePipelineView();
UpdatePipelineRefreshRate();
}
}
@@ -305,10 +383,30 @@ namespace AZ
}
}
void ViewportContext::OnRefreshRateChanged(uint32_t refreshRate)
{
if (m_refreshRate != refreshRate)
{
m_refreshRate = refreshRate;
m_refreshRateChangedEvent.Signal(m_refreshRate);
UpdatePipelineRefreshRate();
}
}
void ViewportContext::OnDpiScaleFactorChanged(float dpiScaleFactor)
{
m_viewportDpiScaleFactor = dpiScaleFactor;
m_dpiScalingFactorChangedEvent.Signal(dpiScaleFactor);
}
void ViewportContext::OnVsyncIntervalChanged(uint32_t interval)
{
if (m_vsyncInterval != interval)
{
m_vsyncInterval = interval;
m_vsyncIntervalChangedEvent.Signal(m_vsyncInterval);
UpdatePipelineRefreshRate();
}
}
} // namespace RPI
} // namespace AZ
@@ -128,7 +128,7 @@ namespace AZ
if (m_scriptStatus == ScriptStatus::Ready)
{
LuaMaterialFunctorRuntimeContext luaContext{&context, m_propertyNamePrefix, m_srgNamePrefix, m_optionsNamePrefix};
LuaMaterialFunctorRuntimeContext luaContext{&context, &GetMaterialPropertyDependencies(), m_propertyNamePrefix, m_srgNamePrefix, m_optionsNamePrefix};
AZ::ScriptDataContext call;
if (m_scriptContext->Call("Process", call))
{
@@ -146,7 +146,7 @@ namespace AZ
if (m_scriptStatus == ScriptStatus::Ready)
{
LuaMaterialFunctorEditorContext luaContext{&context, m_propertyNamePrefix, m_srgNamePrefix, m_optionsNamePrefix};
LuaMaterialFunctorEditorContext luaContext{&context, &GetMaterialPropertyDependencies(), m_propertyNamePrefix, m_srgNamePrefix, m_optionsNamePrefix};
AZ::ScriptDataContext call;
if (m_scriptContext->Call("ProcessEditor", call))
{
@@ -157,10 +157,12 @@ namespace AZ
}
LuaMaterialFunctorCommonContext::LuaMaterialFunctorCommonContext(MaterialFunctor::RuntimeContext* runtimeContextImpl,
const MaterialPropertyFlags* materialPropertyDependencies,
const AZStd::string& propertyNamePrefix,
const AZStd::string& srgNamePrefix,
const AZStd::string& optionsNamePrefix)
: m_runtimeContextImpl(runtimeContextImpl)
, m_materialPropertyDependencies(materialPropertyDependencies)
, m_propertyNamePrefix(propertyNamePrefix)
, m_srgNamePrefix(srgNamePrefix)
, m_optionsNamePrefix(optionsNamePrefix)
@@ -168,34 +170,96 @@ namespace AZ
}
LuaMaterialFunctorCommonContext::LuaMaterialFunctorCommonContext(MaterialFunctor::EditorContext* editorContextImpl,
const MaterialPropertyFlags* materialPropertyDependencies,
const AZStd::string& propertyNamePrefix,
const AZStd::string& srgNamePrefix,
const AZStd::string& optionsNamePrefix)
: m_editorContextImpl(editorContextImpl)
, m_materialPropertyDependencies(materialPropertyDependencies)
, m_propertyNamePrefix(propertyNamePrefix)
, m_srgNamePrefix(srgNamePrefix)
, m_optionsNamePrefix(optionsNamePrefix)
{
}
MaterialPropertyPsoHandling LuaMaterialFunctorCommonContext::GetMaterialPropertyPsoHandling() const
{
if (m_runtimeContextImpl)
{
return m_runtimeContextImpl->GetMaterialPropertyPsoHandling();
}
else
{
return m_editorContextImpl->GetMaterialPropertyPsoHandling();
}
}
RHI::ConstPtr<MaterialPropertiesLayout> LuaMaterialFunctorCommonContext::GetMaterialPropertiesLayout() const
{
if (m_runtimeContextImpl)
{
return m_runtimeContextImpl->GetMaterialPropertiesLayout();
}
else
{
return m_editorContextImpl->GetMaterialPropertiesLayout();
}
}
AZStd::string LuaMaterialFunctorCommonContext::GetMaterialPropertyDependenciesString() const
{
AZStd::vector<AZStd::string> propertyList;
for (size_t i = 0; i < m_materialPropertyDependencies->size(); ++i)
{
if ((*m_materialPropertyDependencies)[i])
{
propertyList.push_back(GetMaterialPropertiesLayout()->GetPropertyDescriptor(MaterialPropertyIndex{i})->GetName().GetStringView());
}
}
AZStd::string propertyListString;
AzFramework::StringFunc::Join(propertyListString, propertyList.begin(), propertyList.end(), ", ");
return propertyListString;
}
bool LuaMaterialFunctorCommonContext::CheckPsoChangesAllowed()
{
if (GetMaterialPropertyPsoHandling() == MaterialPropertyPsoHandling::Error)
{
if (!m_psoChangesReported)
{
LuaMaterialFunctorUtilities::Script_Error(
AZStd::string::format(
"The following material properties must not be changed at runtime because they impact Pipeline State Objects: %s", GetMaterialPropertyDependenciesString().c_str()));
m_psoChangesReported = true;
}
return false;
}
else if (GetMaterialPropertyPsoHandling() == MaterialPropertyPsoHandling::Warning)
{
if (!m_psoChangesReported)
{
LuaMaterialFunctorUtilities::Script_Warning(
AZStd::string::format(
"The following material properties should not be changed at runtime because they impact Pipeline State Objects: %s", GetMaterialPropertyDependenciesString().c_str()));
m_psoChangesReported = true;
}
}
return true;
}
MaterialPropertyIndex LuaMaterialFunctorCommonContext::GetMaterialPropertyIndex(const char* name, const char* functionName) const
{
MaterialPropertyIndex propertyIndex;
Name propertyFullName{m_propertyNamePrefix + name};
if (m_runtimeContextImpl)
{
propertyIndex = m_runtimeContextImpl->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyFullName);
}
else if (m_editorContextImpl)
{
propertyIndex = m_editorContextImpl->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyFullName);
}
else
{
AZ_Assert(false, "Context not initialized properly");
}
propertyIndex = GetMaterialPropertiesLayout()->FindPropertyIndex(propertyFullName);
if (!propertyIndex.IsValid())
{
@@ -297,10 +361,11 @@ namespace AZ
}
LuaMaterialFunctorRuntimeContext::LuaMaterialFunctorRuntimeContext(MaterialFunctor::RuntimeContext* runtimeContextImpl,
const MaterialPropertyFlags* materialPropertyDependencies,
const AZStd::string& propertyNamePrefix,
const AZStd::string& srgNamePrefix,
const AZStd::string& optionsNamePrefix)
: LuaMaterialFunctorCommonContext(runtimeContextImpl, propertyNamePrefix, srgNamePrefix, optionsNamePrefix)
: LuaMaterialFunctorCommonContext(runtimeContextImpl, materialPropertyDependencies, propertyNamePrefix, srgNamePrefix, optionsNamePrefix)
, m_runtimeContextImpl(runtimeContextImpl)
{
}
@@ -331,7 +396,7 @@ namespace AZ
if (!shaderItem.MaterialOwnsShaderOption(optionIndex))
{
LuaMaterialFunctorUtilities::Script_Error(AZStd::string::format("Shader option '%s' is not owned by this material.", fullOptionName.GetCStr()).c_str());
LuaMaterialFunctorUtilities::Script_Error(AZStd::string::format("Shader option '%s' is not owned by this material.", fullOptionName.GetCStr()));
break;
}
@@ -398,12 +463,12 @@ namespace AZ
{
if (index < GetShaderCount())
{
return LuaMaterialFunctorShaderItem{&(*m_runtimeContextImpl->m_shaderCollection)[index]};
return LuaMaterialFunctorShaderItem{this, &(*m_runtimeContextImpl->m_shaderCollection)[index]};
}
else
{
LuaMaterialFunctorUtilities::Script_Error(AZStd::string::format("GetShader(%zu) is invalid.", index));
return LuaMaterialFunctorShaderItem{nullptr};
return {};
}
}
@@ -412,13 +477,13 @@ namespace AZ
const AZ::Name tag{shaderTag};
if (m_runtimeContextImpl->m_shaderCollection->HasShaderTag(tag))
{
return LuaMaterialFunctorShaderItem{&(*m_runtimeContextImpl->m_shaderCollection)[tag]};
return LuaMaterialFunctorShaderItem{this, &(*m_runtimeContextImpl->m_shaderCollection)[tag]};
}
else
{
LuaMaterialFunctorUtilities::Script_Error(AZStd::string::format(
"GetShaderByTag('%s') is invalid: Could not find a shader with the tag '%s'.", tag.GetCStr(), tag.GetCStr()));
return LuaMaterialFunctorShaderItem{nullptr};
return {};
}
}
@@ -459,10 +524,11 @@ namespace AZ
}
LuaMaterialFunctorEditorContext::LuaMaterialFunctorEditorContext(MaterialFunctor::EditorContext* editorContextImpl,
const MaterialPropertyFlags* materialPropertyDependencies,
const AZStd::string& propertyNamePrefix,
const AZStd::string& srgNamePrefix,
const AZStd::string& optionsNamePrefix)
: LuaMaterialFunctorCommonContext(editorContextImpl, propertyNamePrefix, srgNamePrefix, optionsNamePrefix)
: LuaMaterialFunctorCommonContext(editorContextImpl, materialPropertyDependencies, propertyNamePrefix, srgNamePrefix, optionsNamePrefix)
, m_editorContextImpl(editorContextImpl)
{
}
@@ -595,7 +661,7 @@ namespace AZ
LuaMaterialFunctorRenderStates LuaMaterialFunctorShaderItem::GetRenderStatesOverride()
{
if (m_shaderItem)
if (m_context->CheckPsoChangesAllowed() && m_shaderItem)
{
return LuaMaterialFunctorRenderStates{m_shaderItem->GetRenderStatesOverlay()};
}
@@ -638,8 +704,7 @@ namespace AZ
{
LuaMaterialFunctorUtilities::Script_Error(
AZStd::string::format(
"Shader option '%s' is not owned by the shader '%s'.", name.GetCStr(), m_shaderItem->GetShaderTag().GetCStr())
.c_str());
"Shader option '%s' is not owned by the shader '%s'.", name.GetCStr(), m_shaderItem->GetShaderTag().GetCStr()));
return;
}
@@ -35,13 +35,15 @@ namespace AZ
RHI::ConstPtr<MaterialPropertiesLayout> materialPropertiesLayout,
ShaderCollection* shaderCollection,
ShaderResourceGroup* shaderResourceGroup,
const MaterialPropertyFlags* materialPropertyDependencies
const MaterialPropertyFlags* materialPropertyDependencies,
MaterialPropertyPsoHandling psoHandling
)
: m_materialPropertyValues(propertyValues)
, m_materialPropertiesLayout(materialPropertiesLayout)
, m_shaderCollection(shaderCollection)
, m_shaderResourceGroup(shaderResourceGroup)
, m_materialPropertyDependencies(materialPropertyDependencies)
, m_psoHandling(psoHandling)
{}
bool MaterialFunctor::RuntimeContext::SetShaderOptionValue(ShaderCollection::Item& shaderItem, ShaderOptionIndex optionIndex, ShaderOptionValue value)
@@ -419,9 +421,7 @@ namespace AZ
{
if (!materialPropertyDependencies.test(index.GetIndex()))
{
#if defined(AZ_ENABLE_TRACING)
const MaterialPropertyDescriptor* propertyDescriptor = materialPropertiesLayout.GetPropertyDescriptor(index);
#endif
AZ_Error("MaterialFunctor", false, "Material functor accessing an unregistered material property '%s'.",
propertyDescriptor ? propertyDescriptor->GetName().GetCStr() : "<unknown>");
}
@@ -22,7 +22,7 @@ namespace AZ
: public SerializeContext::IEventHandler
{
//! Called right before we start reading from the instance pointed by classPtr.
virtual void OnReadBegin(void* classPtr)
void OnReadBegin(void* classPtr) override
{
ShaderCollection::Item* shaderVariantReference = reinterpret_cast<ShaderCollection::Item*>(classPtr);
shaderVariantReference->m_shaderVariantId = shaderVariantReference->m_shaderOptionGroup.GetShaderVariantId();
@@ -96,8 +96,6 @@ namespace AZ
const AZ::Vector3& rayStart, const AZ::Vector3& rayDir, bool allowBruteForce,
float& distanceNormalized, AZ::Vector3& normal) const
{
AZ_PROFILE_FUNCTION(RPI);
if (!m_modelTriangleCount)
{
// [GFX TODO][ATOM-4343 Bake mesh spatial information during AP processing]
@@ -172,8 +172,6 @@ namespace AZ
Data::Asset<ShaderVariantAsset> ShaderAsset::GetVariant(
const ShaderVariantId& shaderVariantId, SupervariantIndex supervariantIndex)
{
AZ_PROFILE_FUNCTION(RPI);
auto variantFinder = AZ::Interface<IShaderVariantFinder>::Get();
AZ_Assert(variantFinder, "The IShaderVariantFinder doesn't exist");
@@ -189,8 +187,6 @@ namespace AZ
ShaderVariantSearchResult ShaderAsset::FindVariantStableId(const ShaderVariantId& shaderVariantId)
{
AZ_PROFILE_FUNCTION(RPI);
uint32_t dynamicOptionCount = aznumeric_cast<uint32_t>(GetShaderOptionGroupLayout()->GetShaderOptions().size());
ShaderVariantSearchResult variantSearchResult{RootShaderVariantStableId, dynamicOptionCount };
@@ -72,8 +72,6 @@ namespace AZ
ShaderVariantSearchResult ShaderVariantTreeAsset::FindVariantStableId(const ShaderOptionGroupLayout* shaderOptionGroupLayout, const ShaderVariantId& shaderVariantId) const
{
AZ_PROFILE_FUNCTION(RPI);
struct NodeToVisit
{
uint32_t m_branchCount; // Number of static branches
+9 -9
View File
@@ -69,8 +69,8 @@ namespace UnitTest
void FillFormatsCapabilitiesInternal([[maybe_unused]] FormatCapabilitiesList& formatsCapabilities) override {}
AZ::RHI::ResultCode InitializeLimits() override { return AZ::RHI::ResultCode::Success; }
void PreShutdown() override {}
AZ::RHI::ResourceMemoryRequirements GetResourceMemoryRequirements([[maybe_unused]] const AZ::RHI::ImageDescriptor& descriptor) { return AZ::RHI::ResourceMemoryRequirements{}; };
AZ::RHI::ResourceMemoryRequirements GetResourceMemoryRequirements([[maybe_unused]] const AZ::RHI::BufferDescriptor& descriptor) { return AZ::RHI::ResourceMemoryRequirements{}; };
AZ::RHI::ResourceMemoryRequirements GetResourceMemoryRequirements([[maybe_unused]] const AZ::RHI::ImageDescriptor& descriptor) override { return AZ::RHI::ResourceMemoryRequirements{}; };
AZ::RHI::ResourceMemoryRequirements GetResourceMemoryRequirements([[maybe_unused]] const AZ::RHI::BufferDescriptor& descriptor) override { return AZ::RHI::ResourceMemoryRequirements{}; };
void ObjectCollectionNotify(AZ::RHI::ObjectCollectorNotifyFunction notifyFunction) override {}
};
@@ -228,12 +228,12 @@ namespace UnitTest
AZ_CLASS_ALLOCATOR(Fence, AZ::SystemAllocator, 0);
private:
virtual AZ::RHI::ResultCode InitInternal(AZ::RHI::Device&, AZ::RHI::FenceState) override { return AZ::RHI::ResultCode::Success; }
virtual void ShutdownInternal() override {}
virtual void SignalOnCpuInternal() override {}
virtual void WaitOnCpuInternal() const override {};
virtual void ResetInternal() override {}
virtual AZ::RHI::FenceState GetFenceStateInternal() const override { return AZ::RHI::FenceState::Reset; }
AZ::RHI::ResultCode InitInternal(AZ::RHI::Device&, AZ::RHI::FenceState) override { return AZ::RHI::ResultCode::Success; }
void ShutdownInternal() override {}
void SignalOnCpuInternal() override {}
void WaitOnCpuInternal() const override {};
void ResetInternal() override {}
AZ::RHI::FenceState GetFenceStateInternal() const override { return AZ::RHI::FenceState::Reset; }
};
class ShaderResourceGroupPool
@@ -276,7 +276,7 @@ namespace UnitTest
AZ_CLASS_ALLOCATOR(ShaderStageFunction, AZ::SystemAllocator, 0);
private:
virtual AZ::RHI::ResultCode FinalizeInternal() { return AZ::RHI::ResultCode::Success; }
AZ::RHI::ResultCode FinalizeInternal() override { return AZ::RHI::ResultCode::Success; }
};
class PipelineState
@@ -23,6 +23,7 @@ namespace UnitTest
: m_serializeContext{serializeContext}
, m_outStream{&m_buffer}
{}
virtual ~SerializeTester() = default;
// Serializes an object out to a the internal stream. Resets the stream with each call.
virtual void SerializeOut(T* object, AZ::DataStream::StreamType streamType = AZ::DataStream::ST_XML);
@@ -76,7 +77,7 @@ namespace UnitTest
m_assetHandler = AZ::Data::AssetManager::Instance().GetHandler(AssetDataT::RTTI_Type());
}
~AssetTester() = default;
virtual ~AssetTester() = default;
void SerializeOut(AZ::Data::Asset<AssetDataT> assetToSave)
{
@@ -40,10 +40,9 @@ namespace AZ
: public UnitTest::AssetTester<StreamingImageAsset>
{
public:
StreamingImageAssetTester()
{
StreamingImageAssetTester() = default;
~StreamingImageAssetTester() override = default;
}
void SetAssetReady(Data::Asset<StreamingImageAsset>& asset) override
{
asset->SetReady();
@@ -54,7 +53,8 @@ namespace AZ
: public UnitTest::AssetTester<ImageMipChainAsset>
{
public:
ImageMipChainAssetTester() {}
ImageMipChainAssetTester() = default;
~ImageMipChainAssetTester() override = default;
void SetAssetReady(Data::Asset<ImageMipChainAsset>& asset) override
{
@@ -1039,6 +1039,42 @@ namespace UnitTest
drawListTagRegistry->ReleaseTag(tag);
}
TEST_F(LuaMaterialFunctorTests, LuaMaterialFunctor_RuntimeContext_PsoChangesNotAllowed_Error)
{
using namespace AZ::RPI;
const char* functorScript =
R"(
function GetMaterialPropertyDependencies()
return {"general.MyBool"}
end
function GetShaderOptionDependencies()
return {}
end
function Process(context)
local boolValue = context:GetMaterialPropertyValue_bool("general.MyBool")
if(boolValue) then
context:GetShader(0):GetRenderStatesOverride():SetFillMode(FillMode_Wireframe)
else
context:GetShader(0):GetRenderStatesOverride():ClearFillMode()
end
end
)";
TestMaterialData testData;
testData.Setup(MaterialPropertyDataType::Bool, "general.MyBool", functorScript);
testData.GetMaterial()->SetPropertyValue(testData.GetMaterialPropertyIndex(), MaterialPropertyValue{true});
ErrorMessageFinder errorMessageFinder;
errorMessageFinder.AddExpectedErrorMessage("not be changed at runtime because they impact Pipeline State Objects: general.MyBool");
EXPECT_TRUE(testData.GetMaterial()->Compile());
errorMessageFinder.CheckExpectedErrorsFound();
}
TEST_F(LuaMaterialFunctorTests, LuaMaterialFunctor_RuntimeContext_MultisampleCustomPositionCountIndex_Error)
{
@@ -1067,6 +1103,7 @@ namespace UnitTest
TestMaterialData testData;
testData.Setup(MaterialPropertyDataType::Bool, "general.MyBool", functorScript);
testData.GetMaterial()->SetPsoHandlingOverride(AZ::RPI::MaterialPropertyPsoHandling::Allowed);
testData.GetMaterial()->SetPropertyValue(testData.GetMaterialPropertyIndex(), MaterialPropertyValue{true});
ErrorMessageFinder errorMessageFinder;
@@ -1107,7 +1144,8 @@ namespace UnitTest
errorMessageFinder.AddExpectedErrorMessage("ClearMultisampleCustomPosition(18,...) index is out of range. Must be less than 16.");
testData.Setup(MaterialPropertyDataType::Bool, "general.MyBool", functorScript);
errorMessageFinder.CheckExpectedErrorsFound();
testData.GetMaterial()->SetPsoHandlingOverride(AZ::RPI::MaterialPropertyPsoHandling::Allowed);
testData.GetMaterial()->SetPropertyValue(testData.GetMaterialPropertyIndex(), MaterialPropertyValue{true});
errorMessageFinder.AddExpectedErrorMessage("SetMultisampleCustomPosition(17,...) index is out of range. Must be less than 16.");
@@ -1146,7 +1184,8 @@ namespace UnitTest
errorMessageFinder.AddExpectedErrorMessage("ClearBlendEnabled(10,...) index is out of range. Must be less than 8.");
testData.Setup(MaterialPropertyDataType::Bool, "general.MyBool", functorScript);
errorMessageFinder.CheckExpectedErrorsFound();
testData.GetMaterial()->SetPsoHandlingOverride(AZ::RPI::MaterialPropertyPsoHandling::Allowed);
testData.GetMaterial()->SetPropertyValue(testData.GetMaterialPropertyIndex(), MaterialPropertyValue{true});
errorMessageFinder.AddExpectedErrorMessage("SetBlendEnabled(9,...) index is out of range. Must be less than 8.");
@@ -41,6 +41,7 @@ namespace UnitTest
{
}
using MaterialFunctor::Process;
void Process(MaterialFunctor::RuntimeContext& context) override
{
m_processResult = context.SetShaderOptionValue(0, m_shaderOptionIndex, m_shaderOptionValue);
@@ -65,6 +66,7 @@ namespace UnitTest
public:
MOCK_METHOD0(ProcessCalled, void());
using MaterialFunctor::Process;
void Process(RuntimeContext& context) override
{
ProcessCalled();
@@ -87,6 +89,7 @@ namespace UnitTest
: public MaterialFunctorSourceData
{
public:
using MaterialFunctorSourceData::CreateFunctor;
FunctorResult CreateFunctor(const RuntimeContext& context) const override
{
Ptr<PropertyDependencyTestFunctor> functor = aznew PropertyDependencyTestFunctor;
@@ -165,7 +168,8 @@ namespace UnitTest
materialTypeAsset->GetMaterialPropertiesLayout(),
&shaderCollectionCopy,
unusedSrg,
&testFunctorSetOptionA.GetMaterialPropertyDependencies()
&testFunctorSetOptionA.GetMaterialPropertyDependencies(),
AZ::RPI::MaterialPropertyPsoHandling::Allowed
};
testFunctorSetOptionA.Process(runtimeContext);
EXPECT_TRUE(testFunctorSetOptionA.GetProcessResult());
@@ -181,7 +185,8 @@ namespace UnitTest
materialTypeAsset->GetMaterialPropertiesLayout(),
&shaderCollectionCopy,
unusedSrg,
&testFunctorSetOptionB.GetMaterialPropertyDependencies()
&testFunctorSetOptionB.GetMaterialPropertyDependencies(),
AZ::RPI::MaterialPropertyPsoHandling::Allowed
};
testFunctorSetOptionB.Process(runtimeContext);
EXPECT_TRUE(testFunctorSetOptionB.GetProcessResult());
@@ -198,7 +203,8 @@ namespace UnitTest
materialTypeAsset->GetMaterialPropertiesLayout(),
&shaderCollectionCopy,
unusedSrg,
&testFunctorSetOptionC.GetMaterialPropertyDependencies()
&testFunctorSetOptionC.GetMaterialPropertyDependencies(),
AZ::RPI::MaterialPropertyPsoHandling::Allowed
};
testFunctorSetOptionC.Process(runtimeContext);
EXPECT_FALSE(testFunctorSetOptionC.GetProcessResult());
@@ -213,7 +219,8 @@ namespace UnitTest
materialTypeAsset->GetMaterialPropertiesLayout(),
&shaderCollectionCopy,
unusedSrg,
&testFunctorSetOptionInvalid.GetMaterialPropertyDependencies()
&testFunctorSetOptionInvalid.GetMaterialPropertyDependencies(),
AZ::RPI::MaterialPropertyPsoHandling::Allowed
};
testFunctorSetOptionInvalid.Process(runtimeContext);
EXPECT_FALSE(testFunctorSetOptionInvalid.GetProcessResult());
@@ -21,14 +21,14 @@ namespace JsonSerializationTests
public JsonSerializerConformityTestDescriptor<AZ::RPI::MaterialTypeSourceData::PropertyDefinition>
{
public:
void Reflect(AZStd::unique_ptr<AZ::SerializeContext>& context)
void Reflect(AZStd::unique_ptr<AZ::SerializeContext>& context) override
{
AZ::RPI::MaterialTypeSourceData::Reflect(context.get());
AZ::RPI::MaterialPropertyDescriptor::Reflect(context.get());
AZ::RPI::ReflectMaterialDynamicMetadata(context.get());
}
void Reflect(AZStd::unique_ptr<AZ::JsonRegistrationContext>& context)
void Reflect(AZStd::unique_ptr<AZ::JsonRegistrationContext>& context) override
{
AZ::RPI::MaterialTypeSourceData::Reflect(context.get());
}
@@ -142,6 +142,7 @@ namespace UnitTest
AZStd::string m_propertyName;
MaterialPropertyValueSourceData m_propertyValue;
using MaterialFunctorSourceData::CreateFunctor;
FunctorResult CreateFunctor(const RuntimeContext& context) const override
{
Ptr<ValueFunctor> functor = aznew ValueFunctor;
@@ -47,6 +47,7 @@ namespace UnitTest
;
}
using AZ::RPI::MaterialFunctor::Process;
void Process(AZ::RPI::MaterialFunctor::RuntimeContext& context) override
{
// This code isn't actually called in the unit test, but we include it here just to demonstrate what a real functor might look like.
@@ -74,6 +75,7 @@ namespace UnitTest
;
}
using AZ::RPI::MaterialFunctor::Process;
void Process(AZ::RPI::MaterialFunctor::RuntimeContext& context) override
{
// This code isn't actually called in the unit test, but we include it here just to demonstrate what a real functor might look like.
@@ -70,6 +70,7 @@ namespace UnitTest
}
}
using AZ::RPI::MaterialFunctor::Process;
void Process(AZ::RPI::MaterialFunctor::RuntimeContext& context) override
{
// This code isn't actually called in the unit test, but we include it here just to demonstrate what a real functor might look like.
@@ -110,6 +111,7 @@ namespace UnitTest
AZStd::string m_floatPropertyInputId;
AZStd::string m_float3ShaderSettingOutputId;
using MaterialFunctorSourceData::CreateFunctor;
FunctorResult CreateFunctor(const RuntimeContext& context) const override
{
Ptr<Splat3Functor> functor = aznew Splat3Functor;
@@ -138,6 +140,7 @@ namespace UnitTest
}
}
using AZ::RPI::MaterialFunctor::Process;
void Process(AZ::RPI::MaterialFunctor::RuntimeContext& context) override
{
// This code isn't actually called in the unit test, but we include it here just to demonstrate what a real functor might look like.
@@ -174,6 +177,7 @@ namespace UnitTest
m_shaderIndex{shaderIndex}
{}
using MaterialFunctorSourceData::CreateFunctor;
FunctorResult CreateFunctor(const RuntimeContext& context) const override
{
Ptr<EnableShaderFunctor> functor = aznew EnableShaderFunctor;
@@ -200,6 +204,7 @@ namespace UnitTest
}
}
using AZ::RPI::MaterialFunctor::Process;
void Process(AZ::RPI::MaterialFunctor::RuntimeContext& context) override
{
// This code isn't actually called in the unit test, but we include it here just to demonstrate what a real functor might look like.
@@ -232,6 +237,7 @@ namespace UnitTest
return options;
}
using MaterialFunctorSourceData::CreateFunctor;
FunctorResult CreateFunctor([[maybe_unused]] const RuntimeContext& context) const override
{
Ptr<SetShaderOptionFunctor> functor = aznew SetShaderOptionFunctor;