Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Revert "[dart:ui] Adds a reusable FragmentShader" #35843

Merged
merged 1 commit into from
Aug 31, 2022
Merged
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
4 changes: 0 additions & 4 deletions lib/ui/dart_ui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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) \
Expand Down Expand Up @@ -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) \
Expand Down
188 changes: 37 additions & 151 deletions lib/ui/painting.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -4088,29 +4056,55 @@ class ImageShader extends Shader {
}
}

@override
void dispose() {
super.dispose();
_dispose();
}

@FfiNative<Void Function(Handle)>('ImageShader::Create')
external void _constructor();

@FfiNative<Handle Function(Pointer<Void>, Pointer<Void>, 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<Void Function(Pointer<Void>)>('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) {
Expand Down Expand Up @@ -4187,9 +4181,6 @@ class FragmentProgram extends NativeFieldWrapperClass1 {
@FfiNative<Handle Function(Pointer<Void>, 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.
///
Expand Down Expand Up @@ -4272,111 +4263,6 @@ class FragmentProgram extends NativeFieldWrapperClass1 {
external Handle _shader(_FragmentShader shader, Float32List floatUniforms, List<ImageShader> 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<Handle Function(Handle, Handle, Handle, Handle)>('ReusableFragmentShader::Create')
external Float32List _constructor(FragmentProgram program, int floatUniforms, int samplerUniforms);

@FfiNative<Void Function(Pointer<Void>, Handle, Handle)>('ReusableFragmentShader::SetSampler')
external void _setSampler(int index, ImageShader sampler);

@FfiNative<Void Function(Pointer<Void>)>('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
Expand Down
7 changes: 0 additions & 7 deletions lib/ui/painting/fragment_program.cc
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,6 @@ fml::RefPtr<FragmentShader> FragmentProgram::shader(Dart_Handle shader,
std::move(uniform_data)));
}

std::shared_ptr<DlColorSource> FragmentProgram::MakeDlColorSource(
sk_sp<SkData> float_uniforms,
const std::vector<std::shared_ptr<DlColorSource>>& children) {
return DlColorSource::MakeRuntimeEffect(runtime_effect_, std::move(children),
std::move(float_uniforms));
}

void FragmentProgram::Create(Dart_Handle wrapper) {
auto res = fml::MakeRefCounted<FragmentProgram>();
res->AssociateWithDartWrapper(wrapper);
Expand Down
7 changes: 0 additions & 7 deletions lib/ui/painting/fragment_program.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -17,8 +16,6 @@

namespace flutter {

class FragmentShader;

class FragmentProgram : public RefCountedDartWrappable<FragmentProgram> {
DEFINE_WRAPPERTYPEINFO();
FML_FRIEND_MAKE_REF_COUNTED(FragmentProgram);
Expand All @@ -33,10 +30,6 @@ class FragmentProgram : public RefCountedDartWrappable<FragmentProgram> {
Dart_Handle uniforms_handle,
Dart_Handle samplers);

std::shared_ptr<DlColorSource> MakeDlColorSource(
sk_sp<SkData> float_uniforms,
const std::vector<std::shared_ptr<DlColorSource>>& children);

private:
FragmentProgram();
sk_sp<SkRuntimeEffect> runtime_effect_;
Expand Down
72 changes: 0 additions & 72 deletions lib/ui/painting/fragment_shader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -49,75 +48,4 @@ FragmentShader::FragmentShader(

FragmentShader::~FragmentShader() = default;

IMPLEMENT_WRAPPERTYPEINFO(ui, ReusableFragmentShader);

ReusableFragmentShader::ReusableFragmentShader(
fml::RefPtr<FragmentProgram> 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<FragmentProgram*>::FromDart(program);
uint64_t float_count =
tonic::DartConverter<uint64_t>::FromDart(float_count_handle);
uint64_t sampler_count =
tonic::DartConverter<uint64_t>::FromDart(sampler_count_handle);

auto res = fml::MakeRefCounted<ReusableFragmentShader>(
fml::Ref(fragment_program), float_count, sampler_count);
res->AssociateWithDartWrapper(wrapper);

void* raw_uniform_data =
reinterpret_cast<void*>(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<uint64_t>::FromDart(index_handle);
ImageShader* sampler =
tonic::DartConverter<ImageShader*>::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<float*>(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<DlColorSource> 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
Loading