Browse Source

GL: make it possible for a Mesh to own the vertex/index buffers.

I wanted to do this since 2015.
pull/255/head
Vladimír Vondruš 8 years ago
parent
commit
9be24a241e
  1. 4
      doc/changelog.dox
  2. 17
      doc/snippets/MagnumGL.cpp
  3. 2
      src/Magnum/GL/Implementation/MeshState.cpp
  4. 3
      src/Magnum/GL/Implementation/MeshState.h
  5. 74
      src/Magnum/GL/Mesh.cpp
  6. 135
      src/Magnum/GL/Mesh.h
  7. 198
      src/Magnum/GL/Test/MeshGLTest.cpp

4
doc/changelog.dox

@ -62,6 +62,10 @@ See also:
- To prevent nothing being rendered by accident, @ref GL::Mesh::setCount()
and @ref GL::MeshView::setCount() now has always to be called, even just to
set the count to @cpp 0 @ce.
- @ref GL::Mesh::addVertexBuffer(), @ref GL::Mesh::addVertexBufferInstanced()
@ref GL::Mesh::setIndexBuffer() can now take ownership of a passed
@ref GL::Buffer to simplify resource management on user side. See
@ref GL-Mesh-buffer-ownership for more information.
@subsubsection changelog-latest-changes-platform Platform libraries

17
doc/snippets/MagnumGL.cpp

