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 // 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 gl
     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 template<class IndexType>
     67 void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
     68 {
     69 	*minIndex = indices[0];
     70 	*maxIndex = indices[0];
     71 
     72 	for(GLsizei i = 0; i < count; i++)
     73 	{
     74 		if(*minIndex > indices[i]) *minIndex = indices[i];
     75 		if(*maxIndex < indices[i]) *maxIndex = indices[i];
     76 	}
     77 }
     78 
     79 void computeRange(GLenum type, const void *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
     80 {
     81 	if(type == GL_UNSIGNED_BYTE)
     82 	{
     83 		computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
     84 	}
     85 	else if(type == GL_UNSIGNED_INT)
     86 	{
     87 		computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
     88 	}
     89 	else if(type == GL_UNSIGNED_SHORT)
     90 	{
     91 		computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
     92 	}
     93 	else UNREACHABLE(type);
     94 }
     95 
     96 GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, Buffer *buffer, const void *indices, TranslatedIndexData *translated)
     97 {
     98 	if(!mStreamingBuffer)
     99 	{
    100 		return GL_OUT_OF_MEMORY;
    101 	}
    102 
    103 	intptr_t offset = reinterpret_cast<intptr_t>(indices);
    104 	bool alignedOffset = false;
    105 
    106 	if(buffer)
    107 	{
    108 		switch(type)
    109 		{
    110 		case GL_UNSIGNED_BYTE:  alignedOffset = (offset % sizeof(GLubyte) == 0);  break;
    111 		case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
    112 		case GL_UNSIGNED_INT:   alignedOffset = (offset % sizeof(GLuint) == 0);   break;
    113 		default: UNREACHABLE(type); alignedOffset = false;
    114 		}
    115 
    116 		if(typeSize(type) * count + offset > static_cast<std::size_t>(buffer->size()))
    117 		{
    118 			return GL_INVALID_OPERATION;
    119 		}
    120 
    121 		indices = static_cast<const GLubyte*>(buffer->data()) + offset;
    122 	}
    123 
    124 	StreamingIndexBuffer *streamingBuffer = mStreamingBuffer;
    125 
    126 	sw::Resource *staticBuffer = buffer ? buffer->getResource() : nullptr;
    127 
    128 	if(staticBuffer)
    129 	{
    130 		computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
    131 
    132 		translated->indexBuffer = staticBuffer;
    133 		translated->indexOffset = offset;
    134 	}
    135 	else
    136 	{
    137 		unsigned int streamOffset = 0;
    138 		int convertCount = count;
    139 
    140 		streamingBuffer->reserveSpace(convertCount * typeSize(type), type);
    141 		void *output = streamingBuffer->map(typeSize(type) * convertCount, &streamOffset);
    142 
    143 		if(!output)
    144 		{
    145 			ERR("Failed to map index buffer.");
    146 			return GL_OUT_OF_MEMORY;
    147 		}
    148 
    149 		copyIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output);
    150 		streamingBuffer->unmap();
    151 
    152 		computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
    153 
    154 		translated->indexBuffer = streamingBuffer->getResource();
    155 		translated->indexOffset = streamOffset;
    156 	}
    157 
    158 	return GL_NO_ERROR;
    159 }
    160 
    161 std::size_t IndexDataManager::typeSize(GLenum type)
    162 {
    163 	switch(type)
    164 	{
    165 	case GL_UNSIGNED_INT:   return sizeof(GLuint);
    166 	case GL_UNSIGNED_SHORT: return sizeof(GLushort);
    167 	case GL_UNSIGNED_BYTE:  return sizeof(GLubyte);
    168 	default: UNREACHABLE(type); return sizeof(GLushort);
    169 	}
    170 }
    171 
    172 StreamingIndexBuffer::StreamingIndexBuffer(unsigned int initialSize) : mIndexBuffer(nullptr), mBufferSize(initialSize)
    173 {
    174 	if(initialSize > 0)
    175 	{
    176 		mIndexBuffer = new sw::Resource(initialSize + 16);
    177 
    178 		if(!mIndexBuffer)
    179 		{
    180 			ERR("Out of memory allocating an index buffer of size %u.", initialSize);
    181 		}
    182 	}
    183 
    184 	mWritePosition = 0;
    185 }
    186 
    187 StreamingIndexBuffer::~StreamingIndexBuffer()
    188 {
    189 	if(mIndexBuffer)
    190 	{
    191 		mIndexBuffer->destruct();
    192 	}
    193 }
    194 
    195 void *StreamingIndexBuffer::map(unsigned int requiredSpace, unsigned int *offset)
    196 {
    197 	void *mapPtr = nullptr;
    198 
    199 	if(mIndexBuffer)
    200 	{
    201 		mapPtr = (char*)mIndexBuffer->lock(sw::PUBLIC) + mWritePosition;
    202 
    203 		if(!mapPtr)
    204 		{
    205 			ERR(" Lock failed");
    206 			return nullptr;
    207 		}
    208 
    209 		*offset = mWritePosition;
    210 		mWritePosition += requiredSpace;
    211 	}
    212 
    213 	return mapPtr;
    214 }
    215 
    216 void StreamingIndexBuffer::unmap()
    217 {
    218 	if(mIndexBuffer)
    219 	{
    220 		mIndexBuffer->unlock();
    221 	}
    222 }
    223 
    224 void StreamingIndexBuffer::reserveSpace(unsigned int requiredSpace, GLenum type)
    225 {
    226 	if(requiredSpace > mBufferSize)
    227 	{
    228 		if(mIndexBuffer)
    229 		{
    230 			mIndexBuffer->destruct();
    231 			mIndexBuffer = 0;
    232 		}
    233 
    234 		mBufferSize = std::max(requiredSpace, 2 * mBufferSize);
    235 
    236 		mIndexBuffer = new sw::Resource(mBufferSize + 16);
    237 
    238 		if(!mIndexBuffer)
    239 		{
    240 			ERR("Out of memory allocating an index buffer of size %u.", mBufferSize);
    241 		}
    242 
    243 		mWritePosition = 0;
    244 	}
    245 	else if(mWritePosition + requiredSpace > mBufferSize)   // Recycle
    246 	{
    247 		if(mIndexBuffer)
    248 		{
    249 			mIndexBuffer->destruct();
    250 			mIndexBuffer = new sw::Resource(mBufferSize + 16);
    251 		}
    252 
    253 		mWritePosition = 0;
    254 	}
    255 }
    256 
    257 sw::Resource *StreamingIndexBuffer::getResource() const
    258 {
    259 	return mIndexBuffer;
    260 }
    261 
    262 }
    263