Add Chromium-only Blender WebEngine parity work

This commit is contained in:
mes123456
2026-08-12 04:47:48 -04:00
commit 9fd26010f6
18225 changed files with 11622124 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,157 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#ifdef WIN32_LEAN_AND_MEAN
# undef WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#include <strsafe.h>
#include <PathCch.h>
#include <tlhelp32.h>
static BOOL LaunchedFromSteam(void)
{
HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
BOOL isSteam = FALSE;
if (!hSnapShot) {
return (FALSE);
}
PROCESSENTRY32 process_entry;
process_entry.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hSnapShot, &process_entry)) {
CloseHandle(hSnapShot);
return (FALSE);
}
/* First find our parent process ID. */
DWORD our_pid = GetCurrentProcessId();
DWORD parent_pid = -1;
do {
if (process_entry.th32ProcessID == our_pid) {
parent_pid = process_entry.th32ParentProcessID;
break;
}
} while (Process32Next(hSnapShot, &process_entry));
if (parent_pid == -1 || !Process32First(hSnapShot, &process_entry)) {
CloseHandle(hSnapShot);
return (FALSE);
}
/* Then do another loop to find the process name of the parent.
* this is done in 2 loops, since the order of the processes is
* unknown and we may already have passed the parent process by
* the time we figure out its pid in the first loop. */
do {
if (process_entry.th32ProcessID == parent_pid) {
if (_wcsicmp(process_entry.szExeFile, L"steam.exe") == 0) {
isSteam = TRUE;
}
break;
}
} while (Process32Next(hSnapShot, &process_entry));
CloseHandle(hSnapShot);
return isSteam;
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
/* Silence unreferenced formal parameter warning. */
(void)hInstance;
(void)hPrevInstance;
(void)nCmdShow;
STARTUPINFO siStartInfo = {0};
PROCESS_INFORMATION procInfo;
wchar_t path[MAX_PATH];
siStartInfo.wShowWindow = SW_HIDE;
siStartInfo.dwFlags = STARTF_USESHOWWINDOW;
/* Get the path to the currently running executable (`blender-launcher.exe`). */
DWORD nSize = GetModuleFileName(NULL, path, MAX_PATH);
if (!nSize) {
return -1;
}
/* #GetModuleFileName returns the number of characters written, but GetLastError needs to be
* called to see if it ran out of space or not. However where would we be without exceptions
* to the rule: "If the buffer is too small to hold the module name, the function returns nSize.
* The last error code remains ERROR_SUCCESS." - source: MSDN. */
if (GetLastError() == ERROR_SUCCESS && nSize == MAX_PATH) {
return -1;
}
/* Remove the filename (blender-launcher.exe) from path. */
if (PathCchRemoveFileSpec(path, MAX_PATH) != S_OK) {
return -1;
}
/* Add blender.exe to path, resulting in the full path to the blender executable. */
if (PathCchCombine(path, MAX_PATH, path, L"blender.exe") != S_OK) {
return -1;
}
int required_size_chars = lstrlenW(path) + /* Module name. */
3 + /* 2 quotes + Space. */
lstrlenW(pCmdLine) + /* Original command line. */
1; /* Zero terminator. */
size_t required_size_bytes = required_size_chars * sizeof(wchar_t);
wchar_t *buffer = (wchar_t *)malloc(required_size_bytes);
if (!buffer) {
return -1;
}
if (StringCbPrintfEx(buffer,
required_size_bytes,
NULL,
NULL,
STRSAFE_NULL_ON_FAILURE,
L"\"%s\" %s",
path,
pCmdLine) != S_OK)
{
free(buffer);
return -1;
}
BOOL success = CreateProcess(
path, buffer, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &siStartInfo, &procInfo);
DWORD returnValue = success ? 0 : -1;
if (success) {
/* If blender-launcher is called with background command line flag or launched from steam,
* wait for the blender process to exit and return its return value. */
BOOL background = LaunchedFromSteam();
int argc = 0;
LPWSTR *argv = CommandLineToArgvW(pCmdLine, &argc);
for (int i = 0; i < argc; i++) {
if ((wcscmp(argv[i], L"-b") == 0) || (wcscmp(argv[i], L"--background") == 0)) {
background = TRUE;
break;
}
}
if (background) {
WaitForSingleObject(procInfo.hProcess, INFINITE);
GetExitCodeProcess(procInfo.hProcess, &returnValue);
}
/* Handles in PROCESS_INFORMATION must be closed with CloseHandle when they are no longer
* needed - MSDN. Closing the handles will NOT terminate the thread/process that we just
* started. */
CloseHandle(procInfo.hThread);
CloseHandle(procInfo.hProcess);
}
free(buffer);
return returnValue;
}

View File

