Update rive-cpp to 2.0 version
[platform/core/uifw/rive-tizen.git] / submodule / skia / modules / canvaskit / gpu.js
1 // Adds compile-time JS functions to augment the CanvasKit interface.
2 // Specifically, anything that should only be on the GPU 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       function get(obj, attr, defaultValue) {
8         if (obj && obj.hasOwnProperty(attr)) {
9           return obj[attr];
10         }
11         return defaultValue;
12       }
13
14       CanvasKit.GetWebGLContext = function(canvas, attrs) {
15         if (!canvas) {
16           throw 'null canvas passed into makeWebGLContext';
17         }
18         var contextAttributes = {
19           'alpha': get(attrs, 'alpha', 1),
20           'depth': get(attrs, 'depth', 1),
21           'stencil': get(attrs, 'stencil', 8),
22           'antialias': get(attrs, 'antialias', 0),
23           'premultipliedAlpha': get(attrs, 'premultipliedAlpha', 1),
24           'preserveDrawingBuffer': get(attrs, 'preserveDrawingBuffer', 0),
25           'preferLowPowerToHighPerformance': get(attrs, 'preferLowPowerToHighPerformance', 0),
26           'failIfMajorPerformanceCaveat': get(attrs, 'failIfMajorPerformanceCaveat', 0),
27           'enableExtensionsByDefault': get(attrs, 'enableExtensionsByDefault', 1),
28           'explicitSwapControl': get(attrs, 'explicitSwapControl', 0),
29           'renderViaOffscreenBackBuffer': get(attrs, 'renderViaOffscreenBackBuffer', 0),
30         };
31
32         if (attrs && attrs['majorVersion']) {
33           contextAttributes['majorVersion'] = attrs['majorVersion']
34         } else {
35           // Default to WebGL 2 if available and not specified.
36           contextAttributes['majorVersion'] = (typeof WebGL2RenderingContext !== 'undefined') ? 2 : 1;
37         }
38
39         // This check is from the emscripten version
40         if (contextAttributes['explicitSwapControl']) {
41           throw 'explicitSwapControl is not supported';
42         }
43         // Creates a WebGL context and sets it to be the current context.
44         // These functions are defined in emscripten's library_webgl.js
45         var handle = GL.createContext(canvas, contextAttributes);
46         if (!handle) {
47           return 0;
48         }
49         GL.makeContextCurrent(handle);
50         return handle;
51       };
52
53       CanvasKit.deleteContext = function(handle) {
54         GL.deleteContext(handle);
55       };
56
57       CanvasKit._setTextureCleanup({
58         'deleteTexture': function(webglHandle, texHandle) {
59           var tex = GL.textures[texHandle];
60           if (tex) {
61             GL.getContext(webglHandle).GLctx.deleteTexture(tex);
62           }
63           GL.textures[texHandle] = null;
64         },
65       });
66
67       CanvasKit.MakeGrContext = function(ctx) {
68         // Make sure we are pointing at the right WebGL context.
69         if (!this.setCurrentContext(ctx)) {
70           return null;
71         }
72         var grCtx = this._MakeGrContext();
73         if (!grCtx) {
74           return null;
75         }
76         // This context is an index into the emscripten-provided GL wrapper.
77         grCtx._context = ctx;
78         return grCtx;
79       }
80
81       CanvasKit.MakeOnScreenGLSurface = function(grCtx, w, h, colorspace) {
82         if (!this.setCurrentContext(grCtx._context)) {
83           return null;
84         }
85         var surface = this._MakeOnScreenGLSurface(grCtx, w, h, colorspace);
86         if (!surface) {
87           return null;
88         }
89         surface._context = grCtx._context;
90         return surface;
91       }
92
93       CanvasKit.MakeRenderTarget = function() {
94         var grCtx = arguments[0];
95         if (!this.setCurrentContext(grCtx._context)) {
96           return null;
97         }
98         var surface;
99         if (arguments.length === 3) {
100           surface = this._MakeRenderTargetWH(grCtx, arguments[1], arguments[2]);
101           if (!surface) {
102             return null;
103           }
104         } else if (arguments.length === 2) {
105           surface = this._MakeRenderTargetII(grCtx, arguments[1]);
106           if (!surface) {
107             return null;
108           }
109         } else {
110           Debug('Expected 2 or 3 params');
111           return null;
112         }
113         surface._context = grCtx._context;
114         return surface;
115       }
116
117       // idOrElement can be of types:
118       //  - String - in which case it is interpreted as an id of a
119       //          canvas element.
120       //  - HTMLCanvasElement - in which the provided canvas element will
121       //          be used directly.
122       // colorSpace - sk_sp<ColorSpace> - one of the supported color spaces:
123       //          CanvasKit.ColorSpace.SRGB
124       //          CanvasKit.ColorSpace.DISPLAY_P3
125       //          CanvasKit.ColorSpace.ADOBE_RGB
126       CanvasKit.MakeWebGLCanvasSurface = function(idOrElement, colorSpace, attrs) {
127         colorSpace = colorSpace || null;
128         var canvas = idOrElement;
129         var isHTMLCanvas = typeof HTMLCanvasElement !== 'undefined' && canvas instanceof HTMLCanvasElement;
130         var isOffscreenCanvas = typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas;
131         if (!isHTMLCanvas && !isOffscreenCanvas) {
132           canvas = document.getElementById(idOrElement);
133           if (!canvas) {
134             throw 'Canvas with id ' + idOrElement + ' was not found';
135           }
136         }
137
138         var ctx = this.GetWebGLContext(canvas, attrs);
139         if (!ctx || ctx < 0) {
140           throw 'failed to create webgl context: err ' + ctx;
141         }
142
143         var grcontext = this.MakeGrContext(ctx);
144
145         // Note that canvas.width/height here is used because it gives the size of the buffer we're
146         // rendering into. This may not be the same size the element is displayed on the page, which
147         // constrolled by css, and available in canvas.clientWidth/height.
148         var surface = this.MakeOnScreenGLSurface(grcontext, canvas.width, canvas.height, colorSpace);
149         if (!surface) {
150           Debug('falling back from GPU implementation to a SW based one');
151           // we need to throw away the old canvas (which was locked to
152           // a webGL context) and create a new one so we can
153           var newCanvas = canvas.cloneNode(true);
154           var parent = canvas.parentNode;
155           parent.replaceChild(newCanvas, canvas);
156           // add a class so the user can detect that it was replaced.
157           newCanvas.classList.add('ck-replaced');
158
159           return CanvasKit.MakeSWCanvasSurface(newCanvas);
160         }
161         return surface;
162       };
163       // Default to trying WebGL first.
164       CanvasKit.MakeCanvasSurface = CanvasKit.MakeWebGLCanvasSurface;
165
166       function pushTexture(tex) {
167         // GL is an emscripten object that holds onto WebGL state. One item in that state is
168         // an array of textures, of which the index is the handle/id. We must call getNewId so
169         // the GL's tracking of textures is up to date and we do not accidentally use the same
170         // texture in two different places if Skia creates a texture. (e.g. skbug.com/12797)
171         var texHandle = GL.getNewId(GL.textures);
172         GL.textures[texHandle] = tex;
173         return texHandle
174       }
175
176       CanvasKit.Surface.prototype.makeImageFromTexture = function(tex, info) {
177         CanvasKit.setCurrentContext(this._context);
178         var texHandle = pushTexture(tex);
179         var img = this._makeImageFromTexture(this._context, texHandle, info);
180         if (img) {
181           img._tex = texHandle;
182         }
183         return img;
184       };
185
186       // We try to find the natural media type (for <img> and <video>), display* for
187       // https://developer.mozilla.org/en-US/docs/Web/API/VideoFrame and then fall back to
188       // the height and width (to cover <canvas>, ImageBitmap or ImageData).
189       function getHeight(src) {
190         return src['naturalHeight'] || src['videoHeight'] || src['displayHeight'] || src['height'];
191       }
192
193       function getWidth(src) {
194         return src['naturalWidth'] || src['videoWidth'] || src['displayWidth'] || src['width'];
195       }
196
197       CanvasKit.Surface.prototype.makeImageFromTextureSource = function(src, info) {
198         if (!info) {
199           info = {
200             'height': getHeight(src),
201             'width': getWidth(src),
202             'colorType': CanvasKit.ColorType.RGBA_8888,
203             'alphaType': CanvasKit.AlphaType.Unpremul,
204           };
205         }
206         if (!info['colorSpace']) {
207           info['colorSpace'] = CanvasKit.ColorSpace.SRGB;
208         }
209         if (info['colorType'] !== CanvasKit.ColorType.RGBA_8888) {
210           Debug('colorType currently has no impact on makeImageFromTextureSource');
211         }
212
213         // We want to be pointing at the context associated with this surface.
214         CanvasKit.setCurrentContext(this._context);
215         var glCtx = GL.currentContext.GLctx;
216         var newTex = glCtx.createTexture();
217         glCtx.bindTexture(glCtx.TEXTURE_2D, newTex);
218         if (GL.currentContext.version === 2) {
219           glCtx.texImage2D(glCtx.TEXTURE_2D, 0, glCtx.RGBA, info['width'], info['height'], 0, glCtx.RGBA, glCtx.UNSIGNED_BYTE, src);
220         } else {
221           glCtx.texImage2D(glCtx.TEXTURE_2D, 0, glCtx.RGBA, glCtx.RGBA, glCtx.UNSIGNED_BYTE, src);
222         }
223         glCtx.bindTexture(glCtx.TEXTURE_2D, null);
224         return this.makeImageFromTexture(newTex, info);
225       };
226
227       CanvasKit.Surface.prototype.updateTextureFromSource = function(img, src) {
228         if (!img._tex) {
229           Debug('Image is not backed by a user-provided texture');
230           return;
231         }
232         CanvasKit.setCurrentContext(this._context);
233         var glCtx = GL.currentContext.GLctx;
234         // Copy the contents of src over the texture associated with this image.
235         var tex = GL.textures[img._tex];
236         glCtx.bindTexture(glCtx.TEXTURE_2D, tex);
237         if (GL.currentContext.version === 2) {
238           glCtx.texImage2D(glCtx.TEXTURE_2D, 0, glCtx.RGBA, getWidth(src), getHeight(src), 0, glCtx.RGBA, glCtx.UNSIGNED_BYTE, src);
239         } else {
240           glCtx.texImage2D(glCtx.TEXTURE_2D, 0, glCtx.RGBA, glCtx.RGBA, glCtx.UNSIGNED_BYTE, src);
241         }
242         glCtx.bindTexture(glCtx.TEXTURE_2D, null);
243         // Tell Skia we messed with the currently bound texture.
244         this._resetContext();
245         // Create a new texture entry and put null into the old slot. This keeps our texture alive,
246         // otherwise it will be deleted when we delete the old Image.
247         GL.textures[img._tex] = null;
248         img._tex = pushTexture(tex);
249         var ii = img.getImageInfo();
250         ii['colorSpace'] = img.getColorSpace();
251         // Skia may cache parts of the image, and some places assume images are immutable. In order
252         // to make things work, we create a new SkImage based on the same texture as the old image.
253         var newImg = this._makeImageFromTexture(this._context, img._tex, ii);
254         // To make things more ergonomic for the user, we change passed in img object to refer
255         // to the new image and clean up the old SkImage object. This has the effect of updating
256         // the Image (from the user's side of things), because they shouldn't be caring about what
257         // part of WASM memory we are pointing to.
258         // The $$ part is provided by emscripten's embind, so this could break if they change
259         // things on us.
260         // https://github.com/emscripten-core/emscripten/blob/a65d70c809f077542649c60097787e1c7460ced6/src/embind/embind.js
261         // They do not do anything special to keep closure from minifying things and neither do we.
262         var oldPtr = img.$$.ptr;
263         var oldSmartPtr = img.$$.smartPtr;
264         img.$$.ptr = newImg.$$.ptr;
265         img.$$.smartPtr = newImg.$$.smartPtr;
266         // We want to clean up the previous image, so we swap out the pointers and call delete on it
267         // which should have that effect.
268         newImg.$$.ptr = oldPtr;
269         newImg.$$.smartPtr = oldSmartPtr;
270         newImg.delete();
271         // Clean up the colorspace that we used.
272         ii['colorSpace'].delete();
273       }
274
275       CanvasKit.MakeLazyImageFromTextureSource = function(src, info) {
276         if (!info) {
277           info = {
278             'height': getHeight(src),
279             'width': getWidth(src),
280             'colorType': CanvasKit.ColorType.RGBA_8888,
281             'alphaType': CanvasKit.AlphaType.Unpremul,
282           };
283         }
284         if (!info['colorSpace']) {
285           info['colorSpace'] = CanvasKit.ColorSpace.SRGB;
286         }
287         if (info['colorType'] !== CanvasKit.ColorType.RGBA_8888) {
288           Debug('colorType currently has no impact on MakeLazyImageFromTextureSource');
289         }
290
291         var callbackObj = {
292           'makeTexture': function() {
293             // This callback function will make a texture on the current drawing surface (i.e.
294             // the current WebGL context). It assumes that Skia is just about to draw the texture
295             // to the desired surface, and thus the currentContext is the correct one.
296             // This is a lot easier than needing to pass the surface handle from the C++ side here.
297             var ctx = GL.currentContext;
298             var glCtx = ctx.GLctx;
299             var newTex = glCtx.createTexture();
300             glCtx.bindTexture(glCtx.TEXTURE_2D, newTex);
301             if (ctx.version === 2) {
302               glCtx.texImage2D(glCtx.TEXTURE_2D, 0, glCtx.RGBA, info['width'], info['height'], 0, glCtx.RGBA, glCtx.UNSIGNED_BYTE, src);
303             } else {
304               glCtx.texImage2D(glCtx.TEXTURE_2D, 0, glCtx.RGBA, glCtx.RGBA, glCtx.UNSIGNED_BYTE, src);
305             }
306             glCtx.bindTexture(glCtx.TEXTURE_2D, null);
307             return pushTexture(newTex);
308           },
309           'freeSrc': function() {
310             // This callback will be executed whenever the returned image is deleted. This gives
311             // us a chance to free up the src (which we now own). Generally, there's nothing
312             // we need to do (we can let JS garbage collection do its thing). The one exception
313             // is for https://developer.mozilla.org/en-US/docs/Web/API/VideoFrame, which we should
314             // close when we are done.
315           },
316         }
317         if (src.constructor.name === 'VideoFrame') {
318           callbackObj['freeSrc'] = function() {
319             src.close();
320           }
321         }
322         return CanvasKit.Image._makeFromGenerator(info, callbackObj);
323       }
324
325       CanvasKit.setCurrentContext = function(ctx) {
326         if (!ctx) {
327           return false;
328         }
329         return GL.makeContextCurrent(ctx);
330       };
331     });
332 }(Module)); // When this file is loaded in, the high level object is "Module";