• 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 gl
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,GLsizei count,Buffer * buffer,const void * indices,TranslatedIndexData * translated)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 
typeSize(GLenum type)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 
StreamingIndexBuffer(unsigned int initialSize)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 
~StreamingIndexBuffer()187 StreamingIndexBuffer::~StreamingIndexBuffer()
188 {
189 	if(mIndexBuffer)
190 	{
191 		mIndexBuffer->destruct();
192 	}
193 }
194 
map(unsigned int requiredSpace,unsigned int * offset)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 
unmap()216 void StreamingIndexBuffer::unmap()
217 {
218 	if(mIndexBuffer)
219 	{
220 		mIndexBuffer->unlock();
221 	}
222 }
223 
reserveSpace(unsigned int requiredSpace,GLenum type)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 
getResource() const257 sw::Resource *StreamingIndexBuffer::getResource() const
258 {
259 	return mIndexBuffer;
260 }
261 
262 }
263