Browse Source

GL: implemented ARB_buffer_storage.

pull/470/head
Vladimír Vondruš 6 years ago
parent
commit
75d238f50b
  1. 3
      doc/changelog.dox
  2. 2
      doc/opengl-mapping.dox
  3. 2
      doc/opengl-support.dox
  4. 17
      src/Magnum/GL/Buffer.cpp
  5. 130
      src/Magnum/GL/Buffer.h
  6. 6
      src/Magnum/GL/Implementation/BufferState.cpp
  7. 3
      src/Magnum/GL/Implementation/BufferState.h
  8. 23
      src/Magnum/GL/Test/BufferGLTest.cpp

3
doc/changelog.dox

@ -62,6 +62,9 @@ See also:
means these can'be implemented right now. means these can'be implemented right now.
- Added a @ref GL::AbstractTexture::target() getter to simplify interaction - Added a @ref GL::AbstractTexture::target() getter to simplify interaction
with raw GL code with raw GL code
- Exposed @gl_extension{ARB,buffer_storage} as
@ref GL::Buffer::setStorage() together with additions to
@ref GL::Buffer::MapFlag
@subsubsection changelog-latest-new-math Math library @subsubsection changelog-latest-new-math Math library

2
doc/opengl-mapping.dox

@ -85,7 +85,7 @@ OpenGL function | Matching API
@fn_gl{BlitFramebuffer}, \n `glBlitNamedFramebuffer()` | @ref GL::AbstractFramebuffer::blit() @fn_gl{BlitFramebuffer}, \n `glBlitNamedFramebuffer()` | @ref GL::AbstractFramebuffer::blit()
@fn_gl{BufferData}, \n `glNamedBufferData()` | @ref GL::Buffer::setData() @fn_gl{BufferData}, \n `glNamedBufferData()` | @ref GL::Buffer::setData()
@fn_gl_extension{BufferPageCommitment,ARB,sparse_buffer}, \n `glNamedBufferPageCommitmentEXT()`, \n `glNamedBufferPageCommitmentARB()` | | @fn_gl_extension{BufferPageCommitment,ARB,sparse_buffer}, \n `glNamedBufferPageCommitmentEXT()`, \n `glNamedBufferPageCommitmentARB()` | |
@fn_gl{BufferStorage}, \n `glNamedBufferStorage()` | | @fn_gl{BufferStorage}, \n `glNamedBufferStorage()` | @ref GL::Buffer::setStorage()
@fn_gl{BufferSubData}, \n `glNamedBufferSubData()` | @ref GL::Buffer::setSubData() @fn_gl{BufferSubData}, \n `glNamedBufferSubData()` | @ref GL::Buffer::setSubData()
@subsection opengl-mapping-functions-c C @subsection opengl-mapping-functions-c C

2
doc/opengl-support.dox

@ -229,7 +229,7 @@ Extension | Status
------------------------------------------- | ------ ------------------------------------------- | ------
GLSL 4.40 | done GLSL 4.40 | done
@def_gl{MAX_VERTEX_ATTRIB_STRIDE} | | @def_gl{MAX_VERTEX_ATTRIB_STRIDE} | |
@gl_extension{ARB,buffer_storage} | | @gl_extension{ARB,buffer_storage} | done
@gl_extension{ARB,clear_texture} | | @gl_extension{ARB,clear_texture} | |
@gl_extension{ARB,enhanced_layouts} | done (shading language only) @gl_extension{ARB,enhanced_layouts} | done (shading language only)
@gl_extension{ARB,multi_bind} | missing sampler and vertex buffer binding @gl_extension{ARB,multi_bind} | missing sampler and vertex buffer binding

17
src/Magnum/GL/Buffer.cpp

