blob: 6decc0a4edbaa872428572ad98401f73aac69830 [file] [log] [blame]
Geoff Langf9a6f082015-01-22 13:32:49 -05001//
2// Copyright 2015 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// VertexArrayGL.cpp: Implements the class methods for VertexArrayGL.
8
9#include "libANGLE/renderer/gl/VertexArrayGL.h"
10
Jamie Madill20e005b2017-04-07 14:19:22 -040011#include "common/bitset_utils.h"
Geoff Langf9a6f082015-01-22 13:32:49 -050012#include "common/debug.h"
Geoff Lang7c82bc42015-03-09 16:18:08 -040013#include "common/mathutil.h"
Geoff Lang831b1952015-05-05 11:02:27 -040014#include "common/utilities.h"
Geoff Lang6ae6efc2015-03-09 14:42:35 -040015#include "libANGLE/Buffer.h"
Jamie Madilldc358af2018-07-31 11:22:13 -040016#include "libANGLE/Context.h"
Geoff Langba4c4a82015-02-24 12:38:46 -050017#include "libANGLE/angletypes.h"
Geoff Lang7c82bc42015-03-09 16:18:08 -040018#include "libANGLE/formatutils.h"
Geoff Langba4c4a82015-02-24 12:38:46 -050019#include "libANGLE/renderer/gl/BufferGL.h"
20#include "libANGLE/renderer/gl/FunctionsGL.h"
21#include "libANGLE/renderer/gl/StateManagerGL.h"
Jamie Madill231c7f52017-04-26 13:45:37 -040022#include "libANGLE/renderer/gl/renderergl_utils.h"
Geoff Langf9a6f082015-01-22 13:32:49 -050023
Jamie Madill0b9e9032015-08-17 11:51:52 +000024using namespace gl;
25
Geoff Langf9a6f082015-01-22 13:32:49 -050026namespace rx
27{
Jamie Madill0b9e9032015-08-17 11:51:52 +000028namespace
29{
Shaodf682a82017-03-31 15:13:21 +080030bool SameVertexAttribFormat(const VertexAttribute &a, const VertexAttribute &b)
31{
32 return a.size == b.size && a.type == b.type && a.normalized == b.normalized &&
33 a.pureInteger == b.pureInteger && a.relativeOffset == b.relativeOffset;
34}
35
36bool SameVertexBuffer(const VertexBinding &a, const VertexBinding &b)
37{
Martin Radevdd5f27e2017-06-07 10:17:09 +030038 return a.getStride() == b.getStride() && a.getOffset() == b.getOffset() &&
39 a.getBuffer().get() == b.getBuffer().get();
Shaodf682a82017-03-31 15:13:21 +080040}
41
42bool IsVertexAttribPointerSupported(size_t attribIndex, const VertexAttribute &attrib)
43{
44 return (attribIndex == attrib.bindingIndex && attrib.relativeOffset == 0);
45}
Martin Radev553590a2017-07-31 16:40:39 +030046
47GLuint GetAdjustedDivisor(GLuint numViews, GLuint divisor)
48{
49 return numViews * divisor;
50}
51
Jamie Madill0b9e9032015-08-17 11:51:52 +000052} // anonymous namespace
53
Jamie Madill3f572682016-04-26 13:41:36 -040054VertexArrayGL::VertexArrayGL(const VertexArrayState &state,
Jamie Madill77a90c22015-08-11 16:33:17 -040055 const FunctionsGL *functions,
56 StateManagerGL *stateManager)
Jamie Madill3f572682016-04-26 13:41:36 -040057 : VertexArrayImpl(state),
Geoff Langba4c4a82015-02-24 12:38:46 -050058 mFunctions(functions),
59 mStateManager(stateManager),
60 mVertexArrayID(0),
Martin Radev553590a2017-07-31 16:40:39 +030061 mAppliedNumViews(1),
Jamie Madill77a90c22015-08-11 16:33:17 -040062 mAppliedElementArrayBuffer(),
Jiawei-Shao2597fb62016-12-09 16:38:02 +080063 mAppliedBindings(state.getMaxBindings()),
Geoff Lang7c82bc42015-03-09 16:18:08 -040064 mStreamingElementArrayBufferSize(0),
65 mStreamingElementArrayBuffer(0),
66 mStreamingArrayBufferSize(0),
67 mStreamingArrayBuffer(0)
Geoff Langba4c4a82015-02-24 12:38:46 -050068{
69 ASSERT(mFunctions);
70 ASSERT(mStateManager);
71 mFunctions->genVertexArrays(1, &mVertexArrayID);
72
Jiawei-Shao2597fb62016-12-09 16:38:02 +080073 // Set the cached vertex attribute array and vertex attribute binding array size
74 GLuint maxVertexAttribs = static_cast<GLuint>(state.getMaxAttribs());
75 for (GLuint i = 0; i < maxVertexAttribs; i++)
76 {
77 mAppliedAttributes.emplace_back(i);
78 }
Geoff Langba4c4a82015-02-24 12:38:46 -050079}
Geoff Langf9a6f082015-01-22 13:32:49 -050080
Jamie Madillacf2f3a2017-11-21 19:22:44 -050081VertexArrayGL::~VertexArrayGL()
82{
83}
84
Jamie Madill4928b7c2017-06-20 12:57:39 -040085void VertexArrayGL::destroy(const gl::Context *context)
Geoff Langba4c4a82015-02-24 12:38:46 -050086{
Geoff Lang1eb708e2015-05-04 14:58:23 -040087 mStateManager->deleteVertexArray(mVertexArrayID);
88 mVertexArrayID = 0;
Martin Radev553590a2017-07-31 16:40:39 +030089 mAppliedNumViews = 1;
Geoff Langba4c4a82015-02-24 12:38:46 -050090
Geoff Lang1eb708e2015-05-04 14:58:23 -040091 mStateManager->deleteBuffer(mStreamingElementArrayBuffer);
92 mStreamingElementArrayBufferSize = 0;
Shao80957d92017-02-20 21:25:59 +080093 mStreamingElementArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040094
Geoff Lang1eb708e2015-05-04 14:58:23 -040095 mStateManager->deleteBuffer(mStreamingArrayBuffer);
96 mStreamingArrayBufferSize = 0;
Shao80957d92017-02-20 21:25:59 +080097 mStreamingArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040098
Jamie Madill4928b7c2017-06-20 12:57:39 -040099 mAppliedElementArrayBuffer.set(context, nullptr);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800100 for (auto &binding : mAppliedBindings)
Geoff Langba4c4a82015-02-24 12:38:46 -0500101 {
James Darpiniane8a93c62018-01-04 18:02:24 -0800102 binding.setBuffer(context, nullptr, false);
Geoff Langba4c4a82015-02-24 12:38:46 -0500103 }
104}
Geoff Langf9a6f082015-01-22 13:32:49 -0500105
Jamie Madill4928b7c2017-06-20 12:57:39 -0400106gl::Error VertexArrayGL::syncDrawArraysState(const gl::Context *context,
107 const gl::AttributesMask &activeAttributesMask,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000108 GLint first,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400109 GLsizei count,
110 GLsizei instanceCount) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400111{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400112 return syncDrawState(context, activeAttributesMask, first, count, GL_NONE, nullptr,
113 instanceCount, false, nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400114}
115
Jamie Madill4928b7c2017-06-20 12:57:39 -0400116gl::Error VertexArrayGL::syncDrawElementsState(const gl::Context *context,
117 const gl::AttributesMask &activeAttributesMask,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000118 GLsizei count,
119 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400120 const void *indices,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400121 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400122 bool primitiveRestartEnabled,
Jamie Madill876429b2017-04-20 15:46:24 -0400123 const void **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400124{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400125 return syncDrawState(context, activeAttributesMask, 0, count, type, indices, instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400126 primitiveRestartEnabled, outIndices);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400127}
128
Jiajia Qin47474142017-12-29 13:41:00 +0800129void VertexArrayGL::updateElementArrayBufferBinding(const gl::Context *context) const
Jiajia Qind9671222016-11-29 16:30:31 +0800130{
Jamie Madill492f58e2017-10-09 19:41:33 -0400131 gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer().get();
Jiajia Qin47474142017-12-29 13:41:00 +0800132 if (elementArrayBuffer != nullptr && elementArrayBuffer != mAppliedElementArrayBuffer.get())
Jiajia Qind9671222016-11-29 16:30:31 +0800133 {
134 const BufferGL *bufferGL = GetImplAs<BufferGL>(elementArrayBuffer);
Corentin Wallez336129f2017-10-17 15:55:40 -0400135 mStateManager->bindBuffer(gl::BufferBinding::ElementArray, bufferGL->getBufferID());
Jamie Madill4928b7c2017-06-20 12:57:39 -0400136 mAppliedElementArrayBuffer.set(context, elementArrayBuffer);
Jiajia Qind9671222016-11-29 16:30:31 +0800137 }
Jiajia Qind9671222016-11-29 16:30:31 +0800138}
139
Jamie Madill4928b7c2017-06-20 12:57:39 -0400140gl::Error VertexArrayGL::syncDrawState(const gl::Context *context,
141 const gl::AttributesMask &activeAttributesMask,
Jamie Madill0b9e9032015-08-17 11:51:52 +0000142 GLint first,
143 GLsizei count,
144 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400145 const void *indices,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400146 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400147 bool primitiveRestartEnabled,
Jamie Madill876429b2017-04-20 15:46:24 -0400148 const void **outIndices) const
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400149{
Shao80957d92017-02-20 21:25:59 +0800150 // Check if any attributes need to be streamed, determines if the index range needs to be
151 // computed
Jamie Madillbcef3222018-04-13 15:19:11 -0400152 const gl::AttributesMask &needsStreamingAttribs =
Jamie Madilldc358af2018-07-31 11:22:13 -0400153 context->getStateCache().getActiveClientAttribsMask();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400154
Shao80957d92017-02-20 21:25:59 +0800155 // Determine if an index buffer needs to be streamed and the range of vertices that need to be
156 // copied
Geoff Lang3edfe032015-09-04 16:38:24 -0400157 IndexRange indexRange;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400158 if (type != GL_NONE)
Geoff Langba4c4a82015-02-24 12:38:46 -0500159 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400160 ANGLE_TRY(syncIndexData(context, count, type, indices, primitiveRestartEnabled,
Jamie Madillbcef3222018-04-13 15:19:11 -0400161 needsStreamingAttribs.any(), &indexRange, outIndices));
Geoff Lang7c82bc42015-03-09 16:18:08 -0400162 }
163 else
164 {
Corentin Wallez2c34a4b2015-08-25 16:26:02 -0400165 // Not an indexed call, set the range to [first, first + count - 1]
Geoff Lang7c82bc42015-03-09 16:18:08 -0400166 indexRange.start = first;
Shao80957d92017-02-20 21:25:59 +0800167 indexRange.end = first + count - 1;
Geoff Langba4c4a82015-02-24 12:38:46 -0500168 }
169
Jamie Madillbcef3222018-04-13 15:19:11 -0400170 if (needsStreamingAttribs.any())
Geoff Langba4c4a82015-02-24 12:38:46 -0500171 {
Jamie Madillbcef3222018-04-13 15:19:11 -0400172 ANGLE_TRY(streamAttributes(needsStreamingAttribs, instanceCount, indexRange));
Geoff Lang7c82bc42015-03-09 16:18:08 -0400173 }
174
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500175 return gl::NoError();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400176}
177
Jamie Madill4928b7c2017-06-20 12:57:39 -0400178gl::Error VertexArrayGL::syncIndexData(const gl::Context *context,
179 GLsizei count,
Jiajia Qind9671222016-11-29 16:30:31 +0800180 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 Madill492f58e2017-10-09 19:41:33 -0400189 gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer().get();
Jamie Madill8e344942015-07-09 14:22:07 -0400190
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 {
Jiajia Qin47474142017-12-29 13:41:00 +0800194 ASSERT(elementArrayBuffer == mAppliedElementArrayBuffer.get());
Geoff Lang7c82bc42015-03-09 16:18:08 -0400195 // Only compute the index range if the attributes also need to be streamed
196 if (attributesNeedStreaming)
197 {
198 ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices);
Jamie Madill492f58e2017-10-09 19:41:33 -0400199 Error error = mState.getElementArrayBuffer()->getIndexRange(
Jamie Madill33510102017-09-20 10:39:18 -0400200 context, type, elementArrayBufferOffset, count, primitiveRestartEnabled,
201 outIndexRange);
Geoff Lang520c4ae2015-05-05 13:12:36 -0400202 if (error.isError())
Geoff Lang7c82bc42015-03-09 16:18:08 -0400203 {
Geoff Lang520c4ae2015-05-05 13:12:36 -0400204 return error;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400205 }
206 }
207
Shao80957d92017-02-20 21:25:59 +0800208 // Indices serves as an offset into the index buffer in this case, use the same value for
209 // the draw call
Geoff Lang7c82bc42015-03-09 16:18:08 -0400210 *outIndices = indices;
211 }
212 else
213 {
214 // Need to stream the index buffer
215 // TODO: if GLES, nothing needs to be streamed
216
217 // Only compute the index range if the attributes also need to be streamed
218 if (attributesNeedStreaming)
219 {
Geoff Lang3edfe032015-09-04 16:38:24 -0400220 *outIndexRange = ComputeIndexRange(type, indices, count, primitiveRestartEnabled);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400221 }
222
223 // Allocate the streaming element array buffer
224 if (mStreamingElementArrayBuffer == 0)
225 {
226 mFunctions->genBuffers(1, &mStreamingElementArrayBuffer);
227 mStreamingElementArrayBufferSize = 0;
228 }
229
Geoff Lang5f3047c2018-02-14 14:39:12 -0500230 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
231
Corentin Wallez336129f2017-10-17 15:55:40 -0400232 mStateManager->bindBuffer(gl::BufferBinding::ElementArray, 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 Madillbcef3222018-04-13 15:19:11 -0400260void VertexArrayGL::computeStreamingAttributeSizes(const gl::AttributesMask &attribsToStream,
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
Jamie Madillbcef3222018-04-13 15:19:11 -0400269 ASSERT(attribsToStream.any());
Jamie Madill0b9e9032015-08-17 11:51:52 +0000270
Jamie Madill492f58e2017-10-09 19:41:33 -0400271 const auto &attribs = mState.getVertexAttributes();
272 const auto &bindings = mState.getVertexBindings();
Jamie Madill6de51852017-04-12 09:53:01 -0400273
Jamie Madill6de51852017-04-12 09:53:01 -0400274 for (auto idx : attribsToStream)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000275 {
Shao80957d92017-02-20 21:25:59 +0800276 const auto &attrib = attribs[idx];
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800277 const auto &binding = bindings[attrib.bindingIndex];
Jamie Madill0b9e9032015-08-17 11:51:52 +0000278
Jamie Madill0b9e9032015-08-17 11:51:52 +0000279 // If streaming is going to be required, compute the size of the required buffer
280 // and how much slack space at the beginning of the buffer will be required by determining
281 // the attribute with the largest data size.
282 size_t typeSize = ComputeVertexAttributeTypeSize(attrib);
Martin Radev553590a2017-07-31 16:40:39 +0300283 GLuint adjustedDivisor = GetAdjustedDivisor(mAppliedNumViews, binding.getDivisor());
284 *outStreamingDataSize +=
285 typeSize * ComputeVertexBindingElementCount(adjustedDivisor, indexRange.vertexCount(),
286 instanceCount);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000287 *outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
288 }
289}
290
Jamie Madillbcef3222018-04-13 15:19:11 -0400291gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &attribsToStream,
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400292 GLsizei instanceCount,
Geoff Lang3edfe032015-09-04 16:38:24 -0400293 const gl::IndexRange &indexRange) const
Jamie Madill0b9e9032015-08-17 11:51:52 +0000294{
295 // Sync the vertex attribute state and track what data needs to be streamed
296 size_t streamingDataSize = 0;
297 size_t maxAttributeDataSize = 0;
298
Jamie Madillbcef3222018-04-13 15:19:11 -0400299 computeStreamingAttributeSizes(attribsToStream, instanceCount, indexRange, &streamingDataSize,
300 &maxAttributeDataSize);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000301
302 if (streamingDataSize == 0)
303 {
He Yunchaoacd18982017-01-04 10:46:42 +0800304 return gl::NoError();
Jamie Madill0b9e9032015-08-17 11:51:52 +0000305 }
306
Geoff Lang7c82bc42015-03-09 16:18:08 -0400307 if (mStreamingArrayBuffer == 0)
308 {
309 mFunctions->genBuffers(1, &mStreamingArrayBuffer);
310 mStreamingArrayBufferSize = 0;
311 }
312
Shao80957d92017-02-20 21:25:59 +0800313 // If first is greater than zero, a slack space needs to be left at the beginning of the buffer
314 // so that the same 'first' argument can be passed into the draw call.
315 const size_t bufferEmptySpace = maxAttributeDataSize * indexRange.start;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400316 const size_t requiredBufferSize = streamingDataSize + bufferEmptySpace;
317
Corentin Wallez336129f2017-10-17 15:55:40 -0400318 mStateManager->bindBuffer(gl::BufferBinding::Array, mStreamingArrayBuffer);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400319 if (requiredBufferSize > mStreamingArrayBufferSize)
320 {
321 mFunctions->bufferData(GL_ARRAY_BUFFER, requiredBufferSize, nullptr, GL_DYNAMIC_DRAW);
322 mStreamingArrayBufferSize = requiredBufferSize;
323 }
324
Geoff Lang5f3047c2018-02-14 14:39:12 -0500325 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
326
Geoff Lang7c82bc42015-03-09 16:18:08 -0400327 // Unmapping a buffer can return GL_FALSE to indicate that the system has corrupted the data
Shao80957d92017-02-20 21:25:59 +0800328 // somehow (such as by a screen change), retry writing the data a few times and return
329 // OUT_OF_MEMORY if that fails.
330 GLboolean unmapResult = GL_FALSE;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400331 size_t unmapRetryAttempts = 5;
332 while (unmapResult != GL_TRUE && --unmapRetryAttempts > 0)
333 {
Geoff Langb2ebb5e2016-06-08 18:17:55 +0000334 uint8_t *bufferPointer = MapBufferRangeWithFallback(mFunctions, GL_ARRAY_BUFFER, 0,
335 requiredBufferSize, GL_MAP_WRITE_BIT);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400336 size_t curBufferOffset = bufferEmptySpace;
337
Jamie Madill492f58e2017-10-09 19:41:33 -0400338 const auto &attribs = mState.getVertexAttributes();
339 const auto &bindings = mState.getVertexBindings();
Jamie Madill6de51852017-04-12 09:53:01 -0400340
Jamie Madill6de51852017-04-12 09:53:01 -0400341 for (auto idx : attribsToStream)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400342 {
Shao80957d92017-02-20 21:25:59 +0800343 const auto &attrib = attribs[idx];
Shaodde78e82017-05-22 14:13:27 +0800344 ASSERT(IsVertexAttribPointerSupported(idx, attrib));
345
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800346 const auto &binding = bindings[attrib.bindingIndex];
Geoff Lang7c82bc42015-03-09 16:18:08 -0400347
Martin Radev553590a2017-07-31 16:40:39 +0300348 GLuint adjustedDivisor = GetAdjustedDivisor(mAppliedNumViews, binding.getDivisor());
349 const size_t streamedVertexCount = ComputeVertexBindingElementCount(
350 adjustedDivisor, indexRange.vertexCount(), instanceCount);
Geoff Lang3cf12ce2015-08-27 14:40:48 -0400351
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800352 const size_t sourceStride = ComputeVertexAttributeStride(attrib, binding);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000353 const size_t destStride = ComputeVertexAttributeTypeSize(attrib);
354
Geoff Lang38a24a92017-02-15 13:53:06 -0500355 // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing
356 // a non-instanced draw call
Martin Radev553590a2017-07-31 16:40:39 +0300357 const size_t firstIndex = adjustedDivisor == 0 ? indexRange.start : 0;
Geoff Lang38a24a92017-02-15 13:53:06 -0500358
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800359 // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state.
360 // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt
Rafael Cintron05a449a2018-06-20 18:08:04 -0700361 const uint8_t *inputPointer = static_cast<const uint8_t *>(attrib.pointer);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000362
363 // Pack the data when copying it, user could have supplied a very large stride that
364 // would cause the buffer to be much larger than needed.
365 if (destStride == sourceStride)
Jamie Madill8e344942015-07-09 14:22:07 -0400366 {
Jamie Madill0b9e9032015-08-17 11:51:52 +0000367 // Can copy in one go, the data is packed
Geoff Lang38a24a92017-02-15 13:53:06 -0500368 memcpy(bufferPointer + curBufferOffset, inputPointer + (sourceStride * firstIndex),
Jamie Madill0b9e9032015-08-17 11:51:52 +0000369 destStride * streamedVertexCount);
Jamie Madill6d51c702015-08-14 10:38:10 -0400370 }
Jamie Madill0b9e9032015-08-17 11:51:52 +0000371 else
372 {
373 // Copy each vertex individually
Geoff Lang6b10ddb2015-09-02 15:55:10 -0400374 for (size_t vertexIdx = 0; vertexIdx < streamedVertexCount; vertexIdx++)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000375 {
Shao80957d92017-02-20 21:25:59 +0800376 uint8_t *out = bufferPointer + curBufferOffset + (destStride * vertexIdx);
Geoff Lang38a24a92017-02-15 13:53:06 -0500377 const uint8_t *in = inputPointer + sourceStride * (vertexIdx + firstIndex);
Corentin Wallez4d5362d2015-08-25 11:25:14 -0400378 memcpy(out, in, destStride);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000379 }
380 }
381
382 // Compute where the 0-index vertex would be.
Geoff Lang38a24a92017-02-15 13:53:06 -0500383 const size_t vertexStartOffset = curBufferOffset - (firstIndex * destStride);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000384
Shaodf682a82017-03-31 15:13:21 +0800385 callVertexAttribPointer(static_cast<GLuint>(idx), attrib,
386 static_cast<GLsizei>(destStride),
387 static_cast<GLintptr>(vertexStartOffset));
Jamie Madill0b9e9032015-08-17 11:51:52 +0000388
389 curBufferOffset += destStride * streamedVertexCount;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400390 }
391
392 unmapResult = mFunctions->unmapBuffer(GL_ARRAY_BUFFER);
393 }
394
395 if (unmapResult != GL_TRUE)
396 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500397 return gl::OutOfMemory() << "Failed to unmap the client data streaming buffer.";
Geoff Lang7c82bc42015-03-09 16:18:08 -0400398 }
399
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500400 return gl::NoError();
Geoff Langba4c4a82015-02-24 12:38:46 -0500401}
402
403GLuint VertexArrayGL::getVertexArrayID() const
404{
405 return mVertexArrayID;
Geoff Langf9a6f082015-01-22 13:32:49 -0500406}
407
Geoff Lang294cad92015-05-26 15:11:23 -0400408GLuint VertexArrayGL::getAppliedElementArrayBufferID() const
409{
Jamie Madill77a90c22015-08-11 16:33:17 -0400410 if (mAppliedElementArrayBuffer.get() == nullptr)
411 {
412 return mStreamingElementArrayBuffer;
413 }
414
415 return GetImplAs<BufferGL>(mAppliedElementArrayBuffer.get())->getBufferID();
Geoff Lang294cad92015-05-26 15:11:23 -0400416}
417
Jamie Madill0b9e9032015-08-17 11:51:52 +0000418void VertexArrayGL::updateAttribEnabled(size_t attribIndex)
419{
Jamie Madill492f58e2017-10-09 19:41:33 -0400420 const bool enabled = mState.getVertexAttribute(attribIndex).enabled;
Shaodf682a82017-03-31 15:13:21 +0800421 if (mAppliedAttributes[attribIndex].enabled == enabled)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000422 {
423 return;
424 }
425
Shaodf682a82017-03-31 15:13:21 +0800426 if (enabled)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000427 {
428 mFunctions->enableVertexAttribArray(static_cast<GLuint>(attribIndex));
429 }
430 else
431 {
432 mFunctions->disableVertexAttribArray(static_cast<GLuint>(attribIndex));
433 }
Shaodf682a82017-03-31 15:13:21 +0800434
435 mAppliedAttributes[attribIndex].enabled = enabled;
Jamie Madill0b9e9032015-08-17 11:51:52 +0000436}
437
Jamie Madill4928b7c2017-06-20 12:57:39 -0400438void VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attribIndex)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000439{
Jamie Madill492f58e2017-10-09 19:41:33 -0400440 const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800441
Shaodde78e82017-05-22 14:13:27 +0800442 // According to SPEC, VertexAttribPointer should update the binding indexed attribIndex instead
443 // of the binding indexed attrib.bindingIndex (unless attribIndex == attrib.bindingIndex).
Jamie Madill492f58e2017-10-09 19:41:33 -0400444 const VertexBinding &binding = mState.getVertexBinding(attribIndex);
Shaodf682a82017-03-31 15:13:21 +0800445
Shaodde78e82017-05-22 14:13:27 +0800446 // Early return when the vertex attribute isn't using a buffer object:
447 // - If we need to stream, defer the attribPointer to the draw call.
448 // - Skip the attribute that is disabled and uses a client memory pointer.
449 // - Skip the attribute whose buffer is detached by BindVertexBuffer. Since it cannot have a
450 // client memory pointer either, it must be disabled and shouldn't affect the draw.
Jamie Madillbcef3222018-04-13 15:19:11 -0400451 const auto &bindingBuffer = binding.getBuffer();
Shaodde78e82017-05-22 14:13:27 +0800452 const Buffer *arrayBuffer = bindingBuffer.get();
453 if (arrayBuffer == nullptr)
454 {
455 // Mark the applied binding isn't using a buffer by setting its buffer to nullptr so that if
456 // it starts to use a buffer later, there is no chance that the caching will skip it.
James Darpiniane8a93c62018-01-04 18:02:24 -0800457 mAppliedBindings[attribIndex].setBuffer(context, nullptr, false);
Shaodde78e82017-05-22 14:13:27 +0800458 return;
459 }
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800460
Shaodf682a82017-03-31 15:13:21 +0800461 // We do not need to compare attrib.pointer because when we use a different client memory
462 // pointer, we don't need to update mAttributesNeedStreaming by binding.buffer and we won't
463 // update attribPointer in this function.
Shaodde78e82017-05-22 14:13:27 +0800464 if ((SameVertexAttribFormat(mAppliedAttributes[attribIndex], attrib)) &&
465 (mAppliedAttributes[attribIndex].bindingIndex == attrib.bindingIndex) &&
466 (SameVertexBuffer(mAppliedBindings[attribIndex], binding)))
Jamie Madill0b9e9032015-08-17 11:51:52 +0000467 {
468 return;
469 }
470
Shao4181bc92017-03-17 14:55:25 +0800471 // Since ANGLE always uses a non-zero VAO, we cannot use a client memory pointer on it:
472 // [OpenGL ES 3.0.2] Section 2.8 page 24:
473 // An INVALID_OPERATION error is generated when a non-zero vertex array object is bound,
474 // zero is bound to the ARRAY_BUFFER buffer object binding point, and the pointer argument
475 // is not NULL.
Shaodf682a82017-03-31 15:13:21 +0800476
Shao4181bc92017-03-17 14:55:25 +0800477 const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
Corentin Wallez336129f2017-10-17 15:55:40 -0400478 mStateManager->bindBuffer(gl::BufferBinding::Array, arrayBufferGL->getBufferID());
Martin Radevdd5f27e2017-06-07 10:17:09 +0300479 callVertexAttribPointer(static_cast<GLuint>(attribIndex), attrib, binding.getStride(),
480 binding.getOffset());
Shaodf682a82017-03-31 15:13:21 +0800481
Shaodde78e82017-05-22 14:13:27 +0800482 mAppliedAttributes[attribIndex].size = attrib.size;
483 mAppliedAttributes[attribIndex].type = attrib.type;
484 mAppliedAttributes[attribIndex].normalized = attrib.normalized;
485 mAppliedAttributes[attribIndex].pureInteger = attrib.pureInteger;
Shaodf682a82017-03-31 15:13:21 +0800486
Shaodde78e82017-05-22 14:13:27 +0800487 // After VertexAttribPointer, attrib.relativeOffset is set to 0 and attrib.bindingIndex is set
488 // to attribIndex in driver. If attrib.relativeOffset != 0 or attrib.bindingIndex !=
489 // attribIndex, they should be set in updateAttribFormat and updateAttribBinding. The cache
490 // should be consistent with driver so that we won't miss anything.
491 mAppliedAttributes[attribIndex].relativeOffset = 0;
492 mAppliedAttributes[attribIndex].bindingIndex = static_cast<GLuint>(attribIndex);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800493
Shaodde78e82017-05-22 14:13:27 +0800494 mAppliedBindings[attribIndex].setStride(binding.getStride());
495 mAppliedBindings[attribIndex].setOffset(binding.getOffset());
James Darpiniane8a93c62018-01-04 18:02:24 -0800496 mAppliedBindings[attribIndex].setBuffer(context, binding.getBuffer().get(), false);
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800497}
498
Shaodf682a82017-03-31 15:13:21 +0800499void VertexArrayGL::callVertexAttribPointer(GLuint attribIndex,
500 const VertexAttribute &attrib,
501 GLsizei stride,
502 GLintptr offset) const
503{
504 const GLvoid *pointer = reinterpret_cast<const GLvoid *>(offset);
505 if (attrib.pureInteger)
506 {
507 ASSERT(!attrib.normalized);
508 mFunctions->vertexAttribIPointer(attribIndex, attrib.size, attrib.type, stride, pointer);
509 }
510 else
511 {
512 mFunctions->vertexAttribPointer(attribIndex, attrib.size, attrib.type, attrib.normalized,
513 stride, pointer);
514 }
515}
516
Shaodde78e82017-05-22 14:13:27 +0800517bool VertexArrayGL::supportVertexAttribBinding() const
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800518{
Shaodde78e82017-05-22 14:13:27 +0800519 ASSERT(mFunctions);
520 return (mFunctions->vertexAttribBinding != nullptr);
521}
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800522
Shaodde78e82017-05-22 14:13:27 +0800523void VertexArrayGL::updateAttribFormat(size_t attribIndex)
524{
525 ASSERT(supportVertexAttribBinding());
526
Jamie Madill492f58e2017-10-09 19:41:33 -0400527 const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
Shaodde78e82017-05-22 14:13:27 +0800528 if (SameVertexAttribFormat(mAppliedAttributes[attribIndex], attrib))
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800529 {
Shaodf682a82017-03-31 15:13:21 +0800530 return;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800531 }
Shaodf682a82017-03-31 15:13:21 +0800532
Shaodde78e82017-05-22 14:13:27 +0800533 if (attrib.pureInteger)
534 {
535 ASSERT(!attrib.normalized);
536 mFunctions->vertexAttribIFormat(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
537 attrib.relativeOffset);
538 }
539 else
540 {
541 mFunctions->vertexAttribFormat(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
542 attrib.normalized, attrib.relativeOffset);
543 }
544
545 mAppliedAttributes[attribIndex].size = attrib.size;
546 mAppliedAttributes[attribIndex].type = attrib.type;
547 mAppliedAttributes[attribIndex].normalized = attrib.normalized;
548 mAppliedAttributes[attribIndex].pureInteger = attrib.pureInteger;
549 mAppliedAttributes[attribIndex].relativeOffset = attrib.relativeOffset;
550}
551
552void VertexArrayGL::updateAttribBinding(size_t attribIndex)
553{
554 ASSERT(supportVertexAttribBinding());
555
Jamie Madill492f58e2017-10-09 19:41:33 -0400556 GLuint bindingIndex = mState.getVertexAttribute(attribIndex).bindingIndex;
Shaodde78e82017-05-22 14:13:27 +0800557 if (mAppliedAttributes[attribIndex].bindingIndex == bindingIndex)
558 {
559 return;
560 }
561
562 mFunctions->vertexAttribBinding(static_cast<GLuint>(attribIndex), bindingIndex);
Shaodf682a82017-03-31 15:13:21 +0800563
564 mAppliedAttributes[attribIndex].bindingIndex = bindingIndex;
Shaodde78e82017-05-22 14:13:27 +0800565}
566
567void VertexArrayGL::updateBindingBuffer(const gl::Context *context, size_t bindingIndex)
568{
569 ASSERT(supportVertexAttribBinding());
570
Jamie Madill492f58e2017-10-09 19:41:33 -0400571 const VertexBinding &binding = mState.getVertexBinding(bindingIndex);
Shaodde78e82017-05-22 14:13:27 +0800572 if (SameVertexBuffer(mAppliedBindings[bindingIndex], binding))
573 {
574 return;
575 }
576
577 const Buffer *arrayBuffer = binding.getBuffer().get();
578 GLuint bufferId = 0;
579 if (arrayBuffer != nullptr)
580 {
581 bufferId = GetImplAs<BufferGL>(arrayBuffer)->getBufferID();
582 }
583
584 mFunctions->bindVertexBuffer(static_cast<GLuint>(bindingIndex), bufferId, binding.getOffset(),
585 binding.getStride());
586
587 mAppliedBindings[bindingIndex].setStride(binding.getStride());
588 mAppliedBindings[bindingIndex].setOffset(binding.getOffset());
James Darpiniane8a93c62018-01-04 18:02:24 -0800589 mAppliedBindings[bindingIndex].setBuffer(context, binding.getBuffer().get(), false);
Shaodde78e82017-05-22 14:13:27 +0800590}
591
592void VertexArrayGL::updateBindingDivisor(size_t bindingIndex)
593{
Martin Radev553590a2017-07-31 16:40:39 +0300594 GLuint adjustedDivisor =
Jamie Madill492f58e2017-10-09 19:41:33 -0400595 GetAdjustedDivisor(mAppliedNumViews, mState.getVertexBinding(bindingIndex).getDivisor());
Martin Radev553590a2017-07-31 16:40:39 +0300596 if (mAppliedBindings[bindingIndex].getDivisor() == adjustedDivisor)
Shaodde78e82017-05-22 14:13:27 +0800597 {
598 return;
599 }
600
601 if (supportVertexAttribBinding())
602 {
Martin Radev553590a2017-07-31 16:40:39 +0300603 mFunctions->vertexBindingDivisor(static_cast<GLuint>(bindingIndex), adjustedDivisor);
Shaodde78e82017-05-22 14:13:27 +0800604 }
605 else
606 {
607 // We can only use VertexAttribDivisor on platforms that don't support Vertex Attrib
608 // Binding.
Martin Radev553590a2017-07-31 16:40:39 +0300609 mFunctions->vertexAttribDivisor(static_cast<GLuint>(bindingIndex), adjustedDivisor);
Shaodde78e82017-05-22 14:13:27 +0800610 }
611
Martin Radev553590a2017-07-31 16:40:39 +0300612 mAppliedBindings[bindingIndex].setDivisor(adjustedDivisor);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000613}
614
Jamie Madille858cb12018-03-27 09:44:32 -0400615void VertexArrayGL::syncDirtyAttrib(const gl::Context *context,
616 size_t attribIndex,
617 const gl::VertexArray::DirtyAttribBits &dirtyAttribBits)
618{
619 ASSERT(dirtyAttribBits.any());
620
621 for (size_t dirtyBit : dirtyAttribBits)
622 {
623 switch (dirtyBit)
624 {
625 case VertexArray::DIRTY_ATTRIB_ENABLED:
626 updateAttribEnabled(attribIndex);
627 break;
628
629 case VertexArray::DIRTY_ATTRIB_POINTER:
630 updateAttribPointer(context, attribIndex);
631 break;
632
633 case VertexArray::DIRTY_ATTRIB_FORMAT:
634 ASSERT(supportVertexAttribBinding());
635 updateAttribFormat(attribIndex);
636 break;
637
638 case VertexArray::DIRTY_ATTRIB_BINDING:
639 ASSERT(supportVertexAttribBinding());
640 updateAttribBinding(attribIndex);
641 break;
642
643 default:
644 UNREACHABLE();
645 break;
646 }
647 }
648}
649
650void VertexArrayGL::syncDirtyBinding(const gl::Context *context,
651 size_t bindingIndex,
652 const gl::VertexArray::DirtyBindingBits &dirtyBindingBits)
653{
Jamie Madill02c9c042018-04-17 13:43:48 -0400654 // Dependent state changes in buffers can trigger updates with no dirty bits set.
Jamie Madille858cb12018-03-27 09:44:32 -0400655
656 for (size_t dirtyBit : dirtyBindingBits)
657 {
658 switch (dirtyBit)
659 {
660 case VertexArray::DIRTY_BINDING_BUFFER:
661 ASSERT(supportVertexAttribBinding());
662 updateBindingBuffer(context, bindingIndex);
663 break;
664
665 case VertexArray::DIRTY_BINDING_DIVISOR:
666 updateBindingDivisor(bindingIndex);
667 break;
668
669 default:
670 UNREACHABLE();
671 break;
672 }
673 }
674}
675
Jamie Madilla56467e2018-04-11 16:19:41 -0400676#define ANGLE_DIRTY_ATTRIB_FUNC(INDEX) \
677 case VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX: \
678 syncDirtyAttrib(context, INDEX, attribBits[INDEX]); \
679 break;
680
681#define ANGLE_DIRTY_BINDING_FUNC(INDEX) \
682 case VertexArray::DIRTY_BIT_BINDING_0 + INDEX: \
683 syncDirtyBinding(context, INDEX, bindingBits[INDEX]); \
684 break;
685
686#define ANGLE_DIRTY_BUFFER_DATA_FUNC(INDEX) \
687 case VertexArray::DIRTY_BIT_BUFFER_DATA_0 + INDEX: \
688 break;
689
Frank Henigman0af5b862018-03-27 20:19:33 -0400690gl::Error VertexArrayGL::syncState(const gl::Context *context,
691 const VertexArray::DirtyBits &dirtyBits,
692 const gl::VertexArray::DirtyAttribBitsArray &attribBits,
693 const gl::VertexArray::DirtyBindingBitsArray &bindingBits)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000694{
Shaodf682a82017-03-31 15:13:21 +0800695 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
696
Jamie Madill6de51852017-04-12 09:53:01 -0400697 for (size_t dirtyBit : dirtyBits)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000698 {
Jamie Madille858cb12018-03-27 09:44:32 -0400699 switch (dirtyBit)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000700 {
Jamie Madille858cb12018-03-27 09:44:32 -0400701 case VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER:
702 updateElementArrayBufferBinding(context);
703 break;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800704
Jamie Madill09463932018-04-04 05:26:59 -0400705 case VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA:
706 break;
707
Jamie Madilla56467e2018-04-11 16:19:41 -0400708 ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_ATTRIB_FUNC);
709 ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_BINDING_FUNC);
710 ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_BUFFER_DATA_FUNC);
711
Jamie Madille858cb12018-03-27 09:44:32 -0400712 default:
Jamie Madilla56467e2018-04-11 16:19:41 -0400713 UNREACHABLE();
Jamie Madille858cb12018-03-27 09:44:32 -0400714 break;
Jamie Madill0b9e9032015-08-17 11:51:52 +0000715 }
Jamie Madill0b9e9032015-08-17 11:51:52 +0000716 }
Frank Henigman0af5b862018-03-27 20:19:33 -0400717
718 return gl::NoError();
Jamie Madill0b9e9032015-08-17 11:51:52 +0000719}
720
Martin Radev553590a2017-07-31 16:40:39 +0300721void VertexArrayGL::applyNumViewsToDivisor(int numViews)
722{
723 if (numViews != mAppliedNumViews)
724 {
725 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
726 mAppliedNumViews = numViews;
727 for (size_t index = 0u; index < mAppliedBindings.size(); ++index)
728 {
729 updateBindingDivisor(index);
730 }
731 }
732}
733
Jamie Madill09463932018-04-04 05:26:59 -0400734} // namespace rx