Skip to content

Repository files navigation

SequentialGPU

npm version License: ISC

A production-ready WebGPU image processing library for sequential filter processing with multi-pass support.

Introduction

SequentialGPU provides a powerful, flexible framework for GPU-accelerated image processing using the WebGPU API. Built for production use with extensive performance optimizations and comprehensive monitoring capabilities.

Key Features

  • Sequential Filter Processing - Apply multiple filters in sequence with multi-pass support
  • High Performance - 0.4ms render times with advanced GPU optimizations
  • Multiple Shader Types - Support for both fragment and compute shaders
  • Dynamic Buffer Management - Easy updating of filter parameters at runtime
  • Flexible Texture Handling - Create and manage multiple input/output textures
  • MSAA Support - Multi-sample anti-aliasing for high-quality rendering
  • Unified Statistics System - Real-time performance monitoring and analytics
  • Advanced Caching - Pipeline caching (>99% hit rate), bind group caching (85-90% hit rate)
  • Memory Management - Automatic buffer pooling, texture pooling, and resource cleanup
  • Queue System - Priority-based operation queue with async GPU operations

Requirements

  • Modern browser with WebGPU support (Chrome 113+, Edge 113+, or Firefox with flags)
  • For development: Node.js 18+ and npm

WebGPU Browser Support:

  • Chrome/Edge 113+ (stable support)
  • Firefox: Enable dom.webgpu.enabled flag
  • Safari: Experimental support in Safari Technology Preview

Table of Contents

Installation

To install the package, use npm:

npm install sequentialgpu

Quick Start

import SequentialGPU from 'sequentialgpu';

// Minimal configuration
const settings = {
    images: ['path/to/image.png'],
    presentationFormat: 'rgba8unorm',
    textures: {
        outputTexture: { label: 'Processed Output' }
    },
    filters: {
        myFilter: {
            active: true,
            type: 'render', // 'render' or 'compute'
            passes: [{
                active: true,
                inputTexture: ['texture'],
                outputTexture: undefined, // undefined = render to screen
                shaderURL: 'shaders/myshader.wgsl'
            }]
        }
    }
};

// Initialize and render
const app = await SequentialGPU.createApp(settings);
await app.loadImage(0);
await app.renderFilterPasses(settings.filters.myFilter);

Usage

Complete Configuration

The SequentialGPU module provides a WebGpuRenderer class that initializes WebGPU processing with comprehensive settings:

import SequentialGPU from 'sequentialgpu';

const settings = {
    // Image Configuration
    imageArray: ['path/to/image1.png', 'path/to/image2.png'], // or 'images' (both supported)
    presentationFormat: 'rgba8unorm', // or 'rgba16float'

    // Performance Options (Optional)
    enableCaching: true,  // Enable all caching (default: true)
    enableStats: false,   // Enable statistics tracking (default: false for performance)

    // Texture Definitions
    textures: {
      textureOneIN_OUT: {
         label: 'Processing Buffer 1',
         notes: 'Used for intermediate processing',
         format: 'rgba8unorm',        // Optional: defaults to presentationFormat
         usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT,
         sampleCount: 1,              // 1 or 4 for MSAA
      },
      textureTwoOUT_IN: {
         label: 'Processing Buffer 2'
      }
   },

    // Filter Pipeline
    filters: {
        firstFilterName: {
            label: 'First Filter Name',
            active: true,
            type: 'render', // 'render' for fragment shaders, 'compute' for compute shaders
            passes: [
                {
                    label: 'Filter 1 Pass 1',
                    active: true,
                    inputTexture: ['texture'], // 'texture' is auto-created for your loaded image
                    outputTexture: 'textureOneIN_OUT',
                    shaderURL: 'path/to/shader.wgsl'
                }
            ],
            bufferAttachment: {
                groupIndex: 0,
                bindingIndex: 3, // Bindings 0-2 reserved; custom bindings start at 3
                bindings: {
                    // Uniform buffers (for fragment/render shaders)
                    uniformKey: {
                        type: 'uniform',
                        value: 255,
                    },
                    floatKey: {
                        type: 'float',
                        value: [0.0, 0.0, 0.0, 0.0],
                    }
                }
            }
        },
        secondFilterName: {
            label: 'Second Filter Name (Compute Shader)',
            active: true,
            type: 'compute',
            passes: [
                {
                    label: 'Filter 2 Pass 1',
                    active: true,
                    inputTexture: ['textureOneIN_OUT'],
                    shaderURL: 'path/to/compute.wgsl'
                }
            ],
            bufferAttachment: {
                groupIndex: 0,
                bindingIndex: 3,
                bindings: {
                   // Storage buffers (for compute shaders)
                   dataBuffer: {
                       type: 'storage',
                       usage: 'readwrite', // 'read', 'write', or 'readwrite'
                       size: 1024,         // Required for storage buffers
                       value: new Float32Array(256),
                    }
                }
            }
        },
        thirdFilterName: {
            label: 'Third Filter Name (Multi-Pass to Screen)',
            active: true,
            type: 'render',
            passes: [
                {
                    label: 'Filter 3 Pass 1',
                    active: true,
                    inputTexture: ['textureOneIN_OUT'],
                    outputTexture: 'textureTwoOUT_IN',
                    shaderURL: 'path/to/shader.wgsl'
                },
                {
                    label: 'Filter 3 Pass 2',
                    inputTexture: ['textureTwoOUT_IN'],
                    outputTexture: 'textureTwoOUT_IN', // Reuse same texture (auto-swaps with temp)
                    shaderURL: 'path/to/shader.wgsl'
                },
                {
                    label: 'Filter 3 Pass 3',
                    inputTexture: ['textureTwoOUT_IN'],
                    outputTexture: undefined, // undefined = render to screen
                    shaderURL: 'path/to/shader.wgsl'
                }
            ],
            bufferAttachment: {
                groupIndex: 0,
                bindingIndex: 3,
                bindings: {
                    uniformKey: {
                        type: 'uniform',
                        value: 255,
                    },
                    floatKey: {
                        type: 'float',
                        value: 0.0,
                    }
                }
            }
        },
    }
};