@ -1075,6 +1075,23 @@ mesh.addVertexBuffer(colorBuffer, 0, 4, GL::DynamicAttribute{
/* [Mesh-dynamic] */
}
{
GL::Mesh mesh;
/* [Mesh-buffer-ownership] */
GL::Buffer vertices, indices;
// ...
mesh.addVertexBuffer(std::move(vertices), 0,
Shaders::Phong::Position{},
Shaders::Phong::Normal{})
.setIndexBuffer(std::move(indices), 0, MeshIndexType::UnsignedInt);
/* [Mesh-buffer-ownership] */
/* [Mesh-buffer-ownership-multiple] */
mesh.addVertexBuffer(vertices, 0, Shaders::Phong::Position{}, 20)
.addVertexBuffer(std::move(vertices), 0, 20, Shaders::Phong::Normal{});
/* [Mesh-buffer-ownership-multiple] */
}
{
/* [Mesh-addVertexBuffer1] */
GL::Buffer buffer;

2
src/Magnum/GL/Implementation/MeshState.cpp

@ -69,6 +69,7 @@ MeshState::MeshState(Context& context, ContextState& contextState, std::vector<s
attributePointerImplementation = &Mesh::attributePointerImplementationVAO;
}
acquireVertexBufferImplementation = &Mesh::acquireVertexBufferImplementationVAO;
bindIndexBufferImplementation = &Mesh::bindIndexBufferImplementationVAO;
bindVAOImplementation = &Mesh::bindVAOImplementationVAO;
bindImplementation = &Mesh::bindImplementationVAO;
@ -81,6 +82,7 @@ MeshState::MeshState(Context& context, ContextState& contextState, std::vector<s
moveAssignImplementation = &Mesh::moveAssignImplementationDefault;
destroyImplementation = &Mesh::destroyImplementationDefault;
attributePointerImplementation = &Mesh::attributePointerImplementationDefault;
acquireVertexBufferImplementation = &Mesh::acquireVertexBufferImplementationDefault;
bindIndexBufferImplementation = &Mesh::bindIndexBufferImplementationDefault;
bindVAOImplementation = &Mesh::bindVAOImplementationDefault;
bindImplementation = &Mesh::bindImplementationDefault;

3
src/Magnum/GL/Implementation/MeshState.h

@ -44,10 +44,11 @@ struct MeshState {
void(Mesh::*moveConstructImplementation)(Mesh&&);
void(Mesh::*moveAssignImplementation)(Mesh&&);
void(Mesh::*destroyImplementation)();
void(Mesh::*attributePointerImplementation)(Mesh::AttributeLayout&);
void(Mesh::*attributePointerImplementation)(Mesh::AttributeLayout&&);
#if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES2)
void(Mesh::*vertexAttribDivisorImplementation)(GLuint, GLuint);
#endif
void(Mesh::*acquireVertexBufferImplementation)(Buffer&&);
void(Mesh::*bindIndexBufferImplementation)(Buffer&);
void(Mesh::*bindImplementation)();
void(Mesh::*unbindImplementation)();

74
src/Magnum/GL/Mesh.cpp

@ -134,7 +134,10 @@ Debug& operator<<(Debug& debug, MeshIndexType value) {
struct Mesh::AttributeLayout {
explicit AttributeLayout(const Buffer& buffer, GLuint location, GLint size, GLenum type, DynamicAttribute::Kind kind, GLintptr offset, GLsizei stride, GLuint divisor) noexcept: buffer{Buffer::wrap(buffer.id())}, location{location}, size{size}, type{type}, kind{kind}, offset{offset}, stride{stride}, divisor{divisor} {}
explicit AttributeLayout(const AttributeLayout& other): buffer{Buffer::wrap(other.buffer.id())}, location{other.location}, size{other.size}, type{other.type}, kind{other.kind}, offset{other.offset}, stride{other.stride}, divisor{other.divisor} {}
AttributeLayout(AttributeLayout&&) noexcept = default;
AttributeLayout(const AttributeLayout&) noexcept = delete;
AttributeLayout& operator=(AttributeLayout&&) noexcept = default;
AttributeLayout& operator=(const AttributeLayout&) noexcept = delete;
Buffer buffer;
GLuint location;
@ -311,19 +314,18 @@ UnsignedInt Mesh::indexTypeSize() const {
}
Mesh& Mesh::addVertexBufferInstanced(Buffer& buffer, const UnsignedInt divisor, const GLintptr offset, const GLsizei stride, const DynamicAttribute& attribute) {
AttributeLayout l{buffer,
attributePointerInternal(AttributeLayout{buffer,
attribute.location(),
GLint(attribute.components()),
GLenum(attribute.dataType()),
attribute.kind(),
offset,
stride,
divisor};
attributePointerInternal(l);
divisor});
return *this;
}
Mesh& Mesh::setIndexBuffer(Buffer& buffer, GLintptr offset, MeshIndexType type, UnsignedInt start, UnsignedInt end) {
Mesh& Mesh::setIndexBuffer(Buffer&& buffer, GLintptr offset, MeshIndexType type, UnsignedInt start, UnsignedInt end) {
CORRADE_ASSERT(buffer.id(),
"GL::Mesh::setIndexBuffer(): empty or moved-out Buffer instance was passed", *this);
#ifdef MAGNUM_TARGET_WEBGL
@ -331,7 +333,7 @@ Mesh& Mesh::setIndexBuffer(Buffer& buffer, GLintptr offset, MeshIndexType type,
"GL::Mesh::setIndexBuffer(): the buffer has unexpected target hint, expected" << Buffer::TargetHint::ElementArray << "but got" << buffer.targetHint(), *this);
#endif
_indexBuffer = Buffer::wrap(buffer.id());
_indexBuffer = std::move(buffer);
_indexOffset = offset;
_indexType = type;
#ifndef MAGNUM_TARGET_GLES2
@ -341,7 +343,12 @@ Mesh& Mesh::setIndexBuffer(Buffer& buffer, GLintptr offset, MeshIndexType type,
static_cast<void>(start);
static_cast<void>(end);
#endif
(this->*Context::current().state().mesh->bindIndexBufferImplementation)(buffer);
(this->*Context::current().state().mesh->bindIndexBufferImplementation)(_indexBuffer);
return *this;
}
Mesh& Mesh::setIndexBuffer(Buffer& buffer, const GLintptr offset, const MeshIndexType type, const UnsignedInt start, const UnsignedInt end) {
setIndexBuffer(Buffer::wrap(buffer.id()), offset, type, start, end);
return *this;
}
@ -545,12 +552,20 @@ void Mesh::createImplementationVAO() {
glGenVertexArraysOES(1, &_id);
#endif
CORRADE_INTERNAL_ASSERT(_id != Implementation::State::DisengagedBinding);
static_assert(sizeof(_attributes) >= sizeof(std::vector<Buffer>),
"attribute storage buffer size too small");
new(&_attributes) std::vector<Buffer>;
}
#ifndef MAGNUM_TARGET_GLES
void Mesh::createImplementationVAODSA() {
glCreateVertexArrays(1, &_id);
_flags |= ObjectFlag::Created;
static_assert(sizeof(_attributes) >= sizeof(std::vector<Buffer>),
"attribute storage buffer size too small");
new(&_attributes) std::vector<Buffer>;
}
#endif
@ -558,14 +573,19 @@ void Mesh::moveConstructImplementationDefault(Mesh&& other) {
new(&_attributes) std::vector<AttributeLayout>{std::move(*reinterpret_cast<std::vector<AttributeLayout>*>(&other._attributes))};
}
void Mesh::moveConstructImplementationVAO(Mesh&&) {}
void Mesh::moveConstructImplementationVAO(Mesh&& other) {
new(&_attributes) std::vector<Buffer>{std::move(*reinterpret_cast<std::vector<Buffer>*>(&other._attributes))};
}
void Mesh::moveAssignImplementationDefault(Mesh&& other) {
std::swap(*reinterpret_cast<std::vector<AttributeLayout>*>(&_attributes),
*reinterpret_cast<std::vector<AttributeLayout>*>(&other._attributes));
}
void Mesh::moveAssignImplementationVAO(Mesh&&) {}
void Mesh::moveAssignImplementationVAO(Mesh&& other) {
std::swap(*reinterpret_cast<std::vector<Buffer>*>(&_attributes),
*reinterpret_cast<std::vector<Buffer>*>(&other._attributes));
}
void Mesh::destroyImplementationDefault() {
reinterpret_cast<std::vector<AttributeLayout>*>(&_attributes)->~vector();
@ -577,29 +597,30 @@ void Mesh::destroyImplementationVAO() {
#else
glDeleteVertexArraysOES(1, &_id);
#endif
reinterpret_cast<std::vector<Buffer>*>(&_attributes)->~vector();
}
void Mesh::attributePointerInternal(const Buffer& buffer, const GLuint location, const GLint size, const GLenum type, const DynamicAttribute::Kind kind, const GLintptr offset, const GLsizei stride, const GLuint divisor) {
AttributeLayout l{buffer, location, size, type, kind, offset, stride, divisor};
attributePointerInternal(l);
attributePointerInternal(AttributeLayout{buffer, location, size, type, kind, offset, stride, divisor});
}
void Mesh::attributePointerInternal(AttributeLayout& attribute) {
void Mesh::attributePointerInternal(AttributeLayout&& attribute) {
CORRADE_ASSERT(attribute.buffer.id(),
"GL::Mesh::addVertexBuffer(): empty or moved-out Buffer instance was passed", );
(this->*Context::current().state().mesh->attributePointerImplementation)(attribute);
(this->*Context::current().state().mesh->attributePointerImplementation)(std::move(attribute));
}
void Mesh::attributePointerImplementationDefault(AttributeLayout& attribute) {
void Mesh::attributePointerImplementationDefault(AttributeLayout&& attribute) {
#ifdef MAGNUM_TARGET_WEBGL
CORRADE_ASSERT(attribute.buffer.targetHint() == Buffer::TargetHint::Array,
"GL::Mesh::addVertexBuffer(): the buffer has unexpected target hint, expected" << Buffer::TargetHint::Array << "but got" << attribute.buffer.targetHint(), );
#endif
reinterpret_cast<std::vector<AttributeLayout>*>(&_attributes)->push_back(attribute);
reinterpret_cast<std::vector<AttributeLayout>*>(&_attributes)->push_back(std::move(attribute));
}
void Mesh::attributePointerImplementationVAO(AttributeLayout& attribute) {
void Mesh::attributePointerImplementationVAO(AttributeLayout&& attribute) {
#ifdef MAGNUM_TARGET_WEBGL
CORRADE_ASSERT(attribute.buffer.targetHint() == Buffer::TargetHint::Array,
"GL::Mesh::addVertexBuffer(): the buffer has unexpected target hint, expected" << Buffer::TargetHint::Array << "but got" << attribute.buffer.targetHint(), );
@ -610,7 +631,7 @@ void Mesh::attributePointerImplementationVAO(AttributeLayout& attribute) {
}
#ifndef MAGNUM_TARGET_GLES
void Mesh::attributePointerImplementationDSAEXT(AttributeLayout& attribute) {
void Mesh::attributePointerImplementationDSAEXT(AttributeLayout&& attribute) {
_flags |= ObjectFlag::Created;
glEnableVertexArrayAttribEXT(_id, attribute.location);
@ -680,6 +701,25 @@ void Mesh::vertexAttribDivisorImplementationNV(const GLuint index, const GLuint
#endif
#endif
void Mesh::acquireVertexBuffer(Buffer&& buffer) {
(this->*Context::current().state().mesh->acquireVertexBufferImplementation)(std::move(buffer));
}
void Mesh::acquireVertexBufferImplementationDefault(Buffer&& buffer) {
/* The last added buffer should be this one, replace it with a owning one */
auto& attributes = *reinterpret_cast<std::vector<AttributeLayout>*>(&_attributes);
CORRADE_INTERNAL_ASSERT(!attributes.empty() && attributes.back().buffer.id() == buffer.id() && buffer.id());
attributes.back().buffer.release(); /* so we swap back a zero ID */
attributes.back().buffer = std::move(buffer);
}
void Mesh::acquireVertexBufferImplementationVAO(Buffer&& buffer) {
CORRADE_INTERNAL_ASSERT(buffer.id());
/* With VAOs we are not maintaining the attribute list, so just store the
buffer directly */
reinterpret_cast<std::vector<Buffer>*>(&_attributes)->emplace_back(std::move(buffer));
}
void Mesh::bindIndexBufferImplementationDefault(Buffer&) {}
void Mesh::bindIndexBufferImplementationVAO(Buffer& buffer) {

135
src/Magnum/GL/Mesh.h

@ -192,11 +192,11 @@ There is also @ref MeshTools::compile() function which operates directly on
@ref Trade::MeshData2D / @ref Trade::MeshData3D and returns fully configured
mesh and vertex/index buffers for use with stock shaders.
Note that neither vertex buffers nor index buffer is managed (e.g. deleted on
destruction) by the mesh, so you have to manage them on your own and ensure
that they are available for whole mesh lifetime. On the other hand it allows
you to use one buffer for more meshes (each mesh for example configured for
different usage) or store data for more meshes in one buffer.
@attention Note that, by default, neither vertex buffers nor index buffer is
managed (e.g. deleted on destruction) by the mesh, so you have to manage
them on your own and ensure that they are available for whole mesh
lifetime. See @ref GL-Mesh-buffer-ownership for a way to transfer buffer
ownership to the mesh.
If vertex/index count or instance count is zero, the mesh is empty and no draw
commands are issued when calling @ref draw().
@ -238,6 +238,24 @@ this:
@snippet MagnumGL.cpp Mesh-dynamic
@section GL-Mesh-buffer-ownership Transfering buffer ownership
If a vertex/index buffer is used only by a single mesh, it's possible to
transfer its ownership to the mesh itself to simplify resource management on
the user side. Simply use the @ref addVertexBuffer() /
@ref addVertexBufferInstanced() and @ref setIndexBuffer() overloads that take
a @ref Buffer as a rvalue:
@snippet MagnumGL.cpp Mesh-buffer-ownership
While this allows you to destruct the buffer instances and pass just the mesh
around, this also means you lose a way to access or update the buffers. If
adding the same buffer multiple times or using it for both vertex and index
data, be sure to transfer the ownership last to avoid the other functions
getting only a moved-out instance. For example:
@snippet MagnumGL.cpp Mesh-buffer-ownership-multiple
@section GL-Mesh-rendering Rendering meshes
Basic workflow is: bind specific framebuffer for drawing (if needed), set up
@ -727,7 +745,7 @@ class MAGNUM_GL_EXPORT Mesh: public AbstractObject {
}
/**
* @brief Add buffer with dynamic vertex attributes for use with given shader
* @brief Add vertex buffer with dynamic vertex attributes
* @return Reference to self (for method chaining)
*
* Equivalent to @ref addVertexBuffer(Buffer&, GLintptr, const T&... attributes)
@ -741,7 +759,7 @@ class MAGNUM_GL_EXPORT Mesh: public AbstractObject {
}
/**
* @brief Add buffer with dynamic vertex attributes for use with given shader
* @brief Add instanced vertex buffer with dynamic vertex attributes
* @return Reference to self (for method chaining)
*
* Equivalent to @ref addVertexBufferInstanced(Buffer&, UnsignedInt, GLintptr, const T&... attributes)
@ -752,6 +770,62 @@ class MAGNUM_GL_EXPORT Mesh: public AbstractObject {
*/
Mesh& addVertexBufferInstanced(Buffer& buffer, UnsignedInt divisor, GLintptr offset, GLsizei stride, const DynamicAttribute& attribute);
/**
* @brief Add vertex buffer with ownership transfer
* @return Reference to self (for method chaining)
*
* Unlike @ref addVertexBuffer(Buffer&, GLintptr, const T&... attributes)
* this function takes ownership of @p buffer. See
* @ref GL-Mesh-buffer-ownership for more information.
*/
template<class ...T> inline Mesh& addVertexBuffer(Buffer&& buffer, GLintptr offset, const T&... attributes) {
addVertexBuffer<T...>(buffer, offset, attributes...);
acquireVertexBuffer(std::move(buffer));
return *this;
}
/**
* @brief Add instanced vertex buffer with ownership transfer
* @return Reference to self (for method chaining)
*
* Unlike @ref addVertexBufferInstanced(Buffer&, UnsignedInt, GLintptr, const T&... attributes)
* this function takes ownership of @p buffer. See
* @ref GL-Mesh-buffer-ownership for more information.
*/
template<class ...T> inline Mesh& addVertexBufferInstanced(Buffer&& buffer, UnsignedInt divisor, GLintptr offset, const T&... attributes) {
addVertexBufferInstanced<T...>(buffer, divisor, offset, attributes...);
acquireVertexBuffer(std::move(buffer));
return *this;
}
/**
* @brief Add vertex buffer with dynamic vertex attributes with ownership transfer
* @return Reference to self (for method chaining)
*
* Unlike @ref addVertexBuffer(Buffer&, GLintptr, GLsizei, const DynamicAttribute&)
* this function takes ownership of @p buffer. See
* @ref GL-Mesh-buffer-ownership for more information.
*/
Mesh& addVertexBuffer(Buffer&& buffer, GLintptr offset, GLsizei stride, const DynamicAttribute& attribute) {
addVertexBuffer(buffer, offset, stride, attribute);
acquireVertexBuffer(std::move(buffer));
return *this;
}
/**
* @brief Add instanced vertex buffer with dynamic vertex attributes with ownership transfer
* @return Reference to self (for method chaining)
*
* Unlike @ref addVertexBufferInstanced(Buffer&, UnsignedInt, GLintptr, GLsizei, const DynamicAttribute&)
* this function takes ownership of @p buffer. See
* @ref GL-Mesh-buffer-ownership for more information.
*/
Mesh& addVertexBufferInstanced(Buffer&& buffer, UnsignedInt divisor, GLintptr offset, GLsizei stride, const DynamicAttribute& attribute) {
addVertexBufferInstanced(buffer, divisor, offset, stride, attribute);
acquireVertexBuffer(std::move(buffer));
return *this;
}
/**
* @brief Set index buffer
* @param buffer Index buffer
@ -807,6 +881,36 @@ class MAGNUM_GL_EXPORT Mesh: public AbstractObject {
return setIndexBuffer(buffer, offset, meshIndexType(type), 0, 0);
}
/**
* @brief Set index buffer with ownership transfer
*
* Unlike @ref setIndexBuffer(Buffer&, GLintptr, MeshIndexType, UnsignedInt, UnsignedInt)
* this function takes ownership of @p buffer. See
* @ref GL-Mesh-buffer-ownership for more information.
*/
Mesh& setIndexBuffer(Buffer&& buffer, GLintptr offset, MeshIndexType type, UnsignedInt start, UnsignedInt end);
/** @overload */
Mesh& setIndexBuffer(Buffer&& buffer, GLintptr offset, Magnum::MeshIndexType type, UnsignedInt start, UnsignedInt end) {
return setIndexBuffer(std::move(buffer), offset, meshIndexType(type), start, end);
}
/**
* @brief Set index buffer with ownership transfer
*
* Unlike @ref setIndexBuffer(Buffer&, GLintptr, MeshIndexType) this
* function takes ownership of @p buffer. See
* @ref GL-Mesh-buffer-ownership for more information.
*/
Mesh& setIndexBuffer(Buffer&& buffer, GLintptr offset, MeshIndexType type) {
return setIndexBuffer(std::move(buffer), offset, type, 0, 0);
}
/** @overload */
Mesh& setIndexBuffer(Buffer&& buffer, GLintptr offset, Magnum::MeshIndexType type) {
return setIndexBuffer(std::move(buffer), offset, meshIndexType(type), 0, 0);
}
/**
* @brief Draw the mesh
* @param shader Shader to use for drawing
@ -995,11 +1099,11 @@ class MAGNUM_GL_EXPORT Mesh: public AbstractObject {
void MAGNUM_GL_LOCAL destroyImplementationVAO();
void attributePointerInternal(const Buffer& buffer, GLuint location, GLint size, GLenum type, DynamicAttribute::Kind kind, GLintptr offset, GLsizei stride, GLuint divisor);
void MAGNUM_GL_LOCAL attributePointerInternal(AttributeLayout& attribute);
void MAGNUM_GL_LOCAL attributePointerImplementationDefault(AttributeLayout& attribute);
void MAGNUM_GL_LOCAL attributePointerImplementationVAO(AttributeLayout& attribute);
void MAGNUM_GL_LOCAL attributePointerInternal(AttributeLayout&& attribute);
void MAGNUM_GL_LOCAL attributePointerImplementationDefault(AttributeLayout&& attribute);
void MAGNUM_GL_LOCAL attributePointerImplementationVAO(AttributeLayout&& attribute);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_GL_LOCAL attributePointerImplementationDSAEXT(AttributeLayout& attribute);
void MAGNUM_GL_LOCAL attributePointerImplementationDSAEXT(AttributeLayout&& attribute);
#endif
void MAGNUM_GL_LOCAL vertexAttribPointer(AttributeLayout& attribute);
@ -1014,6 +1118,10 @@ class MAGNUM_GL_EXPORT Mesh: public AbstractObject {
#endif
#endif
void acquireVertexBuffer(Buffer&& buffer);
void MAGNUM_GL_LOCAL acquireVertexBufferImplementationDefault(Buffer&& buffer);
void MAGNUM_GL_LOCAL acquireVertexBufferImplementationVAO(Buffer&& buffer);
void MAGNUM_GL_LOCAL bindIndexBufferImplementationDefault(Buffer&);
void MAGNUM_GL_LOCAL bindIndexBufferImplementationVAO(Buffer& buffer);
@ -1055,8 +1163,9 @@ class MAGNUM_GL_EXPORT Mesh: public AbstractObject {
MeshIndexType _indexType{};
Buffer _indexBuffer{NoCreate};
/* Storage for std::vector with attribute layout / attribute buffer
instances. 4 pointers should be one pointer more than enough. */
/* Storage for either std::vector<AttributeLayout> (in case of no VAOs)
or std::vector<Buffer> (in case of VAOs). 4 pointers should be one
pointer more than enough. */
struct { std::intptr_t data[4]; } _attributes;
};

198
src/Magnum/GL/Test/MeshGLTest.cpp

@ -118,12 +118,18 @@ struct MeshGLTest: OpenGLTester {
void addVertexBufferMultipleGaps();
void addVertexBufferMovedOutInstance();
void addVertexBufferTransferOwnwership();
void addVertexBufferInstancedTransferOwnwership();
void addVertexBufferDynamicTransferOwnwership();
void addVertexBufferInstancedDynamicTransferOwnwership();
template<class T> void setIndexBuffer();
template<class T> void setIndexBufferRange();
void setIndexBufferUnsignedInt();
void setIndexBufferMovedOutInstance();
template<class T> void setIndexBufferTransferOwnership();
template<class T> void setIndexBufferRangeTransferOwnership();
void unbindVAOWhenSettingIndexBufferData();
void unbindVAOBeforeEnteringExternalSection();
@ -227,6 +233,10 @@ MeshGLTest::MeshGLTest() {
&MeshGLTest::addVertexBufferMultipleGaps,
&MeshGLTest::addVertexBufferMovedOutInstance,
&MeshGLTest::addVertexBufferTransferOwnwership,
&MeshGLTest::addVertexBufferInstancedTransferOwnwership,
&MeshGLTest::addVertexBufferDynamicTransferOwnwership,
&MeshGLTest::addVertexBufferInstancedDynamicTransferOwnwership,
&MeshGLTest::setIndexBuffer<GL::MeshIndexType>,
&MeshGLTest::setIndexBuffer<Magnum::MeshIndexType>,
@ -235,6 +245,10 @@ MeshGLTest::MeshGLTest() {
&MeshGLTest::setIndexBufferUnsignedInt,
&MeshGLTest::setIndexBufferMovedOutInstance,
&MeshGLTest::setIndexBufferTransferOwnership<GL::MeshIndexType>,
&MeshGLTest::setIndexBufferTransferOwnership<Magnum::MeshIndexType>,
&MeshGLTest::setIndexBufferRangeTransferOwnership<GL::MeshIndexType>,
&MeshGLTest::setIndexBufferRangeTransferOwnership<Magnum::MeshIndexType>,
&MeshGLTest::unbindVAOWhenSettingIndexBufferData,
&MeshGLTest::unbindVAOBeforeEnteringExternalSection,
@ -1663,6 +1677,126 @@ void MeshGLTest::addVertexBufferMovedOutInstance() {
CORRADE_COMPARE(out.str(), "GL::Mesh::addVertexBuffer(): empty or moved-out Buffer instance was passed\n");
}
void MeshGLTest::addVertexBufferTransferOwnwership() {
const Float data = 1.0f;
Buffer buffer;
buffer.setData({&data, 1}, BufferUsage::StaticDraw);
const GLuint id = buffer.id();
CORRADE_VERIFY(glIsBuffer(id));
{
Mesh mesh;
mesh.addVertexBuffer(buffer, 0, Attribute<0, Float>{});
CORRADE_VERIFY(buffer.id());
CORRADE_VERIFY(glIsBuffer(id));
}
CORRADE_VERIFY(glIsBuffer(id));
{
Mesh mesh;
mesh.addVertexBuffer(std::move(buffer), 0, Attribute<0, Float>{});
CORRADE_VERIFY(!buffer.id());
CORRADE_VERIFY(glIsBuffer(id));
}
CORRADE_VERIFY(!glIsBuffer(id));
}
void MeshGLTest::addVertexBufferInstancedTransferOwnwership() {
const Float data = 1.0f;
Buffer buffer;
buffer.setData({&data, 1}, BufferUsage::StaticDraw);
const GLuint id = buffer.id();
CORRADE_VERIFY(glIsBuffer(id));
{
Mesh mesh;
mesh.addVertexBufferInstanced(buffer, 1, 0, Attribute<0, Float>{});
CORRADE_VERIFY(buffer.id());
CORRADE_VERIFY(glIsBuffer(id));
}
CORRADE_VERIFY(glIsBuffer(id));
{
Mesh mesh;
mesh.addVertexBufferInstanced(std::move(buffer), 1, 0, Attribute<0, Float>{});
CORRADE_VERIFY(!buffer.id());
CORRADE_VERIFY(glIsBuffer(id));
}
CORRADE_VERIFY(!glIsBuffer(id));
}
void MeshGLTest::addVertexBufferDynamicTransferOwnwership() {
const Float data = 1.0f;
Buffer buffer;
buffer.setData({&data, 1}, BufferUsage::StaticDraw);
const GLuint id = buffer.id();
CORRADE_VERIFY(glIsBuffer(id));
{
Mesh mesh;
mesh.addVertexBuffer(buffer, 0, 4, DynamicAttribute{
DynamicAttribute::Kind::GenericNormalized, 0,
DynamicAttribute::Components::One,
DynamicAttribute::DataType::Float});
CORRADE_VERIFY(buffer.id());
CORRADE_VERIFY(glIsBuffer(id));
}
CORRADE_VERIFY(glIsBuffer(id));
{
Mesh mesh;
mesh.addVertexBuffer(std::move(buffer), 0, 4, DynamicAttribute{
DynamicAttribute::Kind::GenericNormalized, 0,
DynamicAttribute::Components::One,
DynamicAttribute::DataType::Float});
CORRADE_VERIFY(!buffer.id());
CORRADE_VERIFY(glIsBuffer(id));
}
CORRADE_VERIFY(!glIsBuffer(id));
}
void MeshGLTest::addVertexBufferInstancedDynamicTransferOwnwership() {
const Float data = 1.0f;
Buffer buffer;
buffer.setData({&data, 1}, BufferUsage::StaticDraw);
const GLuint id = buffer.id();
CORRADE_VERIFY(glIsBuffer(id));
{
Mesh mesh;
mesh.addVertexBufferInstanced(buffer, 1, 0, 4, DynamicAttribute{
DynamicAttribute::Kind::GenericNormalized, 0,
DynamicAttribute::Components::One,
DynamicAttribute::DataType::Float});
CORRADE_VERIFY(buffer.id());
CORRADE_VERIFY(glIsBuffer(id));
}
CORRADE_VERIFY(glIsBuffer(id));
{
Mesh mesh;
mesh.addVertexBufferInstanced(std::move(buffer), 1, 0, 4, DynamicAttribute{
DynamicAttribute::Kind::GenericNormalized, 0,
DynamicAttribute::Components::One,
DynamicAttribute::DataType::Float});
CORRADE_VERIFY(!buffer.id());
CORRADE_VERIFY(glIsBuffer(id));
}
CORRADE_VERIFY(!glIsBuffer(id));
}
namespace {
const Float indexedVertexData[] = {
0.0f, /* Offset */
@ -1829,6 +1963,70 @@ void MeshGLTest::setIndexBufferMovedOutInstance() {
CORRADE_COMPARE(out.str(), "GL::Mesh::setIndexBuffer(): empty or moved-out Buffer instance was passed\n");
}
template<class T> void MeshGLTest::setIndexBufferTransferOwnership() {
setTestCaseName(std::is_same<T, MeshIndexType>::value ?
"setIndexBufferTransferOwnership<GL::MeshIndexType>" :
"setIndexBufferTransferOwnership<Magnum::MeshIndexType>");
const UnsignedShort data = 0;
Buffer buffer;
buffer.setData({&data, 1}, BufferUsage::StaticDraw);
const GLuint id = buffer.id();
CORRADE_VERIFY(glIsBuffer(id));
{
Mesh mesh;
mesh.setIndexBuffer(buffer, 0, T::UnsignedShort);
CORRADE_VERIFY(buffer.id());
CORRADE_VERIFY(glIsBuffer(id));
}
CORRADE_VERIFY(glIsBuffer(id));
{
Mesh mesh;
mesh.setIndexBuffer(std::move(buffer), 0, T::UnsignedShort);
CORRADE_VERIFY(!buffer.id());
CORRADE_VERIFY(glIsBuffer(id));
}
CORRADE_VERIFY(!glIsBuffer(id));
}
template<class T> void MeshGLTest::setIndexBufferRangeTransferOwnership() {
setTestCaseName(std::is_same<T, MeshIndexType>::value ?
"setIndexBufferRangeTransferOwnership<GL::MeshIndexType>" :
"setIndexBufferRangeTransferOwnership<Magnum::MeshIndexType>");
const UnsignedShort data = 0;
Buffer buffer;
buffer.setData({&data, 1}, BufferUsage::StaticDraw);
const GLuint id = buffer.id();
CORRADE_VERIFY(glIsBuffer(id));
{
Mesh mesh;
mesh.setIndexBuffer(buffer, 0, T::UnsignedShort, 0, 1);
CORRADE_VERIFY(buffer.id());
CORRADE_VERIFY(glIsBuffer(id));
}
CORRADE_VERIFY(glIsBuffer(id));
{
Mesh mesh;
mesh.setIndexBuffer(std::move(buffer), 0, T::UnsignedShort, 0, 1);
CORRADE_VERIFY(!buffer.id());
CORRADE_VERIFY(glIsBuffer(id));
}
CORRADE_VERIFY(!glIsBuffer(id));
}
void MeshGLTest::unbindVAOWhenSettingIndexBufferData() {
#ifndef MAGNUM_TARGET_GLES
if(!Context::current().isExtensionSupported<Extensions::ARB::vertex_array_object>())

Loading…
Cancel
Save