xref: /aosp_15_r20/external/angle/src/libANGLE/VertexAttribute.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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> bufferOffset(binding.getOffset());
94     angle::CheckedNumeric<GLint64> bufferSize(buffer->getSize());
95     angle::CheckedNumeric<GLint64> attribOffset(relativeOffset);
96     angle::CheckedNumeric<GLint64> attribSize(ComputeVertexAttributeTypeSize(*this));
97 
98     // Disallow referencing data before the start of the buffer with negative offsets
99     angle::CheckedNumeric<GLint64> offset = bufferOffset + attribOffset;
100     if (!offset.IsValid() || offset.ValueOrDie() < 0)
101     {
102         mCachedElementLimit = kIntegerOverflow;
103         return;
104     }
105 
106     // The element limit is (exclusive) end of the accessible range for the vertex.  For example, if
107     // N attributes can be accessed, the following calculates N.
108     //
109     // (buffer.size - buffer.offset - attrib.relativeOffset - attrib.size) / binding.stride + 1
110     angle::CheckedNumeric<GLint64> elementLimit = (bufferSize - offset - attribSize);
111 
112     // Use the special integer overflow value if there was a math error.
113     if (!elementLimit.IsValid())
114     {
115         static_assert(kIntegerOverflow < 0, "Unexpected value");
116         mCachedElementLimit = kIntegerOverflow;
117         return;
118     }
119 
120     mCachedElementLimit = elementLimit.ValueOrDie();
121     if (mCachedElementLimit < 0)
122     {
123         return;
124     }
125 
126     if (binding.getStride() == 0)
127     {
128         // Special case for a zero stride. If we can fit one vertex we can fit infinite vertices.
129         mCachedElementLimit = std::numeric_limits<GLint64>::max();
130         return;
131     }
132 
133     mCachedElementLimit /= binding.getStride();
134     ++mCachedElementLimit;
135 }
136 
ComputeVertexAttributeStride(const VertexAttribute & attrib,const VertexBinding & binding)137 size_t ComputeVertexAttributeStride(const VertexAttribute &attrib, const VertexBinding &binding)
138 {
139     // In ES 3.1, VertexAttribPointer will store the type size in the binding stride.
140     // Hence, rendering always uses the binding's stride.
141     return attrib.enabled ? binding.getStride() : 16u;
142 }
143 
144 // Warning: you should ensure binding really matches attrib.bindingIndex before using this function.
ComputeVertexAttributeOffset(const VertexAttribute & attrib,const VertexBinding & binding)145 GLintptr ComputeVertexAttributeOffset(const VertexAttribute &attrib, const VertexBinding &binding)
146 {
147     return attrib.relativeOffset + binding.getOffset();
148 }
149 
ComputeVertexBindingElementCount(GLuint divisor,size_t drawCount,size_t instanceCount)150 size_t ComputeVertexBindingElementCount(GLuint divisor, size_t drawCount, size_t instanceCount)
151 {
152     // For instanced rendering, we draw "instanceDrawCount" sets of "vertexDrawCount" vertices.
153     //
154     // A vertex attribute with a positive divisor loads one instanced vertex for every set of
155     // non-instanced vertices, and the instanced vertex index advances once every "mDivisor"
156     // instances.
157     if (instanceCount > 0 && divisor > 0)
158     {
159         // When instanceDrawCount is not a multiple attrib.divisor, the division must round up.
160         // For instance, with 5 non-instanced vertices and a divisor equal to 3, we need 2 instanced
161         // vertices.
162         return (instanceCount + divisor - 1u) / divisor;
163     }
164 
165     return drawCount;
166 }
167 
168 }  // namespace gl
169