blob: 86252a79fdb99493b3fd3f8a98a2b5350ef40da2 [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
Jamie Madill20e005b2017-04-07 14:19:22 -040011#include "common/bitset_utils.h"
Geoff Langf9a6f082015-01-22 13:32:49 -050012#include "common/debug.h"
Geoff Lang7c82bc42015-03-09 16:18:08 -040013#include "common/mathutil.h"
Geoff Lang831b1952015-05-05 11:02:27 -040014#include "common/utilities.h"
Geoff Lang6ae6efc2015-03-09 14:42:35 -040015#include "libANGLE/Buffer.h"
Geoff Langba4c4a82015-02-24 12:38:46 -050016#include "libANGLE/angletypes.h"
Geoff Lang7c82bc42015-03-09 16:18:08 -040017#include "libANGLE/formatutils.h"
Geoff Langba4c4a82015-02-24 12:38:46 -050018#include "libANGLE/renderer/gl/BufferGL.h"
19#include "libANGLE/renderer/gl/FunctionsGL.h"
20#include "libANGLE/renderer/gl/StateManagerGL.h"
Jamie Madill231c7f52017-04-26 13:45:37 -040021#include "libANGLE/renderer/gl/renderergl_utils.h"
Geoff Langf9a6f082015-01-22 13:32:49 -050022
Jamie Madill0b9e9032015-08-17 11:51:52 +000023using namespace gl;
24
Geoff Langf9a6f082015-01-22 13:32:49 -050025namespace rx
26{
Jamie Madill0b9e9032015-08-17 11:51:52 +000027namespace
28{
Jiawei-Shao2597fb62016-12-09 16:38:02 +080029// Warning: you should ensure binding really matches attrib.bindingIndex before using this function.
30bool AttributeNeedsStreaming(const VertexAttribute &attrib, const VertexBinding &binding)
Jamie Madill0b9e9032015-08-17 11:51:52 +000031{
Martin Radevdd5f27e2017-06-07 10:17:09 +030032 return (attrib.enabled && binding.getBuffer().get() == nullptr);
Jamie Madill0b9e9032015-08-17 11:51:52 +000033}
Shaodf682a82017-03-31 15:13:21 +080034
35bool SameVertexAttribFormat(const VertexAttribute &a, const VertexAttribute &b)
36{
37 return a.size == b.size && a.type == b.type && a.normalized == b.normalized &&
38 a.pureInteger == b.pureInteger && a.relativeOffset == b.relativeOffset;
39}
40
41bool SameVertexBuffer(const VertexBinding &a, const VertexBinding &b)
42{
Martin Radevdd5f27e2017-06-07 10:17:09 +030043 return a.getStride() == b.getStride() && a.getOffset() == b.getOffset() &&
44 a.getBuffer().get() == b.getBuffer().get();
Shaodf682a82017-03-31 15:13:21 +080045}
46
47bool IsVertexAttribPointerSupported(size_t attribIndex, const VertexAttribute &attrib)
48{
49 return (attribIndex == attrib.bindingIndex && attrib.relativeOffset == 0);
50}
Jamie Madill0b9e9032015-08-17 11:51:52 +000051} // anonymous namespace
52
Jamie Madill3f572682016-04-26 13:41:36 -040053VertexArrayGL::VertexArrayGL(const VertexArrayState &state,
Jamie Madill77a90c22015-08-11 16:33:17 -040054 const FunctionsGL *functions,
55 StateManagerGL *stateManager)
Jamie Madill3f572682016-04-26 13:41:36 -040056 : VertexArrayImpl(state),
Geoff Langba4c4a82015-02-24 12:38:46 -050057 mFunctions(functions),
58 mStateManager(stateManager),
59 mVertexArrayID(0),
Jamie Madill77a90c22015-08-11 16:33:17 -040060 mAppliedElementArrayBuffer(),
Jiawei-Shao2597fb62016-12-09 16:38:02 +080061 mAppliedBindings(state.getMaxBindings()),
Geoff Lang7c82bc42015-03-09 16:18:08 -040062 mStreamingElementArrayBufferSize(0),
63 mStreamingElementArrayBuffer(0),
64 mStreamingArrayBufferSize(0),
65 mStreamingArrayBuffer(0)
Geoff Langba4c4a82015-02-24 12:38:46 -050066{
67 ASSERT(mFunctions);
68 ASSERT(mStateManager);
69 mFunctions->genVertexArrays(1, &mVertexArrayID);
70
Jiawei-Shao2597fb62016-12-09 16:38:02 +080071 // Set the cached vertex attribute array and vertex attribute binding array size
72 GLuint maxVertexAttribs = static_cast<GLuint>(state.getMaxAttribs());
73 for (GLuint i = 0; i < maxVertexAttribs; i++)
74 {
75 mAppliedAttributes.emplace_back(i);
76 }
Geoff Langba4c4a82015-02-24 12:38:46 -050077}
Geoff Langf9a6f082015-01-22 13:32:49 -050078
79VertexArrayGL::~VertexArrayGL()
Geoff Langba4c4a82015-02-24 12:38:46 -050080{
Geoff Lang1eb708e2015-05-04 14:58:23 -040081 mStateManager->deleteVertexArray(mVertexArrayID);
82 mVertexArrayID = 0;
Geoff Langba4c4a82015-02-24 12:38:46 -050083
Geoff Lang1eb708e2015-05-04 14:58:23 -040084 mStateManager->deleteBuffer(mStreamingElementArrayBuffer);
85 mStreamingElementArrayBufferSize = 0;
Shao80957d92017-02-20 21:25:59 +080086 mStreamingElementArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040087
Geoff Lang1eb708e2015-05-04 14:58:23 -040088 mStateManager->deleteBuffer(mStreamingArrayBuffer);
89 mStreamingArrayBufferSize = 0;
Shao80957d92017-02-20 21:25:59 +080090 mStreamingArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040091
Jamie Madill77a90c22015-08-11 16:33:17 -040092 mAppliedElementArrayBuffer.set(nullptr);
Jiawei-Shao2597fb62016-12-09 16:38:02 +080093 for (auto &binding : mAppliedBindings)
Geoff Langba4c4a82015-02-24 12:38:46 -050094 {
Martin Radevdd5f27e2017-06-07 10:17:09 +030095 binding.setBuffer(nullptr);
Geoff Langba4c4a82015-02-24 12:38:46 -050096 }
97}
Geoff Langf9a6f082015-01-22 13:32:49 -050098
Jamie Madill0b9e9032015-08-17 11:51:52 +000099gl::Error VertexArrayGL::syncDrawArraysState(const gl::AttributesMask &activeAttributesMask,
100 GLint first,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400101 GLsizei count,
102 GLsizei instanceCount) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400103{
Geoff Lang3edfe032015-09-04 16:38:24 -0400104 return syncDrawState(activeAttributesMask, first, count, GL_NONE, nullptr, instanceCount, false,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400105 nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400106}
107
Jamie Madill0b9e9032015-08-17 11:51:52 +0000108gl::Error VertexArrayGL::syncDrawElementsState(const gl::AttributesMask &activeAttributesMask,
109 GLsizei count,
110 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400111 const void *indices,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400112 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400113 bool primitiveRestartEnabled,
Jamie Madill876429b2017-04-20 15:46:24 -0400114 const void **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400115{
Geoff Lang3edfe032015-09-04 16:38:24 -0400116 return syncDrawState(activeAttributesMask, 0, count, type, indices, instanceCount,
117 primitiveRestartEnabled, outIndices);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400118}
119
Jiajia Qind9671222016-11-29 16:30:31 +0800120gl::Error VertexArrayGL::syncElementArrayState() const
121{
122 gl::Buffer *elementArrayBuffer = mData.getElementArrayBuffer().get();
123 ASSERT(elementArrayBuffer);
124 if (elementArrayBuffer != mAppliedElementArrayBuffer.get())
125 {
126 const BufferGL *bufferGL = GetImplAs<BufferGL>(elementArrayBuffer);
127 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferGL->getBufferID());
128 mAppliedElementArrayBuffer.set(elementArrayBuffer);
129 }
130
131 return gl::NoError();
132}
133
Jamie Madill0b9e9032015-08-17 11:51:52 +0000134gl::Error VertexArrayGL::syncDrawState(const gl::AttributesMask &activeAttributesMask,
135 GLint first,
136 GLsizei count,
137 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400138 const void *indices,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400139 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400140 bool primitiveRestartEnabled,
Jamie Madill876429b2017-04-20 15:46:24 -0400141 const void **outIndices) const
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400142{
Jamie Madill77a90c22015-08-11 16:33:17 -0400143 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400144
Shao80957d92017-02-20 21:25:59 +0800145 // Check if any attributes need to be streamed, determines if the index range needs to be
146 // computed
Jamie Madill0b9e9032015-08-17 11:51:52 +0000147 bool attributesNeedStreaming = mAttributesNeedStreaming.any();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400148
Shao80957d92017-02-20 21:25:59 +0800149 // Determine if an index buffer needs to be streamed and the range of vertices that need to be
150 // copied
Geoff Lang3edfe032015-09-04 16:38:24 -0400151 IndexRange indexRange;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400152 if (type != GL_NONE)
Geoff Langba4c4a82015-02-24 12:38:46 -0500153 {
Geoff Lang3edfe032015-09-04 16:38:24 -0400154 Error error = syncIndexData(count, type, indices, primitiveRestartEnabled,
155 attributesNeedStreaming, &indexRange, outIndices);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400156 if (error.isError())
157 {
158 return error;
159 }
160 }
161 else
162 {
Corentin Wallez2c34a4b2015-08-25 16:26:02 -0400163 // Not an indexed call, set the range to [first, first + count - 1]
Geoff Lang7c82bc42015-03-09 16:18:08 -0400164 indexRange.start = first;
Shao80957d92017-02-20 21:25:59 +0800165 indexRange.end = first + count - 1;
Geoff Langba4c4a82015-02-24 12:38:46 -0500166 }
167
Jamie Madill0b9e9032015-08-17 11:51:52 +0000168 if (attributesNeedStreaming)
Geoff Langba4c4a82015-02-24 12:38:46 -0500169 {
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400170 Error error = streamAttributes(activeAttributesMask, instanceCount, indexRange);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400171 if (error.isError())
172 {
173 return error;
174 }
175 }
176
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500177 return gl::NoError();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400178}
179
Jiajia Qind9671222016-11-29 16:30:31 +0800180gl::Error VertexArrayGL::syncIndexData(GLsizei count,
181 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400182 const void *indices,
Jiajia Qind9671222016-11-29 16:30:31 +0800183 bool primitiveRestartEnabled,
184 bool attributesNeedStreaming,
185 IndexRange *outIndexRange,
Jamie Madill876429b2017-04-20 15:46:24 -0400186 const void **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400187{
188 ASSERT(outIndices);
189
Jamie Madill8e344942015-07-09 14:22:07 -0400190 gl::Buffer *elementArrayBuffer = mData.getElementArrayBuffer().get();
191
Geoff Lang7c82bc42015-03-09 16:18:08 -0400192 // Need to check the range of indices if attributes need to be streamed
Jamie Madill8e344942015-07-09 14:22:07 -0400193 if (elementArrayBuffer != nullptr)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400194 {
Jamie Madill77a90c22015-08-11 16:33:17 -0400195 if (elementArrayBuffer != mAppliedElementArrayBuffer.get())
Geoff Lang7c82bc42015-03-09 16:18:08 -0400196 {
Jamie Madill77a90c22015-08-11 16:33:17 -0400197 const BufferGL *bufferGL = GetImplAs<BufferGL>(elementArrayBuffer);
198 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferGL->getBufferID());
199 mAppliedElementArrayBuffer.set(elementArrayBuffer);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400200 }
201
202 // Only compute the index range if the attributes also need to be streamed
203 if (attributesNeedStreaming)
204 {
205 ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices);
Shao80957d92017-02-20 21:25:59 +0800206 Error error = mData.getElementArrayBuffer()->getIndexRange(
Geoff Lang3edfe032015-09-04 16:38:24 -0400207 type, elementArrayBufferOffset, count, primitiveRestartEnabled, outIndexRange);
Geoff Lang520c4ae2015-05-05 13:12:36 -0400208 if (error.isError())
Geoff Lang7c82bc42015-03-09 16:18:08 -0400209 {
Geoff Lang520c4ae2015-05-05 13:12:36 -0400210 return error;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400211 }
212 }
213
Shao80957d92017-02-20 21:25:59 +0800214 // Indices serves as an offset into the index buffer in this case, use the same value for
215 // the draw call
Geoff Lang7c82bc42015-03-09 16:18:08 -0400216 *outIndices = indices;
217 }
218 else
219 {
220 // Need to stream the index buffer
221 // TODO: if GLES, nothing needs to be streamed
222
223 // Only compute the index range if the attributes also need to be streamed
224 if (attributesNeedStreaming)
225 {
Geoff Lang3edfe032015-09-04 16:38:24 -0400226 *outIndexRange = ComputeIndexRange(type, indices, count, primitiveRestartEnabled);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400227 }
228
229 // Allocate the streaming element array buffer
230 if (mStreamingElementArrayBuffer == 0)
231 {
232 mFunctions->genBuffers(1, &mStreamingElementArrayBuffer);
233 mStreamingElementArrayBufferSize = 0;
234 }
235
236 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, mStreamingElementArrayBuffer);
Jamie Madill77a90c22015-08-11 16:33:17 -0400237 mAppliedElementArrayBuffer.set(nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400238
239 // Make sure the element array buffer is large enough
Jamie Madill0b9e9032015-08-17 11:51:52 +0000240 const Type &indexTypeInfo = GetTypeInfo(type);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400241 size_t requiredStreamingBufferSize = indexTypeInfo.bytes * count;
242 if (requiredStreamingBufferSize > mStreamingElementArrayBufferSize)
243 {
244 // Copy the indices in while resizing the buffer
Shao80957d92017-02-20 21:25:59 +0800245 mFunctions->bufferData(GL_ELEMENT_ARRAY_BUFFER, requiredStreamingBufferSize, indices,
246 GL_DYNAMIC_DRAW);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400247 mStreamingElementArrayBufferSize = requiredStreamingBufferSize;
248 }
249 else
250 {
251 // Put the indices at the beginning of the buffer
Shao80957d92017-02-20 21:25:59 +0800252 mFunctions->bufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, requiredStreamingBufferSize,
253 indices);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400254 }
255
Shao80957d92017-02-20 21:25:59 +0800256 // Set the index offset for the draw call to zero since the supplied index pointer is to
257 // client data
Geoff Lang7c82bc42015-03-09 16:18:08 -0400258 *outIndices = nullptr;
259 }
260
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500261 return gl::NoError();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400262}
263
Jamie Madill0b9e9032015-08-17 11:51:52 +0000264void VertexArrayGL::computeStreamingAttributeSizes(const gl::AttributesMask &activeAttributesMask,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400265 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400266 const gl::IndexRange &indexRange,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000267 size_t *outStreamingDataSize,
268 size_t *outMaxAttributeDataSize) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400269{
Jamie Madill0b9e9032015-08-17 11:51:52 +0000270 *outStreamingDataSize = 0;
271 *outMaxAttributeDataSize = 0;
272
273 ASSERT(mAttributesNeedStreaming.any());
274
Shao80957d92017-02-20 21:25:59 +0800275 const auto &attribs = mData.getVertexAttributes();
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800276 const auto &bindings = mData.getVertexBindings();
Jamie Madill6de51852017-04-12 09:53:01 -0400277
278 gl::AttributesMask attribsToStream = (mAttributesNeedStreaming & activeAttributesMask);
279
280 for (auto idx : attribsToStream)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000281 {
Shao80957d92017-02-20 21:25:59 +0800282 const auto &attrib = attribs[idx];
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800283 const auto &binding = bindings[attrib.bindingIndex];
284 ASSERT(AttributeNeedsStreaming(attrib, binding));
Jamie Madill0b9e9032015-08-17 11:51:52 +0000285
Jamie Madill0b9e9032015-08-17 11:51:52 +0000286 // If streaming is going to be required, compute the size of the required buffer
287 // and how much slack space at the beginning of the buffer will be required by determining
288 // the attribute with the largest data size.
289 size_t typeSize = ComputeVertexAttributeTypeSize(attrib);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800290 *outStreamingDataSize += typeSize * ComputeVertexBindingElementCount(
291 binding, indexRange.vertexCount(), instanceCount);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000292 *outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
293 }
294}
295
296gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &activeAttributesMask,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400297 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400298 const gl::IndexRange &indexRange) const
Jamie Madill0b9e9032015-08-17 11:51:52 +0000299{
300 // Sync the vertex attribute state and track what data needs to be streamed
301 size_t streamingDataSize = 0;
302 size_t maxAttributeDataSize = 0;
303
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400304 computeStreamingAttributeSizes(activeAttributesMask, instanceCount, indexRange,
305 &streamingDataSize, &maxAttributeDataSize);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000306
307 if (streamingDataSize == 0)
308 {
He Yunchaoacd18982017-01-04 10:46:42 +0800309 return gl::NoError();
Jamie Madill0b9e9032015-08-17 11:51:52 +0000310 }
311
Geoff Lang7c82bc42015-03-09 16:18:08 -0400312 if (mStreamingArrayBuffer == 0)
313 {
314 mFunctions->genBuffers(1, &mStreamingArrayBuffer);
315 mStreamingArrayBufferSize = 0;
316 }
317
Shao80957d92017-02-20 21:25:59 +0800318 // If first is greater than zero, a slack space needs to be left at the beginning of the buffer
319 // so that the same 'first' argument can be passed into the draw call.
320 const size_t bufferEmptySpace = maxAttributeDataSize * indexRange.start;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400321 const size_t requiredBufferSize = streamingDataSize + bufferEmptySpace;
322
323 mStateManager->bindBuffer(GL_ARRAY_BUFFER, mStreamingArrayBuffer);
324 if (requiredBufferSize > mStreamingArrayBufferSize)
325 {
326 mFunctions->bufferData(GL_ARRAY_BUFFER, requiredBufferSize, nullptr, GL_DYNAMIC_DRAW);
327 mStreamingArrayBufferSize = requiredBufferSize;
328 }
329
330 // Unmapping a buffer can return GL_FALSE to indicate that the system has corrupted the data
Shao80957d92017-02-20 21:25:59 +0800331 // somehow (such as by a screen change), retry writing the data a few times and return
332 // OUT_OF_MEMORY if that fails.
333 GLboolean unmapResult = GL_FALSE;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400334 size_t unmapRetryAttempts = 5;
335 while (unmapResult != GL_TRUE && --unmapRetryAttempts > 0)
336 {
Geoff Langb2ebb5e2016-06-08 18:17:55 +0000337 uint8_t *bufferPointer = MapBufferRangeWithFallback(mFunctions, GL_ARRAY_BUFFER, 0,
338 requiredBufferSize, GL_MAP_WRITE_BIT);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400339 size_t curBufferOffset = bufferEmptySpace;
340
Shao80957d92017-02-20 21:25:59 +0800341 const auto &attribs = mData.getVertexAttributes();
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800342 const auto &bindings = mData.getVertexBindings();
Jamie Madill6de51852017-04-12 09:53:01 -0400343
344 gl::AttributesMask attribsToStream = (mAttributesNeedStreaming & activeAttributesMask);
345
346 for (auto idx : attribsToStream)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400347 {
Shao80957d92017-02-20 21:25:59 +0800348 const auto &attrib = attribs[idx];
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800349 const auto &binding = bindings[attrib.bindingIndex];
350 ASSERT(AttributeNeedsStreaming(attrib, binding));
Geoff Lang7c82bc42015-03-09 16:18:08 -0400351
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400352 const size_t streamedVertexCount =
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800353 ComputeVertexBindingElementCount(binding, indexRange.vertexCount(), instanceCount);
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400354
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800355 const size_t sourceStride = ComputeVertexAttributeStride(attrib, binding);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000356 const size_t destStride = ComputeVertexAttributeTypeSize(attrib);
357
Geoff Lang38a24a92017-02-15 13:53:06 -0500358 // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing
359 // a non-instanced draw call
Martin Radevdd5f27e2017-06-07 10:17:09 +0300360 const size_t firstIndex = binding.getDivisor() == 0 ? indexRange.start : 0;
Geoff Lang38a24a92017-02-15 13:53:06 -0500361
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800362 // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state.
363 // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt
Jamie Madill0b9e9032015-08-17 11:51:52 +0000364 const uint8_t *inputPointer = reinterpret_cast<const uint8_t *>(attrib.pointer);
365
366 // Pack the data when copying it, user could have supplied a very large stride that
367 // would cause the buffer to be much larger than needed.
368 if (destStride == sourceStride)
Jamie Madill8e344942015-07-09 14:22:07 -0400369 {
Jamie Madill0b9e9032015-08-17 11:51:52 +0000370 // Can copy in one go, the data is packed
Geoff Lang38a24a92017-02-15 13:53:06 -0500371 memcpy(bufferPointer + curBufferOffset, inputPointer + (sourceStride * firstIndex),
Jamie Madill0b9e9032015-08-17 11:51:52 +0000372 destStride * streamedVertexCount);
Jamie Madill6d51c702015-08-14 10:38:10 -0400373 }
Jamie Madill0b9e9032015-08-17 11:51:52 +0000374 else
375 {
376 // Copy each vertex individually
Geoff Lang6b10ddb2015-09-02 15:55:10 -0400377 for (size_t vertexIdx = 0; vertexIdx < streamedVertexCount; vertexIdx++)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000378 {
Shao80957d92017-02-20 21:25:59 +0800379 uint8_t *out = bufferPointer + curBufferOffset + (destStride * vertexIdx);
Geoff Lang38a24a92017-02-15 13:53:06 -0500380 const uint8_t *in = inputPointer + sourceStride * (vertexIdx + firstIndex);
Corentin Wallez4d5362d2015-08-25 11:25:14 -0400381 memcpy(out, in, destStride);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000382 }
383 }
384
385 // Compute where the 0-index vertex would be.
Geoff Lang38a24a92017-02-15 13:53:06 -0500386 const size_t vertexStartOffset = curBufferOffset - (firstIndex * destStride);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000387
Shaodf682a82017-03-31 15:13:21 +0800388 callVertexAttribPointer(static_cast<GLuint>(idx), attrib,
389 static_cast<GLsizei>(destStride),
390 static_cast<GLintptr>(vertexStartOffset));
Jamie Madill0b9e9032015-08-17 11:51:52 +0000391
392 curBufferOffset += destStride * streamedVertexCount;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400393 }
394
395 unmapResult = mFunctions->unmapBuffer(GL_ARRAY_BUFFER);
396 }
397
398 if (unmapResult != GL_TRUE)
399 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500400 return gl::OutOfMemory() << "Failed to unmap the client data streaming buffer.";
Geoff Lang7c82bc42015-03-09 16:18:08 -0400401 }
402
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500403 return gl::NoError();
Geoff Langba4c4a82015-02-24 12:38:46 -0500404}
405
406GLuint VertexArrayGL::getVertexArrayID() const
407{
408 return mVertexArrayID;
Geoff Langf9a6f082015-01-22 13:32:49 -0500409}
410
Geoff Lang294cad92015-05-26 15:11:23 -0400411GLuint VertexArrayGL::getAppliedElementArrayBufferID() const
412{
Jamie Madill77a90c22015-08-11 16:33:17 -0400413 if (mAppliedElementArrayBuffer.get() == nullptr)
414 {
415 return mStreamingElementArrayBuffer;
416 }
417
418 return GetImplAs<BufferGL>(mAppliedElementArrayBuffer.get())->getBufferID();
Geoff Lang294cad92015-05-26 15:11:23 -0400419}
420
Jamie Madill0b9e9032015-08-17 11:51:52 +0000421void VertexArrayGL::updateNeedsStreaming(size_t attribIndex)
422{
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800423 const auto &attrib = mData.getVertexAttribute(attribIndex);
424 const auto &binding = mData.getBindingFromAttribIndex(attribIndex);
425 mAttributesNeedStreaming.set(attribIndex, AttributeNeedsStreaming(attrib, binding));
Geoff Langf9a6f082015-01-22 13:32:49 -0500426}
Jamie Madill0b9e9032015-08-17 11:51:52 +0000427
428void VertexArrayGL::updateAttribEnabled(size_t attribIndex)
429{
Shaodf682a82017-03-31 15:13:21 +0800430 const bool enabled = mData.getVertexAttribute(attribIndex).enabled;
431 if (mAppliedAttributes[attribIndex].enabled == enabled)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000432 {
433 return;
434 }
435
436 updateNeedsStreaming(attribIndex);
437
Shaodf682a82017-03-31 15:13:21 +0800438 if (enabled)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000439 {
440 mFunctions->enableVertexAttribArray(static_cast<GLuint>(attribIndex));
441 }
442 else
443 {
444 mFunctions->disableVertexAttribArray(static_cast<GLuint>(attribIndex));
445 }
Shaodf682a82017-03-31 15:13:21 +0800446
447 mAppliedAttributes[attribIndex].enabled = enabled;
Jamie Madill0b9e9032015-08-17 11:51:52 +0000448}
449
450void VertexArrayGL::updateAttribPointer(size_t attribIndex)
451{
452 const VertexAttribute &attrib = mData.getVertexAttribute(attribIndex);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800453
Shaodf682a82017-03-31 15:13:21 +0800454 // TODO(jiawei.shao@intel.com): Vertex Attrib Binding
455 ASSERT(IsVertexAttribPointerSupported(attribIndex, attrib));
456
457 const GLuint bindingIndex = attrib.bindingIndex;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800458 const VertexBinding &binding = mData.getVertexBinding(bindingIndex);
459
Shaodf682a82017-03-31 15:13:21 +0800460 // We do not need to compare attrib.pointer because when we use a different client memory
461 // pointer, we don't need to update mAttributesNeedStreaming by binding.buffer and we won't
462 // update attribPointer in this function.
463 if (SameVertexAttribFormat(mAppliedAttributes[attribIndex], attrib) &&
464 mAppliedAttributes[attribIndex].bindingIndex == bindingIndex &&
465 SameVertexBuffer(mAppliedBindings[attribIndex], binding))
Jamie Madill0b9e9032015-08-17 11:51:52 +0000466 {
467 return;
468 }
469
470 updateNeedsStreaming(attribIndex);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000471
472 // If we need to stream, defer the attribPointer to the draw call.
Shao4181bc92017-03-17 14:55:25 +0800473 // Skip the attribute that is disabled and uses a client memory pointer.
Martin Radevdd5f27e2017-06-07 10:17:09 +0300474 const Buffer *arrayBuffer = binding.getBuffer().get();
Shao4181bc92017-03-17 14:55:25 +0800475 if (arrayBuffer == nullptr)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000476 {
Shaodf682a82017-03-31 15:13:21 +0800477 // Mark the applied binding is using a client memory pointer by setting its buffer to
478 // nullptr so that if it doesn't use a client memory pointer later, there is no chance that
479 // the caching will skip it.
Martin Radevdd5f27e2017-06-07 10:17:09 +0300480 mAppliedBindings[bindingIndex].setBuffer(nullptr);
Shao4181bc92017-03-17 14:55:25 +0800481 return;
Jamie Madill0b9e9032015-08-17 11:51:52 +0000482 }
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800483
Shao4181bc92017-03-17 14:55:25 +0800484 // Since ANGLE always uses a non-zero VAO, we cannot use a client memory pointer on it:
485 // [OpenGL ES 3.0.2] Section 2.8 page 24:
486 // An INVALID_OPERATION error is generated when a non-zero vertex array object is bound,
487 // zero is bound to the ARRAY_BUFFER buffer object binding point, and the pointer argument
488 // is not NULL.
Shaodf682a82017-03-31 15:13:21 +0800489
Shao4181bc92017-03-17 14:55:25 +0800490 const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
491 mStateManager->bindBuffer(GL_ARRAY_BUFFER, arrayBufferGL->getBufferID());
Jamie Madill0b9e9032015-08-17 11:51:52 +0000492
Martin Radevdd5f27e2017-06-07 10:17:09 +0300493 callVertexAttribPointer(static_cast<GLuint>(attribIndex), attrib, binding.getStride(),
494 binding.getOffset());
Shaodf682a82017-03-31 15:13:21 +0800495
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800496 mAppliedAttributes[attribIndex].size = attrib.size;
497 mAppliedAttributes[attribIndex].type = attrib.type;
498 mAppliedAttributes[attribIndex].normalized = attrib.normalized;
499 mAppliedAttributes[attribIndex].pureInteger = attrib.pureInteger;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800500 mAppliedAttributes[attribIndex].relativeOffset = attrib.relativeOffset;
Shaodf682a82017-03-31 15:13:21 +0800501
502 mAppliedAttributes[attribIndex].bindingIndex = bindingIndex;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800503
Martin Radevdd5f27e2017-06-07 10:17:09 +0300504 mAppliedBindings[bindingIndex].setStride(binding.getStride());
505 mAppliedBindings[bindingIndex].setOffset(binding.getOffset());
506 mAppliedBindings[bindingIndex].setBuffer(binding.getBuffer().get());
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800507}
508
Shaodf682a82017-03-31 15:13:21 +0800509void VertexArrayGL::callVertexAttribPointer(GLuint attribIndex,
510 const VertexAttribute &attrib,
511 GLsizei stride,
512 GLintptr offset) const
513{
514 const GLvoid *pointer = reinterpret_cast<const GLvoid *>(offset);
515 if (attrib.pureInteger)
516 {
517 ASSERT(!attrib.normalized);
518 mFunctions->vertexAttribIPointer(attribIndex, attrib.size, attrib.type, stride, pointer);
519 }
520 else
521 {
522 mFunctions->vertexAttribPointer(attribIndex, attrib.size, attrib.type, attrib.normalized,
523 stride, pointer);
524 }
525}
526
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800527void VertexArrayGL::updateAttribDivisor(size_t attribIndex)
528{
Shaodf682a82017-03-31 15:13:21 +0800529 const GLuint bindingIndex = mData.getVertexAttribute(attribIndex).bindingIndex;
530 ASSERT(attribIndex == bindingIndex);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800531
Martin Radevdd5f27e2017-06-07 10:17:09 +0300532 const GLuint divisor = mData.getVertexBinding(bindingIndex).getDivisor();
Shaodf682a82017-03-31 15:13:21 +0800533 if (mAppliedAttributes[attribIndex].bindingIndex == bindingIndex &&
Martin Radevdd5f27e2017-06-07 10:17:09 +0300534 mAppliedBindings[bindingIndex].getDivisor() == divisor)
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800535 {
Shaodf682a82017-03-31 15:13:21 +0800536 return;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800537 }
Shaodf682a82017-03-31 15:13:21 +0800538
539 mFunctions->vertexAttribDivisor(static_cast<GLuint>(attribIndex), divisor);
540
541 mAppliedAttributes[attribIndex].bindingIndex = bindingIndex;
Martin Radevdd5f27e2017-06-07 10:17:09 +0300542 mAppliedBindings[bindingIndex].setDivisor(divisor);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000543}
544
Jamie Madillc564c072017-06-01 12:45:42 -0400545void VertexArrayGL::syncState(const gl::Context *context, const VertexArray::DirtyBits &dirtyBits)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000546{
Shaodf682a82017-03-31 15:13:21 +0800547 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
548
Jamie Madill6de51852017-04-12 09:53:01 -0400549 for (size_t dirtyBit : dirtyBits)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000550 {
551 if (dirtyBit == VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER)
552 {
553 // TODO(jmadill): Element array buffer bindings
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800554 continue;
Jamie Madill0b9e9032015-08-17 11:51:52 +0000555 }
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800556
557 size_t index = VertexArray::GetAttribIndex(dirtyBit);
558 if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_ENABLED &&
559 dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_ENABLED)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000560 {
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800561 updateAttribEnabled(index);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000562 }
563 else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_POINTER &&
564 dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_POINTER)
565 {
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800566 updateAttribPointer(index);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000567 }
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800568 else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_FORMAT &&
569 dirtyBit < VertexArray::DIRTY_BIT_BINDING_MAX_BUFFER)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000570 {
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800571 // TODO(jiawei.shao@intel.com): Vertex Attrib Bindings
572 ASSERT(index == mData.getBindingIndexFromAttribIndex(index));
573 }
574 else if (dirtyBit >= VertexArray::DIRTY_BIT_BINDING_0_DIVISOR &&
575 dirtyBit < VertexArray::DIRTY_BIT_BINDING_MAX_DIVISOR)
576 {
577 updateAttribDivisor(index);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000578 }
579 else
580 UNREACHABLE();
581 }
582}
583
584} // rx