diff options
author | Joseph Eagar <joeedh@gmail.com> | 2022-10-23 02:33:47 +0300 |
---|---|---|
committer | Joseph Eagar <joeedh@gmail.com> | 2022-10-23 02:33:47 +0300 |
commit | fe7088c99ff084f7218ab20136d49eb1a1dccd0b (patch) | |
tree | 3b3df4270110bbffa4a738e379dce5319fec9653 | |
parent | b5a69061e7d464914662ae0dd6fed46a999a56bb (diff) | |
parent | b70bbfadfecec049ad1ac2de7a949198ca6c15bc (diff) |
Merge remote-tracking branch 'origin' into temp-sculpt-brush-channel
240 files changed, 4971 insertions, 2498 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 408cf819ce8..f2f34ca3dd2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -336,11 +336,9 @@ if(APPLE) else() set(WITH_COREAUDIO OFF) endif() -if(NOT WIN32) +if(UNIX AND NOT APPLE) option(WITH_JACK "Enable JACK Support (http://www.jackaudio.org)" ON) - if(UNIX AND NOT APPLE) - option(WITH_JACK_DYNLOAD "Enable runtime dynamic JACK libraries loading" OFF) - endif() + option(WITH_JACK_DYNLOAD "Enable runtime dynamic JACK libraries loading" OFF) else() set(WITH_JACK OFF) endif() @@ -489,13 +487,12 @@ endif() if(NOT APPLE) option(WITH_CYCLES_DEVICE_ONEAPI "Enable Cycles oneAPI compute support" OFF) option(WITH_CYCLES_ONEAPI_BINARIES "Enable Ahead-Of-Time compilation for Cycles oneAPI device" OFF) - option(WITH_CYCLES_ONEAPI_SYCL_HOST_ENABLED "Enable use of SYCL host (CPU) device execution by oneAPI implementation. This option is for debugging purposes and impacts GPU execution." OFF) # https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compilation/ahead-of-time-compilation.html + # acm-g10 is the architecture for the first Arc Alchemist GPUs but we'll keep using dg2 until IGC dependency is updated to support acm-g10. set(CYCLES_ONEAPI_SPIR64_GEN_DEVICES "dg2" CACHE STRING "oneAPI Intel GPU architectures to build binaries for") set(CYCLES_ONEAPI_SYCL_TARGETS spir64 spir64_gen CACHE STRING "oneAPI targets to build AOT binaries for") - mark_as_advanced(WITH_CYCLES_ONEAPI_SYCL_HOST_ENABLED) mark_as_advanced(CYCLES_ONEAPI_SPIR64_GEN_DEVICES) mark_as_advanced(CYCLES_ONEAPI_SYCL_TARGETS) endif() @@ -780,6 +777,8 @@ endif() # ----------------------------------------------------------------------------- # Check for Conflicting/Unsupported Configurations +option(WITH_STRICT_BUILD_OPTIONS "When requirements for a build option are not met, error instead of disabling the option" OFF) + if(NOT WITH_BLENDER AND NOT WITH_CYCLES_STANDALONE AND NOT WITH_CYCLES_HYDRA_RENDER_DELEGATE) message(FATAL_ERROR "At least one of WITH_BLENDER or WITH_CYCLES_STANDALONE " @@ -895,10 +894,7 @@ endif() if(WITH_BUILDINFO) find_package(Git) - if(NOT GIT_FOUND) - message(WARNING "Git was not found, disabling WITH_BUILDINFO") - set(WITH_BUILDINFO OFF) - endif() + set_and_warn_library_found("Git" GIT_FOUND WITH_BUILDINFO) endif() if(WITH_AUDASPACE) @@ -938,9 +934,10 @@ if(WITH_INTERNATIONAL) WARNING "Translation path '${CMAKE_SOURCE_DIR}/release/datafiles/locale' is missing, " "This is a 'git submodule', which are known not to work with bridges to other version " - "control systems, disabling 'WITH_INTERNATIONAL'." + "control systems." ) - set(WITH_INTERNATIONAL OFF) + set(TRANSLATIONS_FOUND OFF) + set_and_warn_library_found("Translations" TRANSLATIONS_FOUND WITH_INTERNATIONAL) endif() endif() @@ -1245,6 +1242,8 @@ if(WITH_OPENMP) find_package(OpenMP) endif() + set_and_warn_library_found("OpenMP" OPENMP_FOUND WITH_OPENMP) + if(OPENMP_FOUND) if(NOT WITH_OPENMP_STATIC) string(APPEND CMAKE_C_FLAGS " ${OpenMP_C_FLAGS}") @@ -1260,9 +1259,6 @@ if(WITH_OPENMP) find_library_static(OpenMP_LIBRARIES gomp ${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES}) endif() - else() - message(STATUS "OpenMP not found, disabling WITH_OPENMP") - set(WITH_OPENMP OFF) endif() mark_as_advanced( @@ -1277,10 +1273,7 @@ endif() if(WITH_BULLET AND WITH_SYSTEM_BULLET) find_package(Bullet) - if(NOT BULLET_FOUND) - message(STATUS "Bullet not found, disabling WITH_BULLET") - set(WITH_BULLET OFF) - endif() + set_and_warn_library_found("Bullet" BULLET_FOUND WITH_BULLET) else() set(BULLET_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/extern/bullet2/src") # set(BULLET_LIBRARIES "") diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt index 4f40f44ad18..023d113b551 100644 --- a/build_files/build_environment/CMakeLists.txt +++ b/build_files/build_environment/CMakeLists.txt @@ -97,6 +97,8 @@ include(cmake/embree.cmake) include(cmake/openpgl.cmake) include(cmake/fmt.cmake) include(cmake/robinmap.cmake) +include(cmake/xml2.cmake) + if(NOT APPLE) include(cmake/xr_openxr.cmake) if(NOT WIN32 OR BUILD_MODE STREQUAL Release) @@ -149,7 +151,6 @@ if(NOT WIN32 OR ENABLE_MINGW64) endif() if(UNIX) include(cmake/flac.cmake) - include(cmake/xml2.cmake) if(NOT APPLE) include(cmake/spnav.cmake) include(cmake/jemalloc.cmake) diff --git a/build_files/build_environment/cmake/aom.cmake b/build_files/build_environment/cmake/aom.cmake index 9f64439771f..11c81c3f6e4 100644 --- a/build_files/build_environment/cmake/aom.cmake +++ b/build_files/build_environment/cmake/aom.cmake @@ -8,11 +8,6 @@ if(WIN32) # building with mingw, it'll have an unhappy time with that and # we need to clear them out. set(AOM_CMAKE_FLAGS ) - # CMake will correctly identify phreads being available, however - # we do not want to use them, as that gains a dependency on - # libpthreadswin.dll which we do not want. when pthreads is not - # available oam will use a pthreads emulation layer using win32 threads - set(AOM_EXTRA_ARGS_WIN32 -DCMAKE_HAVE_PTHREAD_H=OFF) else() set(AOM_GENERATOR "Unix Makefiles") set(AOM_CMAKE_FLAGS ${DEFAULT_CMAKE_FLAGS}) @@ -36,6 +31,7 @@ ExternalProject_Add(external_aom DOWNLOAD_DIR ${DOWNLOAD_DIR} URL_HASH ${AOM_HASH_TYPE}=${AOM_HASH} PREFIX ${BUILD_DIR}/aom + PATCH_COMMAND ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/aom/src/external_aom < ${PATCH_DIR}/aom.diff CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/aom/src/external_aom-build/ && ${CMAKE_COMMAND} -G "${AOM_GENERATOR}" -DCMAKE_INSTALL_PREFIX=${LIBDIR}/aom ${AOM_CMAKE_FLAGS} ${AOM_EXTRA_ARGS} ${BUILD_DIR}/aom/src/external_aom/ diff --git a/build_files/build_environment/cmake/cve_check.cmake b/build_files/build_environment/cmake/cve_check.cmake index dfb190bcffa..ac42444aef1 100644 --- a/build_files/build_environment/cmake/cve_check.cmake +++ b/build_files/build_environment/cmake/cve_check.cmake @@ -27,10 +27,12 @@ get_cmake_property(_variableNames VARIABLES) foreach (_variableName ${_variableNames}) if(_variableName MATCHES "CPE$") string(REPLACE ":" ";" CPE_LIST ${${_variableName}}) + string(REPLACE "_CPE" "_ID" CPE_DEPNAME ${_variableName}) list(GET CPE_LIST 3 CPE_VENDOR) list(GET CPE_LIST 4 CPE_NAME) list(GET CPE_LIST 5 CPE_VERSION) - set(SBOMCONTENTS "${SBOMCONTENTS}${CPE_VENDOR},${CPE_NAME},${CPE_VERSION}\n") + set(${CPE_DEPNAME} "${CPE_VENDOR},${CPE_NAME},${CPE_VERSION}") + set(SBOMCONTENTS "${SBOMCONTENTS}${CPE_VENDOR},${CPE_NAME},${CPE_VERSION},,,\n") endif() endforeach() configure_file(${CMAKE_SOURCE_DIR}/cmake/cve_check.csv.in ${CMAKE_CURRENT_BINARY_DIR}/cve_check.csv @ONLY) diff --git a/build_files/build_environment/cmake/cve_check.csv.in b/build_files/build_environment/cmake/cve_check.csv.in index 6e7e8db5609..734a24f8c77 100644 --- a/build_files/build_environment/cmake/cve_check.csv.in +++ b/build_files/build_environment/cmake/cve_check.csv.in @@ -1,2 +1,23 @@ -vendor,product,version +vendor,product,version,cve_number,remarks,comment +@OPENJPEG_ID@,CVE-2016-9675,Ignored,issue in convert command line tool not used by blender +@PYTHON_ID@,CVE-2009-2940,Ignored,issue in pygresql not used by blender +@PYTHON_ID@,CVE-2020-29396,Ignored,issue in odoo not used by blender +@PYTHON_ID@,CVE-2021-32052,Ignored,issue in django not used by blender +@PYTHON_ID@,CVE-2009-3720,Ignored,already fixed in libexpat version used +@SSL_ID@,CVE-2009-1390,Ignored,issue in mutt not used by blender +@SSL_ID@,CVE-2009-3765,Ignored,issue in mutt not used by blender +@SSL_ID@,CVE-2009-3766,Ignored,issue in mutt not used by blender +@SSL_ID@,CVE-2009-3767,Ignored,issue in ldap not used by blender +@SSL_ID@,CVE-2019-0190,Ignored,issue in apache not used by blender +@TIFF_ID@,CVE-2022-2056,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-2057,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-2058,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-2519,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-2520,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-2521,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-2953,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-34526,Ignored,issue in tiff command line tool not used by blender +@XML2_ID@,CVE-2016-3709,Ignored,not affecting blender and not considered a security issue upstream +@GMP_ID@,CVE-2021-43618,Mitigated,patched using upstream commit 561a9c25298e +@SQLITE_ID@,CVE-2022-35737,Ignored,only affects SQLITE_ENABLE_STAT4 compile option not used by blender or python @SBOMCONTENTS@ diff --git a/build_files/build_environment/cmake/download.cmake b/build_files/build_environment/cmake/download.cmake index 35bc028a1e3..8d75f0ff0ed 100644 --- a/build_files/build_environment/cmake/download.cmake +++ b/build_files/build_environment/cmake/download.cmake @@ -62,7 +62,7 @@ function(download_source dep) # since the actual build of the dep will notify the # platform maintainer if there is a problem with the # source package and refuse to build. - if(NOT PACKAGE_USE_UPSTREAM_SOURCES) + if(NOT PACKAGE_USE_UPSTREAM_SOURCES OR FORCE_CHECK_HASH) file(${TARGET_HASH_TYPE} ${TARGET_FILE} LOCAL_HASH) if(NOT ${TARGET_HASH} STREQUAL ${LOCAL_HASH}) message(FATAL_ERROR "${TARGET_FILE} ${TARGET_HASH_TYPE} mismatch\nExpected\t: ${TARGET_HASH}\nActual\t: ${LOCAL_HASH}") @@ -114,7 +114,6 @@ download_source(WEBP) download_source(SPNAV) download_source(JEMALLOC) download_source(XML2) -download_source(TINYXML) download_source(YAMLCPP) download_source(EXPAT) download_source(PUGIXML) diff --git a/build_files/build_environment/cmake/ffmpeg.cmake b/build_files/build_environment/cmake/ffmpeg.cmake index 7730607c514..e2b60e161f2 100644 --- a/build_files/build_environment/cmake/ffmpeg.cmake +++ b/build_files/build_environment/cmake/ffmpeg.cmake @@ -16,12 +16,6 @@ if(WIN32) --enable-libopenjpeg --disable-mediafoundation ) - if("${CMAKE_SIZEOF_VOID_P}" EQUAL "4") - set(FFMPEG_EXTRA_FLAGS - ${FFMPEG_EXTRA_FLAGS} - --x86asmexe=yasm - ) - endif() else() set(FFMPEG_EXTRA_FLAGS ${FFMPEG_EXTRA_FLAGS} diff --git a/build_files/build_environment/cmake/freetype.cmake b/build_files/build_environment/cmake/freetype.cmake index b6f53ede2db..842e5c42e25 100644 --- a/build_files/build_environment/cmake/freetype.cmake +++ b/build_files/build_environment/cmake/freetype.cmake @@ -7,8 +7,11 @@ set(FREETYPE_EXTRA_ARGS -DFT_DISABLE_HARFBUZZ=ON -DFT_DISABLE_PNG=ON -DFT_REQUIRE_BROTLI=ON + -DFT_REQUIRE_ZLIB=ON -DPC_BROTLIDEC_INCLUDEDIR=${LIBDIR}/brotli/include -DPC_BROTLIDEC_LIBDIR=${LIBDIR}/brotli/lib + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include ) ExternalProject_Add(external_freetype @@ -23,6 +26,7 @@ ExternalProject_Add(external_freetype add_dependencies( external_freetype external_brotli + external_zlib ) if(BUILD_MODE STREQUAL Release AND WIN32) diff --git a/build_files/build_environment/cmake/gmp.cmake b/build_files/build_environment/cmake/gmp.cmake index e624778869e..ddfdba6662d 100644 --- a/build_files/build_environment/cmake/gmp.cmake +++ b/build_files/build_environment/cmake/gmp.cmake @@ -27,6 +27,7 @@ ExternalProject_Add(external_gmp DOWNLOAD_DIR ${DOWNLOAD_DIR} URL_HASH ${GMP_HASH_TYPE}=${GMP_HASH} PREFIX ${BUILD_DIR}/gmp + PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/gmp/src/external_gmp < ${PATCH_DIR}/gmp.diff CONFIGURE_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/gmp/src/external_gmp/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/gmp ${GMP_OPTIONS} ${GMP_EXTRA_ARGS} BUILD_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/gmp/src/external_gmp/ && make -j${MAKE_THREADS} INSTALL_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/gmp/src/external_gmp/ && make install diff --git a/build_files/build_environment/cmake/llvm.cmake b/build_files/build_environment/cmake/llvm.cmake index e4ddc7db846..11f6bf7c218 100644 --- a/build_files/build_environment/cmake/llvm.cmake +++ b/build_files/build_environment/cmake/llvm.cmake @@ -9,6 +9,7 @@ endif() if(APPLE) set(LLVM_XML2_ARGS -DLIBXML2_LIBRARY=${LIBDIR}/xml2/lib/libxml2.a + -DLIBXML2_INCLUDE_DIR=${LIBDIR}/xml2/include/libxml2 ) set(LLVM_BUILD_CLANG_TOOLS_EXTRA ^^clang-tools-extra) set(BUILD_CLANG_TOOLS ON) diff --git a/build_files/build_environment/cmake/opencollada.cmake b/build_files/build_environment/cmake/opencollada.cmake index b2ae1a1a351..9473aafbe88 100644 --- a/build_files/build_environment/cmake/opencollada.cmake +++ b/build_files/build_environment/cmake/opencollada.cmake @@ -4,6 +4,16 @@ if(UNIX) set(OPENCOLLADA_EXTRA_ARGS -DLIBXML2_INCLUDE_DIR=${LIBDIR}/xml2/include/libxml2 -DLIBXML2_LIBRARIES=${LIBDIR}/xml2/lib/libxml2.a) +else() + set(OPENCOLLADA_EXTRA_ARGS + -DCMAKE_DEBUG_POSTFIX=_d + -DLIBXML2_INCLUDE_DIR=${LIBDIR}/xml2/include/libxml2 + ) + if(BUILD_MODE STREQUAL Release) + list(APPEND OPENCOLLADA_EXTRA_ARGS -DLIBXML2_LIBRARIES=${LIBDIR}/xml2/lib/libxml2s.lib) + else() + list(APPEND OPENCOLLADA_EXTRA_ARGS -DLIBXML2_LIBRARIES=${LIBDIR}/xml2/lib/libxml2sd.lib) + endif() endif() ExternalProject_Add(external_opencollada @@ -16,12 +26,11 @@ ExternalProject_Add(external_opencollada INSTALL_DIR ${LIBDIR}/opencollada ) -if(UNIX) - add_dependencies( - external_opencollada - external_xml2 - ) -endif() + +add_dependencies( + external_opencollada + external_xml2 +) if(WIN32) if(BUILD_MODE STREQUAL Release) @@ -32,17 +41,7 @@ if(WIN32) endif() if(BUILD_MODE STREQUAL Debug) ExternalProject_Add_Step(external_opencollada after_install - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/buffer.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/buffer_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/ftoa.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/ftoa_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/GeneratedSaxParser.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/GeneratedSaxParser_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/MathMLSolver.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/MathMLSolver_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/OpenCOLLADABaseUtils.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/OpenCOLLADABaseUtils_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/OpenCOLLADAFramework.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/OpenCOLLADAFramework_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/OpenCOLLADASaxFrameworkLoader.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/OpenCOLLADASaxFrameworkLoader_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/OpenCOLLADAStreamWriter.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/OpenCOLLADAStreamWriter_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/pcre.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/pcre_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/UTF.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/UTF_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/xml.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/xml_d.lib + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/opencollada/lib ${HARVEST_TARGET}/opencollada/lib DEPENDEES install ) endif() diff --git a/build_files/build_environment/cmake/options.cmake b/build_files/build_environment/cmake/options.cmake index 6e5f9df20b4..9058e945f6d 100644 --- a/build_files/build_environment/cmake/options.cmake +++ b/build_files/build_environment/cmake/options.cmake @@ -3,6 +3,7 @@ if(WIN32) option(ENABLE_MINGW64 "Enable building of ffmpeg/iconv/libsndfile/fftw3 by installing mingw64" ON) endif() +option(FORCE_CHECK_HASH "Force a check of all hashses during CMake the configure phase" OFF) option(WITH_BOOST_PYTHON "Enable building of boost with python support" OFF) cmake_host_system_information(RESULT NUM_CORES QUERY NUMBER_OF_LOGICAL_CORES) set(MAKE_THREADS ${NUM_CORES} CACHE STRING "Number of threads to run make with") diff --git a/build_files/build_environment/cmake/osl.cmake b/build_files/build_environment/cmake/osl.cmake index 9719de94d47..a5d000e4f44 100644 --- a/build_files/build_environment/cmake/osl.cmake +++ b/build_files/build_environment/cmake/osl.cmake @@ -32,6 +32,8 @@ set(OSL_EXTRA_ARGS -DUSE_Qt5=OFF -DINSTALL_DOCS=OFF -Dpugixml_ROOT=${LIBDIR}/pugixml + -DTIFF_ROOT=${LIBDIR}/tiff + -DJPEG_ROOT=${LIBDIR}/jpeg -DUSE_PYTHON=OFF -DCMAKE_CXX_STANDARD=14 -DImath_ROOT=${LIBDIR}/imath @@ -81,6 +83,7 @@ if(WIN32) COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/osl/lib/oslcomp.lib ${HARVEST_TARGET}/osl/lib/oslcomp_d.lib COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/osl/lib/oslexec.lib ${HARVEST_TARGET}/osl/lib/oslexec_d.lib COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/osl/lib/oslquery.lib ${HARVEST_TARGET}/osl/lib/oslquery_d.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/osl/lib/oslnoise.lib ${HARVEST_TARGET}/osl/lib/oslnoise_d.lib DEPENDEES install ) endif() diff --git a/build_files/build_environment/cmake/png.cmake b/build_files/build_environment/cmake/png.cmake index 890be673cb8..371f2608e2a 100644 --- a/build_files/build_environment/cmake/png.cmake +++ b/build_files/build_environment/cmake/png.cmake @@ -24,6 +24,14 @@ add_dependencies( external_zlib ) +if(WIN32 AND BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_png after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/png/include/ ${HARVEST_TARGET}/png/include/ + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/png/lib/libpng16_static${LIBEXT} ${HARVEST_TARGET}/png/lib/libpng${LIBEXT} + DEPENDEES install + ) +endif() + if(WIN32 AND BUILD_MODE STREQUAL Debug) ExternalProject_Add_Step(external_png after_install COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/png/lib/libpng16_staticd${LIBEXT} ${LIBDIR}/png/lib/libpng16${LIBEXT} diff --git a/build_files/build_environment/cmake/python.cmake b/build_files/build_environment/cmake/python.cmake index 8fed10e9d72..72ae27ddfdb 100644 --- a/build_files/build_environment/cmake/python.cmake +++ b/build_files/build_environment/cmake/python.cmake @@ -15,9 +15,11 @@ if(WIN32) endmacro() set(PYTHON_EXTERNALS_FOLDER ${BUILD_DIR}/python/src/external_python/externals) + set(ZLIB_SOURCE_FOLDER ${BUILD_DIR}/zlib/src/external_zlib) set(DOWNLOADS_EXTERNALS_FOLDER ${DOWNLOAD_DIR}/externals) cmake_to_dos_path(${PYTHON_EXTERNALS_FOLDER} PYTHON_EXTERNALS_FOLDER_DOS) + cmake_to_dos_path(${ZLIB_SOURCE_FOLDER} ZLIB_SOURCE_FOLDER_DOS) cmake_to_dos_path(${DOWNLOADS_EXTERNALS_FOLDER} DOWNLOADS_EXTERNALS_FOLDER_DOS) ExternalProject_Add(external_python @@ -25,12 +27,21 @@ if(WIN32) DOWNLOAD_DIR ${DOWNLOAD_DIR} URL_HASH ${PYTHON_HASH_TYPE}=${PYTHON_HASH} PREFIX ${BUILD_DIR}/python - CONFIGURE_COMMAND "" + # Python will download its own deps and there's very little we can do about + # that beyond placing some code in their externals dir before it tries. + # the foldernames *HAVE* to match the ones inside pythons get_externals.cmd. + # python 3.10.8 still ships zlib 1.2.12, replace it with our 1.2.13 + # copy until they update. + CONFIGURE_COMMAND mkdir ${PYTHON_EXTERNALS_FOLDER_DOS} && + mklink /J ${PYTHON_EXTERNALS_FOLDER_DOS}\\zlib-1.2.12 ${ZLIB_SOURCE_FOLDER_DOS} && + ${CMAKE_COMMAND} -E copy ${ZLIB_SOURCE_FOLDER}/../external_zlib-build/zconf.h ${PYTHON_EXTERNALS_FOLDER}/zlib-1.2.12/zconf.h BUILD_COMMAND cd ${BUILD_DIR}/python/src/external_python/pcbuild/ && set IncludeTkinter=false && call build.bat -e -p x64 -c ${BUILD_MODE} - PATCH_COMMAND ${PATCH_CMD} --verbose -p1 -d ${BUILD_DIR}/python/src/external_python < ${PATCH_DIR}/python_windows.diff INSTALL_COMMAND ${PYTHON_BINARY_INTERNAL} ${PYTHON_SRC}/PC/layout/main.py -b ${PYTHON_SRC}/PCbuild/amd64 -s ${PYTHON_SRC} -t ${PYTHON_SRC}/tmp/ --include-stable --include-pip --include-dev --include-launchers --include-venv --include-symbols ${PYTHON_EXTRA_INSTLAL_FLAGS} --copy ${LIBDIR}/python ) - + add_dependencies( + external_python + external_zlib + ) else() if(APPLE) # Disable functions that can be in 10.13 sdk but aren't available on 10.9 target. diff --git a/build_files/build_environment/cmake/sndfile.cmake b/build_files/build_environment/cmake/sndfile.cmake index 192c25f5ed1..a2ac2a33779 100644 --- a/build_files/build_environment/cmake/sndfile.cmake +++ b/build_files/build_environment/cmake/sndfile.cmake @@ -11,18 +11,11 @@ else() set(SNDFILE_OPTIONS --enable-static --disable-shared ) endif() -if(UNIX) - set(SNDFILE_PATCH_CMD ${PATCH_CMD} --verbose -p 0 -d ${BUILD_DIR}/sndfile/src/external_sndfile < ${PATCH_DIR}/sndfile.diff) -else() - set(SNDFILE_PATCH_CMD) -endif() - ExternalProject_Add(external_sndfile URL file://${PACKAGE_DIR}/${SNDFILE_FILE} DOWNLOAD_DIR ${DOWNLOAD_DIR} URL_HASH ${SNDFILE_HASH_TYPE}=${SNDFILE_HASH} PREFIX ${BUILD_DIR}/sndfile - PATCH_COMMAND ${SNDFILE_PATCH_CMD} CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sndfile/src/external_sndfile/ && ${SNDFILE_ENV} ${CONFIGURE_COMMAND} ${SNDFILE_OPTIONS} --prefix=${mingw_LIBDIR}/sndfile BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sndfile/src/external_sndfile/ && make -j${MAKE_THREADS} INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sndfile/src/external_sndfile/ && make install diff --git a/build_files/build_environment/cmake/sqlite.cmake b/build_files/build_environment/cmake/sqlite.cmake index c82d832574a..c151a495ff1 100644 --- a/build_files/build_environment/cmake/sqlite.cmake +++ b/build_files/build_environment/cmake/sqlite.cmake @@ -48,7 +48,6 @@ ExternalProject_Add(external_sqlite DOWNLOAD_DIR ${DOWNLOAD_DIR} URL_HASH ${SQLITE_HASH_TYPE}=${SQLITE_HASH} PREFIX ${BUILD_DIR}/sqlite - PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/sqlite/src/external_sqlite < ${PATCH_DIR}/sqlite.diff CONFIGURE_COMMAND ${SQLITE_CONFIGURE_ENV} && cd ${BUILD_DIR}/sqlite/src/external_sqlite/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/sqlite ${SQLITE_CONFIGURATION_ARGS} BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sqlite/src/external_sqlite/ && make -j${MAKE_THREADS} INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sqlite/src/external_sqlite/ && make install diff --git a/build_files/build_environment/cmake/ssl.cmake b/build_files/build_environment/cmake/ssl.cmake index 21c4d2418c3..628187dc0ac 100644 --- a/build_files/build_environment/cmake/ssl.cmake +++ b/build_files/build_environment/cmake/ssl.cmake @@ -5,6 +5,7 @@ set(SSL_PATCH_CMD echo .) 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") diff --git a/build_files/build_environment/cmake/tiff.cmake b/build_files/build_environment/cmake/tiff.cmake index 1f8e9442ae5..1ac2e4c6058 100644 --- a/build_files/build_environment/cmake/tiff.cmake +++ b/build_files/build_environment/cmake/tiff.cmake @@ -25,6 +25,7 @@ ExternalProject_Add(external_tiff add_dependencies( external_tiff external_zlib + external_jpeg ) if(WIN32) if(BUILD_MODE STREQUAL Release) diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake index bfc6d27f74d..06a923e5c22 100644 --- a/build_files/build_environment/cmake/versions.cmake +++ b/build_files/build_environment/cmake/versions.cmake @@ -8,9 +8,9 @@ # Not all of our dependencies are currently in the nvd database so not all # dependencies have one assigned. -set(ZLIB_VERSION 1.2.12) +set(ZLIB_VERSION 1.2.13) set(ZLIB_URI https://zlib.net/zlib-${ZLIB_VERSION}.tar.gz) -set(ZLIB_HASH 5fc414a9726be31427b440b434d05f78) +set(ZLIB_HASH 9b8aa094c4e5765dabf4da391f00d15c) set(ZLIB_HASH_TYPE MD5) set(ZLIB_FILE zlib-${ZLIB_VERSION}.tar.gz) set(ZLIB_CPE "cpe:2.3:a:zlib:zlib:${ZLIB_VERSION}:*:*:*:*:*:*:*") @@ -88,9 +88,9 @@ else() set(OPENEXR_VERSION_POSTFIX) endif() -set(FREETYPE_VERSION 2.11.1) +set(FREETYPE_VERSION 2.12.1) set(FREETYPE_URI http://prdownloads.sourceforge.net/freetype/freetype-${FREETYPE_VERSION}.tar.gz) -set(FREETYPE_HASH bd4e3b007474319909a6b79d50908e85) +set(FREETYPE_HASH 8bc5c9c9df7ac12c504f8918552a7cf2) set(FREETYPE_HASH_TYPE MD5) set(FREETYPE_FILE freetype-${FREETYPE_VERSION}.tar.gz) SET(FREETYPE_CPE "cpe:2.3:a:freetype:freetype:${FREETYPE_VERSION}:*:*:*:*:*:*:*") @@ -159,9 +159,9 @@ 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.3.13.0) +set(OPENIMAGEIO_VERSION v2.3.20.0) set(OPENIMAGEIO_URI https://github.com/OpenImageIO/oiio/archive/refs/tags/${OPENIMAGEIO_VERSION}.tar.gz) -set(OPENIMAGEIO_HASH de45fb38501c4581062b522b53b6141c) +set(OPENIMAGEIO_HASH defb1fe7c8e64bac60eb3cacaf5c3736) set(OPENIMAGEIO_HASH_TYPE MD5) set(OPENIMAGEIO_FILE OpenImageIO-${OPENIMAGEIO_VERSION}.tar.gz) @@ -189,17 +189,17 @@ set(TIFF_HASH_TYPE MD5) set(TIFF_FILE tiff-${TIFF_VERSION}.tar.gz) set(TIFF_CPE "cpe:2.3:a:libtiff:libtiff:${TIFF_VERSION}:*:*:*:*:*:*:*") -set(OSL_VERSION 1.11.17.0) -set(OSL_URI https://github.com/imageworks/OpenShadingLanguage/archive/Release-${OSL_VERSION}.tar.gz) -set(OSL_HASH 63265472ce14548839ace2e21e401544) +set(OSL_VERSION 1.12.6.2) +set(OSL_URI https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/archive/refs/tags/v${OSL_VERSION}.tar.gz) +set(OSL_HASH 6fef11548adfdd3e5b25c49d2dae96ee) set(OSL_HASH_TYPE MD5) set(OSL_FILE OpenShadingLanguage-${OSL_VERSION}.tar.gz) -set(PYTHON_VERSION 3.10.2) +set(PYTHON_VERSION 3.10.8) 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 14e8c22458ed7779a1957b26cde01db9) +set(PYTHON_HASH e92356b012ed4d0e09675131d39b1bde) set(PYTHON_HASH_TYPE MD5) set(PYTHON_FILE Python-${PYTHON_VERSION}.tar.xz) set(PYTHON_CPE "cpe:2.3:a:python:python:${PYTHON_VERSION}:-:*:*:*:*:*:*") @@ -298,17 +298,17 @@ set(XVIDCORE_HASH abbdcbd39555691dd1c9b4d08f0a031376a3b211652c0d8b3b8aa9be1303ce set(XVIDCORE_HASH_TYPE SHA256) set(XVIDCORE_FILE xvidcore-${XVIDCORE_VERSION}.tar.gz) -set(OPENJPEG_VERSION 2.4.0) -set(OPENJPEG_SHORT_VERSION 2.4) +set(OPENJPEG_VERSION 2.5.0) +set(OPENJPEG_SHORT_VERSION 2.5) set(OPENJPEG_URI https://github.com/uclouvain/openjpeg/archive/v${OPENJPEG_VERSION}.tar.gz) -set(OPENJPEG_HASH 8702ba68b442657f11aaeb2b338443ca8d5fb95b0d845757968a7be31ef7f16d) +set(OPENJPEG_HASH 0333806d6adecc6f7a91243b2b839ff4d2053823634d4f6ed7a59bc87409122a) 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.0) +set(FFMPEG_VERSION 5.1.2) set(FFMPEG_URI http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.bz2) -set(FFMPEG_HASH c0130b8db2c763430fd1c6905288d61bc44ee0548ad5fcd2dfd650b88432bed9) +set(FFMPEG_HASH 39a0bcc8d98549f16c570624678246a6ac736c066cebdb409f9502e915b22f2b) set(FFMPEG_HASH_TYPE SHA256) set(FFMPEG_FILE ffmpeg-${FFMPEG_VERSION}.tar.bz2) set(FFMPEG_CPE "cpe:2.3:a:ffmpeg:ffmpeg:${FFMPEG_VERSION}:*:*:*:*:*:*:*") @@ -325,9 +325,9 @@ set(ICONV_HASH 7d2a800b952942bb2880efb00cfd524c) set(ICONV_HASH_TYPE MD5) set(ICONV_FILE libiconv-${ICONV_VERSION}.tar.gz) -set(SNDFILE_VERSION 1.0.28) -set(SNDFILE_URI http://www.mega-nerd.com/libsndfile/files/libsndfile-${SNDFILE_VERSION}.tar.gz) -set(SNDFILE_HASH 646b5f98ce89ac60cdb060fcd398247c) +set(SNDFILE_VERSION 1.1.0) +set(SNDFILE_URI https://github.com/libsndfile/libsndfile/releases/download/1.1.0/libsndfile-${SNDFILE_VERSION}.tar.xz) +set(SNDFILE_HASH e63dead2b4f0aaf323687619d007ee6a) set(SNDFILE_HASH_TYPE MD5) set(SNDFILE_FILE libsndfile-${SNDFILE_VERSION}.tar.gz) set(SNDFILE_CPE "cpe:2.3:a:libsndfile_project:libsndfile:${SNDFILE_VERSION}:*:*:*:*:*:*:*") @@ -351,21 +351,13 @@ set(JEMALLOC_HASH 3d41fbf006e6ebffd489bdb304d009ae) set(JEMALLOC_HASH_TYPE MD5) set(JEMALLOC_FILE jemalloc-${JEMALLOC_VERSION}.tar.bz2) -set(XML2_VERSION 2.9.10) -set(XML2_URI http://xmlsoft.org/sources/libxml2-${XML2_VERSION}.tar.gz) -set(XML2_HASH 10942a1dc23137a8aa07f0639cbfece5) +set(XML2_VERSION 2.10.3) +set(XML2_URI https://download.gnome.org/sources/libxml2/2.10/libxml2-${XML2_VERSION}.tar.xz) +set(XML2_HASH f9edac7fac232b3657a003fd9a5bbe42) set(XML2_HASH_TYPE MD5) -set(XML2_FILE libxml2-${XML2_VERSION}.tar.gz) +set(XML2_FILE libxml2-${XML2_VERSION}.tar.xz) set(XML2_CPE "cpe:2.3:a:xmlsoft:libxml2:${XML2_VERSION}:*:*:*:*:*:*:*") -set(TINYXML_VERSION 2_6_2) -set(TINYXML_VERSION_DOTS 2.6.2) -set(TINYXML_URI https://nchc.dl.sourceforge.net/project/tinyxml/tinyxml/${TINYXML_VERSION_DOTS}/tinyxml_${TINYXML_VERSION}.tar.gz) -set(TINYXML_HASH c1b864c96804a10526540c664ade67f0) -set(TINYXML_HASH_TYPE MD5) -set(TINYXML_FILE tinyxml_${TINYXML_VERSION}.tar.gz) -set(TINYXML_CPE "cpe:2.3:a:tinyxml_project:tinyxml:${TINYXML_VERSION_DOTS}:*:*:*:*:*:*:*") - set(YAMLCPP_VERSION 0.6.3) set(YAMLCPP_URI https://codeload.github.com/jbeder/yaml-cpp/tar.gz/yaml-cpp-${YAMLCPP_VERSION}) set(YAMLCPP_HASH b45bf1089a382e81f6b661062c10d0c2) @@ -379,10 +371,10 @@ set(PYSTRING_HASH f2c68786b359f5e4e62bed53bc4fb86d) set(PYSTRING_HASH_TYPE MD5) set(PYSTRING_FILE pystring-${PYSTRING_VERSION}.tar.gz) -set(EXPAT_VERSION 2_4_4) -set(EXPAT_VERSION_DOTS 2.4.4) +set(EXPAT_VERSION 2_4_9) +set(EXPAT_VERSION_DOTS 2.4.9) set(EXPAT_URI https://github.com/libexpat/libexpat/archive/R_${EXPAT_VERSION}.tar.gz) -set(EXPAT_HASH 2d3e81dee94b452369dc6394ff0f8f98) +set(EXPAT_HASH b59a2aa796be1ee177bbab3b7231dfa5) set(EXPAT_HASH_TYPE MD5) set(EXPAT_FILE libexpat-${EXPAT_VERSION}.tar.gz) set(EXPAT_CPE "cpe:2.3:a:libexpat_project:libexpat:${EXPAT_VERSION_DOTS}:*:*:*:*:*:*:*") @@ -410,6 +402,10 @@ set(FLEX_FILE flex-${FLEX_VERSION}.tar.gz) # NOTE: bzip.org domain does no longer belong to BZip 2 project, so we download # sources from Debian packaging. +# +# NOTE 2: 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(BZIP2_VERSION 1.0.8) set(BZIP2_URI http://http.debian.net/debian/pool/main/b/bzip2/bzip2_${BZIP2_VERSION}.orig.tar.gz) set(BZIP2_HASH ab5a03176ee106d3f0fa90e381da478ddae405918153cca248e682cd0c4a2269) @@ -417,6 +413,9 @@ set(BZIP2_HASH_TYPE SHA256) set(BZIP2_FILE bzip2_${BZIP2_VERSION}.orig.tar.gz) set(BZIP2_CPE "cpe:2.3:a:bzip:bzip2:${BZIP2_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(FFI_VERSION 3.3) set(FFI_URI https://sourceware.org/pub/libffi/libffi-${FFI_VERSION}.tar.gz) set(FFI_HASH 72fba7922703ddfa7a028d513ac15a85c8d54c8d67f55fa5a4802885dc652056) @@ -430,27 +429,25 @@ set(LZMA_HASH 5117f930900b341493827d63aa910ff5e011e0b994197c3b71c08a20228a42df) set(LZMA_HASH_TYPE SHA256) set(LZMA_FILE xz-${LZMA_VERSION}.tar.bz2) -if(BLENDER_PLATFORM_ARM) - # Need at least 1.1.1i for aarch64 support (https://github.com/openssl/openssl/pull/13218) - set(SSL_VERSION 1.1.1i) - set(SSL_URI https://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz) - set(SSL_HASH e8be6a35fe41d10603c3cc635e93289ed00bf34b79671a3a4de64fcee00d5242) - set(SSL_HASH_TYPE SHA256) - set(SSL_FILE openssl-${SSL_VERSION}.tar.gz) -else() - set(SSL_VERSION 1.1.1g) - set(SSL_URI https://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz) - set(SSL_HASH ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46) - set(SSL_HASH_TYPE SHA256) - set(SSL_FILE openssl-${SSL_VERSION}.tar.gz) -endif() +# 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(SSL_VERSION 1.1.1q) +set(SSL_URI https://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz) +set(SSL_HASH d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca) +set(SSL_HASH_TYPE SHA256) +set(SSL_FILE openssl-${SSL_VERSION}.tar.gz) set(SSL_CPE "cpe:2.3:a:openssl:openssl:${SSL_VERSION}:*:*:*:*:*:*:*") -set(SQLITE_VERSION 3.31.1) -set(SQLITE_URI https://www.sqlite.org/2018/sqlite-src-3240000.zip) -set(SQLITE_HASH fb558c49ee21a837713c4f1e7e413309aabdd9c7) +# 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.37.2) +set(SQLLITE_LONG_VERSION 3370200) +set(SQLITE_URI https://www.sqlite.org/2022/sqlite-autoconf-${SQLLITE_LONG_VERSION}.tar.gz) +set(SQLITE_HASH e56faacadfb4154f8fbd0f2a3f827d13706b70a1) set(SQLITE_HASH_TYPE SHA1) -set(SQLITE_FILE sqlite-src-3240000.zip) +set(SQLITE_FILE sqlite-autoconf-${SQLLITE_LONG_VERSION}.tar.gz) set(SQLITE_CPE "cpe:2.3:a:sqlite:sqlite:${SQLITE_VERSION}:*:*:*:*:*:*:*") set(EMBREE_VERSION 3.13.4) @@ -564,19 +561,19 @@ set(BROTLI_CPE "cpe:2.3:a:google:brotli:${BROTLI_VERSION}:*:*:*:*:*:*:*") set(OPENPGL_VERSION v0.4.0-beta) set(OPENPGL_SHORT_VERSION 0.4.0) set(OPENPGL_URI https://github.com/OpenPathGuidingLibrary/openpgl/archive/refs/tags/${OPENPGL_VERSION}.tar.gz) -set(OPENPGL_HASH 58d5b65c533ce6cac3f7e1d51cf169a5411adf356abcd85f04049bbcaecc2e77) +set(OPENPGL_HASH 1f090f88ab2bad028e8b3619aa926f4f97cf7b2c175b904704d2fec8593dd3cd) set(OPENPGL_HASH_TYPE SHA256) set(OPENPGL_FILE openpgl-${OPENPGL_VERSION}.tar.gz) -set(LEVEL_ZERO_VERSION v1.7.15) +set(LEVEL_ZERO_VERSION v1.8.5) set(LEVEL_ZERO_URI https://github.com/oneapi-src/level-zero/archive/refs/tags/${LEVEL_ZERO_VERSION}.tar.gz) -set(LEVEL_ZERO_HASH c39bb05a8e5898aa6c444e1704105b93d3f1888b9c333f8e7e73825ffbfb2617) +set(LEVEL_ZERO_HASH b6e9663bbcc53c148d32376998298bec6f7c434ef2218c61fa708963e3a09394) set(LEVEL_ZERO_HASH_TYPE SHA256) set(LEVEL_ZERO_FILE level-zero-${LEVEL_ZERO_VERSION}.tar.gz) -set(DPCPP_VERSION 20220812) +set(DPCPP_VERSION 20221019) set(DPCPP_URI https://github.com/intel/llvm/archive/refs/tags/sycl-nightly/${DPCPP_VERSION}.tar.gz) -set(DPCPP_HASH 0e3c95346c295f5cf80f3a42d80b1c49481955898530242636ddc002627248d6) +set(DPCPP_HASH 2f533946e91ce3829431758ea17b0b834b960c1a796e9e4563c86e03eb9603a2) set(DPCPP_HASH_TYPE SHA256) set(DPCPP_FILE DPCPP-${DPCPP_VERSION}.tar.gz) @@ -589,9 +586,9 @@ set(DPCPP_FILE DPCPP-${DPCPP_VERSION}.tar.gz) # will take care of building them, unpack is being done in dpcpp_deps.cmake # Source llvm/lib/SYCLLowerIR/CMakeLists.txt -set(VCINTRINSICS_VERSION 984bb27baacce6ee5c716c2e64845f2a1928025b) +set(VCINTRINSICS_VERSION abce9184b7a3a7fe1b02289b9285610d9dc45465) set(VCINTRINSICS_URI https://github.com/intel/vc-intrinsics/archive/${VCINTRINSICS_VERSION}.tar.gz) -set(VCINTRINSICS_HASH abea415a15a0dd11fdc94dee8fb462910f2548311b787e02f42509789e1b0d7b) +set(VCINTRINSICS_HASH 3e9fd471246b87633b26f7e15e17ab7733d357458c53d5c5881c03929d6c551f) set(VCINTRINSICS_HASH_TYPE SHA256) set(VCINTRINSICS_FILE vc-intrinsics-${VCINTRINSICS_VERSION}.tar.gz) @@ -603,9 +600,9 @@ set(OPENCLHEADERS_HASH_TYPE SHA256) set(OPENCLHEADERS_FILE opencl_headers-${OPENCLHEADERS_VERSION}.tar.gz) # Source opencl/CMakeLists.txt -set(ICDLOADER_VERSION aec3952654832211636fc4af613710f80e203b0a) +set(ICDLOADER_VERSION 792682ad3d877ab38573b997808bab3b43902b70) set(ICDLOADER_URI https://github.com/KhronosGroup/OpenCL-ICD-Loader/archive/${ICDLOADER_VERSION}.tar.gz) -set(ICDLOADER_HASH e1880551d67bd8dc31d13de63b94bbfd6b1f315b6145dad1ffcd159b89bda93c) +set(ICDLOADER_HASH b33a0320d94bf300efa1da97931ded506d27813bd1148da6858fe79d412d1ea2) set(ICDLOADER_HASH_TYPE SHA256) set(ICDLOADER_FILE icdloader-${ICDLOADER_VERSION}.tar.gz) @@ -620,9 +617,9 @@ set(MP11_FILE mp11-${MP11_VERSION}.tar.gz) # Source llvm-spirv/CMakeLists.txt (repo) # Source llvm-spirv/spirv-headers-tag.conf (hash) -set(SPIRV_HEADERS_VERSION 36c0c1596225e728bd49abb7ef56a3953e7ed468) +set(SPIRV_HEADERS_VERSION 5a121866927a16ab9d49bed4788b532c7fcea766) set(SPIRV_HEADERS_URI https://github.com/KhronosGroup/SPIRV-Headers/archive/${SPIRV_HEADERS_VERSION}.tar.gz) -set(SPIRV_HEADERS_HASH 7a5c89633f8740456fe8adee052033e134476d267411d1336c0cb1e587a9229a) +set(SPIRV_HEADERS_HASH ec8ecb471a62672697846c436501638ab25447ae9d4a6761e0bfe8a9a839502a) set(SPIRV_HEADERS_HASH_TYPE SHA256) set(SPIRV_HEADERS_FILE SPIR-V-Headers-${SPIRV_HEADERS_VERSION}.tar.gz) @@ -637,9 +634,9 @@ set(SPIRV_HEADERS_FILE SPIR-V-Headers-${SPIRV_HEADERS_VERSION}.tar.gz) # compiler, the versions used are taken from the following location # https://github.com/intel/intel-graphics-compiler/releases -set(IGC_VERSION 1.0.11222) +set(IGC_VERSION 1.0.12149.1) set(IGC_URI https://github.com/intel/intel-graphics-compiler/archive/refs/tags/igc-${IGC_VERSION}.tar.gz) -set(IGC_HASH d92f0608dcbb52690855685f9447282e5c09c0ba98ae35fabf114fcf8b1e9fcf) +set(IGC_HASH 44f67f24e3bc5130f9f062533abf8154782a9d0a992bc19b498639a8521ae836) set(IGC_HASH_TYPE SHA256) set(IGC_FILE igc-${IGC_VERSION}.tar.gz) @@ -659,15 +656,15 @@ set(IGC_LLVM_FILE ${IGC_LLVM_VERSION}.tar.gz) # # WARNING WARNING WARNING -set(IGC_OPENCL_CLANG_VERSION bbdd1587f577397a105c900be114b56755d1f7dc) +set(IGC_OPENCL_CLANG_VERSION 363a5262d8c7cff3fb28f3bdb5d85c8d7e91c1bb) set(IGC_OPENCL_CLANG_URI https://github.com/intel/opencl-clang/archive/${IGC_OPENCL_CLANG_VERSION}.tar.gz) -set(IGC_OPENCL_CLANG_HASH d08315f1b0d8a6fef33de2b3e6aa7356534c324910634962c72523d970773efc) +set(IGC_OPENCL_CLANG_HASH aa8cf72bb239722ce8ce44f79413c6887ecc8ca18477dd520aa5c4809756da9a) set(IGC_OPENCL_CLANG_HASH_TYPE SHA256) set(IGC_OPENCL_CLANG_FILE opencl-clang-${IGC_OPENCL_CLANG_VERSION}.tar.gz) -set(IGC_VCINTRINSICS_VERSION v0.4.0) +set(IGC_VCINTRINSICS_VERSION v0.5.0) set(IGC_VCINTRINSICS_URI https://github.com/intel/vc-intrinsics/archive/refs/tags/${IGC_VCINTRINSICS_VERSION}.tar.gz) -set(IGC_VCINTRINSICS_HASH c8b92682ad5031cf9d5b82a40e7d5c0e763cd9278660adbcaa69aab988e4b589) +set(IGC_VCINTRINSICS_HASH 70bb47c5e32173cf61514941e83ae7c7eb4485e6d2fca60cfa1f50d4f42c41f2) set(IGC_VCINTRINSICS_HASH_TYPE SHA256) set(IGC_VCINTRINSICS_FILE vc-intrinsics-${IGC_VCINTRINSICS_VERSION}.tar.gz) @@ -683,9 +680,9 @@ set(IGC_SPIRV_TOOLS_HASH 6e19900e948944243024aedd0a201baf3854b377b9cc7a386553bc1 set(IGC_SPIRV_TOOLS_HASH_TYPE SHA256) set(IGC_SPIRV_TOOLS_FILE SPIR-V-Tools-${IGC_SPIRV_TOOLS_VERSION}.tar.gz) -set(IGC_SPIRV_TRANSLATOR_VERSION 99420daab98998a7e36858befac9c5ed109d4920) +set(IGC_SPIRV_TRANSLATOR_VERSION a31ffaeef77e23d500b3ea3d35e0c42ff5648ad9) set(IGC_SPIRV_TRANSLATOR_URI https://github.com/KhronosGroup/SPIRV-LLVM-Translator/archive/${IGC_SPIRV_TRANSLATOR_VERSION}.tar.gz) -set(IGC_SPIRV_TRANSLATOR_HASH 77dfb4ddb6bfb993535562c02ddea23f0a0d1c5a0258c1afe7e27c894ff783a8) +set(IGC_SPIRV_TRANSLATOR_HASH 9e26c96a45341b8f8af521bacea20e752623346340addd02af95d669f6e89252) set(IGC_SPIRV_TRANSLATOR_HASH_TYPE SHA256) set(IGC_SPIRV_TRANSLATOR_FILE SPIR-V-Translator-${IGC_SPIRV_TRANSLATOR_VERSION}.tar.gz) @@ -693,15 +690,15 @@ set(IGC_SPIRV_TRANSLATOR_FILE SPIR-V-Translator-${IGC_SPIRV_TRANSLATOR_VERSION}. ### Intel Graphics Compiler DEPS END ### ######################################## -set(GMMLIB_VERSION intel-gmmlib-22.1.2) +set(GMMLIB_VERSION intel-gmmlib-22.1.8) set(GMMLIB_URI https://github.com/intel/gmmlib/archive/refs/tags/${GMMLIB_VERSION}.tar.gz) -set(GMMLIB_HASH 3b9a6d5e7e3f5748b3d0a2fb0e980ae943907fece0980bd9c0508e71c838e334) +set(GMMLIB_HASH bf23e9a3742b4fb98c7666c9e9b29f3219e4b2fb4d831aaf4eed71f5e2d17368) set(GMMLIB_HASH_TYPE SHA256) set(GMMLIB_FILE ${GMMLIB_VERSION}.tar.gz) -set(OCLOC_VERSION 22.20.23198) +set(OCLOC_VERSION 22.38.24278) set(OCLOC_URI https://github.com/intel/compute-runtime/archive/refs/tags/${OCLOC_VERSION}.tar.gz) -set(OCLOC_HASH ab22b8bf2560a57fdd3def0e35a62ca75991406f959c0263abb00cd6cd9ae998) +set(OCLOC_HASH db0c542fccd651e6404b15a74d46027f1ce0eda8dc9e25a40cbb6c0faef257ee) set(OCLOC_HASH_TYPE SHA256) set(OCLOC_FILE ocloc-${OCLOC_VERSION}.tar.gz) diff --git a/build_files/build_environment/cmake/wayland.cmake b/build_files/build_environment/cmake/wayland.cmake index 799f2513da9..c73db1d10ff 100644 --- a/build_files/build_environment/cmake/wayland.cmake +++ b/build_files/build_environment/cmake/wayland.cmake @@ -7,10 +7,14 @@ ExternalProject_Add(external_wayland PREFIX ${BUILD_DIR}/wayland PATCH_COMMAND ${PATCH_CMD} -d ${BUILD_DIR}/wayland/src/external_wayland < ${PATCH_DIR}/wayland.diff # Use `-E` so the `PKG_CONFIG_PATH` can be defined to link against our own LIBEXPAT & LIBXML2. - # Note that passing link args "ffi/lib" should not be needed, but + # + # NOTE: passing link args "ffi/lib" should not be needed, but # `pkgconfig` would incorrectly look in "ffi/lib/../lib64" otherwise. + # + # NOTE: `-lm` is needed for `libxml2` which is a static library that uses `libm.so`, + # without this, math symbols such as `floor` aren't found. CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env PKG_CONFIG_PATH=${LIBDIR}/expat/lib/pkgconfig:${LIBDIR}/xml2/lib/pkgconfig:${LIBDIR}/ffi/lib/pkgconfig:$PKG_CONFIG_PATH - meson --prefix ${LIBDIR}/wayland -Ddocumentation=false -Dtests=false -Dc_link_args=-L${LIBDIR}/ffi/lib . ../external_wayland + meson --prefix ${LIBDIR}/wayland -Ddocumentation=false -Dtests=false -D "c_link_args=-L${LIBDIR}/ffi/lib -lm" . ../external_wayland BUILD_COMMAND ninja INSTALL_COMMAND ninja install ) diff --git a/build_files/build_environment/cmake/xml2.cmake b/build_files/build_environment/cmake/xml2.cmake index cd24fd836b0..3d31ec131bb 100644 --- a/build_files/build_environment/cmake/xml2.cmake +++ b/build_files/build_environment/cmake/xml2.cmake @@ -1,20 +1,48 @@ # SPDX-License-Identifier: GPL-2.0-or-later -ExternalProject_Add(external_xml2 - URL file://${PACKAGE_DIR}/${XML2_FILE} - DOWNLOAD_DIR ${DOWNLOAD_DIR} - URL_HASH ${XML2_HASH_TYPE}=${XML2_HASH} - PREFIX ${BUILD_DIR}/xml2 - CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && ${CONFIGURE_COMMAND} - --prefix=${LIBDIR}/xml2 - --disable-shared - --enable-static - --with-pic - --with-python=no - --with-lzma=no - --with-zlib=no - --with-iconv=no - BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && make -j${MAKE_THREADS} - INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && make install - INSTALL_DIR ${LIBDIR}/xml2 -) +if(WIN32) + set(XML2_EXTRA_ARGS + -DLIBXML2_WITH_ZLIB=OFF + -DLIBXML2_WITH_LZMA=OFF + -DLIBXML2_WITH_PYTHON=OFF + -DLIBXML2_WITH_ICONV=OFF + -DLIBXML2_WITH_TESTS=OFF + -DLIBXML2_WITH_PROGRAMS=OFF + -DBUILD_SHARED_LIBS=OFF + ) + ExternalProject_Add(external_xml2 + URL file://${PACKAGE_DIR}/${XML2_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${XML2_HASH_TYPE}=${XML2_HASH} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/xml2 ${DEFAULT_CMAKE_FLAGS} ${XML2_EXTRA_ARGS} + PREFIX ${BUILD_DIR}/xml2 + INSTALL_DIR ${LIBDIR}/xml2 + ) +else() + ExternalProject_Add(external_xml2 + URL file://${PACKAGE_DIR}/${XML2_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${XML2_HASH_TYPE}=${XML2_HASH} + PREFIX ${BUILD_DIR}/xml2 + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && ${CONFIGURE_COMMAND} + --prefix=${LIBDIR}/xml2 + --disable-shared + --enable-static + --with-pic + --with-python=no + --with-lzma=no + --with-zlib=no + --with-iconv=no + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && make install + INSTALL_DIR ${LIBDIR}/xml2 + ) +endif() + +if(WIN32 AND BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_xml2 after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/xml2/include ${HARVEST_TARGET}/xml2/include + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/xml2/lib/libxml2s.lib ${HARVEST_TARGET}/xml2/lib/libxml2s.lib + DEPENDEES install + ) +endif() diff --git a/build_files/build_environment/dependencies.dot b/build_files/build_environment/dependencies.dot index 7e8637fbced..bb42856c3ac 100644 --- a/build_files/build_environment/dependencies.dot +++ b/build_files/build_environment/dependencies.dot @@ -1,96 +1,114 @@ strict graph { -graph[autosize = false, size = "25.7,8.3!", resolution = 300, overlap = false, splines = false, outputorder=edgesfirst ]; - node [style=filled fillcolor=white]; - external_alembic -- external_boost; - external_alembic -- external_zlib; +graph[autosize = false, size = "25.7,8.3!", resolution = 300]; external_alembic -- external_openexr; + external_alembic -- external_imath; external_blosc -- external_zlib; external_blosc -- external_pthreads; - external_boost -- Make_Python_Environment; - external_clang -- ll; + external_boost -- external_python; + external_boost -- external_numpy; + external_dpcpp -- external_python; + external_dpcpp -- external_python_site_packages; + external_dpcpp -- external_vcintrinsics; + external_dpcpp -- external_openclheaders; + external_dpcpp -- external_icdloader; + external_dpcpp -- external_mp11; + external_dpcpp -- external_level_zero; + external_dpcpp -- external_spirvheaders; + external_embree -- external_tbb; external_ffmpeg -- external_zlib; - external_ffmpeg -- external_faad; external_ffmpeg -- external_openjpeg; external_ffmpeg -- external_xvidcore; external_ffmpeg -- external_x264; + external_ffmpeg -- external_opus; external_ffmpeg -- external_vpx; external_ffmpeg -- external_theora; external_ffmpeg -- external_vorbis; external_ffmpeg -- external_ogg; external_ffmpeg -- external_lame; + external_ffmpeg -- external_aom; external_ffmpeg -- external_zlib_mingw; - external_numpy -- Make_Python_Environment; + external_ffmpeg -- external_nasm; + external_freetype -- external_brotli; + external_freetype -- external_zlib; + external_gmpxx -- external_gmp; + external_igc_llvm -- external_igc_opencl_clang; + external_igc_spirv_translator -- external_igc_opencl_clang; + external_igc -- external_igc_vcintrinsics; + external_igc -- external_igc_llvm; + external_igc -- external_igc_opencl_clang; + external_igc -- external_igc_vcintrinsics; + external_igc -- external_igc_spirv_headers; + external_igc -- external_igc_spirv_tools; + external_igc -- external_igc_spirv_translator; + external_igc -- external_flex; + external_ispc -- ll; + external_ispc -- external_python; + external_ispc -- external_flexbison; + external_ispc -- external_flex; + ll -- external_xml2; + ll -- external_python; + external_mesa -- ll; + external_numpy -- external_python; + external_numpy -- external_python_site_packages; + external_ocloc -- external_igc; + external_ocloc -- external_gmmlib; external_opencollada -- external_xml2; - external_opencolorio -- external_boost; - external_opencolorio -- external_tinyxml; external_opencolorio -- external_yamlcpp; + external_opencolorio -- external_expat; + external_opencolorio -- external_imath; + external_opencolorio -- external_pystring; external_openexr -- external_zlib; + external_openimagedenoise -- external_tbb; + external_openimagedenoise -- external_ispc; + external_openimagedenoise -- external_python; external_openimageio -- external_png; external_openimageio -- external_zlib; external_openimageio -- external_openexr; - external_openimageio -- external_openexr; + external_openimageio -- external_imath; external_openimageio -- external_jpeg; external_openimageio -- external_boost; external_openimageio -- external_tiff; - external_openimageio -- external_opencolorio; + external_openimageio -- external_pugixml; + external_openimageio -- external_fmt; + external_openimageio -- external_robinmap; external_openimageio -- external_openjpeg; external_openimageio -- external_webp; - external_openimageio -- external_opencolorio_extra; - external_openmp -- external_clang; + external_openmp -- ll; + external_openpgl -- external_tbb; external_opensubdiv -- external_tbb; openvdb -- external_tbb; openvdb -- external_boost; - openvdb -- external_openexr; - openvdb -- external_openexr; openvdb -- external_zlib; openvdb -- external_blosc; external_osl -- external_boost; external_osl -- ll; - external_osl -- external_clang; - external_osl -- external_openexr; external_osl -- external_openexr; external_osl -- external_zlib; - external_osl -- external_flexbison; external_osl -- external_openimageio; external_osl -- external_pugixml; + external_osl -- external_flexbison; + external_osl -- external_flex; external_png -- external_zlib; - external_python_site_packages -- Make_Python_Environment; + external_python -- external_bzip2; + external_python -- external_ffi; + external_python -- external_lzma; + external_python -- external_ssl; + external_python -- external_sqlite; + external_python -- external_zlib; + external_python_site_packages -- external_python; external_sndfile -- external_ogg; external_sndfile -- external_vorbis; external_sndfile -- external_flac; external_theora -- external_vorbis; external_theora -- external_ogg; external_tiff -- external_zlib; + external_usd -- external_tbb; + external_usd -- external_boost; + external_usd -- external_opensubdiv; external_vorbis -- external_ogg; - blender-- external_ffmpeg; - blender-- external_alembic; - blender-- external_openjpeg; - blender-- external_opencolorio; - blender-- external_openexr; - blender-- external_opensubdiv; - blender-- openvdb; - blender-- external_osl; - blender-- external_boost; - blender-- external_jpeg; - blender-- external_png; - blender-- external_python; - blender-- external_sndfile; - blender-- external_iconv; - blender-- external_fftw3; - external_python-- external_python_site_packages; - external_python_site_packages-- requests; - external_python_site_packages-- idna; - external_python_site_packages-- chardet; - external_python_site_packages-- urllib3; - external_python_site_packages-- certifi; - external_python-- external_numpy; - external_usd-- external_boost; - external_usd-- external_tbb; - blender-- external_opencollada; - blender-- external_sdl; - blender-- external_freetype; - blender-- external_pthreads; - blender-- external_zlib; - blender-- external_openal; - blender-- external_usd; + external_wayland -- external_expat; + external_wayland -- external_xml2; + external_wayland -- external_ffi; + external_wayland_protocols -- external_wayland; + external_x264 -- external_nasm; } diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index f913ac5e73c..5a191f7669b 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -394,7 +394,7 @@ CLANG_FORMAT_VERSION="10.0" CLANG_FORMAT_VERSION_MIN="6.0" CLANG_FORMAT_VERSION_MEX="14.0" -PYTHON_VERSION="3.10.2" +PYTHON_VERSION="3.10.8" PYTHON_VERSION_SHORT="3.10" PYTHON_VERSION_MIN="3.10" PYTHON_VERSION_MEX="3.12" @@ -505,7 +505,7 @@ OPENEXR_FORCE_REBUILD=false OPENEXR_SKIP=false _with_built_openexr=false -OIIO_VERSION="2.3.13.0" +OIIO_VERSION="2.3.20.0" OIIO_VERSION_SHORT="2.3" OIIO_VERSION_MIN="2.1.12" OIIO_VERSION_MEX="2.4.0" @@ -523,8 +523,8 @@ LLVM_FORCE_REBUILD=false LLVM_SKIP=false # OSL needs to be compiled for now! -OSL_VERSION="1.11.17.0" -OSL_VERSION_SHORT="1.11" +OSL_VERSION="1.12.6.2" +OSL_VERSION_SHORT="1.12" OSL_VERSION_MIN="1.11" OSL_VERSION_MEX="2.0" OSL_FORCE_BUILD=false @@ -602,10 +602,10 @@ LEVEL_ZERO_FORCE_BUILD=false LEVEL_ZERO_FORCE_REBUILD=false LEVEL_ZERO_SKIP=false -OPENPGL_VERSION="0.3.1" -OPENPGL_VERSION_SHORT="0.3" +OPENPGL_VERSION="0.4.0" +OPENPGL_VERSION_SHORT="0.4" OPENPGL_VERSION_MIN="0.3.1" -OPENPGL_VERSION_MEX="0.3.2" +OPENPGL_VERSION_MEX="0.5" OPENPGL_FORCE_BUILD=false OPENPGL_FORCE_REBUILD=false OPENPGL_SKIP=false @@ -618,8 +618,8 @@ XR_OPENXR_FORCE_BUILD=false XR_OPENXR_FORCE_REBUILD=false XR_OPENXR_SKIP=false -FFMPEG_VERSION="5.0" -FFMPEG_VERSION_SHORT="5.0" +FFMPEG_VERSION="5.1.2" +FFMPEG_VERSION_SHORT="5.1" FFMPEG_VERSION_MIN="4.0" FFMPEG_VERSION_MEX="6.0" FFMPEG_FORCE_BUILD=false @@ -1139,7 +1139,7 @@ LLVM_SOURCE=( "$_LLVM_SOURCE_ROOT/llvm-$LLVM_VERSION.src.tar.xz" ) LLVM_CLANG_SOURCE=( "$_LLVM_SOURCE_ROOT/clang-$LLVM_VERSION.src.tar.xz" "$_LLVM_SOURCE_ROOT/cfe-$LLVM_VERSION.src.tar.xz" ) OSL_USE_REPO=false -OSL_SOURCE=( "https://github.com/imageworks/OpenShadingLanguage/archive/Release-$OSL_VERSION.tar.gz" ) +OSL_SOURCE=( "https://github.com/imageworks/OpenShadingLanguage/archive/v$OSL_VERSION.tar.gz" ) #~ OSL_SOURCE_REPO=( "https://github.com/imageworks/OpenShadingLanguage.git" ) #~ OSL_SOURCE_REPO_BRANCH="master" #~ OSL_SOURCE_REPO_UID="85179714e1bc69cd25ecb6bb711c1a156685d395" diff --git a/build_files/build_environment/patches/aom.diff b/build_files/build_environment/patches/aom.diff new file mode 100644 index 00000000000..1611cff5dca --- /dev/null +++ b/build_files/build_environment/patches/aom.diff @@ -0,0 +1,18 @@ +diff -Naur libaom-3.4.0/build/cmake/aom_configure.cmake external_aom/build/cmake/aom_configure.cmake +--- libaom-3.4.0/build/cmake/aom_configure.cmake 2022-06-17 11:46:18 -0600 ++++ external_aom/build/cmake/aom_configure.cmake 2022-10-16 15:35:54 -0600 +@@ -15,8 +15,12 @@ + + include(FindGit) + include(FindPerl) +-include(FindThreads) +- ++# Blender: This will drag in a dep on libwinpthreads which we prefer ++# not to have, aom will fallback on a native win32 thread wrapper ++# if pthreads are not found. ++if(NOT WIN32) ++ include(FindThreads) ++endif() + include("${AOM_ROOT}/build/cmake/aom_config_defaults.cmake") + include("${AOM_ROOT}/build/cmake/aom_experiment_deps.cmake") + include("${AOM_ROOT}/build/cmake/aom_optimization.cmake") diff --git a/build_files/build_environment/patches/ffmpeg.diff b/build_files/build_environment/patches/ffmpeg.diff index c255f7c37a3..ac104a20ffe 100644 --- a/build_files/build_environment/patches/ffmpeg.diff +++ b/build_files/build_environment/patches/ffmpeg.diff @@ -68,34 +68,18 @@ + return ret; } ---- a/libavcodec/rl.c -+++ b/libavcodec/rl.c -@@ -71,17 +71,19 @@ - av_cold void ff_rl_init_vlc(RLTable *rl, unsigned static_size) - { - int i, q; -- VLC_TYPE table[1500][2] = {{0}}; -+ VLC_TYPE (*table)[2] = av_calloc(sizeof(VLC_TYPE), 1500 * 2); - VLC vlc = { .table = table, .table_allocated = static_size }; -- av_assert0(static_size <= FF_ARRAY_ELEMS(table)); -+ av_assert0(static_size < 1500); - init_vlc(&vlc, 9, rl->n + 1, &rl->table_vlc[0][1], 4, 2, &rl->table_vlc[0][0], 4, 2, INIT_VLC_USE_NEW_STATIC); +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 @@ - for (q = 0; q < 32; q++) { - int qmul = q * 2; - int qadd = (q - 1) | 1; + %include "libavutil/x86/x86util.asm" -- if (!rl->rl_vlc[q]) -+ if (!rl->rl_vlc[q]){ -+ av_free(table); - return; -+ } +-%if ARCH_X86_32 + SECTION_RODATA - if (q == 0) { - qmul = 1; -@@ -113,4 +115,5 @@ - rl->rl_vlc[q][i].run = run; - } - } -+ av_free(table); - } ++%if ARCH_X86_32 + cextern pb_80 + + wm1010: dw 0, 0xffff, 0, 0xffff diff --git a/build_files/build_environment/patches/gmp.diff b/build_files/build_environment/patches/gmp.diff new file mode 100644 index 00000000000..bf22f93bc4f --- /dev/null +++ b/build_files/build_environment/patches/gmp.diff @@ -0,0 +1,15 @@ +--- a/mpz/inp_raw.c Tue Dec 22 23:49:51 2020 +0100 ++++ b/mpz/inp_raw.c Thu Oct 21 19:06:49 2021 +0200 +@@ -88,8 +88,11 @@ + + abs_csize = ABS (csize); + ++ if (UNLIKELY (abs_csize > ~(mp_bitcnt_t) 0 / 8)) ++ return 0; /* Bit size overflows */ ++ + /* round up to a multiple of limbs */ +- abs_xsize = BITS_TO_LIMBS (abs_csize*8); ++ abs_xsize = BITS_TO_LIMBS ((mp_bitcnt_t) abs_csize * 8); + + if (abs_xsize != 0) + { diff --git a/build_files/build_environment/patches/opencollada.diff b/build_files/build_environment/patches/opencollada.diff index e8efc1a6909..02eab251a13 100644 --- a/build_files/build_environment/patches/opencollada.diff +++ b/build_files/build_environment/patches/opencollada.diff @@ -130,3 +130,28 @@ index 715d903..24423ce 100644 { string id = node.attribute("id").value(); size_t line = node.line(); +diff -Naur a/CMakeLists.txt b/CMakeLists.txt +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -274,7 +274,7 @@ + add_subdirectory(${EXTERNAL_LIBRARIES}/UTF) + add_subdirectory(common/libBuffer) + add_subdirectory(${EXTERNAL_LIBRARIES}/MathMLSolver) +-add_subdirectory(${EXTERNAL_LIBRARIES}/zlib) ++#add_subdirectory(${EXTERNAL_LIBRARIES}/zlib) + + # building OpenCOLLADA libs + add_subdirectory(COLLADABaseUtils) +@@ -284,10 +284,10 @@ + add_subdirectory(COLLADAStreamWriter) + + # building COLLADAValidator app +-add_subdirectory(COLLADAValidator) ++#add_subdirectory(COLLADAValidator) + + # DAE validator app +-add_subdirectory(DAEValidator) ++#add_subdirectory(DAEValidator) + + # Library export + install(EXPORT LibraryExport DESTINATION ${OPENCOLLADA_INST_CMAKECONFIG} FILE OpenCOLLADATargets.cmake) diff --git a/build_files/build_environment/patches/osl.diff b/build_files/build_environment/patches/osl.diff index 28e1d6e101d..3f4a485b037 100644 --- a/build_files/build_environment/patches/osl.diff +++ b/build_files/build_environment/patches/osl.diff @@ -1,67 +1,53 @@ -diff -Naur OpenShadingLanguage-Release-1.9.9/src/include/OSL/llvm_util.h external_osl/src/include/OSL/llvm_util.h ---- OpenShadingLanguage-Release-1.9.9/src/include/OSL/llvm_util.h 2018-05-01 16:39:02 -0600 -+++ external_osl/src/include/OSL/llvm_util.h 2018-08-25 14:05:00 -0600 -@@ -33,6 +33,8 @@ - - #include <vector> - -+#define OSL_HAS_BLENDER_CLEANUP_FIX -+ - #ifdef LLVM_NAMESPACE - namespace llvm = LLVM_NAMESPACE; - #endif -@@ -487,6 +489,7 @@ - std::string func_name (llvm::Function *f); - - static size_t total_jit_memory_held (); -+ static void Cleanup (); - - private: - class MemoryManager; -diff -Naur OpenShadingLanguage-Release-1.9.9/src/liboslexec/llvm_util.cpp external_osl/src/liboslexec/llvm_util.cpp ---- OpenShadingLanguage-Release-1.9.9/src/liboslexec/llvm_util.cpp 2018-05-01 16:39:02 -0600 -+++ external_osl/src/liboslexec/llvm_util.cpp 2018-08-25 14:04:27 -0600 -@@ -140,7 +140,10 @@ - }; - - -- -+void LLVM_Util::Cleanup () -+{ -+ if(jitmm_hold) jitmm_hold->clear(); -+} - - size_t - LLVM_Util::total_jit_memory_held () -diff -Naur org/CMakeLists.txt external_osl/CMakeLists.txt ---- org/CMakeLists.txt 2020-12-01 12:37:15 -0700 -+++ external_osl/CMakeLists.txt 2021-01-20 13:26:50 -0700 -@@ -84,6 +84,11 @@ +diff -Naur OpenShadingLanguage-1.12.6.2/CMakeLists.txt external_osl/CMakeLists.txt +--- OpenShadingLanguage-1.12.6.2/CMakeLists.txt 2022-09-30 17:43:53 -0600 ++++ external_osl/CMakeLists.txt 2022-10-15 14:49:26 -0600 +@@ -101,6 +101,11 @@ CACHE STRING "Directory where OptiX PTX files will be installed") set (CMAKE_DEBUG_POSTFIX "" CACHE STRING "Library naming postfix for Debug builds (e.g., '_debug')") - + +set (USE_OIIO_STATIC ON CACHE BOOL "If OIIO is built static") +if (USE_OIIO_STATIC) + add_definitions ("-DOIIO_STATIC_BUILD=1") + add_definitions ("-DOIIO_STATIC_DEFINE=1") +endif () - + set (OSL_NO_DEFAULT_TEXTURESYSTEM OFF CACHE BOOL "Do not use create a raw OIIO::TextureSystem") if (OSL_NO_DEFAULT_TEXTURESYSTEM) -diff -Naur external_osl_orig/src/cmake/externalpackages.cmake external_osl/src/cmake/externalpackages.cmake ---- external_osl_orig/src/cmake/externalpackages.cmake 2021-06-01 13:44:18 -0600 -+++ external_osl/src/cmake/externalpackages.cmake 2021-06-28 07:44:32 -0600 -@@ -80,6 +80,7 @@ - - +diff -Naur OpenShadingLanguage-1.12.6.2/src/cmake/externalpackages.cmake external_osl/src/cmake/externalpackages.cmake +--- OpenShadingLanguage-1.12.6.2/src/cmake/externalpackages.cmake 2022-09-30 17:43:53 -0600 ++++ external_osl/src/cmake/externalpackages.cmake 2022-10-15 14:49:26 -0600 +@@ -77,6 +77,7 @@ + + checked_find_package (ZLIB REQUIRED) # Needed by several packages +checked_find_package (PNG REQUIRED) # Needed since OIIO needs it - + # IlmBase & OpenEXR checked_find_package (OpenEXR REQUIRED -diff -Naur external_osl_orig/src/liboslcomp/oslcomp.cpp external_osl/src/liboslcomp/oslcomp.cpp ---- external_osl_orig/src/liboslcomp/oslcomp.cpp 2021-06-01 13:44:18 -0600 -+++ external_osl/src/liboslcomp/oslcomp.cpp 2021-06-28 09:11:06 -0600 +diff -Naur OpenShadingLanguage-1.12.6.2/src/include/OSL/llvm_util.h external_osl/src/include/OSL/llvm_util.h +--- OpenShadingLanguage-1.12.6.2/src/include/OSL/llvm_util.h 2022-09-30 17:43:53 -0600 ++++ external_osl/src/include/OSL/llvm_util.h 2022-10-15 15:37:24 -0600 +@@ -9,6 +9,8 @@ + #include <unordered_set> + #include <vector> + ++#define OSL_HAS_BLENDER_CLEANUP_FIX ++ + #ifdef LLVM_NAMESPACE + namespace llvm = LLVM_NAMESPACE; + #endif +@@ -455,7 +457,7 @@ + llvm::BasicBlock* masked_return_block() const; + + bool is_masking_required() const { return m_is_masking_required; } +- ++ static void Cleanup (); + struct ScopedMasking { + ScopedMasking() {} + +diff -Naur OpenShadingLanguage-1.12.6.2/src/liboslcomp/oslcomp.cpp external_osl/src/liboslcomp/oslcomp.cpp +--- OpenShadingLanguage-1.12.6.2/src/liboslcomp/oslcomp.cpp 2022-09-30 17:43:53 -0600 ++++ external_osl/src/liboslcomp/oslcomp.cpp 2022-10-15 14:49:26 -0600 @@ -21,6 +21,13 @@ #if !defined(__STDC_CONSTANT_MACROS) # define __STDC_CONSTANT_MACROS 1 @@ -76,3 +62,50 @@ diff -Naur external_osl_orig/src/liboslcomp/oslcomp.cpp external_osl/src/liboslc #include <clang/Basic/TargetInfo.h> #include <clang/Frontend/CompilerInstance.h> #include <clang/Frontend/TextDiagnosticPrinter.h> +diff -Naur OpenShadingLanguage-1.12.6.2/src/liboslexec/llvm_util.cpp external_osl/src/liboslexec/llvm_util.cpp +--- OpenShadingLanguage-1.12.6.2/src/liboslexec/llvm_util.cpp 2022-09-30 17:43:53 -0600 ++++ external_osl/src/liboslexec/llvm_util.cpp 2022-10-15 15:53:11 -0600 +@@ -116,8 +116,6 @@ + return { A.data(), size_t(A.size()) }; + } + +- +- + namespace pvt { + + typedef llvm::SectionMemoryManager LLVMMemoryManager; +@@ -182,6 +180,13 @@ + ++jit_mem_hold_users; + } + ++void ++LLVM_Util::Cleanup() ++{ ++ if (jitmm_hold) ++ jitmm_hold->clear(); ++} ++ + + LLVM_Util::ScopedJitMemoryUser::~ScopedJitMemoryUser() + { +diff --git a/src/include/OSL/mask.h b/src/include/OSL/mask.h +index 24197af..b9275f6 100644 +--- a/src/include/OSL/mask.h ++++ b/src/include/OSL/mask.h +@@ -4,7 +4,6 @@ + + #pragma once + +-#include <immintrin.h> + #include <type_traits> + + #include <OSL/oslconfig.h> +@@ -23,6 +22,8 @@ using std::countr_zero; + + #elif OSL_INTEL_CLASSIC_COMPILER_VERSION + ++#include <immintrin.h> ++ + OSL_FORCEINLINE int popcount(uint32_t x) noexcept { return _mm_popcnt_u32(x);} + OSL_FORCEINLINE int popcount(uint64_t x) noexcept { return _mm_popcnt_u64(x); } + OSL_FORCEINLINE int countr_zero(uint32_t x) noexcept { return _bit_scan_forward(x); } diff --git a/build_files/build_environment/patches/python_windows.diff b/build_files/build_environment/patches/python_windows.diff deleted file mode 100644 index f9c89a90fde..00000000000 --- a/build_files/build_environment/patches/python_windows.diff +++ /dev/null @@ -1,24 +0,0 @@ -diff -Naur orig/PCbuild/get_externals.bat Python-3.10.2/PCbuild/get_externals.bat ---- orig/PCbuild/get_externals.bat 2022-01-13 11:52:14 -0700 -+++ Python-3.10.2/PCbuild/get_externals.bat 2022-08-17 11:24:42 -0600 -@@ -51,7 +51,7 @@ - echo.Fetching external libraries... - - set libraries= --set libraries=%libraries% bzip2-1.0.6 -+set libraries=%libraries% bzip2-1.0.8 - if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.3.0 - if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1m - set libraries=%libraries% sqlite-3.35.5.0 - diff -Naur orig/PCbuild/python.props external_python/PCbuild/python.props ---- orig/PCbuild/python.props 2022-01-13 11:52:14 -0700 -+++ external_python/PCbuild/python.props 2022-08-17 11:38:38 -0600 -@@ -58,7 +58,7 @@ - <ExternalsDir Condition="$(ExternalsDir) == ''">$([System.IO.Path]::GetFullPath(`$(PySourcePath)externals`))</ExternalsDir> - <ExternalsDir Condition="!HasTrailingSlash($(ExternalsDir))">$(ExternalsDir)\</ExternalsDir> - <sqlite3Dir>$(ExternalsDir)sqlite-3.35.5.0\</sqlite3Dir> -- <bz2Dir>$(ExternalsDir)bzip2-1.0.6\</bz2Dir> -+ <bz2Dir>$(ExternalsDir)bzip2-1.0.8\</bz2Dir> - <lzmaDir>$(ExternalsDir)xz-5.2.2\</lzmaDir> - <libffiDir>$(ExternalsDir)libffi-3.3.0\</libffiDir> - <libffiOutDir>$(ExternalsDir)libffi-3.3.0\$(ArchName)\</libffiOutDir> diff --git a/build_files/build_environment/patches/sndfile.diff b/build_files/build_environment/patches/sndfile.diff deleted file mode 100644 index ab43baa78df..00000000000 --- a/build_files/build_environment/patches/sndfile.diff +++ /dev/null @@ -1,42 +0,0 @@ ---- src/Makefile.in 2017-09-26 01:28:47.000000000 +0300 -+++ src/Makefile.in 2017-09-26 01:19:06.000000000 +0300 -@@ -513,7 +513,7 @@ - libcommon_la_SOURCES = common.c file_io.c command.c pcm.c ulaw.c alaw.c \ - float32.c double64.c ima_adpcm.c ms_adpcm.c gsm610.c dwvw.c vox_adpcm.c \ - interleave.c strings.c dither.c cart.c broadcast.c audio_detect.c \ -- ima_oki_adpcm.c ima_oki_adpcm.h alac.c chunk.c ogg.c chanmap.c \ -+ ima_oki_adpcm.c ima_oki_adpcm.h alac.c chunk.c ogg.c chanmap.c \ - windows.c id3.c $(WIN_VERSION_FILE) - - -@@ -719,10 +719,10 @@ - $(AM_V_CCLD)$(LINK) $(GSM610_libgsm_la_OBJECTS) $(GSM610_libgsm_la_LIBADD) $(LIBS) - - libcommon.la: $(libcommon_la_OBJECTS) $(libcommon_la_DEPENDENCIES) $(EXTRA_libcommon_la_DEPENDENCIES) -- $(AM_V_CCLD)$(LINK) $(libcommon_la_OBJECTS) $(libcommon_la_LIBADD) $(LIBS) -+ $(AM_V_CCLD)$(LINK) $(libcommon_la_OBJECTS) $(libcommon_la_LIBADD) $(LIBS) $(EXTERNAL_XIPH_LIBS) - - libsndfile.la: $(libsndfile_la_OBJECTS) $(libsndfile_la_DEPENDENCIES) $(EXTRA_libsndfile_la_DEPENDENCIES) -- $(AM_V_CCLD)$(libsndfile_la_LINK) -rpath $(libdir) $(libsndfile_la_OBJECTS) $(libsndfile_la_LIBADD) $(LIBS) -+ $(AM_V_CCLD)$(libsndfile_la_LINK) -rpath $(libdir) $(libsndfile_la_OBJECTS) $(libsndfile_la_LIBADD) $(LIBS) $(EXTERNAL_XIPH_LIBS) - - clean-checkPROGRAMS: - @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ -@@ -924,7 +924,7 @@ - @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) -c -o libsndfile_la-dwd.lo `test -f 'dwd.c' || echo '$(srcdir)/'`dwd.c - - libsndfile_la-flac.lo: flac.c --@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) -MT libsndfile_la-flac.lo -MD -MP -MF $(DEPDIR)/libsndfile_la-flac.Tpo -c -o libsndfile_la-flac.lo `test -f 'flac.c' || echo '$(srcdir)/'`flac.c -+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) $(EXTERNAL_XIPH_CFLAGS) -MT libsndfile_la-flac.lo -MD -MP -MF $(DEPDIR)/libsndfile_la-flac.Tpo -c -o libsndfile_la-flac.lo `test -f 'flac.c' || echo '$(srcdir)/'`flac.c - @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsndfile_la-flac.Tpo $(DEPDIR)/libsndfile_la-flac.Plo - @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='flac.c' object='libsndfile_la-flac.lo' libtool=yes @AMDEPBACKSLASH@ - @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@@ -1092,7 +1092,7 @@ - @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) -c -o libsndfile_la-rf64.lo `test -f 'rf64.c' || echo '$(srcdir)/'`rf64.c - - libsndfile_la-ogg_vorbis.lo: ogg_vorbis.c --@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) -MT libsndfile_la-ogg_vorbis.lo -MD -MP -MF $(DEPDIR)/libsndfile_la-ogg_vorbis.Tpo -c -o libsndfile_la-ogg_vorbis.lo `test -f 'ogg_vorbis.c' || echo '$(srcdir)/'`ogg_vorbis.c -+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) $(EXTERNAL_XIPH_CFLAGS) -MT libsndfile_la-ogg_vorbis.lo -MD -MP -MF $(DEPDIR)/libsndfile_la-ogg_vorbis.Tpo -c -o libsndfile_la-ogg_vorbis.lo `test -f 'ogg_vorbis.c' || echo '$(srcdir)/'`ogg_vorbis.c - @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsndfile_la-ogg_vorbis.Tpo $(DEPDIR)/libsndfile_la-ogg_vorbis.Plo - @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ogg_vorbis.c' object='libsndfile_la-ogg_vorbis.lo' libtool=yes @AMDEPBACKSLASH@ - @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ diff --git a/build_files/build_environment/patches/sqlite.diff b/build_files/build_environment/patches/sqlite.diff deleted file mode 100644 index 80f1384f9cf..00000000000 --- a/build_files/build_environment/patches/sqlite.diff +++ /dev/null @@ -1,14 +0,0 @@ -Only in external_sqlite_orig: config.log -diff -ru external_sqlite_orig/config.sub external_sqlite/config.sub ---- external_sqlite_orig/config.sub 2020-07-10 14:06:42.000000000 +0200 -+++ external_sqlite/config.sub 2020-07-10 14:10:24.000000000 +0200 -@@ -314,6 +314,7 @@ - # Recognize the basic CPU types with company name. - 580-* \ - | a29k-* \ -+ | aarch64-* \ - | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ - | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ - | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ -Only in external_sqlite: mksourceid -Only in external_sqlite: sqlite3session.h diff --git a/build_files/build_environment/patches/ssl.diff b/build_files/build_environment/patches/ssl.diff new file mode 100644 index 00000000000..7bb4413952c --- /dev/null +++ b/build_files/build_environment/patches/ssl.diff @@ -0,0 +1,10 @@ +--- ./test/v3ext.c 2022-07-05 11:08:33.000000000 +0200 ++++ ./test/v3ext.c 2022-10-18 13:58:05.000000000 +0200 +@@ -8,6 +8,7 @@ + */ + + #include <stdio.h> ++#include <string.h> + #include <openssl/x509.h> + #include <openssl/x509v3.h> + #include <openssl/pem.h> diff --git a/build_files/cmake/Modules/FindOSL.cmake b/build_files/cmake/Modules/FindOSL.cmake index ab5de53d3c9..a8d8344ae66 100644 --- a/build_files/cmake/Modules/FindOSL.cmake +++ b/build_files/cmake/Modules/FindOSL.cmake @@ -20,6 +20,7 @@ IF(NOT OSL_ROOT_DIR AND NOT $ENV{OSL_ROOT_DIR} STREQUAL "") ENDIF() SET(_osl_FIND_COMPONENTS + oslnoise oslcomp oslexec oslquery @@ -39,7 +40,6 @@ FIND_PATH(OSL_INCLUDE_DIR include ) -SET(_osl_LIBRARIES) FOREACH(COMPONENT ${_osl_FIND_COMPONENTS}) STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT) @@ -51,9 +51,20 @@ FOREACH(COMPONENT ${_osl_FIND_COMPONENTS}) PATH_SUFFIXES lib64 lib ) - LIST(APPEND _osl_LIBRARIES "${OSL_${UPPERCOMPONENT}_LIBRARY}") ENDFOREACH() +# Note linking order matters, and oslnoise existence depends on version. +SET(_osl_LIBRARIES ${OSL_OSLCOMP_LIBRARY}) +IF(APPLE) + list(APPEND _osl_LIBRARIES -force_load ${OSL_OSLEXEC_LIBRARY}) +ELSE() + list(APPEND _osl_LIBRARIES ${OSL_OSLEXEC_LIBRARY}) +ENDIF() +list(APPEND _osl_LIBRARIES ${OSL_OSLQUERY_LIBRARY}) +IF(OSL_OSLNOISE_LIBRARY) + list(APPEND _osl_LIBRARIES ${OSL_OSLNOISE_LIBRARY}) +ENDIF() + FIND_PROGRAM(OSL_COMPILER oslc HINTS ${_osl_SEARCH_DIRS} PATH_SUFFIXES bin) diff --git a/build_files/cmake/Modules/FindOpenSubdiv.cmake b/build_files/cmake/Modules/FindOpenSubdiv.cmake index 37a2cddf3de..66d3b435c46 100644 --- a/build_files/cmake/Modules/FindOpenSubdiv.cmake +++ b/build_files/cmake/Modules/FindOpenSubdiv.cmake @@ -71,21 +71,6 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenSubdiv DEFAULT_MSG IF(OPENSUBDIV_FOUND) SET(OPENSUBDIV_LIBRARIES ${_opensubdiv_LIBRARIES}) SET(OPENSUBDIV_INCLUDE_DIRS ${OPENSUBDIV_INCLUDE_DIR}) - - # Find available compute controllers. - - FIND_PACKAGE(OpenMP) - IF(OPENMP_FOUND) - SET(OPENSUBDIV_HAS_OPENMP TRUE) - ELSE() - SET(OPENSUBDIV_HAS_OPENMP FALSE) - ENDIF() - - OPENSUBDIV_CHECK_CONTROLLER("tbbEvaluator.h" OPENSUBDIV_HAS_TBB) - OPENSUBDIV_CHECK_CONTROLLER("clEvaluator.h" OPENSUBDIV_HAS_OPENCL) - OPENSUBDIV_CHECK_CONTROLLER("cudaEvaluator.h" OPENSUBDIV_HAS_CUDA) - OPENSUBDIV_CHECK_CONTROLLER("glXFBEvaluator.h" OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK) - OPENSUBDIV_CHECK_CONTROLLER("glComputeEvaluator.h" OPENSUBDIV_HAS_GLSL_COMPUTE) ENDIF() MARK_AS_ADVANCED( diff --git a/build_files/cmake/Modules/FindSYCL.cmake b/build_files/cmake/Modules/FindSYCL.cmake index 139ebad46b1..1ccbee179fb 100644 --- a/build_files/cmake/Modules/FindSYCL.cmake +++ b/build_files/cmake/Modules/FindSYCL.cmake @@ -30,6 +30,7 @@ SET(_sycl_search_dirs # dpcpp binary. FIND_PROGRAM(SYCL_COMPILER NAMES + icpx dpcpp clang++ HINTS @@ -45,6 +46,7 @@ FIND_PROGRAM(SYCL_COMPILER if(NOT SYCL_COMPILER) FIND_PROGRAM(SYCL_COMPILER NAMES + icpx dpcpp HINTS ${_sycl_search_dirs} @@ -55,6 +57,8 @@ endif() FIND_LIBRARY(SYCL_LIBRARY NAMES + sycl7 + sycl6 sycl HINTS ${_sycl_search_dirs} @@ -63,34 +67,51 @@ FIND_LIBRARY(SYCL_LIBRARY ) if(WIN32) - string(REPLACE ".lib" "d.lib" SYCL_LIBRARY_DEBUG ${SYCL_LIBRARY}) - set(SYCL_LIBRARY_DEBUG ${SYCL_LIBRARY_DEBUG} CACHE FILEPATH "Path to SYCL debug library") -else() - set(SYCL_LIBRARY_DEBUG ${SYCL_LIBRARY} CACHE FILEPATH "Path to SYCL debug library") + FIND_LIBRARY(SYCL_LIBRARY_DEBUG + NAMES + sycl7d + sycl6d + sycld + HINTS + ${_sycl_search_dirs} + PATH_SUFFIXES + lib64 lib + ) endif() FIND_PATH(SYCL_INCLUDE_DIR NAMES - CL/sycl.hpp + sycl/sycl.hpp HINTS ${_sycl_search_dirs} PATH_SUFFIXES include - include/sycl ) +IF(EXISTS "${SYCL_INCLUDE_DIR}/sycl/version.hpp") + FILE(STRINGS "${SYCL_INCLUDE_DIR}/sycl/version.hpp" _libsycl_major_version REGEX "^#define __LIBSYCL_MAJOR_VERSION[ \t].*$") + STRING(REGEX MATCHALL "[0-9]+" _libsycl_major_version ${_libsycl_major_version}) + FILE(STRINGS "${SYCL_INCLUDE_DIR}/sycl/version.hpp" _libsycl_minor_version REGEX "^#define __LIBSYCL_MINOR_VERSION[ \t].*$") + STRING(REGEX MATCHALL "[0-9]+" _libsycl_minor_version ${_libsycl_minor_version}) + FILE(STRINGS "${SYCL_INCLUDE_DIR}/sycl/version.hpp" _libsycl_patch_version REGEX "^#define __LIBSYCL_PATCH_VERSION[ \t].*$") + STRING(REGEX MATCHALL "[0-9]+" _libsycl_patch_version ${_libsycl_patch_version}) + + SET(SYCL_VERSION "${_libsycl_major_version}.${_libsycl_minor_version}.${_libsycl_patch_version}") +ENDIF() + INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(SYCL DEFAULT_MSG SYCL_LIBRARY SYCL_INCLUDE_DIR) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SYCL + REQUIRED_VARS SYCL_LIBRARY SYCL_INCLUDE_DIR + VERSION_VAR SYCL_VERSION +) IF(SYCL_FOUND) - get_filename_component(_SYCL_INCLUDE_PARENT_DIR ${SYCL_INCLUDE_DIR} DIRECTORY) - SET(SYCL_INCLUDE_DIR ${SYCL_INCLUDE_DIR} ${_SYCL_INCLUDE_PARENT_DIR}) + SET(SYCL_INCLUDE_DIR ${SYCL_INCLUDE_DIR} ${SYCL_INCLUDE_DIR}/sycl) ELSE() SET(SYCL_SYCL_FOUND FALSE) ENDIF() MARK_AS_ADVANCED( _SYCL_INCLUDE_PARENT_DIR - SYCL_LIBRARY_DEBUG ) diff --git a/build_files/cmake/config/blender_full.cmake b/build_files/cmake/config/blender_full.cmake index 958eb17522b..95304bd64c7 100644 --- a/build_files/cmake/config/blender_full.cmake +++ b/build_files/cmake/config/blender_full.cmake @@ -66,13 +66,11 @@ set(WITH_MEM_JEMALLOC ON CACHE BOOL "" FORCE) if(APPLE) set(WITH_COREAUDIO ON CACHE BOOL "" FORCE) endif() -if(NOT WIN32) - set(WITH_JACK ON CACHE BOOL "" FORCE) -endif() if(WIN32) set(WITH_WASAPI ON CACHE BOOL "" FORCE) endif() if(UNIX AND NOT APPLE) + set(WITH_JACK ON CACHE BOOL "" FORCE) set(WITH_DOC_MANPAGE ON CACHE BOOL "" FORCE) set(WITH_GHOST_XDND ON CACHE BOOL "" FORCE) set(WITH_PULSEAUDIO ON CACHE BOOL "" FORCE) diff --git a/build_files/cmake/config/blender_release.cmake b/build_files/cmake/config/blender_release.cmake index d5f5230862b..74bbcb223c3 100644 --- a/build_files/cmake/config/blender_release.cmake +++ b/build_files/cmake/config/blender_release.cmake @@ -67,13 +67,11 @@ if(APPLE) set(WITH_COREAUDIO ON CACHE BOOL "" FORCE) set(WITH_CYCLES_DEVICE_METAL ON CACHE BOOL "" FORCE) endif() -if(NOT WIN32) - set(WITH_JACK ON CACHE BOOL "" FORCE) -endif() if(WIN32) set(WITH_WASAPI ON CACHE BOOL "" FORCE) endif() if(UNIX AND NOT APPLE) + set(WITH_JACK ON CACHE BOOL "" FORCE) set(WITH_DOC_MANPAGE ON CACHE BOOL "" FORCE) set(WITH_GHOST_XDND ON CACHE BOOL "" FORCE) set(WITH_PULSEAUDIO ON CACHE BOOL "" FORCE) diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index 3acea19079b..8af45690862 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -1205,11 +1205,27 @@ macro(set_and_warn_dependency _dependency _setting _val) # when $_dependency is disabled, forces $_setting = $_val if(NOT ${${_dependency}} AND ${${_setting}}) - message(STATUS "'${_dependency}' is disabled: forcing 'set(${_setting} ${_val})'") + if(WITH_STRICT_BUILD_OPTIONS) + message(SEND_ERROR "${_dependency} disabled but required by ${_setting}") + else() + message(STATUS "${_dependency} is disabled, setting ${_setting}=${_val}") + endif() set(${_setting} ${_val}) endif() endmacro() +macro(set_and_warn_library_found + _library_name _library_found _setting) + if(NOT ${${_library_found}} AND ${${_setting}}) + if(WITH_STRICT_BUILD_OPTIONS) + message(SEND_ERROR "${_library_name} required but not found") + else() + message(STATUS "${_library_name} not found, disabling ${_setting}") + endif() + set(${_setting} OFF) + endif() +endmacro() + macro(without_system_libs_begin) set(CMAKE_IGNORE_PATH "${CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES};${CMAKE_SYSTEM_INCLUDE_PATH};${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES};${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}") endmacro() diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake index 04f5a312030..c5fe3c908de 100644 --- a/build_files/cmake/platform/platform_apple.cmake +++ b/build_files/cmake/platform/platform_apple.cmake @@ -43,22 +43,18 @@ find_package(BZip2 REQUIRED) list(APPEND ZLIB_LIBRARIES ${BZIP2_LIBRARIES}) if(WITH_OPENAL) - find_package(OpenAL) - if(NOT OPENAL_FOUND) - message(WARNING "OpenAL not found, disabling WITH_OPENAL") - set(WITH_OPENAL OFF) - endif() + find_package(OpenAL REQUIRED) endif() if(WITH_JACK) find_library(JACK_FRAMEWORK NAMES jackmp ) - if(NOT JACK_FRAMEWORK) - message(STATUS "JACK not found, disabling WITH_JACK") - set(WITH_JACK OFF) - else() + + if(JACK_FRAMEWORK) set(JACK_INCLUDE_DIRS ${JACK_FRAMEWORK}/headers) + else() + set_and_warn_library_found("JACK" JACK_FRAMEWORK WITH_JACK) endif() endif() @@ -101,11 +97,7 @@ if(WITH_ALEMBIC) endif() if(WITH_USD) - find_package(USD) - if(NOT USD_FOUND) - message(STATUS "USD not found, disabling WITH_USD") - set(WITH_USD OFF) - endif() + find_package(USD REQUIRED) endif() if(WITH_OPENSUBDIV) @@ -227,20 +219,12 @@ find_package(JPEG REQUIRED) if(WITH_IMAGE_TIFF) set(TIFF_ROOT ${LIBDIR}/tiff) - find_package(TIFF) - if(NOT TIFF_FOUND) - message(WARNING "TIFF not found, disabling WITH_IMAGE_TIFF") - set(WITH_IMAGE_TIFF OFF) - endif() + find_package(TIFF REQUIRED) endif() if(WITH_IMAGE_WEBP) set(WEBP_ROOT_DIR ${LIBDIR}/webp) - find_package(WebP) - if(NOT WEBP_FOUND) - message(WARNING "WebP not found, disabling WITH_IMAGE_WEBP") - set(WITH_IMAGE_WEBP OFF) - endif() + find_package(WebP REQUIRED) endif() if(WITH_BOOST) @@ -270,11 +254,7 @@ if(WITH_INTERNATIONAL OR WITH_CODEC_FFMPEG) endif() if(WITH_PUGIXML) - find_package(PugiXML) - if(NOT PUGIXML_FOUND) - message(WARNING "PugiXML not found, disabling WITH_PUGIXML") - set(WITH_PUGIXML OFF) - endif() + find_package(PugiXML REQUIRED) endif() if(WITH_OPENIMAGEIO) @@ -292,12 +272,7 @@ if(WITH_OPENIMAGEIO) endif() if(WITH_OPENCOLORIO) - find_package(OpenColorIO 2.0.0) - - if(NOT OPENCOLORIO_FOUND) - set(WITH_OPENCOLORIO OFF) - message(STATUS "OpenColorIO not found, disabling WITH_OPENCOLORIO") - endif() + find_package(OpenColorIO 2.0.0 REQUIRED) endif() if(WITH_OPENVDB) @@ -331,23 +306,7 @@ if(WITH_LLVM) endif() if(WITH_CYCLES AND WITH_CYCLES_OSL) - set(CYCLES_OSL ${LIBDIR}/osl) - - find_library(OSL_LIB_EXEC NAMES oslexec PATHS ${CYCLES_OSL}/lib) - find_library(OSL_LIB_COMP NAMES oslcomp PATHS ${CYCLES_OSL}/lib) - find_library(OSL_LIB_QUERY NAMES oslquery PATHS ${CYCLES_OSL}/lib) - # WARNING! depends on correct order of OSL libs linking - list(APPEND OSL_LIBRARIES ${OSL_LIB_COMP} -force_load ${OSL_LIB_EXEC} ${OSL_LIB_QUERY}) - find_path(OSL_INCLUDE_DIR OSL/oslclosure.h PATHS ${CYCLES_OSL}/include) - find_program(OSL_COMPILER NAMES oslc PATHS ${CYCLES_OSL}/bin) - find_path(OSL_SHADER_DIR NAMES stdosl.h PATHS ${CYCLES_OSL}/share/OSL/shaders) - - if(OSL_INCLUDE_DIR AND OSL_LIBRARIES AND OSL_COMPILER AND OSL_SHADER_DIR) - set(OSL_FOUND TRUE) - else() - message(WARNING "OSL not found, disabling WITH_CYCLES_OSL") - set(WITH_CYCLES_OSL OFF) - endif() + find_package(OSL REQUIRED) endif() if(WITH_CYCLES AND WITH_CYCLES_EMBREE) @@ -365,28 +324,15 @@ if(WITH_CYCLES AND WITH_CYCLES_EMBREE) endif() if(WITH_OPENIMAGEDENOISE) - find_package(OpenImageDenoise) - - if(NOT OPENIMAGEDENOISE_FOUND) - set(WITH_OPENIMAGEDENOISE OFF) - message(STATUS "OpenImageDenoise not found, disabling WITH_OPENIMAGEDENOISE") - endif() + find_package(OpenImageDenoise REQUIRED) endif() if(WITH_TBB) - find_package(TBB) - if(NOT TBB_FOUND) - message(WARNING "TBB not found, disabling WITH_TBB") - set(WITH_TBB OFF) - endif() + find_package(TBB REQUIRED) endif() if(WITH_POTRACE) - find_package(Potrace) - if(NOT POTRACE_FOUND) - message(WARNING "potrace not found, disabling WITH_POTRACE") - set(WITH_POTRACE OFF) - endif() + find_package(Potrace REQUIRED) endif() # CMake FindOpenMP doesn't know about AppleClang before 3.12, so provide custom flags. @@ -406,27 +352,15 @@ if(WITH_OPENMP) endif() if(WITH_XR_OPENXR) - find_package(XR_OpenXR_SDK) - if(NOT XR_OPENXR_SDK_FOUND) - message(WARNING "OpenXR-SDK was not found, disabling WITH_XR_OPENXR") - set(WITH_XR_OPENXR OFF) - endif() + find_package(XR_OpenXR_SDK REQUIRED) endif() if(WITH_GMP) - find_package(GMP) - if(NOT GMP_FOUND) - message(WARNING "GMP not found, disabling WITH_GMP") - set(WITH_GMP OFF) - endif() + find_package(GMP REQUIRED) endif() if(WITH_HARU) - find_package(Haru) - if(NOT HARU_FOUND) - message(WARNING "Haru not found, disabling WITH_HARU") - set(WITH_HARU OFF) - endif() + find_package(Haru REQUIRED) endif() if(WITH_CYCLES AND WITH_CYCLES_PATH_GUIDING) diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index 695ea3d773e..424926afe39 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -174,32 +174,24 @@ endif() if(WITH_IMAGE_OPENEXR) find_package_wrapper(OpenEXR) # our own module - if(NOT OPENEXR_FOUND) - set(WITH_IMAGE_OPENEXR OFF) - endif() + set_and_warn_library_found("OpenEXR" OPENEXR_FOUND WITH_IMAGE_OPENEXR) endif() if(WITH_IMAGE_OPENJPEG) find_package_wrapper(OpenJPEG) - if(NOT OPENJPEG_FOUND) - set(WITH_IMAGE_OPENJPEG OFF) - endif() + set_and_warn_library_found("OpenJPEG" OPENJPEG_FOUND WITH_IMAGE_OPENJPEG) endif() if(WITH_IMAGE_TIFF) # XXX Linking errors with debian static tiff :/ # find_package_wrapper(TIFF) find_package(TIFF) - if(NOT TIFF_FOUND) - set(WITH_IMAGE_TIFF OFF) - endif() + set_and_warn_library_found("TIFF" TIFF_FOUND WITH_IMAGE_TIFF) endif() if(WITH_OPENAL) find_package_wrapper(OpenAL) - if(NOT OPENAL_FOUND) - set(WITH_OPENAL OFF) - endif() + set_and_warn_library_found("OpenAL" OPENAL_FOUND WITH_OPENAL) endif() if(WITH_SDL) @@ -221,18 +213,14 @@ if(WITH_SDL) SDL_LIBRARY ) # unset(SDLMAIN_LIBRARY CACHE) - if(NOT SDL_FOUND) - set(WITH_SDL OFF) - endif() + set_and_warn_library_found("SDL" SDL_FOUND WITH_SDL) endif() endif() # Codecs if(WITH_CODEC_SNDFILE) find_package_wrapper(SndFile) - if(NOT SNDFILE_FOUND) - set(WITH_CODEC_SNDFILE OFF) - endif() + set_and_warn_library_found("libsndfile" SNDFILE_FOUND WITH_CODEC_SNDFILE) endif() if(WITH_CODEC_FFMPEG) @@ -260,17 +248,12 @@ if(WITH_CODEC_FFMPEG) endif() find_package(FFmpeg) - if(NOT FFMPEG_FOUND) - set(WITH_CODEC_FFMPEG OFF) - message(STATUS "FFmpeg not found, disabling it") - endif() + set_and_warn_library_found("FFmpeg" FFMPEG_FOUND WITH_CODEC_FFMPEG) endif() if(WITH_FFTW3) find_package_wrapper(Fftw3) - if(NOT FFTW3_FOUND) - set(WITH_FFTW3 OFF) - endif() + set_and_warn_library_found("fftw3" FFTW3_FOUND WITH_FFTW3) endif() if(WITH_OPENCOLLADA) @@ -285,25 +268,23 @@ if(WITH_OPENCOLLADA) endif() find_package_wrapper(XML2) else() - set(WITH_OPENCOLLADA OFF) + set_and_warn_library_found("OpenCollada" OPENCOLLADA_FOUND WITH_OPENCOLLADA) endif() endif() if(WITH_MEM_JEMALLOC) find_package_wrapper(JeMalloc) - if(NOT JEMALLOC_FOUND) - set(WITH_MEM_JEMALLOC OFF) - endif() + set_and_warn_library_found("JeMalloc" JEMALLOC_FOUND WITH_MEM_JEMALLOC) endif() if(WITH_INPUT_NDOF) find_package_wrapper(Spacenav) + set_and_warn_library_found("SpaceNav" SPACENAV_FOUND WITH_INPUT_NDOF) + if(SPACENAV_FOUND) # use generic names within blenders buildsystem. set(NDOF_INCLUDE_DIRS ${SPACENAV_INCLUDE_DIRS}) set(NDOF_LIBRARIES ${SPACENAV_LIBRARIES}) - else() - set(WITH_INPUT_NDOF OFF) endif() endif() @@ -313,6 +294,8 @@ if(WITH_CYCLES AND WITH_CYCLES_OSL) set(OSL_ROOT ${CYCLES_OSL}) endif() find_package_wrapper(OSL) + set_and_warn_library_found("OSL" OSL_FOUND WITH_CYCLES_OSL) + if(OSL_FOUND) if(${OSL_LIBRARY_VERSION_MAJOR} EQUAL "1" AND ${OSL_LIBRARY_VERSION_MINOR} LESS "6") # Note: --whole-archive is needed to force loading of all symbols in liboslexec, @@ -323,9 +306,6 @@ if(WITH_CYCLES AND WITH_CYCLES_OSL) -Wl,--no-whole-archive ${OSL_OSLQUERY_LIBRARY} ) endif() - else() - message(STATUS "OSL not found, disabling it from Cycles") - set(WITH_CYCLES_OSL OFF) endif() endif() @@ -341,35 +321,27 @@ if(WITH_CYCLES AND WITH_CYCLES_DEVICE_ONEAPI) endif() file(GLOB _sycl_runtime_libraries ${SYCL_ROOT_DIR}/lib/libsycl.so - ${SYCL_ROOT_DIR}/lib/libsycl.so.[0-9] - ${SYCL_ROOT_DIR}/lib/libsycl.so.[0-9].[0-9].[0-9]-[0-9] + ${SYCL_ROOT_DIR}/lib/libsycl.so.* ${SYCL_ROOT_DIR}/lib/libpi_level_zero.so ) + list(FILTER _sycl_runtime_libraries EXCLUDE REGEX ".*\.py") list(APPEND PLATFORM_BUNDLED_LIBRARIES ${_sycl_runtime_libraries}) unset(_sycl_runtime_libraries) endif() if(WITH_OPENVDB) find_package_wrapper(OpenVDB) - find_package_wrapper(Blosc) - - if(NOT OPENVDB_FOUND) - set(WITH_OPENVDB OFF) - set(WITH_OPENVDB_BLOSC OFF) - message(STATUS "OpenVDB not found, disabling it") - elseif(NOT BLOSC_FOUND) - set(WITH_OPENVDB_BLOSC OFF) - message(STATUS "Blosc not found, disabling it for OpenVBD") + set_and_warn_library_found("OpenVDB" OPENVDB_FOUND WITH_OPENVDB) + + if(OPENVDB_FOUND) + find_package_wrapper(Blosc) + set_and_warn_library_found("Blosc" BLOSC_FOUND WITH_OPENVDB_BLOSC) endif() endif() if(WITH_NANOVDB) find_package_wrapper(NanoVDB) - - if(NOT NANOVDB_FOUND) - set(WITH_NANOVDB OFF) - message(STATUS "NanoVDB not found, disabling it") - endif() + set_and_warn_library_found("NanoVDB" NANOVDB_FOUND WITH_NANOVDB) endif() if(WITH_CPU_SIMD AND SUPPORT_NEON_BUILD) @@ -378,18 +350,12 @@ endif() if(WITH_ALEMBIC) find_package_wrapper(Alembic) - - if(NOT ALEMBIC_FOUND) - set(WITH_ALEMBIC OFF) - endif() + set_and_warn_library_found("Alembic" ALEMBIC_FOUND WITH_ALEMBIC) endif() if(WITH_USD) find_package_wrapper(USD) - - if(NOT USD_FOUND) - set(WITH_USD OFF) - endif() + set_and_warn_library_found("USD" USD_FOUND WITH_USD) endif() if(WITH_BOOST) @@ -442,20 +408,13 @@ endif() if(WITH_PUGIXML) find_package_wrapper(PugiXML) - - if(NOT PUGIXML_FOUND) - set(WITH_PUGIXML OFF) - message(STATUS "PugiXML not found, disabling WITH_PUGIXML") - endif() + set_and_warn_library_found("PugiXML" PUGIXML_FOUND WITH_PUGIXML) endif() if(WITH_IMAGE_WEBP) set(WEBP_ROOT_DIR ${LIBDIR}/webp) find_package_wrapper(WebP) - if(NOT WEBP_FOUND) - set(WITH_IMAGE_WEBP OFF) - message(WARNING "WebP not found, disabling WITH_IMAGE_WEBP") - endif() + set_and_warn_library_found("WebP" WEBP_FOUND WITH_IMAGE_WEBP) endif() if(WITH_OPENIMAGEIO) @@ -480,10 +439,7 @@ if(WITH_OPENIMAGEIO) list(APPEND OPENIMAGEIO_LIBRARIES "${WEBP_LIBRARIES}") endif() - if(NOT OPENIMAGEIO_FOUND) - set(WITH_OPENIMAGEIO OFF) - message(STATUS "OpenImageIO not found, disabling WITH_CYCLES") - endif() + set_and_warn_library_found("OPENIMAGEIO" OPENIMAGEIO_FOUND WITH_OPENIMAGEIO) endif() if(WITH_OPENCOLORIO) @@ -493,10 +449,7 @@ if(WITH_OPENCOLORIO) set(OPENCOLORIO_LIBPATH) # TODO, remove and reference the absolute path everywhere set(OPENCOLORIO_DEFINITIONS) - if(NOT OPENCOLORIO_FOUND) - set(WITH_OPENCOLORIO OFF) - message(STATUS "OpenColorIO not found") - endif() + set_and_warn_library_found("OpenColorIO" OPENCOLORIO_FOUND WITH_OPENCOLORIO) endif() if(WITH_CYCLES AND WITH_CYCLES_EMBREE) @@ -505,11 +458,7 @@ endif() if(WITH_OPENIMAGEDENOISE) find_package_wrapper(OpenImageDenoise) - - if(NOT OPENIMAGEDENOISE_FOUND) - set(WITH_OPENIMAGEDENOISE OFF) - message(STATUS "OpenImageDenoise not found") - endif() + set_and_warn_library_found("OpenImageDenoise" OPENIMAGEDENOISE_FOUND WITH_OPENIMAGEDENOISE) endif() if(WITH_LLVM) @@ -518,24 +467,19 @@ if(WITH_LLVM) endif() find_package_wrapper(LLVM) - if(WITH_CLANG) - find_package_wrapper(Clang) - endif() - # Symbol conflicts with same UTF library used by OpenCollada - if(EXISTS ${LIBDIR}) - if(WITH_OPENCOLLADA AND (${LLVM_VERSION} VERSION_LESS "4.0.0")) - list(REMOVE_ITEM OPENCOLLADA_LIBRARIES ${OPENCOLLADA_UTF_LIBRARY}) + set_and_warn_library_found("LLVM" LLVM_FOUND WITH_LLVM) + + if(LLVM_FOUND) + if(WITH_CLANG) + find_package_wrapper(Clang) + set_and_warn_library_found("Clang" CLANG_FOUND WITH_CLANG) endif() - endif() - if(NOT LLVM_FOUND) - set(WITH_LLVM OFF) - set(WITH_CLANG OFF) - message(STATUS "LLVM not found") - else() - if(NOT CLANG_FOUND) - set(WITH_CLANG OFF) - message(STATUS "Clang not found") + # Symbol conflicts with same UTF library used by OpenCollada + if(EXISTS ${LIBDIR}) + if(WITH_OPENCOLLADA AND (${LLVM_VERSION} VERSION_LESS "4.0.0")) + list(REMOVE_ITEM OPENCOLLADA_LIBRARIES ${OPENCOLLADA_UTF_LIBRARY}) + endif() endif() endif() endif() @@ -546,50 +490,32 @@ if(WITH_OPENSUBDIV) set(OPENSUBDIV_LIBRARIES ${OPENSUBDIV_LIBRARIES}) set(OPENSUBDIV_LIBPATH) # TODO, remove and reference the absolute path everywhere - if(NOT OPENSUBDIV_FOUND) - set(WITH_OPENSUBDIV OFF) - message(STATUS "OpenSubdiv not found") - endif() + set_and_warn_library_found("OpenSubdiv" OPENSUBDIV_FOUND WITH_OPENSUBDIV) endif() if(WITH_TBB) find_package_wrapper(TBB) - if(NOT TBB_FOUND) - message(WARNING "TBB not found, disabling WITH_TBB") - set(WITH_TBB OFF) - endif() + set_and_warn_library_found("TBB" TBB_FOUND WITH_TBB) endif() if(WITH_XR_OPENXR) find_package(XR_OpenXR_SDK) - if(NOT XR_OPENXR_SDK_FOUND) - message(WARNING "OpenXR-SDK not found, disabling WITH_XR_OPENXR") - set(WITH_XR_OPENXR OFF) - endif() + set_and_warn_library_found("OpenXR-SDK" XR_OPENXR_SDK_FOUND WITH_XR_OPENXR) endif() if(WITH_GMP) find_package_wrapper(GMP) - if(NOT GMP_FOUND) - message(WARNING "GMP not found, disabling WITH_GMP") - set(WITH_GMP OFF) - endif() + set_and_warn_library_found("GMP" GMP_FOUND WITH_GMP) endif() if(WITH_POTRACE) find_package_wrapper(Potrace) - if(NOT POTRACE_FOUND) - message(WARNING "potrace not found, disabling WITH_POTRACE") - set(WITH_POTRACE OFF) - endif() + set_and_warn_library_found("Potrace" POTRACE_FOUND WITH_POTRACE) endif() if(WITH_HARU) find_package_wrapper(Haru) - if(NOT HARU_FOUND) - message(WARNING "Haru not found, disabling WITH_HARU") - set(WITH_HARU OFF) - endif() + set_and_warn_library_found("Haru" HARU_FOUND WITH_HARU) endif() if(WITH_CYCLES AND WITH_CYCLES_PATH_GUIDING) @@ -676,25 +602,20 @@ endif() # Jack is intended to use the system library. if(WITH_JACK) find_package_wrapper(Jack) - if(NOT JACK_FOUND) - set(WITH_JACK OFF) - endif() + set_and_warn_library_found("JACK" JACK_FOUND WITH_JACK) endif() # Pulse is intended to use the system library. if(WITH_PULSEAUDIO) find_package_wrapper(Pulse) - if(NOT PULSE_FOUND) - set(WITH_PULSEAUDIO OFF) - endif() + set_and_warn_library_found("PulseAudio" PULSE_FOUND WITH_PULSEAUDIO) endif() # Audio IO if(WITH_SYSTEM_AUDASPACE) find_package_wrapper(Audaspace) - if(NOT AUDASPACE_FOUND OR NOT AUDASPACE_C_FOUND) - message(FATAL_ERROR "Audaspace external library not found!") - endif() + set(AUDASPACE_FOUND ${AUDASPACE_FOUND} AND ${AUDASPACE_C_FOUND}) + set_and_warn_library_found("External Audaspace" AUDASPACE_FOUND WITH_SYSTEM_AUDASPACE) endif() if(WITH_GHOST_WAYLAND) @@ -740,30 +661,12 @@ if(WITH_GHOST_WAYLAND) set(wayland-cursor_FOUND ON) endif() - if (NOT wayland-client_FOUND) - message(STATUS "wayland-client not found, disabling WITH_GHOST_WAYLAND") - set(WITH_GHOST_WAYLAND OFF) - endif() - if (NOT wayland-egl_FOUND) - message(STATUS "wayland-egl not found, disabling WITH_GHOST_WAYLAND") - set(WITH_GHOST_WAYLAND OFF) - endif() - if (NOT wayland-scanner_FOUND) - message(STATUS "wayland-scanner not found, disabling WITH_GHOST_WAYLAND") - set(WITH_GHOST_WAYLAND OFF) - endif() - if (NOT wayland-cursor_FOUND) - message(STATUS "wayland-cursor not found, disabling WITH_GHOST_WAYLAND") - set(WITH_GHOST_WAYLAND OFF) - endif() - if (NOT wayland-protocols_FOUND) - message(STATUS "wayland-protocols not found, disabling WITH_GHOST_WAYLAND") - set(WITH_GHOST_WAYLAND OFF) - endif() - if (NOT xkbcommon_FOUND) - message(STATUS "xkbcommon not found, disabling WITH_GHOST_WAYLAND") - set(WITH_GHOST_WAYLAND OFF) - endif() + set_and_warn_library_found("wayland-client" wayland-client_FOUND WITH_GHOST_WAYLAND) + set_and_warn_library_found("wayland-egl" wayland-egl_FOUND WITH_GHOST_WAYLAND) + set_and_warn_library_found("wayland-scanner" wayland-scanner_FOUND WITH_GHOST_WAYLAND) + set_and_warn_library_found("wayland-cursor" wayland-cursor_FOUND WITH_GHOST_WAYLAND) + set_and_warn_library_found("wayland-protocols" wayland-protocols_FOUND WITH_GHOST_WAYLAND) + set_and_warn_library_found("xkbcommon" xkbcommon_FOUND WITH_GHOST_WAYLAND) if(WITH_GHOST_WAYLAND) if(WITH_GHOST_WAYLAND_DBUS) diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake index cfb8bf34b81..3818076634a 100644 --- a/build_files/cmake/platform/platform_win32.cmake +++ b/build_files/cmake/platform/platform_win32.cmake @@ -326,18 +326,10 @@ if(WITH_FFTW3) endif() if(WITH_IMAGE_WEBP) - windows_find_package(WebP) - if(NOT WEBP_FOUND) - if(EXISTS ${LIBDIR}/webp) - set(WEBP_INCLUDE_DIRS ${LIBDIR}/webp/include) - set(WEBP_ROOT_DIR ${LIBDIR}/webp) - set(WEBP_LIBRARIES ${LIBDIR}/webp/lib/webp.lib ${LIBDIR}/webp/lib/webpdemux.lib ${LIBDIR}/webp/lib/webpmux.lib) - set(WEBP_FOUND ON) - else() - message(STATUS "WITH_IMAGE_WEBP is ON but WEBP libraries are not found, setting WITH_IMAGE_WEBP=OFF") - set(WITH_IMAGE_WEBP OFF) - endif() - endif() + set(WEBP_INCLUDE_DIRS ${LIBDIR}/webp/include) + set(WEBP_ROOT_DIR ${LIBDIR}/webp) + set(WEBP_LIBRARIES ${LIBDIR}/webp/lib/webp.lib ${LIBDIR}/webp/lib/webpdemux.lib ${LIBDIR}/webp/lib/webpmux.lib) + set(WEBP_FOUND ON) endif() if(WITH_OPENCOLLADA) @@ -358,7 +350,6 @@ if(WITH_OPENCOLLADA) optimized ${OPENCOLLADA}/lib/opencollada/OpenCOLLADAStreamWriter.lib optimized ${OPENCOLLADA}/lib/opencollada/MathMLSolver.lib optimized ${OPENCOLLADA}/lib/opencollada/GeneratedSaxParser.lib - optimized ${OPENCOLLADA}/lib/opencollada/xml.lib optimized ${OPENCOLLADA}/lib/opencollada/buffer.lib optimized ${OPENCOLLADA}/lib/opencollada/ftoa.lib @@ -368,10 +359,14 @@ if(WITH_OPENCOLLADA) debug ${OPENCOLLADA}/lib/opencollada/OpenCOLLADAStreamWriter_d.lib debug ${OPENCOLLADA}/lib/opencollada/MathMLSolver_d.lib debug ${OPENCOLLADA}/lib/opencollada/GeneratedSaxParser_d.lib - debug ${OPENCOLLADA}/lib/opencollada/xml_d.lib debug ${OPENCOLLADA}/lib/opencollada/buffer_d.lib debug ${OPENCOLLADA}/lib/opencollada/ftoa_d.lib ) + if(EXISTS ${LIBDIR}/xml2/lib/libxml2s.lib) # 3.4 libraries + list(APPEND OPENCOLLADA_LIBRARIES ${LIBDIR}/xml2/lib/libxml2s.lib) + else() + list(APPEND OPENCOLLADA_LIBRARIES ${OPENCOLLADA}/lib/opencollada/xml.lib) + endif() list(APPEND OPENCOLLADA_LIBRARIES ${OPENCOLLADA}/lib/opencollada/UTF.lib) @@ -679,11 +674,11 @@ endif() if(WITH_IMAGE_OPENJPEG) set(OPENJPEG ${LIBDIR}/openjpeg) - set(OPENJPEG_INCLUDE_DIRS ${OPENJPEG}/include/openjpeg-2.4) + set(OPENJPEG_INCLUDE_DIRS ${OPENJPEG}/include/openjpeg-2.5) if(NOT EXISTS "${OPENJPEG_INCLUDE_DIRS}") - # when not found, could be an older lib folder with openjpeg 2.3 - # to ease the transition period, fall back if 2.4 is not found. - set(OPENJPEG_INCLUDE_DIRS ${OPENJPEG}/include/openjpeg-2.3) + # when not found, could be an older lib folder with openjpeg 2.4 + # to ease the transition period, fall back if 2.5 is not found. + set(OPENJPEG_INCLUDE_DIRS ${OPENJPEG}/include/openjpeg-2.4) endif() set(OPENJPEG_LIBRARIES ${OPENJPEG}/lib/openjp2.lib) endif() @@ -700,12 +695,6 @@ if(WITH_OPENSUBDIV) debug ${OPENSUBDIV_LIBPATH}/osdCPU_d.lib debug ${OPENSUBDIV_LIBPATH}/osdGPU_d.lib ) - set(OPENSUBDIV_HAS_OPENMP TRUE) - set(OPENSUBDIV_HAS_TBB FALSE) - set(OPENSUBDIV_HAS_OPENCL TRUE) - set(OPENSUBDIV_HAS_CUDA FALSE) - set(OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK TRUE) - set(OPENSUBDIV_HAS_GLSL_COMPUTE TRUE) endif() endif() @@ -773,9 +762,11 @@ if(WITH_CYCLES AND WITH_CYCLES_OSL) find_library(OSL_LIB_EXEC NAMES oslexec PATHS ${CYCLES_OSL}/lib) find_library(OSL_LIB_COMP NAMES oslcomp PATHS ${CYCLES_OSL}/lib) find_library(OSL_LIB_QUERY NAMES oslquery PATHS ${CYCLES_OSL}/lib) + find_library(OSL_LIB_NOISE NAMES oslnoise PATHS ${CYCLES_OSL}/lib) find_library(OSL_LIB_EXEC_DEBUG NAMES oslexec_d PATHS ${CYCLES_OSL}/lib) find_library(OSL_LIB_COMP_DEBUG NAMES oslcomp_d PATHS ${CYCLES_OSL}/lib) find_library(OSL_LIB_QUERY_DEBUG NAMES oslquery_d PATHS ${CYCLES_OSL}/lib) + find_library(OSL_LIB_NOISE_DEBUG NAMES oslnoise_d PATHS ${CYCLES_OSL}/lib) list(APPEND OSL_LIBRARIES optimized ${OSL_LIB_COMP} optimized ${OSL_LIB_EXEC} @@ -785,15 +776,14 @@ if(WITH_CYCLES AND WITH_CYCLES_OSL) debug ${OSL_LIB_QUERY_DEBUG} ${PUGIXML_LIBRARIES} ) + if(OSL_LIB_NOISE) + list(APPEND OSL_LIBRARIES optimized ${OSL_LIB_NOISE}) + endif() + if(OSL_LIB_NOISE_DEBUG) + list(APPEND OSL_LIBRARIES debug ${OSL_LIB_NOISE_DEBUG}) + endif() find_path(OSL_INCLUDE_DIR OSL/oslclosure.h PATHS ${CYCLES_OSL}/include) find_program(OSL_COMPILER NAMES oslc PATHS ${CYCLES_OSL}/bin) - - if(OSL_INCLUDE_DIR AND OSL_LIBRARIES AND OSL_COMPILER) - set(OSL_FOUND TRUE) - else() - message(STATUS "OSL not found") - set(WITH_CYCLES_OSL OFF) - endif() endif() if(WITH_CYCLES AND WITH_CYCLES_EMBREE) @@ -893,21 +883,16 @@ if(WINDOWS_PYTHON_DEBUG) endif() if(WITH_XR_OPENXR) - if(EXISTS ${LIBDIR}/xr_openxr_sdk) - set(XR_OPENXR_SDK ${LIBDIR}/xr_openxr_sdk) - set(XR_OPENXR_SDK_LIBPATH ${LIBDIR}/xr_openxr_sdk/lib) - set(XR_OPENXR_SDK_INCLUDE_DIR ${XR_OPENXR_SDK}/include) - # This is the old name of this library, it is checked to - # support the transition between the old and new lib versions - # this can be removed after the next lib update. - if(EXISTS ${XR_OPENXR_SDK_LIBPATH}/openxr_loader_d.lib) - set(XR_OPENXR_SDK_LIBRARIES optimized ${XR_OPENXR_SDK_LIBPATH}/openxr_loader.lib debug ${XR_OPENXR_SDK_LIBPATH}/openxr_loader_d.lib) - else() - set(XR_OPENXR_SDK_LIBRARIES optimized ${XR_OPENXR_SDK_LIBPATH}/openxr_loader.lib debug ${XR_OPENXR_SDK_LIBPATH}/openxr_loaderd.lib) - endif() + set(XR_OPENXR_SDK ${LIBDIR}/xr_openxr_sdk) + set(XR_OPENXR_SDK_LIBPATH ${LIBDIR}/xr_openxr_sdk/lib) + set(XR_OPENXR_SDK_INCLUDE_DIR ${XR_OPENXR_SDK}/include) + # This is the old name of this library, it is checked to + # support the transition between the old and new lib versions + # this can be removed after the next lib update. + if(EXISTS ${XR_OPENXR_SDK_LIBPATH}/openxr_loader_d.lib) + set(XR_OPENXR_SDK_LIBRARIES optimized ${XR_OPENXR_SDK_LIBPATH}/openxr_loader.lib debug ${XR_OPENXR_SDK_LIBPATH}/openxr_loader_d.lib) else() - message(WARNING "OpenXR-SDK was not found, disabling WITH_XR_OPENXR") - set(WITH_XR_OPENXR OFF) + set(XR_OPENXR_SDK_LIBRARIES optimized ${XR_OPENXR_SDK_LIBPATH}/openxr_loader.lib debug ${XR_OPENXR_SDK_LIBPATH}/openxr_loaderd.lib) endif() endif() @@ -925,15 +910,10 @@ if(WITH_POTRACE) endif() if(WITH_HARU) - if(EXISTS ${LIBDIR}/haru) - set(HARU_FOUND ON) - set(HARU_ROOT_DIR ${LIBDIR}/haru) - set(HARU_INCLUDE_DIRS ${HARU_ROOT_DIR}/include) - set(HARU_LIBRARIES ${HARU_ROOT_DIR}/lib/libhpdfs.lib) - else() - message(WARNING "Haru was not found, disabling WITH_HARU") - set(WITH_HARU OFF) - endif() + set(HARU_FOUND ON) + set(HARU_ROOT_DIR ${LIBDIR}/haru) + set(HARU_INCLUDE_DIRS ${HARU_ROOT_DIR}/include) + set(HARU_LIBRARIES ${HARU_ROOT_DIR}/lib/libhpdfs.lib) endif() if(WITH_CYCLES AND WITH_CYCLES_PATH_GUIDING) diff --git a/build_files/windows/svn_update.cmd b/build_files/windows/svn_update.cmd new file mode 100644 index 00000000000..f91f03f15b3 --- /dev/null +++ b/build_files/windows/svn_update.cmd @@ -0,0 +1,24 @@ +if "%BUILD_VS_YEAR%"=="2019" set BUILD_VS_LIBDIRPOST=vc15 +if "%BUILD_VS_YEAR%"=="2022" set BUILD_VS_LIBDIRPOST=vc15 + +set BUILD_VS_SVNDIR=win64_%BUILD_VS_LIBDIRPOST% +set BUILD_VS_LIBDIR="%BLENDER_DIR%..\lib\%BUILD_VS_SVNDIR%" + +cd %BUILD_VS_LIBDIR% +:RETRY +"%SVN%" update +if errorlevel 1 ( + set /p LibRetry= "Error during update, retry? y/n" + if /I "!LibRetry!"=="Y" ( + "%SVN%" cleanup + goto RETRY + ) + echo. + echo Error: Download of external libraries failed. + echo This is needed for building, please manually run 'svn cleanup' and 'svn update' in + echo %BUILD_VS_LIBDIR% , until this is resolved you CANNOT make a successful blender build + echo. + exit /b 1 +) + +cd %BLENDER_DIR%
\ No newline at end of file diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt index f619e6b104e..329aa3990f6 100644 --- a/intern/cycles/CMakeLists.txt +++ b/intern/cycles/CMakeLists.txt @@ -263,8 +263,7 @@ if(WITH_CYCLES_DEVICE_OPTIX) ${OPTIX_INCLUDE_DIR} ) else() - message(STATUS "OptiX not found, disabling it from Cycles") - set(WITH_CYCLES_DEVICE_OPTIX OFF) + set_and_warn_library_found("OptiX" OPTIX_FOUND WITH_CYCLES_DEVICE_OPTIX) endif() endif() @@ -387,8 +386,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_C_COMPILER_ID MATCHES "Clang") endif() if(WITH_CYCLES_HYDRA_RENDER_DELEGATE AND (NOT WITH_USD)) - message(STATUS "USD not found, disabling WITH_CYCLES_HYDRA_RENDER_DELEGATE") - set(WITH_CYCLES_HYDRA_RENDER_DELEGATE OFF) + set_and_warn_library_found("USD" WITH_USD WITH_CYCLES_HYDRA_RENDER_DELEGATE) endif() if(WITH_CYCLES_HYDRA_RENDER_DELEGATE AND (NOT WITH_BLENDER) AND (NOT WITH_CYCLES_STANDALONE)) set(CYCLES_INSTALL_PATH ${CYCLES_INSTALL_PATH}/hdCycles/resources) diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt index 0988b1c0ac4..1c7a861ea93 100644 --- a/intern/cycles/app/CMakeLists.txt +++ b/intern/cycles/app/CMakeLists.txt @@ -43,7 +43,10 @@ else() endif() if(WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI) - list(APPEND INC_SYS ${Epoxy_INCLUDE_DIRS} ${SDL2_INCLUDE_DIRS}) + list(APPEND INC_SYS + ${Epoxy_INCLUDE_DIRS} + ${SDL2_INCLUDE_DIRS} + ) list(APPEND LIB ${Epoxy_LIBRARIES} ${SDL2_LIBRARIES}) endif() diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py index 794338fe78e..e33891fa7a2 100644 --- a/intern/cycles/blender/addon/engine.py +++ b/intern/cycles/blender/addon/engine.py @@ -209,22 +209,25 @@ def list_render_passes(scene, srl): yield ("Debug Sample Count", "X", 'VALUE') # Cryptomatte passes. - crypto_depth = (srl.pass_cryptomatte_depth + 1) // 2 + # NOTE: Name channels are lowercase RGBA so that compression rules check in OpenEXR DWA code + # uses lossless compression. Reportedly this naming is the only one which works good from the + # interoperability point of view. Using XYZW naming is not portable. + crypto_depth = (min(16, srl.pass_cryptomatte_depth) + 1) // 2 if srl.use_pass_cryptomatte_object: for i in range(0, crypto_depth): - yield ("CryptoObject" + '{:02d}'.format(i), "RGBA", 'COLOR') + yield ("CryptoObject" + '{:02d}'.format(i), "rgba", 'COLOR') if srl.use_pass_cryptomatte_material: for i in range(0, crypto_depth): - yield ("CryptoMaterial" + '{:02d}'.format(i), "RGBA", 'COLOR') + yield ("CryptoMaterial" + '{:02d}'.format(i), "rgba", 'COLOR') if srl.use_pass_cryptomatte_asset: for i in range(0, crypto_depth): - yield ("CryptoAsset" + '{:02d}'.format(i), "RGBA", 'COLOR') + yield ("CryptoAsset" + '{:02d}'.format(i), "rgba", 'COLOR') # Denoising passes. if scene.cycles.use_denoising and crl.use_denoising: yield ("Noisy Image", "RGBA", 'COLOR') if crl.use_pass_shadow_catcher: - yield ("Noisy Shadow Catcher", "RGBA", 'COLOR') + yield ("Noisy Shadow Catcher", "RGB", 'COLOR') if crl.denoising_store_passes: yield ("Denoising Normal", "XYZ", 'VECTOR') yield ("Denoising Albedo", "RGB", 'COLOR') @@ -232,6 +235,8 @@ def list_render_passes(scene, srl): # Custom AOV passes. for aov in srl.aovs: + if not aov.is_valid: + continue if aov.type == 'VALUE': yield (aov.name, "X", 'VALUE') else: diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index b7ce76d8f44..425d123e9e6 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -1651,6 +1651,7 @@ class CyclesPreferences(bpy.types.AddonPreferences): box.prop( device, "use", text=device.name .replace('(TM)', unicodedata.lookup('TRADE MARK SIGN')) + .replace('(tm)', unicodedata.lookup('TRADE MARK SIGN')) .replace('(R)', unicodedata.lookup('REGISTERED SIGN')) .replace('(C)', unicodedata.lookup('COPYRIGHT SIGN')) ) diff --git a/intern/cycles/blender/sync.cpp b/intern/cycles/blender/sync.cpp index a69a94614d3..5251f0fee9c 100644 --- a/intern/cycles/blender/sync.cpp +++ b/intern/cycles/blender/sync.cpp @@ -575,68 +575,72 @@ void BlenderSync::sync_images() /* Passes */ -static PassType get_blender_pass_type(BL::RenderPass &b_pass) +static bool get_known_pass_type(BL::RenderPass &b_pass, PassType &type, PassMode &mode) { string name = b_pass.name(); -#define MAP_PASS(passname, passtype) \ +#define MAP_PASS(passname, passtype, noisy) \ if (name == passname) { \ - return passtype; \ + type = passtype; \ + mode = (noisy) ? PassMode::NOISY : PassMode::DENOISED; \ + return true; \ } \ ((void)0) - /* NOTE: Keep in sync with defined names from DNA_scene_types.h */ + /* NOTE: Keep in sync with defined names from engine.py */ - MAP_PASS("Combined", PASS_COMBINED); - MAP_PASS("Noisy Image", PASS_COMBINED); + MAP_PASS("Combined", PASS_COMBINED, false); + MAP_PASS("Noisy Image", PASS_COMBINED, true); - MAP_PASS("Depth", PASS_DEPTH); - MAP_PASS("Mist", PASS_MIST); - MAP_PASS("Position", PASS_POSITION); - MAP_PASS("Normal", PASS_NORMAL); - MAP_PASS("IndexOB", PASS_OBJECT_ID); - MAP_PASS("UV", PASS_UV); - MAP_PASS("Vector", PASS_MOTION); - MAP_PASS("IndexMA", PASS_MATERIAL_ID); + MAP_PASS("Depth", PASS_DEPTH, false); + MAP_PASS("Mist", PASS_MIST, false); + MAP_PASS("Position", PASS_POSITION, false); + MAP_PASS("Normal", PASS_NORMAL, false); + MAP_PASS("IndexOB", PASS_OBJECT_ID, false); + MAP_PASS("UV", PASS_UV, false); + MAP_PASS("Vector", PASS_MOTION, false); + MAP_PASS("IndexMA", PASS_MATERIAL_ID, false); - MAP_PASS("DiffDir", PASS_DIFFUSE_DIRECT); - MAP_PASS("GlossDir", PASS_GLOSSY_DIRECT); - MAP_PASS("TransDir", PASS_TRANSMISSION_DIRECT); - MAP_PASS("VolumeDir", PASS_VOLUME_DIRECT); + MAP_PASS("DiffDir", PASS_DIFFUSE_DIRECT, false); + MAP_PASS("GlossDir", PASS_GLOSSY_DIRECT, false); + MAP_PASS("TransDir", PASS_TRANSMISSION_DIRECT, false); + MAP_PASS("VolumeDir", PASS_VOLUME_DIRECT, false); - MAP_PASS("DiffInd", PASS_DIFFUSE_INDIRECT); - MAP_PASS("GlossInd", PASS_GLOSSY_INDIRECT); - MAP_PASS("TransInd", PASS_TRANSMISSION_INDIRECT); - MAP_PASS("VolumeInd", PASS_VOLUME_INDIRECT); + MAP_PASS("DiffInd", PASS_DIFFUSE_INDIRECT, false); + MAP_PASS("GlossInd", PASS_GLOSSY_INDIRECT, false); + MAP_PASS("TransInd", PASS_TRANSMISSION_INDIRECT, false); + MAP_PASS("VolumeInd", PASS_VOLUME_INDIRECT, false); - MAP_PASS("DiffCol", PASS_DIFFUSE_COLOR); - MAP_PASS("GlossCol", PASS_GLOSSY_COLOR); - MAP_PASS("TransCol", PASS_TRANSMISSION_COLOR); + MAP_PASS("DiffCol", PASS_DIFFUSE_COLOR, false); + MAP_PASS("GlossCol", PASS_GLOSSY_COLOR, false); + MAP_PASS("TransCol", PASS_TRANSMISSION_COLOR, false); - MAP_PASS("Emit", PASS_EMISSION); - MAP_PASS("Env", PASS_BACKGROUND); - MAP_PASS("AO", PASS_AO); - MAP_PASS("Shadow", PASS_SHADOW); + MAP_PASS("Emit", PASS_EMISSION, false); + MAP_PASS("Env", PASS_BACKGROUND, false); + MAP_PASS("AO", PASS_AO, false); + MAP_PASS("Shadow", PASS_SHADOW, false); - MAP_PASS("BakePrimitive", PASS_BAKE_PRIMITIVE); - MAP_PASS("BakeDifferential", PASS_BAKE_DIFFERENTIAL); + MAP_PASS("BakePrimitive", PASS_BAKE_PRIMITIVE, false); + MAP_PASS("BakeDifferential", PASS_BAKE_DIFFERENTIAL, false); - MAP_PASS("Denoising Normal", PASS_DENOISING_NORMAL); - MAP_PASS("Denoising Albedo", PASS_DENOISING_ALBEDO); - MAP_PASS("Denoising Depth", PASS_DENOISING_DEPTH); + MAP_PASS("Denoising Normal", PASS_DENOISING_NORMAL, true); + MAP_PASS("Denoising Albedo", PASS_DENOISING_ALBEDO, true); + MAP_PASS("Denoising Depth", PASS_DENOISING_DEPTH, true); - MAP_PASS("Shadow Catcher", PASS_SHADOW_CATCHER); - MAP_PASS("Noisy Shadow Catcher", PASS_SHADOW_CATCHER); + MAP_PASS("Shadow Catcher", PASS_SHADOW_CATCHER, false); + MAP_PASS("Noisy Shadow Catcher", PASS_SHADOW_CATCHER, true); - MAP_PASS("AdaptiveAuxBuffer", PASS_ADAPTIVE_AUX_BUFFER); - MAP_PASS("Debug Sample Count", PASS_SAMPLE_COUNT); + MAP_PASS("AdaptiveAuxBuffer", PASS_ADAPTIVE_AUX_BUFFER, false); + MAP_PASS("Debug Sample Count", PASS_SAMPLE_COUNT, false); if (string_startswith(name, cryptomatte_prefix)) { - return PASS_CRYPTOMATTE; + type = PASS_CRYPTOMATTE; + mode = PassMode::DENOISED; + return true; } #undef MAP_PASS - return PASS_NONE; + return false; } static Pass *pass_add(Scene *scene, @@ -655,8 +659,6 @@ static Pass *pass_add(Scene *scene, void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_view_layer) { - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - /* Delete all existing passes. */ set<Pass *> clear_passes(scene->passes.begin(), scene->passes.end()); scene->delete_nodes(clear_passes); @@ -664,103 +666,23 @@ void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_v /* Always add combined pass. */ pass_add(scene, PASS_COMBINED, "Combined"); - /* Blender built-in data and light passes. */ - for (BL::RenderPass &b_pass : b_rlay.passes) { - const PassType pass_type = get_blender_pass_type(b_pass); - - if (pass_type == PASS_NONE) { - LOG(ERROR) << "Unknown pass " << b_pass.name(); - continue; - } - - if (pass_type == PASS_MOTION && - (b_view_layer.use_motion_blur() && b_scene.render().use_motion_blur())) { - continue; - } - - pass_add(scene, pass_type, b_pass.name().c_str()); - } - - PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles"); - - /* Debug passes. */ - if (get_boolean(crl, "pass_debug_sample_count")) { - b_engine.add_pass("Debug Sample Count", 1, "X", b_view_layer.name().c_str()); - pass_add(scene, PASS_SAMPLE_COUNT, "Debug Sample Count"); - } - - /* Cycles specific passes. */ - if (get_boolean(crl, "use_pass_volume_direct")) { - b_engine.add_pass("VolumeDir", 3, "RGB", b_view_layer.name().c_str()); - pass_add(scene, PASS_VOLUME_DIRECT, "VolumeDir"); - } - if (get_boolean(crl, "use_pass_volume_indirect")) { - b_engine.add_pass("VolumeInd", 3, "RGB", b_view_layer.name().c_str()); - pass_add(scene, PASS_VOLUME_INDIRECT, "VolumeInd"); - } - if (get_boolean(crl, "use_pass_shadow_catcher")) { - b_engine.add_pass("Shadow Catcher", 3, "RGB", b_view_layer.name().c_str()); - pass_add(scene, PASS_SHADOW_CATCHER, "Shadow Catcher"); - } - /* Cryptomatte stores two ID/weight pairs per RGBA layer. - * User facing parameter is the number of pairs. - * - * NOTE: Name channels lowercase RGBA so that compression rules check in OpenEXR DWA code uses - * lossless compression. Reportedly this naming is the only one which works good from the - * interoperability point of view. Using XYZW naming is not portable. */ + * User facing parameter is the number of pairs. */ int crypto_depth = divide_up(min(16, b_view_layer.pass_cryptomatte_depth()), 2); scene->film->set_cryptomatte_depth(crypto_depth); CryptomatteType cryptomatte_passes = CRYPT_NONE; if (b_view_layer.use_pass_cryptomatte_object()) { - for (int i = 0; i < crypto_depth; i++) { - string passname = cryptomatte_prefix + string_printf("Object%02d", i); - b_engine.add_pass(passname.c_str(), 4, "rgba", b_view_layer.name().c_str()); - pass_add(scene, PASS_CRYPTOMATTE, passname.c_str()); - } cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_OBJECT); } if (b_view_layer.use_pass_cryptomatte_material()) { - for (int i = 0; i < crypto_depth; i++) { - string passname = cryptomatte_prefix + string_printf("Material%02d", i); - b_engine.add_pass(passname.c_str(), 4, "rgba", b_view_layer.name().c_str()); - pass_add(scene, PASS_CRYPTOMATTE, passname.c_str()); - } cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_MATERIAL); } if (b_view_layer.use_pass_cryptomatte_asset()) { - for (int i = 0; i < crypto_depth; i++) { - string passname = cryptomatte_prefix + string_printf("Asset%02d", i); - b_engine.add_pass(passname.c_str(), 4, "rgba", b_view_layer.name().c_str()); - pass_add(scene, PASS_CRYPTOMATTE, passname.c_str()); - } cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_ASSET); } scene->film->set_cryptomatte_passes(cryptomatte_passes); - /* Denoising passes. */ - const bool use_denoising = get_boolean(cscene, "use_denoising") && - get_boolean(crl, "use_denoising"); - const bool store_denoising_passes = get_boolean(crl, "denoising_store_passes"); - if (use_denoising) { - b_engine.add_pass("Noisy Image", 4, "RGBA", b_view_layer.name().c_str()); - pass_add(scene, PASS_COMBINED, "Noisy Image", PassMode::NOISY); - if (get_boolean(crl, "use_pass_shadow_catcher")) { - b_engine.add_pass("Noisy Shadow Catcher", 3, "RGB", b_view_layer.name().c_str()); - pass_add(scene, PASS_SHADOW_CATCHER, "Noisy Shadow Catcher", PassMode::NOISY); - } - } - if (store_denoising_passes) { - b_engine.add_pass("Denoising Normal", 3, "XYZ", b_view_layer.name().c_str()); - pass_add(scene, PASS_DENOISING_NORMAL, "Denoising Normal", PassMode::NOISY); - - b_engine.add_pass("Denoising Albedo", 3, "RGB", b_view_layer.name().c_str()); - pass_add(scene, PASS_DENOISING_ALBEDO, "Denoising Albedo", PassMode::NOISY); - - b_engine.add_pass("Denoising Depth", 1, "Z", b_view_layer.name().c_str()); - pass_add(scene, PASS_DENOISING_DEPTH, "Denoising Depth", PassMode::NOISY); - } - + /* Path guiding debug passes. */ #ifdef WITH_CYCLES_DEBUG b_engine.add_pass("Guiding Color", 3, "RGB", b_view_layer.name().c_str()); pass_add(scene, PASS_GUIDING_COLOR, "Guiding Color", PassMode::NOISY); @@ -772,6 +694,8 @@ void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_v pass_add(scene, PASS_GUIDING_AVG_ROUGHNESS, "Guiding Average Roughness", PassMode::NOISY); #endif + unordered_set<string> expected_passes; + /* Custom AOV passes. */ BL::ViewLayer::aovs_iterator b_aov_iter; for (b_view_layer.aovs.begin(b_aov_iter); b_aov_iter != b_view_layer.aovs.end(); ++b_aov_iter) { @@ -781,16 +705,10 @@ void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_v } string name = b_aov.name(); - bool is_color = b_aov.type() == BL::AOV::type_COLOR; + PassType type = (b_aov.type() == BL::AOV::type_COLOR) ? PASS_AOV_COLOR : PASS_AOV_VALUE; - if (is_color) { - b_engine.add_pass(name.c_str(), 4, "RGBA", b_view_layer.name().c_str()); - pass_add(scene, PASS_AOV_COLOR, name.c_str()); - } - else { - b_engine.add_pass(name.c_str(), 1, "X", b_view_layer.name().c_str()); - pass_add(scene, PASS_AOV_VALUE, name.c_str()); - } + pass_add(scene, type, name.c_str()); + expected_passes.insert(name); } /* Light Group passes. */ @@ -802,9 +720,29 @@ void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_v string name = string_printf("Combined_%s", b_lightgroup.name().c_str()); - b_engine.add_pass(name.c_str(), 3, "RGB", b_view_layer.name().c_str()); Pass *pass = pass_add(scene, PASS_COMBINED, name.c_str(), PassMode::NOISY); pass->set_lightgroup(ustring(b_lightgroup.name())); + expected_passes.insert(name); + } + + /* Sync the passes that were defined in engine.py. */ + for (BL::RenderPass &b_pass : b_rlay.passes) { + PassType pass_type = PASS_NONE; + PassMode pass_mode = PassMode::DENOISED; + + if (!get_known_pass_type(b_pass, pass_type, pass_mode)) { + if (!expected_passes.count(b_pass.name())) { + LOG(ERROR) << "Unknown pass " << b_pass.name(); + } + continue; + } + + if (pass_type == PASS_MOTION && + (b_view_layer.use_motion_blur() && b_scene.render().use_motion_blur())) { + continue; + } + + pass_add(scene, pass_type, b_pass.name().c_str(), pass_mode); } scene->film->set_pass_alpha_threshold(b_view_layer.pass_alpha_threshold()); diff --git a/intern/cycles/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake index 9524cda54f5..44542a08156 100644 --- a/intern/cycles/cmake/external_libs.cmake +++ b/intern/cycles/cmake/external_libs.cmake @@ -289,8 +289,7 @@ if(CYCLES_STANDALONE_REPOSITORY AND WITH_CYCLES_PATH_GUIDING) endif() get_target_property(OPENPGL_INCLUDE_DIR openpgl::openpgl INTERFACE_INCLUDE_DIRECTORIES) else() - set(WITH_CYCLES_PATH_GUIDING OFF) - message(STATUS "OpenPGL not found, disabling WITH_CYCLES_PATH_GUIDING") + set_and_warn_library_found("OpenPGL" openpgl_FOUND WITH_CYCLES_PATH_GUIDING) endif() endif() @@ -588,16 +587,14 @@ if(WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI) # We can't use the version from the Blender precompiled libraries because # it does not include the video subsystem. find_package(SDL2 REQUIRED) + set_and_warn_library_found("SDL" SDL2_FOUND WITH_CYCLES_STANDALONE_GUI) - if(NOT SDL2_FOUND) - set(WITH_CYCLES_STANDALONE_GUI OFF) - message(STATUS "SDL not found, disabling Cycles standalone GUI") + if(SDL2_FOUND) + include_directories( + SYSTEM + ${SDL2_INCLUDE_DIRS} + ) endif() - - include_directories( - SYSTEM - ${SDL2_INCLUDE_DIRS} - ) endif() ########################################################################### @@ -606,11 +603,11 @@ endif() if(WITH_CYCLES_DEVICE_CUDA AND (WITH_CYCLES_CUDA_BINARIES OR NOT WITH_CUDA_DYNLOAD)) find_package(CUDA) # Try to auto locate CUDA toolkit + set_and_warn_library_found("CUDA compiler" CUDA_FOUND WITH_CYCLES_CUDA_BINARIES) + if(CUDA_FOUND) message(STATUS "Found CUDA ${CUDA_NVCC_EXECUTABLE} (${CUDA_VERSION})") else() - message(STATUS "CUDA compiler not found, disabling WITH_CYCLES_CUDA_BINARIES") - set(WITH_CYCLES_CUDA_BINARIES OFF) if(NOT WITH_CUDA_DYNLOAD) message(STATUS "Additionally falling back to dynamic CUDA load") set(WITH_CUDA_DYNLOAD ON) @@ -624,11 +621,10 @@ endif() if(WITH_CYCLES_HIP_BINARIES AND WITH_CYCLES_DEVICE_HIP) find_package(HIP) + set_and_warn_library_found("HIP compiler" HIP_FOUND WITH_CYCLES_HIP_BINARIES) + if(HIP_FOUND) message(STATUS "Found HIP ${HIP_HIPCC_EXECUTABLE} (${HIP_VERSION})") - else() - message(STATUS "HIP compiler not found, disabling WITH_CYCLES_HIP_BINARIES") - set(WITH_CYCLES_HIP_BINARIES OFF) endif() endif() @@ -644,13 +640,17 @@ if(WITH_CYCLES_DEVICE_METAL) find_library(METAL_LIBRARY Metal) # This file was added in the 12.0 SDK, use it as a way to detect the version. - if(METAL_LIBRARY AND NOT EXISTS "${METAL_LIBRARY}/Headers/MTLFunctionStitching.h") - message(STATUS "Metal version too old, must be SDK 12.0 or newer, disabling WITH_CYCLES_DEVICE_METAL") - set(WITH_CYCLES_DEVICE_METAL OFF) - elseif(NOT METAL_LIBRARY) - message(STATUS "Metal not found, disabling WITH_CYCLES_DEVICE_METAL") - set(WITH_CYCLES_DEVICE_METAL OFF) - else() + if(METAL_LIBRARY) + if(EXISTS "${METAL_LIBRARY}/Headers/MTLFunctionStitching.h") + set(METAL_FOUND ON) + else() + message(STATUS "Metal version too old, must be SDK 12.0 or newer") + set(METAL_FOUND OFF) + endif() + endif() + + set_and_warn_library_found("Metal" METAL_FOUND WITH_CYCLES_DEVICE_METAL) + if(METAL_FOUND) message(STATUS "Found Metal: ${METAL_LIBRARY}") endif() endif() @@ -662,9 +662,10 @@ endif() if(WITH_CYCLES_DEVICE_ONEAPI) find_package(SYCL) find_package(LevelZero) + set_and_warn_library_found("oneAPI" SYCL_FOUND WITH_CYCLES_DEVICE_ONEAPI) + set_and_warn_library_found("Level Zero" LEVEL_ZERO_FOUND WITH_CYCLES_DEVICE_ONEAPI) - if(SYCL_FOUND AND LEVEL_ZERO_FOUND) - message(STATUS "Found oneAPI: ${SYCL_LIBRARY}") + if(SYCL_FOUND AND SYCL_VERSION VERSION_GREATER_EQUAL 6.0 AND LEVEL_ZERO_FOUND) message(STATUS "Found Level Zero: ${LEVEL_ZERO_LIBRARY}") if(WITH_CYCLES_ONEAPI_BINARIES) @@ -675,13 +676,14 @@ if(WITH_CYCLES_DEVICE_ONEAPI) endif() if(NOT EXISTS ${OCLOC_INSTALL_DIR}) - message(STATUS "oneAPI ocloc not found in ${OCLOC_INSTALL_DIR}, disabling WITH_CYCLES_ONEAPI_BINARIES." + set(OCLOC_FOUND OFF) + message(STATUS "oneAPI ocloc not found in ${OCLOC_INSTALL_DIR}." " A different ocloc directory can be set using OCLOC_INSTALL_DIR cmake variable.") - set(WITH_CYCLES_ONEAPI_BINARIES OFF) + set_and_warn_library_found("ocloc" OCLOC_FOUND WITH_CYCLES_ONEAPI_BINARIES) endif() endif() else() - message(STATUS "oneAPI or Level Zero not found, disabling WITH_CYCLES_DEVICE_ONEAPI") + message(STATUS "SYCL 6.0+ or Level Zero not found, disabling WITH_CYCLES_DEVICE_ONEAPI") set(WITH_CYCLES_DEVICE_ONEAPI OFF) endif() endif() diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt index 5516e97f34f..5296d819e42 100644 --- a/intern/cycles/device/CMakeLists.txt +++ b/intern/cycles/device/CMakeLists.txt @@ -187,18 +187,22 @@ if(WITH_CYCLES_DEVICE_METAL) ) endif() if (WITH_CYCLES_DEVICE_ONEAPI) + if(WITH_CYCLES_ONEAPI_BINARIES) + set(cycles_kernel_oneapi_lib_suffix "_aot") + else() + set(cycles_kernel_oneapi_lib_suffix "_jit") + endif() if(WIN32) - set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/../kernel/cycles_kernel_oneapi.lib) + set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/../kernel/cycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.lib) else() - set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/../kernel/libcycles_kernel_oneapi.so) + set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/../kernel/libcycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.so) + endif() + list(APPEND LIB ${cycles_kernel_oneapi_lib}) + if(WIN32) + list(APPEND LIB debug ${SYCL_LIBRARY_DEBUG} optimized ${SYCL_LIBRARY}) + else() + list(APPEND LIB ${SYCL_LIBRARY}) endif() - list(APPEND LIB - ${cycles_kernel_oneapi_lib} - "$<$<CONFIG:Debug>:${SYCL_LIBRARY_DEBUG}>" - "$<$<CONFIG:Release>:${SYCL_LIBRARY}>" - "$<$<CONFIG:RelWithDebInfo>:${SYCL_LIBRARY}>" - "$<$<CONFIG:MinSizeRel>:${SYCL_LIBRARY}>" - ) add_definitions(-DWITH_ONEAPI) list(APPEND SRC ${SRC_ONEAPI} diff --git a/intern/cycles/device/metal/device_impl.mm b/intern/cycles/device/metal/device_impl.mm index 6a16d4bb3b4..4b929b6bc0a 100644 --- a/intern/cycles/device/metal/device_impl.mm +++ b/intern/cycles/device/metal/device_impl.mm @@ -339,6 +339,14 @@ bool MetalDevice::compile_and_load(MetalPipelineType pso_type) MTLCompileOptions *options = [[MTLCompileOptions alloc] init]; +# if defined(MAC_OS_VERSION_13_0) + if (@available(macos 13.0, *)) { + if (device_vendor == METAL_GPU_INTEL) { + [options setOptimizationLevel:MTLLibraryOptimizationLevelSize]; + } + } +# endif + options.fastMathEnabled = YES; if (@available(macOS 12.0, *)) { options.languageVersion = MTLLanguageVersion2_4; diff --git a/intern/cycles/device/metal/kernel.mm b/intern/cycles/device/metal/kernel.mm index 5e0cb6d18f4..8ccc50e57a3 100644 --- a/intern/cycles/device/metal/kernel.mm +++ b/intern/cycles/device/metal/kernel.mm @@ -317,6 +317,12 @@ bool MetalKernelPipeline::should_use_binary_archive() const } } + /* Workaround for Intel GPU having issue using Binary Archives */ + MetalGPUVendor gpu_vendor = MetalInfo::get_device_vendor(mtlDevice); + if (gpu_vendor == METAL_GPU_INTEL) { + return false; + } + if (pso_type == PSO_GENERIC) { /* Archive the generic kernels. */ return true; diff --git a/intern/cycles/device/metal/util.mm b/intern/cycles/device/metal/util.mm index 65c67c400fe..f47638fac15 100644 --- a/intern/cycles/device/metal/util.mm +++ b/intern/cycles/device/metal/util.mm @@ -110,6 +110,12 @@ vector<id<MTLDevice>> const &MetalInfo::get_usable_devices() usable |= (vendor == METAL_GPU_AMD); } +# if defined(MAC_OS_VERSION_13_0) + if (@available(macos 13.0, *)) { + usable |= (vendor == METAL_GPU_INTEL); + } +# endif + if (usable) { metal_printf("- %s\n", device_name.c_str()); [device retain]; diff --git a/intern/cycles/device/oneapi/device.cpp b/intern/cycles/device/oneapi/device.cpp index f303ab41627..66d6f749e30 100644 --- a/intern/cycles/device/oneapi/device.cpp +++ b/intern/cycles/device/oneapi/device.cpp @@ -39,7 +39,7 @@ bool device_oneapi_init() _putenv_s("SYCL_CACHE_THRESHOLD", "0"); } if (getenv("SYCL_DEVICE_FILTER") == nullptr) { - _putenv_s("SYCL_DEVICE_FILTER", "host,level_zero"); + _putenv_s("SYCL_DEVICE_FILTER", "level_zero"); } if (getenv("SYCL_ENABLE_PCI") == nullptr) { _putenv_s("SYCL_ENABLE_PCI", "1"); @@ -50,7 +50,7 @@ bool device_oneapi_init() # elif __linux__ setenv("SYCL_CACHE_PERSISTENT", "1", false); setenv("SYCL_CACHE_THRESHOLD", "0", false); - setenv("SYCL_DEVICE_FILTER", "host,level_zero", false); + setenv("SYCL_DEVICE_FILTER", "level_zero", false); setenv("SYCL_ENABLE_PCI", "1", false); setenv("SYCL_PI_LEVEL_ZERO_USE_COPY_ENGINE_FOR_IN_ORDER_QUEUE", "0", false); # endif diff --git a/intern/cycles/device/oneapi/device_impl.cpp b/intern/cycles/device/oneapi/device_impl.cpp index 91f53fd1eae..3588b75713b 100644 --- a/intern/cycles/device/oneapi/device_impl.cpp +++ b/intern/cycles/device/oneapi/device_impl.cpp @@ -430,9 +430,9 @@ void OneapiDevice::check_usm(SyclQueue *queue_, const void *usm_ptr, bool allow_ sycl::usm::alloc usm_type = get_pointer_type(usm_ptr, queue->get_context()); (void)usm_type; assert(usm_type == sycl::usm::alloc::device || - ((device_type == sycl::info::device_type::host || - device_type == sycl::info::device_type::cpu || allow_host) && - usm_type == sycl::usm::alloc::host)); + ((device_type == sycl::info::device_type::cpu || allow_host) && + usm_type == sycl::usm::alloc::host || + usm_type == sycl::usm::alloc::unknown)); # else /* Silence warning about unused arguments. */ (void)queue_; @@ -671,14 +671,6 @@ std::vector<sycl::device> OneapiDevice::available_devices() if (getenv("CYCLES_ONEAPI_ALL_DEVICES") != nullptr) allow_all_devices = true; - /* Host device is useful only for debugging at the moment - * so we hide this device with default build settings. */ -# ifdef WITH_ONEAPI_SYCL_HOST_ENABLED - bool allow_host = true; -# else - bool allow_host = false; -# endif - const std::vector<sycl::platform> &oneapi_platforms = sycl::platform::get_platforms(); std::vector<sycl::device> available_devices; @@ -690,17 +682,11 @@ std::vector<sycl::device> OneapiDevice::available_devices() } const std::vector<sycl::device> &oneapi_devices = - (allow_all_devices || allow_host) ? platform.get_devices(sycl::info::device_type::all) : - platform.get_devices(sycl::info::device_type::gpu); + (allow_all_devices) ? platform.get_devices(sycl::info::device_type::all) : + platform.get_devices(sycl::info::device_type::gpu); for (const sycl::device &device : oneapi_devices) { - if (allow_all_devices) { - /* still filter out host device if build doesn't support it. */ - if (allow_host || !device.is_host()) { - available_devices.push_back(device); - } - } - else { + if (!allow_all_devices) { bool filter_out = false; /* For now we support all Intel(R) Arc(TM) devices and likely any future GPU, @@ -712,11 +698,11 @@ std::vector<sycl::device> OneapiDevice::available_devices() int number_of_eus = 96; int threads_per_eu = 7; if (device.has(sycl::aspect::ext_intel_gpu_eu_count)) { - number_of_eus = device.get_info<sycl::info::device::ext_intel_gpu_eu_count>(); + number_of_eus = device.get_info<sycl::ext::intel::info::device::gpu_eu_count>(); } if (device.has(sycl::aspect::ext_intel_gpu_hw_threads_per_eu)) { threads_per_eu = - device.get_info<sycl::info::device::ext_intel_gpu_hw_threads_per_eu>(); + device.get_info<sycl::ext::intel::info::device::gpu_hw_threads_per_eu>(); } /* This filters out all Level-Zero supported GPUs from older generation than Arc. */ if (number_of_eus <= 96 && threads_per_eu == 7) { @@ -732,9 +718,6 @@ std::vector<sycl::device> OneapiDevice::available_devices() } } } - else if (!allow_host && device.is_host()) { - filter_out = true; - } else if (!allow_all_devices) { filter_out = true; } @@ -797,9 +780,7 @@ char *OneapiDevice::device_capabilities() GET_NUM_ATTR(native_vector_width_double) GET_NUM_ATTR(native_vector_width_half) - size_t max_clock_frequency = - (size_t)(device.is_host() ? (size_t)0 : - device.get_info<sycl::info::device::max_clock_frequency>()); + size_t max_clock_frequency = device.get_info<sycl::info::device::max_clock_frequency>(); WRITE_ATTR("max_clock_frequency", max_clock_frequency) GET_NUM_ATTR(address_bits) @@ -837,7 +818,7 @@ void OneapiDevice::iterate_devices(OneAPIDeviceIteratorCallback cb, void *user_p std::string name = device.get_info<sycl::info::device::name>(); std::string id = "ONEAPI_" + platform_name + "_" + name; if (device.has(sycl::aspect::ext_intel_pci_address)) { - id.append("_" + device.get_info<sycl::info::device::ext_intel_pci_address>()); + id.append("_" + device.get_info<sycl::ext::intel::info::device::pci_address>()); } (cb)(id.c_str(), name.c_str(), num, user_ptr); num++; @@ -855,7 +836,7 @@ int OneapiDevice::get_num_multiprocessors() { const sycl::device &device = reinterpret_cast<sycl::queue *>(device_queue_)->get_device(); if (device.has(sycl::aspect::ext_intel_gpu_eu_count)) { - return device.get_info<sycl::info::device::ext_intel_gpu_eu_count>(); + return device.get_info<sycl::ext::intel::info::device::gpu_eu_count>(); } else return 0; @@ -866,8 +847,8 @@ int OneapiDevice::get_max_num_threads_per_multiprocessor() const sycl::device &device = reinterpret_cast<sycl::queue *>(device_queue_)->get_device(); if (device.has(sycl::aspect::ext_intel_gpu_eu_simd_width) && device.has(sycl::aspect::ext_intel_gpu_hw_threads_per_eu)) { - return device.get_info<sycl::info::device::ext_intel_gpu_eu_simd_width>() * - device.get_info<sycl::info::device::ext_intel_gpu_hw_threads_per_eu>(); + return device.get_info<sycl::ext::intel::info::device::gpu_eu_simd_width>() * + device.get_info<sycl::ext::intel::info::device::gpu_hw_threads_per_eu>(); } else return 0; diff --git a/intern/cycles/device/oneapi/device_impl.h b/intern/cycles/device/oneapi/device_impl.h index 62034150eac..197cf03d60d 100644 --- a/intern/cycles/device/oneapi/device_impl.h +++ b/intern/cycles/device/oneapi/device_impl.h @@ -3,7 +3,7 @@ #ifdef WITH_ONEAPI -# include <CL/sycl.hpp> +# include <sycl/sycl.hpp> # include "device/device.h" # include "device/oneapi/device.h" diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 36c8b23d983..81c5f593974 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -713,10 +713,17 @@ endif() # oneAPI module if(WITH_CYCLES_DEVICE_ONEAPI) + if(WITH_CYCLES_ONEAPI_BINARIES) + set(cycles_kernel_oneapi_lib_suffix "_aot") + else() + set(cycles_kernel_oneapi_lib_suffix "_jit") + endif() + if(WIN32) - set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/cycles_kernel_oneapi.dll) + set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/cycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.dll) + set(cycles_kernel_oneapi_linker_lib ${CMAKE_CURRENT_BINARY_DIR}/cycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.lib) else() - set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/libcycles_kernel_oneapi.so) + set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/libcycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.so) endif() set(cycles_oneapi_kernel_sources @@ -751,10 +758,6 @@ if(WITH_CYCLES_DEVICE_ONEAPI) ${SYCL_CPP_FLAGS} ) - if (WITH_CYCLES_ONEAPI_SYCL_HOST_ENABLED) - list(APPEND sycl_compiler_flags -DWITH_ONEAPI_SYCL_HOST_ENABLED) - endif() - # Set defaults for spir64 and spir64_gen options if (NOT DEFINED CYCLES_ONEAPI_SYCL_OPTIONS_spir64) set(CYCLES_ONEAPI_SYCL_OPTIONS_spir64 "-options '-ze-opt-large-register-file -ze-opt-regular-grf-kernel integrator_intersect'") @@ -767,6 +770,8 @@ if(WITH_CYCLES_DEVICE_ONEAPI) string(PREPEND CYCLES_ONEAPI_SYCL_OPTIONS_spir64_gen "-device ${CYCLES_ONEAPI_SPIR64_GEN_DEVICES} ") if (WITH_CYCLES_ONEAPI_BINARIES) + # AoT binaries aren't currently reused when calling sycl::build. + list (APPEND sycl_compiler_flags -DSYCL_SKIP_KERNELS_PRELOAD) # Iterate over all targest and their options list (JOIN CYCLES_ONEAPI_SYCL_TARGETS "," targets_string) list (APPEND sycl_compiler_flags -fsycl-targets=${targets_string}) @@ -819,12 +824,17 @@ if(WITH_CYCLES_DEVICE_ONEAPI) -DONEAPI_EXPORT) string(REPLACE /Redist/ /Tools/ MSVC_TOOLS_DIR ${MSVC_REDIST_DIR}) - if(NOT CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION) # case for Ninja on Windows + # Version Folder between Redist and Tools can mismatch sometimes + if(NOT EXISTS ${MSVC_TOOLS_DIR}) + get_filename_component(cmake_ar_dir ${CMAKE_AR} DIRECTORY) + get_filename_component(MSVC_TOOLS_DIR "${cmake_ar_dir}/../../../" ABSOLUTE) + endif() + if(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION) + set(WINDOWS_KIT_DIR ${WINDOWS_KITS_DIR}/Lib/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}) + else() # case for Ninja on Windows get_filename_component(cmake_mt_dir ${CMAKE_MT} DIRECTORY) string(REPLACE /bin/ /Lib/ WINDOWS_KIT_DIR ${cmake_mt_dir}) get_filename_component(WINDOWS_KIT_DIR "${WINDOWS_KIT_DIR}/../" ABSOLUTE) - else() - set(WINDOWS_KIT_DIR ${WINDOWS_KITS_DIR}/Lib/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}) endif() list(APPEND sycl_compiler_flags -L "${MSVC_TOOLS_DIR}/lib/x64" @@ -836,15 +846,13 @@ if(WITH_CYCLES_DEVICE_ONEAPI) set(sycl_compiler_flags_RelWithDebInfo ${sycl_compiler_flags}) set(sycl_compiler_flags_MinSizeRel ${sycl_compiler_flags}) list(APPEND sycl_compiler_flags_RelWithDebInfo -g) - get_filename_component(sycl_library_debug_name ${SYCL_LIBRARY_DEBUG} NAME_WE) list(APPEND sycl_compiler_flags_Debug -g -D_DEBUG - -nostdlib -Xclang --dependent-lib=msvcrtd - -Xclang --dependent-lib=${sycl_library_debug_name}) + -nostdlib -Xclang --dependent-lib=msvcrtd) add_custom_command( - OUTPUT ${cycles_kernel_oneapi_lib} + OUTPUT ${cycles_kernel_oneapi_lib} ${cycles_kernel_oneapi_linker_lib} COMMAND ${CMAKE_COMMAND} -E env "LIB=${sycl_compiler_root}/../lib" # for compiler to find sycl.lib "PATH=${OCLOC_INSTALL_DIR}\;${sycl_compiler_root}" diff --git a/intern/cycles/kernel/bvh/shadow_all.h b/intern/cycles/kernel/bvh/shadow_all.h index 2ffe1496c72..b31ba479e4f 100644 --- a/intern/cycles/kernel/bvh/shadow_all.h +++ b/intern/cycles/kernel/bvh/shadow_all.h @@ -229,7 +229,7 @@ ccl_device_inline /* Always use baked shadow transparency for curves. */ if (isect.type & PRIMITIVE_CURVE) { *r_throughput *= intersection_curve_shadow_transparency( - kg, isect.object, isect.prim, isect.u); + kg, isect.object, isect.prim, isect.type, isect.u); if (*r_throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) { return true; diff --git a/intern/cycles/kernel/bvh/util.h b/intern/cycles/kernel/bvh/util.h index a57703a8b8c..9ba787550c5 100644 --- a/intern/cycles/kernel/bvh/util.h +++ b/intern/cycles/kernel/bvh/util.h @@ -190,10 +190,8 @@ ccl_device_inline int intersection_find_attribute(KernelGlobals kg, /* Cut-off value to stop transparent shadow tracing when practically opaque. */ #define CURVE_SHADOW_TRANSPARENCY_CUTOFF 0.001f -ccl_device_inline float intersection_curve_shadow_transparency(KernelGlobals kg, - const int object, - const int prim, - const float u) +ccl_device_inline float intersection_curve_shadow_transparency( + KernelGlobals kg, const int object, const int prim, const int type, const float u) { /* Find attribute. */ const int offset = intersection_find_attribute(kg, object, ATTR_STD_SHADOW_TRANSPARENCY); @@ -204,7 +202,7 @@ ccl_device_inline float intersection_curve_shadow_transparency(KernelGlobals kg, /* Interpolate transparency between curve keys. */ const KernelCurve kcurve = kernel_data_fetch(curves, prim); - const int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(kcurve.type); + const int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(type); const int k1 = k0 + 1; const float f0 = kernel_data_fetch(attributes_float, offset + k0); diff --git a/intern/cycles/kernel/device/cpu/bvh.h b/intern/cycles/kernel/device/cpu/bvh.h index d9267e1cd6d..2d7d8c2d704 100644 --- a/intern/cycles/kernel/device/cpu/bvh.h +++ b/intern/cycles/kernel/device/cpu/bvh.h @@ -252,7 +252,7 @@ ccl_device void kernel_embree_filter_occluded_func(const RTCFilterFunctionNArgum /* Always use baked shadow transparency for curves. */ if (current_isect.type & PRIMITIVE_CURVE) { ctx->throughput *= intersection_curve_shadow_transparency( - kg, current_isect.object, current_isect.prim, current_isect.u); + kg, current_isect.object, current_isect.prim, current_isect.type, current_isect.u); if (ctx->throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) { ctx->opaque_hit = true; diff --git a/intern/cycles/kernel/device/gpu/parallel_active_index.h b/intern/cycles/kernel/device/gpu/parallel_active_index.h index c1df49c4f49..38cdcb572eb 100644 --- a/intern/cycles/kernel/device/gpu/parallel_active_index.h +++ b/intern/cycles/kernel/device/gpu/parallel_active_index.h @@ -23,22 +23,6 @@ CCL_NAMESPACE_BEGIN * and keep device specific code in compat.h */ #ifdef __KERNEL_ONEAPI__ -# ifdef WITH_ONEAPI_SYCL_HOST_ENABLED -template<typename IsActiveOp> -void cpu_serial_active_index_array_impl(const uint num_states, - ccl_global int *ccl_restrict indices, - ccl_global int *ccl_restrict num_indices, - IsActiveOp is_active_op) -{ - int write_index = 0; - for (int state_index = 0; state_index < num_states; state_index++) { - if (is_active_op(state_index)) - indices[write_index++] = state_index; - } - *num_indices = write_index; - return; -} -# endif /* WITH_ONEAPI_SYCL_HOST_ENABLED */ template<typename IsActiveOp> void gpu_parallel_active_index_array_impl(const uint num_states, @@ -182,18 +166,11 @@ __device__ num_simd_groups, \ simdgroup_offset) #elif defined(__KERNEL_ONEAPI__) -# ifdef WITH_ONEAPI_SYCL_HOST_ENABLED -# define gpu_parallel_active_index_array( \ - blocksize, num_states, indices, num_indices, is_active_op) \ - if (ccl_gpu_global_size_x() == 1) \ - cpu_serial_active_index_array_impl(num_states, indices, num_indices, is_active_op); \ - else \ - gpu_parallel_active_index_array_impl(num_states, indices, num_indices, is_active_op); -# else -# define gpu_parallel_active_index_array( \ - blocksize, num_states, indices, num_indices, is_active_op) \ - gpu_parallel_active_index_array_impl(num_states, indices, num_indices, is_active_op) -# endif + +# define gpu_parallel_active_index_array( \ + blocksize, num_states, indices, num_indices, is_active_op) \ + gpu_parallel_active_index_array_impl(num_states, indices, num_indices, is_active_op) + #else # define gpu_parallel_active_index_array( \ diff --git a/intern/cycles/kernel/device/metal/context_begin.h b/intern/cycles/kernel/device/metal/context_begin.h index 99cb1e3826e..e75ec9cadec 100644 --- a/intern/cycles/kernel/device/metal/context_begin.h +++ b/intern/cycles/kernel/device/metal/context_begin.h @@ -34,21 +34,48 @@ class MetalKernelContext { kernel_assert(0); return 0; } - + +#ifdef __KERNEL_METAL_INTEL__ + template<typename TextureType, typename CoordsType> + inline __attribute__((__always_inline__)) + auto ccl_gpu_tex_object_read_intel_workaround(TextureType texture_array, + const uint tid, const uint sid, + CoordsType coords) const + { + switch(sid) { + default: + case 0: return texture_array[tid].tex.sample(sampler(address::repeat, filter::nearest), coords); + case 1: return texture_array[tid].tex.sample(sampler(address::clamp_to_edge, filter::nearest), coords); + case 2: return texture_array[tid].tex.sample(sampler(address::clamp_to_zero, filter::nearest), coords); + case 3: return texture_array[tid].tex.sample(sampler(address::repeat, filter::linear), coords); + case 4: return texture_array[tid].tex.sample(sampler(address::clamp_to_edge, filter::linear), coords); + case 5: return texture_array[tid].tex.sample(sampler(address::clamp_to_zero, filter::linear), coords); + } + } +#endif + // texture2d template<> inline __attribute__((__always_inline__)) float4 ccl_gpu_tex_object_read_2D(ccl_gpu_tex_object_2D tex, float x, float y) const { const uint tid(tex); const uint sid(tex >> 32); +#ifndef __KERNEL_METAL_INTEL__ return metal_ancillaries->textures_2d[tid].tex.sample(metal_samplers[sid], float2(x, y)); +#else + return ccl_gpu_tex_object_read_intel_workaround(metal_ancillaries->textures_2d, tid, sid, float2(x, y)); +#endif } template<> inline __attribute__((__always_inline__)) float ccl_gpu_tex_object_read_2D(ccl_gpu_tex_object_2D tex, float x, float y) const { const uint tid(tex); const uint sid(tex >> 32); +#ifndef __KERNEL_METAL_INTEL__ return metal_ancillaries->textures_2d[tid].tex.sample(metal_samplers[sid], float2(x, y)).x; +#else + return ccl_gpu_tex_object_read_intel_workaround(metal_ancillaries->textures_2d, tid, sid, float2(x, y)).x; +#endif } // texture3d @@ -57,14 +84,22 @@ class MetalKernelContext { float4 ccl_gpu_tex_object_read_3D(ccl_gpu_tex_object_3D tex, float x, float y, float z) const { const uint tid(tex); const uint sid(tex >> 32); +#ifndef __KERNEL_METAL_INTEL__ return metal_ancillaries->textures_3d[tid].tex.sample(metal_samplers[sid], float3(x, y, z)); +#else + return ccl_gpu_tex_object_read_intel_workaround(metal_ancillaries->textures_3d, tid, sid, float3(x, y, z)); +#endif } template<> inline __attribute__((__always_inline__)) float ccl_gpu_tex_object_read_3D(ccl_gpu_tex_object_3D tex, float x, float y, float z) const { const uint tid(tex); const uint sid(tex >> 32); +#ifndef __KERNEL_METAL_INTEL__ return metal_ancillaries->textures_3d[tid].tex.sample(metal_samplers[sid], float3(x, y, z)).x; +#else + return ccl_gpu_tex_object_read_intel_workaround(metal_ancillaries->textures_3d, tid, sid, float3(x, y, z)).x; +#endif } # include "kernel/device/gpu/image.h" diff --git a/intern/cycles/kernel/device/metal/kernel.metal b/intern/cycles/kernel/device/metal/kernel.metal index 5646c7446db..8b69ee025cd 100644 --- a/intern/cycles/kernel/device/metal/kernel.metal +++ b/intern/cycles/kernel/device/metal/kernel.metal @@ -228,7 +228,7 @@ bool metalrt_shadow_all_hit(constant KernelParamsMetal &launch_params_metal, /* Always use baked shadow transparency for curves. */ if (type & PRIMITIVE_CURVE) { float throughput = payload.throughput; - throughput *= context.intersection_curve_shadow_transparency(nullptr, object, prim, u); + throughput *= context.intersection_curve_shadow_transparency(nullptr, object, prim, type, u); payload.throughput = throughput; payload.num_hits += 1; diff --git a/intern/cycles/kernel/device/oneapi/compat.h b/intern/cycles/kernel/device/oneapi/compat.h index 8ae40b0612e..dfaec65130c 100644 --- a/intern/cycles/kernel/device/oneapi/compat.h +++ b/intern/cycles/kernel/device/oneapi/compat.h @@ -55,18 +55,6 @@ #define ccl_gpu_kernel(block_num_threads, thread_num_registers) #define ccl_gpu_kernel_threads(block_num_threads) -#ifdef WITH_ONEAPI_SYCL_HOST_ENABLED -# define KG_ND_ITEMS \ - kg->nd_item_local_id_0 = item.get_local_id(0); \ - kg->nd_item_local_range_0 = item.get_local_range(0); \ - kg->nd_item_group_0 = item.get_group(0); \ - kg->nd_item_group_range_0 = item.get_group_range(0); \ - kg->nd_item_global_id_0 = item.get_global_id(0); \ - kg->nd_item_global_range_0 = item.get_global_range(0); -#else -# define KG_ND_ITEMS -#endif - #define ccl_gpu_kernel_signature(name, ...) \ void oneapi_kernel_##name(KernelGlobalsGPU *ccl_restrict kg, \ size_t kernel_global_size, \ @@ -76,8 +64,7 @@ void oneapi_kernel_##name(KernelGlobalsGPU *ccl_restrict kg, \ (kg); \ cgh.parallel_for<class kernel_##name>( \ sycl::nd_range<1>(kernel_global_size, kernel_local_size), \ - [=](sycl::nd_item<1> item) { \ - KG_ND_ITEMS + [=](sycl::nd_item<1> item) { #define ccl_gpu_kernel_postfix \ }); \ @@ -95,31 +82,17 @@ void oneapi_kernel_##name(KernelGlobalsGPU *ccl_restrict kg, \ } ccl_gpu_kernel_lambda_pass((ONEAPIKernelContext *)kg) /* GPU thread, block, grid size and index */ -#ifndef WITH_ONEAPI_SYCL_HOST_ENABLED -# define ccl_gpu_thread_idx_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_local_id(0)) -# define ccl_gpu_block_dim_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_local_range(0)) -# define ccl_gpu_block_idx_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_group(0)) -# define ccl_gpu_grid_dim_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_group_range(0)) -# define ccl_gpu_warp_size (sycl::ext::oneapi::experimental::this_sub_group().get_local_range()[0]) -# define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp)) - -# define ccl_gpu_global_id_x() (sycl::ext::oneapi::experimental::this_nd_item<1>().get_global_id(0)) -# define ccl_gpu_global_size_x() (sycl::ext::oneapi::experimental::this_nd_item<1>().get_global_range(0)) -#else -# define ccl_gpu_thread_idx_x (kg->nd_item_local_id_0) -# define ccl_gpu_block_dim_x (kg->nd_item_local_range_0) -# define ccl_gpu_block_idx_x (kg->nd_item_group_0) -# define ccl_gpu_grid_dim_x (kg->nd_item_group_range_0) -# define ccl_gpu_warp_size (sycl::ext::oneapi::experimental::this_sub_group().get_local_range()[0]) -# define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp)) - -# define ccl_gpu_global_id_x() (kg->nd_item_global_id_0) -# define ccl_gpu_global_size_x() (kg->nd_item_global_range_0) -#endif +#define ccl_gpu_thread_idx_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_local_id(0)) +#define ccl_gpu_block_dim_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_local_range(0)) +#define ccl_gpu_block_idx_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_group(0)) +#define ccl_gpu_grid_dim_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_group_range(0)) +#define ccl_gpu_warp_size (sycl::ext::oneapi::experimental::this_sub_group().get_local_range()[0]) +#define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp)) +#define ccl_gpu_global_id_x() (sycl::ext::oneapi::experimental::this_nd_item<1>().get_global_id(0)) +#define ccl_gpu_global_size_x() (sycl::ext::oneapi::experimental::this_nd_item<1>().get_global_range(0)) /* GPU warp synchronization */ - #define ccl_gpu_syncthreads() sycl::ext::oneapi::experimental::this_nd_item<1>().barrier() #define ccl_gpu_local_syncthreads() sycl::ext::oneapi::experimental::this_nd_item<1>().barrier(sycl::access::fence_space::local_space) #ifdef __SYCL_DEVICE_ONLY__ diff --git a/intern/cycles/kernel/device/oneapi/globals.h b/intern/cycles/kernel/device/oneapi/globals.h index d60f4f135ba..116620eb725 100644 --- a/intern/cycles/kernel/device/oneapi/globals.h +++ b/intern/cycles/kernel/device/oneapi/globals.h @@ -23,15 +23,6 @@ typedef struct KernelGlobalsGPU { #undef KERNEL_DATA_ARRAY IntegratorStateGPU *integrator_state; const KernelData *__data; -#ifdef WITH_ONEAPI_SYCL_HOST_ENABLED - size_t nd_item_local_id_0; - size_t nd_item_local_range_0; - size_t nd_item_group_0; - size_t nd_item_group_range_0; - - size_t nd_item_global_id_0; - size_t nd_item_global_range_0; -#endif } KernelGlobalsGPU; typedef ccl_global KernelGlobalsGPU *ccl_restrict KernelGlobals; diff --git a/intern/cycles/kernel/device/oneapi/kernel.cpp b/intern/cycles/kernel/device/oneapi/kernel.cpp index 40e0b1f0b2b..525ae288f0c 100644 --- a/intern/cycles/kernel/device/oneapi/kernel.cpp +++ b/intern/cycles/kernel/device/oneapi/kernel.cpp @@ -8,7 +8,7 @@ # include <map> # include <set> -# include <CL/sycl.hpp> +# include <sycl/sycl.hpp> # include "kernel/device/oneapi/compat.h" # include "kernel/device/oneapi/globals.h" @@ -144,6 +144,10 @@ size_t oneapi_kernel_preferred_local_size(SyclQueue *queue, bool oneapi_load_kernels(SyclQueue *queue_, const uint requested_features) { +# ifdef SYCL_SKIP_KERNELS_PRELOAD + (void)queue_; + (void)requested_features; +# else assert(queue_); sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_); @@ -175,7 +179,7 @@ bool oneapi_load_kernels(SyclQueue *queue_, const uint requested_features) sycl::kernel_bundle<sycl::bundle_state::input> one_kernel_bundle = sycl::get_kernel_bundle<sycl::bundle_state::input>(queue->get_context(), {kernel_id}); - sycl::build(one_kernel_bundle, {queue->get_device()}, sycl::property::queue::in_order()); + sycl::build(one_kernel_bundle); } } catch (sycl::exception const &e) { @@ -184,7 +188,7 @@ bool oneapi_load_kernels(SyclQueue *queue_, const uint requested_features) } return false; } - +# endif return true; } @@ -226,13 +230,6 @@ bool oneapi_enqueue_kernel(KernelContext *kernel_context, /* NOTE(@nsirgien): As for now non-uniform work-groups don't work on most oneAPI devices, * we extend work size to fit uniformity requirements. */ global_size = groups_count * local_size; - -# ifdef WITH_ONEAPI_SYCL_HOST_ENABLED - if (queue->get_device().is_host()) { - global_size = 1; - local_size = 1; - } -# endif } /* Let the compiler throw an error if there are any kernels missing in this implementation. */ diff --git a/intern/cycles/kernel/device/optix/bvh.h b/intern/cycles/kernel/device/optix/bvh.h index fb9907709ce..6d81b44660c 100644 --- a/intern/cycles/kernel/device/optix/bvh.h +++ b/intern/cycles/kernel/device/optix/bvh.h @@ -202,7 +202,7 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit() /* Always use baked shadow transparency for curves. */ if (type & PRIMITIVE_CURVE) { float throughput = __uint_as_float(optixGetPayload_1()); - throughput *= intersection_curve_shadow_transparency(nullptr, object, prim, u); + throughput *= intersection_curve_shadow_transparency(nullptr, object, prim, type, u); optixSetPayload_1(__float_as_uint(throughput)); optixSetPayload_2(uint16_pack_to_uint(num_recorded_hits, num_hits + 1)); diff --git a/intern/ffmpeg/tests/ffmpeg_codecs.cc b/intern/ffmpeg/tests/ffmpeg_codecs.cc index d0c40736884..e5c33202417 100644 --- a/intern/ffmpeg/tests/ffmpeg_codecs.cc +++ b/intern/ffmpeg/tests/ffmpeg_codecs.cc @@ -130,6 +130,7 @@ FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_DVVIDEO, AV_PIX_FMT_YUV420P) FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_MPEG1VIDEO, AV_PIX_FMT_YUV420P) FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_MPEG2VIDEO, AV_PIX_FMT_YUV420P) FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_FLV1, AV_PIX_FMT_YUV420P) +FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_AV1, AV_PIX_FMT_YUV420P) /* Audio codecs */ @@ -149,6 +150,12 @@ FFMPEG_TEST_VCODEC_NAME(libx264, AV_PIX_FMT_YUV420P) FFMPEG_TEST_VCODEC_NAME(libvpx, AV_PIX_FMT_YUV420P) FFMPEG_TEST_VCODEC_NAME(libopenjpeg, AV_PIX_FMT_YUV420P) FFMPEG_TEST_VCODEC_NAME(libxvid, AV_PIX_FMT_YUV420P) +/* aom's AV1 encoder is "libaom-av1". FFMPEG_TEST_VCODEC_NAME(libaom-av1, ...) + * will not work because the dash will not work with the test macro. */ +TEST(ffmpeg, libaom_av1_AV_PIX_FMT_YUV420P) +{ + EXPECT_TRUE(test_codec_video_by_name("libaom-av1", AV_PIX_FMT_YUV420P)); +} FFMPEG_TEST_ACODEC_NAME(libvorbis, AV_SAMPLE_FMT_FLTP) FFMPEG_TEST_ACODEC_NAME(libopus, AV_SAMPLE_FMT_FLT) FFMPEG_TEST_ACODEC_NAME(libmp3lame, AV_SAMPLE_FMT_FLTP) diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index 2f8ea1f9065..fb10530bfae 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -268,7 +268,7 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND) if(WITH_GHOST_WAYLAND_DYNLOAD) list(APPEND INC_SYS - ../../intern/wayland_dynload/extern + ../wayland_dynload/extern ) list(APPEND LIB bf_intern_wayland_dynload @@ -372,10 +372,18 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND) generate_protocol_bindings( "${WAYLAND_PROTOCOLS_DIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml" ) + # Pointer-gestures (multi-touch). + generate_protocol_bindings( + "${WAYLAND_PROTOCOLS_DIR}/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml" + ) # Tablet. generate_protocol_bindings( "${WAYLAND_PROTOCOLS_DIR}/unstable/tablet/tablet-unstable-v2.xml" ) + # Primary-selection. + generate_protocol_bindings( + "${WAYLAND_PROTOCOLS_DIR}/unstable/primary-selection/primary-selection-unstable-v1.xml" + ) add_definitions(-DWITH_GHOST_WAYLAND) diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index 7fda535a7ac..62984c762c1 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -162,7 +162,6 @@ extern void GHOST_GetAllDisplayDimensions(GHOST_SystemHandle systemhandle, * \param height: The height the window. * \param state: The state of the window when opened. * \param is_dialog: Stay on top of parent window, no icon in taskbar, can't be minimized. - * \param type: The type of drawing context installed in this window. * \param glSettings: Misc OpenGL options. * \return A handle to the new window ( == NULL if creation failed). */ @@ -175,7 +174,6 @@ extern GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle, uint32_t height, GHOST_TWindowState state, bool is_dialog, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings); /** diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h index 9fb94ed1525..64b5f4ee496 100644 --- a/intern/ghost/GHOST_ISystem.h +++ b/intern/ghost/GHOST_ISystem.h @@ -232,7 +232,6 @@ class GHOST_ISystem { * \param width: The width the window. * \param height: The height the window. * \param state: The state of the window when opened. - * \param type: The type of drawing context installed in this window. * \param glSettings: Misc OpenGL settings. * \param exclusive: Use to show the window on top and ignore others (used full-screen). * \param is_dialog: Stay on top of parent window, no icon in taskbar, can't be minimized. @@ -245,7 +244,6 @@ class GHOST_ISystem { uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive = false, const bool is_dialog = false, diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 2645ce448b0..db4eeff3122 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -60,10 +60,6 @@ typedef struct { int hot_spot[2]; } GHOST_CursorBitmapRef; -typedef struct { - int flags; -} GHOST_GLSettings; - typedef enum { GHOST_glStereoVisual = (1 << 0), GHOST_glDebugContext = (1 << 1), @@ -157,6 +153,9 @@ typedef enum { #ifdef WIN32 GHOST_kDrawingContextTypeD3D, #endif +#ifdef __APPLE__ + GHOST_kDrawingContextTypeMetal, +#endif } GHOST_TDrawingContextType; typedef enum { @@ -598,6 +597,11 @@ typedef struct { uint32_t frequency; } GHOST_DisplaySetting; +typedef struct { + int flags; + GHOST_TDrawingContextType context_type; +} GHOST_GLSettings; + typedef enum { /** Axis that cursor grab will wrap. */ GHOST_kDebugDefault = (1 << 1), diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index 158e979cdf2..aa2363c10b3 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -161,7 +161,6 @@ GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle, uint32_t height, GHOST_TWindowState state, bool is_dialog, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings) { GHOST_ISystem *system = (GHOST_ISystem *)systemhandle; @@ -172,7 +171,6 @@ GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle, width, height, state, - type, glSettings, false, is_dialog, diff --git a/intern/ghost/intern/GHOST_ContextCGL.h b/intern/ghost/intern/GHOST_ContextCGL.h index 130b926f25c..d19fffffb43 100644 --- a/intern/ghost/intern/GHOST_ContextCGL.h +++ b/intern/ghost/intern/GHOST_ContextCGL.h @@ -30,7 +30,8 @@ class GHOST_ContextCGL : public GHOST_Context { GHOST_ContextCGL(bool stereoVisual, NSView *metalView, CAMetalLayer *metalLayer, - NSOpenGLView *openglView); + NSOpenGLView *openglView, + GHOST_TDrawingContextType type); /** * Destructor. diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm index ff53ecdbbba..9dad337a5d6 100644 --- a/intern/ghost/intern/GHOST_ContextCGL.mm +++ b/intern/ghost/intern/GHOST_ContextCGL.mm @@ -46,8 +46,10 @@ int GHOST_ContextCGL::s_sharedCount = 0; GHOST_ContextCGL::GHOST_ContextCGL(bool stereoVisual, NSView *metalView, CAMetalLayer *metalLayer, - NSOpenGLView *openGLView) + NSOpenGLView *openGLView, + GHOST_TDrawingContextType type) : GHOST_Context(stereoVisual), + m_useMetalForRendering(type == GHOST_kDrawingContextTypeMetal), m_metalView(metalView), m_metalLayer(metalLayer), m_metalCmdQueue(nil), diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp index f4c726c7450..9e9b9f14c43 100644 --- a/intern/ghost/intern/GHOST_NDOFManager.cpp +++ b/intern/ghost/intern/GHOST_NDOFManager.cpp @@ -12,11 +12,14 @@ #include <climits> #include <cmath> -#include <cstdio> /* For error/info reporting. */ #include <cstring> /* For memory functions. */ -/* Printable version of each GHOST_TProgress value. */ -static const char *progress_string[] = { +/* -------------------------------------------------------------------- */ +/** \name NDOF Enum Strings + * \{ */ + +/* Printable values for #GHOST_TProgress enum (keep aligned). */ +static const char *ndof_progress_string[] = { "not started", "starting", "in progress", @@ -24,41 +27,30 @@ static const char *progress_string[] = { "finished", }; +/* Printable values for #NDOF_ButtonT enum (keep aligned) */ static const char *ndof_button_names[] = { - /* used internally, never sent */ - "NDOF_BUTTON_NONE", - /* these two are available from any 3Dconnexion device */ + /* Exclude `NDOF_BUTTON_NONE` (-1). */ "NDOF_BUTTON_MENU", "NDOF_BUTTON_FIT", - /* standard views */ "NDOF_BUTTON_TOP", "NDOF_BUTTON_BOTTOM", "NDOF_BUTTON_LEFT", "NDOF_BUTTON_RIGHT", "NDOF_BUTTON_FRONT", "NDOF_BUTTON_BACK", - /* more views */ "NDOF_BUTTON_ISO1", "NDOF_BUTTON_ISO2", - /* 90 degree rotations */ "NDOF_BUTTON_ROLL_CW", "NDOF_BUTTON_ROLL_CCW", "NDOF_BUTTON_SPIN_CW", "NDOF_BUTTON_SPIN_CCW", "NDOF_BUTTON_TILT_CW", "NDOF_BUTTON_TILT_CCW", - /* device control */ "NDOF_BUTTON_ROTATE", "NDOF_BUTTON_PANZOOM", "NDOF_BUTTON_DOMINANT", "NDOF_BUTTON_PLUS", "NDOF_BUTTON_MINUS", - /* keyboard emulation */ - "NDOF_BUTTON_ESC", - "NDOF_BUTTON_ALT", - "NDOF_BUTTON_SHIFT", - "NDOF_BUTTON_CTRL", - /* general-purpose buttons */ "NDOF_BUTTON_1", "NDOF_BUTTON_2", "NDOF_BUTTON_3", @@ -69,18 +61,47 @@ static const char *ndof_button_names[] = { "NDOF_BUTTON_8", "NDOF_BUTTON_9", "NDOF_BUTTON_10", - /* more general-purpose buttons */ "NDOF_BUTTON_A", "NDOF_BUTTON_B", "NDOF_BUTTON_C", - /* the end */ - "NDOF_BUTTON_LAST", + "NDOF_BUTTON_V1", + "NDOF_BUTTON_V2", + "NDOF_BUTTON_V3", + /* Keyboard emulation. */ + "NDOF_BUTTON_ESC", + "NDOF_BUTTON_ENTER", + "NDOF_BUTTON_DELETE", + "NDOF_BUTTON_TAB", + "NDOF_BUTTON_SPACE", + "NDOF_BUTTON_ALT", + "NDOF_BUTTON_SHIFT", + "NDOF_BUTTON_CTRL", }; +static const char *ndof_device_names[] = { + "UnknownDevice", + "SpaceNavigator", + "SpaceExplorer", + "SpacePilotPro", + "SpaceMousePro", + "SpaceMouseWireless", + "SpaceMouseProWireless", + "SpaceMouseEnterprise", + "SpacePilot", + "Spaceball5000", + "SpaceTraveler", +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name NDOF Button Maps + * \{ */ + /* Shared by the latest 3Dconnexion hardware * SpacePilotPro uses all of these * smaller devices use only some, based on button mask. */ -static const NDOF_ButtonT Modern3Dx_HID_map[] = { +static const NDOF_ButtonT ndof_HID_map_Modern3Dx[] = { NDOF_BUTTON_MENU, NDOF_BUTTON_FIT, NDOF_BUTTON_TOP, NDOF_BUTTON_LEFT, NDOF_BUTTON_RIGHT, NDOF_BUTTON_FRONT, NDOF_BUTTON_BOTTOM, NDOF_BUTTON_BACK, NDOF_BUTTON_ROLL_CW, NDOF_BUTTON_ROLL_CCW, NDOF_BUTTON_ISO1, NDOF_BUTTON_ISO2, @@ -90,7 +111,7 @@ static const NDOF_ButtonT Modern3Dx_HID_map[] = { NDOF_BUTTON_SHIFT, NDOF_BUTTON_CTRL, NDOF_BUTTON_ROTATE, NDOF_BUTTON_PANZOOM, NDOF_BUTTON_DOMINANT, NDOF_BUTTON_PLUS, NDOF_BUTTON_MINUS}; -static const NDOF_ButtonT SpaceExplorer_HID_map[] = { +static const NDOF_ButtonT ndof_HID_map_SpaceExplorer[] = { NDOF_BUTTON_1, NDOF_BUTTON_2, NDOF_BUTTON_TOP, @@ -108,9 +129,8 @@ static const NDOF_ButtonT SpaceExplorer_HID_map[] = { NDOF_BUTTON_ROTATE, }; -/* This is the older SpacePilot (sans Pro) - * thanks to polosson for info about this device. */ -static const NDOF_ButtonT SpacePilot_HID_map[] = { +/* This is the older SpacePilot (sans Pro). */ +static const NDOF_ButtonT ndof_HID_map_SpacePilot[] = { NDOF_BUTTON_1, NDOF_BUTTON_2, NDOF_BUTTON_3, NDOF_BUTTON_4, NDOF_BUTTON_5, NDOF_BUTTON_6, NDOF_BUTTON_TOP, NDOF_BUTTON_LEFT, NDOF_BUTTON_RIGHT, NDOF_BUTTON_FRONT, NDOF_BUTTON_ESC, NDOF_BUTTON_ALT, @@ -119,7 +139,7 @@ static const NDOF_ButtonT SpacePilot_HID_map[] = { NDOF_BUTTON_NONE /* the CONFIG button -- what does it do? */ }; -static const NDOF_ButtonT Generic_HID_map[] = { +static const NDOF_ButtonT ndof_HID_map_Generic[] = { NDOF_BUTTON_1, NDOF_BUTTON_2, NDOF_BUTTON_3, @@ -134,27 +154,70 @@ static const NDOF_ButtonT Generic_HID_map[] = { NDOF_BUTTON_C, }; -static const int genericButtonCount = ARRAY_SIZE(Generic_HID_map); +/* Values taken from: https://github.com/FreeSpacenav/spacenavd/wiki/Device-button-names */ +static const NDOF_ButtonT ndof_HID_map_SpaceMouseEnterprise[] = { + NDOF_BUTTON_1, /* (0) */ + NDOF_BUTTON_2, /* (1) */ + NDOF_BUTTON_3, /* (2) */ + NDOF_BUTTON_4, /* (3) */ + NDOF_BUTTON_5, /* (4) */ + NDOF_BUTTON_6, /* (5) */ + NDOF_BUTTON_7, /* (6) */ + NDOF_BUTTON_8, /* (7) */ + NDOF_BUTTON_9, /* (8) */ + NDOF_BUTTON_A, /* Labeled "10" (9). */ + NDOF_BUTTON_B, /* Labeled "11" (10). */ + NDOF_BUTTON_C, /* Labeled "12" (11). */ + NDOF_BUTTON_MENU, /* (12). */ + NDOF_BUTTON_FIT, /* (13). */ + NDOF_BUTTON_TOP, /* (14). */ + NDOF_BUTTON_RIGHT, /* (15). */ + NDOF_BUTTON_FRONT, /* (16). */ + NDOF_BUTTON_ROLL_CW, /* (17). */ + NDOF_BUTTON_ESC, /* (18). */ + NDOF_BUTTON_ALT, /* (19). */ + NDOF_BUTTON_SHIFT, /* (20). */ + NDOF_BUTTON_CTRL, /* (21). */ + NDOF_BUTTON_ROTATE, /* Labeled "Lock Rotate" (22). */ + NDOF_BUTTON_ENTER, /* Labeled "Enter" (23). */ + NDOF_BUTTON_DELETE, /* (24). */ + NDOF_BUTTON_TAB, /* (25). */ + NDOF_BUTTON_SPACE, /* (26). */ + NDOF_BUTTON_V1, /* Labeled "V1" (27). */ + NDOF_BUTTON_V2, /* Labeled "V2" (28). */ + NDOF_BUTTON_V3, /* Labeled "V3" (29). */ + NDOF_BUTTON_ISO1, /* Labeled "ISO1" (30). */ +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name NDOF Manager Class + * \{ */ + +static const int genericButtonCount = ARRAY_SIZE(ndof_HID_map_Generic); GHOST_NDOFManager::GHOST_NDOFManager(GHOST_System &sys) - : m_system(sys), - m_deviceType(NDOF_UnknownDevice), /* Each platform has its own device detection code. */ - m_buttonCount(genericButtonCount), - m_buttonMask(0), - m_hidMap(Generic_HID_map), - m_buttons(0), - m_motionTime(0), - m_prevMotionTime(0), - m_motionState(GHOST_kNotStarted), - m_motionEventPending(false), - m_deadZone(0.0f) + : system_(sys), + device_type_(NDOF_UnknownDevice), /* Each platform has its own device detection code. */ + hid_map_button_num_(genericButtonCount), + hid_map_button_mask_(0), + hid_map_(ndof_HID_map_Generic), + button_depressed_(0), + motion_time_(0), + motion_time_prev_(0), + motion_state_(GHOST_kNotStarted), + motion_event_pending_(false), + motion_dead_zone_(0.0f) { /* To avoid the rare situation where one triple is updated and * the other is not, initialize them both here: */ - memset(m_translation, 0, sizeof(m_translation)); - memset(m_rotation, 0, sizeof(m_rotation)); + memset(translation_, 0, sizeof(translation_)); + memset(rotation_, 0, sizeof(rotation_)); } +/** \} */ + /* -------------------------------------------------------------------- */ /** \name NDOF Device Setup * \{ */ @@ -166,16 +229,16 @@ bool GHOST_NDOFManager::setDevice(ushort vendor_id, ushort product_id) { /* Call this function until it returns true * it's a good idea to stop calling it after that, as it will "forget" - * whichever device it already found */ + * whichever device it already found. */ /* Default to safe generic behavior for "unknown" devices * unidentified devices will emit motion events like normal * rogue buttons do nothing by default, but can be customized by the user. */ - m_deviceType = NDOF_UnknownDevice; - m_hidMap = Generic_HID_map; - m_buttonCount = genericButtonCount; - m_buttonMask = 0; + device_type_ = NDOF_UnknownDevice; + hid_map_ = ndof_HID_map_Generic; + hid_map_button_num_ = genericButtonCount; + hid_map_button_mask_ = 0; /* "mystery device" owners can help build a HID_map for their hardware * A few users have already contributed information about several older devices @@ -185,96 +248,101 @@ bool GHOST_NDOFManager::setDevice(ushort vendor_id, ushort product_id) case 0x046D: /* Logitech (3Dconnexion was a subsidiary). */ switch (product_id) { /* -- current devices -- */ - case 0xC626: /* full-size SpaceNavigator */ - case 0xC628: /* the "for Notebooks" one */ - puts("ndof: using SpaceNavigator"); - m_deviceType = NDOF_SpaceNavigator; - m_buttonCount = 2; - m_hidMap = Modern3Dx_HID_map; + case 0xC626: /* Full-size SpaceNavigator. */ + case 0xC628: /* The "for Notebooks" one. */ + { + device_type_ = NDOF_SpaceNavigator; + hid_map_button_num_ = 2; + hid_map_ = ndof_HID_map_Modern3Dx; break; - case 0xC627: - puts("ndof: using SpaceExplorer"); - m_deviceType = NDOF_SpaceExplorer; - m_buttonCount = 15; - m_hidMap = SpaceExplorer_HID_map; + } + case 0xC627: { + device_type_ = NDOF_SpaceExplorer; + hid_map_button_num_ = 15; + hid_map_ = ndof_HID_map_SpaceExplorer; break; - case 0xC629: - puts("ndof: using SpacePilot Pro"); - m_deviceType = NDOF_SpacePilotPro; - m_buttonCount = 31; - m_hidMap = Modern3Dx_HID_map; + } + case 0xC629: { + device_type_ = NDOF_SpacePilotPro; + hid_map_button_num_ = 31; + hid_map_ = ndof_HID_map_Modern3Dx; break; - case 0xC62B: - puts("ndof: using SpaceMouse Pro"); - m_deviceType = NDOF_SpaceMousePro; - m_buttonCount = 27; - /* ^^ actually has 15 buttons, but their HID codes range from 0 to 26 */ - m_buttonMask = 0x07C0F137; - m_hidMap = Modern3Dx_HID_map; + } + case 0xC62B: { + device_type_ = NDOF_SpaceMousePro; + hid_map_button_num_ = 27; /* 15 physical buttons, but HID codes range from 0 to 26. */ + hid_map_button_mask_ = 0x07C0F137; + hid_map_ = ndof_HID_map_Modern3Dx; break; + } /* -- older devices -- */ - case 0xC625: - puts("ndof: using SpacePilot"); - m_deviceType = NDOF_SpacePilot; - m_buttonCount = 21; - m_hidMap = SpacePilot_HID_map; + case 0xC625: { + device_type_ = NDOF_SpacePilot; + hid_map_button_num_ = 21; + hid_map_ = ndof_HID_map_SpacePilot; break; - case 0xC621: - puts("ndof: using Spaceball 5000"); - m_deviceType = NDOF_Spaceball5000; - m_buttonCount = 12; + } + case 0xC621: { + device_type_ = NDOF_Spaceball5000; + hid_map_button_num_ = 12; break; - case 0xC623: - puts("ndof: using SpaceTraveler"); - m_deviceType = NDOF_SpaceTraveler; - m_buttonCount = 8; + } + case 0xC623: { + device_type_ = NDOF_SpaceTraveler; + hid_map_button_num_ = 8; break; - - default: - printf("ndof: unknown Logitech product %04hx\n", product_id); + } + default: { + CLOG_INFO(LOG, 2, "unknown Logitech product %04hx", product_id); + } } break; - case 0x256F: /* 3Dconnexion */ + case 0x256F: /* 3Dconnexion. */ switch (product_id) { case 0xC62E: /* Plugged in. */ case 0xC62F: /* Wireless. */ - puts("ndof: using SpaceMouse Wireless"); - m_deviceType = NDOF_SpaceMouseWireless; - m_buttonCount = 2; - m_hidMap = Modern3Dx_HID_map; + { + device_type_ = NDOF_SpaceMouseWireless; + hid_map_button_num_ = 2; + hid_map_ = ndof_HID_map_Modern3Dx; break; + } case 0xC631: /* Plugged in. */ case 0xC632: /* Wireless. */ - puts("ndof: using SpaceMouse Pro Wireless"); - m_deviceType = NDOF_SpaceMouseProWireless; - m_buttonCount = 27; - /* ^^ actually has 15 buttons, but their HID codes range from 0 to 26. */ - m_buttonMask = 0x07C0F137; - m_hidMap = Modern3Dx_HID_map; + { + device_type_ = NDOF_SpaceMouseProWireless; + hid_map_button_num_ = 27; /* 15 physical buttons, but HID codes range from 0 to 26. */ + hid_map_button_mask_ = 0x07C0F137; + hid_map_ = ndof_HID_map_Modern3Dx; break; - case 0xC633: - puts("ndof: using SpaceMouse Enterprise"); - m_deviceType = NDOF_SpaceMouseEnterprise; - m_buttonCount = 31; - m_hidMap = Modern3Dx_HID_map; + } + case 0xC633: { + device_type_ = NDOF_SpaceMouseEnterprise; + hid_map_button_num_ = 31; + hid_map_ = ndof_HID_map_SpaceMouseEnterprise; break; - - default: - printf("ndof: unknown 3Dconnexion product %04hx\n", product_id); + } + default: { + CLOG_INFO(LOG, 2, "unknown 3Dconnexion product %04hx", product_id); + } } break; default: - printf("ndof: unknown device %04hx:%04hx\n", vendor_id, product_id); + CLOG_INFO(LOG, 2, "unknown device %04hx:%04hx", vendor_id, product_id); + } + + if (device_type_ != NDOF_UnknownDevice) { + CLOG_INFO(LOG, 2, "using %s", ndof_device_names[device_type_]); } - if (m_buttonMask == 0) { - m_buttonMask = int(~(UINT_MAX << m_buttonCount)); + if (hid_map_button_mask_ == 0) { + hid_map_button_mask_ = int(~(UINT_MAX << hid_map_button_num_)); } - CLOG_INFO(LOG, 2, "%d buttons -> hex:%X", m_buttonCount, (uint)m_buttonMask); + CLOG_INFO(LOG, 2, "%d buttons -> hex:%X", hid_map_button_num_, (uint)hid_map_button_mask_); - return m_deviceType != NDOF_UnknownDevice; + return device_type_ != NDOF_UnknownDevice; } #undef LOG @@ -287,16 +355,16 @@ bool GHOST_NDOFManager::setDevice(ushort vendor_id, ushort product_id) void GHOST_NDOFManager::updateTranslation(const int t[3], uint64_t time) { - memcpy(m_translation, t, sizeof(m_translation)); - m_motionTime = time; - m_motionEventPending = true; + memcpy(translation_, t, sizeof(translation_)); + motion_time_ = time; + motion_event_pending_ = true; } void GHOST_NDOFManager::updateRotation(const int r[3], uint64_t time) { - memcpy(m_rotation, r, sizeof(m_rotation)); - m_motionTime = time; - m_motionEventPending = true; + memcpy(rotation_, r, sizeof(rotation_)); + motion_time_ = time; + motion_event_pending_ = true; } /** \} */ @@ -314,6 +382,18 @@ static GHOST_TKey ghost_map_keyboard_from_ndof_buttom(const NDOF_ButtonT button) case NDOF_BUTTON_ESC: { return GHOST_kKeyEsc; } + case NDOF_BUTTON_ENTER: { + return GHOST_kKeyEnter; + } + case NDOF_BUTTON_DELETE: { + return GHOST_kKeyDelete; + } + case NDOF_BUTTON_TAB: { + return GHOST_kKeyTab; + } + case NDOF_BUTTON_SPACE: { + return GHOST_kKeySpace; + } case NDOF_BUTTON_ALT: { return GHOST_kKeyLeftAlt; } @@ -334,7 +414,7 @@ void GHOST_NDOFManager::sendButtonEvent(NDOF_ButtonT button, uint64_t time, GHOST_IWindow *window) { - GHOST_ASSERT(button > NDOF_BUTTON_NONE && button < NDOF_BUTTON_LAST, + GHOST_ASSERT(button > NDOF_BUTTON_NONE && button < NDOF_BUTTON_NUM, "rogue button trying to escape NDOF manager"); GHOST_EventNDOFButton *event = new GHOST_EventNDOFButton(time, window); @@ -343,7 +423,7 @@ void GHOST_NDOFManager::sendButtonEvent(NDOF_ButtonT button, data->action = press ? GHOST_kPress : GHOST_kRelease; data->button = button; - m_system.pushEvent(event); + system_.pushEvent(event); } void GHOST_NDOFManager::sendKeyEvent(GHOST_TKey key, @@ -354,21 +434,21 @@ void GHOST_NDOFManager::sendKeyEvent(GHOST_TKey key, GHOST_TEventType type = press ? GHOST_kEventKeyDown : GHOST_kEventKeyUp; GHOST_EventKey *event = new GHOST_EventKey(time, type, window, key, false); - m_system.pushEvent(event); + system_.pushEvent(event); } void GHOST_NDOFManager::updateButton(int button_number, bool press, uint64_t time) { - if (button_number >= m_buttonCount) { + if (button_number >= hid_map_button_num_) { CLOG_INFO(LOG, 2, "button=%d, press=%d (out of range %d, ignoring!)", button_number, (int)press, - m_buttonCount); + hid_map_button_num_); return; } - const NDOF_ButtonT button = m_hidMap[button_number]; + const NDOF_ButtonT button = hid_map_[button_number]; if (button == NDOF_BUTTON_NONE) { CLOG_INFO( LOG, 2, "button=%d, press=%d (mapped to none, ignoring!)", button_number, (int)press); @@ -382,7 +462,7 @@ void GHOST_NDOFManager::updateButton(int button_number, bool press, uint64_t tim (int)press, ndof_button_names[button]); - GHOST_IWindow *window = m_system.getWindowManager()->getActiveWindow(); + GHOST_IWindow *window = system_.getWindowManager()->getActiveWindow(); const GHOST_TKey key = ghost_map_keyboard_from_ndof_buttom(button); if (key != GHOST_kKeyUnknown) { sendKeyEvent(key, press, time, window); @@ -393,20 +473,20 @@ void GHOST_NDOFManager::updateButton(int button_number, bool press, uint64_t tim int mask = 1 << button_number; if (press) { - m_buttons |= mask; /* Set this button's bit. */ + button_depressed_ |= mask; /* Set this button's bit. */ } else { - m_buttons &= ~mask; /* Clear this button's bit. */ + button_depressed_ &= ~mask; /* Clear this button's bit. */ } } void GHOST_NDOFManager::updateButtons(int button_bits, uint64_t time) { - button_bits &= m_buttonMask; /* Discard any "garbage" bits. */ + button_bits &= hid_map_button_mask_; /* Discard any "garbage" bits. */ - int diff = m_buttons ^ button_bits; + int diff = button_depressed_ ^ button_bits; - for (int button_number = 0; button_number < m_buttonCount; ++button_number) { + for (int button_number = 0; button_number < hid_map_button_num_; ++button_number) { int mask = 1 << button_number; if (diff & mask) { @@ -433,7 +513,7 @@ void GHOST_NDOFManager::setDeadZone(float dz) /* Negative values don't make sense, so clamp at zero. */ dz = 0.0f; } - m_deadZone = dz; + motion_dead_zone_ = dz; /* Warn the rogue user/developer about high dead-zone, but allow it. */ CLOG_INFO(LOG, 2, "dead zone set to %.2f%s", dz, (dz > 0.5f) ? " (unexpectedly high)" : ""); @@ -458,20 +538,20 @@ static bool nearHomePosition(GHOST_TEventNDOFMotionData *ndof, float threshold) bool GHOST_NDOFManager::sendMotionEvent() { - if (!m_motionEventPending) { + if (!motion_event_pending_) { return false; } - m_motionEventPending = false; /* Any pending motion is handled right now. */ + motion_event_pending_ = false; /* Any pending motion is handled right now. */ - GHOST_IWindow *window = m_system.getWindowManager()->getActiveWindow(); + GHOST_IWindow *window = system_.getWindowManager()->getActiveWindow(); if (window == nullptr) { - m_motionState = GHOST_kNotStarted; /* Avoid large `dt` times when changing windows. */ + motion_state_ = GHOST_kNotStarted; /* Avoid large `dt` times when changing windows. */ return false; /* Delivery will fail, so don't bother sending. */ } - GHOST_EventNDOFMotion *event = new GHOST_EventNDOFMotion(m_motionTime, window); + GHOST_EventNDOFMotion *event = new GHOST_EventNDOFMotion(motion_time_, window); GHOST_TEventNDOFMotionData *data = (GHOST_TEventNDOFMotionData *)event->getData(); /* Scale axis values here to normalize them to around +/- 1 @@ -479,26 +559,26 @@ bool GHOST_NDOFManager::sendMotionEvent() const float scale = 1.0f / 350.0f; /* 3Dconnexion devices send +/- 350 usually */ - data->tx = scale * m_translation[0]; - data->ty = scale * m_translation[1]; - data->tz = scale * m_translation[2]; + data->tx = scale * translation_[0]; + data->ty = scale * translation_[1]; + data->tz = scale * translation_[2]; - data->rx = scale * m_rotation[0]; - data->ry = scale * m_rotation[1]; - data->rz = scale * m_rotation[2]; - data->dt = 0.001f * (m_motionTime - m_prevMotionTime); /* In seconds. */ - m_prevMotionTime = m_motionTime; + data->rx = scale * rotation_[0]; + data->ry = scale * rotation_[1]; + data->rz = scale * rotation_[2]; + data->dt = 0.001f * (motion_time_ - motion_time_prev_); /* In seconds. */ + motion_time_prev_ = motion_time_; - bool weHaveMotion = !nearHomePosition(data, m_deadZone); + bool weHaveMotion = !nearHomePosition(data, motion_dead_zone_); /* Determine what kind of motion event to send `(Starting, InProgress, Finishing)` * and where that leaves this NDOF manager `(NotStarted, InProgress, Finished)`. */ - switch (m_motionState) { + switch (motion_state_) { case GHOST_kNotStarted: case GHOST_kFinished: { if (weHaveMotion) { data->progress = GHOST_kStarting; - m_motionState = GHOST_kInProgress; + motion_state_ = GHOST_kInProgress; /* Previous motion time will be ancient, so just make up a reasonable time delta. */ data->dt = 0.0125f; } @@ -517,7 +597,7 @@ bool GHOST_NDOFManager::sendMotionEvent() } else { data->progress = GHOST_kFinishing; - m_motionState = GHOST_kFinished; + motion_state_ = GHOST_kFinished; } break; } @@ -538,21 +618,21 @@ bool GHOST_NDOFManager::sendMotionEvent() data->ry, data->rz, data->dt, - progress_string[data->progress]); + ndof_progress_string[data->progress]); #else /* Raw values, may be useful for debugging. */ CLOG_INFO(LOG, 2, "motion sent, T=(%d,%d,%d) R=(%d,%d,%d) status=%s", - m_translation[0], - m_translation[1], - m_translation[2], - m_rotation[0], - m_rotation[1], - m_rotation[2], - progress_string[data->progress]); + translation_[0], + translation_[1], + translation_[2], + rotation_[0], + rotation_[1], + rotation_[2], + ndof_progress_string[data->progress]); #endif - m_system.pushEvent(event); + system_.pushEvent(event); return true; } diff --git a/intern/ghost/intern/GHOST_NDOFManager.h b/intern/ghost/intern/GHOST_NDOFManager.h index 73c1b17f891..2d5bba14aa4 100644 --- a/intern/ghost/intern/GHOST_NDOFManager.h +++ b/intern/ghost/intern/GHOST_NDOFManager.h @@ -9,7 +9,7 @@ #include "GHOST_System.h" typedef enum { - NDOF_UnknownDevice, + NDOF_UnknownDevice = 0, /* Current devices. */ NDOF_SpaceNavigator, @@ -29,8 +29,8 @@ typedef enum { /* NDOF device button event types */ typedef enum { - /* Used internally, never sent. */ - NDOF_BUTTON_NONE = 0, + /* Used internally, never sent or used as an index. */ + NDOF_BUTTON_NONE = -1, /* These two are available from any 3Dconnexion device. */ NDOF_BUTTON_MENU, NDOF_BUTTON_FIT, @@ -58,11 +58,6 @@ typedef enum { NDOF_BUTTON_DOMINANT, NDOF_BUTTON_PLUS, NDOF_BUTTON_MINUS, - /* Keyboard emulation. */ - NDOF_BUTTON_ESC, - NDOF_BUTTON_ALT, - NDOF_BUTTON_SHIFT, - NDOF_BUTTON_CTRL, /* General-purpose buttons. * Users can assign functions via keymap editor. */ NDOF_BUTTON_1, @@ -79,8 +74,20 @@ typedef enum { NDOF_BUTTON_A, NDOF_BUTTON_B, NDOF_BUTTON_C, - /* The end. */ - NDOF_BUTTON_LAST + /* Store Views. */ + NDOF_BUTTON_V1, + NDOF_BUTTON_V2, + NDOF_BUTTON_V3, + /* Keyboard emulation. */ + NDOF_BUTTON_ESC, + NDOF_BUTTON_ENTER, + NDOF_BUTTON_DELETE, + NDOF_BUTTON_TAB, + NDOF_BUTTON_SPACE, + NDOF_BUTTON_ALT, + NDOF_BUTTON_SHIFT, + NDOF_BUTTON_CTRL, +#define NDOF_BUTTON_NUM (NDOF_BUTTON_CTRL + 1) } NDOF_ButtonT; class GHOST_NDOFManager { @@ -140,25 +147,25 @@ class GHOST_NDOFManager { bool sendMotionEvent(); protected: - GHOST_System &m_system; + GHOST_System &system_; private: void sendButtonEvent(NDOF_ButtonT, bool press, uint64_t time, GHOST_IWindow *); void sendKeyEvent(GHOST_TKey, bool press, uint64_t time, GHOST_IWindow *); - NDOF_DeviceT m_deviceType; - int m_buttonCount; - int m_buttonMask; - const NDOF_ButtonT *m_hidMap; + NDOF_DeviceT device_type_; + int hid_map_button_num_; + int hid_map_button_mask_; + const NDOF_ButtonT *hid_map_; - int m_translation[3]; - int m_rotation[3]; - int m_buttons; /* Bit field. */ + int translation_[3]; + int rotation_[3]; + int button_depressed_; /* Bit field. */ - uint64_t m_motionTime; /* In milliseconds. */ - uint64_t m_prevMotionTime; /* Time of most recent motion event sent. */ + uint64_t motion_time_; /* In milliseconds. */ + uint64_t motion_time_prev_; /* Time of most recent motion event sent. */ - GHOST_TProgress m_motionState; - bool m_motionEventPending; - float m_deadZone; /* Discard motion with each component < this. */ + GHOST_TProgress motion_state_; + bool motion_event_pending_; + float motion_dead_zone_; /* Discard motion with each component < this. */ }; diff --git a/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp index 94bf0337371..0ccf4dc9bfb 100644 --- a/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp +++ b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp @@ -10,7 +10,7 @@ #define SPNAV_SOCK_PATH "/var/run/spnav.sock" GHOST_NDOFManagerUnix::GHOST_NDOFManagerUnix(GHOST_System &sys) - : GHOST_NDOFManager(sys), m_available(false) + : GHOST_NDOFManager(sys), available_(false) { if (access(SPNAV_SOCK_PATH, F_OK) != 0) { #ifdef DEBUG @@ -20,7 +20,7 @@ GHOST_NDOFManagerUnix::GHOST_NDOFManagerUnix(GHOST_System &sys) #endif } else if (spnav_open() != -1) { - m_available = true; + available_ = true; /* determine exactly which device (if any) is plugged in */ @@ -45,14 +45,14 @@ GHOST_NDOFManagerUnix::GHOST_NDOFManagerUnix(GHOST_System &sys) GHOST_NDOFManagerUnix::~GHOST_NDOFManagerUnix() { - if (m_available) { + if (available_) { spnav_close(); } } bool GHOST_NDOFManagerUnix::available() { - return m_available; + return available_; } /* @@ -74,7 +74,7 @@ bool GHOST_NDOFManagerUnix::processEvents() { bool anyProcessed = false; - if (m_available) { + if (available_) { spnav_event e; #ifdef USE_FINISH_GLITCH_WORKAROUND @@ -85,7 +85,7 @@ bool GHOST_NDOFManagerUnix::processEvents() switch (e.type) { case SPNAV_EVENT_MOTION: { /* convert to blender view coords */ - uint64_t now = m_system.getMilliSeconds(); + uint64_t now = system_.getMilliSeconds(); const int t[3] = {int(e.motion.x), int(e.motion.y), int(-e.motion.z)}; const int r[3] = {int(-e.motion.rx), int(-e.motion.ry), int(e.motion.rz)}; @@ -97,7 +97,7 @@ bool GHOST_NDOFManagerUnix::processEvents() break; } case SPNAV_EVENT_BUTTON: - uint64_t now = m_system.getMilliSeconds(); + uint64_t now = system_.getMilliSeconds(); updateButton(e.button.bnum, e.button.press, now); break; } @@ -106,7 +106,7 @@ bool GHOST_NDOFManagerUnix::processEvents() #ifdef USE_FINISH_GLITCH_WORKAROUND if (motion_test_prev == true && motion_test == false) { - uint64_t now = m_system.getMilliSeconds(); + uint64_t now = system_.getMilliSeconds(); const int v[3] = {0, 0, 0}; updateTranslation(v, now); diff --git a/intern/ghost/intern/GHOST_NDOFManagerUnix.h b/intern/ghost/intern/GHOST_NDOFManagerUnix.h index fd603e3cb54..2b98fad974f 100644 --- a/intern/ghost/intern/GHOST_NDOFManagerUnix.h +++ b/intern/ghost/intern/GHOST_NDOFManagerUnix.h @@ -15,5 +15,5 @@ class GHOST_NDOFManagerUnix : public GHOST_NDOFManager { bool processEvents(); private: - bool m_available; + bool available_; }; diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp index 94d021fd822..670ede35989 100644 --- a/intern/ghost/intern/GHOST_System.cpp +++ b/intern/ghost/intern/GHOST_System.cpp @@ -384,6 +384,7 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window, if (stereoVisual) { glSettings.flags |= GHOST_glStereoVisual; } + glSettings.context_type = GHOST_kDrawingContextTypeOpenGL; /* NOTE: don't use #getCurrentDisplaySetting() because on X11 we may * be zoomed in and the desktop may be bigger than the viewport. */ GHOST_ASSERT(m_displayManager, @@ -395,7 +396,6 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window, settings.xPixels, settings.yPixels, GHOST_kWindowStateNormal, - GHOST_kDrawingContextTypeOpenGL, glSettings, true /* exclusive */); return (*window == nullptr) ? GHOST_kFailure : GHOST_kSuccess; diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h index dbb41c7fddf..0211694aad4 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.h +++ b/intern/ghost/intern/GHOST_SystemCocoa.h @@ -77,7 +77,6 @@ class GHOST_SystemCocoa : public GHOST_System { * \param width: The width the window. * \param height: The height the window. * \param state: The state of the window when opened. - * \param type: The type of drawing context installed in this window. * \param glSettings: Misc OpenGL settings. * \param exclusive: Use to show the window on top and ignore others (used full-screen). * \param parentWindow: Parent (embedder) window. @@ -89,7 +88,6 @@ class GHOST_SystemCocoa : public GHOST_System { uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive = false, const bool is_dialog = false, diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index bfa90114e4c..a1016dd4843 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -689,7 +689,6 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title, uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive, const bool is_dialog, @@ -719,7 +718,7 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title, width, height, state, - type, + glSettings.context_type, glSettings.flags & GHOST_glStereoVisual, glSettings.flags & GHOST_glDebugContext, is_dialog, @@ -751,7 +750,7 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title, */ GHOST_IContext *GHOST_SystemCocoa::createOffscreenContext(GHOST_GLSettings glSettings) { - GHOST_Context *context = new GHOST_ContextCGL(false, NULL, NULL, NULL); + GHOST_Context *context = new GHOST_ContextCGL(false, NULL, NULL, NULL, glSettings.context_type); if (context->initializeDrawingContext()) return context; else diff --git a/intern/ghost/intern/GHOST_SystemHeadless.h b/intern/ghost/intern/GHOST_SystemHeadless.h index b02a82fc9eb..66af65f763d 100644 --- a/intern/ghost/intern/GHOST_SystemHeadless.h +++ b/intern/ghost/intern/GHOST_SystemHeadless.h @@ -142,7 +142,6 @@ class GHOST_SystemHeadless : public GHOST_System { uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool /*exclusive*/, const bool /*is_dialog*/, @@ -155,7 +154,7 @@ class GHOST_SystemHeadless : public GHOST_System { height, state, parentWindow, - type, + glSettings.context_type, ((glSettings.flags & GHOST_glStereoVisual) != 0)); } diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp index ad5c4dc85fb..9174664adc4 100644 --- a/intern/ghost/intern/GHOST_SystemSDL.cpp +++ b/intern/ghost/intern/GHOST_SystemSDL.cpp @@ -42,7 +42,6 @@ GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title, uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive, const bool /* is_dialog */, @@ -57,7 +56,7 @@ GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title, width, height, state, - type, + glSettings.context_type, ((glSettings.flags & GHOST_glStereoVisual) != 0), exclusive, parentWindow); diff --git a/intern/ghost/intern/GHOST_SystemSDL.h b/intern/ghost/intern/GHOST_SystemSDL.h index bee277ba674..385bfb841e3 100644 --- a/intern/ghost/intern/GHOST_SystemSDL.h +++ b/intern/ghost/intern/GHOST_SystemSDL.h @@ -71,7 +71,6 @@ class GHOST_SystemSDL : public GHOST_System { uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive = false, const bool is_dialog = false, diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp index 04c7e103bde..442e51d4f7c 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cpp +++ b/intern/ghost/intern/GHOST_SystemWayland.cpp @@ -10,6 +10,7 @@ #include "GHOST_EventCursor.h" #include "GHOST_EventDragnDrop.h" #include "GHOST_EventKey.h" +#include "GHOST_EventTrackpad.h" #include "GHOST_EventWheel.h" #include "GHOST_PathUtils.h" #include "GHOST_TimerManager.h" @@ -50,6 +51,8 @@ /* Generated by `wayland-scanner`. */ #include <pointer-constraints-unstable-v1-client-protocol.h> +#include <pointer-gestures-unstable-v1-client-protocol.h> +#include <primary-selection-unstable-v1-client-protocol.h> #include <relative-pointer-unstable-v1-client-protocol.h> #include <tablet-unstable-v2-client-protocol.h> #include <xdg-output-unstable-v1-client-protocol.h> @@ -82,6 +85,10 @@ static void keyboard_handle_key_repeat_cancel(struct GWL_Seat *seat); static void output_handle_done(void *data, struct wl_output *wl_output); +static void gwl_seat_capability_pointer_disable(GWL_Seat *seat); +static void gwl_seat_capability_keyboard_disable(GWL_Seat *seat); +static void gwl_seat_capability_touch_disable(GWL_Seat *seat); + /* -------------------------------------------------------------------- */ /** \name Local Defines * @@ -116,6 +123,8 @@ static bool use_gnome_confine_hack = false; * This define could be removed without changing any functionality, * it just means GNOME users will see verbose warning messages that alert them about * a known problem that needs to be fixed up-stream. + * + * This has been fixed for GNOME 43. Keep the workaround until support for gnome 42 is dropped. * See: https://gitlab.gnome.org/GNOME/mutter/-/issues/2457 */ #define USE_GNOME_KEYBOARD_SUPPRESS_WARNING @@ -140,8 +149,7 @@ static bool use_gnome_confine_hack = false; * \{ */ /** - * The event codes are used to - * to differentiate from which mouse button an event comes from. + * The event codes are used to differentiate from which mouse button an event comes from. */ #define BTN_LEFT 0x110 #define BTN_RIGHT 0x111 @@ -190,48 +198,93 @@ struct GWL_ModifierInfo { }; static const GWL_ModifierInfo g_modifier_info_table[MOD_INDEX_NUM] = { - [MOD_INDEX_SHIFT] = - { - .display_name = "Shift", - .xkb_id = XKB_MOD_NAME_SHIFT, - .key_l = GHOST_kKeyLeftShift, - .key_r = GHOST_kKeyRightShift, - .mod_l = GHOST_kModifierKeyLeftShift, - .mod_r = GHOST_kModifierKeyRightShift, - }, - [MOD_INDEX_ALT] = - { - .display_name = "Alt", - .xkb_id = XKB_MOD_NAME_ALT, - .key_l = GHOST_kKeyLeftAlt, - .key_r = GHOST_kKeyRightAlt, - .mod_l = GHOST_kModifierKeyLeftAlt, - .mod_r = GHOST_kModifierKeyRightAlt, - }, - [MOD_INDEX_CTRL] = - { - .display_name = "Control", - .xkb_id = XKB_MOD_NAME_CTRL, - .key_l = GHOST_kKeyLeftControl, - .key_r = GHOST_kKeyRightControl, - .mod_l = GHOST_kModifierKeyLeftControl, - .mod_r = GHOST_kModifierKeyRightControl, - }, - [MOD_INDEX_OS] = - { - .display_name = "OS", - .xkb_id = XKB_MOD_NAME_LOGO, - .key_l = GHOST_kKeyLeftOS, - .key_r = GHOST_kKeyRightOS, - .mod_l = GHOST_kModifierKeyLeftOS, - .mod_r = GHOST_kModifierKeyRightOS, - }, + /* MOD_INDEX_SHIFT */ + { + /* display_name */ "Shift", + /* xkb_id */ XKB_MOD_NAME_SHIFT, + /* key_l */ GHOST_kKeyLeftShift, + /* key_r */ GHOST_kKeyRightShift, + /* mod_l */ GHOST_kModifierKeyLeftShift, + /* mod_r */ GHOST_kModifierKeyRightShift, + }, + /* MOD_INDEX_ALT */ + { + /* display_name */ "Alt", + /* xkb_id */ XKB_MOD_NAME_ALT, + /* key_l */ GHOST_kKeyLeftAlt, + /* key_r */ GHOST_kKeyRightAlt, + /* mod_l */ GHOST_kModifierKeyLeftAlt, + /* mod_r */ GHOST_kModifierKeyRightAlt, + }, + /* MOD_INDEX_CTRL */ + { + /* display_name */ "Control", + /* xkb_id */ XKB_MOD_NAME_CTRL, + /* key_l */ GHOST_kKeyLeftControl, + /* key_r */ GHOST_kKeyRightControl, + /* mod_l */ GHOST_kModifierKeyLeftControl, + /* mod_r */ GHOST_kModifierKeyRightControl, + }, + /* MOD_INDEX_OS */ + { + /* display_name */ "OS", + /* xkb_id */ XKB_MOD_NAME_LOGO, + /* key_l */ GHOST_kKeyLeftOS, + /* key_r */ GHOST_kKeyRightOS, + /* mod_l */ GHOST_kModifierKeyLeftOS, + /* mod_r */ GHOST_kModifierKeyRightOS, + }, }; /** \} */ /* -------------------------------------------------------------------- */ -/** \name Private Types & Defines +/** \name Internal #GWL_SimpleBuffer Type + * \{ */ + +struct GWL_SimpleBuffer { + /** Constant data, but may be freed. */ + const char *data = nullptr; + size_t data_size = 0; +}; + +static void gwl_simple_buffer_free_data(GWL_SimpleBuffer *buffer) +{ + free(const_cast<char *>(buffer->data)); + buffer->data = nullptr; + buffer->data_size = 0; +} + +static void gwl_simple_buffer_set_and_take_ownership(GWL_SimpleBuffer *buffer, + const char *data, + size_t data_size) +{ + free(const_cast<char *>(buffer->data)); + buffer->data = data; + buffer->data_size = data_size; +} + +static void gwl_simple_buffer_set_from_string(GWL_SimpleBuffer *buffer, const char *str) +{ + free(const_cast<char *>(buffer->data)); + buffer->data_size = strlen(str); + char *data = static_cast<char *>(malloc(buffer->data_size)); + std::memcpy(data, str, buffer->data_size); + buffer->data = data; +} + +static char *gwl_simple_buffer_as_string(const GWL_SimpleBuffer *buffer) +{ + char *buffer_str = static_cast<char *>(malloc(buffer->data_size + 1)); + memcpy(buffer_str, buffer->data, buffer->data_size); + buffer_str[buffer->data_size] = '\0'; + return buffer_str; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal #GWL_Cursor Type * \{ */ /** @@ -249,16 +302,26 @@ struct GWL_Cursor { * the hardware cursor is used. */ bool is_hardware = true; + /** When true, a custom image is used to display the cursor (stored in `wl_image`). */ bool is_custom = false; struct wl_surface *wl_surface = nullptr; struct wl_buffer *wl_buffer = nullptr; struct wl_cursor_image wl_image = {0}; struct wl_cursor_theme *wl_theme = nullptr; void *custom_data = nullptr; + /** The size of `custom_data` in bytes. */ size_t custom_data_size = 0; - int size = 0; + /** + * The name of the theme (loaded by DBUS, depends on #WITH_GHOST_WAYLAND_DBUS). + * When disabled, leave as an empty string and the default theme will be used. + */ std::string theme_name; - + /** + * The size of the cursor (when looking up a cursor theme). + * This must be scaled by the maximum output scale when passing to wl_cursor_theme_load. + * See #update_cursor_scale. + * */ + int theme_size = 0; int custom_scale = 1; }; @@ -269,6 +332,7 @@ struct GWL_Cursor { */ struct GWL_TabletTool { struct GWL_Seat *seat = nullptr; + /** Tablets have a separate cursor to the 'pointer', this surface is used for cursor drawing. */ struct wl_surface *wl_surface_cursor = nullptr; /** Used to delay clearing tablet focused wl_surface until the frame is handled. */ bool proximity = false; @@ -276,23 +340,51 @@ struct GWL_TabletTool { GHOST_TabletData data = GHOST_TABLET_DATA_NONE; }; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal #GWL_DataOffer Type + * \{ */ + +/** + * Data storage used for clipboard paste & drag-and-drop. + */ struct GWL_DataOffer { - std::unordered_set<std::string> types; - uint32_t source_actions = 0; - uint32_t dnd_action = 0; struct wl_data_offer *id = nullptr; + std::unordered_set<std::string> types; std::atomic<bool> in_use = false; + struct { + /** + * Bit-mask with available drop options. + * #WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY, #WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE.. etc. + * The application that initializes the drag may set these depending on modifiers held + * \note when dragging begins. Currently ghost doesn't make use of these. + */ + enum wl_data_device_manager_dnd_action source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; + enum wl_data_device_manager_dnd_action action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; /** Compatible with #GWL_Seat.xy coordinates. */ wl_fixed_t xy[2] = {0, 0}; } dnd; }; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal #GWL_DataSource Type + * \{ */ + struct GWL_DataSource { - struct wl_data_source *data_source = nullptr; - char *buffer_out = nullptr; + struct wl_data_source *wl_source = nullptr; + GWL_SimpleBuffer buffer_out; }; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal #GWL_Seat Type (#wl_seat wrapper & associated types) + * \{ */ + /** * Data used to implement client-side key-repeat. * @@ -358,6 +450,52 @@ struct GWL_SeatStatePointer { }; /** + * Scroll state, applying to pointer (not tablet) events. + * Otherwise this would be part of #GWL_SeatStatePointer. + */ +struct GWL_SeatStatePointerScroll { + /** Smooth scrolling (handled & reset with pointer "frame" callback). */ + wl_fixed_t smooth_xy[2] = {0, 0}; + /** Discrete scrolling (handled & reset with pointer "frame" callback). */ + int32_t discrete_xy[2] = {0, 0}; + /** The source of scroll event. */ + enum wl_pointer_axis_source axis_source = WL_POINTER_AXIS_SOURCE_WHEEL; +}; + +/** + * Utility struct to access rounded values from a scaled `wl_fixed_t`, + * without loosing information. + * + * As the rounded result is rounded to a lower precision integer, + * the high precision value is accumulated and converted to an integer to + * prevent the accumulation of rounded values giving an inaccurate result. + * + * \note This is simple but doesn't read well when expanded multiple times inline. + */ +struct GWL_ScaledFixedT { + wl_fixed_t value = 0; + wl_fixed_t factor = 1; +}; + +static int gwl_scaled_fixed_t_add_and_calc_rounded_delta(GWL_ScaledFixedT *sf, + const wl_fixed_t add) +{ + const int result_prev = wl_fixed_to_int(sf->value * sf->factor); + sf->value += add; + const int result_curr = wl_fixed_to_int(sf->value * sf->factor); + return result_curr - result_prev; +} + +/** + * Gesture state. + * This is needed so the gesture values can be converted to deltas. + */ +struct GWL_SeatStatePointerGesture_Pinch { + GWL_ScaledFixedT scale; + GWL_ScaledFixedT rotation; +}; + +/** * State of the keyboard (in #GWL_Seat). */ struct GWL_SeatStateKeyboard { @@ -376,16 +514,16 @@ struct GWL_SeatStateKeyboard { * * Needed as #GWL_Seat.xkb_state doesn't store which modifier keys are held. */ -struct WGL_KeyboardDepressedState { +struct GWL_KeyboardDepressedState { int16_t mods[GHOST_KEY_MODIFIER_NUM] = {0}; }; #ifdef WITH_GHOST_WAYLAND_LIBDECOR -struct WGL_LibDecor_System { +struct GWL_LibDecor_System { struct libdecor *context = nullptr; }; -static void wgl_libdecor_system_destroy(WGL_LibDecor_System *decor) +static void gwl_libdecor_system_destroy(GWL_LibDecor_System *decor) { if (decor->context) { libdecor_unref(decor->context); @@ -394,12 +532,12 @@ static void wgl_libdecor_system_destroy(WGL_LibDecor_System *decor) } #endif -struct WGL_XDG_Decor_System { +struct GWL_XDG_Decor_System { struct xdg_wm_base *shell = nullptr; struct zxdg_decoration_manager_v1 *manager = nullptr; }; -static void wgl_xdg_decor_system_destroy(WGL_XDG_Decor_System *decor) +static void gwl_xdg_decor_system_destroy(GWL_XDG_Decor_System *decor) { if (decor->manager) { zxdg_decoration_manager_v1_destroy(decor->manager); @@ -410,14 +548,65 @@ static void wgl_xdg_decor_system_destroy(WGL_XDG_Decor_System *decor) delete decor; } +struct GWL_PrimarySelection_DataOffer { + struct zwp_primary_selection_offer_v1 *id = nullptr; + std::atomic<bool> in_use = false; + + std::unordered_set<std::string> types; +}; + +struct GWL_PrimarySelection_DataSource { + struct zwp_primary_selection_source_v1 *wp_source = nullptr; + GWL_SimpleBuffer buffer_out; +}; + +/** Primary selection support. */ +struct GWL_PrimarySelection { + + GWL_PrimarySelection_DataSource *data_source = nullptr; + std::mutex data_source_mutex; + + GWL_PrimarySelection_DataOffer *data_offer = nullptr; + std::mutex data_offer_mutex; +}; + +static void gwl_primary_selection_discard_offer(GWL_PrimarySelection *primary) +{ + if (primary->data_offer == nullptr) { + return; + } + zwp_primary_selection_offer_v1_destroy(primary->data_offer->id); + delete primary->data_offer; + primary->data_offer = nullptr; +} + +static void gwl_primary_selection_discard_source(GWL_PrimarySelection *primary) +{ + GWL_PrimarySelection_DataSource *data_source = primary->data_source; + if (data_source == nullptr) { + return; + } + gwl_simple_buffer_free_data(&data_source->buffer_out); + if (data_source->wp_source) { + zwp_primary_selection_source_v1_destroy(data_source->wp_source); + } + delete primary->data_source; + primary->data_source = nullptr; +} + struct GWL_Seat { GHOST_SystemWayland *system = nullptr; std::string name; struct wl_seat *wl_seat = nullptr; struct wl_pointer *wl_pointer = nullptr; + struct wl_touch *wl_touch = nullptr; struct wl_keyboard *wl_keyboard = nullptr; - struct zwp_tablet_seat_v2 *tablet_seat = nullptr; + struct zwp_tablet_seat_v2 *wp_tablet_seat = nullptr; + + struct zwp_pointer_gesture_hold_v1 *wp_pointer_gesture_hold = nullptr; + struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch = nullptr; + struct zwp_pointer_gesture_swipe_v1 *wp_pointer_gesture_swipe = nullptr; /** All currently active tablet tools (needed for changing the cursor). */ std::unordered_set<zwp_tablet_tool_v2 *> tablet_tools; @@ -426,6 +615,8 @@ struct GWL_Seat { uint32_t cursor_source_serial = 0; GWL_SeatStatePointer pointer; + GWL_SeatStatePointerScroll pointer_scroll; + GWL_SeatStatePointerGesture_Pinch pointer_gesture_pinch; /** Mostly this can be interchanged with `pointer` however it can't be locked/confined. */ GWL_SeatStatePointer tablet; @@ -440,9 +631,9 @@ struct GWL_Seat { struct GWL_Cursor cursor; - struct zwp_relative_pointer_v1 *relative_pointer = nullptr; - struct zwp_locked_pointer_v1 *locked_pointer = nullptr; - struct zwp_confined_pointer_v1 *confined_pointer = nullptr; + struct zwp_relative_pointer_v1 *wp_relative_pointer = nullptr; + struct zwp_locked_pointer_v1 *wp_locked_pointer = nullptr; + struct zwp_confined_pointer_v1 *wp_confined_pointer = nullptr; struct xkb_context *xkb_context = nullptr; @@ -458,7 +649,7 @@ struct GWL_Seat { struct xkb_state *xkb_state_empty_with_numlock = nullptr; /** Keys held matching `xkb_state`. */ - struct WGL_KeyboardDepressedState key_depressed; + struct GWL_KeyboardDepressedState key_depressed; #ifdef USE_GNOME_KEYBOARD_SUPPRESS_WARNING struct { @@ -485,7 +676,7 @@ struct GWL_Seat { struct wl_surface *wl_surface_focus_dnd = nullptr; - struct wl_data_device *data_device = nullptr; + struct wl_data_device *wl_data_device = nullptr; /** Drag & Drop. */ struct GWL_DataOffer *data_offer_dnd = nullptr; std::mutex data_offer_dnd_mutex; @@ -497,10 +688,19 @@ struct GWL_Seat { struct GWL_DataSource *data_source = nullptr; std::mutex data_source_mutex; + struct zwp_primary_selection_device_v1 *wp_primary_selection_device = nullptr; + struct GWL_PrimarySelection primary_selection; + /** Last device that was active. */ uint32_t data_source_serial = 0; }; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal #GWL_Display Type (#wl_display & #wl_compositor wrapper) + * \{ */ + struct GWL_Display { GHOST_SystemWayland *system = nullptr; @@ -508,23 +708,27 @@ struct GWL_Display { struct wl_compositor *wl_compositor = nullptr; #ifdef WITH_GHOST_WAYLAND_LIBDECOR - WGL_LibDecor_System *libdecor = nullptr; + GWL_LibDecor_System *libdecor = nullptr; bool libdecor_required = false; #endif - WGL_XDG_Decor_System *xdg_decor = nullptr; + GWL_XDG_Decor_System *xdg_decor = nullptr; struct zxdg_output_manager_v1 *xdg_output_manager = nullptr; struct wl_shm *wl_shm = nullptr; std::vector<GWL_Output *> outputs; std::vector<GWL_Seat *> seats; - struct wl_data_device_manager *data_device_manager = nullptr; - struct zwp_tablet_manager_v2 *tablet_manager = nullptr; - struct zwp_relative_pointer_manager_v1 *relative_pointer_manager = nullptr; - struct zwp_pointer_constraints_v1 *pointer_constraints = nullptr; -}; + struct wl_data_device_manager *wl_data_device_manager = nullptr; + struct zwp_tablet_manager_v2 *wp_tablet_manager = nullptr; + struct zwp_relative_pointer_manager_v1 *wp_relative_pointer_manager = nullptr; + struct zwp_pointer_constraints_v1 *wp_pointer_constraints = nullptr; + struct zwp_pointer_gestures_v1 *wp_pointer_gestures = nullptr; -#undef LOG + struct zwp_primary_selection_device_manager_v1 *wp_primary_selection_device_manager = nullptr; + + GWL_SimpleBuffer clipboard; + GWL_SimpleBuffer clipboard_primary; +}; /** \} */ @@ -580,12 +784,12 @@ static GWL_SeatStatePointer *seat_state_pointer_from_cursor_surface(GWL_Seat *se static void display_destroy(GWL_Display *display) { - if (display->data_device_manager) { - wl_data_device_manager_destroy(display->data_device_manager); + if (display->wl_data_device_manager) { + wl_data_device_manager_destroy(display->wl_data_device_manager); } - if (display->tablet_manager) { - zwp_tablet_manager_v2_destroy(display->tablet_manager); + if (display->wp_tablet_manager) { + zwp_tablet_manager_v2_destroy(display->wp_tablet_manager); } for (GWL_Output *output : display->outputs) { @@ -600,9 +804,9 @@ static void display_destroy(GWL_Display *display) { std::lock_guard lock{seat->data_source_mutex}; if (seat->data_source) { - free(seat->data_source->buffer_out); - if (seat->data_source->data_source) { - wl_data_source_destroy(seat->data_source->data_source); + gwl_simple_buffer_free_data(&seat->data_source->buffer_out); + if (seat->data_source->wl_source) { + wl_data_source_destroy(seat->data_source->wl_source); } delete seat->data_source; } @@ -624,32 +828,39 @@ static void display_destroy(GWL_Display *display) } } - if (seat->data_device) { - wl_data_device_release(seat->data_device); + { + GWL_PrimarySelection *primary = &seat->primary_selection; + std::lock_guard lock{primary->data_offer_mutex}; + gwl_primary_selection_discard_offer(primary); } - if (seat->cursor.custom_data) { - munmap(seat->cursor.custom_data, seat->cursor.custom_data_size); + { + GWL_PrimarySelection *primary = &seat->primary_selection; + std::lock_guard lock{primary->data_source_mutex}; + gwl_primary_selection_discard_source(primary); } - if (seat->wl_pointer) { - if (seat->cursor.wl_surface) { - wl_surface_destroy(seat->cursor.wl_surface); - } - if (seat->cursor.wl_theme) { - wl_cursor_theme_destroy(seat->cursor.wl_theme); - } - if (seat->wl_pointer) { - wl_pointer_destroy(seat->wl_pointer); - } + if (seat->wp_primary_selection_device) { + zwp_primary_selection_device_v1_destroy(seat->wp_primary_selection_device); } - if (seat->wl_keyboard) { - if (seat->key_repeat.timer) { - keyboard_handle_key_repeat_cancel(seat); - } - wl_keyboard_destroy(seat->wl_keyboard); + + if (seat->wl_data_device) { + wl_data_device_release(seat->wl_data_device); + } + + if (seat->cursor.custom_data) { + munmap(seat->cursor.custom_data, seat->cursor.custom_data_size); } + /* Disable all capabilities as a way to free: + * - `seat.wl_pointer` (and related cursor variables). + * - `seat.wl_touch`. + * - `seat.wl_keyboard`. + */ + gwl_seat_capability_pointer_disable(seat); + gwl_seat_capability_keyboard_disable(seat); + gwl_seat_capability_touch_disable(seat); + /* Un-referencing checks for NULL case. */ xkb_state_unref(seat->xkb_state); xkb_state_unref(seat->xkb_state_empty); @@ -665,12 +876,16 @@ static void display_destroy(GWL_Display *display) wl_shm_destroy(display->wl_shm); } - if (display->relative_pointer_manager) { - zwp_relative_pointer_manager_v1_destroy(display->relative_pointer_manager); + if (display->wp_relative_pointer_manager) { + zwp_relative_pointer_manager_v1_destroy(display->wp_relative_pointer_manager); } - if (display->pointer_constraints) { - zwp_pointer_constraints_v1_destroy(display->pointer_constraints); + if (display->wp_pointer_constraints) { + zwp_pointer_constraints_v1_destroy(display->wp_pointer_constraints); + } + + if (display->wp_pointer_gestures) { + zwp_pointer_gestures_v1_destroy(display->wp_pointer_gestures); } if (display->wl_compositor) { @@ -680,14 +895,14 @@ static void display_destroy(GWL_Display *display) #ifdef WITH_GHOST_WAYLAND_LIBDECOR if (use_libdecor) { if (display->libdecor) { - wgl_libdecor_system_destroy(display->libdecor); + gwl_libdecor_system_destroy(display->libdecor); } } else #endif { if (display->xdg_decor) { - wgl_xdg_decor_system_destroy(display->xdg_decor); + gwl_xdg_decor_system_destroy(display->xdg_decor); } } @@ -699,6 +914,12 @@ static void display_destroy(GWL_Display *display) wl_display_disconnect(display->wl_display); } + { + std::lock_guard lock{system_clipboard_mutex}; + gwl_simple_buffer_free_data(&display->clipboard); + gwl_simple_buffer_free_data(&display->clipboard_primary); + } + delete display; } @@ -837,9 +1058,24 @@ static GHOST_TKey xkb_map_gkey_or_scan_code(const xkb_keysym_t sym, const uint32 return gkey; } -static GHOST_TTabletMode tablet_tool_map_type(enum zwp_tablet_tool_v2_type wl_tablet_tool_type) +static int pointer_axis_as_index(const uint32_t axis) +{ + switch (axis) { + case WL_POINTER_AXIS_HORIZONTAL_SCROLL: { + return 0; + } + case WL_POINTER_AXIS_VERTICAL_SCROLL: { + return 1; + } + default: { + return -1; + } + } +} + +static GHOST_TTabletMode tablet_tool_map_type(enum zwp_tablet_tool_v2_type wp_tablet_tool_type) { - switch (wl_tablet_tool_type) { + switch (wp_tablet_tool_type) { case ZWP_TABLET_TOOL_V2_TYPE_ERASER: { return GHOST_kTabletModeEraser; } @@ -1045,7 +1281,7 @@ static void keyboard_depressed_state_key_event(GWL_Seat *seat, } static void keyboard_depressed_state_push_events_from_change( - GWL_Seat *seat, const WGL_KeyboardDepressedState &key_depressed_prev) + GWL_Seat *seat, const GWL_KeyboardDepressedState &key_depressed_prev) { GHOST_IWindow *win = ghost_wl_surface_user_data(seat->keyboard.wl_surface); GHOST_SystemWayland *system = seat->system; @@ -1183,15 +1419,81 @@ static void dnd_events(const GWL_Seat *const seat, const GHOST_TEventType event) } } -static std::string read_pipe(GWL_DataOffer *data_offer, - const std::string mime_receive, - std::mutex *mutex) +/** + * Read from `fd` into a buffer which is returned. + * \return the buffer or null on failure. + */ +static const char *read_file_as_buffer(const int fd, size_t *r_len) +{ + struct ByteChunk { + ByteChunk *next; + char data[4096 - sizeof(ByteChunk *)]; + }; + ByteChunk *chunk_first = nullptr, **chunk_link_p = &chunk_first; + bool ok = true; + size_t len = 0; + while (true) { + ByteChunk *chunk = static_cast<typeof(chunk)>(malloc(sizeof(*chunk))); + if (UNLIKELY(chunk == nullptr)) { + CLOG_WARN(LOG, "unable to allocate chunk for file buffer"); + ok = false; + break; + } + chunk->next = nullptr; + const ssize_t len_chunk = read(fd, chunk->data, sizeof(chunk->data)); + if (len_chunk <= 0) { + if (UNLIKELY(len_chunk < 0)) { + CLOG_WARN(LOG, "error reading from pipe: %s", std::strerror(errno)); + ok = false; + } + free(chunk); + break; + } + if (chunk_first == nullptr) { + chunk_first = chunk; + } + *chunk_link_p = chunk; + chunk_link_p = &chunk->next; + len += len_chunk; + } + + char *buf = nullptr; + if (ok) { + buf = static_cast<char *>(malloc(len)); + if (UNLIKELY(buf == nullptr)) { + CLOG_WARN(LOG, "unable to allocate file buffer: %zu bytes", len); + ok = false; + } + } + + *r_len = ok ? len : 0; + char *buf_stride = buf; + while (chunk_first) { + if (ok) { + const size_t len_chunk = std::min(len, sizeof(chunk_first->data)); + memcpy(buf_stride, chunk_first->data, len_chunk); + buf_stride += len_chunk; + len -= len_chunk; + } + ByteChunk *chunk = chunk_first->next; + free(chunk_first); + chunk_first = chunk; + } + + return buf; +} + +static const char *read_buffer_from_data_offer(GWL_DataOffer *data_offer, + const char *mime_receive, + std::mutex *mutex, + size_t *r_len) { int pipefd[2]; if (UNLIKELY(pipe(pipefd) != 0)) { - return {}; + CLOG_WARN(LOG, "error creating pipe: %s", std::strerror(errno)); + return nullptr; } - wl_data_offer_receive(data_offer->id, mime_receive.c_str(), pipefd[1]); + wl_data_offer_receive(data_offer->id, mime_receive, pipefd[1]); close(pipefd[1]); data_offer->in_use.store(false); @@ -1201,15 +1503,34 @@ static std::string read_pipe(GWL_DataOffer *data_offer, } /* WARNING: `data_offer` may be freed from now on. */ - std::string data; - ssize_t len; - char buffer[4096]; - while ((len = read(pipefd[0], buffer, sizeof(buffer))) > 0) { - data.insert(data.end(), buffer, buffer + len); - } + const char *buf = read_file_as_buffer(pipefd[0], r_len); close(pipefd[0]); + return buf; +} + +static const char *read_buffer_from_primary_selection_offer( + GWL_PrimarySelection_DataOffer *data_offer, + const char *mime_receive, + std::mutex *mutex, + size_t *r_len) +{ + int pipefd[2]; + if (UNLIKELY(pipe(pipefd) != 0)) { + CLOG_WARN(LOG, "error creating pipe: %s", std::strerror(errno)); + return nullptr; + } + zwp_primary_selection_offer_v1_receive(data_offer->id, mime_receive, pipefd[1]); + close(pipefd[1]); + + data_offer->in_use.store(false); - return data; + if (mutex) { + mutex->unlock(); + } + /* WARNING: `data_offer` may be freed from now on. */ + const char *buf = read_file_as_buffer(pipefd[0], r_len); + close(pipefd[0]); + return buf; } /** @@ -1235,16 +1556,22 @@ static void data_source_handle_send(void *data, CLOG_INFO(LOG, 2, "send"); - const char *const buffer = seat->data_source->buffer_out; - if (write(fd, buffer, strlen(buffer)) < 0) { - GHOST_PRINT("error writing to clipboard: " << std::strerror(errno) << std::endl); + const char *const buffer = seat->data_source->buffer_out.data; + if (UNLIKELY(write(fd, buffer, seat->data_source->buffer_out.data_size) < 0)) { + CLOG_WARN(LOG, "error writing to clipboard: %s", std::strerror(errno)); } close(fd); } -static void data_source_handle_cancelled(void * /*data*/, struct wl_data_source *wl_data_source) +static void data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source) { CLOG_INFO(LOG, 2, "cancelled"); + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + GWL_DataSource *data_source = seat->data_source; + if (seat->data_source->wl_source == wl_data_source) { + data_source->wl_source = nullptr; + } + wl_data_source_destroy(wl_data_source); } @@ -1313,7 +1640,8 @@ static void data_offer_handle_offer(void *data, const char *mime_type) { CLOG_INFO(LOG, 2, "offer (mime_type=%s)", mime_type); - static_cast<GWL_DataOffer *>(data)->types.insert(mime_type); + GWL_DataOffer *data_offer = static_cast<GWL_DataOffer *>(data); + data_offer->types.insert(mime_type); } static void data_offer_handle_source_actions(void *data, @@ -1321,7 +1649,8 @@ static void data_offer_handle_source_actions(void *data, const uint32_t source_actions) { CLOG_INFO(LOG, 2, "source_actions (%u)", source_actions); - static_cast<GWL_DataOffer *>(data)->source_actions = source_actions; + GWL_DataOffer *data_offer = static_cast<GWL_DataOffer *>(data); + data_offer->dnd.source_actions = (enum wl_data_device_manager_dnd_action)source_actions; } static void data_offer_handle_action(void *data, @@ -1329,7 +1658,8 @@ static void data_offer_handle_action(void *data, const uint32_t dnd_action) { CLOG_INFO(LOG, 2, "actions (%u)", dnd_action); - static_cast<GWL_DataOffer *>(data)->dnd_action = dnd_action; + GWL_DataOffer *data_offer = static_cast<GWL_DataOffer *>(data); + data_offer->dnd.action = (enum wl_data_device_manager_dnd_action)dnd_action; } static const struct wl_data_offer_listener data_offer_listener = { @@ -1452,7 +1782,11 @@ static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_dat const std::string mime_receive) { const wl_fixed_t xy[2] = {UNPACK2(data_offer->dnd.xy)}; - const std::string data = read_pipe(data_offer, mime_receive, nullptr); + size_t data_buf_len = 0; + const char *data_buf = read_buffer_from_data_offer( + data_offer, mime_receive.c_str(), nullptr, &data_buf_len); + std::string data = data_buf ? std::string(data_buf, data_buf_len) : ""; + free(const_cast<char *>(data_buf)); CLOG_INFO( LOG, 2, "drop_read_uris mime_receive=%s, data=%s", mime_receive.c_str(), data.c_str()); @@ -1567,12 +1901,15 @@ static void data_device_handle_selection(void *data, break; } } - const std::string data = read_pipe( - data_offer, mime_receive, &seat->data_offer_copy_paste_mutex); + + size_t data_len = 0; + const char *data = read_buffer_from_data_offer( + data_offer, mime_receive.c_str(), &seat->data_offer_copy_paste_mutex, &data_len); { std::lock_guard lock{system_clipboard_mutex}; - system->clipboard_set(data); + GWL_SimpleBuffer *buf = system->clipboard_data(false); + gwl_simple_buffer_set_and_take_ownership(buf, data, data_len); } }; @@ -1646,7 +1983,8 @@ static bool update_cursor_scale(GWL_Cursor &cursor, wl_surface_set_buffer_scale(wl_cursor_surface, scale); } wl_cursor_theme_destroy(cursor.wl_theme); - cursor.wl_theme = wl_cursor_theme_load(cursor.theme_name.c_str(), scale * cursor.size, shm); + cursor.wl_theme = wl_cursor_theme_load( + cursor.theme_name.c_str(), scale * cursor.theme_size, shm); return true; } return false; @@ -1726,6 +2064,15 @@ static void pointer_handle_enter(void *data, seat->pointer.serial = serial; seat->pointer.xy[0] = surface_x; seat->pointer.xy[1] = surface_y; + + /* Resetting scroll events is likely unnecessary, + * do this to avoid any possible problems as it's harmless. */ + seat->pointer_scroll.smooth_xy[0] = 0; + seat->pointer_scroll.smooth_xy[1] = 0; + seat->pointer_scroll.discrete_xy[0] = 0; + seat->pointer_scroll.discrete_xy[1] = 0; + seat->pointer_scroll.axis_source = WL_POINTER_AXIS_SOURCE_WHEEL; + seat->pointer.wl_surface = wl_surface; win->setCursorShape(win->getCursorShape()); @@ -1837,24 +2184,91 @@ static void pointer_handle_button(void *data, } } -static void pointer_handle_axis(void * /*data*/, +static void pointer_handle_axis(void *data, struct wl_pointer * /*wl_pointer*/, const uint32_t /*time*/, const uint32_t axis, const wl_fixed_t value) { + /* NOTE: this is used for touch based scrolling - or other input that doesn't scroll with + * discrete "steps". This allows supporting smooth-scrolling without "touch" gesture support. */ CLOG_INFO(LOG, 2, "axis (axis=%u, value=%d)", axis, value); + const int index = pointer_axis_as_index(axis); + if (UNLIKELY(index == -1)) { + return; + } + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + seat->pointer_scroll.smooth_xy[index] = value; } -static void pointer_handle_frame(void * /*data*/, struct wl_pointer * /*wl_pointer*/) +static void pointer_handle_frame(void *data, struct wl_pointer * /*wl_pointer*/) { CLOG_INFO(LOG, 2, "frame"); + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + + /* Both discrete and smooth events may be set at once, never generate events for both + * as this will be handling the same event in to different ways. + * Prioritize discrete axis events for the mouse wheel, otherwise smooth scroll. */ + if (seat->pointer_scroll.axis_source == WL_POINTER_AXIS_SOURCE_WHEEL) { + if (seat->pointer_scroll.discrete_xy[0]) { + seat->pointer_scroll.smooth_xy[0] = 0; + } + if (seat->pointer_scroll.discrete_xy[1]) { + seat->pointer_scroll.smooth_xy[1] = 0; + } + } + else { + if (seat->pointer_scroll.smooth_xy[0]) { + seat->pointer_scroll.discrete_xy[0] = 0; + } + if (seat->pointer_scroll.smooth_xy[1]) { + seat->pointer_scroll.discrete_xy[1] = 0; + } + } + + /* Discrete X axis currently unsupported. */ + if (seat->pointer_scroll.discrete_xy[1]) { + if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) { + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); + const int32_t discrete = seat->pointer_scroll.discrete_xy[1]; + seat->system->pushEvent(new GHOST_EventWheel( + seat->system->getMilliSeconds(), win, std::signbit(discrete) ? +1 : -1)); + } + seat->pointer_scroll.discrete_xy[0] = 0; + seat->pointer_scroll.discrete_xy[1] = 0; + } + + if (seat->pointer_scroll.smooth_xy[0] || seat->pointer_scroll.smooth_xy[1]) { + if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) { + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); + const wl_fixed_t scale = win->scale(); + seat->system->pushEvent(new GHOST_EventTrackpad( + seat->system->getMilliSeconds(), + win, + GHOST_kTrackpadEventScroll, + wl_fixed_to_int(scale * seat->pointer.xy[0]), + wl_fixed_to_int(scale * seat->pointer.xy[1]), + /* NOTE: scaling the delta doesn't seem necessary. + * NOTE: inverting delta gives correct results, see: QTBUG-85767. */ + -wl_fixed_to_int(seat->pointer_scroll.smooth_xy[0]), + -wl_fixed_to_int(seat->pointer_scroll.smooth_xy[1]), + /* TODO: investigate a way to request this configuration from the system. */ + false)); + } + + seat->pointer_scroll.smooth_xy[0] = 0; + seat->pointer_scroll.smooth_xy[1] = 0; + } + + seat->pointer_scroll.axis_source = WL_POINTER_AXIS_SOURCE_WHEEL; } -static void pointer_handle_axis_source(void * /*data*/, +static void pointer_handle_axis_source(void *data, struct wl_pointer * /*wl_pointer*/, uint32_t axis_source) { CLOG_INFO(LOG, 2, "axis_source (axis_source=%u)", axis_source); + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + seat->pointer_scroll.axis_source = (enum wl_pointer_axis_source)axis_source; } static void pointer_handle_axis_stop(void * /*data*/, struct wl_pointer * /*wl_pointer*/, @@ -1868,18 +2282,15 @@ static void pointer_handle_axis_discrete(void *data, uint32_t axis, int32_t discrete) { + /* NOTE: a discrete axis are typically mouse wheel events. + * The non-discrete version of this function is used for touch-pad. */ CLOG_INFO(LOG, 2, "axis_discrete (axis=%u, discrete=%d)", axis, discrete); - - GWL_Seat *seat = static_cast<GWL_Seat *>(data); - if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) { + const int index = pointer_axis_as_index(axis); + if (UNLIKELY(index == -1)) { return; } - - if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) { - GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); - seat->system->pushEvent(new GHOST_EventWheel( - seat->system->getMilliSeconds(), win, std::signbit(discrete) ? +1 : -1)); - } + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + seat->pointer_scroll.discrete_xy[index] = discrete; } static const struct wl_pointer_listener pointer_listener = { @@ -1899,6 +2310,306 @@ static const struct wl_pointer_listener pointer_listener = { /** \} */ /* -------------------------------------------------------------------- */ +/** \name Listener (Pointer Gesture: Hold), #zwp_pointer_gesture_hold_v1_listener + * \{ */ + +static CLG_LogRef LOG_WL_POINTER_GESTURE_HOLD = {"ghost.wl.handle.pointer_gesture.hold"}; +#define LOG (&LOG_WL_POINTER_GESTURE_HOLD) + +static void gesture_hold_handle_begin( + void * /*data*/, + struct zwp_pointer_gesture_hold_v1 * /*zwp_pointer_gesture_hold_v1*/, + uint32_t /*serial*/, + uint32_t /*time*/, + struct wl_surface * /*surface*/, + uint32_t fingers) +{ + CLOG_INFO(LOG, 2, "begin (fingers=%u)", fingers); +} + +static void gesture_hold_handle_end( + void * /*data*/, + struct zwp_pointer_gesture_hold_v1 * /*zwp_pointer_gesture_hold_v1*/, + uint32_t /*serial*/, + uint32_t /*time*/, + int32_t cancelled) +{ + CLOG_INFO(LOG, 2, "end (cancelled=%i)", cancelled); +} + +static const struct zwp_pointer_gesture_hold_v1_listener gesture_hold_listener = { + gesture_hold_handle_begin, + gesture_hold_handle_end, +}; + +#undef LOG + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Listener (Pointer Gesture: Pinch), #zwp_pointer_gesture_pinch_v1_listener + * \{ */ + +static CLG_LogRef LOG_WL_POINTER_GESTURE_PINCH = {"ghost.wl.handle.pointer_gesture.pinch"}; +#define LOG (&LOG_WL_POINTER_GESTURE_PINCH) + +static void gesture_pinch_handle_begin(void *data, + struct zwp_pointer_gesture_pinch_v1 * /*pinch*/, + uint32_t /*serial*/, + uint32_t /*time*/, + struct wl_surface * /*surface*/, + uint32_t fingers) +{ + CLOG_INFO(LOG, 2, "begin (fingers=%u)", fingers); + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + /* Reset defaults. */ + seat->pointer_gesture_pinch = GWL_SeatStatePointerGesture_Pinch{}; + + GHOST_WindowWayland *win = nullptr; + if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) { + win = ghost_wl_surface_user_data(wl_surface_focus); + } + const wl_fixed_t win_scale = win ? win->scale() : 1; + + /* NOTE(@campbellbarton): Scale factors match Blender's operators & default preferences. + * For these values to work correctly, operator logic will need to be changed not to scale input + * by the region size (as with 3D view zoom) or preference for 3D view orbit sensitivity. + * + * By working "correctly" I mean that a rotation action where the users fingers rotate to + * opposite locations should always rotate the viewport 180d, since users will expect the + * physical location of their fingers to match the viewport. + * Similarly with zoom, the scale value from the pinch action can be mapped to a zoom level + * although unlike rotation, an inexact mapping is less noticeable. + * Users may even prefer the zoom level to be scaled - which could be a preference. */ + seat->pointer_gesture_pinch.scale.value = wl_fixed_from_int(1); + /* The value 300 matches a value used in clip & image zoom operators. + * It seems OK for the 3D view too. */ + seat->pointer_gesture_pinch.scale.factor = 300 * win_scale; + /* The value 5 is used on macOS and roughly maps 1:1 with turntable rotation, + * although preferences can scale the sensitivity (which would be skipped ideally). */ + seat->pointer_gesture_pinch.rotation.factor = 5 * win_scale; +} + +static void gesture_pinch_handle_update(void *data, + struct zwp_pointer_gesture_pinch_v1 * /*pinch*/, + uint32_t /*time*/, + wl_fixed_t dx, + wl_fixed_t dy, + wl_fixed_t scale, + wl_fixed_t rotation) +{ + CLOG_INFO(LOG, + 2, + "update (dx=%.3f, dy=%.3f, scale=%.3f, rotation=%.3f)", + wl_fixed_to_double(dx), + wl_fixed_to_double(dy), + wl_fixed_to_double(scale), + wl_fixed_to_double(rotation)); + + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + + GHOST_WindowWayland *win = nullptr; + + if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) { + win = ghost_wl_surface_user_data(wl_surface_focus); + } + + /* Scale defaults to `wl_fixed_from_int(1)` which may change while pinching. + * This needs to be converted to a delta. */ + const wl_fixed_t scale_delta = scale - seat->pointer_gesture_pinch.scale.value; + const int scale_as_delta_px = gwl_scaled_fixed_t_add_and_calc_rounded_delta( + &seat->pointer_gesture_pinch.scale, scale_delta); + + /* Rotation in degrees, unlike scale this is a delta. */ + const int rotation_as_delta_px = gwl_scaled_fixed_t_add_and_calc_rounded_delta( + &seat->pointer_gesture_pinch.rotation, rotation); + + if (win) { + const wl_fixed_t win_scale = win->scale(); + const int32_t event_xy[2] = { + wl_fixed_to_int(win_scale * seat->pointer.xy[0]), + wl_fixed_to_int(win_scale * seat->pointer.xy[1]), + }; + if (scale_as_delta_px) { + seat->system->pushEvent(new GHOST_EventTrackpad(seat->system->getMilliSeconds(), + win, + GHOST_kTrackpadEventMagnify, + event_xy[0], + event_xy[1], + scale_as_delta_px, + 0, + false)); + } + + if (rotation_as_delta_px) { + seat->system->pushEvent(new GHOST_EventTrackpad(seat->system->getMilliSeconds(), + win, + GHOST_kTrackpadEventRotate, + event_xy[0], + event_xy[1], + rotation_as_delta_px, + 0, + false)); + } + } +} + +static void gesture_pinch_handle_end(void * /*data*/, + struct zwp_pointer_gesture_pinch_v1 * /*pinch*/, + uint32_t /*serial*/, + uint32_t /*time*/, + int32_t cancelled) +{ + CLOG_INFO(LOG, 2, "end (cancelled=%i)", cancelled); +} + +static const struct zwp_pointer_gesture_pinch_v1_listener gesture_pinch_listener = { + gesture_pinch_handle_begin, + gesture_pinch_handle_update, + gesture_pinch_handle_end, +}; + +#undef LOG + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Listener (Pointer Gesture: Swipe), #zwp_pointer_gesture_swipe_v1 + * + * \note In both Gnome-Shell & KDE this gesture isn't emitted at time of writing, + * instead, high resolution 2D #wl_pointer_listener.axis data is generated which works well. + * There may be some situations where WAYLAND compositors generate this gesture + * (swiping with 3+ fingers, for e.g.). So keep this to allow logging & testing gestures. + * \{ */ + +static CLG_LogRef LOG_WL_POINTER_GESTURE_SWIPE = {"ghost.wl.handle.pointer_gesture.swipe"}; +#define LOG (&LOG_WL_POINTER_GESTURE_SWIPE) + +static void gesture_swipe_handle_begin( + void * /*data*/, + struct zwp_pointer_gesture_swipe_v1 * /*zwp_pointer_gesture_swipe_v1*/, + uint32_t /*serial*/, + uint32_t /*time*/, + struct wl_surface * /*surface*/, + uint32_t fingers) +{ + CLOG_INFO(LOG, 2, "begin (fingers=%u)", fingers); +} + +static void gesture_swipe_handle_update( + void * /*data*/, + struct zwp_pointer_gesture_swipe_v1 * /*zwp_pointer_gesture_swipe_v1*/, + uint32_t /*time*/, + wl_fixed_t dx, + wl_fixed_t dy) +{ + CLOG_INFO(LOG, 2, "update (dx=%.3f, dy=%.3f)", wl_fixed_to_double(dx), wl_fixed_to_double(dy)); +} + +static void gesture_swipe_handle_end( + void * /*data*/, + struct zwp_pointer_gesture_swipe_v1 * /*zwp_pointer_gesture_swipe_v1*/, + uint32_t /*serial*/, + uint32_t /*time*/, + int32_t cancelled) +{ + CLOG_INFO(LOG, 2, "end (cancelled=%i)", cancelled); +} + +static const struct zwp_pointer_gesture_swipe_v1_listener gesture_swipe_listener = { + gesture_swipe_handle_begin, + gesture_swipe_handle_update, + gesture_swipe_handle_end, +}; + +#undef LOG + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Listener (Touch Seat), #wl_touch_listener + * + * TODO(@campbellbarton): Only setup the callbacks for now as I don't have + * hardware that generates touch events. + * \{ */ + +static CLG_LogRef LOG_WL_TOUCH = {"ghost.wl.handle.touch"}; +#define LOG (&LOG_WL_TOUCH) + +static void touch_seat_handle_down(void * /*data*/, + struct wl_touch * /*wl_touch*/, + uint32_t /*serial*/, + uint32_t /*time*/, + struct wl_surface * /*wl_surface*/, + int32_t /*id*/, + wl_fixed_t /*x*/, + wl_fixed_t /*y*/) +{ + CLOG_INFO(LOG, 2, "down"); +} + +static void touch_seat_handle_up(void * /*data*/, + struct wl_touch * /*wl_touch*/, + uint32_t /*serial*/, + uint32_t /*time*/, + int32_t /*id*/) +{ + CLOG_INFO(LOG, 2, "up"); +} + +static void touch_seat_handle_motion(void * /*data*/, + struct wl_touch * /*wl_touch*/, + uint32_t /*time*/, + int32_t /*id*/, + wl_fixed_t /*x*/, + wl_fixed_t /*y*/) +{ + CLOG_INFO(LOG, 2, "motion"); +} + +static void touch_seat_handle_frame(void * /*data*/, struct wl_touch * /*wl_touch*/) +{ + CLOG_INFO(LOG, 2, "frame"); +} + +static void touch_seat_handle_cancel(void * /*data*/, struct wl_touch * /*wl_touch*/) +{ + + CLOG_INFO(LOG, 2, "cancel"); +} + +static void touch_seat_handle_shape(void * /*data*/, + struct wl_touch * /*touch*/, + int32_t /*id*/, + wl_fixed_t /*major*/, + wl_fixed_t /*minor*/) +{ + CLOG_INFO(LOG, 2, "shape"); +} + +static void touch_seat_handle_orientation(void * /*data*/, + struct wl_touch * /*touch*/, + int32_t /*id*/, + wl_fixed_t /*orientation*/) +{ + CLOG_INFO(LOG, 2, "orientation"); +} + +static const struct wl_touch_listener touch_seat_listener = { + touch_seat_handle_down, + touch_seat_handle_up, + touch_seat_handle_motion, + touch_seat_handle_frame, + touch_seat_handle_cancel, + touch_seat_handle_shape, + touch_seat_handle_orientation, +}; + +#undef LOG + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Listener (Tablet Tool), #zwp_tablet_tool_v2_listener * \{ */ @@ -2377,7 +3088,7 @@ static void keyboard_handle_enter(void *data, /* If there are any keys held when activating the window, * modifiers will be compared against the seat state, * only enabling modifiers that were previously disabled. */ - WGL_KeyboardDepressedState key_depressed_prev = seat->key_depressed; + GWL_KeyboardDepressedState key_depressed_prev = seat->key_depressed; keyboard_depressed_state_reset(seat); uint32_t *key; @@ -2587,11 +3298,10 @@ static void keyboard_handle_key(void *data, /* Start timer for repeating key, if applicable. */ if ((seat->key_repeat.rate > 0) && (etype == GHOST_kEventKeyDown) && xkb_keymap_key_repeats(xkb_state_get_keymap(seat->xkb_state), key_code)) { - key_repeat_payload = new GWL_KeyRepeatPlayload({ - .seat = seat, - .key_code = key_code, - .key_data = {.gkey = gkey}, - }); + key_repeat_payload = new GWL_KeyRepeatPlayload(); + key_repeat_payload->seat = seat; + key_repeat_payload->key_code = key_code; + key_repeat_payload->key_data.gkey = gkey; } } @@ -2681,12 +3391,294 @@ static const struct wl_keyboard_listener keyboard_listener = { /** \} */ /* -------------------------------------------------------------------- */ +/** \name Listener (Primary Selection Offer), #zwp_primary_selection_offer_v1_listener + * \{ */ + +static CLG_LogRef LOG_WL_PRIMARY_SELECTION_OFFER = {"ghost.wl.handle.primary_selection_offer"}; +#define LOG (&LOG_WL_PRIMARY_SELECTION_OFFER) + +static void primary_selection_offer_offer(void *data, + struct zwp_primary_selection_offer_v1 *id, + const char *type) +{ + GWL_PrimarySelection_DataOffer *data_offer = static_cast<GWL_PrimarySelection_DataOffer *>(data); + if (data_offer->id != id) { + CLOG_INFO(LOG, 2, "offer: %p: offer for unknown selection %p of %s (skipped)", data, id, type); + return; + } + + data_offer->types.insert(std::string(type)); +} + +static const struct zwp_primary_selection_offer_v1_listener primary_selection_offer_listener = { + primary_selection_offer_offer, +}; + +#undef LOG + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Listener (Primary Selection Device), #zwp_primary_selection_device_v1_listener + * \{ */ + +static CLG_LogRef LOG_WL_PRIMARY_SELECTION_DEVICE = {"ghost.wl.handle.primary_selection_device"}; +#define LOG (&LOG_WL_PRIMARY_SELECTION_DEVICE) + +static void primary_selection_device_handle_data_offer( + void * /*data*/, + struct zwp_primary_selection_device_v1 * /*zwp_primary_selection_device_v1*/, + struct zwp_primary_selection_offer_v1 *id) +{ + CLOG_INFO(LOG, 2, "data_offer"); + + GWL_PrimarySelection_DataOffer *data_offer = new GWL_PrimarySelection_DataOffer; + data_offer->id = id; + zwp_primary_selection_offer_v1_add_listener(id, &primary_selection_offer_listener, data_offer); +} + +static void primary_selection_device_handle_selection( + void *data, + struct zwp_primary_selection_device_v1 * /*zwp_primary_selection_device_v1*/, + struct zwp_primary_selection_offer_v1 *id) +{ + GWL_PrimarySelection *primary = static_cast<GWL_PrimarySelection *>(data); + + std::lock_guard lock{primary->data_offer_mutex}; + + /* Delete old data offer. */ + if (primary->data_offer != nullptr) { + gwl_primary_selection_discard_offer(primary); + } + + if (id == nullptr) { + CLOG_INFO(LOG, 2, "selection: (skipped)"); + return; + } + CLOG_INFO(LOG, 2, "selection"); + /* Get new data offer. */ + GWL_PrimarySelection_DataOffer *data_offer = static_cast<GWL_PrimarySelection_DataOffer *>( + zwp_primary_selection_offer_v1_get_user_data(id)); + primary->data_offer = data_offer; + + auto read_selection_fn = [](GWL_PrimarySelection *primary) { + GHOST_SystemWayland *system = static_cast<GHOST_SystemWayland *>(GHOST_ISystem::getSystem()); + primary->data_offer_mutex.lock(); + + GWL_PrimarySelection_DataOffer *data_offer = primary->data_offer; + std::string mime_receive; + for (const std::string type : {mime_text_utf8, mime_text_plain}) { + if (data_offer->types.count(type)) { + mime_receive = type; + break; + } + } + size_t data_len = 0; + const char *data = read_buffer_from_primary_selection_offer( + data_offer, mime_receive.c_str(), &primary->data_offer_mutex, &data_len); + + { + std::lock_guard lock{system_clipboard_mutex}; + GWL_SimpleBuffer *buf = system->clipboard_data(true); + gwl_simple_buffer_set_and_take_ownership(buf, data, data_len); + } + }; + + std::thread read_thread(read_selection_fn, primary); + read_thread.detach(); +} + +static const struct zwp_primary_selection_device_v1_listener primary_selection_device_listener = { + primary_selection_device_handle_data_offer, + primary_selection_device_handle_selection, +}; + +#undef LOG + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Listener (Primary Selection Source), #zwp_primary_selection_source_v1_listener + * \{ */ + +static CLG_LogRef LOG_WL_PRIMARY_SELECTION_SOURCE = {"ghost.wl.handle.primary_selection_source"}; +#define LOG (&LOG_WL_PRIMARY_SELECTION_SOURCE) + +static void primary_selection_source_send(void *data, + struct zwp_primary_selection_source_v1 * /*source*/, + const char * /*mime_type*/, + int32_t fd) +{ + CLOG_INFO(LOG, 2, "send"); + + GWL_PrimarySelection *primary = static_cast<GWL_PrimarySelection *>(data); + + std::lock_guard lock{primary->data_source_mutex}; + GWL_PrimarySelection_DataSource *data_source = primary->data_source; + + const char *const buffer = data_source->buffer_out.data; + if (UNLIKELY(write(fd, buffer, data_source->buffer_out.data_size) < 0)) { + CLOG_WARN(LOG, "error writing to primary clipboard: %s", std::strerror(errno)); + } + close(fd); +} + +static void primary_selection_source_cancelled(void *data, + struct zwp_primary_selection_source_v1 *source) +{ + CLOG_INFO(LOG, 2, "cancelled"); + + GWL_PrimarySelection *primary = static_cast<GWL_PrimarySelection *>(data); + + if (source == primary->data_source->wp_source) { + gwl_primary_selection_discard_source(primary); + } +} + +static const struct zwp_primary_selection_source_v1_listener primary_selection_source_listener = { + primary_selection_source_send, + primary_selection_source_cancelled, +}; + +#undef LOG + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Listener (Seat), #wl_seat_listener * \{ */ static CLG_LogRef LOG_WL_SEAT = {"ghost.wl.handle.seat"}; #define LOG (&LOG_WL_SEAT) +static void gwl_seat_capability_pointer_enable(GWL_Seat *seat) +{ + if (seat->wl_pointer) { + return; + } + seat->wl_pointer = wl_seat_get_pointer(seat->wl_seat); + seat->cursor.wl_surface = wl_compositor_create_surface(seat->system->wl_compositor()); + seat->cursor.visible = true; + seat->cursor.wl_buffer = nullptr; + if (!get_cursor_settings(seat->cursor.theme_name, seat->cursor.theme_size)) { + seat->cursor.theme_name = std::string(); + seat->cursor.theme_size = default_cursor_size; + } + wl_pointer_add_listener(seat->wl_pointer, &pointer_listener, seat); + + wl_surface_add_listener(seat->cursor.wl_surface, &cursor_surface_listener, seat); + ghost_wl_surface_tag_cursor_pointer(seat->cursor.wl_surface); + + zwp_pointer_gestures_v1 *pointer_gestures = seat->system->wp_pointer_gestures(); + if (pointer_gestures) { + { /* Hold gesture. */ + struct zwp_pointer_gesture_hold_v1 *gesture = zwp_pointer_gestures_v1_get_hold_gesture( + pointer_gestures, seat->wl_pointer); + zwp_pointer_gesture_hold_v1_set_user_data(gesture, seat); + zwp_pointer_gesture_hold_v1_add_listener(gesture, &gesture_hold_listener, seat); + seat->wp_pointer_gesture_hold = gesture; + } + { /* Pinch gesture. */ + struct zwp_pointer_gesture_pinch_v1 *gesture = zwp_pointer_gestures_v1_get_pinch_gesture( + pointer_gestures, seat->wl_pointer); + zwp_pointer_gesture_pinch_v1_set_user_data(gesture, seat); + zwp_pointer_gesture_pinch_v1_add_listener(gesture, &gesture_pinch_listener, seat); + seat->wp_pointer_gesture_pinch = gesture; + } + { /* Swipe gesture. */ + struct zwp_pointer_gesture_swipe_v1 *gesture = zwp_pointer_gestures_v1_get_swipe_gesture( + pointer_gestures, seat->wl_pointer); + zwp_pointer_gesture_swipe_v1_set_user_data(gesture, seat); + zwp_pointer_gesture_swipe_v1_add_listener(gesture, &gesture_swipe_listener, seat); + seat->wp_pointer_gesture_swipe = gesture; + } + } +} + +static void gwl_seat_capability_pointer_disable(GWL_Seat *seat) +{ + if (!seat->wl_pointer) { + return; + } + + zwp_pointer_gestures_v1 *pointer_gestures = seat->system->wp_pointer_gestures(); + if (pointer_gestures) { + { /* Hold gesture. */ + struct zwp_pointer_gesture_hold_v1 **gesture_p = &seat->wp_pointer_gesture_hold; + if (*gesture_p) { + zwp_pointer_gesture_hold_v1_destroy(*gesture_p); + *gesture_p = nullptr; + } + } + { /* Pinch gesture. */ + struct zwp_pointer_gesture_pinch_v1 **gesture_p = &seat->wp_pointer_gesture_pinch; + if (*gesture_p) { + zwp_pointer_gesture_pinch_v1_destroy(*gesture_p); + *gesture_p = nullptr; + } + } + { /* Swipe gesture. */ + struct zwp_pointer_gesture_swipe_v1 **gesture_p = &seat->wp_pointer_gesture_swipe; + if (*gesture_p) { + zwp_pointer_gesture_swipe_v1_destroy(*gesture_p); + *gesture_p = nullptr; + } + } + } + + if (seat->cursor.wl_surface) { + wl_surface_destroy(seat->cursor.wl_surface); + seat->cursor.wl_surface = nullptr; + } + if (seat->cursor.wl_theme) { + wl_cursor_theme_destroy(seat->cursor.wl_theme); + seat->cursor.wl_theme = nullptr; + } + + wl_pointer_destroy(seat->wl_pointer); + seat->wl_pointer = nullptr; +} + +static void gwl_seat_capability_keyboard_enable(GWL_Seat *seat) +{ + if (seat->wl_keyboard) { + return; + } + seat->wl_keyboard = wl_seat_get_keyboard(seat->wl_seat); + wl_keyboard_add_listener(seat->wl_keyboard, &keyboard_listener, seat); +} + +static void gwl_seat_capability_keyboard_disable(GWL_Seat *seat) +{ + if (!seat->wl_keyboard) { + return; + } + if (seat->key_repeat.timer) { + keyboard_handle_key_repeat_cancel(seat); + } + wl_keyboard_destroy(seat->wl_keyboard); + seat->wl_keyboard = nullptr; +} + +static void gwl_seat_capability_touch_enable(GWL_Seat *seat) +{ + if (seat->wl_touch) { + return; + } + seat->wl_touch = wl_seat_get_touch(seat->wl_seat); + wl_touch_set_user_data(seat->wl_touch, seat); + wl_touch_add_listener(seat->wl_touch, &touch_seat_listener, seat); +} + +static void gwl_seat_capability_touch_disable(GWL_Seat *seat) +{ + if (!seat->wl_touch) { + return; + } + wl_touch_destroy(seat->wl_touch); + seat->wl_touch = nullptr; +} + static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, const uint32_t capabilities) @@ -2699,27 +3691,43 @@ static void seat_handle_capabilities(void *data, (capabilities & WL_SEAT_CAPABILITY_TOUCH) != 0); GWL_Seat *seat = static_cast<GWL_Seat *>(data); - seat->wl_pointer = nullptr; - seat->wl_keyboard = nullptr; + GHOST_ASSERT(seat->wl_seat == wl_seat, "Seat mismatch"); if (capabilities & WL_SEAT_CAPABILITY_POINTER) { - seat->wl_pointer = wl_seat_get_pointer(wl_seat); - seat->cursor.wl_surface = wl_compositor_create_surface(seat->system->wl_compositor()); - seat->cursor.visible = true; - seat->cursor.wl_buffer = nullptr; - if (!get_cursor_settings(seat->cursor.theme_name, seat->cursor.size)) { - seat->cursor.theme_name = std::string(); - seat->cursor.size = default_cursor_size; - } - wl_pointer_add_listener(seat->wl_pointer, &pointer_listener, data); - - wl_surface_add_listener(seat->cursor.wl_surface, &cursor_surface_listener, data); - ghost_wl_surface_tag_cursor_pointer(seat->cursor.wl_surface); + gwl_seat_capability_pointer_enable(seat); + } + else { + gwl_seat_capability_pointer_disable(seat); } if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { - seat->wl_keyboard = wl_seat_get_keyboard(wl_seat); - wl_keyboard_add_listener(seat->wl_keyboard, &keyboard_listener, data); + gwl_seat_capability_keyboard_enable(seat); + } + else { + gwl_seat_capability_keyboard_disable(seat); + } + + if (capabilities & WL_SEAT_CAPABILITY_TOUCH) { + gwl_seat_capability_touch_enable(seat); + } + else { + gwl_seat_capability_touch_disable(seat); + } + + /* TODO(@campbellbarton): this could be moved out elsewhere. */ + if (seat->system) { + zwp_primary_selection_device_manager_v1 *primary_selection_device_manager = + seat->system->wp_primary_selection_manager(); + if (primary_selection_device_manager) { + if (seat->wp_primary_selection_device == nullptr) { + seat->wp_primary_selection_device = zwp_primary_selection_device_manager_v1_get_device( + primary_selection_device_manager, seat->wl_seat); + + zwp_primary_selection_device_v1_add_listener(seat->wp_primary_selection_device, + &primary_selection_device_listener, + &seat->primary_selection); + } + } } } @@ -3026,13 +4034,13 @@ static void global_handle_add(void *data, wl_registry_bind(wl_registry, name, &wl_compositor_interface, 3)); } else if (STREQ(interface, xdg_wm_base_interface.name)) { - WGL_XDG_Decor_System &decor = *display->xdg_decor; + GWL_XDG_Decor_System &decor = *display->xdg_decor; decor.shell = static_cast<xdg_wm_base *>( wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1)); xdg_wm_base_add_listener(decor.shell, &shell_listener, nullptr); } else if (STREQ(interface, zxdg_decoration_manager_v1_interface.name)) { - WGL_XDG_Decor_System &decor = *display->xdg_decor; + GWL_XDG_Decor_System &decor = *display->xdg_decor; decor.manager = static_cast<zxdg_decoration_manager_v1 *>( wl_registry_bind(wl_registry, name, &zxdg_decoration_manager_v1_interface, 1)); } @@ -3076,21 +4084,32 @@ static void global_handle_add(void *data, wl_registry_bind(wl_registry, name, &wl_shm_interface, 1)); } else if (STREQ(interface, wl_data_device_manager_interface.name)) { - display->data_device_manager = static_cast<wl_data_device_manager *>( + display->wl_data_device_manager = static_cast<wl_data_device_manager *>( wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, 3)); } else if (STREQ(interface, zwp_tablet_manager_v2_interface.name)) { - display->tablet_manager = static_cast<zwp_tablet_manager_v2 *>( + display->wp_tablet_manager = static_cast<zwp_tablet_manager_v2 *>( wl_registry_bind(wl_registry, name, &zwp_tablet_manager_v2_interface, 1)); } else if (STREQ(interface, zwp_relative_pointer_manager_v1_interface.name)) { - display->relative_pointer_manager = static_cast<zwp_relative_pointer_manager_v1 *>( + display->wp_relative_pointer_manager = static_cast<zwp_relative_pointer_manager_v1 *>( wl_registry_bind(wl_registry, name, &zwp_relative_pointer_manager_v1_interface, 1)); } else if (STREQ(interface, zwp_pointer_constraints_v1_interface.name)) { - display->pointer_constraints = static_cast<zwp_pointer_constraints_v1 *>( + display->wp_pointer_constraints = static_cast<zwp_pointer_constraints_v1 *>( wl_registry_bind(wl_registry, name, &zwp_pointer_constraints_v1_interface, 1)); } + else if (STREQ(interface, zwp_pointer_gestures_v1_interface.name)) { + display->wp_pointer_gestures = static_cast<zwp_pointer_gestures_v1 *>( + wl_registry_bind(wl_registry, name, &zwp_pointer_gestures_v1_interface, 3)); + } + + else if (!strcmp(interface, zwp_primary_selection_device_manager_v1_interface.name)) { + display->wp_primary_selection_device_manager = + static_cast<zwp_primary_selection_device_manager_v1 *>(wl_registry_bind( + wl_registry, name, &zwp_primary_selection_device_manager_v1_interface, 1)); + } + else { found = false; @@ -3156,7 +4175,7 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), display_(new GWL_Di } /* This may be removed later if decorations are required, needed as part of registration. */ - display_->xdg_decor = new WGL_XDG_Decor_System; + display_->xdg_decor = new GWL_XDG_Decor_System; /* Register interfaces. */ struct wl_registry *registry = wl_display_get_registry(display_->wl_display); @@ -3169,7 +4188,7 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), display_(new GWL_Di #ifdef WITH_GHOST_WAYLAND_LIBDECOR if (display_->libdecor_required) { - wgl_xdg_decor_system_destroy(display_->xdg_decor); + gwl_xdg_decor_system_destroy(display_->xdg_decor); display_->xdg_decor = nullptr; if (!has_libdecor) { @@ -3190,8 +4209,8 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), display_(new GWL_Di #ifdef WITH_GHOST_WAYLAND_LIBDECOR if (use_libdecor) { - display_->libdecor = new WGL_LibDecor_System; - WGL_LibDecor_System &decor = *display_->libdecor; + display_->libdecor = new GWL_LibDecor_System; + GWL_LibDecor_System &decor = *display_->libdecor; decor.context = libdecor_new(display_->wl_display, &libdecor_interface); if (!decor.context) { display_destroy(display_); @@ -3201,7 +4220,7 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), display_(new GWL_Di else #endif { - WGL_XDG_Decor_System &decor = *display_->xdg_decor; + GWL_XDG_Decor_System &decor = *display_->xdg_decor; if (!decor.shell) { display_destroy(display_); throw std::runtime_error("Wayland: unable to access xdg_shell!"); @@ -3209,19 +4228,19 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), display_(new GWL_Di } /* Register data device per seat for IPC between Wayland clients. */ - if (display_->data_device_manager) { + if (display_->wl_data_device_manager) { for (GWL_Seat *seat : display_->seats) { - seat->data_device = wl_data_device_manager_get_data_device(display_->data_device_manager, - seat->wl_seat); - wl_data_device_add_listener(seat->data_device, &data_device_listener, seat); + seat->wl_data_device = wl_data_device_manager_get_data_device( + display_->wl_data_device_manager, seat->wl_seat); + wl_data_device_add_listener(seat->wl_data_device, &data_device_listener, seat); } } - if (display_->tablet_manager) { + if (display_->wp_tablet_manager) { for (GWL_Seat *seat : display_->seats) { - seat->tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(display_->tablet_manager, - seat->wl_seat); - zwp_tablet_seat_v2_add_listener(seat->tablet_seat, &tablet_seat_listener, seat); + seat->wp_tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(display_->wp_tablet_manager, + seat->wl_seat); + zwp_tablet_seat_v2_add_listener(seat->wp_tablet_seat, &tablet_seat_listener, seat); } } } @@ -3300,7 +4319,7 @@ GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) co } #endif - /* Use local #WGL_KeyboardDepressedState to check which key is pressed. + /* Use local #GWL_KeyboardDepressedState to check which key is pressed. * Use XKB as the source of truth, if there is any discrepancy. */ for (int i = 0; i < MOD_INDEX_NUM; i++) { if (UNLIKELY(seat->xkb_keymap_mod_index[i] == XKB_MOD_INVALID)) { @@ -3358,43 +4377,86 @@ GHOST_TSuccess GHOST_SystemWayland::getButtons(GHOST_Buttons &buttons) const return GHOST_kSuccess; } -char *GHOST_SystemWayland::getClipboard(bool /*selection*/) const +char *GHOST_SystemWayland::getClipboard(bool selection) const { - char *clipboard = static_cast<char *>(malloc(clipboard_.size() + 1)); - memcpy(clipboard, clipboard_.data(), clipboard_.size() + 1); - return clipboard; + const GWL_SimpleBuffer *buf = clipboard_data(selection); + if (buf->data == nullptr) { + return nullptr; + } + return gwl_simple_buffer_as_string(buf); } -void GHOST_SystemWayland::putClipboard(const char *buffer, bool /*selection*/) const +static void system_clipboard_put_primary_selection(GWL_Display *display, const char *buffer) { - if (UNLIKELY(!display_->data_device_manager || display_->seats.empty())) { + if (!display->wp_primary_selection_device_manager) { return; } + GWL_Seat *seat = display->seats[0]; + GWL_PrimarySelection *primary = &seat->primary_selection; - GWL_Seat *seat = display_->seats[0]; + std::lock_guard lock{primary->data_source_mutex}; + + gwl_primary_selection_discard_source(primary); + + GWL_PrimarySelection_DataSource *data_source = new GWL_PrimarySelection_DataSource; + primary->data_source = data_source; + + /* Copy buffer. */ + gwl_simple_buffer_set_from_string(&data_source->buffer_out, buffer); + + data_source->wp_source = zwp_primary_selection_device_manager_v1_create_source( + display->wp_primary_selection_device_manager); + + zwp_primary_selection_source_v1_add_listener( + data_source->wp_source, &primary_selection_source_listener, primary); + + for (const std::string &type : mime_send) { + zwp_primary_selection_source_v1_offer(data_source->wp_source, type.c_str()); + } + + if (seat->wp_primary_selection_device) { + zwp_primary_selection_device_v1_set_selection( + seat->wp_primary_selection_device, data_source->wp_source, seat->data_source_serial); + } +} + +static void system_clipboard_put(GWL_Display *display, const char *buffer) +{ + GWL_Seat *seat = display->seats[0]; std::lock_guard lock{seat->data_source_mutex}; GWL_DataSource *data_source = seat->data_source; /* Copy buffer. */ - free(data_source->buffer_out); - const size_t buffer_size = strlen(buffer) + 1; - data_source->buffer_out = static_cast<char *>(malloc(buffer_size)); - std::memcpy(data_source->buffer_out, buffer, buffer_size); + gwl_simple_buffer_set_from_string(&data_source->buffer_out, buffer); - data_source->data_source = wl_data_device_manager_create_data_source( - display_->data_device_manager); + data_source->wl_source = wl_data_device_manager_create_data_source( + display->wl_data_device_manager); - wl_data_source_add_listener(data_source->data_source, &data_source_listener, seat); + wl_data_source_add_listener(data_source->wl_source, &data_source_listener, seat); for (const std::string &type : mime_send) { - wl_data_source_offer(data_source->data_source, type.c_str()); + wl_data_source_offer(data_source->wl_source, type.c_str()); } - if (seat->data_device) { + if (seat->wl_data_device) { wl_data_device_set_selection( - seat->data_device, data_source->data_source, seat->data_source_serial); + seat->wl_data_device, data_source->wl_source, seat->data_source_serial); + } +} + +void GHOST_SystemWayland::putClipboard(const char *buffer, bool selection) const +{ + if (UNLIKELY(!display_->wl_data_device_manager || display_->seats.empty())) { + return; + } + + if (selection) { + system_clipboard_put_primary_selection(display_, buffer); + } + else { + system_clipboard_put(display_, buffer); } } @@ -3423,7 +4485,7 @@ static GHOST_TSuccess setCursorPositionClientRelative_impl(GWL_Seat *seat, /* NOTE: WAYLAND doesn't support warping the cursor. * However when grab is enabled, we already simulate a cursor location * so that can be set to a new location. */ - if (!seat->relative_pointer) { + if (!seat->wp_relative_pointer) { return GHOST_kFailure; } const wl_fixed_t scale = win->scale(); @@ -3616,7 +4678,6 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title, const uint32_t width, const uint32_t height, const GHOST_TWindowState state, - const GHOST_TDrawingContextType type, const GHOST_GLSettings glSettings, const bool exclusive, const bool is_dialog, @@ -3636,7 +4697,7 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title, height, state, parentWindow, - type, + glSettings.context_type, is_dialog, ((glSettings.flags & GHOST_glStereoVisual) != 0), exclusive); @@ -3664,22 +4725,22 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title, */ static void cursor_buffer_show(const GWL_Seat *seat) { - const GWL_Cursor *c = &seat->cursor; + const GWL_Cursor *cursor = &seat->cursor; if (seat->wl_pointer) { - const int scale = c->is_custom ? c->custom_scale : seat->pointer.theme_scale; - const int32_t hotspot_x = int32_t(c->wl_image.hotspot_x) / scale; - const int32_t hotspot_y = int32_t(c->wl_image.hotspot_y) / scale; + const int scale = cursor->is_custom ? cursor->custom_scale : seat->pointer.theme_scale; + const int32_t hotspot_x = int32_t(cursor->wl_image.hotspot_x) / scale; + const int32_t hotspot_y = int32_t(cursor->wl_image.hotspot_y) / scale; if (seat->wl_pointer) { wl_pointer_set_cursor( - seat->wl_pointer, seat->pointer.serial, c->wl_surface, hotspot_x, hotspot_y); + seat->wl_pointer, seat->pointer.serial, cursor->wl_surface, hotspot_x, hotspot_y); } } if (!seat->tablet_tools.empty()) { - const int scale = c->is_custom ? c->custom_scale : seat->tablet.theme_scale; - const int32_t hotspot_x = int32_t(c->wl_image.hotspot_x) / scale; - const int32_t hotspot_y = int32_t(c->wl_image.hotspot_y) / scale; + const int scale = cursor->is_custom ? cursor->custom_scale : seat->tablet.theme_scale; + const int32_t hotspot_x = int32_t(cursor->wl_image.hotspot_x) / scale; + const int32_t hotspot_y = int32_t(cursor->wl_image.hotspot_y) / scale; for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->tablet_tools) { GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>( zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2)); @@ -3742,21 +4803,21 @@ static void cursor_buffer_set_surface_impl(const GWL_Seat *seat, static void cursor_buffer_set(const GWL_Seat *seat, wl_buffer *buffer) { - const GWL_Cursor *c = &seat->cursor; + const GWL_Cursor *cursor = &seat->cursor; const wl_cursor_image *wl_image = &seat->cursor.wl_image; - const bool visible = (c->visible && c->is_hardware); + const bool visible = (cursor->visible && cursor->is_hardware); /* This is a requirement of WAYLAND, when this isn't the case, * it causes Blender's window to close intermittently. */ if (seat->wl_pointer) { const int scale = cursor_buffer_compatible_scale_from_image( - wl_image, c->is_custom ? c->custom_scale : seat->pointer.theme_scale); + wl_image, cursor->is_custom ? cursor->custom_scale : seat->pointer.theme_scale); const int32_t hotspot_x = int32_t(wl_image->hotspot_x) / scale; const int32_t hotspot_y = int32_t(wl_image->hotspot_y) / scale; - cursor_buffer_set_surface_impl(seat, buffer, c->wl_surface, scale); + cursor_buffer_set_surface_impl(seat, buffer, cursor->wl_surface, scale); wl_pointer_set_cursor(seat->wl_pointer, seat->pointer.serial, - visible ? c->wl_surface : nullptr, + visible ? cursor->wl_surface : nullptr, hotspot_x, hotspot_y); } @@ -3764,7 +4825,7 @@ static void cursor_buffer_set(const GWL_Seat *seat, wl_buffer *buffer) /* Set the cursor for all tablet tools as well. */ if (!seat->tablet_tools.empty()) { const int scale = cursor_buffer_compatible_scale_from_image( - wl_image, c->is_custom ? c->custom_scale : seat->tablet.theme_scale); + wl_image, cursor->is_custom ? cursor->custom_scale : seat->tablet.theme_scale); const int32_t hotspot_x = int32_t(wl_image->hotspot_x) / scale; const int32_t hotspot_y = int32_t(wl_image->hotspot_y) / scale; for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->tablet_tools) { @@ -3851,31 +4912,31 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(const GHOST_TStandardCursor s (*cursor_find).second; GWL_Seat *seat = display_->seats[0]; - GWL_Cursor *c = &seat->cursor; + GWL_Cursor *cursor = &seat->cursor; - if (!c->wl_theme) { + if (!cursor->wl_theme) { /* The cursor wl_surface hasn't entered an output yet. Initialize theme with scale 1. */ - c->wl_theme = wl_cursor_theme_load( - c->theme_name.c_str(), c->size, display_->seats[0]->system->wl_shm()); + cursor->wl_theme = wl_cursor_theme_load( + cursor->theme_name.c_str(), cursor->theme_size, wl_shm()); } - wl_cursor *cursor = wl_cursor_theme_get_cursor(c->wl_theme, cursor_name); + wl_cursor *wl_cursor = wl_cursor_theme_get_cursor(cursor->wl_theme, cursor_name); - if (!cursor) { + if (!wl_cursor) { GHOST_PRINT("cursor '" << cursor_name << "' does not exist" << std::endl); return GHOST_kFailure; } - struct wl_cursor_image *image = cursor->images[0]; + struct wl_cursor_image *image = wl_cursor->images[0]; struct wl_buffer *buffer = wl_cursor_image_get_buffer(image); if (!buffer) { return GHOST_kFailure; } - c->visible = true; - c->is_custom = false; - c->wl_buffer = buffer; - c->wl_image = *image; + cursor->visible = true; + cursor->is_custom = false; + cursor->wl_buffer = buffer; + cursor->wl_image = *image; cursor_buffer_set(seat, buffer); @@ -4062,11 +5123,10 @@ static GWL_SeatStateGrab seat_grab_state_from_mode(const GHOST_TGrabCursorMode m const bool use_software_confine) { /* Initialize all members. */ - const struct GWL_SeatStateGrab grab_state = { - /* Warping happens to require software cursor which also hides. */ - .use_lock = ELEM(mode, GHOST_kGrabWrap, GHOST_kGrabHide) || use_software_confine, - .use_confine = (mode == GHOST_kGrabNormal) && (use_software_confine == false), - }; + GWL_SeatStateGrab grab_state; + /* Warping happens to require software cursor which also hides. */ + grab_state.use_lock = ELEM(mode, GHOST_kGrabWrap, GHOST_kGrabHide) || use_software_confine; + grab_state.use_confine = (mode == GHOST_kGrabNormal) && (use_software_confine == false); return grab_state; } @@ -4140,6 +5200,16 @@ wl_compositor *GHOST_SystemWayland::wl_compositor() return display_->wl_compositor; } +struct zwp_primary_selection_device_manager_v1 *GHOST_SystemWayland::wp_primary_selection_manager() +{ + return display_->wp_primary_selection_device_manager; +} + +struct zwp_pointer_gestures_v1 *GHOST_SystemWayland::wp_pointer_gestures() +{ + return display_->wp_pointer_gestures; +} + #ifdef WITH_GHOST_WAYLAND_LIBDECOR libdecor *GHOST_SystemWayland::libdecor_context() @@ -4202,11 +5272,6 @@ GHOST_WindowWayland *ghost_wl_surface_user_data(struct wl_surface *wl_surface) * Functionality only used for the WAYLAND implementation. * \{ */ -void GHOST_SystemWayland::clipboard_set(const std::string &clipboard) -{ - clipboard_ = clipboard; -} - void GHOST_SystemWayland::window_surface_unref(const wl_surface *wl_surface) { #define SURFACE_CLEAR_PTR(surface_test) \ @@ -4234,7 +5299,7 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod const int scale) { /* Ignore, if the required protocols are not supported. */ - if (UNLIKELY(!display_->relative_pointer_manager || !display_->pointer_constraints)) { + if (UNLIKELY(!display_->wp_relative_pointer_manager || !display_->wp_pointer_constraints)) { return GHOST_kFailure; } @@ -4273,11 +5338,11 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod * in this case disable the current locks as it makes logic confusing, * postpone changing the cursor to avoid flickering. */ if (!grab_state_next.use_lock) { - if (seat->relative_pointer) { - zwp_relative_pointer_v1_destroy(seat->relative_pointer); - seat->relative_pointer = nullptr; + if (seat->wp_relative_pointer) { + zwp_relative_pointer_v1_destroy(seat->wp_relative_pointer); + seat->wp_relative_pointer = nullptr; } - if (seat->locked_pointer) { + if (seat->wp_locked_pointer) { /* Potentially add a motion event so the application has updated X/Y coordinates. */ int32_t xy_motion[2] = {0, 0}; bool xy_motion_create_event = false; @@ -4306,7 +5371,7 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod seat->pointer.xy[0] = xy_next[0]; seat->pointer.xy[1] = xy_next[1]; - zwp_locked_pointer_v1_set_cursor_position_hint(seat->locked_pointer, UNPACK2(xy_next)); + zwp_locked_pointer_v1_set_cursor_position_hint(seat->wp_locked_pointer, UNPACK2(xy_next)); wl_surface_commit(wl_surface); } else if (mode_current == GHOST_kGrabHide) { @@ -4316,7 +5381,8 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod wl_fixed_from_int(init_grab_xy[0]) / scale, wl_fixed_from_int(init_grab_xy[1]) / scale, }; - zwp_locked_pointer_v1_set_cursor_position_hint(seat->locked_pointer, UNPACK2(xy_next)); + zwp_locked_pointer_v1_set_cursor_position_hint(seat->wp_locked_pointer, + UNPACK2(xy_next)); wl_surface_commit(wl_surface); /* NOTE(@campbellbarton): The new cursor position is a hint, @@ -4330,7 +5396,7 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod #ifdef USE_GNOME_CONFINE_HACK else if (mode_current == GHOST_kGrabNormal) { if (was_software_confine) { - zwp_locked_pointer_v1_set_cursor_position_hint(seat->locked_pointer, + zwp_locked_pointer_v1_set_cursor_position_hint(seat->wp_locked_pointer, UNPACK2(seat->pointer.xy)); wl_surface_commit(wl_surface); } @@ -4346,15 +5412,15 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod GHOST_TABLET_DATA_NONE)); } - zwp_locked_pointer_v1_destroy(seat->locked_pointer); - seat->locked_pointer = nullptr; + zwp_locked_pointer_v1_destroy(seat->wp_locked_pointer); + seat->wp_locked_pointer = nullptr; } } if (!grab_state_next.use_confine) { - if (seat->confined_pointer) { - zwp_confined_pointer_v1_destroy(seat->confined_pointer); - seat->confined_pointer = nullptr; + if (seat->wp_confined_pointer) { + zwp_confined_pointer_v1_destroy(seat->wp_confined_pointer); + seat->wp_confined_pointer = nullptr; } } @@ -4365,12 +5431,12 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod * possible to support #GHOST_kGrabWrap by pragmatically settings it's coordinates. * An alternative could be to draw the cursor in software (and hide the real cursor), * or just accept a locked cursor on WAYLAND. */ - seat->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer( - display_->relative_pointer_manager, seat->wl_pointer); + seat->wp_relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer( + display_->wp_relative_pointer_manager, seat->wl_pointer); zwp_relative_pointer_v1_add_listener( - seat->relative_pointer, &relative_pointer_listener, seat); - seat->locked_pointer = zwp_pointer_constraints_v1_lock_pointer( - display_->pointer_constraints, + seat->wp_relative_pointer, &relative_pointer_listener, seat); + seat->wp_locked_pointer = zwp_pointer_constraints_v1_lock_pointer( + display_->wp_pointer_constraints, wl_surface, seat->wl_pointer, nullptr, @@ -4387,8 +5453,8 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod } else if (grab_state_next.use_confine) { if (!grab_state_prev.use_confine) { - seat->confined_pointer = zwp_pointer_constraints_v1_confine_pointer( - display_->pointer_constraints, + seat->wp_confined_pointer = zwp_pointer_constraints_v1_confine_pointer( + display_->wp_pointer_constraints, wl_surface, seat->wl_pointer, nullptr, @@ -4407,6 +5473,11 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod return GHOST_kSuccess; } +struct GWL_SimpleBuffer *GHOST_SystemWayland::clipboard_data(bool selection) const +{ + return selection ? &display_->clipboard_primary : &display_->clipboard; +} + #ifdef WITH_GHOST_WAYLAND_LIBDECOR bool GHOST_SystemWayland::use_libdecor_runtime() { diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h index 5d2cfe45582..f08e9fdcf9c 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.h +++ b/intern/ghost/intern/GHOST_SystemWayland.h @@ -88,7 +88,7 @@ class GHOST_SystemWayland : public GHOST_System { ~GHOST_SystemWayland() override; - GHOST_TSuccess init(); + GHOST_TSuccess init() override; bool processEvents(bool waitForEvent) override; @@ -128,7 +128,6 @@ class GHOST_SystemWayland : public GHOST_System { uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive, const bool is_dialog, @@ -150,8 +149,8 @@ class GHOST_SystemWayland : public GHOST_System { GHOST_TSuccess setCursorVisibility(bool visible); - bool supportsCursorWarp(); - bool supportsWindowPosition(); + bool supportsCursorWarp() override; + bool supportsWindowPosition() override; bool getCursorGrabUseSoftwareDisplay(const GHOST_TGrabCursorMode mode); @@ -159,6 +158,8 @@ class GHOST_SystemWayland : public GHOST_System { struct wl_display *wl_display(); struct wl_compositor *wl_compositor(); + struct zwp_primary_selection_device_manager_v1 *wp_primary_selection_manager(); + struct zwp_pointer_gestures_v1 *wp_pointer_gestures(); #ifdef WITH_GHOST_WAYLAND_LIBDECOR libdecor *libdecor_context(); @@ -173,8 +174,6 @@ class GHOST_SystemWayland : public GHOST_System { /* WAYLAND utility functions. */ - void clipboard_set(const std::string &clipboard); - /** Clear all references to this surface to prevent accessing NULL pointers. */ void window_surface_unref(const wl_surface *wl_surface); @@ -186,11 +185,12 @@ class GHOST_SystemWayland : public GHOST_System { wl_surface *wl_surface, int scale); + struct GWL_SimpleBuffer *clipboard_data(bool selection) const; + #ifdef WITH_GHOST_WAYLAND_LIBDECOR static bool use_libdecor_runtime(); #endif private: struct GWL_Display *display_; - std::string clipboard_; }; diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 667198241f0..54c892d296e 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -213,7 +213,6 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const char *title, uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive, const bool is_dialog, @@ -227,7 +226,7 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const char *title, width, height, state, - type, + glSettings.context_type, ((glSettings.flags & GHOST_glStereoVisual) != 0), false, (GHOST_WindowWin32 *)parentWindow, diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h index f5cd0055b34..98a7e5dfb35 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -103,7 +103,6 @@ class GHOST_SystemWin32 : public GHOST_System { * \param width: The width the window. * \param height: The height the window. * \param state: The state of the window when opened. - * \param type: The type of drawing context installed in this window. * \param glSettings: Misc OpenGL settings. * \param exclusive: Use to show the window on top and ignore others (used full-screen). * \param parentWindow: Parent window. @@ -115,7 +114,6 @@ class GHOST_SystemWin32 : public GHOST_System { uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive = false, const bool is_dialog = false, diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 4523f6fa37c..5c89febe97c 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -308,7 +308,6 @@ void GHOST_SystemX11::getAllDisplayDimensions(uint32_t &width, uint32_t &height) * \param width: The width the window. * \param height: The height the window. * \param state: The state of the window when opened. - * \param type: The type of drawing context installed in this window. * \param glSettings: Misc OpenGL settings. * \param exclusive: Use to show the window on top and ignore others (used full-screen). * \param parentWindow: Parent window. @@ -320,7 +319,6 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title, uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive, const bool is_dialog, @@ -341,7 +339,7 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title, height, state, (GHOST_WindowX11 *)parentWindow, - type, + glSettings.context_type, is_dialog, ((glSettings.flags & GHOST_glStereoVisual) != 0), exclusive, diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index 572be30174d..1f071da6da7 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -113,7 +113,6 @@ class GHOST_SystemX11 : public GHOST_System { * \param width: The width the window. * \param height: The height the window. * \param state: The state of the window when opened. - * \param type: The type of drawing context installed in this window. * \param stereoVisual: Create a stereo visual for quad buffered stereo. * \param exclusive: Use to show the window on top and ignore others (used full-screen). * \param parentWindow: Parent (embedder) window. @@ -125,7 +124,6 @@ class GHOST_SystemX11 : public GHOST_System { uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive = false, const bool is_dialog = false, diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index 737fd64bdf0..bc1f1e99a3a 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -803,10 +803,10 @@ GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order) GHOST_Context *GHOST_WindowCocoa::newDrawingContext(GHOST_TDrawingContextType type) { - if (type == GHOST_kDrawingContextTypeOpenGL) { + if (type == GHOST_kDrawingContextTypeOpenGL || type == GHOST_kDrawingContextTypeMetal) { GHOST_Context *context = new GHOST_ContextCGL( - m_wantStereoVisual, m_metalView, m_metalLayer, m_openGLView); + m_wantStereoVisual, m_metalView, m_metalLayer, m_openGLView, type); if (context->initializeDrawingContext()) return context; diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp index b29c5efd8d4..986e18d7a87 100644 --- a/intern/ghost/intern/GHOST_WindowWayland.cpp +++ b/intern/ghost/intern/GHOST_WindowWayland.cpp @@ -946,7 +946,12 @@ GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType EGL_OPENGL_API); } - return (context->initializeDrawingContext() == GHOST_kSuccess) ? context : nullptr; + if (context->initializeDrawingContext()) { + return context; + } + + delete context; + return nullptr; } /** \} */ diff --git a/intern/ghost/test/gears/GHOST_Test.cpp b/intern/ghost/test/gears/GHOST_Test.cpp index 1891f1eca77..3c9206b2010 100644 --- a/intern/ghost/test/gears/GHOST_Test.cpp +++ b/intern/ghost/test/gears/GHOST_Test.cpp @@ -407,17 +407,12 @@ Application::Application(GHOST_ISystem *system) stereo(false) { GHOST_GLSettings glSettings = {0}; + glSettings.context_type = GHOST_kDrawingContextTypeOpenGL; fApp = this; // Create the main window - m_mainWindow = system->createWindow("gears - main window", - 10, - 64, - 320, - 200, - GHOST_kWindowStateNormal, - GHOST_kDrawingContextTypeOpenGL, - glSettings); + m_mainWindow = system->createWindow( + "gears - main window", 10, 64, 320, 200, GHOST_kWindowStateNormal, glSettings); if (!m_mainWindow) { std::cout << "could not create main window\n"; @@ -425,14 +420,8 @@ Application::Application(GHOST_ISystem *system) } // Create a secondary window - m_secondaryWindow = system->createWindow("gears - secondary window", - 340, - 64, - 320, - 200, - GHOST_kWindowStateNormal, - GHOST_kDrawingContextTypeOpenGL, - glSettings); + m_secondaryWindow = system->createWindow( + "gears - secondary window", 340, 64, 320, 200, GHOST_kWindowStateNormal, glSettings); if (!m_secondaryWindow) { std::cout << "could not create secondary window\n"; exit(-1); diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt index 1dddd70928a..920b8d5c542 100644 --- a/intern/opensubdiv/CMakeLists.txt +++ b/intern/opensubdiv/CMakeLists.txt @@ -81,12 +81,6 @@ if(WITH_OPENSUBDIV) ) endif() - opensubdiv_define_component(OPENSUBDIV_HAS_OPENMP) - opensubdiv_define_component(OPENSUBDIV_HAS_OPENCL) - opensubdiv_define_component(OPENSUBDIV_HAS_CUDA) - opensubdiv_define_component(OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK) - opensubdiv_define_component(OPENSUBDIV_HAS_GLSL_COMPUTE) - if(WIN32) add_definitions(-DNOMINMAX) add_definitions(-D_USE_MATH_DEFINES) diff --git a/intern/wayland_dynload/extern/wayland_dynload_client.h b/intern/wayland_dynload/extern/wayland_dynload_client.h index 8e9dddd91a3..d80ef5c9f0c 100644 --- a/intern/wayland_dynload/extern/wayland_dynload_client.h +++ b/intern/wayland_dynload/extern/wayland_dynload_client.h @@ -41,6 +41,7 @@ WAYLAND_DYNLOAD_IFACE(wl_seat_interface) WAYLAND_DYNLOAD_IFACE(wl_shm_interface) WAYLAND_DYNLOAD_IFACE(wl_shm_pool_interface) WAYLAND_DYNLOAD_IFACE(wl_surface_interface) +WAYLAND_DYNLOAD_IFACE(wl_touch_interface) #else /* Header guard. */ @@ -62,9 +62,17 @@ if "%SVN_FIX%" == "1" ( ) if "%BUILD_UPDATE%" == "1" ( + REM First see if the SVN libs are there and check them out if they are not. call "%BLENDER_DIR%\build_files\windows\check_libraries.cmd" if errorlevel 1 goto EOF - + REM Then update SVN platform libraries, since updating python while python is + REM running tends to be problematic. The python script that update_sources + REM calls later on may still try to switch branches and run into trouble, + REM but for *most* people this will side step the problem. + call "%BLENDER_DIR%\build_files\windows\svn_update.cmd" + REM Finally call the python script shared between all platforms that updates git + REM and does any other SVN work like update the tests or branch switches + REM if required. call "%BLENDER_DIR%\build_files\windows\update_sources.cmd" goto EOF ) diff --git a/release/scripts/modules/gpu_extras/batch.py b/release/scripts/modules/gpu_extras/batch.py index ba8e3879a8e..6c9ab52c1a3 100644 --- a/release/scripts/modules/gpu_extras/batch.py +++ b/release/scripts/modules/gpu_extras/batch.py @@ -34,13 +34,13 @@ def batch_for_shader(shader, type, content, *, indices=None): return 'I32' def recommended_attr_len(attr_name): - item = content[attr_name][0] attr_len = 1 try: + item = content[attr_name][0] while True: attr_len *= len(item) item = item[0] - except TypeError: + except (TypeError, IndexError): pass return attr_len diff --git a/release/scripts/modules/sys_info.py b/release/scripts/modules/sys_info.py index 7f6d0b1e9bf..5bd38acb19c 100644 --- a/release/scripts/modules/sys_info.py +++ b/release/scripts/modules/sys_info.py @@ -184,6 +184,7 @@ def write_sysinfo(filepath): output.write("vendor:\t\t%r\n" % gpu.platform.vendor_get()) output.write("version:\t%r\n" % gpu.platform.version_get()) output.write("device type:\t%r\n" % gpu.platform.device_type_get()) + output.write("backend type:\t%r\n" % gpu.platform.backend_type_get()) output.write("extensions:\n") glext = sorted(gpu.capabilities.extensions_get()) diff --git a/release/scripts/startup/bl_ui/properties_data_curves.py b/release/scripts/startup/bl_ui/properties_data_curves.py index ff0eabeb7d9..df80bdb4552 100644 --- a/release/scripts/startup/bl_ui/properties_data_curves.py +++ b/release/scripts/startup/bl_ui/properties_data_curves.py @@ -44,7 +44,13 @@ class DATA_PT_curves_surface(DataButtonsPanel, Panel): layout.use_property_split = True layout.prop(ob.data, "surface") - layout.prop(ob.data, "surface_uv_map", text="UV Map") + has_surface = ob.data.surface is not None + if has_surface: + layout.prop_search(ob.data, "surface_uv_map", ob.data.surface.data, "uv_layers", text="UV Map") + else: + row = layout.row() + row.prop(ob.data, "surface_uv_map", text="UV Map") + row.enabled = has_surface class CURVES_MT_add_attribute(Menu): diff --git a/release/scripts/startup/bl_ui/properties_output.py b/release/scripts/startup/bl_ui/properties_output.py index ca0e698500e..61384f25afb 100644 --- a/release/scripts/startup/bl_ui/properties_output.py +++ b/release/scripts/startup/bl_ui/properties_output.py @@ -380,7 +380,14 @@ class RENDER_PT_encoding_video(RenderOutputButtonsPanel, Panel): layout = self.layout ffmpeg = context.scene.render.ffmpeg - needs_codec = ffmpeg.format in {'AVI', 'QUICKTIME', 'MKV', 'OGG', 'MPEG4', 'WEBM'} + needs_codec = ffmpeg.format in { + 'AVI', + 'QUICKTIME', + 'MKV', + 'OGG', + 'MPEG4', + 'WEBM' + } if needs_codec: layout.prop(ffmpeg, "codec") @@ -391,7 +398,12 @@ class RENDER_PT_encoding_video(RenderOutputButtonsPanel, Panel): layout.prop(ffmpeg, "use_lossless_output") # Output quality - use_crf = needs_codec and ffmpeg.codec in {'H264', 'MPEG4', 'WEBM'} + use_crf = needs_codec and ffmpeg.codec in { + 'H264', + 'MPEG4', + 'WEBM', + 'AV1' + } if use_crf: layout.prop(ffmpeg, "constant_rate_factor") diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 92beba2c032..b16983c1492 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -3030,6 +3030,7 @@ class VIEW3D_MT_brush_paint_modes(Menu): layout.prop(brush, "use_paint_vertex", text="Vertex Paint") layout.prop(brush, "use_paint_weight", text="Weight Paint") layout.prop(brush, "use_paint_image", text="Texture Paint") + layout.prop(brush, "use_paint_sculpt_curves", text="Sculpt Curves") class VIEW3D_MT_paint_vertex(Menu): diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index dfe92f64341..0157f01a0e5 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -53,6 +53,8 @@ class VIEW3D_MT_brush_context_menu(Menu): elif context.sculpt_object: layout.prop_menu_enum(brush, "sculpt_tool") layout.operator("brush.reset") + elif context.tool_settings.curves_sculpt: + layout.prop_menu_enum(brush, "curves_sculpt_tool") class VIEW3D_MT_brush_gpencil_context_menu(Menu): @@ -82,22 +84,6 @@ class VIEW3D_MT_brush_gpencil_context_menu(Menu): layout.operator("gpencil.brush_reset_all") -class VIEW3D_MT_brush_context_menu_paint_modes(Menu): - bl_label = "Enabled Modes" - - def draw(self, context): - layout = self.layout - - settings = UnifiedPaintPanel.paint_settings(context) - brush = settings.brush - - layout.prop(brush, "use_paint_sculpt", text="Sculpt") - layout.prop(brush, "use_paint_uv_sculpt", text="UV Sculpt") - layout.prop(brush, "use_paint_vertex", text="Vertex Paint") - layout.prop(brush, "use_paint_weight", text="Weight Paint") - layout.prop(brush, "use_paint_image", text="Texture Paint") - - class View3DPanel: bl_space_type = 'VIEW_3D' bl_region_type = 'UI' @@ -2448,7 +2434,6 @@ class VIEW3D_PT_gpencil_brush_presets(Panel, PresetPanel): classes = ( VIEW3D_MT_brush_context_menu, VIEW3D_MT_brush_gpencil_context_menu, - VIEW3D_MT_brush_context_menu_paint_modes, VIEW3D_PT_tools_object_options, VIEW3D_PT_tools_object_options_transform, VIEW3D_PT_tools_meshedit_options, diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh index 7b13b8a2b09..a4f9d73c31e 100644 --- a/source/blender/blenkernel/BKE_attribute.hh +++ b/source/blender/blenkernel/BKE_attribute.hh @@ -793,7 +793,9 @@ class CustomDataAttributes { ~CustomDataAttributes(); CustomDataAttributes(const CustomDataAttributes &other); CustomDataAttributes(CustomDataAttributes &&other); + CustomDataAttributes &operator=(const CustomDataAttributes &other); + CustomDataAttributes &operator=(CustomDataAttributes &&other); void reallocate(int size); diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 96df8f7a443..806fff2099e 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -25,7 +25,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 4 +#define BLENDER_FILE_SUBVERSION 5 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 38bf30a773c..ed75a69b81f 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -130,7 +130,7 @@ float BKE_brush_sample_masktex(const struct Scene *scene, * Get the mask texture for this given object mode. * * This is preferred above using mtex/mask_mtex attributes directly as due to legacy these - * attributes got switched in sculpt mode. + * attributes got switched in sculpt mode. */ const struct MTex *BKE_brush_mask_texture_get(const struct Brush *brush, const eObjectMode object_mode); diff --git a/source/blender/blenkernel/BKE_instances.hh b/source/blender/blenkernel/BKE_instances.hh index 6502fefec88..f17ebba0dfa 100644 --- a/source/blender/blenkernel/BKE_instances.hh +++ b/source/blender/blenkernel/BKE_instances.hh @@ -5,7 +5,7 @@ /** \file * \ingroup bke * - * #Instances is a container for geometry instances. It fullfills some key requirements: + * #Instances is a container for geometry instances. It fulfills some key requirements: * - Support nested instances. * - Support instance attributes. * - Support referencing different kinds of instances (objects, collections, geometry sets). diff --git a/source/blender/blenkernel/BKE_writeffmpeg.h b/source/blender/blenkernel/BKE_writeffmpeg.h index 736f7548bb4..cfe246eb470 100644 --- a/source/blender/blenkernel/BKE_writeffmpeg.h +++ b/source/blender/blenkernel/BKE_writeffmpeg.h @@ -27,6 +27,7 @@ enum { FFMPEG_OGG = 10, FFMPEG_INVALID = 11, FFMPEG_WEBM = 12, + FFMPEG_AV1 = 13, }; enum { @@ -38,6 +39,7 @@ enum { FFMPEG_PRESET_H264 = 5, FFMPEG_PRESET_THEORA = 6, FFMPEG_PRESET_XVID = 7, + FFMPEG_PRESET_AV1 = 8, }; struct RenderData; diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index b86353bdb74..544427cfdd3 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -642,15 +642,26 @@ CustomDataAttributes::CustomDataAttributes(CustomDataAttributes &&other) size_ = other.size_; data = other.data; CustomData_reset(&other.data); + other.size_ = 0; } CustomDataAttributes &CustomDataAttributes::operator=(const CustomDataAttributes &other) { - if (this != &other) { - CustomData_copy(&other.data, &data, CD_MASK_ALL, CD_DUPLICATE, other.size_); - size_ = other.size_; + if (this == &other) { + return *this; } + this->~CustomDataAttributes(); + new (this) CustomDataAttributes(other); + return *this; +} +CustomDataAttributes &CustomDataAttributes::operator=(CustomDataAttributes &&other) +{ + if (this == &other) { + return *this; + } + this->~CustomDataAttributes(); + new (this) CustomDataAttributes(std::move(other)); return *this; } diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c index 394469e19a4..4dd225c09ec 100644 --- a/source/blender/blenkernel/intern/blendfile_link_append.c +++ b/source/blender/blenkernel/intern/blendfile_link_append.c @@ -1494,6 +1494,7 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context, * code is wrong, we need to redo it here after adding them back to main. */ BKE_main_id_refcount_recompute(bmain, false); + BKE_layer_collection_resync_forbid(); /* Note that in reload case, we also want to replace indirect usages. */ const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE); @@ -1523,6 +1524,8 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context, id_us_plus_no_lib(&old_key->id); } } + BKE_layer_collection_resync_allow(); + BKE_main_collection_sync_remap(bmain); BKE_main_unlock(bmain); @@ -1614,6 +1617,9 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context, (id->tag & LIB_TAG_PRE_EXISTING) == 0) { continue; } + if ((id->override_library->reference->tag & LIB_TAG_MISSING) == 0) { + id->tag &= ~LIB_TAG_MISSING; + } if ((id->override_library->reference->tag & LIB_TAG_PRE_EXISTING) == 0) { BKE_lib_override_library_update(bmain, id); } diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc index 01be22a57b0..72e53023d6d 100644 --- a/source/blender/blenkernel/intern/curves.cc +++ b/source/blender/blenkernel/intern/curves.cc @@ -287,7 +287,10 @@ static void curves_evaluate_modifiers(struct Depsgraph *depsgraph, { /* Modifier evaluation modes. */ const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); - const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime; + int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime; + if (BKE_object_is_in_editmode(object)) { + required_mode = (ModifierMode)(int(required_mode) | eModifierMode_Editmode); + } ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE; const ModifierEvalContext mectx = {depsgraph, object, apply_flag}; diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index 29f8d62545f..7c338480c71 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -9,6 +9,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_array_utils.hh" #include "BLI_bounds.hh" #include "BLI_index_mask_ops.hh" #include "BLI_length_parameterize.hh" @@ -1111,21 +1112,11 @@ static void copy_between_buffers(const CPPType &type, src_range.size()); } -template<typename T> -static void copy_with_map(const Span<T> src, const Span<int> map, MutableSpan<T> dst) -{ - threading::parallel_for(map.index_range(), 1024, [&](const IndexRange range) { - for (const int i : range) { - dst[i] = src[map[i]]; - } - }); -} - static void copy_with_map(const GSpan src, const Span<int> map, GMutableSpan dst) { attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { using T = decltype(dummy); - copy_with_map(src.typed<T>(), map, dst.typed<T>()); + array_utils::gather(src.typed<T>(), map, dst.typed<T>()); }); } @@ -1233,6 +1224,10 @@ static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves, attribute.dst.finish(); } + if (new_curves.curves_num() != curves.curves_num()) { + new_curves.remove_attributes_based_on_types(); + } + return new_curves; } @@ -1338,6 +1333,8 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves, attribute.dst.finish(); } + new_curves.remove_attributes_based_on_types(); + return new_curves; } diff --git a/source/blender/blenkernel/intern/image_format.cc b/source/blender/blenkernel/intern/image_format.cc index 8d1aeac76fb..5b861eff166 100644 --- a/source/blender/blenkernel/intern/image_format.cc +++ b/source/blender/blenkernel/intern/image_format.cc @@ -201,6 +201,7 @@ bool BKE_imtype_is_movie(const char imtype) case R_IMF_IMTYPE_H264: case R_IMF_IMTYPE_THEORA: case R_IMF_IMTYPE_XVID: + case R_IMF_IMTYPE_AV1: return true; } return false; @@ -433,7 +434,8 @@ static bool do_add_image_extension(char *string, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, - R_IMF_IMTYPE_XVID)) { + R_IMF_IMTYPE_XVID, + R_IMF_IMTYPE_AV1)) { if (!BLI_path_extension_check(string, extension_test = ".png")) { extension = extension_test; } @@ -627,7 +629,8 @@ void BKE_image_format_to_imbuf(ImBuf *ibuf, const ImageFormatData *imf) R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, - R_IMF_IMTYPE_XVID)) { + R_IMF_IMTYPE_XVID, + R_IMF_IMTYPE_AV1)) { ibuf->ftype = IMB_FTYPE_PNG; if (imtype == R_IMF_IMTYPE_PNG) { diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc index 4e47e71fb2b..003211e6288 100644 --- a/source/blender/blenkernel/intern/image_save.cc +++ b/source/blender/blenkernel/intern/image_save.cc @@ -968,6 +968,7 @@ bool BKE_image_render_write(ReportList *reports, /* optional preview images for exr */ if (ok && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { image_format.imtype = R_IMF_IMTYPE_JPEG90; + image_format.depth = R_IMF_CHAN_DEPTH_8; if (BLI_path_extension_check(filepath, ".exr")) { filepath[strlen(filepath) - 4] = 0; @@ -1025,6 +1026,7 @@ bool BKE_image_render_write(ReportList *reports, /* optional preview images for exr */ if (ok && is_exr_rr && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { image_format.imtype = R_IMF_IMTYPE_JPEG90; + image_format.depth = R_IMF_CHAN_DEPTH_8; if (BLI_path_extension_check(filepath, ".exr")) { filepath[strlen(filepath) - 4] = 0; diff --git a/source/blender/blenkernel/intern/instances.cc b/source/blender/blenkernel/intern/instances.cc index dd759453630..4675562e927 100644 --- a/source/blender/blenkernel/intern/instances.cc +++ b/source/blender/blenkernel/intern/instances.cc @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BLI_array_utils.hh" #include "BLI_cpp_type_make.hh" #include "BLI_rand.hh" #include "BLI_task.hh" @@ -107,18 +108,6 @@ blender::Span<InstanceReference> Instances::references() const return references_; } -template<typename T> -static void copy_data_based_on_mask(Span<T> src, MutableSpan<T> dst, IndexMask mask) -{ - BLI_assert(src.data() != dst.data()); - using namespace blender; - threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) { - for (const int i : range) { - dst[i] = src[mask[i]]; - } - }); -} - void Instances::remove(const IndexMask mask) { using namespace blender; @@ -129,11 +118,14 @@ void Instances::remove(const IndexMask mask) return; } + const Span<int> old_handles = this->reference_handles(); Vector<int> new_handles(mask.size()); - copy_data_based_on_mask<int>(this->reference_handles(), new_handles, mask); + array_utils::gather(old_handles, mask.indices(), new_handles.as_mutable_span()); reference_handles_ = std::move(new_handles); + + const Span<float4x4> old_tansforms = this->transforms(); Vector<float4x4> new_transforms(mask.size()); - copy_data_based_on_mask<float4x4>(this->transforms(), new_transforms, mask); + array_utils::gather(old_tansforms, mask.indices(), new_transforms.as_mutable_span()); transforms_ = std::move(new_transforms); const bke::CustomDataAttributes &src_attributes = attributes_; @@ -150,11 +142,8 @@ void Instances::remove(const IndexMask mask) GSpan src = *src_attributes.get_for_read(id); dst_attributes.create(id, meta_data.data_type); GMutableSpan dst = *dst_attributes.get_for_write(id); + array_utils::gather(src, mask.indices(), dst); - attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { - using T = decltype(dummy); - copy_data_based_on_mask<T>(src.typed<T>(), dst.typed<T>(), mask); - }); return true; }, ATTR_DOMAIN_INSTANCE); @@ -266,7 +255,7 @@ bool Instances::owns_direct_data() const void Instances::ensure_owns_direct_data() { for (const InstanceReference &const_reference : references_) { - /* Const cast is fine because we are not changing anything that would change the hash of the + /* `const` cast is fine because we are not changing anything that would change the hash of the * reference. */ InstanceReference &reference = const_cast<InstanceReference &>(const_reference); reference.ensure_owns_direct_data(); diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c index f4f5ca7a1d7..1a80376f482 100644 --- a/source/blender/blenkernel/intern/lib_id_delete.c +++ b/source/blender/blenkernel/intern/lib_id_delete.c @@ -16,6 +16,7 @@ #include "BLI_utildefines.h" +#include "BLI_linklist.h" #include "BLI_listbase.h" #include "BKE_anim_data.h" @@ -23,10 +24,10 @@ #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_key.h" +#include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_lib_override.h" #include "BKE_lib_remap.h" -#include "BKE_library.h" #include "BKE_main.h" #include "BKE_main_namemap.h" @@ -202,7 +203,6 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) { const int tag = LIB_TAG_DOIT; ListBase *lbarray[INDEX_ID_MAX]; - Link dummy_link = {0}; int base_count, i; /* Used by batch tagged deletion, when we call BKE_id_free then, id is no more in Main database, @@ -217,6 +217,9 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) BKE_main_lock(bmain); if (do_tagged_deletion) { + struct IDRemapper *id_remapper = BKE_id_remapper_create(); + BKE_layer_collection_resync_forbid(); + /* Main idea of batch deletion is to remove all IDs to be deleted from Main database. * This means that we won't have to loop over all deleted IDs to remove usages * of other deleted IDs. @@ -227,7 +230,6 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) bool keep_looping = true; while (keep_looping) { ID *id, *id_next; - ID *last_remapped_id = tagged_deleted_ids.last; keep_looping = false; /* First tag and remove from Main all datablocks directly from target lib. @@ -243,6 +245,7 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) BLI_remlink(lb, id); BKE_main_namemap_remove_name(bmain, id, id->name + 2); BLI_addtail(&tagged_deleted_ids, id); + BKE_id_remapper_add(id_remapper, id, NULL); /* Do not tag as no_main now, we want to unlink it first (lower-level ID management * code has some specific handling of 'no main' IDs that would be a problem in that * case). */ @@ -251,33 +254,38 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) } } } - if (last_remapped_id == NULL) { - dummy_link.next = tagged_deleted_ids.first; - last_remapped_id = (ID *)(&dummy_link); - } - for (id = last_remapped_id->next; id; id = id->next) { - /* Will tag 'never NULL' users of this ID too. - * - * NOTE: #BKE_libblock_unlink() cannot be used here, since it would ignore indirect - * 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_locked(bmain, - id, - NULL, - (ID_REMAP_FLAG_NEVER_NULL_USAGE | - ID_REMAP_FORCE_NEVER_NULL_USAGE | - ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS)); - /* Since we removed ID from Main, - * we also need to unlink its own other IDs usages ourself. */ - BKE_libblock_relink_ex( - bmain, - id, - NULL, - NULL, - (ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS | ID_REMAP_SKIP_USER_CLEAR)); - } + + /* Will tag 'never NULL' users of this ID too. + * + * NOTE: #BKE_libblock_unlink() cannot be used here, since it would ignore indirect + * 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_id_remapper_clear(id_remapper); + } + + /* Since we removed IDs from Main, their own other IDs usages need to be removed 'manually'. */ + LinkNode *cleanup_ids = NULL; + for (ID *id = tagged_deleted_ids.first; id; id = id->next) { + BLI_linklist_prepend(&cleanup_ids, id); } + BKE_libblock_relink_multiple(bmain, + cleanup_ids, + ID_REMAP_TYPE_CLEANUP, + id_remapper, + ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS | + ID_REMAP_SKIP_USER_CLEAR); + + BKE_id_remapper_free(id_remapper); + BLI_linklist_free(cleanup_ids, NULL); + + BKE_layer_collection_resync_allow(); + BKE_main_collection_sync_remap(bmain); /* Now we can safely mark that ID as not being in Main database anymore. */ /* NOTE: This needs to be done in a separate loop than above, otherwise some user-counts of @@ -285,6 +293,10 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) * is never affected). */ for (ID *id = tagged_deleted_ids.first; id; id = id->next) { id->tag |= LIB_TAG_NO_MAIN; + /* Usercount needs to be reset artificially, since some usages may not be cleared in batch + * deletion (typically, if one deleted ID uses another deleted ID, this may not be cleared by + * remapping code, depending on order in which these are handled). */ + id->us = ID_FAKE_USERS(id); } } else { diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index 027423f5774..784d35a8d65 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -1313,6 +1313,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob) CustomData_duplicate_referenced_layers(&mesh_src->pdata, mesh_src->totpoly); CustomData_duplicate_referenced_layers(&mesh_src->ldata, mesh_src->totloop); + const bool verts_num_changed = mesh_dst->totvert != mesh_src->totvert; mesh_dst->totvert = mesh_src->totvert; mesh_dst->totedge = mesh_src->totedge; mesh_dst->totpoly = mesh_src->totpoly; @@ -1339,11 +1340,10 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob) const int uid_active = ob ? find_object_active_key_uid(*key_dst, *ob) : -1; move_shapekey_layers_to_keyblocks(*mesh_dst, mesh_src->vdata, *key_dst, uid_active); } - else if (mesh_src->totvert != mesh_dst->totvert) { - CLOG_ERROR(&LOG, "Mesh in Main '%s' lost shape keys", mesh_src->id.name); - if (mesh_src->key) { - id_us_min(&mesh_src->key->id); - } + else if (verts_num_changed) { + CLOG_WARN(&LOG, "Shape key data lost when replacing mesh '%s' in Main", mesh_src->id.name); + id_us_min(&mesh_dst->key->id); + mesh_dst->key = nullptr; } } diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index ba63cdff917..24663d6db05 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -1918,7 +1918,7 @@ bool BKE_nla_action_stash(AnimData *adt, const bool is_liboverride) * NOTE: this must be done *after* adding the strip to the track, or else * the strip locking will prevent the strip from getting added */ - nlt->flag = (NLATRACK_MUTED | NLATRACK_PROTECTED); + nlt->flag |= (NLATRACK_MUTED | NLATRACK_PROTECTED); strip->flag &= ~(NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE); /* also mark the strip for auto syncing the length, so that the strips accurately diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 2d949fb5c65..d98f5e85028 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -1902,6 +1902,7 @@ bool BKE_object_is_in_editmode(const Object *ob) /* Grease Pencil object has no edit mode data. */ return GPENCIL_EDIT_MODE((bGPdata *)ob->data); case OB_CURVES: + /* Curves object has no edit mode data. */ return ob->mode == OB_MODE_EDIT; default: return false; diff --git a/source/blender/blenkernel/intern/object_update.cc b/source/blender/blenkernel/intern/object_update.cc index ceef6404bf0..e53090bcffe 100644 --- a/source/blender/blenkernel/intern/object_update.cc +++ b/source/blender/blenkernel/intern/object_update.cc @@ -292,6 +292,8 @@ void BKE_object_batch_cache_dirty_tag(Object *ob) BKE_lattice_batch_cache_dirty_tag((struct Lattice *)ob->data, BKE_LATTICE_BATCH_DIRTY_ALL); break; case OB_CURVES_LEGACY: + case OB_SURF: + case OB_FONT: BKE_curve_batch_cache_dirty_tag((struct Curve *)ob->data, BKE_CURVE_BATCH_DIRTY_ALL); break; case OB_MBALL: { diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index 13243925b28..408cd117e32 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -1043,6 +1043,8 @@ eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode) return OB_MODE_TEXTURE_PAINT; case PAINT_MODE_SCULPT_UV: return OB_MODE_EDIT; + case PAINT_MODE_SCULPT_CURVES: + return OB_MODE_SCULPT_CURVES; case PAINT_MODE_INVALID: default: return OB_MODE_OBJECT; diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc index 7c54b4d3f2f..e81657f9ef0 100644 --- a/source/blender/blenkernel/intern/volume.cc +++ b/source/blender/blenkernel/intern/volume.cc @@ -445,7 +445,7 @@ struct VolumeGrid { * may actually be loaded by another user while this is false. But only after * calling load() and is_loaded changes to true is it safe to access. * - * Const write access to this must be protected by `entry->mutex`. + * `const` write access to this must be protected by `entry->mutex`. */ mutable bool is_loaded; }; @@ -480,7 +480,7 @@ struct VolumeGridVector : public std::list<VolumeGrid> { metadata.reset(); } - /* Mutex for file loading of grids list. Const write access to the fields after this must be + /* Mutex for file loading of grids list. `const` write access to the fields after this must be * protected by locking with this mutex. */ mutable std::mutex mutex; /* Absolute file path that grids have been loaded from. */ diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c index dbdf8cc395d..de2e196c163 100644 --- a/source/blender/blenkernel/intern/writeavi.c +++ b/source/blender/blenkernel/intern/writeavi.c @@ -122,7 +122,8 @@ bMovieHandle *BKE_movie_handle_get(const char imtype) R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_XVID, - R_IMF_IMTYPE_THEORA)) { + R_IMF_IMTYPE_THEORA, + R_IMF_IMTYPE_AV1)) { mh.start_movie = BKE_ffmpeg_start; mh.append_movie = BKE_ffmpeg_append; mh.end_movie = BKE_ffmpeg_end; diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 99df07b6105..0d3a790ba00 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -299,6 +299,10 @@ static const char **get_file_extensions(int format) static const char *rv[] = {".webm", NULL}; return rv; } + case FFMPEG_AV1: { + static const char *rv[] = {".mp4", ".mkv", NULL}; + return rv; + } default: return NULL; } @@ -455,6 +459,204 @@ static AVRational calc_time_base(uint den, double num, int codec_id) return time_base; } +static const AVCodec *get_av1_encoder( + FFMpegContext *context, RenderData *rd, AVDictionary **opts, int rectx, int recty) +{ + /* There are three possible encoders for AV1: libaom-av1, librav1e, and libsvtav1. librav1e tends + * to give the best compression quality while libsvtav1 tends to be the fastest encoder. One of + * each will be picked based on the preset setting, and if a particular encoder is not available, + * then use the default returned by FFMpeg. */ + const AVCodec *codec = NULL; + switch (context->ffmpeg_preset) { + case FFM_PRESET_BEST: + /* Default to libaom-av1 for BEST preset due to it performing better than rav1e in terms of + * video quality (VMAF scores). Fallback to rav1e if libaom-av1 isn't available. */ + codec = avcodec_find_encoder_by_name("libaom-av1"); + if (!codec) { + codec = avcodec_find_encoder_by_name("librav1e"); + } + break; + case FFM_PRESET_REALTIME: + codec = avcodec_find_encoder_by_name("libsvtav1"); + break; + case FFM_PRESET_GOOD: + default: + codec = avcodec_find_encoder_by_name("libaom-av1"); + break; + } + + /* Use the default AV1 encoder if the specified encoder wasn't found. */ + if (!codec) { + codec = avcodec_find_encoder(AV_CODEC_ID_AV1); + } + + /* Apply AV1 encoder specific settings. */ + if (codec) { + if (strcmp(codec->name, "librav1e") == 0) { + /* Set "tiles" to 8 to enable multi-threaded encoding. */ + if (rd->threads > 8) { + ffmpeg_dict_set_int(opts, "tiles", rd->threads); + } + else { + ffmpeg_dict_set_int(opts, "tiles", 8); + } + + /* Use a reasonable speed setting based on preset. Speed ranges from 0-10. + * Must check context->ffmpeg_preset again in case this encoder was selected due to the + * absence of another. */ + switch (context->ffmpeg_preset) { + case FFM_PRESET_BEST: + ffmpeg_dict_set_int(opts, "speed", 4); + break; + case FFM_PRESET_REALTIME: + ffmpeg_dict_set_int(opts, "speed", 10); + break; + case FFM_PRESET_GOOD: + default: + ffmpeg_dict_set_int(opts, "speed", 6); + break; + } + if (context->ffmpeg_crf >= 0) { + /* librav1e does not use -crf, but uses -qp in the range of 0-255. Calculates the roughly + * equivalent float, and truncates it to an integer. */ + unsigned int qp_value = ((float)context->ffmpeg_crf) * 255.0F / 51.0F; + if (qp_value > 255) { + qp_value = 255; + } + ffmpeg_dict_set_int(opts, "qp", qp_value); + } + /* Set gop_size as rav1e's "--keyint". */ + char buffer[64]; + BLI_snprintf(buffer, sizeof(buffer), "keyint=%d", context->ffmpeg_gop_size); + av_dict_set(opts, "rav1e-params", buffer, 0); + } + else if (strcmp(codec->name, "libsvtav1") == 0) { + /* Set preset value based on ffmpeg_preset. + * Must check context->ffmpeg_preset again in case this encoder was selected due to the + * absence of another. */ + switch (context->ffmpeg_preset) { + case FFM_PRESET_REALTIME: + ffmpeg_dict_set_int(opts, "preset", 8); + break; + case FFM_PRESET_BEST: + ffmpeg_dict_set_int(opts, "preset", 3); + break; + case FFM_PRESET_GOOD: + default: + ffmpeg_dict_set_int(opts, "preset", 5); + break; + } + if (context->ffmpeg_crf >= 0) { + /* libsvtav1 does not support crf until FFmpeg builds since 2022-02-24, use qp as fallback. + */ + ffmpeg_dict_set_int(opts, "qp", context->ffmpeg_crf); + } + } + else if (strcmp(codec->name, "libaom-av1") == 0) { + /* Speed up libaom-av1 encoding by enabling multithreading and setting tiles. */ + ffmpeg_dict_set_int(opts, "row-mt", 1); + const char *tiles_string = NULL; + bool tiles_string_is_dynamic = false; + if (rd->threads > 0) { + /* See if threads is a square. */ + int threads_sqrt = sqrtf(rd->threads); + if (threads_sqrt < 4) { + /* Ensure a default minimum. */ + threads_sqrt = 4; + } + if (is_power_of_2_i(threads_sqrt) && threads_sqrt * threads_sqrt == rd->threads) { + /* Is a square num, therefore just do "sqrt x sqrt" for tiles parameter. */ + int digits = 0; + for (int t_sqrt_copy = threads_sqrt; t_sqrt_copy > 0; t_sqrt_copy /= 10) { + ++digits; + } + /* A char array need only an alignment of 1. */ + char *tiles_string_mut = (char *)calloc(digits * 2 + 2, 1); + BLI_snprintf(tiles_string_mut, digits * 2 + 2, "%dx%d", threads_sqrt, threads_sqrt); + tiles_string_is_dynamic = true; + tiles_string = tiles_string_mut; + } + else { + /* Is not a square num, set greater side based on longer side, or use a square if both + sides are equal. */ + int sqrt_p2 = power_of_2_min_i(threads_sqrt); + if (sqrt_p2 < 2) { + /* Ensure a default minimum. */ + sqrt_p2 = 2; + } + int sqrt_p2_next = power_of_2_min_i((int)rd->threads / sqrt_p2); + if (sqrt_p2_next < 1) { + sqrt_p2_next = 1; + } + if (sqrt_p2 > sqrt_p2_next) { + /* Ensure sqrt_p2_next is greater or equal to sqrt_p2. */ + int temp = sqrt_p2; + sqrt_p2 = sqrt_p2_next; + sqrt_p2_next = temp; + } + int combined_digits = 0; + for (int sqrt_p2_copy = sqrt_p2; sqrt_p2_copy > 0; sqrt_p2_copy /= 10) { + ++combined_digits; + } + for (int sqrt_p2_copy = sqrt_p2_next; sqrt_p2_copy > 0; sqrt_p2_copy /= 10) { + ++combined_digits; + } + /* A char array need only an alignment of 1. */ + char *tiles_string_mut = (char *)calloc(combined_digits + 2, 1); + if (rectx > recty) { + BLI_snprintf(tiles_string_mut, combined_digits + 2, "%dx%d", sqrt_p2_next, sqrt_p2); + } + else if (rectx < recty) { + BLI_snprintf(tiles_string_mut, combined_digits + 2, "%dx%d", sqrt_p2, sqrt_p2_next); + } + else { + BLI_snprintf(tiles_string_mut, combined_digits + 2, "%dx%d", sqrt_p2, sqrt_p2); + } + tiles_string_is_dynamic = true; + tiles_string = tiles_string_mut; + } + } + else { + /* Thread count unknown, default to 8. */ + if (rectx > recty) { + tiles_string = "4x2"; + } + else if (rectx < recty) { + tiles_string = "2x4"; + } + else { + tiles_string = "2x2"; + } + } + av_dict_set(opts, "tiles", tiles_string, 0); + if (tiles_string_is_dynamic) { + free((void *)tiles_string); + } + /* libaom-av1 uses "cpu-used" instead of "preset" for defining compression quality. + * This value is in a range from 0-8. 0 and 8 are extremes, but we will allow 8. + * Must check context->ffmpeg_preset again in case this encoder was selected due to the + * absence of another. */ + switch (context->ffmpeg_preset) { + case FFM_PRESET_REALTIME: + ffmpeg_dict_set_int(opts, "cpu-used", 8); + break; + case FFM_PRESET_BEST: + ffmpeg_dict_set_int(opts, "cpu-used", 4); + break; + case FFM_PRESET_GOOD: + default: + ffmpeg_dict_set_int(opts, "cpu-used", 6); + break; + } + + /* CRF related settings is similar to H264 for libaom-av1, so we will rely on those settings + * applied later. */ + } + } + + return codec; +} + /* prepare a video stream for the output file */ static AVStream *alloc_video_stream(FFMpegContext *context, @@ -480,7 +682,14 @@ static AVStream *alloc_video_stream(FFMpegContext *context, /* Set up the codec context */ - codec = avcodec_find_encoder(codec_id); + if (codec_id == AV_CODEC_ID_AV1) { + /* Use get_av1_encoder() to get the ideal (hopefully) encoder for AV1 based + * on given parameters, and also set up opts. */ + codec = get_av1_encoder(context, rd, &opts, rectx, recty); + } + else { + codec = avcodec_find_encoder(codec_id); + } if (!codec) { fprintf(stderr, "Couldn't find valid video codec\n"); context->video_codec = NULL; @@ -568,7 +777,9 @@ static AVStream *alloc_video_stream(FFMpegContext *context, default: printf("Unknown preset number %i, ignoring.\n", context->ffmpeg_preset); } - if (preset_name != NULL) { + /* "codec_id != AV_CODEC_ID_AV1" is required due to "preset" already being set by an AV1 codec. + */ + if (preset_name != NULL && codec_id != AV_CODEC_ID_AV1) { av_dict_set(&opts, "preset", preset_name, 0); } if (deadline_name != NULL) { @@ -951,6 +1162,9 @@ static int start_ffmpeg_impl(FFMpegContext *context, case FFMPEG_FLV: video_codec = AV_CODEC_ID_FLV1; break; + case FFMPEG_AV1: + video_codec = AV_CODEC_ID_AV1; + break; default: /* These containers are not restricted to any specific codec types. * Currently we expect these to be .avi, .mov, .mkv, and .mp4. @@ -1482,6 +1696,18 @@ void BKE_ffmpeg_preset_set(RenderData *rd, int preset) rd->ffcodecdata.mux_packet_size = 2048; rd->ffcodecdata.mux_rate = 10080000; break; + case FFMPEG_PRESET_AV1: + rd->ffcodecdata.type = FFMPEG_AV1; + rd->ffcodecdata.codec = AV_CODEC_ID_AV1; + rd->ffcodecdata.video_bitrate = 6000; + rd->ffcodecdata.gop_size = is_ntsc ? 18 : 15; + rd->ffcodecdata.rc_max_rate = 9000; + rd->ffcodecdata.rc_min_rate = 0; + rd->ffcodecdata.rc_buffer_size = 224 * 8; + rd->ffcodecdata.mux_packet_size = 2048; + rd->ffcodecdata.mux_rate = 10080000; + + break; } } @@ -1521,6 +1747,12 @@ void BKE_ffmpeg_image_type_verify(RenderData *rd, const ImageFormatData *imf) audio = 1; } } + else if (imf->imtype == R_IMF_IMTYPE_AV1) { + if (rd->ffcodecdata.codec != AV_CODEC_ID_AV1) { + BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_AV1); + audio = 1; + } + } if (audio && rd->ffcodecdata.audio_codec < 0) { rd->ffcodecdata.audio_codec = AV_CODEC_ID_NONE; diff --git a/source/blender/blenlib/BLI_array_utils.hh b/source/blender/blenlib/BLI_array_utils.hh index 95b3bde10f4..264ac00e034 100644 --- a/source/blender/blenlib/BLI_array_utils.hh +++ b/source/blender/blenlib/BLI_array_utils.hh @@ -42,6 +42,11 @@ void gather(const GVArray &src, IndexMask indices, GMutableSpan dst, int64_t gra /** * Fill the destination span by gathering indexed values from the `src` array. */ +void gather(GSpan src, IndexMask indices, GMutableSpan dst, int64_t grain_size = 4096); + +/** + * Fill the destination span by gathering indexed values from the `src` array. + */ template<typename T> inline void gather(const VArray<T> &src, const IndexMask indices, diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h index 15926e8f2d2..17abcf52ecc 100644 --- a/source/blender/blenlib/BLI_string.h +++ b/source/blender/blenlib/BLI_string.h @@ -309,6 +309,28 @@ void BLI_str_format_byte_unit(char dst[15], long long int bytes, bool base_10) A */ void BLI_str_format_decimal_unit(char dst[7], int number_to_format) ATTR_NONNULL(); /** + * Format a count to up to 3 places (plus minus sign, plus '\0' terminator) string using long + * number names abbreviations. Used to produce a compact representation of large numbers as + * integers. + * + * It shows a lower bound instead of rounding the number. + * + * 1 -> 1 + * 15 -> 15 + * 155 -> 155 + * 1555 -> 1K + * 15555 -> 15K + * 155555 -> .1M + * 1555555 -> 1M + * 15555555 -> 15M + * 155555555 -> .1B + * 1000000000 -> 1B + * ... + * + * Length of 5 is the maximum of the resulting string, for example, `-15K\0`. + */ +void BLI_str_format_integer_unit(char dst[5], int number_to_format) ATTR_NONNULL(); +/** * Compare two strings without regard to case. * * \retval True if the strings are equal, false otherwise. diff --git a/source/blender/blenlib/intern/array_utils.cc b/source/blender/blenlib/intern/array_utils.cc index a837d6aceec..2a231228dcb 100644 --- a/source/blender/blenlib/intern/array_utils.cc +++ b/source/blender/blenlib/intern/array_utils.cc @@ -28,4 +28,9 @@ void gather(const GVArray &src, }); } +void gather(const GSpan src, const IndexMask indices, GMutableSpan dst, const int64_t grain_size) +{ + gather(GVArray::ForSpan(src), indices, dst, grain_size); +} + } // namespace blender::array_utils diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index 89d31c5e93f..755d2dbd55d 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -1176,4 +1176,34 @@ void BLI_str_format_decimal_unit(char dst[7], int number_to_format) BLI_snprintf(dst, dst_len, "%.*f%s", decimals, number_to_format_converted, units[order]); } +void BLI_str_format_integer_unit(char dst[5], const int number_to_format) +{ + float number_to_format_converted = number_to_format; + int order = 0; + const float base = 1000; + const char *units[] = {"", "K", "M", "B"}; + const int units_num = ARRAY_SIZE(units); + + while ((fabsf(number_to_format_converted) >= base) && ((order + 1) < units_num)) { + number_to_format_converted /= base; + order++; + } + + const bool add_dot = (abs(number_to_format) > 99999) && fabsf(number_to_format_converted) > 99; + + if (add_dot) { + number_to_format_converted /= 100; + order++; + } + + const size_t dst_len = 5; + BLI_snprintf(dst, + dst_len, + "%s%s%d%s", + number_to_format < 0 ? "-" : "", + add_dot ? "." : "", + (int)floorf(fabsf(number_to_format_converted)), + units[order]); +} + /** \} */ diff --git a/source/blender/blenlib/tests/BLI_string_test.cc b/source/blender/blenlib/tests/BLI_string_test.cc index 9bdf6075c70..d726fbccf20 100644 --- a/source/blender/blenlib/tests/BLI_string_test.cc +++ b/source/blender/blenlib/tests/BLI_string_test.cc @@ -515,6 +515,103 @@ TEST(string, StrFormatDecimalUnits) EXPECT_STREQ("-2.1B", size_str); } +/* BLI_str_format_integer_unit */ +TEST(string, StrFormatIntegerUnits) +{ + char size_str[7]; + int size; + + BLI_str_format_integer_unit(size_str, size = 0); + EXPECT_STREQ("0", size_str); + BLI_str_format_integer_unit(size_str, size = 1); + EXPECT_STREQ("1", size_str); + BLI_str_format_integer_unit(size_str, size = 10); + EXPECT_STREQ("10", size_str); + BLI_str_format_integer_unit(size_str, size = 15); + EXPECT_STREQ("15", size_str); + BLI_str_format_integer_unit(size_str, size = 100); + EXPECT_STREQ("100", size_str); + BLI_str_format_integer_unit(size_str, size = 155); + EXPECT_STREQ("155", size_str); + BLI_str_format_integer_unit(size_str, size = 1000); + EXPECT_STREQ("1K", size_str); + BLI_str_format_integer_unit(size_str, size = 1555); + EXPECT_STREQ("1K", size_str); + BLI_str_format_integer_unit(size_str, size = 10000); + EXPECT_STREQ("10K", size_str); + BLI_str_format_integer_unit(size_str, size = 15555); + EXPECT_STREQ("15K", size_str); + BLI_str_format_integer_unit(size_str, size = 100000); + EXPECT_STREQ(".1M", size_str); + BLI_str_format_integer_unit(size_str, size = 155555); + EXPECT_STREQ(".1M", size_str); + BLI_str_format_integer_unit(size_str, size = 1000000); + EXPECT_STREQ("1M", size_str); + BLI_str_format_integer_unit(size_str, size = 1555555); + EXPECT_STREQ("1M", size_str); + BLI_str_format_integer_unit(size_str, size = 2555555); + EXPECT_STREQ("2M", size_str); + BLI_str_format_integer_unit(size_str, size = 10000000); + EXPECT_STREQ("10M", size_str); + BLI_str_format_integer_unit(size_str, size = 15555555); + EXPECT_STREQ("15M", size_str); + BLI_str_format_integer_unit(size_str, size = 100000000); + EXPECT_STREQ(".1B", size_str); + BLI_str_format_integer_unit(size_str, size = 155555555); + EXPECT_STREQ(".1B", size_str); + BLI_str_format_integer_unit(size_str, size = 255555555); + EXPECT_STREQ(".2B", size_str); + BLI_str_format_integer_unit(size_str, size = 1000000000); + EXPECT_STREQ("1B", size_str); + + /* Largest possible value. */ + BLI_str_format_integer_unit(size_str, size = INT32_MAX); + EXPECT_STREQ("2B", size_str); + + BLI_str_format_integer_unit(size_str, size = -0); + EXPECT_STREQ("0", size_str); + BLI_str_format_integer_unit(size_str, size = -1); + EXPECT_STREQ("-1", size_str); + BLI_str_format_integer_unit(size_str, size = -10); + EXPECT_STREQ("-10", size_str); + BLI_str_format_integer_unit(size_str, size = -15); + EXPECT_STREQ("-15", size_str); + BLI_str_format_integer_unit(size_str, size = -100); + EXPECT_STREQ("-100", size_str); + BLI_str_format_integer_unit(size_str, size = -155); + EXPECT_STREQ("-155", size_str); + BLI_str_format_integer_unit(size_str, size = -1000); + EXPECT_STREQ("-1K", size_str); + BLI_str_format_integer_unit(size_str, size = -1555); + EXPECT_STREQ("-1K", size_str); + BLI_str_format_integer_unit(size_str, size = -10000); + EXPECT_STREQ("-10K", size_str); + BLI_str_format_integer_unit(size_str, size = -15555); + EXPECT_STREQ("-15K", size_str); + BLI_str_format_integer_unit(size_str, size = -100000); + EXPECT_STREQ("-.1M", size_str); + BLI_str_format_integer_unit(size_str, size = -155555); + EXPECT_STREQ("-.1M", size_str); + BLI_str_format_integer_unit(size_str, size = -1000000); + EXPECT_STREQ("-1M", size_str); + BLI_str_format_integer_unit(size_str, size = -1555555); + EXPECT_STREQ("-1M", size_str); + BLI_str_format_integer_unit(size_str, size = -10000000); + EXPECT_STREQ("-10M", size_str); + BLI_str_format_integer_unit(size_str, size = -15555555); + EXPECT_STREQ("-15M", size_str); + BLI_str_format_integer_unit(size_str, size = -100000000); + EXPECT_STREQ("-.1B", size_str); + BLI_str_format_integer_unit(size_str, size = -155555555); + EXPECT_STREQ("-.1B", size_str); + BLI_str_format_integer_unit(size_str, size = -1000000000); + EXPECT_STREQ("-1B", size_str); + + /* Smallest possible value. */ + BLI_str_format_integer_unit(size_str, size = -INT32_MAX); + EXPECT_STREQ("-2B", size_str); +} + struct WordInfo { WordInfo() = default; WordInfo(int start, int end) : start(start), end(end) diff --git a/source/blender/blenloader/intern/versioning_300.cc b/source/blender/blenloader/intern/versioning_300.cc index e2b98b2283f..a2bd7fd2fd1 100644 --- a/source/blender/blenloader/intern/versioning_300.cc +++ b/source/blender/blenloader/intern/versioning_300.cc @@ -3630,6 +3630,29 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain) } } + if (!MAIN_VERSION_ATLEAST(bmain, 304, 5)) { + /* Fix for T101622 - update flags of sequence editor regions that were not initialized + * properly. */ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase : + &sl->regionbase; + if (sl->spacetype == SPACE_SEQ) { + LISTBASE_FOREACH (ARegion *, region, regionbase) { + if (region->regiontype == RGN_TYPE_TOOLS) { + region->v2d.flag &= ~V2D_VIEWSYNC_AREA_VERTICAL; + } + if (region->regiontype == RGN_TYPE_CHANNELS) { + region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL; + } + } + } + } + } + } + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/compositor/realtime_compositor/CMakeLists.txt b/source/blender/compositor/realtime_compositor/CMakeLists.txt index 90cbe0988ad..bab0b5385ec 100644 --- a/source/blender/compositor/realtime_compositor/CMakeLists.txt +++ b/source/blender/compositor/realtime_compositor/CMakeLists.txt @@ -2,7 +2,7 @@ set(INC . - ./algorithms + algorithms ../../blenkernel ../../blenlib ../../gpu diff --git a/source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh b/source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh index 9d0851eff84..f6d479f9bbe 100644 --- a/source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh +++ b/source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh @@ -27,6 +27,13 @@ float sum_blue(Context &context, GPUTexture *texture); * coefficients to compute the luminance. */ float sum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients); +/* Computes the sum of the logarithm of the luminance of all pixels in the given texture, using the + * given luminance coefficients to compute the luminance. */ +float sum_log_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients); + +/* Computes the sum of the colors of all pixels in the given texture. */ +float4 sum_color(Context &context, GPUTexture *texture); + /* -------------------------------------------------------------------- * Sum Of Squared Difference Reductions. */ @@ -55,4 +62,42 @@ float sum_luminance_squared_difference(Context &context, float3 luminance_coefficients, float subtrahend); +/* -------------------------------------------------------------------- + * Maximum Reductions. + */ + +/* Computes the maximum luminance of all pixels in the given texture, using the given luminance + * coefficients to compute the luminance. */ +float maximum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients); + +/* Computes the maximum float of all pixels in the given float texture, limited to the given range. + * Values outside of the given range are ignored. If non of the pixel values are in the range, the + * lower bound of the range is returned. For instance, if the given range is [-10, 10] and the + * image contains the values {2, 5, 11}, the maximum will be 5, since 11 is outside of the range. + * This is particularly useful for Z Depth normalization, since Z Depth can contain near infinite + * values, so enforcing an upper bound is beneficial. */ +float maximum_float_in_range(Context &context, + GPUTexture *texture, + float lower_bound, + float upper_bound); + +/* -------------------------------------------------------------------- + * Minimum Reductions. + */ + +/* Computes the minimum luminance of all pixels in the given texture, using the given luminance + * coefficients to compute the luminance. */ +float minimum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients); + +/* Computes the minimum float of all pixels in the given float texture, limited to the given range. + * Values outside of the given range are ignored. If non of the pixel values are in the range, the + * upper bound of the range is returned. For instance, if the given range is [-10, 10] and the + * image contains the values {-11, 2, 5}, the minimum will be 2, since -11 is outside of the range. + * This is particularly useful for Z Depth normalization, since Z Depth can contain near infinite + * values, so enforcing a lower bound is beneficial. */ +float minimum_float_in_range(Context &context, + GPUTexture *texture, + float lower_bound, + float upper_bound); + } // namespace blender::realtime_compositor diff --git a/source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc b/source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc index 3266ccd14eb..9672431992d 100644 --- a/source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc +++ b/source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc @@ -134,6 +134,34 @@ float sum_luminance(Context &context, GPUTexture *texture, float3 luminance_coef return sum; } +float sum_log_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients) +{ + GPUShader *shader = context.shader_manager().get("compositor_sum_log_luminance"); + GPU_shader_bind(shader); + + GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float sum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return sum; +} + +float4 sum_color(Context &context, GPUTexture *texture) +{ + GPUShader *shader = context.shader_manager().get("compositor_sum_color"); + GPU_shader_bind(shader); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_RGBA32F); + const float4 sum = float4(reduced_value); + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return sum; +} + /* -------------------------------------------------------------------- * Sum Of Squared Difference Reductions. */ @@ -202,4 +230,80 @@ float sum_luminance_squared_difference(Context &context, return sum; } +/* -------------------------------------------------------------------- + * Maximum Reductions. + */ + +float maximum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients) +{ + GPUShader *shader = context.shader_manager().get("compositor_maximum_luminance"); + GPU_shader_bind(shader); + + GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float maximum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return maximum; +} + +float maximum_float_in_range(Context &context, + GPUTexture *texture, + float lower_bound, + float upper_bound) +{ + GPUShader *shader = context.shader_manager().get("compositor_maximum_float_in_range"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1f(shader, "lower_bound", lower_bound); + GPU_shader_uniform_1f(shader, "upper_bound", upper_bound); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float maximum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return maximum; +} + +/* -------------------------------------------------------------------- + * Minimum Reductions. + */ + +float minimum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients) +{ + GPUShader *shader = context.shader_manager().get("compositor_minimum_luminance"); + GPU_shader_bind(shader); + + GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float minimum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return minimum; +} + +float minimum_float_in_range(Context &context, + GPUTexture *texture, + float lower_bound, + float upper_bound) +{ + GPUShader *shader = context.shader_manager().get("compositor_minimum_float_in_range"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1f(shader, "lower_bound", lower_bound); + GPU_shader_uniform_1f(shader, "upper_bound", upper_bound); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float minimum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return minimum; +} + } // namespace blender::realtime_compositor diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 6cb0b985d3d..c84852788fd 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -454,8 +454,8 @@ static int foreach_id_cow_detect_need_for_update_callback(LibraryIDLinkCallbackD return IDWALK_RET_NOP; } if (!ID_TYPE_IS_COW(GS(id->name))) { - /* No need to go further if thte id never had a cow copy in the depsgraph. This function is - * only concerned with keeping the mapping between original and cow ids intact. */ + /* No need to go further if the id never had a cow copy in the depsgraph. This function is + * only concerned with keeping the mapping between original and COW ids intact. */ return IDWALK_RET_NOP; } diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index b5f81f3a307..068b18f1117 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -924,17 +924,14 @@ void EEVEE_particle_hair_cache_populate(EEVEE_Data *vedata, if (matcache.depth_grp) { *matcache.depth_grp_p = DRW_shgroup_hair_create_sub( ob, psys, md, matcache.depth_grp, NULL); - DRW_shgroup_add_material_resources(*matcache.depth_grp_p, matcache.shading_gpumat); } if (matcache.shading_grp) { *matcache.shading_grp_p = DRW_shgroup_hair_create_sub( ob, psys, md, matcache.shading_grp, matcache.shading_gpumat); - DRW_shgroup_add_material_resources(*matcache.shading_grp_p, matcache.shading_gpumat); } if (matcache.shadow_grp) { *matcache.shadow_grp_p = DRW_shgroup_hair_create_sub( ob, psys, md, matcache.shadow_grp, NULL); - DRW_shgroup_add_material_resources(*matcache.shadow_grp_p, matcache.shading_gpumat); *cast_shadow = true; } @@ -954,16 +951,13 @@ void EEVEE_object_curves_cache_populate(EEVEE_Data *vedata, if (matcache.depth_grp) { *matcache.depth_grp_p = DRW_shgroup_curves_create_sub(ob, matcache.depth_grp, NULL); - DRW_shgroup_add_material_resources(*matcache.depth_grp_p, matcache.shading_gpumat); } if (matcache.shading_grp) { *matcache.shading_grp_p = DRW_shgroup_curves_create_sub( ob, matcache.shading_grp, matcache.shading_gpumat); - DRW_shgroup_add_material_resources(*matcache.shading_grp_p, matcache.shading_gpumat); } if (matcache.shadow_grp) { *matcache.shadow_grp_p = DRW_shgroup_curves_create_sub(ob, matcache.shadow_grp, NULL); - DRW_shgroup_add_material_resources(*matcache.shadow_grp_p, matcache.shading_gpumat); *cast_shadow = true; } diff --git a/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl b/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl index 90272400915..5af317b7398 100644 --- a/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl @@ -96,7 +96,7 @@ vec4 cubemap_seamless(sampler2DArray tex, vec4 cubevec, float lod) /* Mix all colors to get the corner color. */ vec4 col3 = (col + col1 + col2) / 3.0; - vec2 mix_fac = uv_border * 0.5; + vec2 mix_fac = saturate(uv_border * 0.5); return mix(mix(col, col2, mix_fac.x), mix(col1, col3, mix_fac.x), mix_fac.y); } else if (any(border)) { @@ -108,7 +108,7 @@ vec4 cubemap_seamless(sampler2DArray tex, vec4 cubevec, float lod) uv = cubemap_face_coord(cubevec.xyz, face); coord = vec3(uv, cubevec.w * 6.0 + face); - float mix_fac = max(uv_border.x, uv_border.y) * 0.5; + float mix_fac = saturate(max(uv_border.x, uv_border.y) * 0.5); return mix(col, textureLod(tex, coord, lod), mix_fac); } else { diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl index 51a351babd3..5f04cdcebfa 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl @@ -95,7 +95,11 @@ void main() weights = dof_layer_weight(cocs) * dof_sample_weight(cocs); /* Filter NaNs. */ - weights = select(weights, vec4(0.0), equal(cocs, vec4(0.0))); + for (int i = 0; i < 4; i++) { + if (isnan(weights[i]) || isinf(weights[i])) { + weights[i] = 0.0; + } + } color1 = colors[0] * weights[0]; color2 = colors[1] * weights[1]; diff --git a/source/blender/draw/intern/draw_curves.cc b/source/blender/draw/intern/draw_curves.cc index a61769e7a63..8847e3f6016 100644 --- a/source/blender/draw/intern/draw_curves.cc +++ b/source/blender/draw/intern/draw_curves.cc @@ -394,6 +394,11 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object, DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", hair_rad_root); DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", hair_rad_tip); DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", hair_close_tip); + if (gpu_material) { + /* \note: This needs to happen before the drawcall to allow correct attribute extraction. + * (see T101896) */ + DRW_shgroup_add_material_resources(shgrp, gpu_material); + } /* TODO(fclem): Until we have a better way to cull the curves and render with orco, bypass * culling test. */ GPUBatch *geom = curves_cache->final[subdiv].proc_hairs[thickness_res - 1]; diff --git a/source/blender/draw/intern/draw_hair.cc b/source/blender/draw/intern/draw_hair.cc index 4e44967e5e9..281e58ea230 100644 --- a/source/blender/draw/intern/draw_hair.cc +++ b/source/blender/draw/intern/draw_hair.cc @@ -293,6 +293,11 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", hair_rad_root); DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", hair_rad_tip); DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", hair_close_tip); + if (gpu_material) { + /* \note: This needs to happen before the drawcall to allow correct attribute extraction. + * (see T101896) */ + DRW_shgroup_add_material_resources(shgrp, gpu_material); + } /* TODO(fclem): Until we have a better way to cull the hair and render with orco, bypass * culling test. */ GPUBatch *geom = hair_cache->final[subdiv].proc_hairs[thickness_res - 1]; diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index da77845feb4..b9a9780e651 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1959,20 +1959,6 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph DST.buffer_finish_called = false; } -/* Callback function for RE_engine_update_render_passes to ensure all - * render passes are registered. */ -static void draw_render_result_ensure_pass_cb(void *user_data, - struct Scene *UNUSED(scene), - struct ViewLayer *view_layer, - const char *name, - int channels, - const char *chanid, - eNodeSocketDatatype UNUSED(type)) -{ - RenderEngine *engine = user_data; - RE_engine_add_pass(engine, name, channels, chanid, view_layer->name); -} - void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) { Scene *scene = DEG_get_evaluated_scene(depsgraph); @@ -2023,10 +2009,6 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) /* set default viewport */ GPU_viewport(0, 0, size[0], size[1]); - /* Update the render passes. This needs to be done before acquiring the render result. */ - RE_engine_update_render_passes( - engine, scene, view_layer, draw_render_result_ensure_pass_cb, engine); - /* Init render result. */ RenderResult *render_result = RE_engine_begin_result(engine, 0, diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index 677bf1bb392..2fd58a9cee0 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -13,9 +13,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_math_geom.h" #include "BLI_utildefines.h" #include "BLT_translation.h" diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index c8ffbb9acb1..b97cd6a9099 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -345,12 +345,14 @@ typedef enum { ED_UVPACK_MARGIN_FRACTION, /* Specify a precise fraction of final UV output. */ } eUVPackIsland_MarginMethod; +/** See also #UnwrapOptions. */ struct UVPackIsland_Params { uint rotate : 1; uint only_selected_uvs : 1; uint only_selected_faces : 1; uint use_seams : 1; uint correct_aspect : 1; + bool ignore_pinned; /* Ignore islands which have any pinned UVs. */ eUVPackIsland_MarginMethod margin_method; /* Which formula to use when scaling island margin. */ float margin; /* Additional space to add around each island. */ }; diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 2a1941f0d9e..7e9422ff867 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1683,6 +1683,7 @@ int UI_search_items_find_index(uiSearchItems *items, const char *name); * Adds a hint to the button which draws right aligned, grayed out and never clipped. */ void UI_but_hint_drawstr_set(uiBut *but, const char *string); +void UI_but_icon_indicator_number_set(uiBut *but, const int indicator_number); void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]); @@ -2788,7 +2789,8 @@ typedef struct uiPropertySplitWrapper { uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout); void uiItemL(uiLayout *layout, const char *name, int icon); /* label */ -void uiItemL_ex(uiLayout *layout, const char *name, int icon, bool highlight, bool redalert); +struct uiBut *uiItemL_ex( + uiLayout *layout, const char *name, int icon, bool highlight, bool redalert); /** * Helper to add a label and creates a property split layout if needed. */ diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh index 6c756984203..fc03b0218c0 100644 --- a/source/blender/editors/include/UI_interface.hh +++ b/source/blender/editors/include/UI_interface.hh @@ -35,6 +35,7 @@ struct ContextPathItem { std::string name; /* #BIFIconID */ int icon; + int icon_indicator_number; }; void context_path_add_generic(Vector<ContextPathItem> &path, diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h index a1a98a4b08c..9669e242dac 100644 --- a/source/blender/editors/include/UI_interface_icons.h +++ b/source/blender/editors/include/UI_interface_icons.h @@ -27,6 +27,12 @@ typedef struct IconFile { int index; } IconFile; +typedef struct IconTextOverlay { + char text[5]; +} IconTextOverlay; + +#define UI_NO_ICON_OVERLAY_TEXT NULL + #define ICON_DEFAULT_HEIGHT 16 #define ICON_DEFAULT_WIDTH 16 @@ -105,7 +111,8 @@ void UI_icon_draw_ex(float x, float alpha, float desaturate, const uchar mono_color[4], - bool mono_border); + bool mono_border, + const struct IconTextOverlay *text_overlay); void UI_icons_free(void); void UI_icons_free_drawinfo(void *drawinfo); @@ -124,6 +131,9 @@ int UI_icon_from_library(const struct ID *id); int UI_icon_from_object_mode(int mode); int UI_icon_color_from_collection(const struct Collection *collection); +void UI_icon_text_overlay_init_from_count(struct IconTextOverlay *text_overlay, + const int icon_indicator_number); + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc index 422fc34aa50..1f88d25af2b 100644 --- a/source/blender/editors/interface/interface.cc +++ b/source/blender/editors/interface/interface.cc @@ -6452,6 +6452,11 @@ void UI_but_hint_drawstr_set(uiBut *but, const char *string) ui_but_add_shortcut(but, string, false); } +void UI_but_icon_indicator_number_set(uiBut *but, const int indicator_number) +{ + UI_icon_text_overlay_init_from_count(&but->icon_overlay_text, indicator_number); +} + void UI_but_node_link_set(uiBut *but, bNodeSocket *socket, const float draw_color[4]) { but->flag |= UI_BUT_NODE_LINK; diff --git a/source/blender/editors/interface/interface_context_path.cc b/source/blender/editors/interface/interface_context_path.cc index e8f552e26a3..91b2f9613de 100644 --- a/source/blender/editors/interface/interface_context_path.cc +++ b/source/blender/editors/interface/interface_context_path.cc @@ -17,6 +17,8 @@ #include "UI_interface.hh" #include "UI_resources.h" +#include "RNA_prototypes.h" + #include "WM_api.h" namespace blender::ui { @@ -41,7 +43,13 @@ void context_path_add_generic(Vector<ContextPathItem> &path, static_cast<BIFIconID>(RNA_struct_ui_icon(rna_ptr.type)) : icon_override; - path.append({name, int(icon)}); + if (&rna_type == &RNA_NodeTree) { + ID *id = (ID *)ptr; + path.append({name, int(icon), id->us}); + } + else { + path.append({name, int(icon), 1}); + } } /* -------------------------------------------------------------------- */ @@ -60,7 +68,9 @@ void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path) if (i > 0) { uiItemL(sub_row, "", ICON_RIGHTARROW_THIN); } - uiItemL(sub_row, context_path[i].name.c_str(), context_path[i].icon); + uiBut *but = uiItemL_ex( + sub_row, context_path[i].name.c_str(), context_path[i].icon, false, false); + UI_but_icon_indicator_number_set(but, context_path[i].icon_indicator_number); } } diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index deb3d84ae66..9a4f98ebcd6 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -415,8 +415,15 @@ static void vicon_collection_color_draw( const float aspect = (float)ICON_DEFAULT_WIDTH / (float)w; - UI_icon_draw_ex( - x, y, ICON_OUTLINER_COLLECTION, aspect, 1.0f, 0.0f, collection_color->color, true); + UI_icon_draw_ex(x, + y, + ICON_OUTLINER_COLLECTION, + aspect, + 1.0f, + 0.0f, + collection_color->color, + true, + UI_NO_ICON_OVERLAY_TEXT); } # define DEF_ICON_COLLECTION_COLOR_DRAW(index, color) \ @@ -444,7 +451,8 @@ static void vicon_strip_color_draw( const float aspect = (float)ICON_DEFAULT_WIDTH / (float)w; - UI_icon_draw_ex(x, y, ICON_SNAP_FACE, aspect, 1.0f, 0.0f, strip_color->color, true); + UI_icon_draw_ex( + x, y, ICON_SNAP_FACE, aspect, 1.0f, 0.0f, strip_color->color, true, UI_NO_ICON_OVERLAY_TEXT); } # define DEF_ICON_STRIP_COLOR_DRAW(index, color) \ @@ -472,8 +480,15 @@ static void vicon_strip_color_draw_library_data_indirect( { const float aspect = (float)ICON_DEFAULT_WIDTH / (float)w; - UI_icon_draw_ex( - x, y, ICON_LIBRARY_DATA_DIRECT, aspect, ICON_INDIRECT_DATA_ALPHA * alpha, 0.0f, NULL, false); + UI_icon_draw_ex(x, + y, + ICON_LIBRARY_DATA_DIRECT, + aspect, + ICON_INDIRECT_DATA_ALPHA * alpha, + 0.0f, + NULL, + false, + UI_NO_ICON_OVERLAY_TEXT); } static void vicon_strip_color_draw_library_data_override_noneditable( @@ -488,7 +503,8 @@ static void vicon_strip_color_draw_library_data_override_noneditable( ICON_INDIRECT_DATA_ALPHA * alpha * 0.75f, 0.0f, NULL, - false); + false, + UI_NO_ICON_OVERLAY_TEXT); } /* Dynamically render icon instead of rendering a plain color to a texture/buffer @@ -1716,9 +1732,47 @@ static void icon_draw_texture(float x, int ih, float alpha, const float rgb[3], - bool with_border) -{ - if (g_icon_draw_cache.enabled) { + bool with_border, + const IconTextOverlay *text_overlay) +{ + const float zoom_factor = w / UI_DPI_ICON_SIZE; + float text_width = 0.0f; + + /* No need to show if too zoomed out, otherwise it just adds noise. */ + const bool show_indicator = (text_overlay && text_overlay->text[0] != '\0') && + (zoom_factor > 0.7f); + + if (show_indicator) { + /* Handle the little numbers on top of the icon. */ + uchar text_color[4]; + UI_GetThemeColor3ubv(TH_TEXT, text_color); + text_color[3] = 255; + + uiFontStyle fstyle_small = *UI_FSTYLE_WIDGET; + fstyle_small.points *= zoom_factor; + fstyle_small.points *= 0.8f; + + rcti text_rect = { + .xmax = x + UI_UNIT_X * zoom_factor, + .xmin = x, + .ymax = y, + .ymin = y, + }; + + UI_fontstyle_draw(&fstyle_small, + &text_rect, + text_overlay->text, + sizeof(text_overlay->text), + text_color, + &(struct uiFontStyleDraw_Params){ + .align = UI_STYLE_TEXT_RIGHT, + }); + text_width = (float)UI_fontstyle_string_width(&fstyle_small, text_overlay->text) / UI_UNIT_X / + zoom_factor; + } + + /* Draw the actual icon. */ + if (!show_indicator && g_icon_draw_cache.enabled) { icon_draw_texture_cached(x, y, w, h, ix, iy, iw, ih, alpha, rgb, with_border); return; } @@ -1735,7 +1789,7 @@ static void icon_draw_texture(float x, GPUTexture *texture = with_border ? icongltex.tex[1] : icongltex.tex[0]; - GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR); + GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_ICON); GPU_shader_bind(shader); const int img_binding = GPU_shader_get_texture_binding(shader, "image"); @@ -1752,6 +1806,7 @@ static void icon_draw_texture(float x, GPU_shader_uniform_vector(shader, rect_tex_loc, 4, 1, (float[4]){x1, y1, x2, y2}); GPU_shader_uniform_vector(shader, rect_geom_loc, 4, 1, (float[4]){x, y, x + w, y + h}); + GPU_shader_uniform_1f(shader, "text_width", text_width); GPU_texture_bind_ex(texture, GPU_SAMPLER_ICON, img_binding, false); @@ -1786,7 +1841,8 @@ static void icon_draw_size(float x, int draw_size, const float desaturate, const uchar mono_rgba[4], - const bool mono_border) + const bool mono_border, + const IconTextOverlay *text_overlay) { bTheme *btheme = UI_GetTheme(); const float fdraw_size = (float)draw_size; @@ -1874,7 +1930,8 @@ static void icon_draw_size(float x, di->data.texture.h, alpha, NULL, - false); + false, + text_overlay); } else if (di->type == ICON_TYPE_MONO_TEXTURE) { /* Monochrome icon that uses text or theme color. */ @@ -1908,7 +1965,8 @@ static void icon_draw_size(float x, di->data.texture.h + 2 * border_texel, color[3], color, - with_border); + with_border, + text_overlay); } else if (di->type == ICON_TYPE_BUFFER) { @@ -2425,17 +2483,27 @@ int UI_icon_color_from_collection(const Collection *collection) void UI_icon_draw(float x, float y, int icon_id) { - UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, 1.0f, 0.0f, NULL, false); + UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, 1.0f, 0.0f, NULL, false, UI_NO_ICON_OVERLAY_TEXT); } void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha) { - UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, alpha, 0.0f, NULL, false); + UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, alpha, 0.0f, NULL, false, UI_NO_ICON_OVERLAY_TEXT); } void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size) { - icon_draw_size(x, y, icon_id, aspect, alpha, ICON_SIZE_PREVIEW, size, false, NULL, false); + icon_draw_size(x, + y, + icon_id, + aspect, + alpha, + ICON_SIZE_PREVIEW, + size, + false, + NULL, + false, + UI_NO_ICON_OVERLAY_TEXT); } void UI_icon_draw_ex(float x, @@ -2445,7 +2513,8 @@ void UI_icon_draw_ex(float x, float alpha, float desaturate, const uchar mono_color[4], - const bool mono_border) + const bool mono_border, + const IconTextOverlay *text_overlay) { const int draw_size = get_draw_size(ICON_SIZE_ICON); icon_draw_size(x, @@ -2457,7 +2526,19 @@ void UI_icon_draw_ex(float x, draw_size, desaturate, mono_color, - mono_border); + mono_border, + text_overlay); +} + +void UI_icon_text_overlay_init_from_count(IconTextOverlay *text_overlay, + const int icon_indicator_number) +{ + /* The icon indicator is used as an aggregator, no need to show if it is 1. */ + if (icon_indicator_number < 2) { + text_overlay->text[0] = '\0'; + return; + } + BLI_str_format_integer_unit(text_overlay->text, icon_indicator_number); } /* ********** Alert Icons ********** */ diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 6ef7d346418..6ef81ad897e 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -23,6 +23,7 @@ struct ARegion; struct AnimationEvalContext; struct CurveMapping; struct CurveProfile; +struct IconTextOverlay; struct ID; struct ImBuf; struct Main; @@ -275,6 +276,9 @@ struct uiBut { uiButPushedStateFunc pushed_state_func; const void *pushed_state_arg; + /** Little indicator (e.g., counter) displayed on top of some icons. */ + struct IconTextOverlay icon_overlay_text; + /* pointer back */ uiBlock *block; }; diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index c906a5b36f1..496f72c089a 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -3235,7 +3235,7 @@ static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon) return but; } -void uiItemL_ex( +uiBut *uiItemL_ex( uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert) { uiBut *but = uiItemL_(layout, name, icon); @@ -3248,6 +3248,8 @@ void uiItemL_ex( if (redalert) { UI_but_flag_enable(but, UI_BUT_REDALERT); } + + return but; } void uiItemL(uiLayout *layout, const char *name, int icon) diff --git a/source/blender/editors/interface/interface_panel.cc b/source/blender/editors/interface/interface_panel.cc index 7a69e2f9b2f..24d8281aad8 100644 --- a/source/blender/editors/interface/interface_panel.cc +++ b/source/blender/editors/interface/interface_panel.cc @@ -1112,7 +1112,8 @@ static void panel_draw_aligned_widgets(const uiStyle *style, 0.7f, 0.0f, title_color, - false); + false, + UI_NO_ICON_OVERLAY_TEXT); GPU_blend(GPU_BLEND_NONE); } @@ -1140,7 +1141,8 @@ static void panel_draw_aligned_widgets(const uiStyle *style, 1.0f, 0.0f, title_color, - false); + false, + UI_NO_ICON_OVERLAY_TEXT); GPU_blend(GPU_BLEND_NONE); } diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 6ba80e2e0d9..1bad9b34a72 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1420,21 +1420,25 @@ static void widget_draw_icon( /* to indicate draggable */ if (ui_but_drag_is_draggable(but) && (but->flag & UI_ACTIVE)) { - UI_icon_draw_ex(xs, ys, icon, aspect, 1.25f, 0.0f, color, has_theme); + UI_icon_draw_ex( + xs, ys, icon, aspect, 1.25f, 0.0f, color, has_theme, &but->icon_overlay_text); } else if (but->flag & (UI_ACTIVE | UI_SELECT | UI_SELECT_DRAW)) { - UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, has_theme); + UI_icon_draw_ex( + xs, ys, icon, aspect, alpha, 0.0f, color, has_theme, &but->icon_overlay_text); } else if (!((but->icon != ICON_NONE) && UI_but_is_tool(but))) { if (has_theme) { alpha *= 0.8f; } - UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, has_theme); + UI_icon_draw_ex( + xs, ys, icon, aspect, alpha, 0.0f, color, has_theme, &but->icon_overlay_text); } else { const bTheme *btheme = UI_GetTheme(); const float desaturate = 1.0 - btheme->tui.icon_saturation; - UI_icon_draw_ex(xs, ys, icon, aspect, alpha, desaturate, color, has_theme); + UI_icon_draw_ex( + xs, ys, icon, aspect, alpha, desaturate, color, has_theme, &but->icon_overlay_text); } } @@ -5426,7 +5430,8 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, GPU_blend(GPU_BLEND_ALPHA); /* XXX scale weak get from fstyle? */ - UI_icon_draw_ex(xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false); + UI_icon_draw_ex( + xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false, UI_NO_ICON_OVERLAY_TEXT); GPU_blend(GPU_BLEND_NONE); } diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc index 3ce39b695e0..f6eee7c0c9e 100644 --- a/source/blender/editors/object/object_add.cc +++ b/source/blender/editors/object/object_add.cc @@ -3556,11 +3556,62 @@ void OBJECT_OT_convert(wmOperatorType *ot) /** \name Duplicate Object Operator * \{ */ +static void object_add_sync_base_collection( + Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_src, Object *object_new) +{ + if ((base_src != nullptr) && (base_src->flag & BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT)) { + BKE_collection_object_add_from(bmain, scene, base_src->object, object_new); + } + else { + LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer); + BKE_collection_object_add(bmain, layer_collection->collection, object_new); + } +} + +static void object_add_sync_local_view(Base *base_src, Base *base_new) +{ + base_new->local_view_bits = base_src->local_view_bits; +} + +static void object_add_sync_rigid_body(Main *bmain, Object *object_src, Object *object_new) +{ + /* 1) duplis should end up in same collection as the original + * 2) Rigid Body sim participants MUST always be part of a collection... + */ + /* XXX: is 2) really a good measure here? */ + if (object_src->rigidbody_object || object_src->rigidbody_constraint) { + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { + if (BKE_collection_has_object(collection, object_src)) { + BKE_collection_object_add(bmain, collection, object_new); + } + } + } +} + /** * - Assumes `id.new` is correct. * - Leaves selection of base/object unaltered. * - Sets #ID.newid pointers. */ +static void object_add_duplicate_internal(Main *bmain, + Object *ob, + const eDupli_ID_Flags dupflag, + const eLibIDDuplicateFlags duplicate_options, + Object **r_ob_new) +{ + if (ob->mode & OB_MODE_POSE) { + return; + } + + Object *obn = static_cast<Object *>( + ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag, duplicate_options))); + if (r_ob_new) { + *r_ob_new = obn; + } + DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + return; +} + static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer *view_layer, @@ -3569,49 +3620,25 @@ static Base *object_add_duplicate_internal(Main *bmain, const eLibIDDuplicateFlags duplicate_options, Object **r_ob_new) { - Base *base, *basen = nullptr; - Object *obn; - - if (ob->mode & OB_MODE_POSE) { - /* nothing? */ + Object *object_new = nullptr; + object_add_duplicate_internal(bmain, ob, dupflag, duplicate_options, &object_new); + if (r_ob_new) { + *r_ob_new = object_new; + } + if (object_new == nullptr) { + return nullptr; } - else { - obn = static_cast<Object *>( - ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag, duplicate_options))); - if (r_ob_new) { - *r_ob_new = obn; - } - DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - - BKE_view_layer_synced_ensure(scene, view_layer); - base = BKE_view_layer_base_find(view_layer, ob); - if ((base != nullptr) && (base->flag & BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT)) { - BKE_collection_object_add_from(bmain, scene, ob, obn); - } - else { - LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer); - BKE_collection_object_add(bmain, layer_collection->collection, obn); - } - - BKE_view_layer_synced_ensure(scene, view_layer); - basen = BKE_view_layer_base_find(view_layer, obn); - if (base != nullptr && basen != nullptr) { - basen->local_view_bits = base->local_view_bits; - } - /* 1) duplis should end up in same collection as the original - * 2) Rigid Body sim participants MUST always be part of a collection... - */ - /* XXX: is 2) really a good measure here? */ - if (ob->rigidbody_object || ob->rigidbody_constraint) { - LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { - if (BKE_collection_has_object(collection, ob)) { - BKE_collection_object_add(bmain, collection, obn); - } - } - } + BKE_view_layer_synced_ensure(scene, view_layer); + Base *base_src = BKE_view_layer_base_find(view_layer, ob); + object_add_sync_base_collection(bmain, scene, view_layer, base_src, object_new); + BKE_view_layer_synced_ensure(scene, view_layer); + Base *base_new = BKE_view_layer_base_find(view_layer, object_new); + if (base_src && base_new) { + object_add_sync_local_view(base_src, base_new); } - return basen; + object_add_sync_rigid_body(bmain, ob, object_new); + return base_new; } Base *ED_object_add_duplicate( @@ -3665,70 +3692,70 @@ static int duplicate_exec(bContext *C, wmOperator *op) * we also want to remap pointers between those... */ BKE_main_id_newptr_and_tag_clear(bmain); - /* Do not do collection re-syncs for each object; will do it once afterwards. - * However this means we can't get to new duplicated Base's immediately, will - * have to process them after the sync. */ - BKE_layer_collection_resync_forbid(); - /* Duplicate the selected objects, remember data needed to process - * after the sync (the base of the original object, and the copy of the - * original object). */ - blender::Vector<std::pair<Base *, Object *>> source_bases_new_objects; - Object *ob_new_active = nullptr; + * after the sync. */ + struct DuplicateObjectLink { + Base *base_src = nullptr; + Object *object_new = nullptr; + + DuplicateObjectLink(Base *base_src) : base_src(base_src) + { + } + }; + blender::Vector<DuplicateObjectLink> object_base_links; CTX_DATA_BEGIN (C, Base *, base, selected_bases) { - Object *ob_new = nullptr; + object_base_links.append(DuplicateObjectLink(base)); + } + CTX_DATA_END; + + bool new_objects_created = false; + for (DuplicateObjectLink &link : object_base_links) { object_add_duplicate_internal(bmain, - scene, - view_layer, - base->object, + link.base_src->object, dupflag, LIB_ID_DUPLICATE_IS_SUBPROCESS | LIB_ID_DUPLICATE_IS_ROOT_ID, - &ob_new); - if (ob_new == nullptr) { - continue; - } - source_bases_new_objects.append({base, ob_new}); - - /* note that this is safe to do with this context iterator, - * the list is made in advance */ - ED_object_base_select(base, BA_DESELECT); - - /* new object will become active */ - BKE_view_layer_synced_ensure(scene, view_layer); - if (BKE_view_layer_active_base_get(view_layer) == base) { - ob_new_active = ob_new; + &link.object_new); + if (link.object_new) { + new_objects_created = true; } } - CTX_DATA_END; - BKE_layer_collection_resync_allow(); - if (source_bases_new_objects.is_empty()) { + if (!new_objects_created) { return OPERATOR_CANCELLED; } - /* Sync the collection now, after everything is duplicated. */ - BKE_main_collection_sync(bmain); + /* Sync that could tag the view_layer out of sync. */ + for (DuplicateObjectLink &link : object_base_links) { + /* note that this is safe to do with this context iterator, + * the list is made in advance */ + ED_object_base_select(link.base_src, BA_DESELECT); + if (link.object_new) { + object_add_sync_base_collection(bmain, scene, view_layer, link.base_src, link.object_new); + object_add_sync_rigid_body(bmain, link.base_src->object, link.object_new); + } + } - /* After sync we can get to the new Base data, process it here. */ - for (const auto &item : source_bases_new_objects) { - Object *ob_new = item.second; - Base *base_source = item.first; - BKE_view_layer_synced_ensure(scene, view_layer); - Base *base_new = BKE_view_layer_base_find(view_layer, ob_new); - if (base_new == nullptr) { + /* Sync the view layer. Everything else should not tag the view_layer out of sync. */ + BKE_view_layer_synced_ensure(scene, view_layer); + const Base *active_base = BKE_view_layer_active_base_get(view_layer); + for (DuplicateObjectLink &link : object_base_links) { + if (!link.object_new) { continue; } + + Base *base_new = BKE_view_layer_base_find(view_layer, link.object_new); + BLI_assert(base_new); ED_object_base_select(base_new, BA_SELECT); - if (ob_new == ob_new_active) { + if (active_base == link.base_src) { ED_object_base_activate(C, base_new); } - if (base_new->object->data) { - DEG_id_tag_update(static_cast<ID *>(base_new->object->data), 0); + + if (link.object_new->data) { + DEG_id_tag_update(static_cast<ID *>(link.object_new->data), 0); } - /* #object_add_duplicate_internal will not have done this, since - * before the collection sync it would not have found the new base yet. */ - base_new->local_view_bits = base_source->local_view_bits; + + object_add_sync_local_view(link.base_src, base_new); } /* Note that this will also clear newid pointers and tags. */ diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 39e3c7a2f0a..8db968cbb8a 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -187,7 +187,8 @@ static void area_draw_azone_fullscreen( min_ff(alpha, 0.75f), 0.0f, NULL, - false); + false, + UI_NO_ICON_OVERLAY_TEXT); } /** diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.cc b/source/blender/editors/sculpt_paint/sculpt_face_set.cc index ee1238e0f24..8fb4dea668e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.cc +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.cc @@ -18,6 +18,7 @@ #include "BLI_math_vector.hh" #include "BLI_span.hh" #include "BLI_task.h" +#include "BLI_task.hh" #include "DNA_brush_types.h" #include "DNA_customdata_types.h" @@ -313,6 +314,7 @@ static EnumPropertyItem prop_sculpt_face_set_create_types[] = { static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) { + using namespace blender; Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); @@ -396,25 +398,16 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) } if (mode == SCULPT_FACE_SET_SELECTION) { - BMesh *bm; - const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh); - BMeshCreateParams create_params{}; - create_params.use_toolflags = true; - bm = BM_mesh_create(&allocsize, &create_params); - - BMeshFromMeshParams convert_params{}; - convert_params.calc_vert_normal = true; - convert_params.calc_face_normal = true; - BM_mesh_bm_from_me(bm, mesh, &convert_params); - - BMIter iter; - BMFace *f; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - ss->face_sets[BM_elem_index_get(f)] = next_face_set; + const bke::AttributeAccessor attributes = mesh->attributes(); + const VArraySpan<bool> select_poly = attributes.lookup_or_default<bool>( + ".select_poly", ATTR_DOMAIN_FACE, false); + threading::parallel_for(IndexRange(mesh->totvert), 4096, [&](const IndexRange range) { + for (const int i : range) { + if (select_poly[i]) { + ss->face_sets[i] = next_face_set; + } } - } - BM_mesh_free(bm); + }); } for (int i = 0; i < totnode; i++) { diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index e4085bbe9cc..240901318b5 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -410,8 +410,15 @@ static void file_draw_preview(const SpaceFile *sfile, } icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f); icon_y = yco + (ey / 2.0f) - (icon_size * ((file->typeflag & FILE_TYPE_DIR) ? 0.78f : 0.75f)); - UI_icon_draw_ex( - icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false); + UI_icon_draw_ex(icon_x, + icon_y, + icon, + icon_aspect / U.dpi_fac, + icon_opacity, + 0.0f, + icon_color, + false, + UI_NO_ICON_OVERLAY_TEXT); } if (is_link || is_offline) { @@ -424,8 +431,24 @@ static void file_draw_preview(const SpaceFile *sfile, /* At very bottom-left if preview style. */ const uchar dark[4] = {0, 0, 0, 255}; const uchar light[4] = {255, 255, 255, 255}; - UI_icon_draw_ex(icon_x + 1, icon_y - 1, arrow, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false); - UI_icon_draw_ex(icon_x, icon_y, arrow, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); + UI_icon_draw_ex(icon_x + 1, + icon_y - 1, + arrow, + 1.0f / U.dpi_fac, + 0.2f, + 0.0f, + dark, + false, + UI_NO_ICON_OVERLAY_TEXT); + UI_icon_draw_ex(icon_x, + icon_y, + arrow, + 1.0f / U.dpi_fac, + 0.6f, + 0.0f, + light, + false, + UI_NO_ICON_OVERLAY_TEXT); } else { /* Link to folder or non-previewed file. */ @@ -433,8 +456,15 @@ static void file_draw_preview(const SpaceFile *sfile, UI_GetThemeColor4ubv(TH_BACK, icon_color); icon_x = xco + ((file->typeflag & FILE_TYPE_DIR) ? 0.14f : 0.23f) * scaledx; icon_y = yco + ((file->typeflag & FILE_TYPE_DIR) ? 0.24f : 0.14f) * scaledy; - UI_icon_draw_ex( - icon_x, icon_y, arrow, icon_aspect / U.dpi_fac * 1.8, 0.3f, 0.0f, icon_color, false); + UI_icon_draw_ex(icon_x, + icon_y, + arrow, + icon_aspect / U.dpi_fac * 1.8, + 0.3f, + 0.0f, + icon_color, + false, + UI_NO_ICON_OVERLAY_TEXT); } } else if (icon && !is_icon && !(file->typeflag & FILE_TYPE_FTFONT)) { @@ -444,8 +474,17 @@ static void file_draw_preview(const SpaceFile *sfile, const uchar light[4] = {255, 255, 255, 255}; icon_x = xco + (2.0f * UI_DPI_FAC); icon_y = yco + (2.0f * UI_DPI_FAC); - UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false); - UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); + UI_icon_draw_ex(icon_x + 1, + icon_y - 1, + icon, + 1.0f / U.dpi_fac, + 0.2f, + 0.0f, + dark, + false, + UI_NO_ICON_OVERLAY_TEXT); + UI_icon_draw_ex( + icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false, UI_NO_ICON_OVERLAY_TEXT); } const bool is_current_main_data = filelist_file_get_id(file) != NULL; @@ -456,7 +495,15 @@ static void file_draw_preview(const SpaceFile *sfile, const uchar light[4] = {255, 255, 255, 255}; icon_x = xco + ex - UI_UNIT_X; icon_y = yco + ey - UI_UNIT_Y; - UI_icon_draw_ex(icon_x, icon_y, ICON_CURRENT_FILE, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); + UI_icon_draw_ex(icon_x, + icon_y, + ICON_CURRENT_FILE, + 1.0f / U.dpi_fac, + 0.6f, + 0.0f, + light, + false, + UI_NO_ICON_OVERLAY_TEXT); } /* Contrasting outline around some preview types. */ diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c index aee72860a0a..12ee6f45991 100644 --- a/source/blender/editors/space_info/textview.c +++ b/source/blender/editors/space_info/textview.c @@ -235,7 +235,8 @@ static bool textview_draw_string(TextViewDrawState *tds, 1.0f, 0.0f, icon_fg, - false); + false, + UI_NO_ICON_OVERLAY_TEXT); GPU_blend(GPU_BLEND_NONE); } diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index ee9ebd541a0..98b2cacd162 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -2145,6 +2145,9 @@ static void node_draw_basis(const bContext &C, 0, ""); UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_group_edit"); + if (node.id) { + UI_but_icon_indicator_number_set(but, node.id->us); + } UI_block_emboss_set(&block, UI_EMBOSS); } if (node.type == NODE_CUSTOM && node.typeinfo->ui_icon != ICON_NONE) { diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index b12afcb1faa..637c795d4d7 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -815,7 +815,8 @@ static void draw_draglink_tooltip(const bContext * /*C*/, ARegion * /*region*/, nldrag->cursor[0]; const float y = nldrag->cursor[1] - 2.0f * UI_DPI_FAC; - UI_icon_draw_ex(x, y, ICON_ADD, U.inv_dpi_fac, 1.0f, 0.0f, text_col, false); + UI_icon_draw_ex( + x, y, ICON_ADD, U.inv_dpi_fac, 1.0f, 0.0f, text_col, false, UI_NO_ICON_OVERLAY_TEXT); } static void draw_draglink_tooltip_activate(const ARegion ®ion, bNodeLinkDrag &nldrag) diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc index e366c58349f..f76c0980c4f 100644 --- a/source/blender/editors/space_outliner/outliner_draw.cc +++ b/source/blender/editors/space_outliner/outliner_draw.cc @@ -2877,7 +2877,8 @@ static bool tselem_draw_icon(uiBlock *block, TreeStoreElem *tselem, TreeElement *te, float alpha, - const bool is_clickable) + const bool is_clickable, + const int num_elements) { TreeElementIcon data = tree_element_get_icon(tselem, te); if (data.icon == 0) { @@ -2885,6 +2886,8 @@ static bool tselem_draw_icon(uiBlock *block, } const bool is_collection = outliner_is_collection_tree_element(te); + IconTextOverlay text_overlay; + UI_icon_text_overlay_init_from_count(&text_overlay, num_elements); /* Collection colors and icons covered by restrict buttons. */ if (!is_clickable || x >= xmax || is_collection) { @@ -2904,7 +2907,8 @@ static bool tselem_draw_icon(uiBlock *block, alpha, 0.0f, btheme->collection_color[collection->color_tag].color, - true); + true, + &text_overlay); return true; } } @@ -2915,10 +2919,10 @@ static bool tselem_draw_icon(uiBlock *block, /* Restrict column clip. it has been coded by simply overdrawing, doesn't work for buttons. */ uchar color[4]; if (UI_icon_get_theme_color(data.icon, color)) { - UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, color, true); + UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, color, true, &text_overlay); } else { - UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, nullptr, false); + UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, nullptr, false, &text_overlay); } } else { @@ -2941,104 +2945,6 @@ static bool tselem_draw_icon(uiBlock *block, return true; } -static bool outliner_is_main_row(const ARegion *region, const int ys) -{ - int ystart; - - ystart = int(region->v2d.tot.ymax); - ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET; - - return ((ys - ystart) / UI_UNIT_Y) % 2; -} - -/** - * Get the expected row background color to use for the data-block counter - * - * This reproduces some of the logic of outliner_draw_highlights. - * At the moment it doesn't implement the search match color since - * we don't draw the data-block counter in those cases. - */ -static void outliner_get_row_color(const ARegion *region, - const TreeElement *te, - int ys, - float r_color[4]) -{ - const TreeStoreElem *tselem = TREESTORE(te); - - if ((tselem->flag & TSE_ACTIVE) && (tselem->flag & TSE_SELECTED)) { - UI_GetThemeColor3fv(TH_ACTIVE, r_color); - } - else if (tselem->flag & TSE_SELECTED) { - UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, r_color); - } - else if (outliner_is_main_row(region, ys)) { - UI_GetThemeColor3fv(TH_BACK, r_color); - } - else { - float color_alternating[4]; - UI_GetThemeColor4fv(TH_ROW_ALTERNATE, color_alternating); - UI_GetThemeColorBlend3f(TH_BACK, TH_ROW_ALTERNATE, color_alternating[3], r_color); - } - - if (tselem->flag & TSE_HIGHLIGHTED) { - const float color_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f}; - interp_v3_v3v3(r_color, r_color, color_highlight, color_highlight[3]); - } - r_color[3] = 1.0f; -} - -/** - * For icon-only children of a collapsed tree, - * Draw small number over the icon to show how many items of this type are displayed. - */ -static void outliner_draw_iconrow_number(const ARegion *region, - const uiFontStyle *fstyle, - int offsx, - int ys, - const TreeElement *te_visible, - const int num_elements) -{ - float color[4]; - outliner_get_row_color(region, te_visible, ys, color); - - float ufac = 0.25f * UI_UNIT_X; - float offset_x = float(offsx) + UI_UNIT_X * 0.35f; - rctf rect{}; - BLI_rctf_init(&rect, - offset_x + ufac, - offset_x + UI_UNIT_X - ufac, - float(ys) - UI_UNIT_Y * 0.2f + ufac, - float(ys) - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac); - - UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_4fv_ex( - &rect, color, NULL, 1.0f, color, U.pixelsize, float(UI_UNIT_Y) / 2.0f - ufac); - - /* Now the numbers. */ - uchar text_col[4]; - - UI_GetThemeColor3ubv(TH_TEXT, text_col); - text_col[3] = 255; - - uiFontStyle fstyle_small = *fstyle; - fstyle_small.points *= 0.8f; - - /* We treat +99 as 4 digits to make sure the (eyeballed) alignment looks nice. */ - int num_digits = 4; - char number_text[4] = "+99"; - if (num_elements < 100) { - BLI_snprintf(number_text, sizeof(number_text), "%d", num_elements); - num_digits = num_elements < 10 ? 1 : 2; - } - UI_fontstyle_draw_simple(&fstyle_small, - (offset_x + ufac + UI_UNIT_X * (2 - num_digits) * 0.12f), - float(ys) - UI_UNIT_Y * 0.095f + ufac, - number_text, - text_col); - UI_fontstyle_set(fstyle); - GPU_blend(GPU_BLEND_ALPHA); /* Round-box and text drawing disables. */ -} - static void outliner_icon_background_colors(float icon_color[4], float icon_border[4]) { float text[4]; @@ -3069,11 +2975,8 @@ static void outliner_draw_active_indicator(const float minx, GPU_blend(GPU_BLEND_ALPHA); /* Round-box disables. */ } -static void outliner_draw_iconrow_doit(const ARegion *region, - uiBlock *block, - TreeElement *te_visible, +static void outliner_draw_iconrow_doit(uiBlock *block, TreeElement *te, - const uiFontStyle *fstyle, int xmax, int *offsx, int ys, @@ -3102,13 +3005,13 @@ static void outliner_draw_iconrow_doit(const ARegion *region, if (tselem->flag & TSE_HIGHLIGHTED_ICON) { alpha_fac += 0.5; } - tselem_draw_icon(block, xmax, float(*offsx), float(ys), tselem, te, alpha_fac, false); + tselem_draw_icon( + block, xmax, float(*offsx), float(ys), tselem, te, alpha_fac, false, num_elements); te->xs = *offsx; te->ys = ys; te->xend = short(*offsx) + UI_UNIT_X; if (num_elements > 1) { - outliner_draw_iconrow_number(region, fstyle, *offsx, ys, te_visible, num_elements); te->flag |= TE_ICONROW_MERGED; } else { @@ -3145,7 +3048,6 @@ static void outliner_draw_iconrow(bContext *C, const uiFontStyle *fstyle, const TreeViewContext *tvc, SpaceOutliner *space_outliner, - TreeElement *te_visible, ListBase *lb, int level, int xmax, @@ -3154,7 +3056,6 @@ static void outliner_draw_iconrow(bContext *C, float alpha_fac, MergedIconRow *merged) { - const ARegion *region = CTX_wm_region(C); eOLDrawState active = OL_DRAWSEL_NONE; LISTBASE_FOREACH (TreeElement *, te, lb) { @@ -3194,8 +3095,7 @@ static void outliner_draw_iconrow(bContext *C, TSE_POSE_CHANNEL, TSE_POSEGRP, TSE_DEFGROUP)) { - outliner_draw_iconrow_doit( - region, block, te_visible, te, fstyle, xmax, offsx, ys, alpha_fac, active, 1); + outliner_draw_iconrow_doit(block, te, xmax, offsx, ys, alpha_fac, active, 1); } else { const int index = tree_element_id_type_to_index(te); @@ -3214,7 +3114,6 @@ static void outliner_draw_iconrow(bContext *C, fstyle, tvc, space_outliner, - te, &te->subtree, level + 1, xmax, @@ -3236,11 +3135,8 @@ static void outliner_draw_iconrow(bContext *C, for (int j = 0; j < num_subtypes; j++) { const int index = index_base + j; if (merged->num_elements[index] != 0) { - outliner_draw_iconrow_doit(region, - block, - te_visible, + outliner_draw_iconrow_doit(block, merged->tree_element[index], - fstyle, xmax, offsx, ys, @@ -3429,7 +3325,8 @@ static void outliner_draw_tree_element(bContext *C, tselem, te, (tselem->flag & TSE_HIGHLIGHTED_ICON) ? alpha_fac + 0.5f : alpha_fac, - true)) { + true, + 1)) { offsx += UI_UNIT_X + 4 * ufac; } else { @@ -3478,7 +3375,6 @@ static void outliner_draw_tree_element(bContext *C, fstyle, tvc, space_outliner, - te, &te->subtree, 0, xmax, diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 8b6d37caa41..1d20926d16c 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -129,7 +129,6 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce region->regiontype = RGN_TYPE_TOOLS; region->alignment = RGN_ALIGN_LEFT; region->flag = RGN_FLAG_HIDDEN; - region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL; /* Channels. */ region = MEM_callocN(sizeof(ARegion), "channels for sequencer"); @@ -137,6 +136,7 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce BLI_addtail(&sseq->regionbase, region); region->regiontype = RGN_TYPE_CHANNELS; region->alignment = RGN_ALIGN_LEFT; + region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL; /* Preview region. */ /* NOTE: if you change values here, also change them in sequencer_init_preview_region. */ diff --git a/source/blender/editors/space_view3d/view3d_navigate_walk.c b/source/blender/editors/space_view3d/view3d_navigate_walk.c index 3e0ce892b5a..fcb4f549353 100644 --- a/source/blender/editors/space_view3d/view3d_navigate_walk.c +++ b/source/blender/editors/space_view3d/view3d_navigate_walk.c @@ -849,11 +849,15 @@ static void walkEvent(WalkInfo *walk, const wmEvent *event) if (ret) { WalkTeleport *teleport = &walk->teleport; + + /* Store the current navigation mode if we are not already teleporting. */ + if (teleport->state == WALK_TELEPORT_STATE_OFF) { + teleport->navigation_mode = walk->navigation_mode; + } teleport->state = WALK_TELEPORT_STATE_ON; teleport->initial_time = PIL_check_seconds_timer(); teleport->duration = U.walk_navigation.teleport_time; - teleport->navigation_mode = walk->navigation_mode; walk_navigation_mode_set(walk, WALK_MODE_FREE); copy_v3_v3(teleport->origin, walk->rv3d->viewinv[3]); @@ -864,9 +868,7 @@ static void walkEvent(WalkInfo *walk, const wmEvent *event) sub_v3_v3v3(teleport->direction, loc, teleport->origin); } - else { - walk->teleport.state = WALK_TELEPORT_STATE_OFF; - } + break; } @@ -1229,11 +1231,11 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm) /* keep moving if we were moving */ copy_v2_v2(dvec, walk->teleport.direction); - z_cur = walk->rv3d->viewinv[3][2]; - z_new = walk->teleport.origin[2] - getFreeFallDistance(walk->gravity, t) * walk->grid; + z_cur = walk->rv3d->viewinv[3][2] / walk->grid; + z_new = (walk->teleport.origin[2] / walk->grid) - getFreeFallDistance(walk->gravity, t); /* jump */ - z_new += t * walk->speed_jump * walk->grid; + z_new += t * walk->speed_jump; /* duration is the jump duration */ if (t > walk->teleport.duration) { diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 34e5b78c48f..5b194ae7237 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1594,9 +1594,9 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) RNA_enum_set(op->ptr, "snap_target", t->tsnap.source_select); eSnapTargetSelect target = t->tsnap.target_select; - RNA_boolean_set(op->ptr, "use_snap_self", (target & SCE_SNAP_TARGET_NOT_ACTIVE) != 0); - RNA_boolean_set(op->ptr, "use_snap_edit", (target & SCE_SNAP_TARGET_NOT_EDITED) != 0); - RNA_boolean_set(op->ptr, "use_snap_nonedit", (target & SCE_SNAP_TARGET_NOT_NONEDITED) != 0); + RNA_boolean_set(op->ptr, "use_snap_self", (target & SCE_SNAP_TARGET_NOT_ACTIVE) == 0); + RNA_boolean_set(op->ptr, "use_snap_edit", (target & SCE_SNAP_TARGET_NOT_EDITED) == 0); + RNA_boolean_set(op->ptr, "use_snap_nonedit", (target & SCE_SNAP_TARGET_NOT_NONEDITED) == 0); RNA_boolean_set( op->ptr, "use_snap_selectable", (target & SCE_SNAP_TARGET_ONLY_SELECTABLE) != 0); } @@ -1721,13 +1721,18 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } } -static void initSnapSpatial(TransInfo *t, float r_snap[2], float r_snap_y[2]) +static void initSnapSpatial(TransInfo *t, float r_snap[3], float *r_snap_precision) { + /* Default values. */ + r_snap[0] = r_snap[1] = 1.0f; + r_snap[1] = 0.0f; + *r_snap_precision = 0.1f; + if (t->spacetype == SPACE_VIEW3D) { if (t->region->regiondata) { View3D *v3d = t->area->spacedata.first; - r_snap[0] = ED_view3d_grid_view_scale(t->scene, v3d, t->region, NULL) * 1.0f; - r_snap[1] = r_snap[0] * 0.1f; + r_snap[0] = r_snap[1] = r_snap[2] = ED_view3d_grid_view_scale( + t->scene, v3d, t->region, NULL); } } else if (t->spacetype == SPACE_IMAGE) { @@ -1741,24 +1746,16 @@ static void initSnapSpatial(TransInfo *t, float r_snap[2], float r_snap_y[2]) ED_space_image_grid_steps(sima, grid_steps_x, grid_steps_y, grid_size); /* Snapping value based on what type of grid is used (adaptive-subdividing or custom-grid). */ r_snap[0] = ED_space_image_increment_snap_value(grid_size, grid_steps_x, zoom_factor); - r_snap[1] = r_snap[0] / 2.0f; - r_snap_y[0] = ED_space_image_increment_snap_value(grid_size, grid_steps_y, zoom_factor); - r_snap_y[1] = r_snap_y[0] / 2.0f; + r_snap[1] = ED_space_image_increment_snap_value(grid_size, grid_steps_y, zoom_factor); + *r_snap_precision = 0.5f; } else if (t->spacetype == SPACE_CLIP) { - r_snap[0] = 0.125f; - r_snap[1] = 0.0625f; + r_snap[0] = r_snap[1] = 0.125f; + *r_snap_precision = 0.5f; } else if (t->spacetype == SPACE_NODE) { r_snap[0] = r_snap[1] = ED_node_grid_size(); } - else if (t->spacetype == SPACE_GRAPH) { - r_snap[0] = 1.0; - r_snap[1] = 0.1f; - } - else { - r_snap[0] = r_snap[1] = 1.0f; - } } bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode) @@ -1898,7 +1895,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve initSnapping(t, op); /* Initialize snapping data AFTER mode flags */ - initSnapSpatial(t, t->snap_spatial_x, t->snap_spatial_y); + initSnapSpatial(t, t->snap_spatial, &t->snap_spatial_precision); /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. * will be removed (ton) */ diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 95686f12fe2..90f2795184b 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -555,9 +555,12 @@ typedef struct TransInfo { /** Snapping Gears. */ float snap[2]; /** Spatial snapping gears(even when rotating, scaling... etc). */ - float snap_spatial_x[2]; - /** Spatial snapping in the Y coordinate, for non-uniform grid in UV Editor. */ - float snap_spatial_y[2]; + float snap_spatial[3]; + /** + * Precision factor that is multiplied to snap_spatial when precision + * modifier is enabled for snap to grid or incremental snap. + */ + float snap_spatial_precision; /** Mouse side of the current frame, 'L', 'R' or 'B' */ char frame_side; diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index fa56456d8e7..7abf0e5c00c 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -404,9 +404,11 @@ static void applyAxisConstraintVec(const TransInfo *t, } } + /* Fallback for when axes are aligned. */ + mul_m3_v3(t->con.pmtx, out); + if (is_snap_to_point) { - /* With snap points, a projection is alright, no adjustments needed. */ - mul_m3_v3(t->con.pmtx, out); + /* Pass. With snap points, a projection is alright, no adjustments needed. */ } else { const int dims = getConstraintSpaceDimension(t); @@ -422,14 +424,9 @@ static void applyAxisConstraintVec(const TransInfo *t, /* Disabled, as it has not proven to be really useful. (See T82386). */ // constraint_snap_plane_to_face(t, plane, out); } - else { + else if (!isPlaneProjectionViewAligned(t, plane)) { /* View alignment correction. */ - if (!isPlaneProjectionViewAligned(t, plane)) { - planeProjection(t, plane, in, out); - } - else { - mul_m3_v3(t->con.pmtx, out); - } + planeProjection(t, plane, in, out); } } } diff --git a/source/blender/editors/transform/transform_convert_node.cc b/source/blender/editors/transform/transform_convert_node.cc index eb5eb822d69..6ab0e1fe701 100644 --- a/source/blender/editors/transform/transform_convert_node.cc +++ b/source/blender/editors/transform/transform_convert_node.cc @@ -155,9 +155,52 @@ static void createTransNodeData(bContext * /*C*/, TransInfo *t) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Node Transform Creation +/** \name Flush Transform Nodes * \{ */ +static void node_snap_grid_apply(TransInfo *t) +{ + int i; + + if (!(activeSnap(t) && (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) { + return; + } + + float grid_size[2]; + copy_v2_v2(grid_size, t->snap_spatial); + if (t->modifiers & MOD_PRECISION) { + mul_v2_fl(grid_size, t->snap_spatial_precision); + } + + /* Early exit on unusable grid size. */ + if (is_zero_v2(grid_size)) { + return; + } + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td; + + for (i = 0, td = tc->data; i < tc->data_len; i++, td++) { + float iloc[2], loc[2], tvec[2]; + if (td->flag & TD_SKIP) { + continue; + } + + if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) { + continue; + } + + copy_v2_v2(iloc, td->loc); + + loc[0] = roundf(iloc[0] / grid_size[0]) * grid_size[0]; + loc[1] = roundf(iloc[1] / grid_size[1]) * grid_size[1]; + + sub_v2_v2v2(tvec, loc, iloc); + add_v2_v2(td->loc, tvec); + } + } +} + static void flushTransNodes(TransInfo *t) { using namespace blender::ed; @@ -191,7 +234,7 @@ static void flushTransNodes(TransInfo *t) } FOREACH_TRANS_DATA_CONTAINER (t, tc) { - applyGridAbsolute(t); + node_snap_grid_apply(t); /* flush to 2d vector from internally used 3d vector */ for (int i = 0; i < tc->data_len; i++) { diff --git a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c index f7f9e14b8ac..76ce7b29619 100644 --- a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c +++ b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c @@ -8,6 +8,7 @@ #include <stdlib.h> #include "BLI_math.h" +#include "BLI_math_bits.h" #include "BLI_string.h" #include "BKE_context.h" @@ -62,7 +63,14 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) } if (td->val) { - *td->val = td->ival * ratio; + if (td->ival == 0.0f && ratio > 1.0f) { + /* Allow Shrink/Fatten for zero radius. */ + *td->val = (ratio - 1.0f) * uint_as_float(POINTER_AS_UINT(t->custom.mode.data)); + } + else { + *td->val = td->ival * ratio; + } + /* apply PET */ *td->val = interpf(*td->val, td->ival, td->factor); CLAMP_MIN(*td->val, 0.0f); @@ -92,6 +100,13 @@ void initCurveShrinkFatten(TransInfo *t) t->num.unit_type[0] = B_UNIT_NONE; t->flag |= T_NO_CONSTRAINT; + + if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { + /* Save a factor to multiply the ratio and use in zero radius cases. */ + RegionView3D *rv3d = t->region->regiondata; + float scale_factor = rv3d->pixsize * t->mouse.factor * t->zfac; + t->custom.mode.data = POINTER_FROM_UINT(float_as_uint(scale_factor)); + } } /** \} */ diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 91388ecd661..c751a68092f 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -170,7 +170,7 @@ static void transdata_elem_translate_fn(void *__restrict iter_data_v, /** \} */ /* -------------------------------------------------------------------- */ -/** \name Transform (Translation) +/** \name Transform (Translation) Header * \{ */ static void translate_dist_to_str(char *r_str, @@ -341,6 +341,96 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_ } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform (Translation) Snapping + * \{ */ + +static void translate_snap_target_grid_ensure(TransInfo *t) +{ + /* Only need to calculate once. */ + if ((t->tsnap.status & TARGET_GRID_INIT) == 0) { + if (t->data_type == &TransConvertType_Cursor3D) { + /* Use a fallback when transforming the cursor. + * In this case the center is _not_ derived from the cursor which is being transformed. */ + copy_v3_v3(t->tsnap.snapTargetGrid, TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->data->iloc); + } + else if (t->around == V3D_AROUND_CURSOR) { + /* Use a fallback for cursor selection, + * this isn't useful as a global center for absolute grid snapping + * since its not based on the position of the selection. */ + tranform_snap_target_median_calc(t, t->tsnap.snapTargetGrid); + } + else { + copy_v3_v3(t->tsnap.snapTargetGrid, t->center_global); + } + t->tsnap.status |= TARGET_GRID_INIT; + } +} + +static void translate_snap_grid_apply(TransInfo *t, + const int max_index, + const float grid_dist[3], + const float loc[3], + float r_out[3]) +{ + BLI_assert(max_index <= 2); + translate_snap_target_grid_ensure(t); + const float *center_global = t->tsnap.snapTargetGrid; + const float *asp = t->aspect; + + float in[3]; + if (t->con.mode & CON_APPLY) { + BLI_assert(t->tsnap.snapElem == SCE_SNAP_MODE_NONE); + t->con.applyVec(t, NULL, NULL, loc, in); + } + else { + copy_v3_v3(in, loc); + } + + for (int i = 0; i <= max_index; i++) { + const float iter_fac = grid_dist[i] * asp[i]; + r_out[i] = iter_fac * roundf((in[i] + center_global[i]) / iter_fac) - center_global[i]; + } +} + +static bool translate_snap_grid(TransInfo *t, float *val) +{ + if (!activeSnap(t)) { + return false; + } + + if (!(t->tsnap.mode & SCE_SNAP_MODE_GRID) || validSnap(t)) { + /* Don't do grid snapping if there is a valid snap point. */ + return false; + } + + /* Don't do grid snapping if not in 3D viewport or UV editor */ + if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) { + return false; + } + + if (t->mode != TFM_TRANSLATION) { + return false; + } + + float grid_dist[3]; + copy_v3_v3(grid_dist, t->snap_spatial); + if (t->modifiers & MOD_PRECISION) { + mul_v3_fl(grid_dist, t->snap_spatial_precision); + } + + /* Early bailing out if no need to snap */ + if (is_zero_v3(grid_dist)) { + return false; + } + + translate_snap_grid_apply(t, t->idx_max, grid_dist, val, val); + t->tsnap.snapElem = SCE_SNAP_MODE_GRID; + return true; +} + static void ApplySnapTranslation(TransInfo *t, float vec[3]) { float point[3]; @@ -372,6 +462,12 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3]) } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform (Translation) + * \{ */ + static void applyTranslationValue(TransInfo *t, const float vec[3]) { struct TranslateCustomData *custom_data = t->custom.mode.data; @@ -514,7 +610,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) t->tsnap.snapElem = SCE_SNAP_MODE_NONE; applySnappingAsGroup(t, global_dir); - transform_snap_grid(t, global_dir); + translate_snap_grid(t, global_dir); if (t->con.mode & CON_APPLY) { float in[3]; @@ -590,7 +686,8 @@ void initTranslation(TransInfo *t) t->num.flag = 0; t->num.idx_max = t->idx_max; - copy_v2_v2(t->snap, t->snap_spatial_x); + t->snap[0] = 1.0; + t->snap[1] = t->snap_spatial_precision; copy_v3_fl(t->num.val_inc, t->snap[0]); t->num.unit_sys = t->scene->unit.system; diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 553202b5798..672d947936d 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -511,56 +511,6 @@ void applySnappingIndividual(TransInfo *t) } } -void applyGridAbsolute(TransInfo *t) -{ - int i; - - if (!(activeSnap(t) && (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) { - return; - } - - float grid_size_x = (t->modifiers & MOD_PRECISION) ? t->snap_spatial_x[1] : t->snap_spatial_x[0]; - float grid_size_y = (t->modifiers & MOD_PRECISION) ? t->snap_spatial_y[1] : t->snap_spatial_y[0]; - float grid_size_z = grid_size_x; - - /* Early exit on unusable grid size. */ - if (grid_size_x == 0.0f || grid_size_y == 0.0f || grid_size_z == 0.0f) { - return; - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td; - - for (i = 0, td = tc->data; i < tc->data_len; i++, td++) { - float iloc[3], loc[3], tvec[3]; - if (td->flag & TD_SKIP) { - continue; - } - - if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) { - continue; - } - - copy_v3_v3(iloc, td->loc); - if (tc->use_local_mat) { - mul_m4_v3(tc->mat, iloc); - } - else if (t->options & CTX_OBJECT) { - BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob); - copy_v3_v3(iloc, td->ob->obmat[3]); - } - - loc[0] = roundf(iloc[0] / grid_size_x) * grid_size_x; - loc[1] = roundf(iloc[1] / grid_size_y) * grid_size_y; - loc[2] = roundf(iloc[2] / grid_size_z) * grid_size_z; - - sub_v3_v3v3(tvec, loc, iloc); - mul_m3_v3(td->smtx, tvec); - add_v3_v3(td->loc, tvec); - } - } -} - void applySnappingAsGroup(TransInfo *t, float *vec) { if (!activeSnap_SnappingAsGroup(t)) { @@ -1187,7 +1137,7 @@ static void snap_calc_sequencer_fn(TransInfo *t, float *UNUSED(vec)) /** \name Target * \{ */ -static void snap_target_median_impl(TransInfo *t, float r_median[3]) +void tranform_snap_target_median_calc(const TransInfo *t, float r_median[3]) { int i_accum = 0; @@ -1223,28 +1173,6 @@ static void snap_target_median_impl(TransInfo *t, float r_median[3]) // TargetSnapOffset(t, NULL); } -static void snap_target_grid_ensure(TransInfo *t) -{ - /* Only need to calculate once. */ - if ((t->tsnap.status & TARGET_GRID_INIT) == 0) { - if (t->data_type == &TransConvertType_Cursor3D) { - /* Use a fallback when transforming the cursor. - * In this case the center is _not_ derived from the cursor which is being transformed. */ - copy_v3_v3(t->tsnap.snapTargetGrid, TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->data->iloc); - } - else if (t->around == V3D_AROUND_CURSOR) { - /* Use a fallback for cursor selection, - * this isn't useful as a global center for absolute grid snapping - * since its not based on the position of the selection. */ - snap_target_median_impl(t, t->tsnap.snapTargetGrid); - } - else { - copy_v3_v3(t->tsnap.snapTargetGrid, t->center_global); - } - t->tsnap.status |= TARGET_GRID_INIT; - } -} - static void TargetSnapOffset(TransInfo *t, TransData *td) { if (t->spacetype == SPACE_NODE && td != NULL) { @@ -1316,7 +1244,7 @@ static void TargetSnapMedian(TransInfo *t) { /* Only need to calculate once. */ if ((t->tsnap.status & TARGET_INIT) == 0) { - snap_target_median_impl(t, t->tsnap.snapTarget); + tranform_snap_target_median_calc(t, t->tsnap.snapTarget); t->tsnap.status |= TARGET_INIT; } } @@ -1654,66 +1582,6 @@ bool snapNodesTransform( /** \name snap Grid * \{ */ -static void snap_grid_apply(TransInfo *t, - const int max_index, - const float grid_dist_x, - const float grid_dist_y, - const float loc[3], - float r_out[3]) -{ - BLI_assert(max_index <= 2); - snap_target_grid_ensure(t); - const float *center_global = t->tsnap.snapTargetGrid; - const float *asp = t->aspect; - - float in[3]; - if (t->con.mode & CON_APPLY) { - BLI_assert(t->tsnap.snapElem == SCE_SNAP_MODE_NONE); - t->con.applyVec(t, NULL, NULL, loc, in); - } - else { - copy_v3_v3(in, loc); - } - - for (int i = 0; i <= max_index; i++) { - const float iter_fac = ((i == 1) ? grid_dist_y : grid_dist_x) * asp[i]; - r_out[i] = iter_fac * roundf((in[i] + center_global[i]) / iter_fac) - center_global[i]; - } -} - -bool transform_snap_grid(TransInfo *t, float *val) -{ - if (!activeSnap(t)) { - return false; - } - - if (!(t->tsnap.mode & SCE_SNAP_MODE_GRID) || validSnap(t)) { - /* Don't do grid snapping if there is a valid snap point. */ - return false; - } - - /* Don't do grid snapping if not in 3D viewport or UV editor */ - if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) { - return false; - } - - if (t->mode != TFM_TRANSLATION) { - return false; - } - - float grid_dist_x = (t->modifiers & MOD_PRECISION) ? t->snap_spatial_x[1] : t->snap_spatial_x[0]; - float grid_dist_y = (t->modifiers & MOD_PRECISION) ? t->snap_spatial_y[1] : t->snap_spatial_y[0]; - - /* Early bailing out if no need to snap */ - if (grid_dist_x == 0.0f || grid_dist_y == 0.0f) { - return false; - } - - snap_grid_apply(t, t->idx_max, grid_dist_x, grid_dist_y, val, val); - t->tsnap.snapElem = SCE_SNAP_MODE_GRID; - return true; -} - static void snap_increment_apply_ex(const TransInfo *UNUSED(t), const int max_index, const float increment_val, diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h index 2b78c554ad8..16d9062e978 100644 --- a/source/blender/editors/transform/transform_snap.h +++ b/source/blender/editors/transform/transform_snap.h @@ -38,10 +38,10 @@ bool snapNodesTransform(struct TransInfo *t, bool transformModeUseSnap(const TransInfo *t); +void tranform_snap_target_median_calc(const TransInfo *t, float r_median[3]); bool transform_snap_increment_ex(const TransInfo *t, bool use_local_space, float *r_val); bool transform_snap_increment(const TransInfo *t, float *val); float transform_snap_increment_get(const TransInfo *t); -bool transform_snap_grid(TransInfo *t, float *val); bool activeSnap(const TransInfo *t); bool activeSnap_SnappingIndividual(const TransInfo *t); @@ -52,7 +52,6 @@ bool validSnap(const TransInfo *t); void initSnapping(struct TransInfo *t, struct wmOperator *op); void freeSnapping(struct TransInfo *t); void applySnappingIndividual(TransInfo *t); -void applyGridAbsolute(TransInfo *t); void applySnappingAsGroup(TransInfo *t, float *vec); void resetSnapping(TransInfo *t); eRedrawFlag handleSnapping(TransInfo *t, const struct wmEvent *event); diff --git a/source/blender/editors/util/ed_viewer_path.cc b/source/blender/editors/util/ed_viewer_path.cc index 5c03367cba8..4da1559b726 100644 --- a/source/blender/editors/util/ed_viewer_path.cc +++ b/source/blender/editors/util/ed_viewer_path.cc @@ -249,6 +249,9 @@ bool is_active_geometry_nodes_viewer(const bContext &C, if (md->type != eModifierType_Nodes) { return false; } + if ((md->mode & eModifierMode_Realtime) == 0) { + return false; + } modifier = reinterpret_cast<const NodesModifierData *>(md); break; } diff --git a/source/blender/editors/uvedit/uvedit_islands.cc b/source/blender/editors/uvedit/uvedit_islands.cc index bdd05b06d94..92745667505 100644 --- a/source/blender/editors/uvedit/uvedit_islands.cc +++ b/source/blender/editors/uvedit/uvedit_islands.cc @@ -600,6 +600,22 @@ static BoxPack *pack_islands_params(const blender::Vector<FaceIsland *> &island_ return box_array; } +static bool island_has_pins(FaceIsland *island) +{ + BMLoop *l; + BMIter iter; + const int cd_loop_uv_offset = island->cd_loop_uv_offset; + for (int i = 0; i < island->faces_len; i++) { + BM_ITER_ELEM (l, &iter, island->faces[i], BM_LOOPS_OF_FACE) { + MLoopUV *luv = static_cast<MLoopUV *>(BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset)); + if (luv->flag & MLOOPUV_PINNED) { + return true; + } + } + } + return false; +} + /* -------------------------------------------------------------------- */ /** \name Public UV Island Packing * @@ -651,8 +667,14 @@ void ED_uvedit_pack_islands_multi(const Scene *scene, aspect_y, cd_loop_uv_offset); - int index; - LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list, index) { + /* Remove from linked list and append to blender::Vector. */ + LISTBASE_FOREACH_MUTABLE (struct FaceIsland *, island, &island_list) { + BLI_remlink(&island_list, island); + if (params->ignore_pinned && island_has_pins(island)) { + MEM_freeN(island->faces); + MEM_freeN(island); + continue; + } island_vector.append(island); } } diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 5e2d9097abd..b65f4889347 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -37,6 +37,7 @@ #include "BKE_node.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "ED_image.h" #include "ED_mesh.h" @@ -113,7 +114,8 @@ bool ED_object_get_active_image(Object *ob, bNode **r_node, bNodeTree **r_ntree) { - Material *ma = BKE_object_material_get(ob, mat_nr); + Material *ma = DEG_is_evaluated_object(ob) ? BKE_object_material_get_eval(ob, mat_nr) : + BKE_object_material_get(ob, mat_nr); bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL; bNode *node = (ntree) ? nodeGetActiveTexture(ntree) : NULL; diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 2c977552e72..ecaba3234a7 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -1050,31 +1050,6 @@ void UV_OT_minimize_stretch(wmOperatorType *ot) /** \name Pack UV Islands Operator * \{ */ -/** - * \warning Since this uses #ParamHandle it doesn't work with non-manifold meshes (see T82637). - * Use #ED_uvedit_pack_islands_multi for a more general solution. - * - * TODO: remove this function, in favor of #ED_uvedit_pack_islands_multi. - */ -static void uvedit_pack_islands_multi(const Scene *scene, - Object **objects, - const uint objects_len, - const UnwrapOptions *options, - bool rotate, - bool ignore_pinned) -{ - ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, options); - GEO_uv_parametrizer_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned); - GEO_uv_parametrizer_flush(handle); - GEO_uv_parametrizer_delete(handle); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); - WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data); - } -} - /* Packing targets. */ enum { PACK_UDIM_SRC_CLOSEST = 0, @@ -1119,16 +1094,22 @@ static int pack_islands_exec(bContext *C, wmOperator *op) const bool use_udim_params = ED_uvedit_udim_params_from_image_space( sima, use_active, &udim_params); - struct UVPackIsland_Params params = { + const struct UVPackIsland_Params pack_island_params = { .rotate = RNA_boolean_get(op->ptr, "rotate"), - .only_selected_uvs = true, - .only_selected_faces = true, - .correct_aspect = true, + .only_selected_uvs = options.only_selected_uvs, + .only_selected_faces = options.only_selected_faces, + .use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams, + .correct_aspect = options.correct_aspect, + .ignore_pinned = false, .margin_method = RNA_enum_get(op->ptr, "margin_method"), .margin = RNA_float_get(op->ptr, "margin"), }; - ED_uvedit_pack_islands_multi( - scene, objects, objects_len, NULL, use_udim_params ? &udim_params : NULL, ¶ms); + ED_uvedit_pack_islands_multi(scene, + objects, + objects_len, + NULL, + use_udim_params ? &udim_params : NULL, + &pack_island_params); MEM_freeN(objects); return OPERATOR_FINISHED; @@ -1889,12 +1870,19 @@ void ED_uvedit_live_unwrap(const Scene *scene, Object **objects, int objects_len .fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0, .correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0, }; - - bool rotate = true; - bool ignore_pinned = true; - uvedit_unwrap_multi(scene, objects, objects_len, &options, NULL); - uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned); + + const struct UVPackIsland_Params pack_island_params = { + .rotate = true, + .only_selected_uvs = options.only_selected_uvs, + .only_selected_faces = options.only_selected_faces, + .use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams, + .correct_aspect = options.correct_aspect, + .ignore_pinned = true, + .margin_method = ED_UVPACK_MARGIN_SCALED, + .margin = scene->toolsettings->uvcalc_margin, + }; + ED_uvedit_pack_islands_multi(scene, objects, objects_len, NULL, NULL, &pack_island_params); } } @@ -1926,8 +1914,6 @@ static int unwrap_exec(bContext *C, wmOperator *op) .correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"), }; - bool rotate = true; - bool ignore_pinned = true; if (CTX_wm_space_image(C)) { /* Inside the UV Editor, only unwrap selected UVs. */ options.only_selected_uvs = true; @@ -2032,7 +2018,18 @@ static int unwrap_exec(bContext *C, wmOperator *op) .count_failed = 0, }; uvedit_unwrap_multi(scene, objects, objects_len, &options, &result_info); - uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned); + + const struct UVPackIsland_Params pack_island_params = { + .rotate = true, + .only_selected_uvs = options.only_selected_uvs, + .only_selected_faces = options.only_selected_faces, + .use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams, + .correct_aspect = options.correct_aspect, + .ignore_pinned = true, + .margin_method = RNA_enum_get(op->ptr, "margin_method"), + .margin = RNA_float_get(op->ptr, "margin"), + }; + ED_uvedit_pack_islands_multi(scene, objects, objects_len, NULL, NULL, &pack_island_params); MEM_freeN(objects); diff --git a/source/blender/geometry/intern/fillet_curves.cc b/source/blender/geometry/intern/fillet_curves.cc index 1bbbee6edef..2479458f88d 100644 --- a/source/blender/geometry/intern/fillet_curves.cc +++ b/source/blender/geometry/intern/fillet_curves.cc @@ -148,12 +148,14 @@ static float limit_radius(const float3 &position_prev, const float displacement_prev = radius_prev * std::tan(angle_prev / 2.0f); const float segment_length_prev = math::distance(position, position_prev); const float total_displacement_prev = displacement_prev + displacement; - const float factor_prev = std::clamp(segment_length_prev / total_displacement_prev, 0.0f, 1.0f); + const float factor_prev = std::clamp( + safe_divide(segment_length_prev, total_displacement_prev), 0.0f, 1.0f); const float displacement_next = radius_next * std::tan(angle_next / 2.0f); const float segment_length_next = math::distance(position, position_next); const float total_displacement_next = displacement_next + displacement; - const float factor_next = std::clamp(segment_length_next / total_displacement_next, 0.0f, 1.0f); + const float factor_next = std::clamp( + safe_divide(segment_length_next, total_displacement_next), 0.0f, 1.0f); return radius * std::min(factor_prev, factor_next); } diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 5a1e0cde1d8..58b1cd0a50b 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -282,6 +282,8 @@ set(GLSL_SRC shaders/gpu_shader_2D_image_vert.glsl shaders/gpu_shader_2D_image_rect_vert.glsl shaders/gpu_shader_2D_image_multi_rect_vert.glsl + shaders/gpu_shader_icon_frag.glsl + shaders/gpu_shader_icon_vert.glsl shaders/gpu_shader_image_frag.glsl shaders/gpu_shader_image_desaturate_frag.glsl shaders/gpu_shader_image_overlays_merge_frag.glsl @@ -349,6 +351,7 @@ set(GLSL_SRC shaders/compositor/compositor_morphological_distance_feather.glsl shaders/compositor/compositor_morphological_distance_threshold.glsl shaders/compositor/compositor_morphological_step.glsl + shaders/compositor/compositor_normalize.glsl shaders/compositor/compositor_parallel_reduction.glsl shaders/compositor/compositor_projector_lens_distortion.glsl shaders/compositor/compositor_realize_on_domain.glsl @@ -357,6 +360,8 @@ set(GLSL_SRC shaders/compositor/compositor_split_viewer.glsl shaders/compositor/compositor_symmetric_blur.glsl shaders/compositor/compositor_symmetric_separable_blur.glsl + shaders/compositor/compositor_tone_map_photoreceptor.glsl + shaders/compositor/compositor_tone_map_simple.glsl shaders/compositor/library/gpu_shader_compositor_alpha_over.glsl shaders/compositor/library/gpu_shader_compositor_blur_common.glsl @@ -606,6 +611,7 @@ set(SRC_SHADER_CREATE_INFOS shaders/infos/gpu_shader_3D_smooth_color_info.hh shaders/infos/gpu_shader_3D_uniform_color_info.hh shaders/infos/gpu_shader_gpencil_stroke_info.hh + shaders/infos/gpu_shader_icon_info.hh shaders/infos/gpu_shader_instance_varying_color_varying_size_info.hh shaders/infos/gpu_shader_keyframe_shape_info.hh shaders/infos/gpu_shader_line_dashed_uniform_color_info.hh @@ -631,6 +637,7 @@ set(SRC_SHADER_CREATE_INFOS shaders/compositor/infos/compositor_morphological_distance_info.hh shaders/compositor/infos/compositor_morphological_distance_threshold_info.hh shaders/compositor/infos/compositor_morphological_step_info.hh + shaders/compositor/infos/compositor_normalize_info.hh shaders/compositor/infos/compositor_parallel_reduction_info.hh shaders/compositor/infos/compositor_projector_lens_distortion_info.hh shaders/compositor/infos/compositor_realize_on_domain_info.hh @@ -639,6 +646,8 @@ set(SRC_SHADER_CREATE_INFOS shaders/compositor/infos/compositor_split_viewer_info.hh shaders/compositor/infos/compositor_symmetric_blur_info.hh shaders/compositor/infos/compositor_symmetric_separable_blur_info.hh + shaders/compositor/infos/compositor_tone_map_photoreceptor_info.hh + shaders/compositor/infos/compositor_tone_map_simple_info.hh ) set(SRC_SHADER_CREATE_INFOS_MTL diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h index b59ea9e55d2..ac82774039a 100644 --- a/source/blender/gpu/GPU_context.h +++ b/source/blender/gpu/GPU_context.h @@ -21,6 +21,8 @@ extern "C" { * automatically initializes the back-end, and #GPU_context_discard frees it when there * are no more contexts. */ bool GPU_backend_supported(void); +void GPU_backend_type_selection_set(const eGPUBackendType backend); +eGPUBackendType GPU_backend_type_selection_get(void); eGPUBackendType GPU_backend_get_type(void); /** Opaque type hiding blender::gpu::Context. */ diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 3f35db42eb9..1148207fc57 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -209,6 +209,10 @@ typedef enum eGPUBuiltinShader { GPU_SHADER_KEYFRAME_SHAPE, GPU_SHADER_SIMPLE_LIGHTING, /** + * Draw an icon, leaving a semi-transparent rectangle on top of the icon. + */ + GPU_SHADER_ICON, + /** * Take a 2D position and color for each vertex with linear interpolation in window space. * * \param color: in vec4 diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc index 48d7b2019c5..f6b88c4231c 100644 --- a/source/blender/gpu/intern/gpu_context.cc +++ b/source/blender/gpu/intern/gpu_context.cc @@ -223,9 +223,19 @@ void GPU_render_step() /* NOTE: To enable Metal API, we need to temporarily change this to `GPU_BACKEND_METAL`. * Until a global switch is added, Metal also needs to be enabled in GHOST_ContextCGL: * `m_useMetalForRendering = true`. */ -static const eGPUBackendType g_backend_type = GPU_BACKEND_OPENGL; +static eGPUBackendType g_backend_type = GPU_BACKEND_OPENGL; static GPUBackend *g_backend = nullptr; +void GPU_backend_type_selection_set(const eGPUBackendType backend) +{ + g_backend_type = backend; +} + +eGPUBackendType GPU_backend_type_selection_get() +{ + return g_backend_type; +} + bool GPU_backend_supported(void) { switch (g_backend_type) { diff --git a/source/blender/gpu/intern/gpu_framebuffer_private.hh b/source/blender/gpu/intern/gpu_framebuffer_private.hh index 76e816e7f65..5afcc102e44 100644 --- a/source/blender/gpu/intern/gpu_framebuffer_private.hh +++ b/source/blender/gpu/intern/gpu_framebuffer_private.hh @@ -95,11 +95,6 @@ class FrameBuffer { #endif public: - /* Reference of a pointer that needs to be cleaned when deallocating the frame-buffer. - * Points to #BPyGPUFrameBuffer::fb */ - void **ref = nullptr; - - public: FrameBuffer(const char *name); virtual ~FrameBuffer(); diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc index 3b4accf9cc5..81c0a65bb7c 100644 --- a/source/blender/gpu/intern/gpu_immediate.cc +++ b/source/blender/gpu/intern/gpu_immediate.cc @@ -45,7 +45,7 @@ void immBindShader(GPUShader *shader) BLI_assert(imm->shader == nullptr); imm->shader = shader; - imm->builtin_shader_bound = GPU_SHADER_TEXT; /* Default value. */ + imm->builtin_shader_bound = std::nullopt; if (!imm->vertex_format.packed) { VertexFormat_pack(&imm->vertex_format); @@ -125,9 +125,12 @@ static void wide_line_workaround_start(GPUPrimType prim_type) /* No need to change the shader. */ return; } + if (!imm->builtin_shader_bound) { + return; + } eGPUBuiltinShader polyline_sh; - switch (imm->builtin_shader_bound) { + switch (*imm->builtin_shader_bound) { case GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR: polyline_sh = GPU_SHADER_3D_POLYLINE_CLIPPED_UNIFORM_COLOR; break; @@ -180,8 +183,8 @@ static void wide_line_workaround_end() } immUnbindProgram(); - immBindBuiltinProgram(imm->prev_builtin_shader); - imm->prev_builtin_shader = GPU_SHADER_TEXT; + immBindBuiltinProgram(*imm->prev_builtin_shader); + imm->prev_builtin_shader = std::nullopt; } } diff --git a/source/blender/gpu/intern/gpu_immediate_private.hh b/source/blender/gpu/intern/gpu_immediate_private.hh index 74ebbdc7ae3..c4e11e7082b 100644 --- a/source/blender/gpu/intern/gpu_immediate_private.hh +++ b/source/blender/gpu/intern/gpu_immediate_private.hh @@ -9,6 +9,8 @@ #pragma once +#include <optional> + #include "GPU_batch.h" #include "GPU_primitive.h" #include "GPU_shader.h" @@ -42,9 +44,9 @@ class Immediate { /** Wide Line workaround. */ /** Previously bound shader to restore after drawing. */ - eGPUBuiltinShader prev_builtin_shader = GPU_SHADER_TEXT; - /** Builtin shader index. Used to test if the workaround can be done. */ - eGPUBuiltinShader builtin_shader_bound = GPU_SHADER_TEXT; + std::optional<eGPUBuiltinShader> prev_builtin_shader; + /** Builtin shader index. Used to test if the line width workaround can be done. */ + std::optional<eGPUBuiltinShader> builtin_shader_bound; /** Uniform color: Kept here to update the wide-line shader just before #immBegin. */ float uniform_color[4]; diff --git a/source/blender/gpu/intern/gpu_shader_builder.cc b/source/blender/gpu/intern/gpu_shader_builder.cc index 3aa2963ecd0..abb45ca074a 100644 --- a/source/blender/gpu/intern/gpu_shader_builder.cc +++ b/source/blender/gpu/intern/gpu_shader_builder.cc @@ -15,6 +15,8 @@ #include "GPU_init_exit.h" #include "gpu_shader_create_info_private.hh" +#include "BLI_vector.hh" + #include "CLG_log.h" namespace blender::gpu::shader_builder { @@ -41,6 +43,22 @@ void ShaderBuilder::init() CLG_init(); GHOST_GLSettings glSettings = {0}; + switch (GPU_backend_type_selection_get()) { + case GPU_BACKEND_OPENGL: + glSettings.context_type = GHOST_kDrawingContextTypeOpenGL; + break; + +#ifdef WITH_METAL_BACKEND + case GPU_BACKEND_METAL: + glSettings.context_type = GHOST_kDrawingContextTypeMetal; + break; +#endif + + default: + BLI_assert_unreachable(); + break; + } + ghost_system_ = GHOST_CreateSystem(); ghost_context_ = GHOST_CreateOpenGLContext(ghost_system_, glSettings); GHOST_ActivateOpenGLContext(ghost_context_); @@ -73,13 +91,32 @@ int main(int argc, const char *argv[]) int exit_code = 0; - blender::gpu::shader_builder::ShaderBuilder builder; - builder.init(); - if (!builder.bake_create_infos()) { - exit_code = 1; + struct NamedBackend { + std::string name; + eGPUBackendType backend; + }; + + blender::Vector<NamedBackend> backends_to_validate; + backends_to_validate.append({"OpenGL", GPU_BACKEND_OPENGL}); +#ifdef WITH_METAL_BACKEND + backends_to_validate.append({"Metal", GPU_BACKEND_METAL}); +#endif + for (NamedBackend &backend : backends_to_validate) { + GPU_backend_type_selection_set(backend.backend); + if (!GPU_backend_supported()) { + printf("%s isn't supported on this platform. Shader compilation is skipped\n", + backend.name.c_str()); + continue; + } + blender::gpu::shader_builder::ShaderBuilder builder; + builder.init(); + if (!builder.bake_create_infos()) { + printf("Shader compilation failed for %s backend\n", backend.name.c_str()); + exit_code = 1; + } + builder.exit(); } - builder.exit(); - exit(exit_code); + exit(exit_code); return exit_code; } diff --git a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc index 7a06ede5c6d..65bda7ba858 100644 --- a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc +++ b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc @@ -46,6 +46,15 @@ void IMB_freeImBuf(ImBuf * /*ibuf*/) BLI_assert_unreachable(); } +struct ImBuf *IMB_allocImBuf(unsigned int /*x*/, + unsigned int /*y*/, + unsigned char /*planes*/, + unsigned int /*flags*/) +{ + BLI_assert_unreachable(); + return nullptr; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/gpu/intern/gpu_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c index 8a6586e06f6..470643ba863 100644 --- a/source/blender/gpu/intern/gpu_shader_builtin.c +++ b/source/blender/gpu/intern/gpu_shader_builtin.c @@ -153,6 +153,11 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { .create_info = "gpu_shader_2D_diag_stripes", }, + [GPU_SHADER_ICON] = + { + .name = "GPU_SHADER_ICON", + .create_info = "gpu_shader_icon", + }, [GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE] = { .name = "GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE", diff --git a/source/blender/gpu/metal/mtl_batch.mm b/source/blender/gpu/metal/mtl_batch.mm index e9804d4be77..988fb9b793b 100644 --- a/source/blender/gpu/metal/mtl_batch.mm +++ b/source/blender/gpu/metal/mtl_batch.mm @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /** \file * \ingroup gpu @@ -68,7 +69,7 @@ void MTLBatch::MTLVertexDescriptorCache::vertex_descriptor_cache_ensure() } } - /* Initialise cache if not ready. */ + /* Initialize cache if not ready. */ if (cache_context_ == nullptr) { this->vertex_descriptor_cache_init(MTLContext::get()); } @@ -188,7 +189,7 @@ int MTLBatch::prepare_vertex_binding(MTLVertBuf *verts, buffer_stride); } else { - /* Ensure stride is correct for de-interlevaed attributes. */ + /* Ensure stride is correct for de-interleaved attributes. */ desc.vertex_descriptor.buffer_layouts[buffer_index].stride = buffer_stride; } @@ -278,7 +279,7 @@ int MTLBatch::prepare_vertex_binding(MTLVertBuf *verts, * elements). * * Certain conversion cannot be performed however, and in these cases, we need to - * instruct the shader to generate a specialised version with a conversion routine upon + * instruct the shader to generate a specialized version with a conversion routine upon * attribute read. * - This handles cases such as conversion between types e.g. Integer to float without * normalization. @@ -310,7 +311,7 @@ int MTLBatch::prepare_vertex_binding(MTLVertBuf *verts, * This then controls how a given attribute is interpreted. The data will be read * as specified and then converted appropriately to the correct form. * - * e.g. if `GPU_FETCH_INT_TO_FLOAT` is specified, the specialised read-routine + * e.g. if `GPU_FETCH_INT_TO_FLOAT` is specified, the specialized read-routine * in the shader will read the data as an int, and cast this to floating point * representation. (Rather than reading the source data as float). * @@ -403,7 +404,7 @@ id<MTLRenderCommandEncoder> MTLBatch::bind(uint v_first, uint v_count, uint i_fi active_shader_ = (shader) ? static_cast<MTLShader *>(unwrap(shader)) : nullptr; if (active_shader_ == nullptr || !active_shader_->is_valid()) { - /* Skip drawing if there is no vaid Metal shader. + /* Skip drawing if there is no valid Metal shader. * This will occur if the path through which the shader is prepared * is invalid (e.g. Python without create-info), or, the source shader uses a geometry pass. */ BLI_assert_msg(false, "No valid Metal shader!"); @@ -455,7 +456,7 @@ id<MTLRenderCommandEncoder> MTLBatch::bind(uint v_first, uint v_count, uint i_fi /* Fetch RenderPassState to enable resource binding for active pass. */ MTLRenderPassState &rps = ctx->main_command_buffer.get_render_pass_state(); - /* Debug Check: Ensure Framebuffer instance is not dirty. */ + /* Debug Check: Ensure Frame-buffer instance is not dirty. */ BLI_assert(!ctx->main_command_buffer.get_active_framebuffer()->get_dirty()); /* Bind Shader. */ @@ -495,8 +496,8 @@ id<MTLRenderCommandEncoder> MTLBatch::bind(uint v_first, uint v_count, uint i_fi if (mtl_elem != nullptr) { - /* Fetch index buffer. This function can situationally return an optimised - * index buffer of a different primtiive type. If this is the case, `final_prim_type` + /* Fetch index buffer. This function can situationally return an optimized + * index buffer of a different primitive type. If this is the case, `final_prim_type` * and `v_count` will be updated with the new format. * NOTE: For indexed rendering, v_count represents the number of indices. */ idx_buffer = mtl_elem->get_index_buffer(final_prim_type, v_count); @@ -594,8 +595,10 @@ void MTLBatch::prepare_vertex_descriptor_and_bindings( desc.reset_vertex_descriptor(); /* Fetch Vertex and Instance Buffers. */ - Span<MTLVertBuf *> mtl_verts(reinterpret_cast<MTLVertBuf **>(this->verts), GPU_BATCH_VBO_MAX_LEN); - Span<MTLVertBuf *> mtl_inst(reinterpret_cast<MTLVertBuf **>(this->inst), GPU_BATCH_INST_VBO_MAX_LEN); + Span<MTLVertBuf *> mtl_verts(reinterpret_cast<MTLVertBuf **>(this->verts), + GPU_BATCH_VBO_MAX_LEN); + Span<MTLVertBuf *> mtl_inst(reinterpret_cast<MTLVertBuf **>(this->inst), + GPU_BATCH_INST_VBO_MAX_LEN); /* SSBO Vertex fetch also passes vertex descriptor information into the shader. */ if (active_shader_->get_uses_ssbo_vertex_fetch()) { @@ -671,7 +674,7 @@ void MTLBatch::prepare_vertex_descriptor_and_bindings( } } - /* Extract Vertex attribues (First-bound vertex buffer takes priority). */ + /* Extract Vertex attributes (First-bound vertex buffer takes priority). */ for (int v = 0; v < GPU_BATCH_VBO_MAX_LEN; v++) { if (mtl_verts[v] != NULL) { MTL_LOG_INFO(" -- [Batch] Checking bindings for bound vertex buffer %p\n", mtl_verts[v]); @@ -829,7 +832,7 @@ void MTLBatch::draw_advanced(int v_first, int v_count, int i_first, int i_count) "Index offset is not 2/4-byte aligned as per METAL spec"); /* Fetch index buffer. May return an index buffer of a differing format, - * if index buffer optimisation is used. In these cases, final_prim_type and + * if index buffer optimization is used. In these cases, final_prim_type and * index_count get updated with the new properties. */ GPUPrimType final_prim_type = this->prim_type; uint index_count = v_count; diff --git a/source/blender/gpu/metal/mtl_drawlist.mm b/source/blender/gpu/metal/mtl_drawlist.mm index 76e2abb4ea6..99194d2b72c 100644 --- a/source/blender/gpu/metal/mtl_drawlist.mm +++ b/source/blender/gpu/metal/mtl_drawlist.mm @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /** \file * \ingroup gpu * @@ -151,7 +153,7 @@ void MTLDrawList::submit() { /* Metal does not support MDI from the host side, but we still benefit from only executing the * batch bind a single time, rather than per-draw. - * NOTE(Metal): Consider using MTLIndirectCommandBuffer to achieve similar behaviour. */ + * NOTE(Metal): Consider using #MTLIndirectCommandBuffer to achieve similar behavior. */ if (command_len_ == 0) { return; } @@ -192,12 +194,12 @@ void MTLDrawList::submit() /* Common properties. */ MTLPrimitiveType mtl_prim_type = gpu_prim_type_to_metal(batch_->prim_type); - /* Execute multidraw indirect. */ + /* Execute multi-draw indirect. */ if (can_use_MDI && false) { /* Metal Doesn't support MDI -- Singular Indirect draw calls are supported, - * but Multidraw is not. - * TODO(Metal): Consider using IndirectCommandBuffers to provide similar - * behaviour. */ + * but Multi-draw is not. + * TODO(Metal): Consider using #IndirectCommandBuffers to provide similar + * behavior. */ } else { @@ -214,7 +216,7 @@ void MTLDrawList::submit() uint32_t index_count = cmd->indexCount; /* Fetch index buffer. May return an index buffer of a differing format, - * if index buffer optimisation is used. In these cases, mtl_prim_type and + * if index buffer optimization is used. In these cases, mtl_prim_type and * index_count get updated with the new properties. */ GPUPrimType final_prim_type = batch_->prim_type; id<MTLBuffer> index_buffer = mtl_elem->get_index_buffer(final_prim_type, index_count); diff --git a/source/blender/gpu/metal/mtl_texture.mm b/source/blender/gpu/metal/mtl_texture.mm index 4931f8a4f52..29dcc8d32ee 100644 --- a/source/blender/gpu/metal/mtl_texture.mm +++ b/source/blender/gpu/metal/mtl_texture.mm @@ -1510,7 +1510,7 @@ bool gpu::MTLTexture::init_internal(GPUVertBuf *vbo) texture_descriptor_.mipmapLevelCount = mtl_max_mips_; texture_descriptor_.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite | - MTLTextureUsagePixelFormatView; /* TODO(Metal): Optimise usage flags. */ + MTLTextureUsagePixelFormatView; /* TODO(Metal): Optimize usage flags. */ texture_descriptor_.storageMode = [source_buffer storageMode]; texture_descriptor_.sampleCount = 1; texture_descriptor_.cpuCacheMode = [source_buffer cpuCacheMode]; diff --git a/source/blender/gpu/opengl/gl_batch.cc b/source/blender/gpu/opengl/gl_batch.cc index ff8867fe3e6..28105e326ee 100644 --- a/source/blender/gpu/opengl/gl_batch.cc +++ b/source/blender/gpu/opengl/gl_batch.cc @@ -272,8 +272,8 @@ void GLBatch::bind(int i_first) #if GPU_TRACK_INDEX_RANGE /* Can be removed if GL 4.3 is required. */ - if (!GLContext::fixed_restart_index_support && (elem != nullptr)) { - glPrimitiveRestartIndex(this->elem_()->restart_index()); + if (!GLContext::fixed_restart_index_support) { + glPrimitiveRestartIndex((elem != nullptr) ? this->elem_()->restart_index() : 0xFFFFFFFFu); } #endif diff --git a/source/blender/gpu/opengl/gl_shader_interface.cc b/source/blender/gpu/opengl/gl_shader_interface.cc index c9432fca561..ef97d74bf81 100644 --- a/source/blender/gpu/opengl/gl_shader_interface.cc +++ b/source/blender/gpu/opengl/gl_shader_interface.cc @@ -200,6 +200,9 @@ static Type gpu_type_from_gl_type(int gl_type) GLShaderInterface::GLShaderInterface(GLuint program) { + GLuint last_program; + glGetIntegerv(GL_CURRENT_PROGRAM, (GLint *)&last_program); + /* Necessary to make #glUniform works. */ glUseProgram(program); @@ -385,6 +388,8 @@ GLShaderInterface::GLShaderInterface(GLuint program) // this->debug_print(); this->sort_inputs(); + + glUseProgram(last_program); } GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateInfo &info) @@ -442,6 +447,9 @@ GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateI uint32_t name_buffer_offset = 0; /* Necessary to make #glUniform works. TODO(fclem) Remove. */ + GLuint last_program; + glGetIntegerv(GL_CURRENT_PROGRAM, (GLint *)&last_program); + glUseProgram(program); /* Attributes */ @@ -552,6 +560,8 @@ GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateI this->sort_inputs(); // this->debug_print(); + + glUseProgram(last_program); } GLShaderInterface::~GLShaderInterface() diff --git a/source/blender/gpu/shaders/compositor/compositor_blur.glsl b/source/blender/gpu/shaders/compositor/compositor_blur.glsl index 4f981c84f59..c7ac620f99b 100644 --- a/source/blender/gpu/shaders/compositor/compositor_blur.glsl +++ b/source/blender/gpu/shaders/compositor/compositor_blur.glsl @@ -18,13 +18,24 @@ vec4 load_input(ivec2 texel) } /* Given the texel in the range [-radius, radius] in both axis, load the appropriate weight from - * the weights texture, where the texel (0, 0) is considered the center of weights texture. */ + * the weights texture, where the given texel (0, 0) corresponds the center of weights texture. + * Note that we load the weights texture inverted along both directions to maintain the shape of + * the weights if it was not symmetrical. To understand why inversion makes sense, consider a 1D + * weights texture whose right half is all ones and whose left half is all zeros. Further, consider + * that we are blurring a single white pixel on a black background. When computing the value of a + * pixel that is to the right of the white pixel, the white pixel will be in the left region of the + * search window, and consequently, without inversion, a zero will be sampled from the left side of + * the weights texture and result will be zero. However, what we expect is that pixels to the right + * of the white pixel will be white, that is, they should sample a weight of 1 from the right side + * of the weights texture, hence the need for inversion. */ vec4 load_weight(ivec2 texel) { - /* Add the radius to transform the texel into the range [0, radius * 2], then divide by the upper - * bound plus one to transform the texel into the normalized range [0, 1] needed to sample the - * weights sampler. Finally, also add 0.5 to sample at the center of the pixels. */ - return texture(weights_tx, (texel + vec2(radius + 0.5)) / (radius * 2 + 1)); + /* Add the radius to transform the texel into the range [0, radius * 2], with an additional 0.5 + * to sample at the center of the pixels, then divide by the upper bound plus one to transform + * the texel into the normalized range [0, 1] needed to sample the weights sampler. Finally, + * invert the textures coordinates by subtracting from 1 to maintain the shape of the weights as + * mentioned in the function description. */ + return texture(weights_tx, 1.0 - ((texel + vec2(radius + 0.5)) / (radius * 2 + 1))); } void main() diff --git a/source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl b/source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl index e7e5aac12a5..9383bbf9825 100644 --- a/source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl +++ b/source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl @@ -2,7 +2,16 @@ #pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) /* Given the texel in the range [-radius, radius] in both axis, load the appropriate weight from - * the weights texture, where the texel (0, 0) is considered the center of weights texture. */ + * the weights texture, where the given texel (0, 0) corresponds the center of weights texture. + * Note that we load the weights texture inverted along both directions to maintain the shape of + * the weights if it was not symmetrical. To understand why inversion makes sense, consider a 1D + * weights texture whose right half is all ones and whose left half is all zeros. Further, consider + * that we are blurring a single white pixel on a black background. When computing the value of a + * pixel that is to the right of the white pixel, the white pixel will be in the left region of the + * search window, and consequently, without inversion, a zero will be sampled from the left side of + * the weights texture and result will be zero. However, what we expect is that pixels to the right + * of the white pixel will be white, that is, they should sample a weight of 1 from the right side + * of the weights texture, hence the need for inversion. */ vec4 load_weight(ivec2 texel, float radius) { /* The center zero texel is always assigned a unit weight regardless of the corresponding weight @@ -12,10 +21,12 @@ vec4 load_weight(ivec2 texel, float radius) return vec4(1.0); } - /* Add the radius to transform the texel into the range [0, radius * 2], then divide by the upper - * bound plus one to transform the texel into the normalized range [0, 1] needed to sample the - * weights sampler. Finally, also add 0.5 to sample at the center of the pixels. */ - return texture(weights_tx, (texel + vec2(radius + 0.5)) / (radius * 2 + 1)); + /* Add the radius to transform the texel into the range [0, radius * 2], with an additional 0.5 + * to sample at the center of the pixels, then divide by the upper bound plus one to transform + * the texel into the normalized range [0, 1] needed to sample the weights sampler. Finally, + * invert the textures coordinates by subtracting from 1 to maintain the shape of the weights as + * mentioned in the function description. */ + return texture(weights_tx, 1.0 - ((texel + vec2(radius + 0.5)) / (radius * 2 + 1))); } void main() diff --git a/source/blender/gpu/shaders/compositor/compositor_normalize.glsl b/source/blender/gpu/shaders/compositor/compositor_normalize.glsl new file mode 100644 index 00000000000..53dfeb01730 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/compositor_normalize.glsl @@ -0,0 +1,10 @@ +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) + +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + float value = texture_load(input_tx, texel).x; + float normalized_value = (value - minimum) * scale; + float clamped_value = clamp(normalized_value, 0.0, 1.0); + imageStore(output_img, texel, vec4(clamped_value)); +} diff --git a/source/blender/gpu/shaders/compositor/compositor_tone_map_photoreceptor.glsl b/source/blender/gpu/shaders/compositor/compositor_tone_map_photoreceptor.glsl new file mode 100644 index 00000000000..167006585ca --- /dev/null +++ b/source/blender/gpu/shaders/compositor/compositor_tone_map_photoreceptor.glsl @@ -0,0 +1,22 @@ +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) + +/* Tone mapping based on equation (1) and the trilinear interpolation between equations (6) and (7) + * from Reinhard, Erik, and Kate Devlin. "Dynamic range reduction inspired by photoreceptor + * physiology." IEEE transactions on visualization and computer graphics 11.1 (2005): 13-24. */ +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + + vec4 input_color = texture_load(input_tx, texel); + float input_luminance = dot(input_color.rgb, luminance_coefficients); + + /* Trilinear interpolation between equations (6) and (7) from Reinhard's 2005 paper. */ + vec4 local_adaptation_level = mix(vec4(input_luminance), input_color, chromatic_adaptation); + vec4 adaptation_level = mix(global_adaptation_level, local_adaptation_level, light_adaptation); + + /* Equation (1) from Reinhard's 2005 paper, assuming Vmax is 1. */ + vec4 semi_saturation = pow(intensity * adaptation_level, vec4(contrast)); + vec4 tone_mapped_color = input_color / (input_color + semi_saturation); + + imageStore(output_img, texel, vec4(tone_mapped_color.rgb, input_color.a)); +} diff --git a/source/blender/gpu/shaders/compositor/compositor_tone_map_simple.glsl b/source/blender/gpu/shaders/compositor/compositor_tone_map_simple.glsl new file mode 100644 index 00000000000..ce42d021dd1 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/compositor_tone_map_simple.glsl @@ -0,0 +1,26 @@ +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl) + +/* Tone mapping based on equation (3) from Reinhard, Erik, et al. "Photographic tone reproduction + * for digital images." Proceedings of the 29th annual conference on Computer graphics and + * interactive techniques. 2002. */ +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + + vec4 input_color = texture_load(input_tx, texel); + + /* Equation (2) from Reinhard's 2002 paper. */ + vec4 scaled_color = input_color * luminance_scale; + + /* Equation (3) from Reinhard's 2002 paper, but with the 1 replaced with the blend factor for + * more flexibility. See ToneMapOperation::compute_luminance_scale_blend_factor. */ + vec4 denominator = luminance_scale_blend_factor + scaled_color; + vec4 tone_mapped_color = safe_divide(scaled_color, denominator); + + if (inverse_gamma != 0.0) { + tone_mapped_color = pow(max(tone_mapped_color, vec4(0.0)), vec4(inverse_gamma)); + } + + imageStore(output_img, texel, vec4(tone_mapped_color.rgb, input_color.a)); +} diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_normalize_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_normalize_info.hh new file mode 100644 index 00000000000..02fdc424014 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/infos/compositor_normalize_info.hh @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_normalize) + .local_group_size(16, 16) + .push_constant(Type::FLOAT, "minimum") + .push_constant(Type::FLOAT, "scale") + .sampler(0, ImageType::FLOAT_2D, "input_tx") + .image(0, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .compute_source("compositor_normalize.glsl") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh index 2e661f280af..e2252b14758 100644 --- a/source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh +++ b/source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh @@ -12,14 +12,17 @@ GPU_SHADER_CREATE_INFO(compositor_parallel_reduction_shared) * Sum Reductions. */ -GPU_SHADER_CREATE_INFO(compositor_sum_float_shared) +GPU_SHADER_CREATE_INFO(compositor_sum_shared) .additional_info("compositor_parallel_reduction_shared") - .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") - .define("TYPE", "float") .define("IDENTITY", "vec4(0.0)") - .define("LOAD(value)", "value.x") .define("REDUCE(lhs, rhs)", "lhs + rhs"); +GPU_SHADER_CREATE_INFO(compositor_sum_float_shared) + .additional_info("compositor_sum_shared") + .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .define("TYPE", "float") + .define("LOAD(value)", "value.x"); + GPU_SHADER_CREATE_INFO(compositor_sum_red) .additional_info("compositor_sum_float_shared") .define("INITIALIZE(value)", "value.r") @@ -41,6 +44,20 @@ GPU_SHADER_CREATE_INFO(compositor_sum_luminance) .define("INITIALIZE(value)", "dot(value.rgb, luminance_coefficients)") .do_static_compilation(true); +GPU_SHADER_CREATE_INFO(compositor_sum_log_luminance) + .additional_info("compositor_sum_float_shared") + .push_constant(Type::VEC3, "luminance_coefficients") + .define("INITIALIZE(value)", "log(max(dot(value.rgb, luminance_coefficients), 1e-5))") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_sum_color) + .additional_info("compositor_sum_shared") + .image(0, GPU_RGBA32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .define("TYPE", "vec4") + .define("INITIALIZE(value)", "value") + .define("LOAD(value)", "value") + .do_static_compilation(true); + /* -------------------------------------------------------------------- * Sum Of Squared Difference Reductions. */ @@ -74,3 +91,59 @@ GPU_SHADER_CREATE_INFO(compositor_sum_luminance_squared_difference) .push_constant(Type::VEC3, "luminance_coefficients") .define("INITIALIZE(value)", "pow(dot(value.rgb, luminance_coefficients) - subtrahend, 2.0)") .do_static_compilation(true); + +/* -------------------------------------------------------------------- + * Maximum Reductions. + */ + +GPU_SHADER_CREATE_INFO(compositor_maximum_luminance) + .additional_info("compositor_parallel_reduction_shared") + .typedef_source("common_math_lib.glsl") + .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .push_constant(Type::VEC3, "luminance_coefficients") + .define("TYPE", "float") + .define("IDENTITY", "vec4(FLT_MIN)") + .define("INITIALIZE(value)", "dot(value.rgb, luminance_coefficients)") + .define("LOAD(value)", "value.x") + .define("REDUCE(lhs, rhs)", "max(lhs, rhs)") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_maximum_float_in_range) + .additional_info("compositor_parallel_reduction_shared") + .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .push_constant(Type::FLOAT, "lower_bound") + .push_constant(Type::FLOAT, "upper_bound") + .define("TYPE", "float") + .define("IDENTITY", "vec4(lower_bound)") + .define("INITIALIZE(v)", "((v.x <= upper_bound) && (v.x >= lower_bound)) ? v.x : lower_bound") + .define("LOAD(value)", "value.x") + .define("REDUCE(lhs, rhs)", "((rhs > lhs) && (rhs <= upper_bound)) ? rhs : lhs") + .do_static_compilation(true); + +/* -------------------------------------------------------------------- + * Minimum Reductions. + */ + +GPU_SHADER_CREATE_INFO(compositor_minimum_luminance) + .additional_info("compositor_parallel_reduction_shared") + .typedef_source("common_math_lib.glsl") + .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .push_constant(Type::VEC3, "luminance_coefficients") + .define("TYPE", "float") + .define("IDENTITY", "vec4(FLT_MAX)") + .define("INITIALIZE(value)", "dot(value.rgb, luminance_coefficients)") + .define("LOAD(value)", "value.x") + .define("REDUCE(lhs, rhs)", "min(lhs, rhs)") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_minimum_float_in_range) + .additional_info("compositor_parallel_reduction_shared") + .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .push_constant(Type::FLOAT, "lower_bound") + .push_constant(Type::FLOAT, "upper_bound") + .define("TYPE", "float") + .define("IDENTITY", "vec4(upper_bound)") + .define("INITIALIZE(v)", "((v.x <= upper_bound) && (v.x >= lower_bound)) ? v.x : upper_bound") + .define("LOAD(value)", "value.x") + .define("REDUCE(lhs, rhs)", "((rhs < lhs) && (rhs >= lower_bound)) ? rhs : lhs") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_photoreceptor_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_photoreceptor_info.hh new file mode 100644 index 00000000000..a460c9d58a6 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_photoreceptor_info.hh @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_tone_map_photoreceptor) + .local_group_size(16, 16) + .push_constant(Type::VEC4, "global_adaptation_level") + .push_constant(Type::FLOAT, "contrast") + .push_constant(Type::FLOAT, "intensity") + .push_constant(Type::FLOAT, "chromatic_adaptation") + .push_constant(Type::FLOAT, "light_adaptation") + .push_constant(Type::VEC3, "luminance_coefficients") + .sampler(0, ImageType::FLOAT_2D, "input_tx") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .compute_source("compositor_tone_map_photoreceptor.glsl") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_simple_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_simple_info.hh new file mode 100644 index 00000000000..2b220af9460 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_simple_info.hh @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_tone_map_simple) + .local_group_size(16, 16) + .push_constant(Type::FLOAT, "luminance_scale") + .push_constant(Type::FLOAT, "luminance_scale_blend_factor") + .push_constant(Type::FLOAT, "inverse_gamma") + .sampler(0, ImageType::FLOAT_2D, "input_tx") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .compute_source("compositor_tone_map_simple.glsl") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/gpu_shader_icon_frag.glsl b/source/blender/gpu/shaders/gpu_shader_icon_frag.glsl new file mode 100644 index 00000000000..4452349f23c --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_icon_frag.glsl @@ -0,0 +1,42 @@ +/** + * Draw the icons, leaving a semi-transparent rectangle on top of the icon. + * + * The top-left corner of the rectangle is rounded and drawned with anti-alias. + * The anti-alias is done by transitioning from the outer to the inner radius of + * the rounded corner, and the rectangle sides. + */ + +void main() +{ + /* Top-left rounded corner parameters. */ + const float circle_radius_outer = 0.1; + const float circle_radius_inner = 0.075; + + /** + * Add a bit transparency to see a bit of the icon, without + * getting on the way of readability. */ + const float mask_transparency = 0.25; + + vec2 circle_center = vec2(circle_radius_outer - text_width, 0.5); + fragColor = texture(image, texCoord_interp) * color; + + /* radius in icon space (1 is the icon width). */ + float radius = length(mask_coord_interp - circle_center); + float mask = smoothstep(circle_radius_inner, circle_radius_outer, radius); + + bool lower_half = mask_coord_interp.y < circle_center.y; + bool right_half = mask_coord_interp.x > circle_center.x; + + if (right_half && mask_coord_interp.y < circle_center.y + circle_radius_outer) { + mask = smoothstep(circle_center.y + circle_radius_inner, + circle_center.y + circle_radius_outer, + mask_coord_interp.y); + } + if (lower_half && mask_coord_interp.x > circle_center.x - circle_radius_outer) { + mask = smoothstep(circle_center.x - circle_radius_inner, + circle_center.x - circle_radius_outer, + mask_coord_interp.x); + } + + fragColor = mix(vec4(0.0), fragColor, max(mask_transparency, mask)); +} diff --git a/source/blender/gpu/shaders/gpu_shader_icon_vert.glsl b/source/blender/gpu/shaders/gpu_shader_icon_vert.glsl new file mode 100644 index 00000000000..25f64bfe0b6 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_icon_vert.glsl @@ -0,0 +1,37 @@ +/** + * Simple shader that just draw one icon at the specified location + * does not need any vertex input (producing less call to immBegin/End) + */ + +void main() +{ + vec2 uv; + vec2 co; + + if (gl_VertexID == 0) { + co = rect_geom.xw; + uv = rect_icon.xw; + mask_coord_interp = vec2(0, 1); + } + else if (gl_VertexID == 1) { + co = rect_geom.xy; + uv = rect_icon.xy; + mask_coord_interp = vec2(0, 0); + } + else if (gl_VertexID == 2) { + co = rect_geom.zw; + uv = rect_icon.zw; + mask_coord_interp = vec2(1, 1); + } + else { + co = rect_geom.zy; + uv = rect_icon.zy; + mask_coord_interp = vec2(1, 0); + } + + /* Put origin in lower right corner. */ + mask_coord_interp.x -= 1; + + gl_Position = ModelViewProjectionMatrix * vec4(co, 0.0f, 1.0f); + texCoord_interp = uv; +} diff --git a/source/blender/gpu/shaders/infos/gpu_interface_info.hh b/source/blender/gpu/shaders/infos/gpu_interface_info.hh index d77c65e48a7..060def16f81 100644 --- a/source/blender/gpu/shaders/infos/gpu_interface_info.hh +++ b/source/blender/gpu/shaders/infos/gpu_interface_info.hh @@ -18,3 +18,6 @@ GPU_SHADER_INTERFACE_INFO(smooth_radii_outline_iface, "").smooth(Type::VEC4, "ra GPU_SHADER_INTERFACE_INFO(flat_color_smooth_tex_coord_interp_iface, "") .flat(Type::VEC4, "finalColor") .smooth(Type::VEC2, "texCoord_interp"); +GPU_SHADER_INTERFACE_INFO(smooth_icon_interp_iface, "") + .smooth(Type::VEC2, "texCoord_interp") + .smooth(Type::VEC2, "mask_coord_interp"); diff --git a/source/blender/gpu/shaders/infos/gpu_shader_icon_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_icon_info.hh new file mode 100644 index 00000000000..3d4077bdb09 --- /dev/null +++ b/source/blender/gpu/shaders/infos/gpu_shader_icon_info.hh @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "gpu_interface_info.hh" +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(gpu_shader_icon) + .vertex_out(smooth_icon_interp_iface) + .fragment_out(0, Type::VEC4, "fragColor") + .push_constant(Type::MAT4, "ModelViewProjectionMatrix") + .push_constant(Type::VEC4, "color") + .push_constant(Type::VEC4, "rect_icon") + .push_constant(Type::VEC4, "rect_geom") + .push_constant(Type::FLOAT, "text_width") + .sampler(0, ImageType::FLOAT_2D, "image") + .vertex_source("gpu_shader_icon_vert.glsl") + .fragment_source("gpu_shader_icon_frag.glsl") + .do_static_compilation(true); diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index 8965700c08a..eaa72441fb6 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -498,7 +498,9 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg( rv->anim = anim; get_proxy_filepath(rv->anim, rv->proxy_size, filepath, true); - BLI_make_existing_file(filepath); + if (!BLI_make_existing_file(filepath)) { + return NULL; + } rv->of = avformat_alloc_context(); rv->of->oformat = av_guess_format("avi", NULL, NULL); @@ -905,6 +907,14 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim, } } + if (context->proxy_ctx[0] == NULL && context->proxy_ctx[1] == NULL && + context->proxy_ctx[2] == NULL && context->proxy_ctx[3] == NULL) { + avformat_close_input(&context->iFormatCtx); + avcodec_free_context(&context->iCodecCtx); + MEM_freeN(context); + return NULL; /* Nothing to transcode. */ + } + for (i = 0; i < num_indexers; i++) { if (tcs_in_use & tc_types[i]) { char filepath[FILE_MAX]; diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c index dd509677d8d..5ed6b2b9843 100644 --- a/source/blender/imbuf/intern/util_gpu.c +++ b/source/blender/imbuf/intern/util_gpu.c @@ -174,6 +174,7 @@ static void *imb_gpu_get_data(const ImBuf *ibuf, /* Other colorspace, store as float texture to avoid precision loss. */ data_rect = MEM_mallocN(sizeof(float[4]) * ibuf->x * ibuf->y, __func__); *r_freedata = freedata = true; + is_float_rect = true; if (data_rect == NULL) { return NULL; diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc index f08514dc45c..2531bd62609 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.cc +++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc @@ -763,7 +763,7 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh, std::map<std::string, int> mat_map; bke::MutableAttributeAccessor attributes = new_mesh->attributes_for_write(); bke::SpanAttributeWriter<int> material_indices = - attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE); + attributes.lookup_or_add_for_write_span<int>("material_index", ATTR_DOMAIN_FACE); assign_facesets_to_material_indices(sample_sel, material_indices.span, mat_map); material_indices.finish(); } @@ -823,8 +823,8 @@ void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const ISampleSel { std::map<std::string, int> mat_map; bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); - bke::SpanAttributeWriter<int> material_indices = - attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE); + bke::SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>( + "material_index", ATTR_DOMAIN_FACE); assign_facesets_to_material_indices(sample_sel, material_indices.span, mat_map); material_indices.finish(); utils::assign_materials(bmain, m_object, mat_map); diff --git a/source/blender/io/stl/CMakeLists.txt b/source/blender/io/stl/CMakeLists.txt index 3a21da5c579..f7eb933d198 100644 --- a/source/blender/io/stl/CMakeLists.txt +++ b/source/blender/io/stl/CMakeLists.txt @@ -2,7 +2,7 @@ set(INC . - ./importer + importer ../common ../../blenkernel ../../blenlib diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc index 77c79852141..01db6baeb5c 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.cc +++ b/source/blender/io/usd/intern/usd_reader_mesh.cc @@ -804,8 +804,8 @@ void USDMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const double mot std::map<pxr::SdfPath, int> mat_map; bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); - bke::SpanAttributeWriter<int> material_indices = - attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE); + bke::SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>( + "material_index", ATTR_DOMAIN_FACE); this->assign_facesets_to_material_indices(motionSampleTime, material_indices.span, &mat_map); material_indices.finish(); /* Build material name map if it's not built yet. */ @@ -914,7 +914,7 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh, std::map<pxr::SdfPath, int> mat_map; bke::MutableAttributeAccessor attributes = active_mesh->attributes_for_write(); bke::SpanAttributeWriter<int> material_indices = - attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE); + attributes.lookup_or_add_for_write_span<int>("material_index", ATTR_DOMAIN_FACE); assign_facesets_to_material_indices(motionSampleTime, material_indices.span, &mat_map); material_indices.finish(); } diff --git a/source/blender/io/wavefront_obj/CMakeLists.txt b/source/blender/io/wavefront_obj/CMakeLists.txt index f7958ef4ec6..bfbc715a45f 100644 --- a/source/blender/io/wavefront_obj/CMakeLists.txt +++ b/source/blender/io/wavefront_obj/CMakeLists.txt @@ -2,8 +2,8 @@ set(INC . - ./exporter - ./importer + exporter + importer ../common ../../blenkernel ../../blenlib diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 315bcbd971c..c7962db8198 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -2083,6 +2083,12 @@ typedef enum CMPNodeLevelsChannel { CMP_NODE_LEVLES_LUMINANCE_BT709 = 5, } CMPNodeLevelsChannel; +/* Tone Map Node. Stored in NodeTonemap.type. */ +typedef enum CMPNodeToneMapType { + CMP_NODE_TONE_MAP_SIMPLE = 0, + CMP_NODE_TONE_MAP_PHOTORECEPTOR = 1, +} CMPNodeToneMapType; + /* Plane track deform node. */ enum { diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 16c101c15d3..1776376b8ce 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -473,6 +473,7 @@ typedef struct ImageFormatData { #define R_IMF_IMTYPE_THEORA 33 #define R_IMF_IMTYPE_PSD 34 #define R_IMF_IMTYPE_WEBP 35 +#define R_IMF_IMTYPE_AV1 36 #define R_IMF_IMTYPE_INVALID 255 diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt index 0d04d7df067..50fd51e88a1 100644 --- a/source/blender/makesdna/intern/CMakeLists.txt +++ b/source/blender/makesdna/intern/CMakeLists.txt @@ -116,8 +116,8 @@ blender_add_lib(bf_dna "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") # ----------------------------------------------------------------------------- # Build bf_dna_blenlib library set(INC + .. ../../blenlib - ../../makesdna ../../../../intern/atomic ../../../../intern/guardedalloc ) diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index a5a7fd84203..a4830dfed36 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -201,7 +201,7 @@ set(INC ../../imbuf ../../makesdna ../../modifiers - ../../nodes/ + ../../nodes ../../sequencer ../../simulation ../../windowmanager diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index b986b720447..e4bc3b3ffd3 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -3630,6 +3630,10 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Use Vertex", "Use this brush in grease pencil vertex color mode"); + prop = RNA_def_property(srna, "use_paint_sculpt_curves", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "ob_mode", OB_MODE_SCULPT_CURVES); + RNA_def_property_ui_text(prop, "Use Sculpt", "Use this brush in sculpt curves mode"); + /* texture */ prop = RNA_def_property(srna, "texture_slot", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "BrushTextureSlot"); diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index 4a36443ca42..320ef169ae5 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -9,11 +9,8 @@ #include <stdlib.h> #include "DNA_armature_types.h" -#include "DNA_brush_types.h" -#include "DNA_cachefile_types.h" #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" -#include "DNA_mesh_types.h" #include "DNA_modifier_types.h" #include "DNA_object_force_types.h" #include "DNA_object_types.h" @@ -21,20 +18,13 @@ #include "MEM_guardedalloc.h" -#include "BLI_math.h" -#include "BLI_rand.h" +#include "BLI_math_base.h" +#include "BLI_math_rotation.h" #include "BLI_string_utils.h" #include "BLT_translation.h" #include "BKE_animsys.h" -#include "BKE_data_transfer.h" -#include "BKE_dynamicpaint.h" -#include "BKE_effect.h" -#include "BKE_fluid.h" /* For BKE_fluid_modifier_free & BKE_fluid_modifier_create_type_data */ -#include "BKE_mesh_mapping.h" -#include "BKE_mesh_remap.h" -#include "BKE_multires.h" #include "RNA_access.h" #include "RNA_define.h" diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index a22ed5d1d5c..f437f3b698f 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -328,7 +328,9 @@ void rna_object_vcollayer_name_set(struct PointerRNA *ptr, PointerRNA rna_object_shapekey_index_get(struct ID *id, int value); int rna_object_shapekey_index_set(struct ID *id, PointerRNA value, int current); -void rna_def_object_type_visibility_flags_common(StructRNA *srna, int noteflag); +void rna_def_object_type_visibility_flags_common(StructRNA *srna, + int noteflag, + const char *update_func); int rna_object_type_visibility_icon_get_common(int object_type_exclude_viewport, const int *object_type_exclude_select); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 9252d790261..b1a2c1243b8 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -6020,6 +6020,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) {FFMPEG_MKV, "MKV", 0, "Matroska", ""}, {FFMPEG_FLV, "FLASH", 0, "Flash", ""}, {FFMPEG_WEBM, "WEBM", 0, "WebM", ""}, + {AV_CODEC_ID_AV1, "AV1", 0, "AV1", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -6037,7 +6038,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) {AV_CODEC_ID_PNG, "PNG", 0, "PNG", ""}, {AV_CODEC_ID_QTRLE, "QTRLE", 0, "QT rle / QT Animation", ""}, {AV_CODEC_ID_THEORA, "THEORA", 0, "Theora", ""}, - {AV_CODEC_ID_VP9, "WEBM", 0, "WEBM / VP9", ""}, + {AV_CODEC_ID_VP9, "WEBM", 0, "WebM / VP9", ""}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 5c192b80dc1..b2663b89333 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -990,6 +990,13 @@ static PointerRNA rna_SpaceView3D_region_3d_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_RegionView3D, regiondata); } +static void rna_SpaceView3D_object_type_visibility_update(Main *UNUSED(bmain), + Scene *scene, + PointerRNA *UNUSED(ptr)) +{ + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); +} + static void rna_SpaceView3D_region_quadviews_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { @@ -5086,7 +5093,8 @@ static void rna_def_space_view3d(BlenderRNA *brna) prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_mirror_xr_session_update"); rna_def_object_type_visibility_flags_common(srna, - NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING); + NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, + "rna_SpaceView3D_object_type_visibility_update"); /* Helper for drawing the icon. */ prop = RNA_def_property(srna, "icon_from_show_object_viewport", PROP_INT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c index b3896919275..9790a85e1c8 100644 --- a/source/blender/makesrna/intern/rna_space_api.c +++ b/source/blender/makesrna/intern/rna_space_api.c @@ -119,7 +119,9 @@ void RNA_api_space_text(StructRNA *srna) RNA_def_function_output(func, parm); } -void rna_def_object_type_visibility_flags_common(StructRNA *srna, int noteflag) +void rna_def_object_type_visibility_flags_common(StructRNA *srna, + int noteflag, + const char *update_func) { PropertyRNA *prop; @@ -173,7 +175,7 @@ void rna_def_object_type_visibility_flags_common(StructRNA *srna, int noteflag) RNA_def_property_boolean_negative_sdna( prop, NULL, view_mask_member[mask_index], info[type_index].type_mask); RNA_def_property_ui_text(prop, info[type_index].name, ""); - RNA_def_property_update(prop, noteflag, NULL); + RNA_def_property_update(prop, noteflag, update_func); } } } diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 5b5544120a1..eebe595820e 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -99,13 +99,6 @@ static const EnumPropertyItem event_ndof_type_items[] = { {NDOF_BUTTON_DOMINANT, "NDOF_BUTTON_DOMINANT", 0, "Dominant", ""}, {NDOF_BUTTON_PLUS, "NDOF_BUTTON_PLUS", 0, "Plus", ""}, {NDOF_BUTTON_MINUS, "NDOF_BUTTON_MINUS", 0, "Minus", ""}, -# if 0 /* Never used (converted to keyboard events by GHOST). */ - /* keyboard emulation */ - {NDOF_BUTTON_ESC, "NDOF_BUTTON_ESC", 0, "Esc"}, - {NDOF_BUTTON_ALT, "NDOF_BUTTON_ALT", 0, "Alt"}, - {NDOF_BUTTON_SHIFT, "NDOF_BUTTON_SHIFT", 0, "Shift"}, - {NDOF_BUTTON_CTRL, "NDOF_BUTTON_CTRL", 0, "Ctrl"}, -# endif /* general-purpose buttons */ {NDOF_BUTTON_1, "NDOF_BUTTON_1", 0, "Button 1", ""}, {NDOF_BUTTON_2, "NDOF_BUTTON_2", 0, "Button 2", ""}, @@ -120,6 +113,21 @@ static const EnumPropertyItem event_ndof_type_items[] = { {NDOF_BUTTON_A, "NDOF_BUTTON_A", 0, "Button A", ""}, {NDOF_BUTTON_B, "NDOF_BUTTON_B", 0, "Button B", ""}, {NDOF_BUTTON_C, "NDOF_BUTTON_C", 0, "Button C", ""}, + /* View buttons. */ + {NDOF_BUTTON_V1, "NDOF_BUTTON_V1", 0, "View 1", ""}, + {NDOF_BUTTON_V2, "NDOF_BUTTON_V2", 0, "View 2", ""}, + {NDOF_BUTTON_V3, "NDOF_BUTTON_V3", 0, "View 3", ""}, +# if 0 /* Never used (converted to keyboard events by GHOST). */ + /* keyboard emulation */ + {NDOF_BUTTON_ESC, "NDOF_BUTTON_ESC", 0, "Esc"}, + {NDOF_BUTTON_ENTER, "NDOF_BUTTON_ENTER", 0, "Enter"}, + {NDOF_BUTTON_DELETE, "NDOF_BUTTON_DELETE", 0, "Delete"}, + {NDOF_BUTTON_TAB, "NDOF_BUTTON_TAB", 0, "Tab"}, + {NDOF_BUTTON_SPACE, "NDOF_BUTTON_SPACE", 0, "Space"}, + {NDOF_BUTTON_ALT, "NDOF_BUTTON_ALT", 0, "Alt"}, + {NDOF_BUTTON_SHIFT, "NDOF_BUTTON_SHIFT", 0, "Shift"}, + {NDOF_BUTTON_CTRL, "NDOF_BUTTON_CTRL", 0, "Ctrl"}, +# endif {0, NULL, 0, NULL, NULL}, }; #endif /* RNA_RUNTIME */ diff --git a/source/blender/makesrna/intern/rna_xr.c b/source/blender/makesrna/intern/rna_xr.c index dcfa1bbca51..c803e5dc9a8 100644 --- a/source/blender/makesrna/intern/rna_xr.c +++ b/source/blender/makesrna/intern/rna_xr.c @@ -2052,7 +2052,7 @@ static void rna_def_xr_session_settings(BlenderRNA *brna) "Allow the VR tracking origin to be defined independently of the headset location"); RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL); - rna_def_object_type_visibility_flags_common(srna, NC_WM | ND_XR_DATA_CHANGED); + rna_def_object_type_visibility_flags_common(srna, NC_WM | ND_XR_DATA_CHANGED, NULL); /* Helper for drawing the icon. */ prop = RNA_def_property(srna, "icon_from_show_object_viewport", PROP_INT, PROP_NONE); diff --git a/source/blender/nodes/composite/nodes/node_composite_normalize.cc b/source/blender/nodes/composite/nodes/node_composite_normalize.cc index 21765825468..34fd63e5805 100644 --- a/source/blender/nodes/composite/nodes/node_composite_normalize.cc +++ b/source/blender/nodes/composite/nodes/node_composite_normalize.cc @@ -5,7 +5,9 @@ * \ingroup cmpnodes */ +#include "COM_algorithm_parallel_reduction.hh" #include "COM_node_operation.hh" +#include "COM_utilities.hh" #include "node_composite_util.hh" @@ -15,19 +17,60 @@ namespace blender::nodes::node_composite_normalize_cc { static void cmp_node_normalize_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f); + b.add_input<decl::Float>(N_("Value")) + .default_value(1.0f) + .min(0.0f) + .max(1.0f) + .compositor_domain_priority(0); b.add_output<decl::Float>(N_("Value")); } using namespace blender::realtime_compositor; class NormalizeOperation : public NodeOperation { + private: + /* The normalize operation is specifically designed to normalize Z Depth information. But since Z + * Depth can contain near infinite values, normalization is limited to [-range_, range], meaning + * that values outside of that range will be ignored when computing the maximum and minimum for + * normalization and will eventually be 0 or 1 if they are less than or larger than the range + * respectively. */ + constexpr static float range_ = 10000.0f; + public: using NodeOperation::NodeOperation; void execute() override { - get_input("Value").pass_through(get_result("Value")); + Result &input_image = get_input("Value"); + Result &output_image = get_result("Value"); + if (input_image.is_single_value()) { + input_image.pass_through(output_image); + return; + } + + const float maximum = maximum_float_in_range( + context(), input_image.texture(), -range_, range_); + const float minimum = minimum_float_in_range( + context(), input_image.texture(), -range_, range_); + const float scale = (maximum != minimum) ? (1.0f / (maximum - minimum)) : 0.0f; + + GPUShader *shader = shader_manager().get("compositor_normalize"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1f(shader, "minimum", minimum); + GPU_shader_uniform_1f(shader, "scale", scale); + + 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"); + + compute_dispatch_threads_at_least(shader, domain.size); + + GPU_shader_unbind(); + output_image.unbind_as_image(); + input_image.unbind_as_texture(); } }; diff --git a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc index 2e06ad99df1..d26a01bb3c9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc +++ b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc @@ -5,20 +5,35 @@ * \ingroup cmpnodes */ +#include <cmath> + +#include "BLI_assert.h" +#include "BLI_math_base.hh" +#include "BLI_math_vec_types.hh" +#include "BLI_math_vector.hh" + #include "RNA_access.h" #include "UI_interface.h" #include "UI_resources.h" +#include "IMB_colormanagement.h" + +#include "COM_algorithm_parallel_reduction.hh" #include "COM_node_operation.hh" +#include "COM_utilities.hh" #include "node_composite_util.hh" namespace blender::nodes::node_composite_tonemap_cc { +NODE_STORAGE_FUNCS(NodeTonemap) + static void cmp_node_tonemap_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Color>(N_("Image")) + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(0); b.add_output<decl::Color>(N_("Image")); } @@ -68,7 +83,236 @@ class ToneMapOperation : public NodeOperation { void execute() override { - get_input("Image").pass_through(get_result("Image")); + Result &input_image = get_input("Image"); + Result &output_image = get_result("Image"); + if (input_image.is_single_value()) { + input_image.pass_through(output_image); + return; + } + + switch (get_type()) { + case CMP_NODE_TONE_MAP_SIMPLE: + execute_simple(); + return; + case CMP_NODE_TONE_MAP_PHOTORECEPTOR: + execute_photoreceptor(); + return; + default: + BLI_assert_unreachable(); + return; + } + } + + /* Tone mapping based on equation (3) from Reinhard, Erik, et al. "Photographic tone reproduction + * for digital images." Proceedings of the 29th annual conference on Computer graphics and + * interactive techniques. 2002. */ + void execute_simple() + { + const float luminance_scale = compute_luminance_scale(); + const float luminance_scale_blend_factor = compute_luminance_scale_blend_factor(); + const float gamma = node_storage(bnode()).gamma; + const float inverse_gamma = gamma != 0.0f ? 1.0f / gamma : 0.0f; + + GPUShader *shader = shader_manager().get("compositor_tone_map_simple"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1f(shader, "luminance_scale", luminance_scale); + GPU_shader_uniform_1f(shader, "luminance_scale_blend_factor", luminance_scale_blend_factor); + GPU_shader_uniform_1f(shader, "inverse_gamma", inverse_gamma); + + const Result &input_image = get_input("Image"); + input_image.bind_as_texture(shader, "input_tx"); + + const Domain domain = compute_domain(); + Result &output_image = get_result("Image"); + output_image.allocate_texture(domain); + output_image.bind_as_image(shader, "output_img"); + + compute_dispatch_threads_at_least(shader, domain.size); + + GPU_shader_unbind(); + output_image.unbind_as_image(); + input_image.unbind_as_texture(); + } + + /* Computes the scaling factor in equation (2) from Reinhard's 2002 paper. */ + float compute_luminance_scale() + { + const float geometric_mean = compute_geometric_mean_of_luminance(); + return geometric_mean != 0.0 ? node_storage(bnode()).key / geometric_mean : 0.0f; + } + + /* Computes equation (1) from Reinhard's 2002 paper. However, note that the equation in the paper + * is most likely wrong, and the intention is actually to compute the geometric mean through a + * logscale arithmetic mean, that is, the division should happen inside the exponential function, + * not outside of it. That's because the sum of the log luminance will be a very large negative + * number, whose exponential will almost always be zero, which is unexpected and useless. */ + float compute_geometric_mean_of_luminance() + { + return std::exp(compute_average_log_luminance()); + } + + /* Equation (3) from Reinhard's 2002 paper blends between high luminance scaling for high + * luminance values and low luminance scaling for low luminance values. This is done by adding 1 + * to the denominator, since for low luminance values, the denominator will be close to 1 and for + * high luminance values, the 1 in the denominator will be relatively insignificant. But the + * response of such function is not always ideal, so in this implementation, the 1 was exposed as + * a parameter to the user for more flexibility. */ + float compute_luminance_scale_blend_factor() + { + return node_storage(bnode()).offset; + } + + /* Tone mapping based on equation (1) and the trilinear interpolation between equations (6) and + * (7) from Reinhard, Erik, and Kate Devlin. "Dynamic range reduction inspired by photoreceptor + * physiology." IEEE transactions on visualization and computer graphics 11.1 (2005): 13-24. */ + void execute_photoreceptor() + { + const float4 global_adaptation_level = compute_global_adaptation_level(); + const float contrast = compute_contrast(); + const float intensity = compute_intensity(); + const float chromatic_adaptation = get_chromatic_adaptation(); + const float light_adaptation = get_light_adaptation(); + + GPUShader *shader = shader_manager().get("compositor_tone_map_photoreceptor"); + GPU_shader_bind(shader); + + GPU_shader_uniform_4fv(shader, "global_adaptation_level", global_adaptation_level); + GPU_shader_uniform_1f(shader, "contrast", contrast); + GPU_shader_uniform_1f(shader, "intensity", intensity); + GPU_shader_uniform_1f(shader, "chromatic_adaptation", chromatic_adaptation); + GPU_shader_uniform_1f(shader, "light_adaptation", light_adaptation); + + float luminance_coefficients[3]; + IMB_colormanagement_get_luminance_coefficients(luminance_coefficients); + GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients); + + const Result &input_image = get_input("Image"); + input_image.bind_as_texture(shader, "input_tx"); + + const Domain domain = compute_domain(); + Result &output_image = get_result("Image"); + output_image.allocate_texture(domain); + output_image.bind_as_image(shader, "output_img"); + + compute_dispatch_threads_at_least(shader, domain.size); + + GPU_shader_unbind(); + output_image.unbind_as_image(); + input_image.unbind_as_texture(); + } + + /* Computes the global adaptation level from the trilinear interpolation equations constructed + * from equations (6) and (7) in Reinhard's 2005 paper. */ + float4 compute_global_adaptation_level() + { + const float4 average_color = compute_average_color(); + const float average_luminance = compute_average_luminance(); + const float chromatic_adaptation = get_chromatic_adaptation(); + return math::interpolate(float4(average_luminance), average_color, chromatic_adaptation); + } + + float4 compute_average_color() + { + /* The average color will reduce to zero if chromatic adaptation is zero, so just return zero + * in this case to avoid needlessly computing the average. See the trilinear interpolation + * equations constructed from equations (6) and (7) in Reinhard's 2005 paper. */ + if (get_chromatic_adaptation() == 0.0f) { + return float4(0.0f); + } + + const Result &input = get_input("Image"); + return sum_color(context(), input.texture()) / (input.domain().size.x * input.domain().size.y); + } + + float compute_average_luminance() + { + /* The average luminance will reduce to zero if chromatic adaptation is one, so just return + * zero in this case to avoid needlessly computing the average. See the trilinear interpolation + * equations constructed from equations (6) and (7) in Reinhard's 2005 paper. */ + if (get_chromatic_adaptation() == 1.0f) { + return 0.0f; + } + + float luminance_coefficients[3]; + IMB_colormanagement_get_luminance_coefficients(luminance_coefficients); + const Result &input = get_input("Image"); + float sum = sum_luminance(context(), input.texture(), luminance_coefficients); + return sum / (input.domain().size.x * input.domain().size.y); + } + + /* Computes equation (5) from Reinhard's 2005 paper. */ + float compute_intensity() + { + return std::exp(-node_storage(bnode()).f); + } + + /* If the contrast is not zero, return it, otherwise, a zero contrast denote automatic derivation + * of the contrast value based on equations (2) and (4) from Reinhard's 2005 paper. */ + float compute_contrast() + { + if (node_storage(bnode()).m != 0.0f) { + return node_storage(bnode()).m; + } + + const float log_maximum_luminance = compute_log_maximum_luminance(); + const float log_minimum_luminance = compute_log_minimum_luminance(); + + /* This is merely to guard against zero division later. */ + if (log_maximum_luminance == log_minimum_luminance) { + return 1.0f; + } + + const float average_log_luminance = compute_average_log_luminance(); + const float dynamic_range = log_maximum_luminance - log_minimum_luminance; + const float luminance_key = (log_maximum_luminance - average_log_luminance) / (dynamic_range); + + return 0.3f + 0.7f * std::pow(luminance_key, 1.4f); + } + + float compute_average_log_luminance() + { + const Result &input_image = get_input("Image"); + + float luminance_coefficients[3]; + IMB_colormanagement_get_luminance_coefficients(luminance_coefficients); + const float sum_of_log_luminance = sum_log_luminance( + context(), input_image.texture(), luminance_coefficients); + + return sum_of_log_luminance / (input_image.domain().size.x * input_image.domain().size.y); + } + + float compute_log_maximum_luminance() + { + float luminance_coefficients[3]; + IMB_colormanagement_get_luminance_coefficients(luminance_coefficients); + const float maximum = maximum_luminance( + context(), get_input("Image").texture(), luminance_coefficients); + return std::log(math::max(maximum, 1e-5f)); + } + + float compute_log_minimum_luminance() + { + float luminance_coefficients[3]; + IMB_colormanagement_get_luminance_coefficients(luminance_coefficients); + const float minimum = minimum_luminance( + context(), get_input("Image").texture(), luminance_coefficients); + return std::log(math::max(minimum, 1e-5f)); + } + + float get_chromatic_adaptation() + { + return node_storage(bnode()).c; + } + + float get_light_adaptation() + { + return node_storage(bnode()).a; + } + + CMPNodeToneMapType get_type() + { + return static_cast<CMPNodeToneMapType>(node_storage(bnode()).type); } }; diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc index a433a0df9b0..3e48a9fd923 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc @@ -4,6 +4,7 @@ #include "UI_resources.h" #include "BLI_array.hh" +#include "BLI_array_utils.hh" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -23,15 +24,9 @@ namespace blender::nodes::node_geo_delete_geometry_cc { using blender::bke::CustomDataAttributes; template<typename T> -static void copy_data_based_on_mask(Span<T> data, MutableSpan<T> r_data, IndexMask mask) -{ - for (const int i_out : mask.index_range()) { - r_data[i_out] = data[mask[i_out]]; - } -} - -template<typename T> -static void copy_data_based_on_map(Span<T> src, MutableSpan<T> dst, Span<int> index_map) +static void copy_data_based_on_map(const Span<T> src, + const Span<int> index_map, + MutableSpan<T> dst) { for (const int i_src : index_map.index_range()) { const int i_dst = index_map[i_src]; @@ -55,26 +50,17 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes if (!attribute) { continue; } - /* Only copy if it is on a domain we want. */ if (!domains.contains(attribute.domain)) { continue; } const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); - GSpanAttributeWriter result_attribute = dst_attributes.lookup_or_add_for_write_only_span( attribute_id, attribute.domain, data_type); - if (!result_attribute) { continue; } - - attribute_math::convert_to_static_type(data_type, [&](auto dummy) { - using T = decltype(dummy); - VArraySpan<T> span{attribute.varray.typed<T>()}; - MutableSpan<T> out_span = result_attribute.span.typed<T>(); - out_span.copy_from(span); - }); + attribute.varray.materialize(result_attribute.span.data()); result_attribute.finish(); } } @@ -95,26 +81,19 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin if (!attribute) { continue; } - /* Only copy if it is on a domain we want. */ if (domain != attribute.domain) { continue; } const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); - GSpanAttributeWriter result_attribute = dst_attributes.lookup_or_add_for_write_only_span( attribute_id, attribute.domain, data_type); - if (!result_attribute) { continue; } - attribute_math::convert_to_static_type(data_type, [&](auto dummy) { - using T = decltype(dummy); - VArraySpan<T> span{attribute.varray.typed<T>()}; - MutableSpan<T> out_span = result_attribute.span.typed<T>(); - copy_data_based_on_mask(span, out_span, mask); - }); + array_utils::gather(attribute.varray, mask, result_attribute.span); + result_attribute.finish(); } } @@ -131,16 +110,13 @@ static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind if (!attribute) { continue; } - /* Only copy if it is on a domain we want. */ if (domain != attribute.domain) { continue; } const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); - GSpanAttributeWriter result_attribute = dst_attributes.lookup_or_add_for_write_only_span( attribute_id, attribute.domain, data_type); - if (!result_attribute) { continue; } @@ -149,7 +125,7 @@ static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind using T = decltype(dummy); VArraySpan<T> span{attribute.varray.typed<T>()}; MutableSpan<T> out_span = result_attribute.span.typed<T>(); - copy_data_based_on_map(span, out_span, index_map); + copy_data_based_on_map(span, index_map, out_span); }); result_attribute.finish(); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc index 091337c28cf..95173bd23a5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc @@ -15,6 +15,8 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "DEG_depsgraph_query.h" + #include "node_geometry_util.hh" namespace blender::nodes { @@ -208,6 +210,7 @@ static void geo_node_distribute_points_in_volume_exec(GeoNodeExecParams params) } const VolumeComponent *component = geometry_set.get_component_for_read<VolumeComponent>(); const Volume *volume = component->get_for_read(); + BKE_volume_load(volume, DEG_get_bmain(params.depsgraph())); Vector<float3> positions; diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc index 84e63845b84..9b1c13bf563 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BLI_array_utils.hh" #include "BLI_task.hh" #include "DNA_mesh_types.h" @@ -105,18 +106,6 @@ static void copy_data_based_on_pairs(Span<T> data, } } -/* Copy using the map. */ -template<typename T> -static void copy_data_based_on_new_to_old_map(Span<T> data, - MutableSpan<T> r_data, - const Span<int> new_to_old_map) -{ - for (const int i : r_data.index_range()) { - const int old_i = new_to_old_map[i]; - r_data[i] = data[old_i]; - } -} - /** * Transfers the attributes from the original mesh to the new mesh using the following logic: * - If the attribute was on the face domain it is now on the point domain, and this is true @@ -168,7 +157,6 @@ static void transfer_attributes( src_attribute.varray.type()); GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span( attribute_id, out_domain, data_type); - if (!dst_attribute) { continue; } @@ -177,20 +165,24 @@ static void transfer_attributes( using T = decltype(dummy); VArraySpan<T> span{src_attribute.varray.typed<T>()}; MutableSpan<T> dst_span = dst_attribute.span.typed<T>(); - if (src_attribute.domain == ATTR_DOMAIN_FACE) { - dst_span.take_front(span.size()).copy_from(span); - if (keep_boundaries) { - copy_data_based_on_pairs(span, dst_span, boundary_vertex_to_relevant_face_map); - } - } - else if (src_attribute.domain == ATTR_DOMAIN_POINT) { - copy_data_based_on_vertex_types(span, dst_span, vertex_types, keep_boundaries); - } - else if (src_attribute.domain == ATTR_DOMAIN_EDGE) { - copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_edges_map); - } - else { - copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_face_corners_map); + switch (src_attribute.domain) { + case ATTR_DOMAIN_POINT: + copy_data_based_on_vertex_types(span, dst_span, vertex_types, keep_boundaries); + break; + case ATTR_DOMAIN_EDGE: + array_utils::gather(span, new_to_old_edges_map, dst_span); + break; + case ATTR_DOMAIN_FACE: + dst_span.take_front(span.size()).copy_from(span); + if (keep_boundaries) { + copy_data_based_on_pairs(span, dst_span, boundary_vertex_to_relevant_face_map); + } + break; + case ATTR_DOMAIN_CORNER: + array_utils::gather(span, new_to_old_face_corners_map, dst_span); + break; + default: + BLI_assert_unreachable(); } }); dst_attribute.finish(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc index 70583625a7a..486f900aca5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BLI_array_utils.hh" #include "BLI_map.hh" #include "BLI_noise.hh" #include "BLI_span.hh" @@ -105,16 +106,6 @@ static void threaded_slice_fill(Span<int> offsets, }); } -template<typename T> -static void threaded_mapped_copy(const Span<int> mapping, const Span<T> src, MutableSpan<T> dst) -{ - threading::parallel_for(mapping.index_range(), 512, [&](IndexRange range) { - for (const int i : range) { - dst[i] = src[mapping[i]]; - } - }); -} - static void copy_hashed_ids(const Span<int> src, const int hash, MutableSpan<int> dst) { for (const int i : src.index_range()) { @@ -440,17 +431,17 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set, MutableSpan<T> dst = dst_attribute.span.typed<T>(); switch (out_domain) { - case ATTR_DOMAIN_FACE: - threaded_slice_fill<T>(offsets, selection, src, dst); + case ATTR_DOMAIN_POINT: + array_utils::gather(src, vert_mapping, dst); break; case ATTR_DOMAIN_EDGE: - threaded_mapped_copy<T>(edge_mapping, src, dst); + array_utils::gather(src, edge_mapping, dst); break; - case ATTR_DOMAIN_POINT: - threaded_mapped_copy<T>(vert_mapping, src, dst); + case ATTR_DOMAIN_FACE: + threaded_slice_fill<T>(offsets, selection, src, dst); break; case ATTR_DOMAIN_CORNER: - threaded_mapped_copy<T>(loop_mapping, src, dst); + array_utils::gather(src, loop_mapping, dst); break; default: break; @@ -653,7 +644,7 @@ static void copy_edge_attributes_without_id(GeometrySet &geometry_set, threaded_slice_fill<T>(offsets, selection, src, dst); break; case ATTR_DOMAIN_POINT: - threaded_mapped_copy<T>(point_mapping, src, dst); + array_utils::gather(src, point_mapping, dst); break; default: break; diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc index d348d886ad6..151ba3e59cc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BLI_array_utils.hh" #include "BLI_disjoint_set.hh" #include "BLI_task.hh" #include "BLI_vector_set.hh" @@ -175,24 +176,6 @@ static MPoly new_poly(const int loopstart, const int totloop) return poly; } -template<typename T> void copy_with_indices(MutableSpan<T> dst, Span<T> src, Span<int> indices) -{ - BLI_assert(dst.size() == indices.size()); - for (const int i : dst.index_range()) { - dst[i] = src[indices[i]]; - } -} - -template<typename T> void copy_with_mask(MutableSpan<T> dst, Span<T> src, IndexMask mask) -{ - BLI_assert(dst.size() == mask.size()); - threading::parallel_for(mask.index_range(), 512, [&](const IndexRange range) { - for (const int i : range) { - dst[i] = src[mask[i]]; - } - }); -} - /** * \param get_mix_indices_fn: Returns a Span of indices of the source points to mix for every * result point. @@ -265,26 +248,24 @@ static void extrude_mesh_vertices(Mesh &mesh, } GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( id, meta_data.domain, meta_data.data_type); - attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) { - using T = decltype(dummy); - MutableSpan<T> data = attribute.span.typed<T>(); - switch (attribute.domain) { - case ATTR_DOMAIN_POINT: { - /* New vertices copy the attribute values from their source vertex. */ - copy_with_mask(data.slice(new_vert_range), data.as_span(), selection); - break; - } - case ATTR_DOMAIN_EDGE: { + 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: + 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(); - } - }); + }); + break; + default: + BLI_assert_unreachable(); + } attribute.finish(); return true; @@ -524,13 +505,14 @@ static void extrude_mesh_edges(Mesh &mesh, switch (attribute.domain) { case ATTR_DOMAIN_POINT: { /* New vertices copy the attribute values from their source vertex. */ - copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices); + array_utils::gather( + data.as_span(), new_vert_indices.as_span(), data.slice(new_vert_range)); break; } case ATTR_DOMAIN_EDGE: { /* Edges parallel to original edges copy the edge attributes from the original edges. */ MutableSpan<T> duplicate_data = data.slice(duplicate_edge_range); - copy_with_mask(duplicate_data, data.as_span(), edge_selection); + 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); @@ -910,17 +892,18 @@ static void extrude_mesh_face_regions(Mesh &mesh, switch (attribute.domain) { case ATTR_DOMAIN_POINT: { /* New vertices copy the attributes from their original vertices. */ - copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices); + array_utils::gather( + data.as_span(), new_vert_indices.as_span(), data.slice(new_vert_range)); break; } case ATTR_DOMAIN_EDGE: { /* Edges parallel to original edges copy the edge attributes from the original edges. */ MutableSpan<T> boundary_data = data.slice(boundary_edge_range); - copy_with_indices(boundary_data, data.as_span(), boundary_edge_indices); + array_utils::gather(data.as_span(), boundary_edge_indices.as_span(), boundary_data); /* Edges inside of face regions also just duplicate their source data. */ MutableSpan<T> new_inner_data = data.slice(new_inner_edge_range); - copy_with_indices(new_inner_data, data.as_span(), new_inner_edge_indices); + 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); @@ -932,8 +915,8 @@ static void extrude_mesh_face_regions(Mesh &mesh, case ATTR_DOMAIN_FACE: { /* New faces on the side of extrusions get the values from the corresponding selected * face. */ - copy_with_indices( - data.slice(side_poly_range), data.as_span(), edge_extruded_face_indices); + array_utils::gather( + data.as_span(), edge_extruded_face_indices.as_span(), data.slice(side_poly_range)); break; } case ATTR_DOMAIN_CORNER: { diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc index affeb43e33b..64546684186 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc @@ -2,6 +2,7 @@ #include "DNA_collection_types.h" +#include "BLI_array_utils.hh" #include "BLI_hash.h" #include "BLI_task.hh" @@ -172,18 +173,7 @@ static void add_instances_from_component( dst_attribute_opt = instance_attributes.get_for_write(attribute_id); } BLI_assert(dst_attribute_opt); - const GMutableSpan dst_attribute = dst_attribute_opt->slice(start_len, select_len); - threading::parallel_for(selection.index_range(), 1024, [&](IndexRange selection_range) { - attribute_math::convert_to_static_type(attribute_kind.data_type, [&](auto dummy) { - using T = decltype(dummy); - VArray<T> src = src_attribute.typed<T>(); - MutableSpan<T> dst = dst_attribute.typed<T>(); - for (const int range_i : selection_range) { - const int i = selection[range_i]; - dst[range_i] = src[i]; - } - }); - }); + array_utils::gather(src_attribute, selection, dst_attribute_opt->slice(start_len, select_len)); } } diff --git a/source/blender/nodes/texture/CMakeLists.txt b/source/blender/nodes/texture/CMakeLists.txt index 77db71d4b1a..2d704ac2228 100644 --- a/source/blender/nodes/texture/CMakeLists.txt +++ b/source/blender/nodes/texture/CMakeLists.txt @@ -2,7 +2,7 @@ set(INC . - ../ + .. ../intern ../../editors/include ../../blenkernel diff --git a/source/blender/python/gpu/gpu_py_platform.c b/source/blender/python/gpu/gpu_py_platform.c index b877e3ceb98..51366d199b0 100644 --- a/source/blender/python/gpu/gpu_py_platform.c +++ b/source/blender/python/gpu/gpu_py_platform.c @@ -11,6 +11,7 @@ #include "BLI_utildefines.h" +#include "GPU_context.h" #include "GPU_platform.h" #include "gpu_py_platform.h" /* Own include. */ @@ -83,6 +84,28 @@ static PyObject *pygpu_platform_device_type_get(PyObject *UNUSED(self)) return PyUnicode_FromString("UNKNOWN"); } +PyDoc_STRVAR(pygpu_platform_backend_type_get_doc, + ".. function:: backend_type_get()\n" + "\n" + " Get actuve GPU backend.\n" + "\n" + " :return: Backend type ('OPENGL', 'METAL', 'NONE', 'UNKNOWN').\n" + " :rtype: str\n"); +static PyObject *pygpu_platform_backend_type_get(PyObject *UNUSED(self)) +{ + switch (GPU_backend_get_type()) { + case GPU_BACKEND_METAL: + return PyUnicode_FromString("METAL"); + case GPU_BACKEND_NONE: + return PyUnicode_FromString("NONE"); + case GPU_BACKEND_OPENGL: + return PyUnicode_FromString("OPENGL"); + case GPU_BACKEND_ANY: + break; + } + return PyUnicode_FromString("UNKNOWN"); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -106,6 +129,10 @@ static struct PyMethodDef pygpu_platform__tp_methods[] = { (PyCFunction)pygpu_platform_device_type_get, METH_NOARGS, pygpu_platform_device_type_get_doc}, + {"backend_type_get", + (PyCFunction)pygpu_platform_backend_type_get, + METH_NOARGS, + pygpu_platform_backend_type_get_doc}, {NULL, NULL, 0, NULL}, }; diff --git a/source/blender/render/intern/engine.cc b/source/blender/render/intern/engine.cc index 5eb4db6faa4..b8757d33580 100644 --- a/source/blender/render/intern/engine.cc +++ b/source/blender/render/intern/engine.cc @@ -969,6 +969,40 @@ static void engine_render_view_layer(Render *re, engine_depsgraph_exit(engine); } +/* Callback function for engine_render_create_result to add all render passes to the result. */ +static void engine_render_add_result_pass_cb(void *user_data, + struct Scene *UNUSED(scene), + struct ViewLayer *view_layer, + const char *name, + int channels, + const char *chanid, + eNodeSocketDatatype UNUSED(type)) +{ + RenderResult *rr = (RenderResult *)user_data; + RE_create_render_pass(rr, name, channels, chanid, view_layer->name, RR_ALL_VIEWS, false); +} + +static RenderResult *engine_render_create_result(Render *re) +{ + RenderResult *rr = render_result_new(re, &re->disprect, RR_ALL_LAYERS, RR_ALL_VIEWS); + if (rr == nullptr) { + return nullptr; + } + + FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer) { + RE_engine_update_render_passes( + re->engine, re->scene, view_layer, engine_render_add_result_pass_cb, rr); + } + FOREACH_VIEW_LAYER_TO_RENDER_END; + + /* Preview does not support deferred render result allocation. */ + if (re->r.scemode & R_BUTS_PREVIEW) { + render_result_passes_allocated_ensure(rr); + } + + return rr; +} + bool RE_engine_render(Render *re, bool do_all) { RenderEngineType *type = RE_engines_find(re->r.engine); @@ -1008,6 +1042,14 @@ bool RE_engine_render(Render *re, bool do_all) render_update_anim_renderdata(re, &re->scene->r, &re->scene->view_layers); } + /* Create engine. */ + RenderEngine *engine = re->engine; + + if (!engine) { + engine = RE_engine_create(type); + re->engine = engine; + } + /* create render result */ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); if (re->result == nullptr || !(re->r.scemode & R_BUTS_PREVIEW)) { @@ -1015,7 +1057,7 @@ bool RE_engine_render(Render *re, bool do_all) render_result_free(re->result); } - re->result = render_result_new(re, &re->disprect, RR_ALL_LAYERS, RR_ALL_VIEWS); + re->result = engine_render_create_result(re); } BLI_rw_mutex_unlock(&re->resultmutex); @@ -1024,6 +1066,9 @@ bool RE_engine_render(Render *re, bool do_all) if (re->draw_lock) { re->draw_lock(re->dlh, false); } + /* Free engine. */ + RE_engine_free(engine); + re->engine = nullptr; /* Too small image is handled earlier, here it could only happen if * there was no sufficient memory to allocate all passes. */ @@ -1036,14 +1081,6 @@ bool RE_engine_render(Render *re, bool do_all) re->i.cfra = re->scene->r.cfra; BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name)); - /* render */ - RenderEngine *engine = re->engine; - - if (!engine) { - engine = RE_engine_create(type); - re->engine = engine; - } - engine->flag |= RE_ENGINE_RENDERING; /* TODO: actually link to a parent which shouldn't happen */ diff --git a/source/blender/render/intern/render_result.cc b/source/blender/render/intern/render_result.cc index bd5c6a0f5c4..f9524fdbf05 100644 --- a/source/blender/render/intern/render_result.cc +++ b/source/blender/render/intern/render_result.cc @@ -290,90 +290,8 @@ RenderResult *render_result_new(Render *re, } } -#define RENDER_LAYER_ADD_PASS_SAFE(rr, rl, channels, name, viewname, chan_id) \ - do { \ - if (render_layer_add_pass(rr, rl, channels, name, viewname, chan_id, false) == nullptr) { \ - render_result_free(rr); \ - return nullptr; \ - } \ - } while (false) - /* A render-layer should always have a "Combined" pass. */ render_layer_add_pass(rr, rl, 4, "Combined", view, "RGBA", false); - - if (view_layer->passflag & SCE_PASS_Z) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_Z, view, "Z"); - } - if (view_layer->passflag & SCE_PASS_VECTOR) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, RE_PASSNAME_VECTOR, view, "XYZW"); - } - if (view_layer->passflag & SCE_PASS_NORMAL) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_NORMAL, view, "XYZ"); - } - if (view_layer->passflag & SCE_PASS_POSITION) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_POSITION, view, "XYZ"); - } - if (view_layer->passflag & SCE_PASS_UV) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_UV, view, "UVA"); - } - if (view_layer->passflag & SCE_PASS_EMIT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_EMIT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_AO) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_AO, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_ENVIRONMENT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_ENVIRONMENT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_SHADOW) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SHADOW, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_INDEXOB) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_INDEXOB, view, "X"); - } - if (view_layer->passflag & SCE_PASS_INDEXMA) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_INDEXMA, view, "X"); - } - if (view_layer->passflag & SCE_PASS_MIST) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_MIST, view, "Z"); - } - if (view_layer->passflag & SCE_PASS_DIFFUSE_DIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_DIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_DIFFUSE_INDIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_INDIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_DIFFUSE_COLOR) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_COLOR, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_GLOSSY_DIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_DIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_GLOSSY_INDIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_INDIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_GLOSSY_COLOR) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_COLOR, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_TRANSM_DIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_DIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_TRANSM_INDIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_INDIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_TRANSM_COLOR) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_COLOR, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_SUBSURFACE_DIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_DIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_SUBSURFACE_INDIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_INDIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_SUBSURFACE_COLOR) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_COLOR, view, "RGB"); - } -#undef RENDER_LAYER_ADD_PASS_SAFE } } FOREACH_VIEW_LAYER_TO_RENDER_END; @@ -411,11 +329,6 @@ RenderResult *render_result_new(Render *re, rr->xof = re->disprect.xmin + BLI_rcti_cent_x(&re->disprect) - (re->winx / 2); rr->yof = re->disprect.ymin + BLI_rcti_cent_y(&re->disprect) - (re->winy / 2); - /* Preview does not support deferred render result allocation. */ - if (re->r.scemode & R_BUTS_PREVIEW) { - render_result_passes_allocated_ensure(rr); - } - return rr; } diff --git a/source/blender/windowmanager/intern/wm_dragdrop.cc b/source/blender/windowmanager/intern/wm_dragdrop.cc index 0896daec561..fb63abed9e9 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.cc +++ b/source/blender/windowmanager/intern/wm_dragdrop.cc @@ -853,7 +853,8 @@ static void wm_drag_draw_icon(bContext * /*C*/, wmWindow * /*win*/, wmDrag *drag y = xy[1] - 2 * UI_DPI_FAC; const uchar text_col[] = {255, 255, 255, 255}; - UI_icon_draw_ex(x, y, drag->icon, U.inv_dpi_fac, 0.8, 0.0f, text_col, false); + UI_icon_draw_ex( + x, y, drag->icon, U.inv_dpi_fac, 0.8, 0.0f, text_col, false, UI_NO_ICON_OVERLAY_TEXT); } } diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc index affe0bcf45a..181ec89cabd 100644 --- a/source/blender/windowmanager/intern/wm_event_system.cc +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -5620,7 +5620,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void case GHOST_kEventNDOFButton: { GHOST_TEventNDOFButtonData *e = static_cast<GHOST_TEventNDOFButtonData *>(customdata); - event.type = NDOF_BUTTON_NONE + e->button; + event.type = NDOF_BUTTON_INDEX_AS_EVENT(e->button); switch (e->action) { case GHOST_kPress: diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index bf793ee41a0..3e5399a6f56 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -59,6 +59,8 @@ #include "DEG_depsgraph.h" +#include "wm_window_private.h" + #include "WM_api.h" /* only for WM_main_playanim */ #ifdef WITH_AUDASPACE @@ -1340,6 +1342,8 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) static void playanim_window_open(const char *title, int posx, int posy, int sizex, int sizey) { GHOST_GLSettings glsettings = {0}; + const eGPUBackendType gpu_backend = GPU_backend_type_selection_get(); + glsettings.context_type = wm_ghost_drawing_context_type(gpu_backend); uint32_t scr_w, scr_h; GHOST_GetMainDisplayDimensions(g_WS.ghost_system, &scr_w, &scr_h); @@ -1356,7 +1360,6 @@ static void playanim_window_open(const char *title, int posx, int posy, int size /* Could optionally start full-screen. */ GHOST_kWindowStateNormal, false, - GHOST_kDrawingContextTypeOpenGL, glsettings); } diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index b1b13390932..2ca7b5f470d 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -556,6 +556,9 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, glSettings.flags |= GHOST_glDebugContext; } + eGPUBackendType gpu_backend = GPU_backend_type_selection_get(); + glSettings.context_type = wm_ghost_drawing_context_type(gpu_backend); + int scr_w, scr_h; wm_get_desktopsize(&scr_w, &scr_h); int posy = (scr_h - win->posy - win->sizey); @@ -573,7 +576,6 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, win->sizey, (GHOST_TWindowState)win->windowstate, is_dialog, - GHOST_kDrawingContextTypeOpenGL, glSettings); if (ghostwin) { @@ -1615,6 +1617,29 @@ const char *WM_ghost_backend(void) #endif } +GHOST_TDrawingContextType wm_ghost_drawing_context_type(const eGPUBackendType gpu_backend) +{ + switch (gpu_backend) { + case GPU_BACKEND_NONE: + return GHOST_kDrawingContextTypeNone; + case GPU_BACKEND_ANY: + case GPU_BACKEND_OPENGL: + return GHOST_kDrawingContextTypeOpenGL; + case GPU_BACKEND_METAL: +#ifdef WITH_METAL_BACKEND + return GHOST_kDrawingContextTypeMetal; +#else + BLI_assert_unreachable(); + return GHOST_kDrawingContextTypeNone; +#endif + } + + /* Avoid control reaches end of non-void function compilation warning, which could be promoted + * to error. */ + BLI_assert_unreachable(); + return GHOST_kDrawingContextTypeNone; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/windowmanager/intern/wm_window_private.h b/source/blender/windowmanager/intern/wm_window_private.h index f68d4e3e693..dad3e749817 100644 --- a/source/blender/windowmanager/intern/wm_window_private.h +++ b/source/blender/windowmanager/intern/wm_window_private.h @@ -7,8 +7,11 @@ #pragma once #include "BLI_sys_types.h" + #include "GHOST_Types.h" +#include "GPU_context.h" + /* *************** Message box *************** */ /* `WM_ghost_show_message_box` is implemented in `wm_windows.c` it is * defined here as it was implemented to be used for showing @@ -21,3 +24,5 @@ void WM_ghost_show_message_box(const char *title, const char *continue_label, const char *link, GHOST_DialogOptions dialog_options); + +GHOST_TDrawingContextType wm_ghost_drawing_context_type(const eGPUBackendType gpu_backend); diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index 405b7225bd5..c36c57a12ae 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -252,8 +252,6 @@ enum { #define _NDOF_MIN NDOF_MOTION #define _NDOF_BUTTON_MIN NDOF_BUTTON_MENU - /* used internally, never sent */ - NDOF_BUTTON_NONE = NDOF_MOTION, /* these two are available from any 3Dconnexion device */ NDOF_BUTTON_MENU = 0x0191, /* 401 */ @@ -281,35 +279,42 @@ enum { NDOF_BUTTON_DOMINANT = 0x01a3, /* 419 */ NDOF_BUTTON_PLUS = 0x01a4, /* 420 */ NDOF_BUTTON_MINUS = 0x01a5, /* 421 */ + /* General-purpose buttons. */ + NDOF_BUTTON_1 = 0x01a6, /* 422 */ + NDOF_BUTTON_2 = 0x01a7, /* 423 */ + NDOF_BUTTON_3 = 0x01a8, /* 424 */ + NDOF_BUTTON_4 = 0x01a9, /* 425 */ + NDOF_BUTTON_5 = 0x01aa, /* 426 */ + NDOF_BUTTON_6 = 0x01ab, /* 427 */ + NDOF_BUTTON_7 = 0x01ac, /* 428 */ + NDOF_BUTTON_8 = 0x01ad, /* 429 */ + NDOF_BUTTON_9 = 0x01ae, /* 430 */ + NDOF_BUTTON_10 = 0x01af, /* 431 */ + /* more general-purpose buttons */ + NDOF_BUTTON_A = 0x01b0, /* 432 */ + NDOF_BUTTON_B = 0x01b1, /* 433 */ + NDOF_BUTTON_C = 0x01b2, /* 434 */ + /* Store/restore views. */ + NDOF_BUTTON_V1 = 0x01b3, /* 435 */ + NDOF_BUTTON_V2 = 0x01b4, /* 436 */ + NDOF_BUTTON_V3 = 0x01b5, /* 437 */ /* Disabled as GHOST converts these to keyboard events * which use regular keyboard event handling logic. */ #if 0 /* keyboard emulation */ - NDOF_BUTTON_ESC = 0x01a6, /* 422 */ - NDOF_BUTTON_ALT = 0x01a7, /* 423 */ - NDOF_BUTTON_SHIFT = 0x01a8, /* 424 */ - NDOF_BUTTON_CTRL = 0x01a9, /* 425 */ + NDOF_BUTTON_ESC = 0x01b6, /* 438 */ + NDOF_BUTTON_ENTER = 0x01b7, /* 439 */ + NDOF_BUTTON_DELETE = 0x01b8, /* 440 */ + NDOF_BUTTON_TAB = 0x01b9, /* 441 */ + NDOF_BUTTON_SPACE = 0x01ba, /* 442 */ + NDOF_BUTTON_ALT = 0x01bb, /* 443 */ + NDOF_BUTTON_SHIFT = 0x01bc, /* 444 */ + NDOF_BUTTON_CTRL = 0x01bd, /* 445 */ #endif - /* general-purpose buttons */ - NDOF_BUTTON_1 = 0x01aa, /* 426 */ - NDOF_BUTTON_2 = 0x01ab, /* 427 */ - NDOF_BUTTON_3 = 0x01ac, /* 428 */ - NDOF_BUTTON_4 = 0x01ad, /* 429 */ - NDOF_BUTTON_5 = 0x01ae, /* 430 */ - NDOF_BUTTON_6 = 0x01af, /* 431 */ - NDOF_BUTTON_7 = 0x01b0, /* 432 */ - NDOF_BUTTON_8 = 0x01b1, /* 433 */ - NDOF_BUTTON_9 = 0x01b2, /* 434 */ - NDOF_BUTTON_10 = 0x01b3, /* 435 */ - /* more general-purpose buttons */ - NDOF_BUTTON_A = 0x01b4, /* 436 */ - NDOF_BUTTON_B = 0x01b5, /* 437 */ - NDOF_BUTTON_C = 0x01b6, /* 438 */ - -#define _NDOF_MAX NDOF_BUTTON_C -#define _NDOF_BUTTON_MAX NDOF_BUTTON_C +#define _NDOF_MAX NDOF_BUTTON_V3 +#define _NDOF_BUTTON_MAX NDOF_BUTTON_V3 /* ********** End of Input devices. ********** */ @@ -449,6 +454,8 @@ enum eEventType_Mask { (EVT_TYPE_MASK_KEYBOARD | EVT_TYPE_MASK_MOUSE | EVT_TYPE_MASK_NDOF) #define EVT_TYPE_MASK_HOTKEY_EXCLUDE EVT_TYPE_MASK_KEYBOARD_MODIFIER +#define NDOF_BUTTON_INDEX_AS_EVENT(i) (_NDOF_BUTTON_MIN + (i)) + bool WM_event_type_mask_test(int event_type, enum eEventType_Mask mask); /** \} */ diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 06b898587bf..4144603555b 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -42,6 +42,8 @@ # include "BKE_scene.h" # include "BKE_sound.h" +# include "GPU_context.h" + # ifdef WITH_FFMPEG # include "IMB_imbuf.h" # endif @@ -1111,6 +1113,44 @@ static int arg_handle_debug_gpu_set(int UNUSED(argc), return 0; } +static const char arg_handle_gpu_backend_set_doc[] = + "\n" + "\tForce to use a specific GPU backend. Valid options: " +# ifdef WITH_METAL_BACKEND + "'metal', " +# endif + "'opengl')."; +static int arg_handle_gpu_backend_set(int argc, const char **argv, void *UNUSED(data)) +{ + if (argc == 0) { + printf("\nError: GPU backend must follow '--gpu-backend'.\n"); + return 0; + } + + eGPUBackendType gpu_backend = GPU_BACKEND_NONE; + + if (STREQ(argv[1], "opengl")) { + gpu_backend = GPU_BACKEND_OPENGL; + } +# ifdef WITH_METAL_BACKEND + else if (STREQ(argv[1], "metal")) { + gpu_backend = GPU_BACKEND_METAL; + } +# endif + else { + printf("\nError: Unrecognized GPU backend for '--gpu-backend'.\n"); + return 0; + } + + GPU_backend_type_selection_set(gpu_backend); + if (!GPU_backend_supported()) { + printf("\nError: GPU backend not supported.\n"); + return 0; + } + + return 1; +} + static const char arg_handle_debug_fpe_set_doc[] = "\n\t" "Enable floating-point exceptions."; @@ -2074,6 +2114,10 @@ void main_args_setup(bContext *C, bArgs *ba) BLI_args_add(ba, NULL, "--log-show-timestamp", CB(arg_handle_log_show_timestamp_set), ba); BLI_args_add(ba, NULL, "--log-file", CB(arg_handle_log_file_set), ba); + /* GPU backend selection should be part of ARG_PASS_ENVIRONMENT for correct GPU context selection + * for anim player. */ + BLI_args_add(ba, NULL, "--gpu-backend", CB(arg_handle_gpu_backend_set), NULL); + /* Pass: Background Mode & Settings * * Also and commands that exit after usage. */ |