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