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