Skip to content

Commit

Permalink
Split Vertex Position and Attribute Streams
Browse files Browse the repository at this point in the history
Implemented splitting of vertex positions and attributes in the vertex
buffer

Positions are sequential at the start of the buffer, followed by the
additional attributes which are interleaved

Made a project setting which enables/disabled the buffer formatting
throughout the project

Implemented in both GLES2 and GLES3

This improves performance particularly on tile-based GPUs as well as
cache performance for something like shadow mapping which only needs
position data

Updated Docs and Project Setting
  • Loading branch information
The-O-King committed Jul 19, 2021
1 parent 9636dea commit 7f8487a
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 67 deletions.
3 changes: 3 additions & 0 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1187,6 +1187,9 @@
<member name="rendering/lossless_compression/webp_compression_level" type="int" setter="" getter="" default="2">
The default compression level for lossless WebP. Higher levels result in smaller files at the cost of compression speed. Decompression speed is mostly unaffected by the compression level. Supported values are 0 to 9. Note that compression levels above 6 are very slow and offer very little savings.
</member>
<member name="rendering/mesh_storage/split_stream" type="bool" setter="" getter="" default="false">
On import, mesh vertex data will be split into two streams within a single vertex buffer, one for position data and the other for interleaved attributes data. Recommended to be enabled if targeting mobile devices. Requires manual reimport of meshes after toggling.
</member>
<member name="rendering/quality/depth/hdr" type="bool" setter="" getter="" default="true">
If [code]true[/code], allocates the main framebuffer with high dynamic range. High dynamic range allows the use of [Color] values greater than 1.
[b]Note:[/b] Only available on the GLES3 backend.
Expand Down
58 changes: 37 additions & 21 deletions drivers/gles2/rasterizer_storage_gles2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2240,10 +2240,13 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
}

//bool has_morph = p_blend_shapes.size();
bool use_split_stream = GLOBAL_GET("rendering/mesh_storage/split_stream");

Surface::Attrib attribs[VS::ARRAY_MAX];

int stride = 0;
int attributes_base_offset = 0;
int attributes_stride = 0;
int positions_stride = 0;
bool uses_half_float = false;

for (int i = 0; i < VS::ARRAY_MAX; i++) {
Expand All @@ -2256,7 +2259,7 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
}

attribs[i].enabled = true;
attribs[i].offset = stride;
attribs[i].offset = attributes_base_offset + attributes_stride;
attribs[i].integer = false;

