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)