blob: c7b6acebc34978e705c2656d034501c6be6c11b1 [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 Madill8e344942015-07-09 14:22:07 -040024VertexArrayGL::VertexArrayGL(const gl::VertexArray::Data &data, const FunctionsGL *functions, StateManagerGL *stateManager)
25 : VertexArrayImpl(data),
Geoff Langba4c4a82015-02-24 12:38:46 -050026 mFunctions(functions),
27 mStateManager(stateManager),
28 mVertexArrayID(0),
29 mAppliedElementArrayBuffer(0),
Geoff Lang7c82bc42015-03-09 16:18:08 -040030 mStreamingElementArrayBufferSize(0),
31 mStreamingElementArrayBuffer(0),
32 mStreamingArrayBufferSize(0),
33 mStreamingArrayBuffer(0)
Geoff Langba4c4a82015-02-24 12:38:46 -050034{
35 ASSERT(mFunctions);
36 ASSERT(mStateManager);
37 mFunctions->genVertexArrays(1, &mVertexArrayID);
38
39 // Set the cached vertex attribute array size
40 GLint maxVertexAttribs;
41 mFunctions->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
42 mAppliedAttributes.resize(maxVertexAttribs);
43}
Geoff Langf9a6f082015-01-22 13:32:49 -050044
45VertexArrayGL::~VertexArrayGL()
Geoff Langba4c4a82015-02-24 12:38:46 -050046{
Geoff Lang1eb708e2015-05-04 14:58:23 -040047 mStateManager->deleteVertexArray(mVertexArrayID);
48 mVertexArrayID = 0;
Geoff Langba4c4a82015-02-24 12:38:46 -050049
Geoff Lang1eb708e2015-05-04 14:58:23 -040050 mStateManager->deleteBuffer(mStreamingElementArrayBuffer);
51 mStreamingElementArrayBufferSize = 0;
52 mStreamingElementArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040053
Geoff Lang1eb708e2015-05-04 14:58:23 -040054 mStateManager->deleteBuffer(mStreamingArrayBuffer);
55 mStreamingArrayBufferSize = 0;
56 mStreamingArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040057
Geoff Langba4c4a82015-02-24 12:38:46 -050058 for (size_t idx = 0; idx < mAppliedAttributes.size(); idx++)
59 {
Jamie Madill8e344942015-07-09 14:22:07 -040060 mAppliedAttributes[idx].buffer.set(nullptr);
Geoff Langba4c4a82015-02-24 12:38:46 -050061 }
62}
Geoff Langf9a6f082015-01-22 13:32:49 -050063
64void VertexArrayGL::setElementArrayBuffer(const gl::Buffer *buffer)
65{
Geoff Langee09b582015-06-16 15:13:52 -070066 // If the buffer is being unbound/deleted, reset the currently applied buffer ID
67 // so that even if a new buffer is generated with the same ID, it will be re-bound.
68 if (buffer == nullptr && mAppliedElementArrayBuffer != mStreamingElementArrayBuffer)
69 {
70 mAppliedElementArrayBuffer = 0;
71 }
Geoff Lang6ae6efc2015-03-09 14:42:35 -040072}
73
74void VertexArrayGL::setAttribute(size_t idx, const gl::VertexAttribute &attr)
75{
Geoff Lang6ae6efc2015-03-09 14:42:35 -040076}
77
78void VertexArrayGL::setAttributeDivisor(size_t idx, GLuint divisor)
79{
Geoff Lang6ae6efc2015-03-09 14:42:35 -040080}
81
82void VertexArrayGL::enableAttribute(size_t idx, bool enabledState)
83{
Geoff Lang6ae6efc2015-03-09 14:42:35 -040084}
85
Geoff Lang7c82bc42015-03-09 16:18:08 -040086gl::Error VertexArrayGL::syncDrawArraysState(GLint first, GLsizei count) const
87{
88 return syncDrawState(first, count, GL_NONE, nullptr, nullptr);
89}
90
91gl::Error VertexArrayGL::syncDrawElementsState(GLsizei count, GLenum type, const GLvoid *indices, const GLvoid **outIndices) const
92{
93 return syncDrawState(0, count, type, indices, outIndices);
94}
95
96gl::Error VertexArrayGL::syncDrawState(GLint first, GLsizei count, GLenum type, const GLvoid *indices, const GLvoid **outIndices) const
Geoff Lang6ae6efc2015-03-09 14:42:35 -040097{
Geoff Lang294cad92015-05-26 15:11:23 -040098 mStateManager->bindVertexArray(mVertexArrayID, mAppliedElementArrayBuffer);
Geoff Lang6ae6efc2015-03-09 14:42:35 -040099
Geoff Lang7c82bc42015-03-09 16:18:08 -0400100 // Check if any attributes need to be streamed, determines if the index range needs to be computed
101 bool attributesNeedStreaming = doAttributesNeedStreaming();
102
103 // 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 -0400104 gl::RangeUI indexRange(0, 0);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400105 if (type != GL_NONE)
Geoff Langba4c4a82015-02-24 12:38:46 -0500106 {
Geoff Lang7c82bc42015-03-09 16:18:08 -0400107 gl::Error error = syncIndexData(count, type, indices, attributesNeedStreaming, &indexRange, outIndices);
108 if (error.isError())
109 {
110 return error;
111 }
112 }
113 else
114 {
115 // Not an indexed call, set the range to [first, first + count)
116 indexRange.start = first;
117 indexRange.end = first + count;
Geoff Langba4c4a82015-02-24 12:38:46 -0500118 }
119
Geoff Lang7c82bc42015-03-09 16:18:08 -0400120 // Sync the vertex attribute state and track what data needs to be streamed
121 size_t streamingDataSize = 0;
122 size_t maxAttributeDataSize = 0;
123 gl::Error error = syncAttributeState(attributesNeedStreaming, indexRange, &streamingDataSize, &maxAttributeDataSize);
124 if (error.isError())
Geoff Langba4c4a82015-02-24 12:38:46 -0500125 {
Geoff Lang7c82bc42015-03-09 16:18:08 -0400126 return error;
Geoff Langba4c4a82015-02-24 12:38:46 -0500127 }
Geoff Langf9a6f082015-01-22 13:32:49 -0500128
Geoff Lang7c82bc42015-03-09 16:18:08 -0400129 if (streamingDataSize > 0)
130 {
131 ASSERT(attributesNeedStreaming);
132
133 gl::Error error = streamAttributes(streamingDataSize, maxAttributeDataSize, indexRange);
134 if (error.isError())
135 {
136 return error;
137 }
138 }
139
140 return gl::Error(GL_NO_ERROR);
141}
142
143bool VertexArrayGL::doAttributesNeedStreaming() const
144{
145 // TODO: if GLES, nothing needs to be streamed
Jamie Madill8e344942015-07-09 14:22:07 -0400146 const auto &attribs = mData.getVertexAttributes();
147 for (size_t idx = 0; idx < attribs.size(); idx++)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400148 {
Jamie Madill8e344942015-07-09 14:22:07 -0400149 if (attribs[idx].enabled && attribs[idx].buffer.get() == nullptr)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400150 {
151 return true;
152 }
153 }
154
155 return false;
156}
157
Geoff Lang831b1952015-05-05 11:02:27 -0400158gl::Error VertexArrayGL::syncAttributeState(bool attributesNeedStreaming, const gl::RangeUI &indexRange,
Geoff Lang7c82bc42015-03-09 16:18:08 -0400159 size_t *outStreamingDataSize, size_t *outMaxAttributeDataSize) const
160{
161 *outStreamingDataSize = 0;
162 *outMaxAttributeDataSize = 0;
163
Jamie Madill8e344942015-07-09 14:22:07 -0400164 const auto &attribs = mData.getVertexAttributes();
165 for (size_t idx = 0; idx < attribs.size(); idx++)
Geoff Langba4c4a82015-02-24 12:38:46 -0500166 {
Jamie Madill8e344942015-07-09 14:22:07 -0400167 const auto &attrib = attribs[idx];
168
Geoff Lang7c82bc42015-03-09 16:18:08 -0400169 // Always sync the enabled and divisor state, they are required for both streaming and buffered
170 // attributes
Jamie Madill8e344942015-07-09 14:22:07 -0400171 if (mAppliedAttributes[idx].enabled != attrib.enabled)
Geoff Langba4c4a82015-02-24 12:38:46 -0500172 {
Jamie Madill8e344942015-07-09 14:22:07 -0400173 if (attrib.enabled)
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400174 {
175 mFunctions->enableVertexAttribArray(idx);
176 }
177 else
178 {
179 mFunctions->disableVertexAttribArray(idx);
180 }
Jamie Madill8e344942015-07-09 14:22:07 -0400181 mAppliedAttributes[idx].enabled = attrib.enabled;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400182 }
Jamie Madill8e344942015-07-09 14:22:07 -0400183 if (mAppliedAttributes[idx].divisor != attrib.divisor)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400184 {
Jamie Madill8e344942015-07-09 14:22:07 -0400185 mFunctions->vertexAttribDivisor(idx, attrib.divisor);
186 mAppliedAttributes[idx].divisor = attrib.divisor;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400187 }
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400188
Jamie Madill8e344942015-07-09 14:22:07 -0400189 if (attribs[idx].enabled && attrib.buffer.get() == nullptr)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400190 {
191 ASSERT(attributesNeedStreaming);
192
193 const size_t streamedVertexCount = indexRange.end - indexRange.start + 1;
194
195 // If streaming is going to be required, compute the size of the required buffer
196 // and how much slack space at the beginning of the buffer will be required by determining
197 // the attribute with the largest data size.
Jamie Madill8e344942015-07-09 14:22:07 -0400198 size_t typeSize = ComputeVertexAttributeTypeSize(attrib);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400199 *outStreamingDataSize += typeSize * streamedVertexCount;
200 *outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
201 }
202 else
203 {
204 // Sync the attribute with no translation
Jamie Madill8e344942015-07-09 14:22:07 -0400205 if (mAppliedAttributes[idx] != attrib)
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400206 {
Jamie Madill8e344942015-07-09 14:22:07 -0400207 const gl::Buffer *arrayBuffer = attrib.buffer.get();
Geoff Lang851cd582015-05-26 16:47:23 -0400208 if (arrayBuffer != nullptr)
209 {
210 const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
211 mStateManager->bindBuffer(GL_ARRAY_BUFFER, arrayBufferGL->getBufferID());
212 }
213 else
214 {
215 mStateManager->bindBuffer(GL_ARRAY_BUFFER, 0);
216 }
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400217
Jamie Madill8e344942015-07-09 14:22:07 -0400218 if (attrib.pureInteger)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400219 {
Jamie Madill8e344942015-07-09 14:22:07 -0400220 mFunctions->vertexAttribIPointer(idx, attrib.size, attrib.type,
221 attrib.stride, attrib.pointer);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400222 }
223 else
224 {
Jamie Madill8e344942015-07-09 14:22:07 -0400225 mFunctions->vertexAttribPointer(idx, attrib.size, attrib.type,
226 attrib.normalized, attrib.stride,
227 attrib.pointer);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400228 }
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400229
Jamie Madill8e344942015-07-09 14:22:07 -0400230 mAppliedAttributes[idx] = attrib;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400231 }
Geoff Langba4c4a82015-02-24 12:38:46 -0500232 }
Geoff Langba4c4a82015-02-24 12:38:46 -0500233 }
Geoff Lang7c82bc42015-03-09 16:18:08 -0400234
235 return gl::Error(GL_NO_ERROR);
236}
237
238gl::Error VertexArrayGL::syncIndexData(GLsizei count, GLenum type, const GLvoid *indices, bool attributesNeedStreaming,
Geoff Lang831b1952015-05-05 11:02:27 -0400239 gl::RangeUI *outIndexRange, const GLvoid **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400240{
241 ASSERT(outIndices);
242
Jamie Madill8e344942015-07-09 14:22:07 -0400243 gl::Buffer *elementArrayBuffer = mData.getElementArrayBuffer().get();
244
Geoff Lang7c82bc42015-03-09 16:18:08 -0400245 // Need to check the range of indices if attributes need to be streamed
Jamie Madill8e344942015-07-09 14:22:07 -0400246 if (elementArrayBuffer != nullptr)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400247 {
Jamie Madill8e344942015-07-09 14:22:07 -0400248 const BufferGL *bufferGL = GetImplAs<BufferGL>(elementArrayBuffer);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400249 GLuint elementArrayBufferID = bufferGL->getBufferID();
250 if (elementArrayBufferID != mAppliedElementArrayBuffer)
251 {
252 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementArrayBufferID);
253 mAppliedElementArrayBuffer = elementArrayBufferID;
254 }
255
256 // Only compute the index range if the attributes also need to be streamed
257 if (attributesNeedStreaming)
258 {
259 ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices);
Jamie Madill8e344942015-07-09 14:22:07 -0400260 gl::Error error = mData.getElementArrayBuffer()->getIndexRange(type, static_cast<size_t>(elementArrayBufferOffset), count, outIndexRange);
Geoff Lang520c4ae2015-05-05 13:12:36 -0400261 if (error.isError())
Geoff Lang7c82bc42015-03-09 16:18:08 -0400262 {
Geoff Lang520c4ae2015-05-05 13:12:36 -0400263 return error;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400264 }
265 }
266
267 // Indices serves as an offset into the index buffer in this case, use the same value for the draw call
268 *outIndices = indices;
269 }
270 else
271 {
272 // Need to stream the index buffer
273 // TODO: if GLES, nothing needs to be streamed
274
275 // Only compute the index range if the attributes also need to be streamed
276 if (attributesNeedStreaming)
277 {
Geoff Lang831b1952015-05-05 11:02:27 -0400278 *outIndexRange = gl::ComputeIndexRange(type, indices, count);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400279 }
280
281 // Allocate the streaming element array buffer
282 if (mStreamingElementArrayBuffer == 0)
283 {
284 mFunctions->genBuffers(1, &mStreamingElementArrayBuffer);
285 mStreamingElementArrayBufferSize = 0;
286 }
287
288 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, mStreamingElementArrayBuffer);
289 mAppliedElementArrayBuffer = mStreamingElementArrayBuffer;
290
291 // Make sure the element array buffer is large enough
292 const gl::Type &indexTypeInfo = gl::GetTypeInfo(type);
293 size_t requiredStreamingBufferSize = indexTypeInfo.bytes * count;
294 if (requiredStreamingBufferSize > mStreamingElementArrayBufferSize)
295 {
296 // Copy the indices in while resizing the buffer
297 mFunctions->bufferData(GL_ELEMENT_ARRAY_BUFFER, requiredStreamingBufferSize, indices, GL_DYNAMIC_DRAW);
298 mStreamingElementArrayBufferSize = requiredStreamingBufferSize;
299 }
300 else
301 {
302 // Put the indices at the beginning of the buffer
303 mFunctions->bufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, requiredStreamingBufferSize, indices);
304 }
305
306 // Set the index offset for the draw call to zero since the supplied index pointer is to client data
307 *outIndices = nullptr;
308 }
309
310 return gl::Error(GL_NO_ERROR);
311}
312
Geoff Lang831b1952015-05-05 11:02:27 -0400313gl::Error VertexArrayGL::streamAttributes(size_t streamingDataSize, size_t maxAttributeDataSize, const gl::RangeUI &indexRange) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400314{
315 if (mStreamingArrayBuffer == 0)
316 {
317 mFunctions->genBuffers(1, &mStreamingArrayBuffer);
318 mStreamingArrayBufferSize = 0;
319 }
320
321 // If first is greater than zero, a slack space needs to be left at the beginning of the buffer so that
322 // the same 'first' argument can be passed into the draw call.
323 const size_t bufferEmptySpace = maxAttributeDataSize * indexRange.start;
324 const size_t requiredBufferSize = streamingDataSize + bufferEmptySpace;
325
326 mStateManager->bindBuffer(GL_ARRAY_BUFFER, mStreamingArrayBuffer);
327 if (requiredBufferSize > mStreamingArrayBufferSize)
328 {
329 mFunctions->bufferData(GL_ARRAY_BUFFER, requiredBufferSize, nullptr, GL_DYNAMIC_DRAW);
330 mStreamingArrayBufferSize = requiredBufferSize;
331 }
332
333 // Unmapping a buffer can return GL_FALSE to indicate that the system has corrupted the data
334 // somehow (such as by a screen change), retry writing the data a few times and return OUT_OF_MEMORY
335 // if that fails.
336 GLboolean unmapResult = GL_FALSE;
337 size_t unmapRetryAttempts = 5;
338 while (unmapResult != GL_TRUE && --unmapRetryAttempts > 0)
339 {
340 uint8_t *bufferPointer = reinterpret_cast<uint8_t*>(mFunctions->mapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
341 size_t curBufferOffset = bufferEmptySpace;
342
343 const size_t streamedVertexCount = indexRange.end - indexRange.start + 1;
344
Jamie Madill8e344942015-07-09 14:22:07 -0400345 const auto &attribs = mData.getVertexAttributes();
346 for (size_t idx = 0; idx < attribs.size(); idx++)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400347 {
Jamie Madill8e344942015-07-09 14:22:07 -0400348 const auto &attrib = attribs[idx];
Geoff Lang7c82bc42015-03-09 16:18:08 -0400349
Jamie Madill8e344942015-07-09 14:22:07 -0400350 if (attrib.enabled && attrib.buffer.get() == nullptr)
351 {
352 const size_t sourceStride = ComputeVertexAttributeStride(attrib);
353 const size_t destStride = ComputeVertexAttributeTypeSize(attrib);
354
355 const uint8_t *inputPointer = reinterpret_cast<const uint8_t*>(attrib.pointer);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400356
357 // Pack the data when copying it, user could have supplied a very large stride that would
358 // cause the buffer to be much larger than needed.
359 if (destStride == sourceStride)
360 {
361 // Can copy in one go, the data is packed
362 memcpy(bufferPointer + curBufferOffset,
363 inputPointer + (sourceStride * indexRange.start),
364 destStride * streamedVertexCount);
365 }
366 else
367 {
368 // Copy each vertex individually
369 for (size_t vertexIdx = indexRange.start; vertexIdx <= indexRange.end; vertexIdx++)
370 {
371 memcpy(bufferPointer + curBufferOffset + (destStride * vertexIdx),
372 inputPointer + (sourceStride * vertexIdx),
373 destStride);
374 }
375 }
376
377 // Compute where the 0-index vertex would be.
378 const size_t vertexStartOffset = curBufferOffset - (indexRange.start * destStride);
379
Jamie Madill8e344942015-07-09 14:22:07 -0400380 mFunctions->vertexAttribPointer(idx, attrib.size, attrib.type,
381 attrib.normalized, destStride,
Geoff Lang7c82bc42015-03-09 16:18:08 -0400382 reinterpret_cast<const GLvoid*>(vertexStartOffset));
383
384 curBufferOffset += destStride * streamedVertexCount;
385
386 // Mark the applied attribute as dirty by setting an invalid size so that if it doesn't
387 // need to be streamed later, there is no chance that the caching will skip it.
388 mAppliedAttributes[idx].size = static_cast<GLuint>(-1);
389 }
390 }
391
392 unmapResult = mFunctions->unmapBuffer(GL_ARRAY_BUFFER);
393 }
394
395 if (unmapResult != GL_TRUE)
396 {
397 return gl::Error(GL_OUT_OF_MEMORY, "Failed to unmap the client data streaming buffer.");
398 }
399
400 return gl::Error(GL_NO_ERROR);
Geoff Langba4c4a82015-02-24 12:38:46 -0500401}
402
403GLuint VertexArrayGL::getVertexArrayID() const
404{
405 return mVertexArrayID;
Geoff Langf9a6f082015-01-22 13:32:49 -0500406}
407
Geoff Lang294cad92015-05-26 15:11:23 -0400408GLuint VertexArrayGL::getAppliedElementArrayBufferID() const
409{
410 return mAppliedElementArrayBuffer;
411}
412
Geoff Langf9a6f082015-01-22 13:32:49 -0500413}