UNPKG

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