diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 360e4054a7fa1..fca4c2fda4006 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1337,7 +1337,9 @@ ORIGIN: ../../../flutter/impeller/entity/shaders/border_mask_blur.vert + ../../. ORIGIN: ../../../flutter/impeller/entity/shaders/color_matrix_color_filter.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/color_matrix_color_filter.vert + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur.frag + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur.glsl + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur.vert + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur_decal.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas.vert + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas_sdf.frag + ../../../flutter/LICENSE @@ -3813,7 +3815,9 @@ FILE: ../../../flutter/impeller/entity/shaders/border_mask_blur.vert FILE: ../../../flutter/impeller/entity/shaders/color_matrix_color_filter.frag FILE: ../../../flutter/impeller/entity/shaders/color_matrix_color_filter.vert FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur.frag +FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur.glsl FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur.vert +FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur_decal.frag FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.vert FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas_sdf.frag diff --git a/impeller/compiler/shader_lib/impeller/texture.glsl b/impeller/compiler/shader_lib/impeller/texture.glsl index d478a3a268cca..e91eaabb26962 100644 --- a/impeller/compiler/shader_lib/impeller/texture.glsl +++ b/impeller/compiler/shader_lib/impeller/texture.glsl @@ -19,6 +19,13 @@ vec4 IPSample(sampler2D texture_sampler, vec2 coords, float y_coord_scale) { return texture(texture_sampler, coords); } +vec2 IPRemapCoords(vec2 coords, float y_coord_scale) { + if (y_coord_scale < 0.0) { + coords.y = 1.0 - coords.y; + } + return coords; +} + /// Sample from a texture. /// /// If `y_coord_scale` < 0.0, the Y coordinate is flipped. This is useful @@ -119,6 +126,15 @@ vec4 IPSampleLinearWithTileMode(sampler2D tex, y_coord_scale, half_texel); } +/// Sample a texture with decal tile mode. +vec4 IPSampleDecal(sampler2D texture_sampler, vec2 coords) { + if (any(lessThan(coords, vec2(0))) || + any(greaterThanEqual(coords, vec2(1)))) { + return vec4(0); + } + return texture(texture_sampler, coords); +} + /// Sample a texture, emulating a specific tile mode. /// /// This is useful for Impeller graphics backend that don't have native support diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 261a89a0ac27c..a66ff8329e89a 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -31,6 +31,7 @@ impeller_shaders("entity_shaders") { "shaders/color_matrix_color_filter.frag", "shaders/color_matrix_color_filter.vert", "shaders/gaussian_blur.frag", + "shaders/gaussian_blur_decal.frag", "shaders/gaussian_blur.vert", "shaders/glyph_atlas.frag", "shaders/glyph_atlas.vert", diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 1f0f8c4c37130..fe6d231d1586a 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -207,6 +207,8 @@ ContentContext::ContentContext(std::shared_ptr context) CreateDefaultPipeline(*context_); gaussian_blur_pipelines_[{}] = CreateDefaultPipeline(*context_); + gaussian_blur_decal_pipelines_[{}] = + CreateDefaultPipeline(*context_); border_mask_blur_pipelines_[{}] = CreateDefaultPipeline(*context_); morphology_filter_pipelines_[{}] = diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index e8cabf188c246..9be86fb5193cb 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -36,6 +36,7 @@ #include "impeller/entity/entity.h" #include "impeller/entity/gaussian_blur.frag.h" #include "impeller/entity/gaussian_blur.vert.h" +#include "impeller/entity/gaussian_blur_decal.frag.h" #include "impeller/entity/glyph_atlas.frag.h" #include "impeller/entity/glyph_atlas.vert.h" #include "impeller/entity/glyph_atlas_sdf.frag.h" @@ -146,6 +147,8 @@ using TiledTexturePipeline = RenderPipelineT; using GaussianBlurPipeline = RenderPipelineT; +using GaussianBlurDecalPipeline = + RenderPipelineT; using BorderMaskBlurPipeline = RenderPipelineT; using MorphologyFilterPipeline = @@ -281,6 +284,11 @@ class ContentContext { return GetPipeline(gaussian_blur_pipelines_, opts); } + std::shared_ptr> GetGaussianBlurDecalPipeline( + ContentContextOptions opts) const { + return GetPipeline(gaussian_blur_decal_pipelines_, opts); + } + std::shared_ptr> GetBorderMaskBlurPipeline( ContentContextOptions opts) const { return GetPipeline(border_mask_blur_pipelines_, opts); @@ -455,6 +463,7 @@ class ContentContext { mutable Variants texture_pipelines_; mutable Variants tiled_texture_pipelines_; mutable Variants gaussian_blur_pipelines_; + mutable Variants gaussian_blur_decal_pipelines_; mutable Variants border_mask_blur_pipelines_; mutable Variants morphology_filter_pipelines_; mutable Variants diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index 782615cca274e..d3d056727acc9 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -183,13 +183,12 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( VS::FrameInfo frame_info; frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1)); - - FS::FragInfo frag_info; - frag_info.texture_sampler_y_coord_scale = + frame_info.texture_sampler_y_coord_scale = input_snapshot->texture->GetYCoordScale(); - frag_info.alpha_mask_sampler_y_coord_scale = + frame_info.alpha_mask_sampler_y_coord_scale = source_snapshot->texture->GetYCoordScale(); + FS::FragInfo frag_info; auto r = Radius{transformed_blur_radius_length}; frag_info.blur_sigma = Sigma{r}.sigma; frag_info.blur_radius = r.radius; @@ -198,7 +197,6 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( frag_info.blur_direction = pass_transform.Invert().TransformDirection(Vector2(1, 0)).Normalize(); - frag_info.tile_mode = static_cast(tile_mode_); frag_info.src_factor = src_color_factor_; frag_info.inner_blur_factor = inner_blur_factor_; frag_info.outer_blur_factor = outer_blur_factor_; @@ -207,19 +205,48 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( Command cmd; cmd.label = SPrintF("Gaussian Blur Filter (Radius=%.2f)", transformed_blur_radius_length); + cmd.BindVertices(vtx_buffer); + auto options = OptionsFromPass(pass); options.blend_mode = BlendMode::kSource; - cmd.pipeline = renderer.GetGaussianBlurPipeline(options); - cmd.BindVertices(vtx_buffer); + auto input_descriptor = input_snapshot->sampler_descriptor; + auto source_descriptor = source_snapshot->sampler_descriptor; + switch (tile_mode_) { + case Entity::TileMode::kDecal: + cmd.pipeline = renderer.GetGaussianBlurDecalPipeline(options); + break; + case Entity::TileMode::kClamp: + cmd.pipeline = renderer.GetGaussianBlurPipeline(options); + input_descriptor.width_address_mode = SamplerAddressMode::kClampToEdge; + input_descriptor.height_address_mode = SamplerAddressMode::kClampToEdge; + source_descriptor.width_address_mode = SamplerAddressMode::kClampToEdge; + source_descriptor.height_address_mode = + SamplerAddressMode::kClampToEdge; + break; + case Entity::TileMode::kMirror: + cmd.pipeline = renderer.GetGaussianBlurPipeline(options); + input_descriptor.width_address_mode = SamplerAddressMode::kMirror; + input_descriptor.height_address_mode = SamplerAddressMode::kMirror; + source_descriptor.width_address_mode = SamplerAddressMode::kMirror; + source_descriptor.height_address_mode = SamplerAddressMode::kMirror; + break; + case Entity::TileMode::kRepeat: + cmd.pipeline = renderer.GetGaussianBlurPipeline(options); + input_descriptor.width_address_mode = SamplerAddressMode::kRepeat; + input_descriptor.height_address_mode = SamplerAddressMode::kRepeat; + source_descriptor.width_address_mode = SamplerAddressMode::kRepeat; + source_descriptor.height_address_mode = SamplerAddressMode::kRepeat; + break; + } FS::BindTextureSampler( cmd, input_snapshot->texture, renderer.GetContext()->GetSamplerLibrary()->GetSampler( - input_snapshot->sampler_descriptor)); + input_descriptor)); FS::BindAlphaMaskSampler( cmd, source_snapshot->texture, renderer.GetContext()->GetSamplerLibrary()->GetSampler( - source_snapshot->sampler_descriptor)); + source_descriptor)); VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info)); @@ -281,7 +308,7 @@ std::optional DirectionalGaussianBlurFilterContents::GetFilterCoverage( auto transform = inputs[0]->GetTransform(entity) * effect_transform; auto transformed_blur_vector = - transform.TransformDirection(blur_direction_ * Radius{blur_sigma_}.radius) + transform.TransformDirection(blur_direction_* Radius{blur_sigma_}.radius) .Abs(); auto extent = coverage->size + transformed_blur_vector * 2; return Rect(coverage->origin - transformed_blur_vector, diff --git a/impeller/entity/shaders/gaussian_blur.frag b/impeller/entity/shaders/gaussian_blur.frag index b831baa6f8c77..8b483ae45de30 100644 --- a/impeller/entity/shaders/gaussian_blur.frag +++ b/impeller/entity/shaders/gaussian_blur.frag @@ -2,80 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// 1D (directional) gaussian blur. -// -// Paths for future optimization: -// * Remove the uv bounds multiplier in SampleColor by adding optional -// support for SamplerAddressMode::ClampToBorder in the texture sampler. -// * Render both blur passes into a smaller texture than the source image -// (~1/radius size). -// * If doing the small texture render optimization, cache misses can be -// reduced in the first pass by sampling the source textures with a mip -// level of log2(min_radius). - -#include -#include #include -#include - -uniform sampler2D texture_sampler; -uniform sampler2D alpha_mask_sampler; - -uniform FragInfo { - float texture_sampler_y_coord_scale; - float alpha_mask_sampler_y_coord_scale; - - vec2 texture_size; - vec2 blur_direction; - float tile_mode; - - // The blur sigma and radius have a linear relationship which is defined - // host-side, but both are useful controls here. Sigma (pixels per standard - // deviation) is used to define the gaussian function itself, whereas the - // radius is used to limit how much of the function is integrated. - float blur_sigma; - float blur_radius; - - float src_factor; - float inner_blur_factor; - float outer_blur_factor; +vec4 Sample(sampler2D tex, vec2 coords) { + return texture(tex, coords); } -frag_info; - -in vec2 v_texture_coords; -in vec2 v_src_texture_coords; -out vec4 frag_color; - -void main() { - vec4 total_color = vec4(0); - float gaussian_integral = 0; - vec2 blur_uv_offset = frag_info.blur_direction / frag_info.texture_size; - - for (float i = -frag_info.blur_radius; i <= frag_info.blur_radius; i++) { - float gaussian = IPGaussian(i, frag_info.blur_sigma); - gaussian_integral += gaussian; - total_color += - gaussian * - IPSampleWithTileMode( - texture_sampler, // sampler - v_texture_coords + blur_uv_offset * i, // texture coordinates - frag_info.texture_sampler_y_coord_scale, // y coordinate scale - frag_info.tile_mode // tile mode - ); - } - - vec4 blur_color = total_color / gaussian_integral; - - vec4 src_color = IPSampleWithTileMode( - alpha_mask_sampler, // sampler - v_src_texture_coords, // texture coordinates - frag_info.alpha_mask_sampler_y_coord_scale, // y coordinate scale - frag_info.tile_mode // tile mode - ); - float blur_factor = frag_info.inner_blur_factor * float(src_color.a > 0) + - frag_info.outer_blur_factor * float(src_color.a == 0); - - frag_color = blur_color * blur_factor + src_color * frag_info.src_factor; -} +#include "gaussian_blur.glsl" diff --git a/impeller/entity/shaders/gaussian_blur.glsl b/impeller/entity/shaders/gaussian_blur.glsl new file mode 100644 index 0000000000000..718b4826021c0 --- /dev/null +++ b/impeller/entity/shaders/gaussian_blur.glsl @@ -0,0 +1,70 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// 1D (directional) gaussian blur. +// +// Paths for future optimization: +// * Remove the uv bounds multiplier in SampleColor by adding optional +// support for SamplerAddressMode::ClampToBorder in the texture sampler. +// * Render both blur passes into a smaller texture than the source image +// (~1/radius size). +// * If doing the small texture render optimization, cache misses can be +// reduced in the first pass by sampling the source textures with a mip +// level of log2(min_radius). + +#include +#include +#include +#include + +uniform sampler2D texture_sampler; +uniform sampler2D alpha_mask_sampler; + +uniform FragInfo { + vec2 texture_size; + vec2 blur_direction; + + // The blur sigma and radius have a linear relationship which is defined + // host-side, but both are useful controls here. Sigma (pixels per standard + // deviation) is used to define the gaussian function itself, whereas the + // radius is used to limit how much of the function is integrated. + float blur_sigma; + float blur_radius; + + float src_factor; + float inner_blur_factor; + float outer_blur_factor; +} +frag_info; + +in vec2 v_texture_coords; +in vec2 v_src_texture_coords; + +out vec4 frag_color; + +void main() { + vec4 total_color = vec4(0); + float gaussian_integral = 0; + vec2 blur_uv_offset = frag_info.blur_direction / frag_info.texture_size; + + for (float i = -frag_info.blur_radius; i <= frag_info.blur_radius; i++) { + float gaussian = IPGaussian(i, frag_info.blur_sigma); + gaussian_integral += gaussian; + total_color += + gaussian * + Sample(texture_sampler, // sampler + v_texture_coords + blur_uv_offset * i // texture coordinates + ); + } + + vec4 blur_color = total_color / gaussian_integral; + + vec4 src_color = Sample(alpha_mask_sampler, // sampler + v_src_texture_coords // texture coordinates + ); + float blur_factor = frag_info.inner_blur_factor * float(src_color.a > 0) + + frag_info.outer_blur_factor * float(src_color.a == 0); + + frag_color = blur_color * blur_factor + src_color * frag_info.src_factor; +} diff --git a/impeller/entity/shaders/gaussian_blur.vert b/impeller/entity/shaders/gaussian_blur.vert index 1fac06eb058b8..f402003b13bf1 100644 --- a/impeller/entity/shaders/gaussian_blur.vert +++ b/impeller/entity/shaders/gaussian_blur.vert @@ -2,10 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include #include uniform FrameInfo { mat4 mvp; + float texture_sampler_y_coord_scale; + float alpha_mask_sampler_y_coord_scale; } frame_info; @@ -18,6 +21,8 @@ out vec2 v_src_texture_coords; void main() { gl_Position = frame_info.mvp * vec4(vertices, 0.0, 1.0); - v_texture_coords = texture_coords; - v_src_texture_coords = src_texture_coords; + v_texture_coords = + IPRemapCoords(texture_coords, frame_info.texture_sampler_y_coord_scale); + v_src_texture_coords = IPRemapCoords( + src_texture_coords, frame_info.alpha_mask_sampler_y_coord_scale); } diff --git a/impeller/entity/shaders/gaussian_blur_decal.frag b/impeller/entity/shaders/gaussian_blur_decal.frag new file mode 100644 index 0000000000000..c3076c7f7f902 --- /dev/null +++ b/impeller/entity/shaders/gaussian_blur_decal.frag @@ -0,0 +1,11 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +vec4 Sample(sampler2D tex, vec2 coords) { + return IPSampleDecal(tex, coords); +} + +#include "gaussian_blur.glsl"