#ifndef Magnum_Buffer_h #define Magnum_Buffer_h /* This file is part of Magnum. Copyright © 2010, 2011, 2012, 2013, 2014 Vladimír Vondruš Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** @file * @brief Class @ref Magnum::Buffer, enum @ref Magnum::BufferUsage */ #include #include #include #include #include #include #include "Magnum/AbstractObject.h" #include "Magnum/Magnum.h" namespace Magnum { /** @brief %Buffer usage @see @ref Buffer, @ref Buffer::setData(Containers::ArrayReference, BufferUsage) */ enum class BufferUsage: GLenum { /** Set once by the application and used infrequently for drawing. */ StreamDraw = GL_STREAM_DRAW, #ifndef MAGNUM_TARGET_GLES2 /** * Set once as output from an OpenGL command and used infequently for * drawing. * @requires_gles30 Only @ref Magnum::BufferUsage::StreamDraw "BufferUsage::StreamDraw" * is available in OpenGL ES 2.0. */ StreamRead = GL_STREAM_READ, /** * Set once as output from an OpenGL command and used infrequently for * drawing or copying to other buffers. * @requires_gles30 Only @ref Magnum::BufferUsage::StreamDraw "BufferUsage::StreamDraw" * is available in OpenGL ES 2.0. */ StreamCopy = GL_STREAM_COPY, #endif /** Set once by the application and used frequently for drawing. */ StaticDraw = GL_STATIC_DRAW, #ifndef MAGNUM_TARGET_GLES2 /** * Set once as output from an OpenGL command and queried many times by the * application. * @requires_gles30 Only @ref Magnum::BufferUsage::StaticDraw "BufferUsage::StaticDraw" * is available in OpenGL ES 2.0. */ StaticRead = GL_STATIC_READ, /** * Set once as output from an OpenGL command and used frequently for * drawing or copying to other buffers. * @requires_gles30 Only @ref Magnum::BufferUsage::StaticDraw "BufferUsage::StaticDraw" * is available in OpenGL ES 2.0. */ StaticCopy = GL_STATIC_COPY, #endif /** * Updated frequently by the application and used frequently for drawing or * copying to other images. */ DynamicDraw = GL_DYNAMIC_DRAW, #ifndef MAGNUM_TARGET_GLES2 /** * Updated frequently as output from OpenGL command and queried many times * from the application. * @requires_gles30 Only @ref Magnum::BufferUsage::DynamicDraw "BufferUsage::DynamicDraw" * is available in OpenGL ES 2.0. */ DynamicRead = GL_DYNAMIC_READ, /** * Updated frequently as output from OpenGL command and used frequently for * drawing or copying to other images. * @requires_gles30 Only @ref Magnum::BufferUsage::DynamicDraw "BufferUsage::DynamicDraw" * is available in OpenGL ES 2.0. */ DynamicCopy = GL_DYNAMIC_COPY #endif }; namespace Implementation { struct BufferState; } /** @brief %Buffer Encapsulates one OpenGL buffer object and provides functions for convenient data updates. @section Buffer-data Data updating Default way to set or update buffer data with @ref setData() or @ref setSubData() is to use @ref Corrade::Containers::ArrayReference. See its documentation for more information about automatic conversions etc. @code Containers::ArrayReference data; buffer.setData(data, BufferUsage::StaticDraw); @endcode There is also overload for array-like containers from STL, such as `std::vector` or `std::array`: @code std::vector data; buffer.setData(data, BufferUsage::StaticDraw); @endcode @subsection Buffer-data-mapping Memory mapping %Buffer data can be also updated asynchronously. First you need to allocate the buffer to desired size by passing `nullptr` to @ref setData(), e.g.: @code buffer.setData({nullptr, 200*sizeof(Vector3)}, BufferUsage::StaticDraw); @endcode Then you can map the buffer to client memory and operate with the memory directly. After you are done with the operation, call @ref unmap() to unmap the buffer again. @code Vector3* data = static_cast(buffer.map(0, 200*sizeof(Vector3), Buffer::MapFlag::Write|Buffer::MapFlag::InvalidateBuffer)); for(std::size_t i = 0; i != 200; ++i) data[i] = ...; CORRADE_INTERNAL_ASSERT_OUTPUT(buffer.unmap()); @endcode If you are updating only a few discrete portions of the buffer, you can use @ref MapFlag::FlushExplicit and @ref flushMappedRange() to reduce number of memory operations performed by OpenGL on unmapping. Example: @code Vector3* data = static_cast(buffer.map(0, 200*sizeof(Vector3), Buffer::MapFlag::Write|Buffer::MapFlag::FlushExplicit)); for(std::size_t i: {7, 27, 56, 128}) { data[i] = ...; buffer.flushMappedRange(i*sizeof(Vector3), sizeof(Vector3)); } CORRADE_INTERNAL_ASSERT_OUTPUT(buffer.unmap()); @endcode @section Buffer-webgl-restrictions WebGL and NaCl restrictions Buffers in @ref MAGNUM_TARGET_WEBGL "WebGL" and @ref CORRADE_TARGET_NACL "NaCl" need to be bound only to one unique target, i.e., @ref Buffer bound to @ref Buffer::Target::Array cannot be later rebound to @ref Buffer::Target::ElementArray. However, %Magnum by default uses any sufficient target when binding the buffer internally (e.g. for setting data). To avoid GL errors, set target hint to desired target, either in constructor or using @ref Buffer::setTargetHint(): @code Buffer vertices{Buffer::Target::Array}; Buffer indices{Buffer::Target::ElementArray}; @endcode To ease up the development, @ref Mesh checks proper target hint when adding vertex and index buffers in both WebGL and NaCl. @section Buffer-performance-optimization Performance optimizations The engine tracks currently bound buffers to avoid unnecessary calls to @fn_gl{BindBuffer}. If the buffer is already bound to some target, functions @ref copy(), @ref setData(), @ref setSubData(), @ref map(), @ref flushMappedRange() and @ref unmap() use that target instead of binding the buffer to some specific target. You can also use @ref setTargetHint() to possibly reduce unnecessary rebinding. %Buffer limits and implementation-defined values (such as @ref maxUniformBindings()) are cached, so repeated queries don't result in repeated @fn_gl{Get} calls. If extension @extension{EXT,direct_state_access} is available, functions @ref copy(), @ref setData(), @ref setSubData(), @ref map(), @ref flushMappedRange() and @ref unmap() use DSA functions to avoid unnecessary calls to @fn_gl{BindBuffer}. See their respective documentation for more information. You can use functions @ref invalidateData() and @ref invalidateSubData() if you don't need buffer data anymore to avoid unnecessary memory operations performed by OpenGL in order to preserve the data. If running on OpenGL ES or extension @extension{ARB,invalidate_subdata} (part of OpenGL 4.3) is not available, these functions do nothing. */ class MAGNUM_EXPORT Buffer: public AbstractObject { friend struct Implementation::BufferState; public: /** * @brief %Buffer target * * @see @ref bind(Target), @ref unbind(Target) */ enum class Target: GLenum { /** Used for storing vertex attributes. */ Array = GL_ARRAY_BUFFER, #ifndef MAGNUM_TARGET_GLES /** * Used for storing atomic counters. * @requires_gl42 %Extension @extension{ARB,shader_atomic_counters} * @requires_gl Atomic counters are not available in OpenGL ES. */ AtomicCounter = GL_ATOMIC_COUNTER_BUFFER, #endif #ifndef MAGNUM_TARGET_GLES2 /** * Source for copies. See @ref copy(). * @requires_gl31 %Extension @extension{ARB,copy_buffer} * @requires_gles30 Buffer copying is not available in OpenGL ES * 2.0. */ CopyRead = GL_COPY_READ_BUFFER, /** * Target for copies. See @ref copy(). * @requires_gl31 %Extension @extension{ARB,copy_buffer} * @requires_gles30 Buffer copying is not available in OpenGL ES * 2.0. */ CopyWrite = GL_COPY_WRITE_BUFFER, #endif #ifndef MAGNUM_TARGET_GLES /** * Indirect compute dispatch commands. * @requires_gl43 %Extension @extension{ARB,compute_shader} * @requires_gl Compute shaders are not available in OpenGL ES. */ DispatchIndirect = GL_DISPATCH_INDIRECT_BUFFER, /** * Used for supplying arguments for indirect drawing. * @requires_gl40 %Extension @extension{ARB,draw_indirect} * @requires_gl Indirect drawing not available in OpenGL ES. */ DrawIndirect = GL_DRAW_INDIRECT_BUFFER, #endif /** Used for storing vertex indices. */ ElementArray = GL_ELEMENT_ARRAY_BUFFER #ifndef MAGNUM_TARGET_GLES2 , /** * Target for pixel pack operations. * @requires_gles30 Pixel buffer objects are not available in * OpenGL ES 2.0. */ PixelPack = GL_PIXEL_PACK_BUFFER, /** * Source for texture update operations. * @requires_gles30 Pixel buffer objects are not available in * OpenGL ES 2.0. */ PixelUnpack = GL_PIXEL_UNPACK_BUFFER, #endif #ifndef MAGNUM_TARGET_GLES /** * Used for shader storage. * @requires_gl43 %Extension @extension{ARB,shader_storage_buffer_object} * @requires_gl Shader storage is not available in OpenGL ES. */ ShaderStorage = GL_SHADER_STORAGE_BUFFER, /** * Source for texel fetches. See @ref BufferTexture. * @requires_gl31 %Extension @extension{ARB,texture_buffer_object} * @requires_gl Texture buffers are not available in OpenGL ES. */ Texture = GL_TEXTURE_BUFFER, #endif #ifndef MAGNUM_TARGET_GLES2 /** * Target for transform feedback. * @requires_gl30 %Extension @extension{EXT,transform_feedback} * @requires_gles30 Transform feedback is not available in OpenGL * ES 2.0. */ TransformFeedback = GL_TRANSFORM_FEEDBACK_BUFFER, /** * Used for storing uniforms. * @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 }; #ifdef MAGNUM_BUILD_DEPRECATED /** * @copybrief BufferUsage * @deprecated Use @ref Magnum::BufferUsage "BufferUsage" instead. */ typedef CORRADE_DEPRECATED("use BufferUsage instead") BufferUsage Usage; #endif /** * @brief Memory mapping access * * @see @ref map(MapAccess), @ref mapSub() * @requires_es_extension %Extension @es_extension{OES,mapbuffer} or * @es_extension{CHROMIUM,map_sub} * @deprecated_gl Prefer to use @ref Magnum::Buffer::map(GLintptr, GLsizeiptr, MapFlags) "map(GLintptr, GLsizeiptr, MapFlags)" * instead, as it has more complete set of features. */ enum class MapAccess: GLenum { #ifndef MAGNUM_TARGET_GLES /** * Map buffer for reading only. * @requires_gl Only @ref Magnum::Buffer::MapAccess "MapAccess::WriteOnly" * is available in OpenGL ES. */ ReadOnly = GL_READ_ONLY, #endif /** Map buffer for writing only. */ #ifdef MAGNUM_TARGET_GLES WriteOnly = GL_WRITE_ONLY_OES #else WriteOnly = GL_WRITE_ONLY, /** * Map buffer for both reading and writing. * @requires_gl Only @ref Magnum::Buffer::MapAccess "MapAccess::WriteOnly" * is available in OpenGL ES. */ ReadWrite = GL_READ_WRITE #endif }; /** * @brief Memory mapping flag * * @see @ref MapFlags, @ref map(GLintptr, GLsizeiptr, MapFlags) * @requires_gl30 %Extension @extension{ARB,map_buffer_range} * @requires_gles30 %Extension @es_extension{EXT,map_buffer_range} in * OpenGL ES 2.0 */ enum class MapFlag: GLbitfield { /** Map buffer for reading. */ #ifndef MAGNUM_TARGET_GLES2 Read = GL_MAP_READ_BIT, #else Read = GL_MAP_READ_BIT_EXT, #endif /** Map buffer for writing. */ #ifndef MAGNUM_TARGET_GLES2 Write = GL_MAP_WRITE_BIT, #else Write = GL_MAP_WRITE_BIT_EXT, #endif /** * Previous contents of the entire buffer may be discarded. May not * be used in combination with @ref MapFlag::Read. * @see @ref invalidateData() */ #ifndef MAGNUM_TARGET_GLES2 InvalidateBuffer = GL_MAP_INVALIDATE_BUFFER_BIT, #else InvalidateBuffer = GL_MAP_INVALIDATE_BUFFER_BIT_EXT, #endif /** * Previous contents of mapped range may be discarded. May not be * used in combination with @ref MapFlag::Read. * @see @ref invalidateSubData() */ #ifndef MAGNUM_TARGET_GLES2 InvalidateRange = GL_MAP_INVALIDATE_RANGE_BIT, #else InvalidateRange = GL_MAP_INVALIDATE_RANGE_BIT_EXT, #endif /** * Only one or more discrete subranges of the mapping will be * modified. See @ref flushMappedRange() for more information. May * only be used in conjuction with @ref MapFlag::Write. */ #ifndef MAGNUM_TARGET_GLES2 FlushExplicit = GL_MAP_FLUSH_EXPLICIT_BIT, #else FlushExplicit = GL_MAP_FLUSH_EXPLICIT_BIT_EXT, #endif /** * No pending operations on the buffer should be synchronized * before mapping. */ #ifndef MAGNUM_TARGET_GLES2 Unsynchronized = GL_MAP_UNSYNCHRONIZED_BIT #else Unsynchronized = GL_MAP_UNSYNCHRONIZED_BIT_EXT #endif }; /** * @brief Memory mapping flags * * @see @ref map(GLintptr, GLsizeiptr, MapFlags) * @requires_gl30 %Extension @extension{ARB,map_buffer_range} * @requires_gles30 %Extension @es_extension{EXT,map_buffer_range} in * OpenGL ES 2.0 */ typedef Containers::EnumSet MapFlags; #ifndef MAGNUM_TARGET_GLES /** * @brief Minimal supported mapping alignment * * The result is cached, repeated queries don't result in repeated * OpenGL calls. If extension @extension{ARB,map_buffer_alignment} is * not available, returns `0`. * @see @ref map(), @fn_gl{Get} with @def_gl{MIN_MAP_BUFFER_ALIGNMENT} * @requires_gl No minimal value is specified for OpenGL ES. */ static Int minMapAlignment(); /** * @brief Max supported atomic counter buffer binding count * * The result is cached, repeated queries don't result in repeated * OpenGL calls. If extension @extension{ARB,shader_atomic_counters} is * not available, returns `0`. * @see @fn_gl{Get} with @def_gl{MAX_ATOMIC_COUNTER_BUFFER_BINDINGS} * @requires_gl Atomic counters are not available in OpenGL ES. */ static Int maxAtomicCounterBindings(); /** * @brief Max supported shader storage buffer binding count * * The result is cached, repeated queries don't result in repeated * OpenGL calls. If extension @extension{ARB,shader_storage_buffer_object} * is not available, returns `0`. * @see @fn_gl{Get} with @def_gl{MAX_SHADER_STORAGE_BUFFER_BINDINGS} * @requires_gl Atomic counters are not available in OpenGL ES. */ static Int maxShaderStorageBindings(); /** * @brief Alignment of shader storage buffer binding offset * * The result is cached, repeated queries don't result in repeated * OpenGL calls. If extension @extension{ARB,shader_storage_buffer_object} * is not available, returns `0`. * @see @fn_gl{Get} with @def_gl{SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT} * @requires_gl Atomic counters are not available in OpenGL ES. */ static Int shaderStorageOffsetAlignment(); #endif #ifndef MAGNUM_TARGET_GLES2 /** * @brief Max supported uniform buffer binding count * * The result is cached, repeated queries don't result in repeated * OpenGL calls. If extension @extension{ARB,uniform_buffer_object} * is not available, returns `0`. * @see @fn_gl{Get} with @def_gl{MAX_UNIFORM_BUFFER_BINDINGS} * @requires_gles30 Uniform blocks are not available in OpenGL ES 2.0. */ static Int maxUniformBindings(); #endif /** * @brief Unbind any buffer from given target * @param target %Target * * @see @fn_gl{BindBuffer} */ static void unbind(Target target) { bind(target, 0); } #ifndef MAGNUM_TARGET_GLES2 /** * @brief Copy one buffer to another * @param read %Buffer from which to read * @param write %Buffer to which to copy * @param readOffset Offset in the read buffer * @param writeOffset Offset in the write buffer * @param size Data size * * If @extension{EXT,direct_state_access} is not available and the * buffers aren't already bound somewhere, they are bound to * @ref Target::CopyRead and @ref Target::CopyWrite before the copy is * performed. * @see @fn_gl{BindBuffer} and @fn_gl{CopyBufferSubData} or * @fn_gl_extension{NamedCopyBufferSubData,EXT,direct_state_access} * @requires_gl31 %Extension @extension{ARB,copy_buffer} * @requires_gles30 %Buffer copying is not available in OpenGL ES 2.0. */ static void copy(Buffer& read, Buffer& write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); #endif /** * @brief Constructor * @param targetHint Target hint, see @ref setTargetHint() for more * information * * Creates new OpenGL buffer. * @see @fn_gl{GenBuffers} */ explicit Buffer(Target targetHint = Target::Array); /** @brief Copying is not allowed */ Buffer(const Buffer&) = delete; /** @brief Move constructor */ Buffer(Buffer&& other) noexcept; /** * @brief Destructor * * Deletes associated OpenGL buffer. * @see @fn_gl{DeleteBuffers} */ ~Buffer(); /** @brief Copying is not allowed */ Buffer& operator=(const Buffer&) = delete; /** @brief Move assignment */ Buffer& operator=(Buffer&& other) noexcept; /** @brief OpenGL buffer ID */ GLuint id() const { return _id; } /** * @brief %Buffer label * * The result is *not* cached, repeated queries will result in repeated * OpenGL calls. If OpenGL 4.3 is not supported and neither * @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES * extension is available, this function returns empty string. * @see @fn_gl{GetObjectLabel} with @def_gl{BUFFER} or * @fn_gl_extension2{GetObjectLabel,EXT,debug_label} with * @def_gl{BUFFER_OBJECT_EXT} */ std::string label() const; /** * @brief Set buffer label * @return Reference to self (for method chaining) * * Default is empty string. If OpenGL 4.3 is not supported and neither * @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES * extension is available, this function does nothing. * @see @ref maxLabelLength(), @fn_gl{ObjectLabel} with @def_gl{BUFFER} * or @fn_gl_extension2{LabelObject,EXT,debug_label} with * @def_gl{BUFFER_OBJECT_EXT} */ Buffer& setLabel(const std::string& label); /** @brief Target hint */ Target targetHint() const { return _targetHint; } /** * @brief Set target hint * @return Reference to self (for method chaining) * * If @extension{EXT,direct_state_access} is not available, the buffer * must be internally bound to some target before any operation. You * can specify target which will always be used when binding the buffer * internally, possibly saving some calls to @fn_gl{BindBuffer}. * * Default target hint is @ref Target::Array. * @see @ref setData(), @ref setSubData() * @todo Target::ElementArray cannot be used when no VAO is bound - * http://www.opengl.org/wiki/Vertex_Specification#Index_buffers * ... damned GL state */ Buffer& setTargetHint(Target hint) { _targetHint = hint; return *this; } /** * @brief Bind buffer * @param target %Target * * @see @fn_gl{BindBuffer} * @todo Allow binding to Target::ElementArray only if VAO is bound * to avoid potential issues? * @todo Don't allow user to bind buffers? * @bug Binding to ElementArray if any VAO is active will corrupt the mesh */ void bind(Target target) { bind(target, _id); } /** * @brief %Buffer size * * If @extension{EXT,direct_state_access} is not available and the * buffer is not already bound somewhere, it is bound to hinted target * before the operation. * @see @fn_gl{BindBuffer} and @fn_gl{GetBufferParameter} or * @fn_gl_extension{GetNamedBufferParameter,EXT,direct_state_access} * with @def_gl{BUFFER_SIZE} */ Int size(); #ifndef MAGNUM_TARGET_GLES /** * @brief %Buffer data * * Returns data of whole buffer. If @extension{EXT,direct_state_access} * is not available and the buffer is not already bound somewhere, it * is bound to hinted target before the operation. * @see @ref size(), @ref subData(), @ref setData(), @fn_gl{BindBuffer} * and @fn_gl{GetBufferParameter} or * @fn_gl_extension{GetNamedBufferParameter,EXT,direct_state_access} * with @def_gl{BUFFER_SIZE}, @fn_gl{GetBufferSubData} or * @fn_gl_extension{GetNamedBufferSubData,EXT,direct_state_access} * @requires_gl %Buffer data queries are not available in OpenGL ES. * Use @ref Magnum::Buffer::map() "map()" instead. */ template Containers::Array data(); /** * @brief %Buffer subdata * @param offset Byte offset in the buffer * @param size Data size (count of @p T values) * * Returns data of given buffer portion. If @extension{EXT,direct_state_access} * is not available and the buffer is not already bound somewhere, it * is bound to hinted target before the operation. * @see @ref size(), @ref data(), @ref setSubData(), @fn_gl{BindBuffer} * and @fn_gl{GetBufferSubData} or * @fn_gl_extension{GetNamedBufferSubData,EXT,direct_state_access} * @requires_gl %Buffer data queries are not available in OpenGL ES. * Use @ref Magnum::Buffer::map() "map()" instead. */ template Containers::Array subData(GLintptr offset, GLsizeiptr size); #endif /** * @brief Set buffer data * @param data Data * @param usage %Buffer usage * @return Reference to self (for method chaining) * * If @extension{EXT,direct_state_access} is not available and the * buffer is not already bound somewhere, it is bound to hinted target * before the operation. * @see @ref setTargetHint(), @fn_gl{BindBuffer} and @fn_gl{BufferData} * or @fn_gl_extension{NamedBufferData,EXT,direct_state_access} */ Buffer& setData(Containers::ArrayReference data, BufferUsage usage); /** @overload */ template Buffer& setData(const std::vector& data, BufferUsage usage) { setData({data.data(), data.size()}, usage); return *this; } /** @overload */ template Buffer& setData(const std::array& data, BufferUsage usage) { setData({data.data(), data.size()}, usage); return *this; } /** * @brief Set buffer subdata * @param offset Offset in the buffer * @param data Data * @return Reference to self (for method chaining) * * If @extension{EXT,direct_state_access} is not available and the * buffer is not already bound somewhere, it is bound to hinted target * before the operation. * @see @ref setTargetHint(), @fn_gl{BindBuffer} and @fn_gl{BufferSubData} * or @fn_gl_extension{NamedBufferSubData,EXT,direct_state_access} */ Buffer& setSubData(GLintptr offset, Containers::ArrayReference data); /** @overload */ template Buffer& setSubData(GLintptr offset, const std::vector& data) { setSubData(offset, {data.data(), data.size()}); return *this; } /** @overload */ template Buffer& setSubData(GLintptr offset, const std::array& data) { setSubData(offset, {data.data(), data.size()}); return *this; } /** * @brief Invalidate buffer data * @return Reference to self (for method chaining) * * If running on OpenGL ES or extension @extension{ARB,invalidate_subdata} * (part of OpenGL 4.3) is not available, this function does nothing. * @see @ref MapFlag::InvalidateBuffer, @fn_gl{InvalidateBufferData} */ Buffer& invalidateData(); /** * @brief Invalidate buffer subdata * @param offset Offset into the buffer * @param length Length of the invalidated range * @return Reference to self (for method chaining) * * If running on OpenGL ES or extension @extension{ARB,invalidate_subdata} * (part of OpenGL 4.3) is not available, this function does nothing. * @see @ref MapFlag::InvalidateRange, @fn_gl{InvalidateBufferData} */ Buffer& invalidateSubData(GLintptr offset, GLsizeiptr length); /** * @brief Map buffer to client memory * @param access Access * @return Pointer to buffer data * * If @extension{EXT,direct_state_access} is not available and the * buffer is not already bound somewhere, it is bound to hinted target * before the operation. * @see @ref minMapAlignment(), @ref unmap(), @ref setTargetHint(), * @fn_gl{BindBuffer} and @fn_gl{MapBuffer} or * @fn_gl_extension{MapNamedBuffer,EXT,direct_state_access} * @requires_es_extension %Extension @es_extension{OES,mapbuffer} in * OpenGL ES 2.0, use @ref Magnum::Buffer::map(GLintptr, GLsizeiptr, MapFlags) "map(GLintptr, GLsizeiptr, MapFlags)" * in OpenGL ES 3.0 instead. * @deprecated_gl Prefer to use @ref Magnum::Buffer::map(GLintptr, GLsizeiptr, MapFlags) "map(GLintptr, GLsizeiptr, MapFlags)" * instead, as it has more complete set of features. */ void* map(MapAccess access); #if defined(MAGNUM_TARGET_GLES2) || defined(DOXYGEN_GENERATING_OUTPUT) /** * @brief Map portion of buffer to client memory * @param offset Offset into the buffer * @param length Length of the mapped memory * @param access Access * @return Pointer to buffer data * * If the buffer is not already bound somewhere, it is bound to hinted * target before the operation. * @see @ref unmapSub(), @ref setTargetHint(), * @fn_gl_extension{MapBufferSubData,CHROMIUM,map_sub} * @requires_gles20 Not available in ES 3.0 or desktop OpenGL. Use * @ref Magnum::Buffer::map(GLintptr, GLsizeiptr, MapFlags) "map(GLintptr, GLsizeiptr, MapFlags)" * instead. * @requires_es_extension %Extension @es_extension{CHROMIUM,map_sub} * @deprecated_gl Prefer to use @ref Magnum::Buffer::map(GLintptr, GLsizeiptr, MapFlags) "map(GLintptr, GLsizeiptr, MapFlags)" * instead, as it has more complete set of features. */ void* mapSub(GLintptr offset, GLsizeiptr length, MapAccess access); #endif /** * @brief Map buffer to client memory * @param offset Offset into the buffer * @param length Length of the mapped memory * @param flags Flags. At least @ref MapFlag::Read or * @ref MapFlag::Write must be specified. * @return Pointer to buffer data * * If @extension{EXT,direct_state_access} is not available and the * buffer is not already bound somewhere, it is bound to hinted target * before the operation. * @see @ref minMapAlignment(), @ref flushMappedRange(), @ref unmap(), * @ref map(MapAccess), @ref setTargetHint(), @fn_gl{BindBuffer} * and @fn_gl{MapBufferRange} or @fn_gl_extension{MapNamedBufferRange,EXT,direct_state_access} * @requires_gl30 %Extension @extension{ARB,map_buffer_range} * @requires_gles30 %Extension @es_extension{EXT,map_buffer_range} in * OpenGL ES 2.0 */ void* map(GLintptr offset, GLsizeiptr length, MapFlags flags); /** * @brief Flush mapped range * @param offset Offset relative to start of mapped range * @param length Length of the flushed memory * @return Reference to self (for method chaining) * * Flushes specified subsection of mapped range. Use only if you called * @ref map() with @ref MapFlag::FlushExplicit flag. See * @ref Buffer-data-mapping "class documentation" for usage example. * * If @extension{EXT,direct_state_access} is not available and the * buffer is not already bound somewhere, it is bound to hinted target * before the operation. * @see @ref setTargetHint(), @fn_gl{BindBuffer} and @fn_gl{FlushMappedBufferRange} * or @fn_gl_extension{FlushMappedNamedBufferRange,EXT,direct_state_access} * @requires_gl30 %Extension @extension{ARB,map_buffer_range} * @requires_gles30 %Extension @es_extension{EXT,map_buffer_range} in * OpenGL ES 2.0 */ Buffer& flushMappedRange(GLintptr offset, GLsizeiptr length); /** * @brief Unmap buffer * @return `False` if the data have become corrupt during the time * the buffer was mapped (e.g. after screen was resized), `true` * otherwise. * * Unmaps buffer previously mapped with @ref map(), invalidating the * pointer returned by these functions. If @extension{EXT,direct_state_access} * is not available and the buffer is not already bound somewhere, it * is bound to hinted target before the operation. * @see setTargetHint(), @fn_gl{BindBuffer} and @fn_gl{UnmapBuffer} or * @fn_gl_extension{UnmapNamedBuffer,EXT,direct_state_access} * @requires_gles30 %Extension @es_extension{OES,mapbuffer} in OpenGL * ES 2.0 */ bool unmap(); #if defined(MAGNUM_TARGET_GLES2) || defined(DOXYGEN_GENERATING_OUTPUT) /** * @brief Unmap portion of buffer * * Unmaps portion of buffer previously mapped with @ref mapSub(), * invalidating the pointer returned by the function. * @see @fn_gl_extension{UnmapBufferSubData,CHROMIUM,map_sub} * @requires_gles20 Not available in ES 3.0 or desktop OpenGL. Use * @ref Magnum::Buffer::map(GLintptr, GLsizeiptr, MapFlags) "map(GLintptr, GLsizeiptr, MapFlags)" * instead. * @requires_es_extension %Extension @es_extension{CHROMIUM,map_sub} */ void unmapSub(); #endif private: static void bind(Target hint, GLuint id); Target MAGNUM_LOCAL bindInternal(Target hint); #ifndef MAGNUM_TARGET_GLES2 static void MAGNUM_LOCAL copyImplementationDefault(Buffer& read, Buffer& write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); #ifndef MAGNUM_TARGET_GLES static void MAGNUM_LOCAL copyImplementationDSA(Buffer& read, Buffer& write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); #endif #endif #ifndef MAGNUM_TARGET_GLES void subDataInternal(GLintptr offset, GLsizeiptr size, GLvoid* data); #endif void MAGNUM_LOCAL getParameterImplementationDefault(GLenum value, GLint* data); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL getParameterImplementationDSA(GLenum value, GLint* data); #endif #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL getSubDataImplementationDefault(GLintptr offset, GLsizeiptr size, GLvoid* data); void MAGNUM_LOCAL getSubDataImplementationDSA(GLintptr offset, GLsizeiptr size, GLvoid* data); #endif void MAGNUM_LOCAL dataImplementationDefault(GLsizeiptr size, const GLvoid* data, BufferUsage usage); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL dataImplementationDSA(GLsizeiptr size, const GLvoid* data, BufferUsage usage); #endif void MAGNUM_LOCAL subDataImplementationDefault(GLintptr offset, GLsizeiptr size, const GLvoid* data); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL subDataImplementationDSA(GLintptr offset, GLsizeiptr size, const GLvoid* data); #endif void MAGNUM_LOCAL invalidateImplementationNoOp(); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL invalidateImplementationARB(); #endif void MAGNUM_LOCAL invalidateSubImplementationNoOp(GLintptr offset, GLsizeiptr length); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL invalidateSubImplementationARB(GLintptr offset, GLsizeiptr length); #endif void MAGNUM_LOCAL * mapImplementationDefault(MapAccess access); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL * mapImplementationDSA(MapAccess access); #endif void MAGNUM_LOCAL * mapRangeImplementationDefault(GLintptr offset, GLsizeiptr length, MapFlags access); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL * mapRangeImplementationDSA(GLintptr offset, GLsizeiptr length, MapFlags access); #endif void MAGNUM_LOCAL flushMappedRangeImplementationDefault(GLintptr offset, GLsizeiptr length); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL flushMappedRangeImplementationDSA(GLintptr offset, GLsizeiptr length); #endif bool MAGNUM_LOCAL unmapImplementationDefault(); #ifndef MAGNUM_TARGET_GLES bool MAGNUM_LOCAL unmapImplementationDSA(); #endif GLuint _id; Target _targetHint; #ifdef CORRADE_TARGET_NACL void* _mappedBuffer; #endif }; CORRADE_ENUMSET_OPERATORS(Buffer::MapFlags) /** @debugoperatorclassenum{Magnum::Buffer,Magnum::Buffer::Target} */ Debug MAGNUM_EXPORT operator<<(Debug debug, Buffer::Target value); inline Buffer::Buffer(Buffer&& other) noexcept: _id(other._id), _targetHint(other._targetHint) { other._id = 0; } inline Buffer& Buffer::operator=(Buffer&& other) noexcept { std::swap(_id, other._id); std::swap(_targetHint, other._targetHint); return *this; } #ifndef MAGNUM_TARGET_GLES template Containers::Array inline Buffer::data() { const Int bufferSize = size(); #ifndef CORRADE_GCC45_COMPATIBILITY CORRADE_ASSERT(bufferSize%sizeof(T) == 0, "Buffer::data(): the buffer size is" << bufferSize << "bytes, which can't be expressed as array of types with size" << sizeof(T), nullptr); #else CORRADE_ASSERT(bufferSize%sizeof(T) == 0, "Buffer::data(): the buffer size is" << bufferSize << "bytes, which can't be expressed as array of types with size" << sizeof(T), {}); #endif return subData(0, bufferSize/sizeof(T)); } template Containers::Array inline Buffer::subData(const GLintptr offset, const GLsizeiptr size) { Containers::Array data(size); if(size) subDataInternal(offset, size*sizeof(T), data); return std::move(data); } #endif } #endif