diff options
26 files changed, 527 insertions, 434 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/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..9f9b77d9d0 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 { @@ -368,6 +368,10 @@ class CommandQueueMT { sync_cond_var.notify_all(); } + // 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(); @@ -384,6 +388,8 @@ class CommandQueueMT { } while (sync_head != sync_head_goal); // Can't use lower-than because of wraparound. } + void _no_op() {} + public: void lock(); void unlock(); @@ -405,10 +411,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 +427,9 @@ public: } void set_pump_task_id(WorkerThreadPool::TaskID p_task_id) { + lock(); pump_task_id = p_task_id; + unlock(); } CommandQueueMT(); 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/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/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/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/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/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; |