Skip to content

Commit 2b78480

Browse files
chinmaygardednfield
authored andcommitted
Allow for the on-demand creation and caching of pipeline variants from the prototype.
1 parent 30f28f1 commit 2b78480

File tree

5 files changed

+110
-62
lines changed

5 files changed

+110
-62
lines changed

impeller/aiks/aiks_unittests.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ TEST_F(AiksTest, CanRenderGroupOpacity) {
127127

128128
canvas.Restore();
129129

130-
// ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
130+
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
131131
}
132132

133133
TEST_F(AiksTest, CanPerformFullScreenMSAA) {
@@ -138,7 +138,7 @@ TEST_F(AiksTest, CanPerformFullScreenMSAA) {
138138

139139
canvas.DrawCircle({250, 250}, 125, red);
140140

141-
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
141+
// ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
142142
}
143143

144144
} // namespace testing

impeller/entity/content_renderer.cc

Lines changed: 8 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ ContentRenderer::ContentRenderer(std::shared_ptr<Context> context)
1313
}
1414

1515
// Pipelines whose default descriptors work fine for the entity framework.
16-
gradient_fill_pipeline_ = std::make_unique<GradientFillPipeline>(*context_);
17-
solid_fill_pipeline_ = std::make_unique<SolidFillPipeline>(*context_);
18-
texture_pipeline_ = std::make_unique<TexturePipeline>(*context_);
19-
solid_stroke_pipeline_ = std::make_unique<SolidStrokePipeline>(*context_);
16+
gradient_fill_pipelines_[{}] =
17+
std::make_unique<GradientFillPipeline>(*context_);
18+
solid_fill_pipelines_[{}] = std::make_unique<SolidFillPipeline>(*context_);
19+
texture_pipelines_[{}] = std::make_unique<TexturePipeline>(*context_);
20+
solid_stroke_pipelines_[{}] =
21+
std::make_unique<SolidStrokePipeline>(*context_);
2022

