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.
- Added a @ref GL::AbstractTexture::target() getter to simplify interaction
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

2
doc/opengl-mapping.dox

@ -85,7 +85,7 @@ OpenGL function | Matching API
@fn_gl{BlitFramebuffer}, \n `glBlitNamedFramebuffer()` | @ref GL::AbstractFramebuffer::blit()
@fn_gl{BufferData}, \n `glNamedBufferData()` | @ref GL::Buffer::setData()
@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()
@subsection opengl-mapping-functions-c C

2
doc/opengl-support.dox

@ -229,7 +229,7 @@ Extension | Status
------------------------------------------- | ------
GLSL 4.40 | done
@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,enhanced_layouts} | done (shading language only)
@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
#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() {
/**
* @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
#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) {
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
@fn_gl_keyword{BindBuffer}. If the buffer is already bound to some target,
functions @ref copy(), @ref setData(), @ref setSubData(), @ref map(),
@ref mapRead(), @ref flushMappedRange() and @ref unmap() use that target
instead of binding the buffer to some specific target. You can also use
functions @ref copy(), @ref setStorage(), @ref setData(), @ref setSubData(),
@ref map(), @ref mapRead(), @ref flushMappedRange() and @ref unmap() use that
target instead of binding the buffer to some specific target. You can also use
@ref setTargetHint() to possibly reduce unnecessary rebinding. Buffer limits
and implementation-defined values (such as @ref maxUniformBindings()) are
cached, so repeated queries don't result in repeated @fn_gl{Get} calls. See
also @ref Context::resetState() and @ref Context::State::Buffers.
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(),
@ref setSubData(), @ref map(), @ref mapRead(), @ref flushMappedRange() and
@ref unmap() use DSA functions to avoid unnecessary calls to @fn_gl{BindBuffer}.
See their respective documentation for more information.
functions @ref copy(), @ref setStorage(), @ref size(), @ref data(),
@ref subData(), @ref setData(), @ref setSubData(), @ref map(), @ref mapRead(),
@ref flushMappedRange() and @ref unmap() use DSA functions to avoid unnecessary
calls to @fn_gl{BindBuffer}. See their respective documentation for more
information.
You can use functions @ref invalidateData() and @ref invalidateSubData() if you
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.
*/
#ifndef MAGNUM_TARGET_GLES2
Unsynchronized = GL_MAP_UNSYNCHRONIZED_BIT
Unsynchronized = GL_MAP_UNSYNCHRONIZED_BIT,
#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
};
@ -507,6 +529,53 @@ class MAGNUM_GL_EXPORT Buffer: public AbstractObject {
typedef Containers::EnumSet<MapFlag> MapFlags;
#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
/**
* @brief Minimal supported mapping alignment
@ -963,6 +1032,40 @@ class MAGNUM_GL_EXPORT Buffer: public AbstractObject {
Buffer& bind(Target target, UnsignedInt index);
#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
*
@ -1236,6 +1339,11 @@ class MAGNUM_GL_EXPORT Buffer: public AbstractObject {
Buffer& setLabelInternal(Containers::ArrayView<const char> label);
#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);
#ifndef MAGNUM_TARGET_GLES
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)
#endif
#ifndef MAGNUM_TARGET_GLES
CORRADE_ENUMSET_OPERATORS(Buffer::StorageFlags)
#endif
/** @debugoperatorclassenum{Buffer,Buffer::TargetHint} */
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;
copyImplementation = &Buffer::copyImplementationDSA;
#ifndef MAGNUM_TARGET_GLES
storageImplementation = &Buffer::storageImplementationDSA;
#endif
getParameterImplementation = &Buffer::getParameterImplementationDSA;
getSubDataImplementation = &Buffer::getSubDataImplementationDSA;
dataImplementation = &Buffer::dataImplementationDSA;
@ -115,6 +118,9 @@ BufferState::BufferState(Context& context, std::vector<std::string>& extensions)
#ifndef MAGNUM_TARGET_GLES2
copyImplementation = &Buffer::copyImplementationDefault;
#endif
#ifndef MAGNUM_TARGET_GLES
storageImplementation = &Buffer::storageImplementationDefault;
#endif
getParameterImplementation = &Buffer::getParameterImplementationDefault;
#ifndef MAGNUM_TARGET_GLES
getSubDataImplementation = &Buffer::getSubDataImplementationDefault;

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

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

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

@ -54,6 +54,10 @@ struct BufferGLTest: OpenGLTester {
void bindRange();
#endif
#ifndef MAGNUM_TARGET_GLES
void storage();
#endif
void data();
#ifndef MAGNUM_TARGET_WEBGL
void map();
@ -81,6 +85,10 @@ BufferGLTest::BufferGLTest() {
&BufferGLTest::bindRange,
#endif
#ifndef MAGNUM_TARGET_GLES
&BufferGLTest::storage,
#endif
&BufferGLTest::data,
#ifndef MAGNUM_TARGET_WEBGL
&BufferGLTest::map,
@ -241,6 +249,21 @@ void BufferGLTest::bindRange() {
}
#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() {
Buffer buffer;

Loading…
Cancel
Save