summaryrefslogtreecommitdiffstats
path: root/drivers/gles3/storage/mesh_storage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gles3/storage/mesh_storage.cpp')
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp24
1 files changed, 22 insertions, 2 deletions
diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp
index 3213fa3775..88ee749ed6 100644
--- a/drivers/gles3/storage/mesh_storage.cpp
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -217,8 +217,23 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
if (new_surface.vertex_data.size()) {
glGenBuffers(1, &s->vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, s->vertex_buffer);
- GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->vertex_buffer, new_surface.vertex_data.size(), new_surface.vertex_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh vertex buffer");
- s->vertex_buffer_size = new_surface.vertex_data.size();
+ // If we have an uncompressed surface that contains normals, but not tangents, we need to differentiate the array
+ // from a compressed array in the shader. To do so, we allow the the normal to read 4 components out of the buffer
+ // But only give it 2 components per normal. So essentially, each vertex reads the next normal in normal.zw.
+ // This allows us to avoid adding a shader permutation, and avoid passing dummy tangents. Since the stride is kept small
+ // this should still be a net win for bandwidth.
+ // If we do this, then the last normal will read past the end of the array. So we need to pad the array with dummy data.
+ if (!(new_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) && (new_surface.format & RS::ARRAY_FORMAT_NORMAL) && !(new_surface.format & RS::ARRAY_FORMAT_TANGENT)) {
+ // Unfortunately, we need to copy the buffer, which is fine as doing a resize triggers a CoW anyway.
+ Vector<uint8_t> new_vertex_data;
+ new_vertex_data.resize_zeroed(new_surface.vertex_data.size() + sizeof(uint16_t) * 2);
+ memcpy(new_vertex_data.ptrw(), new_surface.vertex_data.ptr(), new_surface.vertex_data.size());
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->vertex_buffer, new_vertex_data.size(), new_vertex_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh vertex buffer");
+ s->vertex_buffer_size = new_vertex_data.size();
+ } else {
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->vertex_buffer, new_surface.vertex_data.size(), new_surface.vertex_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh vertex buffer");
+ s->vertex_buffer_size = new_surface.vertex_data.size();
+ }
}
if (new_surface.attribute_data.size()) {
@@ -461,6 +476,11 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
sd.format = s.format;
if (s.vertex_buffer != 0) {
sd.vertex_data = Utilities::buffer_get_data(GL_ARRAY_BUFFER, s.vertex_buffer, s.vertex_buffer_size);
+
+ // When using an uncompressed buffer with normals, but without tangents, we have to trim the padding.
+ if (!(s.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) && (s.format & RS::ARRAY_FORMAT_NORMAL) && !(s.format & RS::ARRAY_FORMAT_TANGENT)) {
+ sd.vertex_data.resize(sd.vertex_data.size() - sizeof(uint16_t) * 2);
+ }
}
if (s.attribute_buffer != 0) {