@antv/g-webgpu-engine
Advanced tools
Comparing version 0.4.1 to 0.5.0
@@ -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 @@ |
@@ -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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
650583
11
95
6045
2
+ Added@antv/g-webgpu-core@0.5.6(transitive)
+ Added@webgpu/types@0.0.31(transitive)
+ Addedeventemitter3@4.0.7(transitive)
- Removed@antv/g-webgpu-compiler@^0.4.1
- Removed@antv/g-webgpu-compiler@0.4.1(transitive)
- Removed@antv/g-webgpu-core@0.4.1(transitive)
- Removed@webgpu/types@0.0.22(transitive)
Updated@antv/g-webgpu-core@^0.5.0
Updated@webgpu/types@^0.0.31