Skip to content

Commit

Permalink
WebGPURenderer: Fix getArrayBufferAsync in WebGPUBackend (#30132)
Browse files Browse the repository at this point in the history
  • Loading branch information
RenaudRohlinger authored Dec 16, 2024
1 parent b367df1 commit 1698253
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 17 deletions.
26 changes: 16 additions & 10 deletions examples/webgpu_compute_audio.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

let camera, scene, renderer;
let computeNode;
let computeNode, computeResetNode;
let waveBuffer, sampleRate;
let waveArray;
let waveArray, originalWaveBuffer;
let currentAudio, currentAnalyser;
const analyserBuffer = new Uint8Array( 1024 );
let analyserTexture;
Expand All @@ -49,10 +49,9 @@

if ( currentAudio ) currentAudio.stop();

await renderer.computeAsync( computeResetNode );
// compute audio

await renderer.computeAsync( computeNode );

const wave = new Float32Array( await renderer.getArrayBufferAsync( waveArray.value ) );

// play result
Expand Down Expand Up @@ -94,12 +93,14 @@

// adding extra silence to delay and pitch
waveBuffer = new Float32Array( [ ...waveBuffer, ...new Float32Array( 200000 ) ] );

originalWaveBuffer = waveBuffer.slice();

sampleRate = audioBuffer.sampleRate / audioBuffer.numberOfChannels;

// create webgpu buffers

waveArray = instancedArray( waveBuffer );
const originalWave = instancedArray( originalWaveBuffer ).toReadOnly();

// The Pixel Buffer Object (PBO) is required to get the GPU computed data to the CPU in the WebGL2 fallback.
// As used in `renderer.getArrayBufferAsync( waveArray.value )`.
Expand All @@ -113,9 +114,9 @@
const delayOffset = uniform( .55 );


// compute (shader-node)
// compute

const computeShaderFn = Fn( () => {
computeNode = Fn( () => {

const index = float( instanceIndex );

Expand Down Expand Up @@ -144,12 +145,14 @@

waveStorageElementNode.assign( wave );

} );
} )().compute( waveBuffer.length );

computeResetNode = Fn( () => {

// compute
waveArray.element( instanceIndex ).assign( originalWave.element( instanceIndex ) );

} )().compute( waveBuffer.length );

computeNode = computeShaderFn().compute( waveBuffer.length );


// gui
Expand Down Expand Up @@ -194,6 +197,9 @@

playAudioBuffer();

// on click replay
renderer.domElement.addEventListener( 'click', playAudioBuffer );

}

function onWindowResize() {
Expand Down
16 changes: 9 additions & 7 deletions src/renderers/webgpu/utils/WebGPUAttributeUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,18 +227,18 @@ class WebGPUAttributeUtils {
const device = backend.device;

const data = backend.get( this._getBufferAttribute( attribute ) );

const bufferGPU = data.buffer;
const size = bufferGPU.size;

const readBufferGPU = device.createBuffer( {
label: attribute.name,
label: `${attribute.name}_readback`,
size,
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
} );


const cmdEncoder = device.createCommandEncoder( {} );
const cmdEncoder = device.createCommandEncoder( {
label: `readback_encoder_${attribute.name}`
} );

cmdEncoder.copyBufferToBuffer(
bufferGPU,
Expand All @@ -248,16 +248,18 @@ class WebGPUAttributeUtils {
size
);

readBufferGPU.unmap();

const gpuCommands = cmdEncoder.finish();
device.queue.submit( [ gpuCommands ] );

await readBufferGPU.mapAsync( GPUMapMode.READ );

const arrayBuffer = readBufferGPU.getMappedRange();

return arrayBuffer;
const dstBuffer = new attribute.array.constructor( arrayBuffer.slice( 0 ) );

readBufferGPU.unmap();

return dstBuffer.buffer;

}

Expand Down

0 comments on commit 1698253

Please sign in to comment.