Skip to content

Commit

Permalink
Fix asymmetric stencil setting in GLES backend
Browse files Browse the repository at this point in the history
- Small fix for GLES backend.
- Add unit test for stencil masking.
  • Loading branch information
johnmccutchan committed Jul 12, 2023
1 parent 2a0dd9d commit 3de072c
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 6 deletions.
3 changes: 2 additions & 1 deletion impeller/core/formats.h
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,7 @@ struct StencilAttachmentDescriptor {
/// Indicates what to do when both the stencil and depth tests pass.
///
StencilOperation depth_stencil_pass = StencilOperation::kKeep;

//----------------------------------------------------------------------------
/// The mask applied to the reference and stencil buffer values before
/// performing the stencil_compare operation.
Expand All @@ -567,7 +568,7 @@ struct StencilAttachmentDescriptor {

constexpr size_t GetHash() const {
return fml::HashCombine(stencil_compare, stencil_failure, depth_failure,
depth_stencil_pass, read_mask);
depth_stencil_pass, read_mask, write_mask);
}
};

Expand Down
12 changes: 7 additions & 5 deletions impeller/renderer/backend/gles/render_pass_gles.cc
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,16 @@ void ConfigureStencil(const ProcTableGLES& gl,
gl.Enable(GL_STENCIL_TEST);
const auto& front = pipeline.GetFrontStencilAttachmentDescriptor();
const auto& back = pipeline.GetBackStencilAttachmentDescriptor();
if (front.has_value() && front == back) {

if (front.has_value() && back.has_value() && front == back) {
ConfigureStencil(GL_FRONT_AND_BACK, gl, *front, stencil_reference);
} else if (front.has_value()) {
return;
}
if (front.has_value()) {
ConfigureStencil(GL_FRONT, gl, *front, stencil_reference);
} else if (back.has_value()) {
}
if (back.has_value()) {
ConfigureStencil(GL_BACK, gl, *back, stencil_reference);
} else {
FML_UNREACHABLE();
}
}

Expand Down
136 changes: 136 additions & 0 deletions impeller/renderer/renderer_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,142 @@ TEST_P(RendererTest, VertexBufferBuilder) {
ASSERT_EQ(vertex_builder.GetVertexCount(), 4u);
}

TEST_P(RendererTest, StencilMask) {
using VS = BoxFadeVertexShader;
using FS = BoxFadeFragmentShader;
auto context = GetContext();
ASSERT_TRUE(context);
using BoxFadePipelineBuilder = PipelineBuilder<VS, FS>;
auto desc = BoxFadePipelineBuilder::MakeDefaultPipelineDescriptor(*context);
ASSERT_TRUE(desc.has_value());

// Vertex buffer.
VertexBufferBuilder<VS::PerVertexData> vertex_builder;
vertex_builder.SetLabel("Box");
vertex_builder.AddVertices({
{{100, 100, 0.0}, {0.0, 0.0}}, // 1
{{800, 100, 0.0}, {1.0, 0.0}}, // 2
{{800, 800, 0.0}, {1.0, 1.0}}, // 3
{{100, 100, 0.0}, {0.0, 0.0}}, // 1
{{800, 800, 0.0}, {1.0, 1.0}}, // 3
{{100, 800, 0.0}, {0.0, 1.0}}, // 4
});
auto vertex_buffer =
vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
ASSERT_TRUE(vertex_buffer);

desc->SetSampleCount(SampleCount::kCount4);

auto bridge = CreateTextureForFixture("bay_bridge.jpg");
auto boston = CreateTextureForFixture("boston.jpg");
ASSERT_TRUE(bridge && boston);
auto sampler = context->GetSamplerLibrary()->GetSampler({});
ASSERT_TRUE(sampler);

static bool mirror = false;
static int stencil_reference_write = 0xFF;
static int stencil_reference_read = 0x1;
std::vector<uint8_t> stencil_contents;
static int last_stencil_contents_reference_value = 0;
Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
auto buffer = context->CreateCommandBuffer();
if (!buffer) {
return false;
}
buffer->SetLabel("Playground Command Buffer");

{
// Configure the stencil attachment for the test.
RenderTarget::AttachmentConfig stencil_config;
stencil_config.load_action = LoadAction::kLoad;
stencil_config.store_action = StoreAction::kDontCare;
stencil_config.storage_mode = StorageMode::kHostVisible;
render_target.SetupStencilAttachment(*context,
render_target.GetRenderTargetSize(),
true, "stencil", stencil_config);
// Fill the stencil buffer with an checkerboard pattern.
const auto target_width = render_target.GetRenderTargetSize().width;
const auto target_height = render_target.GetRenderTargetSize().height;
const size_t target_size = target_width * target_height;
if (stencil_contents.size() != target_size ||
last_stencil_contents_reference_value != stencil_reference_write) {
stencil_contents.resize(target_size);
last_stencil_contents_reference_value = stencil_reference_write;
for (int y = 0; y < target_height; y++) {
for (int x = 0; x < target_width; x++) {
const auto index = y * target_width + x;
const auto kCheckSize = 64;
const auto value =
(((y / kCheckSize) + (x / kCheckSize)) % 2 == 0) *
stencil_reference_write;
stencil_contents[index] = value;
}
}
}
if (!render_target.GetStencilAttachment()->texture->SetContents(
stencil_contents.data(), stencil_contents.size(), 0, false)) {
VALIDATION_LOG << "Could not upload stencil contents to device memory";
return false;
}
auto pass = buffer->CreateRenderPass(render_target);
if (!pass) {
return false;
}
pass->SetLabel("Stencil Buffer");
ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
ImGui::SliderInt("Stencil Write Value", &stencil_reference_write, 0,
0xFF);
ImGui::SliderInt("Stencil Compare Value", &stencil_reference_read, 0,
0xFF);
ImGui::Checkbox("Mirror", &mirror);
ImGui::End();
StencilAttachmentDescriptor front_and_back;
front_and_back.stencil_compare = CompareFunction::kLessEqual;
desc->SetStencilAttachmentDescriptors(front_and_back);
auto pipeline = context->GetPipelineLibrary()->GetPipeline(desc).Get();

assert(pipeline && pipeline->IsValid());

Command cmd;
cmd.label = "Box";
cmd.pipeline = pipeline;
cmd.stencil_reference = stencil_reference_read;

cmd.BindVertices(vertex_buffer);

VS::UniformBuffer uniforms;
uniforms.mvp = Matrix::MakeOrthographic(pass->GetRenderTargetSize()) *
Matrix::MakeScale(GetContentScale());
if (mirror) {
uniforms.mvp = Matrix::MakeScale(Vector2(-1, -1)) * uniforms.mvp;
}
VS::BindUniformBuffer(
cmd, pass->GetTransientsBuffer().EmplaceUniform(uniforms));

FS::FrameInfo frame_info;
frame_info.current_time = GetSecondsElapsed();
frame_info.cursor_position = GetCursorPosition();
frame_info.window_size.x = GetWindowSize().width;
frame_info.window_size.y = GetWindowSize().height;

FS::BindFrameInfo(cmd,
pass->GetTransientsBuffer().EmplaceUniform(frame_info));
FS::BindContents1(cmd, boston, sampler);
FS::BindContents2(cmd, bridge, sampler);
if (!pass->AddCommand(std::move(cmd))) {
return false;
}
pass->EncodeCommands();
}

if (!buffer->SubmitCommands()) {
return false;
}
return true;
};
OpenPlaygroundHere(callback);
}

} // namespace testing
} // namespace impeller

Expand Down

0 comments on commit 3de072c

Please sign in to comment.