Reduces the compile size of Pipelines and ContentContext (#167671)

This reduces the size of ContentContext by introducing generic
superclass versions of `RenderPipelineHandle` and `Variants` which
allows the compiler to put most of the .text in the superclasses.

testing: no new functionality, refactor

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
gaaclarke 2025-04-28 10:56:03 -07:00 committed by GitHub
parent 2ca6284ce3
commit bee65f3a4f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 104 additions and 59 deletions

View File

@ -28,6 +28,56 @@ namespace impeller {
namespace {
/// A generic version of `Variants` which mostly exists to reduce code size.
class GenericVariants {
public:
void Set(const ContentContextOptions& options,
std::unique_ptr<GenericRenderPipelineHandle> pipeline) {
uint64_t p_key = options.ToKey();
for (const auto& [key, pipeline] : pipelines_) {
if (key == p_key) {
return;
}
}
pipelines_.push_back(std::make_pair(p_key, std::move(pipeline)));
}
void SetDefault(const ContentContextOptions& options,
std::unique_ptr<GenericRenderPipelineHandle> pipeline) {
default_options_ = options;
if (pipeline) {
Set(options, std::move(pipeline));
}
}
GenericRenderPipelineHandle* Get(const ContentContextOptions& options) const {
uint64_t p_key = options.ToKey();
for (const auto& [key, pipeline] : pipelines_) {
if (key == p_key) {
return pipeline.get();
}
}
return nullptr;
}
void SetDefaultDescriptor(std::optional<PipelineDescriptor> desc) {
desc_ = std::move(desc);
}
size_t GetPipelineCount() const { return pipelines_.size(); }
bool IsDefault(const ContentContextOptions& opts) {
return default_options_.has_value() &&
opts.ToKey() == default_options_.value().ToKey();
}
protected:
std::optional<PipelineDescriptor> desc_;
std::optional<ContentContextOptions> default_options_;
std::vector<std::pair<uint64_t, std::unique_ptr<GenericRenderPipelineHandle>>>
pipelines_;
};
/// Holds multiple Pipelines associated with the same PipelineHandle types.
///
/// For example, it may have multiple
@ -42,7 +92,7 @@ namespace {
/// - impeller::RenderPipelineHandle<> - The type of objects this typically
/// contains.
template <class PipelineHandleT>
class Variants {
class Variants : public GenericVariants {
static_assert(
ShaderStageCompatibilityChecker<
typename PipelineHandleT::VertexShader,
@ -55,32 +105,20 @@ class Variants {
void Set(const ContentContextOptions& options,
std::unique_ptr<PipelineHandleT> pipeline) {
uint64_t p_key = options.ToKey();
for (const auto& [key, pipeline] : pipelines_) {
if (key == p_key) {
return;
}
}
pipelines_.push_back(std::make_pair(p_key, std::move(pipeline)));
GenericVariants::Set(options, std::move(pipeline));
}
void SetDefault(const ContentContextOptions& options,
std::unique_ptr<PipelineHandleT> pipeline) {
default_options_ = options;
if (pipeline) {
Set(options, std::move(pipeline));
}
}
void SetDefaultDescriptor(std::optional<PipelineDescriptor> desc) {
desc_ = std::move(desc);
GenericVariants::SetDefault(options, std::move(pipeline));
}
void CreateDefault(const Context& context,
const ContentContextOptions& options,
const std::vector<Scalar>& constants = {}) {
auto desc = PipelineHandleT::Builder::MakeDefaultPipelineDescriptor(
context, constants);
std::optional<PipelineDescriptor> desc =
PipelineHandleT::Builder::MakeDefaultPipelineDescriptor(context,
constants);
if (!desc.has_value()) {
VALIDATION_LOG << "Failed to create default pipeline.";
return;
@ -96,18 +134,7 @@ class Variants {
}
PipelineHandleT* Get(const ContentContextOptions& options) const {
uint64_t p_key = options.ToKey();
for (const auto& [key, pipeline] : pipelines_) {
if (key == p_key) {
return pipeline.get();
}
}
return nullptr;
}
bool IsDefault(const ContentContextOptions& opts) {
return default_options_.has_value() &&
opts.ToKey() == default_options_.value().ToKey();
return static_cast<PipelineHandleT*>(GenericVariants::Get(options));
}
PipelineHandleT* GetDefault(const Context& context) {
@ -123,13 +150,7 @@ class Variants {
return Get(default_options_.value());
}
size_t GetPipelineCount() const { return pipelines_.size(); }
private:
std::optional<PipelineDescriptor> desc_;
std::optional<ContentContextOptions> default_options_;
std::vector<std::pair<uint64_t, std::unique_ptr<PipelineHandleT>>> pipelines_;
Variants(const Variants&) = delete;
Variants& operator=(const Variants&) = delete;

View File

@ -107,34 +107,24 @@ PipelineFuture<ComputePipelineDescriptor> CreatePipelineFuture(
const Context& context,
std::optional<ComputePipelineDescriptor> desc);
/// Holds a reference to a Pipeline used for rendering while also maintaining
/// the vertex shader and fragment shader types at compile-time.
/// Holds a reference to a Pipeline used for rendering.
///
/// See also:
/// - impeller::ContentContext::Variants - the typical container for
/// RenderPipelineHandles.
template <class VertexShader_, class FragmentShader_>
class RenderPipelineHandle {
/// @see RenderPipelineHandle the templated subclass that stores compile-time
/// shader information.
class GenericRenderPipelineHandle {
public:
using VertexShader = VertexShader_;
using FragmentShader = FragmentShader_;
using Builder = PipelineBuilder<VertexShader, FragmentShader>;
explicit GenericRenderPipelineHandle(const Context& context,
std::optional<PipelineDescriptor> desc,
bool async = true)
: GenericRenderPipelineHandle(
CreatePipelineFuture(context, std::move(desc), /*async=*/async)) {}
explicit RenderPipelineHandle(const Context& context, bool async = true)
: RenderPipelineHandle(CreatePipelineFuture(
context,
Builder::MakeDefaultPipelineDescriptor(context),
async)) {}
explicit RenderPipelineHandle(const Context& context,
std::optional<PipelineDescriptor> desc,
bool async = true)
: RenderPipelineHandle(
CreatePipelineFuture(context, desc, /*async=*/async)) {}
explicit RenderPipelineHandle(PipelineFuture<PipelineDescriptor> future)
explicit GenericRenderPipelineHandle(
PipelineFuture<PipelineDescriptor> future)
: pipeline_future_(std::move(future)) {}
virtual ~GenericRenderPipelineHandle() = default;
std::shared_ptr<Pipeline<PipelineDescriptor>> WaitAndGet() {
if (did_wait_) {
return pipeline_;
@ -155,6 +145,40 @@ class RenderPipelineHandle {
std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline_;
bool did_wait_ = false;
GenericRenderPipelineHandle(const GenericRenderPipelineHandle&) = delete;
GenericRenderPipelineHandle& operator=(const GenericRenderPipelineHandle&) =
delete;
};
/// Holds a reference to a Pipeline used for rendering while also maintaining
/// the vertex shader and fragment shader types at compile-time.
///
/// See also:
/// - impeller::ContentContext::Variants - the typical container for
/// RenderPipelineHandles.
template <class VertexShader_, class FragmentShader_>
class RenderPipelineHandle : public GenericRenderPipelineHandle {
public:
using VertexShader = VertexShader_;
using FragmentShader = FragmentShader_;
using Builder = PipelineBuilder<VertexShader, FragmentShader>;
explicit RenderPipelineHandle(const Context& context, bool async = true)
: GenericRenderPipelineHandle(CreatePipelineFuture(
context,
Builder::MakeDefaultPipelineDescriptor(context),
async)) {}
explicit RenderPipelineHandle(const Context& context,
std::optional<PipelineDescriptor> desc,
bool async = true)
: GenericRenderPipelineHandle(context, desc, async) {}
explicit RenderPipelineHandle(PipelineFuture<PipelineDescriptor> future)
: GenericRenderPipelineHandle(std::move(future)) {}
private:
RenderPipelineHandle(const RenderPipelineHandle&) = delete;
RenderPipelineHandle& operator=(const RenderPipelineHandle&) = delete;