Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions impeller/compiler/shader_lib/impeller/texture.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions impeller/entity/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,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",
Expand Down
2 changes: 2 additions & 0 deletions impeller/entity/contents/content_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ ContentContext::ContentContext(std::shared_ptr<Context> context)
CreateDefaultPipeline<TiledTexturePipeline>(*context_);
gaussian_blur_pipelines_[{}] =
CreateDefaultPipeline<GaussianBlurPipeline>(*context_);
gaussian_blur_decal_pipelines_[{}] =
CreateDefaultPipeline<GaussianBlurDecalPipeline>(*context_);
border_mask_blur_pipelines_[{}] =
CreateDefaultPipeline<BorderMaskBlurPipeline>(*context_);
morphology_filter_pipelines_[{}] =
Expand Down
9 changes: 9 additions & 0 deletions impeller/entity/contents/content_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,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"
Expand Down Expand Up @@ -146,6 +147,8 @@ using TiledTexturePipeline = RenderPipelineT<TiledTextureFillVertexShader,
TiledTextureFillFragmentShader>;
using GaussianBlurPipeline =
RenderPipelineT<GaussianBlurVertexShader, GaussianBlurFragmentShader>;
using GaussianBlurDecalPipeline =
RenderPipelineT<GaussianBlurVertexShader, GaussianBlurDecalFragmentShader>;
using BorderMaskBlurPipeline =
RenderPipelineT<BorderMaskBlurVertexShader, BorderMaskBlurFragmentShader>;
using MorphologyFilterPipeline =
Expand Down Expand Up @@ -281,6 +284,11 @@ class ContentContext {
return GetPipeline(gaussian_blur_pipelines_, opts);
}

std::shared_ptr<Pipeline<PipelineDescriptor>> GetGaussianBlurDecalPipeline(
ContentContextOptions opts) const {
return GetPipeline(gaussian_blur_decal_pipelines_, opts);
}

std::shared_ptr<Pipeline<PipelineDescriptor>> GetBorderMaskBlurPipeline(
ContentContextOptions opts) const {
return GetPipeline(border_mask_blur_pipelines_, opts);
Expand Down Expand Up @@ -460,6 +468,7 @@ class ContentContext {
mutable Variants<TexturePipeline> texture_pipelines_;
mutable Variants<TiledTexturePipeline> tiled_texture_pipelines_;
mutable Variants<GaussianBlurPipeline> gaussian_blur_pipelines_;
mutable Variants<GaussianBlurDecalPipeline> gaussian_blur_decal_pipelines_;
mutable Variants<BorderMaskBlurPipeline> border_mask_blur_pipelines_;
mutable Variants<MorphologyFilterPipeline> morphology_filter_pipelines_;
mutable Variants<ColorMatrixColorFilterPipeline>
Expand Down
45 changes: 36 additions & 9 deletions impeller/entity/contents/filters/gaussian_blur_filter_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,12 @@ std::optional<Snapshot> 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;
Expand All @@ -198,7 +197,6 @@ std::optional<Snapshot> DirectionalGaussianBlurFilterContents::RenderFilter(
frag_info.blur_direction =
pass_transform.Invert().TransformDirection(Vector2(1, 0)).Normalize();

frag_info.tile_mode = static_cast<Scalar>(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_;
Expand All @@ -207,19 +205,48 @@ std::optional<Snapshot> 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));

Expand Down
76 changes: 3 additions & 73 deletions impeller/entity/shaders/gaussian_blur.frag
Original file line number Diff line number Diff line change
Expand Up @@ -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 <impeller/constants.glsl>
#include <impeller/gaussian.glsl>
#include <impeller/texture.glsl>
#include <impeller/types.glsl>

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"
70 changes: 70 additions & 0 deletions impeller/entity/shaders/gaussian_blur.glsl
Original file line number Diff line number Diff line change
@@ -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 <impeller/constants.glsl>
#include <impeller/gaussian.glsl>
#include <impeller/texture.glsl>
#include <impeller/types.glsl>

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;
}
9 changes: 7 additions & 2 deletions impeller/entity/shaders/gaussian_blur.vert
Original file line number Diff line number Diff line change
Expand Up @@ -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 <impeller/texture.glsl>
#include <impeller/types.glsl>

uniform FrameInfo {
mat4 mvp;
float texture_sampler_y_coord_scale;
float alpha_mask_sampler_y_coord_scale;
}
frame_info;

Expand All @@ -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);
}
11 changes: 11 additions & 0 deletions impeller/entity/shaders/gaussian_blur_decal.frag
Original file line number Diff line number Diff line change
@@ -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 <impeller/texture.glsl>

vec4 Sample(sampler2D tex, vec2 coords) {
return IPSampleDecal(tex, coords);
}

#include "gaussian_blur.glsl"