Browse Source

Simplify Mesh class internals.

The original goal was to avoid branches when binding the vertex
attributes for drawing, so I stored float, integral and double
attributes in separate std::vector instances and then was going through
each one of them in separate loop. In retrospect that was _not_ a good
idea, because it results in larger Mesh class, two more allocations
resulting in far more pointer chasing and more complicated
constructor/destructor.

Now everything is stored in a single vector. I may optimize it further
by not calling the constructor/destructor on it when VAOs are used.
pull/107/head
Vladimír Vondruš 11 years ago
parent
commit
ff6cc7b969
  1. 14
      src/Magnum/Implementation/MeshState.cpp
  2. 8
      src/Magnum/Implementation/MeshState.h
  3. 138
      src/Magnum/Mesh.cpp
  4. 85
      src/Magnum/Mesh.h

14
src/Magnum/Implementation/MeshState.cpp

@ -61,18 +61,10 @@ MeshState::MeshState(Context& context, std::vector<std::string>& extensions): cu
extensions.push_back(Extensions::GL::EXT::direct_state_access::string());
attributePointerImplementation = &Mesh::attributePointerImplementationDSAEXT;
attributeIPointerImplementation = &Mesh::attributePointerImplementationDSAEXT;
attributeLPointerImplementation = &Mesh::attributePointerImplementationDSAEXT;
} else
#endif
{
attributePointerImplementation = &Mesh::attributePointerImplementationVAO;
#ifndef MAGNUM_TARGET_GLES2
attributeIPointerImplementation = &Mesh::attributePointerImplementationVAO;
#ifndef MAGNUM_TARGET_GLES
attributeLPointerImplementation = &Mesh::attributePointerImplementationVAO;
#endif
#endif
}
bindIndexBufferImplementation = &Mesh::bindIndexBufferImplementationVAO;
@ -84,12 +76,6 @@ MeshState::MeshState(Context& context, std::vector<std::string>& extensions): cu
createImplementation = &Mesh::createImplementationDefault;
destroyImplementation = &Mesh::destroyImplementationDefault;
attributePointerImplementation = &Mesh::attributePointerImplementationDefault;
#ifndef MAGNUM_TARGET_GLES2
attributeIPointerImplementation = &Mesh::attributePointerImplementationDefault;
#ifndef MAGNUM_TARGET_GLES
attributeLPointerImplementation = &Mesh::attributePointerImplementationDefault;
#endif
#endif
bindIndexBufferImplementation = &Mesh::bindIndexBufferImplementationDefault;
bindImplementation = &Mesh::bindImplementationDefault;
unbindImplementation = &Mesh::unbindImplementationDefault;

8
src/Magnum/Implementation/MeshState.h