switch (i) {
Expand All @@ -2269,26 +2272,31 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:

if (p_format & VS::ARRAY_COMPRESS_VERTEX) {
attribs[i].type = _GL_HALF_FLOAT_OES;
stride += attribs[i].size * 2;
uses_half_float = true;
positions_stride += attribs[i].size * 2;
} else {
attribs[i].type = GL_FLOAT;
stride += attribs[i].size * 4;
positions_stride += attribs[i].size * 4;
}

attribs[i].normalized = GL_FALSE;

if (use_split_stream) {
attributes_base_offset = positions_stride * p_vertex_count;
} else {
attributes_base_offset = positions_stride;
}

} break;
case VS::ARRAY_NORMAL: {
attribs[i].size = 3;

if (p_format & VS::ARRAY_COMPRESS_NORMAL) {
attribs[i].type = GL_BYTE;
stride += 4; //pad extra byte
attributes_stride += 4; //pad extra byte
attribs[i].normalized = GL_TRUE;
} else {
attribs[i].type = GL_FLOAT;
stride += 12;
attributes_stride += 12;
attribs[i].normalized = GL_FALSE;
}

Expand All @@ -2298,11 +2306,11 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:

if (p_format & VS::ARRAY_COMPRESS_TANGENT) {
attribs[i].type = GL_BYTE;
stride += 4;
attributes_stride += 4;
attribs[i].normalized = GL_TRUE;
} else {
attribs[i].type = GL_FLOAT;
stride += 16;
attributes_stride += 16;
attribs[i].normalized = GL_FALSE;
}

Expand All @@ -2312,11 +2320,11 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:

if (p_format & VS::ARRAY_COMPRESS_COLOR) {
attribs[i].type = GL_UNSIGNED_BYTE;
stride += 4;
attributes_stride += 4;
attribs[i].normalized = GL_TRUE;
} else {
attribs[i].type = GL_FLOAT;
stride += 16;
attributes_stride += 16;
attribs[i].normalized = GL_FALSE;
}

Expand All @@ -2326,11 +2334,11 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:

if (p_format & VS::ARRAY_COMPRESS_TEX_UV) {
attribs[i].type = _GL_HALF_FLOAT_OES;
stride += 4;
attributes_stride += 4;
uses_half_float = true;
} else {
attribs[i].type = GL_FLOAT;
stride += 8;
attributes_stride += 8;
}

attribs[i].normalized = GL_FALSE;
Expand All @@ -2341,11 +2349,11 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:

if (p_format & VS::ARRAY_COMPRESS_TEX_UV2) {
attribs[i].type = _GL_HALF_FLOAT_OES;
stride += 4;
attributes_stride += 4;
uses_half_float = true;
} else {
attribs[i].type = GL_FLOAT;
stride += 8;
attributes_stride += 8;
}
attribs[i].normalized = GL_FALSE;

Expand All @@ -2355,10 +2363,10 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:

if (p_format & VS::ARRAY_FLAG_USE_16_BIT_BONES) {
attribs[i].type = GL_UNSIGNED_SHORT;
stride += 8;
attributes_stride += 8;
} else {
attribs[i].type = GL_UNSIGNED_BYTE;
stride += 4;
attributes_stride += 4;
}

attribs[i].normalized = GL_FALSE;
Expand All @@ -2370,11 +2378,11 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:

if (p_format & VS::ARRAY_COMPRESS_WEIGHTS) {
attribs[i].type = GL_UNSIGNED_SHORT;
stride += 8;
attributes_stride += 8;
attribs[i].normalized = GL_TRUE;
} else {
attribs[i].type = GL_FLOAT;
stride += 16;
attributes_stride += 16;
attribs[i].normalized = GL_FALSE;
}

Expand All @@ -2396,13 +2404,21 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
}
}

