#include #include #include #include using namespace XCEngine::Resources; using namespace XCEngine::Containers; namespace { TEST(Shader, DefaultConstructor) { Shader shader; EXPECT_EQ(shader.GetShaderType(), ShaderType::Fragment); EXPECT_EQ(shader.GetShaderLanguage(), ShaderLanguage::GLSL); EXPECT_FALSE(shader.IsValid()); EXPECT_EQ(shader.GetMemorySize(), 0u); } TEST(Shader, GetType) { Shader shader; EXPECT_EQ(shader.GetType(), ResourceType::Shader); } TEST(Shader, SetGetShaderType) { Shader shader; shader.SetShaderType(ShaderType::Vertex); EXPECT_EQ(shader.GetShaderType(), ShaderType::Vertex); shader.SetShaderType(ShaderType::Fragment); EXPECT_EQ(shader.GetShaderType(), ShaderType::Fragment); shader.SetShaderType(ShaderType::Geometry); EXPECT_EQ(shader.GetShaderType(), ShaderType::Geometry); shader.SetShaderType(ShaderType::Compute); EXPECT_EQ(shader.GetShaderType(), ShaderType::Compute); } TEST(Shader, SetGetShaderLanguage) { Shader shader; shader.SetShaderLanguage(ShaderLanguage::GLSL); EXPECT_EQ(shader.GetShaderLanguage(), ShaderLanguage::GLSL); shader.SetShaderLanguage(ShaderLanguage::HLSL); EXPECT_EQ(shader.GetShaderLanguage(), ShaderLanguage::HLSL); shader.SetShaderLanguage(ShaderLanguage::SPIRV); EXPECT_EQ(shader.GetShaderLanguage(), ShaderLanguage::SPIRV); } TEST(Shader, SetGetSourceCode) { Shader shader; const char* source = "#version 330 core\nvoid main() {}"; shader.SetSourceCode(source); EXPECT_EQ(shader.GetSourceCode(), source); } TEST(Shader, SetGetCompiledBinary) { Shader shader; XCEngine::Containers::Array binary = { 0x00, 0x01, 0x02, 0x03 }; shader.SetCompiledBinary(binary); EXPECT_EQ(shader.GetCompiledBinary().Size(), 4u); EXPECT_EQ(shader.GetCompiledBinary()[0], 0x00); EXPECT_EQ(shader.GetCompiledBinary()[3], 0x03); } TEST(Shader, AddGetUniforms) { Shader shader; ShaderUniform uniform1; uniform1.name = "uModelView"; uniform1.location = 0; uniform1.size = 1; uniform1.type = 4; shader.AddUniform(uniform1); const auto& uniforms = shader.GetUniforms(); EXPECT_EQ(uniforms.Size(), 1u); EXPECT_EQ(uniforms[0].name, "uModelView"); } TEST(Shader, AddGetAttributes) { Shader shader; ShaderAttribute attr1; attr1.name = "aPosition"; attr1.location = 0; attr1.size = 1; attr1.type = 3; shader.AddAttribute(attr1); const auto& attributes = shader.GetAttributes(); EXPECT_EQ(attributes.Size(), 1u); EXPECT_EQ(attributes[0].name, "aPosition"); } TEST(Shader, LegacySingleStageStateSyncsIntoDefaultPassVariant) { Shader shader; shader.SetShaderType(ShaderType::Vertex); shader.SetShaderLanguage(ShaderLanguage::HLSL); shader.SetSourceCode("float4 MainVS() : SV_POSITION { return 0; }"); ASSERT_EQ(shader.GetPassCount(), 1u); const ShaderPass* pass = shader.FindPass("Default"); ASSERT_NE(pass, nullptr); ASSERT_EQ(pass->variants.Size(), 1u); EXPECT_EQ(pass->variants[0].stage, ShaderType::Vertex); EXPECT_EQ(pass->variants[0].language, ShaderLanguage::HLSL); EXPECT_EQ(pass->variants[0].backend, ShaderBackend::Generic); EXPECT_EQ(pass->variants[0].sourceCode, "float4 MainVS() : SV_POSITION { return 0; }"); } TEST(Shader, FindsBackendSpecificVariantAndFallsBackToGeneric) { Shader shader; ShaderStageVariant genericFragment = {}; genericFragment.stage = ShaderType::Fragment; genericFragment.language = ShaderLanguage::GLSL; genericFragment.backend = ShaderBackend::Generic; genericFragment.sourceCode = "generic fragment"; shader.AddPassVariant("ForwardLit", genericFragment); ShaderStageVariant d3d12Fragment = {}; d3d12Fragment.stage = ShaderType::Fragment; d3d12Fragment.language = ShaderLanguage::HLSL; d3d12Fragment.backend = ShaderBackend::D3D12; d3d12Fragment.sourceCode = "d3d12 fragment"; shader.AddPassVariant("ForwardLit", d3d12Fragment); const ShaderStageVariant* d3d12Variant = shader.FindVariant("ForwardLit", ShaderType::Fragment, ShaderBackend::D3D12); ASSERT_NE(d3d12Variant, nullptr); EXPECT_EQ(d3d12Variant->sourceCode, "d3d12 fragment"); const ShaderStageVariant* openglVariant = shader.FindVariant("ForwardLit", ShaderType::Fragment, ShaderBackend::OpenGL); ASSERT_NE(openglVariant, nullptr); EXPECT_EQ(openglVariant->sourceCode, "generic fragment"); } TEST(Shader, StoresPerPassTags) { Shader shader; shader.SetPassTag("ForwardLit", "LightMode", "ForwardBase"); shader.SetPassTag("ForwardLit", "Queue", "Geometry"); const ShaderPass* pass = shader.FindPass("ForwardLit"); ASSERT_NE(pass, nullptr); ASSERT_EQ(pass->tags.Size(), 2u); EXPECT_EQ(pass->tags[0].name, "LightMode"); EXPECT_EQ(pass->tags[0].value, "ForwardBase"); EXPECT_EQ(pass->tags[1].name, "Queue"); EXPECT_EQ(pass->tags[1].value, "Geometry"); } TEST(Shader, StoresShaderPropertiesAndPassResources) { Shader shader; ShaderPropertyDesc baseColor = {}; baseColor.name = "_BaseColor"; baseColor.displayName = "Base Color"; baseColor.type = ShaderPropertyType::Color; baseColor.defaultValue = "(1,1,1,1)"; baseColor.semantic = "BaseColor"; shader.AddProperty(baseColor); ShaderResourceBindingDesc perObject = {}; perObject.name = "PerObjectConstants"; perObject.type = ShaderResourceType::ConstantBuffer; perObject.set = 1; perObject.binding = 0; perObject.semantic = "PerObject"; shader.AddPassResourceBinding("ForwardLit", perObject); ASSERT_EQ(shader.GetProperties().Size(), 1u); const ShaderPropertyDesc* storedProperty = shader.FindProperty("_BaseColor"); ASSERT_NE(storedProperty, nullptr); EXPECT_EQ(storedProperty->displayName, "Base Color"); EXPECT_EQ(storedProperty->type, ShaderPropertyType::Color); EXPECT_EQ(storedProperty->semantic, "BaseColor"); const ShaderResourceBindingDesc* storedBinding = shader.FindPassResourceBinding("ForwardLit", "PerObjectConstants"); ASSERT_NE(storedBinding, nullptr); EXPECT_EQ(storedBinding->type, ShaderResourceType::ConstantBuffer); EXPECT_EQ(storedBinding->set, 1u); EXPECT_EQ(storedBinding->binding, 0u); EXPECT_EQ(storedBinding->semantic, "PerObject"); } TEST(Shader, ReleaseClearsPassRuntimeData) { Shader shader; shader.SetSourceCode("void main() {}"); ShaderPropertyDesc property = {}; property.name = "_BaseColor"; property.type = ShaderPropertyType::Color; shader.AddProperty(property); ShaderStageVariant variant = {}; variant.stage = ShaderType::Fragment; variant.sourceCode = "fragment"; shader.AddPassVariant("ForwardLit", variant); shader.Release(); EXPECT_EQ(shader.GetProperties().Size(), 0u); EXPECT_EQ(shader.GetPassCount(), 0u); EXPECT_EQ(shader.GetSourceCode(), ""); EXPECT_EQ(shader.GetCompiledBinary().Size(), 0u); EXPECT_FALSE(shader.IsValid()); } } // namespace