Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@antv/g-webgpu-engine

Package Overview
Dependencies
Maintainers
29
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@antv/g-webgpu-engine - npm Package Compare versions

Comparing version 0.4.1 to 0.5.0

es/utils/uniform.js

12

CHANGELOG.md

@@ -6,2 +6,14 @@ # Change Log

# [0.5.0](https://github.com/xiaoiver/GWebGPUEngine/compare/v0.4.1...v0.5.0) (2020-11-06)
### Features
* ray tracer ([3fa95b9](https://github.com/xiaoiver/GWebGPUEngine/commit/3fa95b939b2dbf519ebf266b5e57bc7493258b9b))
* support unit chart ([11511a1](https://github.com/xiaoiver/GWebGPUEngine/commit/11511a17b71f82de0de48f6cd2e51cd1c09f18d7))
## [0.4.1](https://github.com/xiaoiver/GWebGPUEngine/compare/v0.4.0...v0.4.1) (2020-06-24)

@@ -8,0 +20,0 @@

584

es/webgl/index.js

@@ -1,5 +0,3 @@

import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
import _regeneratorRuntime from "@babel/runtime/regenerator";
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";

@@ -10,11 +8,17 @@ import _createClass from "@babel/runtime/helpers/createClass";

/**
* render w/ regl
* @see https://github.com/regl-project/regl/blob/gh-pages/API.md
*/
import { injectable } from 'inversify';
import isTypedArray from 'lodash/isTypedArray';
import regl from 'regl';
/* babel-plugin-inline-import './shaders/quad.vert.glsl' */
var quadVert = "attribute vec3 a_Position;\nattribute vec2 a_TexCoord;\n\nvarying vec2 v_TexCoord;\n\nvoid main() {\n gl_Position = vec4(a_Position, 1.0);\n v_TexCoord = a_TexCoord;\n}";
import ReglAttribute from './ReglAttribute';
import ReglBuffer from './ReglBuffer';
import ReglComputeModel from './ReglComputeModel';
import ReglElements from './ReglElements';
import ReglFramebuffer from './ReglFramebuffer';
import ReglModel from './ReglModel';
import ReglTexture2D from './ReglTexture2D';
/**
* implements with regl
* @see https://github.com/regl-project/regl/blob/gh-pages/API.md
* regl renderer
*/

@@ -24,113 +28,14 @@

function WebGLEngine() {
var _this = this;
_classCallCheck(this, WebGLEngine);
this.supportWebGPU = false;
this.canvas = void 0;
this.options = void 0;
this.useWGSL = false;
this.$canvas = void 0;
this.gl = void 0;
this.contextCache = {};
}
this.inited = void 0;
_createClass(WebGLEngine, [{
key: "startRecordBundle",
value: function startRecordBundle() {
throw new Error('Method not implemented.');
}
}, {
key: "stopRecordBundle",
value: function stopRecordBundle() {
throw new Error('Method not implemented.');
}
}, {
key: "executeBundles",
value: function executeBundles(bundles) {
throw new Error('Method not implemented.');
}
}, {
key: "enableScissor",
value: function enableScissor(x, y, width, height) {
throw new Error('Method not implemented.');
}
}, {
key: "disableScissor",
value: function disableScissor() {
throw new Error('Method not implemented.');
}
}, {
key: "compileRawPipelineStageDescriptor",
value: function compileRawPipelineStageDescriptor(vertexCode, fragmentCode) {
throw new Error('Method not implemented.');
}
}, {
key: "compilePipelineStageDescriptor",
value: function compilePipelineStageDescriptor(vertexCode, fragmentCode, defines) {
throw new Error('Method not implemented.');
}
}, {
key: "drawElementsType",
value: function drawElementsType(pipelineName, descriptor, indexStart, indexCount, instancesCount) {
throw new Error('Method not implemented.');
}
}, {
key: "drawArraysType",
value: function drawArraysType(pipelineName, descriptor, verticesStart, verticesCount, instancesCount) {
throw new Error('Method not implemented.');
}
}, {
key: "createVertexBuffer",
value: function createVertexBuffer(data, usage) {
throw new Error('Method not implemented.');
}
}, {
key: "createUniformBuffer",
value: function createUniformBuffer(data) {
throw new Error('Method not implemented.');
}
}, {
key: "createIndexBuffer",
value: function createIndexBuffer(data) {
throw new Error('Method not implemented.');
}
}, {
key: "createTexture",
value: function createTexture(_ref, imageData, usage) {
var _ref2 = _slicedToArray(_ref, 2),
width = _ref2[0],
height = _ref2[1];
throw new Error('Method not implemented.');
}
}, {
key: "createSampler",
value: function createSampler(descriptor) {
throw new Error('Method not implemented.');
}
}, {
key: "setRenderBindGroups",
value: function setRenderBindGroups(bindGroups) {
throw new Error('Method not implemented.');
}
}, {
key: "setSubData",
value: function setSubData(destBuffer, destOffset, srcArrayBuffer) {
throw new Error('Method not implemented.');
}
}, {
key: "bindVertexInputs",
value: function bindVertexInputs(vertexInputs) {
throw new Error('Method not implemented.');
}
}, {
key: "getDevice",
value: function getDevice() {
throw new Error('Method not implemented.');
}
}, {
key: "init",
value: function () {
var _init = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(canvas) {
var _this = this;
var options,
_args = arguments;
this.createModel = /*#__PURE__*/function () {
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(options) {
return _regeneratorRuntime.wrap(function _callee$(_context) {

@@ -140,39 +45,5 @@ while (1) {

case 0:
options = _args.length > 1 && _args[1] !== undefined ? _args[1] : {};
this.canvas = canvas;
this.options = options;
_context.next = 5;
return new Promise(function (resolve, reject) {
regl({
// @ts-ignore
canvas: _this.canvas,
attributes: {
alpha: true,
// use TAA instead of MSAA
// @see https://www.khronos.org/registry/webgl/specs/1.0/#5.2.1
antialias: options.antialiasing,
premultipliedAlpha: true
},
// TODO: use extensions
extensions: ['OES_element_index_uint', // 'EXT_shader_texture_lod', // IBL
// 'OES_standard_derivatives', // wireframe
'OES_texture_float', // must be enabled during computing
'WEBGL_depth_texture', 'angle_instanced_arrays' // 'EXT_texture_filter_anisotropic', // VSM shadow map
],
optionalExtensions: ['oes_texture_float_linear'],
profile: true,
onDone: function onDone(err, r) {
if (err || !r) {
reject(err);
}
return _context.abrupt("return", new ReglModel(_this.gl, options));
resolve(r);
}
});
});
case 5:
this.gl = _context.sent;
case 6:
case 1:
case "end":

@@ -182,229 +53,131 @@ return _context.stop();

}
}, _callee, this);
}, _callee);
}));
function init(_x) {
return _init.apply(this, arguments);
}
return function (_x) {
return _ref.apply(this, arguments);
};
}();
return init;
}()
}, {
key: "isFloatSupported",
value: function isFloatSupported() {
// @see https://github.com/antvis/GWebGPUEngine/issues/26
// @ts-ignore
return this.gl.limits.readFloat;
}
}, {
key: "compileComputePipelineStageDescriptor",
value: function () {
var _compileComputePipelineStageDescriptor = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(computeCode, context) {
var _this2 = this;
this.createAttribute = function (options) {
return new ReglAttribute(_this.gl, options);
};
var cache, uniforms, outputTextureName, outputTextureData, outputTextureSize, outputTextureTypedArrayConstructor, outputDataLength, outputTexelCount, outputElementsPerTexel, drawParams;
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
cache = this.contextCache[context.name];
this.createBuffer = function (options) {
return new ReglBuffer(_this.gl, options);
};
if (!cache) {
// @ts-ignore
cache = {
textureCache: {}
};
}
this.createElements = function (options) {
return new ReglElements(_this.gl, options);
};
uniforms = {};
outputTextureName = '';
context.uniforms.forEach(function (uniform) {
var name = uniform.name,
type = uniform.type,
data = uniform.data,
format = uniform.format; // 使用纹理存储
this.createTexture2D = function (options) {
return new ReglTexture2D(_this.gl, options);
};
if (type === 'sampler2D') {
var elementsPerTexel = 1;
this.createFramebuffer = function (options) {
return new ReglFramebuffer(_this.gl, options);
};
if (format.endsWith('ec4[]')) {
elementsPerTexel = 4;
} else if (format.endsWith('ec3[]')) {
elementsPerTexel = 3;
} else if (format.endsWith('ec2[]')) {
elementsPerTexel = 2;
} // 用 0 补全不足 vec4 的部分
this.useFramebuffer = function (framebuffer, drawCommands) {
_this.gl({
framebuffer: framebuffer ? framebuffer.get() : null
})(drawCommands);
};
this.createComputeModel = /*#__PURE__*/function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(context) {
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
return _context2.abrupt("return", new ReglComputeModel(_this.gl, context));
var paddingData = [];
case 1:
case "end":
return _context2.stop();
}
}
}, _callee2);
}));
for (var i = 0; i < data.length; i += elementsPerTexel) {
if (elementsPerTexel === 1) {
paddingData.push(data[i], 0, 0, 0);
} else if (elementsPerTexel === 2) {
paddingData.push(data[i], data[i + 1], 0, 0);
} else if (elementsPerTexel === 3) {
paddingData.push(data[i], data[i + 1], data[i + 2], 0);
} else if (elementsPerTexel === 4) {
paddingData.push(data[i], data[i + 1], data[i + 2], data[i + 3]);
}
}
return function (_x2) {
return _ref2.apply(this, arguments);
};
}();
var originalDataLength = data.length;
var texelCount = Math.ceil(originalDataLength / elementsPerTexel);
var width = Math.ceil(Math.sqrt(texelCount));
var paddingTexelCount = width * width;
this.clear = function (options) {
// @see https://github.com/regl-project/regl/blob/gh-pages/API.md#clear-the-draw-buffer
var color = options.color,
depth = options.depth,
stencil = options.stencil,
_options$framebuffer = options.framebuffer,
framebuffer = _options$framebuffer === void 0 ? null : _options$framebuffer;
var reglClearOptions = {
color: color,
depth: depth,
stencil: stencil
};
reglClearOptions.framebuffer = framebuffer === null ? framebuffer : framebuffer.get();
if (texelCount < paddingTexelCount) {
paddingData.push.apply(paddingData, _toConsumableArray(new Array((paddingTexelCount - texelCount) * 4).fill(0)));
}
_this.gl.clear(reglClearOptions);
};
if (name === context.output.name) {
outputTextureName = name;
outputTextureData = paddingData;
outputDataLength = originalDataLength;
outputTextureSize = width;
outputTexelCount = texelCount;
outputElementsPerTexel = elementsPerTexel;
this.viewport = function (_ref3) {
var x = _ref3.x,
y = _ref3.y,
width = _ref3.width,
height = _ref3.height;
if (isTypedArray(data)) {
outputTextureTypedArrayConstructor = data.constructor;
}
}
if (_this.gl && _this.gl._gl) {
// use WebGL context directly
// @see https://github.com/regl-project/regl/blob/gh-pages/API.md#unsafe-escape-hatch
_this.gl._gl.viewport(x, y, width, height);
var uniformTexture = _this2.gl.texture({
width: width,
height: width,
data: paddingData,
type: 'float'
});
_this.gl._refresh();
}
};
cache.textureCache[name] = uniformTexture; // 需要动态获取,有可能在运行时通过 setBinding 关联到另一个计算程序的输出
// @ts-ignore
this.readPixels = function (options) {
var framebuffer = options.framebuffer,
x = options.x,
y = options.y,
width = options.width,
height = options.height;
var readPixelsOptions = {
x: x,
y: y,
width: width,
height: height
};
uniforms[name] = context.maxIteration > 1 && context.needPingpong ? cache.textureCache[name] : function () {
return cache.textureCache[name];
}; // @ts-ignore
if (framebuffer) {
readPixelsOptions.framebuffer = framebuffer.get();
}
uniforms["".concat(name, "Size")] = [width, width];
} else {
if (data && (Array.isArray(data) || isTypedArray(data)) && data.length > 16) {
// 最多支持到 mat4 包含 16 个元素
throw new Error("invalid data type ".concat(type));
} // @ts-ignore
return _this.gl.read(readPixelsOptions);
};
this.getCanvas = function () {
return _this.$canvas;
};
uniforms[name] = function () {
return uniform.data;
};
}
}); // 传入 output 纹理尺寸和数据长度,便于多余的 texel 提前退出
// @ts-ignore
this.getGLContext = function () {
return _this.gl._gl;
};
uniforms.u_OutputTextureSize = [outputTextureSize, outputTextureSize]; // @ts-ignore
this.destroy = function () {
if (_this.gl) {
// @see https://github.com/regl-project/regl/blob/gh-pages/API.md#clean-up
_this.gl.destroy();
uniforms.u_OutputTexelCount = outputTexelCount; // 大于一次且 输入输出均为自身的 认为需要 pingpong
if (context.maxIteration > 1 && context.needPingpong) {
// @ts-ignore
cache.texInput = uniforms[outputTextureName]; // @ts-ignore
uniforms[outputTextureName] = function () {
return cache.texInput;
};
cache.texOutput = this.gl.texture({
width: outputTextureSize,
height: outputTextureSize,
data: outputTextureData,
type: 'float'
});
} else {
cache.texOutput = this.gl.texture({
width: outputTextureSize,
height: outputTextureSize,
type: 'float'
});
}
context.output.typedArrayConstructor = outputTextureTypedArrayConstructor;
context.output.length = outputDataLength;
context.output.outputElementsPerTexel = outputElementsPerTexel;
drawParams = {
attributes: {
a_Position: [[-1, 1, 0], [-1, -1, 0], [1, 1, 0], [1, -1, 0]],
a_TexCoord: [[0, 1], [0, 0], [1, 1], [1, 0]]
},
frag: computeCode,
uniforms: uniforms,
vert: quadVert,
// TODO: use a fullscreen triangle instead.
primitive: 'triangle strip',
count: 4
};
cache.computeCommand = this.gl(drawParams);
this.contextCache[context.name] = cache;
return _context2.abrupt("return", {
computeStage: {
// @ts-ignore
module: {
label: 'compute'
},
entryPoint: 'main'
}
});
case 15:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
function compileComputePipelineStageDescriptor(_x2, _x3) {
return _compileComputePipelineStageDescriptor.apply(this, arguments);
_this.inited = false;
}
};
}
return compileComputePipelineStageDescriptor;
}()
}, {
key: "confirmInput",
value: function confirmInput(contextName, textureName, referContextName) {
var cache = this.contextCache[contextName];
var referCache = this.contextCache[referContextName];
if (cache && referCache) {
// 需要 pingpong 的都有 texInput
cache.textureCache[textureName] = referCache.texInput || referCache.texOutput;
}
}
}, {
key: "dispatch",
value: function dispatch(context) {
var cache = this.contextCache[context.name];
if (cache) {
cache.texFBO = this.gl.framebuffer({
color: cache.texOutput
});
cache.texFBO.use(function () {
cache.computeCommand();
}); // 需要 swap
if (context.maxIteration > 1 && context.needPingpong) {
var tmp = cache.texOutput;
cache.texOutput = cache.texInput;
cache.texInput = tmp;
}
}
}
}, {
key: "readData",
_createClass(WebGLEngine, [{
key: "init",
value: function () {
var _readData = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(context) {
var _this3 = this;
var cache, pixels, _context$output, length, outputElementsPerTexel, _context$output$typed, typedArrayConstructor, formattedPixels, i;
var _init = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(cfg) {
return _regeneratorRuntime.wrap(function _callee3$(_context3) {

@@ -414,45 +187,46 @@ while (1) {

case 0:
cache = this.contextCache[context.name];
if (!cache) {
_context3.next = 8;
if (!this.inited) {
_context3.next = 2;
break;
}
this.gl({
framebuffer: cache.texFBO
})(function () {
pixels = _this3.gl.read();
}); // @ts-ignore
return _context3.abrupt("return");
if (!pixels) {
_context3.next = 8;
break;
}
case 2:
this.$canvas = cfg.canvas; // tslint:disable-next-line:typedef
_context$output = context.output, length = _context$output.length, outputElementsPerTexel = _context$output.outputElementsPerTexel, _context$output$typed = _context$output.typedArrayConstructor, typedArrayConstructor = _context$output$typed === void 0 ? Float32Array : _context$output$typed;
formattedPixels = [];
_context3.next = 5;
return new Promise(function (resolve, reject) {
regl({
canvas: cfg.canvas,
attributes: {
alpha: true,
// use TAA instead of MSAA
// @see https://www.khronos.org/registry/webgl/specs/1.0/#5.2.1
antialias: cfg.antialias,
premultipliedAlpha: true,
preserveDrawingBuffer: true
},
// TODO: use extensions
extensions: ['OES_element_index_uint', 'OES_texture_float', 'OES_standard_derivatives', // wireframe
'angle_instanced_arrays' // VSM shadow map
],
optionalExtensions: ['EXT_texture_filter_anisotropic', 'EXT_blend_minmax', 'WEBGL_depth_texture'],
profile: true,
onDone: function onDone(err, r) {
if (err || !r) {
reject(err);
} // @ts-ignore
if (outputElementsPerTexel !== 4) {
for (i = 0; i < pixels.length; i += 4) {
if (outputElementsPerTexel === 1) {
formattedPixels.push(pixels[i]);
} else if (outputElementsPerTexel === 2) {
formattedPixels.push(pixels[i], pixels[i + 1]);
} else {
formattedPixels.push(pixels[i], pixels[i + 1], pixels[i + 2]);
resolve(r);
}
}
} else {
// @ts-ignore
formattedPixels = pixels;
} // 截取多余的部分
});
});
case 5:
this.gl = _context3.sent;
this.inited = true;
return _context3.abrupt("return", new typedArrayConstructor(formattedPixels.slice(0, length)));
case 8:
return _context3.abrupt("return", new Float32Array());
case 9:
case 7:
case "end":

@@ -465,30 +239,16 @@ return _context3.stop();

function readData(_x4) {
return _readData.apply(this, arguments);
function init(_x3) {
return _init.apply(this, arguments);
}
return readData;
return init;
}()
}, {
key: "setComputePipeline",
value: function setComputePipeline(computePipelineName, descriptor) {//
key: "isFloatSupported",
value: function isFloatSupported() {
// @see https://github.com/antvis/GWebGPUEngine/issues/26
// @ts-ignore
return this.gl.limits.readFloat;
}
}, {
key: "setComputeBindGroups",
value: function setComputeBindGroups(bindGroups) {//
}
}, {
key: "clear",
value: function clear(color, backBuffer, depth) {
var stencil = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
if (!Array.isArray(color)) {
color = [color.r, color.g, color.b, color.a];
}
this.gl.clear({
color: color
}); // TODO: depth & stencil
}
}, {
key: "beginFrame",

@@ -499,11 +259,3 @@ value: function beginFrame() {//

key: "endFrame",
value: function endFrame() {} //
/**
* Dispose and release all associated resources
*/
}, {
key: "dispose",
value: function dispose() {// this.dataTextures.forEach((d) => d.destroy());
value: function endFrame() {//
}

@@ -510,0 +262,0 @@ }]);

import _regeneratorRuntime from "@babel/runtime/regenerator";
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
// import glslangInit from '@webgpu/glslang/dist/web-devel/glslang.onefile';
// @ts-nocheck

@@ -4,0 +5,0 @@

@@ -1,4 +0,1 @@

import _defineProperty from "@babel/runtime/helpers/defineProperty";
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
import _regeneratorRuntime from "@babel/runtime/regenerator";

@@ -11,13 +8,8 @@ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
/**
* implements renderService with WebGPU API
* @see https://webgpu.io/
* @see https://github.com/BabylonJS/Babylon.js/blob/WebGPU/src/Engines/webgpuEngine.ts
* 主要修改
* * 使用最新 GPUBuffer API
* * ComputePipeline
*/
import { isSafari } from '@antv/g-webgpu-core'; // tslint:disable-next-line:no-submodule-imports
import { isSafari } from '@antv/g-webgpu-core'; // import { Glslang } from '@webgpu/glslang/dist/web-devel/glslang.onefile';

@@ -27,7 +19,22 @@ import * as WebGPUConstants from '@webgpu/types/dist/constants';

import glslang from './glslang';
export var WebGPUEngine = (_dec = injectable(), _dec(_class = (_temp = /*#__PURE__*/function () {
import WebGPUAttribute from './WebGPUAttribute';
import WebGPUBuffer from './WebGPUBuffer';
import WebGPUComputeModel from './WebGPUComputeModel';
import WebGPUElements from './WebGPUElements';
import WebGPUFramebuffer from './WebGPUFramebuffer';
import WebGPUModel from './WebGPUModel';
import WebGPUTexture2D from './WebGPUTexture2D';
export
/**
* regl renderer
*/
var WebGPUEngine = (_dec = injectable(), _dec(_class = (_temp = /*#__PURE__*/function () {
function WebGPUEngine() {
var _this = this;
_classCallCheck(this, WebGPUEngine);
this.supportWebGPU = true;
this.useWGSL = false;
this.options = void 0;
this.canvas = void 0;

@@ -39,4 +46,2 @@ this.context = void 0;

this.swapChain = void 0;
this.pipelines = {};
this.computePipelines = {};
this.mainPassSampleCount = void 0;

@@ -51,11 +56,11 @@ this.mainTexture = void 0;

this.computeEncoder = void 0;
this.commandBuffers = new Array(3).fill(undefined);
this.renderTargetEncoder = void 0;
this.commandBuffers = new Array(4).fill(undefined);
this.currentRenderPass = null;
this.mainRenderPass = null;
this.currentRenderTargetViewDescriptor = void 0;
this.currentComputePass = null;
this.bundleEncoder = void 0;
this.tempBuffers = [];
this.options = void 0;
this.defaultSampleCount = 4;
this.clearDepthValue = 1;
this.clearStencilValue = 0;
this.currentRenderTarget = null;
this.uploadEncoderDescriptor = {

@@ -67,28 +72,62 @@ label: 'upload'

};
this.renderTargetEncoderDescriptor = {
label: 'renderTarget'
};
this.computeEncoderDescriptor = {
label: 'compute'
};
}
this.pipelines = {};
this.computePipelines = {};
this.defaultSampleCount = 4;
this.clearDepthValue = 1;
this.clearStencilValue = 0;
this.transientViewport = {
x: Infinity,
y: 0,
width: 0,
height: 0
};
this.cachedViewport = {
x: 0,
y: 0,
width: 0,
height: 0
};
_createClass(WebGPUEngine, [{
key: "isFloatSupported",
value: function isFloatSupported() {
return true;
}
}, {
key: "getDevice",
value: function getDevice() {
return this.device;
}
}, {
key: "getSwapChain",
value: function getSwapChain() {
return this.swapChain;
}
}, {
key: "init",
value: function () {
var _init = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(canvas) {
var options,
_args = arguments;
this.clear = function (options) {
var framebuffer = options.framebuffer,
color = options.color,
depth = options.depth,
stencil = options.stencil;
if (_this.options.supportCompute) {
_this.startComputePass();
} // We need to recreate the render pass so that the new parameters for clear color / depth / stencil are taken into account
if (_this.currentRenderTarget) {
if (_this.currentRenderPass) {
_this.endRenderTargetRenderPass();
}
_this.startRenderTargetRenderPass(_this.currentRenderTarget, color ? color : null, !!depth, !!stencil);
} else {
// if (this.useReverseDepthBuffer) {
// this._depthCullingState.depthFunc = Constants.GREATER;
// }
_this.mainColorAttachments[0].loadValue = color ? color : WebGPUConstants.LoadOp.Load;
_this.mainDepthAttachment.depthLoadValue = depth ? depth : WebGPUConstants.LoadOp.Load;
_this.mainDepthAttachment.stencilLoadValue = stencil ? _this.clearStencilValue : WebGPUConstants.LoadOp.Load;
if (_this.mainRenderPass) {
_this.endMainRenderPass();
}
_this.startMainRenderPass();
}
};
this.createModel = /*#__PURE__*/function () {
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(options) {
var model;
return _regeneratorRuntime.wrap(function _callee$(_context) {

@@ -98,14 +137,10 @@ while (1) {

case 0:
options = _args.length > 1 && _args[1] !== undefined ? _args[1] : {};
this.canvas = canvas;
this.options = options;
this.mainPassSampleCount = options.antialiasing ? this.defaultSampleCount : 1;
_context.next = 6;
return this.initGlslang();
model = new WebGPUModel(_this, options);
_context.next = 3;
return model.init();
case 6:
this.initContextAndSwapChain();
this.initMainAttachments();
case 3:
return _context.abrupt("return", model);
case 8:
case 4:
case "end":

@@ -115,145 +150,53 @@ return _context.stop();

}
}, _callee, this);
}, _callee);
}));
function init(_x) {
return _init.apply(this, arguments);
}
return function (_x) {
return _ref.apply(this, arguments);
};
}();
return init;
}()
}, {
key: "beginFrame",
value: function beginFrame() {
this.uploadEncoder = this.device.createCommandEncoder(this.uploadEncoderDescriptor);
this.renderEncoder = this.device.createCommandEncoder(this.renderEncoderDescriptor);
this.computeEncoder = this.device.createCommandEncoder(this.computeEncoderDescriptor);
}
}, {
key: "endFrame",
value: function endFrame() {
// this.endRenderPass();
if (this.options.supportCompute) {
this.endComputePass();
} else {
this.endRenderPass();
}
this.createAttribute = function (options) {
return new WebGPUAttribute(_this, options);
};
this.commandBuffers[0] = this.uploadEncoder.finish();
this.commandBuffers[1] = this.renderEncoder.finish();
this.commandBuffers[2] = this.computeEncoder.finish();
this.createBuffer = function (options) {
return new WebGPUBuffer(_this, options);
};
if (isSafari) {
// @ts-ignore
this.device.getQueue().submit(this.commandBuffers);
} else {
this.device.defaultQueue.submit(this.commandBuffers);
}
this.createElements = function (options) {
return new WebGPUElements(_this, options);
};
this.tempBuffers.forEach(function (buffer) {
return buffer.destroy();
});
this.tempBuffers = [];
}
/**
* Start recording all the gpu calls into a bundle.
* @see https://zhuanlan.zhihu.com/p/99993704
*/
this.createTexture2D = function (options) {
return new WebGPUTexture2D(_this, options);
};
}, {
key: "startRecordBundle",
value: function startRecordBundle() {
this.bundleEncoder = this.device.createRenderBundleEncoder({
colorFormats: [WebGPUConstants.TextureFormat.BGRA8Unorm],
depthStencilFormat: WebGPUConstants.TextureFormat.Depth24PlusStencil8,
sampleCount: this.mainPassSampleCount
});
}
/**
* Stops recording the bundle.
* @returns the recorded bundle
*/
this.createFramebuffer = function (options) {
return new WebGPUFramebuffer(_this, options);
};
}, {
key: "stopRecordBundle",
value: function stopRecordBundle() {
var bundle = this.bundleEncoder.finish();
this.bundleEncoder = null;
return bundle;
}
/**
* Execute the previously recorded bundle.
* @param bundles defines the bundle to replay
*/
}, {
key: "executeBundles",
value: function executeBundles(bundles) {
var _this$currentRenderPa;
if (!this.currentRenderPass) {
this.startMainRenderPass();
this.useFramebuffer = function (framebuffer, drawCommands) {
// bind
if (_this.currentRenderTarget) {
_this.unbindFramebuffer(_this.currentRenderTarget);
}
(_this$currentRenderPa = this.currentRenderPass) === null || _this$currentRenderPa === void 0 ? void 0 : _this$currentRenderPa.executeBundles(bundles);
}
}, {
key: "enableScissor",
value: function enableScissor(x, y, width, height) {
if (!this.currentRenderPass) {
this.startMainRenderPass();
}
_this.currentRenderTarget = framebuffer; // TODO: use mipmap options in framebuffer
this.currentRenderPass.setScissorRect(x, y, width, height);
}
}, {
key: "disableScissor",
value: function disableScissor() {
var _this$currentRenderPa2;
_this.currentRenderTargetViewDescriptor = {
dimension: WebGPUConstants.TextureViewDimension.E2d,
// mipLevelCount: bindWithMipMaps ? WebGPUTextureHelper.computeNumMipmapLevels(texture.width, texture.height) - lodLevel : 1,
// baseArrayLayer: faceIndex,
// baseMipLevel: lodLevel,
arrayLayerCount: 1,
aspect: WebGPUConstants.TextureAspect.All
};
_this.currentRenderPass = null;
drawCommands();
};
if (!this.currentRenderPass) {
this.startMainRenderPass();
}
(_this$currentRenderPa2 = this.currentRenderPass) === null || _this$currentRenderPa2 === void 0 ? void 0 : _this$currentRenderPa2.setScissorRect(0, 0, this.canvas.width, this.canvas.height);
}
}, {
key: "setSize",
value: function setSize(width, height) {
this.initMainAttachments();
}
}, {
key: "clear",
value: function clear(color, backBuffer, depth) {
var stencil = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
this.mainColorAttachments[0].loadValue = backBuffer ? color : WebGPUConstants.LoadOp.Load;
this.mainDepthAttachment.depthLoadValue = depth ? this.clearDepthValue : WebGPUConstants.LoadOp.Load;
this.mainDepthAttachment.stencilLoadValue = stencil ? this.clearStencilValue : WebGPUConstants.LoadOp.Load; // this.startMainRenderPass();
if (this.options.supportCompute) {
this.startComputePass();
} else {
this.startMainRenderPass();
}
}
/**
* Dispose and release all associated resources
*/
}, {
key: "dispose",
value: function dispose() {
if (this.mainTexture) {
this.mainTexture.destroy();
}
if (this.depthTexture) {
this.depthTexture.destroy();
}
}
}, {
key: "compileRawPipelineStageDescriptor",
value: function () {
var _compileRawPipelineStageDescriptor = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(vertexCode, fragmentCode) {
var vertexShader, fragmentShader;
this.createComputeModel = /*#__PURE__*/function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(context) {
var model;
return _regeneratorRuntime.wrap(function _callee2$(_context2) {

@@ -263,15 +206,10 @@ while (1) {

case 0:
_context2.next = 2;
return this.compileRawShaderToSpirV(vertexCode, 'vertex');
model = new WebGPUComputeModel(_this, context);
_context2.next = 3;
return model.init();
case 2:
vertexShader = _context2.sent;
_context2.next = 5;
return this.compileRawShaderToSpirV(fragmentCode, 'fragment');
case 3:
return _context2.abrupt("return", model);
case 5:
fragmentShader = _context2.sent;
return _context2.abrupt("return", this.createPipelineStageDescriptor(vertexShader, fragmentShader));
case 7:
case 4:
case "end":

@@ -281,16 +219,65 @@ return _context2.stop();

}
}, _callee2, this);
}, _callee2);
}));
function compileRawPipelineStageDescriptor(_x2, _x3) {
return _compileRawPipelineStageDescriptor.apply(this, arguments);
return function (_x2) {
return _ref2.apply(this, arguments);
};
}();
this.getCanvas = function () {
return _this.canvas;
};
this.getGLContext = function () {
throw new Error('Method not implemented.');
};
this.viewport = function (_ref3) {
var x = _ref3.x,
y = _ref3.y,
width = _ref3.width,
height = _ref3.height;
if (!_this.currentRenderPass) {
// call viewport() before current render pass created
_this.transientViewport = {
x: x,
y: y,
width: width,
height: height
};
} else if (_this.transientViewport.x !== Infinity) {
var renderPass = _this.getCurrentRenderPass(); // @see https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-setviewport
renderPass.setViewport(_this.transientViewport.x, _this.transientViewport.y, _this.transientViewport.width, _this.transientViewport.height, 0, 1);
} else if (x !== _this.cachedViewport.x || y !== _this.cachedViewport.y || width !== _this.cachedViewport.width || height !== _this.cachedViewport.height) {
_this.cachedViewport = {
x: x,
y: y,
width: width,
height: height
};
var _renderPass = _this.getCurrentRenderPass();
_renderPass.setViewport(x, y, width, height, 0, 1);
}
};
return compileRawPipelineStageDescriptor;
}()
this.readPixels = function (options) {
throw new Error('Method not implemented.');
};
}
_createClass(WebGPUEngine, [{
key: "isFloatSupported",
value: function isFloatSupported() {
return true;
}
}, {
key: "compilePipelineStageDescriptor",
key: "init",
value: function () {
var _compilePipelineStageDescriptor = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(vertexCode, fragmentCode, defines) {
var shaderVersion, vertexShader, fragmentShader;
var _init = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(config) {
return _regeneratorRuntime.wrap(function _callee3$(_context3) {

@@ -300,14 +287,12 @@ while (1) {

case 0:
shaderVersion = '#version 450\n';
_context3.next = 3;
return this.compileShaderToSpirV(vertexCode, 'vertex', shaderVersion);
case 3:
vertexShader = _context3.sent;
this.canvas = config.canvas;
this.options = config;
this.useWGSL = !!config.useWGSL;
this.mainPassSampleCount = config.antialiasing ? this.defaultSampleCount : 1;
_context3.next = 6;
return this.compileShaderToSpirV(fragmentCode, 'fragment', shaderVersion);
return this.initGlslang();
case 6:
fragmentShader = _context3.sent;
return _context3.abrupt("return", this.createPipelineStageDescriptor(vertexShader, fragmentShader));
this.initContextAndSwapChain();
this.initMainAttachments();

@@ -322,402 +307,105 @@ case 8:

function compilePipelineStageDescriptor(_x4, _x5, _x6) {
return _compilePipelineStageDescriptor.apply(this, arguments);
function init(_x3) {
return _init.apply(this, arguments);
}
return compilePipelineStageDescriptor;
return init;
}()
}, {
key: "compileComputePipelineStageDescriptor",
value: function () {
var _compileComputePipelineStageDescriptor = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(computeCode, context) {
var computeShader, shaderVersion;
return _regeneratorRuntime.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
if (!isSafari) {
_context4.next = 4;
break;
}
key: "destroy",
value: function destroy() {
if (this.mainTexture) {
this.mainTexture.destroy();
}
computeShader = computeCode;
_context4.next = 8;
break;
case 4:
shaderVersion = '#version 450\n';
_context4.next = 7;
return this.compileShaderToSpirV(computeCode, 'compute', shaderVersion);
case 7:
computeShader = _context4.sent;
case 8:
return _context4.abrupt("return", {
computeStage: {
module: this.device.createShaderModule({
code: computeShader,
// @ts-ignore
isWHLSL: isSafari
}),
entryPoint: 'main'
}
});
case 9:
case "end":
return _context4.stop();
}
}
}, _callee4, this);
}));
function compileComputePipelineStageDescriptor(_x7, _x8) {
return _compileComputePipelineStageDescriptor.apply(this, arguments);
if (this.depthTexture) {// this.depthTexture.destroy();
}
return compileComputePipelineStageDescriptor;
}()
}, {
key: "drawElementsType",
value: function drawElementsType(pipelineName, descriptor, indexStart, indexCount) {
var instancesCount = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
var renderPass = this.bundleEncoder || this.currentRenderPass;
this.setRenderPipeline(pipelineName, descriptor);
renderPass.drawIndexed(indexCount, instancesCount, indexStart, 0, 0);
this.tempBuffers.forEach(function (buffer) {
return buffer.destroy();
});
this.tempBuffers = [];
}
}, {
key: "drawArraysType",
value: function drawArraysType(pipelineName, descriptor, verticesStart, verticesCount) {
var instancesCount = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
var renderPass = this.bundleEncoder || this.currentRenderPass; // this.currentIndexBuffer = null;
key: "beginFrame",
value: function beginFrame() {
this.uploadEncoder = this.device.createCommandEncoder(this.uploadEncoderDescriptor);
this.renderEncoder = this.device.createCommandEncoder(this.renderEncoderDescriptor);
this.renderTargetEncoder = this.device.createCommandEncoder(this.renderTargetEncoderDescriptor);
this.setRenderPipeline(pipelineName, descriptor);
renderPass.draw(verticesCount, instancesCount, verticesStart, 0);
}
}, {
key: "createVertexBuffer",
value: function createVertexBuffer(data) {
var usage = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
var view;
if (data instanceof Array) {
view = new Float32Array(data);
} else if (data instanceof ArrayBuffer) {
view = new Uint8Array(data);
} else {
view = data;
if (this.options.supportCompute) {
this.computeEncoder = this.device.createCommandEncoder(this.computeEncoderDescriptor);
}
var dataBuffer;
if (isSafari) {
dataBuffer = this.createBuffer(view, WebGPUConstants.BufferUsage.Vertex | WebGPUConstants.BufferUsage.CopyDst | WebGPUConstants.BufferUsage.MapRead | usage);
} else {
// 如果添加了 MapRead,Chrome 会报错
dataBuffer = this.createBuffer(view, WebGPUConstants.BufferUsage.Vertex | WebGPUConstants.BufferUsage.CopyDst | WebGPUConstants.BufferUsage.CopySrc | usage);
}
return dataBuffer;
}
}, {
key: "createUniformBuffer",
value: function createUniformBuffer(data) {
var view;
if (data instanceof Array) {
view = new Float32Array(data);
} else if (data instanceof ArrayBuffer) {
view = new Uint8Array(data);
} else {
view = data;
key: "endFrame",
value: function endFrame() {
if (this.options.supportCompute) {
this.endComputePass();
}
var dataBuffer = this.createBuffer(view, WebGPUConstants.BufferUsage.Uniform | WebGPUConstants.BufferUsage.CopyDst);
return dataBuffer;
}
}, {
key: "createIndexBuffer",
value: function createIndexBuffer(data) {
var view;
this.endMainRenderPass();
this.commandBuffers[0] = this.uploadEncoder.finish();
this.commandBuffers[1] = this.renderEncoder.finish();
if (data instanceof Array) {
view = new Uint16Array(data);
} else if (data instanceof ArrayBuffer) {
view = new Uint8Array(data);
} else {
view = data;
if (this.options.supportCompute) {
this.commandBuffers[2] = this.computeEncoder.finish();
}
var dataBuffer = this.createBuffer(view, WebGPUConstants.BufferUsage.Index | WebGPUConstants.BufferUsage.CopyDst);
return dataBuffer;
}
}, {
key: "createSampler",
value: function createSampler(descriptor) {
return this.device.createSampler(descriptor);
}
}, {
key: "createTexture",
value: function createTexture(_ref, imageData, usage) {
var _ref2 = _slicedToArray(_ref, 2),
width = _ref2[0],
height = _ref2[1];
this.commandBuffers[3] = this.renderTargetEncoder.finish();
var data = null;
var rowPitch = Math.ceil(width * 4 / 256) * 256;
if (rowPitch === width * 4) {
data = imageData;
if (isSafari) {
this.device // @ts-ignore
.getQueue().submit(this.commandBuffers.filter(function (buffer) {
return buffer;
}));
} else {
data = new Uint8Array(rowPitch * height);
var imagePixelIndex = 0;
for (var y = 0; y < height; ++y) {
for (var x = 0; x < width; ++x) {
var i = x * 4 + y * rowPitch;
data[i] = imageData[imagePixelIndex];
data[i + 1] = imageData[imagePixelIndex + 1];
data[i + 2] = imageData[imagePixelIndex + 2];
data[i + 3] = imageData[imagePixelIndex + 3];
imagePixelIndex += 4;
}
}
this.device.defaultQueue.submit(this.commandBuffers.filter(function (buffer) {
return buffer;
}));
}
var texture = this.device.createTexture({
size: {
width: width,
height: height,
depth: 1
},
format: 'rgba8unorm',
usage: GPUTextureUsage.COPY_DST | usage
});
var textureDataBuffer = this.createBuffer(data, WebGPUConstants.BufferUsage.CopyDst | WebGPUConstants.BufferUsage.CopySrc);
this.uploadEncoder.copyBufferToTexture({
buffer: textureDataBuffer,
bytesPerRow: rowPitch
}, {
texture: texture
}, {
width: width,
height: height,
depth: 1
});
return texture;
}
}, {
key: "setRenderBindGroups",
value: function setRenderBindGroups(bindGroups) {
var renderPass = this.bundleEncoder || this.currentRenderPass;
for (var i = 0; i < bindGroups.length; i++) {
renderPass.setBindGroup(i, bindGroups[i]);
key: "getCurrentRenderPass",
value: function getCurrentRenderPass() {
if (this.currentRenderTarget && !this.currentRenderPass) {
this.startRenderTargetRenderPass(this.currentRenderTarget, null, false, false);
} else if (!this.currentRenderPass) {
this.startMainRenderPass();
}
}
}, {
key: "setComputeBindGroups",
value: function setComputeBindGroups(bindGroups) {
if (this.currentComputePass) {
for (var i = 0; i < bindGroups.length; i++) {
this.currentComputePass.setBindGroup(i, bindGroups[i]);
}
}
}
}, {
key: "setComputePipeline",
value: function setComputePipeline(computePipelineName, descriptor) {
var _this$currentComputeP;
if (!this.computePipelines[computePipelineName]) {
var computePipeline = this.device.createComputePipeline(descriptor);
this.computePipelines[computePipelineName] = computePipeline;
}
(_this$currentComputeP = this.currentComputePass) === null || _this$currentComputeP === void 0 ? void 0 : _this$currentComputeP.setPipeline(this.computePipelines[computePipelineName]);
return this.currentRenderPass;
}
/**
* 不同于 Babylon.js 的版本,使用最新的 map buffer 方法,创建一个临时的 mapped buffer 用于拷贝数据
* @see https://gpuweb.github.io/gpuweb/#GPUDevice-createBufferMapped
* @see https://github.com/gpuweb/gpuweb/blob/master/design/BufferOperations.md#updating-data-to-an-existing-buffer-like-webgls-buffersubdata
*
* TODO: 使用类似 AutoRingBuffer 之类的缓存结构尽可能复用临时 GPUBuffer
*/
}, {
key: "setSubData",
value: function setSubData(destBuffer, destOffset, srcArrayBuffer) {
// deprecated API
// destBuffer.setSubData(0, srcArrayBuffer);
var byteCount = srcArrayBuffer.byteLength;
var _this$device$createBu = this.device.createBufferMapped({
size: byteCount,
usage: WebGPUConstants.BufferUsage.CopySrc
}),
_this$device$createBu2 = _slicedToArray(_this$device$createBu, 2),
srcBuffer = _this$device$createBu2[0],
arrayBuffer = _this$device$createBu2[1];
new Uint8Array(arrayBuffer).set(new Uint8Array(srcArrayBuffer.buffer));
srcBuffer.unmap();
this.uploadEncoder.copyBufferToBuffer(srcBuffer, 0, destBuffer, destOffset, byteCount); // 不能立即 destroy 掉临时 buffer,因为 encoder 还未提交,
// 会报 'Destroyed buffer used in a submit',因此只能在 encoder 提交后统一进行销毁
// srcBuffer.destroy();
this.tempBuffers.push(srcBuffer);
}
}, {
key: "readData",
value: function () {
var _readData = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5(context) {
var output, length, typedArrayConstructor, gpuBuffer, arraybuffer, byteCount, gpuReadBuffer;
return _regeneratorRuntime.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
output = context.output;
if (!output) {
_context5.next = 21;
break;
}
length = output.length, typedArrayConstructor = output.typedArrayConstructor, gpuBuffer = output.gpuBuffer;
if (!gpuBuffer) {
_context5.next = 21;
break;
}
if (!isSafari) {
_context5.next = 10;
break;
}
_context5.next = 7;
return gpuBuffer.mapReadAsync();
case 7:
arraybuffer = _context5.sent;
_context5.next = 20;
break;
case 10:
byteCount = length * typedArrayConstructor.BYTES_PER_ELEMENT;
gpuReadBuffer = this.device.createBuffer({
size: byteCount,
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
});
this.uploadEncoder.copyBufferToBuffer(gpuBuffer, 0, gpuReadBuffer, 0, byteCount); // submit copy command
this.commandBuffers[0] = this.uploadEncoder.finish(); // filter undefined buffers
this.device.defaultQueue.submit(this.commandBuffers.filter(function (b) {
return b;
}));
this.uploadEncoder = this.device.createCommandEncoder(this.uploadEncoderDescriptor);
_context5.next = 18;
return gpuReadBuffer.mapReadAsync();
case 18:
arraybuffer = _context5.sent;
// destroy read buffer later
this.tempBuffers.push(gpuReadBuffer);
case 20:
return _context5.abrupt("return", new typedArrayConstructor(arraybuffer));
case 21:
return _context5.abrupt("return", new Float32Array());
case 22:
case "end":
return _context5.stop();
}
}
}, _callee5, this);
}));
function readData(_x9) {
return _readData.apply(this, arguments);
}
return readData;
}()
}, {
key: "bindVertexInputs",
value: function bindVertexInputs(vertexInputs) {
var renderPass = this.bundleEncoder || this.currentRenderPass;
if (vertexInputs.indexBuffer) {
renderPass.setIndexBuffer(vertexInputs.indexBuffer, vertexInputs.indexOffset);
}
for (var i = 0; i < vertexInputs.vertexBuffers.length; i++) {
var buf = vertexInputs.vertexBuffers[i];
if (buf) {
renderPass.setVertexBuffer(vertexInputs.vertexStartSlot + i, vertexInputs.vertexBuffers[i], vertexInputs.vertexOffsets[i]);
}
}
}
}, {
key: "dispatch",
value: function dispatch(context) {
if (this.currentComputePass) {
var _this$currentComputeP2;
(_this$currentComputeP2 = this.currentComputePass).dispatch.apply(_this$currentComputeP2, _toConsumableArray(context.dispatch));
}
}
}, {
key: "confirmInput",
value: function confirmInput(contextName, textureName, referContextName) {//
}
}, {
key: "createBuffer",
value: function createBuffer(view, flags) {
var padding = view.byteLength % 4;
var verticesBufferDescriptor = {
size: view.byteLength + padding,
usage: flags
};
var buffer = this.device.createBuffer(verticesBufferDescriptor);
this.setSubData(buffer, 0, view);
return buffer;
}
}, {
key: "initGlslang",
value: function () {
var _initGlslang = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee6() {
var _initGlslang = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
var _navigator, _navigator$gpu;
return _regeneratorRuntime.wrap(function _callee6$(_context6) {
return _regeneratorRuntime.wrap(function _callee4$(_context4) {
while (1) {
switch (_context6.prev = _context6.next) {
switch (_context4.prev = _context4.next) {
case 0:
_context6.next = 2;
_context4.next = 2;
return glslang();
case 2:
this.glslang = _context6.sent;
_context6.next = 5;
this.glslang = _context4.sent;
_context4.next = 5;
return (_navigator = navigator) === null || _navigator === void 0 ? void 0 : (_navigator$gpu = _navigator.gpu) === null || _navigator$gpu === void 0 ? void 0 : _navigator$gpu.requestAdapter();
case 5:
this.adapter = _context6.sent;
_context6.next = 8;
this.adapter = _context4.sent;
_context4.next = 8;
return this.adapter.requestDevice();
case 8:
this.device = _context6.sent;
this.device = _context4.sent;
case 9:
case "end":
return _context6.stop();
return _context4.stop();
}
}
}, _callee6, this);
}, _callee4, this);
}));

@@ -794,6 +482,6 @@

this.depthTexture.destroy();
} // @ts-ignore
}
this.depthTexture = this.device.createTexture(depthTextureDescriptor);
this.depthTexture = this.device.createTexture( // @ts-ignore
depthTextureDescriptor);
this.mainDepthAttachment = {

@@ -820,4 +508,6 @@ attachment: isSafari ? // @ts-ignore

value: function startMainRenderPass() {
if (this.currentRenderPass) {
this.endRenderPass();
this.renderEncoder.pushDebugGroup('start main rendering');
if (this.currentRenderPass && !this.currentRenderTarget) {
this.endMainRenderPass();
} // Resolve in case of MSAA

@@ -836,11 +526,62 @@

colorAttachments: this.mainColorAttachments,
depthStencilAttachment: this.mainDepthAttachment
depthStencilAttachment: this.mainDepthAttachment // TODO: use framebuffer's depth & stencil
});
this.mainRenderPass = this.currentRenderPass;
if (this.cachedViewport) {
this.viewport(this.cachedViewport);
}
}
}, {
key: "endRenderPass",
value: function endRenderPass() {
if (this.currentRenderPass) {
key: "startRenderTargetRenderPass",
value: function startRenderTargetRenderPass(renderTarget, clearColor, clearDepth) {
var _renderTarget$get$col, _renderTarget$get$dep;
var clearStencil = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
this.renderTargetEncoder.pushDebugGroup('start render target rendering');
var gpuTexture = (_renderTarget$get$col = renderTarget.get().color) === null || _renderTarget$get$col === void 0 ? void 0 : _renderTarget$get$col.texture;
var colorTextureView;
if (gpuTexture) {
colorTextureView = gpuTexture.createView(this.currentRenderTargetViewDescriptor);
}
var depthStencilTexture = (_renderTarget$get$dep = renderTarget.get().depth) === null || _renderTarget$get$dep === void 0 ? void 0 : _renderTarget$get$dep.texture;
var depthStencilTextureView;
if (depthStencilTexture) {
depthStencilTextureView = depthStencilTexture.createView();
}
var renderPass = this.renderTargetEncoder.beginRenderPass({
colorAttachments: [{
attachment: colorTextureView,
loadValue: clearColor !== null ? clearColor : WebGPUConstants.LoadOp.Load,
storeOp: WebGPUConstants.StoreOp.Store
}],
depthStencilAttachment: depthStencilTexture && depthStencilTextureView ? {
attachment: depthStencilTextureView,
depthLoadValue: clearDepth ? this.clearDepthValue : WebGPUConstants.LoadOp.Load,
depthStoreOp: WebGPUConstants.StoreOp.Store,
stencilLoadValue: clearStencil ? this.clearStencilValue : WebGPUConstants.LoadOp.Load,
stencilStoreOp: WebGPUConstants.StoreOp.Store
} : undefined
});
this.currentRenderPass = renderPass;
if (this.cachedViewport) {
this.viewport(this.cachedViewport);
} // TODO WEBGPU set the scissor rect and the stencil reference value
}
}, {
key: "endMainRenderPass",
value: function endMainRenderPass() {
if (this.currentRenderPass === this.mainRenderPass && this.currentRenderPass !== null) {
this.currentRenderPass.endPass();
this.resetCachedViewport();
this.currentRenderPass = null;
this.mainRenderPass = null;
this.renderEncoder.popDebugGroup();
}

@@ -857,146 +598,35 @@ }

}, {
key: "setRenderPipeline",
value: function setRenderPipeline(name, descriptor) {
var renderPass = this.bundleEncoder || this.currentRenderPass;
var pipeline = this.getRenderPipeline(name, descriptor);
if (pipeline) {
renderPass.setPipeline(pipeline);
} // const vertexInputs = this.getVertexInputsToRender();
// this.bindVertexInputs(vertexInputs);
// const bindGroups = this.getBindGroupsToRender();
// this.setRenderBindGroups(bindGroups);
// if (this._alphaState.alphaBlend && this._alphaState._isBlendConstantsDirty) {
// // TODO WebGPU. should use renderPass.
// this.currentRenderPass!.setBlendColor(this._alphaState._blendConstants as any);
// }
key: "endRenderTargetRenderPass",
value: function endRenderTargetRenderPass() {
if (this.currentRenderPass) {
this.currentRenderPass.endPass();
this.renderTargetEncoder.popDebugGroup();
this.resetCachedViewport();
}
}
}, {
key: "compileRawShaderToSpirV",
value: function compileRawShaderToSpirV(source, type) {
return this.glslang.compileGLSL(source, type);
}
}, {
key: "compileShaderToSpirV",
value: function compileShaderToSpirV(source, type, shaderVersion) {
return this.compileRawShaderToSpirV(shaderVersion + source, type);
}
}, {
key: "createPipelineStageDescriptor",
value: function createPipelineStageDescriptor(vertexShader, fragmentShader) {
return {
vertexStage: {
module: this.device.createShaderModule({
code: vertexShader,
// @ts-ignore
isWHLSL: isSafari
}),
entryPoint: 'main'
},
fragmentStage: {
module: this.device.createShaderModule({
code: fragmentShader,
// @ts-ignore
isWHLSL: isSafari
}),
entryPoint: 'main'
}
key: "resetCachedViewport",
value: function resetCachedViewport() {
this.cachedViewport = {
x: 0,
y: 0,
width: 0,
height: 0
};
}
}, {
key: "getRenderPipeline",
value: function getRenderPipeline(name, descriptor) {
if (this.pipelines[name]) {
return this.pipelines[name];
key: "unbindFramebuffer",
value: function unbindFramebuffer(framebuffer) {
// unbind
if (this.currentRenderPass && this.currentRenderPass !== this.mainRenderPass) {
this.endRenderTargetRenderPass();
}
var primitiveTopology = descriptor.primitiveTopology,
rasterizationState = descriptor.rasterizationState,
depthStencilState = descriptor.depthStencilState,
colorStates = descriptor.colorStates,
vertexStage = descriptor.vertexStage,
fragmentStage = descriptor.fragmentStage,
vertexState = descriptor.vertexState,
layout = descriptor.layout;
this.transientViewport.x = Infinity;
this.currentRenderTarget = null; // if (texture.generateMipMaps && !disableGenerateMipMaps && !texture.isCube) {
// this._generateMipmaps(texture);
// }
if (vertexStage && fragmentStage) {
var renderPipeline = this.device.createRenderPipeline({
sampleCount: this.mainPassSampleCount,
primitiveTopology: primitiveTopology || 'triangle-list',
rasterizationState: _objectSpread(_objectSpread({}, this.getDefaultRasterizationStateDescriptor()), rasterizationState),
depthStencilState: _objectSpread(_objectSpread({}, this.getDefaultDepthStencilStateDescriptor()), depthStencilState),
colorStates: colorStates || this.getDefaultColorStateDescriptors(),
layout: layout,
vertexStage: vertexStage,
fragmentStage: fragmentStage,
vertexState: vertexState
});
this.pipelines[name] = renderPipeline;
return renderPipeline;
}
return null;
this.currentRenderPass = this.mainRenderPass;
}
/**
* @see https://gpuweb.github.io/gpuweb/#rasterization-state
*/
}, {
key: "getDefaultRasterizationStateDescriptor",
value: function getDefaultRasterizationStateDescriptor() {
return {
frontFace: WebGPUConstants.FrontFace.CCW,
cullMode: WebGPUConstants.CullMode.None,
depthBias: 0,
depthBiasSlopeScale: 0,
depthBiasClamp: 0
};
}
/**
* @see https://gpuweb.github.io/gpuweb/#depth-stencil-state
*/
}, {
key: "getDefaultDepthStencilStateDescriptor",
value: function getDefaultDepthStencilStateDescriptor() {
var stencilFrontBack = {
compare: WebGPUConstants.CompareFunction.Always,
depthFailOp: WebGPUConstants.StencilOperation.Keep,
failOp: WebGPUConstants.StencilOperation.Keep,
passOp: WebGPUConstants.StencilOperation.Keep
};
return {
depthWriteEnabled: false,
depthCompare: WebGPUConstants.CompareFunction.Always,
format: WebGPUConstants.TextureFormat.Depth24PlusStencil8,
stencilFront: stencilFrontBack,
stencilBack: stencilFrontBack,
stencilReadMask: 0xffffffff,
stencilWriteMask: 0xffffffff
};
}
/**
* @see https://gpuweb.github.io/gpuweb/#color-state
*/
}, {
key: "getDefaultColorStateDescriptors",
value: function getDefaultColorStateDescriptors() {
return [{
format: this.options.swapChainFormat,
// https://gpuweb.github.io/gpuweb/#blend-state
alphaBlend: {
srcFactor: WebGPUConstants.BlendFactor.One,
dstFactor: WebGPUConstants.BlendFactor.Zero,
operation: WebGPUConstants.BlendOperation.Add
},
colorBlend: {
srcFactor: WebGPUConstants.BlendFactor.One,
dstFactor: WebGPUConstants.BlendFactor.Zero,
operation: WebGPUConstants.BlendOperation.Add
},
writeMask: WebGPUConstants.ColorWrite.All
}];
}
}]);

@@ -1003,0 +633,0 @@

@@ -10,4 +10,2 @@ "use strict";

var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));

@@ -17,4 +15,2 @@

var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));

@@ -26,127 +22,36 @@

var _isTypedArray = _interopRequireDefault(require("lodash/isTypedArray"));
var _regl = _interopRequireDefault(require("regl"));
var _ReglAttribute = _interopRequireDefault(require("./ReglAttribute"));
var _ReglBuffer = _interopRequireDefault(require("./ReglBuffer"));
var _ReglComputeModel = _interopRequireDefault(require("./ReglComputeModel"));
var _ReglElements = _interopRequireDefault(require("./ReglElements"));
var _ReglFramebuffer = _interopRequireDefault(require("./ReglFramebuffer"));
var _ReglModel = _interopRequireDefault(require("./ReglModel"));
var _ReglTexture2D = _interopRequireDefault(require("./ReglTexture2D"));
var _dec, _class, _temp;
/* babel-plugin-inline-import './shaders/quad.vert.glsl' */
var quadVert = "attribute vec3 a_Position;\nattribute vec2 a_TexCoord;\n\nvarying vec2 v_TexCoord;\n\nvoid main() {\n gl_Position = vec4(a_Position, 1.0);\n v_TexCoord = a_TexCoord;\n}";
/**
* implements with regl
* @see https://github.com/regl-project/regl/blob/gh-pages/API.md
* regl renderer
*/
var WebGLEngine = (_dec = (0, _inversify.injectable)(), _dec(_class = (_temp = /*#__PURE__*/function () {
function WebGLEngine() {
var _this = this;
(0, _classCallCheck2.default)(this, WebGLEngine);
this.supportWebGPU = false;
this.canvas = void 0;
this.options = void 0;
this.useWGSL = false;
this.$canvas = void 0;
this.gl = void 0;
this.contextCache = {};
}
this.inited = void 0;
(0, _createClass2.default)(WebGLEngine, [{
key: "startRecordBundle",
value: function startRecordBundle() {
throw new Error('Method not implemented.');
}
}, {
key: "stopRecordBundle",
value: function stopRecordBundle() {
throw new Error('Method not implemented.');
}
}, {
key: "executeBundles",
value: function executeBundles(bundles) {
throw new Error('Method not implemented.');
}
}, {
key: "enableScissor",
value: function enableScissor(x, y, width, height) {
throw new Error('Method not implemented.');
}
}, {
key: "disableScissor",
value: function disableScissor() {
throw new Error('Method not implemented.');
}
}, {
key: "compileRawPipelineStageDescriptor",
value: function compileRawPipelineStageDescriptor(vertexCode, fragmentCode) {
throw new Error('Method not implemented.');
}
}, {
key: "compilePipelineStageDescriptor",
value: function compilePipelineStageDescriptor(vertexCode, fragmentCode, defines) {
throw new Error('Method not implemented.');
}
}, {
key: "drawElementsType",
value: function drawElementsType(pipelineName, descriptor, indexStart, indexCount, instancesCount) {
throw new Error('Method not implemented.');
}
}, {
key: "drawArraysType",
value: function drawArraysType(pipelineName, descriptor, verticesStart, verticesCount, instancesCount) {
throw new Error('Method not implemented.');
}
}, {
key: "createVertexBuffer",
value: function createVertexBuffer(data, usage) {
throw new Error('Method not implemented.');
}
}, {
key: "createUniformBuffer",
value: function createUniformBuffer(data) {
throw new Error('Method not implemented.');
}
}, {
key: "createIndexBuffer",
value: function createIndexBuffer(data) {
throw new Error('Method not implemented.');
}
}, {
key: "createTexture",
value: function createTexture(_ref, imageData, usage) {
var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
width = _ref2[0],
height = _ref2[1];
throw new Error('Method not implemented.');
}
}, {
key: "createSampler",
value: function createSampler(descriptor) {
throw new Error('Method not implemented.');
}
}, {
key: "setRenderBindGroups",
value: function setRenderBindGroups(bindGroups) {
throw new Error('Method not implemented.');
}
}, {
key: "setSubData",
value: function setSubData(destBuffer, destOffset, srcArrayBuffer) {
throw new Error('Method not implemented.');
}
}, {
key: "bindVertexInputs",
value: function bindVertexInputs(vertexInputs) {
throw new Error('Method not implemented.');
}
}, {
key: "getDevice",
value: function getDevice() {
throw new Error('Method not implemented.');
}
}, {
key: "init",
value: function () {
var _init = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(canvas) {
var _this = this;
var options,
_args = arguments;
this.createModel = /*#__PURE__*/function () {
var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(options) {
return _regenerator.default.wrap(function _callee$(_context) {

@@ -156,39 +61,5 @@ while (1) {

case 0:
options = _args.length > 1 && _args[1] !== undefined ? _args[1] : {};
this.canvas = canvas;
this.options = options;
_context.next = 5;
return new Promise(function (resolve, reject) {
(0, _regl.default)({
// @ts-ignore
canvas: _this.canvas,
attributes: {
alpha: true,
// use TAA instead of MSAA
// @see https://www.khronos.org/registry/webgl/specs/1.0/#5.2.1
antialias: options.antialiasing,
premultipliedAlpha: true
},
// TODO: use extensions
extensions: ['OES_element_index_uint', // 'EXT_shader_texture_lod', // IBL
// 'OES_standard_derivatives', // wireframe
'OES_texture_float', // must be enabled during computing
'WEBGL_depth_texture', 'angle_instanced_arrays' // 'EXT_texture_filter_anisotropic', // VSM shadow map
],
optionalExtensions: ['oes_texture_float_linear'],
profile: true,
onDone: function onDone(err, r) {
if (err || !r) {
reject(err);
}
return _context.abrupt("return", new _ReglModel.default(_this.gl, options));
resolve(r);
}
});
});
case 5:
this.gl = _context.sent;
case 6:
case 1:
case "end":

@@ -198,229 +69,131 @@ return _context.stop();

}
}, _callee, this);
}, _callee);
}));
function init(_x) {
return _init.apply(this, arguments);
}
return function (_x) {
return _ref.apply(this, arguments);
};
}();
return init;
}()
}, {
key: "isFloatSupported",
value: function isFloatSupported() {
// @see https://github.com/antvis/GWebGPUEngine/issues/26
// @ts-ignore
return this.gl.limits.readFloat;
}
}, {
key: "compileComputePipelineStageDescriptor",
value: function () {
var _compileComputePipelineStageDescriptor = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(computeCode, context) {
var _this2 = this;
this.createAttribute = function (options) {
return new _ReglAttribute.default(_this.gl, options);
};
var cache, uniforms, outputTextureName, outputTextureData, outputTextureSize, outputTextureTypedArrayConstructor, outputDataLength, outputTexelCount, outputElementsPerTexel, drawParams;
return _regenerator.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
cache = this.contextCache[context.name];
this.createBuffer = function (options) {
return new _ReglBuffer.default(_this.gl, options);
};
if (!cache) {
// @ts-ignore
cache = {
textureCache: {}
};
}
this.createElements = function (options) {
return new _ReglElements.default(_this.gl, options);
};
uniforms = {};
outputTextureName = '';
context.uniforms.forEach(function (uniform) {
var name = uniform.name,
type = uniform.type,
data = uniform.data,
format = uniform.format; // 使用纹理存储
this.createTexture2D = function (options) {
return new _ReglTexture2D.default(_this.gl, options);
};
if (type === 'sampler2D') {
var elementsPerTexel = 1;
this.createFramebuffer = function (options) {
return new _ReglFramebuffer.default(_this.gl, options);
};
if (format.endsWith('ec4[]')) {
elementsPerTexel = 4;
} else if (format.endsWith('ec3[]')) {
elementsPerTexel = 3;
} else if (format.endsWith('ec2[]')) {
elementsPerTexel = 2;
} // 用 0 补全不足 vec4 的部分
this.useFramebuffer = function (framebuffer, drawCommands) {
_this.gl({
framebuffer: framebuffer ? framebuffer.get() : null
})(drawCommands);
};
this.createComputeModel = /*#__PURE__*/function () {
var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(context) {
return _regenerator.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
return _context2.abrupt("return", new _ReglComputeModel.default(_this.gl, context));
var paddingData = [];
case 1:
case "end":
return _context2.stop();
}
}
}, _callee2);
}));
for (var i = 0; i < data.length; i += elementsPerTexel) {
if (elementsPerTexel === 1) {
paddingData.push(data[i], 0, 0, 0);
} else if (elementsPerTexel === 2) {
paddingData.push(data[i], data[i + 1], 0, 0);
} else if (elementsPerTexel === 3) {
paddingData.push(data[i], data[i + 1], data[i + 2], 0);
} else if (elementsPerTexel === 4) {
paddingData.push(data[i], data[i + 1], data[i + 2], data[i + 3]);
}
}
return function (_x2) {
return _ref2.apply(this, arguments);
};
}();
var originalDataLength = data.length;
var texelCount = Math.ceil(originalDataLength / elementsPerTexel);
var width = Math.ceil(Math.sqrt(texelCount));
var paddingTexelCount = width * width;
this.clear = function (options) {
// @see https://github.com/regl-project/regl/blob/gh-pages/API.md#clear-the-draw-buffer
var color = options.color,
depth = options.depth,
stencil = options.stencil,
_options$framebuffer = options.framebuffer,
framebuffer = _options$framebuffer === void 0 ? null : _options$framebuffer;
var reglClearOptions = {
color: color,
depth: depth,
stencil: stencil
};
reglClearOptions.framebuffer = framebuffer === null ? framebuffer : framebuffer.get();
if (texelCount < paddingTexelCount) {
paddingData.push.apply(paddingData, (0, _toConsumableArray2.default)(new Array((paddingTexelCount - texelCount) * 4).fill(0)));
}
_this.gl.clear(reglClearOptions);
};
if (name === context.output.name) {
outputTextureName = name;
outputTextureData = paddingData;
outputDataLength = originalDataLength;
outputTextureSize = width;
outputTexelCount = texelCount;
outputElementsPerTexel = elementsPerTexel;
this.viewport = function (_ref3) {
var x = _ref3.x,
y = _ref3.y,
width = _ref3.width,
height = _ref3.height;
if ((0, _isTypedArray.default)(data)) {
outputTextureTypedArrayConstructor = data.constructor;
}
}
if (_this.gl && _this.gl._gl) {
// use WebGL context directly
// @see https://github.com/regl-project/regl/blob/gh-pages/API.md#unsafe-escape-hatch
_this.gl._gl.viewport(x, y, width, height);
var uniformTexture = _this2.gl.texture({
width: width,
height: width,
data: paddingData,
type: 'float'
});
_this.gl._refresh();
}
};
cache.textureCache[name] = uniformTexture; // 需要动态获取,有可能在运行时通过 setBinding 关联到另一个计算程序的输出
// @ts-ignore
this.readPixels = function (options) {
var framebuffer = options.framebuffer,
x = options.x,
y = options.y,
width = options.width,
height = options.height;
var readPixelsOptions = {
x: x,
y: y,
width: width,
height: height
};
uniforms[name] = context.maxIteration > 1 && context.needPingpong ? cache.textureCache[name] : function () {
return cache.textureCache[name];
}; // @ts-ignore
if (framebuffer) {
readPixelsOptions.framebuffer = framebuffer.get();
}
uniforms["".concat(name, "Size")] = [width, width];
} else {
if (data && (Array.isArray(data) || (0, _isTypedArray.default)(data)) && data.length > 16) {
// 最多支持到 mat4 包含 16 个元素
throw new Error("invalid data type ".concat(type));
} // @ts-ignore
return _this.gl.read(readPixelsOptions);
};
this.getCanvas = function () {
return _this.$canvas;
};
uniforms[name] = function () {
return uniform.data;
};
}
}); // 传入 output 纹理尺寸和数据长度,便于多余的 texel 提前退出
// @ts-ignore
this.getGLContext = function () {
return _this.gl._gl;
};
uniforms.u_OutputTextureSize = [outputTextureSize, outputTextureSize]; // @ts-ignore
this.destroy = function () {
if (_this.gl) {
// @see https://github.com/regl-project/regl/blob/gh-pages/API.md#clean-up
_this.gl.destroy();
uniforms.u_OutputTexelCount = outputTexelCount; // 大于一次且 输入输出均为自身的 认为需要 pingpong
if (context.maxIteration > 1 && context.needPingpong) {
// @ts-ignore
cache.texInput = uniforms[outputTextureName]; // @ts-ignore
uniforms[outputTextureName] = function () {
return cache.texInput;
};
cache.texOutput = this.gl.texture({
width: outputTextureSize,
height: outputTextureSize,
data: outputTextureData,
type: 'float'
});
} else {
cache.texOutput = this.gl.texture({
width: outputTextureSize,
height: outputTextureSize,
type: 'float'
});
}
context.output.typedArrayConstructor = outputTextureTypedArrayConstructor;
context.output.length = outputDataLength;
context.output.outputElementsPerTexel = outputElementsPerTexel;
drawParams = {
attributes: {
a_Position: [[-1, 1, 0], [-1, -1, 0], [1, 1, 0], [1, -1, 0]],
a_TexCoord: [[0, 1], [0, 0], [1, 1], [1, 0]]
},
frag: computeCode,
uniforms: uniforms,
vert: quadVert,
// TODO: use a fullscreen triangle instead.
primitive: 'triangle strip',
count: 4
};
cache.computeCommand = this.gl(drawParams);
this.contextCache[context.name] = cache;
return _context2.abrupt("return", {
computeStage: {
// @ts-ignore
module: {
label: 'compute'
},
entryPoint: 'main'
}
});
case 15:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
function compileComputePipelineStageDescriptor(_x2, _x3) {
return _compileComputePipelineStageDescriptor.apply(this, arguments);
_this.inited = false;
}
};
}
return compileComputePipelineStageDescriptor;
}()
}, {
key: "confirmInput",
value: function confirmInput(contextName, textureName, referContextName) {
var cache = this.contextCache[contextName];
var referCache = this.contextCache[referContextName];
if (cache && referCache) {
// 需要 pingpong 的都有 texInput
cache.textureCache[textureName] = referCache.texInput || referCache.texOutput;
}
}
}, {
key: "dispatch",
value: function dispatch(context) {
var cache = this.contextCache[context.name];
if (cache) {
cache.texFBO = this.gl.framebuffer({
color: cache.texOutput
});
cache.texFBO.use(function () {
cache.computeCommand();
}); // 需要 swap
if (context.maxIteration > 1 && context.needPingpong) {
var tmp = cache.texOutput;
cache.texOutput = cache.texInput;
cache.texInput = tmp;
}
}
}
}, {
key: "readData",
(0, _createClass2.default)(WebGLEngine, [{
key: "init",
value: function () {
var _readData = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(context) {
var _this3 = this;
var cache, pixels, _context$output, length, outputElementsPerTexel, _context$output$typed, typedArrayConstructor, formattedPixels, i;
var _init = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(cfg) {
return _regenerator.default.wrap(function _callee3$(_context3) {

@@ -430,45 +203,46 @@ while (1) {

case 0:
cache = this.contextCache[context.name];
if (!cache) {
_context3.next = 8;
if (!this.inited) {
_context3.next = 2;
break;
}
this.gl({
framebuffer: cache.texFBO
})(function () {
pixels = _this3.gl.read();
}); // @ts-ignore
return _context3.abrupt("return");
if (!pixels) {
_context3.next = 8;
break;
}
case 2:
this.$canvas = cfg.canvas; // tslint:disable-next-line:typedef
_context$output = context.output, length = _context$output.length, outputElementsPerTexel = _context$output.outputElementsPerTexel, _context$output$typed = _context$output.typedArrayConstructor, typedArrayConstructor = _context$output$typed === void 0 ? Float32Array : _context$output$typed;
formattedPixels = [];
_context3.next = 5;
return new Promise(function (resolve, reject) {
(0, _regl.default)({
canvas: cfg.canvas,
attributes: {
alpha: true,
// use TAA instead of MSAA
// @see https://www.khronos.org/registry/webgl/specs/1.0/#5.2.1
antialias: cfg.antialias,
premultipliedAlpha: true,
preserveDrawingBuffer: true
},
// TODO: use extensions
extensions: ['OES_element_index_uint', 'OES_texture_float', 'OES_standard_derivatives', // wireframe
'angle_instanced_arrays' // VSM shadow map
],
optionalExtensions: ['EXT_texture_filter_anisotropic', 'EXT_blend_minmax', 'WEBGL_depth_texture'],
profile: true,
onDone: function onDone(err, r) {
if (err || !r) {
reject(err);
} // @ts-ignore
if (outputElementsPerTexel !== 4) {
for (i = 0; i < pixels.length; i += 4) {
if (outputElementsPerTexel === 1) {
formattedPixels.push(pixels[i]);
} else if (outputElementsPerTexel === 2) {
formattedPixels.push(pixels[i], pixels[i + 1]);
} else {
formattedPixels.push(pixels[i], pixels[i + 1], pixels[i + 2]);
resolve(r);
}
}
} else {
// @ts-ignore
formattedPixels = pixels;
} // 截取多余的部分
});
});
case 5:
this.gl = _context3.sent;
this.inited = true;
return _context3.abrupt("return", new typedArrayConstructor(formattedPixels.slice(0, length)));
case 8:
return _context3.abrupt("return", new Float32Array());
case 9:
case 7:
case "end":

@@ -481,30 +255,16 @@ return _context3.stop();

function readData(_x4) {
return _readData.apply(this, arguments);
function init(_x3) {
return _init.apply(this, arguments);
}
return readData;
return init;
}()
}, {
key: "setComputePipeline",
value: function setComputePipeline(computePipelineName, descriptor) {//
key: "isFloatSupported",
value: function isFloatSupported() {
// @see https://github.com/antvis/GWebGPUEngine/issues/26
// @ts-ignore
return this.gl.limits.readFloat;
}
}, {
key: "setComputeBindGroups",
value: function setComputeBindGroups(bindGroups) {//
}
}, {
key: "clear",
value: function clear(color, backBuffer, depth) {
var stencil = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
if (!Array.isArray(color)) {
color = [color.r, color.g, color.b, color.a];
}
this.gl.clear({
color: color
}); // TODO: depth & stencil
}
}, {
key: "beginFrame",

@@ -515,11 +275,3 @@ value: function beginFrame() {//

key: "endFrame",
value: function endFrame() {} //
/**
* Dispose and release all associated resources
*/
}, {
key: "dispose",
value: function dispose() {// this.dataTextures.forEach((d) => d.destroy());
value: function endFrame() {//
}

@@ -526,0 +278,0 @@ }]);

@@ -16,2 +16,3 @@ "use strict";

// import glslangInit from '@webgpu/glslang/dist/web-devel/glslang.onefile';
// @ts-nocheck

@@ -18,0 +19,0 @@

@@ -12,8 +12,2 @@ "use strict";

var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));

@@ -35,12 +29,29 @@

var _dec, _class, _temp;
var _WebGPUAttribute = _interopRequireDefault(require("./WebGPUAttribute"));
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
var _WebGPUBuffer = _interopRequireDefault(require("./WebGPUBuffer"));
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
var _WebGPUComputeModel = _interopRequireDefault(require("./WebGPUComputeModel"));
var _WebGPUElements = _interopRequireDefault(require("./WebGPUElements"));
var _WebGPUFramebuffer = _interopRequireDefault(require("./WebGPUFramebuffer"));
var _WebGPUModel = _interopRequireDefault(require("./WebGPUModel"));
var _WebGPUTexture2D = _interopRequireDefault(require("./WebGPUTexture2D"));
var _dec, _class, _temp;
/**
* regl renderer
*/
var WebGPUEngine = (_dec = (0, _inversify.injectable)(), _dec(_class = (_temp = /*#__PURE__*/function () {
function WebGPUEngine() {
var _this = this;
(0, _classCallCheck2.default)(this, WebGPUEngine);
this.supportWebGPU = true;
this.useWGSL = false;
this.options = void 0;
this.canvas = void 0;

@@ -52,4 +63,2 @@ this.context = void 0;

this.swapChain = void 0;
this.pipelines = {};
this.computePipelines = {};
this.mainPassSampleCount = void 0;

@@ -64,11 +73,11 @@ this.mainTexture = void 0;

this.computeEncoder = void 0;
this.commandBuffers = new Array(3).fill(undefined);
this.renderTargetEncoder = void 0;
this.commandBuffers = new Array(4).fill(undefined);
this.currentRenderPass = null;
this.mainRenderPass = null;
this.currentRenderTargetViewDescriptor = void 0;
this.currentComputePass = null;
this.bundleEncoder = void 0;
this.tempBuffers = [];
this.options = void 0;
this.defaultSampleCount = 4;
this.clearDepthValue = 1;
this.clearStencilValue = 0;
this.currentRenderTarget = null;
this.uploadEncoderDescriptor = {

@@ -80,28 +89,62 @@ label: 'upload'

};
this.renderTargetEncoderDescriptor = {
label: 'renderTarget'
};
this.computeEncoderDescriptor = {
label: 'compute'
};
}
this.pipelines = {};
this.computePipelines = {};
this.defaultSampleCount = 4;
this.clearDepthValue = 1;
this.clearStencilValue = 0;
this.transientViewport = {
x: Infinity,
y: 0,
width: 0,
height: 0
};
this.cachedViewport = {
x: 0,
y: 0,
width: 0,
height: 0
};
(0, _createClass2.default)(WebGPUEngine, [{
key: "isFloatSupported",
value: function isFloatSupported() {
return true;
}
}, {
key: "getDevice",
value: function getDevice() {
return this.device;
}
}, {
key: "getSwapChain",
value: function getSwapChain() {
return this.swapChain;
}
}, {
key: "init",
value: function () {
var _init = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(canvas) {
var options,
_args = arguments;
this.clear = function (options) {
var framebuffer = options.framebuffer,
color = options.color,
depth = options.depth,
stencil = options.stencil;
if (_this.options.supportCompute) {
_this.startComputePass();
} // We need to recreate the render pass so that the new parameters for clear color / depth / stencil are taken into account
if (_this.currentRenderTarget) {
if (_this.currentRenderPass) {
_this.endRenderTargetRenderPass();
}
_this.startRenderTargetRenderPass(_this.currentRenderTarget, color ? color : null, !!depth, !!stencil);
} else {
// if (this.useReverseDepthBuffer) {
// this._depthCullingState.depthFunc = Constants.GREATER;
// }
_this.mainColorAttachments[0].loadValue = color ? color : WebGPUConstants.LoadOp.Load;
_this.mainDepthAttachment.depthLoadValue = depth ? depth : WebGPUConstants.LoadOp.Load;
_this.mainDepthAttachment.stencilLoadValue = stencil ? _this.clearStencilValue : WebGPUConstants.LoadOp.Load;
if (_this.mainRenderPass) {
_this.endMainRenderPass();
}
_this.startMainRenderPass();
}
};
this.createModel = /*#__PURE__*/function () {
var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(options) {
var model;
return _regenerator.default.wrap(function _callee$(_context) {

@@ -111,14 +154,10 @@ while (1) {

case 0:
options = _args.length > 1 && _args[1] !== undefined ? _args[1] : {};
this.canvas = canvas;
this.options = options;
this.mainPassSampleCount = options.antialiasing ? this.defaultSampleCount : 1;
_context.next = 6;
return this.initGlslang();
model = new _WebGPUModel.default(_this, options);
_context.next = 3;
return model.init();
case 6:
this.initContextAndSwapChain();
this.initMainAttachments();
case 3:
return _context.abrupt("return", model);
case 8:
case 4:
case "end":

@@ -128,145 +167,53 @@ return _context.stop();

}
}, _callee, this);
}, _callee);
}));
function init(_x) {
return _init.apply(this, arguments);
}
return function (_x) {
return _ref.apply(this, arguments);
};
}();
return init;
}()
}, {
key: "beginFrame",
value: function beginFrame() {
this.uploadEncoder = this.device.createCommandEncoder(this.uploadEncoderDescriptor);
this.renderEncoder = this.device.createCommandEncoder(this.renderEncoderDescriptor);
this.computeEncoder = this.device.createCommandEncoder(this.computeEncoderDescriptor);
}
}, {
key: "endFrame",
value: function endFrame() {
// this.endRenderPass();
if (this.options.supportCompute) {
this.endComputePass();
} else {
this.endRenderPass();
}
this.createAttribute = function (options) {
return new _WebGPUAttribute.default(_this, options);
};
this.commandBuffers[0] = this.uploadEncoder.finish();
this.commandBuffers[1] = this.renderEncoder.finish();
this.commandBuffers[2] = this.computeEncoder.finish();
this.createBuffer = function (options) {
return new _WebGPUBuffer.default(_this, options);
};
if (_gWebgpuCore.isSafari) {
// @ts-ignore
this.device.getQueue().submit(this.commandBuffers);
} else {
this.device.defaultQueue.submit(this.commandBuffers);
}
this.createElements = function (options) {
return new _WebGPUElements.default(_this, options);
};
this.tempBuffers.forEach(function (buffer) {
return buffer.destroy();
});
this.tempBuffers = [];
}
/**
* Start recording all the gpu calls into a bundle.
* @see https://zhuanlan.zhihu.com/p/99993704
*/
this.createTexture2D = function (options) {
return new _WebGPUTexture2D.default(_this, options);
};
}, {
key: "startRecordBundle",
value: function startRecordBundle() {
this.bundleEncoder = this.device.createRenderBundleEncoder({
colorFormats: [WebGPUConstants.TextureFormat.BGRA8Unorm],
depthStencilFormat: WebGPUConstants.TextureFormat.Depth24PlusStencil8,
sampleCount: this.mainPassSampleCount
});
}
/**
* Stops recording the bundle.
* @returns the recorded bundle
*/
this.createFramebuffer = function (options) {
return new _WebGPUFramebuffer.default(_this, options);
};
}, {
key: "stopRecordBundle",
value: function stopRecordBundle() {
var bundle = this.bundleEncoder.finish();
this.bundleEncoder = null;
return bundle;
}
/**
* Execute the previously recorded bundle.
* @param bundles defines the bundle to replay
*/
}, {
key: "executeBundles",
value: function executeBundles(bundles) {
var _this$currentRenderPa;
if (!this.currentRenderPass) {
this.startMainRenderPass();
this.useFramebuffer = function (framebuffer, drawCommands) {
// bind
if (_this.currentRenderTarget) {
_this.unbindFramebuffer(_this.currentRenderTarget);
}
(_this$currentRenderPa = this.currentRenderPass) === null || _this$currentRenderPa === void 0 ? void 0 : _this$currentRenderPa.executeBundles(bundles);
}
}, {
key: "enableScissor",
value: function enableScissor(x, y, width, height) {
if (!this.currentRenderPass) {
this.startMainRenderPass();
}
_this.currentRenderTarget = framebuffer; // TODO: use mipmap options in framebuffer
this.currentRenderPass.setScissorRect(x, y, width, height);
}
}, {
key: "disableScissor",
value: function disableScissor() {
var _this$currentRenderPa2;
_this.currentRenderTargetViewDescriptor = {
dimension: WebGPUConstants.TextureViewDimension.E2d,
// mipLevelCount: bindWithMipMaps ? WebGPUTextureHelper.computeNumMipmapLevels(texture.width, texture.height) - lodLevel : 1,
// baseArrayLayer: faceIndex,
// baseMipLevel: lodLevel,
arrayLayerCount: 1,
aspect: WebGPUConstants.TextureAspect.All
};
_this.currentRenderPass = null;
drawCommands();
};
if (!this.currentRenderPass) {
this.startMainRenderPass();
}
(_this$currentRenderPa2 = this.currentRenderPass) === null || _this$currentRenderPa2 === void 0 ? void 0 : _this$currentRenderPa2.setScissorRect(0, 0, this.canvas.width, this.canvas.height);
}
}, {
key: "setSize",
value: function setSize(width, height) {
this.initMainAttachments();
}
}, {
key: "clear",
value: function clear(color, backBuffer, depth) {
var stencil = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
this.mainColorAttachments[0].loadValue = backBuffer ? color : WebGPUConstants.LoadOp.Load;
this.mainDepthAttachment.depthLoadValue = depth ? this.clearDepthValue : WebGPUConstants.LoadOp.Load;
this.mainDepthAttachment.stencilLoadValue = stencil ? this.clearStencilValue : WebGPUConstants.LoadOp.Load; // this.startMainRenderPass();
if (this.options.supportCompute) {
this.startComputePass();
} else {
this.startMainRenderPass();
}
}
/**
* Dispose and release all associated resources
*/
}, {
key: "dispose",
value: function dispose() {
if (this.mainTexture) {
this.mainTexture.destroy();
}
if (this.depthTexture) {
this.depthTexture.destroy();
}
}
}, {
key: "compileRawPipelineStageDescriptor",
value: function () {
var _compileRawPipelineStageDescriptor = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(vertexCode, fragmentCode) {
var vertexShader, fragmentShader;
this.createComputeModel = /*#__PURE__*/function () {
var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(context) {
var model;
return _regenerator.default.wrap(function _callee2$(_context2) {

@@ -276,15 +223,10 @@ while (1) {

case 0:
_context2.next = 2;
return this.compileRawShaderToSpirV(vertexCode, 'vertex');
model = new _WebGPUComputeModel.default(_this, context);
_context2.next = 3;
return model.init();
case 2:
vertexShader = _context2.sent;
_context2.next = 5;
return this.compileRawShaderToSpirV(fragmentCode, 'fragment');
case 3:
return _context2.abrupt("return", model);
case 5:
fragmentShader = _context2.sent;
return _context2.abrupt("return", this.createPipelineStageDescriptor(vertexShader, fragmentShader));
case 7:
case 4:
case "end":

@@ -294,16 +236,65 @@ return _context2.stop();

}
}, _callee2, this);
}, _callee2);
}));
function compileRawPipelineStageDescriptor(_x2, _x3) {
return _compileRawPipelineStageDescriptor.apply(this, arguments);
return function (_x2) {
return _ref2.apply(this, arguments);
};
}();
this.getCanvas = function () {
return _this.canvas;
};
this.getGLContext = function () {
throw new Error('Method not implemented.');
};
this.viewport = function (_ref3) {
var x = _ref3.x,
y = _ref3.y,
width = _ref3.width,
height = _ref3.height;
if (!_this.currentRenderPass) {
// call viewport() before current render pass created
_this.transientViewport = {
x: x,
y: y,
width: width,
height: height
};
} else if (_this.transientViewport.x !== Infinity) {
var renderPass = _this.getCurrentRenderPass(); // @see https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-setviewport
renderPass.setViewport(_this.transientViewport.x, _this.transientViewport.y, _this.transientViewport.width, _this.transientViewport.height, 0, 1);
} else if (x !== _this.cachedViewport.x || y !== _this.cachedViewport.y || width !== _this.cachedViewport.width || height !== _this.cachedViewport.height) {
_this.cachedViewport = {
x: x,
y: y,
width: width,
height: height
};
var _renderPass = _this.getCurrentRenderPass();
_renderPass.setViewport(x, y, width, height, 0, 1);
}
};
return compileRawPipelineStageDescriptor;
}()
this.readPixels = function (options) {
throw new Error('Method not implemented.');
};
}
(0, _createClass2.default)(WebGPUEngine, [{
key: "isFloatSupported",
value: function isFloatSupported() {
return true;
}
}, {
key: "compilePipelineStageDescriptor",
key: "init",
value: function () {
var _compilePipelineStageDescriptor = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(vertexCode, fragmentCode, defines) {
var shaderVersion, vertexShader, fragmentShader;
var _init = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(config) {
return _regenerator.default.wrap(function _callee3$(_context3) {

@@ -313,14 +304,12 @@ while (1) {

case 0:
shaderVersion = '#version 450\n';
_context3.next = 3;
return this.compileShaderToSpirV(vertexCode, 'vertex', shaderVersion);
case 3:
vertexShader = _context3.sent;
this.canvas = config.canvas;
this.options = config;
this.useWGSL = !!config.useWGSL;
this.mainPassSampleCount = config.antialiasing ? this.defaultSampleCount : 1;
_context3.next = 6;
return this.compileShaderToSpirV(fragmentCode, 'fragment', shaderVersion);
return this.initGlslang();
case 6:
fragmentShader = _context3.sent;
return _context3.abrupt("return", this.createPipelineStageDescriptor(vertexShader, fragmentShader));
this.initContextAndSwapChain();
this.initMainAttachments();

@@ -335,402 +324,105 @@ case 8:

function compilePipelineStageDescriptor(_x4, _x5, _x6) {
return _compilePipelineStageDescriptor.apply(this, arguments);
function init(_x3) {
return _init.apply(this, arguments);
}
return compilePipelineStageDescriptor;
return init;
}()
}, {
key: "compileComputePipelineStageDescriptor",
value: function () {
var _compileComputePipelineStageDescriptor = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4(computeCode, context) {
var computeShader, shaderVersion;
return _regenerator.default.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
if (!_gWebgpuCore.isSafari) {
_context4.next = 4;
break;
}
key: "destroy",
value: function destroy() {
if (this.mainTexture) {
this.mainTexture.destroy();
}
computeShader = computeCode;
_context4.next = 8;
break;
case 4:
shaderVersion = '#version 450\n';
_context4.next = 7;
return this.compileShaderToSpirV(computeCode, 'compute', shaderVersion);
case 7:
computeShader = _context4.sent;
case 8:
return _context4.abrupt("return", {
computeStage: {
module: this.device.createShaderModule({
code: computeShader,
// @ts-ignore
isWHLSL: _gWebgpuCore.isSafari
}),
entryPoint: 'main'
}
});
case 9:
case "end":
return _context4.stop();
}
}
}, _callee4, this);
}));
function compileComputePipelineStageDescriptor(_x7, _x8) {
return _compileComputePipelineStageDescriptor.apply(this, arguments);
if (this.depthTexture) {// this.depthTexture.destroy();
}
return compileComputePipelineStageDescriptor;
}()
}, {
key: "drawElementsType",
value: function drawElementsType(pipelineName, descriptor, indexStart, indexCount) {
var instancesCount = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
var renderPass = this.bundleEncoder || this.currentRenderPass;
this.setRenderPipeline(pipelineName, descriptor);
renderPass.drawIndexed(indexCount, instancesCount, indexStart, 0, 0);
this.tempBuffers.forEach(function (buffer) {
return buffer.destroy();
});
this.tempBuffers = [];
}
}, {
key: "drawArraysType",
value: function drawArraysType(pipelineName, descriptor, verticesStart, verticesCount) {
var instancesCount = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
var renderPass = this.bundleEncoder || this.currentRenderPass; // this.currentIndexBuffer = null;
key: "beginFrame",
value: function beginFrame() {
this.uploadEncoder = this.device.createCommandEncoder(this.uploadEncoderDescriptor);
this.renderEncoder = this.device.createCommandEncoder(this.renderEncoderDescriptor);
this.renderTargetEncoder = this.device.createCommandEncoder(this.renderTargetEncoderDescriptor);
this.setRenderPipeline(pipelineName, descriptor);
renderPass.draw(verticesCount, instancesCount, verticesStart, 0);
}
}, {
key: "createVertexBuffer",
value: function createVertexBuffer(data) {
var usage = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
var view;
if (data instanceof Array) {
view = new Float32Array(data);
} else if (data instanceof ArrayBuffer) {
view = new Uint8Array(data);
} else {
view = data;
if (this.options.supportCompute) {
this.computeEncoder = this.device.createCommandEncoder(this.computeEncoderDescriptor);
}
var dataBuffer;
if (_gWebgpuCore.isSafari) {
dataBuffer = this.createBuffer(view, WebGPUConstants.BufferUsage.Vertex | WebGPUConstants.BufferUsage.CopyDst | WebGPUConstants.BufferUsage.MapRead | usage);
} else {
// 如果添加了 MapRead,Chrome 会报错
dataBuffer = this.createBuffer(view, WebGPUConstants.BufferUsage.Vertex | WebGPUConstants.BufferUsage.CopyDst | WebGPUConstants.BufferUsage.CopySrc | usage);
}
return dataBuffer;
}
}, {
key: "createUniformBuffer",
value: function createUniformBuffer(data) {
var view;
if (data instanceof Array) {
view = new Float32Array(data);
} else if (data instanceof ArrayBuffer) {
view = new Uint8Array(data);
} else {
view = data;
key: "endFrame",
value: function endFrame() {
if (this.options.supportCompute) {
this.endComputePass();
}
var dataBuffer = this.createBuffer(view, WebGPUConstants.BufferUsage.Uniform | WebGPUConstants.BufferUsage.CopyDst);
return dataBuffer;
}
}, {
key: "createIndexBuffer",
value: function createIndexBuffer(data) {
var view;
this.endMainRenderPass();
this.commandBuffers[0] = this.uploadEncoder.finish();
this.commandBuffers[1] = this.renderEncoder.finish();
if (data instanceof Array) {
view = new Uint16Array(data);
} else if (data instanceof ArrayBuffer) {
view = new Uint8Array(data);
} else {
view = data;
if (this.options.supportCompute) {
this.commandBuffers[2] = this.computeEncoder.finish();
}
var dataBuffer = this.createBuffer(view, WebGPUConstants.BufferUsage.Index | WebGPUConstants.BufferUsage.CopyDst);
return dataBuffer;
}
}, {
key: "createSampler",
value: function createSampler(descriptor) {
return this.device.createSampler(descriptor);
}
}, {
key: "createTexture",
value: function createTexture(_ref, imageData, usage) {
var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
width = _ref2[0],
height = _ref2[1];
this.commandBuffers[3] = this.renderTargetEncoder.finish();
var data = null;
var rowPitch = Math.ceil(width * 4 / 256) * 256;
if (rowPitch === width * 4) {
data = imageData;
if (_gWebgpuCore.isSafari) {
this.device // @ts-ignore
.getQueue().submit(this.commandBuffers.filter(function (buffer) {
return buffer;
}));
} else {
data = new Uint8Array(rowPitch * height);
var imagePixelIndex = 0;
for (var y = 0; y < height; ++y) {
for (var x = 0; x < width; ++x) {
var i = x * 4 + y * rowPitch;
data[i] = imageData[imagePixelIndex];
data[i + 1] = imageData[imagePixelIndex + 1];
data[i + 2] = imageData[imagePixelIndex + 2];
data[i + 3] = imageData[imagePixelIndex + 3];
imagePixelIndex += 4;
}
}
this.device.defaultQueue.submit(this.commandBuffers.filter(function (buffer) {
return buffer;
}));
}
var texture = this.device.createTexture({
size: {
width: width,
height: height,
depth: 1
},
format: 'rgba8unorm',
usage: GPUTextureUsage.COPY_DST | usage
});
var textureDataBuffer = this.createBuffer(data, WebGPUConstants.BufferUsage.CopyDst | WebGPUConstants.BufferUsage.CopySrc);
this.uploadEncoder.copyBufferToTexture({
buffer: textureDataBuffer,
bytesPerRow: rowPitch
}, {
texture: texture
}, {
width: width,
height: height,
depth: 1
});
return texture;
}
}, {
key: "setRenderBindGroups",
value: function setRenderBindGroups(bindGroups) {
var renderPass = this.bundleEncoder || this.currentRenderPass;
for (var i = 0; i < bindGroups.length; i++) {
renderPass.setBindGroup(i, bindGroups[i]);
key: "getCurrentRenderPass",
value: function getCurrentRenderPass() {
if (this.currentRenderTarget && !this.currentRenderPass) {
this.startRenderTargetRenderPass(this.currentRenderTarget, null, false, false);
} else if (!this.currentRenderPass) {
this.startMainRenderPass();
}
}
}, {
key: "setComputeBindGroups",
value: function setComputeBindGroups(bindGroups) {
if (this.currentComputePass) {
for (var i = 0; i < bindGroups.length; i++) {
this.currentComputePass.setBindGroup(i, bindGroups[i]);
}
}
}
}, {
key: "setComputePipeline",
value: function setComputePipeline(computePipelineName, descriptor) {
var _this$currentComputeP;
if (!this.computePipelines[computePipelineName]) {
var computePipeline = this.device.createComputePipeline(descriptor);
this.computePipelines[computePipelineName] = computePipeline;
}
(_this$currentComputeP = this.currentComputePass) === null || _this$currentComputeP === void 0 ? void 0 : _this$currentComputeP.setPipeline(this.computePipelines[computePipelineName]);
return this.currentRenderPass;
}
/**
* 不同于 Babylon.js 的版本,使用最新的 map buffer 方法,创建一个临时的 mapped buffer 用于拷贝数据
* @see https://gpuweb.github.io/gpuweb/#GPUDevice-createBufferMapped
* @see https://github.com/gpuweb/gpuweb/blob/master/design/BufferOperations.md#updating-data-to-an-existing-buffer-like-webgls-buffersubdata
*
* TODO: 使用类似 AutoRingBuffer 之类的缓存结构尽可能复用临时 GPUBuffer
*/
}, {
key: "setSubData",
value: function setSubData(destBuffer, destOffset, srcArrayBuffer) {
// deprecated API
// destBuffer.setSubData(0, srcArrayBuffer);
var byteCount = srcArrayBuffer.byteLength;
var _this$device$createBu = this.device.createBufferMapped({
size: byteCount,
usage: WebGPUConstants.BufferUsage.CopySrc
}),
_this$device$createBu2 = (0, _slicedToArray2.default)(_this$device$createBu, 2),
srcBuffer = _this$device$createBu2[0],
arrayBuffer = _this$device$createBu2[1];
new Uint8Array(arrayBuffer).set(new Uint8Array(srcArrayBuffer.buffer));
srcBuffer.unmap();
this.uploadEncoder.copyBufferToBuffer(srcBuffer, 0, destBuffer, destOffset, byteCount); // 不能立即 destroy 掉临时 buffer,因为 encoder 还未提交,
// 会报 'Destroyed buffer used in a submit',因此只能在 encoder 提交后统一进行销毁
// srcBuffer.destroy();
this.tempBuffers.push(srcBuffer);
}
}, {
key: "readData",
value: function () {
var _readData = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee5(context) {
var output, length, typedArrayConstructor, gpuBuffer, arraybuffer, byteCount, gpuReadBuffer;
return _regenerator.default.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
output = context.output;
if (!output) {
_context5.next = 21;
break;
}
length = output.length, typedArrayConstructor = output.typedArrayConstructor, gpuBuffer = output.gpuBuffer;
if (!gpuBuffer) {
_context5.next = 21;
break;
}
if (!_gWebgpuCore.isSafari) {
_context5.next = 10;
break;
}
_context5.next = 7;
return gpuBuffer.mapReadAsync();
case 7:
arraybuffer = _context5.sent;
_context5.next = 20;
break;
case 10:
byteCount = length * typedArrayConstructor.BYTES_PER_ELEMENT;
gpuReadBuffer = this.device.createBuffer({
size: byteCount,
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
});
this.uploadEncoder.copyBufferToBuffer(gpuBuffer, 0, gpuReadBuffer, 0, byteCount); // submit copy command
this.commandBuffers[0] = this.uploadEncoder.finish(); // filter undefined buffers
this.device.defaultQueue.submit(this.commandBuffers.filter(function (b) {
return b;
}));
this.uploadEncoder = this.device.createCommandEncoder(this.uploadEncoderDescriptor);
_context5.next = 18;
return gpuReadBuffer.mapReadAsync();
case 18:
arraybuffer = _context5.sent;
// destroy read buffer later
this.tempBuffers.push(gpuReadBuffer);
case 20:
return _context5.abrupt("return", new typedArrayConstructor(arraybuffer));
case 21:
return _context5.abrupt("return", new Float32Array());
case 22:
case "end":
return _context5.stop();
}
}
}, _callee5, this);
}));
function readData(_x9) {
return _readData.apply(this, arguments);
}
return readData;
}()
}, {
key: "bindVertexInputs",
value: function bindVertexInputs(vertexInputs) {
var renderPass = this.bundleEncoder || this.currentRenderPass;
if (vertexInputs.indexBuffer) {
renderPass.setIndexBuffer(vertexInputs.indexBuffer, vertexInputs.indexOffset);
}
for (var i = 0; i < vertexInputs.vertexBuffers.length; i++) {
var buf = vertexInputs.vertexBuffers[i];
if (buf) {
renderPass.setVertexBuffer(vertexInputs.vertexStartSlot + i, vertexInputs.vertexBuffers[i], vertexInputs.vertexOffsets[i]);
}
}
}
}, {
key: "dispatch",
value: function dispatch(context) {
if (this.currentComputePass) {
var _this$currentComputeP2;
(_this$currentComputeP2 = this.currentComputePass).dispatch.apply(_this$currentComputeP2, (0, _toConsumableArray2.default)(context.dispatch));
}
}
}, {
key: "confirmInput",
value: function confirmInput(contextName, textureName, referContextName) {//
}
}, {
key: "createBuffer",
value: function createBuffer(view, flags) {
var padding = view.byteLength % 4;
var verticesBufferDescriptor = {
size: view.byteLength + padding,
usage: flags
};
var buffer = this.device.createBuffer(verticesBufferDescriptor);
this.setSubData(buffer, 0, view);
return buffer;
}
}, {
key: "initGlslang",
value: function () {
var _initGlslang = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee6() {
var _initGlslang = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4() {
var _navigator, _navigator$gpu;
return _regenerator.default.wrap(function _callee6$(_context6) {
return _regenerator.default.wrap(function _callee4$(_context4) {
while (1) {
switch (_context6.prev = _context6.next) {
switch (_context4.prev = _context4.next) {
case 0:
_context6.next = 2;
_context4.next = 2;
return (0, _glslang.default)();
case 2:
this.glslang = _context6.sent;
_context6.next = 5;
this.glslang = _context4.sent;
_context4.next = 5;
return (_navigator = navigator) === null || _navigator === void 0 ? void 0 : (_navigator$gpu = _navigator.gpu) === null || _navigator$gpu === void 0 ? void 0 : _navigator$gpu.requestAdapter();
case 5:
this.adapter = _context6.sent;
_context6.next = 8;
this.adapter = _context4.sent;
_context4.next = 8;
return this.adapter.requestDevice();
case 8:
this.device = _context6.sent;
this.device = _context4.sent;
case 9:
case "end":
return _context6.stop();
return _context4.stop();
}
}
}, _callee6, this);
}, _callee4, this);
}));

@@ -807,6 +499,6 @@

this.depthTexture.destroy();
} // @ts-ignore
}
this.depthTexture = this.device.createTexture(depthTextureDescriptor);
this.depthTexture = this.device.createTexture( // @ts-ignore
depthTextureDescriptor);
this.mainDepthAttachment = {

@@ -833,4 +525,6 @@ attachment: _gWebgpuCore.isSafari ? // @ts-ignore

value: function startMainRenderPass() {
if (this.currentRenderPass) {
this.endRenderPass();
this.renderEncoder.pushDebugGroup('start main rendering');
if (this.currentRenderPass && !this.currentRenderTarget) {
this.endMainRenderPass();
} // Resolve in case of MSAA

@@ -849,11 +543,62 @@

colorAttachments: this.mainColorAttachments,
depthStencilAttachment: this.mainDepthAttachment
depthStencilAttachment: this.mainDepthAttachment // TODO: use framebuffer's depth & stencil
});
this.mainRenderPass = this.currentRenderPass;
if (this.cachedViewport) {
this.viewport(this.cachedViewport);
}
}
}, {
key: "endRenderPass",
value: function endRenderPass() {
if (this.currentRenderPass) {
key: "startRenderTargetRenderPass",
value: function startRenderTargetRenderPass(renderTarget, clearColor, clearDepth) {
var _renderTarget$get$col, _renderTarget$get$dep;
var clearStencil = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
this.renderTargetEncoder.pushDebugGroup('start render target rendering');
var gpuTexture = (_renderTarget$get$col = renderTarget.get().color) === null || _renderTarget$get$col === void 0 ? void 0 : _renderTarget$get$col.texture;
var colorTextureView;
if (gpuTexture) {
colorTextureView = gpuTexture.createView(this.currentRenderTargetViewDescriptor);
}
var depthStencilTexture = (_renderTarget$get$dep = renderTarget.get().depth) === null || _renderTarget$get$dep === void 0 ? void 0 : _renderTarget$get$dep.texture;
var depthStencilTextureView;
if (depthStencilTexture) {
depthStencilTextureView = depthStencilTexture.createView();
}
var renderPass = this.renderTargetEncoder.beginRenderPass({
colorAttachments: [{
attachment: colorTextureView,
loadValue: clearColor !== null ? clearColor : WebGPUConstants.LoadOp.Load,
storeOp: WebGPUConstants.StoreOp.Store
}],
depthStencilAttachment: depthStencilTexture && depthStencilTextureView ? {
attachment: depthStencilTextureView,
depthLoadValue: clearDepth ? this.clearDepthValue : WebGPUConstants.LoadOp.Load,
depthStoreOp: WebGPUConstants.StoreOp.Store,
stencilLoadValue: clearStencil ? this.clearStencilValue : WebGPUConstants.LoadOp.Load,
stencilStoreOp: WebGPUConstants.StoreOp.Store
} : undefined
});
this.currentRenderPass = renderPass;
if (this.cachedViewport) {
this.viewport(this.cachedViewport);
} // TODO WEBGPU set the scissor rect and the stencil reference value
}
}, {
key: "endMainRenderPass",
value: function endMainRenderPass() {
if (this.currentRenderPass === this.mainRenderPass && this.currentRenderPass !== null) {
this.currentRenderPass.endPass();
this.resetCachedViewport();
this.currentRenderPass = null;
this.mainRenderPass = null;
this.renderEncoder.popDebugGroup();
}

@@ -870,146 +615,35 @@ }

}, {
key: "setRenderPipeline",
value: function setRenderPipeline(name, descriptor) {
var renderPass = this.bundleEncoder || this.currentRenderPass;
var pipeline = this.getRenderPipeline(name, descriptor);
if (pipeline) {
renderPass.setPipeline(pipeline);
} // const vertexInputs = this.getVertexInputsToRender();
// this.bindVertexInputs(vertexInputs);
// const bindGroups = this.getBindGroupsToRender();
// this.setRenderBindGroups(bindGroups);
// if (this._alphaState.alphaBlend && this._alphaState._isBlendConstantsDirty) {
// // TODO WebGPU. should use renderPass.
// this.currentRenderPass!.setBlendColor(this._alphaState._blendConstants as any);
// }
key: "endRenderTargetRenderPass",
value: function endRenderTargetRenderPass() {
if (this.currentRenderPass) {
this.currentRenderPass.endPass();
this.renderTargetEncoder.popDebugGroup();
this.resetCachedViewport();
}
}
}, {
key: "compileRawShaderToSpirV",
value: function compileRawShaderToSpirV(source, type) {
return this.glslang.compileGLSL(source, type);
}
}, {
key: "compileShaderToSpirV",
value: function compileShaderToSpirV(source, type, shaderVersion) {
return this.compileRawShaderToSpirV(shaderVersion + source, type);
}
}, {
key: "createPipelineStageDescriptor",
value: function createPipelineStageDescriptor(vertexShader, fragmentShader) {
return {
vertexStage: {
module: this.device.createShaderModule({
code: vertexShader,
// @ts-ignore
isWHLSL: _gWebgpuCore.isSafari
}),
entryPoint: 'main'
},
fragmentStage: {
module: this.device.createShaderModule({
code: fragmentShader,
// @ts-ignore
isWHLSL: _gWebgpuCore.isSafari
}),
entryPoint: 'main'
}
key: "resetCachedViewport",
value: function resetCachedViewport() {
this.cachedViewport = {
x: 0,
y: 0,
width: 0,
height: 0
};
}
}, {
key: "getRenderPipeline",
value: function getRenderPipeline(name, descriptor) {
if (this.pipelines[name]) {
return this.pipelines[name];
key: "unbindFramebuffer",
value: function unbindFramebuffer(framebuffer) {
// unbind
if (this.currentRenderPass && this.currentRenderPass !== this.mainRenderPass) {
this.endRenderTargetRenderPass();
}
var primitiveTopology = descriptor.primitiveTopology,
rasterizationState = descriptor.rasterizationState,
depthStencilState = descriptor.depthStencilState,
colorStates = descriptor.colorStates,
vertexStage = descriptor.vertexStage,
fragmentStage = descriptor.fragmentStage,
vertexState = descriptor.vertexState,
layout = descriptor.layout;
this.transientViewport.x = Infinity;
this.currentRenderTarget = null; // if (texture.generateMipMaps && !disableGenerateMipMaps && !texture.isCube) {
// this._generateMipmaps(texture);
// }
if (vertexStage && fragmentStage) {
var renderPipeline = this.device.createRenderPipeline({
sampleCount: this.mainPassSampleCount,
primitiveTopology: primitiveTopology || 'triangle-list',
rasterizationState: _objectSpread(_objectSpread({}, this.getDefaultRasterizationStateDescriptor()), rasterizationState),
depthStencilState: _objectSpread(_objectSpread({}, this.getDefaultDepthStencilStateDescriptor()), depthStencilState),
colorStates: colorStates || this.getDefaultColorStateDescriptors(),
layout: layout,
vertexStage: vertexStage,
fragmentStage: fragmentStage,
vertexState: vertexState
});
this.pipelines[name] = renderPipeline;
return renderPipeline;
}
return null;
this.currentRenderPass = this.mainRenderPass;
}
/**
* @see https://gpuweb.github.io/gpuweb/#rasterization-state
*/
}, {
key: "getDefaultRasterizationStateDescriptor",
value: function getDefaultRasterizationStateDescriptor() {
return {
frontFace: WebGPUConstants.FrontFace.CCW,
cullMode: WebGPUConstants.CullMode.None,
depthBias: 0,
depthBiasSlopeScale: 0,
depthBiasClamp: 0
};
}
/**
* @see https://gpuweb.github.io/gpuweb/#depth-stencil-state
*/
}, {
key: "getDefaultDepthStencilStateDescriptor",
value: function getDefaultDepthStencilStateDescriptor() {
var stencilFrontBack = {
compare: WebGPUConstants.CompareFunction.Always,
depthFailOp: WebGPUConstants.StencilOperation.Keep,
failOp: WebGPUConstants.StencilOperation.Keep,
passOp: WebGPUConstants.StencilOperation.Keep
};
return {
depthWriteEnabled: false,
depthCompare: WebGPUConstants.CompareFunction.Always,
format: WebGPUConstants.TextureFormat.Depth24PlusStencil8,
stencilFront: stencilFrontBack,
stencilBack: stencilFrontBack,
stencilReadMask: 0xffffffff,
stencilWriteMask: 0xffffffff
};
}
/**
* @see https://gpuweb.github.io/gpuweb/#color-state
*/
}, {
key: "getDefaultColorStateDescriptors",
value: function getDefaultColorStateDescriptors() {
return [{
format: this.options.swapChainFormat,
// https://gpuweb.github.io/gpuweb/#blend-state
alphaBlend: {
srcFactor: WebGPUConstants.BlendFactor.One,
dstFactor: WebGPUConstants.BlendFactor.Zero,
operation: WebGPUConstants.BlendOperation.Add
},
colorBlend: {
srcFactor: WebGPUConstants.BlendFactor.One,
dstFactor: WebGPUConstants.BlendFactor.Zero,
operation: WebGPUConstants.BlendOperation.Add
},
writeMask: WebGPUConstants.ColorWrite.All
}];
}
}]);

@@ -1016,0 +650,0 @@ return WebGPUEngine;

{
"name": "@antv/g-webgpu-engine",
"version": "0.4.1",
"version": "0.5.0",
"description": "",

@@ -25,6 +25,5 @@ "main": "lib/index.js",

"dependencies": {
"@antv/g-webgpu-compiler": "^0.4.1",
"@antv/g-webgpu-core": "^0.4.1",
"@antv/g-webgpu-core": "^0.5.0",
"@webgpu/glslang": "^0.0.15",
"@webgpu/types": "^0.0.22",
"@webgpu/types": "^0.0.31",
"gl-matrix": "^3.1.0",

@@ -47,3 +46,3 @@ "hammerjs": "^2.0.8",

},
"gitHead": "5dba85a429f34d6efdfe94bdd9cc481fc975871d"
"gitHead": "a6003b54fa7581815a7d4c0ef503fb334546eacb"
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc