2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* rendering_server_default.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. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2020-12-03 22:09:47 +01:00
# include "rendering_server_default.h"
2017-08-27 21:07:15 +02:00
2020-11-07 23:33:38 +01:00
# include "core/config/project_settings.h"
2018-09-11 18:13:45 +02:00
# include "core/io/marshalls.h"
# include "core/os/os.h"
2020-11-07 23:33:38 +01:00
# include "core/templates/sort_array.h"
2020-12-04 19:26:24 +01:00
# include "renderer_canvas_cull.h"
# include "renderer_scene_cull.h"
2020-03-27 19:21:27 +01:00
# include "rendering_server_globals.h"
2016-10-03 21:33:42 +02:00
2021-10-07 15:46:55 +02:00
// careful, these may run in different threads than the rendering server
2014-02-10 02:10:30 +01:00
2020-12-03 22:09:47 +01:00
int RenderingServerDefault : : changes = 0 ;
2017-04-07 04:36:37 +02:00
2016-10-03 21:33:42 +02:00
/* FREE */
2021-02-09 17:19:03 +01:00
void RenderingServerDefault : : _free ( RID p_rid ) {
2021-09-29 10:59:46 +02:00
if ( unlikely ( p_rid . is_null ( ) ) ) {
return ;
}
2022-06-21 02:08:33 +02:00
if ( RSG : : utilities - > free ( p_rid ) ) {
2016-10-03 21:33:42 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
if ( RSG : : canvas - > free ( p_rid ) ) {
2016-10-03 21:33:42 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
if ( RSG : : viewport - > free ( p_rid ) ) {
2016-10-03 21:33:42 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
if ( RSG : : scene - > free ( p_rid ) ) {
2016-10-19 16:14:41 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-10-03 21:33:42 +02:00
}
/* EVENT QUEUING */
2021-11-05 06:59:38 +01:00
void RenderingServerDefault : : request_frame_drawn_callback ( const Callable & p_callable ) {
frame_drawn_callbacks . push_back ( p_callable ) ;
2017-06-09 05:23:50 +02:00
}
2021-02-09 17:19:03 +01:00
void RenderingServerDefault : : _draw ( bool p_swap_buffers , double frame_step ) {
2018-07-16 16:43:26 +02:00
//needs to be done before changes is reset to 0, to not force the editor to redraw
2021-07-17 23:22:52 +02:00
RS : : get_singleton ( ) - > emit_signal ( SNAME ( " frame_pre_draw " ) ) ;
2018-07-07 01:21:13 +02:00
2018-07-16 16:43:26 +02:00
changes = 0 ;
2020-03-27 19:21:27 +01:00
RSG : : rasterizer - > begin_frame ( frame_step ) ;
2016-12-20 04:21:07 +01:00
2019-10-04 01:15:38 +02:00
TIMESTAMP_BEGIN ( )
2019-09-20 22:58:06 +02:00
2020-12-24 04:13:52 +01:00
uint64_t time_usec = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
2020-12-03 22:09:47 +01:00
RSG : : scene - > update ( ) ; //update scenes stuff before updating instances
2019-08-26 22:43:58 +02:00
2020-12-24 04:13:52 +01:00
frame_setup_time = double ( OS : : get_singleton ( ) - > get_ticks_usec ( ) - time_usec ) / 1000.0 ;
2022-04-12 13:41:50 +02:00
RSG : : particles_storage - > update_particles ( ) ; //need to be done after instances are updated (colliders and particle transforms), and colliders are rendered
2020-10-08 02:29:49 +02:00
2020-03-27 19:21:27 +01:00
RSG : : scene - > render_probes ( ) ;
2020-12-24 04:13:52 +01:00
2020-03-27 19:21:27 +01:00
RSG : : viewport - > draw_viewports ( ) ;
RSG : : canvas_render - > update ( ) ;
2019-06-16 04:45:24 +02:00
2022-09-12 23:57:11 +02:00
if ( OS : : get_singleton ( ) - > get_current_rendering_driver_name ( ) ! = " opengl3 " ) {
// Already called for gl_compatibility renderer.
RSG : : rasterizer - > end_frame ( p_swap_buffers ) ;
}
2017-06-09 05:23:50 +02:00
2022-01-26 02:25:20 +01:00
XRServer * xr_server = XRServer : : get_singleton ( ) ;
if ( xr_server ! = nullptr ) {
// let our XR server know we're done so we can get our frame timing
xr_server - > end_frame ( ) ;
}
2021-06-15 22:33:24 +02:00
RSG : : canvas - > update_visibility_notifiers ( ) ;
2021-06-16 20:43:02 +02:00
RSG : : scene - > update_visibility_notifiers ( ) ;
2021-06-15 22:33:24 +02:00
2017-06-09 05:23:50 +02:00
while ( frame_drawn_callbacks . front ( ) ) {
2021-11-05 06:59:38 +01:00
Callable c = frame_drawn_callbacks . front ( ) - > get ( ) ;
Variant result ;
Callable : : CallError ce ;
2022-07-28 22:56:41 +02:00
c . callp ( nullptr , 0 , result , ce ) ;
2021-11-05 06:59:38 +01:00
if ( ce . error ! = Callable : : CallError : : CALL_OK ) {
String err = Variant : : get_callable_error_text ( c , nullptr , 0 , ce ) ;
ERR_PRINT ( " Error calling frame drawn function: " + err ) ;
2017-06-09 05:23:50 +02:00
}
frame_drawn_callbacks . pop_front ( ) ;
}
2021-07-17 23:22:52 +02:00
RS : : get_singleton ( ) - > emit_signal ( SNAME ( " frame_post_draw " ) ) ;
2019-09-20 22:58:06 +02:00
2022-06-21 02:08:33 +02:00
if ( RSG : : utilities - > get_captured_timestamps_count ( ) ) {
2019-09-20 22:58:06 +02:00
Vector < FrameProfileArea > new_profile ;
2022-06-21 02:08:33 +02:00
if ( RSG : : utilities - > capturing_timestamps ) {
new_profile . resize ( RSG : : utilities - > get_captured_timestamps_count ( ) ) ;
2020-04-10 19:18:42 +02:00
}
2019-09-20 22:58:06 +02:00
2022-06-21 02:08:33 +02:00
uint64_t base_cpu = RSG : : utilities - > get_captured_timestamp_cpu_time ( 0 ) ;
uint64_t base_gpu = RSG : : utilities - > get_captured_timestamp_gpu_time ( 0 ) ;
for ( uint32_t i = 0 ; i < RSG : : utilities - > get_captured_timestamps_count ( ) ; i + + ) {
uint64_t time_cpu = RSG : : utilities - > get_captured_timestamp_cpu_time ( i ) ;
uint64_t time_gpu = RSG : : utilities - > get_captured_timestamp_gpu_time ( i ) ;
2020-04-10 19:18:42 +02:00
2022-06-21 02:08:33 +02:00
String name = RSG : : utilities - > get_captured_timestamp_name ( i ) ;
2020-04-10 19:18:42 +02:00
if ( name . begins_with ( " vp_ " ) ) {
RSG : : viewport - > handle_timestamp ( name , time_cpu , time_gpu ) ;
}
2022-06-21 02:08:33 +02:00
if ( RSG : : utilities - > capturing_timestamps ) {
2021-02-02 03:16:37 +01:00
new_profile . write [ i ] . gpu_msec = double ( ( time_gpu - base_gpu ) / 1000 ) / 1000.0 ;
new_profile . write [ i ] . cpu_msec = double ( time_cpu - base_cpu ) / 1000.0 ;
2022-06-21 02:08:33 +02:00
new_profile . write [ i ] . name = RSG : : utilities - > get_captured_timestamp_name ( i ) ;
2020-04-10 19:18:42 +02:00
}
2019-09-20 22:58:06 +02:00
}
frame_profile = new_profile ;
}
2022-06-21 02:08:33 +02:00
frame_profile_frame = RSG : : utilities - > get_captured_timestamps_frame ( ) ;
2021-01-23 00:50:24 +01:00
if ( print_gpu_profile ) {
if ( print_frame_profile_ticks_from = = 0 ) {
print_frame_profile_ticks_from = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
}
2021-02-02 03:16:37 +01:00
double total_time = 0.0 ;
2021-01-23 00:50:24 +01:00
for ( int i = 0 ; i < frame_profile . size ( ) - 1 ; i + + ) {
String name = frame_profile [ i ] . name ;
if ( name [ 0 ] = = ' < ' | | name [ 0 ] = = ' > ' ) {
continue ;
}
2021-02-02 03:16:37 +01:00
double time = frame_profile [ i + 1 ] . gpu_msec - frame_profile [ i ] . gpu_msec ;
2021-01-23 00:50:24 +01:00
if ( name [ 0 ] ! = ' < ' & & name [ 0 ] ! = ' > ' ) {
if ( print_gpu_profile_task_time . has ( name ) ) {
print_gpu_profile_task_time [ name ] + = time ;
} else {
print_gpu_profile_task_time [ name ] = time ;
}
}
}
if ( frame_profile . size ( ) ) {
total_time = frame_profile [ frame_profile . size ( ) - 1 ] . gpu_msec ;
}
uint64_t ticks_elapsed = OS : : get_singleton ( ) - > get_ticks_usec ( ) - print_frame_profile_ticks_from ;
print_frame_profile_frame_count + + ;
if ( ticks_elapsed > 1000000 ) {
print_line ( " GPU PROFILE (total " + rtos ( total_time ) + " ms): " ) ;
float print_threshold = 0.01 ;
2022-05-08 10:09:19 +02:00
for ( const KeyValue < String , float > & E : print_gpu_profile_task_time ) {
double time = E . value / double ( print_frame_profile_frame_count ) ;
2021-01-23 00:50:24 +01:00
if ( time > print_threshold ) {
2022-05-08 10:09:19 +02:00
print_line ( " \t - " + E . key + " : " + rtos ( time ) + " ms " ) ;
2021-01-23 00:50:24 +01:00
}
}
print_gpu_profile_task_time . clear ( ) ;
print_frame_profile_ticks_from = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
print_frame_profile_frame_count = 0 ;
}
}
2021-07-03 01:14:19 +02:00
2022-06-21 02:08:33 +02:00
RSG : : utilities - > update_memory_info ( ) ;
2016-10-03 21:33:42 +02:00
}
2020-05-14 14:29:06 +02:00
2021-02-02 03:16:37 +01:00
double RenderingServerDefault : : get_frame_setup_time_cpu ( ) const {
2020-12-24 04:13:52 +01:00
return frame_setup_time ;
}
2020-12-03 22:09:47 +01:00
bool RenderingServerDefault : : has_changed ( ) const {
2016-10-04 04:46:24 +02:00
return changes > 0 ;
2016-10-03 21:33:42 +02:00
}
2020-05-14 14:29:06 +02:00
2021-02-09 17:19:03 +01:00
void RenderingServerDefault : : _init ( ) {
2020-03-27 19:21:27 +01:00
RSG : : rasterizer - > initialize ( ) ;
2016-10-03 21:33:42 +02:00
}
2020-05-14 14:29:06 +02:00
2021-02-09 17:19:03 +01:00
void RenderingServerDefault : : _finish ( ) {
2016-10-03 21:33:42 +02:00
if ( test_cube . is_valid ( ) ) {
free ( test_cube ) ;
}
2020-03-27 19:21:27 +01:00
RSG : : rasterizer - > finalize ( ) ;
2016-10-03 21:33:42 +02:00
}
2021-02-09 17:19:03 +01:00
void RenderingServerDefault : : init ( ) {
if ( create_thread ) {
print_verbose ( " RenderingServerWrapMT: Creating render thread " ) ;
DisplayServer : : get_singleton ( ) - > release_rendering_thread ( ) ;
if ( create_thread ) {
thread . start ( _thread_callback , this ) ;
print_verbose ( " RenderingServerWrapMT: Starting render thread " ) ;
}
2021-02-10 19:22:13 +01:00
while ( ! draw_thread_up . is_set ( ) ) {
2021-02-09 17:19:03 +01:00
OS : : get_singleton ( ) - > delay_usec ( 1000 ) ;
}
print_verbose ( " RenderingServerWrapMT: Finished render thread " ) ;
} else {
_init ( ) ;
}
}
void RenderingServerDefault : : finish ( ) {
if ( create_thread ) {
command_queue . push ( this , & RenderingServerDefault : : _thread_exit ) ;
2023-04-27 18:34:30 +02:00
if ( thread . is_started ( ) ) {
thread . wait_to_finish ( ) ;
}
2021-02-09 17:19:03 +01:00
} else {
_finish ( ) ;
}
}
2016-10-03 21:33:42 +02:00
/* STATUS INFORMATION */
2021-07-03 01:14:19 +02:00
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 ) {
2023-05-27 03:09:39 +02:00
return RSG : : viewport - > get_total_primitives_drawn ( ) ;
2021-07-03 01:14:19 +02:00
} else if ( p_info = = RENDERING_INFO_TOTAL_DRAW_CALLS_IN_FRAME ) {
return RSG : : viewport - > get_total_draw_calls_used ( ) ;
}
2022-06-21 02:08:33 +02:00
return RSG : : utilities - > get_rendering_info ( p_info ) ;
2016-10-03 21:33:42 +02:00
}
2021-12-10 17:01:51 +01:00
RenderingDevice : : DeviceType RenderingServerDefault : : get_video_adapter_type ( ) const {
2022-06-21 02:08:33 +02:00
return RSG : : utilities - > get_video_adapter_type ( ) ;
2021-12-10 17:01:51 +01:00
}
2020-12-03 22:09:47 +01:00
void RenderingServerDefault : : set_frame_profiling_enabled ( bool p_enable ) {
2022-06-21 02:08:33 +02:00
RSG : : utilities - > capturing_timestamps = p_enable ;
2019-09-20 22:58:06 +02:00
}
2020-12-03 22:09:47 +01:00
uint64_t RenderingServerDefault : : get_frame_profile_frame ( ) {
2019-09-20 22:58:06 +02:00
return frame_profile_frame ;
}
2020-12-03 22:09:47 +01:00
Vector < RenderingServer : : FrameProfileArea > RenderingServerDefault : : get_frame_profile ( ) {
2019-09-20 22:58:06 +02:00
return frame_profile ;
}
2016-10-03 21:33:42 +02:00
/* TESTING */
2022-01-19 16:09:52 +01:00
void RenderingServerDefault : : set_boot_image ( const Ref < Image > & p_image , const Color & p_color , bool p_scale , bool p_use_filter ) {
2017-04-10 01:40:48 +02:00
redraw_request ( ) ;
2022-01-19 16:09:52 +01:00
RSG : : rasterizer - > set_boot_image ( p_image , p_color , p_scale , p_use_filter ) ;
2016-10-03 21:33:42 +02:00
}
2020-05-14 14:29:06 +02:00
2023-01-11 19:14:43 +01:00
Color RenderingServerDefault : : get_default_clear_color ( ) {
return RSG : : texture_storage - > get_default_clear_color ( ) ;
}
2020-12-03 22:09:47 +01:00
void RenderingServerDefault : : set_default_clear_color ( const Color & p_color ) {
2020-03-27 19:21:27 +01:00
RSG : : viewport - > set_default_clear_color ( p_color ) ;
2016-10-03 21:33:42 +02:00
}
2020-12-03 22:09:47 +01:00
bool RenderingServerDefault : : has_feature ( Features p_feature ) const {
2016-10-03 21:33:42 +02:00
return false ;
}
2020-12-03 22:09:47 +01:00
void RenderingServerDefault : : sdfgi_set_debug_probe_select ( const Vector3 & p_position , const Vector3 & p_dir ) {
RSG : : scene - > sdfgi_set_debug_probe_select ( p_position , p_dir ) ;
2020-06-25 15:33:28 +02:00
}
2021-01-23 00:50:24 +01:00
void RenderingServerDefault : : set_print_gpu_profile ( bool p_enable ) {
2022-06-21 02:08:33 +02:00
RSG : : utilities - > capturing_timestamps = p_enable ;
2021-01-23 00:50:24 +01:00
print_gpu_profile = p_enable ;
}
2020-12-03 22:09:47 +01:00
RID RenderingServerDefault : : get_test_cube ( ) {
2016-10-03 21:33:42 +02:00
if ( ! test_cube . is_valid ( ) ) {
test_cube = _make_test_cube ( ) ;
}
return test_cube ;
}
2020-12-03 22:09:47 +01:00
bool RenderingServerDefault : : has_os_feature ( const String & p_feature ) const {
2022-06-21 02:08:33 +02:00
if ( RSG : : utilities ) {
return RSG : : utilities - > has_os_feature ( p_feature ) ;
2022-05-28 13:09:23 +02:00
} else {
return false ;
}
2017-02-06 04:38:39 +01:00
}
2020-12-03 22:09:47 +01:00
void RenderingServerDefault : : set_debug_generate_wireframes ( bool p_generate ) {
2022-06-21 02:08:33 +02:00
RSG : : utilities - > set_debug_generate_wireframes ( p_generate ) ;
2017-06-11 20:52:03 +02:00
}
2020-12-03 22:09:47 +01:00
bool RenderingServerDefault : : is_low_end ( ) const {
2022-04-30 00:34:01 +02:00
return RendererCompositor : : is_low_end ( ) ;
2018-09-29 01:32:40 +02:00
}
2020-05-14 14:29:06 +02:00
2022-08-22 00:16:56 +02:00
Size2i RenderingServerDefault : : get_maximum_viewport_size ( ) const {
if ( RSG : : utilities ) {
return RSG : : utilities - > get_maximum_viewport_size ( ) ;
} else {
return Size2i ( ) ;
}
}
2021-02-09 17:19:03 +01:00
void RenderingServerDefault : : _thread_exit ( ) {
2021-02-10 19:22:13 +01:00
exit . set ( ) ;
2021-02-09 17:19:03 +01:00
}
void RenderingServerDefault : : _thread_draw ( bool p_swap_buffers , double frame_step ) {
2020-01-30 22:22:36 +01:00
_draw ( p_swap_buffers , frame_step ) ;
2021-02-09 17:19:03 +01:00
}
void RenderingServerDefault : : _thread_flush ( ) {
}
void RenderingServerDefault : : _thread_callback ( void * _instance ) {
RenderingServerDefault * vsmt = reinterpret_cast < RenderingServerDefault * > ( _instance ) ;
vsmt - > _thread_loop ( ) ;
}
void RenderingServerDefault : : _thread_loop ( ) {
server_thread = Thread : : get_caller_id ( ) ;
DisplayServer : : get_singleton ( ) - > make_rendering_thread ( ) ;
_init ( ) ;
2021-02-10 19:22:13 +01:00
draw_thread_up . set ( ) ;
while ( ! exit . is_set ( ) ) {
2021-02-09 17:19:03 +01:00
// flush commands one by one, until exit is requested
2021-06-09 17:09:31 +02:00
command_queue . wait_and_flush ( ) ;
2021-02-09 17:19:03 +01:00
}
command_queue . flush_all ( ) ; // flush all
_finish ( ) ;
}
/* EVENT QUEUING */
void RenderingServerDefault : : sync ( ) {
if ( create_thread ) {
command_queue . push_and_sync ( this , & RenderingServerDefault : : _thread_flush ) ;
} else {
command_queue . flush_all ( ) ; //flush all pending from other threads
}
}
void RenderingServerDefault : : draw ( bool p_swap_buffers , double frame_step ) {
if ( create_thread ) {
command_queue . push ( this , & RenderingServerDefault : : _thread_draw , p_swap_buffers , frame_step ) ;
} else {
_draw ( p_swap_buffers , frame_step ) ;
}
}
RenderingServerDefault : : RenderingServerDefault ( bool p_create_thread ) :
command_queue ( p_create_thread ) {
2022-05-28 13:09:23 +02:00
RenderingServer : : init ( ) ;
2021-02-09 17:19:03 +01:00
create_thread = p_create_thread ;
if ( ! p_create_thread ) {
server_thread = Thread : : get_caller_id ( ) ;
} else {
server_thread = 0 ;
}
2021-06-15 22:33:24 +02:00
RSG : : threaded = p_create_thread ;
2020-12-04 19:26:24 +01:00
RSG : : canvas = memnew ( RendererCanvasCull ) ;
RSG : : viewport = memnew ( RendererViewport ) ;
RendererSceneCull * sr = memnew ( RendererSceneCull ) ;
2022-08-01 01:20:24 +02:00
RSG : : camera_attributes = memnew ( RendererCameraAttributes ) ;
2020-12-03 22:09:47 +01:00
RSG : : scene = sr ;
2020-12-04 19:26:24 +01:00
RSG : : rasterizer = RendererCompositor : : create ( ) ;
2022-06-21 02:08:33 +02:00
RSG : : utilities = RSG : : rasterizer - > get_utilities ( ) ;
2022-04-09 11:34:31 +02:00
RSG : : light_storage = RSG : : rasterizer - > get_light_storage ( ) ;
2022-03-21 12:25:25 +01:00
RSG : : material_storage = RSG : : rasterizer - > get_material_storage ( ) ;
2022-04-02 07:29:04 +02:00
RSG : : mesh_storage = RSG : : rasterizer - > get_mesh_storage ( ) ;
2022-04-12 13:41:50 +02:00
RSG : : particles_storage = RSG : : rasterizer - > get_particles_storage ( ) ;
2022-03-12 12:19:59 +01:00
RSG : : texture_storage = RSG : : rasterizer - > get_texture_storage ( ) ;
2022-05-20 04:52:19 +02:00
RSG : : gi = RSG : : rasterizer - > get_gi ( ) ;
2022-06-21 02:08:33 +02:00
RSG : : fog = RSG : : rasterizer - > get_fog ( ) ;
2020-03-27 19:21:27 +01:00
RSG : : canvas_render = RSG : : rasterizer - > get_canvas ( ) ;
2020-12-31 13:42:56 +01:00
sr - > set_scene_render ( RSG : : rasterizer - > get_scene ( ) ) ;
2017-08-07 23:06:57 +02:00
2019-09-20 22:58:06 +02:00
frame_profile_frame = 0 ;
2016-10-03 21:33:42 +02:00
}
2020-12-03 22:09:47 +01:00
RenderingServerDefault : : ~ RenderingServerDefault ( ) {
2020-03-27 19:21:27 +01:00
memdelete ( RSG : : canvas ) ;
memdelete ( RSG : : viewport ) ;
memdelete ( RSG : : rasterizer ) ;
memdelete ( RSG : : scene ) ;
2022-08-01 01:20:24 +02:00
memdelete ( RSG : : camera_attributes ) ;
2016-10-03 21:33:42 +02:00
}