rendering: add opengl hlsl shader translation

This commit is contained in:
2026-04-06 18:07:13 +08:00
parent f912e81ade
commit 97e986b52c
9 changed files with 1561 additions and 752 deletions

View File

@@ -19,10 +19,37 @@
#include <cstdint>
#include <cstring>
#include <algorithm>
#include <filesystem>
#include <vector>
using namespace XCEngine::RHI;
namespace {
bool FindToolFromVulkanSdkOrPath(const wchar_t* fileName) {
wchar_t sdkBuffer[32767] = {};
const DWORD sdkBufferCount = static_cast<DWORD>(sizeof(sdkBuffer) / sizeof(sdkBuffer[0]));
const DWORD sdkLength = GetEnvironmentVariableW(L"VULKAN_SDK", sdkBuffer, sdkBufferCount);
if (sdkLength > 0 && sdkLength < sdkBufferCount) {
const std::filesystem::path candidate = std::filesystem::path(sdkBuffer) / L"Bin" / fileName;
if (std::filesystem::exists(candidate)) {
return true;
}
}
wchar_t pathBuffer[MAX_PATH] = {};
const DWORD pathLength = SearchPathW(nullptr, fileName, nullptr, MAX_PATH, pathBuffer, nullptr);
return pathLength > 0 && pathLength < MAX_PATH;
}
bool SupportsOpenGLHlslToolchainForTests() {
return FindToolFromVulkanSdkOrPath(L"glslangValidator.exe") &&
FindToolFromVulkanSdkOrPath(L"spirv-cross.exe");
}
} // namespace
TEST_F(OpenGLTestFixture, Device_Initialize_UnifiedPath_CanCreateSwapChain) {
auto* device = new OpenGLDevice();
ASSERT_NE(device, nullptr);
@@ -52,6 +79,100 @@ TEST_F(OpenGLTestFixture, Device_Initialize_UnifiedPath_CanCreateSwapChain) {
delete device;
}
TEST_F(OpenGLTestFixture, Device_CreateShader_HlslVertex_UsesTranspiledHlslPath) {
ASSERT_TRUE(GetDevice()->MakeContextCurrent());
if (!SupportsOpenGLHlslToolchainForTests()) {
GTEST_SKIP() << "glslangValidator.exe or spirv-cross.exe was not found.";
}
static const char* vertexSource = R"(
struct VSInput {
float4 position : POSITION;
};
struct VSOutput {
float4 position : SV_POSITION;
};
VSOutput MainVS(VSInput input) {
VSOutput output;
output.position = input.position;
return output;
}
)";
ShaderCompileDesc shaderDesc = {};
shaderDesc.source.assign(vertexSource, vertexSource + std::strlen(vertexSource));
shaderDesc.sourceLanguage = ShaderLanguage::HLSL;
shaderDesc.entryPoint = L"MainVS";
shaderDesc.profile = L"vs_5_0";
RHIShader* shader = GetDevice()->CreateShader(shaderDesc);
ASSERT_NE(shader, nullptr);
EXPECT_TRUE(shader->IsValid());
EXPECT_EQ(shader->GetType(), ShaderType::Vertex);
shader->Shutdown();
delete shader;
}
TEST_F(OpenGLTestFixture, Device_CreatePipelineState_HlslGraphicsShaders_UsesTranspiledHlslPath) {
ASSERT_TRUE(GetDevice()->MakeContextCurrent());
if (!SupportsOpenGLHlslToolchainForTests()) {
GTEST_SKIP() << "glslangValidator.exe or spirv-cross.exe was not found.";
}
static const char* hlslSource = R"(
struct VSInput {
float4 position : POSITION;
};
struct PSInput {
float4 position : SV_POSITION;
};
PSInput MainVS(VSInput input) {
PSInput output;
output.position = input.position;
return output;
}
float4 MainPS(PSInput input) : SV_TARGET {
return float4(1.0f, 0.25f, 0.0f, 1.0f);
}
)";
GraphicsPipelineDesc pipelineDesc = {};
pipelineDesc.topologyType = static_cast<uint32_t>(PrimitiveTopologyType::Triangle);
pipelineDesc.renderTargetFormats[0] = static_cast<uint32_t>(Format::R8G8B8A8_UNorm);
pipelineDesc.depthStencilFormat = static_cast<uint32_t>(Format::Unknown);
InputElementDesc position = {};
position.semanticName = "POSITION";
position.semanticIndex = 0;
position.format = static_cast<uint32_t>(Format::R32G32B32A32_Float);
position.inputSlot = 0;
position.alignedByteOffset = 0;
pipelineDesc.inputLayout.elements.push_back(position);
pipelineDesc.vertexShader.source.assign(hlslSource, hlslSource + std::strlen(hlslSource));
pipelineDesc.vertexShader.sourceLanguage = ShaderLanguage::HLSL;
pipelineDesc.vertexShader.entryPoint = L"MainVS";
pipelineDesc.vertexShader.profile = L"vs_5_0";
pipelineDesc.fragmentShader.source.assign(hlslSource, hlslSource + std::strlen(hlslSource));
pipelineDesc.fragmentShader.sourceLanguage = ShaderLanguage::HLSL;
pipelineDesc.fragmentShader.entryPoint = L"MainPS";
pipelineDesc.fragmentShader.profile = L"ps_5_0";
RHIPipelineState* pipelineState = GetDevice()->CreatePipelineState(pipelineDesc);
ASSERT_NE(pipelineState, nullptr);
EXPECT_NE(pipelineState->GetNativeHandle(), nullptr);
pipelineState->Shutdown();
delete pipelineState;
}
TEST_F(OpenGLTestFixture, CommandList_SetRenderTargets_BindsColorAndDepthAttachments) {
TextureDesc colorDesc = {};
colorDesc.width = 128;