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