#include #include #include #include #include #include #include #include #include using namespace XCEngine::Resources; using namespace XCEngine::Containers; namespace { TEST(ShaderLoader, GetResourceType) { ShaderLoader loader; EXPECT_EQ(loader.GetResourceType(), ResourceType::Shader); } TEST(ShaderLoader, GetSupportedExtensions) { ShaderLoader loader; auto extensions = loader.GetSupportedExtensions(); EXPECT_GE(extensions.Size(), 1u); } TEST(ShaderLoader, CanLoad) { ShaderLoader loader; EXPECT_TRUE(loader.CanLoad("test.vert")); EXPECT_TRUE(loader.CanLoad("test.frag")); EXPECT_TRUE(loader.CanLoad("test.glsl")); EXPECT_TRUE(loader.CanLoad("test.hlsl")); EXPECT_TRUE(loader.CanLoad(GetBuiltinForwardLitShaderPath())); EXPECT_TRUE(loader.CanLoad(GetBuiltinObjectIdShaderPath())); EXPECT_TRUE(loader.CanLoad(GetBuiltinObjectIdOutlineShaderPath())); EXPECT_TRUE(loader.CanLoad(GetBuiltinInfiniteGridShaderPath())); EXPECT_FALSE(loader.CanLoad("test.txt")); EXPECT_FALSE(loader.CanLoad("test.png")); } TEST(ShaderLoader, LoadInvalidPath) { ShaderLoader loader; LoadResult result = loader.Load("invalid/path/shader.glsl"); EXPECT_FALSE(result); } TEST(ShaderLoader, LoadLegacySingleStageShaderBuildsDefaultPassVariant) { namespace fs = std::filesystem; const fs::path shaderPath = fs::temp_directory_path() / "xc_shader_loader_stage.vert"; { std::ofstream shaderFile(shaderPath); ASSERT_TRUE(shaderFile.is_open()); shaderFile << "#version 430\nvoid main() {}"; } ShaderLoader loader; LoadResult result = loader.Load(shaderPath.string().c_str()); ASSERT_TRUE(result); ASSERT_NE(result.resource, nullptr); Shader* shader = static_cast(result.resource); ASSERT_NE(shader, nullptr); EXPECT_EQ(shader->GetShaderType(), ShaderType::Vertex); 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].backend, ShaderBackend::Generic); EXPECT_EQ(pass->variants[0].sourceCode, shader->GetSourceCode()); delete shader; std::remove(shaderPath.string().c_str()); } TEST(ShaderLoader, LoadBuiltinForwardLitShaderBuildsBackendVariants) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinForwardLitShaderPath()); ASSERT_TRUE(result); ASSERT_NE(result.resource, nullptr); Shader* shader = static_cast(result.resource); ASSERT_NE(shader, nullptr); ASSERT_TRUE(shader->IsValid()); const ShaderPass* pass = shader->FindPass("ForwardLit"); ASSERT_NE(pass, nullptr); ASSERT_EQ(pass->variants.Size(), 6u); ASSERT_EQ(pass->tags.Size(), 1u); EXPECT_EQ(pass->tags[0].name, "LightMode"); EXPECT_EQ(pass->tags[0].value, "ForwardBase"); EXPECT_NE(shader->FindVariant("ForwardLit", ShaderType::Vertex, ShaderBackend::D3D12), nullptr); EXPECT_NE(shader->FindVariant("ForwardLit", ShaderType::Fragment, ShaderBackend::D3D12), nullptr); EXPECT_NE(shader->FindVariant("ForwardLit", ShaderType::Vertex, ShaderBackend::OpenGL), nullptr); EXPECT_NE(shader->FindVariant("ForwardLit", ShaderType::Fragment, ShaderBackend::OpenGL), nullptr); EXPECT_NE(shader->FindVariant("ForwardLit", ShaderType::Vertex, ShaderBackend::Vulkan), nullptr); EXPECT_NE(shader->FindVariant("ForwardLit", ShaderType::Fragment, ShaderBackend::Vulkan), nullptr); delete shader; } TEST(ShaderLoader, LoadBuiltinObjectIdShaderBuildsBackendVariants) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinObjectIdShaderPath()); ASSERT_TRUE(result); ASSERT_NE(result.resource, nullptr); Shader* shader = static_cast(result.resource); ASSERT_NE(shader, nullptr); ASSERT_TRUE(shader->IsValid()); const ShaderPass* pass = shader->FindPass("ObjectId"); ASSERT_NE(pass, nullptr); ASSERT_EQ(pass->variants.Size(), 6u); ASSERT_EQ(pass->tags.Size(), 1u); EXPECT_EQ(pass->tags[0].name, "LightMode"); EXPECT_EQ(pass->tags[0].value, "ObjectId"); EXPECT_NE(shader->FindVariant("ObjectId", ShaderType::Vertex, ShaderBackend::D3D12), nullptr); EXPECT_NE(shader->FindVariant("ObjectId", ShaderType::Fragment, ShaderBackend::D3D12), nullptr); EXPECT_NE(shader->FindVariant("ObjectId", ShaderType::Vertex, ShaderBackend::OpenGL), nullptr); EXPECT_NE(shader->FindVariant("ObjectId", ShaderType::Fragment, ShaderBackend::OpenGL), nullptr); EXPECT_NE(shader->FindVariant("ObjectId", ShaderType::Vertex, ShaderBackend::Vulkan), nullptr); EXPECT_NE(shader->FindVariant("ObjectId", ShaderType::Fragment, ShaderBackend::Vulkan), nullptr); delete shader; } TEST(ShaderLoader, LoadBuiltinInfiniteGridShaderBuildsD3D12Variants) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinInfiniteGridShaderPath()); ASSERT_TRUE(result); ASSERT_NE(result.resource, nullptr); Shader* shader = static_cast(result.resource); ASSERT_NE(shader, nullptr); ASSERT_TRUE(shader->IsValid()); const ShaderPass* pass = shader->FindPass("InfiniteGrid"); ASSERT_NE(pass, nullptr); ASSERT_EQ(pass->variants.Size(), 2u); ASSERT_EQ(pass->tags.Size(), 1u); EXPECT_EQ(pass->tags[0].name, "LightMode"); EXPECT_EQ(pass->tags[0].value, "InfiniteGrid"); EXPECT_NE(shader->FindVariant("InfiniteGrid", ShaderType::Vertex, ShaderBackend::D3D12), nullptr); EXPECT_NE(shader->FindVariant("InfiniteGrid", ShaderType::Fragment, ShaderBackend::D3D12), nullptr); EXPECT_EQ(shader->FindVariant("InfiniteGrid", ShaderType::Vertex, ShaderBackend::OpenGL), nullptr); EXPECT_EQ(shader->FindVariant("InfiniteGrid", ShaderType::Fragment, ShaderBackend::OpenGL), nullptr); delete shader; } TEST(ShaderLoader, LoadBuiltinObjectIdOutlineShaderBuildsD3D12Variants) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinObjectIdOutlineShaderPath()); ASSERT_TRUE(result); ASSERT_NE(result.resource, nullptr); Shader* shader = static_cast(result.resource); ASSERT_NE(shader, nullptr); ASSERT_TRUE(shader->IsValid()); const ShaderPass* pass = shader->FindPass("ObjectIdOutline"); ASSERT_NE(pass, nullptr); ASSERT_EQ(pass->variants.Size(), 2u); ASSERT_EQ(pass->tags.Size(), 1u); EXPECT_EQ(pass->tags[0].name, "LightMode"); EXPECT_EQ(pass->tags[0].value, "ObjectIdOutline"); EXPECT_NE(shader->FindVariant("ObjectIdOutline", ShaderType::Vertex, ShaderBackend::D3D12), nullptr); EXPECT_NE(shader->FindVariant("ObjectIdOutline", ShaderType::Fragment, ShaderBackend::D3D12), nullptr); EXPECT_EQ(shader->FindVariant("ObjectIdOutline", ShaderType::Vertex, ShaderBackend::OpenGL), nullptr); EXPECT_EQ(shader->FindVariant("ObjectIdOutline", ShaderType::Fragment, ShaderBackend::OpenGL), nullptr); delete shader; } TEST(ShaderLoader, ResourceManagerLazilyLoadsBuiltinForwardLitShader) { ResourceManager& manager = ResourceManager::Get(); manager.Shutdown(); manager.UnregisterLoader(ResourceType::Shader); ResourceHandle shaderHandle = manager.Load(GetBuiltinForwardLitShaderPath()); ASSERT_TRUE(shaderHandle.IsValid()); ASSERT_NE(shaderHandle->FindPass("ForwardLit"), nullptr); ResourceHandle objectIdShaderHandle = manager.Load(GetBuiltinObjectIdShaderPath()); ASSERT_TRUE(objectIdShaderHandle.IsValid()); ASSERT_NE(objectIdShaderHandle->FindPass("ObjectId"), nullptr); ResourceHandle objectIdOutlineShaderHandle = manager.Load(GetBuiltinObjectIdOutlineShaderPath()); ASSERT_TRUE(objectIdOutlineShaderHandle.IsValid()); ASSERT_NE(objectIdOutlineShaderHandle->FindPass("ObjectIdOutline"), nullptr); ResourceHandle infiniteGridShaderHandle = manager.Load(GetBuiltinInfiniteGridShaderPath()); ASSERT_TRUE(infiniteGridShaderHandle.IsValid()); ASSERT_NE(infiniteGridShaderHandle->FindPass("InfiniteGrid"), nullptr); manager.Shutdown(); } } // namespace