1 // 2 // Copyright (c) 2002-2012 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 "libGLESv2/renderer/d3d/VertexBuffer.h" 11 #include "libGLESv2/renderer/d3d/BufferD3D.h" 12 #include "libGLESv2/renderer/Renderer.h" 13 #include "libGLESv2/VertexAttribute.h" 14 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 gl::Error 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 gl::Error VertexBufferInterface::discard() 88 { 89 return mVertexBuffer->discard(); 90 } 91 92 gl::Error VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, 93 GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset) 94 { 95 gl::Error error(GL_NO_ERROR); 96 97 unsigned int spaceRequired; 98 error = mVertexBuffer->getSpaceRequired(attrib, count, instances, &spaceRequired); 99 if (error.isError()) 100 { 101 return error; 102 } 103 104 if (mWritePosition + spaceRequired < mWritePosition) 105 { 106 return gl::Error(GL_OUT_OF_MEMORY, "Internal error, new vertex buffer write position would overflow."); 107 } 108 109 error = reserveSpace(mReservedSpace); 110 if (error.isError()) 111 { 112 return error; 113 } 114 mReservedSpace = 0; 115 116 error = mVertexBuffer->storeVertexAttributes(attrib, currentValue, start, count, instances, mWritePosition); 117 if (error.isError()) 118 { 119 return error; 120 } 121 122 if (outStreamOffset) 123 { 124 *outStreamOffset = mWritePosition; 125 } 126 127 mWritePosition += spaceRequired; 128 129 // Align to 16-byte boundary 130 mWritePosition = rx::roundUp(mWritePosition, 16u); 131 132 return gl::Error(GL_NO_ERROR); 133 } 134 135 gl::Error VertexBufferInterface::reserveVertexSpace(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances) 136 { 137 gl::Error error(GL_NO_ERROR); 138 139 unsigned int requiredSpace; 140 error = mVertexBuffer->getSpaceRequired(attrib, count, instances, &requiredSpace); 141 if (error.isError()) 142 { 143 return error; 144 } 145 146 // Protect against integer overflow 147 if (mReservedSpace + requiredSpace < mReservedSpace) 148 { 149 return gl::Error(GL_OUT_OF_MEMORY, "Unable to reserve %u extra bytes in internal vertex buffer, " 150 "it would result in an overflow.", requiredSpace); 151 } 152 153 mReservedSpace += requiredSpace; 154 155 // Align to 16-byte boundary 156 mReservedSpace = rx::roundUp(mReservedSpace, 16u); 157 158 return gl::Error(GL_NO_ERROR); 159 } 160 161 VertexBuffer* VertexBufferInterface::getVertexBuffer() const 162 { 163 return mVertexBuffer; 164 } 165 166 bool VertexBufferInterface::directStoragePossible(const gl::VertexAttribute &attrib, 167 const gl::VertexAttribCurrentValueData ¤tValue) const 168 { 169 gl::Buffer *buffer = attrib.buffer.get(); 170 BufferD3D *storage = buffer ? BufferD3D::makeBufferD3D(buffer->getImplementation()) : NULL; 171 172 if (!storage || !storage->supportsDirectBinding()) 173 { 174 return false; 175 } 176 177 // Alignment restrictions: In D3D, vertex data must be aligned to 178 // the format stride, or to a 4-byte boundary, whichever is smaller. 179 // (Undocumented, and experimentally confirmed) 180 size_t alignment = 4; 181 bool requiresConversion = false; 182 183 if (attrib.type != GL_FLOAT) 184 { 185 gl::VertexFormat vertexFormat(attrib, currentValue.Type); 186 187 unsigned int outputElementSize; 188 getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); 189 alignment = std::min<size_t>(outputElementSize, 4); 190 191 requiresConversion = (mRenderer->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_CPU) != 0; 192 } 193 194 bool isAligned = (static_cast<size_t>(ComputeVertexAttributeStride(attrib)) % alignment == 0) && 195 (static_cast<size_t>(attrib.offset) % alignment == 0); 196 197 return !requiresConversion && isAligned; 198 } 199 200 StreamingVertexBufferInterface::StreamingVertexBufferInterface(rx::Renderer *renderer, std::size_t initialSize) : VertexBufferInterface(renderer, true) 201 { 202 setBufferSize(initialSize); 203 } 204 205 StreamingVertexBufferInterface::~StreamingVertexBufferInterface() 206 { 207 } 208 209 gl::Error StreamingVertexBufferInterface::reserveSpace(unsigned int size) 210 { 211 unsigned int curBufferSize = getBufferSize(); 212 if (size > curBufferSize) 213 { 214 gl::Error error = setBufferSize(std::max(size, 3 * curBufferSize / 2)); 215 if (error.isError()) 216 { 217 return error; 218 } 219 setWritePosition(0); 220 } 221 else if (getWritePosition() + size > curBufferSize) 222 { 223 gl::Error error = discard(); 224 if (error.isError()) 225 { 226 return error; 227 } 228 setWritePosition(0); 229 } 230 231 return gl::Error(GL_NO_ERROR); 232 } 233 234 StaticVertexBufferInterface::StaticVertexBufferInterface(rx::Renderer *renderer) : VertexBufferInterface(renderer, false) 235 { 236 } 237 238 StaticVertexBufferInterface::~StaticVertexBufferInterface() 239 { 240 } 241 242 bool StaticVertexBufferInterface::lookupAttribute(const gl::VertexAttribute &attrib, unsigned int *outStreamOffset) 243 { 244 for (unsigned int element = 0; element < mCache.size(); element++) 245 { 246 if (mCache[element].type == attrib.type && 247 mCache[element].size == attrib.size && 248 mCache[element].stride == ComputeVertexAttributeStride(attrib) && 249 mCache[element].normalized == attrib.normalized && 250 mCache[element].pureInteger == attrib.pureInteger) 251 { 252 size_t offset = (static_cast<size_t>(attrib.offset) % ComputeVertexAttributeStride(attrib)); 253 if (mCache[element].attributeOffset == offset) 254 { 255 if (outStreamOffset) 256 { 257 *outStreamOffset = mCache[element].streamOffset; 258 } 259 return true; 260 } 261 } 262 } 263 264 return false; 265 } 266 267 gl::Error StaticVertexBufferInterface::reserveSpace(unsigned int size) 268 { 269 unsigned int curSize = getBufferSize(); 270 if (curSize == 0) 271 { 272 return setBufferSize(size); 273 } 274 else if (curSize >= size) 275 { 276 return gl::Error(GL_NO_ERROR); 277 } 278 else 279 { 280 UNREACHABLE(); 281 return gl::Error(GL_INVALID_OPERATION, "Internal error, Static vertex buffers can't be resized."); 282 } 283 } 284 285 gl::Error StaticVertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, 286 GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset) 287 { 288 unsigned int streamOffset; 289 gl::Error error = VertexBufferInterface::storeVertexAttributes(attrib, currentValue, start, count, instances, &streamOffset); 290 if (error.isError()) 291 { 292 return error; 293 } 294 295 size_t attributeOffset = static_cast<size_t>(attrib.offset) % ComputeVertexAttributeStride(attrib); 296 VertexElement element = { attrib.type, attrib.size, ComputeVertexAttributeStride(attrib), attrib.normalized, attrib.pureInteger, attributeOffset, streamOffset }; 297 mCache.push_back(element); 298 299 if (outStreamOffset) 300 { 301 *outStreamOffset = streamOffset; 302 } 303 304 return gl::Error(GL_NO_ERROR); 305 } 306 307 } 308