summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngine
diff options
context:
space:
mode:
authorazhirnov <zh1dron@gmail.com>2020-10-21 22:15:55 +0000
committerazhirnov <zh1dron@gmail.com>2020-10-25 10:50:53 +0000
commit42217cc1ec7f81c028dcc5c1f845a2fc3b3da497 (patch)
tree2efcb7c0fdeae582ecb5c8d13c7bedd593ab9a3c /Graphics/GraphicsEngine
parentFixed Mac/iOS build (diff)
parentUpdated Metal testing environment (diff)
downloadDiligentCore-42217cc1ec7f81c028dcc5c1f845a2fc3b3da497.tar.gz
DiligentCore-42217cc1ec7f81c028dcc5c1f845a2fc3b3da497.zip
Merge branch 'master' into ray_tracing
# Conflicts: # Graphics/GraphicsEngine/interface/PipelineState.h # Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp # Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp # Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp
Diffstat (limited to 'Graphics/GraphicsEngine')
-rw-r--r--Graphics/GraphicsEngine/CMakeLists.txt1
-rw-r--r--Graphics/GraphicsEngine/include/BufferBase.hpp10
-rw-r--r--Graphics/GraphicsEngine/include/DeviceContextBase.hpp10
-rw-r--r--Graphics/GraphicsEngine/include/PipelineStateBase.hpp753
-rw-r--r--Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp78
-rw-r--r--Graphics/GraphicsEngine/include/TextureBase.hpp3
-rw-r--r--Graphics/GraphicsEngine/interface/APIInfo.h119
-rw-r--r--Graphics/GraphicsEngine/interface/GraphicsTypes.h43
-rw-r--r--Graphics/GraphicsEngine/interface/InputLayout.h2
-rw-r--r--Graphics/GraphicsEngine/interface/PipelineState.h138
-rw-r--r--Graphics/GraphicsEngine/interface/RenderDevice.h53
-rw-r--r--Graphics/GraphicsEngine/interface/Shader.h4
-rw-r--r--Graphics/GraphicsEngine/src/APIInfo.cpp5
-rw-r--r--Graphics/GraphicsEngine/src/BufferBase.cpp6
-rw-r--r--Graphics/GraphicsEngine/src/PipelineStateBase.cpp260
15 files changed, 874 insertions, 611 deletions
diff --git a/Graphics/GraphicsEngine/CMakeLists.txt b/Graphics/GraphicsEngine/CMakeLists.txt
index 3162b6a0..47692deb 100644
--- a/Graphics/GraphicsEngine/CMakeLists.txt
+++ b/Graphics/GraphicsEngine/CMakeLists.txt
@@ -72,6 +72,7 @@ set(SOURCE
src/DefaultShaderSourceStreamFactory.cpp
src/EngineMemory.cpp
src/FramebufferBase.cpp
+ src/PipelineStateBase.cpp
src/ResourceMappingBase.cpp
src/RenderPassBase.cpp
src/TextureBase.cpp
diff --git a/Graphics/GraphicsEngine/include/BufferBase.hpp b/Graphics/GraphicsEngine/include/BufferBase.hpp
index 9ae6db92..605bc2ed 100644
--- a/Graphics/GraphicsEngine/include/BufferBase.hpp
+++ b/Graphics/GraphicsEngine/include/BufferBase.hpp
@@ -30,12 +30,14 @@
/// \file
/// Implementation of the Diligent::BufferBase template class
+#include <memory>
+
#include "Buffer.h"
#include "GraphicsTypes.h"
#include "DeviceObjectBase.hpp"
#include "GraphicsAccessories.hpp"
#include "STDAllocator.hpp"
-#include <memory>
+#include "FormatString.hpp"
namespace Diligent
{
@@ -232,6 +234,9 @@ void BufferBase<BaseInterface, RenderDeviceImplType, BufferViewImplType, TBuffVi
{
BufferViewDesc ViewDesc;
ViewDesc.ViewType = BUFFER_VIEW_UNORDERED_ACCESS;
+ auto UAVName = FormatString("Default UAV of buffer '", this->m_Desc.Name, '\'');
+ ViewDesc.Name = UAVName.c_str();
+
IBufferView* pUAV = nullptr;
CreateViewInternal(ViewDesc, &pUAV, true);
m_pDefaultUAV.reset(static_cast<BufferViewImplType*>(pUAV));
@@ -242,6 +247,9 @@ void BufferBase<BaseInterface, RenderDeviceImplType, BufferViewImplType, TBuffVi
{
BufferViewDesc ViewDesc;
ViewDesc.ViewType = BUFFER_VIEW_SHADER_RESOURCE;
+ auto SRVName = FormatString("Default SRV of buffer '", this->m_Desc.Name, '\'');
+ ViewDesc.Name = SRVName.c_str();
+
IBufferView* pSRV = nullptr;
CreateViewInternal(ViewDesc, &pSRV, true);
m_pDefaultSRV.reset(static_cast<BufferViewImplType*>(pSRV));
diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp
index dd8851c7..c16219da 100644
--- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp
+++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp
@@ -1672,6 +1672,13 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
return;
}
+ const auto& PSODesc = m_pPipelineState->GetDesc();
+ if (!PSODesc.IsAnyGraphicsPipeline())
+ {
+ LOG_ERROR_MESSAGE("Pipeline state '", PSODesc.Name, "' is not a graphics pipeline");
+ return;
+ }
+
TEXTURE_FORMAT BoundRTVFormats[8] = {TEX_FORMAT_UNKNOWN};
TEXTURE_FORMAT BoundDSVFormat = TEX_FORMAT_UNKNOWN;
@@ -1685,8 +1692,7 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
BoundDSVFormat = m_pBoundDepthStencil ? m_pBoundDepthStencil->GetDesc().Format : TEX_FORMAT_UNKNOWN;
- const auto& PSODesc = m_pPipelineState->GetDesc();
- const auto& GraphicsPipeline = PSODesc.GraphicsPipeline;
+ const auto& GraphicsPipeline = m_pPipelineState->GetGraphicsPipelineDesc();
if (GraphicsPipeline.NumRenderTargets != m_NumBoundRenderTargets)
{
LOG_WARNING_MESSAGE("The number of currently bound render targets (", m_NumBoundRenderTargets,
diff --git a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp
index b54a2f76..1effd32f 100644
--- a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp
+++ b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp
@@ -38,11 +38,16 @@
#include "STDAllocator.hpp"
#include "EngineMemory.h"
#include "GraphicsAccessories.hpp"
-#include "StringPool.hpp"
+#include "LinearAllocator.hpp"
namespace Diligent
{
+void ValidateGraphicsPipelineCreateInfo(const GraphicsPipelineStateCreateInfo& CreateInfo) noexcept(false);
+void ValidateComputePipelineCreateInfo(const ComputePipelineStateCreateInfo& CreateInfo) noexcept(false);
+
+void CorrectGraphicsPipelineDesc(GraphicsPipelineDesc& GraphicsPipeline) noexcept;
+
/// Template class implementing base functionality for a pipeline state object.
/// \tparam BaseInterface - base interface that this class will inheret
@@ -57,298 +62,17 @@ class PipelineStateBase : public DeviceObjectBase<BaseInterface, RenderDeviceImp
public:
using TDeviceObjectBase = DeviceObjectBase<BaseInterface, RenderDeviceImplType, PipelineStateDesc>;
- /// \param pRefCounters - reference counters object that controls the lifetime of this PSO
- /// \param pDevice - pointer to the device.
- /// \param PSODesc - pipeline state description.
- /// \param bIsDeviceInternal - flag indicating if the blend state is an internal device object and
+ /// \param pRefCounters - Reference counters object that controls the lifetime of this PSO
+ /// \param pDevice - Pointer to the device.
+ /// \param CreateInfo - Pipeline state create info.
+ /// \param bIsDeviceInternal - Flag indicating if the pipeline state is an internal device object and
/// must not keep a strong reference to the device.
PipelineStateBase(IReferenceCounters* pRefCounters,
RenderDeviceImplType* pDevice,
const PipelineStateDesc& PSODesc,
bool bIsDeviceInternal = false) :
- TDeviceObjectBase{pRefCounters, pDevice, PSODesc, bIsDeviceInternal},
- m_NumShaders{0}
+ TDeviceObjectBase{pRefCounters, pDevice, PSODesc, bIsDeviceInternal}
{
- ValidateDesc();
-
- const auto& SrcLayout = PSODesc.ResourceLayout;
- size_t StringPoolSize = 0;
- if (SrcLayout.Variables != nullptr)
- {
- for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i)
- StringPoolSize += strlen(SrcLayout.Variables[i].Name) + 1;
- }
-
- if (SrcLayout.StaticSamplers != nullptr)
- {
- for (Uint32 i = 0; i < SrcLayout.NumStaticSamplers; ++i)
- StringPoolSize += strlen(SrcLayout.StaticSamplers[i].SamplerOrTextureName) + 1;
- }
-
- if (PSODesc.IsAnyGraphicsPipeline())
- {
- CheckAndCorrectBlendStateDesc();
- CheckRasterizerStateDesc();
- CheckAndCorrectDepthStencilDesc();
-
- const auto& InputLayout = PSODesc.GraphicsPipeline.InputLayout;
- for (Uint32 i = 0; i < InputLayout.NumElements; ++i)
- StringPoolSize += strlen(InputLayout.LayoutElements[i].HLSLSemantic) + 1;
- }
- else
- {
- DEV_CHECK_ERR(PSODesc.GraphicsPipeline.InputLayout.NumElements == 0, "Compute pipelines must not have input layout elements");
- }
-
- m_StringPool.Reserve(StringPoolSize, GetRawAllocator());
-
- auto& DstLayout = this->m_Desc.ResourceLayout;
- if (SrcLayout.Variables != nullptr)
- {
- ShaderResourceVariableDesc* Variables =
- ALLOCATE(GetRawAllocator(), "Memory for ShaderResourceVariableDesc array", ShaderResourceVariableDesc, SrcLayout.NumVariables);
- DstLayout.Variables = Variables;
- for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i)
- {
- VERIFY(SrcLayout.Variables[i].Name != nullptr, "Variable name can't be null");
- Variables[i] = SrcLayout.Variables[i];
- Variables[i].Name = m_StringPool.CopyString(SrcLayout.Variables[i].Name);
- }
- }
-
- if (SrcLayout.StaticSamplers != nullptr)
- {
- StaticSamplerDesc* StaticSamplers =
- ALLOCATE(GetRawAllocator(), "Memory for StaticSamplerDesc array", StaticSamplerDesc, SrcLayout.NumStaticSamplers);
- DstLayout.StaticSamplers = StaticSamplers;
- for (Uint32 i = 0; i < SrcLayout.NumStaticSamplers; ++i)
- {
- VERIFY(SrcLayout.StaticSamplers[i].SamplerOrTextureName != nullptr, "Static sampler or texture name can't be null");
-#ifdef DILIGENT_DEVELOPMENT
- {
- const auto& BorderColor = SrcLayout.StaticSamplers[i].Desc.BorderColor;
- if (!((BorderColor[0] == 0 && BorderColor[1] == 0 && BorderColor[2] == 0 && BorderColor[3] == 0) ||
- (BorderColor[0] == 0 && BorderColor[1] == 0 && BorderColor[2] == 0 && BorderColor[3] == 1) ||
- (BorderColor[0] == 1 && BorderColor[1] == 1 && BorderColor[2] == 1 && BorderColor[3] == 1)))
- {
- LOG_WARNING_MESSAGE("Static sampler for variable \"", SrcLayout.StaticSamplers[i].SamplerOrTextureName, "\" specifies border color (",
- BorderColor[0], ", ", BorderColor[1], ", ", BorderColor[2], ", ", BorderColor[3],
- "). D3D12 static samplers only allow transparent black (0,0,0,0), opaque black (0,0,0,1) or opaque white (1,1,1,1) as border colors");
- }
- }
-#endif
-
- StaticSamplers[i] = SrcLayout.StaticSamplers[i];
- StaticSamplers[i].SamplerOrTextureName = m_StringPool.CopyString(SrcLayout.StaticSamplers[i].SamplerOrTextureName);
- }
- }
-
-
- if (this->m_Desc.IsComputePipeline())
- {
- const auto& ComputePipeline = PSODesc.ComputePipeline;
- if (ComputePipeline.pCS == nullptr)
- {
- LOG_ERROR_AND_THROW("Compute shader is not provided");
- }
-
-#define VALIDATE_SHADER_TYPE(Shader, ExpectedType, ShaderName) \
- if (Shader && Shader->GetDesc().ShaderType != ExpectedType) \
- { \
- LOG_ERROR_AND_THROW(GetShaderTypeLiteralName(Shader->GetDesc().ShaderType), " is not a valid type for ", ShaderName, " shader"); \
- }
-
- VALIDATE_SHADER_TYPE(ComputePipeline.pCS, SHADER_TYPE_COMPUTE, "compute")
-
- m_pCS = ComputePipeline.pCS;
- m_ppShaders[0] = ComputePipeline.pCS;
- m_NumShaders = 1;
- }
- else
- {
- const auto& GraphicsPipeline = PSODesc.GraphicsPipeline;
-
- VALIDATE_SHADER_TYPE(GraphicsPipeline.pVS, SHADER_TYPE_VERTEX, "vertex")
- VALIDATE_SHADER_TYPE(GraphicsPipeline.pPS, SHADER_TYPE_PIXEL, "pixel")
- VALIDATE_SHADER_TYPE(GraphicsPipeline.pGS, SHADER_TYPE_GEOMETRY, "geometry")
- VALIDATE_SHADER_TYPE(GraphicsPipeline.pHS, SHADER_TYPE_HULL, "hull")
- VALIDATE_SHADER_TYPE(GraphicsPipeline.pDS, SHADER_TYPE_DOMAIN, "domain")
- VALIDATE_SHADER_TYPE(GraphicsPipeline.pAS, SHADER_TYPE_AMPLIFICATION, "amplification")
- VALIDATE_SHADER_TYPE(GraphicsPipeline.pMS, SHADER_TYPE_MESH, "mesh")
-#undef VALIDATE_SHADER_TYPE
-
- if (PSODesc.PipelineType == PIPELINE_TYPE_GRAPHICS)
- {
- DEV_CHECK_ERR(GraphicsPipeline.pVS, "Vertex shader must be defined");
- DEV_CHECK_ERR(!GraphicsPipeline.pAS && !GraphicsPipeline.pMS, "Mesh shaders are not supported in graphics pipeline");
- m_pVS = GraphicsPipeline.pVS;
- m_pPS = GraphicsPipeline.pPS;
- m_pGS = GraphicsPipeline.pGS;
- m_pDS = GraphicsPipeline.pDS;
- m_pHS = GraphicsPipeline.pHS;
- }
- else if (PSODesc.PipelineType == PIPELINE_TYPE_MESH)
- {
- DEV_CHECK_ERR(GraphicsPipeline.pMS, "Mesh shader must be defined");
- DEV_CHECK_ERR(!GraphicsPipeline.pVS && !GraphicsPipeline.pGS && !GraphicsPipeline.pDS && !GraphicsPipeline.pHS,
- "Vertex, geometry and tessellation shaders are not supported in a mesh pipeline");
- DEV_CHECK_ERR(GraphicsPipeline.InputLayout.NumElements == 0, "Input layout ignored in mesh shader");
- DEV_CHECK_ERR(GraphicsPipeline.PrimitiveTopology == PRIMITIVE_TOPOLOGY_TRIANGLE_LIST ||
- GraphicsPipeline.PrimitiveTopology == PRIMITIVE_TOPOLOGY_UNDEFINED,
- "Primitive topology is ignored in a mesh pipeline, set it to undefined or keep default value (triangle list)");
- m_pAS = GraphicsPipeline.pAS;
- m_pMS = GraphicsPipeline.pMS;
- m_pPS = GraphicsPipeline.pPS;
- }
-
- if (GraphicsPipeline.pVS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pVS;
- if (GraphicsPipeline.pPS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pPS;
- if (GraphicsPipeline.pGS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pGS;
- if (GraphicsPipeline.pHS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pHS;
- if (GraphicsPipeline.pDS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pDS;
- if (GraphicsPipeline.pAS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pAS;
- if (GraphicsPipeline.pMS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pMS;
-
- DEV_CHECK_ERR(m_NumShaders > 0, "There must be at least one shader in the Pipeline State");
-
- m_pRenderPass = PSODesc.GraphicsPipeline.pRenderPass;
-
- for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < _countof(GraphicsPipeline.RTVFormats); ++rt)
- {
- auto RTVFmt = GraphicsPipeline.RTVFormats[rt];
- if (RTVFmt != TEX_FORMAT_UNKNOWN)
- {
- LOG_ERROR_MESSAGE("Render target format (", GetTextureFormatAttribs(RTVFmt).Name, ") of unused slot ", rt,
- " must be set to TEX_FORMAT_UNKNOWN");
- }
- }
-
- if (m_pRenderPass)
- {
- const auto& RPDesc = m_pRenderPass->GetDesc();
- VERIFY_EXPR(GraphicsPipeline.SubpassIndex < RPDesc.SubpassCount);
- const auto& Subpass = RPDesc.pSubpasses[GraphicsPipeline.SubpassIndex];
-
- this->m_Desc.GraphicsPipeline.NumRenderTargets = static_cast<Uint8>(Subpass.RenderTargetAttachmentCount);
- for (Uint32 rt = 0; rt < Subpass.RenderTargetAttachmentCount; ++rt)
- {
- const auto& RTAttachmentRef = Subpass.pRenderTargetAttachments[rt];
- if (RTAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED)
- {
- VERIFY_EXPR(RTAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount);
- this->m_Desc.GraphicsPipeline.RTVFormats[rt] = RPDesc.pAttachments[RTAttachmentRef.AttachmentIndex].Format;
- }
- }
-
- if (Subpass.pDepthStencilAttachment != nullptr)
- {
- const auto& DSAttachmentRef = *Subpass.pDepthStencilAttachment;
- if (DSAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED)
- {
- VERIFY_EXPR(DSAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount);
- this->m_Desc.GraphicsPipeline.DSVFormat = RPDesc.pAttachments[DSAttachmentRef.AttachmentIndex].Format;
- }
- }
- }
-
- const auto& InputLayout = PSODesc.GraphicsPipeline.InputLayout;
- LayoutElement* pLayoutElements = nullptr;
- if (InputLayout.NumElements > 0)
- {
- pLayoutElements = ALLOCATE(GetRawAllocator(), "Raw memory for input layout elements", LayoutElement, InputLayout.NumElements);
- }
- this->m_Desc.GraphicsPipeline.InputLayout.LayoutElements = pLayoutElements;
- for (size_t Elem = 0; Elem < InputLayout.NumElements; ++Elem)
- {
- pLayoutElements[Elem] = InputLayout.LayoutElements[Elem];
- pLayoutElements[Elem].HLSLSemantic = m_StringPool.CopyString(InputLayout.LayoutElements[Elem].HLSLSemantic);
- }
-
-
- // Correct description and compute offsets and tight strides
- std::array<Uint32, MAX_BUFFER_SLOTS> Strides, TightStrides = {};
- // Set all strides to an invalid value because an application may want to use 0 stride
- for (auto& Stride : Strides)
- Stride = LAYOUT_ELEMENT_AUTO_STRIDE;
-
- for (Uint32 i = 0; i < InputLayout.NumElements; ++i)
- {
- auto& LayoutElem = pLayoutElements[i];
-
- if (LayoutElem.ValueType == VT_FLOAT32 || LayoutElem.ValueType == VT_FLOAT16)
- LayoutElem.IsNormalized = false; // Floating point values cannot be normalized
-
- auto BuffSlot = LayoutElem.BufferSlot;
- if (BuffSlot >= Strides.size())
- {
- UNEXPECTED("Buffer slot (", BuffSlot, ") exceeds maximum allowed value (", Strides.size() - 1, ")");
- continue;
- }
- m_BufferSlotsUsed = std::max(m_BufferSlotsUsed, BuffSlot + 1);
-
- auto& CurrAutoStride = TightStrides[BuffSlot];
- // If offset is not explicitly specified, use current auto stride value
- if (LayoutElem.RelativeOffset == LAYOUT_ELEMENT_AUTO_OFFSET)
- {
- LayoutElem.RelativeOffset = CurrAutoStride;
- }
-
- // If stride is explicitly specified, use it for the current buffer slot
- if (LayoutElem.Stride != LAYOUT_ELEMENT_AUTO_STRIDE)
- {
- // Verify that the value is consistent with the previously specified stride, if any
- if (Strides[BuffSlot] != LAYOUT_ELEMENT_AUTO_STRIDE && Strides[BuffSlot] != LayoutElem.Stride)
- {
- LOG_ERROR_MESSAGE("Inconsistent strides are specified for buffer slot ", BuffSlot,
- ". Input element at index ", LayoutElem.InputIndex, " explicitly specifies stride ",
- LayoutElem.Stride, ", while current value is ", Strides[BuffSlot],
- ". Specify consistent strides or use LAYOUT_ELEMENT_AUTO_STRIDE to allow "
- "the engine compute strides automatically.");
- }
- Strides[BuffSlot] = LayoutElem.Stride;
- }
-
- CurrAutoStride = std::max(CurrAutoStride, LayoutElem.RelativeOffset + LayoutElem.NumComponents * GetValueSize(LayoutElem.ValueType));
- }
-
- for (Uint32 i = 0; i < InputLayout.NumElements; ++i)
- {
- auto& LayoutElem = pLayoutElements[i];
-
- auto BuffSlot = LayoutElem.BufferSlot;
- // If no input elements explicitly specified stride for this buffer slot, use automatic stride
- if (Strides[BuffSlot] == LAYOUT_ELEMENT_AUTO_STRIDE)
- {
- Strides[BuffSlot] = TightStrides[BuffSlot];
- }
- else
- {
- if (Strides[BuffSlot] < TightStrides[BuffSlot])
- {
- LOG_ERROR_MESSAGE("Stride ", Strides[BuffSlot], " explicitly specified for slot ", BuffSlot,
- " is smaller than the minimum stride ", TightStrides[BuffSlot],
- " required to accomodate all input elements.");
- }
- }
- if (LayoutElem.Stride == LAYOUT_ELEMENT_AUTO_STRIDE)
- LayoutElem.Stride = Strides[BuffSlot];
- }
-
- if (m_BufferSlotsUsed > 0)
- {
- m_pStrides = ALLOCATE(GetRawAllocator(), "Raw memory for buffer strides", Uint32, m_BufferSlotsUsed);
-
- // Set strides for all unused slots to 0
- for (Uint32 i = 0; i < m_BufferSlotsUsed; ++i)
- {
- auto Stride = Strides[i];
- m_pStrides[i] = Stride != LAYOUT_ELEMENT_AUTO_STRIDE ? Stride : 0;
- }
- }
- }
-
- VERIFY_EXPR(m_StringPool.GetRemainingSize() == 0);
-
Uint64 DeviceQueuesMask = pDevice->GetCommandQueueMask();
DEV_CHECK_ERR((this->m_Desc.CommandQueueMask & DeviceQueuesMask) != 0,
"No bits in the command queue mask (0x", std::hex, this->m_Desc.CommandQueueMask,
@@ -356,6 +80,35 @@ public:
this->m_Desc.CommandQueueMask &= DeviceQueuesMask;
}
+ /// \param pRefCounters - Reference counters object that controls the lifetime of this PSO
+ /// \param pDevice - Pointer to the device.
+ /// \param GraphicsPipelineCI - Graphics pipeline create information.
+ /// \param bIsDeviceInternal - Flag indicating if the pipeline state is an internal device object and
+ /// must not keep a strong reference to the device.
+ PipelineStateBase(IReferenceCounters* pRefCounters,
+ RenderDeviceImplType* pDevice,
+ const GraphicsPipelineStateCreateInfo& GraphicsPipelineCI,
+ bool bIsDeviceInternal = false) :
+ PipelineStateBase{pRefCounters, pDevice, GraphicsPipelineCI.PSODesc, bIsDeviceInternal}
+ {
+ ValidateGraphicsPipelineCreateInfo(GraphicsPipelineCI);
+ }
+
+ /// \param pRefCounters - Reference counters object that controls the lifetime of this PSO
+ /// \param pDevice - Pointer to the device.
+ /// \param ComputePipelineCI - Compute pipeline create information.
+ /// \param bIsDeviceInternal - Flag indicating if the pipeline state is an internal device object and
+ /// must not keep a strong reference to the device.
+ PipelineStateBase(IReferenceCounters* pRefCounters,
+ RenderDeviceImplType* pDevice,
+ const ComputePipelineStateCreateInfo& ComputePipelineCI,
+ bool bIsDeviceInternal = false) :
+ PipelineStateBase{pRefCounters, pDevice, ComputePipelineCI.PSODesc, bIsDeviceInternal}
+ {
+ ValidateComputePipelineCreateInfo(ComputePipelineCI);
+ }
+
+
~PipelineStateBase()
{
/*
@@ -375,16 +128,6 @@ public:
RasterizerStateRegistry.ReportDeletedObject();
DSSRegistry.ReportDeletedObject();
*/
-
- auto& RawAllocator = GetRawAllocator();
- if (this->m_Desc.ResourceLayout.Variables != nullptr)
- RawAllocator.Free(const_cast<ShaderResourceVariableDesc*>(this->m_Desc.ResourceLayout.Variables));
- if (this->m_Desc.ResourceLayout.StaticSamplers != nullptr)
- RawAllocator.Free(const_cast<StaticSamplerDesc*>(this->m_Desc.ResourceLayout.StaticSamplers));
- if (this->m_Desc.GraphicsPipeline.InputLayout.LayoutElements != nullptr)
- RawAllocator.Free(const_cast<LayoutElement*>(this->m_Desc.GraphicsPipeline.InputLayout.LayoutElements));
- if (m_pStrides != nullptr)
- RawAllocator.Free(m_pStrides);
}
IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_PipelineState, TDeviceObjectBase)
@@ -399,28 +142,8 @@ public:
return m_BufferSlotsUsed;
}
- IShader* GetVS() { return m_pVS; }
- IShader* GetPS() { return m_pPS; }
- IShader* GetGS() { return m_pGS; }
- IShader* GetDS() { return m_pDS; }
- IShader* GetHS() { return m_pHS; }
- IShader* GetCS() { return m_pCS; }
-
- IShader* const* GetShaders() const { return m_ppShaders.data(); }
- Uint32 GetNumShaders() const { return m_NumShaders; }
-
- template <typename ShaderType>
- ShaderType* GetShader(Uint32 ShaderInd)
- {
- VERIFY_EXPR(ShaderInd < m_NumShaders);
- return ValidatedCast<ShaderType>(m_ppShaders[ShaderInd]);
- }
- template <typename ShaderType>
- ShaderType* GetShader(Uint32 ShaderInd) const
- {
- VERIFY_EXPR(ShaderInd < m_NumShaders);
- return ValidatedCast<ShaderType>(m_ppShaders[ShaderInd]);
- }
+ SHADER_TYPE GetShaderStageType(Uint32 Stage) const { return m_ShaderStageTypes[Stage]; }
+ Uint32 GetNumShaderStages() const { return m_NumShaderStages; }
// This function only compares shader resource layout hashes, so
// it can potentially give false negatives
@@ -429,27 +152,12 @@ public:
return m_ShaderResourceLayoutHash != ValidatedCast<const PipelineStateBase>(pPSO)->m_ShaderResourceLayoutHash;
}
-protected:
- Uint32 m_BufferSlotsUsed = 0;
- Uint32 m_NumShaders = 0; ///< Number of shaders that this PSO uses
- Uint32* m_pStrides = nullptr;
-
- StringPool m_StringPool;
-
- RefCntAutoPtr<IShader> m_pVS; ///< Strong reference to the vertex shader
- RefCntAutoPtr<IShader> m_pPS; ///< Strong reference to the pixel shader
- RefCntAutoPtr<IShader> m_pGS; ///< Strong reference to the geometry shader
- RefCntAutoPtr<IShader> m_pDS; ///< Strong reference to the domain shader
- RefCntAutoPtr<IShader> m_pHS; ///< Strong reference to the hull shader
- RefCntAutoPtr<IShader> m_pCS; ///< Strong reference to the compute shader
- RefCntAutoPtr<IShader> m_pAS; ///< Strong reference to the amplification shader
- RefCntAutoPtr<IShader> m_pMS; ///< Strong reference to the mesh shader
-
- RefCntAutoPtr<IRenderPass> m_pRenderPass; ///< Strong reference to the render pass object
-
- std::array<IShader*, MAX_SHADERS_IN_PIPELINE> m_ppShaders = {}; ///< Array of pointers to the shaders used by this PSO
- size_t m_ShaderResourceLayoutHash = 0; ///< Hash computed from the shader resource layout
-
+ virtual const GraphicsPipelineDesc& DILIGENT_CALL_TYPE GetGraphicsPipelineDesc() const override final
+ {
+ VERIFY_EXPR(this->m_Desc.IsAnyGraphicsPipeline());
+ VERIFY_EXPR(m_pGraphicsPipelineDesc != nullptr);
+ return *m_pGraphicsPipelineDesc;
+ }
protected:
Int8 GetStaticVariableCountHelper(SHADER_TYPE ShaderType, const std::array<Int8, MAX_SHADERS_IN_PIPELINE>& ResourceLayoutIndex) const
@@ -512,143 +220,312 @@ protected:
return LayoutInd;
}
-private:
-#define LOG_PSO_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of ", GetPipelineTypeString(this->m_Desc.PipelineType), " PSO '", this->m_Desc.Name, "' is invalid: ", ##__VA_ARGS__)
- void ValidateDesc() const
+ void ReserveSpaceForPipelineDesc(const GraphicsPipelineStateCreateInfo& CreateInfo,
+ LinearAllocator& MemPool) noexcept
{
- if (this->m_Desc.IsComputePipeline())
+ MemPool.AddSpace<GraphicsPipelineDesc>();
+ ReserveResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool);
+
+ const auto& InputLayout = CreateInfo.GraphicsPipeline.InputLayout;
+ MemPool.AddSpace<LayoutElement>(InputLayout.NumElements);
+ for (Uint32 i = 0; i < InputLayout.NumElements; ++i)
{
- if (this->m_Desc.GraphicsPipeline.pRenderPass != nullptr)
+ auto& LayoutElem = InputLayout.LayoutElements[i];
+ MemPool.AddSpaceForString(LayoutElem.HLSLSemantic);
+ m_BufferSlotsUsed = std::max(m_BufferSlotsUsed, static_cast<Uint8>(LayoutElem.BufferSlot + 1));
+ }
+
+ MemPool.AddSpace<Uint32>(m_BufferSlotsUsed);
+ }
+
+ void ReserveSpaceForPipelineDesc(const ComputePipelineStateCreateInfo& CreateInfo,
+ LinearAllocator& MemPool) const noexcept
+ {
+ ReserveResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool);
+ }
+
+
+ template <typename ShaderImplType, typename TShaderStages>
+ void ExtractShaders(const GraphicsPipelineStateCreateInfo& CreateInfo,
+ TShaderStages& ShaderStages)
+ {
+ VERIFY(m_NumShaderStages == 0, "The number of shader stages is not zero! ExtractShaders must only be called once.");
+
+ ShaderStages.clear();
+ auto AddShaderStage = [&](IShader* pShader) {
+ if (pShader != nullptr)
+ {
+ auto ShaderType = pShader->GetDesc().ShaderType;
+ ShaderStages.emplace_back(ShaderType, ValidatedCast<ShaderImplType>(pShader));
+ VERIFY(m_ShaderStageTypes[m_NumShaderStages] == SHADER_TYPE_UNKNOWN, "This shader stage is already initialized.");
+ m_ShaderStageTypes[m_NumShaderStages++] = ShaderType;
+ }
+ };
+
+ switch (CreateInfo.PSODesc.PipelineType)
+ {
+ case PIPELINE_TYPE_GRAPHICS:
{
- LOG_PSO_ERROR_AND_THROW("GraphicsPipeline.pRenderPass must be null for compute pipelines");
+ AddShaderStage(CreateInfo.pVS);
+ AddShaderStage(CreateInfo.pHS);
+ AddShaderStage(CreateInfo.pDS);
+ AddShaderStage(CreateInfo.pGS);
+ AddShaderStage(CreateInfo.pPS);
+ VERIFY(CreateInfo.pVS != nullptr, "Vertex shader must not be null");
+ break;
}
+
+ case PIPELINE_TYPE_MESH:
+ {
+ AddShaderStage(CreateInfo.pAS);
+ AddShaderStage(CreateInfo.pMS);
+ AddShaderStage(CreateInfo.pPS);
+ VERIFY(CreateInfo.pMS != nullptr, "Mesh shader must not be null");
+ break;
+ }
+
+ default:
+ UNEXPECTED("unknown pipeline type");
}
- else
+
+ VERIFY_EXPR(!ShaderStages.empty() && ShaderStages.size() == m_NumShaderStages);
+ }
+
+ template <typename ShaderImplType, typename TShaderStages>
+ void ExtractShaders(const ComputePipelineStateCreateInfo& CreateInfo,
+ TShaderStages& ShaderStages)
+ {
+ VERIFY(m_NumShaderStages == 0, "The number of shader stages is not zero! ExtractShaders must only be called once.");
+
+ ShaderStages.clear();
+
+ VERIFY_EXPR(CreateInfo.PSODesc.PipelineType == PIPELINE_TYPE_COMPUTE);
+ VERIFY_EXPR(CreateInfo.pCS != nullptr);
+ VERIFY_EXPR(CreateInfo.pCS->GetDesc().ShaderType == SHADER_TYPE_COMPUTE);
+
+ ShaderStages.emplace_back(SHADER_TYPE_COMPUTE, ValidatedCast<ShaderImplType>(CreateInfo.pCS));
+ m_ShaderStageTypes[m_NumShaderStages++] = SHADER_TYPE_COMPUTE;
+
+ VERIFY_EXPR(!ShaderStages.empty() && ShaderStages.size() == m_NumShaderStages);
+ }
+
+
+ void InitializePipelineDesc(const GraphicsPipelineStateCreateInfo& CreateInfo,
+ LinearAllocator& MemPool)
+ {
+ this->m_pGraphicsPipelineDesc = MemPool.Copy(CreateInfo.GraphicsPipeline);
+
+ auto& GraphicsPipeline = *this->m_pGraphicsPipelineDesc;
+ CorrectGraphicsPipelineDesc(GraphicsPipeline);
+
+ CopyResourceLayout(CreateInfo.PSODesc.ResourceLayout, this->m_Desc.ResourceLayout, MemPool);
+
+ m_pRenderPass = GraphicsPipeline.pRenderPass;
+ if (m_pRenderPass)
{
- const auto& GraphicsPipeline = this->m_Desc.GraphicsPipeline;
- if (GraphicsPipeline.pRenderPass != nullptr)
+ const auto& RPDesc = m_pRenderPass->GetDesc();
+ VERIFY_EXPR(GraphicsPipeline.SubpassIndex < RPDesc.SubpassCount);
+ const auto& Subpass = RPDesc.pSubpasses[GraphicsPipeline.SubpassIndex];
+
+ GraphicsPipeline.NumRenderTargets = static_cast<Uint8>(Subpass.RenderTargetAttachmentCount);
+ for (Uint32 rt = 0; rt < Subpass.RenderTargetAttachmentCount; ++rt)
{
- if (GraphicsPipeline.NumRenderTargets != 0)
- LOG_PSO_ERROR_AND_THROW("NumRenderTargets must be 0 when explicit render pass is used");
- if (GraphicsPipeline.DSVFormat != TEX_FORMAT_UNKNOWN)
- LOG_PSO_ERROR_AND_THROW("DSVFormat must be TEX_FORMAT_UNKNOWN when explicit render pass is used");
+ const auto& RTAttachmentRef = Subpass.pRenderTargetAttachments[rt];
+ if (RTAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED)
+ {
+ VERIFY_EXPR(RTAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount);
+ GraphicsPipeline.RTVFormats[rt] = RPDesc.pAttachments[RTAttachmentRef.AttachmentIndex].Format;
+ }
+ }
- for (Uint32 rt = 0; rt < MAX_RENDER_TARGETS; ++rt)
+ if (Subpass.pDepthStencilAttachment != nullptr)
+ {
+ const auto& DSAttachmentRef = *Subpass.pDepthStencilAttachment;
+ if (DSAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED)
{
- if (GraphicsPipeline.RTVFormats[rt] != TEX_FORMAT_UNKNOWN)
- LOG_PSO_ERROR_AND_THROW("RTVFormats[", rt, "] must be TEX_FORMAT_UNKNOWN when explicit render pass is used");
+ VERIFY_EXPR(DSAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount);
+ GraphicsPipeline.DSVFormat = RPDesc.pAttachments[DSAttachmentRef.AttachmentIndex].Format;
}
+ }
+ }
+
+ const auto& InputLayout = GraphicsPipeline.InputLayout;
+ LayoutElement* pLayoutElements = MemPool.Allocate<LayoutElement>(InputLayout.NumElements);
+ for (size_t Elem = 0; Elem < InputLayout.NumElements; ++Elem)
+ {
+ const auto& SrcElem = InputLayout.LayoutElements[Elem];
+ pLayoutElements[Elem] = SrcElem;
+ VERIFY_EXPR(SrcElem.HLSLSemantic != nullptr);
+ pLayoutElements[Elem].HLSLSemantic = MemPool.CopyString(SrcElem.HLSLSemantic);
+ }
+ GraphicsPipeline.InputLayout.LayoutElements = pLayoutElements;
+
+
+ // Correct description and compute offsets and tight strides
+ std::array<Uint32, MAX_BUFFER_SLOTS> Strides, TightStrides = {};
+ // Set all strides to an invalid value because an application may want to use 0 stride
+ for (auto& Stride : Strides)
+ Stride = LAYOUT_ELEMENT_AUTO_STRIDE;
+
+ for (Uint32 i = 0; i < InputLayout.NumElements; ++i)
+ {
+ auto& LayoutElem = pLayoutElements[i];
- const auto& RPDesc = GraphicsPipeline.pRenderPass->GetDesc();
- if (GraphicsPipeline.SubpassIndex >= RPDesc.SubpassCount)
- LOG_PSO_ERROR_AND_THROW("Subpass index (", Uint32{GraphicsPipeline.SubpassIndex}, ") exceeds the number of subpasses (", Uint32{RPDesc.SubpassCount}, ") in render pass '", RPDesc.Name, "'");
+ if (LayoutElem.ValueType == VT_FLOAT32 || LayoutElem.ValueType == VT_FLOAT16)
+ LayoutElem.IsNormalized = false; // Floating point values cannot be normalized
+
+ auto BuffSlot = LayoutElem.BufferSlot;
+ if (BuffSlot >= Strides.size())
+ {
+ UNEXPECTED("Buffer slot (", BuffSlot, ") exceeds the maximum allowed value (", Strides.size() - 1, ")");
+ continue;
+ }
+ VERIFY_EXPR(BuffSlot < m_BufferSlotsUsed);
+
+ auto& CurrAutoStride = TightStrides[BuffSlot];
+ // If offset is not explicitly specified, use current auto stride value
+ if (LayoutElem.RelativeOffset == LAYOUT_ELEMENT_AUTO_OFFSET)
+ {
+ LayoutElem.RelativeOffset = CurrAutoStride;
+ }
+
+ // If stride is explicitly specified, use it for the current buffer slot
+ if (LayoutElem.Stride != LAYOUT_ELEMENT_AUTO_STRIDE)
+ {
+ // Verify that the value is consistent with the previously specified stride, if any
+ if (Strides[BuffSlot] != LAYOUT_ELEMENT_AUTO_STRIDE && Strides[BuffSlot] != LayoutElem.Stride)
+ {
+ LOG_ERROR_MESSAGE("Inconsistent strides are specified for buffer slot ", BuffSlot,
+ ". Input element at index ", LayoutElem.InputIndex, " explicitly specifies stride ",
+ LayoutElem.Stride, ", while current value is ", Strides[BuffSlot],
+ ". Specify consistent strides or use LAYOUT_ELEMENT_AUTO_STRIDE to allow "
+ "the engine compute strides automatically.");
+ }
+ Strides[BuffSlot] = LayoutElem.Stride;
+ }
+
+ CurrAutoStride = std::max(CurrAutoStride, LayoutElem.RelativeOffset + LayoutElem.NumComponents * GetValueSize(LayoutElem.ValueType));
+ }
+
+ for (Uint32 i = 0; i < InputLayout.NumElements; ++i)
+ {
+ auto& LayoutElem = pLayoutElements[i];
+
+ auto BuffSlot = LayoutElem.BufferSlot;
+ // If no input elements explicitly specified stride for this buffer slot, use automatic stride
+ if (Strides[BuffSlot] == LAYOUT_ELEMENT_AUTO_STRIDE)
+ {
+ Strides[BuffSlot] = TightStrides[BuffSlot];
}
else
{
- if (GraphicsPipeline.SubpassIndex != 0)
- LOG_PSO_ERROR_AND_THROW("Subpass index (", Uint32{GraphicsPipeline.SubpassIndex}, ") must be 0 when explicit render pass is not used");
+ if (Strides[BuffSlot] < TightStrides[BuffSlot])
+ {
+ LOG_ERROR_MESSAGE("Stride ", Strides[BuffSlot], " explicitly specified for slot ", BuffSlot,
+ " is smaller than the minimum stride ", TightStrides[BuffSlot],
+ " required to accomodate all input elements.");
+ }
}
+ if (LayoutElem.Stride == LAYOUT_ELEMENT_AUTO_STRIDE)
+ LayoutElem.Stride = Strides[BuffSlot];
+ }
+
+ m_pStrides = MemPool.Allocate<Uint32>(m_BufferSlotsUsed);
+
+ // Set strides for all unused slots to 0
+ for (Uint32 i = 0; i < m_BufferSlotsUsed; ++i)
+ {
+ auto Stride = Strides[i];
+ m_pStrides[i] = Stride != LAYOUT_ELEMENT_AUTO_STRIDE ? Stride : 0;
}
}
- void CheckRasterizerStateDesc() const
+ void InitializePipelineDesc(const ComputePipelineStateCreateInfo& CreateInfo,
+ LinearAllocator& MemPool)
{
- const auto& RSDesc = this->m_Desc.GraphicsPipeline.RasterizerDesc;
- if (RSDesc.FillMode == FILL_MODE_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("RasterizerDesc.FillMode must not be FILL_MODE_UNDEFINED");
- if (RSDesc.CullMode == CULL_MODE_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("RasterizerDesc.CullMode must not be CULL_MODE_UNDEFINED");
+ CopyResourceLayout(CreateInfo.PSODesc.ResourceLayout, this->m_Desc.ResourceLayout, MemPool);
}
- void CheckAndCorrectDepthStencilDesc()
+private:
+ static void ReserveResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, LinearAllocator& MemPool) noexcept
{
- auto& DSSDesc = this->m_Desc.GraphicsPipeline.DepthStencilDesc;
- if (DSSDesc.DepthFunc == COMPARISON_FUNC_UNKNOWN)
+ if (SrcLayout.Variables != nullptr)
{
- if (DSSDesc.DepthEnable)
- LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.DepthFunc must not be COMPARISON_FUNC_UNKNOWN when depth is enabled");
- else
- DSSDesc.DepthFunc = DepthStencilStateDesc{}.DepthFunc;
+ MemPool.AddSpace<ShaderResourceVariableDesc>(SrcLayout.NumVariables);
+ for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i)
+ {
+ VERIFY(SrcLayout.Variables[i].Name != nullptr, "Variable name can't be null");
+ MemPool.AddSpaceForString(SrcLayout.Variables[i].Name);
+ }
}
- auto CheckAndCorrectStencilOpDesc = [&](StencilOpDesc& OpDesc, const char* FaceName) //
+ if (SrcLayout.ImmutableSamplers != nullptr)
{
- if (DSSDesc.StencilEnable)
- {
- if (OpDesc.StencilFailOp == STENCIL_OP_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilFailOp must not be STENCIL_OP_UNDEFINED when stencil is enabled");
- if (OpDesc.StencilDepthFailOp == STENCIL_OP_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilDepthFailOp must not be STENCIL_OP_UNDEFINED when stencil is enabled");
- if (OpDesc.StencilPassOp == STENCIL_OP_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilPassOp must not be STENCIL_OP_UNDEFINED when stencil is enabled");
- if (OpDesc.StencilFunc == COMPARISON_FUNC_UNKNOWN)
- LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilFunc must not be COMPARISON_FUNC_UNKNOWN when stencil is enabled");
- }
- else
+ MemPool.AddSpace<ImmutableSamplerDesc>(SrcLayout.NumImmutableSamplers);
+ for (Uint32 i = 0; i < SrcLayout.NumImmutableSamplers; ++i)
{
- if (OpDesc.StencilFailOp == STENCIL_OP_UNDEFINED)
- OpDesc.StencilFailOp = StencilOpDesc{}.StencilFailOp;
- if (OpDesc.StencilDepthFailOp == STENCIL_OP_UNDEFINED)
- OpDesc.StencilDepthFailOp = StencilOpDesc{}.StencilDepthFailOp;
- if (OpDesc.StencilPassOp == STENCIL_OP_UNDEFINED)
- OpDesc.StencilPassOp = StencilOpDesc{}.StencilPassOp;
- if (OpDesc.StencilFunc == COMPARISON_FUNC_UNKNOWN)
- OpDesc.StencilFunc = StencilOpDesc{}.StencilFunc;
+ VERIFY(SrcLayout.ImmutableSamplers[i].SamplerOrTextureName != nullptr, "Immutable sampler or texture name can't be null");
+ MemPool.AddSpaceForString(SrcLayout.ImmutableSamplers[i].SamplerOrTextureName);
}
- };
- CheckAndCorrectStencilOpDesc(DSSDesc.FrontFace, "FrontFace");
- CheckAndCorrectStencilOpDesc(DSSDesc.BackFace, "BackFace");
+ }
}
- void CheckAndCorrectBlendStateDesc()
+ static void CopyResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, PipelineResourceLayoutDesc& DstLayout, LinearAllocator& MemPool)
{
- auto& BlendDesc = this->m_Desc.GraphicsPipeline.BlendDesc;
- for (Uint32 rt = 0; rt < MAX_RENDER_TARGETS; ++rt)
+ if (SrcLayout.Variables != nullptr)
{
- auto& RTDesc = BlendDesc.RenderTargets[rt];
- // clang-format off
- const auto BlendEnable = RTDesc.BlendEnable && (rt == 0 || (BlendDesc.IndependentBlendEnable && rt > 0));
- const auto LogicOpEnable = RTDesc.LogicOperationEnable && (rt == 0 || (BlendDesc.IndependentBlendEnable && rt > 0));
- // clang-format on
- if (BlendEnable)
+ auto* Variables = MemPool.Allocate<ShaderResourceVariableDesc>(SrcLayout.NumVariables);
+ DstLayout.Variables = Variables;
+ for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i)
{
- if (RTDesc.SrcBlend == BLEND_FACTOR_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].SrcBlend must not be BLEND_FACTOR_UNDEFINED");
- if (RTDesc.DestBlend == BLEND_FACTOR_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].DestBlend must not be BLEND_FACTOR_UNDEFINED");
- if (RTDesc.BlendOp == BLEND_OPERATION_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].BlendOp must not be BLEND_OPERATION_UNDEFINED");
-
- if (RTDesc.SrcBlendAlpha == BLEND_FACTOR_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].SrcBlendAlpha must not be BLEND_FACTOR_UNDEFINED");
- if (RTDesc.DestBlendAlpha == BLEND_FACTOR_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].DestBlendAlpha must not be BLEND_FACTOR_UNDEFINED");
- if (RTDesc.BlendOpAlpha == BLEND_OPERATION_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].BlendOpAlpha must not be BLEND_OPERATION_UNDEFINED");
+ const auto& SrcVar = SrcLayout.Variables[i];
+ Variables[i] = SrcVar;
+ Variables[i].Name = MemPool.CopyString(SrcVar.Name);
}
- else
+ }
+
+ if (SrcLayout.ImmutableSamplers != nullptr)
+ {
+ auto* ImmutableSamplers = MemPool.Allocate<ImmutableSamplerDesc>(SrcLayout.NumImmutableSamplers);
+ DstLayout.ImmutableSamplers = ImmutableSamplers;
+ for (Uint32 i = 0; i < SrcLayout.NumImmutableSamplers; ++i)
{
- if (RTDesc.SrcBlend == BLEND_FACTOR_UNDEFINED)
- RTDesc.SrcBlend = RenderTargetBlendDesc{}.SrcBlend;
- if (RTDesc.DestBlend == BLEND_FACTOR_UNDEFINED)
- RTDesc.DestBlend = RenderTargetBlendDesc{}.DestBlend;
- if (RTDesc.BlendOp == BLEND_OPERATION_UNDEFINED)
- RTDesc.BlendOp = RenderTargetBlendDesc{}.BlendOp;
-
- if (RTDesc.SrcBlendAlpha == BLEND_FACTOR_UNDEFINED)
- RTDesc.SrcBlendAlpha = RenderTargetBlendDesc{}.SrcBlendAlpha;
- if (RTDesc.DestBlendAlpha == BLEND_FACTOR_UNDEFINED)
- RTDesc.DestBlendAlpha = RenderTargetBlendDesc{}.DestBlendAlpha;
- if (RTDesc.BlendOpAlpha == BLEND_OPERATION_UNDEFINED)
- RTDesc.BlendOpAlpha = RenderTargetBlendDesc{}.BlendOpAlpha;
- }
+ const auto& SrcSmplr = SrcLayout.ImmutableSamplers[i];
+#ifdef DILIGENT_DEVELOPMENT
+ {
+ const auto& BorderColor = SrcSmplr.Desc.BorderColor;
+ if (!((BorderColor[0] == 0 && BorderColor[1] == 0 && BorderColor[2] == 0 && BorderColor[3] == 0) ||
+ (BorderColor[0] == 0 && BorderColor[1] == 0 && BorderColor[2] == 0 && BorderColor[3] == 1) ||
+ (BorderColor[0] == 1 && BorderColor[1] == 1 && BorderColor[2] == 1 && BorderColor[3] == 1)))
+ {
+ LOG_WARNING_MESSAGE("Immutable sampler for variable \"", SrcSmplr.SamplerOrTextureName, "\" specifies border color (",
+ BorderColor[0], ", ", BorderColor[1], ", ", BorderColor[2], ", ", BorderColor[3],
+ "). D3D12 static samplers only allow transparent black (0,0,0,0), opaque black (0,0,0,1) or opaque white (1,1,1,1) as border colors");
+ }
+ }
+#endif
- if (!LogicOpEnable)
- RTDesc.LogicOp = RenderTargetBlendDesc{}.LogicOp;
+ ImmutableSamplers[i] = SrcSmplr;
+ ImmutableSamplers[i].SamplerOrTextureName = MemPool.CopyString(SrcSmplr.SamplerOrTextureName);
+ }
}
}
-#undef LOG_PSO_ERROR_AND_THROW
+
+protected:
+ size_t m_ShaderResourceLayoutHash = 0; ///< Hash computed from the shader resource layout
+
+ Uint32* m_pStrides = nullptr;
+ Uint8 m_BufferSlotsUsed = 0;
+
+ Uint8 m_NumShaderStages = 0; ///< Number of shader stages in this PSO
+
+ /// Array of shader types for every shader stage used by this PSO
+ std::array<SHADER_TYPE, MAX_SHADERS_IN_PIPELINE> m_ShaderStageTypes = {};
+
+ RefCntAutoPtr<IRenderPass> m_pRenderPass; ///< Strong reference to the render pass object
+
+ GraphicsPipelineDesc* m_pGraphicsPipelineDesc = nullptr;
};
} // namespace Diligent
diff --git a/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp b/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp
index 5648e39d..1130fbff 100644
--- a/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp
+++ b/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp
@@ -32,6 +32,7 @@
#include <vector>
+#include "Atomics.hpp"
#include "ShaderResourceVariable.h"
#include "PipelineState.h"
#include "StringTools.hpp"
@@ -114,15 +115,15 @@ inline Uint32 GetAllowedTypeBits(const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVar
return AllowedTypeBits;
}
-inline Int32 FindStaticSampler(const StaticSamplerDesc* StaticSamplers,
- Uint32 NumStaticSamplers,
- SHADER_TYPE ShaderType,
- const char* ResourceName,
- const char* SamplerSuffix)
+inline Int32 FindImmutableSampler(const ImmutableSamplerDesc* ImtblSamplers,
+ Uint32 NumImtblSamplers,
+ SHADER_TYPE ShaderType,
+ const char* ResourceName,
+ const char* SamplerSuffix)
{
- for (Uint32 s = 0; s < NumStaticSamplers; ++s)
+ for (Uint32 s = 0; s < NumImtblSamplers; ++s)
{
- const auto& StSam = StaticSamplers[s];
+ const auto& StSam = ImtblSamplers[s];
if (((StSam.ShaderStages & ShaderType) != 0) && StreqSuff(ResourceName, StSam.SamplerOrTextureName, SamplerSuffix))
return s;
}
@@ -214,6 +215,28 @@ inline const char* GetResourceTypeName<BUFFER_VIEW_TYPE>()
return "buffer view";
}
+inline RESOURCE_DIMENSION GetResourceViewDimension(const ITextureView* pTexView)
+{
+ VERIFY_EXPR(pTexView != nullptr);
+ return pTexView->GetDesc().TextureDim;
+}
+
+inline RESOURCE_DIMENSION GetResourceViewDimension(const IBufferView* /*pBuffView*/)
+{
+ return RESOURCE_DIM_BUFFER;
+}
+
+inline Uint32 GetResourceSampleCount(const ITextureView* pTexView)
+{
+ VERIFY_EXPR(pTexView != nullptr);
+ return const_cast<ITextureView*>(pTexView)->GetTexture()->GetDesc().SampleCount;
+}
+
+inline Uint32 GetResourceSampleCount(const IBufferView* /*pBuffView*/)
+{
+ return 0;
+}
+
template <typename ResourceAttribsType,
typename ResourceViewImplType,
typename ViewTypeEnumType>
@@ -254,8 +277,6 @@ bool VerifyResourceViewBinding(const ResourceAttribsType& Attribs,
if (!IsExpectedViewType)
{
- std::string ExpectedViewTypeName;
-
std::stringstream ss;
ss << "Error binding " << ExpectedResourceType << " '" << pViewImpl->GetDesc().Name << "' to variable '"
<< Attribs.GetPrintName(ArrayIndex) << '\'';
@@ -279,11 +300,45 @@ bool VerifyResourceViewBinding(const ResourceAttribsType& Attribs,
BindingOK = false;
}
+
+ const auto ExpectedResourceDim = Attribs.GetResourceDimension();
+ if (ExpectedResourceDim != RESOURCE_DIM_UNDEFINED)
+ {
+ auto ResourceDim = GetResourceViewDimension(pViewImpl);
+ if (ResourceDim != ExpectedResourceDim)
+ {
+ LOG_ERROR_MESSAGE("Error binding ", ExpectedResourceType, " '", pViewImpl->GetDesc().Name, "' to variable '",
+ Attribs.GetPrintName(ArrayIndex), "': incorrect resource dimension: ",
+ GetResourceDimString(ExpectedResourceDim), " is expected, but the actual dimension is ",
+ GetResourceDimString(ResourceDim));
+
+ BindingOK = false;
+ }
+
+ if (ResourceDim == RESOURCE_DIM_TEX_2D || ResourceDim == RESOURCE_DIM_TEX_2D_ARRAY)
+ {
+ auto SampleCount = GetResourceSampleCount(pViewImpl);
+ auto IsMS = Attribs.IsMultisample();
+ if (IsMS && SampleCount == 1)
+ {
+ LOG_ERROR_MESSAGE("Error binding ", ExpectedResourceType, " '", pViewImpl->GetDesc().Name, "' to variable '",
+ Attribs.GetPrintName(ArrayIndex), "': multisample texture is expected.");
+ BindingOK = false;
+ }
+ else if (!IsMS && SampleCount > 1)
+ {
+ LOG_ERROR_MESSAGE("Error binding ", ExpectedResourceType, " '", pViewImpl->GetDesc().Name, "' to variable '",
+ Attribs.GetPrintName(ArrayIndex), "': single-sample texture is expected.");
+ BindingOK = false;
+ }
+ }
+ }
}
if (VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && pCachedView != nullptr && pCachedView != pViewImpl)
{
- auto VarTypeStr = GetShaderVariableTypeLiteralName(VarType);
+ const auto* VarTypeStr = GetShaderVariableTypeLiteralName(VarType);
+
std::stringstream ss;
ss << "Non-null resource '" << pCachedView->GetDesc().Name << "' is already bound to " << VarTypeStr
<< " shader variable '" << Attribs.GetPrintName(ArrayIndex) << '\'';
@@ -305,6 +360,7 @@ bool VerifyResourceViewBinding(const ResourceAttribsType& Attribs,
BindingOK = false;
}
+
return BindingOK;
}
@@ -340,7 +396,7 @@ template <typename ResourceLayoutType,
struct ShaderVariableBase : public ResourceVariableBaseInterface
{
ShaderVariableBase(ResourceLayoutType& ParentResLayout) :
- m_ParentResLayout(ParentResLayout)
+ m_ParentResLayout{ParentResLayout}
{
}
diff --git a/Graphics/GraphicsEngine/include/TextureBase.hpp b/Graphics/GraphicsEngine/include/TextureBase.hpp
index 1805f7d3..559df1ea 100644
--- a/Graphics/GraphicsEngine/include/TextureBase.hpp
+++ b/Graphics/GraphicsEngine/include/TextureBase.hpp
@@ -30,13 +30,14 @@
/// \file
/// Implementation of the Diligent::TextureBase template class
+#include <memory>
+
#include "Texture.h"
#include "GraphicsTypes.h"
#include "DeviceObjectBase.hpp"
#include "GraphicsAccessories.hpp"
#include "STDAllocator.hpp"
#include "FormatString.hpp"
-#include <memory>
namespace Diligent
{
diff --git a/Graphics/GraphicsEngine/interface/APIInfo.h b/Graphics/GraphicsEngine/interface/APIInfo.h
index a7596e3f..0ecbd92b 100644
--- a/Graphics/GraphicsEngine/interface/APIInfo.h
+++ b/Graphics/GraphicsEngine/interface/APIInfo.h
@@ -30,7 +30,7 @@
/// \file
/// Diligent API information
-#define DILIGENT_API_VERSION 240074
+#define DILIGENT_API_VERSION 240078
#include "../../../Primitives/interface/BasicTypes.h"
@@ -39,64 +39,65 @@ DILIGENT_BEGIN_NAMESPACE(Diligent)
/// Diligent API Info. This tructure can be used to verify API compatibility.
struct APIInfo
{
- size_t StructSize DEFAULT_INITIALIZER(0);
- int APIVersion DEFAULT_INITIALIZER(0);
- size_t RenderTargetBlendDescSize DEFAULT_INITIALIZER(0);
- size_t BlendStateDescSize DEFAULT_INITIALIZER(0);
- size_t BufferDescSize DEFAULT_INITIALIZER(0);
- size_t BufferDataSize DEFAULT_INITIALIZER(0);
- size_t BufferFormatSize DEFAULT_INITIALIZER(0);
- size_t BufferViewDescSize DEFAULT_INITIALIZER(0);
- size_t StencilOpDescSize DEFAULT_INITIALIZER(0);
- size_t DepthStencilStateDescSize DEFAULT_INITIALIZER(0);
- size_t SamplerCapsSize DEFAULT_INITIALIZER(0);
- size_t TextureCapsSize DEFAULT_INITIALIZER(0);
- size_t DeviceCapsSize DEFAULT_INITIALIZER(0);
- size_t DrawAttribsSize DEFAULT_INITIALIZER(0);
- size_t DispatchComputeAttribsSize DEFAULT_INITIALIZER(0);
- size_t ViewportSize DEFAULT_INITIALIZER(0);
- size_t RectSize DEFAULT_INITIALIZER(0);
- size_t CopyTextureAttribsSize DEFAULT_INITIALIZER(0);
- size_t DeviceObjectAttribsSize DEFAULT_INITIALIZER(0);
- size_t GraphicsAdapterInfoSize DEFAULT_INITIALIZER(0);
- size_t DisplayModeAttribsSize DEFAULT_INITIALIZER(0);
- size_t SwapChainDescSize DEFAULT_INITIALIZER(0);
- size_t FullScreenModeDescSize DEFAULT_INITIALIZER(0);
- size_t EngineCreateInfoSize DEFAULT_INITIALIZER(0);
- size_t EngineGLCreateInfoSize DEFAULT_INITIALIZER(0);
- size_t EngineD3D11CreateInfoSize DEFAULT_INITIALIZER(0);
- size_t EngineD3D12CreateInfoSize DEFAULT_INITIALIZER(0);
- size_t EngineVkCreateInfoSize DEFAULT_INITIALIZER(0);
- size_t EngineMtlCreateInfoSize DEFAULT_INITIALIZER(0);
- size_t BoxSize DEFAULT_INITIALIZER(0);
- size_t TextureFormatAttribsSize DEFAULT_INITIALIZER(0);
- size_t TextureFormatInfoSize DEFAULT_INITIALIZER(0);
- size_t TextureFormatInfoExtSize DEFAULT_INITIALIZER(0);
- size_t StateTransitionDescSize DEFAULT_INITIALIZER(0);
- size_t LayoutElementSize DEFAULT_INITIALIZER(0);
- size_t InputLayoutDescSize DEFAULT_INITIALIZER(0);
- size_t SampleDescSize DEFAULT_INITIALIZER(0);
- size_t ShaderResourceVariableDescSize DEFAULT_INITIALIZER(0);
- size_t StaticSamplerDescSize DEFAULT_INITIALIZER(0);
- size_t PipelineResourceLayoutDescSize DEFAULT_INITIALIZER(0);
- size_t GraphicsPipelineDescSize DEFAULT_INITIALIZER(0);
- size_t ComputePipelineDescSize DEFAULT_INITIALIZER(0);
- size_t PipelineStateDescSize DEFAULT_INITIALIZER(0);
- size_t RasterizerStateDescSize DEFAULT_INITIALIZER(0);
- size_t ResourceMappingEntrySize DEFAULT_INITIALIZER(0);
- size_t ResourceMappingDescSize DEFAULT_INITIALIZER(0);
- size_t SamplerDescSize DEFAULT_INITIALIZER(0);
- size_t ShaderDescSize DEFAULT_INITIALIZER(0);
- size_t ShaderMacroSize DEFAULT_INITIALIZER(0);
- size_t ShaderCreateInfoSize DEFAULT_INITIALIZER(0);
- size_t ShaderResourceDescSize DEFAULT_INITIALIZER(0);
- size_t DepthStencilClearValueSize DEFAULT_INITIALIZER(0);
- size_t OptimizedClearValueSize DEFAULT_INITIALIZER(0);
- size_t TextureDescSize DEFAULT_INITIALIZER(0);
- size_t TextureSubResDataSize DEFAULT_INITIALIZER(0);
- size_t TextureDataSize DEFAULT_INITIALIZER(0);
- size_t MappedTextureSubresourceSize DEFAULT_INITIALIZER(0);
- size_t TextureViewDescSize DEFAULT_INITIALIZER(0);
+ size_t StructSize DEFAULT_INITIALIZER(0);
+ int APIVersion DEFAULT_INITIALIZER(0);
+ size_t RenderTargetBlendDescSize DEFAULT_INITIALIZER(0);
+ size_t BlendStateDescSize DEFAULT_INITIALIZER(0);
+ size_t BufferDescSize DEFAULT_INITIALIZER(0);
+ size_t BufferDataSize DEFAULT_INITIALIZER(0);
+ size_t BufferFormatSize DEFAULT_INITIALIZER(0);
+ size_t BufferViewDescSize DEFAULT_INITIALIZER(0);
+ size_t StencilOpDescSize DEFAULT_INITIALIZER(0);
+ size_t DepthStencilStateDescSize DEFAULT_INITIALIZER(0);
+ size_t SamplerCapsSize DEFAULT_INITIALIZER(0);
+ size_t TextureCapsSize DEFAULT_INITIALIZER(0);
+ size_t DeviceCapsSize DEFAULT_INITIALIZER(0);
+ size_t DrawAttribsSize DEFAULT_INITIALIZER(0);
+ size_t DispatchComputeAttribsSize DEFAULT_INITIALIZER(0);
+ size_t ViewportSize DEFAULT_INITIALIZER(0);
+ size_t RectSize DEFAULT_INITIALIZER(0);
+ size_t CopyTextureAttribsSize DEFAULT_INITIALIZER(0);
+ size_t DeviceObjectAttribsSize DEFAULT_INITIALIZER(0);
+ size_t GraphicsAdapterInfoSize DEFAULT_INITIALIZER(0);
+ size_t DisplayModeAttribsSize DEFAULT_INITIALIZER(0);
+ size_t SwapChainDescSize DEFAULT_INITIALIZER(0);
+ size_t FullScreenModeDescSize DEFAULT_INITIALIZER(0);
+ size_t EngineCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t EngineGLCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t EngineD3D11CreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t EngineD3D12CreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t EngineVkCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t EngineMtlCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t BoxSize DEFAULT_INITIALIZER(0);
+ size_t TextureFormatAttribsSize DEFAULT_INITIALIZER(0);
+ size_t TextureFormatInfoSize DEFAULT_INITIALIZER(0);
+ size_t TextureFormatInfoExtSize DEFAULT_INITIALIZER(0);
+ size_t StateTransitionDescSize DEFAULT_INITIALIZER(0);
+ size_t LayoutElementSize DEFAULT_INITIALIZER(0);
+ size_t InputLayoutDescSize DEFAULT_INITIALIZER(0);
+ size_t SampleDescSize DEFAULT_INITIALIZER(0);
+ size_t ShaderResourceVariableDescSize DEFAULT_INITIALIZER(0);
+ size_t ImmutableSamplerDescSize DEFAULT_INITIALIZER(0);
+ size_t PipelineResourceLayoutDescSize DEFAULT_INITIALIZER(0);
+ size_t GraphicsPipelineDescSize DEFAULT_INITIALIZER(0);
+ size_t GraphicsPipelineStateCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t ComputePipelineStateCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t PipelineStateDescSize DEFAULT_INITIALIZER(0);
+ size_t RasterizerStateDescSize DEFAULT_INITIALIZER(0);
+ size_t ResourceMappingEntrySize DEFAULT_INITIALIZER(0);
+ size_t ResourceMappingDescSize DEFAULT_INITIALIZER(0);
+ size_t SamplerDescSize DEFAULT_INITIALIZER(0);
+ size_t ShaderDescSize DEFAULT_INITIALIZER(0);
+ size_t ShaderMacroSize DEFAULT_INITIALIZER(0);
+ size_t ShaderCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t ShaderResourceDescSize DEFAULT_INITIALIZER(0);
+ size_t DepthStencilClearValueSize DEFAULT_INITIALIZER(0);
+ size_t OptimizedClearValueSize DEFAULT_INITIALIZER(0);
+ size_t TextureDescSize DEFAULT_INITIALIZER(0);
+ size_t TextureSubResDataSize DEFAULT_INITIALIZER(0);
+ size_t TextureDataSize DEFAULT_INITIALIZER(0);
+ size_t MappedTextureSubresourceSize DEFAULT_INITIALIZER(0);
+ size_t TextureViewDescSize DEFAULT_INITIALIZER(0);
};
typedef struct APIInfo APIInfo;
diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h
index 56db9e61..85dbcff6 100644
--- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h
+++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h
@@ -105,7 +105,7 @@ DILIGENT_TYPED_ENUM(USAGE, Uint8)
/// when it is created, since it cannot be changed after creation. \n
/// D3D11 Counterpart: D3D11_USAGE_IMMUTABLE. OpenGL counterpart: GL_STATIC_DRAW
/// \remarks Static buffers do not allow CPU access and must use CPU_ACCESS_NONE flag.
- USAGE_STATIC = 0,
+ USAGE_IMMUTABLE = 0,
/// A resource that requires read and write access by the GPU and can also be occasionally
/// written by the CPU. \n
@@ -213,16 +213,16 @@ DEFINE_FLAG_ENUM_OPERATORS(MAP_FLAGS)
/// - TextureViewDesc to describe texture view type
DILIGENT_TYPED_ENUM(RESOURCE_DIMENSION, Uint8)
{
- RESOURCE_DIM_UNDEFINED = 0, ///< Texture type undefined
- RESOURCE_DIM_BUFFER, ///< Buffer
- RESOURCE_DIM_TEX_1D, ///< One-dimensional texture
- RESOURCE_DIM_TEX_1D_ARRAY, ///< One-dimensional texture array
- RESOURCE_DIM_TEX_2D, ///< Two-dimensional texture
- RESOURCE_DIM_TEX_2D_ARRAY, ///< Two-dimensional texture array
- RESOURCE_DIM_TEX_3D, ///< Three-dimensional texture
- RESOURCE_DIM_TEX_CUBE, ///< Cube-map texture
- RESOURCE_DIM_TEX_CUBE_ARRAY, ///< Cube-map array texture
- RESOURCE_DIM_NUM_DIMENSIONS ///< Helper value that stores the total number of texture types in the enumeration
+ RESOURCE_DIM_UNDEFINED = 0, ///< Texture type undefined
+ RESOURCE_DIM_BUFFER, ///< Buffer
+ RESOURCE_DIM_TEX_1D, ///< One-dimensional texture
+ RESOURCE_DIM_TEX_1D_ARRAY, ///< One-dimensional texture array
+ RESOURCE_DIM_TEX_2D, ///< Two-dimensional texture
+ RESOURCE_DIM_TEX_2D_ARRAY, ///< Two-dimensional texture array
+ RESOURCE_DIM_TEX_3D, ///< Three-dimensional texture
+ RESOURCE_DIM_TEX_CUBE, ///< Cube-map texture
+ RESOURCE_DIM_TEX_CUBE_ARRAY, ///< Cube-map array texture
+ RESOURCE_DIM_NUM_DIMENSIONS ///< Helper value that stores the total number of texture types in the enumeration
};
/// Texture view type
@@ -1517,6 +1517,17 @@ struct DeviceFeatures
/// Indicates if device supports separable programs
DEVICE_FEATURE_STATE SeparablePrograms DEFAULT_INITIALIZER(DEVICE_FEATURE_STATE_DISABLED);
+ /// Indicates if device supports resource queries from shader objects.
+
+ /// \ note This feature indicates if IShader::GetResourceCount() and IShader::GetResourceDesc() methods
+ /// can be used to query the list of resources of individual shader objects.
+ /// Shader variable queries from pipeline state and shader resource binding objects are always
+ /// available.
+ ///
+ /// The feature is always enabled in Direct3D11, Direct3D12 and Vulkan. It is enabled in
+ /// OpenGL when separable programs are available, and it is always disabled in Metal.
+ DEVICE_FEATURE_STATE ShaderResourceQueries DEFAULT_INITIALIZER(DEVICE_FEATURE_STATE_DISABLED);
+
/// Indicates if device supports indirect draw commands
DEVICE_FEATURE_STATE IndirectRendering DEFAULT_INITIALIZER(DEVICE_FEATURE_STATE_DISABLED);
@@ -1621,6 +1632,7 @@ struct DeviceFeatures
explicit DeviceFeatures(DEVICE_FEATURE_STATE State) noexcept :
SeparablePrograms {State},
+ ShaderResourceQueries {State},
IndirectRendering {State},
WireframeFill {State},
MultithreadedResourceCreation {State},
@@ -1653,7 +1665,7 @@ struct DeviceFeatures
UniformBuffer8BitAccess {State}
{
# if defined(_MSC_VER) && defined(_WIN64)
- static_assert(sizeof(*this) == 31, "Did you add a new feature to DeviceFeatures? Please handle its status above.");
+ static_assert(sizeof(*this) == 32, "Did you add a new feature to DeviceFeatures? Please handle its status above.");
# endif
}
#endif
@@ -1712,7 +1724,7 @@ struct GraphicsAdapterInfo
/// The amount of local video memory that is inaccessible by CPU, in bytes.
- /// \note Device-local memory is where USAGE_DEFAULT and USAGE_STATIC resources
+ /// \note Device-local memory is where USAGE_DEFAULT and USAGE_IMMUTABLE resources
/// are typically allocated.
///
/// On some devices it may not be possible to query the memory size,
@@ -1881,6 +1893,11 @@ struct EngineGLCreateInfo DILIGENT_DERIVE(EngineCreateInfo)
/// provide additional runtime checking, validation, and logging
/// functionality while possibly incurring performance penalties
bool CreateDebugContext DEFAULT_INITIALIZER(false);
+
+ /// Force using non-separable programs.
+
+ /// Setting this to true is typically needed for testing purposes only.
+ bool ForceNonSeparablePrograms DEFAULT_INITIALIZER(false);
};
typedef struct EngineGLCreateInfo EngineGLCreateInfo;
diff --git a/Graphics/GraphicsEngine/interface/InputLayout.h b/Graphics/GraphicsEngine/interface/InputLayout.h
index 19904974..c7b18965 100644
--- a/Graphics/GraphicsEngine/interface/InputLayout.h
+++ b/Graphics/GraphicsEngine/interface/InputLayout.h
@@ -179,7 +179,7 @@ typedef struct LayoutElement LayoutElement;
/// Layout description
-/// This structure is used by IRenderDevice::CreatePipelineState().
+/// This structure is used by IRenderDevice::CreateGraphicsPipelineState().
struct InputLayoutDesc
{
/// Array of layout elements
diff --git a/Graphics/GraphicsEngine/interface/PipelineState.h b/Graphics/GraphicsEngine/interface/PipelineState.h
index 2ea0d224..f953b851 100644
--- a/Graphics/GraphicsEngine/interface/PipelineState.h
+++ b/Graphics/GraphicsEngine/interface/PipelineState.h
@@ -96,32 +96,36 @@ struct ShaderResourceVariableDesc
typedef struct ShaderResourceVariableDesc ShaderResourceVariableDesc;
-/// Static sampler description
-struct StaticSamplerDesc
+/// Immutable sampler description.
+
+/// An immutable sampler is compiled into the pipeline state and can't be changed.
+/// It is generally more efficient than a regular sampler and should be used
+/// whenever possible.
+struct ImmutableSamplerDesc
{
- /// Shader stages that this static sampler applies to. More than one shader stage can be specified.
+ /// Shader stages that this immutable sampler applies to. More than one shader stage can be specified.
SHADER_TYPE ShaderStages DEFAULT_INITIALIZER(SHADER_TYPE_UNKNOWN);
/// The name of the sampler itself or the name of the texture variable that
- /// this static sampler is assigned to if combined texture samplers are used.
+ /// this immutable sampler is assigned to if combined texture samplers are used.
const Char* SamplerOrTextureName DEFAULT_INITIALIZER(nullptr);
/// Sampler description
struct SamplerDesc Desc;
#if DILIGENT_CPP_INTERFACE
- StaticSamplerDesc()noexcept{}
+ ImmutableSamplerDesc()noexcept{}
- StaticSamplerDesc(SHADER_TYPE _ShaderStages,
- const Char* _SamplerOrTextureName,
- const SamplerDesc& _Desc)noexcept :
+ ImmutableSamplerDesc(SHADER_TYPE _ShaderStages,
+ const Char* _SamplerOrTextureName,
+ const SamplerDesc& _Desc)noexcept :
ShaderStages {_ShaderStages },
SamplerOrTextureName{_SamplerOrTextureName},
Desc {_Desc }
{}
#endif
};
-typedef struct StaticSamplerDesc StaticSamplerDesc;
+typedef struct ImmutableSamplerDesc ImmutableSamplerDesc;
/// Pipeline layout description
struct PipelineResourceLayoutDesc
@@ -129,19 +133,19 @@ struct PipelineResourceLayoutDesc
/// Default shader resource variable type. This type will be used if shader
/// variable description is not found in the Variables array
/// or if Variables == nullptr
- SHADER_RESOURCE_VARIABLE_TYPE DefaultVariableType DEFAULT_INITIALIZER(SHADER_RESOURCE_VARIABLE_TYPE_STATIC);
+ SHADER_RESOURCE_VARIABLE_TYPE DefaultVariableType DEFAULT_INITIALIZER(SHADER_RESOURCE_VARIABLE_TYPE_STATIC);
/// Number of elements in Variables array
- Uint32 NumVariables DEFAULT_INITIALIZER(0);
+ Uint32 NumVariables DEFAULT_INITIALIZER(0);
/// Array of shader resource variable descriptions
- const ShaderResourceVariableDesc* Variables DEFAULT_INITIALIZER(nullptr);
+ const ShaderResourceVariableDesc* Variables DEFAULT_INITIALIZER(nullptr);
- /// Number of static samplers in StaticSamplers array
- Uint32 NumStaticSamplers DEFAULT_INITIALIZER(0);
+ /// Number of immutable samplers in ImmutableSamplers array
+ Uint32 NumImmutableSamplers DEFAULT_INITIALIZER(0);
- /// Array of static sampler descriptions
- const StaticSamplerDesc* StaticSamplers DEFAULT_INITIALIZER(nullptr);
+ /// Array of immutable sampler descriptions
+ const ImmutableSamplerDesc* ImmutableSamplers DEFAULT_INITIALIZER(nullptr);
};
typedef struct PipelineResourceLayoutDesc PipelineResourceLayoutDesc;
@@ -151,29 +155,6 @@ typedef struct PipelineResourceLayoutDesc PipelineResourceLayoutDesc;
/// This structure describes the graphics pipeline state and is part of the PipelineStateDesc structure.
struct GraphicsPipelineDesc
{
- /// Vertex shader to be used with the pipeline.
- IShader* pVS DEFAULT_INITIALIZER(nullptr);
-
- /// Pixel shader to be used with the pipeline.
- IShader* pPS DEFAULT_INITIALIZER(nullptr);
-
- /// Domain shader to be used with the pipeline.
- IShader* pDS DEFAULT_INITIALIZER(nullptr);
-
- /// Hull shader to be used with the pipeline.
- IShader* pHS DEFAULT_INITIALIZER(nullptr);
-
- /// Geometry shader to be used with the pipeline.
- IShader* pGS DEFAULT_INITIALIZER(nullptr);
-
- /// Amplification shader to be used with the pipeline.
- IShader* pAS DEFAULT_INITIALIZER(nullptr);
-
- /// Mesh shader to be used with the pipeline.
- IShader* pMS DEFAULT_INITIALIZER(nullptr);
-
- //D3D12_STREAM_OUTPUT_DESC StreamOutput;
-
/// Blend state description.
BlendStateDesc BlendDesc;
@@ -348,19 +329,9 @@ struct PipelineStateDesc DILIGENT_DERIVE(DeviceObjectAttribs)
/// Pipeline layout description
PipelineResourceLayoutDesc ResourceLayout;
- /// Graphics pipeline state description. This memeber is ignored if PipelineType is not PIPELINE_TYPE_GRAPHICS or PIPELINE_TYPE_MESH
- GraphicsPipelineDesc GraphicsPipeline;
-
- /// Compute pipeline state description. This memeber is ignored if PipelineType is not PIPELINE_TYPE_COMPUTE
- ComputePipelineDesc ComputePipeline;
-
- // TODO (AZ): use pointer
- /// Ray tracing pipeline state description. This memeber is ignored if PipelineType is not PIPELINE_TYPE_RAY_TRACING.
- RayTracingPipelineDesc RayTracingPipeline;
-
#if DILIGENT_CPP_INTERFACE
bool IsAnyGraphicsPipeline() const { return PipelineType == PIPELINE_TYPE_GRAPHICS || PipelineType == PIPELINE_TYPE_MESH; }
- bool IsComputePipeline () const { return PipelineType == PIPELINE_TYPE_COMPUTE; }
+ bool IsComputePipeline() const { return PipelineType == PIPELINE_TYPE_COMPUTE; }
#endif
};
typedef struct PipelineStateDesc PipelineStateDesc;
@@ -370,7 +341,7 @@ typedef struct PipelineStateDesc PipelineStateDesc;
DILIGENT_TYPED_ENUM(PSO_CREATE_FLAGS, Uint32)
{
/// Null flag.
- PSO_CREATE_FLAG_NONE = 0x00,
+ PSO_CREATE_FLAG_NONE = 0x00,
/// Ignore missing variables.
@@ -378,15 +349,15 @@ DILIGENT_TYPED_ENUM(PSO_CREATE_FLAGS, Uint32)
/// provided as part of the pipeline resource layout description
/// that is not found in any of the designated shader stages.
/// Use this flag to silence these warnings.
- PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES = 0x01,
+ PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES = 0x01,
- /// Ignore missing static samplers.
+ /// Ignore missing immutable samplers.
- /// By default, the engine outputs a warning for every static sampler
+ /// By default, the engine outputs a warning for every immutable sampler
/// provided as part of the pipeline resource layout description
/// that is not found in any of the designated shader stages.
/// Use this flag to silence these warnings.
- PSO_CREATE_FLAG_IGNORE_MISSING_STATIC_SAMPLERS = 0x02,
+ PSO_CREATE_FLAG_IGNORE_MISSING_IMMUTABLE_SAMPLERS = 0x02,
};
DEFINE_FLAG_ENUM_OPERATORS(PSO_CREATE_FLAGS);
@@ -398,10 +369,57 @@ struct PipelineStateCreateInfo
PipelineStateDesc PSODesc;
/// Pipeline state creation flags, see Diligent::PSO_CREATE_FLAGS.
- PSO_CREATE_FLAGS Flags DEFAULT_INITIALIZER(PSO_CREATE_FLAG_NONE);
+ PSO_CREATE_FLAGS Flags DEFAULT_INITIALIZER(PSO_CREATE_FLAG_NONE);
};
typedef struct PipelineStateCreateInfo PipelineStateCreateInfo;
+
+/// Graphics pipeline state creation attributes
+struct GraphicsPipelineStateCreateInfo DILIGENT_DERIVE(PipelineStateCreateInfo)
+
+ /// Graphics pipeline state description.
+ GraphicsPipelineDesc GraphicsPipeline;
+
+ /// Vertex shader to be used with the pipeline.
+ IShader* pVS DEFAULT_INITIALIZER(nullptr);
+
+ /// Pixel shader to be used with the pipeline.
+ IShader* pPS DEFAULT_INITIALIZER(nullptr);
+
+ /// Domain shader to be used with the pipeline.
+ IShader* pDS DEFAULT_INITIALIZER(nullptr);
+
+ /// Hull shader to be used with the pipeline.
+ IShader* pHS DEFAULT_INITIALIZER(nullptr);
+
+ /// Geometry shader to be used with the pipeline.
+ IShader* pGS DEFAULT_INITIALIZER(nullptr);
+
+ /// Amplification shader to be used with the pipeline.
+ IShader* pAS DEFAULT_INITIALIZER(nullptr);
+
+ /// Mesh shader to be used with the pipeline.
+ IShader* pMS DEFAULT_INITIALIZER(nullptr);
+};
+typedef struct GraphicsPipelineStateCreateInfo GraphicsPipelineStateCreateInfo;
+
+
+/// Compute pipeline state description.
+struct ComputePipelineStateCreateInfo DILIGENT_DERIVE(PipelineStateCreateInfo)
+
+ /// Compute shader to be used with the pipeline
+ IShader* pCS DEFAULT_INITIALIZER(nullptr);
+
+#if DILIGENT_CPP_INTERFACE
+ ComputePipelineStateCreateInfo() noexcept
+ {
+ PSODesc.PipelineType = PIPELINE_TYPE_COMPUTE;
+ }
+#endif
+};
+typedef struct ComputePipelineStateCreateInfo ComputePipelineStateCreateInfo;
+
+
// {06084AE5-6A71-4FE8-84B9-395DD489A28C}
static const struct INTERFACE_ID IID_PipelineState =
{0x6084ae5, 0x6a71, 0x4fe8, {0x84, 0xb9, 0x39, 0x5d, 0xd4, 0x89, 0xa2, 0x8c}};
@@ -419,10 +437,13 @@ static const struct INTERFACE_ID IID_PipelineState =
DILIGENT_BEGIN_INTERFACE(IPipelineState, IDeviceObject)
{
#if DILIGENT_CPP_INTERFACE
- /// Returns the blend state description used to create the object
- virtual const PipelineStateDesc& METHOD(GetDesc)()const override = 0;
+ /// Returns the pipeline description used to create the object
+ virtual const PipelineStateDesc& METHOD(GetDesc)() const override = 0;
#endif
+ /// Returns the graphics pipeline description used to create the object.
+ /// This method must only be called for a graphics or mesh pipeline.
+ VIRTUAL const GraphicsPipelineDesc REF METHOD(GetGraphicsPipelineDesc)(THIS) CONST PURE;
/// Binds resources for all shaders in the pipeline state
@@ -512,6 +533,7 @@ DILIGENT_END_INTERFACE
# define IPipelineState_GetDesc(This) (const struct PipelineStateDesc*)IDeviceObject_GetDesc(This)
+# define IPipelineState_GetGraphicsPipelineDesc(This) CALL_IFACE_METHOD(PipelineState, GetGraphicsPipelineDesc, This)
# define IPipelineState_BindStaticResources(This, ...) CALL_IFACE_METHOD(PipelineState, BindStaticResources, This, __VA_ARGS__)
# define IPipelineState_GetStaticVariableCount(This, ...) CALL_IFACE_METHOD(PipelineState, GetStaticVariableCount, This, __VA_ARGS__)
# define IPipelineState_GetStaticVariableByName(This, ...) CALL_IFACE_METHOD(PipelineState, GetStaticVariableByName, This, __VA_ARGS__)
diff --git a/Graphics/GraphicsEngine/interface/RenderDevice.h b/Graphics/GraphicsEngine/interface/RenderDevice.h
index 027d0f5c..19d98a94 100644
--- a/Graphics/GraphicsEngine/interface/RenderDevice.h
+++ b/Graphics/GraphicsEngine/interface/RenderDevice.h
@@ -78,7 +78,7 @@ DILIGENT_BEGIN_INTERFACE(IRenderDevice, IObject)
/// \param [in] BuffDesc - Buffer description, see Diligent::BufferDesc for details.
/// \param [in] pBuffData - Pointer to Diligent::BufferData structure that describes
/// initial buffer data or nullptr if no data is provided.
- /// Static buffers (USAGE_STATIC) must be initialized at creation time.
+ /// Immutable buffers (USAGE_IMMUTABLE) must be initialized at creation time.
/// \param [out] ppBuffer - Address of the memory location where the pointer to the
/// buffer interface will be stored. The function calls AddRef(),
/// so that the new buffer will contain one reference and must be
@@ -109,7 +109,7 @@ DILIGENT_BEGIN_INTERFACE(IRenderDevice, IObject)
/// \param [in] TexDesc - Texture description, see Diligent::TextureDesc for details.
/// \param [in] pData - Pointer to Diligent::TextureData structure that describes
/// initial texture data or nullptr if no data is provided.
- /// Static textures (USAGE_STATIC) must be initialized at creation time.
+ /// Immutable textures (USAGE_IMMUTABLE) must be initialized at creation time.
///
/// \param [out] ppTexture - Address of the memory location where the pointer to the
/// texture interface will be stored.
@@ -156,17 +156,27 @@ DILIGENT_BEGIN_INTERFACE(IRenderDevice, IObject)
const ResourceMappingDesc REF MappingDesc,
IResourceMapping** ppMapping) PURE;
- /// Creates a new pipeline state object
+ /// Creates a new graphics pipeline state object
- /// \param [in] PSOCreateInfo - Pipeline state create info, see Diligent::PipelineStateCreateInfo for details.
+ /// \param [in] PSOCreateInfo - Graphics pipeline state create info, see Diligent::GraphicsPipelineStateCreateInfo for details.
/// \param [out] ppPipelineState - Address of the memory location where the pointer to the
/// pipeline state interface will be stored.
/// The function calls AddRef(), so that the new object will contain
/// one reference.
- VIRTUAL void METHOD(CreatePipelineState)(THIS_
- const PipelineStateCreateInfo REF PSOCreateInfo,
- IPipelineState** ppPipelineState) PURE;
+ VIRTUAL void METHOD(CreateGraphicsPipelineState)(THIS_
+ const GraphicsPipelineStateCreateInfo REF PSOCreateInfo,
+ IPipelineState** ppPipelineState) PURE;
+
+ /// Creates a new compute pipeline state object
+ /// \param [in] PSOCreateInfo - Compute pipeline state create info, see Diligent::ComputePipelineStateCreateInfo for details.
+ /// \param [out] ppPipelineState - Address of the memory location where the pointer to the
+ /// pipeline state interface will be stored.
+ /// The function calls AddRef(), so that the new object will contain
+ /// one reference.
+ VIRTUAL void METHOD(CreateComputePipelineState)(THIS_
+ const ComputePipelineStateCreateInfo REF PSOCreateInfo,
+ IPipelineState** ppPipelineState) PURE;
/// Creates a new fence object
@@ -312,20 +322,21 @@ DILIGENT_END_INTERFACE
// clang-format off
-# define IRenderDevice_CreateBuffer(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateBuffer, This, __VA_ARGS__)
-# define IRenderDevice_CreateShader(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateShader, This, __VA_ARGS__)
-# define IRenderDevice_CreateTexture(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateTexture, This, __VA_ARGS__)
-# define IRenderDevice_CreateSampler(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateSampler, This, __VA_ARGS__)
-# define IRenderDevice_CreateResourceMapping(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateResourceMapping, This, __VA_ARGS__)
-# define IRenderDevice_CreatePipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreatePipelineState, This, __VA_ARGS__)
-# define IRenderDevice_CreateFence(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateFence, This, __VA_ARGS__)
-# define IRenderDevice_CreateQuery(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateQuery, This, __VA_ARGS__)
-# define IRenderDevice_GetDeviceCaps(This) CALL_IFACE_METHOD(RenderDevice, GetDeviceCaps, This)
-# define IRenderDevice_GetTextureFormatInfo(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfo, This, __VA_ARGS__)
-# define IRenderDevice_GetTextureFormatInfoExt(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfoExt,This, __VA_ARGS__)
-# define IRenderDevice_ReleaseStaleResources(This, ...) CALL_IFACE_METHOD(RenderDevice, ReleaseStaleResources, This, __VA_ARGS__)
-# define IRenderDevice_IdleGPU(This) CALL_IFACE_METHOD(RenderDevice, IdleGPU, This)
-# define IRenderDevice_GetEngineFactory(This) CALL_IFACE_METHOD(RenderDevice, GetEngineFactory, This)
+# define IRenderDevice_CreateBuffer(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateBuffer, This, __VA_ARGS__)
+# define IRenderDevice_CreateShader(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateShader, This, __VA_ARGS__)
+# define IRenderDevice_CreateTexture(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateTexture, This, __VA_ARGS__)
+# define IRenderDevice_CreateSampler(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateSampler, This, __VA_ARGS__)
+# define IRenderDevice_CreateResourceMapping(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateResourceMapping, This, __VA_ARGS__)
+# define IRenderDevice_CreateGraphicsPipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateGraphicsPipelineState, This, __VA_ARGS__)
+# define IRenderDevice_CreateComputePipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateComputePipelineState, This, __VA_ARGS__)
+# define IRenderDevice_CreateFence(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateFence, This, __VA_ARGS__)
+# define IRenderDevice_CreateQuery(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateQuery, This, __VA_ARGS__)
+# define IRenderDevice_GetDeviceCaps(This) CALL_IFACE_METHOD(RenderDevice, GetDeviceCaps, This)
+# define IRenderDevice_GetTextureFormatInfo(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfo, This, __VA_ARGS__)
+# define IRenderDevice_GetTextureFormatInfoExt(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfoExt, This, __VA_ARGS__)
+# define IRenderDevice_ReleaseStaleResources(This, ...) CALL_IFACE_METHOD(RenderDevice, ReleaseStaleResources, This, __VA_ARGS__)
+# define IRenderDevice_IdleGPU(This) CALL_IFACE_METHOD(RenderDevice, IdleGPU, This)
+# define IRenderDevice_GetEngineFactory(This) CALL_IFACE_METHOD(RenderDevice, GetEngineFactory, This)
// clang-format on
diff --git a/Graphics/GraphicsEngine/interface/Shader.h b/Graphics/GraphicsEngine/interface/Shader.h
index 03dc06f0..950ecc77 100644
--- a/Graphics/GraphicsEngine/interface/Shader.h
+++ b/Graphics/GraphicsEngine/interface/Shader.h
@@ -352,7 +352,9 @@ DILIGENT_TYPED_ENUM(SHADER_RESOURCE_TYPE, Uint8)
SHADER_RESOURCE_TYPE_SAMPLER,
/// Input attachment in a render pass
- SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT
+ SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT,
+
+ SHADER_RESOURCE_TYPE_LAST = SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT
};
// clang-format on
diff --git a/Graphics/GraphicsEngine/src/APIInfo.cpp b/Graphics/GraphicsEngine/src/APIInfo.cpp
index f71b943e..e4111327 100644
--- a/Graphics/GraphicsEngine/src/APIInfo.cpp
+++ b/Graphics/GraphicsEngine/src/APIInfo.cpp
@@ -87,10 +87,11 @@ static APIInfo InitAPIInfo()
INIT_STRUCTURE_SIZE(InputLayoutDesc);
INIT_STRUCTURE_SIZE(SampleDesc);
INIT_STRUCTURE_SIZE(ShaderResourceVariableDesc);
- INIT_STRUCTURE_SIZE(StaticSamplerDesc);
+ INIT_STRUCTURE_SIZE(ImmutableSamplerDesc);
INIT_STRUCTURE_SIZE(PipelineResourceLayoutDesc);
INIT_STRUCTURE_SIZE(GraphicsPipelineDesc);
- INIT_STRUCTURE_SIZE(ComputePipelineDesc);
+ INIT_STRUCTURE_SIZE(GraphicsPipelineStateCreateInfo);
+ INIT_STRUCTURE_SIZE(ComputePipelineStateCreateInfo);
INIT_STRUCTURE_SIZE(PipelineStateDesc);
INIT_STRUCTURE_SIZE(RasterizerStateDesc);
INIT_STRUCTURE_SIZE(ResourceMappingEntry);
diff --git a/Graphics/GraphicsEngine/src/BufferBase.cpp b/Graphics/GraphicsEngine/src/BufferBase.cpp
index c42fd698..aab770fd 100644
--- a/Graphics/GraphicsEngine/src/BufferBase.cpp
+++ b/Graphics/GraphicsEngine/src/BufferBase.cpp
@@ -74,7 +74,7 @@ void ValidateBufferDesc(const BufferDesc& Desc, const DeviceCaps& deviceCaps)
switch (Desc.Usage)
{
- case USAGE_STATIC:
+ case USAGE_IMMUTABLE:
case USAGE_DEFAULT:
VERIFY_BUFFER(Desc.CPUAccessFlags == CPU_ACCESS_NONE, "static and default buffers can't have any CPU access flags set.");
break;
@@ -117,8 +117,8 @@ void ValidateBufferDesc(const BufferDesc& Desc, const DeviceCaps& deviceCaps)
void ValidateBufferInitData(const BufferDesc& Desc, const BufferData* pBuffData)
{
- if (Desc.Usage == USAGE_STATIC && (pBuffData == nullptr || pBuffData->pData == nullptr))
- LOG_BUFFER_ERROR_AND_THROW("initial data must not be null as static buffers must be initialized at creation time.");
+ if (Desc.Usage == USAGE_IMMUTABLE && (pBuffData == nullptr || pBuffData->pData == nullptr))
+ LOG_BUFFER_ERROR_AND_THROW("initial data must not be null as immutable buffers must be initialized at creation time.");
if (Desc.Usage == USAGE_DYNAMIC && pBuffData != nullptr && pBuffData->pData != nullptr)
LOG_BUFFER_ERROR_AND_THROW("initial data must be null for dynamic buffers.");
diff --git a/Graphics/GraphicsEngine/src/PipelineStateBase.cpp b/Graphics/GraphicsEngine/src/PipelineStateBase.cpp
new file mode 100644
index 00000000..fedc332d
--- /dev/null
+++ b/Graphics/GraphicsEngine/src/PipelineStateBase.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "pch.h"
+#include "PipelineStateBase.hpp"
+
+namespace Diligent
+{
+
+#define LOG_PSO_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of ", GetPipelineTypeString(PSODesc.PipelineType), " PSO '", PSODesc.Name, "' is invalid: ", ##__VA_ARGS__)
+
+namespace
+{
+
+void ValidateRasterizerStateDesc(const PipelineStateDesc& PSODesc, const GraphicsPipelineDesc& GraphicsPipeline) noexcept(false)
+{
+ const auto& RSDesc = GraphicsPipeline.RasterizerDesc;
+ if (RSDesc.FillMode == FILL_MODE_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("RasterizerDesc.FillMode must not be FILL_MODE_UNDEFINED");
+ if (RSDesc.CullMode == CULL_MODE_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("RasterizerDesc.CullMode must not be CULL_MODE_UNDEFINED");
+}
+
+void ValidateDepthStencilDesc(const PipelineStateDesc& PSODesc, const GraphicsPipelineDesc& GraphicsPipeline) noexcept(false)
+{
+ const auto& DSSDesc = GraphicsPipeline.DepthStencilDesc;
+ if (DSSDesc.DepthEnable && DSSDesc.DepthFunc == COMPARISON_FUNC_UNKNOWN)
+ LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.DepthFunc must not be COMPARISON_FUNC_UNKNOWN when depth is enabled");
+
+ auto CheckStencilOpDesc = [&](const StencilOpDesc& OpDesc, const char* FaceName) //
+ {
+ if (DSSDesc.StencilEnable)
+ {
+ if (OpDesc.StencilFailOp == STENCIL_OP_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilFailOp must not be STENCIL_OP_UNDEFINED when stencil is enabled");
+ if (OpDesc.StencilDepthFailOp == STENCIL_OP_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilDepthFailOp must not be STENCIL_OP_UNDEFINED when stencil is enabled");
+ if (OpDesc.StencilPassOp == STENCIL_OP_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilPassOp must not be STENCIL_OP_UNDEFINED when stencil is enabled");
+ if (OpDesc.StencilFunc == COMPARISON_FUNC_UNKNOWN)
+ LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilFunc must not be COMPARISON_FUNC_UNKNOWN when stencil is enabled");
+ }
+ };
+ CheckStencilOpDesc(DSSDesc.FrontFace, "FrontFace");
+ CheckStencilOpDesc(DSSDesc.BackFace, "BackFace");
+}
+
+void CorrectDepthStencilDesc(GraphicsPipelineDesc& GraphicsPipeline) noexcept
+{
+ auto& DSSDesc = GraphicsPipeline.DepthStencilDesc;
+ if (!DSSDesc.DepthEnable && DSSDesc.DepthFunc == COMPARISON_FUNC_UNKNOWN)
+ DSSDesc.DepthFunc = DepthStencilStateDesc{}.DepthFunc;
+
+ auto CorrectStencilOpDesc = [&](StencilOpDesc& OpDesc) //
+ {
+ if (!DSSDesc.StencilEnable)
+ {
+ if (OpDesc.StencilFailOp == STENCIL_OP_UNDEFINED)
+ OpDesc.StencilFailOp = StencilOpDesc{}.StencilFailOp;
+ if (OpDesc.StencilDepthFailOp == STENCIL_OP_UNDEFINED)
+ OpDesc.StencilDepthFailOp = StencilOpDesc{}.StencilDepthFailOp;
+ if (OpDesc.StencilPassOp == STENCIL_OP_UNDEFINED)
+ OpDesc.StencilPassOp = StencilOpDesc{}.StencilPassOp;
+ if (OpDesc.StencilFunc == COMPARISON_FUNC_UNKNOWN)
+ OpDesc.StencilFunc = StencilOpDesc{}.StencilFunc;
+ }
+ };
+ CorrectStencilOpDesc(DSSDesc.FrontFace);
+ CorrectStencilOpDesc(DSSDesc.BackFace);
+}
+
+void ValidateBlendStateDesc(const PipelineStateDesc& PSODesc, const GraphicsPipelineDesc& GraphicsPipeline) noexcept(false)
+{
+ const auto& BlendDesc = GraphicsPipeline.BlendDesc;
+ for (Uint32 rt = 0; rt < MAX_RENDER_TARGETS; ++rt)
+ {
+ auto& RTDesc = BlendDesc.RenderTargets[rt];
+
+ const auto BlendEnable = RTDesc.BlendEnable && (rt == 0 || (BlendDesc.IndependentBlendEnable && rt > 0));
+ if (BlendEnable)
+ {
+ if (RTDesc.SrcBlend == BLEND_FACTOR_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].SrcBlend must not be BLEND_FACTOR_UNDEFINED");
+ if (RTDesc.DestBlend == BLEND_FACTOR_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].DestBlend must not be BLEND_FACTOR_UNDEFINED");
+ if (RTDesc.BlendOp == BLEND_OPERATION_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].BlendOp must not be BLEND_OPERATION_UNDEFINED");
+
+ if (RTDesc.SrcBlendAlpha == BLEND_FACTOR_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].SrcBlendAlpha must not be BLEND_FACTOR_UNDEFINED");
+ if (RTDesc.DestBlendAlpha == BLEND_FACTOR_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].DestBlendAlpha must not be BLEND_FACTOR_UNDEFINED");
+ if (RTDesc.BlendOpAlpha == BLEND_OPERATION_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].BlendOpAlpha must not be BLEND_OPERATION_UNDEFINED");
+ }
+ }
+}
+
+void CorrectBlendStateDesc(GraphicsPipelineDesc& GraphicsPipeline) noexcept
+{
+ auto& BlendDesc = GraphicsPipeline.BlendDesc;
+ for (Uint32 rt = 0; rt < MAX_RENDER_TARGETS; ++rt)
+ {
+ auto& RTDesc = BlendDesc.RenderTargets[rt];
+ // clang-format off
+ const auto BlendEnable = RTDesc.BlendEnable && (rt == 0 || (BlendDesc.IndependentBlendEnable && rt > 0));
+ const auto LogicOpEnable = RTDesc.LogicOperationEnable && (rt == 0 || (BlendDesc.IndependentBlendEnable && rt > 0));
+ // clang-format on
+ if (!BlendEnable)
+ {
+ if (RTDesc.SrcBlend == BLEND_FACTOR_UNDEFINED)
+ RTDesc.SrcBlend = RenderTargetBlendDesc{}.SrcBlend;
+ if (RTDesc.DestBlend == BLEND_FACTOR_UNDEFINED)
+ RTDesc.DestBlend = RenderTargetBlendDesc{}.DestBlend;
+ if (RTDesc.BlendOp == BLEND_OPERATION_UNDEFINED)
+ RTDesc.BlendOp = RenderTargetBlendDesc{}.BlendOp;
+
+ if (RTDesc.SrcBlendAlpha == BLEND_FACTOR_UNDEFINED)
+ RTDesc.SrcBlendAlpha = RenderTargetBlendDesc{}.SrcBlendAlpha;
+ if (RTDesc.DestBlendAlpha == BLEND_FACTOR_UNDEFINED)
+ RTDesc.DestBlendAlpha = RenderTargetBlendDesc{}.DestBlendAlpha;
+ if (RTDesc.BlendOpAlpha == BLEND_OPERATION_UNDEFINED)
+ RTDesc.BlendOpAlpha = RenderTargetBlendDesc{}.BlendOpAlpha;
+ }
+
+ if (!LogicOpEnable)
+ RTDesc.LogicOp = RenderTargetBlendDesc{}.LogicOp;
+ }
+}
+
+} // namespace
+
+#define VALIDATE_SHADER_TYPE(Shader, ExpectedType, ShaderName) \
+ if (Shader != nullptr && Shader->GetDesc().ShaderType != ExpectedType) \
+ { \
+ LOG_ERROR_AND_THROW(GetShaderTypeLiteralName(Shader->GetDesc().ShaderType), " is not a valid type for ", ShaderName, " shader"); \
+ }
+
+void ValidateGraphicsPipelineCreateInfo(const GraphicsPipelineStateCreateInfo& CreateInfo) noexcept(false)
+{
+ const auto& PSODesc = CreateInfo.PSODesc;
+ if (PSODesc.PipelineType != PIPELINE_TYPE_GRAPHICS && PSODesc.PipelineType != PIPELINE_TYPE_MESH)
+ LOG_PSO_ERROR_AND_THROW("Pipeline type must be GRAPHICS or MESH");
+
+ const auto& GraphicsPipeline = CreateInfo.GraphicsPipeline;
+
+ ValidateBlendStateDesc(PSODesc, GraphicsPipeline);
+ ValidateRasterizerStateDesc(PSODesc, GraphicsPipeline);
+ ValidateDepthStencilDesc(PSODesc, GraphicsPipeline);
+
+
+ if (PSODesc.PipelineType == PIPELINE_TYPE_GRAPHICS)
+ {
+ if (CreateInfo.pVS == nullptr)
+ LOG_ERROR_AND_THROW("Vertex shader must not be null");
+
+ DEV_CHECK_ERR(CreateInfo.pAS == nullptr && CreateInfo.pMS == nullptr, "Mesh shaders are not supported in graphics pipeline");
+ }
+ else if (PSODesc.PipelineType == PIPELINE_TYPE_MESH)
+ {
+ if (CreateInfo.pMS == nullptr)
+ LOG_ERROR_AND_THROW("Mesh shader must not be null");
+
+ DEV_CHECK_ERR(CreateInfo.pVS == nullptr && CreateInfo.pGS == nullptr && CreateInfo.pDS == nullptr && CreateInfo.pHS == nullptr,
+ "Vertex, geometry and tessellation shaders are not supported in a mesh pipeline");
+ DEV_CHECK_ERR(GraphicsPipeline.InputLayout.NumElements == 0, "Input layout is ignored in a mesh pipeline");
+ DEV_CHECK_ERR(GraphicsPipeline.PrimitiveTopology == PRIMITIVE_TOPOLOGY_TRIANGLE_LIST ||
+ GraphicsPipeline.PrimitiveTopology == PRIMITIVE_TOPOLOGY_UNDEFINED,
+ "Primitive topology is ignored in a mesh pipeline, set it to undefined or keep default value (triangle list)");
+ }
+
+
+ VALIDATE_SHADER_TYPE(CreateInfo.pVS, SHADER_TYPE_VERTEX, "vertex")
+ VALIDATE_SHADER_TYPE(CreateInfo.pPS, SHADER_TYPE_PIXEL, "pixel")
+ VALIDATE_SHADER_TYPE(CreateInfo.pGS, SHADER_TYPE_GEOMETRY, "geometry")
+ VALIDATE_SHADER_TYPE(CreateInfo.pHS, SHADER_TYPE_HULL, "hull")
+ VALIDATE_SHADER_TYPE(CreateInfo.pDS, SHADER_TYPE_DOMAIN, "domain")
+ VALIDATE_SHADER_TYPE(CreateInfo.pAS, SHADER_TYPE_AMPLIFICATION, "amplification")
+ VALIDATE_SHADER_TYPE(CreateInfo.pMS, SHADER_TYPE_MESH, "mesh")
+
+
+ if (GraphicsPipeline.pRenderPass != nullptr)
+ {
+ if (GraphicsPipeline.NumRenderTargets != 0)
+ LOG_PSO_ERROR_AND_THROW("NumRenderTargets must be 0 when explicit render pass is used");
+ if (GraphicsPipeline.DSVFormat != TEX_FORMAT_UNKNOWN)
+ LOG_PSO_ERROR_AND_THROW("DSVFormat must be TEX_FORMAT_UNKNOWN when explicit render pass is used");
+
+ for (Uint32 rt = 0; rt < MAX_RENDER_TARGETS; ++rt)
+ {
+ if (GraphicsPipeline.RTVFormats[rt] != TEX_FORMAT_UNKNOWN)
+ LOG_PSO_ERROR_AND_THROW("RTVFormats[", rt, "] must be TEX_FORMAT_UNKNOWN when explicit render pass is used");
+ }
+
+ const auto& RPDesc = GraphicsPipeline.pRenderPass->GetDesc();
+ if (GraphicsPipeline.SubpassIndex >= RPDesc.SubpassCount)
+ LOG_PSO_ERROR_AND_THROW("Subpass index (", Uint32{GraphicsPipeline.SubpassIndex}, ") exceeds the number of subpasses (", Uint32{RPDesc.SubpassCount}, ") in render pass '", RPDesc.Name, "'");
+ }
+ else
+ {
+ for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < _countof(GraphicsPipeline.RTVFormats); ++rt)
+ {
+ auto RTVFmt = GraphicsPipeline.RTVFormats[rt];
+ if (RTVFmt != TEX_FORMAT_UNKNOWN)
+ {
+ LOG_ERROR_MESSAGE("Render target format (", GetTextureFormatAttribs(RTVFmt).Name, ") of unused slot ", rt,
+ " must be set to TEX_FORMAT_UNKNOWN");
+ }
+ }
+
+ if (GraphicsPipeline.SubpassIndex != 0)
+ LOG_PSO_ERROR_AND_THROW("Subpass index (", Uint32{GraphicsPipeline.SubpassIndex}, ") must be 0 when explicit render pass is not used");
+ }
+}
+
+void ValidateComputePipelineCreateInfo(const ComputePipelineStateCreateInfo& CreateInfo) noexcept(false)
+{
+ const auto& PSODesc = CreateInfo.PSODesc;
+ if (PSODesc.PipelineType != PIPELINE_TYPE_COMPUTE)
+ LOG_PSO_ERROR_AND_THROW("Pipeline type must be COMPUTE");
+
+ if (CreateInfo.pCS == nullptr)
+ LOG_ERROR_AND_THROW("Compute shader must not be null");
+
+ VALIDATE_SHADER_TYPE(CreateInfo.pCS, SHADER_TYPE_COMPUTE, "compute");
+}
+#undef VALIDATE_SHADER_TYPE
+#undef LOG_PSO_ERROR_AND_THROW
+
+void CorrectGraphicsPipelineDesc(GraphicsPipelineDesc& GraphicsPipeline) noexcept
+{
+ CorrectBlendStateDesc(GraphicsPipeline);
+ CorrectDepthStencilDesc(GraphicsPipeline);
+}
+
+} // namespace Diligent