Browse Source

Merge pull request #59807 from BastiaanOlij/mesh_storage

Rémi Verschelde 3 years ago
parent
commit
e7c1888d20
28 changed files with 3509 additions and 2707 deletions
  1. 3 0
      drivers/gles3/rasterizer_gles3.h
  2. 5 197
      drivers/gles3/rasterizer_storage_gles3.cpp
  3. 2 138
      drivers/gles3/rasterizer_storage_gles3.h
  4. 257 0
      drivers/gles3/storage/mesh_storage.cpp
  5. 204 0
      drivers/gles3/storage/mesh_storage.h
  6. 3 0
      servers/rendering/dummy/rasterizer_dummy.h
  7. 2 77
      servers/rendering/dummy/rasterizer_storage_dummy.h
  8. 129 0
      servers/rendering/dummy/storage/mesh_storage.h
  9. 5 5
      servers/rendering/renderer_canvas_cull.cpp
  10. 3 2
      servers/rendering/renderer_canvas_render.h
  11. 2 0
      servers/rendering/renderer_compositor.h
  12. 32 25
      servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
  13. 33 25
      servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
  14. 26 22
      servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
  15. 2 0
      servers/rendering/renderer_rd/renderer_compositor_rd.cpp
  16. 3 0
      servers/rendering/renderer_rd/renderer_compositor_rd.h
  17. 1 1
      servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
  18. 4 1483
      servers/rendering/renderer_rd/renderer_storage_rd.cpp
  19. 0 610
      servers/rendering/renderer_rd/renderer_storage_rd.h
  20. 1921 0
      servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
  21. 694 0
      servers/rendering/renderer_rd/storage_rd/mesh_storage.h
  22. 24 24
      servers/rendering/renderer_scene_cull.cpp
  23. 0 89
      servers/rendering/renderer_storage.h
  24. 1 0
      servers/rendering/rendering_server_default.cpp
  25. 14 9
      servers/rendering/rendering_server_default.h
  26. 1 0
      servers/rendering/rendering_server_globals.cpp
  27. 2 0
      servers/rendering/rendering_server_globals.h
  28. 136 0
      servers/rendering/storage/mesh_storage.h

+ 3 - 0
drivers/gles3/rasterizer_gles3.h

@@ -41,6 +41,7 @@
 #include "storage/config.h"
 #include "storage/config.h"
 #include "storage/decal_atlas_storage.h"
 #include "storage/decal_atlas_storage.h"
 #include "storage/material_storage.h"
 #include "storage/material_storage.h"
+#include "storage/mesh_storage.h"
 #include "storage/render_target_storage.h"
 #include "storage/render_target_storage.h"
 #include "storage/texture_storage.h"
 #include "storage/texture_storage.h"
 
 
@@ -57,6 +58,7 @@ protected:
 	GLES3::TextureStorage texture_storage;
 	GLES3::TextureStorage texture_storage;
 	GLES3::DecalAtlasStorage decal_atlas_storage;
 	GLES3::DecalAtlasStorage decal_atlas_storage;
 	GLES3::MaterialStorage material_storage;
 	GLES3::MaterialStorage material_storage;
+	GLES3::MeshStorage mesh_storage;
 	RasterizerStorageGLES3 storage;
 	RasterizerStorageGLES3 storage;
 	RasterizerCanvasGLES3 canvas;
 	RasterizerCanvasGLES3 canvas;
 	RasterizerSceneGLES3 scene;
 	RasterizerSceneGLES3 scene;
@@ -66,6 +68,7 @@ protected:
 public:
 public:
 	RendererCanvasTextureStorage *get_canvas_texture_storage() { return &canvas_texture_storage; }
 	RendererCanvasTextureStorage *get_canvas_texture_storage() { return &canvas_texture_storage; }
 	RendererMaterialStorage *get_material_storage() { return &material_storage; }
 	RendererMaterialStorage *get_material_storage() { return &material_storage; }
+	RendererMeshStorage *get_mesh_storage() { return &mesh_storage; }
 	RendererTextureStorage *get_texture_storage() { return &texture_storage; }
 	RendererTextureStorage *get_texture_storage() { return &texture_storage; }
 	RendererDecalAtlasStorage *get_decal_atlas_storage() { return &decal_atlas_storage; }
 	RendererDecalAtlasStorage *get_decal_atlas_storage() { return &decal_atlas_storage; }
 	RendererStorage *get_storage() { return &storage; }
 	RendererStorage *get_storage() { return &storage; }

+ 5 - 197
drivers/gles3/rasterizer_storage_gles3.cpp

@@ -58,202 +58,6 @@ RID RasterizerStorageGLES3::sky_create() {
 void RasterizerStorageGLES3::sky_set_texture(RID p_sky, RID p_panorama, int p_radiance_size) {
 void RasterizerStorageGLES3::sky_set_texture(RID p_sky, RID p_panorama, int p_radiance_size) {
 }
 }
 
 
-/* MESH API */
-
-RID RasterizerStorageGLES3::mesh_allocate() {
-	return RID();
-}
-
-void RasterizerStorageGLES3::mesh_initialize(RID p_rid) {
-}
-
-void RasterizerStorageGLES3::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) {
-}
-
-bool RasterizerStorageGLES3::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) {
-	return false;
-}
-
-RID RasterizerStorageGLES3::mesh_instance_create(RID p_base) {
-	return RID();
-}
-
-void RasterizerStorageGLES3::mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) {
-}
-
-void RasterizerStorageGLES3::mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) {
-}
-
-void RasterizerStorageGLES3::mesh_instance_check_for_update(RID p_mesh_instance) {
-}
-
-void RasterizerStorageGLES3::update_mesh_instances() {
-}
-
-void RasterizerStorageGLES3::reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_ratio) {
-}
-
-float RasterizerStorageGLES3::reflection_probe_get_mesh_lod_threshold(RID p_probe) const {
-	return 0.0;
-}
-
-void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) {
-}
-
-int RasterizerStorageGLES3::mesh_get_blend_shape_count(RID p_mesh) const {
-	return 0;
-}
-
-void RasterizerStorageGLES3::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) {
-}
-
-RS::BlendShapeMode RasterizerStorageGLES3::mesh_get_blend_shape_mode(RID p_mesh) const {
-	return RS::BLEND_SHAPE_MODE_NORMALIZED;
-}
-
-void RasterizerStorageGLES3::mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
-}
-
-void RasterizerStorageGLES3::mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
-}
-
-void RasterizerStorageGLES3::mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
-}
-
-void RasterizerStorageGLES3::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) {
-}
-
-RID RasterizerStorageGLES3::mesh_surface_get_material(RID p_mesh, int p_surface) const {
-	return RID();
-}
-
-RS::SurfaceData RasterizerStorageGLES3::mesh_get_surface(RID p_mesh, int p_surface) const {
-	return RS::SurfaceData();
-}
-
-int RasterizerStorageGLES3::mesh_get_surface_count(RID p_mesh) const {
-	return 1;
-}
-
-void RasterizerStorageGLES3::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) {
-}
-
-AABB RasterizerStorageGLES3::mesh_get_custom_aabb(RID p_mesh) const {
-	return AABB();
-}
-
-AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
-	return AABB();
-}
-
-void RasterizerStorageGLES3::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) {
-}
-
-void RasterizerStorageGLES3::mesh_clear(RID p_mesh) {
-}
-
-/* MULTIMESH API */
-
-RID RasterizerStorageGLES3::multimesh_allocate() {
-	return RID();
-}
-
-void RasterizerStorageGLES3::multimesh_initialize(RID p_rid) {
-}
-
-void RasterizerStorageGLES3::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) {
-}
-
-int RasterizerStorageGLES3::multimesh_get_instance_count(RID p_multimesh) const {
-	return 0;
-}
-
-void RasterizerStorageGLES3::multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
-}
-
-void RasterizerStorageGLES3::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) {
-}
-
-void RasterizerStorageGLES3::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) {
-}
-
-void RasterizerStorageGLES3::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) {
-}
-
-void RasterizerStorageGLES3::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) {
-}
-
-RID RasterizerStorageGLES3::multimesh_get_mesh(RID p_multimesh) const {
-	return RID();
-}
-
-AABB RasterizerStorageGLES3::multimesh_get_aabb(RID p_multimesh) const {
-	return AABB();
-}
-
-Transform3D RasterizerStorageGLES3::multimesh_instance_get_transform(RID p_multimesh, int p_index) const {
-	return Transform3D();
-}
-
-Transform2D RasterizerStorageGLES3::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const {
-	return Transform2D();
-}
-
-Color RasterizerStorageGLES3::multimesh_instance_get_color(RID p_multimesh, int p_index) const {
-	return Color();
-}
-
-Color RasterizerStorageGLES3::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const {
-	return Color();
-}
-
-void RasterizerStorageGLES3::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) {
-}
-
-Vector<float> RasterizerStorageGLES3::multimesh_get_buffer(RID p_multimesh) const {
-	return Vector<float>();
-}
-
-void RasterizerStorageGLES3::multimesh_set_visible_instances(RID p_multimesh, int p_visible) {
-}
-
-int RasterizerStorageGLES3::multimesh_get_visible_instances(RID p_multimesh) const {
-	return 0;
-}
-
-/* SKELETON API */
-
-RID RasterizerStorageGLES3::skeleton_allocate() {
-	return RID();
-}
-
-void RasterizerStorageGLES3::skeleton_initialize(RID p_rid) {
-}
-
-void RasterizerStorageGLES3::skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton) {
-}
-
-void RasterizerStorageGLES3::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) {
-}
-
-int RasterizerStorageGLES3::skeleton_get_bone_count(RID p_skeleton) const {
-	return 0;
-}
-
-void RasterizerStorageGLES3::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) {
-}
-
-Transform3D RasterizerStorageGLES3::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const {
-	return Transform3D();
-}
-
-void RasterizerStorageGLES3::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) {
-}
-
-Transform2D RasterizerStorageGLES3::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const {
-	return Transform2D();
-}
-
 /* Light API */
 /* Light API */
 
 
 RID RasterizerStorageGLES3::directional_light_allocate() {
 RID RasterizerStorageGLES3::directional_light_allocate() {
@@ -450,7 +254,11 @@ bool RasterizerStorageGLES3::reflection_probe_renders_shadows(RID p_probe) const
 void RasterizerStorageGLES3::base_update_dependency(RID p_base, DependencyTracker *p_instance) {
 void RasterizerStorageGLES3::base_update_dependency(RID p_base, DependencyTracker *p_instance) {
 }
 }
 
 
-void RasterizerStorageGLES3::skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) {
+void RasterizerStorageGLES3::reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_ratio) {
+}
+
+float RasterizerStorageGLES3::reflection_probe_get_mesh_lod_threshold(RID p_probe) const {
+	return 0.0;
 }
 }
 
 
 /* VOXEL GI API */
 /* VOXEL GI API */

+ 2 - 138
drivers/gles3/rasterizer_storage_gles3.h

@@ -132,143 +132,6 @@ public:
 	RID sky_create();
 	RID sky_create();
 	void sky_set_texture(RID p_sky, RID p_panorama, int p_radiance_size);
 	void sky_set_texture(RID p_sky, RID p_panorama, int p_radiance_size);
 
 
-	/* MESH API */
-
-	RID mesh_allocate() override;
-	void mesh_initialize(RID p_rid) override;
-	void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) override;
-	bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override;
-	RID mesh_instance_create(RID p_base) override;
-	void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override;
-	void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) override;
-	void mesh_instance_check_for_update(RID p_mesh_instance) override;
-	void update_mesh_instances() override;
-	void reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_ratio) override;
-	float reflection_probe_get_mesh_lod_threshold(RID p_probe) const override;
-
-	void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) override;
-
-	int mesh_get_blend_shape_count(RID p_mesh) const override;
-
-	void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) override;
-	RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const override;
-
-	void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override;
-	void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override;
-	void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override;
-
-	void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) override;
-	RID mesh_surface_get_material(RID p_mesh, int p_surface) const override;
-
-	RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const override;
-	int mesh_get_surface_count(RID p_mesh) const override;
-
-	void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) override;
-	AABB mesh_get_custom_aabb(RID p_mesh) const override;
-
-	AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) override;
-	void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override;
-	void mesh_clear(RID p_mesh) override;
-
-	/* MULTIMESH API */
-
-	struct MultiMesh {
-		RID mesh;
-		int instances = 0;
-		RS::MultimeshTransformFormat xform_format = RS::MULTIMESH_TRANSFORM_3D;
-		bool uses_colors = false;
-		bool uses_custom_data = false;
-		int visible_instances = -1;
-		AABB aabb;
-		bool aabb_dirty = false;
-		bool buffer_set = false;
-		uint32_t stride_cache = 0;
-		uint32_t color_offset_cache = 0;
-		uint32_t custom_data_offset_cache = 0;
-
-		Vector<float> data_cache; //used if individual setting is used
-		bool *data_cache_dirty_regions = nullptr;
-		uint32_t data_cache_used_dirty_regions = 0;
-
-		RID buffer; //storage buffer
-		RID uniform_set_3d;
-		RID uniform_set_2d;
-
-		bool dirty = false;
-		MultiMesh *dirty_list = nullptr;
-
-		Dependency dependency;
-	};
-
-	mutable RID_Owner<MultiMesh, true> multimesh_owner;
-
-	MultiMesh *multimesh_dirty_list = nullptr;
-
-	_FORCE_INLINE_ void _multimesh_make_local(MultiMesh *multimesh) const;
-	_FORCE_INLINE_ void _multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb);
-	_FORCE_INLINE_ void _multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb);
-	_FORCE_INLINE_ void _multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances);
-	void _update_dirty_multimeshes();
-
-	RID multimesh_allocate() override;
-	void multimesh_initialize(RID p_rid) override;
-	void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) override;
-	int multimesh_get_instance_count(RID p_multimesh) const override;
-
-	void multimesh_set_mesh(RID p_multimesh, RID p_mesh) override;
-	void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) override;
-	void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) override;
-	void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override;
-	void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override;
-
-	RID multimesh_get_mesh(RID p_multimesh) const override;
-	AABB multimesh_get_aabb(RID p_multimesh) const override;
-
-	Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const override;
-	Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override;
-	Color multimesh_instance_get_color(RID p_multimesh, int p_index) const override;
-	Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override;
-	void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override;
-	Vector<float> multimesh_get_buffer(RID p_multimesh) const override;
-
-	void multimesh_set_visible_instances(RID p_multimesh, int p_visible) override;
-	int multimesh_get_visible_instances(RID p_multimesh) const override;
-
-	_FORCE_INLINE_ RS::MultimeshTransformFormat multimesh_get_transform_format(RID p_multimesh) const {
-		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
-		return multimesh->xform_format;
-	}
-
-	_FORCE_INLINE_ bool multimesh_uses_colors(RID p_multimesh) const {
-		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
-		return multimesh->uses_colors;
-	}
-
-	_FORCE_INLINE_ bool multimesh_uses_custom_data(RID p_multimesh) const {
-		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
-		return multimesh->uses_custom_data;
-	}
-
-	_FORCE_INLINE_ uint32_t multimesh_get_instances_to_draw(RID p_multimesh) const {
-		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
-		if (multimesh->visible_instances >= 0) {
-			return multimesh->visible_instances;
-		}
-		return multimesh->instances;
-	}
-
-	/* SKELETON API */
-
-	RID skeleton_allocate() override;
-	void skeleton_initialize(RID p_rid) override;
-	void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) override;
-	void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) override;
-	int skeleton_get_bone_count(RID p_skeleton) const override;
-	void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) override;
-	Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const override;
-	void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) override;
-	Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const override;
-
 	/* Light API */
 	/* Light API */
 
 
 	RID directional_light_allocate() override;
 	RID directional_light_allocate() override;
@@ -328,6 +191,8 @@ public:
 	void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) override;
 	void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) override;
 	void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) override;
 	void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) override;
 	void reflection_probe_set_resolution(RID p_probe, int p_resolution) override;
 	void reflection_probe_set_resolution(RID p_probe, int p_resolution) override;
+	void reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_ratio) override;
+	float reflection_probe_get_mesh_lod_threshold(RID p_probe) const override;
 
 
 	AABB reflection_probe_get_aabb(RID p_probe) const override;
 	AABB reflection_probe_get_aabb(RID p_probe) const override;
 	RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const override;
 	RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const override;
@@ -338,7 +203,6 @@ public:
 	bool reflection_probe_renders_shadows(RID p_probe) const override;
 	bool reflection_probe_renders_shadows(RID p_probe) const override;
 
 
 	void base_update_dependency(RID p_base, DependencyTracker *p_instance) override;
 	void base_update_dependency(RID p_base, DependencyTracker *p_instance) override;
-	void skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) override;
 
 
 	/* VOXEL GI API */
 	/* VOXEL GI API */
 
 

+ 257 - 0
drivers/gles3/storage/mesh_storage.cpp

@@ -0,0 +1,257 @@
+/*************************************************************************/
+/*  mesh_storage.cpp                                                     */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifdef GLES3_ENABLED
+
+#include "mesh_storage.h"
+
+using namespace GLES3;
+
+MeshStorage *MeshStorage::singleton = nullptr;
+
+MeshStorage *MeshStorage::get_singleton() {
+	return singleton;
+}
+
+MeshStorage::MeshStorage() {
+	singleton = this;
+}
+
+MeshStorage::~MeshStorage() {
+	singleton = nullptr;
+}
+
+/* MESH API */
+
+RID MeshStorage::mesh_allocate() {
+	return RID();
+}
+
+void MeshStorage::mesh_initialize(RID p_rid) {
+}
+
+void MeshStorage::mesh_free(RID p_rid) {
+}
+
+void MeshStorage::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) {
+}
+
+bool MeshStorage::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) {
+	return false;
+}
+
+void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) {
+}
+
+int MeshStorage::mesh_get_blend_shape_count(RID p_mesh) const {
+	return 0;
+}
+
+void MeshStorage::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) {
+}
+
+RS::BlendShapeMode MeshStorage::mesh_get_blend_shape_mode(RID p_mesh) const {
+	return RS::BLEND_SHAPE_MODE_NORMALIZED;
+}
+
+void MeshStorage::mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+}
+
+void MeshStorage::mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+}
+
+void MeshStorage::mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+}
+
+void MeshStorage::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) {
+}
+
+RID MeshStorage::mesh_surface_get_material(RID p_mesh, int p_surface) const {
+	return RID();
+}
+
+RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
+	return RS::SurfaceData();
+}
+
+int MeshStorage::mesh_get_surface_count(RID p_mesh) const {
+	return 1;
+}
+
+void MeshStorage::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) {
+}
+
+AABB MeshStorage::mesh_get_custom_aabb(RID p_mesh) const {
+	return AABB();
+}
+
+AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
+	return AABB();
+}
+
+void MeshStorage::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) {
+}
+
+void MeshStorage::mesh_clear(RID p_mesh) {
+}
+
+/* MESH INSTANCE API */
+
+RID MeshStorage::mesh_instance_create(RID p_base) {
+	return RID();
+}
+
+void MeshStorage::mesh_instance_free(RID p_rid) {
+}
+
+void MeshStorage::mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) {
+}
+
+void MeshStorage::mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) {
+}
+
+void MeshStorage::mesh_instance_check_for_update(RID p_mesh_instance) {
+}
+
+void MeshStorage::update_mesh_instances() {
+}
+
+/* MULTIMESH API */
+
+RID MeshStorage::multimesh_allocate() {
+	return RID();
+}
+
+void MeshStorage::multimesh_initialize(RID p_rid) {
+}
+
+void MeshStorage::multimesh_free(RID p_rid) {
+}
+
+void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) {
+}
+
+int MeshStorage::multimesh_get_instance_count(RID p_multimesh) const {
+	return 0;
+}
+
+void MeshStorage::multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
+}
+
+void MeshStorage::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) {
+}
+
+void MeshStorage::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) {
+}
+
+void MeshStorage::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) {
+}
+
+void MeshStorage::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) {
+}
+
+RID MeshStorage::multimesh_get_mesh(RID p_multimesh) const {
+	return RID();
+}
+
+AABB MeshStorage::multimesh_get_aabb(RID p_multimesh) const {
+	return AABB();
+}
+
+Transform3D MeshStorage::multimesh_instance_get_transform(RID p_multimesh, int p_index) const {
+	return Transform3D();
+}
+
+Transform2D MeshStorage::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const {
+	return Transform2D();
+}
+
+Color MeshStorage::multimesh_instance_get_color(RID p_multimesh, int p_index) const {
+	return Color();
+}
+
+Color MeshStorage::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const {
+	return Color();
+}
+
+void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) {
+}
+
+Vector<float> MeshStorage::multimesh_get_buffer(RID p_multimesh) const {
+	return Vector<float>();
+}
+
+void MeshStorage::multimesh_set_visible_instances(RID p_multimesh, int p_visible) {
+}
+
+int MeshStorage::multimesh_get_visible_instances(RID p_multimesh) const {
+	return 0;
+}
+
+/* SKELETON API */
+
+RID MeshStorage::skeleton_allocate() {
+	return RID();
+}
+
+void MeshStorage::skeleton_initialize(RID p_rid) {
+}
+
+void MeshStorage::skeleton_free(RID p_rid) {
+}
+
+void MeshStorage::skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton) {
+}
+
+void MeshStorage::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) {
+}
+
+int MeshStorage::skeleton_get_bone_count(RID p_skeleton) const {
+	return 0;
+}
+
+void MeshStorage::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) {
+}
+
+Transform3D MeshStorage::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const {
+	return Transform3D();
+}
+
+void MeshStorage::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) {
+}
+
+Transform2D MeshStorage::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const {
+	return Transform2D();
+}
+
+void MeshStorage::skeleton_update_dependency(RID p_base, RendererStorage::DependencyTracker *p_instance) {
+}
+
+#endif // GLES3_ENABLED

+ 204 - 0
drivers/gles3/storage/mesh_storage.h

@@ -0,0 +1,204 @@
+/*************************************************************************/
+/*  mesh_storage.h                                                       */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef MESH_STORAGE_GLES3_H
+#define MESH_STORAGE_GLES3_H
+
+#ifdef GLES3_ENABLED
+
+#include "core/templates/local_vector.h"
+#include "core/templates/rid_owner.h"
+#include "core/templates/self_list.h"
+#include "servers/rendering/storage/mesh_storage.h"
+
+namespace GLES3 {
+
+class MeshStorage : public RendererMeshStorage {
+private:
+	static MeshStorage *singleton;
+
+public:
+	static MeshStorage *get_singleton();
+
+	MeshStorage();
+	virtual ~MeshStorage();
+
+	/* MESH API */
+
+	virtual RID mesh_allocate() override;
+	virtual void mesh_initialize(RID p_rid) override;
+	virtual void mesh_free(RID p_rid) override;
+
+	virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) override;
+	virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override;
+
+	virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) override;
+
+	virtual int mesh_get_blend_shape_count(RID p_mesh) const override;
+
+	virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) override;
+	virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const override;
+
+	virtual void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override;
+	virtual void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override;
+	virtual void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override;
+
+	virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) override;
+	virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const override;
+
+	virtual RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const override;
+	virtual int mesh_get_surface_count(RID p_mesh) const override;
+
+	virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) override;
+	virtual AABB mesh_get_custom_aabb(RID p_mesh) const override;
+
+	virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) override;
+	virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override;
+	virtual void mesh_clear(RID p_mesh) override;
+
+	/* MESH INSTANCE API */
+
+	virtual RID mesh_instance_create(RID p_base) override;
+	virtual void mesh_instance_free(RID p_rid) override;
+	virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override;
+	virtual void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) override;
+	virtual void mesh_instance_check_for_update(RID p_mesh_instance) override;
+	virtual void update_mesh_instances() override;
+
+	/* MULTIMESH API */
+
+	struct MultiMesh {
+		RID mesh;
+		int instances = 0;
+		RS::MultimeshTransformFormat xform_format = RS::MULTIMESH_TRANSFORM_3D;
+		bool uses_colors = false;
+		bool uses_custom_data = false;
+		int visible_instances = -1;
+		AABB aabb;
+		bool aabb_dirty = false;
+		bool buffer_set = false;
+		uint32_t stride_cache = 0;
+		uint32_t color_offset_cache = 0;
+		uint32_t custom_data_offset_cache = 0;
+
+		Vector<float> data_cache; //used if individual setting is used
+		bool *data_cache_dirty_regions = nullptr;
+		uint32_t data_cache_used_dirty_regions = 0;
+
+		RID buffer; //storage buffer
+		RID uniform_set_3d;
+		RID uniform_set_2d;
+
+		bool dirty = false;
+		MultiMesh *dirty_list = nullptr;
+
+		RendererStorage::Dependency dependency;
+	};
+
+	mutable RID_Owner<MultiMesh, true> multimesh_owner;
+
+	MultiMesh *multimesh_dirty_list = nullptr;
+
+	_FORCE_INLINE_ void _multimesh_make_local(MultiMesh *multimesh) const;
+	_FORCE_INLINE_ void _multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb);
+	_FORCE_INLINE_ void _multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb);
+	_FORCE_INLINE_ void _multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances);
+	void _update_dirty_multimeshes();
+
+	virtual RID multimesh_allocate() override;
+	virtual void multimesh_initialize(RID p_rid) override;
+	virtual void multimesh_free(RID p_rid) override;
+	virtual void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) override;
+	virtual int multimesh_get_instance_count(RID p_multimesh) const override;
+
+	virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) override;
+	virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) override;
+	virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) override;
+	virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override;
+	virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override;
+
+	virtual RID multimesh_get_mesh(RID p_multimesh) const override;
+	virtual AABB multimesh_get_aabb(RID p_multimesh) const override;
+
+	virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const override;
+	virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override;
+	virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const override;
+	virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override;
+	virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override;
+	virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const override;
+
+	virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) override;
+	virtual int multimesh_get_visible_instances(RID p_multimesh) const override;
+
+	_FORCE_INLINE_ RS::MultimeshTransformFormat multimesh_get_transform_format(RID p_multimesh) const {
+		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+		return multimesh->xform_format;
+	}
+
+	_FORCE_INLINE_ bool multimesh_uses_colors(RID p_multimesh) const {
+		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+		return multimesh->uses_colors;
+	}
+
+	_FORCE_INLINE_ bool multimesh_uses_custom_data(RID p_multimesh) const {
+		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+		return multimesh->uses_custom_data;
+	}
+
+	_FORCE_INLINE_ uint32_t multimesh_get_instances_to_draw(RID p_multimesh) const {
+		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+		if (multimesh->visible_instances >= 0) {
+			return multimesh->visible_instances;
+		}
+		return multimesh->instances;
+	}
+
+	/* SKELETON API */
+
+	virtual RID skeleton_allocate() override;
+	virtual void skeleton_initialize(RID p_rid) override;
+	virtual void skeleton_free(RID p_rid) override;
+
+	virtual void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) override;
+	virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) override;
+	virtual int skeleton_get_bone_count(RID p_skeleton) const override;
+	virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) override;
+	virtual Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const override;
+	virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) override;
+	virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const override;
+
+	virtual void skeleton_update_dependency(RID p_base, RendererStorage::DependencyTracker *p_instance) override;
+};
+
+} // namespace GLES3
+
+#endif // GLES3_ENABLED
+
+#endif // !MESH_STORAGE_GLES3_H

+ 3 - 0
servers/rendering/dummy/rasterizer_dummy.h

@@ -40,6 +40,7 @@
 #include "servers/rendering/dummy/storage/canvas_texture_storage.h"
 #include "servers/rendering/dummy/storage/canvas_texture_storage.h"
 #include "servers/rendering/dummy/storage/decal_atlas_storage.h"
 #include "servers/rendering/dummy/storage/decal_atlas_storage.h"
 #include "servers/rendering/dummy/storage/material_storage.h"
 #include "servers/rendering/dummy/storage/material_storage.h"
