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// VertexDataManager.h: Defines the VertexDataManager, a class that 9// runs the Buffer translation process. 10 11#include "libGLESv2/renderer/VertexDataManager.h" 12#include "libGLESv2/renderer/BufferStorage.h" 13 14#include "libGLESv2/Buffer.h" 15#include "libGLESv2/ProgramBinary.h" 16#include "libGLESv2/Context.h" 17#include "libGLESv2/renderer/VertexBuffer.h" 18 19namespace 20{ 21 enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 }; 22 // This has to be at least 4k or else it fails on ATI cards. 23 enum { CONSTANT_VERTEX_BUFFER_SIZE = 4096 }; 24} 25 26namespace rx 27{ 28 29static int elementsInBuffer(const gl::VertexAttribute &attribute, unsigned int size) 30{ 31 // Size cannot be larger than a GLsizei 32 if (size > static_cast<unsigned int>(std::numeric_limits<int>::max())) 33 { 34 size = static_cast<unsigned int>(std::numeric_limits<int>::max()); 35 } 36 37 GLsizei stride = attribute.stride(); 38 return (size - attribute.mOffset % stride + (stride - attribute.typeSize())) / stride; 39} 40 41static int StreamingBufferElementCount(const gl::VertexAttribute &attribute, int vertexDrawCount, int instanceDrawCount) 42{ 43 // For instanced rendering, we draw "instanceDrawCount" sets of "vertexDrawCount" vertices. 44 // 45 // A vertex attribute with a positive divisor loads one instanced vertex for every set of 46 // non-instanced vertices, and the instanced vertex index advances once every "mDivisor" instances. 47 if (instanceDrawCount > 0 && attribute.mDivisor > 0) 48 { 49 return instanceDrawCount / attribute.mDivisor; 50 } 51 52 return vertexDrawCount; 53} 54 55VertexDataManager::VertexDataManager(Renderer *renderer) : mRenderer(renderer) 56{ 57 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) 58 { 59 mCurrentValue[i][0] = std::numeric_limits<float>::quiet_NaN(); 60 mCurrentValue[i][1] = std::numeric_limits<float>::quiet_NaN(); 61 mCurrentValue[i][2] = std::numeric_limits<float>::quiet_NaN(); 62 mCurrentValue[i][3] = std::numeric_limits<float>::quiet_NaN(); 63 mCurrentValueBuffer[i] = NULL; 64 mCurrentValueOffsets[i] = 0; 65 } 66 67 mStreamingBuffer = new StreamingVertexBufferInterface(renderer, INITIAL_STREAM_BUFFER_SIZE); 68 69 if (!mStreamingBuffer) 70 { 71 ERR("Failed to allocate the streaming vertex buffer."); 72 } 73} 74 75VertexDataManager::~VertexDataManager() 76{ 77 delete mStreamingBuffer; 78 79 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) 80 { 81 delete mCurrentValueBuffer[i]; 82 } 83} 84 85static bool directStoragePossible(VertexBufferInterface* vb, const gl::VertexAttribute& attrib) 86{ 87 gl::Buffer *buffer = attrib.mBoundBuffer.get(); 88 BufferStorage *storage = buffer ? buffer->getStorage() : NULL; 89 90 const bool isAligned = (attrib.stride() % 4 == 0) && (attrib.mOffset % 4 == 0); 91 92 return storage && storage->supportsDirectBinding() && !vb->getVertexBuffer()->requiresConversion(attrib) && isAligned; 93} 94 95GLenum VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], gl::ProgramBinary *programBinary, GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instances) 96{ 97 if (!mStreamingBuffer) 98 { 99 return GL_OUT_OF_MEMORY; 100 } 101 102 for (int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) 103 { 104 translated[attributeIndex].active = (programBinary->getSemanticIndex(attributeIndex) != -1); 105 } 106 107 // Invalidate static buffers that don't contain matching attributes 108 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) 109 { 110 if (translated[i].active && attribs[i].mArrayEnabled) 111 { 112 gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); 113 StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; 114 115 if (staticBuffer && staticBuffer->getBufferSize() > 0 && !staticBuffer->lookupAttribute(attribs[i], NULL) && 116 !directStoragePossible(staticBuffer, attribs[i])) 117 { 118 buffer->invalidateStaticData(); 119 } 120 } 121 } 122 123 // Reserve the required space in the buffers 124 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) 125 { 126 if (translated[i].active && attribs[i].mArrayEnabled) 127 { 128 gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); 129 StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; 130 VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer); 131 132 if (!directStoragePossible(vertexBuffer, attribs[i])) 133 { 134 if (staticBuffer) 135 { 136 if (staticBuffer->getBufferSize() == 0) 137 { 138 int totalCount = elementsInBuffer(attribs[i], buffer->size()); 139 if (!staticBuffer->reserveVertexSpace(attribs[i], totalCount, 0)) 140 { 141 return GL_OUT_OF_MEMORY; 142 } 143 } 144 } 145 else 146 { 147 int totalCount = StreamingBufferElementCount(attribs[i], count, instances); 148 149 // Undefined behaviour: 150 // We can return INVALID_OPERATION if our vertex attribute does not have enough backing data. 151 if (buffer && elementsInBuffer(attribs[i], buffer->size()) < totalCount) 152 { 153 return GL_INVALID_OPERATION; 154 } 155 156 if (!mStreamingBuffer->reserveVertexSpace(attribs[i], totalCount, instances)) 157 { 158 return GL_OUT_OF_MEMORY; 159 } 160 } 161 } 162 } 163 } 164 165 // Perform the vertex data translations 166 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) 167 { 168 if (translated[i].active) 169 { 170 if (attribs[i].mArrayEnabled) 171 { 172 gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); 173 174 if (!buffer && attribs[i].mPointer == NULL) 175 { 176 // This is an application error that would normally result in a crash, but we catch it and return an error 177 ERR("An enabled vertex array has no buffer and no pointer."); 178 return GL_INVALID_OPERATION; 179 } 180 181 StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; 182 VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer); 183 184 BufferStorage *storage = buffer ? buffer->getStorage() : NULL; 185 bool directStorage = directStoragePossible(vertexBuffer, attribs[i]); 186 187 unsigned int streamOffset = 0; 188 unsigned int outputElementSize = 0; 189 190 if (directStorage) 191 { 192 outputElementSize = attribs[i].stride(); 193 streamOffset = attribs[i].mOffset + outputElementSize * start; 194 storage->markBufferUsage(); 195 } 196 else if (staticBuffer) 197 { 198 if (!staticBuffer->getVertexBuffer()->getSpaceRequired(attribs[i], 1, 0, &outputElementSize)) 199 { 200 return GL_OUT_OF_MEMORY; 201 } 202 203 if (!staticBuffer->lookupAttribute(attribs[i], &streamOffset)) 204 { 205 // Convert the entire buffer 206 int totalCount = elementsInBuffer(attribs[i], storage->getSize()); 207 int startIndex = attribs[i].mOffset / attribs[i].stride(); 208 209 if (!staticBuffer->storeVertexAttributes(attribs[i], -startIndex, totalCount, 0, &streamOffset)) 210 { 211 return GL_OUT_OF_MEMORY; 212 } 213 } 214 215 unsigned int firstElementOffset = (attribs[i].mOffset / attribs[i].stride()) * outputElementSize; 216 unsigned int startOffset = (instances == 0 || attribs[i].mDivisor == 0) ? start * outputElementSize : 0; 217 if (streamOffset + firstElementOffset + startOffset < streamOffset) 218 { 219 return GL_OUT_OF_MEMORY; 220 } 221 222 streamOffset += firstElementOffset + startOffset; 223 } 224 else 225 { 226 int totalCount = StreamingBufferElementCount(attribs[i], count, instances); 227 if (!mStreamingBuffer->getVertexBuffer()->getSpaceRequired(attribs[i], 1, 0, &outputElementSize) || 228 !mStreamingBuffer->storeVertexAttributes(attribs[i], start, totalCount, instances, &streamOffset)) 229 { 230 return GL_OUT_OF_MEMORY; 231 } 232 } 233 234 translated[i].storage = directStorage ? storage : NULL; 235 translated[i].vertexBuffer = vertexBuffer->getVertexBuffer(); 236 translated[i].serial = directStorage ? storage->getSerial() : vertexBuffer->getSerial(); 237 translated[i].divisor = attribs[i].mDivisor; 238 239 translated[i].attribute = &attribs[i]; 240 translated[i].stride = outputElementSize; 241 translated[i].offset = streamOffset; 242 } 243 else 244 { 245 if (!mCurrentValueBuffer[i]) 246 { 247 mCurrentValueBuffer[i] = new StreamingVertexBufferInterface(mRenderer, CONSTANT_VERTEX_BUFFER_SIZE); 248 } 249 250 StreamingVertexBufferInterface *buffer = mCurrentValueBuffer[i]; 251 252 if (mCurrentValue[i][0] != attribs[i].mCurrentValue[0] || 253 mCurrentValue[i][1] != attribs[i].mCurrentValue[1] || 254 mCurrentValue[i][2] != attribs[i].mCurrentValue[2] || 255 mCurrentValue[i][3] != attribs[i].mCurrentValue[3]) 256 { 257 unsigned int requiredSpace = sizeof(float) * 4; 258 if (!buffer->reserveRawDataSpace(requiredSpace)) 259 { 260 return GL_OUT_OF_MEMORY; 261 } 262 263 unsigned int streamOffset; 264 if (!buffer->storeRawData(attribs[i].mCurrentValue, requiredSpace, &streamOffset)) 265 { 266 return GL_OUT_OF_MEMORY; 267 } 268 269 mCurrentValue[i][0] = attribs[i].mCurrentValue[0]; 270 mCurrentValue[i][1] = attribs[i].mCurrentValue[1]; 271 mCurrentValue[i][2] = attribs[i].mCurrentValue[2]; 272 mCurrentValue[i][3] = attribs[i].mCurrentValue[3]; 273 mCurrentValueOffsets[i] = streamOffset; 274 } 275 276 translated[i].storage = NULL; 277 translated[i].vertexBuffer = mCurrentValueBuffer[i]->getVertexBuffer(); 278 translated[i].serial = mCurrentValueBuffer[i]->getSerial(); 279 translated[i].divisor = 0; 280 281 translated[i].attribute = &attribs[i]; 282 translated[i].stride = 0; 283 translated[i].offset = mCurrentValueOffsets[i]; 284 } 285 } 286 } 287 288 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) 289 { 290 if (translated[i].active && attribs[i].mArrayEnabled) 291 { 292 gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); 293 294 if (buffer) 295 { 296 buffer->promoteStaticUsage(count * attribs[i].typeSize()); 297 } 298 } 299 } 300 301 return GL_NO_ERROR; 302} 303 304} 305