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