@@ -0,0 +1,55 @@
/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup creator
*/
#ifdef WITH_BUILDINFO_HEADER
# include "buildinfo.h"
#endif
typedef unsigned long ulong;
#ifdef BUILD_DATE
extern char build_date[];
extern char build_time[];
extern char build_hash[];
extern ulong build_commit_timestamp;
extern char build_commit_date[];
extern char build_commit_time[];
extern char build_branch[];
extern char build_platform[];
extern char build_type[];
extern char build_cflags[];
extern char build_cxxflags[];
extern char build_linkflags[];
extern char build_system[];
/* Currently only these are defined in the header. */
char build_date[] = BUILD_DATE;
char build_time[] = BUILD_TIME;
char build_hash[] = BUILD_HASH;
ulong build_commit_timestamp = BUILD_COMMIT_TIMESTAMP;
char build_commit_date[16] = "\0";
char build_commit_time[16] = "\0";
char build_branch[] = BUILD_BRANCH;
char build_platform[] = BUILD_PLATFORM;
char build_type[] = BUILD_TYPE;
# ifdef BUILD_CFLAGS
char build_cflags[] = BUILD_CFLAGS;
char build_cxxflags[] = BUILD_CXXFLAGS;
char build_linkflags[] = BUILD_LINKFLAGS;
char build_system[] = BUILD_SYSTEM;
# else
char build_cflags[] = "unmaintained buildsystem alert!";
char build_cxxflags[] = "unmaintained buildsystem alert!";
char build_linkflags[] = "unmaintained buildsystem alert!";
char build_system[] = "unmaintained buildsystem alert!";
# endif
#endif // BUILD_DATE

View File