+#include "servers/rendering/dummy/storage/mesh_storage.h"
 #include "servers/rendering/dummy/storage/texture_storage.h"
 #include "servers/rendering/dummy/storage/texture_storage.h"
 #include "servers/rendering/renderer_compositor.h"
 #include "servers/rendering/renderer_compositor.h"
 #include "servers/rendering_server.h"
 #include "servers/rendering_server.h"
@@ -53,6 +54,7 @@ protected:
 	RasterizerCanvasDummy canvas;
 	RasterizerCanvasDummy canvas;
 	RendererDummy::CanvasTextureStorage canvas_texture_storage;
 	RendererDummy::CanvasTextureStorage canvas_texture_storage;
 	RendererDummy::MaterialStorage material_storage;
 	RendererDummy::MaterialStorage material_storage;
+	RendererDummy::MeshStorage mesh_storage;
 	RendererDummy::TextureStorage texture_storage;
 	RendererDummy::TextureStorage texture_storage;
 	RendererDummy::DecalAtlasStorage decal_atlas_storage;
 	RendererDummy::DecalAtlasStorage decal_atlas_storage;
 	RasterizerStorageDummy storage;
 	RasterizerStorageDummy storage;
@@ -61,6 +63,7 @@ protected:
 public:
 public:
 	RendererCanvasTextureStorage *get_canvas_texture_storage() override { return &canvas_texture_storage; };
 	RendererCanvasTextureStorage *get_canvas_texture_storage() override { return &canvas_texture_storage; };
 	RendererMaterialStorage *get_material_storage() override { return &material_storage; };
 	RendererMaterialStorage *get_material_storage() override { return &material_storage; };
+	RendererMeshStorage *get_mesh_storage() override { return &mesh_storage; };
 	RendererTextureStorage *get_texture_storage() override { return &texture_storage; };
 	RendererTextureStorage *get_texture_storage() override { return &texture_storage; };
 	RendererDecalAtlasStorage *get_decal_atlas_storage() override { return &decal_atlas_storage; };
 	RendererDecalAtlasStorage *get_decal_atlas_storage() override { return &decal_atlas_storage; };
 	RendererStorage *get_storage() override { return &storage; }
 	RendererStorage *get_storage() override { return &storage; }

+ 2 - 77
servers/rendering/dummy/rasterizer_storage_dummy.h

@@ -36,82 +36,6 @@
 
 
 class RasterizerStorageDummy : public RendererStorage {
 class RasterizerStorageDummy : public RendererStorage {
 public:
 public:
-	/* MESH API */
-
-	RID mesh_allocate() override { return RID(); }
-	void mesh_initialize(RID p_rid) override {}
-	void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) override {}
-	bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override { return false; }
-	RID mesh_instance_create(RID p_base) override { return RID(); }
-	void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override {}
-	void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) override {}
-	void mesh_instance_check_for_update(RID p_mesh_instance) override {}
-	void update_mesh_instances() override {}
-	void reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_ratio) override {}
-	float reflection_probe_get_mesh_lod_threshold(RID p_probe) const override { return 0.0; }
-
-	void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) override {}
-
-	int mesh_get_blend_shape_count(RID p_mesh) const override { return 0; }
-
-	void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) override {}
-	RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const override { return RS::BLEND_SHAPE_MODE_NORMALIZED; }
-
-	void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {}
-	void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {}
-	void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {}
-
-	void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) override {}
-	RID mesh_surface_get_material(RID p_mesh, int p_surface) const override { return RID(); }
-
-	RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const override { return RS::SurfaceData(); }
-	int mesh_get_surface_count(RID p_mesh) const override { return 0; }
-
-	void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) override {}
-	AABB mesh_get_custom_aabb(RID p_mesh) const override { return AABB(); }
-
-	AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) override { return AABB(); }
-	void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override {}
-	void mesh_clear(RID p_mesh) override {}
-
-	/* MULTIMESH API */
-
-	RID multimesh_allocate() override { return RID(); }
-	void multimesh_initialize(RID p_rid) override {}
-	void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) override {}
-	int multimesh_get_instance_count(RID p_multimesh) const override { return 0; }
-
-	void multimesh_set_mesh(RID p_multimesh, RID p_mesh) override {}
-	void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) override {}
-	void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) override {}
-	void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override {}
-	void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override {}
-
-	RID multimesh_get_mesh(RID p_multimesh) const override { return RID(); }
-	AABB multimesh_get_aabb(RID p_multimesh) const override { return AABB(); }
-
-	Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const override { return Transform3D(); }
-	Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override { return Transform2D(); }
-	Color multimesh_instance_get_color(RID p_multimesh, int p_index) const override { return Color(); }
-	Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override { return Color(); }
-	void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override {}
-	Vector<float> multimesh_get_buffer(RID p_multimesh) const override { return Vector<float>(); }
-
-	void multimesh_set_visible_instances(RID p_multimesh, int p_visible) override {}
-	int multimesh_get_visible_instances(RID p_multimesh) const override { return 0; }
-
-	/* SKELETON API */
-
-	RID skeleton_allocate() override { return RID(); }
-	void skeleton_initialize(RID p_rid) override {}
-	void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) override {}
-	void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) override {}
-	int skeleton_get_bone_count(RID p_skeleton) const override { return 0; }
-	void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) override {}
-	Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const override { return Transform3D(); }
-	void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) override {}
-	Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const override { return Transform2D(); }
-
 	/* Light API */
 	/* Light API */
 
 
 	RID directional_light_allocate() override { return RID(); }
 	RID directional_light_allocate() override { return RID(); }
@@ -171,6 +95,8 @@ public:
 	void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) override {}
 	void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) override {}
 	void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) override {}
 	void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) override {}
 	void reflection_probe_set_resolution(RID p_probe, int p_resolution) override {}
 	void reflection_probe_set_resolution(RID p_probe, int p_resolution) override {}
+	void reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_ratio) override {}
+	float reflection_probe_get_mesh_lod_threshold(RID p_probe) const override { return 0.0; }
 
 
 	AABB reflection_probe_get_aabb(RID p_probe) const override { return AABB(); }
 	AABB reflection_probe_get_aabb(RID p_probe) const override { return AABB(); }
 	RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const override { return RenderingServer::REFLECTION_PROBE_UPDATE_ONCE; }
 	RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const override { return RenderingServer::REFLECTION_PROBE_UPDATE_ONCE; }
@@ -181,7 +107,6 @@ public:
 	bool reflection_probe_renders_shadows(RID p_probe) const override { return false; }
 	bool reflection_probe_renders_shadows(RID p_probe) const override { return false; }
 
 
 	void base_update_dependency(RID p_base, DependencyTracker *p_instance) override {}
 	void base_update_dependency(RID p_base, DependencyTracker *p_instance) override {}
-	void skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) override {}
 
 
 	/* VOXEL GI API */
 	/* VOXEL GI API */
 
 

+ 129 - 0
servers/rendering/dummy/storage/mesh_storage.h

@@ -0,0 +1,129 @@
+/*************************************************************************/
+/*  mesh_storage.h                                                       */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef MESH_STORAGE_DUMMY_H
+#define MESH_STORAGE_DUMMY_H
+
+#include "servers/rendering/storage/mesh_storage.h"
+
+namespace RendererDummy {
+
+class MeshStorage : public RendererMeshStorage {
+public:
+	/* MESH API */
+
+	virtual RID mesh_allocate() override { return RID(); }
+	virtual void mesh_initialize(RID p_rid) override {}
+	virtual void mesh_free(RID p_rid) override {}
+
+	virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) override {}
+	virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override { return false; }
+
+	virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) override {}
+
+	virtual int mesh_get_blend_shape_count(RID p_mesh) const override { return 0; }
+
+	virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) override {}
+	virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const override { return RS::BLEND_SHAPE_MODE_NORMALIZED; }
+
+	virtual void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {}
+	virtual void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {}
+	virtual void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {}
+
+	virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) override {}
+	virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const override { return RID(); }
+
+	virtual RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const override { return RS::SurfaceData(); }
+	virtual int mesh_get_surface_count(RID p_mesh) const override { return 0; }
+
+	virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) override {}
+	virtual AABB mesh_get_custom_aabb(RID p_mesh) const override { return AABB(); }
+
+	virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) override { return AABB(); }
+	virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override {}
+	virtual void mesh_clear(RID p_mesh) override {}
+
+	/* MESH INSTANCE */
+
+	virtual RID mesh_instance_create(RID p_base) override { return RID(); }
+	virtual void mesh_instance_free(RID p_rid) override {}
+
+	virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override {}
+	virtual void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) override {}
+	virtual void mesh_instance_check_for_update(RID p_mesh_instance) override {}
+	virtual void update_mesh_instances() override {}
+
+	/* MULTIMESH API */
+
+	virtual RID multimesh_allocate() override { return RID(); }
+	virtual void multimesh_initialize(RID p_rid) override {}
+	virtual void multimesh_free(RID p_rid) override {}
+
+	virtual void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) override {}
+	virtual int multimesh_get_instance_count(RID p_multimesh) const override { return 0; }
+
+	virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) override {}
+	virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) override {}
+	virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) override {}
+	virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override {}
+	virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override {}
+
+	virtual RID multimesh_get_mesh(RID p_multimesh) const override { return RID(); }
+	virtual AABB multimesh_get_aabb(RID p_multimesh) const override { return AABB(); }
+
+	virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const override { return Transform3D(); }
+	virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override { return Transform2D(); }
+	virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const override { return Color(); }
+	virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override { return Color(); }
+	virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override {}
+	virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const override { return Vector<float>(); }
+
+	virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) override {}
+	virtual int multimesh_get_visible_instances(RID p_multimesh) const override { return 0; }
+
+	/* SKELETON API */
+
+	virtual RID skeleton_allocate() override { return RID(); }
+	virtual void skeleton_initialize(RID p_rid) override {}
+	virtual void skeleton_free(RID p_rid) override {}
+	virtual void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) override {}
+	virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) override {}
+	virtual int skeleton_get_bone_count(RID p_skeleton) const override { return 0; }
+	virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) override {}
+	virtual Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const override { return Transform3D(); }
+	virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) override {}
+	virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const override { return Transform2D(); }
+
+	virtual void skeleton_update_dependency(RID p_base, RendererStorage::DependencyTracker *p_instance) override {}
+};
+
+} // namespace RendererDummy
+
+#endif // !MESH_STORAGE_DUMMY_H

+ 5 - 5
servers/rendering/renderer_canvas_cull.cpp

@@ -997,8 +997,8 @@ void RendererCanvasCull::canvas_item_add_mesh(RID p_item, const RID &p_mesh, con
 	ERR_FAIL_COND(!m);
 	ERR_FAIL_COND(!m);
 	m->mesh = p_mesh;
 	m->mesh = p_mesh;
 	if (canvas_item->skeleton.is_valid()) {
 	if (canvas_item->skeleton.is_valid()) {
-		m->mesh_instance = RSG::storage->mesh_instance_create(p_mesh);
-		RSG::storage->mesh_instance_set_skeleton(m->mesh_instance, canvas_item->skeleton);
+		m->mesh_instance = RSG::mesh_storage->mesh_instance_create(p_mesh);
+		RSG::mesh_storage->mesh_instance_set_skeleton(m->mesh_instance, canvas_item->skeleton);
 	}
 	}
 
 
 	m->texture = p_texture;
 	m->texture = p_texture;
@@ -1093,12 +1093,12 @@ void RendererCanvasCull::canvas_item_attach_skeleton(RID p_item, RID p_skeleton)
 			Item::CommandMesh *cm = static_cast<Item::CommandMesh *>(c);
 			Item::CommandMesh *cm = static_cast<Item::CommandMesh *>(c);
 			if (canvas_item->skeleton.is_valid()) {
 			if (canvas_item->skeleton.is_valid()) {
 				if (cm->mesh_instance.is_null()) {
 				if (cm->mesh_instance.is_null()) {
-					cm->mesh_instance = RSG::storage->mesh_instance_create(cm->mesh);
+					cm->mesh_instance = RSG::mesh_storage->mesh_instance_create(cm->mesh);
 				}
 				}
-				RSG::storage->mesh_instance_set_skeleton(cm->mesh_instance, canvas_item->skeleton);
+				RSG::mesh_storage->mesh_instance_set_skeleton(cm->mesh_instance, canvas_item->skeleton);
 			} else {
 			} else {
 				if (cm->mesh_instance.is_valid()) {
 				if (cm->mesh_instance.is_valid()) {
-					RSG::storage->free(cm->mesh_instance);
+					RSG::mesh_storage->mesh_instance_free(cm->mesh_instance);
 					cm->mesh_instance = RID();
 					cm->mesh_instance = RID();
 				}
 				}
 			}
 			}

+ 3 - 2
servers/rendering/renderer_canvas_render.h

@@ -31,6 +31,7 @@
 #ifndef RENDERINGSERVERCANVASRENDER_H
 #ifndef RENDERINGSERVERCANVASRENDER_H
 #define RENDERINGSERVERCANVASRENDER_H
 #define RENDERINGSERVERCANVASRENDER_H
 
 
+#include "servers/rendering/renderer_rd/storage_rd/mesh_storage.h"
 #include "servers/rendering/renderer_storage.h"
 #include "servers/rendering/renderer_storage.h"
 
 
 class RendererCanvasRender {
 class RendererCanvasRender {
@@ -403,14 +404,14 @@ public:
 					} break;
 					} break;
 					case Item::Command::TYPE_MESH: {
 					case Item::Command::TYPE_MESH: {
 						const Item::CommandMesh *mesh = static_cast<const Item::CommandMesh *>(c);
 						const Item::CommandMesh *mesh = static_cast<const Item::CommandMesh *>(c);
-						AABB aabb = RendererStorage::base_singleton->mesh_get_aabb(mesh->mesh, RID());
+						AABB aabb = RendererRD::MeshStorage::get_singleton()->mesh_get_aabb(mesh->mesh, RID());
 
 
 						r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
 						r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
 
 
 					} break;
 					} break;
 					case Item::Command::TYPE_MULTIMESH: {
 					case Item::Command::TYPE_MULTIMESH: {
 						const Item::CommandMultiMesh *multimesh = static_cast<const Item::CommandMultiMesh *>(c);
 						const Item::CommandMultiMesh *multimesh = static_cast<const Item::CommandMultiMesh *>(c);
-						AABB aabb = RendererStorage::base_singleton->multimesh_get_aabb(multimesh->multimesh);
+						AABB aabb = RendererRD::MeshStorage::get_singleton()->multimesh_get_aabb(multimesh->multimesh);
 
 
 						r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
 						r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
 
 

+ 2 - 0
servers/rendering/renderer_compositor.h

@@ -37,6 +37,7 @@
 #include "servers/rendering/storage/canvas_texture_storage.h"
 #include "servers/rendering/storage/canvas_texture_storage.h"
 #include "servers/rendering/storage/decal_atlas_storage.h"
 #include "servers/rendering/storage/decal_atlas_storage.h"
 #include "servers/rendering/storage/material_storage.h"
 #include "servers/rendering/storage/material_storage.h"
+#include "servers/rendering/storage/mesh_storage.h"
 #include "servers/rendering/storage/texture_storage.h"
 #include "servers/rendering/storage/texture_storage.h"
 #include "servers/rendering_server.h"
 #include "servers/rendering_server.h"
 
 
@@ -76,6 +77,7 @@ public:
 
 
 	virtual RendererCanvasTextureStorage *get_canvas_texture_storage() = 0;
 	virtual RendererCanvasTextureStorage *get_canvas_texture_storage() = 0;
 	virtual RendererMaterialStorage *get_material_storage() = 0;
 	virtual RendererMaterialStorage *get_material_storage() = 0;
+	virtual RendererMeshStorage *get_mesh_storage() = 0;
 	virtual RendererTextureStorage *get_texture_storage() = 0;
 	virtual RendererTextureStorage *get_texture_storage() = 0;
 	virtual RendererDecalAtlasStorage *get_decal_atlas_storage() = 0;
 	virtual RendererDecalAtlasStorage *get_decal_atlas_storage() = 0;
 	virtual RendererStorage *get_storage() = 0;
 	virtual RendererStorage *get_storage() = 0;

+ 32 - 25
servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp

@@ -31,6 +31,7 @@
 #include "render_forward_clustered.h"
 #include "render_forward_clustered.h"
 #include "core/config/project_settings.h"
 #include "core/config/project_settings.h"
 #include "servers/rendering/renderer_rd/storage_rd/decal_atlas_storage.h"
 #include "servers/rendering/renderer_rd/storage_rd/decal_atlas_storage.h"
+#include "servers/rendering/renderer_rd/storage_rd/mesh_storage.h"
 #include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
 #include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
 #include "servers/rendering/rendering_device.h"
 #include "servers/rendering/rendering_device.h"
 #include "servers/rendering/rendering_server_default.h"
 #include "servers/rendering/rendering_server_default.h"
@@ -316,6 +317,7 @@ bool RenderForwardClustered::free(RID p_rid) {
 
 
 template <RenderForwardClustered::PassMode p_pass_mode, uint32_t p_color_pass_flags>
 template <RenderForwardClustered::PassMode p_pass_mode, uint32_t p_color_pass_flags>
 void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
 void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
+	RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
 	RD::DrawListID draw_list = p_draw_list;
 	RD::DrawListID draw_list = p_draw_list;
 	RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format;
 	RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format;
 
 
@@ -491,12 +493,12 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
 
 
 		//skeleton and blend shape
 		//skeleton and blend shape
 		if (surf->owner->mesh_instance.is_valid()) {
 		if (surf->owner->mesh_instance.is_valid()) {
-			storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
+			mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
 		} else {
 		} else {
-			storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
+			mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
 		}
 		}
 
 
-		index_array_rd = storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index);
+		index_array_rd = mesh_storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index);
 
 
 		if (prev_vertex_array_rd != vertex_array_rd) {
 		if (prev_vertex_array_rd != vertex_array_rd) {
 			RD::get_singleton()->draw_list_bind_vertex_array(draw_list, vertex_array_rd);
 			RD::get_singleton()->draw_list_bind_vertex_array(draw_list, vertex_array_rd);
@@ -963,6 +965,8 @@ _FORCE_INLINE_ static uint32_t _indices_to_primitives(RS::PrimitiveType p_primit
 	return (p_indices - subtractor[p_primitive]) / divisor[p_primitive];
 	return (p_indices - subtractor[p_primitive]) / divisor[p_primitive];
 }
 }
 void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_using_sdfgi, bool p_using_opaque_gi, bool p_append) {
 void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_using_sdfgi, bool p_using_opaque_gi, bool p_append) {
+	RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
+
 	if (p_render_list == RENDER_LIST_OPAQUE) {
 	if (p_render_list == RENDER_LIST_OPAQUE) {
 		scene_state.used_sss = false;
 		scene_state.used_sss = false;
 		scene_state.used_screen_texture = false;
 		scene_state.used_screen_texture = false;
@@ -1099,7 +1103,7 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
 
 
 			// LOD
 			// LOD
 
 
-			if (p_render_data->screen_mesh_lod_threshold > 0.0 && storage->mesh_surface_has_lod(surf->surface)) {
+			if (p_render_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) {
 				//lod
 				//lod
 				Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->lod_camera_plane.normal);
 				Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->lod_camera_plane.normal);
 				Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->lod_camera_plane.normal);
 				Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->lod_camera_plane.normal);
@@ -1123,7 +1127,7 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
 				}
 				}
 
 
 				uint32_t indices;
 				uint32_t indices;
-				surf->sort.lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, &indices);
+				surf->sort.lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, &indices);
 				if (p_render_data->render_info) {
 				if (p_render_data->render_info) {
 					indices = _indices_to_primitives(surf->primitive, indices);
 					indices = _indices_to_primitives(surf->primitive, indices);
 					if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
 					if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
@@ -1135,13 +1139,13 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
 			} else {
 			} else {
 				surf->sort.lod_index = 0;
 				surf->sort.lod_index = 0;
 				if (p_render_data->render_info) {
 				if (p_render_data->render_info) {
-					uint32_t to_draw = storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+					uint32_t to_draw = mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
 					to_draw = _indices_to_primitives(surf->primitive, to_draw);
 					to_draw = _indices_to_primitives(surf->primitive, to_draw);
 					to_draw *= inst->instance_count;
 					to_draw *= inst->instance_count;
 					if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
 					if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
-						p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+						p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
 					} else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow
 					} else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow
-						p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+						p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
 					}
 					}
 				}
 				}
 			}
 			}
@@ -2610,6 +2614,8 @@ void RenderForwardClustered::_geometry_instance_mark_dirty(GeometryInstance *p_g
 }
 }
 
 
 void RenderForwardClustered::_geometry_instance_add_surface_with_material(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, SceneShaderForwardClustered::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) {
 void RenderForwardClustered::_geometry_instance_add_surface_with_material(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, SceneShaderForwardClustered::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) {
+	RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
+
 	bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture;
 	bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture;
 	bool has_base_alpha = (p_material->shader_data->uses_alpha && !p_material->shader_data->uses_alpha_clip) || has_read_screen_alpha;
 	bool has_base_alpha = (p_material->shader_data->uses_alpha && !p_material->shader_data->uses_alpha_clip) || has_read_screen_alpha;
 	bool has_blend_alpha = p_material->shader_data->uses_blend_alpha;
 	bool has_blend_alpha = p_material->shader_data->uses_blend_alpha;
@@ -2660,10 +2666,10 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet
 		flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
 		flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
 		material_shadow = (SceneShaderForwardClustered::MaterialData *)RendererRD::MaterialStorage::get_singleton()->material_get_data(scene_shader.default_material, RendererRD::SHADER_TYPE_3D);
 		material_shadow = (SceneShaderForwardClustered::MaterialData *)RendererRD::MaterialStorage::get_singleton()->material_get_data(scene_shader.default_material, RendererRD::SHADER_TYPE_3D);
 
 
-		RID shadow_mesh = storage->mesh_get_shadow_mesh(p_mesh);
+		RID shadow_mesh = mesh_storage->mesh_get_shadow_mesh(p_mesh);
 
 
 		if (shadow_mesh.is_valid()) {
 		if (shadow_mesh.is_valid()) {
-			surface_shadow = storage->mesh_get_surface(shadow_mesh, p_surface);
+			surface_shadow = mesh_storage->mesh_get_surface(shadow_mesh, p_surface);
 		}
 		}
 
 
 	} else {
 	} else {
@@ -2676,8 +2682,8 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet
 
 
 	sdcache->shader = p_material->shader_data;
 	sdcache->shader = p_material->shader_data;
 	sdcache->material_uniform_set = p_material->uniform_set;
 	sdcache->material_uniform_set = p_material->uniform_set;
-	sdcache->surface = storage->mesh_get_surface(p_mesh, p_surface);
-	sdcache->primitive = storage->mesh_surface_get_primitive(sdcache->surface);
+	sdcache->surface = mesh_storage->mesh_get_surface(p_mesh, p_surface);
+	sdcache->primitive = mesh_storage->mesh_surface_get_primitive(sdcache->surface);
 	sdcache->surface_index = p_surface;
 	sdcache->surface_index = p_surface;
 
 
 	if (ginstance->data->dirty_dependencies) {
 	if (ginstance->data->dirty_dependencies) {
@@ -2773,6 +2779,7 @@ void RenderForwardClustered::_geometry_instance_add_surface(GeometryInstanceForw
 }
 }
 
 
 void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geometry_instance) {
 void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geometry_instance) {
+	RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
 	GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
 	GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
 
 
 	if (ginstance->data->dirty_dependencies) {
 	if (ginstance->data->dirty_dependencies) {
@@ -2786,7 +2793,7 @@ void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geome
 			uint32_t surface_count;
 			uint32_t surface_count;
 			RID mesh = ginstance->data->base;
 			RID mesh = ginstance->data->base;
 
 
-			materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count);
+			materials = mesh_storage->mesh_get_surface_count_and_materials(mesh, surface_count);
 			if (materials) {
 			if (materials) {
 				//if no materials, no surfaces.
 				//if no materials, no surfaces.
 				const RID *inst_materials = ginstance->data->surface_materials.ptr();
 				const RID *inst_materials = ginstance->data->surface_materials.ptr();
@@ -2803,19 +2810,19 @@ void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geome
 		} break;
 		} break;
 
 
 		case RS::INSTANCE_MULTIMESH: {
 		case RS::INSTANCE_MULTIMESH: {
-			RID mesh = storage->multimesh_get_mesh(ginstance->data->base);
+			RID mesh = mesh_storage->multimesh_get_mesh(ginstance->data->base);
 			if (mesh.is_valid()) {
 			if (mesh.is_valid()) {
 				const RID *materials = nullptr;
 				const RID *materials = nullptr;
 				uint32_t surface_count;
 				uint32_t surface_count;
 
 
-				materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count);
+				materials = mesh_storage->mesh_get_surface_count_and_materials(mesh, surface_count);
 				if (materials) {
 				if (materials) {
 					for (uint32_t j = 0; j < surface_count; j++) {
 					for (uint32_t j = 0; j < surface_count; j++) {
 						_geometry_instance_add_surface(ginstance, j, materials[j], mesh);
 						_geometry_instance_add_surface(ginstance, j, materials[j], mesh);
 					}
 					}
 				}
 				}
 
 
-				ginstance->instance_count = storage->multimesh_get_instances_to_draw(ginstance->data->base);
+				ginstance->instance_count = mesh_storage->multimesh_get_instances_to_draw(ginstance->data->base);
 			}
 			}
 
 
 		} break;
 		} break;
@@ -2840,7 +2847,7 @@ void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geome
 				const RID *materials = nullptr;
 				const RID *materials = nullptr;
 				uint32_t surface_count;
 				uint32_t surface_count;
 
 
-				materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count);
+				materials = mesh_storage->mesh_get_surface_count_and_materials(mesh, surface_count);
 				if (materials) {
 				if (materials) {
 					for (uint32_t k = 0; k < surface_count; k++) {
 					for (uint32_t k = 0; k < surface_count; k++) {
 						_geometry_instance_add_surface(ginstance, k, materials[k], mesh);
 						_geometry_instance_add_surface(ginstance, k, materials[k], mesh);
@@ -2864,17 +2871,17 @@ void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geome
 
 
 	if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
 	if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
 		ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
 		ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
-		if (storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) {
+		if (mesh_storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) {
 			ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
 			ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
 		}
 		}
-		if (storage->multimesh_uses_colors(ginstance->data->base)) {
+		if (mesh_storage->multimesh_uses_colors(ginstance->data->base)) {
 			ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
 			ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
 		}
 		}
-		if (storage->multimesh_uses_custom_data(ginstance->data->base)) {
+		if (mesh_storage->multimesh_uses_custom_data(ginstance->data->base)) {
 			ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
 			ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
 		}
 		}
 
 
-		ginstance->transforms_uniform_set = storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
+		ginstance->transforms_uniform_set = mesh_storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
 
 
 	} else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) {
 	} else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) {
 		ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
 		ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
@@ -2891,10 +2898,10 @@ void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geome
 		ginstance->transforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
 		ginstance->transforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
 
 
 	} else if (ginstance->data->base_type == RS::INSTANCE_MESH) {
 	} else if (ginstance->data->base_type == RS::INSTANCE_MESH) {
-		if (storage->skeleton_is_valid(ginstance->data->skeleton)) {
-			ginstance->transforms_uniform_set = storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
+		if (mesh_storage->skeleton_is_valid(ginstance->data->skeleton)) {
+			ginstance->transforms_uniform_set = mesh_storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
 			if (ginstance->data->dirty_dependencies) {
 			if (ginstance->data->dirty_dependencies) {
-				storage->skeleton_update_dependency(ginstance->data->skeleton, &ginstance->data->dependency_tracker);
+				mesh_storage->skeleton_update_dependency(ginstance->data->skeleton, &ginstance->data->dependency_tracker);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -2934,7 +2941,7 @@ void RenderForwardClustered::_geometry_instance_dependency_changed(RendererStora
 		case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: {
 		case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: {
 			GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_tracker->userdata);
 			GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_tracker->userdata);
 			if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
 			if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
-				ginstance->instance_count = static_cast<RenderForwardClustered *>(singleton)->storage->multimesh_get_instances_to_draw(ginstance->data->base);
+				ginstance->instance_count = RendererRD::MeshStorage::get_singleton()->multimesh_get_instances_to_draw(ginstance->data->base);
 			}
 			}
 		} break;
 		} break;
 		default: {
 		default: {

+ 33 - 25
servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp

@@ -31,6 +31,7 @@
 #include "render_forward_mobile.h"
 #include "render_forward_mobile.h"
 #include "core/config/project_settings.h"
 #include "core/config/project_settings.h"
 #include "servers/rendering/renderer_rd/storage_rd/decal_atlas_storage.h"
 #include "servers/rendering/renderer_rd/storage_rd/decal_atlas_storage.h"
+#include "servers/rendering/renderer_rd/storage_rd/mesh_storage.h"
 #include "servers/rendering/rendering_device.h"
 #include "servers/rendering/rendering_device.h"
 #include "servers/rendering/rendering_server_default.h"
 #include "servers/rendering/rendering_server_default.h"
 
 
@@ -1325,6 +1326,8 @@ _FORCE_INLINE_ static uint32_t _indices_to_primitives(RS::PrimitiveType p_primit
 }
 }
 
 
 void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append) {
 void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append) {
+	RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
+
 	if (p_render_list == RENDER_LIST_OPAQUE) {
 	if (p_render_list == RENDER_LIST_OPAQUE) {
 		scene_state.used_sss = false;
 		scene_state.used_sss = false;
 		scene_state.used_screen_texture = false;
 		scene_state.used_screen_texture = false;
@@ -1414,7 +1417,7 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
 
 
 			// LOD
 			// LOD
 
 
-			if (p_render_data->screen_mesh_lod_threshold > 0.0 && storage->mesh_surface_has_lod(surf->surface)) {
+			if (p_render_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) {
 				//lod
 				//lod
 				Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->lod_camera_plane.normal);
 				Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->lod_camera_plane.normal);
 				Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->lod_camera_plane.normal);
 				Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->lod_camera_plane.normal);
@@ -1438,7 +1441,7 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
 				}
 				}
 
 
 				uint32_t indices;
 				uint32_t indices;
-				surf->lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, &indices);
+				surf->lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, &indices);
 				if (p_render_data->render_info) {
 				if (p_render_data->render_info) {
 					indices = _indices_to_primitives(surf->primitive, indices);
 					indices = _indices_to_primitives(surf->primitive, indices);
 					if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
 					if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
@@ -1450,13 +1453,13 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
 			} else {
 			} else {
 				surf->lod_index = 0;
 				surf->lod_index = 0;
 				if (p_render_data->render_info) {
 				if (p_render_data->render_info) {
-					uint32_t to_draw = storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+					uint32_t to_draw = mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
 					to_draw = _indices_to_primitives(surf->primitive, to_draw);
 					to_draw = _indices_to_primitives(surf->primitive, to_draw);
 					to_draw *= inst->instance_count;
 					to_draw *= inst->instance_count;
 					if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
 					if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
-						p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+						p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
 					} else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow
 					} else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow
-						p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+						p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
 					}
 					}
 				}
 				}
 			}
 			}
@@ -1814,6 +1817,8 @@ void RenderForwardMobile::_fill_push_constant_instance_indices(GeometryInstanceF
 
 
 template <RenderForwardMobile::PassMode p_pass_mode>
 template <RenderForwardMobile::PassMode p_pass_mode>
 void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
 void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
+	RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
+
 	RD::DrawListID draw_list = p_draw_list;
 	RD::DrawListID draw_list = p_draw_list;
 	RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format;
 	RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format;
 
 
@@ -1956,12 +1961,12 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
 
 
 		//skeleton and blend shape
 		//skeleton and blend shape
 		if (surf->owner->mesh_instance.is_valid()) {
 		if (surf->owner->mesh_instance.is_valid()) {
-			storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
+			mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
 		} else {
 		} else {
-			storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
+			mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
 		}
 		}
 
 
-		index_array_rd = storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index);
+		index_array_rd = mesh_storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index);
 
 
 		if (prev_vertex_array_rd != vertex_array_rd) {
 		if (prev_vertex_array_rd != vertex_array_rd) {
 			RD::get_singleton()->draw_list_bind_vertex_array(draw_list, vertex_array_rd);
 			RD::get_singleton()->draw_list_bind_vertex_array(draw_list, vertex_array_rd);
@@ -2280,6 +2285,8 @@ void RenderForwardMobile::_geometry_instance_mark_dirty(GeometryInstance *p_geom
 }
 }
 
 
 void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) {
 void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) {
+	RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
+
 	bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture;
 	bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture;
 	bool has_base_alpha = ((p_material->shader_data->uses_alpha && !p_material->shader_data->uses_alpha_clip) || has_read_screen_alpha);
 	bool has_base_alpha = ((p_material->shader_data->uses_alpha && !p_material->shader_data->uses_alpha_clip) || has_read_screen_alpha);
 	bool has_blend_alpha = p_material->shader_data->uses_blend_alpha;
 	bool has_blend_alpha = p_material->shader_data->uses_blend_alpha;
@@ -2330,10 +2337,10 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI
 		flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
 		flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
 		material_shadow = (SceneShaderForwardMobile::MaterialData *)RendererRD::MaterialStorage::get_singleton()->material_get_data(scene_shader.default_material, RendererRD::SHADER_TYPE_3D);
 		material_shadow = (SceneShaderForwardMobile::MaterialData *)RendererRD::MaterialStorage::get_singleton()->material_get_data(scene_shader.default_material, RendererRD::SHADER_TYPE_3D);
 
 
-		RID shadow_mesh = storage->mesh_get_shadow_mesh(p_mesh);
+		RID shadow_mesh = mesh_storage->mesh_get_shadow_mesh(p_mesh);
 
 
 		if (shadow_mesh.is_valid()) {
 		if (shadow_mesh.is_valid()) {
-			surface_shadow = storage->mesh_get_surface(shadow_mesh, p_surface);
+			surface_shadow = mesh_storage->mesh_get_surface(shadow_mesh, p_surface);
 		}
 		}
 
 
 	} else {
 	} else {
@@ -2346,8 +2353,8 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI
 
 
 	sdcache->shader = p_material->shader_data;
 	sdcache->shader = p_material->shader_data;
 	sdcache->material_uniform_set = p_material->uniform_set;
 	sdcache->material_uniform_set = p_material->uniform_set;
-	sdcache->surface = storage->mesh_get_surface(p_mesh, p_surface);
-	sdcache->primitive = storage->mesh_surface_get_primitive(sdcache->surface);
+	sdcache->surface = mesh_storage->mesh_get_surface(p_mesh, p_surface);
+	sdcache->primitive = mesh_storage->mesh_surface_get_primitive(sdcache->surface);
 	sdcache->surface_index = p_surface;
 	sdcache->surface_index = p_surface;
 
 
 	if (ginstance->data->dirty_dependencies) {
 	if (ginstance->data->dirty_dependencies) {
@@ -2441,6 +2448,7 @@ void RenderForwardMobile::_geometry_instance_add_surface(GeometryInstanceForward
 }
 }
 
 
 void RenderForwardMobile::_geometry_instance_update(GeometryInstance *p_geometry_instance) {
 void RenderForwardMobile::_geometry_instance_update(GeometryInstance *p_geometry_instance) {
+	RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
 	GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
 	GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
 
 
 	if (ginstance->data->dirty_dependencies) {
 	if (ginstance->data->dirty_dependencies) {
@@ -2454,7 +2462,7 @@ void RenderForwardMobile::_geometry_instance_update(GeometryInstance *p_geometry
 			uint32_t surface_count;
 			uint32_t surface_count;
 			RID mesh = ginstance->data->base;
 			RID mesh = ginstance->data->base;
 
 
-			materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count);
+			materials = mesh_storage->mesh_get_surface_count_and_materials(mesh, surface_count);
 			if (materials) {
 			if (materials) {
 				//if no materials, no surfaces.
 				//if no materials, no surfaces.
 				const RID *inst_materials = ginstance->data->surface_materials.ptr();
 				const RID *inst_materials = ginstance->data->surface_materials.ptr();
@@ -2471,19 +2479,19 @@ void RenderForwardMobile::_geometry_instance_update(GeometryInstance *p_geometry
 		} break;
 		} break;
 
 
 		case RS::INSTANCE_MULTIMESH: {
 		case RS::INSTANCE_MULTIMESH: {
-			RID mesh = storage->multimesh_get_mesh(ginstance->data->base);
+			RID mesh = mesh_storage->multimesh_get_mesh(ginstance->data->base);
 			if (mesh.is_valid()) {
 			if (mesh.is_valid()) {
 				const RID *materials = nullptr;
 				const RID *materials = nullptr;
 				uint32_t surface_count;
 				uint32_t surface_count;
 
 
-				materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count);
+				materials = mesh_storage->mesh_get_surface_count_and_materials(mesh, surface_count);
 				if (materials) {
 				if (materials) {
 					for (uint32_t j = 0; j < surface_count; j++) {
 					for (uint32_t j = 0; j < surface_count; j++) {
 						_geometry_instance_add_surface(ginstance, j, materials[j], mesh);
 						_geometry_instance_add_surface(ginstance, j, materials[j], mesh);
 					}
 					}
 				}
 				}
 
 
-				ginstance->instance_count = storage->multimesh_get_instances_to_draw(ginstance->data->base);
+				ginstance->instance_count = mesh_storage->multimesh_get_instances_to_draw(ginstance->data->base);
 			}
 			}
 
 
 		} break;
 		} break;
@@ -2508,7 +2516,7 @@ void RenderForwardMobile::_geometry_instance_update(GeometryInstance *p_geometry
 				const RID *materials = nullptr;
 				const RID *materials = nullptr;
 				uint32_t surface_count;
 				uint32_t surface_count;
 
 
-				materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count);
+				materials = mesh_storage->mesh_get_surface_count_and_materials(mesh, surface_count);
 				if (materials) {
 				if (materials) {
 					for (uint32_t k = 0; k < surface_count; k++) {
 					for (uint32_t k = 0; k < surface_count; k++) {
 						_geometry_instance_add_surface(ginstance, k, materials[k], mesh);
 						_geometry_instance_add_surface(ginstance, k, materials[k], mesh);
@@ -2531,17 +2539,17 @@ void RenderForwardMobile::_geometry_instance_update(GeometryInstance *p_geometry
 
 
 	if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
 	if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
 		ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
 		ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
-		if (storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) {
+		if (mesh_storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) {
 			ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
 			ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
 		}
 		}
-		if (storage->multimesh_uses_colors(ginstance->data->base)) {
+		if (mesh_storage->multimesh_uses_colors(ginstance->data->base)) {
 			ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
 			ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
 		}
 		}
-		if (storage->multimesh_uses_custom_data(ginstance->data->base)) {
+		if (mesh_storage->multimesh_uses_custom_data(ginstance->data->base)) {
 			ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
 			ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
 		}
 		}
 
 
-		ginstance->transforms_uniform_set = storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
+		ginstance->transforms_uniform_set = mesh_storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
 
 
 	} else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) {
 	} else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) {
 		ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
 		ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
@@ -2561,10 +2569,10 @@ void RenderForwardMobile::_geometry_instance_update(GeometryInstance *p_geometry
 		ginstance->transforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
 		ginstance->transforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
 
 
 	} else if (ginstance->data->base_type == RS::INSTANCE_MESH) {
 	} else if (ginstance->data->base_type == RS::INSTANCE_MESH) {
-		if (storage->skeleton_is_valid(ginstance->data->skeleton)) {
-			ginstance->transforms_uniform_set = storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
+		if (mesh_storage->skeleton_is_valid(ginstance->data->skeleton)) {
+			ginstance->transforms_uniform_set = mesh_storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
 			if (ginstance->data->dirty_dependencies) {
 			if (ginstance->data->dirty_dependencies) {
-				storage->skeleton_update_dependency(ginstance->data->skeleton, &ginstance->data->dependency_tracker);
+				mesh_storage->skeleton_update_dependency(ginstance->data->skeleton, &ginstance->data->dependency_tracker);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -2597,7 +2605,7 @@ void RenderForwardMobile::_geometry_instance_dependency_changed(RendererStorage:
 		case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: {
 		case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: {
 			GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_tracker->userdata);
 			GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_tracker->userdata);
 			if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
 			if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
-				ginstance->instance_count = static_cast<RenderForwardMobile *>(singleton)->storage->multimesh_get_instances_to_draw(ginstance->data->base);
+				ginstance->instance_count = RendererRD::MeshStorage::get_singleton()->multimesh_get_instances_to_draw(ginstance->data->base);
 			}
 			}
 		} break;
 		} break;
 		default: {
 		default: {

+ 26 - 22
servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp

@@ -109,6 +109,8 @@ RendererCanvasRender::PolygonID RendererCanvasRenderRD::request_polygon(const Ve
 	// This dramatically reduces the amount of pipeline objects
 	// This dramatically reduces the amount of pipeline objects
 	// that need to be created for these formats.
 	// that need to be created for these formats.
 
 
+	RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
+
 	uint32_t vertex_count = p_points.size();
 	uint32_t vertex_count = p_points.size();
 	uint32_t stride = 2; //vertices always repeat
 	uint32_t stride = 2; //vertices always repeat
 	if ((uint32_t)p_colors.size() == vertex_count || p_colors.size() == 1) {
 	if ((uint32_t)p_colors.size() == vertex_count || p_colors.size() == 1) {
@@ -191,7 +193,7 @@ RendererCanvasRender::PolygonID RendererCanvasRenderRD::request_polygon(const Ve
 			vd.stride = 0;
 			vd.stride = 0;
 
 
 			descriptions.write[1] = vd;
 			descriptions.write[1] = vd;
-			buffers.write[1] = storage->mesh_get_default_rd_buffer(RendererStorageRD::DEFAULT_RD_BUFFER_COLOR);
+			buffers.write[1] = mesh_storage->mesh_get_default_rd_buffer(RendererRD::DEFAULT_RD_BUFFER_COLOR);
 		}
 		}
 
 
 		//uvs
 		//uvs
@@ -219,7 +221,7 @@ RendererCanvasRender::PolygonID RendererCanvasRenderRD::request_polygon(const Ve
 			vd.stride = 0;
 			vd.stride = 0;
 
 
 			descriptions.write[2] = vd;
 			descriptions.write[2] = vd;
-			buffers.write[2] = storage->mesh_get_default_rd_buffer(RendererStorageRD::DEFAULT_RD_BUFFER_TEX_UV);
+			buffers.write[2] = mesh_storage->mesh_get_default_rd_buffer(RendererRD::DEFAULT_RD_BUFFER_TEX_UV);
 		}
 		}
 
 
 		//bones
 		//bones
@@ -252,7 +254,7 @@ RendererCanvasRender::PolygonID RendererCanvasRenderRD::request_polygon(const Ve
 			vd.stride = 0;
 			vd.stride = 0;
 
 
 			descriptions.write[3] = vd;
 			descriptions.write[3] = vd;
-			buffers.write[3] = storage->mesh_get_default_rd_buffer(RendererStorageRD::DEFAULT_RD_BUFFER_BONES);
+			buffers.write[3] = mesh_storage->mesh_get_default_rd_buffer(RendererRD::DEFAULT_RD_BUFFER_BONES);
 		}
 		}
 
 
 		//weights
 		//weights
@@ -285,7 +287,7 @@ RendererCanvasRender::PolygonID RendererCanvasRenderRD::request_polygon(const Ve
 			vd.stride = 0;
 			vd.stride = 0;
 
 
 			descriptions.write[4] = vd;
 			descriptions.write[4] = vd;
-			buffers.write[4] = storage->mesh_get_default_rd_buffer(RendererStorageRD::DEFAULT_RD_BUFFER_WEIGHTS);
+			buffers.write[4] = mesh_storage->mesh_get_default_rd_buffer(RendererRD::DEFAULT_RD_BUFFER_WEIGHTS);
 		}
 		}
 
 
 		//check that everything is as it should be
 		//check that everything is as it should be
@@ -399,6 +401,7 @@ void RendererCanvasRenderRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RI
 
 
 void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants) {
 void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants) {
 	//create an empty push constant
 	//create an empty push constant
+	RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
 
 
 	RS::CanvasItemTextureFilter current_filter = default_filter;
 	RS::CanvasItemTextureFilter current_filter = default_filter;
 	RS::CanvasItemTextureRepeat current_repeat = default_repeat;
 	RS::CanvasItemTextureRepeat current_repeat = default_repeat;
@@ -753,26 +756,26 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
 				} else if (c->type == Item::Command::TYPE_MULTIMESH) {
 				} else if (c->type == Item::Command::TYPE_MULTIMESH) {
 					const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(c);
 					const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(c);
 					RID multimesh = mm->multimesh;
 					RID multimesh = mm->multimesh;
-					mesh = storage->multimesh_get_mesh(multimesh);
+					mesh = mesh_storage->multimesh_get_mesh(multimesh);
 					texture = mm->texture;
 					texture = mm->texture;
 
 
-					if (storage->multimesh_get_transform_format(multimesh) != RS::MULTIMESH_TRANSFORM_2D) {
+					if (mesh_storage->multimesh_get_transform_format(multimesh) != RS::MULTIMESH_TRANSFORM_2D) {
 						break;
 						break;
 					}
 					}
 
 
-					instance_count = storage->multimesh_get_instances_to_draw(multimesh);
+					instance_count = mesh_storage->multimesh_get_instances_to_draw(multimesh);
 
 
 					if (instance_count == 0) {
 					if (instance_count == 0) {
 						break;
 						break;
 					}
 					}
 
 
-					RID uniform_set = storage->multimesh_get_2d_uniform_set(multimesh, shader.default_version_rd_shader, TRANSFORMS_UNIFORM_SET);
+					RID uniform_set = mesh_storage->multimesh_get_2d_uniform_set(multimesh, shader.default_version_rd_shader, TRANSFORMS_UNIFORM_SET);
 					RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, uniform_set, TRANSFORMS_UNIFORM_SET);
 					RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, uniform_set, TRANSFORMS_UNIFORM_SET);
 					push_constant.flags |= 1; //multimesh, trails disabled
 					push_constant.flags |= 1; //multimesh, trails disabled
-					if (storage->multimesh_uses_colors(multimesh)) {
+					if (mesh_storage->multimesh_uses_colors(multimesh)) {
 						push_constant.flags |= FLAGS_INSTANCING_HAS_COLORS;
 						push_constant.flags |= FLAGS_INSTANCING_HAS_COLORS;
 					}
 					}
-					if (storage->multimesh_uses_custom_data(multimesh)) {
+					if (mesh_storage->multimesh_uses_custom_data(multimesh)) {
 						push_constant.flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;
 						push_constant.flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;
 					}
 					}
 				} else if (c->type == Item::Command::TYPE_PARTICLES) {
 				} else if (c->type == Item::Command::TYPE_PARTICLES) {
@@ -837,7 +840,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
 
 
 				_bind_canvas_texture(p_draw_list, texture, current_filter, current_repeat, last_texture, push_constant, texpixel_size);
 				_bind_canvas_texture(p_draw_list, texture, current_filter, current_repeat, last_texture, push_constant, texpixel_size);
 
 
-				uint32_t surf_count = storage->mesh_get_surface_count(mesh);
+				uint32_t surf_count = mesh_storage->mesh_get_surface_count(mesh);
 				static const PipelineVariant variant[RS::PRIMITIVE_MAX] = { PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_ATTRIBUTE_LINES, PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP };
 				static const PipelineVariant variant[RS::PRIMITIVE_MAX] = { PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_ATTRIBUTE_LINES, PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP };
 
 
 				push_constant.modulation[0] = base_color.r * modulate.r;
 				push_constant.modulation[0] = base_color.r * modulate.r;
@@ -852,9 +855,9 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
 				}
 				}
 
 
 				for (uint32_t j = 0; j < surf_count; j++) {
 				for (uint32_t j = 0; j < surf_count; j++) {
-					void *surface = storage->mesh_get_surface(mesh, j);
+					void *surface = mesh_storage->mesh_get_surface(mesh, j);
 
 
-					RS::PrimitiveType primitive = storage->mesh_surface_get_primitive(surface);
+					RS::PrimitiveType primitive = mesh_storage->mesh_surface_get_primitive(surface);
 					ERR_CONTINUE(primitive < 0 || primitive >= RS::PRIMITIVE_MAX);
 					ERR_CONTINUE(primitive < 0 || primitive >= RS::PRIMITIVE_MAX);
 
 
 					uint32_t input_mask = pipeline_variants->variants[light_mode][variant[primitive]].get_vertex_input_mask();
 					uint32_t input_mask = pipeline_variants->variants[light_mode][variant[primitive]].get_vertex_input_mask();
@@ -863,15 +866,15 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
 					RD::VertexFormatID vertex_format = RD::INVALID_FORMAT_ID;
 					RD::VertexFormatID vertex_format = RD::INVALID_FORMAT_ID;
 
 
 					if (mesh_instance.is_valid()) {
 					if (mesh_instance.is_valid()) {
-						storage->mesh_instance_surface_get_vertex_arrays_and_format(mesh_instance, j, input_mask, vertex_array, vertex_format);
+						mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(mesh_instance, j, input_mask, vertex_array, vertex_format);
 					} else {
 					} else {
-						storage->mesh_surface_get_vertex_arrays_and_format(surface, input_mask, vertex_array, vertex_format);
+						mesh_storage->mesh_surface_get_vertex_arrays_and_format(surface, input_mask, vertex_array, vertex_format);
 					}
 					}
 
 
 					RID pipeline = pipeline_variants->variants[light_mode][variant[primitive]].get_render_pipeline(vertex_format, p_framebuffer_format);
 					RID pipeline = pipeline_variants->variants[light_mode][variant[primitive]].get_render_pipeline(vertex_format, p_framebuffer_format);
 					RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
 					RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
 
 
-					RID index_array = storage->mesh_surface_get_index_array(surface, 0);
+					RID index_array = mesh_storage->mesh_surface_get_index_array(surface, 0);
 
 
 					if (index_array.is_valid()) {
 					if (index_array.is_valid()) {
 						RD::get_singleton()->draw_list_bind_index_array(p_draw_list, index_array);
 						RD::get_singleton()->draw_list_bind_index_array(p_draw_list, index_array);
@@ -1134,6 +1137,7 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co
 
 
 void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) {
 void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) {
 	RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
 	RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
+	RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
 
 
 	r_sdf_used = false;
 	r_sdf_used = false;
 	int item_count = 0;
 	int item_count = 0;
@@ -1395,7 +1399,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
 				if (c->type == Item::Command::TYPE_MESH) {
 				if (c->type == Item::Command::TYPE_MESH) {
 					const Item::CommandMesh *cm = static_cast<const Item::CommandMesh *>(c);
 					const Item::CommandMesh *cm = static_cast<const Item::CommandMesh *>(c);
 					if (cm->mesh_instance.is_valid()) {
 					if (cm->mesh_instance.is_valid()) {
-						storage->mesh_instance_check_for_update(cm->mesh_instance);
+						mesh_storage->mesh_instance_check_for_update(cm->mesh_instance);
 						update_skeletons = true;
 						update_skeletons = true;
 					}
 					}
 				}
 				}
@@ -1407,7 +1411,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
 			if (canvas_group_owner == nullptr) {
 			if (canvas_group_owner == nullptr) {
 				//Canvas group begins here, render until before this item
 				//Canvas group begins here, render until before this item
 				if (update_skeletons) {
 				if (update_skeletons) {
-					storage->update_mesh_instances();
+					mesh_storage->update_mesh_instances();
 					update_skeletons = false;
 					update_skeletons = false;
 				}
 				}
 				_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
 				_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
@@ -1430,7 +1434,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
 
 
 		if (ci == canvas_group_owner) {
 		if (ci == canvas_group_owner) {
 			if (update_skeletons) {
 			if (update_skeletons) {
-				storage->update_mesh_instances();
+				mesh_storage->update_mesh_instances();
 				update_skeletons = false;
 				update_skeletons = false;
 			}
 			}
 
 
@@ -1447,7 +1451,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
 		if (backbuffer_copy) {
 		if (backbuffer_copy) {
 			//render anything pending, including clearing if no items
 			//render anything pending, including clearing if no items
 			if (update_skeletons) {
 			if (update_skeletons) {
-				storage->update_mesh_instances();
+				mesh_storage->update_mesh_instances();
 				update_skeletons = false;
 				update_skeletons = false;
 			}
 			}
 			_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
 			_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
@@ -1463,7 +1467,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
 
 
 		if (!ci->next || item_count == MAX_RENDER_ITEMS - 1) {
 		if (!ci->next || item_count == MAX_RENDER_ITEMS - 1) {
 			if (update_skeletons) {
 			if (update_skeletons) {
-				storage->update_mesh_instances();
+				mesh_storage->update_mesh_instances();
 				update_skeletons = false;
 				update_skeletons = false;
 			}
 			}
 
 
@@ -2579,7 +2583,7 @@ RendererCanvasRenderRD::RendererCanvasRenderRD(RendererStorageRD *p_storage) {
 			RD::Uniform u;
 			RD::Uniform u;
 			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
 			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
 			u.binding = 0;
 			u.binding = 0;
-			u.append_id(storage->get_default_rd_storage_buffer());
+			u.append_id(RendererRD::MeshStorage::get_singleton()->get_default_rd_storage_buffer());
 			uniforms.push_back(u);
 			uniforms.push_back(u);
 		}
 		}
 
 

+ 2 - 0
servers/rendering/renderer_rd/renderer_compositor_rd.cpp

@@ -156,6 +156,7 @@ void RendererCompositorRD::finalize() {
 	memdelete(canvas);
 	memdelete(canvas);
 	memdelete(storage);
 	memdelete(storage);
 	memdelete(decal_atlas_storage);
 	memdelete(decal_atlas_storage);
+	memdelete(mesh_storage);
 	memdelete(material_storage);
 	memdelete(material_storage);
 	memdelete(texture_storage);
 	memdelete(texture_storage);
 	memdelete(canvas_texture_storage);
 	memdelete(canvas_texture_storage);
@@ -291,6 +292,7 @@ RendererCompositorRD::RendererCompositorRD() {
 	texture_storage = memnew(RendererRD::TextureStorage);
 	texture_storage = memnew(RendererRD::TextureStorage);
 	decal_atlas_storage = memnew(RendererRD::DecalAtlasStorage);
 	decal_atlas_storage = memnew(RendererRD::DecalAtlasStorage);
 	material_storage = memnew(RendererRD::MaterialStorage);
 	material_storage = memnew(RendererRD::MaterialStorage);
+	mesh_storage = memnew(RendererRD::MeshStorage);
 	storage = memnew(RendererStorageRD);
 	storage = memnew(RendererStorageRD);
 	canvas = memnew(RendererCanvasRenderRD(storage));
 	canvas = memnew(RendererCanvasRenderRD(storage));
 
 

+ 3 - 0
servers/rendering/renderer_rd/renderer_compositor_rd.h

@@ -42,6 +42,7 @@
 #include "servers/rendering/renderer_rd/storage_rd/canvas_texture_storage.h"
 #include "servers/rendering/renderer_rd/storage_rd/canvas_texture_storage.h"
 #include "servers/rendering/renderer_rd/storage_rd/decal_atlas_storage.h"
 #include "servers/rendering/renderer_rd/storage_rd/decal_atlas_storage.h"
 #include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
 #include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
+#include "servers/rendering/renderer_rd/storage_rd/mesh_storage.h"
 #include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
 #include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
 #include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
 #include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
 
 
@@ -51,6 +52,7 @@ protected:
 	RendererCanvasRenderRD *canvas;
 	RendererCanvasRenderRD *canvas;
 	RendererRD::CanvasTextureStorage *canvas_texture_storage;
 	RendererRD::CanvasTextureStorage *canvas_texture_storage;
 	RendererRD::MaterialStorage *material_storage;
 	RendererRD::MaterialStorage *material_storage;
+	RendererRD::MeshStorage *mesh_storage;
 	RendererRD::TextureStorage *texture_storage;
 	RendererRD::TextureStorage *texture_storage;
 	RendererRD::DecalAtlasStorage *decal_atlas_storage;
 	RendererRD::DecalAtlasStorage *decal_atlas_storage;
 	RendererStorageRD *storage;
 	RendererStorageRD *storage;
@@ -99,6 +101,7 @@ public:
 	RendererCanvasTextureStorage *get_canvas_texture_storage() { return canvas_texture_storage; }
 	RendererCanvasTextureStorage *get_canvas_texture_storage() { return canvas_texture_storage; }
 	RendererDecalAtlasStorage *get_decal_atlas_storage() { return decal_atlas_storage; }
 	RendererDecalAtlasStorage *get_decal_atlas_storage() { return decal_atlas_storage; }
 	RendererMaterialStorage *get_material_storage() { return material_storage; };
 	RendererMaterialStorage *get_material_storage() { return material_storage; };
+	RendererMeshStorage *get_mesh_storage() { return mesh_storage; };
 	RendererTextureStorage *get_texture_storage() { return texture_storage; };
 	RendererTextureStorage *get_texture_storage() { return texture_storage; };
 	RendererStorage *get_storage() { return storage; }
 	RendererStorage *get_storage() { return storage; }
 	RendererCanvasRender *get_canvas() { return canvas; }
 	RendererCanvasRender *get_canvas() { return canvas; }

+ 1 - 1
servers/rendering/renderer_rd/renderer_scene_render_rd.cpp

@@ -5501,7 +5501,7 @@ TypedArray<Image> RendererSceneRenderRD::bake_render_uv2(RID p_base, const Vecto
 
 
 	GeometryInstance *gi = geometry_instance_create(p_base);
 	GeometryInstance *gi = geometry_instance_create(p_base);
 
 
-	uint32_t sc = RSG::storage->mesh_get_surface_count(p_base);
+	uint32_t sc = RSG::mesh_storage->mesh_get_surface_count(p_base);
 	Vector<RID> materials;
 	Vector<RID> materials;
 	materials.resize(sc);
 	materials.resize(sc);
 
 

File diff suppressed because it is too large
+ 4 - 1483
servers/rendering/renderer_rd/renderer_storage_rd.cpp


+ 0 - 610
servers/rendering/renderer_rd/renderer_storage_rd.h

@@ -39,12 +39,8 @@
 #include "servers/rendering/renderer_rd/shaders/canvas_sdf.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/canvas_sdf.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/particles.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/particles.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/particles_copy.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/particles_copy.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/skeleton.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl.gen.h"
-#include "servers/rendering/renderer_rd/storage_rd/canvas_texture_storage.h"
-#include "servers/rendering/renderer_rd/storage_rd/decal_atlas_storage.h"
 #include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
 #include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
-#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
 #include "servers/rendering/renderer_scene_render.h"
 #include "servers/rendering/renderer_scene_render.h"
 #include "servers/rendering/rendering_device.h"
 #include "servers/rendering/rendering_device.h"
 #include "servers/rendering/shader_compiler.h"
 #include "servers/rendering/shader_compiler.h"
@@ -129,232 +125,11 @@ public:
 		}
 		}
 	}
 	}
 
 
-	enum DefaultRDBuffer {
-		DEFAULT_RD_BUFFER_VERTEX,
-		DEFAULT_RD_BUFFER_NORMAL,
-		DEFAULT_RD_BUFFER_TANGENT,
-		DEFAULT_RD_BUFFER_COLOR,
-		DEFAULT_RD_BUFFER_TEX_UV,
-		DEFAULT_RD_BUFFER_TEX_UV2,
-		DEFAULT_RD_BUFFER_CUSTOM0,
-		DEFAULT_RD_BUFFER_CUSTOM1,
-		DEFAULT_RD_BUFFER_CUSTOM2,
-		DEFAULT_RD_BUFFER_CUSTOM3,
-		DEFAULT_RD_BUFFER_BONES,
-		DEFAULT_RD_BUFFER_WEIGHTS,
-		DEFAULT_RD_BUFFER_MAX,
-	};
-
 private:
 private:
 	/* TEXTURE API */
 	/* TEXTURE API */
 
 
 	RID default_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
 	RID default_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
 	RID custom_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
 	RID custom_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
-	RID default_rd_storage_buffer;
-
-	/* Mesh */
-
-	struct MeshInstance;
-
-	struct Mesh {
-		struct Surface {
-			RS::PrimitiveType primitive = RS::PRIMITIVE_POINTS;
-			uint32_t format = 0;
-
-			RID vertex_buffer;
-			RID attribute_buffer;
-			RID skin_buffer;
-			uint32_t vertex_count = 0;
-			uint32_t vertex_buffer_size = 0;
-			uint32_t skin_buffer_size = 0;
-
-			// A different pipeline needs to be allocated
-			// depending on the inputs available in the
-			// material.
-			// There are never that many geometry/material
-			// combinations, so a simple array is the most
-			// cache-efficient structure.
-
-			struct Version {
-				uint32_t input_mask = 0;
-				RD::VertexFormatID vertex_format = 0;
-				RID vertex_array;
-			};
-
-			SpinLock version_lock; //needed to access versions
-			Version *versions = nullptr; //allocated on demand
-			uint32_t version_count = 0;
-
-			RID index_buffer;
-			RID index_array;
-			uint32_t index_count = 0;
-
-			struct LOD {
-				float edge_length = 0.0;
-				uint32_t index_count = 0;
-				RID index_buffer;
-				RID index_array;
-			};
-
-			LOD *lods = nullptr;
-			uint32_t lod_count = 0;
-
-			AABB aabb;
-
-			Vector<AABB> bone_aabbs;
-
-			RID blend_shape_buffer;
-
-			RID material;
-
-			uint32_t render_index = 0;
-			uint64_t render_pass = 0;
-
-			uint32_t multimesh_render_index = 0;
-			uint64_t multimesh_render_pass = 0;
-
-			uint32_t particles_render_index = 0;
-			uint64_t particles_render_pass = 0;
-
-			RID uniform_set;
-		};
-
-		uint32_t blend_shape_count = 0;
-		RS::BlendShapeMode blend_shape_mode = RS::BLEND_SHAPE_MODE_NORMALIZED;
-
-		Surface **surfaces = nullptr;
-		uint32_t surface_count = 0;
-
-		Vector<AABB> bone_aabbs;
-
-		bool has_bone_weights = false;
-
-		AABB aabb;
-		AABB custom_aabb;
-
-		Vector<RID> material_cache;
-
-		List<MeshInstance *> instances;
-
-		RID shadow_mesh;
-		Set<Mesh *> shadow_owners;
-
-		Dependency dependency;
-	};
-
-	mutable RID_Owner<Mesh, true> mesh_owner;
-
-	struct MeshInstance {
-		Mesh *mesh;
-		RID skeleton;
-		struct Surface {
-			RID vertex_buffer;
-			RID uniform_set;
-
-			Mesh::Surface::Version *versions = nullptr; //allocated on demand
-			uint32_t version_count = 0;
-		};
-		LocalVector<Surface> surfaces;
-		LocalVector<float> blend_weights;
-
-		RID blend_weights_buffer;
-		List<MeshInstance *>::Element *I = nullptr; //used to erase itself
-		uint64_t skeleton_version = 0;
-		bool dirty = false;
-		bool weights_dirty = false;
-		SelfList<MeshInstance> weight_update_list;
-		SelfList<MeshInstance> array_update_list;
-		MeshInstance() :
-				weight_update_list(this), array_update_list(this) {}
-	};
-
-	void _mesh_instance_clear(MeshInstance *mi);
-	void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface);
-
-	mutable RID_Owner<MeshInstance> mesh_instance_owner;
-
-	SelfList<MeshInstance>::List dirty_mesh_instance_weights;
-	SelfList<MeshInstance>::List dirty_mesh_instance_arrays;
-
-	struct SkeletonShader {
-		struct PushConstant {
-			uint32_t has_normal;
-			uint32_t has_tangent;
-			uint32_t has_skeleton;
-			uint32_t has_blend_shape;
-
-			uint32_t vertex_count;
-			uint32_t vertex_stride;
-			uint32_t skin_stride;
-			uint32_t skin_weight_offset;
-
-			uint32_t blend_shape_count;
-			uint32_t normalized_blend_shapes;
-			uint32_t pad0;
-			uint32_t pad1;
-		};
-
-		enum {
-			UNIFORM_SET_INSTANCE = 0,
-			UNIFORM_SET_SURFACE = 1,
-			UNIFORM_SET_SKELETON = 2,
-		};
-		enum {
-			SHADER_MODE_2D,
-			SHADER_MODE_3D,
-			SHADER_MODE_MAX
-		};
-
-		SkeletonShaderRD shader;
-		RID version;
-		RID version_shader[SHADER_MODE_MAX];
-		RID pipeline[SHADER_MODE_MAX];
-
-		RID default_skeleton_uniform_set;
-	} skeleton_shader;
-
-	void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, MeshInstance::Surface *mis = nullptr);
-
-	RID mesh_default_rd_buffers[DEFAULT_RD_BUFFER_MAX];
-
-	/* MultiMesh */
-	struct MultiMesh {
-		RID mesh;
-		int instances = 0;
-		RS::MultimeshTransformFormat xform_format = RS::MULTIMESH_TRANSFORM_3D;
-		bool uses_colors = false;
-		bool uses_custom_data = false;
-		int visible_instances = -1;
-		AABB aabb;
-		bool aabb_dirty = false;
-		bool buffer_set = false;
-		uint32_t stride_cache = 0;
-		uint32_t color_offset_cache = 0;
-		uint32_t custom_data_offset_cache = 0;
-
-		Vector<float> data_cache; //used if individual setting is used
-		bool *data_cache_dirty_regions = nullptr;
-		uint32_t data_cache_used_dirty_regions = 0;
-
-		RID buffer; //storage buffer
-		RID uniform_set_3d;
-		RID uniform_set_2d;
-
-		bool dirty = false;
-		MultiMesh *dirty_list = nullptr;
-
-		Dependency dependency;
-	};
-
-	mutable RID_Owner<MultiMesh, true> multimesh_owner;
-
-	MultiMesh *multimesh_dirty_list = nullptr;
-
-	_FORCE_INLINE_ void _multimesh_make_local(MultiMesh *multimesh) const;
-	_FORCE_INLINE_ void _multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb);
-	_FORCE_INLINE_ void _multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb);
-	_FORCE_INLINE_ void _multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances);
-	void _update_dirty_multimeshes();
 
 
 	/* PARTICLES */
 	/* PARTICLES */
 
 
@@ -732,34 +507,6 @@ private:
 
 
 	mutable RID_Owner<VisibilityNotifier> visibility_notifier_owner;
 	mutable RID_Owner<VisibilityNotifier> visibility_notifier_owner;
 
 
-	/* Skeleton */
-
-	struct Skeleton {
-		bool use_2d = false;
-		int size = 0;
-		Vector<float> data;
-		RID buffer;
-
-		bool dirty = false;
-		Skeleton *dirty_list = nullptr;
-		Transform2D base_transform_2d;
-
-		RID uniform_set_3d;
-		RID uniform_set_mi;
-
-		uint64_t version = 1;
-
-		Dependency dependency;
-	};
-
-	mutable RID_Owner<Skeleton, true> skeleton_owner;
-
-	_FORCE_INLINE_ void _skeleton_make_dirty(Skeleton *skeleton);
-
-	Skeleton *skeleton_dirty_list = nullptr;
-
-	void _update_dirty_skeletons();
-
 	/* LIGHT */
 	/* LIGHT */
 
 
 	struct Light {
 	struct Light {
@@ -975,360 +722,6 @@ public:
 
 
 	void sampler_rd_set_default(float p_mipmap_bias);
 	void sampler_rd_set_default(float p_mipmap_bias);
 
 
-	/* MESH API */
-
-	RID mesh_allocate();
-	void mesh_initialize(RID p_mesh);
-
-	virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count);
-
-	/// Return stride
-	virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface);
-
-	virtual int mesh_get_blend_shape_count(RID p_mesh) const;
-
-	virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode);
-	virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const;
-
-	virtual void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data);
-	virtual void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data);
-	virtual void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data);
-
-	virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material);
-	virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const;
-
-	virtual RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const;
-
-	virtual int mesh_get_surface_count(RID p_mesh) const;
-
-	virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb);
-	virtual AABB mesh_get_custom_aabb(RID p_mesh) const;
-
-	virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID());
-	virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh);
-
-	virtual void mesh_clear(RID p_mesh);
-
-	virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton);
-
-	/* MESH INSTANCE */
-
-	virtual RID mesh_instance_create(RID p_base);
-	virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton);
-	virtual void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight);
-	virtual void mesh_instance_check_for_update(RID p_mesh_instance);
-	virtual void update_mesh_instances();
-
-	_FORCE_INLINE_ const RID *mesh_get_surface_count_and_materials(RID p_mesh, uint32_t &r_surface_count) {
-		Mesh *mesh = mesh_owner.get_or_null(p_mesh);
-		ERR_FAIL_COND_V(!mesh, nullptr);
-		r_surface_count = mesh->surface_count;
-		if (r_surface_count == 0) {
-			return nullptr;
-		}
-		if (mesh->material_cache.is_empty()) {
-			mesh->material_cache.resize(mesh->surface_count);
-			for (uint32_t i = 0; i < r_surface_count; i++) {
-				mesh->material_cache.write[i] = mesh->surfaces[i]->material;
-			}
-		}
-
-		return mesh->material_cache.ptr();
-	}
-
-	_FORCE_INLINE_ void *mesh_get_surface(RID p_mesh, uint32_t p_surface_index) {
-		Mesh *mesh = mesh_owner.get_or_null(p_mesh);
-		ERR_FAIL_COND_V(!mesh, nullptr);
-		ERR_FAIL_UNSIGNED_INDEX_V(p_surface_index, mesh->surface_count, nullptr);
-
-		return mesh->surfaces[p_surface_index];
-	}
-
-	_FORCE_INLINE_ RID mesh_get_shadow_mesh(RID p_mesh) {
-		Mesh *mesh = mesh_owner.get_or_null(p_mesh);
-		ERR_FAIL_COND_V(!mesh, RID());
-
-		return mesh->shadow_mesh;
-	}
-
-	_FORCE_INLINE_ RS::PrimitiveType mesh_surface_get_primitive(void *p_surface) {
-		Mesh::Surface *surface = reinterpret_cast<Mesh::Surface *>(p_surface);
-		return surface->primitive;
-	}
-
-	_FORCE_INLINE_ bool mesh_surface_has_lod(void *p_surface) const {
-		Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
-		return s->lod_count > 0;
-	}
-
-	_FORCE_INLINE_ uint32_t mesh_surface_get_vertices_drawn_count(void *p_surface) const {
-		Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
-		return s->index_count ? s->index_count : s->vertex_count;
-	}
-
-	_FORCE_INLINE_ uint32_t mesh_surface_get_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_mesh_lod_threshold, uint32_t *r_index_count = nullptr) const {
-		Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
-
-		int32_t current_lod = -1;
-		if (r_index_count) {
-			*r_index_count = s->index_count;
-		}
-		for (uint32_t i = 0; i < s->lod_count; i++) {
-			float screen_size = s->lods[i].edge_length * p_model_scale / p_distance_threshold;
-			if (screen_size > p_mesh_lod_threshold) {
-				break;
-			}
-			current_lod = i;
-		}
-		if (current_lod == -1) {
-			return 0;
-		} else {
-			if (r_index_count) {
-				*r_index_count = s->lods[current_lod].index_count;
-			}
-			return current_lod + 1;
-		}
-	}
-
-	_FORCE_INLINE_ RID mesh_surface_get_index_array(void *p_surface, uint32_t p_lod) const {
-		Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
-
-		if (p_lod == 0) {
-			return s->index_array;
-		} else {
-			return s->lods[p_lod - 1].index_array;
-		}
-	}
-
-	_FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint32_t p_input_mask, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) {
-		Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
-
-		s->version_lock.lock();
-
-		//there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way
-
-		for (uint32_t i = 0; i < s->version_count; i++) {
-			if (s->versions[i].input_mask != p_input_mask) {
-				continue;
-			}
-			//we have this version, hooray
-			r_vertex_format = s->versions[i].vertex_format;
-			r_vertex_array_rd = s->versions[i].vertex_array;
-			s->version_lock.unlock();
-			return;
-		}
-
-		uint32_t version = s->version_count;
-		s->version_count++;
-		s->versions = (Mesh::Surface::Version *)memrealloc(s->versions, sizeof(Mesh::Surface::Version) * s->version_count);
-
-		_mesh_surface_generate_version_for_input_mask(s->versions[version], s, p_input_mask);
-
-		r_vertex_format = s->versions[version].vertex_format;
-		r_vertex_array_rd = s->versions[version].vertex_array;
-
-		s->version_lock.unlock();
-	}
-
-	_FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint32_t p_input_mask, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) {
-		MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
-		ERR_FAIL_COND(!mi);
-		Mesh *mesh = mi->mesh;
-		ERR_FAIL_UNSIGNED_INDEX(p_surface_index, mesh->surface_count);
-
-		MeshInstance::Surface *mis = &mi->surfaces[p_surface_index];
-		Mesh::Surface *s = mesh->surfaces[p_surface_index];
-
-		s->version_lock.lock();
-
-		//there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way
-
-		for (uint32_t i = 0; i < mis->version_count; i++) {
-			if (mis->versions[i].input_mask != p_input_mask) {
-				continue;
-			}
-			//we have this version, hooray
-			r_vertex_format = mis->versions[i].vertex_format;
-			r_vertex_array_rd = mis->versions[i].vertex_array;
-			s->version_lock.unlock();
-			return;
-		}
-
-		uint32_t version = mis->version_count;
-		mis->version_count++;
-		mis->versions = (Mesh::Surface::Version *)memrealloc(mis->versions, sizeof(Mesh::Surface::Version) * mis->version_count);
-
-		_mesh_surface_generate_version_for_input_mask(mis->versions[version], s, p_input_mask, mis);
-
-		r_vertex_format = mis->versions[version].vertex_format;
-		r_vertex_array_rd = mis->versions[version].vertex_array;
-
-		s->version_lock.unlock();
-	}
-
-	_FORCE_INLINE_ RID mesh_get_default_rd_buffer(DefaultRDBuffer p_buffer) {
-		ERR_FAIL_INDEX_V(p_buffer, DEFAULT_RD_BUFFER_MAX, RID());
-		return mesh_default_rd_buffers[p_buffer];
-	}
-
-	_FORCE_INLINE_ uint32_t mesh_surface_get_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) {
-		Mesh *mesh = mesh_owner.get_or_null(p_mesh);
-		Mesh::Surface *s = mesh->surfaces[p_surface_index];
-
-		if (s->render_pass != p_render_pass) {
-			(*r_index)++;
-			s->render_pass = p_render_pass;
-			s->render_index = *r_index;
-		}
-
-		return s->render_index;
-	}
-
-	_FORCE_INLINE_ uint32_t mesh_surface_get_multimesh_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) {
-		Mesh *mesh = mesh_owner.get_or_null(p_mesh);
-		Mesh::Surface *s = mesh->surfaces[p_surface_index];
-
-		if (s->multimesh_render_pass != p_render_pass) {
-			(*r_index)++;
-			s->multimesh_render_pass = p_render_pass;
-			s->multimesh_render_index = *r_index;
-		}
-
-		return s->multimesh_render_index;
-	}
-
-	_FORCE_INLINE_ uint32_t mesh_surface_get_particles_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) {
-		Mesh *mesh = mesh_owner.get_or_null(p_mesh);
-		Mesh::Surface *s = mesh->surfaces[p_surface_index];
-
-		if (s->particles_render_pass != p_render_pass) {
-			(*r_index)++;
-			s->particles_render_pass = p_render_pass;
-			s->particles_render_index = *r_index;
-		}
-
-		return s->particles_render_index;
-	}
-
-	/* MULTIMESH API */
-
-	RID multimesh_allocate();
-	void multimesh_initialize(RID p_multimesh);
-
-	void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false);
-	int multimesh_get_instance_count(RID p_multimesh) const;
-
-	void multimesh_set_mesh(RID p_multimesh, RID p_mesh);
-	void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform);
-	void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform);
-	void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color);
-	void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color);
-
-	RID multimesh_get_mesh(RID p_multimesh) const;
-
-	Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const;
-	Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const;
-	Color multimesh_instance_get_color(RID p_multimesh, int p_index) const;
-	Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const;
-
-	void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer);
-	Vector<float> multimesh_get_buffer(RID p_multimesh) const;
-
-	void multimesh_set_visible_instances(RID p_multimesh, int p_visible);
-	int multimesh_get_visible_instances(RID p_multimesh) const;
-
-	AABB multimesh_get_aabb(RID p_multimesh) const;
-
-	_FORCE_INLINE_ RS::MultimeshTransformFormat multimesh_get_transform_format(RID p_multimesh) const {
-		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
-		return multimesh->xform_format;
-	}
-
-	_FORCE_INLINE_ bool multimesh_uses_colors(RID p_multimesh) const {
-		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
-		return multimesh->uses_colors;
-	}
-
-	_FORCE_INLINE_ bool multimesh_uses_custom_data(RID p_multimesh) const {
-		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
-		return multimesh->uses_custom_data;
-	}
-
-	_FORCE_INLINE_ uint32_t multimesh_get_instances_to_draw(RID p_multimesh) const {
-		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
-		if (multimesh->visible_instances >= 0) {
-			return multimesh->visible_instances;
-		}
-		return multimesh->instances;
-	}
-
-	_FORCE_INLINE_ RID multimesh_get_3d_uniform_set(RID p_multimesh, RID p_shader, uint32_t p_set) const {
-		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
-		if (!multimesh->uniform_set_3d.is_valid()) {
-			Vector<RD::Uniform> uniforms;
-			RD::Uniform u;
-			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
-			u.binding = 0;
-			u.append_id(multimesh->buffer);
-			uniforms.push_back(u);
-			multimesh->uniform_set_3d = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set);
-		}
-
-		return multimesh->uniform_set_3d;
-	}
-
-	_FORCE_INLINE_ RID multimesh_get_2d_uniform_set(RID p_multimesh, RID p_shader, uint32_t p_set) const {
-		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
-		if (!multimesh->uniform_set_2d.is_valid()) {
-			Vector<RD::Uniform> uniforms;
-			RD::Uniform u;
-			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
-			u.binding = 0;
-			u.append_id(multimesh->buffer);
-			uniforms.push_back(u);
-			multimesh->uniform_set_2d = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set);
-		}
-
-		return multimesh->uniform_set_2d;
-	}
-
-	/* SKELETON API */
-
-	RID skeleton_allocate();
-	void skeleton_initialize(RID p_skeleton);
-
-	void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false);
-	void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform);
-	void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform3D &p_world_transform);
-	int skeleton_get_bone_count(RID p_skeleton) const;
-	void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform);
-	Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const;
-	void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform);
-	Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const;
-
-	_FORCE_INLINE_ bool skeleton_is_valid(RID p_skeleton) {
-		return skeleton_owner.get_or_null(p_skeleton) != nullptr;
-	}
-
-	_FORCE_INLINE_ RID skeleton_get_3d_uniform_set(RID p_skeleton, RID p_shader, uint32_t p_set) const {
-		Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
-		ERR_FAIL_COND_V(!skeleton, RID());
-		ERR_FAIL_COND_V(skeleton->size == 0, RID());
-		if (skeleton->use_2d) {
-			return RID();
-		}
-		if (!skeleton->uniform_set_3d.is_valid()) {
-			Vector<RD::Uniform> uniforms;
-			RD::Uniform u;
-			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
-			u.binding = 0;
-			u.append_id(skeleton->buffer);
-			uniforms.push_back(u);
-			skeleton->uniform_set_3d = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set);
-		}
-
-		return skeleton->uniform_set_3d;
-	}
 	/* Light API */
 	/* Light API */
 
 
 	void _light_initialize(RID p_rid, RS::LightType p_type);
 	void _light_initialize(RID p_rid, RS::LightType p_type);
