Geometry Nodes: new repeat zone #109164

Merged
Jacques Lucke merged 98 commits from JacquesLucke/blender:serial-loop into main 2023-07-11 22:36:17 +02:00
58 changed files with 2405 additions and 575 deletions
Showing only changes of commit aab9abf8d1 - Show all commits

View File

@ -122,5 +122,6 @@ if(BUILD_MODE STREQUAL Release AND WIN32)
COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/lld.exe
COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/lld-link.exe
COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/wasm-ld.exe
DEPENDEES install
)
endif()

View File

@ -46,7 +46,7 @@ ${temp_LIBDIR}/vpx/lib/pkgconfig:\
${temp_LIBDIR}/theora/lib/pkgconfig:\
${temp_LIBDIR}/openjpeg/lib/pkgconfig:\
${temp_LIBDIR}/opus/lib/pkgconfig:\
${temp_LIBDIR}/aom/lib/pkgconfig"
${temp_LIBDIR}/aom/lib/pkgconfig:"
)
unset(temp_LIBDIR)

View File

@ -2,35 +2,45 @@
set(FFTW_EXTRA_ARGS)
if(WIN32)
set(FFTW3_PATCH_COMMAND ${PATCH_CMD} --verbose -p 0 -N -d ${BUILD_DIR}/fftw3/src/external_fftw3 < ${PATCH_DIR}/fftw3.diff)
set(FFTW_EXTRA_ARGS --disable-static --enable-shared)
set(FFTW_INSTALL install-strip)
else()
set(FFTW_EXTRA_ARGS --enable-static)
set(FFTW_INSTALL install)
endif()
macro(fftw_build FFTW_POSTFIX)
if(WIN32)
set(FFTW3_PATCH_COMMAND ${PATCH_CMD} --verbose -p 0 -N -d ${BUILD_DIR}/fftw3/src/external_fftw3_${FFTW_POSTFIX} < ${PATCH_DIR}/fftw3.diff)
set(FFTW_EXTRA_ARGS --disable-static --enable-shared)
set(FFTW_INSTALL install-strip)
else()
set(FFTW_EXTRA_ARGS --enable-static)
set(FFTW_INSTALL install)
endif()
ExternalProject_Add(external_fftw3_${FFTW_POSTFIX}
URL file://${PACKAGE_DIR}/${FFTW_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
URL_HASH ${FFTW_HASH_TYPE}=${FFTW_HASH}
PREFIX ${BUILD_DIR}/fftw3
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/fftw3/src/external_fftw3_${FFTW_POSTFIX}/ && ${CONFIGURE_COMMAND} ${FFTW_EXTRA_ARGS} ${ARGN} --prefix=${mingw_LIBDIR}/fftw3
PATCH_COMMAND ${FFTW3_PATCH_COMMAND}
BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/fftw3/src/external_fftw3_${FFTW_POSTFIX}/ && make -j${MAKE_THREADS}
INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/fftw3/src/external_fftw3_${FFTW_POSTFIX}/ && make ${FFTW_INSTALL}
INSTALL_DIR ${LIBDIR}/fftw3
)
endmacro()
ExternalProject_Add(external_fftw3
URL file://${PACKAGE_DIR}/${FFTW_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
URL_HASH ${FFTW_HASH_TYPE}=${FFTW_HASH}
PREFIX ${BUILD_DIR}/fftw3
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/fftw3/src/external_fftw3/ && ${CONFIGURE_COMMAND} ${FFTW_EXTRA_ARGS} --prefix=${mingw_LIBDIR}/fftw3
PATCH_COMMAND ${FFTW3_PATCH_COMMAND}
BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/fftw3/src/external_fftw3/ && make -j${MAKE_THREADS}
INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/fftw3/src/external_fftw3/ && make ${FFTW_INSTALL}
INSTALL_DIR ${LIBDIR}/fftw3
)
fftw_build(double)
fftw_build(float --enable-float)
if(MSVC)
set_target_properties(external_fftw3 PROPERTIES FOLDER Mingw)
set_target_properties(external_fftw3_double PROPERTIES FOLDER Mingw)
if(BUILD_MODE STREQUAL Release)
ExternalProject_Add_Step(external_fftw3 after_install
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/fftw3/lib/libfftw3.dll.a ${HARVEST_TARGET}/fftw3/lib/libfftw.lib
ExternalProject_Add_Step(external_fftw3_double after_install
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/fftw3/lib/libfftw3.dll.a ${HARVEST_TARGET}/fftw3/lib/libfftw3-3.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/fftw3/bin/libfftw3-3.dll ${HARVEST_TARGET}/fftw3/lib/libfftw3-3.dll
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/fftw3/include/fftw3.h ${HARVEST_TARGET}/fftw3/include/fftw3.h
DEPENDEES install
)
ExternalProject_Add_Step(external_fftw3_float after_install
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/fftw3/lib/libfftw3f.dll.a ${HARVEST_TARGET}/fftw3/lib/libfftw3f.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/fftw3/bin/libfftw3f-3.dll ${HARVEST_TARGET}/fftw3/lib/libfftw3f-3.dll
DEPENDEES install
)
endif()
endif()

View File

@ -218,7 +218,7 @@ else()
harvest(openimagedenoise/lib openimagedenoise/lib "*.a")
harvest(embree/include embree/include "*.h")
harvest(embree/lib embree/lib "*.a")
harvest(embree/lib embree/lib "*${SHAREDLIBEXT}*")
harvest_rpath_lib(embree/lib embree/lib "*${SHAREDLIBEXT}*")
harvest(openpgl/include openpgl/include "*.h")
harvest(openpgl/lib openpgl/lib "*.a")
harvest(openpgl/lib/cmake/openpgl-${OPENPGL_SHORT_VERSION} openpgl/lib/cmake/openpgl "*.cmake")

View File

@ -11,7 +11,7 @@ if(WIN32)
elseif(APPLE)
# Use bison and flex installed via Homebrew.
# The ones that come with Xcode toolset are too old.
if("${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "arm64")
if(BLENDER_PLATFORM_ARM)
set(ISPC_EXTRA_ARGS_APPLE
-DBISON_EXECUTABLE=/opt/homebrew/opt/bison/bin/bison
-DFLEX_EXECUTABLE=/opt/homebrew/opt/flex/bin/flex

View File

@ -2,11 +2,12 @@
set(MATERIALX_EXTRA_ARGS
-DMATERIALX_BUILD_PYTHON=ON
-DMATERIALX_BUILD_RENDER=OFF
-DMATERIALX_BUILD_RENDER=ON
-DMATERIALX_INSTALL_PYTHON=OFF
-DMATERIALX_PYTHON_EXECUTABLE=${PYTHON_BINARY}
-DMATERIALX_PYTHON_VERSION=${PYTHON_SHORT_VERSION}
-DMATERIALX_BUILD_SHARED_LIBS=ON
-DMATERIALX_BUILD_TESTS=OFF
-DCMAKE_DEBUG_POSTFIX=_d
-Dpybind11_ROOT=${LIBDIR}/pybind11
-DPython_EXECUTABLE=${PYTHON_BINARY}

View File

@ -27,6 +27,7 @@ ExternalProject_Add(external_openexr
URL file://${PACKAGE_DIR}/${OPENEXR_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
URL_HASH ${OPENEXR_HASH_TYPE}=${OPENEXR_HASH}
PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/openexr/src/external_openexr < ${PATCH_DIR}/openexr_b18905772e.diff
CMAKE_GENERATOR ${PLATFORM_ALT_GENERATOR}
PREFIX ${BUILD_DIR}/openexr
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openexr ${DEFAULT_CMAKE_FLAGS} ${OPENEXR_EXTRA_ARGS}

View File

@ -54,7 +54,7 @@ set(OPENIMAGEIO_EXTRA_ARGS
-DUSE_DCMTK=OFF
-DUSE_LIBHEIF=OFF
-DUSE_OPENGL=OFF
-DUSE_TBB=OFF
-DUSE_TBB=ON
-DUSE_QT=OFF
-DUSE_PYTHON=ON
-DUSE_GIF=OFF
@ -96,6 +96,7 @@ set(OPENIMAGEIO_EXTRA_ARGS
-DImath_ROOT=${LIBDIR}/imath
-Dpybind11_ROOT=${LIBDIR}/pybind11
-DPython_EXECUTABLE=${PYTHON_BINARY}
-DTBB_ROOT=${LIBDIR}/tbb
)
ExternalProject_Add(external_openimageio
@ -104,7 +105,8 @@ ExternalProject_Add(external_openimageio
URL_HASH ${OPENIMAGEIO_HASH_TYPE}=${OPENIMAGEIO_HASH}
CMAKE_GENERATOR ${PLATFORM_ALT_GENERATOR}
PREFIX ${BUILD_DIR}/openimageio
PATCH_COMMAND ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/openimageio.diff
PATCH_COMMAND ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/openimageio.diff &&
${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/oiio_3832.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openimageio ${DEFAULT_CMAKE_FLAGS} ${OPENIMAGEIO_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/openimageio
)
@ -125,6 +127,7 @@ add_dependencies(
external_webp
external_python
external_pybind11
external_tbb
)
if(WIN32)

View File

@ -35,7 +35,7 @@ if(WIN32)
# regardless of the version actually in there.
PATCH_COMMAND mkdir ${PYTHON_EXTERNALS_FOLDER_DOS} &&
mklink /J ${PYTHON_EXTERNALS_FOLDER_DOS}\\zlib-1.2.13 ${ZLIB_SOURCE_FOLDER_DOS} &&
mklink /J ${PYTHON_EXTERNALS_FOLDER_DOS}\\openssl-1.1.1q ${SSL_SOURCE_FOLDER_DOS} &&
mklink /J ${PYTHON_EXTERNALS_FOLDER_DOS}\\openssl-1.1.1t ${SSL_SOURCE_FOLDER_DOS} &&
${CMAKE_COMMAND} -E copy ${ZLIB_SOURCE_FOLDER}/../external_zlib-build/zconf.h ${PYTHON_EXTERNALS_FOLDER}/zlib-1.2.13/zconf.h &&
${PATCH_CMD} --verbose -p1 -d ${BUILD_DIR}/python/src/external_python < ${PATCH_DIR}/python_windows.diff
CONFIGURE_COMMAND echo "."

View File

@ -1,7 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-or-later
set(SSL_CONFIGURE_COMMAND ./Configure)
set(SSL_PATCH_CMD echo .)
if(WIN32)
# Python will build this with its preferred build options and patches. We only need to unpack openssl
@ -18,7 +17,6 @@ if(WIN32)
else()
if(APPLE)
set(SSL_OS_COMPILER "blender-darwin-${CMAKE_OSX_ARCHITECTURES}")
set(SSL_PATCH_CMD ${PATCH_CMD} --verbose -p 0 -d ${BUILD_DIR}/ssl/src/external_ssl < ${PATCH_DIR}/ssl.diff)
else()
if(BLENDER_PLATFORM_ARM)
set(SSL_OS_COMPILER "blender-linux-aarch64")
@ -35,7 +33,6 @@ else()
DOWNLOAD_DIR ${DOWNLOAD_DIR}
URL_HASH ${SSL_HASH_TYPE}=${SSL_HASH}
PREFIX ${BUILD_DIR}/ssl
PATCH_COMMAND ${SSL_PATCH_CMD}
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ssl/src/external_ssl/ && ${SSL_CONFIGURE_COMMAND} --prefix=${LIBDIR}/ssl
--openssldir=${LIBDIR}/ssl
no-shared

View File

@ -15,8 +15,7 @@ if(WIN32)
-D_PXR_CXX_DEFINITIONS=/DBOOST_ALL_NO_LIB
-DCMAKE_SHARED_LINKER_FLAGS_INIT=/LIBPATH:${LIBDIR}/tbb/lib
-DPython_FIND_REGISTRY=NEVER
-DPYTHON_INCLUDE_DIRS=${LIBDIR}/python/include
-DPYTHON_LIBRARY=${LIBDIR}/python/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}${LIBEXT}
-DPython3_EXECUTABLE=${PYTHON_BINARY}
)
if(BUILD_MODE STREQUAL Debug)
list(APPEND USD_PLATFORM_FLAGS -DPXR_USE_DEBUG_PYTHON=ON)
@ -27,6 +26,12 @@ elseif(UNIX)
# part of the interpret in the USD library. Allow undefined Python symbols and replace
# Python library with TBB so it doesn't complain about missing library.
set(USD_PLATFORM_FLAGS
# NOTE(@ideasman42): Setting the root is needed, without this an older version of Python
# is detected from the system. Referencing the root-directory may remove the need
# to explicitly set the `PYTHON_INCLUDE_DIR` & `PYTHON_LIBRARY`.
# Keep them as it's known these are the libraries to use and it avoids any ambiguity.
-DPython3_ROOT_DIR=${LIBDIR}/python/
-DPYTHON_INCLUDE_DIR=${LIBDIR}/python/include/python${PYTHON_SHORT_VERSION}/
-DPYTHON_LIBRARY=${LIBDIR}/tbb/lib/${LIBPREFIX}${TBB_LIBRARY}${SHAREDLIBEXT}
)
@ -44,6 +49,7 @@ set(USD_EXTRA_ARGS
${USD_PLATFORM_FLAGS}
-DOPENSUBDIV_ROOT_DIR=${LIBDIR}/opensubdiv
-DOpenImageIO_ROOT=${LIBDIR}/openimageio
-DMaterialX_ROOT=${LIBDIR}/materialx
-DOPENEXR_LIBRARIES=${LIBDIR}/imath/lib/${LIBPREFIX}Imath${OPENEXR_VERSION_POSTFIX}${SHAREDLIBEXT}
-DOPENEXR_INCLUDE_DIR=${LIBDIR}/imath/include
-DImath_DIR=${LIBDIR}/imath
@ -56,9 +62,10 @@ set(USD_EXTRA_ARGS
-DPXR_BUILD_TUTORIALS=OFF
-DPXR_BUILD_USDVIEW=OFF
-DPXR_ENABLE_HDF5_SUPPORT=OFF
-DPXR_ENABLE_MATERIALX_SUPPORT=OFF
-DPXR_ENABLE_MATERIALX_SUPPORT=ON
-DPXR_ENABLE_OPENVDB_SUPPORT=ON
-DPYTHON_EXECUTABLE=${PYTHON_BINARY}
-DPython3_EXECUTABLE=${PYTHON_BINARY}
-DPXR_BUILD_MONOLITHIC=ON
# OSL is an optional dependency of the Imaging module. However, since that
# module was included for its support for converting primitive shapes (sphere,
@ -95,7 +102,12 @@ ExternalProject_Add(external_usd
CMAKE_GENERATOR ${PLATFORM_ALT_GENERATOR}
PREFIX ${BUILD_DIR}/usd
LIST_SEPARATOR ^^
PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/usd/src/external_usd < ${PATCH_DIR}/usd.diff
# usd_pull_1965.diff https://github.com/PixarAnimationStudios/USD/pull/1965
# usd_hydra.diff - https://github.com/bnagirniak/RPRHydraRenderBlenderAddon/blob/master/usd.diff
# usd_hydra.diff also included the blender changes and usd_pull_1965 and has been edited to remove those sections.
PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/usd/src/external_usd < ${PATCH_DIR}/usd.diff &&
${PATCH_CMD} -p 1 -d ${BUILD_DIR}/usd/src/external_usd < ${PATCH_DIR}/usd_pull_1965.diff &&
${PATCH_CMD} -p 1 -d ${BUILD_DIR}/usd/src/external_usd < ${PATCH_DIR}/usd_hydra.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/usd -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${USD_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/usd
)
@ -107,6 +119,7 @@ add_dependencies(
external_opensubdiv
external_python
external_openimageio
external_materialx
openvdb
)

View File

@ -58,16 +58,16 @@ set(PTHREADS_HASH f3bf81bb395840b3446197bcf4ecd653)
set(PTHREADS_HASH_TYPE MD5)
set(PTHREADS_FILE pthreads4w-code-${PTHREADS_VERSION}.zip)
set(OPENEXR_VERSION 3.1.5)
set(OPENEXR_VERSION 3.1.7)
set(OPENEXR_URI https://github.com/AcademySoftwareFoundation/openexr/archive/v${OPENEXR_VERSION}.tar.gz)
set(OPENEXR_HASH a92f38eedd43e56c0af56d4852506886)
set(OPENEXR_HASH ae68f0cb8b30a49c961fa87d31c60394)
set(OPENEXR_HASH_TYPE MD5)
set(OPENEXR_FILE openexr-${OPENEXR_VERSION}.tar.gz)
set(OPENEXR_CPE "cpe:2.3:a:openexr:openexr:${OPENEXR_VERSION}:*:*:*:*:*:*:*")
set(IMATH_VERSION 3.1.5)
set(IMATH_VERSION 3.1.7)
set(IMATH_URI https://github.com/AcademySoftwareFoundation/Imath/archive/v${OPENEXR_VERSION}.tar.gz)
set(IMATH_HASH dd375574276c54872b7b3d54053baff0)
set(IMATH_HASH 5cedab446ab296c080957c3037c6d097)
set(IMATH_HASH_TYPE MD5)
set(IMATH_FILE imath-${IMATH_VERSION}.tar.gz)
@ -88,9 +88,9 @@ else()
set(OPENEXR_VERSION_POSTFIX)
endif()
set(FREETYPE_VERSION 2.12.1)
set(FREETYPE_VERSION 2.13.0)
set(FREETYPE_URI http://prdownloads.sourceforge.net/freetype/freetype-${FREETYPE_VERSION}.tar.gz)
set(FREETYPE_HASH 8bc5c9c9df7ac12c504f8918552a7cf2)
set(FREETYPE_HASH 98bc3cf234fe88ef3cf24569251fe0a4)
set(FREETYPE_HASH_TYPE MD5)
set(FREETYPE_FILE freetype-${FREETYPE_VERSION}.tar.gz)
SET(FREETYPE_CPE "cpe:2.3:a:freetype:freetype:${FREETYPE_VERSION}:*:*:*:*:*:*:*")
@ -112,7 +112,6 @@ set(ALEMBIC_URI https://github.com/alembic/alembic/archive/${ALEMBIC_VERSION}.ta
set(ALEMBIC_HASH 2cd8d6e5a3ac4a014e24a4b04f4fadf9)
set(ALEMBIC_HASH_TYPE MD5)
set(ALEMBIC_FILE alembic-${ALEMBIC_VERSION}.tar.gz)
SET(FREETYPE_CPE "cpe:2.3:a:freetype:freetype:${FREETYPE_VERSION}:*:*:*:*:*:*:*")
set(OPENSUBDIV_VERSION v3_5_0)
set(OPENSUBDIV_URI https://github.com/PixarAnimationStudios/OpenSubdiv/archive/${OPENSUBDIV_VERSION}.tar.gz)
@ -165,17 +164,17 @@ set(OPENMP_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${
set(OPENMP_HASH_TYPE MD5)
set(OPENMP_FILE openmp-${OPENMP_VERSION}.src.tar.xz)
set(OPENIMAGEIO_VERSION v2.4.9.0)
set(OPENIMAGEIO_VERSION v2.4.11.0)
set(OPENIMAGEIO_URI https://github.com/OpenImageIO/oiio/archive/refs/tags/${OPENIMAGEIO_VERSION}.tar.gz)
set(OPENIMAGEIO_HASH 7da92a7d6029921a8599a977ff1efa2a)
set(OPENIMAGEIO_HASH 7eb997479ecfe7d9fa59cc8ddd35d0ae)
set(OPENIMAGEIO_HASH_TYPE MD5)
set(OPENIMAGEIO_FILE OpenImageIO-${OPENIMAGEIO_VERSION}.tar.gz)
# 8.0.0 is currently oiio's preferred version although never versions may be available.
# 9.1.0 is currently oiio's preferred version although never versions may be available.
# the preferred version can be found in oiio's externalpackages.cmake
set(FMT_VERSION 8.0.0)
set(FMT_VERSION 9.1.0)
set(FMT_URI https://github.com/fmtlib/fmt/archive/refs/tags/${FMT_VERSION}.tar.gz)
set(FMT_HASH 7bce0e9e022e586b178b150002e7c2339994e3c2bbe44027e9abb0d60f9cce83)
set(FMT_HASH 5dea48d1fcddc3ec571ce2058e13910a0d4a6bab4cc09a809d8b1dd1c88ae6f2)
set(FMT_HASH_TYPE SHA256)
set(FMT_FILE fmt-${FMT_VERSION}.tar.gz)
set(FMT_CPE "cpe:2.3:a:fmt:fmt:${FMT_VERSION}:*:*:*:*:*:*:*")
@ -209,11 +208,11 @@ set(OSL_FILE OpenShadingLanguage-${OSL_VERSION}.tar.gz)
# BZIP2, FFI, SQLITE and change the versions in this file as well. For compliance
# reasons there can be no exceptions to this.
set(PYTHON_VERSION 3.10.9)
set(PYTHON_VERSION 3.10.11)
set(PYTHON_SHORT_VERSION 3.10)
set(PYTHON_SHORT_VERSION_NO_DOTS 310)
set(PYTHON_URI https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tar.xz)
set(PYTHON_HASH dc8c0f274b28ee9e95923d20cfc364c9)
set(PYTHON_HASH 1bf8481a683e0881e14d52e0f23633a6)
set(PYTHON_HASH_TYPE MD5)
set(PYTHON_FILE Python-${PYTHON_VERSION}.tar.xz)
set(PYTHON_CPE "cpe:2.3:a:python:python:${PYTHON_VERSION}:-:*:*:*:*:*:*")
@ -296,9 +295,9 @@ set(THEORA_HASH b6ae1ee2fa3d42ac489287d3ec34c5885730b1296f0801ae577a35193d3affbc
set(THEORA_HASH_TYPE SHA256)
set(THEORA_FILE libtheora-${THEORA_VERSION}.tar.bz2)
set(FLAC_VERSION 1.3.4)
set(FLAC_VERSION 1.4.2)
set(FLAC_URI http://downloads.xiph.org/releases/flac/flac-${FLAC_VERSION}.tar.xz)
set(FLAC_HASH 8ff0607e75a322dd7cd6ec48f4f225471404ae2730d0ea945127b1355155e737 )
set(FLAC_HASH e322d58a1f48d23d9dd38f432672865f6f79e73a6f9cc5a5f57fcaa83eb5a8e4 )
set(FLAC_HASH_TYPE SHA256)
set(FLAC_FILE flac-${FLAC_VERSION}.tar.xz)
set(FLAC_CPE "cpe:2.3:a:flac_project:flac:${FLAC_VERSION}:*:*:*:*:*:*:*")
@ -336,9 +335,9 @@ set(OPENJPEG_HASH_TYPE SHA256)
set(OPENJPEG_FILE openjpeg-v${OPENJPEG_VERSION}.tar.gz)
set(OPENJPEG_CPE "cpe:2.3:a:uclouvain:openjpeg:${OPENJPEG_VERSION}:*:*:*:*:*:*:*")
set(FFMPEG_VERSION 5.1.2)
set(FFMPEG_VERSION 6.0)
set(FFMPEG_URI http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.bz2)
set(FFMPEG_HASH 39a0bcc8d98549f16c570624678246a6ac736c066cebdb409f9502e915b22f2b)
set(FFMPEG_HASH 47d062731c9f66a78380e35a19aac77cebceccd1c7cc309b9c82343ffc430c3d)
set(FFMPEG_HASH_TYPE SHA256)
set(FFMPEG_FILE ffmpeg-${FFMPEG_VERSION}.tar.bz2)
set(FFMPEG_CPE "cpe:2.3:a:ffmpeg:ffmpeg:${FFMPEG_VERSION}:*:*:*:*:*:*:*")
@ -460,9 +459,9 @@ set(LZMA_HASH_TYPE SHA256)
set(LZMA_FILE xz-${LZMA_VERSION}.tar.bz2)
# NOTE: Python's build has been modified to use our ssl version.
set(SSL_VERSION 1.1.1q)
set(SSL_VERSION 1.1.1t)
set(SSL_URI https://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz)
set(SSL_HASH d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca)
set(SSL_HASH 8dee9b24bdb1dcbf0c3d1e9b02fb8f6bf22165e807f45adeb7c9677536859d3b)
set(SSL_HASH_TYPE SHA256)
set(SSL_FILE openssl-${SSL_VERSION}.tar.gz)
set(SSL_CPE "cpe:2.3:a:openssl:openssl:${SSL_VERSION}:*:*:*:*:*:*:*")
@ -470,10 +469,10 @@ set(SSL_CPE "cpe:2.3:a:openssl:openssl:${SSL_VERSION}:*:*:*:*:*:*:*")
# Note: This will *HAVE* to match the version python ships on windows which
# is hardcoded in pythons PCbuild/get_externals.bat for compliance reasons there
# can be no exceptions to this.
set(SQLITE_VERSION 3.39.4)
set(SQLLITE_LONG_VERSION 3390400)
set(SQLITE_VERSION 3.40.1)
set(SQLLITE_LONG_VERSION 3400100)
set(SQLITE_URI https://www.sqlite.org/2022/sqlite-autoconf-${SQLLITE_LONG_VERSION}.tar.gz)
set(SQLITE_HASH c4c5c39269d1b9bb1487cff580c1f583608229b2)
set(SQLITE_HASH b8c2d4bc0094f5c0ce985dc0e237dfcbaa1f6275)
set(SQLITE_HASH_TYPE SHA1)
set(SQLITE_FILE sqlite-autoconf-${SQLLITE_LONG_VERSION}.tar.gz)
set(SQLITE_CPE "cpe:2.3:a:sqlite:sqlite:${SQLITE_VERSION}:*:*:*:*:*:*:*")
@ -484,9 +483,9 @@ set(EMBREE_HASH dd26617719a587e126b341d1b32f7fd0)
set(EMBREE_HASH_TYPE MD5)
set(EMBREE_FILE embree-v${EMBREE_VERSION}.zip)
set(USD_VERSION 22.11)
set(USD_VERSION 23.05)
set(USD_URI https://github.com/PixarAnimationStudios/USD/archive/v${USD_VERSION}.tar.gz)
set(USD_HASH 8c89459e48a2ef0e7ae9e7e490377507)
set(USD_HASH 56684f4fdd1a9209dabf03856be5eca6)
set(USD_HASH_TYPE MD5)
set(USD_FILE usd-v${USD_VERSION}.tar.gz)

View File

@ -9,77 +9,3 @@
enabled libopenmpt && require_pkg_config libopenmpt "libopenmpt >= 0.2.6557" libopenmpt/libopenmpt.h openmpt_module_create -lstdc++ && append libopenmpt_extralibs "-lstdc++"
enabled libopus && {
enabled libopus_decoder && {
--- a/libavcodec/cfhddata.c
+++ b/libavcodec/cfhddata.c
@@ -276,10 +276,10 @@
av_cold int ff_cfhd_init_vlcs(CFHDContext *s)
{
int i, j, ret = 0;
- uint32_t new_cfhd_vlc_bits[NB_VLC_TABLE_18 * 2];
- uint8_t new_cfhd_vlc_len[NB_VLC_TABLE_18 * 2];
- uint16_t new_cfhd_vlc_run[NB_VLC_TABLE_18 * 2];
- int16_t new_cfhd_vlc_level[NB_VLC_TABLE_18 * 2];
+ uint32_t *new_cfhd_vlc_bits = av_calloc(sizeof(uint32_t), NB_VLC_TABLE_18 * 2);
+ uint8_t *new_cfhd_vlc_len = av_calloc(sizeof(uint8_t), NB_VLC_TABLE_18 * 2);
+ uint16_t *new_cfhd_vlc_run = av_calloc(sizeof(uint16_t), NB_VLC_TABLE_18 * 2);
+ int16_t *new_cfhd_vlc_level = av_calloc(sizeof(int16_t), NB_VLC_TABLE_18 * 2);
/** Similar to dv.c, generate signed VLC tables **/
@@ -305,8 +305,13 @@
ret = init_vlc(&s->vlc_9, VLC_BITS, j, new_cfhd_vlc_len,
1, 1, new_cfhd_vlc_bits, 4, 4, 0);
- if (ret < 0)
+ if (ret < 0) {
+ av_free(new_cfhd_vlc_bits);
+ av_free(new_cfhd_vlc_len);
+ av_free(new_cfhd_vlc_run);
+ av_free(new_cfhd_vlc_level);
return ret;
+ }
for (i = 0; i < s->vlc_9.table_size; i++) {
int code = s->vlc_9.table[i][0];
int len = s->vlc_9.table[i][1];
@@ -346,8 +351,14 @@
ret = init_vlc(&s->vlc_18, VLC_BITS, j, new_cfhd_vlc_len,
1, 1, new_cfhd_vlc_bits, 4, 4, 0);
- if (ret < 0)
+ if (ret < 0) {
+ av_free(new_cfhd_vlc_bits);
+ av_free(new_cfhd_vlc_len);
+ av_free(new_cfhd_vlc_run);
+ av_free(new_cfhd_vlc_level);
return ret;
+ }
+
av_assert0(s->vlc_18.table_size == 4572);
for (i = 0; i < s->vlc_18.table_size; i++) {
@@ -367,5 +378,10 @@
s->table_18_rl_vlc[i].run = run;
}
+ av_free(new_cfhd_vlc_bits);
+ av_free(new_cfhd_vlc_len);
+ av_free(new_cfhd_vlc_run);
+ av_free(new_cfhd_vlc_level);
+
return ret;
}
diff --git a/libavcodec/x86/simple_idct.asm b/libavcodec/x86/simple_idct.asm
index dcf0da6df121..982b2f0bbba1 100644
--- a/libavcodec/x86/simple_idct.asm
+++ b/libavcodec/x86/simple_idct.asm
@@ -25,9 +25,9 @@
%include "libavutil/x86/x86util.asm"
-%if ARCH_X86_32
SECTION_RODATA
+%if ARCH_X86_32
cextern pb_80
wm1010: dw 0, 0xffff, 0, 0xffff

View File

@ -0,0 +1,13 @@
diff --git a/src/python/py_oiio.cpp b/src/python/py_oiio.cpp
index 6031d2c23..e71105da5 100644
--- a/src/python/py_oiio.cpp
+++ b/src/python/py_oiio.cpp
@@ -153,7 +153,7 @@ oiio_bufinfo::oiio_bufinfo(const py::buffer_info& pybuf, int nchans, int width,
format = TypeUnknown; // No idea what's going on -- error
error = Strutil::fmt::format(
"Python array shape is [{:,}] but expecting h={}, w={}, ch={}",
- cspan<ssize_t>(pybuf.shape), height, width, nchans);
+ cspan<py::ssize_t>(pybuf.shape), height, width, nchans);
}
} else if (pixeldims == 1) {
// Reading a 1D scanline span

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
diff --git a/pxr/usd/usdMtlx/reader.cpp b/pxr/usd/usdMtlx/reader.cpp
index 29e901816..e6fc68b20 100644
--- a/pxr/usd/usdMtlx/reader.cpp
+++ b/pxr/usd/usdMtlx/reader.cpp
@@ -797,6 +797,15 @@ _NodeGraphBuilder::_CreateInterfaceInputs(
// We deliberately ignore tokens here.
}
+mx::StringSet _GetStdlibIncludes() {
+ mx::StringSet stdlibIncludes = UsdMtlxGetDocument("")->getReferencedSourceUris();
+ mx::StringSet normStdlibIncludes;
+ for (std::string const& entry : stdlibIncludes) {
+ normStdlibIncludes.insert(TfNormPath(entry));
+ }
+ return normStdlibIncludes;
+}
+
// Returns True if the mtlxNodeDef corresponds to a locally defined custom node
// with an associated nodegraph.
// XXX Locally defined custom nodes without nodegraphs are not supported
@@ -818,13 +827,14 @@ _NodeGraphBuilder::_IsLocalCustomNode(const mx::ConstNodeDefPtr &mtlxNodeDef)
}
// Combine with the nodeDef relative path
nodeDefUri = TfNormPath(fullMtlxPath + nodeDefUri);
+ } else {
+ nodeDefUri = TfNormPath(nodeDefUri);
}
// This is a locally defined custom node if the absolute path to the
// nodedef is not included in the stdlibDoc.
static mx::StringSet customNodeDefNames;
- static const mx::StringSet stdlibIncludes =
- UsdMtlxGetDocument("")->getReferencedSourceUris();
+ static const mx::StringSet stdlibIncludes = _GetStdlibIncludes();
if (stdlibIncludes.find(nodeDefUri) == stdlibIncludes.end()) {
// Check if we already used this custom node
if (std::find(customNodeDefNames.begin(), customNodeDefNames.end(),

View File

@ -0,0 +1,106 @@
diff --git a/build_scripts/build_usd.py b/build_scripts/build_usd.py
index cfe243effb..a4bb94eee1 100644
--- a/build_scripts/build_usd.py
+++ b/build_scripts/build_usd.py
@@ -1415,7 +1415,7 @@ def InstallDraco(context, force, buildArgs):
############################################################
# MaterialX
-MATERIALX_URL = "https://github.com/materialx/MaterialX/archive/v1.38.4.zip"
+MATERIALX_URL = "https://github.com/materialx/MaterialX/archive/v1.38.5.zip"
def InstallMaterialX(context, force, buildArgs):
with CurrentWorkingDirectory(DownloadURL(MATERIALX_URL, context, force)):
diff --git a/pxr/imaging/hdSt/materialXShaderGen.cpp b/pxr/imaging/hdSt/materialXShaderGen.cpp
index df80ff119f..e4b5f04a73 100644
--- a/pxr/imaging/hdSt/materialXShaderGen.cpp
+++ b/pxr/imaging/hdSt/materialXShaderGen.cpp
@@ -136,8 +136,7 @@ HdStMaterialXShaderGen::HdStMaterialXShaderGen(
"st" : mxHdInfo.defaultTexcoordName;
// Register the customized version of the Surface node generator
- registerImplementation("IM_surface_" + GlslShaderGenerator::TARGET,
- HdStMaterialXSurfaceNodeGen::create);
+ registerImplementation("IM_surface_genglsl", HdStMaterialXSurfaceNodeGen::create);
}
// Based on GlslShaderGenerator::generate()
@@ -273,8 +272,7 @@ HdStMaterialXShaderGen::_EmitMxFunctions(
mx::ShaderStage& mxStage) const
{
// Add global constants and type definitions
- emitLibraryInclude("stdlib/" + mx::GlslShaderGenerator::TARGET
- + "/lib/mx_math.glsl", mxContext, mxStage);
+ emitLibraryInclude("stdlib/genglsl/lib/mx_math.glsl", mxContext, mxStage);
emitLine("#if NUM_LIGHTS > 0", mxStage, false);
emitLine("#define MAX_LIGHT_SOURCES NUM_LIGHTS", mxStage, false);
emitLine("#else", mxStage, false);
@@ -394,16 +392,24 @@ HdStMaterialXShaderGen::_EmitMxFunctions(
emitSpecularEnvironment(mxContext, mxStage);
}
if (shadowing) {
- emitLibraryInclude("pbrlib/" + mx::GlslShaderGenerator::TARGET
- + "/lib/mx_shadow.glsl", mxContext, mxStage);
+ emitLibraryInclude("pbrlib/genglsl/lib/mx_shadow.glsl", mxContext, mxStage);
}
+#if MATERIALX_MAJOR_VERSION > 1 || \
+ (MATERIALX_MAJOR_VERSION == 1 && MATERIALX_MINOR_VERSION > 38) || \
+ (MATERIALX_MAJOR_VERSION == 1 && MATERIALX_MINOR_VERSION == 38 && MATERIALX_BUILD_VERSION > 4)
+ // MaterialX 1.38.5 changes the default transmission method to "refraction".
+ mxContext.getOptions().hwTransmissionRenderMethod = mx::TRANSMISSION_OPACITY;
+
+ // Emit transmission code
+ emitTransmissionRender(mxContext, mxStage);
+#endif
+
// Emit directional albedo table code.
if (mxContext.getOptions().hwDirectionalAlbedoMethod ==
mx::HwDirectionalAlbedoMethod::DIRECTIONAL_ALBEDO_TABLE ||
mxContext.getOptions().hwWriteAlbedoTable) {
- emitLibraryInclude("pbrlib/" + mx::GlslShaderGenerator::TARGET
- + "/lib/mx_table.glsl", mxContext, mxStage);
+ emitLibraryInclude("pbrlib/genglsl/lib/mx_table.glsl", mxContext, mxStage);
emitLineBreak(mxStage);
}
@@ -421,7 +427,7 @@ HdStMaterialXShaderGen::_EmitMxFunctions(
// Emit uv transform code globally if needed.
if (mxContext.getOptions().hwAmbientOcclusion) {
emitLibraryInclude(
- "stdlib/" + mx::GlslShaderGenerator::TARGET + "/lib/" +
+ "stdlib/genglsl/lib/" +
_tokenSubstitutions[ShaderGenerator::T_FILE_TRANSFORM_UV],
mxContext, mxStage);
}
@@ -490,10 +496,30 @@ HdStMaterialXShaderGen::_EmitMxSurfaceShader(
// closure/shader nodes and need to be emitted first.
emitFunctionCalls(mxGraph, mxContext, mxStage, mx::ShaderNode::Classification::TEXTURE);
+#if MATERIALX_MAJOR_VERSION == 1 && \
+ MATERIALX_MINOR_VERSION == 38 && \
+ MATERIALX_BUILD_VERSION <= 4
// Emit function calls for all surface shader nodes.
// These will internally emit their closure function calls.
emitFunctionCalls(mxGraph, mxContext, mxStage, mx::ShaderNode::Classification::SHADER |
mx::ShaderNode::Classification::SURFACE);
+#else
+ // Emit function calls for "root" closure/shader nodes.
+ // These will internally emit function calls for any dependent closure nodes upstream.
+ for (mx::ShaderGraphOutputSocket* socket : mxGraph.getOutputSockets())
+ {
+ if (socket->getConnection())
+ {
+ const mx::ShaderNode* upstream = socket->getConnection()->getNode();
+ if (upstream->getParent() == &mxGraph &&
+ (upstream->hasClassification(mx::ShaderNode::Classification::CLOSURE) ||
+ upstream->hasClassification(mx::ShaderNode::Classification::SHADER)))
+ {
+ emitFunctionCall(*upstream, mxContext, mxStage);
+ }
+ }
+ }
+#endif
}
else
{

View File

@ -108,7 +108,8 @@ set oiio_paths=%Staging%\%BuildDir%%ARCH%R\Release\openimageio\bin;%Staging%\%Bu
set boost_paths=%Staging%\%BuildDir%%ARCH%R\Release\boost\lib;%Staging%\%BuildDir%%ARCH%D\Debug\boost\lib
set openexr_paths=%Staging%\%BuildDir%%ARCH%R\Release\openexr\bin;%Staging%\%BuildDir%%ARCH%D\Debug\openexr\bin
set imath_paths=%Staging%\%BuildDir%%ARCH%R\Release\imath\bin;%Staging%\%BuildDir%%ARCH%D\Debug\imath\bin
set path=%BUILD_DIR%\downloads\mingw\mingw64\msys\1.0\bin\;%BUILD_DIR%\downloads\nasm-2.12.01\;%path%;%boost_paths%;%oiio_paths%;%openexr_paths%;%imath_paths%
set tbb_paths=%Staging%\%BuildDir%%ARCH%R\Release\tbb\bin;%Staging%\%BuildDir%%ARCH%D\Debug\tbb\bin
set path=%BUILD_DIR%\downloads\mingw\mingw64\msys\1.0\bin\;%BUILD_DIR%\downloads\nasm-2.12.01\;%path%;%boost_paths%;%oiio_paths%;%openexr_paths%;%imath_paths%;%tbb_paths%
mkdir %STAGING%\%BuildDir%%ARCH%R
cd %Staging%\%BuildDir%%ARCH%R
echo %DATE% %TIME% : Start > %StatusFile%

View File

@ -39,6 +39,11 @@ class PHYSICS_PT_geometry_nodes(Panel):
row.operator("object.simulation_nodes_cache_bake", text=bake_text).selected = True
row.operator("object.simulation_nodes_cache_delete", text="", icon='TRASH').selected = True
layout.use_property_split = True
layout.use_property_decorate = False
ob = context.object
layout.prop(ob, "use_simulation_cache", text="Cache")
classes = (
PHYSICS_PT_geometry_nodes,

View File

@ -31,7 +31,7 @@ extern "C" {
* version. Older Blender versions will test this and show a warning if the file
* was written with too new a version. */
#define BLENDER_FILE_MIN_VERSION 305
#define BLENDER_FILE_MIN_SUBVERSION 8
#define BLENDER_FILE_MIN_SUBVERSION 9
/** User readable version string. */
const char *BKE_blender_version_string(void);

View File

@ -308,6 +308,15 @@ void BKE_id_free_us(struct Main *bmain, void *idv) ATTR_NONNULL();
* Properly delete a single ID from given \a bmain database.
*/
void BKE_id_delete(struct Main *bmain, void *idv) ATTR_NONNULL();
/**
* Like BKE_id_delete, but with extra corner-case options.
*
* \param extra_remapping_flags Additional `ID_REMAP_` flags to pass to remapping code when
* ensuring that deleted IDs are not used by any other ID in given `bmain`. Typical example would
* be e.g. `ID_REMAP_FORCE_UI_POINTERS`, required when default UI-handling callbacks of remapping
* code won't be working (e.g. from readfile code). */
void BKE_id_delete_ex(struct Main *bmain, void *idv, const int extra_remapping_flags)
ATTR_NONNULL(1, 2);
/**
* Properly delete all IDs tagged with \a LIB_TAG_DOIT, in given \a bmain database.
*

View File

@ -269,7 +269,7 @@ bool BKE_library_id_can_use_idtype(struct ID *id_owner, short id_type_used);
/**
* Given the id_owner return the type of id_types it can use as a filter_id.
*/
uint64_t BKE_library_id_can_use_filter_id(const struct ID *id_owner);
uint64_t BKE_library_id_can_use_filter_id(const struct ID *id_owner, const bool include_ui);
/**
* Check whether given ID is used locally (i.e. by another non-linked ID).

View File

@ -181,6 +181,7 @@ class ModifierSimulationCache {
}
void reset();
void clear_prev_states();
};
} // namespace blender::bke::sim

View File

@ -199,7 +199,9 @@ void BKE_id_free_us(Main *bmain, void *idv) /* test users */
}
}
static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
static size_t id_delete(Main *bmain,
const bool do_tagged_deletion,
const int extra_remapping_flags)
{
const int tag = LIB_TAG_DOIT;
ListBase *lbarray[INDEX_ID_MAX];
@ -211,6 +213,8 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
const int free_flag = LIB_ID_FREE_NO_UI_USER |
(do_tagged_deletion ? LIB_ID_FREE_NO_MAIN | LIB_ID_FREE_NO_USER_REFCOUNT :
0);
const int remapping_flags = (ID_REMAP_FLAG_NEVER_NULL_USAGE | ID_REMAP_FORCE_NEVER_NULL_USAGE |
ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS | extra_remapping_flags);
ListBase tagged_deleted_ids = {NULL};
base_count = set_listbasepointers(bmain, lbarray);
@ -261,11 +265,7 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
* links, this can lead to nasty crashing here in second, actual deleting loop.
* Also, this will also flag users of deleted data that cannot be unlinked
* (object using deleted obdata, etc.), so that they also get deleted. */
BKE_libblock_remap_multiple_locked(bmain,
id_remapper,
ID_REMAP_FLAG_NEVER_NULL_USAGE |
ID_REMAP_FORCE_NEVER_NULL_USAGE |
ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS);
BKE_libblock_remap_multiple_locked(bmain, id_remapper, remapping_flags);
BKE_id_remapper_clear(id_remapper);
}
@ -329,11 +329,7 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
* links, this can lead to nasty crashing here in second, actual deleting loop.
* Also, this will also flag users of deleted data that cannot be unlinked
* (object using deleted obdata, etc.), so that they also get deleted. */
BKE_libblock_remap_multiple_locked(bmain,
remapper,
(ID_REMAP_FLAG_NEVER_NULL_USAGE |
ID_REMAP_FORCE_NEVER_NULL_USAGE |
ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS));
BKE_libblock_remap_multiple_locked(bmain, remapper, remapping_flags);
}
BKE_id_remapper_free(remapper);
}
@ -371,7 +367,7 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
return num_datablocks_deleted;
}
void BKE_id_delete(Main *bmain, void *idv)
void BKE_id_delete_ex(Main *bmain, void *idv, const int extra_remapping_flags)
{
BLI_assert_msg((((ID *)idv)->tag & LIB_TAG_NO_MAIN) == 0,
"Cannot be used with IDs outside of Main");
@ -379,12 +375,17 @@ void BKE_id_delete(Main *bmain, void *idv)
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
((ID *)idv)->tag |= LIB_TAG_DOIT;
id_delete(bmain, false);
id_delete(bmain, false, extra_remapping_flags);
}
void BKE_id_delete(Main *bmain, void *idv)
{
BKE_id_delete_ex(bmain, idv, 0);
}
size_t BKE_id_multi_tagged_delete(Main *bmain)
{
return id_delete(bmain, true);
return id_delete(bmain, true, 0);
}
/* -------------------------------------------------------------------- */

View File

@ -374,7 +374,7 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
}
}
uint64_t BKE_library_id_can_use_filter_id(const ID *id_owner)
uint64_t BKE_library_id_can_use_filter_id(const ID *id_owner, const bool include_ui)
{
/* any type of ID can be used in custom props. */
if (id_owner->properties) {
@ -387,6 +387,11 @@ uint64_t BKE_library_id_can_use_filter_id(const ID *id_owner)
return FILTER_ID_ALL;
}
/* Screen UI IDs can also link to virtually any ID (through e.g. the Outliner). */
if (include_ui && id_type_owner == ID_SCR) {
return FILTER_ID_ALL;
}
/* Casting to non const.
* TODO(jbakker): We should introduce a ntree_id_has_tree function as we are actually not
* interested in the result. */
@ -510,7 +515,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
}
const uint64_t filter_id_type_used = BKE_idtype_idcode_to_idfilter(id_type_used);
const uint64_t can_be_used = BKE_library_id_can_use_filter_id(id_owner);
const uint64_t can_be_used = BKE_library_id_can_use_filter_id(id_owner, false);
return (can_be_used & filter_id_type_used) != 0;
}

View File

@ -482,13 +482,14 @@ static void libblock_remap_data(Main *bmain,
const int remap_flags)
{
IDRemap id_remap_data = {0};
const int foreach_id_flags =
(((remap_flags & ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS) != 0 ?
IDWALK_DO_INTERNAL_RUNTIME_POINTERS :
IDWALK_NOP) |
((remap_flags & ID_REMAP_FORCE_UI_POINTERS) != 0 ? IDWALK_INCLUDE_UI : IDWALK_NOP) |
((remap_flags & ID_REMAP_NO_ORIG_POINTERS_ACCESS) != 0 ? IDWALK_NO_ORIG_POINTERS_ACCESS :
IDWALK_NOP));
const bool include_ui = (remap_flags & ID_REMAP_FORCE_UI_POINTERS) != 0;
const int foreach_id_flags = (((remap_flags & ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS) != 0 ?
IDWALK_DO_INTERNAL_RUNTIME_POINTERS :
IDWALK_NOP) |
(include_ui ? IDWALK_INCLUDE_UI : IDWALK_NOP) |
((remap_flags & ID_REMAP_NO_ORIG_POINTERS_ACCESS) != 0 ?
IDWALK_NO_ORIG_POINTERS_ACCESS :
IDWALK_NOP));
id_remap_data.id_remapper = id_remapper;
id_remap_data.type = remap_type;
@ -514,7 +515,7 @@ static void libblock_remap_data(Main *bmain,
ID *id_curr;
FOREACH_MAIN_ID_BEGIN (bmain, id_curr) {
const uint64_t can_use_filter_id = BKE_library_id_can_use_filter_id(id_curr);
const uint64_t can_use_filter_id = BKE_library_id_can_use_filter_id(id_curr, include_ui);
const bool has_mapping = BKE_id_remapper_has_mapping_for(id_remapper, can_use_filter_id);
/* Continue when id_remapper doesn't have any mappings that can be used by id_curr. */

View File

@ -1020,22 +1020,14 @@ int *BKE_mesh_poly_offsets_for_write(Mesh *mesh)
static void mesh_ensure_cdlayers_primary(Mesh &mesh)
{
if (!CustomData_get_layer_named(&mesh.vdata, CD_PROP_FLOAT3, "position")) {
CustomData_add_layer_named(
&mesh.vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, mesh.totvert, "position");
}
if (!CustomData_get_layer_named(&mesh.edata, CD_PROP_INT32_2D, ".edge_verts")) {
CustomData_add_layer_named(
&mesh.edata, CD_PROP_INT32_2D, CD_CONSTRUCT, mesh.totedge, ".edge_verts");
}
if (!CustomData_get_layer_named(&mesh.ldata, CD_PROP_INT32, ".corner_vert")) {
CustomData_add_layer_named(
&mesh.ldata, CD_PROP_INT32, CD_CONSTRUCT, mesh.totloop, ".corner_vert");
}
if (!CustomData_get_layer_named(&mesh.ldata, CD_PROP_INT32, ".corner_edge")) {
CustomData_add_layer_named(
&mesh.ldata, CD_PROP_INT32, CD_CONSTRUCT, mesh.totloop, ".corner_edge");
}
blender::bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
blender::bke::AttributeInitConstruct attribute_init;
/* Try to create attributes if they do not exist. */
attributes.add("position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, attribute_init);
attributes.add(".edge_verts", ATTR_DOMAIN_EDGE, CD_PROP_INT32_2D, attribute_init);
attributes.add(".corner_vert", ATTR_DOMAIN_CORNER, CD_PROP_INT32, attribute_init);
attributes.add(".corner_edge", ATTR_DOMAIN_CORNER, CD_PROP_INT32, attribute_init);
}
Mesh *BKE_mesh_new_nomain(const int verts_num,

View File

@ -2,9 +2,9 @@
#pragma once
#include "BLI_vector.hh"
#include "BLI_math_vector_types.hh"
#include "BLI_span.hh"
#include "BLI_vector.hh"
/** \file
* \ingroup bke

View File

@ -202,6 +202,15 @@ void ModifierSimulationState::ensure_bake_loaded() const
bake_loaded_ = true;
}
void ModifierSimulationCache::clear_prev_states()
{
std::lock_guard lock(states_at_frames_mutex_);
std::unique_ptr<ModifierSimulationStateAtFrame> temp = std::move(states_at_frames_.last());
states_at_frames_.clear_and_shrink();
bdata_sharing_.reset();
states_at_frames_.append(std::move(temp));
}
void ModifierSimulationCache::reset()
{
std::lock_guard lock(states_at_frames_mutex_);

View File

@ -290,7 +290,11 @@ static BLI_freenode *mempool_chunk_add(BLI_mempool *pool,
static void mempool_chunk_free(BLI_mempool_chunk *mpchunk, BLI_mempool *pool)
{
#ifdef WITH_ASAN
BLI_asan_unpoison(mpchunk, sizeof(BLI_mempool_chunk) + pool->esize * pool->csize);
#else
UNUSED_VARS(pool);
#endif
MEM_freeN(mpchunk);
}

View File

@ -26,21 +26,118 @@
# pragma GCC diagnostic error "-Wsign-conversion"
#endif
/* -------------------------------------------------------------------- */
/** \name UTF8 Character Decoding (Skip & Mask Lookup)
*
* Derived from GLIB `gutf8.c`.
*
* Ranges (zero based, inclusive):
*
* - 000..127: 1 byte.
* - 128..191: invalid.
* - 192..223: 2 bytes.
* - 224..239: 3 bytes.
* - 240..247: 4 bytes.
* - 248..251: 4 bytes.
* - 252..253: 4 bytes.
* - 254..255: invalid.
*
* Invalid values fall back to 1 byte or -1 (for an error value).
* \{ */
BLI_INLINE int utf8_char_compute_skip(const char c)
{
if (UNLIKELY(c >= 192)) {
if ((c & 0xe0) == 0xc0) {
return 2;
}
if ((c & 0xf0) == 0xe0) {
return 3;
}
if ((c & 0xf8) == 0xf0) {
return 4;
}
if ((c & 0xfc) == 0xf8) {
return 5;
}
if ((c & 0xfe) == 0xfc) {
return 6;
}
}
return 1;
}
BLI_INLINE int utf8_char_compute_skip_or_error(const char c)
{
if (c < 128) {
return 1;
}
if ((c & 0xe0) == 0xc0) {
return 2;
}
if ((c & 0xf0) == 0xe0) {
return 3;
}
if ((c & 0xf8) == 0xf0) {
return 4;
}
if ((c & 0xfc) == 0xf8) {
return 5;
}
if ((c & 0xfe) == 0xfc) {
return 6;
}
return -1;
}
BLI_INLINE int utf8_char_compute_skip_or_error_with_mask(const char c, char *r_mask)
{
/* Originally from GLIB `UTF8_COMPUTE` macro. */
if (c < 128) {
*r_mask = 0x7f;
return 1;
}
if ((c & 0xe0) == 0xc0) {
*r_mask = 0x1f;
return 2;
}
if ((c & 0xf0) == 0xe0) {
*r_mask = 0x0f;
return 3;
}
if ((c & 0xf8) == 0xf0) {
*r_mask = 0x07;
return 4;
}
if ((c & 0xfc) == 0xf8) {
*r_mask = 0x03;
return 5;
}
if ((c & 0xfe) == 0xfc) {
*r_mask = 0x01;
return 6;
}
return -1;
}
/**
* Array copied from GLIB's `gutf8.c`.
* \note last two values (0xfe and 0xff) are forbidden in UTF-8,
* so they are considered 1 byte length too.
* Decode a UTF8 code-point, use in combination with #utf8_char_compute_skip_or_error_with_mask.
*/
static const size_t utf8_skip_data[256] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1,
};
BLI_INLINE uint utf8_char_decode(const char *p, const char mask, const int len, const uint err)
{
/* Originally from GLIB `UTF8_GET` macro, added an 'err' argument. */
uint result = p[0] & mask;
for (int count = 1; count < len; count++) {
if ((p[count] & 0xc0) != 0x80) {
return err;
}
result <<= 6;
result |= p[count] & 0x3f;
}
return result;
}
/** \} */
ptrdiff_t BLI_str_utf8_invalid_byte(const char *str, size_t length)
{
@ -75,7 +172,7 @@ ptrdiff_t BLI_str_utf8_invalid_byte(const char *str, size_t length)
/* Note that since we always increase p (and decrease length) by one byte in main loop,
* we only add/subtract extra utf8 bytes in code below
* (ab number, aka number of bytes remaining in the utf8 sequence after the initial one). */
ab = (int)utf8_skip_data[c] - 1;
ab = utf8_char_compute_skip(c) - 1;
if (length <= ab) {
goto utf8_error;
}
@ -212,21 +309,24 @@ int BLI_str_utf8_invalid_strip(char *str, size_t length)
*/
BLI_INLINE char *str_utf8_copy_max_bytes_impl(char *dst, const char *src, size_t dst_maxncpy)
{
/* Cast to `uint8_t` is a no-op, quiets array subscript of type `char` warning. */
/* Cast to `uint8_t` is a no-op, quiets array subscript of type `char` warning.
* No need to check `src` points to a nil byte, this will break out of the switch statement. */
size_t utf8_size;
while (*src != '\0' && (utf8_size = utf8_skip_data[(uint8_t)*src]) < dst_maxncpy) {
while ((utf8_size = (size_t)utf8_char_compute_skip(*src)) < dst_maxncpy) {
dst_maxncpy -= utf8_size;
/* Prefer more compact block. */
/* NOLINTBEGIN: bugprone-assignment-in-if-condition */
/* clang-format off */
switch (utf8_size) {
case 6: *dst++ = *src++; ATTR_FALLTHROUGH;
case 5: *dst++ = *src++; ATTR_FALLTHROUGH;
case 4: *dst++ = *src++; ATTR_FALLTHROUGH;
case 3: *dst++ = *src++; ATTR_FALLTHROUGH;
case 2: *dst++ = *src++; ATTR_FALLTHROUGH;
case 1: *dst++ = *src++;
case 6: if (UNLIKELY(!(*dst = *src++))) { return dst; } dst++; ATTR_FALLTHROUGH;
case 5: if (UNLIKELY(!(*dst = *src++))) { return dst; } dst++; ATTR_FALLTHROUGH;
case 4: if (UNLIKELY(!(*dst = *src++))) { return dst; } dst++; ATTR_FALLTHROUGH;
case 3: if (UNLIKELY(!(*dst = *src++))) { return dst; } dst++; ATTR_FALLTHROUGH;
case 2: if (UNLIKELY(!(*dst = *src++))) { return dst; } dst++; ATTR_FALLTHROUGH;
case 1: if (UNLIKELY(!(*dst = *src++))) { return dst; } dst++;
}
/* clang-format on */
/* NOLINTEND: bugprone-assignment-in-if-condition */
}
*dst = '\0';
return dst;
@ -237,10 +337,8 @@ char *BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t
BLI_assert(dst_maxncpy != 0);
BLI_string_debug_size(dst, dst_maxncpy);
char *r_dst = dst;
str_utf8_copy_max_bytes_impl(dst, src, dst_maxncpy);
return r_dst;
return dst;
}
size_t BLI_strncpy_utf8_rlen(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy)
@ -615,115 +713,46 @@ char32_t BLI_str_utf32_char_to_lower(const char32_t wc)
/** \} */ /* -------------------------------------------------------------------- */
/* copied from glib's gutf8.c, added 'Err' arg */
/* NOTE(@ideasman42): glib uses uint for unicode, best we do the same,
* though we don't typedef it. */
#define UTF8_COMPUTE(Char, Mask, Len, Err) \
if (Char < 128) { \
Len = 1; \
Mask = 0x7f; \
} \
else if ((Char & 0xe0) == 0xc0) { \
Len = 2; \
Mask = 0x1f; \
} \
else if ((Char & 0xf0) == 0xe0) { \
Len = 3; \
Mask = 0x0f; \
} \
else if ((Char & 0xf8) == 0xf0) { \
Len = 4; \
Mask = 0x07; \
} \
else if ((Char & 0xfc) == 0xf8) { \
Len = 5; \
Mask = 0x03; \
} \
else if ((Char & 0xfe) == 0xfc) { \
Len = 6; \
Mask = 0x01; \
} \
else { \
Len = Err; /* -1 is the typical error value or 1 to skip */ \
} \
(void)0
/* same as glib define but added an 'Err' arg */
#define UTF8_GET(Result, Chars, Count, Mask, Len, Err) \
(Result) = (Chars)[0] & (Mask); \
for ((Count) = 1; (Count) < (Len); ++(Count)) { \
if (((Chars)[(Count)] & 0xc0) != 0x80) { \
(Result) = Err; \
break; \
} \
(Result) <<= 6; \
(Result) |= ((Chars)[(Count)] & 0x3f); \
} \
(void)0
int BLI_str_utf8_size(const char *p)
{
/* NOTE: uses glib functions but not from GLIB. */
int mask = 0, len;
const uchar c = (uchar)*p;
UTF8_COMPUTE(c, mask, len, -1);
(void)mask; /* quiet warning */
return len;
return utf8_char_compute_skip_or_error(*p);
}
int BLI_str_utf8_size_safe(const char *p)
{
int mask = 0, len;
const uchar c = (uchar)*p;
UTF8_COMPUTE(c, mask, len, 1);
(void)mask; /* quiet warning */
return len;
return utf8_char_compute_skip(*p);
}
uint BLI_str_utf8_as_unicode(const char *p)
{
/* Originally `g_utf8_get_char` in GLIB. */
int i, len;
uint mask = 0;
uint result;
const uchar c = (uchar)*p;
UTF8_COMPUTE(c, mask, len, -1);
char mask = 0;
const int len = utf8_char_compute_skip_or_error_with_mask(c, &mask);
if (UNLIKELY(len == -1)) {
return BLI_UTF8_ERR;
}
UTF8_GET(result, p, i, mask, len, BLI_UTF8_ERR);
return result;
return utf8_char_decode(p, mask, len, BLI_UTF8_ERR);
}
uint BLI_str_utf8_as_unicode_step_or_error(const char *__restrict p,
const size_t p_len,
size_t *__restrict index)
{
int i, len;
uint mask = 0;
uint result;
const uchar c = (uchar) * (p += *index);
BLI_assert(*index < p_len);
BLI_assert(c != '\0');
UTF8_COMPUTE(c, mask, len, -1);
char mask = 0;
const int len = utf8_char_compute_skip_or_error_with_mask(c, &mask);
if (UNLIKELY(len == -1) || (*index + (size_t)len > p_len)) {
return BLI_UTF8_ERR;
}
UTF8_GET(result, p, i, mask, len, BLI_UTF8_ERR);
const uint result = utf8_char_decode(p, mask, len, BLI_UTF8_ERR);
if (UNLIKELY(result == BLI_UTF8_ERR)) {
return BLI_UTF8_ERR;
}

View File

@ -19,6 +19,109 @@ using std::pair;
using std::string;
using std::vector;
/* -------------------------------------------------------------------- */
/** \name String Copy (UTF8)
* \{ */
TEST(string, StrCopyUTF8_ASCII)
{
#define STRNCPY_UTF8_ASCII(...) \
{ \
const char src[] = {__VA_ARGS__, 0}; \
char dst[sizeof(src)]; \
memset(dst, 0xff, sizeof(dst)); \
BLI_strncpy_utf8(dst, src, sizeof(dst)); \
EXPECT_EQ(strlen(dst), sizeof(dst) - 1); \
EXPECT_STREQ(dst, src); \
}
STRNCPY_UTF8_ASCII('a');
STRNCPY_UTF8_ASCII('a', 'b', 'c');
#undef STRNCPY_UTF8_ASCII
}
TEST(string, StrCopyUTF8_ASCII_Truncate)
{
#define STRNCPY_UTF8_ASCII_TRUNCATE(maxncpy, ...) \
{ \
char src[] = {__VA_ARGS__}; \
char dst[sizeof(src)]; \
memset(dst, 0xff, sizeof(dst)); \
BLI_strncpy_utf8(dst, src, maxncpy); \
int len_expect = MIN2(sizeof(src), maxncpy) - 1; \
src[len_expect] = '\0'; /* To be able to use `EXPECT_STREQ`. */ \
EXPECT_EQ(strlen(dst), len_expect); \
EXPECT_STREQ(dst, src); \
}
STRNCPY_UTF8_ASCII_TRUNCATE(1, '\0');
STRNCPY_UTF8_ASCII_TRUNCATE(3, 'A', 'A', 'A', 'A');
#undef STRNCPY_UTF8_ASCII_TRUNCATE
}
TEST(string, StrCopyUTF8_TruncateEncoding)
{
/* Ensure copying one byte less than the code-point results in it being ignored entirely. */
#define STRNCPY_UTF8_TRUNCATE(byte_size, ...) \
{ \
const char src[] = {__VA_ARGS__, 0}; \
EXPECT_EQ(BLI_str_utf8_size(src), byte_size); \
char dst[sizeof(src)]; \
memset(dst, 0xff, sizeof(dst)); \
BLI_strncpy_utf8(dst, src, sizeof(dst)); \
EXPECT_EQ(strlen(dst), sizeof(dst) - 1); \
EXPECT_STREQ(dst, src); \
BLI_strncpy_utf8(dst, src, sizeof(dst) - 1); \
EXPECT_STREQ(dst, ""); \
}
STRNCPY_UTF8_TRUNCATE(6, 252, 1, 1, 1, 1, 1);
STRNCPY_UTF8_TRUNCATE(5, 248, 1, 1, 1, 1);
STRNCPY_UTF8_TRUNCATE(4, 240, 1, 1, 1);
STRNCPY_UTF8_TRUNCATE(3, 224, 1, 1);
STRNCPY_UTF8_TRUNCATE(2, 192, 1);
STRNCPY_UTF8_TRUNCATE(1, 96);
#undef STRNCPY_UTF8_TRUNCATE
}
TEST(string, StrCopyUTF8_TerminateEncodingEarly)
{
/* A UTF8 sequence that has a null byte before the sequence ends.
* Ensure the the UTF8 sequence does not step over the null byte. */
#define STRNCPY_UTF8_TERMINATE_EARLY(byte_size, ...) \
{ \
char src[] = {__VA_ARGS__, 0}; \
EXPECT_EQ(BLI_str_utf8_size(src), byte_size); \
char dst[sizeof(src)]; \
memset(dst, 0xff, sizeof(dst)); \
BLI_strncpy_utf8(dst, src, sizeof(dst)); \
EXPECT_EQ(strlen(dst), sizeof(dst) - 1); \
EXPECT_STREQ(dst, src); \
for (int i = sizeof(dst) - 1; i > 1; i--) { \
src[i] = '\0'; \
memset(dst, 0xff, sizeof(dst)); \
const int dst_copied = BLI_strncpy_utf8_rlen(dst, src, sizeof(dst)); \
EXPECT_STREQ(dst, src); \
EXPECT_EQ(strlen(dst), i); \
EXPECT_EQ(dst_copied, i); \
} \
}
STRNCPY_UTF8_TERMINATE_EARLY(6, 252, 1, 1, 1, 1, 1);
STRNCPY_UTF8_TERMINATE_EARLY(5, 248, 1, 1, 1, 1);
STRNCPY_UTF8_TERMINATE_EARLY(4, 240, 1, 1, 1);
STRNCPY_UTF8_TERMINATE_EARLY(3, 224, 1, 1);
STRNCPY_UTF8_TERMINATE_EARLY(2, 192, 1);
STRNCPY_UTF8_TERMINATE_EARLY(1, 96);
#undef STRNCPY_UTF8_TERMINATE_EARLY
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name String Partition
* \{ */

View File

@ -24,6 +24,7 @@
#include "BKE_key.h"
#include "BKE_lib_id.h"
#include "BKE_lib_remap.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_report.h"
@ -196,7 +197,10 @@ bool BLO_main_validate_shapekeys(Main *bmain, ReportList *reports)
"Shapekey %s has an invalid 'from' pointer (%p), it will be deleted",
shapekey->id.name,
shapekey->from);
BKE_id_delete(bmain, shapekey);
/* NOTE: also need to remap UI data ID pointers here, since `bmain` is not the current
* `G_MAIN`, default UI-handling remapping callback (defined by call to
* `BKE_library_callback_remap_editor_id_reference_set`) won't work on exoected data here. */
BKE_id_delete_ex(bmain, shapekey, ID_REMAP_FORCE_UI_POINTERS);
}
return is_valid;

View File

@ -3472,7 +3472,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
ob->flag &= ~(OB_FLAG_UNUSED_11 | OB_FLAG_UNUSED_12);
ob->flag &= ~(OB_FLAG_USE_SIMULATION_CACHE | OB_FLAG_UNUSED_12);
ob->transflag &= ~(OB_TRANSFORM_ADJUST_ROOT_PARENT_FOR_VIEW_LOCK | OB_TRANSFLAG_UNUSED_1);
ob->shapeflag &= ~OB_SHAPE_FLAG_UNUSED_1;
}

View File

@ -1174,8 +1174,7 @@ void do_versions_after_linking_300(FileData * /*fd*/, Main *bmain)
SOCK_OBJECT,
SOCK_COLLECTION,
SOCK_TEXTURE,
SOCK_MATERIAL))
{
SOCK_MATERIAL)) {
link->tosock = link->tosock->next;
}
}
@ -2646,8 +2645,7 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 300, 17)) {
if (!DNA_struct_elem_find(
fd->filesdna, "View3DOverlay", "float", "normals_constant_screen_size"))
{
fd->filesdna, "View3DOverlay", "float", "normals_constant_screen_size")) {
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
@ -2675,8 +2673,7 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 300, 18)) {
if (!DNA_struct_elem_find(
fd->filesdna, "WorkSpace", "AssetLibraryReference", "asset_library_ref"))
{
fd->filesdna, "WorkSpace", "AssetLibraryReference", "asset_library_ref")) {
LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
BKE_asset_library_reference_init_default(&workspace->asset_library_ref);
}
@ -4351,6 +4348,13 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 306, 8)) {
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
ob->flag |= OB_FLAG_USE_SIMULATION_CACHE;
}
}
/**
* Versioning code until next subversion bump goes here.
*

View File

@ -132,6 +132,7 @@ set(GLSL_SRC
shaders/compositor_normalize.glsl
shaders/compositor_parallel_reduction.glsl
shaders/compositor_plane_deform.glsl
shaders/compositor_plane_deform_motion_blur.glsl
shaders/compositor_projector_lens_distortion.glsl
shaders/compositor_read_pass.glsl
shaders/compositor_realize_on_domain.glsl
@ -231,6 +232,7 @@ set(SRC_SHADER_CREATE_INFOS
shaders/infos/compositor_normalize_info.hh
shaders/infos/compositor_parallel_reduction_info.hh
shaders/infos/compositor_plane_deform_info.hh
shaders/infos/compositor_plane_deform_motion_blur_info.hh
shaders/infos/compositor_projector_lens_distortion_info.hh
shaders/infos/compositor_read_pass_info.hh
shaders/infos/compositor_realize_on_domain_info.hh

View File

@ -0,0 +1,31 @@
void main()
{
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
/* Add 0.5 to evaluate the sampler at the center of the pixel and divide by the size to get the
* coordinates into the sampler's expected [0, 1] range. We choose the maximum between both
* output sizes because one of the outputs might be a dummy 1x1 image. */
ivec2 output_size = max(imageSize(output_img), imageSize(mask_img));
vec2 coordinates = (vec2(texel) + vec2(0.5)) / vec2(output_size);
vec4 accumulated_color = vec4(0.0);
for (int i = 0; i < number_of_motion_blur_samples; i++) {
mat3 homography_matrix = mat3(homography_matrices[i]);
vec3 transformed_coordinates = homography_matrix * vec3(coordinates, 1.0);
vec2 projected_coordinates = transformed_coordinates.xy / transformed_coordinates.z;
/* The derivatives of the projected coordinates with respect to x and y are the first and
* second columns respectively, divided by the z projection factor as can be shown by
* differentiating the above matrix multiplication with respect to x and y. */
vec2 x_gradient = homography_matrix[0].xy / transformed_coordinates.z;
vec2 y_gradient = homography_matrix[1].xy / transformed_coordinates.z;
accumulated_color += textureGrad(input_tx, projected_coordinates, x_gradient, y_gradient);
}
accumulated_color /= number_of_motion_blur_samples;
imageStore(output_img, texel, accumulated_color);
imageStore(mask_img, texel, accumulated_color.aaaa);
}

View File

@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_create_info.hh"
GPU_SHADER_CREATE_INFO(compositor_plane_deform_motion_blur)
.local_group_size(16, 16)
.push_constant(Type::INT, "number_of_motion_blur_samples")
.uniform_buf(0, "mat4", "homography_matrices[64]")
.sampler(0, ImageType::FLOAT_2D, "input_tx")
.image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
.image(1, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "mask_img")
.compute_source("compositor_plane_deform_motion_blur.glsl")
.do_static_compilation(true);

View File

@ -137,6 +137,27 @@ static bNode *node_group_get_active(bContext *C, const char *node_idname)
return nullptr;
}
/* Maps old to new identifiers for simulation input node pairing. */
static void remap_pairing(bNodeTree &dst_tree,
Span<bNode *> nodes,
const Map<int32_t, int32_t> &identifier_map)
{
for (bNode *dst_node : nodes) {
if (dst_node->type == GEO_NODE_SIMULATION_INPUT) {
NodeGeometrySimulationInput *data = static_cast<NodeGeometrySimulationInput *>(
dst_node->storage);
if (data->output_node_id == 0) {
continue;
}
data->output_node_id = identifier_map.lookup_default(data->output_node_id, 0);
if (data->output_node_id == 0) {
blender::nodes::update_node_declaration_and_sockets(dst_tree, *dst_node);
}
}
}
}
/** \} */
/* -------------------------------------------------------------------- */
@ -232,7 +253,10 @@ static bool node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
bNodeTree *wgroup = ntreeCopyTree(bmain, ngroup);
/* Add the nodes into the `ntree`. */
Vector<bNode *> new_nodes;
Map<int32_t, int32_t> node_identifier_map;
LISTBASE_FOREACH_MUTABLE (bNode *, node, &wgroup->nodes) {
new_nodes.append(node);
/* Remove interface nodes.
* This also removes remaining links to and from interface nodes.
*/
@ -253,8 +277,10 @@ static bool node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
/* migrate node */
BLI_remlink(&wgroup->nodes, node);
BLI_addtail(&ntree->nodes, node);
const int32_t old_identifier = node->identifier;
nodeUniqueID(ntree, node);
nodeUniqueName(ntree, node);
node_identifier_map.add(old_identifier, node->identifier);
BKE_ntree_update_tag_node_new(ntree, node);
@ -310,6 +336,8 @@ static bool node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
}
}
remap_pairing(*ntree, new_nodes, node_identifier_map);
/* free the group tree (takes care of user count) */
BKE_id_free(bmain, wgroup);
@ -440,28 +468,6 @@ void NODE_OT_group_ungroup(wmOperatorType *ot)
/** \name Separate Operator
* \{ */
static void remap_pairing(bNodeTree &dst_tree, const Set<bNode *> &nodes)
{
for (bNode *dst_node : nodes) {
if (dst_node->type == GEO_NODE_SIMULATION_INPUT) {
NodeGeometrySimulationInput &data = *static_cast<NodeGeometrySimulationInput *>(
dst_node->storage);
/* XXX Technically this is not correct because the output_node_id is only valid
* in the original node group tree and we'd have map old IDs to new nodes first.
* The ungroup operator does not build a node map, it just expects node IDs to
* remain unchanged, which is probably true most of the time because they are
* mostly random numbers out of the uint32_t range. */
if (const bNode *output_node = dst_tree.node_by_id(data.output_node_id)) {
data.output_node_id = output_node->identifier;
}
else {
data.output_node_id = 0;
blender::nodes::update_node_declaration_and_sockets(dst_tree, *dst_node);
}
}
}
}
/**
* \return True if successful.
*/
@ -472,28 +478,31 @@ static bool node_group_separate_selected(
ListBase anim_basepaths = {nullptr, nullptr};
Map<bNode *, bNode *> node_map;
Map<const bNodeSocket *, bNodeSocket *> socket_map;
Map<int32_t, int32_t> node_identifier_map;
/* Add selected nodes into the ntree, ignoring interface nodes. */
VectorSet<bNode *> nodes_to_move = get_selected_nodes(ngroup);
nodes_to_move.remove_if(
[](const bNode *node) { return node->is_group_input() || node->is_group_output(); });
Set<bNode *> new_nodes;
for (bNode *node : nodes_to_move) {
bNode *newnode;
if (make_copy) {
newnode = bke::node_copy_with_mapping(&ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
new_nodes.add_new(newnode);
node_identifier_map.add(node->identifier, newnode->identifier);
}
else {
newnode = node;
BLI_remlink(&ngroup.nodes, newnode);
BLI_addtail(&ntree.nodes, newnode);
const int32_t old_identifier = node->identifier;
nodeUniqueID(&ntree, newnode);
nodeUniqueName(&ntree, newnode);
node_identifier_map.add(old_identifier, newnode->identifier);
}
node_map.add_new(node, newnode);
/* Keep track of this node's RNA "base" path (the part of the path identifying the node)
* if the old node-tree has animation data which potentially covers this node. */
@ -525,16 +534,16 @@ static bool node_group_separate_selected(
/* add internal links to the ntree */
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ngroup.links) {
const bool fromselect = (link->fromnode && (link->fromnode->flag & NODE_SELECT));
const bool toselect = (link->tonode && (link->tonode->flag & NODE_SELECT));
const bool fromselect = (link->fromnode && nodes_to_move.contains(link->fromnode));
const bool toselect = (link->tonode && nodes_to_move.contains(link->tonode));
if (make_copy) {
/* make a copy of internal links */
if (fromselect && toselect) {
nodeAddLink(&ntree,
ntree.node_by_id(link->fromnode->identifier),
node_map.lookup(link->fromnode),
socket_map.lookup(link->fromsock),
ntree.node_by_id(link->tonode->identifier),
node_map.lookup(link->tonode),
socket_map.lookup(link->tosock));
}
}
@ -550,7 +559,9 @@ static bool node_group_separate_selected(
}
}
for (bNode *node : new_nodes) {
remap_pairing(ntree, nodes_to_move, node_identifier_map);
for (bNode *node : node_map.values()) {
nodeDeclarationEnsure(&ntree, node);
}
@ -566,8 +577,6 @@ static bool node_group_separate_selected(
}
}
remap_pairing(ntree, new_nodes);
BKE_ntree_update_tag_all(&ntree);
if (!make_copy) {
BKE_ntree_update_tag_all(&ngroup);
@ -734,6 +743,36 @@ static bool node_group_make_test_selected(bNodeTree &ntree,
return false;
}
}
/* Check if simulation zone pairs are fully selected.
* Simulation input or output nodes can only be grouped together with the paired node.
*/
for (bNode *input_node : ntree.nodes_by_type("GeometryNodeSimulationInput")) {
const NodeGeometrySimulationInput &input_data =
*static_cast<const NodeGeometrySimulationInput *>(input_node->storage);
if (bNode *output_node = ntree.node_by_id(input_data.output_node_id)) {
const bool input_selected = nodes_to_group.contains(input_node);
const bool output_selected = nodes_to_group.contains(output_node);
if (input_selected && !output_selected) {
BKE_reportf(
&reports,
RPT_WARNING,
"Can not add simulation input node '%s' to a group without its paired output '%s'",
input_node->name,
output_node->name);
return false;
}
if (output_selected && !input_selected) {
BKE_reportf(
&reports,
RPT_WARNING,
"Can not add simulation output node '%s' to a group without its paired input '%s'",
output_node->name,
input_node->name);
return false;
}
}
}
return true;
}
@ -863,6 +902,8 @@ static void node_group_make_insert_selected(const bContext &C,
Vector<OutputLinkInfo> output_links;
Set<bNodeLink *> internal_links_to_move;
Set<bNodeLink *> links_to_remove;
/* Map old to new node identifiers. */
Map<int32_t, int32_t> node_identifier_map;
ntree.ensure_topology_cache();
for (bNode *node : nodes_to_move) {
@ -959,11 +1000,15 @@ static void node_group_make_insert_selected(const bContext &C,
/* Move nodes into the group. */
for (bNode *node : nodes_to_move) {
const int32_t old_identifier = node->identifier;
BLI_remlink(&ntree.nodes, node);
BLI_addtail(&group.nodes, node);
nodeUniqueID(&group, node);
nodeUniqueName(&group, node);
node_identifier_map.add(old_identifier, node->identifier);
BKE_ntree_update_tag_node_removed(&ntree);
BKE_ntree_update_tag_node_new(&group, node);
}
@ -1029,6 +1074,8 @@ static void node_group_make_insert_selected(const bContext &C,
}
}
remap_pairing(group, nodes_to_move, node_identifier_map);
if (group.type == NTREE_GEOMETRY) {
bke::node_field_inferencing::update_field_inferencing(group);
}

View File

@ -18,7 +18,7 @@
namespace blender::geometry {
bke::CurvesGeometry create_curve_from_vert_indices(
BLI_NOINLINE bke::CurvesGeometry create_curve_from_vert_indices(
const bke::AttributeAccessor &mesh_attributes,
const Span<int> vert_indices,
const Span<int> curve_offsets,
@ -80,27 +80,20 @@ struct CurveFromEdgesOutput {
IndexRange cyclic_curves;
};
static CurveFromEdgesOutput edges_to_curve_point_indices(const int verts_num,
const Span<int2> edges)
BLI_NOINLINE static CurveFromEdgesOutput edges_to_curve_point_indices(const int verts_num,
const Span<int2> edges)
{
Vector<int> vert_indices;
vert_indices.reserve(edges.size());
Vector<int> curve_offsets;
/* Compute the number of edges connecting to each vertex. */
Array<int> neighbor_count(verts_num, 0);
for (const int2 &edge : edges) {
neighbor_count[edge[0]]++;
neighbor_count[edge[1]]++;
}
/* Compute an offset into the array of neighbor edges based on the counts. */
Array<int> neighbor_offsets(verts_num);
int start = 0;
for (const int i : IndexRange(verts_num)) {
neighbor_offsets[i] = start;
start += neighbor_count[i];
Array<int> neighbor_offsets_data(verts_num + 1, 0);
for (const int vert : edges.cast<int>()) {
neighbor_offsets_data[vert]++;
}
offset_indices::accumulate_counts_to_offsets(neighbor_offsets_data);
const OffsetIndices<int> neighbor_offsets(neighbor_offsets_data);
/* Use as an index into the "neighbor group" for each vertex. */
Array<int> used_slots(verts_num, 0);
@ -109,8 +102,8 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(const int verts_num,
for (const int i : edges.index_range()) {
const int v1 = edges[i][0];
const int v2 = edges[i][1];
neighbors[neighbor_offsets[v1] + used_slots[v1]] = v2;
neighbors[neighbor_offsets[v2] + used_slots[v2]] = v1;
neighbors[neighbor_offsets[v1].start() + used_slots[v1]] = v2;
neighbors[neighbor_offsets[v2].start() + used_slots[v2]] = v1;
used_slots[v1]++;
used_slots[v2]++;
}
@ -120,7 +113,7 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(const int verts_num,
for (const int start_vert : IndexRange(verts_num)) {
/* The vertex will be part of a cyclic curve. */
if (neighbor_count[start_vert] == 2) {
if (neighbor_offsets[start_vert].size() == 2) {
continue;
}
@ -129,9 +122,9 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(const int verts_num,
continue;
}
for (const int i : IndexRange(neighbor_count[start_vert])) {
for (const int neighbor : neighbors.as_span().slice(neighbor_offsets[start_vert])) {
int current_vert = start_vert;
int next_vert = neighbors[neighbor_offsets[current_vert] + i];
int next_vert = neighbor;
if (unused_edges[next_vert] == 0) {
continue;
@ -150,11 +143,11 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(const int verts_num,
unused_edges[current_vert]--;
unused_edges[last_vert]--;
if (neighbor_count[current_vert] != 2) {
if (neighbor_offsets[current_vert].size() != 2) {
break;
}
const int offset = neighbor_offsets[current_vert];
const int offset = neighbor_offsets[current_vert].start();
const int next_a = neighbors[offset];
const int next_b = neighbors[offset + 1];
next_vert = (last_vert == next_a) ? next_b : next_a;
@ -172,7 +165,7 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(const int verts_num,
}
int current_vert = start_vert;
int next_vert = neighbors[neighbor_offsets[current_vert]];
int next_vert = neighbors[neighbor_offsets[current_vert].start()];
curve_offsets.append(vert_indices.size());
vert_indices.append(current_vert);
@ -186,7 +179,7 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(const int verts_num,
unused_edges[current_vert]--;
unused_edges[last_vert]--;
const int offset = neighbor_offsets[current_vert];
const int offset = neighbor_offsets[current_vert].start();
const int next_a = neighbors[offset];
const int next_b = neighbors[offset + 1];
next_vert = (last_vert == next_a) ? next_b : next_a;
@ -198,7 +191,7 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(const int verts_num,
return {std::move(vert_indices), std::move(curve_offsets), cyclic_curves};
}
static bke::CurvesGeometry edges_to_curves_convert(
BLI_NOINLINE static bke::CurvesGeometry edges_to_curves_convert(
const Mesh &mesh,
const Span<int2> edges,
const bke::AnonymousAttributePropagationInfo &propagation_info)

View File

@ -89,6 +89,24 @@ static float dist_signed_squared_to_edge(float2 probe, float2 uva, float2 uvb)
return numerator_ssq / edge_length_squared;
}
/**
* \return the larger dimension of `extent`, factoring in the target aspect ratio.
*/
static float get_aspect_scaled_extent(const rctf &extent, const UVPackIsland_Params &params)
{
const float width = BLI_rctf_size_x(&extent);
const float height = BLI_rctf_size_y(&extent);
return std::max(width / params.target_aspect_y, height);
}
/**
* \return true iff `b` is a preferred layout over `a`, given the packing parameters supplied.
*/
static bool is_larger(const rctf &a, const rctf &b, const UVPackIsland_Params &params)
{
return get_aspect_scaled_extent(b, params) < get_aspect_scaled_extent(a, params);
}
PackIsland::PackIsland()
{
/* Initialize to the identity transform. */
@ -345,12 +363,11 @@ static void pack_islands_alpaca_turbo(const int64_t start_index,
const Span<UVAABBIsland *> islands,
const float target_aspect_y,
MutableSpan<uv_phi> r_phis,
float *r_max_u,
float *r_max_v)
rctf *r_extent)
{
/* Exclude an initial AABB near the origin. */
float next_u1 = *r_max_u;
float next_v1 = *r_max_v;
float next_u1 = r_extent->xmax;
float next_v1 = r_extent->ymax;
bool zigzag = next_u1 < next_v1 * target_aspect_y; /* Horizontal or Vertical strip? */
float u0 = zigzag ? next_u1 : 0.0f;
@ -395,9 +412,8 @@ static void pack_islands_alpaca_turbo(const int64_t start_index,
}
}
/* Write back total pack AABB. */
*r_max_u = next_u1;
*r_max_v = next_v1;
/* Write back extent. */
*r_extent = {0.0f, next_u1, 0.0f, next_v1};
}
/**
@ -457,12 +473,11 @@ static void pack_islands_alpaca_rotate(const int64_t start_index,
const Span<UVAABBIsland *> islands,
const float target_aspect_y,
MutableSpan<uv_phi> r_phis,
float *r_max_u,
float *r_max_v)
rctf *r_extent)
{
/* Exclude an initial AABB near the origin. */
float next_u1 = *r_max_u;
float next_v1 = *r_max_v;
float next_u1 = r_extent->xmax;
float next_v1 = r_extent->ymax;
bool zigzag = next_u1 / target_aspect_y < next_v1; /* Horizontal or Vertical strip? */
/* Track an AABB "hole" which may be filled at any time. */
@ -553,8 +568,25 @@ static void pack_islands_alpaca_rotate(const int64_t start_index,
}
/* Write back total pack AABB. */
*r_max_u = next_u1;
*r_max_v = next_v1;
*r_extent = {0.0f, next_u1, 0.0f, next_v1};
}
/**
* Use a fast algorithm to pack the supplied `aabbs`.
*/
static void pack_islands_fast(const int64_t start_index,
const Span<UVAABBIsland *> aabbs,
const bool rotate,
const float target_aspect_y,
MutableSpan<uv_phi> r_phis,
rctf *r_extent)
{
if (rotate) {
pack_islands_alpaca_rotate(start_index, aabbs, target_aspect_y, r_phis, r_extent);
}
else {
pack_islands_alpaca_turbo(start_index, aabbs, target_aspect_y, r_phis, r_extent);
}
}
/** Frits Göbel, 1979. */
@ -594,24 +626,11 @@ static void pack_gobel(const Span<UVAABBIsland *> aabbs,
}
}
/* Attempt to find an "Optimal" packing of the islands, e.g. assuming squares or circles. */
static void pack_island_optimal_pack(const Span<UVAABBIsland *> aabbs,
const UVPackIsland_Params &params,
const bool all_can_rotate,
MutableSpan<uv_phi> r_phis,
float *r_max_u,
float *r_max_v)
static void pack_islands_optimal_pack(const Span<UVAABBIsland *> aabbs,
const UVPackIsland_Params &params,
MutableSpan<uv_phi> r_phis,
rctf *r_extent)
{
*r_max_u = 0.0f;
*r_max_v = 0.0f;
if (!all_can_rotate) {
/* Alpaca will produce an optimal layout when the inputs are uniform squares. */
pack_islands_alpaca_turbo(0, aabbs, params.target_aspect_y, r_phis, r_max_u, r_max_v);
return;
}
/* For many rectangle-only inputs, alpaca_rotate can produce an optimal layout. */
pack_islands_alpaca_rotate(0, aabbs, params.target_aspect_y, r_phis, r_max_u, r_max_v);
if (params.shape_method == ED_UVPACK_SHAPE_AABB) {
return;
}
@ -647,10 +666,10 @@ static void pack_island_optimal_pack(const Span<UVAABBIsland *> aabbs,
int n = a * a + a + 3 + floorf((a - 1) * sqrtf(2.0f));
if (island_count_patch == n) {
float max_uv_gobel = large_uv * (a + 1 + sqrtf(0.5f));
if (max_uv_gobel < std::max(*r_max_u, *r_max_v)) {
rctf extent = {0.0f, max_uv_gobel, 0.0f, max_uv_gobel};
if (is_larger(*r_extent, extent, params)) {
*r_extent = extent;
pack_gobel(aabbs, large_uv, a, r_phis);
*r_max_u = max_uv_gobel;
*r_max_v = max_uv_gobel;
}
return;
}
@ -659,10 +678,9 @@ static void pack_island_optimal_pack(const Span<UVAABBIsland *> aabbs,
/* Wrapper around #BLI_box_pack_2d. */
static void pack_island_box_pack_2d(const Span<UVAABBIsland *> aabbs,
const float target_aspect_y,
const UVPackIsland_Params &params,
MutableSpan<uv_phi> r_phis,
float *r_max_u,
float *r_max_v)
rctf *r_extent)
{
/* Allocate storage. */
BoxPack *box_array = static_cast<BoxPack *>(
@ -671,7 +689,7 @@ static void pack_island_box_pack_2d(const Span<UVAABBIsland *> aabbs,
/* Prepare for box_pack_2d. */
for (const int64_t i : aabbs.index_range()) {
BoxPack *box = box_array + i;
box->w = aabbs[i]->uv_diagonal.x / target_aspect_y;
box->w = aabbs[i]->uv_diagonal.x / params.target_aspect_y;
box->h = aabbs[i]->uv_diagonal.y;
}
@ -680,19 +698,17 @@ static void pack_island_box_pack_2d(const Span<UVAABBIsland *> aabbs,
float box_max_u = 0.0f;
float box_max_v = 0.0f;
BLI_box_pack_2d(box_array, int(aabbs.size()), sort_boxes, &box_max_u, &box_max_v);
box_max_u *= target_aspect_y;
box_max_u *= params.target_aspect_y;
rctf extent = {0.0f, box_max_u, 0.0f, box_max_v};
if (std::max(box_max_u / target_aspect_y, box_max_v) <
std::max(*r_max_u / target_aspect_y, *r_max_v))
{
*r_max_u = box_max_u;
*r_max_v = box_max_v;
if (is_larger(*r_extent, extent, params)) {
*r_extent = extent;
/* Write back box_pack UVs. */
for (const int64_t i : aabbs.index_range()) {
BoxPack *box = box_array + i;
uv_phi &phi = *(uv_phi *)&r_phis[aabbs[i]->index];
phi.rotation = 0.0f; /* #BLI_box_pack_2d never rotates. */
phi.translation.x = (box->x + box->w * 0.5f) * target_aspect_y;
phi.translation.x = (box->x + box->w * 0.5f) * params.target_aspect_y;
phi.translation.y = (box->y + box->h * 0.5f);
}
}
@ -1020,8 +1036,7 @@ class UVMinimumEnclosingSquareFinder {
bounds.ymin -= margin_;
bounds.xmax += margin_;
bounds.ymax += margin_;
const float current_quad = std::max(BLI_rctf_size_x(&bounds) / params_->target_aspect_y,
BLI_rctf_size_y(&bounds));
const float current_quad = get_aspect_scaled_extent(bounds, *params_);
if (best_quad > current_quad) {
best_quad = current_quad;
best_angle = angle;
@ -1067,8 +1082,7 @@ static bool rotate_inside_square(const Span<UVAABBIsland *> island_indices,
const float scale,
const float margin,
MutableSpan<uv_phi> r_phis,
float *r_max_u,
float *r_max_v)
rctf *r_extent)
{
if (island_indices.size() == 0) {
return false; /* Nothing to do. */
@ -1088,7 +1102,7 @@ static bool rotate_inside_square(const Span<UVAABBIsland *> island_indices,
}
UVMinimumEnclosingSquareFinder square_finder(scale, margin, &params);
square_finder.best_quad = std::max(*r_max_u / params.target_aspect_y, *r_max_v) * 0.999f;
square_finder.best_quad = get_aspect_scaled_extent(*r_extent, params) * 0.999f;
float matrix[2][2];
@ -1137,9 +1151,9 @@ static bool rotate_inside_square(const Span<UVAABBIsland *> island_indices,
r_phis[i].translation.x -= square_finder.best_bounds.xmin;
r_phis[i].translation.y -= square_finder.best_bounds.ymin;
}
*r_max_u = BLI_rctf_size_x(&square_finder.best_bounds);
*r_max_v = BLI_rctf_size_y(&square_finder.best_bounds);
return true; /* `r_phis` were modified. */
r_extent->xmax = BLI_rctf_size_x(&square_finder.best_bounds);
r_extent->ymax = BLI_rctf_size_y(&square_finder.best_bounds);
return true; /* `r_phis` and `r_extent` were modified. */
}
/**
@ -1157,18 +1171,17 @@ static bool rotate_inside_square(const Span<UVAABBIsland *> island_indices,
* Performance would normally be `O(n^4)`, however the occupancy
* bitmap_radix is fixed, which gives a reduced time complexity of `O(n^3)`.
*/
static void pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
const Span<PackIsland *> islands,
const float scale,
const float margin,
const UVPackIsland_Params &params,
MutableSpan<uv_phi> r_phis,
float *r_max_u,
float *r_max_v)
static int64_t pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
const Span<PackIsland *> islands,
const float scale,
const float margin,
const UVPackIsland_Params &params,
MutableSpan<uv_phi> r_phis,
rctf *r_extent)
{
blender::Array<uv_phi> phis(r_phis.size());
Occupancy occupancy(guess_initial_scale(islands, scale, margin));
float max_u = 0.0f;
float max_v = 0.0f;
rctf extent = {0.0f, 0.0f, 0.0f, 0.0f};
/* A heuristic to improve final layout efficiency by making an
* intermediate call to #rotate_inside_square. */
@ -1192,7 +1205,7 @@ static void pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
const int64_t island_index = island_indices[traced_islands]->index;
PackIsland *island = islands[island_index];
const float island_scale = island->can_scale_(params) ? scale : 1.0f;
occupancy.trace_island(island, r_phis[island_index], island_scale, margin, true);
occupancy.trace_island(island, phis[island_index], island_scale, margin, true);
traced_islands++;
}
@ -1201,7 +1214,7 @@ static void pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
uv_phi phi;
phi.translation = island->pivot_;
phi.rotation = 0.0f;
r_phis[island_indices[i]->index] = phi;
phis[island_indices[i]->index] = phi;
i++;
placed_can_rotate = false;
continue;
@ -1262,30 +1275,31 @@ static void pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
}
/* Place island. */
r_phis[island_indices[i]->index] = phi;
phis[island_indices[i]->index] = phi;
i++; /* Next island. */
if (i == square_milestone && placed_can_rotate) {
if (rotate_inside_square(island_indices.take_front(i),
islands,
params,
scale,
margin,
r_phis,
&max_u,
&max_v))
if (rotate_inside_square(
island_indices.take_front(i), islands, params, scale, margin, phis, &extent))
{
scan_line = 0;
traced_islands = 0;
occupancy.clear();
continue;
}
}
/* Update top-right corner. */
float2 top_right = island->get_diagonal_support(island_scale, phi.rotation, margin) +
phi.translation;
max_u = std::max(top_right.x, max_u);
max_v = std::max(top_right.y, max_v);
extent.xmax = std::max(top_right.x, extent.xmax);
extent.ymax = std::max(top_right.y, extent.ymax);
if (!is_larger(*r_extent, extent, params)) {
if (i >= square_milestone) {
return 0; /* Early exit, we already have a better layout. */
}
}
/* Heuristics to reduce size of brute-force search. */
if (i < 128 || (i & 31) == 16) {
@ -1296,8 +1310,15 @@ static void pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
}
}
*r_max_u = max_u;
*r_max_v = max_v;
if (!is_larger(*r_extent, extent, params)) {
return 0;
}
*r_extent = extent;
for (const int64_t i : phis.index_range()) {
const int64_t island_index = island_indices[i]->index;
r_phis[island_index] = phis[island_index];
}
return phis.size();
}
/**
@ -1415,20 +1436,27 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
}
const int64_t max_box_pack = std::min(alpaca_cutoff, islands.size());
float optimal_pack_u = 0.0f;
float optimal_pack_v = 0.0f;
rctf extent = {0.0f, 1e30f, 0.0f, 1e30f};
if (all_can_translate) {
pack_island_optimal_pack(aabbs.as_span().take_front(max_box_pack),
params,
all_can_rotate,
r_phis,
&optimal_pack_u,
&optimal_pack_v);
pack_islands_fast(0,
aabbs.as_span().take_front(max_box_pack),
all_can_rotate,
params.target_aspect_y,
r_phis,
&extent);
}
if (all_can_translate) {
pack_islands_optimal_pack(aabbs.as_span().take_front(max_box_pack), params, r_phis, &extent);
}
/* Call box_pack_2d (slow for large N.) */
if (all_can_translate) {
pack_island_box_pack_2d(aabbs.as_span().take_front(max_box_pack), params, r_phis, &extent);
}
/* Call xatlas (slow for large N.) */
float max_u = 1e30f;
float max_v = 1e30f;
switch (params.shape_method) {
case ED_UVPACK_SHAPE_CONVEX:
case ED_UVPACK_SHAPE_CONCAVE:
@ -1438,53 +1466,23 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
margin,
params,
r_phis,
&max_u,
&max_v);
&extent);
break;
default:
break;
}
/* Call box_pack_2d (slow for large N.) */
if (all_can_translate) {
pack_island_box_pack_2d(
aabbs.as_span().take_front(max_box_pack), params.target_aspect_y, r_phis, &max_u, &max_v);
if (std::max(optimal_pack_u / params.target_aspect_y, optimal_pack_v) <
std::max(max_u / params.target_aspect_y, max_v))
{
pack_island_optimal_pack(aabbs.as_span().take_front(max_box_pack),
params,
all_can_rotate,
r_phis,
&max_u,
&max_v);
}
}
/* At this stage, `max_u` and `max_v` contain the box_pack/xatlas UVs. */
if (all_can_rotate) {
rotate_inside_square(aabbs.as_span().take_front(max_box_pack),
islands,
params,
scale,
margin,
r_phis,
&max_u,
&max_v);
rotate_inside_square(
aabbs.as_span().take_front(max_box_pack), islands, params, scale, margin, r_phis, &extent);
}
/* Call Alpaca. */
if (all_can_rotate) {
pack_islands_alpaca_rotate(
max_box_pack, aabbs, params.target_aspect_y, r_phis, &max_u, &max_v);
}
else {
pack_islands_alpaca_turbo(max_box_pack, aabbs, params.target_aspect_y, r_phis, &max_u, &max_v);
}
/* Call fast packer for remaining islands. */
pack_islands_fast(max_box_pack, aabbs, all_can_rotate, params.target_aspect_y, r_phis, &extent);
return std::max(max_u / params.target_aspect_y, max_v);
return get_aspect_scaled_extent(extent, params);
}
/** Find the optimal scale to pack islands into the unit square.

View File

@ -841,9 +841,11 @@ if(WITH_GTESTS)
tests/gpu_testing.cc
tests/framebuffer_test.cc
tests/immediate_test.cc
tests/index_buffer_test.cc
tests/push_constants_test.cc
tests/shader_test.cc
tests/state_blend_test.cc
tests/storage_buffer_test.cc
tests/texture_test.cc

View File

@ -0,0 +1,126 @@
/* SPDX-License-Identifier: Apache-2.0 */
#include "testing/testing.h"
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
#include "GPU_shader_builtin.h"
#include "gpu_testing.hh"
#include "BLI_math_vector.hh"
namespace blender::gpu::tests {
static constexpr int Size = 256;
static void test_immediate_one_plane()
{
GPUOffScreen *offscreen = GPU_offscreen_create(Size,
Size,
false,
GPU_RGBA16F,
GPU_TEXTURE_USAGE_ATTACHMENT |
GPU_TEXTURE_USAGE_HOST_READ,
nullptr);
BLI_assert(offscreen != nullptr);
GPU_offscreen_bind(offscreen, false);
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
float4 color(1.0, 0.5, 0.25, 1.0);
immUniformColor4fv(color);
immBegin(GPU_PRIM_TRI_STRIP, 4);
immVertex3f(pos, -1.0f, 1.0f, 0.0f);
immVertex3f(pos, 1.0f, 1.0f, 0.0f);
immVertex3f(pos, -1.0f, -1.0f, 0.0f);
immVertex3f(pos, 1.0f, -1.0f, 0.0f);
immEnd();
GPU_offscreen_unbind(offscreen, false);
GPU_flush();
/* Read back data and perform some basic tests. */
float read_data[4 * Size * Size];
GPU_offscreen_read_color(offscreen, GPU_DATA_FLOAT, &read_data);
for (int pixel_index = 0; pixel_index < Size * Size; pixel_index++) {
float4 read_color = float4(&read_data[pixel_index * 4]);
EXPECT_EQ(read_color, color);
}
GPU_offscreen_free(offscreen);
}
GPU_TEST(immediate_one_plane)
/**
* Draws two planes with two different colors.
* - Tests that both planes are stored in the same buffer (depends on backend).
* - Test that data of the first plane isn't overwritten by the second plane.
* (push constants, buffer, bind points etc.)
*/
static void test_immediate_two_planes()
{
GPUOffScreen *offscreen = GPU_offscreen_create(Size,
Size,
false,
GPU_RGBA16F,
GPU_TEXTURE_USAGE_ATTACHMENT |
GPU_TEXTURE_USAGE_HOST_READ,
nullptr);
BLI_assert(offscreen != nullptr);
GPU_offscreen_bind(offscreen, false);
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
float4 color(1.0, 0.5, 0.25, 1.0);
immUniformColor4fv(color);
immBegin(GPU_PRIM_TRI_STRIP, 4);
immVertex3f(pos, -1.0f, 1.0f, 0.0f);
immVertex3f(pos, 0.0f, 1.0f, 0.0f);
immVertex3f(pos, -1.0f, -1.0f, 0.0f);
immVertex3f(pos, 0.0f, -1.0f, 0.0f);
immEnd();
float4 color2(0.25, 0.5, 1.0, 1.0);
immUniformColor4fv(color2);
immBegin(GPU_PRIM_TRI_STRIP, 4);
immVertex3f(pos, 0.0f, 1.0f, 0.0f);
immVertex3f(pos, 1.0f, 1.0f, 0.0f);
immVertex3f(pos, 0.0f, -1.0f, 0.0f);
immVertex3f(pos, 1.0f, -1.0f, 0.0f);
immEnd();
GPU_offscreen_unbind(offscreen, false);
GPU_flush();
/* Read back data and perform some basic tests.
* Not performing detailed tests as there might be driver specific limitations. */
float read_data[4 * Size * Size];
GPU_offscreen_read_color(offscreen, GPU_DATA_FLOAT, &read_data);
int64_t color_num = 0;
int64_t color2_num = 0;
for (int pixel_index = 0; pixel_index < Size * Size; pixel_index++) {
float4 read_color = float4(&read_data[pixel_index * 4]);
if (read_color == color) {
color_num++;
}
else if (read_color == color2) {
color2_num++;
}
else {
EXPECT_TRUE(read_color == color || read_color == color2);
}
}
EXPECT_TRUE(color_num > 0);
EXPECT_TRUE(color2_num > 0);
GPU_offscreen_free(offscreen);
}
GPU_TEST(immediate_two_planes)
} // namespace blender::gpu::tests

View File

@ -0,0 +1,132 @@
/* SPDX-License-Identifier: Apache-2.0 */
#include "testing/testing.h"
#include "gpu_testing.hh"
#include "GPU_batch.h"
#include "GPU_batch_presets.h"
#include "GPU_framebuffer.h"
#include "GPU_matrix.h"
#include "BLI_math_vector.hh"
#include "intern/draw_cache.h"
namespace blender::gpu::tests {
template<eGPUBlend blend_type>
void blend_test(float4 source_a, float4 source_b, float4 expected_result)
{
GPUOffScreen *offscreen = GPU_offscreen_create(1,
1,
false,
GPU_RGBA16F,
GPU_TEXTURE_USAGE_ATTACHMENT |
GPU_TEXTURE_USAGE_HOST_READ,
nullptr);
BLI_assert(offscreen != nullptr);
GPU_offscreen_bind(offscreen, false);
GPUTexture *color_texture = GPU_offscreen_color_texture(offscreen);
GPU_texture_clear(color_texture, GPU_DATA_FLOAT, source_a);
GPUBatch *batch = DRW_cache_quad_get();
GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR);
GPU_batch_uniform_4fv(batch, "color", source_b);
GPU_blend(blend_type);
GPU_batch_draw(batch);
GPU_offscreen_unbind(offscreen, false);
GPU_flush();
float4 read_back;
GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH);
GPU_offscreen_read_color(offscreen, GPU_DATA_FLOAT, &read_back);
EXPECT_EQ(read_back, expected_result);
GPU_offscreen_free(offscreen);
DRW_shape_cache_free();
}
static void test_blend_none()
{
blend_test<GPU_BLEND_NONE>(float4(1.0f, 0.0f, 1.0f, 1.0f),
float4(0.0f, 1.0f, 0.0f, 0.5f),
float4(0.0f, 1.0f, 0.0f, 0.5f));
}
GPU_TEST(blend_none)
static void test_blend_alpha()
{
blend_test<GPU_BLEND_ALPHA>(float4(1.0f, 0.0f, 1.0f, 1.0f),
float4(0.0f, 1.0f, 0.0f, 0.5f),
float4(0.5f, 0.5f, 0.5f, 1.0f));
}
GPU_TEST(blend_alpha)
static void test_blend_alpha_premult()
{
blend_test<GPU_BLEND_ALPHA_PREMULT>(float4(1.0f, 0.0f, 1.0f, 1.0f),
float4(0.0f, 1.0f, 0.0f, 0.5f),
float4(0.5f, 1.0f, 0.5f, 1.0f));
}
GPU_TEST(blend_alpha_premult)
static void test_blend_additive()
{
blend_test<GPU_BLEND_ADDITIVE>(float4(1.0f, 0.0f, 1.0f, 1.0f),
float4(0.0f, 1.0f, 0.0f, 0.5f),
float4(1.0f, 0.5f, 1.0f, 1.0f));
}
GPU_TEST(blend_additive)
static void test_blend_additive_premult()
{
blend_test<GPU_BLEND_ADDITIVE_PREMULT>(float4(1.0f, 0.0f, 1.0f, 1.0f),
float4(0.0f, 1.0f, 0.0f, 0.5f),
float4(1.0f, 1.0f, 1.0f, 1.5f));
}
GPU_TEST(blend_additive_premult)
static void test_blend_multiply()
{
blend_test<GPU_BLEND_MULTIPLY>(float4(1.0f, 0.0f, 1.0f, 1.0f),
float4(0.0f, 1.0f, 0.0f, 0.5f),
float4(0.0f, 0.0f, 0.0f, 0.5f));
}
GPU_TEST(blend_multiply)
static void test_blend_subtract()
{
blend_test<GPU_BLEND_SUBTRACT>(float4(1.0f, 1.0f, 1.0f, 1.0f),
float4(0.0f, 1.0f, 0.0f, 0.5f),
float4(1.0f, 0.0f, 1.0f, 0.5f));
}
GPU_TEST(blend_subtract)
static void test_blend_invert()
{
blend_test<GPU_BLEND_INVERT>(float4(1.0f, 1.0f, 1.0f, 1.0f),
float4(0.0f, 1.0f, 0.0f, 0.5f),
float4(0.0f, 0.0f, 0.0f, 1.0f));
}
GPU_TEST(blend_invert)
static void test_blend_oit()
{
blend_test<GPU_BLEND_OIT>(float4(1.0f, 1.0f, 1.0f, 1.0f),
float4(0.0f, 1.0f, 0.0f, 0.5f),
float4(1.0f, 2.0f, 1.0f, 0.5f));
}
GPU_TEST(blend_oit)
static void test_blend_background()
{
blend_test<GPU_BLEND_BACKGROUND>(float4(1.0f, 1.0f, 1.0f, 1.0f),
float4(0.0f, 1.0f, 0.0f, 0.5f),
float4(0.5f, 0.5f, 0.5f, 0.5f));
}
GPU_TEST(blend_background)
} // namespace blender::gpu::tests

View File

@ -45,9 +45,11 @@ void VKIndexBuffer::bind_as_ssbo(uint binding)
VKContext &context = *VKContext::get();
VKShader *shader = static_cast<VKShader *>(context.shader);
const VKShaderInterface &shader_interface = shader->interface_get();
const VKDescriptorSet::Location location = shader_interface.descriptor_set_location(
shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, binding);
shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, location);
const std::optional<VKDescriptorSet::Location> location =
shader_interface.descriptor_set_location(
shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, binding);
BLI_assert_msg(location, "Locations to SSBOs should always exist.");
shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, *location);
}
void VKIndexBuffer::read(uint32_t *data) const

View File

@ -196,11 +196,13 @@ const VKDescriptorSet::Location VKShaderInterface::descriptor_set_location(
return descriptor_set_location(shader_input);
}
const VKDescriptorSet::Location VKShaderInterface::descriptor_set_location(
const std::optional<VKDescriptorSet::Location> VKShaderInterface::descriptor_set_location(
const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const
{
const ShaderInput *shader_input = shader_input_get(bind_type, binding);
BLI_assert(shader_input);
if (shader_input == nullptr) {
return std::nullopt;
}
return descriptor_set_location(shader_input);
}

View File

@ -38,7 +38,7 @@ class VKShaderInterface : public ShaderInterface {
const VKDescriptorSet::Location descriptor_set_location(
const shader::ShaderCreateInfo::Resource &resource) const;
const VKDescriptorSet::Location descriptor_set_location(
const std::optional<VKDescriptorSet::Location> descriptor_set_location(
const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const;
/** Get the Layout of the shader. */

View File

@ -37,9 +37,11 @@ void VKStorageBuffer::bind(int slot)
}
VKShader *shader = static_cast<VKShader *>(context.shader);
const VKShaderInterface &shader_interface = shader->interface_get();
const VKDescriptorSet::Location location = shader_interface.descriptor_set_location(
shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, slot);
shader->pipeline_get().descriptor_set_get().bind(*this, location);
const std::optional<VKDescriptorSet::Location> location =
shader_interface.descriptor_set_location(
shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, slot);
BLI_assert_msg(location, "Locations to SSBOs should always exist.");
shader->pipeline_get().descriptor_set_get().bind(*this, *location);
}
void VKStorageBuffer::unbind() {}

View File

@ -319,9 +319,13 @@ void VKTexture::image_bind(int binding)
VKContext &context = *VKContext::get();
VKShader *shader = static_cast<VKShader *>(context.shader);
const VKShaderInterface &shader_interface = shader->interface_get();
const VKDescriptorSet::Location location = shader_interface.descriptor_set_location(
shader::ShaderCreateInfo::Resource::BindType::IMAGE, binding);
shader->pipeline_get().descriptor_set_get().image_bind(*this, location);
const std::optional<VKDescriptorSet::Location> location =
shader_interface.descriptor_set_location(shader::ShaderCreateInfo::Resource::BindType::IMAGE,
binding);
if (location) {
VKDescriptorSetTracker &descriptor_set = shader->pipeline_get().descriptor_set_get();
descriptor_set.image_bind(*this, *location);
}
}
/* -------------------------------------------------------------------- */

View File

@ -44,10 +44,12 @@ void VKUniformBuffer::bind(int slot, shader::ShaderCreateInfo::Resource::BindTyp
VKContext &context = *VKContext::get();
VKShader *shader = static_cast<VKShader *>(context.shader);
const VKShaderInterface &shader_interface = shader->interface_get();
const VKDescriptorSet::Location location = shader_interface.descriptor_set_location(bind_type,
slot);
VKDescriptorSetTracker &descriptor_set = shader->pipeline_get().descriptor_set_get();
descriptor_set.bind(*this, location);
const std::optional<VKDescriptorSet::Location> location =
shader_interface.descriptor_set_location(bind_type, slot);
if (location) {
VKDescriptorSetTracker &descriptor_set = shader->pipeline_get().descriptor_set_get();
descriptor_set.bind(*this, *location);
}
}
void VKUniformBuffer::bind(int slot)

View File

@ -27,9 +27,11 @@ void VKVertexBuffer::bind_as_ssbo(uint binding)
VKContext &context = *VKContext::get();
VKShader *shader = static_cast<VKShader *>(context.shader);
const VKShaderInterface &shader_interface = shader->interface_get();
const VKDescriptorSet::Location location = shader_interface.descriptor_set_location(
shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, binding);
shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, location);
const std::optional<VKDescriptorSet::Location> location =
shader_interface.descriptor_set_location(
shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, binding);
BLI_assert_msg(location, "Locations to SSBOs should always exist.");
shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, *location);
}
void VKVertexBuffer::bind_as_texture(uint /*binding*/) {}

View File

@ -37,6 +37,7 @@
.drotAngle = 0, \
.quat = _DNA_DEFAULT_UNIT_QT, \
.dquat = _DNA_DEFAULT_UNIT_QT, \
.flag = OB_FLAG_USE_SIMULATION_CACHE, \
.protectflag = OB_LOCK_ROT4D, \
\
.dt = OB_TEXTURE, \

View File

@ -720,8 +720,8 @@ enum {
#define OB_FROMDUPLI (1 << 9)
#define OB_DONE (1 << 10) /* unknown state, clear before use */
#define OB_FLAG_USE_SIMULATION_CACHE (1 << 11)
#ifdef DNA_DEPRECATED_ALLOW
# define OB_FLAG_UNUSED_11 (1 << 11) /* cleared */
# define OB_FLAG_UNUSED_12 (1 << 12) /* cleared */
#endif

View File

@ -3679,6 +3679,12 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "RigidBodyConstraint");
RNA_def_property_ui_text(prop, "Rigid Body Constraint", "Constraint constraining rigid bodies");
prop = RNA_def_property(srna, "use_simulation_cache", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", OB_FLAG_USE_SIMULATION_CACHE);
RNA_def_property_ui_text(
prop, "Use Simulation Cache", "Cache all frames during simulation nodes playback");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
rna_def_object_visibility(srna);
/* instancing */

View File

@ -1351,6 +1351,14 @@ static GeometrySet compute_geometry(const bNodeTree &btree,
nmd_orig->runtime_eval_log = eval_log.release();
}
if (DEG_is_active(ctx->depsgraph)) {
/* When caching is turned off, remove all states except the last which was just created in this
* evaluation. Check if active status to avoid changing original data in other depsgraphs. */
if (!(ctx->object->flag & OB_FLAG_USE_SIMULATION_CACHE)) {
nmd_orig->simulation_cache->clear_prev_states();
}
}
return output_geometry_set;
}

View File

@ -5,13 +5,19 @@
* \ingroup cmpnodes
*/
#include "BLI_array.hh"
#include "BLI_math_matrix_types.hh"
#include "BLI_math_vector_types.hh"
#include "BLT_translation.h"
#include "DNA_defaults.h"
#include "DNA_movieclip_types.h"
#include "DNA_tracking_types.h"
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
#include "RNA_access.h"
@ -20,15 +26,22 @@
#include "UI_interface.h"
#include "UI_resources.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
#include "GPU_uniform_buffer.h"
#include "COM_node_operation.hh"
#include "COM_utilities.hh"
#include "node_composite_util.hh"
namespace blender::nodes::node_composite_planetrackdeform_cc {
NODE_STORAGE_FUNCS(NodePlaneTrackDeformData)
static void cmp_node_planetrackdeform_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>(N_("Image"));
b.add_input<decl::Color>(N_("Image")).compositor_skip_realization();
b.add_output<decl::Color>(N_("Image"));
b.add_output<decl::Float>(N_("Plane"));
}
@ -116,9 +129,144 @@ class PlaneTrackDeformOperation : public NodeOperation {
void execute() override
{
get_input("Image").pass_through(get_result("Image"));
get_result("Plane").allocate_invalid();
context().set_info_message("Viewport compositor setup not fully supported");
MovieTrackingPlaneTrack *plane_track = get_plane_track();
Result &input_image = get_input("Image");
Result &output_image = get_result("Image");
Result &output_mask = get_result("Plane");
if (input_image.is_single_value() || !plane_track) {
if (output_image.should_compute()) {
input_image.pass_through(output_image);
}
if (output_mask.should_compute()) {
output_mask.allocate_single_value();
output_mask.set_float_value(1.0f);
}
return;
}
const Array<float4x4> homography_matrices = compute_homography_matrices(plane_track);
GPUShader *shader = shader_manager().get("compositor_plane_deform_motion_blur");
GPU_shader_bind(shader);
GPU_shader_uniform_1i(shader, "number_of_motion_blur_samples", homography_matrices.size());
GPUUniformBuf *matrices_buffer = GPU_uniformbuf_create_ex(
homography_matrices.size() * sizeof(float4x4),
homography_matrices.data(),
"Plane Track Deform Homography Matrices");
const int ubo_location = GPU_shader_get_ubo_binding(shader, "homography_matrices");
GPU_uniformbuf_bind(matrices_buffer, ubo_location);
GPU_texture_mipmap_mode(input_image.texture(), true, true);
GPU_texture_anisotropic_filter(input_image.texture(), true);
GPU_texture_extend_mode(input_image.texture(), GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
input_image.bind_as_texture(shader, "input_tx");
const Domain domain = compute_domain();
output_image.allocate_texture(domain);
output_image.bind_as_image(shader, "output_img");
output_mask.allocate_texture(domain);
output_mask.bind_as_image(shader, "mask_img");
compute_dispatch_threads_at_least(shader, domain.size);
input_image.unbind_as_texture();
output_image.unbind_as_image();
output_mask.unbind_as_image();
GPU_shader_unbind();
GPU_uniformbuf_unbind(matrices_buffer);
GPU_uniformbuf_free(matrices_buffer);
}
Domain compute_domain() override
{
MovieTrackingPlaneTrack *plane_track = get_plane_track();
Result &input_image = get_input("Image");
if (input_image.is_single_value() || !plane_track) {
return input_image.domain();
}
return Domain(get_movie_clip_size());
}
Array<float4x4> compute_homography_matrices(MovieTrackingPlaneTrack *plane_track)
{
/* We evaluate at the frames in the range [frame - shutter, frame + shutter], if no motion blur
* is enabled or the motion blur samples is set to 1, we just evaluate at the current frame. */
const int samples = use_motion_blur() ? node_storage(bnode()).motion_blur_samples : 1;
const float shutter = samples != 1 ? node_storage(bnode()).motion_blur_shutter : 0.0f;
const float start_frame = context().get_frame_number() - shutter;
const float frame_step = (shutter * 2.0f) / samples;
Array<float4x4> matrices(samples);
for (int i = 0; i < samples; i++) {
const float frame = start_frame + frame_step * i;
const float clip_frame = BKE_movieclip_remap_scene_to_clip_frame(get_movie_clip(), frame);
float corners[4][2];
BKE_tracking_plane_marker_get_subframe_corners(plane_track, clip_frame, corners);
/* Compute a 2D projection matrix that projects from the corners of the image in normalized
* coordinates into the corners of the tracking plane. */
float3x3 homography_matrix;
float identity_corners[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}};
BKE_tracking_homography_between_two_quads(
corners, identity_corners, homography_matrix.ptr());
/* Store in a 4x4 matrix due to the alignment requirements of GPU uniform buffers. */
matrices[i] = float4x4(homography_matrix);
}
return matrices;
}
MovieTrackingPlaneTrack *get_plane_track()
{
MovieClip *movie_clip = get_movie_clip();
if (!movie_clip) {
return nullptr;
}
MovieTrackingObject *tracking_object = BKE_tracking_object_get_named(
&movie_clip->tracking, node_storage(bnode()).tracking_object);
if (!tracking_object) {
return nullptr;
}
return BKE_tracking_object_find_plane_track_with_name(tracking_object,
node_storage(bnode()).plane_track_name);
}
int2 get_movie_clip_size()
{
MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
BKE_movieclip_user_set_frame(&user, context().get_frame_number());
int2 size;
BKE_movieclip_get_size(get_movie_clip(), &user, &size.x, &size.y);
return size;
}
bool use_motion_blur()
{
return get_flags() & CMP_NODE_PLANE_TRACK_DEFORM_FLAG_MOTION_BLUR;
}
CMPNodePlaneTrackDeformFlags get_flags()
{
return static_cast<CMPNodePlaneTrackDeformFlags>(node_storage(bnode()).flag);
}
MovieClip *get_movie_clip()
{
return reinterpret_cast<MovieClip *>(bnode().id);
}
};
@ -142,8 +290,6 @@ void register_node_type_cmp_planetrackdeform()
node_type_storage(
&ntype, "NodePlaneTrackDeformData", node_free_standard_storage, node_copy_standard_storage);
ntype.get_compositor_operation = file_ns::get_compositor_operation;
ntype.realtime_compositor_unsupported_message = N_(
"Node not supported in the Viewport compositor");
nodeRegisterType(&ntype);
}

View File

@ -115,10 +115,8 @@ static void expand_mesh(Mesh &mesh,
const int vert_expand,
const int edge_expand,
const int poly_expand,
const int loop_expand,
const AnonymousAttributePropagationInfo &propagation_info)
const int loop_expand)
{
remove_non_propagated_attributes(mesh.attributes_for_write(), propagation_info);
/* Remove types that aren't supported for interpolation in this node. */
if (vert_expand != 0) {
CustomData_free_layers(&mesh.vdata, CD_ORCO, mesh.totvert);
@ -202,7 +200,9 @@ static MutableSpan<int> get_orig_index_layer(Mesh &mesh, const eAttrDomain domai
* result point.
*/
template<typename T, typename GetMixIndicesFn>
void copy_with_mixing(MutableSpan<T> dst, Span<T> src, GetMixIndicesFn get_mix_indices_fn)
void copy_with_mixing(const Span<T> src,
const GetMixIndicesFn &get_mix_indices_fn,
MutableSpan<T> dst)
{
threading::parallel_for(dst.index_range(), 512, [&](const IndexRange range) {
bke::attribute_math::DefaultPropagationMixer<T> mixer{dst.slice(range)};
@ -215,6 +215,15 @@ void copy_with_mixing(MutableSpan<T> dst, Span<T> src, GetMixIndicesFn get_mix_i
});
}
template<typename GetMixIndicesFn>
void copy_with_mixing(const GSpan src, const GetMixIndicesFn &get_mix_indices_fn, GMutableSpan dst)
{
bke::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
copy_with_mixing(src.typed<T>(), get_mix_indices_fn, dst.typed<T>());
});
}
static Array<Vector<int>> create_vert_to_edge_map(const int vert_size,
const Span<int2> edges,
const int vert_offset = 0)
@ -246,61 +255,67 @@ static void extrude_mesh_vertices(Mesh &mesh,
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
/* This allows parallelizing attribute mixing for new edges. */
Array<Vector<int>> vert_to_edge_map = create_vert_to_edge_map(orig_vert_size, mesh.edges());
remove_non_propagated_attributes(mesh.attributes_for_write(), propagation_info);
expand_mesh(mesh, selection.size(), selection.size(), 0, 0, propagation_info);
Set<AttributeIDRef> point_ids;
Set<AttributeIDRef> edge_ids;
mesh.attributes().for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
if (meta_data.data_type == CD_PROP_STRING) {
return true;
}
if (meta_data.domain == ATTR_DOMAIN_POINT) {
if (id.name() != "position") {
point_ids.add(id);
}
}
else if (meta_data.domain == ATTR_DOMAIN_EDGE) {
if (id.name() != ".edge_verts") {
edge_ids.add(id);
}
}
return true;
});
/* This allows parallelizing attribute mixing for new edges. */
Array<Vector<int>> vert_to_edge_map;
if (!edge_ids.is_empty()) {
vert_to_edge_map = create_vert_to_edge_map(orig_vert_size, mesh.edges());
}
expand_mesh(mesh, selection.size(), selection.size(), 0, 0);
const IndexRange new_vert_range{orig_vert_size, selection.size()};
const IndexRange new_edge_range{orig_edge_size, selection.size()};
MutableSpan<float3> new_positions = mesh.vert_positions_for_write().slice(new_vert_range);
MutableSpan<int2> new_edges = mesh.edges_for_write().slice(new_edge_range);
for (const int i_selection : selection.index_range()) {
new_edges[i_selection] = int2(selection[i_selection], new_vert_range[i_selection]);
}
MutableAttributeAccessor attributes = mesh.attributes_for_write();
attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
if (!ELEM(meta_data.domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE)) {
return true;
}
if (ELEM(id.name(), ".corner_vert", ".corner_edge", ".edge_verts")) {
return true;
}
if (meta_data.data_type == CD_PROP_STRING) {
return true;
}
GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
switch (attribute.domain) {
case ATTR_DOMAIN_POINT:
/* New vertices copy the attribute values from their source vertex. */
array_utils::gather(attribute.span, selection, attribute.span.slice(new_vert_range));
break;
case ATTR_DOMAIN_EDGE:
bke::attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
using T = decltype(dummy);
MutableSpan<T> data = attribute.span.typed<T>();
/* New edge values are mixed from of all the edges connected to the source vertex. */
copy_with_mixing(data.slice(new_edge_range), data.as_span(), [&](const int i) {
return vert_to_edge_map[selection[i]].as_span();
});
});
break;
default:
BLI_assert_unreachable();
}
/* New vertices copy the attribute values from their source vertex. */
for (const AttributeIDRef &id : point_ids) {
GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
array_utils::gather(attribute.span, selection, attribute.span.slice(new_vert_range));
attribute.finish();
return true;
});
}
/* New edge values are mixed from of all the edges connected to the source vertex. */
for (const AttributeIDRef &id : edge_ids) {
GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
copy_with_mixing(
attribute.span,
[&](const int i) { return vert_to_edge_map[selection[i]].as_span(); },
attribute.span.slice(new_edge_range));
attribute.finish();
}
MutableSpan<float3> positions = mesh.vert_positions_for_write();
MutableSpan<float3> new_positions = positions.slice(new_vert_range);
threading::parallel_for(selection.index_range(), 1024, [&](const IndexRange range) {
for (const int i : range) {
new_positions[i] += offsets[selection[i]];
new_positions[i] = positions[selection[i]] + offsets[selection[i]];
}
});
@ -436,12 +451,12 @@ static void extrude_mesh_edges(Mesh &mesh,
/* Every new polygon is a quad with four corners. */
const IndexRange new_loop_range{orig_loop_size, new_poly_range.size() * 4};
remove_non_propagated_attributes(mesh.attributes_for_write(), propagation_info);
expand_mesh(mesh,
new_vert_range.size(),
connect_edge_range.size() + duplicate_edge_range.size(),
new_poly_range.size(),
new_loop_range.size(),
propagation_info);
new_loop_range.size());
MutableSpan<int2> edges = mesh.edges_for_write();
MutableSpan<int2> connect_edges = edges.slice(connect_edge_range);
@ -518,8 +533,7 @@ static void extrude_mesh_edges(Mesh &mesh,
if (ELEM(id.name(), ".corner_vert", ".corner_edge", ".edge_verts")) {
return true;
}
GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
bke::attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
using T = decltype(dummy);
@ -537,18 +551,19 @@ static void extrude_mesh_edges(Mesh &mesh,
array_utils::gather(data.as_span(), edge_selection, duplicate_data);
/* Edges connected to original vertices mix values of selected connected edges. */
MutableSpan<T> connect_data = data.slice(connect_edge_range);
copy_with_mixing(connect_data, duplicate_data.as_span(), [&](const int i_new_vert) {
return new_vert_to_duplicate_edge_map[i_new_vert].as_span();
});
copy_with_mixing(
duplicate_data.as_span(),
[&](const int i) { return new_vert_to_duplicate_edge_map[i].as_span(); },
data.slice(connect_edge_range));
break;
}
case ATTR_DOMAIN_FACE: {
/* Attribute values for new faces are a mix of the values of faces connected to the its
* original edge. */
copy_with_mixing(data.slice(new_poly_range), data.as_span(), [&](const int i) {
return edge_to_poly_map[edge_selection[i]].as_span();
});
copy_with_mixing(
data.as_span(),
[&](const int i) { return edge_to_poly_map[edge_selection[i]].as_span(); },
data.slice(new_poly_range));
break;
}
@ -800,12 +815,12 @@ static void extrude_mesh_face_regions(Mesh &mesh,
/* The loops that form the new side faces. */
const IndexRange side_loop_range{orig_corner_verts.size(), side_poly_range.size() * 4};
remove_non_propagated_attributes(mesh.attributes_for_write(), propagation_info);
expand_mesh(mesh,
new_vert_range.size(),
connect_edge_range.size() + boundary_edge_range.size() + new_inner_edge_range.size(),
side_poly_range.size(),
side_loop_range.size(),
propagation_info);
side_loop_range.size());
MutableSpan<int2> edges = mesh.edges_for_write();
MutableSpan<int2> connect_edges = edges.slice(connect_edge_range);
@ -918,8 +933,7 @@ static void extrude_mesh_face_regions(Mesh &mesh,
if (ELEM(id.name(), ".corner_vert", ".corner_edge", ".edge_verts")) {
return true;
}
GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
bke::attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
using T = decltype(dummy);
@ -941,10 +955,10 @@ static void extrude_mesh_face_regions(Mesh &mesh,
array_utils::gather(data.as_span(), new_inner_edge_indices.as_span(), new_inner_data);
/* Edges connected to original vertices mix values of selected connected edges. */
MutableSpan<T> connect_data = data.slice(connect_edge_range);
copy_with_mixing(connect_data, boundary_data.as_span(), [&](const int i) {
return new_vert_to_duplicate_edge_map[i].as_span();
});
copy_with_mixing(
boundary_data.as_span(),
[&](const int i) { return new_vert_to_duplicate_edge_map[i].as_span(); },
data.slice(connect_edge_range));
break;
}
case ATTR_DOMAIN_FACE: {
@ -1132,12 +1146,12 @@ static void extrude_individual_mesh_faces(
const IndexRange side_poly_range{orig_polys.size(), duplicate_edge_range.size()};
const IndexRange side_loop_range{orig_loop_size, side_poly_range.size() * 4};
remove_non_propagated_attributes(mesh.attributes_for_write(), propagation_info);
expand_mesh(mesh,
new_vert_range.size(),
connect_edge_range.size() + duplicate_edge_range.size(),
side_poly_range.size(),
side_loop_range.size(),
propagation_info);
side_loop_range.size());
MutableSpan<float3> new_positions = mesh.vert_positions_for_write().slice(new_vert_range);
MutableSpan<int2> edges = mesh.edges_for_write();
@ -1218,8 +1232,7 @@ static void extrude_individual_mesh_faces(
if (ELEM(id.name(), ".corner_vert", ".corner_edge", ".edge_verts")) {
return true;
}
GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
bke::attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
using T = decltype(dummy);

View File

@ -1205,9 +1205,20 @@ elseif(WIN32)
endif()
# Filenames change slightly between FFMPEG versions check both 5.0 and fallback to 4.4
# Filenames change slightly between FFMPEG versions check both 6.0 and fallback to 5.0
# to ease the transition between versions.
if(EXISTS "${LIBDIR}/ffmpeg/lib/avcodec-59.dll")
if(EXISTS "${LIBDIR}/ffmpeg/lib/avcodec-60.dll")
windows_install_shared_manifest(
FILES
${LIBDIR}/ffmpeg/lib/avcodec-60.dll
${LIBDIR}/ffmpeg/lib/avformat-60.dll
${LIBDIR}/ffmpeg/lib/avdevice-60.dll
${LIBDIR}/ffmpeg/lib/avutil-58.dll
${LIBDIR}/ffmpeg/lib/swscale-7.dll
${LIBDIR}/ffmpeg/lib/swresample-4.dll
ALL
)
else()
windows_install_shared_manifest(
FILES
${LIBDIR}/ffmpeg/lib/avcodec-59.dll
@ -1218,17 +1229,6 @@ elseif(WIN32)
${LIBDIR}/ffmpeg/lib/swresample-4.dll
ALL
)
else()
windows_install_shared_manifest(
FILES
${LIBDIR}/ffmpeg/lib/avcodec-58.dll
${LIBDIR}/ffmpeg/lib/avformat-58.dll
${LIBDIR}/ffmpeg/lib/avdevice-58.dll
${LIBDIR}/ffmpeg/lib/avutil-56.dll
${LIBDIR}/ffmpeg/lib/swscale-5.dll
${LIBDIR}/ffmpeg/lib/swresample-3.dll
ALL
)
endif()
windows_install_shared_manifest(
FILES