Skip to content

Commit

Permalink
add mechanism to ensure shaders compiled before render pass submitted
Browse files Browse the repository at this point in the history
  • Loading branch information
aardgoose committed Jul 14, 2023
1 parent 22631dd commit 468008f
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 6 deletions.
1 change: 1 addition & 0 deletions examples/jsm/renderers/common/ProgrammableStage.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class ProgrammableStage {
this.code = code;
this.stage = type;

this.compiled = false;
this.usedTimes = 0;

}
Expand Down
4 changes: 2 additions & 2 deletions examples/jsm/renderers/common/Renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ class Renderer {

}

async render( scene, camera ) {
async render( scene, camera, waitForCompilation = false ) {

if ( this._initialized === false ) await this.init();

Expand Down Expand Up @@ -300,7 +300,7 @@ class Renderer {

//

this.backend.beginRender( renderContext );
this.backend.beginRender( renderContext, waitForCompilation );

// process render lists

Expand Down
98 changes: 94 additions & 4 deletions examples/jsm/renderers/webgpu/WebGPUBackend.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ class WebGPUBackend extends Backend {
this.pipelineUtils = new WebGPUPipelineUtils( this );
this.textureUtils = new WebGPUTextureUtils( this );

this.waitForCompilation = false;
this.pendingCompilation = [];

}

async init( renderer ) {
Expand Down Expand Up @@ -130,7 +133,15 @@ class WebGPUBackend extends Backend {

}

beginRender( renderContext ) {
beginRender( renderContext, waitForCompilation = false ) {

if ( waitForCompilation ) {

this.waitForCompilation = waitForCompilation;

if ( renderContext.textures === null ) return _beginRenderSync( renderContext );

}

const renderContextData = this.get( renderContext );

Expand Down Expand Up @@ -269,13 +280,46 @@ class WebGPUBackend extends Backend {

}

finishRender( renderContext ) {
async finishRender( renderContext ) {

const renderContextData = this.get( renderContext );

if ( this.waitForCompilation ) {

let bundle;

this.waitForCompilation = false;

if ( renderContext.textures === null ) {

// currentPass is a bundle encoder here to delay getCurrentTexture() until required
// avoids attempting to render to a destroyed texture

bundle = renderContextData.currentPass.finish();

}

await Promise.all( this.pendingCompilation );

this.pendingCompilation.length = 0;

if ( renderContext.textures === null ) {

// start real pass

this.beginRender( renderContext, false );

renderContextData.currentPass.executeBundles( [ bundle ] );

}

}

renderContextData.currentPass.end();

this.device.queue.submit( [ renderContextData.encoder.finish() ] );
const commandBuffer = renderContextData.encoder.finish();

this.device.queue.submit( [ commandBuffer ] );

//

Expand Down Expand Up @@ -409,6 +453,32 @@ class WebGPUBackend extends Backend {
const passEncoderGPU = contextData.currentPass;
passEncoderGPU.setPipeline( pipelineGPU );

// check compilation status of all shaders in this pipeline

if ( this.waitForCompilation === true ) {

if ( pipeline.vertexProgram.compiled === false ) {

const vertexStage = this.get( pipeline.vertexProgram );

this.pendingCompilation.push( vertexStage.module.module.getCompilationInfo() );

pipeline.vertexProgram.compiled = true;

}

if ( pipeline.fragmentProgram.compiled === false ) {

const fragmentStage = this.get( pipeline.fragmentProgram );

this.pendingCompilation.push( fragmentStage.module.module.getCompilationInfo() );

pipeline.fragmentProgram.compiled = true;

}

}

// bind group

const bindGroupGPU = bindingsData.group;
Expand Down Expand Up @@ -593,8 +663,10 @@ class WebGPUBackend extends Backend {

const programGPU = this.get( program );

const module = this.device.createShaderModule( { code: program.code, label: program.stage } );

programGPU.module = {
module: this.device.createShaderModule( { code: program.code, label: program.stage } ),
module,
entryPoint: 'main'
};

Expand Down Expand Up @@ -829,6 +901,24 @@ class WebGPUBackend extends Backend {

}

_beginRenderSync( renderContext ) {

// path only used when texture obtained from context.getCurrentTexture() is used
// which may exipre before compilation completes if called initially

const renderContextData = this.get( renderContext );

renderContextData.currentPass = this.device.createBundleEncoder( {
colorFormats: [ GPUTextureFormat.BGRA8Unorm ],
depthStencilFormat: this._getDepthBufferGPU( renderContext ).format,
samples: this.parameters.sampleCount
} );

renderContextData.currentAttributesSet = {};

}

}


export default WebGPUBackend;

0 comments on commit 468008f

Please sign in to comment.