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