VertexBuffer.cpp (10499B)
1 // 2 // Copyright 2002 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 // VertexBuffer.cpp: Defines the abstract VertexBuffer class and VertexBufferInterface 8 // class with derivations, classes that perform graphics API agnostic vertex buffer operations. 9 10 #include "libANGLE/renderer/d3d/VertexBuffer.h" 11 12 #include "common/mathutil.h" 13 #include "libANGLE/Context.h" 14 #include "libANGLE/VertexAttribute.h" 15 #include "libANGLE/renderer/d3d/BufferD3D.h" 16 #include "libANGLE/renderer/d3d/ContextD3D.h" 17 18 namespace rx 19 { 20 21 // VertexBuffer Implementation 22 unsigned int VertexBuffer::mNextSerial = 1; 23 24 VertexBuffer::VertexBuffer() : mRefCount(1) 25 { 26 updateSerial(); 27 } 28 29 VertexBuffer::~VertexBuffer() {} 30 31 void VertexBuffer::updateSerial() 32 { 33 mSerial = mNextSerial++; 34 } 35 36 unsigned int VertexBuffer::getSerial() const 37 { 38 return mSerial; 39 } 40 41 void VertexBuffer::addRef() 42 { 43 mRefCount++; 44 } 45 46 void VertexBuffer::release() 47 { 48 ASSERT(mRefCount > 0); 49 mRefCount--; 50 51 if (mRefCount == 0) 52 { 53 delete this; 54 } 55 } 56 57 // VertexBufferInterface Implementation 58 VertexBufferInterface::VertexBufferInterface(BufferFactoryD3D *factory, bool dynamic) 59 : mFactory(factory), mVertexBuffer(factory->createVertexBuffer()), mDynamic(dynamic) 60 {} 61 62 VertexBufferInterface::~VertexBufferInterface() 63 { 64 if (mVertexBuffer) 65 { 66 mVertexBuffer->release(); 67 mVertexBuffer = nullptr; 68 } 69 } 70 71 unsigned int VertexBufferInterface::getSerial() const 72 { 73 ASSERT(mVertexBuffer); 74 return mVertexBuffer->getSerial(); 75 } 76 77 unsigned int VertexBufferInterface::getBufferSize() const 78 { 79 ASSERT(mVertexBuffer); 80 return mVertexBuffer->getBufferSize(); 81 } 82 83 angle::Result VertexBufferInterface::setBufferSize(const gl::Context *context, unsigned int size) 84 { 85 ASSERT(mVertexBuffer); 86 if (mVertexBuffer->getBufferSize() == 0) 87 { 88 return mVertexBuffer->initialize(context, size, mDynamic); 89 } 90 91 return mVertexBuffer->setBufferSize(context, size); 92 } 93 94 angle::Result VertexBufferInterface::getSpaceRequired(const gl::Context *context, 95 const gl::VertexAttribute &attrib, 96 const gl::VertexBinding &binding, 97 size_t count, 98 GLsizei instances, 99 GLuint baseInstance, 100 unsigned int *spaceInBytesOut) const 101 { 102 unsigned int spaceRequired = 0; 103 ANGLE_TRY(mFactory->getVertexSpaceRequired(context, attrib, binding, count, instances, 104 baseInstance, &spaceRequired)); 105 106 // Align to 16-byte boundary 107 unsigned int alignedSpaceRequired = roundUpPow2(spaceRequired, 16u); 108 ANGLE_CHECK_GL_ALLOC(GetImplAs<ContextD3D>(context), alignedSpaceRequired >= spaceRequired); 109 110 *spaceInBytesOut = alignedSpaceRequired; 111 return angle::Result::Continue; 112 } 113 114 angle::Result VertexBufferInterface::discard(const gl::Context *context) 115 { 116 ASSERT(mVertexBuffer); 117 return mVertexBuffer->discard(context); 118 } 119 120 VertexBuffer *VertexBufferInterface::getVertexBuffer() const 121 { 122 ASSERT(mVertexBuffer); 123 return mVertexBuffer; 124 } 125 126 // StreamingVertexBufferInterface Implementation 127 StreamingVertexBufferInterface::StreamingVertexBufferInterface(BufferFactoryD3D *factory) 128 : VertexBufferInterface(factory, true), mWritePosition(0), mReservedSpace(0) 129 {} 130 131 angle::Result StreamingVertexBufferInterface::initialize(const gl::Context *context, 132 std::size_t initialSize) 133 { 134 return setBufferSize(context, static_cast<unsigned int>(initialSize)); 135 } 136 137 void StreamingVertexBufferInterface::reset() 138 { 139 if (mVertexBuffer) 140 { 141 mVertexBuffer->release(); 142 mVertexBuffer = mFactory->createVertexBuffer(); 143 } 144 } 145 146 StreamingVertexBufferInterface::~StreamingVertexBufferInterface() {} 147 148 angle::Result StreamingVertexBufferInterface::reserveSpace(const gl::Context *context, 149 unsigned int size) 150 { 151 unsigned int curBufferSize = getBufferSize(); 152 if (size > curBufferSize) 153 { 154 ANGLE_TRY(setBufferSize(context, std::max(size, 3 * curBufferSize / 2))); 155 mWritePosition = 0; 156 } 157 else if (mWritePosition + size > curBufferSize) 158 { 159 ANGLE_TRY(discard(context)); 160 mWritePosition = 0; 161 } 162 163 mReservedSpace = size; 164 return angle::Result::Continue; 165 } 166 167 angle::Result StreamingVertexBufferInterface::storeDynamicAttribute( 168 const gl::Context *context, 169 const gl::VertexAttribute &attrib, 170 const gl::VertexBinding &binding, 171 gl::VertexAttribType currentValueType, 172 GLint start, 173 size_t count, 174 GLsizei instances, 175 GLuint baseInstance, 176 unsigned int *outStreamOffset, 177 const uint8_t *sourceData) 178 { 179 unsigned int spaceRequired = 0; 180 ANGLE_TRY( 181 getSpaceRequired(context, attrib, binding, count, instances, baseInstance, &spaceRequired)); 182 183 // Protect against integer overflow 184 angle::CheckedNumeric<unsigned int> checkedPosition(mWritePosition); 185 checkedPosition += spaceRequired; 186 ANGLE_CHECK_GL_ALLOC(GetImplAs<ContextD3D>(context), checkedPosition.IsValid()); 187 188 mReservedSpace = 0; 189 190 size_t adjustedCount = count; 191 GLuint divisor = binding.getDivisor(); 192 193 if (instances != 0 && divisor != 0) 194 { 195 // The attribute is an instanced attribute and it's an draw instance call 196 // Extra number of elements are copied at the beginning to make sure 197 // the driver is referencing the correct data with non-zero baseInstance 198 adjustedCount += UnsignedCeilDivide(baseInstance, divisor); 199 } 200 201 ANGLE_TRY(mVertexBuffer->storeVertexAttributes(context, attrib, binding, currentValueType, 202 start, adjustedCount, instances, mWritePosition, 203 sourceData)); 204 205 if (outStreamOffset) 206 { 207 *outStreamOffset = mWritePosition; 208 } 209 210 mWritePosition += spaceRequired; 211 212 return angle::Result::Continue; 213 } 214 215 angle::Result StreamingVertexBufferInterface::reserveVertexSpace(const gl::Context *context, 216 const gl::VertexAttribute &attrib, 217 const gl::VertexBinding &binding, 218 size_t count, 219 GLsizei instances, 220 GLuint baseInstance) 221 { 222 unsigned int requiredSpace = 0; 223 ANGLE_TRY(mFactory->getVertexSpaceRequired(context, attrib, binding, count, instances, 224 baseInstance, &requiredSpace)); 225 226 // Align to 16-byte boundary 227 auto alignedRequiredSpace = rx::CheckedRoundUp(requiredSpace, 16u); 228 alignedRequiredSpace += mReservedSpace; 229 230 // Protect against integer overflow 231 ANGLE_CHECK_GL_ALLOC(GetImplAs<ContextD3D>(context), alignedRequiredSpace.IsValid()); 232 233 ANGLE_TRY(reserveSpace(context, alignedRequiredSpace.ValueOrDie())); 234 235 return angle::Result::Continue; 236 } 237 238 // StaticVertexBufferInterface Implementation 239 StaticVertexBufferInterface::AttributeSignature::AttributeSignature() 240 : formatID(angle::FormatID::NONE), stride(0), offset(0) 241 {} 242 243 bool StaticVertexBufferInterface::AttributeSignature::matchesAttribute( 244 const gl::VertexAttribute &attrib, 245 const gl::VertexBinding &binding) const 246 { 247 size_t attribStride = ComputeVertexAttributeStride(attrib, binding); 248 249 if (formatID != attrib.format->id || static_cast<GLuint>(stride) != attribStride) 250 { 251 return false; 252 } 253 254 size_t attribOffset = 255 (static_cast<size_t>(ComputeVertexAttributeOffset(attrib, binding)) % attribStride); 256 return (offset == attribOffset); 257 } 258 259 void StaticVertexBufferInterface::AttributeSignature::set(const gl::VertexAttribute &attrib, 260 const gl::VertexBinding &binding) 261 { 262 formatID = attrib.format->id; 263 offset = stride = static_cast<GLuint>(ComputeVertexAttributeStride(attrib, binding)); 264 offset = static_cast<size_t>(ComputeVertexAttributeOffset(attrib, binding)) % 265 ComputeVertexAttributeStride(attrib, binding); 266 } 267 268 StaticVertexBufferInterface::StaticVertexBufferInterface(BufferFactoryD3D *factory) 269 : VertexBufferInterface(factory, false) 270 {} 271 272 StaticVertexBufferInterface::~StaticVertexBufferInterface() {} 273 274 bool StaticVertexBufferInterface::matchesAttribute(const gl::VertexAttribute &attrib, 275 const gl::VertexBinding &binding) const 276 { 277 return mSignature.matchesAttribute(attrib, binding); 278 } 279 280 void StaticVertexBufferInterface::setAttribute(const gl::VertexAttribute &attrib, 281 const gl::VertexBinding &binding) 282 { 283 return mSignature.set(attrib, binding); 284 } 285 286 angle::Result StaticVertexBufferInterface::storeStaticAttribute(const gl::Context *context, 287 const gl::VertexAttribute &attrib, 288 const gl::VertexBinding &binding, 289 GLint start, 290 GLsizei count, 291 GLsizei instances, 292 const uint8_t *sourceData) 293 { 294 unsigned int spaceRequired = 0; 295 ANGLE_TRY(getSpaceRequired(context, attrib, binding, count, instances, 0, &spaceRequired)); 296 ANGLE_TRY(setBufferSize(context, spaceRequired)); 297 298 ASSERT(attrib.enabled); 299 ANGLE_TRY(mVertexBuffer->storeVertexAttributes(context, attrib, binding, 300 gl::VertexAttribType::InvalidEnum, start, count, 301 instances, 0, sourceData)); 302 303 mSignature.set(attrib, binding); 304 mVertexBuffer->hintUnmapResource(); 305 return angle::Result::Continue; 306 } 307 308 } // namespace rx