Name
ARB_uniform_buffer_object
Name Strings
GL_ARB_uniform_buffer_object
Contact
Benj Lipchak, APPLE (lipchak 'at' apple.com)
John Rosasco, APPLE (jdr 'at' apple.com)
Jeremy Sandmel, APPLE (jsandmel 'at' apple.com)
Pat Brown, NVIDIA (pbrown 'at' nvidia.com)
Contributors
Rob Barris
Keith Bauer
Bob Beretta
Pat Brown
Nick Burns
Matt Collins
Michael Gold
John Kessenich
Jon Leech
Barthold Lichtenbelt
Benj Lipchak
Bruce Merry
John Rosasco
Jeremy Sandmel
Geoff Stahl
Notice
Copyright (c) 2009-2013 The Khronos Group Inc. Copyright terms at
http://www.khronos.org/registry/speccopyright.html
Status
Complete. Approved by the ARB on February 17, 2009.
Version
Last Modified Date: 2015/06/23
Author revision: 68
Number
ARB Extension #57
Dependencies
The OpenGL Shading Language (GLSL) is required. OpenGL 2.0 or the
ARB_shader_objects extension is required.
OpenGL 1.5 or ARB_vertex_buffer_object is required.
This extension is written against the OpenGL 2.1 specification and
version 1.20-8 of the OpenGL Shading Language specification.
This extension interacts with OpenGL 3.0, ARB_geometry_shader4,
ARB_texture_rectangle, EXT_gpu_shader4, EXT_texture_array,
EXT_texture_integer, and EXT_texture_buffer_object.
Overview
This extension introduces the concept of a group of GLSL uniforms
known as a "uniform block", and the API mechanisms to store "uniform
blocks" in GL buffer objects.
The extension also defines both a standard cross-platform layout in
memory for uniform block data, as well as mechanisms to allow the GL
to optimize the data layout in an implementation-defined manner.
Prior to this extension, the existing interface for modification of
uniform values allowed modification of large numbers of values using
glUniform* calls, but only for a single uniform name (or a uniform
array) at a time. However, updating uniforms in this manner may not
map well to heterogenous uniform data structures defined for a GL
application and in these cases, the application is forced to either:
A) restructure their uniform data definitions into arrays
or
B) make an excessive number of calls through the GL interface
to one of the Uniform* variants.
These solutions have their disadvantages. Solution A imposes
considerable development overhead on the application developer.
Solution B may impose considerable run-time overhead on the
application if the number of uniforms modified in a given frame of
rendering is sufficiently large.
This extension provides a better alternative to either (A) or (B) by
allowing buffer object backing for the storage associated with all
uniforms of a given GLSL program.
Storing uniform blocks in buffer objects enables several key use
cases:
- sharing of uniform data storage between program objects and
between program stages
- rapid swapping of sets of previously defined uniforms by storing
sets of uniform data on the GL server
- rapid updates of uniform data from both the client and the server
The data storage for a uniform block can be declared to use one of
three layouts in memory: packed, shared, or std140.
- "packed" uniform blocks have an implementation-dependent data
layout for efficiency, and unused uniforms may be eliminated by
the compiler to save space.
- "shared" uniform blocks, the default layout, have an implementation-
dependent data layout for efficiency, but the layout will be uniquely
determined by the structure of the block, allowing data storage to be
shared across programs.
- "std140" uniform blocks have a standard cross-platform cross-vendor
layout (see below). Unused uniforms will not be eliminated.
Any uniforms not declared in a named uniform block are said to
be part of the "default uniform block".
While uniforms in the default uniform block are updated with
glUniform* entry points and can have static initializers, uniforms
in named uniform blocks are not. Instead, uniform block data is updated
using the routines that update buffer objects and can not use static
initializers.
Rules and Concepts Guiding this Specification:
For reference, a uniform has a "uniform index" (subsequently
referred to as "u_index) and also a "uniform location" to
efficiently identify it in the uniform data store of the
implementation. We subsequently refer to this uniform data store of
the implementation as the "uniform database".
A "uniform block" only has a "uniform block index" used for queries
and connecting the "uniform block" to a buffer object. A "uniform
block" has no "location" because "uniform blocks" are not updated
directly. The buffer object APIs are used instead.
Properties of Uniforms and uniform blocks:
a) A uniform is "active" if it exists in the database and has a valid
u_index.
b) A "uniform block" is "active" if it exists in the database and
has a valid ub_index.
c) Uniforms and "uniform blocks" can be inactive because they don't
exist in the source, or because they have been removed by dead
code elimination.
d) An inactive uniform has u_index == INVALID_INDEX.
e) An inactive uniform block has ub_index == INVALID_INDEX.
f) A u_index or ub_index of INVALID_INDEX generates the
INVALID_VALUE error if given as a function argument.
g) The default uniform block, which is not assigned any ub_index, uses a
private, internal data storage, and does not have any buffer object
associated with it.
h) An active uniform that is a member of the default uniform block has
location >= 0 and it has offset == stride == -1.
i) An active uniform that is a member of a named uniform block has
location == -1.
j) A uniform location of -1 is silently ignored if given as a function
argument.
k) Uniform block declarations may not be nested
IP Status
No known IP claims.
New Procedures and Functions
void GetUniformIndices(uint program,
sizei uniformCount,
const char* const * uniformNames,
uint* uniformIndices);
void GetActiveUniformsiv(uint program,
sizei uniformCount,
const uint* uniformIndices,
enum pname,
int* params);
void GetActiveUniformName(uint program,
uint uniformIndex,
sizei bufSize,
sizei* length,
char* uniformName);
uint GetUniformBlockIndex(uint program,
const char* uniformBlockName);
void GetActiveUniformBlockiv(uint program,
uint uniformBlockIndex,
enum pname,
int* params);
void GetActiveUniformBlockName(uint program,
uint uniformBlockIndex,
sizei bufSize,
sizei* length,
char* uniformBlockName);
void BindBufferRange(enum target,
uint index,
uint buffer,
intptr offset,
sizeiptr size);
void BindBufferBase(enum target,
uint index,
uint buffer);
void GetIntegeri_v(enum target, uint index, int* data);
void UniformBlockBinding(uint program,
uint uniformBlockIndex,
uint uniformBlockBinding);
New Types
None.
New Tokens
Accepted by the parameters of BindBuffer, BufferData,
BufferSubData, MapBuffer, UnmapBuffer, GetBufferSubData, and
GetBufferPointerv:
UNIFORM_BUFFER 0x8A11
Accepted by the parameter of GetIntegeri_v, GetBooleanv,
GetIntegerv, GetFloatv, and GetDoublev:
UNIFORM_BUFFER_BINDING 0x8A28
Accepted by the parameter of GetIntegeri_v:
UNIFORM_BUFFER_START 0x8A29
UNIFORM_BUFFER_SIZE 0x8A2A
Accepted by the parameter of GetBooleanv, GetIntegerv,
GetFloatv, and GetDoublev:
MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B
MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C
MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D
MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E
MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F
MAX_UNIFORM_BLOCK_SIZE 0x8A30
MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31
MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32
MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33
UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34
Accepted by the parameter of GetProgramiv:
ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35
ACTIVE_UNIFORM_BLOCKS 0x8A36
Accepted by the parameter of GetActiveUniformsiv:
UNIFORM_TYPE 0x8A37
UNIFORM_SIZE 0x8A38
UNIFORM_NAME_LENGTH 0x8A39
UNIFORM_BLOCK_INDEX 0x8A3A
UNIFORM_OFFSET 0x8A3B
UNIFORM_ARRAY_STRIDE 0x8A3C
UNIFORM_MATRIX_STRIDE 0x8A3D
UNIFORM_IS_ROW_MAJOR 0x8A3E
Accepted by the parameter of GetActiveUniformBlockiv:
UNIFORM_BLOCK_BINDING 0x8A3F
UNIFORM_BLOCK_DATA_SIZE 0x8A40
UNIFORM_BLOCK_NAME_LENGTH 0x8A41
UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42
UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43
UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44
UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45
UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46
Returned by GetActiveUniformsiv and GetUniformBlockIndex
INVALID_INDEX 0xFFFFFFFFu
2.1 Specification Updates
Additions to Chapter 2 - OpenGL Operation
Section 2.9 - Buffer Objects
Add UNIFORM_BUFFER to list of buffer object targets on:
Pg 35, 2nd pgph
Pg 37, top of page
Pg 38, top of page
Section 2.15 - Vertex Shaders
Pg 79, bump Uniform Variables up to a numbered section since there
will now be hierarchy under it; replace all but first paragraph of
Uniform Variables section on this page, through to the start of the
first full paragraph on p. 80 (beginning "A valid ...") under
the description of GetUniformLocation:
Sets of uniforms can be grouped into "uniform blocks". The values of each
uniform in such a set are extracted from the data store of a buffer object
corresponding to the uniform block.
OpenGL Shading Language syntax serves to delimit named blocks of
uniforms that can be backed by a buffer object. These are referred to as
"named uniform blocks," and are assigned a uniform block index. Uniforms
that are declared outside of a named uniform block are said to be part of
the "default uniform block." Default uniform blocks have no name or uniform
block index. Like uniforms, uniform blocks can be active or inactive. Active
uniform blocks are those that contain active uniforms after a program has
been compiled and linked.
The amount of storage available for uniform variables in the default uniform
block accessed by a vertex shader is specified by the value of the
implementation-dependent constant MAX_VERTEX_UNIFORM_COMPONENTS. The total
amount of combined storage available for uniform variables in all uniform
blocks accessed by a vertex shader (including the default uniform block)
is specified by the value of the implementation-dependent
constant MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS. These values
represent the numbers of individual floating-point, integer, or boolean
values that can be held in uniform variable storage for a vertex shader.
A link error is generated if an attempt is made to utilize more than
the space available for vertex shader uniform variables.
When a program is successfully linked, all active uniforms belonging to
the program object's default uniform block are initialized to zero (FALSE
for booleans). A successful link will also generate a location for each
active uniform in the default uniform block. The values of active uniforms
in the default uniform block can be changed using this location and the
appropriate Uniform* command (see below). These locations are invalidated
and new ones assigned after each successful re-link.
Similarly, when a program is successfully linked, all active uniforms
belonging to the program's named uniform blocks are assigned offsets
(and strides for array and matrix type uniforms) within the uniform block
according to layout rules described below. Uniform buffer objects provide
the storage for named uniform blocks, so the values of active uniforms in
named uniform blocks may be changed by modifying the contents of the buffer
object using commands such as BufferData, BufferSubData, MapBuffer, and
UnmapBuffer. Uniforms in a named uniform block are not assigned a location
and may not be modified using the Uniform* commands. The offsets and strides
of all active uniforms belonging to named uniform blocks of a program object
are invalidated and new ones assigned after each successful re-link.
To find the location within a program object of an active uniform
variable associated with the default uniform block, use the command
int GetUniformLocation(uint program, const char *name);
This command will return the location of uniform variable if it
is associated with the default uniform block. must be a
null-terminated string, without white space. The value -1 will be returned
if does not correspond to an active uniform variable name in
, if is associated with a named uniform block, or if
starts with the reserved prefix "gl_".
If has not been successfully linked, the error INVALID_OPERATION
is generated. After a program is linked, the location of a uniform
variable will not change, unless the program is re-linked.
A valid ...
Pg 80, insert before the description of GetActiveUniform:
Named uniform blocks, like uniforms, are identified by name strings.
Uniform block indices corresponding to uniform block names can be queried
by calling
uint GetUniformBlockIndex(uint program,
const char* uniformBlockName);
is the name of a program object for which the command
LinkProgram has been issued in the past. It is not
necessary for to have been linked successfully. The link
could have failed because the number of active uniforms exceeded the
limit.
must contain a null-terminated string specifying
the name of a uniform block.
GetUniformBlockIndex returns the uniform block index for the
uniform block named of . If
does not identify an active uniform block of
, or an error occurred, then INVALID_INDEX is returned.
The indices of the active uniform blocks of a program are assigned in
consecutive order, beginning with zero.
An active uniform block's name string can be queried from its
uniform block index by calling
void GetActiveUniformBlockName(uint program,
uint uniformBlockIndex,
sizei bufSize,
sizei* length,
char* uniformBlockName);
is the name of a program object for which the command
LinkProgram has been issued in the past. It is not
necessary for to have been linked successfully. The link
could have failed because the number of active uniforms exceeded the
limit.
must be an active uniform block index of
, in the range zero to the value of
ACTIVE_UNIFORM_BLOCKS - 1. The value of
ACTIVE_UNIFORM_BLOCKS can be queried with GetProgramiv (see
section 6.1.14). If is greater than or equal to
the value of ACTIVE_UNIFORM_BLOCKS, the error INVALID_VALUE is
generated.
The string name of the uniform block identified by
is returned into . The name is
null-terminated. The actual number of characters written into
, excluding the null terminator, is returned in .
If is NULL, no length is returned.
contains the maximum number of characters (including the
null terminator) that will be written back to .
If an error occurs, nothing will be written to or
.
Information about an active uniform block can be queried by calling
void GetActiveUniformBlockiv(uint program,
uint uniformBlockIndex,
enum pname,
int* params);
is the name of a program object for which the command
LinkProgram has been issued in the past. It is not
necessary for to have been linked successfully. The link
could have failed because the number of active uniforms exceeded the
limit.
is an active uniform block index of .
If is greater than or equal to the value of
ACTIVE_UNIFORM_BLOCKS, or is not the index of an active uniform
block in , the error INVALID_VALUE is generated.
If no error occurs, the uniform block parameter(s) specified by
are returned in . Otherwise, nothing will be written
to .
If is UNIFORM_BLOCK_BINDING, then
the index of the uniform buffer binding
point last selected by the uniform block specified by
for is returned. If no uniform block has been previously
specified, zero is returned.
If is UNIFORM_BLOCK_DATA_SIZE, the value returned is the
implementation-dependent minimum total buffer object size, in
basic machine units, required to hold all active uniforms in the
uniform block identified by .
It is neither guaranteed nor expected that a given implementation will
arrange uniform values as tightly packed in a buffer object. The exception
to this is the "std140" uniform block layout, which guarantees specific
packing behavior and does not require the application to query for offsets
and strides. In this case, the minimum size may still be queried, even
though it is determined in advance based only on the uniform block
declaration (see "Standard Uniform Block Layout" in section 2.15.3.1.2).
The total amount of buffer object storage available for any given uniform
block is subject to an implementation-dependent limit; the maximum amount
of available space, in basic machine units, can be queried by calling
GetIntegerv with the constant MAX_UNIFORM_BLOCK_SIZE. If the amount
of storage required for a uniform block exceeds this limit, a program may
fail to link.
If is UNIFORM_BLOCK_NAME_LENGTH, then the total length
(including the null terminator) of the name of the uniform block
identified by is returned.
If is UNIFORM_BLOCK_ACTIVE_UNIFORMS, then the number of
active uniforms in the uniform block identified by
is returned.
If is UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, then a list
of the active uniform indices for the uniform block identified by
is returned.
The number of elements that will be written to is the value
of UNIFORM_BLOCK_ACTIVE_UNIFORMS for .
If is UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER,
UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER, or
UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER, then
a boolean value indicating whether the uniform block identified by
is referenced by the vertex, geometry, or fragment
programming stage of , respectively, is returned.
Each active uniform, whether in a named uniform block or in the default
block, is assigned an index when a program is linked. These indices are
assigned in consecutive order, beginning with zero. The indices assigned
to a set of uniforms in a program may be queried by calling
void GetUniformIndices(uint program,
sizei uniformCount,
const char* const * uniformNames,
uint* uniformIndices);
is the name of a program object for which the command
LinkProgram has been issued in the past. It is not
necessary for to have been linked successfully. The link
could have failed because the number of active uniforms exceeded the
limit.
indicates both the number of elements in the array of
names and the number of indices that may be written to
.
contains a list of name strings
identifying the uniform names to be queried for indices. For each name
string in , the index assigned to the active uniform of
that name will be written to the corresponding element of
. If a string in is not the name of an
active uniform, the value INVALID_INDEX will be written to the
corresponding element of .
If an error occurs, nothing is written to .
The name of an active uniform may be queried from the corresponding uniform
index by calling
void GetActiveUniformName(uint program,
uint uniformIndex,
sizei bufSize,
sizei* length,
char* uniformName);
is the name of a program object for which the command
LinkProgram has been issued in the past. It is not
necessary for to have been linked successfully. The link
could have failed because the number of active uniforms exceeded the
limit.
must be an active uniform index of the program
, in the range zero to the value of ACTIVE_UNIFORMS - 1.
The value of ACTIVE_UNIFORMS can be queried with GetProgramiv. If
is greater than or equal to the value of
ACTIVE_UNIFORMS, the error INVALID_VALUE is generated.
The name of the uniform identified by is
returned as a null-terminated string in .
The actual number of characters written into , excluding the
null terminator, is returned in . If is NULL, no length is
returned. The maximum number of characters that may be written into
, including the null terminator, is specified by .
The returned uniform name can be the name of built-in uniform state as
well. The complete list of built-in uniform state is described in section
7.5 of the OpenGL Shading Language specification. The length of the
longest uniform name in is given by the value of
ACTIVE_UNIFORM_MAX_LENGTH, which can be queried with GetProgramiv.
If GetActiveUniformName is not successful, nothing is written to
or .
Each uniform variable, declared in a shader, is broken down into one or
more strings using the "." (dot) and "[]" operators, if necessary, to the
point that it is legal to pass each string back into GetUniformLocation,
for default uniform block uniform names, or GetUniformIndices, for
named uniform block uniform names.
Pg 80, replace description of GetActiveUniform
Information about active uniforms can be obtained by calling either
void GetActiveUniform(uint program,
uint index,
sizei bufSize,
sizei* length,
int* size,
enum* type,
char* name);
or
void GetActiveUniformsiv(uint program,
sizei uniformCount,
const uint* uniformIndices,
enum pname,
int* params);
is the name of a program object for which the command
LinkProgram has been issued in the past. It is not
necessary for to have been linked successfully. The link
could have failed because the number of active uniforms exceeded the
limit.
These commands provide information about the uniform or uniforms selected
by or , respectively. In GetActiveUniform, an
of 0 selects the first active uniform, and an of the value
of ACTIVE_UNIFORMS - 1 selects the last active uniform. In
GetActiveUniformsiv, is an array of such active uniform
indices. If any index is greater than or equal to the value of
ACTIVE_UNIFORMS, the error INVALID_VALUE is generated.
For the selected uniform, GetActiveUniform returns the uniform name as a
null-terminated string in . The actual number of
characters written into , excluding the null terminator, is returned
in . If is NULL, no length is returned. The maximum
number of characters that may be written into , including the null
terminator, is specified by . The returned uniform name can be the
name of built-in uniform state as well. The complete list of built-in
uniform state is described in section 7.5 of the OpenGL Shading Language
specification. The length of the longest uniform name in is given
by ACTIVE_UNIFORM_MAX_LENGTH.
Each uniform variable, declared in a shader, is broken down into one or
more strings using the "." (dot) and "[]" operators, if necessary, to the
point that it is legal to pass each string back into GetUniformLocation,
for default uniform block uniform names, or GetUniformIndices, for
named uniform block uniform names.
For the selected uniform, GetActiveUniform returns the type of the uniform
into and the size of the uniform is into . The value in
is in units of the uniform type, which can be any of the
values in Table 2.utype.
If one or more elements of an array are active, GetActiveUniform will
return the name of the array in , subject to the restrictions listed
above. The type of the array is returned in . The parameter
contains the highest array element index used, plus one. The compiler or
linker determines the highest index used. There will be only one active
uniform reported by the GL per uniform array.
GetActiveUniform will return as much information about active uniforms as
possible. If no information is available, will be set to zero and
will be an empty string. This situation could arise if
GetActiveUniform is issued after a failed link.
If an error occurs, nothing is written to , , ,
or .
Type Name Token Keyword Type Name Token Keyword
--------------- ------- --------------- -------
FLOAT float SAMPLER_1D sampler1D
FLOAT_VEC2 vec2 SAMPLER_2D sampler2D
FLOAT_VEC3 vec3 SAMPLER_3D sampler3D
FLOAT_VEC4 vec4 SAMPLER_CUBE samplerCube
INT int SAMPLER_1D_SHADOW sampler1DShadow
INT_VEC2 ivec2 SAMPLER_2D_SHADOW sampler2DShadow
INT_VEC3 ivec3 SAMPLER_1D_ARRAY_EXT sampler1DArray
INT_VEC4 ivec4 SAMPLER_2D_ARRAY_EXT sampler2DArray
UNSIGNED_INT unsigned int SAMPLER_1D_ARRAY_SHADOW_EXT sampler1DArrayShadow
UNSIGNED_INT_VEC2_EXT uvec2 SAMPLER_2D_ARRAY_SHADOW_EXT sampler2DArrayShadow
UNSIGNED_INT_VEC3_EXT uvec3 SAMPLER_CUBE_SHADOW_EXT samplerCubeShadow
UNSIGNED_INT_VEC4_EXT uvec4 SAMPLER_2D_RECT_ARB sampler2DRect
BOOL bool SAMPLER_2D_RECT_SHADOW_ARB sampler2DRectShadow
BOOL_VEC2 bvec2 INT_SAMPLER_1D_EXT isampler1D
BOOL_VEC3 bvec3 INT_SAMPLER_2D_EXT isampler2D
BOOL_VEC4 bvec4 INT_SAMPLER_3D_EXT isampler3D
FLOAT_MAT2 mat2 INT_SAMPLER_CUBE_EXT isamplerCube
FLOAT_MAT3 mat3 INT_SAMPLER_1D_ARRAY_EXT isampler1DArray
FLOAT_MAT4 mat4 INT_SAMPLER_2D_ARRAY_EXT isampler2DArray
FLOAT_MAT2x3 mat2x3 UNSIGNED_INT_SAMPLER_1D_EXT usampler1D
FLOAT_MAT2x4 mat2x4 UNSIGNED_INT_SAMPLER_2D_EXT usampler2D
FLOAT_MAT3x2 mat3x2 UNSIGNED_INT_SAMPLER_3D_EXT usampler3D
FLOAT_MAT3x4 mat3x4 UNSIGNED_INT_SAMPLER_CUBE_EXT usamplerCube
FLOAT_MAT4x2 mat4x2 UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT usampler1DArray
FLOAT_MAT4x3 mat4x3 UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT usampler2DArray
SAMPLER_BUFFER_EXT samplerBuffer
INT_SAMPLER_BUFFER_EXT isamplerBuffer
UNSIGNED_INT_SAMPLER_BUFFER_EXT usamplerBuffer
INT_SAMPLER_2D_RECT_EXT isampler2DRect
UNSIGNED_INT_SAMPLER_2D_RECT_EXT usampler2DRect
-----------------------------------------------------------------------
Table 2.utype: OpenGL Shading Language type tokens returned by
GetActiveUniform and GetActiveUniformsiv, and corresponding shading
language keywords declaring each such type.
For GetActiveUniformsiv, indicates both the number of
elements in the array of indices and the number of
parameters written to upon successful return. identifies
a property of each uniform in that should be written into
the corresponding element of . If an error occurs, nothing will
be written to .
If is UNIFORM_TYPE, then an array identifying the types
of the uniforms specified by the corresponding array of
is returned. The returned types can be any of the
values in Table 2.utype.
If is UNIFORM_SIZE, then an array identifying the size
of the uniforms specified by the corresponding array of
is returned. The sizes returned are in units of the type
returned by a query of UNIFORM_TYPE. For active uniforms that are
arrays, the size is the number of active elements in the array; for
all other uniforms, the size is one.
If is UNIFORM_NAME_LENGTH, then an array identifying the
length, including the terminating null character, of the uniform
name strings specified by the corresponding array of
is returned.
If is UNIFORM_BLOCK_INDEX, then an array identifying the
uniform block index of each of the uniforms specified by the
corresponding array of is returned. The index of a
uniform associated with the default uniform block is -1.
If is UNIFORM_OFFSET, then an array of uniform buffer offsets
is returned. For uniforms in a named uniform block, the returned value
will be its offset, in basic machine units, relative to the beginning of
the uniform block in the buffer object data store. For uniforms in the
default uniform block, -1 will be returned.
If is UNIFORM_ARRAY_STRIDE, then an array identifying
the stride between elements, in basic machine units, of each of the
uniforms specified by the corresponding array of is
returned. The stride of a uniform associated with the default
uniform block is -1. Note that this information only makes sense for
uniforms that are arrays. For uniforms that are not arrays, but are
declared in a named uniform block, an array stride of zero is
returned.
If is UNIFORM_MATRIX_STRIDE, then an array identifying
the stride between columns of a column-major matrix or rows of a
row-major matrix, in basic machine units, of each of the uniforms
specified by the corresponding array of is
returned. The matrix stride of a uniform associated with the default
uniform block is -1. Note that this information only makes sense for
uniforms that are matrices. For uniforms that are not matrices, but
are declared in a named uniform block, a matrix stride of zero is
returned.
If is UNIFORM_IS_ROW_MAJOR, then
an array identifying whether each of the uniforms
specified by the corresponding array of is a row-major
matrix or not is returned. A value of one indicates a row-major
matrix, and a value of zero indicates a column-major matrix, a matrix
in the default uniform block, or a non-matrix.
Pg 81, replace Uniform* description with:
To load values into the uniform variables of the default uniform block of
the program object that is currently in use, use the commands
...
The given values are loaded into the default uniform block uniform
variable location identified by .
Sub-section 2.15.3.1 - Uniform Blocks
The values of uniforms arranged in named uniform blocks are extracted from
buffer object storage. The mechanisms for placing individual uniforms in
a buffer object and connecting a uniform block to an individual buffer
object are described below.
There is a set of implementation-dependent maximums for the number of
active uniform blocks used by each shader (vertex, fragment, geometry).
If the number of uniform blocks used by any shader in the program exceeds
its corresponding limit, the program will fail to link. The limits for
vertex, fragment, and geometry shaders can be obtained by calling
GetIntegerv with values of MAX_VERTEX_UNIFORM_BLOCKS,
MAX_FRAGMENT_UNIFORM_BLOCKS, and MAX_GEOMETRY_UNIFORM_BLOCKS,
respectively.
Additionally, there is an implementation-dependent limit on the sum of the
number of active uniform blocks used by each shader of a program. If a
uniform block is used by multiple shaders, each such use counts separately
against this combined limit. The combined uniform block use limit can be
obtained by calling GetIntegerv with a of
MAX_COMBINED_UNIFORM_BLOCKS.
When a named uniform block is declared by multiple shaders in a program,
it must be declared identically in each shader. The uniforms within the
block must be declared with the same names and types, and in the same
order. If a program contains multiple shaders with different declarations
for the same named uniform block differs between shader, the program will
fail to link.
Sub-section 2.15.3.1.1 - Uniform Buffer Object Storage
When stored in buffer objects associated with uniform blocks, uniforms are
represented in memory as follows:
- Members of type "bool" are extracted from a buffer object by reading a
single uint-typed value at the specified offset. All non-zero
values correspond to true, and zero corresponds to false.
- Members of type "int" are extracted from a buffer object by reading a
single int-typed value at the specified offset.
- Members of type "uint" are extracted from a buffer object by reading a
single uint-typed value at the specified offset.
- Members of type "float" are extracted from a buffer object by reading a
single float-typed value at the specified offset.
- Vectors with elements with basic data types of "bool", "int",
"uint", or "float" are extracted as values in consecutive memory
locations beginning at the specified offset, with components stored in
order with the first (X) component at the lowest offset. The GL data
type used for component extraction is derived according to the rules for
scalar members above.
- Column-major matrices with columns and rows (using the type
"matx", or simply "mat" if ==) are treated as an array of
floating-point column vectors, each consisting of components.
The column vectors will be stored in order, with column zero at the
lowest offset. The difference in offsets between consecutive columns of
the matrix will be referred to as the column stride, and is constant
across the matrix. The column stride, UNIFORM_MATRIX_STRIDE, is an
implementation-dependent value and may be queried after a program is
linked.
- Row-major matrices with columns and rows (using the type
"matx", or simply "mat" if ==) are treated as an array of
floating-point row vectors, each consisting of components. The
row vectors will be stored in order, with row zero at the lowest offset.
The difference in offsets between consecutive rows of the matrix will be
referred to as the row stride, and is constant across the matrix. The
row stride, UNIFORM_MATRIX_STRIDE, is an implementation-dependent
value and may be queried after a program is linked.
- Arrays of scalars, vectors, and matrices are stored in memory by element
order, with array member zero at the lowest offset. The difference in
offsets between each pair of elements in the array in basic machine
units is referred to as the array stride, and is constant across the
entire array. The array stride, UNIFORM_ARRAY_STRIDE, is an
implementation-dependent value and may be queried after a program is
linked.
Sub-section 2.15.3.1.2 - Standard Uniform Block Layout
By default, uniforms contained within a uniform block are extracted from
buffer storage in an implementation-dependent manner. Applications may
query the offsets assigned to uniforms inside uniform blocks with query
functions provided by the GL.
The "layout" qualifier provides shaders with control of the layout of
uniforms within a uniform block. When the "std140" layout is specified,
the offset of each uniform in a uniform block can be derived from the
definition of the uniform block by applying the set of rules described
below.
If a uniform block is declared in multiple shaders linked together into a
single program, the link will fail unless the uniform block declaration,
including layout qualifier, are identical in all such shaders.
When using the "std140" storage layout, structures will be laid out in
buffer storage with its members stored in monotonically increasing order
based on their location in the declaration. A structure and each
structure member have a base offset and a base alignment, from which an
aligned offset is computed by rounding the base offset up to a multiple of
the base alignment. The base offset of the first member of a structure is
taken from the aligned offset of the structure itself. The base offset of
all other structure members is derived by taking the offset of the last
basic machine unit consumed by the previous member and adding one. Each
structure member is stored in memory at its aligned offset. The members
of a top-level uniform block are laid out in buffer storage by treating
the uniform block as a structure with a base offset of zero.
(1) If the member is a scalar consuming basic machine units, the
base alignment is .
(2) If the member is a two- or four-component vector with components
consuming basic machine units, the base alignment is 2 or
4, respectively.
(3) If the member is a three-component vector with components consuming
basic machine units, the base alignment is 4.
(4) If the member is an array of scalars or vectors, the base alignment
and array stride are set to match the base alignment of a single
array element, according to rules (1), (2), and (3), and rounded up
to the base alignment of a vec4. The array may have padding at the
end; the base offset of the member following the array is rounded up
to the next multiple of the base alignment.
(5) If the member is a column-major matrix with columns and
rows, the matrix is stored identically to an array of column
vectors with components each, according to rule (4).
(6) If the member is an array of column-major matrices with
columns and rows, the matrix is stored identically to a row of
* column vectors with components each, according to rule
(4).
(7) If the member is a row-major matrix with columns and rows,
the matrix is stored identically to an array of row vectors
with components each, according to rule (4).
(8) If the member is an array of row-major matrices with columns
and rows, the matrix is stored identically to a row of *
row vectors with components each, according to rule (4).
(9) If the member is a structure, the base alignment of the structure is
, where is the largest base alignment value of any of its
members, and rounded up to the base alignment of a vec4. The
individual members of this sub-structure are then assigned offsets
by applying this set of rules recursively, where the base offset of
the first member of the sub-structure is equal to the aligned offset
of the structure. The structure may have padding at the end; the
base offset of the member following the sub-structure is rounded up
to the next multiple of the base alignment of the structure.
(10) If the member is an array of structures, the elements of
the array are laid out in order, according to rule (9).
For uniform blocks laid out according to these rules, the minimum buffer
object size returned by the UNIFORM_BLOCK_DATA_SIZE query is derived by
taking the offset of the last basic machine unit consumed by the last
uniform of the uniform block (including any end-of-array or
end-of-structure padding), adding one, and rounding up to the next
multiple of the base alignment required for a vec4.
Sub-section 2.15.3.2 - Uniform Buffer Object Bindings
The value an active uniform inside a named uniform block is extracted from
the data store of a buffer object bound to one of an array of uniform
buffer binding points. The number of binding points can be queried using
GetIntegerv with the constant MAX_UNIFORM_BUFFER_BINDINGS.
Buffer objects are bound to uniform block binding points by calling one of
the commands
void BindBufferRange(enum target,
uint index,
uint buffer,
intptr offset,
sizeiptr size);
void BindBufferBase(enum target,
uint index,
uint buffer);
with set to UNIFORM_BUFFER. There is an array of buffer
object binding points with which uniform blocks can be associated via
UniformBlockBinding, plus a single general binding point that can be
used by other buffer object manipulation functions (e.g. BindBuffer,
MapBuffer). Both commands bind the buffer object named by to the
general binding point, and additionally bind the buffer object to the
binding point in the array given by . The error INVALID_VALUE is
generated if is greater than or equal to the value of
MAX_UNIFORM_BUFFER_BINDINGS.
For BindBufferRange, specifies a starting offset into the
buffer object , and specifies the amount of data that can
be read from the buffer object while used as the storage for a uniform
block. Both and are in basic machine units. An
INVALID_VALUE error is generated if is less than or equal to zero
or if is not a multiple of the implementation-dependent
required alignment (the value of UNIFORM_BUFFER_OFFSET_ALIGNMENT).
BindBufferBase binds the entire buffer, even when the size of the buffer
is changed after the binding is established. It is equivalent to calling
BindBufferRange with zero, while is determined by the
size of the bound buffer at the time the binding is used.
Regardless of the size specified with BindBufferRange, or indirectly
with BindBufferBase, the GL will never read or write beyond the end of a
bound buffer. This may result in visibly different behavior when a
buffer overflow would otherwise result.
Each of a program's active uniform blocks has a corresponding uniform buffer
object binding point. This binding point can be assigned by calling:
void UniformBlockBinding(uint program,
uint uniformBlockIndex,
uint uniformBlockBinding);
is a name of a program object for which the command LinkProgram
has been issued in the past.
must be an active uniform block index of the program
. Otherwise, INVALID_VALUE is generated.
must be less than MAX_UNIFORM_BUFFER_BINDINGS.
Otherwise, INVALID_VALUE is generated.
If successful, UniformBlockBinding specifies that
will use the data store of the buffer object bound to the
binding point to extract the values of the uniforms
in the uniform block identified by .
The results of Begin or commands that perform an implicit Begin are
undefined when an active uniform block of the active program is assigned a
uniform buffer binding point where the parameter to BindBufferRange
is less than the value of UNIFORM_BLOCK_DATA_SIZE for that uniform
block, or when no buffer object is bound to that binding point, and may
result in GL interruption or termination.
When executing shaders that access uniform blocks, the binding point
corresponding to each active uniform block must be populated with a buffer
object with a size no smaller than the minimum required size of the
uniform block (UNIFORM_BLOCK_DATA_SIZE). For binding points populated
by BindBufferRange, the size in question is the value of the
parameter. If any active uniform block is not backed by a sufficiently
large buffer object, the results of shader execution are undefined, and
may result in GL interruption or termination. Shaders may be executed to
process the primitives and vertices specified between Begin and End commands
or by Draw* or MultiDraw* commands (see section 2.8). Shaders may also
be executed as a result of DrawPixels, Bitmap, or RasterPos* commands.
When a program object is linked or re-linked, the uniform buffer object
binding point assigned to each of its active uniform blocks is reset to
zero.
Additions to Chapter 3 - Rasterization
3.11.1 Shader Variables, p. 196
Replace the second two sentences with:
The amount of storage available for fragment shader uniform variables in
the default uniform block is specified by the value of the implementation-
dependent constant MAX_FRAGMENT_UNIFORM_COMPONENTS. The total amount of
combined storage available for fragment shader uniform variables in all
uniform blocks (including the default uniform block) is specified by the
value of the implementation-dependent constant
MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS. These values represent the
numbers of individual floating-point, integer, or boolean values that can be
held in uniform variable storage for a fragment shader.
Additions to Chapter 4 - Per-Fragment Operations and the Framebuffer
None
Additions to Chapter 5 - State and State Requests
5.4 Display Lists, p. 244
Add the following language to the list of commands excluded from
display list compilation:
"Buffer objects: BindBufferRange, BindBufferBase"
Additions to Chapter 6 - State and State Requests
6.1.1 Simple Queries, p. 247
Add the following paragraph:
Indexed simple state variables are queried with the command
void GetIntegeri_v(enum target, uint index, int* data);
is the name of the indexed state and is the
index of the particular element being queried. is a
pointer to a scalar or array of the indicated type in which
to place the returned data. An INVALID_VALUE error is generated
if is outside the valid range for the indexed state
.
6.1.13 Buffer Object Queries, p. 260
Add after description of GetBufferPointerv:
To query which buffer objects are bound to the array of uniform
buffer binding points and will be used as the storage for
active uniform blocks, call GetIntegeri_v with set to
UNIFORM_BUFFER_BINDING. must be in the range
zero to the value of MAX_UNIFORM_BUFFER_BINDINGS - 1.
The name of the buffer object bound to is returned in
. If no buffer object is bound for , zero is
returned in .
To query the starting offset or size of the range of each buffer object
binding used for uniform buffers, call GetIntegeri_v with set to
UNIFORM_BUFFER_START or UNIFORM_BUFFER_SIZE respectively. must
be in the range zero to the value of MAX_UNIFORM_BUFFER_BINDINGS - 1. If
the parameter (starting offset or size) was not specified when the
buffer object was bound (e.g. if bound with BindBufferBase), or if no
buffer object is bound to , zero is returned.
6.1.14 Shader and Program Queries
Pg 261, continuation of paragraph defining "GetProgramiv"
If is ACTIVE_UNIFORM_BLOCKS the number of uniform
blocks for containing active uniforms is returned.
If is ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, the
length of the longest active uniform block name, including
the null terminator, is returned.
Pg 263, replace GetUniform{f|i}v description with:
... return the value or values of the uniform at location
of the default uniform block for program object ...
GLX Protocol
GLX protocol for BindBufferRange, BindBufferBase and GetIntegeri_v
was added through NV_transform_feedback and EXT_draw_buffers2
protocol specs.
The following rendering commands are sent to the server as part of
a glXRender request:
UniformBlockBinding
2 16 rendering command length
2 366 rendering command opcode
4 CARD32 program
4 CARD32 uniformBlockIndex
4 CARD32 uniformBlockBinding
The following non-rendering commands are added:
GetUniformIndices
1 CARD8 opcode(X assigned)
1 215 GLX opcode
2 4+n+(s+p)/4 request length
4 GLX_CONTEXT_TAG context tag
4 CARD32 program
4 CARD32 uniformCount
n LISTofINT32 lengths[n], n = uniformCount, lengths[i] = strlen(uniformNames[i]) + 1, 0 <= i < n.
s LISTofCHAR uniformNames, s = length[0]+...+length[n-1].
array
p unused, p = pad(s)
=>
1 1 reply
1 unused
2 CARD16 sequence number
4 n reply length
4 unused
4 CARD32 n (number of uniform Indices)
if (n == 1) this follows:
4 CARD32 uniformIndices
12 unused
otherwise this follows:
16 unused
4*n LISTofCARD32 uniformIndices
GetActiveUniformsiv
1 CARD8 opcode(X assigned)
1 216 GLX opcode
2 5+n request length
4 GLX_CONTEXT_TAG context tag
4 CARD32 program
4 INT32 uniformCount(n)
4 ENUM pname
n LISTofCARD32 uniformIndices
=>
1 1 reply
1 unused
2 CARD16 sequence number
4 n reply length
4 unused
if (n == 1) this follows:
4 INT32 params
12 unused
otherwise this follows:
16 unused
4*n LISTofINT32 params
GetActiveUniformName
1 CARD8 opcode(X assigned)
1 217 GLX opcode
2 5 request length
4 GLX_CONTEXT_TAG context tag
4 CARD32 program
4 CARD32 uniformIndex
4 INT32 bufsize
=>
1 1 reply
1 unused
2 CARD16 sequence number
4 m reply length, m = (n+p)/4
4 unused
4 INT32 n
16 unused
n LISTofCHAR uniformName, n = strlen(uniformName)+1
p unused, p=pad(n)
GetUniformBlockIndex
1 CARD8 opcode(X assigned)
1 218 GLX opcode
2 3+(n+p)/4 request length
4 GLX_CONTEXT_TAG context tag
4 CARD32 program
n LISTofCHAR uniformBlockName, n = strlen(uniformBlockName)+1
p unused, p=pad(n)
=>
1 1 reply
1 unused
2 CARD16 sequence number
4 0 reply length
4 CARD32 return value
20 unused
GetActiveUniformBlockiv
1 CARD8 opcode(X assigned)
1 219 GLX opcode
2 5 request length
4 GLX_CONTEXT_TAG context tag
4 CARD32 program
4 CARD32 uniformBlockIndex
4 ENUM pname
=>
1 1 reply
1 unused
2 CARD16 sequence number
4 n reply length
4 unused
if (n == 1) this follows:
4 INT32 params
12 unused
otherwise this follows:
16 unused
4*n LISTofINT32 params
GetActiveUniformBlockName
1 CARD8 opcode(X assigned)
1 220 GLX opcode
2 5 request length
4 GLX_CONTEXT_TAG context tag
4 CARD32 program
4 CARD32 uniformBlockIndex
4 INT32 bufsize
=>
1 1 reply
1 unused
2 CARD16 sequence number
4 m reply length, m = (n+p)/4
4 unused
4 INT32 n
16 unused
n LISTofCHAR uniformBlockName, n = strlen(uniformBlockName)+1
p unused, p=pad(n)
OpenGL Shading Language Spec v1.20.8 Updates
Including the following line in a shader can be used to control the
language features described in this extension:
#extension GL_ARB_uniform_buffer_object :
where is as specified in section 3.3.
A new preprocessor #define is added to the OpenGL Shading
Language:
#define GL_ARB_uniform_buffer_object 1
Add two new sections:
4.3.5.1 Uniform Blocks
Variable declarations at global scope can be grouped into a named block to
provide coarser granularity for manipulation, sharing, or backing than is
achievable with individual declarations. This is currently only allowed for
uniform variables grouped into uniform blocks. All other uses are reserved.
The application backs a uniform block with a buffer. This allows application
access to a set of uniform variables through a single buffer. The
application will need to query the offsets of the variables within the
block or follow standard rules for block layout in order to know how to
layout the contents of a buffer used to back the block.
A uniform block (rather than a uniform variable) is created by the uniform
keyword, followed by a block name, followed by an open curly brace ( { ) as
follows:
uniform-block :
layout-qualifieropt uniform block-name { member-list } ;
layout-qualifier :
layout ( layout-qualifier-id-list )
member-list :
member-declaration
member-declaration member-list
member-declaration :
layout-qualifieropt uniformopt basic-type declarators ;
Where declarators are the same as for other uniform variable declarations,
except initializers are not allowed. Layout qualifiers are defined in the
next section.
For example,
uniform Transform {
mat4 ModelViewMatrix;
mat4 ModelViewProjectionMatrix;
uniform mat3 NormalMatrix; // reuse of uniform is optional
float Deformation;
};
The above establishes a uniform block named "Transform" with four uniforms
grouped inside it.
The names declared inside the block are accessed as if they were declared
outside the block. In no way does the shader ever access block members
through any use of block-name.
Uniform block names and variable names declared within uniform blocks are
scoped at the program level. Matching block names from multiple compilation
units in the same program must match in terms of having the same number of
declarations with the same sequence of types and the same sequence of member
names, as well as having the same member-wise layout qualification (see next
section). Any mismatch will generate a link error.
Sampler types are not allowed inside of uniform blocks. All other types,
arrays, and structures allowed for uniforms are allowed within a uniform
block.
There is an implementation-dependent limit on the number of uniform blocks
that can be used per stage. If this limit is exceeded, it will cause a link
error.
4.3.5.2 Uniform Block Layout Qualifiers
The layout-qualifier-id-list for uniform blocks is a comma separated list of
the following qualifiers:
shared (default)
packed
std140
row_major
column_major (default)
These qualifiers are identifiers, not keywords. None of these have any
semantic affect at all on the usage of the variables being declared; they
only describe how data is laid out in memory. For example, matrix semantics
are always column-based, as described in the rest of this specification, no
matter what layout qualifiers are being used.
Uniform block layout qualifiers can be declared at global scope, on a single
uniform block, or on a single block member.
At global scope, it is an error to use layout qualifiers to declare a
variable. Instead, at global scope, layout qualifiers apply just to the
keyword uniform and establish default qualification for subsequent blocks:
layout-defaults :
layout-qualifier uniform ;
When this is done, the previous default qualification is first inherited and
then overridden as per the override rules listed below for each qualifier
listed in the declaration. The result becomes the new default qualification
scoped to subsequent uniform block definitions. Layout defaults can only be
specified at global scope.
The initial state of compilation is as if the following were declared:
layout(shared, column_major) uniform;
Explicitly declaring this in a shader will return defaults back to their
initial state.
Uniform blocks can be declared with optional layout qualifiers, and so can
their individual member declarations. Such block layout qualification is
scoped only to the content of the block. As with global layout declarations,
block layout qualification first inherits from the current default
qualification and then overrides it. Similarly, individual member layout
qualification is scoped just to the member declaration, and inherits from
and overrides the block's qualification.
The shared qualifier overrides only the std140 and packed qualifiers; other
qualifiers are inherited. The compiler/linker will ensure that multiple
programs and programmable stages containing this definition will share the
same memory layout for this block, as long as they also matched in their
row_major and/or column_major qualifications. This allows use of the same
buffer to back the same block definition across different programs.
The packed qualifier overrides only std140 and shared; other qualifiers are
inherited. When packed is used, no shareable layout is guaranteed. The
compiler and linker can optimize memory use based on what variables actively
get used and on other criteria. Offsets must be queried, as there is no
other way of guaranteeing where (and which) variables reside within the
block. Attempts to share a packed uniform block across programs or stages
will generally fail. However, implementations may aid application management
of packed blocks by using canonical layouts for packed blocks.
The std140 qualifier overrides only the packed and shared qualifiers; other
qualifiers are inherited. The layout is explicitly determined by this, as
described in the API specification section 2.15.3.1.2. Hence, as in shared
above, the resulting layout is shareable across programs.
Layout qualifiers on member declarations cannot use the shared, packed, or
std140 qualifiers. These can only be used at global scope or on a block
declaration.
The row_major qualifier overrides only the column_major qualifier; other
qualifiers are inherited. It only affects the layout of matrices. Elements
within a matrix row will be contiguous in memory.
The column_major qualifier overrides only the row_major qualifier; other
qualifiers are inherited. It only affects the layout of matrices. Elements
within a matrix column will be contiguous in memory.
When multiple arguments are listed in a layout declaration, the affect will
be the same as if they were declared one at a time, in order from left to
right, each in turn inheriting from and overriding the result from the
previous qualification.
For example
layout(row_major, column_major)
results in the qualification being column_major. Other examples:
layout(shared, row_major) uniform; // default is now shared & row_major
layout(std140) uniform Transform { // layout of this block is std140
mat4 M1; // row_major
layout(column_major) mat4 M2; // column major
mat3 N1; // row_major
};
uniform T2 { // layout of this block is shared
...
};
layout(column_major) uniform T3 { // shared and column_major
mat4 M3; // column_major
layout(row_major) mat4 m4; // row major
mat3 N2; // column_major
};
Interactions with OpenGL 3.0
If OpenGL 3.0 is supported, the introduction of BindBufferBase and
BindBufferRange can be ignored, though the uniform buffer object
language herein will need to be merged with the transform feedback
language in GL 3.0.
If OpenGL 3.0 is supported, the introduction of GetIntegeri_v
can be ignored.
If OpenGL 3.0 is supported, change:
"When a program is successfully linked, all active uniforms belonging to
the program object's default uniform block are initialized to zero (FALSE
for booleans). A successful link will also generate a location for each
active uniform in the default uniform block. The values of active uniforms
in the default uniform block can be changed using this location and the
appropriate Uniform* command (see below)."
to
"When a program is successfully linked, all active uniforms belonging to
the program object's default uniform block are initialized as defined by
the version of the OpenGL Shading Language used to compile the program. A
successful link will also generate a location for each active uniform in
the default uniform block. The values of active uniforms in the default
uniform block can be changed using this location and the appropriate
Uniform* command (see below)."
If OpenGL 3.0 is supported, replace "Begin or commands that perform
an implicit Begin" with "Draw* commands."
If OpenGL 3.0 is supported, UNIFORM_BUFFER is a valid target for
new buffer-related API, e.g. MapBufferRange.
Interactions with EXT_gpu_shader4
If EXT_gpu_shader4 is not supported, then all of the types in table
2.utype with extension suffixes should be omitted.
Interactions with ARB_texture_rectangle
If ARB_texture_rectangle is not available, then all of the types in
table 2.utype with RECT in their names should be omitted.
Interactions with EXT_texture_array
If EXT_texture_array is not available, then all of the types in
table 2.utype with ARRAY in their names should be omitted.
Interactions with EXT_texture_buffer_object
If EXT_texture_buffer_object is not available, then all of the types
in table 2.utype with BUFFER in their names should be omitted.
Interactions with EXT_texture_integer
If EXT_texture_integer is not available, then all of the types in
table 2.utype with UNSIGNED_INT or INT_SAMPLER in their names should
be omitted.
Interactions with ARB_geometry_shader4
If ARB_geometry_shader4 is not supported, omit all mentions of the
geometry shader stage, including MAX_GEOMETRY_UNIFORM_BUFFERS
and UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER. The minimum
value of MAX_COMBINED_UNIFORM_BLOCKS and
MAX_UNIFORM_BUFFER_BINDINGS changes from 36 to 24.
Language describing MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS can be found
in the ARB_geometry_shader4 specification.
Errors
The error INVALID_OPERATION is generated by BindBufferRange and
BindBufferBase if is not the name of a valid buffer object.
The error INVALID_VALUE is generated by GetUniformIndices,
GetActiveUniformsiv, GetActiveUniformName, GetUniformBlockIndex,
GetActiveUniformBlockiv, GetActiveUniformBlockName, and
UniformBlockBinding if is not a value generated by GL.
The error INVALID_VALUE is generated by GetUniformIndices and
GetActiveUniformsiv if is less than zero.
The error INVALID_VALUE is generated by GetActiveUniformName and
GetActiveUniformBlockName if is less than zero.
The error INVALID_VALUE is generated by BindBufferRange if is less
than zero.
The error INVALID_VALUE is generated by GetActiveUniformName if
is greater than or equal to ACTIVE_UNIFORMS.
The error INVALID_VALUE is generated by GetActiveUniformsiv if any of
the indices in is greater than or equal to ACTIVE_UNIFORMS.
The error INVALID_VALUE is generated by GetActiveUniformBlockiv,
GetActiveUniformBlockName, and UniformBlockBinding if
is greater than or equal to ACTIVE_UNIFORM_BLOCKS.
The error INVALID_VALUE is generated by UniformBlockBinding if
is greater than or equal to
MAX_UNIFORM_BUFFER_BINDINGS.
The error INVALID_VALUE is generated by BindBufferRange and BindBufferBase
if is greater than or equal to MAX_UNIFORM_BUFFER_BINDINGS.
The error INVALID_VALUE is generated by BindBufferRange if is not
a multiple of UNIFORM_BUFFER_OFFSET_ALIGNMENT basic machine units.
The error INVALID_ENUM is generated by GetActiveUniformsiv and
GetActiveUniformBlockiv if is not one of the accepted values.
The error INVALID_ENUM is generated by BindBufferRange and BindBufferBase
if is not an accepted indexable buffer object target.
New State
Initial
Get Value Type Get Command Value Description Sec Attribute
-------------------------- ---- ----------- ----- ------------------------- ----- ---------
UNIFORM_BUFFER_BINDING Z+ GetIntegerv 0 Uniform buffer object 2.15.3 -
bound to the context for
buffer object manipulation.
UNIFORM_BUFFER_BINDING nxZ+ GetIntegeri_v 0 Uniform buffer object 2.15.3 -
bound to the specified
context binding point
ACTIVE_UNIFORM_BLOCKS Z+ GetProgramiv 0 Number of active 2.15.3 -
uniform blocks in a
program
ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH
Z+ GetProgramiv 0 Length of longest active 2.15.3 -
uniform block name
UNIFORM_TYPE 0*xZ_27 GetActiveUniformsiv - Type of active uniform 2.15.3 -
UNIFORM_SIZE 0*xZ+ GetActiveUniformsiv - Size of active uniform 2.15.3 -
UNIFORM_NAME_LENGTH 0*xZ+ GetActiveUniformsiv - Uniform name length 2.15.3 -
UNIFORM_BLOCK_INDEX 0*xZ GetActiveUniformsiv - Uniform block index 2.15.3 -
UNIFORM_OFFSET 0*xZ GetActiveUniformsiv - Uniform buffer offset 2.15.3 -
UNIFORM_ARRAY_STRIDE 0*xZ GetActiveUniformsiv - Uniform buffer array 2.15.3 -
stride
UNIFORM_MATRIX_STRIDE 0*xZ GetActiveUniformsiv - Uniform buffer intra- 2.15.3 -
matrix stride
UNIFORM_IS_ROW_MAJOR 0*xZ+ GetActiveUniformsiv - Whether uniform is a 2.15.3 -
row-major matrix
UNIFORM_BLOCK_BINDING 0*xZ+ GetActiveUniformBlockiv 0 Uniform buffer binding 2.15.3 -
points associated with the
specified uniform block
UNIFORM_BLOCK_DATA_SIZE 0*xZ+ GetActiveUniformBlockiv - Size of the storage 2.15.3 -
needed to hold this
uniform block's data
UNIFORM_BLOCK_ACTIVE_UNIFORMS 0*xZ+ GetActiveUniformBlockiv - Count of active 2.15.3 -
uniforms in
the specified
uniform block
UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES
0*xnxZ+ GetActiveUniformBlockiv - Array of active 2.15.3 -
uniform indices of
the specified
uniform block
UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER
0*xB GetActiveUniformBlockiv 0 TRUE if uniform block 2.15.3 -
is actively
referenced by the
vertex shader
UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER
0*xB GetActiveUniformBlockiv 0 TRUE if uniform block 2.15.3 -
is actively
referenced by the
geometry shader
UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER
0*xB GetActiveUniformBlockiv 0 TRUE if uniform block 2.15.3 -
is actively
referenced by the
fragment shader
New Implementation Dependent State
Minimum
Get Value Type Get Command Value Description Sec Attribute
-------------------------------- -- ----------- ----- ------------------------- ----- ----------
MAX_VERTEX_UNIFORM_BLOCKS Z+ GetIntegerv 12 Maximum number of vertex 2.15.3 -
uniform buffers per
program
MAX_FRAGMENT_UNIFORM_BLOCKS Z+ GetIntegerv 12 Maximum number of fragment 2.15.3 -
uniform buffers per
program
MAX_GEOMETRY_UNIFORM_BLOCKS Z+ GetIntegerv 12 Maximum number of geometry 2.15.3 -
uniform buffers per
program
MAX_COMBINED_UNIFORM_BLOCKS Z+ GetIntegerv 36 Maximum number of uniform 2.15.3 -
buffers per program
MAX_UNIFORM_BUFFER_BINDINGS Z+ GetIntegerv 36 Maximum number of uniform 2.15.3 -
buffer binding points
on the context
MAX_UNIFORM_BLOCK_SIZE Z+ GetIntegerv 16384 Max size in basic machine 2.15.3 -
units of a uniform block
MAX_VERTEX_UNIFORM_COMPONENTS Z+ GetIntegerv * Number of words for vertex 2.15.3 -
shader uniform variables
in default uniform block
MAX_FRAGMENT_UNIFORM_COMPONENTS Z+ GetIntegerv * Number of words for fragment 2.15.3 -
shader uniform variables
in default uniform block
MAX_GEOMETRY_UNIFORM_COMPONENTS Z+ GetIntegerv * Number of words for geometry 2.15.3 -
shader uniform variables
in default uniform block
MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS Z+ GetIntegerv * Number of words for vertex 2.15.3 -
shader uniform variables
in all uniform blocks
(including default)
MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS Z+ GetIntegerv * Number of words for fragment 2.15.3 -
shader uniform variables
in all uniform blocks
(including default)
MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS Z+ GetIntegerv * Number of words for geometry 2.15.3 -
shader uniform variables
in all uniform blocks
(including default)
UNIFORM_BUFFER_OFFSET_ALIGNMENT Z+ GetIntegerv 1 Minimum required alignment 2.15.3 -
for uniform buffer sizes
and offsets
* Minimum value for OpenGL 3.1 is (MAX__UNIFORM_BLOCKS *
MAX_UNIFORM_BLOCK_SIZE) + MAX__UNIFORM_COMPONENTS. Minimum
value prior to OpenGL 3.1 is MAX__UNIFORM_COMPONENTS.
Sample Code
////////////////////////////////////////////////////////////////////////////
Example: Full code of a simple use case: updating a group of variables
in a real shader.
////////////////////////////////////////////////////////////////////////////
//Platform-specific includes go here
#define glError() { \
GLenum err = glGetError(); \
while (err != GL_NO_ERROR) { \
printf("glError: %s caught at %s:%u", \
(char*)gluErrorString(err), __FILE__, __LINE__); \
err = glGetError(); \
exit(-1); \
} \
}
// globals
int initialized = 0;
int width=640;
int height=480;
GLfloat wf,hf;
//uniform names
GLchar* names[] =
{
"SurfaceColor",
"WarmColor",
"CoolColor",
"DiffuseWarm",
"DiffuseCool"
};
GLuint buffer_id, uniformBlockIndex, index, vshad_id, fshad_id, prog_id;
GLsizei uniformBlockSize;
GLint singleSize, offset;
GLfloat colors[] =
{
0.45,0.45,1,1,
0.45,0.45,1,1,
0.75,0.75,0.75,1,
0.0,0.0,1.0,1,
0.0,1.0,0.0,1,
};
void reshape(int w, int h) {
width = w; height = h;
wf = (GLfloat) width;
hf = (GLfloat) height;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, wf/hf, 0.1, 100.0);
}
void init_opengl()
{
reshape(width, height);
//load_shader and link_program are utility functions omitted here
vshad_id = load_shader(GL_VERTEX_SHADER, "gooch.vs");
fshad_id = load_shader(GL_FRAGMENT_SHADER, "gooch.fs");
prog_id = glCreateProgram();
glAttachShader(prog_id, vshad_id);
glAttachShader(prog_id, fshad_id);
link_program(prog_id);
//Update the uniforms using ARB_uniform_buffer_object
glGenBuffers(1, &buffer_id);
//There's only one uniform block here, the 'colors0' uniform block.
//It contains the color info for the gooch shader.
uniformBlockIndex = glGetUniformBlockIndex(prog_id, "colors0");
//We need to get the uniform block's size in order to back it with the
//appropriate buffer
glGetActiveUniformBlockiv(prog_id, uniformBlockIndex,
GL_UNIFORM_BLOCK_DATA_SIZE,
&uniformBlockSize);
glError();
//Create UBO.
glBindBuffer(GL_UNIFORM_BUFFER, buffer_id);
glBufferData(GL_UNIFORM_BUFFER, uniformBlockSize,
NULL, GL_DYNAMIC_DRAW);
//Now we attach the buffer to UBO binding point 0...
glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer_id);
//And associate the uniform block to this binding point.
glUniformBlockBinding(prog_id, uniformBlockIndex, 0);
glError();
//To update a single uniform in a uniform block, we need to get its
//offset into the buffer.
glGetUniformIndices(prog_id, 1, &names[2], &index);
glGetActiveUniformsiv(prog_id, 1, &index,
GL_UNIFORM_OFFSET, &offset);
glGetActiveUniformsiv(prog_id, 1, &index,
GL_UNIFORM_SIZE, &singleSize);
glError();
glViewport(0, 0, width, height);
}
void render()
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
glUseProgram(prog_id);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0, 0, -4);
glColor3f(1.0, 1.0, 1.0);
glBindBuffer(GL_UNIFORM_BUFFER, buffer_id);
//We can use BufferData to upload our data to the shader,
//since we know it's in the std140 layout
glBufferData(GL_UNIFORM_BUFFER, 80, colors, GL_DYNAMIC_DRAW);
//With a non-standard layout, we'd use BufferSubData for each uniform.
glBufferSubData(GL_UNIFORM_BUFFER, offset, singleSize, &colors[8]);
//the teapot winds backwards
glFrontFace(GL_CW);
glutSolidTeapot(1.33);
glFrontFace(GL_CCW);
glutSwapBuffers();
}
void display()
{
if(!initialized)
{
init_opengl();
initialized = 1;
}
render();
}
int main (int argc, const char** argv) {
//GLUT initialization goes here
}
// Vertex shader for Gooch shading
// Author: Randi Rost
// Copyright (c) 2002-2006 3Dlabs Inc. Ltd.
// See 3Dlabs-License.txt for license information
vec3 LightPosition = vec3(0.0, 10.0, 4.0);
varying float NdotL;
varying vec3 ReflectVec;
varying vec3 ViewVec;
void main(void)
{
vec3 ecPos = vec3 (gl_ModelViewMatrix * gl_Vertex);
vec3 tnorm = normalize(gl_NormalMatrix * gl_Normal);
vec3 lightVec = normalize(LightPosition - ecPos);
ReflectVec = normalize(reflect(-lightVec, tnorm));
ViewVec = normalize(-ecPos);
NdotL = (dot(lightVec, tnorm) + 1.0) * 0.5;
gl_Position = ftransform();
}
// Fragment shader for Gooch shading, adapted for ARB_uniform_buffer_object
#extension GL_ARB_uniform_buffer_object : enable
layout(std140) uniform colors0
{
float DiffuseCool;
float DiffuseWarm;
vec3 SurfaceColor;
vec3 WarmColor;
vec3 CoolColor;
};
varying float NdotL;
varying vec3 ReflectVec;
varying vec3 ViewVec;
void main (void)
{
vec3 kcool = min(CoolColor + DiffuseCool * SurfaceColor, 1.0);
vec3 kwarm = min(WarmColor + DiffuseWarm * SurfaceColor, 1.0);
vec3 kfinal = mix(kcool, kwarm, NdotL);
vec3 nreflect = normalize(ReflectVec);
vec3 nview = normalize(ViewVec);
float spec = max(dot(nreflect, nview), 0.0);
spec = pow(spec, 32.0);
gl_FragColor = vec4 (min(kfinal + spec, 1.0), 1.0);
}
Examples
The following example illustrates the rules specified by the "std140"
layout.
layout(std140) uniform Example {
// Base types below consume 4 basic machine units
//
// base base align
// rule align off. off. bytes used
// ---- ------ ---- ---- -----------------------
float a; // 1 4 0 0 0..3
vec2 b; // 2 8 4 8 8..15
vec3 c; // 3 16 16 16 16..27
struct { // 9 16 28 32 (align begin)
int d; // 1 4 32 32 32..35
bvec2 e; // 2 8 36 40 40..47
} f; // 9 16 48 48 (pad end)
float g; // 1 4 48 48 48..51
float h[2]; // 4 16 52 64 64..67 (h[0])
// 80 80..83 (h[1])
// 4 16 84 96 (pad end of h)
mat2x3 i; // 5/4 16 96 96 96..107 (i, column 0)
// 112 112..123 (i, column 1)
// 5/4 16 124 128 (pad end of i)
struct { // 10 16 128 128 (align begin)
uvec3 j; // 3 16 128 128 128..139 (o[0].j)
vec2 k; // 2 8 140 144 144..151 (o[0].k)
float l[2]; // 4 16 152 160 160..163 (o[0].l[0])
// 176 176..179 (o[0].l[1])
// 4 16 180 192 (pad end of o[0].l)
vec2 m; // 2 8 192 192 192..199 (o[0].m)
mat3 n[2]; // 6/4 16 200 208 208..219 (o[0].n[0], column 0)
// 224 224..235 (o[0].n[0], column 1)
// 240 240..251 (o[0].n[0], column 2)
// 256 256..267 (o[0].n[1], column 0)
// 272 272..283 (o[0].n[1], column 1)
// 288 288..299 (o[0].n[1], column 2)
// 6/4 16 300 304 (pad end of o[0].n)
// 9 16 304 304 (pad end of o[0])
// 3 16 304 304 304..315 (o[1].j)
// 2 8 316 320 320..327 (o[1].k)
// 4 16 328 336 336..347 (o[1].l[0])
// 352 352..355 (o[1].l[1])
// 4 16 356 368 (pad end of o[1].l)
// 2 8 368 368 368..375 (o[1].m)
// 6/4 16 376 384 384..395 (o[1].n[0], column 0)
// 400 400..411 (o[1].n[0], column 1)
// 416 416..427 (o[1].n[0], column 2)
// 432 432..443 (o[1].n[1], column 0)
// 448 448..459 (o[1].n[1], column 1)
// 464 464..475 (o[1].n[1], column 2)
// 6/4 16 476 480 (pad end of o[1].n)
// 9 16 480 480 (pad end of o[1])
} o[2];
};
Issues
(1) How are offsets to elements in a uniform buffer correlated to
uniform locations?
Resolved: Traditional uniform locations were used in the glUniform
API to access the private uniform storage. This API does not allow
the use of glUniform to update uniforms stored in uniform blocks.
Instead it uses the various means to update buffer objects, and
exposes the byte offsets of the uniforms in the buffer object. So,
in short, uniform locations and uniform offsets are similar concepts
but unrelated.
(2) Should uniforms declared bindable be excluded from a uniform
buffer?
Resolved: No, however, if a bindable uniform is declared inside
a named uniform uniform block, the bindable declaration and all
associated behavior of the bindable uniform extension will be
superceded by the mechanisms defined in this extension to obtain
information about the location of uniforms and to update the values
of those uniforms.
In other words, if the bindable modifier is used on a uniform declared
within a named uniform block, it will be ignored.
(3) Are there restrictions on the data types or the order in which uniforms
are declared that are to be included as part of the uniform buffer?
Resolved: The only restriction is that sampler uniforms can not be
stored in a uniform buffer object. All other uniform types can be
stored in a uniform block.
(4) Should a uniform buffer be split into multiple uniform buffers
on a per data type basis to simplify the buffer offset interface ?
Resolved: No. This violates the intended "generic data store"
convention of buffer objects. Users of this extension are free
to group their uniform definitions on a per data-type basis in
this manner and, indeed, it may, on some implementations, result
in a more efficient uniform update model.
(5) Should uniform buffers be scoped per shader (program
stage) rather than per program (as in GLSL) ?
Resolved: No, this extension does not change the per-program
scope of uniforms. Uniforms in a uniform block, like traditional
GLSL uniforms, are global to a program object.
It's tricky because allowing uniforms to have per-stage scope
exposes both a feature and the possibility for an application
programming error.
feature: an application that wants to use a uniform "foo" in two
stages and wants uniform "foo" has different layouts
and/or values in each stage (or possibly simply does not
care if they do)
vs.
error: an application that wants to use a uniform "foo" in two
stages and does not want them to have different values, but
*accidentally* defines "foo" in each stage differently or
binds different uniform buffers to each stage.
Rather than enable this feature (and simultaneously add possibility
for error) in this extension, we defer the choice to a future
extension.
Note however, some of the motivation for a per-stage scope for
uniform names comes from a broader desire to augment the GLSL API
with a set of per-stage program objects that do not need to be
linked at all. This is possibly a valuable addition to the GL API,
but is left to be defined by an additional extension. Such a future
extension could, if desired, add syntax to the GLSL to allow any
uniform (uniform block or default) to be defined with "per-stage" scope
in a more comprehensive way.
(6) Should AttachUniformBuffer take a argument?
This issue is moot. Earlier versions of this extension included
the additional ability to attach a uniform buffer object directly
to a progam's uniform blocks instead of going through the per-context
uniform buffer binding points.
This feature has been deferred, possibly to be added in a future
extension.
If this routine were to be added and does not take a program
argument, then it should work on the currently bound program
object, and its name should be changed to
ProgramUniformBuffer, to conform to precedent set by
FramebufferTexture, et. all.
Alternately, if AttachUniformBuffer requires a program
argument, it would be for consistency with existing C API to
GLSL (i.e., those that attach shaders to program objects and
query program objects for information).
RESOLUTION: RESOLVED, moot.
(7) Should uniforms in a uniform block be identified by location or
string?
Resolved: By string and also by index (but not location). Name
strings will be used to identify uniforms much as they are
today. Uniform indices were available before for referring to
uniforms because they provide a more efficient update mechanism
to specify uniforms. Uniform block indices have been used in
this extension for the same reason.
The location API not used by this extension and is only relevant for
the glUniform* API.
RESOLUTION: RESOLVED, moot.
(8) What is the order of operations under which a uniform buffer
association is made with a program (or shader)?
It is known that at very least, that the uniform buffer
offsets and strides will be known at link time. Does the
uniform buffer need to be attached to the program prior to linking in
order to keep these offsets constant or can a uniform buffer be
bound to a program at any time post-link effectively acting as
substitute storage for the uniform data?
RESOLVED: Uniform buffer objects are bound to the context's
uniform buffer binding points, and this can happen at any time.
However, the association of a program's uniform block to the context's
uniform buffer binding points can only happen after linking because only
then are uniform block indices known.
(9) Can the existing Uniform API be used to update values in a
uniform buffer?
Resolved: No. The Uniform* API won't update values in a uniform buffer,
which is reinforced by the fact that uniform block uniforms do not have
a location.
(10) When is the size of a uniform block's storage known?
Resolved: Only after linking.
Once a program is linked, the storage needed for a given uniform
block can be determined by querying for
UNIFORM_BLOCK_DATA_SIZE.
If a uniform block needs more storage than the buffer object
bound to the associated uniform buffer binding point can provide,
results are undefined. This is no different than fetching off the end
of an array.
(11) Is it an error to call AttachUniformBuffer prior to
linking the program designated by ?
Resolved. This issue is moot because the
AttachUniformBuffer was removed/deferred to a future
extension.
But if this API were added, then yes. INVALID_VALUE is generated
if AttachUniformBuffer is used to attach a buffer to an
invalid uniform block index. Prior to linking, there are no
uniform block indices.
(12) Some hardware does not support some of the GLSL data types
natively (bools or ints perhaps). What limitations do we have in
exposing the raw uniform data storage via the buffer object API ?
Resolved: None, but note that some implementations without
native support for these data types may have to copy the data
in these data types into some more native data types.
Also, queries are provided to expose the layout of the buffer
objects to allow the buffers to be packed properly.
(13) Are there expected limitations for dead uniform elimination
using this extension?
Resolved: yes.
For starters, when using the "std140" layout, an implementation
may not alter the storage layout in any way. This limitation
includes dead uniform elimination. The standard layout must
remain unchanged because an application will depend on it
rather than querying for uniform offsets/strides.
When using the "shared" layout, dead uniform elimination is again
excluded because different uniforms could be eliminated based on
different shaders' uniform usage. In order to preserve shareability
of the uniform blocks, the full contingent of uniforms must remain.
For the "packed" layout, an implementation may take the liberty of
eliminating uniforms and uniform blocks that are not used by the paired
shaders. Here, limitations exist only for arrays. Dead elements may be
stripped from the end of an array that is never dynamically
dereferenced. An application must query UNIFORM_SIZE before
loading array data into the uniform buffer to ensure that trailing
elements exist.
Issue (24) deals with stripping leading elements from an array, and
issue (25) deals with stripping arbitrary elements from an array,
both of which are currently disallowed.
Note that the default uniform block always exists even if it is empty.
(14) Is it necessary to provide array uniform element offsets into
a uniform buffer object? If so, this suggests string parsing
of things such as "myuniform[12]". If not, this assumes array
strides be guaranteed based on array data type for all hw platforms?
Resolved: No. The stride is provided explictly by querying
UNIFORM_ARRAY_STRIDE with GetActiveUniformsiv.
(15) How are the values from static initializer values propagated
to a buffer object once it is attached?
Resolved: Static initialization values declared in a shader mapped
to a uniform buffer are disallowed by the grammar and must be
established through writes to the uniform buffer.
(16) Is GetUniformBlockIndex needed? This information can be
obtained (in reverse mapping) from GetActiveUniformBlock.
Resolved: Yes. GetUniformBlockIndex allows the uniform
block database to be queried in the most natural manner: step 1)
do the expensive conversion from a uniform block name to a
uniform block index, step 2) use the uniform block index to
obtain all other uniform block data, which is a simple array
dereference, not a search.
(17) is GetUniformIndex needed? This information can be obtained (in
reverse mapping) from GetActiveUniform.
Resolved: Yes. See issue (16).
(18) Should we add a separate function GetActiveUniformBlockBufferSize
instead of using GetActiveUniformBlock to return everything.
Resolved: No. This issue became moot when the more general function
GetActiveUniformBlockiv was added.
(19) Should we provide a mechanism for iterating over the uniforms in a
particular uniform block?
Resolved: Yes. This is provided by querying
UNIFORM_BLOCK_ACTIVE_UNIFORMS with GetActiveUniformBlockiv.
(20) Should we provide a means for the application to query the desired
storage format for integers, booleans, and matrices, or should we specify
a format and force non-conforming implementations to do a conversion?
RESOLUTION: No queries will be introduced. Implementations that cannot
handle the prescribed storage formats must convert as necessary.
See also issue (48)
(21) Should we delete the integer and boolean storage types in favor of
implementation repacking of the data when the hardware doesn't support it?
RESOLUTION: RESOLVED, no.
Hardware that doesn't support the types must repack the uniform data
if needed. This is true for all layout options.
(22) How does the program notice new changes to the uniform buffer object?
Should we add a new "UpdateUniforms()" call or use
AttachUniformBuffer(), or UseProgram() to realize changes.
RESOLUTION: Following the "standard" way in which object changes are
noticed, the buffer object in question must be re-bound or
re-attached if the changes to the buffer object come from another
context.
If the changes come from this context, then the intent is to
follow the general object model decision here that governs how
child/container object state changes are made.
[Currently, this means that changes by this context will be
noticed at next draw time, at the latest].
(23) The naming convention choosen for GetActiveUniformsiv and
GetActivePartitionsiv is not a simple matter.
First, considering that the list of uniforms passed into these
routines must be active uniform indices, and is an error if not,
suggests that the name "Active" in these function calls is
redundant. GLSL established a precedent of using "Active" in
the names of functions that require their uniform parameters to
consist solely of active uniforms. For these routines, it is an
error to include an inactive uniform as one of their input
parameters. Consistency with this GLSL precedent is the reason
we've choosen to include "Active" in these routine names.
Second, note that GetActiveUniformsiv does not "get active
uniforms" and GetActiveUniformBlocksiv does not "get active
uniform blocks". There is a compelling argument therefore that
these names are counterintuitive. In reality, these routines
return parameters of active uniforms and active uniform blocks
rather than the uniforms or uniform blocks themselves. Again,
looking back at GLSL precedent note the conventions used for
both GetProgramiv and GetShaderiv. Both of these routines have
a argument and both of these routines are in fact
returning parameters of programs and shaders respectively
however "Parameters" was not included in the name.
Further challenging this second point are two other
considerations. First, the GL spec prior to GLSL does in fact
use "Parameters" in the name of functions that match this
pattern. Second, this spec itself includes the name of the
output parameter in the name (specifically calls to get Indices
and Names).
In the end, because this specification has to work within the
GLSL framework, it was decided that this precendent should
prevail over all others. Therefore, these routines will not
include "Parameters" in their names.
Resolved: See above.
(24) Do we need to be able to query UNIFORM_START to get the index of
the first active element of an array?
An application must query UNIFORM_SIZE to find the extent of an
array at runtime because the GLSL compiler may have eliminated elements
from the end of a static array during dead code elimination. If the
application is not required to similarly query UNIFORM_START, the
compiler must be prevented from eliminating elements from the start of
an array.
For example, if an application declares "uniform float myFloat[10];" and
accesses only the single element myFloat[7] in the shader text, the
compiler may eliminate elements 8-9 only. Querying UNIFORM_SIZE
will give 8, and UNIFORM_OFFSET will give the offset of element 0.
If we add UNIFORM_START, in this example, querying
UNIFORM_SIZE will give 1, UNIFORM_START will give 7, and
UNIFORM_OFFSET will give the offset of element 7 in the uniform
buffer.
Purely for symmetry, it seems that the compiler should be as free to
strip leading elements as it is to strip trailing elements.
After additional discussions, however, the working group decided
not to introduce this complexity. This feature could be layered
as an additional extension if desired.
RESOLUTION: RESOLVED
(25) Following issue (24), should we provide a mechanism to allow the
compiler to strip *any* dead elements from a uniform array without
restriction, not just leading and trailing elements?
Resolved: No. Too cumbersome for the application to use.
(26) Should we make any guarantees about the ordering of uniforms in the
active uniform array, relative to their uniform block number?
It might be useful to guarantee that the ordering of the
uniforms in the active uniform array is such that all uniforms
in a single uniform block form a contiguous subrange of the
active uniform array.
On the other hand, just knowing the order is probably not enough
since you need to know offsets/strides, packing, etc.
This extension provides uniform block-based uniform updates.
This level of organization is efficient and requires no further
augmentation as this issue suggests.
RESOLUTION: RESOLVED, no
(27) What is the difference between
MAX_LOGICAL_UNIFORM_BUFFERS and
MAX_COMBINED_UNIFORM_BUFFERS?
MAX_LOGICAL_UNIFORM_BUFFERS is the maximum number of
uniform buffer binding points on the context.
MAX_COMBINED_UNIFORM_BUFFERS is the maximum number of
uniform buffers that any one program can use at one time.
Note, see issue (46) for a related issue with textures.
RESOLUTION: RESOLVED
(28) Should we have versions of GetActiveUniforms and GetActiveUniformBlocks
that return intptr types so a cast is not required.
No. Another extension can add them, and they have no real
utility at this time except causing the app to allocate twice as much
storage to store values that can't exceed 32 bits.
RESOLUTION: RESOLVED, No.
(29) Transform feedback writes primitive information to a buffer object
tightly arranged and in accordance with the size of the attributes
designated for transform feedback (or varyings thereof). If uniform
buffers are to leverage data supplied from the transform feedback
operation, yet uniforms are not guaranteed to be tightly packed, how
can one reasonably use transform feedback to populate uniform
buffers?
DISCUSSION: As it stands, existing implementations pack uniform
definitions on 16 byte boundaries, 4 byte boundaries or are tightly
packed. If this is known for a given implementation, uniform
declarations could of course be made such that they lined up on these
boundaries. However, without a dedicated queryable interface in the GL
C API, there is no way to guarantee the portability of this logic.
RESOLUTION: resolved, compatibility with XFB output is only guaranteed
for vec4 types in a "std140" layout uniform block:
In order to facilitate the read-only nature of uniform and
transform feedback data formatting, we've added to this
specification a uniform buffer "std140" layout qualifier guarantee of
vec4 types being tightly packed. This layout guarantee will provide
portability of applications that wish to use transform feedback in
conjunction with uniform buffers as they can simply rely on this
data arrangement, declaring their uniforms accordingly, to allow
ARB_uniform_buffer_object and EXT_transform_feedback to
interoperate.
(30) Should the "active" keyword in shader text be declared per uniform or
per uniform block ?
Note, this issue is mostly moot, as we've decided to use a
different syntax in the GLSL. Earlier versions of this spec
leveraged the concept of 'active' uniforms from GLSL that were
defined with the initial GLSL API.
The discussion that follows pertains to a feature where the user can
declare uniforms and uniform blocks as active explicitly.
DISCUSSION: Declaring a uniform active has the advantages of simplicity
and little additional spec language to describe behavior. When a
uniform is declared active, all of its members are considered active
(for structs and arrays) and therefore the arrangement of the data in
that uniform can be guaranteed to be consistent. Consistency of this
uniform data arrangement can be used to share the uniform across muliple
programs without worrying about dead code elimination changing the
offsets and strides of uniform data.
Declaring uniform blocks active has some of the advantages that were
primary motivating factors for this specficiation being written.
Namely, that uniforms did not have to be aggregated into structures in
order to update them efficiently. In this case, uniforms don't have to
be aggregated into structs in order to share them easily. Another
advantage is the logical distinction of a group of shared uniforms that
is analogous to how the uniform buffer object, also a shared entity,
that backs them.
If a uniform uniform block is declared active, all uniforms therein are
considered active. It is presumed under this model, that an advisable
usage pattern would be to gather the declaration of shared uniforms of
multiple shaders into an atomic shader source call. Then each
individual shader would carry declarations of uniforms unique to
themselves.
GLSL allows piecewise declaration of uniforms in multiple modules in a
program. Piecewise declaration of shared uniform blocks carries with it
some difficulties because missing pieces can change the layout of the
uniform block.
A) Should we disallow piecewise construction of uniform blocks
declared active by setting a compile time error if this is
attempted ?
RESOLVED: Yes, piecewise construction of uniform blocks will be
allowed.
Proposal for active uniform block demarcation:
Active uniform blocks are declared as followed:
active uniform block foo;
uniform a;
uniform b;
uniform c;
uniform block;
The first uniform block delimiter names the uniform block. The second
uniform block, with no name argument, terminates the "foo" uniform block
and indicates that any subsequent uniform definition will be part of the
default uniform block.
Subsequent declarations referring to uniform block "foo" augment the
contents of the uniform block. These subsequent declarations, of
course, can appear within the same shader or within other shader sources
in the same program.
This aggregation mechanism, and the use of piece-wise definitions of
uniform blocks, has sharing implications.
Considering the following example:
*****************************
PROGRAM A Text:
active uniform block foo;
uniform