summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/static_checks.yml64
-rw-r--r--.pre-commit-config.yaml152
-rw-r--r--SConstruct13
-rw-r--r--core/SCsub129
-rw-r--r--core/object/object.cpp7
-rw-r--r--core/templates/command_queue_mt.h36
-rw-r--r--doc/classes/CryptoKey.xml2
-rw-r--r--doc/classes/SkeletonModifier3D.xml10
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp7
-rw-r--r--drivers/gles3/storage/texture_storage.cpp4
-rw-r--r--editor/SCsub83
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp9
-rw-r--r--editor/themes/editor_color_map.cpp2
-rw-r--r--editor/themes/editor_theme_manager.cpp14
-rw-r--r--methods.py244
-rwxr-xr-xmisc/scripts/codespell.sh8
-rw-r--r--misc/scripts/dotnet_format.py16
-rw-r--r--misc/scripts/file_format.py51
-rwxr-xr-xmisc/scripts/file_format.sh89
-rw-r--r--misc/scripts/header_guards.py150
-rwxr-xr-xmisc/scripts/header_guards.sh87
-rwxr-xr-xmisc/scripts/mypy_check.sh6
-rwxr-xr-xmisc/scripts/pytest_builders.sh5
-rw-r--r--modules/SCsub65
-rw-r--r--modules/modules_builders.py15
-rw-r--r--modules/mono/csharp_script.cpp50
-rw-r--r--modules/mono/csharp_script.h4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs18
-rw-r--r--platform/SCsub65
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp2
-rw-r--r--platform/macos/display_server_macos.mm8
-rw-r--r--platform/windows/detect.py105
-rw-r--r--platform/windows/display_server_windows.cpp14
-rw-r--r--platform/windows/platform_windows_builders.py26
-rw-r--r--platform_methods.py27
-rw-r--r--scene/3d/skeleton_modifier_3d.cpp3
-rw-r--r--scene/3d/skeleton_modifier_3d.h1
-rw-r--r--scene/register_scene_types.cpp2
-rw-r--r--scene/resources/audio_stream_wav.cpp5
-rw-r--r--servers/physics_server_2d_wrap_mt.cpp44
-rw-r--r--servers/physics_server_2d_wrap_mt.h9
-rw-r--r--servers/physics_server_3d_wrap_mt.cpp44
-rw-r--r--servers/physics_server_3d_wrap_mt.h10
-rw-r--r--servers/rendering/renderer_viewport.cpp6
-rw-r--r--servers/rendering/renderer_viewport.h1
-rw-r--r--servers/rendering/rendering_server_default.cpp126
-rw-r--r--servers/rendering/rendering_server_default.h27
47 files changed, 1047 insertions, 818 deletions
diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml
index 3ff70077c4..2506cb7227 100644
--- a/.github/workflows/static_checks.yml
+++ b/.github/workflows/static_checks.yml
@@ -19,28 +19,13 @@ jobs:
- name: Install APT dependencies
uses: awalsh128/cache-apt-pkgs-action@latest
with:
- packages: dos2unix libxml2-utils moreutils
+ packages: libxml2-utils
- name: Install Python dependencies and general setup
run: |
- pip3 install pytest==7.1.2 mypy==0.971
+ pip3 install pytest==7.1.2
git config diff.wsErrorHighlight all
- - name: Get changed files
- id: changed-files
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: |
- if [ "${{ github.event_name }}" == "pull_request" ]; then
- files=$(git diff-tree --no-commit-id --name-only -r HEAD^1..HEAD 2> /dev/null || true)
- elif [ "${{ github.event_name }}" == "push" -a "${{ github.event.forced }}" == "false" -a "${{ github.event.created }}" == "false" ]; then
- files=$(git diff-tree --no-commit-id --name-only -r ${{ github.event.before }}..${{ github.event.after }} 2> /dev/null || true)
- fi
- echo "$files" >> changed.txt
- cat changed.txt
- files=$(echo "$files" | grep -v 'thirdparty' | xargs -I {} sh -c 'echo "./{}"' | tr '\n' ' ')
- echo "CHANGED_FILES=$files" >> $GITHUB_ENV
-
# This needs to happen before Python and npm execution; it must happen before any extra files are written.
- name: .gitignore checks (gitignore_check.sh)
run: |
@@ -49,51 +34,12 @@ jobs:
- name: Style checks via pre-commit
uses: pre-commit/action@v3.0.1
with:
- extra_args: --verbose --files ${{ env.CHANGED_FILES }}
-
- - name: File formatting checks (file_format.sh)
- run: |
- bash ./misc/scripts/file_format.sh changed.txt
-
- - name: Header guards formatting checks (header_guards.sh)
- run: |
- bash ./misc/scripts/header_guards.sh changed.txt
-
- - name: Python scripts static analysis (mypy_check.sh)
- run: |
- if grep -qE '\.py$|SConstruct|SCsub' changed.txt || [ -z "$(cat changed.txt)" ]; then
- bash ./misc/scripts/mypy_check.sh
- else
- echo "Skipping Python static analysis as no Python files were changed."
- fi
-
- - name: Python builders checks via pytest (pytest_builders.sh)
- run: |
- bash ./misc/scripts/pytest_builders.sh
+ extra_args: --verbose
- - name: JavaScript style and documentation checks via ESLint and JSDoc
+ - name: Python builders checks via pytest
run: |
- if grep -q "\.js" changed.txt || [ -z "$(cat changed.txt)" ]; then
- cd platform/web
- npm ci
- npm run lint
- npm run docs -- -d dry-run
- else
- echo "Skipping JavaScript formatting as no Web/JS files were changed."
- fi
+ pytest ./tests/python_build
- name: Class reference schema checks
run: |
xmllint --noout --schema doc/class.xsd doc/classes/*.xml modules/*/doc_classes/*.xml platform/*/doc_classes/*.xml
-
- - name: Documentation checks
- run: |
- doc/tools/doc_status.py doc/classes modules/*/doc_classes platform/*/doc_classes
-
- - name: Spell checks via codespell
- if: github.event_name == 'pull_request' && env.CHANGED_FILES != ''
- uses: codespell-project/actions-codespell@v2
- with:
- skip: "./bin,./thirdparty,*.desktop,*.gen.*,*.po,*.pot,*.rc,./AUTHORS.md,./COPYRIGHT.txt,./DONORS.md,./core/input/gamecontrollerdb.txt,./core/string/locales.h,./editor/project_converter_3_to_4.cpp,./misc/scripts/codespell.sh,./platform/android/java/lib/src/com,./platform/web/node_modules,./platform/web/package-lock.json"
- ignore_words_list: "breaked,colour,curvelinear,doubleclick,expct,findn,gird,hel,inout,lod,mis,nd,numer,ot,requestor,te,thirdparty,vai"
- path: ${{ env.CHANGED_FILES }}
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 7122363f77..e59419ac08 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,3 +1,9 @@
+exclude: |
+ (?x)^(
+ .*thirdparty/.*|
+ .*-so_wrap\.(h|c)$
+ )
+
repos:
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v17.0.6
@@ -7,10 +13,8 @@ repos:
types_or: [text]
exclude: |
(?x)^(
- tests/python_build.*|
- .*thirdparty.*|
- .*platform/android/java/lib/src/com.*|
- .*-so_wrap.*
+ tests/python_build/.*|
+ platform/android/java/lib/src/com/.*
)
- repo: https://github.com/psf/black-pre-commit-mirror
@@ -19,33 +23,155 @@ repos:
- id: black
files: (\.py$|SConstruct|SCsub)
types_or: [text]
- exclude: .*thirdparty.*
args:
- --line-length=120
+ - repo: https://github.com/pre-commit/mirrors-mypy
+ rev: v0.971
+ hooks:
+ - id: mypy
+ files: \.py$
+ types_or: [text]
+ args: [--config-file=./misc/scripts/mypy.ini]
+
+ - repo: https://github.com/codespell-project/codespell
+ rev: v2.2.6
+ hooks:
+ - id: codespell
+ types_or: [text]
+ exclude: |
+ (?x)^(
+ .*\.desktop$|
+ .*\.gitignore$|
+ .*\.po$|
+ .*\.pot$|
+ .*\.rc$|
+ \.mailmap$|
+ AUTHORS.md$|
+ COPYRIGHT.txt$|
+ DONORS.md$|
+ core/input/gamecontrollerdb.txt$|
+ core/string/locales.h$|
+ editor/project_converter_3_to_4.cpp$|
+ platform/android/java/lib/src/com/.*|
+ platform/web/package-lock.json$
+ )
+ args:
+ - --enable-colors
+ - --write-changes
+ - --check-hidden
+ - --quiet-level
+ - '3'
+ - --ignore-words-list
+ - aesthetic,aesthetics,breaked,cancelled,colour,curvelinear,doubleclick,expct,findn,gird,hel,inout,lod,mis,nd,numer,ot,requestor,te,thirdparty,vai
+ - --builtin
+ - clear,rare,en-GB_to_en-US
+
+ ### Requires Docker; look into alternative implementation.
+ # - repo: https://github.com/comkieffer/pre-commit-xmllint.git
+ # rev: 1.0.0
+ # hooks:
+ # - id: xmllint
+ # language: docker
+ # types_or: [text]
+ # files: ^(doc/classes|.*/doc_classes)/.*\.xml$
+ # args: [--schema, doc/class.xsd]
+
+ - repo: https://github.com/pre-commit/mirrors-eslint
+ rev: v8.46.0
+ hooks:
+ - id: eslint
+ name: eslint-engine
+ files: ^(platform/web/js/engine/|js/jsdoc2rst/).*\.js$
+ args: [--fix, --no-eslintrc, --config, platform/web/.eslintrc.engine.js]
+ additional_dependencies: &eslint-deps
+ - eslint@8.46.0
+ - eslint-config-airbnb-base@15.0.0
+ - eslint-plugin-import@2.28.0
+ - eslint-plugin-html@7.1.0
+ - '@html-eslint/eslint-plugin@0.19.1'
+ - '@html-eslint/parser@0.19.1'
+ - id: eslint
+ name: eslint-libs
+ files: ^(platform/web/js/libs/|modules/).*\.js$
+ args: [--fix, --no-eslintrc, --config, platform/web/.eslintrc.libs.js]
+ additional_dependencies: *eslint-deps
+ - id: eslint
+ name: eslint-sw
+ files: ^misc/dist/html/service-worker\.js$
+ args: [--fix, --no-eslintrc, --config, platform/web/.eslintrc.sw.js]
+ additional_dependencies: *eslint-deps
+ - id: eslint
+ name: eslint-html
+ files: ^misc/dist/html/.*\.html$
+ types: [html]
+ args: [--fix, --no-eslintrc, --config, platform/web/.eslintrc.html.js]
+ additional_dependencies: *eslint-deps
+
- repo: local
hooks:
- id: make-rst
name: make-rst
+ language: python
entry: python3 doc/tools/make_rst.py doc/classes modules platform --dry-run --color
pass_filenames: false
+ files: ^(doc/classes|.*/doc_classes)/.*\.xml$
+
+ - id: doc-status
+ name: doc-status
language: python
- files: ^(doc|modules|platform).*xml$
+ entry: python3 doc/tools/doc_status.py
+ files: ^(doc/classes|.*/doc_classes)/.*\.xml$
+
+ - id: jsdoc
+ name: jsdoc
+ language: node
+ entry: jsdoc
+ files: ^platform/web/js/engine/(engine|config|features)\.js$
+ args: [--template, platform/web/js/jsdoc2rst/, --destination, '', -d, dry-run]
+ additional_dependencies: ["jsdoc@4.0.2"]
- id: copyright-headers
name: copyright-headers
language: python
- files: \.(c|h|cpp|hpp|cc|cxx|m|mm|inc|java)$
entry: python3 misc/scripts/copyright_headers.py
+ files: \.(c|h|cpp|hpp|cc|cxx|m|mm|inc|java)$
exclude: |
(?x)^(
- .*thirdparty.*|
- .*-so_wrap.*|
core/math/bvh_.*\.inc$|
- platform/android/java/lib/src/com.*|
- platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.*|
- platform/android/java/lib/src/org/godotengine/godot/gl/EGLLogWrapper.*|
- platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix.*
+ platform/android/java/lib/src/com/.*|
+ platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView\.java$|
+ platform/android/java/lib/src/org/godotengine/godot/gl/EGLLogWrapper\.java$|
+ platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix\.java$
+ )
+
+ - id: header-guards
+ name: header-guards
+ language: python
+ entry: python3 misc/scripts/header_guards.py
+ files: \.(h|hpp)$
+ exclude: |
+ (?x)^(
+ .*/thread\.h$|
+ .*/platform_config\.h$|
+ .*/platform_gl\.$h
+ )
+
+ - id: file-format
+ name: file-format
+ language: python
+ entry: python3 misc/scripts/file_format.py
+ types_or: [text]
+ exclude: |
+ (?x)^(
+ .*\.test\.txt$|
+ .*\.svg$|
+ .*\.patch$|
+ .*\.out$|
+ modules/gdscript/tests/scripts/parser/features/mixed_indentation_on_blank_lines\.gd$|
+ modules/gdscript/tests/scripts/parser/warnings/empty_file_newline_comment\.notest\.gd$|
+ modules/gdscript/tests/scripts/parser/warnings/empty_file_newline\.notest\.gd$|
+ platform/android/java/lib/src/com/google/.*
)
- id: dotnet-format
diff --git a/SConstruct b/SConstruct
index 81ce4bca52..cfedcc84ed 100644
--- a/SConstruct
+++ b/SConstruct
@@ -61,7 +61,6 @@ _helper_module("platform_methods", "platform_methods.py")
_helper_module("version", "version.py")
_helper_module("core.core_builders", "core/core_builders.py")
_helper_module("main.main_builders", "main/main_builders.py")
-_helper_module("modules.modules_builders", "modules/modules_builders.py")
# Local
import methods
@@ -69,7 +68,7 @@ import glsl_builders
import gles3_builders
import scu_builders
from methods import print_warning, print_error
-from platform_methods import architectures, architecture_aliases, generate_export_icons
+from platform_methods import architectures, architecture_aliases
if ARGUMENTS.get("target", "editor") == "editor":
_helper_module("editor.editor_builders", "editor/editor_builders.py")
@@ -107,7 +106,6 @@ for x in sorted(glob.glob("platform/*")):
if os.path.exists(x + "/export/export.cpp"):
platform_exporters.append(platform_name)
- generate_export_icons(x, platform_name)
if os.path.exists(x + "/api/api.cpp"):
platform_apis.append(platform_name)
if detect.can_build():
@@ -428,7 +426,7 @@ for name, path in modules_detected.items():
sys.path.remove(path)
sys.modules.pop("config")
-methods.write_modules(modules_detected)
+env.modules_detected = modules_detected
# Update the environment again after all the module options are added.
opts.Update(env)
@@ -544,7 +542,7 @@ env.Append(CFLAGS=env.get("cflags", "").split())
env.Append(LINKFLAGS=env.get("linkflags", "").split())
# Feature build profile
-disabled_classes = []
+env.disabled_classes = []
if env["build_profile"] != "":
print('Using feature build profile: "{}"'.format(env["build_profile"]))
import json
@@ -552,7 +550,7 @@ if env["build_profile"] != "":
try:
ft = json.load(open(env["build_profile"]))
if "disabled_classes" in ft:
- disabled_classes = ft["disabled_classes"]
+ env.disabled_classes = ft["disabled_classes"]
if "disabled_build_options" in ft:
dbo = ft["disabled_build_options"]
for c in dbo:
@@ -560,7 +558,6 @@ if env["build_profile"] != "":
except:
print_error('Failed to open feature build profile: "{}"'.format(env["build_profile"]))
Exit(255)
-methods.write_disabled_classes(disabled_classes)
# Platform specific flags.
# These can sometimes override default options.
@@ -926,7 +923,7 @@ if env.editor_build:
print_error("Not all modules required by editor builds are enabled.")
Exit(255)
-methods.generate_version_header(env.module_version_string)
+env.version_info = methods.get_version_info(env.module_version_string)
env["PROGSUFFIX_WRAP"] = suffix + env.module_version_string + ".console" + env["PROGSUFFIX"]
env["PROGSUFFIX"] = suffix + env.module_version_string + env["PROGSUFFIX"]
diff --git a/core/SCsub b/core/SCsub
index 91620cb075..640c6de6a1 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -4,44 +4,9 @@ Import("env")
import core_builders
import methods
-
-env.core_sources = []
-
-
-# Generate AES256 script encryption key
import os
-txt = "0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0"
-if "SCRIPT_AES256_ENCRYPTION_KEY" in os.environ:
- key = os.environ["SCRIPT_AES256_ENCRYPTION_KEY"]
- ec_valid = True
- if len(key) != 64:
- ec_valid = False
- else:
- txt = ""
- for i in range(len(key) >> 1):
- if i > 0:
- txt += ","
- txts = "0x" + key[i * 2 : i * 2 + 2]
- try:
- int(txts, 16)
- except Exception:
- ec_valid = False
- txt += txts
- if not ec_valid:
- methods.print_error(
- f'Invalid AES256 encryption key, not 64 hexadecimal characters: "{key}".\n'
- "Unset 'SCRIPT_AES256_ENCRYPTION_KEY' in your environment "
- "or make sure that it contains exactly 64 hexadecimal characters."
- )
- Exit(255)
-
-
-script_encryption_key_contents = (
- '#include "core/config/project_settings.h"\nuint8_t script_encryption_key[32]={' + txt + "};\n"
-)
-
-methods.write_file_if_needed("script_encryption_key.gen.cpp", script_encryption_key_contents)
+env.core_sources = []
# Add required thirdparty code.
@@ -193,8 +158,96 @@ env.core_sources += thirdparty_obj
# Godot source files
env.add_source_files(env.core_sources, "*.cpp")
-env.add_source_files(env.core_sources, "script_encryption_key.gen.cpp")
-env.add_source_files(env.core_sources, "version_hash.gen.cpp")
+
+
+# Generate disabled classes
+def disabled_class_builder(target, source, env):
+ with methods.generated_wrapper(target) as file:
+ for c in source[0].read():
+ cs = c.strip()
+ if cs != "":
+ file.write(f"#define ClassDB_Disable_{cs} 1")
+
+
+env.CommandNoCache("disabled_classes.gen.h", env.Value(env.disabled_classes), env.Run(disabled_class_builder))
+
+
+# Generate version info
+def version_info_builder(target, source, env):
+ with methods.generated_wrapper(target) as file:
+ file.write(
+ """\
+#define VERSION_SHORT_NAME "{short_name}"
+#define VERSION_NAME "{name}"
+#define VERSION_MAJOR {major}
+#define VERSION_MINOR {minor}
+#define VERSION_PATCH {patch}
+#define VERSION_STATUS "{status}"
+#define VERSION_BUILD "{build}"
+#define VERSION_MODULE_CONFIG "{module_config}"
+#define VERSION_WEBSITE "{website}"
+#define VERSION_DOCS_BRANCH "{docs_branch}"
+#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH
+""".format(
+ **env.version_info
+ )
+ )
+
+
+env.CommandNoCache("version_generated.gen.h", "#version.py", env.Run(version_info_builder))
+
+
+# Generate version hash
+def version_hash_builder(target, source, env):
+ with methods.generated_wrapper(target) as file:
+ file.write(
+ """\
+#include "core/version.h"
+
+const char *const VERSION_HASH = "{git_hash}";
+const uint64_t VERSION_TIMESTAMP = {git_timestamp};
+""".format(
+ **env.version_info
+ )
+ )
+
+
+gen_hash = env.CommandNoCache(
+ "version_hash.gen.cpp", env.Value(env.version_info["git_hash"]), env.Run(version_hash_builder)
+)
+env.add_source_files(env.core_sources, gen_hash)
+
+
+# Generate AES256 script encryption key
+def encryption_key_builder(target, source, env):
+ with methods.generated_wrapper(target) as file:
+ file.write(
+ f"""\
+#include "core/config/project_settings.h"
+
+uint8_t script_encryption_key[32] = {{
+ {source[0]}
+}};"""
+ )
+
+
+gdkey = os.environ.get("SCRIPT_AES256_ENCRYPTION_KEY", "0" * 64)
+ec_valid = len(gdkey) == 64
+if ec_valid:
+ try:
+ gdkey = ", ".join([str(int(f"{a}{b}", 16)) for a, b in zip(gdkey[0::2], gdkey[1::2])])
+ except Exception:
+ ec_valid = False
+if not ec_valid:
+ methods.print_error(
+ f'Invalid AES256 encryption key, not 64 hexadecimal characters: "{gdkey}".\n'
+ "Unset `SCRIPT_AES256_ENCRYPTION_KEY` in your environment "
+ "or make sure that it contains exactly 64 hexadecimal characters."
+ )
+ Exit(255)
+gen_encrypt = env.CommandNoCache("script_encryption_key.gen.cpp", env.Value(gdkey), env.Run(encryption_key_builder))
+env.add_source_files(env.core_sources, gen_encrypt)
+
# Certificates
env.Depends(
diff --git a/core/object/object.cpp b/core/object/object.cpp
index ab89f96a0d..dfc8e2a29a 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -2307,9 +2307,9 @@ void ObjectDB::setup() {
}
void ObjectDB::cleanup() {
- if (slot_count > 0) {
- spin_lock.lock();
+ spin_lock.lock();
+ if (slot_count > 0) {
WARN_PRINT("ObjectDB instances leaked at exit (run with --verbose for details).");
if (OS::get_singleton()->is_stdout_verbose()) {
// Ensure calling the native classes because if a leaked instance has a script
@@ -2340,10 +2340,11 @@ void ObjectDB::cleanup() {
}
print_line("Hint: Leaked instances typically happen when nodes are removed from the scene tree (with `remove_child()`) but not freed (with `free()` or `queue_free()`).");
}
- spin_lock.unlock();
}
if (object_slots) {
memfree(object_slots);
}
+
+ spin_lock.unlock();
}
diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h
index bb36f38d54..dbf938a117 100644
--- a/core/templates/command_queue_mt.h
+++ b/core/templates/command_queue_mt.h
@@ -302,7 +302,7 @@ class CommandQueueMT {
struct CommandBase {
bool sync = false;
virtual void call() = 0;
- virtual ~CommandBase() = default; // Won't be called.
+ virtual ~CommandBase() = default;
};
struct SyncCommand : public CommandBase {
@@ -327,7 +327,6 @@ class CommandQueueMT {
enum {
DEFAULT_COMMAND_MEM_SIZE_KB = 256,
- SYNC_SEMAPHORES = 8
};
BinaryMutex mutex;
@@ -335,6 +334,7 @@ class CommandQueueMT {
ConditionVariable sync_cond_var;
uint32_t sync_head = 0;
uint32_t sync_tail = 0;
+ uint32_t sync_awaiters = 0;
WorkerThreadPool::TaskID pump_task_id = WorkerThreadPool::INVALID_TASK_ID;
uint64_t flush_read_ptr = 0;
@@ -349,6 +349,15 @@ class CommandQueueMT {
return cmd;
}
+ _FORCE_INLINE_ void _prevent_sync_wraparound() {
+ bool safe_to_reset = !sync_awaiters;
+ bool already_sync_to_latest = sync_head == sync_tail;
+ if (safe_to_reset && already_sync_to_latest) {
+ sync_head = 0;
+ sync_tail = 0;
+ }
+ }
+
void _flush() {
if (unlikely(flush_read_ptr)) {
// Re-entrant call.
@@ -365,25 +374,39 @@ class CommandQueueMT {
cmd->call();
if (unlikely(cmd->sync)) {
sync_head++;
+ unlock(); // Give an opportunity to awaiters right away.
sync_cond_var.notify_all();
+ lock();
}
+ // If the command involved reallocating the buffer, the address may have changed.
+ cmd = reinterpret_cast<CommandBase *>(&command_mem[flush_read_ptr]);
+ cmd->~CommandBase();
+
flush_read_ptr += size;
}
WorkerThreadPool::thread_exit_command_queue_mt_flush();
command_mem.clear();
flush_read_ptr = 0;
+
+ _prevent_sync_wraparound();
+
unlock();
}
_FORCE_INLINE_ void _wait_for_sync(MutexLock<BinaryMutex> &p_lock) {
+ sync_awaiters++;
uint32_t sync_head_goal = sync_tail;
do {
sync_cond_var.wait(p_lock);
- } while (sync_head != sync_head_goal); // Can't use lower-than because of wraparound.
+ } while (sync_head < sync_head_goal);
+ sync_awaiters--;
+ _prevent_sync_wraparound();
}
+ void _no_op() {}
+
public:
void lock();
void unlock();
@@ -405,10 +428,15 @@ public:
_flush();
}
}
+
void flush_all() {
_flush();
}
+ void sync() {
+ push_and_sync(this, &CommandQueueMT::_no_op);
+ }
+
void wait_and_flush() {
ERR_FAIL_COND(pump_task_id == WorkerThreadPool::INVALID_TASK_ID);
WorkerThreadPool::get_singleton()->wait_for_task_completion(pump_task_id);
@@ -416,7 +444,9 @@ public:
}
void set_pump_task_id(WorkerThreadPool::TaskID p_task_id) {
+ lock();
pump_task_id = p_task_id;
+ unlock();
}
CommandQueueMT();
diff --git a/doc/classes/CryptoKey.xml b/doc/classes/CryptoKey.xml
index ff826a3ae5..dd128b6806 100644
--- a/doc/classes/CryptoKey.xml
+++ b/doc/classes/CryptoKey.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="CryptoKey" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- A cryptographic key (RSA).
+ A cryptographic key (RSA or elliptic-curve).
</brief_description>
<description>
The CryptoKey class represents a cryptographic key. Keys can be loaded and saved like any other [Resource].
diff --git a/doc/classes/SkeletonModifier3D.xml b/doc/classes/SkeletonModifier3D.xml
index fab33750ea..c0b1b6fd53 100644
--- a/doc/classes/SkeletonModifier3D.xml
+++ b/doc/classes/SkeletonModifier3D.xml
@@ -6,9 +6,19 @@
<description>
[SkeletonModifier3D] retrieves a target [Skeleton3D] by having a [Skeleton3D] parent.
If there is [AnimationMixer], modification always performs after playback process of the [AnimationMixer].
+ This node should be used to implement custom IK solvers, constraints, or skeleton physics
</description>
<tutorials>
</tutorials>
+ <methods>
+ <method name="_process_modification" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Override this virtual method to implement a custom skeleton modifier. You should do things like get the [Skeleton3D]'s current pose and apply the pose here.
+ [method _process_modification] must not apply [member influence] to bone poses because the [Skeleton3D] automatically applies influence to all bone poses set by the modifier.
+ </description>
+ </method>
+ </methods>
<members>
<member name="active" type="bool" setter="set_active" getter="is_active" default="true">
If [code]true[/code], the [SkeletonModifier3D] will be processing.
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index 767a394ce5..6e7d4a6733 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -395,10 +395,13 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
if (p_first) {
- Size2i win_size = DisplayServer::get_singleton()->window_get_size();
if (p_screen_rect.position != Vector2() || p_screen_rect.size != rt->size) {
// Viewport doesn't cover entire window so clear window to black before blitting.
- glViewport(0, 0, win_size.width, win_size.height);
+ // Querying the actual window size from the DisplayServer would deadlock in separate render thread mode,
+ // so let's set the biggest viewport the implementation supports, to be sure the window is fully covered.
+ GLsizei max_vp[2] = {};
+ glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_vp);
+ glViewport(0, 0, max_vp[0], max_vp[1]);
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
}
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index 373df8d8de..a65347a5b1 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -2312,9 +2312,11 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
if (rt->backbuffer_fbo != 0) {
glDeleteFramebuffers(1, &rt->backbuffer_fbo);
+ rt->backbuffer_fbo = 0;
+ }
+ if (rt->backbuffer != 0) {
GLES3::Utilities::get_singleton()->texture_free_data(rt->backbuffer);
rt->backbuffer = 0;
- rt->backbuffer_fbo = 0;
}
if (rt->backbuffer_depth != 0) {
GLES3::Utilities::get_singleton()->texture_free_data(rt->backbuffer_depth);
diff --git a/editor/SCsub b/editor/SCsub
index e3b17b83f8..e613a71238 100644
--- a/editor/SCsub
+++ b/editor/SCsub
@@ -10,40 +10,59 @@ import editor_builders
import methods
-def _make_doc_data_class_path(to_path):
- file_path = os.path.join(to_path, "doc_data_class_path.gen.h")
-
- class_path_data = ""
- class_path_data += "static const int _doc_data_class_path_count = " + str(len(env.doc_class_path)) + ";\n"
- class_path_data += "struct _DocDataClassPath { const char* name; const char* path; };\n"
- class_path_data += (
- "static const _DocDataClassPath _doc_data_class_paths[" + str(len(env.doc_class_path) + 1) + "] = {\n"
- )
- for c in sorted(env.doc_class_path):
- class_path_data += '\t{"' + c + '", "' + env.doc_class_path[c] + '"},\n'
- class_path_data += "\t{nullptr, nullptr}\n"
- class_path_data += "};\n"
-
- methods.write_file_if_needed(file_path, class_path_data)
-
-
if env.editor_build:
+ # Generate doc data paths
+ def doc_data_class_path_builder(target, source, env):
+ paths = dict(sorted(source[0].read().items()))
+ data = "\n".join([f'\t{{"{key}", "{value}"}},' for key, value in paths.items()])
+ with methods.generated_wrapper(target) as file:
+ file.write(
+ f"""\
+static const int _doc_data_class_path_count = {len(paths)};
+
+struct _DocDataClassPath {{
+ const char *name;
+ const char *path;
+}};
+
+static const _DocDataClassPath _doc_data_class_paths[{len(env.doc_class_path) + 1}] = {{
+{data}
+ {{nullptr, nullptr}},
+}};
+"""
+ )
+
+ env.CommandNoCache("doc_data_class_path.gen.h", env.Value(env.doc_class_path), env.Run(doc_data_class_path_builder))
+
# Register exporters
- reg_exporters_inc = '#include "register_exporters.h"\n\n'
- reg_exporters = "void register_exporters() {\n"
+ def register_exporters_builder(target, source, env):
+ platforms = source[0].read()
+ exp_inc = "\n".join([f'#include "platform/{p}/export/export.h"' for p in platforms])
+ exp_reg = "\n".join([f"\tregister_{p}_exporter();" for p in platforms])
+ exp_type = "\n".join([f"\tregister_{p}_exporter_types();" for p in platforms])
+ with methods.generated_wrapper(target) as file:
+ file.write(
+ f"""\
+#include "register_exporters.h"
+
+{exp_inc}
+
+void register_exporters() {{
+{exp_reg}
+}}
+
+void register_exporter_types() {{
+{exp_type}
+}}
+"""
+ )
+
+ gen_exporters = env.CommandNoCache(
+ "register_exporters.gen.cpp", env.Value(env.platform_exporters), env.Run(register_exporters_builder)
+ )
for e in env.platform_exporters:
# Add all .cpp files in export folder
- env.add_source_files(env.editor_sources, "../platform/" + e + "/export/" + "*.cpp")
-
- reg_exporters += "\tregister_" + e + "_exporter();\n"
- reg_exporters_inc += '#include "platform/' + e + '/export/export.h"\n'
- reg_exporters += "}\n\n"
- reg_exporters += "void register_exporter_types() {\n"
- for e in env.platform_exporters:
- reg_exporters += "\tregister_" + e + "_exporter_types();\n"
- reg_exporters += "}\n"
-
- methods.write_file_if_needed("register_exporters.gen.cpp", reg_exporters_inc + reg_exporters)
+ env.add_source_files(env.editor_sources, f"../platform/{e}/export/*.cpp")
# Core API documentation.
docs = []
@@ -61,8 +80,6 @@ if env.editor_build:
else:
docs += Glob(d + "/*.xml") # Custom.
- _make_doc_data_class_path(env.Dir("#editor").abspath)
-
docs = sorted(docs)
env.Depends("#editor/doc_data_compressed.gen.h", docs)
env.CommandNoCache(
@@ -115,7 +132,7 @@ if env.editor_build:
)
env.add_source_files(env.editor_sources, "*.cpp")
- env.add_source_files(env.editor_sources, "register_exporters.gen.cpp")
+ env.add_source_files(env.editor_sources, gen_exporters)
SConscript("debugger/SCsub")
SConscript("export/SCsub")
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index 3f86d30368..de56767929 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -912,7 +912,9 @@ void EditorNode3DGizmoPlugin::create_icon_material(const String &p_name, const R
Color color = instantiated ? instantiated_color : p_albedo;
if (!selected) {
- color.a *= 0.85;
+ color.r *= 0.6;
+ color.g *= 0.6;
+ color.b *= 0.6;
}
icon->set_albedo(color);
@@ -921,9 +923,8 @@ void EditorNode3DGizmoPlugin::create_icon_material(const String &p_name, const R
icon->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
icon->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
icon->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
- icon->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
- icon->set_depth_draw_mode(StandardMaterial3D::DEPTH_DRAW_DISABLED);
- icon->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ icon->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA_SCISSOR);
+ icon->set_alpha_scissor_threshold(0.1);
icon->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, p_texture);
icon->set_flag(StandardMaterial3D::FLAG_FIXED_SIZE, true);
icon->set_billboard_mode(StandardMaterial3D::BILLBOARD_ENABLED);
diff --git a/editor/themes/editor_color_map.cpp b/editor/themes/editor_color_map.cpp
index 99bcf109d0..9046a8b688 100644
--- a/editor/themes/editor_color_map.cpp
+++ b/editor/themes/editor_color_map.cpp
@@ -169,9 +169,7 @@ void EditorColorMap::create() {
add_conversion_exception("ZoomReset");
add_conversion_exception("LockViewport");
add_conversion_exception("GroupViewport");
- add_conversion_exception("StatusError");
add_conversion_exception("StatusSuccess");
- add_conversion_exception("StatusWarning");
add_conversion_exception("OverbrightIndicator");
add_conversion_exception("MaterialPreviewCube");
add_conversion_exception("MaterialPreviewSphere");
diff --git a/editor/themes/editor_theme_manager.cpp b/editor/themes/editor_theme_manager.cpp
index ee008e5636..2ef62c60a2 100644
--- a/editor/themes/editor_theme_manager.cpp
+++ b/editor/themes/editor_theme_manager.cpp
@@ -436,8 +436,8 @@ void EditorThemeManager::_create_shared_styles(const Ref<EditorTheme> &p_theme,
if (!p_config.dark_theme) {
// Darken some colors to be readable on a light background.
p_config.success_color = p_config.success_color.lerp(p_config.mono_color, 0.35);
- p_config.warning_color = p_config.warning_color.lerp(p_config.mono_color, 0.35);
- p_config.error_color = p_config.error_color.lerp(p_config.mono_color, 0.25);
+ p_config.warning_color = Color(0.82, 0.56, 0.1);
+ p_config.error_color = Color(0.8, 0.22, 0.22);
}
p_theme->set_color("mono_color", EditorStringName(Editor), p_config.mono_color);
@@ -1901,14 +1901,20 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme
// When pressed, don't tint the icons with the accent color, just leave them normal.
p_theme->set_color("icon_pressed_color", "EditorLogFilterButton", p_config.icon_normal_color);
// When unpressed, dim the icons.
- p_theme->set_color("icon_normal_color", "EditorLogFilterButton", p_config.icon_disabled_color);
+ Color icon_normal_color = Color(p_config.icon_normal_color, (p_config.dark_theme ? 0.4 : 0.8));
+ p_theme->set_color("icon_normal_color", "EditorLogFilterButton", icon_normal_color);
+ Color icon_hover_color = p_config.icon_normal_color * (p_config.dark_theme ? 1.15 : 1.0);
+ icon_hover_color.a = 1.0;
+ p_theme->set_color("icon_hover_color", "EditorLogFilterButton", icon_hover_color);
// When pressed, add a small bottom border to the buttons to better show their active state,
// similar to active tabs.
Ref<StyleBoxFlat> editor_log_button_pressed = style_flat_button_pressed->duplicate();
editor_log_button_pressed->set_border_width(SIDE_BOTTOM, 2 * EDSCALE);
editor_log_button_pressed->set_border_color(p_config.accent_color);
-
+ if (!p_config.dark_theme) {
+ editor_log_button_pressed->set_bg_color(flat_pressed_color.lightened(0.5));
+ }
p_theme->set_stylebox("normal", "EditorLogFilterButton", style_flat_button);
p_theme->set_stylebox("hover", "EditorLogFilterButton", style_flat_button_hover);
p_theme->set_stylebox("pressed", "EditorLogFilterButton", editor_log_button_pressed);
diff --git a/methods.py b/methods.py
index 0c29632f10..da221cc0ea 100644
--- a/methods.py
+++ b/methods.py
@@ -3,13 +3,16 @@ import sys
import re
import glob
import subprocess
+import contextlib
from collections import OrderedDict
from collections.abc import Mapping
from enum import Enum
-from typing import Iterator
+from typing import Generator, Optional
+from io import TextIOWrapper, StringIO
from pathlib import Path
from os.path import normpath, basename
+
# Get the "Godot" folder name ahead of time
base_folder_path = str(os.path.abspath(Path(__file__).parent)) + "/"
base_folder_only = os.path.basename(os.path.normpath(base_folder_path))
@@ -277,79 +280,6 @@ def get_version_info(module_version_string="", silent=False):
return version_info
-_cleanup_env = None
-_cleanup_bool = False
-
-
-def write_file_if_needed(path, string):
- """Generates a file only if it doesn't already exist or the content has changed.
-
- Utilizes a dedicated SCons environment to ensure the files are properly removed
- during cleanup; will not attempt to create files during cleanup.
-
- - `path` - Path to the file in question; used to create cleanup logic.
- - `string` - Content to compare against an existing file.
- """
- global _cleanup_env
- global _cleanup_bool
-
- if _cleanup_env is None:
- from SCons.Environment import Environment
-
- _cleanup_env = Environment()
- _cleanup_bool = _cleanup_env.GetOption("clean")
-
- _cleanup_env.Clean("#", path)
- if _cleanup_bool:
- return
-
- try:
- with open(path, "r", encoding="utf-8", newline="\n") as f:
- if f.read() == string:
- return
- except FileNotFoundError:
- pass
-
- with open(path, "w", encoding="utf-8", newline="\n") as f:
- f.write(string)
-
-
-def generate_version_header(module_version_string=""):
- version_info = get_version_info(module_version_string)
-
- version_info_header = """\
-/* THIS FILE IS GENERATED DO NOT EDIT */
-#ifndef VERSION_GENERATED_GEN_H
-#define VERSION_GENERATED_GEN_H
-#define VERSION_SHORT_NAME "{short_name}"
-#define VERSION_NAME "{name}"
-#define VERSION_MAJOR {major}
-#define VERSION_MINOR {minor}
-#define VERSION_PATCH {patch}
-#define VERSION_STATUS "{status}"
-#define VERSION_BUILD "{build}"
-#define VERSION_MODULE_CONFIG "{module_config}"
-#define VERSION_WEBSITE "{website}"
-#define VERSION_DOCS_BRANCH "{docs_branch}"
-#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH
-#endif // VERSION_GENERATED_GEN_H
-""".format(
- **version_info
- )
-
- version_hash_data = """\
-/* THIS FILE IS GENERATED DO NOT EDIT */
-#include "core/version.h"
-const char *const VERSION_HASH = "{git_hash}";
-const uint64_t VERSION_TIMESTAMP = {git_timestamp};
-""".format(
- **version_info
- )
-
- write_file_if_needed("core/version_generated.gen.h", version_info_header)
- write_file_if_needed("core/version_hash.gen.cpp", version_hash_data)
-
-
def parse_cg_file(fname, uniforms, sizes, conditionals):
with open(fname, "r", encoding="utf-8") as fs:
line = fs.readline()
@@ -465,63 +395,6 @@ def is_module(path):
return True
-def write_disabled_classes(class_list):
- file_contents = ""
-
- file_contents += "/* THIS FILE IS GENERATED DO NOT EDIT */\n"
- file_contents += "#ifndef DISABLED_CLASSES_GEN_H\n"
- file_contents += "#define DISABLED_CLASSES_GEN_H\n\n"
- for c in class_list:
- cs = c.strip()
- if cs != "":
- file_contents += "#define ClassDB_Disable_" + cs + " 1\n"
- file_contents += "\n#endif\n"
-
- write_file_if_needed("core/disabled_classes.gen.h", file_contents)
-
-
-def write_modules(modules):
- includes_cpp = ""
- initialize_cpp = ""
- uninitialize_cpp = ""
-
- for name, path in modules.items():
- try:
- with open(os.path.join(path, "register_types.h")):
- includes_cpp += '#include "' + path + '/register_types.h"\n'
- initialize_cpp += "#ifdef MODULE_" + name.upper() + "_ENABLED\n"
- initialize_cpp += "\tinitialize_" + name + "_module(p_level);\n"
- initialize_cpp += "#endif\n"
- uninitialize_cpp += "#ifdef MODULE_" + name.upper() + "_ENABLED\n"
- uninitialize_cpp += "\tuninitialize_" + name + "_module(p_level);\n"
- uninitialize_cpp += "#endif\n"
- except OSError:
- pass
-
- modules_cpp = """// register_module_types.gen.cpp
-/* THIS FILE IS GENERATED DO NOT EDIT */
-#include "register_module_types.h"
-
-#include "modules/modules_enabled.gen.h"
-
-%s
-
-void initialize_modules(ModuleInitializationLevel p_level) {
-%s
-}
-
-void uninitialize_modules(ModuleInitializationLevel p_level) {
-%s
-}
-""" % (
- includes_cpp,
- initialize_cpp,
- uninitialize_cpp,
- )
-
- write_file_if_needed("modules/register_module_types.gen.cpp", modules_cpp)
-
-
def convert_custom_modules_path(path):
if not path:
return path
@@ -1649,3 +1522,112 @@ def generate_vs_project(env, original_args, project_name="godot"):
if get_bool(original_args, "vsproj_gen_only", True):
sys.exit()
+
+
+def generate_copyright_header(filename: str) -> str:
+ MARGIN = 70
+ TEMPLATE = """\
+/**************************************************************************/
+/* %s*/
+/**************************************************************************/
+/* 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. */
+/**************************************************************************/
+"""
+ filename = filename.split("/")[-1].ljust(MARGIN)
+ if len(filename) > MARGIN:
+ print(f'WARNING: Filename "{filename}" too large for copyright header.')
+ return TEMPLATE % filename
+
+
+@contextlib.contextmanager
+def generated_wrapper(
+ path, # FIXME: type with `Union[str, Node, List[Node]]` when pytest conflicts are resolved
+ guard: Optional[bool] = None,
+ prefix: str = "",
+ suffix: str = "",
+) -> Generator[TextIOWrapper, None, None]:
+ """
+ Wrapper class to automatically handle copyright headers and header guards
+ for generated scripts. Meant to be invoked via `with` statement similar to
+ creating a file.
+
+ - `path`: The path of the file to be created. Can be passed a raw string, an
+ isolated SCons target, or a full SCons target list. If a target list contains
+ multiple entries, produces a warning & only creates the first entry.
+ - `guard`: Optional bool to determine if a header guard should be added. If
+ unassigned, header guards are determined by the file extension.
+ - `prefix`: Custom prefix to prepend to a header guard. Produces a warning if
+ provided a value when `guard` evaluates to `False`.
+ - `suffix`: Custom suffix to append to a header guard. Produces a warning if
+ provided a value when `guard` evaluates to `False`.
+ """
+
+ # Handle unfiltered SCons target[s] passed as path.
+ if not isinstance(path, str):
+ if isinstance(path, list):
+ if len(path) > 1:
+ print_warning(
+ "Attempting to use generated wrapper with multiple targets; "
+ f"will only use first entry: {path[0]}"
+ )
+ path = path[0]
+ if not hasattr(path, "get_abspath"):
+ raise TypeError(f'Expected type "str", "Node" or "List[Node]"; was passed {type(path)}.')
+ path = path.get_abspath()
+
+ path = str(path).replace("\\", "/")
+ if guard is None:
+ guard = path.endswith((".h", ".hh", ".hpp", ".inc"))
+ if not guard and (prefix or suffix):
+ print_warning(f'Trying to assign header guard prefix/suffix while `guard` is disabled: "{path}".')
+
+ header_guard = ""
+ if guard:
+ if prefix:
+ prefix += "_"
+ if suffix:
+ suffix = f"_{suffix}"
+ split = path.split("/")[-1].split(".")
+ header_guard = (f"{prefix}{split[0]}{suffix}.{'.'.join(split[1:])}".upper()
+ .replace(".", "_").replace("-", "_").replace(" ", "_").replace("__", "_")) # fmt: skip
+
+ with open(path, "wt", encoding="utf-8", newline="\n") as file:
+ file.write(generate_copyright_header(path))
+ file.write("\n/* THIS FILE IS GENERATED. EDITS WILL BE LOST. */\n\n")
+
+ if guard:
+ file.write(f"#ifndef {header_guard}\n")
+ file.write(f"#define {header_guard}\n\n")
+
+ with StringIO(newline="\n") as str_io:
+ yield str_io
+ file.write(str_io.getvalue().strip() or "/* NO CONTENT */")
+
+ if guard:
+ file.write(f"\n\n#endif // {header_guard}")
+
+ file.write("\n")
diff --git a/misc/scripts/codespell.sh b/misc/scripts/codespell.sh
deleted file mode 100755
index ef361a6495..0000000000
--- a/misc/scripts/codespell.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-SKIP_LIST="./.*,./**/.*,./bin,./thirdparty,*.desktop,*.gen.*,*.po,*.pot,*.rc,./AUTHORS.md,./COPYRIGHT.txt,./DONORS.md,"
-SKIP_LIST+="./core/input/gamecontrollerdb.txt,./core/string/locales.h,./editor/renames_map_3_to_4.cpp,./misc/scripts/codespell.sh,"
-SKIP_LIST+="./platform/android/java/lib/src/com,./platform/web/node_modules,./platform/web/package-lock.json,"
-
-IGNORE_LIST="breaked,cancelled,colour,curvelinear,doubleclick,expct,findn,gird,hel,inout,lod,mis,nd,numer,ot,requestor,te,thirdparty,vai"
-
-codespell -w -q 3 -S "${SKIP_LIST}" -L "${IGNORE_LIST}" --builtin "clear,rare,en-GB_to_en-US"
diff --git a/misc/scripts/dotnet_format.py b/misc/scripts/dotnet_format.py
index 83265be7c5..51fd7a1223 100644
--- a/misc/scripts/dotnet_format.py
+++ b/misc/scripts/dotnet_format.py
@@ -5,10 +5,16 @@ import glob
import os
import sys
-# Create dummy generated files.
+if len(sys.argv) < 2:
+ print("Invalid usage of dotnet_format.py, it should be called with a path to one or multiple files.")
+ sys.exit(1)
+
+# Create dummy generated files, if needed.
for path in [
"modules/mono/SdkPackageVersions.props",
]:
+ if os.path.exists(path):
+ continue
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w", encoding="utf-8", newline="\n") as f:
f.write("<Project />")
@@ -17,14 +23,12 @@ for path in [
os.environ["GodotSkipGenerated"] = "true"
# Match all the input files to their respective C# project.
-input_files = [os.path.normpath(x) for x in sys.argv]
projects = {
- path: [f for f in sys.argv if os.path.commonpath([f, path]) == path]
+ path: " ".join([f for f in sys.argv[1:] if os.path.commonpath([f, path]) == path])
for path in [os.path.dirname(f) for f in glob.glob("**/*.csproj", recursive=True)]
}
# Run dotnet format on all projects with more than 0 modified files.
for path, files in projects.items():
- if len(files) > 0:
- command = f"dotnet format {path} --include {' '.join(files)}"
- os.system(command)
+ if files:
+ os.system(f"dotnet format {path} --include {files}")
diff --git a/misc/scripts/file_format.py b/misc/scripts/file_format.py
new file mode 100644
index 0000000000..a4ea544a45
--- /dev/null
+++ b/misc/scripts/file_format.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import sys
+
+if len(sys.argv) < 2:
+ print("Invalid usage of file_format.py, it should be called with a path to one or multiple files.")
+ sys.exit(1)
+
+BOM = b"\xef\xbb\xbf"
+
+changed = []
+invalid = []
+
+for file in sys.argv[1:]:
+ try:
+ with open(file, "rt", encoding="utf-8") as f:
+ original = f.read()
+ except UnicodeDecodeError:
+ invalid.append(file)
+ continue
+
+ if original == "":
+ continue
+
+ EOL = "\r\n" if file.endswith((".csproj", ".sln", ".bat")) or file.startswith("misc/msvs") else "\n"
+ WANTS_BOM = file.endswith((".csproj", ".sln"))
+
+ revamp = EOL.join([line.rstrip("\n\r\t ") for line in original.splitlines(True)]).rstrip(EOL) + EOL
+
+ new_raw = revamp.encode(encoding="utf-8")
+ if not WANTS_BOM and new_raw.startswith(BOM):
+ new_raw = new_raw[len(BOM) :]
+ elif WANTS_BOM and not new_raw.startswith(BOM):
+ new_raw = BOM + new_raw
+
+ with open(file, "rb") as f:
+ old_raw = f.read()
+
+ if old_raw != new_raw:
+ changed.append(file)
+ with open(file, "wb") as f:
+ f.write(new_raw)
+
+if changed:
+ for file in changed:
+ print(f"FIXED: {file}")
+if invalid:
+ for file in invalid:
+ print(f"REQUIRES MANUAL CHANGES: {file}")
+ sys.exit(1)
diff --git a/misc/scripts/file_format.sh b/misc/scripts/file_format.sh
deleted file mode 100755
index ad58657883..0000000000
--- a/misc/scripts/file_format.sh
+++ /dev/null
@@ -1,89 +0,0 @@
-#!/usr/bin/env bash
-
-# This script ensures proper POSIX text file formatting and a few other things.
-# This is supplementary to clang_format.sh and black_format.sh, but should be
-# run before them.
-
-# We need dos2unix and isutf8.
-if [ ! -x "$(command -v dos2unix)" -o ! -x "$(command -v isutf8)" ]; then
- printf "Install 'dos2unix' and 'isutf8' (moreutils package) to use this script.\n"
- exit 1
-fi
-
-set -uo pipefail
-
-if [ $# -eq 0 ]; then
- # Loop through all code files tracked by Git.
- mapfile -d '' files < <(git grep -zIl '')
-else
- # $1 should be a file listing file paths to process. Used in CI.
- mapfile -d ' ' < <(cat "$1")
-fi
-
-for f in "${files[@]}"; do
- # Exclude some types of files.
- if [[ "$f" == *"csproj" ]]; then
- continue
- elif [[ "$f" == *"sln" ]]; then
- continue
- elif [[ "$f" == *".bat" ]]; then
- continue
- elif [[ "$f" == *".out" ]]; then
- # GDScript integration testing files.
- continue
- elif [[ "$f" == *"patch" ]]; then
- continue
- elif [[ "$f" == *"pot" ]]; then
- continue
- elif [[ "$f" == *"po" ]]; then
- continue
- elif [[ "$f" == "thirdparty/"* ]]; then
- continue
- elif [[ "$f" == *"/thirdparty/"* ]]; then
- continue
- elif [[ "$f" == "platform/android/java/lib/src/com/google"* ]]; then
- continue
- elif [[ "$f" == *"-so_wrap."* ]]; then
- continue
- elif [[ "$f" == *".test.txt" ]]; then
- continue
- fi
- # Ensure that files are UTF-8 formatted.
- isutf8 "$f" >> utf8-validation.txt 2>&1
- # Ensure that files have LF line endings and do not contain a BOM.
- dos2unix "$f" 2> /dev/null
- # Remove trailing space characters and ensures that files end
- # with newline characters. -l option handles newlines conveniently.
- perl -i -ple 's/\s*$//g' "$f"
-done
-
-diff=$(git diff --color)
-
-if [ ! -s utf8-validation.txt ] && [ -z "$diff" ] ; then
- # If no UTF-8 violations were collected (the file is empty) and
- # no diff has been generated all is OK, clean up, and exit.
- printf "\e[1;32m*** Files in this commit comply with the file formatting rules.\e[0m\n"
- rm -f utf8-validation.txt
- exit 0
-fi
-
-if [ -s utf8-validation.txt ]
-then
- # If the file has content and is not empty, violations
- # detected, notify the user, clean up, and exit.
- printf "\n\e[1;33m*** The following files contain invalid UTF-8 character sequences:\e[0m\n\n"
- cat utf8-validation.txt
-fi
-
-rm -f utf8-validation.txt
-
-if [ ! -z "$diff" ]
-then
- # A diff has been created, notify the user, clean up, and exit.
- printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n"
- # Perl commands replace trailing spaces with `·` and tabs with `<TAB>`.
- printf "%s\n" "$diff" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="<TAB>" x length($2); sprintf("$1$tabs$3")/ge'
-fi
-
-printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\e[0m\n"
-exit 1
diff --git a/misc/scripts/header_guards.py b/misc/scripts/header_guards.py
new file mode 100644
index 0000000000..b554be5159
--- /dev/null
+++ b/misc/scripts/header_guards.py
@@ -0,0 +1,150 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import sys
+from pathlib import Path
+
+if len(sys.argv) < 2:
+ print("Invalid usage of header_guards.py, it should be called with a path to one or multiple files.")
+ sys.exit(1)
+
+HEADER_CHECK_OFFSET = 30
+HEADER_BEGIN_OFFSET = 31
+HEADER_END_OFFSET = -1
+
+changed = []
+invalid = []
+
+for file in sys.argv[1:]:
+ with open(file, "rt", encoding="utf-8", newline="\n") as f:
+ lines = f.readlines()
+
+ if len(lines) <= HEADER_BEGIN_OFFSET:
+ continue # Most likely a dummy file.
+
+ if lines[HEADER_CHECK_OFFSET].startswith("#import"):
+ continue # Early catch obj-c file.
+
+ split = file.split("/") # Already in posix-format.
+
+ prefix = ""
+ if split[0] == "modules" and split[-1] == "register_types.h":
+ prefix = f"{split[1]}_" # Name of module.
+ elif split[0] == "platform" and (file.endswith("api/api.h") or "/export/" in file):
+ prefix = f"{split[1]}_" # Name of platform.
+ elif file.startswith("modules/mono/utils") and "mono" not in split[-1]:
+ prefix = "MONO_"
+ elif file == "servers/rendering/storage/utilities.h":
+ prefix = "RENDERER_"
+
+ suffix = ""
+ if "dummy" in file and "dummy" not in split[-1]:
+ suffix = "_DUMMY"
+ elif "gles3" in file and "gles3" not in split[-1]:
+ suffix = "_GLES3"
+ elif "renderer_rd" in file and "rd" not in split[-1]:
+ suffix = "_RD"
+ elif split[-1] == "ustring.h":
+ suffix = "_GODOT"
+
+ name = (f"{prefix}{Path(file).stem}{suffix}{Path(file).suffix}".upper()
+ .replace(".", "_").replace("-", "_").replace(" ", "_")) # fmt: skip
+
+ HEADER_CHECK = f"#ifndef {name}\n"
+ HEADER_BEGIN = f"#define {name}\n"
+ HEADER_END = f"#endif // {name}\n"
+
+ if (
+ lines[HEADER_CHECK_OFFSET] == HEADER_CHECK
+ and lines[HEADER_BEGIN_OFFSET] == HEADER_BEGIN
+ and lines[HEADER_END_OFFSET] == HEADER_END
+ ):
+ continue
+
+ # Guards might exist but with the wrong names.
+ if (
+ lines[HEADER_CHECK_OFFSET].startswith("#ifndef")
+ and lines[HEADER_BEGIN_OFFSET].startswith("#define")
+ and lines[HEADER_END_OFFSET].startswith("#endif")
+ ):
+ lines[HEADER_CHECK_OFFSET] = HEADER_CHECK
+ lines[HEADER_BEGIN_OFFSET] = HEADER_BEGIN
+ lines[HEADER_END_OFFSET] = HEADER_END
+ with open(file, "wt", encoding="utf-8", newline="\n") as f:
+ f.writelines(lines)
+ changed.append(file)
+ continue
+
+ header_check = -1
+ header_begin = -1
+ header_end = -1
+ pragma_once = -1
+ objc = False
+
+ for idx, line in enumerate(lines):
+ if not line.startswith("#"):
+ continue
+ elif line.startswith("#ifndef") and header_check == -1:
+ header_check = idx
+ elif line.startswith("#define") and header_begin == -1:
+ header_begin = idx
+ elif line.startswith("#endif") and header_end == -1:
+ header_end = idx
+ elif line.startswith("#pragma once"):
+ pragma_once = idx
+ break
+ elif line.startswith("#import"):
+ objc = True
+ break
+
+ if objc:
+ continue
+
+ if pragma_once != -1:
+ lines.pop(pragma_once)
+ lines.insert(HEADER_CHECK_OFFSET, HEADER_CHECK)
+ lines.insert(HEADER_BEGIN_OFFSET, HEADER_BEGIN)
+ lines.append("\n")
+ lines.append(HEADER_END)
+ with open(file, "wt", encoding="utf-8", newline="\n") as f:
+ f.writelines(lines)
+ changed.append(file)
+ continue
+
+ if header_check == -1 and header_begin == -1 and header_end == -1:
+ # Guards simply didn't exist
+ lines.insert(HEADER_CHECK_OFFSET, HEADER_CHECK)
+ lines.insert(HEADER_BEGIN_OFFSET, HEADER_BEGIN)
+ lines.append("\n")
+ lines.append(HEADER_END)
+ with open(file, "wt", encoding="utf-8", newline="\n") as f:
+ f.writelines(lines)
+ changed.append(file)
+ continue
+
+ if header_check != -1 and header_begin != -1 and header_end != -1:
+ # All prepends "found", see if we can salvage this.
+ if header_check == header_begin - 1 and header_begin < header_end:
+ lines.pop(header_check)
+ lines.pop(header_begin - 1)
+ lines.pop(header_end - 2)
+ if lines[header_end - 3] == "\n":
+ lines.pop(header_end - 3)
+ lines.insert(HEADER_CHECK_OFFSET, HEADER_CHECK)
+ lines.insert(HEADER_BEGIN_OFFSET, HEADER_BEGIN)
+ lines.append("\n")
+ lines.append(HEADER_END)
+ with open(file, "wt", encoding="utf-8", newline="\n") as f:
+ f.writelines(lines)
+ changed.append(file)
+ continue
+
+ invalid.append(file)
+
+if changed:
+ for file in changed:
+ print(f"FIXED: {file}")
+if invalid:
+ for file in invalid:
+ print(f"REQUIRES MANUAL CHANGES: {file}")
+ sys.exit(1)
diff --git a/misc/scripts/header_guards.sh b/misc/scripts/header_guards.sh
deleted file mode 100755
index a79ccd4bee..0000000000
--- a/misc/scripts/header_guards.sh
+++ /dev/null
@@ -1,87 +0,0 @@
-#!/bin/bash
-
-if [ ! -f "version.py" ]; then
- echo "Warning: This script is intended to be run from the root of the Godot repository."
- echo "Some of the paths checks may not work as intended from a different folder."
-fi
-
-if [ $# -eq 0 ]; then
- # Loop through all code files tracked by Git.
- files=$(find -name "thirdparty" -prune -o -name "*.h" -print | sed "s@^\./@@g")
-else
- # $1 should be a file listing file paths to process. Used in CI.
- files=$(cat "$1" | grep -v "thirdparty/" | grep -E "\.h$" | sed "s@^\./@@g")
-fi
-
-files_invalid_guard=""
-
-for file in $files; do
- # Skip *.gen.h and *-so_wrap.h, they're generated.
- if [[ "$file" == *".gen.h" || "$file" == *"-so_wrap.h" ]]; then continue; fi
- # Has important define before normal header guards.
- if [[ "$file" == *"thread.h" || "$file" == *"platform_config.h" || "$file" == *"platform_gl.h" ]]; then continue; fi
- # Obj-C files don't use header guards.
- if grep -q "#import " "$file"; then continue; fi
-
- bname=$(basename $file .h)
-
- # Add custom prefix or suffix for generic filenames with a well-defined namespace.
-
- prefix=
- if [[ "$file" == "modules/"*"/register_types.h" ]]; then
- module=$(echo $file | sed "s@.*modules/\([^/]*\).*@\1@")
- prefix="${module^^}_"
- fi
- if [[ "$file" == "platform/"*"/api/api.h" || "$file" == "platform/"*"/export/"* ]]; then
- platform=$(echo $file | sed "s@.*platform/\([^/]*\).*@\1@")
- prefix="${platform^^}_"
- fi
- if [[ "$file" == "modules/mono/utils/"* && "$bname" != *"mono"* ]]; then prefix="MONO_"; fi
- if [[ "$file" == "servers/rendering/storage/utilities.h" ]]; then prefix="RENDERER_"; fi
-
- suffix=
- if [[ "$file" == *"dummy"* && "$bname" != *"dummy"* ]]; then suffix="_DUMMY"; fi
- if [[ "$file" == *"gles3"* && "$bname" != *"gles3"* ]]; then suffix="_GLES3"; fi
- if [[ "$file" == *"renderer_rd"* && "$bname" != *"rd"* ]]; then suffix="_RD"; fi
- if [[ "$file" == *"ustring.h" ]]; then suffix="_GODOT"; fi
-
- # ^^ is bash builtin for UPPERCASE.
- guard="${prefix}${bname^^}${suffix}_H"
-
- # Replaces guards to use computed name.
- # We also add some \n to make sure there's a proper separation.
- sed -i $file -e "0,/ifndef/s/#ifndef.*/\n#ifndef $guard/"
- sed -i $file -e "0,/define/s/#define.*/#define $guard\n/"
- sed -i $file -e "$ s/#endif.*/\n#endif \/\/ $guard/"
- # Removes redundant \n added before, if they weren't needed.
- sed -i $file -e "/^$/N;/^\n$/D"
-
- # Check that first ifndef (should be header guard) is at the expected position.
- # If not it can mean we have some code before the guard that should be after.
- # "31" is the expected line with the copyright header.
- first_ifndef=$(grep -n -m 1 "ifndef" $file | sed 's/\([0-9]*\).*/\1/')
- if [[ "$first_ifndef" != "31" ]]; then
- files_invalid_guard+="$file\n"
- fi
-done
-
-if [[ ! -z "$files_invalid_guard" ]]; then
- echo -e "The following files were found to have potentially invalid header guard:\n"
- echo -e "$files_invalid_guard"
-fi
-
-diff=$(git diff --color)
-
-# If no diff has been generated all is OK, clean up, and exit.
-if [ -z "$diff" ] ; then
- printf "\e[1;32m*** Files in this commit comply with the header guards formatting rules.\e[0m\n"
- exit 0
-fi
-
-# A diff has been created, notify the user, clean up, and exit.
-printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n"
-# Perl commands replace trailing spaces with `·` and tabs with `<TAB>`.
-printf "%s\n" "$diff" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="<TAB>" x length($2); sprintf("$1$tabs$3")/ge'
-
-printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\e[0m\n"
-exit 1
diff --git a/misc/scripts/mypy_check.sh b/misc/scripts/mypy_check.sh
deleted file mode 100755
index 2a06486d67..0000000000
--- a/misc/scripts/mypy_check.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/env bash
-
-set -uo pipefail
-
-echo -e "Python: mypy static analysis..."
-mypy --config-file=./misc/scripts/mypy.ini .
diff --git a/misc/scripts/pytest_builders.sh b/misc/scripts/pytest_builders.sh
deleted file mode 100755
index eb2ddbcddc..0000000000
--- a/misc/scripts/pytest_builders.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env bash
-set -uo pipefail
-
-echo "Running Python checks for builder system"
-pytest ./tests/python_build
diff --git a/modules/SCsub b/modules/SCsub
index 6fb2aa67f4..739c5de0b5 100644
--- a/modules/SCsub
+++ b/modules/SCsub
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-import modules_builders
+import methods
import os
Import("env")
@@ -12,15 +12,51 @@ env_modules.Append(CPPDEFINES=["GODOT_MODULE"])
Export("env_modules")
-# Header with MODULE_*_ENABLED defines.
-env.Depends("modules_enabled.gen.h", Value(env.module_list))
-env.CommandNoCache(
- "modules_enabled.gen.h",
- Value(env.module_list),
- env.Run(modules_builders.generate_modules_enabled),
+
+def register_module_types_builder(target, source, env):
+ modules = source[0].read()
+ mod_inc = "\n".join([f'#include "{p}/register_types.h"' for p in modules.values()])
+ mod_init = "\n".join(
+ [f"#ifdef MODULE_{n.upper()}_ENABLED\n\tinitialize_{n}_module(p_level);\n#endif" for n in modules.keys()]
+ )
+ mod_uninit = "\n".join(
+ [f"#ifdef MODULE_{n.upper()}_ENABLED\n\tuninitialize_{n}_module(p_level);\n#endif" for n in modules.keys()]
+ )
+ with methods.generated_wrapper(target) as file:
+ file.write(
+ f"""\
+#include "register_module_types.h"
+
+#include "modules/modules_enabled.gen.h"
+
+{mod_inc}
+
+void initialize_modules(ModuleInitializationLevel p_level) {{
+{mod_init}
+}}
+
+void uninitialize_modules(ModuleInitializationLevel p_level) {{
+{mod_uninit}
+}}
+"""
+ )
+
+
+register_module_types = env.CommandNoCache(
+ "register_module_types.gen.cpp", env.Value(env.modules_detected), env.Run(register_module_types_builder)
)
+# Header with MODULE_*_ENABLED defines.
+def modules_enabled_builder(target, source, env):
+ with methods.generated_wrapper(target) as file:
+ for module in source[0].read():
+ file.write(f"#define MODULE_{module.upper()}_ENABLED\n")
+
+
+env.CommandNoCache("modules_enabled.gen.h", env.Value(env.module_list), env.Run(modules_enabled_builder))
+
+
vs_sources = []
test_headers = []
# libmodule_<name>.a for each active module.
@@ -47,18 +83,19 @@ for name, path in env.module_list.items():
# Generate header to be included in `tests/test_main.cpp` to run module-specific tests.
if env["tests"]:
- env.Depends("modules_tests.gen.h", test_headers)
- env.CommandNoCache(
- "modules_tests.gen.h",
- test_headers,
- env.Run(modules_builders.generate_modules_tests),
- )
+
+ def modules_tests_builder(target, source, env):
+ with methods.generated_wrapper(target) as file:
+ for header in source:
+ file.write('#include "{}"\n'.format(os.path.normpath(header.path).replace("\\", "/")))
+
+ env.CommandNoCache("modules_tests.gen.h", test_headers, env.Run(modules_tests_builder))
# libmodules.a with only register_module_types.
# Must be last so that all libmodule_<name>.a libraries are on the right side
# in the linker command.
env.modules_sources = []
-env_modules.add_source_files(env.modules_sources, "register_module_types.gen.cpp")
+env_modules.add_source_files(env.modules_sources, register_module_types)
lib = env_modules.add_library("modules", env.modules_sources)
env.Prepend(LIBS=[lib])
if env["vsproj"]:
diff --git a/modules/modules_builders.py b/modules/modules_builders.py
deleted file mode 100644
index 5db7c88a90..0000000000
--- a/modules/modules_builders.py
+++ /dev/null
@@ -1,15 +0,0 @@
-"""Functions used to generate source files during build time"""
-
-
-def generate_modules_enabled(target, source, env):
- with open(target[0].path, "w", encoding="utf-8", newline="\n") as f:
- for module in env.module_list:
- f.write("#define %s\n" % ("MODULE_" + module.upper() + "_ENABLED"))
-
-
-def generate_modules_tests(target, source, env):
- import os
-
- with open(target[0].path, "w", encoding="utf-8", newline="\n") as f:
- for header in source:
- f.write('#include "%s"\n' % (os.path.normpath(header.path)))
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index ff2ca9f0ce..36c8a40ed9 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -1596,14 +1596,7 @@ void CSharpInstance::get_method_list(List<MethodInfo> *p_list) const {
return;
}
- const CSharpScript *top = script.ptr();
- while (top != nullptr) {
- for (const CSharpScript::CSharpMethodInfo &E : top->methods) {
- p_list->push_back(E.method_info);
- }
-
- top = top->base_script.ptr();
- }
+ script->get_script_method_list(p_list);
}
bool CSharpInstance::has_method(const StringName &p_method) const {
@@ -1771,16 +1764,19 @@ void CSharpInstance::mono_object_disposed_baseref(GCHandleIntPtr p_gchandle_to_f
}
void CSharpInstance::connect_event_signals() {
- // The script signals list includes the signals declared in base scripts.
- for (CSharpScript::EventSignalInfo &signal : script->get_script_event_signals()) {
- String signal_name = signal.name;
+ const CSharpScript *top = script.ptr();
+ while (top != nullptr && top->valid) {
+ for (const CSharpScript::EventSignalInfo &signal : top->event_signals) {
+ String signal_name = signal.name;
- // TODO: Use pooling for ManagedCallable instances.
- EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, signal_name));
+ // TODO: Use pooling for ManagedCallable instances.
+ EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, signal_name));
- Callable callable(event_signal_callable);
- connected_event_signals.push_back(callable);
- owner->connect(signal_name, callable);
+ Callable callable(event_signal_callable);
+ connected_event_signals.push_back(callable);
+ owner->connect(signal_name, callable);
+ }
+ top = top->base_script.ptr();
}
}
@@ -2624,25 +2620,33 @@ bool CSharpScript::has_script_signal(const StringName &p_signal) const {
}
}
+ if (base_script.is_valid()) {
+ return base_script->has_script_signal(p_signal);
+ }
+
return false;
}
-void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
+void CSharpScript::_get_script_signal_list(List<MethodInfo> *r_signals, bool p_include_base) const {
if (!valid) {
return;
}
- for (const EventSignalInfo &signal : get_script_event_signals()) {
+ for (const EventSignalInfo &signal : event_signals) {
r_signals->push_back(signal.method_info);
}
-}
-Vector<CSharpScript::EventSignalInfo> CSharpScript::get_script_event_signals() const {
- if (!valid) {
- return Vector<EventSignalInfo>();
+ if (!p_include_base) {
+ return;
+ }
+
+ if (base_script.is_valid()) {
+ base_script->get_script_signal_list(r_signals);
}
+}
- return event_signals;
+void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
+ _get_script_signal_list(r_signals, true);
}
bool CSharpScript::inherits_script(const Ref<Script> &p_script) const {
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 17df3988ee..c48e1a95c9 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -215,6 +215,8 @@ private:
// Do not use unless you know what you are doing
static void update_script_class_info(Ref<CSharpScript> p_script);
+ void _get_script_signal_list(List<MethodInfo> *r_signals, bool p_include_base) const;
+
protected:
static void _bind_methods();
@@ -251,8 +253,6 @@ public:
bool has_script_signal(const StringName &p_signal) const override;
void get_script_signal_list(List<MethodInfo> *r_signals) const override;
- Vector<EventSignalInfo> get_script_event_signals() const;
-
bool get_property_default_value(const StringName &p_property, Variant &r_value) const override;
void get_script_property_list(List<PropertyInfo> *r_list) const override;
void update_exports() override;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
index 1b23276bbd..eef26cdd4e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
@@ -798,17 +798,17 @@ namespace Godot.Bridge
GetScriptTypeInfo(scriptType, outTypeInfo);
+ Type native = GodotObject.InternalGetClassNativeBase(scriptType);
+
// Methods
// Performance is not critical here as this will be replaced with source generators.
using var methods = new Collections.Array();
Type? top = scriptType;
- Type native = GodotObject.InternalGetClassNativeBase(top);
-
- while (top != null && top != native)
+ if (scriptType != native)
{
- var methodList = GetMethodListForType(top);
+ var methodList = GetMethodListForType(scriptType);
if (methodList != null)
{
@@ -859,8 +859,6 @@ namespace Godot.Bridge
methods.Add(methodInfo);
}
}
-
- top = top.BaseType;
}
*outMethodsDest = NativeFuncs.godotsharp_array_new_copy(
@@ -912,11 +910,9 @@ namespace Godot.Bridge
// Performance is not critical here as this will be replaced with source generators.
using var signals = new Collections.Dictionary();
- top = scriptType;
-
- while (top != null && top != native)
+ if (scriptType != native)
{
- var signalList = GetSignalListForType(top);
+ var signalList = GetSignalListForType(scriptType);
if (signalList != null)
{
@@ -951,8 +947,6 @@ namespace Godot.Bridge
signals.Add(signalName, signalParams);
}
}
-
- top = top.BaseType;
}
*outEventSignalsDest = NativeFuncs.godotsharp_dictionary_new_copy(
diff --git a/platform/SCsub b/platform/SCsub
index ca282e3e68..b24c189848 100644
--- a/platform/SCsub
+++ b/platform/SCsub
@@ -1,27 +1,64 @@
#!/usr/bin/env python
import methods
+from glob import glob
+from pathlib import Path
Import("env")
env.platform_sources = []
+
+# Generate export icons
+def export_icon_builder(target, source, env):
+ src_path = Path(str(source[0]))
+ src_name = src_path.stem
+ platform = src_path.parent.parent.stem
+ with open(str(source[0]), "rb") as file:
+ svg = "".join([f"\\{hex(x)[1:]}" for x in file.read()])
+ with methods.generated_wrapper(target, prefix=platform) as file:
+ file.write(
+ f"""\
+static const char *_{platform}_{src_name}_svg = "{svg}";
+"""
+ )
+
+
+for platform in env.platform_exporters:
+ for path in glob(f"{platform}/export/*.svg"):
+ env.CommandNoCache(path.replace(".svg", "_svg.gen.h"), path, env.Run(export_icon_builder))
+
+
# Register platform-exclusive APIs
-reg_apis_inc = '#include "register_platform_apis.h"\n'
-reg_apis = "void register_platform_apis() {\n"
-unreg_apis = "void unregister_platform_apis() {\n"
+def register_platform_apis_builder(target, source, env):
+ platforms = source[0].read()
+ api_inc = "\n".join([f'#include "{p}/api/api.h"' for p in platforms])
+ api_reg = "\n".join([f"\tregister_{p}_api();" for p in platforms])
+ api_unreg = "\n".join([f"\tunregister_{p}_api();" for p in platforms])
+ with methods.generated_wrapper(target) as file:
+ file.write(
+ f"""\
+#include "register_platform_apis.h"
+
+{api_inc}
+
+void register_platform_apis() {{
+{api_reg}
+}}
+
+void unregister_platform_apis() {{
+{api_unreg}
+}}
+"""
+ )
+
+
+register_platform_apis = env.CommandNoCache(
+ "register_platform_apis.gen.cpp", env.Value(env.platform_apis), env.Run(register_platform_apis_builder)
+)
+env.add_source_files(env.platform_sources, register_platform_apis)
for platform in env.platform_apis:
- platform_dir = env.Dir(platform)
- env.add_source_files(env.platform_sources, platform + "/api/api.cpp")
- reg_apis += "\tregister_" + platform + "_api();\n"
- unreg_apis += "\tunregister_" + platform + "_api();\n"
- reg_apis_inc += '#include "' + platform + '/api/api.h"\n'
-reg_apis_inc += "\n"
-reg_apis += "}\n\n"
-unreg_apis += "}\n"
-
-methods.write_file_if_needed("register_platform_apis.gen.cpp", reg_apis_inc + reg_apis + unreg_apis)
-env.add_source_files(env.platform_sources, "register_platform_apis.gen.cpp")
+ env.add_source_files(env.platform_sources, f"{platform}/api/api.cpp")
lib = env.add_library("platform", env.platform_sources)
env.Prepend(LIBS=[lib])
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index b76cbc126f..9174b65b1b 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -4268,6 +4268,8 @@ bool DisplayServerX11::_window_focus_check() {
}
void DisplayServerX11::process_events() {
+ ERR_FAIL_COND(!Thread::is_main_thread());
+
_THREAD_SAFE_LOCK_
#ifdef DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 0041848c78..e093f01a8a 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -2985,7 +2985,7 @@ Key DisplayServerMacOS::keyboard_get_label_from_physical(Key p_keycode) const {
}
void DisplayServerMacOS::process_events() {
- _THREAD_SAFE_LOCK_
+ ERR_FAIL_COND(!Thread::is_main_thread());
while (true) {
NSEvent *event = [NSApp
@@ -3018,11 +3018,11 @@ void DisplayServerMacOS::process_events() {
if (!drop_events) {
_process_key_events();
- _THREAD_SAFE_UNLOCK_
Input::get_singleton()->flush_buffered_events();
- _THREAD_SAFE_LOCK_
}
+ _THREAD_SAFE_LOCK_
+
for (KeyValue<WindowID, WindowData> &E : windows) {
WindowData &wd = E.value;
if (wd.mpass) {
@@ -3051,7 +3051,7 @@ void DisplayServerMacOS::process_events() {
}
void DisplayServerMacOS::force_process_and_drop_events() {
- _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND(!Thread::is_main_thread());
drop_events = true;
process_events();
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index ccf889f1a3..93eb34001e 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -18,30 +18,36 @@ def get_name():
return "Windows"
-def get_mingw_tool(tool, prefix="", arch="", test="--version"):
- if not prefix:
- prefix = os.getenv("MINGW_PREFIX", "")
- supported_arches = ["x86_64", "x86_32", "arm64", "arm32"]
- if arch in supported_arches:
- arches = [arch, ""]
- else:
- arches = ["x86_64", "x86_32", "arm64", "arm32", ""]
- for a in arches:
+def try_cmd(test, prefix, arch):
+ if arch:
try:
- path = f"{get_mingw_bin_prefix(prefix, a)}{tool}"
out = subprocess.Popen(
- f"{path} {test}",
+ get_mingw_bin_prefix(prefix, arch) + test,
shell=True,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
)
out.communicate()
if out.returncode == 0:
- return path
+ return True
except Exception:
pass
+ else:
+ for a in ["x86_64", "x86_32", "arm64", "arm32"]:
+ try:
+ out = subprocess.Popen(
+ get_mingw_bin_prefix(prefix, a) + test,
+ shell=True,
+ stderr=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ )
+ out.communicate()
+ if out.returncode == 0:
+ return True
+ except Exception:
+ pass
- return ""
+ return False
def can_build():
@@ -59,7 +65,9 @@ def can_build():
if os.name == "posix":
# Cross-compiling with MinGW-w64 (old MinGW32 is not supported)
- if get_mingw_tool("gcc") or get_mingw_tool("clang"):
+ prefix = os.getenv("MINGW_PREFIX", "")
+
+ if try_cmd("gcc --version", prefix, "") or try_cmd("clang --version", prefix, ""):
return True
return False
@@ -247,26 +255,36 @@ def get_flags():
def build_res_file(target, source, env: "SConsEnvironment"):
- cmdbase = get_mingw_tool("windres", env["mingw_prefix"], env["arch"])
- if not cmdbase:
- return -1
-
arch_aliases = {
"x86_32": "pe-i386",
"x86_64": "pe-x86-64",
"arm32": "armv7-w64-mingw32",
"arm64": "aarch64-w64-mingw32",
}
- cmdbase += " --include-dir . --target=" + arch_aliases[env["arch"]]
+ cmdbase = "windres --include-dir . --target=" + arch_aliases[env["arch"]]
+
+ mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"])
for x in range(len(source)):
- cmd = f"{cmdbase} -i {source[x]} -o {target[x]}"
+ ok = True
+ # Try prefixed executable (MinGW on Linux).
+ cmd = mingw_bin_prefix + cmdbase + " -i " + str(source[x]) + " -o " + str(target[x])
try:
out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
if len(out[1]):
- return -1
+ ok = False
except Exception:
- return -1
+ ok = False
+
+ # Try generic executable (MSYS2).
+ if not ok:
+ cmd = cmdbase + " -i " + str(source[x]) + " -o " + str(target[x])
+ try:
+ out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
+ if len(out[1]):
+ return -1
+ except Exception:
+ return -1
return 0
@@ -340,8 +358,8 @@ def setup_mingw(env: "SConsEnvironment"):
)
sys.exit(255)
- if not get_mingw_tool("gcc", env["mingw_prefix"], env["arch"]) and not get_mingw_tool(
- "clang", env["mingw_prefix"], env["arch"]
+ if not try_cmd("gcc --version", env["mingw_prefix"], env["arch"]) and not try_cmd(
+ "clang --version", env["mingw_prefix"], env["arch"]
):
print_error("No valid compilers found, use MINGW_PREFIX environment variable to set MinGW path.")
sys.exit(255)
@@ -582,10 +600,10 @@ def configure_mingw(env: "SConsEnvironment"):
## Build type
- if not env["use_llvm"] and not get_mingw_tool("gcc", env["mingw_prefix"], env["arch"]):
+ if not env["use_llvm"] and not try_cmd("gcc --version", env["mingw_prefix"], env["arch"]):
env["use_llvm"] = True
- if env["use_llvm"] and not get_mingw_tool("clang", env["mingw_prefix"], env["arch"]):
+ if env["use_llvm"] and not try_cmd("clang --version", env["mingw_prefix"], env["arch"]):
env["use_llvm"] = False
# TODO: Re-evaluate the need for this / streamline with common config.
@@ -620,26 +638,27 @@ def configure_mingw(env: "SConsEnvironment"):
if env["arch"] in ["x86_32", "x86_64"]:
env["x86_libtheora_opt_gcc"] = True
+ mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"])
+
if env["use_llvm"]:
- env["CC"] = get_mingw_tool("clang", env["mingw_prefix"], env["arch"])
- env["CXX"] = get_mingw_tool("clang++", env["mingw_prefix"], env["arch"])
- tool_as = get_mingw_tool("as", env["mingw_prefix"], env["arch"])
- tool_ar = get_mingw_tool("ar", env["mingw_prefix"], env["arch"])
- tool_ranlib = get_mingw_tool("ranlib", env["mingw_prefix"], env["arch"])
+ env["CC"] = mingw_bin_prefix + "clang"
+ env["CXX"] = mingw_bin_prefix + "clang++"
+ if try_cmd("as --version", env["mingw_prefix"], env["arch"]):
+ env["AS"] = mingw_bin_prefix + "as"
+ if try_cmd("ar --version", env["mingw_prefix"], env["arch"]):
+ env["AR"] = mingw_bin_prefix + "ar"
+ if try_cmd("ranlib --version", env["mingw_prefix"], env["arch"]):
+ env["RANLIB"] = mingw_bin_prefix + "ranlib"
env.extra_suffix = ".llvm" + env.extra_suffix
else:
- env["CC"] = get_mingw_tool("gcc", env["mingw_prefix"], env["arch"])
- env["CXX"] = get_mingw_tool("g++", env["mingw_prefix"], env["arch"])
- tool_as = get_mingw_tool("as", env["mingw_prefix"], env["arch"])
- tool_ar = get_mingw_tool("gcc-ar", env["mingw_prefix"], env["arch"])
- tool_ranlib = get_mingw_tool("gcc-ranlib", env["mingw_prefix"], env["arch"])
-
- if tool_as:
- env["AS"] = tool_as
- if tool_ar:
- env["AR"] = tool_ar
- if tool_ranlib:
- env["RANLIB"] = tool_ranlib
+ env["CC"] = mingw_bin_prefix + "gcc"
+ env["CXX"] = mingw_bin_prefix + "g++"
+ if try_cmd("as --version", env["mingw_prefix"], env["arch"]):
+ env["AS"] = mingw_bin_prefix + "as"
+ if try_cmd("gcc-ar --version", env["mingw_prefix"], env["arch"]):
+ env["AR"] = mingw_bin_prefix + "gcc-ar"
+ if try_cmd("gcc-ranlib --version", env["mingw_prefix"], env["arch"]):
+ env["RANLIB"] = mingw_bin_prefix + "gcc-ranlib"
## LTO
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 94c368c504..e79d16629e 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -2962,30 +2962,28 @@ String DisplayServerWindows::keyboard_get_layout_name(int p_index) const {
}
void DisplayServerWindows::process_events() {
- _THREAD_SAFE_LOCK_
-
- MSG msg;
+ ERR_FAIL_COND(!Thread::is_main_thread());
if (!drop_events) {
joypad->process_joypads();
}
+ _THREAD_SAFE_LOCK_
+ MSG msg = {};
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
+ _THREAD_SAFE_UNLOCK_
if (!drop_events) {
_process_key_events();
- _THREAD_SAFE_UNLOCK_
Input::get_singleton()->flush_buffered_events();
- } else {
- _THREAD_SAFE_UNLOCK_
}
}
void DisplayServerWindows::force_process_and_drop_events() {
- _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND(!Thread::is_main_thread());
drop_events = true;
process_events();
@@ -4664,10 +4662,12 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
} break;
case WM_TIMER: {
if (wParam == windows[window_id].move_timer_id) {
+ _THREAD_SAFE_UNLOCK_
_process_key_events();
if (!Main::is_iterating()) {
Main::iteration();
}
+ _THREAD_SAFE_LOCK_
} else if (wParam == windows[window_id].activate_timer_id) {
_process_activate_event(window_id);
KillTimer(windows[window_id].hWnd, windows[window_id].activate_timer_id);
diff --git a/platform/windows/platform_windows_builders.py b/platform/windows/platform_windows_builders.py
index dd480571ba..729d55cea6 100644
--- a/platform/windows/platform_windows_builders.py
+++ b/platform/windows/platform_windows_builders.py
@@ -1,20 +1,24 @@
"""Functions used to generate source files during build time"""
import os
-from detect import get_mingw_tool
+from detect import get_mingw_bin_prefix
+from detect import try_cmd
def make_debug_mingw(target, source, env):
dst = str(target[0])
# Force separate debug symbols if executable size is larger than 1.9 GB.
if env["separate_debug_symbols"] or os.stat(dst).st_size >= 2040109465:
- objcopy = get_mingw_tool("objcopy", env["mingw_prefix"], env["arch"])
- strip = get_mingw_tool("strip", env["mingw_prefix"], env["arch"])
-
- if not objcopy or not strip:
- print('`separate_debug_symbols` requires both "objcopy" and "strip" to function.')
- return
-
- os.system("{0} --only-keep-debug {1} {1}.debugsymbols".format(objcopy, dst))
- os.system("{0} --strip-debug --strip-unneeded {1}".format(strip, dst))
- os.system("{0} --add-gnu-debuglink={1}.debugsymbols {1}".format(objcopy, dst))
+ mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"])
+ if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]):
+ os.system(mingw_bin_prefix + "objcopy --only-keep-debug {0} {0}.debugsymbols".format(dst))
+ else:
+ os.system("objcopy --only-keep-debug {0} {0}.debugsymbols".format(dst))
+ if try_cmd("strip --version", env["mingw_prefix"], env["arch"]):
+ os.system(mingw_bin_prefix + "strip --strip-debug --strip-unneeded {0}".format(dst))
+ else:
+ os.system("strip --strip-debug --strip-unneeded {0}".format(dst))
+ if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]):
+ os.system(mingw_bin_prefix + "objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(dst))
+ else:
+ os.system("objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(dst))
diff --git a/platform_methods.py b/platform_methods.py
index 57b11d1a47..5326e36077 100644
--- a/platform_methods.py
+++ b/platform_methods.py
@@ -43,33 +43,6 @@ def detect_arch():
return "x86_64"
-def generate_export_icons(platform_path, platform_name):
- """
- Generate headers for logo and run icon for the export plugin.
- """
- export_path = platform_path + "/export"
- svg_names = []
- if os.path.isfile(export_path + "/logo.svg"):
- svg_names.append("logo")
- if os.path.isfile(export_path + "/run_icon.svg"):
- svg_names.append("run_icon")
-
- for name in svg_names:
- with open(export_path + "/" + name + ".svg", "rb") as svgf:
- b = svgf.read(1)
- svg_str = " /* AUTOGENERATED FILE, DO NOT EDIT */ \n"
- svg_str += " static const char *_" + platform_name + "_" + name + '_svg = "'
- while len(b) == 1:
- svg_str += "\\" + hex(ord(b))[1:]
- b = svgf.read(1)
-
- svg_str += '";\n'
-
- wf = export_path + "/" + name + "_svg.gen.h"
-
- methods.write_file_if_needed(wf, svg_str)
-
-
def get_build_version(short):
import version
diff --git a/scene/3d/skeleton_modifier_3d.cpp b/scene/3d/skeleton_modifier_3d.cpp
index 96e3e33841..8d806ef5fc 100644
--- a/scene/3d/skeleton_modifier_3d.cpp
+++ b/scene/3d/skeleton_modifier_3d.cpp
@@ -110,7 +110,7 @@ void SkeletonModifier3D::process_modification() {
}
void SkeletonModifier3D::_process_modification() {
- //
+ GDVIRTUAL_CALL(_process_modification);
}
void SkeletonModifier3D::_notification(int p_what) {
@@ -133,6 +133,7 @@ void SkeletonModifier3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "influence", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_influence", "get_influence");
ADD_SIGNAL(MethodInfo("modification_processed"));
+ GDVIRTUAL_BIND(_process_modification);
}
SkeletonModifier3D::SkeletonModifier3D() {
diff --git a/scene/3d/skeleton_modifier_3d.h b/scene/3d/skeleton_modifier_3d.h
index 25c09f3b93..d00a1e94a9 100644
--- a/scene/3d/skeleton_modifier_3d.h
+++ b/scene/3d/skeleton_modifier_3d.h
@@ -60,6 +60,7 @@ protected:
virtual void _set_active(bool p_active);
virtual void _process_modification();
+ GDVIRTUAL0(_process_modification);
public:
virtual PackedStringArray get_configuration_warnings() const override;
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 6fac096c93..de94327d79 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -589,7 +589,7 @@ void register_scene_types() {
GDREGISTER_CLASS(CPUParticles3D);
GDREGISTER_CLASS(Marker3D);
GDREGISTER_CLASS(RootMotionView);
- GDREGISTER_ABSTRACT_CLASS(SkeletonModifier3D);
+ GDREGISTER_VIRTUAL_CLASS(SkeletonModifier3D);
OS::get_singleton()->yield(); // may take time to init
diff --git a/scene/resources/audio_stream_wav.cpp b/scene/resources/audio_stream_wav.cpp
index ba5dad088f..db2564af22 100644
--- a/scene/resources/audio_stream_wav.cpp
+++ b/scene/resources/audio_stream_wav.cpp
@@ -542,7 +542,7 @@ double AudioStreamWAV::get_length() const {
break;
case AudioStreamWAV::FORMAT_QOA:
qoa_desc desc = { 0, 0, 0, { { { 0 }, { 0 } } } };
- qoa_decode_header((uint8_t *)data + DATA_PAD, QOA_MIN_FILESIZE, &desc);
+ qoa_decode_header((uint8_t *)data + DATA_PAD, data_bytes, &desc);
len = desc.samples * desc.channels;
}
@@ -681,7 +681,8 @@ Ref<AudioStreamPlayback> AudioStreamWAV::instantiate_playback() {
if (format == AudioStreamWAV::FORMAT_QOA) {
sample->qoa.desc = (qoa_desc *)memalloc(sizeof(qoa_desc));
- qoa_decode_header((uint8_t *)data + DATA_PAD, QOA_MIN_FILESIZE, sample->qoa.desc);
+ uint32_t ffp = qoa_decode_header((uint8_t *)data + DATA_PAD, data_bytes, sample->qoa.desc);
+ ERR_FAIL_COND_V(ffp != 8, Ref<AudioStreamPlaybackWAV>());
sample->qoa.frame_len = qoa_max_frame_size(sample->qoa.desc);
int samples_len = (sample->qoa.desc->samples > QOA_FRAME_LEN ? QOA_FRAME_LEN : sample->qoa.desc->samples);
int alloc_len = sample->qoa.desc->channels * samples_len * sizeof(int16_t);
diff --git a/servers/physics_server_2d_wrap_mt.cpp b/servers/physics_server_2d_wrap_mt.cpp
index 4548bb91cb..8e9f7aa8fc 100644
--- a/servers/physics_server_2d_wrap_mt.cpp
+++ b/servers/physics_server_2d_wrap_mt.cpp
@@ -32,45 +32,37 @@
#include "core/os/os.h"
-void PhysicsServer2DWrapMT::thread_exit() {
- exit = true;
+void PhysicsServer2DWrapMT::_assign_mt_ids(WorkerThreadPool::TaskID p_pump_task_id) {
+ server_thread = Thread::get_caller_id();
+ server_task_id = p_pump_task_id;
}
-void PhysicsServer2DWrapMT::thread_step(real_t p_delta) {
- physics_server_2d->step(p_delta);
- step_sem.post();
+void PhysicsServer2DWrapMT::_thread_exit() {
+ exit = true;
}
-void PhysicsServer2DWrapMT::thread_loop() {
- server_thread = Thread::get_caller_id();
-
- physics_server_2d->init();
-
- command_queue.set_pump_task_id(server_task_id);
+void PhysicsServer2DWrapMT::_thread_loop() {
while (!exit) {
WorkerThreadPool::get_singleton()->yield();
command_queue.flush_all();
}
-
- command_queue.flush_all();
-
- physics_server_2d->finish();
}
/* EVENT QUEUING */
void PhysicsServer2DWrapMT::step(real_t p_step) {
if (create_thread) {
- command_queue.push(this, &PhysicsServer2DWrapMT::thread_step, p_step);
+ command_queue.push(physics_server_2d, &PhysicsServer2D::step, p_step);
} else {
- command_queue.flush_all(); // Flush all pending from other threads.
physics_server_2d->step(p_step);
}
}
void PhysicsServer2DWrapMT::sync() {
if (create_thread) {
- step_sem.wait();
+ command_queue.sync();
+ } else {
+ command_queue.flush_all(); // Flush all pending from other threads.
}
physics_server_2d->sync();
}
@@ -85,21 +77,26 @@ void PhysicsServer2DWrapMT::end_sync() {
void PhysicsServer2DWrapMT::init() {
if (create_thread) {
- exit = false;
- server_task_id = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &PhysicsServer2DWrapMT::thread_loop), true);
- step_sem.post();
+ WorkerThreadPool::TaskID tid = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &PhysicsServer2DWrapMT::_thread_loop), true);
+ command_queue.set_pump_task_id(tid);
+ command_queue.push(this, &PhysicsServer2DWrapMT::_assign_mt_ids, tid);
+ command_queue.push_and_sync(physics_server_2d, &PhysicsServer2D::init);
+ DEV_ASSERT(server_task_id == tid);
} else {
+ server_thread = Thread::MAIN_ID;
physics_server_2d->init();
}
}
void PhysicsServer2DWrapMT::finish() {
if (create_thread) {
- command_queue.push(this, &PhysicsServer2DWrapMT::thread_exit);
+ command_queue.push(physics_server_2d, &PhysicsServer2D::finish);
+ command_queue.push(this, &PhysicsServer2DWrapMT::_thread_exit);
if (server_task_id != WorkerThreadPool::INVALID_TASK_ID) {
WorkerThreadPool::get_singleton()->wait_for_task_completion(server_task_id);
server_task_id = WorkerThreadPool::INVALID_TASK_ID;
}
+ server_thread = Thread::MAIN_ID;
} else {
physics_server_2d->finish();
}
@@ -108,9 +105,6 @@ void PhysicsServer2DWrapMT::finish() {
PhysicsServer2DWrapMT::PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool p_create_thread) {
physics_server_2d = p_contained;
create_thread = p_create_thread;
- if (!create_thread) {
- server_thread = Thread::MAIN_ID;
- }
}
PhysicsServer2DWrapMT::~PhysicsServer2DWrapMT() {
diff --git a/servers/physics_server_2d_wrap_mt.h b/servers/physics_server_2d_wrap_mt.h
index 5e2b3b4086..f0c36a906f 100644
--- a/servers/physics_server_2d_wrap_mt.h
+++ b/servers/physics_server_2d_wrap_mt.h
@@ -53,17 +53,14 @@ class PhysicsServer2DWrapMT : public PhysicsServer2D {
mutable CommandQueueMT command_queue;
- void thread_loop();
-
Thread::ID server_thread = Thread::UNASSIGNED_ID;
WorkerThreadPool::TaskID server_task_id = WorkerThreadPool::INVALID_TASK_ID;
bool exit = false;
- Semaphore step_sem;
bool create_thread = false;
- void thread_step(real_t p_delta);
-
- void thread_exit();
+ void _assign_mt_ids(WorkerThreadPool::TaskID p_pump_task_id);
+ void _thread_exit();
+ void _thread_loop();
public:
#define ServerName PhysicsServer2D
diff --git a/servers/physics_server_3d_wrap_mt.cpp b/servers/physics_server_3d_wrap_mt.cpp
index f8f60281a7..95b71217c4 100644
--- a/servers/physics_server_3d_wrap_mt.cpp
+++ b/servers/physics_server_3d_wrap_mt.cpp
@@ -32,45 +32,37 @@
#include "core/os/os.h"
-void PhysicsServer3DWrapMT::thread_exit() {
- exit = true;
+void PhysicsServer3DWrapMT::_assign_mt_ids(WorkerThreadPool::TaskID p_pump_task_id) {
+ server_thread = Thread::get_caller_id();
+ server_task_id = p_pump_task_id;
}
-void PhysicsServer3DWrapMT::thread_step(real_t p_delta) {
- physics_server_3d->step(p_delta);
- step_sem.post();
+void PhysicsServer3DWrapMT::_thread_exit() {
+ exit = true;
}
-void PhysicsServer3DWrapMT::thread_loop() {
- server_thread = Thread::get_caller_id();
-
- physics_server_3d->init();
-
- command_queue.set_pump_task_id(server_task_id);
+void PhysicsServer3DWrapMT::_thread_loop() {
while (!exit) {
WorkerThreadPool::get_singleton()->yield();
command_queue.flush_all();
}
-
- command_queue.flush_all(); // flush all
-
- physics_server_3d->finish();
}
/* EVENT QUEUING */
void PhysicsServer3DWrapMT::step(real_t p_step) {
if (create_thread) {
- command_queue.push(this, &PhysicsServer3DWrapMT::thread_step, p_step);
+ command_queue.push(physics_server_3d, &PhysicsServer3D::step, p_step);
} else {
- command_queue.flush_all(); // Flush all pending from other threads.
physics_server_3d->step(p_step);
}
}
void PhysicsServer3DWrapMT::sync() {
if (create_thread) {
- step_sem.wait();
+ command_queue.sync();
+ } else {
+ command_queue.flush_all(); // Flush all pending from other threads.
}
physics_server_3d->sync();
}
@@ -85,21 +77,26 @@ void PhysicsServer3DWrapMT::end_sync() {
void PhysicsServer3DWrapMT::init() {
if (create_thread) {
- exit = false;
- server_task_id = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &PhysicsServer3DWrapMT::thread_loop), true);
- step_sem.post();
+ WorkerThreadPool::TaskID tid = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &PhysicsServer3DWrapMT::_thread_loop), true);
+ command_queue.set_pump_task_id(tid);
+ command_queue.push(this, &PhysicsServer3DWrapMT::_assign_mt_ids, tid);
+ command_queue.push_and_sync(physics_server_3d, &PhysicsServer3D::init);
+ DEV_ASSERT(server_task_id == tid);
} else {
+ server_thread = Thread::MAIN_ID;
physics_server_3d->init();
}
}
void PhysicsServer3DWrapMT::finish() {
if (create_thread) {
- command_queue.push(this, &PhysicsServer3DWrapMT::thread_exit);
+ command_queue.push(physics_server_3d, &PhysicsServer3D::finish);
+ command_queue.push(this, &PhysicsServer3DWrapMT::_thread_exit);
if (server_task_id != WorkerThreadPool::INVALID_TASK_ID) {
WorkerThreadPool::get_singleton()->wait_for_task_completion(server_task_id);
server_task_id = WorkerThreadPool::INVALID_TASK_ID;
}
+ server_thread = Thread::MAIN_ID;
} else {
physics_server_3d->finish();
}
@@ -108,9 +105,6 @@ void PhysicsServer3DWrapMT::finish() {
PhysicsServer3DWrapMT::PhysicsServer3DWrapMT(PhysicsServer3D *p_contained, bool p_create_thread) {
physics_server_3d = p_contained;
create_thread = p_create_thread;
- if (!create_thread) {
- server_thread = Thread::MAIN_ID;
- }
}
PhysicsServer3DWrapMT::~PhysicsServer3DWrapMT() {
diff --git a/servers/physics_server_3d_wrap_mt.h b/servers/physics_server_3d_wrap_mt.h
index 22f3ee0e45..0909c46b55 100644
--- a/servers/physics_server_3d_wrap_mt.h
+++ b/servers/physics_server_3d_wrap_mt.h
@@ -52,17 +52,15 @@ class PhysicsServer3DWrapMT : public PhysicsServer3D {
mutable CommandQueueMT command_queue;
- void thread_loop();
-
Thread::ID server_thread = Thread::UNASSIGNED_ID;
WorkerThreadPool::TaskID server_task_id = WorkerThreadPool::INVALID_TASK_ID;
bool exit = false;
- Semaphore step_sem;
bool create_thread = false;
- void thread_step(real_t p_delta);
-
- void thread_exit();
+ void _assign_mt_ids(WorkerThreadPool::TaskID p_pump_task_id);
+ void _thread_exit();
+ void _thread_step(real_t p_delta);
+ void _thread_loop();
public:
#define ServerName PhysicsServer3D
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index e739ffa535..884f8adb8c 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -678,7 +678,7 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
#endif // _3D_DISABLED
if (Engine::get_singleton()->is_editor_hint()) {
- set_default_clear_color(GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
+ RSG::texture_storage->set_default_clear_color(GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
}
if (sorted_active_viewports_dirty) {
@@ -1521,10 +1521,6 @@ void RendererViewport::handle_timestamp(String p_timestamp, uint64_t p_cpu_time,
}
}
-void RendererViewport::set_default_clear_color(const Color &p_color) {
- RSG::texture_storage->set_default_clear_color(p_color);
-}
-
void RendererViewport::viewport_set_canvas_cull_mask(RID p_viewport, uint32_t p_canvas_cull_mask) {
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_NULL(viewport);
diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h
index 8bdce04c50..b36fc7f57f 100644
--- a/servers/rendering/renderer_viewport.h
+++ b/servers/rendering/renderer_viewport.h
@@ -303,7 +303,6 @@ public:
void handle_timestamp(String p_timestamp, uint64_t p_cpu_time, uint64_t p_gpu_time);
- void set_default_clear_color(const Color &p_color);
void draw_viewports(bool p_swap_buffers);
bool free(RID p_rid);
diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp
index 7e5ccee0e3..51ff009eaf 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -69,8 +69,6 @@ void RenderingServerDefault::request_frame_drawn_callback(const Callable &p_call
}
void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
- changes = 0;
-
RSG::rasterizer->begin_frame(frame_step);
TIMESTAMP_BEGIN()
@@ -102,19 +100,11 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
RSG::canvas->update_visibility_notifiers();
RSG::scene->update_visibility_notifiers();
- while (frame_drawn_callbacks.front()) {
- Callable c = frame_drawn_callbacks.front()->get();
- Variant result;
- Callable::CallError ce;
- c.callp(nullptr, 0, result, ce);
- 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);
- }
-
- frame_drawn_callbacks.pop_front();
+ if (create_thread) {
+ callable_mp(this, &RenderingServerDefault::_run_post_draw_steps).call_deferred();
+ } else {
+ _run_post_draw_steps();
}
- RS::get_singleton()->emit_signal(SNAME("frame_post_draw"));
if (RSG::utilities->get_captured_timestamps_count()) {
Vector<FrameProfileArea> new_profile;
@@ -194,6 +184,23 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
RSG::utilities->update_memory_info();
}
+void RenderingServerDefault::_run_post_draw_steps() {
+ while (frame_drawn_callbacks.front()) {
+ Callable c = frame_drawn_callbacks.front()->get();
+ Variant result;
+ Callable::CallError ce;
+ c.callp(nullptr, 0, result, ce);
+ 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);
+ }
+
+ frame_drawn_callbacks.pop_front();
+ }
+
+ emit_signal(SNAME("frame_post_draw"));
+}
+
double RenderingServerDefault::get_frame_setup_time_cpu() const {
return frame_setup_time;
}
@@ -203,7 +210,25 @@ bool RenderingServerDefault::has_changed() const {
}
void RenderingServerDefault::_init() {
+ RSG::threaded = create_thread;
+
+ RSG::canvas = memnew(RendererCanvasCull);
+ RSG::viewport = memnew(RendererViewport);
+ RendererSceneCull *sr = memnew(RendererSceneCull);
+ RSG::camera_attributes = memnew(RendererCameraAttributes);
+ RSG::scene = sr;
+ RSG::rasterizer = RendererCompositor::create();
+ RSG::utilities = RSG::rasterizer->get_utilities();
RSG::rasterizer->initialize();
+ RSG::light_storage = RSG::rasterizer->get_light_storage();
+ RSG::material_storage = RSG::rasterizer->get_material_storage();
+ RSG::mesh_storage = RSG::rasterizer->get_mesh_storage();
+ RSG::particles_storage = RSG::rasterizer->get_particles_storage();
+ RSG::texture_storage = RSG::rasterizer->get_texture_storage();
+ RSG::gi = RSG::rasterizer->get_gi();
+ RSG::fog = RSG::rasterizer->get_fog();
+ RSG::canvas_render = RSG::rasterizer->get_canvas();
+ sr->set_scene_render(RSG::rasterizer->get_scene());
}
void RenderingServerDefault::_finish() {
@@ -212,26 +237,38 @@ void RenderingServerDefault::_finish() {
}
RSG::canvas->finalize();
+ memdelete(RSG::canvas);
RSG::rasterizer->finalize();
+ memdelete(RSG::viewport);
+ memdelete(RSG::rasterizer);
+ memdelete(RSG::scene);
+ memdelete(RSG::camera_attributes);
}
void RenderingServerDefault::init() {
if (create_thread) {
print_verbose("RenderingServerWrapMT: Starting render thread");
DisplayServer::get_singleton()->release_rendering_thread();
- server_task_id = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &RenderingServerDefault::_thread_loop), true);
+ WorkerThreadPool::TaskID tid = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &RenderingServerDefault::_thread_loop), true);
+ command_queue.set_pump_task_id(tid);
+ command_queue.push(this, &RenderingServerDefault::_assign_mt_ids, tid);
+ command_queue.push_and_sync(this, &RenderingServerDefault::_init);
+ DEV_ASSERT(server_task_id == tid);
} else {
+ server_thread = Thread::MAIN_ID;
_init();
}
}
void RenderingServerDefault::finish() {
if (create_thread) {
+ command_queue.push(this, &RenderingServerDefault::_finish);
command_queue.push(this, &RenderingServerDefault::_thread_exit);
if (server_task_id != WorkerThreadPool::INVALID_TASK_ID) {
WorkerThreadPool::get_singleton()->wait_for_task_completion(server_task_id);
server_task_id = WorkerThreadPool::INVALID_TASK_ID;
}
+ server_thread = Thread::MAIN_ID;
} else {
_finish();
}
@@ -268,17 +305,12 @@ Vector<RenderingServer::FrameProfileArea> RenderingServerDefault::get_frame_prof
/* TESTING */
-void RenderingServerDefault::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) {
- redraw_request();
- RSG::rasterizer->set_boot_image(p_image, p_color, p_scale, p_use_filter);
-}
-
Color RenderingServerDefault::get_default_clear_color() {
return RSG::texture_storage->get_default_clear_color();
}
void RenderingServerDefault::set_default_clear_color(const Color &p_color) {
- RSG::viewport->set_default_clear_color(p_color);
+ RSG::texture_storage->set_default_clear_color(p_color);
}
#ifndef DISABLE_DEPRECATED
@@ -327,29 +359,23 @@ Size2i RenderingServerDefault::get_maximum_viewport_size() const {
}
}
-void RenderingServerDefault::_thread_exit() {
- exit = true;
+void RenderingServerDefault::_assign_mt_ids(WorkerThreadPool::TaskID p_pump_task_id) {
+ server_thread = Thread::get_caller_id();
+ server_task_id = p_pump_task_id;
}
-void RenderingServerDefault::_thread_draw(bool p_swap_buffers, double frame_step) {
- _draw(p_swap_buffers, frame_step);
+void RenderingServerDefault::_thread_exit() {
+ exit = true;
}
void RenderingServerDefault::_thread_loop() {
- server_thread = Thread::get_caller_id();
-
DisplayServer::get_singleton()->gl_window_make_current(DisplayServer::MAIN_WINDOW_ID); // Move GL to this thread.
- _init();
- command_queue.set_pump_task_id(server_task_id);
while (!exit) {
WorkerThreadPool::get_singleton()->yield();
command_queue.flush_all();
}
- command_queue.flush_all();
-
- _finish();
DisplayServer::get_singleton()->release_rendering_thread();
}
@@ -366,7 +392,9 @@ void RenderingServerDefault::set_physics_interpolation_enabled(bool p_enabled) {
/* EVENT QUEUING */
void RenderingServerDefault::sync() {
- if (!create_thread) {
+ if (create_thread) {
+ command_queue.sync();
+ } else {
command_queue.flush_all(); // Flush all pending from other threads.
}
}
@@ -375,8 +403,9 @@ void RenderingServerDefault::draw(bool p_swap_buffers, double frame_step) {
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Manually triggering the draw function from the RenderingServer can only be done on the main thread. Call this function from the main thread or use call_deferred().");
// Needs to be done before changes is reset to 0, to not force the editor to redraw.
RS::get_singleton()->emit_signal(SNAME("frame_pre_draw"));
+ changes = 0;
if (create_thread) {
- command_queue.push(this, &RenderingServerDefault::_thread_draw, p_swap_buffers, frame_step);
+ command_queue.push(this, &RenderingServerDefault::_draw, p_swap_buffers, frame_step);
} else {
_draw(p_swap_buffers, frame_step);
}
@@ -390,36 +419,7 @@ RenderingServerDefault::RenderingServerDefault(bool p_create_thread) {
RenderingServer::init();
create_thread = p_create_thread;
- if (!create_thread) {
- server_thread = Thread::MAIN_ID;
- }
-
- RSG::threaded = create_thread;
-
- RSG::canvas = memnew(RendererCanvasCull);
- RSG::viewport = memnew(RendererViewport);
- RendererSceneCull *sr = memnew(RendererSceneCull);
- RSG::camera_attributes = memnew(RendererCameraAttributes);
- RSG::scene = sr;
- RSG::rasterizer = RendererCompositor::create();
- RSG::utilities = RSG::rasterizer->get_utilities();
- RSG::light_storage = RSG::rasterizer->get_light_storage();
- RSG::material_storage = RSG::rasterizer->get_material_storage();
- RSG::mesh_storage = RSG::rasterizer->get_mesh_storage();
- RSG::particles_storage = RSG::rasterizer->get_particles_storage();
- RSG::texture_storage = RSG::rasterizer->get_texture_storage();
- RSG::gi = RSG::rasterizer->get_gi();
- RSG::fog = RSG::rasterizer->get_fog();
- RSG::canvas_render = RSG::rasterizer->get_canvas();
- sr->set_scene_render(RSG::rasterizer->get_scene());
-
- frame_profile_frame = 0;
}
RenderingServerDefault::~RenderingServerDefault() {
- memdelete(RSG::canvas);
- memdelete(RSG::viewport);
- memdelete(RSG::rasterizer);
- memdelete(RSG::scene);
- memdelete(RSG::camera_attributes);
}
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index bb2f3d94ce..d0b6bc492d 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -63,7 +63,7 @@ class RenderingServerDefault : public RenderingServer {
static void _changes_changed() {}
- uint64_t frame_profile_frame;
+ uint64_t frame_profile_frame = 0;
Vector<FrameProfileArea> frame_profile;
double frame_setup_time = 0;
@@ -76,18 +76,17 @@ class RenderingServerDefault : public RenderingServer {
mutable CommandQueueMT command_queue;
- void _thread_loop();
-
- Thread::ID server_thread = Thread::UNASSIGNED_ID;
+ Thread::ID server_thread = Thread::MAIN_ID;
WorkerThreadPool::TaskID server_task_id = WorkerThreadPool::INVALID_TASK_ID;
bool exit = false;
bool create_thread = false;
- void _thread_draw(bool p_swap_buffers, double frame_step);
-
+ void _assign_mt_ids(WorkerThreadPool::TaskID p_pump_task_id);
void _thread_exit();
+ void _thread_loop();
void _draw(bool p_swap_buffers, double frame_step);
+ void _run_post_draw_steps();
void _init();
void _finish();
@@ -998,9 +997,22 @@ public:
FUNC1(global_shader_parameters_load_settings, bool)
FUNC0(global_shader_parameters_clear)
+ /* COMPOSITOR */
+
#undef server_name
#undef ServerName
+#define ServerName RendererCompositor
+#define server_name RSG::rasterizer
+
+ FUNC4S(set_boot_image, const Ref<Image> &, const Color &, bool, bool)
+
/* STATUS INFORMATION */
+
+#undef server_name
+#undef ServerName
+
+ /* UTILITIES */
+
#define ServerName RendererUtilities
#define server_name RSG::utilities
FUNC0RC(String, get_video_adapter_name)
@@ -1056,7 +1068,7 @@ public:
virtual void call_on_render_thread(const Callable &p_callable) override {
if (Thread::get_caller_id() == server_thread) {
command_queue.flush_if_pending();
- _call_on_render_thread(p_callable);
+ p_callable.call();
} else {
command_queue.push(this, &RenderingServerDefault::_call_on_render_thread, p_callable);
}
@@ -1066,7 +1078,6 @@ public:
virtual double get_frame_setup_time_cpu() const override;
- virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) override;
virtual Color get_default_clear_color() override;
virtual void set_default_clear_color(const Color &p_color) override;