blob: 74967330f7bae6dede7c1bc814e9295840541763 [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}
Martin Radev553590a2017-07-31 16:40:39 +030051
52GLuint GetAdjustedDivisor(GLuint numViews, GLuint divisor)
53{
54 return numViews * divisor;
55}
56
Jamie Madill0b9e9032015-08-17 11:51:52 +000057} // anonymous namespace
58
Jamie Madill3f572682016-04-26 13:41:36 -040059VertexArrayGL::VertexArrayGL(const VertexArrayState &state,
Jamie Madill77a90c22015-08-11 16:33:17 -040060 const FunctionsGL *functions,
61 StateManagerGL *stateManager)
Jamie Madill3f572682016-04-26 13:41:36 -040062 : VertexArrayImpl(state),
Geoff Langba4c4a82015-02-24 12:38:46 -050063 mFunctions(functions),
64 mStateManager(stateManager),
65 mVertexArrayID(0),
Martin Radev553590a2017-07-31 16:40:39 +030066 mAppliedNumViews(1),
Jamie Madill77a90c22015-08-11 16:33:17 -040067 mAppliedElementArrayBuffer(),
Jiawei-Shao2597fb62016-12-09 16:38:02 +080068 mAppliedBindings(state.getMaxBindings()),
Geoff Lang7c82bc42015-03-09 16:18:08 -040069 mStreamingElementArrayBufferSize(0),
70 mStreamingElementArrayBuffer(0),
71 mStreamingArrayBufferSize(0),
72 mStreamingArrayBuffer(0)
Geoff Langba4c4a82015-02-24 12:38:46 -050073{
74 ASSERT(mFunctions);
75 ASSERT(mStateManager);
76 mFunctions->genVertexArrays(1, &mVertexArrayID);
77
Jiawei-Shao2597fb62016-12-09 16:38:02 +080078 // Set the cached vertex attribute array and vertex attribute binding array size
79 GLuint maxVertexAttribs = static_cast<GLuint>(state.getMaxAttribs());
80 for (GLuint i = 0; i < maxVertexAttribs; i++)
81 {
82 mAppliedAttributes.emplace_back(i);
83 }
Geoff Langba4c4a82015-02-24 12:38:46 -050084}
Geoff Langf9a6f082015-01-22 13:32:49 -050085
Jamie Madillacf2f3a2017-11-21 19:22:44 -050086VertexArrayGL::~VertexArrayGL()
87{
88}
89
Jamie Madill4928b7c2017-06-20 12:57:39 -040090void VertexArrayGL::destroy(const gl::Context *context)
Geoff Langba4c4a82015-02-24 12:38:46 -050091{
Geoff Lang1eb708e2015-05-04 14:58:23 -040092 mStateManager->deleteVertexArray(mVertexArrayID);
93 mVertexArrayID = 0;
Martin Radev553590a2017-07-31 16:40:39 +030094 mAppliedNumViews = 1;
Geoff Langba4c4a82015-02-24 12:38:46 -050095
Geoff Lang1eb708e2015-05-04 14:58:23 -040096 mStateManager->deleteBuffer(mStreamingElementArrayBuffer);
97 mStreamingElementArrayBufferSize = 0;
Shao80957d92017-02-20 21:25:59 +080098 mStreamingElementArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040099
Geoff Lang1eb708e2015-05-04 14:58:23 -0400100 mStateManager->deleteBuffer(mStreamingArrayBuffer);
101 mStreamingArrayBufferSize = 0;
Shao80957d92017-02-20 21:25:59 +0800102 mStreamingArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400103
Jamie Madill4928b7c2017-06-20 12:57:39 -0400104 mAppliedElementArrayBuffer.set(context, nullptr);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800105 for (auto &binding : mAppliedBindings)
Geoff Langba4c4a82015-02-24 12:38:46 -0500106 {
James Darpiniane8a93c62018-01-04 18:02:24 -0800107 binding.setBuffer(context, nullptr, false);
Geoff Langba4c4a82015-02-24 12:38:46 -0500108 }
109}
Geoff Langf9a6f082015-01-22 13:32:49 -0500110
Jamie Madill4928b7c2017-06-20 12:57:39 -0400111gl::Error VertexArrayGL::syncDrawArraysState(const gl::Context *context,
112 const gl::AttributesMask &activeAttributesMask,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000113 GLint first,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400114 GLsizei count,
115 GLsizei instanceCount) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400116{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400117 return syncDrawState(context, activeAttributesMask, first, count, GL_NONE, nullptr,
118 instanceCount, false, nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400119}
120
Jamie Madill4928b7c2017-06-20 12:57:39 -0400121gl::Error VertexArrayGL::syncDrawElementsState(const gl::Context *context,
122 const gl::AttributesMask &activeAttributesMask,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000123 GLsizei count,
124 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400125 const void *indices,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400126 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400127 bool primitiveRestartEnabled,
Jamie Madill876429b2017-04-20 15:46:24 -0400128 const void **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400129{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400130 return syncDrawState(context, activeAttributesMask, 0, count, type, indices, instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400131 primitiveRestartEnabled, outIndices);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400132}
133
Jiajia Qin47474142017-12-29 13:41:00 +0800134void VertexArrayGL::updateElementArrayBufferBinding(const gl::Context *context) const
Jiajia Qind9671222016-11-29 16:30:31 +0800135{
Jamie Madill492f58e2017-10-09 19:41:33 -0400136 gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer().get();
Jiajia Qin47474142017-12-29 13:41:00 +0800137 if (elementArrayBuffer != nullptr && elementArrayBuffer != mAppliedElementArrayBuffer.get())
Jiajia Qind9671222016-11-29 16:30:31 +0800138 {
139 const BufferGL *bufferGL = GetImplAs<BufferGL>(elementArrayBuffer);
Corentin Wallez336129f2017-10-17 15:55:40 -0400140 mStateManager->bindBuffer(gl::BufferBinding::ElementArray, bufferGL->getBufferID());
Jamie Madill4928b7c2017-06-20 12:57:39 -0400141 mAppliedElementArrayBuffer.set(context, elementArrayBuffer);
Jiajia Qind9671222016-11-29 16:30:31 +0800142 }
Jiajia Qind9671222016-11-29 16:30:31 +0800143}
144
Jamie Madill4928b7c2017-06-20 12:57:39 -0400145gl::Error VertexArrayGL::syncDrawState(const gl::Context *context,
146 const gl::AttributesMask &activeAttributesMask,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000147 GLint first,
148 GLsizei count,
149 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400150 const void *indices,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400151 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400152 bool primitiveRestartEnabled,
Jamie Madill876429b2017-04-20 15:46:24 -0400153 const void **outIndices) const
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400154{
Shao80957d92017-02-20 21:25:59 +0800155 // Check if any attributes need to be streamed, determines if the index range needs to be
156 // computed
Jamie Madill0b9e9032015-08-17 11:51:52 +0000157 bool attributesNeedStreaming = mAttributesNeedStreaming.any();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400158
Shao80957d92017-02-20 21:25:59 +0800159 // Determine if an index buffer needs to be streamed and the range of vertices that need to be
160 // copied
Geoff Lang3edfe032015-09-04 16:38:24 -0400161 IndexRange indexRange;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400162 if (type != GL_NONE)
Geoff Langba4c4a82015-02-24 12:38:46 -0500163 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400164 ANGLE_TRY(syncIndexData(context, count, type, indices, primitiveRestartEnabled,
165 attributesNeedStreaming, &indexRange, outIndices));
Geoff Lang7c82bc42015-03-09 16:18:08 -0400166 }
167 else
168 {
Corentin Wallez2c34a4b2015-08-25 16:26:02 -0400169 // Not an indexed call, set the range to [first, first + count - 1]
Geoff Lang7c82bc42015-03-09 16:18:08 -0400170 indexRange.start = first;
Shao80957d92017-02-20 21:25:59 +0800171 indexRange.end = first + count - 1;
Geoff Langba4c4a82015-02-24 12:38:46 -0500172 }
173
Jamie Madill0b9e9032015-08-17 11:51:52 +0000174 if (attributesNeedStreaming)
Geoff Langba4c4a82015-02-24 12:38:46 -0500175 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400176 ANGLE_TRY(streamAttributes(activeAttributesMask, instanceCount, indexRange));
Geoff Lang7c82bc42015-03-09 16:18:08 -0400177 }
178
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500179 return gl::NoError();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400180}
181
Jamie Madill4928b7c2017-06-20 12:57:39 -0400182gl::Error VertexArrayGL::syncIndexData(const gl::Context *context,
183 GLsizei count,
Jiajia Qind9671222016-11-29 16:30:31 +0800184 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400185 const void *indices,
Jiajia Qind9671222016-11-29 16:30:31 +0800186 bool primitiveRestartEnabled,
187 bool attributesNeedStreaming,
188 IndexRange *outIndexRange,
Jamie Madill876429b2017-04-20 15:46:24 -0400189 const void **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400190{
191 ASSERT(outIndices);
192
Jamie Madill492f58e2017-10-09 19:41:33 -0400193 gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer().get();
Jamie Madill8e344942015-07-09 14:22:07 -0400194
Geoff Lang7c82bc42015-03-09 16:18:08 -0400195 // Need to check the range of indices if attributes need to be streamed
Jamie Madill8e344942015-07-09 14:22:07 -0400196 if (elementArrayBuffer != nullptr)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400197 {
Jiajia Qin47474142017-12-29 13:41:00 +0800198 ASSERT(elementArrayBuffer == mAppliedElementArrayBuffer.get());
Geoff Lang7c82bc42015-03-09 16:18:08 -0400199 // Only compute the index range if the attributes also need to be streamed
200 if (attributesNeedStreaming)
201 {
202 ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices);
Jamie Madill492f58e2017-10-09 19:41:33 -0400203 Error error = mState.getElementArrayBuffer()->getIndexRange(
Jamie Madill33510102017-09-20 10:39:18 -0400204 context, type, elementArrayBufferOffset, count, primitiveRestartEnabled,
205 outIndexRange);
Geoff Lang520c4ae2015-05-05 13:12:36 -0400206 if (error.isError())
Geoff Lang7c82bc42015-03-09 16:18:08 -0400207 {
Geoff Lang520c4ae2015-05-05 13:12:36 -0400208 return error;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400209 }
210 }
211
Shao80957d92017-02-20 21:25:59 +0800212 // Indices serves as an offset into the index buffer in this case, use the same value for
213 // the draw call
Geoff Lang7c82bc42015-03-09 16:18:08 -0400214 *outIndices = indices;
215 }
216 else
217 {
218 // Need to stream the index buffer
219 // TODO: if GLES, nothing needs to be streamed
220
221 // Only compute the index range if the attributes also need to be streamed
222 if (attributesNeedStreaming)
223 {
Geoff Lang3edfe032015-09-04 16:38:24 -0400224 *outIndexRange = ComputeIndexRange(type, indices, count, primitiveRestartEnabled);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400225 }
226
227 // Allocate the streaming element array buffer
228 if (mStreamingElementArrayBuffer == 0)
229 {
230 mFunctions->genBuffers(1, &mStreamingElementArrayBuffer);
231 mStreamingElementArrayBufferSize = 0;
232 }
233
Geoff Lang5f3047c2018-02-14 14:39:12 -0500234 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
235
Corentin Wallez336129f2017-10-17 15:55:40 -0400236 mStateManager->bindBuffer(gl::BufferBinding::ElementArray, mStreamingElementArrayBuffer);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400237 mAppliedElementArrayBuffer.set(context, 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
Jamie Madill492f58e2017-10-09 19:41:33 -0400275 const auto &attribs = mState.getVertexAttributes();
276 const auto &bindings = mState.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);
Martin Radev553590a2017-07-31 16:40:39 +0300290 GLuint adjustedDivisor = GetAdjustedDivisor(mAppliedNumViews, binding.getDivisor());
291 *outStreamingDataSize +=
292 typeSize * ComputeVertexBindingElementCount(adjustedDivisor, indexRange.vertexCount(),
293 instanceCount);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000294 *outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
295 }
296}
297
298gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &activeAttributesMask,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400299 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400300 const gl::IndexRange &indexRange) const
Jamie Madill0b9e9032015-08-17 11:51:52 +0000301{
302 // Sync the vertex attribute state and track what data needs to be streamed
303 size_t streamingDataSize = 0;
304 size_t maxAttributeDataSize = 0;
305
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400306 computeStreamingAttributeSizes(activeAttributesMask, instanceCount, indexRange,
307 &streamingDataSize, &maxAttributeDataSize);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000308
309 if (streamingDataSize == 0)
310 {
He Yunchaoacd18982017-01-04 10:46:42 +0800311 return gl::NoError();
Jamie Madill0b9e9032015-08-17 11:51:52 +0000312 }
313
Geoff Lang7c82bc42015-03-09 16:18:08 -0400314 if (mStreamingArrayBuffer == 0)
315 {
316 mFunctions->genBuffers(1, &mStreamingArrayBuffer);
317 mStreamingArrayBufferSize = 0;
318 }
319
Shao80957d92017-02-20 21:25:59 +0800320 // If first is greater than zero, a slack space needs to be left at the beginning of the buffer
321 // so that the same 'first' argument can be passed into the draw call.
322 const size_t bufferEmptySpace = maxAttributeDataSize * indexRange.start;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400323 const size_t requiredBufferSize = streamingDataSize + bufferEmptySpace;
324
Corentin Wallez336129f2017-10-17 15:55:40 -0400325 mStateManager->bindBuffer(gl::BufferBinding::Array, mStreamingArrayBuffer);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400326 if (requiredBufferSize > mStreamingArrayBufferSize)
327 {
328 mFunctions->bufferData(GL_ARRAY_BUFFER, requiredBufferSize, nullptr, GL_DYNAMIC_DRAW);
329 mStreamingArrayBufferSize = requiredBufferSize;
330 }
331
Geoff Lang5f3047c2018-02-14 14:39:12 -0500332 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
333
Geoff Lang7c82bc42015-03-09 16:18:08 -0400334 // Unmapping a buffer can return GL_FALSE to indicate that the system has corrupted the data
Shao80957d92017-02-20 21:25:59 +0800335 // somehow (such as by a screen change), retry writing the data a few times and return
336 // OUT_OF_MEMORY if that fails.
337 GLboolean unmapResult = GL_FALSE;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400338 size_t unmapRetryAttempts = 5;
339 while (unmapResult != GL_TRUE && --unmapRetryAttempts > 0)
340 {
Geoff Langb2ebb5e2016-06-08 18:17:55 +0000341 uint8_t *bufferPointer = MapBufferRangeWithFallback(mFunctions, GL_ARRAY_BUFFER, 0,
342 requiredBufferSize, GL_MAP_WRITE_BIT);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400343 size_t curBufferOffset = bufferEmptySpace;
344
Jamie Madill492f58e2017-10-09 19:41:33 -0400345 const auto &attribs = mState.getVertexAttributes();
346 const auto &bindings = mState.getVertexBindings();
Jamie Madill6de51852017-04-12 09:53:01 -0400347
348 gl::AttributesMask attribsToStream = (mAttributesNeedStreaming & activeAttributesMask);
349
350 for (auto idx : attribsToStream)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400351 {
Shao80957d92017-02-20 21:25:59 +0800352 const auto &attrib = attribs[idx];
Shaodde78e82017-05-22 14:13:27 +0800353 ASSERT(IsVertexAttribPointerSupported(idx, attrib));
354
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800355 const auto &binding = bindings[attrib.bindingIndex];
356 ASSERT(AttributeNeedsStreaming(attrib, binding));
Geoff Lang7c82bc42015-03-09 16:18:08 -0400357
Martin Radev553590a2017-07-31 16:40:39 +0300358 GLuint adjustedDivisor = GetAdjustedDivisor(mAppliedNumViews, binding.getDivisor());
359 const size_t streamedVertexCount = ComputeVertexBindingElementCount(
360 adjustedDivisor, indexRange.vertexCount(), instanceCount);
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400361
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800362 const size_t sourceStride = ComputeVertexAttributeStride(attrib, binding);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000363 const size_t destStride = ComputeVertexAttributeTypeSize(attrib);
364
Geoff Lang38a24a92017-02-15 13:53:06 -0500365 // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing
366 // a non-instanced draw call
Martin Radev553590a2017-07-31 16:40:39 +0300367 const size_t firstIndex = adjustedDivisor == 0 ? indexRange.start : 0;
Geoff Lang38a24a92017-02-15 13:53:06 -0500368
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800369 // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state.
370 // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt
Jamie Madill0b9e9032015-08-17 11:51:52 +0000371 const uint8_t *inputPointer = reinterpret_cast<const uint8_t *>(attrib.pointer);
372
373 // Pack the data when copying it, user could have supplied a very large stride that
374 // would cause the buffer to be much larger than needed.
375 if (destStride == sourceStride)
Jamie Madill8e344942015-07-09 14:22:07 -0400376 {
Jamie Madill0b9e9032015-08-17 11:51:52 +0000377 // Can copy in one go, the data is packed
Geoff Lang38a24a92017-02-15 13:53:06 -0500378 memcpy(bufferPointer + curBufferOffset, inputPointer + (sourceStride * firstIndex),
Jamie Madill0b9e9032015-08-17 11:51:52 +0000379 destStride * streamedVertexCount);
Jamie Madill6d51c702015-08-14 10:38:10 -0400380 }
Jamie Madill0b9e9032015-08-17 11:51:52 +0000381 else
382 {
383 // Copy each vertex individually
Geoff Lang6b10ddb2015-09-02 15:55:10 -0400384 for (size_t vertexIdx = 0; vertexIdx < streamedVertexCount; vertexIdx++)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000385 {
Shao80957d92017-02-20 21:25:59 +0800386 uint8_t *out = bufferPointer + curBufferOffset + (destStride * vertexIdx);
Geoff Lang38a24a92017-02-15 13:53:06 -0500387 const uint8_t *in = inputPointer + sourceStride * (vertexIdx + firstIndex);
Corentin Wallez4d5362d2015-08-25 11:25:14 -0400388 memcpy(out, in, destStride);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000389 }
390 }
391
392 // Compute where the 0-index vertex would be.
Geoff Lang38a24a92017-02-15 13:53:06 -0500393 const size_t vertexStartOffset = curBufferOffset - (firstIndex * destStride);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000394
Shaodf682a82017-03-31 15:13:21 +0800395 callVertexAttribPointer(static_cast<GLuint>(idx), attrib,
396 static_cast<GLsizei>(destStride),
397 static_cast<GLintptr>(vertexStartOffset));
Jamie Madill0b9e9032015-08-17 11:51:52 +0000398
399 curBufferOffset += destStride * streamedVertexCount;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400400 }
401
402 unmapResult = mFunctions->unmapBuffer(GL_ARRAY_BUFFER);
403 }
404
405 if (unmapResult != GL_TRUE)
406 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500407 return gl::OutOfMemory() << "Failed to unmap the client data streaming buffer.";
Geoff Lang7c82bc42015-03-09 16:18:08 -0400408 }
409
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500410 return gl::NoError();
Geoff Langba4c4a82015-02-24 12:38:46 -0500411}
412
413GLuint VertexArrayGL::getVertexArrayID() const
414{
415 return mVertexArrayID;
Geoff Langf9a6f082015-01-22 13:32:49 -0500416}
417
Geoff Lang294cad92015-05-26 15:11:23 -0400418GLuint VertexArrayGL::getAppliedElementArrayBufferID() const
419{
Jamie Madill77a90c22015-08-11 16:33:17 -0400420 if (mAppliedElementArrayBuffer.get() == nullptr)
421 {
422 return mStreamingElementArrayBuffer;
423 }
424
425 return GetImplAs<BufferGL>(mAppliedElementArrayBuffer.get())->getBufferID();
Geoff Lang294cad92015-05-26 15:11:23 -0400426}
427
Jamie Madill0b9e9032015-08-17 11:51:52 +0000428void VertexArrayGL::updateNeedsStreaming(size_t attribIndex)
429{
Jamie Madill492f58e2017-10-09 19:41:33 -0400430 const auto &attrib = mState.getVertexAttribute(attribIndex);
431 const auto &binding = mState.getBindingFromAttribIndex(attribIndex);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800432 mAttributesNeedStreaming.set(attribIndex, AttributeNeedsStreaming(attrib, binding));
Geoff Langf9a6f082015-01-22 13:32:49 -0500433}
Jamie Madill0b9e9032015-08-17 11:51:52 +0000434
435void VertexArrayGL::updateAttribEnabled(size_t attribIndex)
436{
Jamie Madill492f58e2017-10-09 19:41:33 -0400437 const bool enabled = mState.getVertexAttribute(attribIndex).enabled;
Shaodf682a82017-03-31 15:13:21 +0800438 if (mAppliedAttributes[attribIndex].enabled == enabled)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000439 {
440 return;
441 }
442
443 updateNeedsStreaming(attribIndex);
444
Shaodf682a82017-03-31 15:13:21 +0800445 if (enabled)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000446 {
447 mFunctions->enableVertexAttribArray(static_cast<GLuint>(attribIndex));
448 }
449 else
450 {
451 mFunctions->disableVertexAttribArray(static_cast<GLuint>(attribIndex));
452 }
Shaodf682a82017-03-31 15:13:21 +0800453
454 mAppliedAttributes[attribIndex].enabled = enabled;
Jamie Madill0b9e9032015-08-17 11:51:52 +0000455}
456
Jamie Madill4928b7c2017-06-20 12:57:39 -0400457void VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attribIndex)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000458{
Jamie Madill492f58e2017-10-09 19:41:33 -0400459 const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800460
Shaodde78e82017-05-22 14:13:27 +0800461 // According to SPEC, VertexAttribPointer should update the binding indexed attribIndex instead
462 // of the binding indexed attrib.bindingIndex (unless attribIndex == attrib.bindingIndex).
Jamie Madill492f58e2017-10-09 19:41:33 -0400463 const VertexBinding &binding = mState.getVertexBinding(attribIndex);
Shaodf682a82017-03-31 15:13:21 +0800464
Shaodde78e82017-05-22 14:13:27 +0800465 // Since mAttributesNeedStreaming[attribIndex] keeps the value set in the last draw, here we
466 // only need to update it when the buffer has been changed. e.g. When we set an attribute to be
467 // streamed in the last draw, and only change its format in this draw without calling
468 // updateNeedsStreaming, it will still be streamed because the flag is already on.
469 const auto &bindingBuffer = binding.getBuffer();
470 if (bindingBuffer != mAppliedBindings[attribIndex].getBuffer())
471 {
472 updateNeedsStreaming(attribIndex);
473 }
474
475 // Early return when the vertex attribute isn't using a buffer object:
476 // - If we need to stream, defer the attribPointer to the draw call.
477 // - Skip the attribute that is disabled and uses a client memory pointer.
478 // - Skip the attribute whose buffer is detached by BindVertexBuffer. Since it cannot have a
479 // client memory pointer either, it must be disabled and shouldn't affect the draw.
480 const Buffer *arrayBuffer = bindingBuffer.get();
481 if (arrayBuffer == nullptr)
482 {
483 // Mark the applied binding isn't using a buffer by setting its buffer to nullptr so that if
484 // it starts to use a buffer later, there is no chance that the caching will skip it.
James Darpiniane8a93c62018-01-04 18:02:24 -0800485 mAppliedBindings[attribIndex].setBuffer(context, nullptr, false);
Shaodde78e82017-05-22 14:13:27 +0800486 return;
487 }
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800488
Shaodf682a82017-03-31 15:13:21 +0800489 // We do not need to compare attrib.pointer because when we use a different client memory
490 // pointer, we don't need to update mAttributesNeedStreaming by binding.buffer and we won't
491 // update attribPointer in this function.
Shaodde78e82017-05-22 14:13:27 +0800492 if ((SameVertexAttribFormat(mAppliedAttributes[attribIndex], attrib)) &&
493 (mAppliedAttributes[attribIndex].bindingIndex == attrib.bindingIndex) &&
494 (SameVertexBuffer(mAppliedBindings[attribIndex], binding)))
Jamie Madill0b9e9032015-08-17 11:51:52 +0000495 {
496 return;
497 }
498
Shao4181bc92017-03-17 14:55:25 +0800499 // Since ANGLE always uses a non-zero VAO, we cannot use a client memory pointer on it:
500 // [OpenGL ES 3.0.2] Section 2.8 page 24:
501 // An INVALID_OPERATION error is generated when a non-zero vertex array object is bound,
502 // zero is bound to the ARRAY_BUFFER buffer object binding point, and the pointer argument
503 // is not NULL.
Shaodf682a82017-03-31 15:13:21 +0800504
Shao4181bc92017-03-17 14:55:25 +0800505 const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
Corentin Wallez336129f2017-10-17 15:55:40 -0400506 mStateManager->bindBuffer(gl::BufferBinding::Array, arrayBufferGL->getBufferID());
Martin Radevdd5f27e2017-06-07 10:17:09 +0300507 callVertexAttribPointer(static_cast<GLuint>(attribIndex), attrib, binding.getStride(),
508 binding.getOffset());
Shaodf682a82017-03-31 15:13:21 +0800509
Shaodde78e82017-05-22 14:13:27 +0800510 mAppliedAttributes[attribIndex].size = attrib.size;
511 mAppliedAttributes[attribIndex].type = attrib.type;
512 mAppliedAttributes[attribIndex].normalized = attrib.normalized;
513 mAppliedAttributes[attribIndex].pureInteger = attrib.pureInteger;
Shaodf682a82017-03-31 15:13:21 +0800514
Shaodde78e82017-05-22 14:13:27 +0800515 // After VertexAttribPointer, attrib.relativeOffset is set to 0 and attrib.bindingIndex is set
516 // to attribIndex in driver. If attrib.relativeOffset != 0 or attrib.bindingIndex !=
517 // attribIndex, they should be set in updateAttribFormat and updateAttribBinding. The cache
518 // should be consistent with driver so that we won't miss anything.
519 mAppliedAttributes[attribIndex].relativeOffset = 0;
520 mAppliedAttributes[attribIndex].bindingIndex = static_cast<GLuint>(attribIndex);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800521
Shaodde78e82017-05-22 14:13:27 +0800522 mAppliedBindings[attribIndex].setStride(binding.getStride());
523 mAppliedBindings[attribIndex].setOffset(binding.getOffset());
James Darpiniane8a93c62018-01-04 18:02:24 -0800524 mAppliedBindings[attribIndex].setBuffer(context, binding.getBuffer().get(), false);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800525}
526
Shaodf682a82017-03-31 15:13:21 +0800527void VertexArrayGL::callVertexAttribPointer(GLuint attribIndex,
528 const VertexAttribute &attrib,
529 GLsizei stride,
530 GLintptr offset) const
531{
532 const GLvoid *pointer = reinterpret_cast<const GLvoid *>(offset);
533 if (attrib.pureInteger)
534 {
535 ASSERT(!attrib.normalized);
536 mFunctions->vertexAttribIPointer(attribIndex, attrib.size, attrib.type, stride, pointer);
537 }
538 else
539 {
540 mFunctions->vertexAttribPointer(attribIndex, attrib.size, attrib.type, attrib.normalized,
541 stride, pointer);
542 }
543}
544
Shaodde78e82017-05-22 14:13:27 +0800545bool VertexArrayGL::supportVertexAttribBinding() const
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800546{
Shaodde78e82017-05-22 14:13:27 +0800547 ASSERT(mFunctions);
548 return (mFunctions->vertexAttribBinding != nullptr);
549}
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800550
Shaodde78e82017-05-22 14:13:27 +0800551void VertexArrayGL::updateAttribFormat(size_t attribIndex)
552{
553 ASSERT(supportVertexAttribBinding());
554
Jamie Madill492f58e2017-10-09 19:41:33 -0400555 const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
Shaodde78e82017-05-22 14:13:27 +0800556 if (SameVertexAttribFormat(mAppliedAttributes[attribIndex], attrib))
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800557 {
Shaodf682a82017-03-31 15:13:21 +0800558 return;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800559 }
Shaodf682a82017-03-31 15:13:21 +0800560
Shaodde78e82017-05-22 14:13:27 +0800561 if (attrib.pureInteger)
562 {
563 ASSERT(!attrib.normalized);
564 mFunctions->vertexAttribIFormat(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
565 attrib.relativeOffset);
566 }
567 else
568 {
569 mFunctions->vertexAttribFormat(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
570 attrib.normalized, attrib.relativeOffset);
571 }
572
573 mAppliedAttributes[attribIndex].size = attrib.size;
574 mAppliedAttributes[attribIndex].type = attrib.type;
575 mAppliedAttributes[attribIndex].normalized = attrib.normalized;
576 mAppliedAttributes[attribIndex].pureInteger = attrib.pureInteger;
577 mAppliedAttributes[attribIndex].relativeOffset = attrib.relativeOffset;
578}
579
580void VertexArrayGL::updateAttribBinding(size_t attribIndex)
581{
582 ASSERT(supportVertexAttribBinding());
583
Jamie Madill492f58e2017-10-09 19:41:33 -0400584 GLuint bindingIndex = mState.getVertexAttribute(attribIndex).bindingIndex;
Shaodde78e82017-05-22 14:13:27 +0800585 if (mAppliedAttributes[attribIndex].bindingIndex == bindingIndex)
586 {
587 return;
588 }
589
590 mFunctions->vertexAttribBinding(static_cast<GLuint>(attribIndex), bindingIndex);
Shaodf682a82017-03-31 15:13:21 +0800591
592 mAppliedAttributes[attribIndex].bindingIndex = bindingIndex;
Shaodde78e82017-05-22 14:13:27 +0800593}
594
595void VertexArrayGL::updateBindingBuffer(const gl::Context *context, size_t bindingIndex)
596{
597 ASSERT(supportVertexAttribBinding());
598
Jamie Madill492f58e2017-10-09 19:41:33 -0400599 const VertexBinding &binding = mState.getVertexBinding(bindingIndex);
Shaodde78e82017-05-22 14:13:27 +0800600 if (SameVertexBuffer(mAppliedBindings[bindingIndex], binding))
601 {
602 return;
603 }
604
605 const Buffer *arrayBuffer = binding.getBuffer().get();
606 GLuint bufferId = 0;
607 if (arrayBuffer != nullptr)
608 {
609 bufferId = GetImplAs<BufferGL>(arrayBuffer)->getBufferID();
610 }
611
612 mFunctions->bindVertexBuffer(static_cast<GLuint>(bindingIndex), bufferId, binding.getOffset(),
613 binding.getStride());
614
615 mAppliedBindings[bindingIndex].setStride(binding.getStride());
616 mAppliedBindings[bindingIndex].setOffset(binding.getOffset());
James Darpiniane8a93c62018-01-04 18:02:24 -0800617 mAppliedBindings[bindingIndex].setBuffer(context, binding.getBuffer().get(), false);
Shaodde78e82017-05-22 14:13:27 +0800618}
619
620void VertexArrayGL::updateBindingDivisor(size_t bindingIndex)
621{
Martin Radev553590a2017-07-31 16:40:39 +0300622 GLuint adjustedDivisor =
Jamie Madill492f58e2017-10-09 19:41:33 -0400623 GetAdjustedDivisor(mAppliedNumViews, mState.getVertexBinding(bindingIndex).getDivisor());
Martin Radev553590a2017-07-31 16:40:39 +0300624 if (mAppliedBindings[bindingIndex].getDivisor() == adjustedDivisor)
Shaodde78e82017-05-22 14:13:27 +0800625 {
626 return;
627 }
628
629 if (supportVertexAttribBinding())
630 {
Martin Radev553590a2017-07-31 16:40:39 +0300631 mFunctions->vertexBindingDivisor(static_cast<GLuint>(bindingIndex), adjustedDivisor);
Shaodde78e82017-05-22 14:13:27 +0800632 }
633 else
634 {
635 // We can only use VertexAttribDivisor on platforms that don't support Vertex Attrib
636 // Binding.
Martin Radev553590a2017-07-31 16:40:39 +0300637 mFunctions->vertexAttribDivisor(static_cast<GLuint>(bindingIndex), adjustedDivisor);
Shaodde78e82017-05-22 14:13:27 +0800638 }
639
Martin Radev553590a2017-07-31 16:40:39 +0300640 mAppliedBindings[bindingIndex].setDivisor(adjustedDivisor);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000641}
642
Jamie Madille858cb12018-03-27 09:44:32 -0400643void VertexArrayGL::syncDirtyAttrib(const gl::Context *context,
644 size_t attribIndex,
645 const gl::VertexArray::DirtyAttribBits &dirtyAttribBits)
646{
647 ASSERT(dirtyAttribBits.any());
648
649 for (size_t dirtyBit : dirtyAttribBits)
650 {
651 switch (dirtyBit)
652 {
653 case VertexArray::DIRTY_ATTRIB_ENABLED:
654 updateAttribEnabled(attribIndex);
655 break;
656
657 case VertexArray::DIRTY_ATTRIB_POINTER:
658 updateAttribPointer(context, attribIndex);
659 break;
660
661 case VertexArray::DIRTY_ATTRIB_FORMAT:
662 ASSERT(supportVertexAttribBinding());
663 updateAttribFormat(attribIndex);
664 break;
665
666 case VertexArray::DIRTY_ATTRIB_BINDING:
667 ASSERT(supportVertexAttribBinding());
668 updateAttribBinding(attribIndex);
669 break;
670
671 default:
672 UNREACHABLE();
673 break;
674 }
675 }
676}
677
678void VertexArrayGL::syncDirtyBinding(const gl::Context *context,
679 size_t bindingIndex,
680 const gl::VertexArray::DirtyBindingBits &dirtyBindingBits)
681{
682 ASSERT(dirtyBindingBits.any());
683
684 for (size_t dirtyBit : dirtyBindingBits)
685 {
686 switch (dirtyBit)
687 {
688 case VertexArray::DIRTY_BINDING_BUFFER:
689 ASSERT(supportVertexAttribBinding());
690 updateBindingBuffer(context, bindingIndex);
691 break;
692
693 case VertexArray::DIRTY_BINDING_DIVISOR:
694 updateBindingDivisor(bindingIndex);
695 break;
696
697 default:
698 UNREACHABLE();
699 break;
700 }
701 }
702}
703
704void VertexArrayGL::syncState(const gl::Context *context,
705 const VertexArray::DirtyBits &dirtyBits,
706 const gl::VertexArray::DirtyAttribBitsArray &attribBits,
707 const gl::VertexArray::DirtyBindingBitsArray &bindingBits)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000708{
Shaodf682a82017-03-31 15:13:21 +0800709 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
710
Jamie Madill6de51852017-04-12 09:53:01 -0400711 for (size_t dirtyBit : dirtyBits)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000712 {
Jamie Madille858cb12018-03-27 09:44:32 -0400713 switch (dirtyBit)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000714 {
Jamie Madille858cb12018-03-27 09:44:32 -0400715 case VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER:
716 updateElementArrayBufferBinding(context);
717 break;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800718
Jamie Madille858cb12018-03-27 09:44:32 -0400719 default:
720 {
721 ASSERT(dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0);
722 size_t index = VertexArray::GetVertexIndexFromDirtyBit(dirtyBit);
723 if (dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX)
724 {
725 syncDirtyAttrib(context, index, attribBits[index]);
726 }
727 else
728 {
729 ASSERT(dirtyBit >= VertexArray::DIRTY_BIT_BINDING_0 &&
730 dirtyBit < VertexArray::DIRTY_BIT_BINDING_MAX);
731 syncDirtyBinding(context, index, bindingBits[index]);
732 }
733 break;
734 }
Jamie Madill0b9e9032015-08-17 11:51:52 +0000735 }
Jamie Madill0b9e9032015-08-17 11:51:52 +0000736 }
737}
738
Martin Radev553590a2017-07-31 16:40:39 +0300739void VertexArrayGL::applyNumViewsToDivisor(int numViews)
740{
741 if (numViews != mAppliedNumViews)
742 {
743 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
744 mAppliedNumViews = numViews;
745 for (size_t index = 0u; index < mAppliedBindings.size(); ++index)
746 {
747 updateBindingDivisor(index);
748 }
749 }
750}
751
Jamie Madill0b9e9032015-08-17 11:51:52 +0000752} // rx