10 #include "impeller/entity/texture_fill.frag.h"
11 #include "impeller/entity/texture_fill.vert.h"
36 std::initializer_list<typename T::PerVertexData>&& vertices) {
69 fml::StatusOr<RenderTarget> MakeDownsampleSubpass(
71 std::shared_ptr<Texture> input_texture,
74 const ISize& subpass_size,
78 HostBuffer& host_buffer = pass.GetTransientsBuffer();
86 TextureFillVertexShader::FrameInfo frame_info;
88 frame_info.texture_sampler_y_coord_scale = 1.0;
89 frame_info.alpha = 1.0;
91 BindVertices<TextureFillVertexShader>(cmd, host_buffer,
93 {
Point(0, 0), uvs[0]},
94 {
Point(1, 0), uvs[1]},
95 {
Point(0, 1), uvs[2]},
96 {
Point(1, 1), uvs[3]},
100 SetTileMode(&linear_sampler_descriptor, renderer, tile_mode);
103 TextureFillVertexShader::BindFrameInfo(
105 TextureFillFragmentShader::BindTextureSampler(
107 renderer.
GetContext()->GetSamplerLibrary()->GetSampler(
108 linear_sampler_descriptor));
110 pass.AddCommand(std::move(cmd));
114 fml::StatusOr<RenderTarget> render_target = renderer.
MakeSubpass(
115 "Gaussian Blur Filter", subpass_size, subpass_callback);
116 return render_target;
119 fml::StatusOr<RenderTarget> MakeBlurSubpass(
125 std::optional<RenderTarget> destination_target,
126 const Quad& blur_uvs) {
135 ISize subpass_size = input_texture->GetSize();
138 GaussianBlurVertexShader::FrameInfo frame_info{
140 .texture_sampler_y_coord_scale = 1.0};
142 HostBuffer& host_buffer = pass.GetTransientsBuffer();
156 BindVertices<GaussianBlurVertexShader>(cmd, host_buffer,
158 {blur_uvs[0], blur_uvs[0]},
159 {blur_uvs[1], blur_uvs[1]},
160 {blur_uvs[2], blur_uvs[2]},
161 {blur_uvs[3], blur_uvs[3]},
167 GaussianBlurFragmentShader::BindTextureSampler(
169 renderer.
GetContext()->GetSamplerLibrary()->GetSampler(
170 linear_sampler_descriptor));
171 GaussianBlurVertexShader::BindFrameInfo(
173 GaussianBlurFragmentShader::BindKernelSamples(
175 pass.AddCommand(std::move(cmd));
179 if (destination_target.has_value()) {
180 return renderer.
MakeSubpass(
"Gaussian Blur Filter",
181 destination_target.value(), subpass_callback);
183 return renderer.
MakeSubpass(
"Gaussian Blur Filter", subpass_size,
190 Rect MakeReferenceUVs(
const Rect& reference,
const Rect& rect) {
202 : sigma_x_(sigma_x), sigma_y_(sigma_y), tile_mode_(tile_mode) {}
215 const Matrix& effect_transform,
216 const Rect& output_limit)
const {
221 effect_transform.
Basis() *
Vector3{blur_radius.
x, blur_radius.
y, 0.0};
222 return output_limit.
Expand(
Point(blur_radii.
x, blur_radii.
y));
228 const Matrix& effect_transform)
const {
229 if (inputs.empty()) {
233 std::optional<Rect> input_coverage = inputs[0]->GetCoverage(entity);
234 if (!input_coverage.has_value()) {
242 (inputs[0]->GetTransform(entity).Basis() * effect_transform.
Basis() *
243 Vector3{blur_radius.
x, blur_radius.
y, 0.0})
245 return input_coverage.value().Expand(
Point(blur_radii.
x, blur_radii.
y));
248 std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
252 const Matrix& effect_transform,
253 const Rect& coverage,
254 const std::optional<Rect>& coverage_hint)
const {
255 if (inputs.empty()) {
262 Vector2 padding(ceil(blur_radius.x), ceil(blur_radius.y));
270 std::optional<Rect> expanded_coverage_hint;
271 if (coverage_hint.has_value()) {
272 expanded_coverage_hint = coverage_hint->Expand(local_padding);
275 std::optional<Snapshot> input_snapshot =
276 inputs[0]->GetSnapshot(
"GaussianBlur", renderer, entity,
277 expanded_coverage_hint);
278 if (!input_snapshot.has_value()) {
292 Vector2 downsample_scalar(desired_scalar, desired_scalar);
294 Rect source_rect_padded = source_rect.
Expand(padding);
304 Vector2 downsampled_size = source_rect_padded.GetSize() * downsample_scalar;
306 ISize(round(downsampled_size.x), round(downsampled_size.y));
308 Vector2(subpass_size) / source_rect_padded.GetSize();
311 input_snapshot->texture->GetSize());
313 fml::StatusOr<RenderTarget> pass1_out = MakeDownsampleSubpass(
314 renderer, input_snapshot->texture, input_snapshot->sampler_descriptor,
315 uvs, subpass_size, tile_mode_);
317 if (!pass1_out.ok()) {
322 1.0 /
Vector2(pass1_out.value().GetRenderTargetTexture()->GetSize());
324 std::optional<Rect> input_snapshot_coverage = input_snapshot->GetCoverage();
326 if (expanded_coverage_hint.has_value() &&
327 input_snapshot_coverage.has_value() &&
332 input_snapshot.has_value() &&
333 input_snapshot.value().transform.IsTranslationScaleOnly()) {
335 std::optional<Rect> uvs = MakeReferenceUVs(input_snapshot_coverage.value(),
336 expanded_coverage_hint.value())
338 FML_DCHECK(uvs.has_value());
339 if (uvs.has_value()) {
340 blur_uvs[0] = uvs->GetLeftTop();
341 blur_uvs[1] = uvs->GetRightTop();
342 blur_uvs[2] = uvs->GetLeftBottom();
343 blur_uvs[3] = uvs->GetRightBottom();
347 fml::StatusOr<RenderTarget> pass2_out = MakeBlurSubpass(
348 renderer, pass1_out.value(),
349 input_snapshot->sampler_descriptor, tile_mode_,
351 .blur_uv_offset = Point(0.0, pass1_pixel_size.y),
352 .blur_sigma = scaled_sigma.y * effective_scalar.y,
354 static_cast<int>(std::round(blur_radius.y * effective_scalar.y)),
357 std::nullopt, blur_uvs);
359 if (!pass2_out.ok()) {
364 auto pass3_destination = pass2_out.value().GetRenderTargetTexture() !=
365 pass1_out.value().GetRenderTargetTexture()
366 ? std::optional<RenderTarget>(pass1_out.value())
367 :
std::optional<RenderTarget>(
std::nullopt);
369 fml::StatusOr<RenderTarget> pass3_out = MakeBlurSubpass(
370 renderer, pass2_out.value(),
371 input_snapshot->sampler_descriptor, tile_mode_,
373 .blur_uv_offset = Point(pass1_pixel_size.x, 0.0),
374 .blur_sigma = scaled_sigma.x * effective_scalar.x,
376 static_cast<int>(std::round(blur_radius.x * effective_scalar.x)),
379 pass3_destination, blur_uvs);
381 if (!pass3_out.ok()) {
387 FML_DCHECK((pass1_out.value().GetRenderTargetSize() ==
388 pass2_out.value().GetRenderTargetSize()) &&
389 (pass2_out.value().GetRenderTargetSize() ==
390 pass3_out.value().GetRenderTargetSize()));
392 SamplerDescriptor sampler_desc = MakeSamplerDescriptor(
396 Snapshot{.texture = pass3_out.value().GetRenderTargetTexture(),
397 .transform = input_snapshot->transform *
398 padding_snapshot_adjustment *
400 .sampler_descriptor = sampler_desc,
401 .opacity = input_snapshot->opacity},
410 const std::shared_ptr<FilterInput>& filter_input,
412 const Rect& source_rect,
413 const ISize& texture_size) {
414 Matrix input_transform = filter_input->GetLocalTransform(entity);
418 {1.0f / texture_size.
width, 1.0f / texture_size.
height, 1.0f});
419 return uv_transform.
Transform(coverage_quad);
427 Scalar clamped = std::min(sigma, 500.0f);
428 constexpr
Scalar a = 3.4e-06;
429 constexpr
Scalar b = -3.4e-3;
431 Scalar scalar = c + b * clamped + a * clamped * clamped;
432 return clamped * scalar;
437 KernelPipeline::FragmentShader::KernelSamples result;
438 result.sample_count =
440 FML_CHECK(result.sample_count < 24);
443 for (
int i = 0; i < result.sample_count; ++i) {
445 result.samples[i] = KernelPipeline::FragmentShader::KernelSample{
447 .coefficient = expf(-0.5f * (x * x) /
451 tally += result.samples[i].coefficient;
455 for (
auto& sample : result.samples) {
456 sample.coefficient /= tally;