UNPKG

14.6 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4Object.defineProperty(exports, "__esModule", {
5 value: true
6});
7exports.default = void 0;
8var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
10var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
12var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
13var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
14var _isTypedArray2 = _interopRequireDefault(require("lodash/isTypedArray"));
15var _gWebgpuCore = require("@antv/g-webgpu-core");
16function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
17function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
18/* babel-plugin-inline-import './shaders/quad.vert.glsl' */
19var 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}";
20var textureId = 0;
21var debug = false;
22
23/**
24 * adaptor for regl.DrawCommand
25 */
26var ReglComputeModel = /*#__PURE__*/function () {
27 function ReglComputeModel(reGl, context) {
28 var _this = this;
29 (0, _classCallCheck2.default)(this, ReglComputeModel);
30 this.reGl = reGl;
31 this.context = context;
32 this.entity = (0, _gWebgpuCore.createEntity)();
33 this.texFBO = void 0;
34 this.computeCommand = void 0;
35 this.textureCache = {};
36 this.outputTextureName = void 0;
37 this.swapOutputTextureName = void 0;
38 this.compiledPingpong = void 0;
39 this.dynamicPingpong = void 0;
40 var uniforms = {};
41 this.context.uniforms.forEach(function (uniform) {
42 var name = uniform.name,
43 type = uniform.type,
44 data = uniform.data,
45 isReferer = uniform.isReferer,
46 storageClass = uniform.storageClass;
47 // store data with a 2D texture
48 if (storageClass === _gWebgpuCore.STORAGE_CLASS.StorageBuffer) {
49 if (!isReferer) {
50 _this.textureCache[name] = _this.calcDataTexture(name, type, data);
51 var _this$textureCache$na = _this.textureCache[name],
52 width = _this$textureCache$na.textureWidth,
53 isOutput = _this$textureCache$na.isOutput;
54 uniforms["".concat(name, "Size")] = [width, width];
55 if (isOutput) {
56 _this.outputTextureName = name;
57 if (_this.context.needPingpong) {
58 _this.outputTextureName = "".concat(name, "Output");
59 _this.textureCache[_this.outputTextureName] = _this.calcDataTexture(name, type, data);
60 }
61 }
62 } else {
63 // @ts-ignore
64 _this.textureCache[name] = {
65 data: undefined
66 };
67 // refer to another kernel's output,
68 // the referred kernel may not have been initialized, so we use dynamic way here
69 uniforms["".concat(name, "Size")] = function () {
70 return (
71 // @ts-ignore
72 data.compiledBundle.context.output.textureSize
73 );
74 };
75 }
76 uniforms[name] = function () {
77 if (debug) {
78 console.log("[".concat(_this.entity, "]: ").concat(name, " ").concat(_this.textureCache[name].id));
79 }
80 return _this.textureCache[name].texture;
81 };
82 } else if (storageClass === _gWebgpuCore.STORAGE_CLASS.Uniform) {
83 if (data && (Array.isArray(data) || (0, _isTypedArray2.default)(data)) && data.length > 16) {
84 // up to mat4 which includes 16 elements
85 throw new Error("invalid data type ".concat(type));
86 }
87 // get uniform dynamically
88 uniforms[name] = function () {
89 return uniform.data;
90 };
91 }
92 });
93 var _this$getOuputDataTex = this.getOuputDataTexture(),
94 textureWidth = _this$getOuputDataTex.textureWidth,
95 texelCount = _this$getOuputDataTex.texelCount;
96
97 // 传入 output 纹理尺寸和数据长度,便于多余的 texel 提前退出
98 uniforms.u_OutputTextureSize = [textureWidth, textureWidth];
99 uniforms.u_OutputTexelCount = texelCount;
100
101 // 保存在 Kernel 的上下文中,供其他 Kernel 引用
102 this.context.output.textureSize = [textureWidth, textureWidth];
103 var drawParams = {
104 attributes: {
105 a_Position: [[-1, 1, 0], [-1, -1, 0], [1, 1, 0], [1, -1, 0]],
106 a_TexCoord: [[0, 1], [0, 0], [1, 1], [1, 0]]
107 },
108 frag: "#ifdef GL_FRAGMENT_PRECISION_HIGH\n precision highp float;\n#else\n precision mediump float;\n#endif\n".concat(this.context.shader),
109 uniforms: uniforms,
110 vert: quadVert,
111 // TODO: use a fullscreen triangle instead.
112 primitive: 'triangle strip',
113 count: 4
114 };
115 this.computeCommand = this.reGl(drawParams);
116 }
117 (0, _createClass2.default)(ReglComputeModel, [{
118 key: "run",
119 value: function run() {
120 var _this2 = this;
121 if (this.context.maxIteration > 1 && this.context.needPingpong) {
122 this.compiledPingpong = true;
123 }
124 // need pingpong when (@in@out and execute(10)) or use `setBinding('out', self)`
125 // this.needPingpong =
126 // !!(this.context.maxIteration > 1 && this.context.needPingpong);
127
128 // if (this.relativeOutputTextureNames.length) {
129 // const { id, texture } = this.getOuputDataTexture();
130 // this.relativeOutputTextureNames.forEach((name) => {
131 // this.textureCache[name].id = id;
132 // this.textureCache[name].texture = texture;
133 // });
134 // this.swap();
135 // }
136
137 if (this.compiledPingpong || this.dynamicPingpong) {
138 this.swap();
139 }
140 this.texFBO = this.reGl.framebuffer({
141 color: this.getOuputDataTexture().texture
142 });
143 this.texFBO.use(function () {
144 _this2.computeCommand();
145 });
146 if (debug) {
147 console.log("[".concat(this.entity, "]: output ").concat(this.getOuputDataTexture().id));
148 }
149 }
150 }, {
151 key: "readData",
152 value: function () {
153 var _readData = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
154 var _this3 = this;
155 var pixels, _this$getOuputDataTex2, originalDataLength, elementsPerTexel, _this$getOuputDataTex3, typedArrayConstructor, formattedPixels, i;
156 return _regenerator.default.wrap(function _callee$(_context) {
157 while (1) {
158 switch (_context.prev = _context.next) {
159 case 0:
160 this.reGl({
161 framebuffer: this.texFBO
162 })(function () {
163 pixels = _this3.reGl.read();
164 });
165
166 // @ts-ignore
167 if (!pixels) {
168 _context.next = 6;
169 break;
170 }
171 _this$getOuputDataTex2 = this.getOuputDataTexture(), originalDataLength = _this$getOuputDataTex2.originalDataLength, elementsPerTexel = _this$getOuputDataTex2.elementsPerTexel, _this$getOuputDataTex3 = _this$getOuputDataTex2.typedArrayConstructor, typedArrayConstructor = _this$getOuputDataTex3 === void 0 ? Float32Array : _this$getOuputDataTex3;
172 formattedPixels = [];
173 if (elementsPerTexel !== 4) {
174 for (i = 0; i < pixels.length; i += 4) {
175 if (elementsPerTexel === 1) {
176 formattedPixels.push(pixels[i]);
177 } else if (elementsPerTexel === 2) {
178 formattedPixels.push(pixels[i], pixels[i + 1]);
179 } else {
180 formattedPixels.push(pixels[i], pixels[i + 1], pixels[i + 2]);
181 }
182 }
183 } else {
184 // @ts-ignore
185 formattedPixels = pixels;
186 }
187
188 // 截取多余的部分
189 // @ts-ignore
190 return _context.abrupt("return", new typedArrayConstructor(formattedPixels.slice(0, originalDataLength)));
191 case 6:
192 return _context.abrupt("return", new Float32Array());
193 case 7:
194 case "end":
195 return _context.stop();
196 }
197 }
198 }, _callee, this);
199 }));
200 function readData() {
201 return _readData.apply(this, arguments);
202 }
203 return readData;
204 }()
205 }, {
206 key: "confirmInput",
207 value: function confirmInput(model, inputName) {
208 var inputModel;
209 // refer to self, same as pingpong
210 if (this.entity === model.entity) {
211 this.dynamicPingpong = true;
212 inputModel = this;
213 } else {
214 inputModel = model;
215 }
216 this.textureCache[inputName].id = inputModel.getOuputDataTexture().id;
217 this.textureCache[inputName].texture = inputModel.getOuputDataTexture().texture;
218 if (debug) {
219 console.log("[".concat(this.entity, "]: confirm input ").concat(inputName, " from model ").concat(inputModel.entity, ", ").concat(inputModel.getOuputDataTexture().id));
220 }
221 }
222 }, {
223 key: "updateUniform",
224 value: function updateUniform() {
225 // already get uniform's data dynamically when created, do nothing here
226 }
227 }, {
228 key: "updateBuffer",
229 value: function updateBuffer(bufferName, data) {
230 var offset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
231 // regenerate data texture
232 var buffer = this.context.uniforms.find(function (_ref) {
233 var name = _ref.name;
234 return name === bufferName;
235 });
236 if (buffer) {
237 var _this$calcDataTexture = this.calcDataTexture(bufferName, buffer.type, data),
238 texture = _this$calcDataTexture.texture,
239 paddingData = _this$calcDataTexture.data;
240
241 // TODO: destroy outdated texture
242 this.textureCache[bufferName].data = paddingData;
243 this.textureCache[bufferName].texture = texture;
244 }
245 }
246 }, {
247 key: "destroy",
248 value: function destroy() {
249 // regl will destroy all resources
250 }
251 }, {
252 key: "swap",
253 value: function swap() {
254 if (!this.swapOutputTextureName) {
255 this.createSwapOutputDataTexture();
256 }
257 if (this.compiledPingpong) {
258 var outputTextureUniformName = this.context.output.name;
259 this.textureCache[outputTextureUniformName].id = this.getOuputDataTexture().id;
260 this.textureCache[outputTextureUniformName].texture = this.getOuputDataTexture().texture;
261 }
262 var tmp = this.outputTextureName;
263 this.outputTextureName = this.swapOutputTextureName;
264 this.swapOutputTextureName = tmp;
265 if (debug) {
266 console.log("[".concat(this.entity, "]: after swap, output ").concat(this.getOuputDataTexture().id));
267 }
268 }
269 }, {
270 key: "getOuputDataTexture",
271 value: function getOuputDataTexture() {
272 return this.textureCache[this.outputTextureName];
273 }
274 }, {
275 key: "createSwapOutputDataTexture",
276 value: function createSwapOutputDataTexture() {
277 var texture = this.cloneDataTexture(this.getOuputDataTexture());
278 this.swapOutputTextureName = "".concat(this.entity, "-swap");
279 this.textureCache[this.swapOutputTextureName] = texture;
280 }
281 }, {
282 key: "cloneDataTexture",
283 value: function cloneDataTexture(texture) {
284 var data = texture.data,
285 textureWidth = texture.textureWidth;
286 return _objectSpread(_objectSpread({}, texture), {}, {
287 id: textureId++,
288 // @ts-ignore
289 texture: this.reGl.texture({
290 width: textureWidth,
291 height: textureWidth,
292 data: data,
293 type: 'float'
294 })
295 });
296 }
297 }, {
298 key: "calcDataTexture",
299 value: function calcDataTexture(name, type, data) {
300 var elementsPerTexel = 1;
301 if (type === _gWebgpuCore.AST_TOKEN_TYPES.Vector4FloatArray) {
302 elementsPerTexel = 4;
303 }
304
305 // 用 0 补全不足 vec4 的部分
306 var paddingData = [];
307 for (var i = 0; i < data.length; i += elementsPerTexel) {
308 if (elementsPerTexel === 1) {
309 paddingData.push(data[i], 0, 0, 0);
310 } else if (elementsPerTexel === 2) {
311 paddingData.push(data[i], data[i + 1], 0, 0);
312 } else if (elementsPerTexel === 3) {
313 paddingData.push(data[i], data[i + 1], data[i + 2], 0);
314 } else if (elementsPerTexel === 4) {
315 paddingData.push(data[i], data[i + 1], data[i + 2], data[i + 3]);
316 }
317 }
318
319 // 使用纹理存储,例如 Array(8) 使用 3 * 3 纹理,末尾空白使用 0 填充
320 var originalDataLength = data.length;
321 var texelCount = Math.ceil(originalDataLength / elementsPerTexel);
322 var width = Math.ceil(Math.sqrt(texelCount));
323 var paddingTexelCount = width * width;
324 if (texelCount < paddingTexelCount) {
325 paddingData.push.apply(paddingData, (0, _toConsumableArray2.default)(new Array((paddingTexelCount - texelCount) * 4).fill(0)));
326 }
327 var texture = this.reGl.texture({
328 width: width,
329 height: width,
330 data: paddingData,
331 type: 'float'
332 });
333 return {
334 id: textureId++,
335 data: paddingData,
336 originalDataLength: originalDataLength,
337 typedArrayConstructor: (0, _isTypedArray2.default)(data) ? data.constructor : undefined,
338 textureWidth: width,
339 texture: texture,
340 texelCount: texelCount,
341 elementsPerTexel: elementsPerTexel,
342 isOutput: name === this.context.output.name
343 };
344 }
345 }]);
346 return ReglComputeModel;
347}();
348exports.default = ReglComputeModel;
349//# sourceMappingURL=ReglComputeModel.js.map
\No newline at end of file