Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit fa4958d

Browse files
committed
Fix asymmetric stencil setting in GLES backend
- Small fix for GLES backend. - Add unit test for stencil masking.
1 parent 2a0dd9d commit fa4958d

File tree

3 files changed

+140
-6
lines changed

3 files changed

+140
-6
lines changed

impeller/core/formats.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,7 @@ struct StencilAttachmentDescriptor {
546546
/// Indicates what to do when both the stencil and depth tests pass.
547547
///
548548
StencilOperation depth_stencil_pass = StencilOperation::kKeep;
549+
549550
//----------------------------------------------------------------------------
550551
/// The mask applied to the reference and stencil buffer values before
551552
/// performing the stencil_compare operation.
@@ -567,7 +568,7 @@ struct StencilAttachmentDescriptor {
567568

568569
constexpr size_t GetHash() const {
569570
return fml::HashCombine(stencil_compare, stencil_failure, depth_failure,
570-
depth_stencil_pass, read_mask);
571+
depth_stencil_pass, read_mask, write_mask);
571572
}
572573
};
573574

impeller/renderer/backend/gles/render_pass_gles.cc

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,16 @@ void ConfigureStencil(const ProcTableGLES& gl,
100100
gl.Enable(GL_STENCIL_TEST);
101101
const auto& front = pipeline.GetFrontStencilAttachmentDescriptor();
102102
const auto& back = pipeline.GetBackStencilAttachmentDescriptor();
103-
if (front.has_value() && front == back) {
103+
104+
if (front.has_value() && back.has_value() && front == back) {
104105
ConfigureStencil(GL_FRONT_AND_BACK, gl, *front, stencil_reference);
105-
} else if (front.has_value()) {
106+
return;
107+
}
108+
if (front.has_value()) {
106109
ConfigureStencil(GL_FRONT, gl, *front, stencil_reference);
107-
} else if (back.has_value()) {
110+
}
111+
if (back.has_value()) {
108112
ConfigureStencil(GL_BACK, gl, *back, stencil_reference);
109-
} else {
110-
FML_UNREACHABLE();
111113
}
112114
}
113115

impeller/renderer/renderer_unittests.cc

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,137 @@ TEST_P(RendererTest, VertexBufferBuilder) {
10461046
ASSERT_EQ(vertex_builder.GetVertexCount(), 4u);
10471047
}
10481048

1049+
TEST_P(RendererTest, StencilMask) {
1050+
using VS = BoxFadeVertexShader;
1051+
using FS = BoxFadeFragmentShader;
1052+
auto context = GetContext();
1053+
ASSERT_TRUE(context);
1054+
using BoxFadePipelineBuilder = PipelineBuilder<VS, FS>;
1055+
auto desc = BoxFadePipelineBuilder::MakeDefaultPipelineDescriptor(*context);
1056+
ASSERT_TRUE(desc.has_value());
1057+
1058+
// Vertex buffer.
1059+
VertexBufferBuilder<VS::PerVertexData> vertex_builder;
1060+
vertex_builder.SetLabel("Box");
1061+
vertex_builder.AddVertices({
1062+
{{100, 100, 0.0}, {0.0, 0.0}}, // 1
1063+
{{800, 100, 0.0}, {1.0, 0.0}}, // 2
1064+
{{800, 800, 0.0}, {1.0, 1.0}}, // 3
1065+
{{100, 100, 0.0}, {0.0, 0.0}}, // 1
1066+
{{800, 800, 0.0}, {1.0, 1.0}}, // 3
1067+
{{100, 800, 0.0}, {0.0, 1.0}}, // 4
1068+
});
1069+
auto vertex_buffer =
1070+
vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
1071+
ASSERT_TRUE(vertex_buffer);
1072+
1073+
desc->SetSampleCount(SampleCount::kCount4);
1074+
1075+
auto bridge = CreateTextureForFixture("bay_bridge.jpg");
1076+
auto boston = CreateTextureForFixture("boston.jpg");
1077+
ASSERT_TRUE(bridge && boston);
1078+
auto sampler = context->GetSamplerLibrary()->GetSampler({});
1079+
ASSERT_TRUE(sampler);
1080+
1081+
static int stencil_reference_write = 0xFF;
1082+
static int stencil_reference_read = 0x1;
1083+
std::vector<uint8_t> stencil_contents;
1084+
static int last_stencil_contents_reference_value = 0;
1085+
Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
1086+
auto buffer = context->CreateCommandBuffer();
1087+
if (!buffer) {
1088+
return false;
1089+
}
1090+
buffer->SetLabel("Playground Command Buffer");
1091+
1092+
{
1093+
// Configure the stencil attachment for the test.
1094+
RenderTarget::AttachmentConfig stencil_config;
1095+
stencil_config.load_action = LoadAction::kLoad;
1096+
stencil_config.store_action = StoreAction::kDontCare;
1097+
stencil_config.storage_mode = StorageMode::kHostVisible;
1098+
render_target.SetupStencilAttachment(*context,
1099+
render_target.GetRenderTargetSize(),
1100+
true, "stencil", stencil_config);
1101+
// Fill the stencil buffer with an checkerboard pattern.
1102+
const auto target_width = render_target.GetRenderTargetSize().width;
1103+
const auto target_height = render_target.GetRenderTargetSize().height;
1104+
const size_t target_size = target_width * target_height;
1105+
if (stencil_contents.size() != target_size ||
1106+
last_stencil_contents_reference_value != stencil_reference_write) {
1107+
stencil_contents.resize(target_size);
1108+
last_stencil_contents_reference_value = stencil_reference_write;
1109+
for (int y = 0; y < target_height; y++) {
1110+
for (int x = 0; x < target_width; x++) {
1111+
const auto index = y * target_width + x;
1112+
const auto kCheckSize = 64;
1113+
const auto value =
1114+
(((y / kCheckSize) + (x / kCheckSize)) % 2 == 0) *
1115+
stencil_reference_write;
1116+
stencil_contents[index] = value;
1117+
}
1118+
}
1119+
}
1120+
if (!render_target.GetStencilAttachment()->texture->SetContents(
1121+
stencil_contents.data(), stencil_contents.size(), 0, false)) {
1122+
VALIDATION_LOG << "Could not upload stencil contents to device memory";
1123+
return false;
1124+
}
1125+
auto pass = buffer->CreateRenderPass(render_target);
1126+
if (!pass) {
1127+
return false;
1128+
}
1129+
pass->SetLabel("Stencil Buffer");
1130+
ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1131+
ImGui::SliderInt("Stencil Write Value", &stencil_reference_write, 0,
1132+
0xFF);
1133+
ImGui::SliderInt("Stencil Compare Value", &stencil_reference_read, 0,
1134+
0xFF);
1135+
ImGui::End();
1136+
StencilAttachmentDescriptor front_and_back;
1137+
front_and_back.stencil_compare = CompareFunction::kGreater;
1138+
desc->SetStencilAttachmentDescriptors(front_and_back);
1139+
auto pipeline = context->GetPipelineLibrary()->GetPipeline(desc).Get();
1140+
1141+
assert(pipeline && pipeline->IsValid());
1142+
1143+
Command cmd;
1144+
cmd.label = "Box";
1145+
cmd.pipeline = pipeline;
1146+
cmd.stencil_reference = stencil_reference_read;
1147+
1148+
cmd.BindVertices(vertex_buffer);
1149+
1150+
VS::UniformBuffer uniforms;
1151+
uniforms.mvp = Matrix::MakeOrthographic(pass->GetRenderTargetSize()) *
1152+
Matrix::MakeScale(GetContentScale());
1153+
VS::BindUniformBuffer(
1154+
cmd, pass->GetTransientsBuffer().EmplaceUniform(uniforms));
1155+
1156+
FS::FrameInfo frame_info;
1157+
frame_info.current_time = GetSecondsElapsed();
1158+
frame_info.cursor_position = GetCursorPosition();
1159+
frame_info.window_size.x = GetWindowSize().width;
1160+
frame_info.window_size.y = GetWindowSize().height;
1161+
1162+
FS::BindFrameInfo(cmd,
1163+
pass->GetTransientsBuffer().EmplaceUniform(frame_info));
1164+
FS::BindContents1(cmd, boston, sampler);
1165+
FS::BindContents2(cmd, bridge, sampler);
1166+
if (!pass->AddCommand(std::move(cmd))) {
1167+
return false;
1168+
}
1169+
pass->EncodeCommands();
1170+
}
1171+
1172+
if (!buffer->SubmitCommands()) {
1173+
return false;
1174+
}
1175+
return true;
1176+
};
1177+
OpenPlaygroundHere(callback);
1178+
}
1179+
10491180
} // namespace testing
10501181
} // namespace impeller
10511182

0 commit comments

Comments
 (0)