| 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 | |