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
25namespace
26{
27 enum {INITIAL_STREAM_BUFFER_SIZE = 1024 * 1024};
28}
29
30namespace es2
31{
32
33VertexDataManager::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
49VertexDataManager::~VertexDataManager()
50{
51 delete mStreamingBuffer;
52
53 for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
54 {
55 delete mCurrentValueBuffer[i];
56 }
57}
58
59unsigned 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
112GLenum 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 &currentAttribs = 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
239VertexBuffer::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
252VertexBuffer::~VertexBuffer()
253{
254 if(mVertexBuffer)
255 {
256 mVertexBuffer->destruct();
257 }
258}
259
260void VertexBuffer::unmap()
261{
262 if(mVertexBuffer)
263 {
264 mVertexBuffer->unlock();
265 }
266}
267
268sw::Resource *VertexBuffer::getResource() const
269{
270 return mVertexBuffer;
271}
272
273ConstantVertexBuffer::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
288ConstantVertexBuffer::~ConstantVertexBuffer()
289{
290}
291
292StreamingVertexBuffer::StreamingVertexBuffer(unsigned int size) : VertexBuffer(size)
293{
294 mBufferSize = size;
295 mWritePosition = 0;
296 mRequiredSpace = 0;
297}
298
299StreamingVertexBuffer::~StreamingVertexBuffer()
300{
301}
302
303void StreamingVertexBuffer::addRequiredSpace(unsigned int requiredSpace)
304{
305 mRequiredSpace += requiredSpace;
306}
307
308void *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
324void 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