Add Vulkan quad integration path

This commit is contained in:
2026-03-27 13:52:56 +08:00
parent 4b21b5d3d1
commit 727b6ca249
23 changed files with 1574 additions and 39 deletions

View File

@@ -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_quad
main.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../fixtures/RHIIntegrationFixture.cpp
@@ -33,6 +35,60 @@ target_link_libraries(rhi_integration_quad 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 quad shaders")
endif()
set(QUAD_VULKAN_VERTEX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/Res/Shader/quad_vulkan.vert)
set(QUAD_VULKAN_FRAGMENT_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/Res/Shader/quad_vulkan.frag)
add_custom_command(TARGET rhi_integration_quad PRE_BUILD
COMMAND ${XCENGINE_GLSLANG_VALIDATOR}
-V
-S
vert
-o
$<TARGET_FILE_DIR:rhi_integration_quad>/quad_vulkan.vert.spv
${QUAD_VULKAN_VERTEX_SOURCE}
COMMAND ${XCENGINE_GLSLANG_VALIDATOR}
-V
-S
frag
-o
$<TARGET_FILE_DIR:rhi_integration_quad>/quad_vulkan.frag.spv
${QUAD_VULKAN_FRAGMENT_SOURCE}
VERBATIM)
target_link_libraries(rhi_integration_quad PRIVATE Vulkan::Vulkan)
target_compile_definitions(rhi_integration_quad PRIVATE XCENGINE_SUPPORT_VULKAN)
endif()
target_compile_definitions(rhi_integration_quad PRIVATE
UNICODE
_UNICODE

View File

@@ -0,0 +1,11 @@
#version 450
layout(set = 0, binding = 0) uniform texture2D uTexture;
layout(set = 1, binding = 0) uniform sampler uSampler;
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 fragColor;
void main() {
fragColor = texture(sampler2D(uTexture, uSampler), vTexCoord);
}

View File

@@ -0,0 +1,11 @@
#version 450
layout(location = 0) in vec4 aPosition;
layout(location = 1) in vec2 aTexCoord;
layout(location = 0) out vec2 vTexCoord;
void main() {
gl_Position = aPosition;
vTexCoord = aTexCoord;
}

View File

@@ -1,5 +1,6 @@
#include <windows.h>
#include <filesystem>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -53,6 +54,27 @@ std::filesystem::path ResolveRuntimePath(const char* relativePath) {
return GetExecutableDirectory() / relativePath;
}
std::vector<uint8_t> 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<uint8_t> bytes(static_cast<size_t>(size));
file.seekg(0, std::ios::beg);
if (!file.read(reinterpret_cast<char*>(bytes.data()), size)) {
return {};
}
return bytes;
}
const char kQuadHlsl[] = R"(
Texture2D gTexture : register(t0);
SamplerState gSampler : register(s0);
@@ -104,7 +126,16 @@ void main() {
)";
const char* GetScreenshotFilename(RHIType type) {
return type == RHIType::D3D12 ? "quad_d3d12.ppm" : "quad_opengl.ppm";
switch (type) {
case RHIType::D3D12:
return "quad_d3d12.ppm";
case RHIType::OpenGL:
return "quad_opengl.ppm";
case RHIType::Vulkan:
return "quad_vulkan.ppm";
default:
return "quad_unknown.ppm";
}
}
RHITexture* LoadQuadTexture(RHIDevice* device) {
@@ -190,7 +221,7 @@ GraphicsPipelineDesc CreateQuadPipelineDesc(RHIType type, RHIPipelineLayout* pip
desc.fragmentShader.sourceLanguage = ShaderLanguage::HLSL;
desc.fragmentShader.entryPoint = L"MainPS";
desc.fragmentShader.profile = L"ps_5_0";
} else {
} else if (type == RHIType::OpenGL) {
desc.vertexShader.source.assign(kQuadVertexShader, kQuadVertexShader + strlen(kQuadVertexShader));
desc.vertexShader.sourceLanguage = ShaderLanguage::GLSL;
desc.vertexShader.profile = L"vs_4_30";
@@ -198,6 +229,14 @@ GraphicsPipelineDesc CreateQuadPipelineDesc(RHIType type, RHIPipelineLayout* pip
desc.fragmentShader.source.assign(kQuadFragmentShader, kQuadFragmentShader + strlen(kQuadFragmentShader));
desc.fragmentShader.sourceLanguage = ShaderLanguage::GLSL;
desc.fragmentShader.profile = L"fs_4_30";
} else if (type == RHIType::Vulkan) {
desc.vertexShader.source = LoadBinaryFileRelative("quad_vulkan.vert.spv");
desc.vertexShader.sourceLanguage = ShaderLanguage::SPIRV;
desc.vertexShader.entryPoint = L"main";
desc.fragmentShader.source = LoadBinaryFileRelative("quad_vulkan.frag.spv");
desc.fragmentShader.sourceLanguage = ShaderLanguage::SPIRV;
desc.fragmentShader.entryPoint = L"main";
}
return desc;
@@ -342,9 +381,34 @@ void QuadTest::InitializeQuadResources() {
ASSERT_NE(mSamplerSet, nullptr);
mSamplerSet->UpdateSampler(0, mSampler);
DescriptorSetLayoutBinding pipelineTextureBinding = {};
pipelineTextureBinding.binding = 0;
pipelineTextureBinding.type = static_cast<uint32_t>(DescriptorType::SRV);
pipelineTextureBinding.count = 1;
pipelineTextureBinding.visibility = static_cast<uint32_t>(ShaderVisibility::Pixel);
DescriptorSetLayoutDesc textureSetLayout = {};
textureSetLayout.bindings = &pipelineTextureBinding;
textureSetLayout.bindingCount = 1;
DescriptorSetLayoutBinding pipelineSamplerBinding = {};
pipelineSamplerBinding.binding = 0;
pipelineSamplerBinding.type = static_cast<uint32_t>(DescriptorType::Sampler);
pipelineSamplerBinding.count = 1;
pipelineSamplerBinding.visibility = static_cast<uint32_t>(ShaderVisibility::Pixel);
DescriptorSetLayoutDesc samplerSetLayout = {};
samplerSetLayout.bindings = &pipelineSamplerBinding;
samplerSetLayout.bindingCount = 1;
DescriptorSetLayoutDesc setLayouts[] = {
textureSetLayout,
samplerSetLayout,
};
RHIPipelineLayoutDesc pipelineLayoutDesc = {};
pipelineLayoutDesc.textureCount = 1;
pipelineLayoutDesc.samplerCount = 1;
pipelineLayoutDesc.setLayouts = setLayouts;
pipelineLayoutDesc.setLayoutCount = 2;
mPipelineLayout = GetDevice()->CreatePipelineLayout(pipelineLayoutDesc);
ASSERT_NE(mPipelineLayout, nullptr);
@@ -510,6 +574,9 @@ TEST_P(QuadTest, RenderQuad) {
INSTANTIATE_TEST_SUITE_P(D3D12, QuadTest, ::testing::Values(RHIType::D3D12));
INSTANTIATE_TEST_SUITE_P(OpenGL, QuadTest, ::testing::Values(RHIType::OpenGL));
#if defined(XCENGINE_SUPPORT_VULKAN)
INSTANTIATE_TEST_SUITE_P(Vulkan, QuadTest, ::testing::Values(RHIType::Vulkan));
#endif
GTEST_API_ int main(int argc, char** argv) {
Logger::Get().Initialize();