summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorassiduous <assiduous@diligentgraphics.com>2021-02-26 06:34:36 +0000
committerassiduous <assiduous@diligentgraphics.com>2021-03-19 00:38:11 +0000
commitf6afada5ec4ece09b2056b540dac70ee5be5a332 (patch)
tree17aff3486e51a07e1020d681f7d38d355e2d65be
parentReworked PSO intialization to allow shader resources be combined when defined... (diff)
downloadDiligentCore-f6afada5ec4ece09b2056b540dac70ee5be5a332.tar.gz
DiligentCore-f6afada5ec4ece09b2056b540dac70ee5be5a332.zip
Added PSO creation failure tests
-rw-r--r--Graphics/GraphicsEngine/src/PipelineStateBase.cpp6
-rw-r--r--Tests/DiligentCoreAPITest/CMakeLists.txt2
-rw-r--r--Tests/DiligentCoreAPITest/include/TestingEnvironment.hpp4
-rw-r--r--Tests/DiligentCoreAPITest/src/ObjectCreationFailure/PSOCreationFailureTest.cpp661
-rw-r--r--Tests/DiligentCoreAPITest/src/TestingEnvironment.cpp21
5 files changed, 691 insertions, 3 deletions
diff --git a/Graphics/GraphicsEngine/src/PipelineStateBase.cpp b/Graphics/GraphicsEngine/src/PipelineStateBase.cpp
index 85b7da0a..57fc1ae3 100644
--- a/Graphics/GraphicsEngine/src/PipelineStateBase.cpp
+++ b/Graphics/GraphicsEngine/src/PipelineStateBase.cpp
@@ -268,7 +268,8 @@ void ValidatePipelineResourceLayoutDesc(const PipelineStateDesc& PSODesc) noexce
if ((it->second & Var.ShaderStages) != 0)
{
LOG_PSO_ERROR_AND_THROW("Shader variable '", Var.Name, "' is defined in overlapping shader stages (", GetShaderStagesString(Var.ShaderStages),
- " and ", GetShaderStagesString(it->second), "), which is not allowed.");
+ " and ", GetShaderStagesString(it->second),
+ "). Multiple variables with the same name are allowed, but shader stages they use must not overlap.");
}
}
UniqueVariables.emplace(Var.Name, Var.ShaderStages);
@@ -286,7 +287,8 @@ void ValidatePipelineResourceLayoutDesc(const PipelineStateDesc& PSODesc) noexce
if ((it->second & Sam.ShaderStages) != 0)
{
LOG_PSO_ERROR_AND_THROW("Immutable sampler '", Sam.SamplerOrTextureName, "' is defined in overlapping shader stages (", GetShaderStagesString(Sam.ShaderStages),
- " and ", GetShaderStagesString(it->second), "), which is not allowed.");
+ " and ", GetShaderStagesString(it->second),
+ "). Multiple immutable samplers with the same name are allowed, but shader stages they use must not overlap.");
}
}
UniqueSamplers.emplace(Sam.SamplerOrTextureName, Sam.ShaderStages);
diff --git a/Tests/DiligentCoreAPITest/CMakeLists.txt b/Tests/DiligentCoreAPITest/CMakeLists.txt
index a3d09ecc..135dc660 100644
--- a/Tests/DiligentCoreAPITest/CMakeLists.txt
+++ b/Tests/DiligentCoreAPITest/CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required (VERSION 3.17)
project(DiligentCoreAPITest)
-file(GLOB COMMON_SOURCE LIST_DIRECTORIES false src/*)
+file(GLOB COMMON_SOURCE LIST_DIRECTORIES false src/* src/ObjectCreationFailure/*)
file(GLOB COMMON_INCLUDE LIST_DIRECTORIES false include/*)
file(GLOB INLINE_SHADERS LIST_DIRECTORIES false include/InlineShaders/*)
file(GLOB_RECURSE SHADERS LIST_DIRECTORIES false assets/shaders/*.*)
diff --git a/Tests/DiligentCoreAPITest/include/TestingEnvironment.hpp b/Tests/DiligentCoreAPITest/include/TestingEnvironment.hpp
index 4e66f44b..de04a3b4 100644
--- a/Tests/DiligentCoreAPITest/include/TestingEnvironment.hpp
+++ b/Tests/DiligentCoreAPITest/include/TestingEnvironment.hpp
@@ -117,6 +117,8 @@ public:
return m_NeedWARPResourceArrayIndexingBugWorkaround;
}
+ static void PushExpectedErrorSubstring(const char* Str);
+
protected:
NativeWindow CreateNativeWindow();
@@ -151,6 +153,8 @@ protected:
static std::atomic_int m_NumAllowedErrors;
+ static std::vector<std::string> m_ExpectedErrorSubstrings;
+
// As of Windows version 2004 (build 19041), there is a bug in D3D12 WARP rasterizer:
// Shader resource array indexing always references array element 0 when shaders are compiled.
// A workaround is to use SM5.0 and default shader compiler.
diff --git a/Tests/DiligentCoreAPITest/src/ObjectCreationFailure/PSOCreationFailureTest.cpp b/Tests/DiligentCoreAPITest/src/ObjectCreationFailure/PSOCreationFailureTest.cpp
new file mode 100644
index 00000000..8ee55109
--- /dev/null
+++ b/Tests/DiligentCoreAPITest/src/ObjectCreationFailure/PSOCreationFailureTest.cpp
@@ -0,0 +1,661 @@
+/*
+ * Copyright 2019-2021 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 "TestingEnvironment.hpp"
+#include "GraphicsAccessories.hpp"
+
+#include "gtest/gtest.h"
+
+using namespace Diligent;
+using namespace Diligent::Testing;
+
+namespace
+{
+
+static const char g_TrivialVSSource[] = R"(
+void main(out float4 pos : SV_Position)
+{
+ pos = float4(0.0, 0.0, 0.0, 0.0);
+}
+)";
+
+static const char g_TrivialPSSource[] = R"(
+float4 main() : SV_Target
+{
+ return float4(0.0, 0.0, 0.0, 0.0);
+}
+)";
+
+static const char g_TrivialCSSource[] = R"(
+[numthreads(8,8,1)]
+void main()
+{
+}
+)";
+
+class PSOCreationFailureTest : public ::testing::Test
+{
+protected:
+ static void SetUpTestSuite()
+ {
+ auto* const pEnv = TestingEnvironment::GetInstance();
+ auto* const pDevice = pEnv->GetDevice();
+
+ ShaderCreateInfo Attrs;
+ Attrs.Source = g_TrivialVSSource;
+ Attrs.EntryPoint = "main";
+ Attrs.Desc.ShaderType = SHADER_TYPE_VERTEX;
+ Attrs.Desc.Name = "TrivialVS (PSOCreationFailureTest)";
+ Attrs.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL;
+ Attrs.ShaderCompiler = pEnv->GetDefaultCompiler(Attrs.SourceLanguage);
+ Attrs.UseCombinedTextureSamplers = true;
+ pDevice->CreateShader(Attrs, &sm_pTrivialVS);
+ ASSERT_TRUE(sm_pTrivialVS);
+
+ Attrs.Source = g_TrivialPSSource;
+ Attrs.Desc.ShaderType = SHADER_TYPE_PIXEL;
+ Attrs.Desc.Name = "TrivialPS (PSOCreationFailureTest)";
+ pDevice->CreateShader(Attrs, &sm_pTrivialPS);
+ ASSERT_TRUE(sm_pTrivialPS);
+
+ Attrs.Source = g_TrivialCSSource;
+ Attrs.Desc.ShaderType = SHADER_TYPE_COMPUTE;
+ Attrs.Desc.Name = "TrivialCS (PSOCreationFailureTest)";
+ pDevice->CreateShader(Attrs, &sm_pTrivialCS);
+ ASSERT_TRUE(sm_pTrivialCS);
+
+ sm_DefaultGraphicsPsoCI.PSODesc.Name = "PSOCreationFailureTest - default graphics PSO desc";
+ sm_DefaultGraphicsPsoCI.GraphicsPipeline.NumRenderTargets = 1;
+ sm_DefaultGraphicsPsoCI.GraphicsPipeline.RTVFormats[0] = TEX_FORMAT_RGBA8_UNORM;
+ sm_DefaultGraphicsPsoCI.GraphicsPipeline.DSVFormat = TEX_FORMAT_D32_FLOAT;
+
+ sm_DefaultGraphicsPsoCI.pVS = sm_pTrivialVS;
+ sm_DefaultGraphicsPsoCI.pPS = sm_pTrivialPS;
+
+ {
+ RefCntAutoPtr<IPipelineState> pGraphicsPSO;
+ pDevice->CreateGraphicsPipelineState(GetGraphicsPSOCreateInfo("PSOCreationFailureTest - OK graphics PSO"), &pGraphicsPSO);
+ ASSERT_TRUE(pGraphicsPSO);
+ }
+
+ sm_DefaultComputePsoCI.PSODesc.Name = "PSOCreationFailureTest - default compute PSO desc";
+ sm_DefaultComputePsoCI.pCS = sm_pTrivialCS;
+
+ {
+ RefCntAutoPtr<IPipelineState> pComputePSO;
+ pDevice->CreateComputePipelineState(GetComputePSOCreateInfo("PSOCreationFailureTest - OK compute PSO"), &pComputePSO);
+ ASSERT_TRUE(pComputePSO);
+ }
+
+ RenderPassDesc RPDesc;
+ RPDesc.Name = "PSOCreationFailureTest - render pass";
+ RenderPassAttachmentDesc Attachments[2]{};
+ Attachments[0].Format = TEX_FORMAT_RGBA8_UNORM;
+ Attachments[0].InitialState = RESOURCE_STATE_RENDER_TARGET;
+ Attachments[0].FinalState = RESOURCE_STATE_RENDER_TARGET;
+ Attachments[1].Format = TEX_FORMAT_D32_FLOAT;
+ Attachments[1].InitialState = RESOURCE_STATE_DEPTH_WRITE;
+ Attachments[1].FinalState = RESOURCE_STATE_DEPTH_WRITE;
+ RPDesc.AttachmentCount = _countof(Attachments);
+ RPDesc.pAttachments = Attachments;
+
+ AttachmentReference ColorAttachmentRef{0, RESOURCE_STATE_RENDER_TARGET};
+ AttachmentReference DepthAttachmentRef{1, RESOURCE_STATE_DEPTH_WRITE};
+ SubpassDesc Subpasses[1]{};
+ Subpasses[0].RenderTargetAttachmentCount = 1;
+ Subpasses[0].pRenderTargetAttachments = &ColorAttachmentRef;
+ Subpasses[0].pDepthStencilAttachment = &DepthAttachmentRef;
+
+ RPDesc.SubpassCount = _countof(Subpasses);
+ RPDesc.pSubpasses = Subpasses;
+
+ pDevice->CreateRenderPass(RPDesc, &sm_pRenderPass);
+ ASSERT_TRUE(sm_pRenderPass);
+
+ {
+ RefCntAutoPtr<IPipelineState> pGraphicsPSO;
+ pDevice->CreateGraphicsPipelineState(GetGraphicsPSOCreateInfo("PSOCreationFailureTest - OK PSO with render pass", true), &pGraphicsPSO);
+ ASSERT_TRUE(pGraphicsPSO);
+ }
+
+ {
+ PipelineResourceDesc Resources[] = //
+ {
+ PipelineResourceDesc{SHADER_TYPE_VERTEX | SHADER_TYPE_PIXEL, "g_Texture", 1, SHADER_RESOURCE_TYPE_TEXTURE_SRV, SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE} //
+ };
+ ImmutableSamplerDesc ImmutableSmplers[] //
+ {
+ ImmutableSamplerDesc{SHADER_TYPE_VERTEX | SHADER_TYPE_PIXEL, "g_Texture_sampler", SamplerDesc{}} //
+ };
+
+ PipelineResourceSignatureDesc PRSDesc;
+ PRSDesc.Name = "PRS0";
+ PRSDesc.NumResources = _countof(Resources);
+ PRSDesc.Resources = Resources;
+ PRSDesc.NumImmutableSamplers = _countof(ImmutableSmplers);
+ PRSDesc.ImmutableSamplers = ImmutableSmplers;
+ pDevice->CreatePipelineResourceSignature(PRSDesc, &sm_pSignature0);
+ ASSERT_TRUE(sm_pSignature0);
+ }
+
+ {
+ PipelineResourceDesc Resources[] = //
+ {
+ PipelineResourceDesc{SHADER_TYPE_VERTEX | SHADER_TYPE_PIXEL, "g_Texture2", 1, SHADER_RESOURCE_TYPE_TEXTURE_SRV, SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE} //
+ };
+ PipelineResourceSignatureDesc PRSDesc;
+ PRSDesc.Name = "PRS0A";
+ PRSDesc.NumResources = _countof(Resources);
+ PRSDesc.Resources = Resources;
+ pDevice->CreatePipelineResourceSignature(PRSDesc, &sm_pSignature0A);
+ ASSERT_TRUE(sm_pSignature0A);
+ }
+
+ {
+ PipelineResourceDesc Resources[] = //
+ {
+ PipelineResourceDesc{SHADER_TYPE_VERTEX | SHADER_TYPE_GEOMETRY, "g_Texture", 1, SHADER_RESOURCE_TYPE_TEXTURE_SRV, SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE} //
+ };
+ PipelineResourceSignatureDesc PRSDesc;
+ PRSDesc.Name = "PRS1";
+ PRSDesc.BindingIndex = 1;
+ PRSDesc.NumResources = _countof(Resources);
+ PRSDesc.Resources = Resources;
+ pDevice->CreatePipelineResourceSignature(PRSDesc, &sm_pSignature1);
+ ASSERT_TRUE(sm_pSignature1);
+ }
+
+ {
+ PipelineResourceDesc Resources[] = //
+ {
+ PipelineResourceDesc{SHADER_TYPE_GEOMETRY, "g_Texture", 1, SHADER_RESOURCE_TYPE_TEXTURE_SRV, SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE} //
+ };
+ ImmutableSamplerDesc ImmutableSmplers[] //
+ {
+ ImmutableSamplerDesc{SHADER_TYPE_VERTEX | SHADER_TYPE_GEOMETRY, "g_Texture_sampler", SamplerDesc{}} //
+ };
+
+ PipelineResourceSignatureDesc PRSDesc;
+ PRSDesc.Name = "PRS1A";
+ PRSDesc.BindingIndex = 1;
+ PRSDesc.NumResources = _countof(Resources);
+ PRSDesc.Resources = Resources;
+ PRSDesc.NumImmutableSamplers = _countof(ImmutableSmplers);
+ PRSDesc.ImmutableSamplers = ImmutableSmplers;
+ pDevice->CreatePipelineResourceSignature(PRSDesc, &sm_pSignature1A);
+ ASSERT_TRUE(sm_pSignature1A);
+ }
+ }
+
+ static void TearDownTestSuite()
+ {
+ sm_pTrivialVS.Release();
+ sm_pTrivialPS.Release();
+ sm_pTrivialCS.Release();
+ sm_pRenderPass.Release();
+ sm_pSignature0.Release();
+ sm_pSignature0A.Release();
+ sm_pSignature1.Release();
+ sm_pSignature1A.Release();
+ }
+
+ static GraphicsPipelineStateCreateInfo GetGraphicsPSOCreateInfo(const char* Name, bool UseRenderPass = false)
+ {
+ auto CI{sm_DefaultGraphicsPsoCI};
+ CI.PSODesc.Name = Name;
+ if (UseRenderPass)
+ {
+ CI.GraphicsPipeline.NumRenderTargets = 0;
+ CI.GraphicsPipeline.RTVFormats[0] = TEX_FORMAT_UNKNOWN;
+ CI.GraphicsPipeline.DSVFormat = TEX_FORMAT_UNKNOWN;
+ CI.GraphicsPipeline.pRenderPass = sm_pRenderPass;
+ }
+ return CI;
+ }
+ static ComputePipelineStateCreateInfo GetComputePSOCreateInfo(const char* Name)
+ {
+ auto CI{sm_DefaultComputePsoCI};
+ CI.PSODesc.Name = Name;
+ return CI;
+ }
+ static IShader* GetVS() { return sm_pTrivialVS; }
+ static IShader* GetPS() { return sm_pTrivialPS; }
+
+ static void TestCreatePSOFailure(GraphicsPipelineStateCreateInfo CI, const char* ExpectedErrorSubstring)
+ {
+ auto* const pEnv = TestingEnvironment::GetInstance();
+ auto* const pDevice = pEnv->GetDevice();
+
+ RefCntAutoPtr<IPipelineState> pPSO;
+ pEnv->SetErrorAllowance(2, "Errors below are expected: testing PSO creation failure\n");
+ pEnv->PushExpectedErrorSubstring(ExpectedErrorSubstring);
+ pDevice->CreateGraphicsPipelineState(CI, &pPSO);
+
+ CI.PSODesc.Name = nullptr;
+ pEnv->SetErrorAllowance(2);
+ pEnv->PushExpectedErrorSubstring(ExpectedErrorSubstring);
+ pDevice->CreateGraphicsPipelineState(CI, &pPSO);
+
+ pEnv->SetErrorAllowance(0);
+ ASSERT_FALSE(pPSO);
+ }
+
+ static void TestCreatePSOFailure(ComputePipelineStateCreateInfo CI, const char* ExpectedErrorSubstring)
+ {
+ auto* const pEnv = TestingEnvironment::GetInstance();
+ auto* const pDevice = pEnv->GetDevice();
+
+ RefCntAutoPtr<IPipelineState> pPSO;
+
+ pEnv->SetErrorAllowance(2, "Errors below are expected: testing PSO creation failure\n");
+ pEnv->PushExpectedErrorSubstring(ExpectedErrorSubstring);
+ pDevice->CreateComputePipelineState(CI, &pPSO);
+
+ CI.PSODesc.Name = nullptr;
+ pEnv->SetErrorAllowance(2);
+ pEnv->PushExpectedErrorSubstring(ExpectedErrorSubstring);
+ pDevice->CreateComputePipelineState(CI, &pPSO);
+
+ pEnv->SetErrorAllowance(0);
+ ASSERT_FALSE(pPSO);
+ }
+
+protected:
+ static RefCntAutoPtr<IPipelineResourceSignature> sm_pSignature0;
+ static RefCntAutoPtr<IPipelineResourceSignature> sm_pSignature0A;
+ static RefCntAutoPtr<IPipelineResourceSignature> sm_pSignature1;
+ static RefCntAutoPtr<IPipelineResourceSignature> sm_pSignature1A;
+
+private:
+ static RefCntAutoPtr<IShader> sm_pTrivialVS;
+ static RefCntAutoPtr<IShader> sm_pTrivialPS;
+ static RefCntAutoPtr<IShader> sm_pTrivialCS;
+ static RefCntAutoPtr<IRenderPass> sm_pRenderPass;
+
+ static GraphicsPipelineStateCreateInfo sm_DefaultGraphicsPsoCI;
+ static ComputePipelineStateCreateInfo sm_DefaultComputePsoCI;
+};
+
+RefCntAutoPtr<IShader> PSOCreationFailureTest::sm_pTrivialVS;
+RefCntAutoPtr<IShader> PSOCreationFailureTest::sm_pTrivialPS;
+RefCntAutoPtr<IShader> PSOCreationFailureTest::sm_pTrivialCS;
+RefCntAutoPtr<IRenderPass> PSOCreationFailureTest::sm_pRenderPass;
+RefCntAutoPtr<IPipelineResourceSignature> PSOCreationFailureTest::sm_pSignature0;
+RefCntAutoPtr<IPipelineResourceSignature> PSOCreationFailureTest::sm_pSignature0A;
+RefCntAutoPtr<IPipelineResourceSignature> PSOCreationFailureTest::sm_pSignature1;
+RefCntAutoPtr<IPipelineResourceSignature> PSOCreationFailureTest::sm_pSignature1A;
+
+GraphicsPipelineStateCreateInfo PSOCreationFailureTest::sm_DefaultGraphicsPsoCI;
+ComputePipelineStateCreateInfo PSOCreationFailureTest::sm_DefaultComputePsoCI;
+
+TEST_F(PSOCreationFailureTest, InvalidGraphicsPipelineType)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Invalid Graphics Pipeline Type")};
+ PsoCI.PSODesc.PipelineType = PIPELINE_TYPE_COMPUTE;
+ TestCreatePSOFailure(PsoCI, "Pipeline type must be GRAPHICS or MESH");
+}
+
+TEST_F(PSOCreationFailureTest, NoVS)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - no VS")};
+ PsoCI.pVS = nullptr;
+ TestCreatePSOFailure(PsoCI, "Vertex shader must not be null");
+}
+
+TEST_F(PSOCreationFailureTest, IncorrectVSType)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - incorrect VS Type")};
+ PsoCI.pVS = GetPS();
+ TestCreatePSOFailure(PsoCI, "SHADER_TYPE_PIXEL is not a valid type for vertex shader");
+}
+
+TEST_F(PSOCreationFailureTest, IncorrectPSType)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - incorrect PS Type")};
+ PsoCI.pPS = GetVS();
+ TestCreatePSOFailure(PsoCI, "SHADER_TYPE_VERTEX is not a valid type for pixel shader");
+}
+
+TEST_F(PSOCreationFailureTest, IncorrectGSType)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - incorrect GS Type")};
+ PsoCI.pGS = GetVS();
+ TestCreatePSOFailure(PsoCI, "SHADER_TYPE_VERTEX is not a valid type for geometry shader");
+}
+
+TEST_F(PSOCreationFailureTest, IncorrectDSType)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - incorrect DS Type")};
+ PsoCI.pDS = GetVS();
+ TestCreatePSOFailure(PsoCI, "SHADER_TYPE_VERTEX is not a valid type for domain shader");
+}
+
+TEST_F(PSOCreationFailureTest, IncorrectHSType)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - incorrect HS Type")};
+ PsoCI.pHS = GetVS();
+ TestCreatePSOFailure(PsoCI, "SHADER_TYPE_VERTEX is not a valid type for hull shader");
+}
+
+TEST_F(PSOCreationFailureTest, WrongSubpassIndex)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - wrong subpass index")};
+ PsoCI.GraphicsPipeline.SubpassIndex = 1;
+ TestCreatePSOFailure(PsoCI, "Subpass index (1) must be 0");
+}
+
+TEST_F(PSOCreationFailureTest, UndefinedFillMode)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Undefined Fill Mode")};
+ PsoCI.GraphicsPipeline.RasterizerDesc.FillMode = FILL_MODE_UNDEFINED;
+ TestCreatePSOFailure(PsoCI, "RasterizerDesc.FillMode must not be FILL_MODE_UNDEFINED");
+}
+
+TEST_F(PSOCreationFailureTest, UndefinedCullMode)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Undefined Cull Mode")};
+ PsoCI.GraphicsPipeline.RasterizerDesc.CullMode = CULL_MODE_UNDEFINED;
+ TestCreatePSOFailure(PsoCI, "RasterizerDesc.CullMode must not be CULL_MODE_UNDEFINED");
+}
+
+TEST_F(PSOCreationFailureTest, InvalidDepthFunc)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Invalid Depth Func")};
+ PsoCI.GraphicsPipeline.DepthStencilDesc.DepthFunc = COMPARISON_FUNC_UNKNOWN;
+ TestCreatePSOFailure(PsoCI, "DepthStencilDesc.DepthFunc must not be COMPARISON_FUNC_UNKNOWN");
+}
+
+TEST_F(PSOCreationFailureTest, InvalidFrontStencilFailOp)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Invalid Front Face StencilFailOp")};
+ PsoCI.GraphicsPipeline.DepthStencilDesc.StencilEnable = True;
+ PsoCI.GraphicsPipeline.DepthStencilDesc.FrontFace.StencilFailOp = STENCIL_OP_UNDEFINED;
+ TestCreatePSOFailure(PsoCI, "DepthStencilDesc.FrontFace.StencilFailOp must not be STENCIL_OP_UNDEFINED");
+}
+
+TEST_F(PSOCreationFailureTest, InvalidBackStencilFailOp)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Invalid Back Face StencilFailOp")};
+ PsoCI.GraphicsPipeline.DepthStencilDesc.StencilEnable = True;
+ PsoCI.GraphicsPipeline.DepthStencilDesc.BackFace.StencilFailOp = STENCIL_OP_UNDEFINED;
+ TestCreatePSOFailure(PsoCI, "DepthStencilDesc.BackFace.StencilFailOp must not be STENCIL_OP_UNDEFINED");
+}
+
+TEST_F(PSOCreationFailureTest, InvalidFrontStencilDepthFailOp)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Invalid Front Face StencilDepthFailOp")};
+ PsoCI.GraphicsPipeline.DepthStencilDesc.StencilEnable = True;
+ PsoCI.GraphicsPipeline.DepthStencilDesc.FrontFace.StencilDepthFailOp = STENCIL_OP_UNDEFINED;
+ TestCreatePSOFailure(PsoCI, "DepthStencilDesc.FrontFace.StencilDepthFailOp must not be STENCIL_OP_UNDEFINED");
+}
+
+TEST_F(PSOCreationFailureTest, InvalidBackStencilDepthFailOp)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Invalid Back Face StencilDepthFailOp")};
+ PsoCI.GraphicsPipeline.DepthStencilDesc.StencilEnable = True;
+ PsoCI.GraphicsPipeline.DepthStencilDesc.BackFace.StencilDepthFailOp = STENCIL_OP_UNDEFINED;
+ TestCreatePSOFailure(PsoCI, "DepthStencilDesc.BackFace.StencilDepthFailOp must not be STENCIL_OP_UNDEFINED");
+}
+
+TEST_F(PSOCreationFailureTest, InvalidFrontStencilPassOp)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Invalid Front Face StencilPassOp")};
+ PsoCI.GraphicsPipeline.DepthStencilDesc.StencilEnable = True;
+ PsoCI.GraphicsPipeline.DepthStencilDesc.FrontFace.StencilPassOp = STENCIL_OP_UNDEFINED;
+ TestCreatePSOFailure(PsoCI, "DepthStencilDesc.FrontFace.StencilPassOp must not be STENCIL_OP_UNDEFINED");
+}
+
+TEST_F(PSOCreationFailureTest, InvalidBackStencilPassOp)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Invalid Back Face StencilPassOp")};
+ PsoCI.GraphicsPipeline.DepthStencilDesc.StencilEnable = True;
+ PsoCI.GraphicsPipeline.DepthStencilDesc.BackFace.StencilPassOp = STENCIL_OP_UNDEFINED;
+ TestCreatePSOFailure(PsoCI, "DepthStencilDesc.BackFace.StencilPassOp must not be STENCIL_OP_UNDEFINED");
+}
+
+TEST_F(PSOCreationFailureTest, InvalidFrontStencilFunc)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Invalid Front Face StencilFunc")};
+ PsoCI.GraphicsPipeline.DepthStencilDesc.StencilEnable = True;
+ PsoCI.GraphicsPipeline.DepthStencilDesc.FrontFace.StencilFunc = COMPARISON_FUNC_UNKNOWN;
+ TestCreatePSOFailure(PsoCI, "DepthStencilDesc.FrontFace.StencilFunc must not be COMPARISON_FUNC_UNKNOWN");
+}
+
+TEST_F(PSOCreationFailureTest, InvalidBackStencilFunc)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Invalid Back Face StencilFunc")};
+ PsoCI.GraphicsPipeline.DepthStencilDesc.StencilEnable = True;
+ PsoCI.GraphicsPipeline.DepthStencilDesc.BackFace.StencilFunc = COMPARISON_FUNC_UNKNOWN;
+ TestCreatePSOFailure(PsoCI, "DepthStencilDesc.BackFace.StencilFunc must not be COMPARISON_FUNC_UNKNOWN");
+}
+
+TEST_F(PSOCreationFailureTest, InvalidSrcBlend)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Invalid SrcBlend")};
+ PsoCI.GraphicsPipeline.BlendDesc.RenderTargets[0].BlendEnable = True;
+ PsoCI.GraphicsPipeline.BlendDesc.RenderTargets[0].SrcBlend = BLEND_FACTOR_UNDEFINED;
+ TestCreatePSOFailure(PsoCI, "BlendDesc.RenderTargets[0].SrcBlend must not be BLEND_FACTOR_UNDEFINED");
+}
+
+TEST_F(PSOCreationFailureTest, InvalidDestBlend)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Invalid DestBlend")};
+ PsoCI.GraphicsPipeline.BlendDesc.RenderTargets[0].BlendEnable = True;
+ PsoCI.GraphicsPipeline.BlendDesc.RenderTargets[0].DestBlend = BLEND_FACTOR_UNDEFINED;
+ TestCreatePSOFailure(PsoCI, "BlendDesc.RenderTargets[0].DestBlend must not be BLEND_FACTOR_UNDEFINED");
+}
+
+TEST_F(PSOCreationFailureTest, InvalidBlendOp)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Invalid BlendOp")};
+ PsoCI.GraphicsPipeline.BlendDesc.RenderTargets[0].BlendEnable = True;
+ PsoCI.GraphicsPipeline.BlendDesc.RenderTargets[0].BlendOp = BLEND_OPERATION_UNDEFINED;
+ TestCreatePSOFailure(PsoCI, "BlendDesc.RenderTargets[0].BlendOp must not be BLEND_OPERATION_UNDEFINED");
+}
+
+TEST_F(PSOCreationFailureTest, InvalidSrcBlendAlpha)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Invalid SrcBlendAlpha")};
+ PsoCI.GraphicsPipeline.BlendDesc.RenderTargets[0].BlendEnable = True;
+ PsoCI.GraphicsPipeline.BlendDesc.RenderTargets[0].SrcBlendAlpha = BLEND_FACTOR_UNDEFINED;
+ TestCreatePSOFailure(PsoCI, "BlendDesc.RenderTargets[0].SrcBlendAlpha must not be BLEND_FACTOR_UNDEFINED");
+}
+
+TEST_F(PSOCreationFailureTest, InvalidDestBlendAlpha)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Invalid DestBlendAlpha")};
+ PsoCI.GraphicsPipeline.BlendDesc.RenderTargets[0].BlendEnable = True;
+ PsoCI.GraphicsPipeline.BlendDesc.RenderTargets[0].DestBlendAlpha = BLEND_FACTOR_UNDEFINED;
+ TestCreatePSOFailure(PsoCI, "BlendDesc.RenderTargets[0].DestBlendAlpha must not be BLEND_FACTOR_UNDEFINED");
+}
+
+TEST_F(PSOCreationFailureTest, InvalidBlendOpAlpha)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Invalid BlendOpAlpha")};
+ PsoCI.GraphicsPipeline.BlendDesc.RenderTargets[0].BlendEnable = True;
+ PsoCI.GraphicsPipeline.BlendDesc.RenderTargets[0].BlendOpAlpha = BLEND_OPERATION_UNDEFINED;
+ TestCreatePSOFailure(PsoCI, "BlendDesc.RenderTargets[0].BlendOpAlpha must not be BLEND_OPERATION_UNDEFINED");
+}
+
+TEST_F(PSOCreationFailureTest, OverlappingVariableStages)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Overlapping Variable Stages")};
+
+ ShaderResourceVariableDesc Variables[] //
+ {
+ ShaderResourceVariableDesc{SHADER_TYPE_VERTEX | SHADER_TYPE_PIXEL, "g_Texture", SHADER_RESOURCE_VARIABLE_TYPE_STATIC},
+ ShaderResourceVariableDesc{SHADER_TYPE_VERTEX | SHADER_TYPE_GEOMETRY, "g_Texture", SHADER_RESOURCE_VARIABLE_TYPE_STATIC} //
+ };
+ PsoCI.PSODesc.ResourceLayout.Variables = Variables;
+ PsoCI.PSODesc.ResourceLayout.NumVariables = _countof(Variables);
+ TestCreatePSOFailure(PsoCI, "'g_Texture' is defined in overlapping shader stages (SHADER_TYPE_VERTEX, SHADER_TYPE_GEOMETRY and SHADER_TYPE_VERTEX, SHADER_TYPE_PIXEL)");
+}
+
+TEST_F(PSOCreationFailureTest, OverlappingImmutableSamplerStages)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Overlapping Immutable Sampler Stages")};
+
+ ImmutableSamplerDesc ImtblSamplers[] //
+ {
+ ImmutableSamplerDesc{SHADER_TYPE_VERTEX | SHADER_TYPE_PIXEL, "g_Texture_sampler", SamplerDesc{}},
+ ImmutableSamplerDesc{SHADER_TYPE_VERTEX | SHADER_TYPE_GEOMETRY, "g_Texture_sampler", SamplerDesc{}} //
+ };
+ PsoCI.PSODesc.ResourceLayout.ImmutableSamplers = ImtblSamplers;
+ PsoCI.PSODesc.ResourceLayout.NumImmutableSamplers = _countof(ImtblSamplers);
+ TestCreatePSOFailure(PsoCI, "'g_Texture_sampler' is defined in overlapping shader stages (SHADER_TYPE_VERTEX, SHADER_TYPE_GEOMETRY and SHADER_TYPE_VERTEX, SHADER_TYPE_PIXEL)");
+}
+
+TEST_F(PSOCreationFailureTest, RenderPassWithNonZeroNumRenderTargets)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Render Pass With non-zero NumRenderTargets", true)};
+ PsoCI.GraphicsPipeline.NumRenderTargets = 1;
+ TestCreatePSOFailure(PsoCI, "NumRenderTargets must be 0");
+}
+
+TEST_F(PSOCreationFailureTest, RenderPassWithDSVFormat)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Render Pass With defined DSV format", true)};
+ PsoCI.GraphicsPipeline.DSVFormat = TEX_FORMAT_D32_FLOAT;
+ TestCreatePSOFailure(PsoCI, "DSVFormat must be TEX_FORMAT_UNKNOWN");
+}
+
+TEST_F(PSOCreationFailureTest, RenderPassWithRTVFormat)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Render Pass With defined RTV format", true)};
+ PsoCI.GraphicsPipeline.RTVFormats[1] = TEX_FORMAT_RGBA8_UNORM;
+ TestCreatePSOFailure(PsoCI, "RTVFormats[1] must be TEX_FORMAT_UNKNOWN");
+}
+
+TEST_F(PSOCreationFailureTest, RenderPassWithInvalidSubpassIndex)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Render Pass With invalid Subpass index", true)};
+ PsoCI.GraphicsPipeline.SubpassIndex = 2;
+ TestCreatePSOFailure(PsoCI, "Subpass index (2) exceeds the number of subpasses (1)");
+}
+
+TEST_F(PSOCreationFailureTest, NullResourceSignatures)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Null Resource Signatures", true)};
+ PsoCI.ResourceSignaturesCount = 2;
+ TestCreatePSOFailure(PsoCI, "ppResourceSignatures is null, but ResourceSignaturesCount (2) is not zero");
+}
+
+TEST_F(PSOCreationFailureTest, ZeroResourceSignaturesCount)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Zero Resource Signatures Count", true)};
+
+ IPipelineResourceSignature* pSignatures[] = {sm_pSignature0};
+ PsoCI.ppResourceSignatures = pSignatures;
+ PsoCI.ResourceSignaturesCount = 0;
+ TestCreatePSOFailure(PsoCI, "ppResourceSignatures is not null, but ResourceSignaturesCount is zero.");
+}
+
+
+TEST_F(PSOCreationFailureTest, SignatureWithNonZeroNumVariables)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Resource Signature With non-zero NumVariables", true)};
+
+ IPipelineResourceSignature* pSignatures[] = {sm_pSignature0};
+ PsoCI.ppResourceSignatures = pSignatures;
+ PsoCI.ResourceSignaturesCount = _countof(pSignatures);
+ PsoCI.PSODesc.ResourceLayout.NumVariables = 3;
+ TestCreatePSOFailure(PsoCI, "The number of variables defined through resource layout (3) must be zero");
+}
+
+TEST_F(PSOCreationFailureTest, SignatureWithNonZeroNumImmutableSamplers)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Resource Signature With non-zero NumImmutableSamplers", true)};
+
+ IPipelineResourceSignature* pSignatures[] = {sm_pSignature0};
+ PsoCI.ppResourceSignatures = pSignatures;
+ PsoCI.ResourceSignaturesCount = _countof(pSignatures);
+ PsoCI.PSODesc.ResourceLayout.NumImmutableSamplers = 4;
+ TestCreatePSOFailure(PsoCI, "The number of immutable samplers defined through resource layout (4) must be zero");
+}
+
+TEST_F(PSOCreationFailureTest, NullSignature)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Null Signature", true)};
+
+ IPipelineResourceSignature* pSignatures[] = {sm_pSignature0, nullptr};
+ PsoCI.ppResourceSignatures = pSignatures;
+ PsoCI.ResourceSignaturesCount = _countof(pSignatures);
+ TestCreatePSOFailure(PsoCI, "signature at index 1 is null");
+}
+
+TEST_F(PSOCreationFailureTest, ConflictingSignatureBindIndex)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - Conflicting Signature Bind Index", true)};
+
+ IPipelineResourceSignature* pSignatures[] = {sm_pSignature0, sm_pSignature0A};
+ PsoCI.ppResourceSignatures = pSignatures;
+ PsoCI.ResourceSignaturesCount = _countof(pSignatures);
+ TestCreatePSOFailure(PsoCI, "'PRS0A' at binding index 0 conflicts with another resource signature 'PRS0'");
+}
+
+TEST_F(PSOCreationFailureTest, ConflictingSignatureResourceStages)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - conflicting signature resource stages", true)};
+
+ IPipelineResourceSignature* pSignatures[] = {sm_pSignature0, sm_pSignature1};
+ PsoCI.ppResourceSignatures = pSignatures;
+ PsoCI.ResourceSignaturesCount = _countof(pSignatures);
+ TestCreatePSOFailure(PsoCI, "Shader resource 'g_Texture' is found in more than one resource signature ('PRS1' and 'PRS0')");
+}
+
+TEST_F(PSOCreationFailureTest, ConflictingImmutableSamplerStages)
+{
+ auto PsoCI{GetGraphicsPSOCreateInfo("PSO Create Failure - conflicting signature immutable sampler stages", true)};
+
+ IPipelineResourceSignature* pSignatures[] = {sm_pSignature0, sm_pSignature1A};
+ PsoCI.ppResourceSignatures = pSignatures;
+ PsoCI.ResourceSignaturesCount = _countof(pSignatures);
+ TestCreatePSOFailure(PsoCI, "Immutable sampler 'g_Texture_sampler' is found in more than one resource signature ('PRS1A' and 'PRS0')");
+}
+
+TEST_F(PSOCreationFailureTest, InvalidComputePipelineType)
+{
+ auto PsoCI{GetComputePSOCreateInfo("PSO Create Failure - Invalid Compute Pipeline Type")};
+ PsoCI.PSODesc.PipelineType = PIPELINE_TYPE_GRAPHICS;
+ TestCreatePSOFailure(PsoCI, "Pipeline type must be COMPUTE");
+}
+
+TEST_F(PSOCreationFailureTest, NoCS)
+{
+ auto PsoCI{GetComputePSOCreateInfo("PSO Create Failure - no CS")};
+ PsoCI.pCS = nullptr;
+ TestCreatePSOFailure(PsoCI, "Compute shader must not be null");
+}
+
+TEST_F(PSOCreationFailureTest, InvalidCS)
+{
+ auto PsoCI{GetComputePSOCreateInfo("PSO Create Failure - invalid CS")};
+ PsoCI.pCS = GetPS();
+ TestCreatePSOFailure(PsoCI, "SHADER_TYPE_PIXEL is not a valid type for compute shader");
+}
+
+} // namespace
diff --git a/Tests/DiligentCoreAPITest/src/TestingEnvironment.cpp b/Tests/DiligentCoreAPITest/src/TestingEnvironment.cpp
index 796bf580..9cdfa4d9 100644
--- a/Tests/DiligentCoreAPITest/src/TestingEnvironment.cpp
+++ b/Tests/DiligentCoreAPITest/src/TestingEnvironment.cpp
@@ -58,6 +58,8 @@ namespace Testing
TestingEnvironment* TestingEnvironment::m_pTheEnvironment = nullptr;
std::atomic_int TestingEnvironment::m_NumAllowedErrors;
+std::vector<std::string> TestingEnvironment::m_ExpectedErrorSubstrings;
+
void TestingEnvironment::MessageCallback(DEBUG_MESSAGE_SEVERITY Severity,
const Char* Message,
const char* Function,
@@ -73,6 +75,15 @@ void TestingEnvironment::MessageCallback(DEBUG_MESSAGE_SEVERITY Severity,
else
{
m_NumAllowedErrors--;
+ if (!m_ExpectedErrorSubstrings.empty())
+ {
+ const auto& ErrorSubstring = m_ExpectedErrorSubstrings.back();
+ if (strstr(Message, ErrorSubstring.c_str()) == nullptr)
+ {
+ ADD_FAILURE() << "Expected error substring '" << ErrorSubstring << "' was not found in the error message";
+ }
+ m_ExpectedErrorSubstrings.pop_back();
+ }
}
}
@@ -86,6 +97,16 @@ void TestingEnvironment::SetErrorAllowance(int NumErrorsToAllow, const char* Inf
{
std::cout << InfoMessage;
}
+ if (m_NumAllowedErrors == 0)
+ {
+ m_ExpectedErrorSubstrings.clear();
+ }
+}
+
+void TestingEnvironment::PushExpectedErrorSubstring(const char* Str)
+{
+ VERIFY_EXPR(Str != nullptr && Str[0] != '\0');
+ m_ExpectedErrorSubstrings.push_back(Str);
}
Uint32 TestingEnvironment::FindAdapater(const std::vector<GraphicsAdapterInfo>& Adapters,