for (int i = 0; i < VS::ARRAY_MAX - 1; i++) {
attribs[i].stride = stride;
if (use_split_stream) {
attribs[VS::ARRAY_VERTEX].stride = positions_stride;
for (int i = 1; i < VS::ARRAY_MAX - 1; i++) {
attribs[i].stride = attributes_stride;
}
} else {
for (int i = 0; i < VS::ARRAY_MAX - 1; i++) {
attribs[i].stride = positions_stride + attributes_stride;
}
}

//validate sizes
PoolVector<uint8_t> array = p_array;

int stride = positions_stride + attributes_stride;
int array_size = stride * p_vertex_count;
int index_array_size = 0;
if (array.size() != array_size && array.size() + p_vertex_count * 2 == array_size) {
Expand Down
57 changes: 37 additions & 20 deletions drivers/gles3/rasterizer_storage_gles3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3349,10 +3349,13 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
}

//bool has_morph = p_blend_shapes.size();
bool use_split_stream = GLOBAL_GET("rendering/mesh_storage/split_stream");

Surface::Attrib attribs[VS::ARRAY_MAX];

int stride = 0;
int attributes_base_offset = 0;
int attributes_stride = 0;
int positions_stride = 0;

for (int i = 0; i < VS::ARRAY_MAX; i++) {
attribs[i].index = i;
Expand All @@ -3364,7 +3367,7 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
}

attribs[i].enabled = true;
attribs[i].offset = stride;
attribs[i].offset = attributes_base_offset + attributes_stride;
attribs[i].integer = false;

switch (i) {
Expand All @@ -3377,25 +3380,31 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:

if (p_format & VS::ARRAY_COMPRESS_VERTEX) {
attribs[i].type = GL_HALF_FLOAT;
stride += attribs[i].size * 2;
positions_stride += attribs[i].size * 2;
} else {
attribs[i].type = GL_FLOAT;
stride += attribs[i].size * 4;
positions_stride += attribs[i].size * 4;
}

attribs[i].normalized = GL_FALSE;

if (use_split_stream) {
attributes_base_offset = positions_stride * p_vertex_count;
} else {
attributes_base_offset = positions_stride;
}

} break;
case VS::ARRAY_NORMAL: {
attribs[i].size = 3;

if (p_format & VS::ARRAY_COMPRESS_NORMAL) {
attribs[i].type = GL_BYTE;
stride += 4; //pad extra byte
attributes_stride += 4; //pad extra byte
attribs[i].normalized = GL_TRUE;
} else {
attribs[i].type = GL_FLOAT;
stride += 12;
attributes_stride += 12;
attribs[i].normalized = GL_FALSE;
}

Expand All @@ -3405,11 +3414,11 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:

if (p_format & VS::ARRAY_COMPRESS_TANGENT) {
attribs[i].type = GL_BYTE;
stride += 4;
attributes_stride += 4;
attribs[i].normalized = GL_TRUE;
} else {
attribs[i].type = GL_FLOAT;
stride += 16;
attributes_stride += 16;
attribs[i].normalized = GL_FALSE;
}

Expand All @@ -3419,11 +3428,11 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:

if (p_format & VS::ARRAY_COMPRESS_COLOR) {
attribs[i].type = GL_UNSIGNED_BYTE;
stride += 4;
attributes_stride += 4;
attribs[i].normalized = GL_TRUE;
} else {
attribs[i].type = GL_FLOAT;
stride += 16;
attributes_stride += 16;
attribs[i].normalized = GL_FALSE;
}

Expand All @@ -3433,10 +3442,10 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:

if (p_format & VS::ARRAY_COMPRESS_TEX_UV) {
attribs[i].type = GL_HALF_FLOAT;
stride += 4;
attributes_stride += 4;
} else {
attribs[i].type = GL_FLOAT;
stride += 8;
attributes_stride += 8;
}

attribs[i].normalized = GL_FALSE;
Expand All @@ -3447,10 +3456,10 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:

if (p_format & VS::ARRAY_COMPRESS_TEX_UV2) {
attribs[i].type = GL_HALF_FLOAT;
stride += 4;
attributes_stride += 4;
} else {
attribs[i].type = GL_FLOAT;
stride += 8;
attributes_stride += 8;
}
attribs[i].normalized = GL_FALSE;

Expand All @@ -3460,10 +3469,10 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:

if (p_format & VS::ARRAY_FLAG_USE_16_BIT_BONES) {
attribs[i].type = GL_UNSIGNED_SHORT;
stride += 8;
attributes_stride += 8;
} else {
attribs[i].type = GL_UNSIGNED_BYTE;
stride += 4;
attributes_stride += 4;
}

attribs[i].normalized = GL_FALSE;
Expand All @@ -3475,11 +3484,11 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:

if (p_format & VS::ARRAY_COMPRESS_WEIGHTS) {
attribs[i].type = GL_UNSIGNED_SHORT;
stride += 8;
attributes_stride += 8;
attribs[i].normalized = GL_TRUE;
} else {
attribs[i].type = GL_FLOAT;
stride += 16;
attributes_stride += 16;
attribs[i].normalized = GL_FALSE;
}

Expand All @@ -3501,12 +3510,20 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
}
}

for (int i = 0; i < VS::ARRAY_MAX - 1; i++) {
attribs[i].stride = stride;
if (use_split_stream) {
attribs[VS::ARRAY_VERTEX].stride = positions_stride;
for (int i = 1; i < VS::ARRAY_MAX - 1; i++) {
attribs[i].stride = attributes_stride;
}
} else {
for (int i = 0; i < VS::ARRAY_MAX - 1; i++) {
attribs[i].stride = positions_stride + attributes_stride;
}
}

//validate sizes

int stride = positions_stride + attributes_stride;
int array_size = stride * p_vertex_count;
int index_array_size = 0;
if (array.size() != array_size && array.size() + p_vertex_count * 2 == array_size) {
Expand Down
Loading

0 comments on commit 7f8487a

Please sign in to comment.