1/**************************************************************************/
2/* utilities.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#ifdef GLES3_ENABLED
32
33#include "utilities.h"
34#include "config.h"
35#include "light_storage.h"
36#include "material_storage.h"
37#include "mesh_storage.h"
38#include "particles_storage.h"
39#include "texture_storage.h"
40
41#include "servers/rendering/rendering_server_globals.h"
42
43using namespace GLES3;
44
45Utilities *Utilities::singleton = nullptr;
46
47Utilities::Utilities() {
48 singleton = this;
49 frame = 0;
50 for (int i = 0; i < FRAME_COUNT; i++) {
51 frames[i].index = 0;
52 glGenQueries(max_timestamp_query_elements, frames[i].queries);
53
54 frames[i].timestamp_names.resize(max_timestamp_query_elements);
55 frames[i].timestamp_cpu_values.resize(max_timestamp_query_elements);
56 frames[i].timestamp_count = 0;
57
58 frames[i].timestamp_result_names.resize(max_timestamp_query_elements);
59 frames[i].timestamp_cpu_result_values.resize(max_timestamp_query_elements);
60 frames[i].timestamp_result_values.resize(max_timestamp_query_elements);
61 frames[i].timestamp_result_count = 0;
62 }
63}
64
65Utilities::~Utilities() {
66 singleton = nullptr;
67 for (int i = 0; i < FRAME_COUNT; i++) {
68 glDeleteQueries(max_timestamp_query_elements, frames[i].queries);
69 }
70
71 if (texture_mem_cache) {
72 uint32_t leaked_data_size = 0;
73 for (const KeyValue<GLuint, ResourceAllocation> &E : texture_allocs_cache) {
74#ifdef DEV_ENABLED
75 ERR_PRINT(E.value.name + ": leaked " + itos(E.value.size) + " bytes.");
76#else
77 ERR_PRINT("Texture with GL ID of " + itos(E.key) + ": leaked " + itos(E.value.size) + " bytes.");
78#endif
79 leaked_data_size += E.value.size;
80 }
81 if (leaked_data_size < texture_mem_cache) {
82 ERR_PRINT("Texture cache is not empty. There may be an additional texture leak of " + itos(texture_mem_cache - leaked_data_size) + " bytes.");
83 }
84 }
85
86 if (buffer_mem_cache) {
87 uint32_t leaked_data_size = 0;
88
89 for (const KeyValue<GLuint, ResourceAllocation> &E : buffer_allocs_cache) {
90#ifdef DEV_ENABLED
91 ERR_PRINT(E.value.name + ": leaked " + itos(E.value.size) + " bytes.");
92#else
93 ERR_PRINT("Buffer with GL ID of " + itos(E.key) + ": leaked " + itos(E.value.size) + " bytes.");
94#endif
95 leaked_data_size += E.value.size;
96 }
97 if (leaked_data_size < buffer_mem_cache) {
98 ERR_PRINT("Buffer cache is not empty. There may be an additional buffer leak of " + itos(buffer_mem_cache - leaked_data_size) + " bytes.");
99 }
100 }
101}
102
103Vector<uint8_t> Utilities::buffer_get_data(GLenum p_target, GLuint p_buffer, uint32_t p_buffer_size) {
104 Vector<uint8_t> ret;
105
106 if (p_buffer_size == 0) {
107 return ret;
108 }
109
110 ret.resize(p_buffer_size);
111 glBindBuffer(p_target, p_buffer);
112
113#if defined(__EMSCRIPTEN__)
114 {
115 uint8_t *w = ret.ptrw();
116 glGetBufferSubData(p_target, 0, p_buffer_size, w);
117 }
118#else
119 void *data = glMapBufferRange(p_target, 0, p_buffer_size, GL_MAP_READ_BIT);
120 ERR_FAIL_NULL_V(data, Vector<uint8_t>());
121 {
122 uint8_t *w = ret.ptrw();
123 memcpy(w, data, p_buffer_size);
124 }
125 glUnmapBuffer(p_target);
126#endif
127 glBindBuffer(p_target, 0);
128 return ret;
129}
130
131/* INSTANCES */
132
133RS::InstanceType Utilities::get_base_type(RID p_rid) const {
134 if (GLES3::MeshStorage::get_singleton()->owns_mesh(p_rid)) {
135 return RS::INSTANCE_MESH;
136 } else if (GLES3::MeshStorage::get_singleton()->owns_multimesh(p_rid)) {
137 return RS::INSTANCE_MULTIMESH;
138 } else if (GLES3::LightStorage::get_singleton()->owns_light(p_rid)) {
139 return RS::INSTANCE_LIGHT;
140 } else if (GLES3::LightStorage::get_singleton()->owns_lightmap(p_rid)) {
141 return RS::INSTANCE_LIGHTMAP;
142 } else if (GLES3::ParticlesStorage::get_singleton()->owns_particles(p_rid)) {
143 return RS::INSTANCE_PARTICLES;
144 } else if (GLES3::ParticlesStorage::get_singleton()->owns_particles_collision(p_rid)) {
145 return RS::INSTANCE_PARTICLES_COLLISION;
146 }
147 return RS::INSTANCE_NONE;
148}
149
150bool Utilities::free(RID p_rid) {
151 if (GLES3::TextureStorage::get_singleton()->owns_render_target(p_rid)) {
152 GLES3::TextureStorage::get_singleton()->render_target_free(p_rid);
153 return true;
154 } else if (GLES3::TextureStorage::get_singleton()->owns_texture(p_rid)) {
155 GLES3::TextureStorage::get_singleton()->texture_free(p_rid);
156 return true;
157 } else if (GLES3::TextureStorage::get_singleton()->owns_canvas_texture(p_rid)) {
158 GLES3::TextureStorage::get_singleton()->canvas_texture_free(p_rid);
159 return true;
160 } else if (GLES3::MaterialStorage::get_singleton()->owns_shader(p_rid)) {
161 GLES3::MaterialStorage::get_singleton()->shader_free(p_rid);
162 return true;
163 } else if (GLES3::MaterialStorage::get_singleton()->owns_material(p_rid)) {
164 GLES3::MaterialStorage::get_singleton()->material_free(p_rid);
165 return true;
166 } else if (GLES3::MeshStorage::get_singleton()->owns_mesh(p_rid)) {
167 GLES3::MeshStorage::get_singleton()->mesh_free(p_rid);
168 return true;
169 } else if (GLES3::MeshStorage::get_singleton()->owns_multimesh(p_rid)) {
170 GLES3::MeshStorage::get_singleton()->multimesh_free(p_rid);
171 return true;
172 } else if (GLES3::MeshStorage::get_singleton()->owns_mesh_instance(p_rid)) {
173 GLES3::MeshStorage::get_singleton()->mesh_instance_free(p_rid);
174 return true;
175 } else if (GLES3::LightStorage::get_singleton()->owns_light(p_rid)) {
176 GLES3::LightStorage::get_singleton()->light_free(p_rid);
177 return true;
178 } else if (GLES3::LightStorage::get_singleton()->owns_lightmap(p_rid)) {
179 GLES3::LightStorage::get_singleton()->lightmap_free(p_rid);
180 return true;
181 } else if (GLES3::ParticlesStorage::get_singleton()->owns_particles(p_rid)) {
182 GLES3::ParticlesStorage::get_singleton()->particles_free(p_rid);
183 return true;
184 } else if (GLES3::ParticlesStorage::get_singleton()->owns_particles_collision(p_rid)) {
185 GLES3::ParticlesStorage::get_singleton()->particles_collision_free(p_rid);
186 return true;
187 } else if (GLES3::ParticlesStorage::get_singleton()->owns_particles_collision_instance(p_rid)) {
188 GLES3::ParticlesStorage::get_singleton()->particles_collision_instance_free(p_rid);
189 return true;
190 } else if (GLES3::MeshStorage::get_singleton()->owns_skeleton(p_rid)) {
191 GLES3::MeshStorage::get_singleton()->skeleton_free(p_rid);
192 return true;
193 } else {
194 return false;
195 }
196}
197
198/* DEPENDENCIES */
199
200void Utilities::base_update_dependency(RID p_base, DependencyTracker *p_instance) {
201 if (MeshStorage::get_singleton()->owns_mesh(p_base)) {
202 Mesh *mesh = MeshStorage::get_singleton()->get_mesh(p_base);
203 p_instance->update_dependency(&mesh->dependency);
204 } else if (MeshStorage::get_singleton()->owns_multimesh(p_base)) {
205 MultiMesh *multimesh = MeshStorage::get_singleton()->get_multimesh(p_base);
206 p_instance->update_dependency(&multimesh->dependency);
207 if (multimesh->mesh.is_valid()) {
208 base_update_dependency(multimesh->mesh, p_instance);
209 }
210 } else if (LightStorage::get_singleton()->owns_light(p_base)) {
211 Light *l = LightStorage::get_singleton()->get_light(p_base);
212 p_instance->update_dependency(&l->dependency);
213 } else if (ParticlesStorage::get_singleton()->owns_particles(p_base)) {
214 Dependency *dependency = ParticlesStorage::get_singleton()->particles_get_dependency(p_base);
215 p_instance->update_dependency(dependency);
216 } else if (ParticlesStorage::get_singleton()->owns_particles_collision(p_base)) {
217 Dependency *dependency = ParticlesStorage::get_singleton()->particles_collision_get_dependency(p_base);
218 p_instance->update_dependency(dependency);
219 }
220}
221
222/* VISIBILITY NOTIFIER */
223
224RID Utilities::visibility_notifier_allocate() {
225 return RID();
226}
227
228void Utilities::visibility_notifier_initialize(RID p_notifier) {
229}
230
231void Utilities::visibility_notifier_free(RID p_notifier) {
232}
233
234void Utilities::visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) {
235}
236
237void Utilities::visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) {
238}
239
240AABB Utilities::visibility_notifier_get_aabb(RID p_notifier) const {
241 return AABB();
242}
243
244void Utilities::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) {
245}
246
247/* TIMING */
248
249void Utilities::capture_timestamps_begin() {
250 capture_timestamp("Frame Begin");
251}
252
253void Utilities::capture_timestamp(const String &p_name) {
254 ERR_FAIL_COND(frames[frame].timestamp_count >= max_timestamp_query_elements);
255
256#ifdef GLES_OVER_GL
257 glQueryCounter(frames[frame].queries[frames[frame].timestamp_count], GL_TIMESTAMP);
258#endif
259
260 frames[frame].timestamp_names[frames[frame].timestamp_count] = p_name;
261 frames[frame].timestamp_cpu_values[frames[frame].timestamp_count] = OS::get_singleton()->get_ticks_usec();
262 frames[frame].timestamp_count++;
263}
264
265void Utilities::_capture_timestamps_begin() {
266 // frame is incremented at the end of the frame so this gives us the queries for frame - 2. By then they should be ready.
267 if (frames[frame].timestamp_count) {
268#ifdef GLES_OVER_GL
269 for (uint32_t i = 0; i < frames[frame].timestamp_count; i++) {
270 uint64_t temp = 0;
271 glGetQueryObjectui64v(frames[frame].queries[i], GL_QUERY_RESULT, &temp);
272 frames[frame].timestamp_result_values[i] = temp;
273 }
274#endif
275 SWAP(frames[frame].timestamp_names, frames[frame].timestamp_result_names);
276 SWAP(frames[frame].timestamp_cpu_values, frames[frame].timestamp_cpu_result_values);
277 }
278
279 frames[frame].timestamp_result_count = frames[frame].timestamp_count;
280 frames[frame].timestamp_count = 0;
281 frames[frame].index = Engine::get_singleton()->get_frames_drawn();
282 capture_timestamp("Internal Begin");
283}
284
285void Utilities::capture_timestamps_end() {
286 capture_timestamp("Internal End");
287 frame = (frame + 1) % FRAME_COUNT;
288}
289
290uint32_t Utilities::get_captured_timestamps_count() const {
291 return frames[frame].timestamp_result_count;
292}
293
294uint64_t Utilities::get_captured_timestamps_frame() const {
295 return frames[frame].index;
296}
297
298uint64_t Utilities::get_captured_timestamp_gpu_time(uint32_t p_index) const {
299 ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);
300 return frames[frame].timestamp_result_values[p_index];
301}
302
303uint64_t Utilities::get_captured_timestamp_cpu_time(uint32_t p_index) const {
304 ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);
305 return frames[frame].timestamp_cpu_result_values[p_index];
306}
307
308String Utilities::get_captured_timestamp_name(uint32_t p_index) const {
309 ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, String());
310 return frames[frame].timestamp_result_names[p_index];
311}
312
313/* MISC */
314
315void Utilities::update_dirty_resources() {
316 MaterialStorage::get_singleton()->_update_global_shader_uniforms();
317 MaterialStorage::get_singleton()->_update_queued_materials();
318 MeshStorage::get_singleton()->_update_dirty_skeletons();
319 MeshStorage::get_singleton()->_update_dirty_multimeshes();
320 TextureStorage::get_singleton()->update_texture_atlas();
321}
322
323void Utilities::set_debug_generate_wireframes(bool p_generate) {
324}
325
326bool Utilities::has_os_feature(const String &p_feature) const {
327 Config *config = Config::get_singleton();
328 if (!config) {
329 return false;
330 }
331
332 if (p_feature == "rgtc") {
333 return config->rgtc_supported;
334 }
335
336 if (p_feature == "s3tc") {
337 return config->s3tc_supported;
338 }
339
340 if (p_feature == "bptc") {
341 return config->bptc_supported;
342 }
343 if (p_feature == "astc") {
344 return config->astc_supported;
345 }
346
347 if (p_feature == "etc" || p_feature == "etc2") {
348 return config->etc2_supported;
349 }
350
351 return false;
352}
353
354void Utilities::update_memory_info() {
355}
356
357uint64_t Utilities::get_rendering_info(RS::RenderingInfo p_info) {
358 if (p_info == RS::RENDERING_INFO_TEXTURE_MEM_USED) {
359 return texture_mem_cache;
360 } else if (p_info == RS::RENDERING_INFO_BUFFER_MEM_USED) {
361 return buffer_mem_cache;
362 } else if (p_info == RS::RENDERING_INFO_VIDEO_MEM_USED) {
363 return texture_mem_cache + buffer_mem_cache;
364 }
365 return 0;
366}
367
368String Utilities::get_video_adapter_name() const {
369 const String rendering_device_name = (const char *)glGetString(GL_RENDERER);
370 // NVIDIA suffixes all GPU model names with "/PCIe/SSE2" in OpenGL (but not Vulkan). This isn't necessary to display nowadays, so it can be trimmed.
371 return rendering_device_name.trim_suffix("/PCIe/SSE2");
372}
373
374String Utilities::get_video_adapter_vendor() const {
375 const String rendering_device_vendor = (const char *)glGetString(GL_VENDOR);
376 // NVIDIA suffixes its vendor name with " Corporation". This is neither necessary to process nor display.
377 return rendering_device_vendor.trim_suffix(" Corporation");
378}
379
380RenderingDevice::DeviceType Utilities::get_video_adapter_type() const {
381 return RenderingDevice::DeviceType::DEVICE_TYPE_OTHER;
382}
383
384String Utilities::get_video_adapter_api_version() const {
385 return (const char *)glGetString(GL_VERSION);
386}
387
388Size2i Utilities::get_maximum_viewport_size() const {
389 Config *config = Config::get_singleton();
390 if (!config) {
391 return Size2i();
392 }
393
394 return Size2i(config->max_viewport_size[0], config->max_viewport_size[1]);
395}
396
397#endif // GLES3_ENABLED
398