1 | use crate::{ |
2 | interop::{self, AsStr}, |
3 | prelude::*, |
4 | Blender, ColorFilter, Data, Matrix, Shader, |
5 | }; |
6 | use sb::{SkFlattenable, SkRuntimeEffect_Child}; |
7 | use skia_bindings::{ |
8 | self as sb, SkRefCntBase, SkRuntimeEffect, SkRuntimeEffect_Options, SkRuntimeEffect_Uniform, |
9 | }; |
10 | use std::{fmt, marker::PhantomData, ops::DerefMut, ptr}; |
11 | |
12 | pub type Uniform = Handle<SkRuntimeEffect_Uniform>; |
13 | unsafe_send_sync!(Uniform); |
14 | |
15 | #[deprecated (since = "0.35.0" , note = "Use Uniform instead" )] |
16 | pub type Variable = Uniform; |
17 | |
18 | impl NativeDrop for SkRuntimeEffect_Uniform { |
19 | fn drop(&mut self) { |
20 | panic!("native type SkRuntimeEffect::Uniform can't be owned by Rust" ); |
21 | } |
22 | } |
23 | |
24 | impl fmt::Debug for Uniform { |
25 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
26 | self.native().fmt(f) |
27 | } |
28 | } |
29 | |
30 | impl Uniform { |
31 | pub fn name(&self) -> &str { |
32 | self.native().name.as_str() |
33 | } |
34 | |
35 | pub fn offset(&self) -> usize { |
36 | self.native().offset |
37 | } |
38 | |
39 | pub fn ty(&self) -> uniform::Type { |
40 | self.native().type_ |
41 | } |
42 | |
43 | pub fn count(&self) -> i32 { |
44 | self.native().count |
45 | } |
46 | |
47 | pub fn flags(&self) -> uniform::Flags { |
48 | uniform::Flags::from_bits(self.native().flags).unwrap() |
49 | } |
50 | |
51 | pub fn is_array(&self) -> bool { |
52 | self.flags().contains(uniform::Flags::ARRAY) |
53 | } |
54 | |
55 | pub fn is_color(&self) -> bool { |
56 | self.flags().contains(uniform::Flags::COLOR) |
57 | } |
58 | |
59 | pub fn size_in_bytes(&self) -> usize { |
60 | unsafe { self.native().sizeInBytes() } |
61 | } |
62 | } |
63 | |
64 | pub mod uniform { |
65 | use skia_bindings as sb; |
66 | |
67 | pub use sb::SkRuntimeEffect_Uniform_Type as Type; |
68 | variant_name!(Type::Float2x2); |
69 | |
70 | bitflags! { |
71 | #[derive (Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
72 | pub struct Flags : u32 { |
73 | const ARRAY = sb::SkRuntimeEffect_Uniform_Flags_kArray_Flag as _; |
74 | const COLOR = sb::SkRuntimeEffect_Uniform_Flags_kColor_Flag as _; |
75 | const VERTEX = sb::SkRuntimeEffect_Uniform_Flags_kVertex_Flag as _; |
76 | const FRAGMENT = sb::SkRuntimeEffect_Uniform_Flags_kFragment_Flag as _; |
77 | const HALF_PRECISION = sb::SkRuntimeEffect_Uniform_Flags_kHalfPrecision_Flag as _; |
78 | } |
79 | } |
80 | } |
81 | |
82 | pub use sb::SkRuntimeEffect_ChildType as ChildType; |
83 | variant_name!(ChildType::Shader); |
84 | |
85 | #[deprecated (since = "0.41.0" , note = "Use Child" )] |
86 | pub type Varying = Child; |
87 | |
88 | pub type Child = Handle<SkRuntimeEffect_Child>; |
89 | unsafe_send_sync!(Child); |
90 | |
91 | impl NativeDrop for SkRuntimeEffect_Child { |
92 | fn drop(&mut self) { |
93 | panic!("native type SkRuntimeEffect::Child can't be owned in Rust" ); |
94 | } |
95 | } |
96 | |
97 | impl fmt::Debug for Child { |
98 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
99 | f&mut DebugStruct<'_, '_>.debug_struct("Child" ) |
100 | .field("name" , &self.name()) |
101 | .field("type" , &self.ty()) |
102 | .field(name:"index" , &self.index()) |
103 | .finish() |
104 | } |
105 | } |
106 | |
107 | impl Child { |
108 | pub fn name(&self) -> &str { |
109 | self.native().name.as_str() |
110 | } |
111 | |
112 | pub fn ty(&self) -> ChildType { |
113 | self.native().type_ |
114 | } |
115 | |
116 | pub fn index(&self) -> usize { |
117 | self.native().index.try_into().unwrap() |
118 | } |
119 | } |
120 | |
121 | pub type RuntimeEffect = RCHandle<SkRuntimeEffect>; |
122 | |
123 | impl NativeRefCountedBase for SkRuntimeEffect { |
124 | type Base = SkRefCntBase; |
125 | } |
126 | |
127 | #[repr (C)] |
128 | #[derive (Copy, Clone, PartialEq, Eq, Debug)] |
129 | pub struct Options { |
130 | pub force_unoptimized: bool, |
131 | use_private_rt_shader_module: bool, |
132 | max_version_allowed: sb::SkSL_Version, |
133 | } |
134 | |
135 | native_transmutable!(SkRuntimeEffect_Options, Options, options_layout); |
136 | |
137 | impl Default for Options { |
138 | fn default() -> Self { |
139 | Options { |
140 | force_unoptimized: false, |
141 | use_private_rt_shader_module: false, |
142 | max_version_allowed: sb::SkSL_Version::k100, |
143 | } |
144 | } |
145 | } |
146 | |
147 | impl fmt::Debug for RuntimeEffect { |
148 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
149 | f&mut DebugStruct<'_, '_>.debug_struct("RuntimeEffect" ) |
150 | .field("uniform_size" , &self.uniform_size()) |
151 | .field("uniforms" , &self.uniforms()) |
152 | .field("children" , &self.children()) |
153 | .field("allow_shader" , &self.allow_shader()) |
154 | .field("allow_color_filter" , &self.allow_color_filter()) |
155 | .field(name:"allow_blender" , &self.allow_blender()) |
156 | .finish() |
157 | } |
158 | } |
159 | |
160 | impl RuntimeEffect { |
161 | pub fn make_for_color_filer<'a>( |
162 | sksl: impl AsRef<str>, |
163 | options: impl Into<Option<&'a Options>>, |
164 | ) -> Result<RuntimeEffect, String> { |
165 | let str = interop::String::from_str(sksl); |
166 | let options = options.into().copied().unwrap_or_default(); |
167 | let mut error = interop::String::default(); |
168 | RuntimeEffect::from_ptr(unsafe { |
169 | sb::C_SkRuntimeEffect_MakeForColorFilter( |
170 | str.native(), |
171 | options.native(), |
172 | error.native_mut(), |
173 | ) |
174 | }) |
175 | .ok_or_else(|| error.to_string()) |
176 | } |
177 | |
178 | pub fn make_for_shader<'a>( |
179 | sksl: impl AsRef<str>, |
180 | options: impl Into<Option<&'a Options>>, |
181 | ) -> Result<RuntimeEffect, String> { |
182 | let str = interop::String::from_str(sksl); |
183 | let options = options.into().copied().unwrap_or_default(); |
184 | let mut error = interop::String::default(); |
185 | RuntimeEffect::from_ptr(unsafe { |
186 | sb::C_SkRuntimeEffect_MakeForShader(str.native(), options.native(), error.native_mut()) |
187 | }) |
188 | .ok_or_else(|| error.to_string()) |
189 | } |
190 | |
191 | pub fn make_for_blender<'a>( |
192 | sksl: impl AsRef<str>, |
193 | options: impl Into<Option<&'a Options>>, |
194 | ) -> Result<RuntimeEffect, String> { |
195 | let str = interop::String::from_str(sksl); |
196 | let options = options.into().copied().unwrap_or_default(); |
197 | let mut error = interop::String::default(); |
198 | RuntimeEffect::from_ptr(unsafe { |
199 | sb::C_SkRuntimeEffect_MakeForBlender(str.native(), options.native(), error.native_mut()) |
200 | }) |
201 | .ok_or_else(|| error.to_string()) |
202 | } |
203 | |
204 | pub fn make_shader<'a>( |
205 | &self, |
206 | uniforms: impl Into<Data>, |
207 | children: &[ChildPtr], |
208 | local_matrix: impl Into<Option<&'a Matrix>>, |
209 | ) -> Option<Shader> { |
210 | let mut children: Vec<_> = children |
211 | .iter() |
212 | .map(|child_ptr| child_ptr.native()) |
213 | .collect(); |
214 | let children_ptr = children |
215 | .first_mut() |
216 | .map(|c| c.deref_mut() as *mut _) |
217 | .unwrap_or(ptr::null_mut()); |
218 | Shader::from_ptr(unsafe { |
219 | sb::C_SkRuntimeEffect_makeShader( |
220 | self.native(), |
221 | uniforms.into().into_ptr(), |
222 | children_ptr, |
223 | children.len(), |
224 | local_matrix.into().native_ptr_or_null(), |
225 | ) |
226 | }) |
227 | } |
228 | |
229 | pub fn make_color_filter<'a>( |
230 | &self, |
231 | inputs: impl Into<Data>, |
232 | children: impl Into<Option<&'a [ChildPtr]>>, |
233 | ) -> Option<ColorFilter> { |
234 | let mut children: Vec<_> = children |
235 | .into() |
236 | .map(|c| c.iter().map(|child_ptr| child_ptr.native()).collect()) |
237 | .unwrap_or_default(); |
238 | let children_ptr = children |
239 | .first_mut() |
240 | .map(|c| c.deref_mut() as *mut _) |
241 | .unwrap_or(ptr::null_mut()); |
242 | ColorFilter::from_ptr(unsafe { |
243 | sb::C_SkRuntimeEffect_makeColorFilter( |
244 | self.native(), |
245 | inputs.into().into_ptr(), |
246 | children_ptr, |
247 | children.len(), |
248 | ) |
249 | }) |
250 | } |
251 | |
252 | pub fn make_blender<'a>( |
253 | &self, |
254 | uniforms: impl Into<Data>, |
255 | children: impl Into<Option<&'a [ChildPtr]>>, |
256 | ) -> Option<Blender> { |
257 | let mut children: Vec<_> = children |
258 | .into() |
259 | .map(|c| c.iter().map(|child_ptr| child_ptr.native()).collect()) |
260 | .unwrap_or_default(); |
261 | let children_ptr = children |
262 | .first_mut() |
263 | .map(|c| c.deref_mut() as *mut _) |
264 | .unwrap_or(ptr::null_mut()); |
265 | Blender::from_ptr(unsafe { |
266 | sb::C_SkRuntimeEffect_makeBlender( |
267 | self.native(), |
268 | uniforms.into().into_ptr(), |
269 | children_ptr, |
270 | children.len(), |
271 | ) |
272 | }) |
273 | } |
274 | |
275 | // TODO: wrap MakeTraced |
276 | |
277 | pub fn source(&self) -> &str { |
278 | let mut len = 0; |
279 | let ptr = unsafe { sb::C_SkRuntimeEffect_source(self.native(), &mut len) }; |
280 | std::str::from_utf8(unsafe { safer::from_raw_parts(ptr, len) }).unwrap() |
281 | } |
282 | |
283 | #[deprecated (since = "0.35.0" , note = "Use uniform_size() instead" )] |
284 | pub fn input_size(&self) -> usize { |
285 | self.uniform_size() |
286 | } |
287 | |
288 | pub fn uniform_size(&self) -> usize { |
289 | unsafe { self.native().uniformSize() } |
290 | } |
291 | |
292 | #[deprecated (since = "0.35.0" , note = "Use uniforms() instead" )] |
293 | pub fn inputs(&self) -> &[Uniform] { |
294 | self.uniforms() |
295 | } |
296 | |
297 | pub fn uniforms(&self) -> &[Uniform] { |
298 | unsafe { |
299 | let mut count: usize = 0; |
300 | let ptr = sb::C_SkRuntimeEffect_uniforms(self.native(), &mut count); |
301 | safer::from_raw_parts(Uniform::from_native_ptr(ptr), count) |
302 | } |
303 | } |
304 | |
305 | pub fn children(&self) -> &[Child] { |
306 | unsafe { |
307 | let mut count: usize = 0; |
308 | let ptr = sb::C_SkRuntimeEffect_children(self.native(), &mut count); |
309 | safer::from_raw_parts(Child::from_native_ptr(ptr), count) |
310 | } |
311 | } |
312 | |
313 | #[deprecated (since = "0.35.0" , note = "Use find_uniform()" )] |
314 | pub fn find_input(&self, name: impl AsRef<str>) -> Option<&Uniform> { |
315 | self.find_uniform(name) |
316 | } |
317 | |
318 | pub fn find_uniform(&self, name: impl AsRef<str>) -> Option<&Uniform> { |
319 | let name = name.as_ref().as_bytes(); |
320 | unsafe { sb::C_SkRuntimeEffect_findUniform(self.native(), name.as_ptr() as _, name.len()) } |
321 | .into_option() |
322 | .map(|ptr| Uniform::from_native_ref(unsafe { &*ptr })) |
323 | } |
324 | |
325 | pub fn find_child(&self, name: impl AsRef<str>) -> Option<&Child> { |
326 | let name = name.as_ref().as_bytes(); |
327 | unsafe { sb::C_SkRuntimeEffect_findChild(self.native(), name.as_ptr() as _, name.len()) } |
328 | .into_option() |
329 | .map(|ptr| Child::from_native_ref(unsafe { &*ptr })) |
330 | } |
331 | |
332 | pub fn allow_shader(&self) -> bool { |
333 | unsafe { sb::C_SkRuntimeEffect_allowShader(self.native()) } |
334 | } |
335 | |
336 | pub fn allow_color_filter(&self) -> bool { |
337 | unsafe { sb::C_SkRuntimeEffect_allowColorFilter(self.native()) } |
338 | } |
339 | |
340 | pub fn allow_blender(&self) -> bool { |
341 | unsafe { sb::C_SkRuntimeEffect_allowBlender(self.native()) } |
342 | } |
343 | } |
344 | |
345 | #[derive (Clone, Debug)] |
346 | pub enum ChildPtr { |
347 | Shader(Shader), |
348 | ColorFilter(ColorFilter), |
349 | Blender(Blender), |
350 | } |
351 | |
352 | impl From<Shader> for ChildPtr { |
353 | fn from(shader: Shader) -> Self { |
354 | Self::Shader(shader) |
355 | } |
356 | } |
357 | |
358 | impl From<ColorFilter> for ChildPtr { |
359 | fn from(color_filter: ColorFilter) -> Self { |
360 | Self::ColorFilter(color_filter) |
361 | } |
362 | } |
363 | |
364 | impl From<Blender> for ChildPtr { |
365 | fn from(blender: Blender) -> Self { |
366 | Self::Blender(blender) |
367 | } |
368 | } |
369 | |
370 | // TODO: Create `ChildPtr` from a Flattenable? |
371 | |
372 | impl ChildPtr { |
373 | pub fn ty(&self) -> ChildType { |
374 | match self { |
375 | ChildPtr::Shader(_) => ChildType::Shader, |
376 | ChildPtr::ColorFilter(_) => ChildType::ColorFilter, |
377 | ChildPtr::Blender(_) => ChildType::Blender, |
378 | } |
379 | } |
380 | |
381 | // We are treating [`ChildPtr`]s as a _reference_ to a smart pointer: no reference counters are |
382 | // changed (no drop() is called either). |
383 | // |
384 | // Skia will copy the pointers and increase the reference counters if it uses the actual |
385 | // objects. |
386 | pub(self) fn native(&self) -> Borrows<sb::SkRuntimeEffect_ChildPtr> { |
387 | let flattenable: *mut SkFlattenable = match self { |
388 | // casting to &T &mut T is UB, so we don't use the base() indirection and directly cast |
389 | // to a pointer. |
390 | ChildPtr::Shader(shader) => unsafe { shader.native_mut_force() as _ }, |
391 | ChildPtr::ColorFilter(color_filter) => unsafe { color_filter.native_mut_force() as _ }, |
392 | ChildPtr::Blender(blender) => unsafe { blender.native_mut_force() as _ }, |
393 | }; |
394 | |
395 | sb::SkRuntimeEffect_ChildPtr { |
396 | fChild: sb::sk_sp { |
397 | fPtr: flattenable, |
398 | _phantom_0: PhantomData, |
399 | }, |
400 | } |
401 | .borrows(self) |
402 | } |
403 | } |
404 | |
405 | // TODO: wrap SkRuntimeEffectBuilder, SkRuntimeShaderBuilder, SkRuntimeColorFilterBuilder, |
406 | // SkRuntimeBlendBuilder |
407 | |