xref: /aosp_15_r20/external/angle/doc/BufferImplementation.md (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker# Introduction
2*8975f5c5SAndroid Build Coastguard Worker
3*8975f5c5SAndroid Build Coastguard WorkerSince Direct3D 9 only supports buffers that either contain vertex or index data,
4*8975f5c5SAndroid Build Coastguard Workerand OpenGL buffers can contain both, ANGLE waits till a draw call is issued to
5*8975f5c5SAndroid Build Coastguard Workerdetermine which resources to create/update. The generic implementation 'streams'
6*8975f5c5SAndroid Build Coastguard Workerthe data into global vertex and index buffers. This streaming buffer
7*8975f5c5SAndroid Build Coastguard Workerimplementation works in all circumstances, but does not offer optimal
8*8975f5c5SAndroid Build Coastguard Workerperformance. When buffer data isn't updated, there's no reason to copy the data
9*8975f5c5SAndroid Build Coastguard Workeragain. For these cases a 'static' buffer implementation is used.
10*8975f5c5SAndroid Build Coastguard Worker
11*8975f5c5SAndroid Build Coastguard WorkerThe OpenGL ES 2.0 glBufferData() function allows to specify a usage hint
12*8975f5c5SAndroid Build Coastguard Workerparameter (GL\_STREAM\_DRAW, GL\_DYNAMIC\_DRAW or GL\_STATIC\_DRAW). Both
13*8975f5c5SAndroid Build Coastguard WorkerGL\_STREAM\_DRAW and GL\_DYNAMIC\_DRAW use the streaming buffer implementation.
14*8975f5c5SAndroid Build Coastguard WorkerWith the GL\_STATIC\_DRAW hint, ANGLE will attempt to use the static buffer
15*8975f5c5SAndroid Build Coastguard Workerimplementation. If you update the buffer data after it has already been used in
16*8975f5c5SAndroid Build Coastguard Workera draw call, it falls back to the streaming buffer implementation, because
17*8975f5c5SAndroid Build Coastguard Workerupdating static ones would involve creating new ones, which is slower than
18*8975f5c5SAndroid Build Coastguard Workerupdating streaming ones (more on this later).
19*8975f5c5SAndroid Build Coastguard Worker
20*8975f5c5SAndroid Build Coastguard WorkerBecause some applications use GL\_STREAM\_DRAW or GL\_DYNAMIC\_DRAW even when
21*8975f5c5SAndroid Build Coastguard Workerthe data is not or very infrequently updated, ANGLE also has a heuristic to
22*8975f5c5SAndroid Build Coastguard Workerpromote buffers to use the static implementation.
23*8975f5c5SAndroid Build Coastguard Worker
24*8975f5c5SAndroid Build Coastguard Worker# Streaming buffers
25*8975f5c5SAndroid Build Coastguard Worker
26*8975f5c5SAndroid Build Coastguard WorkerThe streaming buffers implementation uses one Context-global vertex buffer
27*8975f5c5SAndroid Build Coastguard Worker(VertexDataManager::mStreamingBuffer) and two index buffers
28*8975f5c5SAndroid Build Coastguard Worker(IndexDataManager::mStreamingBufferShort and
29*8975f5c5SAndroid Build Coastguard WorkerIndexDataManager::mStreamingBufferInt). The streaming behavior is achieved by
30*8975f5c5SAndroid Build Coastguard Workerwriting new data behind previously written data (i.e. without overwriting old
31*8975f5c5SAndroid Build Coastguard Workerdata). Direct3D 9 allows to efficiently update vertex and index buffers when
32*8975f5c5SAndroid Build Coastguard Workeryou're not reading or overwriting anything (it won't stall waiting for the GPU
33*8975f5c5SAndroid Build Coastguard Workerfinish using it).
34*8975f5c5SAndroid Build Coastguard Worker
35*8975f5c5SAndroid Build Coastguard WorkerWhen the end of these streaming buffers is reached, they are 'recycled' by
36*8975f5c5SAndroid Build Coastguard Workerdiscarding their content. D3D9 will still keep a copy of the data that's in use,
37*8975f5c5SAndroid Build Coastguard Workerso this recycling efficiently renames the driver level buffers. ANGLE can then
38*8975f5c5SAndroid Build Coastguard Workerwrite new data to the beginning of the vertex or index buffer.
39*8975f5c5SAndroid Build Coastguard Worker
40*8975f5c5SAndroid Build Coastguard WorkerThe ArrayVertexBuffer::mWritePosition variable holds the current end position of
41*8975f5c5SAndroid Build Coastguard Workerthe last data that was written. StreamingVertexBuffer::reserveRequiredSpace()
42*8975f5c5SAndroid Build Coastguard Workerallocates space to write the data, and StreamingVertexBuffer::map() actually
43*8975f5c5SAndroid Build Coastguard Workerlocks the D3D buffer and updates the write position. Similar for index buffers.
44*8975f5c5SAndroid Build Coastguard Worker
45*8975f5c5SAndroid Build Coastguard Worker# Static buffers
46*8975f5c5SAndroid Build Coastguard Worker
47*8975f5c5SAndroid Build Coastguard WorkerEach GL buffer object can have a corresponding static vertex or index buffer
48*8975f5c5SAndroid Build Coastguard Worker(Buffer::mVertexBuffer and Buffer::mIndexBuffer). When a GL buffer with static
49*8975f5c5SAndroid Build Coastguard Workerusage is used in a draw call for the first time, all of its data is converted to
50*8975f5c5SAndroid Build Coastguard Workera D3D vertex or index buffer, based on the attribute or index formats
51*8975f5c5SAndroid Build Coastguard Workerrespectively. If a subsequent draw call uses different formats, the static
52*8975f5c5SAndroid Build Coastguard Workerbuffer is invalidated (deleted) and the streaming buffer implementation is used
53*8975f5c5SAndroid Build Coastguard Workerfor this buffer object instead. So for optimal performance it's important to
54*8975f5c5SAndroid Build Coastguard Workerstore only a single format of vertices or indices in a buffer. This is highly
55*8975f5c5SAndroid Build Coastguard Workertypical, and even when in some cases it falls back to the streaming buffer
56*8975f5c5SAndroid Build Coastguard Workerimplementation the performance isn't bad at all.
57*8975f5c5SAndroid Build Coastguard Worker
58*8975f5c5SAndroid Build Coastguard WorkerThe StreamingVertexBuffer and StaticVertexBuffer classes share a common base
59*8975f5c5SAndroid Build Coastguard Workerclass, ArrayVertexBuffer. StaticVertexBuffer also has access to the write
60*8975f5c5SAndroid Build Coastguard Workerposition, but it's used only for the initial conversion of the data. So the
61*8975f5c5SAndroid Build Coastguard Workerinterfaces of both classes are not that different. Static buffers have an exact
62*8975f5c5SAndroid Build Coastguard Workersize though, and can't be changed afterwards (streaming buffers can grow to
63*8975f5c5SAndroid Build Coastguard Workerhandle draw calls which use more data, and avoid excessive recycling).
64*8975f5c5SAndroid Build Coastguard WorkerStaticVertexBuffer has a lookupAttribute() method to retrieve the location of a
65*8975f5c5SAndroid Build Coastguard Workercertain attribute (this is also used to verify that the formats haven't changed,
66*8975f5c5SAndroid Build Coastguard Workerwhich would result in invalidating the static buffer). The descriptions of all
67*8975f5c5SAndroid Build Coastguard Workerthe attribute formats a static buffer contains are stored in the
68*8975f5c5SAndroid Build Coastguard WorkerStaticVertexBuffer::mCache vector.
69*8975f5c5SAndroid Build Coastguard Worker
70*8975f5c5SAndroid Build Coastguard WorkerStaticIndexBuffer also caches information about what's stored in them, namely
71*8975f5c5SAndroid Build Coastguard Workerthe minimum and maximum value for certain ranges of indices. This information is
72*8975f5c5SAndroid Build Coastguard Workerrequired by the Direct3D 9 draw calls, and is also used to know the range of
73*8975f5c5SAndroid Build Coastguard Workervertices that need to be copied to the streaming vertex buffer in case it needs
74*8975f5c5SAndroid Build Coastguard Workerto be used (e.g. it is not uncommon to have a buffer with static vertex position
75*8975f5c5SAndroid Build Coastguard Workerdata and a buffer with streaming texture coordinate data for skinning).
76*8975f5c5SAndroid Build Coastguard Worker
77*8975f5c5SAndroid Build Coastguard Worker# Constant attributes
78*8975f5c5SAndroid Build Coastguard Worker
79*8975f5c5SAndroid Build Coastguard WorkerAside from using array buffers to feed attribute data to the vertex shader,
80*8975f5c5SAndroid Build Coastguard WorkerOpenGL also supports attributes which remain constant for all vertices used in a
81*8975f5c5SAndroid Build Coastguard Workerdraw call. Direct3D 9 doesn't have a similar concept, at least not explicitly.
82*8975f5c5SAndroid Build Coastguard Worker
83*8975f5c5SAndroid Build Coastguard WorkerConstant attributes are implemented using separate (static) vertex buffers,
84*8975f5c5SAndroid Build Coastguard Workerand uses a stride of 0 to ensure that every vertex retrieves the same data.
85*8975f5c5SAndroid Build Coastguard WorkerUsing a stride of 0 is not possible with streaming buffers because on some
86*8975f5c5SAndroid Build Coastguard Workerhardware it is incompatible with the D3DUSAGE\_DYNAMIC flag. We found that with
87*8975f5c5SAndroid Build Coastguard Workerstatic usage, all hardware tested so far can handle stride 0 fine.
88*8975f5c5SAndroid Build Coastguard Worker
89*8975f5c5SAndroid Build Coastguard WorkerThis functionality was implemented in a ConstantVertexBuffer class, and it
90*8975f5c5SAndroid Build Coastguard Workerintegrates nicely with the rest of the static buffer implementation.
91*8975f5c5SAndroid Build Coastguard Worker
92*8975f5c5SAndroid Build Coastguard Worker# Line loops
93*8975f5c5SAndroid Build Coastguard Worker
94*8975f5c5SAndroid Build Coastguard WorkerDirect3D 9 does not support the 'line loop' primitive type directly. This is
95*8975f5c5SAndroid Build Coastguard Workerimplemented by drawing the 'closing' line segment separately, constructing a
96*8975f5c5SAndroid Build Coastguard Workertiny temporary index buffer connecting the last and first vertex.
97*8975f5c5SAndroid Build Coastguard Worker
98*8975f5c5SAndroid Build Coastguard Worker# Putting it all together
99*8975f5c5SAndroid Build Coastguard Worker
100*8975f5c5SAndroid Build Coastguard WorkerglDrawElements() calls IndexDataManager::prepareIndexData() to retrieve a
101*8975f5c5SAndroid Build Coastguard WorkerDirect3D index buffer containing the necessary data. If an element array is used
102*8975f5c5SAndroid Build Coastguard Worker(i.e. a buffer object), it has static usage, and it hasn't been invalidated, the
103*8975f5c5SAndroid Build Coastguard WorkerGL buffer's static D3D index buffer will be returned. Else the updated streaming
104*8975f5c5SAndroid Build Coastguard Workerindex buffer is returned, as well as the index offset (write position) where the
105*8975f5c5SAndroid Build Coastguard Workernew data is located. When prepareIndexData() does find a static index buffer,
106*8975f5c5SAndroid Build Coastguard Workerbut it's empty, it means the GL buffer's data hasn't been converted and stored
107*8975f5c5SAndroid Build Coastguard Workerin the D3D index buffer yet. So in the convertIndices() call it will convert the
108*8975f5c5SAndroid Build Coastguard Workerentire buffer. prepareIndexData() will also look up the min/max value of a range
109*8975f5c5SAndroid Build Coastguard Workerof indices, or computes it when not already in the static buffer or when a
110*8975f5c5SAndroid Build Coastguard Workerstreaming buffer is used.
111*8975f5c5SAndroid Build Coastguard Worker
112*8975f5c5SAndroid Build Coastguard WorkerSimilarly, both glDrawElements() and glDrawArrays() both call
113*8975f5c5SAndroid Build Coastguard WorkerVertexDataManager::prepareVertexData() to retrieve a set of Direct3D vertex
114*8975f5c5SAndroid Build Coastguard Workerbuffers and their translated format and offset information. It's implementation
115*8975f5c5SAndroid Build Coastguard Workeris more complicated than prepareIndexData() because buffer objects can contain
116*8975f5c5SAndroid Build Coastguard Workermultiple vertex attributes, and multiple buffers can be used as input to the
117*8975f5c5SAndroid Build Coastguard Workervertex shader. So first it accumulates how much storage space is required for
118*8975f5c5SAndroid Build Coastguard Workereach of the buffers in use. For all static non-empty buffers in use, it
119*8975f5c5SAndroid Build Coastguard Workerdetermines whether the stored attributes still match what is required by the
120*8975f5c5SAndroid Build Coastguard Workerdraw call, and invalidates them if not (at which point more space is allocated
121*8975f5c5SAndroid Build Coastguard Workerin the streaming buffer). Converting the GL buffer object's data into D3D
122*8975f5c5SAndroid Build Coastguard Workercompatible vertex formats is still done by specialized template functions.
123