@@ -1498,7 +891,6 @@ public:
 	float reflection_probe_get_ambient_color_energy(RID p_probe) const;
 	float reflection_probe_get_ambient_color_energy(RID p_probe) const;
 
 
 	void base_update_dependency(RID p_base, DependencyTracker *p_instance);
 	void base_update_dependency(RID p_base, DependencyTracker *p_instance);
-	void skeleton_update_dependency(RID p_skeleton, DependencyTracker *p_instance);
 
 
 	/* VOXEL GI API */
 	/* VOXEL GI API */
 
 
@@ -1829,8 +1221,6 @@ public:
 	virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const;
 	virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const;
 	virtual String get_captured_timestamp_name(uint32_t p_index) const;
 	virtual String get_captured_timestamp_name(uint32_t p_index) const;
 
 
-	RID get_default_rd_storage_buffer() { return default_rd_storage_buffer; }
-
 	static RendererStorageRD *base_singleton;
 	static RendererStorageRD *base_singleton;
 
 
 	void init_effects(bool p_prefer_raster_effects);
 	void init_effects(bool p_prefer_raster_effects);

+ 1921 - 0
servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp

@@ -0,0 +1,1921 @@
+/*************************************************************************/
+/*  mesh_storage.cpp                                                     */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include "mesh_storage.h"
+
+using namespace RendererRD;
+
+MeshStorage *MeshStorage::singleton = nullptr;
+
+MeshStorage *MeshStorage::get_singleton() {
+	return singleton;
+}
+
+MeshStorage::MeshStorage() {
+	singleton = this;
+
+	default_rd_storage_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4);
+
+	//default rd buffers
+	{
+		Vector<uint8_t> buffer;
+		{
+			buffer.resize(sizeof(float) * 3);
+			{
+				uint8_t *w = buffer.ptrw();
+				float *fptr = (float *)w;
+				fptr[0] = 0.0;
+				fptr[1] = 0.0;
+				fptr[2] = 0.0;
+			}
+			mesh_default_rd_buffers[DEFAULT_RD_BUFFER_VERTEX] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+		}
+
+		{ //normal
+			buffer.resize(sizeof(float) * 3);
+			{
+				uint8_t *w = buffer.ptrw();
+				float *fptr = (float *)w;
+				fptr[0] = 1.0;
+				fptr[1] = 0.0;
+				fptr[2] = 0.0;
+			}
+			mesh_default_rd_buffers[DEFAULT_RD_BUFFER_NORMAL] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+		}
+
+		{ //tangent
+			buffer.resize(sizeof(float) * 4);
+			{
+				uint8_t *w = buffer.ptrw();
+				float *fptr = (float *)w;
+				fptr[0] = 1.0;
+				fptr[1] = 0.0;
+				fptr[2] = 0.0;
+				fptr[3] = 0.0;
+			}
+			mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TANGENT] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+		}
+
+		{ //color
+			buffer.resize(sizeof(float) * 4);
+			{
+				uint8_t *w = buffer.ptrw();
+				float *fptr = (float *)w;
+				fptr[0] = 1.0;
+				fptr[1] = 1.0;
+				fptr[2] = 1.0;
+				fptr[3] = 1.0;
+			}
+			mesh_default_rd_buffers[DEFAULT_RD_BUFFER_COLOR] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+		}
+
+		{ //tex uv 1
+			buffer.resize(sizeof(float) * 2);
+			{
+				uint8_t *w = buffer.ptrw();
+				float *fptr = (float *)w;
+				fptr[0] = 0.0;
+				fptr[1] = 0.0;
+			}
+			mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+		}
+		{ //tex uv 2
+			buffer.resize(sizeof(float) * 2);
+			{
+				uint8_t *w = buffer.ptrw();
+				float *fptr = (float *)w;
+				fptr[0] = 0.0;
+				fptr[1] = 0.0;
+			}
+			mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV2] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+		}
+
+		for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) {
+			buffer.resize(sizeof(float) * 4);
+			{
+				uint8_t *w = buffer.ptrw();
+				float *fptr = (float *)w;
+				fptr[0] = 0.0;
+				fptr[1] = 0.0;
+				fptr[2] = 0.0;
+				fptr[3] = 0.0;
+			}
+			mesh_default_rd_buffers[DEFAULT_RD_BUFFER_CUSTOM0 + i] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+		}
+
+		{ //bones
+			buffer.resize(sizeof(uint32_t) * 4);
+			{
+				uint8_t *w = buffer.ptrw();
+				uint32_t *fptr = (uint32_t *)w;
+				fptr[0] = 0;
+				fptr[1] = 0;
+				fptr[2] = 0;
+				fptr[3] = 0;
+			}
+			mesh_default_rd_buffers[DEFAULT_RD_BUFFER_BONES] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+		}
+
+		{ //weights
+			buffer.resize(sizeof(float) * 4);
+			{
+				uint8_t *w = buffer.ptrw();
+				float *fptr = (float *)w;
+				fptr[0] = 0.0;
+				fptr[1] = 0.0;
+				fptr[2] = 0.0;
+				fptr[3] = 0.0;
+			}
+			mesh_default_rd_buffers[DEFAULT_RD_BUFFER_WEIGHTS] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+		}
+	}
+
+	{
+		Vector<String> skeleton_modes;
+		skeleton_modes.push_back("\n#define MODE_2D\n");
+		skeleton_modes.push_back("");
+
+		skeleton_shader.shader.initialize(skeleton_modes);
+		skeleton_shader.version = skeleton_shader.shader.version_create();
+		for (int i = 0; i < SkeletonShader::SHADER_MODE_MAX; i++) {
+			skeleton_shader.version_shader[i] = skeleton_shader.shader.version_get_shader(skeleton_shader.version, i);
+			skeleton_shader.pipeline[i] = RD::get_singleton()->compute_pipeline_create(skeleton_shader.version_shader[i]);
+		}
+
+		{
+			Vector<RD::Uniform> uniforms;
+			{
+				RD::Uniform u;
+				u.binding = 0;
+				u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+				u.append_id(default_rd_storage_buffer);
+				uniforms.push_back(u);
+			}
+			skeleton_shader.default_skeleton_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_SKELETON);
+		}
+	}
+}
+
+MeshStorage::~MeshStorage() {
+	//def buffers
+	for (int i = 0; i < DEFAULT_RD_BUFFER_MAX; i++) {
+		RD::get_singleton()->free(mesh_default_rd_buffers[i]);
+	}
+
+	skeleton_shader.shader.version_free(skeleton_shader.version);
+
+	RD::get_singleton()->free(default_rd_storage_buffer);
+
+	singleton = nullptr;
+}
+
+/* MESH API */
+
+RID MeshStorage::mesh_allocate() {
+	return mesh_owner.allocate_rid();
+}
+
+void MeshStorage::mesh_initialize(RID p_rid) {
+	mesh_owner.initialize_rid(p_rid, Mesh());
+}
+
+void MeshStorage::mesh_free(RID p_rid) {
+	mesh_clear(p_rid);
+	mesh_set_shadow_mesh(p_rid, RID());
+	Mesh *mesh = mesh_owner.get_or_null(p_rid);
+	mesh->dependency.deleted_notify(p_rid);
+	if (mesh->instances.size()) {
+		ERR_PRINT("deleting mesh with active instances");
+	}
+	if (mesh->shadow_owners.size()) {
+		for (Set<Mesh *>::Element *E = mesh->shadow_owners.front(); E; E = E->next()) {
+			Mesh *shadow_owner = E->get();
+			shadow_owner->shadow_mesh = RID();
+			shadow_owner->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MESH);
+		}
+	}
+	mesh_owner.free(p_rid);
+}
+
+void MeshStorage::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) {
+	ERR_FAIL_COND(p_blend_shape_count < 0);
+
+	Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+	ERR_FAIL_COND(!mesh);
+
+	ERR_FAIL_COND(mesh->surface_count > 0); //surfaces already exist
+
+	mesh->blend_shape_count = p_blend_shape_count;
+}
+
+/// Returns stride
+void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) {
+	Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+	ERR_FAIL_COND(!mesh);
+
+	ERR_FAIL_COND(mesh->surface_count == RS::MAX_MESH_SURFACES);
+
+#ifdef DEBUG_ENABLED
+	//do a validation, to catch errors first
+	{
+		uint32_t stride = 0;
+		uint32_t attrib_stride = 0;
+		uint32_t skin_stride = 0;
+
+		for (int i = 0; i < RS::ARRAY_WEIGHTS; i++) {
+			if ((p_surface.format & (1 << i))) {
+				switch (i) {
+					case RS::ARRAY_VERTEX: {
+						if (p_surface.format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
+							stride += sizeof(float) * 2;
+						} else {
+							stride += sizeof(float) * 3;
+						}
+
+					} break;
+					case RS::ARRAY_NORMAL: {
+						stride += sizeof(int32_t);
+
+					} break;
+					case RS::ARRAY_TANGENT: {
+						stride += sizeof(int32_t);
+
+					} break;
+					case RS::ARRAY_COLOR: {
+						attrib_stride += sizeof(uint32_t);
+					} break;
+					case RS::ARRAY_TEX_UV: {
+						attrib_stride += sizeof(float) * 2;
+
+					} break;
+					case RS::ARRAY_TEX_UV2: {
+						attrib_stride += sizeof(float) * 2;
+
+					} break;
+					case RS::ARRAY_CUSTOM0:
+					case RS::ARRAY_CUSTOM1:
+					case RS::ARRAY_CUSTOM2:
+					case RS::ARRAY_CUSTOM3: {
+						int idx = i - RS::ARRAY_CUSTOM0;
+						uint32_t fmt_shift[RS::ARRAY_CUSTOM_COUNT] = { RS::ARRAY_FORMAT_CUSTOM0_SHIFT, RS::ARRAY_FORMAT_CUSTOM1_SHIFT, RS::ARRAY_FORMAT_CUSTOM2_SHIFT, RS::ARRAY_FORMAT_CUSTOM3_SHIFT };
+						uint32_t fmt = (p_surface.format >> fmt_shift[idx]) & RS::ARRAY_FORMAT_CUSTOM_MASK;
+						uint32_t fmtsize[RS::ARRAY_CUSTOM_MAX] = { 4, 4, 4, 8, 4, 8, 12, 16 };
+						attrib_stride += fmtsize[fmt];
+
+					} break;
+					case RS::ARRAY_WEIGHTS:
+					case RS::ARRAY_BONES: {
+						//uses a separate array
+						bool use_8 = p_surface.format & RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS;
+						skin_stride += sizeof(int16_t) * (use_8 ? 16 : 8);
+					} break;
+				}
+			}
+		}
+
+		int expected_size = stride * p_surface.vertex_count;
+		ERR_FAIL_COND_MSG(expected_size != p_surface.vertex_data.size(), "Size of vertex data provided (" + itos(p_surface.vertex_data.size()) + ") does not match expected (" + itos(expected_size) + ")");
+
+		int bs_expected_size = expected_size * mesh->blend_shape_count;
+
+		ERR_FAIL_COND_MSG(bs_expected_size != p_surface.blend_shape_data.size(), "Size of blend shape data provided (" + itos(p_surface.blend_shape_data.size()) + ") does not match expected (" + itos(bs_expected_size) + ")");
+
+		int expected_attrib_size = attrib_stride * p_surface.vertex_count;
+		ERR_FAIL_COND_MSG(expected_attrib_size != p_surface.attribute_data.size(), "Size of attribute data provided (" + itos(p_surface.attribute_data.size()) + ") does not match expected (" + itos(expected_attrib_size) + ")");
+
+		if ((p_surface.format & RS::ARRAY_FORMAT_WEIGHTS) && (p_surface.format & RS::ARRAY_FORMAT_BONES)) {
+			expected_size = skin_stride * p_surface.vertex_count;
+			ERR_FAIL_COND_MSG(expected_size != p_surface.skin_data.size(), "Size of skin data provided (" + itos(p_surface.skin_data.size()) + ") does not match expected (" + itos(expected_size) + ")");
+		}
+	}
+
+#endif
+
+	Mesh::Surface *s = memnew(Mesh::Surface);
+
+	s->format = p_surface.format;
+	s->primitive = p_surface.primitive;
+
+	bool use_as_storage = (p_surface.skin_data.size() || mesh->blend_shape_count > 0);
+
+	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 (p_surface.attribute_data.size()) {
+		s->attribute_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.attribute_data.size(), p_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();
+	}
+
+	s->vertex_count = p_surface.vertex_count;
+
+	if (p_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;
+
+		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_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();
+
+			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);
+				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].index_count = indices;
+			}
+		}
+	}
+
+	s->aabb = p_surface.aabb;
+	s->bone_aabbs = p_surface.bone_aabbs; //only really useful for returning them.
+
+	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);
+	}
+
+	if (use_as_storage) {
+		Vector<RD::Uniform> uniforms;
+		{
+			RD::Uniform u;
+			u.binding = 0;
+			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+			u.append_id(s->vertex_buffer);
+			uniforms.push_back(u);
+		}
+		{
+			RD::Uniform u;
+			u.binding = 1;
+			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+			if (s->skin_buffer.is_valid()) {
+				u.append_id(s->skin_buffer);
+			} else {
+				u.append_id(default_rd_storage_buffer);
+			}
+			uniforms.push_back(u);
+		}
+		{
+			RD::Uniform u;
+			u.binding = 2;
+			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+			if (s->blend_shape_buffer.is_valid()) {
+				u.append_id(s->blend_shape_buffer);
+			} else {
+				u.append_id(default_rd_storage_buffer);
+			}
+			uniforms.push_back(u);
+		}
+
+		s->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_SURFACE);
+	}
+
+	if (mesh->surface_count == 0) {
+		mesh->bone_aabbs = p_surface.bone_aabbs;
+		mesh->aabb = p_surface.aabb;
+	} else {
+		if (mesh->bone_aabbs.size() < p_surface.bone_aabbs.size()) {
+			// ArrayMesh::_surface_set_data only allocates bone_aabbs up to max_bone
+			// Each surface may affect different numbers of bones.
+			mesh->bone_aabbs.resize(p_surface.bone_aabbs.size());
+		}
+		for (int i = 0; i < p_surface.bone_aabbs.size(); i++) {
+			mesh->bone_aabbs.write[i].merge_with(p_surface.bone_aabbs[i]);
+		}
+		mesh->aabb.merge_with(p_surface.aabb);
+	}
+
+	s->material = p_surface.material;
+
+	mesh->surfaces = (Mesh::Surface **)memrealloc(mesh->surfaces, sizeof(Mesh::Surface *) * (mesh->surface_count + 1));
+	mesh->surfaces[mesh->surface_count] = s;
+	mesh->surface_count++;
+
+	for (MeshInstance *mi : mesh->instances) {
+		_mesh_instance_add_surface(mi, mesh, mesh->surface_count - 1);
+	}
+
+	mesh->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MESH);
+
+	for (Set<Mesh *>::Element *E = mesh->shadow_owners.front(); E; E = E->next()) {
+		Mesh *shadow_owner = E->get();
+		shadow_owner->shadow_mesh = RID();
+		shadow_owner->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MESH);
+	}
+
+	mesh->material_cache.clear();
+}
+
+int MeshStorage::mesh_get_blend_shape_count(RID p_mesh) const {
+	const Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+	ERR_FAIL_COND_V(!mesh, -1);
+	return mesh->blend_shape_count;
+}
+
+void MeshStorage::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) {
+	Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+	ERR_FAIL_COND(!mesh);
+	ERR_FAIL_INDEX((int)p_mode, 2);
+
+	mesh->blend_shape_mode = p_mode;
+}
+
+RS::BlendShapeMode MeshStorage::mesh_get_blend_shape_mode(RID p_mesh) const {
+	Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+	ERR_FAIL_COND_V(!mesh, RS::BLEND_SHAPE_MODE_NORMALIZED);
+	return mesh->blend_shape_mode;
+}
+
+void MeshStorage::mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+	Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+	ERR_FAIL_COND(!mesh);
+	ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
+	ERR_FAIL_COND(p_data.size() == 0);
+	uint64_t data_size = p_data.size();
+	const uint8_t *r = p_data.ptr();
+
+	RD::get_singleton()->buffer_update(mesh->surfaces[p_surface]->vertex_buffer, p_offset, data_size, r);
+}
+
+void MeshStorage::mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+	Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+	ERR_FAIL_COND(!mesh);
+	ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
+	ERR_FAIL_COND(p_data.size() == 0);
+	ERR_FAIL_COND(mesh->surfaces[p_surface]->attribute_buffer.is_null());
+	uint64_t data_size = p_data.size();
+	const uint8_t *r = p_data.ptr();
+
+	RD::get_singleton()->buffer_update(mesh->surfaces[p_surface]->attribute_buffer, p_offset, data_size, r);
+}
+
+void MeshStorage::mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+	Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+	ERR_FAIL_COND(!mesh);
+	ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
+	ERR_FAIL_COND(p_data.size() == 0);
+	ERR_FAIL_COND(mesh->surfaces[p_surface]->skin_buffer.is_null());
+	uint64_t data_size = p_data.size();
+	const uint8_t *r = p_data.ptr();
+
+	RD::get_singleton()->buffer_update(mesh->surfaces[p_surface]->skin_buffer, p_offset, data_size, r);
+}
+
+void MeshStorage::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) {
+	Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+	ERR_FAIL_COND(!mesh);
+	ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
+	mesh->surfaces[p_surface]->material = p_material;
+
+	mesh->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MATERIAL);
+	mesh->material_cache.clear();
+}
+
+RID MeshStorage::mesh_surface_get_material(RID p_mesh, int p_surface) const {
+	Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+	ERR_FAIL_COND_V(!mesh, RID());
+	ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RID());
+
+	return mesh->surfaces[p_surface]->material;
+}
+
+RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
+	Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+	ERR_FAIL_COND_V(!mesh, RS::SurfaceData());
+	ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RS::SurfaceData());
+
+	Mesh::Surface &s = *mesh->surfaces[p_surface];
+
+	RS::SurfaceData sd;
+	sd.format = s.format;
+	sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer);
+	if (s.attribute_buffer.is_valid()) {
+		sd.attribute_data = RD::get_singleton()->buffer_get_data(s.attribute_buffer);
+	}
+	if (s.skin_buffer.is_valid()) {
+		sd.skin_data = RD::get_singleton()->buffer_get_data(s.skin_buffer);
+	}
+	sd.vertex_count = s.vertex_count;
+	sd.index_count = s.index_count;
+	sd.primitive = s.primitive;
+
+	if (sd.index_count) {
+		sd.index_data = RD::get_singleton()->buffer_get_data(s.index_buffer);
+	}
+	sd.aabb = s.aabb;
+	for (uint32_t i = 0; i < s.lod_count; i++) {
+		RS::SurfaceData::LOD lod;
+		lod.edge_length = s.lods[i].edge_length;
+		lod.index_data = RD::get_singleton()->buffer_get_data(s.lods[i].index_buffer);
+		sd.lods.push_back(lod);
+	}
+
+	sd.bone_aabbs = s.bone_aabbs;
+
+	if (s.blend_shape_buffer.is_valid()) {
+		sd.blend_shape_data = RD::get_singleton()->buffer_get_data(s.blend_shape_buffer);
+	}
+
+	return sd;
+}
+
+int MeshStorage::mesh_get_surface_count(RID p_mesh) const {
+	Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+	ERR_FAIL_COND_V(!mesh, 0);
+	return mesh->surface_count;
+}
+
+void MeshStorage::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) {
+	Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+	ERR_FAIL_COND(!mesh);
+	mesh->custom_aabb = p_aabb;
+}
+
+AABB MeshStorage::mesh_get_custom_aabb(RID p_mesh) const {
+	Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+	ERR_FAIL_COND_V(!mesh, AABB());
+	return mesh->custom_aabb;
+}
+
+AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
+	Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+	ERR_FAIL_COND_V(!mesh, AABB());
+
+	if (mesh->custom_aabb != AABB()) {
+		return mesh->custom_aabb;
+	}
+
+	Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
+
+	if (!skeleton || skeleton->size == 0) {
+		return mesh->aabb;
+	}
+
+	AABB aabb;
+
+	for (uint32_t i = 0; i < mesh->surface_count; i++) {
+		AABB laabb;
+		if ((mesh->surfaces[i]->format & RS::ARRAY_FORMAT_BONES) && mesh->surfaces[i]->bone_aabbs.size()) {
+			int bs = mesh->surfaces[i]->bone_aabbs.size();
+			const AABB *skbones = mesh->surfaces[i]->bone_aabbs.ptr();
+
+			int sbs = skeleton->size;
+			ERR_CONTINUE(bs > sbs);
+			const float *baseptr = skeleton->data.ptr();
+
+			bool first = true;
+
+			if (skeleton->use_2d) {
+				for (int j = 0; j < bs; j++) {
+					if (skbones[0].size == Vector3()) {
+						continue; //bone is unused
+					}
+
+					const float *dataptr = baseptr + j * 8;
+
+					Transform3D mtx;
+
+					mtx.basis.elements[0].x = dataptr[0];
+					mtx.basis.elements[1].x = dataptr[1];
+					mtx.origin.x = dataptr[3];
+
+					mtx.basis.elements[0].y = dataptr[4];
+					mtx.basis.elements[1].y = dataptr[5];
+					mtx.origin.y = dataptr[7];
+
+					AABB baabb = mtx.xform(skbones[j]);
+
+					if (first) {
+						laabb = baabb;
+						first = false;
+					} else {
+						laabb.merge_with(baabb);
+					}
+				}
+			} else {
+				for (int j = 0; j < bs; j++) {
+					if (skbones[0].size == Vector3()) {
+						continue; //bone is unused
+					}
+
+					const float *dataptr = baseptr + j * 12;
+
+					Transform3D mtx;
+
+					mtx.basis.elements[0][0] = dataptr[0];
+					mtx.basis.elements[0][1] = dataptr[1];
+					mtx.basis.elements[0][2] = dataptr[2];
+					mtx.origin.x = dataptr[3];
+					mtx.basis.elements[1][0] = dataptr[4];
+					mtx.basis.elements[1][1] = dataptr[5];
+					mtx.basis.elements[1][2] = dataptr[6];
+					mtx.origin.y = dataptr[7];
+					mtx.basis.elements[2][0] = dataptr[8];
+					mtx.basis.elements[2][1] = dataptr[9];
+					mtx.basis.elements[2][2] = dataptr[10];
+					mtx.origin.z = dataptr[11];
+
+					AABB baabb = mtx.xform(skbones[j]);
+					if (first) {
+						laabb = baabb;
+						first = false;
+					} else {
+						laabb.merge_with(baabb);
+					}
+				}
+			}
+
+			if (laabb.size == Vector3()) {
+				laabb = mesh->surfaces[i]->aabb;
+			}
+		} else {
+			laabb = mesh->surfaces[i]->aabb;
+		}
+
+		if (i == 0) {
+			aabb = laabb;
+		} else {
+			aabb.merge_with(laabb);
+		}
+	}
+
+	return aabb;
+}
+
+void MeshStorage::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) {
+	Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+	ERR_FAIL_COND(!mesh);
+
+	Mesh *shadow_mesh = mesh_owner.get_or_null(mesh->shadow_mesh);
+	if (shadow_mesh) {
+		shadow_mesh->shadow_owners.erase(mesh);
+	}
+	mesh->shadow_mesh = p_shadow_mesh;
+
+	shadow_mesh = mesh_owner.get_or_null(mesh->shadow_mesh);
+
+	if (shadow_mesh) {
+		shadow_mesh->shadow_owners.insert(mesh);
+	}
+
+	mesh->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MESH);
+}
+
+void MeshStorage::mesh_clear(RID p_mesh) {
+	Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+	ERR_FAIL_COND(!mesh);
+	for (uint32_t i = 0; i < mesh->surface_count; i++) {
+		Mesh::Surface &s = *mesh->surfaces[i];
+		RD::get_singleton()->free(s.vertex_buffer); //clears arrays as dependency automatically, including all versions
+		if (s.attribute_buffer.is_valid()) {
+			RD::get_singleton()->free(s.attribute_buffer);
+		}
+		if (s.skin_buffer.is_valid()) {
+			RD::get_singleton()->free(s.skin_buffer);
+		}
+		if (s.versions) {
+			memfree(s.versions); //reallocs, so free with memfree.
+		}
+
+		if (s.index_buffer.is_valid()) {
+			RD::get_singleton()->free(s.index_buffer);
+		}
+
+		if (s.lod_count) {
+			for (uint32_t j = 0; j < s.lod_count; j++) {
+				RD::get_singleton()->free(s.lods[j].index_buffer);
+			}
+			memdelete_arr(s.lods);
+		}
+
+		if (s.blend_shape_buffer.is_valid()) {
+			RD::get_singleton()->free(s.blend_shape_buffer);
+		}
+
+		memdelete(mesh->surfaces[i]);
+	}
+	if (mesh->surfaces) {
+		memfree(mesh->surfaces);
+	}
+
+	mesh->surfaces = nullptr;
+	mesh->surface_count = 0;
+	mesh->material_cache.clear();
+	//clear instance data
+	for (MeshInstance *mi : mesh->instances) {
+		_mesh_instance_clear(mi);
+	}
+	mesh->has_bone_weights = false;
+	mesh->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MESH);
+
+	for (Set<Mesh *>::Element *E = mesh->shadow_owners.front(); E; E = E->next()) {
+		Mesh *shadow_owner = E->get();
+		shadow_owner->shadow_mesh = RID();
+		shadow_owner->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MESH);
+	}
+}
+
+bool MeshStorage::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) {
+	Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+	ERR_FAIL_COND_V(!mesh, false);
+
+	return mesh->blend_shape_count > 0 || (mesh->has_bone_weights && p_has_skeleton);
+}
+
+/* MESH INSTANCE */
+
+RID MeshStorage::mesh_instance_create(RID p_base) {
+	Mesh *mesh = mesh_owner.get_or_null(p_base);
+	ERR_FAIL_COND_V(!mesh, RID());
+
+	RID rid = mesh_instance_owner.make_rid();
+	MeshInstance *mi = mesh_instance_owner.get_or_null(rid);
+
+	mi->mesh = mesh;
+
+	for (uint32_t i = 0; i < mesh->surface_count; i++) {
+		_mesh_instance_add_surface(mi, mesh, i);
+	}
+
+	mi->I = mesh->instances.push_back(mi);
+
+	mi->dirty = true;
+
+	return rid;
+}
+
+void MeshStorage::mesh_instance_free(RID p_rid) {
+	MeshInstance *mi = mesh_instance_owner.get_or_null(p_rid);
+	_mesh_instance_clear(mi);
+	mi->mesh->instances.erase(mi->I);
+	mi->I = nullptr;
+
+	mesh_instance_owner.free(p_rid);
+}
+
+void MeshStorage::mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) {
+	MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
+	if (mi->skeleton == p_skeleton) {
+		return;
+	}
+	mi->skeleton = p_skeleton;
+	mi->skeleton_version = 0;
+	mi->dirty = true;
+}
+
+void MeshStorage::mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) {
+	MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
+	ERR_FAIL_COND(!mi);
+	ERR_FAIL_INDEX(p_shape, (int)mi->blend_weights.size());
+	mi->blend_weights[p_shape] = p_weight;
+	mi->weights_dirty = true;
+	//will be eventually updated
+}
+
+void MeshStorage::_mesh_instance_clear(MeshInstance *mi) {
+	for (uint32_t i = 0; i < mi->surfaces.size(); i++) {
+		if (mi->surfaces[i].versions) {
+			for (uint32_t j = 0; j < mi->surfaces[i].version_count; j++) {
+				RD::get_singleton()->free(mi->surfaces[i].versions[j].vertex_array);
+			}
+			memfree(mi->surfaces[i].versions);
+		}
+		if (mi->surfaces[i].vertex_buffer.is_valid()) {
+			RD::get_singleton()->free(mi->surfaces[i].vertex_buffer);
+		}
+	}
+	mi->surfaces.clear();
+
+	if (mi->blend_weights_buffer.is_valid()) {
+		RD::get_singleton()->free(mi->blend_weights_buffer);
+	}
+	mi->blend_weights.clear();
+	mi->weights_dirty = false;
+	mi->skeleton_version = 0;
+}
+
+void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface) {
+	if (mesh->blend_shape_count > 0 && mi->blend_weights_buffer.is_null()) {
+		mi->blend_weights.resize(mesh->blend_shape_count);
+		for (uint32_t i = 0; i < mi->blend_weights.size(); i++) {
+			mi->blend_weights[i] = 0;
+		}
+		mi->blend_weights_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * mi->blend_weights.size(), mi->blend_weights.to_byte_array());
+		mi->weights_dirty = true;
+	}
+
+	MeshInstance::Surface s;
+	if (mesh->blend_shape_count > 0 || (mesh->surfaces[p_surface]->format & RS::ARRAY_FORMAT_BONES)) {
+		//surface warrants transform
+		s.vertex_buffer = RD::get_singleton()->vertex_buffer_create(mesh->surfaces[p_surface]->vertex_buffer_size, Vector<uint8_t>(), true);
+
+		Vector<RD::Uniform> uniforms;
+		{
+			RD::Uniform u;
+			u.binding = 1;
+			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+			u.append_id(s.vertex_buffer);
+			uniforms.push_back(u);
+		}
+		{
+			RD::Uniform u;
+			u.binding = 2;
+			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+			if (mi->blend_weights_buffer.is_valid()) {
+				u.append_id(mi->blend_weights_buffer);
+			} else {
+				u.append_id(default_rd_storage_buffer);
+			}
+			uniforms.push_back(u);
+		}
+		s.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_INSTANCE);
+	}
+
+	mi->surfaces.push_back(s);
+	mi->dirty = true;
+}
+
+void MeshStorage::mesh_instance_check_for_update(RID p_mesh_instance) {
+	MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
+
+	bool needs_update = mi->dirty;
+
+	if (mi->weights_dirty && !mi->weight_update_list.in_list()) {
+		dirty_mesh_instance_weights.add(&mi->weight_update_list);
+		needs_update = true;
+	}
+
+	if (mi->array_update_list.in_list()) {
+		return;
+	}
+
+	if (!needs_update && mi->skeleton.is_valid()) {
+		Skeleton *sk = skeleton_owner.get_or_null(mi->skeleton);
+		if (sk && sk->version != mi->skeleton_version) {
+			needs_update = true;
+		}
+	}
+
+	if (needs_update) {
+		dirty_mesh_instance_arrays.add(&mi->array_update_list);
+	}
+}
+
+void MeshStorage::update_mesh_instances() {
+	while (dirty_mesh_instance_weights.first()) {
+		MeshInstance *mi = dirty_mesh_instance_weights.first()->self();
+
+		if (mi->blend_weights_buffer.is_valid()) {
+			RD::get_singleton()->buffer_update(mi->blend_weights_buffer, 0, mi->blend_weights.size() * sizeof(float), mi->blend_weights.ptr());
+		}
+		dirty_mesh_instance_weights.remove(&mi->weight_update_list);
+		mi->weights_dirty = false;
+	}
+	if (dirty_mesh_instance_arrays.first() == nullptr) {
+		return; //nothing to do
+	}
+
+	//process skeletons and blend shapes
+	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+	while (dirty_mesh_instance_arrays.first()) {
+		MeshInstance *mi = dirty_mesh_instance_arrays.first()->self();
+
+		Skeleton *sk = skeleton_owner.get_or_null(mi->skeleton);
+
+		for (uint32_t i = 0; i < mi->surfaces.size(); i++) {
+			if (mi->surfaces[i].uniform_set == RID() || mi->mesh->surfaces[i]->uniform_set == RID()) {
+				continue;
+			}
+
+			bool array_is_2d = mi->mesh->surfaces[i]->format & RS::ARRAY_FLAG_USE_2D_VERTICES;
+
+			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, skeleton_shader.pipeline[array_is_2d ? SkeletonShader::SHADER_MODE_2D : SkeletonShader::SHADER_MODE_3D]);
+
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mi->surfaces[i].uniform_set, SkeletonShader::UNIFORM_SET_INSTANCE);
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mi->mesh->surfaces[i]->uniform_set, SkeletonShader::UNIFORM_SET_SURFACE);
+			if (sk && sk->uniform_set_mi.is_valid()) {
+				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sk->uniform_set_mi, SkeletonShader::UNIFORM_SET_SKELETON);
+			} else {
+				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, skeleton_shader.default_skeleton_uniform_set, SkeletonShader::UNIFORM_SET_SKELETON);
+			}
+
+			SkeletonShader::PushConstant push_constant;
+
+			push_constant.has_normal = mi->mesh->surfaces[i]->format & RS::ARRAY_FORMAT_NORMAL;
+			push_constant.has_tangent = mi->mesh->surfaces[i]->format & RS::ARRAY_FORMAT_TANGENT;
+			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.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.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;
+
+			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));
+
+			//dispatch without barrier, so all is done at the same time
+			RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.vertex_count, 1, 1);
+		}
+
+		mi->dirty = false;
+		if (sk) {
+			mi->skeleton_version = sk->version;
+		}
+		dirty_mesh_instance_arrays.remove(&mi->array_update_list);
+	}
+
+	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, MeshInstance::Surface *mis) {
+	Vector<RD::VertexAttribute> attributes;
+	Vector<RID> buffers;
+
+	uint32_t stride = 0;
+	uint32_t attribute_stride = 0;
+	uint32_t skin_stride = 0;
+
+	for (int i = 0; i < RS::ARRAY_INDEX; i++) {
+		RD::VertexAttribute vd;
+		RID buffer;
+		vd.location = i;
+
+		if (!(s->format & (1 << i))) {
+			// Not supplied by surface, use default value
+			buffer = mesh_default_rd_buffers[i];
+			vd.stride = 0;
+			switch (i) {
+				case RS::ARRAY_VERTEX: {
+					vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
+
+				} break;
+				case RS::ARRAY_NORMAL: {
+					vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
+				} break;
+				case RS::ARRAY_TANGENT: {
+					vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+				} break;
+				case RS::ARRAY_COLOR: {
+					vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+
+				} break;
+				case RS::ARRAY_TEX_UV: {
+					vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+
+				} break;
+				case RS::ARRAY_TEX_UV2: {
+					vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+				} break;
+				case RS::ARRAY_CUSTOM0:
+				case RS::ARRAY_CUSTOM1:
+				case RS::ARRAY_CUSTOM2:
+				case RS::ARRAY_CUSTOM3: {
+					//assumed weights too
+					vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+				} break;
+				case RS::ARRAY_BONES: {
+					//assumed weights too
+					vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
+				} break;
+				case RS::ARRAY_WEIGHTS: {
+					//assumed weights too
+					vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+				} break;
+			}
+		} else {
+			//Supplied, use it
+
+			vd.stride = 1; //mark that it needs a stride set (default uses 0)
+
+			switch (i) {
+				case RS::ARRAY_VERTEX: {
+					vd.offset = stride;
+
+					if (s->format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
+						vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+						stride += sizeof(float) * 2;
+					} else {
+						vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
+						stride += sizeof(float) * 3;
+					}
+
+					if (mis) {
+						buffer = mis->vertex_buffer;
+					} else {
+						buffer = s->vertex_buffer;
+					}
+
+				} break;
+				case RS::ARRAY_NORMAL: {
+					vd.offset = stride;
+
+					vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32;
+
+					stride += sizeof(uint32_t);
+					if (mis) {
+						buffer = mis->vertex_buffer;
+					} else {
+						buffer = s->vertex_buffer;
+					}
+				} break;
+				case RS::ARRAY_TANGENT: {
+					vd.offset = stride;
+
+					vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32;
+					stride += sizeof(uint32_t);
+					if (mis) {
+						buffer = mis->vertex_buffer;
+					} else {
+						buffer = s->vertex_buffer;
+					}
+				} break;
+				case RS::ARRAY_COLOR: {
+					vd.offset = attribute_stride;
+
+					vd.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+					attribute_stride += sizeof(int8_t) * 4;
+					buffer = s->attribute_buffer;
+				} break;
+				case RS::ARRAY_TEX_UV: {
+					vd.offset = attribute_stride;
+
+					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;
+					buffer = s->attribute_buffer;
+				} break;
+				case RS::ARRAY_CUSTOM0:
+				case RS::ARRAY_CUSTOM1:
+				case RS::ARRAY_CUSTOM2:
+				case RS::ARRAY_CUSTOM3: {
+					vd.offset = attribute_stride;
+
+					int idx = i - RS::ARRAY_CUSTOM0;
+					uint32_t fmt_shift[RS::ARRAY_CUSTOM_COUNT] = { RS::ARRAY_FORMAT_CUSTOM0_SHIFT, RS::ARRAY_FORMAT_CUSTOM1_SHIFT, RS::ARRAY_FORMAT_CUSTOM2_SHIFT, RS::ARRAY_FORMAT_CUSTOM3_SHIFT };
+					uint32_t fmt = (s->format >> fmt_shift[idx]) & RS::ARRAY_FORMAT_CUSTOM_MASK;
+					uint32_t fmtsize[RS::ARRAY_CUSTOM_MAX] = { 4, 4, 4, 8, 4, 8, 12, 16 };
+					RD::DataFormat fmtrd[RS::ARRAY_CUSTOM_MAX] = { RD::DATA_FORMAT_R8G8B8A8_UNORM, RD::DATA_FORMAT_R8G8B8A8_SNORM, RD::DATA_FORMAT_R16G16_SFLOAT, RD::DATA_FORMAT_R16G16B16A16_SFLOAT, RD::DATA_FORMAT_R32_SFLOAT, RD::DATA_FORMAT_R32G32_SFLOAT, RD::DATA_FORMAT_R32G32B32_SFLOAT, RD::DATA_FORMAT_R32G32B32A32_SFLOAT };
+					vd.format = fmtrd[fmt];
+					attribute_stride += fmtsize[fmt];
+					buffer = s->attribute_buffer;
+				} break;
+				case RS::ARRAY_BONES: {
+					vd.offset = skin_stride;
+
+					vd.format = RD::DATA_FORMAT_R16G16B16A16_UINT;
+					skin_stride += sizeof(int16_t) * 4;
+					buffer = s->skin_buffer;
+				} break;
+				case RS::ARRAY_WEIGHTS: {
+					vd.offset = skin_stride;
+
+					vd.format = RD::DATA_FORMAT_R16G16B16A16_UNORM;
+					skin_stride += sizeof(int16_t) * 4;
+					buffer = s->skin_buffer;
+				} break;
+			}
+		}
+
+		if (!(p_input_mask & (1 << i))) {
+			continue; // Shader does not need this, skip it (but computing stride was important anyway)
+		}
+
+		attributes.push_back(vd);
+		buffers.push_back(buffer);
+	}
+
+	//update final stride
+	for (int i = 0; i < attributes.size(); i++) {
+		if (attributes[i].stride == 0) {
+			continue; //default location
+		}
+		int loc = attributes[i].location;
+
+		if (loc < RS::ARRAY_COLOR) {
+			attributes.write[i].stride = stride;
+		} else if (loc < RS::ARRAY_BONES) {
+			attributes.write[i].stride = attribute_stride;
+		} else {
+			attributes.write[i].stride = skin_stride;
+		}
+	}
+
+	v.input_mask = p_input_mask;
+	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);
+}
+
+////////////////// MULTIMESH
+
+RID MeshStorage::multimesh_allocate() {
+	return multimesh_owner.allocate_rid();
+}
+void MeshStorage::multimesh_initialize(RID p_rid) {
+	multimesh_owner.initialize_rid(p_rid, MultiMesh());
+}
+
+void MeshStorage::multimesh_free(RID p_rid) {
+	_update_dirty_multimeshes();
+	multimesh_allocate_data(p_rid, 0, RS::MULTIMESH_TRANSFORM_2D);
+	MultiMesh *multimesh = multimesh_owner.get_or_null(p_rid);
+	multimesh->dependency.deleted_notify(p_rid);
+	multimesh_owner.free(p_rid);
+}
+
+void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) {
+	MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+	ERR_FAIL_COND(!multimesh);
+
+	if (multimesh->instances == p_instances && multimesh->xform_format == p_transform_format && multimesh->uses_colors == p_use_colors && multimesh->uses_custom_data == p_use_custom_data) {
+		return;
+	}
+
+	if (multimesh->buffer.is_valid()) {
+		RD::get_singleton()->free(multimesh->buffer);
+		multimesh->buffer = RID();
+		multimesh->uniform_set_2d = RID(); //cleared by dependency
+		multimesh->uniform_set_3d = RID(); //cleared by dependency
+	}
+
+	if (multimesh->data_cache_dirty_regions) {
+		memdelete_arr(multimesh->data_cache_dirty_regions);
+		multimesh->data_cache_dirty_regions = nullptr;
+		multimesh->data_cache_used_dirty_regions = 0;
+	}
+
+	multimesh->instances = p_instances;
+	multimesh->xform_format = p_transform_format;
+	multimesh->uses_colors = p_use_colors;
+	multimesh->color_offset_cache = p_transform_format == RS::MULTIMESH_TRANSFORM_2D ? 8 : 12;
+	multimesh->uses_custom_data = p_use_custom_data;
+	multimesh->custom_data_offset_cache = multimesh->color_offset_cache + (p_use_colors ? 4 : 0);
+	multimesh->stride_cache = multimesh->custom_data_offset_cache + (p_use_custom_data ? 4 : 0);
+	multimesh->buffer_set = false;
+
+	//print_line("allocate, elements: " + itos(p_instances) + " 2D: " + itos(p_transform_format == RS::MULTIMESH_TRANSFORM_2D) + " colors " + itos(multimesh->uses_colors) + " data " + itos(multimesh->uses_custom_data) + " stride " + itos(multimesh->stride_cache) + " total size " + itos(multimesh->stride_cache * multimesh->instances));
+	multimesh->data_cache = Vector<float>();
+	multimesh->aabb = AABB();
+	multimesh->aabb_dirty = false;
+	multimesh->visible_instances = MIN(multimesh->visible_instances, multimesh->instances);
+
+	if (multimesh->instances) {
+		multimesh->buffer = RD::get_singleton()->storage_buffer_create(multimesh->instances * multimesh->stride_cache * 4);
+	}
+
+	multimesh->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MULTIMESH);
+}
+
+int MeshStorage::multimesh_get_instance_count(RID p_multimesh) const {
+	MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+	ERR_FAIL_COND_V(!multimesh, 0);
+	return multimesh->instances;
+}
+
+void MeshStorage::multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
+	MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+	ERR_FAIL_COND(!multimesh);
+	if (multimesh->mesh == p_mesh) {
+		return;
+	}
+	multimesh->mesh = p_mesh;
+
+	if (multimesh->instances == 0) {
+		return;
+	}
+
+	if (multimesh->data_cache.size()) {
+		//we have a data cache, just mark it dirt
+		_multimesh_mark_all_dirty(multimesh, false, true);
+	} else if (multimesh->instances) {
+		//need to re-create AABB unfortunately, calling this has a penalty
+		if (multimesh->buffer_set) {
+			Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer);
+			const uint8_t *r = buffer.ptr();
+			const float *data = (const float *)r;
+			_multimesh_re_create_aabb(multimesh, data, multimesh->instances);
+		}
+	}
+
+	multimesh->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MESH);
+}
+
+#define MULTIMESH_DIRTY_REGION_SIZE 512
+
+void MeshStorage::_multimesh_make_local(MultiMesh *multimesh) const {
+	if (multimesh->data_cache.size() > 0) {
+		return; //already local
+	}
+	ERR_FAIL_COND(multimesh->data_cache.size() > 0);
+	// this means that the user wants to load/save individual elements,
+	// for this, the data must reside on CPU, so just copy it there.
+	multimesh->data_cache.resize(multimesh->instances * multimesh->stride_cache);
+	{
+		float *w = multimesh->data_cache.ptrw();
+
+		if (multimesh->buffer_set) {
+			Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer);
+			{
+				const uint8_t *r = buffer.ptr();
+				memcpy(w, r, buffer.size());
+			}
+		} else {
+			memset(w, 0, (size_t)multimesh->instances * multimesh->stride_cache * sizeof(float));
+		}
+	}
+	uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+	multimesh->data_cache_dirty_regions = memnew_arr(bool, data_cache_dirty_region_count);
+	for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
+		multimesh->data_cache_dirty_regions[i] = false;
+	}
+	multimesh->data_cache_used_dirty_regions = 0;
+}
+
+void MeshStorage::_multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb) {
+	uint32_t region_index = p_index / MULTIMESH_DIRTY_REGION_SIZE;
+#ifdef DEBUG_ENABLED
+	uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+	ERR_FAIL_UNSIGNED_INDEX(region_index, data_cache_dirty_region_count); //bug
+#endif
+	if (!multimesh->data_cache_dirty_regions[region_index]) {
+		multimesh->data_cache_dirty_regions[region_index] = true;
+		multimesh->data_cache_used_dirty_regions++;
+	}
+
+	if (p_aabb) {
+		multimesh->aabb_dirty = true;
+	}
+
+	if (!multimesh->dirty) {
+		multimesh->dirty_list = multimesh_dirty_list;
+		multimesh_dirty_list = multimesh;
+		multimesh->dirty = true;
+	}
+}
+
+void MeshStorage::_multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb) {
+	if (p_data) {
+		uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+
+		for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
+			if (!multimesh->data_cache_dirty_regions[i]) {
+				multimesh->data_cache_dirty_regions[i] = true;
+				multimesh->data_cache_used_dirty_regions++;
+			}
+		}
+	}
+
+	if (p_aabb) {
+		multimesh->aabb_dirty = true;
+	}
+
+	if (!multimesh->dirty) {
+		multimesh->dirty_list = multimesh_dirty_list;
+		multimesh_dirty_list = multimesh;
+		multimesh->dirty = true;
+	}
+}
+
+void MeshStorage::_multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances) {
+	ERR_FAIL_COND(multimesh->mesh.is_null());
+	AABB aabb;
+	AABB mesh_aabb = mesh_get_aabb(multimesh->mesh);
+	for (int i = 0; i < p_instances; i++) {
+		const float *data = p_data + multimesh->stride_cache * i;
+		Transform3D t;
+
+		if (multimesh->xform_format == RS::MULTIMESH_TRANSFORM_3D) {
+			t.basis.elements[0][0] = data[0];
+			t.basis.elements[0][1] = data[1];
+			t.basis.elements[0][2] = data[2];
+			t.origin.x = data[3];
+			t.basis.elements[1][0] = data[4];
+			t.basis.elements[1][1] = data[5];
+			t.basis.elements[1][2] = data[6];
+			t.origin.y = data[7];
+			t.basis.elements[2][0] = data[8];
+			t.basis.elements[2][1] = data[9];
+			t.basis.elements[2][2] = data[10];
+			t.origin.z = data[11];
+
+		} else {
+			t.basis.elements[0].x = data[0];
+			t.basis.elements[1].x = data[1];
+			t.origin.x = data[3];
+
+			t.basis.elements[0].y = data[4];
+			t.basis.elements[1].y = data[5];
+			t.origin.y = data[7];
+		}
+
+		if (i == 0) {
+			aabb = t.xform(mesh_aabb);
+		} else {
+			aabb.merge_with(t.xform(mesh_aabb));
+		}
+	}
+
+	multimesh->aabb = aabb;
+}
+
+void MeshStorage::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) {
+	MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+	ERR_FAIL_COND(!multimesh);
+	ERR_FAIL_INDEX(p_index, multimesh->instances);
+	ERR_FAIL_COND(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D);
+
+	_multimesh_make_local(multimesh);
+
+	{
+		float *w = multimesh->data_cache.ptrw();
+
+		float *dataptr = w + p_index * multimesh->stride_cache;
+
+		dataptr[0] = p_transform.basis.elements[0][0];
+		dataptr[1] = p_transform.basis.elements[0][1];
+		dataptr[2] = p_transform.basis.elements[0][2];
+		dataptr[3] = p_transform.origin.x;
+		dataptr[4] = p_transform.basis.elements[1][0];
+		dataptr[5] = p_transform.basis.elements[1][1];
+		dataptr[6] = p_transform.basis.elements[1][2];
+		dataptr[7] = p_transform.origin.y;
+		dataptr[8] = p_transform.basis.elements[2][0];
+		dataptr[9] = p_transform.basis.elements[2][1];
+		dataptr[10] = p_transform.basis.elements[2][2];
+		dataptr[11] = p_transform.origin.z;
+	}
+
+	_multimesh_mark_dirty(multimesh, p_index, true);
+}
+
+void MeshStorage::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) {
+	MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+	ERR_FAIL_COND(!multimesh);
+	ERR_FAIL_INDEX(p_index, multimesh->instances);
+	ERR_FAIL_COND(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_2D);
+
+	_multimesh_make_local(multimesh);
+
+	{
+		float *w = multimesh->data_cache.ptrw();
+
+		float *dataptr = w + p_index * multimesh->stride_cache;
+
+		dataptr[0] = p_transform.elements[0][0];
+		dataptr[1] = p_transform.elements[1][0];
+		dataptr[2] = 0;
+		dataptr[3] = p_transform.elements[2][0];
+		dataptr[4] = p_transform.elements[0][1];
+		dataptr[5] = p_transform.elements[1][1];
+		dataptr[6] = 0;
+		dataptr[7] = p_transform.elements[2][1];
+	}
+
+	_multimesh_mark_dirty(multimesh, p_index, true);
+}
+
+void MeshStorage::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) {
+	MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+	ERR_FAIL_COND(!multimesh);
+	ERR_FAIL_INDEX(p_index, multimesh->instances);
+	ERR_FAIL_COND(!multimesh->uses_colors);
+
+	_multimesh_make_local(multimesh);
+
+	{
+		float *w = multimesh->data_cache.ptrw();
+
+		float *dataptr = w + p_index * multimesh->stride_cache + multimesh->color_offset_cache;
+
+		dataptr[0] = p_color.r;
+		dataptr[1] = p_color.g;
+		dataptr[2] = p_color.b;
+		dataptr[3] = p_color.a;
+	}
+
+	_multimesh_mark_dirty(multimesh, p_index, false);
+}
+
+void MeshStorage::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) {
+	MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+	ERR_FAIL_COND(!multimesh);
+	ERR_FAIL_INDEX(p_index, multimesh->instances);
+	ERR_FAIL_COND(!multimesh->uses_custom_data);
+
+	_multimesh_make_local(multimesh);
+
+	{
+		float *w = multimesh->data_cache.ptrw();
+
+		float *dataptr = w + p_index * multimesh->stride_cache + multimesh->custom_data_offset_cache;
+
+		dataptr[0] = p_color.r;
+		dataptr[1] = p_color.g;
+		dataptr[2] = p_color.b;
+		dataptr[3] = p_color.a;
+	}
+
+	_multimesh_mark_dirty(multimesh, p_index, false);
+}
+
+RID MeshStorage::multimesh_get_mesh(RID p_multimesh) const {
+	MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+	ERR_FAIL_COND_V(!multimesh, RID());
+
+	return multimesh->mesh;
+}
+
+Transform3D MeshStorage::multimesh_instance_get_transform(RID p_multimesh, int p_index) const {
+	MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+	ERR_FAIL_COND_V(!multimesh, Transform3D());
+	ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform3D());
+	ERR_FAIL_COND_V(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D, Transform3D());
+
+	_multimesh_make_local(multimesh);
+
+	Transform3D t;
+	{
+		const float *r = multimesh->data_cache.ptr();
+
+		const float *dataptr = r + p_index * multimesh->stride_cache;
+
+		t.basis.elements[0][0] = dataptr[0];
+		t.basis.elements[0][1] = dataptr[1];
+		t.basis.elements[0][2] = dataptr[2];
+		t.origin.x = dataptr[3];
+		t.basis.elements[1][0] = dataptr[4];
+		t.basis.elements[1][1] = dataptr[5];
+		t.basis.elements[1][2] = dataptr[6];
+		t.origin.y = dataptr[7];
+		t.basis.elements[2][0] = dataptr[8];
+		t.basis.elements[2][1] = dataptr[9];
+		t.basis.elements[2][2] = dataptr[10];
+		t.origin.z = dataptr[11];
+	}
+
+	return t;
+}
+
+Transform2D MeshStorage::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const {
+	MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+	ERR_FAIL_COND_V(!multimesh, Transform2D());
+	ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform2D());
+	ERR_FAIL_COND_V(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_2D, Transform2D());
+
+	_multimesh_make_local(multimesh);
+
+	Transform2D t;
+	{
+		const float *r = multimesh->data_cache.ptr();
+
+		const float *dataptr = r + p_index * multimesh->stride_cache;
+
+		t.elements[0][0] = dataptr[0];
+		t.elements[1][0] = dataptr[1];
+		t.elements[2][0] = dataptr[3];
+		t.elements[0][1] = dataptr[4];
+		t.elements[1][1] = dataptr[5];
+		t.elements[2][1] = dataptr[7];
+	}
+
+	return t;
+}
+
+Color MeshStorage::multimesh_instance_get_color(RID p_multimesh, int p_index) const {
+	MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+	ERR_FAIL_COND_V(!multimesh, Color());
+	ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color());
+	ERR_FAIL_COND_V(!multimesh->uses_colors, Color());
+
+	_multimesh_make_local(multimesh);
+
+	Color c;
+	{
+		const float *r = multimesh->data_cache.ptr();
+
+		const float *dataptr = r + p_index * multimesh->stride_cache + multimesh->color_offset_cache;
+
+		c.r = dataptr[0];
+		c.g = dataptr[1];
+		c.b = dataptr[2];
+		c.a = dataptr[3];
+	}
+
+	return c;
+}
+
+Color MeshStorage::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const {
+	MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+	ERR_FAIL_COND_V(!multimesh, Color());
+	ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color());
+	ERR_FAIL_COND_V(!multimesh->uses_custom_data, Color());
+
+	_multimesh_make_local(multimesh);
+
+	Color c;
+	{
+		const float *r = multimesh->data_cache.ptr();
+
+		const float *dataptr = r + p_index * multimesh->stride_cache + multimesh->custom_data_offset_cache;
+
+		c.r = dataptr[0];
+		c.g = dataptr[1];
+		c.b = dataptr[2];
+		c.a = dataptr[3];
+	}
+
+	return c;
+}
+
+void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) {
+	MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+	ERR_FAIL_COND(!multimesh);
+	ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache));
+
+	{
+		const float *r = p_buffer.ptr();
+		RD::get_singleton()->buffer_update(multimesh->buffer, 0, p_buffer.size() * sizeof(float), r);
+		multimesh->buffer_set = true;
+	}
+
+	if (multimesh->data_cache.size()) {
+		//if we have a data cache, just update it
+		multimesh->data_cache = p_buffer;
+		{
+			//clear dirty since nothing will be dirty anymore
+			uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+			for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
+				multimesh->data_cache_dirty_regions[i] = false;
+			}
+			multimesh->data_cache_used_dirty_regions = 0;
+		}
+
+		_multimesh_mark_all_dirty(multimesh, false, true); //update AABB
+	} else if (multimesh->mesh.is_valid()) {
+		//if we have a mesh set, we need to re-generate the AABB from the new data
+		const float *data = p_buffer.ptr();
+
+		_multimesh_re_create_aabb(multimesh, data, multimesh->instances);
+		multimesh->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_AABB);
+	}
+}
+
+Vector<float> MeshStorage::multimesh_get_buffer(RID p_multimesh) const {
+	MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+	ERR_FAIL_COND_V(!multimesh, Vector<float>());
+	if (multimesh->buffer.is_null()) {
+		return Vector<float>();
+	} else if (multimesh->data_cache.size()) {
+		return multimesh->data_cache;
+	} else {
+		//get from memory
+
+		Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer);
+		Vector<float> ret;
+		ret.resize(multimesh->instances * multimesh->stride_cache);
+		{
+			float *w = ret.ptrw();
+			const uint8_t *r = buffer.ptr();
+			memcpy(w, r, buffer.size());
+		}
+
+		return ret;
+	}
+}
+
+void MeshStorage::multimesh_set_visible_instances(RID p_multimesh, int p_visible) {
+	MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+	ERR_FAIL_COND(!multimesh);
+	ERR_FAIL_COND(p_visible < -1 || p_visible > multimesh->instances);
+	if (multimesh->visible_instances == p_visible) {
+		return;
+	}
+
+	if (multimesh->data_cache.size()) {
+		//there is a data cache..
+		_multimesh_mark_all_dirty(multimesh, false, true);
+	}
+
+	multimesh->visible_instances = p_visible;
+
+	multimesh->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES);
+}
+
+int MeshStorage::multimesh_get_visible_instances(RID p_multimesh) const {
+	MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+	ERR_FAIL_COND_V(!multimesh, 0);
+	return multimesh->visible_instances;
+}
+
+AABB MeshStorage::multimesh_get_aabb(RID p_multimesh) const {
+	MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+	ERR_FAIL_COND_V(!multimesh, AABB());
+	if (multimesh->aabb_dirty) {
+		const_cast<MeshStorage *>(this)->_update_dirty_multimeshes();
+	}
+	return multimesh->aabb;
+}
+
+void MeshStorage::_update_dirty_multimeshes() {
+	while (multimesh_dirty_list) {
+		MultiMesh *multimesh = multimesh_dirty_list;
+
+		if (multimesh->data_cache.size()) { //may have been cleared, so only process if it exists
+			const float *data = multimesh->data_cache.ptr();
+
+			uint32_t visible_instances = multimesh->visible_instances >= 0 ? multimesh->visible_instances : multimesh->instances;
+
+			if (multimesh->data_cache_used_dirty_regions) {
+				uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+				uint32_t visible_region_count = visible_instances == 0 ? 0 : (visible_instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+
+				uint32_t region_size = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * sizeof(float);
+
+				if (multimesh->data_cache_used_dirty_regions > 32 || multimesh->data_cache_used_dirty_regions > visible_region_count / 2) {
+					//if there too many dirty regions, or represent the majority of regions, just copy all, else transfer cost piles up too much
+					RD::get_singleton()->buffer_update(multimesh->buffer, 0, MIN(visible_region_count * region_size, multimesh->instances * (uint32_t)multimesh->stride_cache * (uint32_t)sizeof(float)), data);
+				} else {
+					//not that many regions? update them all
+					for (uint32_t i = 0; i < visible_region_count; i++) {
+						if (multimesh->data_cache_dirty_regions[i]) {
+							uint32_t offset = i * region_size;
+							uint32_t size = multimesh->stride_cache * (uint32_t)multimesh->instances * (uint32_t)sizeof(float);
+							uint32_t region_start_index = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * i;
+							RD::get_singleton()->buffer_update(multimesh->buffer, offset, MIN(region_size, size - offset), &data[region_start_index]);
+						}
+					}
+				}
+
+				for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
+					multimesh->data_cache_dirty_regions[i] = false;
+				}
+
+				multimesh->data_cache_used_dirty_regions = 0;
+			}
+
+			if (multimesh->aabb_dirty) {
+				//aabb is dirty..
+				_multimesh_re_create_aabb(multimesh, data, visible_instances);
+				multimesh->aabb_dirty = false;
+				multimesh->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_AABB);
+			}
+		}
+
+		multimesh_dirty_list = multimesh->dirty_list;
+
+		multimesh->dirty_list = nullptr;
+		multimesh->dirty = false;
+	}
+
+	multimesh_dirty_list = nullptr;
+}
+
+/* SKELETON API */
+
+RID MeshStorage::skeleton_allocate() {
+	return skeleton_owner.allocate_rid();
+}
+void MeshStorage::skeleton_initialize(RID p_rid) {
+	skeleton_owner.initialize_rid(p_rid, Skeleton());
+}
+
+void MeshStorage::skeleton_free(RID p_rid) {
+	_update_dirty_skeletons();
+	skeleton_allocate_data(p_rid, 0);
+	Skeleton *skeleton = skeleton_owner.get_or_null(p_rid);
+	skeleton->dependency.deleted_notify(p_rid);
+	skeleton_owner.free(p_rid);
+}
+
+void MeshStorage::_skeleton_make_dirty(Skeleton *skeleton) {
+	if (!skeleton->dirty) {
+		skeleton->dirty = true;
+		skeleton->dirty_list = skeleton_dirty_list;
+		skeleton_dirty_list = skeleton;
+	}
+}
+
+void MeshStorage::skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton) {
+	Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
+	ERR_FAIL_COND(!skeleton);
+	ERR_FAIL_COND(p_bones < 0);
+
+	if (skeleton->size == p_bones && skeleton->use_2d == p_2d_skeleton) {
+		return;
+	}
+
+	skeleton->size = p_bones;
+	skeleton->use_2d = p_2d_skeleton;
+	skeleton->uniform_set_3d = RID();
+
+	if (skeleton->buffer.is_valid()) {
+		RD::get_singleton()->free(skeleton->buffer);
+		skeleton->buffer = RID();
+		skeleton->data.clear();
+		skeleton->uniform_set_mi = RID();
+	}
+
+	if (skeleton->size) {
+		skeleton->data.resize(skeleton->size * (skeleton->use_2d ? 8 : 12));
+		skeleton->buffer = RD::get_singleton()->storage_buffer_create(skeleton->data.size() * sizeof(float));
+		memset(skeleton->data.ptrw(), 0, skeleton->data.size() * sizeof(float));
+
+		_skeleton_make_dirty(skeleton);
+
+		{
+			Vector<RD::Uniform> uniforms;
+			{
+				RD::Uniform u;
+				u.binding = 0;
+				u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+				u.append_id(skeleton->buffer);
+				uniforms.push_back(u);
+			}
+			skeleton->uniform_set_mi = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_SKELETON);
+		}
+	}
+
+	skeleton->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_SKELETON_DATA);
+}
+
+int MeshStorage::skeleton_get_bone_count(RID p_skeleton) const {
+	Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
+	ERR_FAIL_COND_V(!skeleton, 0);
+
+	return skeleton->size;
+}
+
+void MeshStorage::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) {
+	Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
+
+	ERR_FAIL_COND(!skeleton);
+	ERR_FAIL_INDEX(p_bone, skeleton->size);
+	ERR_FAIL_COND(skeleton->use_2d);
+
+	float *dataptr = skeleton->data.ptrw() + p_bone * 12;
+
+	dataptr[0] = p_transform.basis.elements[0][0];
+	dataptr[1] = p_transform.basis.elements[0][1];
+	dataptr[2] = p_transform.basis.elements[0][2];
+	dataptr[3] = p_transform.origin.x;
+	dataptr[4] = p_transform.basis.elements[1][0];
+	dataptr[5] = p_transform.basis.elements[1][1];
+	dataptr[6] = p_transform.basis.elements[1][2];
+	dataptr[7] = p_transform.origin.y;
+	dataptr[8] = p_transform.basis.elements[2][0];
+	dataptr[9] = p_transform.basis.elements[2][1];
+	dataptr[10] = p_transform.basis.elements[2][2];
+	dataptr[11] = p_transform.origin.z;
+
+	_skeleton_make_dirty(skeleton);
+}
+
+Transform3D MeshStorage::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const {
+	Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
+
+	ERR_FAIL_COND_V(!skeleton, Transform3D());
+	ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform3D());
+	ERR_FAIL_COND_V(skeleton->use_2d, Transform3D());
+
+	const float *dataptr = skeleton->data.ptr() + p_bone * 12;
+
+	Transform3D t;
+
+	t.basis.elements[0][0] = dataptr[0];
+	t.basis.elements[0][1] = dataptr[1];
+	t.basis.elements[0][2] = dataptr[2];
+	t.origin.x = dataptr[3];
+	t.basis.elements[1][0] = dataptr[4];
+	t.basis.elements[1][1] = dataptr[5];
+	t.basis.elements[1][2] = dataptr[6];
+	t.origin.y = dataptr[7];
+	t.basis.elements[2][0] = dataptr[8];
+	t.basis.elements[2][1] = dataptr[9];
+	t.basis.elements[2][2] = dataptr[10];
+	t.origin.z = dataptr[11];
+
+	return t;
+}
+
+void MeshStorage::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) {
+	Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
+
+	ERR_FAIL_COND(!skeleton);
+	ERR_FAIL_INDEX(p_bone, skeleton->size);
+	ERR_FAIL_COND(!skeleton->use_2d);
+
+	float *dataptr = skeleton->data.ptrw() + p_bone * 8;
+
+	dataptr[0] = p_transform.elements[0][0];
+	dataptr[1] = p_transform.elements[1][0];
+	dataptr[2] = 0;
+	dataptr[3] = p_transform.elements[2][0];
+	dataptr[4] = p_transform.elements[0][1];
+	dataptr[5] = p_transform.elements[1][1];
+	dataptr[6] = 0;
+	dataptr[7] = p_transform.elements[2][1];
+
+	_skeleton_make_dirty(skeleton);
+}
+
+Transform2D MeshStorage::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const {
+	Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
+
+	ERR_FAIL_COND_V(!skeleton, Transform2D());
+	ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform2D());
+	ERR_FAIL_COND_V(!skeleton->use_2d, Transform2D());
+
+	const float *dataptr = skeleton->data.ptr() + p_bone * 8;
+
+	Transform2D t;
+	t.elements[0][0] = dataptr[0];
+	t.elements[1][0] = dataptr[1];
+	t.elements[2][0] = dataptr[3];
+	t.elements[0][1] = dataptr[4];
+	t.elements[1][1] = dataptr[5];
+	t.elements[2][1] = dataptr[7];
+
+	return t;
+}
+
+void MeshStorage::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) {
+	Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
+
+	ERR_FAIL_COND(!skeleton->use_2d);
+
+	skeleton->base_transform_2d = p_base_transform;
+}
+
+void MeshStorage::_update_dirty_skeletons() {
+	while (skeleton_dirty_list) {
+		Skeleton *skeleton = skeleton_dirty_list;
+
+		if (skeleton->size) {
+			RD::get_singleton()->buffer_update(skeleton->buffer, 0, skeleton->data.size() * sizeof(float), skeleton->data.ptr());
+		}
+
+		skeleton_dirty_list = skeleton->dirty_list;
+
+		skeleton->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_SKELETON_BONES);
+
+		skeleton->version++;
+
+		skeleton->dirty = false;
+		skeleton->dirty_list = nullptr;
+	}
+
+	skeleton_dirty_list = nullptr;
+}
+
+void MeshStorage::skeleton_update_dependency(RID p_skeleton, RendererStorage::DependencyTracker *p_instance) {
+	Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
+	ERR_FAIL_COND(!skeleton);
+
+	p_instance->update_dependency(&skeleton->dependency);
+}

