@@ -28,10 +28,33 @@ namespace impeller {
2828std::shared_ptr<FilterContents> FilterContents::MakeBlend (
2929 Entity::BlendMode blend_mode,
3030 InputTextures input_textures) {
31- auto blend = std::make_shared<BlendFilterContents>();
32- blend->SetInputTextures (input_textures);
33- blend->SetBlendMode (blend_mode);
34- return blend;
31+ if (blend_mode > Entity::BlendMode::kLastAdvancedBlendMode ) {
32+ VALIDATION_LOG << " Invalid blend mode " << static_cast <int >(blend_mode)
33+ << " passed to FilterContents::MakeBlend." ;
34+ return nullptr ;
35+ }
36+
37+ if (input_textures.size () < 2 ||
38+ blend_mode <= Entity::BlendMode::kLastPipelineBlendMode ) {
39+ auto blend = std::make_shared<BlendFilterContents>();
40+ blend->SetInputTextures (input_textures);
41+ blend->SetBlendMode (blend_mode);
42+ return blend;
43+ }
44+
45+ if (blend_mode <= Entity::BlendMode::kLastAdvancedBlendMode ) {
46+ InputVariant blend = input_textures[0 ];
47+ for (auto in_i = input_textures.begin () + 1 ; in_i < input_textures.end ();
48+ in_i++) {
49+ auto new_blend = std::make_shared<BlendFilterContents>();
50+ new_blend->SetInputTextures ({blend, *in_i});
51+ new_blend->SetBlendMode (blend_mode);
52+ blend = new_blend;
53+ }
54+ return std::get<std::shared_ptr<FilterContents>>(blend);
55+ }
56+
57+ FML_UNREACHABLE ();
3558}
3659
3760FilterContents::FilterContents () = default ;
@@ -150,20 +173,106 @@ ISize FilterContents::GetOutputSize() const {
150173 ******* BlendFilterContents
151174 ******************************************************************************/
152175
153- BlendFilterContents::BlendFilterContents () = default ;
176+ BlendFilterContents::BlendFilterContents () {
177+ SetBlendMode (Entity::BlendMode::kSourceOver );
178+ }
154179
155180BlendFilterContents::~BlendFilterContents () = default ;
156181
182+ using PipelineProc =
183+ std::shared_ptr<Pipeline> (ContentContext::*)(ContentContextOptions) const ;
184+
185+ template <typename VS, typename FS>
186+ static void AdvancedBlendPass (std::shared_ptr<Texture> input_d,
187+ std::shared_ptr<Texture> input_s,
188+ std::shared_ptr<const Sampler> sampler,
189+ const ContentContext& renderer,
190+ RenderPass& pass,
191+ Command& cmd) {}
192+
193+ template <typename VS, typename FS>
194+ static bool AdvancedBlend (
195+ const std::vector<std::shared_ptr<Texture>>& input_textures,
196+ const ContentContext& renderer,
197+ RenderPass& pass,
198+ PipelineProc pipeline_proc) {
199+ if (input_textures.size () < 2 ) {
200+ return false ;
201+ }
202+
203+ auto & host_buffer = pass.GetTransientsBuffer ();
204+
205+ VertexBufferBuilder<typename VS::PerVertexData> vtx_builder;
206+ vtx_builder.AddVertices ({
207+ {Point (0 , 0 ), Point (0 , 0 )},
208+ {Point (1 , 0 ), Point (1 , 0 )},
209+ {Point (1 , 1 ), Point (1 , 1 )},
210+ {Point (0 , 0 ), Point (0 , 0 )},
211+ {Point (1 , 1 ), Point (1 , 1 )},
212+ {Point (0 , 1 ), Point (0 , 1 )},
213+ });
214+ auto vtx_buffer = vtx_builder.CreateVertexBuffer (host_buffer);
215+
216+ typename VS::FrameInfo frame_info;
217+ frame_info.mvp = Matrix::MakeOrthographic (ISize (1 , 1 ));
218+
219+ auto uniform_view = host_buffer.EmplaceUniform (frame_info);
220+ auto sampler = renderer.GetContext ()->GetSamplerLibrary ()->GetSampler ({});
221+
222+ auto options = OptionsFromPass (pass);
223+ options.blend_mode = Entity::BlendMode::kSource ;
224+ std::shared_ptr<Pipeline> pipeline =
225+ std::invoke (pipeline_proc, renderer, options);
226+
227+ Command cmd;
228+ cmd.label = " Advanced Blend Filter" ;
229+ cmd.BindVertices (vtx_buffer);
230+ cmd.pipeline = std::move (pipeline);
231+ VS::BindFrameInfo (cmd, uniform_view);
232+
233+ FS::BindTextureSamplerDst (cmd, input_textures[0 ], sampler);
234+ FS::BindTextureSamplerSrc (cmd, input_textures[1 ], sampler);
235+ pass.AddCommand (cmd);
236+
237+ return true ;
238+ }
239+
157240void BlendFilterContents::SetBlendMode (Entity::BlendMode blend_mode) {
241+ if (blend_mode > Entity::BlendMode::kLastAdvancedBlendMode ) {
242+ VALIDATION_LOG << " Invalid blend mode " << static_cast <int >(blend_mode)
243+ << " assigned to BlendFilterContents." ;
244+ }
245+
158246 blend_mode_ = blend_mode;
247+
248+ if (blend_mode > Entity::BlendMode::kLastPipelineBlendMode ) {
249+ static_assert (Entity::BlendMode::kLastAdvancedBlendMode ==
250+ Entity::BlendMode::kScreen );
251+
252+ switch (blend_mode) {
253+ case Entity::BlendMode::kScreen :
254+ advanced_blend_proc_ =
255+ [](const std::vector<std::shared_ptr<Texture>>& input_textures,
256+ const ContentContext& renderer, RenderPass& pass) {
257+ PipelineProc p = &ContentContext::GetTextureBlendScreenPipeline;
258+ return AdvancedBlend<TextureBlendScreenPipeline::VertexShader,
259+ TextureBlendScreenPipeline::FragmentShader>(
260+ input_textures, renderer, pass, p);
261+ };
262+ break ;
263+ default :
264+ FML_UNREACHABLE ();
265+ }
266+ }
159267}
160268
161- bool BlendFilterContents::RenderFilter (
269+ static bool BasicBlend (
162270 const std::vector<std::shared_ptr<Texture>>& input_textures,
163271 const ContentContext& renderer,
164- RenderPass& pass) const {
165- using VS = TexturePipeline::VertexShader;
166- using FS = TexturePipeline::FragmentShader;
272+ RenderPass& pass,
273+ Entity::BlendMode basic_blend) {
274+ using VS = TextureBlendPipeline::VertexShader;
275+ using FS = TextureBlendPipeline::FragmentShader;
167276
168277 auto & host_buffer = pass.GetTransientsBuffer ();
169278
@@ -180,24 +289,63 @@ bool BlendFilterContents::RenderFilter(
180289
181290 VS::FrameInfo frame_info;
182291 frame_info.mvp = Matrix::MakeOrthographic (ISize (1 , 1 ));
183- frame_info.alpha = 1 ;
184292
185293 auto uniform_view = host_buffer.EmplaceUniform (frame_info);
186294 auto sampler = renderer.GetContext ()->GetSamplerLibrary ()->GetSampler ({});
187295
296+ // Draw the first texture using kSource.
297+
188298 Command cmd;
189- cmd.label = " Blend Filter" ;
190- auto options = OptionsFromPass (pass);
191- options.blend_mode = blend_mode_;
192- cmd.pipeline = renderer.GetTexturePipeline (options);
299+ cmd.label = " Basic Blend Filter" ;
193300 cmd.BindVertices (vtx_buffer);
301+ auto options = OptionsFromPass (pass);
302+ options.blend_mode = Entity::BlendMode::kSource ;
303+ cmd.pipeline = renderer.GetTextureBlendPipeline (options);
304+ FS::BindTextureSamplerSrc (cmd, input_textures[0 ], sampler);
194305 VS::BindFrameInfo (cmd, uniform_view);
195- for (const auto & texture : input_textures) {
196- FS::BindTextureSampler (cmd, texture, sampler);
306+ pass.AddCommand (cmd);
307+
308+ if (input_textures.size () < 2 ) {
309+ return true ;
310+ }
311+
312+ // Write subsequent textures using the selected blend mode.
313+
314+ options.blend_mode = basic_blend;
315+ cmd.pipeline = renderer.GetTextureBlendPipeline (options);
316+
317+ for (auto texture_i = input_textures.begin () + 1 ;
318+ texture_i < input_textures.end (); texture_i++) {
319+ FS::BindTextureSamplerSrc (cmd, *texture_i, sampler);
197320 pass.AddCommand (cmd);
198321 }
199322
200323 return true ;
201324}
202325
326+ bool BlendFilterContents::RenderFilter (
327+ const std::vector<std::shared_ptr<Texture>>& input_textures,
328+ const ContentContext& renderer,
329+ RenderPass& pass) const {
330+ if (input_textures.empty ()) {
331+ return true ;
332+ }
333+
334+ if (input_textures.size () == 1 ) {
335+ // Nothing to blend.
336+ return BasicBlend (input_textures, renderer, pass,
337+ Entity::BlendMode::kSource );
338+ }
339+
340+ if (blend_mode_ <= Entity::BlendMode::kLastPipelineBlendMode ) {
341+ return BasicBlend (input_textures, renderer, pass, blend_mode_);
342+ }
343+
344+ if (blend_mode_ <= Entity::BlendMode::kLastAdvancedBlendMode ) {
345+ return advanced_blend_proc_ (input_textures, renderer, pass);
346+ }
347+
348+ FML_UNREACHABLE ();
349+ }
350+
203351} // namespace impeller
0 commit comments