diff --git a/crates/effects/src/catalog.rs b/crates/effects/src/catalog.rs index bac2bb065..332968baf 100644 --- a/crates/effects/src/catalog.rs +++ b/crates/effects/src/catalog.rs @@ -89,12 +89,11 @@ const CPU_ONLY_CONTROLS: &[(&str, &[&str])] = &[ ("ec.distort.ccpowerpin", &["unstretch"]), ("ec.matte.refinesoft", &["reduceChatter", "useMotionBlur", "invert"]), ("ec.matte.refinehard", &["reduceChatter", "useMotionBlur", "invert"]), - ("ec.sim.ccparticleworld", &["particle/texture/textureLayer"]), ]; /// Whether the GPU kernel of effect `id` covers the instance's current settings (see -/// `CPU_ONLY_CONTROLS`; plus Cell Pattern's HQ variants and Turbulent Displace's locked -/// pinning). +/// `CPU_ONLY_CONTROLS`; plus Cell Pattern's HQ variants, Turbulent Displace's locked +/// pinning and CC Particle World's motion trails and textured squares). pub fn gpu_supported(id: &str, ctx: &crate::EffectCtx) -> bool { match id { "ec.generate.cellpattern" if (6..=10).contains(&ctx.params.e("cellPattern")) => return false, @@ -102,6 +101,8 @@ pub fn gpu_supported(id: &str, ctx: &crate::EffectCtx) -> bool { // #1195: CC Particle World's motion trails (the averaged shutter samples) render on the // CPU kernel until the GPU particle pass supports them. "ec.sim.ccparticleworld" if ctx.env.shutter.filter(|(a, _, _)| *a > 0.0).is_some() => return false, + // #1465: Textured Square's Texture Layer is drawn on the CPU only. + "ec.sim.ccparticleworld" if crate::sim::particle_world_textured(ctx) => return false, _ => {} } let Some((_, controls)) = CPU_ONLY_CONTROLS.iter().find(|(e, _)| *e == id) else { return true }; @@ -225,6 +226,10 @@ mod tests { assert!(!super::gpu_supported("ec.sim.ccparticleworld", &ctx)); } assert!(ok("ec.sim.ccparticleworld", &[])); + // #1465: the Texture Layer keeps CC Particle World on the CPU only when Textured Square draws it. + let tex = ("particle/texture/textureLayer", Value::Layer(Some(1))); + assert!(ok("ec.sim.ccparticleworld", &[tex.clone(), ("particle/particleType", Value::Enum(2))])); + assert!(!ok("ec.sim.ccparticleworld", &[tex, ("particle/particleType", Value::Enum(8))])); assert!(ok("ec.generate.cellpattern", &[("cellPattern", Value::Enum(3))])); assert!(!ok("ec.generate.cellpattern", &[("cellPattern", Value::Enum(9))])); assert!(!ok("ec.distort.turbulentdisplace", &[("pinning", Value::Enum(9))])); diff --git a/crates/effects/src/sim.rs b/crates/effects/src/sim.rs index 79a225f75..248a66178 100644 --- a/crates/effects/src/sim.rs +++ b/crates/effects/src/sim.rs @@ -32,6 +32,7 @@ use engine::{MERCURY, PS2, PW_EFFECT_CAMERA, Stepped, rate_history, sim_key, sim #[cfg(test)] pub(crate) use engine::{PState, PW_ANIMS, Phys, simulate}; pub(crate) use engine::{SPS, steps_at}; +pub(crate) use particle_fx::particle_world_textured; pub use particle_fx::{Blob, mercury_blobs}; #[cfg(test)] use particle_fx::{PW_RATE, mercury_phys, ps2_phys, pw_phys}; diff --git a/crates/effects/src/sim/particle_fx.rs b/crates/effects/src/sim/particle_fx.rs index a17a9f68b..382913964 100644 --- a/crates/effects/src/sim/particle_fx.rs +++ b/crates/effects/src/sim/particle_fx.rs @@ -41,8 +41,8 @@ const PW_TEXTURED_SQUARE: u32 = 8; pub(super) const PW_TEXTURE_LAYER: &str = "particle/texture/textureLayer"; /// Whether CC Particle World draws its Texture Layer on the particles (Textured Square with a -/// layer chosen). Only the CPU does: the Texture Layer is a CPU-only control in `catalog`. -fn particle_world_textured(ctx: &EffectCtx) -> bool { +/// layer chosen). Only the CPU does: `catalog::gpu_supported` keeps this case off the GPU. +pub(crate) fn particle_world_textured(ctx: &EffectCtx) -> bool { ctx.params.e("particle/particleType") == PW_TEXTURED_SQUARE && ctx.params.get(PW_TEXTURE_LAYER).and_then(Value::as_layer).is_some() }