@@ -0,0 +1,674 @@
/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup creator
*/
#include <cstdlib>
#include <cstring>
#ifdef WIN32
# ifdef WIN32_LEAN_AND_MEAN
# undef WIN32_LEAN_AND_MEAN
# endif
# include "utfconv.hh"
# include <windows.h>
# ifdef WITH_CPU_CHECK
# pragma comment(linker, "/include:cpu_check_win32")
# endif
#endif
#if defined(WITH_TBB_MALLOC) && defined(_MSC_VER) && defined(NDEBUG)
# pragma comment(lib, "tbbmalloc_proxy.lib")
# pragma comment(linker, "/include:__TBB_malloc_proxy")
#endif
#include "MEM_guardedalloc.h"
#include "CLG_log.h"
#include "DNA_genfile.h"
#include "BLI_endian_defines.h"
#include "BLI_fftw.hh"
#include "BLI_path_utils.hh"
#include "BLI_string.h"
#include "BLI_system.h"
#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
/* Mostly initialization functions. */
#include "BKE_appdir.hh"
#include "BKE_blender.hh"
#include "BKE_brush.hh"
#include "BKE_callbacks.hh"
#include "BKE_context.hh"
#include "BKE_cpp_types.hh"
#include "BKE_global.hh"
#include "BKE_idtype.hh"
#include "BKE_material.hh"
#include "BKE_modifier.hh"
#include "BKE_node.hh"
#include "BKE_particle.h"
#include "BKE_shader_fx.hh"
#include "BKE_sound.hh"
#include "BKE_vfont.hh"
#include "BKE_volume.hh"
#ifndef WITH_PYTHON_MODULE
# include "BLI_args.h"
#endif
#include "DEG_depsgraph.hh"
#include "IMB_imbuf.hh" /* For #IMB_init. */
#include "MOV_util.hh"
#include "RE_engine.h"
#include "RE_texture.h"
#include "ED_datafiles.h"
#include "SEQ_modifier.hh"
#include "WM_api.hh"
#include "RNA_define.hh"
#include "FN_init.hh"
#ifdef WITH_OPENGL_BACKEND
# include "GPU_compilation_subprocess.hh"
#endif
#ifdef WITH_FREESTYLE
# include "FRS_freestyle.h"
#endif
#include <csignal>
#ifdef __FreeBSD__
# include <floatingpoint.h>
#endif
#ifdef WITH_BINRELOC
# include "binreloc.h"
#endif
#ifdef WITH_LIBMV
# include "libmv-capi.h"
#endif
#ifdef WITH_CYCLES
# include "CCL_api.h"
#endif
#if defined(WITH_PYTHON_MODULE) && defined(__APPLE__)
/* Environment is not available in macOS shared libraries. */
# include <crt_externs.h>
char **environ = nullptr;
#endif
#if defined(WITH_TBB_MALLOC) && defined(__linux__)
# include <tbb/scalable_allocator.h>
#endif
#include "creator_intern.h" /* Own include. */
BLI_STATIC_ASSERT(ENDIAN_ORDER == L_ENDIAN, "Blender only builds on little endian systems")
/* -------------------------------------------------------------------- */
/** \name GMP Allocator Workaround
* \{ */
#if (defined(WITH_TBB_MALLOC) && defined(_MSC_VER) && defined(NDEBUG) && defined(WITH_GMP)) || \
defined(DOXYGEN)
# include "gmp.h"
# include "tbb/scalable_allocator.h"
void *gmp_alloc(size_t size)
{
return scalable_malloc(size);
}
void *gmp_realloc(void *ptr, size_t /*old_size*/, size_t new_size)
{
return scalable_realloc(ptr, new_size);
}
void gmp_free(void *ptr, size_t /*size*/)
{
scalable_free(ptr);
}
/**
* Use TBB's scalable_allocator on Windows.
* `TBBmalloc` correctly captures all allocations already,
* however, GMP is built with MINGW since it doesn't build with MSVC,
* which TBB has issues hooking into automatically.
*/
void gmp_blender_init_allocator()
{
mp_set_memory_functions(gmp_alloc, gmp_realloc, gmp_free);
}
#endif
/** \} */
/* -------------------------------------------------------------------- */
/** \name Local Defines
* \{ */
/* When building as a Python module, don't use special argument handling
* so the module loading logic can control the `argv` & `argc`. */
#if defined(WIN32) && !defined(WITH_PYTHON_MODULE)
# define USE_WIN32_UNICODE_ARGS
#endif
/** \} */
namespace blender {
/* -------------------------------------------------------------------- */
/** \name Local Application State
* \{ */
/* Written to by `creator_args.cc`. */
ApplicationState app_state = []() {
ApplicationState app_state{};
app_state.signal.use_crash_handler = true;
app_state.signal.use_console_crash_handler = false;
app_state.signal.use_abort_handler = true;
app_state.exit_code_on_error.python = 0;
app_state.main_arg_deferred = nullptr;
return app_state;
}();
/** \} */
/* -------------------------------------------------------------------- */
/** \name Application Level Callbacks
*
* Initialize callbacks for the modules that need them.
* \{ */
static void callback_mem_error(const char *errorStr)
{
fputs(errorStr, stderr);
fflush(stderr);
}
static void main_callback_setup()
{
/* Error output from the guarded allocation routines. */
MEM_set_error_callback(callback_mem_error);
}
/** Data to free when Blender exits early on. */
struct CreatorAtExitData_EarlyExit {
bContext *C;
};
/** Free data on early exit (if Python calls `sys.exit()` while parsing args for eg). */
struct CreatorAtExitData {
#ifndef WITH_PYTHON_MODULE
bArgs *ba;
#endif
#ifdef USE_WIN32_UNICODE_ARGS
char **argv;
int argv_num;
#endif
/**
* When non-null, run additional exit logic.
* Cleared once early initialization is over.
*/
CreatorAtExitData_EarlyExit *early_exit = nullptr;
};
static void callback_main_atexit(void *user_data)
{
CreatorAtExitData *app_init_data = static_cast<CreatorAtExitData *>(user_data);
#ifndef WITH_PYTHON_MODULE
if (app_init_data->ba) {
BLI_args_destroy(app_init_data->ba);
app_init_data->ba = nullptr;
}
#endif
#ifdef USE_WIN32_UNICODE_ARGS
if (app_init_data->argv) {
while (app_init_data->argv_num) {
free((void *)app_init_data->argv[--app_init_data->argv_num]);
}
free((void *)app_init_data->argv);
app_init_data->argv = nullptr;
}
#endif
if (CreatorAtExitData_EarlyExit *early_exit = app_init_data->early_exit) {
CTX_free(early_exit->C);
DEG_free_node_types();
BKE_blender_globals_clear();
BKE_appdir_exit();
DNA_sdna_current_free();
CLG_exit();
}
}
static void callback_clg_fatal(void *fp)
{
BLI_system_backtrace(static_cast<FILE *>(fp));
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name LD_PRELOAD for Linux
* \{ */
static void restore_ld_preload()
{
/* LD_PRELOAD may have been modified on startup for Blender. However
* we don't want it for other executables launched from Blender. */
const char *restore_ld_preload = BLI_getenv("BLENDER_RESTORE_LD_PRELOAD");
if (restore_ld_preload) {
BLI_setenv("LD_PRELOAD", restore_ld_preload);
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Blender as a Stand-Alone Python Module (bpy)
*
* While not officially supported, this can be useful for Python developers.
* See: https://developer.blender.org/docs/handbook/building_blender/python_module/
* \{ */
#ifdef WITH_PYTHON_MODULE
static void *main_python_evil_C = nullptr;
/* Called in `bpy_interface.cc` when building as a Python module. */
int main_python_enter(int argc, const char **argv);
void main_python_exit()
{
WM_exit_ex((bContext *)main_python_evil_C, true, false);
main_python_evil_C = nullptr;
}
/* Rename the `main(..)` function, allowing Python initialization to call it. */
# define main blender::main_python_enter
#endif /* WITH_PYTHON_MODULE */
/** \} */
} // namespace blender
/* -------------------------------------------------------------------- */
/** \name Main Function
* \{ */
#if defined(__APPLE__)
extern "C" int GHOST_HACK_getFirstFile(char buf[]);
#endif
/**
* Blender's main function responsibilities are:
* - setup subsystems.
* - handle arguments.
* - run #WM_main() event loop,
* or exit immediately when running in background-mode.
*/
int main(int argc,
#ifdef USE_WIN32_UNICODE_ARGS
const char ** /*argv_c*/
#else
const char **argv
#endif
)
{
using namespace blender;
bContext *C;
#ifndef WITH_PYTHON_MODULE
bArgs *ba;
#endif
/* Ensure we free data on early-exit. */
CreatorAtExitData app_init_data = {nullptr};
BKE_blender_atexit_register(callback_main_atexit, &app_init_data);
CreatorAtExitData_EarlyExit app_init_data_early_exit = {nullptr};
app_init_data.early_exit = &app_init_data_early_exit;
/* Un-buffered `stdout` makes `stdout` and `stderr` better synchronized, and helps
* when stepping through code in a debugger (prints are immediately
* visible). However disabling buffering causes lock contention on windows
* see #76767 for details, since this is a debugging aid, we do not enable
* the un-buffered behavior for release builds. */
#ifndef NDEBUG
setvbuf(stdout, nullptr, _IONBF, 0);
#endif
restore_ld_preload();
#ifdef WIN32
# ifdef USE_WIN32_UNICODE_ARGS
/* Win32 Unicode Arguments. */
{
/* NOTE: Can't use `guardedalloc` allocation here, as it's not yet initialized
* (it depends on the arguments passed in, which is what we're getting here!). */
wchar_t **argv_16 = CommandLineToArgvW(GetCommandLineW(), &argc);
app_init_data.argv = static_cast<char **>(malloc(argc * sizeof(char *)));
for (int i = 0; i < argc; i++) {
app_init_data.argv[i] = alloc_utf_8_from_16(argv_16[i], 0);
}
LocalFree(argv_16);
/* Free on early-exit. */
app_init_data.argv_num = argc;
}
const char **argv = const_cast<const char **>(app_init_data.argv);
# endif /* USE_WIN32_UNICODE_ARGS */
#endif /* WIN32 */
#if defined(WITH_OPENGL_BACKEND) && BLI_SUBPROCESS_SUPPORT
if (STREQ(argv[0], "--compilation-subprocess")) {
BLI_assert(argc == 2);
GPU_compilation_subprocess_run(argv[1]);
return 0;
}
#endif
#if defined(WITH_TBB_MALLOC) && defined(__linux__)
/* Enable huge pages for performance. */
scalable_allocation_mode(TBBMALLOC_USE_HUGE_PAGES, 1);
#endif
/* NOTE: Special exception for guarded allocator type switch:
* we need to perform switch from lock-free to fully
* guarded allocator before any allocation happened.
*/
{
int i;
for (i = 0; i < argc; i++) {
if (STR_ELEM(argv[i], "-d", "--debug", "--debug-memory", "--debug-all")) {
printf("Switching to fully guarded memory allocator.\n");
MEM_use_guarded_allocator();
break;
}
if (STR_ELEM(argv[i], "--", "-c", "--command")) {
break;
}
}
MEM_init_memleak_detection();
}
#ifdef BUILD_DATE
{
const time_t temp_time = build_commit_timestamp;
const tm *tm = gmtime(&temp_time);
if (LIKELY(tm)) {
strftime(build_commit_date, sizeof(build_commit_date), "%Y-%m-%d", tm);
strftime(build_commit_time, sizeof(build_commit_time), "%H:%M", tm);
}
else {
const char *unknown = "date-unknown";
STRNCPY(build_commit_date, unknown);
STRNCPY(build_commit_time, unknown);
}
}
#endif
/* Initialize logging. */
CLG_init();
CLG_output_use_timestamp_set(true);
CLG_output_use_memory_set(false);
CLG_output_use_source_set(false);
CLG_output_use_basename_set(false);
CLG_fatal_fn_set(callback_clg_fatal);
C = CTX_create();
app_init_data_early_exit.C = C;
#ifdef WITH_PYTHON_MODULE
# ifdef __APPLE__
environ = *_NSGetEnviron();
# endif
# undef main
main_python_evil_C = C;
#endif
#ifdef WITH_BINRELOC
br_init(nullptr);
#endif
#ifdef WITH_LIBMV
libmv_initLogging(argv[0]);
#endif
#if defined(WITH_TBB_MALLOC) && defined(_MSC_VER) && defined(NDEBUG) && defined(WITH_GMP)
gmp_blender_init_allocator();
#endif
main_callback_setup();
#if defined(__APPLE__) && !defined(WITH_PYTHON_MODULE) && !defined(WITH_HEADLESS)
/* Patch to ignore argument finder gives us (PID?). */
if (argc == 2 && STRPREFIX(argv[1], "-psn_")) {
static char firstfilebuf[512];
argc = 1;
if (GHOST_HACK_getFirstFile(firstfilebuf)) {
argc = 2;
argv[1] = firstfilebuf;
}
}
#endif
#ifdef __FreeBSD__
fpsetmask(0);
#endif
/* Initialize path to executable. */
BKE_appdir_program_path_init(argv[0]);
BLI_threadapi_init();
DNA_sdna_current_init();
BKE_blender_globals_init(); /* `blender.cc` */
BKE_cpp_types_init();
fn::multi_function::register_common_functions();
BKE_idtype_init();
BKE_modifier_init();
seq::modifiers_init();
BKE_shaderfx_init();
BKE_volumes_init();
DEG_register_node_types();
BKE_callback_global_init();
/* First test for background-mode (#Global.background). */
#ifndef WITH_PYTHON_MODULE
ba = BLI_args_create(argc, argv); /* Skip binary path. */
/* Ensure we free on early exit. */
app_init_data.ba = ba;
main_args_setup(C, ba, false);
/* Parse environment handling arguments. */
BLI_args_parse(ba, ARG_PASS_ENVIRONMENT, nullptr, nullptr);
#else
/* Using preferences or user startup makes no sense for #WITH_PYTHON_MODULE. */
G.factory_startup = true;
#endif
/* After parsing #ARG_PASS_ENVIRONMENT such as `--env-*`,
* since they impact `BKE_appdir` behavior. */
BKE_appdir_init();
/* After parsing number of threads argument. */
BLI_task_scheduler_init();
/* Initialize FFTW threading support. */
fftw::initialize_float();
#ifndef WITH_PYTHON_MODULE
/* The settings pass includes:
* - Background-mode assignment (#Global.background), checked by other subsystems
* which may be skipped in background mode.
* - The animation player may be launched which takes over argument passing,
* initializes the sub-systems it needs which have not yet been started.
* The animation player will call `exit(..)` too, so code after this call
* never runs when it's invoked.
* - All the `--debug-*` flags.
*/
BLI_args_parse(ba, ARG_PASS_SETTINGS, nullptr, nullptr);
main_signal_setup();
#endif
/* Continue with regular initialization, no need to use "early" exit. */
app_init_data.early_exit = nullptr;
#ifdef WITH_CYCLES
CCL_log_init();
CCL_implicit_sharing_init();
#endif
/* Set max open files to better handle production files that may use many
* open geometry or texture cache file handles. After logging since it's used .*/
BLI_system_max_open_files_ensure();
/* Must be initialized after #BKE_appdir_init to account for color-management paths. */
IMB_init();
/* Keep after #ARG_PASS_SETTINGS since debug flags are checked. */
MOV_init();
/* After #ARG_PASS_SETTINGS arguments, this is so #WM_main_playanim skips #RNA_init. */
RNA_init();
RE_texture_rng_init();
RE_engines_init();
bke::node_system_init();
BKE_brush_system_init();
BKE_particle_init_rng();
/* End second initialization. */
#if defined(WITH_PYTHON_MODULE) || defined(WITH_HEADLESS)
/* Python module mode ALWAYS runs in background-mode (for now). */
G.background = true;
/* Manually using `--background` also forces the audio device. */
BKE_sound_force_device("None");
#else
if (G.background) {
main_signal_setup_background();
}
#endif
/* Background render uses this font too. */
BKE_vfont_builtin_register(datatoc_bfont_pfb, datatoc_bfont_pfb_size);
/* Initialize FFMPEG if built in, also needed for background-mode if videos are
* rendered via FFMPEG. */
BKE_sound_init_once();
BKE_materials_init();
#ifndef WITH_PYTHON_MODULE
if (G.background == 0) {
BLI_args_parse(ba, ARG_PASS_SETTINGS_GUI, nullptr, nullptr);
}
BLI_args_parse(ba, ARG_PASS_SETTINGS_FORCE, nullptr, nullptr);
#endif
WM_init(C, argc, argv);
#ifndef WITH_PYTHON
fprintf(stderr,
"\n"
"WARNING: Blender compiled without Python!\n"
"This is not intended for typical usage.\n"
"\n");
#endif
#ifdef WITH_FREESTYLE
/* Initialize Freestyle. */
FRS_init();
FRS_set_context(C);
#endif
/* OK we are ready for it. */
#ifndef WITH_PYTHON_MODULE
/* Handles #ARG_PASS_FINAL. */
BLI_args_parse(ba, ARG_PASS_FINAL, main_args_handle_load_file, C);
#endif
/* Explicitly free data allocated for argument parsing:
* - `ba`
* - `argv` on WIN32.
*/
callback_main_atexit(&app_init_data);
BKE_blender_atexit_unregister(callback_main_atexit, &app_init_data);
/* Paranoid, avoid accidental re-use. */
#ifndef WITH_PYTHON_MODULE
ba = nullptr;
(void)ba;
#endif
#ifdef USE_WIN32_UNICODE_ARGS
argv = nullptr;
(void)argv;
#endif
#ifndef WITH_PYTHON_MODULE
if (G.background) {
int exit_code;
if (app_state.main_arg_deferred != nullptr) {
exit_code = main_arg_deferred_handle();
main_arg_deferred_free();
}
else {
exit_code = G.is_break ? EXIT_FAILURE : EXIT_SUCCESS;
}
/* Using window-manager API in background-mode is a bit odd, but works fine. */
WM_exit(C, exit_code);
}
else {
/* Not supported, although it could be made to work if needed. */
BLI_assert(app_state.main_arg_deferred == nullptr);
/* Shows the splash as needed. */
WM_init_splash_on_startup(C);
WM_main(C);
}
/* Neither #WM_exit, #WM_main return, this quiets CLANG's `unreachable-code-return` warning. */
BLI_assert_unreachable();
#endif /* !WITH_PYTHON_MODULE */
return 0;
} /* End of `int main(...)` function. */
/** \} */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,130 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
/** \file
* \ingroup creator
*
* Functionality for main() initialization.
*/
namespace blender {
struct BA_ArgCallback_Deferred;
struct bArgs;
struct bContext;
#ifdef __cplusplus
extern "C" {
#endif
#ifndef WITH_PYTHON_MODULE
/* `creator_args.cc` */
/**
* \param all: When enabled, all arguments are initialized
* even for configurations that don't apply to the current system.
* Used for documentation (see Python API: `bpy.app.help_text(all=True)`).
*/
void main_args_setup(struct bContext *C, struct bArgs *ba, bool all);
/**
* Handler for loading blend files.
* \note arguments that cannot be parsed are assumed to be blend files.
*/
int main_args_handle_load_file(int argc, const char **argv, void *data);
/**
* Handle an argument which requested deferred evaluation.
* Needed when arguments which evaluate early need Python to be initialized for example.
*/
int main_arg_deferred_handle();
void main_arg_deferred_free();
/* `creator_signals.cc` */
void main_signal_setup(void);
void main_signal_setup_background(void);
void main_signal_setup_fpe(void);
#endif /* !WITH_PYTHON_MODULE */
/** Shared data for argument handlers to store state in. */
struct ApplicationState {
struct {
bool use_crash_handler;
bool use_console_crash_handler;
bool use_abort_handler;
} signal;
/* We may want to set different exit codes for other kinds of errors. */
struct {
unsigned char python;
} exit_code_on_error;
/** Store the argument state for later handling. */
struct BA_ArgCallback_Deferred *main_arg_deferred;
};
extern struct ApplicationState app_state; /* `creator.cc` */
/**
* Passes for use by #main_args_setup.
* Keep in order of execution.
*/
enum {
/** Run before sub-system initialization. */
ARG_PASS_ENVIRONMENT = 1,
/** General settings parsing, also animation player. */
ARG_PASS_SETTINGS = 2,
/** Windowing & graphical settings (ignored in background mode). */
ARG_PASS_SETTINGS_GUI = 3,
/** Currently use for audio devices. */
ARG_PASS_SETTINGS_FORCE = 4,
/**
* Actions & fall back to loading blend file.
*
* \note arguments in the final pass must use #WM_exit instead of `exit()` environment is
* properly shut-down (temporary directory deleted, etc).
*/
ARG_PASS_FINAL = 5,
};
/* for the callbacks: */
#ifndef WITH_PYTHON_MODULE
# define BLEND_VERSION_FMT "Blender %d.%d.%d"
# define BLEND_VERSION_ARG (BLENDER_VERSION / 100), (BLENDER_VERSION % 100), BLENDER_VERSION_PATCH
#endif
#ifdef WITH_BUILDINFO_HEADER
# define BUILD_DATE
#endif
/* From `buildinfo.c`. */
#ifdef BUILD_DATE
extern char build_date[];
extern char build_time[];
extern char build_hash[];
extern unsigned long build_commit_timestamp;
/* TODO(@sergey): ideally size need to be in sync with `buildinfo.c`. */
extern char build_commit_date[16];
extern char build_commit_time[16];
extern char build_branch[];
extern char build_platform[];
extern char build_type[];
extern char build_cflags[];
extern char build_cxxflags[];
extern char build_linkflags[];
extern char build_system[];
#endif /* BUILD_DATE */
#ifdef __cplusplus
}
#endif
} // namespace blender

View File

@@ -0,0 +1,274 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup creator
*/
#ifndef WITH_PYTHON_MODULE
# include <cerrno>
# include <cstdlib>
# if defined(__linux__) && defined(__GNUC__)
# ifndef _GNU_SOURCE
# define _GNU_SOURCE
# endif
# include <cfenv>
# endif
# if (defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__)))
# define OSX_SSE_FPE
# include <xmmintrin.h>
# endif
# ifdef WIN32
# include <float.h>
# include <windows.h>
# include "BLI_winstuff.h"
# include "GPU_platform.hh"
# endif
# include "BLI_fileops.h"
# include "BLI_path_utils.hh"
# include "BLI_string.h"
# include "BLI_system.h"
# include BLI_SYSTEM_PID_H
# include "BKE_appdir.hh" /* #BKE_tempdir_session_purge. */
# include "BKE_blender.hh"
# include "BKE_blender_version.h"
# include "BKE_global.hh"
# include "BKE_main.hh"
# include "BKE_report.hh"
# include "BKE_wm_runtime.hh"
# include <csignal>
# ifdef WITH_PYTHON
# include "BPY_extern_python.hh" /* #BPY_python_backtrace. */
# endif
# include "creator_intern.h" /* Own include. */
namespace blender {
# if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE)
/**
* Set breakpoints here when running in debug mode, useful to catch floating point errors.
*/
static void sig_handle_fpe(int /*sig*/)
{
fprintf(stderr, "debug: SIGFPE trapped\n");
}
# endif
/* Handling `Ctrl-C` event in the console. */
static void sig_handle_blender_esc(int sig)
{
/* Forces render loop to read queue, not sure if its needed. */
G.is_break = true;
if (sig == 2) {
static int count = 0;
if (count) {
printf("\nBlender killed\n");
exit(2);
}
printf("\nSent an internal break event. Press ^C again to kill Blender\n");
count++;
}
}
static void crashlog_file_generate(const char *filepath, const void *os_info)
{
/* Might be called after WM/Main exit, so needs to be careful about nullptr-checking before
* de-referencing. */
wmWindowManager *wm = G_MAIN ? static_cast<wmWindowManager *>(G_MAIN->wm.first) : nullptr;
FILE *fp;
char header[512];
if (!app_state.signal.use_console_crash_handler) {
printf("Writing: %s\n", filepath);
}
fflush(stdout);
# ifndef BUILD_DATE
SNPRINTF(header, "# " BLEND_VERSION_FMT ", Unknown revision\n", BLEND_VERSION_ARG);
# else
SNPRINTF(header,
"# " BLEND_VERSION_FMT ", Commit date: %s %s, Hash %s\n",
BLEND_VERSION_ARG,
build_commit_date,
build_commit_time,
build_hash);
# endif
/* Open the crash log. */
errno = 0;
if (app_state.signal.use_console_crash_handler) {
fp = stderr;
}
else {
fp = BLI_fopen(filepath, "wb");
if (fp == nullptr) {
fprintf(stderr,
"Unable to save '%s': %s , falling back to console\n",
filepath,
errno ? strerror(errno) : "Unknown error opening file");
fp = stderr;
}
}
if (wm) {
BKE_report_write_file_fp(fp, &wm->runtime->reports, header);
}
fputs("\n# backtrace\n", fp);
BLI_system_backtrace_with_os_info(fp, os_info);
# ifdef WITH_PYTHON
/* Generate python back-trace if Python is currently active. */
BPY_python_backtrace(fp);
# endif
if (fp != stderr) {
fclose(fp);
}
}
static void sig_cleanup_and_terminate(int signum)
{
/* Delete content of temp directory. */
BKE_tempdir_session_purge();
/* Really crash. */
signal(signum, SIG_DFL);
# ifndef WIN32
kill(getpid(), signum);
# else
TerminateProcess(GetCurrentProcess(), signum);
# endif
}
# if !defined(WIN32)
static void sig_handle_crash_fn(int signum)
{
char filepath_crashlog[FILE_MAX];
BKE_blender_globals_crash_path_get(filepath_crashlog);
crashlog_file_generate(filepath_crashlog, nullptr);
sig_cleanup_and_terminate(signum);
}
# else
extern LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
{
/* If this is a stack overflow then we can't walk the stack, so just try to show
* where the error happened. */
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) {
HMODULE mod;
CHAR modulename[MAX_PATH];
LPVOID address = ExceptionInfo->ExceptionRecord->ExceptionAddress;
fprintf(stderr, "Error : EXCEPTION_STACK_OVERFLOW\n");
fprintf(stderr, "Address : 0x%p\n", address);
if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, LPCSTR(address), &mod)) {
if (GetModuleFileName(mod, modulename, MAX_PATH)) {
fprintf(stderr, "Module : %s\n", modulename);
}
}
}
else {
char filepath_crashlog[FILE_MAX];
BLI_windows_exception_print_message(ExceptionInfo);
BKE_blender_globals_crash_path_get(filepath_crashlog);
crashlog_file_generate(filepath_crashlog, ExceptionInfo);
/* Disable popup in background mode to avoid blocking automation.
* (e.g., when used by a render farm; see #142314). */
if ((!G.background) && (!app_state.signal.use_console_crash_handler)) {
std::string version;
# ifndef BUILD_DATE
const char *build_hash = G_MAIN ? G_MAIN->build_hash : "unknown";
version = std::string(BKE_blender_version_string()) + ", hash: `" + build_hash + "`";
# else
version = std::string(BKE_blender_version_string()) + ", Commit date: " + build_commit_date +
" " + build_commit_time + ", hash: `" + build_hash + "`";
# endif
BLI_windows_exception_show_dialog(
filepath_crashlog, G.filepath_last_blend, GPU_platform_gpu_name(), version.c_str());
}
sig_cleanup_and_terminate(SIGSEGV);
}
return EXCEPTION_EXECUTE_HANDLER;
}
# endif
static void sig_handle_abort(int /*signum*/)
{
/* Delete content of temp directory. */
BKE_tempdir_session_purge();
}
void main_signal_setup()
{
if (app_state.signal.use_crash_handler) {
# ifdef WIN32
SetUnhandledExceptionFilter(windows_exception_handler);
# else
/* After parsing arguments. */
signal(SIGSEGV, sig_handle_crash_fn);
# endif
}
# ifdef WIN32
/* Prevent any error mode dialogs from hanging the application. */
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX |
SEM_NOOPENFILEERRORBOX);
# endif
if (app_state.signal.use_abort_handler) {
signal(SIGABRT, sig_handle_abort);
}
}
void main_signal_setup_background()
{
/* for all platforms, even windows has it! */
BLI_assert(G.background);
/* Support pressing `Ctrl-C` to close Blender in background-mode.
* Useful to be able to cancel a render operation. */
signal(SIGINT, sig_handle_blender_esc);
}
void main_signal_setup_fpe()
{
# if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE)
/* Zealous but makes float issues a heck of a lot easier to find!
* Set breakpoints on #sig_handle_fpe. */
signal(SIGFPE, sig_handle_fpe);
# if defined(__linux__) && defined(__GNUC__) && defined(HAVE_FEENABLEEXCEPT)
feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
# endif /* defined(__linux__) && defined(__GNUC__) */
# if defined(OSX_SSE_FPE)
/* OSX uses SSE for floating point by default, so here
* use SSE instructions to throw floating point exceptions. */
_MM_SET_EXCEPTION_MASK(_MM_MASK_MASK &
~(_MM_MASK_OVERFLOW | _MM_MASK_INVALID | _MM_MASK_DIV_ZERO));
# endif /* OSX_SSE_FPE */
# if defined(_WIN32) && defined(_MSC_VER)
/* Enables all floating-point exceptions. */
_controlfp_s(nullptr, 0, _MCW_EM);
/* Hide the ones we don't care about. */
_controlfp_s(nullptr, _EM_DENORMAL | _EM_UNDERFLOW | _EM_INEXACT, _MCW_EM);
# endif /* _WIN32 && _MSC_VER */
# endif
}
} // namespace blender
#endif /* WITH_PYTHON_MODULE */

View File

@@ -0,0 +1,71 @@
## The symbols will be treated as if they were marked as __private_extern__
## (aka visibility=hidden) and will not be global in the output file
al*
*Alembic*
av*
blosc*
*boost*
*ceres*
*cineon*
*clang*
cu*
decodeInstruction
*default_error_condition*
*dpx*
*embree*
ff_*
fftw*
FLAC*
ForceStackAlign
FT_*
*GeneratedSaxParser*
*google*
gsm*
Gsm*
html*
id3tag*
*Iex*
*Ilm*
*Imath*
*Imf*
jack_*
jpeg_*
jsimd**
_Jv_RegisterClasses
lame_*
*llvm*
*LLVM*
*Manta*
*MathML*
*mkldnn*
Name
NumNamedVarArgParams
nvrtc*
oc_*
ogg*
*oidn*
*OpenColorIO*
*OpenImageIO*
*OpenSubdiv*
*openvdb*
opj_*
opus_*
*OSL*
*pathYy*
png_*
*SDL*
*squish*
*tbb*
*textFileFormatYy*
*TIFF*
*tinyformat*
*usdBlender*
vorbis*
vp8*
vp9*
vpx*
x264_*
X86CompilationCallback*
xml*
xvid*
*YAML*

View File

@@ -0,0 +1,45 @@
/* Hide all symbols except a few required ones.
*
* Otherwise LLVM symbols conflict with Mesa llvm pipe, boost symbols conflict
* with Luxrender, etc. */
{
global:
/* Essential symbols for the program to start and exit. */
_fini;
_init;
/* Needed for Python modules to work. */
Py*;
_Py*;
/* Needed for sanitizers. Based on:
* llvm/compiler-rt/lib/sanitizer_common/scripts/gen_dynamic_list.py. */
__asan*;
__lsan*;
__tsan*;
__ubsan*;
__sanitizer*;
/* Memory allocation (new, delete, malloc). */
__Znw*;
__Zna*;
__Zdl*;
__Zda*;
aligned_alloc*;
calloc*;
free*;
mallinfo*;
malloc*;
mallopt*;
memalign*;
memcpy*;
posix_memalign*;
pthread_*;
pvalloc*;
realloc*;
realpath*;
sched_*;
valloc*;
/* Needed on FreeBSD. Uses wildcard to avoid linker error when symbols are not found. */
__progname*;
environ*;
local:
*;
};