+ 694 - 0
servers/rendering/renderer_rd/storage_rd/mesh_storage.h

@@ -0,0 +1,694 @@
+/*************************************************************************/
+/*  mesh_storage.h                                                       */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef MESH_STORAGE_RD_H
+#define MESH_STORAGE_RD_H
+
+#include "core/templates/local_vector.h"
+#include "core/templates/rid_owner.h"
+#include "core/templates/self_list.h"
+#include "servers/rendering/renderer_rd/shaders/skeleton.glsl.gen.h"
+#include "servers/rendering/renderer_storage.h"
+#include "servers/rendering/storage/mesh_storage.h"
+
+namespace RendererRD {
+
+/* Mesh */
+
+enum DefaultRDBuffer {
+	DEFAULT_RD_BUFFER_VERTEX,
+	DEFAULT_RD_BUFFER_NORMAL,
+	DEFAULT_RD_BUFFER_TANGENT,
+	DEFAULT_RD_BUFFER_COLOR,
+	DEFAULT_RD_BUFFER_TEX_UV,
+	DEFAULT_RD_BUFFER_TEX_UV2,
+	DEFAULT_RD_BUFFER_CUSTOM0,
+	DEFAULT_RD_BUFFER_CUSTOM1,
+	DEFAULT_RD_BUFFER_CUSTOM2,
+	DEFAULT_RD_BUFFER_CUSTOM3,
+	DEFAULT_RD_BUFFER_BONES,
+	DEFAULT_RD_BUFFER_WEIGHTS,
+	DEFAULT_RD_BUFFER_MAX,
+};
+
+struct MeshInstance;
+
+struct Mesh {
+	struct Surface {
+		RS::PrimitiveType primitive = RS::PRIMITIVE_POINTS;
+		uint32_t format = 0;
+
+		RID vertex_buffer;
+		RID attribute_buffer;
+		RID skin_buffer;
+		uint32_t vertex_count = 0;
+		uint32_t vertex_buffer_size = 0;
+		uint32_t skin_buffer_size = 0;
+
+		// A different pipeline needs to be allocated
+		// depending on the inputs available in the
+		// material.
+		// There are never that many geometry/material
+		// combinations, so a simple array is the most
+		// cache-efficient structure.
+
+		struct Version {
+			uint32_t input_mask = 0;
+			RD::VertexFormatID vertex_format = 0;
+			RID vertex_array;
+		};
+
+		SpinLock version_lock; //needed to access versions
+		Version *versions = nullptr; //allocated on demand
+		uint32_t version_count = 0;
+
+		RID index_buffer;
+		RID index_array;
+		uint32_t index_count = 0;
+
+		struct LOD {
+			float edge_length = 0.0;
+			uint32_t index_count = 0;
+			RID index_buffer;
+			RID index_array;
+		};
+
+		LOD *lods = nullptr;
+		uint32_t lod_count = 0;
+
+		AABB aabb;
+
+		Vector<AABB> bone_aabbs;
+
+		RID blend_shape_buffer;
+
+		RID material;
+
+		uint32_t render_index = 0;
+		uint64_t render_pass = 0;
+
+		uint32_t multimesh_render_index = 0;
+		uint64_t multimesh_render_pass = 0;
+
+		uint32_t particles_render_index = 0;
+		uint64_t particles_render_pass = 0;
+
+		RID uniform_set;
+	};
+
+	uint32_t blend_shape_count = 0;
+	RS::BlendShapeMode blend_shape_mode = RS::BLEND_SHAPE_MODE_NORMALIZED;
+
+	Surface **surfaces = nullptr;
+	uint32_t surface_count = 0;
+
+	Vector<AABB> bone_aabbs;
+
+	bool has_bone_weights = false;
+
+	AABB aabb;
+	AABB custom_aabb;
+
+	Vector<RID> material_cache;
+
+	List<MeshInstance *> instances;
+
+	RID shadow_mesh;
+	Set<Mesh *> shadow_owners;
+
+	RendererStorage::Dependency dependency;
+};
+
+/* Mesh Instance */
+
+struct MeshInstance {
+	Mesh *mesh;
+	RID skeleton;
+	struct Surface {
+		RID vertex_buffer;
+		RID uniform_set;
+
+		Mesh::Surface::Version *versions = nullptr; //allocated on demand
+		uint32_t version_count = 0;
+	};
+	LocalVector<Surface> surfaces;
+	LocalVector<float> blend_weights;
+
+	RID blend_weights_buffer;
+	List<MeshInstance *>::Element *I = nullptr; //used to erase itself
+	uint64_t skeleton_version = 0;
+	bool dirty = false;
+	bool weights_dirty = false;
+	SelfList<MeshInstance> weight_update_list;
+	SelfList<MeshInstance> array_update_list;
+	MeshInstance() :
+			weight_update_list(this), array_update_list(this) {}
+};
+
+/* MultiMesh */
+
+struct MultiMesh {
+	RID mesh;
+	int instances = 0;
+	RS::MultimeshTransformFormat xform_format = RS::MULTIMESH_TRANSFORM_3D;
+	bool uses_colors = false;
+	bool uses_custom_data = false;
+	int visible_instances = -1;
+	AABB aabb;
+	bool aabb_dirty = false;
+	bool buffer_set = false;
+	uint32_t stride_cache = 0;
+	uint32_t color_offset_cache = 0;
+	uint32_t custom_data_offset_cache = 0;
+
+	Vector<float> data_cache; //used if individual setting is used
+	bool *data_cache_dirty_regions = nullptr;
+	uint32_t data_cache_used_dirty_regions = 0;
+
+	RID buffer; //storage buffer
+	RID uniform_set_3d;
+	RID uniform_set_2d;
+
+	bool dirty = false;
+	MultiMesh *dirty_list = nullptr;
+
+	RendererStorage::Dependency dependency;
+};
+
+/* Skeleton */
+
+struct SkeletonShader {
+	struct PushConstant {
+		uint32_t has_normal;
+		uint32_t has_tangent;
+		uint32_t has_skeleton;
+		uint32_t has_blend_shape;
+
+		uint32_t vertex_count;
+		uint32_t vertex_stride;
+		uint32_t skin_stride;
+		uint32_t skin_weight_offset;
+
+		uint32_t blend_shape_count;
+		uint32_t normalized_blend_shapes;
+		uint32_t pad0;
+		uint32_t pad1;
+	};
+
+	enum {
+		UNIFORM_SET_INSTANCE = 0,
+		UNIFORM_SET_SURFACE = 1,
+		UNIFORM_SET_SKELETON = 2,
+	};
+	enum {
+		SHADER_MODE_2D,
+		SHADER_MODE_3D,
+		SHADER_MODE_MAX
+	};
+
+	SkeletonShaderRD shader;
+	RID version;
+	RID version_shader[SHADER_MODE_MAX];
+	RID pipeline[SHADER_MODE_MAX];
+
+	RID default_skeleton_uniform_set;
+};
+
+struct Skeleton {
+	bool use_2d = false;
+	int size = 0;
+	Vector<float> data;
+	RID buffer;
+
+	bool dirty = false;
+	Skeleton *dirty_list = nullptr;
+	Transform2D base_transform_2d;
+
+	RID uniform_set_3d;
+	RID uniform_set_mi;
+
+	uint64_t version = 1;
+
+	RendererStorage::Dependency dependency;
+};
+
+class MeshStorage : public RendererMeshStorage {
+private:
+	static MeshStorage *singleton;
+
+	RID mesh_default_rd_buffers[DEFAULT_RD_BUFFER_MAX];
+	RID default_rd_storage_buffer;
+
+	/* Mesh */
+
+	mutable RID_Owner<Mesh, true> mesh_owner;
+
+	void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, MeshInstance::Surface *mis = nullptr);
+
+	/* Mesh Instance API */
+
+	void _mesh_instance_clear(MeshInstance *mi);
+	void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface);
+
+	mutable RID_Owner<MeshInstance> mesh_instance_owner;
+
+	SelfList<MeshInstance>::List dirty_mesh_instance_weights;
+	SelfList<MeshInstance>::List dirty_mesh_instance_arrays;
+
+	/* MultiMesh */
+
+	mutable RID_Owner<MultiMesh, true> multimesh_owner;
+
+	MultiMesh *multimesh_dirty_list = nullptr;
+
+	_FORCE_INLINE_ void _multimesh_make_local(MultiMesh *multimesh) const;
+	_FORCE_INLINE_ void _multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb);
+	_FORCE_INLINE_ void _multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb);
+	_FORCE_INLINE_ void _multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances);
+
+	/* Skeleton */
+
+	SkeletonShader skeleton_shader;
+
+	mutable RID_Owner<Skeleton, true> skeleton_owner;
+
+	_FORCE_INLINE_ void _skeleton_make_dirty(Skeleton *skeleton);
+
+	Skeleton *skeleton_dirty_list = nullptr;
+
+public:
+	static MeshStorage *get_singleton();
+
+	MeshStorage();
+	virtual ~MeshStorage();
+
+	RID get_default_rd_storage_buffer() { return default_rd_storage_buffer; }
+
+	/* MESH API */
+
+	Mesh *get_mesh(RID p_rid) { return mesh_owner.get_or_null(p_rid); };
+	bool owns_mesh(RID p_rid) { return mesh_owner.owns(p_rid); };
+
+	virtual RID mesh_allocate() override;
+	virtual void mesh_initialize(RID p_mesh) override;
+	virtual void mesh_free(RID p_rid) override;
+
+	virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) override;
+
+	/// Return stride
+	virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) override;
+
+	virtual int mesh_get_blend_shape_count(RID p_mesh) const override;
+
+	virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) override;
+	virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const override;
+
+	virtual void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override;
+	virtual void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override;
+	virtual void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override;
+
+	virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) override;
+	virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const override;
+
+	virtual RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const override;
+
+	virtual int mesh_get_surface_count(RID p_mesh) const override;
+
+	virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) override;
+	virtual AABB mesh_get_custom_aabb(RID p_mesh) const override;
+
+	virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) override;
+	virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override;
+
+	virtual void mesh_clear(RID p_mesh) override;
+
+	virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override;
+
+	_FORCE_INLINE_ const RID *mesh_get_surface_count_and_materials(RID p_mesh, uint32_t &r_surface_count) {
+		Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+		ERR_FAIL_COND_V(!mesh, nullptr);
+		r_surface_count = mesh->surface_count;
+		if (r_surface_count == 0) {
+			return nullptr;
+		}
+		if (mesh->material_cache.is_empty()) {
+			mesh->material_cache.resize(mesh->surface_count);
+			for (uint32_t i = 0; i < r_surface_count; i++) {
+				mesh->material_cache.write[i] = mesh->surfaces[i]->material;
+			}
+		}
+
+		return mesh->material_cache.ptr();
+	}
+
+	_FORCE_INLINE_ void *mesh_get_surface(RID p_mesh, uint32_t p_surface_index) {
+		Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+		ERR_FAIL_COND_V(!mesh, nullptr);
+		ERR_FAIL_UNSIGNED_INDEX_V(p_surface_index, mesh->surface_count, nullptr);
+
+		return mesh->surfaces[p_surface_index];
+	}
+
+	_FORCE_INLINE_ RID mesh_get_shadow_mesh(RID p_mesh) {
+		Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+		ERR_FAIL_COND_V(!mesh, RID());
+
+		return mesh->shadow_mesh;
+	}
+
+	_FORCE_INLINE_ RS::PrimitiveType mesh_surface_get_primitive(void *p_surface) {
+		Mesh::Surface *surface = reinterpret_cast<Mesh::Surface *>(p_surface);
+		return surface->primitive;
+	}
+
+	_FORCE_INLINE_ bool mesh_surface_has_lod(void *p_surface) const {
+		Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+		return s->lod_count > 0;
+	}
+
+	_FORCE_INLINE_ uint32_t mesh_surface_get_vertices_drawn_count(void *p_surface) const {
+		Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+		return s->index_count ? s->index_count : s->vertex_count;
+	}
+
+	_FORCE_INLINE_ uint32_t mesh_surface_get_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_mesh_lod_threshold, uint32_t *r_index_count = nullptr) const {
+		Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+
+		int32_t current_lod = -1;
+		if (r_index_count) {
+			*r_index_count = s->index_count;
+		}
+		for (uint32_t i = 0; i < s->lod_count; i++) {
+			float screen_size = s->lods[i].edge_length * p_model_scale / p_distance_threshold;
+			if (screen_size > p_mesh_lod_threshold) {
+				break;
+			}
+			current_lod = i;
+		}
+		if (current_lod == -1) {
+			return 0;
+		} else {
+			if (r_index_count) {
+				*r_index_count = s->lods[current_lod].index_count;
+			}
+			return current_lod + 1;
+		}
+	}
+
+	_FORCE_INLINE_ RID mesh_surface_get_index_array(void *p_surface, uint32_t p_lod) const {
+		Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+
+		if (p_lod == 0) {
+			return s->index_array;
+		} else {
+			return s->lods[p_lod - 1].index_array;
+		}
+	}
+
+	_FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint32_t p_input_mask, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) {
+		Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+
+		s->version_lock.lock();
+
+		//there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way
+
+		for (uint32_t i = 0; i < s->version_count; i++) {
+			if (s->versions[i].input_mask != p_input_mask) {
+				continue;
+			}
+			//we have this version, hooray
+			r_vertex_format = s->versions[i].vertex_format;
+			r_vertex_array_rd = s->versions[i].vertex_array;
+			s->version_lock.unlock();
+			return;
+		}
+
+		uint32_t version = s->version_count;
+		s->version_count++;
+		s->versions = (Mesh::Surface::Version *)memrealloc(s->versions, sizeof(Mesh::Surface::Version) * s->version_count);
+
+		_mesh_surface_generate_version_for_input_mask(s->versions[version], s, p_input_mask);
+
+		r_vertex_format = s->versions[version].vertex_format;
+		r_vertex_array_rd = s->versions[version].vertex_array;
+
+		s->version_lock.unlock();
+	}
+
+	_FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint32_t p_input_mask, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) {
+		MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
+		ERR_FAIL_COND(!mi);
+		Mesh *mesh = mi->mesh;
+		ERR_FAIL_UNSIGNED_INDEX(p_surface_index, mesh->surface_count);
+
+		MeshInstance::Surface *mis = &mi->surfaces[p_surface_index];
+		Mesh::Surface *s = mesh->surfaces[p_surface_index];
+
+		s->version_lock.lock();
+
+		//there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way
+
+		for (uint32_t i = 0; i < mis->version_count; i++) {
+			if (mis->versions[i].input_mask != p_input_mask) {
+				continue;
+			}
+			//we have this version, hooray
+			r_vertex_format = mis->versions[i].vertex_format;
+			r_vertex_array_rd = mis->versions[i].vertex_array;
+			s->version_lock.unlock();
+			return;
+		}
+
+		uint32_t version = mis->version_count;
+		mis->version_count++;
+		mis->versions = (Mesh::Surface::Version *)memrealloc(mis->versions, sizeof(Mesh::Surface::Version) * mis->version_count);
+
+		_mesh_surface_generate_version_for_input_mask(mis->versions[version], s, p_input_mask, mis);
+
+		r_vertex_format = mis->versions[version].vertex_format;
+		r_vertex_array_rd = mis->versions[version].vertex_array;
+
+		s->version_lock.unlock();
+	}
+
+	_FORCE_INLINE_ RID mesh_get_default_rd_buffer(DefaultRDBuffer p_buffer) {
+		ERR_FAIL_INDEX_V(p_buffer, DEFAULT_RD_BUFFER_MAX, RID());
+		return mesh_default_rd_buffers[p_buffer];
+	}
+
+	_FORCE_INLINE_ uint32_t mesh_surface_get_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) {
+		Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+		Mesh::Surface *s = mesh->surfaces[p_surface_index];
+
+		if (s->render_pass != p_render_pass) {
+			(*r_index)++;
+			s->render_pass = p_render_pass;
+			s->render_index = *r_index;
+		}
+
+		return s->render_index;
+	}
+
+	_FORCE_INLINE_ uint32_t mesh_surface_get_multimesh_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) {
+		Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+		Mesh::Surface *s = mesh->surfaces[p_surface_index];
+
+		if (s->multimesh_render_pass != p_render_pass) {
+			(*r_index)++;
+			s->multimesh_render_pass = p_render_pass;
+			s->multimesh_render_index = *r_index;
+		}
+
+		return s->multimesh_render_index;
+	}
+
+	_FORCE_INLINE_ uint32_t mesh_surface_get_particles_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) {
+		Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+		Mesh::Surface *s = mesh->surfaces[p_surface_index];
+
+		if (s->particles_render_pass != p_render_pass) {
+			(*r_index)++;
+			s->particles_render_pass = p_render_pass;
+			s->particles_render_index = *r_index;
+		}
+
+		return s->particles_render_index;
+	}
+
+	/* MESH INSTANCE API */
+
+	MeshInstance *get_mesh_instance(RID p_rid) { return mesh_instance_owner.get_or_null(p_rid); };
+	bool owns_mesh_instance(RID p_rid) { return mesh_instance_owner.owns(p_rid); };
+
+	virtual RID mesh_instance_create(RID p_base) override;
+	virtual void mesh_instance_free(RID p_rid) override;
+	virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override;
+	virtual void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) override;
+	virtual void mesh_instance_check_for_update(RID p_mesh_instance) override;
+	virtual void update_mesh_instances() override;
+
+	/* MULTIMESH API */
+
+	MultiMesh *get_multimesh(RID p_rid) { return multimesh_owner.get_or_null(p_rid); };
+	bool owns_multimesh(RID p_rid) { return multimesh_owner.owns(p_rid); };
+
+	virtual RID multimesh_allocate() override;
+	virtual void multimesh_initialize(RID p_multimesh) override;
+	virtual void multimesh_free(RID p_rid) override;
+
+	virtual void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) override;
+	virtual int multimesh_get_instance_count(RID p_multimesh) const override;
+
+	virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) override;
+	virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) override;
+	virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) override;
+	virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override;
+	virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override;
+
+	virtual RID multimesh_get_mesh(RID p_multimesh) const override;
+
+	virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const override;
+	virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override;
+	virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const override;
+	virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override;
+
+	virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override;
+	virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const override;
+
+	virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) override;
+	virtual int multimesh_get_visible_instances(RID p_multimesh) const override;
+
+	virtual AABB multimesh_get_aabb(RID p_multimesh) const override;
+
+	void _update_dirty_multimeshes();
+
+	_FORCE_INLINE_ RS::MultimeshTransformFormat multimesh_get_transform_format(RID p_multimesh) const {
+		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+		return multimesh->xform_format;
+	}
+
+	_FORCE_INLINE_ bool multimesh_uses_colors(RID p_multimesh) const {
+		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+		return multimesh->uses_colors;
+	}
+
+	_FORCE_INLINE_ bool multimesh_uses_custom_data(RID p_multimesh) const {
+		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+		return multimesh->uses_custom_data;
+	}
+
+	_FORCE_INLINE_ uint32_t multimesh_get_instances_to_draw(RID p_multimesh) const {
+		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+		if (multimesh->visible_instances >= 0) {
+			return multimesh->visible_instances;
+		}
+		return multimesh->instances;
+	}
+
+	_FORCE_INLINE_ RID multimesh_get_3d_uniform_set(RID p_multimesh, RID p_shader, uint32_t p_set) const {
+		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+		if (!multimesh->uniform_set_3d.is_valid()) {
+			Vector<RD::Uniform> uniforms;
+			RD::Uniform u;
+			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+			u.binding = 0;
+			u.append_id(multimesh->buffer);
+			uniforms.push_back(u);
+			multimesh->uniform_set_3d = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set);
+		}
+
+		return multimesh->uniform_set_3d;
+	}
+
+	_FORCE_INLINE_ RID multimesh_get_2d_uniform_set(RID p_multimesh, RID p_shader, uint32_t p_set) const {
+		MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+		if (!multimesh->uniform_set_2d.is_valid()) {
+			Vector<RD::Uniform> uniforms;
+			RD::Uniform u;
+			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+			u.binding = 0;
+			u.append_id(multimesh->buffer);
+			uniforms.push_back(u);
+			multimesh->uniform_set_2d = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set);
+		}
+
+		return multimesh->uniform_set_2d;
+	}
+
+	/* SKELETON API */
+
+	Skeleton *get_skeleton(RID p_rid) { return skeleton_owner.get_or_null(p_rid); };
+	bool owns_skeleton(RID p_rid) { return skeleton_owner.owns(p_rid); };
+
+	virtual RID skeleton_allocate() override;
+	virtual void skeleton_initialize(RID p_skeleton) override;
+	virtual void skeleton_free(RID p_rid) override;
+
+	virtual void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) override;
+	virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) override;
+	void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform3D &p_world_transform);
+	virtual int skeleton_get_bone_count(RID p_skeleton) const override;
+	virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) override;
+	virtual Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const override;
+	virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) override;
+	virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const override;
+
+	virtual void skeleton_update_dependency(RID p_skeleton, RendererStorage::DependencyTracker *p_instance) override;
+
+	void _update_dirty_skeletons();
+
+	_FORCE_INLINE_ bool skeleton_is_valid(RID p_skeleton) {
+		return skeleton_owner.get_or_null(p_skeleton) != nullptr;
+	}
+
+	_FORCE_INLINE_ RID skeleton_get_3d_uniform_set(RID p_skeleton, RID p_shader, uint32_t p_set) const {
+		Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
+		ERR_FAIL_COND_V(!skeleton, RID());
+		ERR_FAIL_COND_V(skeleton->size == 0, RID());
+		if (skeleton->use_2d) {
+			return RID();
+		}
+		if (!skeleton->uniform_set_3d.is_valid()) {
+			Vector<RD::Uniform> uniforms;
+			RD::Uniform u;
+			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+			u.binding = 0;
+			u.append_id(skeleton->buffer);
+			uniforms.push_back(u);
+			skeleton->uniform_set_3d = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set);
+		}
+
+		return skeleton->uniform_set_3d;
+	}
+};
+
+} // namespace RendererRD
+
+#endif // !MESH_STORAGE_RD_H

