npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

webgpu-spd

v2.0.1

Published

A port of AMD's Single Pass Downsampler for WebGPU

Downloads

10

Readme

WebGPU SPD

A utility library for generating up to 12 mip levels for 2d textures & texture arrays in a single WebGPU compute pass.

Docs

Find the docs here.

Try it out here.

Installation

NPM

npm install webgpu-spd

From GitHub

import { WebGPUSinglePassDownsampler } from 'https://jolifantobambla.github.io/webgpu-spd/2.x/dist/index.js';

From UNPKG

import { WebGPUSinglePassDownsampler } from 'https://unpkg.com/[email protected]/dist/index.js';

Usage

WebGPU SPD downsamples 2d textures and 2d texture arrays using compute pipelines generating up to 12 mip levels in a single pass (all array layers are processed in the same pass). The maximum number of mip levels that can be generated within a single pass depends on the maxStorageTexturesPerShaderStage limit supported by the device used. Should the number of mip levels requested for a texture exceed this limit, multiple passes, generating up to min(maxStorageTexturesPerShaderStage, 12) mip levels each, will be used instead. The mip levels generated for a given input texture are stored either in the input texture or in a separate target texture if specified. This output texture must support GPUTextureUsage.STORAGE_BINDING with access mode "write-only".

Generate mipmaps

import { WebGPUSinglePassDownsampler, maxMipLevelCount } from 'webgpu-spd';

const downsampler = new WebGPUSinglePassDownsampler();

const size = [/* size + array layers */];
const texture = device.createTexture({
    size,
    mipLevelCount: maxMipLevelCount(size[0], size[1]),
    format: 'rgba8unorm',
    usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.STORAGE_BINDING,
});

// write mip level 0

downsampler.generateMipmaps(device, texture);

Downsample a texture each frame

import { WebGPUSinglePassDownsampler, SPDFilters } from 'webgpu-spd';

// during setup
const downsampler = new WebGPUSinglePassDownsampler();
const downsampleDepthPass = downsampler.preparePass(device, linearDepthTexture, { filter: SPDFilters.Min }); 

// in render loop
const commandEncoder = device.createCommandEncoder();

const computePassEncoder = commandEncoder.beginComputePass();
downsampleDepthPass.encode(computePassEncoder);
computePassEncoder.end();

device.queue.submit([commandEncoder.finish()]);

Downsample into target

import { WebGPUSinglePassDownsampler, maxMipLevelCount } from 'webgpu-spd';

const downsampler = new WebGPUSinglePassDownsampler();

const size = [/* width, height, array layers */];
const texture = device.createTexture({
    size,
    mipLevelCount: 1,
    format: 'rgba8unorm',
    usage: GPUTextureUsage.TEXTURE_BINDING,
});
const target = device.createTexture({
    size: [size[0] / 2, size[1] / 2, size[2]],
    mipLevelCount: maxMipLevelCount(size[0], size[1]) - 1,
    format: 'rgba8unorm',
    usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.STORAGE_BINDING,
});

// write mip level 0

downsampler.generateMipmaps(device, texture, { target });

Use min-max filter to generate a min-max pyramid for single-channel textures

The SPDFilters.MinMax filter provided by WebGPU SPD is a special filter that is meant to be used with input textures using single-channel formats like "r32float", and a target texture using a two-channel format like "rg32float". After the downsampling pass, the target texture will contain the minimum values in the red channel and the maximum values in the green channel.

import { WebGPUSinglePassDownsampler, SPDFilters, maxMipLevelCount } from 'webgpu-spd';

// during setup
const downsampler = new WebGPUSinglePassDownsampler();
const linearDepth = device.createTexture({
    size: [/* gBuffer size */],
    mipLevelCount: 1,
    format: 'r32float',
    usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.STORAGE_BINDING,
});
const minMaxDepthPyramid = device.createTexture({
    size: [linearDepth.width / 2, linearDepth.height / 2],
    mipLevelCount: maxMipLevelCount(linearDepth.width, linearDepth.height) - 1
    format: 'rg32float',
    usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.STORAGE_BINDING,
});
const minMaxDepthPass = downsampler.preparePass(device, linearDepth, {
    target: minMaxDepthPyramid,
    filter: SPDFilters.MinMax,
}); 

// in render loop

// ... write mip level 0 of linearDepth

minMaxDepthPass.encode(computePassEncoder);

