diff --git a/lib/ui/dart_ui.cc b/lib/ui/dart_ui.cc index 5199821389311..b9488181966ae 100644 --- a/lib/ui/dart_ui.cc +++ b/lib/ui/dart_ui.cc @@ -174,6 +174,7 @@ typedef CanvasPath Path; V(EngineLayer, dispose, 1) \ V(FragmentProgram, initFromAsset, 2) \ V(ReusableFragmentShader, Dispose, 1) \ + V(ReusableFragmentShader, SetImageSampler, 3) \ V(ReusableFragmentShader, SetSampler, 3) \ V(ReusableFragmentShader, ValidateSamplers, 1) \ V(Gradient, initLinear, 6) \ diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 307ac9ca7affa..23d4ac32e66f6 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -4314,6 +4314,18 @@ class FragmentShader extends Shader { _floats[index] = value; } + /// Sets the sampler uniform at [index] to [image]. + /// + /// The index provided to setImageSampler is the index of the sampler uniform defined + /// in the fragment program, excluding all non-sampler uniforms. + /// + /// All the sampler uniforms that a shader expects must be provided or the + /// results will be undefined. + void setImageSampler(int index, Image image) { + assert(!debugDisposed, 'Tried to access uniforms on a disposed Shader: $this'); + _setImageSampler(index, image._image); + } + /// Sets the sampler uniform at [index] to [sampler]. /// /// The index provided to setSampler is the index of the sampler uniform defined @@ -4341,6 +4353,9 @@ class FragmentShader extends Shader { @FfiNative('ReusableFragmentShader::Create') external Float32List _constructor(FragmentProgram program, int floatUniforms, int samplerUniforms); + @FfiNative, Handle, Handle)>('ReusableFragmentShader::SetImageSampler') + external void _setImageSampler(int index, _Image sampler); + @FfiNative, Handle, Handle)>('ReusableFragmentShader::SetSampler') external void _setSampler(int index, ImageShader sampler); diff --git a/lib/ui/painting/fragment_shader.cc b/lib/ui/painting/fragment_shader.cc index 38f62ef3d507e..3a87c260f3d6a 100644 --- a/lib/ui/painting/fragment_shader.cc +++ b/lib/ui/painting/fragment_shader.cc @@ -7,6 +7,8 @@ #include "flutter/lib/ui/painting/fragment_shader.h" +#include "flutter/display_list/display_list_color_source.h" +#include "flutter/display_list/display_list_tile_mode.h" #include "flutter/lib/ui/dart_wrapper.h" #include "flutter/lib/ui/painting/fragment_program.h" #include "flutter/lib/ui/ui_dart_state.h" @@ -61,6 +63,27 @@ bool ReusableFragmentShader::ValidateSamplers() { return true; } +void ReusableFragmentShader::SetImageSampler(Dart_Handle index_handle, + Dart_Handle image_handle) { + uint64_t index = tonic::DartConverter::FromDart(index_handle); + CanvasImage* image = + tonic::DartConverter::FromDart(image_handle); + if (index >= samplers_.size()) { + Dart_ThrowException(tonic::ToDart("Sampler index out of bounds")); + } + + // TODO(115794): Once the DlImageSampling enum is replaced, expose the + // sampling options as a new default parameter for users. + samplers_[index] = std::make_shared( + image->image(), DlTileMode::kClamp, DlTileMode::kClamp, + DlImageSampling::kNearestNeighbor, nullptr); + + auto* uniform_floats = + reinterpret_cast(uniform_data_->writable_data()); + uniform_floats[float_count_ + 2 * index] = image->width(); + uniform_floats[float_count_ + 2 * index + 1] = image->height(); +} + void ReusableFragmentShader::SetSampler(Dart_Handle index_handle, Dart_Handle sampler_handle) { uint64_t index = tonic::DartConverter::FromDart(index_handle); diff --git a/lib/ui/painting/fragment_shader.h b/lib/ui/painting/fragment_shader.h index 5b948e80dea0c..36dea2c61c711 100644 --- a/lib/ui/painting/fragment_shader.h +++ b/lib/ui/painting/fragment_shader.h @@ -34,6 +34,8 @@ class ReusableFragmentShader : public Shader { Dart_Handle float_count, Dart_Handle sampler_count); + void SetImageSampler(Dart_Handle index, Dart_Handle image); + void SetSampler(Dart_Handle index, Dart_Handle sampler); bool ValidateSamplers(); diff --git a/lib/web_ui/lib/painting.dart b/lib/web_ui/lib/painting.dart index 7a0d7439cb8ff..445b5f79dbb50 100644 --- a/lib/web_ui/lib/painting.dart +++ b/lib/web_ui/lib/painting.dart @@ -818,6 +818,8 @@ abstract class FragmentProgram { abstract class FragmentShader implements Shader { void setFloat(int index, double value); + void setImageSampler(int index, Image image); + void setSampler(int index, ImageShader sampler); @override diff --git a/lib/web_ui/lib/src/engine/canvaskit/painting.dart b/lib/web_ui/lib/src/engine/canvaskit/painting.dart index b9a7296207c7e..bb586ef545f1a 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/painting.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/painting.dart @@ -8,6 +8,7 @@ import 'dart:typed_data'; import 'package:ui/ui.dart' as ui; import '../color_filter.dart'; +import '../vector_math.dart'; import 'canvaskit_api.dart'; import 'color_filter.dart'; import 'image_filter.dart'; @@ -476,6 +477,15 @@ class CkFragmentShader implements ui.FragmentShader { floats[index] = value; } + @override + void setImageSampler(int index, ui.Image image) { + final ui.ImageShader sampler = ui.ImageShader(image, ui.TileMode.clamp, + ui.TileMode.clamp, toMatrix64(Matrix4.identity().storage)); + samplers[index] = (sampler as CkShader).skiaObject; + setFloat(lastFloatIndex + 2 * index, (sampler as CkImageShader).imageWidth.toDouble()); + setFloat(lastFloatIndex + 2 * index + 1, sampler.imageHeight.toDouble()); + } + @override void setSampler(int index, ui.ImageShader sampler) { samplers[index] = (sampler as CkShader).skiaObject; diff --git a/lib/web_ui/lib/src/engine/html/painting.dart b/lib/web_ui/lib/src/engine/html/painting.dart index dc3ccdc4f63a7..22408fa188e38 100644 --- a/lib/web_ui/lib/src/engine/html/painting.dart +++ b/lib/web_ui/lib/src/engine/html/painting.dart @@ -302,6 +302,11 @@ class HtmlFragmentShader implements ui.FragmentShader { throw UnsupportedError('FragmentShader is not supported for the HTML renderer.'); } + @override + void setImageSampler(int index, ui.Image image) { + throw UnsupportedError('FragmentShader is not supported for the HTML renderer.'); + } + @override void setSampler(int index, ui.ImageShader sampler) { throw UnsupportedError('FragmentShader is not supported for the HTML renderer.');