Home | History | Annotate | Download | only in libGLESv2
      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 // IndexDataManager.cpp: Defines the IndexDataManager, a class that
     16 // runs the Buffer translation process for index buffers.
     17 
     18 #include "IndexDataManager.h"
     19 
     20 #include "Buffer.h"
     21 #include "common/debug.h"
     22 
     23 #include <string.h>
     24 #include <algorithm>
     25 
     26 namespace
     27 {
     28 	enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) };
     29 }
     30 
     31 namespace es2
     32 {
     33 
     34 IndexDataManager::IndexDataManager()
     35 {
     36 	mStreamingBuffer = new StreamingIndexBuffer(INITIAL_INDEX_BUFFER_SIZE);
     37 
     38 	if(!mStreamingBuffer)
     39 	{
     40 		ERR("Failed to allocate the streaming index buffer.");
     41 	}
     42 }
     43 
     44 IndexDataManager::~IndexDataManager()
     45 {
     46 	delete mStreamingBuffer;
     47 }
     48 
     49 void copyIndices(GLenum type, const void *input, GLsizei count, void *output)
     50 {
     51 	if(type == GL_UNSIGNED_BYTE)
     52 	{
     53 		memcpy(output, input, count * sizeof(GLubyte));
     54 	}
     55 	else if(type == GL_UNSIGNED_INT)
     56 	{
     57 		memcpy(output, input, count * sizeof(GLuint));
     58 	}
     59 	else if(type == GL_UNSIGNED_SHORT)
     60 	{
     61 		memcpy(output, input, count * sizeof(GLushort));
     62 	}
     63 	else UNREACHABLE(type);
     64 }
     65 
     66 inline GLsizei getNumIndices(const std::vector<GLsizei>& restartIndices, size_t i, GLsizei count)
     67 {
     68 	return restartIndices.empty() ? count :
     69 	       ((i == 0) ? restartIndices[0] : ((i == restartIndices.size()) ? (count - restartIndices[i - 1] - 1) : (restartIndices[i] - restartIndices[i - 1] - 1)));
     70 }
     71 
     72 void copyIndices(GLenum mode, GLenum type, const std::vector<GLsizei>& restartIndices, const void *input, GLsizei count, void* output)
     73 {
     74 	size_t bytesPerIndex = 0;
     75 	const unsigned char* inPtr = static_cast<const unsigned char*>(input);
     76 	unsigned char* outPtr = static_cast<unsigned char*>(output);
     77 	switch(type)
     78 	{
     79 	case GL_UNSIGNED_BYTE:
     80 		bytesPerIndex = sizeof(GLubyte);
     81 		break;
     82 	case GL_UNSIGNED_INT:
     83 		bytesPerIndex = sizeof(GLuint);
     84 		break;
     85 	case GL_UNSIGNED_SHORT:
     86 		bytesPerIndex = sizeof(GLushort);
     87 		break;
     88 	default:
     89 		UNREACHABLE(type);
     90 	}
     91 
     92 	size_t numRestarts = restartIndices.size();
     93 	switch(mode)
     94 	{
     95 	case GL_TRIANGLES:
     96 	case GL_LINES:
     97 	case GL_POINTS:
     98 	{
     99 		GLsizei verticesPerPrimitive = (mode == GL_TRIANGLES) ? 3 : ((mode == GL_LINES) ? 2 : 1);
    100 		for(size_t i = 0; i <= numRestarts; ++i)
    101 		{
    102 			GLsizei numIndices = getNumIndices(restartIndices, i, count);
    103 			size_t numBytes = (numIndices / verticesPerPrimitive) * verticesPerPrimitive * bytesPerIndex;
    104 			if(numBytes > 0)
    105 			{
    106 				memcpy(outPtr, inPtr, numBytes);
    107 				outPtr += numBytes;
    108 			}
    109 			inPtr += (numIndices + 1) * bytesPerIndex;
    110 		}
    111 	}
    112 		break;
    113 	case GL_TRIANGLE_FAN:
    114 		for(size_t i = 0; i <= numRestarts; ++i)
    115 		{
    116 			GLsizei numIndices = getNumIndices(restartIndices, i, count);
    117 			GLsizei numTriangles = (numIndices - 2);
    118 			for(GLsizei tri = 0; tri < numTriangles; ++tri)
    119 			{
    120 				memcpy(outPtr, inPtr, bytesPerIndex);
    121 				outPtr += bytesPerIndex;
    122 				memcpy(outPtr, inPtr + ((tri + 1) * bytesPerIndex), bytesPerIndex + bytesPerIndex);
    123 				outPtr += bytesPerIndex + bytesPerIndex;
    124 			}
    125 			inPtr += (numIndices + 1) * bytesPerIndex;
    126 		}
    127 		break;
    128 	case GL_TRIANGLE_STRIP:
    129 		for(size_t i = 0; i <= numRestarts; ++i)
    130 		{
    131 			GLsizei numIndices = getNumIndices(restartIndices, i, count);
    132 			GLsizei numTriangles = (numIndices - 2);
    133 			for(GLsizei tri = 0; tri < numTriangles; ++tri)
    134 			{
    135 				if(tri & 1) // Reverse odd triangles
    136 				{
    137 					memcpy(outPtr, inPtr + ((tri + 1) * bytesPerIndex), bytesPerIndex);
    138 					outPtr += bytesPerIndex;
    139 					memcpy(outPtr, inPtr + ((tri + 0) * bytesPerIndex), bytesPerIndex);
    140 					outPtr += bytesPerIndex;
    141 					memcpy(outPtr, inPtr + ((tri + 2) * bytesPerIndex), bytesPerIndex);
    142 					outPtr += bytesPerIndex;
    143 				}
    144 				else
    145 				{
    146 					size_t numBytes = 3 * bytesPerIndex;
    147 					memcpy(outPtr, inPtr + (tri * bytesPerIndex), numBytes);
    148 					outPtr += numBytes;
    149 				}
    150 			}
    151 			inPtr += (numIndices + 1) * bytesPerIndex;
    152 		}
    153 		break;
    154 	case GL_LINE_LOOP:
    155 		for(size_t i = 0; i <= numRestarts; ++i)
    156 		{
    157 			GLsizei numIndices = getNumIndices(restartIndices, i, count);
    158 			if(numIndices >= 2)
    159 			{
    160 				GLsizei numLines = numIndices;
    161 				memcpy(outPtr, inPtr + (numIndices - 1) * bytesPerIndex, bytesPerIndex); // Last vertex
    162 				outPtr += bytesPerIndex;
    163 				memcpy(outPtr, inPtr, bytesPerIndex); // First vertex
    164 				outPtr += bytesPerIndex;
    165 				size_t bytesPerLine = 2 * bytesPerIndex;
    166 				for(GLsizei tri = 0; tri < (numLines - 1); ++tri)
    167 				{
    168 					memcpy(outPtr, inPtr + tri * bytesPerIndex, bytesPerLine);
    169 					outPtr += bytesPerLine;
    170 				}
    171 			}
    172 			inPtr += (numIndices + 1) * bytesPerIndex;
    173 		}
    174 		break;
    175 	case GL_LINE_STRIP:
    176 		for(size_t i = 0; i <= numRestarts; ++i)
    177 		{
    178 			GLsizei numIndices = getNumIndices(restartIndices, i, count);
    179 			GLsizei numLines = numIndices - 1;
    180 			size_t bytesPerLine = 2 * bytesPerIndex;
    181 			for(GLsizei tri = 0; tri < numLines; ++tri)
    182 			{
    183 				memcpy(outPtr, inPtr + tri * bytesPerIndex, bytesPerLine);
    184 				outPtr += bytesPerLine;
    185 			}
    186 			inPtr += (numIndices + 1) * bytesPerIndex;
    187 		}
    188 		break;
    189 	default:
    190 		UNREACHABLE(mode);
    191 		break;
    192 	}
    193 }
    194 
    195 template<class IndexType>
    196 void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex, std::vector<GLsizei>* restartIndices)
    197 {
    198 	*maxIndex = 0;
    199 	*minIndex = MAX_ELEMENTS_INDICES;
    200 
    201 	for(GLsizei i = 0; i < count; i++)
    202 	{
    203 		if(restartIndices && indices[i] == IndexType(-1))
    204 		{
    205 			restartIndices->push_back(i);
    206 			continue;
    207 		}
    208 		if(*minIndex > indices[i]) *minIndex = indices[i];
    209 		if(*maxIndex < indices[i]) *maxIndex = indices[i];
    210 	}
    211 }
    212 
    213 void computeRange(GLenum type, const void *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex, std::vector<GLsizei>* restartIndices)
    214 {
    215 	if(type == GL_UNSIGNED_BYTE)
    216 	{
    217 		computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex, restartIndices);
    218 	}
    219 	else if(type == GL_UNSIGNED_INT)
    220 	{
    221 		computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex, restartIndices);
    222 	}
    223 	else if(type == GL_UNSIGNED_SHORT)
    224 	{
    225 		computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex, restartIndices);
    226 	}
    227 	else UNREACHABLE(type);
    228 }
    229 
    230 int recomputePrimitiveCount(GLenum mode, GLsizei count, const std::vector<GLsizei>& restartIndices, unsigned int* primitiveCount)
    231 {
    232 	size_t numRestarts = restartIndices.size();
    233 	*primitiveCount = 0;
    234 
    235 	unsigned int countOffset = 0;
    236 	unsigned int vertexPerPrimitive = 0;
    237 
    238 	switch(mode)
    239 	{
    240 	case GL_TRIANGLES: // 3 vertex per primitive
    241 		++vertexPerPrimitive;
    242 	case GL_LINES: //  2 vertex per primitive
    243 		vertexPerPrimitive += 2;
    244 		for(size_t i = 0; i <= numRestarts; ++i)
    245 		{
    246 			unsigned int nbIndices = getNumIndices(restartIndices, i, count);
    247 			*primitiveCount += nbIndices / vertexPerPrimitive;
    248 		}
    249 		return vertexPerPrimitive;
    250 	case GL_TRIANGLE_FAN:
    251 	case GL_TRIANGLE_STRIP: // (N - 2) polygons, 3 vertex per primitive
    252 		++vertexPerPrimitive;
    253 		--countOffset;
    254 	case GL_LINE_STRIP: // (N - 1) polygons, 2 vertex per primitive
    255 		--countOffset;
    256 	case GL_LINE_LOOP: // N polygons, 2 vertex per primitive
    257 		vertexPerPrimitive += 2;
    258 		for(size_t i = 0; i <= numRestarts; ++i)
    259 		{
    260 			unsigned int nbIndices = getNumIndices(restartIndices, i, count);
    261 			*primitiveCount += (nbIndices >= vertexPerPrimitive) ? (nbIndices + countOffset) : 0;
    262 		}
    263 		return vertexPerPrimitive;
    264 	case GL_POINTS:
    265 		*primitiveCount = static_cast<unsigned int>(count - restartIndices.size());
    266 		return 1;
    267 	default:
    268 		UNREACHABLE(mode);
    269 		return -1;
    270 	}
    271 }
    272 
    273 GLenum IndexDataManager::prepareIndexData(GLenum mode, GLenum type, GLuint start, GLuint end, GLsizei count, Buffer *buffer, const void *indices, TranslatedIndexData *translated, bool primitiveRestart)
    274 {
    275 	if(!mStreamingBuffer)
    276 	{
    277 		return GL_OUT_OF_MEMORY;
    278 	}
    279 
    280 	intptr_t offset = reinterpret_cast<intptr_t>(indices);
    281 
    282 	if(buffer != NULL)
    283 	{
    284 		if(typeSize(type) * count + offset > static_cast<std::size_t>(buffer->size()))
    285 		{
    286 			return GL_INVALID_OPERATION;
    287 		}
    288 
    289 		indices = static_cast<const GLubyte*>(buffer->data()) + offset;
    290 	}
    291 
    292 	std::vector<GLsizei>* restartIndices = primitiveRestart ? new std::vector<GLsizei>() : nullptr;
    293 	computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex, restartIndices);
    294 
    295 	StreamingIndexBuffer *streamingBuffer = mStreamingBuffer;
    296 
    297 	sw::Resource *staticBuffer = buffer ? buffer->getResource() : NULL;
    298 
    299 	if(restartIndices)
    300 	{
    301 		int vertexPerPrimitive = recomputePrimitiveCount(mode, count, *restartIndices, &translated->primitiveCount);
    302 		if(vertexPerPrimitive == -1)
    303 		{
    304 			delete restartIndices;
    305 			return GL_INVALID_ENUM;
    306 		}
    307 
    308 		size_t streamOffset = 0;
    309 		int convertCount = translated->primitiveCount * vertexPerPrimitive;
    310 
    311 		streamingBuffer->reserveSpace(convertCount * typeSize(type), type);
    312 		void *output = streamingBuffer->map(typeSize(type) * convertCount, &streamOffset);
    313 
    314 		if(output == NULL)
    315 		{
    316 			delete restartIndices;
    317 			ERR("Failed to map index buffer.");
    318 			return GL_OUT_OF_MEMORY;
    319 		}
    320 
    321 		copyIndices(mode, type, *restartIndices, indices, count, output);
    322 		streamingBuffer->unmap();
    323 
    324 		translated->indexBuffer = streamingBuffer->getResource();
    325 		translated->indexOffset = static_cast<unsigned int>(streamOffset);
    326 		delete restartIndices;
    327 	}
    328 	else if(staticBuffer)
    329 	{
    330 		translated->indexBuffer = staticBuffer;
    331 		translated->indexOffset = static_cast<unsigned int>(offset);
    332 	}
    333 	else
    334 	{
    335 		size_t streamOffset = 0;
    336 		int convertCount = count;
    337 
    338 		streamingBuffer->reserveSpace(convertCount * typeSize(type), type);
    339 		void *output = streamingBuffer->map(typeSize(type) * convertCount, &streamOffset);
    340 
    341 		if(output == NULL)
    342 		{
    343 			ERR("Failed to map index buffer.");
    344 			return GL_OUT_OF_MEMORY;
    345 		}
    346 
    347 		copyIndices(type, indices, convertCount, output);
    348 		streamingBuffer->unmap();
    349 
    350 		translated->indexBuffer = streamingBuffer->getResource();
    351 		translated->indexOffset = static_cast<unsigned int>(streamOffset);
    352 	}
    353 
    354 	if(translated->minIndex < start || translated->maxIndex > end)
    355 	{
    356 		ERR("glDrawRangeElements: out of range access. Range provided: [%d -> %d]. Range used: [%d -> %d].", start, end, translated->minIndex, translated->maxIndex);
    357 	}
    358 
    359 	return GL_NO_ERROR;
    360 }
    361 
    362 std::size_t IndexDataManager::typeSize(GLenum type)
    363 {
    364 	switch(type)
    365 	{
    366 	case GL_UNSIGNED_INT:   return sizeof(GLuint);
    367 	case GL_UNSIGNED_SHORT: return sizeof(GLushort);
    368 	case GL_UNSIGNED_BYTE:  return sizeof(GLubyte);
    369 	default: UNREACHABLE(type); return sizeof(GLushort);
    370 	}
    371 }
    372 
    373 StreamingIndexBuffer::StreamingIndexBuffer(size_t initialSize) : mIndexBuffer(NULL), mBufferSize(initialSize)
    374 {
    375 	if(initialSize > 0)
    376 	{
    377 		mIndexBuffer = new sw::Resource(initialSize + 16);
    378 
    379 		if(!mIndexBuffer)
    380 		{
    381 			ERR("Out of memory allocating an index buffer of size %u.", initialSize);
    382 		}
    383 	}
    384 
    385 	mWritePosition = 0;
    386 }
    387 
    388 StreamingIndexBuffer::~StreamingIndexBuffer()
    389 {
    390 	if(mIndexBuffer)
    391 	{
    392 		mIndexBuffer->destruct();
    393 	}
    394 }
    395 
    396 void *StreamingIndexBuffer::map(size_t requiredSpace, size_t *offset)
    397 {
    398 	void *mapPtr = NULL;
    399 
    400 	if(mIndexBuffer)
    401 	{
    402 		mapPtr = (char*)mIndexBuffer->lock(sw::PUBLIC) + mWritePosition;
    403 
    404 		if(!mapPtr)
    405 		{
    406 			ERR(" Lock failed");
    407 			return NULL;
    408 		}
    409 
    410 		*offset = mWritePosition;
    411 		mWritePosition += requiredSpace;
    412 	}
    413 
    414 	return mapPtr;
    415 }
    416 
    417 void StreamingIndexBuffer::unmap()
    418 {
    419 	if(mIndexBuffer)
    420 	{
    421 		mIndexBuffer->unlock();
    422 	}
    423 }
    424 
    425 void StreamingIndexBuffer::reserveSpace(size_t requiredSpace, GLenum type)
    426 {
    427 	if(requiredSpace > mBufferSize)
    428 	{
    429 		if(mIndexBuffer)
    430 		{
    431 			mIndexBuffer->destruct();
    432 			mIndexBuffer = 0;
    433 		}
    434 
    435 		mBufferSize = std::max(requiredSpace, 2 * mBufferSize);
    436 
    437 		mIndexBuffer = new sw::Resource(mBufferSize + 16);
    438 
    439 		if(!mIndexBuffer)
    440 		{
    441 			ERR("Out of memory allocating an index buffer of size %u.", mBufferSize);
    442 		}
    443 
    444 		mWritePosition = 0;
    445 	}
    446 	else if(mWritePosition + requiredSpace > mBufferSize)   // Recycle
    447 	{
    448 		if(mIndexBuffer)
    449 		{
    450 			mIndexBuffer->destruct();
    451 			mIndexBuffer = new sw::Resource(mBufferSize + 16);
    452 		}
    453 
    454 		mWritePosition = 0;
    455 	}
    456 }
    457 
    458 sw::Resource *StreamingIndexBuffer::getResource() const
    459 {
    460 	return mIndexBuffer;
    461 }
    462 
    463 }
    464