gpt4 book ai didi

performance - 解绑 WebGL 缓冲区,值得吗?

转载 作者:行者123 更新时间:2023-12-04 03:37:18 26 4
gpt4 key购买 nike

在各种来源中,我看到了使用后“解除绑定(bind)”缓冲区的建议,即将其设置为 null。我很好奇是否真的需要这样做。例如

var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

// ... buffer related operations ...

gl.bindBuffer(gl.ARRAY_BUFFER, null); // unbinding

一方面,它可能更适合调试,因为您可能会收到更好的错误消息,但是一直解除绑定(bind)缓冲区是否有任何显着的性能损失?通常建议尽可能减少 WebGL 调用。

最佳答案

人们经常取消绑定(bind)缓冲区和其他对象的原因是为了尽量减少函数/方法的副作用。这是一个通用的软件开发原则,函数应该只执行它们所宣传的操作,并且没有任何意外的副作用。因此,一个常见的做法是,如果一个函数绑定(bind)了对象,它会在返回之前取消绑定(bind)它们。

让我们看一个典型的例子(没有特定的语言语法)。首先,我们定义一个函数来创建一个没有任何定义内容的纹理:

function GLuint createEmptyTexture(int texWidth, int texHeight) {
GLuint texId;
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texWidth, texHeight, 0,
GL_RGBA, GL_UNSIGNED_BYTE, 0);
return texId;
}

然后,让我们使用另一个函数来创建纹理。但是这个用缓冲区中的数据填充纹理(我相信 WebGL 还不支持它,但它仍然有助于说明一般原则):
function GLuint createTextureFromBuffer(int texWidth, int texHeight,
GLuint bufferId) {
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bufferId);
GLuint texId;
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texWidth, texHeight, 0,
GL_RGBA, GL_UNSIGNED_BYTE, 0);
return texId;
}

现在,我可以调用这些函数,一切都按预期工作:
GLuint tex1 = createEmptyTexture(width, height);
GLuint tex2 = createTextureFromBuffer(width, height, bufferId);

但是看看如果我以相反的顺序调用它们会发生什么:
GLuint tex1 = createTextureFromBuffer(width, height, bufferId);
GLuint tex2 = createEmptyTexture(width, height);

这一次,两个纹理都将填充缓冲区内容,因为像素解包缓冲区在第一个函数返回后仍然绑定(bind),因此在调用第二个函数时。

避免这种情况的一种方法是在绑定(bind)它的函数末尾取消绑定(bind)像素解包缓冲区。并且为了确保由于纹理仍然绑定(bind)而不会发生类似的问题,它也可以取消绑定(bind)该纹理:
function GLuint createTextureFromBuffer(int texWidth, int texHeight,
GLuint bufferId) {
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bufferId);
GLuint texId;
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texWidth, texHeight, 0,
GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
return texId;
}

使用此实现,使用这两个函数的两个调用序列将产生相同的结果。

还有其他方法可以解决这个问题。例如:
  • 每个函数都记录其前提条件和副作用,调用者负责在调用具有副作用的函数后进行任何必要的状态更改以满足下一个函数的前提条件。
  • 每个函数都完全负责设置它的所有状态。在上面的例子中,这意味着 createEmptyTexture()函数必须取消绑定(bind)像素解包缓冲区,因为它依赖于没有绑定(bind)。

  • 方法 1 并不能很好地扩展,并且在更大的系统中维护起来会很痛苦。方法 2 也不尽如人意,因为 OpenGL 有很多状态,并且必须设置 全部 每个函数中的相关状态都是冗长且低效的。

    这确实是一个更大问题的一部分:您如何在模块化软件架构中处理基于状态的 OpenGL?缓冲区绑定(bind)只是您需要处理的状态的一个示例。这在您自己编写的小程序中通常不是很难处理,但在较大的系统中可能会出现问题。如果混合来自不同来源(例如不同供应商)的组件,情况会变得更糟。

    我认为没有一种方法在所有可能的情况下都是理想的。重要的是您选择一个明确定义的策略,并始终如一地使用它。如何在各种情况下最好地处理这个问题有点超出了这里的答案范围。

    虽然解绑缓冲区应该相当便宜,但我不喜欢不必要的调用。所以我会尽量避免这些调用,除非你真的觉得你需要它们来为你正在编写的软件执行一个清晰一致的策略。

    关于performance - 解绑 WebGL 缓冲区,值得吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28259022/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com