duhaime
duhaime

Reputation: 27574

Webgl: Device seems to report incorrect gl.MAX_TEXTURE_SIZE value

I'm working on a webgl scene that involves big textures. I have been querying to determine the largest texture size supported by a given device as follows:

var gl = document.createElement('canvas').getContext('webgl')
console.log(gl.getParameter(gl.MAX_TEXTURE_SIZE))

On my 2015 Macbook Pro, I can use a texture at the returned size just fine. On a 2015 MacBook Air, however, when I try to pass a texture of the returned size as a uniform to my shaders, I get an error:

[.WebGL-0x7fcb4489200]GL ERROR :GL_INVALID_FRAMEBUFFER_OPERATION :
glGenerateMipmap <- error from previous GL command

If I use instead a texture that's size gl.getParameter(gl.MAX_TEXTURE_SIZE)/2 however, the MacBook Air renders the scene just fine and there's no error.

Is it possible the MacBook Air has mis-reported its gl capabilities? Or am I trying to determine the max texture size incorrectly? My goal is to query for the largest texture supported by the current browser device. Any suggestions others can offer on how best to achieve this goal would be entirely welcome!

I observed the behavior above in Chrome 78 and Safari 13.

Upvotes: 0

Views: 762

Answers (1)

user128511
user128511

Reputation:

Post some code! There is no guarantee you can allocate a texture of the max size since the system could be out of memory.

A texture that is MAX_TEXTURE_SIZE x 1 or 1 x MAX_TEXTURE_SIZE is likely to not run out of memory. MAX_TEXTURE_SIZE x MAX_TEXTURE_SIZE when MAX_TEXTURE_SIZE is 2^14 requires min 1gig of vram if it was RGBA/UNSIGNED_BYTE. With mips it would be 1.4gig of vram. On top of that the browser will potentially allocate 1.4gig of vram to try to clear the texture and the driver itself will potentially allocate 1.4gig of ram to backup the texture or to prepare it to be uploaded to the GPU or both. Lots of opportunity to run out of memory. If it was RGBA/FLOAT textures it would require 5.6gig.

Here's a test allocating MAX x 1

const gl = document.createElement('canvas').getContext('webgl');
const maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);
const maxRenderbufferSize = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE);
console.log('max texture size:', maxTextureSize);
console.log('max renderbuffer size:', maxRenderbufferSize);

const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(
    gl.TEXTURE_2D,
    0,
    gl.RGBA,
    maxTextureSize,
    1,
    0,
    gl.RGBA,
    gl.UNSIGNED_BYTE,
    null);
gl.generateMipmap(gl.TEXTURE_2D);
console.log('GL ERROR:', glEnumToString(gl, gl.getError()));


function glEnumToString(gl, value) {
  const keys = [];
  for (const key in gl) {
    if (gl[key] === value) {
      keys.push(key);
    }
  }
  return keys.length ? keys.join(' | ') : `0x${value.toString(16)}`;
}

Upvotes: 1

Related Questions