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 gl
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 int offset = attribute.mOffset;
85
86 input = static_cast<const char*>(buffer->data()) + offset;
87 }
88 else
89 {
90 input = static_cast<const char*>(attribute.mPointer);
91 }
92
93 input += inputStride * start;
94
95 if(inputStride == elementSize)
96 {
97 memcpy(output, input, count * inputStride);
98 }
99 else
100 {
101 for(int i = 0; i < count; i++)
102 {
103 memcpy(output, input, elementSize);
104 output += elementSize;
105 input += inputStride;
106 }
107 }
108
109 vertexBuffer->unmap();
110
111 return streamOffset;
112 }
113
prepareVertexData(GLint start,GLsizei count,TranslatedAttribute * translated)114 GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated)
115 {
116 if(!mStreamingBuffer)
117 {
118 return GL_OUT_OF_MEMORY;
119 }
120
121 const VertexAttributeArray &attribs = mContext->getVertexAttributes();
122 Program *program = mContext->getCurrentProgram();
123
124 // Determine the required storage size per used buffer
125 for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
126 {
127 if(!program || program->getAttributeStream(i) != -1)
128 {
129 if(attribs[i].mArrayEnabled)
130 {
131 if(!attribs[i].mBoundBuffer)
132 {
133 mStreamingBuffer->addRequiredSpace(attribs[i].typeSize() * count);
134 }
135 }
136 }
137 }
138
139 mStreamingBuffer->reserveRequiredSpace();
140
141 // Perform the vertex data translations
142 for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
143 {
144 if(!program || program->getAttributeStream(i) != -1)
145 {
146 if(attribs[i].mArrayEnabled)
147 {
148 Buffer *buffer = attribs[i].mBoundBuffer;
149
150 if(!buffer && attribs[i].mPointer == nullptr)
151 {
152 // This is an application error that would normally result in a crash, but we catch it and return an error
153 ERR("An enabled vertex array has no buffer and no pointer.");
154 return GL_INVALID_OPERATION;
155 }
156
157 sw::Resource *staticBuffer = buffer ? buffer->getResource() : nullptr;
158
159 if(staticBuffer)
160 {
161 translated[i].vertexBuffer = staticBuffer;
162 translated[i].offset = start * attribs[i].stride() + attribs[i].mOffset;
163 translated[i].stride = attribs[i].stride();
164 }
165 else
166 {
167 unsigned int streamOffset = writeAttributeData(mStreamingBuffer, start, count, attribs[i]);
168
169 if(streamOffset == ~0u)
170 {
171 return GL_OUT_OF_MEMORY;
172 }
173
174 translated[i].vertexBuffer = mStreamingBuffer->getResource();
175 translated[i].offset = streamOffset;
176 translated[i].stride = attribs[i].typeSize();
177 }
178
179 switch(attribs[i].mType)
180 {
181 case GL_BYTE: translated[i].type = sw::STREAMTYPE_SBYTE; break;
182 case GL_UNSIGNED_BYTE: translated[i].type = sw::STREAMTYPE_BYTE; break;
183 case GL_SHORT: translated[i].type = sw::STREAMTYPE_SHORT; break;
184 case GL_UNSIGNED_SHORT: translated[i].type = sw::STREAMTYPE_USHORT; break;
185 case GL_INT: translated[i].type = sw::STREAMTYPE_INT; break;
186 case GL_UNSIGNED_INT: translated[i].type = sw::STREAMTYPE_UINT; break;
187 case GL_FIXED: translated[i].type = sw::STREAMTYPE_FIXED; break;
188 case GL_FLOAT: translated[i].type = sw::STREAMTYPE_FLOAT; break;
189 default: UNREACHABLE(attribs[i].mType); translated[i].type = sw::STREAMTYPE_FLOAT; break;
190 }
191
192 translated[i].count = attribs[i].mSize;
193 translated[i].normalized = attribs[i].mNormalized;
194 }
195 else
196 {
197 if(mDirtyCurrentValue[i])
198 {
199 delete mCurrentValueBuffer[i];
200 mCurrentValueBuffer[i] = new ConstantVertexBuffer(attribs[i].mCurrentValue[0], attribs[i].mCurrentValue[1], attribs[i].mCurrentValue[2], attribs[i].mCurrentValue[3]);
201 mDirtyCurrentValue[i] = false;
202 }
203
204 translated[i].vertexBuffer = mCurrentValueBuffer[i]->getResource();
205
206 translated[i].type = sw::STREAMTYPE_FLOAT;
207 translated[i].count = 4;
208 translated[i].stride = 0;
209 translated[i].offset = 0;
210 }
211 }
212 }
213
214 return GL_NO_ERROR;
215 }
216
VertexBuffer(unsigned int size)217 VertexBuffer::VertexBuffer(unsigned int size) : mVertexBuffer(nullptr)
218 {
219 if(size > 0)
220 {
221 mVertexBuffer = new sw::Resource(size + 1024);
222
223 if(!mVertexBuffer)
224 {
225 ERR("Out of memory allocating a vertex buffer of size %u.", size);
226 }
227 }
228 }
229
~VertexBuffer()230 VertexBuffer::~VertexBuffer()
231 {
232 if(mVertexBuffer)
233 {
234 mVertexBuffer->destruct();
235 }
236 }
237
unmap()238 void VertexBuffer::unmap()
239 {
240 if(mVertexBuffer)
241 {
242 mVertexBuffer->unlock();
243 }
244 }
245
getResource() const246 sw::Resource *VertexBuffer::getResource() const
247 {
248 return mVertexBuffer;
249 }
250
ConstantVertexBuffer(float x,float y,float z,float w)251 ConstantVertexBuffer::ConstantVertexBuffer(float x, float y, float z, float w) : VertexBuffer(4 * sizeof(float))
252 {
253 if(mVertexBuffer)
254 {
255 float *vector = (float*)mVertexBuffer->lock(sw::PUBLIC);
256
257 vector[0] = x;
258 vector[1] = y;
259 vector[2] = z;
260 vector[3] = w;
261
262 mVertexBuffer->unlock();
263 }
264 }
265
~ConstantVertexBuffer()266 ConstantVertexBuffer::~ConstantVertexBuffer()
267 {
268 }
269
StreamingVertexBuffer(unsigned int size)270 StreamingVertexBuffer::StreamingVertexBuffer(unsigned int size) : VertexBuffer(size)
271 {
272 mBufferSize = size;
273 mWritePosition = 0;
274 mRequiredSpace = 0;
275 }
276
~StreamingVertexBuffer()277 StreamingVertexBuffer::~StreamingVertexBuffer()
278 {
279 }
280
addRequiredSpace(unsigned int requiredSpace)281 void StreamingVertexBuffer::addRequiredSpace(unsigned int requiredSpace)
282 {
283 mRequiredSpace += requiredSpace;
284 }
285
map(const VertexAttribute & attribute,unsigned int requiredSpace,unsigned int * offset)286 void *StreamingVertexBuffer::map(const VertexAttribute &attribute, unsigned int requiredSpace, unsigned int *offset)
287 {
288 void *mapPtr = nullptr;
289
290 if(mVertexBuffer)
291 {
292 // We can use a private lock because we never overwrite the content
293 mapPtr = (char*)mVertexBuffer->lock(sw::PRIVATE) + mWritePosition;
294
295 *offset = mWritePosition;
296 mWritePosition += requiredSpace;
297 }
298
299 return mapPtr;
300 }
301
reserveRequiredSpace()302 void StreamingVertexBuffer::reserveRequiredSpace()
303 {
304 if(mRequiredSpace > mBufferSize)
305 {
306 if(mVertexBuffer)
307 {
308 mVertexBuffer->destruct();
309 mVertexBuffer = 0;
310 }
311
312 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.
313
314 mVertexBuffer = new sw::Resource(mBufferSize);
315
316 if(!mVertexBuffer)
317 {
318 ERR("Out of memory allocating a vertex buffer of size %u.", mBufferSize);
319 }
320
321 mWritePosition = 0;
322 }
323 else if(mWritePosition + mRequiredSpace > mBufferSize) // Recycle
324 {
325 if(mVertexBuffer)
326 {
327 mVertexBuffer->destruct();
328 mVertexBuffer = new sw::Resource(mBufferSize);
329 }
330
331 mWritePosition = 0;
332 }
333
334 mRequiredSpace = 0;
335 }
336
337 }
338