Merge branch 'development' into Atom/dmcdiar/ATOM-4126
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user