1 | // Copyright 2013 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | #include <memory> |
6 | #include <utility> |
7 | |
8 | #include "flutter/lib/ui/painting/fragment_shader.h" |
9 | |
10 | #include "flutter/display_list/dl_tile_mode.h" |
11 | #include "flutter/display_list/effects/dl_color_source.h" |
12 | #include "flutter/lib/ui/dart_wrapper.h" |
13 | #include "flutter/lib/ui/painting/fragment_program.h" |
14 | #include "flutter/lib/ui/ui_dart_state.h" |
15 | #include "third_party/skia/include/core/SkString.h" |
16 | #include "third_party/tonic/converter/dart_converter.h" |
17 | #include "third_party/tonic/dart_args.h" |
18 | #include "third_party/tonic/dart_binding_macros.h" |
19 | #include "third_party/tonic/dart_library_natives.h" |
20 | #include "third_party/tonic/typed_data/typed_list.h" |
21 | |
22 | namespace flutter { |
23 | |
24 | IMPLEMENT_WRAPPERTYPEINFO(ui, ReusableFragmentShader); |
25 | |
26 | ReusableFragmentShader::ReusableFragmentShader( |
27 | fml::RefPtr<FragmentProgram> program, |
28 | uint64_t float_count, |
29 | uint64_t sampler_count) |
30 | : program_(std::move(program)), |
31 | uniform_data_(SkData::MakeUninitialized( |
32 | length: (float_count + 2 * sampler_count) * sizeof(float))), |
33 | samplers_(sampler_count), |
34 | float_count_(float_count) {} |
35 | |
36 | Dart_Handle ReusableFragmentShader::Create(Dart_Handle wrapper, |
37 | Dart_Handle program, |
38 | Dart_Handle float_count_handle, |
39 | Dart_Handle sampler_count_handle) { |
40 | auto* fragment_program = |
41 | tonic::DartConverter<FragmentProgram*>::FromDart(handle: program); |
42 | uint64_t float_count = |
43 | tonic::DartConverter<uint64_t>::FromDart(handle: float_count_handle); |
44 | uint64_t sampler_count = |
45 | tonic::DartConverter<uint64_t>::FromDart(handle: sampler_count_handle); |
46 | |
47 | auto res = fml::MakeRefCounted<ReusableFragmentShader>( |
48 | args: fml::Ref(ptr: fragment_program), args&: float_count, args&: sampler_count); |
49 | res->AssociateWithDartWrapper(wrappable: wrapper); |
50 | |
51 | void* raw_uniform_data = |
52 | reinterpret_cast<void*>(res->uniform_data_->writable_data()); |
53 | return Dart_NewExternalTypedData(type: Dart_TypedData_kFloat32, data: raw_uniform_data, |
54 | length: float_count); |
55 | } |
56 | |
57 | bool ReusableFragmentShader::ValidateSamplers() { |
58 | for (auto i = 0u; i < samplers_.size(); i += 1) { |
59 | if (samplers_[i] == nullptr) { |
60 | return false; |
61 | } |
62 | // The samplers should have been checked as they were added, this |
63 | // is a double-sanity-check. |
64 | FML_DCHECK(samplers_[i]->isUIThreadSafe()); |
65 | } |
66 | return true; |
67 | } |
68 | |
69 | void ReusableFragmentShader::SetImageSampler(Dart_Handle index_handle, |
70 | Dart_Handle image_handle) { |
71 | uint64_t index = tonic::DartConverter<uint64_t>::FromDart(handle: index_handle); |
72 | CanvasImage* image = |
73 | tonic::DartConverter<CanvasImage*>::FromDart(handle: image_handle); |
74 | if (index >= samplers_.size()) { |
75 | Dart_ThrowException(exception: tonic::ToDart(val: "Sampler index out of bounds" )); |
76 | } |
77 | if (!image->image()->isUIThreadSafe()) { |
78 | Dart_ThrowException(exception: tonic::ToDart(val: "Image is not thread-safe" )); |
79 | } |
80 | |
81 | // TODO(115794): Once the DlImageSampling enum is replaced, expose the |
82 | // sampling options as a new default parameter for users. |
83 | samplers_[index] = std::make_shared<DlImageColorSource>( |
84 | args: image->image(), args: DlTileMode::kClamp, args: DlTileMode::kClamp, |
85 | args: DlImageSampling::kNearestNeighbor, args: nullptr); |
86 | // This should be true since we already checked the image above, but |
87 | // we check again for sanity. |
88 | FML_DCHECK(samplers_[index]->isUIThreadSafe()); |
89 | |
90 | auto* uniform_floats = |
91 | reinterpret_cast<float*>(uniform_data_->writable_data()); |
92 | uniform_floats[float_count_ + 2 * index] = image->width(); |
93 | uniform_floats[float_count_ + 2 * index + 1] = image->height(); |
94 | } |
95 | |
96 | std::shared_ptr<DlColorSource> ReusableFragmentShader::shader( |
97 | DlImageSampling sampling) { |
98 | FML_CHECK(program_); |
99 | |
100 | // The lifetime of this object is longer than a frame, and the uniforms can be |
101 | // continually changed on the UI thread. So we take a copy of the uniforms |
102 | // before handing it to the DisplayList for consumption on the render thread. |
103 | auto uniform_data = std::make_shared<std::vector<uint8_t>>(); |
104 | uniform_data->resize(sz: uniform_data_->size()); |
105 | memcpy(dest: uniform_data->data(), src: uniform_data_->bytes(), n: uniform_data->size()); |
106 | |
107 | auto source = program_->MakeDlColorSource(float_uniforms: std::move(uniform_data), children: samplers_); |
108 | // The samplers should have been checked as they were added, this |
109 | // is a double-sanity-check. |
110 | FML_DCHECK(source->isUIThreadSafe()); |
111 | return source; |
112 | } |
113 | |
114 | void ReusableFragmentShader::Dispose() { |
115 | uniform_data_.reset(); |
116 | program_ = nullptr; |
117 | samplers_.clear(); |
118 | ClearDartWrapper(); |
119 | } |
120 | |
121 | ReusableFragmentShader::~ReusableFragmentShader() = default; |
122 | |
123 | } // namespace flutter |
124 | |