1use crate::{
2 interop::{self, AsStr},
3 prelude::*,
4 Blender, ColorFilter, Data, Matrix, Shader,
5};
6use core::ffi;
7use sb::{SkFlattenable, SkRuntimeEffect_Child};
8use skia_bindings::{
9 self as sb, ShaderBuilderUniformResult, SkRefCntBase, SkRuntimeEffect, SkRuntimeEffect_Uniform,
10};
11use std::{fmt, marker::PhantomData, ops::DerefMut, ptr};
12
13pub type Uniform = Handle<SkRuntimeEffect_Uniform>;
14unsafe_send_sync!(Uniform);
15
16#[deprecated(since = "0.35.0", note = "Use Uniform instead")]
17pub type Variable = Uniform;
18
19impl NativeDrop for SkRuntimeEffect_Uniform {
20 fn drop(&mut self) {
21 panic!("native type SkRuntimeEffect::Uniform can't be owned by Rust");
22 }
23}
24
25impl fmt::Debug for Uniform {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 self.native().fmt(f)
28 }
29}
30
31impl 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
65pub 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
83pub use sb::SkRuntimeEffect_ChildType as ChildType;
84variant_name!(ChildType::Shader);
85
86#[deprecated(since = "0.41.0", note = "Use Child")]
87pub type Varying = Child;
88
89pub type Child = Handle<SkRuntimeEffect_Child>;
90unsafe_send_sync!(Child);
91
92impl NativeDrop for SkRuntimeEffect_Child {
93 fn drop(&mut self) {
94 panic!("native type SkRuntimeEffect::Child can't be owned in Rust");
95 }
96}
97
98impl fmt::Debug for Child {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 f.debug_struct("Child")
101 .field("name", &self.name())
102 .field("type", &self.ty())
103 .field("index", &self.index())
104 .finish()
105 }
106}
107
108impl 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
122pub type RuntimeEffect = RCHandle<SkRuntimeEffect>;
123
124impl NativeRefCountedBase for SkRuntimeEffect {
125 type Base = SkRefCntBase;
126}
127
128#[repr(C)]
129#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
130pub struct Options<'a> {
131 pub force_unoptimized: bool,
132 pub name: &'a str,
133}
134
135impl fmt::Debug for RuntimeEffect {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137 f.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("allow_blender", &self.allow_blender())
144 .finish()
145 }
146}
147
148impl RuntimeEffect {
149 pub fn make_for_color_filter(
150 sksl: impl AsRef<str>,
151 options: Option<&Options<'_>>,
152 ) -> Result<RuntimeEffect, String> {
153 let str = interop::String::from_str(sksl);
154 let options = options.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: Option<&Options<'_>>,
166 ) -> Result<RuntimeEffect, String> {
167 let str = interop::String::from_str(sksl);
168 let options = options.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: Option<&Options<'_>>,
180 ) -> Result<RuntimeEffect, String> {
181 let str = interop::String::from_str(sksl);
182 let options = options.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 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)]
344pub enum ChildPtr {
345 Shader(Shader),
346 ColorFilter(ColorFilter),
347 Blender(Blender),
348}
349
350impl From<Shader> for ChildPtr {
351 fn from(shader: Shader) -> Self {
352 Self::Shader(shader)
353 }
354}
355
356impl From<ColorFilter> for ChildPtr {
357 fn from(color_filter: ColorFilter) -> Self {
358 Self::ColorFilter(color_filter)
359 }
360}
361
362impl From<Blender> for ChildPtr {
363 fn from(blender: Blender) -> Self {
364 Self::Blender(blender)
365 }
366}
367
368impl 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 pub(self) fn native(&self) -> Borrows<sb::SkRuntimeEffect_ChildPtr> {
385 let flattenable: *mut SkFlattenable = match self {
386 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
403pub type RuntimeShaderBuilder = Handle<sb::SkRuntimeShaderBuilder>;
407unsafe_send_sync!(RuntimeShaderBuilder);
408
409#[derive(Debug)]
410pub enum ShaderBuilderError {
411 UniformSizeNotSupported,
412}
413impl 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}
420impl std::error::Error for ShaderBuilderError {}
421
422impl NativeDrop for sb::SkRuntimeShaderBuilder {
423 fn drop(&mut self) {
424 unsafe {
425 sb::C_SkRuntimeShaderBuilder_destruct(self);
426 }
427 }
428}
429
430impl 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 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 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
512#[cfg(test)]
513mod tests {
514 use super::*;
515
516 #[allow(unused)]
518 fn none_cases_compile() {
519 RuntimeEffect::make_for_color_filter("", None);
520 RuntimeEffect::make_for_shader("", None);
521 RuntimeEffect::make_for_blender("", None);
522 }
523}