1 //
2 // Copyright 2014 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 // Implementation of the state classes for mananging GLES 3.1 Vertex Array Objects.
7 //
8
9 #include "libANGLE/VertexAttribute.h"
10
11 namespace gl
12 {
13
14 // [OpenGL ES 3.1] (November 3, 2016) Section 20 Page 361
15 // Table 20.2: Vertex Array Object State
VertexBinding()16 VertexBinding::VertexBinding() : VertexBinding(0) {}
17
VertexBinding(GLuint boundAttribute)18 VertexBinding::VertexBinding(GLuint boundAttribute) : mStride(16u), mDivisor(0), mOffset(0)
19 {
20 mBoundAttributesMask.set(boundAttribute);
21 }
22
VertexBinding(VertexBinding && binding)23 VertexBinding::VertexBinding(VertexBinding &&binding)
24 {
25 *this = std::move(binding);
26 }
27
~VertexBinding()28 VertexBinding::~VertexBinding() {}
29
operator =(VertexBinding && binding)30 VertexBinding &VertexBinding::operator=(VertexBinding &&binding)
31 {
32 if (this != &binding)
33 {
34 mStride = binding.mStride;
35 mDivisor = binding.mDivisor;
36 mOffset = binding.mOffset;
37 mBoundAttributesMask = binding.mBoundAttributesMask;
38 std::swap(binding.mBuffer, mBuffer);
39 }
40 return *this;
41 }
42
onContainerBindingChanged(const Context * context,int incr) const43 void VertexBinding::onContainerBindingChanged(const Context *context, int incr) const
44 {
45 if (mBuffer.get())
46 mBuffer->onNonTFBindingChanged(incr);
47 }
48
VertexAttribute(GLuint bindingIndex)49 VertexAttribute::VertexAttribute(GLuint bindingIndex)
50 : enabled(false),
51 format(&angle::Format::Get(angle::FormatID::R32G32B32A32_FLOAT)),
52 pointer(nullptr),
53 relativeOffset(0),
54 vertexAttribArrayStride(0),
55 bindingIndex(bindingIndex),
56 mCachedElementLimit(0)
57 {}
58
VertexAttribute(VertexAttribute && attrib)59 VertexAttribute::VertexAttribute(VertexAttribute &&attrib)
60 : enabled(attrib.enabled),
61 format(attrib.format),
62 pointer(attrib.pointer),
63 relativeOffset(attrib.relativeOffset),
64 vertexAttribArrayStride(attrib.vertexAttribArrayStride),
65 bindingIndex(attrib.bindingIndex),
66 mCachedElementLimit(attrib.mCachedElementLimit)
67 {}
68
operator =(VertexAttribute && attrib)69 VertexAttribute &VertexAttribute::operator=(VertexAttribute &&attrib)
70 {
71 if (this != &attrib)
72 {
73 enabled = attrib.enabled;
74 format = attrib.format;
75 pointer = attrib.pointer;
76 relativeOffset = attrib.relativeOffset;
77 vertexAttribArrayStride = attrib.vertexAttribArrayStride;
78 bindingIndex = attrib.bindingIndex;
79 mCachedElementLimit = attrib.mCachedElementLimit;
80 }
81 return *this;
82 }
83
updateCachedElementLimit(const VertexBinding & binding)84 void VertexAttribute::updateCachedElementLimit(const VertexBinding &binding)
85 {
86 Buffer *buffer = binding.getBuffer().get();
87 if (!buffer)
88 {
89 mCachedElementLimit = 0;
90 return;
91 }
92
93 angle::CheckedNumeric<GLint64> bufferSize(buffer->getSize());
94 angle::CheckedNumeric<GLint64> bufferOffset(binding.getOffset());
95 angle::CheckedNumeric<GLint64> attribOffset(relativeOffset);
96 angle::CheckedNumeric<GLint64> attribSize(ComputeVertexAttributeTypeSize(*this));
97
98 // (buffer.size - buffer.offset - attrib.relativeOffset - attrib.size) / binding.stride
99 angle::CheckedNumeric<GLint64> elementLimit =
100 (bufferSize - bufferOffset - attribOffset - attribSize);
101
102 // Use the special integer overflow value if there was a math error.
103 if (!elementLimit.IsValid())
104 {
105 static_assert(kIntegerOverflow < 0, "Unexpected value");
106 mCachedElementLimit = kIntegerOverflow;
107 return;
108 }
109
110 mCachedElementLimit = elementLimit.ValueOrDie();
111 if (mCachedElementLimit < 0)
112 {
113 return;
114 }
115
116 if (binding.getStride() == 0)
117 {
118 // Special case for a zero stride. If we can fit one vertex we can fit infinite vertices.
119 mCachedElementLimit = std::numeric_limits<GLint64>::max();
120 return;
121 }
122
123 angle::CheckedNumeric<GLint64> bindingStride(binding.getStride());
124 elementLimit /= bindingStride;
125
126 if (binding.getDivisor() > 0)
127 {
128 // For instanced draws, the element count is floor(instanceCount - 1) / binding.divisor.
129 angle::CheckedNumeric<GLint64> bindingDivisor(binding.getDivisor());
130 elementLimit *= bindingDivisor;
131
132 // We account for the floor() part rounding by adding a rounding constant.
133 elementLimit += bindingDivisor - 1;
134 }
135
136 mCachedElementLimit = elementLimit.ValueOrDefault(kIntegerOverflow);
137 }
138
ComputeVertexAttributeStride(const VertexAttribute & attrib,const VertexBinding & binding)139 size_t ComputeVertexAttributeStride(const VertexAttribute &attrib, const VertexBinding &binding)
140 {
141 // In ES 3.1, VertexAttribPointer will store the type size in the binding stride.
142 // Hence, rendering always uses the binding's stride.
143 return attrib.enabled ? binding.getStride() : 16u;
144 }
145
146 // Warning: you should ensure binding really matches attrib.bindingIndex before using this function.
ComputeVertexAttributeOffset(const VertexAttribute & attrib,const VertexBinding & binding)147 GLintptr ComputeVertexAttributeOffset(const VertexAttribute &attrib, const VertexBinding &binding)
148 {
149 return attrib.relativeOffset + binding.getOffset();
150 }
151
ComputeVertexBindingElementCount(GLuint divisor,size_t drawCount,size_t instanceCount)152 size_t ComputeVertexBindingElementCount(GLuint divisor, size_t drawCount, size_t instanceCount)
153 {
154 // For instanced rendering, we draw "instanceDrawCount" sets of "vertexDrawCount" vertices.
155 //
156 // A vertex attribute with a positive divisor loads one instanced vertex for every set of
157 // non-instanced vertices, and the instanced vertex index advances once every "mDivisor"
158 // instances.
159 if (instanceCount > 0 && divisor > 0)
160 {
161 // When instanceDrawCount is not a multiple attrib.divisor, the division must round up.
162 // For instance, with 5 non-instanced vertices and a divisor equal to 3, we need 2 instanced
163 // vertices.
164 return (instanceCount + divisor - 1u) / divisor;
165 }
166
167 return drawCount;
168 }
169
170 } // namespace gl
171