| // |
| // Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| |
| // geometry/VertexDataManager.h: Defines the VertexDataManager, a class that |
| // runs the Buffer translation process. |
| |
| #include "libGLESv2/geometry/VertexDataManager.h" |
| |
| #include "common/debug.h" |
| |
| #include "libGLESv2/Buffer.h" |
| #include "libGLESv2/Program.h" |
| |
| #include "libGLESv2/geometry/backend.h" |
| #include "libGLESv2/geometry/IndexDataManager.h" |
| |
| namespace |
| { |
| enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 }; |
| enum { MAX_CURRENT_VALUE_EXPANSION = 16 }; |
| enum { CURRENT_VALUES_REQUIRED_SPACE = 4 * sizeof(float) * gl::MAX_VERTEX_ATTRIBS * MAX_CURRENT_VALUE_EXPANSION }; |
| } |
| |
| namespace gl |
| { |
| |
| VertexDataManager::VertexDataManager(Context *context, BufferBackEnd *backend) |
| : mContext(context), mBackend(backend), mDirtyCurrentValues(true), mCurrentValueOffset(0) |
| { |
| mStreamBuffer = mBackend->createVertexBuffer(INITIAL_STREAM_BUFFER_SIZE); |
| try |
| { |
| mCurrentValueBuffer = mBackend->createVertexBufferForStrideZero(4 * sizeof(float) * MAX_VERTEX_ATTRIBS); |
| } |
| catch (...) |
| { |
| delete mStreamBuffer; |
| throw; |
| } |
| } |
| |
| VertexDataManager::~VertexDataManager() |
| { |
| delete mStreamBuffer; |
| delete mCurrentValueBuffer; |
| } |
| |
| std::bitset<MAX_VERTEX_ATTRIBS> VertexDataManager::getActiveAttribs() const |
| { |
| std::bitset<MAX_VERTEX_ATTRIBS> active; |
| |
| Program *program = mContext->getCurrentProgram(); |
| |
| for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) |
| { |
| active[attributeIndex] = (program->getSemanticIndex(attributeIndex) != -1); |
| } |
| |
| return active; |
| } |
| |
| GLenum VertexDataManager::preRenderValidate(GLint start, GLsizei count, |
| TranslatedAttribute *translated) |
| { |
| const AttributeState *attribs = mContext->getVertexAttribBlock(); |
| const std::bitset<MAX_VERTEX_ATTRIBS> activeAttribs = getActiveAttribs(); |
| |
| for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) |
| { |
| if (!activeAttribs[i] && attribs[i].mEnabled && attribs[i].mBoundBuffer != 0 && !mContext->getBuffer(attribs[i].mBoundBuffer)) |
| return GL_INVALID_OPERATION; |
| } |
| |
| for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) |
| { |
| translated[i].enabled = activeAttribs[i]; |
| } |
| |
| bool usesCurrentValues = false; |
| |
| for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) |
| { |
| if (activeAttribs[i] && !attribs[i].mEnabled) |
| { |
| usesCurrentValues = true; |
| break; |
| } |
| } |
| |
| // Handle the identity-mapped attributes. |
| // Process array attributes. |
| |
| std::size_t requiredSpace = 0; |
| |
| for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) |
| { |
| if (activeAttribs[i] && attribs[i].mEnabled) |
| { |
| requiredSpace += spaceRequired(attribs[i], count); |
| } |
| } |
| |
| if (usesCurrentValues) |
| { |
| requiredSpace += CURRENT_VALUES_REQUIRED_SPACE; |
| } |
| |
| if (requiredSpace > mStreamBuffer->size()) |
| { |
| std::size_t newSize = std::max(requiredSpace, 3 * mStreamBuffer->size() / 2); // 1.5 x mStreamBuffer->size() is arbitrary and should be checked to see we don't have too many reallocations. |
| |
| TranslatedVertexBuffer *newStreamBuffer = mBackend->createVertexBuffer(newSize); |
| |
| delete mStreamBuffer; |
| mStreamBuffer = newStreamBuffer; |
| } |
| |
| mStreamBuffer->reserveSpace(requiredSpace); |
| |
| for (size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++) |
| { |
| if (activeAttribs[i] && attribs[i].mEnabled) |
| { |
| FormatConverter formatConverter = mBackend->getFormatConverter(attribs[i].mType, attribs[i].mSize, attribs[i].mNormalized); |
| |
| translated[i].type = attribs[i].mType; |
| translated[i].size = attribs[i].mSize; |
| translated[i].normalized = attribs[i].mNormalized; |
| translated[i].stride = formatConverter.outputVertexSize; |
| translated[i].buffer = mStreamBuffer; |
| |
| void *output = mStreamBuffer->map(spaceRequired(attribs[i], count), &translated[i].offset); |
| |
| const void *input; |
| if (attribs[i].mBoundBuffer) |
| { |
| input = mContext->getBuffer(attribs[i].mBoundBuffer)->data(); |
| input = static_cast<const char*>(input) + reinterpret_cast<size_t>(attribs[i].mPointer); |
| } |
| else |
| { |
| input = attribs[i].mPointer; |
| } |
| |
| size_t inputStride = interpretGlStride(attribs[i]); |
| |
| input = static_cast<const char*>(input) + inputStride * start; |
| |
| if (formatConverter.identity && inputStride == typeSize(attribs[i].mType) * attribs[i].mSize) |
| { |
| memcpy(output, input, count * inputStride); |
| } |
| else |
| { |
| formatConverter.convertArray(input, inputStride, count, output); |
| } |
| |
| mStreamBuffer->unmap(); |
| } |
| } |
| |
| if (usesCurrentValues) |
| { |
| processNonArrayAttributes(attribs, activeAttribs, translated, count); |
| } |
| |
| return GL_NO_ERROR; |
| } |
| |
| std::size_t VertexDataManager::typeSize(GLenum type) const |
| { |
| switch (type) |
| { |
| case GL_BYTE: case GL_UNSIGNED_BYTE: return sizeof(GLbyte); |
| case GL_SHORT: case GL_UNSIGNED_SHORT: return sizeof(GLshort); |
| case GL_FIXED: return sizeof(GLfixed); |
| case GL_FLOAT: return sizeof(GLfloat); |
| default: UNREACHABLE(); return sizeof(GLfloat); |
| } |
| } |
| |
| std::size_t VertexDataManager::interpretGlStride(const AttributeState &attrib) const |
| { |
| return attrib.mStride ? attrib.mStride : typeSize(attrib.mType) * attrib.mSize; |
| } |
| |
| // Round up x (>=0) to the next multiple of multiple (>0). |
| // 0 rounds up to 0. |
| std::size_t VertexDataManager::roundUp(std::size_t x, std::size_t multiple) const |
| { |
| ASSERT(x >= 0); |
| ASSERT(multiple > 0); |
| |
| std::size_t remainder = x % multiple; |
| if (remainder != 0) |
| { |
| return x + multiple - remainder; |
| } |
| else |
| { |
| return x; |
| } |
| } |
| |
| std::size_t VertexDataManager::spaceRequired(const AttributeState &attrib, std::size_t maxVertex) const |
| { |
| std::size_t size = mBackend->getFormatConverter(attrib.mType, attrib.mSize, attrib.mNormalized).outputVertexSize; |
| size *= maxVertex; |
| |
| return roundUp(size, 4 * sizeof(GLfloat)); |
| } |
| |
| void VertexDataManager::processNonArrayAttributes(const AttributeState *attribs, const std::bitset<MAX_VERTEX_ATTRIBS> &activeAttribs, TranslatedAttribute *translated, std::size_t count) |
| { |
| if (count <= MAX_CURRENT_VALUE_EXPANSION) |
| { |
| if (mDirtyCurrentValues || mCurrentValueLoadBuffer != mStreamBuffer) |
| { |
| float *p = static_cast<float*>(mStreamBuffer->map(CURRENT_VALUES_REQUIRED_SPACE, &mCurrentValueOffset)); |
| |
| for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) |
| { |
| float *out = p + MAX_CURRENT_VALUE_EXPANSION * 4 * i; |
| for (unsigned int j = 0; j < MAX_CURRENT_VALUE_EXPANSION; j++) |
| { |
| *out++ = attribs[i].mCurrentValue[0]; |
| *out++ = attribs[i].mCurrentValue[1]; |
| *out++ = attribs[i].mCurrentValue[2]; |
| *out++ = attribs[i].mCurrentValue[3]; |
| } |
| } |
| |
| mStreamBuffer->unmap(); |
| |
| mCurrentValueLoadBuffer = mStreamBuffer; |
| mCurrentValueSize = MAX_CURRENT_VALUE_EXPANSION; |
| mCurrentValueStride = 4 * sizeof(float); |
| } |
| } |
| else |
| { |
| if (mDirtyCurrentValues || mCurrentValueLoadBuffer != mCurrentValueBuffer) |
| { |
| std::size_t totalSize = 4 * sizeof(float) * MAX_VERTEX_ATTRIBS; |
| |
| mCurrentValueBuffer->reserveSpace(totalSize); |
| |
| float* p = static_cast<float*>(mCurrentValueBuffer->map(totalSize, &mCurrentValueOffset)); |
| |
| for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) |
| { |
| memcpy(&p[i*4], attribs[i].mCurrentValue, sizeof(attribs[i].mCurrentValue)); // FIXME: this should be doing a translation. This assumes that GL_FLOATx4 is supported. |
| } |
| |
| mCurrentValueBuffer->unmap(); |
| |
| mCurrentValueLoadBuffer = mCurrentValueBuffer; |
| mCurrentValueSize = 1; |
| mCurrentValueStride = 0; |
| } |
| } |
| |
| for (std::size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++) |
| { |
| if (activeAttribs[i] && !attribs[i].mEnabled) |
| { |
| translated[i].buffer = mCurrentValueLoadBuffer; |
| |
| translated[i].type = GL_FLOAT; |
| translated[i].size = 4; |
| translated[i].normalized = false; |
| translated[i].stride = mCurrentValueStride; |
| translated[i].offset = mCurrentValueOffset + 4 * sizeof(float) * i * mCurrentValueSize; |
| } |
| } |
| } |
| |
| } |