+ 24 - 24
servers/rendering/renderer_scene_cull.cpp

@@ -464,10 +464,10 @@ void RendererSceneCull::instance_initialize(RID p_rid) {
 }
 }
 
 
 void RendererSceneCull::_instance_update_mesh_instance(Instance *p_instance) {
 void RendererSceneCull::_instance_update_mesh_instance(Instance *p_instance) {
-	bool needs_instance = RSG::storage->mesh_needs_instance(p_instance->base, p_instance->skeleton.is_valid());
+	bool needs_instance = RSG::mesh_storage->mesh_needs_instance(p_instance->base, p_instance->skeleton.is_valid());
 	if (needs_instance != p_instance->mesh_instance.is_valid()) {
 	if (needs_instance != p_instance->mesh_instance.is_valid()) {
 		if (needs_instance) {
 		if (needs_instance) {
-			p_instance->mesh_instance = RSG::storage->mesh_instance_create(p_instance->base);
+			p_instance->mesh_instance = RSG::mesh_storage->mesh_instance_create(p_instance->base);
 
 
 		} else {
 		} else {
 			RSG::storage->free(p_instance->mesh_instance);
 			RSG::storage->free(p_instance->mesh_instance);
@@ -488,7 +488,7 @@ void RendererSceneCull::_instance_update_mesh_instance(Instance *p_instance) {
 	}
 	}
 
 
 	if (p_instance->mesh_instance.is_valid()) {
 	if (p_instance->mesh_instance.is_valid()) {
-		RSG::storage->mesh_instance_set_skeleton(p_instance->mesh_instance, p_instance->skeleton);
+		RSG::mesh_storage->mesh_instance_set_skeleton(p_instance->mesh_instance, p_instance->skeleton);
 	}
 	}
 }
 }
 
 
@@ -890,7 +890,7 @@ void RendererSceneCull::instance_set_blend_shape_weight(RID p_instance, int p_sh
 	}
 	}
 
 
 	if (instance->mesh_instance.is_valid()) {
 	if (instance->mesh_instance.is_valid()) {
-		RSG::storage->mesh_instance_set_blend_shape_weight(instance->mesh_instance, p_shape, p_weight);
+		RSG::mesh_storage->mesh_instance_set_blend_shape_weight(instance->mesh_instance, p_shape, p_weight);
 	}
 	}
 }
 }
 
 
