Browse Source

Ability to wrap and release existing OpenGL objects.

Allows for better interaction with third-party libraries. I should
probably write a new documentation page about OpenGL wrapping.
pull/107/head
Vladimír Vondruš 11 years ago
parent
commit
ea1c335a2b
  1. 16
      src/Magnum/AbstractFramebuffer.cpp
  2. 9
      src/Magnum/AbstractFramebuffer.h
  3. 40
      src/Magnum/AbstractObject.h
  4. 9
      src/Magnum/AbstractQuery.cpp
  5. 22
      src/Magnum/AbstractQuery.h
  6. 53
      src/Magnum/AbstractTexture.cpp
  7. 32
      src/Magnum/AbstractTexture.h
  8. 36
      src/Magnum/Buffer.cpp
  9. 51
      src/Magnum/Buffer.h
  10. 21
      src/Magnum/BufferTexture.h
  11. 6
      src/Magnum/CubeMapTexture.cpp
  12. 21
      src/Magnum/CubeMapTexture.h
  13. 22
      src/Magnum/CubeMapTextureArray.h
  14. 2
      src/Magnum/DefaultFramebuffer.cpp
  15. 15
      src/Magnum/Framebuffer.cpp
  16. 44
      src/Magnum/Framebuffer.h
  17. 2
      src/Magnum/Magnum.h
  18. 29
      src/Magnum/Mesh.cpp
  19. 57
      src/Magnum/Mesh.h
  20. 23
      src/Magnum/MultisampleTexture.h
  21. 21
      src/Magnum/PrimitiveQuery.h
  22. 22
      src/Magnum/RectangleTexture.h
  23. 17
      src/Magnum/Renderbuffer.cpp
  24. 44
      src/Magnum/Renderbuffer.h
  25. 20
      src/Magnum/SampleQuery.h
  26. 17
      src/Magnum/Test/BufferGLTest.cpp
  27. 22
      src/Magnum/Test/BufferTextureGLTest.cpp
  28. 22
      src/Magnum/Test/CubeMapTextureArrayGLTest.cpp
  29. 19
      src/Magnum/Test/CubeMapTextureGLTest.cpp
  30. 22
      src/Magnum/Test/FramebufferGLTest.cpp
  31. 26
      src/Magnum/Test/MeshGLTest.cpp
  32. 53
      src/Magnum/Test/MultisampleTextureGLTest.cpp
  33. 25
      src/Magnum/Test/PrimitiveQueryGLTest.cpp
  34. 22
      src/Magnum/Test/RectangleTextureGLTest.cpp
  35. 22
      src/Magnum/Test/RenderbufferGLTest.cpp
  36. 35
      src/Magnum/Test/SampleQueryGLTest.cpp
  37. 47
      src/Magnum/Test/TextureArrayGLTest.cpp
  38. 64
      src/Magnum/Test/TextureGLTest.cpp
  39. 29
      src/Magnum/Test/TimeQueryGLTest.cpp
  40. 17
      src/Magnum/Test/TransformFeedbackGLTest.cpp
  41. 21
      src/Magnum/Texture.h
  42. 24
      src/Magnum/TextureArray.h
  43. 21
      src/Magnum/TimeQuery.h
  44. 14
      src/Magnum/TransformFeedback.cpp
  45. 43
      src/Magnum/TransformFeedback.h

16
src/Magnum/AbstractFramebuffer.cpp

