WebGL on Android unable to render texture due to possible rounding issue

I’m currently working on WebGL to do number of post processing to 2d image. The Problem arises when I try to use copyTexImage2D API to send my initial texture to fragment shader with using device’s display dimensions, it resulting with solid black texture unless I artificially add any positive number that greater than one which leads to me believe issue came from some kind of rounding problem. The interesting part of the issue it’s exclusive to Android platform and won’t reproduced in iOS, OSX, Windows platforms with across different browsers.

Here is snippet from my code that copies scene that came from MapLibre to renderTexture variable.

            // render-to-texture
            gl.bindTexture(gl.TEXTURE_2D, this.renderTexture!);
            let w = gl.canvas.width;
            let h = gl.canvas.height;
            gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, w, h, 0); // Solid black texture sent to fragment shader
           // gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, w + 1, h, 0); // Texture correctly sent to fragment shader 
           // gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, w + 1, h - 1, 0); // Also works vice versa
           // gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, w - 1, h, 0); // Doesn't work

            getDeviceDimensions();

            gl.useProgram(this.program!);

            gl.uniform1i(this.sharpenLoc!, this.sharpen ? 1 : 0);
            gl.uniform1i(this.lookupLoc!, this.lookup ? 1 : 0);
            gl.uniform1i(this.grainLoc!, this.grain ? 1 : 0);

            const { lat, lng } = map.getCenter();
            gl.uniform2f(this.mapCoordsLoc!, lat, lng);

            gl.uniform2f(this.resolutionLoc!, gl.canvas.width, gl.canvas.height);

            // Pass texture
            gl.activeTexture(gl.TEXTURE0);
            gl.bindTexture(gl.TEXTURE_2D, this.renderTexture!);
            gl.uniform1i(this.renderTexLoc!, 0);

            // Pass LUT
            gl.activeTexture(gl.TEXTURE1);
            gl.bindTexture(gl.TEXTURE_2D, this.lutTexture!);
            gl.uniform1i(this.lutTexLoc!, 1);

            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

Here is how I initialise the renderTexture

            this.renderTexture = gl.createTexture()!;
            gl.bindTexture(gl.TEXTURE_2D, this.renderTexture);
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.canvas.width, gl.canvas.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

Additional Context

  • Dimensions not always power of 2 but rounding them does not solve the issue
  • gl.canvas.width & gl.canvas.height dimensions matches with destination HTML element
  • Issue can be reproduced both WebGL 1 and WebGL 2 in Android
  • Using gl.viewPort to with additional one pixel size won’t effect the issue
  • In fragment shader texture(…) function returns black color when renderTexture used as an input

Device: Google Pixel 5

Resolution: 1080×2340, Scale Factor 2.75

Browser: Google Chrome 103.0.5060.71