@ -305,6 +305,13 @@ Buffer& Buffer::bind(const Target target, const UnsignedInt index) {
} }
#endif #endif
#ifndef MAGNUM_TARGET_GLES
Buffer& Buffer::setStorage(const Containers::ArrayView<const void> data, const StorageFlags flags) {
(this->*Context::current().state().buffer->storageImplementation)(data, flags);
return *this;
}
#endif
Int Buffer::size() { Int Buffer::size() {
/** /**
* @todo there is something like glGetBufferParameteri64v in 3.2 (I * @todo there is something like glGetBufferParameteri64v in 3.2 (I
@ -434,6 +441,16 @@ void Buffer::copyImplementationDSA(Buffer& read, Buffer& write, const GLintptr r
#endif #endif
#endif #endif
#ifndef MAGNUM_TARGET_GLES
void Buffer::storageImplementationDefault(Containers::ArrayView<const void> data, StorageFlags flags) {
glBufferStorage(GLenum(bindSomewhereInternal(_targetHint)), data.size(), data.data(), GLbitfield(flags));
}
void Buffer::storageImplementationDSA(Containers::ArrayView<const void> data, const StorageFlags flags) {
glNamedBufferStorage(_id, data.size(), data.data(), GLbitfield(flags));
}
#endif
void Buffer::getParameterImplementationDefault(const GLenum value, GLint* const data) { void Buffer::getParameterImplementationDefault(const GLenum value, GLint* const data) {
glGetBufferParameteriv(GLenum(bindSomewhereInternal(_targetHint)), value, data); glGetBufferParameteriv(GLenum(bindSomewhereInternal(_targetHint)), value, data);
} }

130
src/Magnum/GL/Buffer.h

@ -196,19 +196,20 @@ and index buffers in WebGL.
The engine tracks currently bound buffers to avoid unnecessary calls to The engine tracks currently bound buffers to avoid unnecessary calls to
@fn_gl_keyword{BindBuffer}. If the buffer is already bound to some target, @fn_gl_keyword{BindBuffer}. If the buffer is already bound to some target,
functions @ref copy(), @ref setData(), @ref setSubData(), @ref map(), functions @ref copy(), @ref setStorage(), @ref setData(), @ref setSubData(),
@ref mapRead(), @ref flushMappedRange() and @ref unmap() use that target @ref map(), @ref mapRead(), @ref flushMappedRange() and @ref unmap() use that
instead of binding the buffer to some specific target. You can also use target instead of binding the buffer to some specific target. You can also use
@ref setTargetHint() to possibly reduce unnecessary rebinding. Buffer limits @ref setTargetHint() to possibly reduce unnecessary rebinding. Buffer limits
and implementation-defined values (such as @ref maxUniformBindings()) are and implementation-defined values (such as @ref maxUniformBindings()) are
cached, so repeated queries don't result in repeated @fn_gl{Get} calls. See cached, so repeated queries don't result in repeated @fn_gl{Get} calls. See
also @ref Context::resetState() and @ref Context::State::Buffers. also @ref Context::resetState() and @ref Context::State::Buffers.
If @gl_extension{ARB,direct_state_access} (part of OpenGL 4.5) is available, If @gl_extension{ARB,direct_state_access} (part of OpenGL 4.5) is available,
functions @ref copy(), @ref size(), @ref data(), @ref subData(), @ref setData(), functions @ref copy(), @ref setStorage(), @ref size(), @ref data(),
@ref setSubData(), @ref map(), @ref mapRead(), @ref flushMappedRange() and @ref subData(), @ref setData(), @ref setSubData(), @ref map(), @ref mapRead(),
@ref unmap() use DSA functions to avoid unnecessary calls to @fn_gl{BindBuffer}. @ref flushMappedRange() and @ref unmap() use DSA functions to avoid unnecessary
See their respective documentation for more information. calls to @fn_gl{BindBuffer}. See their respective documentation for more
information.
You can use functions @ref invalidateData() and @ref invalidateSubData() if you You can use functions @ref invalidateData() and @ref invalidateSubData() if you
don't need buffer data anymore to avoid unnecessary memory operations performed don't need buffer data anymore to avoid unnecessary memory operations performed
@ -489,9 +490,30 @@ class MAGNUM_GL_EXPORT Buffer: public AbstractObject {
* before mapping. * before mapping.
*/ */
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
Unsynchronized = GL_MAP_UNSYNCHRONIZED_BIT Unsynchronized = GL_MAP_UNSYNCHRONIZED_BIT,
#else #else
Unsynchronized = GL_MAP_UNSYNCHRONIZED_BIT_EXT Unsynchronized = GL_MAP_UNSYNCHRONIZED_BIT_EXT,
#endif
#ifndef MAGNUM_TARGET_GLES
/**
* Allow reading from or writing to the buffer while it is mapped.
* @m_since_latest
* @requires_gl44 Extension @gl_extension{ARB,buffer_storage}
* @requires_gl Buffer storage is not available in OpenGL ES and
* WebGL, use @ref setData() instead.
*/
Persistent = GL_MAP_PERSISTENT_BIT,
/**
* Shared access to buffer that's both mapped and used will be
* coherent.
* @m_since_latest
* @requires_gl44 Extension @gl_extension{ARB,buffer_storage}
* @requires_gl Buffer storage is not available in OpenGL ES and
* WebGL, use @ref setData() instead.
*/
Coherent = GL_MAP_COHERENT_BIT
#endif #endif
}; };
@ -507,6 +529,53 @@ class MAGNUM_GL_EXPORT Buffer: public AbstractObject {
typedef Containers::EnumSet<MapFlag> MapFlags; typedef Containers::EnumSet<MapFlag> MapFlags;
#endif #endif
#ifndef MAGNUM_TARGET_GLES
/**
* @brief Buffer storage flag
* @m_since_latest
*
* @see @ref StorageFlags, @ref setStorage()
* @m_enum_values_as_keywords
* @requires_gl44 Extension @gl_extension{ARB,buffer_storage}
* @requires_gl Buffer storage is not available in OpenGL ES and WebGL,
* use @ref setData() instead.
*/
enum class StorageFlag: GLbitfield {
/** Allow the buffer to be mapped with @ref MapFlag::Read. */
MapRead = GL_MAP_READ_BIT,
/** Allow the buffer to be mapped with @ref MapFlag::Write. */
MapWrite = GL_MAP_WRITE_BIT,
/** Allow the buffer to be mapped with @ref MapFlag::Persistent. */
MapPersistent = GL_MAP_PERSISTENT_BIT,
/** Allow the buffer to be mapped with @ref MapFlag::Coherent. */
MapCoherent = GL_MAP_COHERENT_BIT,
/**
* Allow the buffer to be updated with @ref setSubData(). Note that
* the buffer can still be updated through @ref copy() even without
* this flag present.
*/
DynamicStorage = GL_DYNAMIC_STORAGE_BIT,
/** Prefer to allocate the memory in client memory space. */
ClientStorage = GL_CLIENT_STORAGE_BIT
};
/**
* @brief Buffer storage flags
* @m_since_latest
*
* @see @ref setStorage()
* @requires_gl44 Extension @gl_extension{ARB,buffer_storage}
* @requires_gl Buffer storage is not available in OpenGL ES and WebGL,
* use @ref setData() instead.
*/
typedef Containers::EnumSet<StorageFlag> StorageFlags;
#endif
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
/** /**
* @brief Minimal supported mapping alignment * @brief Minimal supported mapping alignment
@ -963,6 +1032,40 @@ class MAGNUM_GL_EXPORT Buffer: public AbstractObject {
Buffer& bind(Target target, UnsignedInt index); Buffer& bind(Target target, UnsignedInt index);
#endif #endif
#ifndef MAGNUM_TARGET_GLES
/**
* @brief Set storage
* @param data Data
* @param flags Storage flags
* @m_since_latest
*
* If @gl_extension{ARB,direct_state_access} (part of OpenGL 4.5) is
* not available, the buffer is bound to hinted target before the
* operation (if not already).
* @see @ref setTargetHint(),
* @fn_gl2_keyword{NamedBufferStorage,BufferStorage}, eventually
* @fn_gl{BindBuffer} and @fn_gl_keyword{BufferStorage}
* @requires_gl44 Extension @gl_extension{ARB,buffer_storage}
* @requires_gl Buffer storage is not available in OpenGL ES and WebGL,
* use @ref setData() instead.
*/
Buffer& setStorage(Containers::ArrayView<const void> data, StorageFlags flags);
/**
* @brief Set storage
* @param size Size in bytes
* @param flags Storage flags
* @m_since_latest
*
* Equivalent to calling @ref setStorage(Containers::ArrayView<const void>, StorageFlags)
* with a @cpp nullptr @ce view of @p size bytes.
* @requires_gl44 Extension @gl_extension{ARB,buffer_storage}
* @requires_gl Buffer storage is not available in OpenGL ES and WebGL,
* use @ref setData() instead.
*/
Buffer& setStorage(std::size_t size, StorageFlags flags);
#endif
/** /**
* @brief Buffer size in bytes * @brief Buffer size in bytes
* *
@ -1236,6 +1339,11 @@ class MAGNUM_GL_EXPORT Buffer: public AbstractObject {
Buffer& setLabelInternal(Containers::ArrayView<const char> label); Buffer& setLabelInternal(Containers::ArrayView<const char> label);
#endif #endif
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_GL_LOCAL storageImplementationDefault(Containers::ArrayView<const void> data, StorageFlags flags);
void MAGNUM_GL_LOCAL storageImplementationDSA(Containers::ArrayView<const void> data, StorageFlags flags);
#endif
void MAGNUM_GL_LOCAL getParameterImplementationDefault(GLenum value, GLint* data); void MAGNUM_GL_LOCAL getParameterImplementationDefault(GLenum value, GLint* data);
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
void MAGNUM_GL_LOCAL getParameterImplementationDSA(GLenum value, GLint* data); void MAGNUM_GL_LOCAL getParameterImplementationDSA(GLenum value, GLint* data);
@ -1323,6 +1431,10 @@ class MAGNUM_GL_EXPORT Buffer: public AbstractObject {
CORRADE_ENUMSET_OPERATORS(Buffer::MapFlags) CORRADE_ENUMSET_OPERATORS(Buffer::MapFlags)
#endif #endif
#ifndef MAGNUM_TARGET_GLES
CORRADE_ENUMSET_OPERATORS(Buffer::StorageFlags)
#endif
/** @debugoperatorclassenum{Buffer,Buffer::TargetHint} */ /** @debugoperatorclassenum{Buffer,Buffer::TargetHint} */
MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, Buffer::TargetHint value); MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, Buffer::TargetHint value);

