diff --git a/lib/ui/dart_ui.cc b/lib/ui/dart_ui.cc index b82c69fd978d6..20f7345fcd707 100644 --- a/lib/ui/dart_ui.cc +++ b/lib/ui/dart_ui.cc @@ -18,7 +18,6 @@ #include "flutter/lib/ui/painting/color_filter.h" #include "flutter/lib/ui/painting/engine_layer.h" #include "flutter/lib/ui/painting/fragment_program.h" -#include "flutter/lib/ui/painting/fragment_shader.h" #include "flutter/lib/ui/painting/gradient.h" #include "flutter/lib/ui/painting/image.h" #include "flutter/lib/ui/painting/image_descriptor.h" @@ -68,7 +67,6 @@ typedef CanvasPath Path; V(Canvas::Create, 6) \ V(ColorFilter::Create, 1) \ V(FragmentProgram::Create, 1) \ - V(ReusableFragmentShader::Create, 4) \ V(Gradient::Create, 1) \ V(ImageFilter::Create, 1) \ V(ImageShader::Create, 1) \ @@ -169,8 +167,6 @@ typedef CanvasPath Path; V(EngineLayer, dispose, 1) \ V(FragmentProgram, initFromAsset, 2) \ V(FragmentProgram, shader, 4) \ - V(ReusableFragmentShader, Dispose, 1) \ - V(ReusableFragmentShader, SetSampler, 3) \ V(Gradient, initLinear, 6) \ V(Gradient, initRadial, 8) \ V(Gradient, initSweep, 9) \ diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index f57ed6e00f673..cb7c2df5e0fca 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1399,10 +1399,9 @@ class Paint { } set shader(Shader? value) { assert(() { - assert( - value == null || !value.debugDisposed, - 'Attempted to set a disposed shader to $this', - ); + if (value is ImageShader) { + assert(!value.debugDisposed, 'Attempted to set a disposed shader to $this'); + } return true; }()); _ensureObjectsInitialized()[_kShaderIndex] = value; @@ -3683,37 +3682,6 @@ class Shader extends NativeFieldWrapperClass1 { /// or extended directly. @pragma('vm:entry-point') Shader._(); - - bool _debugDisposed = false; - - /// Whether [dispose] has been called. - /// - /// This must only be used when asserts are enabled. Otherwise, it will throw. - bool get debugDisposed { - late bool disposed; - assert(() { - disposed = _debugDisposed; - return true; - }()); - return disposed; - } - - /// Release the resources used by this object. The object is no longer usable - /// after this method is called. - /// - /// The underlying memory allocated by this object will be retained beyond - /// this call if it is still needed by another object that has not been - /// disposed. For example, a [Picture] that has not been disposed that - /// refers to an [ImageShader] may keep its underlying resources alive. - /// - /// Classes that override this method must call `super.dispose()`. - void dispose() { - assert(() { - assert(!_debugDisposed); - _debugDisposed = true; - return true; - }()); - } } /// Defines what happens at the edge of a gradient or the sampling of a source image @@ -4088,29 +4056,55 @@ class ImageShader extends Shader { } } - @override - void dispose() { - super.dispose(); - _dispose(); - } - @FfiNative('ImageShader::Create') external void _constructor(); @FfiNative, Pointer, Int32, Int32, Int32, Handle)>('ImageShader::initWithImage') external String? _initWithImage(_Image image, int tmx, int tmy, int filterQualityIndex, Float64List matrix4); + bool _debugDisposed = false; + + /// Whether [dispose] has been called. + /// + /// This must only be used when asserts are enabled. Otherwise, it will throw. + bool get debugDisposed { + late bool disposed; + assert(() { + disposed = _debugDisposed; + return true; + }()); + return disposed; + } + + /// Release the resources used by this object. The object is no longer usable + /// after this method is called. + /// + /// The underlying memory allocated by this object will be retained beyond + /// this call if it is still needed by another object that has not been + /// disposed. For example, an [Picture] that has not been disposed that + /// refers to this [ImageShader] may keep its underlying resources alive. + void dispose() { + assert(() { + assert(!_debugDisposed); + _debugDisposed = true; + return true; + }()); + _dispose(); + } + /// This can't be a leaf call because the native function calls Dart API /// (Dart_SetNativeInstanceField). @FfiNative)>('ImageShader::dispose') external void _dispose(); } -/// An instance of [FragmentProgram] creates [Shader] objects (as used by -/// [Paint.shader]). +/// An instance of [FragmentProgram] creates [Shader] objects (as used by [Paint.shader]) that run SPIR-V code. /// /// This API is in beta and does not yet work on web. /// See https://github.com/flutter/flutter/projects/207 for roadmap. +/// +/// [A current specification of valid SPIR-V is here.](https://github.com/flutter/engine/blob/main/lib/spirv/README.md) +/// class FragmentProgram extends NativeFieldWrapperClass1 { @pragma('vm:entry-point') FragmentProgram._fromAsset(String assetKey) { @@ -4187,9 +4181,6 @@ class FragmentProgram extends NativeFieldWrapperClass1 { @FfiNative, Handle)>('FragmentProgram::initFromAsset') external String _initFromAsset(String assetKey); - /// Returns a fresh instance of [FragmentShader]. - FragmentShader fragmentShader() => FragmentShader._(this); - /// Constructs a [Shader] object suitable for use by [Paint.shader] with /// the given uniforms. /// @@ -4272,111 +4263,6 @@ class FragmentProgram extends NativeFieldWrapperClass1 { external Handle _shader(_FragmentShader shader, Float32List floatUniforms, List samplerUniforms); } -/// A [Shader] generated from a [FragmentProgram]. -/// -/// Instances of this class can be obtained from the -/// [FragmentProgram.fragmentShader] method. The float uniforms list is -/// initialized to the size expected by the shader and is zero-filled. Uniforms -/// of float type can then be set by calling [setFloat]. Sampler uniforms are -/// set by calling [setSampler]. -/// -/// A [FragmentShader] can be re-used, and this is an efficient way to avoid -/// allocating and re-initializing the uniform buffer and samplers. However, -/// if two [FragmentShader] objects with different float uniforms or samplers -/// are required to exist simultaneously, they must be obtained from two -/// different calls to [FragmentProgram.fragmentShader]. -/// -/// Consider a fragment shader with uniforms like the following: -/// -/// ```glsl -/// layout (location = 0) uniform float a; -/// layout (location = 1) uniform vec2 b; -/// layout (location = 2) uniform vec3 c; -/// layout (location = 3) uniform mat2x2 d; -/// layout (location = 4) uniform sampler2d s; -/// ``` -/// -/// If this shader is loaded into a [FragmentProgram] object `program`, a -/// [FragmentShader] object can be constructed as follows: -/// ```dart -/// ImageShader sampler; -/// final FragmentShader shader = program.fragmentShader() -/// ..setFloat(0, 0.0) -/// ..setFloat(1, 1.0) -/// ..setFloat(2, 2.0) -/// ..setFloat(3, 3.0) -/// ..setFloat(4, 4.0) -/// ..setFloat(5, 5.0) -/// ..setFloat(6, 6.0) -/// ..setFloat(7, 7.0) -/// ..setFloat(8, 8.8) -/// ..setFloat(9, 9.0) -/// ..setSampler(0, sampler); -/// -/// Paint paint = Paint()..shader = shader; -/// ``` -/// -/// The uniforms will then be set as follows: -/// -/// a: 0.0 -/// b: [1.0, 2.0] -/// c: [3.0, 4.0, 5.0] -/// d: [6.0, 7.0, 8.0, 9.0] // 2x2 matrix in column-major order -/// -/// On subsequent frames, if only the uniform `a` is required to vary, then -/// only `shader.setFloat(0, newValue)` needs to be called. The other uniforms -/// will retain their values. The sampler uniforms will also persist in the same -/// way. -class FragmentShader extends Shader { - FragmentShader._(FragmentProgram program) : super._() { - _floats = _constructor( - program, - program._uniformFloatCount, - program._samplerCount, - ); - } - - static final Float32List _kEmptyFloat32List = Float32List(0); - - late Float32List _floats; - - /// Sets the float uniform at [index] to [value]. - void setFloat(int index, double value) { - assert(!debugDisposed, 'Tried to accesss uniforms on a disposed Shader: $this'); - _floats[index] = value; - } - - /// Sets the sampler uniform at [index] to [sampler]. - /// - /// All the sampler uniforms that a shader expects must be provided or the - /// results will be undefined. - void setSampler(int index, ImageShader sampler) { - assert(!debugDisposed, 'Tried to access uniforms on a disposed Shader: $this'); - _setSampler(index, sampler); - } - - /// Releases the native resources held by the [FragmentShader]. - /// - /// After this method is called, calling methods on the shader, or attaching - /// it to a [Paint] object will fail with an exception. Calling [dispose] - /// twice will also result in an exception being thrown. - @override - void dispose() { - super.dispose(); - _floats = _kEmptyFloat32List; - _dispose(); - } - - @FfiNative('ReusableFragmentShader::Create') - external Float32List _constructor(FragmentProgram program, int floatUniforms, int samplerUniforms); - - @FfiNative, Handle, Handle)>('ReusableFragmentShader::SetSampler') - external void _setSampler(int index, ImageShader sampler); - - @FfiNative)>('ReusableFragmentShader::Dispose') - external void _dispose(); -} - @pragma('vm:entry-point') class _FragmentShader extends Shader { /// This class is created by the engine and should not be instantiated diff --git a/lib/ui/painting/fragment_program.cc b/lib/ui/painting/fragment_program.cc index 26a53994a3f90..e55c09f3eac94 100644 --- a/lib/ui/painting/fragment_program.cc +++ b/lib/ui/painting/fragment_program.cc @@ -133,13 +133,6 @@ fml::RefPtr FragmentProgram::shader(Dart_Handle shader, std::move(uniform_data))); } -std::shared_ptr FragmentProgram::MakeDlColorSource( - sk_sp float_uniforms, - const std::vector>& children) { - return DlColorSource::MakeRuntimeEffect(runtime_effect_, std::move(children), - std::move(float_uniforms)); -} - void FragmentProgram::Create(Dart_Handle wrapper) { auto res = fml::MakeRefCounted(); res->AssociateWithDartWrapper(wrapper); diff --git a/lib/ui/painting/fragment_program.h b/lib/ui/painting/fragment_program.h index 0f40ddffd9d41..4bc548acc5a70 100644 --- a/lib/ui/painting/fragment_program.h +++ b/lib/ui/painting/fragment_program.h @@ -7,7 +7,6 @@ #include "flutter/lib/ui/dart_wrapper.h" #include "flutter/lib/ui/painting/fragment_shader.h" -#include "flutter/lib/ui/painting/shader.h" #include "third_party/skia/include/effects/SkRuntimeEffect.h" #include "third_party/tonic/dart_library_natives.h" #include "third_party/tonic/typed_data/typed_list.h" @@ -17,8 +16,6 @@ namespace flutter { -class FragmentShader; - class FragmentProgram : public RefCountedDartWrappable { DEFINE_WRAPPERTYPEINFO(); FML_FRIEND_MAKE_REF_COUNTED(FragmentProgram); @@ -33,10 +30,6 @@ class FragmentProgram : public RefCountedDartWrappable { Dart_Handle uniforms_handle, Dart_Handle samplers); - std::shared_ptr MakeDlColorSource( - sk_sp float_uniforms, - const std::vector>& children); - private: FragmentProgram(); sk_sp runtime_effect_; diff --git a/lib/ui/painting/fragment_shader.cc b/lib/ui/painting/fragment_shader.cc index 7d57b3ac1402d..39cee53482bed 100644 --- a/lib/ui/painting/fragment_shader.cc +++ b/lib/ui/painting/fragment_shader.cc @@ -7,7 +7,6 @@ #include "flutter/lib/ui/painting/fragment_shader.h" #include "flutter/lib/ui/dart_wrapper.h" -#include "flutter/lib/ui/painting/fragment_program.h" #include "flutter/lib/ui/ui_dart_state.h" #include "third_party/skia/include/core/SkString.h" #include "third_party/tonic/converter/dart_converter.h" @@ -49,75 +48,4 @@ FragmentShader::FragmentShader( FragmentShader::~FragmentShader() = default; -IMPLEMENT_WRAPPERTYPEINFO(ui, ReusableFragmentShader); - -ReusableFragmentShader::ReusableFragmentShader( - fml::RefPtr program, - uint64_t float_count, - uint64_t sampler_count) - : program_(program), - uniform_data_(SkData::MakeUninitialized( - (float_count + 2 * sampler_count) * sizeof(float))), - samplers_(sampler_count), - float_count_(float_count) {} - -Dart_Handle ReusableFragmentShader::Create(Dart_Handle wrapper, - Dart_Handle program, - Dart_Handle float_count_handle, - Dart_Handle sampler_count_handle) { - auto* fragment_program = - tonic::DartConverter::FromDart(program); - uint64_t float_count = - tonic::DartConverter::FromDart(float_count_handle); - uint64_t sampler_count = - tonic::DartConverter::FromDart(sampler_count_handle); - - auto res = fml::MakeRefCounted( - fml::Ref(fragment_program), float_count, sampler_count); - res->AssociateWithDartWrapper(wrapper); - - void* raw_uniform_data = - reinterpret_cast(res->uniform_data_->writable_data()); - return Dart_NewExternalTypedData(Dart_TypedData_kFloat32, raw_uniform_data, - float_count); -} - -void ReusableFragmentShader::SetSampler(Dart_Handle index_handle, - Dart_Handle sampler_handle) { - uint64_t index = tonic::DartConverter::FromDart(index_handle); - ImageShader* sampler = - tonic::DartConverter::FromDart(sampler_handle); - if (index >= samplers_.size()) { - Dart_ThrowException(tonic::ToDart("Sampler index out of bounds")); - } - - // ImageShaders can hold a preferred value for sampling options and - // developers are encouraged to use that value or the value will be supplied - // by "the environment where it is used". The environment here does not - // contain a value to be used if the developer did not specify a preference - // when they constructed the ImageShader, so we will use kNearest which is - // the default filterQuality in a Paint object. - DlImageSampling sampling = DlImageSampling::kNearestNeighbor; - auto* uniform_floats = - reinterpret_cast(uniform_data_->writable_data()); - samplers_[index] = sampler->shader(sampling); - uniform_floats[float_count_ + 2 * index] = sampler->width(); - uniform_floats[float_count_ + 2 * index + 1] = sampler->height(); -} - -std::shared_ptr ReusableFragmentShader::shader( - DlImageSampling sampling) { - FML_CHECK(program_); - return program_->MakeDlColorSource(uniform_data_, samplers_); -} - -void ReusableFragmentShader::Dispose() { - uniform_data_.reset(); - program_ = nullptr; - samplers_.clear(); - ClearDartWrapper(); -} - -ReusableFragmentShader::~ReusableFragmentShader() = default; - } // namespace flutter diff --git a/lib/ui/painting/fragment_shader.h b/lib/ui/painting/fragment_shader.h index 2c84b2408ff75..f3aa48a156577 100644 --- a/lib/ui/painting/fragment_shader.h +++ b/lib/ui/painting/fragment_shader.h @@ -6,7 +6,6 @@ #define FLUTTER_LIB_UI_PAINTING_FRAGMENT_SHADER_H_ #include "flutter/lib/ui/dart_wrapper.h" -#include "flutter/lib/ui/painting/fragment_program.h" #include "flutter/lib/ui/painting/image.h" #include "flutter/lib/ui/painting/image_shader.h" #include "flutter/lib/ui/painting/shader.h" @@ -20,8 +19,6 @@ namespace flutter { -class FragmentProgram; - class FragmentShader : public Shader { DEFINE_WRAPPERTYPEINFO(); FML_FRIEND_MAKE_REF_COUNTED(FragmentShader); @@ -32,7 +29,6 @@ class FragmentShader : public Shader { Dart_Handle dart_handle, std::shared_ptr shader); - // |Shader| std::shared_ptr shader(DlImageSampling) override; private: @@ -41,36 +37,6 @@ class FragmentShader : public Shader { std::shared_ptr source_; }; -class ReusableFragmentShader : public Shader { - DEFINE_WRAPPERTYPEINFO(); - FML_FRIEND_MAKE_REF_COUNTED(ReusableFragmentShader); - - public: - ~ReusableFragmentShader() override; - - static Dart_Handle Create(Dart_Handle wrapper, - Dart_Handle program, - Dart_Handle float_count, - Dart_Handle sampler_count); - - void SetSampler(Dart_Handle index, Dart_Handle sampler); - - void Dispose(); - - // |Shader| - std::shared_ptr shader(DlImageSampling) override; - - private: - ReusableFragmentShader(fml::RefPtr program, - uint64_t float_count, - uint64_t sampler_count); - - fml::RefPtr program_; - sk_sp uniform_data_; - std::vector> samplers_; - size_t float_count_; -}; - } // namespace flutter #endif // FLUTTER_LIB_UI_PAINTING_FRAGMENT_SHADER_H_ diff --git a/lib/web_ui/lib/painting.dart b/lib/web_ui/lib/painting.dart index 8daf324d9d77c..0edd2faeb0dbd 100644 --- a/lib/web_ui/lib/painting.dart +++ b/lib/web_ui/lib/painting.dart @@ -270,10 +270,6 @@ abstract class Paint { abstract class Shader { Shader._(); - - void dispose(); - - bool get debugDisposed; } abstract class Gradient extends Shader { @@ -704,10 +700,8 @@ abstract class ImageShader extends Shader { FilterQuality? filterQuality, }) => engine.renderer.createImageShader(image, tmx, tmy, matrix4, filterQuality); - @override void dispose(); - @override bool get debugDisposed; } @@ -805,8 +799,8 @@ class FragmentProgram { throw UnsupportedError('FragmentProgram is not supported for the CanvasKit or HTML renderers.'); } - FragmentShader fragmentShader() { - throw UnsupportedError('FragmentProgram is not supported for the CanvasKit or HTML renderers.'); + static Future fromAssetAsync(String assetKey) { + return Future.microtask(() => FragmentProgram.fromAsset(assetKey)); } Shader shader({ @@ -814,25 +808,3 @@ class FragmentProgram { List? samplerUniforms, }) => throw UnsupportedError('FragmentProgram is not supported for the CanvasKit or HTML renderers.'); } - -class FragmentShader extends Shader { - FragmentShader._() : super._(); - - void setFloat(int index, double value) { - throw UnsupportedError('FragmentShader is not supported for the CanvasKit or HTML renderers.'); - } - - void setSampler(int index, ImageShader sampler) { - throw UnsupportedError('FragmentShader is not supported for the CanvasKit or HTML renderers.'); - } - - @override - void dispose() { - throw UnsupportedError('FragmentShader is not supported for the CanvasKit or HTML renderers.'); - } - - @override - bool get debugDisposed { - throw UnsupportedError('FragmentShader is not supported for the CanvasKit or HTML renderers.'); - } -} diff --git a/lib/web_ui/lib/src/engine/canvaskit/shader.dart b/lib/web_ui/lib/src/engine/canvaskit/shader.dart index 53144103abfec..531a251da5744 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/shader.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/shader.dart @@ -21,26 +21,6 @@ abstract class CkShader extends ManagedSkiaObject void delete() { rawSkiaObject?.delete(); } - - bool _disposed = false; - - @override - bool get debugDisposed { - late bool disposed; - assert(() { - disposed = _disposed; - return true; - }()); - return disposed; - } - - @override - void dispose() { - assert(() { - _disposed = true; - return true; - }()); - } } class CkGradientSweep extends CkShader implements ui.Gradient { @@ -239,9 +219,24 @@ class CkImageShader extends CkShader implements ui.ImageShader { rawSkiaObject?.delete(); } + bool _disposed = false; + + @override + bool get debugDisposed { + late bool disposed; + assert(() { + disposed = _disposed; + return true; + }()); + return disposed; + } + @override void dispose() { - super.dispose(); + assert(() { + _disposed = true; + return true; + }()); _image.dispose(); } } diff --git a/lib/web_ui/lib/src/engine/html/shaders/image_shader.dart b/lib/web_ui/lib/src/engine/html/shaders/image_shader.dart index 0caede789b3e7..60cca92e3db03 100644 --- a/lib/web_ui/lib/src/engine/html/shaders/image_shader.dart +++ b/lib/web_ui/lib/src/engine/html/shaders/image_shader.dart @@ -284,6 +284,6 @@ class EngineImageShader implements ui.ImageShader { _disposed = true; return true; }()); - image.dispose(); + image.dispose(); } } diff --git a/lib/web_ui/lib/src/engine/html/shaders/shader.dart b/lib/web_ui/lib/src/engine/html/shaders/shader.dart index be3ebaa92e361..a12da953df576 100644 --- a/lib/web_ui/lib/src/engine/html/shaders/shader.dart +++ b/lib/web_ui/lib/src/engine/html/shaders/shader.dart @@ -54,12 +54,6 @@ abstract class EngineGradient implements ui.Gradient { /// Creates a CanvasImageSource to paint gradient. Object createImageBitmap( ui.Rect? shaderBounds, double density, bool createDataUrl); - - @override - bool debugDisposed = false; - - @override - void dispose() {} } class GradientSweep extends EngineGradient { diff --git a/testing/dart/fragment_shader_test.dart b/testing/dart/fragment_shader_test.dart index 73404e6e25e49..5fcc63f3ad328 100644 --- a/testing/dart/fragment_shader_test.dart +++ b/testing/dart/fragment_shader_test.dart @@ -14,132 +14,6 @@ import 'package:path/path.dart' as path; import 'shader_test_file_utils.dart'; void main() async { - bool assertsEnabled = false; - assert(() { - assertsEnabled = true; - return true; - }()); - - test('FragmentShader setSampler throws with out-of-bounds index', () async { - final FragmentProgram program = await FragmentProgram.fromAsset( - 'blue_green_sampler.frag.iplr', - ); - final Image blueGreenImage = await _createBlueGreenImage(); - final ImageShader imageShader = ImageShader( - blueGreenImage, TileMode.clamp, TileMode.clamp, _identityMatrix); - final FragmentShader fragmentShader = program.fragmentShader(); - - try { - fragmentShader.setSampler(1, imageShader); - fail('Unreachable'); - } catch (e) { - expect(e, contains('Sampler index out of bounds')); - } finally { - fragmentShader.dispose(); - imageShader.dispose(); - blueGreenImage.dispose(); - } - }); - - test('Disposed FragmentShader on Paint', () async { - final FragmentProgram program = await FragmentProgram.fromAsset( - 'blue_green_sampler.frag.iplr', - ); - final Image blueGreenImage = await _createBlueGreenImage(); - final ImageShader imageShader = ImageShader( - blueGreenImage, TileMode.clamp, TileMode.clamp, _identityMatrix); - - final FragmentShader shader = program.fragmentShader() - ..setSampler(0, imageShader); - shader.dispose(); - try { - final Paint paint = Paint()..shader = shader; // ignore: unused_local_variable - if (assertsEnabled) { - fail('Unreachable'); - } - } catch (e) { - expect(e.toString(), contains('Attempted to set a disposed shader')); - } - imageShader.dispose(); - blueGreenImage.dispose(); - }); - - test('Disposed FragmentShader setFloat', () async { - final FragmentProgram program = await FragmentProgram.fromAsset( - 'uniforms.frag.iplr', - ); - final FragmentShader shader = program.fragmentShader() - ..setFloat(0, 0.0); - shader.dispose(); - try { - shader.setFloat(0, 0.0); - if (assertsEnabled) { - fail('Unreachable'); - } - } catch (e) { - if (assertsEnabled) { - expect( - e.toString(), - contains('Tried to accesss uniforms on a disposed Shader'), - ); - } else { - expect(e is RangeError, true); - } - } - }); - - test('Disposed FragmentShader setSampler', () async { - final FragmentProgram program = await FragmentProgram.fromAsset( - 'blue_green_sampler.frag.iplr', - ); - final Image blueGreenImage = await _createBlueGreenImage(); - final ImageShader imageShader = ImageShader( - blueGreenImage, TileMode.clamp, TileMode.clamp, _identityMatrix); - - final FragmentShader shader = program.fragmentShader() - ..setSampler(0, imageShader); - shader.dispose(); - try { - shader.setSampler(0, imageShader); - if (assertsEnabled) { - fail('Unreachable'); - } - } on AssertionError catch (e) { - expect( - e.toString(), - contains('Tried to access uniforms on a disposed Shader'), - ); - } on StateError catch (e) { - expect( - e.toString(), - contains('the native peer has been collected'), - ); - } - imageShader.dispose(); - blueGreenImage.dispose(); - }); - - test('Disposed FragmentShader dispose', () async { - final FragmentProgram program = await FragmentProgram.fromAsset( - 'uniforms.frag.iplr', - ); - final FragmentShader shader = program.fragmentShader() - ..setFloat(0, 0.0); - shader.dispose(); - try { - shader.dispose(); - if (assertsEnabled) { - fail('Unreachable'); - } - } catch (e) { - if (assertsEnabled) { - expect(e is AssertionError, true); - } else { - expect(e is StateError, true); - } - } - }); - test('simple shader renders correctly', () async { final FragmentProgram program = await FragmentProgram.fromAsset( 'functions.frag.iplr', @@ -147,31 +21,7 @@ void main() async { final Shader shader = program.shader( floatUniforms: Float32List.fromList([1]), ); - await _expectShaderRendersGreen(shader); - }); - - test('FragmentShader simple shader renders correctly', () async { - final FragmentProgram program = await FragmentProgram.fromAsset( - 'functions.frag.iplr', - ); - final FragmentShader shader = program.fragmentShader() - ..setFloat(0, 1.0); - await _expectShaderRendersGreen(shader); - shader.dispose(); - }); - - test('Reused FragmentShader simple shader renders correctly', () async { - final FragmentProgram program = await FragmentProgram.fromAsset( - 'functions.frag.iplr', - ); - final FragmentShader shader = program.fragmentShader() - ..setFloat(0, 1.0); - await _expectShaderRendersGreen(shader); - - shader.setFloat(0, 0.0); - await _expectShaderRendersBlack(shader); - - shader.dispose(); + _expectShaderRendersGreen(shader); }); test('blue-green image renders green', () async { @@ -186,22 +36,6 @@ void main() async { samplerUniforms: [imageShader], ); await _expectShaderRendersGreen(shader); - imageShader.dispose(); - blueGreenImage.dispose(); - }); - - test('FragmentShader blue-green image renders green', () async { - final FragmentProgram program = await FragmentProgram.fromAsset( - 'blue_green_sampler.frag.iplr', - ); - final Image blueGreenImage = await _createBlueGreenImage(); - final ImageShader imageShader = ImageShader( - blueGreenImage, TileMode.clamp, TileMode.clamp, _identityMatrix); - final FragmentShader shader = program.fragmentShader() - ..setSampler(0, imageShader); - await _expectShaderRendersGreen(shader); - shader.dispose(); - imageShader.dispose(); blueGreenImage.dispose(); }); @@ -217,24 +51,9 @@ void main() async { samplerUniforms: [imageShader], ); await _expectShaderRendersGreen(shader); - imageShader.dispose(); blueGreenImage.dispose(); }); - test('FragmentShader blue-green image renders green - GPU image', () async { - final FragmentProgram program = await FragmentProgram.fromAsset( - 'blue_green_sampler.frag.iplr', - ); - final Image blueGreenImage = _createBlueGreenImageSync(); - final ImageShader imageShader = ImageShader( - blueGreenImage, TileMode.clamp, TileMode.clamp, _identityMatrix); - final FragmentShader shader = program.fragmentShader() - ..setSampler(0, imageShader); - await _expectShaderRendersGreen(shader); - shader.dispose(); - imageShader.dispose(); - blueGreenImage.dispose(); - }); test('shader with uniforms renders correctly', () async { final FragmentProgram program = await FragmentProgram.fromAsset( @@ -262,32 +81,6 @@ void main() async { expect(toFloat(renderedBytes.getUint8(3)), closeTo(1.0, epsilon)); }); - test('FragmentShader with uniforms renders correctly', () async { - final FragmentProgram program = await FragmentProgram.fromAsset( - 'uniforms.frag.iplr', - ); - - final FragmentShader shader = program.fragmentShader() - ..setFloat(0, 0.0) - ..setFloat(1, 0.25) - ..setFloat(2, 0.75) - ..setFloat(3, 0.0) - ..setFloat(4, 0.0) - ..setFloat(5, 0.0) - ..setFloat(6, 1.0); - - final ByteData renderedBytes = (await _imageByteDataFromShader( - shader: shader, - ))!; - - expect(toFloat(renderedBytes.getUint8(0)), closeTo(0.0, epsilon)); - expect(toFloat(renderedBytes.getUint8(1)), closeTo(0.25, epsilon)); - expect(toFloat(renderedBytes.getUint8(2)), closeTo(0.75, epsilon)); - expect(toFloat(renderedBytes.getUint8(3)), closeTo(1.0, epsilon)); - - shader.dispose(); - }); - test('shader with array uniforms renders correctly', () async { final FragmentProgram program = await FragmentProgram.fromAsset( 'uniform_arrays.frag.iplr', @@ -304,20 +97,6 @@ void main() async { await _expectShaderRendersGreen(shader); }); - test('FragmentShader shader with array uniforms renders correctly', () async { - final FragmentProgram program = await FragmentProgram.fromAsset( - 'uniform_arrays.frag.iplr', - ); - - final FragmentShader shader = program.fragmentShader(); - for (int i = 0; i < 24; i++) { - shader.setFloat(i, i.toDouble()); - } - - await _expectShaderRendersGreen(shader); - shader.dispose(); - }); - test('The ink_sparkle shader is accepted', () async { final FragmentProgram program = await FragmentProgram.fromAsset( 'ink_sparkle.frag.iplr', @@ -332,19 +111,6 @@ void main() async { // produces the correct pixels are in the framework. }); - test('FragmentShader The ink_sparkle shader is accepted', () async { - final FragmentProgram program = await FragmentProgram.fromAsset( - 'ink_sparkle.frag.iplr', - ); - final FragmentShader shader = program.fragmentShader(); - - await _imageByteDataFromShader(shader: shader); - - // Testing that no exceptions are thrown. Tests that the ink_sparkle shader - // produces the correct pixels are in the framework. - shader.dispose(); - }); - test('Uniforms are sorted correctly', () async { final FragmentProgram program = await FragmentProgram.fromAsset( 'uniforms_sorted.frag.iplr', @@ -361,23 +127,6 @@ void main() async { await _expectShaderRendersGreen(shader); }); - test('FragmentShader Uniforms are sorted correctly', () async { - final FragmentProgram program = await FragmentProgram.fromAsset( - 'uniforms_sorted.frag.iplr', - ); - - // The shader will not render green if the compiler doesn't keep the - // uniforms in the right order. - final FragmentShader shader = program.fragmentShader(); - for (int i = 0; i < 32; i++) { - shader.setFloat(i, i.toDouble()); - } - - await _expectShaderRendersGreen(shader); - - shader.dispose(); - }); - test('fromAsset throws an exception on invalid assetKey', () async { bool throws = false; try { @@ -412,16 +161,6 @@ void main() async { await _expectShaderRendersGreen(shader); }); - test('FragmentShader user defined functions do not redefine builtins', () async { - final FragmentProgram program = await FragmentProgram.fromAsset( - 'no_builtin_redefinition.frag.iplr', - ); - final FragmentShader shader = program.fragmentShader() - ..setFloat(0, 1.0); - await _expectShaderRendersGreen(shader); - shader.dispose(); - }); - test('fromAsset accepts a shader with no uniforms', () async { final FragmentProgram program = await FragmentProgram.fromAsset( 'no_uniforms.frag.iplr', @@ -430,15 +169,6 @@ void main() async { await _expectShaderRendersGreen(shader); }); - test('FragmentShader fromAsset accepts a shader with no uniforms', () async { - final FragmentProgram program = await FragmentProgram.fromAsset( - 'no_uniforms.frag.iplr', - ); - final FragmentShader shader = program.fragmentShader(); - await _expectShaderRendersGreen(shader); - shader.dispose(); - }); - // Test all supported GLSL ops. See lib/spirv/lib/src/constants.dart final Map iplrSupportedGLSLOpShaders = await _loadShaderAssets( path.join('supported_glsl_op_shaders', 'iplr'), @@ -446,7 +176,6 @@ void main() async { ); expect(iplrSupportedGLSLOpShaders.isNotEmpty, true); _expectIplrShadersRenderGreen(iplrSupportedGLSLOpShaders); - _expectFragmentShadersRenderGreen(iplrSupportedGLSLOpShaders); // Test all supported instructions. See lib/spirv/lib/src/constants.dart final Map iplrSupportedOpShaders = await _loadShaderAssets( @@ -455,7 +184,6 @@ void main() async { ); expect(iplrSupportedOpShaders.isNotEmpty, true); _expectIplrShadersRenderGreen(iplrSupportedOpShaders); - _expectFragmentShadersRenderGreen(iplrSupportedOpShaders); test('Equality depends on floatUniforms', () async { final FragmentProgram program = await FragmentProgram.fromAsset( @@ -504,42 +232,22 @@ void _expectIplrShadersRenderGreen(Map shaders) { final Shader shader = program.shader( floatUniforms: Float32List.fromList([1]), ); - await _expectShaderRendersGreen(shader); - }); - } -} - -void _expectFragmentShadersRenderGreen(Map programs) { - for (final String key in programs.keys) { - test('FragmentProgram $key renders green', () async { - final FragmentProgram program = programs[key]!; - final FragmentShader shader = program.fragmentShader() - ..setFloat(0, 1.0); - await _expectShaderRendersGreen(shader); - shader.dispose(); + _expectShaderRendersGreen(shader); }); } } -Future _expectShaderRendersColor(Shader shader, Color color) async { +// Expects that a spirv shader only outputs the color green. +Future _expectShaderRendersGreen(Shader shader) async { final ByteData renderedBytes = (await _imageByteDataFromShader( shader: shader, imageDimension: _shaderImageDimension, ))!; - for (final int c in renderedBytes.buffer.asUint32List()) { - expect(toHexString(c), toHexString(color.value)); + for (final int color in renderedBytes.buffer.asUint32List()) { + expect(toHexString(color), toHexString(_greenColor.value)); } } -// Expects that a shader only outputs the color green. -Future _expectShaderRendersGreen(Shader shader) { - return _expectShaderRendersColor(shader, _greenColor); -} - -Future _expectShaderRendersBlack(Shader shader) { - return _expectShaderRendersColor(shader, _blackColor); -} - Future _imageByteDataFromShader({ required Shader shader, int imageDimension = 100, @@ -589,7 +297,6 @@ Future> _loadShaderAssets( const int _shaderImageDimension = 4; const Color _greenColor = Color(0xFF00FF00); -const Color _blackColor = Color(0xFF000000); // Precision for checking uniform values. const double epsilon = 0.5 / 255.0;