• 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 // 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 
IndexDataManager()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 
~IndexDataManager()44 IndexDataManager::~IndexDataManager()
45 {
46 	delete mStreamingBuffer;
47 }
48 
copyIndices(GLenum type,const void * input,GLsizei count,void * output)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>
computeRange(const IndexType * indices,GLsizei count,GLuint * minIndex,GLuint * maxIndex)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 
computeRange(GLenum type,const void * indices,GLsizei count,GLuint * minIndex,GLuint * maxIndex)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 
prepareIndexData(GLenum type,GLuint start,GLuint end,GLsizei count,Buffer * buffer,const void * indices,TranslatedIndexData * translated)96 GLenum IndexDataManager::prepareIndexData(GLenum type, GLuint start, GLuint end, 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 
105 	if(buffer != NULL)
106 	{
107 		if(typeSize(type) * count + offset > static_cast<std::size_t>(buffer->size()))
108 		{
109 			return GL_INVALID_OPERATION;
110 		}
111 
112 		indices = static_cast<const GLubyte*>(buffer->data()) + offset;
113 	}
114 
115 	StreamingIndexBuffer *streamingBuffer = mStreamingBuffer;
116 
117 	sw::Resource *staticBuffer = buffer ? buffer->getResource() : NULL;
118 
119 	if(staticBuffer)
120 	{
121 		computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
122 
123 		translated->indexBuffer = staticBuffer;
124 		translated->indexOffset = offset;
125 	}
126 	else
127 	{
128 		unsigned int streamOffset = 0;
129 		int convertCount = count;
130 
131 		streamingBuffer->reserveSpace(convertCount * typeSize(type), type);
132 		void *output = streamingBuffer->map(typeSize(type) * convertCount, &streamOffset);
133 
134 		if(output == NULL)
135 		{
136 			ERR("Failed to map index buffer.");
137 			return GL_OUT_OF_MEMORY;
138 		}
139 
140 		copyIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output);
141 		streamingBuffer->unmap();
142 
143 		computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
144 
145 		translated->indexBuffer = streamingBuffer->getResource();
146 		translated->indexOffset = streamOffset;
147 	}
148 
149 	if(translated->minIndex < start || translated->maxIndex > end)
150 	{
151 		ERR("glDrawRangeElements: out of range access. Range provided: [%d -> %d]. Range used: [%d -> %d].", start, end, translated->minIndex, translated->maxIndex);
152 	}
153 
154 	return GL_NO_ERROR;
155 }
156 
typeSize(GLenum type)157 std::size_t IndexDataManager::typeSize(GLenum type)
158 {
159 	switch(type)
160 	{
161 	case GL_UNSIGNED_INT:   return sizeof(GLuint);
162 	case GL_UNSIGNED_SHORT: return sizeof(GLushort);
163 	case GL_UNSIGNED_BYTE:  return sizeof(GLubyte);
164 	default: UNREACHABLE(type); return sizeof(GLushort);
165 	}
166 }
167 
StreamingIndexBuffer(unsigned int initialSize)168 StreamingIndexBuffer::StreamingIndexBuffer(unsigned int initialSize) : mIndexBuffer(NULL), mBufferSize(initialSize)
169 {
170 	if(initialSize > 0)
171 	{
172 		mIndexBuffer = new sw::Resource(initialSize + 16);
173 
174 		if(!mIndexBuffer)
175 		{
176 			ERR("Out of memory allocating an index buffer of size %u.", initialSize);
177 		}
178 	}
179 
180 	mWritePosition = 0;
181 }
182 
~StreamingIndexBuffer()183 StreamingIndexBuffer::~StreamingIndexBuffer()
184 {
185 	if(mIndexBuffer)
186 	{
187 		mIndexBuffer->destruct();
188 	}
189 }
190 
map(unsigned int requiredSpace,unsigned int * offset)191 void *StreamingIndexBuffer::map(unsigned int requiredSpace, unsigned int *offset)
192 {
193 	void *mapPtr = NULL;
194 
195 	if(mIndexBuffer)
196 	{
197 		mapPtr = (char*)mIndexBuffer->lock(sw::PUBLIC) + mWritePosition;
198 
199 		if(!mapPtr)
200 		{
201 			ERR(" Lock failed");
202 			return NULL;
203 		}
204 
205 		*offset = mWritePosition;
206 		mWritePosition += requiredSpace;
207 	}
208 
209 	return mapPtr;
210 }
211 
unmap()212 void StreamingIndexBuffer::unmap()
213 {
214 	if(mIndexBuffer)
215 	{
216 		mIndexBuffer->unlock();
217 	}
218 }
219 
reserveSpace(unsigned int requiredSpace,GLenum type)220 void StreamingIndexBuffer::reserveSpace(unsigned int requiredSpace, GLenum type)
221 {
222 	if(requiredSpace > mBufferSize)
223 	{
224 		if(mIndexBuffer)
225 		{
226 			mIndexBuffer->destruct();
227 			mIndexBuffer = 0;
228 		}
229 
230 		mBufferSize = std::max(requiredSpace, 2 * mBufferSize);
231 
232 		mIndexBuffer = new sw::Resource(mBufferSize + 16);
233 
234 		if(!mIndexBuffer)
235 		{
236 			ERR("Out of memory allocating an index buffer of size %u.", mBufferSize);
237 		}
238 
239 		mWritePosition = 0;
240 	}
241 	else if(mWritePosition + requiredSpace > mBufferSize)   // Recycle
242 	{
243 		if(mIndexBuffer)
244 		{
245 			mIndexBuffer->destruct();
246 			mIndexBuffer = new sw::Resource(mBufferSize + 16);
247 		}
248 
249 		mWritePosition = 0;
250 	}
251 }
252 
getResource() const253 sw::Resource *StreamingIndexBuffer::getResource() const
254 {
255 	return mIndexBuffer;
256 }
257 
258 }
259