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

[Impeller] Make StC work for Position+UV buffers. #50900

Merged
merged 8 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3537,7 +3537,8 @@ TEST_P(AiksTest, CorrectClipDepthAssignedToEntities) {
// once we switch to the clip depth approach.

auto picture = canvas.EndRecordingAsPicture();
std::array<uint32_t, 5> expected = {

std::vector<uint32_t> expected = {
2, // DrawRRect
4, // ClipRRect -- Has a depth value equal to the max depth of all the
// content it affect. In this case, the SaveLayer and all
Expand All @@ -3546,8 +3547,9 @@ TEST_P(AiksTest, CorrectClipDepthAssignedToEntities) {
// contents are rendered, so it should have a depth value
// greater than all its contents.
3, // DrawRRect
5, // Restore (will be removed once we switch to the clip depth approach)
5, // Restore (no longer necessary when clipping on the depth buffer)
};

std::vector<uint32_t> actual;

picture.pass->IterateAllElements([&](EntityPass::Element& element) -> bool {
Expand Down
6 changes: 2 additions & 4 deletions impeller/aiks/canvas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -219,10 +219,8 @@ bool Canvas::Restore() {
}

transform_stack_.pop_back();
if constexpr (!ContentContext::kEnableStencilThenCover) {
if (num_clips > 0) {
RestoreClip();
}
if (num_clips > 0) {
RestoreClip();
}

return true;
Expand Down
161 changes: 66 additions & 95 deletions impeller/entity/contents/color_source_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/contents/contents.h"
#include "impeller/entity/geometry/geometry.h"
#include "impeller/entity/geometry/rect_geometry.h"
#include "impeller/geometry/matrix.h"

namespace impeller {
Expand Down Expand Up @@ -112,80 +113,83 @@ class ColorSourceContents : public Contents {
ContentContextOptions)>;

template <typename VertexShaderT>
bool DrawGeometry(GeometryResult geometry_result,
const ContentContext& renderer,
bool DrawGeometry(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass,
const PipelineBuilderCallback& pipeline_callback,
typename VertexShaderT::FrameInfo frame_info,
const BindFragmentCallback& bind_fragment_callback) const {
const BindFragmentCallback& bind_fragment_callback,
bool enable_uvs = false,
Rect texture_coverage = {},
const Matrix& effect_transform = {}) const {
auto options = OptionsFromPassAndEntity(pass, entity);

GeometryResult::Mode geometry_mode = GetGeometry()->GetResultMode();
Geometry& geometry = *GetGeometry();

const bool is_stencil_then_cover =
geometry_mode == GeometryResult::Mode::kNonZero ||
geometry_mode == GeometryResult::Mode::kEvenOdd;
if (is_stencil_then_cover) {
pass.SetStencilReference(0);

/// Stencil preparation draw.

GeometryResult stencil_geometry_result =
GetGeometry()->GetPositionBuffer(renderer, entity, pass);
pass.SetVertexBuffer(std::move(stencil_geometry_result.vertex_buffer));
options.primitive_type = stencil_geometry_result.type;

options.blend_mode = BlendMode::kDestination;
switch (stencil_geometry_result.mode) {
case GeometryResult::Mode::kNonZero:
pass.SetCommandLabel("Stencil preparation (NonZero)");
options.stencil_mode =
ContentContextOptions::StencilMode::kStencilNonZeroFill;
break;
case GeometryResult::Mode::kEvenOdd:
pass.SetCommandLabel("Stencil preparation (EvenOdd)");
options.stencil_mode =
ContentContextOptions::StencilMode::kStencilEvenOddFill;
break;
default:
FML_UNREACHABLE();
}
pass.SetPipeline(renderer.GetClipPipeline(options));
ClipPipeline::VertexShader::FrameInfo clip_frame_info;
clip_frame_info.depth = entity.GetShaderClipDepth();
clip_frame_info.mvp = stencil_geometry_result.transform;
ClipPipeline::VertexShader::BindFrameInfo(
pass, renderer.GetTransientsBuffer().EmplaceUniform(clip_frame_info));

if (!pass.Draw().ok()) {
return false;
}

/// Cover draw.

options.blend_mode = entity.GetBlendMode();
options.stencil_mode = ContentContextOptions::StencilMode::kCoverCompare;
std::optional<Rect> maybe_cover_area = GetGeometry()->GetCoverage({});
if (!maybe_cover_area.has_value()) {
return true;
}
geometry = RectGeometry(maybe_cover_area.value());
}

GeometryResult geometry_result =
enable_uvs
? geometry.GetPositionUVBuffer(texture_coverage, effect_transform,
renderer, entity, pass)
: geometry.GetPositionBuffer(renderer, entity, pass);
pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));
options.primitive_type = geometry_result.type;

// Take the pre-populated vertex shader uniform struct and set managed
// values.
frame_info.depth = entity.GetShaderClipDepth();
frame_info.mvp = geometry_result.transform;

pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));

if constexpr (ContentContext::kEnableStencilThenCover) {
const bool is_stencil_then_cover =
geometry_result.mode == GeometryResult::Mode::kNonZero ||
geometry_result.mode == GeometryResult::Mode::kEvenOdd;
if (is_stencil_then_cover) {
pass.SetStencilReference(0);

/// Stencil preparation draw.

options.blend_mode = BlendMode::kDestination;
switch (geometry_result.mode) {
case GeometryResult::Mode::kNonZero:
pass.SetCommandLabel("Stencil preparation (NonZero)");
options.stencil_mode =
ContentContextOptions::StencilMode::kStencilNonZeroFill;
break;
case GeometryResult::Mode::kEvenOdd:
pass.SetCommandLabel("Stencil preparation (EvenOdd)");
options.stencil_mode =
ContentContextOptions::StencilMode::kStencilEvenOddFill;
break;
default:
FML_UNREACHABLE();
}
pass.SetPipeline(renderer.GetClipPipeline(options));
ClipPipeline::VertexShader::FrameInfo clip_frame_info;
clip_frame_info.depth = entity.GetShaderClipDepth();
clip_frame_info.mvp = geometry_result.transform;
ClipPipeline::VertexShader::BindFrameInfo(
pass,
renderer.GetTransientsBuffer().EmplaceUniform(clip_frame_info));

if (!pass.Draw().ok()) {
return false;
}

/// Cover draw.

options.stencil_mode =
ContentContextOptions::StencilMode::kCoverCompare;
std::optional<Rect> maybe_cover_area =
GetGeometry()->GetCoverage(entity.GetTransform());
if (!maybe_cover_area.has_value()) {
return true;
}
auto points = maybe_cover_area.value().GetPoints();
auto vertices =
VertexBufferBuilder<typename VertexShaderT::PerVertexData>{}
.AddVertices(
{{points[0]}, {points[1]}, {points[2]}, {points[3]}})
.CreateVertexBuffer(renderer.GetTransientsBuffer());
pass.SetVertexBuffer(std::move(vertices));

frame_info.mvp = pass.GetOrthographicTransform();
}
}

// If overdraw prevention is enabled (like when drawing stroke paths), we
// increment the stencil buffer as we draw, preventing overlapping fragments
// from drawing. Afterwards, we need to append another draw call to clean up
Expand Down Expand Up @@ -234,39 +238,6 @@ class ColorSourceContents : public Contents {
return true;
}

template <typename VertexShaderT>
bool DrawPositions(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass,
const PipelineBuilderCallback& pipeline_callback,
typename VertexShaderT::FrameInfo frame_info,
const BindFragmentCallback& bind_pipeline_callback) const {
GeometryResult geometry_result =
GetGeometry()->GetPositionBuffer(renderer, entity, pass);

return DrawGeometry<VertexShaderT>(std::move(geometry_result), renderer,
entity, pass, pipeline_callback,
frame_info, bind_pipeline_callback);
}

template <typename VertexShaderT>
bool DrawPositionsAndUVs(
Rect texture_coverage,
const Matrix& effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass,
const PipelineBuilderCallback& pipeline_callback,
typename VertexShaderT::FrameInfo frame_info,
const BindFragmentCallback& bind_pipeline_callback) const {
auto geometry_result = GetGeometry()->GetPositionUVBuffer(
texture_coverage, effect_transform, renderer, entity, pass);

return DrawGeometry<VertexShaderT>(std::move(geometry_result), renderer,
entity, pass, pipeline_callback,
frame_info, bind_pipeline_callback);
}

private:
std::shared_ptr<Geometry> geometry_;
Matrix inverse_matrix_;
Expand Down
4 changes: 2 additions & 2 deletions impeller/entity/contents/conical_gradient_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ bool ConicalGradientContents::RenderSSBO(const ContentContext& renderer,
[&renderer](ContentContextOptions options) {
return renderer.GetConicalGradientSSBOFillPipeline(options);
};
return ColorSourceContents::DrawPositions<VS>(
return ColorSourceContents::DrawGeometry<VS>(
renderer, entity, pass, pipeline_callback, frame_info,
[this, &renderer](RenderPass& pass) {
FS::FragInfo frag_info;
Expand Down Expand Up @@ -128,7 +128,7 @@ bool ConicalGradientContents::RenderTexture(const ContentContext& renderer,
[&renderer](ContentContextOptions options) {
return renderer.GetConicalGradientFillPipeline(options);
};
return ColorSourceContents::DrawPositions<VS>(
return ColorSourceContents::DrawGeometry<VS>(
renderer, entity, pass, pipeline_callback, frame_info,
[this, &renderer, &gradient_texture](RenderPass& pass) {
FS::FragInfo frag_info;
Expand Down
14 changes: 8 additions & 6 deletions impeller/entity/contents/content_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -480,23 +480,25 @@ fml::StatusOr<RenderTarget> ContentContext::MakeSubpass(
ISize texture_size,
const SubpassCallback& subpass_callback,
bool msaa_enabled,
bool depth_stencil_enabled,
int32_t mip_count) const {
const std::shared_ptr<Context>& context = GetContext();
RenderTarget subpass_target;

std::optional<RenderTarget::AttachmentConfig> depth_stencil_config =
depth_stencil_enabled ? RenderTarget::kDefaultStencilAttachmentConfig
: std::optional<RenderTarget::AttachmentConfig>();

if (context->GetCapabilities()->SupportsOffscreenMSAA() && msaa_enabled) {
subpass_target = RenderTarget::CreateOffscreenMSAA(
*context, *GetRenderTargetCache(), texture_size,
/*mip_count=*/mip_count, SPrintF("%s Offscreen", label.c_str()),
RenderTarget::kDefaultColorAttachmentConfigMSAA,
std::nullopt // stencil_attachment_config
);
RenderTarget::kDefaultColorAttachmentConfigMSAA, depth_stencil_config);
} else {
subpass_target = RenderTarget::CreateOffscreen(
*context, *GetRenderTargetCache(), texture_size,
/*mip_count=*/mip_count, SPrintF("%s Offscreen", label.c_str()),
RenderTarget::kDefaultColorAttachmentConfig, //
std::nullopt // stencil_attachment_config
);
RenderTarget::kDefaultColorAttachmentConfig, depth_stencil_config);
}
return MakeSubpass(label, subpass_target, subpass_callback);
}
Expand Down
1 change: 1 addition & 0 deletions impeller/entity/contents/content_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,7 @@ class ContentContext {
ISize texture_size,
const SubpassCallback& subpass_callback,
bool msaa_enabled = true,
bool depth_stencil_enabled = false,
int32_t mip_count = 1) const;

/// Makes a subpass that will render to `subpass_target`.
Expand Down
2 changes: 1 addition & 1 deletion impeller/entity/contents/contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ std::optional<Snapshot> Contents::RenderToSnapshot(
entity.GetTransform());
return contents.Render(renderer, sub_entity, pass);
},
msaa_enabled,
msaa_enabled, /*depth_stencil_enabled=*/true,
std::min(mip_count, static_cast<int32_t>(subpass_size.MipCount())));

if (!render_target.ok()) {
Expand Down
4 changes: 2 additions & 2 deletions impeller/entity/contents/linear_gradient_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ bool LinearGradientContents::RenderTexture(const ContentContext& renderer,
[&renderer](ContentContextOptions options) {
return renderer.GetLinearGradientFillPipeline(options);
};
return ColorSourceContents::DrawPositions<VS>(
return ColorSourceContents::DrawGeometry<VS>(
renderer, entity, pass, pipeline_callback, frame_info,
[this, &renderer](RenderPass& pass) {
auto gradient_data = CreateGradientBuffer(colors_, stops_);
Expand Down Expand Up @@ -126,7 +126,7 @@ bool LinearGradientContents::RenderSSBO(const ContentContext& renderer,
[&renderer](ContentContextOptions options) {
return renderer.GetLinearGradientSSBOFillPipeline(options);
};
return ColorSourceContents::DrawPositions<VS>(
return ColorSourceContents::DrawGeometry<VS>(
renderer, entity, pass, pipeline_callback, frame_info,
[this, &renderer](RenderPass& pass) {
FS::FragInfo frag_info;
Expand Down
4 changes: 2 additions & 2 deletions impeller/entity/contents/radial_gradient_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ bool RadialGradientContents::RenderSSBO(const ContentContext& renderer,
[&renderer](ContentContextOptions options) {
return renderer.GetRadialGradientSSBOFillPipeline(options);
};
return ColorSourceContents::DrawPositions<VS>(
return ColorSourceContents::DrawGeometry<VS>(
renderer, entity, pass, pipeline_callback, frame_info,
[this, &renderer](RenderPass& pass) {
FS::FragInfo frag_info;
Expand Down Expand Up @@ -127,7 +127,7 @@ bool RadialGradientContents::RenderTexture(const ContentContext& renderer,
[&renderer](ContentContextOptions options) {
return renderer.GetRadialGradientFillPipeline(options);
};
return ColorSourceContents::DrawPositions<VS>(
return ColorSourceContents::DrawGeometry<VS>(
renderer, entity, pass, pipeline_callback, frame_info,
[this, &renderer, &gradient_texture](RenderPass& pass) {
FS::FragInfo frag_info;
Expand Down
8 changes: 5 additions & 3 deletions impeller/entity/contents/runtime_effect_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer,
BindFragmentCallback bind_callback = [this, &renderer, &context,
&descriptor_set_layouts](
RenderPass& pass) {
descriptor_set_layouts.clear();

size_t minimum_sampler_index = 100000000;
size_t buffer_index = 0;
size_t buffer_offset = 0;
Expand Down Expand Up @@ -313,9 +315,9 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer,
runtime_stage_->GetEntrypoint(), options, create_callback);
};

return ColorSourceContents::DrawPositions<VS>(renderer, entity, pass,
pipeline_callback,
VS::FrameInfo{}, bind_callback);
return ColorSourceContents::DrawGeometry<VS>(renderer, entity, pass,
pipeline_callback,
VS::FrameInfo{}, bind_callback);
}

} // namespace impeller
2 changes: 1 addition & 1 deletion impeller/entity/contents/solid_color_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ bool SolidColorContents::Render(const ContentContext& renderer,
[&renderer](ContentContextOptions options) {
return renderer.GetSolidFillPipeline(options);
};
return ColorSourceContents::DrawPositions<VS>(
return ColorSourceContents::DrawGeometry<VS>(
renderer, entity, pass, pipeline_callback, frame_info,
[](RenderPass& pass) {
pass.SetCommandLabel("Solid Fill");
Expand Down
4 changes: 2 additions & 2 deletions impeller/entity/contents/sweep_gradient_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ bool SweepGradientContents::RenderSSBO(const ContentContext& renderer,
[&renderer](ContentContextOptions options) {
return renderer.GetSweepGradientSSBOFillPipeline(options);
};
return ColorSourceContents::DrawPositions<VS>(
return ColorSourceContents::DrawGeometry<VS>(
renderer, entity, pass, pipeline_callback, frame_info,
[this, &renderer](RenderPass& pass) {
FS::FragInfo frag_info;
Expand Down Expand Up @@ -134,7 +134,7 @@ bool SweepGradientContents::RenderTexture(const ContentContext& renderer,
[&renderer](ContentContextOptions options) {
return renderer.GetSweepGradientFillPipeline(options);
};
return ColorSourceContents::DrawPositions<VS>(
return ColorSourceContents::DrawGeometry<VS>(
renderer, entity, pass, pipeline_callback, frame_info,
[this, &renderer, &gradient_texture](RenderPass& pass) {
FS::FragInfo frag_info;
Expand Down
Loading