/* * Copyright (C) 2017 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ WI.ShaderProgram = class ShaderProgram extends WI.Object { constructor(identifier, programType, canvas, {sharesVertexFragmentShader} = {}) { console.assert(identifier); console.assert(Object.values(ShaderProgram.ProgramType).includes(programType)); console.assert(canvas instanceof WI.Canvas); console.assert(ShaderProgram.contextTypeSupportsProgramType(canvas.contextType, programType)); super(); this._identifier = identifier; this._programType = programType; this._canvas = canvas; this._sharesVertexFragmentShader = !!sharesVertexFragmentShader; console.assert(!this._sharesVertexFragmentShader || (this._canvas.contextType === WI.Canvas.ContextType.WebGPU && this._programType === ShaderProgram.ProgramType.Render)); this._disabled = false; } // Static static contextTypeSupportsProgramType(contextType, programType) { switch (contextType) { case WI.Canvas.ContextType.WebGL: case WI.Canvas.ContextType.WebGL2: return programType === ShaderProgram.ProgramType.Render; case WI.Canvas.ContextType.WebGPU: return programType === ShaderProgram.ProgramType.Compute || programType === ShaderProgram.ProgramType.Render; } console.assert(); return false; } static programTypeSupportsShaderType(programType, shaderType) { switch (programType) { case ShaderProgram.ProgramType.Compute: return shaderType === ShaderProgram.ShaderType.Compute; case ShaderProgram.ProgramType.Render: return shaderType === ShaderProgram.ShaderType.Fragment || shaderType === ShaderProgram.ShaderType.Vertex; } console.assert(); return false; } // Public get identifier() { return this._identifier; } get programType() { return this._programType; } get canvas() { return this._canvas; } get sharesVertexFragmentShader() { return this._sharesVertexFragmentShader; } get displayName() { let format = null; switch (this._canvas.contextType) { case WI.Canvas.ContextType.WebGL: case WI.Canvas.ContextType.WebGL2: format = WI.UIString("Program %d"); break; case WI.Canvas.ContextType.WebGPU: switch (this._programType) { case ShaderProgram.ProgramType.Compute: format = WI.UIString("Compute Pipeline %d"); break; case ShaderProgram.ProgramType.Render: format = WI.UIString("Render Pipeline %d"); break; } break; } console.assert(format); if (!this._uniqueDisplayNumber) this._uniqueDisplayNumber = this._canvas.nextShaderProgramDisplayNumberForProgramType(this._programType); return format.format(this._uniqueDisplayNumber); } get disabled() { return this._disabled; } set disabled(disabled) { console.assert(this._programType === ShaderProgram.ProgramType.Render); console.assert(this._canvas.contextType === WI.Canvas.ContextType.WebGL || this._canvas.contextType === WI.Canvas.ContextType.WebGL2); if (this._canvas.contextType === WI.Canvas.ContextType.WebGPU) return; if (this._disabled === disabled) return; this._disabled = disabled; let target = WI.assumingMainTarget(); target.CanvasAgent.setShaderProgramDisabled(this._identifier, disabled); this.dispatchEventToListeners(ShaderProgram.Event.DisabledChanged); } requestShaderSource(shaderType, callback) { console.assert(Object.values(ShaderProgram.ShaderType).includes(shaderType)); console.assert(ShaderProgram.programTypeSupportsShaderType(this._programType, shaderType)); let target = WI.assumingMainTarget(); // COMPATIBILITY (iOS 13): `content` was renamed to `source`. target.CanvasAgent.requestShaderSource(this._identifier, shaderType, (error, source) => { if (error) { WI.reportInternalError(error); callback(null); return; } callback(source); }); } updateShader(shaderType, source) { console.assert(Object.values(ShaderProgram.ShaderType).includes(shaderType)); console.assert(ShaderProgram.programTypeSupportsShaderType(this._programType, shaderType)); let target = WI.assumingMainTarget(); target.CanvasAgent.updateShader(this._identifier, shaderType, source); } showHighlight() { console.assert(this._programType === ShaderProgram.ProgramType.Render); console.assert(this._canvas.contextType === WI.Canvas.ContextType.WebGL || this._canvas.contextType === WI.Canvas.ContextType.WebGL2); let target = WI.assumingMainTarget(); target.CanvasAgent.setShaderProgramHighlighted(this._identifier, true); } hideHighlight() { console.assert(this._programType === ShaderProgram.ProgramType.Render); console.assert(this._canvas.contextType === WI.Canvas.ContextType.WebGL || this._canvas.contextType === WI.Canvas.ContextType.WebGL2); let target = WI.assumingMainTarget(); target.CanvasAgent.setShaderProgramHighlighted(this._identifier, false); } }; WI.ShaderProgram.ProgramType = { Compute: "compute", Render: "render", }; WI.ShaderProgram.ShaderType = { Compute: "compute", Fragment: "fragment", Vertex: "vertex", }; WI.ShaderProgram.Event = { DisabledChanged: "shader-program-disabled-changed", };