@ -39,13 +39,7 @@ struct MeshState {
void(Mesh::*createImplementation)();
void(Mesh::*destroyImplementation)();
void(Mesh::*attributePointerImplementation)(const Mesh::GenericAttribute&);
#ifndef MAGNUM_TARGET_GLES2
void(Mesh::*attributeIPointerImplementation)(const Mesh::IntegerAttribute&);
#ifndef MAGNUM_TARGET_GLES
void(Mesh::*attributeLPointerImplementation)(const Mesh::LongAttribute&);
#endif
#endif
void(Mesh::*attributePointerImplementation)(const Mesh::AttributeLayout&);
#if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES2)
void(Mesh::*vertexAttribDivisorImplementation)(GLuint, GLuint);
#endif

138
src/Magnum/Mesh.cpp

@ -138,12 +138,6 @@ Mesh::Mesh(Mesh&& other) noexcept: _id(other._id), _primitive(other._primitive),
_indexStart(other._indexStart), _indexEnd(other._indexEnd),
#endif
_indexOffset(other._indexOffset), _indexType(other._indexType), _indexBuffer(other._indexBuffer), _attributes(std::move(other._attributes))
#ifndef MAGNUM_TARGET_GLES2
, _integerAttributes(std::move(other._integerAttributes))
#ifndef MAGNUM_TARGET_GLES
, _longAttributes(std::move(other._longAttributes))
#endif
#endif
{
other._id = 0;
}
@ -167,12 +161,6 @@ Mesh& Mesh::operator=(Mesh&& other) noexcept {
swap(_indexType, other._indexType);
swap(_indexBuffer, other._indexBuffer);
swap(_attributes, other._attributes);
#ifndef MAGNUM_TARGET_GLES2
swap(_integerAttributes, other._integerAttributes);
#ifndef MAGNUM_TARGET_GLES
swap(_longAttributes, other._longAttributes);
#endif
#endif
return *this;
}
@ -400,11 +388,11 @@ void Mesh::destroyImplementationVAO() {
#endif
}
void Mesh::attributePointerInternal(const GenericAttribute& attribute) {
void Mesh::attributePointerInternal(const AttributeLayout& attribute) {
(this->*Context::current()->state().mesh->attributePointerImplementation)(attribute);
}
void Mesh::attributePointerImplementationDefault(const GenericAttribute& attribute) {
void Mesh::attributePointerImplementationDefault(const AttributeLayout& attribute) {
#if defined(CORRADE_TARGET_NACL) || defined(MAGNUM_TARGET_WEBGL)
CORRADE_ASSERT(attribute.buffer->targetHint() == Buffer::TargetHint::Array,
"Mesh::addVertexBuffer(): the buffer has unexpected target hint, expected" << Buffer::TargetHint::Array << "but got" << attribute.buffer->targetHint(), );
@ -413,7 +401,7 @@ void Mesh::attributePointerImplementationDefault(const GenericAttribute& attribu
_attributes.push_back(attribute);
}
void Mesh::attributePointerImplementationVAO(const GenericAttribute& attribute) {
void Mesh::attributePointerImplementationVAO(const AttributeLayout& attribute) {
#if defined(CORRADE_TARGET_NACL) || defined(MAGNUM_TARGET_WEBGL)
CORRADE_ASSERT(attribute.buffer->targetHint() == Buffer::TargetHint::Array,
"Mesh::addVertexBuffer(): the buffer has unexpected target hint, expected" << Buffer::TargetHint::Array << "but got" << attribute.buffer->targetHint(), );
@ -424,19 +412,45 @@ void Mesh::attributePointerImplementationVAO(const GenericAttribute& attribute)
}
#ifndef MAGNUM_TARGET_GLES
void Mesh::attributePointerImplementationDSAEXT(const GenericAttribute& attribute) {
void Mesh::attributePointerImplementationDSAEXT(const AttributeLayout& attribute) {
_flags |= ObjectFlag::Created;
glEnableVertexArrayAttribEXT(_id, attribute.location);
glVertexArrayVertexAttribOffsetEXT(_id, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.normalized, attribute.stride, attribute.offset);
#ifndef MAGNUM_TARGET_GLES2
if(attribute.kind == AttributeLayout::Kind::Integral)
glVertexArrayVertexAttribIOffsetEXT(_id, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.stride, attribute.offset);
#ifndef MAGNUM_TARGET_GLES
else if(attribute.kind == AttributeLayout::Kind::Long)
glVertexArrayVertexAttribLOffsetEXT(_id, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.stride, attribute.offset);
#endif
else
#endif
{
glVertexArrayVertexAttribOffsetEXT(_id, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.kind == AttributeLayout::Kind::GenericNormalized, attribute.stride, attribute.offset);
}
if(attribute.divisor)
(this->*Context::current()->state().mesh->vertexAttribDivisorImplementation)(attribute.location, attribute.divisor);
}
#endif
void Mesh::vertexAttribPointer(const GenericAttribute& attribute) {
void Mesh::vertexAttribPointer(const AttributeLayout& attribute) {
glEnableVertexAttribArray(attribute.location);
attribute.buffer->bindInternal(Buffer::TargetHint::Array);
glVertexAttribPointer(attribute.location, attribute.size, attribute.type, attribute.normalized, attribute.stride, reinterpret_cast<const GLvoid*>(attribute.offset));
#ifndef MAGNUM_TARGET_GLES2
if(attribute.kind == AttributeLayout::Kind::Integral)
glVertexAttribIPointer(attribute.location, attribute.size, attribute.type, attribute.stride, reinterpret_cast<const GLvoid*>(attribute.offset));
#ifndef MAGNUM_TARGET_GLES
else if(attribute.kind == AttributeLayout::Kind::Long)
glVertexAttribLPointer(attribute.location, attribute.size, attribute.type, attribute.stride, reinterpret_cast<const GLvoid*>(attribute.offset));
#endif
else
#endif
{
glVertexAttribPointer(attribute.location, attribute.size, attribute.type, attribute.kind == AttributeLayout::Kind::GenericNormalized, attribute.stride, reinterpret_cast<const GLvoid*>(attribute.offset));
}
if(attribute.divisor) {
#ifndef MAGNUM_TARGET_GLES2
glVertexAttribDivisor(attribute.location, attribute.divisor);
@ -446,68 +460,6 @@ void Mesh::vertexAttribPointer(const GenericAttribute& attribute) {
}
}
#ifndef MAGNUM_TARGET_GLES2
void Mesh::attributePointerInternal(const IntegerAttribute& attribute) {
(this->*Context::current()->state().mesh->attributeIPointerImplementation)(attribute);
}
void Mesh::attributePointerImplementationDefault(const IntegerAttribute& attribute) {
_integerAttributes.push_back(attribute);
}
void Mesh::attributePointerImplementationVAO(const IntegerAttribute& attribute) {
bindVAO();
vertexAttribPointer(attribute);
}
#ifndef MAGNUM_TARGET_GLES
void Mesh::attributePointerImplementationDSAEXT(const IntegerAttribute& attribute) {
_flags |= ObjectFlag::Created;
glEnableVertexArrayAttribEXT(_id, attribute.location);
glVertexArrayVertexAttribIOffsetEXT(_id, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.stride, attribute.offset);
if(attribute.divisor)
(this->*Context::current()->state().mesh->vertexAttribDivisorImplementation)(attribute.location, attribute.divisor);
}
#endif
void Mesh::vertexAttribPointer(const IntegerAttribute& attribute) {
glEnableVertexAttribArray(attribute.location);
attribute.buffer->bindInternal(Buffer::TargetHint::Array);
glVertexAttribIPointer(attribute.location, attribute.size, attribute.type, attribute.stride, reinterpret_cast<const GLvoid*>(attribute.offset));
if(attribute.divisor) glVertexAttribDivisor(attribute.location, attribute.divisor);
}
#endif
#ifndef MAGNUM_TARGET_GLES
void Mesh::attributePointerInternal(const LongAttribute& attribute) {
(this->*Context::current()->state().mesh->attributeLPointerImplementation)(attribute);
}
void Mesh::attributePointerImplementationDefault(const LongAttribute& attribute) {
_longAttributes.push_back(attribute);
}
void Mesh::attributePointerImplementationVAO(const LongAttribute& attribute) {
bindVAO();
vertexAttribPointer(attribute);
}
void Mesh::attributePointerImplementationDSAEXT(const LongAttribute& attribute) {
_flags |= ObjectFlag::Created;
glEnableVertexArrayAttribEXT(_id, attribute.location);
glVertexArrayVertexAttribLOffsetEXT(_id, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.stride, attribute.offset);
if(attribute.divisor)
(this->*Context::current()->state().mesh->vertexAttribDivisorImplementation)(attribute.location, attribute.divisor);
}
void Mesh::vertexAttribPointer(const LongAttribute& attribute) {
glEnableVertexAttribArray(attribute.location);
attribute.buffer->bindInternal(Buffer::TargetHint::Array);
glVertexAttribLPointer(attribute.location, attribute.size, attribute.type, attribute.stride, reinterpret_cast<const GLvoid*>(attribute.offset));
if(attribute.divisor) glVertexAttribDivisor(attribute.location, attribute.divisor);
}
#endif
#ifndef MAGNUM_TARGET_GLES
void Mesh::vertexAttribDivisorImplementationVAO(const GLuint index, const GLuint divisor) {
bindVAO();
@ -562,18 +514,8 @@ void Mesh::bindIndexBufferImplementationVAO(Buffer& buffer) {
void Mesh::bindImplementationDefault() {
/* Specify vertex attributes */
for(const GenericAttribute& attribute: _attributes)
vertexAttribPointer(attribute);
#ifndef MAGNUM_TARGET_GLES2
for(const IntegerAttribute& attribute: _integerAttributes)
vertexAttribPointer(attribute);
#ifndef MAGNUM_TARGET_GLES
for(const LongAttribute& attribute: _longAttributes)
for(const AttributeLayout& attribute: _attributes)
vertexAttribPointer(attribute);
#endif
#endif
/* Bind index buffer, if the mesh is indexed */
if(_indexBuffer) _indexBuffer->bindInternal(Buffer::TargetHint::ElementArray);
@ -584,18 +526,8 @@ void Mesh::bindImplementationVAO() {
}
void Mesh::unbindImplementationDefault() {
for(const GenericAttribute& attribute: _attributes)
glDisableVertexAttribArray(attribute.location);
#ifndef MAGNUM_TARGET_GLES2
for(const IntegerAttribute& attribute: _integerAttributes)
for(const AttributeLayout& attribute: _attributes)
glDisableVertexAttribArray(attribute.location);
#ifndef MAGNUM_TARGET_GLES
for(const LongAttribute& attribute: _longAttributes)
glDisableVertexAttribArray(attribute.location);
#endif
#endif
}
void Mesh::unbindImplementationVAO() {}

85
src/Magnum/Mesh.h

@ -842,42 +842,27 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
void draw(AbstractShaderProgram&& shader) { draw(shader); } /**< @overload */
private:
#ifndef DOXYGEN_GENERATING_OUTPUT
struct MAGNUM_LOCAL GenericAttribute {
Buffer* buffer;
GLuint location;
GLint size;
GLenum type;
bool normalized;
GLintptr offset;
GLsizei stride;
GLuint divisor;
};
#ifndef MAGNUM_TARGET_GLES2
struct MAGNUM_LOCAL IntegerAttribute {
Buffer* buffer;
GLuint location;
GLint size;
GLenum type;
GLintptr offset;
GLsizei stride;
GLuint divisor;
};
struct MAGNUM_LOCAL AttributeLayout {
enum class Kind {
Generic,
GenericNormalized,
#ifndef MAGNUM_TARGET_GLES2
Integral,
#ifndef MAGNUM_TARGET_GLES
Long
#endif
#endif
};
#ifndef MAGNUM_TARGET_GLES
struct MAGNUM_LOCAL LongAttribute {
Buffer* buffer;
GLuint location;
GLint size;
GLenum type;
Kind kind;
GLintptr offset;
GLsizei stride;
GLuint divisor;
};
#endif
#endif
#endif
explicit Mesh(GLuint id, MeshPrimitive primitive, ObjectFlags flags): _id{id}, _primitive{primitive}, _flags{flags} {}
@ -911,12 +896,12 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
template<UnsignedInt location, class T> void addVertexAttribute(typename std::enable_if<std::is_same<typename Implementation::Attribute<T>::ScalarType, Float>::value, Buffer&>::type buffer, const Attribute<location, T>& attribute, GLintptr offset, GLsizei stride, GLuint divisor) {
for(UnsignedInt i = 0; i != Attribute<location, T>::VectorCount; ++i)
attributePointerInternal(GenericAttribute{
attributePointerInternal(AttributeLayout{
&buffer,
location+i,
GLint(attribute.components()),
GLenum(attribute.dataType()),
bool(attribute.dataOptions() & Attribute<location, T>::DataOption::Normalized),
attribute.dataOptions() & Attribute<location, T>::DataOption::Normalized ? AttributeLayout::Kind::GenericNormalized : AttributeLayout::Kind::Generic,
GLintptr(offset+i*attribute.vectorSize()),
stride,
divisor
@ -925,11 +910,12 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt location, class T> void addVertexAttribute(typename std::enable_if<std::is_integral<typename Implementation::Attribute<T>::ScalarType>::value, Buffer&>::type buffer, const Attribute<location, T>& attribute, GLintptr offset, GLsizei stride, GLuint divisor) {
attributePointerInternal(IntegerAttribute{
attributePointerInternal(AttributeLayout{
&buffer,
location,
GLint(attribute.components()),
GLenum(attribute.dataType()),
AttributeLayout::Kind::Integral,
offset,
stride,
divisor
@ -939,11 +925,12 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
#ifndef MAGNUM_TARGET_GLES
template<UnsignedInt location, class T> void addVertexAttribute(typename std::enable_if<std::is_same<typename Implementation::Attribute<T>::ScalarType, Double>::value, Buffer&>::type buffer, const Attribute<location, T>& attribute, GLintptr offset, GLsizei stride, GLuint divisor) {
for(UnsignedInt i = 0; i != Attribute<location, T>::VectorCount; ++i)
attributePointerInternal(LongAttribute{
attributePointerInternal(AttributeLayout{
&buffer,
location+i,
GLint(attribute.components()),
GLenum(attribute.dataType()),
AttributeLayout::Kind::Long,
GLintptr(offset+i*attribute.vectorSize()),
stride,
divisor
@ -971,31 +958,13 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
void MAGNUM_LOCAL destroyImplementationDefault();
void MAGNUM_LOCAL destroyImplementationVAO();
void attributePointerInternal(const GenericAttribute& attribute);
void MAGNUM_LOCAL attributePointerImplementationDefault(const GenericAttribute& attribute);
void MAGNUM_LOCAL attributePointerImplementationVAO(const GenericAttribute& attribute);
void attributePointerInternal(const AttributeLayout& attribute);
void MAGNUM_LOCAL attributePointerImplementationDefault(const AttributeLayout& attribute);
void MAGNUM_LOCAL attributePointerImplementationVAO(const AttributeLayout& attribute);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL attributePointerImplementationDSAEXT(const GenericAttribute& attribute);
#endif
void MAGNUM_LOCAL vertexAttribPointer(const GenericAttribute& attribute);
#ifndef MAGNUM_TARGET_GLES2
void attributePointerInternal(const IntegerAttribute& attribute);
void MAGNUM_LOCAL attributePointerImplementationDefault(const IntegerAttribute& attribute);
void MAGNUM_LOCAL attributePointerImplementationVAO(const IntegerAttribute& attribute);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL attributePointerImplementationDSAEXT(const IntegerAttribute& attribute);
#endif
void MAGNUM_LOCAL vertexAttribPointer(const IntegerAttribute& attribute);
#endif
#ifndef MAGNUM_TARGET_GLES
void attributePointerInternal(const LongAttribute& attribute);
void MAGNUM_LOCAL attributePointerImplementationDefault(const LongAttribute& attribute);
void MAGNUM_LOCAL attributePointerImplementationVAO(const LongAttribute& attribute);
void MAGNUM_LOCAL attributePointerImplementationDSAEXT(const LongAttribute& attribute);
void MAGNUM_LOCAL vertexAttribPointer(const LongAttribute& attribute);
void MAGNUM_LOCAL attributePointerImplementationDSAEXT(const AttributeLayout& attribute);
#endif
void MAGNUM_LOCAL vertexAttribPointer(const AttributeLayout& attribute);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL vertexAttribDivisorImplementationVAO(GLuint index, GLuint divisor);
@ -1045,13 +1014,7 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
IndexType _indexType;
Buffer* _indexBuffer;
std::vector<GenericAttribute> _attributes;
#ifndef MAGNUM_TARGET_GLES2
std::vector<IntegerAttribute> _integerAttributes;
#ifndef MAGNUM_TARGET_GLES
std::vector<LongAttribute> _longAttributes;
#endif
#endif
std::vector<AttributeLayout> _attributes;
};
/** @debugoperatorenum{Magnum::MeshPrimitive} */

Loading…
Cancel
Save