@@ -900,7 +900,7 @@ void RendererSceneCull::instance_set_surface_override_material(RID p_instance, i
 
 
 	if (instance->base_type == RS::INSTANCE_MESH) {
 	if (instance->base_type == RS::INSTANCE_MESH) {
 		//may not have been updated yet, may also have not been set yet. When updated will be correcte, worst case
 		//may not have been updated yet, may also have not been set yet. When updated will be correcte, worst case
-		instance->materials.resize(MAX(p_surface + 1, RSG::storage->mesh_get_surface_count(instance->base)));
+		instance->materials.resize(MAX(p_surface + 1, RSG::mesh_storage->mesh_get_surface_count(instance->base)));
 	}
 	}
 
 
 	ERR_FAIL_INDEX(p_surface, instance->materials.size());
 	ERR_FAIL_INDEX(p_surface, instance->materials.size());
@@ -997,7 +997,7 @@ void RendererSceneCull::instance_attach_skeleton(RID p_instance, RID p_skeleton)
 
 
 	if (p_skeleton.is_valid()) {
 	if (p_skeleton.is_valid()) {
 		//update the dependency now, so if cleared, we remove it
 		//update the dependency now, so if cleared, we remove it
-		RSG::storage->skeleton_update_dependency(p_skeleton, &instance->dependency_tracker);
+		RSG::mesh_storage->skeleton_update_dependency(p_skeleton, &instance->dependency_tracker);
 	}
 	}
 
 
 	_instance_queue_update(instance, true, true);
 	_instance_queue_update(instance, true, true);
@@ -1847,7 +1847,7 @@ void RendererSceneCull::_update_instance_aabb(Instance *p_instance) {
 			if (p_instance->custom_aabb) {
 			if (p_instance->custom_aabb) {
 				new_aabb = *p_instance->custom_aabb;
 				new_aabb = *p_instance->custom_aabb;
 			} else {
 			} else {
-				new_aabb = RSG::storage->mesh_get_aabb(p_instance->base, p_instance->skeleton);
+				new_aabb = RSG::mesh_storage->mesh_get_aabb(p_instance->base, p_instance->skeleton);
 			}
 			}
 
 
 		} break;
 		} break;
