cables_dev/cables/src/core/cgp/cgp_state.js
- import { Logger } from "cables-shared-client";
- import { CG } from "../cg/cg_constants.js";
- import { CGState } from "../cg/cg_state.js";
- import Shader from "./cgp_shader.js";
- import defaultShaderSrcVert from "./cgl_shader_default.wgsl";
- import Texture from "./cgp_texture.js";
- import CgTexture from "../cg/cg_texture.js";
-
- // https://github.com/greggman/webgpu-utils
- // https://developer.chrome.com/blog/from-webgl-to-webgpu/
- // https://gpuweb.github.io/gpuweb/explainer/
-
-
- /**
- * cables webgpu context/state manager
- * @class
- * @namespace external:CGP
- * @hideconstructor
- */
- // const Context = function (_patch)
- class WebGpuContext extends CGState
- {
- constructor(_patch)
- {
- super();
-
- this.patch = _patch;
-
- this.lastErrorMsg = "";
-
- this._log = new Logger("WebGpuContext");
- this.gApi = CG.GAPI_WEBGPU;
- this._viewport = [0, 0, 256, 256];
- this._shaderStack = [];
- this._simpleShader = null;
- this.frame = 0;
- this.catchErrors = false;
-
- this._stackCullFaceFacing = [];
- this._stackDepthTest = [];
- this._stackCullFace = [];
- this._stackDepthFunc = [];
- this._stackDepthWrite = [];
- this._stackErrorScope = [];
- this._stackBlend = [];
- this._stackErrorScopeLogs = [];
-
- this._defaultBlend = {
- "color": {
- "operation": "add",
- "srcFactor": "one",
- "dstFactor": "zero",
- },
- "alpha": {
- "operation": "add",
- "srcFactor": "one",
- "dstFactor": "zero",
- },
- };
-
- this.DEPTH_FUNCS = [
- "never",
- "always",
- "less",
- "less-equal",
- "greater",
- "greater-equal",
- "equal",
- "not-equal"
- ];
-
- this.CULL_MODES = [
- "none",
- "back",
- "front",
- "none" // both does not exist in webgpu
- ];
- }
-
-
- /// ////////////////////
-
- // getViewPort()
- // {
- // return [0, 0, this.canvasWidth, this.canvasHeight];
- // }
-
- renderStart(cgp, identTranslate, identTranslateView)
- {
- this.frame++;
- this.pushErrorScope("cgpstate internal", "internal");
- this.pushErrorScope("cgpstate out-of-memory", "out-of-memory");
-
- if (!this._simpleShader)
- {
- this._simpleShader = new Shader(this, "simple default shader");
- this._simpleShader.setSource(defaultShaderSrcVert);
- this._simpleShader.addUniformFrag("4f", "color", [1, 1, 0, 1]);
- }
-
- this.fpsCounter.startFrame();
-
- this._startMatrixStacks(identTranslate, identTranslateView);
- this.setViewPort(0, 0, this.canvasWidth, this.canvasHeight);
-
- this.pushShader(this._simpleShader);
- this.pushDepthTest(true);
- this.pushDepthWrite(true);
- this.pushDepthFunc("less-equal");
-
-
- this.pushBlend(this._defaultBlend);
-
- this.emitEvent("beginFrame");
- }
-
- renderEnd()
- {
- this._endMatrixStacks();
-
- this.popShader();
- this.popDepthFunc();
- this.popDepthWrite();
- this.popDepthTest();
-
- this.popErrorScope();
- this.popErrorScope();
-
- if (this._stackErrorScope.length > 0)console.log("scope stack length invalid...");
-
- this.emitEvent("endFrame");
- this.fpsCounter.endFrame();
- }
-
-
- setViewPort(x, y, w, h)
- {
- this._viewport = [x, y, w, h];
- }
-
- /**
- * @function getViewPort
- * @memberof Context
- * @instance
- * @description get current gl viewport
- * @returns {Array} array [x,y,w,h]
- */
- getViewPort()
- {
- return this._viewPort;
- }
-
- createMesh(geom, glPrimitive)
- {
- return new CGP.Mesh(this, geom, glPrimitive);
- }
-
- /**
- * push a shader to the shader stack
- * @function pushShader
- * @memberof Context
- * @instance
- * @param {Object} shader
- * @function
- */
- pushShader(shader)
- {
- this._shaderStack.push(shader);
- // currentShader = shader;
- }
-
- /**
- * pop current used shader from shader stack
- * @function popShader
- * @memberof Context
- * @instance
- * @function
- */
- popShader()
- {
- if (this._shaderStack.length === 0) throw new Error("Invalid shader stack pop!");
- this._shaderStack.pop();
- // currentShader = this._shaderStack[this._shaderStack.length - 1];
- }
-
- getShader()
- {
- return this._shaderStack[this._shaderStack.length - 1];
- // if (currentShader) if (!this.frameStore || ((this.frameStore.renderOffscreen === true) == currentShader.offScreenPass) === true) return currentShader;
- // for (let i = this._shaderStack.length - 1; i >= 0; i--) if (this._shaderStack[i]) if (this.frameStore.renderOffscreen == this._shaderStack[i].offScreenPass) return this._shaderStack[i];
- }
-
- setDevice(device)
- {
- this.device = device;
-
-
- if (this._emptyTexture) this._emptyTexture = this._emptyTexture.dispose();
- if (this._defaultTexture) this._defaultTexture = this._defaultTexture.dispose();
- if (this._errorTexture) this._errorTexture = this._errorTexture.dispose();
-
- this.emitEvent("deviceChange");
- }
-
- pushErrorScope(name, options = {})
- {
- if (this.catchErrors)
- {
- this._stackErrorScope.push(name);
- this._stackErrorScopeLogs.push(options.logger || null);
- this.device.pushErrorScope(options.scope || "validation");
- }
- }
-
- popErrorScope(cb)
- {
- if (this.catchErrors)
- {
- const name = this._stackErrorScope.pop();
- const logger = this._stackErrorScopeLogs.pop();
- this.device.popErrorScope().then((error) =>
- {
- if (error)
- {
- if (this.lastErrorMsg == error.message)
- {
- // this._log.warn("last error once more...");
- }
- else
- {
- (logger || this._log).error(error.constructor.name, "in", name);
- (logger || this._log).error(error.message);
- }
- this.lastErrorMsg = error.message;
-
- if (cb)cb(error);
- }
- });
- }
- }
-
- /**
- * push depth testing enabled state
- * @function pushDepthTest
- * @param {Boolean} b enabled
- * @memberof Context
- * @instance
- */
- pushDepthTest(b)
- {
- this._stackDepthTest.push(b);
- }
-
- /**
- * current state of depth testing
- * @function stateDepthTest
- * @returns {Boolean} enabled
- * @memberof Context
- * @instance
- */
- stateDepthTest()
- {
- return this._stackDepthTest[this._stackDepthTest.length - 1];
- }
-
- /**
- * pop depth testing state
- * @function popDepthTest
- * @memberof Context
- * @instance
- */
- popDepthTest()
- {
- this._stackDepthTest.pop();
- }
-
- // --------------------------------------
- // state depthwrite
-
- /**
- * push depth write enabled state
- * @function pushDepthWrite
- * @param {Boolean} b enabled
- * @memberof Context
- * @instance
- */
- pushDepthWrite(b)
- {
- b = b || false;
- this._stackDepthWrite.push(b);
- }
-
- /**
- * current state of depth writing
- * @function stateCullFace
- * @returns {Boolean} enabled
- * @memberof Context
- * @instance
- */
- stateDepthWrite()
- {
- return this._stackDepthWrite[this._stackDepthWrite.length - 1];
- }
-
- /**
- * pop depth writing state
- * @function popCullFace
- * @memberof Context
- * @instance
- */
- popDepthWrite()
- {
- this._stackDepthWrite.pop();
- }
-
- // --------------------------------------
- // state depthfunc
-
- /**
- * @function pushDepthFunc
- * @memberof Context
- * @instance
- * @param {string} f depth compare func
- */
- pushDepthFunc(f)
- {
- this._stackDepthFunc.push(f);
- }
-
- /**
- * @function stateDepthFunc
- * @memberof Context
- * @instance
- * @returns {string}
- */
- stateDepthFunc()
- {
- if (this._stackDepthFunc.length > 0) return this._stackDepthFunc[this._stackDepthFunc.length - 1];
- return false;
- }
-
- /**
- * pop depth compare func
- * @function popDepthFunc
- * @memberof Context
- * @instance
- */
- popDepthFunc()
- {
- this._stackDepthFunc.pop();
- }
-
- // --------------------------------------
- // state CullFace
-
- /**
- * push face culling face enabled state
- * @function pushCullFace
- * @param {Boolean} b enabled
- * @memberof Context
- * @instance
- */
- pushCullFace(b)
- {
- this._stackCullFace.push(b);
- }
-
- /**
- * current state of face culling
- * @function stateCullFace
- * @returns {Boolean} enabled
- * @memberof Context
- * @instance
- */
- stateCullFace()
- {
- return this._stackCullFace[this._stackCullFace.length - 1];
- }
-
- /**
- * pop face culling enabled state
- * @function popCullFace
- * @memberof Context
- * @instance
- */
- popCullFace()
- {
- this._stackCullFace.pop();
- }
-
- // --------------------------------------
- // state CullFace Facing
-
- /**
- * push face culling face side
- * @function pushCullFaceFacing
- * @memberof Context
- * @param b
- * @instance
- */
- pushCullFaceFacing(b)
- {
- this._stackCullFaceFacing.push(b);
- }
-
- /**
- * current state of face culling side
- * @function stateCullFaceFacing
- * @returns {Boolean} enabled
- * @memberof Context
- * @instance
- */
- stateCullFaceFacing()
- {
- return this._stackCullFaceFacing[this._stackCullFaceFacing.length - 1];
- }
-
- /**
- * pop face culling face side
- * @function popCullFaceFacing
- * @memberof Context
- * @instance
- */
- popCullFaceFacing()
- {
- this._stackCullFaceFacing.pop();
- }
-
- pushBlend(b)
- {
- this._stackBlend.push(b);
- }
-
- popBlend()
- {
- this._stackBlend.pop();
- }
-
- stateBlend()
- {
- return this._stackBlend[this._stackBlend.length - 1];
- }
-
- getEmptyTexture()
- {
- if (this._emptyTexture) return this._emptyTexture;
- const size = 8;
- this._emptyTexture = new Texture(this, {});
- this._emptyTexture.initFromData(CgTexture.getDefaultTextureData("empty", size), size, size);
- return this._emptyTexture;
- }
-
- getErrorTexture()
- {
- // if (this._errorTexture) return this._errorTexture;
- const size = 256;
- this._errorTexture = new Texture(this, {});
- this._errorTexture.initFromData(CgTexture.getDefaultTextureData("stripes", size, { "r": 1, "g": 0, "b": 0 }), size, size);
- return this._errorTexture;
- }
-
- getDefaultTexture()
- {
- if (this._defaultTexture) return this._defaultTexture;
- const size = 256;
- this._defaultTexture = new Texture(this, {});
- this._defaultTexture.initFromData(CgTexture.getDefaultTextureData("stripes", size), size, size);
- return this._defaultTexture;
- }
- }
- export { WebGpuContext };