VertexAttribute.cpp (5660B)
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 16 VertexBinding::VertexBinding() : VertexBinding(0) {} 17 18 VertexBinding::VertexBinding(GLuint boundAttribute) : mStride(16u), mDivisor(0), mOffset(0) 19 { 20 mBoundAttributesMask.set(boundAttribute); 21 } 22 23 VertexBinding::VertexBinding(VertexBinding &&binding) 24 { 25 *this = std::move(binding); 26 } 27 28 VertexBinding::~VertexBinding() {} 29 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 43 void VertexBinding::onContainerBindingChanged(const Context *context, int incr) const 44 { 45 if (mBuffer.get()) 46 mBuffer->onNonTFBindingChanged(incr); 47 } 48 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 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 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 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 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. 147 GLintptr ComputeVertexAttributeOffset(const VertexAttribute &attrib, const VertexBinding &binding) 148 { 149 return attrib.relativeOffset + binding.getOffset(); 150 } 151 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