Files
test2/source/blender/blenloader/CMakeLists.txt
Jacques Lucke cadb3fe5c5 Blenloader: stable pointers in .blend files
When writing .blend files, Blender traditionally wrote raw runtime-pointers into
the file. Since these pointers are different whenever Blender is restarted or
the file is loaded again, the written .blend file will be very different every
time. The file always changing is a problem with tools that use change-detection
on .blend files such as:
* Change detection during undo in Blender. When a serialized data-block is the
  same in two consecutive undo steps, it's known that the data didn't change and
  the data-block does not have to be reloaded and can potentially skip depsgraph
  evaluation. Also see #141262.
* BAT: https://projects.blender.org/studio/flamenco/issues/104437
* Generally using .blend files in version control. The diffs can be smaller when
  pointers aren't changing all the time and have a lower memory footprint.

This PR makes pointers in .blend files across multiples saves much more
consistent, improving the situation for the cases above. Although there is still
other data that changes on almost every save currently; that needs to be
addressed separately.

The basic design for pointer stability in blend files stable pointers, described
in #127706, is fairly straight forward. This patch implements a slightly
modified variant of that design. When reading .blend files, Blender already does
not care if the stored pointer values are actual pointer values, or just some
arbitrary identifiers. Therefore, we mainly just have to change the write-file
code. This also implies that this change is fully forward and backward
compatible.

The main non-obvious aspect of this patch is how to actually do the remapping of
runtime pointers to stable identifiers. In theory, having a single integer that
increments for every newly detected pointer works. But in practice that leads to
many changes in the .blend file because one pointer is added or removed
somewhere, all subsequent pointers will be different too. So some kind of
scoping is required to make sure that one small change does not affect
everything else.

This PR starts a new scope pointer identifier scope whenever a new ID data-block
starts. At first I thought it would be good to have separate maps for id-local
and global pointers. However, that's tricky currently, because at write-time, we
don't always have enough information to know if a specific pointer is local or
global. I worked on #146136 to improve the situation but the problem is bigger
than that since we also have various void pointers in DNA structs. Fortunately,
the solution implemented now also works fine with a single global map.

Implicit sharing in undo steps also had to be changed slightly to work with the
stable address identifiers instead of raw pointers.

There's also new code to find all pointers in DNA structs in the first place.
This is done once when writing starts. Then whenever a struct is written, a copy
is made, all pointers are replaced and the modified struct is written to the
.blend file. There is an optimization for the case when a struct does not
contain any pointers because then the copy can be skipped.

For checking the diff between two saved .blend files, I recommend enabling
`GENERATE_DEBUG_BLEND_FILE` and then diffing the text version of the .blend
files.

Co-authored-by: Hans Goudey <hans@blender.org>

Pull Request: https://projects.blender.org/blender/blender/pulls/127729
2025-09-29 13:56:13 +02:00

144 lines
3.1 KiB
CMake

# SPDX-FileCopyrightText: 2006 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
set(INC
PUBLIC .
../editors/include
../makesrna
# RNA_prototypes.hh
${CMAKE_BINARY_DIR}/source/blender/makesrna
)
set(INC_SYS
${ZSTD_INCLUDE_DIRS}
)
set(SRC
${CMAKE_SOURCE_DIR}/release/datafiles/userdef/userdef_default_theme.c
intern/blend_validate.cc
intern/readblenentry.cc
intern/readfile.cc
intern/readfile_tempload.cc
intern/undofile.cc
intern/versioning_250.cc
intern/versioning_260.cc
intern/versioning_270.cc
intern/versioning_280.cc
intern/versioning_290.cc
intern/versioning_300.cc
intern/versioning_400.cc
intern/versioning_410.cc
intern/versioning_420.cc
intern/versioning_430.cc
intern/versioning_440.cc
intern/versioning_450.cc
intern/versioning_500.cc
intern/versioning_common.cc
intern/versioning_defaults.cc
intern/versioning_dna.cc
intern/versioning_legacy.cc
intern/versioning_userdef.cc
intern/writefile.cc
BLO_blend_validate.hh
BLO_read_write.hh
BLO_readfile.hh
BLO_undofile.hh
BLO_userdef_default.h
BLO_writefile.hh
intern/readfile.hh
intern/versioning_common.hh
)
set(LIB
PRIVATE bf::animrig
PRIVATE bf::asset_system
PRIVATE bf::blenkernel
PRIVATE bf::blenlib
PUBLIC bf::blenloader_core
PRIVATE bf::blentranslation
PRIVATE bf::bmesh
PRIVATE bf::depsgraph
PRIVATE bf::dna
PRIVATE bf::draw
PRIVATE bf::gpu
PRIVATE bf::imbuf
PRIVATE bf::imbuf::movie
PRIVATE bf::intern::clog
PRIVATE bf::intern::guardedalloc
PRIVATE bf::extern::fmtlib
PRIVATE bf::intern::memutil
PRIVATE bf::nodes
PRIVATE bf::render
PRIVATE bf::sequencer
PRIVATE bf::windowmanager
PRIVATE bf::extern::xxhash
)
if(WITH_BUILDINFO)
add_definitions(-DWITH_BUILDINFO)
endif()
if(WITH_CODEC_FFMPEG)
add_definitions(-DWITH_FFMPEG)
endif()
if(WITH_ALEMBIC)
list(APPEND INC
../io/alembic
)
add_definitions(-DWITH_ALEMBIC)
endif()
if(WIN32)
add_definitions(-DNOMINMAX)
endif()
blender_add_lib(bf_blenloader "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
add_library(bf::blenloader ALIAS bf_blenloader)
# RNA_prototypes.hh
add_dependencies(bf_blenloader bf_rna)
if(WITH_GTESTS)
# Utility functions for test also used by other tests.
set(TEST_UTIL_SRC
tests/blendfile_loading_base_test.cc
tests/blendfile_loading_base_test.h
)
set(TEST_UTIL_INC
${INC}
../../../tests/gtests
../../../intern/ghost
)
set(TEST_UTIL_INC_SYS
${INC_SYS}
${GFLAGS_INCLUDE_DIRS}
${GLOG_INCLUDE_DIRS}
${CMAKE_SOURCE_DIR}/extern/gtest/include
)
set(TEST_UTIL_LIB
${LIB}
PRIVATE bf::blenfont
bf_blenloader
)
blender_add_lib(bf_blenloader_test_util "${TEST_UTIL_SRC}" "${TEST_UTIL_INC}" "${TEST_UTIL_INC_SYS}" "${TEST_UTIL_LIB}")
# Actual `blenloader` tests.
set(TEST_SRC
tests/blendfile_load_test.cc
)
set(TEST_LIB
${LIB}
bf_blenloader
bf_blenloader_test_util
)
blender_add_test_suite_lib(blenloader "${TEST_SRC}" "${INC}" "${INC_SYS}" "${TEST_LIB}")
endif()
if(WITH_EXPERIMENTAL_FEATURES)
add_definitions(-DWITH_EXPERIMENTAL_FEATURES)
endif()