blob: ba5521c2615832981998aca1fdadbdb5a93794ca [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 Lang831b1952015-05-05 11:02:27 -040013#include "common/utilities.h"
Geoff Lang6ae6efc2015-03-09 14:42:35 -040014#include "libANGLE/Buffer.h"
Geoff Langba4c4a82015-02-24 12:38:46 -050015#include "libANGLE/angletypes.h"
Geoff Lang7c82bc42015-03-09 16:18:08 -040016#include "libANGLE/formatutils.h"
Geoff Langba4c4a82015-02-24 12:38:46 -050017#include "libANGLE/renderer/gl/BufferGL.h"
18#include "libANGLE/renderer/gl/FunctionsGL.h"
19#include "libANGLE/renderer/gl/StateManagerGL.h"
Geoff Langf9a6f082015-01-22 13:32:49 -050020
21namespace rx
22{
23
Geoff Langba4c4a82015-02-24 12:38:46 -050024VertexArrayGL::VertexArrayGL(const FunctionsGL *functions, StateManagerGL *stateManager)
25 : VertexArrayImpl(),
26 mFunctions(functions),
27 mStateManager(stateManager),
28 mVertexArrayID(0),
Geoff Lang6ae6efc2015-03-09 14:42:35 -040029 mElementArrayBuffer(),
30 mAttributes(),
Geoff Langba4c4a82015-02-24 12:38:46 -050031 mAppliedElementArrayBuffer(0),
Geoff Lang7c82bc42015-03-09 16:18:08 -040032 mAppliedAttributes(),
33 mStreamingElementArrayBufferSize(0),
34 mStreamingElementArrayBuffer(0),
35 mStreamingArrayBufferSize(0),
36 mStreamingArrayBuffer(0)
Geoff Langba4c4a82015-02-24 12:38:46 -050037{
38 ASSERT(mFunctions);
39 ASSERT(mStateManager);
40 mFunctions->genVertexArrays(1, &mVertexArrayID);
41
42 // Set the cached vertex attribute array size
43 GLint maxVertexAttribs;
44 mFunctions->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
Geoff Lang6ae6efc2015-03-09 14:42:35 -040045 mAttributes.resize(maxVertexAttribs);
Geoff Langba4c4a82015-02-24 12:38:46 -050046 mAppliedAttributes.resize(maxVertexAttribs);
47}
Geoff Langf9a6f082015-01-22 13:32:49 -050048
49VertexArrayGL::~VertexArrayGL()
Geoff Langba4c4a82015-02-24 12:38:46 -050050{
Geoff Lang1eb708e2015-05-04 14:58:23 -040051 mStateManager->deleteVertexArray(mVertexArrayID);
52 mVertexArrayID = 0;
Geoff Langba4c4a82015-02-24 12:38:46 -050053
Geoff Lang1eb708e2015-05-04 14:58:23 -040054 mStateManager->deleteBuffer(mStreamingElementArrayBuffer);
55 mStreamingElementArrayBufferSize = 0;
56 mStreamingElementArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040057
Geoff Lang1eb708e2015-05-04 14:58:23 -040058 mStateManager->deleteBuffer(mStreamingArrayBuffer);
59 mStreamingArrayBufferSize = 0;
60 mStreamingArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040061
Geoff Lang6ae6efc2015-03-09 14:42:35 -040062 mElementArrayBuffer.set(nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -040063 for (size_t idx = 0; idx < mAttributes.size(); idx++)
64 {
65 mAttributes[idx].buffer.set(NULL);
66 }
67
Geoff Langba4c4a82015-02-24 12:38:46 -050068 for (size_t idx = 0; idx < mAppliedAttributes.size(); idx++)
69 {
70 mAppliedAttributes[idx].buffer.set(NULL);
71 }
72}
Geoff Langf9a6f082015-01-22 13:32:49 -050073
74void VertexArrayGL::setElementArrayBuffer(const gl::Buffer *buffer)
75{
Geoff Lang6ae6efc2015-03-09 14:42:35 -040076 mElementArrayBuffer.set(buffer);
Geoff Langee09b582015-06-16 15:13:52 -070077
78 // If the buffer is being unbound/deleted, reset the currently applied buffer ID
79 // so that even if a new buffer is generated with the same ID, it will be re-bound.
80 if (buffer == nullptr && mAppliedElementArrayBuffer != mStreamingElementArrayBuffer)
81 {
82 mAppliedElementArrayBuffer = 0;
83 }
Geoff Lang6ae6efc2015-03-09 14:42:35 -040084}
85
86void VertexArrayGL::setAttribute(size_t idx, const gl::VertexAttribute &attr)
87{
88 mAttributes[idx] = attr;
89}
90
91void VertexArrayGL::setAttributeDivisor(size_t idx, GLuint divisor)
92{
93 mAttributes[idx].divisor = divisor;
94}
95
96void VertexArrayGL::enableAttribute(size_t idx, bool enabledState)
97{
98 mAttributes[idx].enabled = enabledState;
99}
100
Geoff Lang7c82bc42015-03-09 16:18:08 -0400101gl::Error VertexArrayGL::syncDrawArraysState(GLint first, GLsizei count) const
102{
103 return syncDrawState(first, count, GL_NONE, nullptr, nullptr);
104}
105
106gl::Error VertexArrayGL::syncDrawElementsState(GLsizei count, GLenum type, const GLvoid *indices, const GLvoid **outIndices) const
107{
108 return syncDrawState(0, count, type, indices, outIndices);
109}
110
111gl::Error VertexArrayGL::syncDrawState(GLint first, GLsizei count, GLenum type, const GLvoid *indices, const GLvoid **outIndices) const
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400112{
Geoff Lang294cad92015-05-26 15:11:23 -0400113 mStateManager->bindVertexArray(mVertexArrayID, mAppliedElementArrayBuffer);
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400114
Geoff Lang7c82bc42015-03-09 16:18:08 -0400115 // Check if any attributes need to be streamed, determines if the index range needs to be computed
116 bool attributesNeedStreaming = doAttributesNeedStreaming();
117
118 // Determine if an index buffer needs to be streamed and the range of vertices that need to be copied
Geoff Lang831b1952015-05-05 11:02:27 -0400119 gl::RangeUI indexRange(0, 0);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400120 if (type != GL_NONE)
Geoff Langba4c4a82015-02-24 12:38:46 -0500121 {
Geoff Lang7c82bc42015-03-09 16:18:08 -0400122 gl::Error error = syncIndexData(count, type, indices, attributesNeedStreaming, &indexRange, outIndices);
123 if (error.isError())
124 {
125 return error;
126 }
127 }
128 else
129 {
130 // Not an indexed call, set the range to [first, first + count)
131 indexRange.start = first;
132 indexRange.end = first + count;
Geoff Langba4c4a82015-02-24 12:38:46 -0500133 }
134
Geoff Lang7c82bc42015-03-09 16:18:08 -0400135 // Sync the vertex attribute state and track what data needs to be streamed
136 size_t streamingDataSize = 0;
137 size_t maxAttributeDataSize = 0;
138 gl::Error error = syncAttributeState(attributesNeedStreaming, indexRange, &streamingDataSize, &maxAttributeDataSize);
139 if (error.isError())
Geoff Langba4c4a82015-02-24 12:38:46 -0500140 {
Geoff Lang7c82bc42015-03-09 16:18:08 -0400141 return error;
Geoff Langba4c4a82015-02-24 12:38:46 -0500142 }
Geoff Langf9a6f082015-01-22 13:32:49 -0500143
Geoff Lang7c82bc42015-03-09 16:18:08 -0400144 if (streamingDataSize > 0)
145 {
146 ASSERT(attributesNeedStreaming);
147
148 gl::Error error = streamAttributes(streamingDataSize, maxAttributeDataSize, indexRange);
149 if (error.isError())
150 {
151 return error;
152 }
153 }
154
155 return gl::Error(GL_NO_ERROR);
156}
157
158bool VertexArrayGL::doAttributesNeedStreaming() const
159{
160 // TODO: if GLES, nothing needs to be streamed
161 for (size_t idx = 0; idx < mAttributes.size(); idx++)
162 {
163 if (mAttributes[idx].enabled && mAttributes[idx].buffer.get() == nullptr)
164 {
165 return true;
166 }
167 }
168
169 return false;
170}
171
Geoff Lang831b1952015-05-05 11:02:27 -0400172gl::Error VertexArrayGL::syncAttributeState(bool attributesNeedStreaming, const gl::RangeUI &indexRange,
Geoff Lang7c82bc42015-03-09 16:18:08 -0400173 size_t *outStreamingDataSize, size_t *outMaxAttributeDataSize) const
174{
175 *outStreamingDataSize = 0;
176 *outMaxAttributeDataSize = 0;
177
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400178 for (size_t idx = 0; idx < mAttributes.size(); idx++)
Geoff Langba4c4a82015-02-24 12:38:46 -0500179 {
Geoff Lang7c82bc42015-03-09 16:18:08 -0400180 // Always sync the enabled and divisor state, they are required for both streaming and buffered
181 // attributes
182 if (mAppliedAttributes[idx].enabled != mAttributes[idx].enabled)
Geoff Langba4c4a82015-02-24 12:38:46 -0500183 {
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400184 if (mAttributes[idx].enabled)
185 {
186 mFunctions->enableVertexAttribArray(idx);
187 }
188 else
189 {
190 mFunctions->disableVertexAttribArray(idx);
191 }
Geoff Lang7c82bc42015-03-09 16:18:08 -0400192 mAppliedAttributes[idx].enabled = mAttributes[idx].enabled;
193 }
194 if (mAppliedAttributes[idx].divisor != mAttributes[idx].divisor)
195 {
196 mFunctions->vertexAttribDivisor(idx, mAttributes[idx].divisor);
197 mAppliedAttributes[idx].divisor = mAttributes[idx].divisor;
198 }
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400199
Geoff Lang7c82bc42015-03-09 16:18:08 -0400200 if (mAttributes[idx].enabled && mAttributes[idx].buffer.get() == nullptr)
201 {
202 ASSERT(attributesNeedStreaming);
203
204 const size_t streamedVertexCount = indexRange.end - indexRange.start + 1;
205
206 // If streaming is going to be required, compute the size of the required buffer
207 // and how much slack space at the beginning of the buffer will be required by determining
208 // the attribute with the largest data size.
209 size_t typeSize = ComputeVertexAttributeTypeSize(mAttributes[idx]);
210 *outStreamingDataSize += typeSize * streamedVertexCount;
211 *outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
212 }
213 else
214 {
215 // Sync the attribute with no translation
216 if (mAppliedAttributes[idx] != mAttributes[idx])
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400217 {
Geoff Lang7c82bc42015-03-09 16:18:08 -0400218 const gl::Buffer *arrayBuffer = mAttributes[idx].buffer.get();
Geoff Lang851cd582015-05-26 16:47:23 -0400219 if (arrayBuffer != nullptr)
220 {
221 const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
222 mStateManager->bindBuffer(GL_ARRAY_BUFFER, arrayBufferGL->getBufferID());
223 }
224 else
225 {
226 mStateManager->bindBuffer(GL_ARRAY_BUFFER, 0);
227 }
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400228
Geoff Lang7c82bc42015-03-09 16:18:08 -0400229 if (mAttributes[idx].pureInteger)
230 {
231 mFunctions->vertexAttribIPointer(idx, mAttributes[idx].size, mAttributes[idx].type,
232 mAttributes[idx].stride, mAttributes[idx].pointer);
233 }
234 else
235 {
236 mFunctions->vertexAttribPointer(idx, mAttributes[idx].size, mAttributes[idx].type,
237 mAttributes[idx].normalized, mAttributes[idx].stride,
238 mAttributes[idx].pointer);
239 }
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400240
Geoff Lang7c82bc42015-03-09 16:18:08 -0400241 mAppliedAttributes[idx] = mAttributes[idx];
242 }
Geoff Langba4c4a82015-02-24 12:38:46 -0500243 }
Geoff Langba4c4a82015-02-24 12:38:46 -0500244 }
Geoff Lang7c82bc42015-03-09 16:18:08 -0400245
246 return gl::Error(GL_NO_ERROR);
247}
248
249gl::Error VertexArrayGL::syncIndexData(GLsizei count, GLenum type, const GLvoid *indices, bool attributesNeedStreaming,
Geoff Lang831b1952015-05-05 11:02:27 -0400250 gl::RangeUI *outIndexRange, const GLvoid **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400251{
252 ASSERT(outIndices);
253
254 // Need to check the range of indices if attributes need to be streamed
255 if (mElementArrayBuffer.get() != nullptr)
256 {
257 const BufferGL *bufferGL = GetImplAs<BufferGL>(mElementArrayBuffer.get());
258 GLuint elementArrayBufferID = bufferGL->getBufferID();
259 if (elementArrayBufferID != mAppliedElementArrayBuffer)
260 {
261 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementArrayBufferID);
262 mAppliedElementArrayBuffer = elementArrayBufferID;
263 }
264
265 // Only compute the index range if the attributes also need to be streamed
266 if (attributesNeedStreaming)
267 {
268 ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices);
Geoff Lang520c4ae2015-05-05 13:12:36 -0400269 gl::Error error = mElementArrayBuffer->getIndexRange(type, static_cast<size_t>(elementArrayBufferOffset), count, outIndexRange);
270 if (error.isError())
Geoff Lang7c82bc42015-03-09 16:18:08 -0400271 {
Geoff Lang520c4ae2015-05-05 13:12:36 -0400272 return error;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400273 }
274 }
275
276 // Indices serves as an offset into the index buffer in this case, use the same value for the draw call
277 *outIndices = indices;
278 }
279 else
280 {
281 // Need to stream the index buffer
282 // TODO: if GLES, nothing needs to be streamed
283
284 // Only compute the index range if the attributes also need to be streamed
285 if (attributesNeedStreaming)
286 {
Geoff Lang831b1952015-05-05 11:02:27 -0400287 *outIndexRange = gl::ComputeIndexRange(type, indices, count);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400288 }
289
290 // Allocate the streaming element array buffer
291 if (mStreamingElementArrayBuffer == 0)
292 {
293 mFunctions->genBuffers(1, &mStreamingElementArrayBuffer);
294 mStreamingElementArrayBufferSize = 0;
295 }
296
297 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, mStreamingElementArrayBuffer);
298 mAppliedElementArrayBuffer = mStreamingElementArrayBuffer;
299
300 // Make sure the element array buffer is large enough
301 const gl::Type &indexTypeInfo = gl::GetTypeInfo(type);
302 size_t requiredStreamingBufferSize = indexTypeInfo.bytes * count;
303 if (requiredStreamingBufferSize > mStreamingElementArrayBufferSize)
304 {
305 // Copy the indices in while resizing the buffer
306 mFunctions->bufferData(GL_ELEMENT_ARRAY_BUFFER, requiredStreamingBufferSize, indices, GL_DYNAMIC_DRAW);
307 mStreamingElementArrayBufferSize = requiredStreamingBufferSize;
308 }
309 else
310 {
311 // Put the indices at the beginning of the buffer
312 mFunctions->bufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, requiredStreamingBufferSize, indices);
313 }
314
315 // Set the index offset for the draw call to zero since the supplied index pointer is to client data
316 *outIndices = nullptr;
317 }
318
319 return gl::Error(GL_NO_ERROR);
320}
321
Geoff Lang831b1952015-05-05 11:02:27 -0400322gl::Error VertexArrayGL::streamAttributes(size_t streamingDataSize, size_t maxAttributeDataSize, const gl::RangeUI &indexRange) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400323{
324 if (mStreamingArrayBuffer == 0)
325 {
326 mFunctions->genBuffers(1, &mStreamingArrayBuffer);
327 mStreamingArrayBufferSize = 0;
328 }
329
330 // If first is greater than zero, a slack space needs to be left at the beginning of the buffer so that
331 // the same 'first' argument can be passed into the draw call.
332 const size_t bufferEmptySpace = maxAttributeDataSize * indexRange.start;
333 const size_t requiredBufferSize = streamingDataSize + bufferEmptySpace;
334
335 mStateManager->bindBuffer(GL_ARRAY_BUFFER, mStreamingArrayBuffer);
336 if (requiredBufferSize > mStreamingArrayBufferSize)
337 {
338 mFunctions->bufferData(GL_ARRAY_BUFFER, requiredBufferSize, nullptr, GL_DYNAMIC_DRAW);
339 mStreamingArrayBufferSize = requiredBufferSize;
340 }
341
342 // Unmapping a buffer can return GL_FALSE to indicate that the system has corrupted the data
343 // somehow (such as by a screen change), retry writing the data a few times and return OUT_OF_MEMORY
344 // if that fails.
345 GLboolean unmapResult = GL_FALSE;
346 size_t unmapRetryAttempts = 5;
347 while (unmapResult != GL_TRUE && --unmapRetryAttempts > 0)
348 {
349 uint8_t *bufferPointer = reinterpret_cast<uint8_t*>(mFunctions->mapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
350 size_t curBufferOffset = bufferEmptySpace;
351
352 const size_t streamedVertexCount = indexRange.end - indexRange.start + 1;
353
354 for (size_t idx = 0; idx < mAttributes.size(); idx++)
355 {
356 if (mAttributes[idx].enabled && mAttributes[idx].buffer.get() == nullptr)
357 {
358 const size_t sourceStride = ComputeVertexAttributeStride(mAttributes[idx]);
359 const size_t destStride = ComputeVertexAttributeTypeSize(mAttributes[idx]);
360
361 const uint8_t *inputPointer = reinterpret_cast<const uint8_t*>(mAttributes[idx].pointer);
362
363 // Pack the data when copying it, user could have supplied a very large stride that would
364 // cause the buffer to be much larger than needed.
365 if (destStride == sourceStride)
366 {
367 // Can copy in one go, the data is packed
368 memcpy(bufferPointer + curBufferOffset,
369 inputPointer + (sourceStride * indexRange.start),
370 destStride * streamedVertexCount);
371 }
372 else
373 {
374 // Copy each vertex individually
375 for (size_t vertexIdx = indexRange.start; vertexIdx <= indexRange.end; vertexIdx++)
376 {
377 memcpy(bufferPointer + curBufferOffset + (destStride * vertexIdx),
378 inputPointer + (sourceStride * vertexIdx),
379 destStride);
380 }
381 }
382
383 // Compute where the 0-index vertex would be.
384 const size_t vertexStartOffset = curBufferOffset - (indexRange.start * destStride);
385
386 mFunctions->vertexAttribPointer(idx, mAttributes[idx].size, mAttributes[idx].type,
387 mAttributes[idx].normalized, destStride,
388 reinterpret_cast<const GLvoid*>(vertexStartOffset));
389
390 curBufferOffset += destStride * streamedVertexCount;
391
392 // Mark the applied attribute as dirty by setting an invalid size so that if it doesn't
393 // need to be streamed later, there is no chance that the caching will skip it.
394 mAppliedAttributes[idx].size = static_cast<GLuint>(-1);
395 }
396 }
397
398 unmapResult = mFunctions->unmapBuffer(GL_ARRAY_BUFFER);
399 }
400
401 if (unmapResult != GL_TRUE)
402 {
403 return gl::Error(GL_OUT_OF_MEMORY, "Failed to unmap the client data streaming buffer.");
404 }
405
406 return gl::Error(GL_NO_ERROR);
Geoff Langba4c4a82015-02-24 12:38:46 -0500407}
408
409GLuint VertexArrayGL::getVertexArrayID() const
410{
411 return mVertexArrayID;
Geoff Langf9a6f082015-01-22 13:32:49 -0500412}
413
Geoff Lang294cad92015-05-26 15:11:23 -0400414GLuint VertexArrayGL::getAppliedElementArrayBufferID() const
415{
416 return mAppliedElementArrayBuffer;
417}
418
Geoff Langf9a6f082015-01-22 13:32:49 -0500419}