You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
327 lines
8.4 KiB
327 lines
8.4 KiB
2 months ago
|
#+TITLE: Memory Layout
|
||
|
#+AUTHOR: Riyyi
|
||
|
#+LANGUAGE: en
|
||
|
#+OPTIONS: toc:nil
|
||
|
|
||
|
This chapter is about the memory layout of interface blocks in GLSL.
|
||
|
An interface block is a group of variables, a struct if you will.
|
||
|
|
||
|
There are 4 types of memory layouts that can be used, where the first two aren't
|
||
|
widely used as those are implementation dependent and require querying the
|
||
|
OpenGL API for memory offsets.
|
||
|
|
||
|
- packed
|
||
|
- shared
|
||
|
- std140
|
||
|
- std430
|
||
|
|
||
|
** std140
|
||
|
|
||
|
This type is usable in Uniform Buffer Objects (=UBO=) and Shader Storage Buffer
|
||
|
Objects (=SSBO=).
|
||
|
|
||
|
** std430
|
||
|
|
||
|
This type is only usable in Shader Storage Buffer Objects (=SSBO=).
|
||
|
|
||
|
Main points:
|
||
|
- Memory is organized into chunks.
|
||
|
- One chunk has 4 slots, 4 bytes per slot.
|
||
|
- Can't fit? Move to next chunk.
|
||
|
- An interface block is at least the size of 1 chunk.
|
||
|
|
||
|
The rules:
|
||
|
|
||
|
- Scalar =bool=, =int=, =uint=, =float=, and =double=
|
||
|
|
||
|
#+BEGIN_SRC
|
||
|
Both the size and alignment are the size of the scalar in basic machine types
|
||
|
(e.g., sizeof(GLfloat))
|
||
|
#+END_SRC
|
||
|
|
||
|
- Two-componment Vectors (e.g., =ivec2=)
|
||
|
|
||
|
#+BEGIN_SRC
|
||
|
Both the size and alignment are twice the size of the underlying scalar type.
|
||
|
#+END_SRC
|
||
|
|
||
|
- Three-component Vectors (e.g., =vec3=) and Four-component Vectors (e.g., =vec4=)
|
||
|
|
||
|
#+BEGIN_SRC
|
||
|
Both the size and alignment are four times the size of the scalar type. However,
|
||
|
this is only true when the member is part of an array or nested structure
|
||
|
#+END_SRC
|
||
|
|
||
|
- Array of Scalars and Vectors
|
||
|
|
||
|
#+BEGIN_SRC
|
||
|
The size of each element in the array will be the same size of the element type,
|
||
|
where three-component vectors are rounded up to the size four-component
|
||
|
vectors. This is also the array's alignment. The array's size will be the
|
||
|
element size times the number of elements.
|
||
|
#+END_SRC
|
||
|
|
||
|
- Column-major matrix or an array of column-major matrices of size C columns and R rows
|
||
|
|
||
|
#+BEGIN_SRC
|
||
|
Same layout as an array of N vectors each with R components, where N is the
|
||
|
total number of columns present.
|
||
|
#+END_SRC
|
||
|
|
||
|
- Row-major matrix or an array of row-major matrices of size R rows and C columns
|
||
|
|
||
|
#+BEGIN_SRC
|
||
|
Same layout as an array of N vectors each with C components, where N is the
|
||
|
total number of rows present.
|
||
|
#+END_SRC
|
||
|
|
||
|
Both =GLSL= and the =GLM= math library we're using have column-major matrices!
|
||
|
|
||
|
- Single-structure definition or an array of structures
|
||
|
|
||
|
#+BEGIN_SRC
|
||
|
Structure alignment is the same as the alignment of the biggest structure
|
||
|
member, where three-component vectors are rounded up to the size of
|
||
|
four-component vectors. Each structure will start on this alignment, and its
|
||
|
size will be the space neeeded by its members, according to the previous rules,
|
||
|
rounded up to a multiple of the structure alignment.
|
||
|
#+END_SRC
|
||
|
|
||
|
All of the examples described in the following segments are verified by querying
|
||
|
the OpenGL API.
|
||
|
|
||
|
*** Scalars
|
||
|
|
||
|
These types take up 1 (or 2 with =double=) slot and can appear after anything.
|
||
|
In the example below you can see that due to the larger alignment, the ~double~
|
||
|
is forced to the next chunk.
|
||
|
|
||
|
#+BEGIN_SRC glsl
|
||
|
// Var Size Alignment Offset
|
||
|
bool a; // 4 4 0
|
||
|
int b; // 4 4 4
|
||
|
uint c; // 4 4 8
|
||
|
double d; // 8 8 16
|
||
|
float e; // 4 4 24
|
||
|
#+END_SRC
|
||
|
|
||
|
#+BEGIN_SRC
|
||
|
Chunks:
|
||
|
[a][b][c][ ] #1
|
||
|
[d][d][e][ ] #2
|
||
|
#+END_SRC
|
||
|
|
||
|
*** Two-component Vectors
|
||
|
|
||
|
**** Float
|
||
|
|
||
|
A Vec2 takes up 2 slots, so will be in the first or last half of a chunk.
|
||
|
|
||
|
#+BEGIN_SRC glsl
|
||
|
// Var Size Alignment Offset
|
||
|
vec2 a; // 8 8 0
|
||
|
float b; // 4 4 8
|
||
|
#+END_SRC
|
||
|
|
||
|
#+BEGIN_SRC
|
||
|
Chunks:
|
||
|
[a][a][b][ ] #1
|
||
|
#+END_SRC
|
||
|
|
||
|
#+BEGIN_SRC glsl
|
||
|
// Var Size Alignment Offset
|
||
|
float a; // 4 4 0
|
||
|
vec2 b; // 8 8 8
|
||
|
#+END_SRC
|
||
|
|
||
|
#+BEGIN_SRC
|
||
|
Chunks:
|
||
|
[a][ ][b][b] #1
|
||
|
#+END_SRC
|
||
|
|
||
|
**** Double
|
||
|
|
||
|
#+BEGIN_SRC glsl
|
||
|
// Var Size Alignment Offset
|
||
|
float a; // 4 4 0
|
||
|
dvec2 b; // 16 16 16
|
||
|
#+END_SRC
|
||
|
|
||
|
#+BEGIN_SRC
|
||
|
Chunks:
|
||
|
[a][ ][ ][ ] #1
|
||
|
[b][b][b][b] #2
|
||
|
#+END_SRC
|
||
|
|
||
|
*** Three-component and Four-component Vectors
|
||
|
|
||
|
A Vec3 takes up 3 slots, the alignment is 4 slots so only fits at the start of a
|
||
|
chunk.
|
||
|
|
||
|
#+BEGIN_SRC glsl
|
||
|
// Var Size Alignment Offset
|
||
|
vec3 a; // 12 16 0
|
||
|
float b; // 4 4 12
|
||
|
vec4 c; // 16 16 16
|
||
|
#+END_SRC
|
||
|
|
||
|
#+BEGIN_SRC
|
||
|
Chunks:
|
||
|
[a][a][a][b] #1
|
||
|
[c][c][c][c] #2
|
||
|
#+END_SRC
|
||
|
|
||
|
#+BEGIN_SRC glsl
|
||
|
// Var Size Alignment Offset
|
||
|
float a; // 4 4 0
|
||
|
vec3 b; // 12 16 16
|
||
|
vec4 c; // 16 16 32
|
||
|
#+END_SRC
|
||
|
|
||
|
#+BEGIN_SRC
|
||
|
Chunks:
|
||
|
[a][ ][ ][ ] #1
|
||
|
[b][b][b][ ] #2
|
||
|
[c][c][c][c] #3
|
||
|
#+END_SRC
|
||
|
|
||
|
*** Array of Scalars and Vectors
|
||
|
|
||
|
#+BEGIN_SRC glsl
|
||
|
// Var Size Alignment Offset
|
||
|
float[3] a; // 12 4 0
|
||
|
float b; // 4 4 12
|
||
|
float c; // 4 4 16
|
||
|
float[3] d; // 12 4 20
|
||
|
#+END_SRC
|
||
|
|
||
|
#+BEGIN_SRC
|
||
|
Chunks:
|
||
|
[a][a][a][b] #1
|
||
|
[c][d][d][d] #1
|
||
|
#+END_SRC
|
||
|
|
||
|
*Note* the optimizations in the alignment and strides are not applicable to
|
||
|
~vec3~ elements, these remain unchanged from =std140=.
|
||
|
|
||
|
#+BEGIN_SRC glsl
|
||
|
// Var Size Alignment Offset
|
||
|
float a; // 4 4 0
|
||
|
vec3[3] b; // 48 16 16
|
||
|
float c; // 4 4 64
|
||
|
float d; // 4 4 68
|
||
|
vec2[2] e; // 16 8 72
|
||
|
float f; // 4 4 88
|
||
|
#+END_SRC
|
||
|
|
||
|
#+BEGIN_SRC
|
||
|
Chunks:
|
||
|
[a][ ][ ][ ] #1, offset: 0
|
||
|
[b][b][b][ ] #2, offset: 16
|
||
|
[b][b][b][ ] #3, offset: 32
|
||
|
[b][b][b][ ] #4, offset: 48
|
||
|
[c][d][e][e] #5, offset: 64
|
||
|
[e][e][f][ ] #6, offset: 80
|
||
|
#+END_SRC
|
||
|
|
||
|
*Note* the offset needs to be a multiple of the alignment, forcing an entire
|
||
|
empty chunk in the example below.
|
||
|
|
||
|
#+BEGIN_SRC glsl
|
||
|
// Var Size Alignment Offset
|
||
|
float a; // 4 4 0
|
||
|
dvec2[2] b; // 32 16 16
|
||
|
dvec3[2] c; // 64 32 64
|
||
|
float d; // 4 4 128
|
||
|
#+END_SRC
|
||
|
|
||
|
#+BEGIN_SRC
|
||
|
Chunks:
|
||
|
[a][ ][ ][ ] #1, offset: 0
|
||
|
[d][d][d][d] #2, offset: 16
|
||
|
[d][d][d][d] #3, offset: 32
|
||
|
[ ][ ][ ][ ] #4, offset: 48
|
||
|
[c][c][c][c] #5, offset: 64
|
||
|
[c][c][ ][ ] #6, offset: 80
|
||
|
[c][c][c][c] #7, offset: 96
|
||
|
[c][c][ ][ ] #8, offset: 112
|
||
|
[d][ ][ ][ ] #9, offset: 128
|
||
|
#+END_SRC
|
||
|
|
||
|
*** Matrices
|
||
|
|
||
|
Alignment is the same as an array of 1 “row” of the matrix.
|
||
|
No padding between the “rows” of a matrix, but will pad at the end.
|
||
|
|
||
|
#+BEGIN_SRC glsl
|
||
|
// Var Size Alignment Offset
|
||
|
float a; // 4 4 0
|
||
|
mat2 b; // 16 8 8
|
||
|
vec2 c; // 4 4 24
|
||
|
float d; // 4 4 32
|
||
|
mat2[2] e; // 32 8 40
|
||
|
float f; // 4 4 72
|
||
|
#+END_SRC
|
||
|
|
||
|
#+BEGIN_SRC
|
||
|
Chunks:
|
||
|
[a][ ][b][b] #1, offset: 0
|
||
|
[b][b][c][c] #2, offset: 16
|
||
|
[d][ ][e][e] #3, offset: 32
|
||
|
[e][e][e][e] #4, offset: 48
|
||
|
[e][e][f][ ] #5, offset: 64
|
||
|
#+END_SRC
|
||
|
|
||
|
TODO: Add more examples
|
||
|
|
||
|
*** Structs
|
||
|
|
||
|
Alignment same as biggest struct member. Size is the size of all members,
|
||
|
rounded up to a multiple of the alignment.
|
||
|
|
||
|
In the example below you can see that the ~Stuff~ struct, including padding
|
||
|
between members, is 20 bytes in size. To make that a multiple of the alignment
|
||
|
additional padding needs to be put at the end, to make the total size 24 bytes.
|
||
|
|
||
|
Each element in the array of structs will apply the alignment again, as seen
|
||
|
with ~Stuff[1].a~.
|
||
|
|
||
|
#+BEGIN_SRC glsl
|
||
|
struct Stuff {
|
||
|
float a;
|
||
|
vec2 b;
|
||
|
float c;
|
||
|
};
|
||
|
|
||
|
// Var Size Alignment Offset
|
||
|
Stuff a; // 20 8
|
||
|
a.a; // 4 4 0
|
||
|
a.b; // 8 8 8
|
||
|
a.c; // 4 4 16
|
||
|
float b; // 4 4 24
|
||
|
Stuff[2] c; // 44 8
|
||
|
c.a; // 4 4 32
|
||
|
c.b; // 8 8 40
|
||
|
c.c; // 4 4 48
|
||
|
float d; // 4 4 80
|
||
|
#+END_SRC
|
||
|
|
||
|
#+BEGIN_SRC
|
||
|
Chunks:
|
||
|
[a][ ][a][a] #1, offset: 0
|
||
|
[a][ ][b][ ] #2, offset: 16
|
||
|
[c][ ][c][c] #3, offset: 32
|
||
|
[c][ ][c][ ] #4, offset: 48
|
||
|
[c][c][c][ ] #5, offset: 64
|
||
|
[d][ ][ ][ ] #6, offset: 80
|
||
|
#+END_SRC
|
||
|
|
||
|
TODO: Add more examples
|
||
|
|
||
|
* References
|
||
|
|
||
|
- https://learnopengl.com/Advanced-OpenGL/Advanced-GLSL
|
||
|
- https://www.khronos.org/opengl/wiki/Interface_Block_(GLSL)#Memory_layout
|
||
|
- [[https://www.oreilly.com/library/view/opengl-programming-guide/9780132748445/app09lev1sec2.html][The std140 Layout Rules]]
|
||
|
- [[https://www.youtube.com/watch?v=JPvbRko9lBg][(YouTube) WebGL 2: Uniform Buffer Objects]]
|