33// found in the LICENSE file.
44
55#include < optional>
6+ #include < unordered_map>
67#include < utility>
78
9+ #include " flutter/fml/macros.h"
10+
811#include " impeller/entity/contents/atlas_contents.h"
912#include " impeller/entity/contents/content_context.h"
1013#include " impeller/entity/contents/filters/color_filter_contents.h"
1922#include " impeller/renderer/sampler_library.h"
2023#include " impeller/renderer/vertex_buffer_builder.h"
2124
25+ #ifdef FML_OS_PHYSICAL_IOS
26+ #include " impeller/entity/contents/framebuffer_blend_contents.h"
27+ #endif
28+
2229namespace impeller {
2330
2431AtlasContents::AtlasContents () = default ;
@@ -59,6 +66,87 @@ void AtlasContents::SetCullRect(std::optional<Rect> cull_rect) {
5966 cull_rect_ = cull_rect;
6067}
6168
69+ struct AtlasBlenderKey {
70+ Color color;
71+ Rect rect;
72+ uint32_t color_key;
73+
74+ struct Hash {
75+ std::size_t operator ()(const AtlasBlenderKey& key) const {
76+ return fml::HashCombine (key.color_key , key.rect .size .width ,
77+ key.rect .size .height , key.rect .origin .x ,
78+ key.rect .origin .y );
79+ }
80+ };
81+
82+ struct Equal {
83+ bool operator ()(const AtlasBlenderKey& lhs,
84+ const AtlasBlenderKey& rhs) const {
85+ return lhs.rect == rhs.rect && lhs.color_key == rhs.color_key ;
86+ }
87+ };
88+ };
89+
90+ std::shared_ptr<SubAtlasResult> AtlasContents::GenerateSubAtlas () const {
91+ FML_DCHECK (colors_.size () > 0 && blend_mode_ != BlendMode::kSource &&
92+ blend_mode_ != BlendMode::kDestination );
93+
94+ std::unordered_map<AtlasBlenderKey, std::vector<Matrix>,
95+ AtlasBlenderKey::Hash, AtlasBlenderKey::Equal>
96+ sub_atlas = {};
97+
98+ for (auto i = 0u ; i < texture_coords_.size (); i++) {
99+ AtlasBlenderKey key = {.color = colors_[i],
100+ .rect = texture_coords_[i],
101+ .color_key = Color::ToIColor (colors_[i])};
102+ if (sub_atlas.find (key) == sub_atlas.end ()) {
103+ sub_atlas[key] = {transforms_[i]};
104+ } else {
105+ sub_atlas[key].push_back (transforms_[i]);
106+ }
107+ }
108+
109+ auto result = std::make_shared<SubAtlasResult>();
110+ Scalar x_offset = 0.0 ;
111+ Scalar y_offset = 0.0 ;
112+ Scalar x_extent = 0.0 ;
113+ Scalar y_extent = 0.0 ;
114+
115+ for (auto it = sub_atlas.begin (); it != sub_atlas.end (); it++) {
116+ // This size was arbitrarily chosen to keep the textures from getting too
117+ // wide. We could instead use a more generic rect packer but in the majority
118+ // of cases the sample rects will be fairly close in size making this a good
119+ // enough approximation.
120+ if (x_offset >= 1000 ) {
121+ y_offset = y_extent + 1 ;
122+ x_offset = 0.0 ;
123+ }
124+
125+ auto key = it->first ;
126+ auto transforms = it->second ;
127+
128+ auto new_rect = Rect::MakeXYWH (x_offset, y_offset, key.rect .size .width ,
129+ key.rect .size .height );
130+ auto sub_transform = Matrix::MakeTranslation (Vector2 (x_offset, y_offset));
131+
132+ x_offset += std::ceil (key.rect .size .width ) + 1.0 ;
133+
134+ result->sub_texture_coords .push_back (key.rect );
135+ result->sub_colors .push_back (key.color );
136+ result->sub_transforms .push_back (sub_transform);
137+
138+ x_extent = std::max (x_extent, x_offset);
139+ y_extent = std::max (y_extent, std::ceil (y_offset + key.rect .size .height ));
140+
141+ for (auto transform : transforms) {
142+ result->result_texture_coords .push_back (new_rect);
143+ result->result_transforms .push_back (transform);
144+ }
145+ }
146+ result->size = ISize (std::ceil (x_extent), std::ceil (y_extent));
147+ return result;
148+ }
149+
62150std::optional<Rect> AtlasContents::GetCoverage (const Entity& entity) const {
63151 if (cull_rect_.has_value ()) {
64152 return cull_rect_.value ().TransformBounds (entity.GetTransformation ());
@@ -125,17 +213,56 @@ bool AtlasContents::Render(const ContentContext& renderer,
125213 return child_contents.Render (renderer, entity, pass);
126214 }
127215
216+ auto sub_atlas = GenerateSubAtlas ();
217+ auto sub_coverage = Rect::MakeSize (sub_atlas->size );
218+
128219 auto src_contents = std::make_shared<AtlasTextureContents>(*this );
129- src_contents->SetCoverage (coverage);
220+ src_contents->SetSubAtlas (sub_atlas);
221+ src_contents->SetCoverage (sub_coverage);
130222
131223 auto dst_contents = std::make_shared<AtlasColorContents>(*this );
132- dst_contents->SetCoverage (coverage);
133-
224+ dst_contents->SetSubAtlas (sub_atlas);
225+ dst_contents->SetCoverage (sub_coverage);
226+
227+ #ifdef FML_OS_PHYSICAL_IOS
228+ auto new_texture = renderer.MakeSubpass (
229+ sub_atlas->size , [&](const ContentContext& context, RenderPass& pass) {
230+ Entity entity;
231+ entity.SetContents (dst_contents);
232+ entity.SetBlendMode (BlendMode::kSource );
233+ if (!entity.Render (context, pass)) {
234+ return false ;
235+ }
236+ if (blend_mode_ >= Entity::kLastPipelineBlendMode ) {
237+ auto contents = std::make_shared<FramebufferBlendContents>();
238+ contents->SetBlendMode (blend_mode_);
239+ contents->SetChildContents (src_contents);
240+ entity.SetContents (std::move (contents));
241+ entity.SetBlendMode (BlendMode::kSource );
242+ return entity.Render (context, pass);
243+ }
244+ entity.SetContents (src_contents);
245+ entity.SetBlendMode (blend_mode_);
246+ return entity.Render (context, pass);
247+ });
248+ #else
134249 auto contents = ColorFilterContents::MakeBlend (
135250 blend_mode_,
136251 {FilterInput::Make (dst_contents), FilterInput::Make (src_contents)});
137- contents->SetAlpha (alpha_);
138- return contents->Render (renderer, entity, pass);
252+ auto snapshot = contents->RenderToSnapshot (renderer, entity);
253+ if (!snapshot.has_value ()) {
254+ return false ;
255+ }
256+ auto new_texture = snapshot.value ().texture ;
257+ #endif
258+
259+ auto child_contents = AtlasTextureContents (*this );
260+ child_contents.SetAlpha (alpha_);
261+ child_contents.SetCoverage (coverage);
262+ child_contents.SetTexture (new_texture);
263+ child_contents.SetUseDestination (true );
264+ child_contents.SetSubAtlas (sub_atlas);
265+ return child_contents.Render (renderer, entity, pass);
139266}
140267
141268// AtlasTextureContents
@@ -159,15 +286,38 @@ void AtlasTextureContents::SetCoverage(Rect coverage) {
159286 coverage_ = coverage;
160287}
161288
289+ void AtlasTextureContents::SetUseDestination (bool value) {
290+ use_destination_ = value;
291+ }
292+
293+ void AtlasTextureContents::SetSubAtlas (
294+ const std::shared_ptr<SubAtlasResult>& subatlas) {
295+ subatlas_ = subatlas;
296+ }
297+
298+ void AtlasTextureContents::SetTexture (std::shared_ptr<Texture> texture) {
299+ texture_ = std::move (texture);
300+ }
301+
162302bool AtlasTextureContents::Render (const ContentContext& renderer,
163303 const Entity& entity,
164304 RenderPass& pass) const {
165305 using VS = TextureFillVertexShader;
166306 using FS = TextureFillFragmentShader;
167307
168- auto texture = parent_.GetTexture ();
169- auto texture_coords = parent_.GetTextureCoordinates ();
170- auto transforms = parent_.GetTransforms ();
308+ auto texture = texture_.value_or (parent_.GetTexture ());
309+ std::vector<Rect> texture_coords;
310+ std::vector<Matrix> transforms;
311+ if (subatlas_.has_value ()) {
312+ auto subatlas = subatlas_.value ();
313+ texture_coords = use_destination_ ? subatlas->result_texture_coords
314+ : subatlas->sub_texture_coords ;
315+ transforms = use_destination_ ? subatlas->result_transforms
316+ : subatlas->sub_transforms ;
317+ } else {
318+ texture_coords = parent_.GetTextureCoordinates ();
319+ transforms = parent_.GetTransforms ();
320+ }
171321
172322 const Size texture_size (texture->GetSize ());
173323 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
@@ -242,15 +392,30 @@ void AtlasColorContents::SetCoverage(Rect coverage) {
242392 coverage_ = coverage;
243393}
244394
395+ void AtlasColorContents::SetSubAtlas (
396+ const std::shared_ptr<SubAtlasResult>& subatlas) {
397+ subatlas_ = subatlas;
398+ }
399+
245400bool AtlasColorContents::Render (const ContentContext& renderer,
246401 const Entity& entity,
247402 RenderPass& pass) const {
248403 using VS = GeometryColorPipeline::VertexShader;
249404 using FS = GeometryColorPipeline::FragmentShader;
250405
251- auto texture_coords = parent_.GetTextureCoordinates ();
252- auto transforms = parent_.GetTransforms ();
253- auto colors = parent_.GetColors ();
406+ std::vector<Rect> texture_coords;
407+ std::vector<Matrix> transforms;
408+ std::vector<Color> colors;
409+ if (subatlas_.has_value ()) {
410+ auto subatlas = subatlas_.value ();
411+ texture_coords = subatlas->sub_texture_coords ;
412+ colors = subatlas->sub_colors ;
413+ transforms = subatlas->sub_transforms ;
414+ } else {
415+ texture_coords = parent_.GetTextureCoordinates ();
416+ transforms = parent_.GetTransforms ();
417+ colors = parent_.GetColors ();
418+ }
254419
255420 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
256421 vertex_builder.Reserve (texture_coords.size () * 6 );
0 commit comments