ShaderEffect/ShaderNodeRhi/ShaderCompilerinfrastructure for mounting per-frame shader passes inside a Qt Quick scene graph, plus the zone-aware UBO extension used by the overlay.
Qt Quick's built-in ShaderEffect doesn't support multipass, compute shaders, custom UBO layouts, or shader-file #include. This library replaces it with three cooperating pieces:
ShaderEffect** — a QQuickItem subclass that owns one render node, exposes shader source and parameters as Q_PROPERTYs, and delegates uniform packing to a pluggable IUniformExtension (declared in `phosphor-shaders`).ShaderNodeRhi** — the scene-graph render node. Owns the QRhi pipeline, vertex and index buffers, the uniform buffer object (UBO), texture bindings, and per-pass targets. Supports multipass via ping-pong buffers, input-channel textures (iChannel0..3, Shadertoy-style), and writeable depth attachments.ShaderCompiler** — a runtime GLSL to SPIR-V compiler using Qt6::ShaderToolsPrivate. Feeds into Qt's shader pipeline. Caches compiled modules keyed on source-hash and target-API, so re-entering the editor doesn't recompile unchanged shaders.A second pair of types specialises the base node for the zone-overlay case: ZoneShaderNodeRhi adds a labels texture binding and zone counts in the base UBO, and ZoneUniformExtension writes zone rects, fill / border colours, and per-zone parameters into the UBO tail. They are optional. Non-zone shader effects use ShaderEffect + ShaderNodeRhi directly.
| Type | Purpose |
|---|---|
PhosphorRendering::ShaderEffect | The QQuickItem you instantiate in QML |
PhosphorRendering::ShaderNodeRhi | The QRhi-backed scene-graph node it owns |
PhosphorRendering::ShaderCompiler | GLSL to SPIR-V pipeline with on-disk cache |
PhosphorRendering::ZoneShaderNodeRhi | Zone-aware subclass: labels texture + zone counts in BaseUniforms::appField0/1 |
PhosphorRendering::ZoneShaderCommon | Shared layout constants (MaxZones, GLSL-matching struct) |
PhosphorRendering::ZoneUniformExtension | IUniformExtension writing zone rects / colours / params |
This library does not ship a QML module. A consumer registers ShaderEffect (and any subclass) with qmlRegisterType() under its own module URI, then instantiates it in QML:
qmlRegisterType<PhosphorRendering::ShaderEffect>("MyApp.Shaders", 1, 0, "ShaderEffect");
import MyApp.Shaders 1.0
ShaderEffect {
anchors.fill: parent
shaderSource: "qrc:/shaders/neon-city/effect.frag"
bufferShaderPaths: [
"qrc:/shaders/neon-city/buffer.frag"
]
// Numbered vec4 / color slots packed into the UBO (customParams1..8,
// customColor1..16):
customParams1: Qt.vector4d(0.7, 1.0, 0.35, 0.0)
customColor1: "#3B82F6"
customColor2: "#A855F7"
}A setUniformExtension() method (C++ side) attaches an IUniformExtension such as ZoneUniformExtension to feed per-zone data into the UBO tail.
ShaderNodeRhi inside the render thread. The item just carries paths and parameters. This avoids the GPU-resource-lifetime bugs that plague naive ShaderEffect reimplementations.bufferShaderPaths to a non-empty list enables the multipass path.BaseUniforms + extension. The base layout from `phosphor-shaders` is Shadertoy-compatible, and consumers attach an IUniformExtension to append application-specific data. Zone rendering uses ZoneUniformExtension, and animations use a different one declared in `phosphor-animation`.QtCore, QtGui, QtQuick, QtSvgBaseUniforms, IUniformExtensionQt6::ShaderToolsPrivate for runtime compilationShaderRegistry, parameter metadata, wallpaper provider, include resolver.