Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/os/os.cpp
20791 views
1
/**************************************************************************/
2
/* os.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
#include "os.h"
32
33
#include "core/config/project_settings.h"
34
#include "core/io/dir_access.h"
35
#include "core/io/file_access.h"
36
#include "core/io/json.h"
37
#include "core/os/midi_driver.h"
38
#include "core/version_generated.gen.h"
39
40
#include <cstdarg>
41
42
#ifdef MINGW_ENABLED
43
#define MINGW_STDTHREAD_REDUNDANCY_WARNING
44
#include "thirdparty/mingw-std-threads/mingw.thread.h"
45
#define THREADING_NAMESPACE mingw_stdthread
46
#else
47
#include <thread>
48
#define THREADING_NAMESPACE std
49
#endif
50
51
OS *OS::singleton = nullptr;
52
uint64_t OS::target_ticks = 0;
53
54
OS *OS::get_singleton() {
55
return singleton;
56
}
57
58
bool OS::prefer_meta_over_ctrl() {
59
#if defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
60
return true;
61
#elif defined(WEB_ENABLED)
62
return singleton->has_feature("web_macos") || singleton->has_feature("web_ios");
63
#else
64
return false;
65
#endif
66
}
67
68
uint64_t OS::get_ticks_msec() const {
69
return get_ticks_usec() / 1000ULL;
70
}
71
72
double OS::get_unix_time() const {
73
return 0;
74
}
75
76
void OS::_set_logger(CompositeLogger *p_logger) {
77
if (_logger) {
78
memdelete(_logger);
79
}
80
_logger = p_logger;
81
}
82
83
void OS::add_logger(Logger *p_logger) {
84
if (!_logger) {
85
Vector<Logger *> loggers;
86
loggers.push_back(p_logger);
87
_logger = memnew(CompositeLogger(loggers));
88
} else {
89
_logger->add_logger(p_logger);
90
}
91
}
92
93
String OS::get_identifier() const {
94
return get_name().to_lower();
95
}
96
97
void OS::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, Logger::ErrorType p_type, const Vector<Ref<ScriptBacktrace>> &p_script_backtraces) {
98
if (!_stderr_enabled) {
99
return;
100
}
101
102
if (_logger) {
103
_logger->log_error(p_function, p_file, p_line, p_code, p_rationale, p_editor_notify, p_type, p_script_backtraces);
104
}
105
}
106
107
void OS::print(const char *p_format, ...) {
108
if (!_stdout_enabled) {
109
return;
110
}
111
112
va_list argp;
113
va_start(argp, p_format);
114
115
if (_logger) {
116
_logger->logv(p_format, argp, false);
117
}
118
119
va_end(argp);
120
}
121
122
void OS::print_rich(const char *p_format, ...) {
123
if (!_stdout_enabled) {
124
return;
125
}
126
127
va_list argp;
128
va_start(argp, p_format);
129
130
if (_logger) {
131
_logger->logv(p_format, argp, false);
132
}
133
134
va_end(argp);
135
}
136
137
void OS::printerr(const char *p_format, ...) {
138
if (!_stderr_enabled) {
139
return;
140
}
141
142
va_list argp;
143
va_start(argp, p_format);
144
145
if (_logger) {
146
_logger->logv(p_format, argp, true);
147
}
148
149
va_end(argp);
150
}
151
152
void OS::alert(const String &p_alert, const String &p_title) {
153
fprintf(stderr, "%s: %s\n", p_title.utf8().get_data(), p_alert.utf8().get_data());
154
}
155
156
void OS::set_low_processor_usage_mode(bool p_enabled) {
157
low_processor_usage_mode = p_enabled;
158
}
159
160
bool OS::is_in_low_processor_usage_mode() const {
161
return low_processor_usage_mode;
162
}
163
164
void OS::set_low_processor_usage_mode_sleep_usec(int p_usec) {
165
low_processor_usage_mode_sleep_usec = p_usec;
166
}
167
168
int OS::get_low_processor_usage_mode_sleep_usec() const {
169
return low_processor_usage_mode_sleep_usec;
170
}
171
172
void OS::set_delta_smoothing(bool p_enabled) {
173
_delta_smoothing_enabled = p_enabled;
174
}
175
176
bool OS::is_delta_smoothing_enabled() const {
177
return _delta_smoothing_enabled;
178
}
179
180
String OS::get_executable_path() const {
181
return _execpath;
182
}
183
184
int OS::get_process_id() const {
185
return -1;
186
}
187
188
bool OS::is_stdout_verbose() const {
189
return _verbose_stdout;
190
}
191
192
bool OS::is_stdout_debug_enabled() const {
193
return _debug_stdout;
194
}
195
196
bool OS::is_stdout_enabled() const {
197
return _stdout_enabled;
198
}
199
200
bool OS::is_stderr_enabled() const {
201
return _stderr_enabled;
202
}
203
204
void OS::set_stdout_enabled(bool p_enabled) {
205
_stdout_enabled = p_enabled;
206
}
207
208
void OS::set_stderr_enabled(bool p_enabled) {
209
_stderr_enabled = p_enabled;
210
}
211
212
String OS::multibyte_to_string(const String &p_encoding, const PackedByteArray &p_array) const {
213
return String();
214
}
215
216
PackedByteArray OS::string_to_multibyte(const String &p_encoding, const String &p_string) const {
217
return PackedByteArray();
218
}
219
220
int OS::get_exit_code() const {
221
return _exit_code;
222
}
223
224
void OS::set_exit_code(int p_code) {
225
_exit_code = p_code;
226
}
227
228
String OS::get_locale() const {
229
return "en";
230
}
231
232
// Non-virtual helper to extract the 2 or 3-letter language code from
233
// `get_locale()` in a way that's consistent for all platforms.
234
String OS::get_locale_language() const {
235
return get_locale().left(3).remove_char('_');
236
}
237
238
// Embedded PCK offset.
239
uint64_t OS::get_embedded_pck_offset() const {
240
return 0;
241
}
242
243
// Default boot screen rect scale mode is "Keep Aspect Centered"
244
Rect2 OS::calculate_boot_screen_rect(const Size2 &p_window_size, const Size2 &p_imgrect_size) const {
245
Rect2 screenrect;
246
if (p_window_size.width > p_window_size.height) {
247
// Scale horizontally.
248
screenrect.size.y = p_window_size.height;
249
screenrect.size.x = p_imgrect_size.x * p_window_size.height / p_imgrect_size.y;
250
screenrect.position.x = (p_window_size.width - screenrect.size.x) / 2;
251
} else {
252
// Scale vertically.
253
screenrect.size.x = p_window_size.width;
254
screenrect.size.y = p_imgrect_size.y * p_window_size.width / p_imgrect_size.x;
255
screenrect.position.y = (p_window_size.height - screenrect.size.y) / 2;
256
}
257
return screenrect;
258
}
259
260
// Helper function to ensure that a dir name/path will be valid on the OS
261
String OS::get_safe_dir_name(const String &p_dir_name, bool p_allow_paths) const {
262
String safe_dir_name = p_dir_name;
263
Vector<String> invalid_chars = String(": * ? \" < > |").split(" ");
264
if (p_allow_paths) {
265
// Dir separators are allowed, but disallow ".." to avoid going up the filesystem
266
invalid_chars.push_back("..");
267
safe_dir_name = safe_dir_name.replace_char('\\', '/').replace("//", "/").strip_edges();
268
} else {
269
invalid_chars.push_back("/");
270
invalid_chars.push_back("\\");
271
safe_dir_name = safe_dir_name.strip_edges();
272
273
// These directory names are invalid.
274
if (safe_dir_name == ".") {
275
safe_dir_name = "dot";
276
} else if (safe_dir_name == "..") {
277
safe_dir_name = "twodots";
278
}
279
}
280
281
for (int i = 0; i < invalid_chars.size(); i++) {
282
safe_dir_name = safe_dir_name.replace(invalid_chars[i], "-");
283
}
284
285
// Trim trailing periods from the returned value as it's not valid for folder names on Windows.
286
// This check is still applied on non-Windows platforms so the returned value is consistent across platforms.
287
return safe_dir_name.rstrip(".");
288
}
289
290
// Path to data, config, cache, etc. OS-specific folders
291
292
// Get properly capitalized engine name for system paths
293
String OS::get_godot_dir_name() const {
294
// Default to lowercase, so only override when different case is needed
295
return String(GODOT_VERSION_SHORT_NAME).to_lower();
296
}
297
298
// OS equivalent of XDG_DATA_HOME
299
String OS::get_data_path() const {
300
return ".";
301
}
302
303
// OS equivalent of XDG_CONFIG_HOME
304
String OS::get_config_path() const {
305
return ".";
306
}
307
308
// OS equivalent of XDG_CACHE_HOME
309
String OS::get_cache_path() const {
310
return ".";
311
}
312
313
String OS::get_temp_path() const {
314
return ".";
315
}
316
317
// Path to macOS .app bundle resources
318
String OS::get_bundle_resource_dir() const {
319
return ".";
320
}
321
322
// Path to macOS .app bundle embedded icon (.icns file).
323
String OS::get_bundle_icon_path() const {
324
return String();
325
}
326
327
// Name of macOS .app bundle embedded icon (Liquid Glass asset name).
328
String OS::get_bundle_icon_name() const {
329
return String();
330
}
331
332
// OS specific path for user://
333
String OS::get_user_data_dir(const String &p_user_dir) const {
334
return ".";
335
}
336
337
String OS::get_user_data_dir() const {
338
String appname = get_safe_dir_name(GLOBAL_GET("application/config/name"));
339
if (!appname.is_empty()) {
340
bool use_custom_dir = GLOBAL_GET("application/config/use_custom_user_dir");
341
if (use_custom_dir) {
342
String custom_dir = get_safe_dir_name(GLOBAL_GET("application/config/custom_user_dir_name"), true);
343
if (custom_dir.is_empty()) {
344
custom_dir = appname;
345
}
346
return get_user_data_dir(custom_dir);
347
} else {
348
return get_user_data_dir(get_godot_dir_name().path_join("app_userdata").path_join(appname));
349
}
350
} else {
351
return get_user_data_dir(get_godot_dir_name().path_join("app_userdata").path_join("[unnamed project]"));
352
}
353
}
354
355
// Absolute path to res://
356
String OS::get_resource_dir() const {
357
return ProjectSettings::get_singleton()->get_resource_path();
358
}
359
360
// Access system-specific dirs like Documents, Downloads, etc.
361
String OS::get_system_dir(SystemDir p_dir, bool p_shared_storage) const {
362
return ".";
363
}
364
365
void OS::create_lock_file() {
366
if (Engine::get_singleton()->is_recovery_mode_hint()) {
367
return;
368
}
369
370
String lock_file_path = get_user_data_dir().path_join(".recovery_mode_lock");
371
Ref<FileAccess> lock_file = FileAccess::open(lock_file_path, FileAccess::WRITE);
372
if (lock_file.is_valid()) {
373
lock_file->close();
374
}
375
}
376
377
void OS::remove_lock_file() {
378
String lock_file_path = get_user_data_dir().path_join(".recovery_mode_lock");
379
DirAccess::remove_absolute(lock_file_path);
380
}
381
382
Error OS::shell_open(const String &p_uri) {
383
return ERR_UNAVAILABLE;
384
}
385
386
Error OS::shell_show_in_file_manager(String p_path, bool p_open_folder) {
387
p_path = p_path.trim_prefix("file://");
388
389
if (!DirAccess::dir_exists_absolute(p_path)) {
390
p_path = p_path.get_base_dir();
391
}
392
393
p_path = String("file://") + p_path;
394
395
return shell_open(p_path);
396
}
397
// implement these with the canvas?
398
399
uint64_t OS::get_static_memory_usage() const {
400
return Memory::get_mem_usage();
401
}
402
403
uint64_t OS::get_static_memory_peak_usage() const {
404
return Memory::get_mem_max_usage();
405
}
406
407
Error OS::set_cwd(const String &p_cwd) {
408
return ERR_CANT_OPEN;
409
}
410
411
String OS::get_cwd() const {
412
return ".";
413
}
414
415
Dictionary OS::get_memory_info() const {
416
Dictionary meminfo;
417
418
meminfo["physical"] = -1;
419
meminfo["free"] = -1;
420
meminfo["available"] = -1;
421
meminfo["stack"] = -1;
422
423
return meminfo;
424
}
425
426
void OS::yield() {
427
}
428
429
void OS::ensure_user_data_dir() {
430
String dd = get_user_data_dir();
431
if (DirAccess::exists(dd)) {
432
return;
433
}
434
435
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
436
Error err = da->make_dir_recursive(dd);
437
ERR_FAIL_COND_MSG(err != OK, vformat("Error attempting to create data dir: %s.", dd));
438
}
439
440
String OS::get_model_name() const {
441
return "GenericDevice";
442
}
443
444
void OS::set_cmdline(const char *p_execpath, const List<String> &p_args, const List<String> &p_user_args) {
445
_execpath = String::utf8(p_execpath);
446
_cmdline = p_args;
447
_user_args = p_user_args;
448
}
449
450
String OS::get_unique_id() const {
451
return "";
452
}
453
454
int OS::get_processor_count() const {
455
return THREADING_NAMESPACE::thread::hardware_concurrency();
456
}
457
458
String OS::get_processor_name() const {
459
return "";
460
}
461
462
void OS::set_has_server_feature_callback(HasServerFeatureCallback p_callback) {
463
has_server_feature_callback = p_callback;
464
}
465
466
bool OS::has_feature(const String &p_feature) {
467
// Feature tags are always lowercase for consistency.
468
if (p_feature == get_identifier()) {
469
return true;
470
}
471
472
if (p_feature == "movie") {
473
return _writing_movie;
474
}
475
476
#ifdef DEBUG_ENABLED
477
if (p_feature == "debug") {
478
return true;
479
}
480
#endif // DEBUG_ENABLED
481
482
#ifdef TOOLS_ENABLED
483
if (p_feature == "editor") {
484
return true;
485
}
486
if (p_feature == "editor_hint") {
487
return _in_editor;
488
} else if (p_feature == "editor_runtime") {
489
return !_in_editor;
490
} else if (p_feature == "embedded_in_editor") {
491
return _embedded_in_editor;
492
}
493
#else
494
if (p_feature == "template") {
495
return true;
496
}
497
#ifdef DEBUG_ENABLED
498
if (p_feature == "template_debug") {
499
return true;
500
}
501
#else
502
if (p_feature == "template_release" || p_feature == "release") {
503
return true;
504
}
505
#endif // DEBUG_ENABLED
506
#endif // TOOLS_ENABLED
507
508
#ifdef REAL_T_IS_DOUBLE
509
if (p_feature == "double") {
510
return true;
511
}
512
#else
513
if (p_feature == "single") {
514
return true;
515
}
516
#endif // REAL_T_IS_DOUBLE
517
518
if (sizeof(void *) == 8 && p_feature == "64") {
519
return true;
520
}
521
if (sizeof(void *) == 4 && p_feature == "32") {
522
return true;
523
}
524
#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(__i386) || defined(__i386__) || defined(_M_IX86) || defined(_M_X64)
525
#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(_M_X64)
526
#if defined(MACOS_ENABLED)
527
if (p_feature == "universal") {
528
return true;
529
}
530
#endif
531
if (p_feature == "x86_64") {
532
return true;
533
}
534
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
535
if (p_feature == "x86_32") {
536
return true;
537
}
538
#endif
539
if (p_feature == "x86") {
540
return true;
541
}
542
#elif defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64)
543
#if defined(__aarch64__) || defined(_M_ARM64)
544
#if defined(MACOS_ENABLED)
545
if (p_feature == "universal") {
546
return true;
547
}
548
#endif
549
if (p_feature == "arm64") {
550
return true;
551
}
552
#elif defined(__arm__) || defined(_M_ARM)
553
if (p_feature == "arm32") {
554
return true;
555
}
556
#endif
557
#if defined(__ARM_ARCH_7A__)
558
if (p_feature == "armv7a" || p_feature == "armv7") {
559
return true;
560
}
561
#endif
562
#if defined(__ARM_ARCH_7S__)
563
if (p_feature == "armv7s" || p_feature == "armv7") {
564
return true;
565
}
566
#endif
567
if (p_feature == "arm") {
568
return true;
569
}
570
#elif defined(__riscv)
571
#if __riscv_xlen == 8
572
if (p_feature == "rv64") {
573
return true;
574
}
575
#endif
576
if (p_feature == "riscv") {
577
return true;
578
}
579
#elif defined(__powerpc__)
580
#if defined(__powerpc64__)
581
if (p_feature == "ppc64") {
582
return true;
583
}
584
#endif
585
if (p_feature == "ppc") {
586
return true;
587
}
588
#elif defined(__wasm__)
589
#if defined(__wasm64__)
590
if (p_feature == "wasm64") {
591
return true;
592
}
593
#elif defined(__wasm32__)
594
if (p_feature == "wasm32") {
595
return true;
596
}
597
#endif
598
if (p_feature == "wasm") {
599
return true;
600
}
601
#elif defined(__loongarch64)
602
if (p_feature == "loongarch64") {
603
return true;
604
}
605
#endif
606
607
#if defined(IOS_SIMULATOR) || defined(VISIONOS_SIMULATOR)
608
if (p_feature == "simulator") {
609
return true;
610
}
611
#endif
612
613
if (p_feature == "threads") {
614
#ifdef THREADS_ENABLED
615
return true;
616
#else
617
return false;
618
#endif
619
}
620
if (p_feature == "nothreads") {
621
#ifdef THREADS_ENABLED
622
return false;
623
#else
624
return true;
625
#endif
626
}
627
628
if (_check_internal_feature_support(p_feature)) {
629
return true;
630
}
631
632
if (has_server_feature_callback && has_server_feature_callback(p_feature)) {
633
return true;
634
}
635
636
if (ProjectSettings::get_singleton()->has_custom_feature(p_feature)) {
637
return true;
638
}
639
640
return false;
641
}
642
643
bool OS::is_sandboxed() const {
644
return false;
645
}
646
647
void OS::set_restart_on_exit(bool p_restart, const List<String> &p_restart_arguments) {
648
restart_on_exit = p_restart;
649
restart_commandline = p_restart_arguments;
650
}
651
652
bool OS::is_restart_on_exit_set() const {
653
return restart_on_exit;
654
}
655
656
List<String> OS::get_restart_on_exit_arguments() const {
657
return restart_commandline;
658
}
659
660
PackedStringArray OS::get_connected_midi_inputs() {
661
if (MIDIDriver::get_singleton()) {
662
return MIDIDriver::get_singleton()->get_connected_inputs();
663
}
664
665
PackedStringArray list;
666
ERR_FAIL_V_MSG(list, vformat("MIDI input isn't supported on %s.", OS::get_singleton()->get_name()));
667
}
668
669
void OS::open_midi_inputs() {
670
if (MIDIDriver::get_singleton()) {
671
MIDIDriver::get_singleton()->open();
672
} else {
673
ERR_PRINT(vformat("MIDI input isn't supported on %s.", OS::get_singleton()->get_name()));
674
}
675
}
676
677
void OS::close_midi_inputs() {
678
if (MIDIDriver::get_singleton()) {
679
MIDIDriver::get_singleton()->close();
680
} else {
681
ERR_PRINT(vformat("MIDI input isn't supported on %s.", OS::get_singleton()->get_name()));
682
}
683
}
684
685
uint64_t OS::get_frame_delay(bool p_can_draw) const {
686
const uint32_t frame_delay = Engine::get_singleton()->get_frame_delay();
687
688
// Add a dynamic frame delay to decrease CPU/GPU usage. This takes the
689
// previous frame time into account for a smoother result.
690
uint64_t dynamic_delay = 0;
691
if (is_in_low_processor_usage_mode() || !p_can_draw) {
692
dynamic_delay = get_low_processor_usage_mode_sleep_usec();
693
}
694
const int max_fps = Engine::get_singleton()->get_max_fps();
695
if (max_fps > 0 && !Engine::get_singleton()->is_editor_hint()) {
696
// Override the low processor usage mode sleep delay if the target FPS is lower.
697
dynamic_delay = MAX(dynamic_delay, (uint64_t)(1000000 / max_fps));
698
}
699
700
return frame_delay + dynamic_delay;
701
}
702
703
void OS::add_frame_delay(bool p_can_draw, bool p_wake_for_events) {
704
const uint32_t frame_delay = Engine::get_singleton()->get_frame_delay();
705
if (frame_delay) {
706
// Add fixed frame delay to decrease CPU/GPU usage. This doesn't take
707
// the actual frame time into account.
708
// Due to the high fluctuation of the actual sleep duration, it's not recommended
709
// to use this as a FPS limiter.
710
delay_usec(frame_delay * 1000);
711
}
712
713
// Add a dynamic frame delay to decrease CPU/GPU usage. This takes the
714
// previous frame time into account for a smoother result.
715
uint64_t dynamic_delay = 0;
716
if (is_in_low_processor_usage_mode() || !p_can_draw) {
717
dynamic_delay = get_low_processor_usage_mode_sleep_usec();
718
}
719
const int max_fps = Engine::get_singleton()->get_max_fps();
720
if (max_fps > 0 && !Engine::get_singleton()->is_editor_hint()) {
721
// Override the low processor usage mode sleep delay if the target FPS is lower.
722
dynamic_delay = MAX(dynamic_delay, (uint64_t)(1000000 / max_fps));
723
}
724
725
if (dynamic_delay > 0) {
726
target_ticks += dynamic_delay;
727
uint64_t current_ticks = get_ticks_usec();
728
729
if (current_ticks < target_ticks) {
730
delay_usec(target_ticks - current_ticks);
731
}
732
733
current_ticks = get_ticks_usec();
734
target_ticks = MIN(MAX(target_ticks, current_ticks - dynamic_delay), current_ticks + dynamic_delay);
735
}
736
}
737
738
Error OS::setup_remote_filesystem(const String &p_server_host, int p_port, const String &p_password, String &r_project_path) {
739
return default_rfs.synchronize_with_server(p_server_host, p_port, p_password, r_project_path);
740
}
741
742
OS::PreferredTextureFormat OS::get_preferred_texture_format() const {
743
#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64)
744
return PREFERRED_TEXTURE_FORMAT_ETC2_ASTC; // By rule, ARM hardware uses ETC texture compression.
745
#elif defined(__x86_64__) || defined(_M_X64) || defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86)
746
return PREFERRED_TEXTURE_FORMAT_S3TC_BPTC; // By rule, X86 hardware prefers S3TC and derivatives.
747
#else
748
return PREFERRED_TEXTURE_FORMAT_S3TC_BPTC; // Override in platform if needed.
749
#endif
750
}
751
752
void OS::set_use_benchmark(bool p_use_benchmark) {
753
use_benchmark = p_use_benchmark;
754
}
755
756
bool OS::is_use_benchmark_set() {
757
return use_benchmark;
758
}
759
760
void OS::set_benchmark_file(const String &p_benchmark_file) {
761
benchmark_file = p_benchmark_file;
762
}
763
764
String OS::get_benchmark_file() {
765
return benchmark_file;
766
}
767
768
void OS::benchmark_begin_measure(const String &p_context, const String &p_what) {
769
#ifdef TOOLS_ENABLED
770
Pair<String, String> mark_key(p_context, p_what);
771
ERR_FAIL_COND_MSG(benchmark_marks_from.has(mark_key), vformat("Benchmark key '%s:%s' already exists.", p_context, p_what));
772
773
benchmark_marks_from[mark_key] = OS::get_singleton()->get_ticks_usec();
774
#endif
775
}
776
void OS::benchmark_end_measure(const String &p_context, const String &p_what) {
777
#ifdef TOOLS_ENABLED
778
Pair<String, String> mark_key(p_context, p_what);
779
ERR_FAIL_COND_MSG(!benchmark_marks_from.has(mark_key), vformat("Benchmark key '%s:%s' doesn't exist.", p_context, p_what));
780
781
uint64_t total = OS::get_singleton()->get_ticks_usec() - benchmark_marks_from[mark_key];
782
double total_f = double(total) / double(1000000);
783
benchmark_marks_final[mark_key] = total_f;
784
#endif
785
}
786
787
void OS::benchmark_dump() {
788
#ifdef TOOLS_ENABLED
789
if (!use_benchmark) {
790
return;
791
}
792
793
if (!benchmark_file.is_empty()) {
794
Ref<FileAccess> f = FileAccess::open(benchmark_file, FileAccess::WRITE);
795
if (f.is_valid()) {
796
Dictionary benchmark_marks;
797
for (const KeyValue<Pair<String, String>, double> &E : benchmark_marks_final) {
798
const String mark_key = vformat("[%s] %s", E.key.first, E.key.second);
799
benchmark_marks[mark_key] = E.value;
800
}
801
802
Ref<JSON> json;
803
json.instantiate();
804
f->store_string(json->stringify(benchmark_marks, "\t", false, true));
805
}
806
} else {
807
HashMap<String, String> results;
808
for (const KeyValue<Pair<String, String>, double> &E : benchmark_marks_final) {
809
if (E.key.first == "Startup" && !results.has(E.key.first)) {
810
results.insert(E.key.first, "", true); // Hack to make sure "Startup" always comes first.
811
}
812
813
results[E.key.first] += vformat("\t\t- %s: %.3f msec.\n", E.key.second, (E.value * 1000));
814
}
815
816
print_line("BENCHMARK:");
817
for (const KeyValue<String, String> &E : results) {
818
print_line(vformat("\t[%s]\n%s", E.key, E.value));
819
}
820
}
821
#endif
822
}
823
824
OS::OS() {
825
singleton = this;
826
827
Vector<Logger *> loggers;
828
loggers.push_back(memnew(StdLogger));
829
_set_logger(memnew(CompositeLogger(loggers)));
830
}
831
832
OS::~OS() {
833
if (_logger) {
834
memdelete(_logger);
835
}
836
singleton = nullptr;
837
}
838
839