diff options
Diffstat (limited to 'servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp')
-rw-r--r-- | servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp | 222 |
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 |