Skip to content

Commit

Permalink
Suport for reading from StorageTexture by a shader (WebGPU) (#6268)
Browse files Browse the repository at this point in the history
* Suport for reading from StorageTexture by the shader (WebGPU)

* added comment

* Update src/platform/graphics/graphics-device.js

Co-authored-by: Will Eastcott <will@playcanvas.com>

---------

Co-authored-by: Martin Valigursky <mvaligursky@snapchat.com>
Co-authored-by: Will Eastcott <will@playcanvas.com>
  • Loading branch information
3 people authored Apr 19, 2024
1 parent f335f1d commit 6a57526
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 9 deletions.
27 changes: 20 additions & 7 deletions src/platform/graphics/bind-group-format.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class BindStorageBufferFormat extends BindBaseFormat {
* - {@link SHADERSTAGE_FRAGMENT}
* - {@link SHADERSTAGE_COMPUTE}
*
* @param {boolean} readOnly - Whether the storage buffer is read-only, or read-write. Defaults
* @param {boolean} [readOnly] - Whether the storage buffer is read-only, or read-write. Defaults
* to false. This has to be true for the storage buffer used in the vertex shader.
*/
constructor(name, visibility, readOnly = false) {
Expand Down Expand Up @@ -107,7 +107,7 @@ class BindTextureFormat extends BindBaseFormat {
* - {@link SHADERSTAGE_FRAGMENT}
* - {@link SHADERSTAGE_COMPUTE}
*
* @param {string} textureDimension - The dimension of the texture. Defaults to
* @param {string} [textureDimension] - The dimension of the texture. Defaults to
* {@link TEXTUREDIMENSION_2D}. Can be:
*
* - {@link TEXTUREDIMENSION_1D}
Expand All @@ -117,7 +117,7 @@ class BindTextureFormat extends BindBaseFormat {
* - {@link TEXTUREDIMENSION_CUBE_ARRAY}
* - {@link TEXTUREDIMENSION_3D}
*
* @param {number} sampleType - The type of the texture samples. Defaults to
* @param {number} [sampleType] - The type of the texture samples. Defaults to
* {@link SAMPLETYPE_FLOAT}. Can be:
*
* - {@link SAMPLETYPE_FLOAT}
Expand All @@ -126,7 +126,7 @@ class BindTextureFormat extends BindBaseFormat {
* - {@link SAMPLETYPE_INT}
* - {@link SAMPLETYPE_UINT}
*
* @param {boolean} hasSampler - True if the sampler for the texture is needed. Note that if the
* @param {boolean} [hasSampler] - True if the sampler for the texture is needed. Note that if the
* sampler is used, it will take up an additional slot, directly following the texture slot.
* Defaults to true.
*/
Expand Down Expand Up @@ -158,24 +158,37 @@ class BindStorageTextureFormat extends BindBaseFormat {
* Create a new instance.
*
* @param {string} name - The name of the storage buffer.
* @param {number} format - The pixel format of the texture. Note that not all formats can be
* @param {number} [format] - The pixel format of the texture. Note that not all formats can be
* used. Defaults to {@link PIXELFORMAT_RGBA8}.
* @param {string} textureDimension - The dimension of the texture. Defaults to
* @param {string} [textureDimension] - The dimension of the texture. Defaults to
* {@link TEXTUREDIMENSION_2D}. Can be:
*
* - {@link TEXTUREDIMENSION_1D}
* - {@link TEXTUREDIMENSION_2D}
* - {@link TEXTUREDIMENSION_2D_ARRAY}
* - {@link TEXTUREDIMENSION_3D}
*
* @param {boolean} [write] - Whether the storage texture is writeable. Defaults to true.
* @param {boolean} [read] - Whether the storage texture is readable. Defaults to false. Note
* that storage texture reads are only supported if
* {@link GraphicsDevice#supportsStorageTextureRead} is true. Also note that only a subset of
* pixel formats can be used for storage texture reads - as an example, PIXELFORMAT_RGBA8 is not
* compatible, but PIXELFORMAT_R32U is.
*/
constructor(name, format = PIXELFORMAT_RGBA8, textureDimension = TEXTUREDIMENSION_2D) {
constructor(name, format = PIXELFORMAT_RGBA8, textureDimension = TEXTUREDIMENSION_2D, write = true, read = false) {
super(name, SHADERSTAGE_COMPUTE);

// PIXELFORMAT_***
this.format = format;

// TEXTUREDIMENSION_***
this.textureDimension = textureDimension;

// whether the texture is writeable
this.write = write;

// whether the texture is readable
this.read = read;
}
}

Expand Down
14 changes: 14 additions & 0 deletions src/platform/graphics/graphics-device.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,20 @@ class GraphicsDevice extends EventHandler {
*/
supportsCompute = false;

/**
* True if the device can read from StorageTexture in the compute shader. By default, the
* storage texture can be only used with the write operation.
* When a shader uses this feature, it's recommended to use a `requires` directive to signal the
* potential for non-portability at the top of the WGSL shader code:
* ```javascript
* requires readonly_and_readwrite_storage_textures;
* ```
*
* @readonly
* @type {boolean}
*/
supportsStorageTextureRead = false;

/**
* Currently active render target.
*
Expand Down
6 changes: 4 additions & 2 deletions src/platform/graphics/webgpu/webgpu-bind-group-format.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ class WebgpuBindGroupFormat {
bindGroupFormat.storageTextureFormats.forEach((textureFormat) => {

const { format, textureDimension } = textureFormat;
key += `#${textureFormat.slot}ST:${format}-${textureDimension}`;
const { read, write } = textureFormat;
key += `#${textureFormat.slot}ST:${format}-${textureDimension}-${read ? 'r1' : 'r0'}-${write ? 'w1' : 'w0'}`;

// storage texture
entries.push({
Expand All @@ -176,7 +177,8 @@ class WebgpuBindGroupFormat {
storageTexture: {

// The access mode for this binding, indicating readability and writability.
access: 'write-only', // only single option currently, more in the future
// 'write-only' is always support, 'read-write' and 'read-only' optionally
access: read ? (write ? 'read-write' : 'read-only') : 'write-only',

// The required format of texture views bound to this binding.
format: gpuTextureFormats[format],
Expand Down
4 changes: 4 additions & 0 deletions src/platform/graphics/webgpu/webgpu-graphics-device.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ class WebgpuGraphicsDevice extends GraphicsDevice {

// WebGPU currently only supports 1 and 4 samples
this.samples = this.backBufferAntialias ? 4 : 1;

// WGSL features
const wgslFeatures = navigator.gpu.wgslLanguageFeatures;
this.supportsStorageTextureRead = wgslFeatures.has('readonly_and_readwrite_storage_textures');
}

async initWebGpu(glslangUrl, twgslUrl) {
Expand Down

0 comments on commit 6a57526

Please sign in to comment.