6
src/Magnum/GL/Implementation/BufferState.cpp

@ -100,6 +100,9 @@ BufferState::BufferState(Context& context, std::vector<std::string>& extensions)
createImplementation = &Buffer::createImplementationDSA; createImplementation = &Buffer::createImplementationDSA;
copyImplementation = &Buffer::copyImplementationDSA; copyImplementation = &Buffer::copyImplementationDSA;
#ifndef MAGNUM_TARGET_GLES
storageImplementation = &Buffer::storageImplementationDSA;
#endif
getParameterImplementation = &Buffer::getParameterImplementationDSA; getParameterImplementation = &Buffer::getParameterImplementationDSA;
getSubDataImplementation = &Buffer::getSubDataImplementationDSA; getSubDataImplementation = &Buffer::getSubDataImplementationDSA;
dataImplementation = &Buffer::dataImplementationDSA; dataImplementation = &Buffer::dataImplementationDSA;
@ -115,6 +118,9 @@ BufferState::BufferState(Context& context, std::vector<std::string>& extensions)
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
copyImplementation = &Buffer::copyImplementationDefault; copyImplementation = &Buffer::copyImplementationDefault;
#endif #endif
#ifndef MAGNUM_TARGET_GLES
storageImplementation = &Buffer::storageImplementationDefault;
#endif
getParameterImplementation = &Buffer::getParameterImplementationDefault; getParameterImplementation = &Buffer::getParameterImplementationDefault;
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
getSubDataImplementation = &Buffer::getSubDataImplementationDefault; getSubDataImplementation = &Buffer::getSubDataImplementationDefault;

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

