#include "fixtures/RHITestFixture.h" #include "XCEngine/RHI/RHIShader.h" #include #include using namespace XCEngine::RHI; namespace { std::wstring ResolveShaderPath(const wchar_t* relativePath) { wchar_t exePath[MAX_PATH] = {}; const DWORD length = GetModuleFileNameW(nullptr, exePath, MAX_PATH); std::filesystem::path rootPath = length > 0 ? std::filesystem::path(exePath).parent_path() : std::filesystem::current_path(); for (int i = 0; i < 5; ++i) { rootPath = rootPath.parent_path(); } return (rootPath / relativePath).wstring(); } } // namespace TEST_P(RHITestFixture, Shader_Compile_EmptyDesc_ReturnsNullptr) { ShaderCompileDesc desc = {}; RHIShader* shader = GetDevice()->CreateShader(desc); EXPECT_EQ(shader, nullptr); } TEST_P(RHITestFixture, Shader_Compile_ValidVertexShader) { ShaderCompileDesc desc = {}; if (GetBackendType() == RHIType::D3D12) { desc.fileName = ResolveShaderPath(L"tests/RHI/D3D12/integration/quad/Res/Shader/quad.hlsl"); desc.entryPoint = L"MainVS"; desc.profile = L"vs_5_0"; } else { desc.sourceLanguage = ShaderLanguage::GLSL; static const char* vs = "#version 430\nin vec4 aPosition;\nvoid main() { gl_Position = aPosition; }"; desc.source.assign(vs, vs + strlen(vs)); desc.profile = L"vs"; } RHIShader* shader = GetDevice()->CreateShader(desc); if (shader != nullptr) { EXPECT_TRUE(shader->IsValid()); EXPECT_EQ(shader->GetType(), ShaderType::Vertex); EXPECT_NE(shader->GetNativeHandle(), nullptr); shader->Shutdown(); delete shader; } } TEST_P(RHITestFixture, Shader_Compile_ValidFragmentShader) { ShaderCompileDesc desc = {}; if (GetBackendType() == RHIType::D3D12) { desc.fileName = ResolveShaderPath(L"tests/RHI/D3D12/integration/quad/Res/Shader/quad.hlsl"); desc.entryPoint = L"MainPS"; desc.profile = L"ps_5_0"; } else { desc.sourceLanguage = ShaderLanguage::GLSL; static const char* fs = "#version 430\nout vec4 c;\nvoid main() { c = vec4(1,0,0,1); }"; desc.source.assign(fs, fs + strlen(fs)); desc.profile = L"ps"; } RHIShader* shader = GetDevice()->CreateShader(desc); if (shader != nullptr) { EXPECT_TRUE(shader->IsValid()); EXPECT_EQ(shader->GetType(), ShaderType::Fragment); EXPECT_NE(shader->GetNativeHandle(), nullptr); shader->Shutdown(); delete shader; } } TEST_P(RHITestFixture, Shader_GetType_VertexShader) { ShaderCompileDesc desc = {}; if (GetBackendType() == RHIType::D3D12) { desc.fileName = ResolveShaderPath(L"tests/RHI/D3D12/integration/quad/Res/Shader/quad.hlsl"); desc.entryPoint = L"MainVS"; desc.profile = L"vs_5_0"; } else { desc.sourceLanguage = ShaderLanguage::GLSL; static const char* vs = "#version 430\nin vec4 aPosition;\nvoid main() { gl_Position = aPosition; }"; desc.source.assign(vs, vs + strlen(vs)); desc.profile = L"vs"; } RHIShader* shader = GetDevice()->CreateShader(desc); if (shader != nullptr) { EXPECT_EQ(shader->GetType(), ShaderType::Vertex); shader->Shutdown(); delete shader; } } TEST_P(RHITestFixture, Shader_GetType_FragmentShader) { ShaderCompileDesc desc = {}; if (GetBackendType() == RHIType::D3D12) { desc.fileName = ResolveShaderPath(L"tests/RHI/D3D12/integration/quad/Res/Shader/quad.hlsl"); desc.entryPoint = L"MainPS"; desc.profile = L"ps_5_0"; } else { desc.sourceLanguage = ShaderLanguage::GLSL; static const char* fs = "#version 430\nout vec4 c;\nvoid main() { c = vec4(1,0,0,1); }"; desc.source.assign(fs, fs + strlen(fs)); desc.profile = L"ps"; } RHIShader* shader = GetDevice()->CreateShader(desc); if (shader != nullptr) { EXPECT_EQ(shader->GetType(), ShaderType::Fragment); shader->Shutdown(); delete shader; } } TEST_P(RHITestFixture, Shader_GetNativeHandle_ValidShader) { ShaderCompileDesc desc = {}; if (GetBackendType() == RHIType::D3D12) { desc.fileName = ResolveShaderPath(L"tests/RHI/D3D12/integration/quad/Res/Shader/quad.hlsl"); desc.entryPoint = L"MainVS"; desc.profile = L"vs_5_0"; } else { desc.sourceLanguage = ShaderLanguage::GLSL; static const char* vs = "#version 430\nin vec4 aPosition;\nvoid main() { gl_Position = aPosition; }"; desc.source.assign(vs, vs + strlen(vs)); desc.profile = L"vs"; } RHIShader* shader = GetDevice()->CreateShader(desc); if (shader != nullptr) { void* handle = shader->GetNativeHandle(); EXPECT_NE(handle, nullptr); shader->Shutdown(); delete shader; } } TEST_P(RHITestFixture, Shader_Shutdown_Invalidates) { ShaderCompileDesc desc = {}; if (GetBackendType() == RHIType::D3D12) { desc.fileName = ResolveShaderPath(L"tests/RHI/D3D12/integration/quad/Res/Shader/quad.hlsl"); desc.entryPoint = L"MainVS"; desc.profile = L"vs_5_0"; } else { desc.sourceLanguage = ShaderLanguage::GLSL; static const char* vs = "#version 430\nin vec4 aPosition;\nvoid main() { gl_Position = aPosition; }"; desc.source.assign(vs, vs + strlen(vs)); desc.profile = L"vs"; } RHIShader* shader = GetDevice()->CreateShader(desc); if (shader != nullptr) { EXPECT_TRUE(shader->IsValid()); shader->Shutdown(); EXPECT_FALSE(shader->IsValid()); delete shader; } } TEST_P(RHITestFixture, Shader_Compile_FromFile_ReturnsValidShader) { ShaderCompileDesc desc = {}; if (GetBackendType() == RHIType::D3D12) { desc.fileName = ResolveShaderPath(L"tests/RHI/D3D12/integration/quad/Res/Shader/quad.hlsl"); desc.entryPoint = L"MainVS"; desc.profile = L"vs_5_0"; } else if (GetBackendType() == RHIType::Vulkan) { desc.fileName = ResolveShaderPath(L"tests/RHI/integration/triangle/Res/Shader/triangle_vulkan.vert"); desc.entryPoint = L"main"; desc.profile = L"vs"; } else { desc.fileName = ResolveShaderPath(L"tests/RHI/OpenGL/integration/triangle/Res/Shader/triangle.vert"); desc.entryPoint = L"main"; desc.profile = L"vs_4_30"; } RHIShader* shader = GetDevice()->CreateShader(desc); ASSERT_NE(shader, nullptr); EXPECT_TRUE(shader->IsValid()); EXPECT_EQ(shader->GetType(), ShaderType::Vertex); shader->Shutdown(); delete shader; } TEST_P(RHITestFixture, Shader_Compile_MissingFile_ReturnsNullptr) { ShaderCompileDesc desc = {}; if (GetBackendType() == RHIType::D3D12) { desc.fileName = ResolveShaderPath(L"tests/RHI/D3D12/integration/quad/Res/Shader/does_not_exist.hlsl"); desc.entryPoint = L"MainVS"; desc.profile = L"vs_5_0"; } else { desc.fileName = ResolveShaderPath(L"tests/RHI/OpenGL/integration/triangle/Res/Shader/does_not_exist.vert"); desc.entryPoint = L"main"; desc.profile = L"vs_4_30"; } RHIShader* shader = GetDevice()->CreateShader(desc); EXPECT_EQ(shader, nullptr); }