diff --git a/src/Magnum/GL/Implementation/MeshState.cpp b/src/Magnum/GL/Implementation/MeshState.cpp index 7e9d171af..42786a912 100644 --- a/src/Magnum/GL/Implementation/MeshState.cpp +++ b/src/Magnum/GL/Implementation/MeshState.cpp @@ -54,6 +54,8 @@ MeshState::MeshState(Context& context, ContextState& contextState, std::vector #include #include "Magnum/Mesh.h" @@ -242,8 +243,9 @@ Mesh::Mesh(Mesh&& other) noexcept: _id(other._id), _primitive(other._primitive), #ifndef MAGNUM_TARGET_GLES2 _indexStart(other._indexStart), _indexEnd(other._indexEnd), #endif - _indexOffset(other._indexOffset), _indexType(other._indexType), _indexBuffer(other._indexBuffer), _attributes(std::move(other._attributes)) + _indexOffset(other._indexOffset), _indexType(other._indexType), _indexBuffer(other._indexBuffer) { + (this->*Context::current().state().mesh->moveConstructImplementation)(std::move(other)); other._id = 0; } @@ -265,7 +267,7 @@ Mesh& Mesh::operator=(Mesh&& other) noexcept { swap(_indexOffset, other._indexOffset); swap(_indexType, other._indexType); swap(_indexBuffer, other._indexBuffer); - swap(_attributes, other._attributes); + (this->*Context::current().state().mesh->moveAssignImplementation)(std::move(other)); return *this; } @@ -540,6 +542,10 @@ void Mesh::bindVAO() { void Mesh::createImplementationDefault() { _id = 0; _flags |= ObjectFlag::Created; + + static_assert(sizeof(_attributes) >= sizeof(std::vector), + "attribute storage buffer size too small"); + new(&_attributes) std::vector; } void Mesh::createImplementationVAO() { @@ -558,7 +564,22 @@ void Mesh::createImplementationVAODSA() { } #endif -void Mesh::destroyImplementationDefault() {} +void Mesh::moveConstructImplementationDefault(Mesh&& other) { + new(&_attributes) std::vector{std::move(*reinterpret_cast*>(&other._attributes))}; +} + +void Mesh::moveConstructImplementationVAO(Mesh&&) {} + +void Mesh::moveAssignImplementationDefault(Mesh&& other) { + std::swap(*reinterpret_cast*>(&_attributes), + *reinterpret_cast*>(&other._attributes)); +} + +void Mesh::moveAssignImplementationVAO(Mesh&&) {} + +void Mesh::destroyImplementationDefault() { + reinterpret_cast*>(&_attributes)->~vector(); +} void Mesh::destroyImplementationVAO() { #ifndef MAGNUM_TARGET_GLES2 @@ -583,7 +604,7 @@ void Mesh::attributePointerImplementationDefault(AttributeLayout& attribute) { "GL::Mesh::addVertexBuffer(): the buffer has unexpected target hint, expected" << Buffer::TargetHint::Array << "but got" << attribute.buffer.targetHint(), ); #endif - _attributes.push_back(attribute); + reinterpret_cast*>(&_attributes)->push_back(attribute); } void Mesh::attributePointerImplementationVAO(AttributeLayout& attribute) { @@ -681,7 +702,7 @@ void Mesh::bindIndexBufferImplementationVAO(Buffer& buffer) { void Mesh::bindImplementationDefault() { /* Specify vertex attributes */ - for(AttributeLayout& attribute: _attributes) + for(AttributeLayout& attribute: *reinterpret_cast*>(&_attributes)) vertexAttribPointer(attribute); /* Bind index buffer, if the mesh is indexed */ @@ -693,7 +714,7 @@ void Mesh::bindImplementationVAO() { } void Mesh::unbindImplementationDefault() { - for(const AttributeLayout& attribute: _attributes) + for(const AttributeLayout& attribute: *reinterpret_cast*>(&_attributes)) glDisableVertexAttribArray(attribute.location); } diff --git a/src/Magnum/GL/Mesh.h b/src/Magnum/GL/Mesh.h index 0720dd67b..97ed299ee 100644 --- a/src/Magnum/GL/Mesh.h +++ b/src/Magnum/GL/Mesh.h @@ -29,7 +29,6 @@ * @brief Class @ref Magnum::GL::Mesh, enum @ref Magnum::GL::MeshPrimitive, @ref Magnum::GL::MeshIndexType, function @ref Magnum::GL::meshPrimitive(), @ref Magnum::GL::meshIndexType() */ -#include #include #include @@ -981,6 +980,11 @@ class MAGNUM_GL_EXPORT Mesh: public AbstractObject { void MAGNUM_GL_LOCAL createImplementationVAODSA(); #endif + void MAGNUM_GL_LOCAL moveConstructImplementationDefault(Mesh&& other); + void MAGNUM_GL_LOCAL moveConstructImplementationVAO(Mesh&& other); + void MAGNUM_GL_LOCAL moveAssignImplementationDefault(Mesh&& other); + void MAGNUM_GL_LOCAL moveAssignImplementationVAO(Mesh&& other); + void MAGNUM_GL_LOCAL destroyImplementationDefault(); void MAGNUM_GL_LOCAL destroyImplementationVAO(); @@ -1041,7 +1045,9 @@ class MAGNUM_GL_EXPORT Mesh: public AbstractObject { MeshIndexType _indexType; Buffer* _indexBuffer; - std::vector _attributes; + /* Storage for std::vector with attribute layout / attribute buffer + instances. 4 pointers should be one pointer more than enough. */ + struct { std::intptr_t data[4]; } _attributes; }; /** @debugoperatorenum{MeshPrimitive} */ diff --git a/src/Magnum/GL/Test/MeshGLTest.cpp b/src/Magnum/GL/Test/MeshGLTest.cpp index 8fe2c71e8..d3edb7e48 100644 --- a/src/Magnum/GL/Test/MeshGLTest.cpp +++ b/src/Magnum/GL/Test/MeshGLTest.cpp @@ -285,8 +285,19 @@ void MeshGLTest::constructCopy() { CORRADE_VERIFY(!(std::is_assignable{})); } +namespace { + struct FloatShader: AbstractShaderProgram { + explicit FloatShader(const std::string& type, const std::string& conversion); + }; +} + void MeshGLTest::constructMove() { + const Float data = Math::unpack(96); + Buffer buffer1, buffer2; + buffer1.setData({&data, 1}, BufferUsage::StaticDraw); + Mesh a; + a.addVertexBuffer(buffer1, 0, Attribute<0, Float>{}); const Int id = a.id(); MAGNUM_VERIFY_NO_GL_ERROR(); @@ -306,6 +317,7 @@ void MeshGLTest::constructMove() { CORRADE_COMPARE(b.id(), id); Mesh c; + c.addVertexBuffer(buffer2, 1, Attribute<1, Float>{}); const Int cId = c.id(); c = std::move(b); @@ -322,6 +334,32 @@ void MeshGLTest::constructMove() { CORRADE_COMPARE(b.id(), cId); CORRADE_COMPARE(c.id(), id); + + /* Test that drawing still works properly */ + { + MAGNUM_VERIFY_NO_GL_ERROR(); + + Renderbuffer renderbuffer; + renderbuffer.setStorage( + #ifndef MAGNUM_TARGET_GLES2 + RenderbufferFormat::RGBA8, + #else + RenderbufferFormat::RGBA4, + #endif + Vector2i(1)); + Framebuffer framebuffer{{{}, Vector2i(1)}}; + framebuffer.attachRenderbuffer(Framebuffer::ColorAttachment(0), renderbuffer) + .bind(); + + FloatShader shader{"float", "vec4(valueInterpolated, 0.0, 0.0, 0.0)"}; + c.setPrimitive(MeshPrimitive::Points) + .setCount(1) + .draw(shader); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + CORRADE_COMPARE(framebuffer.read({{}, Vector2i{1}}, {PixelFormat::RGBA, PixelType::UnsignedByte}).data()[0], 96); + } } void MeshGLTest::wrap() { @@ -390,10 +428,6 @@ void MeshGLTest::label() { #endif namespace { - struct FloatShader: AbstractShaderProgram { - explicit FloatShader(const std::string& type, const std::string& conversion); - }; - #ifndef MAGNUM_TARGET_GLES2 struct IntegerShader: AbstractShaderProgram { explicit IntegerShader(const std::string& type);