2022-06-21 00:08:33 +00:00
/**************************************************************************/
/* utilities.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "utilities.h"
2021-11-12 12:49:49 +00:00
# include "../rasterizer_gles3.h"
2022-06-21 00:08:33 +00:00
# include "config.h"
# include "light_storage.h"
# include "material_storage.h"
# include "mesh_storage.h"
# include "particles_storage.h"
# include "texture_storage.h"
2022-10-07 04:24:38 +00:00
# include "servers/rendering/rendering_server_globals.h"
2022-06-21 00:08:33 +00:00
using namespace GLES3 ;
Utilities * Utilities : : singleton = nullptr ;
Utilities : : Utilities ( ) {
singleton = this ;
2022-10-07 04:24:38 +00:00
frame = 0 ;
for ( int i = 0 ; i < FRAME_COUNT ; i + + ) {
frames [ i ] . index = 0 ;
glGenQueries ( max_timestamp_query_elements , frames [ i ] . queries ) ;
frames [ i ] . timestamp_names . resize ( max_timestamp_query_elements ) ;
frames [ i ] . timestamp_cpu_values . resize ( max_timestamp_query_elements ) ;
frames [ i ] . timestamp_count = 0 ;
frames [ i ] . timestamp_result_names . resize ( max_timestamp_query_elements ) ;
frames [ i ] . timestamp_cpu_result_values . resize ( max_timestamp_query_elements ) ;
frames [ i ] . timestamp_result_values . resize ( max_timestamp_query_elements ) ;
frames [ i ] . timestamp_result_count = 0 ;
}
2022-06-21 00:08:33 +00:00
}
Utilities : : ~ Utilities ( ) {
singleton = nullptr ;
2022-10-07 04:24:38 +00:00
for ( int i = 0 ; i < FRAME_COUNT ; i + + ) {
glDeleteQueries ( max_timestamp_query_elements , frames [ i ] . queries ) ;
}
2023-05-27 01:09:39 +00:00
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. " ) ;
}
}
2023-10-26 01:10:38 +00:00
if ( render_buffer_mem_cache ) {
uint32_t leaked_data_size = 0 ;
for ( const KeyValue < GLuint , ResourceAllocation > & E : render_buffer_allocs_cache ) {
# ifdef DEV_ENABLED
ERR_PRINT ( E . value . name + " : leaked " + itos ( E . value . size ) + " bytes. " ) ;
# else
ERR_PRINT ( " Render 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 < render_buffer_mem_cache ) {
ERR_PRINT ( " Render buffer cache is not empty. There may be an additional render buffer leak of " + itos ( render_buffer_mem_cache - leaked_data_size ) + " bytes. " ) ;
}
}
2023-05-27 01:09:39 +00:00
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. " ) ;
}
}
2022-06-21 00:08:33 +00:00
}
Vector < uint8_t > Utilities : : buffer_get_data ( GLenum p_target , GLuint p_buffer , uint32_t p_buffer_size ) {
Vector < uint8_t > ret ;
2022-11-01 20:40:23 +00:00
if ( p_buffer_size = = 0 ) {
return ret ;
}
2022-06-21 00:08:33 +00:00
ret . resize ( p_buffer_size ) ;
glBindBuffer ( p_target , p_buffer ) ;
# if defined(__EMSCRIPTEN__)
{
uint8_t * w = ret . ptrw ( ) ;
2023-07-20 13:42:03 +00:00
godot_webgl2_glGetBufferSubData ( p_target , 0 , p_buffer_size , w ) ;
2022-06-21 00:08:33 +00:00
}
# else
void * data = glMapBufferRange ( p_target , 0 , p_buffer_size , GL_MAP_READ_BIT ) ;
ERR_FAIL_NULL_V ( data , Vector < uint8_t > ( ) ) ;
{
uint8_t * w = ret . ptrw ( ) ;
memcpy ( w , data , p_buffer_size ) ;
}
glUnmapBuffer ( p_target ) ;
# endif
glBindBuffer ( p_target , 0 ) ;
return ret ;
}
/* INSTANCES */
RS : : InstanceType Utilities : : get_base_type ( RID p_rid ) const {
if ( GLES3 : : MeshStorage : : get_singleton ( ) - > owns_mesh ( p_rid ) ) {
return RS : : INSTANCE_MESH ;
} else if ( GLES3 : : MeshStorage : : get_singleton ( ) - > owns_multimesh ( p_rid ) ) {
return RS : : INSTANCE_MULTIMESH ;
} else if ( GLES3 : : LightStorage : : get_singleton ( ) - > owns_light ( p_rid ) ) {
return RS : : INSTANCE_LIGHT ;
2022-07-31 23:20:24 +00:00
} else if ( GLES3 : : LightStorage : : get_singleton ( ) - > owns_lightmap ( p_rid ) ) {
return RS : : INSTANCE_LIGHTMAP ;
2022-11-08 06:40:03 +00:00
} else if ( GLES3 : : ParticlesStorage : : get_singleton ( ) - > owns_particles ( p_rid ) ) {
return RS : : INSTANCE_PARTICLES ;
} else if ( GLES3 : : ParticlesStorage : : get_singleton ( ) - > owns_particles_collision ( p_rid ) ) {
return RS : : INSTANCE_PARTICLES_COLLISION ;
2022-06-21 00:08:33 +00:00
}
return RS : : INSTANCE_NONE ;
}
bool Utilities : : free ( RID p_rid ) {
if ( GLES3 : : TextureStorage : : get_singleton ( ) - > owns_render_target ( p_rid ) ) {
GLES3 : : TextureStorage : : get_singleton ( ) - > render_target_free ( p_rid ) ;
return true ;
} else if ( GLES3 : : TextureStorage : : get_singleton ( ) - > owns_texture ( p_rid ) ) {
GLES3 : : TextureStorage : : get_singleton ( ) - > texture_free ( p_rid ) ;
return true ;
} else if ( GLES3 : : TextureStorage : : get_singleton ( ) - > owns_canvas_texture ( p_rid ) ) {
GLES3 : : TextureStorage : : get_singleton ( ) - > canvas_texture_free ( p_rid ) ;
return true ;
} else if ( GLES3 : : MaterialStorage : : get_singleton ( ) - > owns_shader ( p_rid ) ) {
GLES3 : : MaterialStorage : : get_singleton ( ) - > shader_free ( p_rid ) ;
return true ;
} else if ( GLES3 : : MaterialStorage : : get_singleton ( ) - > owns_material ( p_rid ) ) {
GLES3 : : MaterialStorage : : get_singleton ( ) - > material_free ( p_rid ) ;
return true ;
} else if ( GLES3 : : MeshStorage : : get_singleton ( ) - > owns_mesh ( p_rid ) ) {
GLES3 : : MeshStorage : : get_singleton ( ) - > mesh_free ( p_rid ) ;
return true ;
} else if ( GLES3 : : MeshStorage : : get_singleton ( ) - > owns_multimesh ( p_rid ) ) {
GLES3 : : MeshStorage : : get_singleton ( ) - > multimesh_free ( p_rid ) ;
return true ;
} else if ( GLES3 : : MeshStorage : : get_singleton ( ) - > owns_mesh_instance ( p_rid ) ) {
GLES3 : : MeshStorage : : get_singleton ( ) - > mesh_instance_free ( p_rid ) ;
return true ;
} else if ( GLES3 : : LightStorage : : get_singleton ( ) - > owns_light ( p_rid ) ) {
GLES3 : : LightStorage : : get_singleton ( ) - > light_free ( p_rid ) ;
return true ;
2022-07-31 23:20:24 +00:00
} else if ( GLES3 : : LightStorage : : get_singleton ( ) - > owns_lightmap ( p_rid ) ) {
GLES3 : : LightStorage : : get_singleton ( ) - > lightmap_free ( p_rid ) ;
return true ;
2022-11-08 06:40:03 +00:00
} else if ( GLES3 : : ParticlesStorage : : get_singleton ( ) - > owns_particles ( p_rid ) ) {
GLES3 : : ParticlesStorage : : get_singleton ( ) - > particles_free ( p_rid ) ;
2022-06-21 00:08:33 +00:00
return true ;
2022-11-08 06:40:03 +00:00
} else if ( GLES3 : : ParticlesStorage : : get_singleton ( ) - > owns_particles_collision ( p_rid ) ) {
GLES3 : : ParticlesStorage : : get_singleton ( ) - > particles_collision_free ( p_rid ) ;
2022-06-21 00:08:33 +00:00
return true ;
2022-11-08 06:40:03 +00:00
} else if ( GLES3 : : ParticlesStorage : : get_singleton ( ) - > owns_particles_collision_instance ( p_rid ) ) {
GLES3 : : ParticlesStorage : : get_singleton ( ) - > particles_collision_instance_free ( p_rid ) ;
2022-06-21 00:08:33 +00:00
return true ;
2022-12-07 17:35:13 +00:00
} else if ( GLES3 : : MeshStorage : : get_singleton ( ) - > owns_skeleton ( p_rid ) ) {
GLES3 : : MeshStorage : : get_singleton ( ) - > skeleton_free ( p_rid ) ;
return true ;
2022-11-08 06:40:03 +00:00
} else {
return false ;
2022-06-21 00:08:33 +00:00
}
}
/* DEPENDENCIES */
void Utilities : : base_update_dependency ( RID p_base , DependencyTracker * p_instance ) {
if ( MeshStorage : : get_singleton ( ) - > owns_mesh ( p_base ) ) {
Mesh * mesh = MeshStorage : : get_singleton ( ) - > get_mesh ( p_base ) ;
p_instance - > update_dependency ( & mesh - > dependency ) ;
} else if ( MeshStorage : : get_singleton ( ) - > owns_multimesh ( p_base ) ) {
MultiMesh * multimesh = MeshStorage : : get_singleton ( ) - > get_multimesh ( p_base ) ;
p_instance - > update_dependency ( & multimesh - > dependency ) ;
if ( multimesh - > mesh . is_valid ( ) ) {
base_update_dependency ( multimesh - > mesh , p_instance ) ;
}
} else if ( LightStorage : : get_singleton ( ) - > owns_light ( p_base ) ) {
Light * l = LightStorage : : get_singleton ( ) - > get_light ( p_base ) ;
p_instance - > update_dependency ( & l - > dependency ) ;
2022-11-08 06:40:03 +00:00
} else if ( ParticlesStorage : : get_singleton ( ) - > owns_particles ( p_base ) ) {
Dependency * dependency = ParticlesStorage : : get_singleton ( ) - > particles_get_dependency ( p_base ) ;
p_instance - > update_dependency ( dependency ) ;
} else if ( ParticlesStorage : : get_singleton ( ) - > owns_particles_collision ( p_base ) ) {
Dependency * dependency = ParticlesStorage : : get_singleton ( ) - > particles_collision_get_dependency ( p_base ) ;
p_instance - > update_dependency ( dependency ) ;
2022-06-21 00:08:33 +00:00
}
}
/* VISIBILITY NOTIFIER */
RID Utilities : : visibility_notifier_allocate ( ) {
return RID ( ) ;
}
void Utilities : : visibility_notifier_initialize ( RID p_notifier ) {
}
void Utilities : : visibility_notifier_free ( RID p_notifier ) {
}
void Utilities : : visibility_notifier_set_aabb ( RID p_notifier , const AABB & p_aabb ) {
}
void Utilities : : visibility_notifier_set_callbacks ( RID p_notifier , const Callable & p_enter_callbable , const Callable & p_exit_callable ) {
}
AABB Utilities : : visibility_notifier_get_aabb ( RID p_notifier ) const {
return AABB ( ) ;
}
void Utilities : : visibility_notifier_call ( RID p_notifier , bool p_enter , bool p_deferred ) {
}
/* TIMING */
2022-10-07 04:24:38 +00:00
void Utilities : : capture_timestamps_begin ( ) {
capture_timestamp ( " Frame Begin " ) ;
}
void Utilities : : capture_timestamp ( const String & p_name ) {
ERR_FAIL_COND ( frames [ frame ] . timestamp_count > = max_timestamp_query_elements ) ;
2021-11-12 12:49:49 +00:00
# ifdef GL_API_ENABLED
if ( RasterizerGLES3 : : is_gles_over_gl ( ) ) {
glQueryCounter ( frames [ frame ] . queries [ frames [ frame ] . timestamp_count ] , GL_TIMESTAMP ) ;
}
# endif // GL_API_ENABLED
2022-10-07 04:24:38 +00:00
frames [ frame ] . timestamp_names [ frames [ frame ] . timestamp_count ] = p_name ;
frames [ frame ] . timestamp_cpu_values [ frames [ frame ] . timestamp_count ] = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
frames [ frame ] . timestamp_count + + ;
}
void Utilities : : _capture_timestamps_begin ( ) {
// frame is incremented at the end of the frame so this gives us the queries for frame - 2. By then they should be ready.
if ( frames [ frame ] . timestamp_count ) {
2021-11-12 12:49:49 +00:00
# ifdef GL_API_ENABLED
if ( RasterizerGLES3 : : is_gles_over_gl ( ) ) {
for ( uint32_t i = 0 ; i < frames [ frame ] . timestamp_count ; i + + ) {
uint64_t temp = 0 ;
glGetQueryObjectui64v ( frames [ frame ] . queries [ i ] , GL_QUERY_RESULT , & temp ) ;
frames [ frame ] . timestamp_result_values [ i ] = temp ;
}
2022-10-07 04:24:38 +00:00
}
2021-11-12 12:49:49 +00:00
# endif // GL_API_ENABLED
2022-10-07 04:24:38 +00:00
SWAP ( frames [ frame ] . timestamp_names , frames [ frame ] . timestamp_result_names ) ;
SWAP ( frames [ frame ] . timestamp_cpu_values , frames [ frame ] . timestamp_cpu_result_values ) ;
}
frames [ frame ] . timestamp_result_count = frames [ frame ] . timestamp_count ;
frames [ frame ] . timestamp_count = 0 ;
frames [ frame ] . index = Engine : : get_singleton ( ) - > get_frames_drawn ( ) ;
capture_timestamp ( " Internal Begin " ) ;
}
void Utilities : : capture_timestamps_end ( ) {
capture_timestamp ( " Internal End " ) ;
frame = ( frame + 1 ) % FRAME_COUNT ;
}
uint32_t Utilities : : get_captured_timestamps_count ( ) const {
return frames [ frame ] . timestamp_result_count ;
}
uint64_t Utilities : : get_captured_timestamps_frame ( ) const {
return frames [ frame ] . index ;
}
uint64_t Utilities : : get_captured_timestamp_gpu_time ( uint32_t p_index ) const {
ERR_FAIL_UNSIGNED_INDEX_V ( p_index , frames [ frame ] . timestamp_result_count , 0 ) ;
return frames [ frame ] . timestamp_result_values [ p_index ] ;
}
uint64_t Utilities : : get_captured_timestamp_cpu_time ( uint32_t p_index ) const {
ERR_FAIL_UNSIGNED_INDEX_V ( p_index , frames [ frame ] . timestamp_result_count , 0 ) ;
return frames [ frame ] . timestamp_cpu_result_values [ p_index ] ;
}
String Utilities : : get_captured_timestamp_name ( uint32_t p_index ) const {
ERR_FAIL_UNSIGNED_INDEX_V ( p_index , frames [ frame ] . timestamp_result_count , String ( ) ) ;
return frames [ frame ] . timestamp_result_names [ p_index ] ;
}
2022-06-21 00:08:33 +00:00
/* MISC */
void Utilities : : update_dirty_resources ( ) {
2022-04-03 16:56:43 +00:00
MaterialStorage : : get_singleton ( ) - > _update_global_shader_uniforms ( ) ;
2022-06-21 00:08:33 +00:00
MaterialStorage : : get_singleton ( ) - > _update_queued_materials ( ) ;
2022-11-25 23:30:36 +00:00
MeshStorage : : get_singleton ( ) - > _update_dirty_skeletons ( ) ;
2022-06-21 00:08:33 +00:00
MeshStorage : : get_singleton ( ) - > _update_dirty_multimeshes ( ) ;
2022-10-13 00:55:01 +00:00
TextureStorage : : get_singleton ( ) - > update_texture_atlas ( ) ;
2022-06-21 00:08:33 +00:00
}
void Utilities : : set_debug_generate_wireframes ( bool p_generate ) {
2023-12-01 18:26:03 +00:00
Config * config = Config : : get_singleton ( ) ;
config - > generate_wireframes = p_generate ;
2022-06-21 00:08:33 +00:00
}
bool Utilities : : has_os_feature ( const String & p_feature ) const {
Config * config = Config : : get_singleton ( ) ;
if ( ! config ) {
return false ;
}
if ( p_feature = = " rgtc " ) {
return config - > rgtc_supported ;
}
if ( p_feature = = " s3tc " ) {
return config - > s3tc_supported ;
}
if ( p_feature = = " bptc " ) {
return config - > bptc_supported ;
}
2023-01-25 11:17:11 +00:00
if ( p_feature = = " astc " ) {
return config - > astc_supported ;
}
2022-06-21 00:08:33 +00:00
if ( p_feature = = " etc " | | p_feature = = " etc2 " ) {
return config - > etc2_supported ;
}
return false ;
}
void Utilities : : update_memory_info ( ) {
}
uint64_t Utilities : : get_rendering_info ( RS : : RenderingInfo p_info ) {
2023-05-27 01:09:39 +00:00
if ( p_info = = RS : : RENDERING_INFO_TEXTURE_MEM_USED ) {
2023-10-26 01:10:38 +00:00
return texture_mem_cache + render_buffer_mem_cache ; // Add render buffer memory to our texture mem.
2023-05-27 01:09:39 +00:00
} else if ( p_info = = RS : : RENDERING_INFO_BUFFER_MEM_USED ) {
return buffer_mem_cache ;
} else if ( p_info = = RS : : RENDERING_INFO_VIDEO_MEM_USED ) {
2023-10-26 01:10:38 +00:00
return texture_mem_cache + buffer_mem_cache + render_buffer_mem_cache ;
2023-05-27 01:09:39 +00:00
}
2022-06-21 00:08:33 +00:00
return 0 ;
}
String Utilities : : get_video_adapter_name ( ) const {
2023-10-30 15:24:31 +00:00
const String rendering_device_name = String : : utf8 ( ( const char * ) glGetString ( GL_RENDERER ) ) ;
2023-06-06 21:29:36 +00:00
// 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.
return rendering_device_name . trim_suffix ( " /PCIe/SSE2 " ) ;
2022-06-21 00:08:33 +00:00
}
String Utilities : : get_video_adapter_vendor ( ) const {
2023-10-30 15:24:31 +00:00
const String rendering_device_vendor = String : : utf8 ( ( const char * ) glGetString ( GL_VENDOR ) ) ;
2023-06-06 21:29:36 +00:00
// NVIDIA suffixes its vendor name with " Corporation". This is neither necessary to process nor display.
return rendering_device_vendor . trim_suffix ( " Corporation " ) ;
2022-06-21 00:08:33 +00:00
}
RenderingDevice : : DeviceType Utilities : : get_video_adapter_type ( ) const {
return RenderingDevice : : DeviceType : : DEVICE_TYPE_OTHER ;
}
String Utilities : : get_video_adapter_api_version ( ) const {
2023-10-30 15:24:31 +00:00
return String : : utf8 ( ( const char * ) glGetString ( GL_VERSION ) ) ;
2022-06-21 00:08:33 +00:00
}
2022-08-21 22:16:56 +00:00
Size2i Utilities : : get_maximum_viewport_size ( ) const {
Config * config = Config : : get_singleton ( ) ;
if ( ! config ) {
return Size2i ( ) ;
}
2022-10-19 00:59:31 +00:00
return Size2i ( config - > max_viewport_size [ 0 ] , config - > max_viewport_size [ 1 ] ) ;
2022-08-21 22:16:56 +00:00
}
2022-06-21 00:08:33 +00:00
# endif // GLES3_ENABLED