fix(effects): keep Particle World on the GPU unless Textured Square draws the Texture Layer

A Texture Layer left set with another Particle Type forced the CPU for
nothing. gpu_supported now asks the same predicate the CPU path uses.
This commit is contained in:
Marco Arnulfo committed 2026-10-30 00:52:10 +01:00
1 parent 2a5e9066e5
commit a76c65bd00
3 files changed
+11 -5

No files matched your search

+8 -3
View File
@@ -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))]));
+1
View File
@@ -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};
+2 -2
View File
@@ -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()
}