diff --git a/tests/RHI/integration/backpack/CMakeLists.txt b/tests/RHI/integration/backpack/CMakeLists.txt index ccc9dacf..237a19e1 100644 --- a/tests/RHI/integration/backpack/CMakeLists.txt +++ b/tests/RHI/integration/backpack/CMakeLists.txt @@ -9,6 +9,8 @@ set(PACKAGE_DIR ${CMAKE_SOURCE_DIR}/tests/opengl/package) get_filename_component(PROJECT_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../.. ABSOLUTE) +find_package(Vulkan QUIET) + add_executable(rhi_integration_backpack main.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../fixtures/RHIIntegrationFixture.cpp @@ -33,6 +35,60 @@ target_link_libraries(rhi_integration_backpack PRIVATE GTest::gtest ) +if(Vulkan_FOUND) + set(XCENGINE_GLSLANG_VALIDATOR_HINT "$ENV{VULKAN_SDK}") + find_program( + XCENGINE_GLSLANG_VALIDATOR + NAMES glslangValidator glslangValidator.exe + HINTS + "${XCENGINE_GLSLANG_VALIDATOR_HINT}/Bin" + "${Vulkan_ROOT}/Bin") + + if(NOT XCENGINE_GLSLANG_VALIDATOR) + file(GLOB XCENGINE_VULKAN_BIN_DIRS "D:/VulkanSDK/*/Bin") + if(XCENGINE_VULKAN_BIN_DIRS) + list(SORT XCENGINE_VULKAN_BIN_DIRS COMPARE NATURAL ORDER DESCENDING) + foreach(XCENGINE_VULKAN_BIN_DIR IN LISTS XCENGINE_VULKAN_BIN_DIRS) + find_program( + XCENGINE_GLSLANG_VALIDATOR + NAMES glslangValidator glslangValidator.exe + PATHS "${XCENGINE_VULKAN_BIN_DIR}" + NO_DEFAULT_PATH) + if(XCENGINE_GLSLANG_VALIDATOR) + break() + endif() + endforeach() + endif() + endif() + + if(NOT XCENGINE_GLSLANG_VALIDATOR) + message(FATAL_ERROR "glslangValidator not found for Vulkan backpack shaders") + endif() + + set(BACKPACK_VULKAN_VERTEX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/Res/Shader/backpack_vulkan.vert) + set(BACKPACK_VULKAN_FRAGMENT_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/Res/Shader/backpack_vulkan.frag) + + add_custom_command(TARGET rhi_integration_backpack PRE_BUILD + COMMAND ${XCENGINE_GLSLANG_VALIDATOR} + -V + -S + vert + -o + $/backpack_vulkan.vert.spv + ${BACKPACK_VULKAN_VERTEX_SOURCE} + COMMAND ${XCENGINE_GLSLANG_VALIDATOR} + -V + -S + frag + -o + $/backpack_vulkan.frag.spv + ${BACKPACK_VULKAN_FRAGMENT_SOURCE} + VERBATIM) + + target_link_libraries(rhi_integration_backpack PRIVATE Vulkan::Vulkan) + target_compile_definitions(rhi_integration_backpack PRIVATE XCENGINE_SUPPORT_VULKAN) +endif() + target_compile_definitions(rhi_integration_backpack PRIVATE UNICODE _UNICODE diff --git a/tests/RHI/integration/backpack/Res/Shader/backpack_vulkan.frag b/tests/RHI/integration/backpack/Res/Shader/backpack_vulkan.frag new file mode 100644 index 00000000..300c8655 --- /dev/null +++ b/tests/RHI/integration/backpack/Res/Shader/backpack_vulkan.frag @@ -0,0 +1,17 @@ +#version 450 + +layout(set = 1, binding = 0) uniform texture2D uBaseColorTexture; +layout(set = 1, binding = 1) uniform texture2D uSpecularTexture; +layout(set = 2, binding = 0) uniform sampler uBaseColorSampler; +layout(set = 2, binding = 1) uniform sampler uSpecularSampler; + +layout(location = 0) in vec3 vWorldPosition; +layout(location = 1) in vec3 vWorldNormal; +layout(location = 2) in vec2 vTexCoord; + +layout(location = 0) out vec4 fragColor; + +void main() { + vec3 baseColor = texture(sampler2D(uBaseColorTexture, uBaseColorSampler), vTexCoord).rgb; + fragColor = vec4(baseColor, 1.0); +} diff --git a/tests/RHI/integration/backpack/Res/Shader/backpack_vulkan.vert b/tests/RHI/integration/backpack/Res/Shader/backpack_vulkan.vert new file mode 100644 index 00000000..5c5027ee --- /dev/null +++ b/tests/RHI/integration/backpack/Res/Shader/backpack_vulkan.vert @@ -0,0 +1,28 @@ +#version 450 + +layout(location = 0) in vec4 aPosition; +layout(location = 1) in vec4 aNormal; +layout(location = 2) in vec2 aTexCoord; + +layout(set = 0, binding = 0, std140) uniform SceneData { + mat4 gProjectionMatrix; + mat4 gViewMatrix; + mat4 gModelMatrix; + vec4 gCameraPosition; + vec4 gLightDirection; + vec4 gLightColor; + vec4 gAmbientColor; +}; + +layout(location = 0) out vec3 vWorldPosition; +layout(location = 1) out vec3 vWorldNormal; +layout(location = 2) out vec2 vTexCoord; + +void main() { + vec4 worldPosition = gModelMatrix * aPosition; + vec4 viewPosition = gViewMatrix * worldPosition; + gl_Position = gProjectionMatrix * viewPosition; + vWorldPosition = worldPosition.xyz; + vWorldNormal = mat3(gModelMatrix) * aNormal.xyz; + vTexCoord = aTexCoord; +} diff --git a/tests/RHI/integration/backpack/main.cpp b/tests/RHI/integration/backpack/main.cpp index 00558306..95bc4d25 100644 --- a/tests/RHI/integration/backpack/main.cpp +++ b/tests/RHI/integration/backpack/main.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -92,8 +93,38 @@ std::filesystem::path ResolveRuntimePath(const char* relativePath) { return GetExecutableDirectory() / relativePath; } +std::vector LoadBinaryFileRelative(const char* filename) { + const std::filesystem::path path = ResolveRuntimePath(filename); + std::ifstream file(path, std::ios::binary | std::ios::ate); + if (!file.is_open()) { + return {}; + } + + const std::streamsize size = file.tellg(); + if (size <= 0) { + return {}; + } + + std::vector bytes(static_cast(size)); + file.seekg(0, std::ios::beg); + if (!file.read(reinterpret_cast(bytes.data()), size)) { + return {}; + } + + return bytes; +} + const char* GetScreenshotFilename(RHIType type) { - return type == RHIType::D3D12 ? "backpack_d3d12.ppm" : "backpack_opengl.ppm"; + switch (type) { + case RHIType::D3D12: + return "backpack_d3d12.ppm"; + case RHIType::OpenGL: + return "backpack_opengl.ppm"; + case RHIType::Vulkan: + return "backpack_vulkan.ppm"; + default: + return "backpack_unknown.ppm"; + } } int GetComparisonThreshold(RHIType type) { @@ -374,7 +405,7 @@ void main() { desc.fragmentShader.sourceLanguage = XCEngine::RHI::ShaderLanguage::HLSL; desc.fragmentShader.entryPoint = L"MainPS"; desc.fragmentShader.profile = L"ps_5_0"; - } else { + } else if (type == RHIType::OpenGL) { desc.vertexShader.source.assign(kBackpackVertexShader, kBackpackVertexShader + strlen(kBackpackVertexShader)); desc.vertexShader.sourceLanguage = XCEngine::RHI::ShaderLanguage::GLSL; @@ -384,6 +415,14 @@ void main() { kBackpackFragmentShader + strlen(kBackpackFragmentShader)); desc.fragmentShader.sourceLanguage = XCEngine::RHI::ShaderLanguage::GLSL; desc.fragmentShader.profile = L"fs_4_30"; + } else if (type == RHIType::Vulkan) { + desc.vertexShader.source = LoadBinaryFileRelative("backpack_vulkan.vert.spv"); + desc.vertexShader.sourceLanguage = XCEngine::RHI::ShaderLanguage::SPIRV; + desc.vertexShader.entryPoint = L"main"; + + desc.fragmentShader.source = LoadBinaryFileRelative("backpack_vulkan.frag.spv"); + desc.fragmentShader.sourceLanguage = XCEngine::RHI::ShaderLanguage::SPIRV; + desc.fragmentShader.entryPoint = L"main"; } return desc; @@ -950,6 +989,9 @@ TEST_P(BackpackTest, RenderBackpack) { INSTANTIATE_TEST_SUITE_P(D3D12, BackpackTest, ::testing::Values(RHIType::D3D12)); INSTANTIATE_TEST_SUITE_P(OpenGL, BackpackTest, ::testing::Values(RHIType::OpenGL)); +#if defined(XCENGINE_SUPPORT_VULKAN) +INSTANTIATE_TEST_SUITE_P(Vulkan, BackpackTest, ::testing::Values(RHIType::Vulkan)); +#endif GTEST_API_ int main(int argc, char** argv) { Logger::Get().Initialize();