Unified PSO validation semantics across D3D12 and OpenGL backends: - IsValid() returns whether PSO is ready to use - EnsureValid() ensures PSO is valid (compiles if needed) Behavior by backend: - D3D12: IsValid=false after creation, true after EnsureValid() with shaders - OpenGL: IsValid always=true (immediate model) Also added test_pipeline_state.cpp with 10 tests for RHIPipelineState.
172 lines
5.0 KiB
C++
172 lines
5.0 KiB
C++
#include "fixtures/RHITestFixture.h"
|
|
#include "XCEngine/RHI/RHIPipelineState.h"
|
|
#include <cstring>
|
|
|
|
using namespace XCEngine::RHI;
|
|
|
|
TEST_P(RHITestFixture, PipelineState_Create_DefaultDesc) {
|
|
GraphicsPipelineDesc desc = {};
|
|
RHIPipelineState* pso = GetDevice()->CreatePipelineState(desc);
|
|
if (pso != nullptr) {
|
|
if (GetBackendType() == RHIType::D3D12) {
|
|
EXPECT_FALSE(pso->IsValid());
|
|
} else {
|
|
EXPECT_TRUE(pso->IsValid());
|
|
}
|
|
pso->Shutdown();
|
|
delete pso;
|
|
}
|
|
}
|
|
|
|
TEST_P(RHITestFixture, PipelineState_SetGet_RasterizerState) {
|
|
GraphicsPipelineDesc desc = {};
|
|
RHIPipelineState* pso = GetDevice()->CreatePipelineState(desc);
|
|
ASSERT_NE(pso, nullptr);
|
|
|
|
RasterizerDesc rasterizer = {};
|
|
rasterizer.fillMode = 2;
|
|
rasterizer.cullMode = 2;
|
|
rasterizer.depthClipEnable = true;
|
|
pso->SetRasterizerState(rasterizer);
|
|
|
|
const RasterizerDesc& retrieved = pso->GetRasterizerState();
|
|
EXPECT_EQ(retrieved.cullMode, 2u);
|
|
EXPECT_EQ(retrieved.fillMode, 2u);
|
|
|
|
pso->Shutdown();
|
|
delete pso;
|
|
}
|
|
|
|
TEST_P(RHITestFixture, PipelineState_SetGet_BlendState) {
|
|
GraphicsPipelineDesc desc = {};
|
|
RHIPipelineState* pso = GetDevice()->CreatePipelineState(desc);
|
|
ASSERT_NE(pso, nullptr);
|
|
|
|
BlendDesc blend = {};
|
|
blend.blendEnable = true;
|
|
blend.srcBlend = 1;
|
|
blend.dstBlend = 0;
|
|
pso->SetBlendState(blend);
|
|
|
|
const BlendDesc& retrieved = pso->GetBlendState();
|
|
EXPECT_TRUE(retrieved.blendEnable);
|
|
EXPECT_EQ(retrieved.srcBlend, 1u);
|
|
|
|
pso->Shutdown();
|
|
delete pso;
|
|
}
|
|
|
|
TEST_P(RHITestFixture, PipelineState_SetGet_DepthStencilState) {
|
|
GraphicsPipelineDesc desc = {};
|
|
RHIPipelineState* pso = GetDevice()->CreatePipelineState(desc);
|
|
ASSERT_NE(pso, nullptr);
|
|
|
|
DepthStencilStateDesc ds = {};
|
|
ds.depthTestEnable = true;
|
|
ds.depthWriteEnable = true;
|
|
ds.depthFunc = 3;
|
|
pso->SetDepthStencilState(ds);
|
|
|
|
const DepthStencilStateDesc& retrieved = pso->GetDepthStencilState();
|
|
EXPECT_TRUE(retrieved.depthTestEnable);
|
|
EXPECT_TRUE(retrieved.depthWriteEnable);
|
|
EXPECT_EQ(retrieved.depthFunc, 3u);
|
|
|
|
pso->Shutdown();
|
|
delete pso;
|
|
}
|
|
|
|
TEST_P(RHITestFixture, PipelineState_SetGet_InputLayout) {
|
|
GraphicsPipelineDesc desc = {};
|
|
RHIPipelineState* pso = GetDevice()->CreatePipelineState(desc);
|
|
ASSERT_NE(pso, nullptr);
|
|
|
|
InputElementDesc element = {};
|
|
element.semanticName = "POSITION";
|
|
element.semanticIndex = 0;
|
|
element.format = static_cast<uint32_t>(Format::R32G32B32A32_Float);
|
|
element.inputSlot = 0;
|
|
element.alignedByteOffset = 0;
|
|
|
|
InputLayoutDesc layoutDesc = {};
|
|
layoutDesc.elements.push_back(element);
|
|
pso->SetInputLayout(layoutDesc);
|
|
|
|
const InputLayoutDesc& retrieved = pso->GetInputLayout();
|
|
ASSERT_EQ(retrieved.elements.size(), 1u);
|
|
EXPECT_EQ(retrieved.elements[0].semanticName, "POSITION");
|
|
|
|
pso->Shutdown();
|
|
delete pso;
|
|
}
|
|
|
|
TEST_P(RHITestFixture, PipelineState_SetTopology) {
|
|
GraphicsPipelineDesc desc = {};
|
|
RHIPipelineState* pso = GetDevice()->CreatePipelineState(desc);
|
|
ASSERT_NE(pso, nullptr);
|
|
|
|
pso->SetTopology(3);
|
|
|
|
pso->Shutdown();
|
|
delete pso;
|
|
}
|
|
|
|
TEST_P(RHITestFixture, PipelineState_SetRenderTargetFormats) {
|
|
GraphicsPipelineDesc desc = {};
|
|
RHIPipelineState* pso = GetDevice()->CreatePipelineState(desc);
|
|
ASSERT_NE(pso, nullptr);
|
|
|
|
uint32_t formats[] = { static_cast<uint32_t>(Format::R8G8B8A8_UNorm) };
|
|
pso->SetRenderTargetFormats(1, formats, static_cast<uint32_t>(Format::D24_UNorm_S8_UInt));
|
|
|
|
pso->Shutdown();
|
|
delete pso;
|
|
}
|
|
|
|
TEST_P(RHITestFixture, PipelineState_EnsureValid_IsValid) {
|
|
GraphicsPipelineDesc desc = {};
|
|
desc.renderTargetFormats[0] = static_cast<uint32_t>(Format::R8G8B8A8_UNorm);
|
|
desc.depthStencilFormat = static_cast<uint32_t>(Format::D24_UNorm_S8_UInt);
|
|
|
|
RHIPipelineState* pso = GetDevice()->CreatePipelineState(desc);
|
|
ASSERT_NE(pso, nullptr);
|
|
|
|
if (GetBackendType() == RHIType::D3D12) {
|
|
EXPECT_FALSE(pso->IsValid());
|
|
pso->EnsureValid();
|
|
EXPECT_FALSE(pso->IsValid());
|
|
} else {
|
|
EXPECT_TRUE(pso->IsValid());
|
|
pso->EnsureValid();
|
|
EXPECT_TRUE(pso->IsValid());
|
|
}
|
|
|
|
pso->Shutdown();
|
|
delete pso;
|
|
}
|
|
|
|
TEST_P(RHITestFixture, PipelineState_Shutdown_Invalidates) {
|
|
GraphicsPipelineDesc desc = {};
|
|
desc.renderTargetFormats[0] = static_cast<uint32_t>(Format::R8G8B8A8_UNorm);
|
|
desc.depthStencilFormat = static_cast<uint32_t>(Format::D24_UNorm_S8_UInt);
|
|
|
|
RHIPipelineState* pso = GetDevice()->CreatePipelineState(desc);
|
|
ASSERT_NE(pso, nullptr);
|
|
|
|
pso->EnsureValid();
|
|
pso->Shutdown();
|
|
pso->Shutdown();
|
|
delete pso;
|
|
}
|
|
|
|
TEST_P(RHITestFixture, PipelineState_GetType) {
|
|
GraphicsPipelineDesc desc = {};
|
|
RHIPipelineState* pso = GetDevice()->CreatePipelineState(desc);
|
|
ASSERT_NE(pso, nullptr);
|
|
|
|
PipelineType type = pso->GetType();
|
|
EXPECT_EQ(type, PipelineType::Graphics);
|
|
|
|
pso->Shutdown();
|
|
delete pso;
|
|
} |