|
5 | 5 | #pragma once
|
6 | 6 |
|
7 | 7 | #include <memory>
|
| 8 | +#include <unordered_map> |
8 | 9 |
|
| 10 | +#include "flutter/fml/hash_combine.h" |
9 | 11 | #include "flutter/fml/macros.h"
|
10 | 12 | #include "flutter/impeller/entity/gradient_fill.frag.h"
|
11 | 13 | #include "flutter/impeller/entity/gradient_fill.vert.h"
|
@@ -33,31 +35,99 @@ using ClipPipeline = PipelineT<SolidFillVertexShader, SolidFillFragmentShader>;
|
33 | 35 |
|
34 | 36 | class ContentRenderer {
|
35 | 37 | 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 | + |
36 | 56 | ContentRenderer(std::shared_ptr<Context> context);
|
37 | 57 |
|
38 | 58 | ~ContentRenderer();
|
39 | 59 |
|
40 | 60 | bool IsValid() const;
|
41 | 61 |
|
42 |
| - std::shared_ptr<Pipeline> GetGradientFillPipeline() const; |
| 62 | + std::shared_ptr<Pipeline> GetGradientFillPipeline(Options opts) const { |
| 63 | + return GetPipeline(gradient_fill_pipelines_, opts); |
| 64 | + } |
43 | 65 |
|
44 |
| - std::shared_ptr<Pipeline> GetSolidFillPipeline() const; |
| 66 | + std::shared_ptr<Pipeline> GetSolidFillPipeline(Options opts) const { |
| 67 | + return GetPipeline(solid_fill_pipelines_, opts); |
| 68 | + } |
45 | 69 |
|
46 |
| - std::shared_ptr<Pipeline> GetTexturePipeline() const; |
| 70 | + std::shared_ptr<Pipeline> GetTexturePipeline(Options opts) const { |
| 71 | + return GetPipeline(texture_pipelines_, opts); |
| 72 | + } |
47 | 73 |
|
48 |
| - std::shared_ptr<Pipeline> GetSolidStrokePipeline() const; |
| 74 | + std::shared_ptr<Pipeline> GetSolidStrokePipeline(Options opts) const { |
| 75 | + return GetPipeline(solid_stroke_pipelines_, opts); |
| 76 | + } |
49 | 77 |
|
50 |
| - std::shared_ptr<Pipeline> GetClipPipeline() const; |
| 78 | + std::shared_ptr<Pipeline> GetClipPipeline(Options opts) const { |
| 79 | + return GetPipeline(clip_pipelines_, opts); |
| 80 | + } |
51 | 81 |
|
52 | 82 | std::shared_ptr<Context> GetContext() const;
|
53 | 83 |
|
54 | 84 | private:
|
55 | 85 | 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 | + |
61 | 131 | bool is_valid_ = false;
|
62 | 132 |
|
63 | 133 | FML_DISALLOW_COPY_AND_ASSIGN(ContentRenderer);
|
|
0 commit comments