@@ -28,10 +28,33 @@ namespace impeller {
28
28
std::shared_ptr<FilterContents> FilterContents::MakeBlend (
29
29
Entity::BlendMode blend_mode,
30
30
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 ();
35
58
}
36
59
37
60
FilterContents::FilterContents () = default ;
@@ -150,20 +173,106 @@ ISize FilterContents::GetOutputSize() const {
150
173
******* BlendFilterContents
151
174
******************************************************************************/
152
175
153
- BlendFilterContents::BlendFilterContents () = default ;
176
+ BlendFilterContents::BlendFilterContents () {
177
+ SetBlendMode (Entity::BlendMode::kSourceOver );
178
+ }
154
179
155
180
BlendFilterContents::~BlendFilterContents () = default ;
156
181
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
+
157
240
void 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
+
158
246
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
+ }
159
267
}
160
268
161
- bool BlendFilterContents::RenderFilter (
269
+ static bool BasicBlend (
162
270
const std::vector<std::shared_ptr<Texture>>& input_textures,
163
271
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;
167
276
168
277
auto & host_buffer = pass.GetTransientsBuffer ();
169
278
@@ -180,24 +289,63 @@ bool BlendFilterContents::RenderFilter(
180
289
181
290
VS::FrameInfo frame_info;
182
291
frame_info.mvp = Matrix::MakeOrthographic (ISize (1 , 1 ));
183
- frame_info.alpha = 1 ;
184
292
185
293
auto uniform_view = host_buffer.EmplaceUniform (frame_info);
186
294
auto sampler = renderer.GetContext ()->GetSamplerLibrary ()->GetSampler ({});
187
295
296
+ // Draw the first texture using kSource.
297
+
188
298
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" ;
193
300
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);
194
305
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);
197
320
pass.AddCommand (cmd);
198
321
}
199
322
200
323
return true ;
201
324
}
202
325
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
+
203
351
} // namespace impeller
0 commit comments