Pārlūkot izejas kodu

Add RENDERING_INFO parameters to GL Compatibility renderer

This also fixes RENDERING_INFO_TOTAL_PRIMITIVES_IN_FRAME for the RD renderers as it was incorrectly reporting vertex/index count at times

This also adds memory tracking to textures and buffers to catch memory leaks.

This also cleans up some memory leaks that the new system caught.
clayjohn 2 gadi atpakaļ
vecāks
revīzija
36a005fafc

+ 4 - 4
doc/classes/RenderingServer.xml

@@ -4575,7 +4575,7 @@
 			Number of objects drawn in a single frame.
 		</constant>
 		<constant name="VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME" value="1" enum="ViewportRenderInfo">
-			Number of vertices drawn in a single frame.
+			Number of points, lines, or triangles drawn in a single frame.
 		</constant>
 		<constant name="VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME" value="2" enum="ViewportRenderInfo">
 			Number of draw calls during this frame.
@@ -5201,7 +5201,7 @@
 			Number of objects rendered in the current 3D scene. This varies depending on camera position and rotation.
 		</constant>
 		<constant name="RENDERING_INFO_TOTAL_PRIMITIVES_IN_FRAME" value="1" enum="RenderingInfo">
-			Number of vertices/indices rendered in the current 3D scene. This varies depending on camera position and rotation.
+			Number of points, lines, or triangles rendered in the current 3D scene. This varies depending on camera position and rotation.
 		</constant>
 		<constant name="RENDERING_INFO_TOTAL_DRAW_CALLS_IN_FRAME" value="2" enum="RenderingInfo">
 			Number of draw calls performed to render in the current 3D scene. This varies depending on camera position and rotation.
@@ -5210,10 +5210,10 @@
 			Texture memory used (in bytes).
 		</constant>
 		<constant name="RENDERING_INFO_BUFFER_MEM_USED" value="4" enum="RenderingInfo">
-			Buffer memory used (in bytes).
+			Buffer memory used (in bytes). This includes vertex data, uniform buffers, and many miscellaneous buffer types used internally.
 		</constant>
 		<constant name="RENDERING_INFO_VIDEO_MEM_USED" value="5" enum="RenderingInfo">
-			Video memory used (in bytes). This is always greater than the sum of [constant RENDERING_INFO_TEXTURE_MEM_USED] and [constant RENDERING_INFO_BUFFER_MEM_USED], since there is miscellaneous data not accounted for by those two metrics.
+			Video memory used (in bytes). When using the Forward+ or mobile rendering backends, this is always greater than the sum of [constant RENDERING_INFO_TEXTURE_MEM_USED] and [constant RENDERING_INFO_BUFFER_MEM_USED], since there is miscellaneous data not accounted for by those two metrics. When using the GL Compatibility backend, this is equal to the sum of [constant RENDERING_INFO_TEXTURE_MEM_USED] and [constant RENDERING_INFO_BUFFER_MEM_USED].
 		</constant>
 		<constant name="FEATURE_SHADERS" value="0" enum="Features">
 			Hardware supports shaders. This enum is currently unused in Godot 3.x.

+ 39 - 20
drivers/gles3/rasterizer_canvas_gles3.cpp

@@ -1790,6 +1790,7 @@ void RasterizerCanvasGLES3::_update_shadow_atlas() {
 			state.shadow_depth_buffer = 0;
 			WARN_PRINT("Could not create CanvasItem shadow atlas, status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));
 		}
+		GLES3::Utilities::get_singleton()->texture_allocated_data(state.shadow_texture, state.shadow_texture_size * data.max_lights_per_render * 2 * 4, "2D shadow atlas texture");
 		glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
 	}
 }
@@ -1894,8 +1895,8 @@ void RasterizerCanvasGLES3::occluder_polygon_set_shape(RID p_occluder, const Vec
 
 	if (oc->line_point_count != lines.size() && oc->vertex_array != 0) {
 		glDeleteVertexArrays(1, &oc->vertex_array);
-		glDeleteBuffers(1, &oc->vertex_buffer);
-		glDeleteBuffers(1, &oc->index_buffer);
+		GLES3::Utilities::get_singleton()->buffer_free_data(oc->vertex_buffer);
+		GLES3::Utilities::get_singleton()->buffer_free_data(oc->index_buffer);
 
 		oc->vertex_array = 0;
 		oc->vertex_buffer = 0;
@@ -1954,13 +1955,15 @@ void RasterizerCanvasGLES3::occluder_polygon_set_shape(RID p_occluder, const Vec
 			glGenBuffers(1, &oc->vertex_buffer);
 			glBindBuffer(GL_ARRAY_BUFFER, oc->vertex_buffer);
 
-			glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(float), geometry.ptr(), GL_STATIC_DRAW);
+			GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, oc->vertex_buffer, lc * 6 * sizeof(float), geometry.ptr(), GL_STATIC_DRAW, "Occluder polygon vertex buffer");
+
 			glEnableVertexAttribArray(RS::ARRAY_VERTEX);
 			glVertexAttribPointer(RS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
 
 			glGenBuffers(1, &oc->index_buffer);
 			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oc->index_buffer);
-			glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * lc * sizeof(uint16_t), indices.ptr(), GL_STATIC_DRAW);
+			GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, oc->index_buffer, 3 * lc * sizeof(uint16_t), indices.ptr(), GL_STATIC_DRAW, "Occluder polygon index buffer");
+
 			glBindVertexArray(0);
 		} else {
 			glBindBuffer(GL_ARRAY_BUFFER, oc->vertex_buffer);
@@ -1995,8 +1998,8 @@ void RasterizerCanvasGLES3::occluder_polygon_set_shape(RID p_occluder, const Vec
 
 	if (oc->sdf_index_count != sdf_indices.size() && oc->sdf_point_count != p_points.size() && oc->sdf_vertex_array != 0) {
 		glDeleteVertexArrays(1, &oc->sdf_vertex_array);
-		glDeleteBuffers(1, &oc->sdf_vertex_buffer);
-		glDeleteBuffers(1, &oc->sdf_index_buffer);
+		GLES3::Utilities::get_singleton()->buffer_free_data(oc->sdf_vertex_buffer);
+		GLES3::Utilities::get_singleton()->buffer_free_data(oc->sdf_index_buffer);
 
 		oc->sdf_vertex_array = 0;
 		oc->sdf_vertex_buffer = 0;
@@ -2015,13 +2018,15 @@ void RasterizerCanvasGLES3::occluder_polygon_set_shape(RID p_occluder, const Vec
 			glGenBuffers(1, &oc->sdf_vertex_buffer);
 			glBindBuffer(GL_ARRAY_BUFFER, oc->sdf_vertex_buffer);
 
-			glBufferData(GL_ARRAY_BUFFER, p_points.size() * 2 * sizeof(float), p_points.to_byte_array().ptr(), GL_STATIC_DRAW);
+			GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, oc->sdf_vertex_buffer, oc->sdf_point_count * 2 * sizeof(float), p_points.to_byte_array().ptr(), GL_STATIC_DRAW, "Occluder polygon SDF vertex buffer");
+
 			glEnableVertexAttribArray(RS::ARRAY_VERTEX);
 			glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr);
 
 			glGenBuffers(1, &oc->sdf_index_buffer);
 			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oc->sdf_index_buffer);
-			glBufferData(GL_ELEMENT_ARRAY_BUFFER, sdf_indices.size() * sizeof(uint32_t), sdf_indices.to_byte_array().ptr(), GL_STATIC_DRAW);
+			GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, oc->sdf_index_buffer, oc->sdf_index_count * sizeof(uint32_t), sdf_indices.to_byte_array().ptr(), GL_STATIC_DRAW, "Occluder polygon SDF index buffer");
+
 			glBindVertexArray(0);
 		} else {
 			glBindBuffer(GL_ARRAY_BUFFER, oc->sdf_vertex_buffer);
@@ -2410,7 +2415,7 @@ RendererCanvasRender::PolygonID RasterizerCanvasGLES3::request_polygon(const Vec
 		}
 
 		ERR_FAIL_COND_V(base_offset != stride, 0);
-		glBufferData(GL_ARRAY_BUFFER, vertex_count * stride * sizeof(float), polygon_buffer.ptr(), GL_STATIC_DRAW);
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, pb.vertex_buffer, vertex_count * stride * sizeof(float), polygon_buffer.ptr(), GL_STATIC_DRAW, "Polygon 2D vertex buffer");
 	}
 
 	if (p_indices.size()) {
@@ -2423,7 +2428,7 @@ RendererCanvasRender::PolygonID RasterizerCanvasGLES3::request_polygon(const Vec
 		}
 		glGenBuffers(1, &pb.index_buffer);
 		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pb.index_buffer);
-		glBufferData(GL_ELEMENT_ARRAY_BUFFER, p_indices.size() * 4, index_buffer.ptr(), GL_STATIC_DRAW);
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, pb.index_buffer, p_indices.size() * 4, index_buffer.ptr(), GL_STATIC_DRAW, "Polygon 2D index buffer");
 		pb.count = p_indices.size();
 	}
 
@@ -2444,11 +2449,11 @@ void RasterizerCanvasGLES3::free_polygon(PolygonID p_polygon) {
 	PolygonBuffers &pb = *pb_ptr;
 
 	if (pb.index_buffer != 0) {
-		glDeleteBuffers(1, &pb.index_buffer);
+		GLES3::Utilities::get_singleton()->buffer_free_data(pb.index_buffer);
 	}
 
 	glDeleteVertexArrays(1, &pb.vertex_array);
-	glDeleteBuffers(1, &pb.vertex_buffer);
+	GLES3::Utilities::get_singleton()->buffer_free_data(pb.vertex_buffer);
 
 	polygon_buffers.polygons.erase(p_polygon);
 }
