blob: e4cf43d24b51df32763e841d49fb50572e6881c3 [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{
Jiawei-Shao2597fb62016-12-09 16:38:02 +080032 return (attrib.enabled && binding.buffer.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{
43 return a.stride == b.stride && a.offset == b.offset && a.buffer.get() == b.buffer.get();
44}
45
46bool IsVertexAttribPointerSupported(size_t attribIndex, const VertexAttribute &attrib)
47{
48 return (attribIndex == attrib.bindingIndex && attrib.relativeOffset == 0);
49}
Jamie Madill0b9e9032015-08-17 11:51:52 +000050} // anonymous namespace
51
Jamie Madill3f572682016-04-26 13:41:36 -040052VertexArrayGL::VertexArrayGL(const VertexArrayState &state,
Jamie Madill77a90c22015-08-11 16:33:17 -040053 const FunctionsGL *functions,
54 StateManagerGL *stateManager)
Jamie Madill3f572682016-04-26 13:41:36 -040055 : VertexArrayImpl(state),
Geoff Langba4c4a82015-02-24 12:38:46 -050056 mFunctions(functions),
57 mStateManager(stateManager),
58 mVertexArrayID(0),
Jamie Madill77a90c22015-08-11 16:33:17 -040059 mAppliedElementArrayBuffer(),
Jiawei-Shao2597fb62016-12-09 16:38:02 +080060 mAppliedBindings(state.getMaxBindings()),
Geoff Lang7c82bc42015-03-09 16:18:08 -040061 mStreamingElementArrayBufferSize(0),
62 mStreamingElementArrayBuffer(0),
63 mStreamingArrayBufferSize(0),
64 mStreamingArrayBuffer(0)
Geoff Langba4c4a82015-02-24 12:38:46 -050065{
66 ASSERT(mFunctions);
67 ASSERT(mStateManager);
68 mFunctions->genVertexArrays(1, &mVertexArrayID);
69
Jiawei-Shao2597fb62016-12-09 16:38:02 +080070 // Set the cached vertex attribute array and vertex attribute binding array size
71 GLuint maxVertexAttribs = static_cast<GLuint>(state.getMaxAttribs());
72 for (GLuint i = 0; i < maxVertexAttribs; i++)
73 {
74 mAppliedAttributes.emplace_back(i);
75 }
Geoff Langba4c4a82015-02-24 12:38:46 -050076}
Geoff Langf9a6f082015-01-22 13:32:49 -050077
78VertexArrayGL::~VertexArrayGL()
Geoff Langba4c4a82015-02-24 12:38:46 -050079{
Geoff Lang1eb708e2015-05-04 14:58:23 -040080 mStateManager->deleteVertexArray(mVertexArrayID);
81 mVertexArrayID = 0;
Geoff Langba4c4a82015-02-24 12:38:46 -050082
Geoff Lang1eb708e2015-05-04 14:58:23 -040083 mStateManager->deleteBuffer(mStreamingElementArrayBuffer);
84 mStreamingElementArrayBufferSize = 0;
Shao80957d92017-02-20 21:25:59 +080085 mStreamingElementArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040086
Geoff Lang1eb708e2015-05-04 14:58:23 -040087 mStateManager->deleteBuffer(mStreamingArrayBuffer);
88 mStreamingArrayBufferSize = 0;
Shao80957d92017-02-20 21:25:59 +080089 mStreamingArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040090
Jamie Madill77a90c22015-08-11 16:33:17 -040091 mAppliedElementArrayBuffer.set(nullptr);
Jiawei-Shao2597fb62016-12-09 16:38:02 +080092 for (auto &binding : mAppliedBindings)
Geoff Langba4c4a82015-02-24 12:38:46 -050093 {
Jiawei-Shao2597fb62016-12-09 16:38:02 +080094 binding.buffer.set(nullptr);
Geoff Langba4c4a82015-02-24 12:38:46 -050095 }
96}
Geoff Langf9a6f082015-01-22 13:32:49 -050097
Jamie Madill0b9e9032015-08-17 11:51:52 +000098gl::Error VertexArrayGL::syncDrawArraysState(const gl::AttributesMask &activeAttributesMask,
99 GLint first,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400100 GLsizei count,
101 GLsizei instanceCount) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400102{
Geoff Lang3edfe032015-09-04 16:38:24 -0400103 return syncDrawState(activeAttributesMask, first, count, GL_NONE, nullptr, instanceCount, false,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400104 nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400105}
106
Jamie Madill0b9e9032015-08-17 11:51:52 +0000107gl::Error VertexArrayGL::syncDrawElementsState(const gl::AttributesMask &activeAttributesMask,
108 GLsizei count,
109 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400110 const void *indices,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400111 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400112 bool primitiveRestartEnabled,
Jamie Madill876429b2017-04-20 15:46:24 -0400113 const void **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400114{
Geoff Lang3edfe032015-09-04 16:38:24 -0400115 return syncDrawState(activeAttributesMask, 0, count, type, indices, instanceCount,
116 primitiveRestartEnabled, outIndices);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400117}
118
Jiajia Qind9671222016-11-29 16:30:31 +0800119gl::Error VertexArrayGL::syncElementArrayState() const
120{
121 gl::Buffer *elementArrayBuffer = mData.getElementArrayBuffer().get();
122 ASSERT(elementArrayBuffer);
123 if (elementArrayBuffer != mAppliedElementArrayBuffer.get())
124 {
125 const BufferGL *bufferGL = GetImplAs<BufferGL>(elementArrayBuffer);
126 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferGL->getBufferID());
127 mAppliedElementArrayBuffer.set(elementArrayBuffer);
128 }
129
130 return gl::NoError();
131}
132
Jamie Madill0b9e9032015-08-17 11:51:52 +0000133gl::Error VertexArrayGL::syncDrawState(const gl::AttributesMask &activeAttributesMask,
134 GLint first,
135 GLsizei count,
136 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400137 const void *indices,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400138 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400139 bool primitiveRestartEnabled,
Jamie Madill876429b2017-04-20 15:46:24 -0400140 const void **outIndices) const
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400141{
Jamie Madill77a90c22015-08-11 16:33:17 -0400142 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400143
Shao80957d92017-02-20 21:25:59 +0800144 // Check if any attributes need to be streamed, determines if the index range needs to be
145 // computed
Jamie Madill0b9e9032015-08-17 11:51:52 +0000146 bool attributesNeedStreaming = mAttributesNeedStreaming.any();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400147
Shao80957d92017-02-20 21:25:59 +0800148 // Determine if an index buffer needs to be streamed and the range of vertices that need to be
149 // copied
Geoff Lang3edfe032015-09-04 16:38:24 -0400150 IndexRange indexRange;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400151 if (type != GL_NONE)
Geoff Langba4c4a82015-02-24 12:38:46 -0500152 {
Geoff Lang3edfe032015-09-04 16:38:24 -0400153 Error error = syncIndexData(count, type, indices, primitiveRestartEnabled,
154 attributesNeedStreaming, &indexRange, outIndices);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400155 if (error.isError())
156 {
157 return error;
158 }
159 }
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 {
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400169 Error error = streamAttributes(activeAttributesMask, instanceCount, indexRange);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400170 if (error.isError())
171 {
172 return error;
173 }
174 }
175
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500176 return gl::NoError();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400177}
178
Jiajia Qind9671222016-11-29 16:30:31 +0800179gl::Error VertexArrayGL::syncIndexData(GLsizei count,
180 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400181 const void *indices,
Jiajia Qind9671222016-11-29 16:30:31 +0800182 bool primitiveRestartEnabled,
183 bool attributesNeedStreaming,
184 IndexRange *outIndexRange,
Jamie Madill876429b2017-04-20 15:46:24 -0400185 const void **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400186{
187 ASSERT(outIndices);
188
Jamie Madill8e344942015-07-09 14:22:07 -0400189 gl::Buffer *elementArrayBuffer = mData.getElementArrayBuffer().get();
190
Geoff Lang7c82bc42015-03-09 16:18:08 -0400191 // Need to check the range of indices if attributes need to be streamed
Jamie Madill8e344942015-07-09 14:22:07 -0400192 if (elementArrayBuffer != nullptr)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400193 {
Jamie Madill77a90c22015-08-11 16:33:17 -0400194 if (elementArrayBuffer != mAppliedElementArrayBuffer.get())
Geoff Lang7c82bc42015-03-09 16:18:08 -0400195 {
Jamie Madill77a90c22015-08-11 16:33:17 -0400196 const BufferGL *bufferGL = GetImplAs<BufferGL>(elementArrayBuffer);
197 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferGL->getBufferID());
198 mAppliedElementArrayBuffer.set(elementArrayBuffer);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400199 }
200
201 // Only compute the index range if the attributes also need to be streamed
202 if (attributesNeedStreaming)
203 {
204 ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices);
Shao80957d92017-02-20 21:25:59 +0800205 Error error = mData.getElementArrayBuffer()->getIndexRange(
Geoff Lang3edfe032015-09-04 16:38:24 -0400206 type, elementArrayBufferOffset, count, primitiveRestartEnabled, outIndexRange);
Geoff Lang520c4ae2015-05-05 13:12:36 -0400207 if (error.isError())
Geoff Lang7c82bc42015-03-09 16:18:08 -0400208 {
Geoff Lang520c4ae2015-05-05 13:12:36 -0400209 return error;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400210 }
211 }
212
Shao80957d92017-02-20 21:25:59 +0800213 // Indices serves as an offset into the index buffer in this case, use the same value for
214 // the draw call
Geoff Lang7c82bc42015-03-09 16:18:08 -0400215 *outIndices = indices;
216 }
217 else
218 {
219 // Need to stream the index buffer
220 // TODO: if GLES, nothing needs to be streamed
221
222 // Only compute the index range if the attributes also need to be streamed
223 if (attributesNeedStreaming)
224 {
Geoff Lang3edfe032015-09-04 16:38:24 -0400225 *outIndexRange = ComputeIndexRange(type, indices, count, primitiveRestartEnabled);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400226 }
227
228 // Allocate the streaming element array buffer
229 if (mStreamingElementArrayBuffer == 0)
230 {
231 mFunctions->genBuffers(1, &mStreamingElementArrayBuffer);
232 mStreamingElementArrayBufferSize = 0;
233 }
234
235 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, mStreamingElementArrayBuffer);
Jamie Madill77a90c22015-08-11 16:33:17 -0400236 mAppliedElementArrayBuffer.set(nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400237
238 // Make sure the element array buffer is large enough
Jamie Madill0b9e9032015-08-17 11:51:52 +0000239 const Type &indexTypeInfo = GetTypeInfo(type);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400240 size_t requiredStreamingBufferSize = indexTypeInfo.bytes * count;
241 if (requiredStreamingBufferSize > mStreamingElementArrayBufferSize)
242 {
243 // Copy the indices in while resizing the buffer
Shao80957d92017-02-20 21:25:59 +0800244 mFunctions->bufferData(GL_ELEMENT_ARRAY_BUFFER, requiredStreamingBufferSize, indices,
245 GL_DYNAMIC_DRAW);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400246 mStreamingElementArrayBufferSize = requiredStreamingBufferSize;
247 }
248 else
249 {
250 // Put the indices at the beginning of the buffer
Shao80957d92017-02-20 21:25:59 +0800251 mFunctions->bufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, requiredStreamingBufferSize,
252 indices);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400253 }
254
Shao80957d92017-02-20 21:25:59 +0800255 // Set the index offset for the draw call to zero since the supplied index pointer is to
256 // client data
Geoff Lang7c82bc42015-03-09 16:18:08 -0400257 *outIndices = nullptr;
258 }
259
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500260 return gl::NoError();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400261}
262
Jamie Madill0b9e9032015-08-17 11:51:52 +0000263void VertexArrayGL::computeStreamingAttributeSizes(const gl::AttributesMask &activeAttributesMask,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400264 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400265 const gl::IndexRange &indexRange,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000266 size_t *outStreamingDataSize,
267 size_t *outMaxAttributeDataSize) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400268{
Jamie Madill0b9e9032015-08-17 11:51:52 +0000269 *outStreamingDataSize = 0;
270 *outMaxAttributeDataSize = 0;
271
272 ASSERT(mAttributesNeedStreaming.any());
273
Shao80957d92017-02-20 21:25:59 +0800274 const auto &attribs = mData.getVertexAttributes();
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800275 const auto &bindings = mData.getVertexBindings();
Jamie Madill6de51852017-04-12 09:53:01 -0400276
277 gl::AttributesMask attribsToStream = (mAttributesNeedStreaming & activeAttributesMask);
278
279 for (auto idx : attribsToStream)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000280 {
Shao80957d92017-02-20 21:25:59 +0800281 const auto &attrib = attribs[idx];
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800282 const auto &binding = bindings[attrib.bindingIndex];
283 ASSERT(AttributeNeedsStreaming(attrib, binding));
Jamie Madill0b9e9032015-08-17 11:51:52 +0000284
Jamie Madill0b9e9032015-08-17 11:51:52 +0000285 // If streaming is going to be required, compute the size of the required buffer
286 // and how much slack space at the beginning of the buffer will be required by determining
287 // the attribute with the largest data size.
288 size_t typeSize = ComputeVertexAttributeTypeSize(attrib);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800289 *outStreamingDataSize += typeSize * ComputeVertexBindingElementCount(
290 binding, indexRange.vertexCount(), instanceCount);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000291 *outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
292 }
293}
294
295gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &activeAttributesMask,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400296 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400297 const gl::IndexRange &indexRange) const
Jamie Madill0b9e9032015-08-17 11:51:52 +0000298{
299 // Sync the vertex attribute state and track what data needs to be streamed
300 size_t streamingDataSize = 0;
301 size_t maxAttributeDataSize = 0;
302
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400303 computeStreamingAttributeSizes(activeAttributesMask, instanceCount, indexRange,
304 &streamingDataSize, &maxAttributeDataSize);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000305
306 if (streamingDataSize == 0)
307 {
He Yunchaoacd18982017-01-04 10:46:42 +0800308 return gl::NoError();
Jamie Madill0b9e9032015-08-17 11:51:52 +0000309 }
310
Geoff Lang7c82bc42015-03-09 16:18:08 -0400311 if (mStreamingArrayBuffer == 0)
312 {
313 mFunctions->genBuffers(1, &mStreamingArrayBuffer);
314 mStreamingArrayBufferSize = 0;
315 }
316
Shao80957d92017-02-20 21:25:59 +0800317 // If first is greater than zero, a slack space needs to be left at the beginning of the buffer
318 // so that the same 'first' argument can be passed into the draw call.
319 const size_t bufferEmptySpace = maxAttributeDataSize * indexRange.start;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400320 const size_t requiredBufferSize = streamingDataSize + bufferEmptySpace;
321
322 mStateManager->bindBuffer(GL_ARRAY_BUFFER, mStreamingArrayBuffer);
323 if (requiredBufferSize > mStreamingArrayBufferSize)
324 {
325 mFunctions->bufferData(GL_ARRAY_BUFFER, requiredBufferSize, nullptr, GL_DYNAMIC_DRAW);
326 mStreamingArrayBufferSize = requiredBufferSize;
327 }
328
329 // Unmapping a buffer can return GL_FALSE to indicate that the system has corrupted the data
Shao80957d92017-02-20 21:25:59 +0800330 // somehow (such as by a screen change), retry writing the data a few times and return
331 // OUT_OF_MEMORY if that fails.
332 GLboolean unmapResult = GL_FALSE;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400333 size_t unmapRetryAttempts = 5;
334 while (unmapResult != GL_TRUE && --unmapRetryAttempts > 0)
335 {
Geoff Langb2ebb5e2016-06-08 18:17:55 +0000336 uint8_t *bufferPointer = MapBufferRangeWithFallback(mFunctions, GL_ARRAY_BUFFER, 0,
337 requiredBufferSize, GL_MAP_WRITE_BIT);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400338 size_t curBufferOffset = bufferEmptySpace;
339
Shao80957d92017-02-20 21:25:59 +0800340 const auto &attribs = mData.getVertexAttributes();
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800341 const auto &bindings = mData.getVertexBindings();
Jamie Madill6de51852017-04-12 09:53:01 -0400342
343 gl::AttributesMask attribsToStream = (mAttributesNeedStreaming & activeAttributesMask);
344
345 for (auto idx : attribsToStream)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400346 {
Shao80957d92017-02-20 21:25:59 +0800347 const auto &attrib = attribs[idx];
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800348 const auto &binding = bindings[attrib.bindingIndex];
349 ASSERT(AttributeNeedsStreaming(attrib, binding));
Geoff Lang7c82bc42015-03-09 16:18:08 -0400350
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400351 const size_t streamedVertexCount =
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800352 ComputeVertexBindingElementCount(binding, indexRange.vertexCount(), instanceCount);
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400353
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800354 const size_t sourceStride = ComputeVertexAttributeStride(attrib, binding);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000355 const size_t destStride = ComputeVertexAttributeTypeSize(attrib);
356
Geoff Lang38a24a92017-02-15 13:53:06 -0500357 // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing
358 // a non-instanced draw call
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800359 const size_t firstIndex = binding.divisor == 0 ? indexRange.start : 0;
Geoff Lang38a24a92017-02-15 13:53:06 -0500360
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800361 // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state.
362 // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt
Jamie Madill0b9e9032015-08-17 11:51:52 +0000363 const uint8_t *inputPointer = reinterpret_cast<const uint8_t *>(attrib.pointer);
364
365 // Pack the data when copying it, user could have supplied a very large stride that
366 // would cause the buffer to be much larger than needed.
367 if (destStride == sourceStride)
Jamie Madill8e344942015-07-09 14:22:07 -0400368 {
Jamie Madill0b9e9032015-08-17 11:51:52 +0000369 // Can copy in one go, the data is packed
Geoff Lang38a24a92017-02-15 13:53:06 -0500370 memcpy(bufferPointer + curBufferOffset, inputPointer + (sourceStride * firstIndex),
Jamie Madill0b9e9032015-08-17 11:51:52 +0000371 destStride * streamedVertexCount);
Jamie Madill6d51c702015-08-14 10:38:10 -0400372 }
Jamie Madill0b9e9032015-08-17 11:51:52 +0000373 else
374 {
375 // Copy each vertex individually
Geoff Lang6b10ddb2015-09-02 15:55:10 -0400376 for (size_t vertexIdx = 0; vertexIdx < streamedVertexCount; vertexIdx++)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000377 {
Shao80957d92017-02-20 21:25:59 +0800378 uint8_t *out = bufferPointer + curBufferOffset + (destStride * vertexIdx);
Geoff Lang38a24a92017-02-15 13:53:06 -0500379 const uint8_t *in = inputPointer + sourceStride * (vertexIdx + firstIndex);
Corentin Wallez4d5362d2015-08-25 11:25:14 -0400380 memcpy(out, in, destStride);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000381 }
382 }
383
384 // Compute where the 0-index vertex would be.
Geoff Lang38a24a92017-02-15 13:53:06 -0500385 const size_t vertexStartOffset = curBufferOffset - (firstIndex * destStride);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000386
Shaodf682a82017-03-31 15:13:21 +0800387 callVertexAttribPointer(static_cast<GLuint>(idx), attrib,
388 static_cast<GLsizei>(destStride),
389 static_cast<GLintptr>(vertexStartOffset));
Jamie Madill0b9e9032015-08-17 11:51:52 +0000390
391 curBufferOffset += destStride * streamedVertexCount;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400392 }
393
394 unmapResult = mFunctions->unmapBuffer(GL_ARRAY_BUFFER);
395 }
396
397 if (unmapResult != GL_TRUE)
398 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500399 return gl::OutOfMemory() << "Failed to unmap the client data streaming buffer.";
Geoff Lang7c82bc42015-03-09 16:18:08 -0400400 }
401
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500402 return gl::NoError();
Geoff Langba4c4a82015-02-24 12:38:46 -0500403}
404
405GLuint VertexArrayGL::getVertexArrayID() const
406{
407 return mVertexArrayID;
Geoff Langf9a6f082015-01-22 13:32:49 -0500408}
409
Geoff Lang294cad92015-05-26 15:11:23 -0400410GLuint VertexArrayGL::getAppliedElementArrayBufferID() const
411{
Jamie Madill77a90c22015-08-11 16:33:17 -0400412 if (mAppliedElementArrayBuffer.get() == nullptr)
413 {
414 return mStreamingElementArrayBuffer;
415 }
416
417 return GetImplAs<BufferGL>(mAppliedElementArrayBuffer.get())->getBufferID();
Geoff Lang294cad92015-05-26 15:11:23 -0400418}
419
Jamie Madill0b9e9032015-08-17 11:51:52 +0000420void VertexArrayGL::updateNeedsStreaming(size_t attribIndex)
421{
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800422 const auto &attrib = mData.getVertexAttribute(attribIndex);
423 const auto &binding = mData.getBindingFromAttribIndex(attribIndex);
424 mAttributesNeedStreaming.set(attribIndex, AttributeNeedsStreaming(attrib, binding));
Geoff Langf9a6f082015-01-22 13:32:49 -0500425}
Jamie Madill0b9e9032015-08-17 11:51:52 +0000426
427void VertexArrayGL::updateAttribEnabled(size_t attribIndex)
428{
Shaodf682a82017-03-31 15:13:21 +0800429 const bool enabled = mData.getVertexAttribute(attribIndex).enabled;
430 if (mAppliedAttributes[attribIndex].enabled == enabled)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000431 {
432 return;
433 }
434
435 updateNeedsStreaming(attribIndex);
436
Shaodf682a82017-03-31 15:13:21 +0800437 if (enabled)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000438 {
439 mFunctions->enableVertexAttribArray(static_cast<GLuint>(attribIndex));
440 }
441 else
442 {
443 mFunctions->disableVertexAttribArray(static_cast<GLuint>(attribIndex));
444 }
Shaodf682a82017-03-31 15:13:21 +0800445
446 mAppliedAttributes[attribIndex].enabled = enabled;
Jamie Madill0b9e9032015-08-17 11:51:52 +0000447}
448
449void VertexArrayGL::updateAttribPointer(size_t attribIndex)
450{
451 const VertexAttribute &attrib = mData.getVertexAttribute(attribIndex);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800452
Shaodf682a82017-03-31 15:13:21 +0800453 // TODO(jiawei.shao@intel.com): Vertex Attrib Binding
454 ASSERT(IsVertexAttribPointerSupported(attribIndex, attrib));
455
456 const GLuint bindingIndex = attrib.bindingIndex;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800457 const VertexBinding &binding = mData.getVertexBinding(bindingIndex);
458
Shaodf682a82017-03-31 15:13:21 +0800459 // We do not need to compare attrib.pointer because when we use a different client memory
460 // pointer, we don't need to update mAttributesNeedStreaming by binding.buffer and we won't
461 // update attribPointer in this function.
462 if (SameVertexAttribFormat(mAppliedAttributes[attribIndex], attrib) &&
463 mAppliedAttributes[attribIndex].bindingIndex == bindingIndex &&
464 SameVertexBuffer(mAppliedBindings[attribIndex], binding))
Jamie Madill0b9e9032015-08-17 11:51:52 +0000465 {
466 return;
467 }
468
469 updateNeedsStreaming(attribIndex);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000470
471 // If we need to stream, defer the attribPointer to the draw call.
Shao4181bc92017-03-17 14:55:25 +0800472 // Skip the attribute that is disabled and uses a client memory pointer.
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800473 const Buffer *arrayBuffer = binding.buffer.get();
Shao4181bc92017-03-17 14:55:25 +0800474 if (arrayBuffer == nullptr)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000475 {
Shaodf682a82017-03-31 15:13:21 +0800476 // Mark the applied binding is using a client memory pointer by setting its buffer to
477 // nullptr so that if it doesn't use a client memory pointer later, there is no chance that
478 // the caching will skip it.
479 mAppliedBindings[bindingIndex].buffer.set(nullptr);
Shao4181bc92017-03-17 14:55:25 +0800480 return;
Jamie Madill0b9e9032015-08-17 11:51:52 +0000481 }
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800482
Shao4181bc92017-03-17 14:55:25 +0800483 // Since ANGLE always uses a non-zero VAO, we cannot use a client memory pointer on it:
484 // [OpenGL ES 3.0.2] Section 2.8 page 24:
485 // An INVALID_OPERATION error is generated when a non-zero vertex array object is bound,
486 // zero is bound to the ARRAY_BUFFER buffer object binding point, and the pointer argument
487 // is not NULL.
Shaodf682a82017-03-31 15:13:21 +0800488
Shao4181bc92017-03-17 14:55:25 +0800489 const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
490 mStateManager->bindBuffer(GL_ARRAY_BUFFER, arrayBufferGL->getBufferID());
Jamie Madill0b9e9032015-08-17 11:51:52 +0000491
Shaodf682a82017-03-31 15:13:21 +0800492 callVertexAttribPointer(static_cast<GLuint>(attribIndex), attrib, binding.stride,
493 binding.offset);
494
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800495 mAppliedAttributes[attribIndex].size = attrib.size;
496 mAppliedAttributes[attribIndex].type = attrib.type;
497 mAppliedAttributes[attribIndex].normalized = attrib.normalized;
498 mAppliedAttributes[attribIndex].pureInteger = attrib.pureInteger;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800499 mAppliedAttributes[attribIndex].relativeOffset = attrib.relativeOffset;
Shaodf682a82017-03-31 15:13:21 +0800500
501 mAppliedAttributes[attribIndex].bindingIndex = bindingIndex;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800502
503 mAppliedBindings[bindingIndex].stride = binding.stride;
504 mAppliedBindings[bindingIndex].offset = binding.offset;
Shao4181bc92017-03-17 14:55:25 +0800505 mAppliedBindings[bindingIndex].buffer = binding.buffer;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800506}
507
Shaodf682a82017-03-31 15:13:21 +0800508void VertexArrayGL::callVertexAttribPointer(GLuint attribIndex,
509 const VertexAttribute &attrib,
510 GLsizei stride,
511 GLintptr offset) const
512{
513 const GLvoid *pointer = reinterpret_cast<const GLvoid *>(offset);
514 if (attrib.pureInteger)
515 {
516 ASSERT(!attrib.normalized);
517 mFunctions->vertexAttribIPointer(attribIndex, attrib.size, attrib.type, stride, pointer);
518 }
519 else
520 {
521 mFunctions->vertexAttribPointer(attribIndex, attrib.size, attrib.type, attrib.normalized,
522 stride, pointer);
523 }
524}
525
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800526void VertexArrayGL::updateAttribDivisor(size_t attribIndex)
527{
Shaodf682a82017-03-31 15:13:21 +0800528 const GLuint bindingIndex = mData.getVertexAttribute(attribIndex).bindingIndex;
529 ASSERT(attribIndex == bindingIndex);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800530
Shaodf682a82017-03-31 15:13:21 +0800531 const GLuint divisor = mData.getVertexBinding(bindingIndex).divisor;
532 if (mAppliedAttributes[attribIndex].bindingIndex == bindingIndex &&
533 mAppliedBindings[bindingIndex].divisor == divisor)
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800534 {
Shaodf682a82017-03-31 15:13:21 +0800535 return;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800536 }
Shaodf682a82017-03-31 15:13:21 +0800537
538 mFunctions->vertexAttribDivisor(static_cast<GLuint>(attribIndex), divisor);
539
540 mAppliedAttributes[attribIndex].bindingIndex = bindingIndex;
541 mAppliedBindings[bindingIndex].divisor = divisor;
Jamie Madill0b9e9032015-08-17 11:51:52 +0000542}
543
Jamie Madillc564c072017-06-01 12:45:42 -0400544void VertexArrayGL::syncState(const gl::Context *context, const VertexArray::DirtyBits &dirtyBits)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000545{
Shaodf682a82017-03-31 15:13:21 +0800546 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
547
Jamie Madill6de51852017-04-12 09:53:01 -0400548 for (size_t dirtyBit : dirtyBits)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000549 {
550 if (dirtyBit == VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER)
551 {
552 // TODO(jmadill): Element array buffer bindings
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800553 continue;
Jamie Madill0b9e9032015-08-17 11:51:52 +0000554 }
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800555
556 size_t index = VertexArray::GetAttribIndex(dirtyBit);
557 if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_ENABLED &&
558 dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_ENABLED)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000559 {
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800560 updateAttribEnabled(index);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000561 }
562 else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_POINTER &&
563 dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_POINTER)
564 {
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800565 updateAttribPointer(index);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000566 }
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800567 else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_FORMAT &&
568 dirtyBit < VertexArray::DIRTY_BIT_BINDING_MAX_BUFFER)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000569 {
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800570 // TODO(jiawei.shao@intel.com): Vertex Attrib Bindings
571 ASSERT(index == mData.getBindingIndexFromAttribIndex(index));
572 }
573 else if (dirtyBit >= VertexArray::DIRTY_BIT_BINDING_0_DIVISOR &&
574 dirtyBit < VertexArray::DIRTY_BIT_BINDING_MAX_DIVISOR)
575 {
576 updateAttribDivisor(index);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000577 }
578 else
579 UNREACHABLE();
580 }
581}
582
583} // rx