@@ -1856,7 +1856,7 @@ void RendererSceneCull::_update_instance_aabb(Instance *p_instance) {
 			if (p_instance->custom_aabb) {
 			if (p_instance->custom_aabb) {
 				new_aabb = *p_instance->custom_aabb;
 				new_aabb = *p_instance->custom_aabb;
 			} else {
 			} else {
-				new_aabb = RSG::storage->multimesh_get_aabb(p_instance->base);
+				new_aabb = RSG::mesh_storage->multimesh_get_aabb(p_instance->base);
 			}
 			}
 
 
 		} break;
 		} break;
@@ -2271,14 +2271,14 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
 							}
 							}
 
 
 							if (instance->mesh_instance.is_valid()) {
 							if (instance->mesh_instance.is_valid()) {
-								RSG::storage->mesh_instance_check_for_update(instance->mesh_instance);
+								RSG::mesh_storage->mesh_instance_check_for_update(instance->mesh_instance);
 							}
 							}
 						}
 						}
 
 
 						shadow_data.instances.push_back(static_cast<InstanceGeometryData *>(instance->base_data)->geometry_instance);
 						shadow_data.instances.push_back(static_cast<InstanceGeometryData *>(instance->base_data)->geometry_instance);
 					}
 					}
 
 
-					RSG::storage->update_mesh_instances();
+					RSG::mesh_storage->update_mesh_instances();
 
 
 					scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, i, 0);
 					scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, i, 0);
 					shadow_data.light = light->instance;
 					shadow_data.light = light->instance;
@@ -2348,14 +2348,14 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
 								animated_material_found = true;
 								animated_material_found = true;
 							}
 							}
 							if (instance->mesh_instance.is_valid()) {
 							if (instance->mesh_instance.is_valid()) {
-								RSG::storage->mesh_instance_check_for_update(instance->mesh_instance);
+								RSG::mesh_storage->mesh_instance_check_for_update(instance->mesh_instance);
 							}
 							}
 						}
 						}
 
 
 						shadow_data.instances.push_back(static_cast<InstanceGeometryData *>(instance->base_data)->geometry_instance);
 						shadow_data.instances.push_back(static_cast<InstanceGeometryData *>(instance->base_data)->geometry_instance);
 					}
 					}
 
 
-					RSG::storage->update_mesh_instances();
+					RSG::mesh_storage->update_mesh_instances();
 					scene_render->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i, 0);
 					scene_render->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i, 0);
 
 
 					shadow_data.light = light->instance;
 					shadow_data.light = light->instance;
@@ -2412,13 +2412,13 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
 					}
 					}
 
 
 					if (instance->mesh_instance.is_valid()) {
 					if (instance->mesh_instance.is_valid()) {
-						RSG::storage->mesh_instance_check_for_update(instance->mesh_instance);
+						RSG::mesh_storage->mesh_instance_check_for_update(instance->mesh_instance);
 					}
 					}
 				}
 				}
 				shadow_data.instances.push_back(static_cast<InstanceGeometryData *>(instance->base_data)->geometry_instance);
 				shadow_data.instances.push_back(static_cast<InstanceGeometryData *>(instance->base_data)->geometry_instance);
 			}
 			}
 
 
-			RSG::storage->update_mesh_instances();
+			RSG::mesh_storage->update_mesh_instances();
 
 
 			scene_render->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0, 0);
 			scene_render->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0, 0);
 			shadow_data.light = light->instance;
 			shadow_data.light = light->instance;
@@ -3037,9 +3037,9 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
 
 
 		if (scene_cull_result.mesh_instances.size()) {
 		if (scene_cull_result.mesh_instances.size()) {
 			for (uint64_t i = 0; i < scene_cull_result.mesh_instances.size(); i++) {
 			for (uint64_t i = 0; i < scene_cull_result.mesh_instances.size(); i++) {
-				RSG::storage->mesh_instance_check_for_update(scene_cull_result.mesh_instances[i]);
+				RSG::mesh_storage->mesh_instance_check_for_update(scene_cull_result.mesh_instances[i]);
 			}
 			}
-			RSG::storage->update_mesh_instances();
+			RSG::mesh_storage->update_mesh_instances();
 		}
 		}
 	}
 	}
 
 
@@ -3677,7 +3677,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
 		if (p_instance->base_type == RS::INSTANCE_MESH) {
 		if (p_instance->base_type == RS::INSTANCE_MESH) {
 			//remove materials no longer used and un-own them
 			//remove materials no longer used and un-own them
 
 
-			int new_mat_count = RSG::storage->mesh_get_surface_count(p_instance->base);
+			int new_mat_count = RSG::mesh_storage->mesh_get_surface_count(p_instance->base);
 			p_instance->materials.resize(new_mat_count);
 			p_instance->materials.resize(new_mat_count);
 
 
 			_instance_update_mesh_instance(p_instance);
 			_instance_update_mesh_instance(p_instance);
@@ -3717,7 +3717,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
 						bool cast_shadows = false;
 						bool cast_shadows = false;
 
 
 						for (int i = 0; i < p_instance->materials.size(); i++) {
 						for (int i = 0; i < p_instance->materials.size(); i++) {
-							RID mat = p_instance->materials[i].is_valid() ? p_instance->materials[i] : RSG::storage->mesh_surface_get_material(mesh, i);
+							RID mat = p_instance->materials[i].is_valid() ? p_instance->materials[i] : RSG::mesh_storage->mesh_surface_get_material(mesh, i);
 
 
 							if (!mat.is_valid()) {
 							if (!mat.is_valid()) {
 								cast_shadows = true;
 								cast_shadows = true;
@@ -3742,13 +3742,13 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
 					}
 					}
 
 
 				} else if (p_instance->base_type == RS::INSTANCE_MULTIMESH) {
 				} else if (p_instance->base_type == RS::INSTANCE_MULTIMESH) {
-					RID mesh = RSG::storage->multimesh_get_mesh(p_instance->base);
+					RID mesh = RSG::mesh_storage->multimesh_get_mesh(p_instance->base);
 					if (mesh.is_valid()) {
 					if (mesh.is_valid()) {
 						bool cast_shadows = false;
 						bool cast_shadows = false;
 
 
-						int sc = RSG::storage->mesh_get_surface_count(mesh);
+						int sc = RSG::mesh_storage->mesh_get_surface_count(mesh);
 						for (int i = 0; i < sc; i++) {
 						for (int i = 0; i < sc; i++) {
-							RID mat = RSG::storage->mesh_surface_get_material(mesh, i);
+							RID mat = RSG::mesh_storage->mesh_surface_get_material(mesh, i);
 
 
 							if (!mat.is_valid()) {
 							if (!mat.is_valid()) {
 								cast_shadows = true;
 								cast_shadows = true;
@@ -3784,9 +3784,9 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
 							continue;
 							continue;
 						}
 						}
 
 
-						int sc = RSG::storage->mesh_get_surface_count(mesh);
+						int sc = RSG::mesh_storage->mesh_get_surface_count(mesh);
 						for (int j = 0; j < sc; j++) {
 						for (int j = 0; j < sc; j++) {
-							RID mat = RSG::storage->mesh_surface_get_material(mesh, j);
+							RID mat = RSG::mesh_storage->mesh_surface_get_material(mesh, j);
 
 
 							if (!mat.is_valid()) {
 							if (!mat.is_valid()) {
 								cast_shadows = true;
 								cast_shadows = true;
@@ -3851,7 +3851,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
 		}
 		}
 
 
 		if (p_instance->skeleton.is_valid()) {
 		if (p_instance->skeleton.is_valid()) {
-			RSG::storage->skeleton_update_dependency(p_instance->skeleton, &p_instance->dependency_tracker);
+			RSG::mesh_storage->skeleton_update_dependency(p_instance->skeleton, &p_instance->dependency_tracker);
 		}
 		}
 
 
 		p_instance->dependency_tracker.update_end();
 		p_instance->dependency_tracker.update_end();

+ 0 - 89
servers/rendering/renderer_storage.h

@@ -119,94 +119,6 @@ public:
 		Set<Dependency *> dependencies;
 		Set<Dependency *> dependencies;
 	};
 	};
 
 
-	/* MESH API */
-
-	virtual RID mesh_allocate() = 0;
-	virtual void mesh_initialize(RID p_rid) = 0;
-
-	virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) = 0;
-
-	/// Returns stride
-	virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) = 0;
-
-	virtual int mesh_get_blend_shape_count(RID p_mesh) const = 0;
-
-	virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) = 0;
-	virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const = 0;
-
-	virtual void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0;
-	virtual void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0;
-	virtual void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0;
-
-	virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) = 0;
-	virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const = 0;
-
-	virtual RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const = 0;
-
-	virtual int mesh_get_surface_count(RID p_mesh) const = 0;
-
-	virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) = 0;
-	virtual AABB mesh_get_custom_aabb(RID p_mesh) const = 0;
-
-	virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) = 0;
-
-	virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) = 0;
-
-	virtual void mesh_clear(RID p_mesh) = 0;
-
-	virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) = 0;
-
-	/* MESH INSTANCE */
-
-	virtual RID mesh_instance_create(RID p_base) = 0;
-	virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) = 0;
-	virtual void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) = 0;
-	virtual void mesh_instance_check_for_update(RID p_mesh_instance) = 0;
-	virtual void update_mesh_instances() = 0;
-
-	/* MULTIMESH API */
-
-	virtual RID multimesh_allocate() = 0;
-	virtual void multimesh_initialize(RID p_rid) = 0;
-
-	virtual void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) = 0;
-
-	virtual int multimesh_get_instance_count(RID p_multimesh) const = 0;
-
-	virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0;
-	virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) = 0;
-	virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) = 0;
-	virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) = 0;
-	virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) = 0;
-
-	virtual RID multimesh_get_mesh(RID p_multimesh) const = 0;
-
-	virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0;
-	virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const = 0;
-	virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const = 0;
-	virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0;
-
-	virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) = 0;
-	virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const = 0;
-
-	virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) = 0;
-	virtual int multimesh_get_visible_instances(RID p_multimesh) const = 0;
-
-	virtual AABB multimesh_get_aabb(RID p_multimesh) const = 0;
-
-	/* SKELETON API */
-
-	virtual RID skeleton_allocate() = 0;
-	virtual void skeleton_initialize(RID p_rid) = 0;
-
-	virtual void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) = 0;
-	virtual int skeleton_get_bone_count(RID p_skeleton) const = 0;
-	virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) = 0;
-	virtual Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const = 0;
-	virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0;
-	virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0;
-	virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0;
-
 	/* Light API */
 	/* Light API */
 
 
 	virtual RID directional_light_allocate() = 0;
 	virtual RID directional_light_allocate() = 0;
@@ -282,7 +194,6 @@ public:
 	virtual float reflection_probe_get_mesh_lod_threshold(RID p_probe) const = 0;
 	virtual float reflection_probe_get_mesh_lod_threshold(RID p_probe) const = 0;
 
 
 	virtual void base_update_dependency(RID p_base, DependencyTracker *p_instance) = 0;
 	virtual void base_update_dependency(RID p_base, DependencyTracker *p_instance) = 0;
-	virtual void skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) = 0;
 
 
 	/* VOXEL GI API */
 	/* VOXEL GI API */
 
 

+ 1 - 0
servers/rendering/rendering_server_default.cpp

@@ -401,6 +401,7 @@ RenderingServerDefault::RenderingServerDefault(bool p_create_thread) :
 	RSG::canvas_texture_storage = RSG::rasterizer->get_canvas_texture_storage();
 	RSG::canvas_texture_storage = RSG::rasterizer->get_canvas_texture_storage();
 	RSG::decal_atlas_storage = RSG::rasterizer->get_decal_atlas_storage();
 	RSG::decal_atlas_storage = RSG::rasterizer->get_decal_atlas_storage();
 	RSG::material_storage = RSG::rasterizer->get_material_storage();
 	RSG::material_storage = RSG::rasterizer->get_material_storage();
+	RSG::mesh_storage = RSG::rasterizer->get_mesh_storage();
 	RSG::texture_storage = RSG::rasterizer->get_texture_storage();
 	RSG::texture_storage = RSG::rasterizer->get_texture_storage();
 	RSG::storage = RSG::rasterizer->get_storage();
 	RSG::storage = RSG::rasterizer->get_storage();
 	RSG::canvas_render = RSG::rasterizer->get_canvas();
 	RSG::canvas_render = RSG::rasterizer->get_canvas();

+ 14 - 9
servers/rendering/rendering_server_default.h

@@ -252,11 +252,11 @@ public:
 #undef ServerName
 #undef ServerName
 #undef server_name
 #undef server_name
 
 
-#define ServerName RendererStorage
-#define server_name RSG::storage
+#define ServerName RendererMeshStorage
+#define server_name RSG::mesh_storage
 
 
 	virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces, int p_blend_shape_count = 0) override {
 	virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces, int p_blend_shape_count = 0) override {
-		RID mesh = RSG::storage->mesh_allocate();
+		RID mesh = RSG::mesh_storage->mesh_allocate();
 
 
 		// TODO once we have RSG::mesh_storage, add can_create_resources_async and call here instead of texture_storage!!
 		// TODO once we have RSG::mesh_storage, add can_create_resources_async and call here instead of texture_storage!!
 
 
@@ -264,16 +264,16 @@ public:
 			if (Thread::get_caller_id() == server_thread) {
 			if (Thread::get_caller_id() == server_thread) {
 				command_queue.flush_if_pending();
 				command_queue.flush_if_pending();
 			}
 			}
-			RSG::storage->mesh_initialize(mesh);
-			RSG::storage->mesh_set_blend_shape_count(mesh, p_blend_shape_count);
+			RSG::mesh_storage->mesh_initialize(mesh);
+			RSG::mesh_storage->mesh_set_blend_shape_count(mesh, p_blend_shape_count);
 			for (int i = 0; i < p_surfaces.size(); i++) {
 			for (int i = 0; i < p_surfaces.size(); i++) {
-				RSG::storage->mesh_add_surface(mesh, p_surfaces[i]);
+				RSG::mesh_storage->mesh_add_surface(mesh, p_surfaces[i]);
 			}
 			}
 		} else {
 		} else {
-			command_queue.push(RSG::storage, &RendererStorage::mesh_initialize, mesh);
-			command_queue.push(RSG::storage, &RendererStorage::mesh_set_blend_shape_count, mesh, p_blend_shape_count);
+			command_queue.push(RSG::mesh_storage, &RendererMeshStorage::mesh_initialize, mesh);
+			command_queue.push(RSG::mesh_storage, &RendererMeshStorage::mesh_set_blend_shape_count, mesh, p_blend_shape_count);
 			for (int i = 0; i < p_surfaces.size(); i++) {
 			for (int i = 0; i < p_surfaces.size(); i++) {
-				command_queue.push(RSG::storage, &RendererStorage::mesh_add_surface, mesh, p_surfaces[i]);
+				command_queue.push(RSG::mesh_storage, &RendererMeshStorage::mesh_add_surface, mesh, p_surfaces[i]);
 			}
 			}
 		}
 		}
 
 
@@ -348,6 +348,11 @@ public:
 	FUNC2(skeleton_set_base_transform_2d, RID, const Transform2D &)
 	FUNC2(skeleton_set_base_transform_2d, RID, const Transform2D &)
 
 
 	/* Light API */
 	/* Light API */
+#undef ServerName
+#undef server_name
+
+#define ServerName RendererStorage
+#define server_name RSG::storage
 
 
 	FUNCRIDSPLIT(directional_light)
 	FUNCRIDSPLIT(directional_light)
 	FUNCRIDSPLIT(omni_light)
 	FUNCRIDSPLIT(omni_light)

+ 1 - 0
servers/rendering/rendering_server_globals.cpp

@@ -35,6 +35,7 @@ bool RenderingServerGlobals::threaded = false;
 RendererCanvasTextureStorage *RenderingServerGlobals::canvas_texture_storage = nullptr;
 RendererCanvasTextureStorage *RenderingServerGlobals::canvas_texture_storage = nullptr;
 RendererDecalAtlasStorage *RenderingServerGlobals::decal_atlas_storage = nullptr;
 RendererDecalAtlasStorage *RenderingServerGlobals::decal_atlas_storage = nullptr;
 RendererMaterialStorage *RenderingServerGlobals::material_storage = nullptr;
 RendererMaterialStorage *RenderingServerGlobals::material_storage = nullptr;
+RendererMeshStorage *RenderingServerGlobals::mesh_storage = nullptr;
 RendererTextureStorage *RenderingServerGlobals::texture_storage = nullptr;
 RendererTextureStorage *RenderingServerGlobals::texture_storage = nullptr;
 RendererStorage *RenderingServerGlobals::storage = nullptr;
 RendererStorage *RenderingServerGlobals::storage = nullptr;
 RendererCanvasRender *RenderingServerGlobals::canvas_render = nullptr;
 RendererCanvasRender *RenderingServerGlobals::canvas_render = nullptr;

+ 2 - 0
servers/rendering/rendering_server_globals.h

@@ -37,6 +37,7 @@
 #include "servers/rendering/storage/canvas_texture_storage.h"
 #include "servers/rendering/storage/canvas_texture_storage.h"
 #include "servers/rendering/storage/decal_atlas_storage.h"
 #include "servers/rendering/storage/decal_atlas_storage.h"
 #include "servers/rendering/storage/material_storage.h"
 #include "servers/rendering/storage/material_storage.h"
+#include "servers/rendering/storage/mesh_storage.h"
 #include "servers/rendering/storage/texture_storage.h"
 #include "servers/rendering/storage/texture_storage.h"
 
 
 class RendererCanvasCull;
 class RendererCanvasCull;
@@ -49,6 +50,7 @@ public:
 
 
 	static RendererCanvasTextureStorage *canvas_texture_storage;
 	static RendererCanvasTextureStorage *canvas_texture_storage;
 	static RendererMaterialStorage *material_storage;
 	static RendererMaterialStorage *material_storage;
+	static RendererMeshStorage *mesh_storage;
 	static RendererTextureStorage *texture_storage;
 	static RendererTextureStorage *texture_storage;
 	static RendererDecalAtlasStorage *decal_atlas_storage;
 	static RendererDecalAtlasStorage *decal_atlas_storage;
 	static RendererStorage *storage;
 	static RendererStorage *storage;

+ 136 - 0
servers/rendering/storage/mesh_storage.h

@@ -0,0 +1,136 @@
+/*************************************************************************/
+/*  mesh_storage.h                                                       */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef MESH_STORAGE_H
+#define MESH_STORAGE_H
+
+#include "servers/rendering/renderer_storage.h"
+#include "servers/rendering_server.h"
+
+class RendererMeshStorage {
+public:
+	virtual ~RendererMeshStorage() {}
+
+	/* MESH API */
+
+	virtual RID mesh_allocate() = 0;
+	virtual void mesh_initialize(RID p_rid) = 0;
+	virtual void mesh_free(RID p_rid) = 0;
+
+	virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) = 0;
+
+	/// Returns stride
+	virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) = 0;
+
+	virtual int mesh_get_blend_shape_count(RID p_mesh) const = 0;
+
+	virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) = 0;
+	virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const = 0;
+
+	virtual void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0;
+	virtual void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0;
+	virtual void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0;
+
+	virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) = 0;
+	virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const = 0;
+
+	virtual RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const = 0;
+
+	virtual int mesh_get_surface_count(RID p_mesh) const = 0;
+
+	virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) = 0;
+	virtual AABB mesh_get_custom_aabb(RID p_mesh) const = 0;
+
+	virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) = 0;
+
+	virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) = 0;
+
+	virtual void mesh_clear(RID p_mesh) = 0;
+
+	virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) = 0;
+
+	/* MESH INSTANCE */
+
+	virtual RID mesh_instance_create(RID p_base) = 0;
+	virtual void mesh_instance_free(RID p_rid) = 0;
+	virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) = 0;
+	virtual void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) = 0;
+	virtual void mesh_instance_check_for_update(RID p_mesh_instance) = 0;
+	virtual void update_mesh_instances() = 0;
+
+	/* MULTIMESH API */
+
+	virtual RID multimesh_allocate() = 0;
+	virtual void multimesh_initialize(RID p_rid) = 0;
+	virtual void multimesh_free(RID p_rid) = 0;
+
+	virtual void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) = 0;
+
+	virtual int multimesh_get_instance_count(RID p_multimesh) const = 0;
+
+	virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0;
+	virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) = 0;
+	virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) = 0;
+	virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) = 0;
+	virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) = 0;
+
+	virtual RID multimesh_get_mesh(RID p_multimesh) const = 0;
+
+	virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0;
+	virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const = 0;
+	virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const = 0;
+	virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0;
+
+	virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) = 0;
+	virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const = 0;
+
+	virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) = 0;
+	virtual int multimesh_get_visible_instances(RID p_multimesh) const = 0;
+
+	virtual AABB multimesh_get_aabb(RID p_multimesh) const = 0;
+
+	/* SKELETON API */
+
+	virtual RID skeleton_allocate() = 0;
+	virtual void skeleton_initialize(RID p_rid) = 0;
+	virtual void skeleton_free(RID p_rid) = 0;
+
+	virtual void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) = 0;
+	virtual int skeleton_get_bone_count(RID p_skeleton) const = 0;
+	virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) = 0;
+	virtual Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const = 0;
+	virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0;
+	virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0;
+	virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0;
+
+	virtual void skeleton_update_dependency(RID p_base, RendererStorage::DependencyTracker *p_instance) = 0;
+};
+
+#endif // !MESH_STORAGE_H

Some files were not shown because too many files changed in this diff