// Initialize the app
const app = await SequentialGPU.createApp(settings).catch(error => {
   console.error("Error creating app:", error);
});

Important Notes

  1. Reserved Texture Name: texture is automatically created for your loaded image. Use it as the input for your first filter but do not create or define it in your settings.

  2. System Textures: The following are auto-created and managed:

    • texture - Main input texture for loaded images
    • textureMASS - MSAA texture (4x sampling) for anti-aliasing
    • textureTemp - Temporary buffer for ping-pong rendering
  3. Shader Files: shaderURL should point to your WGSL shader files (.wgsl format).

  4. Buffer Bindings:

    • Group 0, Binding 0: Reserved for sampler
    • Group 0, Binding 1: Reserved for first input texture
    • Group 0, Binding 2: Reserved for second input texture
    • Group 0, Binding 3+: Custom buffer attachments (your uniforms/storage)
  5. Compute Shaders:

    • Set type: 'compute'
    • Use storage buffers with type: 'storage' and specify size
    • Buffer usage: 'read', 'write', or 'readwrite'
  6. Render to Screen: Set outputTexture: undefined to render the pass output to the screen.

  7. Texture Reuse: You can use the same texture as input and output. The system automatically swaps with textureTemp to prevent conflicts.

API Reference

Factory Method

SequentialGPU.createApp(settings)

  • Creates and initializes a new WebGPU renderer instance
  • Parameters: Configuration object (see Usage)
  • Returns: Promise
  • Recommended: Use this factory method instead of direct instantiation
const app = await SequentialGPU.createApp(settings);

Core Methods

Image Management

// Load a specific image from the settings.images array
await app.loadImage(imageIndex);

// Resize canvas and recreate resources
await app.resize(width, height, resetSize);

Filter Control

// Update buffer values dynamically
app.updateFilterBuffer('intensity', 1.5);
app.updateFilterBuffer('colorMatrix', new Float32Array([1.0, 0.0, 0.0, 1.0]));

// Update input textures for a filter pass
app.updateFilterInputTexture(
    'filterName',     // Filter key
    0,                // Pass index
    1,                // Binding index
    'newTexture',     // New texture key
    0                 // Texture index
);

// Render specific filter and its passes
const isScreenRender = await app.renderFilterPasses(settings.filters.myFilter);
if (isScreenRender) {
    console.log('Rendered to screen');
}

// Wait for GPU to complete all operations
await app.waitForRenderComplete();

Resource Management

// Clean up all GPU resources
await app.dispose();

Performance Monitoring

Statistics tracking is disabled by default to maximize performance. Enable it for debugging or profiling:

const settings = {
    images: ['path/to/image.png'],
    enableStats: true,  // Enable statistics tracking
    // ... rest of settings
};

const app = await SequentialGPU.createApp(settings);

Statistics API

// Get complete statistics object
const stats = app.getStats();

// Get specific category
const renderStats = app.getStats({ category: 'render' });

// Human-readable format
const formatted = app.getFormattedStats();
console.log('Resolution:', formatted.render.canvas.resolution);
console.log('FPS:', formatted.render.fps);
console.log('Frame Time:', formatted.render.avgFrameTime);
console.log('Memory:', formatted.memory.current);
console.log('Cache Hit Rate:', formatted.pipelines.cacheHitRate);

// High-level performance overview
const summary = app.getPerformanceSummary();
console.log(`FPS: ${summary.fps}`);
console.log(`Frame Time: ${summary.frameTimeMs}ms`);
console.log(`Canvas: ${summary.canvas.resolution}`);

// Export complete stats for external analytics
const exportData = app.exportStats();

Available Statistics Categories

