blob: 2536b009d24f6d53aabf10650e6d4ae92bb998d1 [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{
51 if (mVertexArrayID != 0)
52 {
53 mFunctions->deleteVertexArrays(1, &mVertexArrayID);
54 mVertexArrayID = 0;
55 }
56
Geoff Lang7c82bc42015-03-09 16:18:08 -040057 if (mStreamingElementArrayBuffer != 0)
58 {
59 mFunctions->deleteBuffers(1, &mStreamingElementArrayBuffer);
60 mStreamingElementArrayBufferSize = 0;
61 mStreamingElementArrayBuffer = 0;
62 }
63
64 if (mStreamingArrayBuffer != 0)
65 {
66 mFunctions->deleteBuffers(1, &mStreamingArrayBuffer);
67 mStreamingArrayBufferSize = 0;
68 mStreamingArrayBuffer = 0;
69 }
70
Geoff Lang6ae6efc2015-03-09 14:42:35 -040071 mElementArrayBuffer.set(nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -040072 for (size_t idx = 0; idx < mAttributes.size(); idx++)
73 {
74 mAttributes[idx].buffer.set(NULL);
75 }
76
Geoff Langba4c4a82015-02-24 12:38:46 -050077 for (size_t idx = 0; idx < mAppliedAttributes.size(); idx++)
78 {
79 mAppliedAttributes[idx].buffer.set(NULL);
80 }
81}
Geoff Langf9a6f082015-01-22 13:32:49 -050082
83void VertexArrayGL::setElementArrayBuffer(const gl::Buffer *buffer)
84{
Geoff Lang6ae6efc2015-03-09 14:42:35 -040085 mElementArrayBuffer.set(buffer);
86}
87
88void VertexArrayGL::setAttribute(size_t idx, const gl::VertexAttribute &attr)
89{
90 mAttributes[idx] = attr;
91}
92
93void VertexArrayGL::setAttributeDivisor(size_t idx, GLuint divisor)
94{
95 mAttributes[idx].divisor = divisor;
96}
97
98void VertexArrayGL::enableAttribute(size_t idx, bool enabledState)
99{
100 mAttributes[idx].enabled = enabledState;
101}
102
Geoff Lang7c82bc42015-03-09 16:18:08 -0400103gl::Error VertexArrayGL::syncDrawArraysState(GLint first, GLsizei count) const
104{
105 return syncDrawState(first, count, GL_NONE, nullptr, nullptr);
106}
107
108gl::Error VertexArrayGL::syncDrawElementsState(GLsizei count, GLenum type, const GLvoid *indices, const GLvoid **outIndices) const
109{
110 return syncDrawState(0, count, type, indices, outIndices);
111}
112
113gl::Error VertexArrayGL::syncDrawState(GLint first, GLsizei count, GLenum type, const GLvoid *indices, const GLvoid **outIndices) const
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400114{
115 mStateManager->bindVertexArray(mVertexArrayID);
116
Geoff Lang7c82bc42015-03-09 16:18:08 -0400117 // Check if any attributes need to be streamed, determines if the index range needs to be computed
118 bool attributesNeedStreaming = doAttributesNeedStreaming();
119
120 // 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 -0400121 gl::RangeUI indexRange(0, 0);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400122 if (type != GL_NONE)
Geoff Langba4c4a82015-02-24 12:38:46 -0500123 {
Geoff Lang7c82bc42015-03-09 16:18:08 -0400124 gl::Error error = syncIndexData(count, type, indices, attributesNeedStreaming, &indexRange, outIndices);
125 if (error.isError())
126 {
127 return error;
128 }
129 }
130 else
131 {
132 // Not an indexed call, set the range to [first, first + count)
133 indexRange.start = first;
134 indexRange.end = first + count;
Geoff Langba4c4a82015-02-24 12:38:46 -0500135 }
136
Geoff Lang7c82bc42015-03-09 16:18:08 -0400137 // Sync the vertex attribute state and track what data needs to be streamed
138 size_t streamingDataSize = 0;
139 size_t maxAttributeDataSize = 0;
140 gl::Error error = syncAttributeState(attributesNeedStreaming, indexRange, &streamingDataSize, &maxAttributeDataSize);
141 if (error.isError())
Geoff Langba4c4a82015-02-24 12:38:46 -0500142 {
Geoff Lang7c82bc42015-03-09 16:18:08 -0400143 return error;
Geoff Langba4c4a82015-02-24 12:38:46 -0500144 }
Geoff Langf9a6f082015-01-22 13:32:49 -0500145
Geoff Lang7c82bc42015-03-09 16:18:08 -0400146 if (streamingDataSize > 0)
147 {
148 ASSERT(attributesNeedStreaming);
149
150 gl::Error error = streamAttributes(streamingDataSize, maxAttributeDataSize, indexRange);
151 if (error.isError())
152 {
153 return error;
154 }
155 }
156
157 return gl::Error(GL_NO_ERROR);
158}
159
160bool VertexArrayGL::doAttributesNeedStreaming() const
161{
162 // TODO: if GLES, nothing needs to be streamed
163 for (size_t idx = 0; idx < mAttributes.size(); idx++)
164 {
165 if (mAttributes[idx].enabled && mAttributes[idx].buffer.get() == nullptr)
166 {
167 return true;
168 }
169 }
170
171 return false;
172}
173
Geoff Lang831b1952015-05-05 11:02:27 -0400174gl::Error VertexArrayGL::syncAttributeState(bool attributesNeedStreaming, const gl::RangeUI &indexRange,
Geoff Lang7c82bc42015-03-09 16:18:08 -0400175 size_t *outStreamingDataSize, size_t *outMaxAttributeDataSize) const
176{
177 *outStreamingDataSize = 0;
178 *outMaxAttributeDataSize = 0;
179
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400180 for (size_t idx = 0; idx < mAttributes.size(); idx++)
Geoff Langba4c4a82015-02-24 12:38:46 -0500181 {
Geoff Lang7c82bc42015-03-09 16:18:08 -0400182 // Always sync the enabled and divisor state, they are required for both streaming and buffered
183 // attributes
184 if (mAppliedAttributes[idx].enabled != mAttributes[idx].enabled)
Geoff Langba4c4a82015-02-24 12:38:46 -0500185 {
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400186 if (mAttributes[idx].enabled)
187 {
188 mFunctions->enableVertexAttribArray(idx);
189 }
190 else
191 {
192 mFunctions->disableVertexAttribArray(idx);
193 }
Geoff Lang7c82bc42015-03-09 16:18:08 -0400194 mAppliedAttributes[idx].enabled = mAttributes[idx].enabled;
195 }
196 if (mAppliedAttributes[idx].divisor != mAttributes[idx].divisor)
197 {
198 mFunctions->vertexAttribDivisor(idx, mAttributes[idx].divisor);
199 mAppliedAttributes[idx].divisor = mAttributes[idx].divisor;
200 }
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400201
Geoff Lang7c82bc42015-03-09 16:18:08 -0400202 if (mAttributes[idx].enabled && mAttributes[idx].buffer.get() == nullptr)
203 {
204 ASSERT(attributesNeedStreaming);
205
206 const size_t streamedVertexCount = indexRange.end - indexRange.start + 1;
207
208 // If streaming is going to be required, compute the size of the required buffer
209 // and how much slack space at the beginning of the buffer will be required by determining
210 // the attribute with the largest data size.
211 size_t typeSize = ComputeVertexAttributeTypeSize(mAttributes[idx]);
212 *outStreamingDataSize += typeSize * streamedVertexCount;
213 *outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
214 }
215 else
216 {
217 // Sync the attribute with no translation
218 if (mAppliedAttributes[idx] != mAttributes[idx])
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400219 {
Geoff Lang7c82bc42015-03-09 16:18:08 -0400220 const gl::Buffer *arrayBuffer = mAttributes[idx].buffer.get();
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400221 const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
222 mStateManager->bindBuffer(GL_ARRAY_BUFFER, arrayBufferGL->getBufferID());
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400223
Geoff Lang7c82bc42015-03-09 16:18:08 -0400224 if (mAttributes[idx].pureInteger)
225 {
226 mFunctions->vertexAttribIPointer(idx, mAttributes[idx].size, mAttributes[idx].type,
227 mAttributes[idx].stride, mAttributes[idx].pointer);
228 }
229 else
230 {
231 mFunctions->vertexAttribPointer(idx, mAttributes[idx].size, mAttributes[idx].type,
232 mAttributes[idx].normalized, mAttributes[idx].stride,
233 mAttributes[idx].pointer);
234 }
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400235
Geoff Lang7c82bc42015-03-09 16:18:08 -0400236 mAppliedAttributes[idx] = mAttributes[idx];
237 }
Geoff Langba4c4a82015-02-24 12:38:46 -0500238 }
Geoff Langba4c4a82015-02-24 12:38:46 -0500239 }
Geoff Lang7c82bc42015-03-09 16:18:08 -0400240
241 return gl::Error(GL_NO_ERROR);
242}
243
244gl::Error VertexArrayGL::syncIndexData(GLsizei count, GLenum type, const GLvoid *indices, bool attributesNeedStreaming,
Geoff Lang831b1952015-05-05 11:02:27 -0400245 gl::RangeUI *outIndexRange, const GLvoid **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400246{
247 ASSERT(outIndices);
248
249 // Need to check the range of indices if attributes need to be streamed
250 if (mElementArrayBuffer.get() != nullptr)
251 {
252 const BufferGL *bufferGL = GetImplAs<BufferGL>(mElementArrayBuffer.get());
253 GLuint elementArrayBufferID = bufferGL->getBufferID();
254 if (elementArrayBufferID != mAppliedElementArrayBuffer)
255 {
256 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementArrayBufferID);
257 mAppliedElementArrayBuffer = elementArrayBufferID;
258 }
259
260 // Only compute the index range if the attributes also need to be streamed
261 if (attributesNeedStreaming)
262 {
263 ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices);
Geoff Lang520c4ae2015-05-05 13:12:36 -0400264 gl::Error error = mElementArrayBuffer->getIndexRange(type, static_cast<size_t>(elementArrayBufferOffset), count, outIndexRange);
265 if (error.isError())
Geoff Lang7c82bc42015-03-09 16:18:08 -0400266 {
Geoff Lang520c4ae2015-05-05 13:12:36 -0400267 return error;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400268 }
269 }
270
271 // Indices serves as an offset into the index buffer in this case, use the same value for the draw call
272 *outIndices = indices;
273 }
274 else
275 {
276 // Need to stream the index buffer
277 // TODO: if GLES, nothing needs to be streamed
278
279 // Only compute the index range if the attributes also need to be streamed
280 if (attributesNeedStreaming)
281 {
Geoff Lang831b1952015-05-05 11:02:27 -0400282 *outIndexRange = gl::ComputeIndexRange(type, indices, count);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400283 }
284
285 // Allocate the streaming element array buffer
286 if (mStreamingElementArrayBuffer == 0)
287 {
288 mFunctions->genBuffers(1, &mStreamingElementArrayBuffer);
289 mStreamingElementArrayBufferSize = 0;
290 }
291
292 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, mStreamingElementArrayBuffer);
293 mAppliedElementArrayBuffer = mStreamingElementArrayBuffer;
294
295 // Make sure the element array buffer is large enough
296 const gl::Type &indexTypeInfo = gl::GetTypeInfo(type);
297 size_t requiredStreamingBufferSize = indexTypeInfo.bytes * count;
298 if (requiredStreamingBufferSize > mStreamingElementArrayBufferSize)
299 {
300 // Copy the indices in while resizing the buffer
301 mFunctions->bufferData(GL_ELEMENT_ARRAY_BUFFER, requiredStreamingBufferSize, indices, GL_DYNAMIC_DRAW);
302 mStreamingElementArrayBufferSize = requiredStreamingBufferSize;
303 }
304 else
305 {
306 // Put the indices at the beginning of the buffer
307 mFunctions->bufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, requiredStreamingBufferSize, indices);
308 }
309
310 // Set the index offset for the draw call to zero since the supplied index pointer is to client data
311 *outIndices = nullptr;
312 }
313
314 return gl::Error(GL_NO_ERROR);
315}
316
Geoff Lang831b1952015-05-05 11:02:27 -0400317gl::Error VertexArrayGL::streamAttributes(size_t streamingDataSize, size_t maxAttributeDataSize, const gl::RangeUI &indexRange) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400318{
319 if (mStreamingArrayBuffer == 0)
320 {
321 mFunctions->genBuffers(1, &mStreamingArrayBuffer);
322 mStreamingArrayBufferSize = 0;
323 }
324
325 // If first is greater than zero, a slack space needs to be left at the beginning of the buffer so that
326 // the same 'first' argument can be passed into the draw call.
327 const size_t bufferEmptySpace = maxAttributeDataSize * indexRange.start;
328 const size_t requiredBufferSize = streamingDataSize + bufferEmptySpace;
329
330 mStateManager->bindBuffer(GL_ARRAY_BUFFER, mStreamingArrayBuffer);
331 if (requiredBufferSize > mStreamingArrayBufferSize)
332 {
333 mFunctions->bufferData(GL_ARRAY_BUFFER, requiredBufferSize, nullptr, GL_DYNAMIC_DRAW);
334 mStreamingArrayBufferSize = requiredBufferSize;
335 }
336
337 // Unmapping a buffer can return GL_FALSE to indicate that the system has corrupted the data
338 // somehow (such as by a screen change), retry writing the data a few times and return OUT_OF_MEMORY
339 // if that fails.
340 GLboolean unmapResult = GL_FALSE;
341 size_t unmapRetryAttempts = 5;
342 while (unmapResult != GL_TRUE && --unmapRetryAttempts > 0)
343 {
344 uint8_t *bufferPointer = reinterpret_cast<uint8_t*>(mFunctions->mapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
345 size_t curBufferOffset = bufferEmptySpace;
346
347 const size_t streamedVertexCount = indexRange.end - indexRange.start + 1;
348
349 for (size_t idx = 0; idx < mAttributes.size(); idx++)
350 {
351 if (mAttributes[idx].enabled && mAttributes[idx].buffer.get() == nullptr)
352 {
353 const size_t sourceStride = ComputeVertexAttributeStride(mAttributes[idx]);
354 const size_t destStride = ComputeVertexAttributeTypeSize(mAttributes[idx]);
355
356 const uint8_t *inputPointer = reinterpret_cast<const uint8_t*>(mAttributes[idx].pointer);
357
358 // Pack the data when copying it, user could have supplied a very large stride that would
359 // cause the buffer to be much larger than needed.
360 if (destStride == sourceStride)
361 {
362 // Can copy in one go, the data is packed
363 memcpy(bufferPointer + curBufferOffset,
364 inputPointer + (sourceStride * indexRange.start),
365 destStride * streamedVertexCount);
366 }
367 else
368 {
369 // Copy each vertex individually
370 for (size_t vertexIdx = indexRange.start; vertexIdx <= indexRange.end; vertexIdx++)
371 {
372 memcpy(bufferPointer + curBufferOffset + (destStride * vertexIdx),
373 inputPointer + (sourceStride * vertexIdx),
374 destStride);
375 }
376 }
377
378 // Compute where the 0-index vertex would be.
379 const size_t vertexStartOffset = curBufferOffset - (indexRange.start * destStride);
380
381 mFunctions->vertexAttribPointer(idx, mAttributes[idx].size, mAttributes[idx].type,
382 mAttributes[idx].normalized, destStride,
383 reinterpret_cast<const GLvoid*>(vertexStartOffset));
384
385 curBufferOffset += destStride * streamedVertexCount;
386
387 // Mark the applied attribute as dirty by setting an invalid size so that if it doesn't
388 // need to be streamed later, there is no chance that the caching will skip it.
389 mAppliedAttributes[idx].size = static_cast<GLuint>(-1);
390 }
391 }
392
393 unmapResult = mFunctions->unmapBuffer(GL_ARRAY_BUFFER);
394 }
395
396 if (unmapResult != GL_TRUE)
397 {
398 return gl::Error(GL_OUT_OF_MEMORY, "Failed to unmap the client data streaming buffer.");
399 }
400
401 return gl::Error(GL_NO_ERROR);
Geoff Langba4c4a82015-02-24 12:38:46 -0500402}
403
404GLuint VertexArrayGL::getVertexArrayID() const
405{
406 return mVertexArrayID;
Geoff Langf9a6f082015-01-22 13:32:49 -0500407}
408
409}