summaryrefslogtreecommitdiffstats
path: root/Graphics
diff options
context:
space:
mode:
authorEgor Yusov <egor.yusov@gmail.com>2018-11-24 00:07:34 +0000
committerEgor Yusov <egor.yusov@gmail.com>2018-11-24 00:07:34 +0000
commit84d8fedc201a66835f5c234160bda63bbc40f682 (patch)
tree6edc9cac7e76058a5e2b6f61804ab3a04e562e6f /Graphics
parentFixed issue with resource state transition in D3D11 backend (diff)
downloadDiligentCore-84d8fedc201a66835f5c234160bda63bbc40f682.tar.gz
DiligentCore-84d8fedc201a66835f5c234160bda63bbc40f682.zip
Added IShaderResourceBinding::InitializeStaticResources() method to allow explicit initialization of static shader resources in a SRB
Diffstat (limited to 'Graphics')
-rw-r--r--Graphics/GraphicsEngine/interface/PipelineState.h5
-rw-r--r--Graphics/GraphicsEngine/interface/ShaderResourceBinding.h20
-rw-r--r--Graphics/GraphicsEngineD3D11/include/PipelineStateD3D11Impl.h2
-rwxr-xr-xGraphics/GraphicsEngineD3D11/include/ShaderResourceBindingD3D11Impl.h3
-rwxr-xr-xGraphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp13
-rw-r--r--Graphics/GraphicsEngineD3D11/src/PipelineStateD3D11Impl.cpp5
-rw-r--r--Graphics/GraphicsEngineD3D11/src/ShaderResourceBindingD3D11Impl.cpp15
-rw-r--r--Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.h3
-rw-r--r--Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp15
-rw-r--r--Graphics/GraphicsEngineD3D12/src/RootSignature.cpp18
-rw-r--r--Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp25
-rw-r--r--Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.h2
-rw-r--r--Graphics/GraphicsEngineOpenGL/include/ShaderResourceBindingGLImpl.h2
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp4
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/ShaderResourceBindingGLImpl.cpp5
-rw-r--r--Graphics/GraphicsEngineVulkan/include/PipelineLayout.h14
-rw-r--r--Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h2
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.h7
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.h2
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderVkImpl.h6
-rw-r--r--Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp10
-rw-r--r--Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp26
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp33
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp16
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp6
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp2
27 files changed, 179 insertions, 84 deletions
diff --git a/Graphics/GraphicsEngine/interface/PipelineState.h b/Graphics/GraphicsEngine/interface/PipelineState.h
index ca12dda4..2169eefb 100644
--- a/Graphics/GraphicsEngine/interface/PipelineState.h
+++ b/Graphics/GraphicsEngine/interface/PipelineState.h
@@ -190,7 +190,10 @@ public:
/// \param [out] ppShaderResourceBinding - memory location where pointer to the new shader resource
/// binding object is written.
- virtual void CreateShaderResourceBinding( IShaderResourceBinding **ppShaderResourceBinding ) = 0;
+ /// \param [in] InitStaticResources - if set to true, the method will initialize static resources in
+ /// the created object, which has the exact same effect as calling
+ /// IShaderResourceBinding::InitializeStaticResources().
+ virtual void CreateShaderResourceBinding( IShaderResourceBinding **ppShaderResourceBinding, bool InitStaticResources = false ) = 0;
/// Checks if this pipeline state object is compatible with another PSO
diff --git a/Graphics/GraphicsEngine/interface/ShaderResourceBinding.h b/Graphics/GraphicsEngine/interface/ShaderResourceBinding.h
index 2c177926..9b71f06c 100644
--- a/Graphics/GraphicsEngine/interface/ShaderResourceBinding.h
+++ b/Graphics/GraphicsEngine/interface/ShaderResourceBinding.h
@@ -58,7 +58,7 @@ public:
/// Any combination of Diligent::SHADER_TYPE may be specified.
/// \param [in] pResMapping - Shader resource mapping, where required resources will be looked up
/// \param [in] Flags - Additional flags. See Diligent::BIND_SHADER_RESOURCES_FLAGS.
- virtual void BindResources(Uint32 ShaderFlags, IResourceMapping *pResMapping, Uint32 Flags) = 0;
+ virtual void BindResources(Uint32 ShaderFlags, IResourceMapping* pResMapping, Uint32 Flags) = 0;
/// Returns variable
@@ -84,6 +84,24 @@ public:
/// \remark Only mutable and dynamic variables can be accessed through this method.
/// Static variables are accessed through the Shader object.
virtual IShaderVariable* GetVariable(SHADER_TYPE ShaderType, Uint32 Index) = 0;
+
+
+ /// Initializes static resources
+
+ /// If shaders in the pipeline state contain static resources
+ /// (see Diligent::SHADER_VARIABLE_TYPE_STATIC), this method must be called
+ /// once to initialize static resources in this shader resource binding object.
+ /// The method must be called after all static variables are initialized
+ /// in the shaders.
+ /// \param [in] pPipelineState - Pipeline state to copy static shader resource
+ /// bindings from. The pipeline state must be compatible
+ /// with this shader resource binding object.
+ /// If null pointer is provided, the pipeline state
+ /// that this SRB object was created from is used.
+ /// \note The method must be called exactly once. If static resources have
+ /// already been initialized and the method is called again, it will have
+ /// no effect and a warning messge will be displayed.
+ virtual void InitializeStaticResources(const IPipelineState* pPipelineState = nullptr) = 0;
};
}
diff --git a/Graphics/GraphicsEngineD3D11/include/PipelineStateD3D11Impl.h b/Graphics/GraphicsEngineD3D11/include/PipelineStateD3D11Impl.h
index 2ea2d8da..4d3776c8 100644
--- a/Graphics/GraphicsEngineD3D11/include/PipelineStateD3D11Impl.h
+++ b/Graphics/GraphicsEngineD3D11/include/PipelineStateD3D11Impl.h
@@ -68,7 +68,7 @@ public:
virtual ID3D11HullShader* GetD3D11HullShader()override final;
virtual ID3D11ComputeShader* GetD3D11ComputeShader()override final;
- virtual void CreateShaderResourceBinding( IShaderResourceBinding **ppShaderResourceBinding )override final;
+ virtual void CreateShaderResourceBinding( IShaderResourceBinding **ppShaderResourceBinding, bool InitStaticResources )override final;
virtual bool IsCompatibleWith(const IPipelineState *pPSO)const override final;
diff --git a/Graphics/GraphicsEngineD3D11/include/ShaderResourceBindingD3D11Impl.h b/Graphics/GraphicsEngineD3D11/include/ShaderResourceBindingD3D11Impl.h
index 479ec282..9c6c354d 100755
--- a/Graphics/GraphicsEngineD3D11/include/ShaderResourceBindingD3D11Impl.h
+++ b/Graphics/GraphicsEngineD3D11/include/ShaderResourceBindingD3D11Impl.h
@@ -58,10 +58,11 @@ public:
virtual IShaderVariable* GetVariable(SHADER_TYPE ShaderType, Uint32 Index)override final;
+ virtual void InitializeStaticResources(const IPipelineState* pPipelineState)override final;
+
ShaderResourceCacheD3D11& GetResourceCache (Uint32 Ind){VERIFY_EXPR(Ind < m_NumActiveShaders); return m_pBoundResourceCaches[Ind];}
ShaderResourceLayoutD3D11& GetResourceLayout(Uint32 Ind){VERIFY_EXPR(Ind < m_NumActiveShaders); return m_pResourceLayouts[Ind];}
- void BindStaticShaderResources();
inline bool IsStaticResourcesBound(){return m_bIsStaticResourcesBound;}
Uint32 GetNumActiveShaders()
diff --git a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp
index 3456ee47..f64409cc 100755
--- a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp
+++ b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp
@@ -175,17 +175,22 @@ namespace Diligent
}
#endif
- if(!pShaderResBindingD3D11->IsStaticResourcesBound())
- pShaderResBindingD3D11->BindStaticShaderResources();
-
auto NumShaders = pShaderResBindingD3D11->GetNumActiveShaders();
VERIFY(NumShaders == pdbgPipelineStateD3D11->GetNumShaders(), "Number of active shaders in shader resource binding is not consistent with the number of shaders in the pipeline state");
#ifdef DEVELOPMENT
+ bool StaticResourcesPresent = false;
for (Uint32 s = 0; s < NumShaders; ++s)
{
pShaderResBindingD3D11->GetResourceLayout(s).dvpVerifyBindings();
// Static resource bindings are verified in BindStaticShaderResources()
+ auto* pShaderD3D11 = ValidatedCast<ShaderD3D11Impl>(ppdbgShaders[s]);
+ if (pShaderD3D11->GetStaticResourceLayout().GetTotalResourceCount() > 0)
+ StaticResourcesPresent = true;
+ }
+ if (StaticResourcesPresent && !pShaderResBindingD3D11->IsStaticResourcesBound())
+ {
+ LOG_ERROR_MESSAGE("Static resources have not been initialized in the shader resource binding object. Please call IShaderResourceBinding::InitializeStaticResources().");
}
#endif
@@ -767,7 +772,7 @@ namespace Diligent
auto* pd3d11InputLayout = m_pPipelineState->GetD3D11InputLayout();
if (pd3d11InputLayout != nullptr && !m_bCommittedD3D11VBsUpToDate)
{
- VERIFY( m_NumVertexStreams >= m_pPipelineState->GetNumBufferSlotsUsed(), "Currently bound pipeline state '", m_pPipelineState->GetDesc().Name, "' expects ", m_pPipelineState->GetNumBufferSlotsUsed(), " input buffer slots, but only ", m_NumVertexStreams, " is bound");
+ DEV_CHECK_ERR( m_NumVertexStreams >= m_pPipelineState->GetNumBufferSlotsUsed(), "Currently bound pipeline state '", m_pPipelineState->GetDesc().Name, "' expects ", m_pPipelineState->GetNumBufferSlotsUsed(), " input buffer slots, but only ", m_NumVertexStreams, " is bound");
CommitD3D11VertexBuffers(m_pPipelineState, drawAttribs.Flags & DRAW_FLAG_TRANSITION_VERTEX_BUFFERS);
}
diff --git a/Graphics/GraphicsEngineD3D11/src/PipelineStateD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/PipelineStateD3D11Impl.cpp
index d61c85e1..f3a37ddc 100644
--- a/Graphics/GraphicsEngineD3D11/src/PipelineStateD3D11Impl.cpp
+++ b/Graphics/GraphicsEngineD3D11/src/PipelineStateD3D11Impl.cpp
@@ -129,6 +129,7 @@ PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pRefCoun
auto &SRBAllocator = pRenderDeviceD3D11->GetSRBAllocator();
m_pDefaultShaderResBinding.reset( NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingD3D11Impl instance", ShaderResourceBindingD3D11Impl, this)(this, true) );
+ m_pDefaultShaderResBinding->InitializeStaticResources(nullptr);
}
@@ -159,11 +160,13 @@ ID3D11InputLayout* PipelineStateD3D11Impl::GetD3D11InputLayout()
return m_pd3d11InputLayout;
}
-void PipelineStateD3D11Impl::CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding)
+void PipelineStateD3D11Impl::CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding, bool InitStaticResources)
{
auto* pRenderDeviceD3D11 = ValidatedCast<RenderDeviceD3D11Impl>( GetDevice() );
auto &SRBAllocator = pRenderDeviceD3D11->GetSRBAllocator();
auto pShaderResBinding = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingD3D11Impl instance", ShaderResourceBindingD3D11Impl)(this, false);
+ if (InitStaticResources)
+ pShaderResBinding->InitializeStaticResources(nullptr);
pShaderResBinding->QueryInterface(IID_ShaderResourceBinding, reinterpret_cast<IObject**>(static_cast<IShaderResourceBinding**>(ppShaderResourceBinding)));
}
diff --git a/Graphics/GraphicsEngineD3D11/src/ShaderResourceBindingD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/ShaderResourceBindingD3D11Impl.cpp
index 83f0dac1..f63e64f0 100644
--- a/Graphics/GraphicsEngineD3D11/src/ShaderResourceBindingD3D11Impl.cpp
+++ b/Graphics/GraphicsEngineD3D11/src/ShaderResourceBindingD3D11Impl.cpp
@@ -111,15 +111,24 @@ void ShaderResourceBindingD3D11Impl::BindResources(Uint32 ShaderFlags, IResource
}
}
-void ShaderResourceBindingD3D11Impl::BindStaticShaderResources()
+void ShaderResourceBindingD3D11Impl::InitializeStaticResources(const IPipelineState* pPipelineState)
{
if (m_bIsStaticResourcesBound)
{
- LOG_ERROR("Static resources already bound");
+ LOG_WARNING_MESSAGE("Static resources have already been initialized in this shader resource binding object. The operation will be ignored.");
return;
}
- auto *pPSOD3D11 = ValidatedCast<PipelineStateD3D11Impl>(GetPipelineState());
+ if (pPipelineState == nullptr)
+ {
+ pPipelineState = GetPipelineState();
+ }
+ else
+ {
+ DEV_CHECK_ERR(pPipelineState->IsCompatibleWith(GetPipelineState()), "The pipeline state is not compatible with this SRB");
+ }
+
+ const auto *pPSOD3D11 = ValidatedCast<const PipelineStateD3D11Impl>(pPipelineState);
auto ppShaders = pPSOD3D11->GetShaders();
auto NumShaders = pPSOD3D11->GetNumShaders();
VERIFY_EXPR(NumShaders == m_NumActiveShaders);
diff --git a/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.h
index a0f9ab76..0ecda4a1 100644
--- a/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.h
+++ b/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.h
@@ -51,7 +51,7 @@ public:
virtual ID3D12PipelineState *GetD3D12PipelineState()const override final{return m_pd3d12PSO;}
- virtual void CreateShaderResourceBinding( IShaderResourceBinding **ppShaderResourceBinding )override final;
+ virtual void CreateShaderResourceBinding( IShaderResourceBinding **ppShaderResourceBinding, bool InitStaticResources )override final;
virtual bool IsCompatibleWith(const IPipelineState *pPSO)const override final;
diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.h
index 5a237414..2685dde2 100644
--- a/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.h
+++ b/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.h
@@ -58,6 +58,8 @@ public:
virtual Uint32 GetVariableCount(SHADER_TYPE ShaderType) const override final;
virtual IShaderVariable* GetVariable(SHADER_TYPE ShaderType, Uint32 Index)override final;
+
+ virtual void InitializeStaticResources(const IPipelineState* pPipelineState)override final;
ShaderResourceCacheD3D12& GetResourceCache(){return m_ShaderResourceCache;}
@@ -66,7 +68,6 @@ public:
#endif
bool StaticResourcesInitialized()const{return m_bStaticResourcesInitialized;}
- void InitializeStaticResources(const PipelineStateD3D12Impl* pPSO);
private:
diff --git a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp
index 85d8ee0a..8fc17cb2 100644
--- a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp
+++ b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp
@@ -224,6 +224,7 @@ PipelineStateD3D12Impl :: PipelineStateD3D12Impl(IReferenceCounters* pRefCo
auto& SRBAllocator = pDeviceD3D12->GetSRBAllocator();
// Default shader resource binding must be initialized after resource layouts are parsed!
m_pDefaultShaderResBinding.reset( NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingD3D12Impl instance", ShaderResourceBindingD3D12Impl, this)(this, true) );
+ m_pDefaultShaderResBinding->InitializeStaticResources(this);
}
m_ShaderResourceLayoutHash = m_RootSig.GetHash();
@@ -245,10 +246,12 @@ PipelineStateD3D12Impl::~PipelineStateD3D12Impl()
IMPLEMENT_QUERY_INTERFACE( PipelineStateD3D12Impl, IID_PipelineStateD3D12, TPipelineStateBase )
-void PipelineStateD3D12Impl::CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding)
+void PipelineStateD3D12Impl::CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding, bool InitStaticResources )
{
auto& SRBAllocator = m_pDevice->GetSRBAllocator();
auto pResBindingD3D12 = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingD3D12Impl instance", ShaderResourceBindingD3D12Impl)(this, false);
+ if (InitStaticResources)
+ pResBindingD3D12->InitializeStaticResources(nullptr);
pResBindingD3D12->QueryInterface(IID_ShaderResourceBinding, reinterpret_cast<IObject**>(ppShaderResourceBinding));
}
@@ -341,13 +344,13 @@ ShaderResourceCacheD3D12* PipelineStateD3D12Impl::CommitAndTransitionShaderResou
return nullptr;
}
}
-#endif
- // First time only, copy static shader resources to the cache
- if(!pResBindingD3D12Impl->StaticResourcesInitialized())
- pResBindingD3D12Impl->InitializeStaticResources(this);
+ if( (m_RootSig.GetTotalSrvCbvUavSlots(SHADER_VARIABLE_TYPE_STATIC) != 0 ||
+ m_RootSig.GetTotalRootViews(SHADER_VARIABLE_TYPE_STATIC) != 0) && !pResBindingD3D12Impl->StaticResourcesInitialized() )
+ {
+ LOG_ERROR_MESSAGE("Static resources have not been initialized in the shader resource binding object. Please call IShaderResourceBinding::InitializeStaticResources().");
+ }
-#ifdef DEVELOPMENT
pResBindingD3D12Impl->dvpVerifyResourceBindings(this);
#endif
diff --git a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp
index d874d45e..67369355 100644
--- a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp
+++ b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp
@@ -1055,15 +1055,17 @@ void RootSignature::CommitRootViews(ShaderResourceCacheD3D12& ResourceCache,
#endif
auto& Res = ResourceCache.GetRootTable(RootInd).GetResource(0, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, dbgShaderType);
- auto *pBuffToTransition = Res.pObject.RawPtr<BufferD3D12Impl>();
- if (pBuffToTransition->IsInKnownState() && !pBuffToTransition->CheckState(RESOURCE_STATE_CONSTANT_BUFFER) )
- Ctx.TransitionResource(pBuffToTransition, RESOURCE_STATE_CONSTANT_BUFFER);
+ if (auto* pBuffToTransition = Res.pObject.RawPtr<BufferD3D12Impl>())
+ {
+ if (pBuffToTransition->IsInKnownState() && !pBuffToTransition->CheckState(RESOURCE_STATE_CONSTANT_BUFFER) )
+ Ctx.TransitionResource(pBuffToTransition, RESOURCE_STATE_CONSTANT_BUFFER);
- D3D12_GPU_VIRTUAL_ADDRESS CBVAddress = pBuffToTransition->GetGPUAddress(pCtx);
- if(IsCompute)
- Ctx.GetCommandList()->SetComputeRootConstantBufferView(RootInd, CBVAddress);
- else
- Ctx.GetCommandList()->SetGraphicsRootConstantBufferView(RootInd, CBVAddress);
+ D3D12_GPU_VIRTUAL_ADDRESS CBVAddress = pBuffToTransition->GetGPUAddress(pCtx);
+ if(IsCompute)
+ Ctx.GetCommandList()->SetComputeRootConstantBufferView(RootInd, CBVAddress);
+ else
+ Ctx.GetCommandList()->SetGraphicsRootConstantBufferView(RootInd, CBVAddress);
+ }
}
}
diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp
index cec03f11..ff569364 100644
--- a/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp
+++ b/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp
@@ -154,13 +154,26 @@ void ShaderResourceBindingD3D12Impl::dvpVerifyResourceBindings(const PipelineSta
#endif
-void ShaderResourceBindingD3D12Impl::InitializeStaticResources(const PipelineStateD3D12Impl* pPSO)
+void ShaderResourceBindingD3D12Impl::InitializeStaticResources(const IPipelineState* pPSO)
{
- VERIFY(!StaticResourcesInitialized(), "Static resources have already been initialized");
- VERIFY(pPSO->IsCompatibleWith(GetPipelineState()), "Currently bound pipeline state is not compatible with this SRB");
+ if (StaticResourcesInitialized())
+ {
+ LOG_WARNING_MESSAGE("Static resources have already been initialized in this shader resource binding object. The operation will be ignored.");
+ return;
+ }
+
+ if (pPSO == nullptr)
+ {
+ pPSO = GetPipelineState();
+ }
+ else
+ {
+ DEV_CHECK_ERR(pPSO->IsCompatibleWith(GetPipelineState()), "The pipeline state is not compatible with this SRB");
+ }
- auto NumShaders = pPSO->GetNumShaders();
- auto ppShaders = pPSO->GetShaders();
+ auto* pPSO12 = ValidatedCast<const PipelineStateD3D12Impl>(pPSO);
+ auto NumShaders = pPSO12->GetNumShaders();
+ auto ppShaders = pPSO12->GetShaders();
// Copy static resources
for (Uint32 s = 0; s < NumShaders; ++s)
{
@@ -168,7 +181,7 @@ void ShaderResourceBindingD3D12Impl::InitializeStaticResources(const PipelineSta
#ifdef DEVELOPMENT
pShader->DvpVerifyStaticResourceBindings();
#endif
- const auto& ShaderResLayout = pPSO->GetShaderResLayout(s);
+ const auto& ShaderResLayout = pPSO12->GetShaderResLayout(s);
auto& StaticResLayout = pShader->GetStaticResLayout();
auto& StaticResCache = pShader->GetStaticResCache();
StaticResLayout.CopyStaticResourceDesriptorHandles(StaticResCache, ShaderResLayout, m_ShaderResourceCache);
diff --git a/Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.h b/Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.h
index c6f54964..6e03df2e 100644
--- a/Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.h
+++ b/Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.h
@@ -50,7 +50,7 @@ public:
virtual void BindShaderResources( IResourceMapping *pResourceMapping, Uint32 Flags )override final;
- virtual void CreateShaderResourceBinding( IShaderResourceBinding **ppShaderResourceBinding )override final;
+ virtual void CreateShaderResourceBinding( IShaderResourceBinding **ppShaderResourceBinding, bool InitStaticResources )override final;
virtual bool IsCompatibleWith(const IPipelineState *pPSO)const override final;
diff --git a/Graphics/GraphicsEngineOpenGL/include/ShaderResourceBindingGLImpl.h b/Graphics/GraphicsEngineOpenGL/include/ShaderResourceBindingGLImpl.h
index 6500ad29..02193dd9 100644
--- a/Graphics/GraphicsEngineOpenGL/include/ShaderResourceBindingGLImpl.h
+++ b/Graphics/GraphicsEngineOpenGL/include/ShaderResourceBindingGLImpl.h
@@ -55,6 +55,8 @@ public:
virtual IShaderVariable* GetVariable(SHADER_TYPE ShaderType, Uint32 Index)override final;
+ virtual void InitializeStaticResources(const IPipelineState* pPipelineState)override final;
+
GLProgramResources &GetProgramResources(SHADER_TYPE ShaderType, PipelineStateGLImpl *pdbgPSO);
private:
diff --git a/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp
index 19503efb..57c2e4a4 100644
--- a/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp
+++ b/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp
@@ -152,11 +152,13 @@ void PipelineStateGLImpl::BindShaderResources(IResourceMapping *pResourceMapping
}
}
-void PipelineStateGLImpl::CreateShaderResourceBinding(IShaderResourceBinding **ppShaderResourceBinding)
+void PipelineStateGLImpl::CreateShaderResourceBinding(IShaderResourceBinding **ppShaderResourceBinding, bool InitStaticResources)
{
auto *pRenderDeviceGL = ValidatedCast<RenderDeviceGLImpl>( GetDevice() );
auto &SRBAllocator = pRenderDeviceGL->GetSRBAllocator();
auto pResBinding = NEW_RC_OBJ( SRBAllocator, "ShaderResourceBindingGLImpl instance", ShaderResourceBindingGLImpl)(this);
+ if (InitStaticResources)
+ pResBinding->InitializeStaticResources(nullptr);
pResBinding->QueryInterface(IID_ShaderResourceBinding, reinterpret_cast<IObject**>(ppShaderResourceBinding));
}
diff --git a/Graphics/GraphicsEngineOpenGL/src/ShaderResourceBindingGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/ShaderResourceBindingGLImpl.cpp
index 4041afed..d6cae215 100644
--- a/Graphics/GraphicsEngineOpenGL/src/ShaderResourceBindingGLImpl.cpp
+++ b/Graphics/GraphicsEngineOpenGL/src/ShaderResourceBindingGLImpl.cpp
@@ -113,4 +113,9 @@ GLProgramResources &ShaderResourceBindingGLImpl::GetProgramResources(SHADER_TYPE
return m_DynamicProgResources[ShaderInd];
}
+void ShaderResourceBindingGLImpl::InitializeStaticResources(const IPipelineState* pPipelineState)
+{
+
+}
+
}
diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineLayout.h b/Graphics/GraphicsEngineVulkan/include/PipelineLayout.h
index a2ebd353..fbe0ea20 100644
--- a/Graphics/GraphicsEngineVulkan/include/PipelineLayout.h
+++ b/Graphics/GraphicsEngineVulkan/include/PipelineLayout.h
@@ -86,8 +86,8 @@ public:
{
std::vector<VkDescriptorSet> vkSets;
std::vector<uint32_t> DynamicOffsets;
- ShaderResourceCacheVk* pResourceCache = nullptr;
- VkPipelineBindPoint BindPoint = VK_PIPELINE_BIND_POINT_MAX_ENUM;
+ const ShaderResourceCacheVk* pResourceCache = nullptr;
+ VkPipelineBindPoint BindPoint = VK_PIPELINE_BIND_POINT_MAX_ENUM;
Uint32 SetCout = 0;
Uint32 DynamicOffsetCount = 0;
#ifdef _DEBUG
@@ -120,11 +120,11 @@ public:
// may not be possible until draw command time because dynamic offsets are
// set by the same Vulkan command. If there are no dynamic descriptors, this
// function also binds descriptor sets rightaway.
- void PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkImpl,
- bool IsCompute,
- ShaderResourceCacheVk& ResourceCache,
- DescriptorSetBindInfo& BindInfo,
- VkDescriptorSet VkDynamicDescrSet)const;
+ void PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkImpl,
+ bool IsCompute,
+ const ShaderResourceCacheVk& ResourceCache,
+ DescriptorSetBindInfo& BindInfo,
+ VkDescriptorSet VkDynamicDescrSet)const;
// Computes dynamic offsets and binds descriptor sets
void BindDescriptorSetsWithDynamicOffsets(DeviceContextVkImpl* pCtxVkImpl,
diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h
index 1475c9ff..0d2988c7 100644
--- a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h
+++ b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h
@@ -56,7 +56,7 @@ public:
virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject** ppInterface );
- virtual void CreateShaderResourceBinding( IShaderResourceBinding **ppShaderResourceBinding )override final;
+ virtual void CreateShaderResourceBinding( IShaderResourceBinding **ppShaderResourceBinding, bool InitStaticResources )override final;
virtual bool IsCompatibleWith(const IPipelineState* pPSO)const override final;
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.h b/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.h
index 6ebea962..d61a04cf 100644
--- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.h
+++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.h
@@ -58,10 +58,11 @@ public:
virtual IShaderVariable* GetVariable(SHADER_TYPE ShaderType, Uint32 Index)override final;
- ShaderResourceCacheVk& GetResourceCache(){return m_ShaderResourceCache;}
+ virtual void InitializeStaticResources(const IPipelineState* pPipelineState)override final;
- bool StaticResourcesInitialized()const{return m_bStaticResourcesInitialized;}
- void SetStaticResourcesInitialized(){m_bStaticResourcesInitialized = true;}
+ ShaderResourceCacheVk& GetResourceCache() { return m_ShaderResourceCache; }
+
+ bool StaticResourcesInitialized() const { return m_bStaticResourcesInitialized; }
private:
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.h b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.h
index 2bfc65ca..c53d4d1f 100644
--- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.h
+++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.h
@@ -226,7 +226,7 @@ public:
// Copies static resources from SrcResourceCache defined by SrcLayout
// to DstResourceCache defined by this layout
void InitializeStaticResources(const ShaderResourceLayoutVk& SrcLayout,
- ShaderResourceCacheVk& SrcResourceCache,
+ const ShaderResourceCacheVk& SrcResourceCache,
ShaderResourceCacheVk& DstResourceCache)const;
#ifdef DEVELOPMENT
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderVkImpl.h b/Graphics/GraphicsEngineVulkan/include/ShaderVkImpl.h
index d42973c2..ca0373bf 100644
--- a/Graphics/GraphicsEngineVulkan/include/ShaderVkImpl.h
+++ b/Graphics/GraphicsEngineVulkan/include/ShaderVkImpl.h
@@ -77,13 +77,13 @@ public:
}
const std::shared_ptr<const SPIRVShaderResources>& GetShaderResources()const{return m_pShaderResources;}
- const ShaderResourceLayoutVk& GetStaticResLayout()const{return m_StaticResLayout;}
- ShaderResourceCacheVk& GetStaticResCache(){return m_StaticResCache;}
+ const ShaderResourceLayoutVk& GetStaticResLayout()const { return m_StaticResLayout; }
+ const ShaderResourceCacheVk& GetStaticResCache() const { return m_StaticResCache; }
const char* GetEntryPoint() const { return m_EntryPoint.c_str(); }
#ifdef DEVELOPMENT
- void DvpVerifyStaticResourceBindings();
+ void DvpVerifyStaticResourceBindings()const;
#endif
private:
diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp
index 04503613..9260450b 100644
--- a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp
@@ -421,11 +421,11 @@ void PipelineLayout::InitResourceCache(RenderDeviceVkImpl* pDeviceVkImpl, Shader
}
}
-void PipelineLayout::PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkImpl,
- bool IsCompute,
- ShaderResourceCacheVk& ResourceCache,
- DescriptorSetBindInfo& BindInfo,
- VkDescriptorSet VkDynamicDescrSet)const
+void PipelineLayout::PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkImpl,
+ bool IsCompute,
+ const ShaderResourceCacheVk& ResourceCache,
+ DescriptorSetBindInfo& BindInfo,
+ VkDescriptorSet VkDynamicDescrSet)const
{
#ifdef _DEBUG
BindInfo.vkSets.clear();
diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp
index 537411aa..dbdbd63c 100644
--- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp
@@ -427,6 +427,7 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters* pRefCounters
auto& SRBAllocator = pDeviceVk->GetSRBAllocator();
// Default shader resource binding must be initialized after resource layouts are parsed!
m_pDefaultShaderResBinding.reset( NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingVkImpl instance", ShaderResourceBindingVkImpl, this)(this, true) );
+ m_pDefaultShaderResBinding->InitializeStaticResources(this);
}
m_ShaderResourceLayoutHash = m_PipelineLayout.GetHash();
@@ -460,10 +461,12 @@ PipelineStateVkImpl::~PipelineStateVkImpl()
IMPLEMENT_QUERY_INTERFACE( PipelineStateVkImpl, IID_PipelineStateVk, TPipelineStateBase )
-void PipelineStateVkImpl::CreateShaderResourceBinding(IShaderResourceBinding **ppShaderResourceBinding)
+void PipelineStateVkImpl::CreateShaderResourceBinding(IShaderResourceBinding **ppShaderResourceBinding, bool InitStaticResources)
{
auto& SRBAllocator = m_pDevice->GetSRBAllocator();
auto pResBindingVk = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingVkImpl instance", ShaderResourceBindingVkImpl)(this, false);
+ if (InitStaticResources)
+ pResBindingVk->InitializeStaticResources(nullptr);
pResBindingVk->QueryInterface(IID_ShaderResourceBinding, reinterpret_cast<IObject**>(ppShaderResourceBinding));
}
@@ -545,25 +548,14 @@ void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBind
return;
}
}
-#endif
-
- auto& ResourceCache = pResBindingVkImpl->GetResourceCache();
- // First time only, copy static shader resources to the cache
- if (!pResBindingVkImpl->StaticResourcesInitialized())
+ if (m_HasStaticResources && !pResBindingVkImpl->StaticResourcesInitialized())
{
- for (Uint32 s = 0; s < m_NumShaders; ++s)
- {
- auto* pShaderVk = GetShader<ShaderVkImpl>(s);
-#ifdef DEVELOPMENT
- pShaderVk->DvpVerifyStaticResourceBindings();
-#endif
- auto& StaticResLayout = pShaderVk->GetStaticResLayout();
- auto& StaticResCache = pShaderVk->GetStaticResCache();
- m_ShaderResourceLayouts[s].InitializeStaticResources(StaticResLayout, StaticResCache, ResourceCache);
- }
- pResBindingVkImpl->SetStaticResourcesInitialized();
+ LOG_ERROR_MESSAGE("Static resources have not been initialized in the shader resource binding object. Please call IShaderResourceBinding::InitializeStaticResources().");
}
+#endif
+
+ auto& ResourceCache = pResBindingVkImpl->GetResourceCache();
#ifdef DEVELOPMENT
for (Uint32 s = 0; s < m_NumShaders; ++s)
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp
index b531493e..d3f885a3 100644
--- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp
@@ -137,4 +137,37 @@ IShaderVariable* ShaderResourceBindingVkImpl::GetVariable(SHADER_TYPE ShaderType
return m_pShaderVarMgrs[ResLayoutInd].GetVariable(Index);
}
+void ShaderResourceBindingVkImpl::InitializeStaticResources(const IPipelineState* pPipelineState)
+{
+ if (StaticResourcesInitialized())
+ {
+ LOG_WARNING_MESSAGE("Static resources have already been initialized in this shader resource binding object. The operation will be ignored.");
+ return;
+ }
+
+ if (pPipelineState == nullptr)
+ {
+ pPipelineState = GetPipelineState();
+ }
+ else
+ {
+ DEV_CHECK_ERR(pPipelineState->IsCompatibleWith(GetPipelineState()), "The pipeline state is not compatible with this SRB");
+ }
+
+ auto* pPSOVK = ValidatedCast<const PipelineStateVkImpl>(pPipelineState);
+ for (Uint32 s = 0; s < m_NumShaders; ++s)
+ {
+ const auto* pShaderVk = pPSOVK->GetShader<const ShaderVkImpl>(s);
+#ifdef DEVELOPMENT
+ pShaderVk->DvpVerifyStaticResourceBindings();
+#endif
+ const auto& StaticResLayout = pShaderVk->GetStaticResLayout();
+ const auto& StaticResCache = pShaderVk->GetStaticResCache();
+ const auto& ShaderResourceLayouts = pPSOVK->GetShaderResLayout(s);
+ ShaderResourceLayouts.InitializeStaticResources(StaticResLayout, StaticResCache, m_ShaderResourceCache);
+ }
+
+ m_bStaticResourcesInitialized = true;
+}
+
}
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp
index 9e1fb7ca..888e4d00 100644
--- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp
@@ -111,7 +111,7 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl *pCtxVkImpl)
case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer:
{
auto* pBufferVk = Res.pObject.RawPtr<BufferVkImpl>();
- if (pBufferVk->IsInKnownState())
+ if (pBufferVk != nullptr && pBufferVk->IsInKnownState())
{
RESOURCE_STATE RequiredState = RESOURCE_STATE_CONSTANT_BUFFER;
VERIFY_EXPR((ResourceStateFlagsToVkAccessFlags(RequiredState) & VK_ACCESS_UNIFORM_READ_BIT) == VK_ACCESS_UNIFORM_READ_BIT);
@@ -139,8 +139,8 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl *pCtxVkImpl)
case SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer:
{
auto* pBuffViewVk = Res.pObject.RawPtr<BufferViewVkImpl>();
- auto* pBufferVk = ValidatedCast<BufferVkImpl>(pBuffViewVk->GetBuffer());
- if (pBufferVk->IsInKnownState())
+ auto* pBufferVk = pBuffViewVk != nullptr ? ValidatedCast<BufferVkImpl>(pBuffViewVk->GetBuffer()) : nullptr;
+ if (pBufferVk != nullptr && pBufferVk->IsInKnownState())
{
RESOURCE_STATE RequiredState = (Res.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer) ?
RESOURCE_STATE_SHADER_RESOURCE : RESOURCE_STATE_UNORDERED_ACCESS;
@@ -173,8 +173,8 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl *pCtxVkImpl)
case SPIRVShaderResourceAttribs::ResourceType::StorageImage:
{
auto* pTextureViewVk = Res.pObject.RawPtr<TextureViewVkImpl>();
- auto* pTextureVk = ValidatedCast<TextureVkImpl>(pTextureViewVk->GetTexture());
- if (pTextureVk->IsInKnownState())
+ auto* pTextureVk = pTextureViewVk != nullptr ? ValidatedCast<TextureVkImpl>(pTextureViewVk->GetTexture()) : nullptr;
+ if (pTextureVk != nullptr && pTextureVk->IsInKnownState())
{
// The image subresources for a storage image must be in the VK_IMAGE_LAYOUT_GENERAL layout in
// order to access its data in a shader (13.1.1)
@@ -390,7 +390,7 @@ Uint32 ShaderResourceCacheVk::GetDynamicBufferOffsets(DeviceContextVkImpl *pCtxV
break;
const auto* pBufferVk = Res.pObject.RawPtr<const BufferVkImpl>();
- auto Offset = pBufferVk->GetDynamicOffset(CtxId, pCtxVkImpl);
+ auto Offset = pBufferVk != nullptr ? pBufferVk->GetDynamicOffset(CtxId, pCtxVkImpl) : 0;
Offsets[OffsetInd++] = Offset;
++res;
@@ -403,8 +403,8 @@ Uint32 ShaderResourceCacheVk::GetDynamicBufferOffsets(DeviceContextVkImpl *pCtxV
break;
const auto* pBufferVkView = Res.pObject.RawPtr<const BufferViewVkImpl>();
- const auto* pBufferVk = pBufferVkView->GetBufferVk();
- auto Offset = pBufferVk->GetDynamicOffset(CtxId, pCtxVkImpl);
+ const auto* pBufferVk = pBufferVkView != nullptr ? pBufferVkView->GetBufferVk() : 0;
+ auto Offset = pBufferVk != nullptr ? pBufferVk->GetDynamicOffset(CtxId, pCtxVkImpl) : 0;
Offsets[OffsetInd++] = Offset;
++res;
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp
index b9a5a346..d0ba2d3d 100644
--- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp
@@ -683,7 +683,7 @@ bool ShaderResourceLayoutVk::VkResource::IsBound(Uint32 ArrayIndex, const Shader
void ShaderResourceLayoutVk::InitializeStaticResources(const ShaderResourceLayoutVk& SrcLayout,
- ShaderResourceCacheVk& SrcResourceCache,
+ const ShaderResourceCacheVk& SrcResourceCache,
ShaderResourceCacheVk& DstResourceCache)const
{
auto NumStaticResources = m_NumResources[SHADER_VARIABLE_TYPE_STATIC];
@@ -706,7 +706,9 @@ void ShaderResourceLayoutVk::InitializeStaticResources(const ShaderResourceLayou
for (Uint32 ArrInd = 0; ArrInd < DstRes.SpirvAttribs.ArraySize; ++ArrInd)
{
auto SrcOffset = SrcRes.CacheOffset + ArrInd;
- IDeviceObject* pObject = SrcResourceCache.GetDescriptorSet(SrcRes.DescriptorSet).GetResource(SrcOffset).pObject;
+ const auto& SrcCachedSet = SrcResourceCache.GetDescriptorSet(SrcRes.DescriptorSet);
+ const auto& SrcCachedRes = SrcCachedSet.GetResource(SrcOffset);
+ IDeviceObject* pObject = SrcCachedRes.pObject.RawPtr<IDeviceObject>();
if (!pObject)
LOG_ERROR_MESSAGE("No resource assigned to static shader variable '", SrcRes.SpirvAttribs.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'.");
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp
index 54ce0030..a0a76499 100644
--- a/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp
@@ -129,7 +129,7 @@ ShaderVkImpl::~ShaderVkImpl()
}
#ifdef DEVELOPMENT
-void ShaderVkImpl::DvpVerifyStaticResourceBindings()
+void ShaderVkImpl::DvpVerifyStaticResourceBindings()const
{
m_StaticResLayout.dvpVerifyBindings(m_StaticResCache);
}