Category Key Metrics
Buffers totalCreated, currentActive, totalMemoryBytes, poolHits/Misses
Textures totalCreated, currentActive, poolEfficiency
Pipelines cacheHits/Misses, cacheHitRate (>99% expected), averageCompilationTimeMs
Bind Groups cacheHits/Misses, hitRate (85-90% expected), forcedRecreations
Queue totalOperations, completedOperations, averageExecutionTimeMs
Render totalFrames, framesPerSecond, averageFrameTimeMs, canvas/original dimensions
Throughput canvas.megapixelsPerSecond, original.megapixelsPerSecond
Memory currentUsageBytes, peakUsageBytes, pressureLevel

For complete statistics documentation including all fields, historical data, and multi-resolution tracking, see Stats API Quick Start and Stats API Guide.

Render Queue System

SequentialGPU includes a built-in render queue for managing GPU operations with priority-based scheduling:

// Queue operations with priority control
// Operation: Function that returns a Promise
// Priority: 'urgent', 'high', 'normal', 'low', 'background'
// Metadata: Object for tagging operations
await app.queueOperation(async () => {
    return await someAsyncOperation();
}, 'high', {
    type: 'custom',
    operation: 'myOperation',
    description: 'Custom processing task'
});

// Queue management
const status = app.getRenderQueueStatus();
const stats = app.getQueuePerformanceStats();
app.cancelRenderOperations('filterType');
app.clearRenderQueue();

Priority Levels: 'urgent' > 'high' > 'normal' (default) > 'low' > 'background'

For comprehensive queue statistics, use the unified stats system (app.getStats()) instead of legacy queue-specific methods.

Caching Control

SequentialGPU includes comprehensive caching for optimal performance (>99% cache hit rates). For debugging or testing, you can disable all caching:

const settings = {
    enableCaching: false,  // Disable all caching (default: true)
    // ... rest of settings
};

When enableCaching: false:

  • Shaders compile fresh every time
  • Pipelines are created without caching
  • Texture pooling is disabled
  • Performance will be significantly impacted

Use cases: Debugging shader compilation, testing dynamic shader modifications, performance profiling.

Production use: Always keep caching enabled (default).

For details, see Caching Control Documentation.

Advanced Features

Multi-Pass Processing

Create complex filter chains with multiple passes:

filters: {
    gaussianBlur: {
        type: 'render',
        passes: [
            {
                // Horizontal blur pass
                inputTexture: ['texture'],
                outputTexture: 'tempTexture1',
                shaderURL: 'shaders/blur-horizontal.wgsl'
            },
            {
                // Vertical blur pass
                inputTexture: ['tempTexture1'],
                outputTexture: 'tempTexture2',
                shaderURL: 'shaders/blur-vertical.wgsl'
            },
            {
                // Composite to screen
                inputTexture: ['tempTexture2'],
                outputTexture: undefined, // Render to screen
                shaderURL: 'shaders/composite.wgsl'
            }
        ]
    }
}

Dynamic Parameter Updates

Update filter parameters in real-time:

// Update single parameter
app.updateFilterBuffer('intensity', newValue);

// Update array/matrix parameter
app.updateFilterBuffer('colorMatrix', new Float32Array([
    1.0, 0.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    0.0, 0.0, 0.0, 1.0
]));

// Re-render with updated parameters
await app.renderFilterPasses(filter);

Texture Configuration

Configure custom textures with full control:

textures: {
    customBuffer: {
        label: 'Custom Processing Buffer',
        format: 'rgba16float',  // High precision
        usage: GPUTextureUsage.TEXTURE_BINDING |
               GPUTextureUsage.STORAGE_BINDING,
        sampleCount: 4,         // MSAA 4x
        notes: 'Used for HDR processing'
    }
}

Available Formats:

  • rgba8unorm, rgba16float, rgba32float - Color textures
  • r8unorm, r16float, r32float - Single-channel textures

Texture Usage Flags:

  • GPUTextureUsage.TEXTURE_BINDING - Can be sampled in shaders
  • GPUTextureUsage.RENDER_ATTACHMENT - Can be rendered to
  • GPUTextureUsage.STORAGE_BINDING - Can be written in compute shaders
  • GPUTextureUsage.COPY_SRC - Can be copied from
  • GPUTextureUsage.COPY_DST - Can be copied to

Documentation

For more detailed information, see the following documentation:

Contributing

This project is made available primarily as a resource for others to use and learn from. If you'd like to make modifications:

  1. Fork/Clone the Repository: Create your own copy of the codebase to customize for your needs
  2. Build Your Version: Make any modifications you need for your specific use case
  3. Learn and Adapt: Feel free to use any parts of this code in your own projects according to the license

While I'm not actively reviewing pull requests at this time, I hope you find this library useful as a starting point for your own WebGPU image processing implementations.

License

This project is licensed under the ISC License.

About

A WebGPU image processing API for rendering filters and their passes in sequence.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages