From 0d3bb1c02e66526c6ae6be62d594ce6e276b22c8 Mon Sep 17 00:00:00 2001 From: ILOVEPIE Date: Fri, 16 Feb 2024 14:27:28 -0800 Subject: [PATCH] Fixed ImageBitmap transfer mode. Some gaussian blur fixes. --- src/renderer-main.js | 252 +++++++++++++++---------- src/shaders/gauss_blur.1.fragment.glsl | 10 +- src/shaders/gauss_blur.2.fragment.glsl | 10 +- 3 files changed, 169 insertions(+), 103 deletions(-) diff --git a/src/renderer-main.js b/src/renderer-main.js index cc9e3d1..560e10d 100644 --- a/src/renderer-main.js +++ b/src/renderer-main.js @@ -150,6 +150,24 @@ const renderer_prototype = global.Object.create(Object, { writable: true }, + _outputCanvasCounter: { + /** @type {number} */ + value: global.Number.MIN_SAFE_INTEGER, + writable: true + }, + + _outputCanvasContexts: { + /** @type {Object} */ + value: null, + writable: true + }, + + _lastImageBitmap: { + /** @type {?ImageBitmap} */ + value: null, + writable: true + }, + //BEGIN WEBGL VARIABLES _renderData: { @@ -649,7 +667,7 @@ const renderer_prototype = global.Object.create(Object, { * @return {number} the factor */ value: function _calcGaussianBlur (time, style, overrides) { - const blurConstant = 1; //1.17741002251547469; + const blurConstant = 1;//1.17741002251547469; let transitionOverrides = overrides.getTransitions(); let factor = overrides.getGaussianEdgeBlur() ?? 0; for (let i = 0; i < transitionOverrides.length; i++) @@ -2434,6 +2452,7 @@ const renderer_prototype = global.Object.create(Object, { ); this._gaussEdgeBlurPass1Shader.addOption("u_texture", 0, "1i"); this._gaussEdgeBlurPass1Shader.addOption("u_sigma", 0, "1f"); + this._gaussEdgeBlurPass1Shader.addOption("u_width", 0, "1f"); this._gaussEdgeBlurPass2Shader = new sabre.Shader(); this._gaussEdgeBlurPass2Shader.load( @@ -2449,6 +2468,7 @@ const renderer_prototype = global.Object.create(Object, { ); this._gaussEdgeBlurPass2Shader.addOption("u_texture", 0, "1i"); this._gaussEdgeBlurPass2Shader.addOption("u_sigma", 0, "1f"); + this._gaussEdgeBlurPass2Shader.addOption("u_width", 0, "1f"); this._clipShader = new sabre.Shader(); this._clipShader.load( @@ -4107,70 +4127,44 @@ const renderer_prototype = global.Object.create(Object, { let sourceTexture = this._fbTextureA; let swap; if (blurInfo !== null) { - if (blurInfo.blur > 0) { - this._convEdgeBlurShader.updateOption( - "u_resolution_x", - this._compositingCanvas.width + if (blurInfo.gaussBlur > 0) { + this._gl.bindFramebuffer( + this._gl.FRAMEBUFFER, + backFramebuffer ); - this._convEdgeBlurShader.updateOption( - "u_resolution_y", - this._compositingCanvas.height + this._gl.clear( + this._gl.DEPTH_BUFFER_BIT | + this._gl.COLOR_BUFFER_BIT ); - this._convEdgeBlurShader.updateOption("u_texture", 0); - this._convEdgeBlurShader.bindShader(this._gl); - //Draw framebuffer to destination - - for (let i = 0; i < blurInfo.blur - 1; i++) { - this._gl.bindFramebuffer( - this._gl.FRAMEBUFFER, - backFramebuffer - ); - this._gl.clear( - this._gl.DEPTH_BUFFER_BIT | - this._gl.COLOR_BUFFER_BIT - ); - this._gl.activeTexture(this._gl.TEXTURE0); - this._gl.bindTexture( - this._gl.TEXTURE_2D, - sourceTexture - ); - this._gl.bindBuffer( - this._gl.ARRAY_BUFFER, - this._fullscreenPositioningBuffer - ); - this._gl.drawArrays(this._gl.TRIANGLES, 0, 6); - swap = backTexture; - backTexture = sourceTexture; - sourceTexture = swap; - swap = backFramebuffer; - backFramebuffer = sourceFramebuffer; - sourceFramebuffer = swap; - } - if (blurInfo.gaussBlur > 0 || clip_coords !== null) { - this._gl.bindFramebuffer( - this._gl.FRAMEBUFFER, - backFramebuffer - ); - this._gl.clear( - this._gl.DEPTH_BUFFER_BIT | - this._gl.COLOR_BUFFER_BIT - ); - } else { - this._gl.bindFramebuffer( - this._gl.FRAMEBUFFER, - null - ); - } - this._gl.activeTexture(this._gl.TEXTURE0); this._gl.bindTexture( this._gl.TEXTURE_2D, sourceTexture ); - + let gausswidth = (blurInfo.gaussBlur * 3.0 + 0.5) | 1; + if(gausswidth < 3) gausswidth = 3; + //Apply gaussian filter 1 + this._gaussEdgeBlurPass1Shader.updateOption( + "u_resolution_x", + this._compositingCanvas.width + ); + this._gaussEdgeBlurPass1Shader.updateOption( + "u_sigma", + blurInfo.gaussBlur + ); + this._gaussEdgeBlurPass1Shader.updateOption( + "u_width", + gausswidth + ); + this._gaussEdgeBlurPass1Shader.updateOption( + "u_texture", + 0 + ); + this._gaussEdgeBlurPass1Shader.bindShader(this._gl); + //Draw framebuffer X to framebuffer Y { let positionAttrib = - this._convEdgeBlurShader.getAttribute( + this._gaussEdgeBlurPass1Shader.getAttribute( this._gl, "a_position" ); @@ -4196,40 +4190,48 @@ const renderer_prototype = global.Object.create(Object, { swap = backFramebuffer; backFramebuffer = sourceFramebuffer; sourceFramebuffer = swap; - } - if (blurInfo.gaussBlur > 0) { - this._gl.bindFramebuffer( - this._gl.FRAMEBUFFER, - backFramebuffer - ); - this._gl.clear( - this._gl.DEPTH_BUFFER_BIT | - this._gl.COLOR_BUFFER_BIT - ); + if (blurInfo.blur > 0 || clip_coords !== null) { + this._gl.bindFramebuffer( + this._gl.FRAMEBUFFER, + backFramebuffer + ); + this._gl.clear( + this._gl.DEPTH_BUFFER_BIT | + this._gl.COLOR_BUFFER_BIT + ); + } else + this._gl.bindFramebuffer( + this._gl.FRAMEBUFFER, + null + ); this._gl.activeTexture(this._gl.TEXTURE0); this._gl.bindTexture( this._gl.TEXTURE_2D, sourceTexture ); - //Apply gaussian filter 1 - this._gaussEdgeBlurPass1Shader.updateOption( - "u_resolution_x", - this._compositingCanvas.width + //Apply gaussian filter 2 + this._gaussEdgeBlurPass2Shader.updateOption( + "u_resolution_y", + this._compositingCanvas.height ); - this._gaussEdgeBlurPass1Shader.updateOption( + this._gaussEdgeBlurPass2Shader.updateOption( "u_sigma", blurInfo.gaussBlur ); - this._gaussEdgeBlurPass1Shader.updateOption( + this._gaussEdgeBlurPass2Shader.updateOption( + "u_width", + gausswidth + ); + this._gaussEdgeBlurPass2Shader.updateOption( "u_texture", 0 ); - this._gaussEdgeBlurPass1Shader.bindShader(this._gl); - //Draw framebuffer X to framebuffer Y + this._gaussEdgeBlurPass2Shader.bindShader(this._gl); + //Draw framebuffer Y to screen { let positionAttrib = - this._gaussEdgeBlurPass1Shader.getAttribute( + this._gaussEdgeBlurPass2Shader.getAttribute( this._gl, "a_position" ); @@ -4255,7 +4257,47 @@ const renderer_prototype = global.Object.create(Object, { swap = backFramebuffer; backFramebuffer = sourceFramebuffer; sourceFramebuffer = swap; + } + if (blurInfo.blur > 0) { + this._convEdgeBlurShader.updateOption( + "u_resolution_x", + this._compositingCanvas.width + ); + this._convEdgeBlurShader.updateOption( + "u_resolution_y", + this._compositingCanvas.height + ); + this._convEdgeBlurShader.updateOption("u_texture", 0); + this._convEdgeBlurShader.bindShader(this._gl); + //Draw framebuffer to destination + + for (let i = 0; i < blurInfo.blur - 1; i++) { + this._gl.bindFramebuffer( + this._gl.FRAMEBUFFER, + backFramebuffer + ); + this._gl.clear( + this._gl.DEPTH_BUFFER_BIT | + this._gl.COLOR_BUFFER_BIT + ); + this._gl.activeTexture(this._gl.TEXTURE0); + this._gl.bindTexture( + this._gl.TEXTURE_2D, + sourceTexture + ); + this._gl.bindBuffer( + this._gl.ARRAY_BUFFER, + this._fullscreenPositioningBuffer + ); + this._gl.drawArrays(this._gl.TRIANGLES, 0, 6); + swap = backTexture; + backTexture = sourceTexture; + sourceTexture = swap; + swap = backFramebuffer; + backFramebuffer = sourceFramebuffer; + sourceFramebuffer = swap; + } if (clip_coords !== null) { this._gl.bindFramebuffer( this._gl.FRAMEBUFFER, @@ -4265,34 +4307,22 @@ const renderer_prototype = global.Object.create(Object, { this._gl.DEPTH_BUFFER_BIT | this._gl.COLOR_BUFFER_BIT ); - } else + } else { this._gl.bindFramebuffer( this._gl.FRAMEBUFFER, null ); + } + this._gl.activeTexture(this._gl.TEXTURE0); this._gl.bindTexture( this._gl.TEXTURE_2D, sourceTexture ); - //Apply gaussian filter 2 - this._gaussEdgeBlurPass2Shader.updateOption( - "u_resolution_y", - this._compositingCanvas.height - ); - this._gaussEdgeBlurPass2Shader.updateOption( - "u_sigma", - blurInfo.gaussBlur - ); - this._gaussEdgeBlurPass2Shader.updateOption( - "u_texture", - 0 - ); - this._gaussEdgeBlurPass2Shader.bindShader(this._gl); - //Draw framebuffer Y to screen + { let positionAttrib = - this._gaussEdgeBlurPass1Shader.getAttribute( + this._convEdgeBlurShader.getAttribute( this._gl, "a_position" ); @@ -4311,7 +4341,7 @@ const renderer_prototype = global.Object.create(Object, { ); this._gl.drawArrays(this._gl.TRIANGLES, 0, 6); } - + swap = backTexture; backTexture = sourceTexture; sourceTexture = swap; @@ -4478,6 +4508,7 @@ const renderer_prototype = global.Object.create(Object, { */ } }else{ + console.info("Color space support is not available for canvas, falling back to sRGB."); this._nativeColorSpace = sabre.NativeColorSpaces.RGB; } @@ -4650,6 +4681,11 @@ const renderer_prototype = global.Object.create(Object, { this._lastAnimating = true; } + if(this._lastImageBitmap !== null) { + this._lastImageBitmap.close(); + this._lastImageBitmap = null; + } + this._gl.clear( this._gl.DEPTH_BUFFER_BIT | this._gl.COLOR_BUFFER_BIT ); @@ -4773,6 +4809,27 @@ const renderer_prototype = global.Object.create(Object, { writable: false }, + + + _getOutputCanvasContext: { + /** + * Get a canvas context for the output canvas. + * @param {HTMLCanvasElement|OffscreenCanvas} canvas the canvas to get the context for. + * @param {string} type the type of context to get. + * @return {CanvasRenderingContext2D|ImageBitmapRenderingContext} the context. + */ + value: function _getOutputCanvasContext (canvas, type) { + this._outputCanvasContexts = this._outputCanvasContexts ?? {}; + if(typeof(canvas._sabreID) === "undefined"){ + canvas._sabreID = (this._outputCanvasCounter++)+""; + return this._outputCanvasContexts[canvas._sabreID] = canvas.getContext(type); + }else{ + return this._outputCanvasContexts[canvas._sabreID]; + } + }, + writable: false + }, + "getDisplayBitmap": { /** * Get an ImageBitmap containing the frame or null if ImageBitmap is unsupported. @@ -4781,7 +4838,7 @@ const renderer_prototype = global.Object.create(Object, { value: function getDisplayBitmap () { if (!isImageBitmapSupported) return null; if (this._compositingCanvas instanceof global.OffscreenCanvas) { - return this._compositingCanvas.transferToImageBitmap(); + return /** @type {ImageBitmap} */ (global.structuredClone(this._lastImageBitmap = this._lastImageBitmap ?? this._compositingCanvas.transferToImageBitmap())); } else return null; }, writable: false @@ -4797,12 +4854,13 @@ const renderer_prototype = global.Object.create(Object, { value: function copyToCanvas (canvas, bitmap) { let context; if (bitmap) { - context = canvas.getContext("bitmaprenderer"); - context.transferFromImageBitmap(this["getDisplayBitmap"]()); + const bmp = this["getDisplayBitmap"](); + context = this._getOutputCanvasContext(canvas,"bitmaprenderer"); + context.transferFromImageBitmap(bmp); } else { let width = canvas.width | 0; let height = canvas.height | 0; - context = canvas.getContext("2d"); + context = this._getOutputCanvasContext(canvas,"2d"); context.clearRect(0, 0, width, height); context.drawImage(this._compositingCanvas, 0, 0, width, height); } diff --git a/src/shaders/gauss_blur.1.fragment.glsl b/src/shaders/gauss_blur.1.fragment.glsl index 397a956..80dc495 100644 --- a/src/shaders/gauss_blur.1.fragment.glsl +++ b/src/shaders/gauss_blur.1.fragment.glsl @@ -2,6 +2,7 @@ varying vec2 v_texcoord; uniform sampler2D u_texture; uniform float u_sigma; +uniform float u_width; uniform float u_resolution_x; @@ -15,11 +16,14 @@ void main(){ vec4 accumulator = texture2D(u_texture,v_texcoord)*normpdf(0.0,u_sigma); for(float i = 1.0; i < 512.0; i++){ float gaussian_value = normpdf(i,u_sigma); - if(gaussian_value < 0.00135){ + if(gaussian_value < 0.00135 || i > u_width/2.0){ break; } - accumulator += texture2D(u_texture,clamp(v_texcoord+vec2(pixel_x*i,0),0.0,1.0)) * gaussian_value; - accumulator += texture2D(u_texture,clamp(v_texcoord-vec2(pixel_x*i,0),0.0,1.0)) * gaussian_value; + + if( v_texcoord.x + pixel_x*i <= 1.0 && v_texcoord.x - pixel_x*i >= 0.0){ + accumulator += texture2D(u_texture,clamp(v_texcoord+vec2(pixel_x*i,0),0.0,1.0)) * gaussian_value; + accumulator += texture2D(u_texture,clamp(v_texcoord-vec2(pixel_x*i,0),0.0,1.0)) * gaussian_value; + } } gl_FragColor = accumulator.rgba; diff --git a/src/shaders/gauss_blur.2.fragment.glsl b/src/shaders/gauss_blur.2.fragment.glsl index a928dda..7a89274 100644 --- a/src/shaders/gauss_blur.2.fragment.glsl +++ b/src/shaders/gauss_blur.2.fragment.glsl @@ -2,6 +2,7 @@ varying vec2 v_texcoord; uniform sampler2D u_texture; uniform float u_sigma; +uniform float u_width; uniform float u_resolution_y; @@ -15,11 +16,14 @@ void main(){ vec4 accumulator = texture2D(u_texture,v_texcoord)*normpdf(0.0,u_sigma); for(float i = 1.0; i < 512.0; i++){ float gaussian_value = normpdf(i,u_sigma); - if(gaussian_value < 0.00135){ + if(gaussian_value < 0.00135 || i > u_width/2.0){ break; } - accumulator += texture2D(u_texture,clamp(v_texcoord+vec2(0,pixel_y*i),0.0,1.0)) * gaussian_value; - accumulator += texture2D(u_texture,clamp(v_texcoord-vec2(0,pixel_y*i),0.0,1.0)) * gaussian_value; + + if( v_texcoord.y + pixel_y*i <= 1.0 && v_texcoord.y - pixel_y*i >= 0.0){ + accumulator += texture2D(u_texture,clamp(v_texcoord+vec2(0,pixel_y*i),0.0,1.0)) * gaussian_value; + accumulator += texture2D(u_texture,clamp(v_texcoord-vec2(0,pixel_y*i),0.0,1.0)) * gaussian_value; + } } gl_FragColor = accumulator.rgba;