|
1 #include "precompiled.h" |
|
2 // |
|
3 // Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. |
|
4 // Use of this source code is governed by a BSD-style license that can be |
|
5 // found in the LICENSE file. |
|
6 // |
|
7 |
|
8 // VertexDataManager.h: Defines the VertexDataManager, a class that |
|
9 // runs the Buffer translation process. |
|
10 |
|
11 #include "libGLESv2/renderer/VertexDataManager.h" |
|
12 #include "libGLESv2/renderer/BufferStorage.h" |
|
13 |
|
14 #include "libGLESv2/Buffer.h" |
|
15 #include "libGLESv2/ProgramBinary.h" |
|
16 #include "libGLESv2/Context.h" |
|
17 #include "libGLESv2/renderer/VertexBuffer.h" |
|
18 |
|
19 namespace |
|
20 { |
|
21 enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 }; |
|
22 // This has to be at least 4k or else it fails on ATI cards. |
|
23 enum { CONSTANT_VERTEX_BUFFER_SIZE = 4096 }; |
|
24 } |
|
25 |
|
26 namespace rx |
|
27 { |
|
28 |
|
29 static int elementsInBuffer(const gl::VertexAttribute &attribute, unsigned int size) |
|
30 { |
|
31 // Size cannot be larger than a GLsizei |
|
32 if (size > static_cast<unsigned int>(std::numeric_limits<int>::max())) |
|
33 { |
|
34 size = static_cast<unsigned int>(std::numeric_limits<int>::max()); |
|
35 } |
|
36 |
|
37 GLsizei stride = attribute.stride(); |
|
38 return (size - attribute.mOffset % stride + (stride - attribute.typeSize())) / stride; |
|
39 } |
|
40 |
|
41 VertexDataManager::VertexDataManager(Renderer *renderer) : mRenderer(renderer) |
|
42 { |
|
43 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) |
|
44 { |
|
45 mCurrentValue[i][0] = std::numeric_limits<float>::quiet_NaN(); |
|
46 mCurrentValue[i][1] = std::numeric_limits<float>::quiet_NaN(); |
|
47 mCurrentValue[i][2] = std::numeric_limits<float>::quiet_NaN(); |
|
48 mCurrentValue[i][3] = std::numeric_limits<float>::quiet_NaN(); |
|
49 mCurrentValueBuffer[i] = NULL; |
|
50 mCurrentValueOffsets[i] = 0; |
|
51 } |
|
52 |
|
53 mStreamingBuffer = new StreamingVertexBufferInterface(renderer, INITIAL_STREAM_BUFFER_SIZE); |
|
54 |
|
55 if (!mStreamingBuffer) |
|
56 { |
|
57 ERR("Failed to allocate the streaming vertex buffer."); |
|
58 } |
|
59 } |
|
60 |
|
61 VertexDataManager::~VertexDataManager() |
|
62 { |
|
63 delete mStreamingBuffer; |
|
64 |
|
65 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) |
|
66 { |
|
67 delete mCurrentValueBuffer[i]; |
|
68 } |
|
69 } |
|
70 |
|
71 static bool directStoragePossible(VertexBufferInterface* vb, const gl::VertexAttribute& attrib) |
|
72 { |
|
73 gl::Buffer *buffer = attrib.mBoundBuffer.get(); |
|
74 BufferStorage *storage = buffer ? buffer->getStorage() : NULL; |
|
75 |
|
76 const bool isAligned = (attrib.stride() % 4 == 0) && (attrib.mOffset % 4 == 0); |
|
77 |
|
78 return storage && storage->supportsDirectBinding() && !vb->getVertexBuffer()->requiresConversion(attrib) && isAligned; |
|
79 } |
|
80 |
|
81 GLenum VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], gl::ProgramBinary *programBinary, GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instances) |
|
82 { |
|
83 if (!mStreamingBuffer) |
|
84 { |
|
85 return GL_OUT_OF_MEMORY; |
|
86 } |
|
87 |
|
88 for (int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) |
|
89 { |
|
90 translated[attributeIndex].active = (programBinary->getSemanticIndex(attributeIndex) != -1); |
|
91 } |
|
92 |
|
93 // Invalidate static buffers that don't contain matching attributes |
|
94 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) |
|
95 { |
|
96 if (translated[i].active && attribs[i].mArrayEnabled) |
|
97 { |
|
98 gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); |
|
99 StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; |
|
100 |
|
101 if (staticBuffer && staticBuffer->getBufferSize() > 0 && !staticBuffer->lookupAttribute(attribs[i], NULL) && |
|
102 !directStoragePossible(staticBuffer, attribs[i])) |
|
103 { |
|
104 buffer->invalidateStaticData(); |
|
105 } |
|
106 } |
|
107 } |
|
108 |
|
109 // Reserve the required space in the buffers |
|
110 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) |
|
111 { |
|
112 if (translated[i].active && attribs[i].mArrayEnabled) |
|
113 { |
|
114 gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); |
|
115 StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; |
|
116 VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer); |
|
117 |
|
118 if (!directStoragePossible(vertexBuffer, attribs[i])) |
|
119 { |
|
120 if (staticBuffer) |
|
121 { |
|
122 if (staticBuffer->getBufferSize() == 0) |
|
123 { |
|
124 int totalCount = elementsInBuffer(attribs[i], buffer->size()); |
|
125 if (!staticBuffer->reserveVertexSpace(attribs[i], totalCount, 0)) |
|
126 { |
|
127 return GL_OUT_OF_MEMORY; |
|
128 } |
|
129 } |
|
130 } |
|
131 else |
|
132 { |
|
133 if (!mStreamingBuffer->reserveVertexSpace(attribs[i], count, instances)) |
|
134 { |
|
135 return GL_OUT_OF_MEMORY; |
|
136 } |
|
137 } |
|
138 } |
|
139 } |
|
140 } |
|
141 |
|
142 // Perform the vertex data translations |
|
143 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) |
|
144 { |
|
145 if (translated[i].active) |
|
146 { |
|
147 if (attribs[i].mArrayEnabled) |
|
148 { |
|
149 gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); |
|
150 |
|
151 if (!buffer && attribs[i].mPointer == NULL) |
|
152 { |
|
153 // This is an application error that would normally result in a crash, but we catch it and return an error |
|
154 ERR("An enabled vertex array has no buffer and no pointer."); |
|
155 return GL_INVALID_OPERATION; |
|
156 } |
|
157 |
|
158 StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; |
|
159 VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer); |
|
160 |
|
161 BufferStorage *storage = buffer ? buffer->getStorage() : NULL; |
|
162 bool directStorage = directStoragePossible(vertexBuffer, attribs[i]); |
|
163 |
|
164 unsigned int streamOffset = 0; |
|
165 unsigned int outputElementSize = 0; |
|
166 |
|
167 if (directStorage) |
|
168 { |
|
169 outputElementSize = attribs[i].stride(); |
|
170 streamOffset = attribs[i].mOffset + outputElementSize * start; |
|
171 storage->markBufferUsage(); |
|
172 } |
|
173 else if (staticBuffer) |
|
174 { |
|
175 if (!staticBuffer->getVertexBuffer()->getSpaceRequired(attribs[i], 1, 0, &outputElementSize)) |
|
176 { |
|
177 return GL_OUT_OF_MEMORY; |
|
178 } |
|
179 |
|
180 if (!staticBuffer->lookupAttribute(attribs[i], &streamOffset)) |
|
181 { |
|
182 // Convert the entire buffer |
|
183 int totalCount = elementsInBuffer(attribs[i], storage->getSize()); |
|
184 int startIndex = attribs[i].mOffset / attribs[i].stride(); |
|
185 |
|
186 if (!staticBuffer->storeVertexAttributes(attribs[i], -startIndex, totalCount, 0, &streamOffset)) |
|
187 { |
|
188 return GL_OUT_OF_MEMORY; |
|
189 } |
|
190 } |
|
191 |
|
192 unsigned int firstElementOffset = (attribs[i].mOffset / attribs[i].stride()) * outputElementSize; |
|
193 unsigned int startOffset = (instances == 0 || attribs[i].mDivisor == 0) ? start * outputElementSize : 0; |
|
194 if (streamOffset + firstElementOffset + startOffset < streamOffset) |
|
195 { |
|
196 return GL_OUT_OF_MEMORY; |
|
197 } |
|
198 |
|
199 streamOffset += firstElementOffset + startOffset; |
|
200 } |
|
201 else |
|
202 { |
|
203 if (!mStreamingBuffer->getVertexBuffer()->getSpaceRequired(attribs[i], 1, 0, &outputElementSize) || |
|
204 !mStreamingBuffer->storeVertexAttributes(attribs[i], start, count, instances, &streamOffset)) |
|
205 { |
|
206 return GL_OUT_OF_MEMORY; |
|
207 } |
|
208 } |
|
209 |
|
210 translated[i].storage = directStorage ? storage : NULL; |
|
211 translated[i].vertexBuffer = vertexBuffer->getVertexBuffer(); |
|
212 translated[i].serial = directStorage ? storage->getSerial() : vertexBuffer->getSerial(); |
|
213 translated[i].divisor = attribs[i].mDivisor; |
|
214 |
|
215 translated[i].attribute = &attribs[i]; |
|
216 translated[i].stride = outputElementSize; |
|
217 translated[i].offset = streamOffset; |
|
218 } |
|
219 else |
|
220 { |
|
221 if (!mCurrentValueBuffer[i]) |
|
222 { |
|
223 mCurrentValueBuffer[i] = new StreamingVertexBufferInterface(mRenderer, CONSTANT_VERTEX_BUFFER_SIZE); |
|
224 } |
|
225 |
|
226 StreamingVertexBufferInterface *buffer = mCurrentValueBuffer[i]; |
|
227 |
|
228 if (mCurrentValue[i][0] != attribs[i].mCurrentValue[0] || |
|
229 mCurrentValue[i][1] != attribs[i].mCurrentValue[1] || |
|
230 mCurrentValue[i][2] != attribs[i].mCurrentValue[2] || |
|
231 mCurrentValue[i][3] != attribs[i].mCurrentValue[3]) |
|
232 { |
|
233 unsigned int requiredSpace = sizeof(float) * 4; |
|
234 if (!buffer->reserveRawDataSpace(requiredSpace)) |
|
235 { |
|
236 return GL_OUT_OF_MEMORY; |
|
237 } |
|
238 |
|
239 unsigned int streamOffset; |
|
240 if (!buffer->storeRawData(attribs[i].mCurrentValue, requiredSpace, &streamOffset)) |
|
241 { |
|
242 return GL_OUT_OF_MEMORY; |
|
243 } |
|
244 |
|
245 mCurrentValueOffsets[i] = streamOffset; |
|
246 } |
|
247 |
|
248 translated[i].storage = NULL; |
|
249 translated[i].vertexBuffer = mCurrentValueBuffer[i]->getVertexBuffer(); |
|
250 translated[i].serial = mCurrentValueBuffer[i]->getSerial(); |
|
251 translated[i].divisor = 0; |
|
252 |
|
253 translated[i].attribute = &attribs[i]; |
|
254 translated[i].stride = 0; |
|
255 translated[i].offset = mCurrentValueOffsets[i]; |
|
256 } |
|
257 } |
|
258 } |
|
259 |
|
260 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) |
|
261 { |
|
262 if (translated[i].active && attribs[i].mArrayEnabled) |
|
263 { |
|
264 gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); |
|
265 |
|
266 if (buffer) |
|
267 { |
|
268 buffer->promoteStaticUsage(count * attribs[i].typeSize()); |
|
269 } |
|
270 } |
|
271 } |
|
272 |
|
273 return GL_NO_ERROR; |
|
274 } |
|
275 |
|
276 } |