1

I've been trying to debug why my shaders stop working when my textures get large. After cutting and cutting and cutting I've reached the point where I have a constant-output shader only managing to overwrite the first 150 pixels of a texture.

I have no idea why there would be a boundary at 150. It certainly doesn't appear anywhere in the code. It's also not proportional to the size of the texture: decreasing the height to 128 gives a correct output, and increasing it to 256 still has the boundary issue at 150.

I've made the repro as small as I know how. Unfortunately there's still quite a lot of webgl boilerplate. Note that, although the repro omits calls to getError, the original code doesn't (and no errors were being triggered):

let canvas = document.createElement('canvas');
let gl = canvas.getContext('webgl');
const GL = WebGLRenderingContext;
let w = 1;
let h = 256;

// Create a texture that's initially all 2s.
let twos = new Uint8Array(w*h*4);
for (let i = 0; i < twos.length; i++) twos[i] = 2;
let texture = gl.createTexture();
let framebuffer = gl.createFramebuffer();
gl.bindTexture(GL.TEXTURE_2D, texture);
gl.bindFramebuffer(GL.FRAMEBUFFER, framebuffer);
gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.NEAREST);
gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST);
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);
gl.texImage2D(GL.TEXTURE_2D, 0, GL.RGBA, w, h, 0, GL.RGBA, GL.UNSIGNED_BYTE, twos);
gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0, GL.TEXTURE_2D, texture, 0);

gl.bindBuffer(GL.ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(GL.ARRAY_BUFFER, new Float32Array([-1,1,1,1,-1,-1,1,-1]), GL.STATIC_DRAW);
gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array([0,2,1,2,3,1]), GL.STATIC_DRAW);

// Create a set-all-to-1s shader.
let glVertexShader = gl.createShader(GL.VERTEX_SHADER);
let glFragmentShader = gl.createShader(GL.FRAGMENT_SHADER);
let program = gl.createProgram();
gl.shaderSource(glVertexShader, "attribute vec2 position;void main(){gl_Position = vec4(position, 0, 1);}");
gl.shaderSource(glFragmentShader, "void main(){gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0)/255.0;}");
gl.compileShader(glVertexShader);
gl.compileShader(glFragmentShader);
gl.attachShader(program, glVertexShader);
gl.attachShader(program, glFragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
gl.enableVertexAttribArray(gl.getAttribLocation(program, 'position'));
gl.vertexAttribPointer(gl.getAttribLocation(program, 'position'), 2, WebGLRenderingContext.FLOAT, false, 0, 0);

// Should cause all the texture's pixels to get painted [1,1,1,1].
gl.drawElements(GL.TRIANGLES, 6, GL.UNSIGNED_SHORT, 0);

// Read texture's pixels.
let result = new Uint8Array(w * h * 4);
gl.readPixels(0, 0, w, h, GL.RGBA, GL.UNSIGNED_BYTE, result);

console.log(result.join(""));

When I run the above snippet, the console logs 600 ones (600=150*4) followed by 424 twos:

1111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111112222222222222222222222222222222222222222
2222222222222222222222222222222222222222222222222222222222222222
2222222222222222222222222222222222222222222222222222222222222222
2222222222222222222222222222222222222222222222222222222222222222
2222222222222222222222222222222222222222222222222222222222222222
2222222222222222222222222222222222222222222222222222222222222222
2222222222222222222222222222222222222222222222222222222222222222

What could be causing this?

Craig Gidney
  • 17,763
  • 5
  • 68
  • 136

1 Answers1

1

The viewport wasn't tall enough. The discontinuity was at 150 pixels / 600 outputs because the default height of a canvas is 150 pixels, and the viewport defaults to the size of the canvas when the webgl context is created.

Just call gl.viewport(0, 0, w, h) before the draw call.

Community
  • 1
  • 1
Craig Gidney
  • 17,763
  • 5
  • 68
  • 136
  • 1
    I mean you didnt set the `gl.viewport` which defaults to the canvas size in webgl. So your viewport size is mismatched with your texture size. If you add `gl.viewport(0,0,w,h);` in your example i see it only log 1s. – WacławJasper Mar 21 '16 at 05:43
  • 1
    Just to be clear, the viewport defaults to the size of the canvas when the webgl context is created. So technically the default size of the viewport is not 300x150, the default size of the canvas is 300x150. In other words if the canvas size was set to 75x25 before calling `getContext` the viewport would start at 75x25. After that it's up to you to set it to any new sizes for your needs. – gman Mar 22 '16 at 03:26
  • @gman Ah, I see. When I said "that" it could have meant "the current size of the canvas" or "the default size of a canvas". Clarified. – Craig Gidney Mar 22 '16 at 04:18