2123
// Pipelines that are variants of the base pipelines with custom descriptors.
22-
if (auto solid_fill_pipeline = solid_fill_pipeline_->WaitAndGet()) {
24+
if (auto solid_fill_pipeline = solid_fill_pipelines_[{}]->WaitAndGet()) {
2325
auto clip_pipeline_descriptor = solid_fill_pipeline->GetDescriptor();
2426
// Write to the stencil buffer.
2527
StencilAttachmentDescriptor stencil0;
@@ -35,7 +37,7 @@ ContentRenderer::ContentRenderer(std::shared_ptr<Context> context)
3537
}
3638
clip_pipeline_descriptor.SetColorAttachmentDescriptors(
3739
std::move(color_attachments));
38-
clip_pipeline_ = std::make_unique<ClipPipeline>(
40+
clip_pipelines_[{}] = std::make_unique<ClipPipeline>(
3941
*context_, std::move(clip_pipeline_descriptor));
4042
} else {
4143
return;
@@ -54,43 +56,4 @@ std::shared_ptr<Context> ContentRenderer::GetContext() const {
5456
return context_;
5557
}
5658

57-
std::shared_ptr<Pipeline> ContentRenderer::GetGradientFillPipeline() const {
58-
if (!IsValid()) {
59-
return nullptr;
60-
}
61-
return gradient_fill_pipeline_->WaitAndGet();
62-
}
63-
64-
std::shared_ptr<Pipeline> ContentRenderer::GetSolidFillPipeline() const {
65-
if (!IsValid()) {
66-
return nullptr;
67-
}
68-
69-
return solid_fill_pipeline_->WaitAndGet();
70-
}
71-
72-
std::shared_ptr<Pipeline> ContentRenderer::GetTexturePipeline() const {
73-
if (!IsValid()) {
74-
return nullptr;
75-
}
76-
77-
return texture_pipeline_->WaitAndGet();
78-
}
79-
80-
std::shared_ptr<Pipeline> ContentRenderer::GetSolidStrokePipeline() const {
81-
if (!IsValid()) {
82-
return nullptr;
83-
}
84-
85-
return solid_stroke_pipeline_->WaitAndGet();
86-
}
87-
88-
std::shared_ptr<Pipeline> ContentRenderer::GetClipPipeline() const {
89-
if (!IsValid()) {
90-
return nullptr;
91-
}
92-
93-
return clip_pipeline_->WaitAndGet();
94-
}
95-
9659
} // namespace impeller

impeller/entity/content_renderer.h

Lines changed: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
#pragma once
66

77
#include <memory>
8+
#include <unordered_map>
89

10+
#include "flutter/fml/hash_combine.h"
911
#include "flutter/fml/macros.h"
1012
#include "flutter/impeller/entity/gradient_fill.frag.h"
1113
#include "flutter/impeller/entity/gradient_fill.vert.h"
@@ -33,31 +35,99 @@ using ClipPipeline = PipelineT<SolidFillVertexShader, SolidFillFragmentShader>;
3335

3436
class ContentRenderer {
3537
public:
38+
struct Options {
39+
SampleCount sample_count = SampleCount::kCount1;
40+
41+
Options() {}
42+
43+
struct Hash {
44+
constexpr std::size_t operator()(const Options& o) const {
45+
return fml::HashCombine(o.sample_count);
46+
}
47+
};
48+
49+
struct Equal {
50+
constexpr bool operator()(const Options& lhs, const Options& rhs) const {
51+
return lhs.sample_count == rhs.sample_count;
52+
}
53+
};
54+
};
55+
3656
ContentRenderer(std::shared_ptr<Context> context);
3757

3858
~ContentRenderer();
3959

4060
bool IsValid() const;
4161

42-
std::shared_ptr<Pipeline> GetGradientFillPipeline() const;
62+
std::shared_ptr<Pipeline> GetGradientFillPipeline(Options opts) const {
63+
return GetPipeline(gradient_fill_pipelines_, opts);
64+
}
4365

44-
std::shared_ptr<Pipeline> GetSolidFillPipeline() const;
66+
std::shared_ptr<Pipeline> GetSolidFillPipeline(Options opts) const {
67+
return GetPipeline(solid_fill_pipelines_, opts);
68+
}
4569

46-
std::shared_ptr<Pipeline> GetTexturePipeline() const;
70+
std::shared_ptr<Pipeline> GetTexturePipeline(Options opts) const {
71+
return GetPipeline(texture_pipelines_, opts);
72+
}
4773

48-
std::shared_ptr<Pipeline> GetSolidStrokePipeline() const;
74+
std::shared_ptr<Pipeline> GetSolidStrokePipeline(Options opts) const {
75+
return GetPipeline(solid_stroke_pipelines_, opts);
76+
}
4977

50-
std::shared_ptr<Pipeline> GetClipPipeline() const;
78+
std::shared_ptr<Pipeline> GetClipPipeline(Options opts) const {
79+
return GetPipeline(clip_pipelines_, opts);
80+
}
5181

5282
std::shared_ptr<Context> GetContext() const;
5383

5484
private:
5585
std::shared_ptr<Context> context_;
56-
std::unique_ptr<GradientFillPipeline> gradient_fill_pipeline_;
57-
std::unique_ptr<SolidFillPipeline> solid_fill_pipeline_;
58-
std::unique_ptr<TexturePipeline> texture_pipeline_;
59-
std::unique_ptr<SolidStrokePipeline> solid_stroke_pipeline_;
60-
std::unique_ptr<ClipPipeline> clip_pipeline_;
86+
87+
template <class T>
88+
using Variants = std::
89+
unordered_map<Options, std::unique_ptr<T>, Options::Hash, Options::Equal>;
90+
91+
// These are mutable because while the prototypes are created eagerly, any
92+
// variants requested from that are lazily created and cached in the variants
93+
// map.
94+
mutable Variants<GradientFillPipeline> gradient_fill_pipelines_;
95+
mutable Variants<SolidFillPipeline> solid_fill_pipelines_;
96+
mutable Variants<TexturePipeline> texture_pipelines_;
97+
mutable Variants<SolidStrokePipeline> solid_stroke_pipelines_;
98+
mutable Variants<ClipPipeline> clip_pipelines_;
99+
100+
static void ApplyOptionsToDescriptor(PipelineDescriptor& desc,
101+
const Options& options) {
102+
desc.SetSampleCount(options.sample_count);
103+
}
104+
105+
template <class TypedPipeline>
106+
std::shared_ptr<Pipeline> GetPipeline(Variants<TypedPipeline>& container,
107+
Options opts) const {
108+
if (!IsValid()) {
109+
return nullptr;
110+
}
111+
112+
if (auto found = container.find(opts); found != container.end()) {
113+
return found->second->WaitAndGet();
114+
}
115+
116+
auto found = container.find({});
117+
118+
// The prototype must always be initialized in the constructor.
119+
FML_CHECK(found != container.end());
120+
121+
auto variant_future = found->second->WaitAndGet()->CreateVariant(
122+
[&opts](PipelineDescriptor& desc) {
123+
ApplyOptionsToDescriptor(desc, opts);
124+
});
125+
auto variant = std::make_unique<TypedPipeline>(std::move(variant_future));
126+
auto variant_pipeline = variant->WaitAndGet();
127+
container[opts] = std::move(variant);
128+
return variant_pipeline;
129+
}
130+
61131
bool is_valid_ = false;
62132

63133
FML_DISALLOW_COPY_AND_ASSIGN(ContentRenderer);

impeller/entity/contents.cc

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919

2020
namespace impeller {
2121

22+
static ContentRenderer::Options OptionsFromPass(const RenderPass& pass) {
23+
ContentRenderer::Options opts;
24+
opts.sample_count = pass.GetRenderTarget().GetSampleCount();
25+
return opts;
26+
}
27+
2228
/*******************************************************************************
2329
******* Contents
2430
******************************************************************************/
@@ -85,7 +91,7 @@ bool LinearGradientContents::Render(const ContentRenderer& renderer,
8591

8692
Command cmd;
8793
cmd.label = "LinearGradientFill";
88-
cmd.pipeline = renderer.GetGradientFillPipeline();
94+
cmd.pipeline = renderer.GetGradientFillPipeline(OptionsFromPass(pass));
8995
cmd.stencil_reference = entity.GetStencilDepth();
9096
cmd.BindVertices(
9197
vertices_builder.CreateVertexBuffer(pass.GetTransientsBuffer()));
@@ -142,7 +148,7 @@ bool SolidColorContents::Render(const ContentRenderer& renderer,
142148

143149
Command cmd;
144150
cmd.label = "SolidFill";
145-
cmd.pipeline = renderer.GetSolidFillPipeline();
151+
cmd.pipeline = renderer.GetSolidFillPipeline(OptionsFromPass(pass));
146152
cmd.stencil_reference = entity.GetStencilDepth();
147153
cmd.BindVertices(
148154
CreateSolidFillVertices(entity.GetPath(), pass.GetTransientsBuffer()));
@@ -241,7 +247,7 @@ bool TextureContents::Render(const ContentRenderer& renderer,
241247

242248
Command cmd;
243249
cmd.label = "TextureFill";
244-
cmd.pipeline = renderer.GetTexturePipeline();
250+
cmd.pipeline = renderer.GetTexturePipeline(OptionsFromPass(pass));
245251
cmd.stencil_reference = entity.GetStencilDepth();
246252
cmd.BindVertices(vertex_builder.CreateVertexBuffer(host_buffer));
247253
VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info));
@@ -336,7 +342,7 @@ bool SolidStrokeContents::Render(const ContentRenderer& renderer,
336342
Command cmd;
337343
cmd.primitive_type = PrimitiveType::kTriangleStrip;
338344
cmd.label = "SolidStroke";
339-
cmd.pipeline = renderer.GetSolidStrokePipeline();
345+
cmd.pipeline = renderer.GetSolidStrokePipeline(OptionsFromPass(pass));
340346
cmd.stencil_reference = entity.GetStencilDepth();
341347
cmd.BindVertices(
342348
CreateSolidStrokeVertices(entity.GetPath(), pass.GetTransientsBuffer()));
@@ -372,7 +378,7 @@ bool ClipContents::Render(const ContentRenderer& renderer,
372378

373379
Command cmd;
374380
cmd.label = "Clip";
375-
cmd.pipeline = renderer.GetClipPipeline();
381+
cmd.pipeline = renderer.GetClipPipeline(OptionsFromPass(pass));
376382
cmd.stencil_reference = entity.GetStencilDepth() + 1u;
377383
cmd.BindVertices(
378384
CreateSolidFillVertices(entity.GetPath(), pass.GetTransientsBuffer()));

impeller/renderer/pipeline.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ namespace impeller {
1515
class PipelineLibrary;
1616
class Pipeline;
1717

18+
// TODO(csg): Using a simple future is sub-optimal since callers that want to
19+
// eagerly create and cache pipeline variants will have to await on the future
20+
// to get its pipeline descriptor (unless they have explicitly cached it). This
21+
// would be a concurrency pessimization.
22+
//
23+
// Use a struct that stores the future and the descriptor separately.
1824
using PipelineFuture = std::future<std::shared_ptr<Pipeline>>;
1925

2026
//------------------------------------------------------------------------------
@@ -76,6 +82,9 @@ class PipelineT {
7682
std::optional<PipelineDescriptor> desc)
7783
: pipeline_future_(CreatePipelineFuture(context, desc)) {}
7884

85+
explicit PipelineT(PipelineFuture future)
86+
: pipeline_future_(std::move(future)) {}
87+
7988
std::shared_ptr<Pipeline> WaitAndGet() {
8089
if (did_wait_) {
8190
return pipeline_;

0 commit comments

Comments
 (0)