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 gl
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		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
114GLenum 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
217VertexBuffer::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
230VertexBuffer::~VertexBuffer()
231{
232	if(mVertexBuffer)
233	{
234		mVertexBuffer->destruct();
235	}
236}
237
238void VertexBuffer::unmap()
239{
240	if(mVertexBuffer)
241	{
242		mVertexBuffer->unlock();
243	}
244}
245
246sw::Resource *VertexBuffer::getResource() const
247{
248	return mVertexBuffer;
249}
250
251ConstantVertexBuffer::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
266ConstantVertexBuffer::~ConstantVertexBuffer()
267{
268}
269
270StreamingVertexBuffer::StreamingVertexBuffer(unsigned int size) : VertexBuffer(size)
271{
272	mBufferSize = size;
273	mWritePosition = 0;
274	mRequiredSpace = 0;
275}
276
277StreamingVertexBuffer::~StreamingVertexBuffer()
278{
279}
280
281void StreamingVertexBuffer::addRequiredSpace(unsigned int requiredSpace)
282{
283	mRequiredSpace += requiredSpace;
284}
285
286void *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
302void 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