Merge branch 'master' into blender2.8

This commit is contained in:
Stefan Werner 2018-11-07 14:27:41 +01:00
commit 9d0eac6ba5
38 changed files with 2063 additions and 24 deletions

View File

@ -405,6 +405,7 @@ option(WITH_CYCLES "Enable Cycles Render Engine" ON)
option(WITH_CYCLES_STANDALONE "Build Cycles standalone application" OFF)
option(WITH_CYCLES_STANDALONE_GUI "Build Cycles standalone with GUI" OFF)
option(WITH_CYCLES_OSL "Build Cycles with OSL support" ${_init_CYCLES_OSL})
option(WITH_CYCLES_EMBREE "Build Cycles with Embree support" OFF)
option(WITH_CYCLES_OPENSUBDIV "Build Cycles with OpenSubdiv support" ${_init_CYCLES_OPENSUBDIV})
option(WITH_CYCLES_CUDA_BINARIES "Build Cycles CUDA binaries" OFF)
option(WITH_CYCLES_CUBIN_COMPILER "Build cubins with nvrtc based compiler instead of nvcc" OFF)

View File

@ -97,6 +97,10 @@ if(WITH_WEBP)
include(cmake/webp.cmake)
endif()
if(WITH_EMBREE)
include(cmake/embree.cmake)
endif()
if(WIN32)
# HMD branch deps
include(cmake/hidapi.cmake)

View File

