xref: /aosp_15_r20/external/skia/modules/canvaskit/webgpu.js (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1// Adds compile-time JS functions to augment the CanvasKit interface.
2// Specifically, anything that should only be on the WebGL version of canvaskit.
3// Functions in this file are supplemented by cpu.js.
4(function(CanvasKit){
5    CanvasKit._extraInitializations = CanvasKit._extraInitializations || [];
6    CanvasKit._extraInitializations.push(function() {
7      CanvasKit.MakeGPUDeviceContext = function(device) {
8        if (!device) {
9          return null;
10        }
11
12        // This allows native code to access this device by calling
13        // `emscripten_webgpu_get_device().`
14        CanvasKit.preinitializedWebGPUDevice = device;
15        var context = this._MakeGrContext();
16        context._device = device;
17
18        return context;
19      };
20
21      CanvasKit.MakeGPUCanvasContext = function(devCtx, canvas, opts) {
22        var canvasCtx = canvas.getContext('webgpu');
23        if (!canvasCtx) {
24          return null;
25        }
26
27        let format = (opts && opts.format) ? opts.format : navigator.gpu.getPreferredCanvasFormat();
28        // GPUCanvasConfiguration
29        canvasCtx.configure({
30            device: devCtx._device,
31            format: format,
32            alphaMode: (opts && opts.alphaMode) ? opts.alphaMode : undefined,
33        });
34
35        var context = {
36          '_inner': canvasCtx,
37          '_deviceContext': devCtx,
38          '_textureFormat': format,
39        };
40        context['requestAnimationFrame'] =  function(callback) {
41          requestAnimationFrame(function() {
42            const surface = CanvasKit.MakeGPUCanvasSurface(context);
43            if (!surface) {
44              console.error('Failed to initialize Surface for current canvas swapchain texture');
45              return;
46            }
47            callback(surface.getCanvas());
48            surface.flush();
49            surface.dispose();
50          });
51        };
52        return context;
53      };
54
55      CanvasKit.MakeGPUCanvasSurface = function(canvasCtx, colorSpace, width, height) {
56        let context = canvasCtx._inner;
57        if (!width) {
58          width = context.canvas.width;
59        }
60        if (!height) {
61          height = context.canvas.height;
62        }
63        let surface = this.MakeGPUTextureSurface(canvasCtx._deviceContext,
64                                                 context.getCurrentTexture(),
65                                                 canvasCtx._textureFormat,
66                                                 width, height, colorSpace);
67        surface._canvasContext = canvasCtx;
68        return surface;
69      };
70
71      CanvasKit.MakeGPUTextureSurface = function (devCtx, texture, textureFormat, width, height, colorSpace) {
72          colorSpace = colorSpace || null;
73
74          // JsValStore and WebGPU are objects in Emscripten's library_html5_webgpu.js utility
75          // library. JsValStore allows a WebGPU object to be imported by native code by calling the
76          // various `emscripten_webgpu_import_*` functions.
77          //
78          // The CanvasKit WASM module is responsible for removing entries from the value store by
79          // calling `emscripten_webgpu_release_js_handle` after importing the object.
80          //
81          // (see
82          // https://github.com/emscripten-core/emscripten/blob/0e63f74f36b06849ef1c777b130783a43316ade0/src/library_html5_webgpu.js
83          // for reference)
84          return this._MakeGPUTextureSurface(
85              devCtx,
86              this.JsValStore.add(texture),
87              this.WebGPU.TextureFormat.indexOf(textureFormat),
88              width, height,
89              colorSpace);
90      };
91
92      CanvasKit.Surface.prototype.assignCurrentSwapChainTexture = function() {
93        // This feature is only supported for a Surface that was created via MakeGPUCanvasSurface.
94        if (!this._canvasContext) {
95          console.log('Surface is not bound to a canvas context');
96          return false;
97        }
98        let ctx = this._canvasContext._inner;
99        return this._replaceBackendTexture(
100            CanvasKit.JsValStore.add(ctx.getCurrentTexture()),
101            CanvasKit.WebGPU.TextureFormat.indexOf(this._canvasContext._textureFormat),
102            ctx.canvas.width, ctx.canvas.height);
103      };
104
105      CanvasKit.Surface.prototype.requestAnimationFrame = function(callback, dirtyRect) {
106        if (!this.reportBackendTypeIsGPU()) {
107          return this._requestAnimationFrameInternal(callback, dirtyRect);
108        }
109
110        return requestAnimationFrame(function() {
111          // Replace the render target of the Surface with the current swapchain surface if this is
112          // bound to a canvas context.
113          if (this._canvasContext && !this.assignCurrentSwapChainTexture()) {
114            console.log('failed to replace GPU backend texture');
115            return;
116          }
117          callback(this.getCanvas());
118          this.flush(dirtyRect);
119        }.bind(this));
120      };
121
122      CanvasKit.Surface.prototype.drawOnce = function(callback, dirtyRect) {
123        if (!this.reportBackendTypeIsGPU()) {
124          this._drawOnceInternal(callback, dirtyRect);
125          return;
126        }
127
128        requestAnimationFrame(function() {
129          // Replace the render target of the Surface with the current swapchain surface if this is
130          // bound to a canvas context.
131          if (this._canvasContext && !this.assignCurrentSwapChainTexture()) {
132            console.log('failed to replace GPU backend texture');
133            return;
134          }
135          callback(this.getCanvas());
136          this.flush(dirtyRect);
137          this.dispose();
138        }.bind(this));
139      };
140    });
141}(Module));  // When this file is loaded in, the high level object is "Module".
142