UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

173 lines (170 loc) 6.63 kB
import { DebugHelper, Debug } from '../../../core/debug.js'; import { SHADERLANGUAGE_WGSL } from '../constants.js'; import { DebugGraphics } from '../debug-graphics.js'; import { ShaderProcessorGLSL } from '../shader-processor-glsl.js'; import { WebgpuDebug } from './webgpu-debug.js'; import { WebgpuShaderProcessorWGSL } from './webgpu-shader-processor-wgsl.js'; /** * @import { GraphicsDevice } from '../graphics-device.js' * @import { Shader } from '../shader.js' */ /** * A WebGPU implementation of the Shader. * * @ignore */ class WebgpuShader { /** * Free the WebGPU resources associated with a shader. * * @param {Shader} shader - The shader to free. */ destroy(shader) { this._vertexCode = null; this._fragmentCode = null; } createShaderModule(code, shaderType) { var device = this.shader.device; var wgpu = device.wgpu; WebgpuDebug.validate(device); var shaderModule = wgpu.createShaderModule({ code: code }); DebugHelper.setLabel(shaderModule, shaderType + ":" + this.shader.label); WebgpuDebug.endShader(device, shaderModule, code, 6, { shaderType, source: code, shader: this.shader }); return shaderModule; } getVertexShaderModule() { return this.createShaderModule(this._vertexCode, 'Vertex'); } getFragmentShaderModule() { return this.createShaderModule(this._fragmentCode, 'Fragment'); } getComputeShaderModule() { return this.createShaderModule(this._computeCode, 'Compute'); } processGLSL() { var shader = this.shader; // process the shader source to allow for uniforms var processed = ShaderProcessorGLSL.run(shader.device, shader.definition, shader); // keep reference to processed shaders in debug mode Debug.call(()=>{ this.processed = processed; }); this._vertexCode = this.transpile(processed.vshader, 'vertex', shader.definition.vshader); this._fragmentCode = this.transpile(processed.fshader, 'fragment', shader.definition.fshader); if (!(this._vertexCode && this._fragmentCode)) { shader.failed = true; } else { shader.ready = true; } shader.meshUniformBufferFormat = processed.meshUniformBufferFormat; shader.meshBindGroupFormat = processed.meshBindGroupFormat; shader.attributes = processed.attributes; } processWGSL() { var shader = this.shader; // process the shader source to allow for uniforms var processed = WebgpuShaderProcessorWGSL.run(shader.device, shader.definition, shader); // keep reference to processed shaders in debug mode Debug.call(()=>{ this.processed = processed; }); this._vertexCode = processed.vshader; this._fragmentCode = processed.fshader; shader.meshUniformBufferFormat = processed.meshUniformBufferFormat; shader.meshBindGroupFormat = processed.meshBindGroupFormat; shader.attributes = processed.attributes; } transpile(src, shaderType, originalSrc) { try { var spirv = this.shader.device.glslang.compileGLSL(src, shaderType); var wgsl = this.shader.device.twgsl.convertSpirV2WGSL(spirv); return wgsl; } catch (err) { console.error("Failed to transpile webgl " + shaderType + " shader [" + this.shader.label + "] to WebGPU while rendering " + DebugGraphics.toString() + ", error:\n [" + err.stack + "]", { processed: src, original: originalSrc, shader: this.shader, error: err, stack: err.stack }); } } get vertexCode() { Debug.assert(this._vertexCode); return this._vertexCode; } get fragmentCode() { Debug.assert(this._fragmentCode); return this._fragmentCode; } /** * Dispose the shader when the context has been lost. */ loseContext() {} /** * Restore shader after the context has been obtained. * * @param {GraphicsDevice} device - The graphics device. * @param {Shader} shader - The shader to restore. */ restoreContext(device, shader) {} /** * @param {Shader} shader - The shader. */ constructor(shader){ /** * Transpiled vertex shader code. * * @type {string|null} */ this._vertexCode = null; /** * Transpiled fragment shader code. * * @type {string|null} */ this._fragmentCode = null; /** * Compute shader code. * * @type {string|null} */ this._computeCode = null; /** * Name of the vertex entry point function. */ this.vertexEntryPoint = 'main'; /** * Name of the fragment entry point function. */ this.fragmentEntryPoint = 'main'; /** * Name of the compute entry point function. */ this.computeEntryPoint = 'main'; /** @type {Shader} */ this.shader = shader; var definition = shader.definition; Debug.assert(definition); if (definition.shaderLanguage === SHADERLANGUAGE_WGSL) { if (definition.cshader) { var _definition_cshader; this._computeCode = (_definition_cshader = definition.cshader) != null ? _definition_cshader : null; this.computeUniformBufferFormats = definition.computeUniformBufferFormats; this.computeBindGroupFormat = definition.computeBindGroupFormat; } else { this.vertexEntryPoint = 'vertexMain'; this.fragmentEntryPoint = 'fragmentMain'; if (definition.processingOptions) { this.processWGSL(); } else { var _definition_vshader; this._vertexCode = (_definition_vshader = definition.vshader) != null ? _definition_vshader : null; var _definition_fshader; this._fragmentCode = (_definition_fshader = definition.fshader) != null ? _definition_fshader : null; shader.meshUniformBufferFormat = definition.meshUniformBufferFormat; shader.meshBindGroupFormat = definition.meshBindGroupFormat; } } shader.ready = true; } else { if (definition.processingOptions) { this.processGLSL(); } } } } export { WebgpuShader };