|
4 | 4 |
|
5 | 5 | #include "filter_contents.h"
|
6 | 6 |
|
| 7 | +#include <algorithm> |
| 8 | +#include <cmath> |
7 | 9 | #include <memory>
|
8 | 10 | #include <optional>
|
9 | 11 | #include <variant>
|
|
16 | 18 | #include "impeller/entity/entity.h"
|
17 | 19 | #include "impeller/geometry/path_builder.h"
|
18 | 20 | #include "impeller/renderer/command_buffer.h"
|
| 21 | +#include "impeller/renderer/formats.h" |
19 | 22 | #include "impeller/renderer/render_pass.h"
|
| 23 | +#include "impeller/renderer/sampler_descriptor.h" |
20 | 24 | #include "impeller/renderer/sampler_library.h"
|
21 | 25 |
|
22 | 26 | namespace impeller {
|
@@ -57,6 +61,28 @@ std::shared_ptr<FilterContents> FilterContents::MakeBlend(
|
57 | 61 | FML_UNREACHABLE();
|
58 | 62 | }
|
59 | 63 |
|
| 64 | +std::shared_ptr<FilterContents> FilterContents::MakeDirectionalGaussianBlur( |
| 65 | + InputVariant input_texture, |
| 66 | + Scalar radius, |
| 67 | + Vector2 direction, |
| 68 | + bool clip_border) { |
| 69 | + auto blur = std::make_shared<DirectionalGaussianBlurFilterContents>(); |
| 70 | + blur->SetInputTextures({input_texture}); |
| 71 | + blur->SetRadius(radius); |
| 72 | + blur->SetDirection(direction); |
| 73 | + blur->SetClipBorder(clip_border); |
| 74 | + return blur; |
| 75 | +} |
| 76 | + |
| 77 | +std::shared_ptr<FilterContents> FilterContents::MakeGaussianBlur( |
| 78 | + InputVariant input_texture, |
| 79 | + Scalar radius, |
| 80 | + bool clip_border) { |
| 81 | + auto x_blur = MakeDirectionalGaussianBlur(input_texture, radius, Point(1, 0), |
| 82 | + clip_border); |
| 83 | + return MakeDirectionalGaussianBlur(x_blur, radius, Point(0, 1), false); |
| 84 | +} |
| 85 | + |
60 | 86 | FilterContents::FilterContents() = default;
|
61 | 87 |
|
62 | 88 | FilterContents::~FilterContents() = default;
|
@@ -90,7 +116,7 @@ std::optional<std::shared_ptr<Texture>> FilterContents::RenderFilterToTexture(
|
90 | 116 | const ContentContext& renderer,
|
91 | 117 | const Entity& entity,
|
92 | 118 | RenderPass& pass) const {
|
93 |
| - auto output_size = GetOutputSize(); |
| 119 | + auto output_size = GetOutputSize(input_textures_); |
94 | 120 | if (output_size.IsZero()) {
|
95 | 121 | return std::nullopt;
|
96 | 122 | }
|
@@ -155,14 +181,17 @@ ISize FilterContents::GetOutputSize() const {
|
155 | 181 | if (input_textures_.empty()) {
|
156 | 182 | return {};
|
157 | 183 | }
|
| 184 | + return GetOutputSize(input_textures_); |
| 185 | +} |
158 | 186 |
|
| 187 | +ISize FilterContents::GetOutputSize(const InputTextures& input_textures) const { |
159 | 188 | if (auto filter =
|
160 |
| - std::get_if<std::shared_ptr<FilterContents>>(&input_textures_[0])) { |
161 |
| - return filter->get()->GetOutputSize(); |
| 189 | + std::get_if<std::shared_ptr<FilterContents>>(&input_textures[0])) { |
| 190 | + return filter->get()->GetOutputSize(input_textures); |
162 | 191 | }
|
163 | 192 |
|
164 | 193 | if (auto texture =
|
165 |
| - std::get_if<std::shared_ptr<Texture>>(&input_textures_[0])) { |
| 194 | + std::get_if<std::shared_ptr<Texture>>(&input_textures[0])) { |
166 | 195 | return texture->get()->GetSize();
|
167 | 196 | }
|
168 | 197 |
|
@@ -348,4 +377,96 @@ bool BlendFilterContents::RenderFilter(
|
348 | 377 | FML_UNREACHABLE();
|
349 | 378 | }
|
350 | 379 |
|
| 380 | +/******************************************************************************* |
| 381 | + ******* DirectionalGaussianBlurFilterContents |
| 382 | + ******************************************************************************/ |
| 383 | + |
| 384 | +DirectionalGaussianBlurFilterContents::DirectionalGaussianBlurFilterContents() = |
| 385 | + default; |
| 386 | + |
| 387 | +DirectionalGaussianBlurFilterContents:: |
| 388 | + ~DirectionalGaussianBlurFilterContents() = default; |
| 389 | + |
| 390 | +void DirectionalGaussianBlurFilterContents::SetRadius(Scalar radius) { |
| 391 | + radius_ = std::max(radius, 1e-3f); |
| 392 | +} |
| 393 | + |
| 394 | +void DirectionalGaussianBlurFilterContents::SetDirection(Vector2 direction) { |
| 395 | + direction_ = direction.Normalize(); |
| 396 | +} |
| 397 | + |
| 398 | +void DirectionalGaussianBlurFilterContents::SetClipBorder(bool clip) { |
| 399 | + clip_ = clip; |
| 400 | +} |
| 401 | + |
| 402 | +bool DirectionalGaussianBlurFilterContents::RenderFilter( |
| 403 | + const std::vector<std::shared_ptr<Texture>>& input_textures, |
| 404 | + const ContentContext& renderer, |
| 405 | + RenderPass& pass) const { |
| 406 | + using VS = GaussianBlurPipeline::VertexShader; |
| 407 | + using FS = GaussianBlurPipeline::FragmentShader; |
| 408 | + |
| 409 | + auto& host_buffer = pass.GetTransientsBuffer(); |
| 410 | + |
| 411 | + ISize size = FilterContents::GetOutputSize(); |
| 412 | + Point uv_offset = clip_ ? (Point(radius_, radius_) / size) : Point(); |
| 413 | + // LTRB |
| 414 | + Scalar uv[4] = { |
| 415 | + -uv_offset.x, |
| 416 | + -uv_offset.y, |
| 417 | + 1 + uv_offset.x, |
| 418 | + 1 + uv_offset.y, |
| 419 | + }; |
| 420 | + |
| 421 | + VertexBufferBuilder<VS::PerVertexData> vtx_builder; |
| 422 | + vtx_builder.AddVertices({ |
| 423 | + {Point(0, 0), Point(uv[0], uv[1])}, |
| 424 | + {Point(size.width, 0), Point(uv[2], uv[1])}, |
| 425 | + {Point(size.width, size.height), Point(uv[2], uv[3])}, |
| 426 | + {Point(0, 0), Point(uv[0], uv[1])}, |
| 427 | + {Point(size.width, size.height), Point(uv[2], uv[3])}, |
| 428 | + {Point(0, size.height), Point(uv[0], uv[3])}, |
| 429 | + }); |
| 430 | + auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); |
| 431 | + |
| 432 | + VS::FrameInfo frame_info; |
| 433 | + frame_info.mvp = Matrix::MakeOrthographic(size); |
| 434 | + frame_info.texture_size = Point(size); |
| 435 | + frame_info.blur_radius = radius_; |
| 436 | + frame_info.blur_direction = direction_; |
| 437 | + |
| 438 | + auto uniform_view = host_buffer.EmplaceUniform(frame_info); |
| 439 | + auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({}); |
| 440 | + |
| 441 | + Command cmd; |
| 442 | + cmd.label = "Gaussian Blur Filter"; |
| 443 | + auto options = OptionsFromPass(pass); |
| 444 | + options.blend_mode = Entity::BlendMode::kSource; |
| 445 | + cmd.pipeline = renderer.GetGaussianBlurPipeline(options); |
| 446 | + cmd.BindVertices(vtx_buffer); |
| 447 | + VS::BindFrameInfo(cmd, uniform_view); |
| 448 | + for (const auto& texture : input_textures) { |
| 449 | + FS::BindTextureSampler(cmd, texture, sampler); |
| 450 | + pass.AddCommand(cmd); |
| 451 | + } |
| 452 | + |
| 453 | + return true; |
| 454 | +} |
| 455 | + |
| 456 | +ISize DirectionalGaussianBlurFilterContents::GetOutputSize( |
| 457 | + const InputTextures& input_textures) const { |
| 458 | + ISize size; |
| 459 | + if (auto filter = |
| 460 | + std::get_if<std::shared_ptr<FilterContents>>(&input_textures[0])) { |
| 461 | + size = filter->get()->GetOutputSize(); |
| 462 | + } else if (auto texture = |
| 463 | + std::get_if<std::shared_ptr<Texture>>(&input_textures[0])) { |
| 464 | + size = texture->get()->GetSize(); |
| 465 | + } else { |
| 466 | + FML_UNREACHABLE(); |
| 467 | + } |
| 468 | + |
| 469 | + return size + (clip_ ? ISize(radius_ * 2, radius_ * 2) : ISize()); |
| 470 | +} |
| 471 | + |
351 | 472 | } // namespace impeller
|
0 commit comments