@@ -2462,13 +2467,13 @@ void RasterizerCanvasGLES3::_allocate_instance_data_buffer() {
 	glGenBuffers(3, new_buffers);
 	// Batch UBO.
 	glBindBuffer(GL_ARRAY_BUFFER, new_buffers[0]);
-	glBufferData(GL_ARRAY_BUFFER, data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW);
+	GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, new_buffers[0], data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW, "2D Batch UBO[" + itos(state.current_data_buffer_index) + "][0]");
 	// Light uniform buffer.
 	glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[1]);
-	glBufferData(GL_UNIFORM_BUFFER, sizeof(LightUniform) * data.max_lights_per_render, nullptr, GL_STREAM_DRAW);
+	GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, new_buffers[1], sizeof(LightUniform) * data.max_lights_per_render, nullptr, GL_STREAM_DRAW, "2D Lights UBO[" + itos(state.current_data_buffer_index) + "]");
 	// State buffer.
 	glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[2]);
-	glBufferData(GL_UNIFORM_BUFFER, sizeof(StateBuffer), nullptr, GL_STREAM_DRAW);
+	GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, new_buffers[2], sizeof(StateBuffer), nullptr, GL_STREAM_DRAW, "2D State UBO[" + itos(state.current_data_buffer_index) + "]");
 
 	state.current_data_buffer_index = (state.current_data_buffer_index + 1);
 	DataBuffer db;
@@ -2493,7 +2498,7 @@ void RasterizerCanvasGLES3::_allocate_instance_buffer() {
 	glGenBuffers(1, &new_buffer);
 
 	glBindBuffer(GL_ARRAY_BUFFER, new_buffer);
-	glBufferData(GL_ARRAY_BUFFER, data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW);
+	GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, new_buffer, data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW, "Batch UBO[" + itos(state.current_data_buffer_index) + "][" + itos(state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers.size()) + "]");
 
 	state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers.push_back(new_buffer);
 
@@ -2656,13 +2661,13 @@ RasterizerCanvasGLES3::RasterizerCanvasGLES3() {
 		glGenBuffers(3, new_buffers);
 		// Batch UBO.
 		glBindBuffer(GL_ARRAY_BUFFER, new_buffers[0]);
-		glBufferData(GL_ARRAY_BUFFER, data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW);
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, new_buffers[0], data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW, "Batch UBO[0][0]");
 		// Light uniform buffer.
 		glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[1]);
-		glBufferData(GL_UNIFORM_BUFFER, sizeof(LightUniform) * data.max_lights_per_render, nullptr, GL_STREAM_DRAW);
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, new_buffers[1], sizeof(LightUniform) * data.max_lights_per_render, nullptr, GL_STREAM_DRAW, "2D lights UBO[0]");
 		// State buffer.
 		glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[2]);
-		glBufferData(GL_UNIFORM_BUFFER, sizeof(StateBuffer), nullptr, GL_STREAM_DRAW);
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, new_buffers[2], sizeof(StateBuffer), nullptr, GL_STREAM_DRAW, "2D state UBO[0]");
 		DataBuffer db;
 		db.instance_buffers.push_back(new_buffers[0]);
 		db.light_ubo = new_buffers[1];
@@ -2779,12 +2784,26 @@ RasterizerCanvasGLES3::~RasterizerCanvasGLES3() {
 
 	if (state.shadow_fb != 0) {
 		glDeleteFramebuffers(1, &state.shadow_fb);
-		glDeleteTextures(1, &state.shadow_texture);
+		GLES3::Utilities::get_singleton()->texture_free_data(state.shadow_texture);
 		glDeleteRenderbuffers(1, &state.shadow_depth_buffer);
 		state.shadow_fb = 0;
 		state.shadow_texture = 0;
 		state.shadow_depth_buffer = 0;
 	}
+
+	for (uint32_t i = 0; i < state.canvas_instance_data_buffers.size(); i++) {
+		for (int j = 0; j < state.canvas_instance_data_buffers[i].instance_buffers.size(); j++) {
+			if (state.canvas_instance_data_buffers[i].instance_buffers[j]) {
+				GLES3::Utilities::get_singleton()->buffer_free_data(state.canvas_instance_data_buffers[i].instance_buffers[j]);
+			}
+		}
+		if (state.canvas_instance_data_buffers[i].light_ubo) {
+			GLES3::Utilities::get_singleton()->buffer_free_data(state.canvas_instance_data_buffers[i].light_ubo);
+		}
+		if (state.canvas_instance_data_buffers[i].state_ubo) {
+			GLES3::Utilities::get_singleton()->buffer_free_data(state.canvas_instance_data_buffers[i].state_ubo);
+		}
+	}
 }
 
 #endif // GLES3_ENABLED

+ 90 - 32
drivers/gles3/rasterizer_scene_gles3.cpp

@@ -443,8 +443,10 @@ void RasterizerSceneGLES3::_geometry_instance_update(RenderGeometryInstance *p_g
 
 void RasterizerSceneGLES3::_free_sky_data(Sky *p_sky) {
 	if (p_sky->radiance != 0) {
-		glDeleteTextures(1, &p_sky->radiance);
+		GLES3::Utilities::get_singleton()->texture_free_data(p_sky->radiance);
 		p_sky->radiance = 0;
+		GLES3::Utilities::get_singleton()->texture_free_data(p_sky->raw_radiance);
+		p_sky->raw_radiance = 0;
 		glDeleteFramebuffers(1, &p_sky->radiance_framebuffer);
 		p_sky->radiance_framebuffer = 0;
 	}
@@ -546,6 +548,8 @@ void RasterizerSceneGLES3::_update_dirty_skys() {
 			glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
 			glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, sky->mipmap_count - 1);
 
+			GLES3::Utilities::get_singleton()->texture_allocated_data(sky->radiance, Image::get_image_data_size(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBA8, true), "Sky radiance map");
+
 			glGenTextures(1, &sky->raw_radiance);
 			glBindTexture(GL_TEXTURE_CUBE_MAP, sky->raw_radiance);
 
@@ -568,6 +572,7 @@ void RasterizerSceneGLES3::_update_dirty_skys() {
 			glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, sky->mipmap_count - 1);
 
 			glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+			GLES3::Utilities::get_singleton()->texture_allocated_data(sky->raw_radiance, Image::get_image_data_size(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBA8, true), "Sky raw radiance map");
 		}
 
 		sky->reflection_dirty = true;
@@ -1154,6 +1159,11 @@ void RasterizerSceneGLES3::voxel_gi_update(RID p_probe, bool p_update_light_inst
 void RasterizerSceneGLES3::voxel_gi_set_quality(RS::VoxelGIQuality) {
 }
 
+_FORCE_INLINE_ static uint32_t _indices_to_primitives(RS::PrimitiveType p_primitive, uint32_t p_indices) {
+	static const uint32_t divisor[RS::PRIMITIVE_MAX] = { 1, 2, 1, 3, 1 };
+	static const uint32_t subtractor[RS::PRIMITIVE_MAX] = { 0, 0, 1, 0, 1 };
+	return (p_indices - subtractor[p_primitive]) / divisor[p_primitive];
+}
 void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const RenderDataGLES3 *p_render_data, PassMode p_pass_mode, bool p_append) {
 	GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
 
@@ -1258,7 +1268,8 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
 
 				uint32_t indices = 0;
 				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);
-				/*
+				surf->index_count = indices;
+
 				if (p_render_data->render_info) {
 					indices = _indices_to_primitives(surf->primitive, indices);
 					if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
@@ -1267,21 +1278,20 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
 						p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += indices;
 					}
 				}
-				*/
+
 			} else {
 				surf->lod_index = 0;
-				/*
+
 				if (p_render_data->render_info) {
 					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 *= inst->instance_count;
+					to_draw *= inst->instance_count > 0 ? inst->instance_count : 1;
 					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] += mesh_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] += to_draw;
 					} 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] += mesh_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] += to_draw;
 					}
 				}
-				*/
 			}
 
 			// ADD Element
@@ -1451,17 +1461,26 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
 
 	if (scene_state.ubo_buffer == 0) {
 		glGenBuffers(1, &scene_state.ubo_buffer);
+		glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer);
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, scene_state.ubo_buffer, sizeof(SceneState::UBO), &scene_state.ubo, GL_STREAM_DRAW, "Scene state UBO");
+		glBindBuffer(GL_UNIFORM_BUFFER, 0);
+	} else {
+		glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer);
+		glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::UBO), &scene_state.ubo, GL_STREAM_DRAW);
 	}
-	glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer);
-	glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::UBO), &scene_state.ubo, GL_STREAM_DRAW);
+
 	glBindBuffer(GL_UNIFORM_BUFFER, 0);
 
 	if (p_render_data->view_count > 1) {
 		if (scene_state.multiview_buffer == 0) {
 			glGenBuffers(1, &scene_state.multiview_buffer);
+			glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer);
+			GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, scene_state.multiview_buffer, sizeof(SceneState::MultiviewUBO), &scene_state.multiview_ubo, GL_STREAM_DRAW, "Multiview UBO");
+		} else {
+			glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer);
+			glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::MultiviewUBO), &scene_state.multiview_ubo, GL_STREAM_DRAW);
 		}
-		glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer);
-		glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::MultiviewUBO), &scene_state.multiview_ubo, GL_STREAM_DRAW);
+
 		glBindBuffer(GL_UNIFORM_BUFFER, 0);
 	}
 }
@@ -1792,9 +1811,14 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
 	if (scene_state.tonemap_buffer == 0) {
 		// Only create if using 3D
 		glGenBuffers(1, &scene_state.tonemap_buffer);
+		glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_TONEMAP_UNIFORM_LOCATION, scene_state.tonemap_buffer);
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, scene_state.tonemap_buffer, sizeof(SceneState::TonemapUBO), &tonemap_ubo, GL_STREAM_DRAW, "Tonemap UBO");
+	} else {
+		glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_TONEMAP_UNIFORM_LOCATION, scene_state.tonemap_buffer);
+		glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::TonemapUBO), &tonemap_ubo, GL_STREAM_DRAW);
 	}
