Skip to content
dnjulek edited this page Jul 8, 2026 · 5 revisions

Welcome to the vapoursynth-zipcl wiki!

vszipcl is a VapourSynth plugin written in Zig that provides OpenCL-accelerated video filters. Every filter shares one architecture (a shared cl_context, a prewarmed per-stream resource pool, and a num_streams knob that actually scales), and each is a faithful port of an established reference — verified bit-exact where the reference allows.

All filters accept 8/16-bit integer, 16-bit half, and 32-bit float input (except where noted) and are multi-plane (Gray / YUV / RGB, subsampled chroma).

FILTERS

  • Bilateral: OpenCL port of VapourSynth-BilateralGPUbit-exact on integer input.
  • Deband: OpenCL port of placebo.Deband (libplacebo's pl_shader_deband).
  • EEDI3 / EEDI3H: Edge-directed interpolation (vertical / horizontal), same numeric core as the vapoursynth-zip CPU EEDI3.
  • GaussBlur: Separable Gaussian blur.
  • NLMeans: Non-local means denoiser, matching KNLMeansCL.
  • Pipeline: JSON-driven on-GPU chain of the ops above — upload once → bilateral/gaussblur/deband → download once (~2× f32 vs chaining the standalone filters).
  • MSuper / MAnalyse / MDegrain: OpenCL port of the mvtools motion-compensation trio (mvu.Super/Analyse/Degrain) — bit-exact to the CPU reference. Super & Degrain are GPU-fast; the exact motion search is a bit-exact reference (slow — see MAnalyse). GPL-2.0 (see below).

Licensing: the MV* filters are derived from GPL-2.0 mvtools code, so a compiled vszipcl.dll that includes them is distributable under the GPL-2.0-or-later (LICENSE.GPL2). The rest of the plugin is MIT.

📊 See Benchmarks — vszipcl vs each reference at 1080p YUV420 (u16/f16/f32, num_streams 1 & 2).

COMMON ARGUMENTS

Every filter takes these two optional arguments:

  • device_id (int, default: 0):
    OpenCL device index (platform 0). Out-of-range or negative values are rejected.
  • num_streams (int, default: 1, range: 1..32):
    Number of concurrent per-frame resource sets. The default of 1 serializes to one frame at a time; raise it to overlap more frames on the GPU (up to what the kernel/transfer mix can hide — 2 already captures most of the scaling). Output is bit-identical at any stream count.

BENCHMARK

RTX 3070 Ti, 1080p, decode-inclusive (bs.VideoSource), 300 frames. vszipcl wire-format support (u8/u16/f16) halves or quarters the PCIe transfer vs f32, so integer clips are often the fastest path.

# Bilateral (YUV420P8) — bit-exact vs bilateralgpu, ~1.75x faster (on-device convert, 1 byte/sample)
src.vszipcl.Bilateral()          #  ~405 fps
src.bilateralgpu.Bilateral()     #  ~231 fps

# NLMeans (YUV420P8, channels="Y", d=1, s=4)
src.vszipcl.NLMeans(channels="Y", d=1, s=4)   # u8 ~173 fps | f32 ~133 fps
src.knlm.KNLMeansCL(channels="Y", d=1, s=4)   # u8  ~80 fps

# Deband / GaussBlur (GRAY, transfer-bound — u8 ~2x f32)
src.vszipcl.Deband()      # u8 ~880 fps | f16 ~600 | f32 ~383
src.vszipcl.GaussBlur()   # u8 ~800 fps | f16 ~575 | f32 ~380

Clone this wiki locally