重新分配着色器缓冲区值

时间:2018-08-28 06:35:52

标签: opengl shader

this question about growing buffers中,有人回答以下代码。

// Bind the old buffer to `GL_COPY_READ_BUFFER`
glBindBuffer (GL_COPY_READ_BUFFER, old_buffer);

// Allocate data for a new buffer
glGenBuffers (1, &new_buffer);
glBindBuffer (GL_COPY_WRITE_BUFFER, new_buffer);
glBufferData (GL_COPY_WRITE_BUFFER, ...);

// Copy `old_buffer_size`-bytes of data from `GL_COPY_READ_BUFFER`
//   to `GL_COPY_WRITE_BUFFER` beginning at 0.
glCopyBufferSubData (GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, old_buffer_size);

这是我对上述内容的理解,以便将A复制到B:

Bind A
Generate B
Bind B
Write null contents to B at larger size
Copy A to B

我的问题是A是着色器的原始顶点缓冲区,而B也是(因为目标是更改大小)。在我的代码(C#opentk)中,着色器告诉我使用GL.GetActiveAttrib与命名着色器变量重合的缓冲区的ID,我找不到如何使其使用与提供的缓冲区不同的缓冲区的方法。

所以我要么必须重新分配着色器才能在以后使用B,要么进行双重复制:

Bind A
Generate B
Bind B
Write null contents to B at larger size
Copy A to B
Reassign shader to use B
Write null contents to A at larger size (size of B)
Copy B to A

是否有可能使它使用特定的缓冲区或避免重复复制?

1 个答案:

答案 0 :(得分:0)

使用glBufferData设置缓冲区的大小后,该大小将变为不变。这就是为什么需要复制到另一个更大的缓冲区B的原因。

好消息是您可以将缓冲区与其他目标重新绑定。这是您可以在缓冲区管理器中执行的操作(似乎您错误地将其称为“着色器”。着色器是GPU中的程序)。不需要第二份副本。

如果要保留以前的绑定,

GL_COPY_READ_BUFFERGL_COPY_WRITE_BUFFER目标很有用。这不是您的情况,因此副本更简单:

//The buffer must be bound before copying it
glBindBuffer(GL_ARRAY_BUFFER, oldBuf); //or GL_ELEMENT_ARRAY_BUFFER or whatever it was
//New buffer
glGenBuffers (1, &newBuf);
//GL_COPY_WRITE_BUFFER is needed because GL_ARRAY_BUFFER is in use by oldBuf
glBindBuffer (GL_COPY_WRITE_BUFFER, newBuf);
glBufferData (GL_COPY_WRITE_BUFFER, newSize, ...);
glCopyBufferSubData (GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, old_buffer_size);

现在完成复制,可以安全删除缓冲区oldBuf

还有两件事要做:

a) Tell the buffer-manager to use 'newBuf' insted of 'oldBuf'
b) Before using this new buffer, re-bind it to the target you need
   glBindBuffer(GL_ARRAY_BUFFER, newBuf);

嗯,还有另一件事要做。当绑定VAO时,glVertexAttribPointer建立了关联“属性-要读取的缓冲区”,它使用了oldBuf缓冲区。但是现在您想要另一个缓冲区。因此,您必须再次绑定该VAO,绑定新缓冲区并使用glVertexAttribPointer。


更好的解决方案可能是具有较大的缓冲区,并且仅使用其中的一部分。假设您有一个用于一百万个顶点的VBO。 1M x 3浮点数x 4字节= 12M字节。这不是任何不是太老的GPU都无法处理的大小。

如果数据大小发生变化,但不超过1M个顶点,那么最简单的方法是使用glBufferSubData并上传新数据,即使只是添加数据也是如此。没有新的缓冲区,没有副本,没有VAO状态更改。