Add padding to normal attribute in Compatibility renderer to match the RD renderers

This commit is contained in:
clayjohn 2023-10-24 22:32:34 +02:00
parent e8d57afaec
commit a88e519f18
2 changed files with 22 additions and 3 deletions

View file

@ -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) {

View file

@ -591,7 +591,6 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer);
// 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)) {
Vector<uint8_t> new_vertex_data;
sd.vertex_data.resize(sd.vertex_data.size() - sizeof(uint16_t) * 2);
}
}