• 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 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