From dc312cda0d78b60d1ca1f79912cf8f2d86c4d0ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 24 Aug 2014 19:01:51 +0200 Subject: [PATCH] Implemented indexed buffer binding. The indexed binding is allowed for only some types (atomic counters, uniforms, shader storage and transform feedback), thus we need separate enum for that. Because the bind() function will be used far more often than setTargetHint(), the original Target enum is now renamed to TargetHint and the new Target enum contains (in non-deprecated build) only three values. For backwards compatibility, though, we need to have all original Target values, thus the new Target enum contains also all other values from TargetHint, but they are marked as deprecated and (at least) run-time checked in bind() so they aren't accidentaly used for indexed binding. Similarly there are also deprecated Target overloads of Buffer() and setTargetHint(). It's ugly, but hopefully will suffice for now. This mess will be removed as soon as possible in some upcoming version. --- doc/opengl-mapping.dox | 2 +- doc/opengl-support.dox | 6 +- src/Magnum/AbstractFramebuffer.cpp | 2 +- src/Magnum/AbstractTexture.cpp | 26 +- src/Magnum/Buffer.cpp | 151 +++++++- src/Magnum/Buffer.h | 341 +++++++++++++++++- src/Magnum/BufferImage.cpp | 4 +- src/Magnum/DebugTools/ForceRenderer.cpp | 4 +- .../Implementation/AbstractShapeRenderer.cpp | 8 +- src/Magnum/DebugTools/ObjectRenderer.cpp | 4 +- src/Magnum/Implementation/BufferState.cpp | 71 ++-- src/Magnum/Implementation/BufferState.h | 6 +- src/Magnum/Mesh.cpp | 12 +- src/Magnum/MeshTools/Compile.cpp | 8 +- src/Magnum/Test/BufferGLTest.cpp | 64 +++- src/Magnum/Test/MeshGLTest.cpp | 20 +- src/Magnum/Text/Renderer.cpp | 2 +- 17 files changed, 630 insertions(+), 101 deletions(-) diff --git a/doc/opengl-mapping.dox b/doc/opengl-mapping.dox index 31f85dcf0..e4b3988e5 100644 --- a/doc/opengl-mapping.dox +++ b/doc/opengl-mapping.dox @@ -49,7 +49,7 @@ OpenGL function | Matching API @fn_gl{BeginTransformFeedback}, `glEndTransformFeedback()` | | @fn_gl{BindAttribLocation} | @ref AbstractShaderProgram::bindAttributeLocation() @fn_gl{BindBuffer} | not needed, handled internally in @ref Buffer and elsewhere -@fn_gl{BindBufferBase}, \n @fn_gl{BindBuffersBase}, \n @fn_gl{BindBufferRange}, \n @fn_gl{BindBuffersRange} | | +@fn_gl{BindBufferBase}, \n @fn_gl{BindBuffersBase}, \n @fn_gl{BindBufferRange}, \n @fn_gl{BindBuffersRange} | @ref Buffer::bind(), \n @ref Buffer::unbind() @fn_gl{BindFragDataLocation} | @ref AbstractShaderProgram::bindFragmentDataLocation() @fn_gl{BindFragDataLocationIndexed} | @ref AbstractShaderProgram::bindFragmentDataLocationIndexed() @fn_gl{BindFramebuffer} | @ref Framebuffer::bind() diff --git a/doc/opengl-support.dox b/doc/opengl-support.dox index fb75af729..e86d2a38a 100644 --- a/doc/opengl-support.dox +++ b/doc/opengl-support.dox @@ -81,7 +81,7 @@ following: @extension{ARB,texture_rectangle} | done @extension{ARB,draw_instanced} | done @extension{ARB,texture_buffer_object} | done -@extension{ARB,uniform_buffer_object} | | +@extension{ARB,uniform_buffer_object} | missing uniform block binding @extension{ARB,copy_buffer} | done @extension{EXT,texture_snorm} | done @extension{NV,primitive_restart} | | @@ -156,7 +156,7 @@ following: @extension{ARB,conservative_depth} | done (shading language only) @extension{ARB,internalformat_query} | | @extension{ARB,map_buffer_alignment} | done -@extension{ARB,shader_atomic_counters} | | +@extension{ARB,shader_atomic_counters} | done @extension{ARB,shader_image_load_store} | | @extension{ARB,shading_language_packing} | done (shading language only) @extension{ARB,texture_storage} | done @@ -198,7 +198,7 @@ following: @extension{ARB,buffer_storage} | | @extension{ARB,clear_texture} | | @extension{ARB,enhanced_layouts} | done (shading language only) -@extension{ARB,multi_bind} | only texture binding +@extension{ARB,multi_bind} | only texture and buffer binding @extension{ARB,query_buffer_object} | | @extension{ARB,texture_mirror_clamp_to_edge} | done @extension{ARB,texture_stencil8} | done diff --git a/src/Magnum/AbstractFramebuffer.cpp b/src/Magnum/AbstractFramebuffer.cpp index 03b5ab92c..fcc26147d 100644 --- a/src/Magnum/AbstractFramebuffer.cpp +++ b/src/Magnum/AbstractFramebuffer.cpp @@ -237,7 +237,7 @@ void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, Buf if(image.size() != size) image.setData(image.format(), image.type(), size, nullptr, usage); - image.buffer().bindInternal(Buffer::Target::PixelPack); + image.buffer().bindInternal(Buffer::TargetHint::PixelPack); (Context::current()->state().framebuffer->readImplementation)(offset, size, image.format(), image.type(), image.dataSize(size), nullptr); } #endif diff --git a/src/Magnum/AbstractTexture.cpp b/src/Magnum/AbstractTexture.cpp index 419437537..912200142 100644 --- a/src/Magnum/AbstractTexture.cpp +++ b/src/Magnum/AbstractTexture.cpp @@ -1211,7 +1211,7 @@ template void AbstractTexture::image(GLenum target, GLin if(image.size() != size) image.setData(image.format(), image.type(), size, nullptr, usage); - image.buffer().bindInternal(Buffer::Target::PixelPack); + image.buffer().bindInternal(Buffer::TargetHint::PixelPack); (this->*Context::current()->state().texture->getImageImplementation)(target, level, image.format(), image.type(), dataSize, nullptr); } @@ -1279,78 +1279,78 @@ void AbstractTexture::DataHelper<3>::setStorageMultisample(AbstractTexture& text #ifndef MAGNUM_TARGET_GLES void AbstractTexture::DataHelper<1>::setImage(AbstractTexture& texture, const GLenum target, const GLint level, const TextureFormat internalFormat, const ImageReference1D& image) { - Buffer::unbindInternal(Buffer::Target::PixelUnpack); + Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); (texture.*Context::current()->state().texture->image1DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), image.data()); } void AbstractTexture::DataHelper<1>::setImage(AbstractTexture& texture, const GLenum target, const GLint level, const TextureFormat internalFormat, BufferImage1D& image) { - image.buffer().bindInternal(Buffer::Target::PixelUnpack); + image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack); (texture.*Context::current()->state().texture->image1DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), nullptr); } void AbstractTexture::DataHelper<1>::setSubImage(AbstractTexture& texture, const GLenum target, const GLint level, const Math::Vector<1, GLint>& offset, const ImageReference1D& image) { - Buffer::unbindInternal(Buffer::Target::PixelUnpack); + Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); (texture.*Context::current()->state().texture->subImage1DImplementation)(target, level, offset, image.size(), image.format(), image.type(), image.data()); } void AbstractTexture::DataHelper<1>::setSubImage(AbstractTexture& texture, const GLenum target, const GLint level, const Math::Vector<1, GLint>& offset, BufferImage1D& image) { - image.buffer().bindInternal(Buffer::Target::PixelUnpack); + image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack); (texture.*Context::current()->state().texture->subImage1DImplementation)(target, level, offset, image.size(), image.format(), image.type(), nullptr); } #endif void AbstractTexture::DataHelper<2>::setImage(AbstractTexture& texture, const GLenum target, const GLint level, const TextureFormat internalFormat, const ImageReference2D& image) { #ifndef MAGNUM_TARGET_GLES2 - Buffer::unbindInternal(Buffer::Target::PixelUnpack); + Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); #endif (texture.*Context::current()->state().texture->image2DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), image.data()); } #ifndef MAGNUM_TARGET_GLES2 void AbstractTexture::DataHelper<2>::setImage(AbstractTexture& texture, const GLenum target, const GLint level, const TextureFormat internalFormat, BufferImage2D& image) { - image.buffer().bindInternal(Buffer::Target::PixelUnpack); + image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack); (texture.*Context::current()->state().texture->image2DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), nullptr); } #endif void AbstractTexture::DataHelper<2>::setSubImage(AbstractTexture& texture, const GLenum target, const GLint level, const Vector2i& offset, const ImageReference2D& image) { #ifndef MAGNUM_TARGET_GLES2 - Buffer::unbindInternal(Buffer::Target::PixelUnpack); + Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); #endif (texture.*Context::current()->state().texture->subImage2DImplementation)(target, level, offset, image.size(), image.format(), image.type(), image.data()); } #ifndef MAGNUM_TARGET_GLES2 void AbstractTexture::DataHelper<2>::setSubImage(AbstractTexture& texture, const GLenum target, const GLint level, const Vector2i& offset, BufferImage2D& image) { - image.buffer().bindInternal(Buffer::Target::PixelUnpack); + image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack); (texture.*Context::current()->state().texture->subImage2DImplementation)(target, level, offset, image.size(), image.format(), image.type(), nullptr); } #endif void AbstractTexture::DataHelper<3>::setImage(AbstractTexture& texture, const GLenum target, const GLint level, const TextureFormat internalFormat, const ImageReference3D& image) { #ifndef MAGNUM_TARGET_GLES2 - Buffer::unbindInternal(Buffer::Target::PixelUnpack); + Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); #endif (texture.*Context::current()->state().texture->image3DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), image.data()); } #ifndef MAGNUM_TARGET_GLES2 void AbstractTexture::DataHelper<3>::setImage(AbstractTexture& texture, const GLenum target, const GLint level, const TextureFormat internalFormat, BufferImage3D& image) { - image.buffer().bindInternal(Buffer::Target::PixelUnpack); + image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack); (texture.*Context::current()->state().texture->image3DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), nullptr); } #endif void AbstractTexture::DataHelper<3>::setSubImage(AbstractTexture& texture, const GLenum target, const GLint level, const Vector3i& offset, const ImageReference3D& image) { #ifndef MAGNUM_TARGET_GLES2 - Buffer::unbindInternal(Buffer::Target::PixelUnpack); + Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); #endif (texture.*Context::current()->state().texture->subImage3DImplementation)(target, level, offset, image.size(), image.format(), image.type(), image.data()); } #ifndef MAGNUM_TARGET_GLES2 void AbstractTexture::DataHelper<3>::setSubImage(AbstractTexture& texture, const GLenum target, const GLint level, const Vector3i& offset, BufferImage3D& image) { - image.buffer().bindInternal(Buffer::Target::PixelUnpack); + image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack); (texture.*Context::current()->state().texture->subImage3DImplementation)(target, level, offset, image.size(), image.format(), image.type(), nullptr); } #endif diff --git a/src/Magnum/Buffer.cpp b/src/Magnum/Buffer.cpp index b42b95d09..4529c0290 100644 --- a/src/Magnum/Buffer.cpp +++ b/src/Magnum/Buffer.cpp @@ -127,12 +127,42 @@ Int Buffer::maxUniformBindings() { return value; } +void Buffer::unbind(const Target target, const UnsignedInt index) { + #ifdef MAGNUM_BUILD_DEPRECATED + CORRADE_INTERNAL_ASSERT(target == Target::AtomicCounter || target == Target::ShaderStorage || target == Target::Uniform); + #endif + glBindBufferBase(GLenum(target), index, 0); +} + +void Buffer::unbind(const Target target, const UnsignedInt firstIndex, const std::size_t count) { + #ifdef MAGNUM_BUILD_DEPRECATED + CORRADE_INTERNAL_ASSERT(target == Target::AtomicCounter || target == Target::ShaderStorage || target == Target::Uniform); + #endif + Context::current()->state().buffer->bindBasesImplementation(target, firstIndex, {nullptr, count}); +} + +/** @todoc const std::initializer_list makes Doxygen grumpy */ +void Buffer::bind(const Target target, const UnsignedInt firstIndex, std::initializer_list> buffers) { + #ifdef MAGNUM_BUILD_DEPRECATED + CORRADE_INTERNAL_ASSERT(target == Target::AtomicCounter || target == Target::ShaderStorage || target == Target::Uniform); + #endif + Context::current()->state().buffer->bindRangesImplementation(target, firstIndex, {buffers.begin(), buffers.size()}); +} + +/** @todoc const std::initializer_list makes Doxygen grumpy */ +void Buffer::bind(const Target target, const UnsignedInt firstIndex, std::initializer_list buffers) { + #ifdef MAGNUM_BUILD_DEPRECATED + CORRADE_INTERNAL_ASSERT(target == Target::AtomicCounter || target == Target::ShaderStorage || target == Target::Uniform); + #endif + Context::current()->state().buffer->bindBasesImplementation(target, firstIndex, {buffers.begin(), buffers.size()}); +} + void Buffer::copy(Buffer& read, Buffer& write, const GLintptr readOffset, const GLintptr writeOffset, const GLsizeiptr size) { Context::current()->state().buffer->copyImplementation(read, write, readOffset, writeOffset, size); } #endif -Buffer::Buffer(const Target targetHint): _targetHint{targetHint}, +Buffer::Buffer(const TargetHint targetHint): _targetHint{targetHint}, #ifdef CORRADE_TARGET_NACL _mappedBuffer{nullptr}, #endif @@ -186,7 +216,7 @@ Buffer& Buffer::setLabelInternal(const Containers::ArrayReference la return *this; } -void Buffer::bindInternal(const Target target, Buffer* const buffer) { +void Buffer::bindInternal(const TargetHint target, Buffer* const buffer) { const GLuint id = buffer ? buffer->_id : 0; GLuint& bound = Context::current()->state().buffer->bindings[Implementation::BufferState::indexForTarget(target)]; @@ -199,7 +229,7 @@ void Buffer::bindInternal(const Target target, Buffer* const buffer) { glBindBuffer(GLenum(target), id); } -Buffer::Target Buffer::bindSomewhereInternal(Target hint) { +auto Buffer::bindSomewhereInternal(const TargetHint hint) -> TargetHint { GLuint* bindings = Context::current()->state().buffer->bindings; GLuint& hintBinding = bindings[Implementation::BufferState::indexForTarget(hint)]; @@ -218,6 +248,24 @@ Buffer::Target Buffer::bindSomewhereInternal(Target hint) { return hint; } +#ifndef MAGNUM_TARGET_GLES2 +Buffer& Buffer::bind(const Target target, const UnsignedInt index, const GLintptr offset, const GLsizeiptr size) { + #ifdef MAGNUM_BUILD_DEPRECATED + CORRADE_INTERNAL_ASSERT(target == Target::AtomicCounter || target == Target::ShaderStorage || target == Target::Uniform); + #endif + glBindBufferRange(GLenum(target), index, _id, offset, size); + return *this; +} + +Buffer& Buffer::bind(const Target target, const UnsignedInt index) { + #ifdef MAGNUM_BUILD_DEPRECATED + CORRADE_INTERNAL_ASSERT(target == Target::AtomicCounter || target == Target::ShaderStorage || target == Target::Uniform); + #endif + glBindBufferBase(GLenum(target), index, _id); + return *this; +} +#endif + Int Buffer::size() { /** * @todo there is something like glGetBufferParameteri64v in 3.2 (I @@ -296,8 +344,59 @@ void Buffer::subDataInternal(GLintptr offset, GLsizeiptr size, GLvoid* data) { #endif #ifndef MAGNUM_TARGET_GLES2 +void Buffer::bindImplementationFallback(const Target target, const GLuint firstIndex, Containers::ArrayReference buffers) { + for(std::size_t i = 0; i != buffers.size(); ++i) { + if(buffers && buffers[i]) buffers[i]->bind(target, firstIndex + i); + else unbind(target, firstIndex + i); + } +} + +#ifndef MAGNUM_TARGET_GLES +void Buffer::bindImplementationMulti(const Target target, const GLuint firstIndex, Containers::ArrayReference buffers) { + Containers::Array ids{buffers ? buffers.size() : 0}; + if(buffers) for(std::size_t i = 0; i != buffers.size(); ++i) { + if(buffers[i]) { + buffers[i]->createIfNotAlready(); + ids[i] = buffers[i]->_id; + } else { + ids[i] = 0; + } + } + + glBindBuffersBase(GLenum(target), firstIndex, buffers.size(), ids); +} +#endif + +void Buffer::bindImplementationFallback(const Target target, const GLuint firstIndex, const Containers::ArrayReference> buffers) { + for(std::size_t i = 0; i != buffers.size(); ++i) { + if(buffers && std::get<0>(buffers[i])) + std::get<0>(buffers[i])->bind(target, firstIndex + i, std::get<1>(buffers[i]), std::get<2>(buffers[i])); + else unbind(target, firstIndex + i); + } +} + +#ifndef MAGNUM_TARGET_GLES +void Buffer::bindImplementationMulti(const Target target, const GLuint firstIndex, const Containers::ArrayReference> buffers) { + /** @todo use ArrayTuple */ + Containers::Array ids{buffers ? buffers.size() : 0}; + Containers::Array offsetsSizes{buffers ? buffers.size()*2 : 0}; + if(buffers) for(std::size_t i = 0; i != buffers.size(); ++i) { + if(std::get<0>(buffers[i])) { + std::get<0>(buffers[i])->createIfNotAlready(); + ids[i] = std::get<0>(buffers[i])->_id; + std::tie(std::ignore, offsetsSizes[i], offsetsSizes[buffers.size() + i]) = buffers[i]; + } else { + ids[i] = 0; + offsetsSizes[i] = offsetsSizes[buffers.size() + i] = 0; + } + } + + glBindBuffersRange(GLenum(target), firstIndex, buffers.size(), ids, offsetsSizes, offsetsSizes + buffers.size()); +} +#endif + void Buffer::copyImplementationDefault(Buffer& read, Buffer& write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { - glCopyBufferSubData(GLenum(read.bindSomewhereInternal(Target::CopyRead)), GLenum(write.bindSomewhereInternal(Target::CopyWrite)), readOffset, writeOffset, size); + glCopyBufferSubData(GLenum(read.bindSomewhereInternal(TargetHint::CopyRead)), GLenum(write.bindSomewhereInternal(TargetHint::CopyWrite)), readOffset, writeOffset, size); } #ifndef MAGNUM_TARGET_GLES @@ -445,9 +544,9 @@ bool Buffer::unmapImplementationDSA() { #endif #ifndef DOXYGEN_GENERATING_OUTPUT -Debug operator<<(Debug debug, Buffer::Target value) { +Debug operator<<(Debug debug, Buffer::TargetHint value) { switch(value) { - #define _c(value) case Buffer::Target::value: return debug << "Buffer::Target::" #value; + #define _c(value) case Buffer::TargetHint::value: return debug << "Buffer::TargetHint::" #value; _c(Array) #ifndef MAGNUM_TARGET_GLES2 _c(AtomicCounter) @@ -472,8 +571,48 @@ Debug operator<<(Debug debug, Buffer::Target value) { #undef _c } + return debug << "Buffer::TargetHint::(invalid)"; +} +#endif + +#if !defined(MAGNUM_TARGET_GLES2) || defined(MAGNUM_BUILD_DEPRECATED) +#ifndef DOXYGEN_GENERATING_OUTPUT +Debug operator<<(Debug debug, Buffer::Target value) { + switch(value) { + #ifndef MAGNUM_TARGET_GLES2 + #define _c(value) case Buffer::Target::value: return debug << "Buffer::Target::" #value; + _c(AtomicCounter) + _c(ShaderStorage) + _c(Uniform) + #undef _c + #endif + + #ifdef MAGNUM_BUILD_DEPRECATED + case Buffer::Target::Array: + #ifndef MAGNUM_TARGET_GLES2 + case Buffer::Target::CopyRead: + case Buffer::Target::CopyWrite: + case Buffer::Target::DispatchIndirect: + case Buffer::Target::DrawIndirect: + #endif + case Buffer::Target::ElementArray: + #ifndef MAGNUM_TARGET_GLES2 + case Buffer::Target::PixelPack: + case Buffer::Target::PixelUnpack: + #endif + #ifndef MAGNUM_TARGET_GLES + case Buffer::Target::Texture: + #endif + #ifndef MAGNUM_TARGET_GLES2 + case Buffer::Target::TransformFeedback: + #endif + return debug << static_cast(value); + #endif + } + return debug << "Buffer::Target::(invalid)"; } #endif +#endif } diff --git a/src/Magnum/Buffer.h b/src/Magnum/Buffer.h index f04773764..200b185cd 100644 --- a/src/Magnum/Buffer.h +++ b/src/Magnum/Buffer.h @@ -215,7 +215,7 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * * @see @ref Buffer(), @ref setTargetHint() */ - enum class Target: GLenum { + enum class TargetHint: GLenum { /** Used for storing vertex attributes. */ Array = GL_ARRAY_BUFFER, @@ -316,6 +316,139 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { #endif }; + #if !defined(MAGNUM_TARGET_GLES2) || defined(MAGNUM_BUILD_DEPRECATED) + /** + * @brief %Buffer binding target + * + * @see @ref bind(), @ref unbind() + */ + enum class Target: GLenum { + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @copydoc TargetHint::Array + * @deprecated For @ref Magnum::Buffer::setTargetHint() "setTargetHint()" + * only, use @ref Magnum::Buffer::TargetHint::Array "TargetHint::Array" + * instead. + */ + Array = GL_ARRAY_BUFFER, + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * Atomic counter binding + * @requires_gl42 %Extension @extension{ARB,shader_atomic_counters} + * @requires_gles31 Atomic counters are not available in OpenGL ES + * 3.0 and older + */ + AtomicCounter = GL_ATOMIC_COUNTER_BUFFER, + #endif + + #ifdef MAGNUM_BUILD_DEPRECATED + #ifndef MAGNUM_TARGET_GLES2 + /** + * @copydoc TargetHint::CopyRead + * @deprecated For @ref Magnum::Buffer::setTargetHint() "setTargetHint()" + * only, use @ref Magnum::Buffer::TargetHint::CopyRead "TargetHint::CopyRead" + * instead. + */ + CopyRead = GL_COPY_READ_BUFFER, + + /** + * @copydoc TargetHint::CopyWrite + * @deprecated For @ref Magnum::Buffer::setTargetHint() "setTargetHint()" + * only, use @ref Magnum::Buffer::TargetHint::CopyWrite "TargetHint::CopyWrite" + * instead. + */ + CopyWrite = GL_COPY_WRITE_BUFFER, + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * @copydoc TargetHint::DispatchIndirect + * @deprecated For @ref Magnum::Buffer::setTargetHint() "setTargetHint()" + * only, use @ref Magnum::Buffer::TargetHint::DispatchIndirect "TargetHint::DispatchIndirect" + * instead. + */ + DispatchIndirect = GL_DISPATCH_INDIRECT_BUFFER, + + /** + * @copydoc TargetHint::DrawIndirect + * @deprecated For @ref Magnum::Buffer::setTargetHint() "setTargetHint()" + * only, use @ref Magnum::Buffer::TargetHint::DrawIndirect "TargetHint::DrawIndirect" + * instead. + */ + DrawIndirect = GL_DRAW_INDIRECT_BUFFER, + #endif + + /** + * @copydoc TargetHint::ElementArray + * @deprecated For @ref Magnum::Buffer::setTargetHint() "setTargetHint()" + * only, use @ref Magnum::Buffer::TargetHint::ElementArray "TargetHint::ElementArray" + * instead. + */ + ElementArray = GL_ELEMENT_ARRAY_BUFFER, + + #ifndef MAGNUM_TARGET_GLES2 + /** + * @copydoc TargetHint::PixelPack + * @deprecated For @ref Magnum::Buffer::setTargetHint() "setTargetHint()" + * only, use @ref Magnum::Buffer::TargetHint::PixelPack "TargetHint::PixelPack" + * instead. + */ + PixelPack = GL_PIXEL_PACK_BUFFER, + + /** + * @copydoc TargetHint::PixelUnpack + * @deprecated For @ref Magnum::Buffer::setTargetHint() "setTargetHint()" + * only, use @ref Magnum::Buffer::TargetHint::PixelUnpack "TargetHint::PixelUnpack" + * instead. + */ + PixelUnpack = GL_PIXEL_UNPACK_BUFFER, + #endif + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * Shader storage binding + * @requires_gl43 %Extension @extension{ARB,shader_storage_buffer_object} + * @requires_gles31 Shader storage is not available in OpenGL ES + * 3.0 and older + */ + ShaderStorage = GL_SHADER_STORAGE_BUFFER, + #endif + + #if defined(MAGNUM_BUILD_DEPRECATED) && !defined(MAGNUM_TARGET_GLES) + /** + * @copydoc TargetHint::Texture + * @deprecated For @ref Magnum::Buffer::setTargetHint() "setTargetHint()" + * only, use @ref Magnum::Buffer::TargetHint::Texture "TargetHint::Texture" + * instead. + */ + Texture = GL_TEXTURE_BUFFER, + #endif + + #if defined(MAGNUM_BUILD_DEPRECATED) && !defined(MAGNUM_TARGET_GLES2) + /** + * @copydoc TargetHint::TransformFeedback + * @deprecated For @ref Magnum::Buffer::setTargetHint() "setTargetHint()" + * only, use @ref Magnum::Buffer::TargetHint::TransformFeedback "TargetHint::TransformFeedback" + * instead. + */ + TransformFeedback = GL_TRANSFORM_FEEDBACK_BUFFER, + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * Uniform binding + * @requires_gl31 %Extension @extension{ARB,uniform_buffer_object} + * @requires_gles30 Uniform buffers are not available in OpenGL ES + * 2.0 + */ + Uniform = GL_UNIFORM_BUFFER + #endif + }; + #endif + #ifdef MAGNUM_BUILD_DEPRECATED /** * @copybrief BufferUsage @@ -455,7 +588,8 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * The result is cached, repeated queries don't result in repeated * OpenGL calls. If neither extension @extension{ARB,shader_atomic_counters} * (part of OpenGL 4.2) nor OpenGL ES 3.1 is available, returns `0`. - * @see @fn_gl{Get} with @def_gl{MAX_ATOMIC_COUNTER_BUFFER_BINDINGS} + * @see @ref bind(), @ref unbind(), @fn_gl{Get} with + * @def_gl{MAX_ATOMIC_COUNTER_BUFFER_BINDINGS} * @requires_gles30 Not defined in OpenGL ES 2.0 */ static Int maxAtomicCounterBindings(); @@ -466,7 +600,8 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * The result is cached, repeated queries don't result in repeated * OpenGL calls. If neither extension @extension{ARB,shader_storage_buffer_object} * (part of OpenGL 4.3) nor OpenGL ES 3.1 is available, returns `0`. - * @see @fn_gl{Get} with @def_gl{MAX_SHADER_STORAGE_BUFFER_BINDINGS} + * @see @ref bind(), @ref unbind(), @fn_gl{Get} with + * @def_gl{MAX_SHADER_STORAGE_BUFFER_BINDINGS} * @requires_gles30 Not defined in OpenGL ES 2.0 */ static Int maxShaderStorageBindings(); @@ -477,7 +612,7 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * The result is cached, repeated queries don't result in repeated * OpenGL calls. If extension @extension{ARB,uniform_buffer_object} * (part of OpenGL 3.1) is not available, returns `1`. - * @see @fn_gl{Get} with @def_gl{UNIFORM_BUFFER_OFFSET_ALIGNMENT} + * @see @ref bind(), @fn_gl{Get} with @def_gl{UNIFORM_BUFFER_OFFSET_ALIGNMENT} * @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0 */ static Int uniformOffsetAlignment(); @@ -488,7 +623,7 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * The result is cached, repeated queries don't result in repeated * OpenGL calls. If neither extension @extension{ARB,shader_storage_buffer_object} * (part of OpenGL 4.3) nor OpenGL ES 3.1 is available, returns `1`. - * @see @fn_gl{Get} with @def_gl{SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT} + * @see @ref bind(), @fn_gl{Get} with @def_gl{SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT} * @requires_gles30 Not defined in OpenGL ES 2.0 */ static Int shaderStorageOffsetAlignment(); @@ -499,11 +634,108 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * The result is cached, repeated queries don't result in repeated * OpenGL calls. If extension @extension{ARB,uniform_buffer_object} * (part of OpenGL 3.1) is not available, returns `0`. - * @see @fn_gl{Get} with @def_gl{MAX_UNIFORM_BUFFER_BINDINGS} + * @see @ref bind(), @ref unbind(), @fn_gl{Get} with + * @def_gl{MAX_UNIFORM_BUFFER_BINDINGS} * @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0 */ static Int maxUniformBindings(); + /** + * @brief Unbind any buffer from given indexed target + * + * The @p index parameter must respect limits for given @p target. + * @note This function is meant to be used only internally from + * @ref AbstractShaderProgram subclasses. See its documentation + * for more information. + * @see @ref bind(), @ref maxAtomicCounterBindings(), + * @ref maxShaderStorageBindings(), @ref maxUniformBindings(), + * @fn_gl{BindBufferBase} + * @requires_gl30 No form of indexed buffer binding is available in + * OpenGL 2.1, see particular @ref Magnum::Buffer::Target "Target" + * values for version requirements. + * @requires_gles30 No form of indexed buffer binding is available in + * OpenGL ES 2.0, see particular @ref Magnum::Buffer::Target "Target" + * values for version requirements. + */ + static void unbind(Target target, UnsignedInt index); + + /** + * @brief Unbind given range of indexed targets + * + * Unbinds all buffers in given target in range @f$ [ firstIndex ; firstIndex + count ] @f$. + * The range of indices must respect limits for given @p target. If + * @extension{ARB,multi_bind} (part of OpenGL 4.4) is not available, + * the feature is emulated with sequence of @ref unbind(Target, UnsignedInt) + * calls. + * @note This function is meant to be used only internally from + * @ref AbstractShaderProgram subclasses. See its documentation + * for more information. + * @see @ref unbind(Target, UnsignedInt), @ref maxAtomicCounterBindings(), + * @ref maxShaderStorageBindings(), @ref maxUniformBindings(), + * @fn_gl{BindBuffersBase} or @fn_gl{BindBufferBase} + * @requires_gl30 No form of indexed buffer binding is available in + * OpenGL 2.1, see particular @ref Magnum::Buffer::Target "Target" + * values for version requirements. + * @requires_gles30 No form of indexed buffer binding is available in + * OpenGL ES 2.0, see particular @ref Magnum::Buffer::Target "Target" + * values for version requirements. + */ + static void unbind(Target target, UnsignedInt firstIndex, std::size_t count); + + /** + * @brief Bind ranges of buffers to given range of indexed targets + * + * Binds first buffer in the list to @p firstIndex, second to + * `firstIndex + 1` etc. Second parameter is offset, third is size. If + * any buffer is `nullptr`, given indexed target is unbound. The range + * of indices must respect limits for given @p target. The offsets must + * respect alignment, which is 4 bytes for @ref Target::AtomicCounter + * and implementation-defined for other targets. If @extension{ARB,multi_bind} + * (part of OpenGL 4.4) is not available, the feature is emulated with + * sequence of @ref bind(Target, UnsignedInt, GLintptr, GLsizeiptr) / + * @ref unbind(Target, UnsignedInt) calls. + * @note This function is meant to be used only internally from + * @ref AbstractShaderProgram subclasses. See its documentation + * for more information. + * @see @ref bind(Target, UnsignedInt, GLintptr, GLsizeiptr), + * @ref maxAtomicCounterBindings(), @ref maxShaderStorageBindings(), + * @ref maxUniformBindings(), @ref shaderStorageOffsetAlignment(), + * @ref uniformOffsetAlignment(), @fn_gl{BindBuffersRange} or + * @fn_gl{BindBufferRange} + * @requires_gl30 No form of indexed buffer binding is available in + * OpenGL 2.1, see particular @ref Magnum::Buffer::Target "Target" + * values for version requirements. + * @requires_gles30 No form of indexed buffer binding is available in + * OpenGL ES 2.0, see particular @ref Magnum::Buffer::Target "Target" + * values for version requirements. + */ + static void bind(Target target, UnsignedInt firstIndex, std::initializer_list> buffers); + + /** + * @brief Bind buffers to given range of indexed targets + * + * Binds first buffer in the list to @p firstIndex, second to + * `firstIndex + 1` etc. If any buffer is `nullptr`, given indexed + * target is unbound. The range of indices must respect limits for + * given @p target. If @extension{ARB,multi_bind} (part of OpenGL 4.4) + * is not available, the feature is emulated with sequence of + * @ref bind(Target, UnsignedInt) / @ref unbind(Target, UnsignedInt) + * calls. + * @note This function is meant to be used only internally from + * @ref AbstractShaderProgram subclasses. See its documentation + * for more information. + * @see @ref bind(Target, UnsignedInt), @ref maxAtomicCounterBindings(), + * @ref maxShaderStorageBindings(), @ref maxUniformBindings(), + * @fn_gl{BindBuffersBase} or @fn_gl{BindBufferBase} + * @requires_gl30 No form of indexed buffer binding is available in + * OpenGL 2.1, see particular @ref Magnum::Buffer::Target "Target" + * values for version requirements. + * @requires_gles30 No form of indexed buffer binding is available in + * OpenGL ES 2.0, see particular @ref Magnum::Buffer::Target "Target" + * values for version requirements. + */ + static void bind(Target target, UnsignedInt firstIndex, std::initializer_list buffers); + /** * @brief Copy one buffer to another * @param read %Buffer from which to read @@ -532,7 +764,14 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * Creates new OpenGL buffer. * @see @fn_gl{GenBuffers} */ - explicit Buffer(Target targetHint = Target::Array); + explicit Buffer(TargetHint targetHint = TargetHint::Array); + + /** + * @copybrief Buffer(TargetHint) + * @deprecated Use @ref Magnum::Buffer::Buffer(Magnum::Buffer::TargetHint) "Buffer(TargetHint)" + * instead. + */ + CORRADE_DEPRECATED("use Buffer(TargetHint) instead") explicit Buffer(Target targetHint): Buffer{static_cast(targetHint)} {} /** @brief Copying is not allowed */ Buffer(const Buffer&) = delete; @@ -591,7 +830,7 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { } /** @brief Target hint */ - Target targetHint() const { return _targetHint; } + TargetHint targetHint() const { return _targetHint; } /** * @brief Set target hint @@ -608,11 +847,65 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * http://www.opengl.org/wiki/Vertex_Specification#Index_buffers * ... damned GL state */ - Buffer& setTargetHint(Target hint) { + Buffer& setTargetHint(TargetHint hint) { _targetHint = hint; return *this; } + /** + * @copybrief setTargetHint(TargetHint) + * @deprecated Use @ref Magnum::Buffer::setTargetHint(Magnum::Buffer::TargetHint) "setTargetHint(TargetHint)" + * instead. + */ + CORRADE_DEPRECATED("use setTargetHint(TargetHint) instead") Buffer& setTargetHint(Target hint) { + return setTargetHint(static_cast(hint)); + } + + #ifndef MAGNUM_TARGET_GLES2 + /** + * @brief Bind buffer range to given binding index + * + * The @p index parameter must respect limits for given @p target. The + * @p offset parameter must respect alignment, which is 4 bytes for + * @ref Target::AtomicCounter and implementation-defined for other + * targets. + * @note This function is meant to be used only internally from + * @ref AbstractShaderProgram subclasses. See its documentation + * for more information. + * @see @ref bind(Target, UnsignedInt, std::initializer_list>), + * @ref maxAtomicCounterBindings(), @ref maxShaderStorageBindings(), + * @ref maxUniformBindings(), @ref shaderStorageOffsetAlignment(), + * @ref uniformOffsetAlignment(), @fn_gl{BindBufferRange} + * @requires_gl30 No form of indexed buffer binding is available in + * OpenGL 2.1, see particular @ref Magnum::Buffer::Target "Target" + * values for version requirements. + * @requires_gles30 No form of indexed buffer binding is available in + * OpenGL ES 2.0, see particular @ref Magnum::Buffer::Target "Target" + * values for version requirements. + * @todo State tracking for indexed binding + */ + Buffer& bind(Target target, UnsignedInt index, GLintptr offset, GLsizeiptr size); + + /** + * @brief Bind buffer to given binding index + * + * The @p index parameter must respect limits for given @p target. + * @note This function is meant to be used only internally from + * @ref AbstractShaderProgram subclasses. See its documentation + * for more information. + * @see @ref bind(Target, UnsignedInt, std::initializer_list), + * @ref maxAtomicCounterBindings(), @ref maxShaderStorageBindings(), + * @ref maxUniformBindings(), @fn_gl{BindBufferBase} + * @requires_gl30 No form of indexed buffer binding is available in + * OpenGL 2.1, see particular @ref Magnum::Buffer::Target "Target" + * values for version requirements. + * @requires_gles30 No form of indexed buffer binding is available in + * OpenGL ES 2.0, see particular @ref Magnum::Buffer::Target "Target" + * values for version requirements. + */ + Buffer& bind(Target target, UnsignedInt index); + #endif + /** * @brief %Buffer size * @@ -850,13 +1143,26 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { #ifdef DOXYGEN_GENERATING_OUTPUT private: #endif - /* There should be no need to use these from user code */ - static void unbindInternal(Target target) { bindInternal(target, nullptr); } - void bindInternal(Target target) { bindInternal(target, this); } + /* There should be no need to use these from user code. Also it's a bit + unfortunate to have the parameter typed as TargetHint while in this + case it is no hint at all, but it allows to have cleaner public + binding API (just with short Target name) */ + static void unbindInternal(TargetHint target) { bindInternal(target, nullptr); } + void bindInternal(TargetHint target) { bindInternal(target, this); } private: - static void bindInternal(Target hint, Buffer* buffer); - Target MAGNUM_LOCAL bindSomewhereInternal(Target hint); + static void bindInternal(TargetHint hint, Buffer* buffer); + TargetHint MAGNUM_LOCAL bindSomewhereInternal(TargetHint hint); + + static void MAGNUM_LOCAL bindImplementationFallback(Target target, GLuint first, Containers::ArrayReference buffers); + #ifndef MAGNUM_TARGET_GLES + static void MAGNUM_LOCAL bindImplementationMulti(Target target, GLuint first, Containers::ArrayReference buffers); + #endif + + static void MAGNUM_LOCAL bindImplementationFallback(Target target, GLuint first, Containers::ArrayReference> buffers); + #ifndef MAGNUM_TARGET_GLES + static void MAGNUM_LOCAL bindImplementationMulti(Target target, GLuint first, Containers::ArrayReference> buffers); + #endif #ifndef MAGNUM_TARGET_GLES2 static void MAGNUM_LOCAL copyImplementationDefault(Buffer& read, Buffer& write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); @@ -924,7 +1230,7 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { #endif GLuint _id; - Target _targetHint; + TargetHint _targetHint; #ifdef CORRADE_TARGET_NACL void* _mappedBuffer; #endif @@ -933,8 +1239,13 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { CORRADE_ENUMSET_OPERATORS(Buffer::MapFlags) +/** @debugoperatorclassenum{Magnum::Buffer,Magnum::Buffer::TargetHint} */ +Debug MAGNUM_EXPORT operator<<(Debug debug, Buffer::TargetHint value); + +#if !defined(MAGNUM_TARGET_GLES2) || defined(MAGNUM_BUILD_DEPRECATED) /** @debugoperatorclassenum{Magnum::Buffer,Magnum::Buffer::Target} */ Debug MAGNUM_EXPORT operator<<(Debug debug, Buffer::Target value); +#endif inline Buffer::Buffer(Buffer&& other) noexcept: _id{other._id}, _targetHint{other._targetHint}, #ifdef CORRADE_TARGET_NACL diff --git a/src/Magnum/BufferImage.cpp b/src/Magnum/BufferImage.cpp index 38fa069a2..30556b7f6 100644 --- a/src/Magnum/BufferImage.cpp +++ b/src/Magnum/BufferImage.cpp @@ -28,11 +28,11 @@ namespace Magnum { #ifndef MAGNUM_TARGET_GLES2 -template BufferImage::BufferImage(ColorFormat format, ColorType type, const VectorTypeFor& size, const void* data, BufferUsage usage): AbstractImage(format, type), _size(size), _buffer(Buffer::Target::PixelPack) { +template BufferImage::BufferImage(ColorFormat format, ColorType type, const VectorTypeFor& size, const void* data, BufferUsage usage): AbstractImage(format, type), _size(size), _buffer(Buffer::TargetHint::PixelPack) { _buffer.setData({data, dataSize(size)}, usage); } -template BufferImage::BufferImage(ColorFormat format, ColorType type): AbstractImage(format, type), _buffer(Buffer::Target::PixelPack) {} +template BufferImage::BufferImage(ColorFormat format, ColorType type): AbstractImage(format, type), _buffer(Buffer::TargetHint::PixelPack) {} template void BufferImage::setData(ColorFormat format, ColorType type, const VectorTypeFor& size, const void* data, BufferUsage usage) { _format = format; diff --git a/src/Magnum/DebugTools/ForceRenderer.cpp b/src/Magnum/DebugTools/ForceRenderer.cpp index e46a301ea..46a61e9b3 100644 --- a/src/Magnum/DebugTools/ForceRenderer.cpp +++ b/src/Magnum/DebugTools/ForceRenderer.cpp @@ -68,8 +68,8 @@ template ForceRenderer::ForceRenderer(SceneG if(mesh) return; /* Create the mesh */ - Buffer* vertexBuffer = new Buffer(Buffer::Target::Array); - Buffer* indexBuffer = new Buffer(Buffer::Target::ElementArray); + Buffer* vertexBuffer = new Buffer{Buffer::TargetHint::Array}; + Buffer* indexBuffer = new Buffer{Buffer::TargetHint::ElementArray}; vertexBuffer->setData(positions, BufferUsage::StaticDraw); ResourceManager::instance().set(this->vertexBuffer.key(), vertexBuffer, ResourceDataState::Final, ResourcePolicy::Manual); diff --git a/src/Magnum/DebugTools/Implementation/AbstractShapeRenderer.cpp b/src/Magnum/DebugTools/Implementation/AbstractShapeRenderer.cpp index 0258e6609..ce3eb0316 100644 --- a/src/Magnum/DebugTools/Implementation/AbstractShapeRenderer.cpp +++ b/src/Magnum/DebugTools/Implementation/AbstractShapeRenderer.cpp @@ -46,7 +46,7 @@ template void create(typename MeshData::Type template<> void create<2>(Trade::MeshData2D& data, Resource& meshResource, Resource& vertexBufferResource, Resource& indexBufferResource) { /* Vertex buffer */ - Buffer* buffer = new Buffer(Buffer::Target::Array); + Buffer* buffer = new Buffer{Buffer::TargetHint::Array}; buffer->setData(data.positions(0), BufferUsage::StaticDraw); ResourceManager::instance().set(vertexBufferResource.key(), buffer, ResourceDataState::Final, ResourcePolicy::Manual); @@ -65,7 +65,7 @@ template<> void create<2>(Trade::MeshData2D& data, Resource& meshResource, UnsignedInt indexStart, indexEnd; std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(data.indices()); - Buffer* indexBuffer = new Buffer(Buffer::Target::ElementArray); + Buffer* indexBuffer = new Buffer{Buffer::TargetHint::ElementArray}; indexBuffer->setData(indexData, BufferUsage::StaticDraw); mesh->setCount(data.indices().size()) .setIndexBuffer(*indexBuffer, 0, indexType, indexStart, indexEnd); @@ -78,7 +78,7 @@ template<> void create<2>(Trade::MeshData2D& data, Resource& meshResource, template<> void create<3>(Trade::MeshData3D& data, Resource& meshResource, Resource& vertexBufferResource, Resource& indexBufferResource) { /* Vertex buffer */ - Buffer* vertexBuffer = new Buffer(Buffer::Target::Array); + Buffer* vertexBuffer = new Buffer{Buffer::TargetHint::Array}; vertexBuffer->setData(data.positions(0), BufferUsage::StaticDraw); ResourceManager::instance().set(vertexBufferResource.key(), vertexBuffer, ResourceDataState::Final, ResourcePolicy::Manual); @@ -97,7 +97,7 @@ template<> void create<3>(Trade::MeshData3D& data, Resource& meshResource, UnsignedInt indexStart, indexEnd; std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(data.indices()); - Buffer* indexBuffer = new Buffer(Buffer::Target::ElementArray); + Buffer* indexBuffer = new Buffer{Buffer::TargetHint::ElementArray}; indexBuffer->setData(indexData, BufferUsage::StaticDraw); mesh->setCount(data.indices().size()) .setIndexBuffer(*indexBuffer, 0, indexType, indexStart, indexEnd); diff --git a/src/Magnum/DebugTools/ObjectRenderer.cpp b/src/Magnum/DebugTools/ObjectRenderer.cpp index d7be15cf6..75d2da791 100644 --- a/src/Magnum/DebugTools/ObjectRenderer.cpp +++ b/src/Magnum/DebugTools/ObjectRenderer.cpp @@ -156,8 +156,8 @@ template ObjectRenderer::ObjectRenderer(Scen if(mesh) return; /* Create the mesh */ - Buffer* vertexBuffer = new Buffer(Buffer::Target::Array); - Buffer* indexBuffer = new Buffer(Buffer::Target::ElementArray); + Buffer* vertexBuffer = new Buffer{Buffer::TargetHint::Array}; + Buffer* indexBuffer = new Buffer{Buffer::TargetHint::ElementArray}; Mesh* mesh = new Mesh; vertexBuffer->setData(MeshTools::interleave(Renderer::positions, Renderer::colors), BufferUsage::StaticDraw); diff --git a/src/Magnum/Implementation/BufferState.cpp b/src/Magnum/Implementation/BufferState.cpp index 7d285ed78..12ea300ae 100644 --- a/src/Magnum/Implementation/BufferState.cpp +++ b/src/Magnum/Implementation/BufferState.cpp @@ -34,43 +34,43 @@ namespace Magnum { namespace Implementation { -const Buffer::Target BufferState::targetForIndex[] = { - Buffer::Target::Array, - Buffer::Target::ElementArray, +const Buffer::TargetHint BufferState::targetForIndex[] = { + Buffer::TargetHint::Array, + Buffer::TargetHint::ElementArray, #ifndef MAGNUM_TARGET_GLES2 - Buffer::Target::CopyRead, - Buffer::Target::CopyWrite, - Buffer::Target::PixelPack, - Buffer::Target::PixelUnpack, - Buffer::Target::TransformFeedback, - Buffer::Target::Uniform, - Buffer::Target::AtomicCounter, - Buffer::Target::DispatchIndirect, - Buffer::Target::DrawIndirect, - Buffer::Target::ShaderStorage, + Buffer::TargetHint::CopyRead, + Buffer::TargetHint::CopyWrite, + Buffer::TargetHint::PixelPack, + Buffer::TargetHint::PixelUnpack, + Buffer::TargetHint::TransformFeedback, + Buffer::TargetHint::Uniform, + Buffer::TargetHint::AtomicCounter, + Buffer::TargetHint::DispatchIndirect, + Buffer::TargetHint::DrawIndirect, + Buffer::TargetHint::ShaderStorage, #ifndef MAGNUM_TARGET_GLES - Buffer::Target::Texture + Buffer::TargetHint::Texture #endif #endif }; -std::size_t BufferState::indexForTarget(Buffer::Target target) { +std::size_t BufferState::indexForTarget(Buffer::TargetHint target) { switch(target) { - case Buffer::Target::Array: return 1; - case Buffer::Target::ElementArray: return 2; + case Buffer::TargetHint::Array: return 1; + case Buffer::TargetHint::ElementArray: return 2; #ifndef MAGNUM_TARGET_GLES2 - case Buffer::Target::CopyRead: return 3; - case Buffer::Target::CopyWrite: return 4; - case Buffer::Target::PixelPack: return 5; - case Buffer::Target::PixelUnpack: return 6; - case Buffer::Target::TransformFeedback: return 7; - case Buffer::Target::Uniform: return 8; - case Buffer::Target::AtomicCounter: return 9; - case Buffer::Target::DispatchIndirect: return 10; - case Buffer::Target::DrawIndirect: return 11; - case Buffer::Target::ShaderStorage: return 12; + case Buffer::TargetHint::CopyRead: return 3; + case Buffer::TargetHint::CopyWrite: return 4; + case Buffer::TargetHint::PixelPack: return 5; + case Buffer::TargetHint::PixelUnpack: return 6; + case Buffer::TargetHint::TransformFeedback: return 7; + case Buffer::TargetHint::Uniform: return 8; + case Buffer::TargetHint::AtomicCounter: return 9; + case Buffer::TargetHint::DispatchIndirect: return 10; + case Buffer::TargetHint::DrawIndirect: return 11; + case Buffer::TargetHint::ShaderStorage: return 12; #ifndef MAGNUM_TARGET_GLES - case Buffer::Target::Texture: return 13; + case Buffer::TargetHint::Texture: return 13; #endif #endif } @@ -130,6 +130,21 @@ BufferState::BufferState(Context& context, std::vector& extensions) invalidateSubImplementation = &Buffer::invalidateSubImplementationNoOp; } + #ifndef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::ARB::multi_bind::string()); + + bindBasesImplementation = &Buffer::bindImplementationMulti; + bindRangesImplementation = &Buffer::bindImplementationMulti; + } else + #endif + { + bindBasesImplementation = &Buffer::bindImplementationFallback; + bindRangesImplementation = &Buffer::bindImplementationFallback; + } + #endif + #ifdef MAGNUM_TARGET_GLES static_cast(context); static_cast(extensions); diff --git a/src/Magnum/Implementation/BufferState.h b/src/Magnum/Implementation/BufferState.h index 38d9e101e..41a8dc908 100644 --- a/src/Magnum/Implementation/BufferState.h +++ b/src/Magnum/Implementation/BufferState.h @@ -39,14 +39,16 @@ struct BufferState { #endif /* Target <-> index mapping */ - static std::size_t indexForTarget(Buffer::Target target); - static const Buffer::Target targetForIndex[TargetCount-1]; + static std::size_t indexForTarget(Buffer::TargetHint target); + static const Buffer::TargetHint targetForIndex[TargetCount-1]; explicit BufferState(Context& context, std::vector& extensions); void reset(); #ifndef MAGNUM_TARGET_GLES2 + void(*bindBasesImplementation)(Buffer::Target, UnsignedInt, Containers::ArrayReference); + void(*bindRangesImplementation)(Buffer::Target, UnsignedInt, Containers::ArrayReference>); void(*copyImplementation)(Buffer&, Buffer&, GLintptr, GLintptr, GLsizeiptr); #endif void(Buffer::*getParameterImplementation)(GLenum, GLint*); diff --git a/src/Magnum/Mesh.cpp b/src/Magnum/Mesh.cpp index b530fc704..e14d72d21 100644 --- a/src/Magnum/Mesh.cpp +++ b/src/Magnum/Mesh.cpp @@ -392,7 +392,7 @@ void Mesh::attributePointerImplementationDSA(const Attribute& attribute) { void Mesh::vertexAttribPointer(const Attribute& attribute) { glEnableVertexAttribArray(attribute.location); - attribute.buffer->bindInternal(Buffer::Target::Array); + attribute.buffer->bindInternal(Buffer::TargetHint::Array); glVertexAttribPointer(attribute.location, attribute.size, attribute.type, attribute.normalized, attribute.stride, reinterpret_cast(attribute.offset)); if(attribute.divisor) { #ifndef MAGNUM_TARGET_GLES2 @@ -428,7 +428,7 @@ void Mesh::attributePointerImplementationDSA(const IntegerAttribute& attribute) void Mesh::vertexAttribPointer(const IntegerAttribute& attribute) { glEnableVertexAttribArray(attribute.location); - attribute.buffer->bindInternal(Buffer::Target::Array); + attribute.buffer->bindInternal(Buffer::TargetHint::Array); glVertexAttribIPointer(attribute.location, attribute.size, attribute.type, attribute.stride, reinterpret_cast(attribute.offset)); if(attribute.divisor) glVertexAttribDivisor(attribute.location, attribute.divisor); } @@ -457,7 +457,7 @@ void Mesh::attributePointerImplementationDSA(const LongAttribute& attribute) { void Mesh::vertexAttribPointer(const LongAttribute& attribute) { glEnableVertexAttribArray(attribute.location); - attribute.buffer->bindInternal(Buffer::Target::Array); + attribute.buffer->bindInternal(Buffer::TargetHint::Array); glVertexAttribLPointer(attribute.location, attribute.size, attribute.type, attribute.stride, reinterpret_cast(attribute.offset)); if(attribute.divisor) glVertexAttribDivisor(attribute.location, attribute.divisor); } @@ -502,9 +502,9 @@ void Mesh::bindIndexBufferImplementationVAO(Buffer& buffer) { /* Reset ElementArray binding to force explicit glBindBuffer call later */ /** @todo Do this cleaner way */ - Context::current()->state().buffer->bindings[Implementation::BufferState::indexForTarget(Buffer::Target::ElementArray)] = 0; + Context::current()->state().buffer->bindings[Implementation::BufferState::indexForTarget(Buffer::TargetHint::ElementArray)] = 0; - buffer.bindInternal(Buffer::Target::ElementArray); + buffer.bindInternal(Buffer::TargetHint::ElementArray); } void Mesh::bindImplementationDefault() { @@ -523,7 +523,7 @@ void Mesh::bindImplementationDefault() { #endif /* Bind index buffer, if the mesh is indexed */ - if(_indexBuffer) _indexBuffer->bindInternal(Buffer::Target::ElementArray); + if(_indexBuffer) _indexBuffer->bindInternal(Buffer::TargetHint::ElementArray); } void Mesh::bindImplementationVAO() { diff --git a/src/Magnum/MeshTools/Compile.cpp b/src/Magnum/MeshTools/Compile.cpp index 4f0c979d4..adc585a6d 100644 --- a/src/Magnum/MeshTools/Compile.cpp +++ b/src/Magnum/MeshTools/Compile.cpp @@ -49,7 +49,7 @@ std::tuple, std::unique_ptr> compile(const stride += sizeof(Shaders::Generic2D::TextureCoordinates::Type); /* Create vertex buffer */ - std::unique_ptr vertexBuffer{new Buffer{Buffer::Target::Array}}; + std::unique_ptr vertexBuffer{new Buffer{Buffer::TargetHint::Array}}; /* Interleave positions */ Containers::Array data = MeshTools::interleave( @@ -82,7 +82,7 @@ std::tuple, std::unique_ptr> compile(const UnsignedInt indexStart, indexEnd; std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(meshData.indices()); - indexBuffer.reset(new Buffer{Buffer::Target::ElementArray}); + indexBuffer.reset(new Buffer{Buffer::TargetHint::ElementArray}); indexBuffer->setData(indexData, usage); mesh.setCount(meshData.indices().size()) .setIndexBuffer(*indexBuffer, 0, indexType, indexStart, indexEnd); @@ -109,7 +109,7 @@ std::tuple, std::unique_ptr> compile(const stride += sizeof(Shaders::Generic3D::TextureCoordinates::Type); /* Create vertex buffer */ - std::unique_ptr vertexBuffer{new Buffer{Buffer::Target::Array}}; + std::unique_ptr vertexBuffer{new Buffer{Buffer::TargetHint::Array}}; /* Interleave positions */ Containers::Array data = MeshTools::interleave( @@ -154,7 +154,7 @@ std::tuple, std::unique_ptr> compile(const UnsignedInt indexStart, indexEnd; std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(meshData.indices()); - indexBuffer.reset(new Buffer{Buffer::Target::ElementArray}); + indexBuffer.reset(new Buffer{Buffer::TargetHint::ElementArray}); indexBuffer->setData(indexData, usage); mesh.setCount(meshData.indices().size()) .setIndexBuffer(*indexBuffer, 0, indexType, indexStart, indexEnd); diff --git a/src/Magnum/Test/BufferGLTest.cpp b/src/Magnum/Test/BufferGLTest.cpp index f6ffb3220..495cd8059 100644 --- a/src/Magnum/Test/BufferGLTest.cpp +++ b/src/Magnum/Test/BufferGLTest.cpp @@ -43,6 +43,12 @@ class BufferGLTest: public AbstractOpenGLTester { void constructMove(); void label(); + + #ifndef MAGNUM_TARGET_GLES2 + void bindBase(); + void bindRange(); + #endif + void data(); void map(); #ifdef MAGNUM_TARGET_GLES2 @@ -60,7 +66,14 @@ BufferGLTest::BufferGLTest() { addTests({&BufferGLTest::construct, &BufferGLTest::constructCopy, &BufferGLTest::constructMove, + &BufferGLTest::label, + + #ifndef MAGNUM_TARGET_GLES2 + &BufferGLTest::bindBase, + &BufferGLTest::bindRange, + #endif + &BufferGLTest::data, &BufferGLTest::map, #ifdef MAGNUM_TARGET_GLES2 @@ -80,7 +93,7 @@ void BufferGLTest::construct() { MAGNUM_VERIFY_NO_ERROR(); CORRADE_VERIFY(buffer.id() > 0); - CORRADE_COMPARE(buffer.targetHint(), Buffer::Target::Array); + CORRADE_COMPARE(buffer.targetHint(), Buffer::TargetHint::Array); CORRADE_COMPARE(buffer.size(), 0); } @@ -131,6 +144,55 @@ void BufferGLTest::label() { CORRADE_COMPARE(buffer.label(), "MyBuffer"); } +#ifndef MAGNUM_TARGET_GLES2 +void BufferGLTest::bindBase() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::uniform_buffer_object::string() + std::string{" is not supported."}); + #endif + + Buffer buffer; + buffer.bind(Buffer::Target::Uniform, 15); + + MAGNUM_VERIFY_NO_ERROR(); + + Buffer::unbind(Buffer::Target::Uniform, 15); + + MAGNUM_VERIFY_NO_ERROR(); + + Buffer::bind(Buffer::Target::Uniform, 7, {&buffer, nullptr, &buffer}); + + MAGNUM_VERIFY_NO_ERROR(); + + Buffer::unbind(Buffer::Target::Uniform, 7, 3); + + MAGNUM_VERIFY_NO_ERROR(); +} + +void BufferGLTest::bindRange() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::uniform_buffer_object::string() + std::string{" is not supported."}); + #endif + + /* Check that we have correct offset alignment */ + CORRADE_INTERNAL_ASSERT(256 % Buffer::uniformOffsetAlignment() == 0); + + Buffer buffer; + buffer.setData({nullptr, 1024}, BufferUsage::StaticDraw) + .bind(Buffer::Target::Uniform, 15, 256, 13); + + MAGNUM_VERIFY_NO_ERROR(); + + /** @todo C++14: get rid of std::make_tuple */ + Buffer::bind(Buffer::Target::Uniform, 7, { + std::make_tuple(&buffer, 256, 13), {}, + std::make_tuple(&buffer, 768, 64)}); + + MAGNUM_VERIFY_NO_ERROR(); +} +#endif + void BufferGLTest::data() { Buffer buffer; diff --git a/src/Magnum/Test/MeshGLTest.cpp b/src/Magnum/Test/MeshGLTest.cpp index 603b3501a..51bbf2764 100644 --- a/src/Magnum/Test/MeshGLTest.cpp +++ b/src/Magnum/Test/MeshGLTest.cpp @@ -1262,7 +1262,7 @@ void MeshGLTest::setIndexBuffer() { vertices.setData(indexedVertexData, BufferUsage::StaticDraw); constexpr UnsignedShort indexData[] = { 2, 1, 0 }; - Buffer indices(Buffer::Target::ElementArray); + Buffer indices{Buffer::TargetHint::ElementArray}; indices.setData(indexData, BufferUsage::StaticDraw); Mesh mesh; @@ -1289,7 +1289,7 @@ void MeshGLTest::setIndexBufferRange() { vertices.setData(indexedVertexData, BufferUsage::StaticDraw); constexpr UnsignedShort indexData[] = { 2, 1, 0 }; - Buffer indices(Buffer::Target::ElementArray); + Buffer indices{Buffer::TargetHint::ElementArray}; indices.setData(indexData, BufferUsage::StaticDraw); Mesh mesh; @@ -1321,7 +1321,7 @@ void MeshGLTest::setIndexBufferUnsignedInt() { vertices.setData(indexedVertexData, BufferUsage::StaticDraw); constexpr UnsignedInt indexData[] = { 2, 1, 0 }; - Buffer indices(Buffer::Target::ElementArray); + Buffer indices{Buffer::TargetHint::ElementArray}; indices.setData(indexData, BufferUsage::StaticDraw); Mesh mesh; @@ -1352,7 +1352,7 @@ void MeshGLTest::setBaseVertex() { vertices.setData(indexedVertexDataBaseVertex, BufferUsage::StaticDraw); constexpr UnsignedShort indexData[] = { 2, 1, 0 }; - Buffer indices(Buffer::Target::ElementArray); + Buffer indices{Buffer::TargetHint::ElementArray}; indices.setData(indexData, BufferUsage::StaticDraw); Mesh mesh; @@ -1428,7 +1428,7 @@ void MeshGLTest::setInstanceCountIndexed() { vertices.setData(indexedVertexData, BufferUsage::StaticDraw); constexpr UnsignedShort indexData[] = { 2, 1, 0 }; - Buffer indices(Buffer::Target::ElementArray); + Buffer indices{Buffer::TargetHint::ElementArray}; indices.setData(indexData, BufferUsage::StaticDraw); Mesh mesh; @@ -1500,7 +1500,7 @@ void MeshGLTest::setInstanceCountBaseInstanceIndexed() { vertices.setData(indexedVertexData, BufferUsage::StaticDraw); constexpr UnsignedShort indexData[] = { 2, 1, 0 }; - Buffer indices(Buffer::Target::ElementArray); + Buffer indices{Buffer::TargetHint::ElementArray}; indices.setData(indexData, BufferUsage::StaticDraw); Mesh mesh; @@ -1534,7 +1534,7 @@ void MeshGLTest::setInstanceCountBaseVertex() { vertices.setData(indexedVertexDataBaseVertex, BufferUsage::StaticDraw); constexpr UnsignedShort indexData[] = { 2, 1, 0 }; - Buffer indices(Buffer::Target::ElementArray); + Buffer indices{Buffer::TargetHint::ElementArray}; indices.setData(indexData, BufferUsage::StaticDraw); Mesh mesh; @@ -1570,7 +1570,7 @@ void MeshGLTest::setInstanceCountBaseVertexBaseInstance() { vertices.setData(indexedVertexDataBaseVertex, BufferUsage::StaticDraw); constexpr UnsignedShort indexData[] = { 2, 1, 0 }; - Buffer indices(Buffer::Target::ElementArray); + Buffer indices{Buffer::TargetHint::ElementArray}; indices.setData(indexData, BufferUsage::StaticDraw); Mesh mesh; @@ -1788,7 +1788,7 @@ void MeshGLTest::multiDrawIndexed() { vertices.setData(indexedVertexData, BufferUsage::StaticDraw); constexpr UnsignedShort indexData[] = { 2, 1, 0 }; - Buffer indices(Buffer::Target::ElementArray); + Buffer indices{Buffer::TargetHint::ElementArray}; indices.setData(indexData, BufferUsage::StaticDraw); Mesh mesh; @@ -1813,7 +1813,7 @@ void MeshGLTest::multiDrawBaseVertex() { vertices.setData(indexedVertexDataBaseVertex, BufferUsage::StaticDraw); constexpr UnsignedShort indexData[] = { 2, 1, 0 }; - Buffer indices(Buffer::Target::ElementArray); + Buffer indices{Buffer::TargetHint::ElementArray}; indices.setData(indexData, BufferUsage::StaticDraw); Mesh mesh; diff --git a/src/Magnum/Text/Renderer.cpp b/src/Magnum/Text/Renderer.cpp index ed767bca0..77ba77b7d 100644 --- a/src/Magnum/Text/Renderer.cpp +++ b/src/Magnum/Text/Renderer.cpp @@ -301,7 +301,7 @@ void AbstractRenderer::bufferUnmapImplementationDefault(Buffer& buffer) #endif } -AbstractRenderer::AbstractRenderer(AbstractFont& font, const GlyphCache& cache, const Float size, const Alignment alignment): _vertexBuffer(Buffer::Target::Array), _indexBuffer(Buffer::Target::ElementArray), font(font), cache(cache), size(size), _alignment(alignment), _capacity(0) { +AbstractRenderer::AbstractRenderer(AbstractFont& font, const GlyphCache& cache, const Float size, const Alignment alignment): _vertexBuffer{Buffer::TargetHint::Array}, _indexBuffer{Buffer::TargetHint::ElementArray}, font(font), cache(cache), size(size), _alignment(alignment), _capacity(0) { #ifndef MAGNUM_TARGET_GLES MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::map_buffer_range); #elif defined(MAGNUM_TARGET_GLES2) && !defined(CORRADE_TARGET_EMSCRIPTEN)