1 #include "precompiled.h" 2 // 3 // Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE file. 6 // 7 8 // VertexBuffer.cpp: Defines the abstract VertexBuffer class and VertexBufferInterface 9 // class with derivations, classes that perform graphics API agnostic vertex buffer operations. 10 11 #include "libGLESv2/renderer/VertexBuffer.h" 12 #include "libGLESv2/renderer/Renderer.h" 13 #include "libGLESv2/VertexAttribute.h" 14 #include "libGLESv2/renderer/BufferStorage.h" 15 #include "common/mathutil.h" 16 17 namespace rx 18 { 19 20 unsigned int VertexBuffer::mNextSerial = 1; 21 22 VertexBuffer::VertexBuffer() 23 { 24 updateSerial(); 25 } 26 27 VertexBuffer::~VertexBuffer() 28 { 29 } 30 31 void VertexBuffer::updateSerial() 32 { 33 mSerial = mNextSerial++; 34 } 35 36 unsigned int VertexBuffer::getSerial() const 37 { 38 return mSerial; 39 } 40 41 VertexBufferInterface::VertexBufferInterface(rx::Renderer *renderer, bool dynamic) : mRenderer(renderer) 42 { 43 mDynamic = dynamic; 44 mWritePosition = 0; 45 mReservedSpace = 0; 46 47 mVertexBuffer = renderer->createVertexBuffer(); 48 } 49 50 VertexBufferInterface::~VertexBufferInterface() 51 { 52 delete mVertexBuffer; 53 } 54 55 unsigned int VertexBufferInterface::getSerial() const 56 { 57 return mVertexBuffer->getSerial(); 58 } 59 60 unsigned int VertexBufferInterface::getBufferSize() const 61 { 62 return mVertexBuffer->getBufferSize(); 63 } 64 65 bool VertexBufferInterface::setBufferSize(unsigned int size) 66 { 67 if (mVertexBuffer->getBufferSize() == 0) 68 { 69 return mVertexBuffer->initialize(size, mDynamic); 70 } 71 else 72 { 73 return mVertexBuffer->setBufferSize(size); 74 } 75 } 76 77 unsigned int VertexBufferInterface::getWritePosition() const 78 { 79 return mWritePosition; 80 } 81 82 void VertexBufferInterface::setWritePosition(unsigned int writePosition) 83 { 84 mWritePosition = writePosition; 85 } 86 87 bool VertexBufferInterface::discard() 88 { 89 return mVertexBuffer->discard(); 90 } 91 92 bool VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, 93 GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset) 94 { 95 unsigned int spaceRequired; 96 if (!mVertexBuffer->getSpaceRequired(attrib, count, instances, &spaceRequired)) 97 { 98 return false; 99 } 100 101 if (mWritePosition + spaceRequired < mWritePosition) 102 { 103 return false; 104 } 105 106 if (!reserveSpace(mReservedSpace)) 107 { 108 return false; 109 } 110 mReservedSpace = 0; 111 112 if (!mVertexBuffer->storeVertexAttributes(attrib, currentValue, start, count, instances, mWritePosition)) 113 { 114 return false; 115 } 116 117 if (outStreamOffset) 118 { 119 *outStreamOffset = mWritePosition; 120 } 121 122 mWritePosition += spaceRequired; 123 124 // Align to 16-byte boundary 125 mWritePosition = rx::roundUp(mWritePosition, 16u); 126 127 return true; 128 } 129 130 bool VertexBufferInterface::reserveVertexSpace(const gl::VertexAttribute &attribute, GLsizei count, GLsizei instances) 131 { 132 unsigned int requiredSpace; 133 if (!mVertexBuffer->getSpaceRequired(attribute, count, instances, &requiredSpace)) 134 { 135 return false; 136 } 137 138 // Protect against integer overflow 139 if (mReservedSpace + requiredSpace < mReservedSpace) 140 { 141 return false; 142 } 143 144 mReservedSpace += requiredSpace; 145 146 // Align to 16-byte boundary 147 mReservedSpace = rx::roundUp(mReservedSpace, 16u); 148 149 return true; 150 } 151 152 VertexBuffer* VertexBufferInterface::getVertexBuffer() const 153 { 154 return mVertexBuffer; 155 } 156 157 bool VertexBufferInterface::directStoragePossible(const gl::VertexAttribute &attrib, 158 const gl::VertexAttribCurrentValueData ¤tValue) const 159 { 160 gl::Buffer *buffer = attrib.mBoundBuffer.get(); 161 BufferStorage *storage = buffer ? buffer->getStorage() : NULL; 162 163 if (!storage || !storage->supportsDirectBinding()) 164 { 165 return false; 166 } 167 168 // Alignment restrictions: In D3D, vertex data must be aligned to 169 // the format stride, or to a 4-byte boundary, whichever is smaller. 170 // (Undocumented, and experimentally confirmed) 171 size_t alignment = 4; 172 bool requiresConversion = false; 173 174 if (attrib.mType != GL_FLOAT) 175 { 176 gl::VertexFormat vertexFormat(attrib, currentValue.Type); 177 178 unsigned int outputElementSize; 179 getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); 180 alignment = std::min<size_t>(outputElementSize, 4); 181 182 requiresConversion = (mRenderer->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_CPU) != 0; 183 } 184 185 bool isAligned = (static_cast<size_t>(attrib.stride()) % alignment == 0) && 186 (static_cast<size_t>(attrib.mOffset) % alignment == 0); 187 188 return !requiresConversion && isAligned; 189 } 190 191 StreamingVertexBufferInterface::StreamingVertexBufferInterface(rx::Renderer *renderer, std::size_t initialSize) : VertexBufferInterface(renderer, true) 192 { 193 setBufferSize(initialSize); 194 } 195 196 StreamingVertexBufferInterface::~StreamingVertexBufferInterface() 197 { 198 } 199 200 bool StreamingVertexBufferInterface::reserveSpace(unsigned int size) 201 { 202 bool result = true; 203 unsigned int curBufferSize = getBufferSize(); 204 if (size > curBufferSize) 205 { 206 result = setBufferSize(std::max(size, 3 * curBufferSize / 2)); 207 setWritePosition(0); 208 } 209 else if (getWritePosition() + size > curBufferSize) 210 { 211 if (!discard()) 212 { 213 return false; 214 } 215 setWritePosition(0); 216 } 217 218 return result; 219 } 220 221 StaticVertexBufferInterface::StaticVertexBufferInterface(rx::Renderer *renderer) : VertexBufferInterface(renderer, false) 222 { 223 } 224 225 StaticVertexBufferInterface::~StaticVertexBufferInterface() 226 { 227 } 228 229 bool StaticVertexBufferInterface::lookupAttribute(const gl::VertexAttribute &attribute, unsigned int *outStreamOffset) 230 { 231 for (unsigned int element = 0; element < mCache.size(); element++) 232 { 233 if (mCache[element].type == attribute.mType && 234 mCache[element].size == attribute.mSize && 235 mCache[element].stride == attribute.stride() && 236 mCache[element].normalized == attribute.mNormalized && 237 mCache[element].pureInteger == attribute.mPureInteger) 238 { 239 if (mCache[element].attributeOffset == attribute.mOffset % attribute.stride()) 240 { 241 if (outStreamOffset) 242 { 243 *outStreamOffset = mCache[element].streamOffset; 244 } 245 return true; 246 } 247 } 248 } 249 250 return false; 251 } 252 253 bool StaticVertexBufferInterface::reserveSpace(unsigned int size) 254 { 255 unsigned int curSize = getBufferSize(); 256 if (curSize == 0) 257 { 258 setBufferSize(size); 259 return true; 260 } 261 else if (curSize >= size) 262 { 263 return true; 264 } 265 else 266 { 267 UNREACHABLE(); // Static vertex buffers can't be resized 268 return false; 269 } 270 } 271 272 bool StaticVertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, 273 GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset) 274 { 275 unsigned int streamOffset; 276 if (VertexBufferInterface::storeVertexAttributes(attrib, currentValue, start, count, instances, &streamOffset)) 277 { 278 int attributeOffset = attrib.mOffset % attrib.stride(); 279 VertexElement element = { attrib.mType, attrib.mSize, attrib.stride(), attrib.mNormalized, attrib.mPureInteger, attributeOffset, streamOffset }; 280 mCache.push_back(element); 281 282 if (outStreamOffset) 283 { 284 *outStreamOffset = streamOffset; 285 } 286 287 return true; 288 } 289 else 290 { 291 return false; 292 } 293 } 294 295 } 296