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