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