@ -57,6 +57,9 @@ struct BufferState {
#endif #endif
void(Buffer::*createImplementation)(); void(Buffer::*createImplementation)();
void(Buffer::*setTargetHintImplementation)(Buffer::TargetHint); void(Buffer::*setTargetHintImplementation)(Buffer::TargetHint);
#ifndef MAGNUM_TARGET_GLES
void(Buffer::*storageImplementation)(Containers::ArrayView<const void>, Buffer::StorageFlags);
#endif
void(Buffer::*getParameterImplementation)(GLenum, GLint*); void(Buffer::*getParameterImplementation)(GLenum, GLint*);
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
void(Buffer::*getSubDataImplementation)(GLintptr, GLsizeiptr, GLvoid*); void(Buffer::*getSubDataImplementation)(GLintptr, GLsizeiptr, GLvoid*);

23
src/Magnum/GL/Test/BufferGLTest.cpp

@ -54,6 +54,10 @@ struct BufferGLTest: OpenGLTester {
void bindRange(); void bindRange();
#endif #endif
#ifndef MAGNUM_TARGET_GLES
void storage();
#endif
void data(); void data();
#ifndef MAGNUM_TARGET_WEBGL #ifndef MAGNUM_TARGET_WEBGL
void map(); void map();
@ -81,6 +85,10 @@ BufferGLTest::BufferGLTest() {
&BufferGLTest::bindRange, &BufferGLTest::bindRange,
#endif #endif
#ifndef MAGNUM_TARGET_GLES
&BufferGLTest::storage,
#endif
&BufferGLTest::data, &BufferGLTest::data,
#ifndef MAGNUM_TARGET_WEBGL #ifndef MAGNUM_TARGET_WEBGL
&BufferGLTest::map, &BufferGLTest::map,
@ -241,6 +249,21 @@ void BufferGLTest::bindRange() {
} }
#endif #endif
#ifndef MAGNUM_TARGET_GLES
void BufferGLTest::storage() {
Buffer buffer;
constexpr Int data[] = {2, 7, 5, 13, 25};
buffer.setStorage(data, Buffer::StorageFlag::MapRead|Buffer::StorageFlag::ClientStorage);
MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_COMPARE_AS(Containers::arrayCast<Int>(buffer.data()),
Containers::arrayView(data),
TestSuite::Compare::Container);
}
#endif
void BufferGLTest::data() { void BufferGLTest::data() {
Buffer buffer; Buffer buffer;

Loading…
Cancel
Save