前言
glBufferData或glBufferSubData。 应用程序也可以将缓冲区对象的数据存储映射和取消映射到应用程序的地址空间。 有几个原因可以解释为什么应用程序更喜欢映射
而不是使用glBufferData或glBufferSubData加载它的数据:
••映射缓冲区可以减少应用程序的内存使用因为可能只需要存储数据的单个副本。
••在具有共享内存的架构上,映射缓冲区将返回一个直接指向地址空间的指针,在那里的缓冲区将被存储GPU。 通过映射缓冲区,应用程序可以避免复制步骤,从而实现更好的更新性能。
glMapBufferRange命令返回一个指向全部或部分的指针(范围)缓冲区对象的数据存储。 可以使用这个指针由应用程序读取或更新缓冲区对象的内容。
glUnmapBuffer命令用于表示已经更新完成并释放映射指针。
官网解释
翻译
Name
glMapBufferRange — map a section of a buffer object's data store
功能:将缓冲区对象数据存储映射到应用程序的地址空间, 他可以代替glBufferData或者 glBufferSubData函数,以减少程序内存占用
C Specification
| GLenum target, |
GLintptr offset, | |
GLsizeiptr length, | |
GLbitfield access ; |
| GLenum target ; |
Parameters for glMapBufferRange
glMapBufferRange
target
Specifies the target to which the buffer object is bound for
glMapBufferRange
, which must be one of the buffer binding targets in the following table:
翻译:为glMapBufferRange指定缓冲区对象绑定的目标,它必须是下表中的一个缓冲区绑定目标:
Buffer Binding Target | Purpose |
| Vertex attributes |
| Atomic counter storage |
| Buffer copy source |
| Buffer copy destination |
| Indirect compute dispatch commands |
| Indirect command arguments |
| Vertex array indices |
| Pixel read target |
| Texture data source |
| Read-write storage for shaders |
| Texture data buffer |
| Transform feedback buffer |
| Uniform block storage |
offset
Specifies the starting offset within the buffer of the range to be mapped.
指定要映射的范围的缓冲区内的起始偏移量。
length
Specifies the length of the range to be mapped.
指定要映射的范围的长度。
access
Specifies a combination of access flags indicating the desired access to the range.
指定访问标志的组合,指示对范围的期望访问。
Parameters for glUnmapBuffer
glUnmapBuffer
target
Specifies a binding to which the target buffer is bound.
指定目标缓冲区绑定到的绑定。
Description
glMapBufferRange
maps all or part of the data store of a buffer object into the client's address space.
target
specifies the target to which the buffer is bound and must be one of
GL_ARRAY_BUFFER
,
GL_ATOMIC_COUNTER_BUFFER
,
GL_COPY_READ_BUFFER
,
GL_COPY_WRITE_BUFFER
,
GL_DISPATCH_INDIRECT_BUFFER
,
GL_DRAW_INDIRECT_BUFFER
,
GL_ELEMENT_ARRAY_BUFFER
,
GL_PIXEL_PACK_BUFFER
,
GL_PIXEL_UNPACK_BUFFER
,
GL_SHADER_STORAGE_BUFFER
,
GL_TRANSFORM_FEEDBACK_BUFFER
or
GL_UNIFORM_BUFFER
.
offset
and
length
indicate the range of data in the buffer object that is to be mapped, in terms of basic machine units.
access
glMapBufferRange将buffer对象的全部或部分数据存储映射到客户端地址空间。 Target指定缓冲区绑定到的目标,必须是一个 配置GL_ARRAY_BUFFER、GL_ATOMIC_COUNTER_BUFFER、GL_COPY_READ_BUFFER、GL_COPY_WRITE_BUFFER、GL_DISPATCH_INDIRECT_BUFFER、GL_DRAW_INDIRECT_BUFFER、GL_ELEMENT_ARRAY_BUFFER、GL_PIXEL_PACK_BUFFER、GL_PIXEL_UNPACK_BUFFER、GL_SHADER_STORAGE_BUFFER、GL_TRANSFORM_FEEDBACK_BUFFER或GL_UNIFORM_BUFFER。 偏移量和长度表示要映射的缓冲区对象中的数据范围,以基本机器单元为单位。 Access是一个包含描述请求映射的标志的位域。 这些标志描述如下。
If no error occurs, a pointer to the beginning of the mapped range is returned once all pending operations on that buffer have completed, and may be used to modify and/or query the corresponding range of the buffer, according to the following flag bits set in
access
:
-
indicates that the returned pointer may be used to read buffer object data. No GL error is generated if the pointer is used to query a mapping which excludes this flag, but the result is undefined and system errors (possibly including program termination) may occur.GL_MAP_READ_BIT
-
indicates that the returned pointer may be used to modify buffer object data. No GL error is generated if the pointer is used to modify a mapping which excludes this flag, but the result is undefined and system errors (possibly including program termination) may occur.GL_MAP_WRITE_BIT
如果没有错误发生,一旦该缓冲区上所有未决的操作都完成,就返回一个指向映射范围开头的指针,并可用于根据access中设置的下列标志位修改和/或查询缓冲区的相应范围:
GL_MAP_READ_BIT表示返回的指针可用于读取缓冲区对象数据。 如果指针用于查询排除此标志的映射,则不会产生GL错误,但结果是未定义的,并且可能发生系统错误(可能包括程序终止)。
GL_MAP_WRITE_BIT表示返回的指针可用于修改缓冲区对象数据。 如果指针用于修改一个排除此标志的映射,则不会产生GL错误,但结果是未定义的,并且可能发生系统错误(可能包括程序终止)。
Furthermore, the following optional flag bits in
access
-
indicates that the previous contents of the specified range may be discarded. Data within this range are undefined with the exception of subsequently written data. No GL error is generated if subsequent GL operations access unwritten data, but the result is undefined and system errors (possibly including program termination) may occur. This flag may not be used in combination with GL_MAP_INVALIDATE_RANGE_BIT
.GL_MAP_READ_BIT
-
indicates that the previous contents of the entire buffer may be discarded. Data within the entire buffer are undefined with the exception of subsequently written data. No GL error is generated if subsequent GL operations access unwritten data, but the result is undefined and system errors (possibly including program termination) may occur. This flag may not be used in combination with GL_MAP_INVALIDATE_BUFFER_BIT
.GL_MAP_READ_BIT
-
indicates that one or more discrete subranges of the mapping may be modified. When this flag is set, modifications to each subrange must be explicitly flushed by calling glFlushMappedBufferRange. No GL error is set if a subrange of the mapping is modified and not flushed, but data within the corresponding subrange of the buffer are undefined. This flag may only be used in conjunction with GL_MAP_FLUSH_EXPLICIT_BIT
. When this option is selected, flushing is strictly limited to regions that are explicitly indicated with calls to glFlushMappedBufferRange prior to unmap; if this option is not selected glUnmapBuffer will automatically flush the entire mapped range when called.GL_MAP_WRITE_BIT
-
indicates that the GL should not attempt to synchronize pending operations on the buffer prior to returning from GL_MAP_UNSYNCHRONIZED_BIT
. No GL error is generated if pending operations which source or modify the buffer overlap the mapped region, but the result of such previous and any subsequent operations is undefined.glMapBufferRange
此外,在access中可以使用以下可选标志位来修改映射:
GL_MAP_INVALIDATE_RANGE_BIT表示前一个指定范围的内容可能被丢弃。 除随后写入的数据外,此范围内的数据是未定义的。 如果后续的GL操作访问未写入的数据,则不会产生GL错误,但结果是未定义的,并且可能发生系统错误(可能包括程序终止)。 这个标志不能与GL_MAP_READ_BIT一起使用。
GL_MAP_INVALIDATE_BUFFER_BIT表示整个缓冲区之前的内容可能被丢弃。 除了随后写入的数据外,整个缓冲区中的数据都是未定义的。 如果后续的GL操作访问未写入的数据,则不会产生GL错误,但结果是未定义的,并且可能发生系统错误(可能包括程序终止)。 这个标志不能与GL_MAP_READ_BIT一起使用。
GL_MAP_FLUSH_EXPLICIT_BIT表示可以修改映射的一个或多个离散子范围。 设置此标志后,必须通过调用glflushappedbufferrange显式刷新对每个子范围的修改。 如果映射的子范围被修改且未刷新,但缓冲区对应子范围内的数据未定义,则不设置GL错误。 此标志只能与GL_MAP_WRITE_BIT一起使用。 当选择此选项时,刷新严格限于在取消映射之前通过调用glflushappedbufferrange显式指示的区域; 如果未选择此选项,glUnmapBuffer将在调用时自动刷新整个映射范围。
GL_MAP_UNSYNCHRONIZED_BIT表示GL在从glMapBufferRange返回之前不应该尝试同步缓冲区上挂起的操作。 如果源或修改缓冲区的未决操作与映射区域重叠,但之前和后续操作的结果是未定义的,则不会产生GL错误。
If an error occurs,
glMapBufferRange
returns a
NULL
pointer.
A mapped data store must be unmapped with
glUnmapBuffer
before its buffer object is used. Otherwise an error will be generated by any GL command that attempts to dereference the buffer object's data store. When a data store is unmapped, the pointer to its data store becomes invalid.
glUnmapBuffer
returns
GL_TRUE
unless the data store contents have become corrupt during the time the data store was mapped. This can occur for system-specific reasons that affect the availability of graphics memory, such as screen mode changes. In such situations,
GL_FALSE
is returned and the data store contents are undefined. An application must detect this rare condition and reinitialize the data store.
A buffer object's mapped data store is automatically unmapped when the buffer object is deleted or its data store is recreated with
glBufferData
.
如果发生错误,glMapBufferRange返回一个NULL指针。
在使用buffer对象之前,映射的数据存储必须取消glUnmapBuffer的映射。 否则,任何试图解引用缓冲区对象的数据存储的GL命令都会生成错误。 未映射数据存储时,指向该数据存储的指针将失效。 glUnmapBuffer返回GL_TRUE,除非数据存储的内容在数据存储被映射时已经损坏。 这可能是由于影响图形内存可用性的系统特定原因,例如屏幕模式更改。 在这种情况下,返回GL_FALSE,数据存储内容是未定义的。 应用程序必须检测这种罕见的情况并重新初始化数据存储。
当删除缓冲区对象或使用glBufferData重新创建缓冲区对象的数据存储时,缓冲区对象的映射数据存储将自动取消映射。
Notes
Mappings to the data stores of buffer objects may have nonstandard performance characteristics. For example, such mappings may be marked as uncacheable regions of memory, and in such cases reading from them may be very slow. To ensure optimal performance, the client should use the mapping in a fashion consistent with the values of
GL_BUFFER_USAGE
and
access
. Using a mapping in a fashion inconsistent with these values is liable to be multiple orders of magnitude slower than using normal memory.
The
GL_ATOMIC_COUNTER_BUFFER
,
GL_DISPATCH_INDIRECT_BUFFER
,
GL_DRAW_INDIRECT_BUFFER
and
GL_SHADER_STORAGE_BUFFER
targets are available only if the GL ES version is 3.1 or greater.
The
GL_TEXTURE_BUFFER
target is available only if the GL ES version is 3.2 or greater.
注意:
到缓冲区对象的数据存储的映射可能具有非标准的性能特征。 例如,这样的映射可能被标记为内存的非缓存区域,在这种情况下,从它们读取可能会非常慢。 为了确保最佳性能,客户端应该以与GL_BUFFER_USAGE和access值一致的方式使用映射。 以与这些值不一致的方式使用映射容易比使用普通内存慢多个数量级。
GL_ATOMIC_COUNTER_BUFFER、GL_DISPATCH_INDIRECT_BUFFER、GL_DRAW_INDIRECT_BUFFER和GL_SHADER_STORAGE_BUFFER仅在GL ES版本为3.1或更高版本时可用。
GL_TEXTURE_BUFFER目标仅在GL ES版本为3.2或更高时可用。
Errors
GL_INVALID_VALUE
is generated if either of
offset
or
length
is negative, or if
offset
+
length
is greater than the value of
GL_BUFFER_SIZE
.
GL_INVALID_VALUE
is generated if
access
GL_INVALID_OPERATION
is generated for any of the following conditions:
- The buffer is already in a mapped state.
- Neither
or GL_MAP_READ_BIT
is set.GL_MAP_WRITE_BIT
-
is set and any of GL_MAP_READ_BIT
, GL_MAP_INVALIDATE_RANGE_BIT
, or GL_MAP_INVALIDATE_BUFFER_BIT
is set.GL_MAP_UNSYNCHRONIZED_BIT
-
is set and GL_MAP_FLUSH_EXPLICIT_BIT
is not set.GL_MAP_WRITE_BIT
GL_OUT_OF_MEMORY
is generated if
glMapBufferRange
fails because memory for the mapping could not be obtained.
错误
如果offset或length为负,或者offset + length大于GL_BUFFER_SIZE的值,则生成GL_INVALID_VALUE。
如果访问设置了除上面定义的位之外的任何位,则生成GL_INVALID_VALUE。
GL_INVALID_OPERATION是针对以下任何一种情况生成的:
缓冲区已经处于映射状态。
GL_MAP_READ_BIT和GL_MAP_WRITE_BIT都没有设置。
设置GL_MAP_READ_BIT,并设置GL_MAP_INVALIDATE_RANGE_BIT、GL_MAP_INVALIDATE_BUFFER_BIT或GL_MAP_UNSYNCHRONIZED_BIT。
设置GL_MAP_FLUSH_EXPLICIT_BIT,未设置GL_MAP_WRITE_BIT。
如果glMapBufferRange失败,因为无法获取映射的内存,则生成GL_OUT_OF_MEMORY。
API Version Support
OpenGL ES API Version | ||||
Function Name | 2.0 | 3.0 | 3.1 | 3.2 |
| - | ✔ | ✔ | ✔ |
| - | ✔ | ✔ | ✔ |
See Also
glBindBuffer glFlushMappedBufferRange, glUnmapBuffer,
Copyright
Copyright © 2010-2015 Khronos Group. This material may be distributed subject to the terms and conditions set forth in the Open Publication License, v 1.0, 8 June 1999. http://opencontent.org/openpub/.
代码
// The MIT License (MIT)
//
// Copyright (c) 2013 Dan Ginsburg, Budirijanto Purnomo
//
// 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.
//
// Book: OpenGL(R) ES 3.0 Programming Guide, 2nd Edition
// Authors: Dan Ginsburg, Budirijanto Purnomo, Dave Shreiner, Aaftab Munshi
// ISBN-10: 0-321-93388-5
// ISBN-13: 978-0-321-93388-1
// Publisher: Addison-Wesley Professional
// URLs: http://www.opengles-book.com
// http://my.safaribooksonline.com/book/animation-and-3d/9780133440133
//
// MapBuffers.c
//
// This example demonstrates mapping buffer objects
//
#include "esUtil.h"
#include <string.h>
typedef struct
{
// Handle to a program object
GLuint programObject;
// VertexBufferObject Ids
GLuint vboIds[2];
} UserData;
#define VERTEX_POS_SIZE 3 // x, y and z
#define VERTEX_COLOR_SIZE 4 // r, g, b, and a
#define VERTEX_POS_INDX 0
#define VERTEX_COLOR_INDX 1
int Init ( ESContext *esContext )
{
UserData *userData = esContext->userData;
const char vShaderStr[] =
"#version 300 es \n"
"layout(location = 0) in vec4 a_position; \n"
"layout(location = 1) in vec4 a_color; \n"
"out vec4 v_color; \n"
"void main() \n"
"{ \n"
" v_color = a_color; \n"
" gl_Position = a_position; \n"
"}";
const char fShaderStr[] =
"#version 300 es \n"
"precision mediump float; \n"
"in vec4 v_color; \n"
"out vec4 o_fragColor; \n"
"void main() \n"
"{ \n"
" o_fragColor = v_color; \n"
"}" ;
GLuint programObject;
// Create the program object
programObject = esLoadProgram ( vShaderStr, fShaderStr );
if ( programObject == 0 )
{
return GL_FALSE;
}
// Store the program object
userData->programObject = programObject;
userData->vboIds[0] = 0;
userData->vboIds[1] = 0;
glClearColor ( 1.0f, 1.0f, 1.0f, 0.0f );
return GL_TRUE;
}
void DrawPrimitiveWithVBOsMapBuffers ( ESContext *esContext,
GLint numVertices, GLfloat *vtxBuf,
GLint vtxStride, GLint numIndices,
GLushort *indices )
{
UserData *userData = esContext->userData;
GLuint offset = 0;
// vboIds[0] - used to store vertex attribute data
// vboIds[l] - used to store element indices
if ( userData->vboIds[0] == 0 && userData->vboIds[1] == 0 )
{
GLfloat *vtxMappedBuf;
GLushort *idxMappedBuf;
// Only allocate on the first draw
glGenBuffers ( 2, userData->vboIds );
glBindBuffer ( GL_ARRAY_BUFFER, userData->vboIds[0] );
glBufferData ( GL_ARRAY_BUFFER, vtxStride * numVertices,
NULL, GL_STATIC_DRAW );
vtxMappedBuf = ( GLfloat * )
glMapBufferRange ( GL_ARRAY_BUFFER, 0, vtxStride * numVertices,
GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT );
if ( vtxMappedBuf == NULL )
{
esLogMessage ( "Error mapping vertex buffer object." );
return;
}
// Copy the data into the mapped buffer
memcpy ( vtxMappedBuf, vtxBuf, vtxStride * numVertices );
// Unmap the buffer
if ( glUnmapBuffer ( GL_ARRAY_BUFFER ) == GL_FALSE )
{
esLogMessage ( "Error unmapping array buffer object." );
return;
}
// Map the index buffer
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, userData->vboIds[1] );
glBufferData ( GL_ELEMENT_ARRAY_BUFFER,
sizeof ( GLushort ) * numIndices,
NULL, GL_STATIC_DRAW );
idxMappedBuf = ( GLushort * )
glMapBufferRange ( GL_ELEMENT_ARRAY_BUFFER, 0, sizeof ( GLushort ) * numIndices,
GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT );
if ( idxMappedBuf == NULL )
{
esLogMessage ( "Error mapping element array buffer object." );
return;
}
// Copy the data into the mapped buffer
memcpy ( idxMappedBuf, indices, sizeof ( GLushort ) * numIndices );
// Unmap the buffer
if ( glUnmapBuffer ( GL_ELEMENT_ARRAY_BUFFER ) == GL_FALSE )
{
esLogMessage ( "Error unmapping element array buffer object." );
return;
}
}
glBindBuffer ( GL_ARRAY_BUFFER, userData->vboIds[0] );
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, userData->vboIds[1] );
glEnableVertexAttribArray ( VERTEX_POS_INDX );
glEnableVertexAttribArray ( VERTEX_COLOR_INDX );
glVertexAttribPointer ( VERTEX_POS_INDX, VERTEX_POS_SIZE,
GL_FLOAT, GL_FALSE, vtxStride,
( const void * ) offset );
offset += VERTEX_POS_SIZE * sizeof ( GLfloat );
glVertexAttribPointer ( VERTEX_COLOR_INDX,
VERTEX_COLOR_SIZE,
GL_FLOAT, GL_FALSE, vtxStride,
( const void * ) offset );
glDrawElements ( GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT,
0 );
glDisableVertexAttribArray ( VERTEX_POS_INDX );
glDisableVertexAttribArray ( VERTEX_COLOR_INDX );
glBindBuffer ( GL_ARRAY_BUFFER, 0 );
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, 0 );
}
void Draw ( ESContext *esContext )
{
UserData *userData = esContext->userData;
// 3 vertices, with (x,y,z) ,(r, g, b, a) per-vertex
GLfloat vertices[3 * ( VERTEX_POS_SIZE + VERTEX_COLOR_SIZE )] =
{
0.0f, 0.5f, 0.0f, // v0
1.0f, 0.0f, 0.0f, 1.0f, // c0
-0.5f, -0.5f, 0.0f, // v1
0.0f, 1.0f, 0.0f, 1.0f, // c1
0.5f, -0.5f, 0.0f, // v2
0.0f, 0.0f, 1.0f, 1.0f, // c2
};
// Index buffer data
GLushort indices[3] = { 0, 1, 2 };
glViewport ( 0, 0, esContext->width, esContext->height );
glClear ( GL_COLOR_BUFFER_BIT );
glUseProgram ( userData->programObject );
DrawPrimitiveWithVBOsMapBuffers ( esContext, 3, vertices,
sizeof ( GLfloat ) * ( VERTEX_POS_SIZE + VERTEX_COLOR_SIZE ),
3, indices );
}
void Shutdown ( ESContext *esContext )
{
UserData *userData = esContext->userData;
glDeleteProgram ( userData->programObject );
glDeleteBuffers ( 2, userData->vboIds );
}
int esMain ( ESContext *esContext )
{
esContext->userData = malloc ( sizeof ( UserData ) );
esCreateWindow ( esContext, "MapBuffers", 320, 240, ES_WINDOW_RGB );
if ( !Init ( esContext ) )
{
return GL_FALSE;
}
esRegisterShutdownFunc ( esContext, Shutdown );
esRegisterDrawFunc ( esContext, Draw );
return GL_TRUE;
}