@ -0,0 +1,46 @@
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ***** END GPL LICENSE BLOCK *****
# Note the utility apps may use png/tiff/gif system libraries, but the
# library itself does not depend on them, so should give no problems.
set(EMBREE_EXTRA_ARGS
-DEMBREE_ISPC_SUPPORT=OFF
-DEMBREE_TUTORIALS=OFF
-DEMBREE_STATIC_LIB=ON
-DEMBREE_RAY_MASK=ON
-DEMBREE_FILTER_FUNCTION=ON
-DEMBREE_BACKFACE_CULLING=OFF
-DEMBREE_TASKING_SYSTEM=INTERNAL
-DEMBREE_MAX_ISA=AVX2
)
if(WIN32)
set(EMBREE_BUILD_DIR ${BUILD_MODE}/)
else()
set(EMBREE_BUILD_DIR)
endif()
ExternalProject_Add(external_embree
URL ${EMBREE_URI}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
URL_HASH MD5=${EMBREE_HASH}
PREFIX ${BUILD_DIR}/embree
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/embree ${DEFAULT_CMAKE_FLAGS} ${EMBREE_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/embree
)

View File

@ -57,7 +57,9 @@ if(BUILD_MODE STREQUAL Release)
# hidapi
${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/hidapi/ ${HARVEST_TARGET}/hidapi/ &&
# webp, straight up copy
${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/webp ${HARVEST_TARGET}/webp
${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/webp ${HARVEST_TARGET}/webp &&
# embree
${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/embree ${HARVEST_TARGET}/embree
DEPENDS
)
endif()
@ -191,5 +193,7 @@ harvest(vpx/lib ffmpeg/lib "*.a")
harvest(webp/lib ffmpeg/lib "*.a")
harvest(x264/lib ffmpeg/lib "*.a")
harvest(xvidcore/lib ffmpeg/lib "*.a")
harvest(embree/include embree/include "*.h")
harvest(embree/lib embree/lib "*.a")
endif()

View File

@ -20,6 +20,7 @@ if(WIN32)
option(ENABLE_MINGW64 "Enable building of ffmpeg/iconv/libsndfile/lapack/fftw3 by installing mingw64" ON)
endif()
option(WITH_WEBP "Enable building of oiio with webp support" OFF)
option(WITH_EMBREE "Enable building of Embree" OFF)
set(MAKE_THREADS 1 CACHE STRING "Number of threads to run make with")
if(NOT BUILD_MODE)

View File

@ -298,3 +298,7 @@ set(SSL_HASH ebbfc844a8c8cc0ea5dc10b86c9ce97f401837f3fa08c17b2cdadc118253cf99)
set(SQLITE_VERSION 3.24.0)
set(SQLITE_URI https://www.sqlite.org/2018/sqlite-src-3240000.zip)
set(SQLITE_HASH fb558c49ee21a837713c4f1e7e413309aabdd9c7)
set(EMBREE_VERSION 3.2.4)
set(EMBREE_URI https://github.com/embree/embree/archive/v${EMBREE_VERSION}.zip)
set(EMBREE_HASH 3d4a1147002ff43939d45140aa9d6fb8)

View File

@ -0,0 +1,108 @@
# - Find Embree library
# Find the native Embree includes and library
# This module defines
# EMBREE_INCLUDE_DIRS, where to find rtcore.h, Set when
# EMBREE_INCLUDE_DIR is found.
# EMBREE_LIBRARIES, libraries to link against to use Embree.
# EMBREE_ROOT_DIR, The base directory to search for Embree.
# This can also be an environment variable.
# EMBREEFOUND, If false, do not try to use Embree.
#
# also defined, but not for general use are
# EMBREE_LIBRARY, where to find the Embree library.
#=============================================================================
# Copyright 2018 Blender Foundation.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# If EMBREE_ROOT_DIR was defined in the environment, use it.
IF(NOT EMBREE_ROOT_DIR AND NOT $ENV{EMBREE_ROOT_DIR} STREQUAL "")
SET(EMBREE_ROOT_DIR $ENV{EMBREE_ROOT_DIR})
ENDIF()
SET(_embree_SEARCH_DIRS
${EMBREE_ROOT_DIR}
/usr/local
/sw # Fink
/opt/local # DarwinPorts
/opt/embree
/opt/lib/embree
)
FIND_PATH(EMBREE_INCLUDE_DIR
NAMES
embree3/rtcore.h
HINTS
${_embree_SEARCH_DIRS}
PATH_SUFFIXES
include
)
SET(_embree_FIND_COMPONENTS
embree_avx
embree_avx2
embree_sse42
embree3
lexers
math
simd
sys
tasking
)
SET(_embree_LIBRARIES)
FOREACH(COMPONENT ${_embree_FIND_COMPONENTS})
STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)
FIND_LIBRARY(EMBREE_${UPPERCOMPONENT}_LIBRARY
NAMES
${COMPONENT}
HINTS
${_embree_SEARCH_DIRS}
PATH_SUFFIXES
lib64 lib
)
LIST(APPEND _embree_LIBRARIES "${EMBREE_${UPPERCOMPONENT}_LIBRARY}")
ENDFOREACH()
FIND_LIBRARY(EMBREE_LIBRARY
NAMES
libembree3
HINTS
${_embree_SEARCH_DIRS}
PATH_SUFFIXES
lib64 lib
)
# handle the QUIETLY and REQUIRED arguments and set EMBREE_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(EMBREE DEFAULT_MSG
_embree_LIBRARIES EMBREE_INCLUDE_DIR)
IF(EMBREE_FOUND)
SET(EMBREE_LIBRARIES ${_embree_LIBRARIES})
SET(EMBREE_INCLUDE_DIRS ${EMBREE_INCLUDE_DIR})
ENDIF(EMBREE_FOUND)
MARK_AS_ADVANCED(
EMBREE_INCLUDE_DIR
)
FOREACH(COMPONENT ${_embree_FIND_COMPONENTS})
STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)
MARK_AS_ADVANCED(EMBREE_${UPPERCOMPONENT}_LIBRARY)
ENDFOREACH()
UNSET(_embree_SEARCH_DIRS)
UNSET(_embree_FIND_COMPONENTS)
UNSET(_embree_LIBRARIES)

View File

@ -435,6 +435,9 @@ function(setup_liblinks
if(WITH_CYCLES_OSL)
target_link_libraries(${target} ${OSL_LIBRARIES})
endif()
if(WITH_CYCLES_EMBREE)
target_link_libraries(${target} ${EMBREE_LIBRARIES})
endif()
if(WITH_BOOST)
target_link_libraries(${target} ${BOOST_LIBRARIES})
if(Boost_USE_STATIC_LIBS AND Boost_USE_ICU)

View File

@ -380,6 +380,11 @@ if(WITH_CYCLES_OSL)
endif()
endif()
if(WITH_CYCLES_EMBREE)
find_package(Embree 3.2.4 REQUIRED)
set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -Xlinker -stack_size -Xlinker 0x100000")
endif()
if(WITH_OPENMP)
execute_process(COMMAND ${CMAKE_C_COMPILER} --version OUTPUT_VARIABLE COMPILER_VENDOR)
string(SUBSTRING "${COMPILER_VENDOR}" 0 5 VENDOR_NAME) # truncate output

View File

@ -359,6 +359,10 @@ if(WITH_OPENCOLORIO)
endif()
endif()
if(WITH_CYCLES_EMBREE)
find_package(Embree 3.2.4 REQUIRED)
endif()
if(WITH_LLVM)
if(EXISTS ${LIBDIR})
set(LLVM_STATIC ON)

View File

@ -607,6 +607,10 @@ if(WITH_CYCLES_OSL)
endif()
endif()
if(WITH_CYCLES_EMBREE)
find_package(Embree 3.2.4 REQUIRED)
endif()
if (WINDOWS_PYTHON_DEBUG)
# Include the system scripts in the blender_python_system_scripts project.
FILE(GLOB_RECURSE inFiles "${CMAKE_SOURCE_DIR}/release/scripts/*.*" )

View File

@ -0,0 +1,506 @@
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# The Original Code is Copyright (C) 2016, Blender Foundation
# All rights reserved.
#
# Contributor(s): Sergey Sharybin.
#
# ***** END GPL LICENSE BLOCK *****
# Libraries configuration for Windows when compiling with MSVC.
macro(warn_hardcoded_paths package_name
)
if(WITH_WINDOWS_FIND_MODULES)
message(WARNING "Using HARDCODED ${package_name} locations")
endif(WITH_WINDOWS_FIND_MODULES)
endmacro()
macro(windows_find_package package_name
)
if(WITH_WINDOWS_FIND_MODULES)
find_package(${package_name})
endif(WITH_WINDOWS_FIND_MODULES)
endmacro()
macro(find_package_wrapper)
if(WITH_WINDOWS_FIND_MODULES)
find_package(${ARGV})
endif()
endmacro()
add_definitions(-DWIN32)
# Minimum MSVC Version
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
if(MSVC_VERSION EQUAL 1800)
set(_min_ver "18.0.31101")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${_min_ver})
message(FATAL_ERROR
"Visual Studio 2013 (Update 4, ${_min_ver}) required, "
"found (${CMAKE_CXX_COMPILER_VERSION})")
endif()
endif()
if(MSVC_VERSION EQUAL 1900)
set(_min_ver "19.0.24210")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${_min_ver})
message(FATAL_ERROR
"Visual Studio 2015 (Update 3, ${_min_ver}) required, "
"found (${CMAKE_CXX_COMPILER_VERSION})")
endif()
endif()
endif()
unset(_min_ver)
# needed for some MSVC installations
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO")
list(APPEND PLATFORM_LINKLIBS
ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32
advapi32 shfolder shell32 ole32 oleaut32 uuid psapi Dbghelp
)
if(WITH_INPUT_IME)
list(APPEND PLATFORM_LINKLIBS imm32)
endif()
add_definitions(
-D_CRT_NONSTDC_NO_DEPRECATE
-D_CRT_SECURE_NO_DEPRECATE
-D_SCL_SECURE_NO_DEPRECATE
-D_CONSOLE
-D_LIB
)
# MSVC11 needs _ALLOW_KEYWORD_MACROS to build
add_definitions(-D_ALLOW_KEYWORD_MACROS)
# We want to support Vista level ABI
add_definitions(-D_WIN32_WINNT=0x600)
# Make cmake find the msvc redistributables
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
include(InstallRequiredSystemLibraries)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /nologo /J /Gd /MP /EHsc")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /nologo /J /Gd /MP")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MT")
set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} /MT")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MT")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} /MT")
set(PLATFORM_LINKFLAGS "/SUBSYSTEM:CONSOLE /STACK:2097152 /INCREMENTAL:NO ")
set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /NODEFAULTLIB:msvcrt.lib /NODEFAULTLIB:msvcmrt.lib /NODEFAULTLIB:msvcurt.lib /NODEFAULTLIB:msvcrtd.lib ")
# Ignore meaningless for us linker warnings.
set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /ignore:4049 /ignore:4217 /ignore:4221")
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221")
if(CMAKE_CL_64)
set(PLATFORM_LINKFLAGS "/MACHINE:X64 ${PLATFORM_LINKFLAGS}")
else()
set(PLATFORM_LINKFLAGS "/MACHINE:IX86 /LARGEADDRESSAWARE ${PLATFORM_LINKFLAGS}")
endif()
set(PLATFORM_LINKFLAGS_DEBUG "/IGNORE:4099 /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libc.lib")
if(NOT DEFINED LIBDIR)
# Setup 64bit and 64bit windows systems
if(CMAKE_CL_64)
message(STATUS "64 bit compiler detected.")
set(LIBDIR_BASE "win64")
else()
message(STATUS "32 bit compiler detected.")
set(LIBDIR_BASE "windows")
endif()
if(MSVC_VERSION EQUAL 1910)
message(STATUS "Visual Studio 2017 detected.")
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc14)
elseif(MSVC_VERSION EQUAL 1900)
message(STATUS "Visual Studio 2015 detected.")
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc14)
else()
message(STATUS "Visual Studio 2013 detected.")
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc12)
endif()
else()
message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
endif()
if(NOT EXISTS "${LIBDIR}/")
message(FATAL_ERROR "Windows requires pre-compiled libs at: '${LIBDIR}'")
endif()
# Add each of our libraries to our cmake_prefix_path so find_package() could work
file(GLOB children RELATIVE ${LIBDIR} ${LIBDIR}/*)
foreach(child ${children})
if(IS_DIRECTORY ${LIBDIR}/${child})
list(APPEND CMAKE_PREFIX_PATH ${LIBDIR}/${child})
endif()
endforeach()
set(ZLIB_INCLUDE_DIRS ${LIBDIR}/zlib/include)
set(ZLIB_LIBRARIES ${LIBDIR}/zlib/lib/libz_st.lib)
set(ZLIB_INCLUDE_DIR ${LIBDIR}/zlib/include)
set(ZLIB_LIBRARY ${LIBDIR}/zlib/lib/libz_st.lib)
set(ZLIB_DIR ${LIBDIR}/zlib)
windows_find_package(zlib) # we want to find before finding things that depend on it like png
windows_find_package(png)
if(NOT PNG_FOUND)
warn_hardcoded_paths(libpng)
set(PNG_PNG_INCLUDE_DIR ${LIBDIR}/png/include)
set(PNG_LIBRARIES libpng)
set(PNG "${LIBDIR}/png")
set(PNG_INCLUDE_DIRS "${PNG}/include")
set(PNG_LIBPATH ${PNG}/lib) # not cmake defined
endif()
set(JPEG_NAMES ${JPEG_NAMES} libjpeg)
windows_find_package(jpeg REQUIRED)
if(NOT JPEG_FOUND)
warn_hardcoded_paths(jpeg)
set(JPEG_INCLUDE_DIR ${LIBDIR}/jpeg/include)
set(JPEG_LIBRARIES ${LIBDIR}/jpeg/lib/libjpeg.lib)
endif()
set(PTHREADS_INCLUDE_DIRS ${LIBDIR}/pthreads/include)
set(PTHREADS_LIBRARIES ${LIBDIR}/pthreads/lib/pthreadVC2.lib)
set(FREETYPE ${LIBDIR}/freetype)
set(FREETYPE_INCLUDE_DIRS
${LIBDIR}/freetype/include
${LIBDIR}/freetype/include/freetype2
)
set(FREETYPE_LIBRARY ${LIBDIR}/freetype/lib/freetype2ST.lib)
windows_find_package(freetype REQUIRED)
if(WITH_FFTW3)
set(FFTW3 ${LIBDIR}/fftw3)
set(FFTW3_LIBRARIES libfftw)
set(FFTW3_INCLUDE_DIRS ${FFTW3}/include)
set(FFTW3_LIBPATH ${FFTW3}/lib)
endif()
if(WITH_OPENCOLLADA)
set(OPENCOLLADA ${LIBDIR}/opencollada)
set(OPENCOLLADA_INCLUDE_DIRS
${OPENCOLLADA}/include/opencollada/COLLADAStreamWriter
${OPENCOLLADA}/include/opencollada/COLLADABaseUtils
${OPENCOLLADA}/include/opencollada/COLLADAFramework
${OPENCOLLADA}/include/opencollada/COLLADASaxFrameworkLoader
${OPENCOLLADA}/include/opencollada/GeneratedSaxParser
)
set(OPENCOLLADA_LIBRARIES
${OPENCOLLADA}/lib/opencollada/OpenCOLLADASaxFrameworkLoader.lib
${OPENCOLLADA}/lib/opencollada/OpenCOLLADAFramework.lib
${OPENCOLLADA}/lib/opencollada/OpenCOLLADABaseUtils.lib
${OPENCOLLADA}/lib/opencollada/OpenCOLLADAStreamWriter.lib
${OPENCOLLADA}/lib/opencollada/MathMLSolver.lib
${OPENCOLLADA}/lib/opencollada/GeneratedSaxParser.lib
${OPENCOLLADA}/lib/opencollada/xml.lib
${OPENCOLLADA}/lib/opencollada/buffer.lib
${OPENCOLLADA}/lib/opencollada/ftoa.lib
)
if(NOT WITH_LLVM)
list(APPEND OPENCOLLADA_LIBRARIES ${OPENCOLLADA}/lib/opencollada/UTF.lib)
endif()
set(PCRE_LIBRARIES
${OPENCOLLADA}/lib/opencollada/pcre.lib
)
endif()
if(WITH_CODEC_FFMPEG)
set(FFMPEG_INCLUDE_DIRS
${LIBDIR}/ffmpeg/include
${LIBDIR}/ffmpeg/include/msvc
)
windows_find_package(FFMPEG)
if(NOT FFMPEG_FOUND)
warn_hardcoded_paths(ffmpeg)
set(FFMPEG_LIBRARY_VERSION 57)
set(FFMPEG_LIBRARY_VERSION_AVU 55)
set(FFMPEG_LIBRARIES
${LIBDIR}/ffmpeg/lib/avcodec.lib
${LIBDIR}/ffmpeg/lib/avformat.lib
${LIBDIR}/ffmpeg/lib/avdevice.lib
${LIBDIR}/ffmpeg/lib/avutil.lib
${LIBDIR}/ffmpeg/lib/swscale.lib
)
endif()
endif()
if(WITH_IMAGE_OPENEXR)
set(OPENEXR_ROOT_DIR ${LIBDIR}/openexr)
set(OPENEXR_VERSION "2.1")
windows_find_package(OPENEXR REQUIRED)
if(NOT OPENEXR_FOUND)
warn_hardcoded_paths(OpenEXR)
set(OPENEXR ${LIBDIR}/openexr)
set(OPENEXR_INCLUDE_DIR ${OPENEXR}/include)
set(OPENEXR_INCLUDE_DIRS ${OPENEXR_INCLUDE_DIR} ${OPENEXR}/include/OpenEXR)
set(OPENEXR_LIBPATH ${OPENEXR}/lib)
set(OPENEXR_LIBRARIES
optimized ${OPENEXR_LIBPATH}/Iex-2_2.lib
optimized ${OPENEXR_LIBPATH}/Half.lib
optimized ${OPENEXR_LIBPATH}/IlmImf-2_2.lib
optimized ${OPENEXR_LIBPATH}/Imath-2_2.lib
optimized ${OPENEXR_LIBPATH}/IlmThread-2_2.lib
debug ${OPENEXR_LIBPATH}/Iex-2_2_d.lib
debug ${OPENEXR_LIBPATH}/Half_d.lib
debug ${OPENEXR_LIBPATH}/IlmImf-2_2_d.lib
debug ${OPENEXR_LIBPATH}/Imath-2_2_d.lib
debug ${OPENEXR_LIBPATH}/IlmThread-2_2_d.lib
)
endif()
endif()
if(WITH_IMAGE_TIFF)
# Try to find tiff first then complain and set static and maybe wrong paths
windows_find_package(TIFF)
if(NOT TIFF_FOUND)
warn_hardcoded_paths(libtiff)
set(TIFF_LIBRARY ${LIBDIR}/tiff/lib/libtiff.lib)
set(TIFF_INCLUDE_DIR ${LIBDIR}/tiff/include)
endif()
endif()
if(WITH_JACK)
set(JACK_INCLUDE_DIRS
${LIBDIR}/jack/include/jack
${LIBDIR}/jack/include
)
set(JACK_LIBRARIES optimized ${LIBDIR}/jack/lib/libjack.lib debug ${LIBDIR}/jack/lib/libjack_d.lib)
endif()
if(WITH_PYTHON)
set(PYTHON_VERSION 3.5) # CACHE STRING)
string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION})
# Use shared libs for vc2008 and vc2010 until we actually have vc2010 libs
set(PYTHON_LIBRARY ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.lib)
unset(_PYTHON_VERSION_NO_DOTS)
# Shared includes for both vc2008 and vc2010
set(PYTHON_INCLUDE_DIR ${LIBDIR}/python/include/python${PYTHON_VERSION})
# uncached vars
set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}")
set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
endif()
if(WITH_BOOST)
if(WITH_CYCLES_OSL)
set(boost_extra_libs wave)
endif()
if(WITH_INTERNATIONAL)
list(APPEND boost_extra_libs locale)
endif()
if(WITH_OPENVDB)
list(APPEND boost_extra_libs iostreams)
endif()
set(Boost_USE_STATIC_RUNTIME ON) # prefix lib
set(Boost_USE_MULTITHREADED ON) # suffix -mt
set(Boost_USE_STATIC_LIBS ON) # suffix -s
if (WITH_WINDOWS_FIND_MODULES)
find_package(Boost COMPONENTS date_time filesystem thread regex system ${boost_extra_libs})
endif (WITH_WINDOWS_FIND_MODULES)
if(NOT Boost_FOUND)
warn_hardcoded_paths(BOOST)
set(BOOST ${LIBDIR}/boost)
set(BOOST_INCLUDE_DIR ${BOOST}/include)
if(MSVC12)
set(BOOST_LIBPATH ${BOOST}/lib)
set(BOOST_POSTFIX "vc120-mt-s-1_60.lib")
set(BOOST_DEBUG_POSTFIX "vc120-mt-sgd-1_60.lib")
else()
set(BOOST_LIBPATH ${BOOST}/lib)
set(BOOST_POSTFIX "vc140-mt-s-1_60.lib")
set(BOOST_DEBUG_POSTFIX "vc140-mt-sgd-1_60.lib")
endif()
set(BOOST_LIBRARIES
optimized libboost_date_time-${BOOST_POSTFIX}
optimized libboost_filesystem-${BOOST_POSTFIX}
optimized libboost_regex-${BOOST_POSTFIX}
optimized libboost_system-${BOOST_POSTFIX}
optimized libboost_thread-${BOOST_POSTFIX}
debug libboost_date_time-${BOOST_DEBUG_POSTFIX}
debug libboost_filesystem-${BOOST_DEBUG_POSTFIX}
debug libboost_regex-${BOOST_DEBUG_POSTFIX}
debug libboost_system-${BOOST_DEBUG_POSTFIX}
debug libboost_thread-${BOOST_DEBUG_POSTFIX}
)
if(WITH_CYCLES_OSL)
set(BOOST_LIBRARIES ${BOOST_LIBRARIES}
optimized libboost_wave-${BOOST_POSTFIX}
debug libboost_wave-${BOOST_DEBUG_POSTFIX})
endif()
if(WITH_INTERNATIONAL)
set(BOOST_LIBRARIES ${BOOST_LIBRARIES}
optimized libboost_locale-${BOOST_POSTFIX}
debug libboost_locale-${BOOST_DEBUG_POSTFIX})
endif()
else() # we found boost using find_package
set(BOOST_INCLUDE_DIR ${Boost_INCLUDE_DIRS})
set(BOOST_LIBRARIES ${Boost_LIBRARIES})
set(BOOST_LIBPATH ${Boost_LIBRARY_DIRS})
endif()
set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB")
endif()
if(WITH_OPENIMAGEIO)
windows_find_package(OpenImageIO)
set(OPENIMAGEIO ${LIBDIR}/openimageio)
set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO}/include)
set(OIIO_OPTIMIZED optimized OpenImageIO optimized OpenImageIO_Util)
set(OIIO_DEBUG debug OpenImageIO_d debug OpenImageIO_Util_d)
set(OPENIMAGEIO_LIBRARIES ${OIIO_OPTIMIZED} ${OIIO_DEBUG})
set(OPENIMAGEIO_LIBPATH ${OPENIMAGEIO}/lib)
set(OPENIMAGEIO_DEFINITIONS "-DUSE_TBB=0")
set(OPENCOLORIO_DEFINITIONS "-DOCIO_STATIC_BUILD")
set(OPENIMAGEIO_IDIFF "${OPENIMAGEIO}/bin/idiff.exe")
add_definitions(-DOIIO_STATIC_BUILD)
add_definitions(-DOIIO_NO_SSE=1)
endif()
if(WITH_LLVM)
set(LLVM_ROOT_DIR ${LIBDIR}/llvm CACHE PATH "Path to the LLVM installation")
file(GLOB LLVM_LIBRARY_OPTIMIZED ${LLVM_ROOT_DIR}/lib/*.lib)
if(EXISTS ${LLVM_ROOT_DIR}/debug/lib)
foreach(LLVM_OPTIMIZED_LIB ${LLVM_LIBRARY_OPTIMIZED})
get_filename_component(LIBNAME ${LLVM_OPTIMIZED_LIB} ABSOLUTE)
list(APPEND LLVM_LIBS optimized ${LIBNAME})
endforeach(LLVM_OPTIMIZED_LIB)
file(GLOB LLVM_LIBRARY_DEBUG ${LLVM_ROOT_DIR}/debug/lib/*.lib)
foreach(LLVM_DEBUG_LIB ${LLVM_LIBRARY_DEBUG})
get_filename_component(LIBNAME ${LLVM_DEBUG_LIB} ABSOLUTE)
list(APPEND LLVM_LIBS debug ${LIBNAME})
endforeach(LLVM_DEBUG_LIB)
set(LLVM_LIBRARY ${LLVM_LIBS})
else()
message(WARNING "LLVM debug libs not present on this system. Using release libs for debug builds.")
set(LLVM_LIBRARY ${LLVM_LIBRARY_OPTIMIZED})
endif()
endif()
if(WITH_OPENCOLORIO)
set(OPENCOLORIO ${LIBDIR}/opencolorio)
set(OPENCOLORIO_INCLUDE_DIRS ${OPENCOLORIO}/include)
set(OPENCOLORIO_LIBRARIES OpenColorIO)
set(OPENCOLORIO_LIBPATH ${LIBDIR}/opencolorio/lib)
set(OPENCOLORIO_DEFINITIONS)
endif()
if(WITH_CYCLES_EMBREE)
find_package(Embree 3.2.4 REQUIRED)
endif()
if(WITH_OPENVDB)
set(BLOSC_LIBRARIES optimized ${LIBDIR}/blosc/lib/libblosc.lib debug ${LIBDIR}/blosc/lib/libblosc_d.lib)
set(TBB_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbb.lib debug ${LIBDIR}/tbb/lib/tbb_debug.lib)
set(TBB_INCLUDE_DIR ${LIBDIR}/tbb/include)
set(OPENVDB ${LIBDIR}/openvdb)
set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include ${TBB_INCLUDE_DIR})
set(OPENVDB_LIBRARIES optimized openvdb debug openvdb_d ${TBB_LIBRARIES} ${BLOSC_LIBRARIES})
set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib)
endif()
if(WITH_ALEMBIC)
set(ALEMBIC ${LIBDIR}/alembic)
set(ALEMBIC_INCLUDE_DIR ${ALEMBIC}/include)
set(ALEMBIC_INCLUDE_DIRS ${ALEMBIC_INCLUDE_DIR})
set(ALEMBIC_LIBPATH ${ALEMBIC}/lib)
set(ALEMBIC_LIBRARIES optimized alembic debug alembic_d)
set(ALEMBIC_FOUND 1)
endif()
if(WITH_MOD_CLOTH_ELTOPO)
set(LAPACK ${LIBDIR}/lapack)
# set(LAPACK_INCLUDE_DIR ${LAPACK}/include)
set(LAPACK_LIBPATH ${LAPACK}/lib)
set(LAPACK_LIBRARIES
${LIBDIR}/lapack/lib/libf2c.lib
${LIBDIR}/lapack/lib/clapack_nowrap.lib
${LIBDIR}/lapack/lib/BLAS_nowrap.lib
)
endif()
if(WITH_OPENSUBDIV OR WITH_CYCLES_OPENSUBDIV)
set(OPENSUBDIV_INCLUDE_DIR ${LIBDIR}/opensubdiv/include)
set(OPENSUBDIV_LIBPATH ${LIBDIR}/opensubdiv/lib)
set(OPENSUBDIV_LIBRARIES
optimized ${OPENSUBDIV_LIBPATH}/osdCPU.lib
optimized ${OPENSUBDIV_LIBPATH}/osdGPU.lib
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)
windows_find_package(OpenSubdiv)
endif()
if(WITH_SDL)
set(SDL ${LIBDIR}/sdl)
set(SDL_INCLUDE_DIR ${SDL}/include)
set(SDL_LIBPATH ${SDL}/lib)
set(SDL_LIBRARY SDL2)
endif()
# Audio IO
if(WITH_SYSTEM_AUDASPACE)
set(AUDASPACE_INCLUDE_DIRS ${LIBDIR}/audaspace/include/audaspace)
set(AUDASPACE_LIBRARIES ${LIBDIR}/audaspace/lib/audaspace.lib)
set(AUDASPACE_C_INCLUDE_DIRS ${LIBDIR}/audaspace/include/audaspace)
set(AUDASPACE_C_LIBRARIES ${LIBDIR}/audaspace/lib/audaspace-c.lib)
set(AUDASPACE_PY_INCLUDE_DIRS ${LIBDIR}/audaspace/include/audaspace)
set(AUDASPACE_PY_LIBRARIES ${LIBDIR}/audaspace/lib/audaspace-py.lib)
endif()
# used in many places so include globally, like OpenGL
blender_include_dirs_sys("${PTHREADS_INCLUDE_DIRS}")
#find signtool
set(ProgramFilesX86_NAME "ProgramFiles(x86)") #env dislikes the ( )
find_program(SIGNTOOL_EXE signtool
HINTS
"$ENV{${ProgramFilesX86_NAME}}/Windows Kits/10/bin/x86/"
"$ENV{ProgramFiles}/Windows Kits/10/bin/x86/"
"$ENV{${ProgramFilesX86_NAME}}/Windows Kits/8.1/bin/x86/"
"$ENV{ProgramFiles}/Windows Kits/8.1/bin/x86/"
"$ENV{${ProgramFilesX86_NAME}}/Windows Kits/8.0/bin/x86/"
"$ENV{ProgramFiles}/Windows Kits/8.0/bin/x86/"
)

View File

@ -217,6 +217,15 @@ if(WITH_CYCLES_OSL)
)
endif()
if(WITH_CYCLES_EMBREE)
add_definitions(-DWITH_EMBREE)
add_definitions(-DEMBREE_STATIC_LIB)
include_directories(
SYSTEM
${EMBREE_INCLUDE_DIRS}
)
endif()
if(WITH_CYCLES_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
include_directories(

View File

@ -81,6 +81,9 @@ macro(cycles_target_link_libraries target)
if(WITH_CYCLES_OSL)
target_link_libraries(${target} ${OSL_LIBRARIES} ${LLVM_LIBRARIES})
endif()
if(WITH_CYCLES_EMBREE)
target_link_libraries(${target} ${EMBREE_LIBRARIES})
endif()
if(WITH_CYCLES_OPENSUBDIV)
target_link_libraries(${target} ${OPENSUBDIV_LIBRARIES})
endif()

View File

@ -529,6 +529,11 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
items=enum_bvh_types,
default='DYNAMIC_BVH',
)
use_bvh_embree: BoolProperty(
name="Use Embree",
description="Use Embree as ray accelerator",
default=False,
)
debug_use_spatial_splits: BoolProperty(
name="Use Spatial Splits",
description="Use BVH spatial splits: longer builder time, faster render",

View File

@ -19,6 +19,7 @@
import bpy
from bpy_extras.node_utils import find_node_input
from bl_operators.presets import PresetMenu
import _cycles
from bpy.types import (
Panel,
@ -636,10 +637,15 @@ class CYCLES_RENDER_PT_performance_acceleration_structure(CyclesButtonsPanel, Pa
col = layout.column()
if _cycles.with_embree:
row = col.row()
row.active = use_cpu(context)
row.prop(cscene, "use_bvh_embree")
col.prop(cscene, "debug_use_spatial_splits")
col.active = not cscene.use_bvh_embree or not _cycles.with_embree
col.prop(cscene, "debug_use_hair_bvh")
sub = col.column()
sub.active = not cscene.debug_use_spatial_splits
sub.active = not cscene.debug_use_spatial_splits and not cscene.use_bvh_embree
sub.prop(cscene, "debug_bvh_time_steps")

View File

@ -848,5 +848,13 @@ void *CCL_python_module_init()
Py_INCREF(Py_False);
#endif /* WITH_NETWORK */
#ifdef WITH_EMBREE
PyModule_AddObject(mod, "with_embree", Py_True);
Py_INCREF(Py_True);
#else /* WITH_EMBREE */
PyModule_AddObject(mod, "with_embree", Py_False);
Py_INCREF(Py_False);
#endif /* WITH_EMBREE */
return (void*)mod;
}

