blob: 2bac8a9713c385c6bd8488d07e424449dfe38525 [file] [log] [blame]
Geoff Langf9a6f082015-01-22 13:32:49 -05001//
2// Copyright 2015 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// VertexArrayGL.cpp: Implements the class methods for VertexArrayGL.
8
9#include "libANGLE/renderer/gl/VertexArrayGL.h"
10
Jamie Madill20e005b2017-04-07 14:19:22 -040011#include "common/bitset_utils.h"
Geoff Langf9a6f082015-01-22 13:32:49 -050012#include "common/debug.h"
Geoff Lang7c82bc42015-03-09 16:18:08 -040013#include "common/mathutil.h"
Geoff Lang831b1952015-05-05 11:02:27 -040014#include "common/utilities.h"
Geoff Lang6ae6efc2015-03-09 14:42:35 -040015#include "libANGLE/Buffer.h"
Geoff Langba4c4a82015-02-24 12:38:46 -050016#include "libANGLE/angletypes.h"
Geoff Lang7c82bc42015-03-09 16:18:08 -040017#include "libANGLE/formatutils.h"
Geoff Langba4c4a82015-02-24 12:38:46 -050018#include "libANGLE/renderer/gl/BufferGL.h"
19#include "libANGLE/renderer/gl/FunctionsGL.h"
20#include "libANGLE/renderer/gl/StateManagerGL.h"
Jamie Madill231c7f52017-04-26 13:45:37 -040021#include "libANGLE/renderer/gl/renderergl_utils.h"
Geoff Langf9a6f082015-01-22 13:32:49 -050022
Jamie Madill0b9e9032015-08-17 11:51:52 +000023using namespace gl;
24
Geoff Langf9a6f082015-01-22 13:32:49 -050025namespace rx
26{
Jamie Madill0b9e9032015-08-17 11:51:52 +000027namespace
28{
Jiawei-Shao2597fb62016-12-09 16:38:02 +080029// Warning: you should ensure binding really matches attrib.bindingIndex before using this function.
30bool AttributeNeedsStreaming(const VertexAttribute &attrib, const VertexBinding &binding)
Jamie Madill0b9e9032015-08-17 11:51:52 +000031{
Martin Radevdd5f27e2017-06-07 10:17:09 +030032 return (attrib.enabled && binding.getBuffer().get() == nullptr);
Jamie Madill0b9e9032015-08-17 11:51:52 +000033}
Shaodf682a82017-03-31 15:13:21 +080034
35bool SameVertexAttribFormat(const VertexAttribute &a, const VertexAttribute &b)
36{
37 return a.size == b.size && a.type == b.type && a.normalized == b.normalized &&
38 a.pureInteger == b.pureInteger && a.relativeOffset == b.relativeOffset;
39}
40
41bool SameVertexBuffer(const VertexBinding &a, const VertexBinding &b)
42{
Martin Radevdd5f27e2017-06-07 10:17:09 +030043 return a.getStride() == b.getStride() && a.getOffset() == b.getOffset() &&
44 a.getBuffer().get() == b.getBuffer().get();
Shaodf682a82017-03-31 15:13:21 +080045}
46
47bool IsVertexAttribPointerSupported(size_t attribIndex, const VertexAttribute &attrib)
48{
49 return (attribIndex == attrib.bindingIndex && attrib.relativeOffset == 0);
50}
Martin Radev553590a2017-07-31 16:40:39 +030051
52GLuint GetAdjustedDivisor(GLuint numViews, GLuint divisor)
53{
54 return numViews * divisor;
55}
56
Jamie Madill0b9e9032015-08-17 11:51:52 +000057} // anonymous namespace
58
Jamie Madill3f572682016-04-26 13:41:36 -040059VertexArrayGL::VertexArrayGL(const VertexArrayState &state,
Jamie Madill77a90c22015-08-11 16:33:17 -040060 const FunctionsGL *functions,
61 StateManagerGL *stateManager)
Jamie Madill3f572682016-04-26 13:41:36 -040062 : VertexArrayImpl(state),
Geoff Langba4c4a82015-02-24 12:38:46 -050063 mFunctions(functions),
64 mStateManager(stateManager),
65 mVertexArrayID(0),
Martin Radev553590a2017-07-31 16:40:39 +030066 mAppliedNumViews(1),
Jamie Madill77a90c22015-08-11 16:33:17 -040067 mAppliedElementArrayBuffer(),
Jiawei-Shao2597fb62016-12-09 16:38:02 +080068 mAppliedBindings(state.getMaxBindings()),
Geoff Lang7c82bc42015-03-09 16:18:08 -040069 mStreamingElementArrayBufferSize(0),
70 mStreamingElementArrayBuffer(0),
71 mStreamingArrayBufferSize(0),
72 mStreamingArrayBuffer(0)
Geoff Langba4c4a82015-02-24 12:38:46 -050073{
74 ASSERT(mFunctions);
75 ASSERT(mStateManager);
76 mFunctions->genVertexArrays(1, &mVertexArrayID);
77
Jiawei-Shao2597fb62016-12-09 16:38:02 +080078 // Set the cached vertex attribute array and vertex attribute binding array size
79 GLuint maxVertexAttribs = static_cast<GLuint>(state.getMaxAttribs());
80 for (GLuint i = 0; i < maxVertexAttribs; i++)
81 {
82 mAppliedAttributes.emplace_back(i);
83 }
Geoff Langba4c4a82015-02-24 12:38:46 -050084}
Geoff Langf9a6f082015-01-22 13:32:49 -050085
Jamie 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);
89 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 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400103 binding.setBuffer(context, nullptr);
Geoff Langba4c4a82015-02-24 12:38:46 -0500104 }
105}
Geoff Langf9a6f082015-01-22 13:32:49 -0500106
Jamie Madill4928b7c2017-06-20 12:57:39 -0400107gl::Error VertexArrayGL::syncDrawArraysState(const gl::Context *context,
108 const gl::AttributesMask &activeAttributesMask,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000109 GLint first,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400110 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 Madill4928b7c2017-06-20 12:57:39 -0400117gl::Error VertexArrayGL::syncDrawElementsState(const gl::Context *context,
118 const gl::AttributesMask &activeAttributesMask,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000119 GLsizei count,
120 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400121 const void *indices,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400122 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400123 bool primitiveRestartEnabled,
Jamie Madill876429b2017-04-20 15:46:24 -0400124 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
Jamie Madill4928b7c2017-06-20 12:57:39 -0400130gl::Error VertexArrayGL::syncElementArrayState(const gl::Context *context) const
Jiajia Qind9671222016-11-29 16:30:31 +0800131{
Jamie Madill492f58e2017-10-09 19:41:33 -0400132 gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer().get();
Jiajia Qind9671222016-11-29 16:30:31 +0800133 ASSERT(elementArrayBuffer);
134 if (elementArrayBuffer != mAppliedElementArrayBuffer.get())
135 {
136 const BufferGL *bufferGL = GetImplAs<BufferGL>(elementArrayBuffer);
137 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferGL->getBufferID());
Jamie Madill4928b7c2017-06-20 12:57:39 -0400138 mAppliedElementArrayBuffer.set(context, elementArrayBuffer);
Jiajia Qind9671222016-11-29 16:30:31 +0800139 }
140
141 return gl::NoError();
142}
143
Jamie Madill4928b7c2017-06-20 12:57:39 -0400144gl::Error VertexArrayGL::syncDrawState(const gl::Context *context,
145 const gl::AttributesMask &activeAttributesMask,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000146 GLint first,
147 GLsizei count,
148 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400149 const void *indices,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400150 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400151 bool primitiveRestartEnabled,
Jamie Madill876429b2017-04-20 15:46:24 -0400152 const void **outIndices) const
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400153{
Jamie Madill77a90c22015-08-11 16:33:17 -0400154 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400155
Shao80957d92017-02-20 21:25:59 +0800156 // Check if any attributes need to be streamed, determines if the index range needs to be
157 // computed
Jamie Madill0b9e9032015-08-17 11:51:52 +0000158 bool attributesNeedStreaming = mAttributesNeedStreaming.any();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400159
Shao80957d92017-02-20 21:25:59 +0800160 // Determine if an index buffer needs to be streamed and the range of vertices that need to be
161 // copied
Geoff Lang3edfe032015-09-04 16:38:24 -0400162 IndexRange indexRange;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400163 if (type != GL_NONE)
Geoff Langba4c4a82015-02-24 12:38:46 -0500164 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400165 ANGLE_TRY(syncIndexData(context, count, type, indices, primitiveRestartEnabled,
166 attributesNeedStreaming, &indexRange, outIndices));
Geoff Lang7c82bc42015-03-09 16:18:08 -0400167 }
168 else
169 {
Corentin Wallez2c34a4b2015-08-25 16:26:02 -0400170 // Not an indexed call, set the range to [first, first + count - 1]
Geoff Lang7c82bc42015-03-09 16:18:08 -0400171 indexRange.start = first;
Shao80957d92017-02-20 21:25:59 +0800172 indexRange.end = first + count - 1;
Geoff Langba4c4a82015-02-24 12:38:46 -0500173 }
174
Jamie Madill0b9e9032015-08-17 11:51:52 +0000175 if (attributesNeedStreaming)
Geoff Langba4c4a82015-02-24 12:38:46 -0500176 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400177 ANGLE_TRY(streamAttributes(activeAttributesMask, instanceCount, indexRange));
Geoff Lang7c82bc42015-03-09 16:18:08 -0400178 }
179
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500180 return gl::NoError();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400181}
182
Jamie Madill4928b7c2017-06-20 12:57:39 -0400183gl::Error VertexArrayGL::syncIndexData(const gl::Context *context,
184 GLsizei count,
Jiajia Qind9671222016-11-29 16:30:31 +0800185 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400186 const void *indices,
Jiajia Qind9671222016-11-29 16:30:31 +0800187 bool primitiveRestartEnabled,
188 bool attributesNeedStreaming,
189 IndexRange *outIndexRange,
Jamie Madill876429b2017-04-20 15:46:24 -0400190 const void **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400191{
192 ASSERT(outIndices);
193
Jamie Madill492f58e2017-10-09 19:41:33 -0400194 gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer().get();
Jamie Madill8e344942015-07-09 14:22:07 -0400195
Geoff Lang7c82bc42015-03-09 16:18:08 -0400196 // Need to check the range of indices if attributes need to be streamed
Jamie Madill8e344942015-07-09 14:22:07 -0400197 if (elementArrayBuffer != nullptr)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400198 {
Jamie Madill77a90c22015-08-11 16:33:17 -0400199 if (elementArrayBuffer != mAppliedElementArrayBuffer.get())
Geoff Lang7c82bc42015-03-09 16:18:08 -0400200 {
Jamie Madill77a90c22015-08-11 16:33:17 -0400201 const BufferGL *bufferGL = GetImplAs<BufferGL>(elementArrayBuffer);
202 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferGL->getBufferID());
Jamie Madill4928b7c2017-06-20 12:57:39 -0400203 mAppliedElementArrayBuffer.set(context, elementArrayBuffer);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400204 }
205
206 // Only compute the index range if the attributes also need to be streamed
207 if (attributesNeedStreaming)
208 {
209 ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices);
Jamie Madill492f58e2017-10-09 19:41:33 -0400210 Error error = mState.getElementArrayBuffer()->getIndexRange(
Jamie Madill33510102017-09-20 10:39:18 -0400211 context, type, elementArrayBufferOffset, count, primitiveRestartEnabled,
212 outIndexRange);
Geoff Lang520c4ae2015-05-05 13:12:36 -0400213 if (error.isError())
Geoff Lang7c82bc42015-03-09 16:18:08 -0400214 {
Geoff Lang520c4ae2015-05-05 13:12:36 -0400215 return error;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400216 }
217 }
218
Shao80957d92017-02-20 21:25:59 +0800219 // Indices serves as an offset into the index buffer in this case, use the same value for
220 // the draw call
Geoff Lang7c82bc42015-03-09 16:18:08 -0400221 *outIndices = indices;
222 }
223 else
224 {
225 // Need to stream the index buffer
226 // TODO: if GLES, nothing needs to be streamed
227
228 // Only compute the index range if the attributes also need to be streamed
229 if (attributesNeedStreaming)
230 {
Geoff Lang3edfe032015-09-04 16:38:24 -0400231 *outIndexRange = ComputeIndexRange(type, indices, count, primitiveRestartEnabled);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400232 }
233
234 // Allocate the streaming element array buffer
235 if (mStreamingElementArrayBuffer == 0)
236 {
237 mFunctions->genBuffers(1, &mStreamingElementArrayBuffer);
238 mStreamingElementArrayBufferSize = 0;
239 }
240
241 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, mStreamingElementArrayBuffer);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400242 mAppliedElementArrayBuffer.set(context, nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400243
244 // Make sure the element array buffer is large enough
Jamie Madill0b9e9032015-08-17 11:51:52 +0000245 const Type &indexTypeInfo = GetTypeInfo(type);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400246 size_t requiredStreamingBufferSize = indexTypeInfo.bytes * count;
247 if (requiredStreamingBufferSize > mStreamingElementArrayBufferSize)
248 {
249 // Copy the indices in while resizing the buffer
Shao80957d92017-02-20 21:25:59 +0800250 mFunctions->bufferData(GL_ELEMENT_ARRAY_BUFFER, requiredStreamingBufferSize, indices,
251 GL_DYNAMIC_DRAW);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400252 mStreamingElementArrayBufferSize = requiredStreamingBufferSize;
253 }
254 else
255 {
256 // Put the indices at the beginning of the buffer
Shao80957d92017-02-20 21:25:59 +0800257 mFunctions->bufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, requiredStreamingBufferSize,
258 indices);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400259 }
260
Shao80957d92017-02-20 21:25:59 +0800261 // Set the index offset for the draw call to zero since the supplied index pointer is to
262 // client data
Geoff Lang7c82bc42015-03-09 16:18:08 -0400263 *outIndices = nullptr;
264 }
265
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500266 return gl::NoError();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400267}
268
Jamie Madill0b9e9032015-08-17 11:51:52 +0000269void VertexArrayGL::computeStreamingAttributeSizes(const gl::AttributesMask &activeAttributesMask,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400270 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400271 const gl::IndexRange &indexRange,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000272 size_t *outStreamingDataSize,
273 size_t *outMaxAttributeDataSize) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400274{
Jamie Madill0b9e9032015-08-17 11:51:52 +0000275 *outStreamingDataSize = 0;
276 *outMaxAttributeDataSize = 0;
277
278 ASSERT(mAttributesNeedStreaming.any());
279
Jamie Madill492f58e2017-10-09 19:41:33 -0400280 const auto &attribs = mState.getVertexAttributes();
281 const auto &bindings = mState.getVertexBindings();
Jamie Madill6de51852017-04-12 09:53:01 -0400282
283 gl::AttributesMask attribsToStream = (mAttributesNeedStreaming & activeAttributesMask);
284
285 for (auto idx : attribsToStream)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000286 {
Shao80957d92017-02-20 21:25:59 +0800287 const auto &attrib = attribs[idx];
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800288 const auto &binding = bindings[attrib.bindingIndex];
289 ASSERT(AttributeNeedsStreaming(attrib, binding));
Jamie Madill0b9e9032015-08-17 11:51:52 +0000290
Jamie Madill0b9e9032015-08-17 11:51:52 +0000291 // If streaming is going to be required, compute the size of the required buffer
292 // and how much slack space at the beginning of the buffer will be required by determining
293 // the attribute with the largest data size.
294 size_t typeSize = ComputeVertexAttributeTypeSize(attrib);
Martin Radev553590a2017-07-31 16:40:39 +0300295 GLuint adjustedDivisor = GetAdjustedDivisor(mAppliedNumViews, binding.getDivisor());
296 *outStreamingDataSize +=
297 typeSize * ComputeVertexBindingElementCount(adjustedDivisor, indexRange.vertexCount(),
298 instanceCount);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000299 *outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
300 }
301}
302
303gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &activeAttributesMask,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400304 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400305 const gl::IndexRange &indexRange) const
Jamie Madill0b9e9032015-08-17 11:51:52 +0000306{
307 // Sync the vertex attribute state and track what data needs to be streamed
308 size_t streamingDataSize = 0;
309 size_t maxAttributeDataSize = 0;
310
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400311 computeStreamingAttributeSizes(activeAttributesMask, instanceCount, indexRange,
312 &streamingDataSize, &maxAttributeDataSize);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000313
314 if (streamingDataSize == 0)
315 {
He Yunchaoacd18982017-01-04 10:46:42 +0800316 return gl::NoError();
Jamie Madill0b9e9032015-08-17 11:51:52 +0000317 }
318
Geoff Lang7c82bc42015-03-09 16:18:08 -0400319 if (mStreamingArrayBuffer == 0)
320 {
321 mFunctions->genBuffers(1, &mStreamingArrayBuffer);
322 mStreamingArrayBufferSize = 0;
323 }
324
Shao80957d92017-02-20 21:25:59 +0800325 // If first is greater than zero, a slack space needs to be left at the beginning of the buffer
326 // so that the same 'first' argument can be passed into the draw call.
327 const size_t bufferEmptySpace = maxAttributeDataSize * indexRange.start;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400328 const size_t requiredBufferSize = streamingDataSize + bufferEmptySpace;
329
330 mStateManager->bindBuffer(GL_ARRAY_BUFFER, mStreamingArrayBuffer);
331 if (requiredBufferSize > mStreamingArrayBufferSize)
332 {
333 mFunctions->bufferData(GL_ARRAY_BUFFER, requiredBufferSize, nullptr, GL_DYNAMIC_DRAW);
334 mStreamingArrayBufferSize = requiredBufferSize;
335 }
336
337 // Unmapping a buffer can return GL_FALSE to indicate that the system has corrupted the data
Shao80957d92017-02-20 21:25:59 +0800338 // somehow (such as by a screen change), retry writing the data a few times and return
339 // OUT_OF_MEMORY if that fails.
340 GLboolean unmapResult = GL_FALSE;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400341 size_t unmapRetryAttempts = 5;
342 while (unmapResult != GL_TRUE && --unmapRetryAttempts > 0)
343 {
Geoff Langb2ebb5e2016-06-08 18:17:55 +0000344 uint8_t *bufferPointer = MapBufferRangeWithFallback(mFunctions, GL_ARRAY_BUFFER, 0,
345 requiredBufferSize, GL_MAP_WRITE_BIT);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400346 size_t curBufferOffset = bufferEmptySpace;
347
Jamie Madill492f58e2017-10-09 19:41:33 -0400348 const auto &attribs = mState.getVertexAttributes();
349 const auto &bindings = mState.getVertexBindings();
Jamie Madill6de51852017-04-12 09:53:01 -0400350
351 gl::AttributesMask attribsToStream = (mAttributesNeedStreaming & activeAttributesMask);
352
353 for (auto idx : attribsToStream)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400354 {
Shao80957d92017-02-20 21:25:59 +0800355 const auto &attrib = attribs[idx];
Shaodde78e82017-05-22 14:13:27 +0800356 ASSERT(IsVertexAttribPointerSupported(idx, attrib));
357
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800358 const auto &binding = bindings[attrib.bindingIndex];
359 ASSERT(AttributeNeedsStreaming(attrib, binding));
Geoff Lang7c82bc42015-03-09 16:18:08 -0400360
Martin Radev553590a2017-07-31 16:40:39 +0300361 GLuint adjustedDivisor = GetAdjustedDivisor(mAppliedNumViews, binding.getDivisor());
362 const size_t streamedVertexCount = ComputeVertexBindingElementCount(
363 adjustedDivisor, indexRange.vertexCount(), instanceCount);
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400364
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800365 const size_t sourceStride = ComputeVertexAttributeStride(attrib, binding);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000366 const size_t destStride = ComputeVertexAttributeTypeSize(attrib);
367
Geoff Lang38a24a92017-02-15 13:53:06 -0500368 // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing
369 // a non-instanced draw call
Martin Radev553590a2017-07-31 16:40:39 +0300370 const size_t firstIndex = adjustedDivisor == 0 ? indexRange.start : 0;
Geoff Lang38a24a92017-02-15 13:53:06 -0500371
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800372 // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state.
373 // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt
Jamie Madill0b9e9032015-08-17 11:51:52 +0000374 const uint8_t *inputPointer = reinterpret_cast<const uint8_t *>(attrib.pointer);
375
376 // Pack the data when copying it, user could have supplied a very large stride that
377 // would cause the buffer to be much larger than needed.
378 if (destStride == sourceStride)
Jamie Madill8e344942015-07-09 14:22:07 -0400379 {
Jamie Madill0b9e9032015-08-17 11:51:52 +0000380 // Can copy in one go, the data is packed
Geoff Lang38a24a92017-02-15 13:53:06 -0500381 memcpy(bufferPointer + curBufferOffset, inputPointer + (sourceStride * firstIndex),
Jamie Madill0b9e9032015-08-17 11:51:52 +0000382 destStride * streamedVertexCount);
Jamie Madill6d51c702015-08-14 10:38:10 -0400383 }
Jamie Madill0b9e9032015-08-17 11:51:52 +0000384 else
385 {
386 // Copy each vertex individually
Geoff Lang6b10ddb2015-09-02 15:55:10 -0400387 for (size_t vertexIdx = 0; vertexIdx < streamedVertexCount; vertexIdx++)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000388 {
Shao80957d92017-02-20 21:25:59 +0800389 uint8_t *out = bufferPointer + curBufferOffset + (destStride * vertexIdx);
Geoff Lang38a24a92017-02-15 13:53:06 -0500390 const uint8_t *in = inputPointer + sourceStride * (vertexIdx + firstIndex);
Corentin Wallez4d5362d2015-08-25 11:25:14 -0400391 memcpy(out, in, destStride);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000392 }
393 }
394
395 // Compute where the 0-index vertex would be.
Geoff Lang38a24a92017-02-15 13:53:06 -0500396 const size_t vertexStartOffset = curBufferOffset - (firstIndex * destStride);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000397
Shaodf682a82017-03-31 15:13:21 +0800398 callVertexAttribPointer(static_cast<GLuint>(idx), attrib,
399 static_cast<GLsizei>(destStride),
400 static_cast<GLintptr>(vertexStartOffset));
Jamie Madill0b9e9032015-08-17 11:51:52 +0000401
402 curBufferOffset += destStride * streamedVertexCount;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400403 }
404
405 unmapResult = mFunctions->unmapBuffer(GL_ARRAY_BUFFER);
406 }
407
408 if (unmapResult != GL_TRUE)
409 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500410 return gl::OutOfMemory() << "Failed to unmap the client data streaming buffer.";
Geoff Lang7c82bc42015-03-09 16:18:08 -0400411 }
412
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500413 return gl::NoError();
Geoff Langba4c4a82015-02-24 12:38:46 -0500414}
415
416GLuint VertexArrayGL::getVertexArrayID() const
417{
418 return mVertexArrayID;
Geoff Langf9a6f082015-01-22 13:32:49 -0500419}
420
Geoff Lang294cad92015-05-26 15:11:23 -0400421GLuint VertexArrayGL::getAppliedElementArrayBufferID() const
422{
Jamie Madill77a90c22015-08-11 16:33:17 -0400423 if (mAppliedElementArrayBuffer.get() == nullptr)
424 {
425 return mStreamingElementArrayBuffer;
426 }
427
428 return GetImplAs<BufferGL>(mAppliedElementArrayBuffer.get())->getBufferID();
Geoff Lang294cad92015-05-26 15:11:23 -0400429}
430
Jamie Madill0b9e9032015-08-17 11:51:52 +0000431void VertexArrayGL::updateNeedsStreaming(size_t attribIndex)
432{
Jamie Madill492f58e2017-10-09 19:41:33 -0400433 const auto &attrib = mState.getVertexAttribute(attribIndex);
434 const auto &binding = mState.getBindingFromAttribIndex(attribIndex);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800435 mAttributesNeedStreaming.set(attribIndex, AttributeNeedsStreaming(attrib, binding));
Geoff Langf9a6f082015-01-22 13:32:49 -0500436}
Jamie Madill0b9e9032015-08-17 11:51:52 +0000437
438void VertexArrayGL::updateAttribEnabled(size_t attribIndex)
439{
Jamie Madill492f58e2017-10-09 19:41:33 -0400440 const bool enabled = mState.getVertexAttribute(attribIndex).enabled;
Shaodf682a82017-03-31 15:13:21 +0800441 if (mAppliedAttributes[attribIndex].enabled == enabled)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000442 {
443 return;
444 }
445
446 updateNeedsStreaming(attribIndex);
447
Shaodf682a82017-03-31 15:13:21 +0800448 if (enabled)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000449 {
450 mFunctions->enableVertexAttribArray(static_cast<GLuint>(attribIndex));
451 }
452 else
453 {
454 mFunctions->disableVertexAttribArray(static_cast<GLuint>(attribIndex));
455 }
Shaodf682a82017-03-31 15:13:21 +0800456
457 mAppliedAttributes[attribIndex].enabled = enabled;
Jamie Madill0b9e9032015-08-17 11:51:52 +0000458}
459
Jamie Madill4928b7c2017-06-20 12:57:39 -0400460void VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attribIndex)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000461{
Jamie Madill492f58e2017-10-09 19:41:33 -0400462 const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800463
Shaodde78e82017-05-22 14:13:27 +0800464 // According to SPEC, VertexAttribPointer should update the binding indexed attribIndex instead
465 // of the binding indexed attrib.bindingIndex (unless attribIndex == attrib.bindingIndex).
Jamie Madill492f58e2017-10-09 19:41:33 -0400466 const VertexBinding &binding = mState.getVertexBinding(attribIndex);
Shaodf682a82017-03-31 15:13:21 +0800467
Shaodde78e82017-05-22 14:13:27 +0800468 // Since mAttributesNeedStreaming[attribIndex] keeps the value set in the last draw, here we
469 // only need to update it when the buffer has been changed. e.g. When we set an attribute to be
470 // streamed in the last draw, and only change its format in this draw without calling
471 // updateNeedsStreaming, it will still be streamed because the flag is already on.
472 const auto &bindingBuffer = binding.getBuffer();
473 if (bindingBuffer != mAppliedBindings[attribIndex].getBuffer())
474 {
475 updateNeedsStreaming(attribIndex);
476 }
477
478 // Early return when the vertex attribute isn't using a buffer object:
479 // - If we need to stream, defer the attribPointer to the draw call.
480 // - Skip the attribute that is disabled and uses a client memory pointer.
481 // - Skip the attribute whose buffer is detached by BindVertexBuffer. Since it cannot have a
482 // client memory pointer either, it must be disabled and shouldn't affect the draw.
483 const Buffer *arrayBuffer = bindingBuffer.get();
484 if (arrayBuffer == nullptr)
485 {
486 // Mark the applied binding isn't using a buffer by setting its buffer to nullptr so that if
487 // it starts to use a buffer later, there is no chance that the caching will skip it.
488 mAppliedBindings[attribIndex].setBuffer(context, nullptr);
489 return;
490 }
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800491
Shaodf682a82017-03-31 15:13:21 +0800492 // We do not need to compare attrib.pointer because when we use a different client memory
493 // pointer, we don't need to update mAttributesNeedStreaming by binding.buffer and we won't
494 // update attribPointer in this function.
Shaodde78e82017-05-22 14:13:27 +0800495 if ((SameVertexAttribFormat(mAppliedAttributes[attribIndex], attrib)) &&
496 (mAppliedAttributes[attribIndex].bindingIndex == attrib.bindingIndex) &&
497 (SameVertexBuffer(mAppliedBindings[attribIndex], binding)))
Jamie Madill0b9e9032015-08-17 11:51:52 +0000498 {
499 return;
500 }
501
Shao4181bc92017-03-17 14:55:25 +0800502 // Since ANGLE always uses a non-zero VAO, we cannot use a client memory pointer on it:
503 // [OpenGL ES 3.0.2] Section 2.8 page 24:
504 // An INVALID_OPERATION error is generated when a non-zero vertex array object is bound,
505 // zero is bound to the ARRAY_BUFFER buffer object binding point, and the pointer argument
506 // is not NULL.
Shaodf682a82017-03-31 15:13:21 +0800507
Shao4181bc92017-03-17 14:55:25 +0800508 const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
509 mStateManager->bindBuffer(GL_ARRAY_BUFFER, arrayBufferGL->getBufferID());
Martin Radevdd5f27e2017-06-07 10:17:09 +0300510 callVertexAttribPointer(static_cast<GLuint>(attribIndex), attrib, binding.getStride(),
511 binding.getOffset());
Shaodf682a82017-03-31 15:13:21 +0800512
Shaodde78e82017-05-22 14:13:27 +0800513 mAppliedAttributes[attribIndex].size = attrib.size;
514 mAppliedAttributes[attribIndex].type = attrib.type;
515 mAppliedAttributes[attribIndex].normalized = attrib.normalized;
516 mAppliedAttributes[attribIndex].pureInteger = attrib.pureInteger;
Shaodf682a82017-03-31 15:13:21 +0800517
Shaodde78e82017-05-22 14:13:27 +0800518 // After VertexAttribPointer, attrib.relativeOffset is set to 0 and attrib.bindingIndex is set
519 // to attribIndex in driver. If attrib.relativeOffset != 0 or attrib.bindingIndex !=
520 // attribIndex, they should be set in updateAttribFormat and updateAttribBinding. The cache
521 // should be consistent with driver so that we won't miss anything.
522 mAppliedAttributes[attribIndex].relativeOffset = 0;
523 mAppliedAttributes[attribIndex].bindingIndex = static_cast<GLuint>(attribIndex);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800524
Shaodde78e82017-05-22 14:13:27 +0800525 mAppliedBindings[attribIndex].setStride(binding.getStride());
526 mAppliedBindings[attribIndex].setOffset(binding.getOffset());
527 mAppliedBindings[attribIndex].setBuffer(context, binding.getBuffer().get());
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800528}
529
Shaodf682a82017-03-31 15:13:21 +0800530void VertexArrayGL::callVertexAttribPointer(GLuint attribIndex,
531 const VertexAttribute &attrib,
532 GLsizei stride,
533 GLintptr offset) const
534{
535 const GLvoid *pointer = reinterpret_cast<const GLvoid *>(offset);
536 if (attrib.pureInteger)
537 {
538 ASSERT(!attrib.normalized);
539 mFunctions->vertexAttribIPointer(attribIndex, attrib.size, attrib.type, stride, pointer);
540 }
541 else
542 {
543 mFunctions->vertexAttribPointer(attribIndex, attrib.size, attrib.type, attrib.normalized,
544 stride, pointer);
545 }
546}
547
Shaodde78e82017-05-22 14:13:27 +0800548bool VertexArrayGL::supportVertexAttribBinding() const
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800549{
Shaodde78e82017-05-22 14:13:27 +0800550 ASSERT(mFunctions);
551 return (mFunctions->vertexAttribBinding != nullptr);
552}
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800553
Shaodde78e82017-05-22 14:13:27 +0800554void VertexArrayGL::updateAttribFormat(size_t attribIndex)
555{
556 ASSERT(supportVertexAttribBinding());
557
Jamie Madill492f58e2017-10-09 19:41:33 -0400558 const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
Shaodde78e82017-05-22 14:13:27 +0800559 if (SameVertexAttribFormat(mAppliedAttributes[attribIndex], attrib))
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800560 {
Shaodf682a82017-03-31 15:13:21 +0800561 return;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800562 }
Shaodf682a82017-03-31 15:13:21 +0800563
Shaodde78e82017-05-22 14:13:27 +0800564 if (attrib.pureInteger)
565 {
566 ASSERT(!attrib.normalized);
567 mFunctions->vertexAttribIFormat(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
568 attrib.relativeOffset);
569 }
570 else
571 {
572 mFunctions->vertexAttribFormat(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
573 attrib.normalized, attrib.relativeOffset);
574 }
575
576 mAppliedAttributes[attribIndex].size = attrib.size;
577 mAppliedAttributes[attribIndex].type = attrib.type;
578 mAppliedAttributes[attribIndex].normalized = attrib.normalized;
579 mAppliedAttributes[attribIndex].pureInteger = attrib.pureInteger;
580 mAppliedAttributes[attribIndex].relativeOffset = attrib.relativeOffset;
581}
582
583void VertexArrayGL::updateAttribBinding(size_t attribIndex)
584{
585 ASSERT(supportVertexAttribBinding());
586
Jamie Madill492f58e2017-10-09 19:41:33 -0400587 GLuint bindingIndex = mState.getVertexAttribute(attribIndex).bindingIndex;
Shaodde78e82017-05-22 14:13:27 +0800588 if (mAppliedAttributes[attribIndex].bindingIndex == bindingIndex)
589 {
590 return;
591 }
592
593 mFunctions->vertexAttribBinding(static_cast<GLuint>(attribIndex), bindingIndex);
Shaodf682a82017-03-31 15:13:21 +0800594
595 mAppliedAttributes[attribIndex].bindingIndex = bindingIndex;
Shaodde78e82017-05-22 14:13:27 +0800596}
597
598void VertexArrayGL::updateBindingBuffer(const gl::Context *context, size_t bindingIndex)
599{
600 ASSERT(supportVertexAttribBinding());
601
Jamie Madill492f58e2017-10-09 19:41:33 -0400602 const VertexBinding &binding = mState.getVertexBinding(bindingIndex);
Shaodde78e82017-05-22 14:13:27 +0800603 if (SameVertexBuffer(mAppliedBindings[bindingIndex], binding))
604 {
605 return;
606 }
607
608 const Buffer *arrayBuffer = binding.getBuffer().get();
609 GLuint bufferId = 0;
610 if (arrayBuffer != nullptr)
611 {
612 bufferId = GetImplAs<BufferGL>(arrayBuffer)->getBufferID();
613 }
614
615 mFunctions->bindVertexBuffer(static_cast<GLuint>(bindingIndex), bufferId, binding.getOffset(),
616 binding.getStride());
617
618 mAppliedBindings[bindingIndex].setStride(binding.getStride());
619 mAppliedBindings[bindingIndex].setOffset(binding.getOffset());
620 mAppliedBindings[bindingIndex].setBuffer(context, binding.getBuffer().get());
621}
622
623void VertexArrayGL::updateBindingDivisor(size_t bindingIndex)
624{
Martin Radev553590a2017-07-31 16:40:39 +0300625 GLuint adjustedDivisor =
Jamie Madill492f58e2017-10-09 19:41:33 -0400626 GetAdjustedDivisor(mAppliedNumViews, mState.getVertexBinding(bindingIndex).getDivisor());
Martin Radev553590a2017-07-31 16:40:39 +0300627 if (mAppliedBindings[bindingIndex].getDivisor() == adjustedDivisor)
Shaodde78e82017-05-22 14:13:27 +0800628 {
629 return;
630 }
631
632 if (supportVertexAttribBinding())
633 {
Martin Radev553590a2017-07-31 16:40:39 +0300634 mFunctions->vertexBindingDivisor(static_cast<GLuint>(bindingIndex), adjustedDivisor);
Shaodde78e82017-05-22 14:13:27 +0800635 }
636 else
637 {
638 // We can only use VertexAttribDivisor on platforms that don't support Vertex Attrib
639 // Binding.
Martin Radev553590a2017-07-31 16:40:39 +0300640 mFunctions->vertexAttribDivisor(static_cast<GLuint>(bindingIndex), adjustedDivisor);
Shaodde78e82017-05-22 14:13:27 +0800641 }
642
Martin Radev553590a2017-07-31 16:40:39 +0300643 mAppliedBindings[bindingIndex].setDivisor(adjustedDivisor);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000644}
645
Jamie Madillc564c072017-06-01 12:45:42 -0400646void VertexArrayGL::syncState(const gl::Context *context, const VertexArray::DirtyBits &dirtyBits)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000647{
Shaodf682a82017-03-31 15:13:21 +0800648 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
649
Jamie Madill6de51852017-04-12 09:53:01 -0400650 for (size_t dirtyBit : dirtyBits)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000651 {
652 if (dirtyBit == VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER)
653 {
654 // TODO(jmadill): Element array buffer bindings
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800655 continue;
Jamie Madill0b9e9032015-08-17 11:51:52 +0000656 }
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800657
Shaodde78e82017-05-22 14:13:27 +0800658 size_t index = VertexArray::GetVertexIndexFromDirtyBit(dirtyBit);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800659 if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_ENABLED &&
660 dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_ENABLED)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000661 {
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800662 updateAttribEnabled(index);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000663 }
664 else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_POINTER &&
665 dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_POINTER)
666 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400667 updateAttribPointer(context, index);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000668 }
Shaodde78e82017-05-22 14:13:27 +0800669
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800670 else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_FORMAT &&
Shaodde78e82017-05-22 14:13:27 +0800671 dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_FORMAT)
672 {
673 ASSERT(supportVertexAttribBinding());
674 updateAttribFormat(index);
675 }
676 else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_BINDING &&
677 dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_BINDING)
678 {
679 ASSERT(supportVertexAttribBinding());
680 updateAttribBinding(index);
681 }
682 else if (dirtyBit >= VertexArray::DIRTY_BIT_BINDING_0_BUFFER &&
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800683 dirtyBit < VertexArray::DIRTY_BIT_BINDING_MAX_BUFFER)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000684 {
Shaodde78e82017-05-22 14:13:27 +0800685 ASSERT(supportVertexAttribBinding());
686 updateBindingBuffer(context, index);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800687 }
Shaodde78e82017-05-22 14:13:27 +0800688
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800689 else if (dirtyBit >= VertexArray::DIRTY_BIT_BINDING_0_DIVISOR &&
690 dirtyBit < VertexArray::DIRTY_BIT_BINDING_MAX_DIVISOR)
691 {
Shaodde78e82017-05-22 14:13:27 +0800692 updateBindingDivisor(index);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000693 }
694 else
695 UNREACHABLE();
696 }
697}
698
Martin Radev553590a2017-07-31 16:40:39 +0300699void VertexArrayGL::applyNumViewsToDivisor(int numViews)
700{
701 if (numViews != mAppliedNumViews)
702 {
703 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
704 mAppliedNumViews = numViews;
705 for (size_t index = 0u; index < mAppliedBindings.size(); ++index)
706 {
707 updateBindingDivisor(index);
708 }
709 }
710}
711
Jamie Madill0b9e9032015-08-17 11:51:52 +0000712} // rx