engine: sync editor rendering and ui changes

This commit is contained in:
2026-04-08 16:09:15 +08:00
parent 31756847ab
commit 162f1cc12e
153 changed files with 4454 additions and 2990 deletions

View File

@@ -1,6 +1,7 @@
#include "fixtures/OpenGLTestFixture.h"
#include "XCEngine/RHI/OpenGL/OpenGLDescriptorSet.h"
#include "XCEngine/RHI/OpenGL/OpenGLPipelineState.h"
#include "XCEngine/RHI/OpenGL/OpenGLPipelineLayout.h"
#include "XCEngine/RHI/OpenGL/OpenGLResourceView.h"
#include "XCEngine/RHI/OpenGL/OpenGLSampler.h"
@@ -21,6 +22,7 @@
#include <cstring>
#include <algorithm>
#include <filesystem>
#include <iostream>
#include <vector>
using namespace XCEngine::RHI;
@@ -173,6 +175,128 @@ float4 MainPS(PSInput input) : SV_TARGET {
delete pipelineState;
}
TEST_F(OpenGLTestFixture, Device_CreatePipelineState_HlslGraphicsShaders_AssignsCombinedSamplerUniformUnits) {
ASSERT_TRUE(GetDevice()->MakeContextCurrent());
if (!SupportsOpenGLHlslToolchainForTests()) {
GTEST_SKIP() << "glslangValidator.exe or spirv-cross.exe was not found.";
}
static const char* hlslSource = R"(
Texture2D BaseColorTexture : register(t0);
SamplerState LinearClampSampler : register(s0);
Texture2D ShadowMapTexture : register(t1);
SamplerState ShadowMapSampler : register(s1);
struct VSInput {
float4 position : POSITION;
float2 texcoord : TEXCOORD0;
};
struct PSInput {
float4 position : SV_POSITION;
float2 texcoord : TEXCOORD0;
};
PSInput MainVS(VSInput input) {
PSInput output;
output.position = input.position;
output.texcoord = input.texcoord;
return output;
}
float4 MainPS(PSInput input) : SV_TARGET {
float4 baseColor = BaseColorTexture.Sample(LinearClampSampler, input.texcoord);
float shadow = ShadowMapTexture.Sample(ShadowMapSampler, input.texcoord).r;
return float4(baseColor.rgb * shadow, baseColor.a);
}
)";
GraphicsPipelineDesc pipelineDesc = {};
pipelineDesc.topologyType = static_cast<uint32_t>(PrimitiveTopologyType::Triangle);
pipelineDesc.renderTargetFormats[0] = static_cast<uint32_t>(Format::R8G8B8A8_UNorm);
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);
InputElementDesc texcoord = {};
texcoord.semanticName = "TEXCOORD";
texcoord.semanticIndex = 0;
texcoord.format = static_cast<uint32_t>(Format::R32G32_Float);
texcoord.inputSlot = 0;
texcoord.alignedByteOffset = sizeof(float) * 4;
pipelineDesc.inputLayout.elements.push_back(texcoord);
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);
const GLuint program = static_cast<OpenGLPipelineState*>(pipelineState)->GetProgram();
ASSERT_NE(program, 0u);
const GLint baseColorLocation =
glGetUniformLocation(program, "SPIRV_Cross_CombinedBaseColorTextureLinearClampSampler");
const GLint shadowLocation =
glGetUniformLocation(program, "SPIRV_Cross_CombinedShadowMapTextureShadowMapSampler");
ASSERT_GE(baseColorLocation, 0);
ASSERT_GE(shadowLocation, 0);
GLint baseColorUnit = -1;
GLint shadowUnit = -1;
glGetUniformiv(program, baseColorLocation, &baseColorUnit);
glGetUniformiv(program, shadowLocation, &shadowUnit);
GLint activeUniformCount = 0;
glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &activeUniformCount);
for (GLint uniformIndex = 0; uniformIndex < activeUniformCount; ++uniformIndex) {
GLsizei nameLength = 0;
GLint arraySize = 0;
GLenum type = 0;
char nameBuffer[256] = {};
glGetActiveUniform(
program,
static_cast<GLuint>(uniformIndex),
static_cast<GLsizei>(sizeof(nameBuffer)),
&nameLength,
&arraySize,
&type,
nameBuffer);
if (nameLength <= 0) {
continue;
}
GLint location = glGetUniformLocation(program, nameBuffer);
GLint value = -1;
if (location >= 0) {
glGetUniformiv(program, location, &value);
}
std::cout << "uniform[" << uniformIndex << "] name=" << nameBuffer
<< " location=" << location
<< " value=" << value
<< " type=" << type
<< " arraySize=" << arraySize
<< std::endl;
}
EXPECT_EQ(baseColorUnit, 0);
EXPECT_EQ(shadowUnit, 1);
pipelineState->Shutdown();
delete pipelineState;
}
TEST_F(OpenGLTestFixture, CommandList_SetRenderTargets_BindsColorAndDepthAttachments) {
TextureDesc colorDesc = {};
colorDesc.width = 128;

View File

@@ -1,6 +1,7 @@
#include "fixtures/OpenGLTestFixture.h"
#include "XCEngine/RHI/OpenGL/OpenGLCommandList.h"
#include "XCEngine/RHI/OpenGL/OpenGLBuffer.h"
#include "XCEngine/RHI/OpenGL/OpenGLPipelineState.h"
#include "XCEngine/RHI/OpenGL/OpenGLVertexArray.h"
using namespace XCEngine::RHI;
@@ -160,3 +161,30 @@ TEST_F(OpenGLTestFixture, CommandList_SetBlendFactor) {
EXPECT_FLOAT_EQ(color[2], 0.5f);
EXPECT_FLOAT_EQ(color[3], 1.0f);
}
TEST_F(OpenGLTestFixture, CommandList_SetStencilRef_UpdatesActivePipelineStencilReference) {
OpenGLCommandList cmdList;
OpenGLPipelineState pipeline;
DepthStencilStateDesc state = {};
state.stencilEnable = true;
state.front.func = static_cast<uint32_t>(ComparisonFunc::Equal);
state.back.func = static_cast<uint32_t>(ComparisonFunc::NotEqual);
pipeline.SetDepthStencilState(state);
cmdList.SetPipelineState(&pipeline);
cmdList.SetStencilRef(5);
GLint frontRef = 0;
GLint backRef = 0;
GLint frontFunc = 0;
GLint backFunc = 0;
glGetIntegerv(GL_STENCIL_REF, &frontRef);
glGetIntegerv(GL_STENCIL_BACK_REF, &backRef);
glGetIntegerv(GL_STENCIL_FUNC, &frontFunc);
glGetIntegerv(GL_STENCIL_BACK_FUNC, &backFunc);
EXPECT_EQ(frontRef, 5);
EXPECT_EQ(backRef, 5);
EXPECT_EQ(frontFunc, GL_EQUAL);
EXPECT_EQ(backFunc, GL_NOTEQUAL);
}

View File

@@ -39,6 +39,92 @@ TEST_F(OpenGLTestFixture, PipelineState_SetBlendState) {
EXPECT_EQ(blend, 1);
}
TEST_F(OpenGLTestFixture, PipelineState_ApplyDepthStencil_UsesSeparateStencilFaces) {
OpenGLPipelineState pipeline;
DepthStencilStateDesc state = {};
state.depthTestEnable = true;
state.depthWriteEnable = true;
state.depthFunc = static_cast<uint32_t>(ComparisonFunc::LessEqual);
state.stencilEnable = true;
state.stencilReadMask = 0x3F;
state.stencilWriteMask = 0x1F;
state.front.func = static_cast<uint32_t>(ComparisonFunc::Equal);
state.front.failOp = static_cast<uint32_t>(StencilOp::Replace);
state.front.passOp = static_cast<uint32_t>(StencilOp::Incr);
state.front.depthFailOp = static_cast<uint32_t>(StencilOp::DecrSat);
state.back.func = static_cast<uint32_t>(ComparisonFunc::NotEqual);
state.back.failOp = static_cast<uint32_t>(StencilOp::Invert);
state.back.passOp = static_cast<uint32_t>(StencilOp::Decr);
state.back.depthFailOp = static_cast<uint32_t>(StencilOp::Zero);
pipeline.SetDepthStencilState(state);
pipeline.ApplyDepthStencil();
EXPECT_TRUE(glIsEnabled(GL_STENCIL_TEST));
GLint frontFunc = 0;
GLint backFunc = 0;
GLint frontRef = 0;
GLint backRef = 0;
GLint frontValueMask = 0;
GLint backValueMask = 0;
GLint frontWriteMask = 0;
GLint backWriteMask = 0;
GLint frontFail = 0;
GLint backFail = 0;
GLint frontPassDepthPass = 0;
GLint backPassDepthPass = 0;
glGetIntegerv(GL_STENCIL_FUNC, &frontFunc);
glGetIntegerv(GL_STENCIL_BACK_FUNC, &backFunc);
glGetIntegerv(GL_STENCIL_REF, &frontRef);
glGetIntegerv(GL_STENCIL_BACK_REF, &backRef);
glGetIntegerv(GL_STENCIL_VALUE_MASK, &frontValueMask);
glGetIntegerv(GL_STENCIL_BACK_VALUE_MASK, &backValueMask);
glGetIntegerv(GL_STENCIL_WRITEMASK, &frontWriteMask);
glGetIntegerv(GL_STENCIL_BACK_WRITEMASK, &backWriteMask);
glGetIntegerv(GL_STENCIL_FAIL, &frontFail);
glGetIntegerv(GL_STENCIL_BACK_FAIL, &backFail);
glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &frontPassDepthPass);
glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS, &backPassDepthPass);
EXPECT_EQ(frontFunc, GL_EQUAL);
EXPECT_EQ(backFunc, GL_NOTEQUAL);
EXPECT_EQ(frontRef, 0);
EXPECT_EQ(backRef, 0);
EXPECT_EQ(frontValueMask, 0x3F);
EXPECT_EQ(backValueMask, 0x3F);
EXPECT_EQ(frontWriteMask, 0x1F);
EXPECT_EQ(backWriteMask, 0x1F);
EXPECT_EQ(frontFail, GL_REPLACE);
EXPECT_EQ(backFail, GL_INVERT);
EXPECT_EQ(frontPassDepthPass, GL_INCR_WRAP);
EXPECT_EQ(backPassDepthPass, GL_DECR_WRAP);
}
TEST_F(OpenGLTestFixture, PipelineState_ApplyRasterizer_EnablesPolygonOffset) {
OpenGLPipelineState pipeline;
RasterizerDesc state = {};
state.fillMode = static_cast<uint32_t>(FillMode::Solid);
state.cullMode = static_cast<uint32_t>(CullMode::Back);
state.frontFace = static_cast<uint32_t>(FrontFace::CounterClockwise);
state.slopeScaledDepthBias = 1.5f;
state.depthBias = 3;
pipeline.SetRasterizerState(state);
pipeline.ApplyRasterizer();
EXPECT_TRUE(glIsEnabled(GL_POLYGON_OFFSET_FILL));
GLfloat factor = 0.0f;
GLfloat units = 0.0f;
glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &factor);
glGetFloatv(GL_POLYGON_OFFSET_UNITS, &units);
EXPECT_FLOAT_EQ(factor, 1.5f);
EXPECT_FLOAT_EQ(units, 3.0f);
}
TEST_F(OpenGLTestFixture, PipelineState_SetViewport_SetScissor) {
OpenGLPipelineState pipeline;