View File

@ -687,6 +687,9 @@ SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene,
params.bvh_layout = DebugFlags().cpu.bvh_layout;
}
#ifdef WITH_EMBREE
params.bvh_layout = RNA_boolean_get(&cscene, "use_bvh_embree") ? BVH_LAYOUT_EMBREE : params.bvh_layout;
#endif
return params;
}

View File

@ -13,6 +13,7 @@ set(SRC
bvh8.cpp
bvh_binning.cpp
bvh_build.cpp
bvh_embree.cpp
bvh_node.cpp
bvh_sort.cpp
bvh_split.cpp
@ -26,6 +27,7 @@ set(SRC_HEADERS
bvh8.h
bvh_binning.h
bvh_build.h
bvh_embree.h
bvh_node.h
bvh_params.h
bvh_sort.h

View File

@ -26,6 +26,10 @@
#include "bvh/bvh_build.h"
#include "bvh/bvh_node.h"
#ifdef WITH_EMBREE
#include "bvh/bvh_embree.h"
#endif
#include "util/util_foreach.h"
#include "util/util_logging.h"
#include "util/util_progress.h"
@ -41,6 +45,7 @@ const char *bvh_layout_name(BVHLayout layout)
case BVH_LAYOUT_BVH4: return "BVH4";
case BVH_LAYOUT_BVH8: return "BVH8";
case BVH_LAYOUT_NONE: return "NONE";
case BVH_LAYOUT_EMBREE: return "EMBREE";
case BVH_LAYOUT_ALL: return "ALL";
}
LOG(DFATAL) << "Unsupported BVH layout was passed.";
@ -96,6 +101,10 @@ BVH *BVH::create(const BVHParams& params, const vector<Object*>& objects)
return new BVH4(params, objects);
case BVH_LAYOUT_BVH8:
return new BVH8(params, objects);
case BVH_LAYOUT_EMBREE:
#ifdef WITH_EMBREE
return new BVHEmbree(params, objects);
#endif
case BVH_LAYOUT_NONE:
case BVH_LAYOUT_ALL:
break;
@ -106,7 +115,7 @@ BVH *BVH::create(const BVHParams& params, const vector<Object*>& objects)
/* Building */
void BVH::build(Progress& progress)
void BVH::build(Progress& progress, Stats*)
{
progress.set_substatus("Building BVH");

View File

@ -25,6 +25,7 @@
CCL_NAMESPACE_BEGIN
class Stats;
class BVHNode;
struct BVHStackEntry;
class BVHParams;
@ -35,7 +36,6 @@ class Progress;
#define BVH_ALIGN 4096
#define TRI_NODE_SIZE 3
/* Packed BVH
*
* BVH stored as it will be used for traversal on the rendering device. */
@ -91,7 +91,7 @@ public:
static BVH *create(const BVHParams& params, const vector<Object*>& objects);
virtual ~BVH() {}
void build(Progress& progress);
virtual void build(Progress& progress, Stats *stats=NULL);
void refit(Progress& progress);
protected:

View File

@ -0,0 +1,884 @@
/*
* Copyright 2018, Blender Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* This class implemens a ray accelerator for Cycles using Intel's Embree library.
* It supports triangles, curves, object and deformation blur and instancing.
* Not supported are thick line segments, those have no native equivalent in Embree.
* They could be implemented using Embree's thick curves, at the expense of wasted memory.
* User defined intersections for Embree could also be an option, but since Embree only uses aligned BVHs
* for user geometry, this would come with reduced performance and/or higher memory usage.
*
* Since Embree allows object to be either curves or triangles but not both, Cycles object IDs are maapped
* to Embree IDs by multiplying by two and adding one for curves.
*
* This implementation shares RTCDevices between Cycles instances. Eventually each instance should get
* a separate RTCDevice to correctly keep track of memory usage.
*
* Vertex and index buffers are duplicated between Cycles device arrays and Embree. These could be merged,
* which would requrie changes to intersection refinement, shader setup, mesh light sampling and a few
* other places in Cycles where direct access to vertex data is required.
*/
#ifdef WITH_EMBREE
#include <pmmintrin.h>
#include <xmmintrin.h>
#include <embree3/rtcore_geometry.h>
#include "bvh/bvh_embree.h"
/* Kernel includes are necessary so that the filter function for Embree can access the packed BVH. */
#include "kernel/bvh/bvh_embree.h"
#include "kernel/kernel_compat_cpu.h"
#include "kernel/split/kernel_split_data_types.h"
#include "kernel/kernel_globals.h"
#include "kernel/kernel_random.h"
#include "render/mesh.h"
#include "render/object.h"
#include "util/util_foreach.h"
#include "util/util_logging.h"
#include "util/util_progress.h"
CCL_NAMESPACE_BEGIN
#define IS_HAIR(x) (x & 1)
/* This gets called by Embree at every valid ray/object intersection.
* Things like recording subsurface or shadow hits for later evaluation
* as well as filtering for volume objects happen here.
* Cycles' own BVH does that directly inside the traversal calls.
*/
static void rtc_filter_func(const RTCFilterFunctionNArguments *args)
{
/* Current implementation in Cycles assumes only single-ray intersection queries. */
assert(args->N == 1);
const RTCRay *ray = (RTCRay*)args->ray;
const RTCHit *hit = (RTCHit*)args->hit;
CCLIntersectContext *ctx = ((IntersectContext*)args->context)->userRayExt;
KernelGlobals *kg = ctx->kg;
/* Check if there is backfacing hair to ignore. */
if(IS_HAIR(hit->geomID) && (kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
&& !(kernel_data.curve.curveflags & CURVE_KN_BACKFACING)
&& !(kernel_data.curve.curveflags & CURVE_KN_RIBBONS)) {
if(dot(make_float3(ray->dir_x, ray->dir_y, ray->dir_z), make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z)) > 0.0f) {
*args->valid = 0;
return;
}
}
}
static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments* args)
{
assert(args->N == 1);
const RTCRay *ray = (RTCRay*)args->ray;
RTCHit *hit = (RTCHit*)args->hit;
CCLIntersectContext *ctx = ((IntersectContext*)args->context)->userRayExt;
KernelGlobals *kg = ctx->kg;
/* For all ray types: Check if there is backfacing hair to ignore */
if(IS_HAIR(hit->geomID) && (kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
&& !(kernel_data.curve.curveflags & CURVE_KN_BACKFACING)
&& !(kernel_data.curve.curveflags & CURVE_KN_RIBBONS)) {
if(dot(make_float3(ray->dir_x, ray->dir_y, ray->dir_z), make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z)) > 0.0f) {
*args->valid = 0;
return;
}
}
switch(ctx->type) {
case CCLIntersectContext::RAY_SHADOW_ALL: {
/* Append the intersection to the end of the array. */
if(ctx->num_hits < ctx->max_hits) {
Intersection current_isect;
kernel_embree_convert_hit(kg, ray, hit, &current_isect);
for(size_t i = 0; i < ctx->max_hits; ++i) {
if(current_isect.object == ctx->isect_s[i].object &&
current_isect.prim == ctx->isect_s[i].prim &&
current_isect.t == ctx->isect_s[i].t) {
/* This intersection was already recorded, skip it. */
*args->valid = 0;
break;
}
}
Intersection *isect = &ctx->isect_s[ctx->num_hits];
++ctx->num_hits;
*isect = current_isect;
int prim = kernel_tex_fetch(__prim_index, isect->prim);
int shader = 0;
if(kernel_tex_fetch(__prim_type, isect->prim) & PRIMITIVE_ALL_TRIANGLE) {
shader = kernel_tex_fetch(__tri_shader, prim);
}
else {
float4 str = kernel_tex_fetch(__curves, prim);
shader = __float_as_int(str.z);
}
int flag = kernel_tex_fetch(__shaders, shader & SHADER_MASK).flags;
/* If no transparent shadows, all light is blocked. */
if(flag & (SD_HAS_TRANSPARENT_SHADOW)) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
}
}
else {
/* Increase the number of hits beyond ray.max_hits
* so that the caller can detect this as opaque. */
++ctx->num_hits;
}
break;
}
case CCLIntersectContext::RAY_SSS: {
/* No intersection information requested, just return a hit. */
if(ctx->max_hits == 0) {
break;
}
/* See triangle_intersect_subsurface() for the native equivalent. */
for(int i = min(ctx->max_hits, ctx->ss_isect->num_hits) - 1; i >= 0; --i) {
if(ctx->ss_isect->hits[i].t == ray->tfar) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
break;
}
}
++ctx->ss_isect->num_hits;
int hit_idx;
if(ctx->ss_isect->num_hits <= ctx->max_hits) {
hit_idx = ctx->ss_isect->num_hits - 1;
}
else {
/* reservoir sampling: if we are at the maximum number of
* hits, randomly replace element or skip it */
hit_idx = lcg_step_uint(ctx->lcg_state) % ctx->ss_isect->num_hits;
if(hit_idx >= ctx->max_hits) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
break;
}
}
/* record intersection */
kernel_embree_convert_local_hit(kg, ray, hit, &ctx->ss_isect->hits[hit_idx], ctx->sss_object_id);
ctx->ss_isect->Ng[hit_idx].x = hit->Ng_x;
ctx->ss_isect->Ng[hit_idx].y = hit->Ng_y;
ctx->ss_isect->Ng[hit_idx].z = hit->Ng_z;
ctx->ss_isect->Ng[hit_idx] = normalize(ctx->ss_isect->Ng[hit_idx]);
/* This tells Embree to continue tracing .*/
*args->valid = 0;
break;
}
case CCLIntersectContext::RAY_VOLUME_ALL: {
/* Append the intersection to the end of the array. */
if(ctx->num_hits < ctx->max_hits) {
Intersection current_isect;
kernel_embree_convert_hit(kg, ray, hit, &current_isect);
for(size_t i = 0; i < ctx->max_hits; ++i) {
if(current_isect.object == ctx->isect_s[i].object &&
current_isect.prim == ctx->isect_s[i].prim &&
current_isect.t == ctx->isect_s[i].t) {
/* This intersection was already recorded, skip it. */
*args->valid = 0;
break;
}
}
Intersection *isect = &ctx->isect_s[ctx->num_hits];
++ctx->num_hits;
*isect = current_isect;
/* Only primitives from volume object. */
uint tri_object = (isect->object == OBJECT_NONE) ?
kernel_tex_fetch(__prim_object, isect->prim) : isect->object;
int object_flag = kernel_tex_fetch(__object_flag, tri_object);
if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
--ctx->num_hits;
}
/* This tells Embree to continue tracing. */
*args->valid = 0;
break;
}
}
case CCLIntersectContext::RAY_REGULAR:
default:
/* Nothing to do here. */
break;
}
}
static size_t unaccounted_mem = 0;
static bool rtc_memory_monitor_func(void* userPtr, const ssize_t bytes, const bool)
{
Stats *stats = (Stats*)userPtr;
if(stats) {
if(bytes > 0) {
stats->mem_alloc(bytes);
}
else {
stats->mem_free(-bytes);
}
}
else {
/* A stats pointer may not yet be available. Keep track of the memory usage for later. */
if(bytes >= 0) {
atomic_add_and_fetch_z(&unaccounted_mem, bytes);
}
else {
atomic_sub_and_fetch_z(&unaccounted_mem, -bytes);
}
}
return true;
}
static void rtc_error_func(void*, enum RTCError, const char* str)
{
VLOG(1) << str;
}
static double progress_start_time = 0.0f;
static bool rtc_progress_func(void* user_ptr, const double n)
{
Progress *progress = (Progress*)user_ptr;
if(time_dt() - progress_start_time < 0.25) {
return true;
}
string msg = string_printf("Building BVH %.0f%%", n * 100.0);
progress->set_substatus(msg);
progress_start_time = time_dt();
return !progress->get_cancel();
}
/* This is to have a shared device between all BVH instances.
It would be useful to actually to use a separte RTCDevice per Cycles instance. */
RTCDevice BVHEmbree::rtc_shared_device = NULL;
int BVHEmbree::rtc_shared_users = 0;
thread_mutex BVHEmbree::rtc_shared_mutex;
BVHEmbree::BVHEmbree(const BVHParams& params_, const vector<Object*>& objects_)
: BVH(params_, objects_), scene(NULL), mem_used(0), top_level(NULL), stats(NULL),
curve_subdivisions(params.curve_subdivisions), build_quality(RTC_BUILD_QUALITY_REFIT),
use_curves(params_.curve_flags & CURVE_KN_INTERPOLATE),
use_ribbons(params.curve_flags & CURVE_KN_RIBBONS), dynamic_scene(true)
{
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
thread_scoped_lock lock(rtc_shared_mutex);
if(rtc_shared_users == 0) {
rtc_shared_device = rtcNewDevice("verbose=0");
/* Check here if Embree was built with the correct flags. */
ssize_t ret = rtcGetDeviceProperty (rtc_shared_device,RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED);
if(ret != 1) {
assert(0);
VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED flag."\
"Ray visiblity will not work.";
}
ret = rtcGetDeviceProperty (rtc_shared_device,RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED);
if(ret != 1) {
assert(0);
VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED flag."\
"Renders may not look as expected.";
}
ret = rtcGetDeviceProperty (rtc_shared_device,RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED);
if(ret != 1) {
assert(0);
VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED flag. "\
"Line primitives will not be rendered.";
}
ret = rtcGetDeviceProperty (rtc_shared_device,RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED);
if(ret != 1) {
assert(0);
VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED flag. "\
"Triangle primitives will not be rendered.";
}
ret = rtcGetDeviceProperty (rtc_shared_device,RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED);
if(ret != 0) {
assert(0);
VLOG(1) << "Embree is compiled with the RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED flag. "\
"Renders may not look as expected.";
}
}
++rtc_shared_users;
rtcSetDeviceErrorFunction(rtc_shared_device, rtc_error_func, NULL);
pack.root_index = -1;
}
BVHEmbree::~BVHEmbree()
{
if(!params.top_level) {
destroy(scene);
}
}
void BVHEmbree::destroy(RTCScene scene)
{
if(scene) {
rtcReleaseScene(scene);
scene = NULL;
}
thread_scoped_lock lock(rtc_shared_mutex);
--rtc_shared_users;
if(rtc_shared_users == 0) {
rtcReleaseDevice (rtc_shared_device);
rtc_shared_device = NULL;
}
}
void BVHEmbree::delete_rtcScene()
{
if(scene) {
/* When this BVH is used as an instance in a top level BVH, don't delete now
* Let the top_level BVH know that it should delete it later. */
if(top_level) {
top_level->add_delayed_delete_scene(scene);
}
else {
rtcReleaseScene(scene);
if(delayed_delete_scenes.size()) {
foreach(RTCScene s, delayed_delete_scenes) {
rtcReleaseScene(s);
}
}
delayed_delete_scenes.clear();
}
scene = NULL;
}
}
void BVHEmbree::build(Progress& progress, Stats *stats_)
{
assert(rtc_shared_device);
stats = stats_;
rtcSetDeviceMemoryMonitorFunction(rtc_shared_device, rtc_memory_monitor_func, stats);
progress.set_substatus("Building BVH");
if(scene) {
rtcReleaseScene(scene);
scene = NULL;
}
const bool dynamic = params.bvh_type == SceneParams::BVH_DYNAMIC;
scene = rtcNewScene(rtc_shared_device);
const RTCSceneFlags scene_flags = (dynamic ? RTC_SCENE_FLAG_DYNAMIC : RTC_SCENE_FLAG_NONE) |
RTC_SCENE_FLAG_COMPACT | RTC_SCENE_FLAG_ROBUST;
rtcSetSceneFlags(scene, scene_flags);
build_quality = dynamic ? RTC_BUILD_QUALITY_LOW :
(params.use_spatial_split ? RTC_BUILD_QUALITY_HIGH : RTC_BUILD_QUALITY_MEDIUM);
rtcSetSceneBuildQuality(scene, build_quality);
int i = 0;
pack.object_node.clear();
foreach(Object *ob, objects) {
if(params.top_level) {
if(!ob->is_traceable()) {
++i;
continue;
}
if(!ob->mesh->is_instanced()) {
add_object(ob, i);
}
else {
add_instance(ob, i);
}
}
else {
add_object(ob, i);
}
++i;
if(progress.get_cancel()) return;
}
if(progress.get_cancel()) {
delete_rtcScene();
stats = NULL;
return;
}
rtcSetSceneProgressMonitorFunction(scene, rtc_progress_func, &progress);
rtcCommitScene(scene);
pack_primitives();
if(progress.get_cancel()) {
delete_rtcScene();
stats = NULL;
return;
}
progress.set_substatus("Packing geometry");
pack_nodes(NULL);
stats = NULL;
}
void BVHEmbree::add_object(Object *ob, int i)
{
Mesh *mesh = ob->mesh;
if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && mesh->num_triangles() > 0) {
add_triangles(ob, i);
}
if(params.primitive_mask & PRIMITIVE_ALL_CURVE && mesh->num_curves() > 0) {
add_curves(ob, i);
}
}
void BVHEmbree::add_instance(Object *ob, int i)
{
if(!ob || !ob->mesh) {
assert(0);
return;
}
BVHEmbree *instance_bvh = (BVHEmbree*)(ob->mesh->bvh);
if(instance_bvh->top_level != this) {
instance_bvh->top_level = this;
}
const size_t num_motion_steps = ob->use_motion() ? ob->motion.size() : 1;
RTCGeometry geom_id = rtcNewGeometry(rtc_shared_device, RTC_GEOMETRY_TYPE_INSTANCE);
rtcSetGeometryInstancedScene(geom_id, instance_bvh->scene);
rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
if(ob->use_motion()) {
for(size_t step = 0; step < num_motion_steps; ++step) {
rtcSetGeometryTransform(geom_id, step, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (const float*)&ob->motion[step]);
}
}
else {
rtcSetGeometryTransform(geom_id, 0, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (const float*)&ob->tfm);
}
pack.prim_index.push_back_slow(-1);
pack.prim_object.push_back_slow(i);
pack.prim_type.push_back_slow(PRIMITIVE_NONE);
pack.prim_tri_index.push_back_slow(-1);
rtcSetGeometryUserData(geom_id, (void*) instance_bvh->scene);
rtcSetGeometryMask(geom_id, ob->visibility);
rtcCommitGeometry(geom_id);
rtcAttachGeometryByID(scene, geom_id, i*2);
rtcReleaseGeometry(geom_id);
}
void BVHEmbree::add_triangles(Object *ob, int i)
{
size_t prim_offset = pack.prim_index.size();
Mesh *mesh = ob->mesh;
const Attribute *attr_mP = NULL;
size_t num_motion_steps = 1;
if(mesh->has_motion_blur()) {
attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if(attr_mP) {
num_motion_steps = mesh->motion_steps;
if(num_motion_steps > RTC_MAX_TIME_STEP_COUNT) {
assert(0);
num_motion_steps = RTC_MAX_TIME_STEP_COUNT;
}
}
}
const size_t num_triangles = mesh->num_triangles();
RTCGeometry geom_id = rtcNewGeometry(rtc_shared_device, RTC_GEOMETRY_TYPE_TRIANGLE);
rtcSetGeometryBuildQuality(geom_id, build_quality);
rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
unsigned *rtc_indices = (unsigned*)rtcSetNewGeometryBuffer(geom_id, RTC_BUFFER_TYPE_INDEX, 0,
RTC_FORMAT_UINT3, sizeof (int) * 3, num_triangles);
assert(rtc_indices);
if(!rtc_indices) {
VLOG(1) << "Embree could not create new geometry buffer for mesh " << mesh->name.c_str() << ".\n";
return;
}
for(size_t j = 0; j < num_triangles; ++j) {
Mesh::Triangle t = mesh->get_triangle(j);
rtc_indices[j*3] = t.v[0];
rtc_indices[j*3+1] = t.v[1];
rtc_indices[j*3+2] = t.v[2];
}
update_tri_vertex_buffer(geom_id, mesh);
pack.prim_object.reserve(pack.prim_object.size() + num_triangles);
pack.prim_type.reserve(pack.prim_type.size() + num_triangles);
pack.prim_index.reserve(pack.prim_index.size() + num_triangles);
pack.prim_tri_index.reserve(pack.prim_index.size() + num_triangles);
for(size_t j = 0; j < num_triangles; ++j) {
pack.prim_object.push_back_reserved(i);
pack.prim_type.push_back_reserved(num_motion_steps > 1 ? PRIMITIVE_MOTION_TRIANGLE : PRIMITIVE_TRIANGLE);
pack.prim_index.push_back_reserved(j);
pack.prim_tri_index.push_back_reserved(j);
}
rtcSetGeometryUserData(geom_id, (void*) prim_offset);
rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func);
rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
rtcSetGeometryMask(geom_id, ob->visibility);
rtcCommitGeometry(geom_id);
rtcAttachGeometryByID(scene, geom_id, i*2);
rtcReleaseGeometry(geom_id);
}
void BVHEmbree::update_tri_vertex_buffer(RTCGeometry geom_id, const Mesh* mesh)
{
const Attribute *attr_mP = NULL;
size_t num_motion_steps = 1;
int t_mid = 0;
if(mesh->has_motion_blur()) {
attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if(attr_mP) {
num_motion_steps = mesh->motion_steps;
t_mid = (num_motion_steps - 1) / 2;
if(num_motion_steps > RTC_MAX_TIME_STEP_COUNT) {
assert(0);
num_motion_steps = RTC_MAX_TIME_STEP_COUNT;
}
}
}
const size_t num_verts = mesh->verts.size();
for(int t = 0; t < num_motion_steps; ++t) {
const float3 *verts;
if(t == t_mid) {
verts = &mesh->verts[0];
}
else {
int t_ = (t > t_mid) ? (t - 1) : t;
verts = &attr_mP->data_float3()[t_ * num_verts];
}
float *rtc_verts = (float*) rtcSetNewGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t,
RTC_FORMAT_FLOAT3, sizeof(float) * 3, num_verts + 1);
assert(rtc_verts);
if(rtc_verts) {
for(size_t j = 0; j < num_verts; ++j) {
rtc_verts[0] = verts[j].x;
rtc_verts[1] = verts[j].y;
rtc_verts[2] = verts[j].z;
rtc_verts += 3;
}
}
}
}
void BVHEmbree::update_curve_vertex_buffer(RTCGeometry geom_id, const Mesh* mesh)
{
const Attribute *attr_mP = NULL;
size_t num_motion_steps = 1;
if(mesh->has_motion_blur()) {
attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if(attr_mP) {
num_motion_steps = mesh->motion_steps;
}
}
const size_t num_curves = mesh->num_curves();
size_t num_keys = 0;
for(size_t j = 0; j < num_curves; ++j) {
const Mesh::Curve c = mesh->get_curve(j);
num_keys += c.num_keys;
}
/* Copy the CV data to Embree */
const int t_mid = (num_motion_steps - 1) / 2;
const float *curve_radius = &mesh->curve_radius[0];
for(int t = 0; t < num_motion_steps; ++t) {
const float3 *verts;
if(t == t_mid || attr_mP == NULL) {
verts = &mesh->curve_keys[0];
}
else {
int t_ = (t > t_mid) ? (t - 1) : t;
verts = &attr_mP->data_float3()[t_ * num_keys];
}
float4 *rtc_verts = (float4*)rtcSetNewGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t,
RTC_FORMAT_FLOAT4, sizeof (float) * 4, num_keys);
float4 *rtc_tangents = NULL;
if(use_curves) {
rtc_tangents = (float4*)rtcSetNewGeometryBuffer(geom_id, RTC_BUFFER_TYPE_TANGENT, t,
RTC_FORMAT_FLOAT4, sizeof (float) * 4, num_keys);
assert(rtc_tangents);
}
assert(rtc_verts);
if(rtc_verts) {
if(use_curves && rtc_tangents) {
const size_t num_curves = mesh->num_curves();
for(size_t j = 0; j < num_curves; ++j) {
Mesh::Curve c = mesh->get_curve(j);
int fk = c.first_key;
rtc_verts[0] = float3_to_float4(verts[fk]);
rtc_verts[0].w = curve_radius[fk];
rtc_tangents[0] = float3_to_float4(verts[fk + 1] - verts[fk]);
rtc_tangents[0].w = curve_radius[fk + 1] - curve_radius[fk];
++fk;
int k = 1;
for(;k < c.num_segments(); ++k, ++fk) {
rtc_verts[k] = float3_to_float4(verts[fk]);
rtc_verts[k].w = curve_radius[fk];
rtc_tangents[k] = float3_to_float4((verts[fk + 1] - verts[fk - 1]) * 0.5f);
rtc_tangents[k].w = (curve_radius[fk + 1] - curve_radius[fk - 1]) * 0.5f;
}
rtc_verts[k] = float3_to_float4(verts[fk]);
rtc_verts[k].w = curve_radius[fk];
rtc_tangents[k] = float3_to_float4(verts[fk] - verts[fk - 1]);
rtc_tangents[k].w = curve_radius[fk] - curve_radius[fk - 1];
rtc_verts += c.num_keys;
rtc_tangents += c.num_keys;
}
}
else {
for(size_t j = 0; j < num_keys; ++j) {
rtc_verts[j] = float3_to_float4(verts[j]);
rtc_verts[j].w = curve_radius[j];
}
}
}
}
}
void BVHEmbree::add_curves(Object *ob, int i)
{
size_t prim_offset = pack.prim_index.size();
const Mesh *mesh = ob->mesh;
const Attribute *attr_mP = NULL;
size_t num_motion_steps = 1;
if(mesh->has_motion_blur()) {
attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if(attr_mP) {
num_motion_steps = mesh->motion_steps;
}
}
const size_t num_curves = mesh->num_curves();
size_t num_segments = 0;
for(size_t j = 0; j < num_curves; ++j) {
Mesh::Curve c = mesh->get_curve(j);
assert(c.num_segments() > 0);
num_segments += c.num_segments();
}
/* Make room for Cycles specific data. */
pack.prim_object.reserve(pack.prim_object.size() + num_segments);
pack.prim_type.reserve(pack.prim_type.size() + num_segments);
pack.prim_index.reserve(pack.prim_index.size() + num_segments);
pack.prim_tri_index.reserve(pack.prim_index.size() + num_segments);
enum RTCGeometryType type = (!use_curves) ? RTC_GEOMETRY_TYPE_FLAT_LINEAR_CURVE :
(use_ribbons ? RTC_GEOMETRY_TYPE_FLAT_HERMITE_CURVE :
RTC_GEOMETRY_TYPE_ROUND_HERMITE_CURVE);
RTCGeometry geom_id = rtcNewGeometry(rtc_shared_device, type);
rtcSetGeometryTessellationRate(geom_id, curve_subdivisions);
unsigned *rtc_indices = (unsigned*) rtcSetNewGeometryBuffer(geom_id, RTC_BUFFER_TYPE_INDEX, 0,
RTC_FORMAT_UINT, sizeof (int), num_segments);
size_t rtc_index = 0;
for(size_t j = 0; j < num_curves; ++j) {
Mesh::Curve c = mesh->get_curve(j);
for(size_t k = 0; k < c.num_segments(); ++k) {
rtc_indices[rtc_index] = c.first_key + k;
/* Cycles specific data. */
pack.prim_object.push_back_reserved(i);
pack.prim_type.push_back_reserved(PRIMITIVE_PACK_SEGMENT(num_motion_steps > 1 ?
PRIMITIVE_MOTION_CURVE : PRIMITIVE_CURVE, k));
pack.prim_index.push_back_reserved(j);
pack.prim_tri_index.push_back_reserved(rtc_index);
++rtc_index;
}
}
rtcSetGeometryBuildQuality(geom_id, build_quality);
rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
update_curve_vertex_buffer(geom_id, mesh);
rtcSetGeometryUserData(geom_id, (void*) prim_offset);
rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func);
rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
rtcSetGeometryMask(geom_id, ob->visibility);
rtcCommitGeometry(geom_id);
rtcAttachGeometryByID(scene, geom_id, i * 2 + 1);
rtcReleaseGeometry(geom_id);
}
void BVHEmbree::pack_nodes(const BVHNode *)
{
/* Quite a bit of this code is for compatibility with Cycles' native BVH. */
if(!params.top_level) {
return;
}
for(size_t i = 0; i < pack.prim_index.size(); ++i) {
if(pack.prim_index[i] != -1) {
if(pack.prim_type[i] & PRIMITIVE_ALL_CURVE)
pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->curve_offset;
else
pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset;
}
}
size_t prim_offset = pack.prim_index.size();
/* reserve */
size_t prim_index_size = pack.prim_index.size();
size_t prim_tri_verts_size = pack.prim_tri_verts.size();
size_t pack_prim_index_offset = prim_index_size;
size_t pack_prim_tri_verts_offset = prim_tri_verts_size;
size_t object_offset = 0;
map<Mesh*, int> mesh_map;
foreach(Object *ob, objects) {
Mesh *mesh = ob->mesh;
BVH *bvh = mesh->bvh;
if(mesh->need_build_bvh()) {
if(mesh_map.find(mesh) == mesh_map.end()) {
prim_index_size += bvh->pack.prim_index.size();
prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
mesh_map[mesh] = 1;
}
}
}
mesh_map.clear();
pack.prim_index.resize(prim_index_size);
pack.prim_type.resize(prim_index_size);
pack.prim_object.resize(prim_index_size);
pack.prim_visibility.clear();
pack.prim_tri_verts.resize(prim_tri_verts_size);
pack.prim_tri_index.resize(prim_index_size);
pack.object_node.resize(objects.size());
int *pack_prim_index = (pack.prim_index.size())? &pack.prim_index[0]: NULL;
int *pack_prim_type = (pack.prim_type.size())? &pack.prim_type[0]: NULL;
int *pack_prim_object = (pack.prim_object.size())? &pack.prim_object[0]: NULL;
float4 *pack_prim_tri_verts = (pack.prim_tri_verts.size())? &pack.prim_tri_verts[0]: NULL;
uint *pack_prim_tri_index = (pack.prim_tri_index.size())? &pack.prim_tri_index[0]: NULL;
/* merge */
foreach(Object *ob, objects) {
Mesh *mesh = ob->mesh;
/* We assume that if mesh doesn't need own BVH it was already included
* into a top-level BVH and no packing here is needed.
*/
if(!mesh->need_build_bvh()) {
pack.object_node[object_offset++] = prim_offset;
continue;
}
/* if mesh already added once, don't add it again, but used set
* node offset for this object */
map<Mesh*, int>::iterator it = mesh_map.find(mesh);
if(mesh_map.find(mesh) != mesh_map.end()) {
int noffset = it->second;
pack.object_node[object_offset++] = noffset;
continue;
}
BVHEmbree *bvh = (BVHEmbree*)mesh->bvh;
rtc_memory_monitor_func(stats, unaccounted_mem, true);
unaccounted_mem = 0;
int mesh_tri_offset = mesh->tri_offset;
int mesh_curve_offset = mesh->curve_offset;
/* fill in node indexes for instances */
pack.object_node[object_offset++] = prim_offset;
mesh_map[mesh] = pack.object_node[object_offset-1];
/* merge primitive, object and triangle indexes */
if(bvh->pack.prim_index.size()) {
size_t bvh_prim_index_size = bvh->pack.prim_index.size();
int *bvh_prim_index = &bvh->pack.prim_index[0];
int *bvh_prim_type = &bvh->pack.prim_type[0];
uint *bvh_prim_tri_index = &bvh->pack.prim_tri_index[0];
for(size_t i = 0; i < bvh_prim_index_size; ++i) {
if(bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_curve_offset;
pack_prim_tri_index[pack_prim_index_offset] = -1;
}
else {
pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
pack_prim_tri_index[pack_prim_index_offset] =
bvh_prim_tri_index[i] + pack_prim_tri_verts_offset;
}
pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i];
pack_prim_object[pack_prim_index_offset] = 0;
++pack_prim_index_offset;
}
}
/* Merge triangle vertices data. */
if(bvh->pack.prim_tri_verts.size()) {
const size_t prim_tri_size = bvh->pack.prim_tri_verts.size();
memcpy(pack_prim_tri_verts + pack_prim_tri_verts_offset,
&bvh->pack.prim_tri_verts[0],
prim_tri_size*sizeof(float4));
pack_prim_tri_verts_offset += prim_tri_size;
}
prim_offset += bvh->pack.prim_index.size();
}
}
void BVHEmbree::refit_nodes()
{
/* Update all vertex buffers, then tell Embree to rebuild/-fit the BVHs. */
unsigned geom_id = 0;
foreach(Object *ob, objects) {
if(!params.top_level || (ob->is_traceable() && !ob->mesh->is_instanced())) {
if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && ob->mesh->num_triangles() > 0) {
update_tri_vertex_buffer(rtcGetGeometry(scene, geom_id), ob->mesh);
rtcCommitGeometry(rtcGetGeometry(scene,geom_id));
}
if(params.primitive_mask & PRIMITIVE_ALL_CURVE && ob->mesh->num_curves() > 0) {
update_curve_vertex_buffer(rtcGetGeometry(scene, geom_id+1), ob->mesh);
rtcCommitGeometry(rtcGetGeometry(scene,geom_id+1));
}
}
geom_id += 2;
}
rtcCommitScene(scene);
}
CCL_NAMESPACE_END
#endif /* WITH_EMBREE */

