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