blob: 76635a0665045f40ecdac6a7c8b61f75cb4e98f4 [file] [log] [blame]
Geoff Langf9a6f082015-01-22 13:32:49 -05001//
2// Copyright 2015 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// VertexArrayGL.cpp: Implements the class methods for VertexArrayGL.
8
9#include "libANGLE/renderer/gl/VertexArrayGL.h"
10
11#include "common/debug.h"
Geoff Lang7c82bc42015-03-09 16:18:08 -040012#include "common/mathutil.h"
Geoff Lang6ae6efc2015-03-09 14:42:35 -040013#include "libANGLE/Buffer.h"
Geoff Langba4c4a82015-02-24 12:38:46 -050014#include "libANGLE/angletypes.h"
Geoff Lang7c82bc42015-03-09 16:18:08 -040015#include "libANGLE/formatutils.h"
Geoff Langba4c4a82015-02-24 12:38:46 -050016#include "libANGLE/renderer/gl/BufferGL.h"
17#include "libANGLE/renderer/gl/FunctionsGL.h"
18#include "libANGLE/renderer/gl/StateManagerGL.h"
Geoff Langf9a6f082015-01-22 13:32:49 -050019
20namespace rx
21{
22
Geoff Langba4c4a82015-02-24 12:38:46 -050023VertexArrayGL::VertexArrayGL(const FunctionsGL *functions, StateManagerGL *stateManager)
24 : VertexArrayImpl(),
25 mFunctions(functions),
26 mStateManager(stateManager),
27 mVertexArrayID(0),
Geoff Lang6ae6efc2015-03-09 14:42:35 -040028 mElementArrayBuffer(),
29 mAttributes(),
Geoff Langba4c4a82015-02-24 12:38:46 -050030 mAppliedElementArrayBuffer(0),
Geoff Lang7c82bc42015-03-09 16:18:08 -040031 mAppliedAttributes(),
32 mStreamingElementArrayBufferSize(0),
33 mStreamingElementArrayBuffer(0),
34 mStreamingArrayBufferSize(0),
35 mStreamingArrayBuffer(0)
Geoff Langba4c4a82015-02-24 12:38:46 -050036{
37 ASSERT(mFunctions);
38 ASSERT(mStateManager);
39 mFunctions->genVertexArrays(1, &mVertexArrayID);
40
41 // Set the cached vertex attribute array size
42 GLint maxVertexAttribs;
43 mFunctions->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
Geoff Lang6ae6efc2015-03-09 14:42:35 -040044 mAttributes.resize(maxVertexAttribs);
Geoff Langba4c4a82015-02-24 12:38:46 -050045 mAppliedAttributes.resize(maxVertexAttribs);
46}
Geoff Langf9a6f082015-01-22 13:32:49 -050047
48VertexArrayGL::~VertexArrayGL()
Geoff Langba4c4a82015-02-24 12:38:46 -050049{
50 if (mVertexArrayID != 0)
51 {
52 mFunctions->deleteVertexArrays(1, &mVertexArrayID);
53 mVertexArrayID = 0;
54 }
55
Geoff Lang7c82bc42015-03-09 16:18:08 -040056 if (mStreamingElementArrayBuffer != 0)
57 {
58 mFunctions->deleteBuffers(1, &mStreamingElementArrayBuffer);
59 mStreamingElementArrayBufferSize = 0;
60 mStreamingElementArrayBuffer = 0;
61 }
62
63 if (mStreamingArrayBuffer != 0)
64 {
65 mFunctions->deleteBuffers(1, &mStreamingArrayBuffer);
66 mStreamingArrayBufferSize = 0;
67 mStreamingArrayBuffer = 0;
68 }
69
Geoff Lang6ae6efc2015-03-09 14:42:35 -040070 mElementArrayBuffer.set(nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -040071 for (size_t idx = 0; idx < mAttributes.size(); idx++)
72 {
73 mAttributes[idx].buffer.set(NULL);
74 }
75
Geoff Langba4c4a82015-02-24 12:38:46 -050076 for (size_t idx = 0; idx < mAppliedAttributes.size(); idx++)
77 {
78 mAppliedAttributes[idx].buffer.set(NULL);
79 }
80}
Geoff Langf9a6f082015-01-22 13:32:49 -050081
82void VertexArrayGL::setElementArrayBuffer(const gl::Buffer *buffer)
83{
Geoff Lang6ae6efc2015-03-09 14:42:35 -040084 mElementArrayBuffer.set(buffer);
85}
86
87void VertexArrayGL::setAttribute(size_t idx, const gl::VertexAttribute &attr)
88{
89 mAttributes[idx] = attr;
90}
91
92void VertexArrayGL::setAttributeDivisor(size_t idx, GLuint divisor)
93{
94 mAttributes[idx].divisor = divisor;
95}
96
97void VertexArrayGL::enableAttribute(size_t idx, bool enabledState)
98{
99 mAttributes[idx].enabled = enabledState;
100}
101
Geoff Lang7c82bc42015-03-09 16:18:08 -0400102gl::Error VertexArrayGL::syncDrawArraysState(GLint first, GLsizei count) const
103{
104 return syncDrawState(first, count, GL_NONE, nullptr, nullptr);
105}
106
107gl::Error VertexArrayGL::syncDrawElementsState(GLsizei count, GLenum type, const GLvoid *indices, const GLvoid **outIndices) const
108{
109 return syncDrawState(0, count, type, indices, outIndices);
110}
111
112gl::Error VertexArrayGL::syncDrawState(GLint first, GLsizei count, GLenum type, const GLvoid *indices, const GLvoid **outIndices) const
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400113{
114 mStateManager->bindVertexArray(mVertexArrayID);
115
Geoff Lang7c82bc42015-03-09 16:18:08 -0400116 // Check if any attributes need to be streamed, determines if the index range needs to be computed
117 bool attributesNeedStreaming = doAttributesNeedStreaming();
118
119 // Determine if an index buffer needs to be streamed and the range of vertices that need to be copied
120 RangeUI indexRange(0, 0);
121 if (type != GL_NONE)
Geoff Langba4c4a82015-02-24 12:38:46 -0500122 {
Geoff Lang7c82bc42015-03-09 16:18:08 -0400123 gl::Error error = syncIndexData(count, type, indices, attributesNeedStreaming, &indexRange, outIndices);
124 if (error.isError())
125 {
126 return error;
127 }
128 }
129 else
130 {
131 // Not an indexed call, set the range to [first, first + count)
132 indexRange.start = first;
133 indexRange.end = first + count;
Geoff Langba4c4a82015-02-24 12:38:46 -0500134 }
135
Geoff Lang7c82bc42015-03-09 16:18:08 -0400136 // Sync the vertex attribute state and track what data needs to be streamed
137 size_t streamingDataSize = 0;
138 size_t maxAttributeDataSize = 0;
139 gl::Error error = syncAttributeState(attributesNeedStreaming, indexRange, &streamingDataSize, &maxAttributeDataSize);
140 if (error.isError())
Geoff Langba4c4a82015-02-24 12:38:46 -0500141 {
Geoff Lang7c82bc42015-03-09 16:18:08 -0400142 return error;
Geoff Langba4c4a82015-02-24 12:38:46 -0500143 }
Geoff Langf9a6f082015-01-22 13:32:49 -0500144
Geoff Lang7c82bc42015-03-09 16:18:08 -0400145 if (streamingDataSize > 0)
146 {
147 ASSERT(attributesNeedStreaming);
148
149 gl::Error error = streamAttributes(streamingDataSize, maxAttributeDataSize, indexRange);
150 if (error.isError())
151 {
152 return error;
153 }
154 }
155
156 return gl::Error(GL_NO_ERROR);
157}
158
159bool VertexArrayGL::doAttributesNeedStreaming() const
160{
161 // TODO: if GLES, nothing needs to be streamed
162 for (size_t idx = 0; idx < mAttributes.size(); idx++)
163 {
164 if (mAttributes[idx].enabled && mAttributes[idx].buffer.get() == nullptr)
165 {
166 return true;
167 }
168 }
169
170 return false;
171}
172
173gl::Error VertexArrayGL::syncAttributeState(bool attributesNeedStreaming, const RangeUI &indexRange,
174 size_t *outStreamingDataSize, size_t *outMaxAttributeDataSize) const
175{
176 *outStreamingDataSize = 0;
177 *outMaxAttributeDataSize = 0;
178
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400179 for (size_t idx = 0; idx < mAttributes.size(); idx++)
Geoff Langba4c4a82015-02-24 12:38:46 -0500180 {
Geoff Lang7c82bc42015-03-09 16:18:08 -0400181 // Always sync the enabled and divisor state, they are required for both streaming and buffered
182 // attributes
183 if (mAppliedAttributes[idx].enabled != mAttributes[idx].enabled)
Geoff Langba4c4a82015-02-24 12:38:46 -0500184 {
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400185 if (mAttributes[idx].enabled)
186 {
187 mFunctions->enableVertexAttribArray(idx);
188 }
189 else
190 {
191 mFunctions->disableVertexAttribArray(idx);
192 }
Geoff Lang7c82bc42015-03-09 16:18:08 -0400193 mAppliedAttributes[idx].enabled = mAttributes[idx].enabled;
194 }
195 if (mAppliedAttributes[idx].divisor != mAttributes[idx].divisor)
196 {
197 mFunctions->vertexAttribDivisor(idx, mAttributes[idx].divisor);
198 mAppliedAttributes[idx].divisor = mAttributes[idx].divisor;
199 }
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400200
Geoff Lang7c82bc42015-03-09 16:18:08 -0400201 if (mAttributes[idx].enabled && mAttributes[idx].buffer.get() == nullptr)
202 {
203 ASSERT(attributesNeedStreaming);
204
205 const size_t streamedVertexCount = indexRange.end - indexRange.start + 1;
206
207 // If streaming is going to be required, compute the size of the required buffer
208 // and how much slack space at the beginning of the buffer will be required by determining
209 // the attribute with the largest data size.
210 size_t typeSize = ComputeVertexAttributeTypeSize(mAttributes[idx]);
211 *outStreamingDataSize += typeSize * streamedVertexCount;
212 *outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
213 }
214 else
215 {
216 // Sync the attribute with no translation
217 if (mAppliedAttributes[idx] != mAttributes[idx])
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400218 {
Geoff Lang7c82bc42015-03-09 16:18:08 -0400219 const gl::Buffer *arrayBuffer = mAttributes[idx].buffer.get();
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400220 const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
221 mStateManager->bindBuffer(GL_ARRAY_BUFFER, arrayBufferGL->getBufferID());
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400222
Geoff Lang7c82bc42015-03-09 16:18:08 -0400223 if (mAttributes[idx].pureInteger)
224 {
225 mFunctions->vertexAttribIPointer(idx, mAttributes[idx].size, mAttributes[idx].type,
226 mAttributes[idx].stride, mAttributes[idx].pointer);
227 }
228 else
229 {
230 mFunctions->vertexAttribPointer(idx, mAttributes[idx].size, mAttributes[idx].type,
231 mAttributes[idx].normalized, mAttributes[idx].stride,
232 mAttributes[idx].pointer);
233 }
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400234
Geoff Lang7c82bc42015-03-09 16:18:08 -0400235 mAppliedAttributes[idx] = mAttributes[idx];
236 }
Geoff Langba4c4a82015-02-24 12:38:46 -0500237 }
Geoff Langba4c4a82015-02-24 12:38:46 -0500238 }
Geoff Lang7c82bc42015-03-09 16:18:08 -0400239
240 return gl::Error(GL_NO_ERROR);
241}
242
243gl::Error VertexArrayGL::syncIndexData(GLsizei count, GLenum type, const GLvoid *indices, bool attributesNeedStreaming,
244 RangeUI *outIndexRange, const GLvoid **outIndices) const
245{
246 ASSERT(outIndices);
247
248 // Need to check the range of indices if attributes need to be streamed
249 if (mElementArrayBuffer.get() != nullptr)
250 {
251 const BufferGL *bufferGL = GetImplAs<BufferGL>(mElementArrayBuffer.get());
252 GLuint elementArrayBufferID = bufferGL->getBufferID();
253 if (elementArrayBufferID != mAppliedElementArrayBuffer)
254 {
255 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementArrayBufferID);
256 mAppliedElementArrayBuffer = elementArrayBufferID;
257 }
258
259 // Only compute the index range if the attributes also need to be streamed
260 if (attributesNeedStreaming)
261 {
262 ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices);
263
264 // Find the index range in the buffer
265 const IndexRangeCache *rangeCache = mElementArrayBuffer.get()->getIndexRangeCache();
266
Minmin Gong794e0002015-04-07 18:31:54 -0700267 if (!rangeCache->findRange(type, static_cast<unsigned int>(elementArrayBufferOffset), count, outIndexRange))
Geoff Lang7c82bc42015-03-09 16:18:08 -0400268 {
269 // Need to compute the index range.
270 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementArrayBufferID);
271 uint8_t *elementArrayBufferPointer = reinterpret_cast<uint8_t*>(mFunctions->mapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY));
272
273 *outIndexRange = IndexRangeCache::ComputeRange(type, elementArrayBufferPointer + elementArrayBufferOffset, count);
274
275 // TODO: Store the range cache at the impl level since the gl::Buffer object is supposed to remain constant
Minmin Gong794e0002015-04-07 18:31:54 -0700276 const_cast<IndexRangeCache*>(rangeCache)->addRange(type, static_cast<unsigned int>(elementArrayBufferOffset), count, *outIndexRange);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400277
278 if (!mFunctions->unmapBuffer(GL_ELEMENT_ARRAY_BUFFER))
279 {
280 return gl::Error(GL_OUT_OF_MEMORY);
281 }
282 }
283 }
284
285 // Indices serves as an offset into the index buffer in this case, use the same value for the draw call
286 *outIndices = indices;
287 }
288 else
289 {
290 // Need to stream the index buffer
291 // TODO: if GLES, nothing needs to be streamed
292
293 // Only compute the index range if the attributes also need to be streamed
294 if (attributesNeedStreaming)
295 {
296 *outIndexRange = IndexRangeCache::ComputeRange(type, indices, count);
297 }
298
299 // Allocate the streaming element array buffer
300 if (mStreamingElementArrayBuffer == 0)
301 {
302 mFunctions->genBuffers(1, &mStreamingElementArrayBuffer);
303 mStreamingElementArrayBufferSize = 0;
304 }
305
306 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, mStreamingElementArrayBuffer);
307 mAppliedElementArrayBuffer = mStreamingElementArrayBuffer;
308
309 // Make sure the element array buffer is large enough
310 const gl::Type &indexTypeInfo = gl::GetTypeInfo(type);
311 size_t requiredStreamingBufferSize = indexTypeInfo.bytes * count;
312 if (requiredStreamingBufferSize > mStreamingElementArrayBufferSize)
313 {
314 // Copy the indices in while resizing the buffer
315 mFunctions->bufferData(GL_ELEMENT_ARRAY_BUFFER, requiredStreamingBufferSize, indices, GL_DYNAMIC_DRAW);
316 mStreamingElementArrayBufferSize = requiredStreamingBufferSize;
317 }
318 else
319 {
320 // Put the indices at the beginning of the buffer
321 mFunctions->bufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, requiredStreamingBufferSize, indices);
322 }
323
324 // Set the index offset for the draw call to zero since the supplied index pointer is to client data
325 *outIndices = nullptr;
326 }
327
328 return gl::Error(GL_NO_ERROR);
329}
330
331gl::Error VertexArrayGL::streamAttributes(size_t streamingDataSize, size_t maxAttributeDataSize, const RangeUI &indexRange) const
332{
333 if (mStreamingArrayBuffer == 0)
334 {
335 mFunctions->genBuffers(1, &mStreamingArrayBuffer);
336 mStreamingArrayBufferSize = 0;
337 }
338
339 // If first is greater than zero, a slack space needs to be left at the beginning of the buffer so that
340 // the same 'first' argument can be passed into the draw call.
341 const size_t bufferEmptySpace = maxAttributeDataSize * indexRange.start;
342 const size_t requiredBufferSize = streamingDataSize + bufferEmptySpace;
343
344 mStateManager->bindBuffer(GL_ARRAY_BUFFER, mStreamingArrayBuffer);
345 if (requiredBufferSize > mStreamingArrayBufferSize)
346 {
347 mFunctions->bufferData(GL_ARRAY_BUFFER, requiredBufferSize, nullptr, GL_DYNAMIC_DRAW);
348 mStreamingArrayBufferSize = requiredBufferSize;
349 }
350
351 // Unmapping a buffer can return GL_FALSE to indicate that the system has corrupted the data
352 // somehow (such as by a screen change), retry writing the data a few times and return OUT_OF_MEMORY
353 // if that fails.
354 GLboolean unmapResult = GL_FALSE;
355 size_t unmapRetryAttempts = 5;
356 while (unmapResult != GL_TRUE && --unmapRetryAttempts > 0)
357 {
358 uint8_t *bufferPointer = reinterpret_cast<uint8_t*>(mFunctions->mapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
359 size_t curBufferOffset = bufferEmptySpace;
360
361 const size_t streamedVertexCount = indexRange.end - indexRange.start + 1;
362
363 for (size_t idx = 0; idx < mAttributes.size(); idx++)
364 {
365 if (mAttributes[idx].enabled && mAttributes[idx].buffer.get() == nullptr)
366 {
367 const size_t sourceStride = ComputeVertexAttributeStride(mAttributes[idx]);
368 const size_t destStride = ComputeVertexAttributeTypeSize(mAttributes[idx]);
369
370 const uint8_t *inputPointer = reinterpret_cast<const uint8_t*>(mAttributes[idx].pointer);
371
372 // Pack the data when copying it, user could have supplied a very large stride that would
373 // cause the buffer to be much larger than needed.
374 if (destStride == sourceStride)
375 {
376 // Can copy in one go, the data is packed
377 memcpy(bufferPointer + curBufferOffset,
378 inputPointer + (sourceStride * indexRange.start),
379 destStride * streamedVertexCount);
380 }
381 else
382 {
383 // Copy each vertex individually
384 for (size_t vertexIdx = indexRange.start; vertexIdx <= indexRange.end; vertexIdx++)
385 {
386 memcpy(bufferPointer + curBufferOffset + (destStride * vertexIdx),
387 inputPointer + (sourceStride * vertexIdx),
388 destStride);
389 }
390 }
391
392 // Compute where the 0-index vertex would be.
393 const size_t vertexStartOffset = curBufferOffset - (indexRange.start * destStride);
394
395 mFunctions->vertexAttribPointer(idx, mAttributes[idx].size, mAttributes[idx].type,
396 mAttributes[idx].normalized, destStride,
397 reinterpret_cast<const GLvoid*>(vertexStartOffset));
398
399 curBufferOffset += destStride * streamedVertexCount;
400
401 // Mark the applied attribute as dirty by setting an invalid size so that if it doesn't
402 // need to be streamed later, there is no chance that the caching will skip it.
403 mAppliedAttributes[idx].size = static_cast<GLuint>(-1);
404 }
405 }
406
407 unmapResult = mFunctions->unmapBuffer(GL_ARRAY_BUFFER);
408 }
409
410 if (unmapResult != GL_TRUE)
411 {
412 return gl::Error(GL_OUT_OF_MEMORY, "Failed to unmap the client data streaming buffer.");
413 }
414
415 return gl::Error(GL_NO_ERROR);
Geoff Langba4c4a82015-02-24 12:38:46 -0500416}
417
418GLuint VertexArrayGL::getVertexArrayID() const
419{
420 return mVertexArrayID;
Geoff Langf9a6f082015-01-22 13:32:49 -0500421}
422
423}