View File

@ -0,0 +1,79 @@
/*
* Copyright 2018, Blender Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __BVH_EMBREE_H__
#define __BVH_EMBREE_H__
#ifdef WITH_EMBREE
#include <embree3/rtcore.h>
#include <embree3/rtcore_scene.h>
#include "bvh/bvh.h"
#include "bvh/bvh_params.h"
#include "util/util_thread.h"
#include "util/util_types.h"
#include "util/util_vector.h"
CCL_NAMESPACE_BEGIN
class Mesh;
class BVHEmbree : public BVH
{
public:
virtual void build(Progress& progress, Stats *stats) override;
virtual ~BVHEmbree();
RTCScene scene;
static void destroy(RTCScene);
protected:
friend class BVH;
BVHEmbree(const BVHParams& params, const vector<Object*>& objects);
virtual void pack_nodes(const BVHNode*) override;
virtual void refit_nodes() override;
void add_object(Object *ob, int i);
void add_instance(Object *ob, int i);
void add_curves(Object *ob, int i);
void add_triangles(Object *ob, int i);
ssize_t mem_used;
void add_delayed_delete_scene(RTCScene scene) { delayed_delete_scenes.push_back(scene); }
BVHEmbree *top_level;
private:
void delete_rtcScene();
void update_tri_vertex_buffer(RTCGeometry geom_id, const Mesh* mesh);
void update_curve_vertex_buffer(RTCGeometry geom_id, const Mesh* mesh);
static RTCDevice rtc_shared_device;
static int rtc_shared_users;
static thread_mutex rtc_shared_mutex;
Stats *stats;
vector<RTCScene> delayed_delete_scenes;
int curve_subdivisions;
enum RTCBuildQuality build_quality;
bool use_curves, use_ribbons, dynamic_scene;
};
CCL_NAMESPACE_END
#endif /* WITH_EMBREE */
#endif /* __BVH_EMBREE_H__ */

