blob: b22a215e46c108c36e44b56acd56c3df322e29ab [file] [log] [blame]
Geoff Langf9a6f082015-01-22 13:32:49 -05001//
2// Copyright 2015 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// VertexArrayGL.cpp: Implements the class methods for VertexArrayGL.
8
9#include "libANGLE/renderer/gl/VertexArrayGL.h"
10
Jamie Madill20e005b2017-04-07 14:19:22 -040011#include "common/bitset_utils.h"
Geoff Langf9a6f082015-01-22 13:32:49 -050012#include "common/debug.h"
Geoff Lang7c82bc42015-03-09 16:18:08 -040013#include "common/mathutil.h"
Geoff Lang831b1952015-05-05 11:02:27 -040014#include "common/utilities.h"
Geoff Lang6ae6efc2015-03-09 14:42:35 -040015#include "libANGLE/Buffer.h"
Geoff Langba4c4a82015-02-24 12:38:46 -050016#include "libANGLE/angletypes.h"
Geoff Lang7c82bc42015-03-09 16:18:08 -040017#include "libANGLE/formatutils.h"
Geoff Langba4c4a82015-02-24 12:38:46 -050018#include "libANGLE/renderer/gl/BufferGL.h"
19#include "libANGLE/renderer/gl/FunctionsGL.h"
20#include "libANGLE/renderer/gl/StateManagerGL.h"
Jamie Madill231c7f52017-04-26 13:45:37 -040021#include "libANGLE/renderer/gl/renderergl_utils.h"
Geoff Langf9a6f082015-01-22 13:32:49 -050022
Jamie Madill0b9e9032015-08-17 11:51:52 +000023using namespace gl;
24
Geoff Langf9a6f082015-01-22 13:32:49 -050025namespace rx
26{
Jamie Madill0b9e9032015-08-17 11:51:52 +000027namespace
28{
Jiawei-Shao2597fb62016-12-09 16:38:02 +080029// Warning: you should ensure binding really matches attrib.bindingIndex before using this function.
30bool AttributeNeedsStreaming(const VertexAttribute &attrib, const VertexBinding &binding)
Jamie Madill0b9e9032015-08-17 11:51:52 +000031{
Martin Radevdd5f27e2017-06-07 10:17:09 +030032 return (attrib.enabled && binding.getBuffer().get() == nullptr);
Jamie Madill0b9e9032015-08-17 11:51:52 +000033}
Shaodf682a82017-03-31 15:13:21 +080034
35bool SameVertexAttribFormat(const VertexAttribute &a, const VertexAttribute &b)
36{
37 return a.size == b.size && a.type == b.type && a.normalized == b.normalized &&
38 a.pureInteger == b.pureInteger && a.relativeOffset == b.relativeOffset;
39}
40
41bool SameVertexBuffer(const VertexBinding &a, const VertexBinding &b)
42{
Martin Radevdd5f27e2017-06-07 10:17:09 +030043 return a.getStride() == b.getStride() && a.getOffset() == b.getOffset() &&
44 a.getBuffer().get() == b.getBuffer().get();
Shaodf682a82017-03-31 15:13:21 +080045}
46
47bool IsVertexAttribPointerSupported(size_t attribIndex, const VertexAttribute &attrib)
48{
49 return (attribIndex == attrib.bindingIndex && attrib.relativeOffset == 0);
50}
Jamie Madill0b9e9032015-08-17 11:51:52 +000051} // anonymous namespace
52
Jamie Madill3f572682016-04-26 13:41:36 -040053VertexArrayGL::VertexArrayGL(const VertexArrayState &state,
Jamie Madill77a90c22015-08-11 16:33:17 -040054 const FunctionsGL *functions,
55 StateManagerGL *stateManager)
Jamie Madill3f572682016-04-26 13:41:36 -040056 : VertexArrayImpl(state),
Geoff Langba4c4a82015-02-24 12:38:46 -050057 mFunctions(functions),
58 mStateManager(stateManager),
59 mVertexArrayID(0),
Jamie Madill77a90c22015-08-11 16:33:17 -040060 mAppliedElementArrayBuffer(),
Jiawei-Shao2597fb62016-12-09 16:38:02 +080061 mAppliedBindings(state.getMaxBindings()),
Geoff Lang7c82bc42015-03-09 16:18:08 -040062 mStreamingElementArrayBufferSize(0),
63 mStreamingElementArrayBuffer(0),
64 mStreamingArrayBufferSize(0),
65 mStreamingArrayBuffer(0)
Geoff Langba4c4a82015-02-24 12:38:46 -050066{
67 ASSERT(mFunctions);
68 ASSERT(mStateManager);
69 mFunctions->genVertexArrays(1, &mVertexArrayID);
70
Jiawei-Shao2597fb62016-12-09 16:38:02 +080071 // Set the cached vertex attribute array and vertex attribute binding array size
72 GLuint maxVertexAttribs = static_cast<GLuint>(state.getMaxAttribs());
73 for (GLuint i = 0; i < maxVertexAttribs; i++)
74 {
75 mAppliedAttributes.emplace_back(i);
76 }
Geoff Langba4c4a82015-02-24 12:38:46 -050077}
Geoff Langf9a6f082015-01-22 13:32:49 -050078
Jamie Madill4928b7c2017-06-20 12:57:39 -040079void VertexArrayGL::destroy(const gl::Context *context)
Geoff Langba4c4a82015-02-24 12:38:46 -050080{
Geoff Lang1eb708e2015-05-04 14:58:23 -040081 mStateManager->deleteVertexArray(mVertexArrayID);
82 mVertexArrayID = 0;
Geoff Langba4c4a82015-02-24 12:38:46 -050083
Geoff Lang1eb708e2015-05-04 14:58:23 -040084 mStateManager->deleteBuffer(mStreamingElementArrayBuffer);
85 mStreamingElementArrayBufferSize = 0;
Shao80957d92017-02-20 21:25:59 +080086 mStreamingElementArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040087
Geoff Lang1eb708e2015-05-04 14:58:23 -040088 mStateManager->deleteBuffer(mStreamingArrayBuffer);
89 mStreamingArrayBufferSize = 0;
Shao80957d92017-02-20 21:25:59 +080090 mStreamingArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040091
Jamie Madill4928b7c2017-06-20 12:57:39 -040092 mAppliedElementArrayBuffer.set(context, nullptr);
Jiawei-Shao2597fb62016-12-09 16:38:02 +080093 for (auto &binding : mAppliedBindings)
Geoff Langba4c4a82015-02-24 12:38:46 -050094 {
Jamie Madill4928b7c2017-06-20 12:57:39 -040095 binding.setBuffer(context, nullptr);
Geoff Langba4c4a82015-02-24 12:38:46 -050096 }
97}
Geoff Langf9a6f082015-01-22 13:32:49 -050098
Jamie Madill4928b7c2017-06-20 12:57:39 -040099gl::Error VertexArrayGL::syncDrawArraysState(const gl::Context *context,
100 const gl::AttributesMask &activeAttributesMask,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000101 GLint first,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400102 GLsizei count,
103 GLsizei instanceCount) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400104{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400105 return syncDrawState(context, activeAttributesMask, first, count, GL_NONE, nullptr,
106 instanceCount, false, nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400107}
108
Jamie Madill4928b7c2017-06-20 12:57:39 -0400109gl::Error VertexArrayGL::syncDrawElementsState(const gl::Context *context,
110 const gl::AttributesMask &activeAttributesMask,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000111 GLsizei count,
112 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400113 const void *indices,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400114 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400115 bool primitiveRestartEnabled,
Jamie Madill876429b2017-04-20 15:46:24 -0400116 const void **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400117{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400118 return syncDrawState(context, activeAttributesMask, 0, count, type, indices, instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400119 primitiveRestartEnabled, outIndices);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400120}
121
Jamie Madill4928b7c2017-06-20 12:57:39 -0400122gl::Error VertexArrayGL::syncElementArrayState(const gl::Context *context) const
Jiajia Qind9671222016-11-29 16:30:31 +0800123{
124 gl::Buffer *elementArrayBuffer = mData.getElementArrayBuffer().get();
125 ASSERT(elementArrayBuffer);
126 if (elementArrayBuffer != mAppliedElementArrayBuffer.get())
127 {
128 const BufferGL *bufferGL = GetImplAs<BufferGL>(elementArrayBuffer);
129 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferGL->getBufferID());
Jamie Madill4928b7c2017-06-20 12:57:39 -0400130 mAppliedElementArrayBuffer.set(context, elementArrayBuffer);
Jiajia Qind9671222016-11-29 16:30:31 +0800131 }
132
133 return gl::NoError();
134}
135
Jamie Madill4928b7c2017-06-20 12:57:39 -0400136gl::Error VertexArrayGL::syncDrawState(const gl::Context *context,
137 const gl::AttributesMask &activeAttributesMask,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000138 GLint first,
139 GLsizei count,
140 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400141 const void *indices,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400142 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400143 bool primitiveRestartEnabled,
Jamie Madill876429b2017-04-20 15:46:24 -0400144 const void **outIndices) const
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400145{
Jamie Madill77a90c22015-08-11 16:33:17 -0400146 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400147
Shao80957d92017-02-20 21:25:59 +0800148 // Check if any attributes need to be streamed, determines if the index range needs to be
149 // computed
Jamie Madill0b9e9032015-08-17 11:51:52 +0000150 bool attributesNeedStreaming = mAttributesNeedStreaming.any();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400151
Shao80957d92017-02-20 21:25:59 +0800152 // Determine if an index buffer needs to be streamed and the range of vertices that need to be
153 // copied
Geoff Lang3edfe032015-09-04 16:38:24 -0400154 IndexRange indexRange;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400155 if (type != GL_NONE)
Geoff Langba4c4a82015-02-24 12:38:46 -0500156 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400157 ANGLE_TRY(syncIndexData(context, count, type, indices, primitiveRestartEnabled,
158 attributesNeedStreaming, &indexRange, outIndices));
Geoff Lang7c82bc42015-03-09 16:18:08 -0400159 }
160 else
161 {
Corentin Wallez2c34a4b2015-08-25 16:26:02 -0400162 // Not an indexed call, set the range to [first, first + count - 1]
Geoff Lang7c82bc42015-03-09 16:18:08 -0400163 indexRange.start = first;
Shao80957d92017-02-20 21:25:59 +0800164 indexRange.end = first + count - 1;
Geoff Langba4c4a82015-02-24 12:38:46 -0500165 }
166
Jamie Madill0b9e9032015-08-17 11:51:52 +0000167 if (attributesNeedStreaming)
Geoff Langba4c4a82015-02-24 12:38:46 -0500168 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400169 ANGLE_TRY(streamAttributes(activeAttributesMask, instanceCount, indexRange));
Geoff Lang7c82bc42015-03-09 16:18:08 -0400170 }
171
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500172 return gl::NoError();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400173}
174
Jamie Madill4928b7c2017-06-20 12:57:39 -0400175gl::Error VertexArrayGL::syncIndexData(const gl::Context *context,
176 GLsizei count,
Jiajia Qind9671222016-11-29 16:30:31 +0800177 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400178 const void *indices,
Jiajia Qind9671222016-11-29 16:30:31 +0800179 bool primitiveRestartEnabled,
180 bool attributesNeedStreaming,
181 IndexRange *outIndexRange,
Jamie Madill876429b2017-04-20 15:46:24 -0400182 const void **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400183{
184 ASSERT(outIndices);
185
Jamie Madill8e344942015-07-09 14:22:07 -0400186 gl::Buffer *elementArrayBuffer = mData.getElementArrayBuffer().get();
187
Geoff Lang7c82bc42015-03-09 16:18:08 -0400188 // Need to check the range of indices if attributes need to be streamed
Jamie Madill8e344942015-07-09 14:22:07 -0400189 if (elementArrayBuffer != nullptr)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400190 {
Jamie Madill77a90c22015-08-11 16:33:17 -0400191 if (elementArrayBuffer != mAppliedElementArrayBuffer.get())
Geoff Lang7c82bc42015-03-09 16:18:08 -0400192 {
Jamie Madill77a90c22015-08-11 16:33:17 -0400193 const BufferGL *bufferGL = GetImplAs<BufferGL>(elementArrayBuffer);
194 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferGL->getBufferID());
Jamie Madill4928b7c2017-06-20 12:57:39 -0400195 mAppliedElementArrayBuffer.set(context, elementArrayBuffer);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400196 }
197
198 // Only compute the index range if the attributes also need to be streamed
199 if (attributesNeedStreaming)
200 {
201 ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices);
Shao80957d92017-02-20 21:25:59 +0800202 Error error = mData.getElementArrayBuffer()->getIndexRange(
Geoff Lang3edfe032015-09-04 16:38:24 -0400203 type, elementArrayBufferOffset, count, primitiveRestartEnabled, outIndexRange);
Geoff Lang520c4ae2015-05-05 13:12:36 -0400204 if (error.isError())
Geoff Lang7c82bc42015-03-09 16:18:08 -0400205 {
Geoff Lang520c4ae2015-05-05 13:12:36 -0400206 return error;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400207 }
208 }
209
Shao80957d92017-02-20 21:25:59 +0800210 // Indices serves as an offset into the index buffer in this case, use the same value for
211 // the draw call
Geoff Lang7c82bc42015-03-09 16:18:08 -0400212 *outIndices = indices;
213 }
214 else
215 {
216 // Need to stream the index buffer
217 // TODO: if GLES, nothing needs to be streamed
218
219 // Only compute the index range if the attributes also need to be streamed
220 if (attributesNeedStreaming)
221 {
Geoff Lang3edfe032015-09-04 16:38:24 -0400222 *outIndexRange = ComputeIndexRange(type, indices, count, primitiveRestartEnabled);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400223 }
224
225 // Allocate the streaming element array buffer
226 if (mStreamingElementArrayBuffer == 0)
227 {
228 mFunctions->genBuffers(1, &mStreamingElementArrayBuffer);
229 mStreamingElementArrayBufferSize = 0;
230 }
231
232 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, mStreamingElementArrayBuffer);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400233 mAppliedElementArrayBuffer.set(context, nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400234
235 // Make sure the element array buffer is large enough
Jamie Madill0b9e9032015-08-17 11:51:52 +0000236 const Type &indexTypeInfo = GetTypeInfo(type);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400237 size_t requiredStreamingBufferSize = indexTypeInfo.bytes * count;
238 if (requiredStreamingBufferSize > mStreamingElementArrayBufferSize)
239 {
240 // Copy the indices in while resizing the buffer
Shao80957d92017-02-20 21:25:59 +0800241 mFunctions->bufferData(GL_ELEMENT_ARRAY_BUFFER, requiredStreamingBufferSize, indices,
242 GL_DYNAMIC_DRAW);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400243 mStreamingElementArrayBufferSize = requiredStreamingBufferSize;
244 }
245 else
246 {
247 // Put the indices at the beginning of the buffer
Shao80957d92017-02-20 21:25:59 +0800248 mFunctions->bufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, requiredStreamingBufferSize,
249 indices);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400250 }
251
Shao80957d92017-02-20 21:25:59 +0800252 // Set the index offset for the draw call to zero since the supplied index pointer is to
253 // client data
Geoff Lang7c82bc42015-03-09 16:18:08 -0400254 *outIndices = nullptr;
255 }
256
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500257 return gl::NoError();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400258}
259
Jamie Madill0b9e9032015-08-17 11:51:52 +0000260void VertexArrayGL::computeStreamingAttributeSizes(const gl::AttributesMask &activeAttributesMask,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400261 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400262 const gl::IndexRange &indexRange,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000263 size_t *outStreamingDataSize,
264 size_t *outMaxAttributeDataSize) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400265{
Jamie Madill0b9e9032015-08-17 11:51:52 +0000266 *outStreamingDataSize = 0;
267 *outMaxAttributeDataSize = 0;
268
269 ASSERT(mAttributesNeedStreaming.any());
270
Shao80957d92017-02-20 21:25:59 +0800271 const auto &attribs = mData.getVertexAttributes();
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800272 const auto &bindings = mData.getVertexBindings();
Jamie Madill6de51852017-04-12 09:53:01 -0400273
274 gl::AttributesMask attribsToStream = (mAttributesNeedStreaming & activeAttributesMask);
275
276 for (auto idx : attribsToStream)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000277 {
Shao80957d92017-02-20 21:25:59 +0800278 const auto &attrib = attribs[idx];
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800279 const auto &binding = bindings[attrib.bindingIndex];
280 ASSERT(AttributeNeedsStreaming(attrib, binding));
Jamie Madill0b9e9032015-08-17 11:51:52 +0000281
Jamie Madill0b9e9032015-08-17 11:51:52 +0000282 // If streaming is going to be required, compute the size of the required buffer
283 // and how much slack space at the beginning of the buffer will be required by determining
284 // the attribute with the largest data size.
285 size_t typeSize = ComputeVertexAttributeTypeSize(attrib);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800286 *outStreamingDataSize += typeSize * ComputeVertexBindingElementCount(
287 binding, indexRange.vertexCount(), instanceCount);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000288 *outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
289 }
290}
291
292gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &activeAttributesMask,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400293 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400294 const gl::IndexRange &indexRange) const
Jamie Madill0b9e9032015-08-17 11:51:52 +0000295{
296 // Sync the vertex attribute state and track what data needs to be streamed
297 size_t streamingDataSize = 0;
298 size_t maxAttributeDataSize = 0;
299
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400300 computeStreamingAttributeSizes(activeAttributesMask, instanceCount, indexRange,
301 &streamingDataSize, &maxAttributeDataSize);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000302
303 if (streamingDataSize == 0)
304 {
He Yunchaoacd18982017-01-04 10:46:42 +0800305 return gl::NoError();
Jamie Madill0b9e9032015-08-17 11:51:52 +0000306 }
307
Geoff Lang7c82bc42015-03-09 16:18:08 -0400308 if (mStreamingArrayBuffer == 0)
309 {
310 mFunctions->genBuffers(1, &mStreamingArrayBuffer);
311 mStreamingArrayBufferSize = 0;
312 }
313
Shao80957d92017-02-20 21:25:59 +0800314 // If first is greater than zero, a slack space needs to be left at the beginning of the buffer
315 // so that the same 'first' argument can be passed into the draw call.
316 const size_t bufferEmptySpace = maxAttributeDataSize * indexRange.start;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400317 const size_t requiredBufferSize = streamingDataSize + bufferEmptySpace;
318
319 mStateManager->bindBuffer(GL_ARRAY_BUFFER, mStreamingArrayBuffer);
320 if (requiredBufferSize > mStreamingArrayBufferSize)
321 {
322 mFunctions->bufferData(GL_ARRAY_BUFFER, requiredBufferSize, nullptr, GL_DYNAMIC_DRAW);
323 mStreamingArrayBufferSize = requiredBufferSize;
324 }
325
326 // 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
Shao80957d92017-02-20 21:25:59 +0800337 const auto &attribs = mData.getVertexAttributes();
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800338 const auto &bindings = mData.getVertexBindings();
Jamie Madill6de51852017-04-12 09:53:01 -0400339
340 gl::AttributesMask attribsToStream = (mAttributesNeedStreaming & activeAttributesMask);
341
342 for (auto idx : attribsToStream)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400343 {
Shao80957d92017-02-20 21:25:59 +0800344 const auto &attrib = attribs[idx];
Shaodde78e82017-05-22 14:13:27 +0800345 ASSERT(IsVertexAttribPointerSupported(idx, attrib));
346
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800347 const auto &binding = bindings[attrib.bindingIndex];
348 ASSERT(AttributeNeedsStreaming(attrib, binding));
Geoff Lang7c82bc42015-03-09 16:18:08 -0400349
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400350 const size_t streamedVertexCount =
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800351 ComputeVertexBindingElementCount(binding, indexRange.vertexCount(), instanceCount);
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400352
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800353 const size_t sourceStride = ComputeVertexAttributeStride(attrib, binding);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000354 const size_t destStride = ComputeVertexAttributeTypeSize(attrib);
355
Geoff Lang38a24a92017-02-15 13:53:06 -0500356 // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing
357 // a non-instanced draw call
Martin Radevdd5f27e2017-06-07 10:17:09 +0300358 const size_t firstIndex = binding.getDivisor() == 0 ? indexRange.start : 0;
Geoff Lang38a24a92017-02-15 13:53:06 -0500359
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800360 // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state.
361 // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt
Jamie Madill0b9e9032015-08-17 11:51:52 +0000362 const uint8_t *inputPointer = reinterpret_cast<const uint8_t *>(attrib.pointer);
363
364 // Pack the data when copying it, user could have supplied a very large stride that
365 // would cause the buffer to be much larger than needed.
366 if (destStride == sourceStride)
Jamie Madill8e344942015-07-09 14:22:07 -0400367 {
Jamie Madill0b9e9032015-08-17 11:51:52 +0000368 // Can copy in one go, the data is packed
Geoff Lang38a24a92017-02-15 13:53:06 -0500369 memcpy(bufferPointer + curBufferOffset, inputPointer + (sourceStride * firstIndex),
Jamie Madill0b9e9032015-08-17 11:51:52 +0000370 destStride * streamedVertexCount);
Jamie Madill6d51c702015-08-14 10:38:10 -0400371 }
Jamie Madill0b9e9032015-08-17 11:51:52 +0000372 else
373 {
374 // Copy each vertex individually
Geoff Lang6b10ddb2015-09-02 15:55:10 -0400375 for (size_t vertexIdx = 0; vertexIdx < streamedVertexCount; vertexIdx++)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000376 {
Shao80957d92017-02-20 21:25:59 +0800377 uint8_t *out = bufferPointer + curBufferOffset + (destStride * vertexIdx);
Geoff Lang38a24a92017-02-15 13:53:06 -0500378 const uint8_t *in = inputPointer + sourceStride * (vertexIdx + firstIndex);
Corentin Wallez4d5362d2015-08-25 11:25:14 -0400379 memcpy(out, in, destStride);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000380 }
381 }
382
383 // Compute where the 0-index vertex would be.
Geoff Lang38a24a92017-02-15 13:53:06 -0500384 const size_t vertexStartOffset = curBufferOffset - (firstIndex * destStride);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000385
Shaodf682a82017-03-31 15:13:21 +0800386 callVertexAttribPointer(static_cast<GLuint>(idx), attrib,
387 static_cast<GLsizei>(destStride),
388 static_cast<GLintptr>(vertexStartOffset));
Jamie Madill0b9e9032015-08-17 11:51:52 +0000389
390 curBufferOffset += destStride * streamedVertexCount;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400391 }
392
393 unmapResult = mFunctions->unmapBuffer(GL_ARRAY_BUFFER);
394 }
395
396 if (unmapResult != GL_TRUE)
397 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500398 return gl::OutOfMemory() << "Failed to unmap the client data streaming buffer.";
Geoff Lang7c82bc42015-03-09 16:18:08 -0400399 }
400
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500401 return gl::NoError();
Geoff Langba4c4a82015-02-24 12:38:46 -0500402}
403
404GLuint VertexArrayGL::getVertexArrayID() const
405{
406 return mVertexArrayID;
Geoff Langf9a6f082015-01-22 13:32:49 -0500407}
408
Geoff Lang294cad92015-05-26 15:11:23 -0400409GLuint VertexArrayGL::getAppliedElementArrayBufferID() const
410{
Jamie Madill77a90c22015-08-11 16:33:17 -0400411 if (mAppliedElementArrayBuffer.get() == nullptr)
412 {
413 return mStreamingElementArrayBuffer;
414 }
415
416 return GetImplAs<BufferGL>(mAppliedElementArrayBuffer.get())->getBufferID();
Geoff Lang294cad92015-05-26 15:11:23 -0400417}
418
Jamie Madill0b9e9032015-08-17 11:51:52 +0000419void VertexArrayGL::updateNeedsStreaming(size_t attribIndex)
420{
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800421 const auto &attrib = mData.getVertexAttribute(attribIndex);
422 const auto &binding = mData.getBindingFromAttribIndex(attribIndex);
423 mAttributesNeedStreaming.set(attribIndex, AttributeNeedsStreaming(attrib, binding));
Geoff Langf9a6f082015-01-22 13:32:49 -0500424}
Jamie Madill0b9e9032015-08-17 11:51:52 +0000425
426void VertexArrayGL::updateAttribEnabled(size_t attribIndex)
427{
Shaodf682a82017-03-31 15:13:21 +0800428 const bool enabled = mData.getVertexAttribute(attribIndex).enabled;
429 if (mAppliedAttributes[attribIndex].enabled == enabled)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000430 {
431 return;
432 }
433
434 updateNeedsStreaming(attribIndex);
435
Shaodf682a82017-03-31 15:13:21 +0800436 if (enabled)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000437 {
438 mFunctions->enableVertexAttribArray(static_cast<GLuint>(attribIndex));
439 }
440 else
441 {
442 mFunctions->disableVertexAttribArray(static_cast<GLuint>(attribIndex));
443 }
Shaodf682a82017-03-31 15:13:21 +0800444
445 mAppliedAttributes[attribIndex].enabled = enabled;
Jamie Madill0b9e9032015-08-17 11:51:52 +0000446}
447
Jamie Madill4928b7c2017-06-20 12:57:39 -0400448void VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attribIndex)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000449{
450 const VertexAttribute &attrib = mData.getVertexAttribute(attribIndex);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800451
Shaodde78e82017-05-22 14:13:27 +0800452 // According to SPEC, VertexAttribPointer should update the binding indexed attribIndex instead
453 // of the binding indexed attrib.bindingIndex (unless attribIndex == attrib.bindingIndex).
454 const VertexBinding &binding = mData.getVertexBinding(attribIndex);
Shaodf682a82017-03-31 15:13:21 +0800455
Shaodde78e82017-05-22 14:13:27 +0800456 // Since mAttributesNeedStreaming[attribIndex] keeps the value set in the last draw, here we
457 // only need to update it when the buffer has been changed. e.g. When we set an attribute to be
458 // streamed in the last draw, and only change its format in this draw without calling
459 // updateNeedsStreaming, it will still be streamed because the flag is already on.
460 const auto &bindingBuffer = binding.getBuffer();
461 if (bindingBuffer != mAppliedBindings[attribIndex].getBuffer())
462 {
463 updateNeedsStreaming(attribIndex);
464 }
465
466 // Early return when the vertex attribute isn't using a buffer object:
467 // - If we need to stream, defer the attribPointer to the draw call.
468 // - Skip the attribute that is disabled and uses a client memory pointer.
469 // - Skip the attribute whose buffer is detached by BindVertexBuffer. Since it cannot have a
470 // client memory pointer either, it must be disabled and shouldn't affect the draw.
471 const Buffer *arrayBuffer = bindingBuffer.get();
472 if (arrayBuffer == nullptr)
473 {
474 // Mark the applied binding isn't using a buffer by setting its buffer to nullptr so that if
475 // it starts to use a buffer later, there is no chance that the caching will skip it.
476 mAppliedBindings[attribIndex].setBuffer(context, nullptr);
477 return;
478 }
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800479
Shaodf682a82017-03-31 15:13:21 +0800480 // We do not need to compare attrib.pointer because when we use a different client memory
481 // pointer, we don't need to update mAttributesNeedStreaming by binding.buffer and we won't
482 // update attribPointer in this function.
Shaodde78e82017-05-22 14:13:27 +0800483 if ((SameVertexAttribFormat(mAppliedAttributes[attribIndex], attrib)) &&
484 (mAppliedAttributes[attribIndex].bindingIndex == attrib.bindingIndex) &&
485 (SameVertexBuffer(mAppliedBindings[attribIndex], binding)))
Jamie Madill0b9e9032015-08-17 11:51:52 +0000486 {
487 return;
488 }
489
Shao4181bc92017-03-17 14:55:25 +0800490 // Since ANGLE always uses a non-zero VAO, we cannot use a client memory pointer on it:
491 // [OpenGL ES 3.0.2] Section 2.8 page 24:
492 // An INVALID_OPERATION error is generated when a non-zero vertex array object is bound,
493 // zero is bound to the ARRAY_BUFFER buffer object binding point, and the pointer argument
494 // is not NULL.
Shaodf682a82017-03-31 15:13:21 +0800495
Shao4181bc92017-03-17 14:55:25 +0800496 const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
497 mStateManager->bindBuffer(GL_ARRAY_BUFFER, arrayBufferGL->getBufferID());
Martin Radevdd5f27e2017-06-07 10:17:09 +0300498 callVertexAttribPointer(static_cast<GLuint>(attribIndex), attrib, binding.getStride(),
499 binding.getOffset());
Shaodf682a82017-03-31 15:13:21 +0800500
Shaodde78e82017-05-22 14:13:27 +0800501 mAppliedAttributes[attribIndex].size = attrib.size;
502 mAppliedAttributes[attribIndex].type = attrib.type;
503 mAppliedAttributes[attribIndex].normalized = attrib.normalized;
504 mAppliedAttributes[attribIndex].pureInteger = attrib.pureInteger;
Shaodf682a82017-03-31 15:13:21 +0800505
Shaodde78e82017-05-22 14:13:27 +0800506 // After VertexAttribPointer, attrib.relativeOffset is set to 0 and attrib.bindingIndex is set
507 // to attribIndex in driver. If attrib.relativeOffset != 0 or attrib.bindingIndex !=
508 // attribIndex, they should be set in updateAttribFormat and updateAttribBinding. The cache
509 // should be consistent with driver so that we won't miss anything.
510 mAppliedAttributes[attribIndex].relativeOffset = 0;
511 mAppliedAttributes[attribIndex].bindingIndex = static_cast<GLuint>(attribIndex);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800512
Shaodde78e82017-05-22 14:13:27 +0800513 mAppliedBindings[attribIndex].setStride(binding.getStride());
514 mAppliedBindings[attribIndex].setOffset(binding.getOffset());
515 mAppliedBindings[attribIndex].setBuffer(context, binding.getBuffer().get());
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800516}
517
Shaodf682a82017-03-31 15:13:21 +0800518void VertexArrayGL::callVertexAttribPointer(GLuint attribIndex,
519 const VertexAttribute &attrib,
520 GLsizei stride,
521 GLintptr offset) const
522{
523 const GLvoid *pointer = reinterpret_cast<const GLvoid *>(offset);
524 if (attrib.pureInteger)
525 {
526 ASSERT(!attrib.normalized);
527 mFunctions->vertexAttribIPointer(attribIndex, attrib.size, attrib.type, stride, pointer);
528 }
529 else
530 {
531 mFunctions->vertexAttribPointer(attribIndex, attrib.size, attrib.type, attrib.normalized,
532 stride, pointer);
533 }
534}
535
Shaodde78e82017-05-22 14:13:27 +0800536bool VertexArrayGL::supportVertexAttribBinding() const
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800537{
Shaodde78e82017-05-22 14:13:27 +0800538 ASSERT(mFunctions);
539 return (mFunctions->vertexAttribBinding != nullptr);
540}
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800541
Shaodde78e82017-05-22 14:13:27 +0800542void VertexArrayGL::updateAttribFormat(size_t attribIndex)
543{
544 ASSERT(supportVertexAttribBinding());
545
546 const VertexAttribute &attrib = mData.getVertexAttribute(attribIndex);
547 if (SameVertexAttribFormat(mAppliedAttributes[attribIndex], attrib))
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800548 {
Shaodf682a82017-03-31 15:13:21 +0800549 return;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800550 }
Shaodf682a82017-03-31 15:13:21 +0800551
Shaodde78e82017-05-22 14:13:27 +0800552 if (attrib.pureInteger)
553 {
554 ASSERT(!attrib.normalized);
555 mFunctions->vertexAttribIFormat(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
556 attrib.relativeOffset);
557 }
558 else
559 {
560 mFunctions->vertexAttribFormat(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
561 attrib.normalized, attrib.relativeOffset);
562 }
563
564 mAppliedAttributes[attribIndex].size = attrib.size;
565 mAppliedAttributes[attribIndex].type = attrib.type;
566 mAppliedAttributes[attribIndex].normalized = attrib.normalized;
567 mAppliedAttributes[attribIndex].pureInteger = attrib.pureInteger;
568 mAppliedAttributes[attribIndex].relativeOffset = attrib.relativeOffset;
569}
570
571void VertexArrayGL::updateAttribBinding(size_t attribIndex)
572{
573 ASSERT(supportVertexAttribBinding());
574
575 GLuint bindingIndex = mData.getVertexAttribute(attribIndex).bindingIndex;
576 if (mAppliedAttributes[attribIndex].bindingIndex == bindingIndex)
577 {
578 return;
579 }
580
581 mFunctions->vertexAttribBinding(static_cast<GLuint>(attribIndex), bindingIndex);
Shaodf682a82017-03-31 15:13:21 +0800582
583 mAppliedAttributes[attribIndex].bindingIndex = bindingIndex;
Shaodde78e82017-05-22 14:13:27 +0800584}
585
586void VertexArrayGL::updateBindingBuffer(const gl::Context *context, size_t bindingIndex)
587{
588 ASSERT(supportVertexAttribBinding());
589
590 const VertexBinding &binding = mData.getVertexBinding(bindingIndex);
591 if (SameVertexBuffer(mAppliedBindings[bindingIndex], binding))
592 {
593 return;
594 }
595
596 const Buffer *arrayBuffer = binding.getBuffer().get();
597 GLuint bufferId = 0;
598 if (arrayBuffer != nullptr)
599 {
600 bufferId = GetImplAs<BufferGL>(arrayBuffer)->getBufferID();
601 }
602
603 mFunctions->bindVertexBuffer(static_cast<GLuint>(bindingIndex), bufferId, binding.getOffset(),
604 binding.getStride());
605
606 mAppliedBindings[bindingIndex].setStride(binding.getStride());
607 mAppliedBindings[bindingIndex].setOffset(binding.getOffset());
608 mAppliedBindings[bindingIndex].setBuffer(context, binding.getBuffer().get());
609}
610
611void VertexArrayGL::updateBindingDivisor(size_t bindingIndex)
612{
613 GLuint newDivisor = mData.getVertexBinding(bindingIndex).getDivisor();
614 if (mAppliedBindings[bindingIndex].getDivisor() == newDivisor)
615 {
616 return;
617 }
618
619 if (supportVertexAttribBinding())
620 {
621 mFunctions->vertexBindingDivisor(static_cast<GLuint>(bindingIndex), newDivisor);
622 }
623 else
624 {
625 // We can only use VertexAttribDivisor on platforms that don't support Vertex Attrib
626 // Binding.
627 mFunctions->vertexAttribDivisor(static_cast<GLuint>(bindingIndex), newDivisor);
628 }
629
630 mAppliedBindings[bindingIndex].setDivisor(newDivisor);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000631}
632
Jamie Madillc564c072017-06-01 12:45:42 -0400633void VertexArrayGL::syncState(const gl::Context *context, const VertexArray::DirtyBits &dirtyBits)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000634{
Shaodf682a82017-03-31 15:13:21 +0800635 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
636
Jamie Madill6de51852017-04-12 09:53:01 -0400637 for (size_t dirtyBit : dirtyBits)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000638 {
639 if (dirtyBit == VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER)
640 {
641 // TODO(jmadill): Element array buffer bindings
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800642 continue;
Jamie Madill0b9e9032015-08-17 11:51:52 +0000643 }
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800644
Shaodde78e82017-05-22 14:13:27 +0800645 size_t index = VertexArray::GetVertexIndexFromDirtyBit(dirtyBit);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800646 if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_ENABLED &&
647 dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_ENABLED)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000648 {
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800649 updateAttribEnabled(index);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000650 }
651 else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_POINTER &&
652 dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_POINTER)
653 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400654 updateAttribPointer(context, index);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000655 }
Shaodde78e82017-05-22 14:13:27 +0800656
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800657 else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_FORMAT &&
Shaodde78e82017-05-22 14:13:27 +0800658 dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_FORMAT)
659 {
660 ASSERT(supportVertexAttribBinding());
661 updateAttribFormat(index);
662 }
663 else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_BINDING &&
664 dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_BINDING)
665 {
666 ASSERT(supportVertexAttribBinding());
667 updateAttribBinding(index);
668 }
669 else if (dirtyBit >= VertexArray::DIRTY_BIT_BINDING_0_BUFFER &&
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800670 dirtyBit < VertexArray::DIRTY_BIT_BINDING_MAX_BUFFER)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000671 {
Shaodde78e82017-05-22 14:13:27 +0800672 ASSERT(supportVertexAttribBinding());
673 updateBindingBuffer(context, index);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800674 }
Shaodde78e82017-05-22 14:13:27 +0800675
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800676 else if (dirtyBit >= VertexArray::DIRTY_BIT_BINDING_0_DIVISOR &&
677 dirtyBit < VertexArray::DIRTY_BIT_BINDING_MAX_DIVISOR)
678 {
Shaodde78e82017-05-22 14:13:27 +0800679 updateBindingDivisor(index);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000680 }
681 else
682 UNREACHABLE();
683 }
684}
685
686} // rx