chore: checkpoint web Blender migration source, tools and docs
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled

Accumulated uncommitted work: GHOST Web backend, WebGL/GPU web layer,
web workflow engine and protocol, tooling, docs and task records.
Large generated evidence, user-testing archives, build snapshots and
imported test assets remain untracked.

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
mes123456
2026-11-10 11:18:01 +08:00
parent 122142c26c
commit f3e21c6b98
6887 changed files with 257154 additions and 12294 deletions

View File

@@ -342,8 +342,10 @@ bool ZstdWriteWrap::open(const char *filepath)
}
/* Leave one thread open for the main writing logic, unless we only have one HW thread. */
#if !defined(__EMSCRIPTEN__) || defined(__EMSCRIPTEN_PTHREADS__)
int num_threads = max_ii(1, BLI_system_thread_count() - 1);
BLI_threadpool_init(&threadpool, ZstdWriteBlockTask::write_task, num_threads);
#endif
BLI_mutex_init(&mutex);
BLI_condition_init(&condition);
@@ -393,7 +395,9 @@ void ZstdWriteWrap::write_seekable_frames()
bool ZstdWriteWrap::close()
{
#if !defined(__EMSCRIPTEN__) || defined(__EMSCRIPTEN_PTHREADS__)
BLI_threadpool_end(&threadpool);
#endif
tasks.free_no_destruct();
BLI_mutex_end(&mutex);
@@ -418,6 +422,11 @@ bool ZstdWriteWrap::write(const void *buf, const size_t buf_len)
task->frame_number = num_frames++;
task->ww = this;
#if defined(__EMSCRIPTEN__) && !defined(__EMSCRIPTEN_PTHREADS__)
write_task(task);
MEM_delete(task);
return !write_error;
#endif
BLI_mutex_lock(&mutex);
BLI_addtail(&tasks, task);
@@ -1302,7 +1311,7 @@ static void write_id_placeholder(WriteData *wd, ID *id)
}
/** Keep it last of `write_*_data` functions. */
static void write_libraries(WriteData *wd, Main *bmain)
static void write_libraries(WriteData *wd, Main *bmain, const bool materialize_linked_ids)
{
const bool is_undo = wd->use_memfile;
@@ -1327,7 +1336,13 @@ static void write_libraries(WriteData *wd, Main *bmain)
/* Gather IDs that are somehow directly referenced by data in the current blend file. */
Vector<ID *> ids_used_from_library;
if (is_undo) {
if (materialize_linked_ids) {
/* Read-only SceneIR projection of the already loaded Main. Include indirect data too;
* Object.data, materials and nested collections must resolve to complete native IDs.
* This stream is never used as a saved blend or an undo checkpoint. */
ids_used_from_library = ids;
}
else if (is_undo) {
/* Always write placeholders for all linked IDs in undo case. This allows to properly remove
* linked data that should not exist on undo/redo. See also #read_undo_move_libmain_data,
* #read_libblock_undo_restore_linked and #read_undo_libraries_cleanup_unused_ids. */
@@ -1417,7 +1432,7 @@ static void write_libraries(WriteData *wd, Main *bmain)
/* Write placeholders for linked data-blocks that are used, and real IDs for the packed linked
* ones. */
for (ID *id : ids_used_from_library) {
if (ID_IS_PACKED(id)) {
if (materialize_linked_ids || ID_IS_PACKED(id)) {
write_id(wd, id);
}
else {
@@ -1448,7 +1463,11 @@ extern "C" char build_hash[];
* - for forward compatibility, `curscreen` has to be saved
* - for undo-file, `curscene` needs to be saved.
*/
static void write_global(WriteData *wd, const int fileflags, Main *mainvar)
static void write_global(WriteData *wd,
const int fileflags,
Main *mainvar,
Scene *current_scene,
ViewLayer *current_view_layer)
{
const bool is_undo = wd->use_memfile;
FileGlobal fg;
@@ -1464,6 +1483,10 @@ static void write_global(WriteData *wd, const int fileflags, Main *mainvar)
fg._pad1 = nullptr;
current_screen_compat(mainvar, is_undo, &screen, &scene, &view_layer);
if (!scene && current_scene) {
scene = current_scene;
view_layer = current_view_layer ? current_view_layer : BKE_view_layer_default_view(scene);
}
/* XXX: still remap `G`. */
fg.curscreen = screen;
@@ -1564,6 +1587,10 @@ BLO_Write_IDBuffer::BLO_Write_IDBuffer(ID &id, const bool is_undo, const bool is
}
temp_id->us = 0;
temp_id->icon_id = 0;
#ifdef WITH_WEB
// Dependency evaluation and undo-dirty tags are runtime state in ordinary Web snapshots.
if (!is_undo) { temp_id->recalc = 0; temp_id->recalc_after_undo_push = 0; }
#endif
temp_id->runtime = nullptr;
/* Those listbase data change every time we add/remove an ID, and also often when
* renaming one (due to re-sorting). This avoids generating a lot of false 'is changed'
@@ -1735,7 +1762,10 @@ static bool write_file_handle(Main *mainvar,
const int write_flags,
const bool use_userdef,
const BlendThumbnail *thumb,
std::ostream *debug_dst)
std::ostream *debug_dst,
const bool materialize_linked_ids = false,
Scene *current_scene = nullptr,
ViewLayer *current_view_layer = nullptr)
{
WriteData *wd;
@@ -1758,7 +1788,7 @@ static bool write_file_handle(Main *mainvar,
write_blend_file_header(wd);
write_renderinfo(wd, mainvar);
write_thumb(wd, thumb);
write_global(wd, write_flags, mainvar);
write_global(wd, write_flags, mainvar, current_scene, current_view_layer);
/* The window-manager and screen often change,
* avoid thumbnail detecting changes because of this. */
@@ -1784,7 +1814,7 @@ static bool write_file_handle(Main *mainvar,
}
/* Write libraries about libraries and linked data-blocks. */
write_libraries(wd, mainvar);
write_libraries(wd, mainvar, materialize_linked_ids);
/* So changes above don't cause a 'DNA1' to be detected as changed on undo. */
mywrite_flush(wd);
@@ -2124,14 +2154,36 @@ bool BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, const
bool BLO_write_file_to_callback(Main *mainvar,
const int write_flags,
BLO_WriteFileCallback callback,
void *user_data)
void *user_data,
const bool materialize_linked_ids_for_snapshot,
Scene *current_scene,
ViewLayer *current_view_layer)
{
if (callback == nullptr) {
return false;
}
/* Reject foreign or retired pointers before emitting any bytes. */
if (current_scene) {
bool scene_found = false;
for (Scene &scene : mainvar->scenes) {
if (&scene == current_scene) scene_found = true;
}
if (!scene_found) return false;
if (current_view_layer) {
bool layer_found = false;
for (ViewLayer &view_layer : current_scene->view_layers) {
if (&view_layer == current_view_layer) layer_found = true;
}
if (!layer_found) return false;
}
}
else if (current_view_layer) {
return false;
}
CallbackWriteWrap callback_wrap(callback, user_data);
const bool err = write_file_handle(
mainvar, &callback_wrap, nullptr, nullptr, write_flags, false, nullptr, nullptr);
mainvar, &callback_wrap, nullptr, nullptr, write_flags, false, nullptr, nullptr,
materialize_linked_ids_for_snapshot, current_scene, current_view_layer);
return (err == 0);
}
@@ -2288,6 +2340,8 @@ void BLO_write_generated_pointer_tag(BlendWriter *writer, const void *data)
return;
}
if (!BLO_write_is_undo(writer)) {
/* Generated storage can reuse an earlier ID's temporary allocation. */
writer->wd->stable_address_ids.pointer_map.remove(data);
return;
}
const uint64_t address_id = get_address_id_for_undo(*writer->wd);