• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &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 
VertexBuffer(unsigned int size)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 
~VertexBuffer()252 VertexBuffer::~VertexBuffer()
253 {
254 	if(mVertexBuffer)
255 	{
256 		mVertexBuffer->destruct();
257 	}
258 }
259 
unmap()260 void VertexBuffer::unmap()
261 {
262 	if(mVertexBuffer)
263 	{
264 		mVertexBuffer->unlock();
265 	}
266 }
267 
getResource() const268 sw::Resource *VertexBuffer::getResource() const
269 {
270 	return mVertexBuffer;
271 }
272 
ConstantVertexBuffer(float x,float y,float z,float w)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 
~ConstantVertexBuffer()288 ConstantVertexBuffer::~ConstantVertexBuffer()
289 {
290 }
291 
StreamingVertexBuffer(unsigned int size)292 StreamingVertexBuffer::StreamingVertexBuffer(unsigned int size) : VertexBuffer(size)
293 {
294 	mBufferSize = size;
295 	mWritePosition = 0;
296 	mRequiredSpace = 0;
297 }
298 
~StreamingVertexBuffer()299 StreamingVertexBuffer::~StreamingVertexBuffer()
300 {
301 }
302 
addRequiredSpace(unsigned int requiredSpace)303 void StreamingVertexBuffer::addRequiredSpace(unsigned int requiredSpace)
304 {
305 	mRequiredSpace += requiredSpace;
306 }
307 
map(const VertexAttribute & attribute,unsigned int requiredSpace,unsigned int * offset)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 
reserveRequiredSpace()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