blob: 2f617f2a19ea9cd3ce8673f3b0e0c5faf8c8679c [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{
Shaodf682a82017-03-31 15:13:21 +080029bool SameVertexAttribFormat(const VertexAttribute &a, const VertexAttribute &b)
30{
31 return a.size == b.size && a.type == b.type && a.normalized == b.normalized &&
32 a.pureInteger == b.pureInteger && a.relativeOffset == b.relativeOffset;
33}
34
35bool SameVertexBuffer(const VertexBinding &a, const VertexBinding &b)
36{
Martin Radevdd5f27e2017-06-07 10:17:09 +030037 return a.getStride() == b.getStride() && a.getOffset() == b.getOffset() &&
38 a.getBuffer().get() == b.getBuffer().get();
Shaodf682a82017-03-31 15:13:21 +080039}
40
41bool IsVertexAttribPointerSupported(size_t attribIndex, const VertexAttribute &attrib)
42{
43 return (attribIndex == attrib.bindingIndex && attrib.relativeOffset == 0);
44}
Martin Radev553590a2017-07-31 16:40:39 +030045
46GLuint GetAdjustedDivisor(GLuint numViews, GLuint divisor)
47{
48 return numViews * divisor;
49}
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),
Martin Radev553590a2017-07-31 16:40:39 +030060 mAppliedNumViews(1),
Jamie Madill77a90c22015-08-11 16:33:17 -040061 mAppliedElementArrayBuffer(),
Jiawei-Shao2597fb62016-12-09 16:38:02 +080062 mAppliedBindings(state.getMaxBindings()),
Geoff Lang7c82bc42015-03-09 16:18:08 -040063 mStreamingElementArrayBufferSize(0),
64 mStreamingElementArrayBuffer(0),
65 mStreamingArrayBufferSize(0),
66 mStreamingArrayBuffer(0)
Geoff Langba4c4a82015-02-24 12:38:46 -050067{
68 ASSERT(mFunctions);
69 ASSERT(mStateManager);
70 mFunctions->genVertexArrays(1, &mVertexArrayID);
71
Jiawei-Shao2597fb62016-12-09 16:38:02 +080072 // Set the cached vertex attribute array and vertex attribute binding array size
73 GLuint maxVertexAttribs = static_cast<GLuint>(state.getMaxAttribs());
74 for (GLuint i = 0; i < maxVertexAttribs; i++)
75 {
76 mAppliedAttributes.emplace_back(i);
77 }
Geoff Langba4c4a82015-02-24 12:38:46 -050078}
Geoff Langf9a6f082015-01-22 13:32:49 -050079
Jamie Madillacf2f3a2017-11-21 19:22:44 -050080VertexArrayGL::~VertexArrayGL()
81{
82}
83
Jamie Madill4928b7c2017-06-20 12:57:39 -040084void VertexArrayGL::destroy(const gl::Context *context)
Geoff Langba4c4a82015-02-24 12:38:46 -050085{
Geoff Lang1eb708e2015-05-04 14:58:23 -040086 mStateManager->deleteVertexArray(mVertexArrayID);
87 mVertexArrayID = 0;
Martin Radev553590a2017-07-31 16:40:39 +030088 mAppliedNumViews = 1;
Geoff Langba4c4a82015-02-24 12:38:46 -050089
Geoff Lang1eb708e2015-05-04 14:58:23 -040090 mStateManager->deleteBuffer(mStreamingElementArrayBuffer);
91 mStreamingElementArrayBufferSize = 0;
Shao80957d92017-02-20 21:25:59 +080092 mStreamingElementArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040093
Geoff Lang1eb708e2015-05-04 14:58:23 -040094 mStateManager->deleteBuffer(mStreamingArrayBuffer);
95 mStreamingArrayBufferSize = 0;
Shao80957d92017-02-20 21:25:59 +080096 mStreamingArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040097
Jamie Madill4928b7c2017-06-20 12:57:39 -040098 mAppliedElementArrayBuffer.set(context, nullptr);
Jiawei-Shao2597fb62016-12-09 16:38:02 +080099 for (auto &binding : mAppliedBindings)
Geoff Langba4c4a82015-02-24 12:38:46 -0500100 {
James Darpiniane8a93c62018-01-04 18:02:24 -0800101 binding.setBuffer(context, nullptr, false);
Geoff Langba4c4a82015-02-24 12:38:46 -0500102 }
103}
Geoff Langf9a6f082015-01-22 13:32:49 -0500104
Jamie Madill4928b7c2017-06-20 12:57:39 -0400105gl::Error VertexArrayGL::syncDrawArraysState(const gl::Context *context,
106 const gl::AttributesMask &activeAttributesMask,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000107 GLint first,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400108 GLsizei count,
109 GLsizei instanceCount) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400110{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400111 return syncDrawState(context, activeAttributesMask, first, count, GL_NONE, nullptr,
112 instanceCount, false, nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400113}
114
Jamie Madill4928b7c2017-06-20 12:57:39 -0400115gl::Error VertexArrayGL::syncDrawElementsState(const gl::Context *context,
116 const gl::AttributesMask &activeAttributesMask,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000117 GLsizei count,
118 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400119 const void *indices,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400120 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400121 bool primitiveRestartEnabled,
Jamie Madill876429b2017-04-20 15:46:24 -0400122 const void **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400123{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400124 return syncDrawState(context, activeAttributesMask, 0, count, type, indices, instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400125 primitiveRestartEnabled, outIndices);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400126}
127
Jiajia Qin47474142017-12-29 13:41:00 +0800128void VertexArrayGL::updateElementArrayBufferBinding(const gl::Context *context) const
Jiajia Qind9671222016-11-29 16:30:31 +0800129{
Jamie Madill492f58e2017-10-09 19:41:33 -0400130 gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer().get();
Jiajia Qin47474142017-12-29 13:41:00 +0800131 if (elementArrayBuffer != nullptr && elementArrayBuffer != mAppliedElementArrayBuffer.get())
Jiajia Qind9671222016-11-29 16:30:31 +0800132 {
133 const BufferGL *bufferGL = GetImplAs<BufferGL>(elementArrayBuffer);
Corentin Wallez336129f2017-10-17 15:55:40 -0400134 mStateManager->bindBuffer(gl::BufferBinding::ElementArray, bufferGL->getBufferID());
Jamie Madill4928b7c2017-06-20 12:57:39 -0400135 mAppliedElementArrayBuffer.set(context, elementArrayBuffer);
Jiajia Qind9671222016-11-29 16:30:31 +0800136 }
Jiajia Qind9671222016-11-29 16:30:31 +0800137}
138
Jamie Madill4928b7c2017-06-20 12:57:39 -0400139gl::Error VertexArrayGL::syncDrawState(const gl::Context *context,
140 const gl::AttributesMask &activeAttributesMask,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000141 GLint first,
142 GLsizei count,
143 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400144 const void *indices,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400145 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400146 bool primitiveRestartEnabled,
Jamie Madill876429b2017-04-20 15:46:24 -0400147 const void **outIndices) const
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400148{
Shao80957d92017-02-20 21:25:59 +0800149 // Check if any attributes need to be streamed, determines if the index range needs to be
150 // computed
Jamie Madillbcef3222018-04-13 15:19:11 -0400151 const gl::AttributesMask &needsStreamingAttribs =
152 (mState.getEnabledClientMemoryAttribsMask() & activeAttributesMask);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400153
Shao80957d92017-02-20 21:25:59 +0800154 // Determine if an index buffer needs to be streamed and the range of vertices that need to be
155 // copied
Geoff Lang3edfe032015-09-04 16:38:24 -0400156 IndexRange indexRange;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400157 if (type != GL_NONE)
Geoff Langba4c4a82015-02-24 12:38:46 -0500158 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400159 ANGLE_TRY(syncIndexData(context, count, type, indices, primitiveRestartEnabled,
Jamie Madillbcef3222018-04-13 15:19:11 -0400160 needsStreamingAttribs.any(), &indexRange, outIndices));
Geoff Lang7c82bc42015-03-09 16:18:08 -0400161 }
162 else
163 {
Corentin Wallez2c34a4b2015-08-25 16:26:02 -0400164 // Not an indexed call, set the range to [first, first + count - 1]
Geoff Lang7c82bc42015-03-09 16:18:08 -0400165 indexRange.start = first;
Shao80957d92017-02-20 21:25:59 +0800166 indexRange.end = first + count - 1;
Geoff Langba4c4a82015-02-24 12:38:46 -0500167 }
168
Jamie Madillbcef3222018-04-13 15:19:11 -0400169 if (needsStreamingAttribs.any())
Geoff Langba4c4a82015-02-24 12:38:46 -0500170 {
Jamie Madillbcef3222018-04-13 15:19:11 -0400171 ANGLE_TRY(streamAttributes(needsStreamingAttribs, instanceCount, indexRange));
Geoff Lang7c82bc42015-03-09 16:18:08 -0400172 }
173
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500174 return gl::NoError();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400175}
176
Jamie Madill4928b7c2017-06-20 12:57:39 -0400177gl::Error VertexArrayGL::syncIndexData(const gl::Context *context,
178 GLsizei count,
Jiajia Qind9671222016-11-29 16:30:31 +0800179 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400180 const void *indices,
Jiajia Qind9671222016-11-29 16:30:31 +0800181 bool primitiveRestartEnabled,
182 bool attributesNeedStreaming,
183 IndexRange *outIndexRange,
Jamie Madill876429b2017-04-20 15:46:24 -0400184 const void **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400185{
186 ASSERT(outIndices);
187
Jamie Madill492f58e2017-10-09 19:41:33 -0400188 gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer().get();
Jamie Madill8e344942015-07-09 14:22:07 -0400189
Geoff Lang7c82bc42015-03-09 16:18:08 -0400190 // Need to check the range of indices if attributes need to be streamed
Jamie Madill8e344942015-07-09 14:22:07 -0400191 if (elementArrayBuffer != nullptr)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400192 {
Jiajia Qin47474142017-12-29 13:41:00 +0800193 ASSERT(elementArrayBuffer == mAppliedElementArrayBuffer.get());
Geoff Lang7c82bc42015-03-09 16:18:08 -0400194 // Only compute the index range if the attributes also need to be streamed
195 if (attributesNeedStreaming)
196 {
197 ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices);
Jamie Madill492f58e2017-10-09 19:41:33 -0400198 Error error = mState.getElementArrayBuffer()->getIndexRange(
Jamie Madill33510102017-09-20 10:39:18 -0400199 context, type, elementArrayBufferOffset, count, primitiveRestartEnabled,
200 outIndexRange);
Geoff Lang520c4ae2015-05-05 13:12:36 -0400201 if (error.isError())
Geoff Lang7c82bc42015-03-09 16:18:08 -0400202 {
Geoff Lang520c4ae2015-05-05 13:12:36 -0400203 return error;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400204 }
205 }
206
Shao80957d92017-02-20 21:25:59 +0800207 // Indices serves as an offset into the index buffer in this case, use the same value for
208 // the draw call
Geoff Lang7c82bc42015-03-09 16:18:08 -0400209 *outIndices = indices;
210 }
211 else
212 {
213 // Need to stream the index buffer
214 // TODO: if GLES, nothing needs to be streamed
215
216 // Only compute the index range if the attributes also need to be streamed
217 if (attributesNeedStreaming)
218 {
Geoff Lang3edfe032015-09-04 16:38:24 -0400219 *outIndexRange = ComputeIndexRange(type, indices, count, primitiveRestartEnabled);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400220 }
221
222 // Allocate the streaming element array buffer
223 if (mStreamingElementArrayBuffer == 0)
224 {
225 mFunctions->genBuffers(1, &mStreamingElementArrayBuffer);
226 mStreamingElementArrayBufferSize = 0;
227 }
228
Geoff Lang5f3047c2018-02-14 14:39:12 -0500229 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
230
Corentin Wallez336129f2017-10-17 15:55:40 -0400231 mStateManager->bindBuffer(gl::BufferBinding::ElementArray, mStreamingElementArrayBuffer);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400232 mAppliedElementArrayBuffer.set(context, nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400233
234 // Make sure the element array buffer is large enough
Jamie Madill0b9e9032015-08-17 11:51:52 +0000235 const Type &indexTypeInfo = GetTypeInfo(type);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400236 size_t requiredStreamingBufferSize = indexTypeInfo.bytes * count;
237 if (requiredStreamingBufferSize > mStreamingElementArrayBufferSize)
238 {
239 // Copy the indices in while resizing the buffer
Shao80957d92017-02-20 21:25:59 +0800240 mFunctions->bufferData(GL_ELEMENT_ARRAY_BUFFER, requiredStreamingBufferSize, indices,
241 GL_DYNAMIC_DRAW);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400242 mStreamingElementArrayBufferSize = requiredStreamingBufferSize;
243 }
244 else
245 {
246 // Put the indices at the beginning of the buffer
Shao80957d92017-02-20 21:25:59 +0800247 mFunctions->bufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, requiredStreamingBufferSize,
248 indices);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400249 }
250
Shao80957d92017-02-20 21:25:59 +0800251 // Set the index offset for the draw call to zero since the supplied index pointer is to
252 // client data
Geoff Lang7c82bc42015-03-09 16:18:08 -0400253 *outIndices = nullptr;
254 }
255
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500256 return gl::NoError();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400257}
258
Jamie Madillbcef3222018-04-13 15:19:11 -0400259void VertexArrayGL::computeStreamingAttributeSizes(const gl::AttributesMask &attribsToStream,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400260 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400261 const gl::IndexRange &indexRange,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000262 size_t *outStreamingDataSize,
263 size_t *outMaxAttributeDataSize) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400264{
Jamie Madill0b9e9032015-08-17 11:51:52 +0000265 *outStreamingDataSize = 0;
266 *outMaxAttributeDataSize = 0;
267
Jamie Madillbcef3222018-04-13 15:19:11 -0400268 ASSERT(attribsToStream.any());
Jamie Madill0b9e9032015-08-17 11:51:52 +0000269
Jamie Madill492f58e2017-10-09 19:41:33 -0400270 const auto &attribs = mState.getVertexAttributes();
271 const auto &bindings = mState.getVertexBindings();
Jamie Madill6de51852017-04-12 09:53:01 -0400272
Jamie Madill6de51852017-04-12 09:53:01 -0400273 for (auto idx : attribsToStream)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000274 {
Shao80957d92017-02-20 21:25:59 +0800275 const auto &attrib = attribs[idx];
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800276 const auto &binding = bindings[attrib.bindingIndex];
Jamie Madill0b9e9032015-08-17 11:51:52 +0000277
Jamie Madill0b9e9032015-08-17 11:51:52 +0000278 // If streaming is going to be required, compute the size of the required buffer
279 // and how much slack space at the beginning of the buffer will be required by determining
280 // the attribute with the largest data size.
281 size_t typeSize = ComputeVertexAttributeTypeSize(attrib);
Martin Radev553590a2017-07-31 16:40:39 +0300282 GLuint adjustedDivisor = GetAdjustedDivisor(mAppliedNumViews, binding.getDivisor());
283 *outStreamingDataSize +=
284 typeSize * ComputeVertexBindingElementCount(adjustedDivisor, indexRange.vertexCount(),
285 instanceCount);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000286 *outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
287 }
288}
289
Jamie Madillbcef3222018-04-13 15:19:11 -0400290gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &attribsToStream,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400291 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400292 const gl::IndexRange &indexRange) const
Jamie Madill0b9e9032015-08-17 11:51:52 +0000293{
294 // Sync the vertex attribute state and track what data needs to be streamed
295 size_t streamingDataSize = 0;
296 size_t maxAttributeDataSize = 0;
297
Jamie Madillbcef3222018-04-13 15:19:11 -0400298 computeStreamingAttributeSizes(attribsToStream, instanceCount, indexRange, &streamingDataSize,
299 &maxAttributeDataSize);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000300
301 if (streamingDataSize == 0)
302 {
He Yunchaoacd18982017-01-04 10:46:42 +0800303 return gl::NoError();
Jamie Madill0b9e9032015-08-17 11:51:52 +0000304 }
305
Geoff Lang7c82bc42015-03-09 16:18:08 -0400306 if (mStreamingArrayBuffer == 0)
307 {
308 mFunctions->genBuffers(1, &mStreamingArrayBuffer);
309 mStreamingArrayBufferSize = 0;
310 }
311
Shao80957d92017-02-20 21:25:59 +0800312 // If first is greater than zero, a slack space needs to be left at the beginning of the buffer
313 // so that the same 'first' argument can be passed into the draw call.
314 const size_t bufferEmptySpace = maxAttributeDataSize * indexRange.start;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400315 const size_t requiredBufferSize = streamingDataSize + bufferEmptySpace;
316
Corentin Wallez336129f2017-10-17 15:55:40 -0400317 mStateManager->bindBuffer(gl::BufferBinding::Array, mStreamingArrayBuffer);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400318 if (requiredBufferSize > mStreamingArrayBufferSize)
319 {
320 mFunctions->bufferData(GL_ARRAY_BUFFER, requiredBufferSize, nullptr, GL_DYNAMIC_DRAW);
321 mStreamingArrayBufferSize = requiredBufferSize;
322 }
323
Geoff Lang5f3047c2018-02-14 14:39:12 -0500324 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
325
Geoff Lang7c82bc42015-03-09 16:18:08 -0400326 // Unmapping a buffer can return GL_FALSE to indicate that the system has corrupted the data
Shao80957d92017-02-20 21:25:59 +0800327 // somehow (such as by a screen change), retry writing the data a few times and return
328 // OUT_OF_MEMORY if that fails.
329 GLboolean unmapResult = GL_FALSE;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400330 size_t unmapRetryAttempts = 5;
331 while (unmapResult != GL_TRUE && --unmapRetryAttempts > 0)
332 {
Geoff Langb2ebb5e2016-06-08 18:17:55 +0000333 uint8_t *bufferPointer = MapBufferRangeWithFallback(mFunctions, GL_ARRAY_BUFFER, 0,
334 requiredBufferSize, GL_MAP_WRITE_BIT);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400335 size_t curBufferOffset = bufferEmptySpace;
336
Jamie Madill492f58e2017-10-09 19:41:33 -0400337 const auto &attribs = mState.getVertexAttributes();
338 const auto &bindings = mState.getVertexBindings();
Jamie Madill6de51852017-04-12 09:53:01 -0400339
Jamie Madill6de51852017-04-12 09:53:01 -0400340 for (auto idx : attribsToStream)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400341 {
Shao80957d92017-02-20 21:25:59 +0800342 const auto &attrib = attribs[idx];
Shaodde78e82017-05-22 14:13:27 +0800343 ASSERT(IsVertexAttribPointerSupported(idx, attrib));
344
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800345 const auto &binding = bindings[attrib.bindingIndex];
Geoff Lang7c82bc42015-03-09 16:18:08 -0400346
Martin Radev553590a2017-07-31 16:40:39 +0300347 GLuint adjustedDivisor = GetAdjustedDivisor(mAppliedNumViews, binding.getDivisor());
348 const size_t streamedVertexCount = ComputeVertexBindingElementCount(
349 adjustedDivisor, indexRange.vertexCount(), instanceCount);
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400350
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800351 const size_t sourceStride = ComputeVertexAttributeStride(attrib, binding);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000352 const size_t destStride = ComputeVertexAttributeTypeSize(attrib);
353
Geoff Lang38a24a92017-02-15 13:53:06 -0500354 // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing
355 // a non-instanced draw call
Martin Radev553590a2017-07-31 16:40:39 +0300356 const size_t firstIndex = adjustedDivisor == 0 ? indexRange.start : 0;
Geoff Lang38a24a92017-02-15 13:53:06 -0500357
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800358 // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state.
359 // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt
Jamie Madill0b9e9032015-08-17 11:51:52 +0000360 const uint8_t *inputPointer = reinterpret_cast<const uint8_t *>(attrib.pointer);
361
362 // Pack the data when copying it, user could have supplied a very large stride that
363 // would cause the buffer to be much larger than needed.
364 if (destStride == sourceStride)
Jamie Madill8e344942015-07-09 14:22:07 -0400365 {
Jamie Madill0b9e9032015-08-17 11:51:52 +0000366 // Can copy in one go, the data is packed
Geoff Lang38a24a92017-02-15 13:53:06 -0500367 memcpy(bufferPointer + curBufferOffset, inputPointer + (sourceStride * firstIndex),
Jamie Madill0b9e9032015-08-17 11:51:52 +0000368 destStride * streamedVertexCount);
Jamie Madill6d51c702015-08-14 10:38:10 -0400369 }
Jamie Madill0b9e9032015-08-17 11:51:52 +0000370 else
371 {
372 // Copy each vertex individually
Geoff Lang6b10ddb2015-09-02 15:55:10 -0400373 for (size_t vertexIdx = 0; vertexIdx < streamedVertexCount; vertexIdx++)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000374 {
Shao80957d92017-02-20 21:25:59 +0800375 uint8_t *out = bufferPointer + curBufferOffset + (destStride * vertexIdx);
Geoff Lang38a24a92017-02-15 13:53:06 -0500376 const uint8_t *in = inputPointer + sourceStride * (vertexIdx + firstIndex);
Corentin Wallez4d5362d2015-08-25 11:25:14 -0400377 memcpy(out, in, destStride);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000378 }
379 }
380
381 // Compute where the 0-index vertex would be.
Geoff Lang38a24a92017-02-15 13:53:06 -0500382 const size_t vertexStartOffset = curBufferOffset - (firstIndex * destStride);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000383
Shaodf682a82017-03-31 15:13:21 +0800384 callVertexAttribPointer(static_cast<GLuint>(idx), attrib,
385 static_cast<GLsizei>(destStride),
386 static_cast<GLintptr>(vertexStartOffset));
Jamie Madill0b9e9032015-08-17 11:51:52 +0000387
388 curBufferOffset += destStride * streamedVertexCount;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400389 }
390
391 unmapResult = mFunctions->unmapBuffer(GL_ARRAY_BUFFER);
392 }
393
394 if (unmapResult != GL_TRUE)
395 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500396 return gl::OutOfMemory() << "Failed to unmap the client data streaming buffer.";
Geoff Lang7c82bc42015-03-09 16:18:08 -0400397 }
398
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500399 return gl::NoError();
Geoff Langba4c4a82015-02-24 12:38:46 -0500400}
401
402GLuint VertexArrayGL::getVertexArrayID() const
403{
404 return mVertexArrayID;
Geoff Langf9a6f082015-01-22 13:32:49 -0500405}
406
Geoff Lang294cad92015-05-26 15:11:23 -0400407GLuint VertexArrayGL::getAppliedElementArrayBufferID() const
408{
Jamie Madill77a90c22015-08-11 16:33:17 -0400409 if (mAppliedElementArrayBuffer.get() == nullptr)
410 {
411 return mStreamingElementArrayBuffer;
412 }
413
414 return GetImplAs<BufferGL>(mAppliedElementArrayBuffer.get())->getBufferID();
Geoff Lang294cad92015-05-26 15:11:23 -0400415}
416
Jamie Madill0b9e9032015-08-17 11:51:52 +0000417void VertexArrayGL::updateAttribEnabled(size_t attribIndex)
418{
Jamie Madill492f58e2017-10-09 19:41:33 -0400419 const bool enabled = mState.getVertexAttribute(attribIndex).enabled;
Shaodf682a82017-03-31 15:13:21 +0800420 if (mAppliedAttributes[attribIndex].enabled == enabled)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000421 {
422 return;
423 }
424
Shaodf682a82017-03-31 15:13:21 +0800425 if (enabled)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000426 {
427 mFunctions->enableVertexAttribArray(static_cast<GLuint>(attribIndex));
428 }
429 else
430 {
431 mFunctions->disableVertexAttribArray(static_cast<GLuint>(attribIndex));
432 }
Shaodf682a82017-03-31 15:13:21 +0800433
434 mAppliedAttributes[attribIndex].enabled = enabled;
Jamie Madill0b9e9032015-08-17 11:51:52 +0000435}
436
Jamie Madill4928b7c2017-06-20 12:57:39 -0400437void VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attribIndex)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000438{
Jamie Madill492f58e2017-10-09 19:41:33 -0400439 const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800440
Shaodde78e82017-05-22 14:13:27 +0800441 // According to SPEC, VertexAttribPointer should update the binding indexed attribIndex instead
442 // of the binding indexed attrib.bindingIndex (unless attribIndex == attrib.bindingIndex).
Jamie Madill492f58e2017-10-09 19:41:33 -0400443 const VertexBinding &binding = mState.getVertexBinding(attribIndex);
Shaodf682a82017-03-31 15:13:21 +0800444
Shaodde78e82017-05-22 14:13:27 +0800445 // Early return when the vertex attribute isn't using a buffer object:
446 // - If we need to stream, defer the attribPointer to the draw call.
447 // - Skip the attribute that is disabled and uses a client memory pointer.
448 // - Skip the attribute whose buffer is detached by BindVertexBuffer. Since it cannot have a
449 // client memory pointer either, it must be disabled and shouldn't affect the draw.
Jamie Madillbcef3222018-04-13 15:19:11 -0400450 const auto &bindingBuffer = binding.getBuffer();
Shaodde78e82017-05-22 14:13:27 +0800451 const Buffer *arrayBuffer = bindingBuffer.get();
452 if (arrayBuffer == nullptr)
453 {
454 // Mark the applied binding isn't using a buffer by setting its buffer to nullptr so that if
455 // it starts to use a buffer later, there is no chance that the caching will skip it.
James Darpiniane8a93c62018-01-04 18:02:24 -0800456 mAppliedBindings[attribIndex].setBuffer(context, nullptr, false);
Shaodde78e82017-05-22 14:13:27 +0800457 return;
458 }
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800459
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.
Shaodde78e82017-05-22 14:13:27 +0800463 if ((SameVertexAttribFormat(mAppliedAttributes[attribIndex], attrib)) &&
464 (mAppliedAttributes[attribIndex].bindingIndex == attrib.bindingIndex) &&
465 (SameVertexBuffer(mAppliedBindings[attribIndex], binding)))
Jamie Madill0b9e9032015-08-17 11:51:52 +0000466 {
467 return;
468 }
469
Shao4181bc92017-03-17 14:55:25 +0800470 // Since ANGLE always uses a non-zero VAO, we cannot use a client memory pointer on it:
471 // [OpenGL ES 3.0.2] Section 2.8 page 24:
472 // An INVALID_OPERATION error is generated when a non-zero vertex array object is bound,
473 // zero is bound to the ARRAY_BUFFER buffer object binding point, and the pointer argument
474 // is not NULL.
Shaodf682a82017-03-31 15:13:21 +0800475
Shao4181bc92017-03-17 14:55:25 +0800476 const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
Corentin Wallez336129f2017-10-17 15:55:40 -0400477 mStateManager->bindBuffer(gl::BufferBinding::Array, arrayBufferGL->getBufferID());
Martin Radevdd5f27e2017-06-07 10:17:09 +0300478 callVertexAttribPointer(static_cast<GLuint>(attribIndex), attrib, binding.getStride(),
479 binding.getOffset());
Shaodf682a82017-03-31 15:13:21 +0800480
Shaodde78e82017-05-22 14:13:27 +0800481 mAppliedAttributes[attribIndex].size = attrib.size;
482 mAppliedAttributes[attribIndex].type = attrib.type;
483 mAppliedAttributes[attribIndex].normalized = attrib.normalized;
484 mAppliedAttributes[attribIndex].pureInteger = attrib.pureInteger;
Shaodf682a82017-03-31 15:13:21 +0800485
Shaodde78e82017-05-22 14:13:27 +0800486 // After VertexAttribPointer, attrib.relativeOffset is set to 0 and attrib.bindingIndex is set
487 // to attribIndex in driver. If attrib.relativeOffset != 0 or attrib.bindingIndex !=
488 // attribIndex, they should be set in updateAttribFormat and updateAttribBinding. The cache
489 // should be consistent with driver so that we won't miss anything.
490 mAppliedAttributes[attribIndex].relativeOffset = 0;
491 mAppliedAttributes[attribIndex].bindingIndex = static_cast<GLuint>(attribIndex);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800492
Shaodde78e82017-05-22 14:13:27 +0800493 mAppliedBindings[attribIndex].setStride(binding.getStride());
494 mAppliedBindings[attribIndex].setOffset(binding.getOffset());
James Darpiniane8a93c62018-01-04 18:02:24 -0800495 mAppliedBindings[attribIndex].setBuffer(context, binding.getBuffer().get(), false);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800496}
497
Shaodf682a82017-03-31 15:13:21 +0800498void VertexArrayGL::callVertexAttribPointer(GLuint attribIndex,
499 const VertexAttribute &attrib,
500 GLsizei stride,
501 GLintptr offset) const
502{
503 const GLvoid *pointer = reinterpret_cast<const GLvoid *>(offset);
504 if (attrib.pureInteger)
505 {
506 ASSERT(!attrib.normalized);
507 mFunctions->vertexAttribIPointer(attribIndex, attrib.size, attrib.type, stride, pointer);
508 }
509 else
510 {
511 mFunctions->vertexAttribPointer(attribIndex, attrib.size, attrib.type, attrib.normalized,
512 stride, pointer);
513 }
514}
515
Shaodde78e82017-05-22 14:13:27 +0800516bool VertexArrayGL::supportVertexAttribBinding() const
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800517{
Shaodde78e82017-05-22 14:13:27 +0800518 ASSERT(mFunctions);
519 return (mFunctions->vertexAttribBinding != nullptr);
520}
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800521
Shaodde78e82017-05-22 14:13:27 +0800522void VertexArrayGL::updateAttribFormat(size_t attribIndex)
523{
524 ASSERT(supportVertexAttribBinding());
525
Jamie Madill492f58e2017-10-09 19:41:33 -0400526 const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
Shaodde78e82017-05-22 14:13:27 +0800527 if (SameVertexAttribFormat(mAppliedAttributes[attribIndex], attrib))
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800528 {
Shaodf682a82017-03-31 15:13:21 +0800529 return;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800530 }
Shaodf682a82017-03-31 15:13:21 +0800531
Shaodde78e82017-05-22 14:13:27 +0800532 if (attrib.pureInteger)
533 {
534 ASSERT(!attrib.normalized);
535 mFunctions->vertexAttribIFormat(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
536 attrib.relativeOffset);
537 }
538 else
539 {
540 mFunctions->vertexAttribFormat(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
541 attrib.normalized, attrib.relativeOffset);
542 }
543
544 mAppliedAttributes[attribIndex].size = attrib.size;
545 mAppliedAttributes[attribIndex].type = attrib.type;
546 mAppliedAttributes[attribIndex].normalized = attrib.normalized;
547 mAppliedAttributes[attribIndex].pureInteger = attrib.pureInteger;
548 mAppliedAttributes[attribIndex].relativeOffset = attrib.relativeOffset;
549}
550
551void VertexArrayGL::updateAttribBinding(size_t attribIndex)
552{
553 ASSERT(supportVertexAttribBinding());
554
Jamie Madill492f58e2017-10-09 19:41:33 -0400555 GLuint bindingIndex = mState.getVertexAttribute(attribIndex).bindingIndex;
Shaodde78e82017-05-22 14:13:27 +0800556 if (mAppliedAttributes[attribIndex].bindingIndex == bindingIndex)
557 {
558 return;
559 }
560
561 mFunctions->vertexAttribBinding(static_cast<GLuint>(attribIndex), bindingIndex);
Shaodf682a82017-03-31 15:13:21 +0800562
563 mAppliedAttributes[attribIndex].bindingIndex = bindingIndex;
Shaodde78e82017-05-22 14:13:27 +0800564}
565
566void VertexArrayGL::updateBindingBuffer(const gl::Context *context, size_t bindingIndex)
567{
568 ASSERT(supportVertexAttribBinding());
569
Jamie Madill492f58e2017-10-09 19:41:33 -0400570 const VertexBinding &binding = mState.getVertexBinding(bindingIndex);
Shaodde78e82017-05-22 14:13:27 +0800571 if (SameVertexBuffer(mAppliedBindings[bindingIndex], binding))
572 {
573 return;
574 }
575
576 const Buffer *arrayBuffer = binding.getBuffer().get();
577 GLuint bufferId = 0;
578 if (arrayBuffer != nullptr)
579 {
580 bufferId = GetImplAs<BufferGL>(arrayBuffer)->getBufferID();
581 }
582
583 mFunctions->bindVertexBuffer(static_cast<GLuint>(bindingIndex), bufferId, binding.getOffset(),
584 binding.getStride());
585
586 mAppliedBindings[bindingIndex].setStride(binding.getStride());
587 mAppliedBindings[bindingIndex].setOffset(binding.getOffset());
James Darpiniane8a93c62018-01-04 18:02:24 -0800588 mAppliedBindings[bindingIndex].setBuffer(context, binding.getBuffer().get(), false);
Shaodde78e82017-05-22 14:13:27 +0800589}
590
591void VertexArrayGL::updateBindingDivisor(size_t bindingIndex)
592{
Martin Radev553590a2017-07-31 16:40:39 +0300593 GLuint adjustedDivisor =
Jamie Madill492f58e2017-10-09 19:41:33 -0400594 GetAdjustedDivisor(mAppliedNumViews, mState.getVertexBinding(bindingIndex).getDivisor());
Martin Radev553590a2017-07-31 16:40:39 +0300595 if (mAppliedBindings[bindingIndex].getDivisor() == adjustedDivisor)
Shaodde78e82017-05-22 14:13:27 +0800596 {
597 return;
598 }
599
600 if (supportVertexAttribBinding())
601 {
Martin Radev553590a2017-07-31 16:40:39 +0300602 mFunctions->vertexBindingDivisor(static_cast<GLuint>(bindingIndex), adjustedDivisor);
Shaodde78e82017-05-22 14:13:27 +0800603 }
604 else
605 {
606 // We can only use VertexAttribDivisor on platforms that don't support Vertex Attrib
607 // Binding.
Martin Radev553590a2017-07-31 16:40:39 +0300608 mFunctions->vertexAttribDivisor(static_cast<GLuint>(bindingIndex), adjustedDivisor);
Shaodde78e82017-05-22 14:13:27 +0800609 }
610
Martin Radev553590a2017-07-31 16:40:39 +0300611 mAppliedBindings[bindingIndex].setDivisor(adjustedDivisor);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000612}
613
Jamie Madille858cb12018-03-27 09:44:32 -0400614void VertexArrayGL::syncDirtyAttrib(const gl::Context *context,
615 size_t attribIndex,
616 const gl::VertexArray::DirtyAttribBits &dirtyAttribBits)
617{
618 ASSERT(dirtyAttribBits.any());
619
620 for (size_t dirtyBit : dirtyAttribBits)
621 {
622 switch (dirtyBit)
623 {
624 case VertexArray::DIRTY_ATTRIB_ENABLED:
625 updateAttribEnabled(attribIndex);
626 break;
627
628 case VertexArray::DIRTY_ATTRIB_POINTER:
629 updateAttribPointer(context, attribIndex);
630 break;
631
632 case VertexArray::DIRTY_ATTRIB_FORMAT:
633 ASSERT(supportVertexAttribBinding());
634 updateAttribFormat(attribIndex);
635 break;
636
637 case VertexArray::DIRTY_ATTRIB_BINDING:
638 ASSERT(supportVertexAttribBinding());
639 updateAttribBinding(attribIndex);
640 break;
641
642 default:
643 UNREACHABLE();
644 break;
645 }
646 }
647}
648
649void VertexArrayGL::syncDirtyBinding(const gl::Context *context,
650 size_t bindingIndex,
651 const gl::VertexArray::DirtyBindingBits &dirtyBindingBits)
652{
Jamie Madill02c9c042018-04-17 13:43:48 -0400653 // Dependent state changes in buffers can trigger updates with no dirty bits set.
Jamie Madille858cb12018-03-27 09:44:32 -0400654
655 for (size_t dirtyBit : dirtyBindingBits)
656 {
657 switch (dirtyBit)
658 {
659 case VertexArray::DIRTY_BINDING_BUFFER:
660 ASSERT(supportVertexAttribBinding());
661 updateBindingBuffer(context, bindingIndex);
662 break;
663
664 case VertexArray::DIRTY_BINDING_DIVISOR:
665 updateBindingDivisor(bindingIndex);
666 break;
667
668 default:
669 UNREACHABLE();
670 break;
671 }
672 }
673}
674
Jamie Madilla56467e2018-04-11 16:19:41 -0400675#define ANGLE_DIRTY_ATTRIB_FUNC(INDEX) \
676 case VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX: \
677 syncDirtyAttrib(context, INDEX, attribBits[INDEX]); \
678 break;
679
680#define ANGLE_DIRTY_BINDING_FUNC(INDEX) \
681 case VertexArray::DIRTY_BIT_BINDING_0 + INDEX: \
682 syncDirtyBinding(context, INDEX, bindingBits[INDEX]); \
683 break;
684
685#define ANGLE_DIRTY_BUFFER_DATA_FUNC(INDEX) \
686 case VertexArray::DIRTY_BIT_BUFFER_DATA_0 + INDEX: \
687 break;
688
Frank Henigman0af5b862018-03-27 20:19:33 -0400689gl::Error VertexArrayGL::syncState(const gl::Context *context,
690 const VertexArray::DirtyBits &dirtyBits,
691 const gl::VertexArray::DirtyAttribBitsArray &attribBits,
692 const gl::VertexArray::DirtyBindingBitsArray &bindingBits)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000693{
Shaodf682a82017-03-31 15:13:21 +0800694 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
695
Jamie Madill6de51852017-04-12 09:53:01 -0400696 for (size_t dirtyBit : dirtyBits)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000697 {
Jamie Madille858cb12018-03-27 09:44:32 -0400698 switch (dirtyBit)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000699 {
Jamie Madille858cb12018-03-27 09:44:32 -0400700 case VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER:
701 updateElementArrayBufferBinding(context);
702 break;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800703
Jamie Madill09463932018-04-04 05:26:59 -0400704 case VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA:
705 break;
706
Jamie Madilla56467e2018-04-11 16:19:41 -0400707 ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_ATTRIB_FUNC);
708 ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_BINDING_FUNC);
709 ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_BUFFER_DATA_FUNC);
710
Jamie Madille858cb12018-03-27 09:44:32 -0400711 default:
Jamie Madilla56467e2018-04-11 16:19:41 -0400712 UNREACHABLE();
Jamie Madille858cb12018-03-27 09:44:32 -0400713 break;
Jamie Madill0b9e9032015-08-17 11:51:52 +0000714 }
Jamie Madill0b9e9032015-08-17 11:51:52 +0000715 }
Frank Henigman0af5b862018-03-27 20:19:33 -0400716
717 return gl::NoError();
Jamie Madill0b9e9032015-08-17 11:51:52 +0000718}
719
Martin Radev553590a2017-07-31 16:40:39 +0300720void VertexArrayGL::applyNumViewsToDivisor(int numViews)
721{
722 if (numViews != mAppliedNumViews)
723 {
724 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
725 mAppliedNumViews = numViews;
726 for (size_t index = 0u; index < mAppliedBindings.size(); ++index)
727 {
728 updateBindingDivisor(index);
729 }
730 }
731}
732
Jamie Madill09463932018-04-04 05:26:59 -0400733} // namespace rx