blob: 9e7cce866a14233e6f6e24baba1d0c3900e8e66b [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
Jamie Madill5b21ed52015-08-14 18:12:50 +000024VertexArrayGL::VertexArrayGL(const gl::VertexArray::Data &data,
Jamie Madill77a90c22015-08-11 16:33:17 -040025 const FunctionsGL *functions,
26 StateManagerGL *stateManager)
Jamie Madill8e344942015-07-09 14:22:07 -040027 : VertexArrayImpl(data),
Geoff Langba4c4a82015-02-24 12:38:46 -050028 mFunctions(functions),
29 mStateManager(stateManager),
30 mVertexArrayID(0),
Jamie Madill77a90c22015-08-11 16:33:17 -040031 mAppliedElementArrayBuffer(),
Geoff Lang7c82bc42015-03-09 16:18:08 -040032 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);
44 mAppliedAttributes.resize(maxVertexAttribs);
45}
Geoff Langf9a6f082015-01-22 13:32:49 -050046
47VertexArrayGL::~VertexArrayGL()
Geoff Langba4c4a82015-02-24 12:38:46 -050048{
Geoff Lang1eb708e2015-05-04 14:58:23 -040049 mStateManager->deleteVertexArray(mVertexArrayID);
50 mVertexArrayID = 0;
Geoff Langba4c4a82015-02-24 12:38:46 -050051
Geoff Lang1eb708e2015-05-04 14:58:23 -040052 mStateManager->deleteBuffer(mStreamingElementArrayBuffer);
53 mStreamingElementArrayBufferSize = 0;
54 mStreamingElementArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040055
Geoff Lang1eb708e2015-05-04 14:58:23 -040056 mStateManager->deleteBuffer(mStreamingArrayBuffer);
57 mStreamingArrayBufferSize = 0;
58 mStreamingArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040059
Jamie Madill77a90c22015-08-11 16:33:17 -040060 mAppliedElementArrayBuffer.set(nullptr);
Geoff Langba4c4a82015-02-24 12:38:46 -050061 for (size_t idx = 0; idx < mAppliedAttributes.size(); idx++)
62 {
Jamie Madill8e344942015-07-09 14:22:07 -040063 mAppliedAttributes[idx].buffer.set(nullptr);
Geoff Langba4c4a82015-02-24 12:38:46 -050064 }
65}
Geoff Langf9a6f082015-01-22 13:32:49 -050066
Jamie Madill5b21ed52015-08-14 18:12:50 +000067gl::Error VertexArrayGL::syncDrawArraysState(const std::vector<GLuint> &activeAttribLocations, GLint first, GLsizei count) const
Geoff Lang7c82bc42015-03-09 16:18:08 -040068{
Jamie Madill5b21ed52015-08-14 18:12:50 +000069 return syncDrawState(activeAttribLocations, first, count, GL_NONE, nullptr, nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -040070}
71
Jamie Madill5b21ed52015-08-14 18:12:50 +000072gl::Error VertexArrayGL::syncDrawElementsState(const std::vector<GLuint> &activeAttribLocations, GLsizei count,
73 GLenum type, const GLvoid *indices, const GLvoid **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -040074{
Jamie Madill5b21ed52015-08-14 18:12:50 +000075 return syncDrawState(activeAttribLocations, 0, count, type, indices, outIndices);
Geoff Lang7c82bc42015-03-09 16:18:08 -040076}
77
Jamie Madill5b21ed52015-08-14 18:12:50 +000078gl::Error VertexArrayGL::syncDrawState(const std::vector<GLuint> &activeAttribLocations, GLint first, GLsizei count, GLenum type, const GLvoid *indices, const GLvoid **outIndices) const
Geoff Lang6ae6efc2015-03-09 14:42:35 -040079{
Jamie Madill77a90c22015-08-11 16:33:17 -040080 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
Geoff Lang6ae6efc2015-03-09 14:42:35 -040081
Geoff Lang7c82bc42015-03-09 16:18:08 -040082 // Check if any attributes need to be streamed, determines if the index range needs to be computed
Jamie Madill5b21ed52015-08-14 18:12:50 +000083 bool attributesNeedStreaming = doAttributesNeedStreaming(activeAttribLocations);
Geoff Lang7c82bc42015-03-09 16:18:08 -040084
85 // Determine if an index buffer needs to be streamed and the range of vertices that need to be copied
Jamie Madill5b21ed52015-08-14 18:12:50 +000086 gl::RangeUI indexRange(0, 0);
Geoff Lang7c82bc42015-03-09 16:18:08 -040087 if (type != GL_NONE)
Geoff Langba4c4a82015-02-24 12:38:46 -050088 {
Jamie Madill5b21ed52015-08-14 18:12:50 +000089 gl::Error error = syncIndexData(count, type, indices, attributesNeedStreaming, &indexRange, outIndices);
Geoff Lang7c82bc42015-03-09 16:18:08 -040090 if (error.isError())
91 {
92 return error;
93 }
94 }
95 else
96 {
97 // Not an indexed call, set the range to [first, first + count)
98 indexRange.start = first;
99 indexRange.end = first + count;
Geoff Langba4c4a82015-02-24 12:38:46 -0500100 }
101
Jamie Madill5b21ed52015-08-14 18:12:50 +0000102 // Sync the vertex attribute state and track what data needs to be streamed
103 size_t streamingDataSize = 0;
104 size_t maxAttributeDataSize = 0;
105 gl::Error error = syncAttributeState(activeAttribLocations, attributesNeedStreaming, indexRange,
106 &streamingDataSize, &maxAttributeDataSize);
107 if (error.isError())
Geoff Langba4c4a82015-02-24 12:38:46 -0500108 {
Jamie Madill5b21ed52015-08-14 18:12:50 +0000109 return error;
110 }
111
112 if (streamingDataSize > 0)
113 {
114 ASSERT(attributesNeedStreaming);
115
116 error = streamAttributes(activeAttribLocations, streamingDataSize, maxAttributeDataSize,
117 indexRange);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400118 if (error.isError())
119 {
120 return error;
121 }
122 }
123
Jamie Madill5b21ed52015-08-14 18:12:50 +0000124 return gl::Error(GL_NO_ERROR);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400125}
126
Jamie Madill5b21ed52015-08-14 18:12:50 +0000127bool VertexArrayGL::doAttributesNeedStreaming(const std::vector<GLuint> &activeAttribLocations) const
128{
129 // TODO: if GLES, nothing needs to be streamed
130 const auto &attribs = mData.getVertexAttributes();
131 for (size_t activeAttrib = 0; activeAttrib < activeAttribLocations.size(); activeAttrib++)
132 {
133 GLuint idx = activeAttribLocations[activeAttrib];
134 if (attribs[idx].enabled && attribs[idx].buffer.get() == nullptr)
135 {
136 return true;
137 }
138 }
139
140 return false;
141}
142
143gl::Error VertexArrayGL::syncAttributeState(const std::vector<GLuint> &activeAttribLocations, bool attributesNeedStreaming,
144 const gl::RangeUI &indexRange, size_t *outStreamingDataSize, size_t *outMaxAttributeDataSize) const
145{
146 *outStreamingDataSize = 0;
147 *outMaxAttributeDataSize = 0;
148
149 const auto &attribs = mData.getVertexAttributes();
150 for (size_t activeAttrib = 0; activeAttrib < activeAttribLocations.size(); activeAttrib++)
151 {
152 GLuint idx = activeAttribLocations[activeAttrib];
153 const auto &attrib = attribs[idx];
154
155 // Always sync the enabled and divisor state, they are required for both streaming and buffered
156 // attributes
157 if (mAppliedAttributes[idx].enabled != attrib.enabled)
158 {
159 if (attrib.enabled)
160 {
161 mFunctions->enableVertexAttribArray(idx);
162 }
163 else
164 {
165 mFunctions->disableVertexAttribArray(idx);
166 }
167 mAppliedAttributes[idx].enabled = attrib.enabled;
168 }
169 if (mAppliedAttributes[idx].divisor != attrib.divisor)
170 {
171 mFunctions->vertexAttribDivisor(idx, attrib.divisor);
172 mAppliedAttributes[idx].divisor = attrib.divisor;
173 }
174
175 if (attribs[idx].enabled && attrib.buffer.get() == nullptr)
176 {
177 ASSERT(attributesNeedStreaming);
178
179 const size_t streamedVertexCount = indexRange.end - indexRange.start + 1;
180
181 // If streaming is going to be required, compute the size of the required buffer
182 // and how much slack space at the beginning of the buffer will be required by determining
183 // the attribute with the largest data size.
184 size_t typeSize = ComputeVertexAttributeTypeSize(attrib);
185 *outStreamingDataSize += typeSize * streamedVertexCount;
186 *outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
187 }
188 else
189 {
190 // Sync the attribute with no translation
191 if (mAppliedAttributes[idx] != attrib)
192 {
193 const gl::Buffer *arrayBuffer = attrib.buffer.get();
194 if (arrayBuffer != nullptr)
195 {
196 const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
197 mStateManager->bindBuffer(GL_ARRAY_BUFFER, arrayBufferGL->getBufferID());
198 }
199 else
200 {
201 mStateManager->bindBuffer(GL_ARRAY_BUFFER, 0);
202 }
203
204 if (attrib.pureInteger)
205 {
206 mFunctions->vertexAttribIPointer(idx, attrib.size, attrib.type,
207 attrib.stride, attrib.pointer);
208 }
209 else
210 {
211 mFunctions->vertexAttribPointer(idx, attrib.size, attrib.type,
212 attrib.normalized, attrib.stride,
213 attrib.pointer);
214 }
215
216 mAppliedAttributes[idx] = attrib;
217 }
218 }
219 }
220
221 return gl::Error(GL_NO_ERROR);
222}
223
224gl::Error VertexArrayGL::syncIndexData(GLsizei count, GLenum type, const GLvoid *indices, bool attributesNeedStreaming,
225 gl::RangeUI *outIndexRange, const GLvoid **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400226{
227 ASSERT(outIndices);
228
Jamie Madill8e344942015-07-09 14:22:07 -0400229 gl::Buffer *elementArrayBuffer = mData.getElementArrayBuffer().get();
230
Geoff Lang7c82bc42015-03-09 16:18:08 -0400231 // Need to check the range of indices if attributes need to be streamed
Jamie Madill8e344942015-07-09 14:22:07 -0400232 if (elementArrayBuffer != nullptr)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400233 {
Jamie Madill77a90c22015-08-11 16:33:17 -0400234 if (elementArrayBuffer != mAppliedElementArrayBuffer.get())
Geoff Lang7c82bc42015-03-09 16:18:08 -0400235 {
Jamie Madill77a90c22015-08-11 16:33:17 -0400236 const BufferGL *bufferGL = GetImplAs<BufferGL>(elementArrayBuffer);
237 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferGL->getBufferID());
238 mAppliedElementArrayBuffer.set(elementArrayBuffer);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400239 }
240
241 // Only compute the index range if the attributes also need to be streamed
242 if (attributesNeedStreaming)
243 {
244 ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices);
Jamie Madill5b21ed52015-08-14 18:12:50 +0000245 gl::Error error = mData.getElementArrayBuffer()->getIndexRange(type, static_cast<size_t>(elementArrayBufferOffset), count, outIndexRange);
Geoff Lang520c4ae2015-05-05 13:12:36 -0400246 if (error.isError())
Geoff Lang7c82bc42015-03-09 16:18:08 -0400247 {
Geoff Lang520c4ae2015-05-05 13:12:36 -0400248 return error;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400249 }
250 }
251
252 // Indices serves as an offset into the index buffer in this case, use the same value for the draw call
253 *outIndices = indices;
254 }
255 else
256 {
257 // Need to stream the index buffer
258 // TODO: if GLES, nothing needs to be streamed
259
260 // Only compute the index range if the attributes also need to be streamed
261 if (attributesNeedStreaming)
262 {
Jamie Madill5b21ed52015-08-14 18:12:50 +0000263 *outIndexRange = gl::ComputeIndexRange(type, indices, count);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400264 }
265
266 // Allocate the streaming element array buffer
267 if (mStreamingElementArrayBuffer == 0)
268 {
269 mFunctions->genBuffers(1, &mStreamingElementArrayBuffer);
270 mStreamingElementArrayBufferSize = 0;
271 }
272
273 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, mStreamingElementArrayBuffer);
Jamie Madill77a90c22015-08-11 16:33:17 -0400274 mAppliedElementArrayBuffer.set(nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400275
276 // Make sure the element array buffer is large enough
Jamie Madill5b21ed52015-08-14 18:12:50 +0000277 const gl::Type &indexTypeInfo = gl::GetTypeInfo(type);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400278 size_t requiredStreamingBufferSize = indexTypeInfo.bytes * count;
279 if (requiredStreamingBufferSize > mStreamingElementArrayBufferSize)
280 {
281 // Copy the indices in while resizing the buffer
282 mFunctions->bufferData(GL_ELEMENT_ARRAY_BUFFER, requiredStreamingBufferSize, indices, GL_DYNAMIC_DRAW);
283 mStreamingElementArrayBufferSize = requiredStreamingBufferSize;
284 }
285 else
286 {
287 // Put the indices at the beginning of the buffer
288 mFunctions->bufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, requiredStreamingBufferSize, indices);
289 }
290
291 // Set the index offset for the draw call to zero since the supplied index pointer is to client data
292 *outIndices = nullptr;
293 }
294
Jamie Madill5b21ed52015-08-14 18:12:50 +0000295 return gl::Error(GL_NO_ERROR);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400296}
297
Jamie Madill5b21ed52015-08-14 18:12:50 +0000298gl::Error VertexArrayGL::streamAttributes(const std::vector<GLuint> &activeAttribLocations, size_t streamingDataSize,
299 size_t maxAttributeDataSize, const gl::RangeUI &indexRange) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400300{
301 if (mStreamingArrayBuffer == 0)
302 {
303 mFunctions->genBuffers(1, &mStreamingArrayBuffer);
304 mStreamingArrayBufferSize = 0;
305 }
306
307 // If first is greater than zero, a slack space needs to be left at the beginning of the buffer so that
308 // the same 'first' argument can be passed into the draw call.
309 const size_t bufferEmptySpace = maxAttributeDataSize * indexRange.start;
310 const size_t requiredBufferSize = streamingDataSize + bufferEmptySpace;
311
312 mStateManager->bindBuffer(GL_ARRAY_BUFFER, mStreamingArrayBuffer);
313 if (requiredBufferSize > mStreamingArrayBufferSize)
314 {
315 mFunctions->bufferData(GL_ARRAY_BUFFER, requiredBufferSize, nullptr, GL_DYNAMIC_DRAW);
316 mStreamingArrayBufferSize = requiredBufferSize;
317 }
318
319 // Unmapping a buffer can return GL_FALSE to indicate that the system has corrupted the data
320 // somehow (such as by a screen change), retry writing the data a few times and return OUT_OF_MEMORY
321 // if that fails.
322 GLboolean unmapResult = GL_FALSE;
323 size_t unmapRetryAttempts = 5;
324 while (unmapResult != GL_TRUE && --unmapRetryAttempts > 0)
325 {
326 uint8_t *bufferPointer = reinterpret_cast<uint8_t*>(mFunctions->mapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
327 size_t curBufferOffset = bufferEmptySpace;
328
329 const size_t streamedVertexCount = indexRange.end - indexRange.start + 1;
330
Jamie Madill8e344942015-07-09 14:22:07 -0400331 const auto &attribs = mData.getVertexAttributes();
Jamie Madill5b21ed52015-08-14 18:12:50 +0000332 for (size_t activeAttrib = 0; activeAttrib < activeAttribLocations.size(); activeAttrib++)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400333 {
Jamie Madill5b21ed52015-08-14 18:12:50 +0000334 GLuint idx = activeAttribLocations[activeAttrib];
Jamie Madill8e344942015-07-09 14:22:07 -0400335 const auto &attrib = attribs[idx];
Geoff Lang7c82bc42015-03-09 16:18:08 -0400336
Jamie Madill5b21ed52015-08-14 18:12:50 +0000337 if (attrib.enabled && attrib.buffer.get() == nullptr)
Jamie Madill8e344942015-07-09 14:22:07 -0400338 {
Jamie Madill5b21ed52015-08-14 18:12:50 +0000339 const size_t sourceStride = ComputeVertexAttributeStride(attrib);
340 const size_t destStride = ComputeVertexAttributeTypeSize(attrib);
341
342 const uint8_t *inputPointer = reinterpret_cast<const uint8_t*>(attrib.pointer);
343
344 // Pack the data when copying it, user could have supplied a very large stride that would
345 // cause the buffer to be much larger than needed.
346 if (destStride == sourceStride)
Jamie Madill6d51c702015-08-14 10:38:10 -0400347 {
Jamie Madill5b21ed52015-08-14 18:12:50 +0000348 // Can copy in one go, the data is packed
349 memcpy(bufferPointer + curBufferOffset,
350 inputPointer + (sourceStride * indexRange.start),
351 destStride * streamedVertexCount);
Jamie Madill6d51c702015-08-14 10:38:10 -0400352 }
Jamie Madill5b21ed52015-08-14 18:12:50 +0000353 else
354 {
355 // Copy each vertex individually
356 for (size_t vertexIdx = indexRange.start; vertexIdx <= indexRange.end; vertexIdx++)
357 {
358 memcpy(bufferPointer + curBufferOffset + (destStride * vertexIdx),
359 inputPointer + (sourceStride * vertexIdx),
360 destStride);
361 }
362 }
363
364 // Compute where the 0-index vertex would be.
365 const size_t vertexStartOffset = curBufferOffset - (indexRange.start * destStride);
366
367 mFunctions->vertexAttribPointer(
368 idx, attrib.size, attrib.type, attrib.normalized,
369 static_cast<GLsizei>(destStride),
370 reinterpret_cast<const GLvoid *>(vertexStartOffset));
371
372 curBufferOffset += destStride * streamedVertexCount;
373
374 // Mark the applied attribute as dirty by setting an invalid size so that if it doesn't
375 // need to be streamed later, there is no chance that the caching will skip it.
376 mAppliedAttributes[idx].size = static_cast<GLuint>(-1);
Jamie Madill6d51c702015-08-14 10:38:10 -0400377 }
Geoff Lang7c82bc42015-03-09 16:18:08 -0400378 }
379
380 unmapResult = mFunctions->unmapBuffer(GL_ARRAY_BUFFER);
381 }
382
383 if (unmapResult != GL_TRUE)
384 {
Jamie Madill5b21ed52015-08-14 18:12:50 +0000385 return gl::Error(GL_OUT_OF_MEMORY, "Failed to unmap the client data streaming buffer.");
Geoff Lang7c82bc42015-03-09 16:18:08 -0400386 }
387
Jamie Madill5b21ed52015-08-14 18:12:50 +0000388 return gl::Error(GL_NO_ERROR);
Geoff Langba4c4a82015-02-24 12:38:46 -0500389}
390
391GLuint VertexArrayGL::getVertexArrayID() const
392{
393 return mVertexArrayID;
Geoff Langf9a6f082015-01-22 13:32:49 -0500394}
395
Geoff Lang294cad92015-05-26 15:11:23 -0400396GLuint VertexArrayGL::getAppliedElementArrayBufferID() const
397{
Jamie Madill77a90c22015-08-11 16:33:17 -0400398 if (mAppliedElementArrayBuffer.get() == nullptr)
399 {
400 return mStreamingElementArrayBuffer;
401 }
402
403 return GetImplAs<BufferGL>(mAppliedElementArrayBuffer.get())->getBufferID();
Geoff Lang294cad92015-05-26 15:11:23 -0400404}
405
Geoff Langf9a6f082015-01-22 13:32:49 -0500406}