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
VertexDataManager(Context * context)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
~VertexDataManager()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
writeAttributeData(StreamingVertexBuffer * vertexBuffer,GLint start,GLsizei count,const VertexAttribute & attribute)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
prepareVertexData(GLint start,GLsizei count,TranslatedAttribute * translated,GLsizei instanceId)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)
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() + 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_INT_2_10_10_10_REV: translated[i].type = sw::STREAMTYPE_2_10_10_10_INT; break;
197 case GL_UNSIGNED_INT_2_10_10_10_REV: translated[i].type = sw::STREAMTYPE_2_10_10_10_UINT; break;
198 default: UNREACHABLE(attrib.mType); translated[i].type = sw::STREAMTYPE_FLOAT; break;
199 }
200
201 translated[i].count = attrib.mSize;
202 translated[i].normalized = attrib.mNormalized;
203 }
204 else
205 {
206 if(mDirtyCurrentValue[i])
207 {
208 delete mCurrentValueBuffer[i];
209 mCurrentValueBuffer[i] = new ConstantVertexBuffer(attrib.getCurrentValueBitsAsFloat(0), attrib.getCurrentValueBitsAsFloat(1), attrib.getCurrentValueBitsAsFloat(2), attrib.getCurrentValueBitsAsFloat(3));
210 mDirtyCurrentValue[i] = false;
211 }
212
213 translated[i].vertexBuffer = mCurrentValueBuffer[i]->getResource();
214
215 translated[i].type = sw::STREAMTYPE_FLOAT;
216 translated[i].count = 4;
217 translated[i].stride = 0;
218 translated[i].offset = 0;
219 }
220 }
221 }
222
223 return GL_NO_ERROR;
224 }
225
VertexBuffer(unsigned int size)226 VertexBuffer::VertexBuffer(unsigned int size) : mVertexBuffer(nullptr)
227 {
228 if(size > 0)
229 {
230 mVertexBuffer = new sw::Resource(size + 1024);
231
232 if(!mVertexBuffer)
233 {
234 ERR("Out of memory allocating a vertex buffer of size %u.", size);
235 }
236 }
237 }
238
~VertexBuffer()239 VertexBuffer::~VertexBuffer()
240 {
241 if(mVertexBuffer)
242 {
243 mVertexBuffer->destruct();
244 }
245 }
246
unmap()247 void VertexBuffer::unmap()
248 {
249 if(mVertexBuffer)
250 {
251 mVertexBuffer->unlock();
252 }
253 }
254
getResource() const255 sw::Resource *VertexBuffer::getResource() const
256 {
257 return mVertexBuffer;
258 }
259
ConstantVertexBuffer(float x,float y,float z,float w)260 ConstantVertexBuffer::ConstantVertexBuffer(float x, float y, float z, float w) : VertexBuffer(4 * sizeof(float))
261 {
262 if(mVertexBuffer)
263 {
264 float *vector = (float*)mVertexBuffer->lock(sw::PUBLIC);
265
266 vector[0] = x;
267 vector[1] = y;
268 vector[2] = z;
269 vector[3] = w;
270
271 mVertexBuffer->unlock();
272 }
273 }
274
~ConstantVertexBuffer()275 ConstantVertexBuffer::~ConstantVertexBuffer()
276 {
277 }
278
StreamingVertexBuffer(unsigned int size)279 StreamingVertexBuffer::StreamingVertexBuffer(unsigned int size) : VertexBuffer(size)
280 {
281 mBufferSize = size;
282 mWritePosition = 0;
283 mRequiredSpace = 0;
284 }
285
~StreamingVertexBuffer()286 StreamingVertexBuffer::~StreamingVertexBuffer()
287 {
288 }
289
addRequiredSpace(unsigned int requiredSpace)290 void StreamingVertexBuffer::addRequiredSpace(unsigned int requiredSpace)
291 {
292 mRequiredSpace += requiredSpace;
293 }
294
map(const VertexAttribute & attribute,unsigned int requiredSpace,unsigned int * offset)295 void *StreamingVertexBuffer::map(const VertexAttribute &attribute, unsigned int requiredSpace, unsigned int *offset)
296 {
297 void *mapPtr = nullptr;
298
299 if(mVertexBuffer)
300 {
301 // We can use a private lock because we never overwrite the content
302 mapPtr = (char*)mVertexBuffer->lock(sw::PRIVATE) + mWritePosition;
303
304 *offset = mWritePosition;
305 mWritePosition += requiredSpace;
306 }
307
308 return mapPtr;
309 }
310
reserveRequiredSpace()311 void StreamingVertexBuffer::reserveRequiredSpace()
312 {
313 if(mRequiredSpace > mBufferSize)
314 {
315 if(mVertexBuffer)
316 {
317 mVertexBuffer->destruct();
318 mVertexBuffer = 0;
319 }
320
321 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.
322
323 mVertexBuffer = new sw::Resource(mBufferSize);
324
325 if(!mVertexBuffer)
326 {
327 ERR("Out of memory allocating a vertex buffer of size %u.", mBufferSize);
328 }
329
330 mWritePosition = 0;
331 }
332 else if(mWritePosition + mRequiredSpace > mBufferSize) // Recycle
333 {
334 if(mVertexBuffer)
335 {
336 mVertexBuffer->destruct();
337 mVertexBuffer = new sw::Resource(mBufferSize);
338 }
339
340 mWritePosition = 0;
341 }
342
343 mRequiredSpace = 0;
344 }
345
346 }
347