-	glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_TONEMAP_UNIFORM_LOCATION, scene_state.tonemap_buffer);
-	glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::TonemapUBO), &tonemap_ubo, GL_STREAM_DRAW);
+
+	glBindBuffer(GL_UNIFORM_BUFFER, 0);
 
 	scene_state.ubo.emissive_exposure_normalization = -1.0; // Use default exposure normalization.
 
@@ -2086,6 +2110,12 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
 	}
 
 	bool should_request_redraw = false;
+	if constexpr (p_pass_mode != PASS_MODE_DEPTH) {
+		// Don't count elements during depth pre-pass to match the RD renderers.
+		if (p_render_data->render_info) {
+			p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] += p_to_element - p_from_element;
+		}
+	}
 
 	for (uint32_t i = p_from_element; i < p_to_element; i++) {
 		const GeometryInstanceSurface *surf = p_params->elements[i];
@@ -2326,6 +2356,21 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
 		}
 
 		material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, instance_variant, spec_constants);
+
+		// Can be index count or vertex count
+		uint32_t count = 0;
+		if (surf->lod_index > 0) {
+			count = surf->index_count;
+		} else {
+			count = mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface);
+		}
+		if constexpr (p_pass_mode != PASS_MODE_DEPTH) {
+			// Don't count draw calls during depth pre-pass to match the RD renderers.
+			if (p_render_data->render_info) {
+				p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME]++;
+			}
+		}
+
 		if (inst->instance_count > 0) {
 			// Using MultiMesh or Particles.
 			// Bind instance buffers.
@@ -2366,16 +2411,16 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
 				glVertexAttribDivisor(15, 1);
 			}
 			if (use_index_buffer) {
-				glDrawElementsInstanced(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface), mesh_storage->mesh_surface_get_index_type(mesh_surface), 0, inst->instance_count);
+				glDrawElementsInstanced(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), 0, inst->instance_count);
 			} else {
-				glDrawArraysInstanced(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface), inst->instance_count);
+				glDrawArraysInstanced(primitive_gl, 0, count, inst->instance_count);
 			}
 		} else {
 			// Using regular Mesh.
 			if (use_index_buffer) {
-				glDrawElements(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface), mesh_storage->mesh_surface_get_index_type(mesh_surface), 0);
+				glDrawElements(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), 0);
 			} else {
-				glDrawArrays(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface));
+				glDrawArrays(primitive_gl, 0, count);
 			}
 		}
 		if (inst->instance_count > 0) {
@@ -2579,19 +2624,20 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() {
 		scene_state.omni_light_sort = memnew_arr(InstanceSort<GLES3::LightInstance>, config->max_renderable_lights);
 		glGenBuffers(1, &scene_state.omni_light_buffer);
 		glBindBuffer(GL_UNIFORM_BUFFER, scene_state.omni_light_buffer);
-		glBufferData(GL_UNIFORM_BUFFER, light_buffer_size, nullptr, GL_STREAM_DRAW);
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, scene_state.omni_light_buffer, light_buffer_size, nullptr, GL_STREAM_DRAW, "OmniLight UBO");
 
 		scene_state.spot_lights = memnew_arr(LightData, config->max_renderable_lights);
 		scene_state.spot_light_sort = memnew_arr(InstanceSort<GLES3::LightInstance>, config->max_renderable_lights);
 		glGenBuffers(1, &scene_state.spot_light_buffer);
 		glBindBuffer(GL_UNIFORM_BUFFER, scene_state.spot_light_buffer);
-		glBufferData(GL_UNIFORM_BUFFER, light_buffer_size, nullptr, GL_STREAM_DRAW);
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, scene_state.spot_light_buffer, light_buffer_size, nullptr, GL_STREAM_DRAW, "SpotLight UBO");
 
 		uint32_t directional_light_buffer_size = MAX_DIRECTIONAL_LIGHTS * sizeof(DirectionalLightData);
 		scene_state.directional_lights = memnew_arr(DirectionalLightData, MAX_DIRECTIONAL_LIGHTS);
 		glGenBuffers(1, &scene_state.directional_light_buffer);
 		glBindBuffer(GL_UNIFORM_BUFFER, scene_state.directional_light_buffer);
-		glBufferData(GL_UNIFORM_BUFFER, directional_light_buffer_size, nullptr, GL_STREAM_DRAW);
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, scene_state.directional_light_buffer, directional_light_buffer_size, nullptr, GL_STREAM_DRAW, "DirectionalLight UBO");
+
 		glBindBuffer(GL_UNIFORM_BUFFER, 0);
 	}
 
@@ -2603,7 +2649,8 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() {
 		sky_globals.last_frame_directional_light_count = sky_globals.max_directional_lights + 1;
 		glGenBuffers(1, &sky_globals.directional_light_buffer);
 		glBindBuffer(GL_UNIFORM_BUFFER, sky_globals.directional_light_buffer);
-		glBufferData(GL_UNIFORM_BUFFER, directional_light_buffer_size, nullptr, GL_STREAM_DRAW);
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, sky_globals.directional_light_buffer, directional_light_buffer_size, nullptr, GL_STREAM_DRAW, "Sky DirectionalLight UBO");
+
 		glBindBuffer(GL_UNIFORM_BUFFER, 0);
 	}
 
@@ -2702,6 +2749,8 @@ void sky() {
 	}
 
 	{
+		glGenVertexArrays(1, &sky_globals.screen_triangle_array);
+		glBindVertexArray(sky_globals.screen_triangle_array);
 		glGenBuffers(1, &sky_globals.screen_triangle);
 		glBindBuffer(GL_ARRAY_BUFFER, sky_globals.screen_triangle);
 
@@ -2714,12 +2763,8 @@ void sky() {
 			3.0f,
 		};
 
-		glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6, qv, GL_STATIC_DRAW);
-		glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, sky_globals.screen_triangle, sizeof(float) * 6, qv, GL_STATIC_DRAW, "Screen triangle vertex buffer");
 
-		glGenVertexArrays(1, &sky_globals.screen_triangle_array);
-		glBindVertexArray(sky_globals.screen_triangle_array);
-		glBindBuffer(GL_ARRAY_BUFFER, sky_globals.screen_triangle);
 		glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, nullptr);
 		glEnableVertexAttribArray(RS::ARRAY_VERTEX);
 		glBindVertexArray(0);
@@ -2735,9 +2780,9 @@ void sky() {
 }
 
 RasterizerSceneGLES3::~RasterizerSceneGLES3() {
-	glDeleteBuffers(1, &scene_state.directional_light_buffer);
-	glDeleteBuffers(1, &scene_state.omni_light_buffer);
-	glDeleteBuffers(1, &scene_state.spot_light_buffer);
+	GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.directional_light_buffer);
+	GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.omni_light_buffer);
+	GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.spot_light_buffer);
 	memdelete_arr(scene_state.directional_lights);
 	memdelete_arr(scene_state.omni_lights);
 	memdelete_arr(scene_state.spot_lights);
@@ -2756,13 +2801,26 @@ RasterizerSceneGLES3::~RasterizerSceneGLES3() {
 	RSG::material_storage->shader_free(sky_globals.default_shader);
 	RSG::material_storage->material_free(sky_globals.fog_material);
 	RSG::material_storage->shader_free(sky_globals.fog_shader);
-	glDeleteBuffers(1, &sky_globals.screen_triangle);
+	GLES3::Utilities::get_singleton()->buffer_free_data(sky_globals.screen_triangle);
 	glDeleteVertexArrays(1, &sky_globals.screen_triangle_array);
 	glDeleteTextures(1, &sky_globals.radical_inverse_vdc_cache_tex);
-	glDeleteBuffers(1, &sky_globals.directional_light_buffer);
+	GLES3::Utilities::get_singleton()->buffer_free_data(sky_globals.directional_light_buffer);
 	memdelete_arr(sky_globals.directional_lights);
 	memdelete_arr(sky_globals.last_frame_directional_lights);
 
+	// UBOs
+	if (scene_state.ubo_buffer != 0) {
+		GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.ubo_buffer);
+	}
+
+	if (scene_state.multiview_buffer != 0) {
+		GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.multiview_buffer);
+	}
+
+	if (scene_state.tonemap_buffer != 0) {
+		GLES3::Utilities::get_singleton()->buffer_free_data(scene_state.tonemap_buffer);
+	}
+
 	singleton = nullptr;
 }
 

+ 1 - 0
drivers/gles3/rasterizer_scene_gles3.h

@@ -220,6 +220,7 @@ private:
 		uint32_t flags = 0;
 		uint32_t surface_index = 0;
 		uint32_t lod_index = 0;
+		uint32_t index_count = 0;
 
 		void *surface = nullptr;
 		GLES3::SceneShaderData *shader = nullptr;

+ 0 - 100
drivers/gles3/storage/light_storage.cpp

@@ -595,106 +595,6 @@ void LightStorage::lightmap_instance_free(RID p_lightmap) {
 void LightStorage::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) {
 }
 