View File

@ -90,6 +90,13 @@ public:
/* Same as above, but for triangle primitives. */
int num_motion_triangle_steps;
/* Same as in SceneParams. */
int bvh_type;
/* These are needed for Embree. */
int curve_flags;
int curve_subdivisions;
/* fixed parameters */
enum {
MAX_DEPTH = 64,
@ -123,6 +130,11 @@ public:
num_motion_curve_steps = 0;
num_motion_triangle_steps = 0;
bvh_type = 0;
curve_flags = 0;
curve_subdivisions = 4;
}
/* SAH costs */

View File

@ -132,6 +132,12 @@ if(CYCLES_STANDALONE_REPOSITORY)
set(BOOST_LIBPATH ${Boost_LIBRARY_DIRS})
set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB")
####
# embree
if(WITH_CYCLES_EMBREE)
find_package(embree 3.2.4 REQUIRED)
endif()
####
# Logging
if(WITH_CYCLES_LOGGING)

View File

@ -286,6 +286,9 @@ public:
if(DebugFlags().cpu.has_avx2() && system_cpu_support_avx2()) {
bvh_layout_mask |= BVH_LAYOUT_BVH8;
}
#ifdef WITH_EMBREE
bvh_layout_mask |= BVH_LAYOUT_EMBREE;
#endif /* WITH_EMBREE */
return bvh_layout_mask;
}
@ -702,6 +705,9 @@ public:
int start_sample = tile.start_sample;
int end_sample = tile.start_sample + tile.num_samples;
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
for(int sample = start_sample; sample < end_sample; sample++) {
if(task.get_cancel() || task_pool.canceled()) {
if(task.need_finish_queue == false)

View File

@ -82,6 +82,7 @@ set(SRC_BVH_HEADERS
bvh/obvh_traversal.h
bvh/obvh_volume.h
bvh/obvh_volume_all.h
bvh/bvh_embree.h
)
set(SRC_HEADERS

View File

@ -25,6 +25,10 @@
* the code has been extended and modified to support more primitives and work
* with CPU/CUDA/OpenCL. */
#ifdef __EMBREE__
#include "kernel/bvh/bvh_embree.h"
#endif
CCL_NAMESPACE_BEGIN
#include "kernel/bvh/bvh_types.h"
@ -185,6 +189,21 @@ ccl_device_intersect bool scene_intersect(KernelGlobals *kg,
if (!scene_intersect_valid(&ray)) {
return false;
}
#ifdef __EMBREE__
if(kernel_data.bvh.scene) {
isect->t = ray.t;
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_REGULAR);
IntersectContext rtc_ctx(&ctx);
RTCRayHit ray_hit;
kernel_embree_setup_rayhit(ray, ray_hit, visibility);
rtcIntersect1(kernel_data.bvh.scene, &rtc_ctx.context, &ray_hit);
if(ray_hit.hit.geomID != RTC_INVALID_GEOMETRY_ID && ray_hit.hit.primID != RTC_INVALID_GEOMETRY_ID) {
kernel_embree_convert_hit(kg, &ray_hit.ray, &ray_hit.hit, isect);
return true;
}
return false;
}
#endif /* __EMBREE__ */
#ifdef __OBJECT_MOTION__
if(kernel_data.bvh.have_motion) {
# ifdef __HAIR__
@ -232,6 +251,55 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals *kg,
if (!scene_intersect_valid(&ray)) {
return false;
}
#ifdef __EMBREE__
if(kernel_data.bvh.scene) {
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_SSS);
ctx.lcg_state = lcg_state;
ctx.max_hits = max_hits;
ctx.ss_isect = local_isect;
local_isect->num_hits = 0;
ctx.sss_object_id = local_object;
IntersectContext rtc_ctx(&ctx);
RTCRay rtc_ray;
kernel_embree_setup_ray(ray, rtc_ray, PATH_RAY_ALL_VISIBILITY);
/* Get the Embree scene for this intersection. */
RTCGeometry geom = rtcGetGeometry(kernel_data.bvh.scene, local_object * 2);
if(geom) {
Transform ob_itfm;
float3 P = ray.P;
float3 dir = ray.D;
float3 idir = ray.D;
const int object_flag = kernel_tex_fetch(__object_flag, local_object);
if(!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
Transform ob_itfm;
rtc_ray.tfar = bvh_instance_motion_push(kg,
local_object,
&ray,
&P,
&dir,
&idir,
ray.t,
&ob_itfm);
/* bvh_instance_motion_push() returns the inverse transform but it's not needed here. */
(void)ob_itfm;
rtc_ray.org_x = P.x;
rtc_ray.org_y = P.y;
rtc_ray.org_z = P.z;
rtc_ray.dir_x = dir.x;
rtc_ray.dir_y = dir.y;
rtc_ray.dir_z = dir.z;
}
RTCScene scene = (RTCScene)rtcGetGeometryUserData(geom);
if(scene) {
rtcOccluded1(scene, &rtc_ctx.context, &rtc_ray);
}
}
return local_isect->num_hits > 0;
}
#endif /* __EMBREE__ */
#ifdef __OBJECT_MOTION__
if(kernel_data.bvh.have_motion) {
return bvh_intersect_local_motion(kg,
@ -262,6 +330,24 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg,
if (!scene_intersect_valid(ray)) {
return false;
}
# ifdef __EMBREE__
if(kernel_data.bvh.scene) {
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_SHADOW_ALL);
ctx.isect_s = isect;
ctx.max_hits = max_hits;
ctx.num_hits = 0;
IntersectContext rtc_ctx(&ctx);
RTCRay rtc_ray;
kernel_embree_setup_ray(*ray, rtc_ray, PATH_RAY_SHADOW);
rtcOccluded1(kernel_data.bvh.scene, &rtc_ctx.context, &rtc_ray);
if(ctx.num_hits > max_hits) {
return true;
}
*num_hits = ctx.num_hits;
return rtc_ray.tfar == -INFINITY;
}
# endif
# ifdef __OBJECT_MOTION__
if(kernel_data.bvh.have_motion) {
# ifdef __HAIR__
@ -355,6 +441,19 @@ ccl_device_intersect uint scene_intersect_volume_all(KernelGlobals *kg,
if (!scene_intersect_valid(ray)) {
return false;
}
# ifdef __EMBREE__
if(kernel_data.bvh.scene) {
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_VOLUME_ALL);
ctx.isect_s = isect;
ctx.max_hits = max_hits;
ctx.num_hits = 0;
IntersectContext rtc_ctx(&ctx);
RTCRay rtc_ray;
kernel_embree_setup_ray(*ray, rtc_ray, visibility);
rtcOccluded1(kernel_data.bvh.scene, &rtc_ctx.context, &rtc_ray);
return rtc_ray.tfar == -INFINITY;
}
# endif
# ifdef __OBJECT_MOTION__
if(kernel_data.bvh.have_motion) {
return bvh_intersect_volume_all_motion(kg, ray, isect, max_hits, visibility);

View File

@ -0,0 +1,126 @@
/*
* Copyright 2018, Blender Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <embree3/rtcore_ray.h>
#include <embree3/rtcore_scene.h>
#include "kernel/kernel_compat_cpu.h"
#include "kernel/split/kernel_split_data_types.h"
#include "kernel/kernel_globals.h"
#include "util/util_vector.h"
CCL_NAMESPACE_BEGIN
struct CCLIntersectContext {
typedef enum {
RAY_REGULAR = 0,
RAY_SHADOW_ALL = 1,
RAY_SSS = 2,
RAY_VOLUME_ALL = 3,
} RayType;
KernelGlobals *kg;
RayType type;
/* for shadow rays */
Intersection *isect_s;
int max_hits;
int num_hits;
/* for SSS Rays: */
LocalIntersection *ss_isect;
int sss_object_id;
uint *lcg_state;
CCLIntersectContext(KernelGlobals *kg_, RayType type_)
{
kg = kg_;
type = type_;
max_hits = 1;
num_hits = 0;
isect_s = NULL;
ss_isect = NULL;
sss_object_id = -1;
lcg_state = NULL;
}
};
class IntersectContext
{
public:
IntersectContext(CCLIntersectContext* ctx)
{
rtcInitIntersectContext(&context);
userRayExt = ctx;
}
RTCIntersectContext context;
CCLIntersectContext* userRayExt;
};
ccl_device_inline void kernel_embree_setup_ray(const Ray& ray, RTCRay& rtc_ray, const uint visibility)
{
rtc_ray.org_x = ray.P.x;
rtc_ray.org_y = ray.P.y;
rtc_ray.org_z = ray.P.z;
rtc_ray.dir_x = ray.D.x;
rtc_ray.dir_y = ray.D.y;
rtc_ray.dir_z = ray.D.z;
rtc_ray.tnear = 0.0f;
rtc_ray.tfar = ray.t;
rtc_ray.time = ray.time;
rtc_ray.mask = visibility;
}
ccl_device_inline void kernel_embree_setup_rayhit(const Ray& ray, RTCRayHit& rayhit, const uint visibility)
{
kernel_embree_setup_ray(ray, rayhit.ray, visibility);
rayhit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
rayhit.hit.primID = RTC_INVALID_GEOMETRY_ID;
}
ccl_device_inline void kernel_embree_convert_hit(KernelGlobals *kg, const RTCRay *ray, const RTCHit *hit, Intersection *isect)
{
bool is_hair = hit->geomID & 1;
isect->u = is_hair ? hit->u : 1.0f - hit->v - hit->u;
isect->v = is_hair ? hit->v : hit->u;
isect->t = ray->tfar;
isect->Ng = make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z);
if(hit->instID[0] != RTC_INVALID_GEOMETRY_ID) {
RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData(rtcGetGeometry(kernel_data.bvh.scene, hit->instID[0]));
isect->prim = hit->primID + (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID)) + kernel_tex_fetch(__object_node, hit->instID[0]/2);
isect->object = hit->instID[0]/2;
}
else {
isect->prim = hit->primID + (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(kernel_data.bvh.scene, hit->geomID));
isect->object = OBJECT_NONE;
}
isect->type = kernel_tex_fetch(__prim_type, isect->prim);
}
ccl_device_inline void kernel_embree_convert_local_hit(KernelGlobals *kg, const RTCRay *ray, const RTCHit *hit, Intersection *isect, int local_object_id)
{
isect->u = 1.0f - hit->v - hit->u;
isect->v = hit->u;
isect->t = ray->tfar;
isect->Ng = make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z);
RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData(rtcGetGeometry(kernel_data.bvh.scene, local_object_id * 2));
isect->prim = hit->primID + (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID)) + kernel_tex_fetch(__object_node, local_object_id);
isect->object = local_object_id;
isect->type = kernel_tex_fetch(__prim_type, isect->prim);
}
CCL_NAMESPACE_END

View File

@ -817,16 +817,24 @@ ccl_device_inline float3 curve_refine(KernelGlobals *kg,
sd->Ng = normalize(-(D - tg * (dot(tg, D))));
}
else {
/* direction from inside to surface of curve */
float3 p_curr = curvepoint(isect->u, p[0], p[1], p[2], p[3]);
sd->Ng = normalize(P - p_curr);
#ifdef __EMBREE__
if(kernel_data.bvh.scene) {
sd->Ng = normalize(isect->Ng);
}
else
#endif
{
/* direction from inside to surface of curve */
float3 p_curr = curvepoint(isect->u, p[0], p[1], p[2], p[3]);
sd->Ng = normalize(P - p_curr);
/* adjustment for changing radius */
float gd = isect->v;
/* adjustment for changing radius */
float gd = isect->v;
if(gd != 0.0f) {
sd->Ng = sd->Ng - gd * tg;
sd->Ng = normalize(sd->Ng);
if(gd != 0.0f) {
sd->Ng = sd->Ng - gd * tg;
sd->Ng = normalize(sd->Ng);
}
}
}

View File

@ -78,6 +78,12 @@ ccl_device_inline Transform object_fetch_transform_motion(KernelGlobals *kg, int
const uint num_steps = kernel_tex_fetch(__objects, object).numsteps * 2 + 1;
Transform tfm;
#ifdef __EMBREE__
if(kernel_data.bvh.scene) {
transform_motion_array_interpolate_straight(&tfm, motion, num_steps, time);
}
else
#endif
transform_motion_array_interpolate(&tfm, motion, num_steps, time);
return tfm;

View File

@ -25,6 +25,11 @@
# define __KERNEL_CPU__
#endif
#if defined(__KERNEL_CPU__) && defined(WITH_EMBREE)
#include <embree3/rtcore.h>
#include <embree3/rtcore_scene.h>
#endif
/* TODO(sergey): This is only to make it possible to include this header
* from outside of the kernel. but this could be done somewhat cleaner?
*/
@ -97,6 +102,9 @@ CCL_NAMESPACE_BEGIN
# define __SHADOW_RECORD_ALL__
# define __VOLUME_DECOUPLED__
# define __VOLUME_RECORD_ALL__
# ifdef WITH_EMBREE
# define __EMBREE__
# endif
#endif /* __KERNEL_CPU__ */
#ifdef __KERNEL_CUDA__
@ -722,6 +730,9 @@ typedef struct Ray {
/* Intersection */
typedef struct Intersection {
#ifdef __EMBREE__
float3 Ng;
#endif
float t, u, v;
int prim;
int object;
@ -1396,7 +1407,7 @@ typedef enum KernelBVHLayout {
BVH_LAYOUT_BVH2 = (1 << 0),
BVH_LAYOUT_BVH4 = (1 << 1),
BVH_LAYOUT_BVH8 = (1 << 2),
BVH_LAYOUT_EMBREE = (1 << 3),
BVH_LAYOUT_DEFAULT = BVH_LAYOUT_BVH8,
BVH_LAYOUT_ALL = (unsigned int)(-1),
} KernelBVHLayout;
@ -1409,7 +1420,13 @@ typedef struct KernelBVH {
int have_instancing;
int bvh_layout;
int use_bvh_steps;
int pad1, pad2;
int pad1;
#ifdef __EMBREE__
RTCScene scene;
#else
void *unused;
#endif
int pad2, pad3;
} KernelBVH;
static_assert_align(KernelBVH, 16);

View File

@ -39,6 +39,10 @@
#include "util/util_progress.h"
#include "util/util_set.h"
#ifdef WITH_EMBREE
# include "bvh/bvh_embree.h"
#endif
CCL_NAMESPACE_BEGIN
/* Triangle */
@ -1073,6 +1077,9 @@ void Mesh::compute_bvh(Device *device,
params->use_bvh_unaligned_nodes;
bparams.num_motion_triangle_steps = params->num_bvh_time_steps;
bparams.num_motion_curve_steps = params->num_bvh_time_steps;
bparams.bvh_type = params->bvh_type;
bparams.curve_flags = dscene->data.curve.curveflags;
bparams.curve_subdivisions = dscene->data.curve.subdivisions;
delete bvh;
bvh = BVH::create(bparams, objects);
@ -1861,14 +1868,32 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
scene->params.use_bvh_unaligned_nodes;
bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps;
bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps;
bparams.bvh_type = scene->params.bvh_type;
bparams.curve_flags = dscene->data.curve.curveflags;
bparams.curve_subdivisions = dscene->data.curve.subdivisions;
VLOG(1) << "Using " << bvh_layout_name(bparams.bvh_layout)
<< " layout.";
#ifdef WITH_EMBREE
if(bparams.bvh_layout == BVH_LAYOUT_EMBREE) {
if(dscene->data.bvh.scene) {
BVHEmbree::destroy(dscene->data.bvh.scene);
}
}
#endif
BVH *bvh = BVH::create(bparams, scene->objects);
bvh->build(progress);
bvh->build(progress, &device->stats);
if(progress.get_cancel()) {
#ifdef WITH_EMBREE
if(bparams.bvh_layout == BVH_LAYOUT_EMBREE) {
if(dscene->data.bvh.scene) {
BVHEmbree::destroy(dscene->data.bvh.scene);
}
}
#endif
delete bvh;
return;
}
@ -1923,6 +1948,16 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
dscene->data.bvh.bvh_layout = bparams.bvh_layout;
dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0);
#ifdef WITH_EMBREE
if(bparams.bvh_layout == BVH_LAYOUT_EMBREE) {
dscene->data.bvh.scene = ((BVHEmbree*)bvh)->scene;
}
else {
dscene->data.bvh.scene = NULL;
}
#endif
delete bvh;
}

View File

@ -214,6 +214,11 @@ void Scene::device_update(Device *device_, Progress& progress)
progress.set_status("Updating Objects");
object_manager->device_update(device, &dscene, this, progress);
if(progress.get_cancel() || device->have_error()) return;
progress.set_status("Updating Hair Systems");
curve_system_manager->device_update(device, &dscene, this, progress);
if(progress.get_cancel() || device->have_error()) return;
progress.set_status("Updating Particle Systems");
@ -240,12 +245,7 @@ void Scene::device_update(Device *device_, Progress& progress)
camera->device_update_volume(device, &dscene, this);
if(progress.get_cancel() || device->have_error()) return;
progress.set_status("Updating Hair Systems");
curve_system_manager->device_update(device, &dscene, this, progress);
if(progress.get_cancel() || device->have_error()) return;
progress.set_status("Updating Lookup Tables");
lookup_tables->device_update(device, &dscene);

View File

@ -166,7 +166,6 @@ public:
bool use_bvh_spatial_split;
bool use_bvh_unaligned_nodes;
int num_bvh_time_steps;
bool persistent_data;
int texture_limit;

View File

@ -422,6 +422,28 @@ ccl_device void transform_motion_array_interpolate(Transform *tfm,
transform_compose(tfm, &decomp);
}
#ifdef __EMBREE__
ccl_device void transform_motion_array_interpolate_straight(Transform *tfm, const ccl_global DecomposedTransform *motion, uint numsteps, float time)
{
/* Figure out which steps we need to interpolate. */
int maxstep = numsteps - 1;
int step = min((int)(time*maxstep), maxstep - 1);
float t = time * maxstep - step;
const ccl_global DecomposedTransform *a = motion + step;
const ccl_global DecomposedTransform *b = motion + step + 1;
Transform step1, step2;
transform_compose(&step1, a);
transform_compose(&step2, b);
/* matrix lerp */
tfm->x = (1.0f - t) * step1.x + t * step2.x;
tfm->y = (1.0f - t) * step1.y + t * step2.y;
tfm->z = (1.0f - t) * step1.z + t * step2.z;
}
#endif
#ifndef __KERNEL_GPU__
class BoundBox2D;

View File

@ -37,7 +37,7 @@ CCL_NAMESPACE_BEGIN
#ifndef __KERNEL_GPU__
struct ccl_try_align(16) float8 {
struct ccl_try_align(32) float8 {
#ifdef __KERNEL_AVX2__
union {
__m256 m256;

View File

@ -170,6 +170,10 @@ if(WITH_CYCLES_OSL)
add_definitions(-DWITH_CYCLES_OSL)
endif()
if(WITH_CYCLES_EMBREE)
add_definitions(-DWITH_CYCLES_EMBREE)
endif()
if(WITH_FREESTYLE)
list(APPEND INC
../../freestyle/intern/python