← Back

ofxNozzle

github.com/nozzle-io/ofxNozzle · @nozzle-io
OF 0.12 Graphics Utilities

openFrameworks addon for GPU texture sharing via nozzle

5 1 Last commit 4mo ago Created 5mo ago

README

ofxNozzle



This codebase is currently in its AI-slob prototyping phase: the code runs on momentum, vibes, and plausible intent.
Proper debugging will be introduced once demand graduates from hypothetical to measurable.
openFrameworks addon for GPU texture sharing via nozzle — a cross-platform alternative to Syphon (macOS) and Spout (Windows).

Shares textures between processes on the same machine using platform-native GPU interop: Metal/IOSurface on macOS, D3D11 on Windows, DMA-BUF on Linux.

Disclaimer / Notice



This library is currently a work in progress and contains many incomplete features and unverified implementations. Although it may appear usable at first glance, it may not function correctly.

Please use it with the understanding that no guarantees are made regarding its behavior, and perform debugging, validation, and review as needed. If you encounter problems, please do not become angry; instead, contributions in the form of Issues or Pull Requests would be greatly appreciated.

Platform Support



PlatformBackendStatus
macOS (Apple Silicon)Metal/IOSurfaceSupported
macOS (Intel)Metal/IOSurfaceSupported
WindowsD3D11Supported
LinuxDMA-BUFSupported

Setup



Clone into your addons/ directory:

cd <your_oF_project>/addons
git clone --recurse-submodules https://github.com/nozzle-io/ofxNozzle.git


The nozzle static library is bundled in libs/nozzle/. No separate build needed.

Usage



Sender



#include "ofxNozzle.h"

class ofApp : public ofBaseApp {
    ofFbo fbo;
    ofxNozzleSender sender;

    void setup() override {
        fbo.allocate(1920, 1080, GL_RGBA);
        sender.setup("myTextureStream");
    }

    void draw() override {
        fbo.begin();
        ofBackground(0);
        // draw your content here
        fbo.end();
        sender.publishTexture(fbo.getTexture());
    }
};


Receiver



#include "ofxNozzle.h"

class ofApp : public ofBaseApp {
    ofxNozzleReceiver receiver;

    void setup() override {
        receiver.setup("myTextureStream");
    }

    void draw() override {
        if (receiver.receive()) {
            receiver.draw(0, 0);
        }
    }
};


API Reference



ofxNozzleSender



MethodDescription
setup(name)Initialize sender with a name
close()Release resources
publishTexture(const ofTexture&)Publish ofTexture to shared texture
publishTexture(GLuint, GLenum, int, int, int)Publish raw GL texture
setMetadata(key, value)Attach metadata to published frames
isSetup()Check if initialized
getName()Get sender name

ofxNozzleReceiver



MethodDescription
setup(name, timeoutMs)Connect to sender by name. Default timeout: 0 (non-blocking)
close()Release resources
receive()Poll for new frame. Returns true if frame available
getTexture()Get the received texture as ofTexture&
draw(x, y, w, h)Draw received texture at position/size
draw(x, y)Draw at original size
isConnected()Check if sender is alive
getSenderName()Get connected sender's name

Supported GL Formats



Sender GL Formats



The sender supports 14 GL internal formats:

GL Internal Formatnozzle format
GL_R8r8_unorm
GL_RG8rg8_unorm
GL_RGBA8rgba8_unorm
GL_BGRA8_EXTbgra8_unorm
GL_SRGB8_ALPHA8rgba8_srgb
GL_R16r16_unorm
GL_RG16rg16_unorm
GL_RGBA16rgba16_unorm
GL_R16Fr16_float
GL_RG16Frg16_float
GL_RGBA16Frgba16_float
GL_R32Fr32_float
GL_RG32Frg32_float
GL_RGBA32Frgba32_float
GL_R32UIr32_uint
GL_RGBA32UIrgba32_uint
Unsized formats (GL_RGBA, GL_BGRA, GL_RGB) and 3-channel formats (GL_RGB8) are normalized to their 4-channel RGBA equivalents automatically.

Receiver GL Formats



The receiver maps nozzle formats to platform GL texture parameters. On Linux the normal receiver path binds the EGLImage imported by nozzle core from DMA-BUF metadata; the CPU upload path is an explicit fallback only:

nozzle formatGL Internal FormatGL FormatGL TypeNotes
r8_unormGL_R8GL_REDGL_UNSIGNED_BYTE
rg8_unormGL_RG8GL_RGGL_UNSIGNED_BYTE
rgba8_unormGL_RGBA8GL_BGRAGL_UNSIGNED_INT_8_8_8_8_REVNozzle converts to BGRA internally
bgra8_unormGL_RGBA8GL_BGRAGL_UNSIGNED_INT_8_8_8_8_REV
rgba8_srgbGL_RGBA8GL_BGRAGL_UNSIGNED_INT_8_8_8_8_REVCGL sRGB fallback to unorm
bgra8_srgbGL_RGBA8GL_BGRAGL_UNSIGNED_INT_8_8_8_8_REVCGL sRGB fallback to unorm
r16_unormGL_R16GL_REDGL_UNSIGNED_SHORT
rg16_unormGL_RG16GL_RGGL_UNSIGNED_SHORT
rgba16_unormGL_RGBA16FGL_RGBAGL_HALF_FLOATCGL has no GL_RGBA16, falls back to 16F
r16_floatGL_R16FGL_REDGL_HALF_FLOAT
rg16_floatGL_RG16FGL_RGGL_HALF_FLOAT
rgba16_floatGL_RGBA16FGL_RGBAGL_HALF_FLOAT
r32_floatGL_R32FGL_REDGL_FLOAT
rg32_floatGL_RG32FGL_RGGL_FLOAT
rgba32_floatGL_RGBA32FGL_RGBAGL_FLOAT
r32_uintGL_R32UIGL_RED_INTEGERGL_UNSIGNED_INT
rgba32_uintGL_RGBA32UIGL_RGBA_INTEGERGL_UNSIGNED_INT
depth32_floatGL_R32FGL_REDGL_FLOATSingle channel fallback
Integer textures require a custom shader with usampler2D / texelFetch() for correct sampling. The default openFrameworks shader will not render uint data correctly.

Architecture



All Objective-C types are hidden behind pimpl. Headers are pure C++.

Sender flow:
  User's ofTexture → publishTexture() → nozzle core → shared state

Receiver flow:
  macOS:   nozzle acquire_frame → IOSurface → CGLTexImageIOSurface2D → cached GL texture → ofTexture
  Windows: nozzle acquire_frame → D3D11 texture → glTexSubImage2D → cached GL texture → ofTexture
  Linux:   nozzle acquire_frame → DMA-BUF EGLImage → glEGLImageTargetTexture2DOES → cached GL texture → ofTexture
           fallback only: DMA-BUF mmap → glTexSubImage2D; logs as CPU fallback and ignores modifiers


Requirements



License



MIT

Third-party dependencies:

Get this addon

HTTPS
SSH