123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <AzCore/Utils/TypeHash.h>
- #include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
- #include <Atom/RPI.Public/DynamicDraw/DynamicBuffer.h>
- #include <Atom/RPI.Public/DynamicDraw/DynamicDrawContext.h>
- #include <Atom/RPI.Public/DynamicDraw/DynamicDrawInterface.h>
- #include <Atom/RPI.Public/Pass/RasterPass.h>
- #include <Atom/RPI.Public/RenderPipeline.h>
- #include <Atom/RPI.Public/Scene.h>
- #include <Atom/RPI.Public/View.h>
- namespace AZ
- {
- namespace RPI
- {
- namespace
- {
- constexpr const char* PerContextSrgName = "PerContextSrg";
- }
-
- void DynamicDrawContext::MultiStates::UpdateHash(const DrawStateOptions& drawStateOptions)
- {
- if (!m_isDirty)
- {
- return;
- }
- HashValue64 seed = HashValue64{ 0 };
- if (RHI::CheckBitsAny(drawStateOptions, DrawStateOptions::PrimitiveType))
- {
- seed = TypeHash64(m_topology, seed);
- }
- if (RHI::CheckBitsAny(drawStateOptions, DrawStateOptions::DepthState))
- {
- seed = TypeHash64(m_depthState.m_enable, seed);
- seed = TypeHash64(m_depthState.m_func, seed);
- seed = TypeHash64(m_depthState.m_writeMask, seed);
- }
- if (RHI::CheckBitsAny(drawStateOptions, DrawStateOptions::StencilState))
- {
- seed = TypeHash64(m_stencilState.m_enable, seed);
- seed = TypeHash64(m_stencilState.m_readMask, seed);
- seed = TypeHash64(m_stencilState.m_writeMask, seed);
- seed = TypeHash64(m_stencilState.m_frontFace.m_failOp, seed);
- seed = TypeHash64(m_stencilState.m_frontFace.m_depthFailOp, seed);
- seed = TypeHash64(m_stencilState.m_frontFace.m_passOp, seed);
- seed = TypeHash64(m_stencilState.m_frontFace.m_func, seed);
- seed = TypeHash64(m_stencilState.m_backFace.m_failOp, seed);
- seed = TypeHash64(m_stencilState.m_backFace.m_depthFailOp, seed);
- seed = TypeHash64(m_stencilState.m_backFace.m_passOp, seed);
- seed = TypeHash64(m_stencilState.m_backFace.m_func, seed);
- }
- if (RHI::CheckBitsAny(drawStateOptions, DrawStateOptions::FaceCullMode))
- {
- seed = TypeHash64(m_cullMode, seed);
- }
- if (RHI::CheckBitsAny(drawStateOptions, DrawStateOptions::BlendMode))
- {
- seed = TypeHash64(m_blendState0.m_enable, seed);
- seed = TypeHash64(m_blendState0.m_blendOp, seed);
- seed = TypeHash64(m_blendState0.m_blendSource, seed);
- seed = TypeHash64(m_blendState0.m_blendDest, seed);
- seed = TypeHash64(m_blendState0.m_blendAlphaOp, seed);
- seed = TypeHash64(m_blendState0.m_blendAlphaSource, seed);
- seed = TypeHash64(m_blendState0.m_blendAlphaDest, seed);
- }
- if (RHI::CheckBitsAny(drawStateOptions, DrawStateOptions::ShaderVariant))
- {
- seed = TypeHash64(m_shaderVariantId.m_key, seed);
- seed = TypeHash64(m_shaderVariantId.m_mask, seed);
- }
- m_hash = seed;
- m_isDirty = false;
- }
- void DynamicDrawContext::InitShader(Data::Asset<ShaderAsset> shaderAsset)
- {
- Data::Instance<Shader> shader = Shader::FindOrCreate(shaderAsset);
- InitShader(shader);
- }
- void DynamicDrawContext::InitShader(Data::Instance<Shader> shader)
- {
- InitShaderWithVariant(shader, nullptr);
- m_supportShaderVariants = true;
- }
- DynamicDrawContext::~DynamicDrawContext()
- {
- SceneNotificationBus::Handler::BusDisconnect();
- }
- void DynamicDrawContext::InitShaderWithVariant(Data::Asset<ShaderAsset> shaderAsset, const ShaderOptionList* optionAndValues)
- {
- Data::Instance<Shader> shader = Shader::FindOrCreate(shaderAsset);
- InitShaderWithVariant(shader, optionAndValues);
- }
- void DynamicDrawContext::InitShaderWithVariant(Data::Instance<Shader> shader, const ShaderOptionList* optionAndValues)
- {
- AZ_Assert(!m_initialized, "Can't call InitShader after context was initialized (EndInit was called)");
- if (shader == nullptr)
- {
- AZ_Error("RPI", false, "Initializing DynamicDrawContext with invalid shader");
- return;
- }
- m_supportShaderVariants = false;
- m_shader = shader;
- m_pipelineState = aznew RPI::PipelineStateForDraw;
- m_pipelineState->Init(shader, optionAndValues);
- // Set DrawListTag from shader only if it wasn't set
- if (!m_drawListTag.IsValid())
- {
- m_drawListTag = shader->GetDrawListTag();
- }
- // Create per context srg if it exist
- auto contextSrgLayout = m_shader->FindShaderResourceGroupLayout(Name { PerContextSrgName });
- if (contextSrgLayout)
- {
- m_srgPerContext = AZ::RPI::ShaderResourceGroup::Create(
- m_shader->GetAsset(), m_shader->GetSupervariantIndex(), Name { PerContextSrgName });
- m_srgGroups[0] = m_srgPerContext->GetRHIShaderResourceGroup();
- }
- // Save per draw srg asset which can be used to create draw srg later
- m_drawSrgLayout = m_shader->FindShaderResourceGroupLayout(SrgBindingSlot::Draw);
- m_hasShaderVariantKeyFallbackEntry = (m_drawSrgLayout && m_drawSrgLayout->HasShaderVariantKeyFallbackEntry());
- }
- void DynamicDrawContext::InitVertexFormat(const AZStd::vector<VertexChannel>& vertexChannels)
- {
- AZ_Assert(!m_initialized, "Can't call InitVertexFormat after context was initialized (EndInit was called)");
- AZ_Assert(m_pipelineState, "Can't call InitVertexFormat before InitShader is called with a valid shader");
- m_perVertexDataSize = 0;
- RHI::InputStreamLayoutBuilder layoutBuilder;
- RHI::InputStreamLayoutBuilder::BufferDescriptorBuilder* bufferBuilder = layoutBuilder.AddBuffer();
- for (auto& channel : vertexChannels)
- {
- bufferBuilder->Channel(channel.m_channel, channel.m_format);
- m_perVertexDataSize += RHI::GetFormatSize(channel.m_format);
- }
- if (m_pipelineState)
- {
- m_pipelineState->InputStreamLayout() = layoutBuilder.End();
- }
- }
- void DynamicDrawContext::InitDrawListTag(RHI::DrawListTag drawListTag)
- {
- AZ_Assert(!m_initialized, "Can't call InitDrawListTag after context was initialized (EndInit was called)");
- m_drawListTag = drawListTag;
- }
- void DynamicDrawContext::CustomizePipelineState(AZStd::function<void(Ptr<PipelineStateForDraw>)> updatePipelineState)
- {
- AZ_Assert(!m_initialized, "Can't call CustomizePipelineState after context was initialized (EndInit was called)");
- AZ_Assert(m_pipelineState, "Can't call CustomizePipelineState before InitShader is called");
- updatePipelineState(m_pipelineState);
- }
- uint32_t DynamicDrawContext::GetPerVertexDataSize()
- {
- return m_perVertexDataSize;
- }
- void DynamicDrawContext::EndInit()
- {
- AZ_Warning("RPI", m_pipelineState, "Failed to initialize shader for DynamicDrawContext");
- AZ_Warning("RPI", m_drawListTag.IsValid(), "DynamicDrawContext doesn't have a valid DrawListTag");
- if (!m_drawListTag.IsValid() || m_pipelineState == nullptr)
- {
- return;
- }
- if (m_outputScope == OutputScopeType::RenderPipeline || m_outputScope == OutputScopeType::Scene)
- {
- m_pipelineState->SetOutputFromScene(m_scene, m_drawListTag);
- }
- else if (m_outputScope == OutputScopeType::RasterPass)
- {
- m_pipelineState->SetOutputFromPass(m_pass);
- }
- else
- {
- AZ_Assert(false, "DynamicDrawContext need to set output scope before end initialization");
- return;
- }
- m_rhiPipelineState = m_pipelineState->Finalize();
- if (!m_rhiPipelineState)
- {
- AZ_Warning("RPI", false, "Failed to initialize PipelineState for DynamicDrawContext");
- return;
- }
- m_initialized = true;
- // Acquire MultiStates from m_pipelineState
- m_currentStates.m_cullMode = m_pipelineState->ConstDescriptor().m_renderStates.m_rasterState.m_cullMode;
- m_currentStates.m_topology = m_pipelineState->ConstDescriptor().m_inputStreamLayout.GetTopology();
- m_currentStates.m_depthState = m_pipelineState->ConstDescriptor().m_renderStates.m_depthStencilState.m_depth;
- m_currentStates.m_stencilState = m_pipelineState->ConstDescriptor().m_renderStates.m_depthStencilState.m_stencil;
- m_currentStates.m_blendState0 = m_pipelineState->ConstDescriptor().m_renderStates.m_blendState.m_targets[0];
- m_currentStates.m_shaderVariantId = m_pipelineState->GetShaderVariantId();
- // Force update of hash
- m_currentStates.m_isDirty = true;
- m_currentStates.UpdateHash(m_drawStateOptions);
- m_cachedRhiPipelineStates[m_currentStates.m_hash] = m_pipelineState->GetRHIPipelineState();
- m_rhiPipelineState = m_pipelineState->GetRHIPipelineState();
- }
- void DynamicDrawContext::SetOutputScope(Scene* scene)
- {
- AZ_Assert(scene, "SetOutputScope was called with an invalid Scene");
- if (!scene)
- {
- return;
- }
- m_outputScope = OutputScopeType::Scene;
- m_scene = scene;
- m_pass = nullptr;
- m_drawFilter = RHI::DrawFilterMaskDefaultValue;
- SceneNotificationBus::Handler::BusConnect(m_scene->GetId());
-
- ReInit();
- }
- void DynamicDrawContext::SetOutputScope(RenderPipeline* pipeline)
- {
- if (!pipeline)
- {
- return;
- }
- if (!pipeline->GetScene())
- {
- AZ_Error("DynamicDrawContext", false, "SetOutputScope called with a RenderPipeline without adding to a scene");
- return;
- }
-
- m_outputScope = OutputScopeType::RenderPipeline;
- m_scene = pipeline->GetScene();
- m_pass = nullptr;
- m_drawFilter = pipeline->GetDrawFilterMask();
- SceneNotificationBus::Handler::BusConnect(m_scene->GetId());
-
- ReInit();
- }
- void DynamicDrawContext::SetOutputScope(RasterPass* pass)
- {
- AZ_Assert(pass, "SetOutputScope was called with an invalid RasterPass");
- if (!pass)
- {
- return;
- }
- m_outputScope = OutputScopeType::RasterPass;
- m_scene = nullptr;
- m_pass = pass;
- m_drawFilter = RHI::DrawFilterMaskDefaultValue;
- SceneNotificationBus::Handler::BusDisconnect();
- ReInit();
- }
-
- void DynamicDrawContext::ReInit()
- {
- // Reinitialize if it was initialized
- if (m_initialized)
- {
- // Report warning if there were some draw data
- AZ_Warning(
- "DynamicDrawContext", m_cachedDrawItems.size() == 0,
- "DynamicDrawContext::SetForScene should be called"
- " when there is no cached draw data");
- // Clear some cached data
- FrameEnd();
- m_cachedRhiPipelineStates.clear();
- // Reinitialize
- EndInit();
- }
- }
- bool DynamicDrawContext::IsReady()
- {
- return m_initialized;
- }
- ShaderVariantId DynamicDrawContext::UseShaderVariant(const ShaderOptionList& optionAndValues)
- {
- ShaderVariantId variantId;
- if (!m_initialized || !m_supportShaderVariants)
- {
- AZ_WarningOnce("DynamicDrawContext", false, "%s DynamicDrawContext is not initialized or unable to support shader variants. "
- "Check if it was initialized with InitShaderWithVariant", __FUNCTION__);
- return variantId;
- }
- RPI::ShaderOptionGroup shaderOptionGroup = m_shader->CreateShaderOptionGroup();
- shaderOptionGroup.SetUnspecifiedToDefaultValues();
- for (const auto& optionAndValue : optionAndValues)
- {
- shaderOptionGroup.SetValue(optionAndValue.first, optionAndValue.second);
- }
- variantId = shaderOptionGroup.GetShaderVariantId();
- return variantId;
- }
- void DynamicDrawContext::AddDrawStateOptions(DrawStateOptions options)
- {
- AZ_Assert(!m_initialized, "Can't call AddDrawStateOptions after context was initialized (EndInit was called)");
- m_drawStateOptions |= options;
- }
- bool DynamicDrawContext::HasDrawStateOptions(DrawStateOptions options)
- {
- return RHI::CheckBitsAny(m_drawStateOptions, options);
- }
- void DynamicDrawContext::SetDepthState(RHI::DepthState depthState)
- {
- if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::DepthState))
- {
- if (!(m_currentStates.m_depthState == depthState))
- {
- m_currentStates.m_depthState = depthState;
- m_currentStates.m_isDirty = true;
- }
- }
- else
- {
- AZ_Warning("RHI", false, "Can't set SetDepthState if DrawVariation::DepthState wasn't enabled");
- }
- }
- void DynamicDrawContext::SetStencilState(RHI::StencilState stencilState)
- {
- if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::StencilState))
- {
- if (!(m_currentStates.m_stencilState == stencilState))
- {
- m_currentStates.m_stencilState = stencilState;
- m_currentStates.m_isDirty = true;
- }
- }
- else
- {
- AZ_Warning("RHI", false, "Can't set SetStencilState if DrawVariation::StencilState wasn't enabled");
- }
- }
- void DynamicDrawContext::SetCullMode(RHI::CullMode cullMode)
- {
- if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::FaceCullMode))
- {
- if (m_currentStates.m_cullMode != cullMode)
- {
- m_currentStates.m_cullMode = cullMode;
- m_currentStates.m_isDirty = true;
- }
- }
- else
- {
- AZ_Warning("RHI", false, "Can't set CullMode if DrawVariation::FaceCullMode wasn't enabled");
- }
- }
- void DynamicDrawContext::SetTarget0BlendState(RHI::TargetBlendState blendState)
- {
- if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::BlendMode))
- {
- if (!(m_currentStates.m_blendState0 == blendState))
- {
- m_currentStates.m_blendState0 = blendState;
- m_currentStates.m_isDirty = true;
- }
- }
- else
- {
- AZ_Warning("RHI", false, "Can't set TargetBlendState if DrawVariation::BlendMode wasn't enabled");
- }
- }
- void DynamicDrawContext::SetPrimitiveType(RHI::PrimitiveTopology topology)
- {
- if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::PrimitiveType))
- {
- if (m_currentStates.m_topology != topology)
- {
- m_currentStates.m_topology = topology;
- m_currentStates.m_isDirty = true;
- }
- }
- else
- {
- AZ_Warning("RHI", false, "Can't set PrimitiveTopology if DrawVariation::PrimitiveType wasn't enabled");
- }
- }
- void DynamicDrawContext::SetScissor(RHI::Scissor scissor)
- {
- m_useScissor = true;
- m_scissor = scissor;
- }
- void DynamicDrawContext::UnsetScissor()
- {
- m_useScissor = false;
- }
- void DynamicDrawContext::SetViewport(RHI::Viewport viewport)
- {
- m_useViewport = true;
- m_viewport = viewport;
- }
- void DynamicDrawContext::UnsetViewport()
- {
- m_useViewport = false;
- }
- void DynamicDrawContext::SetStencilReference(uint8_t stencilRef)
- {
- m_stencilRef = stencilRef;
- }
- uint8_t DynamicDrawContext::GetStencilReference() const
- {
- return m_stencilRef;
- }
- void DynamicDrawContext::SetShaderVariant(ShaderVariantId shaderVariantId)
- {
- if (!m_initialized || !m_supportShaderVariants)
- {
- AZ_WarningOnce("DynamicDrawContext", false, "%s DynamicDrawContext is not initialized or unable to support shader variants. "
- "Check if it was initialized with InitShaderWithVariant.\n", __FUNCTION__);
- return;
- }
- if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::ShaderVariant))
- {
- if (m_currentStates.m_shaderVariantId != shaderVariantId)
- {
- m_currentStates.m_shaderVariantId = shaderVariantId;
- m_currentStates.m_isDirty = true;
- }
- }
- else
- {
- AZ_Warning("RHI", false, "Can't set SetShaderVariant if DrawVariation::ShaderVariant wasn't enabled");
- }
- }
- void DynamicDrawContext::DrawIndexed(const void* vertexData, uint32_t vertexCount, const void* indexData, uint32_t indexCount, RHI::IndexFormat indexFormat, Data::Instance < ShaderResourceGroup> drawSrg)
- {
- if (!m_initialized)
- {
- AZ_WarningOnce("DynamicDrawContext", false, "%s This function has been disabled because of failed initialization.\n", __FUNCTION__);
- return;
- }
-
- if (m_drawFinalized)
- {
- AZ_Assert(false, "Can't add draw calls after draw data was finalized");
- return;
- }
- if (m_drawSrgLayout && !drawSrg)
- {
- AZ_Assert(false, "drawSrg need to be provided since the shader requires it");
- return;
- }
- // DrawIndexed requires vertex data and index data
- if (indexData == nullptr || indexCount == 0 || vertexData == nullptr || vertexCount == 0)
- {
- AZ_Assert(false, "Failed to draw due to invalid index or vertex data");
- return;
- }
- // Get dynamic buffers for vertex and index buffer. Skip draw if failed to allocate buffers
- uint32_t vertexDataSize = vertexCount * m_perVertexDataSize;
- RHI::Ptr<DynamicBuffer> vertexBuffer;
- vertexBuffer = DynamicDrawInterface::Get()->GetDynamicBuffer(vertexDataSize, RHI::Alignment::InputAssembly);
- uint32_t indexDataSize = indexCount * RHI::GetIndexFormatSize(indexFormat);
- RHI::Ptr<DynamicBuffer> indexBuffer = DynamicDrawInterface::Get()->GetDynamicBuffer(indexDataSize, RHI::Alignment::InputAssembly);
- if (indexBuffer == nullptr || vertexBuffer == nullptr)
- {
- return;
- }
- DrawItemInfo drawItemInfo{{RHI::MultiDevice::AllDevices}};
- RHI::DrawItem& drawItem = drawItemInfo.m_drawItem;
- // --- Geometry View ---
- RHI::GeometryView newGeometryView{ RHI::MultiDevice::AllDevices };
- RHI::DrawIndexed drawIndexed;
- drawIndexed.m_indexCount = indexCount;
- newGeometryView.SetDrawArguments(drawIndexed);
- // Write data to vertex buffer and set up stream buffer views for DrawItem
- // The stream buffer view need to be cached before the frame is end
- vertexBuffer->Write(vertexData, vertexDataSize);
- newGeometryView.AddStreamBufferView(vertexBuffer->GetStreamBufferView(m_perVertexDataSize));
- // Write data to index buffer and set up index buffer view for DrawItem
- indexBuffer->Write(indexData, indexDataSize);
- newGeometryView.SetIndexBufferView(indexBuffer->GetIndexBufferView(indexFormat));
- drawItem.SetStreamIndices(newGeometryView.GetFullStreamBufferIndices());
- drawItemInfo.m_cachedIndex = static_cast<u32>(m_cachedGeometryViews.size());
- m_cachedGeometryViews.emplace_back(AZStd::move(newGeometryView));
- // --- PSO & SRG ---
- // Get RHI pipeline state from cached RHI pipeline states based on current draw state options
- drawItem.SetPipelineState(GetCurrentPipelineState());
- // Setup per context srg if it exists
- if (m_srgPerContext)
- {
- drawItem.SetShaderResourceGroups(m_srgGroups, 1);
- }
- // Setup per draw srg
- if (drawSrg)
- {
- drawItem.SetUniqueShaderResourceGroup(drawSrg->GetRHIShaderResourceGroup());
- }
- // --- Scissor & Viewport ---
- // Set scissor per draw if scissor is enabled.
- if (m_useScissor)
- {
- drawItem.SetScissors(&m_scissor, 1);
- }
- // Set viewport per draw if viewport is enabled.
- if (m_useViewport)
- {
- drawItem.SetViewports(&m_viewport, 1);
- }
- // Set stencil reference. Used when stencil is enabled.
- drawItem.SetStencilRef(m_stencilRef);
- drawItemInfo.m_sortKey = m_sortKey++;
- m_cachedDrawItems.emplace_back(AZStd::move(drawItemInfo));
- }
- void DynamicDrawContext::DrawLinear(const void* vertexData, uint32_t vertexCount, Data::Instance<ShaderResourceGroup> drawSrg)
- {
- if (!m_initialized)
- {
- AZ_WarningOnce("DynamicDrawContext", false, "%s This function has been disabled because of failed initialization.\n", __FUNCTION__);
- return;
- }
- if (m_drawFinalized)
- {
- AZ_Assert(false, "Can't add draw calls after draw data was finalized");
- return;
- }
-
- if (m_drawSrgLayout && !drawSrg)
- {
- AZ_Assert(false, "drawSrg need to be provided since the shader requires it");
- return;
- }
- if (vertexData == nullptr || vertexCount == 0)
- {
- AZ_Assert(false, "Failed to draw due to invalid vertex data");
- return;
- }
- // Get dynamic buffers for vertex and index buffer. Skip draw if failed to allocate buffers
- uint32_t vertexDataSize = vertexCount * m_perVertexDataSize;
- RHI::Ptr<DynamicBuffer> vertexBuffer;
- vertexBuffer = DynamicDrawInterface::Get()->GetDynamicBuffer(vertexDataSize, RHI::Alignment::InputAssembly);
- if (vertexBuffer == nullptr)
- {
- return;
- }
- DrawItemInfo drawItemInfo{{RHI::MultiDevice::AllDevices}};
- RHI::DrawItem& drawItem = drawItemInfo.m_drawItem;
- // --- Geometry View ---
- RHI::GeometryView newGeometryView{ RHI::MultiDevice::AllDevices };
- newGeometryView.SetDrawArguments(RHI::DrawLinear(vertexCount, 0));
- // Write data to vertex buffer and set up stream buffer views for DrawItem
- // The stream buffer view need to be cached before the frame is end
- vertexBuffer->Write(vertexData, vertexDataSize);
- newGeometryView.AddStreamBufferView(vertexBuffer->GetStreamBufferView(m_perVertexDataSize));
- drawItem.SetStreamIndices(newGeometryView.GetFullStreamBufferIndices());
- drawItemInfo.m_cachedIndex = static_cast<u32>(m_cachedGeometryViews.size());
- m_cachedGeometryViews.emplace_back(AZStd::move(newGeometryView));
- // --- PSO & SRG ---
- // Get RHI pipeline state from cached RHI pipeline states based on current draw state options
- drawItem.SetPipelineState(GetCurrentPipelineState());
- // Setup per context srg if it exists
- if (m_srgPerContext)
- {
- drawItem.SetShaderResourceGroups(m_srgGroups, 1);
- }
- // Setup per draw srg
- if (drawSrg)
- {
- drawItem.SetUniqueShaderResourceGroup(drawSrg->GetRHIShaderResourceGroup());
- }
- // --- Scissor & Viewport ---
- // Set scissor per draw if scissor is enabled.
- if (m_useScissor)
- {
- drawItem.SetScissors(&m_scissor, 1);
- }
- // Set viewport per draw if viewport is enabled.
- if (m_useViewport)
- {
- drawItem.SetViewports(&m_viewport, 1);
- }
- drawItemInfo.m_sortKey = m_sortKey++;
- m_cachedDrawItems.emplace_back(AZStd::move(drawItemInfo));
- }
- Data::Instance<ShaderResourceGroup> DynamicDrawContext::NewDrawSrg()
- {
- if (!m_drawSrgLayout)
- {
- return nullptr;
- }
- Data::Instance<ShaderResourceGroup> drawSrg;
- if (m_nextDrawSrgIdx == m_cachedDrawSrg.size())
- {
- drawSrg = AZ::RPI::ShaderResourceGroup::Create(m_shader->GetAsset(), m_shader->GetSupervariantIndex(), m_drawSrgLayout->GetName());
- m_cachedDrawSrg.push_back(drawSrg);
- }
- else if (m_nextDrawSrgIdx < m_cachedDrawSrg.size())
- {
- drawSrg = m_cachedDrawSrg[m_nextDrawSrgIdx];
- }
- else
- {
- AZ_Assert(false, "Unexpected next draw srg index");
- }
- m_nextDrawSrgIdx++;
- // Set fallback value for shader variant if draw srg contains constant for shader variant fallback
- if (m_hasShaderVariantKeyFallbackEntry)
- {
- // If the dynamic draw context support multiple shader variants, it uses m_currentShaderVariantId to setup srg shader variant fallback key
- if (m_supportShaderVariants)
- {
- drawSrg->SetShaderVariantKeyFallbackValue(m_currentStates.m_shaderVariantId.m_key);
- }
- // otherwise use the m_pipelineState to config the fallback
- else
- {
- m_pipelineState->UpdateSrgVariantFallback(drawSrg);
- }
- }
- return drawSrg;
- }
- Data::Instance<ShaderResourceGroup> DynamicDrawContext::GetPerContextSrg()
- {
- return m_srgPerContext;
- }
- bool DynamicDrawContext::IsVertexSizeValid(uint32_t vertexSize)
- {
- return m_perVertexDataSize == vertexSize;
- }
- RHI::DrawListTag DynamicDrawContext::GetDrawListTag()
- {
- return m_drawListTag;
- }
- const Data::Instance<Shader>& DynamicDrawContext::GetShader() const
- {
- return m_shader;
- }
- void DynamicDrawContext::SetSortKey(RHI::DrawItemSortKey key)
- {
- m_sortKey = key;
- }
- RHI::DrawItemSortKey DynamicDrawContext::GetSortKey() const
- {
- return m_sortKey;
- }
- void DynamicDrawContext::FinalizeDrawList()
- {
- if (m_drawFinalized)
- {
- return;
- }
- AZ_Assert(m_cachedDrawList.size() == 0, "m_cachedDrawList should be cleared ine the end of last frame ");
- for (auto& drawItemInfo : m_cachedDrawItems)
- {
- if (drawItemInfo.m_cachedIndex != InvalidIndex)
- {
- // Get the pointer to geometry view here after we've built all the mesh buffers and won't be resizing the array
- drawItemInfo.m_drawItem.SetGeometryView(&m_cachedGeometryViews[drawItemInfo.m_cachedIndex]);
- }
- RHI::DrawItemProperties drawItemProperties;
- drawItemProperties.m_sortKey = drawItemInfo.m_sortKey;
- drawItemProperties.m_item = &drawItemInfo.m_drawItem;
- drawItemProperties.m_drawFilterMask = m_drawFilter;
- m_cachedDrawList.emplace_back(drawItemProperties);
- }
- m_drawFinalized = true;
- }
- void DynamicDrawContext::SubmitDrawList(ViewPtr view)
- {
- if (!m_initialized || m_outputScope == OutputScopeType::RasterPass)
- {
- return;
- }
- if (!view->HasDrawListTag(m_drawListTag))
- {
- return;
- }
- for (auto& drawItemProperties : m_cachedDrawList)
- {
- view->AddDrawItem(m_drawListTag, drawItemProperties);
- }
- }
- RHI::DrawListView DynamicDrawContext::GetDrawList()
- {
- return m_cachedDrawList;
- }
-
- void DynamicDrawContext::FrameEnd()
- {
- m_sortKey = 0;
- m_cachedDrawItems.clear();
- m_cachedGeometryViews.clear();
- m_cachedDrawList.clear();
- m_nextDrawSrgIdx = 0;
- m_drawFinalized = false;
- for (auto srg:m_cachedDrawSrg)
- {
- srg->ResetViews();
- }
- }
- const RHI::PipelineState* DynamicDrawContext::GetCurrentPipelineState()
- {
- // If m_currentStates wasn't changed, it's safe to return m_rhiPipelineState directly.
- if (!m_currentStates.m_isDirty)
- {
- return m_rhiPipelineState;
- }
- // m_currentStates is dirty. need to update m_currentStates's hash
- m_currentStates.UpdateHash(m_drawStateOptions);
- // search for cached pipeline state by using the updated hash
- auto findResult = m_cachedRhiPipelineStates.find(m_currentStates.m_hash);
- if (findResult == m_cachedRhiPipelineStates.end())
- {
- // Create pipelineState for current m_currentStates
- if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::PrimitiveType))
- {
- if (m_pipelineState->ConstDescriptor().m_inputStreamLayout.GetTopology() != m_currentStates.m_topology)
- {
- RHI::InputStreamLayout& inputStreamLayout = m_pipelineState->InputStreamLayout();
- inputStreamLayout.SetTopology(m_currentStates.m_topology);
- inputStreamLayout.Finalize();
- }
- }
- if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::DepthState))
- {
- m_pipelineState->RenderStatesOverlay().m_depthStencilState.m_depth = m_currentStates.m_depthState;
- }
- if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::StencilState))
- {
- m_pipelineState->RenderStatesOverlay().m_depthStencilState.m_stencil = m_currentStates.m_stencilState;
- }
- if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::FaceCullMode))
- {
- m_pipelineState->RenderStatesOverlay().m_rasterState.m_cullMode = m_currentStates.m_cullMode;
- }
- if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::BlendMode))
- {
- m_pipelineState->RenderStatesOverlay().m_blendState.m_targets[0] = m_currentStates.m_blendState0;
- }
- if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::ShaderVariant))
- {
- m_pipelineState->UpdateShaderVaraintId(m_currentStates.m_shaderVariantId);
- }
- const RHI::PipelineState* pipelineState = m_pipelineState->Finalize();
- m_cachedRhiPipelineStates[m_currentStates.m_hash] = pipelineState;
- m_rhiPipelineState = pipelineState;
- }
- else
- {
- m_rhiPipelineState = findResult->second;
- }
- return m_rhiPipelineState;
- }
- void DynamicDrawContext::OnPipelineStateLookupRebuilt()
- {
- m_cachedRhiPipelineStates.clear();
- EndInit();
- }
- }
- }
|