1 | // Copyright 2016 The SwiftShader Authors. All Rights Reserved. |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | // VertexDataManager.h: Defines the VertexDataManager, a class that |
16 | // runs the Buffer translation process. |
17 | |
18 | #include "VertexDataManager.h" |
19 | |
20 | #include "Buffer.h" |
21 | #include "Program.h" |
22 | #include "IndexDataManager.h" |
23 | #include "common/debug.h" |
24 | |
25 | namespace |
26 | { |
27 | enum {INITIAL_STREAM_BUFFER_SIZE = 1024 * 1024}; |
28 | } |
29 | |
30 | namespace es2 |
31 | { |
32 | |
33 | VertexDataManager::VertexDataManager(Context *context) : mContext(context) |
34 | { |
35 | for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++) |
36 | { |
37 | mDirtyCurrentValue[i] = true; |
38 | mCurrentValueBuffer[i] = nullptr; |
39 | } |
40 | |
41 | mStreamingBuffer = new StreamingVertexBuffer(INITIAL_STREAM_BUFFER_SIZE); |
42 | |
43 | if(!mStreamingBuffer) |
44 | { |
45 | ERR("Failed to allocate the streaming vertex buffer." ); |
46 | } |
47 | } |
48 | |
49 | VertexDataManager::~VertexDataManager() |
50 | { |
51 | delete mStreamingBuffer; |
52 | |
53 | for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++) |
54 | { |
55 | delete mCurrentValueBuffer[i]; |
56 | } |
57 | } |
58 | |
59 | unsigned int VertexDataManager::writeAttributeData(StreamingVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute) |
60 | { |
61 | Buffer *buffer = attribute.mBoundBuffer; |
62 | |
63 | int inputStride = attribute.stride(); |
64 | int elementSize = attribute.typeSize(); |
65 | unsigned int streamOffset = 0; |
66 | |
67 | char *output = nullptr; |
68 | |
69 | if(vertexBuffer) |
70 | { |
71 | output = (char*)vertexBuffer->map(attribute, attribute.typeSize() * count, &streamOffset); |
72 | } |
73 | |
74 | if(!output) |
75 | { |
76 | ERR("Failed to map vertex buffer." ); |
77 | return ~0u; |
78 | } |
79 | |
80 | const char *input = nullptr; |
81 | |
82 | if(buffer) |
83 | { |
84 | input = static_cast<const char*>(buffer->data()) + attribute.mOffset; |
85 | } |
86 | else |
87 | { |
88 | input = static_cast<const char*>(attribute.mPointer); |
89 | } |
90 | |
91 | input += inputStride * start; |
92 | |
93 | if(inputStride == elementSize) |
94 | { |
95 | memcpy(output, input, count * inputStride); |
96 | } |
97 | else |
98 | { |
99 | for(int i = 0; i < count; i++) |
100 | { |
101 | memcpy(output, input, elementSize); |
102 | output += elementSize; |
103 | input += inputStride; |
104 | } |
105 | } |
106 | |
107 | vertexBuffer->unmap(); |
108 | |
109 | return streamOffset; |
110 | } |
111 | |
112 | GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instanceId) |
113 | { |
114 | if(!mStreamingBuffer) |
115 | { |
116 | return GL_OUT_OF_MEMORY; |
117 | } |
118 | |
119 | const VertexAttributeArray &attribs = mContext->getVertexArrayAttributes(); |
120 | const VertexAttributeArray ¤tAttribs = mContext->getCurrentVertexAttributes(); |
121 | Program *program = mContext->getCurrentProgram(); |
122 | |
123 | // Determine the required storage size per used buffer |
124 | for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++) |
125 | { |
126 | const VertexAttribute &attrib = attribs[i].mArrayEnabled ? attribs[i] : currentAttribs[i]; |
127 | |
128 | if(program->getAttributeStream(i) != -1 && attrib.mArrayEnabled) |
129 | { |
130 | if(!attrib.mBoundBuffer) |
131 | { |
132 | const bool isInstanced = attrib.mDivisor > 0; |
133 | mStreamingBuffer->addRequiredSpace(attrib.typeSize() * (isInstanced ? 1 : count)); |
134 | } |
135 | } |
136 | } |
137 | |
138 | mStreamingBuffer->reserveRequiredSpace(); |
139 | |
140 | // Perform the vertex data translations |
141 | for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++) |
142 | { |
143 | if(program->getAttributeStream(i) != -1) |
144 | { |
145 | const VertexAttribute &attrib = attribs[i].mArrayEnabled ? attribs[i] : currentAttribs[i]; |
146 | |
147 | if(attrib.mArrayEnabled) |
148 | { |
149 | const bool isInstanced = attrib.mDivisor > 0; |
150 | |
151 | // Instanced vertices do not apply the 'start' offset |
152 | GLint firstVertexIndex = isInstanced ? instanceId / attrib.mDivisor : start; |
153 | |
154 | Buffer *buffer = attrib.mBoundBuffer; |
155 | |
156 | if((!buffer && attrib.mPointer == nullptr) || (buffer && !buffer->data())) |
157 | { |
158 | // This is an application error that would normally result in a crash, but we catch it and return an error |
159 | ERR("An enabled vertex array has no buffer and no pointer." ); |
160 | return GL_INVALID_OPERATION; |
161 | } |
162 | |
163 | sw::Resource *staticBuffer = buffer ? buffer->getResource() : nullptr; |
164 | |
165 | if(staticBuffer) |
166 | { |
167 | translated[i].vertexBuffer = staticBuffer; |
168 | translated[i].offset = firstVertexIndex * attrib.stride() + static_cast<int>(attrib.mOffset); |
169 | translated[i].stride = isInstanced ? 0 : attrib.stride(); |
170 | } |
171 | else |
172 | { |
173 | unsigned int streamOffset = writeAttributeData(mStreamingBuffer, firstVertexIndex, isInstanced ? 1 : count, attrib); |
174 | |
175 | if(streamOffset == ~0u) |
176 | { |
177 | return GL_OUT_OF_MEMORY; |
178 | } |
179 | |
180 | translated[i].vertexBuffer = mStreamingBuffer->getResource(); |
181 | translated[i].offset = streamOffset; |
182 | translated[i].stride = isInstanced ? 0 : attrib.typeSize(); |
183 | } |
184 | |
185 | switch(attrib.mType) |
186 | { |
187 | case GL_BYTE: translated[i].type = sw::STREAMTYPE_SBYTE; break; |
188 | case GL_UNSIGNED_BYTE: translated[i].type = sw::STREAMTYPE_BYTE; break; |
189 | case GL_SHORT: translated[i].type = sw::STREAMTYPE_SHORT; break; |
190 | case GL_UNSIGNED_SHORT: translated[i].type = sw::STREAMTYPE_USHORT; break; |
191 | case GL_INT: translated[i].type = sw::STREAMTYPE_INT; break; |
192 | case GL_UNSIGNED_INT: translated[i].type = sw::STREAMTYPE_UINT; break; |
193 | case GL_FIXED: translated[i].type = sw::STREAMTYPE_FIXED; break; |
194 | case GL_FLOAT: translated[i].type = sw::STREAMTYPE_FLOAT; break; |
195 | case GL_HALF_FLOAT: translated[i].type = sw::STREAMTYPE_HALF; break; |
196 | case GL_HALF_FLOAT_OES: translated[i].type = sw::STREAMTYPE_HALF; break; |
197 | case GL_INT_2_10_10_10_REV: translated[i].type = sw::STREAMTYPE_2_10_10_10_INT; break; |
198 | case GL_UNSIGNED_INT_2_10_10_10_REV: translated[i].type = sw::STREAMTYPE_2_10_10_10_UINT; break; |
199 | default: UNREACHABLE(attrib.mType); translated[i].type = sw::STREAMTYPE_FLOAT; break; |
200 | } |
201 | |
202 | translated[i].count = attrib.mSize; |
203 | translated[i].normalized = attrib.mNormalized; |
204 | } |
205 | else |
206 | { |
207 | if(mDirtyCurrentValue[i]) |
208 | { |
209 | delete mCurrentValueBuffer[i]; |
210 | mCurrentValueBuffer[i] = new ConstantVertexBuffer(attrib.getCurrentValueBitsAsFloat(0), attrib.getCurrentValueBitsAsFloat(1), attrib.getCurrentValueBitsAsFloat(2), attrib.getCurrentValueBitsAsFloat(3)); |
211 | mDirtyCurrentValue[i] = false; |
212 | } |
213 | |
214 | translated[i].vertexBuffer = mCurrentValueBuffer[i]->getResource(); |
215 | |
216 | switch(attrib.currentValueType()) |
217 | { |
218 | case GL_INT: |
219 | translated[i].type = sw::STREAMTYPE_INT; |
220 | break; |
221 | case GL_UNSIGNED_INT: |
222 | translated[i].type = sw::STREAMTYPE_UINT; |
223 | break; |
224 | default: |
225 | translated[i].type = sw::STREAMTYPE_FLOAT; |
226 | break; |
227 | } |
228 | translated[i].count = 4; |
229 | translated[i].stride = 0; |
230 | translated[i].offset = 0; |
231 | translated[i].normalized = false; |
232 | } |
233 | } |
234 | } |
235 | |
236 | return GL_NO_ERROR; |
237 | } |
238 | |
239 | VertexBuffer::VertexBuffer(unsigned int size) : mVertexBuffer(nullptr) |
240 | { |
241 | if(size > 0) |
242 | { |
243 | mVertexBuffer = new sw::Resource(size + 1024); |
244 | |
245 | if(!mVertexBuffer) |
246 | { |
247 | ERR("Out of memory allocating a vertex buffer of size %u." , size); |
248 | } |
249 | } |
250 | } |
251 | |
252 | VertexBuffer::~VertexBuffer() |
253 | { |
254 | if(mVertexBuffer) |
255 | { |
256 | mVertexBuffer->destruct(); |
257 | } |
258 | } |
259 | |
260 | void VertexBuffer::unmap() |
261 | { |
262 | if(mVertexBuffer) |
263 | { |
264 | mVertexBuffer->unlock(); |
265 | } |
266 | } |
267 | |
268 | sw::Resource *VertexBuffer::getResource() const |
269 | { |
270 | return mVertexBuffer; |
271 | } |
272 | |
273 | ConstantVertexBuffer::ConstantVertexBuffer(float x, float y, float z, float w) : VertexBuffer(4 * sizeof(float)) |
274 | { |
275 | if(mVertexBuffer) |
276 | { |
277 | float *vector = (float*)mVertexBuffer->lock(sw::PUBLIC); |
278 | |
279 | vector[0] = x; |
280 | vector[1] = y; |
281 | vector[2] = z; |
282 | vector[3] = w; |
283 | |
284 | mVertexBuffer->unlock(); |
285 | } |
286 | } |
287 | |
288 | ConstantVertexBuffer::~ConstantVertexBuffer() |
289 | { |
290 | } |
291 | |
292 | StreamingVertexBuffer::StreamingVertexBuffer(unsigned int size) : VertexBuffer(size) |
293 | { |
294 | mBufferSize = size; |
295 | mWritePosition = 0; |
296 | mRequiredSpace = 0; |
297 | } |
298 | |
299 | StreamingVertexBuffer::~StreamingVertexBuffer() |
300 | { |
301 | } |
302 | |
303 | void StreamingVertexBuffer::addRequiredSpace(unsigned int requiredSpace) |
304 | { |
305 | mRequiredSpace += requiredSpace; |
306 | } |
307 | |
308 | void *StreamingVertexBuffer::map(const VertexAttribute &attribute, unsigned int requiredSpace, unsigned int *offset) |
309 | { |
310 | void *mapPtr = nullptr; |
311 | |
312 | if(mVertexBuffer) |
313 | { |
314 | // We can use a private lock because we never overwrite the content |
315 | mapPtr = (char*)mVertexBuffer->lock(sw::PRIVATE) + mWritePosition; |
316 | |
317 | *offset = mWritePosition; |
318 | mWritePosition += requiredSpace; |
319 | } |
320 | |
321 | return mapPtr; |
322 | } |
323 | |
324 | void StreamingVertexBuffer::reserveRequiredSpace() |
325 | { |
326 | if(mRequiredSpace > mBufferSize) |
327 | { |
328 | if(mVertexBuffer) |
329 | { |
330 | mVertexBuffer->destruct(); |
331 | mVertexBuffer = 0; |
332 | } |
333 | |
334 | mBufferSize = std::max(mRequiredSpace, 3 * mBufferSize / 2); // 1.5 x mBufferSize is arbitrary and should be checked to see we don't have too many reallocations. |
335 | |
336 | mVertexBuffer = new sw::Resource(mBufferSize); |
337 | |
338 | if(!mVertexBuffer) |
339 | { |
340 | ERR("Out of memory allocating a vertex buffer of size %u." , mBufferSize); |
341 | } |
342 | |
343 | mWritePosition = 0; |
344 | } |
345 | else if(mWritePosition + mRequiredSpace > mBufferSize) // Recycle |
346 | { |
347 | if(mVertexBuffer) |
348 | { |
349 | mVertexBuffer->destruct(); |
350 | mVertexBuffer = new sw::Resource(mBufferSize); |
351 | } |
352 | |
353 | mWritePosition = 0; |
354 | } |
355 | |
356 | mRequiredSpace = 0; |
357 | } |
358 | |
359 | } |
360 | |