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 ;
@@ -57,6 +64,85 @@ void AtlasContents::SetCullRect(std::optional<Rect> cull_rect) {
5764 cull_rect_ = cull_rect;
5865}
5966
67+ struct AtlasBlenderKey {
68+ Color color;
69+ Rect rect;
70+
71+ struct Hash {
72+ std::size_t operator ()(const AtlasBlenderKey& key) const {
73+ return fml::HashCombine (key.color .red , key.color .green , key.color .blue ,
74+ key.color .alpha , key.rect .size .width ,
75+ key.rect .size .height , key.rect .origin .x ,
76+ key.rect .origin .y );
77+ }
78+ };
79+
80+ struct Equal {
81+ bool operator ()(const AtlasBlenderKey& lhs,
82+ const AtlasBlenderKey& rhs) const {
83+ return lhs.rect == rhs.rect && lhs.color == rhs.color ;
84+ }
85+ };
86+ };
87+
88+ std::shared_ptr<SubAtlasResult> AtlasContents::GenerateSubAtlas () const {
89+ FML_DCHECK (colors_.size () > 0 && blend_mode_ != BlendMode::kSource &&
90+ blend_mode_ != BlendMode::kDestination );
91+
92+ std::unordered_map<AtlasBlenderKey, std::vector<Matrix>,
93+ AtlasBlenderKey::Hash, AtlasBlenderKey::Equal>
94+ sub_atlas = {};
95+
96+ for (auto i = 0u ; i < texture_coords_.size (); i++) {
97+ AtlasBlenderKey key = {.color = colors_[i], .rect = texture_coords_[i]};
98+ if (sub_atlas.find (key) == sub_atlas.end ()) {
99+ sub_atlas[key] = {transforms_[i]};
100+ } else {
101+ sub_atlas[key].push_back (transforms_[i]);
102+ }
103+ }
104+
105+ auto result = std::make_shared<SubAtlasResult>();
106+ Scalar x_offset = 0.0 ;
107+ Scalar y_offset = 0.0 ;
108+ Scalar x_extent = 0.0 ;
109+ Scalar y_extent = 0.0 ;
110+
111+ for (auto it = sub_atlas.begin (); it != sub_atlas.end (); it++) {
112+ // This size was arbitrarily chosen to keep the textures from getting too
113+ // wide. We could instead use a more generic rect packer but in the majority
114+ // of cases the sample rects will be fairly close in size making this a good
115+ // enough approximation.
116+ if (x_offset >= 1000 ) {
117+ y_offset = y_extent + 1 ;
118+ x_offset = 0.0 ;
119+ }
120+
121+ auto key = it->first ;
122+ auto transforms = it->second ;
123+
124+ auto new_rect = Rect::MakeXYWH (x_offset, y_offset, key.rect .size .width ,
125+ key.rect .size .height );
126+ auto sub_transform = Matrix::MakeTranslation (Vector2 (x_offset, y_offset));
127+
128+ x_offset += (key.rect .size .width + 1.0 );
129+
130+ result->sub_texture_coords .push_back (key.rect );
131+ result->sub_colors .push_back (key.color );
132+ result->sub_transforms .push_back (sub_transform);
133+
134+ x_extent = std::max (x_extent, x_offset);
135+ y_extent = std::max (y_extent, y_offset + key.rect .size .height );
136+
137+ for (auto transform : transforms) {
138+ result->result_texture_coords .push_back (new_rect);
139+ result->result_transforms .push_back (transform);
140+ }
141+ }
142+ result->size = ISize (std::ceil (x_extent), std::ceil (y_extent));
143+ return result;
144+ }
145+
60146std::optional<Rect> AtlasContents::GetCoverage (const Entity& entity) const {
61147 if (cull_rect_.has_value ()) {
62148 return cull_rect_.value ().TransformBounds (entity.GetTransformation ());
@@ -120,17 +206,56 @@ bool AtlasContents::Render(const ContentContext& renderer,
120206 return child_contents.Render (renderer, entity, pass);
121207 }
122208
209+ auto sub_atlas = GenerateSubAtlas ();
210+ auto sub_coverage = Rect::MakeSize (sub_atlas->size );
211+
123212 auto src_contents = std::make_shared<AtlasTextureContents>(*this );
124- src_contents->SetCoverage (coverage);
213+ src_contents->SetSubAtlas (sub_atlas);
214+ src_contents->SetCoverage (sub_coverage);
125215
126216 auto dst_contents = std::make_shared<AtlasColorContents>(*this );
127- dst_contents->SetCoverage (coverage);
128-
217+ dst_contents->SetSubAtlas (sub_atlas);
218+ dst_contents->SetCoverage (sub_coverage);
219+
220+ #ifdef FML_OS_PHYSICAL_IOS
221+ auto new_texture = renderer.MakeSubpass (
222+ sub_atlas->size , [&](const ContentContext& context, RenderPass& pass) {
223+ Entity entity;
224+ entity.SetContents (dst_contents);
225+ entity.SetBlendMode (BlendMode::kSource );
226+ if (!entity.Render (context, pass)) {
227+ return false ;
228+ }
229+ if (blend_mode_ >= Entity::kLastPipelineBlendMode ) {
230+ auto contents = std::make_shared<FramebufferBlendContents>();
231+ contents->SetBlendMode (blend_mode_);
232+ contents->SetChildContents (src_contents);
233+ entity.SetContents (std::move (contents));
234+ entity.SetBlendMode (BlendMode::kSource );
235+ return entity.Render (context, pass);
236+ }
237+ entity.SetContents (src_contents);
238+ entity.SetBlendMode (blend_mode_);
239+ return entity.Render (context, pass);
240+ });
241+ #else
129242 auto contents = ColorFilterContents::MakeBlend (
130243 blend_mode_,
131244 {FilterInput::Make (dst_contents), FilterInput::Make (src_contents)});
132- contents->SetAlpha (alpha_);
133- return contents->Render (renderer, entity, pass);
245+ auto snapshot = contents->RenderToSnapshot (renderer, entity);
246+ if (!snapshot.has_value ()) {
247+ return false ;
248+ }
249+ auto new_texture = snapshot.value ().texture ;
250+ #endif
251+
252+ auto child_contents = AtlasTextureContents (*this );
253+ child_contents.SetAlpha (alpha_);
254+ child_contents.SetCoverage (coverage);
255+ child_contents.SetTexture (new_texture);
256+ child_contents.SetUseDestination (true );
257+ child_contents.SetSubAtlas (sub_atlas);
258+ return child_contents.Render (renderer, entity, pass);
134259}
135260
136261// AtlasTextureContents
@@ -154,15 +279,38 @@ void AtlasTextureContents::SetCoverage(Rect coverage) {
154279 coverage_ = coverage;
155280}
156281
282+ void AtlasTextureContents::SetUseDestination (bool value) {
283+ use_destination_ = value;
284+ }
285+
286+ void AtlasTextureContents::SetSubAtlas (
287+ const std::shared_ptr<SubAtlasResult>& subatlas) {
288+ subatlas_ = subatlas;
289+ }
290+
291+ void AtlasTextureContents::SetTexture (std::shared_ptr<Texture> texture) {
292+ texture_ = std::move (texture);
293+ }
294+
157295bool AtlasTextureContents::Render (const ContentContext& renderer,
158296 const Entity& entity,
159297 RenderPass& pass) const {
160298 using VS = TextureFillVertexShader;
161299 using FS = TextureFillFragmentShader;
162300
163- auto texture = parent_.GetTexture ();
164- auto texture_coords = parent_.GetTextureCoordinates ();
165- auto transforms = parent_.GetTransforms ();
301+ auto texture = texture_.value_or (parent_.GetTexture ());
302+ std::vector<Rect> texture_coords;
303+ std::vector<Matrix> transforms;
304+ if (subatlas_.has_value ()) {
305+ auto subatlas = subatlas_.value ();
306+ texture_coords = use_destination_ ? subatlas->result_texture_coords
307+ : subatlas->sub_texture_coords ;
308+ transforms = use_destination_ ? subatlas->result_transforms
309+ : subatlas->sub_transforms ;
310+ } else {
311+ texture_coords = parent_.GetTextureCoordinates ();
312+ transforms = parent_.GetTransforms ();
313+ }
166314
167315 const auto texture_size = texture->GetSize ();
168316 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
@@ -237,15 +385,30 @@ void AtlasColorContents::SetCoverage(Rect coverage) {
237385 coverage_ = coverage;
238386}
239387
388+ void AtlasColorContents::SetSubAtlas (
389+ const std::shared_ptr<SubAtlasResult>& subatlas) {
390+ subatlas_ = subatlas;
391+ }
392+
240393bool AtlasColorContents::Render (const ContentContext& renderer,
241394 const Entity& entity,
242395 RenderPass& pass) const {
243396 using VS = GeometryColorPipeline::VertexShader;
244397 using FS = GeometryColorPipeline::FragmentShader;
245398
246- auto texture_coords = parent_.GetTextureCoordinates ();
247- auto transforms = parent_.GetTransforms ();
248- auto colors = parent_.GetColors ();
399+ std::vector<Rect> texture_coords;
400+ std::vector<Matrix> transforms;
401+ std::vector<Color> colors;
402+ if (subatlas_.has_value ()) {
403+ auto subatlas = subatlas_.value ();
404+ texture_coords = subatlas->sub_texture_coords ;
405+ colors = subatlas->sub_colors ;
406+ transforms = subatlas->sub_transforms ;
407+ } else {
408+ texture_coords = parent_.GetTextureCoordinates ();
409+ transforms = parent_.GetTransforms ();
410+ colors = parent_.GetColors ();
411+ }
249412
250413 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
251414 vertex_builder.Reserve (texture_coords.size () * 6 );
0 commit comments