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