Search code examples
javascriptwebglwebgl2

Updating WebGL texture from color buffer during creation fails


I have a WebGL texture,initially filled with pixels from image. Now I am trying to clear it with solid color from an array. Here is my function to create a texture2D:

function createGLTexture(gl, format,intFormat, w, h,wrapType, flip, genMipmaps, data)
{
  var texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, texture);
  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flip);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S,wrapType);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T,wrapType);
  if (genMipmaps === true)
  {
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
    gl.texStorage2D(gl.TEXTURE_2D, 1, intFormat, w, h);
  } else
  {
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texStorage2D(gl.TEXTURE_2D, 1, intFormat, w, h);
  }

  if (data != null) {
    gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, format, gl.UNSIGNED_BYTE, data);
  }

  if (genMipmaps === true) {
    gl.generateMipmap(gl.TEXTURE_2D);
  }

   return texture;
}

This is the code that initialized the texture with color:

  //img - image previously loaded
  var colorData = new Uint8Array(img.width * img.height * 3);
  for(var i = 0; i < colorData.length;i+=3)
  {
  colorData[i] = 0;
  colorData[i + 1] = 0;
  colorData[i + 2] = 255;
  } 
  var tex = createGLTexture(gl,gl.RGB,gl.RGB8,img.width,img.height,gl.CLAMP_TO_EDGE,false,false,colorData);

Calling createGLTexture functions results in the following error:

Uncaught TypeError: Failed to execute 'texSubImage2D' on 'WebGL2RenderingContext': Overload resolution failed.at createGLTexture

I can's see anything I am doing wrong in terms of data/texture size. But what I tried was to update the texture with the color immediately after initialized it from an image source:

 function updateGLTexture(gl,texture, format,w,h, genMipmaps, data)
 {
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0,w,h, format, gl.UNSIGNED_BYTE, data);
    if (genMipmaps === true)
    {
      gl.generateMipmap(gl.TEXTURE_2D);
    }
    gl.bindTexture(gl.TEXTURE_2D, null);
 }

When I am updating the texture with a color using updateGLTexture() it works. I am getting the surface cleared to blue. Why? Why texSubImage2D doesn't allow update from color buffer upon texture creation? Is calling updateGLTexture() not the same as calling texSubImage2D after storage allocation with texStorage2D?


Solution

  • The error you are encountering is hinting at the fact that you didn't provide the correct parameters to the texSubImage2D function. Some functions in WebGL/WebGL2 are "overloaded", which in effect means that based on the amount and combination of parameter types you pass into the function, the parameters may get interpreted differently.

    Judging from your error message, it seems you are using WebGL2. The WebGL2 standard defines three overloads for texSubImage2D:

    undefined texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, [AllowShared] ArrayBufferView srcData, unsigned long long srcOffset)
    undefined texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, TexImageSource source)
    undefined texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLintptr offset)
    

    However, the code that is giving you the error is trying to use an overload that only exists in WebGL1 which was subsequently removed in WebGL2. The code you provided that works is using an overload supported by WebGL2 (the first in my list). If you changed your original code to include the correct function overload from your updateGLTexture function, it should work again.

    Unfortunately, it seems like the older WebGL1 version of the API is displayed quite prominently on MDN without much clarification, so that may have lead to some confusion. It should be noted that the support for WebGL1 or WebGL2 overloads listed on MDN are exclusive, rather than inclusive -- that is, WebGL1 only supports the WebGL1 overloads, and WebGL2 only supports the WebGL2 overloads.

    For others using WebGL1, if you do use the overload from this question it should be noted that the last parameter for that specific overload must be an image (e.g. ImageData), and not a TypedArray or ArrayBuffer.