Webgl2 3D 纹理的最大尺寸?

Webgl2 maximum size of 3D texture?

我正在使用

在 webgl 中创建 3D 纹理

gl.bindTexture(gl.TEXTURE_3D, 纹理) {

const level = 0;
const internalFormat = gl.R32F;
const width = 512;
const height = 512;
const depth = 512; 

const border = 0;
const format = gl.RED;
const type = gl.FLOAT;
const data = imagesDataArray;

......命令

似乎使用 32F 值时 512*512*512 的大小有点麻烦,因为 chrome(运行 在笔记本电脑 8 gb ram 上)浏览器在上传 3D 时崩溃这种大小的纹理,但并非总是如此。使用大小为 512*512*256 的纹理似乎总是适用于我的笔记本电脑。 有没有办法提前告诉GPU相对于webgl2可以容纳的3D纹理的最大尺寸?

此致

很遗憾,没有办法知道有多少space。

您可以查询 GPU 可以处理的最大尺寸,但无法查询其可用内存量,就像您无法查询可用内存量一样 JavaScript。

也就是说,512*512*512*1(R)*4(32F) 至少是 0.5 Gig。您笔记本电脑的 GPU 有 0.5Gig 吗?您实际上可能需要至少 1gig 的 GPU 内存才能使用 .5gig 作为纹理,因为 OS 需要 space 用于您的应用程序的 windows 等...

浏览器对您可以使用的内存量也有不同的限制。

有些事情要检查。

  • 你有多少GPU显存。

    如果它不超过 0.5gig 你就不走运了

  • 如果您的 GPU 超过 0.5gig,请尝试不同的浏览器

    Firefox 的限制可能与 Chrome

  • 不同
  • 你能创建纹理吗?

    使用gl.texStorage3D,然后调用gl.getError。它是否出现内存不足错误或崩溃。

  • 如果gl.texStorage3D不崩溃你能用gl.texSubImage3D

    一次上传一点数据吗

    我怀疑这不会起作用,即使 gl.texStorage3D 确实有效,因为浏览器仍然需要分配 0.5gig 来清除您的纹理。如果它确实有效,这就指向另一个问题,即上传纹理你需要 3x-4x 的内存,至少在 Chrome.

    1. JavaScript

      中有你的数据
      data = new Float32Array(size);
      
    2. 数据被发送到 GPU 进程

      gl.texSubImage3D (or any other texSub or texImage command)
      
    3. GPU 进程将该数据发送给驱动程序

      glTexSubImage3D(...) in C++
      

      我不知道驱动程序需要 1 份还是 2 份。有可能保留 ram 中的副本并将一个上传到 GPU。它保留副本,以便它可以 如果需要将其换出以为其他内容腾出空间,请重新上传数据。 是否发生这种情况取决于驾驶员。

另请注意,虽然我认为这不是问题,但允许驱动器将纹理扩展到需要 2gig 的 RGBA32F。它可能不会这样做,但我知道过去模拟了某些格式。

注意:texImage 可能比 texStorage 占用更多的内存,因为 texImage 的语义意味着驱动程序直到您绘制之前才能真正制作纹理,因为它有不知道您以后是否要添加 mip 级别。 texStorage 另一方面,您告诉驱动程序要开始的确切大小和 mip 数量,因此它不需要中间存储。

function main() {
  const gl = document.createElement('canvas').getContext('webgl2');
  if (!gl) {
    return alert('need webgl2');
  }
  
  const tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_3D, tex);
  gl.texStorage3D(gl.TEXTURE_3D, 1, gl.R32F, 512, 512, 512);
  log('texStorage2D:', glEnumToString(gl, gl.getError()));
  const data = new Float32Array(512*512*512);
  for (let depth = 0; depth < 512; ++depth) {
    gl.texSubImage3D(gl.TEXTURE_3D, 0, 0, 0, depth, 512, 512, 1, gl.RED, gl.FLOAT, data, 512 * 512 * depth);
  }
  log('texSubImage3D:', glEnumToString(gl, gl.getError()));
}

main();

function glEnumToString(gl, value) {
  return Object.keys(WebGL2RenderingContext.prototype)
    .filter(k => gl[k] === value)
    .join(' | ');
}

function log(...args) {
  const elem = document.createElement('pre');
  elem.textContent = [...args].join(' ');
  document.body.appendChild(elem);
}