blob: 09bb9bb3409d040c954ff8fc9de6ba827e33c93c [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"
Jamie Madilldc358af2018-07-31 11:22:13 -040016#include "libANGLE/Context.h"
Geoff Langba4c4a82015-02-24 12:38:46 -050017#include "libANGLE/angletypes.h"
Geoff Lang7c82bc42015-03-09 16:18:08 -040018#include "libANGLE/formatutils.h"
Geoff Langba4c4a82015-02-24 12:38:46 -050019#include "libANGLE/renderer/gl/BufferGL.h"
Jamie Madille39e8f42018-10-05 08:17:38 -040020#include "libANGLE/renderer/gl/ContextGL.h"
Geoff Langba4c4a82015-02-24 12:38:46 -050021#include "libANGLE/renderer/gl/FunctionsGL.h"
22#include "libANGLE/renderer/gl/StateManagerGL.h"
Jamie Madill231c7f52017-04-26 13:45:37 -040023#include "libANGLE/renderer/gl/renderergl_utils.h"
Geoff Langf9a6f082015-01-22 13:32:49 -050024
Jamie Madill0b9e9032015-08-17 11:51:52 +000025using namespace gl;
26
Geoff Langf9a6f082015-01-22 13:32:49 -050027namespace rx
28{
Jamie Madill0b9e9032015-08-17 11:51:52 +000029namespace
30{
Shaodf682a82017-03-31 15:13:21 +080031bool SameVertexAttribFormat(const VertexAttribute &a, const VertexAttribute &b)
32{
33 return a.size == b.size && a.type == b.type && a.normalized == b.normalized &&
34 a.pureInteger == b.pureInteger && a.relativeOffset == b.relativeOffset;
35}
36
37bool SameVertexBuffer(const VertexBinding &a, const VertexBinding &b)
38{
Martin Radevdd5f27e2017-06-07 10:17:09 +030039 return a.getStride() == b.getStride() && a.getOffset() == b.getOffset() &&
40 a.getBuffer().get() == b.getBuffer().get();
Shaodf682a82017-03-31 15:13:21 +080041}
42
43bool IsVertexAttribPointerSupported(size_t attribIndex, const VertexAttribute &attrib)
44{
45 return (attribIndex == attrib.bindingIndex && attrib.relativeOffset == 0);
46}
Martin Radev553590a2017-07-31 16:40:39 +030047
48GLuint GetAdjustedDivisor(GLuint numViews, GLuint divisor)
49{
50 return numViews * divisor;
51}
52
Jamie Madill0b9e9032015-08-17 11:51:52 +000053} // anonymous namespace
54
Jamie Madill3f572682016-04-26 13:41:36 -040055VertexArrayGL::VertexArrayGL(const VertexArrayState &state,
Jamie Madill77a90c22015-08-11 16:33:17 -040056 const FunctionsGL *functions,
57 StateManagerGL *stateManager)
Jamie Madill3f572682016-04-26 13:41:36 -040058 : VertexArrayImpl(state),
Geoff Langba4c4a82015-02-24 12:38:46 -050059 mFunctions(functions),
60 mStateManager(stateManager),
61 mVertexArrayID(0),
Martin Radev553590a2017-07-31 16:40:39 +030062 mAppliedNumViews(1),
Jamie Madill77a90c22015-08-11 16:33:17 -040063 mAppliedElementArrayBuffer(),
Jiawei-Shao2597fb62016-12-09 16:38:02 +080064 mAppliedBindings(state.getMaxBindings()),
Geoff Lang7c82bc42015-03-09 16:18:08 -040065 mStreamingElementArrayBufferSize(0),
66 mStreamingElementArrayBuffer(0),
67 mStreamingArrayBufferSize(0),
68 mStreamingArrayBuffer(0)
Geoff Langba4c4a82015-02-24 12:38:46 -050069{
70 ASSERT(mFunctions);
71 ASSERT(mStateManager);
72 mFunctions->genVertexArrays(1, &mVertexArrayID);
73
Jiawei-Shao2597fb62016-12-09 16:38:02 +080074 // Set the cached vertex attribute array and vertex attribute binding array size
75 GLuint maxVertexAttribs = static_cast<GLuint>(state.getMaxAttribs());
76 for (GLuint i = 0; i < maxVertexAttribs; i++)
77 {
78 mAppliedAttributes.emplace_back(i);
79 }
Geoff Langba4c4a82015-02-24 12:38:46 -050080}
Geoff Langf9a6f082015-01-22 13:32:49 -050081
Jamie Madillacf2f3a2017-11-21 19:22:44 -050082VertexArrayGL::~VertexArrayGL()
83{
84}
85
Jamie Madill4928b7c2017-06-20 12:57:39 -040086void VertexArrayGL::destroy(const gl::Context *context)
Geoff Langba4c4a82015-02-24 12:38:46 -050087{
Geoff Lang1eb708e2015-05-04 14:58:23 -040088 mStateManager->deleteVertexArray(mVertexArrayID);
Jamie Madille4634a12018-11-14 09:54:35 -050089 mVertexArrayID = 0;
Martin Radev553590a2017-07-31 16:40:39 +030090 mAppliedNumViews = 1;
Geoff Langba4c4a82015-02-24 12:38:46 -050091
Geoff Lang1eb708e2015-05-04 14:58:23 -040092 mStateManager->deleteBuffer(mStreamingElementArrayBuffer);
93 mStreamingElementArrayBufferSize = 0;
Shao80957d92017-02-20 21:25:59 +080094 mStreamingElementArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040095
Geoff Lang1eb708e2015-05-04 14:58:23 -040096 mStateManager->deleteBuffer(mStreamingArrayBuffer);
97 mStreamingArrayBufferSize = 0;
Shao80957d92017-02-20 21:25:59 +080098 mStreamingArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040099
Jamie Madill4928b7c2017-06-20 12:57:39 -0400100 mAppliedElementArrayBuffer.set(context, nullptr);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800101 for (auto &binding : mAppliedBindings)
Geoff Langba4c4a82015-02-24 12:38:46 -0500102 {
James Darpiniane8a93c62018-01-04 18:02:24 -0800103 binding.setBuffer(context, nullptr, false);
Geoff Langba4c4a82015-02-24 12:38:46 -0500104 }
105}
Geoff Langf9a6f082015-01-22 13:32:49 -0500106
Jamie Madill0cc11c62018-10-12 18:07:18 -0400107angle::Result VertexArrayGL::syncClientSideData(const gl::Context *context,
108 const gl::AttributesMask &activeAttributesMask,
109 GLint first,
110 GLsizei count,
111 GLsizei instanceCount) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400112{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400113 return syncDrawState(context, activeAttributesMask, first, count, GL_NONE, nullptr,
114 instanceCount, false, nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400115}
116
Jamie Madille39e8f42018-10-05 08:17:38 -0400117angle::Result VertexArrayGL::syncDrawElementsState(const gl::Context *context,
118 const gl::AttributesMask &activeAttributesMask,
119 GLsizei count,
120 GLenum type,
121 const void *indices,
122 GLsizei instanceCount,
123 bool primitiveRestartEnabled,
124 const void **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400125{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400126 return syncDrawState(context, activeAttributesMask, 0, count, type, indices, instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400127 primitiveRestartEnabled, outIndices);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400128}
129
Jiajia Qin47474142017-12-29 13:41:00 +0800130void VertexArrayGL::updateElementArrayBufferBinding(const gl::Context *context) const
Jiajia Qind9671222016-11-29 16:30:31 +0800131{
Jamie Madillcd0a0a32018-10-18 18:41:57 -0400132 gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer();
Jiajia Qin47474142017-12-29 13:41:00 +0800133 if (elementArrayBuffer != nullptr && elementArrayBuffer != mAppliedElementArrayBuffer.get())
Jiajia Qind9671222016-11-29 16:30:31 +0800134 {
135 const BufferGL *bufferGL = GetImplAs<BufferGL>(elementArrayBuffer);
Corentin Wallez336129f2017-10-17 15:55:40 -0400136 mStateManager->bindBuffer(gl::BufferBinding::ElementArray, bufferGL->getBufferID());
Jamie Madill4928b7c2017-06-20 12:57:39 -0400137 mAppliedElementArrayBuffer.set(context, elementArrayBuffer);
Jiajia Qind9671222016-11-29 16:30:31 +0800138 }
Jiajia Qind9671222016-11-29 16:30:31 +0800139}
140
Jamie Madille39e8f42018-10-05 08:17:38 -0400141angle::Result VertexArrayGL::syncDrawState(const gl::Context *context,
142 const gl::AttributesMask &activeAttributesMask,
143 GLint first,
144 GLsizei count,
145 GLenum type,
146 const void *indices,
147 GLsizei instanceCount,
148 bool primitiveRestartEnabled,
149 const void **outIndices) const
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400150{
Shao80957d92017-02-20 21:25:59 +0800151 // Check if any attributes need to be streamed, determines if the index range needs to be
152 // computed
Jamie Madillbcef3222018-04-13 15:19:11 -0400153 const gl::AttributesMask &needsStreamingAttribs =
Jamie Madilldc358af2018-07-31 11:22:13 -0400154 context->getStateCache().getActiveClientAttribsMask();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400155
Shao80957d92017-02-20 21:25:59 +0800156 // Determine if an index buffer needs to be streamed and the range of vertices that need to be
157 // copied
Geoff Lang3edfe032015-09-04 16:38:24 -0400158 IndexRange indexRange;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400159 if (type != GL_NONE)
Geoff Langba4c4a82015-02-24 12:38:46 -0500160 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400161 ANGLE_TRY(syncIndexData(context, count, type, indices, primitiveRestartEnabled,
Jamie Madillbcef3222018-04-13 15:19:11 -0400162 needsStreamingAttribs.any(), &indexRange, outIndices));
Geoff Lang7c82bc42015-03-09 16:18:08 -0400163 }
164 else
165 {
Corentin Wallez2c34a4b2015-08-25 16:26:02 -0400166 // Not an indexed call, set the range to [first, first + count - 1]
Geoff Lang7c82bc42015-03-09 16:18:08 -0400167 indexRange.start = first;
Shao80957d92017-02-20 21:25:59 +0800168 indexRange.end = first + count - 1;
Geoff Langba4c4a82015-02-24 12:38:46 -0500169 }
170
Jamie Madillbcef3222018-04-13 15:19:11 -0400171 if (needsStreamingAttribs.any())
Geoff Langba4c4a82015-02-24 12:38:46 -0500172 {
Jamie Madille39e8f42018-10-05 08:17:38 -0400173 ANGLE_TRY(streamAttributes(context, needsStreamingAttribs, instanceCount, indexRange));
Geoff Lang7c82bc42015-03-09 16:18:08 -0400174 }
175
Jamie Madille39e8f42018-10-05 08:17:38 -0400176 return angle::Result::Continue();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400177}
178
Jamie Madille39e8f42018-10-05 08:17:38 -0400179angle::Result VertexArrayGL::syncIndexData(const gl::Context *context,
180 GLsizei count,
181 GLenum type,
182 const void *indices,
183 bool primitiveRestartEnabled,
184 bool attributesNeedStreaming,
185 IndexRange *outIndexRange,
186 const void **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400187{
188 ASSERT(outIndices);
189
Jamie Madillcd0a0a32018-10-18 18:41:57 -0400190 gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer();
Jamie Madill8e344942015-07-09 14:22:07 -0400191
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 {
Jiajia Qin47474142017-12-29 13:41:00 +0800195 ASSERT(elementArrayBuffer == mAppliedElementArrayBuffer.get());
Geoff Lang7c82bc42015-03-09 16:18:08 -0400196 // Only compute the index range if the attributes also need to be streamed
197 if (attributesNeedStreaming)
198 {
199 ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices);
Jamie Madill526392d2018-11-16 09:35:14 -0500200 ANGLE_TRY(mState.getElementArrayBuffer()->getIndexRange(
201 context, type, elementArrayBufferOffset, count, primitiveRestartEnabled,
202 outIndexRange));
Geoff Lang7c82bc42015-03-09 16:18:08 -0400203 }
204
Shao80957d92017-02-20 21:25:59 +0800205 // Indices serves as an offset into the index buffer in this case, use the same value for
206 // the draw call
Geoff Lang7c82bc42015-03-09 16:18:08 -0400207 *outIndices = indices;
208 }
209 else
210 {
211 // Need to stream the index buffer
212 // TODO: if GLES, nothing needs to be streamed
213
214 // Only compute the index range if the attributes also need to be streamed
215 if (attributesNeedStreaming)
216 {
Geoff Lang3edfe032015-09-04 16:38:24 -0400217 *outIndexRange = ComputeIndexRange(type, indices, count, primitiveRestartEnabled);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400218 }
219
220 // Allocate the streaming element array buffer
221 if (mStreamingElementArrayBuffer == 0)
222 {
223 mFunctions->genBuffers(1, &mStreamingElementArrayBuffer);
224 mStreamingElementArrayBufferSize = 0;
225 }
226
Geoff Lang5f3047c2018-02-14 14:39:12 -0500227 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
228
Corentin Wallez336129f2017-10-17 15:55:40 -0400229 mStateManager->bindBuffer(gl::BufferBinding::ElementArray, mStreamingElementArrayBuffer);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400230 mAppliedElementArrayBuffer.set(context, nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400231
232 // Make sure the element array buffer is large enough
Jamie Madill0b9e9032015-08-17 11:51:52 +0000233 const Type &indexTypeInfo = GetTypeInfo(type);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400234 size_t requiredStreamingBufferSize = indexTypeInfo.bytes * count;
235 if (requiredStreamingBufferSize > mStreamingElementArrayBufferSize)
236 {
237 // Copy the indices in while resizing the buffer
Shao80957d92017-02-20 21:25:59 +0800238 mFunctions->bufferData(GL_ELEMENT_ARRAY_BUFFER, requiredStreamingBufferSize, indices,
239 GL_DYNAMIC_DRAW);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400240 mStreamingElementArrayBufferSize = requiredStreamingBufferSize;
241 }
242 else
243 {
244 // Put the indices at the beginning of the buffer
Shao80957d92017-02-20 21:25:59 +0800245 mFunctions->bufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, requiredStreamingBufferSize,
246 indices);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400247 }
248
Shao80957d92017-02-20 21:25:59 +0800249 // Set the index offset for the draw call to zero since the supplied index pointer is to
250 // client data
Geoff Lang7c82bc42015-03-09 16:18:08 -0400251 *outIndices = nullptr;
252 }
253
Jamie Madille39e8f42018-10-05 08:17:38 -0400254 return angle::Result::Continue();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400255}
256
Jamie Madillbcef3222018-04-13 15:19:11 -0400257void VertexArrayGL::computeStreamingAttributeSizes(const gl::AttributesMask &attribsToStream,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400258 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400259 const gl::IndexRange &indexRange,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000260 size_t *outStreamingDataSize,
261 size_t *outMaxAttributeDataSize) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400262{
Jamie Madill0b9e9032015-08-17 11:51:52 +0000263 *outStreamingDataSize = 0;
264 *outMaxAttributeDataSize = 0;
265
Jamie Madillbcef3222018-04-13 15:19:11 -0400266 ASSERT(attribsToStream.any());
Jamie Madill0b9e9032015-08-17 11:51:52 +0000267
Jamie Madill492f58e2017-10-09 19:41:33 -0400268 const auto &attribs = mState.getVertexAttributes();
269 const auto &bindings = mState.getVertexBindings();
Jamie Madill6de51852017-04-12 09:53:01 -0400270
Jamie Madill6de51852017-04-12 09:53:01 -0400271 for (auto idx : attribsToStream)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000272 {
Shao80957d92017-02-20 21:25:59 +0800273 const auto &attrib = attribs[idx];
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800274 const auto &binding = bindings[attrib.bindingIndex];
Jamie Madill0b9e9032015-08-17 11:51:52 +0000275
Jamie Madill0b9e9032015-08-17 11:51:52 +0000276 // If streaming is going to be required, compute the size of the required buffer
277 // and how much slack space at the beginning of the buffer will be required by determining
278 // the attribute with the largest data size.
Jamie Madille4634a12018-11-14 09:54:35 -0500279 size_t typeSize = ComputeVertexAttributeTypeSize(attrib);
Martin Radev553590a2017-07-31 16:40:39 +0300280 GLuint adjustedDivisor = GetAdjustedDivisor(mAppliedNumViews, binding.getDivisor());
281 *outStreamingDataSize +=
282 typeSize * ComputeVertexBindingElementCount(adjustedDivisor, indexRange.vertexCount(),
283 instanceCount);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000284 *outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
285 }
286}
287
Jamie Madille39e8f42018-10-05 08:17:38 -0400288angle::Result VertexArrayGL::streamAttributes(const gl::Context *context,
289 const gl::AttributesMask &attribsToStream,
290 GLsizei instanceCount,
291 const gl::IndexRange &indexRange) const
Jamie Madill0b9e9032015-08-17 11:51:52 +0000292{
293 // Sync the vertex attribute state and track what data needs to be streamed
294 size_t streamingDataSize = 0;
295 size_t maxAttributeDataSize = 0;
296
Jamie Madillbcef3222018-04-13 15:19:11 -0400297 computeStreamingAttributeSizes(attribsToStream, instanceCount, indexRange, &streamingDataSize,
298 &maxAttributeDataSize);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000299
300 if (streamingDataSize == 0)
301 {
Jamie Madille39e8f42018-10-05 08:17:38 -0400302 return angle::Result::Continue();
Jamie Madill0b9e9032015-08-17 11:51:52 +0000303 }
304
Geoff Lang7c82bc42015-03-09 16:18:08 -0400305 if (mStreamingArrayBuffer == 0)
306 {
307 mFunctions->genBuffers(1, &mStreamingArrayBuffer);
308 mStreamingArrayBufferSize = 0;
309 }
310
Shao80957d92017-02-20 21:25:59 +0800311 // If first is greater than zero, a slack space needs to be left at the beginning of the buffer
312 // so that the same 'first' argument can be passed into the draw call.
313 const size_t bufferEmptySpace = maxAttributeDataSize * indexRange.start;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400314 const size_t requiredBufferSize = streamingDataSize + bufferEmptySpace;
315
Corentin Wallez336129f2017-10-17 15:55:40 -0400316 mStateManager->bindBuffer(gl::BufferBinding::Array, mStreamingArrayBuffer);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400317 if (requiredBufferSize > mStreamingArrayBufferSize)
318 {
319 mFunctions->bufferData(GL_ARRAY_BUFFER, requiredBufferSize, nullptr, GL_DYNAMIC_DRAW);
320 mStreamingArrayBufferSize = requiredBufferSize;
321 }
322
Geoff Lang5f3047c2018-02-14 14:39:12 -0500323 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
324
Geoff Lang7c82bc42015-03-09 16:18:08 -0400325 // Unmapping a buffer can return GL_FALSE to indicate that the system has corrupted the data
Shao80957d92017-02-20 21:25:59 +0800326 // somehow (such as by a screen change), retry writing the data a few times and return
327 // OUT_OF_MEMORY if that fails.
328 GLboolean unmapResult = GL_FALSE;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400329 size_t unmapRetryAttempts = 5;
330 while (unmapResult != GL_TRUE && --unmapRetryAttempts > 0)
331 {
Geoff Langb2ebb5e2016-06-08 18:17:55 +0000332 uint8_t *bufferPointer = MapBufferRangeWithFallback(mFunctions, GL_ARRAY_BUFFER, 0,
333 requiredBufferSize, GL_MAP_WRITE_BIT);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400334 size_t curBufferOffset = bufferEmptySpace;
335
Jamie Madill492f58e2017-10-09 19:41:33 -0400336 const auto &attribs = mState.getVertexAttributes();
337 const auto &bindings = mState.getVertexBindings();
Jamie Madill6de51852017-04-12 09:53:01 -0400338
Jamie Madill6de51852017-04-12 09:53:01 -0400339 for (auto idx : attribsToStream)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400340 {
Jamie Madille4634a12018-11-14 09:54:35 -0500341 const auto &attrib = attribs[idx];
Shaodde78e82017-05-22 14:13:27 +0800342 ASSERT(IsVertexAttribPointerSupported(idx, attrib));
343
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800344 const auto &binding = bindings[attrib.bindingIndex];
Geoff Lang7c82bc42015-03-09 16:18:08 -0400345
Martin Radev553590a2017-07-31 16:40:39 +0300346 GLuint adjustedDivisor = GetAdjustedDivisor(mAppliedNumViews, binding.getDivisor());
347 const size_t streamedVertexCount = ComputeVertexBindingElementCount(
348 adjustedDivisor, indexRange.vertexCount(), instanceCount);
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400349
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800350 const size_t sourceStride = ComputeVertexAttributeStride(attrib, binding);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000351 const size_t destStride = ComputeVertexAttributeTypeSize(attrib);
352
Geoff Lang38a24a92017-02-15 13:53:06 -0500353 // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing
354 // a non-instanced draw call
Martin Radev553590a2017-07-31 16:40:39 +0300355 const size_t firstIndex = adjustedDivisor == 0 ? indexRange.start : 0;
Geoff Lang38a24a92017-02-15 13:53:06 -0500356
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800357 // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state.
358 // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt
Rafael Cintron05a449a2018-06-20 18:08:04 -0700359 const uint8_t *inputPointer = static_cast<const uint8_t *>(attrib.pointer);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000360
361 // Pack the data when copying it, user could have supplied a very large stride that
362 // would cause the buffer to be much larger than needed.
363 if (destStride == sourceStride)
Jamie Madill8e344942015-07-09 14:22:07 -0400364 {
Jamie Madill0b9e9032015-08-17 11:51:52 +0000365 // Can copy in one go, the data is packed
Geoff Lang38a24a92017-02-15 13:53:06 -0500366 memcpy(bufferPointer + curBufferOffset, inputPointer + (sourceStride * firstIndex),
Jamie Madill0b9e9032015-08-17 11:51:52 +0000367 destStride * streamedVertexCount);
Jamie Madill6d51c702015-08-14 10:38:10 -0400368 }
Jamie Madill0b9e9032015-08-17 11:51:52 +0000369 else
370 {
371 // Copy each vertex individually
Geoff Lang6b10ddb2015-09-02 15:55:10 -0400372 for (size_t vertexIdx = 0; vertexIdx < streamedVertexCount; vertexIdx++)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000373 {
Shao80957d92017-02-20 21:25:59 +0800374 uint8_t *out = bufferPointer + curBufferOffset + (destStride * vertexIdx);
Geoff Lang38a24a92017-02-15 13:53:06 -0500375 const uint8_t *in = inputPointer + sourceStride * (vertexIdx + firstIndex);
Corentin Wallez4d5362d2015-08-25 11:25:14 -0400376 memcpy(out, in, destStride);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000377 }
378 }
379
380 // Compute where the 0-index vertex would be.
Geoff Lang38a24a92017-02-15 13:53:06 -0500381 const size_t vertexStartOffset = curBufferOffset - (firstIndex * destStride);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000382
Shaodf682a82017-03-31 15:13:21 +0800383 callVertexAttribPointer(static_cast<GLuint>(idx), attrib,
384 static_cast<GLsizei>(destStride),
385 static_cast<GLintptr>(vertexStartOffset));
Jamie Madill0b9e9032015-08-17 11:51:52 +0000386
387 curBufferOffset += destStride * streamedVertexCount;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400388 }
389
390 unmapResult = mFunctions->unmapBuffer(GL_ARRAY_BUFFER);
391 }
392
Jamie Madille39e8f42018-10-05 08:17:38 -0400393 ANGLE_CHECK(GetImplAs<ContextGL>(context), unmapResult == GL_TRUE,
394 "Failed to unmap the client data streaming buffer.", GL_OUT_OF_MEMORY);
395 return angle::Result::Continue();
Geoff Langba4c4a82015-02-24 12:38:46 -0500396}
397
398GLuint VertexArrayGL::getVertexArrayID() const
399{
400 return mVertexArrayID;
Geoff Langf9a6f082015-01-22 13:32:49 -0500401}
402
Geoff Lang294cad92015-05-26 15:11:23 -0400403GLuint VertexArrayGL::getAppliedElementArrayBufferID() const
404{
Jamie Madill77a90c22015-08-11 16:33:17 -0400405 if (mAppliedElementArrayBuffer.get() == nullptr)
406 {
407 return mStreamingElementArrayBuffer;
408 }
409
410 return GetImplAs<BufferGL>(mAppliedElementArrayBuffer.get())->getBufferID();
Geoff Lang294cad92015-05-26 15:11:23 -0400411}
412
Jamie Madill0b9e9032015-08-17 11:51:52 +0000413void VertexArrayGL::updateAttribEnabled(size_t attribIndex)
414{
Shahbaz Youssefi337bd692018-08-22 16:16:38 -0400415 const bool enabled = mState.getVertexAttribute(attribIndex).enabled &
416 mProgramActiveAttribLocationsMask.test(attribIndex);
Shaodf682a82017-03-31 15:13:21 +0800417 if (mAppliedAttributes[attribIndex].enabled == enabled)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000418 {
419 return;
420 }
421
Shaodf682a82017-03-31 15:13:21 +0800422 if (enabled)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000423 {
424 mFunctions->enableVertexAttribArray(static_cast<GLuint>(attribIndex));
425 }
426 else
427 {
428 mFunctions->disableVertexAttribArray(static_cast<GLuint>(attribIndex));
429 }
Shaodf682a82017-03-31 15:13:21 +0800430
431 mAppliedAttributes[attribIndex].enabled = enabled;
Jamie Madill0b9e9032015-08-17 11:51:52 +0000432}
433
Jamie Madill4928b7c2017-06-20 12:57:39 -0400434void VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attribIndex)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000435{
Jamie Madill492f58e2017-10-09 19:41:33 -0400436 const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800437
Shaodde78e82017-05-22 14:13:27 +0800438 // According to SPEC, VertexAttribPointer should update the binding indexed attribIndex instead
439 // of the binding indexed attrib.bindingIndex (unless attribIndex == attrib.bindingIndex).
Jamie Madill492f58e2017-10-09 19:41:33 -0400440 const VertexBinding &binding = mState.getVertexBinding(attribIndex);
Shaodf682a82017-03-31 15:13:21 +0800441
Shaodde78e82017-05-22 14:13:27 +0800442 // Early return when the vertex attribute isn't using a buffer object:
443 // - If we need to stream, defer the attribPointer to the draw call.
444 // - Skip the attribute that is disabled and uses a client memory pointer.
445 // - Skip the attribute whose buffer is detached by BindVertexBuffer. Since it cannot have a
446 // client memory pointer either, it must be disabled and shouldn't affect the draw.
Jamie Madillbcef3222018-04-13 15:19:11 -0400447 const auto &bindingBuffer = binding.getBuffer();
Shaodde78e82017-05-22 14:13:27 +0800448 const Buffer *arrayBuffer = bindingBuffer.get();
449 if (arrayBuffer == nullptr)
450 {
451 // Mark the applied binding isn't using a buffer by setting its buffer to nullptr so that if
452 // it starts to use a buffer later, there is no chance that the caching will skip it.
James Darpiniane8a93c62018-01-04 18:02:24 -0800453 mAppliedBindings[attribIndex].setBuffer(context, nullptr, false);
Shaodde78e82017-05-22 14:13:27 +0800454 return;
455 }
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800456
Shaodf682a82017-03-31 15:13:21 +0800457 // We do not need to compare attrib.pointer because when we use a different client memory
458 // pointer, we don't need to update mAttributesNeedStreaming by binding.buffer and we won't
459 // update attribPointer in this function.
Shaodde78e82017-05-22 14:13:27 +0800460 if ((SameVertexAttribFormat(mAppliedAttributes[attribIndex], attrib)) &&
461 (mAppliedAttributes[attribIndex].bindingIndex == attrib.bindingIndex) &&
462 (SameVertexBuffer(mAppliedBindings[attribIndex], binding)))
Jamie Madill0b9e9032015-08-17 11:51:52 +0000463 {
464 return;
465 }
466
Shao4181bc92017-03-17 14:55:25 +0800467 // Since ANGLE always uses a non-zero VAO, we cannot use a client memory pointer on it:
468 // [OpenGL ES 3.0.2] Section 2.8 page 24:
469 // An INVALID_OPERATION error is generated when a non-zero vertex array object is bound,
470 // zero is bound to the ARRAY_BUFFER buffer object binding point, and the pointer argument
471 // is not NULL.
Shaodf682a82017-03-31 15:13:21 +0800472
Shao4181bc92017-03-17 14:55:25 +0800473 const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
Corentin Wallez336129f2017-10-17 15:55:40 -0400474 mStateManager->bindBuffer(gl::BufferBinding::Array, arrayBufferGL->getBufferID());
Martin Radevdd5f27e2017-06-07 10:17:09 +0300475 callVertexAttribPointer(static_cast<GLuint>(attribIndex), attrib, binding.getStride(),
476 binding.getOffset());
Shaodf682a82017-03-31 15:13:21 +0800477
Shaodde78e82017-05-22 14:13:27 +0800478 mAppliedAttributes[attribIndex].size = attrib.size;
479 mAppliedAttributes[attribIndex].type = attrib.type;
480 mAppliedAttributes[attribIndex].normalized = attrib.normalized;
481 mAppliedAttributes[attribIndex].pureInteger = attrib.pureInteger;
Shaodf682a82017-03-31 15:13:21 +0800482
Shaodde78e82017-05-22 14:13:27 +0800483 // After VertexAttribPointer, attrib.relativeOffset is set to 0 and attrib.bindingIndex is set
484 // to attribIndex in driver. If attrib.relativeOffset != 0 or attrib.bindingIndex !=
485 // attribIndex, they should be set in updateAttribFormat and updateAttribBinding. The cache
486 // should be consistent with driver so that we won't miss anything.
487 mAppliedAttributes[attribIndex].relativeOffset = 0;
488 mAppliedAttributes[attribIndex].bindingIndex = static_cast<GLuint>(attribIndex);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800489
Shaodde78e82017-05-22 14:13:27 +0800490 mAppliedBindings[attribIndex].setStride(binding.getStride());
491 mAppliedBindings[attribIndex].setOffset(binding.getOffset());
James Darpiniane8a93c62018-01-04 18:02:24 -0800492 mAppliedBindings[attribIndex].setBuffer(context, binding.getBuffer().get(), false);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800493}
494
Shaodf682a82017-03-31 15:13:21 +0800495void VertexArrayGL::callVertexAttribPointer(GLuint attribIndex,
496 const VertexAttribute &attrib,
497 GLsizei stride,
498 GLintptr offset) const
499{
500 const GLvoid *pointer = reinterpret_cast<const GLvoid *>(offset);
501 if (attrib.pureInteger)
502 {
503 ASSERT(!attrib.normalized);
504 mFunctions->vertexAttribIPointer(attribIndex, attrib.size, attrib.type, stride, pointer);
505 }
506 else
507 {
508 mFunctions->vertexAttribPointer(attribIndex, attrib.size, attrib.type, attrib.normalized,
509 stride, pointer);
510 }
511}
512
Shaodde78e82017-05-22 14:13:27 +0800513bool VertexArrayGL::supportVertexAttribBinding() const
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800514{
Shaodde78e82017-05-22 14:13:27 +0800515 ASSERT(mFunctions);
516 return (mFunctions->vertexAttribBinding != nullptr);
517}
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800518
Shaodde78e82017-05-22 14:13:27 +0800519void VertexArrayGL::updateAttribFormat(size_t attribIndex)
520{
521 ASSERT(supportVertexAttribBinding());
522
Jamie Madill492f58e2017-10-09 19:41:33 -0400523 const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
Shaodde78e82017-05-22 14:13:27 +0800524 if (SameVertexAttribFormat(mAppliedAttributes[attribIndex], attrib))
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800525 {
Shaodf682a82017-03-31 15:13:21 +0800526 return;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800527 }
Shaodf682a82017-03-31 15:13:21 +0800528
Shaodde78e82017-05-22 14:13:27 +0800529 if (attrib.pureInteger)
530 {
531 ASSERT(!attrib.normalized);
532 mFunctions->vertexAttribIFormat(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
533 attrib.relativeOffset);
534 }
535 else
536 {
537 mFunctions->vertexAttribFormat(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
538 attrib.normalized, attrib.relativeOffset);
539 }
540
541 mAppliedAttributes[attribIndex].size = attrib.size;
542 mAppliedAttributes[attribIndex].type = attrib.type;
543 mAppliedAttributes[attribIndex].normalized = attrib.normalized;
544 mAppliedAttributes[attribIndex].pureInteger = attrib.pureInteger;
545 mAppliedAttributes[attribIndex].relativeOffset = attrib.relativeOffset;
546}
547
548void VertexArrayGL::updateAttribBinding(size_t attribIndex)
549{
550 ASSERT(supportVertexAttribBinding());
551
Jamie Madill492f58e2017-10-09 19:41:33 -0400552 GLuint bindingIndex = mState.getVertexAttribute(attribIndex).bindingIndex;
Shaodde78e82017-05-22 14:13:27 +0800553 if (mAppliedAttributes[attribIndex].bindingIndex == bindingIndex)
554 {
555 return;
556 }
557
558 mFunctions->vertexAttribBinding(static_cast<GLuint>(attribIndex), bindingIndex);
Shaodf682a82017-03-31 15:13:21 +0800559
560 mAppliedAttributes[attribIndex].bindingIndex = bindingIndex;
Shaodde78e82017-05-22 14:13:27 +0800561}
562
563void VertexArrayGL::updateBindingBuffer(const gl::Context *context, size_t bindingIndex)
564{
565 ASSERT(supportVertexAttribBinding());
566
Jamie Madill492f58e2017-10-09 19:41:33 -0400567 const VertexBinding &binding = mState.getVertexBinding(bindingIndex);
Shaodde78e82017-05-22 14:13:27 +0800568 if (SameVertexBuffer(mAppliedBindings[bindingIndex], binding))
569 {
570 return;
571 }
572
573 const Buffer *arrayBuffer = binding.getBuffer().get();
574 GLuint bufferId = 0;
575 if (arrayBuffer != nullptr)
576 {
577 bufferId = GetImplAs<BufferGL>(arrayBuffer)->getBufferID();
578 }
579
580 mFunctions->bindVertexBuffer(static_cast<GLuint>(bindingIndex), bufferId, binding.getOffset(),
581 binding.getStride());
582
583 mAppliedBindings[bindingIndex].setStride(binding.getStride());
584 mAppliedBindings[bindingIndex].setOffset(binding.getOffset());
James Darpiniane8a93c62018-01-04 18:02:24 -0800585 mAppliedBindings[bindingIndex].setBuffer(context, binding.getBuffer().get(), false);
Shaodde78e82017-05-22 14:13:27 +0800586}
587
588void VertexArrayGL::updateBindingDivisor(size_t bindingIndex)
589{
Martin Radev553590a2017-07-31 16:40:39 +0300590 GLuint adjustedDivisor =
Jamie Madill492f58e2017-10-09 19:41:33 -0400591 GetAdjustedDivisor(mAppliedNumViews, mState.getVertexBinding(bindingIndex).getDivisor());
Martin Radev553590a2017-07-31 16:40:39 +0300592 if (mAppliedBindings[bindingIndex].getDivisor() == adjustedDivisor)
Shaodde78e82017-05-22 14:13:27 +0800593 {
594 return;
595 }
596
597 if (supportVertexAttribBinding())
598 {
Martin Radev553590a2017-07-31 16:40:39 +0300599 mFunctions->vertexBindingDivisor(static_cast<GLuint>(bindingIndex), adjustedDivisor);
Shaodde78e82017-05-22 14:13:27 +0800600 }
601 else
602 {
603 // We can only use VertexAttribDivisor on platforms that don't support Vertex Attrib
604 // Binding.
Martin Radev553590a2017-07-31 16:40:39 +0300605 mFunctions->vertexAttribDivisor(static_cast<GLuint>(bindingIndex), adjustedDivisor);
Shaodde78e82017-05-22 14:13:27 +0800606 }
607
Martin Radev553590a2017-07-31 16:40:39 +0300608 mAppliedBindings[bindingIndex].setDivisor(adjustedDivisor);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000609}
610
Jamie Madille858cb12018-03-27 09:44:32 -0400611void VertexArrayGL::syncDirtyAttrib(const gl::Context *context,
612 size_t attribIndex,
613 const gl::VertexArray::DirtyAttribBits &dirtyAttribBits)
614{
615 ASSERT(dirtyAttribBits.any());
616
617 for (size_t dirtyBit : dirtyAttribBits)
618 {
619 switch (dirtyBit)
620 {
621 case VertexArray::DIRTY_ATTRIB_ENABLED:
622 updateAttribEnabled(attribIndex);
623 break;
624
625 case VertexArray::DIRTY_ATTRIB_POINTER:
626 updateAttribPointer(context, attribIndex);
627 break;
628
629 case VertexArray::DIRTY_ATTRIB_FORMAT:
630 ASSERT(supportVertexAttribBinding());
631 updateAttribFormat(attribIndex);
632 break;
633
634 case VertexArray::DIRTY_ATTRIB_BINDING:
635 ASSERT(supportVertexAttribBinding());
636 updateAttribBinding(attribIndex);
637 break;
638
639 default:
640 UNREACHABLE();
641 break;
642 }
643 }
644}
645
646void VertexArrayGL::syncDirtyBinding(const gl::Context *context,
647 size_t bindingIndex,
648 const gl::VertexArray::DirtyBindingBits &dirtyBindingBits)
649{
Jamie Madill02c9c042018-04-17 13:43:48 -0400650 // Dependent state changes in buffers can trigger updates with no dirty bits set.
Jamie Madille858cb12018-03-27 09:44:32 -0400651
652 for (size_t dirtyBit : dirtyBindingBits)
653 {
654 switch (dirtyBit)
655 {
656 case VertexArray::DIRTY_BINDING_BUFFER:
657 ASSERT(supportVertexAttribBinding());
658 updateBindingBuffer(context, bindingIndex);
659 break;
660
661 case VertexArray::DIRTY_BINDING_DIVISOR:
662 updateBindingDivisor(bindingIndex);
663 break;
664
665 default:
666 UNREACHABLE();
667 break;
668 }
669 }
670}
671
Jamie Madilla56467e2018-04-11 16:19:41 -0400672#define ANGLE_DIRTY_ATTRIB_FUNC(INDEX) \
673 case VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX: \
674 syncDirtyAttrib(context, INDEX, attribBits[INDEX]); \
675 break;
676
677#define ANGLE_DIRTY_BINDING_FUNC(INDEX) \
678 case VertexArray::DIRTY_BIT_BINDING_0 + INDEX: \
679 syncDirtyBinding(context, INDEX, bindingBits[INDEX]); \
680 break;
681
682#define ANGLE_DIRTY_BUFFER_DATA_FUNC(INDEX) \
683 case VertexArray::DIRTY_BIT_BUFFER_DATA_0 + INDEX: \
684 break;
685
Jamie Madill6f755b22018-10-09 12:48:54 -0400686angle::Result VertexArrayGL::syncState(const gl::Context *context,
687 const gl::VertexArray::DirtyBits &dirtyBits,
688 const gl::VertexArray::DirtyAttribBitsArray &attribBits,
689 const gl::VertexArray::DirtyBindingBitsArray &bindingBits)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000690{
Shaodf682a82017-03-31 15:13:21 +0800691 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
692
Jamie Madill6de51852017-04-12 09:53:01 -0400693 for (size_t dirtyBit : dirtyBits)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000694 {
Jamie Madille858cb12018-03-27 09:44:32 -0400695 switch (dirtyBit)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000696 {
Jamie Madille858cb12018-03-27 09:44:32 -0400697 case VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER:
698 updateElementArrayBufferBinding(context);
699 break;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800700
Jamie Madill09463932018-04-04 05:26:59 -0400701 case VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA:
702 break;
703
Jamie Madilla56467e2018-04-11 16:19:41 -0400704 ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_ATTRIB_FUNC);
705 ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_BINDING_FUNC);
706 ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_BUFFER_DATA_FUNC);
707
Jamie Madille858cb12018-03-27 09:44:32 -0400708 default:
Jamie Madilla56467e2018-04-11 16:19:41 -0400709 UNREACHABLE();
Jamie Madille858cb12018-03-27 09:44:32 -0400710 break;
Jamie Madill0b9e9032015-08-17 11:51:52 +0000711 }
Jamie Madill0b9e9032015-08-17 11:51:52 +0000712 }
Frank Henigman0af5b862018-03-27 20:19:33 -0400713
Jamie Madill6f755b22018-10-09 12:48:54 -0400714 return angle::Result::Continue();
Jamie Madill0b9e9032015-08-17 11:51:52 +0000715}
716
Martin Radev553590a2017-07-31 16:40:39 +0300717void VertexArrayGL::applyNumViewsToDivisor(int numViews)
718{
719 if (numViews != mAppliedNumViews)
720 {
721 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
722 mAppliedNumViews = numViews;
723 for (size_t index = 0u; index < mAppliedBindings.size(); ++index)
724 {
725 updateBindingDivisor(index);
726 }
727 }
728}
729
Shahbaz Youssefi337bd692018-08-22 16:16:38 -0400730void VertexArrayGL::applyActiveAttribLocationsMask(const gl::AttributesMask &activeMask)
731{
Jamie Madille4634a12018-11-14 09:54:35 -0500732 gl::AttributesMask updateMask = mProgramActiveAttribLocationsMask ^ activeMask;
Qin Jiajiafcf10b62018-09-19 12:53:18 +0800733 if (!updateMask.any())
734 {
735 return;
736 }
737 ASSERT(mVertexArrayID == mStateManager->getVertexArrayID());
Shahbaz Youssefi337bd692018-08-22 16:16:38 -0400738 mProgramActiveAttribLocationsMask = activeMask;
739
740 for (size_t attribIndex : updateMask)
741 {
742 updateAttribEnabled(attribIndex);
743 }
744}
745
Jamie Madill09463932018-04-04 05:26:59 -0400746} // namespace rx