1use crate::{
2 interop::{self, AsStr},
3 prelude::*,
4 Blender, ColorFilter, Data, Matrix, Shader,
5};
6use sb::{SkFlattenable, SkRuntimeEffect_Child};
7use skia_bindings::{
8 self as sb, SkRefCntBase, SkRuntimeEffect, SkRuntimeEffect_Options, SkRuntimeEffect_Uniform,
9};
10use std::{fmt, marker::PhantomData, ops::DerefMut, ptr};
11
12pub type Uniform = Handle<SkRuntimeEffect_Uniform>;
13unsafe_send_sync!(Uniform);
14
15#[deprecated(since = "0.35.0", note = "Use Uniform instead")]
16pub type Variable = Uniform;
17
18impl NativeDrop for SkRuntimeEffect_Uniform {
19 fn drop(&mut self) {
20 panic!("native type SkRuntimeEffect::Uniform can't be owned by Rust");
21 }
22}
23
24impl fmt::Debug for Uniform {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 self.native().fmt(f)
27 }
28}
29
30impl 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
64pub 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
82pub use sb::SkRuntimeEffect_ChildType as ChildType;
83variant_name!(ChildType::Shader);
84
85#[deprecated(since = "0.41.0", note = "Use Child")]
86pub type Varying = Child;
87
88pub type Child = Handle<SkRuntimeEffect_Child>;
89unsafe_send_sync!(Child);
90
91impl NativeDrop for SkRuntimeEffect_Child {
92 fn drop(&mut self) {
93 panic!("native type SkRuntimeEffect::Child can't be owned in Rust");
94 }
95}
96
97impl 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
107impl 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
121pub type RuntimeEffect = RCHandle<SkRuntimeEffect>;
122
123impl NativeRefCountedBase for SkRuntimeEffect {
124 type Base = SkRefCntBase;
125}
126
127#[repr(C)]
128#[derive(Copy, Clone, PartialEq, Eq, Debug)]
129pub struct Options {
130 pub force_unoptimized: bool,
131 use_private_rt_shader_module: bool,
132 max_version_allowed: sb::SkSL_Version,
133}
134
135native_transmutable!(SkRuntimeEffect_Options, Options, options_layout);
136
137impl 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
147impl 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
160impl 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)]
346pub enum ChildPtr {
347 Shader(Shader),
348 ColorFilter(ColorFilter),
349 Blender(Blender),
350}
351
352impl From<Shader> for ChildPtr {
353 fn from(shader: Shader) -> Self {
354 Self::Shader(shader)
355 }
356}
357
358impl From<ColorFilter> for ChildPtr {
359 fn from(color_filter: ColorFilter) -> Self {
360 Self::ColorFilter(color_filter)
361 }
362}
363
364impl 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
372impl 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