Prepare pipelines for expected formats

In the above examples, GPU resources, like compute pipelines and bind group layouts etc., are created on the fly the first time a new configuration of GPUDevice, GPUTextureFormat, filter, and precision is needed.

WebGPU SPD also supports allocating resources during setup, like this:

import { WebGPUSinglePassDownsampler, SPDFilters, SPDPrecision } from 'webgpu-spd';

const downsampler = new WebGPUSinglePassDownsampler({ device, formats: [
    { format: 'rgba8unorm', halfPrecision: true },
    { format: 'r32float', filters: [ SPDFilters.Min ] },
]});

// alternatively call
downsampler.prepareDeviceResources({ device, formats: [
    { format: 'rgba8unorm', halfPrecision: true },
    { format: 'r32float', filters: [ SPDFilters.Min ] },
]});

Limit the number of mip levels and array layers per pass

Generating more than 6 mip levels per pass might not be supported on each platform due to buffers being not coherent by default yet. WebGPU SPD uses min(device.limits.maxStorageTexturesPerPass, 12) by default and can thus be implicitly configured using the device's limit. However, this might not be desirable in all cases, so WebGPU SPD can be configured to use a different limit by setting the corresponding option when preparing device resources.

If more than 6 mip levels are downsampled per pass, WebGPU SPD allocates additional internal resources to store intermediate texture data (16 * 64 * 64 * maxArrayLayersPerPass bytes) and for control flow purposes (4 * maxArrayLayersPerPass bytes). The size of these resources depends on the number of array layers that can be downsampled each pass. If a texture's number of array layers exceeds the number of array layers per pass, multiple passes will be used instead. By default, WebGPU SPD uses the device's maxTextureArrayLayers limit.

WebGPU SPD can be configured to use different limits like this:

import { WebGPUSinglePassDownsampler, SPDFilters } from 'webgpu-spd';

const downsampler = new WebGPUSinglePassDownsampler({ device, maxMipsPerPass: 6, maxArrayLayersPerPass: 1 });

// alternatively call
downsampler.prepareDeviceResources({ device, maxMipsPerPass: 6, maxArrayLayersPerPass: 1 });

Handling device loss

import { WebGPUSinglePassDownsampler, SPDFilters } from 'webgpu-spd';

const formatConfigs = [
    { format: 'rgba8unorm' },
    { format: 'r32float', filters: [ SPDFilters.Min ] },
];

// on new device
downsampler.deregisterDevice(oldDevice);
downsampler.prepareDeviceResources({ device: newDevice, formats: formatConfig s});
downsampleTexturePass = downsampler.preparePass(newDevice, texture);

Use custom filters

Custom filters for downsampling a quad to a single pixel can be registered with WebGPU SPD using registerFilter. The given WGSL code must at least define a reduction function with the following name and signature:

fn spd_reduce_4(v0: vec4<SPDScalar>, v1: vec4<SPDScalar>, v2: vec4<SPDScalar>, v3: vec4<SPDScalar>) -> vec4<SPDScalar>

If a filter is known to be only used with a single scalar type (e.g., u32), uses of SPDScalar can also be replaced by that scalar type.

For example, a custom filter that only takes a single pixel value out of the four given ones could be implemented and used like this:

import { WebGPUSinglePassDownsampler } from 'webgpu-spd';

const downsampler = new WebGPUSinglePassDownsampler();
downsampler.registerFilter('upperLeft', `
    fn spd_reduce_4(v0: vec4<SPDScalar>, v1: vec4<SPDScalar>, v2: vec4<SPDScalar>, v3: vec4<SPDScalar>) -> vec4<SPDScalar> {
        return v0;
    }
`);

// ...

downsampler.generateMipmaps(device, texture, { filter: 'upperLeft' });

Downsample image region

import { WebGPUSinglePassDownsampler } from 'webgpu-spd';

const downsampler = new WebGPUSinglePassDownsampler();

const sizeHalf = [texture.width / 2, texture.height / 2];
downsampler.generateMipmaps(device, texture, { offset: sizeHalf, size: sizeHalf});

Contributions

Contributions are very welcome. If you find a bug or think some important functionality is missing, please file an issue here. If want to help out yourself, feel free to submit a pull request here.

Acknowledgements

This library is a WebGPU port of the FidelityFX Single Pass Downsampler (SPD) included in AMD's FidelityFX-SDK.