[Feat, Test] (Diligent, MG_Test): add stencil clear and stencil state test

- Use D24S8 for the default offscreen depth/stencil target
- Wire GL_STENCIL_BUFFER_BIT Clear through renderer->ClearStencil
- Add DrawsWithStencilTestFromMobileGLState; 13 Diligent tests pass
This commit is contained in:
BZLZHH
2026-08-23 09:37:49 +08:00
parent e829e70d8b
commit 23b53eacce
5 changed files with 112 additions and 4 deletions
+4 -2
View File
@@ -105,6 +105,7 @@ Working tree is clean.
- `DrawsWithBlendFromMobileGLState`
- `DrawsWithDepthTestFromMobileGLState`
- `DrawsNamedUniformBlockFromMobileGLState`
- `DrawsWithStencilTestFromMobileGLState`
---
@@ -128,6 +129,7 @@ Verified locally on Turnip Adreno 750:
- Textured draw test passes
- Render state:
- Blend enable/factors/equations
- Stencil clear + test enabled on a D24S8 default depth/stencil target
- Depth test enable/func/write mask
- Cull face enable/mode/front-face winding
- Stencil test enable/masks/ops/func/ref
@@ -156,7 +158,7 @@ Verified locally on Turnip Adreno 750:
- Local test result:
```
[ PASSED ] 12 tests
[ PASSED ] 13 tests
```
---
@@ -248,7 +250,7 @@ Notes:
- [x] Texture filtering / sampler state test
- [x] framebuffer offscreen render-to-texture test
- [x] Depth test visual test
- [ ] Stencil test
- [x] Stencil test
---
@@ -47,6 +47,9 @@ namespace MobileGL::MG_Backend::DiligentBackend {
if ((mask & GL_DEPTH_BUFFER_BIT) != 0) {
renderer->ClearDepth(MG_State::pGLContext->GetClearDepth());
}
if ((mask & GL_STENCIL_BUFFER_BIT) != 0) {
renderer->ClearStencil(MG_State::pGLContext->GetClearStencil());
}
}
void DrawArrays(GLenum mode, GLint first, GLsizei count) {
@@ -406,7 +406,7 @@ void main()
::Diligent::TextureDesc depthDesc;
depthDesc.Name = "MobileGL Diligent offscreen depth target";
depthDesc.Type = ::Diligent::RESOURCE_DIM_TEX_2D;
depthDesc.Format = ::Diligent::TEX_FORMAT_D32_FLOAT;
depthDesc.Format = ::Diligent::TEX_FORMAT_D24_UNORM_S8_UINT;
depthDesc.Width = m_width;
depthDesc.Height = m_height;
depthDesc.MipLevels = 1;
@@ -535,6 +535,21 @@ void main()
::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
}
void DiligentRenderer::ClearStencil(Uint32 stencil) {
if (!m_initialized || !m_pContext) {
return;
}
Vector<::Diligent::ITextureView*> rtvs;
::Diligent::ITextureView* dsv = nullptr;
if (!ResolveCurrentRenderTargets(rtvs, dsv) || dsv == nullptr) {
return;
}
m_pContext->SetRenderTargets(static_cast<::Diligent::Uint32>(rtvs.size()), rtvs.data(), dsv,
::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
m_pContext->ClearDepthStencil(dsv, ::Diligent::CLEAR_STENCIL_FLAG, 0, stencil,
::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
}
void DiligentRenderer::DrawTriangle() {
if (!m_initialized || !m_pContext || !m_pPSO) {
return;
@@ -1315,7 +1330,7 @@ void main()
psoDesc.ResourceLayout.DefaultVariableType = ::Diligent::SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC;
graphicsPipeline.NumRenderTargets = 1;
graphicsPipeline.RTVFormats[0] = ::Diligent::TEX_FORMAT_RGBA8_UNORM;
graphicsPipeline.DSVFormat = ::Diligent::TEX_FORMAT_D32_FLOAT;
graphicsPipeline.DSVFormat = ::Diligent::TEX_FORMAT_D24_UNORM_S8_UINT;
switch (mode) {
case GL_POINTS:
graphicsPipeline.PrimitiveTopology = ::Diligent::PRIMITIVE_TOPOLOGY_POINT_LIST;
@@ -51,6 +51,7 @@ namespace MobileGL::MG_Backend::DiligentBackend {
Bool Initialize(Uint32 width, Uint32 height);
void Clear(Float r, Float g, Float b, Float a);
void ClearDepth(Float depth);
void ClearStencil(Uint32 stencil);
void DrawTriangle();
void DrawVertices(const Float* vertices, Uint32 vertexCount);
// Creates a simple 2D RGBA8 texture from CPU data and makes it available
@@ -798,3 +798,90 @@ void main() { Color = u_color; }
EXPECT_LT(center[1], 50) << "center should not be green";
EXPECT_GT(center[2], 200) << "center should be blue from the named uniform block";
}
TEST(DiligentVulkanBackend, DrawsWithStencilTestFromMobileGLState) {
MobileGL::Initialize();
const char* vsSrc = R"(#version 330 core
layout(location = 0) in vec2 Position;
void main() { gl_Position = vec4(Position, 0.0, 1.0); }
)";
const char* redFsSrc = R"(#version 330 core
out vec4 Color;
void main() { Color = vec4(1.0, 0.0, 0.0, 1.0); }
)";
const char* blueFsSrc = R"(#version 330 core
out vec4 Color;
void main() { Color = vec4(0.0, 0.0, 1.0, 1.0); }
)";
const GLuint vs = CreateShader(GL_VERTEX_SHADER);
ShaderSource(vs, 1, &vsSrc, nullptr);
CompileShader(vs);
const GLuint redFs = CreateShader(GL_FRAGMENT_SHADER);
ShaderSource(redFs, 1, &redFsSrc, nullptr);
CompileShader(redFs);
const GLuint redProgram = CreateProgram();
AttachShader(redProgram, vs);
AttachShader(redProgram, redFs);
LinkProgram(redProgram);
const GLuint blueFs = CreateShader(GL_FRAGMENT_SHADER);
ShaderSource(blueFs, 1, &blueFsSrc, nullptr);
CompileShader(blueFs);
const GLuint blueProgram = CreateProgram();
AttachShader(blueProgram, vs);
AttachShader(blueProgram, blueFs);
LinkProgram(blueProgram);
const float vertices[] = {
-0.5f, -0.5f,
0.5f, -0.5f,
0.0f, 0.5f,
};
GLuint vbo = 0;
GenBuffers(1, &vbo);
BindBuffer(GL_ARRAY_BUFFER, vbo);
BufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
GLuint vao = 0;
GenVertexArrays(1, &vao);
BindVertexArray(vao);
EnableVertexAttribArray(0);
VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
BindFramebuffer(GL_FRAMEBUFFER, 0);
Disable(GL_DEPTH_TEST);
Disable(GL_BLEND);
Disable(GL_SCISSOR_TEST);
Viewport(0, 0, 256, 256);
DiligentBackend::BackendObject_Diligent backend;
backend.Initialize();
auto* renderer = backend.GetRenderer();
if (renderer == nullptr) {
GTEST_SKIP() << "No Vulkan adapter available; skipping stencil state test";
}
renderer->Clear(0.0f, 1.0f, 0.0f, 1.0f);
renderer->ClearStencil(0);
Enable(GL_STENCIL_TEST);
StencilMask(0xFF);
StencilFunc(GL_ALWAYS, 1, 0xFF);
StencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
UseProgram(redProgram);
renderer->DrawFromState(GL_TRIANGLES, 0, 3, 0, nullptr);
// Second draw should fail the stencil test (ref 2 != stencil value 1).
StencilFunc(GL_EQUAL, 2, 0xFF);
StencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
UseProgram(blueProgram);
renderer->DrawFromState(GL_TRIANGLES, 0, 3, 0, nullptr);
renderer->Present();
std::uint8_t center[4] = {};
renderer->ReadPixels(128, 128, 1, 1, center);
EXPECT_GT(center[0], 200) << "center should remain red after failing stencil draw";
EXPECT_LT(center[2], 50) << "center should not become blue";
}