OpenGL Buffer Object

3D Application 은 항상 어떻게 하면 빠르게 그릴까를 연구해왔다.
Geometry 를 좀 더 빠른 속도로 그리기 위해 매번 새로운 기법들이 개발되어 왔는데.. OpenGL 1.1 시절에는 Display List 로 rendering command 를 미리 컴파일하여 binary 버퍼화해버리는 원시적인 방법이 사용됐다. 그러다가 동적인 Geometry 를 일반적인 방법으로 사용하기 위해 Vertex Array 를 사용했고, CVA(Compiled Vertex Array) 나 T&L 이 가능해 지면서 더욱 더 빠른 처리가 가능해졌다.

그 후에는 Vertex Array 자체를 Local(Video)/Non-local(AGP) 메모리에 상주시켜 GPU 가 직접 메모리를 access 하도록 하는 VAR/VAO/VBO 같은 확장이 추가되었다. 이 개념은 OpenGL 이나 DirectX 같은 API 보다는, 그래픽 하드웨어와 더 밀접한 관련이 있다고 볼 수 있는데… 하드웨어 입장에서는 몇가지 operation 으로 나눠볼 수 있겠다.

VBO 기준으로 설명하면..

a. 버퍼를 적당한 새로운 곳에 채운다 – BufferData (Video / AGP / System memory)
b. 버퍼의 내용을 버린다(Discard) – BufferData (data 를 NULL 로 세팅)
c. 버퍼의 장소를 유지한채 전체 버퍼를 synchronous 하게 포인터를 얻어온다 – MapBuffer / UnmapBuffer
d. 버퍼의 장소를 유지한채 일정 부분만 synchronous 하게 업데이트 한다 – BufferSubData

2008년에 와서 map_buffer_range 확장으로 좀 더 세밀하게 제어가 가능해졌는데..

버퍼의 일정 부분만 sync or async 하게 Map 이 가능하고,
업데이트시 flush 되는 sub range 를 별도로 지정이 가능해졌다.

보통 GPU 쪽에서 사용할땐 Video > AGP > System memory 순으로 빠르고,
CPU 를 경유한 write 는 System > AGP > Video memory 순으로 빠른데…
용도에 따라서 static 버퍼는 한번만 write 하면 그만이지만, dynamic 버퍼는 여러번 write 하게된다.
GPU 에서 버퍼를 점유중일때, 사용이 끝날때까지 기다리지 않고 asynchronous 하게 write 를 해야 속도를 올릴 수 있다.

※ 필자의 경험을 바탕으로 적은거라 일부 틀린 내용이 있을 수도 있음

다양한 extension 들이 추가되면서 이 buffer 를 아래와 같은 여러가지 데이터 형태로서 사용 할수 있게 되었다. (점점 범용적이 되어가고 있다.)

버퍼를 버텍스 데이터로 사용 — VertexArrayPointer – ARB_vertex_buffer_object (NV10, R100)
프레임버퍼로/프레임버퍼로부터 버퍼를 쓰기 — DrawPixels/ReadPixels – ARB_pixel_buffer_object (NV40, R300)
버퍼로부터 텍스쳐를 업데이트 — TexSubImage – ARB_pixel_buffer_object ( ” )
버퍼로부터 쉐이더 상수를 지정 — UniformBuffer – EXT_bindable_uniform (G80, R600)
버퍼를 커다란 1D 텍스쳐로 사용 — TexBuffer – EXT_texture_buffer_object (G80, R600)

이정도만으로도 활용범위는 뭔가 굉장히 많아 보인다.

몇가지 예를 들면…

ex 1. Render To VertexBuffer

fragment shader 를 거쳐 나온 프레임버퍼를 비동기로 읽어 vertex array 로 재사용 가능

ex 2. 텍스쳐 스트리밍

텍스쳐를 화면에 그리면서 다음 프레임의 내용을 비동기로 업데이트 가능

ex 3. 하드웨어 스키닝에 활용

a) VTF(Vertex Texture Fetch) 를 이용해 텍스쳐 데이터로 전달시 PBO 를 이용해 텍스쳐를 업데이트
b) a 와 같은 방식으로 texture buffer object 를 이용해 버퍼를 텍스쳐 데이터로 직접 사용
c) bindable uniform 을 이용해 쉐이더 상수 버퍼를 구성후 쉐이더에 버퍼 형식으로 전달

참고 자료:
http://developer.nvidia.com/object/using_VBOs.html
http://www.songho.ca/opengl/gl_vbo.html
http://www.songho.ca/opengl/gl_pbo.html
http://winnwe.com/pda/perma/1115/
http://winnwe.com/pda/perma/1116/
http://www.nvidia.com/dev_content/nvopenglspecs/GL_NV_vertex_array_range.txt
http://www.nvidia.com/dev_content/nvopenglspecs/GL_NV_vertex_array_range2.txt
http://www.nvidia.com/dev_content/nvopenglspecs/GL_NV_pixel_data_range.txt
http://developer.download.nvidia.com/opengl/specs/GL_NV_transform_feedback.txt
http://www.nvidia.com/dev_content/nvopenglspecs/GL_ARB_vertex_buffer_object.txt
http://www.nvidia.com/dev_content/nvopenglspecs/GL_ARB_pixel_buffer_object.txt
http://developer.download.nvidia.com/opengl/specs/GL_EXT_bindable_uniform.txt
http://developer.download.nvidia.com/opengl/specs/GL_EXT_texture_buffer_object.txt
http://www.opengl.org/registry/specs/APPLE/flush_buffer_range.txt
http://www.opengl.org/registry/specs/ARB/map_buffer_range.txt
http://www.opengl.org/registry/specs/ARB/copy_buffer.txt
http://www.opengl.org/registry/specs/ARB/uniform_buffer_object.txt

Leave a Reply

Your email address will not be published. Required fields are marked *