UNPKG

20.3 kBJavaScriptView Raw
1import _regeneratorRuntime from "@babel/runtime/regenerator";
2import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
3import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
4import _createClass from "@babel/runtime/helpers/createClass";
5
6var _dec, _class, _temp;
7
8/**
9 * implements renderService with WebGPU API
10 * @see https://webgpu.io/
11 * @see https://github.com/BabylonJS/Babylon.js/blob/WebGPU/src/Engines/webgpuEngine.ts
12 */
13import { isSafari } from '@antv/g-webgpu-core'; // import { Glslang } from '@webgpu/glslang/dist/web-devel/glslang.onefile';
14
15import * as WebGPUConstants from '@webgpu/types/dist/constants';
16import { injectable } from 'inversify';
17import glslang from './glslang';
18import WebGPUAttribute from './WebGPUAttribute';
19import WebGPUBuffer from './WebGPUBuffer';
20import WebGPUComputeModel from './WebGPUComputeModel';
21import WebGPUElements from './WebGPUElements';
22import WebGPUFramebuffer from './WebGPUFramebuffer';
23import WebGPUModel from './WebGPUModel';
24import WebGPUTexture2D from './WebGPUTexture2D';
25export
26/**
27 * regl renderer
28 */
29var WebGPUEngine = (_dec = injectable(), _dec(_class = (_temp = /*#__PURE__*/function () {
30 function WebGPUEngine() {
31 var _this = this;
32
33 _classCallCheck(this, WebGPUEngine);
34
35 this.supportWebGPU = true;
36 this.useWGSL = false;
37 this.options = void 0;
38 this.canvas = void 0;
39 this.context = void 0;
40 this.glslang = void 0;
41 this.adapter = void 0;
42 this.device = void 0;
43 this.swapChain = void 0;
44 this.mainPassSampleCount = void 0;
45 this.mainTexture = void 0;
46 this.depthTexture = void 0;
47 this.mainColorAttachments = void 0;
48 this.mainTextureExtends = void 0;
49 this.mainDepthAttachment = void 0;
50 this.uploadEncoder = void 0;
51 this.renderEncoder = void 0;
52 this.computeEncoder = void 0;
53 this.renderTargetEncoder = void 0;
54 this.commandBuffers = new Array(4).fill(undefined);
55 this.currentRenderPass = null;
56 this.mainRenderPass = null;
57 this.currentRenderTargetViewDescriptor = void 0;
58 this.currentComputePass = null;
59 this.bundleEncoder = void 0;
60 this.tempBuffers = [];
61 this.currentRenderTarget = null;
62 this.uploadEncoderDescriptor = {
63 label: 'upload'
64 };
65 this.renderEncoderDescriptor = {
66 label: 'render'
67 };
68 this.renderTargetEncoderDescriptor = {
69 label: 'renderTarget'
70 };
71 this.computeEncoderDescriptor = {
72 label: 'compute'
73 };
74 this.pipelines = {};
75 this.computePipelines = {};
76 this.defaultSampleCount = 4;
77 this.clearDepthValue = 1;
78 this.clearStencilValue = 0;
79 this.transientViewport = {
80 x: Infinity,
81 y: 0,
82 width: 0,
83 height: 0
84 };
85 this.cachedViewport = {
86 x: 0,
87 y: 0,
88 width: 0,
89 height: 0
90 };
91
92 this.clear = function (options) {
93 var framebuffer = options.framebuffer,
94 color = options.color,
95 depth = options.depth,
96 stencil = options.stencil;
97
98 if (_this.options.supportCompute) {
99 _this.startComputePass();
100 } // We need to recreate the render pass so that the new parameters for clear color / depth / stencil are taken into account
101
102
103 if (_this.currentRenderTarget) {
104 if (_this.currentRenderPass) {
105 _this.endRenderTargetRenderPass();
106 }
107
108 _this.startRenderTargetRenderPass(_this.currentRenderTarget, color ? color : null, !!depth, !!stencil);
109 } else {
110 // if (this.useReverseDepthBuffer) {
111 // this._depthCullingState.depthFunc = Constants.GREATER;
112 // }
113 _this.mainColorAttachments[0].loadValue = color ? color : WebGPUConstants.LoadOp.Load;
114 _this.mainDepthAttachment.depthLoadValue = depth ? depth : WebGPUConstants.LoadOp.Load;
115 _this.mainDepthAttachment.stencilLoadValue = stencil ? _this.clearStencilValue : WebGPUConstants.LoadOp.Load;
116
117 if (_this.mainRenderPass) {
118 _this.endMainRenderPass();
119 }
120
121 _this.startMainRenderPass();
122 }
123 };
124
125 this.createModel = /*#__PURE__*/function () {
126 var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(options) {
127 var model;
128 return _regeneratorRuntime.wrap(function _callee$(_context) {
129 while (1) {
130 switch (_context.prev = _context.next) {
131 case 0:
132 model = new WebGPUModel(_this, options);
133 _context.next = 3;
134 return model.init();
135
136 case 3:
137 return _context.abrupt("return", model);
138
139 case 4:
140 case "end":
141 return _context.stop();
142 }
143 }
144 }, _callee);
145 }));
146
147 return function (_x) {
148 return _ref.apply(this, arguments);
149 };
150 }();
151
152 this.createAttribute = function (options) {
153 return new WebGPUAttribute(_this, options);
154 };
155
156 this.createBuffer = function (options) {
157 return new WebGPUBuffer(_this, options);
158 };
159
160 this.createElements = function (options) {
161 return new WebGPUElements(_this, options);
162 };
163
164 this.createTexture2D = function (options) {
165 return new WebGPUTexture2D(_this, options);
166 };
167
168 this.createFramebuffer = function (options) {
169 return new WebGPUFramebuffer(_this, options);
170 };
171
172 this.useFramebuffer = function (framebuffer, drawCommands) {
173 // bind
174 if (_this.currentRenderTarget) {
175 _this.unbindFramebuffer(_this.currentRenderTarget);
176 }
177
178 _this.currentRenderTarget = framebuffer; // TODO: use mipmap options in framebuffer
179
180 _this.currentRenderTargetViewDescriptor = {
181 dimension: WebGPUConstants.TextureViewDimension.E2d,
182 // mipLevelCount: bindWithMipMaps ? WebGPUTextureHelper.computeNumMipmapLevels(texture.width, texture.height) - lodLevel : 1,
183 // baseArrayLayer: faceIndex,
184 // baseMipLevel: lodLevel,
185 arrayLayerCount: 1,
186 aspect: WebGPUConstants.TextureAspect.All
187 };
188 _this.currentRenderPass = null;
189 drawCommands();
190 };
191
192 this.createComputeModel = /*#__PURE__*/function () {
193 var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(context) {
194 var model;
195 return _regeneratorRuntime.wrap(function _callee2$(_context2) {
196 while (1) {
197 switch (_context2.prev = _context2.next) {
198 case 0:
199 model = new WebGPUComputeModel(_this, context);
200 _context2.next = 3;
201 return model.init();
202
203 case 3:
204 return _context2.abrupt("return", model);
205
206 case 4:
207 case "end":
208 return _context2.stop();
209 }
210 }
211 }, _callee2);
212 }));
213
214 return function (_x2) {
215 return _ref2.apply(this, arguments);
216 };
217 }();
218
219 this.getCanvas = function () {
220 return _this.canvas;
221 };
222
223 this.getGLContext = function () {
224 throw new Error('Method not implemented.');
225 };
226
227 this.viewport = function (_ref3) {
228 var x = _ref3.x,
229 y = _ref3.y,
230 width = _ref3.width,
231 height = _ref3.height;
232
233 if (!_this.currentRenderPass) {
234 // call viewport() before current render pass created
235 _this.transientViewport = {
236 x: x,
237 y: y,
238 width: width,
239 height: height
240 };
241 } else if (_this.transientViewport.x !== Infinity) {
242 var renderPass = _this.getCurrentRenderPass(); // @see https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-setviewport
243
244
245 renderPass.setViewport(_this.transientViewport.x, _this.transientViewport.y, _this.transientViewport.width, _this.transientViewport.height, 0, 1);
246 } else if (x !== _this.cachedViewport.x || y !== _this.cachedViewport.y || width !== _this.cachedViewport.width || height !== _this.cachedViewport.height) {
247 _this.cachedViewport = {
248 x: x,
249 y: y,
250 width: width,
251 height: height
252 };
253
254 var _renderPass = _this.getCurrentRenderPass();
255
256 _renderPass.setViewport(x, y, width, height, 0, 1);
257 }
258 };
259
260 this.readPixels = function (options) {
261 throw new Error('Method not implemented.');
262 };
263 }
264
265 _createClass(WebGPUEngine, [{
266 key: "isFloatSupported",
267 value: function isFloatSupported() {
268 return true;
269 }
270 }, {
271 key: "init",
272 value: function () {
273 var _init = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(config) {
274 return _regeneratorRuntime.wrap(function _callee3$(_context3) {
275 while (1) {
276 switch (_context3.prev = _context3.next) {
277 case 0:
278 this.canvas = config.canvas;
279 this.options = config;
280 this.useWGSL = !!config.useWGSL;
281 this.mainPassSampleCount = config.antialiasing ? this.defaultSampleCount : 1;
282 _context3.next = 6;
283 return this.initGlslang();
284
285 case 6:
286 this.initContextAndSwapChain();
287 this.initMainAttachments();
288
289 case 8:
290 case "end":
291 return _context3.stop();
292 }
293 }
294 }, _callee3, this);
295 }));
296
297 function init(_x3) {
298 return _init.apply(this, arguments);
299 }
300
301 return init;
302 }()
303 }, {
304 key: "destroy",
305 value: function destroy() {
306 if (this.mainTexture) {
307 this.mainTexture.destroy();
308 }
309
310 if (this.depthTexture) {
311 this.depthTexture.destroy();
312 }
313
314 this.tempBuffers.forEach(function (buffer) {
315 return buffer.destroy();
316 });
317 this.tempBuffers = [];
318 }
319 }, {
320 key: "beginFrame",
321 value: function beginFrame() {
322 this.uploadEncoder = this.device.createCommandEncoder(this.uploadEncoderDescriptor);
323 this.renderEncoder = this.device.createCommandEncoder(this.renderEncoderDescriptor);
324 this.renderTargetEncoder = this.device.createCommandEncoder(this.renderTargetEncoderDescriptor);
325
326 if (this.options.supportCompute) {
327 this.computeEncoder = this.device.createCommandEncoder(this.computeEncoderDescriptor);
328 }
329 }
330 }, {
331 key: "endFrame",
332 value: function endFrame() {
333 if (this.options.supportCompute) {
334 this.endComputePass();
335 }
336
337 this.endMainRenderPass();
338 this.commandBuffers[0] = this.uploadEncoder.finish();
339 this.commandBuffers[1] = this.renderEncoder.finish();
340
341 if (this.options.supportCompute) {
342 this.commandBuffers[2] = this.computeEncoder.finish();
343 }
344
345 this.commandBuffers[3] = this.renderTargetEncoder.finish();
346
347 if (isSafari) {
348 this.device // @ts-ignore
349 .getQueue().submit(this.commandBuffers.filter(function (buffer) {
350 return buffer;
351 }));
352 } else {
353 this.device.defaultQueue.submit(this.commandBuffers.filter(function (buffer) {
354 return buffer;
355 }));
356 }
357 }
358 }, {
359 key: "getCurrentRenderPass",
360 value: function getCurrentRenderPass() {
361 if (this.currentRenderTarget && !this.currentRenderPass) {
362 this.startRenderTargetRenderPass(this.currentRenderTarget, null, false, false);
363 } else if (!this.currentRenderPass) {
364 this.startMainRenderPass();
365 }
366
367 return this.currentRenderPass;
368 }
369 }, {
370 key: "initGlslang",
371 value: function () {
372 var _initGlslang = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
373 var _navigator, _navigator$gpu;
374
375 return _regeneratorRuntime.wrap(function _callee4$(_context4) {
376 while (1) {
377 switch (_context4.prev = _context4.next) {
378 case 0:
379 _context4.next = 2;
380 return glslang();
381
382 case 2:
383 this.glslang = _context4.sent;
384 _context4.next = 5;
385 return (_navigator = navigator) === null || _navigator === void 0 ? void 0 : (_navigator$gpu = _navigator.gpu) === null || _navigator$gpu === void 0 ? void 0 : _navigator$gpu.requestAdapter();
386
387 case 5:
388 this.adapter = _context4.sent;
389 _context4.next = 8;
390 return this.adapter.requestDevice();
391
392 case 8:
393 this.device = _context4.sent;
394
395 case 9:
396 case "end":
397 return _context4.stop();
398 }
399 }
400 }, _callee4, this);
401 }));
402
403 function initGlslang() {
404 return _initGlslang.apply(this, arguments);
405 }
406
407 return initGlslang;
408 }()
409 }, {
410 key: "initContextAndSwapChain",
411 value: function initContextAndSwapChain() {
412 this.context = this.canvas.getContext(isSafari ? 'gpu' : 'gpupresent');
413 this.swapChain = this.context.configureSwapChain({
414 device: this.device,
415 format: this.options.swapChainFormat,
416 usage: WebGPUConstants.TextureUsage.OutputAttachment | WebGPUConstants.TextureUsage.CopySrc
417 });
418 }
419 }, {
420 key: "initMainAttachments",
421 value: function initMainAttachments() {
422 this.mainTextureExtends = {
423 width: this.canvas.width,
424 height: this.canvas.height,
425 depth: 1
426 };
427
428 if (this.options.antialiasing) {
429 var mainTextureDescriptor = {
430 size: this.mainTextureExtends,
431 // TODO: arrayLayerCount is deprecated: use size.depth
432 // arrayLayerCount: 1,
433 mipLevelCount: 1,
434 sampleCount: this.mainPassSampleCount,
435 dimension: WebGPUConstants.TextureDimension.E2d,
436 format: WebGPUConstants.TextureFormat.BGRA8Unorm,
437 usage: WebGPUConstants.TextureUsage.OutputAttachment
438 };
439
440 if (this.mainTexture) {
441 this.mainTexture.destroy();
442 }
443
444 this.mainTexture = this.device.createTexture(mainTextureDescriptor);
445 this.mainColorAttachments = [{
446 attachment: isSafari ? // @ts-ignore
447 this.mainTexture.createDefaultView() : this.mainTexture.createView(),
448 loadValue: [0, 0, 0, 1],
449 storeOp: WebGPUConstants.StoreOp.Store
450 }];
451 } else {
452 this.mainColorAttachments = [{
453 attachment: isSafari ? // @ts-ignore
454 this.swapChain.getCurrentTexture().createDefaultView() : this.swapChain.getCurrentTexture().createView(),
455 loadValue: [0, 0, 0, 1],
456 storeOp: WebGPUConstants.StoreOp.Store
457 }];
458 }
459
460 var depthTextureDescriptor = {
461 size: this.mainTextureExtends,
462 // arrayLayerCount: 1,
463 mipLevelCount: 1,
464 sampleCount: this.mainPassSampleCount,
465 dimension: WebGPUConstants.TextureDimension.E2d,
466 format: isSafari ? 'depth32float-stencil8' : WebGPUConstants.TextureFormat.Depth24PlusStencil8,
467 usage: WebGPUConstants.TextureUsage.OutputAttachment
468 };
469
470 if (this.depthTexture) {
471 this.depthTexture.destroy();
472 }
473
474 this.depthTexture = this.device.createTexture( // @ts-ignore
475 depthTextureDescriptor);
476 this.mainDepthAttachment = {
477 attachment: isSafari ? // @ts-ignore
478 this.depthTexture.createDefaultView() : this.depthTexture.createView(),
479 depthLoadValue: this.clearDepthValue,
480 depthStoreOp: WebGPUConstants.StoreOp.Store,
481 stencilLoadValue: this.clearStencilValue,
482 stencilStoreOp: WebGPUConstants.StoreOp.Store
483 };
484 }
485 }, {
486 key: "startComputePass",
487 value: function startComputePass() {
488 if (this.currentComputePass) {
489 this.endComputePass();
490 }
491
492 this.currentComputePass = this.computeEncoder.beginComputePass();
493 }
494 }, {
495 key: "startMainRenderPass",
496 value: function startMainRenderPass() {
497 if (this.currentRenderPass && !this.currentRenderTarget) {
498 this.endMainRenderPass();
499 } // Resolve in case of MSAA
500
501
502 if (this.options.antialiasing) {
503 this.mainColorAttachments[0].resolveTarget = isSafari ? // @ts-ignore
504 this.swapChain.getCurrentTexture().createDefaultView() : this.swapChain.getCurrentTexture().createView();
505 } else {
506 this.mainColorAttachments[0].attachment = isSafari ? // @ts-ignore
507 this.swapChain.getCurrentTexture().createDefaultView() : this.swapChain.getCurrentTexture().createView();
508 }
509
510 this.currentRenderPass = this.renderEncoder.beginRenderPass({
511 colorAttachments: this.mainColorAttachments,
512 depthStencilAttachment: this.mainDepthAttachment // TODO: use framebuffer's depth & stencil
513
514 });
515 this.mainRenderPass = this.currentRenderPass;
516
517 if (this.cachedViewport) {
518 this.viewport(this.cachedViewport);
519 }
520 }
521 }, {
522 key: "startRenderTargetRenderPass",
523 value: function startRenderTargetRenderPass(renderTarget, clearColor, clearDepth) {
524 var _renderTarget$get$col, _renderTarget$get$dep;
525
526 var clearStencil = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
527 var gpuTexture = (_renderTarget$get$col = renderTarget.get().color) === null || _renderTarget$get$col === void 0 ? void 0 : _renderTarget$get$col.texture;
528 var colorTextureView;
529
530 if (gpuTexture) {
531 colorTextureView = gpuTexture.createView(this.currentRenderTargetViewDescriptor);
532 }
533
534 var depthStencilTexture = (_renderTarget$get$dep = renderTarget.get().depth) === null || _renderTarget$get$dep === void 0 ? void 0 : _renderTarget$get$dep.texture;
535 var depthStencilTextureView;
536
537 if (depthStencilTexture) {
538 depthStencilTextureView = depthStencilTexture.createView();
539 }
540
541 var renderPass = this.renderTargetEncoder.beginRenderPass({
542 colorAttachments: [{
543 attachment: colorTextureView,
544 loadValue: clearColor !== null ? clearColor : WebGPUConstants.LoadOp.Load,
545 storeOp: WebGPUConstants.StoreOp.Store
546 }],
547 depthStencilAttachment: depthStencilTexture && depthStencilTextureView ? {
548 attachment: depthStencilTextureView,
549 depthLoadValue: clearDepth ? this.clearDepthValue : WebGPUConstants.LoadOp.Load,
550 depthStoreOp: WebGPUConstants.StoreOp.Store,
551 stencilLoadValue: clearStencil ? this.clearStencilValue : WebGPUConstants.LoadOp.Load,
552 stencilStoreOp: WebGPUConstants.StoreOp.Store
553 } : undefined
554 });
555 this.currentRenderPass = renderPass;
556
557 if (this.cachedViewport) {
558 this.viewport(this.cachedViewport);
559 } // TODO WEBGPU set the scissor rect and the stencil reference value
560
561 }
562 }, {
563 key: "endMainRenderPass",
564 value: function endMainRenderPass() {
565 if (this.currentRenderPass === this.mainRenderPass && this.currentRenderPass !== null) {
566 this.currentRenderPass.endPass();
567 this.resetCachedViewport();
568 this.currentRenderPass = null;
569 this.mainRenderPass = null;
570 }
571 }
572 }, {
573 key: "endComputePass",
574 value: function endComputePass() {
575 if (this.currentComputePass) {
576 this.currentComputePass.endPass();
577 this.currentComputePass = null;
578 }
579 }
580 }, {
581 key: "endRenderTargetRenderPass",
582 value: function endRenderTargetRenderPass() {
583 if (this.currentRenderPass) {
584 this.currentRenderPass.endPass();
585 this.resetCachedViewport();
586 }
587 }
588 }, {
589 key: "resetCachedViewport",
590 value: function resetCachedViewport() {
591 this.cachedViewport = {
592 x: 0,
593 y: 0,
594 width: 0,
595 height: 0
596 };
597 }
598 }, {
599 key: "unbindFramebuffer",
600 value: function unbindFramebuffer(framebuffer) {
601 // unbind
602 if (this.currentRenderPass && this.currentRenderPass !== this.mainRenderPass) {
603 this.endRenderTargetRenderPass();
604 }
605
606 this.transientViewport.x = Infinity;
607 this.currentRenderTarget = null; // if (texture.generateMipMaps && !disableGenerateMipMaps && !texture.isCube) {
608 // this._generateMipmaps(texture);
609 // }
610
611 this.currentRenderPass = this.mainRenderPass;
612 }
613 }]);
614
615 return WebGPUEngine;
616}(), _temp)) || _class);
617//# sourceMappingURL=index.js.map
\No newline at end of file