-/* LIGHT SHADOW MAPPING */
-/*
-
-RID LightStorage::canvas_light_occluder_create() {
-	CanvasOccluder *co = memnew(CanvasOccluder);
-	co->index_id = 0;
-	co->vertex_id = 0;
-	co->len = 0;
-
-	return canvas_occluder_owner.make_rid(co);
-}
-
-void LightStorage::canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector<Vector2> &p_lines) {
-	CanvasOccluder *co = canvas_occluder_owner.get(p_occluder);
-	ERR_FAIL_COND(!co);
-
-	co->lines = p_lines;
-
-	if (p_lines.size() != co->len) {
-		if (co->index_id) {
-			glDeleteBuffers(1, &co->index_id);
-		} if (co->vertex_id) {
-			glDeleteBuffers(1, &co->vertex_id);
-		}
-
-		co->index_id = 0;
-		co->vertex_id = 0;
-		co->len = 0;
-	}
-
-	if (p_lines.size()) {
-		PoolVector<float> geometry;
-		PoolVector<uint16_t> indices;
-		int lc = p_lines.size();
-
-		geometry.resize(lc * 6);
-		indices.resize(lc * 3);
-
-		PoolVector<float>::Write vw = geometry.write();
-		PoolVector<uint16_t>::Write iw = indices.write();
-
-		PoolVector<Vector2>::Read lr = p_lines.read();
-
-		const int POLY_HEIGHT = 16384;
-
-		for (int i = 0; i < lc / 2; i++) {
-			vw[i * 12 + 0] = lr[i * 2 + 0].x;
-			vw[i * 12 + 1] = lr[i * 2 + 0].y;
-			vw[i * 12 + 2] = POLY_HEIGHT;
-
-			vw[i * 12 + 3] = lr[i * 2 + 1].x;
-			vw[i * 12 + 4] = lr[i * 2 + 1].y;
-			vw[i * 12 + 5] = POLY_HEIGHT;
-
-			vw[i * 12 + 6] = lr[i * 2 + 1].x;
-			vw[i * 12 + 7] = lr[i * 2 + 1].y;
-			vw[i * 12 + 8] = -POLY_HEIGHT;
-
-			vw[i * 12 + 9] = lr[i * 2 + 0].x;
-			vw[i * 12 + 10] = lr[i * 2 + 0].y;
-			vw[i * 12 + 11] = -POLY_HEIGHT;
-
-			iw[i * 6 + 0] = i * 4 + 0;
-			iw[i * 6 + 1] = i * 4 + 1;
-			iw[i * 6 + 2] = i * 4 + 2;
-
-			iw[i * 6 + 3] = i * 4 + 2;
-			iw[i * 6 + 4] = i * 4 + 3;
-			iw[i * 6 + 5] = i * 4 + 0;
-		}
-
-		//if same buffer len is being set, just use BufferSubData to avoid a pipeline flush
-
-		if (!co->vertex_id) {
-			glGenBuffers(1, &co->vertex_id);
-			glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id);
-			glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(real_t), vw.ptr(), GL_STATIC_DRAW);
-		} else {
-			glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id);
-			glBufferSubData(GL_ARRAY_BUFFER, 0, lc * 6 * sizeof(real_t), vw.ptr());
-		}
-
-		glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
-
-		if (!co->index_id) {
-			glGenBuffers(1, &co->index_id);
-			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id);
-			glBufferData(GL_ELEMENT_ARRAY_BUFFER, lc * 3 * sizeof(uint16_t), iw.ptr(), GL_DYNAMIC_DRAW);
-		} else {
-			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id);
-			glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, lc * 3 * sizeof(uint16_t), iw.ptr());
-		}
-
-		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind
-
-		co->len = lc;
-	}
-}
-*/
-
 /* SHADOW ATLAS API */
 
 RID LightStorage::shadow_atlas_create() {

+ 24 - 22
drivers/gles3/storage/mesh_storage.cpp

@@ -193,26 +193,26 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
 	if (p_surface.vertex_data.size()) {
 		glGenBuffers(1, &s->vertex_buffer);
 		glBindBuffer(GL_ARRAY_BUFFER, s->vertex_buffer);
-		glBufferData(GL_ARRAY_BUFFER, p_surface.vertex_data.size(), p_surface.vertex_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
-		glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->vertex_buffer, p_surface.vertex_data.size(), p_surface.vertex_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh vertex buffer");
 		s->vertex_buffer_size = p_surface.vertex_data.size();
 	}
 
 	if (p_surface.attribute_data.size()) {
 		glGenBuffers(1, &s->attribute_buffer);
 		glBindBuffer(GL_ARRAY_BUFFER, s->attribute_buffer);
-		glBufferData(GL_ARRAY_BUFFER, p_surface.attribute_data.size(), p_surface.attribute_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
-		glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->attribute_buffer, p_surface.attribute_data.size(), p_surface.attribute_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh attribute buffer");
 		s->attribute_buffer_size = p_surface.attribute_data.size();
 	}
+
 	if (p_surface.skin_data.size()) {
 		glGenBuffers(1, &s->skin_buffer);
 		glBindBuffer(GL_ARRAY_BUFFER, s->skin_buffer);
-		glBufferData(GL_ARRAY_BUFFER, p_surface.skin_data.size(), p_surface.skin_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
-		glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->skin_buffer, p_surface.skin_data.size(), p_surface.skin_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh skin buffer");
 		s->skin_buffer_size = p_surface.skin_data.size();
 	}
 
+	glBindBuffer(GL_ARRAY_BUFFER, 0);
+
 	s->vertex_count = p_surface.vertex_count;
 
 	if (p_surface.format & RS::ARRAY_FORMAT_BONES) {
@@ -223,7 +223,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
 		bool is_index_16 = p_surface.vertex_count <= 65536 && p_surface.vertex_count > 0;
 		glGenBuffers(1, &s->index_buffer);
 		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_buffer);
-		glBufferData(GL_ELEMENT_ARRAY_BUFFER, p_surface.index_data.size(), p_surface.index_data.ptr(), GL_STATIC_DRAW);
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, s->index_buffer, p_surface.index_data.size(), p_surface.index_data.ptr(), GL_STATIC_DRAW, "Mesh index buffer");
 		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind
 		s->index_count = p_surface.index_count;
 		s->index_buffer_size = p_surface.index_data.size();
@@ -235,7 +235,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
 			for (int i = 0; i < p_surface.lods.size(); i++) {
 				glGenBuffers(1, &s->lods[i].index_buffer);
 				glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->lods[i].index_buffer);
-				glBufferData(GL_ELEMENT_ARRAY_BUFFER, p_surface.lods[i].index_data.size(), p_surface.lods[i].index_data.ptr(), GL_STATIC_DRAW);
+				GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, s->lods[i].index_buffer, p_surface.lods[i].index_data.size(), p_surface.lods[i].index_data.ptr(), GL_STATIC_DRAW, "Mesh index buffer LOD[" + itos(i) + "]");
 				glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind
 				s->lods[i].edge_length = p_surface.lods[i].edge_length;
 				s->lods[i].index_count = p_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4);
@@ -282,7 +282,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
 				glBindVertexArray(s->blend_shapes[i].vertex_array);
 				glGenBuffers(1, &s->blend_shapes[i].vertex_buffer);
 				glBindBuffer(GL_ARRAY_BUFFER, s->blend_shapes[i].vertex_buffer);
-				glBufferData(GL_ARRAY_BUFFER, size, p_surface.blend_shape_data.ptr() + i * size, (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
+				GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->blend_shapes[i].vertex_buffer, size, p_surface.blend_shape_data.ptr() + i * size, (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh blend shape buffer");
 
 				if ((p_surface.format & (1 << RS::ARRAY_VERTEX))) {
 					glEnableVertexAttribArray(RS::ARRAY_VERTEX + 3);
@@ -637,7 +637,7 @@ void MeshStorage::mesh_clear(RID p_mesh) {
 		Mesh::Surface &s = *mesh->surfaces[i];
 
 		if (s.vertex_buffer != 0) {
-			glDeleteBuffers(1, &s.vertex_buffer);
+			GLES3::Utilities::get_singleton()->buffer_free_data(s.vertex_buffer);
 			s.vertex_buffer = 0;
 		}
 
@@ -649,17 +649,17 @@ void MeshStorage::mesh_clear(RID p_mesh) {
 		}
 
 		if (s.attribute_buffer != 0) {
-			glDeleteBuffers(1, &s.attribute_buffer);
+			GLES3::Utilities::get_singleton()->buffer_free_data(s.attribute_buffer);
 			s.attribute_buffer = 0;
 		}
 
 		if (s.skin_buffer != 0) {
-			glDeleteBuffers(1, &s.skin_buffer);
+			GLES3::Utilities::get_singleton()->buffer_free_data(s.skin_buffer);
 			s.skin_buffer = 0;
 		}
 
 		if (s.index_buffer != 0) {
-			glDeleteBuffers(1, &s.index_buffer);
+			GLES3::Utilities::get_singleton()->buffer_free_data(s.index_buffer);
 			s.index_buffer = 0;
 		}
 
@@ -670,7 +670,7 @@ void MeshStorage::mesh_clear(RID p_mesh) {
 		if (s.lod_count) {
 			for (uint32_t j = 0; j < s.lod_count; j++) {
 				if (s.lods[j].index_buffer != 0) {
-					glDeleteBuffers(1, &s.lods[j].index_buffer);
+					GLES3::Utilities::get_singleton()->buffer_free_data(s.lods[j].index_buffer);
 					s.lods[j].index_buffer = 0;
 				}
 			}
@@ -680,7 +680,7 @@ void MeshStorage::mesh_clear(RID p_mesh) {
 		if (mesh->blend_shape_count) {
 			for (uint32_t j = 0; j < mesh->blend_shape_count; j++) {
 				if (s.blend_shapes[j].vertex_buffer != 0) {
-					glDeleteBuffers(1, &s.blend_shapes[j].vertex_buffer);
+					GLES3::Utilities::get_singleton()->buffer_free_data(s.blend_shapes[j].vertex_buffer);
 					s.blend_shapes[j].vertex_buffer = 0;
 				}
 				if (s.blend_shapes[j].vertex_array != 0) {
@@ -916,13 +916,14 @@ void MeshStorage::_mesh_instance_clear(MeshInstance *mi) {
 		}
 
 		if (mi->surfaces[i].vertex_buffers[0] != 0) {
-			glDeleteBuffers(2, mi->surfaces[i].vertex_buffers);
+			GLES3::Utilities::get_singleton()->buffer_free_data(mi->surfaces[i].vertex_buffers[0]);
+			GLES3::Utilities::get_singleton()->buffer_free_data(mi->surfaces[i].vertex_buffers[1]);
 			mi->surfaces[i].vertex_buffers[0] = 0;
 			mi->surfaces[i].vertex_buffers[1] = 0;
 		}
 
 		if (mi->surfaces[i].vertex_buffer != 0) {
-			glDeleteBuffers(1, &mi->surfaces[i].vertex_buffer);
+			GLES3::Utilities::get_singleton()->buffer_free_data(mi->surfaces[i].vertex_buffer);
 			mi->surfaces[i].vertex_buffer = 0;
 		}
 	}
@@ -963,13 +964,13 @@ void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint3
 		// Buffer to be used for rendering. Final output of skeleton and blend shapes.
 		glGenBuffers(1, &s.vertex_buffer);
 		glBindBuffer(GL_ARRAY_BUFFER, s.vertex_buffer);
-		glBufferData(GL_ARRAY_BUFFER, s.vertex_stride_cache * mesh->surfaces[p_surface]->vertex_count, nullptr, GL_DYNAMIC_DRAW);
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s.vertex_buffer, s.vertex_stride_cache * mesh->surfaces[p_surface]->vertex_count, nullptr, GL_DYNAMIC_DRAW, "MeshInstance vertex buffer");
 		if (mesh->blend_shape_count > 0) {
 			// Ping-Pong buffers for processing blendshapes.
 			glGenBuffers(2, s.vertex_buffers);
 			for (uint32_t i = 0; i < 2; i++) {
 				glBindBuffer(GL_ARRAY_BUFFER, s.vertex_buffers[i]);
-				glBufferData(GL_ARRAY_BUFFER, s.vertex_stride_cache * mesh->surfaces[p_surface]->vertex_count, nullptr, GL_DYNAMIC_DRAW);
+				GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s.vertex_buffers[i], s.vertex_stride_cache * mesh->surfaces[p_surface]->vertex_count, nullptr, GL_DYNAMIC_DRAW, "MeshInstance process buffer[" + itos(i) + "]");
 			}
 		}
 		glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
@@ -1271,7 +1272,7 @@ void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::
 	}
 
 	if (multimesh->buffer) {
-		glDeleteBuffers(1, &multimesh->buffer);
+		GLES3::Utilities::get_singleton()->buffer_free_data(multimesh->buffer);
 		multimesh->buffer = 0;
 	}
 
@@ -1298,7 +1299,7 @@ void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::
 	if (multimesh->instances) {
 		glGenBuffers(1, &multimesh->buffer);
 		glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer);
-		glBufferData(GL_ARRAY_BUFFER, multimesh->instances * multimesh->stride_cache * sizeof(float), nullptr, GL_STATIC_DRAW);
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, multimesh->buffer, multimesh->instances * multimesh->stride_cache * sizeof(float), nullptr, GL_STATIC_DRAW, "MultiMesh buffer");
 		glBindBuffer(GL_ARRAY_BUFFER, 0);
 	}
 
@@ -1958,7 +1959,7 @@ void MeshStorage::skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_
 	}
 
 	if (skeleton->transforms_texture != 0) {
-		glDeleteTextures(1, &skeleton->transforms_texture);
+		GLES3::Utilities::get_singleton()->texture_free_data(skeleton->transforms_texture);
 		skeleton->transforms_texture = 0;
 		skeleton->data.clear();
 	}
@@ -1973,6 +1974,7 @@ void MeshStorage::skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_
 		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 		glBindTexture(GL_TEXTURE_2D, 0);
+		GLES3::Utilities::get_singleton()->texture_allocated_data(skeleton->transforms_texture, skeleton->data.size() * sizeof(float), "Skeleton transforms texture");
 
 		memset(skeleton->data.ptrw(), 0, skeleton->data.size() * sizeof(float));
 

+ 25 - 19
drivers/gles3/storage/particles_storage.cpp

@@ -141,23 +141,23 @@ void ParticlesStorage::_particles_free_data(Particles *particles) {
 
 	if (particles->front_process_buffer != 0) {
 		glDeleteVertexArrays(1, &particles->front_vertex_array);
-		glDeleteBuffers(1, &particles->front_process_buffer);
-		glDeleteBuffers(1, &particles->front_instance_buffer);
+		GLES3::Utilities::get_singleton()->buffer_free_data(particles->front_process_buffer);
+		GLES3::Utilities::get_singleton()->buffer_free_data(particles->front_instance_buffer);
 		particles->front_vertex_array = 0;
 		particles->front_process_buffer = 0;
 		particles->front_instance_buffer = 0;
 
 		glDeleteVertexArrays(1, &particles->back_vertex_array);
-		glDeleteBuffers(1, &particles->back_process_buffer);
-		glDeleteBuffers(1, &particles->back_instance_buffer);
+		GLES3::Utilities::get_singleton()->buffer_free_data(particles->back_process_buffer);
+		GLES3::Utilities::get_singleton()->buffer_free_data(particles->back_instance_buffer);
 		particles->back_vertex_array = 0;
 		particles->back_process_buffer = 0;
 		particles->back_instance_buffer = 0;
 	}
 
 	if (particles->sort_buffer != 0) {
-		glDeleteBuffers(1, &particles->last_frame_buffer);
-		glDeleteBuffers(1, &particles->sort_buffer);
+		GLES3::Utilities::get_singleton()->buffer_free_data(particles->last_frame_buffer);
+		GLES3::Utilities::get_singleton()->buffer_free_data(particles->sort_buffer);
 		particles->last_frame_buffer = 0;
 		particles->sort_buffer = 0;
 		particles->sort_buffer_filled = false;
@@ -165,7 +165,7 @@ void ParticlesStorage::_particles_free_data(Particles *particles) {
 	}
 
 	if (particles->frame_params_ubo != 0) {
-		glDeleteBuffers(1, &particles->frame_params_ubo);
+		GLES3::Utilities::get_singleton()->buffer_free_data(particles->frame_params_ubo);
 		particles->frame_params_ubo = 0;
 	}
 }
@@ -680,10 +680,13 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
 
 	if (p_particles->frame_params_ubo == 0) {
 		glGenBuffers(1, &p_particles->frame_params_ubo);
+		glBindBufferBase(GL_UNIFORM_BUFFER, PARTICLES_FRAME_UNIFORM_LOCATION, p_particles->frame_params_ubo);
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, p_particles->frame_params_ubo, sizeof(ParticlesFrameParams), &frame_params, GL_STREAM_DRAW, "Particle Frame UBO");
+	} else {
+		// Update per-frame UBO.
+		glBindBufferBase(GL_UNIFORM_BUFFER, PARTICLES_FRAME_UNIFORM_LOCATION, p_particles->frame_params_ubo);
+		glBufferData(GL_UNIFORM_BUFFER, sizeof(ParticlesFrameParams), &frame_params, GL_STREAM_DRAW);
 	}
-	// Update per-frame UBO.
-	glBindBufferBase(GL_UNIFORM_BUFFER, PARTICLES_FRAME_UNIFORM_LOCATION, p_particles->frame_params_ubo);
-	glBufferData(GL_UNIFORM_BUFFER, sizeof(ParticlesFrameParams), &frame_params, GL_STREAM_DRAW);
 
 	// Get shader and set shader uniforms;
 	ParticleProcessMaterialData *m = static_cast<ParticleProcessMaterialData *>(material_storage->material_get_data(p_particles->process_material, RS::SHADER_PARTICLES));
@@ -831,7 +834,7 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) {
 			glGenBuffers(1, &particles->front_instance_buffer);
 
 			glBindBuffer(GL_ARRAY_BUFFER, particles->front_process_buffer);
-			glBufferData(GL_ARRAY_BUFFER, particles->process_buffer_stride_cache * total_amount, data, GL_DYNAMIC_COPY);
+			GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->front_process_buffer, particles->process_buffer_stride_cache * total_amount, data, GL_DYNAMIC_COPY, "Particles front process buffer");
 
 			for (uint32_t j = 0; j < particles->num_attrib_arrays_cache; j++) {
 				glEnableVertexAttribArray(j);
@@ -840,7 +843,7 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) {
 			glBindVertexArray(0);
 
 			glBindBuffer(GL_ARRAY_BUFFER, particles->front_instance_buffer);
-			glBufferData(GL_ARRAY_BUFFER, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_COPY);
+			GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->front_instance_buffer, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_COPY, "Particles front instance buffer");
 		}
 
 		{
@@ -850,7 +853,7 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) {
 			glGenBuffers(1, &particles->back_instance_buffer);
 
 			glBindBuffer(GL_ARRAY_BUFFER, particles->back_process_buffer);
-			glBufferData(GL_ARRAY_BUFFER, particles->process_buffer_stride_cache * total_amount, data, GL_DYNAMIC_COPY);
+			GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->back_process_buffer, particles->process_buffer_stride_cache * total_amount, data, GL_DYNAMIC_COPY, "Particles back process buffer");
 
 			for (uint32_t j = 0; j < particles->num_attrib_arrays_cache; j++) {
 				glEnableVertexAttribArray(j);
@@ -859,7 +862,7 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) {
 			glBindVertexArray(0);
 
 			glBindBuffer(GL_ARRAY_BUFFER, particles->back_instance_buffer);
-			glBufferData(GL_ARRAY_BUFFER, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_COPY);
+			GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->back_instance_buffer, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_COPY, "Particles back instance buffer");
 		}
 		glBindBuffer(GL_ARRAY_BUFFER, 0);
 
@@ -871,11 +874,12 @@ void ParticlesStorage::_particles_allocate_history_buffers(Particles *particles)
 	if (particles->sort_buffer == 0) {
 		glGenBuffers(1, &particles->last_frame_buffer);
 		glBindBuffer(GL_ARRAY_BUFFER, particles->last_frame_buffer);
-		glBufferData(GL_ARRAY_BUFFER, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_READ);
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->last_frame_buffer, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_READ, "Particles last frame buffer");
 
 		glGenBuffers(1, &particles->sort_buffer);
 		glBindBuffer(GL_ARRAY_BUFFER, particles->sort_buffer);
-		glBufferData(GL_ARRAY_BUFFER, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_READ);
+		GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->sort_buffer, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_READ, "Particles sort buffer");
+
 		particles->sort_buffer_filled = false;
 		particles->last_frame_buffer_filled = false;
 		glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -1179,7 +1183,7 @@ void ParticlesStorage::particles_collision_free(RID p_rid) {
 	ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_rid);
 
 	if (particles_collision->heightfield_texture != 0) {
-		glDeleteTextures(1, &particles_collision->heightfield_texture);
+		GLES3::Utilities::get_singleton()->texture_free_data(particles_collision->heightfield_texture);
 		particles_collision->heightfield_texture = 0;
 		glDeleteFramebuffers(1, &particles_collision->heightfield_fb);
 		particles_collision->heightfield_fb = 0;
@@ -1226,6 +1230,8 @@ GLuint ParticlesStorage::particles_collision_get_heightfield_framebuffer(RID p_p
 			WARN_PRINT("Could create heightmap texture status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));
 		}
 #endif
+		GLES3::Utilities::get_singleton()->texture_allocated_data(particles_collision->heightfield_texture, size.x * size.y * 4, "Particles collision heightfield texture");
+
 		particles_collision->heightfield_fb_size = size;
 
 		glBindTexture(GL_TEXTURE_2D, 0);
@@ -1244,7 +1250,7 @@ void ParticlesStorage::particles_collision_set_collision_type(RID p_particles_co
 	}
 
 	if (particles_collision->heightfield_texture != 0) {
-		glDeleteTextures(1, &particles_collision->heightfield_texture);
+		GLES3::Utilities::get_singleton()->texture_free_data(particles_collision->heightfield_texture);
 		particles_collision->heightfield_texture = 0;
 		glDeleteFramebuffers(1, &particles_collision->heightfield_fb);
 		particles_collision->heightfield_fb = 0;
@@ -1319,7 +1325,7 @@ void ParticlesStorage::particles_collision_set_height_field_resolution(RID p_par
 	particles_collision->heightfield_resolution = p_resolution;
 
 	if (particles_collision->heightfield_texture != 0) {
-		glDeleteTextures(1, &particles_collision->heightfield_texture);
+		GLES3::Utilities::get_singleton()->texture_free_data(particles_collision->heightfield_texture);
 		particles_collision->heightfield_texture = 0;
 		glDeleteFramebuffers(1, &particles_collision->heightfield_fb);
 		particles_collision->heightfield_fb = 0;

+ 43 - 33
drivers/gles3/storage/texture_storage.cpp

@@ -33,6 +33,7 @@
 #include "texture_storage.h"
 #include "config.h"
 #include "drivers/gles3/effects/copy_effects.h"
+#include "utilities.h"
 
 #ifdef ANDROID_ENABLED
 #define glFramebufferTextureMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultiviewOVR
@@ -164,6 +165,7 @@ TextureStorage::TextureStorage() {
 
 			glBindTexture(GL_TEXTURE_2D, texture.tex_id);
 			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8UI, 4, 4, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, pixel_data);
+			GLES3::Utilities::get_singleton()->texture_allocated_data(texture.tex_id, 4 * 4 * 4, "Default uint texture");
 			texture.gl_set_filter(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
 		}
 		{
@@ -185,6 +187,7 @@ TextureStorage::TextureStorage() {
 
 			glBindTexture(GL_TEXTURE_2D, texture.tex_id);
 			glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, 4, 4, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, pixel_data);
+			GLES3::Utilities::get_singleton()->texture_allocated_data(texture.tex_id, 4 * 4 * 2, "Default depth texture");
 			texture.gl_set_filter(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
 		}
 	}
@@ -203,6 +206,7 @@ TextureStorage::TextureStorage() {
 		glGenTextures(1, &texture_atlas.texture);
 		glBindTexture(GL_TEXTURE_2D, texture_atlas.texture);
 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel_data);
+		GLES3::Utilities::get_singleton()->texture_allocated_data(texture_atlas.texture, 4 * 4 * 4, "Texture atlas (Default)");
 	}
 
 	glBindTexture(GL_TEXTURE_2D, 0);
@@ -222,8 +226,9 @@ TextureStorage::~TextureStorage() {
 	for (int i = 0; i < DEFAULT_GL_TEXTURE_MAX; i++) {
 		texture_free(default_gl_textures[i]);
 	}
-
-	glDeleteTextures(1, &texture_atlas.texture);
+	if (texture_atlas.texture != 0) {
+		GLES3::Utilities::get_singleton()->texture_free_data(texture_atlas.texture);
+	}
 	texture_atlas.texture = 0;
 	glDeleteFramebuffers(1, &texture_atlas.framebuffer);
 	texture_atlas.framebuffer = 0;
@@ -706,7 +711,7 @@ void TextureStorage::texture_free(RID p_texture) {
 
 	if (t->tex_id != 0) {
 		if (!t->is_external) {
-			glDeleteTextures(1, &t->tex_id);
+			GLES3::Utilities::get_singleton()->texture_free_data(t->tex_id);
 		}
 		t->tex_id = 0;
 	}
@@ -743,9 +748,10 @@ void TextureStorage::texture_2d_initialize(RID p_texture, const Ref<Image> &p_im
 	texture.type = Texture::TYPE_2D;
 	texture.target = GL_TEXTURE_2D;
 	_get_gl_image_and_format(Ref<Image>(), texture.format, texture.real_format, texture.gl_format_cache, texture.gl_internal_format_cache, texture.gl_type_cache, texture.compressed, false);
-	//texture.total_data_size = p_image->get_image_data_size(); // verify that this returns size in bytes
+	texture.total_data_size = p_image->get_image_data_size(texture.width, texture.height, texture.format, texture.mipmaps);
 	texture.active = true;
 	glGenTextures(1, &texture.tex_id);
+	GLES3::Utilities::get_singleton()->texture_allocated_data(texture.tex_id, texture.total_data_size, "Texture 2D");
 	texture_owner.initialize_rid(p_texture, texture);
 	texture_set_data(p_texture, p_image);
 }
@@ -792,8 +798,10 @@ void TextureStorage::texture_2d_layered_initialize(RID p_texture, const Vector<R
 	texture.target = p_layered_type == RS::TEXTURE_LAYERED_CUBEMAP ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D_ARRAY;
 	texture.layers = p_layers.size();
 	_get_gl_image_and_format(Ref<Image>(), texture.format, texture.real_format, texture.gl_format_cache, texture.gl_internal_format_cache, texture.gl_type_cache, texture.compressed, false);
+	texture.total_data_size = p_layers[0]->get_image_data_size(texture.width, texture.height, texture.format, texture.mipmaps) * texture.layers;
 	texture.active = true;
 	glGenTextures(1, &texture.tex_id);
+	GLES3::Utilities::get_singleton()->texture_allocated_data(texture.tex_id, texture.total_data_size, "Texture Layered");
 	texture_owner.initialize_rid(p_texture, texture);
 	for (int i = 0; i < p_layers.size(); i++) {
 		_texture_set_data(p_texture, p_layers[i], i, i == 0);
@@ -850,10 +858,12 @@ RID TextureStorage::texture_create_external(Texture::Type p_type, Image::Format
 
 void TextureStorage::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) {
 	texture_set_data(p_texture, p_image, p_layer);
-#ifdef TOOLS_ENABLED
+
 	Texture *tex = texture_owner.get_or_null(p_texture);
 	ERR_FAIL_COND(!tex);
+	GLES3::Utilities::get_singleton()->texture_resize_data(tex->tex_id, tex->total_data_size);
 
+#ifdef TOOLS_ENABLED
 	tex->image_cache_2d.unref();
 #endif
 }
@@ -1063,7 +1073,7 @@ void TextureStorage::texture_replace(RID p_texture, RID p_by_texture) {
 	}
 
 	if (tex_to->tex_id) {
-		glDeleteTextures(1, &tex_to->tex_id);
+		GLES3::Utilities::get_singleton()->texture_free_data(tex_to->tex_id);
 		tex_to->tex_id = 0;
 	}
 
@@ -1213,15 +1223,11 @@ void TextureStorage::_texture_set_data(RID p_texture, const Ref<Image> &p_image,
 	ERR_FAIL_COND(!p_image->get_width());
 	ERR_FAIL_COND(!p_image->get_height());
 
-	//	ERR_FAIL_COND(texture->type == RS::TEXTURE_TYPE_EXTERNAL);
-
 	GLenum type;
 	GLenum format;
 	GLenum internal_format;
 	bool compressed = false;
 
-	// print_line("texture_set_data width " + itos (p_image->get_width()) + " height " + itos(p_image->get_height()));
-
 	Image::Format real_format;
 	Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), real_format, format, internal_format, type, compressed, texture->resize_to_po2);
 	ERR_FAIL_COND(img.is_null());
@@ -1322,21 +1328,13 @@ void TextureStorage::_texture_set_data(RID p_texture, const Ref<Image> &p_image,
 		h = MAX(1, h >> 1);
 	}
 
-	// info.texture_mem -= texture->total_data_size; // TODO make this work again!!
 	texture->total_data_size = tsize;
-	// info.texture_mem += texture->total_data_size; // TODO make this work again!!
-
-	// printf("texture: %i x %i - size: %i - total: %i\n", texture->width, texture->height, tsize, info.texture_mem);
 
 	texture->stored_cube_sides |= (1 << p_layer);
 
 	texture->mipmaps = mipmaps;
 }
 
-void TextureStorage::texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer) {
-	ERR_PRINT("Not implemented yet, sorry :(");
-}
-
 Image::Format TextureStorage::texture_get_format(RID p_texture) const {
 	Texture *texture = texture_owner.get_or_null(p_texture);
 
@@ -1386,10 +1384,6 @@ void TextureStorage::texture_bind(RID p_texture, uint32_t p_texture_no) {
 	glBindTexture(texture->target, texture->tex_id);
 }
 
-RID TextureStorage::texture_create_radiance_cubemap(RID p_source, int p_resolution) const {
-	return RID();
-}
-
 /* TEXTURE ATLAS API */
 
 void TextureStorage::texture_add_to_texture_atlas(RID p_texture) {
@@ -1442,7 +1436,7 @@ void TextureStorage::update_texture_atlas() {
 	texture_atlas.dirty = false;
 
 	if (texture_atlas.texture != 0) {
-		glDeleteTextures(1, &texture_atlas.texture);
+		GLES3::Utilities::get_singleton()->texture_free_data(texture_atlas.texture);
 		texture_atlas.texture = 0;
 		glDeleteFramebuffers(1, &texture_atlas.framebuffer);
 		texture_atlas.framebuffer = 0;
@@ -1559,6 +1553,7 @@ void TextureStorage::update_texture_atlas() {
 		glActiveTexture(GL_TEXTURE0);
 		glBindTexture(GL_TEXTURE_2D, texture_atlas.texture);
 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texture_atlas.size.width, texture_atlas.size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+		GLES3::Utilities::get_singleton()->texture_allocated_data(texture_atlas.texture, texture_atlas.size.width * texture_atlas.size.height * 4, "Texture atlas");
 
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -1576,7 +1571,7 @@ void TextureStorage::update_texture_atlas() {
 		if (status != GL_FRAMEBUFFER_COMPLETE) {
 			glDeleteFramebuffers(1, &texture_atlas.framebuffer);
 			texture_atlas.framebuffer = 0;
-			glDeleteTextures(1, &texture_atlas.texture);
+			GLES3::Utilities::get_singleton()->texture_free_data(texture_atlas.texture);
 			texture_atlas.texture = 0;
 			WARN_PRINT("Could not create texture atlas, status: " + get_framebuffer_error(status));
 			return;
@@ -1702,6 +1697,8 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
 			glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 			glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 			glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+			GLES3::Utilities::get_singleton()->texture_allocated_data(rt->color, rt->size.x * rt->size.y * rt->view_count * 4, "Render target color texture");
 		}
 #ifndef IOS_ENABLED
 		if (use_multiview) {
@@ -1733,6 +1730,8 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
 			glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 			glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 			glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+			GLES3::Utilities::get_singleton()->texture_allocated_data(rt->depth, rt->size.x * rt->size.y * rt->view_count * 3, "Render target depth texture");
 		}
 #ifndef IOS_ENABLED
 		if (use_multiview) {
@@ -1747,7 +1746,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
 		GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 		if (status != GL_FRAMEBUFFER_COMPLETE) {
 			glDeleteFramebuffers(1, &rt->fbo);
-			glDeleteTextures(1, &rt->color);
+			GLES3::Utilities::get_singleton()->texture_free_data(rt->color);
 			rt->fbo = 0;
 			rt->size.x = 0;
 			rt->size.y = 0;
@@ -1805,8 +1804,10 @@ void TextureStorage::_create_render_target_backbuffer(RenderTarget *rt) {
 
 		glGenTextures(1, &rt->backbuffer);
 		glBindTexture(GL_TEXTURE_2D, rt->backbuffer);
+		uint32_t texture_size_bytes = 0;
 
 		for (int l = 0; l < count; l++) {
+			texture_size_bytes += width * height * 4;
 			glTexImage2D(GL_TEXTURE_2D, l, rt->color_internal_format, width, height, 0, rt->color_format, rt->color_type, nullptr);
 			width = MAX(1, (width / 2));
 			height = MAX(1, (height / 2));
@@ -1826,6 +1827,7 @@ void TextureStorage::_create_render_target_backbuffer(RenderTarget *rt) {
 			glBindFramebuffer(GL_FRAMEBUFFER, system_fbo);
 			return;
 		}
+		GLES3::Utilities::get_singleton()->texture_allocated_data(rt->backbuffer, texture_size_bytes, "Render target backbuffer color texture");
 
 		// Initialize all levels to opaque Magenta.
 		for (int j = 0; j < count; j++) {
@@ -1862,7 +1864,7 @@ void GLES3::TextureStorage::copy_scene_to_backbuffer(RenderTarget *rt, const boo
 		} else {
 			glTexImage2D(texture_target, 0, rt->color_internal_format, rt->size.x, rt->size.y, 0, rt->color_format, rt->color_type, nullptr);
 		}
-
+		GLES3::Utilities::get_singleton()->texture_allocated_data(rt->backbuffer, rt->size.x * rt->size.y * rt->view_count * 4, "Render target backbuffer color texture (3D)");
 		glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 		glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 		glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -1885,6 +1887,8 @@ void GLES3::TextureStorage::copy_scene_to_backbuffer(RenderTarget *rt, const boo
 		} else {
 			glTexImage2D(texture_target, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
 		}
+		GLES3::Utilities::get_singleton()->texture_allocated_data(rt->backbuffer_depth, rt->size.x * rt->size.y * rt->view_count * 3, "Render target backbuffer depth texture");
+
 		glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 		glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 		glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -1941,7 +1945,7 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
 	if (rt->overridden.color.is_valid()) {
 		rt->overridden.color = RID();
 	} else if (rt->color) {
-		glDeleteTextures(1, &rt->color);
+		GLES3::Utilities::get_singleton()->texture_free_data(rt->color);
 		if (rt->texture.is_valid()) {
 			Texture *tex = get_texture(rt->texture);
 			tex->tex_id = 0;
@@ -1952,7 +1956,7 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
 	if (rt->overridden.depth.is_valid()) {
 		rt->overridden.depth = RID();
 	} else if (rt->depth) {
-		glDeleteTextures(1, &rt->depth);
+		GLES3::Utilities::get_singleton()->texture_free_data(rt->depth);
 	}
 	rt->depth = 0;
 
@@ -1961,12 +1965,12 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
 
 	if (rt->backbuffer_fbo != 0) {
 		glDeleteFramebuffers(1, &rt->backbuffer_fbo);
-		glDeleteTextures(1, &rt->backbuffer);
+		GLES3::Utilities::get_singleton()->texture_free_data(rt->backbuffer);
 		rt->backbuffer = 0;
 		rt->backbuffer_fbo = 0;
 	}
 	if (rt->backbuffer_depth != 0) {
-		glDeleteTextures(1, &rt->backbuffer_depth);
+		GLES3::Utilities::get_singleton()->texture_free_data(rt->backbuffer_depth);
 		rt->backbuffer_depth = 0;
 	}
 	_render_target_clear_sdf(rt);
@@ -2331,6 +2335,7 @@ void TextureStorage::_render_target_allocate_sdf(RenderTarget *rt) {
 	glActiveTexture(GL_TEXTURE0);
 	glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_write);
 	glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, size.width, size.height, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr);
+	GLES3::Utilities::get_singleton()->texture_allocated_data(rt->sdf_texture_write, size.width * size.height, "SDF texture");
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
@@ -2371,6 +2376,7 @@ void TextureStorage::_render_target_allocate_sdf(RenderTarget *rt) {
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	GLES3::Utilities::get_singleton()->texture_allocated_data(rt->sdf_texture_process[0], rt->process_size.width * rt->process_size.height * 4, "SDF process texture[0]");
 
 	glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_process[1]);
 	glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16I, rt->process_size.width, rt->process_size.height, 0, GL_RG_INTEGER, GL_SHORT, nullptr);
@@ -2380,6 +2386,7 @@ void TextureStorage::_render_target_allocate_sdf(RenderTarget *rt) {
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	GLES3::Utilities::get_singleton()->texture_allocated_data(rt->sdf_texture_process[1], rt->process_size.width * rt->process_size.height * 4, "SDF process texture[1]");
 
 	glGenTextures(1, &rt->sdf_texture_read);
 	glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_read);
@@ -2390,13 +2397,16 @@ void TextureStorage::_render_target_allocate_sdf(RenderTarget *rt) {
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	GLES3::Utilities::get_singleton()->texture_allocated_data(rt->sdf_texture_read, rt->process_size.width * rt->process_size.height * 4, "SDF texture (read)");
 }
 
 void TextureStorage::_render_target_clear_sdf(RenderTarget *rt) {
 	if (rt->sdf_texture_write_fb != 0) {
-		glDeleteTextures(1, &rt->sdf_texture_read);
-		glDeleteTextures(1, &rt->sdf_texture_write);
-		glDeleteTextures(2, rt->sdf_texture_process);
+		GLES3::Utilities::get_singleton()->texture_free_data(rt->sdf_texture_read);
+		GLES3::Utilities::get_singleton()->texture_free_data(rt->sdf_texture_write);
+		GLES3::Utilities::get_singleton()->texture_free_data(rt->sdf_texture_process[0]);
+		GLES3::Utilities::get_singleton()->texture_free_data(rt->sdf_texture_process[1]);
+
 		glDeleteFramebuffers(1, &rt->sdf_texture_write_fb);
 		rt->sdf_texture_read = 0;
 		rt->sdf_texture_write = 0;

+ 0 - 4
drivers/gles3/storage/texture_storage.h

@@ -542,16 +542,12 @@ public:
 	virtual uint64_t texture_get_native_handle(RID p_texture, bool p_srgb = false) const override;
 
 	void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer = 0);
-	void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer = 0);
-	//Ref<Image> texture_get_data(RID p_texture, int p_layer = 0) const;
-	void texture_set_sampler(RID p_texture, RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat);
 	Image::Format texture_get_format(RID p_texture) const;
 	uint32_t texture_get_texid(RID p_texture) const;
 	uint32_t texture_get_width(RID p_texture) const;
 	uint32_t texture_get_height(RID p_texture) const;
 	uint32_t texture_get_depth(RID p_texture) const;
 	void texture_bind(RID p_texture, uint32_t p_texture_no);
-	RID texture_create_radiance_cubemap(RID p_source, int p_resolution = -1) const;
 
 	/* TEXTURE ATLAS API */
 

+ 38 - 0
drivers/gles3/storage/utilities.cpp

@@ -67,6 +67,37 @@ Utilities::~Utilities() {
 	for (int i = 0; i < FRAME_COUNT; i++) {
 		glDeleteQueries(max_timestamp_query_elements, frames[i].queries);
 	}
+
+	if (texture_mem_cache) {
+		uint32_t leaked_data_size = 0;
+		for (const KeyValue<GLuint, ResourceAllocation> &E : texture_allocs_cache) {
+#ifdef DEV_ENABLED
+			ERR_PRINT(E.value.name + ": leaked " + itos(E.value.size) + " bytes.");
+#else
+			ERR_PRINT("Texture with GL ID of " + itos(E.key) + ": leaked " + itos(E.value.size) + " bytes.");
+#endif
+			leaked_data_size += E.value.size;
+		}
+		if (leaked_data_size < texture_mem_cache) {
+			ERR_PRINT("Texture cache is not empty. There may be an additional texture leak of " + itos(texture_mem_cache - leaked_data_size) + " bytes.");
+		}
+	}
+
+	if (buffer_mem_cache) {
+		uint32_t leaked_data_size = 0;
+
+		for (const KeyValue<GLuint, ResourceAllocation> &E : buffer_allocs_cache) {
+#ifdef DEV_ENABLED
+			ERR_PRINT(E.value.name + ": leaked " + itos(E.value.size) + " bytes.");
+#else
+			ERR_PRINT("Buffer with GL ID of " + itos(E.key) + ": leaked " + itos(E.value.size) + " bytes.");
+#endif
+			leaked_data_size += E.value.size;
+		}
+		if (leaked_data_size < buffer_mem_cache) {
+			ERR_PRINT("Buffer cache is not empty. There may be an additional buffer leak of " + itos(buffer_mem_cache - leaked_data_size) + " bytes.");
+		}
+	}
 }
 
 Vector<uint8_t> Utilities::buffer_get_data(GLenum p_target, GLuint p_buffer, uint32_t p_buffer_size) {
@@ -324,6 +355,13 @@ void Utilities::update_memory_info() {
 }
 
 uint64_t Utilities::get_rendering_info(RS::RenderingInfo p_info) {
+	if (p_info == RS::RENDERING_INFO_TEXTURE_MEM_USED) {
+		return texture_mem_cache;
+	} else if (p_info == RS::RENDERING_INFO_BUFFER_MEM_USED) {
+		return buffer_mem_cache;
+	} else if (p_info == RS::RENDERING_INFO_VIDEO_MEM_USED) {
+		return texture_mem_cache + buffer_mem_cache;
+	}
 	return 0;
 }
 

+ 64 - 0
drivers/gles3/storage/utilities.h

@@ -48,6 +48,18 @@ class Utilities : public RendererUtilities {
 private:
 	static Utilities *singleton;
 
+	struct ResourceAllocation {
+#ifdef DEV_ENABLED
+		String name;
+#endif
+		uint32_t size = 0;
+	};
+	HashMap<GLuint, ResourceAllocation> buffer_allocs_cache;
+	HashMap<GLuint, ResourceAllocation> texture_allocs_cache;
+
+	uint64_t buffer_mem_cache = 0;
+	uint64_t texture_mem_cache = 0;
+
 public:
 	static Utilities *get_singleton() { return singleton; }
 
@@ -57,6 +69,58 @@ public:
 	// Buffer size is specified in bytes
 	static Vector<uint8_t> buffer_get_data(GLenum p_target, GLuint p_buffer, uint32_t p_buffer_size);
 
+	// Allocate memory with glBufferData. Does not handle resizing.
+	_FORCE_INLINE_ void buffer_allocate_data(GLenum p_target, GLuint p_id, uint32_t p_size, const void *p_data, GLenum p_usage, String p_name = "") {
+		glBufferData(p_target, p_size, p_data, p_usage);
+		buffer_mem_cache += p_size;
+
+#ifdef DEV_ENABLED
+		ERR_FAIL_COND_MSG(buffer_allocs_cache.has(p_id), "trying to allocate buffer with name " + p_name + " but ID already used by " + buffer_allocs_cache[p_id].name);
+#endif
+
+		ResourceAllocation resource_allocation;
+		resource_allocation.size = p_size;
+#ifdef DEV_ENABLED
+		resource_allocation.name = p_name + ": " + itos((uint64_t)p_id);
+#endif
+		buffer_allocs_cache[p_id] = resource_allocation;
+	}
+
+	_FORCE_INLINE_ void buffer_free_data(GLuint p_id) {
+		ERR_FAIL_COND(!buffer_allocs_cache.has(p_id));
+		glDeleteBuffers(1, &p_id);
+		buffer_mem_cache -= buffer_allocs_cache[p_id].size;
+		buffer_allocs_cache.erase(p_id);
+	}
+
+	// Records that data was allocated for state tracking purposes.
+	_FORCE_INLINE_ void texture_allocated_data(GLuint p_id, uint32_t p_size, String p_name = "") {
+		texture_mem_cache += p_size;
+#ifdef DEV_ENABLED
+		ERR_FAIL_COND_MSG(texture_allocs_cache.has(p_id), "trying to allocate texture with name " + p_name + " but ID already used by " + texture_allocs_cache[p_id].name);
+#endif
+		ResourceAllocation resource_allocation;
+		resource_allocation.size = p_size;
+#ifdef DEV_ENABLED
+		resource_allocation.name = p_name + ": " + itos((uint64_t)p_id);
+#endif
+		texture_allocs_cache[p_id] = resource_allocation;
+	}
+
+	_FORCE_INLINE_ void texture_free_data(GLuint p_id) {
+		ERR_FAIL_COND(!texture_allocs_cache.has(p_id));
+		glDeleteTextures(1, &p_id);
+		texture_mem_cache -= texture_allocs_cache[p_id].size;
+		texture_allocs_cache.erase(p_id);
+	}
+
+	_FORCE_INLINE_ void texture_resize_data(GLuint p_id, uint32_t p_size) {
+		ERR_FAIL_COND(!texture_allocs_cache.has(p_id));
+		texture_mem_cache -= texture_allocs_cache[p_id].size;
+		texture_mem_cache += p_size;
+		texture_allocs_cache[p_id].size = p_size;
+	}
+
 	/* INSTANCES */
 
 	virtual RS::InstanceType get_base_type(RID p_rid) const override;

+ 1 - 1
editor/plugins/node_3d_editor_plugin.cpp

@@ -2817,7 +2817,7 @@ void Node3DEditorViewport::_notification(int p_what) {
 
 				text += "\n";
 				text += vformat(TTR("Objects: %d\n"), viewport->get_render_info(Viewport::RENDER_INFO_TYPE_VISIBLE, Viewport::RENDER_INFO_OBJECTS_IN_FRAME));
-				text += vformat(TTR("Primitive Indices: %d\n"), viewport->get_render_info(Viewport::RENDER_INFO_TYPE_VISIBLE, Viewport::RENDER_INFO_PRIMITIVES_IN_FRAME));
+				text += vformat(TTR("Primitives: %d\n"), viewport->get_render_info(Viewport::RENDER_INFO_TYPE_VISIBLE, Viewport::RENDER_INFO_PRIMITIVES_IN_FRAME));
 				text += vformat(TTR("Draw Calls: %d"), viewport->get_render_info(Viewport::RENDER_INFO_TYPE_VISIBLE, Viewport::RENDER_INFO_DRAW_CALLS_IN_FRAME));
 
 				info_label->set_text(text);

+ 2 - 2
servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp

@@ -984,9 +984,9 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
 					to_draw = _indices_to_primitives(surf->primitive, to_draw);
 					to_draw *= inst->instance_count;
 					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] += mesh_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] += to_draw;
 					} 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] += mesh_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] += to_draw;
 					}
 				}
 			}

+ 2 - 2
servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp

@@ -1884,9 +1884,9 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
 					to_draw = _indices_to_primitives(surf->primitive, to_draw);
 					to_draw *= inst->instance_count;
 					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] += mesh_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] += to_draw;
 					} 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] += mesh_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] += to_draw;
 					}
 				}
 			}

+ 1 - 1
servers/rendering/renderer_viewport.cpp

@@ -1403,7 +1403,7 @@ void RendererViewport::call_set_vsync_mode(DisplayServer::VSyncMode p_mode, Disp
 int RendererViewport::get_total_objects_drawn() const {
 	return total_objects_drawn;
 }
-int RendererViewport::get_total_vertices_drawn() const {
+int RendererViewport::get_total_primitives_drawn() const {
 	return total_vertices_drawn;
 }
 int RendererViewport::get_total_draw_calls_used() const {

+ 1 - 1
servers/rendering/renderer_viewport.h

@@ -297,7 +297,7 @@ public:
 	bool free(RID p_rid);
 
 	int get_total_objects_drawn() const;
-	int get_total_vertices_drawn() const;
+	int get_total_primitives_drawn() const;
 	int get_total_draw_calls_used() const;
 
 	// Workaround for setting this on thread.

+ 1 - 1
servers/rendering/rendering_server_default.cpp

@@ -251,7 +251,7 @@ uint64_t RenderingServerDefault::get_rendering_info(RenderingInfo p_info) {
 	if (p_info == RENDERING_INFO_TOTAL_OBJECTS_IN_FRAME) {
 		return RSG::viewport->get_total_objects_drawn();
 	} else if (p_info == RENDERING_INFO_TOTAL_PRIMITIVES_IN_FRAME) {
-		return RSG::viewport->get_total_vertices_drawn();
+		return RSG::viewport->get_total_primitives_drawn();
 	} else if (p_info == RENDERING_INFO_TOTAL_DRAW_CALLS_IN_FRAME) {
 		return RSG::viewport->get_total_draw_calls_used();
 	}