Flutter Engine
 
Loading...
Searching...
No Matches
runtime_effect_filter_contents.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <cstring>
8#include <optional>
9
15
16namespace impeller {
17
19 std::shared_ptr<RuntimeStage> runtime_stage) {
20 runtime_stage_ = std::move(runtime_stage);
21}
22
24 std::shared_ptr<std::vector<uint8_t>> uniforms) {
25 uniforms_ = std::move(uniforms);
26}
27
29 std::vector<RuntimeEffectContents::TextureInput> texture_inputs) {
30 texture_inputs_ = std::move(texture_inputs);
31}
32
33// |FilterContents|
34std::optional<Entity> RuntimeEffectFilterContents::RenderFilter(
35 const FilterInput::Vector& inputs,
36 const ContentContext& renderer,
37 const Entity& entity,
38 const Matrix& effect_transform,
39 const Rect& coverage,
40 const std::optional<Rect>& coverage_hint) const {
41 if (inputs.empty()) {
42 return std::nullopt;
43 }
44
45 std::optional<Snapshot> input_snapshot =
46 inputs[0]->GetSnapshot("RuntimeEffectContents", renderer, entity);
47 if (!input_snapshot.has_value()) {
48 return std::nullopt;
49 }
50
51 std::optional<Rect> maybe_input_coverage = input_snapshot->GetCoverage();
52 if (!maybe_input_coverage.has_value()) {
53 return std::nullopt;
54 }
55
56 // If the input snapshot does not have an identity transform the
57 // ImageFilter.shader will not correctly render as it does not know what the
58 // transform is in order to incorporate this into sampling. We need to
59 // re-rasterize the input snapshot so that the transform is absorbed into the
60 // texture.
61 // We can technically render this only when the snapshot is just a translated
62 // version of the original. Unfortunately there isn't a way to test for that
63 // though. Blur with low sigmas will return a transform that doesn't scale but
64 // has a tiny offset to account for the blur radius. That's indistinguishable
65 // from `ImageFilter.compose` which slightly increase the size to account for
66 // rounding errors and add an offset. Said another way; ideally we would skip
67 // this branch for the unit test `ComposePaintRuntimeOuter`, but do it for
68 // `ComposeBackdropRuntimeOuterBlurInner`.
69 if (!input_snapshot->transform.IsIdentity()) {
70 Matrix inverse = input_snapshot->transform.Invert();
71 Quad quad = inverse.Transform(Quad{
72 coverage.GetLeftTop(), //
73 coverage.GetRightTop(), //
74 coverage.GetLeftBottom(), //
75 coverage.GetRightBottom() //
76 });
77 TextureContents texture_contents;
78 texture_contents.SetTexture(input_snapshot->texture);
79 std::optional<Rect> bounds =
80 Rect::MakePointBounds(quad.begin(), quad.end());
81 if (bounds.has_value()) {
82 texture_contents.SetSourceRect(bounds.value());
83 texture_contents.SetDestinationRect(coverage);
84 texture_contents.SetStencilEnabled(false);
85 texture_contents.SetSamplerDescriptor(input_snapshot->sampler_descriptor);
86
87 Entity entity;
88 // In order to maintain precise coordinates in the fragment shader we need
89 // to eliminate the padding typically given to RenderToSnapshot results.
90 input_snapshot = texture_contents.RenderToSnapshot(
91 renderer, entity, {.coverage_expansion = 0});
92 if (!input_snapshot.has_value()) {
93 return std::nullopt;
94 }
95 }
96 }
97
98 // The shader is required to have at least one sampler, the first of
99 // which is treated as the input and a vec2 size uniform to compute the
100 // offsets. These are validated at the dart:ui layer, but to avoid crashes we
101 // check here too.
102 if (texture_inputs_.size() < 1 || uniforms_->size() < 8) {
104 << "Invalid fragment shader in RuntimeEffectFilterContents. "
105 << "Shader must have at least one sampler and a vec2 size uniform.";
106 return std::nullopt;
107 }
108
109 // Update uniform values.
110 std::vector<RuntimeEffectContents::TextureInput> texture_input_copy =
111 texture_inputs_;
112 texture_input_copy[0].texture = input_snapshot->texture;
113
114 Size size = Size(input_snapshot->texture->GetSize());
115 memcpy(uniforms_->data(), &size, sizeof(Size));
116
117 Matrix snapshot_transform = input_snapshot->transform;
118 //----------------------------------------------------------------------------
119 /// Create AnonymousContents for rendering.
120 ///
121 RenderProc render_proc =
122 [snapshot_transform, input_snapshot, runtime_stage = runtime_stage_,
123 uniforms = uniforms_, texture_inputs = texture_input_copy](
124 const ContentContext& renderer, const Entity& entity,
125 RenderPass& pass) -> bool {
126 RuntimeEffectContents contents;
127 FillRectGeometry geom(Rect::MakeSize(input_snapshot->texture->GetSize()));
128 contents.SetRuntimeStage(runtime_stage);
129 contents.SetUniformData(uniforms);
130 contents.SetTextureInputs(texture_inputs);
131 contents.SetGeometry(&geom);
132 Entity offset_entity = entity.Clone();
133 offset_entity.SetTransform(entity.GetTransform() * snapshot_transform);
134 return contents.Render(renderer, offset_entity, pass);
135 };
136
137 CoverageProc coverage_proc =
138 [coverage](const Entity& entity) -> std::optional<Rect> {
139 return coverage;
140 };
141
142 auto contents = AnonymousContents::Make(render_proc, coverage_proc);
143
144 Entity sub_entity;
145 sub_entity.SetContents(std::move(contents));
146 sub_entity.SetBlendMode(entity.GetBlendMode());
147 sub_entity.SetTransform(input_snapshot->transform *
148 snapshot_transform.Invert());
149
150 return sub_entity;
151}
152
153// |FilterContents|
154std::optional<Rect> RuntimeEffectFilterContents::GetFilterSourceCoverage(
155 const Matrix& effect_transform,
156 const Rect& output_limit) const {
157 return output_limit;
158}
159
160} // namespace impeller
static std::shared_ptr< Contents > Make(RenderProc render_proc, CoverageProc coverage_proc)
std::function< std::optional< Rect >(const Entity &entity)> CoverageProc
Definition contents.h:40
std::function< bool(const ContentContext &renderer, const Entity &entity, RenderPass &pass)> RenderProc
Definition contents.h:39
std::vector< FilterInput::Ref > Vector
void SetUniforms(std::shared_ptr< std::vector< uint8_t > > uniforms)
void SetTextureInputs(std::vector< RuntimeEffectContents::TextureInput > texture_inputs)
void SetRuntimeStage(std::shared_ptr< RuntimeStage > runtime_stage)
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
TRect< Scalar > Rect
Definition rect.h:788
TSize< Scalar > Size
Definition size.h:159
std::array< Point, 4 > Quad
Definition point.h:332
A 4x4 matrix using column-major storage.
Definition matrix.h:37
constexpr TPoint< T > GetLeftTop() const
Definition rect.h:359
constexpr TPoint< T > GetRightBottom() const
Definition rect.h:371
constexpr TPoint< T > GetLeftBottom() const
Definition rect.h:367
static constexpr TRect MakeSize(const TSize< U > &size)
Definition rect.h:150
constexpr TPoint< T > GetRightTop() const
Definition rect.h:363
static constexpr std::optional< TRect > MakePointBounds(const U &value)
Definition rect.h:165
#define VALIDATION_LOG
Definition validation.h:91