summaryrefslogtreecommitdiffstats
path: root/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp')
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp222
1 files changed, 150 insertions, 72 deletions
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
index cb7eb3cd59..14605b308e 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
@@ -270,10 +270,10 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
uint32_t skin_stride = 0;
for (int i = 0; i < RS::ARRAY_WEIGHTS; i++) {
- if ((p_surface.format & (1 << i))) {
+ if ((p_surface.format & (1ULL << i))) {
switch (i) {
case RS::ARRAY_VERTEX: {
- if (p_surface.format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
+ if ((p_surface.format & RS::ARRAY_FLAG_USE_2D_VERTICES) || (p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
stride += sizeof(float) * 2;
} else {
stride += sizeof(float) * 3;
@@ -281,22 +281,31 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
} break;
case RS::ARRAY_NORMAL: {
- stride += sizeof(int32_t);
+ stride += sizeof(uint16_t) * 2;
} break;
case RS::ARRAY_TANGENT: {
- stride += sizeof(int32_t);
-
+ if (!(p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
+ stride += sizeof(uint16_t) * 2;
+ }
} break;
case RS::ARRAY_COLOR: {
attrib_stride += sizeof(uint32_t);
} break;
case RS::ARRAY_TEX_UV: {
- attrib_stride += sizeof(float) * 2;
+ if (p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
+ attrib_stride += sizeof(uint16_t) * 2;
+ } else {
+ attrib_stride += sizeof(float) * 2;
+ }
} break;
case RS::ARRAY_TEX_UV2: {
- attrib_stride += sizeof(float) * 2;
+ if (p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
+ attrib_stride += sizeof(uint16_t) * 2;
+ } else {
+ attrib_stride += sizeof(float) * 2;
+ }
} break;
case RS::ARRAY_CUSTOM0:
@@ -338,59 +347,96 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
#endif
- Mesh::Surface *s = memnew(Mesh::Surface);
+ uint64_t surface_version = p_surface.format & (uint64_t(RS::ARRAY_FLAG_FORMAT_VERSION_MASK) << RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT);
+ RS::SurfaceData new_surface = p_surface;
+#ifdef DISABLE_DEPRECATED
- s->format = p_surface.format;
- s->primitive = p_surface.primitive;
+ ERR_FAIL_COND_MSG(surface_version != RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION, "Surface version provided (" + itos(int(surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT)) + ") does not match current version (" + itos(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) + ")");
- bool use_as_storage = (p_surface.skin_data.size() || mesh->blend_shape_count > 0);
+#else
- if (p_surface.vertex_data.size()) {
- s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.vertex_data.size(), p_surface.vertex_data, use_as_storage);
- s->vertex_buffer_size = p_surface.vertex_data.size();
+ if (surface_version != uint64_t(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION)) {
+ RS::_fix_surface_compatibility(new_surface);
+ surface_version = new_surface.format & (RS::ARRAY_FLAG_FORMAT_VERSION_MASK << RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT);
+ ERR_FAIL_COND_MSG(surface_version != RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION,
+ "Surface version provided (" +
+ itos((surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) +
+ ") does not match current version (" +
+ itos((RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) +
+ ")");
}
+#endif
- if (p_surface.attribute_data.size()) {
- s->attribute_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.attribute_data.size(), p_surface.attribute_data);
+ Mesh::Surface *s = memnew(Mesh::Surface);
+
+ s->format = new_surface.format;
+ s->primitive = new_surface.primitive;
+
+ bool use_as_storage = (new_surface.skin_data.size() || mesh->blend_shape_count > 0);
+
+ if (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());
+ s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(new_vertex_data.size(), new_vertex_data, use_as_storage);
+ s->vertex_buffer_size = new_vertex_data.size();
+ } else {
+ s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(new_surface.vertex_data.size(), new_surface.vertex_data, use_as_storage);
+ s->vertex_buffer_size = new_surface.vertex_data.size();
+ }
+ }
+
+ if (new_surface.attribute_data.size()) {
+ s->attribute_buffer = RD::get_singleton()->vertex_buffer_create(new_surface.attribute_data.size(), new_surface.attribute_data);
}
- if (p_surface.skin_data.size()) {
- s->skin_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.skin_data.size(), p_surface.skin_data, use_as_storage);
- s->skin_buffer_size = p_surface.skin_data.size();
+ if (new_surface.skin_data.size()) {
+ s->skin_buffer = RD::get_singleton()->vertex_buffer_create(new_surface.skin_data.size(), new_surface.skin_data, use_as_storage);
+ s->skin_buffer_size = new_surface.skin_data.size();
}
- s->vertex_count = p_surface.vertex_count;
+ s->vertex_count = new_surface.vertex_count;
- if (p_surface.format & RS::ARRAY_FORMAT_BONES) {
+ if (new_surface.format & RS::ARRAY_FORMAT_BONES) {
mesh->has_bone_weights = true;
}
- if (p_surface.index_count) {
- bool is_index_16 = p_surface.vertex_count <= 65536 && p_surface.vertex_count > 0;
+ if (new_surface.index_count) {
+ bool is_index_16 = new_surface.vertex_count <= 65536 && new_surface.vertex_count > 0;
- s->index_buffer = RD::get_singleton()->index_buffer_create(p_surface.index_count, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, p_surface.index_data, false);
- s->index_count = p_surface.index_count;
+ s->index_buffer = RD::get_singleton()->index_buffer_create(new_surface.index_count, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, new_surface.index_data, false);
+ s->index_count = new_surface.index_count;
s->index_array = RD::get_singleton()->index_array_create(s->index_buffer, 0, s->index_count);
- if (p_surface.lods.size()) {
- s->lods = memnew_arr(Mesh::Surface::LOD, p_surface.lods.size());
- s->lod_count = p_surface.lods.size();
+ if (new_surface.lods.size()) {
+ s->lods = memnew_arr(Mesh::Surface::LOD, new_surface.lods.size());
+ s->lod_count = new_surface.lods.size();
- for (int i = 0; i < p_surface.lods.size(); i++) {
- uint32_t indices = p_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4);
- s->lods[i].index_buffer = RD::get_singleton()->index_buffer_create(indices, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, p_surface.lods[i].index_data);
+ for (int i = 0; i < new_surface.lods.size(); i++) {
+ uint32_t indices = new_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4);
+ s->lods[i].index_buffer = RD::get_singleton()->index_buffer_create(indices, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, new_surface.lods[i].index_data);
s->lods[i].index_array = RD::get_singleton()->index_array_create(s->lods[i].index_buffer, 0, indices);
- s->lods[i].edge_length = p_surface.lods[i].edge_length;
+ s->lods[i].edge_length = new_surface.lods[i].edge_length;
s->lods[i].index_count = indices;
}
}
}
- ERR_FAIL_COND_MSG(!p_surface.index_count && !p_surface.vertex_count, "Meshes must contain a vertex array, an index array, or both");
+ ERR_FAIL_COND_MSG(!new_surface.index_count && !new_surface.vertex_count, "Meshes must contain a vertex array, an index array, or both");
- s->aabb = p_surface.aabb;
- s->bone_aabbs = p_surface.bone_aabbs; //only really useful for returning them.
+ s->aabb = new_surface.aabb;
+ s->bone_aabbs = new_surface.bone_aabbs; //only really useful for returning them.
+
+ s->uv_scale = new_surface.uv_scale;
if (mesh->blend_shape_count > 0) {
- s->blend_shape_buffer = RD::get_singleton()->storage_buffer_create(p_surface.blend_shape_data.size(), p_surface.blend_shape_data);
+ s->blend_shape_buffer = RD::get_singleton()->storage_buffer_create(new_surface.blend_shape_data.size(), new_surface.blend_shape_data);
}
if (use_as_storage) {
@@ -433,13 +479,13 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
}
if (mesh->surface_count == 0) {
- mesh->aabb = p_surface.aabb;
+ mesh->aabb = new_surface.aabb;
} else {
- mesh->aabb.merge_with(p_surface.aabb);
+ mesh->aabb.merge_with(new_surface.aabb);
}
mesh->skeleton_aabb_version = 0;
- s->material = p_surface.material;
+ s->material = new_surface.material;
mesh->surfaces = (Mesh::Surface **)memrealloc(mesh->surfaces, sizeof(Mesh::Surface *) * (mesh->surface_count + 1));
mesh->surfaces[mesh->surface_count] = s;
@@ -545,6 +591,11 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
sd.format = s.format;
if (s.vertex_buffer.is_valid()) {
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);
+ }
}
if (s.attribute_buffer.is_valid()) {
sd.attribute_data = RD::get_singleton()->buffer_get_data(s.attribute_buffer);
@@ -560,6 +611,7 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
sd.index_data = RD::get_singleton()->buffer_get_data(s.index_buffer);
}
sd.aabb = s.aabb;
+ sd.uv_scale = s.uv_scale;
for (uint32_t i = 0; i < s.lod_count; i++) {
RS::SurfaceData::LOD lod;
lod.edge_length = s.lods[i].edge_length;
@@ -1016,8 +1068,10 @@ void MeshStorage::update_mesh_instances() {
push_constant.has_skeleton = sk != nullptr && sk->use_2d == array_is_2d && (mi->mesh->surfaces[i]->format & RS::ARRAY_FORMAT_BONES);
push_constant.has_blend_shape = mi->mesh->blend_shape_count > 0;
+ push_constant.normal_tangent_stride = (push_constant.has_normal ? 1 : 0) + (push_constant.has_tangent ? 1 : 0);
+
push_constant.vertex_count = mi->mesh->surfaces[i]->vertex_count;
- push_constant.vertex_stride = (mi->mesh->surfaces[i]->vertex_buffer_size / mi->mesh->surfaces[i]->vertex_count) / 4;
+ push_constant.vertex_stride = ((mi->mesh->surfaces[i]->vertex_buffer_size / mi->mesh->surfaces[i]->vertex_count) / 4) - push_constant.normal_tangent_stride;
push_constant.skin_stride = (mi->mesh->surfaces[i]->skin_buffer_size / mi->mesh->surfaces[i]->vertex_count) / 4;
push_constant.skin_weight_offset = (mi->mesh->surfaces[i]->format & RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 4 : 2;
@@ -1042,7 +1096,6 @@ void MeshStorage::update_mesh_instances() {
push_constant.blend_shape_count = mi->mesh->blend_shape_count;
push_constant.normalized_blend_shapes = mi->mesh->blend_shape_mode == RS::BLEND_SHAPE_MODE_NORMALIZED;
- push_constant.pad0 = 0;
push_constant.pad1 = 0;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SkeletonShader::PushConstant));
@@ -1061,11 +1114,13 @@ void MeshStorage::update_mesh_instances() {
RD::get_singleton()->compute_list_end();
}
-void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis, uint32_t p_current_buffer, uint32_t p_previous_buffer) {
+void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis, uint32_t p_current_buffer, uint32_t p_previous_buffer) {
Vector<RD::VertexAttribute> attributes;
Vector<RID> buffers;
+ Vector<uint64_t> offsets;
- uint32_t stride = 0;
+ uint32_t position_stride = 0;
+ uint32_t normal_tangent_stride = 0;
uint32_t attribute_stride = 0;
uint32_t skin_stride = 0;
@@ -1073,8 +1128,9 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
RD::VertexAttribute vd;
RID buffer;
vd.location = i;
+ uint64_t offset = 0;
- if (!(s->format & (1 << i))) {
+ if (!(s->format & (1ULL << i))) {
// Not supplied by surface, use default value
buffer = mesh_default_rd_buffers[i];
vd.stride = 0;
@@ -1123,14 +1179,19 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
switch (i) {
case RS::ARRAY_VERTEX: {
- vd.offset = stride;
+ vd.offset = position_stride;
if (s->format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
- stride += sizeof(float) * 2;
+ position_stride = sizeof(float) * 2;
} else {
- vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
- stride += sizeof(float) * 3;
+ if (!mis && (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
+ vd.format = RD::DATA_FORMAT_R16G16B16A16_UNORM;
+ position_stride = sizeof(uint16_t) * 4;
+ } else {
+ vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
+ position_stride = sizeof(float) * 3;
+ }
}
if (mis) {
@@ -1141,27 +1202,33 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
} break;
case RS::ARRAY_NORMAL: {
- vd.offset = stride;
- vd.format = RD::DATA_FORMAT_R16G16_UNORM;
- stride += sizeof(uint16_t) * 2;
-
- if (mis) {
- buffer = mis->vertex_buffer[p_current_buffer];
+ vd.offset = 0;
+ offset = position_stride * s->vertex_count;
+ if (!mis && (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
+ vd.format = RD::DATA_FORMAT_R16G16_UNORM;
+ normal_tangent_stride += sizeof(uint16_t) * 2;
} else {
- buffer = s->vertex_buffer;
+ vd.format = RD::DATA_FORMAT_R16G16B16A16_UNORM;
+ // A small trick here: if we are uncompressed and we have normals, but no tangents. We need
+ // the shader to think there are 4 components to "axis_tangent_attrib". So we give a size of 4,
+ // but a stride based on only having 2 elements.
+ if (!(s->format & RS::ARRAY_FORMAT_TANGENT)) {
+ normal_tangent_stride += sizeof(uint16_t) * 2;
+ } else {
+ normal_tangent_stride += sizeof(uint16_t) * 4;
+ }
}
- } break;
- case RS::ARRAY_TANGENT: {
- vd.offset = stride;
- vd.format = RD::DATA_FORMAT_R16G16_UNORM;
- stride += sizeof(uint16_t) * 2;
-
if (mis) {
buffer = mis->vertex_buffer[p_current_buffer];
} else {
buffer = s->vertex_buffer;
}
} break;
+ case RS::ARRAY_TANGENT: {
+ buffer = mesh_default_rd_buffers[i];
+ vd.stride = 0;
+ vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+ } break;
case RS::ARRAY_COLOR: {
vd.offset = attribute_stride;
@@ -1171,17 +1238,25 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
} break;
case RS::ARRAY_TEX_UV: {
vd.offset = attribute_stride;
-
- vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
- attribute_stride += sizeof(float) * 2;
+ if (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
+ vd.format = RD::DATA_FORMAT_R16G16_UNORM;
+ attribute_stride += sizeof(uint16_t) * 2;
+ } else {
+ vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+ attribute_stride += sizeof(float) * 2;
+ }
buffer = s->attribute_buffer;
} break;
case RS::ARRAY_TEX_UV2: {
vd.offset = attribute_stride;
-
- vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
- attribute_stride += sizeof(float) * 2;
+ if (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
+ vd.format = RD::DATA_FORMAT_R16G16_UNORM;
+ attribute_stride += sizeof(uint16_t) * 2;
+ } else {
+ vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+ attribute_stride += sizeof(float) * 2;
+ }
buffer = s->attribute_buffer;
} break;
case RS::ARRAY_CUSTOM0:
@@ -1216,12 +1291,13 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
}
}
- if (!(p_input_mask & (1 << i))) {
+ if (!(p_input_mask & (1ULL << i))) {
continue; // Shader does not need this, skip it (but computing stride was important anyway)
}
attributes.push_back(vd);
buffers.push_back(buffer);
+ offsets.push_back(offset);
if (p_input_motion_vectors) {
// Since the previous vertex, normal and tangent can't be part of the vertex format but they are required when motion
@@ -1246,6 +1322,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
attributes.push_back(vd);
buffers.push_back(buffer);
+ offsets.push_back(offset);
}
}
}
@@ -1256,9 +1333,10 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
continue; //default location
}
int loc = attributes[i].location;
-
- if ((loc < RS::ARRAY_COLOR) || ((loc >= ATTRIBUTE_LOCATION_PREV_VERTEX) && (loc <= ATTRIBUTE_LOCATION_PREV_TANGENT))) {
- attributes.write[i].stride = stride;
+ if (loc == RS::ARRAY_VERTEX || loc == ATTRIBUTE_LOCATION_PREV_VERTEX) {
+ attributes.write[i].stride = position_stride;
+ } else if ((loc < RS::ARRAY_COLOR) || ((loc >= ATTRIBUTE_LOCATION_PREV_NORMAL) && (loc <= ATTRIBUTE_LOCATION_PREV_TANGENT))) {
+ attributes.write[i].stride = normal_tangent_stride;
} else if (loc < RS::ARRAY_BONES) {
attributes.write[i].stride = attribute_stride;
} else {
@@ -1271,7 +1349,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
v.previous_buffer = p_previous_buffer;
v.input_motion_vectors = p_input_motion_vectors;
v.vertex_format = RD::get_singleton()->vertex_format_create(attributes);
- v.vertex_array = RD::get_singleton()->vertex_array_create(s->vertex_count, v.vertex_format, buffers);
+ v.vertex_array = RD::get_singleton()->vertex_array_create(s->vertex_count, v.vertex_format, buffers, offsets);
}
////////////////// MULTIMESH