@ -89,14 +89,14 @@ Int AbstractFramebuffer::maxDualSourceDrawBuffers() {
#endif
void AbstractFramebuffer::createIfNotAlready() {
if(_created) return;
if(_flags & ObjectFlag::Created) return;
/* glGen*() does not create the object, just reserves the name. Some
commands (such as glObjectLabel()) operate with IDs directly and they
require the object to be created. Binding the framebuffer finally
creates it. Also all EXT DSA functions implicitly create it. */
bindInternal();
CORRADE_INTERNAL_ASSERT(_created);
CORRADE_INTERNAL_ASSERT(_flags & ObjectFlag::Created);
}
void AbstractFramebuffer::bind() {
@ -141,7 +141,7 @@ void AbstractFramebuffer::bindImplementationDefault(FramebufferTarget target) {
} else CORRADE_ASSERT_UNREACHABLE();
/* Binding the framebuffer finally creates it */
_created = true;
_flags |= ObjectFlag::Created;
glBindFramebuffer(GLenum(target), _id);
}
@ -187,7 +187,7 @@ FramebufferTarget AbstractFramebuffer::bindImplementationDefault() {
state.readBinding = _id;
/* Binding the framebuffer finally creates it */
_created = true;
_flags |= ObjectFlag::Created;
glBindFramebuffer(GLenum(FramebufferTarget::Read), _id);
return FramebufferTarget::Read;
}
@ -361,7 +361,7 @@ GLenum AbstractFramebuffer::checkStatusImplementationDSA(const FramebufferTarget
}
GLenum AbstractFramebuffer::checkStatusImplementationDSAEXT(const FramebufferTarget target) {
_created = true;
_flags |= ObjectFlag::Created;
return glCheckNamedFramebufferStatusEXT(_id, GLenum(target));
}
#endif
@ -379,7 +379,7 @@ void AbstractFramebuffer::drawBuffersImplementationDSA(const GLsizei count, cons
}
void AbstractFramebuffer::drawBuffersImplementationDSAEXT(GLsizei count, const GLenum* buffers) {
_created = true;
_flags |= ObjectFlag::Created;
glFramebufferDrawBuffersEXT(_id, count, buffers);
}
#endif
@ -423,7 +423,7 @@ void AbstractFramebuffer::drawBufferImplementationDSA(const GLenum buffer) {
}
void AbstractFramebuffer::drawBufferImplementationDSAEXT(GLenum buffer) {
_created = true;
_flags |= ObjectFlag::Created;
glFramebufferDrawBufferEXT(_id, buffer);
}
#endif
@ -449,7 +449,7 @@ void AbstractFramebuffer::readBufferImplementationDSA(const GLenum buffer) {
}
void AbstractFramebuffer::readBufferImplementationDSAEXT(GLenum buffer) {
_created = true;
_flags |= ObjectFlag::Created;
glFramebufferReadBufferEXT(_id, buffer);
}
#endif

9
src/Magnum/AbstractFramebuffer.h

@ -32,8 +32,7 @@
#include <Corrade/Containers/EnumSet.h>
#include <Corrade/Utility/Macros.h>
#include "Magnum/Magnum.h"
#include "Magnum/OpenGL.h"
#include "Magnum/AbstractObject.h"
#include "Magnum/Math/Range.h"
namespace Magnum {
@ -403,7 +402,9 @@ class MAGNUM_EXPORT AbstractFramebuffer {
#else
protected:
#endif
explicit AbstractFramebuffer() = default;
explicit AbstractFramebuffer(): _flags{ObjectFlag::DeleteOnDestruction} {}
explicit AbstractFramebuffer(GLuint id, const Range2Di& viewport, ObjectFlags flags) noexcept: _id{id}, _viewport{viewport}, _flags{flags} {}
~AbstractFramebuffer() = default;
void MAGNUM_LOCAL createIfNotAlready();
@ -413,8 +414,8 @@ class MAGNUM_EXPORT AbstractFramebuffer {
void MAGNUM_LOCAL setViewportInternal();
GLuint _id;
bool _created; /* see createIfNotAlready() for details */
Range2Di _viewport;
ObjectFlags _flags;
private:
#ifndef MAGNUM_TARGET_GLES2

40
src/Magnum/AbstractObject.h

@ -30,7 +30,7 @@
*/
#include <string>
#include <Corrade/Containers/Containers.h>
#include <Corrade/Containers/EnumSet.h>
#include "Magnum/Magnum.h"
#include "Magnum/OpenGL.h"
@ -40,6 +40,42 @@ namespace Magnum {
namespace Implementation { struct DebugState; }
/**
@brief Object wrapping flag
@see @ref ObjectFlags, @ref Buffer::wrap(), @ref BufferTexture::wrap(),
@ref CubeMapTexture::wrap(), @ref CubeMapTextureArray::wrap(),
@ref Framebuffer::wrap(), @ref Mesh::wrap(),
@ref MultisampleTexture::wrap(), @ref PrimitiveQuery::wrap(),
@ref RectangleTexture::wrap(), @ref Renderbuffer::wrap(),
@ref SampleQuery::wrap(), @ref Texture::wrap(), @ref TextureArray::wrap(),
@ref TimeQuery::wrap(), @ref TransformFeedback::wrap()
*/
enum class ObjectFlag: UnsignedByte {
/**
* The object is known to be already created, either by using `glCreate*()`
* function or by binding object previously generated by `glGen*()`
* function. If you are not sure, don't specify this flag.
*/
Created = 1 << 0,
/** Delete the object on destruction. */
DeleteOnDestruction = 1 << 1
};
/**
@brief Object wrapping flags
@see @ref Buffer::wrap(), @ref BufferTexture::wrap(),
@ref CubeMapTexture::wrap(), @ref CubeMapTextureArray::wrap(),
@ref Framebuffer::wrap(), @ref Mesh::wrap(),
@ref MultisampleTexture::wrap(), @ref PrimitiveQuery::wrap(),
@ref RectangleTexture::wrap(), @ref Renderbuffer::wrap(),
@ref SampleQuery::wrap(), @ref Texture::wrap(), @ref TextureArray::wrap(),
@ref TimeQuery::wrap(), @ref TransformFeedback::wrap()
*/
typedef Containers::EnumSet<ObjectFlag> ObjectFlags;
/**
@brief Base for all OpenGL objects
*/
@ -80,6 +116,8 @@ class MAGNUM_EXPORT AbstractObject {
#endif
};
CORRADE_ENUMSET_OPERATORS(ObjectFlags)
}
#endif

9
src/Magnum/AbstractQuery.cpp

@ -36,19 +36,19 @@
namespace Magnum {
AbstractQuery::AbstractQuery(GLenum target): _target{target} {
AbstractQuery::AbstractQuery(GLenum target): _target{target}, _flags{ObjectFlag::DeleteOnDestruction} {
(this->*Context::current()->state().query->createImplementation)();
}
#ifdef MAGNUM_BUILD_DEPRECATED
AbstractQuery::AbstractQuery(): _target{} {
AbstractQuery::AbstractQuery(): _target{}, _flags{ObjectFlag::DeleteOnDestruction} {
createImplementationDefault();
}
#endif
AbstractQuery::~AbstractQuery() {
/* Moved out, nothing to do */
if(!_id) return;
/* Moved out or not deleting on destruction, nothing to do */
if(!_id || !(_flags & ObjectFlag::DeleteOnDestruction)) return;
#ifndef MAGNUM_TARGET_GLES2
glDeleteQueries(1, &_id);
@ -57,6 +57,7 @@ AbstractQuery::~AbstractQuery() {
#else
CORRADE_ASSERT_UNREACHABLE();
#endif
_flags |= ObjectFlag::Created;
}
void AbstractQuery::createImplementationDefault() {

22
src/Magnum/AbstractQuery.h

@ -69,6 +69,17 @@ class MAGNUM_EXPORT AbstractQuery: public AbstractObject {
/** @brief OpenGL query ID */
GLuint id() const { return _id; }
/**
* @brief Release OpenGL object
*
* Releases ownership of OpenGL query object and returns its ID so it
* is not deleted on destruction. The internal state is then equivalent
* to moved-from state.
* @see @ref PrimitiveQuery::wrap(), @ref SampleQuery::wrap(),
* @ref TimeQuery::wrap()
*/
GLuint release();
#ifndef MAGNUM_TARGET_WEBGL
/**
* @brief Query label
@ -153,7 +164,8 @@ class MAGNUM_EXPORT AbstractQuery: public AbstractObject {
* @brief Destructor
*
* Deletes assigned OpenGL query.
* @see @fn_gl{DeleteQueries}
* @see @ref PrimitiveQuery::wrap(), @ref SampleQuery::wrap(),
* @ref TimeQuery::wrap(), @ref release(), @fn_gl{DeleteQueries}
*/
~AbstractQuery();
@ -161,6 +173,7 @@ class MAGNUM_EXPORT AbstractQuery: public AbstractObject {
private:
#endif
explicit AbstractQuery(GLenum target);
explicit AbstractQuery(GLuint id, GLenum target, ObjectFlags flags) noexcept: _id{id}, _target{target}, _flags{flags} {}
#ifdef MAGNUM_BUILD_DEPRECATED
explicit AbstractQuery();
@ -179,6 +192,7 @@ class MAGNUM_EXPORT AbstractQuery: public AbstractObject {
GLuint _id;
GLenum _target;
ObjectFlags _flags;
};
#ifndef DOXYGEN_GENERATING_OUTPUT
@ -202,6 +216,12 @@ inline AbstractQuery& AbstractQuery::operator=(AbstractQuery&& other) noexcept {
return *this;
}
inline GLuint AbstractQuery::release() {
const GLuint id = _id;
_id = 0;
return id;
}
}
#else
#error this header is not available in WebGL 1.0 build

53
src/Magnum/AbstractTexture.cpp

@ -204,26 +204,25 @@ void AbstractTexture::bindImplementationMulti(const GLint firstTextureUnit, Cont
}
#endif
AbstractTexture::AbstractTexture(GLenum target): _target{target} {
AbstractTexture::AbstractTexture(GLenum target): _target{target}, _flags{ObjectFlag::DeleteOnDestruction} {
(this->*Context::current()->state().texture->createImplementation)();
CORRADE_INTERNAL_ASSERT(_id != Implementation::State::DisengagedBinding);
}
void AbstractTexture::createImplementationDefault() {
glGenTextures(1, &_id);
_created = false;
}
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::createImplementationDSA() {
glCreateTextures(_target, 1, &_id);
_created = true;
_flags |= ObjectFlag::Created;
}
#endif
AbstractTexture::~AbstractTexture() {
/* Moved out, nothing to do */
if(!_id) return;
/* Moved out or not deleting on destruction, nothing to do */
if(!_id || !(_flags & ObjectFlag::DeleteOnDestruction)) return;
/* Remove all bindings */
for(auto& binding: Context::current()->state().texture->bindings)
@ -233,7 +232,7 @@ AbstractTexture::~AbstractTexture() {
}
inline void AbstractTexture::createIfNotAlready() {
if(_created) return;
if(_flags & ObjectFlag::Created) return;
/* glGen*() does not create the object, just reserves the name. Some
commands (such as glBindTextures() or glObjectLabel()) operate with IDs
@ -241,7 +240,7 @@ inline void AbstractTexture::createIfNotAlready() {
to desired target finally creates it. Also all EXT DSA functions
implicitly create it. */
bindInternal();
CORRADE_INTERNAL_ASSERT(_created);
CORRADE_INTERNAL_ASSERT(_flags & ObjectFlag::Created);
}
#ifndef MAGNUM_TARGET_WEBGL
@ -276,7 +275,7 @@ void AbstractTexture::bindImplementationDefault(GLint textureUnit) {
glActiveTexture(GL_TEXTURE0 + (textureState.currentTextureUnit = textureUnit));
/* Binding the texture finally creates it */
_created = true;
_flags |= ObjectFlag::Created;
glBindTexture(_target, _id);
}
@ -291,7 +290,7 @@ void AbstractTexture::bindImplementationDSA(const GLint textureUnit) {
}
void AbstractTexture::bindImplementationDSAEXT(GLint textureUnit) {
_created = true;
_flags |= ObjectFlag::Created;
glBindMultiTextureEXT(GL_TEXTURE0 + textureUnit, _target, _id);
}
#endif
@ -430,7 +429,7 @@ void AbstractTexture::mipmapImplementationDSA() {
}
void AbstractTexture::mipmapImplementationDSAEXT() {
_created = true;
_flags |= ObjectFlag::Created;
glGenerateTextureMipmapEXT(_id, _target);
}
#endif
@ -457,7 +456,7 @@ void AbstractTexture::bindInternal() {
textureState.bindings[internalTextureUnit] = {_target, _id};
/* Binding the texture finally creates it */
_created = true;
_flags |= ObjectFlag::Created;
glBindTexture(_target, _id);
}
@ -873,7 +872,7 @@ void AbstractTexture::parameterImplementationDSA(const GLenum parameter, const G
}
void AbstractTexture::parameterImplementationDSAEXT(GLenum parameter, GLint value) {
_created = true;
_flags |= ObjectFlag::Created;
glTextureParameteriEXT(_id, _target, parameter, value);
}
#endif
@ -889,7 +888,7 @@ void AbstractTexture::parameterImplementationDSA(const GLenum parameter, const G
}
void AbstractTexture::parameterImplementationDSAEXT(GLenum parameter, GLfloat value) {
_created = true;
_flags |= ObjectFlag::Created;
glTextureParameterfEXT(_id, _target, parameter, value);
}
#endif
@ -906,7 +905,7 @@ void AbstractTexture::parameterImplementationDSA(const GLenum parameter, const G
}
void AbstractTexture::parameterImplementationDSAEXT(GLenum parameter, const GLint* values) {
_created = true;
_flags |= ObjectFlag::Created;
glTextureParameterivEXT(_id, _target, parameter, values);
}
#endif
@ -923,7 +922,7 @@ void AbstractTexture::parameterImplementationDSA(const GLenum parameter, const G
}
void AbstractTexture::parameterImplementationDSAEXT(GLenum parameter, const GLfloat* values) {
_created = true;
_flags |= ObjectFlag::Created;
glTextureParameterfvEXT(_id, _target, parameter, values);
}
#endif
@ -939,7 +938,7 @@ void AbstractTexture::parameterIImplementationDSA(const GLenum parameter, const
}
void AbstractTexture::parameterIImplementationDSAEXT(GLenum parameter, const GLuint* values) {
_created = true;
_flags |= ObjectFlag::Created;
glTextureParameterIuivEXT(_id, _target, parameter, values);
}
@ -953,7 +952,7 @@ void AbstractTexture::parameterIImplementationDSA(const GLenum parameter, const
}
void AbstractTexture::parameterIImplementationDSAEXT(GLenum parameter, const GLint* values) {
_created = true;
_flags |= ObjectFlag::Created;
glTextureParameterIivEXT(_id, _target, parameter, values);
}
#endif
@ -976,7 +975,7 @@ void AbstractTexture::getLevelParameterImplementationDSA(const GLint level, cons
}
void AbstractTexture::getLevelParameterImplementationDSAEXT(GLint level, GLenum parameter, GLint* values) {
_created = true;
_flags |= ObjectFlag::Created;
glGetTextureLevelParameterivEXT(_id, _target, level, parameter, values);
}
#endif
@ -1002,7 +1001,7 @@ void AbstractTexture::storageImplementationDSA(const GLsizei levels, const Textu
}
void AbstractTexture::storageImplementationDSAEXT(GLsizei levels, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size) {
_created = true;
_flags |= ObjectFlag::Created;
glTextureStorage1DEXT(_id, _target, levels, GLenum(internalFormat), size[0]);
}
#endif
@ -1071,7 +1070,7 @@ void AbstractTexture::storageImplementationDSA(const GLsizei levels, const Textu
}
void AbstractTexture::storageImplementationDSAEXT(GLsizei levels, TextureFormat internalFormat, const Vector2i& size) {
_created = true;
_flags |= ObjectFlag::Created;
glTextureStorage2DEXT(_id, _target, levels, GLenum(internalFormat), size.x(), size.y());
}
#endif
@ -1130,7 +1129,7 @@ void AbstractTexture::storageImplementationDSA(const GLsizei levels, const Textu
}
void AbstractTexture::storageImplementationDSAEXT(GLsizei levels, TextureFormat internalFormat, const Vector3i& size) {
_created = true;
_flags |= ObjectFlag::Created;
glTextureStorage3DEXT(_id, _target, levels, GLenum(internalFormat), size.x(), size.y(), size.z());
}
#endif
@ -1155,7 +1154,7 @@ void AbstractTexture::storageMultisampleImplementationDSA(const GLsizei samples,
}
void AbstractTexture::storageMultisampleImplementationDSAEXT(const GLsizei samples, const TextureFormat internalFormat, const Vector2i& size, const GLboolean fixedSampleLocations) {
_created = true;
_flags |= ObjectFlag::Created;
glTextureStorage2DMultisampleEXT(_id, _target, samples, GLenum(internalFormat), size.x(), size.y(), fixedSampleLocations);
}
@ -1174,7 +1173,7 @@ void AbstractTexture::storageMultisampleImplementationDSA(const GLsizei samples,
}
void AbstractTexture::storageMultisampleImplementationDSAEXT(const GLsizei samples, const TextureFormat internalFormat, const Vector3i& size, const GLboolean fixedSampleLocations) {
_created = true;
_flags |= ObjectFlag::Created;
glTextureStorage3DMultisampleEXT(_id, _target, samples, GLenum(internalFormat), size.x(), size.y(), size.z(), fixedSampleLocations);
}
#endif
@ -1190,7 +1189,7 @@ void AbstractTexture::getImageImplementationDSA(const GLint level, const ColorFo
}
void AbstractTexture::getImageImplementationDSAEXT(const GLint level, const ColorFormat format, const ColorType type, const std::size_t, GLvoid* const data) {
_created = true;
_flags |= ObjectFlag::Created;
glGetTextureImageEXT(_id, _target, level, GLenum(format), GLenum(type), data);
}
@ -1211,7 +1210,7 @@ void AbstractTexture::subImageImplementationDSA(const GLint level, const Math::V
}
void AbstractTexture::subImageImplementationDSAEXT(GLint level, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, ColorFormat format, ColorType type, const GLvoid* data) {
_created = true;
_flags |= ObjectFlag::Created;
glTextureSubImage1DEXT(_id, _target, level, offset[0], size[0], GLenum(format), GLenum(type), data);
}
#endif
@ -1227,7 +1226,7 @@ void AbstractTexture::subImageImplementationDSA(const GLint level, const Vector2
}
void AbstractTexture::subImageImplementationDSAEXT(GLint level, const Vector2i& offset, const Vector2i& size, ColorFormat format, ColorType type, const GLvoid* data) {
_created = true;
_flags |= ObjectFlag::Created;
glTextureSubImage2DEXT(_id, _target, level, offset.x(), offset.y(), size.x(), size.y(), GLenum(format), GLenum(type), data);
}
#endif
@ -1257,7 +1256,7 @@ void AbstractTexture::subImageImplementationDSA(const GLint level, const Vector3
}
void AbstractTexture::subImageImplementationDSAEXT(GLint level, const Vector3i& offset, const Vector3i& size, ColorFormat format, ColorType type, const GLvoid* data) {
_created = true;
_flags |= ObjectFlag::Created;
glTextureSubImage3DEXT(_id, _target, level, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z(), GLenum(format), GLenum(type), data);
}
#endif

32
src/Magnum/AbstractTexture.h

@ -259,7 +259,11 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject {
* @brief Destructor
*
* Deletes associated OpenGL texture.
* @see @fn_gl{DeleteTextures}
* @see @ref BufferTexture::wrap(), @ref CubeMapTexture::wrap(),
* @ref CubeMapTextureArray::wrap(),
* @ref MultisampleTexture::wrap(), @ref RectangleTexture::wrap(),
* @ref Texture::wrap(), @ref TextureArray::wrap(),
* @ref release(), @fn_gl{DeleteTextures}
*/
~AbstractTexture();
@ -272,6 +276,19 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject {
/** @brief OpenGL texture ID */
GLuint id() const { return _id; }
/**
* @brief Release OpenGL object
*
* Releases ownership of OpenGL texture object and returns its ID so it
* is not deleted on destruction. The internal state is then equivalent
* to moved-from state.
* @see @ref BufferTexture::wrap(), @ref CubeMapTexture::wrap(),
* @ref CubeMapTextureArray::wrap(),
* @ref MultisampleTexture::wrap(), @ref RectangleTexture::wrap(),
* @ref Texture::wrap(), @ref TextureArray::wrap()
*/
GLuint release();
#ifndef MAGNUM_TARGET_WEBGL
/**
* @brief Texture label
@ -335,6 +352,7 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject {
template<UnsignedInt textureDimensions> struct DataHelper {};
explicit AbstractTexture(GLenum target);
explicit AbstractTexture(GLuint id, GLenum target, ObjectFlags flags) noexcept: _target{target}, _id{id}, _flags{flags} {}
#ifndef MAGNUM_TARGET_WEBGL
AbstractTexture& setLabelInternal(Containers::ArrayReference<const char> label);
@ -556,7 +574,7 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject {
ColorType MAGNUM_LOCAL imageTypeForInternalFormat(TextureFormat internalFormat);
GLuint _id;
bool _created; /* see createIfNotAlready() for details */
ObjectFlags _flags;
};
#ifndef DOXYGEN_GENERATING_OUTPUT
@ -670,7 +688,7 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<3> {
};
#endif
inline AbstractTexture::AbstractTexture(AbstractTexture&& other) noexcept: _target{other._target}, _id{other._id}, _created{other._created} {
inline AbstractTexture::AbstractTexture(AbstractTexture&& other) noexcept: _target{other._target}, _id{other._id}, _flags{other._flags} {
other._id = 0;
}
@ -678,10 +696,16 @@ inline AbstractTexture& AbstractTexture::operator=(AbstractTexture&& other) noex
using std::swap;
swap(_target, other._target);
swap(_id, other._id);
swap(_created, other._created);
swap(_flags, other._flags);
return *this;
}
inline GLuint AbstractTexture::release() {
const GLuint id = _id;
_id = 0;
return id;
}
}
#endif

36
src/Magnum/Buffer.cpp

@ -184,7 +184,7 @@ void Buffer::copy(Buffer& read, Buffer& write, const GLintptr readOffset, const
}
#endif
Buffer::Buffer(const TargetHint targetHint): _targetHint{targetHint}
Buffer::Buffer(const TargetHint targetHint): _targetHint{targetHint}, _flags{ObjectFlag::DeleteOnDestruction}
#ifdef CORRADE_TARGET_NACL
, _mappedBuffer{nullptr}
#endif
@ -195,19 +195,18 @@ Buffer::Buffer(const TargetHint targetHint): _targetHint{targetHint}
void Buffer::createImplementationDefault() {
glGenBuffers(1, &_id);
_created = false;
}
#ifndef MAGNUM_TARGET_GLES
void Buffer::createImplementationDSA() {
glCreateBuffers(1, &_id);
_created = true;
_flags |= ObjectFlag::Created;
}
#endif
Buffer::~Buffer() {
/* Moved out, nothing to do */
if(!_id) return;
/* Moved out or not deleting on destruction, nothing to do */
if(!_id || !(_flags & ObjectFlag::DeleteOnDestruction)) return;
GLuint* bindings = Context::current()->state().buffer->bindings;
@ -219,7 +218,7 @@ Buffer::~Buffer() {
}
inline void Buffer::createIfNotAlready() {
if(_created) return;
if(_flags & ObjectFlag::Created) return;
/* glGen*() does not create the object, just reserves the name. Some
commands (such as glInvalidateBufferData() or glObjectLabel()) operate
@ -227,7 +226,7 @@ inline void Buffer::createIfNotAlready() {
buffer finally creates it. Also all EXT DSA functions implicitly create
it. */
bindSomewhereInternal(_targetHint);
CORRADE_INTERNAL_ASSERT(_created);
CORRADE_INTERNAL_ASSERT(_flags & ObjectFlag::Created);
}
#ifndef MAGNUM_TARGET_WEBGL
@ -260,7 +259,7 @@ void Buffer::bindInternal(const TargetHint target, Buffer* const buffer) {
/* Bind the buffer otherwise, which will also finally create it */
bound = id;
if(buffer) buffer->_created = true;
if(buffer) buffer->_flags |= ObjectFlag::Created;
glBindBuffer(GLenum(target), id);
}
@ -278,7 +277,7 @@ auto Buffer::bindSomewhereInternal(const TargetHint hint) -> TargetHint {
/* Bind the buffer to hint target otherwise */
hintBinding = _id;
_created = true;
_flags |= ObjectFlag::Created;
glBindBuffer(GLenum(hint), _id);
return hint;
}
@ -443,7 +442,8 @@ void Buffer::copyImplementationDSA(Buffer& read, Buffer& write, const GLintptr r
}
void Buffer::copyImplementationDSAEXT(Buffer& read, Buffer& write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
read._created = write._created = true;
read._flags |= ObjectFlag::Created;
write._flags |= ObjectFlag::Created;
glNamedCopyBufferSubDataEXT(read._id, write._id, readOffset, writeOffset, size);
}
#endif
@ -459,7 +459,7 @@ void Buffer::getParameterImplementationDSA(const GLenum value, GLint* const data
}
void Buffer::getParameterImplementationDSAEXT(const GLenum value, GLint* const data) {
_created = true;
_flags |= ObjectFlag::Created;
glGetNamedBufferParameterivEXT(_id, value, data);
}
#endif
@ -474,7 +474,7 @@ void Buffer::getSubDataImplementationDSA(const GLintptr offset, const GLsizeiptr
}
void Buffer::getSubDataImplementationDSAEXT(const GLintptr offset, const GLsizeiptr size, GLvoid* const data) {
_created = true;
_flags |= ObjectFlag::Created;
glGetNamedBufferSubDataEXT(_id, offset, size, data);
}
#endif
@ -489,7 +489,7 @@ void Buffer::dataImplementationDSA(const GLsizeiptr size, const GLvoid* const da
}
void Buffer::dataImplementationDSAEXT(GLsizeiptr size, const GLvoid* data, BufferUsage usage) {
_created = true;
_flags |= ObjectFlag::Created;
glNamedBufferDataEXT(_id, size, data, GLenum(usage));
}
#endif
@ -504,7 +504,7 @@ void Buffer::subDataImplementationDSA(const GLintptr offset, const GLsizeiptr si
}
void Buffer::subDataImplementationDSAEXT(GLintptr offset, GLsizeiptr size, const GLvoid* data) {
_created = true;
_flags |= ObjectFlag::Created;
glNamedBufferSubDataEXT(_id, offset, size, data);
}
#endif
@ -545,7 +545,7 @@ void* Buffer::mapImplementationDSA(const MapAccess access) {
}
void* Buffer::mapImplementationDSAEXT(MapAccess access) {
_created = true;
_flags |= ObjectFlag::Created;
return glMapNamedBufferEXT(_id, GLenum(access));
}
#endif
@ -569,7 +569,7 @@ void* Buffer::mapRangeImplementationDSA(const GLintptr offset, const GLsizeiptr
}
void* Buffer::mapRangeImplementationDSAEXT(GLintptr offset, GLsizeiptr length, MapFlags access) {
_created = true;
_flags |= ObjectFlag::Created;
return glMapNamedBufferRangeEXT(_id, offset, length, GLenum(access));
}
#endif
@ -592,7 +592,7 @@ void Buffer::flushMappedRangeImplementationDSA(const GLintptr offset, const GLsi
}
void Buffer::flushMappedRangeImplementationDSAEXT(GLintptr offset, GLsizeiptr length) {
_created = true;
_flags |= ObjectFlag::Created;
glFlushMappedNamedBufferRangeEXT(_id, offset, length);
}
#endif
@ -613,7 +613,7 @@ bool Buffer::unmapImplementationDSA() {
}
bool Buffer::unmapImplementationDSAEXT() {
_created = true;
_flags |= ObjectFlag::Created;
return glUnmapNamedBufferEXT(_id);
}
#endif

51
src/Magnum/Buffer.h

@ -820,6 +820,28 @@ class MAGNUM_EXPORT Buffer: public AbstractObject {
static void copy(Buffer& read, Buffer& write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
#endif
/**
* @brief Wrap existing OpenGL buffer object
* @param id OpenGL buffer ID
* @param targetHint Target hint, see @ref setTargetHint() for more
* information
* @param flags Object creation flags
*
* The @p id is expected to be of an existing OpenGL buffer object.
* Unlike buffer created using constructor, the OpenGL object is by
* default not deleted on destruction, use @p flags for different
* behavior.
* @see @ref release()
*/
static Buffer wrap(GLuint id, TargetHint targetHint = TargetHint::Array, ObjectFlags flags = {}) {
return Buffer{id, targetHint, flags};
}
/** @overload */
static Buffer wrap(GLuint id, ObjectFlags flags) {
return Buffer(id, TargetHint::Array, flags);
}
/**
* @brief Constructor
* @param targetHint Target hint, see @ref setTargetHint() for more
@ -828,7 +850,8 @@ class MAGNUM_EXPORT Buffer: public AbstractObject {
* Creates new OpenGL buffer object. If @extension{ARB,direct_state_access}
* (part of OpenGL 4.5) is not available, the buffer is created on
* first use.
* @see @fn_gl{CreateBuffers}, eventually @fn_gl{GenBuffers}
* @see @ref wrap(), @fn_gl{CreateBuffers}, eventually
* @fn_gl{GenBuffers}
*/
explicit Buffer(TargetHint targetHint = TargetHint::Array);
@ -850,7 +873,7 @@ class MAGNUM_EXPORT Buffer: public AbstractObject {
* @brief Destructor
*
* Deletes associated OpenGL buffer object.
* @see @fn_gl{DeleteBuffers}
* @see @ref wrap(), @ref release(), @fn_gl{DeleteBuffers}
*/
~Buffer();
@ -863,6 +886,16 @@ class MAGNUM_EXPORT Buffer: public AbstractObject {
/** @brief OpenGL buffer ID */
GLuint id() const { return _id; }
/**
* @brief Release OpenGL object
*
* Releases ownership of OpenGL buffer object and returns its ID so it
* is not deleted on destruction. The internal state is then equivalent
* to moved-from state.
* @see @ref wrap()
*/
GLuint release();
#ifndef MAGNUM_TARGET_WEBGL
/**
* @brief Buffer label
@ -1294,6 +1327,8 @@ class MAGNUM_EXPORT Buffer: public AbstractObject {
#endif
#endif
explicit Buffer(GLuint id, TargetHint targetHint, ObjectFlags flags) noexcept: _id{id}, _targetHint{targetHint}, _flags{flags} {}
void MAGNUM_LOCAL createImplementationDefault();
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL createImplementationDSA();
@ -1374,7 +1409,7 @@ class MAGNUM_EXPORT Buffer: public AbstractObject {
#ifdef CORRADE_TARGET_NACL
void* _mappedBuffer;
#endif
bool _created; /* see createIfNotAlready() for details */
ObjectFlags _flags;
};
#ifndef MAGNUM_TARGET_WEBGL
@ -1393,7 +1428,7 @@ inline Buffer::Buffer(Buffer&& other) noexcept: _id{other._id}, _targetHint{othe
#ifdef CORRADE_TARGET_NACL
_mappedBuffer{other._mappedBuffer},
#endif
_created{other._created}
_flags{other._flags}
{
other._id = 0;
#ifdef CORRADE_TARGET_NACL
@ -1408,10 +1443,16 @@ inline Buffer& Buffer::operator=(Buffer&& other) noexcept {
#ifdef CORRADE_TARGET_NACL
swap(_mappedBuffer, other._mappedBuffer);
#endif
swap(_created, other._created);
swap(_flags, other._flags);
return *this;
}
inline GLuint Buffer::release() {
const GLuint id = _id;
_id = 0;
return id;
}
#ifndef MAGNUM_TARGET_GLES
template<class T> Containers::Array<T> inline Buffer::data() {
const Int bufferSize = size();

21
src/Magnum/BufferTexture.h

@ -223,14 +223,29 @@ class MAGNUM_EXPORT BufferTexture: public AbstractTexture {
*/
static Int offsetAlignment();
/**
* @brief Wrap existing OpenGL buffer texture object
* @param id OpenGL buffer texture ID
* @param flags Object creation flags
*
* The @p id is expected to be of an existing OpenGL texture object
* with target @def_gl{TEXTURE_BUFFER}. Unlike texture created using
* constructor, the OpenGL object is by default not deleted on
* destruction, use @p flags for different behavior.
* @see @ref release()
*/
static BufferTexture wrap(GLuint id, ObjectFlags flags = {}) {
return BufferTexture{id, flags};
}
/**
* @brief Constructor
*
* Creates new OpenGL texture object. If @extension{ARB,direct_state_access}
* (part of OpenGL 4.5) is not available, the texture is created on
* first use.
* @see @fn_gl{CreateTextures} with @def_gl{TEXTURE_BUFFER}, eventually
* @fn_gl{GenTextures}
* @see @ref wrap(), @fn_gl{CreateTextures} with @def_gl{TEXTURE_BUFFER},
* eventually @fn_gl{GenTextures}
*/
explicit BufferTexture(): AbstractTexture(GL_TEXTURE_BUFFER) {}
@ -288,6 +303,8 @@ class MAGNUM_EXPORT BufferTexture: public AbstractTexture {
#endif
private:
explicit BufferTexture(GLuint id, ObjectFlags flags): AbstractTexture{id, GL_TEXTURE_BUFFER, flags} {}
void MAGNUM_LOCAL setBufferImplementationDefault(BufferTextureFormat internalFormat, Buffer& buffer);
void MAGNUM_LOCAL setBufferImplementationDSA(BufferTextureFormat internalFormat, Buffer& buffer);
void MAGNUM_LOCAL setBufferImplementationDSAEXT(BufferTextureFormat internalFormat, Buffer& buffer);

6
src/Magnum/CubeMapTexture.cpp

@ -171,7 +171,7 @@ Vector2i CubeMapTexture::getImageSizeImplementationDSA(const Int level) {
}
Vector2i CubeMapTexture::getImageSizeImplementationDSAEXT(const Int level) {
_created = true;
_flags |= ObjectFlag::Created;
Vector2i size;
glGetTextureLevelParameterivEXT(_id, GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, GL_TEXTURE_WIDTH, &size.x());
glGetTextureLevelParameterivEXT(_id, GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, GL_TEXTURE_HEIGHT, &size.y());
@ -191,7 +191,7 @@ void CubeMapTexture::getImageImplementationDSA(const Coordinate coordinate, cons
}
void CubeMapTexture::getImageImplementationDSAEXT(const Coordinate coordinate, const GLint level, const Vector2i&, const ColorFormat format, const ColorType type, std::size_t, GLvoid* const data) {
_created = true;
_flags |= ObjectFlag::Created;
glGetTextureImageEXT(_id, GLenum(coordinate), level, GLenum(format), GLenum(type), data);
}
@ -212,7 +212,7 @@ void CubeMapTexture::subImageImplementationDSA(const Coordinate coordinate, cons
}
void CubeMapTexture::subImageImplementationDSAEXT(const Coordinate coordinate, const GLint level, const Vector2i& offset, const Vector2i& size, const ColorFormat format, const ColorType type, const GLvoid* const data) {
_created = true;
_flags |= ObjectFlag::Created;
glTextureSubImage2DEXT(_id, GLenum(coordinate), level, offset.x(), offset.y(), size.x(), size.y(), GLenum(format), GLenum(type), data);
}
#endif

21
src/Magnum/CubeMapTexture.h

@ -102,14 +102,29 @@ class MAGNUM_EXPORT CubeMapTexture: public AbstractTexture {
*/
static Vector2i maxSize();
/**
* @brief Wrap existing OpenGL cube map texture object
* @param id OpenGL cube map texture ID
* @param flags Object creation flags
*
* The @p id is expected to be of an existing OpenGL texture object
* with target @def_gl{TEXTURE_CUBE_MAP}. Unlike texture created using
* constructor, the OpenGL object is by default not deleted on
* destruction, use @p flags for different behavior.
* @see @ref release()
*/
static CubeMapTexture wrap(GLuint id, ObjectFlags flags = {}) {
return CubeMapTexture{id, flags};
}
/**
* @brief Constructor
*
* Creates new OpenGL texture object. If @extension{ARB,direct_state_access}
* (part of OpenGL 4.5) is not available, the texture is created on
* first use.
* @see @fn_gl{CreateTextures} with @def_gl{TEXTURE_CUBE_MAP},
* eventually @fn_gl{GenTextures}
* @see @ref wrap(), @fn_gl{CreateTextures} with
* @def_gl{TEXTURE_CUBE_MAP}, eventually @fn_gl{GenTextures}
*/
explicit CubeMapTexture(): AbstractTexture(GL_TEXTURE_CUBE_MAP) {}
@ -692,6 +707,8 @@ class MAGNUM_EXPORT CubeMapTexture: public AbstractTexture {
#endif
private:
explicit CubeMapTexture(GLuint id, ObjectFlags flags) noexcept: AbstractTexture{id, GL_TEXTURE_CUBE_MAP, flags} {}
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
Vector2i MAGNUM_LOCAL getImageSizeImplementationDefault(Int level);
#ifndef MAGNUM_TARGET_GLES

22
src/Magnum/CubeMapTextureArray.h

@ -95,14 +95,29 @@ class MAGNUM_EXPORT CubeMapTextureArray: public AbstractTexture {
*/
static Vector3i maxSize();
/**
* @brief Wrap existing OpenGL cube map array texture object
* @param id OpenGL cube map array texture ID
* @param flags Object creation flags
*
* The @p id is expected to be of an existing OpenGL texture object
* with target @def_gl{TEXTURE_CUBE_MAP_ARRAY}. Unlike texture created
* using constructor, the OpenGL object is by default not deleted on
* destruction, use @p flags for different behavior.
* @see @ref release()
*/
static CubeMapTextureArray wrap(GLuint id, ObjectFlags flags = {}) {
return CubeMapTextureArray{id, flags};
}
/**
* @brief Constructor
*
* Creates new OpenGL texture object. If @extension{ARB,direct_state_access}
* (part of OpenGL 4.5) is not available, the texture is created on
* first use.
* @see @fn_gl{CreateTextures} with @def_gl{TEXTURE_CUBE_MAP_ARRAY},
* eventually @fn_gl{GenTextures}
* @see @ref wrap(), @fn_gl{CreateTextures} with
* @def_gl{TEXTURE_CUBE_MAP_ARRAY}, eventually @fn_gl{GenTextures}
*/
explicit CubeMapTextureArray(): AbstractTexture(GL_TEXTURE_CUBE_MAP_ARRAY) {}
@ -499,6 +514,9 @@ class MAGNUM_EXPORT CubeMapTextureArray: public AbstractTexture {
return *this;
}
#endif
private:
explicit CubeMapTextureArray(GLuint id, ObjectFlags flags) noexcept: AbstractTexture{id, GL_TEXTURE_CUBE_MAP_ARRAY, flags} {}
};
}

2
src/Magnum/DefaultFramebuffer.cpp

@ -38,7 +38,7 @@ DefaultFramebuffer defaultFramebuffer;
DefaultFramebuffer::DefaultFramebuffer() {
_id = 0;
_created = true;
_flags |= ObjectFlag::Created;
}
DefaultFramebuffer::Status DefaultFramebuffer::checkStatus(const FramebufferTarget target) {

15
src/Magnum/Framebuffer.cpp

@ -103,19 +103,18 @@ Framebuffer::Framebuffer(const Range2Di& viewport) {
void Framebuffer::createImplementationDefault() {
glGenFramebuffers(1, &_id);
_created = false;
}
#ifndef MAGNUM_TARGET_GLES
void Framebuffer::createImplementationDSA() {
glCreateFramebuffers(1, &_id);
_created = true;
_flags |= ObjectFlag::Created;
}
#endif
Framebuffer::~Framebuffer() {
/* Moved out, nothing to do */
if(!_id) return;
/* Moved out or not deleting on destruction, nothing to do */
if(!_id || !(_flags & ObjectFlag::DeleteOnDestruction)) return;
/* If bound, remove itself from state */
Implementation::FramebufferState& state = *Context::current()->state().framebuffer;
@ -305,7 +304,7 @@ void Framebuffer::renderbufferImplementationDSA(const BufferAttachment attachmen
}
void Framebuffer::renderbufferImplementationDSAEXT(BufferAttachment attachment, Renderbuffer& renderbuffer) {
_created = true;
_flags |= ObjectFlag::Created;
glNamedFramebufferRenderbufferEXT(_id, GLenum(attachment), GL_RENDERBUFFER, renderbuffer.id());
}
@ -318,7 +317,7 @@ void Framebuffer::texture1DImplementationDSA(const BufferAttachment attachment,
}
void Framebuffer::texture1DImplementationDSAEXT(BufferAttachment attachment, GLuint textureId, GLint mipLevel) {
_created = true;
_flags |= ObjectFlag::Created;
glNamedFramebufferTexture1DEXT(_id, GLenum(attachment), GL_TEXTURE_1D, textureId, mipLevel);
}
#endif
@ -333,7 +332,7 @@ void Framebuffer::texture2DImplementationDSA(const BufferAttachment attachment,
}
void Framebuffer::texture2DImplementationDSAEXT(BufferAttachment attachment, GLenum textureTarget, GLuint textureId, GLint mipLevel) {
_created = true;
_flags |= ObjectFlag::Created;
glNamedFramebufferTexture2DEXT(_id, GLenum(attachment), textureTarget, textureId, mipLevel);
}
#endif
@ -360,7 +359,7 @@ void Framebuffer::textureLayerImplementationDSA(const BufferAttachment attachmen
}
void Framebuffer::textureLayerImplementationDSAEXT(BufferAttachment attachment, GLuint textureId, GLint mipLevel, GLint layer) {
_created = true;
_flags |= ObjectFlag::Created;
glNamedFramebufferTextureLayerEXT(_id, GLenum(attachment), textureId, mipLevel, layer);
}
#endif

44
src/Magnum/Framebuffer.h

@ -318,14 +318,30 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje
*/
static Int maxColorAttachments();
/**
* @brief Wrap existing OpenGL framebuffer object
* @param id OpenGL framebuffer ID
* @param viewport Viewport to use with this framebuffer
* @param flags Object creation flags
*
* The @p id is expected to be of an existing OpenGL framebuffer
* object. Unlike framebuffer created using constructor, the OpenGL
* object is by default not deleted on destruction, use @p flags for
* different behavior.
* @see @ref release()
*/
static Framebuffer wrap(GLuint id, const Range2Di& viewport, ObjectFlags flags = {}) {
return Framebuffer{id, viewport, flags};
}
/**
* @brief Constructor
*
* Generates new OpenGL framebuffer object. If @extension{ARB,direct_state_access}
* (part of OpenGL 4.5) is not available, the framebuffer is created on
* first use.
* @see @ref setViewport(), @fn_gl{CreateFramebuffers}, eventually
* @fn_gl{GenFramebuffers}
* @see @ref setViewport(), @ref wrap(), @fn_gl{CreateFramebuffers},
* eventually @fn_gl{GenFramebuffers}
*/
explicit Framebuffer(const Range2Di& viewport);
@ -339,7 +355,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje
* @brief Destructor
*
* Deletes associated OpenGL framebuffer object.
* @see @fn_gl{DeleteFramebuffers}
* @see @ref wrap(), @ref release(), @fn_gl{DeleteFramebuffers}
*/
~Framebuffer();
@ -352,6 +368,16 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje
/** @brief OpenGL framebuffer ID */
GLuint id() const { return _id; }
/**
* @brief Release OpenGL object
*
* Releases ownership of OpenGL framebuffer object and returns its ID
* so it is not deleted on destruction. The internal state is then
* equivalent to moved-from state.
* @see @ref wrap()
*/
GLuint release();
#ifndef MAGNUM_TARGET_WEBGL
/**
* @brief Framebuffer label
@ -716,6 +742,8 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje
#endif
private:
explicit Framebuffer(GLuint id, const Range2Di& viewport, ObjectFlags flags) noexcept: AbstractFramebuffer{id, viewport, flags} {}
void MAGNUM_LOCAL createImplementationDefault();
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL createImplementationDSA();
@ -758,7 +786,7 @@ Debug MAGNUM_EXPORT operator<<(Debug debug, Framebuffer::Status value);
inline Framebuffer::Framebuffer(Framebuffer&& other) noexcept {
_id = other._id;
_viewport = other._viewport;
_created = other._created;
_flags = other._flags;
other._id = 0;
other._viewport = {};
}
@ -767,10 +795,16 @@ inline Framebuffer& Framebuffer::operator=(Framebuffer&& other) noexcept {
using std::swap;
swap(_id, other._id);
swap(_viewport, other._viewport);
swap(_created, other._created);
swap(_flags, other._flags);
return *this;
}
inline GLuint Framebuffer::release() {
const GLuint id = _id;
_id = 0;
return id;
}
}
#endif

2
src/Magnum/Magnum.h

@ -494,6 +494,8 @@ typedef MultisampleTexture<3> MultisampleTexture2DArray;
#endif
#endif
/* ObjectFlag, ObjectFlags are used only in conjunction with *::wrap() function */
class PrimitiveQuery;
class SampleQuery;
class TimeQuery;

29
src/Magnum/Mesh.cpp

@ -107,7 +107,7 @@ std::size_t Mesh::indexSize(IndexType type) {
CORRADE_ASSERT_UNREACHABLE();
}
Mesh::Mesh(const MeshPrimitive primitive): _primitive{primitive}, _count{0}, _baseVertex{0}, _instanceCount{1},
Mesh::Mesh(const MeshPrimitive primitive): _primitive{primitive}, _flags{ObjectFlag::DeleteOnDestruction}, _count{0}, _baseVertex{0}, _instanceCount{1},
#ifndef MAGNUM_TARGET_GLES
_baseInstance{0},
#endif
@ -120,8 +120,8 @@ Mesh::Mesh(const MeshPrimitive primitive): _primitive{primitive}, _count{0}, _ba
}
Mesh::~Mesh() {
/* Moved out, nothing to do */
if(!_id) return;
/* Moved out or not deleting on destruction, nothing to do */
if(!_id || !(_flags & ObjectFlag::DeleteOnDestruction)) return;
/* Remove current vao from the state */
GLuint& current = Context::current()->state().mesh->currentVAO;
@ -130,7 +130,7 @@ Mesh::~Mesh() {
(this->*Context::current()->state().mesh->destroyImplementation)();
}
Mesh::Mesh(Mesh&& other) noexcept: _id(other._id), _created{other._created}, _primitive(other._primitive), _count(other._count), _baseVertex{other._baseVertex}, _instanceCount{other._instanceCount},
Mesh::Mesh(Mesh&& other) noexcept: _id(other._id), _primitive(other._primitive), _flags{other._flags}, _count(other._count), _baseVertex{other._baseVertex}, _instanceCount{other._instanceCount},
#ifndef MAGNUM_TARGET_GLES
_baseInstance{other._baseInstance},
#endif
@ -151,7 +151,7 @@ Mesh::Mesh(Mesh&& other) noexcept: _id(other._id), _created{other._created}, _pr
Mesh& Mesh::operator=(Mesh&& other) noexcept {
using std::swap;
swap(_id, other._id);
swap(_created, other._created);
swap(_flags, other._flags);
swap(_primitive, other._primitive);
swap(_count, other._count);
swap(_baseVertex, other._baseVertex);
@ -178,15 +178,15 @@ Mesh& Mesh::operator=(Mesh&& other) noexcept {
}
inline void Mesh::createIfNotAlready() {
/* If VAO extension is not available, _created is always true */
if(_created) return;
/* If VAO extension is not available, the following is always true */
if(_flags & ObjectFlag::Created) return;
/* glGen*() does not create the object, just reserves the name. Some
commands (such as glObjectLabel()) operate with IDs directly and they
require the object to be created. Binding the VAO finally creates it.
Also all EXT DSA functions implicitly create it. */
bindVAO();
CORRADE_INTERNAL_ASSERT(_created);
CORRADE_INTERNAL_ASSERT(_flags & ObjectFlag::Created);
}
#ifndef MAGNUM_TARGET_WEBGL
@ -353,7 +353,7 @@ void Mesh::bindVAO() {
GLuint& current = Context::current()->state().mesh->currentVAO;
if(current != _id) {
/* Binding the VAO finally creates it */
_created = true;
_flags |= ObjectFlag::Created;
#ifndef MAGNUM_TARGET_GLES2
glBindVertexArray(current = _id);
#elif !defined(CORRADE_TARGET_NACL)
@ -366,7 +366,7 @@ void Mesh::bindVAO() {
void Mesh::createImplementationDefault() {
_id = 0;
_created = true;
_flags |= ObjectFlag::Created;
}
void Mesh::createImplementationVAO() {
@ -377,14 +377,13 @@ void Mesh::createImplementationVAO() {
#else
CORRADE_ASSERT_UNREACHABLE();
#endif
_created = false;
CORRADE_INTERNAL_ASSERT(_id != Implementation::State::DisengagedBinding);
}
#ifndef MAGNUM_TARGET_GLES
void Mesh::createImplementationVAODSA() {
glCreateVertexArrays(1, &_id);
_created = true;
_flags |= ObjectFlag::Created;
}
#endif
@ -425,7 +424,7 @@ void Mesh::attributePointerImplementationVAO(const GenericAttribute& attribute)
#ifndef MAGNUM_TARGET_GLES
void Mesh::attributePointerImplementationDSAEXT(const GenericAttribute& attribute) {
_created = true;
_flags |= ObjectFlag::Created;
glEnableVertexArrayAttribEXT(_id, attribute.location);
glVertexArrayVertexAttribOffsetEXT(_id, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.normalized, attribute.stride, attribute.offset);
if(attribute.divisor)
@ -462,7 +461,7 @@ void Mesh::attributePointerImplementationVAO(const IntegerAttribute& attribute)
#ifndef MAGNUM_TARGET_GLES
void Mesh::attributePointerImplementationDSAEXT(const IntegerAttribute& attribute) {
_created = true;
_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)
@ -493,7 +492,7 @@ void Mesh::attributePointerImplementationVAO(const LongAttribute& attribute) {
}
void Mesh::attributePointerImplementationDSAEXT(const LongAttribute& attribute) {
_created = true;
_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)

57
src/Magnum/Mesh.h

@ -425,6 +425,32 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
*/
static std::size_t indexSize(IndexType type);
/**
* @brief Wrap existing OpenGL vertex array object
* @param id OpenGL vertex array ID
* @param primitive Primitive type
* @param flags Object creation flags
*
* The @p id is expected to be of an existing OpenGL vertex array
* object. Unlike vertex array created using constructor, the OpenGL
* object is by default not deleted on destruction, use @p flags for
* different behavior.
* @see @ref release()
* @requires_gl30 Extension @extension{ARB,vertex_array_object}
* @requires_gles30 Extension @es_extension{OES,vertex_array_object} in
* OpenGL ES 2.0.
* @requires_webgl20 Extension @webgl_extension{OES,vertex_array_object}
* in WebGL 1.0.
*/
static Mesh wrap(GLuint id, MeshPrimitive primitive = MeshPrimitive::Triangles, ObjectFlags flags = {}) {
return Mesh{id, primitive, flags};
}
/** @overload */
static Mesh wrap(GLuint id, ObjectFlags flags) {
return wrap(id, MeshPrimitive::Triangles, flags);
}
/**
* @brief Constructor
* @param primitive Primitive type
@ -435,8 +461,8 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
* available, vertex array object is created. If @extension{ARB,direct_state_access}
* (part of OpenGL 4.5) is not available, the vertex array object is
* created on first use.
* @see @ref setPrimitive(), @ref setCount(), @fn_gl{CreateVertexArrays},
* eventually @fn_gl{GenVertexArrays}
* @see @ref setPrimitive(), @ref setCount(), @ref wrap(),
* @fn_gl{CreateVertexArrays}, eventually @fn_gl{GenVertexArrays}
*/
explicit Mesh(MeshPrimitive primitive = MeshPrimitive::Triangles);
@ -453,7 +479,7 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
* ES 3.0, WebGL 2.0, @es_extension{OES,vertex_array_object} in OpenGL
* ES 2.0 or @webgl_extension{OES,vertex_array_object} in WebGL 1.0 is
* available, associated vertex array object is deleted.
* @see @fn_gl{DeleteVertexArrays}
* @see @ref wrap(), @ref release(), @fn_gl{DeleteVertexArrays}
*/
~Mesh();
@ -473,6 +499,21 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
*/
GLuint id() const { return _id; }
/**
* @brief Release OpenGL object
*
* Releases ownership of OpenGL vertex array object and returns its ID
* so it is not deleted on destruction. The internal state is then
* equivalent to moved-from state.
* @see @ref wrap()
* @requires_gl30 Extension @extension{ARB,vertex_array_object}
* @requires_gles30 Extension @es_extension{OES,vertex_array_object} in
* OpenGL ES 2.0.
* @requires_webgl20 Extension @webgl_extension{OES,vertex_array_object}
* in WebGL 1.0.
*/
GLuint release();
#ifndef MAGNUM_TARGET_WEBGL
/**
* @brief Mesh label
@ -887,6 +928,8 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
#endif
#endif
explicit Mesh(GLuint id, MeshPrimitive primitive, ObjectFlags flags): _id{id}, _primitive{primitive}, _flags{flags} {}
void MAGNUM_LOCAL createIfNotAlready();
#ifndef MAGNUM_TARGET_WEBGL
@ -1038,8 +1081,8 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
#endif
GLuint _id;
bool _created; /* see createIfNotAlready() for details */
MeshPrimitive _primitive;
ObjectFlags _flags;
Int _count, _baseVertex, _instanceCount;
#ifndef MAGNUM_TARGET_GLES
UnsignedInt _baseInstance;
@ -1066,6 +1109,12 @@ Debug MAGNUM_EXPORT operator<<(Debug debug, MeshPrimitive value);
/** @debugoperatorclassenum{Magnum::Mesh,Magnum::Mesh::IndexType} */
Debug MAGNUM_EXPORT operator<<(Debug debug, Mesh::IndexType value);
inline GLuint Mesh::release() {
const GLuint id = _id;
_id = 0;
return id;
}
}
namespace Corrade { namespace Utility {

23
src/Magnum/MultisampleTexture.h

@ -111,13 +111,31 @@ template<UnsignedInt dimensions> class MultisampleTexture: public AbstractTextur
return Implementation::maxMultisampleTextureSize<dimensions>();
}
/**
* @brief Wrap existing OpenGL multisample texture object
* @param id OpenGL multisample texture ID
* @param flags Object creation flags
*
* The @p id is expected to be of an existing OpenGL texture object
* with target @def_gl{TEXTURE_2D_MULTISAMPLE} or
* @def_gl{TEXTURE_2D_MULTISAMPLE_ARRAY} based on dimension count.
* Unlike texture created using constructor, the OpenGL object is by
* default not deleted on destruction, use @p flags for different
* behavior.
* @see @ref release()
*/
static MultisampleTexture<dimensions> wrap(GLuint id, ObjectFlags flags = {}) {
return MultisampleTexture<dimensions>{id, flags};
}
/**
* @brief Constructor
*
* Creates new OpenGL texture object. If @extension{ARB,direct_state_access}
* (part of OpenGL 4.5) is not available, the texture is created on
* first use.
* @see @fn_gl{CreateTextures} with @def_gl{TEXTURE_2D_MULTISAMPLE} or
* @see @ref wrap(), @fn_gl{CreateTextures} with
* @def_gl{TEXTURE_2D_MULTISAMPLE} or
* @def_gl{TEXTURE_2D_MULTISAMPLE_ARRAY}, eventually
* @fn_gl{GenTextures}
*/
@ -205,6 +223,9 @@ template<UnsignedInt dimensions> class MultisampleTexture: public AbstractTextur
return *this;
}
#endif
private:
explicit MultisampleTexture(GLuint id, ObjectFlags flags): AbstractTexture{id, Implementation::multisampleTextureTarget<dimensions>(), flags} {}
};
/**

21
src/Magnum/PrimitiveQuery.h

@ -84,6 +84,22 @@ class PrimitiveQuery: public AbstractQuery {
TransformFeedbackPrimitivesWritten = GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
};
/**
* @brief Wrap existing OpenGL primitive query object
* @param id OpenGL primitive query ID
* @param target Query target
* @param flags Object creation flags
*
* The @p id is expected to be of an existing OpenGL query object.
* Unlike query created using constructor, the OpenGL object is by
* default not deleted on destruction, use @p flags for different
* behavior.
* @see @ref release()
*/
static PrimitiveQuery wrap(GLuint id, Target target, ObjectFlags flags = {}) {
return PrimitiveQuery{id, target, flags};
}
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copybrief PrimitiveQuery(Target)
@ -98,7 +114,7 @@ class PrimitiveQuery: public AbstractQuery {
* Creates new OpenGL query object. If @extension{ARB,direct_state_access}
* (part of OpenGL 4.5) is not available, the query is created on first
* use.
* @see @fn_gl{CreateQueries}, eventually @fn_gl{GenQueries}
* @see @ref wrap(), @fn_gl{CreateQueries}, eventually @fn_gl{GenQueries}
*/
explicit PrimitiveQuery(Target target): AbstractQuery(GLenum(target)) {}
@ -125,6 +141,9 @@ class PrimitiveQuery: public AbstractQuery {
return *this;
}
#endif
private:
explicit PrimitiveQuery(GLuint id, Target target, ObjectFlags flags) noexcept: AbstractQuery{id, GLenum(target), flags} {}
};
}

22
src/Magnum/RectangleTexture.h

@ -80,14 +80,29 @@ class MAGNUM_EXPORT RectangleTexture: public AbstractTexture {
*/
static Vector2i maxSize();
/**
* @brief Wrap existing OpenGL rectangle texture object
* @param id OpenGL rectangle texture ID
* @param flags Object creation flags
*
* The @p id is expected to be of an existing OpenGL texture object
* with target @def_gl{TEXTURE_RECTANGLE}. Unlike texture created using
* constructor, the OpenGL object is by default not deleted on
* destruction, use @p flags for different behavior.
* @see @ref release()
*/
static RectangleTexture wrap(GLuint id, ObjectFlags flags = {}) {
return RectangleTexture{id, flags};
}
/**
* @brief Constructor
*
* Creates new OpenGL texture object. If @extension{ARB,direct_state_access}
* (part of OpenGL 4.5) is not available, the texture is created on
* first use.
* @see @fn_gl{CreateTextures} with @def_gl{TEXTURE_RECTANGLE},
* eventually @fn_gl{GenTextures}
* @see @ref wrap(), @fn_gl{CreateTextures} with
* @def_gl{TEXTURE_RECTANGLE}, eventually @fn_gl{GenTextures}
*/
explicit RectangleTexture(): AbstractTexture(GL_TEXTURE_RECTANGLE) {}
@ -410,6 +425,9 @@ class MAGNUM_EXPORT RectangleTexture: public AbstractTexture {
return *this;
}
#endif
private:
explicit RectangleTexture(GLuint id, ObjectFlags flags) noexcept: AbstractTexture{id, GL_TEXTURE_RECTANGLE, flags} {}
};
}

17
src/Magnum/Renderbuffer.cpp

@ -68,25 +68,24 @@ Int Renderbuffer::maxSamples() {
}
#endif
Renderbuffer::Renderbuffer() {
Renderbuffer::Renderbuffer(): _flags{ObjectFlag::DeleteOnDestruction} {
(this->*Context::current()->state().framebuffer->createRenderbufferImplementation)();
}
void Renderbuffer::createImplementationDefault() {
glGenRenderbuffers(1, &_id);
_created = false;
}
#ifndef MAGNUM_TARGET_GLES
void Renderbuffer::createImplementationDSA() {
glCreateRenderbuffers(1, &_id);
_created = true;
_flags |= ObjectFlag::Created;
}
#endif
Renderbuffer::~Renderbuffer() {
/* Moved out, nothing to do */
if(!_id) return;
if(!_id || !(_flags & ObjectFlag::DeleteOnDestruction)) return;
/* If bound, remove itself from state */
GLuint& binding = Context::current()->state().framebuffer->renderbufferBinding;
@ -96,14 +95,14 @@ Renderbuffer::~Renderbuffer() {
}
inline void Renderbuffer::createIfNotAlready() {
if(_created) return;
if(_flags & ObjectFlag::Created) return;
/* glGen*() does not create the object, just reserves the name. Some
commands (such as glObjectLabel()) operate with IDs directly and they
require the object to be created. Binding the renderbuffer finally
creates it. Also all EXT DSA functions implicitly create it. */
bind();
CORRADE_INTERNAL_ASSERT(_created);
CORRADE_INTERNAL_ASSERT(_flags & ObjectFlag::Created);
}
#ifndef MAGNUM_TARGET_WEBGL
@ -136,7 +135,7 @@ void Renderbuffer::bind() {
/* Binding the renderbuffer finally creates it */
binding = _id;
_created = true;
_flags |= ObjectFlag::Created;
glBindRenderbuffer(GL_RENDERBUFFER, _id);
}
@ -151,7 +150,7 @@ void Renderbuffer::storageImplementationDSA(const RenderbufferFormat internalFor
}
void Renderbuffer::storageImplementationDSAEXT(RenderbufferFormat internalFormat, const Vector2i& size) {
_created = true;
_flags |= ObjectFlag::Created;
glNamedRenderbufferStorageEXT(_id, GLenum(internalFormat), size.x(), size.y());
}
#endif
@ -193,7 +192,7 @@ void Renderbuffer::storageMultisampleImplementationDSA(const GLsizei samples, co
}
void Renderbuffer::storageMultisampleImplementationDSAEXT(GLsizei samples, RenderbufferFormat internalFormat, const Vector2i& size) {
_created = true;
_flags |= ObjectFlag::Created;
glNamedRenderbufferStorageMultisampleEXT(_id, samples, GLenum(internalFormat), size.x(), size.y());
}
#endif

44
src/Magnum/Renderbuffer.h

@ -88,13 +88,29 @@ class MAGNUM_EXPORT Renderbuffer: public AbstractObject {
static Int maxSamples();
#endif
/**
* @brief Wrap existing OpenGL renderbuffer object
* @param id OpenGL renderbuffer ID
* @param flags Object creation flags
*
* The @p id is expected to be of an existing OpenGL renderbuffer
* object. Unlike renderbuffer created using constructor, the OpenGL
* object is by default not deleted on destruction, use @p flags for
* different behavior.
* @see @ref release()
*/
static Renderbuffer wrap(GLuint id, ObjectFlags flags = {}) {
return Renderbuffer{id, flags};
}
/**
* @brief Constructor
*
* Generates new OpenGL renderbuffer object. If @extension{ARB,direct_state_access}
* (part of OpenGL 4.5) is not available, the renderbuffer is created
* on first use.
* @see @fn_gl{CreateRenderbuffers}, eventually @fn_gl{GenRenderbuffers}
* @see @ref wrap(), @fn_gl{CreateRenderbuffers}, eventually
* @fn_gl{GenRenderbuffers}
*/
explicit Renderbuffer();
@ -108,7 +124,7 @@ class MAGNUM_EXPORT Renderbuffer: public AbstractObject {
* @brief Destructor
*
* Deletes associated OpenGL renderbuffer object.
* @see @fn_gl{DeleteRenderbuffers}
* @see @ref wrap(), @ref release(), @fn_gl{DeleteRenderbuffers}
*/
~Renderbuffer();
@ -121,6 +137,16 @@ class MAGNUM_EXPORT Renderbuffer: public AbstractObject {
/** @brief OpenGL renderbuffer ID */
GLuint id() const { return _id; }
/**
* @brief Release OpenGL object
*
* Releases ownership of OpenGL renderbuffer object and returns its ID
* so it is not deleted on destruction. The internal state is then
* equivalent to moved-from state.
* @see @ref wrap()
*/
GLuint release();
#ifndef MAGNUM_TARGET_WEBGL
/**
* @brief Renderbuffer label
@ -199,6 +225,8 @@ class MAGNUM_EXPORT Renderbuffer: public AbstractObject {
#endif
private:
explicit Renderbuffer(GLuint id, ObjectFlags flags) noexcept: _id{id}, _flags{flags} {}
void MAGNUM_LOCAL createImplementationDefault();
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL createImplementationDSA();
@ -230,20 +258,26 @@ class MAGNUM_EXPORT Renderbuffer: public AbstractObject {
void MAGNUM_LOCAL bind();
GLuint _id;
bool _created; /* see createIfNotAlready() for details */
ObjectFlags _flags;
};
inline Renderbuffer::Renderbuffer(Renderbuffer&& other) noexcept: _id{other._id}, _created{other._created} {
inline Renderbuffer::Renderbuffer(Renderbuffer&& other) noexcept: _id{other._id}, _flags{other._flags} {
other._id = 0;
}
inline Renderbuffer& Renderbuffer::operator=(Renderbuffer&& other) noexcept {
using std::swap;
swap(_id, other._id);
swap(_created, other._created);
swap(_flags, other._flags);
return *this;
}
inline GLuint Renderbuffer::release() {
const GLuint id = _id;
_id = 0;
return id;
}
}
#endif

20
src/Magnum/SampleQuery.h

@ -182,6 +182,21 @@ class SampleQuery: public AbstractQuery {
};
#endif
/**
* @brief Wrap existing OpenGL sample query object
* @param id OpenGL sample query ID
* @param target Query target
* @param flags Object creation flags
*
* The @p id is expected to be of an existing OpenGL query object.
* Unlike query created using constructor, the OpenGL object is by
* default not deleted on destruction, use @p flags for different
* behavior.
* @see @ref release(), @fn_gl{IsQuery}
*/
static SampleQuery wrap(GLuint id, Target target, ObjectFlags flags = {}) {
return SampleQuery{id, target, flags};
}
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@ -197,7 +212,7 @@ class SampleQuery: public AbstractQuery {
* Creates new OpenGL query object. If @extension{ARB,direct_state_access}
* (part of OpenGL 4.5) is not available, the query is created on first
* use.
* @see @fn_gl{CreateQueries}, eventually @fn_gl{GenQueries}
* @see @ref wrap(), @fn_gl{CreateQueries}, eventually @fn_gl{GenQueries}
*/
explicit SampleQuery(Target target): AbstractQuery(GLenum(target)) {}
@ -250,6 +265,9 @@ class SampleQuery: public AbstractQuery {
return *this;
}
#endif
private:
explicit SampleQuery(GLuint id, Target target, ObjectFlags flags) noexcept: AbstractQuery{id, GLenum(target), flags} {}
};
}

17
src/Magnum/Test/BufferGLTest.cpp

@ -40,6 +40,7 @@ struct BufferGLTest: AbstractOpenGLTester {
void construct();
void constructCopy();
void constructMove();
void wrap();
void label();
@ -65,6 +66,7 @@ BufferGLTest::BufferGLTest() {
addTests({&BufferGLTest::construct,
&BufferGLTest::constructCopy,
&BufferGLTest::constructMove,
&BufferGLTest::wrap,
&BufferGLTest::label,
@ -126,6 +128,21 @@ void BufferGLTest::constructMove() {
CORRADE_COMPARE(c.id(), id);
}
void BufferGLTest::wrap() {
GLuint id;
glGenBuffers(1, &id);
/* Releasing won't delete anything */
{
auto buffer = Buffer::wrap(id, ObjectFlag::DeleteOnDestruction);
CORRADE_COMPARE(buffer.release(), id);
}
/* ...so we can wrap it again */
Buffer::wrap(id);
glDeleteBuffers(1, &id);
}
void BufferGLTest::label() {
/* No-Op version is tested in AbstractObjectGLTest */
if(!Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>() &&

22
src/Magnum/Test/BufferTextureGLTest.cpp

@ -35,6 +35,8 @@ struct BufferTextureGLTest: AbstractOpenGLTester {
explicit BufferTextureGLTest();
void construct();
void wrap();
void bind();
void setBuffer();
void setBufferOffset();
@ -42,6 +44,8 @@ struct BufferTextureGLTest: AbstractOpenGLTester {
BufferTextureGLTest::BufferTextureGLTest() {
addTests({&BufferTextureGLTest::construct,
&BufferTextureGLTest::wrap,
&BufferTextureGLTest::bind,
&BufferTextureGLTest::setBuffer,
&BufferTextureGLTest::setBufferOffset});
@ -61,6 +65,24 @@ void BufferTextureGLTest::construct() {
MAGNUM_VERIFY_NO_ERROR();
}
void BufferTextureGLTest::wrap() {
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::texture_buffer_object>())
CORRADE_SKIP(Extensions::GL::ARB::texture_buffer_object::string() + std::string(" is not supported."));
GLuint id;
glGenTextures(1, &id);
/* Releasing won't delete anything */
{
auto texture = BufferTexture::wrap(id, ObjectFlag::DeleteOnDestruction);
CORRADE_COMPARE(texture.release(), id);
}
/* ...so we can wrap it again */
BufferTexture::wrap(id);
glDeleteTextures(1, &id);
}
void BufferTextureGLTest::bind() {
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::texture_buffer_object>())
CORRADE_SKIP(Extensions::GL::ARB::texture_buffer_object::string() + std::string(" is not supported."));

22
src/Magnum/Test/CubeMapTextureArrayGLTest.cpp

@ -40,6 +40,8 @@ struct CubeMapTextureArrayGLTest: AbstractOpenGLTester {
explicit CubeMapTextureArrayGLTest();
void construct();
void wrap();
void bind();
void sampling();
@ -65,6 +67,8 @@ struct CubeMapTextureArrayGLTest: AbstractOpenGLTester {
CubeMapTextureArrayGLTest::CubeMapTextureArrayGLTest() {
addTests({&CubeMapTextureArrayGLTest::construct,
&CubeMapTextureArrayGLTest::wrap,
&CubeMapTextureArrayGLTest::bind,
&CubeMapTextureArrayGLTest::sampling,
@ -102,6 +106,24 @@ void CubeMapTextureArrayGLTest::construct() {
MAGNUM_VERIFY_NO_ERROR();
}
void CubeMapTextureArrayGLTest::wrap() {
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::texture_cube_map_array>())
CORRADE_SKIP(Extensions::GL::ARB::texture_cube_map_array::string() + std::string(" is not supported."));
GLuint id;
glGenTextures(1, &id);
/* Releasing won't delete anything */
{
auto texture = CubeMapTextureArray::wrap(id, ObjectFlag::DeleteOnDestruction);
CORRADE_COMPARE(texture.release(), id);
}
/* ...so we can wrap it again */
CubeMapTextureArray::wrap(id);
glDeleteTextures(1, &id);
}
void CubeMapTextureArrayGLTest::bind() {
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::texture_cube_map_array>())
CORRADE_SKIP(Extensions::GL::ARB::texture_cube_map_array::string() + std::string(" is not supported."));

19
src/Magnum/Test/CubeMapTextureGLTest.cpp

@ -43,6 +43,8 @@ struct CubeMapTextureGLTest: AbstractOpenGLTester {
explicit CubeMapTextureGLTest();
void construct();
void wrap();
void bind();
void sampling();
@ -88,6 +90,8 @@ struct CubeMapTextureGLTest: AbstractOpenGLTester {
CubeMapTextureGLTest::CubeMapTextureGLTest() {
addTests({&CubeMapTextureGLTest::construct,
&CubeMapTextureGLTest::wrap,
&CubeMapTextureGLTest::bind,
&CubeMapTextureGLTest::sampling,
@ -142,6 +146,21 @@ void CubeMapTextureGLTest::construct() {
MAGNUM_VERIFY_NO_ERROR();
}
void CubeMapTextureGLTest::wrap() {
GLuint id;
glGenTextures(1, &id);
/* Releasing won't delete anything */
{
auto texture = CubeMapTexture::wrap(id, ObjectFlag::DeleteOnDestruction);
CORRADE_COMPARE(texture.release(), id);
}
/* ...so we can wrap it again */
CubeMapTexture::wrap(id);
glDeleteTextures(1, &id);
}
void CubeMapTextureGLTest::bind() {
CubeMapTexture texture;
texture.bind(15);

22
src/Magnum/Test/FramebufferGLTest.cpp

@ -55,6 +55,7 @@ struct FramebufferGLTest: AbstractOpenGLTester {
void construct();
void constructCopy();
void constructMove();
void wrap();
void label();
@ -105,6 +106,7 @@ FramebufferGLTest::FramebufferGLTest() {
addTests({&FramebufferGLTest::construct,
&FramebufferGLTest::constructCopy,
&FramebufferGLTest::constructMove,
&FramebufferGLTest::wrap,
&FramebufferGLTest::label,
@ -207,6 +209,26 @@ void FramebufferGLTest::constructMove() {
CORRADE_COMPARE(c.viewport(), Range2Di({32, 16}, {128, 256}));
}
void FramebufferGLTest::wrap() {
#ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::framebuffer_object>())
CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not available."));
#endif
GLuint id;
glGenFramebuffers(1, &id);
/* Releasing won't delete anything */
{
auto framebuffer = Framebuffer::wrap(id, {}, ObjectFlag::DeleteOnDestruction);
CORRADE_COMPARE(framebuffer.release(), id);
}
/* ...so we can wrap it again */
Framebuffer::wrap(id, {});
glDeleteFramebuffers(1, &id);
}
void FramebufferGLTest::label() {
#ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::framebuffer_object>())

26
src/Magnum/Test/MeshGLTest.cpp

@ -48,6 +48,7 @@ struct MeshGLTest: AbstractOpenGLTester {
void construct();
void constructCopy();
void constructMove();
void wrap();
void label();
@ -139,6 +140,7 @@ MeshGLTest::MeshGLTest() {
addTests({&MeshGLTest::construct,
&MeshGLTest::constructCopy,
&MeshGLTest::constructMove,
&MeshGLTest::wrap,
&MeshGLTest::label,
@ -289,6 +291,30 @@ void MeshGLTest::constructMove() {
CORRADE_COMPARE(c.id(), id);
}
void MeshGLTest::wrap() {
#ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::vertex_array_object>())
#elif defined(MAGNUM_TARGET_GLES2)
if(!Context::current()->isExtensionSupported<Extensions::GL::OES::vertex_array_object>())
#endif
{
CORRADE_SKIP(Extensions::GL::ARB::vertex_array_object::string() + std::string{" is not supported."});
}
GLuint id;
glGenVertexArrays(1, &id);
/* Releasing won't delete anything */
{
auto mesh = Mesh::wrap(id, ObjectFlag::DeleteOnDestruction);
CORRADE_COMPARE(mesh.release(), id);
}
/* ...so we can wrap it again */
Mesh::wrap(id);
glDeleteVertexArrays(1, &id);
}
void MeshGLTest::label() {
/* No-Op version is tested in AbstractObjectGLTest */
if(!Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>() &&

53
src/Magnum/Test/MultisampleTextureGLTest.cpp

@ -40,6 +40,11 @@ struct MultisampleTextureGLTest: AbstractOpenGLTester {
void construct2DArray();
#endif
void wrap2D();
#ifndef MAGNUM_TARGET_GLES
void wrap2DArray();
#endif
void bind2D();
#ifndef MAGNUM_TARGET_GLES
void bind2DArray();
@ -67,6 +72,11 @@ MultisampleTextureGLTest::MultisampleTextureGLTest() {
&MultisampleTextureGLTest::construct2DArray,
#endif
&MultisampleTextureGLTest::wrap2D,
#ifndef MAGNUM_TARGET_GLES
&MultisampleTextureGLTest::wrap2DArray,
#endif
&MultisampleTextureGLTest::bind2D,
#ifndef MAGNUM_TARGET_GLES
&MultisampleTextureGLTest::bind2DArray,
@ -124,6 +134,49 @@ void MultisampleTextureGLTest::construct2DArray() {
}
#endif
void MultisampleTextureGLTest::wrap2D() {
#ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::texture_multisample>())
CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string{" is not supported."});
#else
if(!Context::current()->isVersionSupported(Version::GLES310))
CORRADE_SKIP("OpenGL ES 3.1 is not supported.");
#endif
GLuint id;
glGenTextures(1, &id);
/* Releasing won't delete anything */
{
auto texture = MultisampleTexture2D::wrap(id, ObjectFlag::DeleteOnDestruction);
CORRADE_COMPARE(texture.release(), id);
}
/* ...so we can wrap it again */
MultisampleTexture2D::wrap(id);
glDeleteTextures(1, &id);
}
#ifndef MAGNUM_TARGET_GLES
void MultisampleTextureGLTest::wrap2DArray() {
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::texture_multisample>())
CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string{" is not supported."});
GLuint id;
glGenTextures(1, &id);
/* Releasing won't delete anything */
{
auto texture = MultisampleTexture2DArray::wrap(id, ObjectFlag::DeleteOnDestruction);
CORRADE_COMPARE(texture.release(), id);
}
/* ...so we can wrap it again */
MultisampleTexture2DArray::wrap(id);
glDeleteTextures(1, &id);
}
#endif
void MultisampleTextureGLTest::bind2D() {
#ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::texture_multisample>())

25
src/Magnum/Test/PrimitiveQueryGLTest.cpp

@ -40,6 +40,8 @@ namespace Magnum { namespace Test {
struct PrimitiveQueryGLTest: AbstractOpenGLTester {
explicit PrimitiveQueryGLTest();
void wrap();
#ifndef MAGNUM_TARGET_GLES
void primitivesGenerated();
#endif
@ -47,13 +49,34 @@ struct PrimitiveQueryGLTest: AbstractOpenGLTester {
};
PrimitiveQueryGLTest::PrimitiveQueryGLTest() {
addTests({
addTests({&PrimitiveQueryGLTest::wrap,
#ifndef MAGNUM_TARGET_GLES
&PrimitiveQueryGLTest::primitivesGenerated,
#endif
&PrimitiveQueryGLTest::transformFeedbackPrimitivesWritten});
}
void PrimitiveQueryGLTest::wrap() {
#ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::transform_feedback2>())
CORRADE_SKIP(Extensions::GL::ARB::transform_feedback2::string() + std::string(" is not available."));
#endif
GLuint id;
glGenQueries(1, &id);
/* Releasing won't delete anything */
{
auto query = PrimitiveQuery::wrap(id, PrimitiveQuery::Target::TransformFeedbackPrimitivesWritten, ObjectFlag::DeleteOnDestruction);
CORRADE_COMPARE(query.release(), id);
}
/* ...so we can wrap it again */
PrimitiveQuery::wrap(id, PrimitiveQuery::Target::TransformFeedbackPrimitivesWritten);
glDeleteQueries(1, &id);
}
#ifndef MAGNUM_TARGET_GLES
void PrimitiveQueryGLTest::primitivesGenerated() {
if(!Context::current()->isExtensionSupported<Extensions::GL::EXT::transform_feedback>())

22
src/Magnum/Test/RectangleTextureGLTest.cpp

@ -41,6 +41,8 @@ struct RectangleTextureGLTest: AbstractOpenGLTester {
explicit RectangleTextureGLTest();
void construct();
void wrap();
void bind();
void sampling();
@ -64,6 +66,8 @@ struct RectangleTextureGLTest: AbstractOpenGLTester {
RectangleTextureGLTest::RectangleTextureGLTest() {
addTests({&RectangleTextureGLTest::construct,
&RectangleTextureGLTest::wrap,
&RectangleTextureGLTest::bind,
&RectangleTextureGLTest::sampling,
@ -100,6 +104,24 @@ void RectangleTextureGLTest::construct() {
MAGNUM_VERIFY_NO_ERROR();
}
void RectangleTextureGLTest::wrap() {
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::texture_rectangle>())
CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported."));
GLuint id;
glGenTextures(1, &id);
/* Releasing won't delete anything */
{
auto texture = RectangleTexture::wrap(id, ObjectFlag::DeleteOnDestruction);
CORRADE_COMPARE(texture.release(), id);
}
/* ...so we can wrap it again */
RectangleTexture::wrap(id);
glDeleteTextures(1, &id);
}
void RectangleTextureGLTest::bind() {
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::texture_rectangle>())
CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported."));

22
src/Magnum/Test/RenderbufferGLTest.cpp

@ -38,6 +38,7 @@ struct RenderbufferGLTest: AbstractOpenGLTester {
void construct();
void constructCopy();
void constructMove();
void wrap();
void label();
@ -49,6 +50,7 @@ RenderbufferGLTest::RenderbufferGLTest() {
addTests({&RenderbufferGLTest::construct,
&RenderbufferGLTest::constructCopy,
&RenderbufferGLTest::constructMove,
&RenderbufferGLTest::wrap,
&RenderbufferGLTest::label,
@ -104,6 +106,26 @@ void RenderbufferGLTest::constructMove() {
CORRADE_COMPARE(c.id(), id);
}
void RenderbufferGLTest::wrap() {
#ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::framebuffer_object>())
CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not available."));
#endif
GLuint id;
glGenRenderbuffers(1, &id);
/* Releasing won't delete anything */
{
auto renderbuffer = Renderbuffer::wrap(id, ObjectFlag::DeleteOnDestruction);
CORRADE_COMPARE(renderbuffer.release(), id);
}
/* ...so we can wrap it again */
Renderbuffer::wrap(id);
glDeleteRenderbuffers(1, &id);
}
void RenderbufferGLTest::label() {
#ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::framebuffer_object>())

35
src/Magnum/Test/SampleQueryGLTest.cpp

@ -41,6 +41,8 @@ namespace Magnum { namespace Test {
struct SampleQueryGLTest: AbstractOpenGLTester {
explicit SampleQueryGLTest();
void wrap();
void querySamplesPassed();
#ifndef MAGNUM_TARGET_GLES
void conditionalRender();
@ -48,12 +50,33 @@ struct SampleQueryGLTest: AbstractOpenGLTester {
};
SampleQueryGLTest::SampleQueryGLTest() {
addTests({
&SampleQueryGLTest::querySamplesPassed,
#ifndef MAGNUM_TARGET_GLES
&SampleQueryGLTest::conditionalRender
#endif
});
addTests({&SampleQueryGLTest::wrap,
&SampleQueryGLTest::querySamplesPassed,
#ifndef MAGNUM_TARGET_GLES
&SampleQueryGLTest::conditionalRender
#endif
});
}
void SampleQueryGLTest::wrap() {
#ifdef MAGNUM_TARGET_GLES2
if(!Context::current()->isExtensionSupported<Extensions::GL::EXT::occlusion_query_boolean>())
CORRADE_SKIP(Extensions::GL::EXT::occlusion_query_boolean::string() + std::string(" is not available."));
#endif
GLuint id;
glGenQueries(1, &id);
/* Releasing won't delete anything */
{
auto query = SampleQuery::wrap(id, SampleQuery::Target::AnySamplesPassed, ObjectFlag::DeleteOnDestruction);
CORRADE_COMPARE(query.release(), id);
}
/* ...so we can wrap it again */
SampleQuery::wrap(id, SampleQuery::Target::AnySamplesPassed);
glDeleteQueries(1, &id);
}
namespace {

47
src/Magnum/Test/TextureArrayGLTest.cpp

@ -45,6 +45,11 @@ struct TextureArrayGLTest: AbstractOpenGLTester {
#endif
void construct2D();
#ifndef MAGNUM_TARGET_GLES
void wrap1D();
#endif
void wrap2D();
#ifndef MAGNUM_TARGET_GLES
void bind1D();
#endif
@ -132,6 +137,11 @@ TextureArrayGLTest::TextureArrayGLTest() {
#endif
&TextureArrayGLTest::construct2D,
#ifndef MAGNUM_TARGET_GLES
&TextureArrayGLTest::wrap1D,
#endif
&TextureArrayGLTest::wrap2D,
#ifndef MAGNUM_TARGET_GLES
&TextureArrayGLTest::bind1D,
#endif
@ -239,6 +249,43 @@ void TextureArrayGLTest::construct2D() {
MAGNUM_VERIFY_NO_ERROR();
}
#ifndef MAGNUM_TARGET_GLES
void TextureArrayGLTest::wrap1D() {
GLuint id;
glGenTextures(1, &id);
/* Releasing won't delete anything */
{
auto texture = Texture1DArray::wrap(id, ObjectFlag::DeleteOnDestruction);
CORRADE_COMPARE(texture.release(), id);
}
/* ...so we can wrap it again */
Texture1DArray::wrap(id);
glDeleteTextures(1, &id);
}
#endif
void TextureArrayGLTest::wrap2D() {
#ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::EXT::texture_array>())
CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported."));
#endif
GLuint id;
glGenTextures(1, &id);
/* Releasing won't delete anything */
{
auto texture = Texture2DArray::wrap(id, ObjectFlag::DeleteOnDestruction);
CORRADE_COMPARE(texture.release(), id);
}
/* ...so we can wrap it again */
Texture2DArray::wrap(id);
glDeleteTextures(1, &id);
}
#ifndef MAGNUM_TARGET_GLES
void TextureArrayGLTest::bind1D() {
if(!Context::current()->isExtensionSupported<Extensions::GL::EXT::texture_array>())

64
src/Magnum/Test/TextureGLTest.cpp

@ -48,6 +48,12 @@ struct TextureGLTest: AbstractOpenGLTester {
void construct2D();
void construct3D();
#ifndef MAGNUM_TARGET_GLES
void wrap1D();
#endif
void wrap2D();
void wrap3D();
#ifndef MAGNUM_TARGET_GLES
void bind1D();
#endif
@ -163,6 +169,12 @@ TextureGLTest::TextureGLTest() {
&TextureGLTest::construct2D,
&TextureGLTest::construct3D,
#ifndef MAGNUM_TARGET_GLES
&TextureGLTest::wrap1D,
#endif
&TextureGLTest::wrap2D,
&TextureGLTest::wrap3D,
#ifndef MAGNUM_TARGET_GLES
&TextureGLTest::bind1D,
#endif
@ -309,6 +321,58 @@ void TextureGLTest::construct3D() {
MAGNUM_VERIFY_NO_ERROR();
}
#ifndef MAGNUM_TARGET_GLES
void TextureGLTest::wrap1D() {
GLuint id;
glGenTextures(1, &id);
/* Releasing won't delete anything */
{
auto texture = Texture1D::wrap(id, ObjectFlag::DeleteOnDestruction);
CORRADE_COMPARE(texture.release(), id);
}
/* ...so we can wrap it again */
Texture1D::wrap(id);
glDeleteTextures(1, &id);
}
#endif
void TextureGLTest::wrap2D() {
GLuint id;
glGenTextures(1, &id);
/* Releasing won't delete anything */
{
auto texture = Texture2D::wrap(id, ObjectFlag::DeleteOnDestruction);
CORRADE_COMPARE(texture.release(), id);
}
/* ...so we can wrap it again */
Texture2D::wrap(id);
glDeleteTextures(1, &id);
}
void TextureGLTest::wrap3D() {
#ifdef MAGNUM_TARGET_GLES2
if(!Context::current()->isExtensionSupported<Extensions::GL::OES::texture_3D>())
CORRADE_SKIP(Extensions::GL::OES::texture_3D::string() + std::string(" is not supported."));
#endif
GLuint id;
glGenTextures(1, &id);
/* Releasing won't delete anything */
{
auto texture = Texture3D::wrap(id, ObjectFlag::DeleteOnDestruction);
CORRADE_COMPARE(texture.release(), id);
}
/* ...so we can wrap it again */
Texture3D::wrap(id);
glDeleteTextures(1, &id);
}
#ifndef MAGNUM_TARGET_GLES
void TextureGLTest::bind1D() {
Texture1D texture;

29
src/Magnum/Test/TimeQueryGLTest.cpp

@ -31,15 +31,42 @@ namespace Magnum { namespace Test {
struct TimeQueryGLTest: AbstractOpenGLTester {
explicit TimeQueryGLTest();
void wrap();
void queryTime();
void queryTimestamp();
};
TimeQueryGLTest::TimeQueryGLTest() {
addTests({&TimeQueryGLTest::queryTime,
addTests({&TimeQueryGLTest::wrap,
&TimeQueryGLTest::queryTime,
&TimeQueryGLTest::queryTimestamp});
}
void TimeQueryGLTest::wrap() {
#ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::timer_query>())
CORRADE_SKIP(Extensions::GL::ARB::timer_query::string() + std::string(" is not available"));
#else
if(!Context::current()->isExtensionSupported<Extensions::GL::EXT::disjoint_timer_query>())
CORRADE_SKIP(Extensions::GL::EXT::disjoint_timer_query::string() + std::string(" is not available"));
#endif
GLuint id;
glGenQueries(1, &id);
/* Releasing won't delete anything */
{
auto query = TimeQuery::wrap(id, TimeQuery::Target::TimeElapsed, ObjectFlag::DeleteOnDestruction);
CORRADE_COMPARE(query.release(), id);
}
/* ...so we can wrap it again */
TimeQuery::wrap(id, TimeQuery::Target::TimeElapsed);
glDeleteQueries(1, &id);
}
void TimeQueryGLTest::queryTime() {
#ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::timer_query>())

17
src/Magnum/Test/TransformFeedbackGLTest.cpp

@ -39,6 +39,7 @@ struct TransformFeedbackGLTest: AbstractOpenGLTester {
void construct();
void constructCopy();
void constructMove();
void wrap();
void label();
@ -54,6 +55,7 @@ TransformFeedbackGLTest::TransformFeedbackGLTest() {
addTests({&TransformFeedbackGLTest::construct,
&TransformFeedbackGLTest::constructCopy,
&TransformFeedbackGLTest::constructMove,
&TransformFeedbackGLTest::wrap,
&TransformFeedbackGLTest::label,
@ -103,6 +105,21 @@ void TransformFeedbackGLTest::constructMove() {
CORRADE_COMPARE(c.id(), id);
}
void TransformFeedbackGLTest::wrap() {
GLuint id;
glGenTransformFeedbacks(1, &id);
/* Releasing won't delete anything */
{
auto feedback = TransformFeedback::wrap(id, ObjectFlag::DeleteOnDestruction);
CORRADE_COMPARE(feedback.release(), id);
}
/* ...so we can wrap it again */
TransformFeedback::wrap(id);
glDeleteTransformFeedbacks(1, &id);
}
void TransformFeedbackGLTest::label() {
/* No-Op version is tested in AbstractObjectGLTest */
if(!Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>() &&

21
src/Magnum/Texture.h

@ -159,13 +159,29 @@ template<UnsignedInt dimensions> class Texture: public AbstractTexture {
return Implementation::maxTextureSize<dimensions>();
}
/**
* @brief Wrap existing OpenGL texture object
* @param id OpenGL texture ID
* @param flags Object creation flags
*
* The @p id is expected to be of an existing OpenGL texture object
* with target @def_gl{TEXTURE_1D}, @def_gl{TEXTURE_2D} or
* @def_gl{TEXTURE_3D} based on dimension count. Unlike texture created
* using constructor, the OpenGL object is by default not deleted on
* destruction, use @p flags for different behavior.
* @see @ref release()
*/
static Texture<dimensions> wrap(GLuint id, ObjectFlags flags = {}) {
return Texture<dimensions>{id, flags};
}
/**
* @brief Constructor
*
* Creates new OpenGL texture object. If @extension{ARB,direct_state_access}
* (part of OpenGL 4.5) is not available, the texture is created on
* first use.
* @see @fn_gl{CreateTextures} with @def_gl{TEXTURE_1D},
* @see @ref wrap(), @fn_gl{CreateTextures} with @def_gl{TEXTURE_1D},
* @def_gl{TEXTURE_2D} or @def_gl{TEXTURE_3D}, eventually
* @fn_gl{GenTextures}
*/
@ -923,6 +939,9 @@ template<UnsignedInt dimensions> class Texture: public AbstractTexture {
return *this;
}
#endif
private:
explicit Texture(GLuint id, ObjectFlags flags) noexcept: AbstractTexture{id, Implementation::textureTarget<dimensions>(), flags} {}
};
#ifndef MAGNUM_TARGET_GLES

24
src/Magnum/TextureArray.h

@ -109,14 +109,31 @@ template<UnsignedInt dimensions> class TextureArray: public AbstractTexture {
*/
static VectorTypeFor<dimensions+1, Int> maxSize();
/**
* @brief Wrap existing OpenGL texture array object
* @param id OpenGL texture array ID
* @param flags Object creation flags
*
* The @p id is expected to be of an existing OpenGL texture object
* with target @def_gl{TEXTURE_1D_ARRAY} or @def_gl{TEXTURE_2D_ARRAY}
* based on dimension count. Unlike texture created using constructor,
* the OpenGL object is by default not deleted on destruction, use
* @p flags for different behavior.
* @see @ref release()
*/
static TextureArray<dimensions> wrap(GLuint id, ObjectFlags flags = {}) {
return TextureArray<dimensions>{id, flags};
}
/**
* @brief Constructor
*
* Creates new OpenGL texture object. If @extension{ARB,direct_state_access}
* (part of OpenGL 4.5) is not available, the texture is created on
* first use.
* @see @fn_gl{CreateTextures} with @def_gl{TEXTURE_1D_ARRAY} or
* @def_gl{TEXTURE_2D_ARRAY}, eventually @fn_gl{GenTextures}
* @see @ref wrap(), @fn_gl{CreateTextures} with
* @def_gl{TEXTURE_1D_ARRAY} or @def_gl{TEXTURE_2D_ARRAY},
* eventually @fn_gl{GenTextures}
*/
explicit TextureArray(): AbstractTexture(Implementation::textureArrayTarget<dimensions>()) {}
@ -556,6 +573,9 @@ template<UnsignedInt dimensions> class TextureArray: public AbstractTexture {
return *this;
}
#endif
private:
explicit TextureArray(GLuint id, ObjectFlags flags): AbstractTexture{id, Implementation::textureArrayTarget<dimensions>(), flags} {}
};
#ifndef MAGNUM_TARGET_GLES

21
src/Magnum/TimeQuery.h

@ -104,13 +104,29 @@ class TimeQuery: public AbstractQuery {
CORRADE_DEPRECATED("use TimeQuery(Target) instead") explicit TimeQuery() {}
#endif
/**
* @brief Wrap existing OpenGL time query object
* @param id OpenGL time query ID
* @param target Query target
* @param flags Object creation flags
*
* The @p id is expected to be of an existing OpenGL query object.
* Unlike query created using constructor, the OpenGL object is by
* default not deleted on destruction, use @p flags for different
* behavior.
* @see @ref release()
*/
static TimeQuery wrap(GLuint id, Target target, ObjectFlags flags = {}) {
return TimeQuery{id, target, flags};
}
/**
* @brief Constructor
*
* Creates new OpenGL query object. If @extension{ARB,direct_state_access}
* (part of OpenGL 4.5) is not available, the query is created on first
* use.
* @see @fn_gl{CreateQueries}, eventually @fn_gl{GenQueries}
* @see @ref wrap(), @fn_gl{CreateQueries}, eventually @fn_gl{GenQueries}
*/
explicit TimeQuery(Target target): AbstractQuery(GLenum(target)) {}
@ -152,6 +168,9 @@ class TimeQuery: public AbstractQuery {
return *this;
}
#endif
private:
explicit TimeQuery(GLuint id, Target target, ObjectFlags flags) noexcept: AbstractQuery{id, GLenum(target), flags} {}
};
}

14
src/Magnum/TransformFeedback.cpp

@ -96,25 +96,25 @@ Int TransformFeedback::maxBuffers() {
}
#endif
TransformFeedback::TransformFeedback() {
TransformFeedback::TransformFeedback(): _flags{ObjectFlag::DeleteOnDestruction} {
(this->*Context::current()->state().transformFeedback->createImplementation)();
CORRADE_INTERNAL_ASSERT(_id != Implementation::State::DisengagedBinding);
}
void TransformFeedback::createImplementationDefault() {
glGenTransformFeedbacks(1, &_id);
_created = false;
}
#ifndef MAGNUM_TARGET_GLES
void TransformFeedback::createImplementationDSA() {
glCreateTransformFeedbacks(1, &_id);
_created = true;
_flags |= ObjectFlag::Created;
}
#endif
TransformFeedback::~TransformFeedback() {
if(!_id) return;
/* Moved out or not deleting on destruction, nothing to do */
if(!_id || !(_flags & ObjectFlag::DeleteOnDestruction)) return;
/* If bound, remove itself from state */
GLuint& binding = Context::current()->state().transformFeedback->binding;
@ -131,19 +131,19 @@ void TransformFeedback::bindInternal() {
/* Bind the transform feedback otherwise, which will also finally create it */
bound = _id;
_created = true;
_flags |= ObjectFlag::Created;
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, _id);
}
inline void TransformFeedback::createIfNotAlready() {
if(_created) return;
if(_flags & ObjectFlag::Created) return;
/* glGen*() does not create the object, just reserves the name. Some
commands (such as glObjectLabel()) operate with IDs directly and they
require the object to be created. Binding the transform feedback finally
creates it. Also all EXT DSA functions implicitly create it. */
bindInternal();
CORRADE_INTERNAL_ASSERT(_created);
CORRADE_INTERNAL_ASSERT(_flags & ObjectFlag::Created);
}
#ifndef MAGNUM_TARGET_WEBGL

43
src/Magnum/TransformFeedback.h

@ -147,13 +147,28 @@ class MAGNUM_EXPORT TransformFeedback: public AbstractObject {
static Int maxBuffers();
#endif
/**
* @brief Wrap existing OpenGL transform feedback object
* @param id OpenGL transform feedback ID
* @param flags Object creation flags
*
* The @p id is expected to be of an existing OpenGL transform feedback
* object. Unlike renderbuffer created using constructor, the OpenGL
* object is by default not deleted on destruction, use @p flags for
* different behavior.
* @see @ref release()
*/
static TransformFeedback wrap(GLuint id, ObjectFlags flags = {}) {
return TransformFeedback{id, flags};
}
/**
* @brief Constructor
*
* Creates new OpenGL transform feedback object. If
* @extension{ARB,direct_state_access} (part of OpenGL 4.5) is not
* available, the transform feedback object is created on first use.
* @see @fn_gl{CreateTransformFeedbacks}, eventually
* @see @ref wrap(), @fn_gl{CreateTransformFeedbacks}, eventually
* @fn_gl{GenTransformFeedbacks}
*/
explicit TransformFeedback();
@ -168,7 +183,7 @@ class MAGNUM_EXPORT TransformFeedback: public AbstractObject {
* @brief Destructor
*
* Deletes associated OpenGL transform feedback object.
* @see @fn_gl{DeleteTransformFeedbacks}
* @see @ref wrap(), @ref release(), @fn_gl{DeleteTransformFeedbacks}
*/
~TransformFeedback();
@ -181,6 +196,16 @@ class MAGNUM_EXPORT TransformFeedback: public AbstractObject {
/** @brief OpenGL transform feedback ID */
GLuint id() const { return _id; }
/**
* @brief Release OpenGL object
*
* Releases ownership of OpenGL transform feedback object and returns
* its ID so it is not deleted on destruction. The internal state is
* then equivalent to moved-from state.
* @see @ref wrap()
*/
GLuint release();
#ifndef MAGNUM_TARGET_WEBGL
/**
* @brief Transform feedback label
@ -347,6 +372,8 @@ class MAGNUM_EXPORT TransformFeedback: public AbstractObject {
void end();
private:
explicit TransformFeedback(GLuint id, ObjectFlags flags) noexcept: _id{id}, _flags{flags} {}
void bindInternal();
void MAGNUM_LOCAL createIfNotAlready();
@ -375,20 +402,26 @@ class MAGNUM_EXPORT TransformFeedback: public AbstractObject {
#endif
GLuint _id;
bool _created; /* see createIfNotAlready() for details */
ObjectFlags _flags;
};
inline TransformFeedback::TransformFeedback(TransformFeedback&& other) noexcept: _id{other._id}, _created{other._created} {
inline TransformFeedback::TransformFeedback(TransformFeedback&& other) noexcept: _id{other._id}, _flags{other._flags} {
other._id = 0;
}
inline TransformFeedback& TransformFeedback::operator=(TransformFeedback&& other) noexcept {
using std::swap;
swap(_id, other._id);
swap(_created, other._created);
swap(_flags, other._flags);
return *this;
}
inline GLuint TransformFeedback::release() {
const GLuint id = _id;
_id = 0;
return id;
}
}
#else
#error this header is not available in OpenGL ES 2.0 build

Loading…
Cancel
Save