forked from bartvdbraak/blender
svn merge -r41655:41715 ^/trunk/blender --- this is the real cycles merge, needs some edits to cycles its self before cycles will build
This commit is contained in:
commit
121ff4223d
@ -213,6 +213,10 @@ if(UNIX AND NOT APPLE)
|
|||||||
endif()
|
endif()
|
||||||
option(WITH_PYTHON_INSTALL "Copy system python into the blender install folder" ON)
|
option(WITH_PYTHON_INSTALL "Copy system python into the blender install folder" ON)
|
||||||
|
|
||||||
|
# Cycles
|
||||||
|
option(WITH_CYCLES "Enable Cycles Render Engine" ON)
|
||||||
|
OPTION(WITH_CYCLES_TEST "Build cycles test application" OFF)
|
||||||
|
|
||||||
# disable for now, but plan to support on all platforms eventually
|
# disable for now, but plan to support on all platforms eventually
|
||||||
option(WITH_MEM_JEMALLOC "Enable malloc replacement (http://www.canonware.com/jemalloc)" OFF)
|
option(WITH_MEM_JEMALLOC "Enable malloc replacement (http://www.canonware.com/jemalloc)" OFF)
|
||||||
mark_as_advanced(WITH_MEM_JEMALLOC)
|
mark_as_advanced(WITH_MEM_JEMALLOC)
|
||||||
@ -284,6 +288,12 @@ if(WITH_PYTHON_MODULE)
|
|||||||
set(WITH_HEADLESS ON)
|
set(WITH_HEADLESS ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# auto enable openimageio and boost for cycles
|
||||||
|
if(WITH_CYCLES)
|
||||||
|
set(WITH_OPENIMAGEIO ON)
|
||||||
|
set(WITH_BOOST ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
TEST_SSE_SUPPORT(COMPILER_SSE_FLAG COMPILER_SSE2_FLAG)
|
TEST_SSE_SUPPORT(COMPILER_SSE_FLAG COMPILER_SSE2_FLAG)
|
||||||
|
|
||||||
# don't store paths to libs for portable distrobution
|
# don't store paths to libs for portable distrobution
|
||||||
@ -492,12 +502,12 @@ if(UNIX AND NOT APPLE)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WITH_BOOST)
|
if(WITH_BOOST)
|
||||||
set(BOOST "/usr" CACHE PATH "Boost Directory")
|
|
||||||
|
|
||||||
|
# uses in build instructions to override include and library variables
|
||||||
if(NOT BOOST_CUSTOM)
|
if(NOT BOOST_CUSTOM)
|
||||||
set(BOOST_ROOT ${BOOST})
|
|
||||||
set(Boost_USE_MULTITHREADED ON)
|
set(Boost_USE_MULTITHREADED ON)
|
||||||
find_package(Boost 1.34 REQUIRED COMPONENTS filesystem regex system thread)
|
find_package(Boost 1.34 COMPONENTS filesystem regex system thread)
|
||||||
|
mark_as_advanced(Boost_DIR) # why doesnt boost do this?
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(BOOST_INCLUDE_DIR ${Boost_INCLUDE_DIRS})
|
set(BOOST_INCLUDE_DIR ${Boost_INCLUDE_DIRS})
|
||||||
@ -507,10 +517,7 @@ if(UNIX AND NOT APPLE)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WITH_OPENIMAGEIO)
|
if(WITH_OPENIMAGEIO)
|
||||||
set(OPENIMAGEIO "/usr" CACHE PATH "OpenImageIO Directory")
|
find_package(OpenImageIO)
|
||||||
|
|
||||||
set(OPENIMAGEIO_ROOT_DIR ${OPENIMAGEIO})
|
|
||||||
find_package(OpenImageIO REQUIRED)
|
|
||||||
|
|
||||||
set(OPENIMAGEIO_LIBRARIES ${OPENIMAGEIO_LIBRARIES} ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${TIFF_LIBRARY} ${OPENEXR_LIBRARIES} ${ZLIB_LIBRARIES} ${BOOST_LIBRARIES})
|
set(OPENIMAGEIO_LIBRARIES ${OPENIMAGEIO_LIBRARIES} ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${TIFF_LIBRARY} ${OPENEXR_LIBRARIES} ${ZLIB_LIBRARIES} ${BOOST_LIBRARIES})
|
||||||
set(OPENIMAGEIO_LIBPATH) # TODO, remove and reference the absolute path everywhere
|
set(OPENIMAGEIO_LIBPATH) # TODO, remove and reference the absolute path everywhere
|
||||||
@ -518,6 +525,8 @@ if(UNIX AND NOT APPLE)
|
|||||||
|
|
||||||
if(NOT OPENIMAGEIO_FOUND)
|
if(NOT OPENIMAGEIO_FOUND)
|
||||||
set(WITH_OPENIMAGEIO OFF)
|
set(WITH_OPENIMAGEIO OFF)
|
||||||
|
set(WITH_CYCLES OFF)
|
||||||
|
message(STATUS "OpenImageIO not found, disabling WITH_CYCLES")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -843,7 +852,7 @@ elseif(WIN32)
|
|||||||
else()
|
else()
|
||||||
# keep GCC specific stuff here
|
# keep GCC specific stuff here
|
||||||
if(CMAKE_COMPILER_IS_GNUCC)
|
if(CMAKE_COMPILER_IS_GNUCC)
|
||||||
set(PLATFORM_LINKLIBS "-lshell32 -lshfolder -lgdi32 -lmsvcrt -lwinmm -lmingw32 -lm -lws2_32 -lz -lstdc++ -lole32 -luuid -lwsock32")
|
set(PLATFORM_LINKLIBS "-lshell32 -lshfolder -lgdi32 -lmsvcrt -lwinmm -lmingw32 -lm -lws2_32 -lz -lstdc++ -lole32 -luuid -lwsock32 -lpsapi")
|
||||||
set(PLATFORM_CFLAGS "-pipe -funsigned-char -fno-strict-aliasing")
|
set(PLATFORM_CFLAGS "-pipe -funsigned-char -fno-strict-aliasing")
|
||||||
|
|
||||||
add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE)
|
add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE)
|
||||||
@ -942,26 +951,26 @@ elseif(WIN32)
|
|||||||
if(WITH_BOOST)
|
if(WITH_BOOST)
|
||||||
set(BOOST ${LIBDIR}/boost)
|
set(BOOST ${LIBDIR}/boost)
|
||||||
set(BOOST_INCLUDE_DIR ${BOOST}/include)
|
set(BOOST_INCLUDE_DIR ${BOOST}/include)
|
||||||
set(BOOST_POSTFIX "vc90-mt-s-1_46_1")
|
set(BOOST_POSTFIX "mgw45-mt-s-1_47")
|
||||||
set(BOOST_DEBUG_POSTFIX "vc90-mt-sgd-1_46_1")
|
set(BOOST_DEBUG_POSTFIX "mgw45-mt-sd-1_47")
|
||||||
set(BOOST_LIBRARIES
|
set(BOOST_LIBRARIES
|
||||||
optimized libboost_date_time-${BOOST_POSTFIX} libboost_filesystem-${BOOST_POSTFIX}
|
optimized boost_date_time-${BOOST_POSTFIX} boost_filesystem-${BOOST_POSTFIX}
|
||||||
libboost_regex-${BOOST_POSTFIX} libboost_system-${BOOST_POSTFIX} libboost_thread-${BOOST_POSTFIX}
|
boost_regex-${BOOST_POSTFIX} boost_system-${BOOST_POSTFIX} boost_thread-${BOOST_POSTFIX}
|
||||||
debug libboost_date_time-${BOOST_DEBUG_POSTFIX} libboost_filesystem-${BOOST_DEBUG_POSTFIX}
|
debug boost_date_time-${BOOST_DEBUG_POSTFIX} boost_filesystem-${BOOST_DEBUG_POSTFIX}
|
||||||
libboost_regex-${BOOST_DEBUG_POSTFIX} libboost_system-${BOOST_DEBUG_POSTFIX} libboost_thread-${BOOST_DEBUG_POSTFIX})
|
boost_regex-${BOOST_DEBUG_POSTFIX} boost_system-${BOOST_DEBUG_POSTFIX} boost_thread-${BOOST_DEBUG_POSTFIX})
|
||||||
set(BOOST_LIBPATH ${BOOST}/lib)
|
set(BOOST_LIBPATH ${BOOST}/lib/gcc)
|
||||||
set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB")
|
set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB -DBOOST_THREAD_USE_LIB ")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WITH_OPENIMAGEIO)
|
if(WITH_OPENIMAGEIO)
|
||||||
set(OPENIMAGEIO ${LIBDIR}/openimageio)
|
set(OPENIMAGEIO ${LIBDIR}/gcc/openimageio)
|
||||||
set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO}/include)
|
set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO}/include)
|
||||||
set(OPENIMAGEIO_LIBRARIES OpenImageIO)
|
set(OPENIMAGEIO_LIBRARIES OpenImageIO)
|
||||||
set(OPENIMAGEIO_LIBPATH ${OPENIMAGEIO}/lib)
|
set(OPENIMAGEIO_LIBPATH ${OPENIMAGEIO}/lib)
|
||||||
set(OPENIMAGEIO_DEFINITIONS)
|
set(OPENIMAGEIO_DEFINITIONS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(PLATFORM_LINKFLAGS "--stack,2097152")
|
set(PLATFORM_LINKFLAGS "-Xlinker --stack=2097152")
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -1480,6 +1489,7 @@ if(FIRST_RUN)
|
|||||||
info_cfg_option(WITH_FFTW3)
|
info_cfg_option(WITH_FFTW3)
|
||||||
info_cfg_option(WITH_INTERNATIONAL)
|
info_cfg_option(WITH_INTERNATIONAL)
|
||||||
info_cfg_option(WITH_INPUT_NDOF)
|
info_cfg_option(WITH_INPUT_NDOF)
|
||||||
|
info_cfg_option(WITH_CYCLES)
|
||||||
|
|
||||||
info_cfg_text("Compiler Options:")
|
info_cfg_text("Compiler Options:")
|
||||||
info_cfg_option(WITH_BUILDINFO)
|
info_cfg_option(WITH_BUILDINFO)
|
||||||
|
51
SConstruct
51
SConstruct
@ -435,12 +435,12 @@ B.init_lib_dict()
|
|||||||
|
|
||||||
Export('env')
|
Export('env')
|
||||||
|
|
||||||
|
BuildDir(B.root_build_dir+'/source', 'source', duplicate=0)
|
||||||
|
SConscript(B.root_build_dir+'/source/SConscript')
|
||||||
BuildDir(B.root_build_dir+'/intern', 'intern', duplicate=0)
|
BuildDir(B.root_build_dir+'/intern', 'intern', duplicate=0)
|
||||||
SConscript(B.root_build_dir+'/intern/SConscript')
|
SConscript(B.root_build_dir+'/intern/SConscript')
|
||||||
BuildDir(B.root_build_dir+'/extern', 'extern', duplicate=0)
|
BuildDir(B.root_build_dir+'/extern', 'extern', duplicate=0)
|
||||||
SConscript(B.root_build_dir+'/extern/SConscript')
|
SConscript(B.root_build_dir+'/extern/SConscript')
|
||||||
BuildDir(B.root_build_dir+'/source', 'source', duplicate=0)
|
|
||||||
SConscript(B.root_build_dir+'/source/SConscript')
|
|
||||||
|
|
||||||
# now that we have read all SConscripts, we know what
|
# now that we have read all SConscripts, we know what
|
||||||
# libraries will be built. Create list of
|
# libraries will be built. Create list of
|
||||||
@ -526,6 +526,50 @@ if env['OURPLATFORM']!='darwin':
|
|||||||
if len(source)==0:
|
if len(source)==0:
|
||||||
env.Execute(Mkdir(dir))
|
env.Execute(Mkdir(dir))
|
||||||
scriptinstall.append(env.Install(dir=dir,source=source))
|
scriptinstall.append(env.Install(dir=dir,source=source))
|
||||||
|
if env['WITH_BF_CYCLES']:
|
||||||
|
# cycles python code
|
||||||
|
dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles')
|
||||||
|
source=os.listdir('intern/cycles/blender/addon')
|
||||||
|
if '.svn' in source: source.remove('.svn')
|
||||||
|
if '_svn' in source: source.remove('_svn')
|
||||||
|
if '__pycache__' in source: source.remove('__pycache__')
|
||||||
|
source=['intern/cycles/blender/addon/'+s for s in source]
|
||||||
|
scriptinstall.append(env.Install(dir=dir,source=source))
|
||||||
|
|
||||||
|
# cycles kernel code
|
||||||
|
dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles', 'kernel')
|
||||||
|
source=os.listdir('intern/cycles/kernel')
|
||||||
|
if '.svn' in source: source.remove('.svn')
|
||||||
|
if '_svn' in source: source.remove('_svn')
|
||||||
|
if '__pycache__' in source: source.remove('__pycache__')
|
||||||
|
source.remove('kernel.cpp')
|
||||||
|
source.remove('CMakeLists.txt')
|
||||||
|
source.remove('svm')
|
||||||
|
source.remove('osl')
|
||||||
|
source=['intern/cycles/kernel/'+s for s in source]
|
||||||
|
source.append('intern/cycles/util/util_color.h')
|
||||||
|
source.append('intern/cycles/util/util_math.h')
|
||||||
|
source.append('intern/cycles/util/util_transform.h')
|
||||||
|
source.append('intern/cycles/util/util_types.h')
|
||||||
|
scriptinstall.append(env.Install(dir=dir,source=source))
|
||||||
|
# svm
|
||||||
|
dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles', 'kernel', 'svm')
|
||||||
|
source=os.listdir('intern/cycles/kernel/svm')
|
||||||
|
if '.svn' in source: source.remove('.svn')
|
||||||
|
if '_svn' in source: source.remove('_svn')
|
||||||
|
if '__pycache__' in source: source.remove('__pycache__')
|
||||||
|
source=['intern/cycles/kernel/svm/'+s for s in source]
|
||||||
|
scriptinstall.append(env.Install(dir=dir,source=source))
|
||||||
|
|
||||||
|
# licenses
|
||||||
|
dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles', 'license')
|
||||||
|
source=os.listdir('intern/cycles/doc/license')
|
||||||
|
if '.svn' in source: source.remove('.svn')
|
||||||
|
if '_svn' in source: source.remove('_svn')
|
||||||
|
if '__pycache__' in source: source.remove('__pycache__')
|
||||||
|
source.remove('CMakeLists.txt')
|
||||||
|
source=['intern/cycles/doc/license/'+s for s in source]
|
||||||
|
scriptinstall.append(env.Install(dir=dir,source=source))
|
||||||
|
|
||||||
if env['WITH_BF_INTERNATIONAL']:
|
if env['WITH_BF_INTERNATIONAL']:
|
||||||
internationalpaths=['release' + os.sep + 'datafiles']
|
internationalpaths=['release' + os.sep + 'datafiles']
|
||||||
@ -696,6 +740,9 @@ if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross'):
|
|||||||
dllsources.append('${LCGDIR}/thumbhandler/lib/BlendThumb.dll')
|
dllsources.append('${LCGDIR}/thumbhandler/lib/BlendThumb.dll')
|
||||||
dllsources.append('${LCGDIR}/thumbhandler/lib/BlendThumb64.dll')
|
dllsources.append('${LCGDIR}/thumbhandler/lib/BlendThumb64.dll')
|
||||||
|
|
||||||
|
if env['WITH_BF_OIIO']:
|
||||||
|
dllsources.append('${LCGDIR}/openimageio/bin/OpenImageIO.dll')
|
||||||
|
|
||||||
dllsources.append('#source/icons/blender.exe.manifest')
|
dllsources.append('#source/icons/blender.exe.manifest')
|
||||||
|
|
||||||
windlls = env.Install(dir=env['BF_INSTALLDIR'], source = dllsources)
|
windlls = env.Install(dir=env['BF_INSTALLDIR'], source = dllsources)
|
||||||
|
@ -34,7 +34,7 @@ BF_FFMPEG_LIB_STATIC = '${BF_FFMPEG_LIBPATH}/libavformat.a ${BF_FFMPEG_LIBPATH}/
|
|||||||
|
|
||||||
# Don't depend on system's libstdc++
|
# Don't depend on system's libstdc++
|
||||||
WITH_BF_STATICCXX = True
|
WITH_BF_STATICCXX = True
|
||||||
BF_CXX_LIB_STATIC = '/usr/lib/gcc/i486-linux-gnu/4.3.2/libstdc++.a'
|
BF_CXX_LIB_STATIC = '/usr/lib/gcc/i486-linux-gnu/4.3.4/libstdc++.a'
|
||||||
|
|
||||||
WITH_BF_OPENAL = True
|
WITH_BF_OPENAL = True
|
||||||
WITH_BF_STATICOPENAL = True
|
WITH_BF_STATICOPENAL = True
|
||||||
@ -92,9 +92,24 @@ WITH_BF_STATICFFTW3 = True
|
|||||||
# JACK
|
# JACK
|
||||||
WITH_BF_JACK = True
|
WITH_BF_JACK = True
|
||||||
|
|
||||||
|
# Cycles
|
||||||
|
WITH_BF_CYCLES = True
|
||||||
|
|
||||||
|
WITH_BF_OIIO = True
|
||||||
|
WITH_BF_STATICOIIO = True
|
||||||
|
BF_OIIO = '/opt/oiio'
|
||||||
|
BF_OIIO_INC = '${BF_OIIO}/include'
|
||||||
|
BF_OIIO_LIB_STATIC = '${BF_OIIO_LIBPATH}/libOpenImageIO.a ${BF_OPENEXR}/lib/libIlmImf.a'
|
||||||
|
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
|
||||||
|
|
||||||
|
WITH_BF_BOOST = True
|
||||||
|
WITH_BF_STATICBOOST = True
|
||||||
|
BF_BOOST = '/opt/boost'
|
||||||
|
BF_BOOST_INC = '${BF_BOOST}/include'
|
||||||
|
BF_BOOST_LIB_STATIC = '${BF_BOOST_LIBPATH}/libboost_filesystem.a ${BF_BOOST_LIBPATH}/libboost_date_time.a ${BF_BOOST_LIBPATH}/libboost_regex.a ${BF_BOOST_LIBPATH}/libboost_system.a ${BF_BOOST_LIBPATH}/libboost_thread.a'
|
||||||
|
BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
|
||||||
|
|
||||||
# Compilation and optimization
|
# Compilation and optimization
|
||||||
BF_DEBUG = False
|
BF_DEBUG = False
|
||||||
REL_CFLAGS = []
|
REL_CCFLAGS = ['-O2', '-msse', '-msse2'] # C & C++
|
||||||
REL_CXXFLAGS = []
|
|
||||||
REL_CCFLAGS = ['-O2'] # C & C++
|
|
||||||
PLATFORM_LINKFLAGS = ['-L/home/sources/staticlibs/lib32']
|
PLATFORM_LINKFLAGS = ['-L/home/sources/staticlibs/lib32']
|
||||||
|
@ -28,7 +28,7 @@ BF_FFMPEG_LIB_STATIC = '${BF_FFMPEG_LIBPATH}/libavformat.a ${BF_FFMPEG_LIBPATH}/
|
|||||||
|
|
||||||
# Don't depend on system's libstdc++
|
# Don't depend on system's libstdc++
|
||||||
WITH_BF_STATICCXX = True
|
WITH_BF_STATICCXX = True
|
||||||
BF_CXX_LIB_STATIC = '/usr/lib/gcc/i486-linux-gnu/4.3.2/libstdc++.a'
|
BF_CXX_LIB_STATIC = '/usr/lib/gcc/i486-linux-gnu/4.3.4/libstdc++.a'
|
||||||
|
|
||||||
WITH_BF_OPENAL = True
|
WITH_BF_OPENAL = True
|
||||||
WITH_BF_STATICOPENAL = True
|
WITH_BF_STATICOPENAL = True
|
||||||
@ -83,9 +83,10 @@ BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib32'
|
|||||||
# JACK
|
# JACK
|
||||||
WITH_BF_JACK = True
|
WITH_BF_JACK = True
|
||||||
|
|
||||||
|
# Motion Tracking
|
||||||
|
WITH_BF_LIBMV = False
|
||||||
|
|
||||||
# Compilation and optimization
|
# Compilation and optimization
|
||||||
BF_DEBUG = False
|
BF_DEBUG = False
|
||||||
REL_CFLAGS = []
|
REL_CCFLAGS = ['-O2', '-msse', '-msse2'] # C & C++
|
||||||
REL_CXXFLAGS = []
|
|
||||||
REL_CCFLAGS = ['-O2'] # C & C++
|
|
||||||
PLATFORM_LINKFLAGS = ['-L/home/sources/staticlibs/lib32']
|
PLATFORM_LINKFLAGS = ['-L/home/sources/staticlibs/lib32']
|
||||||
|
@ -28,7 +28,7 @@ BF_FFMPEG_LIB_STATIC = '${BF_FFMPEG_LIBPATH}/libavformat.a ${BF_FFMPEG_LIBPATH}/
|
|||||||
|
|
||||||
# Don't depend on system's libstdc++
|
# Don't depend on system's libstdc++
|
||||||
WITH_BF_STATICCXX = True
|
WITH_BF_STATICCXX = True
|
||||||
BF_CXX_LIB_STATIC = '/usr/lib/gcc/x86_64-linux-gnu/4.3.2/libstdc++.a'
|
BF_CXX_LIB_STATIC = '/usr/lib/gcc/x86_64-linux-gnu/4.3.4/libstdc++.a'
|
||||||
|
|
||||||
WITH_BF_OPENAL = True
|
WITH_BF_OPENAL = True
|
||||||
WITH_BF_STATICOPENAL = True
|
WITH_BF_STATICOPENAL = True
|
||||||
@ -83,9 +83,10 @@ BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib64'
|
|||||||
# JACK
|
# JACK
|
||||||
WITH_BF_JACK = True
|
WITH_BF_JACK = True
|
||||||
|
|
||||||
|
# Motion Tracking
|
||||||
|
WITH_BF_LIBMV = False
|
||||||
|
|
||||||
# Compilation and optimization
|
# Compilation and optimization
|
||||||
BF_DEBUG = False
|
BF_DEBUG = False
|
||||||
REL_CFLAGS = []
|
REL_CCFLAGS = ['-O2', '-msse', '-msse2'] # C & C++
|
||||||
REL_CXXFLAGS = []
|
|
||||||
REL_CCFLAGS = ['-O2'] # C & C++
|
|
||||||
PLATFORM_LINKFLAGS = ['-L/home/sources/staticlibs/lib64']
|
PLATFORM_LINKFLAGS = ['-L/home/sources/staticlibs/lib64']
|
||||||
|
@ -34,7 +34,7 @@ BF_FFMPEG_LIB_STATIC = '${BF_FFMPEG_LIBPATH}/libavformat.a ${BF_FFMPEG_LIBPATH}/
|
|||||||
|
|
||||||
# Don't depend on system's libstdc++
|
# Don't depend on system's libstdc++
|
||||||
WITH_BF_STATICCXX = True
|
WITH_BF_STATICCXX = True
|
||||||
BF_CXX_LIB_STATIC = '/usr/lib/gcc/x86_64-linux-gnu/4.3.2/libstdc++.a'
|
BF_CXX_LIB_STATIC = '/usr/lib/gcc/x86_64-linux-gnu/4.3.4/libstdc++.a'
|
||||||
|
|
||||||
WITH_BF_OPENAL = True
|
WITH_BF_OPENAL = True
|
||||||
WITH_BF_STATICOPENAL = True
|
WITH_BF_STATICOPENAL = True
|
||||||
@ -92,9 +92,24 @@ WITH_BF_STATICFFTW3 = True
|
|||||||
# JACK
|
# JACK
|
||||||
WITH_BF_JACK = True
|
WITH_BF_JACK = True
|
||||||
|
|
||||||
|
# Cycles
|
||||||
|
WITH_BF_CYCLES = True
|
||||||
|
|
||||||
|
WITH_BF_OIIO = True
|
||||||
|
WITH_BF_STATICOIIO = True
|
||||||
|
BF_OIIO = '/opt/oiio'
|
||||||
|
BF_OIIO_INC = '${BF_OIIO}/include'
|
||||||
|
BF_OIIO_LIB_STATIC = '${BF_OIIO_LIBPATH}/libOpenImageIO.a ${BF_OPENEXR}/lib/libIlmImf.a'
|
||||||
|
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
|
||||||
|
|
||||||
|
WITH_BF_BOOST = True
|
||||||
|
WITH_BF_STATICBOOST = True
|
||||||
|
BF_BOOST = '/opt/boost'
|
||||||
|
BF_BOOST_INC = '${BF_BOOST}/include'
|
||||||
|
BF_BOOST_LIB_STATIC = '${BF_BOOST_LIBPATH}/libboost_filesystem.a ${BF_BOOST_LIBPATH}/libboost_date_time.a ${BF_BOOST_LIBPATH}/libboost_regex.a ${BF_BOOST_LIBPATH}/libboost_system.a ${BF_BOOST_LIBPATH}/libboost_thread.a'
|
||||||
|
BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
|
||||||
|
|
||||||
# Compilation and optimization
|
# Compilation and optimization
|
||||||
BF_DEBUG = False
|
BF_DEBUG = False
|
||||||
REL_CFLAGS = []
|
REL_CCFLAGS = ['-O2', '-msse', '-msse2'] # C & C++
|
||||||
REL_CXXFLAGS = []
|
|
||||||
REL_CCFLAGS = ['-O2'] # C & C++
|
|
||||||
PLATFORM_LINKFLAGS = ['-L/home/sources/staticlibs/lib64']
|
PLATFORM_LINKFLAGS = ['-L/home/sources/staticlibs/lib64']
|
||||||
|
70
build_files/cmake/Modules/FindOpenImageIO.cmake
Normal file
70
build_files/cmake/Modules/FindOpenImageIO.cmake
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
# - Find OpenImageIO library
|
||||||
|
# Find the native OpenImageIO includes and library
|
||||||
|
# This module defines
|
||||||
|
# OPENIMAGEIO_INCLUDE_DIRS, where to find openimageio.h, Set when
|
||||||
|
# OPENIMAGEIO_INCLUDE_DIR is found.
|
||||||
|
# OPENIMAGEIO_LIBRARIES, libraries to link against to use OpenImageIO.
|
||||||
|
# OPENIMAGEIO_ROOT_DIR, The base directory to search for OpenImageIO.
|
||||||
|
# This can also be an environment variable.
|
||||||
|
# OPENIMAGEIO_FOUND, If false, do not try to use OpenImageIO.
|
||||||
|
#
|
||||||
|
# also defined, but not for general use are
|
||||||
|
# OPENIMAGEIO_LIBRARY, where to find the OpenImageIO library.
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# Copyright 2011 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 OPENIMAGEIO_ROOT_DIR was defined in the environment, use it.
|
||||||
|
IF(NOT OPENIMAGEIO_ROOT_DIR AND NOT $ENV{OPENIMAGEIO_ROOT_DIR} STREQUAL "")
|
||||||
|
SET(OPENIMAGEIO_ROOT_DIR $ENV{OPENIMAGEIO_ROOT_DIR})
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
SET(_openimageio_SEARCH_DIRS
|
||||||
|
${OPENIMAGEIO_ROOT_DIR}
|
||||||
|
/usr/local
|
||||||
|
/sw # Fink
|
||||||
|
/opt/local # DarwinPorts
|
||||||
|
/opt/csw # Blastwave
|
||||||
|
)
|
||||||
|
|
||||||
|
FIND_PATH(OPENIMAGEIO_INCLUDE_DIR
|
||||||
|
NAMES
|
||||||
|
OpenImageIO/imageio.h
|
||||||
|
HINTS
|
||||||
|
${_openimageio_SEARCH_DIRS}
|
||||||
|
PATH_SUFFIXES
|
||||||
|
include
|
||||||
|
)
|
||||||
|
|
||||||
|
FIND_LIBRARY(OPENIMAGEIO_LIBRARY
|
||||||
|
NAMES
|
||||||
|
OpenImageIO
|
||||||
|
HINTS
|
||||||
|
${_openimageio_SEARCH_DIRS}
|
||||||
|
PATH_SUFFIXES
|
||||||
|
lib64 lib
|
||||||
|
)
|
||||||
|
|
||||||
|
# handle the QUIETLY and REQUIRED arguments and set OPENIMAGEIO_FOUND to TRUE if
|
||||||
|
# all listed variables are TRUE
|
||||||
|
INCLUDE(FindPackageHandleStandardArgs)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenImageIO DEFAULT_MSG
|
||||||
|
OPENIMAGEIO_LIBRARY OPENIMAGEIO_INCLUDE_DIR)
|
||||||
|
|
||||||
|
IF(OPENIMAGEIO_FOUND)
|
||||||
|
SET(OPENIMAGEIO_LIBRARIES ${OPENIMAGEIO_LIBRARY})
|
||||||
|
SET(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO_INCLUDE_DIR})
|
||||||
|
ENDIF(OPENIMAGEIO_FOUND)
|
||||||
|
|
||||||
|
MARK_AS_ADVANCED(
|
||||||
|
OPENIMAGEIO_INCLUDE_DIR
|
||||||
|
OPENIMAGEIO_LIBRARY
|
||||||
|
)
|
@ -172,6 +172,12 @@ def cmake_get_src(f):
|
|||||||
pass
|
pass
|
||||||
elif new_file.endswith(".def"):
|
elif new_file.endswith(".def"):
|
||||||
pass
|
pass
|
||||||
|
elif new_file.endswith(".cl"): # opencl
|
||||||
|
pass
|
||||||
|
elif new_file.endswith(".cu"): # cuda
|
||||||
|
pass
|
||||||
|
elif new_file.endswith(".osl"): # open shading language
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
raise Exception("unknown file type - not c or h %s -> %s" % (f, new_file))
|
raise Exception("unknown file type - not c or h %s -> %s" % (f, new_file))
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ from project_info import (SIMPLE_PROJECTFILE,
|
|||||||
# is_py,
|
# is_py,
|
||||||
cmake_advanced_info,
|
cmake_advanced_info,
|
||||||
cmake_compiler_defines,
|
cmake_compiler_defines,
|
||||||
|
project_name_get,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -59,7 +60,11 @@ def create_nb_project_main():
|
|||||||
includes = list(set(includes) | set(dirname(f) for f in files if is_c_header(f)))
|
includes = list(set(includes) | set(dirname(f) for f in files if is_c_header(f)))
|
||||||
includes.sort()
|
includes.sort()
|
||||||
|
|
||||||
|
if 0:
|
||||||
PROJECT_NAME = "Blender"
|
PROJECT_NAME = "Blender"
|
||||||
|
else:
|
||||||
|
# be tricky, get the project name from SVN if we can!
|
||||||
|
PROJECT_NAME = project_name_get(SOURCE_DIR)
|
||||||
|
|
||||||
# --------------- NB spesific
|
# --------------- NB spesific
|
||||||
defines = [("%s=%s" % cdef) if cdef[1] else cdef[0] for cdef in defines]
|
defines = [("%s=%s" % cdef) if cdef[1] else cdef[0] for cdef in defines]
|
||||||
|
@ -12,6 +12,7 @@ set(WITH_BUILTIN_GLEW OFF CACHE FORCE BOOL)
|
|||||||
set(WITH_BULLET OFF CACHE FORCE BOOL)
|
set(WITH_BULLET OFF CACHE FORCE BOOL)
|
||||||
set(WITH_CODEC_FFMPEG OFF CACHE FORCE BOOL)
|
set(WITH_CODEC_FFMPEG OFF CACHE FORCE BOOL)
|
||||||
set(WITH_CODEC_SNDFILE OFF CACHE FORCE BOOL)
|
set(WITH_CODEC_SNDFILE OFF CACHE FORCE BOOL)
|
||||||
|
set(WITH_CYCLES OFF CACHE FORCE BOOL)
|
||||||
set(WITH_FFTW3 OFF CACHE FORCE BOOL)
|
set(WITH_FFTW3 OFF CACHE FORCE BOOL)
|
||||||
set(WITH_LIBMV OFF CACHE FORCE BOOL)
|
set(WITH_LIBMV OFF CACHE FORCE BOOL)
|
||||||
set(WITH_GAMEENGINE OFF CACHE FORCE BOOL)
|
set(WITH_GAMEENGINE OFF CACHE FORCE BOOL)
|
||||||
|
@ -272,7 +272,7 @@ macro(setup_liblinks
|
|||||||
target_link_libraries(${target} ${BOOST_LIBRARIES})
|
target_link_libraries(${target} ${BOOST_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
if(WITH_IMAGE_OPENEXR)
|
if(WITH_IMAGE_OPENEXR)
|
||||||
if(WIN32 AND NOT UNIX)
|
if(WIN32 AND NOT UNIX AND NOT CMAKE_COMPILER_IS_GNUCC)
|
||||||
file_list_suffix(OPENEXR_LIBRARIES_DEBUG "${OPENEXR_LIBRARIES}" "_d")
|
file_list_suffix(OPENEXR_LIBRARIES_DEBUG "${OPENEXR_LIBRARIES}" "_d")
|
||||||
target_link_libraries_debug(${target} "${OPENEXR_LIBRARIES_DEBUG}")
|
target_link_libraries_debug(${target} "${OPENEXR_LIBRARIES_DEBUG}")
|
||||||
target_link_libraries_optimized(${target} "${OPENEXR_LIBRARIES}")
|
target_link_libraries_optimized(${target} "${OPENEXR_LIBRARIES}")
|
||||||
|
@ -282,6 +282,21 @@ BF_PCRE_LIBPATH = '${BF_PCRE}/lib'
|
|||||||
#BF_EXPAT_LIB = 'expat'
|
#BF_EXPAT_LIB = 'expat'
|
||||||
#BF_EXPAT_LIBPATH = '/usr/lib'
|
#BF_EXPAT_LIBPATH = '/usr/lib'
|
||||||
|
|
||||||
|
#Cycles
|
||||||
|
WITH_BF_CYCLES = True
|
||||||
|
|
||||||
|
WITH_BF_OIIO = True
|
||||||
|
BF_OIIO = LIBDIR + '/openimageio'
|
||||||
|
BF_OIIO_INC = BF_OIIO + '/include'
|
||||||
|
BF_OIIO_LIB = 'OpenImageIO'
|
||||||
|
BF_OIIO_LIBPATH = BF_OIIO + '/lib'
|
||||||
|
|
||||||
|
WITH_BF_BOOST = True
|
||||||
|
BF_BOOST = LIBDIR + '/boost'
|
||||||
|
BF_BOOST_INC = BF_BOOST + '/include'
|
||||||
|
BF_BOOST_LIB = 'boost_date_time-mt boost_filesystem-mt boost_regex-mt boost_system-mt boost_thread-mt'
|
||||||
|
BF_BOOST_LIBPATH = BF_BOOST + '/lib'
|
||||||
|
|
||||||
#Ray trace optimization
|
#Ray trace optimization
|
||||||
if MACOSX_ARCHITECTURE == 'x86_64' or MACOSX_ARCHITECTURE == 'i386':
|
if MACOSX_ARCHITECTURE == 'x86_64' or MACOSX_ARCHITECTURE == 'i386':
|
||||||
WITH_BF_RAYOPTIMIZATION = True
|
WITH_BF_RAYOPTIMIZATION = True
|
||||||
|
@ -178,6 +178,8 @@ BF_JEMALLOC_LIBPATH = '${BF_JEMALLOC}/lib'
|
|||||||
BF_JEMALLOC_LIB = 'jemalloc'
|
BF_JEMALLOC_LIB = 'jemalloc'
|
||||||
BF_JEMALLOC_LIB_STATIC = '${BF_JEMALLOC_LIBPATH}/libjemalloc.a'
|
BF_JEMALLOC_LIB_STATIC = '${BF_JEMALLOC_LIBPATH}/libjemalloc.a'
|
||||||
|
|
||||||
|
WITH_BF_CYCLES = False
|
||||||
|
|
||||||
WITH_BF_OPENMP = True
|
WITH_BF_OPENMP = True
|
||||||
|
|
||||||
#Ray trace optimization
|
#Ray trace optimization
|
||||||
|
@ -17,7 +17,7 @@ BF_OPENAL_INC = '${BF_OPENAL}/include'
|
|||||||
BF_OPENAL_LIB = 'wrap_oal'
|
BF_OPENAL_LIB = 'wrap_oal'
|
||||||
BF_OPENAL_LIBPATH = '${BF_OPENAL}/lib'
|
BF_OPENAL_LIBPATH = '${BF_OPENAL}/lib'
|
||||||
|
|
||||||
WITH_BF_FFMPEG = False
|
WITH_BF_FFMPEG = True
|
||||||
BF_FFMPEG_LIB = 'avformat-53 avcodec-53 avdevice-53 avutil-51 swscale-2'
|
BF_FFMPEG_LIB = 'avformat-53 avcodec-53 avdevice-53 avutil-51 swscale-2'
|
||||||
BF_FFMPEG_LIBPATH = LIBDIR + '/ffmpeg/lib'
|
BF_FFMPEG_LIBPATH = LIBDIR + '/ffmpeg/lib'
|
||||||
BF_FFMPEG_INC = LIBDIR + '/ffmpeg/include'
|
BF_FFMPEG_INC = LIBDIR + '/ffmpeg/include'
|
||||||
@ -46,11 +46,11 @@ BF_PTHREADS_INC = '${BF_PTHREADS}/include'
|
|||||||
BF_PTHREADS_LIB = 'pthreadGC2'
|
BF_PTHREADS_LIB = 'pthreadGC2'
|
||||||
BF_PTHREADS_LIBPATH = '${BF_PTHREADS}/lib'
|
BF_PTHREADS_LIBPATH = '${BF_PTHREADS}/lib'
|
||||||
|
|
||||||
WITH_BF_OPENEXR = False # TODO, gives linking problems for the moment.
|
WITH_BF_OPENEXR = True
|
||||||
WITH_BF_STATICOPENEXR = False
|
WITH_BF_STATICOPENEXR = False
|
||||||
BF_OPENEXR = LIBDIR + '/gcc/openexr'
|
BF_OPENEXR = LIBDIR + '/gcc/openexr'
|
||||||
BF_OPENEXR_INC = '${BF_OPENEXR}/include ${BF_OPENEXR}/include/OpenEXR'
|
BF_OPENEXR_INC = '${BF_OPENEXR}/include ${BF_OPENEXR}/include/OpenEXR'
|
||||||
BF_OPENEXR_LIB = ' Half IlmImf Iex IlmThread '
|
BF_OPENEXR_LIB = 'Half IlmImf Imath IlmThread Iex'
|
||||||
BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib'
|
BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib'
|
||||||
# Warning, this static lib configuration is untested! users of this OS please confirm.
|
# Warning, this static lib configuration is untested! users of this OS please confirm.
|
||||||
BF_OPENEXR_LIB_STATIC = '${BF_OPENEXR}/lib/libHalf.a ${BF_OPENEXR}/lib/libIlmImf.a ${BF_OPENEXR}/lib/libIex.a ${BF_OPENEXR}/lib/libImath.a ${BF_OPENEXR}/lib/libIlmThread.a'
|
BF_OPENEXR_LIB_STATIC = '${BF_OPENEXR}/lib/libHalf.a ${BF_OPENEXR}/lib/libIlmImf.a ${BF_OPENEXR}/lib/libIex.a ${BF_OPENEXR}/lib/libImath.a ${BF_OPENEXR}/lib/libIlmThread.a'
|
||||||
@ -100,8 +100,8 @@ BF_FFTW3_INC = '${BF_FFTW3}/include'
|
|||||||
BF_FFTW3_LIB = 'fftw3'
|
BF_FFTW3_LIB = 'fftw3'
|
||||||
BF_FFTW3_LIBPATH = '${BF_FFTW3}/lib'
|
BF_FFTW3_LIBPATH = '${BF_FFTW3}/lib'
|
||||||
|
|
||||||
WITH_BF_GAMEENGINE = False
|
WITH_BF_GAMEENGINE = True
|
||||||
WITH_BF_PLAYER = False
|
WITH_BF_PLAYER = True
|
||||||
|
|
||||||
WITH_BF_BULLET = True
|
WITH_BF_BULLET = True
|
||||||
BF_BULLET = '#extern/bullet2/src'
|
BF_BULLET = '#extern/bullet2/src'
|
||||||
@ -140,7 +140,7 @@ BF_OPENGL_LIB_STATIC = [ '${BF_OPENGL}/lib/libGL.a', '${BF_OPENGL}/lib/libGLU.a'
|
|||||||
'${BF_OPENGL}/lib/libXmu.a', '${BF_OPENGL}/lib/libXext.a',
|
'${BF_OPENGL}/lib/libXmu.a', '${BF_OPENGL}/lib/libXext.a',
|
||||||
'${BF_OPENGL}/lib/libX11.a', '${BF_OPENGL}/lib/libXi.a' ]
|
'${BF_OPENGL}/lib/libX11.a', '${BF_OPENGL}/lib/libXi.a' ]
|
||||||
|
|
||||||
WITH_BF_COLLADA = False # TODO, gives linking problems at the moment.
|
WITH_BF_COLLADA = True
|
||||||
BF_COLLADA = '#source/blender/collada'
|
BF_COLLADA = '#source/blender/collada'
|
||||||
BF_COLLADA_INC = '${BF_COLLADA}'
|
BF_COLLADA_INC = '${BF_COLLADA}'
|
||||||
BF_COLLADA_LIB = 'bf_collada'
|
BF_COLLADA_LIB = 'bf_collada'
|
||||||
@ -150,8 +150,23 @@ BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include'
|
|||||||
BF_OPENCOLLADA_LIB = 'OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser UTF MathMLSolver expat pcre buffer ftoa'
|
BF_OPENCOLLADA_LIB = 'OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser UTF MathMLSolver expat pcre buffer ftoa'
|
||||||
BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib'
|
BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib'
|
||||||
|
|
||||||
|
#Cycles
|
||||||
|
WITH_BF_CYCLES = True
|
||||||
|
|
||||||
|
WITH_BF_OIIO = True
|
||||||
|
BF_OIIO = LIBDIR + '/gcc/openimageio'
|
||||||
|
BF_OIIO_INC = '#../lib/windows/gcc/openimageio/include'
|
||||||
|
BF_OIIO_LIB = 'OpenImageIO'
|
||||||
|
BF_OIIO_LIBPATH = '#../lib/windows/gcc/openimageio/lib'
|
||||||
|
|
||||||
|
WITH_BF_BOOST = True
|
||||||
|
BF_BOOST = LIBDIR + '/boost'
|
||||||
|
BF_BOOST_INC = '#../lib/windows/boost/include'
|
||||||
|
BF_BOOST_LIB = 'boost_date_time-mgw45-mt-s-1_47 boost_filesystem-mgw45-mt-s-1_47 boost_regex-mgw45-mt-s-1_47 boost_system-mgw45-mt-s-1_47 boost_thread-mgw45-mt-s-1_47'
|
||||||
|
BF_BOOST_LIBPATH = '#../lib/windows/boost/lib/gcc'
|
||||||
|
|
||||||
#Ray trace optimization
|
#Ray trace optimization
|
||||||
WITH_BF_RAYOPTIMIZATION = False
|
WITH_BF_RAYOPTIMIZATION = True
|
||||||
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse']
|
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse']
|
||||||
|
|
||||||
##
|
##
|
||||||
@ -161,7 +176,7 @@ CXX = 'g++'
|
|||||||
CCFLAGS = [ '-pipe', '-funsigned-char', '-fno-strict-aliasing' ]
|
CCFLAGS = [ '-pipe', '-funsigned-char', '-fno-strict-aliasing' ]
|
||||||
CXXFLAGS = []
|
CXXFLAGS = []
|
||||||
|
|
||||||
CPPFLAGS = ['-DWIN32', '-DFREE_WINDOWS', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64', '-D_LARGEFILE64_SOURCE']
|
CPPFLAGS = ['-DWIN32', '-DFREE_WINDOWS', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64', '-D_LARGEFILE64_SOURCE', '-DBOOST_ALL_NO_LIB', '-DBOOST_THREAD_USE_LIB', '-DGLEW_STATIC']
|
||||||
REL_CFLAGS = []
|
REL_CFLAGS = []
|
||||||
REL_CXXFLAGS = []
|
REL_CXXFLAGS = []
|
||||||
REL_CCFLAGS = ['-DNDEBUG', '-O2']
|
REL_CCFLAGS = ['-DNDEBUG', '-O2']
|
||||||
@ -170,9 +185,9 @@ C_WARN = ['-Wno-char-subscripts', '-Wdeclaration-after-statement', '-Wstrict-pro
|
|||||||
|
|
||||||
CC_WARN = [ '-Wall' ]
|
CC_WARN = [ '-Wall' ]
|
||||||
|
|
||||||
LLIBS = ['-lshell32', '-lshfolder', '-lgdi32', '-lmsvcrt', '-lwinmm', '-lmingw32', '-lm', '-lws2_32', '-lz', '-lstdc++','-lole32','-luuid', '-lwsock32']
|
LLIBS = ['-lshell32', '-lshfolder', '-lgdi32', '-lmsvcrt', '-lwinmm', '-lmingw32', '-lm', '-lws2_32', '-lz', '-lstdc++','-lole32','-luuid', '-lwsock32', '-lpsapi']
|
||||||
|
|
||||||
PLATFORM_LINKFLAGS = ['--stack,2097152']
|
PLATFORM_LINKFLAGS = ['-Xlinker', '--stack=2097152']
|
||||||
|
|
||||||
BF_DEBUG = False
|
BF_DEBUG = False
|
||||||
BF_DEBUG_CCFLAGS= ['-g', '-D_DEBUG']
|
BF_DEBUG_CCFLAGS= ['-g', '-D_DEBUG']
|
||||||
|
@ -149,19 +149,20 @@ WITH_BF_3DMOUSE = True
|
|||||||
|
|
||||||
WITH_BF_OPENMP = True
|
WITH_BF_OPENMP = True
|
||||||
|
|
||||||
'''
|
#Cycles
|
||||||
|
WITH_BF_CYCLES = True
|
||||||
|
|
||||||
WITH_BF_OIIO = True
|
WITH_BF_OIIO = True
|
||||||
BF_OIIO = LIBDIR + '/openimageio'
|
BF_OIIO = '${LIBDIR}/openimageio'
|
||||||
BF_OIIO_INC = '${BF_OIIO}/include'
|
BF_OIIO_INC = '${BF_OIIO}/include'
|
||||||
BF_OIIO_LIB = 'OpenImageIO'
|
BF_OIIO_LIB = 'OpenImageIO'
|
||||||
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
|
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
|
||||||
|
|
||||||
WITH_BF_BOOST = True
|
WITH_BF_BOOST = True
|
||||||
BF_BOOST = LIBDIR + '/boost'
|
BF_BOOST = '${LIBDIR}/boost'
|
||||||
BF_BOOST_INC = '${BF_BOOST}/include'
|
BF_BOOST_INC = '${BF_BOOST}/include'
|
||||||
BF_BOOST_LIB = 'libboost_date_time-vc90-mt-s-1_46_1 libboost_filesystem-vc90-mt-s-1_46_1 libboost_regex-vc90-mt-s-1_46_1 libboost_system-vc90-mt-s-1_46_1 libboost_thread-vc90-mt-s-1_46_1'
|
BF_BOOST_LIB = 'libboost_date_time-vc90-mt-s-1_47 libboost_filesystem-vc90-mt-s-1_47 libboost_regex-vc90-mt-s-1_47 libboost_system-vc90-mt-s-1_47 libboost_thread-vc90-mt-s-1_47'
|
||||||
BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
|
BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
|
||||||
'''
|
|
||||||
|
|
||||||
#Ray trace optimization
|
#Ray trace optimization
|
||||||
WITH_BF_RAYOPTIMIZATION = True
|
WITH_BF_RAYOPTIMIZATION = True
|
||||||
|
@ -153,19 +153,20 @@ WITH_BF_3DMOUSE = True
|
|||||||
|
|
||||||
WITH_BF_OPENMP = True
|
WITH_BF_OPENMP = True
|
||||||
|
|
||||||
'''
|
WITH_BF_CYCLES = True
|
||||||
|
|
||||||
WITH_BF_OIIO = True
|
WITH_BF_OIIO = True
|
||||||
BF_OIIO = LIBDIR + '/openimageio'
|
BF_OIIO = '${LIBDIR}/openimageio'
|
||||||
BF_OIIO_INC = '${BF_OIIO}/include'
|
BF_OIIO_INC = '${BF_OIIO}/include'
|
||||||
BF_OIIO_LIB = 'OpenImageIO'
|
BF_OIIO_LIB = 'OpenImageIO'
|
||||||
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
|
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
|
||||||
|
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
|
||||||
|
|
||||||
WITH_BF_BOOST = True
|
WITH_BF_BOOST = True
|
||||||
BF_BOOST = LIBDIR + '/boost'
|
BF_BOOST = '${LIBDIR}/boost'
|
||||||
BF_BOOST_INC = '${BF_BOOST}/include'
|
BF_BOOST_INC = '${BF_BOOST}/include'
|
||||||
BF_BOOST_LIB = 'libboost_date_time-vc90-mt-s-1_45 libboost_filesystem-vc90-mt-s-1_45 libboost_regex-vc90-mt-s-1_45 libboost_system-vc90-mt-s-1_45 libboost_thread-vc90-mt-s-1_45'
|
BF_BOOST_LIB = 'libboost_date_time-vc90-mt-s-1_47 libboost_filesystem-vc90-mt-s-1_47 libboost_regex-vc90-mt-s-1_47 libboost_system-vc90-mt-s-1_47 libboost_thread-vc90-mt-s-1_47'
|
||||||
BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
|
BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
|
||||||
'''
|
|
||||||
|
|
||||||
#Ray trace optimization
|
#Ray trace optimization
|
||||||
WITH_BF_RAYOPTIMIZATION = True
|
WITH_BF_RAYOPTIMIZATION = True
|
||||||
|
@ -195,8 +195,13 @@ def setup_staticlibs(lenv):
|
|||||||
|
|
||||||
if lenv['WITH_BF_OIIO']:
|
if lenv['WITH_BF_OIIO']:
|
||||||
libincs += Split(lenv['BF_OIIO_LIBPATH'])
|
libincs += Split(lenv['BF_OIIO_LIBPATH'])
|
||||||
|
if lenv['WITH_BF_STATICOIIO']:
|
||||||
|
statlibs += Split(lenv['BF_OIIO_LIB_STATIC'])
|
||||||
|
|
||||||
if lenv['WITH_BF_BOOST']:
|
if lenv['WITH_BF_BOOST']:
|
||||||
libincs += Split(lenv['BF_BOOST_LIBPATH'])
|
libincs += Split(lenv['BF_BOOST_LIBPATH'])
|
||||||
|
if lenv['WITH_BF_STATICBOOST']:
|
||||||
|
statlibs += Split(lenv['BF_BOOST_LIB_STATIC'])
|
||||||
|
|
||||||
# setting this last so any overriding of manually libs could be handled
|
# setting this last so any overriding of manually libs could be handled
|
||||||
if lenv['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross'):
|
if lenv['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross'):
|
||||||
@ -216,11 +221,7 @@ def setup_staticlibs(lenv):
|
|||||||
return statlibs, libincs
|
return statlibs, libincs
|
||||||
|
|
||||||
def setup_syslibs(lenv):
|
def setup_syslibs(lenv):
|
||||||
syslibs = [
|
syslibs = []
|
||||||
|
|
||||||
lenv['BF_JPEG_LIB'],
|
|
||||||
lenv['BF_PNG_LIB'],
|
|
||||||
]
|
|
||||||
|
|
||||||
if not lenv['WITH_BF_FREETYPE_STATIC']:
|
if not lenv['WITH_BF_FREETYPE_STATIC']:
|
||||||
syslibs += Split(lenv['BF_FREETYPE_LIB'])
|
syslibs += Split(lenv['BF_FREETYPE_LIB'])
|
||||||
@ -241,6 +242,10 @@ def setup_syslibs(lenv):
|
|||||||
syslibs += ['gomp']
|
syslibs += ['gomp']
|
||||||
if lenv['WITH_BF_ICONV']:
|
if lenv['WITH_BF_ICONV']:
|
||||||
syslibs += Split(lenv['BF_ICONV_LIB'])
|
syslibs += Split(lenv['BF_ICONV_LIB'])
|
||||||
|
if lenv['WITH_BF_OIIO']:
|
||||||
|
if not lenv['WITH_BF_STATICOIIO']:
|
||||||
|
syslibs += Split(lenv['BF_OIIO_LIB'])
|
||||||
|
|
||||||
if lenv['WITH_BF_OPENEXR'] and not lenv['WITH_BF_STATICOPENEXR']:
|
if lenv['WITH_BF_OPENEXR'] and not lenv['WITH_BF_STATICOPENEXR']:
|
||||||
syslibs += Split(lenv['BF_OPENEXR_LIB'])
|
syslibs += Split(lenv['BF_OPENEXR_LIB'])
|
||||||
if lenv['WITH_BF_TIFF'] and not lenv['WITH_BF_STATICTIFF']:
|
if lenv['WITH_BF_TIFF'] and not lenv['WITH_BF_STATICTIFF']:
|
||||||
@ -280,11 +285,12 @@ def setup_syslibs(lenv):
|
|||||||
if not lenv['WITH_BF_STATIC3DMOUSE']:
|
if not lenv['WITH_BF_STATIC3DMOUSE']:
|
||||||
syslibs += Split(lenv['BF_3DMOUSE_LIB'])
|
syslibs += Split(lenv['BF_3DMOUSE_LIB'])
|
||||||
|
|
||||||
if lenv['WITH_BF_OIIO']:
|
if lenv['WITH_BF_BOOST'] and not lenv['WITH_BF_STATICBOOST']:
|
||||||
syslibs += Split(lenv['BF_OIIO_LIB'])
|
|
||||||
if lenv['WITH_BF_BOOST']:
|
|
||||||
syslibs += Split(lenv['BF_BOOST_LIB'])
|
syslibs += Split(lenv['BF_BOOST_LIB'])
|
||||||
|
|
||||||
|
syslibs += Split(lenv['BF_JPEG_LIB'])
|
||||||
|
syslibs += Split(lenv['BF_PNG_LIB'])
|
||||||
|
|
||||||
syslibs += lenv['LLIBS']
|
syslibs += lenv['LLIBS']
|
||||||
|
|
||||||
return syslibs
|
return syslibs
|
||||||
@ -550,10 +556,6 @@ def AppIt(target=None, source=None, env=None):
|
|||||||
bldroot = env.Dir('.').abspath
|
bldroot = env.Dir('.').abspath
|
||||||
binary = env['BINARYKIND']
|
binary = env['BINARYKIND']
|
||||||
|
|
||||||
if b=='verse':
|
|
||||||
print bc.OKBLUE+"no bundle for verse"+bc.ENDC
|
|
||||||
return 0
|
|
||||||
|
|
||||||
sourcedir = bldroot + '/source/darwin/%s.app'%binary
|
sourcedir = bldroot + '/source/darwin/%s.app'%binary
|
||||||
sourceinfo = bldroot + "/source/darwin/%s.app/Contents/Info.plist"%binary
|
sourceinfo = bldroot + "/source/darwin/%s.app/Contents/Info.plist"%binary
|
||||||
targetinfo = installdir +'/' + "%s.app/Contents/Info.plist"%binary
|
targetinfo = installdir +'/' + "%s.app/Contents/Info.plist"%binary
|
||||||
@ -582,6 +584,23 @@ def AppIt(target=None, source=None, env=None):
|
|||||||
cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/%s/'%(bldroot,installdir,binary,VERSION)
|
cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/%s/'%(bldroot,installdir,binary,VERSION)
|
||||||
commands.getoutput(cmd)
|
commands.getoutput(cmd)
|
||||||
|
|
||||||
|
if env['WITH_BF_CYCLES']:
|
||||||
|
croot = '%s/intern/cycles' % (bldroot)
|
||||||
|
cinstalldir = '%s/%s.app/Contents/MacOS/%s/scripts/addons/cycles' % (installdir,binary,VERSION)
|
||||||
|
|
||||||
|
cmd = 'mkdir %s' % (cinstalldir)
|
||||||
|
commands.getoutput(cmd)
|
||||||
|
cmd = 'mkdir %s/kernel' % (cinstalldir)
|
||||||
|
commands.getoutput(cmd)
|
||||||
|
cmd = 'cp -R %s/blender/addon/*.py %s/' % (croot, cinstalldir)
|
||||||
|
commands.getoutput(cmd)
|
||||||
|
cmd = 'cp -R %s/doc/license %s/license' % (croot, cinstalldir)
|
||||||
|
commands.getoutput(cmd)
|
||||||
|
cmd = 'cp -R %s/kernel/*.h %s/kernel/*.cl %s/kernel/*.cu %s/kernel/' % (croot, croot, croot, cinstalldir)
|
||||||
|
commands.getoutput(cmd)
|
||||||
|
cmd = 'cp -R %s/kernel/svm %s/util/util_color.h %s/util/util_math.h %s/util/util_transform.h %s/util/util_types.h %s/kernel/' % (croot, croot, croot, croot, croot, cinstalldir)
|
||||||
|
commands.getoutput(cmd)
|
||||||
|
|
||||||
if env['WITH_OSX_STATICPYTHON']:
|
if env['WITH_OSX_STATICPYTHON']:
|
||||||
cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/python/'%(installdir,binary, VERSION)
|
cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/python/'%(installdir,binary, VERSION)
|
||||||
commands.getoutput(cmd)
|
commands.getoutput(cmd)
|
||||||
|
@ -156,8 +156,9 @@ def validate_arguments(args, bc):
|
|||||||
'WITH_BF_JEMALLOC', 'WITH_BF_STATICJEMALLOC', 'BF_JEMALLOC', 'BF_JEMALLOC_INC', 'BF_JEMALLOC_LIBPATH', 'BF_JEMALLOC_LIB', 'BF_JEMALLOC_LIB_STATIC',
|
'WITH_BF_JEMALLOC', 'WITH_BF_STATICJEMALLOC', 'BF_JEMALLOC', 'BF_JEMALLOC_INC', 'BF_JEMALLOC_LIBPATH', 'BF_JEMALLOC_LIB', 'BF_JEMALLOC_LIB_STATIC',
|
||||||
'BUILDBOT_BRANCH',
|
'BUILDBOT_BRANCH',
|
||||||
'WITH_BF_3DMOUSE', 'WITH_BF_STATIC3DMOUSE', 'BF_3DMOUSE', 'BF_3DMOUSE_INC', 'BF_3DMOUSE_LIB', 'BF_3DMOUSE_LIBPATH', 'BF_3DMOUSE_LIB_STATIC',
|
'WITH_BF_3DMOUSE', 'WITH_BF_STATIC3DMOUSE', 'BF_3DMOUSE', 'BF_3DMOUSE_INC', 'BF_3DMOUSE_LIB', 'BF_3DMOUSE_LIBPATH', 'BF_3DMOUSE_LIB_STATIC',
|
||||||
'WITH_BF_OIIO', 'BF_OIIO', 'BF_OIIO_INC', 'BF_OIIO_LIB', 'BF_OIIO_LIBPATH',
|
'WITH_BF_CYCLES',
|
||||||
'WITH_BF_BOOST', 'BF_BOOST', 'BF_BOOST_INC', 'BF_BOOST_LIB', 'BF_BOOST_LIBPATH'
|
'WITH_BF_OIIO', 'WITH_BF_STATICOIIO', 'BF_OIIO', 'BF_OIIO_INC', 'BF_OIIO_LIB', 'BF_OIIO_LIB_STATIC', 'BF_OIIO_LIBPATH',
|
||||||
|
'WITH_BF_BOOST', 'WITH_BF_STATICBOOST', 'BF_BOOST', 'BF_BOOST_INC', 'BF_BOOST_LIB', 'BF_BOOST_LIB_STATIC', 'BF_BOOST_LIBPATH'
|
||||||
]
|
]
|
||||||
|
|
||||||
# Have options here that scons expects to be lists
|
# Have options here that scons expects to be lists
|
||||||
@ -239,6 +240,7 @@ def read_opts(env, cfg, args):
|
|||||||
localopts = Variables.Variables(cfg, args)
|
localopts = Variables.Variables(cfg, args)
|
||||||
localopts.AddVariables(
|
localopts.AddVariables(
|
||||||
('LCGDIR', 'location of cvs lib dir'),
|
('LCGDIR', 'location of cvs lib dir'),
|
||||||
|
('LIBDIR', 'root dir of libs'),
|
||||||
(BoolVariable('WITH_BF_PYTHON', 'Compile with python', True)),
|
(BoolVariable('WITH_BF_PYTHON', 'Compile with python', True)),
|
||||||
(BoolVariable('WITH_BF_PYTHON_SAFETY', 'Internal API error checking to track invalid data to prevent crash on access (at the expense of some effeciency)', False)),
|
(BoolVariable('WITH_BF_PYTHON_SAFETY', 'Internal API error checking to track invalid data to prevent crash on access (at the expense of some effeciency)', False)),
|
||||||
('BF_PYTHON', 'Base path for python', ''),
|
('BF_PYTHON', 'Base path for python', ''),
|
||||||
@ -536,16 +538,26 @@ def read_opts(env, cfg, args):
|
|||||||
(BoolVariable('WITH_BF_CXX_GUARDEDALLOC', 'Enable GuardedAlloc for C++ memory allocation tracking.', False)),
|
(BoolVariable('WITH_BF_CXX_GUARDEDALLOC', 'Enable GuardedAlloc for C++ memory allocation tracking.', False)),
|
||||||
|
|
||||||
('BUILDBOT_BRANCH', 'Buildbot branch name', ''),
|
('BUILDBOT_BRANCH', 'Buildbot branch name', ''),
|
||||||
|
) # end of opts.AddOptions()
|
||||||
|
|
||||||
|
localopts.AddVariables(
|
||||||
|
(BoolVariable('WITH_BF_CYCLES', 'Build with the Cycles engine', True)),
|
||||||
|
|
||||||
(BoolVariable('WITH_BF_OIIO', 'Build with OpenImageIO', False)),
|
(BoolVariable('WITH_BF_OIIO', 'Build with OpenImageIO', False)),
|
||||||
|
(BoolVariable('WITH_BF_STATICOIIO', 'Staticly link to OpenImageIO', False)),
|
||||||
|
('BF_OIIO', 'OIIO root path', ''),
|
||||||
('BF_OIIO_INC', 'OIIO include path', ''),
|
('BF_OIIO_INC', 'OIIO include path', ''),
|
||||||
('BF_OIIO_LIB', 'OIIO library', ''),
|
('BF_OIIO_LIB', 'OIIO library', ''),
|
||||||
('BF_OIIO_LIBPATH', 'OIIO library path', ''),
|
('BF_OIIO_LIBPATH', 'OIIO library path', ''),
|
||||||
|
('BF_OIIO_LIB_STATIC', 'OIIO static library', ''),
|
||||||
|
|
||||||
(BoolVariable('WITH_BF_BOOST', 'Build with Boost', False)),
|
(BoolVariable('WITH_BF_BOOST', 'Build with Boost', False)),
|
||||||
|
(BoolVariable('WITH_BF_STATICBOOST', 'Staticly link to boost', False)),
|
||||||
|
('BF_BOOST', 'Boost root path', ''),
|
||||||
('BF_BOOST_INC', 'Boost include path', ''),
|
('BF_BOOST_INC', 'Boost include path', ''),
|
||||||
('BF_BOOST_LIB', 'Boost library', ''),
|
('BF_BOOST_LIB', 'Boost library', ''),
|
||||||
('BF_BOOST_LIBPATH', 'Boost library path', '')
|
('BF_BOOST_LIBPATH', 'Boost library path', ''),
|
||||||
|
('BF_BOOST_LIB_STATIC', 'Boost static library', '')
|
||||||
) # end of opts.AddOptions()
|
) # end of opts.AddOptions()
|
||||||
|
|
||||||
return localopts
|
return localopts
|
||||||
|
@ -57,3 +57,8 @@ endif()
|
|||||||
if(WITH_IK_ITASC)
|
if(WITH_IK_ITASC)
|
||||||
add_subdirectory(itasc)
|
add_subdirectory(itasc)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(WITH_CYCLES)
|
||||||
|
add_subdirectory(cycles)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
@ -25,6 +25,9 @@ NEW_CSG='false'
|
|||||||
if env['WITH_BF_FLUID']:
|
if env['WITH_BF_FLUID']:
|
||||||
SConscript(['elbeem/SConscript'])
|
SConscript(['elbeem/SConscript'])
|
||||||
|
|
||||||
|
if env['WITH_BF_CYCLES']:
|
||||||
|
SConscript(['cycles/SConscript'])
|
||||||
|
|
||||||
if NEW_CSG=='false':
|
if NEW_CSG=='false':
|
||||||
SConscript(['bsp/SConscript'])
|
SConscript(['bsp/SConscript'])
|
||||||
else:
|
else:
|
||||||
|
@ -98,7 +98,6 @@ set(SRC
|
|||||||
intern/AUD_IWriter.h
|
intern/AUD_IWriter.h
|
||||||
intern/AUD_JOSResampleFactory.cpp
|
intern/AUD_JOSResampleFactory.cpp
|
||||||
intern/AUD_JOSResampleFactory.h
|
intern/AUD_JOSResampleFactory.h
|
||||||
intern/AUD_JOSResampleReaderCoeff.cpp
|
|
||||||
intern/AUD_JOSResampleReader.cpp
|
intern/AUD_JOSResampleReader.cpp
|
||||||
intern/AUD_JOSResampleReader.h
|
intern/AUD_JOSResampleReader.h
|
||||||
intern/AUD_LinearResampleFactory.cpp
|
intern/AUD_LinearResampleFactory.cpp
|
||||||
|
74
intern/cycles/CMakeLists.txt
Normal file
74
intern/cycles/CMakeLists.txt
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
|
||||||
|
set(CYCLES_INSTALL_PATH "scripts/addons/cycles")
|
||||||
|
set(WITH_CYCLES_BLENDER ON)
|
||||||
|
|
||||||
|
# External Libraries
|
||||||
|
|
||||||
|
include(cmake/external_libs.cmake)
|
||||||
|
|
||||||
|
# Build Flags
|
||||||
|
|
||||||
|
set(GCC_OPTIM_FLAGS "-ffast-math -msse -msse2 -msse3 -mtune=native")
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_OPTIM_FLAGS}")
|
||||||
|
set(RTTI_DISABLE_FLAGS "-fno-rtti -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
if(MSVC)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Ox /Ot /arch:SSE2 -D_CRT_SECURE_NO_WARNINGS /EHsc /fp:fast")
|
||||||
|
set(RTTI_DISABLE_FLAGS "/GR- -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
|
||||||
|
elseif(CMAKE_COMPILER_IS_GNUCC)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_OPTIM_FLAGS}")
|
||||||
|
set(RTTI_DISABLE_FLAGS "-fno-rtti -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_OPTIM_FLAGS}")
|
||||||
|
set(RTTI_DISABLE_FLAGS "-fno-rtti -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Definitions and Includes
|
||||||
|
|
||||||
|
add_definitions(${BOOST_DEFINITIONS} ${OPENIMAGEIO_DEFINITIONS})
|
||||||
|
|
||||||
|
add_definitions(-DCCL_NAMESPACE_BEGIN=namespace\ ccl\ {)
|
||||||
|
add_definitions(-DCCL_NAMESPACE_END=})
|
||||||
|
|
||||||
|
if(WITH_CYCLES_NETWORK)
|
||||||
|
add_definitions(-DWITH_NETWORK)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_CYCLES_OSL)
|
||||||
|
add_definitions(-DWITH_OSL)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_CYCLES_PARTIO)
|
||||||
|
add_definitions(-DWITH_PARTIO)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_definitions(-DWITH_OPENCL)
|
||||||
|
add_definitions(-DWITH_CUDA)
|
||||||
|
add_definitions(-DWITH_MULTI)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${BOOST_INCLUDE_DIR}
|
||||||
|
${OPENIMAGEIO_INCLUDE_DIRS}
|
||||||
|
${OPENIMAGEIO_INCLUDE_DIRS}/OpenImageIO)
|
||||||
|
|
||||||
|
# Subdirectories
|
||||||
|
|
||||||
|
if(WITH_CYCLES_BLENDER)
|
||||||
|
add_subdirectory(blender)
|
||||||
|
endif(WITH_CYCLES_BLENDER)
|
||||||
|
|
||||||
|
add_subdirectory(app)
|
||||||
|
add_subdirectory(bvh)
|
||||||
|
add_subdirectory(device)
|
||||||
|
add_subdirectory(doc)
|
||||||
|
add_subdirectory(kernel)
|
||||||
|
add_subdirectory(render)
|
||||||
|
add_subdirectory(subd)
|
||||||
|
add_subdirectory(util)
|
40
intern/cycles/SConscript
Normal file
40
intern/cycles/SConscript
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
from os import path
|
||||||
|
Import('env')
|
||||||
|
|
||||||
|
cycles = env.Clone()
|
||||||
|
|
||||||
|
cycles.Depends('../../source/blender/makesrna/intern/RNA_blender_cpp.h', 'makesrna')
|
||||||
|
|
||||||
|
sources = cycles.Glob('bvh/*.cpp') + cycles.Glob('device/*.cpp') + cycles.Glob('kernel/*.cpp') + cycles.Glob('render/*.cpp') + cycles.Glob('subd/*.cpp') + cycles.Glob('util/*.cpp') + cycles.Glob('util/*.c') + cycles.Glob('blender/*.cpp')
|
||||||
|
|
||||||
|
sources.remove(path.join('util', 'util_view.cpp'))
|
||||||
|
sources.remove(path.join('render', 'film_response.cpp'))
|
||||||
|
|
||||||
|
incs = []
|
||||||
|
defs = []
|
||||||
|
ccflags = []
|
||||||
|
cxxflags = []
|
||||||
|
|
||||||
|
defs.append('CCL_NAMESPACE_BEGIN=namespace ccl {')
|
||||||
|
defs.append('CCL_NAMESPACE_END=}')
|
||||||
|
|
||||||
|
defs.append('WITH_OPENCL')
|
||||||
|
defs.append('WITH_MULTI')
|
||||||
|
defs.append('WITH_CUDA')
|
||||||
|
|
||||||
|
if env['OURPLATFORM'] in ('win32-mingw'):
|
||||||
|
cxxflags.append('-fno-rtti -ffast-math -msse -msse2 -msse3 -mtune=native'.split())
|
||||||
|
ccflags.append('-ffast-math -msse -msse2 -msse3 -mtune=native'.split())
|
||||||
|
defs.append('BOOST_NO_RTTI BOOST_NO_TYPEID'.split())
|
||||||
|
|
||||||
|
incs.extend('. bvh render device kernel kernel/osl kernel/svm util subd'.split())
|
||||||
|
incs.extend('#intern/guardedalloc #source/blender/makesrna #source/blender/makesdna'.split())
|
||||||
|
incs.extend('#source/blender/blenloader ../../source/blender/makesrna/intern'.split())
|
||||||
|
incs.extend('#extern/glew/include'.split())
|
||||||
|
incs.append(cycles['BF_OIIO_INC'])
|
||||||
|
incs.append(cycles['BF_BOOST_INC'])
|
||||||
|
incs.append(cycles['BF_PYTHON_INC'])
|
||||||
|
|
||||||
|
cycles.BlenderLib('bf_intern_cycles', sources, incs, defs, libtype=['intern'], priority=[0], compileflags=[None], cc_compileflags=ccflags, cxx_compileflags=cxxflags)
|
||||||
|
|
69
intern/cycles/app/CMakeLists.txt
Normal file
69
intern/cycles/app/CMakeLists.txt
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
|
||||||
|
set(INC
|
||||||
|
.
|
||||||
|
../device
|
||||||
|
../kernel
|
||||||
|
../kernel/svm
|
||||||
|
../bvh
|
||||||
|
../util
|
||||||
|
../render
|
||||||
|
../subd
|
||||||
|
)
|
||||||
|
|
||||||
|
set(LIBRARIES
|
||||||
|
cycles_device
|
||||||
|
cycles_kernel
|
||||||
|
cycles_render
|
||||||
|
cycles_bvh
|
||||||
|
cycles_subd
|
||||||
|
cycles_util
|
||||||
|
${BOOST_LIBRARIES}
|
||||||
|
${OPENGL_LIBRARIES}
|
||||||
|
${CYCLES_GLEW_LIBRARY}
|
||||||
|
${OPENIMAGEIO_LIBRARIES}
|
||||||
|
)
|
||||||
|
|
||||||
|
link_directories(${OPENIMAGEIO_LIBPATH} ${BOOST_LIBPATH})
|
||||||
|
|
||||||
|
if(WITH_CYCLES_TEST)
|
||||||
|
list(APPEND LIBRARIES ${GLUT_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_CYCLES_OSL)
|
||||||
|
list(APPEND LIBRARIES cycles_kernel_osl ${OSL_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_CYCLES_PARTIO)
|
||||||
|
list(APPEND LIBRARIES ${PARTIO_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include_directories(${INC})
|
||||||
|
|
||||||
|
if(WITH_CYCLES_TEST)
|
||||||
|
set(SRC
|
||||||
|
cycles_test.cpp
|
||||||
|
cycles_xml.cpp
|
||||||
|
cycles_xml.h
|
||||||
|
)
|
||||||
|
add_executable(cycles_test ${SRC})
|
||||||
|
target_link_libraries(cycles_test ${LIBRARIES})
|
||||||
|
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
set_target_properties(cycles_test PROPERTIES INSTALL_RPATH $ORIGIN/lib)
|
||||||
|
endif()
|
||||||
|
unset(SRC)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_CYCLES_NETWORK)
|
||||||
|
set(SRC
|
||||||
|
cycles_server.cpp
|
||||||
|
)
|
||||||
|
add_executable(cycles_server ${SRC})
|
||||||
|
target_link_libraries(cycles_server ${LIBRARIES})
|
||||||
|
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
set_target_properties(cycles_server PROPERTIES INSTALL_RPATH $ORIGIN/lib)
|
||||||
|
endif()
|
||||||
|
unset(SRC)
|
||||||
|
endif()
|
||||||
|
|
71
intern/cycles/app/cycles_server.cpp
Normal file
71
intern/cycles/app/cycles_server.cpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
|
#include "util_args.h"
|
||||||
|
#include "util_foreach.h"
|
||||||
|
#include "util_path.h"
|
||||||
|
#include "util_string.h"
|
||||||
|
|
||||||
|
using namespace ccl;
|
||||||
|
|
||||||
|
int main(int argc, const char **argv)
|
||||||
|
{
|
||||||
|
path_init();
|
||||||
|
|
||||||
|
/* device types */
|
||||||
|
string devices = "";
|
||||||
|
string devicename = "cpu";
|
||||||
|
|
||||||
|
vector<DeviceType> types = Device::available_types();
|
||||||
|
|
||||||
|
foreach(DeviceType type, types) {
|
||||||
|
if(devices != "")
|
||||||
|
devices += ", ";
|
||||||
|
|
||||||
|
devices += Device::string_from_type(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse options */
|
||||||
|
ArgParse ap;
|
||||||
|
|
||||||
|
ap.options ("Usage: cycles_server [options]",
|
||||||
|
"--device %s", &devicename, ("Devices to use: " + devices).c_str(),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if(ap.parse(argc, argv) < 0) {
|
||||||
|
fprintf(stderr, "%s\n", ap.error_message().c_str());
|
||||||
|
ap.usage();
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceType dtype = Device::type_from_string(devicename.c_str());
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
Device *device = Device::create(dtype);
|
||||||
|
printf("Cycles Server with device: %s\n", device->description().c_str());
|
||||||
|
device->server_run();
|
||||||
|
delete device;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
307
intern/cycles/app/cycles_test.cpp
Normal file
307
intern/cycles/app/cycles_test.cpp
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "buffers.h"
|
||||||
|
#include "camera.h"
|
||||||
|
#include "device.h"
|
||||||
|
#include "scene.h"
|
||||||
|
#include "session.h"
|
||||||
|
|
||||||
|
#include "util_args.h"
|
||||||
|
#include "util_foreach.h"
|
||||||
|
#include "util_function.h"
|
||||||
|
#include "util_path.h"
|
||||||
|
#include "util_progress.h"
|
||||||
|
#include "util_string.h"
|
||||||
|
#include "util_time.h"
|
||||||
|
#include "util_view.h"
|
||||||
|
|
||||||
|
#include "cycles_xml.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
struct Options {
|
||||||
|
Session *session;
|
||||||
|
Scene *scene;
|
||||||
|
string filepath;
|
||||||
|
int width, height;
|
||||||
|
SceneParams scene_params;
|
||||||
|
SessionParams session_params;
|
||||||
|
bool quiet;
|
||||||
|
} options;
|
||||||
|
|
||||||
|
static void session_print(const string& str)
|
||||||
|
{
|
||||||
|
/* print with carriage return to overwrite previous */
|
||||||
|
printf("\r%s", str.c_str());
|
||||||
|
|
||||||
|
/* add spaces to overwrite longer previous print */
|
||||||
|
static int maxlen = 0;
|
||||||
|
int len = str.size();
|
||||||
|
maxlen = max(len, maxlen);
|
||||||
|
|
||||||
|
for(int i = len; i < maxlen; i++)
|
||||||
|
printf(" ");
|
||||||
|
|
||||||
|
/* flush because we don't write an end of line */
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void session_print_status()
|
||||||
|
{
|
||||||
|
int sample;
|
||||||
|
double total_time, sample_time;
|
||||||
|
string status, substatus;
|
||||||
|
|
||||||
|
/* get status */
|
||||||
|
options.session->progress.get_sample(sample, total_time, sample_time);
|
||||||
|
options.session->progress.get_status(status, substatus);
|
||||||
|
|
||||||
|
if(substatus != "")
|
||||||
|
status += ": " + substatus;
|
||||||
|
|
||||||
|
/* print status */
|
||||||
|
status = string_printf("Sample %d %s", sample, status.c_str());
|
||||||
|
session_print(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void session_init()
|
||||||
|
{
|
||||||
|
options.session = new Session(options.session_params);
|
||||||
|
options.session->reset(options.width, options.height, options.session_params.samples);
|
||||||
|
options.session->scene = options.scene;
|
||||||
|
|
||||||
|
if(options.session_params.background && !options.quiet)
|
||||||
|
options.session->progress.set_update_callback(function_bind(&session_print_status));
|
||||||
|
else
|
||||||
|
options.session->progress.set_update_callback(function_bind(&view_redraw));
|
||||||
|
|
||||||
|
options.session->start();
|
||||||
|
|
||||||
|
options.scene = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scene_init()
|
||||||
|
{
|
||||||
|
options.scene = new Scene(options.scene_params);
|
||||||
|
xml_read_file(options.scene, options.filepath.c_str());
|
||||||
|
options.width = options.scene->camera->width;
|
||||||
|
options.height = options.scene->camera->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void session_exit()
|
||||||
|
{
|
||||||
|
if(options.session) {
|
||||||
|
delete options.session;
|
||||||
|
options.session = NULL;
|
||||||
|
}
|
||||||
|
if(options.scene) {
|
||||||
|
delete options.scene;
|
||||||
|
options.scene = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(options.session_params.background && !options.quiet) {
|
||||||
|
session_print("Finished Rendering.");
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void display_info(Progress& progress)
|
||||||
|
{
|
||||||
|
static double latency = 0.0;
|
||||||
|
static double last = 0;
|
||||||
|
double elapsed = time_dt();
|
||||||
|
string str;
|
||||||
|
|
||||||
|
latency = (elapsed - last);
|
||||||
|
last = elapsed;
|
||||||
|
|
||||||
|
int sample;
|
||||||
|
double total_time, sample_time;
|
||||||
|
string status, substatus;
|
||||||
|
|
||||||
|
progress.get_sample(sample, total_time, sample_time);
|
||||||
|
progress.get_status(status, substatus);
|
||||||
|
|
||||||
|
if(substatus != "")
|
||||||
|
status += ": " + substatus;
|
||||||
|
|
||||||
|
str = string_printf("latency: %.4f sample: %d total: %.4f average: %.4f %s",
|
||||||
|
latency, sample, total_time, sample_time, status.c_str());
|
||||||
|
|
||||||
|
view_display_info(str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void display()
|
||||||
|
{
|
||||||
|
options.session->draw(options.width, options.height);
|
||||||
|
|
||||||
|
display_info(options.session->progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resize(int width, int height)
|
||||||
|
{
|
||||||
|
options.width= width;
|
||||||
|
options.height= height;
|
||||||
|
|
||||||
|
if(options.session)
|
||||||
|
options.session->reset(options.width, options.height, options.session_params.samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
void keyboard(unsigned char key)
|
||||||
|
{
|
||||||
|
if(key == 'r')
|
||||||
|
options.session->reset(options.width, options.height, options.session_params.samples);
|
||||||
|
else if(key == 27) // escape
|
||||||
|
options.session->progress.set_cancel("Cancelled");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int files_parse(int argc, const char *argv[])
|
||||||
|
{
|
||||||
|
if(argc > 0)
|
||||||
|
options.filepath = argv[0];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void options_parse(int argc, const char **argv)
|
||||||
|
{
|
||||||
|
options.width= 1024;
|
||||||
|
options.height= 512;
|
||||||
|
options.filepath = "";
|
||||||
|
options.session = NULL;
|
||||||
|
options.quiet = false;
|
||||||
|
|
||||||
|
/* devices */
|
||||||
|
string devices = "";
|
||||||
|
string devicename = "cpu";
|
||||||
|
|
||||||
|
vector<DeviceType> types = Device::available_types();
|
||||||
|
|
||||||
|
foreach(DeviceType type, types) {
|
||||||
|
if(devices != "")
|
||||||
|
devices += ", ";
|
||||||
|
|
||||||
|
devices += Device::string_from_type(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* shading system */
|
||||||
|
string ssname = "svm";
|
||||||
|
string shadingsystems = "Shading system to use: svm";
|
||||||
|
|
||||||
|
#ifdef WITH_OSL
|
||||||
|
shadingsystems += ", osl";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* parse options */
|
||||||
|
ArgParse ap;
|
||||||
|
bool help = false;
|
||||||
|
|
||||||
|
ap.options ("Usage: cycles_test [options] file.xml",
|
||||||
|
"%*", files_parse, "",
|
||||||
|
"--device %s", &devicename, ("Devices to use: " + devices).c_str(),
|
||||||
|
"--shadingsys %s", &ssname, "Shading system to use: svm, osl",
|
||||||
|
"--background", &options.session_params.background, "Render in background, without user interface",
|
||||||
|
"--quiet", &options.quiet, "In background mode, don't print progress messages",
|
||||||
|
"--samples %d", &options.session_params.samples, "Number of samples to render",
|
||||||
|
"--output %s", &options.session_params.output_path, "File path to write output image",
|
||||||
|
"--threads %d", &options.session_params.threads, "CPU Rendering Threads",
|
||||||
|
"--help", &help, "Print help message",
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if(ap.parse(argc, argv) < 0) {
|
||||||
|
fprintf(stderr, "%s\n", ap.error_message().c_str());
|
||||||
|
ap.usage();
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
else if(help || options.filepath == "") {
|
||||||
|
ap.usage();
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
options.session_params.device_type = Device::type_from_string(devicename.c_str());
|
||||||
|
|
||||||
|
if(ssname == "osl")
|
||||||
|
options.scene_params.shadingsystem = SceneParams::OSL;
|
||||||
|
else if(ssname == "svm")
|
||||||
|
options.scene_params.shadingsystem = SceneParams::SVM;
|
||||||
|
|
||||||
|
/* handle invalid configurations */
|
||||||
|
bool type_available = false;
|
||||||
|
|
||||||
|
foreach(DeviceType dtype, types)
|
||||||
|
if(options.session_params.device_type == dtype)
|
||||||
|
type_available = true;
|
||||||
|
|
||||||
|
if(options.session_params.device_type == DEVICE_NONE || !type_available) {
|
||||||
|
fprintf(stderr, "Unknown device: %s\n", devicename.c_str());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
#ifdef WITH_OSL
|
||||||
|
else if(!(ssname == "osl" || ssname == "svm")) {
|
||||||
|
#else
|
||||||
|
else if(!(ssname == "svm")) {
|
||||||
|
#endif
|
||||||
|
fprintf(stderr, "Unknown shading system: %s\n", ssname.c_str());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
else if(options.scene_params.shadingsystem == SceneParams::OSL && options.session_params.device_type != DEVICE_CPU) {
|
||||||
|
fprintf(stderr, "OSL shading system only works with CPU device\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
else if(options.session_params.samples < 0) {
|
||||||
|
fprintf(stderr, "Invalid number of samples: %d\n", options.session_params.samples);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
else if(options.filepath == "") {
|
||||||
|
fprintf(stderr, "No file path specified\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* load scene */
|
||||||
|
scene_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
using namespace ccl;
|
||||||
|
|
||||||
|
int main(int argc, const char **argv)
|
||||||
|
{
|
||||||
|
path_init("../build/bin/2.59/scripts/addons/cycles/");
|
||||||
|
|
||||||
|
options_parse(argc, argv);
|
||||||
|
|
||||||
|
if(options.session_params.background) {
|
||||||
|
session_init();
|
||||||
|
options.session->wait();
|
||||||
|
session_exit();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
string title = "Cycles: " + path_filename(options.filepath);
|
||||||
|
|
||||||
|
/* init/exit are callback so they run while GL is initialized */
|
||||||
|
view_main_loop(title.c_str(), options.width, options.height,
|
||||||
|
session_init, session_exit, resize, display, keyboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
942
intern/cycles/app/cycles_xml.cpp
Normal file
942
intern/cycles/app/cycles_xml.cpp
Normal file
@ -0,0 +1,942 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
#include "camera.h"
|
||||||
|
#include "film.h"
|
||||||
|
#include "graph.h"
|
||||||
|
#include "integrator.h"
|
||||||
|
#include "light.h"
|
||||||
|
#include "mesh.h"
|
||||||
|
#include "nodes.h"
|
||||||
|
#include "object.h"
|
||||||
|
#include "shader.h"
|
||||||
|
#include "scene.h"
|
||||||
|
|
||||||
|
#include "subd_mesh.h"
|
||||||
|
#include "subd_patch.h"
|
||||||
|
#include "subd_split.h"
|
||||||
|
|
||||||
|
#include "util_debug.h"
|
||||||
|
#include "util_foreach.h"
|
||||||
|
#include "util_path.h"
|
||||||
|
#include "util_transform.h"
|
||||||
|
#include "util_xml.h"
|
||||||
|
|
||||||
|
#include "cycles_xml.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* XML reading state */
|
||||||
|
|
||||||
|
struct XMLReadState {
|
||||||
|
Scene *scene; /* scene pointer */
|
||||||
|
Transform tfm; /* current transform state */
|
||||||
|
bool smooth; /* smooth normal state */
|
||||||
|
int shader; /* current shader */
|
||||||
|
string base; /* base path to current file*/
|
||||||
|
float dicing_rate; /* current dicing rate */
|
||||||
|
Mesh::DisplacementMethod displacement_method;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Attribute Reading */
|
||||||
|
|
||||||
|
static bool xml_read_bool(bool *value, pugi::xml_node node, const char *name)
|
||||||
|
{
|
||||||
|
pugi::xml_attribute attr = node.attribute(name);
|
||||||
|
|
||||||
|
if(attr) {
|
||||||
|
*value = (string_iequals(attr.value(), "true")) || (atoi(attr.value()) != 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool xml_read_int(int *value, pugi::xml_node node, const char *name)
|
||||||
|
{
|
||||||
|
pugi::xml_attribute attr = node.attribute(name);
|
||||||
|
|
||||||
|
if(attr) {
|
||||||
|
*value = atoi(attr.value());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool xml_read_int_array(vector<int>& value, pugi::xml_node node, const char *name)
|
||||||
|
{
|
||||||
|
pugi::xml_attribute attr = node.attribute(name);
|
||||||
|
|
||||||
|
if(attr) {
|
||||||
|
vector<string> tokens;
|
||||||
|
string_split(tokens, attr.value());
|
||||||
|
|
||||||
|
foreach(const string& token, tokens)
|
||||||
|
value.push_back(atoi(token.c_str()));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool xml_read_float(float *value, pugi::xml_node node, const char *name)
|
||||||
|
{
|
||||||
|
pugi::xml_attribute attr = node.attribute(name);
|
||||||
|
|
||||||
|
if(attr) {
|
||||||
|
*value = atof(attr.value());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool xml_read_float_array(vector<float>& value, pugi::xml_node node, const char *name)
|
||||||
|
{
|
||||||
|
pugi::xml_attribute attr = node.attribute(name);
|
||||||
|
|
||||||
|
if(attr) {
|
||||||
|
vector<string> tokens;
|
||||||
|
string_split(tokens, attr.value());
|
||||||
|
|
||||||
|
foreach(const string& token, tokens)
|
||||||
|
value.push_back(atof(token.c_str()));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool xml_read_float3(float3 *value, pugi::xml_node node, const char *name)
|
||||||
|
{
|
||||||
|
vector<float> array;
|
||||||
|
|
||||||
|
if(xml_read_float_array(array, node, name) && array.size() == 3) {
|
||||||
|
*value = make_float3(array[0], array[1], array[2]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool xml_read_float3_array(vector<float3>& value, pugi::xml_node node, const char *name)
|
||||||
|
{
|
||||||
|
vector<float> array;
|
||||||
|
|
||||||
|
if(xml_read_float_array(array, node, name)) {
|
||||||
|
for(size_t i = 0; i < array.size(); i += 3)
|
||||||
|
value.push_back(make_float3(array[i+0], array[i+1], array[i+2]));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool xml_read_float4(float4 *value, pugi::xml_node node, const char *name)
|
||||||
|
{
|
||||||
|
vector<float> array;
|
||||||
|
|
||||||
|
if(xml_read_float_array(array, node, name) && array.size() == 4) {
|
||||||
|
*value = make_float4(array[0], array[1], array[2], array[3]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool xml_read_string(string *str, pugi::xml_node node, const char *name)
|
||||||
|
{
|
||||||
|
pugi::xml_attribute attr = node.attribute(name);
|
||||||
|
|
||||||
|
if(attr) {
|
||||||
|
*str = attr.value();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool xml_read_ustring(ustring *str, pugi::xml_node node, const char *name)
|
||||||
|
{
|
||||||
|
pugi::xml_attribute attr = node.attribute(name);
|
||||||
|
|
||||||
|
if(attr) {
|
||||||
|
*str = ustring(attr.value());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool xml_equal_string(pugi::xml_node node, const char *name, const char *value)
|
||||||
|
{
|
||||||
|
pugi::xml_attribute attr = node.attribute(name);
|
||||||
|
|
||||||
|
if(attr)
|
||||||
|
return string_iequals(attr.value(), value);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool xml_read_enum(ustring *str, ShaderEnum& enm, pugi::xml_node node, const char *name)
|
||||||
|
{
|
||||||
|
pugi::xml_attribute attr = node.attribute(name);
|
||||||
|
|
||||||
|
if(attr) {
|
||||||
|
ustring ustr(attr.value());
|
||||||
|
|
||||||
|
if(enm.exists(ustr)) {
|
||||||
|
*str = ustr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fprintf(stderr, "Unknown value \"%s\" for attribute \"%s\".\n", ustr.c_str(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Film */
|
||||||
|
|
||||||
|
static void xml_read_film(const XMLReadState& state, pugi::xml_node node)
|
||||||
|
{
|
||||||
|
Camera *cam = state.scene->camera;
|
||||||
|
|
||||||
|
xml_read_int(&cam->width, node, "width");
|
||||||
|
xml_read_int(&cam->height, node, "height");
|
||||||
|
|
||||||
|
float aspect = (float)cam->width/(float)cam->height;
|
||||||
|
|
||||||
|
if(cam->width >= cam->height) {
|
||||||
|
cam->left = -aspect;
|
||||||
|
cam->right = aspect;
|
||||||
|
cam->bottom = -1.0f;
|
||||||
|
cam->top = 1.0f;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cam->left = -1.0f;
|
||||||
|
cam->right = 1.0f;
|
||||||
|
cam->bottom = -1.0f/aspect;
|
||||||
|
cam->top = 1.0f/aspect;
|
||||||
|
}
|
||||||
|
|
||||||
|
cam->need_update = true;
|
||||||
|
cam->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Integrator */
|
||||||
|
|
||||||
|
static void xml_read_integrator(const XMLReadState& state, pugi::xml_node node)
|
||||||
|
{
|
||||||
|
Integrator *integrator = state.scene->integrator;
|
||||||
|
|
||||||
|
xml_read_int(&integrator->min_bounce, node, "min_bounce");
|
||||||
|
xml_read_int(&integrator->max_bounce, node, "max_bounce");
|
||||||
|
xml_read_bool(&integrator->no_caustics, node, "no_caustics");
|
||||||
|
xml_read_float(&integrator->blur_caustics, node, "blur_caustics");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Camera */
|
||||||
|
|
||||||
|
static void xml_read_camera(const XMLReadState& state, pugi::xml_node node)
|
||||||
|
{
|
||||||
|
Camera *cam = state.scene->camera;
|
||||||
|
|
||||||
|
if(xml_read_float(&cam->fov, node, "fov"))
|
||||||
|
cam->fov *= M_PI/180.0f;
|
||||||
|
|
||||||
|
xml_read_float(&cam->nearclip, node, "nearclip");
|
||||||
|
xml_read_float(&cam->farclip, node, "farclip");
|
||||||
|
xml_read_float(&cam->aperturesize, node, "aperturesize"); // 0.5*focallength/fstop
|
||||||
|
xml_read_float(&cam->focaldistance, node, "focaldistance");
|
||||||
|
xml_read_float(&cam->shutteropen, node, "shutteropen");
|
||||||
|
xml_read_float(&cam->shutterclose, node, "shutterclose");
|
||||||
|
|
||||||
|
if(xml_equal_string(node, "type", "orthographic"))
|
||||||
|
cam->ortho = true;
|
||||||
|
else if(xml_equal_string(node, "type", "perspective"))
|
||||||
|
cam->ortho = false;
|
||||||
|
|
||||||
|
cam->matrix = state.tfm;
|
||||||
|
|
||||||
|
cam->need_update = true;
|
||||||
|
cam->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shader */
|
||||||
|
|
||||||
|
static string xml_socket_name(const char *name)
|
||||||
|
{
|
||||||
|
string sname = name;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
while((i = sname.find(" ")) != string::npos)
|
||||||
|
sname.replace(i, 1, "");
|
||||||
|
|
||||||
|
return sname;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pugi::xml_node graph_node)
|
||||||
|
{
|
||||||
|
ShaderGraph *graph = new ShaderGraph();
|
||||||
|
|
||||||
|
map<string, ShaderNode*> nodemap;
|
||||||
|
|
||||||
|
nodemap["output"] = graph->output();
|
||||||
|
|
||||||
|
for(pugi::xml_node node = graph_node.first_child(); node; node = node.next_sibling()) {
|
||||||
|
ShaderNode *snode = NULL;
|
||||||
|
|
||||||
|
if(string_iequals(node.name(), "image_texture")) {
|
||||||
|
ImageTextureNode *img = new ImageTextureNode();
|
||||||
|
|
||||||
|
xml_read_string(&img->filename, node, "src");
|
||||||
|
img->filename = path_join(state.base, img->filename);
|
||||||
|
|
||||||
|
snode = img;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "environment_texture")) {
|
||||||
|
EnvironmentTextureNode *env = new EnvironmentTextureNode();
|
||||||
|
|
||||||
|
xml_read_string(&env->filename, node, "src");
|
||||||
|
env->filename = path_join(state.base, env->filename);
|
||||||
|
|
||||||
|
snode = env;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "sky_texture")) {
|
||||||
|
SkyTextureNode *sky = new SkyTextureNode();
|
||||||
|
|
||||||
|
xml_read_float3(&sky->sun_direction, node, "sun_direction");
|
||||||
|
xml_read_float(&sky->turbidity, node, "turbidity");
|
||||||
|
|
||||||
|
snode = sky;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "noise_texture")) {
|
||||||
|
snode = new NoiseTextureNode();
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "blend_texture")) {
|
||||||
|
BlendTextureNode *blend = new BlendTextureNode();
|
||||||
|
xml_read_enum(&blend->progression, BlendTextureNode::progression_enum, node, "progression");
|
||||||
|
xml_read_enum(&blend->axis, BlendTextureNode::axis_enum, node, "axis");
|
||||||
|
snode = blend;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "clouds_texture")) {
|
||||||
|
CloudsTextureNode *clouds = new CloudsTextureNode();
|
||||||
|
xml_read_bool(&clouds->hard, node, "hard");
|
||||||
|
xml_read_int(&clouds->depth, node, "depth");
|
||||||
|
xml_read_enum(&clouds->basis, CloudsTextureNode::basis_enum, node, "basis");
|
||||||
|
snode = clouds;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "voronoi_texture")) {
|
||||||
|
VoronoiTextureNode *voronoi = new VoronoiTextureNode();
|
||||||
|
xml_read_enum(&voronoi->distance_metric, VoronoiTextureNode::distance_metric_enum, node, "distance_metric");
|
||||||
|
xml_read_enum(&voronoi->coloring, VoronoiTextureNode::coloring_enum, node, "coloring");
|
||||||
|
snode = voronoi;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "musgrave_texture")) {
|
||||||
|
MusgraveTextureNode *musgrave = new MusgraveTextureNode();
|
||||||
|
xml_read_enum(&musgrave->type, MusgraveTextureNode::type_enum, node, "type");
|
||||||
|
xml_read_enum(&musgrave->basis, MusgraveTextureNode::basis_enum, node, "basis");
|
||||||
|
snode = musgrave;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "marble_texture")) {
|
||||||
|
MarbleTextureNode *marble = new MarbleTextureNode();
|
||||||
|
xml_read_enum(&marble->type, MarbleTextureNode::type_enum, node, "type");
|
||||||
|
xml_read_enum(&marble->wave, MarbleTextureNode::wave_enum, node, "wave");
|
||||||
|
xml_read_enum(&marble->basis, MarbleTextureNode::basis_enum, node, "basis");
|
||||||
|
xml_read_bool(&marble->hard, node, "hard");
|
||||||
|
xml_read_int(&marble->depth, node, "depth");
|
||||||
|
snode = marble;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "magic_texture")) {
|
||||||
|
MagicTextureNode *magic = new MagicTextureNode();
|
||||||
|
xml_read_int(&magic->depth, node, "depth");
|
||||||
|
snode = magic;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "stucci_texture")) {
|
||||||
|
StucciTextureNode *stucci = new StucciTextureNode();
|
||||||
|
xml_read_enum(&stucci->type, StucciTextureNode::type_enum, node, "type");
|
||||||
|
xml_read_enum(&stucci->basis, StucciTextureNode::basis_enum, node, "basis");
|
||||||
|
xml_read_bool(&stucci->hard, node, "hard");
|
||||||
|
snode = stucci;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "distorted_noise_texture")) {
|
||||||
|
DistortedNoiseTextureNode *dist = new DistortedNoiseTextureNode();
|
||||||
|
xml_read_enum(&dist->basis, DistortedNoiseTextureNode::basis_enum, node, "basis");
|
||||||
|
xml_read_enum(&dist->distortion_basis, DistortedNoiseTextureNode::basis_enum, node, "distortion_basis");
|
||||||
|
snode = dist;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "wood_texture")) {
|
||||||
|
WoodTextureNode *wood = new WoodTextureNode();
|
||||||
|
xml_read_enum(&wood->type, WoodTextureNode::type_enum, node, "type");
|
||||||
|
xml_read_enum(&wood->wave, WoodTextureNode::wave_enum, node, "wave");
|
||||||
|
xml_read_enum(&wood->basis, WoodTextureNode::basis_enum, node, "basis");
|
||||||
|
xml_read_bool(&wood->hard, node, "hard");
|
||||||
|
snode = wood;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "mapping")) {
|
||||||
|
snode = new MappingNode();
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "ward_bsdf")) {
|
||||||
|
snode = new WardBsdfNode();
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "diffuse_bsdf")) {
|
||||||
|
snode = new DiffuseBsdfNode();
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "translucent_bsdf")) {
|
||||||
|
snode = new TranslucentBsdfNode();
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "transparent_bsdf")) {
|
||||||
|
snode = new TransparentBsdfNode();
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "velvet_bsdf")) {
|
||||||
|
snode = new VelvetBsdfNode();
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "glossy_bsdf")) {
|
||||||
|
GlossyBsdfNode *glossy = new GlossyBsdfNode();
|
||||||
|
xml_read_enum(&glossy->distribution, GlossyBsdfNode::distribution_enum, node, "distribution");
|
||||||
|
snode = glossy;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "glass_bsdf")) {
|
||||||
|
GlassBsdfNode *diel = new GlassBsdfNode();
|
||||||
|
xml_read_enum(&diel->distribution, GlassBsdfNode::distribution_enum, node, "distribution");
|
||||||
|
snode = diel;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "emission")) {
|
||||||
|
EmissionNode *emission = new EmissionNode();
|
||||||
|
xml_read_bool(&emission->total_power, node, "total_power");
|
||||||
|
snode = emission;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "background")) {
|
||||||
|
snode = new BackgroundNode();
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "transparent_volume")) {
|
||||||
|
snode = new TransparentVolumeNode();
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "isotropic_volume")) {
|
||||||
|
snode = new IsotropicVolumeNode();
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "geometry")) {
|
||||||
|
snode = new GeometryNode();
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "texture_coordinate")) {
|
||||||
|
snode = new TextureCoordinateNode();
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "lightPath")) {
|
||||||
|
snode = new LightPathNode();
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "value")) {
|
||||||
|
ValueNode *value = new ValueNode();
|
||||||
|
xml_read_float(&value->value, node, "value");
|
||||||
|
snode = value;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "color")) {
|
||||||
|
ColorNode *color = new ColorNode();
|
||||||
|
xml_read_float3(&color->value, node, "value");
|
||||||
|
snode = color;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "mix_closure")) {
|
||||||
|
snode = new MixClosureNode();
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "add_closure")) {
|
||||||
|
snode = new AddClosureNode();
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "mix")) {
|
||||||
|
MixNode *mix = new MixNode();
|
||||||
|
xml_read_enum(&mix->type, MixNode::type_enum, node, "type");
|
||||||
|
snode = mix;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "attribute")) {
|
||||||
|
AttributeNode *attr = new AttributeNode();
|
||||||
|
xml_read_ustring(&attr->attribute, node, "attribute");
|
||||||
|
snode = attr;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "fresnel")) {
|
||||||
|
snode = new FresnelNode();
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "math")) {
|
||||||
|
MathNode *math = new MathNode();
|
||||||
|
xml_read_enum(&math->type, MathNode::type_enum, node, "type");
|
||||||
|
snode = math;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "vector_math")) {
|
||||||
|
VectorMathNode *vmath = new VectorMathNode();
|
||||||
|
xml_read_enum(&vmath->type, VectorMathNode::type_enum, node, "type");
|
||||||
|
snode = vmath;
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "connect")) {
|
||||||
|
/* connect nodes */
|
||||||
|
vector<string> from_tokens, to_tokens;
|
||||||
|
|
||||||
|
string_split(from_tokens, node.attribute("from").value());
|
||||||
|
string_split(to_tokens, node.attribute("to").value());
|
||||||
|
|
||||||
|
if(from_tokens.size() == 2 && to_tokens.size() == 2) {
|
||||||
|
/* find nodes and sockets */
|
||||||
|
ShaderOutput *output = NULL;
|
||||||
|
ShaderInput *input = NULL;
|
||||||
|
|
||||||
|
if(nodemap.find(from_tokens[0]) != nodemap.end()) {
|
||||||
|
ShaderNode *fromnode = nodemap[from_tokens[0]];
|
||||||
|
|
||||||
|
foreach(ShaderOutput *out, fromnode->outputs)
|
||||||
|
if(string_iequals(xml_socket_name(out->name), from_tokens[1]))
|
||||||
|
output = out;
|
||||||
|
|
||||||
|
if(!output)
|
||||||
|
fprintf(stderr, "Unknown output socket name \"%s\" on \"%s\".\n", from_tokens[1].c_str(), from_tokens[0].c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fprintf(stderr, "Unknown shader node name \"%s\".\n", from_tokens[0].c_str());
|
||||||
|
|
||||||
|
if(nodemap.find(to_tokens[0]) != nodemap.end()) {
|
||||||
|
ShaderNode *tonode = nodemap[to_tokens[0]];
|
||||||
|
|
||||||
|
foreach(ShaderInput *in, tonode->inputs)
|
||||||
|
if(string_iequals(xml_socket_name(in->name), to_tokens[1]))
|
||||||
|
input = in;
|
||||||
|
|
||||||
|
if(!input)
|
||||||
|
fprintf(stderr, "Unknown input socket name \"%s\" on \"%s\".\n", to_tokens[1].c_str(), to_tokens[0].c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fprintf(stderr, "Unknown shader node name \"%s\".\n", to_tokens[0].c_str());
|
||||||
|
|
||||||
|
/* connect */
|
||||||
|
if(output && input)
|
||||||
|
graph->connect(output, input);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fprintf(stderr, "Invalid from or to value for connect node.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fprintf(stderr, "Unknown shader node \"%s\".\n", node.name());
|
||||||
|
|
||||||
|
if(snode) {
|
||||||
|
/* add to graph */
|
||||||
|
graph->add(snode);
|
||||||
|
|
||||||
|
/* add to map for name lookups */
|
||||||
|
string name = "";
|
||||||
|
xml_read_string(&name, node, "name");
|
||||||
|
|
||||||
|
nodemap[name] = snode;
|
||||||
|
|
||||||
|
/* read input values */
|
||||||
|
for(pugi::xml_attribute attr = node.first_attribute(); attr; attr = attr.next_attribute()) {
|
||||||
|
foreach(ShaderInput *in, snode->inputs) {
|
||||||
|
if(string_iequals(in->name, attr.name())) {
|
||||||
|
switch(in->type) {
|
||||||
|
case SHADER_SOCKET_FLOAT:
|
||||||
|
xml_read_float(&in->value.x, node, attr.name());
|
||||||
|
break;
|
||||||
|
case SHADER_SOCKET_COLOR:
|
||||||
|
case SHADER_SOCKET_VECTOR:
|
||||||
|
case SHADER_SOCKET_POINT:
|
||||||
|
case SHADER_SOCKET_NORMAL:
|
||||||
|
xml_read_float3(&in->value, node, attr.name());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shader->set_graph(graph);
|
||||||
|
shader->tag_update(state.scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xml_read_shader(const XMLReadState& state, pugi::xml_node node)
|
||||||
|
{
|
||||||
|
Shader *shader = new Shader();
|
||||||
|
xml_read_string(&shader->name, node, "name");
|
||||||
|
xml_read_shader_graph(state, shader, node);
|
||||||
|
state.scene->shaders.push_back(shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Background */
|
||||||
|
|
||||||
|
static void xml_read_background(const XMLReadState& state, pugi::xml_node node)
|
||||||
|
{
|
||||||
|
Shader *shader = state.scene->shaders[state.scene->default_background];
|
||||||
|
|
||||||
|
xml_read_shader_graph(state, shader, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mesh */
|
||||||
|
|
||||||
|
static Mesh *xml_add_mesh(Scene *scene, const Transform& tfm)
|
||||||
|
{
|
||||||
|
/* create mesh */
|
||||||
|
Mesh *mesh = new Mesh();
|
||||||
|
scene->meshes.push_back(mesh);
|
||||||
|
|
||||||
|
/* create object*/
|
||||||
|
Object *object = new Object();
|
||||||
|
object->mesh = mesh;
|
||||||
|
object->tfm = tfm;
|
||||||
|
scene->objects.push_back(object);
|
||||||
|
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node)
|
||||||
|
{
|
||||||
|
/* add mesh */
|
||||||
|
Mesh *mesh = xml_add_mesh(state.scene, state.tfm);
|
||||||
|
mesh->used_shaders.push_back(state.shader);
|
||||||
|
|
||||||
|
/* read state */
|
||||||
|
int shader = state.shader;
|
||||||
|
bool smooth = state.smooth;
|
||||||
|
|
||||||
|
mesh->displacement_method = state.displacement_method;
|
||||||
|
|
||||||
|
/* read vertices and polygons, RIB style */
|
||||||
|
vector<float3> P;
|
||||||
|
vector<int> verts, nverts;
|
||||||
|
|
||||||
|
xml_read_float3_array(P, node, "P");
|
||||||
|
xml_read_int_array(verts, node, "verts");
|
||||||
|
xml_read_int_array(nverts, node, "nverts");
|
||||||
|
|
||||||
|
if(xml_equal_string(node, "subdivision", "catmull-clark")) {
|
||||||
|
/* create subd mesh */
|
||||||
|
SubdMesh sdmesh;
|
||||||
|
|
||||||
|
/* create subd vertices */
|
||||||
|
for(size_t i = 0; i < P.size(); i++)
|
||||||
|
sdmesh.add_vert(P[i]);
|
||||||
|
|
||||||
|
/* create subd faces */
|
||||||
|
int index_offset = 0;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < nverts.size(); i++) {
|
||||||
|
if(nverts[i] == 4) {
|
||||||
|
int v0 = verts[index_offset + 0];
|
||||||
|
int v1 = verts[index_offset + 1];
|
||||||
|
int v2 = verts[index_offset + 2];
|
||||||
|
int v3 = verts[index_offset + 3];
|
||||||
|
|
||||||
|
sdmesh.add_face(v0, v1, v2, v3);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for(int j = 0; j < nverts[i]-2; j++) {
|
||||||
|
int v0 = verts[index_offset];
|
||||||
|
int v1 = verts[index_offset + j + 1];
|
||||||
|
int v2 = verts[index_offset + j + 2];;
|
||||||
|
|
||||||
|
sdmesh.add_face(v0, v1, v2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
index_offset += nverts[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finalize subd mesh */
|
||||||
|
sdmesh.link_boundary();
|
||||||
|
|
||||||
|
/* subdivide */
|
||||||
|
DiagSplit dsplit;
|
||||||
|
//dsplit.camera = state.scene->camera;
|
||||||
|
//dsplit.dicing_rate = 5.0f;
|
||||||
|
dsplit.dicing_rate = state.dicing_rate;
|
||||||
|
xml_read_float(&dsplit.dicing_rate, node, "dicing_rate");
|
||||||
|
sdmesh.tesselate(&dsplit, false, mesh, shader, smooth);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* create vertices */
|
||||||
|
mesh->verts = P;
|
||||||
|
|
||||||
|
/* create triangles */
|
||||||
|
int index_offset = 0;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < nverts.size(); i++) {
|
||||||
|
for(int j = 0; j < nverts[i]-2; j++) {
|
||||||
|
int v0 = verts[index_offset];
|
||||||
|
int v1 = verts[index_offset + j + 1];
|
||||||
|
int v2 = verts[index_offset + j + 2];
|
||||||
|
|
||||||
|
assert(v0 < (int)P.size());
|
||||||
|
assert(v1 < (int)P.size());
|
||||||
|
assert(v2 < (int)P.size());
|
||||||
|
|
||||||
|
mesh->add_triangle(v0, v1, v2, shader, smooth);
|
||||||
|
}
|
||||||
|
|
||||||
|
index_offset += nverts[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* temporary for test compatibility */
|
||||||
|
mesh->attributes.remove(Attribute::STD_VERTEX_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Patch */
|
||||||
|
|
||||||
|
static void xml_read_patch(const XMLReadState& state, pugi::xml_node node)
|
||||||
|
{
|
||||||
|
/* read patch */
|
||||||
|
Patch *patch = NULL;
|
||||||
|
|
||||||
|
vector<float3> P;
|
||||||
|
xml_read_float3_array(P, node, "P");
|
||||||
|
|
||||||
|
if(xml_equal_string(node, "type", "bilinear")) {
|
||||||
|
/* bilinear patch */
|
||||||
|
if(P.size() == 4) {
|
||||||
|
LinearQuadPatch *bpatch = new LinearQuadPatch();
|
||||||
|
|
||||||
|
for(int i = 0; i < 4; i++)
|
||||||
|
P[i] = transform(&state.tfm, P[i]);
|
||||||
|
memcpy(bpatch->hull, &P[0], sizeof(bpatch->hull));
|
||||||
|
|
||||||
|
patch = bpatch;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fprintf(stderr, "Invalid number of control points for bilinear patch.\n");
|
||||||
|
}
|
||||||
|
else if(xml_equal_string(node, "type", "bicubic")) {
|
||||||
|
/* bicubic patch */
|
||||||
|
if(P.size() == 16) {
|
||||||
|
BicubicPatch *bpatch = new BicubicPatch();
|
||||||
|
|
||||||
|
for(int i = 0; i < 16; i++)
|
||||||
|
P[i] = transform(&state.tfm, P[i]);
|
||||||
|
memcpy(bpatch->hull, &P[0], sizeof(bpatch->hull));
|
||||||
|
|
||||||
|
patch = bpatch;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fprintf(stderr, "Invalid number of control points for bicubic patch.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fprintf(stderr, "Unknown patch type.\n");
|
||||||
|
|
||||||
|
if(patch) {
|
||||||
|
/* add mesh */
|
||||||
|
Mesh *mesh = xml_add_mesh(state.scene, transform_identity());
|
||||||
|
|
||||||
|
mesh->used_shaders.push_back(state.shader);
|
||||||
|
|
||||||
|
/* split */
|
||||||
|
DiagSplit dsplit;
|
||||||
|
//dsplit.camera = state.scene->camera;
|
||||||
|
//dsplit.dicing_rate = 5.0f;
|
||||||
|
dsplit.dicing_rate = state.dicing_rate;
|
||||||
|
xml_read_float(&dsplit.dicing_rate, node, "dicing_rate");
|
||||||
|
dsplit.split_quad(mesh, patch, state.shader, state.smooth);
|
||||||
|
|
||||||
|
delete patch;
|
||||||
|
|
||||||
|
/* temporary for test compatibility */
|
||||||
|
mesh->attributes.remove(Attribute::STD_VERTEX_NORMAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Light */
|
||||||
|
|
||||||
|
static void xml_read_light(const XMLReadState& state, pugi::xml_node node)
|
||||||
|
{
|
||||||
|
Light *light = new Light();
|
||||||
|
light->shader = state.shader;
|
||||||
|
xml_read_float3(&light->co, node, "P");
|
||||||
|
light->co = transform(&state.tfm, light->co);
|
||||||
|
|
||||||
|
state.scene->lights.push_back(light);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transform */
|
||||||
|
|
||||||
|
static void xml_read_transform(pugi::xml_node node, Transform& tfm)
|
||||||
|
{
|
||||||
|
if(node.attribute("matrix")) {
|
||||||
|
vector<float> matrix;
|
||||||
|
if(xml_read_float_array(matrix, node, "matrix") && matrix.size() == 16)
|
||||||
|
tfm = tfm * transform_transpose((*(Transform*)&matrix[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node.attribute("translate")) {
|
||||||
|
float3 translate = make_float3(0.0f, 0.0f, 0.0f);
|
||||||
|
xml_read_float3(&translate, node, "translate");
|
||||||
|
tfm = tfm * transform_translate(translate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node.attribute("rotate")) {
|
||||||
|
float4 rotate = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
xml_read_float4(&rotate, node, "rotate");
|
||||||
|
tfm = tfm * transform_rotate(rotate.x*M_PI/180.0f, make_float3(rotate.y, rotate.z, rotate.w));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node.attribute("scale")) {
|
||||||
|
float3 scale = make_float3(0.0f, 0.0f, 0.0f);
|
||||||
|
xml_read_float3(&scale, node, "scale");
|
||||||
|
tfm = tfm * transform_scale(scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* State */
|
||||||
|
|
||||||
|
static void xml_read_state(XMLReadState& state, pugi::xml_node node)
|
||||||
|
{
|
||||||
|
/* read shader */
|
||||||
|
string shadername;
|
||||||
|
|
||||||
|
if(xml_read_string(&shadername, node, "shader")) {
|
||||||
|
int i = 0;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
foreach(Shader *shader, state.scene->shaders) {
|
||||||
|
if(shader->name == shadername) {
|
||||||
|
state.shader = i;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!found)
|
||||||
|
fprintf(stderr, "Unknown shader \"%s\".\n", shadername.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
xml_read_float(&state.dicing_rate, node, "dicing_rate");
|
||||||
|
|
||||||
|
/* read smooth/flat */
|
||||||
|
if(xml_equal_string(node, "interpolation", "smooth"))
|
||||||
|
state.smooth = true;
|
||||||
|
else if(xml_equal_string(node, "interpolation", "flat"))
|
||||||
|
state.smooth = false;
|
||||||
|
|
||||||
|
/* read displacement method */
|
||||||
|
if(xml_equal_string(node, "displacement_method", "true"))
|
||||||
|
state.displacement_method = Mesh::DISPLACE_TRUE;
|
||||||
|
else if(xml_equal_string(node, "displacement_method", "bump"))
|
||||||
|
state.displacement_method = Mesh::DISPLACE_BUMP;
|
||||||
|
else if(xml_equal_string(node, "displacement_method", "both"))
|
||||||
|
state.displacement_method = Mesh::DISPLACE_BOTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scene */
|
||||||
|
|
||||||
|
static void xml_read_include(const XMLReadState& state, const string& src);
|
||||||
|
|
||||||
|
static void xml_read_scene(const XMLReadState& state, pugi::xml_node scene_node)
|
||||||
|
{
|
||||||
|
for(pugi::xml_node node = scene_node.first_child(); node; node = node.next_sibling()) {
|
||||||
|
if(string_iequals(node.name(), "film")) {
|
||||||
|
xml_read_film(state, node);
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "integrator")) {
|
||||||
|
xml_read_integrator(state, node);
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "camera")) {
|
||||||
|
xml_read_camera(state, node);
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "shader")) {
|
||||||
|
xml_read_shader(state, node);
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "background")) {
|
||||||
|
xml_read_background(state, node);
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "mesh")) {
|
||||||
|
xml_read_mesh(state, node);
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "patch")) {
|
||||||
|
xml_read_patch(state, node);
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "light")) {
|
||||||
|
xml_read_light(state, node);
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "transform")) {
|
||||||
|
XMLReadState substate = state;
|
||||||
|
|
||||||
|
xml_read_transform(node, substate.tfm);
|
||||||
|
xml_read_scene(substate, node);
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "state")) {
|
||||||
|
XMLReadState substate = state;
|
||||||
|
|
||||||
|
xml_read_state(substate, node);
|
||||||
|
xml_read_scene(substate, node);
|
||||||
|
}
|
||||||
|
else if(string_iequals(node.name(), "include")) {
|
||||||
|
string src;
|
||||||
|
|
||||||
|
if(xml_read_string(&src, node, "src"))
|
||||||
|
xml_read_include(state, src);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fprintf(stderr, "Unknown node \"%s\".\n", node.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Include */
|
||||||
|
|
||||||
|
static void xml_read_include(const XMLReadState& state, const string& src)
|
||||||
|
{
|
||||||
|
/* open XML document */
|
||||||
|
pugi::xml_document doc;
|
||||||
|
pugi::xml_parse_result parse_result;
|
||||||
|
|
||||||
|
string path = path_join(state.base, src);
|
||||||
|
parse_result = doc.load_file(path.c_str());
|
||||||
|
|
||||||
|
if(parse_result) {
|
||||||
|
XMLReadState substate = state;
|
||||||
|
substate.base = path_dirname(path);
|
||||||
|
|
||||||
|
xml_read_scene(substate, doc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fprintf(stderr, "%s read error: %s\n", src.c_str(), parse_result.description());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* File */
|
||||||
|
|
||||||
|
void xml_read_file(Scene *scene, const char *filepath)
|
||||||
|
{
|
||||||
|
XMLReadState state;
|
||||||
|
|
||||||
|
state.scene = scene;
|
||||||
|
state.tfm = transform_identity();
|
||||||
|
state.shader = scene->default_surface;
|
||||||
|
state.smooth = false;
|
||||||
|
state.dicing_rate = 0.1f;
|
||||||
|
state.base = path_dirname(filepath);
|
||||||
|
|
||||||
|
xml_read_include(state, path_filename(filepath));
|
||||||
|
|
||||||
|
scene->params.bvh_type = SceneParams::BVH_STATIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
31
intern/cycles/app/cycles_xml.h
Normal file
31
intern/cycles/app/cycles_xml.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CYCLES_XML__
|
||||||
|
#define __CYCLES_XML__
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class Scene;
|
||||||
|
|
||||||
|
void xml_read_file(Scene *scene, const char *filepath);
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* __CYCLES_XML__ */
|
||||||
|
|
47
intern/cycles/blender/CMakeLists.txt
Normal file
47
intern/cycles/blender/CMakeLists.txt
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
set(INC
|
||||||
|
../render
|
||||||
|
../device
|
||||||
|
../kernel
|
||||||
|
../kernel/svm
|
||||||
|
../util
|
||||||
|
../subd
|
||||||
|
)
|
||||||
|
|
||||||
|
set(INC_SYS
|
||||||
|
${BLENDER_INCLUDE_DIRS}
|
||||||
|
${PYTHON_INCLUDE_DIRS}
|
||||||
|
${GLEW_INCLUDE_PATH}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
set(SRC
|
||||||
|
blender_camera.cpp
|
||||||
|
blender_mesh.cpp
|
||||||
|
blender_object.cpp
|
||||||
|
blender_python.cpp
|
||||||
|
blender_session.cpp
|
||||||
|
blender_shader.cpp
|
||||||
|
blender_sync.cpp
|
||||||
|
|
||||||
|
blender_sync.h
|
||||||
|
blender_session.h
|
||||||
|
blender_util.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(ADDON_FILES
|
||||||
|
addon/__init__.py
|
||||||
|
addon/engine.py
|
||||||
|
addon/enums.py
|
||||||
|
addon/presets.py
|
||||||
|
addon/properties.py
|
||||||
|
addon/ui.py
|
||||||
|
addon/xml.py
|
||||||
|
)
|
||||||
|
|
||||||
|
blender_add_lib(bf_intern_cycles "${SRC}" "${INC}" "${INC_SYS}")
|
||||||
|
|
||||||
|
add_dependencies(bf_intern_cycles bf_rna)
|
||||||
|
|
||||||
|
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${ADDON_FILES}" ${CYCLES_INSTALL_PATH})
|
||||||
|
|
90
intern/cycles/blender/addon/__init__.py
Normal file
90
intern/cycles/blender/addon/__init__.py
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2011, Blender Foundation.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
bl_info = {
|
||||||
|
"name": "Cycles Render Engine",
|
||||||
|
"author": "",
|
||||||
|
"version": (0,0),
|
||||||
|
"blender": (2, 5, 6),
|
||||||
|
"api": 34462,
|
||||||
|
"location": "Info header, render engine menu",
|
||||||
|
"description": "Cycles Render Engine integration.",
|
||||||
|
"warning": "",
|
||||||
|
"wiki_url": "",
|
||||||
|
"tracker_url": "",
|
||||||
|
"category": "Render"}
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
|
||||||
|
from cycles import ui
|
||||||
|
from cycles import properties
|
||||||
|
from cycles import xml
|
||||||
|
from cycles import engine
|
||||||
|
from cycles import presets
|
||||||
|
|
||||||
|
class CyclesRender(bpy.types.RenderEngine):
|
||||||
|
bl_idname = 'CYCLES'
|
||||||
|
bl_label = "Cycles"
|
||||||
|
bl_use_shading_nodes = True
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
engine.init()
|
||||||
|
self.session = None
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
engine.free(self)
|
||||||
|
|
||||||
|
# final render
|
||||||
|
def update(self, data, scene):
|
||||||
|
engine.create(self, data, scene)
|
||||||
|
engine.update(self, data, scene)
|
||||||
|
|
||||||
|
def render(self, scene):
|
||||||
|
engine.render(self)
|
||||||
|
|
||||||
|
# preview render
|
||||||
|
# def preview_update(self, context, id):
|
||||||
|
# pass
|
||||||
|
#
|
||||||
|
# def preview_render(self):
|
||||||
|
# pass
|
||||||
|
|
||||||
|
# viewport render
|
||||||
|
def view_update(self, context):
|
||||||
|
if not self.session:
|
||||||
|
engine.create(self, context.blend_data, context.scene,
|
||||||
|
context.region, context.space_data, context.region_data)
|
||||||
|
engine.update(self, context.blend_data, context.scene)
|
||||||
|
|
||||||
|
def view_draw(self, context):
|
||||||
|
engine.draw(self, context.region, context.space_data, context.region_data)
|
||||||
|
|
||||||
|
def register():
|
||||||
|
properties.register()
|
||||||
|
ui.register()
|
||||||
|
xml.register()
|
||||||
|
presets.register()
|
||||||
|
bpy.utils.register_module(__name__)
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
xml.unregister()
|
||||||
|
ui.unregister()
|
||||||
|
properties.unregister()
|
||||||
|
presets.unregister()
|
||||||
|
bpy.utils.unregister_module(__name__)
|
||||||
|
|
74
intern/cycles/blender/addon/engine.py
Normal file
74
intern/cycles/blender/addon/engine.py
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2011, Blender Foundation.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
|
||||||
|
def init():
|
||||||
|
import bcycles
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
path = os.path.dirname(__file__)
|
||||||
|
user_path = os.path.dirname(os.path.abspath(bpy.utils.user_resource('CONFIG', '')))
|
||||||
|
|
||||||
|
bcycles.init(path, user_path)
|
||||||
|
|
||||||
|
def create(engine, data, scene, region = 0, v3d = 0, rv3d = 0):
|
||||||
|
import bcycles
|
||||||
|
|
||||||
|
data = data.as_pointer()
|
||||||
|
scene = scene.as_pointer()
|
||||||
|
if region:
|
||||||
|
region = region.as_pointer()
|
||||||
|
if v3d:
|
||||||
|
v3d = v3d.as_pointer()
|
||||||
|
if rv3d:
|
||||||
|
rv3d = rv3d.as_pointer()
|
||||||
|
|
||||||
|
engine.session = bcycles.create(engine.as_pointer(), data, scene, region, v3d, rv3d)
|
||||||
|
|
||||||
|
def free(engine):
|
||||||
|
if "session" in dir(engine):
|
||||||
|
if engine.session:
|
||||||
|
import bcycles
|
||||||
|
bcycles.free(engine.session)
|
||||||
|
del engine.session
|
||||||
|
|
||||||
|
def render(engine):
|
||||||
|
import bcycles
|
||||||
|
bcycles.render(engine.session)
|
||||||
|
|
||||||
|
def update(engine, data, scene):
|
||||||
|
import bcycles
|
||||||
|
bcycles.sync(engine.session)
|
||||||
|
|
||||||
|
def draw(engine, region, v3d, rv3d):
|
||||||
|
import bcycles
|
||||||
|
v3d = v3d.as_pointer()
|
||||||
|
rv3d = rv3d.as_pointer()
|
||||||
|
|
||||||
|
# draw render image
|
||||||
|
bcycles.draw(engine.session, v3d, rv3d)
|
||||||
|
|
||||||
|
def available_devices():
|
||||||
|
import bcycles
|
||||||
|
return bcycles.available_devices()
|
||||||
|
|
||||||
|
def with_osl():
|
||||||
|
import bcycles
|
||||||
|
return bcycles.with_osl()
|
||||||
|
|
59
intern/cycles/blender/addon/enums.py
Normal file
59
intern/cycles/blender/addon/enums.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2011, Blender Foundation.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
from cycles import engine
|
||||||
|
|
||||||
|
def get_gpu_device():
|
||||||
|
available_devices = engine.available_devices()
|
||||||
|
cuda = 'cuda' in available_devices
|
||||||
|
opencl = 'opencl' in available_devices
|
||||||
|
if cuda and opencl:
|
||||||
|
gpu_string = "GPU"
|
||||||
|
elif cuda and not opencl:
|
||||||
|
gpu_string = "CUDA GPU"
|
||||||
|
else:
|
||||||
|
gpu_string = "OpenCL GPU"
|
||||||
|
|
||||||
|
return gpu_string
|
||||||
|
|
||||||
|
devices = (
|
||||||
|
("CPU", "CPU", "Processor"),
|
||||||
|
("GPU", get_gpu_device(), "Graphics card"))
|
||||||
|
|
||||||
|
gpu_type = (
|
||||||
|
("CUDA", "CUDA", "NVidia only"),
|
||||||
|
("OPENCL", "OpenCL (incomplete)", ""))
|
||||||
|
|
||||||
|
shading_systems = (
|
||||||
|
("GPU_COMPATIBLE", "GPU Compatible", "Restricted shading system compatible with GPU rendering"),
|
||||||
|
("OSL", "Open Shading Language", "Open Shading Language shading system that only runs on the CPU"))
|
||||||
|
|
||||||
|
displacement_methods = (
|
||||||
|
("BUMP", "Bump", "Bump mapping to simulate the appearance of displacement"),
|
||||||
|
("TRUE", "True", "Use true displacement only, requires fine subdivision"),
|
||||||
|
("BOTH", "Both", "Combination of displacement and bump mapping"))
|
||||||
|
|
||||||
|
bvh_types = (
|
||||||
|
("DYNAMIC_BVH", "Dynamic BVH", "Objects can be individually updated, at the cost of slower render time"),
|
||||||
|
("STATIC_BVH", "Static BVH", "Any object modification requires a complete BVH rebuild, but renders faster"))
|
||||||
|
|
||||||
|
filter_types = (
|
||||||
|
("BOX", "Box", "Box filter"),
|
||||||
|
("GAUSSIAN", "Gaussian", "Gaussian filter"))
|
||||||
|
|
||||||
|
|
53
intern/cycles/blender/addon/presets.py
Normal file
53
intern/cycles/blender/addon/presets.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2011, Blender Foundation.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
from bl_operators.presets import AddPresetBase
|
||||||
|
from bpy.types import Operator
|
||||||
|
|
||||||
|
class AddPresetIntegrator(AddPresetBase, Operator):
|
||||||
|
'''Add an Integrator Preset'''
|
||||||
|
bl_idname = "render.cycles_integrator_preset_add"
|
||||||
|
bl_label = "Add Integrator Preset"
|
||||||
|
preset_menu = "CYCLES_MT_integrator_presets"
|
||||||
|
|
||||||
|
preset_defines = [
|
||||||
|
"cycles = bpy.context.scene.cycles"
|
||||||
|
]
|
||||||
|
|
||||||
|
preset_values = [
|
||||||
|
"cycles.max_bounces",
|
||||||
|
"cycles.min_bounces",
|
||||||
|
"cycles.no_caustics",
|
||||||
|
"cycles.diffuse_bounces",
|
||||||
|
"cycles.glossy_bounces",
|
||||||
|
"cycles.transmission_bounces",
|
||||||
|
"cycles.transparent_min_bounces",
|
||||||
|
"cycles.transparent_max_bounces"
|
||||||
|
]
|
||||||
|
|
||||||
|
preset_subdir = "cycles/integrator"
|
||||||
|
|
||||||
|
def register():
|
||||||
|
pass
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
pass
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
register()
|
||||||
|
|
201
intern/cycles/blender/addon/properties.py
Normal file
201
intern/cycles/blender/addon/properties.py
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2011, Blender Foundation.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
from bpy.props import *
|
||||||
|
|
||||||
|
import math
|
||||||
|
|
||||||
|
from cycles import enums
|
||||||
|
|
||||||
|
class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||||
|
@classmethod
|
||||||
|
def register(cls):
|
||||||
|
bpy.types.Scene.cycles = PointerProperty(type=cls, name="Cycles Render Settings", description="Cycles render settings")
|
||||||
|
|
||||||
|
cls.device = EnumProperty(name="Device", description="Device to use for rendering",
|
||||||
|
items=enums.devices, default="CPU")
|
||||||
|
|
||||||
|
cls.gpu_type = EnumProperty(name="GPU Type", description="Processing system to use on the GPU",
|
||||||
|
items=enums.gpu_type, default="CUDA")
|
||||||
|
|
||||||
|
cls.shading_system = EnumProperty(name="Shading System", description="Shading system to use for rendering",
|
||||||
|
items=enums.shading_systems, default="GPU_COMPATIBLE")
|
||||||
|
|
||||||
|
cls.samples = IntProperty(name="Samples", description="Number of samples to render for each pixel",
|
||||||
|
default=10, min=1, max=2147483647)
|
||||||
|
cls.preview_samples = IntProperty(name="Preview Samples", description="Number of samples to render in the viewport, unlimited if 0",
|
||||||
|
default=10, min=0, max=2147483647)
|
||||||
|
cls.preview_pause = BoolProperty(name="Pause Preview", description="Pause all viewport preview renders",
|
||||||
|
default=False)
|
||||||
|
|
||||||
|
cls.no_caustics = BoolProperty(name="No Caustics", description="Leave out caustics, resulting in a darker image with less noise",
|
||||||
|
default=False)
|
||||||
|
cls.blur_caustics = FloatProperty(name="Blur Caustics", description="Blur caustics to reduce noise",
|
||||||
|
default=0.0, min=0.0, max=1.0)
|
||||||
|
|
||||||
|
cls.min_bounces = IntProperty(name="Min Bounces", description="Minimum number of bounces, setting this lower than the maximum enables probalistic path termination (faster but noisier)",
|
||||||
|
default=3, min=0, max=1024)
|
||||||
|
cls.max_bounces = IntProperty(name="Max Bounces", description="Total maximum number of bounces",
|
||||||
|
default=8, min=0, max=1024)
|
||||||
|
|
||||||
|
cls.diffuse_bounces = IntProperty(name="Diffuse Bounces", description="Maximum number of diffuse reflection bounces, bounded by total maximum",
|
||||||
|
default=128, min=0, max=1024)
|
||||||
|
cls.glossy_bounces = IntProperty(name="Glossy Bounces", description="Maximum number of glossy reflection bounces, bounded by total maximum",
|
||||||
|
default=128, min=0, max=1024)
|
||||||
|
cls.transmission_bounces = IntProperty(name="Transmission Bounces", description="Maximum number of transmission bounces, bounded by total maximum",
|
||||||
|
default=128, min=0, max=1024)
|
||||||
|
|
||||||
|
cls.transparent_min_bounces = IntProperty(name="Transparent Min Bounces", description="Minimum number of transparent bounces, setting this lower than the maximum enables probalistic path termination (faster but noisier)",
|
||||||
|
default=8, min=0, max=1024)
|
||||||
|
cls.transparent_max_bounces = IntProperty(name="Transparent Max Bounces", description="Maximum number of transparent bounces",
|
||||||
|
default=8, min=0, max=1024)
|
||||||
|
cls.use_transparent_shadows = BoolProperty(name="Transparent Shadows", description="Use transparency of surfaces for rendering shadows",
|
||||||
|
default=True)
|
||||||
|
|
||||||
|
cls.film_exposure = FloatProperty(name="Exposure", description="Image brightness scale",
|
||||||
|
default=1.0, min=0.0, max=10.0)
|
||||||
|
cls.film_transparent = BoolProperty(name="Transparent", description="World background is transparent",
|
||||||
|
default=False)
|
||||||
|
|
||||||
|
cls.filter_type = EnumProperty(name="Filter Type", description="Pixel filter type",
|
||||||
|
items=enums.filter_types, default="GAUSSIAN")
|
||||||
|
cls.filter_width = FloatProperty(name="Filter Width", description="Pixel filter width",
|
||||||
|
default=1.5, min=0.01, max=10.0)
|
||||||
|
|
||||||
|
cls.seed = IntProperty(name="Seed", description="Seed value for integrator to get different noise patterns",
|
||||||
|
default=0, min=0, max=2147483647)
|
||||||
|
|
||||||
|
cls.debug_tile_size = IntProperty(name="Tile Size", description="",
|
||||||
|
default=1024, min=1, max=4096)
|
||||||
|
cls.debug_min_size = IntProperty(name="Min Size", description="",
|
||||||
|
default=64, min=1, max=4096)
|
||||||
|
cls.debug_reset_timeout = FloatProperty(name="Reset timeout", description="",
|
||||||
|
default=0.1, min=0.01, max=10.0)
|
||||||
|
cls.debug_cancel_timeout = FloatProperty(name="Cancel timeout", description="",
|
||||||
|
default=0.1, min=0.01, max=10.0)
|
||||||
|
cls.debug_text_timeout = FloatProperty(name="Text timeout", description="",
|
||||||
|
default=1.0, min=0.01, max=10.0)
|
||||||
|
|
||||||
|
cls.debug_bvh_type = EnumProperty(name="Viewport BVH Type", description="Choose between faster updates, or faster render",
|
||||||
|
items=enums.bvh_types, default="DYNAMIC_BVH")
|
||||||
|
cls.debug_use_spatial_splits = BoolProperty(name="Use Spatial Splits", description="Use BVH spatial splits: longer builder time, faster render",
|
||||||
|
default=False)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def unregister(cls):
|
||||||
|
del bpy.types.Scene.cycles
|
||||||
|
|
||||||
|
class CyclesCameraSettings(bpy.types.PropertyGroup):
|
||||||
|
@classmethod
|
||||||
|
def register(cls):
|
||||||
|
bpy.types.Camera.cycles = PointerProperty(type=cls, name="Cycles Camera Settings", description="Cycles camera settings")
|
||||||
|
|
||||||
|
cls.aperture_size = FloatProperty(name="Aperture Size", description="Radius of the aperture for depth of field",
|
||||||
|
default=0.0, min=0.0, max=10.0)
|
||||||
|
cls.aperture_blades = IntProperty(name="Aperture Blades", description="Number of blades in aperture for polygonal bokeh (need 3 or more)",
|
||||||
|
default=0, min=0, max=100)
|
||||||
|
cls.aperture_rotation = FloatProperty(name="Aperture Rotation", description="Rotation of blades in aperture",
|
||||||
|
default=0, soft_min=-math.pi, soft_max=math.pi, subtype='ANGLE')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def unregister(cls):
|
||||||
|
del bpy.types.Camera.cycles
|
||||||
|
|
||||||
|
class CyclesMaterialSettings(bpy.types.PropertyGroup):
|
||||||
|
@classmethod
|
||||||
|
def register(cls):
|
||||||
|
bpy.types.Material.cycles = PointerProperty(type=cls, name="Cycles Material Settings", description="Cycles material settings")
|
||||||
|
cls.sample_as_light = BoolProperty(name="Sample as Light", description="Use direct light sampling, to reduce noise for small or strong emitting materials", default=True)
|
||||||
|
cls.homogeneous_volume = BoolProperty(name="Homogeneous Volume", description="When using volume rendering, assume volume has the same density everywhere, for faster rendering", default=False)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def unregister(cls):
|
||||||
|
del bpy.types.Material.cycles
|
||||||
|
|
||||||
|
class CyclesLampSettings(bpy.types.PropertyGroup):
|
||||||
|
@classmethod
|
||||||
|
def register(cls):
|
||||||
|
bpy.types.Lamp.cycles = PointerProperty(type=cls, name="Cycles Lamp Settings", description="Cycles lamp settings")
|
||||||
|
cls.cast_shadow = BoolProperty(name="Cast Shadow", description="Lamp casts shadows", default=True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def unregister(cls):
|
||||||
|
del bpy.types.Lamp.cycles
|
||||||
|
|
||||||
|
class CyclesWorldSettings(bpy.types.PropertyGroup):
|
||||||
|
@classmethod
|
||||||
|
def register(cls):
|
||||||
|
bpy.types.World.cycles = PointerProperty(type=cls, name="Cycles World Settings", description="Cycles world settings")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def unregister(cls):
|
||||||
|
del bpy.types.World.cycles
|
||||||
|
|
||||||
|
class CyclesVisibilitySettings(bpy.types.PropertyGroup):
|
||||||
|
@classmethod
|
||||||
|
def register(cls):
|
||||||
|
bpy.types.Object.cycles_visibility = PointerProperty(type=cls, name="Cycles Visibility Settings", description="Cycles visibility settings")
|
||||||
|
|
||||||
|
cls.camera = BoolProperty(name="Camera", description="Object visibility for camera rays", default=True)
|
||||||
|
cls.diffuse = BoolProperty(name="Diffuse", description="Object visibility for diffuse reflection rays", default=True)
|
||||||
|
cls.glossy = BoolProperty(name="Glossy", description="Object visibility for glossy reflection rays", default=True)
|
||||||
|
cls.transmission = BoolProperty(name="Transmission", description="Object visibility for transmission rays", default=True)
|
||||||
|
cls.shadow = BoolProperty(name="Shadow", description="Object visibility for shadow rays", default=True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def unregister(cls):
|
||||||
|
del bpy.types.Object.cycles_visibility
|
||||||
|
|
||||||
|
class CyclesMeshSettings(bpy.types.PropertyGroup):
|
||||||
|
@classmethod
|
||||||
|
def register(cls):
|
||||||
|
bpy.types.Mesh.cycles = PointerProperty(type=cls, name="Cycles Mesh Settings", description="Cycles mesh settings")
|
||||||
|
bpy.types.Curve.cycles = PointerProperty(type=cls, name="Cycles Mesh Settings", description="Cycles mesh settings")
|
||||||
|
bpy.types.MetaBall.cycles = PointerProperty(type=cls, name="Cycles Mesh Settings", description="Cycles mesh settings")
|
||||||
|
|
||||||
|
cls.displacement_method = EnumProperty(name="Displacement Method", description="Method to use for the displacement",
|
||||||
|
items=enums.displacement_methods, default="BUMP")
|
||||||
|
cls.use_subdivision = BoolProperty(name="Use Subdivision", description="Subdivide mesh for rendering",
|
||||||
|
default=False)
|
||||||
|
cls.dicing_rate = FloatProperty(name="Dicing Rate", description="", default=1.0, min=0.001, max=1000.0)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def unregister(cls):
|
||||||
|
del bpy.types.Mesh.cycles
|
||||||
|
del bpy.types.Curve.cycles
|
||||||
|
del bpy.types.MetaBall.cycles
|
||||||
|
|
||||||
|
def register():
|
||||||
|
bpy.utils.register_class(CyclesRenderSettings)
|
||||||
|
bpy.utils.register_class(CyclesCameraSettings)
|
||||||
|
bpy.utils.register_class(CyclesMaterialSettings)
|
||||||
|
bpy.utils.register_class(CyclesLampSettings)
|
||||||
|
bpy.utils.register_class(CyclesWorldSettings)
|
||||||
|
bpy.utils.register_class(CyclesVisibilitySettings)
|
||||||
|
bpy.utils.register_class(CyclesMeshSettings)
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
bpy.utils.unregister_class(CyclesRenderSettings)
|
||||||
|
bpy.utils.unregister_class(CyclesCameraSettings)
|
||||||
|
bpy.utils.unregister_class(CyclesMaterialSettings)
|
||||||
|
bpy.utils.unregister_class(CyclesLampSettings)
|
||||||
|
bpy.utils.unregister_class(CyclesWorldSettings)
|
||||||
|
bpy.utils.unregister_class(CyclesMeshSettings)
|
||||||
|
bpy.utils.unregister_class(CyclesVisibilitySettings)
|
||||||
|
|
748
intern/cycles/blender/addon/ui.py
Normal file
748
intern/cycles/blender/addon/ui.py
Normal file
@ -0,0 +1,748 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2011, Blender Foundation.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
|
||||||
|
from bpy.types import Panel, Menu
|
||||||
|
|
||||||
|
from cycles import enums
|
||||||
|
from cycles import engine
|
||||||
|
|
||||||
|
class CYCLES_MT_integrator_presets(Menu):
|
||||||
|
bl_label = "Integrator Presets"
|
||||||
|
preset_subdir = "cycles/integrator"
|
||||||
|
preset_operator = "script.execute_preset"
|
||||||
|
COMPAT_ENGINES = {'CYCLES'}
|
||||||
|
draw = Menu.draw_preset
|
||||||
|
|
||||||
|
class CyclesButtonsPanel():
|
||||||
|
bl_space_type = "PROPERTIES"
|
||||||
|
bl_region_type = "WINDOW"
|
||||||
|
bl_context = "render"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
rd = context.scene.render
|
||||||
|
return rd.engine == 'CYCLES'
|
||||||
|
|
||||||
|
class CyclesRender_PT_integrator(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Integrator"
|
||||||
|
bl_options = {'DEFAULT_CLOSED'}
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
scene = context.scene
|
||||||
|
cscene = scene.cycles
|
||||||
|
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.menu("CYCLES_MT_integrator_presets", text=bpy.types.CYCLES_MT_integrator_presets.bl_label)
|
||||||
|
row.operator("render.cycles_integrator_preset_add", text="", icon="ZOOMIN")
|
||||||
|
row.operator("render.cycles_integrator_preset_add", text="", icon="ZOOMOUT").remove_active = True
|
||||||
|
|
||||||
|
split = layout.split()
|
||||||
|
|
||||||
|
col = split.column()
|
||||||
|
sub = col.column(align=True)
|
||||||
|
sub.label(text="Samples:")
|
||||||
|
sub.prop(cscene, "samples", text="Render")
|
||||||
|
sub.prop(cscene, "preview_samples", text="Preview")
|
||||||
|
sub.prop(cscene, "seed")
|
||||||
|
|
||||||
|
sub = col.column(align=True)
|
||||||
|
sub.label("Transparency:")
|
||||||
|
sub.prop(cscene, "transparent_max_bounces", text="Max")
|
||||||
|
sub.prop(cscene, "transparent_min_bounces", text="Min")
|
||||||
|
sub.prop(cscene, "use_transparent_shadows", text="Shadows")
|
||||||
|
|
||||||
|
col = split.column()
|
||||||
|
|
||||||
|
sub = col.column(align=True)
|
||||||
|
sub.label(text="Bounces:")
|
||||||
|
sub.prop(cscene, "max_bounces", text="Max")
|
||||||
|
sub.prop(cscene, "min_bounces", text="Min")
|
||||||
|
|
||||||
|
sub = col.column(align=True)
|
||||||
|
sub.label(text="Light Paths:")
|
||||||
|
sub.prop(cscene, "diffuse_bounces", text="Diffuse")
|
||||||
|
sub.prop(cscene, "glossy_bounces", text="Glossy")
|
||||||
|
sub.prop(cscene, "transmission_bounces", text="Transmission")
|
||||||
|
sub.prop(cscene, "no_caustics")
|
||||||
|
|
||||||
|
#row = col.row()
|
||||||
|
#row.prop(cscene, "blur_caustics")
|
||||||
|
#row.active = not cscene.no_caustics
|
||||||
|
|
||||||
|
class CyclesRender_PT_film(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Film"
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
scene = context.scene
|
||||||
|
cscene = scene.cycles
|
||||||
|
|
||||||
|
split = layout.split()
|
||||||
|
|
||||||
|
col = split.column();
|
||||||
|
col.prop(cscene, "film_exposure")
|
||||||
|
col.prop(cscene, "film_transparent")
|
||||||
|
|
||||||
|
col = split.column()
|
||||||
|
sub = col.column(align=True)
|
||||||
|
sub.prop(cscene, "filter_type", text="")
|
||||||
|
if cscene.filter_type != 'BOX':
|
||||||
|
sub.prop(cscene, "filter_width", text="Width")
|
||||||
|
|
||||||
|
class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Performance"
|
||||||
|
bl_options = {'DEFAULT_CLOSED'}
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
scene = context.scene
|
||||||
|
rd = scene.render
|
||||||
|
cscene = scene.cycles
|
||||||
|
|
||||||
|
split = layout.split()
|
||||||
|
|
||||||
|
col = split.column(align=True)
|
||||||
|
|
||||||
|
col.label(text="Threads:")
|
||||||
|
col.row().prop(rd, "threads_mode", expand=True)
|
||||||
|
sub = col.column()
|
||||||
|
sub.enabled = rd.threads_mode == 'FIXED'
|
||||||
|
sub.prop(rd, "threads")
|
||||||
|
|
||||||
|
sub = col.column(align=True)
|
||||||
|
sub.label(text="Tiles:")
|
||||||
|
sub.prop(cscene, "debug_tile_size")
|
||||||
|
sub.prop(cscene, "debug_min_size")
|
||||||
|
|
||||||
|
col = split.column()
|
||||||
|
|
||||||
|
sub = col.column(align=True)
|
||||||
|
sub.label(text="Acceleration structure:")
|
||||||
|
sub.prop(cscene, "debug_bvh_type", text="")
|
||||||
|
sub.prop(cscene, "debug_use_spatial_splits")
|
||||||
|
|
||||||
|
class CyclesRender_PT_layers(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Layers"
|
||||||
|
bl_options = {'DEFAULT_CLOSED'}
|
||||||
|
COMPAT_ENGINES = {'BLENDER_RENDER'}
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
scene = context.scene
|
||||||
|
rd = scene.render
|
||||||
|
|
||||||
|
# row = layout.row()
|
||||||
|
# row.template_list(rd, "layers", rd.layers, "active_index", rows=2)
|
||||||
|
|
||||||
|
# col = row.column(align=True)
|
||||||
|
# col.operator("scene.render_layer_add", icon='ZOOMIN', text="")
|
||||||
|
# col.operator("scene.render_layer_remove", icon='ZOOMOUT', text="")
|
||||||
|
|
||||||
|
row = layout.row()
|
||||||
|
# rl = rd.layers.active
|
||||||
|
rl = rd.layers[0]
|
||||||
|
row.prop(rl, "name")
|
||||||
|
#row.prop(rd, "use_single_layer", text="", icon_only=True)
|
||||||
|
|
||||||
|
split = layout.split()
|
||||||
|
|
||||||
|
col = split.column()
|
||||||
|
col.prop(scene, "layers", text="Scene")
|
||||||
|
|
||||||
|
col = split.column()
|
||||||
|
col.prop(rl, "layers", text="Layer")
|
||||||
|
|
||||||
|
layout.separator()
|
||||||
|
|
||||||
|
layout.prop(rl, "material_override", text="Material")
|
||||||
|
|
||||||
|
class Cycles_PT_post_processing(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Post Processing"
|
||||||
|
bl_options = {'DEFAULT_CLOSED'}
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
rd = context.scene.render
|
||||||
|
|
||||||
|
split = layout.split()
|
||||||
|
|
||||||
|
col = split.column()
|
||||||
|
col.prop(rd, "use_compositing")
|
||||||
|
col.prop(rd, "use_sequencer")
|
||||||
|
|
||||||
|
col = split.column()
|
||||||
|
col.prop(rd, "dither_intensity", text="Dither", slider=True)
|
||||||
|
|
||||||
|
class CyclesCamera_PT_dof(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Depth of Field"
|
||||||
|
bl_context = "data"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return context.camera and CyclesButtonsPanel.poll(context)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
cam = context.camera
|
||||||
|
ccam = cam.cycles
|
||||||
|
|
||||||
|
split = layout.split()
|
||||||
|
|
||||||
|
col = split.column()
|
||||||
|
col.label("Focus:")
|
||||||
|
col.prop(cam, "dof_object", text="")
|
||||||
|
|
||||||
|
sub = col.row()
|
||||||
|
sub.active = cam.dof_object is None
|
||||||
|
sub.prop(cam, "dof_distance", text="Distance")
|
||||||
|
|
||||||
|
col = split.column()
|
||||||
|
|
||||||
|
col.label("Aperture:")
|
||||||
|
col.prop(ccam, "aperture_size", text="Size")
|
||||||
|
|
||||||
|
sub = col.column(align=True)
|
||||||
|
sub.prop(ccam, "aperture_blades", text="Blades")
|
||||||
|
sub.prop(ccam, "aperture_rotation", text="Rotation")
|
||||||
|
|
||||||
|
class Cycles_PT_context_material(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Surface"
|
||||||
|
bl_context = "material"
|
||||||
|
bl_options = {'HIDE_HEADER'}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return (context.material or context.object) and CyclesButtonsPanel.poll(context)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
mat = context.material
|
||||||
|
ob = context.object
|
||||||
|
slot = context.material_slot
|
||||||
|
space = context.space_data
|
||||||
|
|
||||||
|
if ob:
|
||||||
|
row = layout.row()
|
||||||
|
|
||||||
|
row.template_list(ob, "material_slots", ob, "active_material_index", rows=2)
|
||||||
|
|
||||||
|
col = row.column(align=True)
|
||||||
|
col.operator("object.material_slot_add", icon='ZOOMIN', text="")
|
||||||
|
col.operator("object.material_slot_remove", icon='ZOOMOUT', text="")
|
||||||
|
|
||||||
|
col.menu("MATERIAL_MT_specials", icon='DOWNARROW_HLT', text="")
|
||||||
|
|
||||||
|
if ob.mode == 'EDIT':
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.operator("object.material_slot_assign", text="Assign")
|
||||||
|
row.operator("object.material_slot_select", text="Select")
|
||||||
|
row.operator("object.material_slot_deselect", text="Deselect")
|
||||||
|
|
||||||
|
split = layout.split(percentage=0.65)
|
||||||
|
|
||||||
|
if ob:
|
||||||
|
split.template_ID(ob, "active_material", new="material.new")
|
||||||
|
row = split.row()
|
||||||
|
|
||||||
|
if slot:
|
||||||
|
row.prop(slot, "link", text="")
|
||||||
|
else:
|
||||||
|
row.label()
|
||||||
|
elif mat:
|
||||||
|
split.template_ID(space, "pin_id")
|
||||||
|
split.separator()
|
||||||
|
|
||||||
|
class Cycles_PT_mesh_displacement(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Displacement"
|
||||||
|
bl_context = "data"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return context.mesh or context.curve or context.meta_ball
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
mesh = context.mesh
|
||||||
|
curve = context.curve
|
||||||
|
mball = context.meta_ball
|
||||||
|
|
||||||
|
if mesh:
|
||||||
|
cdata = mesh.cycles
|
||||||
|
elif curve:
|
||||||
|
cdata = curve.cycles
|
||||||
|
elif mball:
|
||||||
|
cdata = mball.cycles
|
||||||
|
|
||||||
|
layout.prop(cdata, "displacement_method", text="Method")
|
||||||
|
layout.prop(cdata, "use_subdivision");
|
||||||
|
layout.prop(cdata, "dicing_rate");
|
||||||
|
|
||||||
|
class CyclesObject_PT_ray_visibility(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Ray Visibility"
|
||||||
|
bl_context = "object"
|
||||||
|
bl_options = {'DEFAULT_CLOSED'}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
ob = context.object
|
||||||
|
return CyclesButtonsPanel.poll(context) and ob and ob.type in ('MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META') # todo: 'LAMP'
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
ob = context.object
|
||||||
|
visibility = ob.cycles_visibility
|
||||||
|
|
||||||
|
split = layout.split()
|
||||||
|
|
||||||
|
col = split.column()
|
||||||
|
col.prop(visibility, "camera")
|
||||||
|
col.prop(visibility, "diffuse")
|
||||||
|
col.prop(visibility, "glossy")
|
||||||
|
|
||||||
|
col = split.column()
|
||||||
|
col.prop(visibility, "transmission")
|
||||||
|
col.prop(visibility, "shadow")
|
||||||
|
|
||||||
|
def find_node(material, nodetype):
|
||||||
|
if material and material.node_tree:
|
||||||
|
ntree = material.node_tree
|
||||||
|
|
||||||
|
for node in ntree.nodes:
|
||||||
|
if hasattr(node, 'type') and node.type == nodetype:
|
||||||
|
return node
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def find_node_input(node, name):
|
||||||
|
for input in node.inputs:
|
||||||
|
if input.name == name:
|
||||||
|
return input
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def panel_node_draw(layout, id, output_type, input_name):
|
||||||
|
if not id.node_tree:
|
||||||
|
layout.prop(id, "use_nodes", icon='NODETREE')
|
||||||
|
return
|
||||||
|
|
||||||
|
ntree = id.node_tree
|
||||||
|
|
||||||
|
node = find_node(id, output_type)
|
||||||
|
if not node:
|
||||||
|
layout.label(text="No output node.")
|
||||||
|
else:
|
||||||
|
input = find_node_input(node, input_name)
|
||||||
|
layout.template_node_view(ntree, node, input);
|
||||||
|
|
||||||
|
class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Lamp"
|
||||||
|
bl_context = "data"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return context.lamp and CyclesButtonsPanel.poll(context)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
lamp = context.lamp
|
||||||
|
clamp = lamp.cycles
|
||||||
|
|
||||||
|
layout.prop(lamp, "type", expand=True)
|
||||||
|
|
||||||
|
split = layout.split()
|
||||||
|
col = split.column(align=True)
|
||||||
|
|
||||||
|
if lamp.type in ('POINT', 'SUN', 'SPOT'):
|
||||||
|
col.prop(lamp, "shadow_soft_size", text="Size")
|
||||||
|
elif lamp.type == 'AREA':
|
||||||
|
col.prop(lamp, "shape", text="")
|
||||||
|
sub = col.column(align=True)
|
||||||
|
|
||||||
|
if lamp.shape == 'SQUARE':
|
||||||
|
sub.prop(lamp, "size")
|
||||||
|
elif lamp.shape == 'RECTANGLE':
|
||||||
|
sub.prop(lamp, "size", text="Size X")
|
||||||
|
sub.prop(lamp, "size_y", text="Size Y")
|
||||||
|
|
||||||
|
col = split.column()
|
||||||
|
col.prop(clamp, "cast_shadow")
|
||||||
|
|
||||||
|
if lamp.type == 'SPOT':
|
||||||
|
layout.label(text="Not supported, interpreted as point lamp.")
|
||||||
|
elif lamp.type == 'HEMI':
|
||||||
|
layout.label(text="Not supported, interpreted as sun lamp.")
|
||||||
|
|
||||||
|
class CyclesLamp_PT_nodes(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Nodes"
|
||||||
|
bl_context = "data"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return context.lamp and CyclesButtonsPanel.poll(context)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
mat = context.lamp
|
||||||
|
panel_node_draw(layout, mat, 'OUTPUT_LAMP', 'Surface')
|
||||||
|
|
||||||
|
class CyclesWorld_PT_surface(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Surface"
|
||||||
|
bl_context = "world"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return context.world and CyclesButtonsPanel.poll(context)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
mat = context.world
|
||||||
|
panel_node_draw(layout, mat, 'OUTPUT_WORLD', 'Surface')
|
||||||
|
|
||||||
|
class CyclesWorld_PT_volume(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Volume"
|
||||||
|
bl_context = "world"
|
||||||
|
bl_options = {'DEFAULT_CLOSED'}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
world = context.world
|
||||||
|
return False # world and world.node_tree and CyclesButtonsPanel.poll(context)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
layout.active = False
|
||||||
|
|
||||||
|
world = context.world
|
||||||
|
panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Volume')
|
||||||
|
|
||||||
|
class CyclesMaterial_PT_surface(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Surface"
|
||||||
|
bl_context = "material"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return context.material and CyclesButtonsPanel.poll(context)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
mat = context.material
|
||||||
|
panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Surface')
|
||||||
|
|
||||||
|
class CyclesMaterial_PT_volume(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Volume"
|
||||||
|
bl_context = "material"
|
||||||
|
bl_options = {'DEFAULT_CLOSED'}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
mat = context.material
|
||||||
|
return False #mat and mat.node_tree and CyclesButtonsPanel.poll(context)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
layout.active = False
|
||||||
|
|
||||||
|
mat = context.material
|
||||||
|
cmat = mat.cycles
|
||||||
|
|
||||||
|
panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Volume')
|
||||||
|
|
||||||
|
layout.prop(cmat, "homogeneous_volume")
|
||||||
|
|
||||||
|
class CyclesMaterial_PT_displacement(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Displacement"
|
||||||
|
bl_context = "material"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
mat = context.material
|
||||||
|
return mat and mat.node_tree and CyclesButtonsPanel.poll(context)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
mat = context.material
|
||||||
|
panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Displacement')
|
||||||
|
|
||||||
|
class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Settings"
|
||||||
|
bl_context = "material"
|
||||||
|
bl_options = {'DEFAULT_CLOSED'}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return context.material and CyclesButtonsPanel.poll(context)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
mat = context.material
|
||||||
|
cmat = mat.cycles
|
||||||
|
|
||||||
|
split = layout.split()
|
||||||
|
|
||||||
|
col = split.column()
|
||||||
|
col.prop(mat, "diffuse_color", text="Viewport Color")
|
||||||
|
|
||||||
|
col = split.column()
|
||||||
|
col.prop(cmat, "sample_as_light")
|
||||||
|
|
||||||
|
class CyclesTexture_PT_context(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = ""
|
||||||
|
bl_context = "texture"
|
||||||
|
bl_options = {'HIDE_HEADER'}
|
||||||
|
COMPAT_ENGINES = {'CYCLES'}
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
tex = context.texture
|
||||||
|
space = context.space_data
|
||||||
|
pin_id = space.pin_id
|
||||||
|
use_pin_id = space.use_pin_id;
|
||||||
|
user = context.texture_user
|
||||||
|
node = context.texture_node
|
||||||
|
|
||||||
|
if not use_pin_id or not isinstance(pin_id, bpy.types.Texture):
|
||||||
|
pin_id = None
|
||||||
|
|
||||||
|
if not pin_id:
|
||||||
|
layout.template_texture_user()
|
||||||
|
|
||||||
|
if user:
|
||||||
|
layout.separator()
|
||||||
|
|
||||||
|
split = layout.split(percentage=0.65)
|
||||||
|
col = split.column()
|
||||||
|
|
||||||
|
if pin_id:
|
||||||
|
col.template_ID(space, "pin_id")
|
||||||
|
elif user:
|
||||||
|
col.template_ID(user, "texture", new="texture.new")
|
||||||
|
|
||||||
|
if tex:
|
||||||
|
row = split.row()
|
||||||
|
row.prop(tex, "use_nodes", icon="NODETREE", text="")
|
||||||
|
row.label()
|
||||||
|
|
||||||
|
if not tex.use_nodes:
|
||||||
|
split = layout.split(percentage=0.2)
|
||||||
|
split.label(text="Type:")
|
||||||
|
split.prop(tex, "type", text="")
|
||||||
|
|
||||||
|
class CyclesTexture_PT_nodes(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Nodes"
|
||||||
|
bl_context = "texture"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
tex = context.texture
|
||||||
|
return (tex and tex.use_nodes) and CyclesButtonsPanel.poll(context)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
tex = context.texture
|
||||||
|
panel_node_draw(layout, tex, 'OUTPUT_TEXTURE', 'Color')
|
||||||
|
|
||||||
|
class CyclesTexture_PT_node(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Node"
|
||||||
|
bl_context = "texture"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
node = context.texture_node
|
||||||
|
return node and CyclesButtonsPanel.poll(context)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
node = context.texture_node
|
||||||
|
ntree = node.id_data
|
||||||
|
layout.template_node_view(ntree, node, None)
|
||||||
|
|
||||||
|
class CyclesTexture_PT_mapping(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Mapping"
|
||||||
|
bl_context = "texture"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
tex = context.texture
|
||||||
|
node = context.texture_node
|
||||||
|
return (node or (tex and tex.use_nodes)) and CyclesButtonsPanel.poll(context)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
tex = context.texture
|
||||||
|
node = context.texture_node
|
||||||
|
|
||||||
|
mapping = node.texture_mapping
|
||||||
|
|
||||||
|
row = layout.row()
|
||||||
|
|
||||||
|
row.column().prop(mapping, "location")
|
||||||
|
row.column().prop(mapping, "rotation")
|
||||||
|
row.column().prop(mapping, "scale")
|
||||||
|
|
||||||
|
layout.label(text="Projection:")
|
||||||
|
|
||||||
|
row = layout.row()
|
||||||
|
row.prop(mapping, "mapping_x", text="")
|
||||||
|
row.prop(mapping, "mapping_y", text="")
|
||||||
|
row.prop(mapping, "mapping_z", text="")
|
||||||
|
|
||||||
|
class CyclesTexture_PT_colors(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Color"
|
||||||
|
bl_context = "texture"
|
||||||
|
bl_options = {'DEFAULT_CLOSED'}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
tex = context.texture
|
||||||
|
node = context.texture_node
|
||||||
|
return False
|
||||||
|
#return (node or (tex and tex.use_nodes)) and CyclesButtonsPanel.poll(context)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
tex = context.texture
|
||||||
|
node = context.texture_node
|
||||||
|
|
||||||
|
mapping = node.color_mapping
|
||||||
|
|
||||||
|
split = layout.split()
|
||||||
|
|
||||||
|
col = split.column()
|
||||||
|
col.label(text="Blend:")
|
||||||
|
col.prop(mapping, "blend_type", text="")
|
||||||
|
col.prop(mapping, "blend_factor", text="Factor")
|
||||||
|
col.prop(mapping, "blend_color", text="")
|
||||||
|
|
||||||
|
col = split.column()
|
||||||
|
col.label(text="Adjust:")
|
||||||
|
col.prop(mapping, "brightness")
|
||||||
|
col.prop(mapping, "contrast")
|
||||||
|
col.prop(mapping, "saturation")
|
||||||
|
|
||||||
|
layout.separator()
|
||||||
|
|
||||||
|
layout.prop(mapping, "use_color_ramp", text="Ramp")
|
||||||
|
if mapping.use_color_ramp:
|
||||||
|
layout.template_color_ramp(mapping, "color_ramp", expand=True)
|
||||||
|
|
||||||
|
def draw_device(self, context):
|
||||||
|
scene = context.scene
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
if scene.render.engine == "CYCLES":
|
||||||
|
cscene = scene.cycles
|
||||||
|
|
||||||
|
available_devices = engine.available_devices()
|
||||||
|
available_cuda = 'cuda' in available_devices
|
||||||
|
available_opencl = 'opencl' in available_devices
|
||||||
|
|
||||||
|
if available_cuda or available_opencl:
|
||||||
|
layout.prop(cscene, "device")
|
||||||
|
if cscene.device == 'GPU' and available_cuda and available_opencl:
|
||||||
|
layout.prop(cscene, "gpu_type")
|
||||||
|
if cscene.device == 'CPU' and engine.with_osl():
|
||||||
|
layout.prop(cscene, "shading_system")
|
||||||
|
|
||||||
|
def draw_pause(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
scene = context.scene
|
||||||
|
|
||||||
|
if scene.render.engine == "CYCLES":
|
||||||
|
view = context.space_data
|
||||||
|
|
||||||
|
if view.viewport_shade == "RENDERED":
|
||||||
|
cscene = scene.cycles
|
||||||
|
layout.prop(cscene, "preview_pause", icon="PAUSE", text="")
|
||||||
|
|
||||||
|
def get_panels():
|
||||||
|
return [
|
||||||
|
bpy.types.RENDER_PT_render,
|
||||||
|
bpy.types.RENDER_PT_output,
|
||||||
|
bpy.types.RENDER_PT_encoding,
|
||||||
|
bpy.types.RENDER_PT_dimensions,
|
||||||
|
bpy.types.RENDER_PT_stamp,
|
||||||
|
bpy.types.WORLD_PT_context_world,
|
||||||
|
bpy.types.DATA_PT_context_mesh,
|
||||||
|
bpy.types.DATA_PT_context_camera,
|
||||||
|
bpy.types.DATA_PT_context_lamp,
|
||||||
|
bpy.types.DATA_PT_texture_space,
|
||||||
|
bpy.types.DATA_PT_curve_texture_space,
|
||||||
|
bpy.types.DATA_PT_mball_texture_space,
|
||||||
|
bpy.types.DATA_PT_vertex_groups,
|
||||||
|
bpy.types.DATA_PT_shape_keys,
|
||||||
|
bpy.types.DATA_PT_uv_texture,
|
||||||
|
bpy.types.DATA_PT_vertex_colors,
|
||||||
|
bpy.types.DATA_PT_camera,
|
||||||
|
bpy.types.DATA_PT_camera_display,
|
||||||
|
bpy.types.DATA_PT_lens,
|
||||||
|
bpy.types.DATA_PT_custom_props_mesh,
|
||||||
|
bpy.types.DATA_PT_custom_props_camera,
|
||||||
|
bpy.types.DATA_PT_custom_props_lamp,
|
||||||
|
bpy.types.TEXTURE_PT_clouds,
|
||||||
|
bpy.types.TEXTURE_PT_wood,
|
||||||
|
bpy.types.TEXTURE_PT_marble,
|
||||||
|
bpy.types.TEXTURE_PT_magic,
|
||||||
|
bpy.types.TEXTURE_PT_blend,
|
||||||
|
bpy.types.TEXTURE_PT_stucci,
|
||||||
|
bpy.types.TEXTURE_PT_image,
|
||||||
|
bpy.types.TEXTURE_PT_image_sampling,
|
||||||
|
bpy.types.TEXTURE_PT_image_mapping,
|
||||||
|
bpy.types.TEXTURE_PT_musgrave,
|
||||||
|
bpy.types.TEXTURE_PT_voronoi,
|
||||||
|
bpy.types.TEXTURE_PT_distortednoise,
|
||||||
|
bpy.types.TEXTURE_PT_voxeldata,
|
||||||
|
bpy.types.TEXTURE_PT_pointdensity,
|
||||||
|
bpy.types.TEXTURE_PT_pointdensity_turbulence]
|
||||||
|
|
||||||
|
def register():
|
||||||
|
bpy.types.RENDER_PT_render.append(draw_device)
|
||||||
|
bpy.types.VIEW3D_HT_header.append(draw_pause)
|
||||||
|
|
||||||
|
for panel in get_panels():
|
||||||
|
panel.COMPAT_ENGINES.add('CYCLES')
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
bpy.types.RENDER_PT_render.remove(draw_device)
|
||||||
|
bpy.types.VIEW3D_HT_header.remove(draw_pause)
|
||||||
|
|
||||||
|
for panel in get_panels():
|
||||||
|
panel.COMPAT_ENGINES.remove('CYCLES')
|
||||||
|
|
99
intern/cycles/blender/addon/xml.py
Normal file
99
intern/cycles/blender/addon/xml.py
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2011, Blender Foundation.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
# XML exporter for generating test files, not intended for end users
|
||||||
|
|
||||||
|
import os
|
||||||
|
import bpy
|
||||||
|
from bpy_extras.io_utils import ExportHelper
|
||||||
|
import xml.etree.ElementTree as etree
|
||||||
|
import xml.dom.minidom as dom
|
||||||
|
|
||||||
|
def strip(root):
|
||||||
|
root.text = None
|
||||||
|
root.tail = None
|
||||||
|
|
||||||
|
for elem in root:
|
||||||
|
strip(elem)
|
||||||
|
|
||||||
|
def write(node, fname):
|
||||||
|
strip(node)
|
||||||
|
|
||||||
|
s = etree.tostring(node)
|
||||||
|
s = dom.parseString(s).toprettyxml()
|
||||||
|
|
||||||
|
f = open(fname, "w")
|
||||||
|
f.write(s)
|
||||||
|
|
||||||
|
class ExportCyclesXML(bpy.types.Operator, ExportHelper):
|
||||||
|
''''''
|
||||||
|
bl_idname = "export_mesh.cycles_xml"
|
||||||
|
bl_label = "Export Cycles XML"
|
||||||
|
|
||||||
|
filename_ext = ".xml"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return context.active_object != None
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
filepath = bpy.path.ensure_ext(self.filepath, ".xml")
|
||||||
|
|
||||||
|
# get mesh
|
||||||
|
scene = context.scene
|
||||||
|
object = context.object
|
||||||
|
|
||||||
|
if not object:
|
||||||
|
raise Exception("No active object")
|
||||||
|
|
||||||
|
mesh = object.to_mesh(scene, True, 'PREVIEW')
|
||||||
|
|
||||||
|
if not mesh:
|
||||||
|
raise Exception("No mesh data in active object")
|
||||||
|
|
||||||
|
# generate mesh node
|
||||||
|
nverts = ""
|
||||||
|
verts = ""
|
||||||
|
P = ""
|
||||||
|
|
||||||
|
for v in mesh.vertices:
|
||||||
|
P += "%f %f %f " % (v.co[0], v.co[1], v.co[2])
|
||||||
|
|
||||||
|
for i, f in enumerate(mesh.faces):
|
||||||
|
nverts += str(len(f.vertices)) + " "
|
||||||
|
|
||||||
|
for v in f.vertices:
|
||||||
|
verts += str(v) + " "
|
||||||
|
verts += " "
|
||||||
|
|
||||||
|
node = etree.Element('mesh', attrib={'nverts': nverts, 'verts': verts, 'P': P})
|
||||||
|
|
||||||
|
# write to file
|
||||||
|
write(node, filepath)
|
||||||
|
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
def register():
|
||||||
|
pass
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
pass
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
register()
|
||||||
|
|
290
intern/cycles/blender/blender_camera.cpp
Normal file
290
intern/cycles/blender/blender_camera.cpp
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "camera.h"
|
||||||
|
#include "scene.h"
|
||||||
|
|
||||||
|
#include "blender_sync.h"
|
||||||
|
#include "blender_util.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* Blender Camera Intermediate: we first convert both the offline and 3d view
|
||||||
|
* render camera to this, and from there convert to our native camera format. */
|
||||||
|
|
||||||
|
struct BlenderCamera {
|
||||||
|
float nearclip;
|
||||||
|
float farclip;
|
||||||
|
|
||||||
|
bool ortho;
|
||||||
|
float ortho_scale;
|
||||||
|
|
||||||
|
float lens;
|
||||||
|
|
||||||
|
float aperturesize;
|
||||||
|
uint apertureblades;
|
||||||
|
float aperturerotation;
|
||||||
|
float focaldistance;
|
||||||
|
|
||||||
|
float2 shift;
|
||||||
|
float2 offset;
|
||||||
|
float zoom;
|
||||||
|
|
||||||
|
float2 pixelaspect;
|
||||||
|
|
||||||
|
enum { AUTO, HORIZONTAL, VERTICAL } sensor_fit;
|
||||||
|
float sensor_width;
|
||||||
|
float sensor_height;
|
||||||
|
|
||||||
|
Transform matrix;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void blender_camera_init(BlenderCamera *bcam)
|
||||||
|
{
|
||||||
|
memset(bcam, 0, sizeof(BlenderCamera));
|
||||||
|
|
||||||
|
bcam->zoom = 1.0f;
|
||||||
|
bcam->pixelaspect = make_float2(1.0f, 1.0f);
|
||||||
|
bcam->sensor_width = 32.0f;
|
||||||
|
bcam->sensor_height = 18.0f;
|
||||||
|
bcam->sensor_fit = BlenderCamera::AUTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float blender_camera_focal_distance(BL::Object b_ob, BL::Camera b_camera)
|
||||||
|
{
|
||||||
|
BL::Object b_dof_object = b_camera.dof_object();
|
||||||
|
|
||||||
|
if(!b_dof_object)
|
||||||
|
return b_camera.dof_distance();
|
||||||
|
|
||||||
|
/* for dof object, return distance along camera direction. this is
|
||||||
|
* compatible with blender, but does it fit our dof model? */
|
||||||
|
Transform obmat = get_transform(b_ob.matrix_world());
|
||||||
|
Transform dofmat = get_transform(b_dof_object.matrix_world());
|
||||||
|
|
||||||
|
float3 cam_p = transform_get_column(&obmat, 3);
|
||||||
|
float3 cam_dir = normalize(transform_get_column(&obmat, 2));
|
||||||
|
float3 dof_p = transform_get_column(&dofmat, 3);
|
||||||
|
float3 proj_p = dot(dof_p, cam_dir) * cam_dir;
|
||||||
|
|
||||||
|
return len(proj_p - cam_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void blender_camera_from_object(BlenderCamera *bcam, BL::Object b_ob)
|
||||||
|
{
|
||||||
|
BL::ID b_ob_data = b_ob.data();
|
||||||
|
|
||||||
|
if(b_ob_data.is_a(&RNA_Camera)) {
|
||||||
|
BL::Camera b_camera(b_ob_data);
|
||||||
|
PointerRNA ccamera = RNA_pointer_get(&b_camera.ptr, "cycles");
|
||||||
|
|
||||||
|
bcam->nearclip = b_camera.clip_start();
|
||||||
|
bcam->farclip = b_camera.clip_end();
|
||||||
|
|
||||||
|
bcam->ortho = (b_camera.type() == BL::Camera::type_ORTHO);
|
||||||
|
bcam->ortho_scale = b_camera.ortho_scale();
|
||||||
|
|
||||||
|
bcam->lens = b_camera.lens();
|
||||||
|
bcam->aperturesize = RNA_float_get(&ccamera, "aperture_size");
|
||||||
|
bcam->apertureblades = RNA_int_get(&ccamera, "aperture_blades");
|
||||||
|
bcam->aperturerotation = RNA_float_get(&ccamera, "aperture_rotation");
|
||||||
|
bcam->focaldistance = blender_camera_focal_distance(b_ob, b_camera);
|
||||||
|
|
||||||
|
bcam->shift.x = b_camera.shift_x();
|
||||||
|
bcam->shift.y = b_camera.shift_y();
|
||||||
|
|
||||||
|
bcam->sensor_width = b_camera.sensor_width();
|
||||||
|
bcam->sensor_height = b_camera.sensor_height();
|
||||||
|
|
||||||
|
if(b_camera.sensor_fit() == BL::Camera::sensor_fit_AUTO)
|
||||||
|
bcam->sensor_fit = BlenderCamera::AUTO;
|
||||||
|
else if(b_camera.sensor_fit() == BL::Camera::sensor_fit_HORIZONTAL)
|
||||||
|
bcam->sensor_fit = BlenderCamera::HORIZONTAL;
|
||||||
|
else
|
||||||
|
bcam->sensor_fit = BlenderCamera::VERTICAL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* from lamp not implemented yet */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int height)
|
||||||
|
{
|
||||||
|
/* copy camera to compare later */
|
||||||
|
Camera prevcam = *cam;
|
||||||
|
|
||||||
|
/* dimensions */
|
||||||
|
float xratio = width*bcam->pixelaspect.x;
|
||||||
|
float yratio = height*bcam->pixelaspect.y;
|
||||||
|
|
||||||
|
/* compute x/y aspect and ratio */
|
||||||
|
float aspectratio, xaspect, yaspect;
|
||||||
|
|
||||||
|
/* sensor fitting */
|
||||||
|
bool horizontal_fit;
|
||||||
|
float sensor_size;
|
||||||
|
|
||||||
|
if(bcam->sensor_fit == BlenderCamera::AUTO) {
|
||||||
|
horizontal_fit = (xratio > yratio);
|
||||||
|
sensor_size = bcam->sensor_width;
|
||||||
|
}
|
||||||
|
else if(bcam->sensor_fit == BlenderCamera::HORIZONTAL) {
|
||||||
|
horizontal_fit = true;
|
||||||
|
sensor_size = bcam->sensor_width;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
horizontal_fit = false;
|
||||||
|
sensor_size = bcam->sensor_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(horizontal_fit) {
|
||||||
|
aspectratio= xratio/yratio;
|
||||||
|
xaspect= aspectratio;
|
||||||
|
yaspect= 1.0f;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
aspectratio= yratio/xratio;
|
||||||
|
xaspect= 1.0f;
|
||||||
|
yaspect= aspectratio;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* modify aspect for orthographic scale */
|
||||||
|
if(bcam->ortho) {
|
||||||
|
xaspect = xaspect*bcam->ortho_scale/(aspectratio*2.0f);
|
||||||
|
yaspect = yaspect*bcam->ortho_scale/(aspectratio*2.0f);
|
||||||
|
aspectratio = bcam->ortho_scale/2.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set viewplane */
|
||||||
|
cam->left = -xaspect;
|
||||||
|
cam->right = xaspect;
|
||||||
|
cam->bottom = -yaspect;
|
||||||
|
cam->top = yaspect;
|
||||||
|
|
||||||
|
/* zoom for 3d camera view */
|
||||||
|
cam->left *= bcam->zoom;
|
||||||
|
cam->right *= bcam->zoom;
|
||||||
|
cam->bottom *= bcam->zoom;
|
||||||
|
cam->top *= bcam->zoom;
|
||||||
|
|
||||||
|
/* modify viewplane with camera shift and 3d camera view offset */
|
||||||
|
float dx = 2.0f*(aspectratio*bcam->shift.x + bcam->offset.x*xaspect*2.0f);
|
||||||
|
float dy = 2.0f*(aspectratio*bcam->shift.y + bcam->offset.y*yaspect*2.0f);
|
||||||
|
|
||||||
|
cam->left += dx;
|
||||||
|
cam->right += dx;
|
||||||
|
cam->bottom += dy;
|
||||||
|
cam->top += dy;
|
||||||
|
|
||||||
|
/* clipping distances */
|
||||||
|
cam->nearclip = bcam->nearclip;
|
||||||
|
cam->farclip = bcam->farclip;
|
||||||
|
|
||||||
|
/* orthographic */
|
||||||
|
cam->ortho = bcam->ortho;
|
||||||
|
|
||||||
|
/* perspective */
|
||||||
|
cam->fov = 2.0f*atan((0.5f*sensor_size)/bcam->lens/aspectratio);
|
||||||
|
cam->focaldistance = bcam->focaldistance;
|
||||||
|
cam->aperturesize = bcam->aperturesize;
|
||||||
|
cam->blades = bcam->apertureblades;
|
||||||
|
cam->bladesrotation = bcam->aperturerotation;
|
||||||
|
|
||||||
|
/* transform, note the blender camera points along the negative z-axis */
|
||||||
|
cam->matrix = bcam->matrix * transform_scale(1.0f, 1.0f, -1.0f);
|
||||||
|
|
||||||
|
/* set update flag */
|
||||||
|
if(cam->modified(prevcam))
|
||||||
|
cam->tag_update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sync Render Camera */
|
||||||
|
|
||||||
|
void BlenderSync::sync_camera(int width, int height)
|
||||||
|
{
|
||||||
|
BlenderCamera bcam;
|
||||||
|
blender_camera_init(&bcam);
|
||||||
|
|
||||||
|
/* pixel aspect */
|
||||||
|
BL::RenderSettings r = b_scene.render();
|
||||||
|
|
||||||
|
bcam.pixelaspect.x = r.pixel_aspect_x();
|
||||||
|
bcam.pixelaspect.y = r.pixel_aspect_y();
|
||||||
|
|
||||||
|
/* camera object */
|
||||||
|
BL::Object b_ob = b_scene.camera();
|
||||||
|
|
||||||
|
if(b_ob) {
|
||||||
|
blender_camera_from_object(&bcam, b_ob);
|
||||||
|
bcam.matrix = get_transform(b_ob.matrix_world());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sync */
|
||||||
|
Camera *cam = scene->camera;
|
||||||
|
blender_camera_sync(cam, &bcam, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sync 3D View Camera */
|
||||||
|
|
||||||
|
void BlenderSync::sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height)
|
||||||
|
{
|
||||||
|
BlenderCamera bcam;
|
||||||
|
blender_camera_init(&bcam);
|
||||||
|
|
||||||
|
/* 3d view parameters */
|
||||||
|
bcam.nearclip = b_v3d.clip_start();
|
||||||
|
bcam.farclip = b_v3d.clip_end();
|
||||||
|
bcam.lens = b_v3d.lens();
|
||||||
|
|
||||||
|
if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) {
|
||||||
|
/* camera view */
|
||||||
|
BL::Object b_ob = b_scene.camera();
|
||||||
|
|
||||||
|
if(b_ob) {
|
||||||
|
blender_camera_from_object(&bcam, b_ob);
|
||||||
|
|
||||||
|
/* magic zoom formula */
|
||||||
|
bcam.zoom = (float)b_rv3d.view_camera_zoom();
|
||||||
|
bcam.zoom = (1.41421f + bcam.zoom/50.0f);
|
||||||
|
bcam.zoom *= bcam.zoom;
|
||||||
|
bcam.zoom = 2.0f/bcam.zoom;
|
||||||
|
|
||||||
|
/* offset */
|
||||||
|
bcam.offset = get_float2(b_rv3d.view_camera_offset());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_ORTHO) {
|
||||||
|
/* orthographic view */
|
||||||
|
bcam.farclip *= 0.5;
|
||||||
|
bcam.nearclip = -bcam.farclip;
|
||||||
|
|
||||||
|
bcam.ortho = true;
|
||||||
|
bcam.ortho_scale = b_rv3d.view_distance();
|
||||||
|
}
|
||||||
|
|
||||||
|
bcam.zoom *= 2.0f;
|
||||||
|
|
||||||
|
/* 3d view transform */
|
||||||
|
bcam.matrix = transform_inverse(get_transform(b_rv3d.view_matrix()));
|
||||||
|
|
||||||
|
/* sync */
|
||||||
|
blender_camera_sync(scene->camera, &bcam, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
321
intern/cycles/blender/blender_mesh.cpp
Normal file
321
intern/cycles/blender/blender_mesh.cpp
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mesh.h"
|
||||||
|
#include "object.h"
|
||||||
|
#include "scene.h"
|
||||||
|
|
||||||
|
#include "blender_sync.h"
|
||||||
|
#include "blender_util.h"
|
||||||
|
|
||||||
|
#include "subd_mesh.h"
|
||||||
|
#include "subd_patch.h"
|
||||||
|
#include "subd_split.h"
|
||||||
|
|
||||||
|
#include "util_foreach.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* Find/Add */
|
||||||
|
|
||||||
|
static bool mesh_need_attribute(Scene *scene, Mesh *mesh, Attribute::Standard std)
|
||||||
|
{
|
||||||
|
if(std == Attribute::STD_NONE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
foreach(uint shader, mesh->used_shaders)
|
||||||
|
if(scene->shaders[shader]->attributes.find(std))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mesh_need_attribute(Scene *scene, Mesh *mesh, ustring name)
|
||||||
|
{
|
||||||
|
if(name == ustring())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
foreach(uint shader, mesh->used_shaders)
|
||||||
|
if(scene->shaders[shader]->attributes.find(name))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<uint>& used_shaders)
|
||||||
|
{
|
||||||
|
/* create vertices */
|
||||||
|
BL::Mesh::vertices_iterator v;
|
||||||
|
|
||||||
|
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
|
||||||
|
mesh->verts.push_back(get_float3(v->co()));
|
||||||
|
|
||||||
|
/* create vertex normals */
|
||||||
|
Attribute *attr_N = mesh->attributes.add(Attribute::STD_VERTEX_NORMAL);
|
||||||
|
float3 *N = attr_N->data_float3();
|
||||||
|
|
||||||
|
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N)
|
||||||
|
*N= get_float3(v->normal());
|
||||||
|
|
||||||
|
/* create faces */
|
||||||
|
BL::Mesh::faces_iterator f;
|
||||||
|
vector<int> nverts;
|
||||||
|
|
||||||
|
for(b_mesh.faces.begin(f); f != b_mesh.faces.end(); ++f) {
|
||||||
|
int4 vi = get_int4(f->vertices_raw());
|
||||||
|
int n= (vi[3] == 0)? 3: 4;
|
||||||
|
int shader = used_shaders[f->material_index()];
|
||||||
|
bool smooth = f->use_smooth();
|
||||||
|
|
||||||
|
mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
|
||||||
|
|
||||||
|
if(n == 4)
|
||||||
|
mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth);
|
||||||
|
|
||||||
|
nverts.push_back(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create generated coordinates. todo: we should actually get the orco
|
||||||
|
coordinates from modifiers, for now we use texspace loc/size which
|
||||||
|
is available in the api. */
|
||||||
|
if(mesh_need_attribute(scene, mesh, Attribute::STD_GENERATED)) {
|
||||||
|
Attribute *attr = mesh->attributes.add(Attribute::STD_GENERATED);
|
||||||
|
float3 loc = get_float3(b_mesh.texspace_location());
|
||||||
|
float3 size = get_float3(b_mesh.texspace_size());
|
||||||
|
|
||||||
|
if(size.x != 0.0f) size.x = 0.5f/size.x;
|
||||||
|
if(size.y != 0.0f) size.y = 0.5f/size.y;
|
||||||
|
if(size.z != 0.0f) size.z = 0.5f/size.z;
|
||||||
|
|
||||||
|
loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);
|
||||||
|
|
||||||
|
float3 *fdata = attr->data_float3();
|
||||||
|
BL::Mesh::vertices_iterator v;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
|
||||||
|
fdata[i++] = get_float3(v->co())*size - loc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create vertex color attributes */
|
||||||
|
{
|
||||||
|
BL::Mesh::vertex_colors_iterator l;
|
||||||
|
|
||||||
|
for(b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) {
|
||||||
|
if(!mesh_need_attribute(scene, mesh, ustring(l->name().c_str())))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Attribute *attr = mesh->attributes.add(
|
||||||
|
ustring(l->name().c_str()), TypeDesc::TypeColor, Attribute::CORNER);
|
||||||
|
|
||||||
|
BL::MeshColorLayer::data_iterator c;
|
||||||
|
float3 *fdata = attr->data_float3();
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
for(l->data.begin(c); c != l->data.end(); ++c, ++i) {
|
||||||
|
fdata[0] = color_srgb_to_scene_linear(get_float3(c->color1()));
|
||||||
|
fdata[1] = color_srgb_to_scene_linear(get_float3(c->color2()));
|
||||||
|
fdata[2] = color_srgb_to_scene_linear(get_float3(c->color3()));
|
||||||
|
|
||||||
|
if(nverts[i] == 4) {
|
||||||
|
fdata[3] = fdata[0];
|
||||||
|
fdata[4] = fdata[2];
|
||||||
|
fdata[5] = color_srgb_to_scene_linear(get_float3(c->color4()));
|
||||||
|
fdata += 6;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fdata += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create uv layer attributes */
|
||||||
|
{
|
||||||
|
BL::Mesh::uv_textures_iterator l;
|
||||||
|
|
||||||
|
for(b_mesh.uv_textures.begin(l); l != b_mesh.uv_textures.end(); ++l) {
|
||||||
|
Attribute::Standard std = (l->active_render())? Attribute::STD_UV: Attribute::STD_NONE;
|
||||||
|
ustring name = ustring(l->name().c_str());
|
||||||
|
|
||||||
|
if(!(mesh_need_attribute(scene, mesh, name) || mesh_need_attribute(scene, mesh, std)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Attribute *attr;
|
||||||
|
|
||||||
|
if(l->active_render())
|
||||||
|
attr = mesh->attributes.add(std, name);
|
||||||
|
else
|
||||||
|
attr = mesh->attributes.add(name, TypeDesc::TypePoint, Attribute::CORNER);
|
||||||
|
|
||||||
|
BL::MeshTextureFaceLayer::data_iterator t;
|
||||||
|
float3 *fdata = attr->data_float3();
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
for(l->data.begin(t); t != l->data.end(); ++t, ++i) {
|
||||||
|
fdata[0] = get_float3(t->uv1());
|
||||||
|
fdata[1] = get_float3(t->uv2());
|
||||||
|
fdata[2] = get_float3(t->uv3());
|
||||||
|
fdata += 3;
|
||||||
|
|
||||||
|
if(nverts[i] == 4) {
|
||||||
|
fdata[0] = get_float3(t->uv1());
|
||||||
|
fdata[1] = get_float3(t->uv3());
|
||||||
|
fdata[2] = get_float3(t->uv4());
|
||||||
|
fdata += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create_subd_mesh(Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, const vector<uint>& used_shaders)
|
||||||
|
{
|
||||||
|
/* create subd mesh */
|
||||||
|
SubdMesh sdmesh;
|
||||||
|
|
||||||
|
/* create vertices */
|
||||||
|
BL::Mesh::vertices_iterator v;
|
||||||
|
|
||||||
|
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
|
||||||
|
sdmesh.add_vert(get_float3(v->co()));
|
||||||
|
|
||||||
|
/* create faces */
|
||||||
|
BL::Mesh::faces_iterator f;
|
||||||
|
|
||||||
|
for(b_mesh.faces.begin(f); f != b_mesh.faces.end(); ++f) {
|
||||||
|
int4 vi = get_int4(f->vertices_raw());
|
||||||
|
int n= (vi[3] == 0)? 3: 4;
|
||||||
|
//int shader = used_shaders[f->material_index()];
|
||||||
|
|
||||||
|
if(n == 4)
|
||||||
|
sdmesh.add_face(vi[0], vi[1], vi[2], vi[3]);
|
||||||
|
/*else
|
||||||
|
sdmesh.add_face(vi[0], vi[1], vi[2]);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finalize subd mesh */
|
||||||
|
sdmesh.link_boundary();
|
||||||
|
|
||||||
|
/* subdivide */
|
||||||
|
DiagSplit dsplit;
|
||||||
|
dsplit.camera = NULL;
|
||||||
|
dsplit.dicing_rate = RNA_float_get(cmesh, "dicing_rate");
|
||||||
|
|
||||||
|
sdmesh.tesselate(&dsplit, false, mesh, used_shaders[0], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sync */
|
||||||
|
|
||||||
|
Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated)
|
||||||
|
{
|
||||||
|
/* test if we can instance or if the object is modified */
|
||||||
|
BL::ID b_ob_data = b_ob.data();
|
||||||
|
BL::ID key = (object_is_modified(b_ob))? b_ob: b_ob_data;
|
||||||
|
|
||||||
|
/* find shader indices */
|
||||||
|
vector<uint> used_shaders;
|
||||||
|
|
||||||
|
BL::Object::material_slots_iterator slot;
|
||||||
|
for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
|
||||||
|
if(render_layer.material_override)
|
||||||
|
find_shader(render_layer.material_override, used_shaders);
|
||||||
|
else
|
||||||
|
find_shader(slot->material(), used_shaders);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(used_shaders.size() == 0)
|
||||||
|
used_shaders.push_back(scene->default_surface);
|
||||||
|
|
||||||
|
/* test if we need to sync */
|
||||||
|
Mesh *mesh;
|
||||||
|
|
||||||
|
if(!mesh_map.sync(&mesh, key)) {
|
||||||
|
/* if transform was applied to mesh, need full update */
|
||||||
|
if(object_updated && mesh->transform_applied);
|
||||||
|
/* test if shaders changed, these can be object level so mesh
|
||||||
|
does not get tagged for recalc */
|
||||||
|
else if(mesh->used_shaders != used_shaders);
|
||||||
|
else {
|
||||||
|
/* even if not tagged for recalc, we may need to sync anyway
|
||||||
|
* because the shader needs different mesh attributes */
|
||||||
|
bool attribute_recalc = false;
|
||||||
|
|
||||||
|
foreach(uint shader, mesh->used_shaders)
|
||||||
|
if(scene->shaders[shader]->need_update_attributes)
|
||||||
|
attribute_recalc = true;
|
||||||
|
|
||||||
|
if(!attribute_recalc)
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ensure we only sync instanced meshes once */
|
||||||
|
if(mesh_synced.find(mesh) != mesh_synced.end())
|
||||||
|
return mesh;
|
||||||
|
|
||||||
|
mesh_synced.insert(mesh);
|
||||||
|
|
||||||
|
/* create derived mesh */
|
||||||
|
BL::Mesh b_mesh = object_to_mesh(b_ob, b_scene, true, !preview);
|
||||||
|
PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");
|
||||||
|
|
||||||
|
vector<Mesh::Triangle> oldtriangle = mesh->triangles;
|
||||||
|
|
||||||
|
mesh->clear();
|
||||||
|
mesh->used_shaders = used_shaders;
|
||||||
|
mesh->name = ustring(b_ob_data.name().c_str());
|
||||||
|
|
||||||
|
if(b_mesh) {
|
||||||
|
if(cmesh.data && RNA_boolean_get(&cmesh, "use_subdivision"))
|
||||||
|
create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders);
|
||||||
|
else
|
||||||
|
create_mesh(scene, mesh, b_mesh, used_shaders);
|
||||||
|
|
||||||
|
/* free derived mesh */
|
||||||
|
object_remove_mesh(b_data, b_mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* displacement method */
|
||||||
|
if(cmesh.data) {
|
||||||
|
int method = RNA_enum_get(&cmesh, "displacement_method");
|
||||||
|
|
||||||
|
if(method == 0)
|
||||||
|
mesh->displacement_method = Mesh::DISPLACE_BUMP;
|
||||||
|
else if(method == 1)
|
||||||
|
mesh->displacement_method = Mesh::DISPLACE_TRUE;
|
||||||
|
else
|
||||||
|
mesh->displacement_method = Mesh::DISPLACE_BOTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag update */
|
||||||
|
bool rebuild = false;
|
||||||
|
|
||||||
|
if(oldtriangle.size() != mesh->triangles.size())
|
||||||
|
rebuild = true;
|
||||||
|
else if(oldtriangle.size()) {
|
||||||
|
if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0)
|
||||||
|
rebuild = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh->tag_update(scene, rebuild);
|
||||||
|
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
252
intern/cycles/blender/blender_object.cpp
Normal file
252
intern/cycles/blender/blender_object.cpp
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "light.h"
|
||||||
|
#include "mesh.h"
|
||||||
|
#include "object.h"
|
||||||
|
#include "scene.h"
|
||||||
|
|
||||||
|
#include "blender_sync.h"
|
||||||
|
#include "blender_util.h"
|
||||||
|
|
||||||
|
#include "util_foreach.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* Utilities */
|
||||||
|
|
||||||
|
bool BlenderSync::object_is_modified(BL::Object b_ob)
|
||||||
|
{
|
||||||
|
/* test if we can instance or if the object is modified */
|
||||||
|
if(ccl::object_is_modified(b_ob, b_scene, preview)) {
|
||||||
|
/* modifiers */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* object level material links */
|
||||||
|
BL::Object::material_slots_iterator slot;
|
||||||
|
for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot)
|
||||||
|
if(slot->link() == BL::MaterialSlot::link_OBJECT)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BlenderSync::object_is_mesh(BL::Object b_ob)
|
||||||
|
{
|
||||||
|
BL::ID b_ob_data = b_ob.data();
|
||||||
|
|
||||||
|
return (b_ob_data && (b_ob_data.is_a(&RNA_Mesh) ||
|
||||||
|
b_ob_data.is_a(&RNA_Curve) || b_ob_data.is_a(&RNA_MetaBall)));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BlenderSync::object_is_light(BL::Object b_ob)
|
||||||
|
{
|
||||||
|
BL::ID b_ob_data = b_ob.data();
|
||||||
|
|
||||||
|
return (b_ob_data && b_ob_data.is_a(&RNA_Lamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint object_ray_visibility(BL::Object b_ob)
|
||||||
|
{
|
||||||
|
PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility");
|
||||||
|
uint flag = 0;
|
||||||
|
|
||||||
|
flag |= get_boolean(cvisibility, "camera")? PATH_RAY_CAMERA: 0;
|
||||||
|
flag |= get_boolean(cvisibility, "diffuse")? PATH_RAY_DIFFUSE: 0;
|
||||||
|
flag |= get_boolean(cvisibility, "glossy")? PATH_RAY_GLOSSY: 0;
|
||||||
|
flag |= get_boolean(cvisibility, "transmission")? PATH_RAY_TRANSMIT: 0;
|
||||||
|
flag |= get_boolean(cvisibility, "shadow")? PATH_RAY_SHADOW: 0;
|
||||||
|
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Light */
|
||||||
|
|
||||||
|
void BlenderSync::sync_light(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm)
|
||||||
|
{
|
||||||
|
/* test if we need to sync */
|
||||||
|
Light *light;
|
||||||
|
ObjectKey key(b_parent, b_index, b_ob);
|
||||||
|
|
||||||
|
if(!light_map.sync(&light, b_ob, b_parent, key))
|
||||||
|
return;
|
||||||
|
|
||||||
|
BL::Lamp b_lamp(b_ob.data());
|
||||||
|
|
||||||
|
/* type */
|
||||||
|
switch(b_lamp.type()) {
|
||||||
|
case BL::Lamp::type_POINT: {
|
||||||
|
BL::PointLamp b_point_lamp(b_lamp);
|
||||||
|
light->size = b_point_lamp.shadow_soft_size();
|
||||||
|
light->type = LIGHT_POINT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::Lamp::type_SPOT: {
|
||||||
|
BL::SpotLamp b_spot_lamp(b_lamp);
|
||||||
|
light->size = b_spot_lamp.shadow_soft_size();
|
||||||
|
light->type = LIGHT_POINT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::Lamp::type_HEMI: {
|
||||||
|
light->type = LIGHT_DISTANT;
|
||||||
|
light->size = 0.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::Lamp::type_SUN: {
|
||||||
|
BL::SunLamp b_sun_lamp(b_lamp);
|
||||||
|
light->size = b_sun_lamp.shadow_soft_size();
|
||||||
|
light->type = LIGHT_DISTANT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::Lamp::type_AREA: {
|
||||||
|
BL::AreaLamp b_area_lamp(b_lamp);
|
||||||
|
light->size = 1.0f;
|
||||||
|
light->axisu = make_float3(tfm.x.x, tfm.y.x, tfm.z.x);
|
||||||
|
light->axisv = make_float3(tfm.x.y, tfm.y.y, tfm.z.y);
|
||||||
|
light->sizeu = b_area_lamp.size();
|
||||||
|
if(b_area_lamp.shape() == BL::AreaLamp::shape_RECTANGLE)
|
||||||
|
light->sizev = b_area_lamp.size_y();
|
||||||
|
else
|
||||||
|
light->sizev = light->sizeu;
|
||||||
|
light->type = LIGHT_AREA;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* location and (inverted!) direction */
|
||||||
|
light->co = make_float3(tfm.x.w, tfm.y.w, tfm.z.w);
|
||||||
|
light->dir = -make_float3(tfm.x.z, tfm.y.z, tfm.z.z);
|
||||||
|
|
||||||
|
/* shader */
|
||||||
|
vector<uint> used_shaders;
|
||||||
|
|
||||||
|
find_shader(b_lamp, used_shaders);
|
||||||
|
|
||||||
|
if(used_shaders.size() == 0)
|
||||||
|
used_shaders.push_back(scene->default_light);
|
||||||
|
|
||||||
|
light->shader = used_shaders[0];
|
||||||
|
|
||||||
|
/* shadow */
|
||||||
|
PointerRNA clamp = RNA_pointer_get(&b_lamp.ptr, "cycles");
|
||||||
|
light->cast_shadow = get_boolean(clamp, "cast_shadow");
|
||||||
|
|
||||||
|
/* tag */
|
||||||
|
light->tag_update(scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Object */
|
||||||
|
|
||||||
|
void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm, uint visibility)
|
||||||
|
{
|
||||||
|
/* light is handled separately */
|
||||||
|
if(object_is_light(b_ob)) {
|
||||||
|
sync_light(b_parent, b_index, b_ob, tfm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* only interested in object that we can create meshes from */
|
||||||
|
if(!object_is_mesh(b_ob))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* test if we need to sync */
|
||||||
|
ObjectKey key(b_parent, b_index, b_ob);
|
||||||
|
Object *object;
|
||||||
|
bool object_updated = false;
|
||||||
|
|
||||||
|
/* object sync */
|
||||||
|
if(object_map.sync(&object, b_ob, b_parent, key)) {
|
||||||
|
object->name = b_ob.name().c_str();
|
||||||
|
object->tfm = tfm;
|
||||||
|
|
||||||
|
object->visibility = object_ray_visibility(b_ob) & visibility;
|
||||||
|
if(b_parent.ptr.data != b_ob.ptr.data)
|
||||||
|
object->visibility &= object_ray_visibility(b_parent);
|
||||||
|
|
||||||
|
object->tag_update(scene);
|
||||||
|
object_updated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mesh sync */
|
||||||
|
object->mesh = sync_mesh(b_ob, object_updated);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Object Loop */
|
||||||
|
|
||||||
|
void BlenderSync::sync_objects(BL::SpaceView3D b_v3d)
|
||||||
|
{
|
||||||
|
/* layer data */
|
||||||
|
uint scene_layer = render_layer.scene_layer;
|
||||||
|
uint layer = render_layer.layer;
|
||||||
|
|
||||||
|
/* prepare for sync */
|
||||||
|
light_map.pre_sync();
|
||||||
|
mesh_map.pre_sync();
|
||||||
|
object_map.pre_sync();
|
||||||
|
mesh_synced.clear();
|
||||||
|
|
||||||
|
/* object loop */
|
||||||
|
BL::Scene::objects_iterator b_ob;
|
||||||
|
|
||||||
|
for(b_scene.objects.begin(b_ob); b_ob != b_scene.objects.end(); ++b_ob) {
|
||||||
|
bool hide = (b_v3d)? b_ob->hide(): b_ob->hide_render();
|
||||||
|
uint ob_layer = get_layer(b_ob->layers());
|
||||||
|
|
||||||
|
if(!hide && (ob_layer & scene_layer)) {
|
||||||
|
uint visibility = PATH_RAY_ALL;
|
||||||
|
|
||||||
|
if(!(ob_layer & layer))
|
||||||
|
visibility &= ~PATH_RAY_CAMERA;
|
||||||
|
|
||||||
|
if(b_ob->is_duplicator()) {
|
||||||
|
/* dupli objects */
|
||||||
|
object_create_duplilist(*b_ob, b_scene);
|
||||||
|
|
||||||
|
BL::Object::dupli_list_iterator b_dup;
|
||||||
|
int b_index = 0;
|
||||||
|
|
||||||
|
for(b_ob->dupli_list.begin(b_dup); b_dup != b_ob->dupli_list.end(); ++b_dup) {
|
||||||
|
Transform tfm = get_transform(b_dup->matrix());
|
||||||
|
sync_object(*b_ob, b_index, b_dup->object(), tfm, visibility);
|
||||||
|
b_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_free_duplilist(*b_ob);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* object itself */
|
||||||
|
Transform tfm = get_transform(b_ob->matrix_world());
|
||||||
|
sync_object(*b_ob, 0, *b_ob, tfm, visibility);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* handle removed data and modified pointers */
|
||||||
|
if(light_map.post_sync())
|
||||||
|
scene->light_manager->tag_update(scene);
|
||||||
|
if(mesh_map.post_sync())
|
||||||
|
scene->mesh_manager->tag_update(scene);
|
||||||
|
if(object_map.post_sync())
|
||||||
|
scene->object_manager->tag_update(scene);
|
||||||
|
mesh_synced.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
212
intern/cycles/blender/blender_python.cpp
Normal file
212
intern/cycles/blender/blender_python.cpp
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
|
||||||
|
#include "blender_sync.h"
|
||||||
|
#include "blender_session.h"
|
||||||
|
|
||||||
|
#include "util_opengl.h"
|
||||||
|
#include "util_path.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
static PyObject *init_func(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
const char *path, *user_path;
|
||||||
|
|
||||||
|
if(!PyArg_ParseTuple(args, "ss", &path, &user_path))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
path_init(path, user_path);
|
||||||
|
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *create_func(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *pyengine, *pydata, *pyscene, *pyregion, *pyv3d, *pyrv3d;
|
||||||
|
|
||||||
|
if(!PyArg_ParseTuple(args, "OOOOOO", &pyengine, &pydata, &pyscene, &pyregion, &pyv3d, &pyrv3d))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* RNA */
|
||||||
|
PointerRNA engineptr;
|
||||||
|
RNA_pointer_create(NULL, &RNA_RenderEngine, (void*)PyLong_AsVoidPtr(pyengine), &engineptr);
|
||||||
|
BL::RenderEngine engine(engineptr);
|
||||||
|
|
||||||
|
PointerRNA dataptr;
|
||||||
|
RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pydata), &dataptr);
|
||||||
|
BL::BlendData data(dataptr);
|
||||||
|
|
||||||
|
PointerRNA sceneptr;
|
||||||
|
RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr);
|
||||||
|
BL::Scene scene(sceneptr);
|
||||||
|
|
||||||
|
PointerRNA regionptr;
|
||||||
|
RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyregion), ®ionptr);
|
||||||
|
BL::Region region(regionptr);
|
||||||
|
|
||||||
|
PointerRNA v3dptr;
|
||||||
|
RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyv3d), &v3dptr);
|
||||||
|
BL::SpaceView3D v3d(v3dptr);
|
||||||
|
|
||||||
|
PointerRNA rv3dptr;
|
||||||
|
RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyrv3d), &rv3dptr);
|
||||||
|
BL::RegionView3D rv3d(rv3dptr);
|
||||||
|
|
||||||
|
/* create session */
|
||||||
|
BlenderSession *session;
|
||||||
|
|
||||||
|
if(rv3d) {
|
||||||
|
/* interactive session */
|
||||||
|
int width = region.width();
|
||||||
|
int height = region.height();
|
||||||
|
|
||||||
|
session = new BlenderSession(engine, data, scene, v3d, rv3d, width, height);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* offline session */
|
||||||
|
session = new BlenderSession(engine, data, scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PyLong_FromVoidPtr(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *free_func(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *pysession;
|
||||||
|
|
||||||
|
if(!PyArg_ParseTuple(args, "O", &pysession))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
delete (BlenderSession*)PyLong_AsVoidPtr(pysession);
|
||||||
|
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *render_func(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *pysession;
|
||||||
|
|
||||||
|
if(!PyArg_ParseTuple(args, "O", &pysession))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
|
||||||
|
BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
|
||||||
|
session->render();
|
||||||
|
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *draw_func(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *pysession, *pyv3d, *pyrv3d;
|
||||||
|
|
||||||
|
if(!PyArg_ParseTuple(args, "OOO", &pysession, &pyv3d, &pyrv3d))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
|
||||||
|
|
||||||
|
if(PyLong_AsVoidPtr(pyrv3d)) {
|
||||||
|
/* 3d view drawing */
|
||||||
|
int viewport[4];
|
||||||
|
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||||
|
|
||||||
|
session->draw(viewport[2], viewport[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *sync_func(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *pysession;
|
||||||
|
|
||||||
|
if(!PyArg_ParseTuple(args, "O", &pysession))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
|
||||||
|
session->synchronize();
|
||||||
|
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *available_devices_func(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
vector<DeviceType> types = Device::available_types();
|
||||||
|
|
||||||
|
PyObject *ret = PyTuple_New(types.size());
|
||||||
|
|
||||||
|
for(size_t i = 0; i < types.size(); i++) {
|
||||||
|
string name = Device::string_from_type(types[i]);
|
||||||
|
PyTuple_SetItem(ret, i, PyUnicode_FromString(name.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *with_osl_func(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
#ifdef WITH_OSL
|
||||||
|
PyObject *ret = Py_True;
|
||||||
|
#else
|
||||||
|
PyObject *ret = Py_False;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return Py_INCREF(ret), ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef methods[] = {
|
||||||
|
{"init", init_func, METH_VARARGS, ""},
|
||||||
|
{"create", create_func, METH_VARARGS, ""},
|
||||||
|
{"free", free_func, METH_VARARGS, ""},
|
||||||
|
{"render", render_func, METH_VARARGS, ""},
|
||||||
|
{"draw", draw_func, METH_VARARGS, ""},
|
||||||
|
{"sync", sync_func, METH_VARARGS, ""},
|
||||||
|
{"available_devices", available_devices_func, METH_NOARGS, ""},
|
||||||
|
{"with_osl", with_osl_func, METH_NOARGS, ""},
|
||||||
|
{NULL, NULL, 0, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct PyModuleDef module = {
|
||||||
|
PyModuleDef_HEAD_INIT,
|
||||||
|
"bcycles",
|
||||||
|
"Blender cycles render integration",
|
||||||
|
-1,
|
||||||
|
methods,
|
||||||
|
NULL, NULL, NULL, NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
extern "C" PyObject *CYCLES_initPython();
|
||||||
|
|
||||||
|
PyObject *CYCLES_initPython()
|
||||||
|
{
|
||||||
|
return PyModule_Create(&ccl::module);
|
||||||
|
}
|
||||||
|
|
316
intern/cycles/blender/blender_session.cpp
Normal file
316
intern/cycles/blender/blender_session.cpp
Normal file
@ -0,0 +1,316 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "background.h"
|
||||||
|
#include "buffers.h"
|
||||||
|
#include "camera.h"
|
||||||
|
#include "device.h"
|
||||||
|
#include "integrator.h"
|
||||||
|
#include "film.h"
|
||||||
|
#include "light.h"
|
||||||
|
#include "scene.h"
|
||||||
|
#include "session.h"
|
||||||
|
#include "shader.h"
|
||||||
|
|
||||||
|
#include "util_color.h"
|
||||||
|
#include "util_foreach.h"
|
||||||
|
#include "util_function.h"
|
||||||
|
#include "util_progress.h"
|
||||||
|
#include "util_time.h"
|
||||||
|
|
||||||
|
#include "blender_sync.h"
|
||||||
|
#include "blender_session.h"
|
||||||
|
#include "blender_util.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_)
|
||||||
|
: b_engine(b_engine_), b_data(b_data_), b_scene(b_scene_), b_v3d(PointerRNA_NULL), b_rv3d(PointerRNA_NULL)
|
||||||
|
{
|
||||||
|
/* offline render */
|
||||||
|
BL::RenderSettings r = b_scene.render();
|
||||||
|
|
||||||
|
width = (int)(r.resolution_x()*r.resolution_percentage()*0.01f);
|
||||||
|
height = (int)(r.resolution_y()*r.resolution_percentage()*0.01f);
|
||||||
|
background = true;
|
||||||
|
last_redraw_time = 0.0f;
|
||||||
|
|
||||||
|
create_session();
|
||||||
|
}
|
||||||
|
|
||||||
|
BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_,
|
||||||
|
BL::SpaceView3D b_v3d_, BL::RegionView3D b_rv3d_, int width_, int height_)
|
||||||
|
: b_engine(b_engine_), b_data(b_data_), b_scene(b_scene_), b_v3d(b_v3d_), b_rv3d(b_rv3d_)
|
||||||
|
{
|
||||||
|
/* 3d view render */
|
||||||
|
width = width_;
|
||||||
|
height = height_;
|
||||||
|
background = false;
|
||||||
|
last_redraw_time = 0.0f;
|
||||||
|
|
||||||
|
create_session();
|
||||||
|
}
|
||||||
|
|
||||||
|
BlenderSession::~BlenderSession()
|
||||||
|
{
|
||||||
|
free_session();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlenderSession::create_session()
|
||||||
|
{
|
||||||
|
SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
|
||||||
|
SessionParams session_params = BlenderSync::get_session_params(b_scene, background);
|
||||||
|
|
||||||
|
/* reset status/progress */
|
||||||
|
last_status= "";
|
||||||
|
last_progress= -1.0f;
|
||||||
|
|
||||||
|
/* create scene */
|
||||||
|
scene = new Scene(scene_params);
|
||||||
|
|
||||||
|
/* create sync */
|
||||||
|
sync = new BlenderSync(b_data, b_scene, scene, !background);
|
||||||
|
sync->sync_data(b_v3d);
|
||||||
|
|
||||||
|
if(b_rv3d)
|
||||||
|
sync->sync_view(b_v3d, b_rv3d, width, height);
|
||||||
|
else
|
||||||
|
sync->sync_camera(width, height);
|
||||||
|
|
||||||
|
/* create session */
|
||||||
|
session = new Session(session_params);
|
||||||
|
session->scene = scene;
|
||||||
|
session->progress.set_update_callback(function_bind(&BlenderSession::tag_redraw, this));
|
||||||
|
session->progress.set_cancel_callback(function_bind(&BlenderSession::test_cancel, this));
|
||||||
|
session->set_pause(BlenderSync::get_session_pause(b_scene, background));
|
||||||
|
|
||||||
|
/* start rendering */
|
||||||
|
session->reset(width, height, session_params.samples);
|
||||||
|
session->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlenderSession::free_session()
|
||||||
|
{
|
||||||
|
delete sync;
|
||||||
|
delete session;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlenderSession::render()
|
||||||
|
{
|
||||||
|
session->wait();
|
||||||
|
|
||||||
|
if(session->progress.get_cancel())
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* write result */
|
||||||
|
write_render_result();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlenderSession::write_render_result()
|
||||||
|
{
|
||||||
|
/* get result */
|
||||||
|
RenderBuffers *buffers = session->buffers;
|
||||||
|
float exposure = scene->film->exposure;
|
||||||
|
double total_time, sample_time;
|
||||||
|
int sample;
|
||||||
|
session->progress.get_sample(sample, total_time, sample_time);
|
||||||
|
|
||||||
|
float4 *pixels = buffers->copy_from_device(exposure, sample);
|
||||||
|
|
||||||
|
if(!pixels)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct RenderResult *rrp = RE_engine_begin_result((RenderEngine*)b_engine.ptr.data, 0, 0, width, height);
|
||||||
|
PointerRNA rrptr;
|
||||||
|
RNA_pointer_create(NULL, &RNA_RenderResult, rrp, &rrptr);
|
||||||
|
BL::RenderResult rr(rrptr);
|
||||||
|
|
||||||
|
BL::RenderResult::layers_iterator layer;
|
||||||
|
rr.layers.begin(layer);
|
||||||
|
rna_RenderLayer_rect_set(&layer->ptr, (float*)pixels);
|
||||||
|
|
||||||
|
RE_engine_end_result((RenderEngine*)b_engine.ptr.data, rrp);
|
||||||
|
|
||||||
|
delete [] pixels;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlenderSession::synchronize()
|
||||||
|
{
|
||||||
|
/* on session/scene parameter changes, we recreate session entirely */
|
||||||
|
SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
|
||||||
|
SessionParams session_params = BlenderSync::get_session_params(b_scene, background);
|
||||||
|
|
||||||
|
if(session->params.modified(session_params) ||
|
||||||
|
scene->params.modified(scene_params)) {
|
||||||
|
free_session();
|
||||||
|
create_session();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* increase samples, but never decrease */
|
||||||
|
session->set_samples(session_params.samples);
|
||||||
|
session->set_pause(BlenderSync::get_session_pause(b_scene, background));
|
||||||
|
|
||||||
|
/* copy recalc flags, outside of mutex so we can decide to do the real
|
||||||
|
synchronization at a later time to not block on running updates */
|
||||||
|
sync->sync_recalc();
|
||||||
|
|
||||||
|
/* try to acquire mutex. if we don't want to or can't, come back later */
|
||||||
|
if(!session->ready_to_reset() || !session->scene->mutex.try_lock()) {
|
||||||
|
tag_update();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* data and camera synchronize */
|
||||||
|
sync->sync_data(b_v3d);
|
||||||
|
|
||||||
|
if(b_rv3d)
|
||||||
|
sync->sync_view(b_v3d, b_rv3d, width, height);
|
||||||
|
else
|
||||||
|
sync->sync_camera(width, height);
|
||||||
|
|
||||||
|
/* unlock */
|
||||||
|
session->scene->mutex.unlock();
|
||||||
|
|
||||||
|
/* reset if needed */
|
||||||
|
if(scene->need_reset())
|
||||||
|
session->reset(width, height, session_params.samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BlenderSession::draw(int w, int h)
|
||||||
|
{
|
||||||
|
/* before drawing, we verify camera and viewport size changes, because
|
||||||
|
we do not get update callbacks for those, we must detect them here */
|
||||||
|
if(session->ready_to_reset()) {
|
||||||
|
bool reset = false;
|
||||||
|
|
||||||
|
/* try to acquire mutex. if we can't, come back later */
|
||||||
|
if(!session->scene->mutex.try_lock()) {
|
||||||
|
tag_update();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* update camera from 3d view */
|
||||||
|
bool need_update = scene->camera->need_update;
|
||||||
|
|
||||||
|
sync->sync_view(b_v3d, b_rv3d, w, h);
|
||||||
|
|
||||||
|
if(scene->camera->need_update && !need_update)
|
||||||
|
reset = true;
|
||||||
|
|
||||||
|
session->scene->mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if dimensions changed, reset */
|
||||||
|
if(width != w || height != h) {
|
||||||
|
width = w;
|
||||||
|
height = h;
|
||||||
|
reset = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reset if requested */
|
||||||
|
if(reset) {
|
||||||
|
SessionParams session_params = BlenderSync::get_session_params(b_scene, background);
|
||||||
|
session->reset(width, height, session_params.samples);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update status and progress for 3d view draw */
|
||||||
|
update_status_progress();
|
||||||
|
|
||||||
|
/* draw */
|
||||||
|
return !session->draw(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlenderSession::get_status(string& status, string& substatus)
|
||||||
|
{
|
||||||
|
session->progress.get_status(status, substatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlenderSession::get_progress(float& progress, double& total_time)
|
||||||
|
{
|
||||||
|
double sample_time;
|
||||||
|
int sample;
|
||||||
|
|
||||||
|
session->progress.get_sample(sample, total_time, sample_time);
|
||||||
|
progress = ((float)sample/(float)session->params.samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlenderSession::update_status_progress()
|
||||||
|
{
|
||||||
|
string status, substatus;
|
||||||
|
float progress;
|
||||||
|
double total_time;
|
||||||
|
char time_str[128];
|
||||||
|
|
||||||
|
get_status(status, substatus);
|
||||||
|
get_progress(progress, total_time);
|
||||||
|
|
||||||
|
if(!background) {
|
||||||
|
BLI_timestr(total_time, time_str);
|
||||||
|
status = "Time: " + string(time_str) + " | " + status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(substatus.size() > 0)
|
||||||
|
status += " | " + substatus;
|
||||||
|
|
||||||
|
if(status != last_status) {
|
||||||
|
RE_engine_update_stats((RenderEngine*)b_engine.ptr.data, "", status.c_str());
|
||||||
|
last_status = status;
|
||||||
|
}
|
||||||
|
if(progress != last_progress) {
|
||||||
|
RE_engine_update_progress((RenderEngine*)b_engine.ptr.data, progress);
|
||||||
|
last_progress = progress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlenderSession::tag_update()
|
||||||
|
{
|
||||||
|
/* tell blender that we want to get another update callback */
|
||||||
|
engine_tag_update((RenderEngine*)b_engine.ptr.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlenderSession::tag_redraw()
|
||||||
|
{
|
||||||
|
if(background) {
|
||||||
|
/* update stats and progress, only for background here because
|
||||||
|
in 3d view we do it in draw for thread safety reasons */
|
||||||
|
update_status_progress();
|
||||||
|
|
||||||
|
/* offline render, redraw if timeout passed */
|
||||||
|
if(time_dt() - last_redraw_time > 1.0f) {
|
||||||
|
write_render_result();
|
||||||
|
engine_tag_redraw((RenderEngine*)b_engine.ptr.data);
|
||||||
|
last_redraw_time = time_dt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* tell blender that we want to redraw */
|
||||||
|
engine_tag_redraw((RenderEngine*)b_engine.ptr.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlenderSession::test_cancel()
|
||||||
|
{
|
||||||
|
/* test if we need to cancel rendering */
|
||||||
|
if(background)
|
||||||
|
if(RE_engine_test_break((RenderEngine*)b_engine.ptr.data))
|
||||||
|
session->progress.set_cancel("Cancelled");
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
81
intern/cycles/blender/blender_session.h
Normal file
81
intern/cycles/blender/blender_session.h
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BLENDER_SESSION_H__
|
||||||
|
#define __BLENDER_SESSION_H__
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
#include "scene.h"
|
||||||
|
#include "session.h"
|
||||||
|
|
||||||
|
#include "util_vector.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class Scene;
|
||||||
|
class Session;
|
||||||
|
|
||||||
|
class BlenderSession {
|
||||||
|
public:
|
||||||
|
BlenderSession(BL::RenderEngine b_engine, BL::BlendData b_data, BL::Scene b_scene);
|
||||||
|
BlenderSession(BL::RenderEngine b_engine, BL::BlendData b_data, BL::Scene b_scene,
|
||||||
|
BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height);
|
||||||
|
|
||||||
|
~BlenderSession();
|
||||||
|
|
||||||
|
/* session */
|
||||||
|
void create_session();
|
||||||
|
void free_session();
|
||||||
|
|
||||||
|
/* offline render */
|
||||||
|
void render();
|
||||||
|
void write_render_result();
|
||||||
|
|
||||||
|
/* interactive updates */
|
||||||
|
void synchronize();
|
||||||
|
|
||||||
|
/* drawing */
|
||||||
|
bool draw(int w, int h);
|
||||||
|
void tag_redraw();
|
||||||
|
void tag_update();
|
||||||
|
void get_status(string& status, string& substatus);
|
||||||
|
void get_progress(float& progress, double& total_time);
|
||||||
|
void test_cancel();
|
||||||
|
void update_status_progress();
|
||||||
|
|
||||||
|
bool background;
|
||||||
|
Session *session;
|
||||||
|
Scene *scene;
|
||||||
|
BlenderSync *sync;
|
||||||
|
double last_redraw_time;
|
||||||
|
|
||||||
|
BL::RenderEngine b_engine;
|
||||||
|
BL::BlendData b_data;
|
||||||
|
BL::Scene b_scene;
|
||||||
|
BL::SpaceView3D b_v3d;
|
||||||
|
BL::RegionView3D b_rv3d;
|
||||||
|
|
||||||
|
string last_status;
|
||||||
|
float last_progress;
|
||||||
|
|
||||||
|
int width, height;
|
||||||
|
};
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* __BLENDER_SESSION_H__ */
|
702
intern/cycles/blender/blender_shader.cpp
Normal file
702
intern/cycles/blender/blender_shader.cpp
Normal file
@ -0,0 +1,702 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "background.h"
|
||||||
|
#include "graph.h"
|
||||||
|
#include "light.h"
|
||||||
|
#include "nodes.h"
|
||||||
|
#include "scene.h"
|
||||||
|
#include "shader.h"
|
||||||
|
|
||||||
|
#include "blender_sync.h"
|
||||||
|
#include "blender_util.h"
|
||||||
|
|
||||||
|
#include "util_debug.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
typedef map<void*, ShaderNode*> PtrNodeMap;
|
||||||
|
typedef pair<ShaderNode*, std::string> SocketPair;
|
||||||
|
typedef map<void*, SocketPair> PtrSockMap;
|
||||||
|
|
||||||
|
/* Find */
|
||||||
|
|
||||||
|
void BlenderSync::find_shader(BL::ID id, vector<uint>& used_shaders)
|
||||||
|
{
|
||||||
|
Shader *shader = shader_map.find(id);
|
||||||
|
|
||||||
|
for(size_t i = 0; i < scene->shaders.size(); i++) {
|
||||||
|
if(scene->shaders[i] == shader) {
|
||||||
|
used_shaders.push_back(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Graph */
|
||||||
|
|
||||||
|
static BL::NodeSocket get_node_input(BL::Node *b_group_node, BL::NodeSocket b_in)
|
||||||
|
{
|
||||||
|
if(b_group_node) {
|
||||||
|
|
||||||
|
BL::NodeTree b_ntree = BL::NodeGroup(*b_group_node).node_tree();
|
||||||
|
BL::NodeTree::links_iterator b_link;
|
||||||
|
|
||||||
|
for(b_ntree.links.begin(b_link); b_link != b_ntree.links.end(); ++b_link) {
|
||||||
|
if(b_link->to_socket().ptr.data == b_in.ptr.data) {
|
||||||
|
BL::Node::inputs_iterator b_gin;
|
||||||
|
|
||||||
|
for(b_group_node->inputs.begin(b_gin); b_gin != b_group_node->inputs.end(); ++b_gin)
|
||||||
|
if(b_gin->group_socket().ptr.data == b_link->from_socket().ptr.data)
|
||||||
|
return *b_gin;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return b_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BL::NodeSocket get_node_output(BL::Node b_node, const string& name)
|
||||||
|
{
|
||||||
|
BL::Node::outputs_iterator b_out;
|
||||||
|
|
||||||
|
for(b_node.outputs.begin(b_out); b_out != b_node.outputs.end(); ++b_out)
|
||||||
|
if(b_out->name() == name)
|
||||||
|
return *b_out;
|
||||||
|
|
||||||
|
assert(0);
|
||||||
|
|
||||||
|
return *b_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float3 get_node_output_rgba(BL::Node b_node, const string& name)
|
||||||
|
{
|
||||||
|
BL::NodeSocketRGBA sock(get_node_output(b_node, name));
|
||||||
|
return get_float3(sock.default_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
static float get_node_output_value(BL::Node b_node, const string& name)
|
||||||
|
{
|
||||||
|
BL::NodeSocketFloatNone sock(get_node_output(b_node, name));
|
||||||
|
return sock.default_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_tex_mapping(TextureMapping *mapping, BL::TexMapping b_mapping)
|
||||||
|
{
|
||||||
|
mapping->translation = get_float3(b_mapping.location());
|
||||||
|
mapping->rotation = get_float3(b_mapping.rotation())*(M_PI/180.0f); /* in degrees! */
|
||||||
|
mapping->scale = get_float3(b_mapping.scale());
|
||||||
|
|
||||||
|
mapping->x_mapping = (TextureMapping::Mapping)b_mapping.mapping_x();
|
||||||
|
mapping->y_mapping = (TextureMapping::Mapping)b_mapping.mapping_y();
|
||||||
|
mapping->z_mapping = (TextureMapping::Mapping)b_mapping.mapping_z();
|
||||||
|
}
|
||||||
|
|
||||||
|
static ShaderNode *add_node(BL::BlendData b_data, ShaderGraph *graph, BL::Node *b_group_node, BL::ShaderNode b_node)
|
||||||
|
{
|
||||||
|
ShaderNode *node = NULL;
|
||||||
|
|
||||||
|
switch(b_node.type()) {
|
||||||
|
/* not supported */
|
||||||
|
case BL::ShaderNode::type_CAMERA: break;
|
||||||
|
case BL::ShaderNode::type_COMBRGB: break;
|
||||||
|
case BL::ShaderNode::type_CURVE_RGB: break;
|
||||||
|
case BL::ShaderNode::type_CURVE_VEC: break;
|
||||||
|
case BL::ShaderNode::type_GEOMETRY: break;
|
||||||
|
case BL::ShaderNode::type_HUE_SAT: break;
|
||||||
|
case BL::ShaderNode::type_INVERT: break;
|
||||||
|
case BL::ShaderNode::type_MATERIAL: break;
|
||||||
|
case BL::ShaderNode::type_MATERIAL_EXT: break;
|
||||||
|
case BL::ShaderNode::type_NORMAL: break;
|
||||||
|
case BL::ShaderNode::type_OUTPUT: break;
|
||||||
|
case BL::ShaderNode::type_SCRIPT: break;
|
||||||
|
case BL::ShaderNode::type_SEPRGB: break;
|
||||||
|
case BL::ShaderNode::type_SQUEEZE: break;
|
||||||
|
case BL::ShaderNode::type_TEXTURE: break;
|
||||||
|
case BL::ShaderNode::type_VALTORGB: break;
|
||||||
|
/* handled outside this function */
|
||||||
|
case BL::ShaderNode::type_GROUP: break;
|
||||||
|
/* existing blender nodes */
|
||||||
|
case BL::ShaderNode::type_RGB: {
|
||||||
|
ColorNode *color = new ColorNode();
|
||||||
|
color->value = get_node_output_rgba(b_node, "Color");
|
||||||
|
node = color;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_VALUE: {
|
||||||
|
ValueNode *value = new ValueNode();
|
||||||
|
value->value = get_node_output_value(b_node, "Value");
|
||||||
|
node = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_MIX_RGB: {
|
||||||
|
BL::ShaderNodeMixRGB b_mix_node(b_node);
|
||||||
|
MixNode *mix = new MixNode();
|
||||||
|
mix->type = MixNode::type_enum[b_mix_node.blend_type()];
|
||||||
|
node = mix;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_RGBTOBW: {
|
||||||
|
node = new ConvertNode(SHADER_SOCKET_COLOR, SHADER_SOCKET_FLOAT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_MATH: {
|
||||||
|
BL::ShaderNodeMath b_math_node(b_node);
|
||||||
|
MathNode *math = new MathNode();
|
||||||
|
math->type = MathNode::type_enum[b_math_node.operation()];
|
||||||
|
node = math;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_VECT_MATH: {
|
||||||
|
BL::ShaderNodeVectorMath b_vector_math_node(b_node);
|
||||||
|
VectorMathNode *vmath = new VectorMathNode();
|
||||||
|
vmath->type = VectorMathNode::type_enum[b_vector_math_node.operation()];
|
||||||
|
node = vmath;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_MAPPING: {
|
||||||
|
BL::ShaderNodeMapping b_mapping_node(b_node);
|
||||||
|
MappingNode *mapping = new MappingNode();
|
||||||
|
|
||||||
|
get_tex_mapping(&mapping->tex_mapping, b_mapping_node.mapping());
|
||||||
|
|
||||||
|
node = mapping;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* new nodes */
|
||||||
|
case BL::ShaderNode::type_OUTPUT_MATERIAL:
|
||||||
|
case BL::ShaderNode::type_OUTPUT_WORLD:
|
||||||
|
case BL::ShaderNode::type_OUTPUT_LAMP: {
|
||||||
|
node = graph->output();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_FRESNEL: {
|
||||||
|
node = new FresnelNode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_LAYER_WEIGHT: {
|
||||||
|
node = new LayerWeightNode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_ADD_SHADER: {
|
||||||
|
node = new AddClosureNode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_MIX_SHADER: {
|
||||||
|
node = new MixClosureNode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_ATTRIBUTE: {
|
||||||
|
BL::ShaderNodeAttribute b_attr_node(b_node);
|
||||||
|
AttributeNode *attr = new AttributeNode();
|
||||||
|
attr->attribute = b_attr_node.attribute_name();
|
||||||
|
node = attr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_BACKGROUND: {
|
||||||
|
node = new BackgroundNode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_HOLDOUT: {
|
||||||
|
node = new HoldoutNode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_BSDF_DIFFUSE: {
|
||||||
|
node = new DiffuseBsdfNode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_BSDF_GLOSSY: {
|
||||||
|
BL::ShaderNodeBsdfGlossy b_glossy_node(b_node);
|
||||||
|
GlossyBsdfNode *glossy = new GlossyBsdfNode();
|
||||||
|
|
||||||
|
switch(b_glossy_node.distribution()) {
|
||||||
|
case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
|
||||||
|
glossy->distribution = ustring("Sharp");
|
||||||
|
break;
|
||||||
|
case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
|
||||||
|
glossy->distribution = ustring("Beckmann");
|
||||||
|
break;
|
||||||
|
case BL::ShaderNodeBsdfGlossy::distribution_GGX:
|
||||||
|
glossy->distribution = ustring("GGX");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
node = glossy;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_BSDF_GLASS: {
|
||||||
|
BL::ShaderNodeBsdfGlass b_glass_node(b_node);
|
||||||
|
GlassBsdfNode *glass = new GlassBsdfNode();
|
||||||
|
switch(b_glass_node.distribution()) {
|
||||||
|
case BL::ShaderNodeBsdfGlass::distribution_SHARP:
|
||||||
|
glass->distribution = ustring("Sharp");
|
||||||
|
break;
|
||||||
|
case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
|
||||||
|
glass->distribution = ustring("Beckmann");
|
||||||
|
break;
|
||||||
|
case BL::ShaderNodeBsdfGlass::distribution_GGX:
|
||||||
|
glass->distribution = ustring("GGX");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
node = glass;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_BSDF_TRANSLUCENT: {
|
||||||
|
node = new TranslucentBsdfNode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_BSDF_TRANSPARENT: {
|
||||||
|
node = new TransparentBsdfNode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_BSDF_VELVET: {
|
||||||
|
node = new VelvetBsdfNode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_EMISSION: {
|
||||||
|
node = new EmissionNode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_VOLUME_ISOTROPIC: {
|
||||||
|
node = new IsotropicVolumeNode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_VOLUME_TRANSPARENT: {
|
||||||
|
node = new TransparentVolumeNode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_NEW_GEOMETRY: {
|
||||||
|
node = new GeometryNode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_LIGHT_PATH: {
|
||||||
|
node = new LightPathNode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_TEX_IMAGE: {
|
||||||
|
BL::ShaderNodeTexImage b_image_node(b_node);
|
||||||
|
BL::Image b_image(b_image_node.image());
|
||||||
|
ImageTextureNode *image = new ImageTextureNode();
|
||||||
|
/* todo: handle generated/builtin images */
|
||||||
|
if(b_image)
|
||||||
|
image->filename = blender_absolute_path(b_data, b_image, b_image.filepath());
|
||||||
|
image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
|
||||||
|
get_tex_mapping(&image->tex_mapping, b_image_node.texture_mapping());
|
||||||
|
node = image;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_TEX_ENVIRONMENT: {
|
||||||
|
BL::ShaderNodeTexEnvironment b_env_node(b_node);
|
||||||
|
BL::Image b_image(b_env_node.image());
|
||||||
|
EnvironmentTextureNode *env = new EnvironmentTextureNode();
|
||||||
|
if(b_image)
|
||||||
|
env->filename = blender_absolute_path(b_data, b_image, b_image.filepath());
|
||||||
|
env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()];
|
||||||
|
get_tex_mapping(&env->tex_mapping, b_env_node.texture_mapping());
|
||||||
|
node = env;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_TEX_GRADIENT: {
|
||||||
|
BL::ShaderNodeTexGradient b_gradient_node(b_node);
|
||||||
|
GradientTextureNode *gradient = new GradientTextureNode();
|
||||||
|
gradient->type = GradientTextureNode::type_enum[(int)b_gradient_node.gradient_type()];
|
||||||
|
get_tex_mapping(&gradient->tex_mapping, b_gradient_node.texture_mapping());
|
||||||
|
node = gradient;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_TEX_VORONOI: {
|
||||||
|
BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
|
||||||
|
VoronoiTextureNode *voronoi = new VoronoiTextureNode();
|
||||||
|
voronoi->coloring = VoronoiTextureNode::coloring_enum[(int)b_voronoi_node.coloring()];
|
||||||
|
get_tex_mapping(&voronoi->tex_mapping, b_voronoi_node.texture_mapping());
|
||||||
|
node = voronoi;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_TEX_MAGIC: {
|
||||||
|
BL::ShaderNodeTexMagic b_magic_node(b_node);
|
||||||
|
MagicTextureNode *magic = new MagicTextureNode();
|
||||||
|
magic->depth = b_magic_node.turbulence_depth();
|
||||||
|
get_tex_mapping(&magic->tex_mapping, b_magic_node.texture_mapping());
|
||||||
|
node = magic;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_TEX_WAVE: {
|
||||||
|
BL::ShaderNodeTexWave b_wave_node(b_node);
|
||||||
|
WaveTextureNode *wave = new WaveTextureNode();
|
||||||
|
wave->type = WaveTextureNode::type_enum[(int)b_wave_node.wave_type()];
|
||||||
|
get_tex_mapping(&wave->tex_mapping, b_wave_node.texture_mapping());
|
||||||
|
node = wave;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_TEX_NOISE: {
|
||||||
|
BL::ShaderNodeTexNoise b_noise_node(b_node);
|
||||||
|
NoiseTextureNode *noise = new NoiseTextureNode();
|
||||||
|
get_tex_mapping(&noise->tex_mapping, b_noise_node.texture_mapping());
|
||||||
|
node = noise;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_TEX_MUSGRAVE: {
|
||||||
|
BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
|
||||||
|
MusgraveTextureNode *musgrave = new MusgraveTextureNode();
|
||||||
|
musgrave->type = MusgraveTextureNode::type_enum[(int)b_musgrave_node.musgrave_type()];
|
||||||
|
get_tex_mapping(&musgrave->tex_mapping, b_musgrave_node.texture_mapping());
|
||||||
|
node = musgrave;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_TEX_COORD: {
|
||||||
|
node = new TextureCoordinateNode();;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BL::ShaderNode::type_TEX_SKY: {
|
||||||
|
BL::ShaderNodeTexSky b_sky_node(b_node);
|
||||||
|
SkyTextureNode *sky = new SkyTextureNode();
|
||||||
|
sky->sun_direction = get_float3(b_sky_node.sun_direction());
|
||||||
|
sky->turbidity = b_sky_node.turbidity();
|
||||||
|
get_tex_mapping(&sky->tex_mapping, b_sky_node.texture_mapping());
|
||||||
|
node = sky;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node && node != graph->output())
|
||||||
|
graph->add(node);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SocketPair node_socket_map_pair(PtrNodeMap& node_map, BL::Node b_node, BL::NodeSocket b_socket)
|
||||||
|
{
|
||||||
|
BL::Node::inputs_iterator b_input;
|
||||||
|
BL::Node::outputs_iterator b_output;
|
||||||
|
string name = b_socket.name();
|
||||||
|
bool found = false;
|
||||||
|
int counter = 0, total = 0;
|
||||||
|
|
||||||
|
/* find in inputs */
|
||||||
|
for(b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
|
||||||
|
if(b_input->name() == name) {
|
||||||
|
if(!found)
|
||||||
|
counter++;
|
||||||
|
total++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(b_input->ptr.data == b_socket.ptr.data)
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!found) {
|
||||||
|
/* find in outputs */
|
||||||
|
found = false;
|
||||||
|
counter = 0;
|
||||||
|
total = 0;
|
||||||
|
|
||||||
|
for(b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
|
||||||
|
if(b_output->name() == name) {
|
||||||
|
if(!found)
|
||||||
|
counter++;
|
||||||
|
total++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(b_output->ptr.data == b_socket.ptr.data)
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* rename if needed */
|
||||||
|
if(name == "Shader")
|
||||||
|
name = "Closure";
|
||||||
|
|
||||||
|
if(total > 1)
|
||||||
|
name = string_printf("%s%d", name.c_str(), counter);
|
||||||
|
|
||||||
|
return SocketPair(node_map[b_node.ptr.data], name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_nodes(BL::BlendData b_data, ShaderGraph *graph, BL::ShaderNodeTree b_ntree, BL::Node *b_group_node, PtrSockMap& sockets_map)
|
||||||
|
{
|
||||||
|
/* add nodes */
|
||||||
|
BL::ShaderNodeTree::nodes_iterator b_node;
|
||||||
|
PtrNodeMap node_map;
|
||||||
|
map<void*, PtrSockMap> node_groups;
|
||||||
|
|
||||||
|
for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) {
|
||||||
|
if(b_node->is_a(&RNA_NodeGroup)) {
|
||||||
|
BL::NodeGroup b_gnode(*b_node);
|
||||||
|
BL::ShaderNodeTree b_group_ntree(b_gnode.node_tree());
|
||||||
|
|
||||||
|
node_groups[b_node->ptr.data] = PtrSockMap();
|
||||||
|
add_nodes(b_data, graph, b_group_ntree, &b_gnode, node_groups[b_node->ptr.data]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ShaderNode *node = add_node(b_data, graph, b_group_node, BL::ShaderNode(*b_node));
|
||||||
|
|
||||||
|
if(node) {
|
||||||
|
BL::Node::inputs_iterator b_input;
|
||||||
|
BL::Node::outputs_iterator b_output;
|
||||||
|
|
||||||
|
node_map[b_node->ptr.data] = node;
|
||||||
|
|
||||||
|
for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
|
||||||
|
SocketPair pair = node_socket_map_pair(node_map, *b_node, *b_input);
|
||||||
|
ShaderInput *input = pair.first->input(pair.second.c_str());
|
||||||
|
BL::NodeSocket sock(get_node_input(b_group_node, *b_input));
|
||||||
|
|
||||||
|
assert(input);
|
||||||
|
|
||||||
|
/* copy values for non linked inputs */
|
||||||
|
switch(input->type) {
|
||||||
|
case SHADER_SOCKET_FLOAT: {
|
||||||
|
BL::NodeSocketFloatNone value_sock(sock);
|
||||||
|
input->set(value_sock.default_value());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SHADER_SOCKET_COLOR: {
|
||||||
|
BL::NodeSocketRGBA rgba_sock(sock);
|
||||||
|
input->set(get_float3(rgba_sock.default_value()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SHADER_SOCKET_NORMAL:
|
||||||
|
case SHADER_SOCKET_POINT:
|
||||||
|
case SHADER_SOCKET_VECTOR: {
|
||||||
|
BL::NodeSocketVectorNone vec_sock(sock);
|
||||||
|
input->set(get_float3(vec_sock.default_value()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SHADER_SOCKET_CLOSURE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* connect nodes */
|
||||||
|
BL::NodeTree::links_iterator b_link;
|
||||||
|
|
||||||
|
for(b_ntree.links.begin(b_link); b_link != b_ntree.links.end(); ++b_link) {
|
||||||
|
/* get blender link data */
|
||||||
|
BL::Node b_from_node = b_link->from_node();
|
||||||
|
BL::Node b_to_node = b_link->to_node();
|
||||||
|
|
||||||
|
BL::NodeSocket b_from_sock = b_link->from_socket();
|
||||||
|
BL::NodeSocket b_to_sock = b_link->to_socket();
|
||||||
|
|
||||||
|
/* if link with group socket, add to map so we can connect it later */
|
||||||
|
if(b_group_node) {
|
||||||
|
if(!b_from_node) {
|
||||||
|
sockets_map[b_from_sock.ptr.data] =
|
||||||
|
node_socket_map_pair(node_map, b_to_node, b_to_sock);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(!b_to_node) {
|
||||||
|
sockets_map[b_to_sock.ptr.data] =
|
||||||
|
node_socket_map_pair(node_map, b_from_node, b_from_sock);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketPair from_pair, to_pair;
|
||||||
|
|
||||||
|
/* from sock */
|
||||||
|
if(b_from_node.is_a(&RNA_NodeGroup)) {
|
||||||
|
/* group node */
|
||||||
|
BL::NodeSocket group_sock = b_from_sock.group_socket();
|
||||||
|
from_pair = node_groups[b_from_node.ptr.data][group_sock.ptr.data];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* regular node */
|
||||||
|
from_pair = node_socket_map_pair(node_map, b_from_node, b_from_sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* to sock */
|
||||||
|
if(b_to_node.is_a(&RNA_NodeGroup)) {
|
||||||
|
/* group node */
|
||||||
|
BL::NodeSocket group_sock = b_to_sock.group_socket();
|
||||||
|
to_pair = node_groups[b_to_node.ptr.data][group_sock.ptr.data];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* regular node */
|
||||||
|
to_pair = node_socket_map_pair(node_map, b_to_node, b_to_sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* in case of groups there may not actually be a node inside the group
|
||||||
|
that the group socket connects to, so from_node or to_node may be NULL */
|
||||||
|
if(from_pair.first && to_pair.first) {
|
||||||
|
ShaderOutput *output = from_pair.first->output(from_pair.second.c_str());
|
||||||
|
ShaderInput *input = to_pair.first->input(to_pair.second.c_str());
|
||||||
|
|
||||||
|
graph->connect(output, input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sync Materials */
|
||||||
|
|
||||||
|
void BlenderSync::sync_materials()
|
||||||
|
{
|
||||||
|
shader_map.set_default(scene->shaders[scene->default_surface]);
|
||||||
|
|
||||||
|
/* material loop */
|
||||||
|
BL::BlendData::materials_iterator b_mat;
|
||||||
|
|
||||||
|
for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat) {
|
||||||
|
Shader *shader;
|
||||||
|
|
||||||
|
/* test if we need to sync */
|
||||||
|
if(shader_map.sync(&shader, *b_mat)) {
|
||||||
|
ShaderGraph *graph = new ShaderGraph();
|
||||||
|
|
||||||
|
shader->name = b_mat->name().c_str();
|
||||||
|
|
||||||
|
/* create nodes */
|
||||||
|
if(b_mat->use_nodes() && b_mat->node_tree()) {
|
||||||
|
PtrSockMap sock_to_node;
|
||||||
|
BL::ShaderNodeTree b_ntree(b_mat->node_tree());
|
||||||
|
|
||||||
|
add_nodes(b_data, graph, b_ntree, NULL, sock_to_node);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ShaderNode *closure, *out;
|
||||||
|
|
||||||
|
closure = graph->add(new DiffuseBsdfNode());
|
||||||
|
closure->input("Color")->value = get_float3(b_mat->diffuse_color());
|
||||||
|
out = graph->output();
|
||||||
|
|
||||||
|
graph->connect(closure->output("BSDF"), out->input("Surface"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* settings */
|
||||||
|
PointerRNA cmat = RNA_pointer_get(&b_mat->ptr, "cycles");
|
||||||
|
shader->sample_as_light = get_boolean(cmat, "sample_as_light");
|
||||||
|
shader->homogeneous_volume = get_boolean(cmat, "homogeneous_volume");
|
||||||
|
|
||||||
|
shader->set_graph(graph);
|
||||||
|
shader->tag_update(scene);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sync World */
|
||||||
|
|
||||||
|
void BlenderSync::sync_world()
|
||||||
|
{
|
||||||
|
Background *background = scene->background;
|
||||||
|
Background prevbackground = *background;
|
||||||
|
|
||||||
|
BL::World b_world = b_scene.world();
|
||||||
|
|
||||||
|
if(world_recalc || b_world.ptr.data != world_map) {
|
||||||
|
Shader *shader = scene->shaders[scene->default_background];
|
||||||
|
ShaderGraph *graph = new ShaderGraph();
|
||||||
|
|
||||||
|
/* create nodes */
|
||||||
|
if(b_world && b_world.use_nodes() && b_world.node_tree()) {
|
||||||
|
PtrSockMap sock_to_node;
|
||||||
|
BL::ShaderNodeTree b_ntree(b_world.node_tree());
|
||||||
|
|
||||||
|
add_nodes(b_data, graph, b_ntree, NULL, sock_to_node);
|
||||||
|
}
|
||||||
|
else if(b_world) {
|
||||||
|
ShaderNode *closure, *out;
|
||||||
|
|
||||||
|
closure = graph->add(new BackgroundNode());
|
||||||
|
closure->input("Color")->value = get_float3(b_world.horizon_color());
|
||||||
|
out = graph->output();
|
||||||
|
|
||||||
|
graph->connect(closure->output("Background"), out->input("Surface"));
|
||||||
|
}
|
||||||
|
|
||||||
|
shader->set_graph(graph);
|
||||||
|
shader->tag_update(scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||||
|
background->transparent = get_boolean(cscene, "film_transparent");
|
||||||
|
|
||||||
|
if(background->modified(prevbackground))
|
||||||
|
background->tag_update(scene);
|
||||||
|
|
||||||
|
world_map = b_world.ptr.data;
|
||||||
|
world_recalc = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sync Lamps */
|
||||||
|
|
||||||
|
void BlenderSync::sync_lamps()
|
||||||
|
{
|
||||||
|
shader_map.set_default(scene->shaders[scene->default_light]);
|
||||||
|
|
||||||
|
/* lamp loop */
|
||||||
|
BL::BlendData::lamps_iterator b_lamp;
|
||||||
|
|
||||||
|
for(b_data.lamps.begin(b_lamp); b_lamp != b_data.lamps.end(); ++b_lamp) {
|
||||||
|
Shader *shader;
|
||||||
|
|
||||||
|
/* test if we need to sync */
|
||||||
|
if(shader_map.sync(&shader, *b_lamp)) {
|
||||||
|
ShaderGraph *graph = new ShaderGraph();
|
||||||
|
|
||||||
|
/* create nodes */
|
||||||
|
if(b_lamp->use_nodes() && b_lamp->node_tree()) {
|
||||||
|
shader->name = b_lamp->name().c_str();
|
||||||
|
|
||||||
|
PtrSockMap sock_to_node;
|
||||||
|
BL::ShaderNodeTree b_ntree(b_lamp->node_tree());
|
||||||
|
|
||||||
|
add_nodes(b_data, graph, b_ntree, NULL, sock_to_node);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ShaderNode *closure, *out;
|
||||||
|
float strength = 1.0f;
|
||||||
|
|
||||||
|
if(b_lamp->type() == BL::Lamp::type_POINT ||
|
||||||
|
b_lamp->type() == BL::Lamp::type_SPOT ||
|
||||||
|
b_lamp->type() == BL::Lamp::type_AREA)
|
||||||
|
strength = 100.0f;
|
||||||
|
|
||||||
|
closure = graph->add(new EmissionNode());
|
||||||
|
closure->input("Color")->value = get_float3(b_lamp->color());
|
||||||
|
closure->input("Strength")->value.x = strength;
|
||||||
|
out = graph->output();
|
||||||
|
|
||||||
|
graph->connect(closure->output("Emission"), out->input("Surface"));
|
||||||
|
}
|
||||||
|
|
||||||
|
shader->set_graph(graph);
|
||||||
|
shader->tag_update(scene);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlenderSync::sync_shaders()
|
||||||
|
{
|
||||||
|
shader_map.pre_sync();
|
||||||
|
|
||||||
|
sync_world();
|
||||||
|
sync_lamps();
|
||||||
|
sync_materials();
|
||||||
|
|
||||||
|
/* false = don't delete unused shaders, not supported */
|
||||||
|
shader_map.post_sync(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
303
intern/cycles/blender/blender_sync.cpp
Normal file
303
intern/cycles/blender/blender_sync.cpp
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "background.h"
|
||||||
|
#include "film.h"
|
||||||
|
#include "../render/filter.h"
|
||||||
|
#include "graph.h"
|
||||||
|
#include "integrator.h"
|
||||||
|
#include "light.h"
|
||||||
|
#include "mesh.h"
|
||||||
|
#include "nodes.h"
|
||||||
|
#include "object.h"
|
||||||
|
#include "scene.h"
|
||||||
|
#include "shader.h"
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
|
#include "blender_sync.h"
|
||||||
|
#include "blender_util.h"
|
||||||
|
|
||||||
|
#include "util_debug.h"
|
||||||
|
#include "util_foreach.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* Constructor */
|
||||||
|
|
||||||
|
BlenderSync::BlenderSync(BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene_, bool preview_)
|
||||||
|
: b_data(b_data_), b_scene(b_scene_),
|
||||||
|
shader_map(&scene_->shaders),
|
||||||
|
object_map(&scene_->objects),
|
||||||
|
mesh_map(&scene_->meshes),
|
||||||
|
light_map(&scene_->lights),
|
||||||
|
world_map(NULL),
|
||||||
|
world_recalc(false)
|
||||||
|
{
|
||||||
|
scene = scene_;
|
||||||
|
preview = preview_;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlenderSync::~BlenderSync()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sync */
|
||||||
|
|
||||||
|
bool BlenderSync::sync_recalc()
|
||||||
|
{
|
||||||
|
/* sync recalc flags from blender to cycles. actual update is done separate,
|
||||||
|
so we can do it later on if doing it immediate is not suitable */
|
||||||
|
|
||||||
|
BL::BlendData::materials_iterator b_mat;
|
||||||
|
|
||||||
|
for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat)
|
||||||
|
if(b_mat->is_updated())
|
||||||
|
shader_map.set_recalc(*b_mat);
|
||||||
|
|
||||||
|
BL::BlendData::lamps_iterator b_lamp;
|
||||||
|
|
||||||
|
for(b_data.lamps.begin(b_lamp); b_lamp != b_data.lamps.end(); ++b_lamp)
|
||||||
|
if(b_lamp->is_updated())
|
||||||
|
shader_map.set_recalc(*b_lamp);
|
||||||
|
|
||||||
|
BL::BlendData::objects_iterator b_ob;
|
||||||
|
|
||||||
|
for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) {
|
||||||
|
if(b_ob->is_updated()) {
|
||||||
|
object_map.set_recalc(*b_ob);
|
||||||
|
light_map.set_recalc(*b_ob);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(object_is_mesh(*b_ob)) {
|
||||||
|
if(b_ob->is_updated_data() || b_ob->data().is_updated()) {
|
||||||
|
BL::ID key = object_is_modified(*b_ob)? *b_ob: b_ob->data();
|
||||||
|
mesh_map.set_recalc(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(object_is_light(*b_ob)) {
|
||||||
|
if(b_ob->is_updated_data() || b_ob->data().is_updated())
|
||||||
|
light_map.set_recalc(*b_ob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BL::BlendData::meshes_iterator b_mesh;
|
||||||
|
|
||||||
|
for(b_data.meshes.begin(b_mesh); b_mesh != b_data.meshes.end(); ++b_mesh)
|
||||||
|
if(b_mesh->is_updated())
|
||||||
|
mesh_map.set_recalc(*b_mesh);
|
||||||
|
|
||||||
|
BL::BlendData::worlds_iterator b_world;
|
||||||
|
|
||||||
|
for(b_data.worlds.begin(b_world); b_world != b_data.worlds.end(); ++b_world)
|
||||||
|
if(world_map == b_world->ptr.data && b_world->is_updated())
|
||||||
|
world_recalc = true;
|
||||||
|
|
||||||
|
bool recalc =
|
||||||
|
shader_map.has_recalc() ||
|
||||||
|
object_map.has_recalc() ||
|
||||||
|
light_map.has_recalc() ||
|
||||||
|
mesh_map.has_recalc() ||
|
||||||
|
BlendDataObjects_is_updated_get(&b_data.ptr) ||
|
||||||
|
world_recalc;
|
||||||
|
|
||||||
|
return recalc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlenderSync::sync_data(BL::SpaceView3D b_v3d)
|
||||||
|
{
|
||||||
|
sync_integrator();
|
||||||
|
sync_film();
|
||||||
|
sync_render_layer(b_v3d);
|
||||||
|
sync_shaders();
|
||||||
|
sync_objects(b_v3d);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Integrator */
|
||||||
|
|
||||||
|
void BlenderSync::sync_integrator()
|
||||||
|
{
|
||||||
|
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||||
|
|
||||||
|
Integrator *integrator = scene->integrator;
|
||||||
|
Integrator previntegrator = *integrator;
|
||||||
|
|
||||||
|
integrator->min_bounce = get_int(cscene, "min_bounces");
|
||||||
|
integrator->max_bounce = get_int(cscene, "max_bounces");
|
||||||
|
|
||||||
|
integrator->max_diffuse_bounce = get_int(cscene, "diffuse_bounces");
|
||||||
|
integrator->max_glossy_bounce = get_int(cscene, "glossy_bounces");
|
||||||
|
integrator->max_transmission_bounce = get_int(cscene, "transmission_bounces");
|
||||||
|
|
||||||
|
integrator->transparent_max_bounce = get_int(cscene, "transparent_max_bounces");
|
||||||
|
integrator->transparent_min_bounce = get_int(cscene, "transparent_min_bounces");
|
||||||
|
integrator->transparent_shadows = get_boolean(cscene, "use_transparent_shadows");
|
||||||
|
|
||||||
|
integrator->no_caustics = get_boolean(cscene, "no_caustics");
|
||||||
|
integrator->blur_caustics = get_float(cscene, "blur_caustics");
|
||||||
|
|
||||||
|
integrator->seed = get_int(cscene, "seed");
|
||||||
|
|
||||||
|
if(integrator->modified(previntegrator))
|
||||||
|
integrator->tag_update(scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Film */
|
||||||
|
|
||||||
|
void BlenderSync::sync_film()
|
||||||
|
{
|
||||||
|
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||||
|
|
||||||
|
Film *film = scene->film;
|
||||||
|
Film prevfilm = *film;
|
||||||
|
|
||||||
|
film->exposure = get_float(cscene, "film_exposure");
|
||||||
|
|
||||||
|
if(film->modified(prevfilm))
|
||||||
|
film->tag_update(scene);
|
||||||
|
|
||||||
|
Filter *filter = scene->filter;
|
||||||
|
Filter prevfilter = *filter;
|
||||||
|
|
||||||
|
filter->filter_type = (FilterType)RNA_enum_get(&cscene, "filter_type");
|
||||||
|
filter->filter_width = (filter->filter_type == FILTER_BOX)? 1.0f: get_float(cscene, "filter_width");
|
||||||
|
|
||||||
|
if(filter->modified(prevfilter))
|
||||||
|
filter->tag_update(scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Render Layer */
|
||||||
|
|
||||||
|
void BlenderSync::sync_render_layer(BL::SpaceView3D b_v3d)
|
||||||
|
{
|
||||||
|
if(b_v3d) {
|
||||||
|
render_layer.scene_layer = get_layer(b_v3d.layers());
|
||||||
|
render_layer.layer = render_layer.scene_layer;
|
||||||
|
render_layer.material_override = PointerRNA_NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BL::RenderSettings r = b_scene.render();
|
||||||
|
BL::RenderSettings::layers_iterator b_rlay;
|
||||||
|
bool first = true;
|
||||||
|
|
||||||
|
for(r.layers.begin(b_rlay); b_rlay != r.layers.end(); ++b_rlay) {
|
||||||
|
/* single layer for now */
|
||||||
|
if(first) {
|
||||||
|
render_layer.scene_layer = get_layer(b_scene.layers());
|
||||||
|
render_layer.layer = get_layer(b_rlay->layers());
|
||||||
|
render_layer.material_override = b_rlay->material_override();
|
||||||
|
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scene Parameters */
|
||||||
|
|
||||||
|
SceneParams BlenderSync::get_scene_params(BL::Scene b_scene, bool background)
|
||||||
|
{
|
||||||
|
SceneParams params;
|
||||||
|
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||||
|
int shadingsystem = RNA_enum_get(&cscene, "shading_system");
|
||||||
|
|
||||||
|
if(shadingsystem == 0)
|
||||||
|
params.shadingsystem = SceneParams::SVM;
|
||||||
|
else if(shadingsystem == 1)
|
||||||
|
params.shadingsystem = SceneParams::OSL;
|
||||||
|
|
||||||
|
if(background)
|
||||||
|
params.bvh_type = SceneParams::BVH_STATIC;
|
||||||
|
else
|
||||||
|
params.bvh_type = (SceneParams::BVHType)RNA_enum_get(&cscene, "debug_bvh_type");
|
||||||
|
|
||||||
|
params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits");
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Session Parameters */
|
||||||
|
|
||||||
|
bool BlenderSync::get_session_pause(BL::Scene b_scene, bool background)
|
||||||
|
{
|
||||||
|
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||||
|
return (background)? false: get_boolean(cscene, "preview_pause");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool device_type_available(vector<DeviceType>& types, DeviceType dtype)
|
||||||
|
{
|
||||||
|
foreach(DeviceType dt, types)
|
||||||
|
if(dt == dtype)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionParams BlenderSync::get_session_params(BL::Scene b_scene, bool background)
|
||||||
|
{
|
||||||
|
SessionParams params;
|
||||||
|
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||||
|
|
||||||
|
/* device type */
|
||||||
|
params.device_type = DEVICE_CPU;
|
||||||
|
|
||||||
|
if(RNA_enum_get(&cscene, "device") != 0) {
|
||||||
|
vector<DeviceType> types = Device::available_types();
|
||||||
|
DeviceType dtype = (RNA_enum_get(&cscene, "gpu_type") == 0)? DEVICE_CUDA: DEVICE_OPENCL;
|
||||||
|
|
||||||
|
if(device_type_available(types, dtype))
|
||||||
|
params.device_type = dtype;
|
||||||
|
else if(device_type_available(types, DEVICE_OPENCL))
|
||||||
|
params.device_type = DEVICE_OPENCL;
|
||||||
|
else if(device_type_available(types, DEVICE_CUDA))
|
||||||
|
params.device_type = DEVICE_CUDA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Background */
|
||||||
|
params.background = background;
|
||||||
|
|
||||||
|
/* samples */
|
||||||
|
if(background) {
|
||||||
|
params.samples = get_int(cscene, "samples");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
params.samples = get_int(cscene, "preview_samples");
|
||||||
|
if(params.samples == 0)
|
||||||
|
params.samples = INT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* other parameters */
|
||||||
|
params.threads = b_scene.render().threads();
|
||||||
|
params.tile_size = get_int(cscene, "debug_tile_size");
|
||||||
|
params.min_size = get_int(cscene, "debug_min_size");
|
||||||
|
params.cancel_timeout = get_float(cscene, "debug_cancel_timeout");
|
||||||
|
params.reset_timeout = get_float(cscene, "debug_reset_timeout");
|
||||||
|
params.text_timeout = get_float(cscene, "debug_text_timeout");
|
||||||
|
|
||||||
|
if(background) {
|
||||||
|
params.progressive = true;
|
||||||
|
params.min_size = INT_MAX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
params.progressive = true;
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
119
intern/cycles/blender/blender_sync.h
Normal file
119
intern/cycles/blender/blender_sync.h
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BLENDER_SYNC_H__
|
||||||
|
#define __BLENDER_SYNC_H__
|
||||||
|
|
||||||
|
#include "MEM_guardedalloc.h"
|
||||||
|
#include "RNA_types.h"
|
||||||
|
#include "RNA_access.h"
|
||||||
|
#include "RNA_blender_cpp.h"
|
||||||
|
|
||||||
|
#include "blender_util.h"
|
||||||
|
|
||||||
|
#include "scene.h"
|
||||||
|
#include "session.h"
|
||||||
|
|
||||||
|
#include "util_map.h"
|
||||||
|
#include "util_set.h"
|
||||||
|
#include "util_transform.h"
|
||||||
|
#include "util_vector.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class Background;
|
||||||
|
class Camera;
|
||||||
|
class Film;
|
||||||
|
class Light;
|
||||||
|
class Mesh;
|
||||||
|
class Object;
|
||||||
|
class Scene;
|
||||||
|
class Shader;
|
||||||
|
class ShaderGraph;
|
||||||
|
class ShaderNode;
|
||||||
|
|
||||||
|
class BlenderSync {
|
||||||
|
public:
|
||||||
|
BlenderSync(BL::BlendData b_data, BL::Scene b_scene, Scene *scene_, bool preview_);
|
||||||
|
~BlenderSync();
|
||||||
|
|
||||||
|
/* sync */
|
||||||
|
bool sync_recalc();
|
||||||
|
void sync_data(BL::SpaceView3D b_v3d);
|
||||||
|
void sync_camera(int width, int height);
|
||||||
|
void sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height);
|
||||||
|
|
||||||
|
/* get parameters */
|
||||||
|
static SceneParams get_scene_params(BL::Scene b_scene, bool background);
|
||||||
|
static SessionParams get_session_params(BL::Scene b_scene, bool background);
|
||||||
|
static bool get_session_pause(BL::Scene b_scene, bool background);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* sync */
|
||||||
|
void sync_lamps();
|
||||||
|
void sync_materials();
|
||||||
|
void sync_objects(BL::SpaceView3D b_v3d);
|
||||||
|
void sync_film();
|
||||||
|
void sync_integrator();
|
||||||
|
void sync_view();
|
||||||
|
void sync_world();
|
||||||
|
void sync_render_layer(BL::SpaceView3D b_v3d);
|
||||||
|
void sync_shaders();
|
||||||
|
|
||||||
|
void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree);
|
||||||
|
Mesh *sync_mesh(BL::Object b_ob, bool object_updated);
|
||||||
|
void sync_object(BL::Object b_parent, int b_index, BL::Object b_object, Transform& tfm, uint visibility);
|
||||||
|
void sync_light(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm);
|
||||||
|
|
||||||
|
/* util */
|
||||||
|
void find_shader(BL::ID id, vector<uint>& used_shaders);
|
||||||
|
bool object_is_modified(BL::Object b_ob);
|
||||||
|
bool object_is_mesh(BL::Object b_ob);
|
||||||
|
bool object_is_light(BL::Object b_ob);
|
||||||
|
|
||||||
|
/* variables */
|
||||||
|
BL::BlendData b_data;
|
||||||
|
BL::Scene b_scene;
|
||||||
|
|
||||||
|
id_map<void*, Shader> shader_map;
|
||||||
|
id_map<ObjectKey, Object> object_map;
|
||||||
|
id_map<void*, Mesh> mesh_map;
|
||||||
|
id_map<ObjectKey, Light> light_map;
|
||||||
|
set<Mesh*> mesh_synced;
|
||||||
|
void *world_map;
|
||||||
|
bool world_recalc;
|
||||||
|
|
||||||
|
Scene *scene;
|
||||||
|
bool preview;
|
||||||
|
|
||||||
|
struct RenderLayerInfo {
|
||||||
|
RenderLayerInfo()
|
||||||
|
: scene_layer(0), layer(0),
|
||||||
|
material_override(PointerRNA_NULL)
|
||||||
|
{}
|
||||||
|
|
||||||
|
uint scene_layer;
|
||||||
|
uint layer;
|
||||||
|
BL::Material material_override;
|
||||||
|
} render_layer;
|
||||||
|
};
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* __BLENDER_SYNC_H__ */
|
||||||
|
|
332
intern/cycles/blender/blender_util.h
Normal file
332
intern/cycles/blender/blender_util.h
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BLENDER_UTIL_H__
|
||||||
|
#define __BLENDER_UTIL_H__
|
||||||
|
|
||||||
|
#include "util_map.h"
|
||||||
|
#include "util_path.h"
|
||||||
|
#include "util_set.h"
|
||||||
|
#include "util_transform.h"
|
||||||
|
#include "util_types.h"
|
||||||
|
#include "util_vector.h"
|
||||||
|
|
||||||
|
/* Hacks to hook into Blender API
|
||||||
|
todo: clean this up ... */
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
struct RenderEngine;
|
||||||
|
struct RenderResult;
|
||||||
|
|
||||||
|
ID *rna_Object_to_mesh(void *_self, void *reports, void *scene, int apply_modifiers, int settings);
|
||||||
|
void rna_Main_meshes_remove(void *bmain, void *reports, void *mesh);
|
||||||
|
void rna_Object_create_duplilist(void *ob, void *reports, void *sce);
|
||||||
|
void rna_Object_free_duplilist(void *ob, void *reports);
|
||||||
|
void rna_RenderLayer_rect_set(PointerRNA *ptr, const float *values);
|
||||||
|
void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values);
|
||||||
|
struct RenderResult *RE_engine_begin_result(struct RenderEngine *engine, int x, int y, int w, int h);
|
||||||
|
void RE_engine_update_result(struct RenderEngine *engine, struct RenderResult *result);
|
||||||
|
void RE_engine_end_result(struct RenderEngine *engine, struct RenderResult *result);
|
||||||
|
int RE_engine_test_break(struct RenderEngine *engine);
|
||||||
|
void RE_engine_update_stats(struct RenderEngine *engine, const char *stats, const char *info);
|
||||||
|
void RE_engine_update_progress(struct RenderEngine *engine, float progress);
|
||||||
|
void engine_tag_redraw(void *engine);
|
||||||
|
void engine_tag_update(void *engine);
|
||||||
|
int rna_Object_is_modified(void *ob, void *scene, int settings);
|
||||||
|
void BLI_timestr(double _time, char *str);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
static inline BL::Mesh object_to_mesh(BL::Object self, BL::Scene scene, bool apply_modifiers, bool render)
|
||||||
|
{
|
||||||
|
ID *data = rna_Object_to_mesh(self.ptr.data, NULL, scene.ptr.data, apply_modifiers, (render)? 2: 1);
|
||||||
|
PointerRNA ptr;
|
||||||
|
RNA_id_pointer_create(data, &ptr);
|
||||||
|
return BL::Mesh(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void object_remove_mesh(BL::BlendData data, BL::Mesh mesh)
|
||||||
|
{
|
||||||
|
rna_Main_meshes_remove(data.ptr.data, NULL, mesh.ptr.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void object_create_duplilist(BL::Object self, BL::Scene scene)
|
||||||
|
{
|
||||||
|
rna_Object_create_duplilist(self.ptr.data, NULL, scene.ptr.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void object_free_duplilist(BL::Object self)
|
||||||
|
{
|
||||||
|
rna_Object_free_duplilist(self.ptr.data, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool object_is_modified(BL::Object self, BL::Scene scene, bool preview)
|
||||||
|
{
|
||||||
|
return rna_Object_is_modified(self.ptr.data, scene.ptr.data, (preview)? (1<<0): (1<<1))? true: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Utilities */
|
||||||
|
|
||||||
|
static inline Transform get_transform(BL::Array<float, 16> array)
|
||||||
|
{
|
||||||
|
Transform tfm;
|
||||||
|
|
||||||
|
/* we assume both types to be just 16 floats, and transpose because blender
|
||||||
|
use column major matrix order while we use row major */
|
||||||
|
memcpy(&tfm, &array, sizeof(float)*16);
|
||||||
|
tfm = transform_transpose(tfm);
|
||||||
|
|
||||||
|
return tfm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float2 get_float2(BL::Array<float, 2> array)
|
||||||
|
{
|
||||||
|
return make_float2(array[0], array[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float3 get_float3(BL::Array<float, 2> array)
|
||||||
|
{
|
||||||
|
return make_float3(array[0], array[1], 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float3 get_float3(BL::Array<float, 3> array)
|
||||||
|
{
|
||||||
|
return make_float3(array[0], array[1], array[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float3 get_float3(BL::Array<float, 4> array)
|
||||||
|
{
|
||||||
|
return make_float3(array[0], array[1], array[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int4 get_int4(BL::Array<int, 4> array)
|
||||||
|
{
|
||||||
|
return make_int4(array[0], array[1], array[2], array[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint get_layer(BL::Array<int, 20> array)
|
||||||
|
{
|
||||||
|
uint layer = 0;
|
||||||
|
|
||||||
|
for(uint i = 0; i < 20; i++)
|
||||||
|
if(array[i])
|
||||||
|
layer |= (1 << i);
|
||||||
|
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*static inline float3 get_float3(PointerRNA& ptr, const char *name)
|
||||||
|
{
|
||||||
|
float3 f;
|
||||||
|
RNA_float_get_array(&ptr, name, &f.x);
|
||||||
|
return f;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
static inline bool get_boolean(PointerRNA& ptr, const char *name)
|
||||||
|
{
|
||||||
|
return RNA_boolean_get(&ptr, name)? true: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float get_float(PointerRNA& ptr, const char *name)
|
||||||
|
{
|
||||||
|
return RNA_float_get(&ptr, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int get_int(PointerRNA& ptr, const char *name)
|
||||||
|
{
|
||||||
|
return RNA_int_get(&ptr, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int get_enum(PointerRNA& ptr, const char *name)
|
||||||
|
{
|
||||||
|
return RNA_enum_get(&ptr, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline string get_enum_identifier(PointerRNA& ptr, const char *name)
|
||||||
|
{
|
||||||
|
PropertyRNA *prop = RNA_struct_find_property(&ptr, name);
|
||||||
|
const char *identifier = "";
|
||||||
|
int value = RNA_property_enum_get(&ptr, prop);
|
||||||
|
|
||||||
|
RNA_property_enum_identifier(NULL, &ptr, prop, value, &identifier);
|
||||||
|
|
||||||
|
return string(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Relative Paths */
|
||||||
|
|
||||||
|
static inline string blender_absolute_path(BL::BlendData b_data, BL::ID b_id, const string& path)
|
||||||
|
{
|
||||||
|
if(path.size() >= 2 && path[0] == '/' && path[1] == '/') {
|
||||||
|
string dirname = (b_id.library())? b_id.library().filepath(): b_data.filepath();
|
||||||
|
return path_join(path_dirname(dirname), path.substr(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ID Map
|
||||||
|
*
|
||||||
|
* Utility class to keep in sync with blender data.
|
||||||
|
* Used for objects, meshes, lights and shaders. */
|
||||||
|
|
||||||
|
template<typename K, typename T>
|
||||||
|
class id_map {
|
||||||
|
public:
|
||||||
|
id_map(vector<T*> *scene_data_)
|
||||||
|
{
|
||||||
|
scene_data = scene_data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
T *find(BL::ID id)
|
||||||
|
{
|
||||||
|
return find(id.ptr.id.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
T *find(const K& key)
|
||||||
|
{
|
||||||
|
if(b_map.find(key) != b_map.end()) {
|
||||||
|
T *data = b_map[key];
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_recalc(BL::ID id)
|
||||||
|
{
|
||||||
|
b_recalc.insert(id.ptr.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_recalc()
|
||||||
|
{
|
||||||
|
return !(b_recalc.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
void pre_sync()
|
||||||
|
{
|
||||||
|
used_set.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sync(T **r_data, BL::ID id)
|
||||||
|
{
|
||||||
|
return sync(r_data, id, id, id.ptr.id.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sync(T **r_data, BL::ID id, BL::ID parent, const K& key)
|
||||||
|
{
|
||||||
|
T *data = find(key);
|
||||||
|
bool recalc;
|
||||||
|
|
||||||
|
if(!data) {
|
||||||
|
/* add data if it didn't exist yet */
|
||||||
|
data = new T();
|
||||||
|
scene_data->push_back(data);
|
||||||
|
b_map[key] = data;
|
||||||
|
recalc = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
recalc = (b_recalc.find(id.ptr.data) != b_recalc.end());
|
||||||
|
if(parent.ptr.data)
|
||||||
|
recalc = recalc || (b_recalc.find(parent.ptr.data) != b_recalc.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
used(data);
|
||||||
|
|
||||||
|
*r_data = data;
|
||||||
|
return recalc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void used(T *data)
|
||||||
|
{
|
||||||
|
/* tag data as still in use */
|
||||||
|
used_set.insert(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_default(T *data)
|
||||||
|
{
|
||||||
|
b_map[NULL] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool post_sync(bool do_delete = true)
|
||||||
|
{
|
||||||
|
/* remove unused data */
|
||||||
|
vector<T*> new_scene_data;
|
||||||
|
typename vector<T*>::iterator it;
|
||||||
|
bool deleted = false;
|
||||||
|
|
||||||
|
for(it = scene_data->begin(); it != scene_data->end(); it++) {
|
||||||
|
T *data = *it;
|
||||||
|
|
||||||
|
if(do_delete && used_set.find(data) == used_set.end()) {
|
||||||
|
delete data;
|
||||||
|
deleted = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
new_scene_data.push_back(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
*scene_data = new_scene_data;
|
||||||
|
|
||||||
|
/* update mapping */
|
||||||
|
map<K, T*> new_map;
|
||||||
|
typedef pair<const K, T*> TMapPair;
|
||||||
|
typename map<K, T*>::iterator jt;
|
||||||
|
|
||||||
|
for(jt = b_map.begin(); jt != b_map.end(); jt++) {
|
||||||
|
TMapPair& pair = *jt;
|
||||||
|
|
||||||
|
if(used_set.find(pair.second) != used_set.end())
|
||||||
|
new_map[pair.first] = pair.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
used_set.clear();
|
||||||
|
b_recalc.clear();
|
||||||
|
b_map = new_map;
|
||||||
|
|
||||||
|
return deleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
vector<T*> *scene_data;
|
||||||
|
map<K, T*> b_map;
|
||||||
|
set<T*> used_set;
|
||||||
|
set<void*> b_recalc;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Object Key */
|
||||||
|
|
||||||
|
struct ObjectKey {
|
||||||
|
void *parent;
|
||||||
|
int index;
|
||||||
|
void *ob;
|
||||||
|
|
||||||
|
ObjectKey(void *parent_, int index_, void *ob_)
|
||||||
|
: parent(parent_), index(index_), ob(ob_) {}
|
||||||
|
|
||||||
|
bool operator<(const ObjectKey& k) const
|
||||||
|
{ return (parent < k.parent || (parent == k.parent && (index < k.index || (index == k.index && ob < k.ob)))); }
|
||||||
|
};
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* __BLENDER_UTIL_H__ */
|
||||||
|
|
28
intern/cycles/bvh/CMakeLists.txt
Normal file
28
intern/cycles/bvh/CMakeLists.txt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
set(INC
|
||||||
|
.
|
||||||
|
../kernel
|
||||||
|
../kernel/svm
|
||||||
|
../render
|
||||||
|
../util
|
||||||
|
../device
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SRC
|
||||||
|
bvh.cpp
|
||||||
|
bvh_build.cpp
|
||||||
|
bvh_node.cpp
|
||||||
|
bvh_sort.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SRC_HEADERS
|
||||||
|
bvh.h
|
||||||
|
bvh_build.h
|
||||||
|
bvh_node.h
|
||||||
|
bvh_params.h
|
||||||
|
bvh_sort.h
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(${INC})
|
||||||
|
|
||||||
|
add_library(cycles_bvh ${SRC} ${SRC_HEADERS})
|
701
intern/cycles/bvh/bvh.cpp
Normal file
701
intern/cycles/bvh/bvh.cpp
Normal file
@ -0,0 +1,701 @@
|
|||||||
|
/*
|
||||||
|
* Adapted from code copyright 2009-2010 NVIDIA Corporation
|
||||||
|
* Modifications Copyright 2011, 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 "mesh.h"
|
||||||
|
#include "object.h"
|
||||||
|
#include "scene.h"
|
||||||
|
|
||||||
|
#include "bvh.h"
|
||||||
|
#include "bvh_build.h"
|
||||||
|
#include "bvh_node.h"
|
||||||
|
#include "bvh_params.h"
|
||||||
|
|
||||||
|
#include "util_cache.h"
|
||||||
|
#include "util_debug.h"
|
||||||
|
#include "util_foreach.h"
|
||||||
|
#include "util_map.h"
|
||||||
|
#include "util_progress.h"
|
||||||
|
#include "util_types.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* Pack Utility */
|
||||||
|
|
||||||
|
struct BVHStackEntry
|
||||||
|
{
|
||||||
|
const BVHNode *node;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
BVHStackEntry(const BVHNode* n = 0, int i = 0)
|
||||||
|
: node(n), idx(i)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int encodeIdx() const
|
||||||
|
{
|
||||||
|
return (node->is_leaf())? ~idx: idx;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* BVH */
|
||||||
|
|
||||||
|
BVH::BVH(const BVHParams& params_, const vector<Object*>& objects_)
|
||||||
|
: params(params_), objects(objects_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
BVH *BVH::create(const BVHParams& params, const vector<Object*>& objects)
|
||||||
|
{
|
||||||
|
if(params.use_qbvh)
|
||||||
|
return new QBVH(params, objects);
|
||||||
|
else
|
||||||
|
return new RegularBVH(params, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cache */
|
||||||
|
|
||||||
|
bool BVH::cache_read(CacheData& key)
|
||||||
|
{
|
||||||
|
key.add(¶ms, sizeof(params));
|
||||||
|
|
||||||
|
foreach(Object *ob, objects) {
|
||||||
|
key.add(ob->mesh->verts);
|
||||||
|
key.add(ob->mesh->triangles);
|
||||||
|
}
|
||||||
|
|
||||||
|
CacheData value;
|
||||||
|
|
||||||
|
if(Cache::global.lookup(key, value)) {
|
||||||
|
value.read(pack.root_index);
|
||||||
|
|
||||||
|
value.read(pack.nodes);
|
||||||
|
value.read(pack.object_node);
|
||||||
|
value.read(pack.tri_woop);
|
||||||
|
value.read(pack.prim_visibility);
|
||||||
|
value.read(pack.prim_index);
|
||||||
|
value.read(pack.prim_object);
|
||||||
|
value.read(pack.is_leaf);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BVH::cache_write(CacheData& key)
|
||||||
|
{
|
||||||
|
CacheData value;
|
||||||
|
|
||||||
|
value.add(pack.root_index);
|
||||||
|
|
||||||
|
value.add(pack.nodes);
|
||||||
|
value.add(pack.object_node);
|
||||||
|
value.add(pack.tri_woop);
|
||||||
|
value.add(pack.prim_visibility);
|
||||||
|
value.add(pack.prim_index);
|
||||||
|
value.add(pack.prim_object);
|
||||||
|
value.add(pack.is_leaf);
|
||||||
|
|
||||||
|
Cache::global.insert(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Building */
|
||||||
|
|
||||||
|
void BVH::build(Progress& progress)
|
||||||
|
{
|
||||||
|
progress.set_substatus("Building BVH");
|
||||||
|
|
||||||
|
/* cache read */
|
||||||
|
CacheData key("bvh");
|
||||||
|
|
||||||
|
if(params.use_cache) {
|
||||||
|
progress.set_substatus("Looking in BVH cache");
|
||||||
|
|
||||||
|
if(cache_read(key))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* build nodes */
|
||||||
|
vector<int> prim_index;
|
||||||
|
vector<int> prim_object;
|
||||||
|
|
||||||
|
BVHBuild bvh_build(objects, prim_index, prim_object, params, progress);
|
||||||
|
BVHNode *root = bvh_build.run();
|
||||||
|
|
||||||
|
if(progress.get_cancel()) {
|
||||||
|
if(root) root->deleteSubtree();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* todo: get rid of this copy */
|
||||||
|
pack.prim_index = prim_index;
|
||||||
|
pack.prim_object = prim_object;
|
||||||
|
|
||||||
|
/* compute SAH */
|
||||||
|
if(!params.top_level)
|
||||||
|
pack.SAH = root->computeSubtreeSAHCost(params);
|
||||||
|
|
||||||
|
if(progress.get_cancel()) {
|
||||||
|
root->deleteSubtree();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pack triangles */
|
||||||
|
progress.set_substatus("Packing BVH triangles");
|
||||||
|
pack_triangles();
|
||||||
|
|
||||||
|
if(progress.get_cancel()) {
|
||||||
|
root->deleteSubtree();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pack nodes */
|
||||||
|
progress.set_substatus("Packing BVH nodes");
|
||||||
|
array<int> tmp_prim_object = pack.prim_object;
|
||||||
|
pack_nodes(tmp_prim_object, root);
|
||||||
|
|
||||||
|
/* free build nodes */
|
||||||
|
root->deleteSubtree();
|
||||||
|
|
||||||
|
if(progress.get_cancel()) return;
|
||||||
|
|
||||||
|
/* cache write */
|
||||||
|
if(params.use_cache) {
|
||||||
|
progress.set_substatus("Writing BVH cache");
|
||||||
|
cache_write(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Refitting */
|
||||||
|
|
||||||
|
void BVH::refit(Progress& progress)
|
||||||
|
{
|
||||||
|
progress.set_substatus("Packing BVH triangles");
|
||||||
|
pack_triangles();
|
||||||
|
|
||||||
|
if(progress.get_cancel()) return;
|
||||||
|
|
||||||
|
progress.set_substatus("Refitting BVH nodes");
|
||||||
|
refit_nodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Triangles */
|
||||||
|
|
||||||
|
void BVH::pack_triangle(int idx, float4 woop[3])
|
||||||
|
{
|
||||||
|
/* create Woop triangle */
|
||||||
|
int tob = pack.prim_object[idx];
|
||||||
|
const Mesh *mesh = objects[tob]->mesh;
|
||||||
|
int tidx = pack.prim_index[idx];
|
||||||
|
const int *vidx = mesh->triangles[tidx].v;
|
||||||
|
const float3* vpos = &mesh->verts[0];
|
||||||
|
float3 v0 = vpos[vidx[0]];
|
||||||
|
float3 v1 = vpos[vidx[1]];
|
||||||
|
float3 v2 = vpos[vidx[2]];
|
||||||
|
|
||||||
|
float3 r0 = v0 - v2;
|
||||||
|
float3 r1 = v1 - v2;
|
||||||
|
float3 r2 = cross(r0, r1);
|
||||||
|
|
||||||
|
if(dot(r0, r0) == 0.0f || dot(r1, r1) == 0.0f || dot(r2, r2) == 0.0f) {
|
||||||
|
/* degenerate */
|
||||||
|
woop[0] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
woop[1] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
woop[2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Transform t = make_transform(
|
||||||
|
r0.x, r1.x, r2.x, v2.x,
|
||||||
|
r0.y, r1.y, r2.y, v2.y,
|
||||||
|
r0.z, r1.z, r2.z, v2.z,
|
||||||
|
0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
t = transform_inverse(t);
|
||||||
|
|
||||||
|
woop[0] = make_float4(t.z.x, t.z.y, t.z.z, -t.z.w);
|
||||||
|
woop[1] = make_float4(t.x.x, t.x.y, t.x.z, t.x.w);
|
||||||
|
woop[2] = make_float4(t.y.x, t.y.y, t.y.z, t.y.w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BVH::pack_triangles()
|
||||||
|
{
|
||||||
|
int nsize = TRI_NODE_SIZE;
|
||||||
|
size_t tidx_size = pack.prim_index.size();
|
||||||
|
|
||||||
|
pack.tri_woop.clear();
|
||||||
|
pack.tri_woop.resize(tidx_size * nsize);
|
||||||
|
pack.prim_visibility.clear();
|
||||||
|
pack.prim_visibility.resize(tidx_size);
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < tidx_size; i++) {
|
||||||
|
if(pack.prim_index[i] != -1) {
|
||||||
|
float4 woop[3];
|
||||||
|
|
||||||
|
pack_triangle(i, woop);
|
||||||
|
memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3);
|
||||||
|
|
||||||
|
int tob = pack.prim_object[i];
|
||||||
|
Object *ob = objects[tob];
|
||||||
|
pack.prim_visibility[i] = ob->visibility;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pack Instances */
|
||||||
|
|
||||||
|
void BVH::pack_instances(size_t nodes_size)
|
||||||
|
{
|
||||||
|
/* The BVH's for instances are built separately, but for traversal all
|
||||||
|
BVH's are stored in global arrays. This function merges them into the
|
||||||
|
top level BVH, adjusting indexes and offsets where appropriate. */
|
||||||
|
bool use_qbvh = params.use_qbvh;
|
||||||
|
size_t nsize = (use_qbvh)? BVH_QNODE_SIZE: BVH_NODE_SIZE;
|
||||||
|
|
||||||
|
/* adjust primitive index to point to the triangle in the global array, for
|
||||||
|
meshes with transform applied and already in the top level BVH */
|
||||||
|
for(size_t i = 0; i < pack.prim_index.size(); i++)
|
||||||
|
if(pack.prim_index[i] != -1)
|
||||||
|
pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset;
|
||||||
|
|
||||||
|
/* track offsets of instanced BVH data in global array */
|
||||||
|
size_t tri_offset = pack.prim_index.size();
|
||||||
|
size_t nodes_offset = nodes_size;
|
||||||
|
|
||||||
|
/* clear array that gives the node indexes for instanced objects */
|
||||||
|
pack.object_node.clear();
|
||||||
|
|
||||||
|
/* reserve */
|
||||||
|
size_t prim_index_size = pack.prim_index.size();
|
||||||
|
size_t tri_woop_size = pack.tri_woop.size();
|
||||||
|
|
||||||
|
size_t pack_prim_index_offset = prim_index_size;
|
||||||
|
size_t pack_tri_woop_offset = tri_woop_size;
|
||||||
|
size_t pack_nodes_offset = nodes_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->transform_applied) {
|
||||||
|
if(mesh_map.find(mesh) == mesh_map.end()) {
|
||||||
|
prim_index_size += bvh->pack.prim_index.size();
|
||||||
|
tri_woop_size += bvh->pack.tri_woop.size();
|
||||||
|
nodes_size += bvh->pack.nodes.size()*nsize;
|
||||||
|
|
||||||
|
mesh_map[mesh] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh_map.clear();
|
||||||
|
|
||||||
|
pack.prim_index.resize(prim_index_size);
|
||||||
|
pack.prim_object.resize(prim_index_size);
|
||||||
|
pack.prim_visibility.resize(prim_index_size);
|
||||||
|
pack.tri_woop.resize(tri_woop_size);
|
||||||
|
pack.nodes.resize(nodes_size);
|
||||||
|
pack.object_node.resize(objects.size());
|
||||||
|
|
||||||
|
int *pack_prim_index = (pack.prim_index.size())? &pack.prim_index[0]: NULL;
|
||||||
|
int *pack_prim_object = (pack.prim_object.size())? &pack.prim_object[0]: NULL;
|
||||||
|
uint *pack_prim_visibility = (pack.prim_visibility.size())? &pack.prim_visibility[0]: NULL;
|
||||||
|
float4 *pack_tri_woop = (pack.tri_woop.size())? &pack.tri_woop[0]: NULL;
|
||||||
|
int4 *pack_nodes = (pack.nodes.size())? &pack.nodes[0]: NULL;
|
||||||
|
|
||||||
|
/* merge */
|
||||||
|
foreach(Object *ob, objects) {
|
||||||
|
Mesh *mesh = ob->mesh;
|
||||||
|
|
||||||
|
/* if mesh transform is applied, that means it's already in the top
|
||||||
|
level BVH, and we don't need to merge it in */
|
||||||
|
if(mesh->transform_applied) {
|
||||||
|
pack.object_node[object_offset++] = 0;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
BVH *bvh = mesh->bvh;
|
||||||
|
|
||||||
|
int noffset = nodes_offset/nsize;
|
||||||
|
int mesh_tri_offset = mesh->tri_offset;
|
||||||
|
|
||||||
|
/* fill in node indexes for instances */
|
||||||
|
if(bvh->pack.is_leaf[0])
|
||||||
|
pack.object_node[object_offset++] = -noffset-1;
|
||||||
|
else
|
||||||
|
pack.object_node[object_offset++] = noffset;
|
||||||
|
|
||||||
|
mesh_map[mesh] = pack.object_node[object_offset-1];
|
||||||
|
|
||||||
|
/* merge primitive and object 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];
|
||||||
|
uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0];
|
||||||
|
|
||||||
|
for(size_t i = 0; i < bvh_prim_index_size; i++) {
|
||||||
|
pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
|
||||||
|
pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i];
|
||||||
|
pack_prim_object[pack_prim_index_offset] = 0; // unused for instances
|
||||||
|
pack_prim_index_offset++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* merge triangle intersection data */
|
||||||
|
if(bvh->pack.tri_woop.size()) {
|
||||||
|
memcpy(pack_tri_woop+pack_tri_woop_offset, &bvh->pack.tri_woop[0],
|
||||||
|
bvh->pack.tri_woop.size()*sizeof(float4));
|
||||||
|
pack_tri_woop_offset += bvh->pack.tri_woop.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* merge nodes */
|
||||||
|
if( bvh->pack.nodes.size()) {
|
||||||
|
size_t nsize_bbox = (use_qbvh)? nsize-2: nsize-1;
|
||||||
|
int4 *bvh_nodes = &bvh->pack.nodes[0];
|
||||||
|
size_t bvh_nodes_size = bvh->pack.nodes.size();
|
||||||
|
int *bvh_is_leaf = &bvh->pack.is_leaf[0];
|
||||||
|
|
||||||
|
for(size_t i = 0, j = 0; i < bvh_nodes_size; i+=nsize, j++) {
|
||||||
|
memcpy(pack_nodes + pack_nodes_offset, bvh_nodes + i, nsize_bbox*sizeof(int4));
|
||||||
|
|
||||||
|
/* modify offsets into arrays */
|
||||||
|
int4 data = bvh_nodes[i + nsize_bbox];
|
||||||
|
|
||||||
|
if(bvh_is_leaf[j]) {
|
||||||
|
data.x += tri_offset;
|
||||||
|
data.y += tri_offset;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data.x += (data.x < 0)? -noffset: noffset;
|
||||||
|
data.y += (data.y < 0)? -noffset: noffset;
|
||||||
|
|
||||||
|
if(use_qbvh) {
|
||||||
|
data.z += (data.z < 0)? -noffset: noffset;
|
||||||
|
data.w += (data.w < 0)? -noffset: noffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pack_nodes[pack_nodes_offset + nsize_bbox] = data;
|
||||||
|
|
||||||
|
if(use_qbvh)
|
||||||
|
pack_nodes[pack_nodes_offset + nsize_bbox+1] = bvh_nodes[i + nsize_bbox+1];
|
||||||
|
|
||||||
|
pack_nodes_offset += nsize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes_offset += bvh->pack.nodes.size();
|
||||||
|
tri_offset += bvh->pack.prim_index.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Regular BVH */
|
||||||
|
|
||||||
|
RegularBVH::RegularBVH(const BVHParams& params_, const vector<Object*>& objects_)
|
||||||
|
: BVH(params_, objects_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegularBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
|
||||||
|
{
|
||||||
|
if(leaf->num_triangles() == 1 && pack.prim_index[leaf->m_lo] == -1)
|
||||||
|
/* object */
|
||||||
|
pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, ~(leaf->m_lo), 0, leaf->m_visibility, leaf->m_visibility);
|
||||||
|
else
|
||||||
|
/* triangle */
|
||||||
|
pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, leaf->m_lo, leaf->m_hi, leaf->m_visibility, leaf->m_visibility);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegularBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1)
|
||||||
|
{
|
||||||
|
pack_node(e.idx, e0.node->m_bounds, e1.node->m_bounds, e0.encodeIdx(), e1.encodeIdx(), e0.node->m_visibility, e1.node->m_visibility);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegularBVH::pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1, uint visibility0, uint visibility1)
|
||||||
|
{
|
||||||
|
int4 data[BVH_NODE_SIZE] =
|
||||||
|
{
|
||||||
|
make_int4(__float_as_int(b0.min.x), __float_as_int(b0.max.x), __float_as_int(b0.min.y), __float_as_int(b0.max.y)),
|
||||||
|
make_int4(__float_as_int(b1.min.x), __float_as_int(b1.max.x), __float_as_int(b1.min.y), __float_as_int(b1.max.y)),
|
||||||
|
make_int4(__float_as_int(b0.min.z), __float_as_int(b0.max.z), __float_as_int(b1.min.z), __float_as_int(b1.max.z)),
|
||||||
|
make_int4(c0, c1, visibility0, visibility1)
|
||||||
|
};
|
||||||
|
|
||||||
|
memcpy(&pack.nodes[idx * BVH_NODE_SIZE], data, sizeof(int4)*BVH_NODE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegularBVH::pack_nodes(const array<int>& prims, const BVHNode *root)
|
||||||
|
{
|
||||||
|
size_t node_size = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
|
||||||
|
|
||||||
|
/* resize arrays */
|
||||||
|
pack.nodes.clear();
|
||||||
|
pack.is_leaf.clear();
|
||||||
|
pack.is_leaf.resize(node_size);
|
||||||
|
|
||||||
|
/* for top level BVH, first merge existing BVH's so we know the offsets */
|
||||||
|
if(params.top_level)
|
||||||
|
pack_instances(node_size*BVH_NODE_SIZE);
|
||||||
|
else
|
||||||
|
pack.nodes.resize(node_size*BVH_NODE_SIZE);
|
||||||
|
|
||||||
|
int nextNodeIdx = 0;
|
||||||
|
|
||||||
|
vector<BVHStackEntry> stack;
|
||||||
|
stack.push_back(BVHStackEntry(root, nextNodeIdx++));
|
||||||
|
|
||||||
|
while(stack.size()) {
|
||||||
|
BVHStackEntry e = stack.back();
|
||||||
|
stack.pop_back();
|
||||||
|
|
||||||
|
pack.is_leaf[e.idx] = e.node->is_leaf();
|
||||||
|
|
||||||
|
if(e.node->is_leaf()) {
|
||||||
|
/* leaf node */
|
||||||
|
const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node);
|
||||||
|
pack_leaf(e, leaf);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* innner node */
|
||||||
|
stack.push_back(BVHStackEntry(e.node->get_child(0), nextNodeIdx++));
|
||||||
|
stack.push_back(BVHStackEntry(e.node->get_child(1), nextNodeIdx++));
|
||||||
|
|
||||||
|
pack_inner(e, stack[stack.size()-2], stack[stack.size()-1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* root index to start traversal at, to handle case of single leaf node */
|
||||||
|
pack.root_index = (pack.is_leaf[0])? -1: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegularBVH::refit_nodes()
|
||||||
|
{
|
||||||
|
assert(!params.top_level);
|
||||||
|
|
||||||
|
BoundBox bbox;
|
||||||
|
uint visibility = 0;
|
||||||
|
refit_node(0, (pack.is_leaf[0])? true: false, bbox, visibility);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
|
||||||
|
{
|
||||||
|
int4 *data = &pack.nodes[idx*4];
|
||||||
|
|
||||||
|
int c0 = data[3].x;
|
||||||
|
int c1 = data[3].y;
|
||||||
|
|
||||||
|
if(leaf) {
|
||||||
|
/* refit leaf node */
|
||||||
|
for(int tri = c0; tri < c1; tri++) {
|
||||||
|
int tidx = pack.prim_index[tri];
|
||||||
|
int tob = pack.prim_object[tri];
|
||||||
|
Object *ob = objects[tob];
|
||||||
|
|
||||||
|
if(tidx == -1) {
|
||||||
|
/* object instance */
|
||||||
|
bbox.grow(ob->bounds);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* triangles */
|
||||||
|
const Mesh *mesh = ob->mesh;
|
||||||
|
int tri_offset = (params.top_level)? mesh->tri_offset: 0;
|
||||||
|
const int *vidx = mesh->triangles[tidx - tri_offset].v;
|
||||||
|
const float3 *vpos = &mesh->verts[0];
|
||||||
|
|
||||||
|
bbox.grow(vpos[vidx[0]]);
|
||||||
|
bbox.grow(vpos[vidx[1]]);
|
||||||
|
bbox.grow(vpos[vidx[2]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
visibility |= ob->visibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
pack_node(idx, bbox, bbox, c0, c1, visibility, visibility);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* refit inner node, set bbox from children */
|
||||||
|
BoundBox bbox0, bbox1;
|
||||||
|
uint visibility0 = 0, visibility1 = 0;
|
||||||
|
|
||||||
|
refit_node((c0 < 0)? -c0-1: c0, (c0 < 0), bbox0, visibility0);
|
||||||
|
refit_node((c1 < 0)? -c1-1: c1, (c1 < 0), bbox1, visibility1);
|
||||||
|
|
||||||
|
pack_node(idx, bbox0, bbox1, c0, c1, visibility0, visibility1);
|
||||||
|
|
||||||
|
bbox.grow(bbox0);
|
||||||
|
bbox.grow(bbox1);
|
||||||
|
visibility = visibility0|visibility1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* QBVH */
|
||||||
|
|
||||||
|
QBVH::QBVH(const BVHParams& params_, const vector<Object*>& objects_)
|
||||||
|
: BVH(params_, objects_)
|
||||||
|
{
|
||||||
|
params.use_qbvh = true;
|
||||||
|
|
||||||
|
/* todo: use visibility */
|
||||||
|
}
|
||||||
|
|
||||||
|
void QBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
|
||||||
|
{
|
||||||
|
float4 data[BVH_QNODE_SIZE];
|
||||||
|
|
||||||
|
memset(data, 0, sizeof(data));
|
||||||
|
|
||||||
|
if(leaf->num_triangles() == 1 && pack.prim_index[leaf->m_lo] == -1) {
|
||||||
|
/* object */
|
||||||
|
data[6].x = __int_as_float(~(leaf->m_lo));
|
||||||
|
data[6].y = __int_as_float(0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* triangle */
|
||||||
|
data[6].x = __int_as_float(leaf->m_lo);
|
||||||
|
data[6].y = __int_as_float(leaf->m_hi);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&pack.nodes[e.idx * BVH_QNODE_SIZE], data, sizeof(float4)*BVH_QNODE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num)
|
||||||
|
{
|
||||||
|
float4 data[BVH_QNODE_SIZE];
|
||||||
|
|
||||||
|
for(int i = 0; i < num; i++) {
|
||||||
|
float3 bb_min = en[i].node->m_bounds.min;
|
||||||
|
float3 bb_max = en[i].node->m_bounds.max;
|
||||||
|
|
||||||
|
data[0][i] = bb_min.x;
|
||||||
|
data[1][i] = bb_max.x;
|
||||||
|
data[2][i] = bb_min.y;
|
||||||
|
data[3][i] = bb_max.y;
|
||||||
|
data[4][i] = bb_min.z;
|
||||||
|
data[5][i] = bb_max.z;
|
||||||
|
|
||||||
|
data[6][i] = __int_as_float(en[i].encodeIdx());
|
||||||
|
data[7][i] = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = num; i < 4; i++) {
|
||||||
|
data[0][i] = 0.0f;
|
||||||
|
data[1][i] = 0.0f;
|
||||||
|
data[2][i] = 0.0f;
|
||||||
|
|
||||||
|
data[3][i] = 0.0f;
|
||||||
|
data[4][i] = 0.0f;
|
||||||
|
data[5][i] = 0.0f;
|
||||||
|
|
||||||
|
data[6][i] = __int_as_float(0);
|
||||||
|
data[7][i] = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&pack.nodes[e.idx * BVH_QNODE_SIZE], data, sizeof(float4)*BVH_QNODE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quad SIMD Nodes */
|
||||||
|
|
||||||
|
void QBVH::pack_nodes(const array<int>& prims, const BVHNode *root)
|
||||||
|
{
|
||||||
|
size_t node_size = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
|
||||||
|
|
||||||
|
/* resize arrays */
|
||||||
|
pack.nodes.clear();
|
||||||
|
pack.is_leaf.clear();
|
||||||
|
pack.is_leaf.resize(node_size);
|
||||||
|
|
||||||
|
/* for top level BVH, first merge existing BVH's so we know the offsets */
|
||||||
|
if(params.top_level)
|
||||||
|
pack_instances(node_size*BVH_QNODE_SIZE);
|
||||||
|
else
|
||||||
|
pack.nodes.resize(node_size*BVH_QNODE_SIZE);
|
||||||
|
|
||||||
|
int nextNodeIdx = 0;
|
||||||
|
|
||||||
|
vector<BVHStackEntry> stack;
|
||||||
|
stack.push_back(BVHStackEntry(root, nextNodeIdx++));
|
||||||
|
|
||||||
|
while(stack.size()) {
|
||||||
|
BVHStackEntry e = stack.back();
|
||||||
|
stack.pop_back();
|
||||||
|
|
||||||
|
pack.is_leaf[e.idx] = e.node->is_leaf();
|
||||||
|
|
||||||
|
if(e.node->is_leaf()) {
|
||||||
|
/* leaf node */
|
||||||
|
const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node);
|
||||||
|
pack_leaf(e, leaf);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* inner node */
|
||||||
|
const BVHNode *node = e.node;
|
||||||
|
const BVHNode *node0 = node->get_child(0);
|
||||||
|
const BVHNode *node1 = node->get_child(1);
|
||||||
|
|
||||||
|
/* collect nodes */
|
||||||
|
const BVHNode *nodes[4];
|
||||||
|
int numnodes = 0;
|
||||||
|
|
||||||
|
if(node0->is_leaf()) {
|
||||||
|
nodes[numnodes++] = node0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nodes[numnodes++] = node0->get_child(0);
|
||||||
|
nodes[numnodes++] = node0->get_child(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node1->is_leaf()) {
|
||||||
|
nodes[numnodes++] = node1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nodes[numnodes++] = node1->get_child(0);
|
||||||
|
nodes[numnodes++] = node1->get_child(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* push entries on the stack */
|
||||||
|
for(int i = 0; i < numnodes; i++)
|
||||||
|
stack.push_back(BVHStackEntry(nodes[i], nextNodeIdx++));
|
||||||
|
|
||||||
|
/* set node */
|
||||||
|
pack_inner(e, &stack[stack.size()-numnodes], numnodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* root index to start traversal at, to handle case of single leaf node */
|
||||||
|
pack.root_index = (pack.is_leaf[0])? -1: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QBVH::refit_nodes()
|
||||||
|
{
|
||||||
|
assert(0); /* todo */
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
155
intern/cycles/bvh/bvh.h
Normal file
155
intern/cycles/bvh/bvh.h
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* Adapted from code copyright 2009-2010 NVIDIA Corporation
|
||||||
|
* Modifications Copyright 2011, 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_H__
|
||||||
|
#define __BVH_H__
|
||||||
|
|
||||||
|
#include "bvh_params.h"
|
||||||
|
|
||||||
|
#include "util_types.h"
|
||||||
|
#include "util_vector.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class BVHNode;
|
||||||
|
struct BVHStackEntry;
|
||||||
|
class BVHParams;
|
||||||
|
class BoundBox;
|
||||||
|
class CacheData;
|
||||||
|
class LeafNode;
|
||||||
|
class Object;
|
||||||
|
class Progress;
|
||||||
|
|
||||||
|
#define BVH_NODE_SIZE 4
|
||||||
|
#define BVH_QNODE_SIZE 8
|
||||||
|
#define BVH_ALIGN 4096
|
||||||
|
#define TRI_NODE_SIZE 3
|
||||||
|
|
||||||
|
/* Packed BVH
|
||||||
|
*
|
||||||
|
* BVH stored as it will be used for traversal on the rendering device. */
|
||||||
|
|
||||||
|
struct PackedBVH {
|
||||||
|
/* BVH nodes storage, one node is 4x int4, and contains two bounding boxes,
|
||||||
|
and child, triangle or object indexes dependening on the node type */
|
||||||
|
array<int4> nodes;
|
||||||
|
/* object index to BVH node index mapping for instances */
|
||||||
|
array<int> object_node;
|
||||||
|
/* precomputed triangle intersection data, one triangle is 4x float4 */
|
||||||
|
array<float4> tri_woop;
|
||||||
|
/* visibility visibilitys for primitives */
|
||||||
|
array<uint> prim_visibility;
|
||||||
|
/* mapping from BVH primitive index to true primitive index, as primitives
|
||||||
|
may be duplicated due to spatial splits. -1 for instances. */
|
||||||
|
array<int> prim_index;
|
||||||
|
/* mapping from BVH primitive index, to the object id of that primitive. */
|
||||||
|
array<int> prim_object;
|
||||||
|
/* quick array to lookup if a node is a leaf, not used for traversal, only
|
||||||
|
for instance BVH merging */
|
||||||
|
array<int> is_leaf;
|
||||||
|
|
||||||
|
/* index of the root node. */
|
||||||
|
int root_index;
|
||||||
|
|
||||||
|
/* surface area heuristic, for building top level BVH */
|
||||||
|
float SAH;
|
||||||
|
|
||||||
|
PackedBVH()
|
||||||
|
{
|
||||||
|
root_index = 0;
|
||||||
|
SAH = 0.0f;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* BVH */
|
||||||
|
|
||||||
|
class BVH
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PackedBVH pack;
|
||||||
|
BVHParams params;
|
||||||
|
vector<Object*> objects;
|
||||||
|
|
||||||
|
static BVH *create(const BVHParams& params, const vector<Object*>& objects);
|
||||||
|
virtual ~BVH() {}
|
||||||
|
|
||||||
|
void build(Progress& progress);
|
||||||
|
void refit(Progress& progress);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BVH(const BVHParams& params, const vector<Object*>& objects);
|
||||||
|
|
||||||
|
/* cache */
|
||||||
|
bool cache_read(CacheData& key);
|
||||||
|
void cache_write(CacheData& key);
|
||||||
|
|
||||||
|
/* triangles */
|
||||||
|
void pack_triangles();
|
||||||
|
void pack_triangle(int idx, float4 woop[3]);
|
||||||
|
|
||||||
|
/* merge instance BVH's */
|
||||||
|
void pack_instances(size_t nodes_size);
|
||||||
|
|
||||||
|
/* for subclasses to implement */
|
||||||
|
virtual void pack_nodes(const array<int>& prims, const BVHNode *root) = 0;
|
||||||
|
virtual void refit_nodes() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Regular BVH
|
||||||
|
*
|
||||||
|
* Typical BVH with each node having two children. */
|
||||||
|
|
||||||
|
class RegularBVH : public BVH {
|
||||||
|
protected:
|
||||||
|
/* constructor */
|
||||||
|
friend class BVH;
|
||||||
|
RegularBVH(const BVHParams& params, const vector<Object*>& objects);
|
||||||
|
|
||||||
|
/* pack */
|
||||||
|
void pack_nodes(const array<int>& prims, const BVHNode *root);
|
||||||
|
void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf);
|
||||||
|
void pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1);
|
||||||
|
void pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1, uint visibility0, uint visibility1);
|
||||||
|
|
||||||
|
/* refit */
|
||||||
|
void refit_nodes();
|
||||||
|
void refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* QBVH
|
||||||
|
*
|
||||||
|
* Quad BVH, with each node having four children, to use with SIMD instructions. */
|
||||||
|
|
||||||
|
class QBVH : public BVH {
|
||||||
|
protected:
|
||||||
|
/* constructor */
|
||||||
|
friend class BVH;
|
||||||
|
QBVH(const BVHParams& params, const vector<Object*>& objects);
|
||||||
|
|
||||||
|
/* pack */
|
||||||
|
void pack_nodes(const array<int>& prims, const BVHNode *root);
|
||||||
|
void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf);
|
||||||
|
void pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num);
|
||||||
|
|
||||||
|
/* refit */
|
||||||
|
void refit_nodes();
|
||||||
|
};
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* __BVH_H__ */
|
||||||
|
|
549
intern/cycles/bvh/bvh_build.cpp
Normal file
549
intern/cycles/bvh/bvh_build.cpp
Normal file
@ -0,0 +1,549 @@
|
|||||||
|
/*
|
||||||
|
* Adapted from code copyright 2009-2010 NVIDIA Corporation
|
||||||
|
* Modifications Copyright 2011, 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 "bvh_build.h"
|
||||||
|
#include "bvh_node.h"
|
||||||
|
#include "bvh_params.h"
|
||||||
|
#include "bvh_sort.h"
|
||||||
|
|
||||||
|
#include "mesh.h"
|
||||||
|
#include "object.h"
|
||||||
|
#include "scene.h"
|
||||||
|
|
||||||
|
#include "util_algorithm.h"
|
||||||
|
#include "util_foreach.h"
|
||||||
|
#include "util_progress.h"
|
||||||
|
#include "util_time.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* Constructor / Destructor */
|
||||||
|
|
||||||
|
BVHBuild::BVHBuild(const vector<Object*>& objects_,
|
||||||
|
vector<int>& prim_index_, vector<int>& prim_object_,
|
||||||
|
const BVHParams& params_, Progress& progress_)
|
||||||
|
: objects(objects_),
|
||||||
|
prim_index(prim_index_),
|
||||||
|
prim_object(prim_object_),
|
||||||
|
params(params_),
|
||||||
|
progress(progress_),
|
||||||
|
progress_start_time(0.0)
|
||||||
|
{
|
||||||
|
spatial_min_overlap = 0.0f;
|
||||||
|
progress_num_duplicates = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BVHBuild::~BVHBuild()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adding References */
|
||||||
|
|
||||||
|
void BVHBuild::add_reference_mesh(NodeSpec& root, Mesh *mesh, int i)
|
||||||
|
{
|
||||||
|
for(uint j = 0; j < mesh->triangles.size(); j++) {
|
||||||
|
Mesh::Triangle t = mesh->triangles[j];
|
||||||
|
Reference ref;
|
||||||
|
|
||||||
|
ref.prim_index = j;
|
||||||
|
ref.prim_object = i;
|
||||||
|
|
||||||
|
for(int k = 0; k < 3; k++) {
|
||||||
|
float3 pt = mesh->verts[t.v[k]];
|
||||||
|
ref.bounds.grow(pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
references.push_back(ref);
|
||||||
|
root.bounds.grow(ref.bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BVHBuild::add_reference_object(NodeSpec& root, Object *ob, int i)
|
||||||
|
{
|
||||||
|
Reference ref;
|
||||||
|
|
||||||
|
ref.prim_index = -1;
|
||||||
|
ref.prim_object = i;
|
||||||
|
ref.bounds = ob->bounds;
|
||||||
|
|
||||||
|
references.push_back(ref);
|
||||||
|
root.bounds.grow(ref.bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BVHBuild::add_references(NodeSpec& root)
|
||||||
|
{
|
||||||
|
/* init root spec */
|
||||||
|
root.num = 0;
|
||||||
|
root.bounds = BoundBox();
|
||||||
|
|
||||||
|
/* add objects */
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
foreach(Object *ob, objects) {
|
||||||
|
if(params.top_level) {
|
||||||
|
if(ob->mesh->transform_applied)
|
||||||
|
add_reference_mesh(root, ob->mesh, i);
|
||||||
|
else
|
||||||
|
add_reference_object(root, ob, i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
add_reference_mesh(root, ob->mesh, i);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if(progress.get_cancel()) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* happens mostly on empty meshes */
|
||||||
|
if(!root.bounds.valid())
|
||||||
|
root.bounds.grow(make_float3(0.0f, 0.0f, 0.0f));
|
||||||
|
|
||||||
|
root.num = references.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build */
|
||||||
|
|
||||||
|
BVHNode* BVHBuild::run()
|
||||||
|
{
|
||||||
|
NodeSpec root;
|
||||||
|
|
||||||
|
/* add references */
|
||||||
|
add_references(root);
|
||||||
|
|
||||||
|
if(progress.get_cancel()) return NULL;
|
||||||
|
|
||||||
|
/* init spatial splits */
|
||||||
|
if(params.top_level) /* todo: get rid of this */
|
||||||
|
params.use_spatial_split = false;
|
||||||
|
|
||||||
|
spatial_min_overlap = root.bounds.area() * params.spatial_split_alpha;
|
||||||
|
spatial_right_bounds.clear();
|
||||||
|
spatial_right_bounds.resize(max(root.num, (int)BVHParams::NUM_SPATIAL_BINS) - 1);
|
||||||
|
|
||||||
|
/* init progress updates */
|
||||||
|
progress_num_duplicates = 0;
|
||||||
|
progress_start_time = time_dt();
|
||||||
|
|
||||||
|
/* build recursively */
|
||||||
|
return build_node(root, 0, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BVHBuild::progress_update(float progress_start, float progress_end)
|
||||||
|
{
|
||||||
|
if(time_dt() - progress_start_time < 0.25f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float duplicates = (float)progress_num_duplicates/(float)references.size();
|
||||||
|
string msg = string_printf("Building BVH %.0f%%, duplicates %.0f%%",
|
||||||
|
progress_start*100.0f, duplicates*100.0f);
|
||||||
|
|
||||||
|
progress.set_substatus(msg);
|
||||||
|
progress_start_time = time_dt();
|
||||||
|
}
|
||||||
|
|
||||||
|
BVHNode* BVHBuild::build_node(const NodeSpec& spec, int level, float progress_start, float progress_end)
|
||||||
|
{
|
||||||
|
/* progress update */
|
||||||
|
progress_update(progress_start, progress_end);
|
||||||
|
if(progress.get_cancel()) return NULL;
|
||||||
|
|
||||||
|
/* small enough or too deep => create leaf. */
|
||||||
|
if(spec.num <= params.min_leaf_size || level >= BVHParams::MAX_DEPTH)
|
||||||
|
return create_leaf_node(spec);
|
||||||
|
|
||||||
|
/* find split candidates. */
|
||||||
|
float area = spec.bounds.area();
|
||||||
|
float leafSAH = area * params.triangle_cost(spec.num);
|
||||||
|
float nodeSAH = area * params.node_cost(2);
|
||||||
|
ObjectSplit object = find_object_split(spec, nodeSAH);
|
||||||
|
SpatialSplit spatial;
|
||||||
|
|
||||||
|
if(params.use_spatial_split && level < BVHParams::MAX_SPATIAL_DEPTH) {
|
||||||
|
BoundBox overlap = object.left_bounds;
|
||||||
|
overlap.intersect(object.right_bounds);
|
||||||
|
|
||||||
|
if(overlap.area() >= spatial_min_overlap)
|
||||||
|
spatial = find_spatial_split(spec, nodeSAH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* leaf SAH is the lowest => create leaf. */
|
||||||
|
float minSAH = min(min(leafSAH, object.sah), spatial.sah);
|
||||||
|
|
||||||
|
if(minSAH == leafSAH && spec.num <= params.max_leaf_size)
|
||||||
|
return create_leaf_node(spec);
|
||||||
|
|
||||||
|
/* perform split. */
|
||||||
|
NodeSpec left, right;
|
||||||
|
|
||||||
|
if(params.use_spatial_split && minSAH == spatial.sah)
|
||||||
|
do_spatial_split(left, right, spec, spatial);
|
||||||
|
if(!left.num || !right.num)
|
||||||
|
do_object_split(left, right, spec, object);
|
||||||
|
|
||||||
|
/* create inner node. */
|
||||||
|
progress_num_duplicates += left.num + right.num - spec.num;
|
||||||
|
|
||||||
|
float progress_mid = lerp(progress_start, progress_end, (float)right.num / (float)(left.num + right.num));
|
||||||
|
|
||||||
|
BVHNode* rightNode = build_node(right, level + 1, progress_start, progress_mid);
|
||||||
|
if(progress.get_cancel()) {
|
||||||
|
if(rightNode) rightNode->deleteSubtree();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
BVHNode* leftNode = build_node(left, level + 1, progress_mid, progress_end);
|
||||||
|
if(progress.get_cancel()) {
|
||||||
|
if(leftNode) leftNode->deleteSubtree();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new InnerNode(spec.bounds, leftNode, rightNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
BVHNode *BVHBuild::create_object_leaf_nodes(const Reference *ref, int num)
|
||||||
|
{
|
||||||
|
if(num == 0) {
|
||||||
|
BoundBox bounds;
|
||||||
|
return new LeafNode(bounds, 0, 0, 0);
|
||||||
|
}
|
||||||
|
else if(num == 1) {
|
||||||
|
prim_index.push_back(ref[0].prim_index);
|
||||||
|
prim_object.push_back(ref[0].prim_object);
|
||||||
|
uint visibility = objects[ref[0].prim_object]->visibility;
|
||||||
|
return new LeafNode(ref[0].bounds, visibility, prim_index.size()-1, prim_index.size());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int mid = num/2;
|
||||||
|
BVHNode *leaf0 = create_object_leaf_nodes(ref, mid);
|
||||||
|
BVHNode *leaf1 = create_object_leaf_nodes(ref+mid, num-mid);
|
||||||
|
|
||||||
|
BoundBox bounds;
|
||||||
|
bounds.grow(leaf0->m_bounds);
|
||||||
|
bounds.grow(leaf1->m_bounds);
|
||||||
|
|
||||||
|
return new InnerNode(bounds, leaf0, leaf1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BVHNode* BVHBuild::create_leaf_node(const NodeSpec& spec)
|
||||||
|
{
|
||||||
|
vector<int>& p_index = prim_index;
|
||||||
|
vector<int>& p_object = prim_object;
|
||||||
|
BoundBox bounds;
|
||||||
|
int num = 0;
|
||||||
|
uint visibility = 0;
|
||||||
|
|
||||||
|
for(int i = 0; i < spec.num; i++) {
|
||||||
|
if(references.back().prim_index != -1) {
|
||||||
|
p_index.push_back(references.back().prim_index);
|
||||||
|
p_object.push_back(references.back().prim_object);
|
||||||
|
bounds.grow(references.back().bounds);
|
||||||
|
visibility |= objects[references.back().prim_object]->visibility;
|
||||||
|
references.pop_back();
|
||||||
|
num++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BVHNode *leaf = NULL;
|
||||||
|
|
||||||
|
if(num > 0) {
|
||||||
|
leaf = new LeafNode(bounds, visibility, p_index.size() - num, p_index.size());
|
||||||
|
|
||||||
|
if(num == spec.num)
|
||||||
|
return leaf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* while there may be multiple triangles in a leaf, for object primitives
|
||||||
|
* we want them to be the only one, so we */
|
||||||
|
int ob_num = spec.num - num;
|
||||||
|
const Reference *ref = (ob_num)? &references.back() - (ob_num - 1): NULL;
|
||||||
|
BVHNode *oleaf = create_object_leaf_nodes(ref, ob_num);
|
||||||
|
for(int i = 0; i < ob_num; i++)
|
||||||
|
references.pop_back();
|
||||||
|
|
||||||
|
if(leaf)
|
||||||
|
return new InnerNode(spec.bounds, leaf, oleaf);
|
||||||
|
else
|
||||||
|
return oleaf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Object Split */
|
||||||
|
|
||||||
|
BVHBuild::ObjectSplit BVHBuild::find_object_split(const NodeSpec& spec, float nodeSAH)
|
||||||
|
{
|
||||||
|
ObjectSplit split;
|
||||||
|
const Reference *ref_ptr = &references[references.size() - spec.num];
|
||||||
|
|
||||||
|
for(int dim = 0; dim < 3; dim++) {
|
||||||
|
/* sort references */
|
||||||
|
bvh_reference_sort(references.size() - spec.num, references.size(), &references[0], dim);
|
||||||
|
|
||||||
|
/* sweep right to left and determine bounds. */
|
||||||
|
BoundBox right_bounds;
|
||||||
|
|
||||||
|
for(int i = spec.num - 1; i > 0; i--) {
|
||||||
|
right_bounds.grow(ref_ptr[i].bounds);
|
||||||
|
spatial_right_bounds[i - 1] = right_bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sweep left to right and select lowest SAH. */
|
||||||
|
BoundBox left_bounds;
|
||||||
|
|
||||||
|
for(int i = 1; i < spec.num; i++) {
|
||||||
|
left_bounds.grow(ref_ptr[i - 1].bounds);
|
||||||
|
right_bounds = spatial_right_bounds[i - 1];
|
||||||
|
|
||||||
|
float sah = nodeSAH +
|
||||||
|
left_bounds.area() * params.triangle_cost(i) +
|
||||||
|
right_bounds.area() * params.triangle_cost(spec.num - i);
|
||||||
|
|
||||||
|
if(sah < split.sah) {
|
||||||
|
split.sah = sah;
|
||||||
|
split.dim = dim;
|
||||||
|
split.num_left = i;
|
||||||
|
split.left_bounds = left_bounds;
|
||||||
|
split.right_bounds = right_bounds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return split;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BVHBuild::do_object_split(NodeSpec& left, NodeSpec& right, const NodeSpec& spec, const ObjectSplit& split)
|
||||||
|
{
|
||||||
|
/* sort references according to split */
|
||||||
|
int start = references.size() - spec.num;
|
||||||
|
int end = references.size(); /* todo: is this right? */
|
||||||
|
|
||||||
|
bvh_reference_sort(start, end, &references[0], split.dim);
|
||||||
|
|
||||||
|
/* split node specs */
|
||||||
|
left.num = split.num_left;
|
||||||
|
left.bounds = split.left_bounds;
|
||||||
|
right.num = spec.num - split.num_left;
|
||||||
|
right.bounds = split.right_bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Spatial Split */
|
||||||
|
|
||||||
|
BVHBuild::SpatialSplit BVHBuild::find_spatial_split(const NodeSpec& spec, float nodeSAH)
|
||||||
|
{
|
||||||
|
/* initialize bins. */
|
||||||
|
float3 origin = spec.bounds.min;
|
||||||
|
float3 binSize = (spec.bounds.max - origin) * (1.0f / (float)BVHParams::NUM_SPATIAL_BINS);
|
||||||
|
float3 invBinSize = 1.0f / binSize;
|
||||||
|
|
||||||
|
for(int dim = 0; dim < 3; dim++) {
|
||||||
|
for(int i = 0; i < BVHParams::NUM_SPATIAL_BINS; i++) {
|
||||||
|
SpatialBin& bin = spatial_bins[dim][i];
|
||||||
|
|
||||||
|
bin.bounds = BoundBox();
|
||||||
|
bin.enter = 0;
|
||||||
|
bin.exit = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* chop references into bins. */
|
||||||
|
for(unsigned int refIdx = references.size() - spec.num; refIdx < references.size(); refIdx++) {
|
||||||
|
const Reference& ref = references[refIdx];
|
||||||
|
float3 firstBinf = (ref.bounds.min - origin) * invBinSize;
|
||||||
|
float3 lastBinf = (ref.bounds.max - origin) * invBinSize;
|
||||||
|
int3 firstBin = make_int3((int)firstBinf.x, (int)firstBinf.y, (int)firstBinf.z);
|
||||||
|
int3 lastBin = make_int3((int)lastBinf.x, (int)lastBinf.y, (int)lastBinf.z);
|
||||||
|
|
||||||
|
firstBin = clamp(firstBin, 0, BVHParams::NUM_SPATIAL_BINS - 1);
|
||||||
|
lastBin = clamp(lastBin, firstBin, BVHParams::NUM_SPATIAL_BINS - 1);
|
||||||
|
|
||||||
|
for(int dim = 0; dim < 3; dim++) {
|
||||||
|
Reference currRef = ref;
|
||||||
|
|
||||||
|
for(int i = firstBin[dim]; i < lastBin[dim]; i++) {
|
||||||
|
Reference leftRef, rightRef;
|
||||||
|
|
||||||
|
split_reference(leftRef, rightRef, currRef, dim, origin[dim] + binSize[dim] * (float)(i + 1));
|
||||||
|
spatial_bins[dim][i].bounds.grow(leftRef.bounds);
|
||||||
|
currRef = rightRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
spatial_bins[dim][lastBin[dim]].bounds.grow(currRef.bounds);
|
||||||
|
spatial_bins[dim][firstBin[dim]].enter++;
|
||||||
|
spatial_bins[dim][lastBin[dim]].exit++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* select best split plane. */
|
||||||
|
SpatialSplit split;
|
||||||
|
|
||||||
|
for(int dim = 0; dim < 3; dim++) {
|
||||||
|
/* sweep right to left and determine bounds. */
|
||||||
|
BoundBox right_bounds;
|
||||||
|
|
||||||
|
for(int i = BVHParams::NUM_SPATIAL_BINS - 1; i > 0; i--) {
|
||||||
|
right_bounds.grow(spatial_bins[dim][i].bounds);
|
||||||
|
spatial_right_bounds[i - 1] = right_bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sweep left to right and select lowest SAH. */
|
||||||
|
BoundBox left_bounds;
|
||||||
|
int leftNum = 0;
|
||||||
|
int rightNum = spec.num;
|
||||||
|
|
||||||
|
for(int i = 1; i < BVHParams::NUM_SPATIAL_BINS; i++) {
|
||||||
|
left_bounds.grow(spatial_bins[dim][i - 1].bounds);
|
||||||
|
leftNum += spatial_bins[dim][i - 1].enter;
|
||||||
|
rightNum -= spatial_bins[dim][i - 1].exit;
|
||||||
|
|
||||||
|
float sah = nodeSAH +
|
||||||
|
left_bounds.area() * params.triangle_cost(leftNum) +
|
||||||
|
spatial_right_bounds[i - 1].area() * params.triangle_cost(rightNum);
|
||||||
|
|
||||||
|
if(sah < split.sah) {
|
||||||
|
split.sah = sah;
|
||||||
|
split.dim = dim;
|
||||||
|
split.pos = origin[dim] + binSize[dim] * (float)i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return split;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BVHBuild::do_spatial_split(NodeSpec& left, NodeSpec& right, const NodeSpec& spec, const SpatialSplit& split)
|
||||||
|
{
|
||||||
|
/* Categorize references and compute bounds.
|
||||||
|
*
|
||||||
|
* Left-hand side: [left_start, left_end[
|
||||||
|
* Uncategorized/split: [left_end, right_start[
|
||||||
|
* Right-hand side: [right_start, refs.size()[ */
|
||||||
|
|
||||||
|
vector<Reference>& refs = references;
|
||||||
|
int left_start = refs.size() - spec.num;
|
||||||
|
int left_end = left_start;
|
||||||
|
int right_start = refs.size();
|
||||||
|
|
||||||
|
left.bounds = right.bounds = BoundBox();
|
||||||
|
|
||||||
|
for(int i = left_end; i < right_start; i++) {
|
||||||
|
if(refs[i].bounds.max[split.dim] <= split.pos) {
|
||||||
|
/* entirely on the left-hand side */
|
||||||
|
left.bounds.grow(refs[i].bounds);
|
||||||
|
swap(refs[i], refs[left_end++]);
|
||||||
|
}
|
||||||
|
else if(refs[i].bounds.min[split.dim] >= split.pos) {
|
||||||
|
/* entirely on the right-hand side */
|
||||||
|
right.bounds.grow(refs[i].bounds);
|
||||||
|
swap(refs[i--], refs[--right_start]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* duplicate or unsplit references intersecting both sides. */
|
||||||
|
while(left_end < right_start) {
|
||||||
|
/* split reference. */
|
||||||
|
Reference lref, rref;
|
||||||
|
|
||||||
|
split_reference(lref, rref, refs[left_end], split.dim, split.pos);
|
||||||
|
|
||||||
|
/* compute SAH for duplicate/unsplit candidates. */
|
||||||
|
BoundBox lub = left.bounds; // Unsplit to left: new left-hand bounds.
|
||||||
|
BoundBox rub = right.bounds; // Unsplit to right: new right-hand bounds.
|
||||||
|
BoundBox ldb = left.bounds; // Duplicate: new left-hand bounds.
|
||||||
|
BoundBox rdb = right.bounds; // Duplicate: new right-hand bounds.
|
||||||
|
|
||||||
|
lub.grow(refs[left_end].bounds);
|
||||||
|
rub.grow(refs[left_end].bounds);
|
||||||
|
ldb.grow(lref.bounds);
|
||||||
|
rdb.grow(rref.bounds);
|
||||||
|
|
||||||
|
float lac = params.triangle_cost(left_end - left_start);
|
||||||
|
float rac = params.triangle_cost(refs.size() - right_start);
|
||||||
|
float lbc = params.triangle_cost(left_end - left_start + 1);
|
||||||
|
float rbc = params.triangle_cost(refs.size() - right_start + 1);
|
||||||
|
|
||||||
|
float unsplitLeftSAH = lub.area() * lbc + right.bounds.area() * rac;
|
||||||
|
float unsplitRightSAH = left.bounds.area() * lac + rub.area() * rbc;
|
||||||
|
float duplicateSAH = ldb.area() * lbc + rdb.area() * rbc;
|
||||||
|
float minSAH = min(min(unsplitLeftSAH, unsplitRightSAH), duplicateSAH);
|
||||||
|
|
||||||
|
if(minSAH == unsplitLeftSAH) {
|
||||||
|
/* unsplit to left */
|
||||||
|
left.bounds = lub;
|
||||||
|
left_end++;
|
||||||
|
}
|
||||||
|
else if(minSAH == unsplitRightSAH) {
|
||||||
|
/* unsplit to right */
|
||||||
|
right.bounds = rub;
|
||||||
|
swap(refs[left_end], refs[--right_start]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* duplicate */
|
||||||
|
left.bounds = ldb;
|
||||||
|
right.bounds = rdb;
|
||||||
|
refs[left_end++] = lref;
|
||||||
|
refs.push_back(rref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
left.num = left_end - left_start;
|
||||||
|
right.num = refs.size() - right_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BVHBuild::split_reference(Reference& left, Reference& right, const Reference& ref, int dim, float pos)
|
||||||
|
{
|
||||||
|
/* initialize references. */
|
||||||
|
left.prim_index = right.prim_index = ref.prim_index;
|
||||||
|
left.prim_object = right.prim_object = ref.prim_object;
|
||||||
|
left.bounds = right.bounds = BoundBox();
|
||||||
|
|
||||||
|
/* loop over vertices/edges. */
|
||||||
|
Object *ob = objects[ref.prim_object];
|
||||||
|
const Mesh *mesh = ob->mesh;
|
||||||
|
const int *inds = mesh->triangles[ref.prim_index].v;
|
||||||
|
const float3 *verts = &mesh->verts[0];
|
||||||
|
const float3* v1 = &verts[inds[2]];
|
||||||
|
|
||||||
|
for(int i = 0; i < 3; i++) {
|
||||||
|
const float3* v0 = v1;
|
||||||
|
int vindex = inds[i];
|
||||||
|
v1 = &verts[vindex];
|
||||||
|
float v0p = (*v0)[dim];
|
||||||
|
float v1p = (*v1)[dim];
|
||||||
|
|
||||||
|
/* insert vertex to the boxes it belongs to. */
|
||||||
|
if(v0p <= pos)
|
||||||
|
left.bounds.grow(*v0);
|
||||||
|
|
||||||
|
if(v0p >= pos)
|
||||||
|
right.bounds.grow(*v0);
|
||||||
|
|
||||||
|
/* edge intersects the plane => insert intersection to both boxes. */
|
||||||
|
if((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
|
||||||
|
float3 t = lerp(*v0, *v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
|
||||||
|
left.bounds.grow(t);
|
||||||
|
right.bounds.grow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* intersect with original bounds. */
|
||||||
|
left.bounds.max[dim] = pos;
|
||||||
|
right.bounds.min[dim] = pos;
|
||||||
|
left.bounds.intersect(ref.bounds);
|
||||||
|
right.bounds.intersect(ref.bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
152
intern/cycles/bvh/bvh_build.h
Normal file
152
intern/cycles/bvh/bvh_build.h
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* Adapted from code copyright 2009-2010 NVIDIA Corporation
|
||||||
|
* Modifications Copyright 2011, 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_BUILD_H__
|
||||||
|
#define __BVH_BUILD_H__
|
||||||
|
|
||||||
|
#include <float.h>
|
||||||
|
|
||||||
|
#include "bvh.h"
|
||||||
|
|
||||||
|
#include "util_boundbox.h"
|
||||||
|
#include "util_vector.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class BVHParams;
|
||||||
|
class Mesh;
|
||||||
|
class Object;
|
||||||
|
class Progress;
|
||||||
|
|
||||||
|
/* BVH Builder */
|
||||||
|
|
||||||
|
class BVHBuild
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Reference
|
||||||
|
{
|
||||||
|
int prim_index;
|
||||||
|
int prim_object;
|
||||||
|
BoundBox bounds;
|
||||||
|
|
||||||
|
Reference()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NodeSpec
|
||||||
|
{
|
||||||
|
int num;
|
||||||
|
BoundBox bounds;
|
||||||
|
|
||||||
|
NodeSpec()
|
||||||
|
{
|
||||||
|
num = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BVHBuild(
|
||||||
|
const vector<Object*>& objects,
|
||||||
|
vector<int>& prim_index,
|
||||||
|
vector<int>& prim_object,
|
||||||
|
const BVHParams& params,
|
||||||
|
Progress& progress);
|
||||||
|
~BVHBuild();
|
||||||
|
|
||||||
|
BVHNode *run();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/* adding references */
|
||||||
|
void add_reference_mesh(NodeSpec& root, Mesh *mesh, int i);
|
||||||
|
void add_reference_object(NodeSpec& root, Object *ob, int i);
|
||||||
|
void add_references(NodeSpec& root);
|
||||||
|
|
||||||
|
/* building */
|
||||||
|
BVHNode *build_node(const NodeSpec& spec, int level, float progress_start, float progress_end);
|
||||||
|
BVHNode *create_leaf_node(const NodeSpec& spec);
|
||||||
|
BVHNode *create_object_leaf_nodes(const Reference *ref, int num);
|
||||||
|
|
||||||
|
void progress_update(float progress_start, float progress_end);
|
||||||
|
|
||||||
|
/* object splits */
|
||||||
|
struct ObjectSplit
|
||||||
|
{
|
||||||
|
float sah;
|
||||||
|
int dim;
|
||||||
|
int num_left;
|
||||||
|
BoundBox left_bounds;
|
||||||
|
BoundBox right_bounds;
|
||||||
|
|
||||||
|
ObjectSplit()
|
||||||
|
: sah(FLT_MAX), dim(0), num_left(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ObjectSplit find_object_split(const NodeSpec& spec, float nodeSAH);
|
||||||
|
void do_object_split(NodeSpec& left, NodeSpec& right, const NodeSpec& spec, const ObjectSplit& split);
|
||||||
|
|
||||||
|
/* spatial splits */
|
||||||
|
struct SpatialSplit
|
||||||
|
{
|
||||||
|
float sah;
|
||||||
|
int dim;
|
||||||
|
float pos;
|
||||||
|
|
||||||
|
SpatialSplit()
|
||||||
|
: sah(FLT_MAX), dim(0), pos(0.0f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SpatialBin
|
||||||
|
{
|
||||||
|
BoundBox bounds;
|
||||||
|
int enter;
|
||||||
|
int exit;
|
||||||
|
};
|
||||||
|
|
||||||
|
SpatialSplit find_spatial_split(const NodeSpec& spec, float nodeSAH);
|
||||||
|
void do_spatial_split(NodeSpec& left, NodeSpec& right, const NodeSpec& spec, const SpatialSplit& split);
|
||||||
|
void split_reference(Reference& left, Reference& right, const Reference& ref, int dim, float pos);
|
||||||
|
|
||||||
|
/* objects and primitive references */
|
||||||
|
vector<Object*> objects;
|
||||||
|
vector<Reference> references;
|
||||||
|
|
||||||
|
/* output primitive indexes and objects */
|
||||||
|
vector<int>& prim_index;
|
||||||
|
vector<int>& prim_object;
|
||||||
|
|
||||||
|
/* build parameters */
|
||||||
|
BVHParams params;
|
||||||
|
|
||||||
|
/* progress reporting */
|
||||||
|
Progress& progress;
|
||||||
|
double progress_start_time;
|
||||||
|
int progress_num_duplicates;
|
||||||
|
|
||||||
|
/* spatial splitting */
|
||||||
|
float spatial_min_overlap;
|
||||||
|
vector<BoundBox> spatial_right_bounds;
|
||||||
|
SpatialBin spatial_bins[3][BVHParams::NUM_SPATIAL_BINS];
|
||||||
|
};
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* __BVH_BUILD_H__ */
|
||||||
|
|
101
intern/cycles/bvh/bvh_node.cpp
Normal file
101
intern/cycles/bvh/bvh_node.cpp
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Adapted from code copyright 2009-2010 NVIDIA Corporation
|
||||||
|
* Modifications Copyright 2011, 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 "bvh.h"
|
||||||
|
#include "bvh_build.h"
|
||||||
|
#include "bvh_node.h"
|
||||||
|
|
||||||
|
#include "util_debug.h"
|
||||||
|
#include "util_vector.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
int BVHNode::getSubtreeSize(BVH_STAT stat) const
|
||||||
|
{
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
switch(stat)
|
||||||
|
{
|
||||||
|
case BVH_STAT_NODE_COUNT:
|
||||||
|
cnt = 1;
|
||||||
|
break;
|
||||||
|
case BVH_STAT_LEAF_COUNT:
|
||||||
|
cnt = is_leaf() ? 1 : 0;
|
||||||
|
break;
|
||||||
|
case BVH_STAT_INNER_COUNT:
|
||||||
|
cnt = is_leaf() ? 0 : 1;
|
||||||
|
break;
|
||||||
|
case BVH_STAT_TRIANGLE_COUNT:
|
||||||
|
cnt = is_leaf() ? reinterpret_cast<const LeafNode*>(this)->num_triangles() : 0;
|
||||||
|
break;
|
||||||
|
case BVH_STAT_CHILDNODE_COUNT:
|
||||||
|
cnt = num_children();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0); /* unknown mode */
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!is_leaf())
|
||||||
|
for(int i=0;i<num_children();i++)
|
||||||
|
cnt += get_child(i)->getSubtreeSize(stat);
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BVHNode::deleteSubtree()
|
||||||
|
{
|
||||||
|
for(int i=0;i<num_children();i++)
|
||||||
|
get_child(i)->deleteSubtree();
|
||||||
|
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
float BVHNode::computeSubtreeSAHCost(const BVHParams& p, float probability) const
|
||||||
|
{
|
||||||
|
float SAH = probability * p.cost(num_children(), num_triangles());
|
||||||
|
|
||||||
|
for(int i=0;i<num_children();i++) {
|
||||||
|
BVHNode *child = get_child(i);
|
||||||
|
SAH += child->computeSubtreeSAHCost(p, probability * child->m_bounds.area()/m_bounds.area());
|
||||||
|
}
|
||||||
|
|
||||||
|
return SAH;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerNode::print(int depth) const
|
||||||
|
{
|
||||||
|
for(int i = 0; i < depth; i++)
|
||||||
|
printf(" ");
|
||||||
|
|
||||||
|
printf("inner node %p\n", (void*)this);
|
||||||
|
|
||||||
|
if(children[0])
|
||||||
|
children[0]->print(depth+1);
|
||||||
|
if(children[1])
|
||||||
|
children[1]->print(depth+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LeafNode::print(int depth) const
|
||||||
|
{
|
||||||
|
for(int i = 0; i < depth; i++)
|
||||||
|
printf(" ");
|
||||||
|
|
||||||
|
printf("leaf node %d to %d\n", m_lo, m_hi);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
112
intern/cycles/bvh/bvh_node.h
Normal file
112
intern/cycles/bvh/bvh_node.h
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Adapted from code copyright 2009-2010 NVIDIA Corporation
|
||||||
|
* Modifications Copyright 2011, 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_NODE_H__
|
||||||
|
#define __BVH_NODE_H__
|
||||||
|
|
||||||
|
#include "util_boundbox.h"
|
||||||
|
#include "util_debug.h"
|
||||||
|
#include "util_types.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
enum BVH_STAT
|
||||||
|
{
|
||||||
|
BVH_STAT_NODE_COUNT,
|
||||||
|
BVH_STAT_INNER_COUNT,
|
||||||
|
BVH_STAT_LEAF_COUNT,
|
||||||
|
BVH_STAT_TRIANGLE_COUNT,
|
||||||
|
BVH_STAT_CHILDNODE_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
class BVHParams;
|
||||||
|
|
||||||
|
class BVHNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BVHNode()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~BVHNode() {}
|
||||||
|
virtual bool is_leaf() const = 0;
|
||||||
|
virtual int num_children() const = 0;
|
||||||
|
virtual BVHNode *get_child(int i) const = 0;
|
||||||
|
virtual int num_triangles() const { return 0; }
|
||||||
|
virtual void print(int depth = 0) const = 0;
|
||||||
|
|
||||||
|
float getArea() const { return m_bounds.area(); }
|
||||||
|
|
||||||
|
BoundBox m_bounds;
|
||||||
|
uint m_visibility;
|
||||||
|
|
||||||
|
// Subtree functions
|
||||||
|
int getSubtreeSize(BVH_STAT stat=BVH_STAT_NODE_COUNT) const;
|
||||||
|
float computeSubtreeSAHCost(const BVHParams& p, float probability = 1.0f) const;
|
||||||
|
void deleteSubtree();
|
||||||
|
};
|
||||||
|
|
||||||
|
class InnerNode : public BVHNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InnerNode(const BoundBox& bounds, BVHNode* child0, BVHNode* child1)
|
||||||
|
{
|
||||||
|
m_bounds = bounds;
|
||||||
|
m_visibility = child0->m_visibility|child1->m_visibility;
|
||||||
|
children[0] = child0;
|
||||||
|
children[1] = child1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_leaf() const { return false; }
|
||||||
|
int num_children() const { return 2; }
|
||||||
|
BVHNode *get_child(int i) const{ assert(i>=0 && i<2); return children[i]; }
|
||||||
|
void print(int depth) const;
|
||||||
|
|
||||||
|
BVHNode *children[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
class LeafNode : public BVHNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LeafNode(const BoundBox& bounds, uint visibility, int lo, int hi)
|
||||||
|
{
|
||||||
|
m_bounds = bounds;
|
||||||
|
m_visibility = visibility;
|
||||||
|
m_lo = lo;
|
||||||
|
m_hi = hi;
|
||||||
|
}
|
||||||
|
|
||||||
|
LeafNode(const LeafNode& s)
|
||||||
|
: BVHNode()
|
||||||
|
{
|
||||||
|
*this = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_leaf() const { return true; }
|
||||||
|
int num_children() const { return 0; }
|
||||||
|
BVHNode *get_child(int) const { return NULL; }
|
||||||
|
int num_triangles() const { return m_hi - m_lo; }
|
||||||
|
void print(int depth) const;
|
||||||
|
|
||||||
|
int m_lo;
|
||||||
|
int m_hi;
|
||||||
|
};
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* __BVH_NODE_H__ */
|
||||||
|
|
86
intern/cycles/bvh/bvh_params.h
Normal file
86
intern/cycles/bvh/bvh_params.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Adapted from code copyright 2009-2010 NVIDIA Corporation
|
||||||
|
* Modifications Copyright 2011, 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_PARAMS_H__
|
||||||
|
#define __BVH_PARAMS_H__
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* BVH Parameters */
|
||||||
|
|
||||||
|
class BVHParams
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/* spatial split area threshold */
|
||||||
|
bool use_spatial_split;
|
||||||
|
float spatial_split_alpha;
|
||||||
|
|
||||||
|
/* SAH costs */
|
||||||
|
float sah_node_cost;
|
||||||
|
float sah_triangle_cost;
|
||||||
|
|
||||||
|
/* number of triangles in leaf */
|
||||||
|
int min_leaf_size;
|
||||||
|
int max_leaf_size;
|
||||||
|
|
||||||
|
/* object or mesh level bvh */
|
||||||
|
bool top_level;
|
||||||
|
|
||||||
|
/* disk cache */
|
||||||
|
bool use_cache;
|
||||||
|
|
||||||
|
/* QBVH */
|
||||||
|
bool use_qbvh;
|
||||||
|
|
||||||
|
/* fixed parameters */
|
||||||
|
enum {
|
||||||
|
MAX_DEPTH = 64,
|
||||||
|
MAX_SPATIAL_DEPTH = 48,
|
||||||
|
NUM_SPATIAL_BINS = 32
|
||||||
|
};
|
||||||
|
|
||||||
|
BVHParams()
|
||||||
|
{
|
||||||
|
use_spatial_split = true;
|
||||||
|
spatial_split_alpha = 1e-5f;
|
||||||
|
|
||||||
|
sah_node_cost = 1.0f;
|
||||||
|
sah_triangle_cost = 1.0f;
|
||||||
|
|
||||||
|
min_leaf_size = 1;
|
||||||
|
max_leaf_size = 0x7FFFFFF;
|
||||||
|
|
||||||
|
top_level = false;
|
||||||
|
use_cache = false;
|
||||||
|
use_qbvh = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SAH costs */
|
||||||
|
float cost(int num_nodes, int num_tris) const
|
||||||
|
{ return node_cost(num_nodes) + triangle_cost(num_tris); }
|
||||||
|
|
||||||
|
float triangle_cost(int n) const
|
||||||
|
{ return n*sah_triangle_cost; }
|
||||||
|
|
||||||
|
float node_cost(int n) const
|
||||||
|
{ return n*sah_node_cost; }
|
||||||
|
};
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* __BVH_PARAMS_H__ */
|
||||||
|
|
57
intern/cycles/bvh/bvh_sort.cpp
Normal file
57
intern/cycles/bvh/bvh_sort.cpp
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Adapted from code copyright 2009-2010 NVIDIA Corporation
|
||||||
|
* Modifications Copyright 2011, 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 "bvh_build.h"
|
||||||
|
#include "bvh_sort.h"
|
||||||
|
|
||||||
|
#include "util_algorithm.h"
|
||||||
|
#include "util_debug.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
struct BVHReferenceCompare {
|
||||||
|
public:
|
||||||
|
int dim;
|
||||||
|
|
||||||
|
BVHReferenceCompare(int dim_)
|
||||||
|
{
|
||||||
|
dim = dim_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator()(const BVHBuild::Reference& ra, const BVHBuild::Reference& rb)
|
||||||
|
{
|
||||||
|
float ca = ra.bounds.min[dim] + ra.bounds.max[dim];
|
||||||
|
float cb = rb.bounds.min[dim] + rb.bounds.max[dim];
|
||||||
|
|
||||||
|
if(ca < cb) return true;
|
||||||
|
else if(ca > cb) return false;
|
||||||
|
else if(ra.prim_object < rb.prim_object) return true;
|
||||||
|
else if(ra.prim_object > rb.prim_object) return false;
|
||||||
|
else if(ra.prim_index < rb.prim_index) return true;
|
||||||
|
else if(ra.prim_index > rb.prim_index) return false;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void bvh_reference_sort(int start, int end, BVHBuild::Reference *data, int dim)
|
||||||
|
{
|
||||||
|
sort(data+start, data+end, BVHReferenceCompare(dim));
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
28
intern/cycles/bvh/bvh_sort.h
Normal file
28
intern/cycles/bvh/bvh_sort.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Adapted from code copyright 2009-2010 NVIDIA Corporation
|
||||||
|
* Modifications Copyright 2011, 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_SORT_H__
|
||||||
|
#define __BVH_SORT_H__
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
void bvh_reference_sort(int start, int end, BVHBuild::Reference *data, int dim);
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* __BVH_SORT_H__ */
|
||||||
|
|
87
intern/cycles/cmake/external_libs.cmake
Normal file
87
intern/cycles/cmake/external_libs.cmake
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
|
||||||
|
###########################################################################
|
||||||
|
# GLUT
|
||||||
|
|
||||||
|
if(WITH_CYCLES_TEST)
|
||||||
|
set(GLUT_ROOT_PATH ${CYCLES_GLUT})
|
||||||
|
|
||||||
|
find_package(GLUT)
|
||||||
|
message(STATUS "GLUT_FOUND=${GLUT_FOUND}")
|
||||||
|
|
||||||
|
include_directories(${GLUT_INCLUDE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_BUILTIN_GLEW)
|
||||||
|
set(CYCLES_GLEW_LIBRARY extern_glew)
|
||||||
|
else()
|
||||||
|
set(CYCLES_GLEW_LIBRARY ${GLEW_LIBRARY})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
###########################################################################
|
||||||
|
# OpenShadingLanguage
|
||||||
|
|
||||||
|
if(WITH_CYCLES_OSL)
|
||||||
|
|
||||||
|
set(CYCLES_OSL "" CACHE PATH "Path to OpenShadingLanguage installation")
|
||||||
|
|
||||||
|
message(STATUS "CYCLES_OSL = ${CYCLES_OSL}")
|
||||||
|
|
||||||
|
find_library(OSL_LIBRARIES NAMES oslexec oslcomp oslquery PATHS ${CYCLES_OSL}/lib ${CYCLES_OSL}/dist)
|
||||||
|
find_path(OSL_INCLUDES OSL/oslclosure.h PATHS ${CYCLES_OSL}/include ${CYCLES_OSL}/dist)
|
||||||
|
find_program(OSL_COMPILER NAMES oslc PATHS ${CYCLES_OSL}/bin ${CYCLES_OSL}/dist)
|
||||||
|
|
||||||
|
if(OSL_INCLUDES AND OSL_LIBRARIES AND OSL_COMPILER)
|
||||||
|
set(OSL_FOUND TRUE)
|
||||||
|
message(STATUS "OSL includes = ${OSL_INCLUDES}")
|
||||||
|
message(STATUS "OSL library = ${OSL_LIBRARIES}")
|
||||||
|
message(STATUS "OSL compiler = ${OSL_COMPILER}")
|
||||||
|
else()
|
||||||
|
message(STATUS "OSL not found")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include_directories(${OSL_INCLUDES} ${OSL_INCLUDES}/OSL ${OSL_INCLUDES}/../../../src/liboslexec)
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
||||||
|
###########################################################################
|
||||||
|
# Partio
|
||||||
|
|
||||||
|
if(WITH_CYCLES_PARTIO)
|
||||||
|
|
||||||
|
set(CYCLES_PARTIO "" CACHE PATH "Path to Partio installation")
|
||||||
|
|
||||||
|
message(STATUS "CYCLES_PARTIO = ${CYCLES_PARTIO}")
|
||||||
|
|
||||||
|
find_library(PARTIO_LIBRARIES NAMES partio PATHS ${CYCLES_PARTIO}/lib)
|
||||||
|
find_path(PARTIO_INCLUDES Partio.h ${CYCLES_PARTIO}/include)
|
||||||
|
|
||||||
|
find_package(ZLIB)
|
||||||
|
|
||||||
|
if(PARTIO_INCLUDES AND PARTIO_LIBRARIES AND ZLIB_LIBRARIES)
|
||||||
|
list(APPEND PARTIO_LIBRARIES ${ZLIB_LIBRARIES})
|
||||||
|
set(PARTIO_FOUND TRUE)
|
||||||
|
message(STATUS "PARTIO includes = ${PARTIO_INCLUDES}")
|
||||||
|
message(STATUS "PARTIO library = ${PARTIO_LIBRARIES}")
|
||||||
|
else()
|
||||||
|
message(STATUS "PARTIO not found")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include_directories(${PARTIO_INCLUDES})
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
||||||
|
###########################################################################
|
||||||
|
# Blender
|
||||||
|
|
||||||
|
if(WITH_CYCLES_BLENDER)
|
||||||
|
|
||||||
|
set(BLENDER_INCLUDE_DIRS
|
||||||
|
${CMAKE_SOURCE_DIR}/intern/guardedalloc
|
||||||
|
${CMAKE_SOURCE_DIR}/source/blender/makesdna
|
||||||
|
${CMAKE_SOURCE_DIR}/source/blender/makesrna
|
||||||
|
${CMAKE_SOURCE_DIR}/source/blender/blenloader
|
||||||
|
${CMAKE_BINARY_DIR}/source/blender/makesrna/intern)
|
||||||
|
|
||||||
|
add_definitions(-DBLENDER_PLUGIN)
|
||||||
|
endif()
|
||||||
|
|
32
intern/cycles/device/CMakeLists.txt
Normal file
32
intern/cycles/device/CMakeLists.txt
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
set(INC
|
||||||
|
.
|
||||||
|
../kernel
|
||||||
|
../kernel/svm
|
||||||
|
../kernel/osl
|
||||||
|
../util
|
||||||
|
../render
|
||||||
|
${OPENGL_INCLUDE_DIR}
|
||||||
|
${GLEW_INCLUDE_PATH}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SRC
|
||||||
|
device.cpp
|
||||||
|
device_cpu.cpp
|
||||||
|
device_cuda.cpp
|
||||||
|
device_multi.cpp
|
||||||
|
device_network.cpp
|
||||||
|
device_opencl.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SRC_HEADERS
|
||||||
|
device.h
|
||||||
|
device_intern.h
|
||||||
|
device_network.h
|
||||||
|
)
|
||||||
|
|
||||||
|
add_definitions(-DGLEW_STATIC)
|
||||||
|
|
||||||
|
include_directories(${INC})
|
||||||
|
|
||||||
|
add_library(cycles_device ${SRC} ${SRC_HEADERS})
|
222
intern/cycles/device/device.cpp
Normal file
222
intern/cycles/device/device.cpp
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
#include "device_intern.h"
|
||||||
|
|
||||||
|
#include "util_cuda.h"
|
||||||
|
#include "util_debug.h"
|
||||||
|
#include "util_math.h"
|
||||||
|
#include "util_opencl.h"
|
||||||
|
#include "util_opengl.h"
|
||||||
|
#include "util_types.h"
|
||||||
|
#include "util_vector.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* Device Task */
|
||||||
|
|
||||||
|
DeviceTask::DeviceTask(Type type_)
|
||||||
|
: type(type_), x(0), y(0), w(0), h(0), rng_state(0), rgba(0), buffer(0),
|
||||||
|
sample(0), resolution(0),
|
||||||
|
displace_input(0), displace_offset(0), displace_x(0), displace_w(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceTask::split(ThreadQueue<DeviceTask>& tasks, int num)
|
||||||
|
{
|
||||||
|
if(type == DISPLACE) {
|
||||||
|
num = min(displace_w, num);
|
||||||
|
|
||||||
|
for(int i = 0; i < num; i++) {
|
||||||
|
int tx = displace_x + (displace_w/num)*i;
|
||||||
|
int tw = (i == num-1)? displace_w - i*(displace_w/num): displace_w/num;
|
||||||
|
|
||||||
|
DeviceTask task = *this;
|
||||||
|
|
||||||
|
task.displace_x = tx;
|
||||||
|
task.displace_w = tw;
|
||||||
|
|
||||||
|
tasks.push(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
num = min(h, num);
|
||||||
|
|
||||||
|
for(int i = 0; i < num; i++) {
|
||||||
|
int ty = y + (h/num)*i;
|
||||||
|
int th = (i == num-1)? h - i*(h/num): h/num;
|
||||||
|
|
||||||
|
DeviceTask task = *this;
|
||||||
|
|
||||||
|
task.y = ty;
|
||||||
|
task.h = th;
|
||||||
|
|
||||||
|
tasks.push(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Device */
|
||||||
|
|
||||||
|
void Device::pixels_alloc(device_memory& mem)
|
||||||
|
{
|
||||||
|
mem_alloc(mem, MEM_READ_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::pixels_copy_from(device_memory& mem, int y, int w, int h)
|
||||||
|
{
|
||||||
|
mem_copy_from(mem, sizeof(uint8_t)*4*y*w, sizeof(uint8_t)*4*w*h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::pixels_free(device_memory& mem)
|
||||||
|
{
|
||||||
|
mem_free(mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int width, int height, bool transparent)
|
||||||
|
{
|
||||||
|
pixels_copy_from(rgba, y, w, h);
|
||||||
|
|
||||||
|
if(transparent) {
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
}
|
||||||
|
|
||||||
|
glPixelZoom((float)width/(float)w, (float)height/(float)h);
|
||||||
|
glRasterPos2f(0, y);
|
||||||
|
|
||||||
|
uint8_t *pixels = (uint8_t*)rgba.data_pointer;
|
||||||
|
|
||||||
|
/* for multi devices, this assumes the ineffecient method that we allocate
|
||||||
|
all pixels on the device even though we only render to a subset */
|
||||||
|
pixels += 4*y*w;
|
||||||
|
|
||||||
|
glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||||
|
|
||||||
|
glRasterPos2f(0.0f, 0.0f);
|
||||||
|
glPixelZoom(1.0f, 1.0f);
|
||||||
|
|
||||||
|
if(transparent)
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
Device *Device::create(DeviceType type, bool background, int threads)
|
||||||
|
{
|
||||||
|
Device *device;
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case DEVICE_CPU:
|
||||||
|
device = device_cpu_create(threads);
|
||||||
|
break;
|
||||||
|
#ifdef WITH_CUDA
|
||||||
|
case DEVICE_CUDA:
|
||||||
|
if(cuLibraryInit())
|
||||||
|
device = device_cuda_create(background);
|
||||||
|
else
|
||||||
|
device = NULL;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef WITH_MULTI
|
||||||
|
case DEVICE_MULTI:
|
||||||
|
device = device_multi_create(background);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef WITH_NETWORK
|
||||||
|
case DEVICE_NETWORK:
|
||||||
|
device = device_network_create("127.0.0.1");
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef WITH_OPENCL
|
||||||
|
case DEVICE_OPENCL:
|
||||||
|
if(clLibraryInit())
|
||||||
|
device = device_opencl_create(background);
|
||||||
|
else
|
||||||
|
device = NULL;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceType Device::type_from_string(const char *name)
|
||||||
|
{
|
||||||
|
if(strcmp(name, "cpu") == 0)
|
||||||
|
return DEVICE_CPU;
|
||||||
|
else if(strcmp(name, "cuda") == 0)
|
||||||
|
return DEVICE_CUDA;
|
||||||
|
else if(strcmp(name, "opencl") == 0)
|
||||||
|
return DEVICE_OPENCL;
|
||||||
|
else if(strcmp(name, "network") == 0)
|
||||||
|
return DEVICE_NETWORK;
|
||||||
|
else if(strcmp(name, "multi") == 0)
|
||||||
|
return DEVICE_MULTI;
|
||||||
|
|
||||||
|
return DEVICE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
string Device::string_from_type(DeviceType type)
|
||||||
|
{
|
||||||
|
if(type == DEVICE_CPU)
|
||||||
|
return "cpu";
|
||||||
|
else if(type == DEVICE_CUDA)
|
||||||
|
return "cuda";
|
||||||
|
else if(type == DEVICE_OPENCL)
|
||||||
|
return "opencl";
|
||||||
|
else if(type == DEVICE_NETWORK)
|
||||||
|
return "network";
|
||||||
|
else if(type == DEVICE_MULTI)
|
||||||
|
return "multi";
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<DeviceType> Device::available_types()
|
||||||
|
{
|
||||||
|
vector<DeviceType> types;
|
||||||
|
|
||||||
|
types.push_back(DEVICE_CPU);
|
||||||
|
|
||||||
|
#ifdef WITH_CUDA
|
||||||
|
if(cuLibraryInit())
|
||||||
|
types.push_back(DEVICE_CUDA);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WITH_OPENCL
|
||||||
|
if(clLibraryInit())
|
||||||
|
types.push_back(DEVICE_OPENCL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WITH_NETWORK
|
||||||
|
types.push_back(DEVICE_NETWORK);
|
||||||
|
#endif
|
||||||
|
#ifdef WITH_MULTI
|
||||||
|
types.push_back(DEVICE_MULTI);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
140
intern/cycles/device/device.h
Normal file
140
intern/cycles/device/device.h
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DEVICE_H__
|
||||||
|
#define __DEVICE_H__
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "device_memory.h"
|
||||||
|
|
||||||
|
#include "util_string.h"
|
||||||
|
#include "util_thread.h"
|
||||||
|
#include "util_types.h"
|
||||||
|
#include "util_vector.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class Progress;
|
||||||
|
|
||||||
|
enum DeviceType {
|
||||||
|
DEVICE_NONE,
|
||||||
|
DEVICE_CPU,
|
||||||
|
DEVICE_OPENCL,
|
||||||
|
DEVICE_CUDA,
|
||||||
|
DEVICE_NETWORK,
|
||||||
|
DEVICE_MULTI
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MemoryType {
|
||||||
|
MEM_READ_ONLY,
|
||||||
|
MEM_WRITE_ONLY,
|
||||||
|
MEM_READ_WRITE
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Device Task */
|
||||||
|
|
||||||
|
class DeviceTask {
|
||||||
|
public:
|
||||||
|
typedef enum { PATH_TRACE, TONEMAP, DISPLACE } Type;
|
||||||
|
Type type;
|
||||||
|
|
||||||
|
int x, y, w, h;
|
||||||
|
device_ptr rng_state;
|
||||||
|
device_ptr rgba;
|
||||||
|
device_ptr buffer;
|
||||||
|
int sample;
|
||||||
|
int resolution;
|
||||||
|
|
||||||
|
device_ptr displace_input;
|
||||||
|
device_ptr displace_offset;
|
||||||
|
int displace_x, displace_w;
|
||||||
|
|
||||||
|
DeviceTask(Type type = PATH_TRACE);
|
||||||
|
void split(ThreadQueue<DeviceTask>& tasks, int num);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Device */
|
||||||
|
|
||||||
|
class Device {
|
||||||
|
protected:
|
||||||
|
Device() {}
|
||||||
|
|
||||||
|
bool background;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~Device() {}
|
||||||
|
|
||||||
|
virtual bool support_full_kernel() = 0;
|
||||||
|
|
||||||
|
/* info */
|
||||||
|
virtual string description() = 0;
|
||||||
|
|
||||||
|
/* regular memory */
|
||||||
|
virtual void mem_alloc(device_memory& mem, MemoryType type) = 0;
|
||||||
|
virtual void mem_copy_to(device_memory& mem) = 0;
|
||||||
|
virtual void mem_copy_from(device_memory& mem,
|
||||||
|
size_t offset, size_t size) = 0;
|
||||||
|
virtual void mem_zero(device_memory& mem) = 0;
|
||||||
|
virtual void mem_free(device_memory& mem) = 0;
|
||||||
|
|
||||||
|
/* constant memory */
|
||||||
|
virtual void const_copy_to(const char *name, void *host, size_t size) = 0;
|
||||||
|
|
||||||
|
/* texture memory */
|
||||||
|
virtual void tex_alloc(const char *name, device_memory& mem,
|
||||||
|
bool interpolation = false, bool periodic = false) {};
|
||||||
|
virtual void tex_free(device_memory& mem) {};
|
||||||
|
|
||||||
|
/* pixel memory */
|
||||||
|
virtual void pixels_alloc(device_memory& mem);
|
||||||
|
virtual void pixels_copy_from(device_memory& mem, int y, int w, int h);
|
||||||
|
virtual void pixels_free(device_memory& mem);
|
||||||
|
|
||||||
|
/* open shading language, only for CPU device */
|
||||||
|
virtual void *osl_memory() { return NULL; }
|
||||||
|
|
||||||
|
/* load/compile kernels, must be called before adding tasks */
|
||||||
|
virtual bool load_kernels() { return true; }
|
||||||
|
|
||||||
|
/* tasks */
|
||||||
|
virtual void task_add(DeviceTask& task) = 0;
|
||||||
|
virtual void task_wait() = 0;
|
||||||
|
virtual void task_cancel() = 0;
|
||||||
|
|
||||||
|
/* opengl drawing */
|
||||||
|
virtual void draw_pixels(device_memory& mem, int y, int w, int h,
|
||||||
|
int width, int height, bool transparent);
|
||||||
|
|
||||||
|
#ifdef WITH_NETWORK
|
||||||
|
/* networking */
|
||||||
|
void server_run();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
static Device *create(DeviceType type, bool background = true, int threads = 0);
|
||||||
|
|
||||||
|
static DeviceType type_from_string(const char *name);
|
||||||
|
static string string_from_type(DeviceType type);
|
||||||
|
static vector<DeviceType> available_types();
|
||||||
|
};
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* __DEVICE_H__ */
|
||||||
|
|
224
intern/cycles/device/device_cpu.cpp
Normal file
224
intern/cycles/device/device_cpu.cpp
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
#include "device_intern.h"
|
||||||
|
|
||||||
|
#include "kernel.h"
|
||||||
|
#include "kernel_types.h"
|
||||||
|
|
||||||
|
#include "osl_shader.h"
|
||||||
|
|
||||||
|
#include "util_debug.h"
|
||||||
|
#include "util_foreach.h"
|
||||||
|
#include "util_function.h"
|
||||||
|
#include "util_opengl.h"
|
||||||
|
#include "util_progress.h"
|
||||||
|
#include "util_system.h"
|
||||||
|
#include "util_thread.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class CPUDevice : public Device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
vector<thread*> threads;
|
||||||
|
ThreadQueue<DeviceTask> tasks;
|
||||||
|
KernelGlobals *kg;
|
||||||
|
|
||||||
|
CPUDevice(int threads_num)
|
||||||
|
{
|
||||||
|
kg = kernel_globals_create();
|
||||||
|
|
||||||
|
if(threads_num == 0)
|
||||||
|
threads_num = system_cpu_thread_count();
|
||||||
|
|
||||||
|
threads.resize(threads_num);
|
||||||
|
|
||||||
|
for(size_t i = 0; i < threads.size(); i++)
|
||||||
|
threads[i] = new thread(function_bind(&CPUDevice::thread_run, this, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
~CPUDevice()
|
||||||
|
{
|
||||||
|
tasks.stop();
|
||||||
|
|
||||||
|
foreach(thread *t, threads) {
|
||||||
|
t->join();
|
||||||
|
delete t;
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel_globals_free(kg);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool support_full_kernel()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string description()
|
||||||
|
{
|
||||||
|
return system_cpu_brand_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_alloc(device_memory& mem, MemoryType type)
|
||||||
|
{
|
||||||
|
mem.device_pointer = mem.data_pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_copy_to(device_memory& mem)
|
||||||
|
{
|
||||||
|
/* no-op */
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_copy_from(device_memory& mem, size_t offset, size_t size)
|
||||||
|
{
|
||||||
|
/* no-op */
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_zero(device_memory& mem)
|
||||||
|
{
|
||||||
|
memset((void*)mem.device_pointer, 0, mem.memory_size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_free(device_memory& mem)
|
||||||
|
{
|
||||||
|
mem.device_pointer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void const_copy_to(const char *name, void *host, size_t size)
|
||||||
|
{
|
||||||
|
kernel_const_copy(kg, name, host, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
|
||||||
|
{
|
||||||
|
kernel_tex_copy(kg, name, mem.data_pointer, mem.data_width, mem.data_height);
|
||||||
|
mem.device_pointer = mem.data_pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tex_free(device_memory& mem)
|
||||||
|
{
|
||||||
|
mem.device_pointer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *osl_memory()
|
||||||
|
{
|
||||||
|
#ifdef WITH_OSL
|
||||||
|
return kernel_osl_memory(kg);
|
||||||
|
#else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_run(int t)
|
||||||
|
{
|
||||||
|
DeviceTask task;
|
||||||
|
|
||||||
|
while(tasks.worker_wait_pop(task)) {
|
||||||
|
if(task.type == DeviceTask::PATH_TRACE)
|
||||||
|
thread_path_trace(task);
|
||||||
|
else if(task.type == DeviceTask::TONEMAP)
|
||||||
|
thread_tonemap(task);
|
||||||
|
else if(task.type == DeviceTask::DISPLACE)
|
||||||
|
thread_displace(task);
|
||||||
|
|
||||||
|
tasks.worker_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_path_trace(DeviceTask& task)
|
||||||
|
{
|
||||||
|
if(tasks.worker_cancel())
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifdef WITH_OSL
|
||||||
|
if(kernel_osl_use(kg))
|
||||||
|
OSLShader::thread_init(kg);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for(int y = task.y; y < task.y + task.h; y++) {
|
||||||
|
for(int x = task.x; x < task.x + task.w; x++)
|
||||||
|
kernel_cpu_path_trace(kg, (float4*)task.buffer, (unsigned int*)task.rng_state, task.sample, x, y);
|
||||||
|
|
||||||
|
if(tasks.worker_cancel())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_OSL
|
||||||
|
if(kernel_osl_use(kg))
|
||||||
|
OSLShader::thread_free(kg);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_tonemap(DeviceTask& task)
|
||||||
|
{
|
||||||
|
for(int y = task.y; y < task.y + task.h; y++) {
|
||||||
|
for(int x = task.x; x < task.x + task.w; x++)
|
||||||
|
kernel_cpu_tonemap(kg, (uchar4*)task.rgba, (float4*)task.buffer, task.sample, task.resolution, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_displace(DeviceTask& task)
|
||||||
|
{
|
||||||
|
#ifdef WITH_OSL
|
||||||
|
if(kernel_osl_use(kg))
|
||||||
|
OSLShader::thread_init(kg);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for(int x = task.displace_x; x < task.displace_x + task.displace_w; x++) {
|
||||||
|
kernel_cpu_displace(kg, (uint4*)task.displace_input, (float3*)task.displace_offset, x);
|
||||||
|
|
||||||
|
if(tasks.worker_cancel())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_OSL
|
||||||
|
if(kernel_osl_use(kg))
|
||||||
|
OSLShader::thread_free(kg);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_add(DeviceTask& task)
|
||||||
|
{
|
||||||
|
/* split task into smaller ones, more than number of threads for uneven
|
||||||
|
workloads where some parts of the image render slower than others */
|
||||||
|
task.split(tasks, threads.size()*10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_wait()
|
||||||
|
{
|
||||||
|
tasks.wait_done();
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_cancel()
|
||||||
|
{
|
||||||
|
tasks.cancel();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Device *device_cpu_create(int threads)
|
||||||
|
{
|
||||||
|
return new CPUDevice(threads);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
804
intern/cycles/device/device_cuda.cpp
Normal file
804
intern/cycles/device/device_cuda.cpp
Normal file
@ -0,0 +1,804 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
#include "device_intern.h"
|
||||||
|
|
||||||
|
#include "util_cuda.h"
|
||||||
|
#include "util_debug.h"
|
||||||
|
#include "util_map.h"
|
||||||
|
#include "util_opengl.h"
|
||||||
|
#include "util_path.h"
|
||||||
|
#include "util_system.h"
|
||||||
|
#include "util_types.h"
|
||||||
|
#include "util_time.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class CUDADevice : public Device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CUdevice cuDevice;
|
||||||
|
CUcontext cuContext;
|
||||||
|
CUmodule cuModule;
|
||||||
|
map<device_ptr, bool> tex_interp_map;
|
||||||
|
int cuDevId;
|
||||||
|
|
||||||
|
struct PixelMem {
|
||||||
|
GLuint cuPBO;
|
||||||
|
CUgraphicsResource cuPBOresource;
|
||||||
|
GLuint cuTexId;
|
||||||
|
int w, h;
|
||||||
|
};
|
||||||
|
|
||||||
|
map<device_ptr, PixelMem> pixel_mem_map;
|
||||||
|
|
||||||
|
CUdeviceptr cuda_device_ptr(device_ptr mem)
|
||||||
|
{
|
||||||
|
return (CUdeviceptr)mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *cuda_error_string(CUresult result)
|
||||||
|
{
|
||||||
|
switch(result) {
|
||||||
|
case CUDA_SUCCESS: return "No errors";
|
||||||
|
case CUDA_ERROR_INVALID_VALUE: return "Invalid value";
|
||||||
|
case CUDA_ERROR_OUT_OF_MEMORY: return "Out of memory";
|
||||||
|
case CUDA_ERROR_NOT_INITIALIZED: return "Driver not initialized";
|
||||||
|
case CUDA_ERROR_DEINITIALIZED: return "Driver deinitialized";
|
||||||
|
|
||||||
|
case CUDA_ERROR_NO_DEVICE: return "No CUDA-capable device available";
|
||||||
|
case CUDA_ERROR_INVALID_DEVICE: return "Invalid device";
|
||||||
|
|
||||||
|
case CUDA_ERROR_INVALID_IMAGE: return "Invalid kernel image";
|
||||||
|
case CUDA_ERROR_INVALID_CONTEXT: return "Invalid context";
|
||||||
|
case CUDA_ERROR_CONTEXT_ALREADY_CURRENT: return "Context already current";
|
||||||
|
case CUDA_ERROR_MAP_FAILED: return "Map failed";
|
||||||
|
case CUDA_ERROR_UNMAP_FAILED: return "Unmap failed";
|
||||||
|
case CUDA_ERROR_ARRAY_IS_MAPPED: return "Array is mapped";
|
||||||
|
case CUDA_ERROR_ALREADY_MAPPED: return "Already mapped";
|
||||||
|
case CUDA_ERROR_NO_BINARY_FOR_GPU: return "No binary for GPU";
|
||||||
|
case CUDA_ERROR_ALREADY_ACQUIRED: return "Already acquired";
|
||||||
|
case CUDA_ERROR_NOT_MAPPED: return "Not mapped";
|
||||||
|
case CUDA_ERROR_NOT_MAPPED_AS_ARRAY: return "Mapped resource not available for access as an array";
|
||||||
|
case CUDA_ERROR_NOT_MAPPED_AS_POINTER: return "Mapped resource not available for access as a pointer";
|
||||||
|
case CUDA_ERROR_ECC_UNCORRECTABLE: return "Uncorrectable ECC error detected";
|
||||||
|
case CUDA_ERROR_UNSUPPORTED_LIMIT: return "CUlimit not supported by device";
|
||||||
|
|
||||||
|
case CUDA_ERROR_INVALID_SOURCE: return "Invalid source";
|
||||||
|
case CUDA_ERROR_FILE_NOT_FOUND: return "File not found";
|
||||||
|
case CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND: return "Link to a shared object failed to resolve";
|
||||||
|
case CUDA_ERROR_SHARED_OBJECT_INIT_FAILED: return "Shared object initialization failed";
|
||||||
|
|
||||||
|
case CUDA_ERROR_INVALID_HANDLE: return "Invalid handle";
|
||||||
|
|
||||||
|
case CUDA_ERROR_NOT_FOUND: return "Not found";
|
||||||
|
|
||||||
|
case CUDA_ERROR_NOT_READY: return "CUDA not ready";
|
||||||
|
|
||||||
|
case CUDA_ERROR_LAUNCH_FAILED: return "Launch failed";
|
||||||
|
case CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES: return "Launch exceeded resources";
|
||||||
|
case CUDA_ERROR_LAUNCH_TIMEOUT: return "Launch exceeded timeout";
|
||||||
|
case CUDA_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING: return "Launch with incompatible texturing";
|
||||||
|
|
||||||
|
case CUDA_ERROR_UNKNOWN: return "Unknown error";
|
||||||
|
|
||||||
|
default: return "Unknown CUDA error value";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cuda_align_up(int& offset, int alignment)
|
||||||
|
{
|
||||||
|
return (offset + alignment - 1) & ~(alignment - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#define cuda_abort()
|
||||||
|
#else
|
||||||
|
#define cuda_abort() abort()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define cuda_assert(stmt) \
|
||||||
|
{ \
|
||||||
|
CUresult result = stmt; \
|
||||||
|
\
|
||||||
|
if(result != CUDA_SUCCESS) { \
|
||||||
|
fprintf(stderr, "CUDA error: %s in %s\n", cuda_error_string(result), #stmt); \
|
||||||
|
cuda_abort(); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cuda_error(CUresult result)
|
||||||
|
{
|
||||||
|
if(result == CUDA_SUCCESS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
fprintf(stderr, "CUDA error: %s\n", cuda_error_string(result));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cuda_push_context()
|
||||||
|
{
|
||||||
|
cuda_assert(cuCtxSetCurrent(cuContext))
|
||||||
|
}
|
||||||
|
|
||||||
|
void cuda_pop_context()
|
||||||
|
{
|
||||||
|
cuda_assert(cuCtxSetCurrent(NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
CUDADevice(bool background_)
|
||||||
|
{
|
||||||
|
background = background_;
|
||||||
|
|
||||||
|
cuDevId = 0;
|
||||||
|
cuDevice = 0;
|
||||||
|
cuContext = 0;
|
||||||
|
|
||||||
|
/* intialize */
|
||||||
|
if(cuda_error(cuInit(0)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* setup device and context */
|
||||||
|
if(cuda_error(cuDeviceGet(&cuDevice, cuDevId)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
CUresult result;
|
||||||
|
|
||||||
|
if(background)
|
||||||
|
result = cuCtxCreate(&cuContext, 0, cuDevice);
|
||||||
|
else
|
||||||
|
result = cuGLCtxCreate(&cuContext, 0, cuDevice);
|
||||||
|
|
||||||
|
if(cuda_error(result))
|
||||||
|
return;
|
||||||
|
|
||||||
|
cuda_pop_context();
|
||||||
|
}
|
||||||
|
|
||||||
|
~CUDADevice()
|
||||||
|
{
|
||||||
|
cuda_push_context();
|
||||||
|
cuda_assert(cuCtxDetach(cuContext))
|
||||||
|
}
|
||||||
|
|
||||||
|
bool support_full_kernel()
|
||||||
|
{
|
||||||
|
int major, minor;
|
||||||
|
cuDeviceComputeCapability(&major, &minor, cuDevId);
|
||||||
|
|
||||||
|
return (major >= 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
string description()
|
||||||
|
{
|
||||||
|
/* print device information */
|
||||||
|
char deviceName[100];
|
||||||
|
|
||||||
|
cuda_push_context();
|
||||||
|
cuDeviceGetName(deviceName, 256, cuDevId);
|
||||||
|
cuda_pop_context();
|
||||||
|
|
||||||
|
return string("CUDA ") + deviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
string compile_kernel()
|
||||||
|
{
|
||||||
|
/* compute cubin name */
|
||||||
|
int major, minor;
|
||||||
|
cuDeviceComputeCapability(&major, &minor, cuDevId);
|
||||||
|
|
||||||
|
/* attempt to use kernel provided with blender */
|
||||||
|
string cubin = path_get(string_printf("lib/kernel_sm_%d%d.cubin", major, minor));
|
||||||
|
if(path_exists(cubin))
|
||||||
|
return cubin;
|
||||||
|
|
||||||
|
/* not found, try to use locally compiled kernel */
|
||||||
|
string kernel_path = path_get("kernel");
|
||||||
|
string md5 = path_files_md5_hash(kernel_path);
|
||||||
|
|
||||||
|
cubin = string_printf("cycles_kernel_sm%d%d_%s.cubin", major, minor, md5.c_str());;
|
||||||
|
cubin = path_user_get(path_join("cache", cubin));
|
||||||
|
|
||||||
|
/* if exists already, use it */
|
||||||
|
if(path_exists(cubin))
|
||||||
|
return cubin;
|
||||||
|
|
||||||
|
/* if not, find CUDA compiler */
|
||||||
|
string nvcc = cuCompilerPath();
|
||||||
|
|
||||||
|
if(nvcc == "") {
|
||||||
|
fprintf(stderr, "CUDA nvcc compiler not found. Install CUDA toolkit in default location.\n");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compile */
|
||||||
|
string kernel = path_join(kernel_path, "kernel.cu");
|
||||||
|
string include = kernel_path;
|
||||||
|
const int machine = system_cpu_bits();
|
||||||
|
const int maxreg = 24;
|
||||||
|
|
||||||
|
double starttime = time_dt();
|
||||||
|
printf("Compiling CUDA kernel ...\n");
|
||||||
|
|
||||||
|
path_create_directories(cubin);
|
||||||
|
|
||||||
|
string command = string_printf("\"%s\" -arch=sm_%d%d -m%d --cubin \"%s\" --use_fast_math "
|
||||||
|
"-o \"%s\" --ptxas-options=\"-v\" --maxrregcount=%d --opencc-options -OPT:Olimit=0 -I\"%s\" -DNVCC",
|
||||||
|
nvcc.c_str(), major, minor, machine, kernel.c_str(), cubin.c_str(), maxreg, include.c_str());
|
||||||
|
|
||||||
|
if(system(command.c_str()) == -1) {
|
||||||
|
fprintf(stderr, "Failed to execute compilation command.\n");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify if compilation succeeded */
|
||||||
|
if(!path_exists(cubin)) {
|
||||||
|
fprintf(stderr, "CUDA kernel compilation failed.\n");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Kernel compilation finished in %.2lfs.\n", time_dt() - starttime);
|
||||||
|
|
||||||
|
return cubin;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool load_kernels()
|
||||||
|
{
|
||||||
|
/* check if cuda init succeeded */
|
||||||
|
if(cuContext == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get kernel */
|
||||||
|
string cubin = compile_kernel();
|
||||||
|
|
||||||
|
if(cubin == "")
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* open module */
|
||||||
|
cuda_push_context();
|
||||||
|
|
||||||
|
CUresult result = cuModuleLoad(&cuModule, cubin.c_str());
|
||||||
|
if(cuda_error(result))
|
||||||
|
fprintf(stderr, "Failed loading CUDA kernel %s.\n", cubin.c_str());
|
||||||
|
|
||||||
|
cuda_pop_context();
|
||||||
|
|
||||||
|
return (result == CUDA_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_alloc(device_memory& mem, MemoryType type)
|
||||||
|
{
|
||||||
|
cuda_push_context();
|
||||||
|
CUdeviceptr device_pointer;
|
||||||
|
cuda_assert(cuMemAlloc(&device_pointer, mem.memory_size()))
|
||||||
|
mem.device_pointer = (device_ptr)device_pointer;
|
||||||
|
cuda_pop_context();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_copy_to(device_memory& mem)
|
||||||
|
{
|
||||||
|
cuda_push_context();
|
||||||
|
cuda_assert(cuMemcpyHtoD(cuda_device_ptr(mem.device_pointer), (void*)mem.data_pointer, mem.memory_size()))
|
||||||
|
cuda_pop_context();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_copy_from(device_memory& mem, size_t offset, size_t size)
|
||||||
|
{
|
||||||
|
/* todo: offset is ignored */
|
||||||
|
cuda_push_context();
|
||||||
|
cuda_assert(cuMemcpyDtoH((uchar*)mem.data_pointer + offset,
|
||||||
|
(CUdeviceptr)((uchar*)mem.device_pointer + offset), size))
|
||||||
|
cuda_pop_context();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_zero(device_memory& mem)
|
||||||
|
{
|
||||||
|
memset((void*)mem.data_pointer, 0, mem.memory_size());
|
||||||
|
|
||||||
|
cuda_push_context();
|
||||||
|
cuda_assert(cuMemsetD8(cuda_device_ptr(mem.device_pointer), 0, mem.memory_size()))
|
||||||
|
cuda_pop_context();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_free(device_memory& mem)
|
||||||
|
{
|
||||||
|
if(mem.device_pointer) {
|
||||||
|
cuda_push_context();
|
||||||
|
cuda_assert(cuMemFree(cuda_device_ptr(mem.device_pointer)))
|
||||||
|
cuda_pop_context();
|
||||||
|
|
||||||
|
mem.device_pointer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void const_copy_to(const char *name, void *host, size_t size)
|
||||||
|
{
|
||||||
|
CUdeviceptr mem;
|
||||||
|
size_t bytes;
|
||||||
|
|
||||||
|
cuda_push_context();
|
||||||
|
cuda_assert(cuModuleGetGlobal(&mem, &bytes, cuModule, name))
|
||||||
|
//assert(bytes == size);
|
||||||
|
cuda_assert(cuMemcpyHtoD(mem, host, size))
|
||||||
|
cuda_pop_context();
|
||||||
|
}
|
||||||
|
|
||||||
|
void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
|
||||||
|
{
|
||||||
|
/* determine format */
|
||||||
|
CUarray_format_enum format;
|
||||||
|
size_t dsize = datatype_size(mem.data_type);
|
||||||
|
size_t size = mem.memory_size();
|
||||||
|
|
||||||
|
switch(mem.data_type) {
|
||||||
|
case TYPE_UCHAR: format = CU_AD_FORMAT_UNSIGNED_INT8; break;
|
||||||
|
case TYPE_UINT: format = CU_AD_FORMAT_UNSIGNED_INT32; break;
|
||||||
|
case TYPE_INT: format = CU_AD_FORMAT_SIGNED_INT32; break;
|
||||||
|
case TYPE_FLOAT: format = CU_AD_FORMAT_FLOAT; break;
|
||||||
|
default: assert(0); return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CUtexref texref;
|
||||||
|
|
||||||
|
cuda_push_context();
|
||||||
|
cuda_assert(cuModuleGetTexRef(&texref, cuModule, name))
|
||||||
|
|
||||||
|
if(interpolation) {
|
||||||
|
CUarray handle;
|
||||||
|
CUDA_ARRAY_DESCRIPTOR desc;
|
||||||
|
|
||||||
|
desc.Width = mem.data_width;
|
||||||
|
desc.Height = mem.data_height;
|
||||||
|
desc.Format = format;
|
||||||
|
desc.NumChannels = mem.data_elements;
|
||||||
|
|
||||||
|
cuda_assert(cuArrayCreate(&handle, &desc))
|
||||||
|
|
||||||
|
if(mem.data_height > 1) {
|
||||||
|
CUDA_MEMCPY2D param;
|
||||||
|
memset(¶m, 0, sizeof(param));
|
||||||
|
param.dstMemoryType = CU_MEMORYTYPE_ARRAY;
|
||||||
|
param.dstArray = handle;
|
||||||
|
param.srcMemoryType = CU_MEMORYTYPE_HOST;
|
||||||
|
param.srcHost = (void*)mem.data_pointer;
|
||||||
|
param.srcPitch = mem.data_width*dsize*mem.data_elements;
|
||||||
|
param.WidthInBytes = param.srcPitch;
|
||||||
|
param.Height = mem.data_height;
|
||||||
|
|
||||||
|
cuda_assert(cuMemcpy2D(¶m))
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cuda_assert(cuMemcpyHtoA(handle, 0, (void*)mem.data_pointer, size))
|
||||||
|
|
||||||
|
cuda_assert(cuTexRefSetArray(texref, handle, CU_TRSA_OVERRIDE_FORMAT))
|
||||||
|
|
||||||
|
cuda_assert(cuTexRefSetFilterMode(texref, CU_TR_FILTER_MODE_LINEAR))
|
||||||
|
cuda_assert(cuTexRefSetFlags(texref, CU_TRSF_NORMALIZED_COORDINATES))
|
||||||
|
|
||||||
|
mem.device_pointer = (device_ptr)handle;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cuda_pop_context();
|
||||||
|
|
||||||
|
mem_alloc(mem, MEM_READ_ONLY);
|
||||||
|
mem_copy_to(mem);
|
||||||
|
|
||||||
|
cuda_push_context();
|
||||||
|
|
||||||
|
cuda_assert(cuTexRefSetAddress(NULL, texref, cuda_device_ptr(mem.device_pointer), size))
|
||||||
|
cuda_assert(cuTexRefSetFilterMode(texref, CU_TR_FILTER_MODE_POINT))
|
||||||
|
cuda_assert(cuTexRefSetFlags(texref, CU_TRSF_READ_AS_INTEGER))
|
||||||
|
}
|
||||||
|
|
||||||
|
if(periodic) {
|
||||||
|
cuda_assert(cuTexRefSetAddressMode(texref, 0, CU_TR_ADDRESS_MODE_WRAP))
|
||||||
|
cuda_assert(cuTexRefSetAddressMode(texref, 1, CU_TR_ADDRESS_MODE_WRAP))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cuda_assert(cuTexRefSetAddressMode(texref, 0, CU_TR_ADDRESS_MODE_CLAMP))
|
||||||
|
cuda_assert(cuTexRefSetAddressMode(texref, 1, CU_TR_ADDRESS_MODE_CLAMP))
|
||||||
|
}
|
||||||
|
cuda_assert(cuTexRefSetFormat(texref, format, mem.data_elements))
|
||||||
|
|
||||||
|
cuda_pop_context();
|
||||||
|
|
||||||
|
tex_interp_map[mem.device_pointer] = interpolation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tex_free(device_memory& mem)
|
||||||
|
{
|
||||||
|
if(mem.device_pointer) {
|
||||||
|
if(tex_interp_map[mem.device_pointer]) {
|
||||||
|
cuda_push_context();
|
||||||
|
cuArrayDestroy((CUarray)mem.device_pointer);
|
||||||
|
cuda_pop_context();
|
||||||
|
|
||||||
|
tex_interp_map.erase(tex_interp_map.find(mem.device_pointer));
|
||||||
|
mem.device_pointer = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tex_interp_map.erase(tex_interp_map.find(mem.device_pointer));
|
||||||
|
mem_free(mem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void path_trace(DeviceTask& task)
|
||||||
|
{
|
||||||
|
cuda_push_context();
|
||||||
|
|
||||||
|
CUfunction cuPathTrace;
|
||||||
|
CUdeviceptr d_buffer = cuda_device_ptr(task.buffer);
|
||||||
|
CUdeviceptr d_rng_state = cuda_device_ptr(task.rng_state);
|
||||||
|
|
||||||
|
/* get kernel function */
|
||||||
|
cuda_assert(cuModuleGetFunction(&cuPathTrace, cuModule, "kernel_cuda_path_trace"))
|
||||||
|
|
||||||
|
/* pass in parameters */
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
cuda_assert(cuParamSetv(cuPathTrace, offset, &d_buffer, sizeof(d_buffer)))
|
||||||
|
offset += sizeof(d_buffer);
|
||||||
|
|
||||||
|
cuda_assert(cuParamSetv(cuPathTrace, offset, &d_rng_state, sizeof(d_rng_state)))
|
||||||
|
offset += sizeof(d_rng_state);
|
||||||
|
|
||||||
|
int sample = task.sample;
|
||||||
|
offset = cuda_align_up(offset, __alignof(sample));
|
||||||
|
|
||||||
|
cuda_assert(cuParamSeti(cuPathTrace, offset, task.sample))
|
||||||
|
offset += sizeof(task.sample);
|
||||||
|
|
||||||
|
cuda_assert(cuParamSeti(cuPathTrace, offset, task.x))
|
||||||
|
offset += sizeof(task.x);
|
||||||
|
|
||||||
|
cuda_assert(cuParamSeti(cuPathTrace, offset, task.y))
|
||||||
|
offset += sizeof(task.y);
|
||||||
|
|
||||||
|
cuda_assert(cuParamSeti(cuPathTrace, offset, task.w))
|
||||||
|
offset += sizeof(task.w);
|
||||||
|
|
||||||
|
cuda_assert(cuParamSeti(cuPathTrace, offset, task.h))
|
||||||
|
offset += sizeof(task.h);
|
||||||
|
|
||||||
|
cuda_assert(cuParamSetSize(cuPathTrace, offset))
|
||||||
|
|
||||||
|
/* launch kernel: todo find optimal size, cache config for fermi */
|
||||||
|
#ifndef __APPLE__
|
||||||
|
int xthreads = 16;
|
||||||
|
int ythreads = 16;
|
||||||
|
#else
|
||||||
|
int xthreads = 8;
|
||||||
|
int ythreads = 8;
|
||||||
|
#endif
|
||||||
|
int xblocks = (task.w + xthreads - 1)/xthreads;
|
||||||
|
int yblocks = (task.h + ythreads - 1)/ythreads;
|
||||||
|
|
||||||
|
cuda_assert(cuFuncSetCacheConfig(cuPathTrace, CU_FUNC_CACHE_PREFER_L1))
|
||||||
|
cuda_assert(cuFuncSetBlockShape(cuPathTrace, xthreads, ythreads, 1))
|
||||||
|
cuda_assert(cuLaunchGrid(cuPathTrace, xblocks, yblocks))
|
||||||
|
|
||||||
|
cuda_pop_context();
|
||||||
|
}
|
||||||
|
|
||||||
|
void tonemap(DeviceTask& task)
|
||||||
|
{
|
||||||
|
cuda_push_context();
|
||||||
|
|
||||||
|
CUfunction cuFilmConvert;
|
||||||
|
CUdeviceptr d_rgba = map_pixels(task.rgba);
|
||||||
|
CUdeviceptr d_buffer = cuda_device_ptr(task.buffer);
|
||||||
|
|
||||||
|
/* get kernel function */
|
||||||
|
cuda_assert(cuModuleGetFunction(&cuFilmConvert, cuModule, "kernel_cuda_tonemap"))
|
||||||
|
|
||||||
|
/* pass in parameters */
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
cuda_assert(cuParamSetv(cuFilmConvert, offset, &d_rgba, sizeof(d_rgba)))
|
||||||
|
offset += sizeof(d_rgba);
|
||||||
|
|
||||||
|
cuda_assert(cuParamSetv(cuFilmConvert, offset, &d_buffer, sizeof(d_buffer)))
|
||||||
|
offset += sizeof(d_buffer);
|
||||||
|
|
||||||
|
int sample = task.sample;
|
||||||
|
offset = cuda_align_up(offset, __alignof(sample));
|
||||||
|
|
||||||
|
cuda_assert(cuParamSeti(cuFilmConvert, offset, task.sample))
|
||||||
|
offset += sizeof(task.sample);
|
||||||
|
|
||||||
|
cuda_assert(cuParamSeti(cuFilmConvert, offset, task.resolution))
|
||||||
|
offset += sizeof(task.resolution);
|
||||||
|
|
||||||
|
cuda_assert(cuParamSeti(cuFilmConvert, offset, task.x))
|
||||||
|
offset += sizeof(task.x);
|
||||||
|
|
||||||
|
cuda_assert(cuParamSeti(cuFilmConvert, offset, task.y))
|
||||||
|
offset += sizeof(task.y);
|
||||||
|
|
||||||
|
cuda_assert(cuParamSeti(cuFilmConvert, offset, task.w))
|
||||||
|
offset += sizeof(task.w);
|
||||||
|
|
||||||
|
cuda_assert(cuParamSeti(cuFilmConvert, offset, task.h))
|
||||||
|
offset += sizeof(task.h);
|
||||||
|
|
||||||
|
cuda_assert(cuParamSetSize(cuFilmConvert, offset))
|
||||||
|
|
||||||
|
/* launch kernel: todo find optimal size, cache config for fermi */
|
||||||
|
#ifndef __APPLE__
|
||||||
|
int xthreads = 16;
|
||||||
|
int ythreads = 16;
|
||||||
|
#else
|
||||||
|
int xthreads = 8;
|
||||||
|
int ythreads = 8;
|
||||||
|
#endif
|
||||||
|
int xblocks = (task.w + xthreads - 1)/xthreads;
|
||||||
|
int yblocks = (task.h + ythreads - 1)/ythreads;
|
||||||
|
|
||||||
|
cuda_assert(cuFuncSetCacheConfig(cuFilmConvert, CU_FUNC_CACHE_PREFER_L1))
|
||||||
|
cuda_assert(cuFuncSetBlockShape(cuFilmConvert, xthreads, ythreads, 1))
|
||||||
|
cuda_assert(cuLaunchGrid(cuFilmConvert, xblocks, yblocks))
|
||||||
|
|
||||||
|
unmap_pixels(task.rgba);
|
||||||
|
|
||||||
|
cuda_pop_context();
|
||||||
|
}
|
||||||
|
|
||||||
|
void displace(DeviceTask& task)
|
||||||
|
{
|
||||||
|
cuda_push_context();
|
||||||
|
|
||||||
|
CUfunction cuDisplace;
|
||||||
|
CUdeviceptr d_input = cuda_device_ptr(task.displace_input);
|
||||||
|
CUdeviceptr d_offset = cuda_device_ptr(task.displace_offset);
|
||||||
|
|
||||||
|
/* get kernel function */
|
||||||
|
cuda_assert(cuModuleGetFunction(&cuDisplace, cuModule, "kernel_cuda_displace"))
|
||||||
|
|
||||||
|
/* pass in parameters */
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
cuda_assert(cuParamSetv(cuDisplace, offset, &d_input, sizeof(d_input)))
|
||||||
|
offset += sizeof(d_input);
|
||||||
|
|
||||||
|
cuda_assert(cuParamSetv(cuDisplace, offset, &d_offset, sizeof(d_offset)))
|
||||||
|
offset += sizeof(d_offset);
|
||||||
|
|
||||||
|
int displace_x = task.displace_x;
|
||||||
|
offset = cuda_align_up(offset, __alignof(displace_x));
|
||||||
|
|
||||||
|
cuda_assert(cuParamSeti(cuDisplace, offset, task.displace_x))
|
||||||
|
offset += sizeof(task.displace_x);
|
||||||
|
|
||||||
|
cuda_assert(cuParamSetSize(cuDisplace, offset))
|
||||||
|
|
||||||
|
/* launch kernel: todo find optimal size, cache config for fermi */
|
||||||
|
#ifndef __APPLE__
|
||||||
|
int xthreads = 16;
|
||||||
|
#else
|
||||||
|
int xthreads = 8;
|
||||||
|
#endif
|
||||||
|
int xblocks = (task.displace_w + xthreads - 1)/xthreads;
|
||||||
|
|
||||||
|
cuda_assert(cuFuncSetCacheConfig(cuDisplace, CU_FUNC_CACHE_PREFER_L1))
|
||||||
|
cuda_assert(cuFuncSetBlockShape(cuDisplace, xthreads, 1, 1))
|
||||||
|
cuda_assert(cuLaunchGrid(cuDisplace, xblocks, 1))
|
||||||
|
|
||||||
|
cuda_pop_context();
|
||||||
|
}
|
||||||
|
|
||||||
|
CUdeviceptr map_pixels(device_ptr mem)
|
||||||
|
{
|
||||||
|
if(!background) {
|
||||||
|
PixelMem pmem = pixel_mem_map[mem];
|
||||||
|
CUdeviceptr buffer;
|
||||||
|
|
||||||
|
size_t bytes;
|
||||||
|
cuda_assert(cuGraphicsMapResources(1, &pmem.cuPBOresource, 0))
|
||||||
|
cuda_assert(cuGraphicsResourceGetMappedPointer(&buffer, &bytes, pmem.cuPBOresource))
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cuda_device_ptr(mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unmap_pixels(device_ptr mem)
|
||||||
|
{
|
||||||
|
if(!background) {
|
||||||
|
PixelMem pmem = pixel_mem_map[mem];
|
||||||
|
|
||||||
|
cuda_assert(cuGraphicsUnmapResources(1, &pmem.cuPBOresource, 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pixels_alloc(device_memory& mem)
|
||||||
|
{
|
||||||
|
if(!background) {
|
||||||
|
PixelMem pmem;
|
||||||
|
|
||||||
|
pmem.w = mem.data_width;
|
||||||
|
pmem.h = mem.data_height;
|
||||||
|
|
||||||
|
cuda_push_context();
|
||||||
|
|
||||||
|
glGenBuffers(1, &pmem.cuPBO);
|
||||||
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pmem.cuPBO);
|
||||||
|
glBufferData(GL_PIXEL_UNPACK_BUFFER, pmem.w*pmem.h*sizeof(GLfloat)*3, NULL, GL_DYNAMIC_DRAW);
|
||||||
|
|
||||||
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
|
|
||||||
|
glGenTextures(1, &pmem.cuTexId);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, pmem.cuTexId);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pmem.w, pmem.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
cuda_assert(cuGraphicsGLRegisterBuffer(&pmem.cuPBOresource, pmem.cuPBO, CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE))
|
||||||
|
|
||||||
|
cuda_pop_context();
|
||||||
|
|
||||||
|
mem.device_pointer = pmem.cuTexId;
|
||||||
|
pixel_mem_map[mem.device_pointer] = pmem;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Device::pixels_alloc(mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pixels_copy_from(device_memory& mem, int y, int w, int h)
|
||||||
|
{
|
||||||
|
if(!background) {
|
||||||
|
PixelMem pmem = pixel_mem_map[mem.device_pointer];
|
||||||
|
|
||||||
|
cuda_push_context();
|
||||||
|
|
||||||
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pmem.cuPBO);
|
||||||
|
uchar *pixels = (uchar*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_ONLY);
|
||||||
|
size_t offset = sizeof(uchar)*4*y*w;
|
||||||
|
memcpy((uchar*)mem.data_pointer + offset, pixels + offset, sizeof(uchar)*4*w*h);
|
||||||
|
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
|
||||||
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
|
|
||||||
|
cuda_pop_context();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Device::pixels_copy_from(mem, y, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pixels_free(device_memory& mem)
|
||||||
|
{
|
||||||
|
if(mem.device_pointer) {
|
||||||
|
if(!background) {
|
||||||
|
PixelMem pmem = pixel_mem_map[mem.device_pointer];
|
||||||
|
|
||||||
|
cuda_push_context();
|
||||||
|
|
||||||
|
cuda_assert(cuGraphicsUnregisterResource(pmem.cuPBOresource))
|
||||||
|
glDeleteBuffers(1, &pmem.cuPBO);
|
||||||
|
glDeleteTextures(1, &pmem.cuTexId);
|
||||||
|
|
||||||
|
cuda_pop_context();
|
||||||
|
|
||||||
|
pixel_mem_map.erase(pixel_mem_map.find(mem.device_pointer));
|
||||||
|
mem.device_pointer = 0;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Device::pixels_free(mem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_pixels(device_memory& mem, int y, int w, int h, int width, int height, bool transparent)
|
||||||
|
{
|
||||||
|
if(!background) {
|
||||||
|
PixelMem pmem = pixel_mem_map[mem.device_pointer];
|
||||||
|
|
||||||
|
cuda_push_context();
|
||||||
|
|
||||||
|
/* for multi devices, this assumes the ineffecient method that we allocate
|
||||||
|
all pixels on the device even though we only render to a subset */
|
||||||
|
size_t offset = sizeof(uint8_t)*4*y*w;
|
||||||
|
|
||||||
|
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pmem.cuPBO);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, pmem.cuTexId);
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)offset);
|
||||||
|
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
|
||||||
|
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
if(transparent) {
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
}
|
||||||
|
|
||||||
|
glColor3f(1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
|
glPushMatrix();
|
||||||
|
glTranslatef(0.0f, (float)y, 0.0f);
|
||||||
|
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
|
||||||
|
glTexCoord2f(0.0f, 0.0f);
|
||||||
|
glVertex2f(0.0f, 0.0f);
|
||||||
|
glTexCoord2f((float)w/(float)pmem.w, 0.0f);
|
||||||
|
glVertex2f((float)width, 0.0f);
|
||||||
|
glTexCoord2f((float)w/(float)pmem.w, (float)h/(float)pmem.h);
|
||||||
|
glVertex2f((float)width, (float)height);
|
||||||
|
glTexCoord2f(0.0f, (float)h/(float)pmem.h);
|
||||||
|
glVertex2f(0.0f, (float)height);
|
||||||
|
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
if(transparent)
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
cuda_pop_context();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Device::draw_pixels(mem, y, w, h, width, height, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_add(DeviceTask& task)
|
||||||
|
{
|
||||||
|
if(task.type == DeviceTask::TONEMAP)
|
||||||
|
tonemap(task);
|
||||||
|
else if(task.type == DeviceTask::PATH_TRACE)
|
||||||
|
path_trace(task);
|
||||||
|
else if(task.type == DeviceTask::DISPLACE)
|
||||||
|
displace(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_wait()
|
||||||
|
{
|
||||||
|
cuda_push_context();
|
||||||
|
|
||||||
|
cuda_assert(cuCtxSynchronize())
|
||||||
|
|
||||||
|
cuda_pop_context();
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_cancel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Device *device_cuda_create(bool background)
|
||||||
|
{
|
||||||
|
return new CUDADevice(background);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
35
intern/cycles/device/device_intern.h
Normal file
35
intern/cycles/device/device_intern.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DEVICE_INTERN_H__
|
||||||
|
#define __DEVICE_INTERN_H__
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class Device;
|
||||||
|
|
||||||
|
Device *device_cpu_create(int threads);
|
||||||
|
Device *device_opencl_create(bool background);
|
||||||
|
Device *device_cuda_create(bool background);
|
||||||
|
Device *device_network_create(const char *address);
|
||||||
|
Device *device_multi_create(bool background);
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* __DEVICE_INTERN_H__ */
|
||||||
|
|
244
intern/cycles/device/device_memory.h
Normal file
244
intern/cycles/device/device_memory.h
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DEVICE_MEMORY_H__
|
||||||
|
#define __DEVICE_MEMORY_H__
|
||||||
|
|
||||||
|
/* Device Memory
|
||||||
|
*
|
||||||
|
* This file defines data types that can be used in device memory arrays, and
|
||||||
|
* a device_vector<T> type to store such arrays.
|
||||||
|
*
|
||||||
|
* device_vector<T> contains an STL vector, metadata about the data type,
|
||||||
|
* dimensions, elements, and a device pointer. For the CPU device this is just
|
||||||
|
* a pointer to the STL vector data, as no copying needs to take place. For
|
||||||
|
* other devices this is a pointer to device memory, where we will copy memory
|
||||||
|
* to and from. */
|
||||||
|
|
||||||
|
#include "util_debug.h"
|
||||||
|
#include "util_types.h"
|
||||||
|
#include "util_vector.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* Supported Data Types */
|
||||||
|
|
||||||
|
enum DataType {
|
||||||
|
TYPE_UCHAR,
|
||||||
|
TYPE_UINT,
|
||||||
|
TYPE_INT,
|
||||||
|
TYPE_FLOAT
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline size_t datatype_size(DataType datatype)
|
||||||
|
{
|
||||||
|
switch(datatype) {
|
||||||
|
case TYPE_UCHAR: return sizeof(uchar);
|
||||||
|
case TYPE_FLOAT: return sizeof(float);
|
||||||
|
case TYPE_UINT: return sizeof(uint);
|
||||||
|
case TYPE_INT: return sizeof(int);
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Traits for data types */
|
||||||
|
|
||||||
|
template<typename T> struct device_type_traits {
|
||||||
|
static const DataType data_type = TYPE_UCHAR;
|
||||||
|
static const int num_elements = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct device_type_traits<uchar> {
|
||||||
|
static const DataType data_type = TYPE_UCHAR;
|
||||||
|
static const int num_elements = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct device_type_traits<uchar2> {
|
||||||
|
static const DataType data_type = TYPE_UCHAR;
|
||||||
|
static const int num_elements = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct device_type_traits<uchar3> {
|
||||||
|
static const DataType data_type = TYPE_UCHAR;
|
||||||
|
static const int num_elements = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct device_type_traits<uchar4> {
|
||||||
|
static const DataType data_type = TYPE_UCHAR;
|
||||||
|
static const int num_elements = 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct device_type_traits<uint> {
|
||||||
|
static const DataType data_type = TYPE_UINT;
|
||||||
|
static const int num_elements = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct device_type_traits<uint2> {
|
||||||
|
static const DataType data_type = TYPE_UINT;
|
||||||
|
static const int num_elements = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct device_type_traits<uint3> {
|
||||||
|
static const DataType data_type = TYPE_UINT;
|
||||||
|
static const int num_elements = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct device_type_traits<uint4> {
|
||||||
|
static const DataType data_type = TYPE_UINT;
|
||||||
|
static const int num_elements = 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct device_type_traits<int> {
|
||||||
|
static const DataType data_type = TYPE_INT;
|
||||||
|
static const int num_elements = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct device_type_traits<int2> {
|
||||||
|
static const DataType data_type = TYPE_INT;
|
||||||
|
static const int num_elements = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct device_type_traits<int3> {
|
||||||
|
static const DataType data_type = TYPE_INT;
|
||||||
|
static const int num_elements = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct device_type_traits<int4> {
|
||||||
|
static const DataType data_type = TYPE_INT;
|
||||||
|
static const int num_elements = 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct device_type_traits<float> {
|
||||||
|
static const DataType data_type = TYPE_FLOAT;
|
||||||
|
static const int num_elements = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct device_type_traits<float2> {
|
||||||
|
static const DataType data_type = TYPE_FLOAT;
|
||||||
|
static const int num_elements = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct device_type_traits<float3> {
|
||||||
|
static const DataType data_type = TYPE_FLOAT;
|
||||||
|
static const int num_elements = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct device_type_traits<float4> {
|
||||||
|
static const DataType data_type = TYPE_FLOAT;
|
||||||
|
static const int num_elements = 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Device Memory */
|
||||||
|
|
||||||
|
class device_memory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
size_t memory_size() { return data_size*data_elements*datatype_size(data_type); }
|
||||||
|
|
||||||
|
/* data information */
|
||||||
|
DataType data_type;
|
||||||
|
int data_elements;
|
||||||
|
device_ptr data_pointer;
|
||||||
|
size_t data_size;
|
||||||
|
size_t data_width;
|
||||||
|
size_t data_height;
|
||||||
|
|
||||||
|
/* device pointer */
|
||||||
|
device_ptr device_pointer;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
device_memory() {}
|
||||||
|
virtual ~device_memory() { assert(!device_pointer); }
|
||||||
|
|
||||||
|
/* no copying */
|
||||||
|
device_memory(const device_memory&);
|
||||||
|
device_memory& operator = (const device_memory&);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Device Vector */
|
||||||
|
|
||||||
|
template<typename T> class device_vector : public device_memory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
device_vector()
|
||||||
|
{
|
||||||
|
data_type = device_type_traits<T>::data_type;
|
||||||
|
data_elements = device_type_traits<T>::num_elements;
|
||||||
|
data_pointer = 0;
|
||||||
|
data_size = 0;
|
||||||
|
data_width = 0;
|
||||||
|
data_height = 0;
|
||||||
|
|
||||||
|
assert(data_elements > 0);
|
||||||
|
|
||||||
|
device_pointer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~device_vector() {}
|
||||||
|
|
||||||
|
/* vector functions */
|
||||||
|
T *resize(size_t width, size_t height = 0)
|
||||||
|
{
|
||||||
|
data_size = (height == 0)? width: width*height;
|
||||||
|
data.resize(data_size);
|
||||||
|
data_pointer = (device_ptr)&data[0];
|
||||||
|
data_width = width;
|
||||||
|
data_height = height;
|
||||||
|
|
||||||
|
return &data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
T *copy(T *ptr, size_t width, size_t height = 0)
|
||||||
|
{
|
||||||
|
T *mem = resize(width, height);
|
||||||
|
memcpy(mem, ptr, memory_size());
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reference(T *ptr, size_t width, size_t height = 0)
|
||||||
|
{
|
||||||
|
data.clear();
|
||||||
|
data_size = (height == 0)? width: width*height;
|
||||||
|
data_pointer = (device_ptr)ptr;
|
||||||
|
data_width = width;
|
||||||
|
data_height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
data.clear();
|
||||||
|
data_pointer = 0;
|
||||||
|
data_width = 0;
|
||||||
|
data_height = 0;
|
||||||
|
data_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size()
|
||||||
|
{
|
||||||
|
return data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
array<T> data;
|
||||||
|
bool referenced;
|
||||||
|
};
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* __DEVICE_MEMORY_H__ */
|
||||||
|
|
336
intern/cycles/device/device_multi.cpp
Normal file
336
intern/cycles/device/device_multi.cpp
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
#include "device_intern.h"
|
||||||
|
#include "device_network.h"
|
||||||
|
|
||||||
|
#include "util_foreach.h"
|
||||||
|
#include "util_list.h"
|
||||||
|
#include "util_map.h"
|
||||||
|
#include "util_time.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class MultiDevice : public Device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct SubDevice {
|
||||||
|
SubDevice(Device *device_)
|
||||||
|
: device(device_) {}
|
||||||
|
|
||||||
|
Device *device;
|
||||||
|
map<device_ptr, device_ptr> ptr_map;
|
||||||
|
};
|
||||||
|
|
||||||
|
list<SubDevice> devices;
|
||||||
|
device_ptr unique_ptr;
|
||||||
|
|
||||||
|
MultiDevice(bool background_)
|
||||||
|
: unique_ptr(1)
|
||||||
|
{
|
||||||
|
Device *device;
|
||||||
|
|
||||||
|
/* add CPU device */
|
||||||
|
device = Device::create(DEVICE_CPU, background);
|
||||||
|
devices.push_back(SubDevice(device));
|
||||||
|
|
||||||
|
#ifdef WITH_CUDA
|
||||||
|
/* try to add GPU device */
|
||||||
|
device = Device::create(DEVICE_CUDA, background);
|
||||||
|
if(device) {
|
||||||
|
devices.push_back(SubDevice(device));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#ifdef WITH_OPENCL
|
||||||
|
device = Device::create(DEVICE_OPENCL, background);
|
||||||
|
if(device)
|
||||||
|
devices.push_back(SubDevice(device));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_NETWORK
|
||||||
|
/* try to add network devices */
|
||||||
|
ServerDiscovery discovery(true);
|
||||||
|
time_sleep(1.0);
|
||||||
|
|
||||||
|
list<string> servers = discovery.get_server_list();
|
||||||
|
|
||||||
|
foreach(string& server, servers) {
|
||||||
|
device = device_network_create(server.c_str());
|
||||||
|
if(device)
|
||||||
|
devices.push_back(SubDevice(device));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
~MultiDevice()
|
||||||
|
{
|
||||||
|
foreach(SubDevice& sub, devices)
|
||||||
|
delete sub.device;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool support_full_kernel()
|
||||||
|
{
|
||||||
|
foreach(SubDevice& sub, devices) {
|
||||||
|
if(!sub.device->support_full_kernel())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string description()
|
||||||
|
{
|
||||||
|
/* create map to find duplicate descriptions */
|
||||||
|
map<string, int> dupli_map;
|
||||||
|
map<string, int>::iterator dt;
|
||||||
|
|
||||||
|
foreach(SubDevice& sub, devices) {
|
||||||
|
string key = sub.device->description();
|
||||||
|
|
||||||
|
if(dupli_map.find(key) == dupli_map.end())
|
||||||
|
dupli_map[key] = 1;
|
||||||
|
else
|
||||||
|
dupli_map[key]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* generate string */
|
||||||
|
stringstream desc;
|
||||||
|
bool first = true;
|
||||||
|
|
||||||
|
for(dt = dupli_map.begin(); dt != dupli_map.end(); dt++) {
|
||||||
|
if(!first) desc << ", ";
|
||||||
|
first = false;
|
||||||
|
|
||||||
|
if(dt->second > 1)
|
||||||
|
desc << dt->second << "x " << dt->first;
|
||||||
|
else
|
||||||
|
desc << dt->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
return desc.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool load_kernels()
|
||||||
|
{
|
||||||
|
foreach(SubDevice& sub, devices)
|
||||||
|
if(!sub.device->load_kernels())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_alloc(device_memory& mem, MemoryType type)
|
||||||
|
{
|
||||||
|
foreach(SubDevice& sub, devices) {
|
||||||
|
mem.device_pointer = 0;
|
||||||
|
sub.device->mem_alloc(mem, type);
|
||||||
|
sub.ptr_map[unique_ptr] = mem.device_pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem.device_pointer = unique_ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_copy_to(device_memory& mem)
|
||||||
|
{
|
||||||
|
device_ptr tmp = mem.device_pointer;
|
||||||
|
|
||||||
|
foreach(SubDevice& sub, devices) {
|
||||||
|
mem.device_pointer = sub.ptr_map[tmp];
|
||||||
|
sub.device->mem_copy_to(mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
mem.device_pointer = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_copy_from(device_memory& mem, size_t offset, size_t size)
|
||||||
|
{
|
||||||
|
device_ptr tmp = mem.device_pointer;
|
||||||
|
|
||||||
|
/* todo: how does this work? */
|
||||||
|
foreach(SubDevice& sub, devices) {
|
||||||
|
mem.device_pointer = sub.ptr_map[tmp];
|
||||||
|
sub.device->mem_copy_from(mem, offset, size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem.device_pointer = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_zero(device_memory& mem)
|
||||||
|
{
|
||||||
|
device_ptr tmp = mem.device_pointer;
|
||||||
|
|
||||||
|
foreach(SubDevice& sub, devices) {
|
||||||
|
mem.device_pointer = sub.ptr_map[tmp];
|
||||||
|
sub.device->mem_zero(mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
mem.device_pointer = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_free(device_memory& mem)
|
||||||
|
{
|
||||||
|
device_ptr tmp = mem.device_pointer;
|
||||||
|
|
||||||
|
foreach(SubDevice& sub, devices) {
|
||||||
|
mem.device_pointer = sub.ptr_map[tmp];
|
||||||
|
sub.device->mem_free(mem);
|
||||||
|
sub.ptr_map.erase(sub.ptr_map.find(tmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
mem.device_pointer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void const_copy_to(const char *name, void *host, size_t size)
|
||||||
|
{
|
||||||
|
foreach(SubDevice& sub, devices)
|
||||||
|
sub.device->const_copy_to(name, host, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
|
||||||
|
{
|
||||||
|
foreach(SubDevice& sub, devices) {
|
||||||
|
mem.device_pointer = 0;
|
||||||
|
sub.device->tex_alloc(name, mem, interpolation, periodic);
|
||||||
|
sub.ptr_map[unique_ptr] = mem.device_pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem.device_pointer = unique_ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tex_free(device_memory& mem)
|
||||||
|
{
|
||||||
|
device_ptr tmp = mem.device_pointer;
|
||||||
|
|
||||||
|
foreach(SubDevice& sub, devices) {
|
||||||
|
mem.device_pointer = sub.ptr_map[tmp];
|
||||||
|
sub.device->tex_free(mem);
|
||||||
|
sub.ptr_map.erase(sub.ptr_map.find(tmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
mem.device_pointer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pixels_alloc(device_memory& mem)
|
||||||
|
{
|
||||||
|
foreach(SubDevice& sub, devices) {
|
||||||
|
mem.device_pointer = 0;
|
||||||
|
sub.device->pixels_alloc(mem);
|
||||||
|
sub.ptr_map[unique_ptr] = mem.device_pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem.device_pointer = unique_ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pixels_free(device_memory& mem)
|
||||||
|
{
|
||||||
|
device_ptr tmp = mem.device_pointer;
|
||||||
|
|
||||||
|
foreach(SubDevice& sub, devices) {
|
||||||
|
mem.device_pointer = sub.ptr_map[tmp];
|
||||||
|
sub.device->pixels_free(mem);
|
||||||
|
sub.ptr_map.erase(sub.ptr_map.find(tmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
mem.device_pointer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pixels_copy_from(device_memory& mem, int y, int w, int h)
|
||||||
|
{
|
||||||
|
device_ptr tmp = mem.device_pointer;
|
||||||
|
int i = 0, sub_h = h/devices.size();
|
||||||
|
|
||||||
|
foreach(SubDevice& sub, devices) {
|
||||||
|
int sy = y + i*sub_h;
|
||||||
|
int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
|
||||||
|
|
||||||
|
mem.device_pointer = sub.ptr_map[tmp];
|
||||||
|
sub.device->pixels_copy_from(mem, sy, w, sh);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem.device_pointer = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_pixels(device_memory& rgba, int y, int w, int h, int width, int height, bool transparent)
|
||||||
|
{
|
||||||
|
device_ptr tmp = rgba.device_pointer;
|
||||||
|
int i = 0, sub_h = h/devices.size();
|
||||||
|
int sub_height = height/devices.size();
|
||||||
|
|
||||||
|
foreach(SubDevice& sub, devices) {
|
||||||
|
int sy = y + i*sub_h;
|
||||||
|
int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
|
||||||
|
int sheight = (i == (int)devices.size() - 1)? height - sub_height*i: sub_height;
|
||||||
|
/* adjust math for w/width */
|
||||||
|
|
||||||
|
rgba.device_pointer = sub.ptr_map[tmp];
|
||||||
|
sub.device->draw_pixels(rgba, sy, w, sh, width, sheight, transparent);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
rgba.device_pointer = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_add(DeviceTask& task)
|
||||||
|
{
|
||||||
|
ThreadQueue<DeviceTask> tasks;
|
||||||
|
task.split(tasks, devices.size());
|
||||||
|
|
||||||
|
foreach(SubDevice& sub, devices) {
|
||||||
|
DeviceTask subtask;
|
||||||
|
|
||||||
|
if(tasks.worker_wait_pop(subtask)) {
|
||||||
|
if(task.buffer) subtask.buffer = sub.ptr_map[task.buffer];
|
||||||
|
if(task.rng_state) subtask.rng_state = sub.ptr_map[task.rng_state];
|
||||||
|
if(task.rgba) subtask.rgba = sub.ptr_map[task.rgba];
|
||||||
|
if(task.displace_input) subtask.displace_input = sub.ptr_map[task.displace_input];
|
||||||
|
if(task.displace_offset) subtask.displace_offset = sub.ptr_map[task.displace_offset];
|
||||||
|
|
||||||
|
sub.device->task_add(subtask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_wait()
|
||||||
|
{
|
||||||
|
foreach(SubDevice& sub, devices)
|
||||||
|
sub.device->task_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_cancel()
|
||||||
|
{
|
||||||
|
foreach(SubDevice& sub, devices)
|
||||||
|
sub.device->task_cancel();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Device *device_multi_create(bool background)
|
||||||
|
{
|
||||||
|
return new MultiDevice(background);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
391
intern/cycles/device/device_network.cpp
Normal file
391
intern/cycles/device/device_network.cpp
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
#include "device_intern.h"
|
||||||
|
#include "device_network.h"
|
||||||
|
|
||||||
|
#include "util_foreach.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
#ifdef WITH_NETWORK
|
||||||
|
|
||||||
|
class NetworkDevice : public Device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boost::asio::io_service io_service;
|
||||||
|
tcp::socket socket;
|
||||||
|
|
||||||
|
NetworkDevice(const char *address)
|
||||||
|
: socket(io_service)
|
||||||
|
{
|
||||||
|
stringstream portstr;
|
||||||
|
portstr << SERVER_PORT;
|
||||||
|
|
||||||
|
tcp::resolver resolver(io_service);
|
||||||
|
tcp::resolver::query query(address, portstr.str());
|
||||||
|
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
|
||||||
|
tcp::resolver::iterator end;
|
||||||
|
|
||||||
|
boost::system::error_code error = boost::asio::error::host_not_found;
|
||||||
|
while(error && endpoint_iterator != end)
|
||||||
|
{
|
||||||
|
socket.close();
|
||||||
|
socket.connect(*endpoint_iterator++, error);
|
||||||
|
}
|
||||||
|
if(error)
|
||||||
|
throw boost::system::system_error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
~NetworkDevice()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool support_full_kernel()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string description()
|
||||||
|
{
|
||||||
|
RPCSend snd(socket, "description");
|
||||||
|
snd.write();
|
||||||
|
|
||||||
|
RPCReceive rcv(socket);
|
||||||
|
string desc_string;
|
||||||
|
|
||||||
|
*rcv.archive & desc_string;
|
||||||
|
|
||||||
|
return desc_string + " (remote)";
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_alloc(device_memory& mem, MemoryType type)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
RPCSend snd(socket, "mem_alloc");
|
||||||
|
|
||||||
|
snd.archive & size & type;
|
||||||
|
snd.write();
|
||||||
|
|
||||||
|
RPCReceive rcv(socket);
|
||||||
|
|
||||||
|
device_ptr mem;
|
||||||
|
*rcv.archive & mem;
|
||||||
|
|
||||||
|
return mem;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_copy_to(device_memory& mem)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
RPCSend snd(socket, "mem_copy_to");
|
||||||
|
|
||||||
|
snd.archive & mem & size;
|
||||||
|
snd.write();
|
||||||
|
snd.write_buffer(host, size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_copy_from(device_memory& mem, size_t offset, size_t size)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
RPCSend snd(socket, "mem_copy_from");
|
||||||
|
|
||||||
|
snd.archive & mem & offset & size;
|
||||||
|
snd.write();
|
||||||
|
|
||||||
|
RPCReceive rcv(socket);
|
||||||
|
rcv.read_buffer(host, size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_zero(device_memory& mem)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
RPCSend snd(socket, "mem_zero");
|
||||||
|
|
||||||
|
snd.archive & mem & size;
|
||||||
|
snd.write();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_free(device_memory& mem)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
if(mem) {
|
||||||
|
RPCSend snd(socket, "mem_free");
|
||||||
|
|
||||||
|
snd.archive & mem;
|
||||||
|
snd.write();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void const_copy_to(const char *name, void *host, size_t size)
|
||||||
|
{
|
||||||
|
RPCSend snd(socket, "const_copy_to");
|
||||||
|
|
||||||
|
string name_string(name);
|
||||||
|
|
||||||
|
snd.archive & name_string & size;
|
||||||
|
snd.write();
|
||||||
|
snd.write_buffer(host, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
RPCSend snd(socket, "tex_alloc");
|
||||||
|
|
||||||
|
string name_string(name);
|
||||||
|
|
||||||
|
snd.archive & name_string & width & height & datatype & components & interpolation;
|
||||||
|
snd.write();
|
||||||
|
|
||||||
|
size_t size = width*height*components*datatype_size(datatype);
|
||||||
|
snd.write_buffer(host, size);
|
||||||
|
|
||||||
|
RPCReceive rcv(socket);
|
||||||
|
|
||||||
|
device_ptr mem;
|
||||||
|
*rcv.archive & mem;
|
||||||
|
|
||||||
|
return mem;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void tex_free(device_memory& mem)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
if(mem) {
|
||||||
|
RPCSend snd(socket, "tex_free");
|
||||||
|
|
||||||
|
snd.archive & mem;
|
||||||
|
snd.write();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void path_trace(int x, int y, int w, int h, device_ptr buffer, device_ptr rng_state, int sample)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
RPCSend snd(socket, "path_trace");
|
||||||
|
|
||||||
|
snd.archive & x & y & w & h & buffer & rng_state & sample;
|
||||||
|
snd.write();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void tonemap(int x, int y, int w, int h, device_ptr rgba, device_ptr buffer, int sample, int resolution)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
RPCSend snd(socket, "tonemap");
|
||||||
|
|
||||||
|
snd.archive & x & y & w & h & rgba & buffer & sample & resolution;
|
||||||
|
snd.write();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_add(DeviceTask& task)
|
||||||
|
{
|
||||||
|
if(task.type == DeviceTask::TONEMAP)
|
||||||
|
tonemap(task.x, task.y, task.w, task.h, task.rgba, task.buffer, task.sample, task.resolution);
|
||||||
|
else if(task.type == DeviceTask::PATH_TRACE)
|
||||||
|
path_trace(task.x, task.y, task.w, task.h, task.buffer, task.rng_state, task.sample);
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_wait()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_cancel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Device *device_network_create(const char *address)
|
||||||
|
{
|
||||||
|
return new NetworkDevice(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Device::server_run()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
/* starts thread that responds to discovery requests */
|
||||||
|
ServerDiscovery discovery;
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* accept connection */
|
||||||
|
boost::asio::io_service io_service;
|
||||||
|
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), SERVER_PORT));
|
||||||
|
|
||||||
|
tcp::socket socket(io_service);
|
||||||
|
acceptor.accept(socket);
|
||||||
|
|
||||||
|
/* receive remote function calls */
|
||||||
|
for(;;) {
|
||||||
|
RPCReceive rcv(socket);
|
||||||
|
|
||||||
|
if(rcv.name == "description") {
|
||||||
|
string desc = description();
|
||||||
|
|
||||||
|
RPCSend snd(socket);
|
||||||
|
snd.archive & desc;
|
||||||
|
snd.write();
|
||||||
|
}
|
||||||
|
else if(rcv.name == "mem_alloc") {
|
||||||
|
#if 0
|
||||||
|
MemoryType type;
|
||||||
|
size_t size;
|
||||||
|
device_ptr mem;
|
||||||
|
|
||||||
|
*rcv.archive & size & type;
|
||||||
|
mem = mem_alloc(size, type);
|
||||||
|
|
||||||
|
RPCSend snd(socket);
|
||||||
|
snd.archive & mem;
|
||||||
|
snd.write();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if(rcv.name == "mem_copy_to") {
|
||||||
|
#if 0
|
||||||
|
device_ptr mem;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
*rcv.archive & mem & size;
|
||||||
|
|
||||||
|
vector<char> host_vector(size);
|
||||||
|
rcv.read_buffer(&host_vector[0], size);
|
||||||
|
|
||||||
|
mem_copy_to(mem, &host_vector[0], size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if(rcv.name == "mem_copy_from") {
|
||||||
|
#if 0
|
||||||
|
device_ptr mem;
|
||||||
|
size_t offset, size;
|
||||||
|
|
||||||
|
*rcv.archive & mem & offset & size;
|
||||||
|
|
||||||
|
vector<char> host_vector(size);
|
||||||
|
|
||||||
|
mem_copy_from(&host_vector[0], mem, offset, size);
|
||||||
|
|
||||||
|
RPCSend snd(socket);
|
||||||
|
snd.write();
|
||||||
|
snd.write_buffer(&host_vector[0], size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if(rcv.name == "mem_zero") {
|
||||||
|
#if 0
|
||||||
|
device_ptr mem;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
*rcv.archive & mem & size;
|
||||||
|
mem_zero(mem, size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if(rcv.name == "mem_free") {
|
||||||
|
#if 0
|
||||||
|
device_ptr mem;
|
||||||
|
|
||||||
|
*rcv.archive & mem;
|
||||||
|
mem_free(mem);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if(rcv.name == "const_copy_to") {
|
||||||
|
string name_string;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
*rcv.archive & name_string & size;
|
||||||
|
|
||||||
|
vector<char> host_vector(size);
|
||||||
|
rcv.read_buffer(&host_vector[0], size);
|
||||||
|
|
||||||
|
const_copy_to(name_string.c_str(), &host_vector[0], size);
|
||||||
|
}
|
||||||
|
else if(rcv.name == "tex_alloc") {
|
||||||
|
#if 0
|
||||||
|
string name_string;
|
||||||
|
DataType datatype;
|
||||||
|
device_ptr mem;
|
||||||
|
size_t width, height;
|
||||||
|
int components;
|
||||||
|
bool interpolation;
|
||||||
|
|
||||||
|
*rcv.archive & name_string & width & height & datatype & components & interpolation;
|
||||||
|
|
||||||
|
size_t size = width*height*components*datatype_size(datatype);
|
||||||
|
|
||||||
|
vector<char> host_vector(size);
|
||||||
|
rcv.read_buffer(&host_vector[0], size);
|
||||||
|
|
||||||
|
mem = tex_alloc(name_string.c_str(), &host_vector[0], width, height, datatype, components, interpolation);
|
||||||
|
|
||||||
|
RPCSend snd(socket);
|
||||||
|
snd.archive & mem;
|
||||||
|
snd.write();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if(rcv.name == "tex_free") {
|
||||||
|
#if 0
|
||||||
|
device_ptr mem;
|
||||||
|
|
||||||
|
*rcv.archive & mem;
|
||||||
|
tex_free(mem);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if(rcv.name == "path_trace") {
|
||||||
|
#if 0
|
||||||
|
device_ptr buffer, rng_state;
|
||||||
|
int x, y, w, h;
|
||||||
|
int sample;
|
||||||
|
|
||||||
|
*rcv.archive & x & y & w & h & buffer & rng_state & sample;
|
||||||
|
path_trace(x, y, w, h, buffer, rng_state, sample);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if(rcv.name == "tonemap") {
|
||||||
|
#if 0
|
||||||
|
device_ptr rgba, buffer;
|
||||||
|
int x, y, w, h;
|
||||||
|
int sample, resolution;
|
||||||
|
|
||||||
|
*rcv.archive & x & y & w & h & rgba & buffer & sample & resolution;
|
||||||
|
tonemap(x, y, w, h, rgba, buffer, sample, resolution);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(exception& e)
|
||||||
|
{
|
||||||
|
cerr << "Network server exception: " << e.what() << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
308
intern/cycles/device/device_network.h
Normal file
308
intern/cycles/device/device_network.h
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DEVICE_NETWORK_H__
|
||||||
|
#define __DEVICE_NETWORK_H__
|
||||||
|
|
||||||
|
#ifdef WITH_NETWORK
|
||||||
|
|
||||||
|
#include <boost/archive/text_iarchive.hpp>
|
||||||
|
#include <boost/archive/text_oarchive.hpp>
|
||||||
|
#include <boost/array.hpp>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
#include <boost/serialization/vector.hpp>
|
||||||
|
#include <boost/thread.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "util_foreach.h"
|
||||||
|
#include "util_list.h"
|
||||||
|
#include "util_string.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
using std::cout;
|
||||||
|
using std::cerr;
|
||||||
|
using std::endl;
|
||||||
|
using std::hex;
|
||||||
|
using std::setw;
|
||||||
|
using std::exception;
|
||||||
|
|
||||||
|
using boost::asio::ip::tcp;
|
||||||
|
|
||||||
|
static const int SERVER_PORT = 5120;
|
||||||
|
static const int DISCOVER_PORT = 5121;
|
||||||
|
static const string DISCOVER_REQUEST_MSG = "REQUEST_RENDER_SERVER_IP";
|
||||||
|
static const string DISCOVER_REPLY_MSG = "REPLY_RENDER_SERVER_IP";
|
||||||
|
|
||||||
|
typedef struct RPCSend {
|
||||||
|
RPCSend(tcp::socket& socket_, const string& name_ = "")
|
||||||
|
: name(name_), socket(socket_), archive(archive_stream)
|
||||||
|
{
|
||||||
|
archive & name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write()
|
||||||
|
{
|
||||||
|
boost::system::error_code error;
|
||||||
|
|
||||||
|
/* get string from stream */
|
||||||
|
string archive_str = archive_stream.str();
|
||||||
|
|
||||||
|
/* first send fixed size header with size of following data */
|
||||||
|
ostringstream header_stream;
|
||||||
|
header_stream << setw(8) << hex << archive_str.size();
|
||||||
|
string header_str = header_stream.str();
|
||||||
|
|
||||||
|
boost::asio::write(socket,
|
||||||
|
boost::asio::buffer(header_str),
|
||||||
|
boost::asio::transfer_all(), error);
|
||||||
|
|
||||||
|
if(error.value())
|
||||||
|
cout << "Network send error: " << error.message() << "\n";
|
||||||
|
|
||||||
|
/* then send actual data */
|
||||||
|
boost::asio::write(socket,
|
||||||
|
boost::asio::buffer(archive_str),
|
||||||
|
boost::asio::transfer_all(), error);
|
||||||
|
|
||||||
|
if(error.value())
|
||||||
|
cout << "Network send error: " << error.message() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_buffer(void *buffer, size_t size)
|
||||||
|
{
|
||||||
|
boost::system::error_code error;
|
||||||
|
|
||||||
|
boost::asio::write(socket,
|
||||||
|
boost::asio::buffer(buffer, size),
|
||||||
|
boost::asio::transfer_all(), error);
|
||||||
|
|
||||||
|
if(error.value())
|
||||||
|
cout << "Network send error: " << error.message() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
string name;
|
||||||
|
tcp::socket& socket;
|
||||||
|
ostringstream archive_stream;
|
||||||
|
boost::archive::text_oarchive archive;
|
||||||
|
} RPCSend;
|
||||||
|
|
||||||
|
typedef struct RPCReceive {
|
||||||
|
RPCReceive(tcp::socket& socket_)
|
||||||
|
: socket(socket_), archive_stream(NULL), archive(NULL)
|
||||||
|
{
|
||||||
|
/* read head with fixed size */
|
||||||
|
vector<char> header(8);
|
||||||
|
size_t len = boost::asio::read(socket, boost::asio::buffer(header));
|
||||||
|
|
||||||
|
/* verify if we got something */
|
||||||
|
if(len == header.size()) {
|
||||||
|
/* decode header */
|
||||||
|
string header_str(&header[0], header.size());
|
||||||
|
istringstream header_stream(header_str);
|
||||||
|
|
||||||
|
size_t data_size;
|
||||||
|
|
||||||
|
if((header_stream >> hex >> data_size)) {
|
||||||
|
vector<char> data(data_size);
|
||||||
|
size_t len = boost::asio::read(socket, boost::asio::buffer(data));
|
||||||
|
|
||||||
|
if(len == data_size) {
|
||||||
|
archive_str = (data.size())? string(&data[0], data.size()): string("");
|
||||||
|
/*istringstream archive_stream(archive_str);
|
||||||
|
boost::archive::text_iarchive archive(archive_stream);*/
|
||||||
|
archive_stream = new istringstream(archive_str);
|
||||||
|
archive = new boost::archive::text_iarchive(*archive_stream);
|
||||||
|
|
||||||
|
*archive & name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cout << "Network receive error: data size doens't match header\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cout << "Network receive error: can't decode data size from header\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cout << "Network receive error: invalid header size\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
~RPCReceive()
|
||||||
|
{
|
||||||
|
delete archive;
|
||||||
|
delete archive_stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_buffer(void *buffer, size_t size)
|
||||||
|
{
|
||||||
|
size_t len = boost::asio::read(socket, boost::asio::buffer(buffer, size));
|
||||||
|
|
||||||
|
if(len != size)
|
||||||
|
cout << "Network receive error: buffer size doesn't match expected size\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
string name;
|
||||||
|
tcp::socket& socket;
|
||||||
|
string archive_str;
|
||||||
|
istringstream *archive_stream;
|
||||||
|
boost::archive::text_iarchive *archive;
|
||||||
|
} RPCReceive;
|
||||||
|
|
||||||
|
class ServerDiscovery {
|
||||||
|
public:
|
||||||
|
ServerDiscovery(bool discover = false)
|
||||||
|
: listen_socket(io_service), collect_servers(false)
|
||||||
|
{
|
||||||
|
/* setup listen socket */
|
||||||
|
listen_endpoint.address(boost::asio::ip::address_v4::any());
|
||||||
|
listen_endpoint.port(DISCOVER_PORT);
|
||||||
|
|
||||||
|
listen_socket.open(listen_endpoint.protocol());
|
||||||
|
|
||||||
|
boost::asio::socket_base::reuse_address option(true);
|
||||||
|
listen_socket.set_option(option);
|
||||||
|
|
||||||
|
listen_socket.bind(listen_endpoint);
|
||||||
|
|
||||||
|
/* setup receive callback */
|
||||||
|
async_receive();
|
||||||
|
|
||||||
|
/* start server discovery */
|
||||||
|
if(discover) {
|
||||||
|
collect_servers = true;
|
||||||
|
servers.clear();
|
||||||
|
|
||||||
|
broadcast_message(DISCOVER_REQUEST_MSG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* start thread */
|
||||||
|
work = new boost::asio::io_service::work(io_service);
|
||||||
|
thread = new boost::thread(boost::bind(&boost::asio::io_service::run, &io_service));
|
||||||
|
}
|
||||||
|
|
||||||
|
~ServerDiscovery()
|
||||||
|
{
|
||||||
|
io_service.stop();
|
||||||
|
thread->join();
|
||||||
|
delete thread;
|
||||||
|
delete work;
|
||||||
|
}
|
||||||
|
|
||||||
|
list<string> get_server_list()
|
||||||
|
{
|
||||||
|
list<string> result;
|
||||||
|
|
||||||
|
mutex.lock();
|
||||||
|
result = servers;
|
||||||
|
mutex.unlock();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handle_receive_from(const boost::system::error_code& error, size_t size)
|
||||||
|
{
|
||||||
|
if(error) {
|
||||||
|
cout << "Server discovery receive error: " << error.message() << "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(size > 0) {
|
||||||
|
string msg = string(receive_buffer, size);
|
||||||
|
|
||||||
|
/* handle incoming message */
|
||||||
|
if(collect_servers) {
|
||||||
|
if(msg == DISCOVER_REPLY_MSG) {
|
||||||
|
string address = receive_endpoint.address().to_string();
|
||||||
|
|
||||||
|
mutex.lock();
|
||||||
|
|
||||||
|
/* add address if it's not already in the list */
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
foreach(string& server, servers)
|
||||||
|
if(server == address)
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
if(!found)
|
||||||
|
servers.push_back(address);
|
||||||
|
|
||||||
|
mutex.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* reply to request */
|
||||||
|
if(msg == DISCOVER_REQUEST_MSG)
|
||||||
|
broadcast_message(DISCOVER_REPLY_MSG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async_receive();
|
||||||
|
}
|
||||||
|
|
||||||
|
void async_receive()
|
||||||
|
{
|
||||||
|
listen_socket.async_receive_from(
|
||||||
|
boost::asio::buffer(receive_buffer), receive_endpoint,
|
||||||
|
boost::bind(&ServerDiscovery::handle_receive_from, this,
|
||||||
|
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
|
||||||
|
}
|
||||||
|
|
||||||
|
void broadcast_message(const string& msg)
|
||||||
|
{
|
||||||
|
/* setup broadcast socket */
|
||||||
|
boost::asio::ip::udp::socket socket(io_service);
|
||||||
|
|
||||||
|
socket.open(boost::asio::ip::udp::v4());
|
||||||
|
|
||||||
|
boost::asio::socket_base::broadcast option(true);
|
||||||
|
socket.set_option(option);
|
||||||
|
|
||||||
|
boost::asio::ip::udp::endpoint broadcast_endpoint(
|
||||||
|
boost::asio::ip::address::from_string("255.255.255.255"), DISCOVER_PORT);
|
||||||
|
|
||||||
|
/* broadcast message */
|
||||||
|
socket.send_to(boost::asio::buffer(msg), broadcast_endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* network service and socket */
|
||||||
|
boost::asio::io_service io_service;
|
||||||
|
boost::asio::ip::udp::endpoint listen_endpoint;
|
||||||
|
boost::asio::ip::udp::socket listen_socket;
|
||||||
|
|
||||||
|
/* threading */
|
||||||
|
boost::thread *thread;
|
||||||
|
boost::asio::io_service::work *work;
|
||||||
|
boost::mutex mutex;
|
||||||
|
|
||||||
|
/* buffer and endpoint for receiving messages */
|
||||||
|
char receive_buffer[256];
|
||||||
|
boost::asio::ip::udp::endpoint receive_endpoint;
|
||||||
|
|
||||||
|
/* collection of server addresses in list */
|
||||||
|
bool collect_servers;
|
||||||
|
list<string> servers;
|
||||||
|
};
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __DEVICE_NETWORK_H__ */
|
||||||
|
|
648
intern/cycles/device/device_opencl.cpp
Normal file
648
intern/cycles/device/device_opencl.cpp
Normal file
@ -0,0 +1,648 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef WITH_OPENCL
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
#include "device_intern.h"
|
||||||
|
|
||||||
|
#include "util_map.h"
|
||||||
|
#include "util_math.h"
|
||||||
|
#include "util_md5.h"
|
||||||
|
#include "util_opencl.h"
|
||||||
|
#include "util_opengl.h"
|
||||||
|
#include "util_path.h"
|
||||||
|
#include "util_time.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
#define CL_MEM_PTR(p) ((cl_mem)(unsigned long)(p))
|
||||||
|
|
||||||
|
class OpenCLDevice : public Device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cl_context cxContext;
|
||||||
|
cl_command_queue cqCommandQueue;
|
||||||
|
cl_platform_id cpPlatform;
|
||||||
|
cl_device_id cdDevice;
|
||||||
|
cl_program cpProgram;
|
||||||
|
cl_kernel ckPathTraceKernel;
|
||||||
|
cl_kernel ckFilmConvertKernel;
|
||||||
|
cl_int ciErr;
|
||||||
|
map<string, device_vector<uchar>*> const_mem_map;
|
||||||
|
map<string, device_memory*> mem_map;
|
||||||
|
device_ptr null_mem;
|
||||||
|
bool device_initialized;
|
||||||
|
|
||||||
|
const char *opencl_error_string(cl_int err)
|
||||||
|
{
|
||||||
|
switch (err) {
|
||||||
|
case CL_SUCCESS: return "Success!";
|
||||||
|
case CL_DEVICE_NOT_FOUND: return "Device not found.";
|
||||||
|
case CL_DEVICE_NOT_AVAILABLE: return "Device not available";
|
||||||
|
case CL_COMPILER_NOT_AVAILABLE: return "Compiler not available";
|
||||||
|
case CL_MEM_OBJECT_ALLOCATION_FAILURE: return "Memory object allocation failure";
|
||||||
|
case CL_OUT_OF_RESOURCES: return "Out of resources";
|
||||||
|
case CL_OUT_OF_HOST_MEMORY: return "Out of host memory";
|
||||||
|
case CL_PROFILING_INFO_NOT_AVAILABLE: return "Profiling information not available";
|
||||||
|
case CL_MEM_COPY_OVERLAP: return "Memory copy overlap";
|
||||||
|
case CL_IMAGE_FORMAT_MISMATCH: return "Image format mismatch";
|
||||||
|
case CL_IMAGE_FORMAT_NOT_SUPPORTED: return "Image format not supported";
|
||||||
|
case CL_BUILD_PROGRAM_FAILURE: return "Program build failure";
|
||||||
|
case CL_MAP_FAILURE: return "Map failure";
|
||||||
|
case CL_INVALID_VALUE: return "Invalid value";
|
||||||
|
case CL_INVALID_DEVICE_TYPE: return "Invalid device type";
|
||||||
|
case CL_INVALID_PLATFORM: return "Invalid platform";
|
||||||
|
case CL_INVALID_DEVICE: return "Invalid device";
|
||||||
|
case CL_INVALID_CONTEXT: return "Invalid context";
|
||||||
|
case CL_INVALID_QUEUE_PROPERTIES: return "Invalid queue properties";
|
||||||
|
case CL_INVALID_COMMAND_QUEUE: return "Invalid command queue";
|
||||||
|
case CL_INVALID_HOST_PTR: return "Invalid host pointer";
|
||||||
|
case CL_INVALID_MEM_OBJECT: return "Invalid memory object";
|
||||||
|
case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR: return "Invalid image format descriptor";
|
||||||
|
case CL_INVALID_IMAGE_SIZE: return "Invalid image size";
|
||||||
|
case CL_INVALID_SAMPLER: return "Invalid sampler";
|
||||||
|
case CL_INVALID_BINARY: return "Invalid binary";
|
||||||
|
case CL_INVALID_BUILD_OPTIONS: return "Invalid build options";
|
||||||
|
case CL_INVALID_PROGRAM: return "Invalid program";
|
||||||
|
case CL_INVALID_PROGRAM_EXECUTABLE: return "Invalid program executable";
|
||||||
|
case CL_INVALID_KERNEL_NAME: return "Invalid kernel name";
|
||||||
|
case CL_INVALID_KERNEL_DEFINITION: return "Invalid kernel definition";
|
||||||
|
case CL_INVALID_KERNEL: return "Invalid kernel";
|
||||||
|
case CL_INVALID_ARG_INDEX: return "Invalid argument index";
|
||||||
|
case CL_INVALID_ARG_VALUE: return "Invalid argument value";
|
||||||
|
case CL_INVALID_ARG_SIZE: return "Invalid argument size";
|
||||||
|
case CL_INVALID_KERNEL_ARGS: return "Invalid kernel arguments";
|
||||||
|
case CL_INVALID_WORK_DIMENSION: return "Invalid work dimension";
|
||||||
|
case CL_INVALID_WORK_GROUP_SIZE: return "Invalid work group size";
|
||||||
|
case CL_INVALID_WORK_ITEM_SIZE: return "Invalid work item size";
|
||||||
|
case CL_INVALID_GLOBAL_OFFSET: return "Invalid global offset";
|
||||||
|
case CL_INVALID_EVENT_WAIT_LIST: return "Invalid event wait list";
|
||||||
|
case CL_INVALID_EVENT: return "Invalid event";
|
||||||
|
case CL_INVALID_OPERATION: return "Invalid operation";
|
||||||
|
case CL_INVALID_GL_OBJECT: return "Invalid OpenGL object";
|
||||||
|
case CL_INVALID_BUFFER_SIZE: return "Invalid buffer size";
|
||||||
|
case CL_INVALID_MIP_LEVEL: return "Invalid mip-map level";
|
||||||
|
default: return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool opencl_error(cl_int err)
|
||||||
|
{
|
||||||
|
if(err != CL_SUCCESS) {
|
||||||
|
fprintf(stderr, "OpenCL error (%d): %s\n", err, opencl_error_string(err));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void opencl_assert(cl_int err)
|
||||||
|
{
|
||||||
|
if(err != CL_SUCCESS) {
|
||||||
|
fprintf(stderr, "OpenCL error (%d): %s\n", err, opencl_error_string(err));
|
||||||
|
#ifndef NDEBUG
|
||||||
|
abort();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenCLDevice(bool background_)
|
||||||
|
{
|
||||||
|
background = background_;
|
||||||
|
cpPlatform = NULL;
|
||||||
|
cxContext = NULL;
|
||||||
|
cqCommandQueue = NULL;
|
||||||
|
cpProgram = NULL;
|
||||||
|
ckPathTraceKernel = NULL;
|
||||||
|
ckFilmConvertKernel = NULL;
|
||||||
|
null_mem = 0;
|
||||||
|
device_initialized = false;
|
||||||
|
|
||||||
|
vector<cl_platform_id> platform_ids;
|
||||||
|
cl_uint num_platforms;
|
||||||
|
|
||||||
|
/* setup device */
|
||||||
|
ciErr = clGetPlatformIDs(0, NULL, &num_platforms);
|
||||||
|
if(opencl_error(ciErr))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(num_platforms == 0) {
|
||||||
|
fprintf(stderr, "OpenCL: no platforms found.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_ids.resize(num_platforms);
|
||||||
|
ciErr = clGetPlatformIDs(num_platforms, &platform_ids[0], NULL);
|
||||||
|
if(opencl_error(ciErr))
|
||||||
|
return;
|
||||||
|
|
||||||
|
cpPlatform = platform_ids[0]; /* todo: pick specified platform && device */
|
||||||
|
|
||||||
|
ciErr = clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU|CL_DEVICE_TYPE_ACCELERATOR, 1, &cdDevice, NULL);
|
||||||
|
if(opencl_error(ciErr))
|
||||||
|
return;
|
||||||
|
|
||||||
|
cxContext = clCreateContext(0, 1, &cdDevice, NULL, NULL, &ciErr);
|
||||||
|
if(opencl_error(ciErr))
|
||||||
|
return;
|
||||||
|
|
||||||
|
cqCommandQueue = clCreateCommandQueue(cxContext, cdDevice, 0, &ciErr);
|
||||||
|
if(opencl_error(ciErr))
|
||||||
|
return;
|
||||||
|
|
||||||
|
null_mem = (device_ptr)clCreateBuffer(cxContext, CL_MEM_READ_ONLY, 1, NULL, &ciErr);
|
||||||
|
device_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool opencl_version_check()
|
||||||
|
{
|
||||||
|
char version[256];
|
||||||
|
int major, minor, req_major = 1, req_minor = 1;
|
||||||
|
|
||||||
|
clGetPlatformInfo(cpPlatform, CL_PLATFORM_VERSION, sizeof(version), &version, NULL);
|
||||||
|
|
||||||
|
if(sscanf(version, "OpenCL %d.%d", &major, &minor) < 2) {
|
||||||
|
fprintf(stderr, "OpenCL: failed to parse platform version string (%s).", version);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!((major == req_major && minor >= req_minor) || (major > req_major))) {
|
||||||
|
fprintf(stderr, "OpenCL: platform version 1.1 or later required, found %d.%d\n", major, minor);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
clGetDeviceInfo(cdDevice, CL_DEVICE_OPENCL_C_VERSION, sizeof(version), &version, NULL);
|
||||||
|
|
||||||
|
if(sscanf(version, "OpenCL C %d.%d", &major, &minor) < 2) {
|
||||||
|
fprintf(stderr, "OpenCL: failed to parse OpenCL C version string (%s).", version);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!((major == req_major && minor >= req_minor) || (major > req_major))) {
|
||||||
|
fprintf(stderr, "OpenCL: C version 1.1 or later required, found %d.%d\n", major, minor);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we don't check CL_DEVICE_VERSION since for e.g. nvidia sm 1.3 cards this is
|
||||||
|
1.0 even if the language features are there, just limited shared memory */
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool load_binary(const string& kernel_path, const string& clbin)
|
||||||
|
{
|
||||||
|
/* read binary into memory */
|
||||||
|
vector<uint8_t> binary;
|
||||||
|
|
||||||
|
if(!path_read_binary(clbin, binary)) {
|
||||||
|
fprintf(stderr, "OpenCL failed to read cached binary %s.\n", clbin.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create program */
|
||||||
|
cl_int status;
|
||||||
|
size_t size = binary.size();
|
||||||
|
const uint8_t *bytes = &binary[0];
|
||||||
|
|
||||||
|
cpProgram = clCreateProgramWithBinary(cxContext, 1, &cdDevice,
|
||||||
|
&size, &bytes, &status, &ciErr);
|
||||||
|
|
||||||
|
if(opencl_error(status) || opencl_error(ciErr)) {
|
||||||
|
fprintf(stderr, "OpenCL failed create program from cached binary %s.\n", clbin.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!build_kernel(kernel_path))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool save_binary(const string& clbin)
|
||||||
|
{
|
||||||
|
size_t size = 0;
|
||||||
|
clGetProgramInfo(cpProgram, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &size, NULL);
|
||||||
|
|
||||||
|
if(!size)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
vector<uint8_t> binary(size);
|
||||||
|
uint8_t *bytes = &binary[0];
|
||||||
|
|
||||||
|
clGetProgramInfo(cpProgram, CL_PROGRAM_BINARIES, sizeof(uint8_t*), &bytes, NULL);
|
||||||
|
|
||||||
|
if(!path_write_binary(clbin, binary)) {
|
||||||
|
fprintf(stderr, "OpenCL failed to write cached binary %s.\n", clbin.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool build_kernel(const string& kernel_path)
|
||||||
|
{
|
||||||
|
string build_options = "";
|
||||||
|
|
||||||
|
build_options += "-I " + kernel_path + ""; /* todo: escape path */
|
||||||
|
build_options += " -cl-fast-relaxed-math ";
|
||||||
|
|
||||||
|
ciErr = clBuildProgram(cpProgram, 0, NULL, build_options.c_str(), NULL, NULL);
|
||||||
|
|
||||||
|
if(ciErr != CL_SUCCESS) {
|
||||||
|
/* show build errors */
|
||||||
|
char *build_log;
|
||||||
|
size_t ret_val_size;
|
||||||
|
|
||||||
|
clGetProgramBuildInfo(cpProgram, cdDevice, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
|
||||||
|
|
||||||
|
build_log = new char[ret_val_size+1];
|
||||||
|
clGetProgramBuildInfo(cpProgram, cdDevice, CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL);
|
||||||
|
|
||||||
|
build_log[ret_val_size] = '\0';
|
||||||
|
fprintf(stderr, "OpenCL build failed:\n %s\n", build_log);
|
||||||
|
|
||||||
|
delete[] build_log;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool compile_kernel(const string& kernel_path, const string& kernel_md5)
|
||||||
|
{
|
||||||
|
/* we compile kernels consisting of many files. unfortunately opencl
|
||||||
|
kernel caches do not seem to recognize changes in included files.
|
||||||
|
so we force recompile on changes by adding the md5 hash of all files */
|
||||||
|
string source = "#include \"kernel.cl\" // " + kernel_md5 + "\n";
|
||||||
|
size_t source_len = source.size();
|
||||||
|
const char *source_str = source.c_str();
|
||||||
|
|
||||||
|
cpProgram = clCreateProgramWithSource(cxContext, 1, &source_str, &source_len, &ciErr);
|
||||||
|
|
||||||
|
if(opencl_error(ciErr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
double starttime = time_dt();
|
||||||
|
printf("Compiling OpenCL kernel ...\n");
|
||||||
|
|
||||||
|
if(!build_kernel(kernel_path))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
printf("Kernel compilation finished in %.2lfs.\n", time_dt() - starttime);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string device_md5_hash()
|
||||||
|
{
|
||||||
|
MD5Hash md5;
|
||||||
|
char version[256], driver[256], name[256], vendor[256];
|
||||||
|
|
||||||
|
clGetPlatformInfo(cpPlatform, CL_PLATFORM_VENDOR, sizeof(vendor), &vendor, NULL);
|
||||||
|
clGetDeviceInfo(cdDevice, CL_DEVICE_VERSION, sizeof(version), &version, NULL);
|
||||||
|
clGetDeviceInfo(cdDevice, CL_DEVICE_NAME, sizeof(name), &name, NULL);
|
||||||
|
clGetDeviceInfo(cdDevice, CL_DRIVER_VERSION, sizeof(driver), &driver, NULL);
|
||||||
|
|
||||||
|
md5.append((uint8_t*)vendor, strlen(vendor));
|
||||||
|
md5.append((uint8_t*)version, strlen(version));
|
||||||
|
md5.append((uint8_t*)name, strlen(name));
|
||||||
|
md5.append((uint8_t*)driver, strlen(driver));
|
||||||
|
|
||||||
|
return md5.get_hex();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool load_kernels()
|
||||||
|
{
|
||||||
|
/* verify if device was initialized */
|
||||||
|
if(!device_initialized) {
|
||||||
|
fprintf(stderr, "OpenCL: failed to initialize device.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify we have right opencl version */
|
||||||
|
if(!opencl_version_check())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* md5 hash to detect changes */
|
||||||
|
string kernel_path = path_get("kernel");
|
||||||
|
string kernel_md5 = path_files_md5_hash(kernel_path);
|
||||||
|
string device_md5 = device_md5_hash();
|
||||||
|
|
||||||
|
/* try to use cache binary */
|
||||||
|
string clbin = string_printf("cycles_kernel_%s_%s.clbin", device_md5.c_str(), kernel_md5.c_str());;
|
||||||
|
clbin = path_user_get(path_join("cache", clbin));
|
||||||
|
|
||||||
|
if(path_exists(clbin)) {
|
||||||
|
/* if exists already, try use it */
|
||||||
|
if(!load_binary(kernel_path, clbin))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* compile kernel */
|
||||||
|
if(!compile_kernel(kernel_path, kernel_md5))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* save binary for reuse */
|
||||||
|
save_binary(clbin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find kernels */
|
||||||
|
ckPathTraceKernel = clCreateKernel(cpProgram, "kernel_ocl_path_trace", &ciErr);
|
||||||
|
if(opencl_error(ciErr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ckFilmConvertKernel = clCreateKernel(cpProgram, "kernel_ocl_tonemap", &ciErr);
|
||||||
|
if(opencl_error(ciErr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
~OpenCLDevice()
|
||||||
|
{
|
||||||
|
if(null_mem)
|
||||||
|
clReleaseMemObject(CL_MEM_PTR(null_mem));
|
||||||
|
|
||||||
|
map<string, device_vector<uchar>*>::iterator mt;
|
||||||
|
for(mt = const_mem_map.begin(); mt != const_mem_map.end(); mt++) {
|
||||||
|
mem_free(*(mt->second));
|
||||||
|
delete mt->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ckPathTraceKernel)
|
||||||
|
clReleaseKernel(ckPathTraceKernel);
|
||||||
|
if(ckFilmConvertKernel)
|
||||||
|
clReleaseKernel(ckFilmConvertKernel);
|
||||||
|
if(cpProgram)
|
||||||
|
clReleaseProgram(cpProgram);
|
||||||
|
if(cqCommandQueue)
|
||||||
|
clReleaseCommandQueue(cqCommandQueue);
|
||||||
|
if(cxContext)
|
||||||
|
clReleaseContext(cxContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool support_full_kernel()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string description()
|
||||||
|
{
|
||||||
|
char name[1024];
|
||||||
|
|
||||||
|
clGetDeviceInfo(cdDevice, CL_DEVICE_NAME, sizeof(name), &name, NULL);
|
||||||
|
|
||||||
|
return string("OpenCL ") + name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_alloc(device_memory& mem, MemoryType type)
|
||||||
|
{
|
||||||
|
size_t size = mem.memory_size();
|
||||||
|
|
||||||
|
if(type == MEM_READ_ONLY)
|
||||||
|
mem.device_pointer = (device_ptr)clCreateBuffer(cxContext, CL_MEM_READ_ONLY, size, NULL, &ciErr);
|
||||||
|
else if(type == MEM_WRITE_ONLY)
|
||||||
|
mem.device_pointer = (device_ptr)clCreateBuffer(cxContext, CL_MEM_WRITE_ONLY, size, NULL, &ciErr);
|
||||||
|
else
|
||||||
|
mem.device_pointer = (device_ptr)clCreateBuffer(cxContext, CL_MEM_READ_WRITE, size, NULL, &ciErr);
|
||||||
|
|
||||||
|
opencl_assert(ciErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_copy_to(device_memory& mem)
|
||||||
|
{
|
||||||
|
/* this is blocking */
|
||||||
|
size_t size = mem.memory_size();
|
||||||
|
ciErr = clEnqueueWriteBuffer(cqCommandQueue, CL_MEM_PTR(mem.device_pointer), CL_TRUE, 0, size, (void*)mem.data_pointer, 0, NULL, NULL);
|
||||||
|
opencl_assert(ciErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_copy_from(device_memory& mem, size_t offset, size_t size)
|
||||||
|
{
|
||||||
|
ciErr = clEnqueueReadBuffer(cqCommandQueue, CL_MEM_PTR(mem.device_pointer), CL_TRUE, offset, size, (uchar*)mem.data_pointer + offset, 0, NULL, NULL);
|
||||||
|
opencl_assert(ciErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_zero(device_memory& mem)
|
||||||
|
{
|
||||||
|
if(mem.device_pointer) {
|
||||||
|
memset((void*)mem.data_pointer, 0, mem.memory_size());
|
||||||
|
mem_copy_to(mem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_free(device_memory& mem)
|
||||||
|
{
|
||||||
|
if(mem.device_pointer) {
|
||||||
|
ciErr = clReleaseMemObject(CL_MEM_PTR(mem.device_pointer));
|
||||||
|
mem.device_pointer = 0;
|
||||||
|
opencl_assert(ciErr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void const_copy_to(const char *name, void *host, size_t size)
|
||||||
|
{
|
||||||
|
if(const_mem_map.find(name) == const_mem_map.end()) {
|
||||||
|
device_vector<uchar> *data = new device_vector<uchar>();
|
||||||
|
data->copy((uchar*)host, size);
|
||||||
|
|
||||||
|
mem_alloc(*data, MEM_READ_ONLY);
|
||||||
|
const_mem_map[name] = data;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
device_vector<uchar> *data = const_mem_map[name];
|
||||||
|
data->copy((uchar*)host, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_copy_to(*const_mem_map[name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
|
||||||
|
{
|
||||||
|
mem_alloc(mem, MEM_READ_ONLY);
|
||||||
|
mem_copy_to(mem);
|
||||||
|
mem_map[name] = &mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tex_free(device_memory& mem)
|
||||||
|
{
|
||||||
|
if(mem.data_pointer)
|
||||||
|
mem_free(mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t global_size_round_up(int group_size, int global_size)
|
||||||
|
{
|
||||||
|
int r = global_size % group_size;
|
||||||
|
return global_size + ((r == 0)? 0: group_size - r);
|
||||||
|
}
|
||||||
|
|
||||||
|
void path_trace(DeviceTask& task)
|
||||||
|
{
|
||||||
|
/* cast arguments to cl types */
|
||||||
|
cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
|
||||||
|
cl_mem d_buffer = CL_MEM_PTR(task.buffer);
|
||||||
|
cl_mem d_rng_state = CL_MEM_PTR(task.rng_state);
|
||||||
|
cl_int d_x = task.x;
|
||||||
|
cl_int d_y = task.y;
|
||||||
|
cl_int d_w = task.w;
|
||||||
|
cl_int d_h = task.h;
|
||||||
|
cl_int d_sample = task.sample;
|
||||||
|
|
||||||
|
/* sample arguments */
|
||||||
|
int narg = 0;
|
||||||
|
ciErr = 0;
|
||||||
|
|
||||||
|
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_data), (void*)&d_data);
|
||||||
|
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_buffer), (void*)&d_buffer);
|
||||||
|
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_rng_state), (void*)&d_rng_state);
|
||||||
|
|
||||||
|
#define KERNEL_TEX(type, ttype, name) \
|
||||||
|
ciErr |= set_kernel_arg_mem(ckPathTraceKernel, &narg, #name);
|
||||||
|
#include "kernel_textures.h"
|
||||||
|
|
||||||
|
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_sample), (void*)&d_sample);
|
||||||
|
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_x), (void*)&d_x);
|
||||||
|
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_y), (void*)&d_y);
|
||||||
|
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_w), (void*)&d_w);
|
||||||
|
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_h), (void*)&d_h);
|
||||||
|
|
||||||
|
opencl_assert(ciErr);
|
||||||
|
|
||||||
|
size_t workgroup_size;
|
||||||
|
|
||||||
|
clGetKernelWorkGroupInfo(ckPathTraceKernel, cdDevice,
|
||||||
|
CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &workgroup_size, NULL);
|
||||||
|
|
||||||
|
workgroup_size = max(sqrt((double)workgroup_size), 1.0);
|
||||||
|
|
||||||
|
size_t local_size[2] = {workgroup_size, workgroup_size};
|
||||||
|
size_t global_size[2] = {global_size_round_up(local_size[0], d_w), global_size_round_up(local_size[1], d_h)};
|
||||||
|
|
||||||
|
/* run kernel */
|
||||||
|
ciErr = clEnqueueNDRangeKernel(cqCommandQueue, ckPathTraceKernel, 2, NULL, global_size, local_size, 0, NULL, NULL);
|
||||||
|
opencl_assert(ciErr);
|
||||||
|
opencl_assert(clFinish(cqCommandQueue));
|
||||||
|
}
|
||||||
|
|
||||||
|
cl_int set_kernel_arg_mem(cl_kernel kernel, int *narg, const char *name)
|
||||||
|
{
|
||||||
|
cl_mem ptr;
|
||||||
|
cl_int size, err = 0;
|
||||||
|
|
||||||
|
if(mem_map.find(name) != mem_map.end()) {
|
||||||
|
device_memory *mem = mem_map[name];
|
||||||
|
|
||||||
|
ptr = CL_MEM_PTR(mem->device_pointer);
|
||||||
|
size = mem->data_width;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* work around NULL not working, even though the spec says otherwise */
|
||||||
|
ptr = CL_MEM_PTR(null_mem);
|
||||||
|
size = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
err |= clSetKernelArg(kernel, (*narg)++, sizeof(ptr), (void*)&ptr);
|
||||||
|
opencl_assert(err);
|
||||||
|
err |= clSetKernelArg(kernel, (*narg)++, sizeof(size), (void*)&size);
|
||||||
|
opencl_assert(err);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tonemap(DeviceTask& task)
|
||||||
|
{
|
||||||
|
/* cast arguments to cl types */
|
||||||
|
cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
|
||||||
|
cl_mem d_rgba = CL_MEM_PTR(task.rgba);
|
||||||
|
cl_mem d_buffer = CL_MEM_PTR(task.buffer);
|
||||||
|
cl_int d_x = task.x;
|
||||||
|
cl_int d_y = task.y;
|
||||||
|
cl_int d_w = task.w;
|
||||||
|
cl_int d_h = task.h;
|
||||||
|
cl_int d_sample = task.sample;
|
||||||
|
cl_int d_resolution = task.resolution;
|
||||||
|
|
||||||
|
/* sample arguments */
|
||||||
|
int narg = 0;
|
||||||
|
ciErr = 0;
|
||||||
|
|
||||||
|
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_data), (void*)&d_data);
|
||||||
|
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_rgba), (void*)&d_rgba);
|
||||||
|
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_buffer), (void*)&d_buffer);
|
||||||
|
|
||||||
|
#define KERNEL_TEX(type, ttype, name) \
|
||||||
|
ciErr |= set_kernel_arg_mem(ckFilmConvertKernel, &narg, #name);
|
||||||
|
#include "kernel_textures.h"
|
||||||
|
|
||||||
|
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_sample), (void*)&d_sample);
|
||||||
|
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_resolution), (void*)&d_resolution);
|
||||||
|
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_x), (void*)&d_x);
|
||||||
|
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_y), (void*)&d_y);
|
||||||
|
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_w), (void*)&d_w);
|
||||||
|
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_h), (void*)&d_h);
|
||||||
|
|
||||||
|
opencl_assert(ciErr);
|
||||||
|
|
||||||
|
size_t workgroup_size;
|
||||||
|
|
||||||
|
clGetKernelWorkGroupInfo(ckFilmConvertKernel, cdDevice,
|
||||||
|
CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &workgroup_size, NULL);
|
||||||
|
|
||||||
|
workgroup_size = max(sqrt((double)workgroup_size), 1.0);
|
||||||
|
|
||||||
|
size_t local_size[2] = {workgroup_size, workgroup_size};
|
||||||
|
size_t global_size[2] = {global_size_round_up(local_size[0], d_w), global_size_round_up(local_size[1], d_h)};
|
||||||
|
|
||||||
|
/* run kernel */
|
||||||
|
ciErr = clEnqueueNDRangeKernel(cqCommandQueue, ckFilmConvertKernel, 2, NULL, global_size, local_size, 0, NULL, NULL);
|
||||||
|
opencl_assert(ciErr);
|
||||||
|
opencl_assert(clFinish(cqCommandQueue));
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_add(DeviceTask& task)
|
||||||
|
{
|
||||||
|
if(task.type == DeviceTask::TONEMAP)
|
||||||
|
tonemap(task);
|
||||||
|
else if(task.type == DeviceTask::PATH_TRACE)
|
||||||
|
path_trace(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_wait()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_cancel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Device *device_opencl_create(bool background)
|
||||||
|
{
|
||||||
|
return new OpenCLDevice(background);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* WITH_OPENCL */
|
||||||
|
|
2
intern/cycles/doc/CMakeLists.txt
Normal file
2
intern/cycles/doc/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
add_subdirectory(license)
|
203
intern/cycles/doc/license/Apache_2.0.txt
Normal file
203
intern/cycles/doc/license/Apache_2.0.txt
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
17
intern/cycles/doc/license/Blender.txt
Normal file
17
intern/cycles/doc/license/Blender.txt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Contributor(s): Alfredo de Greef, Blender Foundation
|
||||||
|
|
23
intern/cycles/doc/license/Boost.txt
Normal file
23
intern/cycles/doc/license/Boost.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Boost Software License - Version 1.0 - August 17th, 2003
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
do so, all subject to the following:
|
||||||
|
|
||||||
|
The copyright notices in the Software and this entire statement, including
|
||||||
|
the above license grant, this restriction and the following disclaimer,
|
||||||
|
must be included in all copies of the Software, in whole or in part, and
|
||||||
|
all derivative works of the Software, unless such copies or derivative
|
||||||
|
works are solely in the form of machine-executable object code generated by
|
||||||
|
a source language processor.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
13
intern/cycles/doc/license/CMakeLists.txt
Normal file
13
intern/cycles/doc/license/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
set(LICENSES
|
||||||
|
Apache_2.0.txt
|
||||||
|
Blender.txt
|
||||||
|
GPL.txt
|
||||||
|
ILM.txt
|
||||||
|
NVidia.txt
|
||||||
|
OSL.txt
|
||||||
|
Sobol.txt
|
||||||
|
readme.txt
|
||||||
|
)
|
||||||
|
|
||||||
|
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${LICENSES}" ${CYCLES_INSTALL_PATH}/license)
|
342
intern/cycles/doc/license/GPL.txt
Normal file
342
intern/cycles/doc/license/GPL.txt
Normal file
@ -0,0 +1,342 @@
|
|||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Library General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Library General
|
||||||
|
Public License instead of this License.
|
||||||
|
|
29
intern/cycles/doc/license/ILM.txt
Normal file
29
intern/cycles/doc/license/ILM.txt
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
|
||||||
|
Digital Ltd. LLC. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Industrial Light & Magic nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
36
intern/cycles/doc/license/NVidia.txt
Normal file
36
intern/cycles/doc/license/NVidia.txt
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
|
||||||
|
Copyright 2006, NVIDIA Corporation Ignacio Castano <icastano@nvidia.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
Copyright 2009-2010 NVIDIA Corporation
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
28
intern/cycles/doc/license/OSL.txt
Normal file
28
intern/cycles/doc/license/OSL.txt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
|
||||||
|
All Rights Reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of Sony Pictures Imageworks nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
29
intern/cycles/doc/license/Sobol.txt
Normal file
29
intern/cycles/doc/license/Sobol.txt
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
Copyright (c) 2008, Frances Y. Kuo and Stephen Joe
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the names of the copyright holders nor the names of the
|
||||||
|
University of New South Wales and the University of Waikato
|
||||||
|
and its contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
12
intern/cycles/doc/license/readme.txt
Normal file
12
intern/cycles/doc/license/readme.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
This program uses code from various sources. These are the licenses:
|
||||||
|
|
||||||
|
* New code is licensed under the GPL license v2 or later.
|
||||||
|
* BVH building and traversal code is licensed under Apache License v2.
|
||||||
|
* Approximate Catmull Clark subdivision code is licensed under the MIT license.
|
||||||
|
* Open Shading Language code on GPU is licensed under the Modified BSD license.
|
||||||
|
* Sobol direction vectors are licensed under the Modified BSD license.
|
||||||
|
* Matrix code adapted from OpenEXR under the Modified BSD license.
|
||||||
|
* Procedural texture functions from Blender are licensed under GPL v2 or later.
|
||||||
|
* Boost and OpenCL dynamic loading under Boost License.
|
||||||
|
|
117
intern/cycles/kernel/CMakeLists.txt
Normal file
117
intern/cycles/kernel/CMakeLists.txt
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
|
||||||
|
set(INC
|
||||||
|
.
|
||||||
|
../util
|
||||||
|
osl
|
||||||
|
svm
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SRC
|
||||||
|
kernel.cpp
|
||||||
|
kernel.cl
|
||||||
|
kernel.cu
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SRC_HEADERS
|
||||||
|
kernel.h
|
||||||
|
kernel_bvh.h
|
||||||
|
kernel_camera.h
|
||||||
|
kernel_compat_cpu.h
|
||||||
|
kernel_compat_cuda.h
|
||||||
|
kernel_compat_opencl.h
|
||||||
|
kernel_differential.h
|
||||||
|
kernel_displace.h
|
||||||
|
kernel_emission.h
|
||||||
|
kernel_film.h
|
||||||
|
kernel_globals.h
|
||||||
|
kernel_light.h
|
||||||
|
kernel_math.h
|
||||||
|
kernel_mbvh.h
|
||||||
|
kernel_montecarlo.h
|
||||||
|
kernel_object.h
|
||||||
|
kernel_path.h
|
||||||
|
kernel_qbvh.h
|
||||||
|
kernel_random.h
|
||||||
|
kernel_shader.h
|
||||||
|
kernel_textures.h
|
||||||
|
kernel_triangle.h
|
||||||
|
kernel_types.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SRC_SVM_HEADERS
|
||||||
|
svm/bsdf.h
|
||||||
|
svm/bsdf_ashikhmin_velvet.h
|
||||||
|
svm/bsdf_diffuse.h
|
||||||
|
svm/bsdf_microfacet.h
|
||||||
|
svm/bsdf_reflection.h
|
||||||
|
svm/bsdf_refraction.h
|
||||||
|
svm/bsdf_transparent.h
|
||||||
|
svm/bsdf_ward.h
|
||||||
|
svm/bsdf_westin.h
|
||||||
|
svm/emissive.h
|
||||||
|
svm/svm.h
|
||||||
|
svm/svm_attribute.h
|
||||||
|
svm/svm_bsdf.h
|
||||||
|
svm/svm_closure.h
|
||||||
|
svm/svm_convert.h
|
||||||
|
svm/svm_displace.h
|
||||||
|
svm/svm_fresnel.h
|
||||||
|
svm/svm_geometry.h
|
||||||
|
svm/svm_gradient.h
|
||||||
|
svm/svm_image.h
|
||||||
|
svm/svm_light_path.h
|
||||||
|
svm/svm_magic.h
|
||||||
|
svm/svm_mapping.h
|
||||||
|
svm/svm_math.h
|
||||||
|
svm/svm_mix.h
|
||||||
|
svm/svm_musgrave.h
|
||||||
|
svm/svm_noise.h
|
||||||
|
svm/svm_noisetex.h
|
||||||
|
svm/svm_sky.h
|
||||||
|
svm/svm_tex_coord.h
|
||||||
|
svm/svm_texture.h
|
||||||
|
svm/svm_types.h
|
||||||
|
svm/svm_value.h
|
||||||
|
svm/svm_voronoi.h
|
||||||
|
svm/svm_wave.h
|
||||||
|
svm/volume.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SRC_UTIL_HEADERS
|
||||||
|
../util/util_color.h
|
||||||
|
../util/util_math.h
|
||||||
|
../util/util_transform.h
|
||||||
|
../util/util_types.h
|
||||||
|
)
|
||||||
|
|
||||||
|
# OSL module
|
||||||
|
|
||||||
|
if(WITH_CYCLES_OSL)
|
||||||
|
add_subdirectory(osl)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# CPU module
|
||||||
|
|
||||||
|
include_directories(${INC})
|
||||||
|
|
||||||
|
add_library(cycles_kernel ${SRC} ${SRC_HEADERS} ${SRC_SVM_HEADERS})
|
||||||
|
|
||||||
|
if(WITH_CYCLES_CUDA)
|
||||||
|
add_dependencies(cycles_kernel cycles_kernel_cuda)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# OPENCL kernel
|
||||||
|
|
||||||
|
#set(KERNEL_PREPROCESSED ${CMAKE_CURRENT_BINARY_DIR}/kernel_preprocessed.cl)
|
||||||
|
#add_custom_command(
|
||||||
|
# OUTPUT ${KERNEL_PREPROCESSED}
|
||||||
|
# COMMAND gcc -x c++ -E ${CMAKE_CURRENT_SOURCE_DIR}/kernel.cl -I ${CMAKE_CURRENT_SOURCE_DIR}/../util/ -DCCL_NAMESPACE_BEGIN= -DCCL_NAMESPACE_END= -DWITH_OPENCL -o ${KERNEL_PREPROCESSED}
|
||||||
|
# DEPENDS ${SRC_KERNEL} ${SRC_UTIL_HEADERS})
|
||||||
|
#add_custom_target(cycles_kernel_preprocess ALL DEPENDS ${KERNEL_PREPROCESSED})
|
||||||
|
#delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${KERNEL_PREPROCESSED}" ${CYCLES_INSTALL_PATH}/kernel)
|
||||||
|
|
||||||
|
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernel.cl" ${CYCLES_INSTALL_PATH}/kernel)
|
||||||
|
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernel.cu" ${CYCLES_INSTALL_PATH}/kernel)
|
||||||
|
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel)
|
||||||
|
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_SVM_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/svm)
|
||||||
|
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_UTIL_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel)
|
94
intern/cycles/kernel/kernel.cl
Normal file
94
intern/cycles/kernel/kernel.cl
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* OpenCL kernel entry points - unfinished */
|
||||||
|
|
||||||
|
#include "kernel_compat_opencl.h"
|
||||||
|
#include "kernel_math.h"
|
||||||
|
#include "kernel_types.h"
|
||||||
|
#include "kernel_globals.h"
|
||||||
|
|
||||||
|
#include "kernel_film.h"
|
||||||
|
#include "kernel_path.h"
|
||||||
|
//#include "kernel_displace.h"
|
||||||
|
|
||||||
|
__kernel void kernel_ocl_path_trace(
|
||||||
|
__constant KernelData *data,
|
||||||
|
__global float4 *buffer,
|
||||||
|
__global uint *rng_state,
|
||||||
|
|
||||||
|
#define KERNEL_TEX(type, ttype, name) \
|
||||||
|
__global type *name, \
|
||||||
|
int name##_width,
|
||||||
|
#include "kernel_textures.h"
|
||||||
|
|
||||||
|
int sample,
|
||||||
|
int sx, int sy, int sw, int sh)
|
||||||
|
{
|
||||||
|
KernelGlobals kglobals, *kg = &kglobals;
|
||||||
|
|
||||||
|
kg->data = data;
|
||||||
|
|
||||||
|
#define KERNEL_TEX(type, ttype, name) \
|
||||||
|
kg->name = name; \
|
||||||
|
kg->name##_width = name##_width;
|
||||||
|
#include "kernel_textures.h"
|
||||||
|
|
||||||
|
int x = sx + get_global_id(0);
|
||||||
|
int y = sy + get_global_id(1);
|
||||||
|
|
||||||
|
if(x < sx + sw && y < sy + sh)
|
||||||
|
kernel_path_trace(kg, buffer, rng_state, sample, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
__kernel void kernel_ocl_tonemap(
|
||||||
|
__constant KernelData *data,
|
||||||
|
__global uchar4 *rgba,
|
||||||
|
__global float4 *buffer,
|
||||||
|
|
||||||
|
#define KERNEL_TEX(type, ttype, name) \
|
||||||
|
__global type *name, \
|
||||||
|
int name##_width,
|
||||||
|
#include "kernel_textures.h"
|
||||||
|
|
||||||
|
int sample, int resolution,
|
||||||
|
int sx, int sy, int sw, int sh)
|
||||||
|
{
|
||||||
|
KernelGlobals kglobals, *kg = &kglobals;
|
||||||
|
|
||||||
|
kg->data = data;
|
||||||
|
|
||||||
|
#define KERNEL_TEX(type, ttype, name) \
|
||||||
|
kg->name = name; \
|
||||||
|
kg->name##_width = name##_width;
|
||||||
|
#include "kernel_textures.h"
|
||||||
|
|
||||||
|
int x = sx + get_global_id(0);
|
||||||
|
int y = sy + get_global_id(1);
|
||||||
|
|
||||||
|
if(x < sx + sw && y < sy + sh)
|
||||||
|
kernel_film_tonemap(kg, rgba, buffer, sample, resolution, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*__kernel void kernel_ocl_displace(__global uint4 *input, __global float3 *offset, int sx)
|
||||||
|
{
|
||||||
|
int x = sx + get_global_id(0);
|
||||||
|
|
||||||
|
kernel_displace(input, offset, x);
|
||||||
|
}*/
|
||||||
|
|
227
intern/cycles/kernel/kernel.cpp
Normal file
227
intern/cycles/kernel/kernel.cpp
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* CPU kernel entry points */
|
||||||
|
|
||||||
|
#include "kernel.h"
|
||||||
|
#include "kernel_compat_cpu.h"
|
||||||
|
#include "kernel_math.h"
|
||||||
|
#include "kernel_types.h"
|
||||||
|
#include "kernel_globals.h"
|
||||||
|
#include "kernel_film.h"
|
||||||
|
#include "kernel_path.h"
|
||||||
|
#include "kernel_displace.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* Globals */
|
||||||
|
|
||||||
|
KernelGlobals *kernel_globals_create()
|
||||||
|
{
|
||||||
|
KernelGlobals *kg = new KernelGlobals();
|
||||||
|
#ifdef WITH_OSL
|
||||||
|
kg->osl.use = false;
|
||||||
|
#endif
|
||||||
|
return kg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void kernel_globals_free(KernelGlobals *kg)
|
||||||
|
{
|
||||||
|
delete kg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OSL */
|
||||||
|
|
||||||
|
#ifdef WITH_OSL
|
||||||
|
|
||||||
|
void *kernel_osl_memory(KernelGlobals *kg)
|
||||||
|
{
|
||||||
|
return (void*)&kg->osl;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool kernel_osl_use(KernelGlobals *kg)
|
||||||
|
{
|
||||||
|
return kg->osl.use;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Memory Copy */
|
||||||
|
|
||||||
|
void kernel_const_copy(KernelGlobals *kg, const char *name, void *host, size_t size)
|
||||||
|
{
|
||||||
|
if(strcmp(name, "__data") == 0)
|
||||||
|
memcpy(&kg->__data, host, size);
|
||||||
|
else
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t width, size_t height)
|
||||||
|
{
|
||||||
|
if(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#define KERNEL_TEX(type, ttype, tname) \
|
||||||
|
else if(strcmp(name, #tname) == 0) { \
|
||||||
|
kg->tname.data = (type*)mem; \
|
||||||
|
kg->tname.width = width; \
|
||||||
|
}
|
||||||
|
#define KERNEL_IMAGE_TEX(type, ttype, tname)
|
||||||
|
#include "kernel_textures.h"
|
||||||
|
|
||||||
|
else if(strstr(name, "__tex_image")) {
|
||||||
|
texture_image_uchar4 *tex = NULL;
|
||||||
|
int id = atoi(name + strlen("__tex_image_"));
|
||||||
|
|
||||||
|
switch(id) {
|
||||||
|
case 0: tex = &kg->__tex_image_000; break;
|
||||||
|
case 1: tex = &kg->__tex_image_001; break;
|
||||||
|
case 2: tex = &kg->__tex_image_002; break;
|
||||||
|
case 3: tex = &kg->__tex_image_003; break;
|
||||||
|
case 4: tex = &kg->__tex_image_004; break;
|
||||||
|
case 5: tex = &kg->__tex_image_005; break;
|
||||||
|
case 6: tex = &kg->__tex_image_006; break;
|
||||||
|
case 7: tex = &kg->__tex_image_007; break;
|
||||||
|
case 8: tex = &kg->__tex_image_008; break;
|
||||||
|
case 9: tex = &kg->__tex_image_009; break;
|
||||||
|
case 10: tex = &kg->__tex_image_010; break;
|
||||||
|
case 11: tex = &kg->__tex_image_011; break;
|
||||||
|
case 12: tex = &kg->__tex_image_012; break;
|
||||||
|
case 13: tex = &kg->__tex_image_013; break;
|
||||||
|
case 14: tex = &kg->__tex_image_014; break;
|
||||||
|
case 15: tex = &kg->__tex_image_015; break;
|
||||||
|
case 16: tex = &kg->__tex_image_016; break;
|
||||||
|
case 17: tex = &kg->__tex_image_017; break;
|
||||||
|
case 18: tex = &kg->__tex_image_018; break;
|
||||||
|
case 19: tex = &kg->__tex_image_019; break;
|
||||||
|
case 20: tex = &kg->__tex_image_020; break;
|
||||||
|
case 21: tex = &kg->__tex_image_021; break;
|
||||||
|
case 22: tex = &kg->__tex_image_022; break;
|
||||||
|
case 23: tex = &kg->__tex_image_023; break;
|
||||||
|
case 24: tex = &kg->__tex_image_024; break;
|
||||||
|
case 25: tex = &kg->__tex_image_025; break;
|
||||||
|
case 26: tex = &kg->__tex_image_026; break;
|
||||||
|
case 27: tex = &kg->__tex_image_027; break;
|
||||||
|
case 28: tex = &kg->__tex_image_028; break;
|
||||||
|
case 29: tex = &kg->__tex_image_029; break;
|
||||||
|
case 30: tex = &kg->__tex_image_030; break;
|
||||||
|
case 31: tex = &kg->__tex_image_031; break;
|
||||||
|
case 32: tex = &kg->__tex_image_032; break;
|
||||||
|
case 33: tex = &kg->__tex_image_033; break;
|
||||||
|
case 34: tex = &kg->__tex_image_034; break;
|
||||||
|
case 35: tex = &kg->__tex_image_035; break;
|
||||||
|
case 36: tex = &kg->__tex_image_036; break;
|
||||||
|
case 37: tex = &kg->__tex_image_037; break;
|
||||||
|
case 38: tex = &kg->__tex_image_038; break;
|
||||||
|
case 39: tex = &kg->__tex_image_039; break;
|
||||||
|
case 40: tex = &kg->__tex_image_040; break;
|
||||||
|
case 41: tex = &kg->__tex_image_041; break;
|
||||||
|
case 42: tex = &kg->__tex_image_042; break;
|
||||||
|
case 43: tex = &kg->__tex_image_043; break;
|
||||||
|
case 44: tex = &kg->__tex_image_044; break;
|
||||||
|
case 45: tex = &kg->__tex_image_045; break;
|
||||||
|
case 46: tex = &kg->__tex_image_046; break;
|
||||||
|
case 47: tex = &kg->__tex_image_047; break;
|
||||||
|
case 48: tex = &kg->__tex_image_048; break;
|
||||||
|
case 49: tex = &kg->__tex_image_049; break;
|
||||||
|
case 50: tex = &kg->__tex_image_050; break;
|
||||||
|
case 51: tex = &kg->__tex_image_051; break;
|
||||||
|
case 52: tex = &kg->__tex_image_052; break;
|
||||||
|
case 53: tex = &kg->__tex_image_053; break;
|
||||||
|
case 54: tex = &kg->__tex_image_054; break;
|
||||||
|
case 55: tex = &kg->__tex_image_055; break;
|
||||||
|
case 56: tex = &kg->__tex_image_056; break;
|
||||||
|
case 57: tex = &kg->__tex_image_057; break;
|
||||||
|
case 58: tex = &kg->__tex_image_058; break;
|
||||||
|
case 59: tex = &kg->__tex_image_059; break;
|
||||||
|
case 60: tex = &kg->__tex_image_060; break;
|
||||||
|
case 61: tex = &kg->__tex_image_061; break;
|
||||||
|
case 62: tex = &kg->__tex_image_062; break;
|
||||||
|
case 63: tex = &kg->__tex_image_063; break;
|
||||||
|
case 64: tex = &kg->__tex_image_064; break;
|
||||||
|
case 65: tex = &kg->__tex_image_065; break;
|
||||||
|
case 66: tex = &kg->__tex_image_066; break;
|
||||||
|
case 67: tex = &kg->__tex_image_067; break;
|
||||||
|
case 68: tex = &kg->__tex_image_068; break;
|
||||||
|
case 69: tex = &kg->__tex_image_069; break;
|
||||||
|
case 70: tex = &kg->__tex_image_070; break;
|
||||||
|
case 71: tex = &kg->__tex_image_071; break;
|
||||||
|
case 72: tex = &kg->__tex_image_072; break;
|
||||||
|
case 73: tex = &kg->__tex_image_073; break;
|
||||||
|
case 74: tex = &kg->__tex_image_074; break;
|
||||||
|
case 75: tex = &kg->__tex_image_075; break;
|
||||||
|
case 76: tex = &kg->__tex_image_076; break;
|
||||||
|
case 77: tex = &kg->__tex_image_077; break;
|
||||||
|
case 78: tex = &kg->__tex_image_078; break;
|
||||||
|
case 79: tex = &kg->__tex_image_079; break;
|
||||||
|
case 80: tex = &kg->__tex_image_080; break;
|
||||||
|
case 81: tex = &kg->__tex_image_081; break;
|
||||||
|
case 82: tex = &kg->__tex_image_082; break;
|
||||||
|
case 83: tex = &kg->__tex_image_083; break;
|
||||||
|
case 84: tex = &kg->__tex_image_084; break;
|
||||||
|
case 85: tex = &kg->__tex_image_085; break;
|
||||||
|
case 86: tex = &kg->__tex_image_086; break;
|
||||||
|
case 87: tex = &kg->__tex_image_087; break;
|
||||||
|
case 88: tex = &kg->__tex_image_088; break;
|
||||||
|
case 89: tex = &kg->__tex_image_089; break;
|
||||||
|
case 90: tex = &kg->__tex_image_090; break;
|
||||||
|
case 91: tex = &kg->__tex_image_091; break;
|
||||||
|
case 92: tex = &kg->__tex_image_092; break;
|
||||||
|
case 93: tex = &kg->__tex_image_093; break;
|
||||||
|
case 94: tex = &kg->__tex_image_094; break;
|
||||||
|
case 95: tex = &kg->__tex_image_095; break;
|
||||||
|
case 96: tex = &kg->__tex_image_096; break;
|
||||||
|
case 97: tex = &kg->__tex_image_097; break;
|
||||||
|
case 98: tex = &kg->__tex_image_098; break;
|
||||||
|
case 99: tex = &kg->__tex_image_099; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tex) {
|
||||||
|
tex->data = (uchar4*)mem;
|
||||||
|
tex->width = width;
|
||||||
|
tex->height = height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Path Tracing */
|
||||||
|
|
||||||
|
void kernel_cpu_path_trace(KernelGlobals *kg, float4 *buffer, unsigned int *rng_state, int sample, int x, int y)
|
||||||
|
{
|
||||||
|
kernel_path_trace(kg, buffer, rng_state, sample, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tonemapping */
|
||||||
|
|
||||||
|
void kernel_cpu_tonemap(KernelGlobals *kg, uchar4 *rgba, float4 *buffer, int sample, int resolution, int x, int y)
|
||||||
|
{
|
||||||
|
kernel_film_tonemap(kg, rgba, buffer, sample, resolution, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Displacement */
|
||||||
|
|
||||||
|
void kernel_cpu_displace(KernelGlobals *kg, uint4 *input, float3 *offset, int i)
|
||||||
|
{
|
||||||
|
kernel_displace(kg, input, offset, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
53
intern/cycles/kernel/kernel.cu
Normal file
53
intern/cycles/kernel/kernel.cu
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* CUDA kernel entry points */
|
||||||
|
|
||||||
|
#include "kernel_compat_cuda.h"
|
||||||
|
#include "kernel_math.h"
|
||||||
|
#include "kernel_types.h"
|
||||||
|
#include "kernel_globals.h"
|
||||||
|
#include "kernel_film.h"
|
||||||
|
#include "kernel_path.h"
|
||||||
|
#include "kernel_displace.h"
|
||||||
|
|
||||||
|
extern "C" __global__ void kernel_cuda_path_trace(float4 *buffer, uint *rng_state, int sample, int sx, int sy, int sw, int sh)
|
||||||
|
{
|
||||||
|
int x = sx + blockDim.x*blockIdx.x + threadIdx.x;
|
||||||
|
int y = sy + blockDim.y*blockIdx.y + threadIdx.y;
|
||||||
|
|
||||||
|
if(x < sx + sw && y < sy + sh)
|
||||||
|
kernel_path_trace(NULL, buffer, rng_state, sample, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" __global__ void kernel_cuda_tonemap(uchar4 *rgba, float4 *buffer, int sample, int resolution, int sx, int sy, int sw, int sh)
|
||||||
|
{
|
||||||
|
int x = sx + blockDim.x*blockIdx.x + threadIdx.x;
|
||||||
|
int y = sy + blockDim.y*blockIdx.y + threadIdx.y;
|
||||||
|
|
||||||
|
if(x < sx + sw && y < sy + sh)
|
||||||
|
kernel_film_tonemap(NULL, rgba, buffer, sample, resolution, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" __global__ void kernel_cuda_displace(uint4 *input, float3 *offset, int sx)
|
||||||
|
{
|
||||||
|
int x = sx + blockDim.x*blockIdx.x + threadIdx.x;
|
||||||
|
|
||||||
|
kernel_displace(NULL, input, offset, x);
|
||||||
|
}
|
||||||
|
|
47
intern/cycles/kernel/kernel.h
Normal file
47
intern/cycles/kernel/kernel.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __KERNEL_H__
|
||||||
|
#define __KERNEL_H__
|
||||||
|
|
||||||
|
/* CPU Kernel Interfae */
|
||||||
|
|
||||||
|
#include "util_types.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
struct KernelGlobals;
|
||||||
|
|
||||||
|
KernelGlobals *kernel_globals_create();
|
||||||
|
void kernel_globals_free(KernelGlobals *kg);
|
||||||
|
|
||||||
|
void *kernel_osl_memory(KernelGlobals *kg);
|
||||||
|
bool kernel_osl_use(KernelGlobals *kg);
|
||||||
|
|
||||||
|
void kernel_const_copy(KernelGlobals *kg, const char *name, void *host, size_t size);
|
||||||
|
void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t width, size_t height);
|
||||||
|
|
||||||
|
void kernel_cpu_path_trace(KernelGlobals *kg, float4 *buffer, unsigned int *rng_state, int sample, int x, int y);
|
||||||
|
void kernel_cpu_tonemap(KernelGlobals *kg, uchar4 *rgba, float4 *buffer, int sample, int resolution, int x, int y);
|
||||||
|
|
||||||
|
void kernel_cpu_displace(KernelGlobals *kg, uint4 *input, float3 *offset, int i);
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* __KERNEL_H__ */
|
||||||
|
|
375
intern/cycles/kernel/kernel_bvh.h
Normal file
375
intern/cycles/kernel/kernel_bvh.h
Normal file
@ -0,0 +1,375 @@
|
|||||||
|
/*
|
||||||
|
* Adapted from code Copyright 2009-2010 NVIDIA Corporation
|
||||||
|
* Modifications Copyright 2011, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "Persistent while-while kernel" used in:
|
||||||
|
*
|
||||||
|
* "Understanding the Efficiency of Ray Traversal on GPUs",
|
||||||
|
* Timo Aila and Samuli Laine,
|
||||||
|
* Proc. High-Performance Graphics 2009
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* bottom-most stack entry, indicating the end of traversal */
|
||||||
|
|
||||||
|
#define ENTRYPOINT_SENTINEL 0x76543210
|
||||||
|
/* 64 object BVH + 64 mesh BVH + 64 object node splitting */
|
||||||
|
#define BVH_STACK_SIZE 192
|
||||||
|
#define BVH_NODE_SIZE 4
|
||||||
|
#define TRI_NODE_SIZE 3
|
||||||
|
|
||||||
|
__device_inline float3 bvh_inverse_direction(float3 dir)
|
||||||
|
{
|
||||||
|
/* avoid divide by zero (ooeps = exp2f(-80.0f)) */
|
||||||
|
float ooeps = 0.00000000000000000000000082718061255302767487140869206996285356581211090087890625f;
|
||||||
|
float3 idir;
|
||||||
|
|
||||||
|
idir.x = 1.0f/((fabsf(dir.x) > ooeps)? dir.x: copysignf(ooeps, dir.x));
|
||||||
|
idir.y = 1.0f/((fabsf(dir.y) > ooeps)? dir.y: copysignf(ooeps, dir.y));
|
||||||
|
idir.z = 1.0f/((fabsf(dir.z) > ooeps)? dir.z: copysignf(ooeps, dir.z));
|
||||||
|
|
||||||
|
return idir;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device_inline void bvh_instance_push(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *idir, float *t, const float tmax)
|
||||||
|
{
|
||||||
|
Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
|
||||||
|
|
||||||
|
*P = transform(&tfm, ray->P);
|
||||||
|
|
||||||
|
float3 dir = transform_direction(&tfm, ray->D);
|
||||||
|
|
||||||
|
float len;
|
||||||
|
dir = normalize_len(dir, &len);
|
||||||
|
|
||||||
|
*idir = bvh_inverse_direction(dir);
|
||||||
|
|
||||||
|
if(*t != FLT_MAX)
|
||||||
|
*t *= len;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device_inline void bvh_instance_pop(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *idir, float *t, const float tmax)
|
||||||
|
{
|
||||||
|
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
|
||||||
|
|
||||||
|
if(*t != FLT_MAX)
|
||||||
|
*t *= len(transform_direction(&tfm, 1.0f/(*idir)));
|
||||||
|
|
||||||
|
*P = ray->P;
|
||||||
|
*idir = bvh_inverse_direction(ray->D);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* intersect two bounding boxes */
|
||||||
|
__device_inline void bvh_node_intersect(KernelGlobals *kg,
|
||||||
|
bool *traverseChild0, bool *traverseChild1,
|
||||||
|
bool *closestChild1, int *nodeAddr0, int *nodeAddr1,
|
||||||
|
float3 P, float3 idir, float t, uint visibility, int nodeAddr)
|
||||||
|
{
|
||||||
|
/* fetch node data */
|
||||||
|
float4 n0xy = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0);
|
||||||
|
float4 n1xy = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1);
|
||||||
|
float4 nz = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2);
|
||||||
|
float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3);
|
||||||
|
|
||||||
|
/* intersect ray against child nodes */
|
||||||
|
float3 ood = P * idir;
|
||||||
|
float c0lox = n0xy.x * idir.x - ood.x;
|
||||||
|
float c0hix = n0xy.y * idir.x - ood.x;
|
||||||
|
float c0loy = n0xy.z * idir.y - ood.y;
|
||||||
|
float c0hiy = n0xy.w * idir.y - ood.y;
|
||||||
|
float c0loz = nz.x * idir.z - ood.z;
|
||||||
|
float c0hiz = nz.y * idir.z - ood.z;
|
||||||
|
float c1loz = nz.z * idir.z - ood.z;
|
||||||
|
float c1hiz = nz.w * idir.z - ood.z;
|
||||||
|
|
||||||
|
float c0min_x = min(c0lox, c0hix);
|
||||||
|
float c0min_y = min(c0loy, c0hiy);
|
||||||
|
float c0min_z = min(c0loz, c0hiz);
|
||||||
|
|
||||||
|
float c0min = max4(c0min_x, c0min_y, c0min_z, 0.0f);
|
||||||
|
float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t);
|
||||||
|
float c1lox = n1xy.x * idir.x - ood.x;
|
||||||
|
float c1hix = n1xy.y * idir.x - ood.x;
|
||||||
|
float c1loy = n1xy.z * idir.y - ood.y;
|
||||||
|
float c1hiy = n1xy.w * idir.y - ood.y;
|
||||||
|
float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
|
||||||
|
float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
|
||||||
|
|
||||||
|
/* decide which nodes to traverse next */
|
||||||
|
#ifdef __VISIBILITY_FLAG__
|
||||||
|
/* this visibility test gives a 5% performance hit, how to solve? */
|
||||||
|
*traverseChild0 = (c0max >= c0min) && (__float_as_int(cnodes.z) & visibility);
|
||||||
|
*traverseChild1 = (c1max >= c1min) && (__float_as_int(cnodes.w) & visibility);
|
||||||
|
#else
|
||||||
|
*traverseChild0 = (c0max >= c0min);
|
||||||
|
*traverseChild1 = (c1max >= c1min);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
*nodeAddr0 = __float_as_int(cnodes.x);
|
||||||
|
*nodeAddr1 = __float_as_int(cnodes.y);
|
||||||
|
|
||||||
|
*closestChild1 = (c1min < c0min);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sven Woop's algorithm */
|
||||||
|
__device_inline void bvh_triangle_intersect(KernelGlobals *kg, Intersection *isect,
|
||||||
|
float3 P, float3 idir, uint visibility, int object, int triAddr)
|
||||||
|
{
|
||||||
|
/* compute and check intersection t-value */
|
||||||
|
float4 v00 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0);
|
||||||
|
float4 v11 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1);
|
||||||
|
float3 dir = 1.0f/idir;
|
||||||
|
|
||||||
|
float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z;
|
||||||
|
float invDz = 1.0f/(dir.x*v00.x + dir.y*v00.y + dir.z*v00.z);
|
||||||
|
float t = Oz * invDz;
|
||||||
|
|
||||||
|
if(t > 0.0f && t < isect->t) {
|
||||||
|
/* compute and check barycentric u */
|
||||||
|
float Ox = v11.w + P.x*v11.x + P.y*v11.y + P.z*v11.z;
|
||||||
|
float Dx = dir.x*v11.x + dir.y*v11.y + dir.z*v11.z;
|
||||||
|
float u = Ox + t*Dx;
|
||||||
|
|
||||||
|
if(u >= 0.0f) {
|
||||||
|
/* compute and check barycentric v */
|
||||||
|
float4 v22 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2);
|
||||||
|
float Oy = v22.w + P.x*v22.x + P.y*v22.y + P.z*v22.z;
|
||||||
|
float Dy = dir.x*v22.x + dir.y*v22.y + dir.z*v22.z;
|
||||||
|
float v = Oy + t*Dy;
|
||||||
|
|
||||||
|
if(v >= 0.0f && u + v <= 1.0f) {
|
||||||
|
#ifdef __VISIBILITY_FLAG__
|
||||||
|
/* visibility flag test. we do it here under the assumption
|
||||||
|
that most triangles are culled by node flags */
|
||||||
|
if(kernel_tex_fetch(__prim_visibility, triAddr) & visibility)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
/* record intersection */
|
||||||
|
isect->prim = triAddr;
|
||||||
|
isect->object = object;
|
||||||
|
isect->u = u;
|
||||||
|
isect->v = v;
|
||||||
|
isect->t = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__device_inline bool scene_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect)
|
||||||
|
{
|
||||||
|
/* traversal stack in CUDA thread-local memory */
|
||||||
|
int traversalStack[BVH_STACK_SIZE];
|
||||||
|
traversalStack[0] = ENTRYPOINT_SENTINEL;
|
||||||
|
|
||||||
|
/* traversal variables in registers */
|
||||||
|
int stackPtr = 0;
|
||||||
|
int nodeAddr = kernel_data.bvh.root;
|
||||||
|
|
||||||
|
/* ray parameters in registers */
|
||||||
|
const float tmax = ray->t;
|
||||||
|
float3 P = ray->P;
|
||||||
|
float3 idir = bvh_inverse_direction(ray->D);
|
||||||
|
int object = ~0;
|
||||||
|
|
||||||
|
isect->t = tmax;
|
||||||
|
isect->object = ~0;
|
||||||
|
isect->prim = ~0;
|
||||||
|
isect->u = 0.0f;
|
||||||
|
isect->v = 0.0f;
|
||||||
|
|
||||||
|
/* traversal loop */
|
||||||
|
do {
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* traverse internal nodes */
|
||||||
|
while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL)
|
||||||
|
{
|
||||||
|
bool traverseChild0, traverseChild1, closestChild1;
|
||||||
|
int nodeAddrChild1;
|
||||||
|
|
||||||
|
bvh_node_intersect(kg, &traverseChild0, &traverseChild1,
|
||||||
|
&closestChild1, &nodeAddr, &nodeAddrChild1,
|
||||||
|
P, idir, isect->t, visibility, nodeAddr);
|
||||||
|
|
||||||
|
if(traverseChild0 != traverseChild1) {
|
||||||
|
/* one child was intersected */
|
||||||
|
if(traverseChild1) {
|
||||||
|
nodeAddr = nodeAddrChild1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(!traverseChild0) {
|
||||||
|
/* neither child was intersected */
|
||||||
|
nodeAddr = traversalStack[stackPtr];
|
||||||
|
--stackPtr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* both children were intersected, push the farther one */
|
||||||
|
if(closestChild1) {
|
||||||
|
int tmp = nodeAddr;
|
||||||
|
nodeAddr = nodeAddrChild1;
|
||||||
|
nodeAddrChild1 = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
++stackPtr;
|
||||||
|
traversalStack[stackPtr] = nodeAddrChild1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if node is leaf, fetch triangle list */
|
||||||
|
if(nodeAddr < 0) {
|
||||||
|
float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_NODE_SIZE+(BVH_NODE_SIZE-1));
|
||||||
|
int primAddr = __float_as_int(leaf.x);
|
||||||
|
|
||||||
|
#ifdef __INSTANCING__
|
||||||
|
if(primAddr >= 0) {
|
||||||
|
#endif
|
||||||
|
int primAddr2 = __float_as_int(leaf.y);
|
||||||
|
|
||||||
|
/* pop */
|
||||||
|
nodeAddr = traversalStack[stackPtr];
|
||||||
|
--stackPtr;
|
||||||
|
|
||||||
|
/* triangle intersection */
|
||||||
|
while(primAddr < primAddr2) {
|
||||||
|
/* intersect ray against triangle */
|
||||||
|
bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr);
|
||||||
|
|
||||||
|
/* shadow ray early termination */
|
||||||
|
if(visibility == PATH_RAY_SHADOW_OPAQUE && isect->prim != ~0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
primAddr++;
|
||||||
|
}
|
||||||
|
#ifdef __INSTANCING__
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* instance push */
|
||||||
|
object = kernel_tex_fetch(__prim_object, -primAddr-1);
|
||||||
|
|
||||||
|
bvh_instance_push(kg, object, ray, &P, &idir, &isect->t, tmax);
|
||||||
|
|
||||||
|
++stackPtr;
|
||||||
|
traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
|
||||||
|
|
||||||
|
nodeAddr = kernel_tex_fetch(__object_node, object);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} while(nodeAddr != ENTRYPOINT_SENTINEL);
|
||||||
|
|
||||||
|
#ifdef __INSTANCING__
|
||||||
|
if(stackPtr >= 0) {
|
||||||
|
kernel_assert(object != ~0);
|
||||||
|
|
||||||
|
/* instance pop */
|
||||||
|
bvh_instance_pop(kg, object, ray, &P, &idir, &isect->t, tmax);
|
||||||
|
object = ~0;
|
||||||
|
nodeAddr = traversalStack[stackPtr];
|
||||||
|
--stackPtr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} while(nodeAddr != ENTRYPOINT_SENTINEL);
|
||||||
|
|
||||||
|
return (isect->prim != ~0);
|
||||||
|
}
|
||||||
|
|
||||||
|
__device_inline float3 ray_offset(float3 P, float3 Ng)
|
||||||
|
{
|
||||||
|
#ifdef __INTERSECTION_REFINE__
|
||||||
|
const float epsilon_f = 1e-5f;
|
||||||
|
const int epsilon_i = 32;
|
||||||
|
|
||||||
|
float3 res;
|
||||||
|
|
||||||
|
/* x component */
|
||||||
|
if(fabsf(P.x) < epsilon_f) {
|
||||||
|
res.x = P.x + Ng.x*epsilon_f;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uint ix = __float_as_uint(P.x);
|
||||||
|
ix += ((ix ^ __float_as_uint(Ng.x)) >> 31)? -epsilon_i: epsilon_i;
|
||||||
|
res.x = __uint_as_float(ix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* y component */
|
||||||
|
if(fabsf(P.y) < epsilon_f) {
|
||||||
|
res.y = P.y + Ng.y*epsilon_f;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uint iy = __float_as_uint(P.y);
|
||||||
|
iy += ((iy ^ __float_as_uint(Ng.y)) >> 31)? -epsilon_i: epsilon_i;
|
||||||
|
res.y = __uint_as_float(iy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* z component */
|
||||||
|
if(fabsf(P.z) < epsilon_f) {
|
||||||
|
res.z = P.z + Ng.z*epsilon_f;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uint iz = __float_as_uint(P.z);
|
||||||
|
iz += ((iz ^ __float_as_uint(Ng.z)) >> 31)? -epsilon_i: epsilon_i;
|
||||||
|
res.z = __uint_as_float(iz);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
#else
|
||||||
|
const float epsilon_f = 1e-4f;
|
||||||
|
return P + epsilon_f*Ng;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
__device_inline float3 bvh_triangle_refine(KernelGlobals *kg, const Intersection *isect, const Ray *ray)
|
||||||
|
{
|
||||||
|
float3 P = ray->P;
|
||||||
|
float3 D = ray->D;
|
||||||
|
float t = isect->t;
|
||||||
|
|
||||||
|
#ifdef __INTERSECTION_REFINE__
|
||||||
|
if(isect->object != ~0) {
|
||||||
|
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM);
|
||||||
|
|
||||||
|
P = transform(&tfm, P);
|
||||||
|
D = transform_direction(&tfm, D*t);
|
||||||
|
D = normalize_len(D, &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
P = P + D*t;
|
||||||
|
|
||||||
|
float4 v00 = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0);
|
||||||
|
float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z;
|
||||||
|
float invDz = 1.0f/(D.x*v00.x + D.y*v00.y + D.z*v00.z);
|
||||||
|
float rt = Oz * invDz;
|
||||||
|
|
||||||
|
P = P + D*rt;
|
||||||
|
|
||||||
|
if(isect->object != ~0) {
|
||||||
|
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM);
|
||||||
|
P = transform(&tfm, P);
|
||||||
|
}
|
||||||
|
|
||||||
|
return P;
|
||||||
|
#else
|
||||||
|
return P + D*t;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
144
intern/cycles/kernel/kernel_camera.h
Normal file
144
intern/cycles/kernel/kernel_camera.h
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* Perspective Camera */
|
||||||
|
|
||||||
|
__device float2 camera_sample_aperture(KernelGlobals *kg, float u, float v)
|
||||||
|
{
|
||||||
|
float blades = kernel_data.cam.blades;
|
||||||
|
|
||||||
|
if(blades == 0.0f) {
|
||||||
|
/* sample disk */
|
||||||
|
return concentric_sample_disk(u, v);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* sample polygon */
|
||||||
|
float rotation = kernel_data.cam.bladesrotation;
|
||||||
|
return regular_polygon_sample(blades, rotation, u, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__device void camera_sample_perspective(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, Ray *ray)
|
||||||
|
{
|
||||||
|
/* create ray form raster position */
|
||||||
|
Transform rastertocamera = kernel_data.cam.rastertocamera;
|
||||||
|
float3 Pcamera = transform(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
|
||||||
|
|
||||||
|
ray->P = make_float3(0.0f, 0.0f, 0.0f);
|
||||||
|
ray->D = Pcamera;
|
||||||
|
|
||||||
|
/* modify ray for depth of field */
|
||||||
|
float aperturesize = kernel_data.cam.aperturesize;
|
||||||
|
|
||||||
|
if(aperturesize > 0.0f) {
|
||||||
|
/* sample point on aperture */
|
||||||
|
float2 lensuv = camera_sample_aperture(kg, lens_u, lens_v)*aperturesize;
|
||||||
|
|
||||||
|
/* compute point on plane of focus */
|
||||||
|
float ft = kernel_data.cam.focaldistance/ray->D.z;
|
||||||
|
float3 Pfocus = ray->P + ray->D*ft;
|
||||||
|
|
||||||
|
/* update ray for effect of lens */
|
||||||
|
ray->P = make_float3(lensuv.x, lensuv.y, 0.0f);
|
||||||
|
ray->D = normalize(Pfocus - ray->P);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* transform ray from camera to world */
|
||||||
|
Transform cameratoworld = kernel_data.cam.cameratoworld;
|
||||||
|
|
||||||
|
ray->P = transform(&cameratoworld, ray->P);
|
||||||
|
ray->D = transform_direction(&cameratoworld, ray->D);
|
||||||
|
ray->D = normalize(ray->D);
|
||||||
|
|
||||||
|
#ifdef __RAY_DIFFERENTIALS__
|
||||||
|
/* ray differential */
|
||||||
|
float3 Ddiff = transform_direction(&cameratoworld, Pcamera);
|
||||||
|
|
||||||
|
ray->dP.dx = make_float3(0.0f, 0.0f, 0.0f);
|
||||||
|
ray->dP.dy = make_float3(0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
ray->dD.dx = normalize(Ddiff + kernel_data.cam.dx) - normalize(Ddiff);
|
||||||
|
ray->dD.dy = normalize(Ddiff + kernel_data.cam.dy) - normalize(Ddiff);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __CAMERA_CLIPPING__
|
||||||
|
/* clipping */
|
||||||
|
ray->P += kernel_data.cam.nearclip*ray->D;
|
||||||
|
ray->t = kernel_data.cam.cliplength;
|
||||||
|
#else
|
||||||
|
ray->t = FLT_MAX;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Orthographic Camera */
|
||||||
|
|
||||||
|
__device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, float raster_y, Ray *ray)
|
||||||
|
{
|
||||||
|
/* create ray form raster position */
|
||||||
|
Transform rastertocamera = kernel_data.cam.rastertocamera;
|
||||||
|
float3 Pcamera = transform(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
|
||||||
|
|
||||||
|
ray->P = Pcamera;
|
||||||
|
ray->D = make_float3(0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
/* transform ray from camera to world */
|
||||||
|
Transform cameratoworld = kernel_data.cam.cameratoworld;
|
||||||
|
|
||||||
|
ray->P = transform(&cameratoworld, ray->P);
|
||||||
|
ray->D = transform_direction(&cameratoworld, ray->D);
|
||||||
|
ray->D = normalize(ray->D);
|
||||||
|
|
||||||
|
#ifdef __RAY_DIFFERENTIALS__
|
||||||
|
/* ray differential */
|
||||||
|
ray->dP.dx = kernel_data.cam.dx;
|
||||||
|
ray->dP.dy = kernel_data.cam.dy;
|
||||||
|
|
||||||
|
ray->dD.dx = make_float3(0.0f, 0.0f, 0.0f);
|
||||||
|
ray->dD.dy = make_float3(0.0f, 0.0f, 0.0f);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __CAMERA_CLIPPING__
|
||||||
|
/* clipping */
|
||||||
|
ray->t = kernel_data.cam.cliplength;
|
||||||
|
#else
|
||||||
|
ray->t = FLT_MAX;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Common */
|
||||||
|
|
||||||
|
__device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, float filter_v, float lens_u, float lens_v, Ray *ray)
|
||||||
|
{
|
||||||
|
/* pixel filter */
|
||||||
|
float raster_x = x + kernel_tex_interp(__filter_table, filter_u);
|
||||||
|
float raster_y = y + kernel_tex_interp(__filter_table, filter_v);
|
||||||
|
|
||||||
|
/* motion blur */
|
||||||
|
//ray->time = lerp(time_t, kernel_data.cam.shutter_open, kernel_data.cam.shutter_close);
|
||||||
|
|
||||||
|
/* sample */
|
||||||
|
if(kernel_data.cam.ortho)
|
||||||
|
camera_sample_orthographic(kg, raster_x, raster_y, ray);
|
||||||
|
else
|
||||||
|
camera_sample_perspective(kg, raster_x, raster_y, lens_u, lens_v, ray);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
162
intern/cycles/kernel/kernel_compat_cpu.h
Normal file
162
intern/cycles/kernel/kernel_compat_cpu.h
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __KERNEL_COMPAT_CPU_H__
|
||||||
|
#define __KERNEL_COMPAT_CPU_H__
|
||||||
|
|
||||||
|
#define __KERNEL_CPU__
|
||||||
|
|
||||||
|
#include "util_debug.h"
|
||||||
|
#include "util_math.h"
|
||||||
|
#include "util_types.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* Assertions inside the kernel only work for the CPU device, so we wrap it in
|
||||||
|
a macro which is empty for other devices */
|
||||||
|
|
||||||
|
#define kernel_assert(cond) assert(cond)
|
||||||
|
|
||||||
|
/* Texture types to be compatible with CUDA textures. These are really just
|
||||||
|
simple arrays and after inlining fetch hopefully revert to being a simple
|
||||||
|
pointer lookup. */
|
||||||
|
|
||||||
|
template<typename T> struct texture {
|
||||||
|
T fetch(int index)
|
||||||
|
{
|
||||||
|
kernel_assert(index >= 0 && index < width);
|
||||||
|
return data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
__m128 fetch_m128(int index)
|
||||||
|
{
|
||||||
|
kernel_assert(index >= 0 && index < width);
|
||||||
|
return ((__m128*)data)[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
__m128i fetch_m128i(int index)
|
||||||
|
{
|
||||||
|
kernel_assert(index >= 0 && index < width);
|
||||||
|
return ((__m128i*)data)[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
float interp(float x)
|
||||||
|
{
|
||||||
|
x = clamp(x, 0.0f, 1.0f)*width;
|
||||||
|
|
||||||
|
int index = min((int)x, width-1);
|
||||||
|
int nindex = min(index+1, width-1);
|
||||||
|
float t = x - index;
|
||||||
|
|
||||||
|
return (1.0f - t)*data[index] + t*data[nindex];
|
||||||
|
}
|
||||||
|
|
||||||
|
T *data;
|
||||||
|
int width;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T> struct texture_image {
|
||||||
|
float4 read(float4 r)
|
||||||
|
{
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 read(uchar4 r)
|
||||||
|
{
|
||||||
|
float f = 1.0f/255.0f;
|
||||||
|
return make_float4(r.x*f, r.y*f, r.z*f, r.w*f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int wrap_periodic(int x, int width)
|
||||||
|
{
|
||||||
|
x %= width;
|
||||||
|
if(x < 0)
|
||||||
|
x += width;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wrap_clamp(int x, int width)
|
||||||
|
{
|
||||||
|
return clamp(x, 0, width-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
float frac(float x, int *ix)
|
||||||
|
{
|
||||||
|
int i = (int)x - ((x < 0.0f)? 1: 0);
|
||||||
|
*ix = i;
|
||||||
|
return x - (float)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 interp(float x, float y, bool periodic = true)
|
||||||
|
{
|
||||||
|
if(!data)
|
||||||
|
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
int ix, iy, nix, niy;
|
||||||
|
float tx = frac(x*width, &ix);
|
||||||
|
float ty = frac(y*height, &iy);
|
||||||
|
|
||||||
|
if(periodic) {
|
||||||
|
ix = wrap_periodic(ix, width);
|
||||||
|
iy = wrap_periodic(iy, height);
|
||||||
|
|
||||||
|
nix = wrap_periodic(ix+1, width);
|
||||||
|
niy = wrap_periodic(iy+1, height);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ix = wrap_clamp(ix, width);
|
||||||
|
iy = wrap_clamp(iy, height);
|
||||||
|
|
||||||
|
nix = wrap_clamp(ix+1, width);
|
||||||
|
niy = wrap_clamp(iy+1, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 r = (1.0f - ty)*(1.0f - tx)*read(data[ix + iy*width]);
|
||||||
|
r += (1.0f - ty)*tx*read(data[nix + iy*width]);
|
||||||
|
r += ty*(1.0f - tx)*read(data[ix + niy*width]);
|
||||||
|
r += ty*tx*read(data[nix + niy*width]);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
T *data;
|
||||||
|
int width, height;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef texture<float4> texture_float4;
|
||||||
|
typedef texture<float> texture_float;
|
||||||
|
typedef texture<uint> texture_uint;
|
||||||
|
typedef texture<int> texture_int;
|
||||||
|
typedef texture<uint4> texture_uint4;
|
||||||
|
typedef texture_image<float4> texture_image_float4;
|
||||||
|
typedef texture_image<uchar4> texture_image_uchar4;
|
||||||
|
|
||||||
|
/* Macros to handle different memory storage on different devices */
|
||||||
|
|
||||||
|
#define kernel_tex_fetch(tex, index) (kg->tex.fetch(index))
|
||||||
|
#define kernel_tex_fetch_m128(tex, index) (kg->tex.fetch_m128(index))
|
||||||
|
#define kernel_tex_fetch_m128i(tex, index) (kg->tex.fetch_m128i(index))
|
||||||
|
#define kernel_tex_interp(tex, t) (kg->tex.interp(t))
|
||||||
|
#define kernel_tex_image_interp(tex, x, y) (kg->tex.interp(x, y))
|
||||||
|
|
||||||
|
#define kernel_data (kg->__data)
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* __KERNEL_COMPAT_CPU_H__ */
|
||||||
|
|
64
intern/cycles/kernel/kernel_compat_cuda.h
Normal file
64
intern/cycles/kernel/kernel_compat_cuda.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __KERNEL_COMPAT_CUDA_H__
|
||||||
|
#define __KERNEL_COMPAT_CUDA_H__
|
||||||
|
|
||||||
|
#define __KERNEL_GPU__
|
||||||
|
#define __KERNEL_CUDA__
|
||||||
|
#define CCL_NAMESPACE_BEGIN
|
||||||
|
#define CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#include <cuda.h>
|
||||||
|
#include <float.h>
|
||||||
|
|
||||||
|
#include "util_types.h"
|
||||||
|
|
||||||
|
/* Qualifier wrappers for different names on different devices */
|
||||||
|
|
||||||
|
#define __device __device__ __inline__
|
||||||
|
#define __device_inline __device__ __inline__
|
||||||
|
#define __device_noinline __device__ __noinline__
|
||||||
|
#define __global
|
||||||
|
#define __shared __shared__
|
||||||
|
#define __constant
|
||||||
|
|
||||||
|
/* No assert supported for CUDA */
|
||||||
|
|
||||||
|
#define kernel_assert(cond)
|
||||||
|
|
||||||
|
/* Textures */
|
||||||
|
|
||||||
|
typedef texture<float4, 1> texture_float4;
|
||||||
|
typedef texture<float, 1> texture_float;
|
||||||
|
typedef texture<uint, 1> texture_uint;
|
||||||
|
typedef texture<int, 1> texture_int;
|
||||||
|
typedef texture<uint4, 1> texture_uint4;
|
||||||
|
typedef texture<float4, 2> texture_image_float4;
|
||||||
|
typedef texture<uchar4, 2, cudaReadModeNormalizedFloat> texture_image_uchar4;
|
||||||
|
|
||||||
|
/* Macros to handle different memory storage on different devices */
|
||||||
|
|
||||||
|
#define kernel_tex_fetch(t, index) tex1Dfetch(t, index)
|
||||||
|
#define kernel_tex_interp(t, x) tex1D(t, x)
|
||||||
|
#define kernel_tex_image_interp(t, x, y) tex2D(t, x, y)
|
||||||
|
|
||||||
|
#define kernel_data __data
|
||||||
|
|
||||||
|
#endif /* __KERNEL_COMPAT_CUDA_H__ */
|
||||||
|
|
112
intern/cycles/kernel/kernel_compat_opencl.h
Normal file
112
intern/cycles/kernel/kernel_compat_opencl.h
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __KERNEL_COMPAT_OPENCL_H__
|
||||||
|
#define __KERNEL_COMPAT_OPENCL_H__
|
||||||
|
|
||||||
|
#define __KERNEL_GPU__
|
||||||
|
#define __KERNEL_OPENCL__
|
||||||
|
|
||||||
|
/* no namespaces in opencl */
|
||||||
|
#define CCL_NAMESPACE_BEGIN
|
||||||
|
#define CCL_NAMESPACE_END
|
||||||
|
#define WITH_OPENCL
|
||||||
|
|
||||||
|
/* in opencl all functions are device functions, so leave this empty */
|
||||||
|
#define __device
|
||||||
|
#define __device_inline
|
||||||
|
#define __device_noinline
|
||||||
|
|
||||||
|
/* no assert in opencl */
|
||||||
|
#define kernel_assert(cond)
|
||||||
|
|
||||||
|
/* manual implementation of interpolated 1D lookup */
|
||||||
|
__device float kernel_tex_interp_(__global float *data, int width, float x)
|
||||||
|
{
|
||||||
|
x = clamp(x, 0.0f, 1.0f)*width;
|
||||||
|
|
||||||
|
int index = min((int)x, width-1);
|
||||||
|
int nindex = min(index+1, width-1);
|
||||||
|
float t = x - index;
|
||||||
|
|
||||||
|
return (1.0f - t)*data[index] + t*data[nindex];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make_type definitions with opencl style element initializers */
|
||||||
|
#ifdef make_float2
|
||||||
|
#undef make_float2
|
||||||
|
#endif
|
||||||
|
#ifdef make_float3
|
||||||
|
#undef make_float3
|
||||||
|
#endif
|
||||||
|
#ifdef make_float4
|
||||||
|
#undef make_float4
|
||||||
|
#endif
|
||||||
|
#ifdef make_int2
|
||||||
|
#undef make_int2
|
||||||
|
#endif
|
||||||
|
#ifdef make_int3
|
||||||
|
#undef make_int3
|
||||||
|
#endif
|
||||||
|
#ifdef make_int4
|
||||||
|
#undef make_int4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define make_float2(x, y) ((float2)(x, y))
|
||||||
|
#define make_float3(x, y, z) ((float3)(x, y, z))
|
||||||
|
#define make_float4(x, y, z, w) ((float4)(x, y, z, w))
|
||||||
|
#define make_int2(x, y) ((int2)(x, y))
|
||||||
|
#define make_int3(x, y, z) ((int3)(x, y, z))
|
||||||
|
#define make_int4(x, y, z, w) ((int4)(x, y, z, w))
|
||||||
|
|
||||||
|
/* math functions */
|
||||||
|
#define __uint_as_float(x) as_float(x)
|
||||||
|
#define __float_as_uint(x) as_uint(x)
|
||||||
|
#define __int_as_float(x) as_float(x)
|
||||||
|
#define __float_as_int(x) as_int(x)
|
||||||
|
#define sqrtf(x) sqrt(((float)x))
|
||||||
|
#define cosf(x) cos(((float)x))
|
||||||
|
#define sinf(x) sin(((float)x))
|
||||||
|
#define powf(x, y) pow(((float)x), ((float)y))
|
||||||
|
#define fabsf(x) fabs(((float)x))
|
||||||
|
#define copysignf(x, y) copysign(((float)x), ((float)y))
|
||||||
|
#define cosf(x) cos(((float)x))
|
||||||
|
#define asinf(x) asin(((float)x))
|
||||||
|
#define acosf(x) acos(((float)x))
|
||||||
|
#define atanf(x) atan(((float)x))
|
||||||
|
#define tanf(x) tan(((float)x))
|
||||||
|
#define logf(x) log(((float)x))
|
||||||
|
#define floorf(x) floor(((float)x))
|
||||||
|
#define expf(x) exp(((float)x))
|
||||||
|
#define hypotf(x, y) hypot(((float)x), ((float)y))
|
||||||
|
#define atan2f(x, y) atan2(((float)x), ((float)y))
|
||||||
|
#define fmaxf(x, y) fmax(((float)x), ((float)y))
|
||||||
|
#define fminf(x, y) fmin(((float)x), ((float)y))
|
||||||
|
|
||||||
|
/* data lookup defines */
|
||||||
|
#define kernel_data (*kg->data)
|
||||||
|
#define kernel_tex_interp(t, x) kernel_tex_interp_(kg->t, kg->t##_width, x)
|
||||||
|
#define kernel_tex_fetch(t, index) kg->t[index]
|
||||||
|
|
||||||
|
/* define NULL */
|
||||||
|
#define NULL 0
|
||||||
|
|
||||||
|
#include "util_types.h"
|
||||||
|
|
||||||
|
#endif /* __KERNEL_COMPAT_OPENCL_H__ */
|
||||||
|
|
90
intern/cycles/kernel/kernel_differential.h
Normal file
90
intern/cycles/kernel/kernel_differential.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* See "Tracing Ray Differentials", Homan Igehy, 1999. */
|
||||||
|
|
||||||
|
__device void differential_transfer(differential3 *dP_, const differential3 dP, float3 D, const differential3 dD, float3 Ng, float t)
|
||||||
|
{
|
||||||
|
/* ray differential transfer through homogenous medium, to
|
||||||
|
* compute dPdx/dy at a shading point from the incoming ray */
|
||||||
|
|
||||||
|
float3 tmp = D/dot(D, Ng);
|
||||||
|
float3 tmpx = dP.dx + t*dD.dx;
|
||||||
|
float3 tmpy = dP.dy + t*dD.dy;
|
||||||
|
|
||||||
|
dP_->dx = tmpx - dot(tmpx, Ng)*tmp;
|
||||||
|
dP_->dy = tmpy - dot(tmpy, Ng)*tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device void differential_incoming(differential3 *dI, const differential3 dD)
|
||||||
|
{
|
||||||
|
/* compute dIdx/dy at a shading point, we just need to negate the
|
||||||
|
* differential of the ray direction */
|
||||||
|
|
||||||
|
dI->dx = -dD.dx;
|
||||||
|
dI->dy = -dD.dy;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device void differential_dudv(differential *du, differential *dv, float3 dPdu, float3 dPdv, differential3 dP, float3 Ng)
|
||||||
|
{
|
||||||
|
/* now we have dPdx/dy from the ray differential transfer, and dPdu/dv
|
||||||
|
* from the primitive, we can compute dudx/dy and dvdx/dy. these are
|
||||||
|
* mainly used for differentials of arbitrary mesh attributes. */
|
||||||
|
|
||||||
|
/* find most stable axis to project to 2D */
|
||||||
|
float xn= fabsf(Ng.x);
|
||||||
|
float yn= fabsf(Ng.y);
|
||||||
|
float zn= fabsf(Ng.z);
|
||||||
|
|
||||||
|
if(zn < xn || zn < yn) {
|
||||||
|
if(yn < xn || yn < zn) {
|
||||||
|
dPdu.x = dPdu.y;
|
||||||
|
dPdv.x = dPdv.y;
|
||||||
|
dP.dx.x = dP.dx.y;
|
||||||
|
dP.dy.x = dP.dy.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
dPdu.y = dPdu.z;
|
||||||
|
dPdv.y = dPdv.z;
|
||||||
|
dP.dx.y = dP.dx.z;
|
||||||
|
dP.dy.y = dP.dy.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* using Cramer's rule, we solve for dudx and dvdx in a 2x2 linear system,
|
||||||
|
* and the same for dudy and dvdy. the denominator is the same for both
|
||||||
|
* solutions, so we compute it only once.
|
||||||
|
*
|
||||||
|
* dP.dx = dPdu * dudx + dPdv * dvdx;
|
||||||
|
* dP.dy = dPdu * dudy + dPdv * dvdy; */
|
||||||
|
|
||||||
|
float det = (dPdu.x*dPdv.y - dPdv.x*dPdu.y);
|
||||||
|
|
||||||
|
if(det != 0.0f)
|
||||||
|
det = 1.0f/det;
|
||||||
|
|
||||||
|
du->dx = (dP.dx.x*dPdv.y - dP.dx.y*dPdv.x)*det;
|
||||||
|
dv->dx = (dP.dx.y*dPdu.x - dP.dx.x*dPdu.y)*det;
|
||||||
|
|
||||||
|
du->dy = (dP.dy.x*dPdv.y - dP.dy.y*dPdv.x)*det;
|
||||||
|
dv->dy = (dP.dy.y*dPdu.x - dP.dy.x*dPdu.y)*det;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
35
intern/cycles/kernel/kernel_displace.h
Normal file
35
intern/cycles/kernel/kernel_displace.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
__device void kernel_displace(KernelGlobals *kg, uint4 *input, float3 *offset, int i)
|
||||||
|
{
|
||||||
|
/* setup shader data */
|
||||||
|
ShaderData sd;
|
||||||
|
uint4 in = input[i];
|
||||||
|
shader_setup_from_displace(kg, &sd, in.x, in.y, __int_as_float(in.z), __int_as_float(in.w));
|
||||||
|
|
||||||
|
/* evaluate */
|
||||||
|
float3 P = sd.P;
|
||||||
|
shader_eval_displacement(kg, &sd);
|
||||||
|
offset[i] = sd.P - P;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
139
intern/cycles/kernel/kernel_emission.h
Normal file
139
intern/cycles/kernel/kernel_emission.h
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* Direction Emission */
|
||||||
|
|
||||||
|
__device float3 direct_emissive_eval(KernelGlobals *kg, float rando,
|
||||||
|
LightSample *ls, float u, float v, float3 I)
|
||||||
|
{
|
||||||
|
/* setup shading at emitter */
|
||||||
|
ShaderData sd;
|
||||||
|
|
||||||
|
shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v);
|
||||||
|
ls->Ng = sd.Ng;
|
||||||
|
|
||||||
|
/* no path flag, we're evaluating this for all closures. that's weak but
|
||||||
|
we'd have to do multiple evaluations otherwise */
|
||||||
|
shader_eval_surface(kg, &sd, rando, 0);
|
||||||
|
|
||||||
|
float3 eval;
|
||||||
|
|
||||||
|
/* evaluate emissive closure */
|
||||||
|
if(sd.flag & SD_EMISSION)
|
||||||
|
eval = shader_emissive_eval(kg, &sd);
|
||||||
|
else
|
||||||
|
eval = make_float3(0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
shader_release(kg, &sd);
|
||||||
|
|
||||||
|
return eval;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device bool direct_emission(KernelGlobals *kg, ShaderData *sd, int lindex,
|
||||||
|
float randt, float rando, float randu, float randv, Ray *ray, float3 *eval)
|
||||||
|
{
|
||||||
|
LightSample ls;
|
||||||
|
|
||||||
|
#ifdef __MULTI_LIGHT__
|
||||||
|
if(lindex != -1) {
|
||||||
|
/* sample position on a specified light */
|
||||||
|
light_select(kg, lindex, randu, randv, sd->P, &ls);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
/* sample a light and position on int */
|
||||||
|
light_sample(kg, randt, randu, randv, sd->P, &ls);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compute pdf */
|
||||||
|
float pdf = light_sample_pdf(kg, &ls, -ls.D, ls.t);
|
||||||
|
|
||||||
|
/* evaluate closure */
|
||||||
|
*eval = direct_emissive_eval(kg, rando, &ls, randu, randv, -ls.D);
|
||||||
|
|
||||||
|
if(is_zero(*eval) || pdf == 0.0f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* todo: use visbility flag to skip lights */
|
||||||
|
|
||||||
|
/* evaluate BSDF at shading point */
|
||||||
|
float bsdf_pdf;
|
||||||
|
float3 bsdf_eval = shader_bsdf_eval(kg, sd, ls.D, &bsdf_pdf);
|
||||||
|
|
||||||
|
*eval *= bsdf_eval/pdf;
|
||||||
|
|
||||||
|
if(is_zero(*eval))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(ls.prim != ~0) {
|
||||||
|
/* multiple importance sampling */
|
||||||
|
float mis_weight = power_heuristic(pdf, bsdf_pdf);
|
||||||
|
*eval *= mis_weight;
|
||||||
|
}
|
||||||
|
/* todo: clean up these weights */
|
||||||
|
else if(ls.shader & SHADER_AREA_LIGHT)
|
||||||
|
*eval *= 0.25f; /* area lamp */
|
||||||
|
else if(ls.t != FLT_MAX)
|
||||||
|
*eval *= 0.25f*M_1_PI_F; /* point lamp */
|
||||||
|
|
||||||
|
if(ls.shader & SHADER_CAST_SHADOW) {
|
||||||
|
/* setup ray */
|
||||||
|
ray->P = ray_offset(sd->P, sd->Ng);
|
||||||
|
|
||||||
|
if(ls.t == FLT_MAX) {
|
||||||
|
/* distant light */
|
||||||
|
ray->D = ls.D;
|
||||||
|
ray->t = ls.t;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* other lights, avoid self-intersection */
|
||||||
|
ray->D = ray_offset(ls.P, ls.Ng) - ray->P;
|
||||||
|
ray->D = normalize_len(ray->D, &ray->t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* signal to not cast shadow ray */
|
||||||
|
ray->t = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Indirect Emission */
|
||||||
|
|
||||||
|
__device float3 indirect_emission(KernelGlobals *kg, ShaderData *sd, float t, int path_flag, float bsdf_pdf)
|
||||||
|
{
|
||||||
|
/* evaluate emissive closure */
|
||||||
|
float3 L = shader_emissive_eval(kg, sd);
|
||||||
|
|
||||||
|
if(!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_SAMPLE_AS_LIGHT)) {
|
||||||
|
/* multiple importance sampling */
|
||||||
|
float pdf = triangle_light_pdf(kg, sd->Ng, sd->I, t);
|
||||||
|
float mis_weight = power_heuristic(bsdf_pdf, pdf);
|
||||||
|
|
||||||
|
return L*mis_weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
return L;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
64
intern/cycles/kernel/kernel_film.h
Normal file
64
intern/cycles/kernel/kernel_film.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
__device float4 film_map(KernelGlobals *kg, float4 irradiance, int sample)
|
||||||
|
{
|
||||||
|
float scale = 1.0f/(float)(sample+1);
|
||||||
|
float exposure = kernel_data.film.exposure;
|
||||||
|
float4 result = irradiance*scale;
|
||||||
|
|
||||||
|
/* conversion to srgb */
|
||||||
|
result.x = color_scene_linear_to_srgb(result.x*exposure);
|
||||||
|
result.y = color_scene_linear_to_srgb(result.y*exposure);
|
||||||
|
result.z = color_scene_linear_to_srgb(result.z*exposure);
|
||||||
|
|
||||||
|
/* clamp since alpha might be > 1.0 due to russian roulette */
|
||||||
|
result.w = clamp(result.w, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device uchar4 film_float_to_byte(float4 color)
|
||||||
|
{
|
||||||
|
uchar4 result;
|
||||||
|
|
||||||
|
/* simple float to byte conversion */
|
||||||
|
result.x = (uchar)clamp(color.x*255.0f, 0.0f, 255.0f);
|
||||||
|
result.y = (uchar)clamp(color.y*255.0f, 0.0f, 255.0f);
|
||||||
|
result.z = (uchar)clamp(color.z*255.0f, 0.0f, 255.0f);
|
||||||
|
result.w = (uchar)clamp(color.w*255.0f, 0.0f, 255.0f);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device void kernel_film_tonemap(KernelGlobals *kg, __global uchar4 *rgba, __global float4 *buffer, int sample, int resolution, int x, int y)
|
||||||
|
{
|
||||||
|
int w = kernel_data.cam.width;
|
||||||
|
int index = x + y*w;
|
||||||
|
float4 irradiance = buffer[index];
|
||||||
|
|
||||||
|
float4 float_result = film_map(kg, irradiance, sample);
|
||||||
|
uchar4 byte_result = film_float_to_byte(float_result);
|
||||||
|
|
||||||
|
rgba[index] = byte_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
88
intern/cycles/kernel/kernel_globals.h
Normal file
88
intern/cycles/kernel/kernel_globals.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Constant Globals */
|
||||||
|
|
||||||
|
#ifdef __KERNEL_CPU__
|
||||||
|
|
||||||
|
#ifdef __OSL__
|
||||||
|
#include "osl_globals.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* On the CPU, we pass along the struct KernelGlobals to nearly everywhere in
|
||||||
|
the kernel, to access constant data. These are all stored as "textures", but
|
||||||
|
these are really just standard arrays. We can't use actually globals because
|
||||||
|
multiple renders may be running inside the same process. */
|
||||||
|
|
||||||
|
#ifdef __KERNEL_CPU__
|
||||||
|
|
||||||
|
typedef struct KernelGlobals {
|
||||||
|
|
||||||
|
#define KERNEL_TEX(type, ttype, name) ttype name;
|
||||||
|
#define KERNEL_IMAGE_TEX(type, ttype, name) ttype name;
|
||||||
|
#include "kernel_textures.h"
|
||||||
|
|
||||||
|
KernelData __data;
|
||||||
|
|
||||||
|
#ifdef __OSL__
|
||||||
|
/* On the CPU, we also have the OSL globals here. Most data structures are shared
|
||||||
|
with SVM, the difference is in the shaders and object/mesh attributes. */
|
||||||
|
OSLGlobals osl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} KernelGLobals;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* For CUDA, constant memory textures must be globals, so we can't put them
|
||||||
|
into a struct. As a result we don't actually use this struct and use actual
|
||||||
|
globals and simply pass along a NULL pointer everywhere, which we hope gets
|
||||||
|
optimized out. */
|
||||||
|
|
||||||
|
#ifdef __KERNEL_CUDA__
|
||||||
|
|
||||||
|
__constant__ KernelData __data;
|
||||||
|
typedef struct KernelGlobals {} KernelGlobals;
|
||||||
|
|
||||||
|
#define KERNEL_TEX(type, ttype, name) ttype name;
|
||||||
|
#define KERNEL_IMAGE_TEX(type, ttype, name) ttype name;
|
||||||
|
#include "kernel_textures.h"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* OpenCL */
|
||||||
|
|
||||||
|
#ifdef __KERNEL_OPENCL__
|
||||||
|
|
||||||
|
typedef struct KernelGlobals {
|
||||||
|
__constant KernelData *data;
|
||||||
|
|
||||||
|
#define KERNEL_TEX(type, ttype, name) \
|
||||||
|
__global type *name; \
|
||||||
|
int name##_width;
|
||||||
|
#include "kernel_textures.h"
|
||||||
|
} KernelGlobals;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
241
intern/cycles/kernel/kernel_light.h
Normal file
241
intern/cycles/kernel/kernel_light.h
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
typedef struct LightSample {
|
||||||
|
float3 P;
|
||||||
|
float3 D;
|
||||||
|
float3 Ng;
|
||||||
|
float t;
|
||||||
|
int object;
|
||||||
|
int prim;
|
||||||
|
int shader;
|
||||||
|
} LightSample;
|
||||||
|
|
||||||
|
/* Regular Light */
|
||||||
|
|
||||||
|
__device float3 disk_light_sample(float3 v, float randu, float randv)
|
||||||
|
{
|
||||||
|
float3 ru, rv;
|
||||||
|
|
||||||
|
make_orthonormals(v, &ru, &rv);
|
||||||
|
to_unit_disk(&randu, &randv);
|
||||||
|
|
||||||
|
return ru*randu + rv*randv;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device float3 distant_light_sample(float3 D, float size, float randu, float randv)
|
||||||
|
{
|
||||||
|
return normalize(D + disk_light_sample(D, randu, randv)*size);
|
||||||
|
}
|
||||||
|
|
||||||
|
__device float3 sphere_light_sample(float3 P, float3 center, float size, float randu, float randv)
|
||||||
|
{
|
||||||
|
return disk_light_sample(normalize(P - center), randu, randv)*size;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device float3 area_light_sample(float3 axisu, float3 axisv, float randu, float randv)
|
||||||
|
{
|
||||||
|
randu = randu - 0.5f;
|
||||||
|
randv = randv - 0.5f;
|
||||||
|
|
||||||
|
return axisu*randu + axisv*randv;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device void regular_light_sample(KernelGlobals *kg, int point,
|
||||||
|
float randu, float randv, float3 P, LightSample *ls)
|
||||||
|
{
|
||||||
|
float4 data0 = kernel_tex_fetch(__light_data, point*LIGHT_SIZE + 0);
|
||||||
|
float4 data1 = kernel_tex_fetch(__light_data, point*LIGHT_SIZE + 1);
|
||||||
|
|
||||||
|
LightType type = (LightType)__float_as_int(data0.x);
|
||||||
|
|
||||||
|
if(type == LIGHT_DISTANT) {
|
||||||
|
/* distant light */
|
||||||
|
float3 D = make_float3(data0.y, data0.z, data0.w);
|
||||||
|
float size = data1.y;
|
||||||
|
|
||||||
|
if(size > 0.0f)
|
||||||
|
D = distant_light_sample(D, size, randu, randv);
|
||||||
|
|
||||||
|
ls->P = D;
|
||||||
|
ls->Ng = D;
|
||||||
|
ls->D = -D;
|
||||||
|
ls->t = FLT_MAX;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ls->P = make_float3(data0.y, data0.z, data0.w);
|
||||||
|
|
||||||
|
if(type == LIGHT_POINT) {
|
||||||
|
float size = data1.y;
|
||||||
|
|
||||||
|
/* sphere light */
|
||||||
|
if(size > 0.0f)
|
||||||
|
ls->P += sphere_light_sample(P, ls->P, size, randu, randv);
|
||||||
|
|
||||||
|
ls->Ng = normalize(P - ls->P);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* area light */
|
||||||
|
float4 data2 = kernel_tex_fetch(__light_data, point*LIGHT_SIZE + 2);
|
||||||
|
float4 data3 = kernel_tex_fetch(__light_data, point*LIGHT_SIZE + 3);
|
||||||
|
|
||||||
|
float3 axisu = make_float3(data1.y, data1.z, data2.w);
|
||||||
|
float3 axisv = make_float3(data2.y, data2.z, data2.w);
|
||||||
|
float3 D = make_float3(data3.y, data3.z, data3.w);
|
||||||
|
|
||||||
|
ls->P += area_light_sample(axisu, axisv, randu, randv);
|
||||||
|
ls->Ng = D;
|
||||||
|
}
|
||||||
|
|
||||||
|
ls->t = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
ls->shader = __float_as_int(data1.x);
|
||||||
|
ls->object = ~0;
|
||||||
|
ls->prim = ~0;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device float regular_light_pdf(KernelGlobals *kg,
|
||||||
|
const float3 Ng, const float3 I, float t)
|
||||||
|
{
|
||||||
|
float pdf = kernel_data.integrator.pdf_lights;
|
||||||
|
|
||||||
|
if(t == FLT_MAX)
|
||||||
|
return pdf;
|
||||||
|
|
||||||
|
float cos_pi = dot(Ng, I);
|
||||||
|
|
||||||
|
if(cos_pi <= 0.0f)
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return t*t*pdf/cos_pi;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Triangle Light */
|
||||||
|
|
||||||
|
__device void triangle_light_sample(KernelGlobals *kg, int prim, int object,
|
||||||
|
float randu, float randv, LightSample *ls)
|
||||||
|
{
|
||||||
|
/* triangle, so get position, normal, shader */
|
||||||
|
ls->P = triangle_sample_MT(kg, prim, randu, randv);
|
||||||
|
ls->Ng = triangle_normal_MT(kg, prim, &ls->shader);
|
||||||
|
ls->object = object;
|
||||||
|
ls->prim = prim;
|
||||||
|
ls->t = 0.0f;
|
||||||
|
|
||||||
|
#ifdef __INSTANCING__
|
||||||
|
/* instance transform */
|
||||||
|
if(ls->object >= 0) {
|
||||||
|
object_position_transform(kg, ls->object, &ls->P);
|
||||||
|
object_normal_transform(kg, ls->object, &ls->Ng);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
__device float triangle_light_pdf(KernelGlobals *kg,
|
||||||
|
const float3 Ng, const float3 I, float t)
|
||||||
|
{
|
||||||
|
float cos_pi = fabsf(dot(Ng, I));
|
||||||
|
|
||||||
|
if(cos_pi == 0.0f)
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return (t*t*kernel_data.integrator.pdf_triangles)/cos_pi;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Light Distribution */
|
||||||
|
|
||||||
|
__device int light_distribution_sample(KernelGlobals *kg, float randt)
|
||||||
|
{
|
||||||
|
/* this is basically std::upper_bound as used by pbrt, to find a point light or
|
||||||
|
triangle to emit from, proportional to area. a good improvement would be to
|
||||||
|
also sample proportional to power, though it's not so well defined with
|
||||||
|
OSL shaders. */
|
||||||
|
int first = 0;
|
||||||
|
int len = kernel_data.integrator.num_distribution + 1;
|
||||||
|
|
||||||
|
while(len > 0) {
|
||||||
|
int half_len = len >> 1;
|
||||||
|
int middle = first + half_len;
|
||||||
|
|
||||||
|
if(randt < kernel_tex_fetch(__light_distribution, middle).x) {
|
||||||
|
len = half_len;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
first = middle + 1;
|
||||||
|
len = len - half_len - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
first = max(0, first-1);
|
||||||
|
kernel_assert(first >= 0 && first < kernel_data.integrator.num_distribution);
|
||||||
|
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generic Light */
|
||||||
|
|
||||||
|
__device void light_sample(KernelGlobals *kg, float randt, float randu, float randv, float3 P, LightSample *ls)
|
||||||
|
{
|
||||||
|
/* sample index */
|
||||||
|
int index = light_distribution_sample(kg, randt);
|
||||||
|
|
||||||
|
/* fetch light data */
|
||||||
|
float4 l = kernel_tex_fetch(__light_distribution, index);
|
||||||
|
int prim = __float_as_int(l.y);
|
||||||
|
|
||||||
|
if(prim >= 0) {
|
||||||
|
int object = __float_as_int(l.w);
|
||||||
|
triangle_light_sample(kg, prim, object, randu, randv, ls);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int point = -prim-1;
|
||||||
|
regular_light_sample(kg, point, randu, randv, P, ls);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compute incoming direction and distance */
|
||||||
|
if(ls->t != FLT_MAX)
|
||||||
|
ls->D = normalize_len(ls->P - P, &ls->t);
|
||||||
|
}
|
||||||
|
|
||||||
|
__device float light_sample_pdf(KernelGlobals *kg, LightSample *ls, float3 I, float t)
|
||||||
|
{
|
||||||
|
float pdf;
|
||||||
|
|
||||||
|
if(ls->prim != ~0)
|
||||||
|
pdf = triangle_light_pdf(kg, ls->Ng, I, t);
|
||||||
|
else
|
||||||
|
pdf = regular_light_pdf(kg, ls->Ng, I, t);
|
||||||
|
|
||||||
|
return pdf;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device void light_select(KernelGlobals *kg, int index, float randu, float randv, float3 P, LightSample *ls)
|
||||||
|
{
|
||||||
|
regular_light_sample(kg, index, randu, randv, P, ls);
|
||||||
|
}
|
||||||
|
|
||||||
|
__device float light_select_pdf(KernelGlobals *kg, LightSample *ls, float3 I, float t)
|
||||||
|
{
|
||||||
|
return regular_light_pdf(kg, ls->Ng, I, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
27
intern/cycles/kernel/kernel_math.h
Normal file
27
intern/cycles/kernel/kernel_math.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __KERNEL_MATH_H__
|
||||||
|
#define __KERNEL_MATH_H__
|
||||||
|
|
||||||
|
#include "util_color.h"
|
||||||
|
#include "util_math.h"
|
||||||
|
#include "util_transform.h"
|
||||||
|
|
||||||
|
#endif /* __KERNEL_MATH_H__ */
|
||||||
|
|
394
intern/cycles/kernel/kernel_mbvh.h
Normal file
394
intern/cycles/kernel/kernel_mbvh.h
Normal file
@ -0,0 +1,394 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
#define MBVH_OBJECT_SENTINEL 0x76543210
|
||||||
|
#define MBVH_NODE_SIZE 8
|
||||||
|
#define MBVH_STACK_SIZE 1024
|
||||||
|
#define MBVH_RAY_STACK_SIZE 10000
|
||||||
|
|
||||||
|
typedef struct MBVHTask {
|
||||||
|
int node;
|
||||||
|
int index;
|
||||||
|
int num;
|
||||||
|
int object;
|
||||||
|
} MBVHTask;
|
||||||
|
|
||||||
|
typedef struct MVBHRay {
|
||||||
|
float3 P;
|
||||||
|
float u;
|
||||||
|
float3 idir;
|
||||||
|
float v;
|
||||||
|
float t;
|
||||||
|
int index;
|
||||||
|
int object;
|
||||||
|
|
||||||
|
float3 origP;
|
||||||
|
float3 origD;
|
||||||
|
float tmax;
|
||||||
|
} MBVHRay;
|
||||||
|
|
||||||
|
__device float3 mbvh_inverse_direction(float3 dir)
|
||||||
|
{
|
||||||
|
// Avoid divide by zero (ooeps = exp2f(-80.0f))
|
||||||
|
float ooeps = 0.00000000000000000000000082718061255302767487140869206996285356581211090087890625f;
|
||||||
|
float3 idir;
|
||||||
|
|
||||||
|
idir.x = 1.0f / (fabsf(dir.x) > ooeps ? dir.x : copysignf(ooeps, dir.x));
|
||||||
|
idir.y = 1.0f / (fabsf(dir.y) > ooeps ? dir.y : copysignf(ooeps, dir.y));
|
||||||
|
idir.z = 1.0f / (fabsf(dir.z) > ooeps ? dir.z : copysignf(ooeps, dir.z));
|
||||||
|
|
||||||
|
return idir;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device void mbvh_instance_push(KernelGlobals *kg, int object, MBVHRay *ray)
|
||||||
|
{
|
||||||
|
Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
|
||||||
|
|
||||||
|
ray->P = transform(&tfm, ray->origP);
|
||||||
|
|
||||||
|
float3 dir = ray->origD;
|
||||||
|
|
||||||
|
if(ray->t != ray->tmax) dir *= ray->t;
|
||||||
|
|
||||||
|
dir = transform_direction(&tfm, dir);
|
||||||
|
ray->idir = mbvh_inverse_direction(normalize(dir));
|
||||||
|
|
||||||
|
if(ray->t != ray->tmax) ray->t = len(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
__device void mbvh_instance_pop(KernelGlobals *kg, int object, MBVHRay *ray)
|
||||||
|
{
|
||||||
|
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
|
||||||
|
|
||||||
|
if(ray->t != ray->tmax)
|
||||||
|
ray->t = len(transform_direction(&tfm, (1.0f/(ray->idir)) * (ray->t)));
|
||||||
|
|
||||||
|
ray->P = ray->origP;
|
||||||
|
ray->idir = mbvh_inverse_direction(ray->origD);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sven Woop's algorithm */
|
||||||
|
__device void mbvh_triangle_intersect(KernelGlobals *kg, MBVHRay *ray, int object, int triAddr)
|
||||||
|
{
|
||||||
|
float3 P = ray->P;
|
||||||
|
float3 idir = ray->idir;
|
||||||
|
|
||||||
|
/* compute and check intersection t-value */
|
||||||
|
float4 v00 = kernel_tex_fetch(__tri_woop, triAddr*MBVH_NODE_SIZE+0);
|
||||||
|
float4 v11 = kernel_tex_fetch(__tri_woop, triAddr*MBVH_NODE_SIZE+1);
|
||||||
|
float3 dir = 1.0f/idir;
|
||||||
|
|
||||||
|
float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z;
|
||||||
|
float invDz = 1.0f/(dir.x*v00.x + dir.y*v00.y + dir.z*v00.z);
|
||||||
|
float t = Oz * invDz;
|
||||||
|
|
||||||
|
if(t > 0.0f && t < ray->t) {
|
||||||
|
/* compute and check barycentric u */
|
||||||
|
float Ox = v11.w + P.x*v11.x + P.y*v11.y + P.z*v11.z;
|
||||||
|
float Dx = dir.x*v11.x + dir.y*v11.y + dir.z*v11.z;
|
||||||
|
float u = Ox + t*Dx;
|
||||||
|
|
||||||
|
if(u >= 0.0f) {
|
||||||
|
/* compute and check barycentric v */
|
||||||
|
float4 v22 = kernel_tex_fetch(__tri_woop, triAddr*MBVH_NODE_SIZE+2);
|
||||||
|
float Oy = v22.w + P.x*v22.x + P.y*v22.y + P.z*v22.z;
|
||||||
|
float Dy = dir.x*v22.x + dir.y*v22.y + dir.z*v22.z;
|
||||||
|
float v = Oy + t*Dy;
|
||||||
|
|
||||||
|
if(v >= 0.0f && u + v <= 1.0f) {
|
||||||
|
/* record intersection */
|
||||||
|
ray->index = triAddr;
|
||||||
|
ray->object = object;
|
||||||
|
ray->u = u;
|
||||||
|
ray->v = v;
|
||||||
|
ray->t = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__device void mbvh_node_intersect(KernelGlobals *kg, __m128 *traverseChild,
|
||||||
|
__m128 *tHit, float3 P, float3 idir, float t, int nodeAddr)
|
||||||
|
{
|
||||||
|
/* X axis */
|
||||||
|
const __m128 bminx = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+0);
|
||||||
|
const __m128 t0x = _mm_mul_ps(_mm_sub_ps(bminx, _mm_set_ps1(P.x)), _mm_set_ps1(idir.x));
|
||||||
|
const __m128 bmaxx = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+1);
|
||||||
|
const __m128 t1x = _mm_mul_ps(_mm_sub_ps(bmaxx, _mm_set_ps1(P.x)), _mm_set_ps1(idir.x));
|
||||||
|
|
||||||
|
__m128 tmin = _mm_max_ps(_mm_min_ps(t0x, t1x), _mm_setzero_ps());
|
||||||
|
__m128 tmax = _mm_min_ps(_mm_max_ps(t0x, t1x), _mm_set_ps1(t));
|
||||||
|
|
||||||
|
/* Y axis */
|
||||||
|
const __m128 bminy = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+2);
|
||||||
|
const __m128 t0y = _mm_mul_ps(_mm_sub_ps(bminy, _mm_set_ps1(P.y)), _mm_set_ps1(idir.y));
|
||||||
|
const __m128 bmaxy = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+3);
|
||||||
|
const __m128 t1y = _mm_mul_ps(_mm_sub_ps(bmaxy, _mm_set_ps1(P.y)), _mm_set_ps1(idir.y));
|
||||||
|
|
||||||
|
tmin = _mm_max_ps(_mm_min_ps(t0y, t1y), tmin);
|
||||||
|
tmax = _mm_min_ps(_mm_max_ps(t0y, t1y), tmax);
|
||||||
|
|
||||||
|
/* Z axis */
|
||||||
|
const __m128 bminz = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+4);
|
||||||
|
const __m128 t0z = _mm_mul_ps(_mm_sub_ps(bminz, _mm_set_ps1(P.z)), _mm_set_ps1(idir.z));
|
||||||
|
const __m128 bmaxz = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+5);
|
||||||
|
const __m128 t1z = _mm_mul_ps(_mm_sub_ps(bmaxz, _mm_set_ps1(P.z)), _mm_set_ps1(idir.z));
|
||||||
|
|
||||||
|
tmin = _mm_max_ps(_mm_min_ps(t0z, t1z), tmin);
|
||||||
|
tmax = _mm_min_ps(_mm_max_ps(t0z, t1z), tmax);
|
||||||
|
|
||||||
|
/* compare and get mask */
|
||||||
|
*traverseChild = _mm_cmple_ps(tmin, tmax);
|
||||||
|
|
||||||
|
/* get distance XXX probably wrong */
|
||||||
|
*tHit = tmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mbvh_sort_by_length(int id[4], float len[4])
|
||||||
|
{
|
||||||
|
for(int i = 1; i < 4; i++) {
|
||||||
|
int j = i - 1;
|
||||||
|
|
||||||
|
while(j >= 0 && len[j] > len[j+1]) {
|
||||||
|
swap(len[j], len[j+1]);
|
||||||
|
swap(id[j], id[j+1]);
|
||||||
|
j--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__device void scene_intersect(KernelGlobals *kg, MBVHRay *rays, int numrays)
|
||||||
|
{
|
||||||
|
/* traversal stacks */
|
||||||
|
MBVHTask task_stack[MBVH_STACK_SIZE];
|
||||||
|
int active_ray_stacks[4][MBVH_RAY_STACK_SIZE];
|
||||||
|
int num_task, num_active[4] = {0, 0, 0, 0};
|
||||||
|
__m128i one_mm = _mm_set1_epi32(1);
|
||||||
|
|
||||||
|
/* push root node task on stack */
|
||||||
|
task_stack[0].node = kernel_data.bvh.root;
|
||||||
|
task_stack[0].index = 0;
|
||||||
|
task_stack[0].num = numrays;
|
||||||
|
task_stack[0].object = ~0;
|
||||||
|
num_task = 1;
|
||||||
|
|
||||||
|
/* push all rays in first SIMD lane */
|
||||||
|
for(int i = 0; i < numrays; i++)
|
||||||
|
active_ray_stacks[0][i] = i;
|
||||||
|
num_active[0] = numrays;
|
||||||
|
|
||||||
|
while(num_task >= 1) {
|
||||||
|
/* pop task */
|
||||||
|
MBVHTask task = task_stack[--num_task];
|
||||||
|
|
||||||
|
if(task.node == MBVH_OBJECT_SENTINEL) {
|
||||||
|
/* instance pop */
|
||||||
|
|
||||||
|
/* pop rays from stack */
|
||||||
|
num_active[task.index] -= task.num;
|
||||||
|
int ray_offset = num_active[task.index];
|
||||||
|
|
||||||
|
/* transform rays */
|
||||||
|
for(int i = 0; i < task.num; i++) {
|
||||||
|
MBVHRay *ray = &rays[active_ray_stacks[task.index][ray_offset + i]];
|
||||||
|
mbvh_instance_pop(kg, task.object, ray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(task.node >= 0) {
|
||||||
|
/* inner node? */
|
||||||
|
|
||||||
|
/* pop rays from stack*/
|
||||||
|
num_active[task.index] -= task.num;
|
||||||
|
int ray_offset = num_active[task.index];
|
||||||
|
|
||||||
|
/* initialze simd values */
|
||||||
|
__m128i num_active_mm = _mm_load_si128((__m128i*)num_active);
|
||||||
|
__m128 len_mm = _mm_set_ps1(0.0f);
|
||||||
|
|
||||||
|
for(int i = 0; i < task.num; i++) {
|
||||||
|
int rayid = active_ray_stacks[task.index][ray_offset + i];
|
||||||
|
MVBHRay *ray = rays + rayid;
|
||||||
|
|
||||||
|
/* intersect 4 QBVH node children */
|
||||||
|
__m128 result;
|
||||||
|
__m128 thit;
|
||||||
|
|
||||||
|
mbvh_node_intersect(kg, &result, &thit, ray->P, ray->idir, ray->t, task.node);
|
||||||
|
|
||||||
|
/* update length for sorting */
|
||||||
|
len_mm = _mm_add_ps(len_mm, _mm_and_ps(thit, result));
|
||||||
|
|
||||||
|
/* push rays on stack */
|
||||||
|
for(int j = 0; j < 4; j++)
|
||||||
|
active_ray_stacks[j][num_active[j]] = rayid;
|
||||||
|
|
||||||
|
/* update num active */
|
||||||
|
__m128i resulti = _mm_and_si128(*((__m128i*)&result), one_mm);
|
||||||
|
num_active_mm = _mm_add_epi32(resulti, num_active_mm);
|
||||||
|
_mm_store_si128((__m128i*)num_active, num_active_mm);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(num_active[0] || num_active[1] || num_active[2] || num_active[3]) {
|
||||||
|
/* load child node addresses */
|
||||||
|
float4 cnodes = kernel_tex_fetch(__bvh_nodes, task.node);
|
||||||
|
int child[4] = {
|
||||||
|
__float_as_int(cnodes.x),
|
||||||
|
__float_as_int(cnodes.y),
|
||||||
|
__float_as_int(cnodes.z),
|
||||||
|
__float_as_int(cnodes.w)};
|
||||||
|
|
||||||
|
/* sort nodes by average intersection distance */
|
||||||
|
int ids[4] = {0, 1, 2, 3};
|
||||||
|
float len[4];
|
||||||
|
|
||||||
|
_mm_store_ps(len, len_mm);
|
||||||
|
mbvh_sort_by_length(ids, len);
|
||||||
|
|
||||||
|
/* push new tasks on stack */
|
||||||
|
for(int j = 0; j < 4; j++) {
|
||||||
|
if(num_active[j]) {
|
||||||
|
int id = ids[j];
|
||||||
|
|
||||||
|
task_stack[num_task].node = child[id];
|
||||||
|
task_stack[num_task].index = id;
|
||||||
|
task_stack[num_task].num = num_active[id];
|
||||||
|
task_stack[num_task].object = task.object;
|
||||||
|
num_task++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* fetch leaf node data */
|
||||||
|
float4 leaf = kernel_tex_fetch(__bvh_nodes, (-task.node-1)*MBVH_NODE_SIZE+(MBVH_NODE_SIZE-2));
|
||||||
|
int triAddr = __float_as_int(leaf.x);
|
||||||
|
int triAddr2 = __float_as_int(leaf.y);
|
||||||
|
|
||||||
|
/* pop rays from stack*/
|
||||||
|
num_active[task.index] -= task.num;
|
||||||
|
int ray_offset = num_active[task.index];
|
||||||
|
|
||||||
|
/* triangles */
|
||||||
|
if(triAddr >= 0) {
|
||||||
|
int i, numq = (task.num >> 2) << 2;
|
||||||
|
|
||||||
|
/* SIMD ray leaf intersection */
|
||||||
|
for(i = 0; i < numq; i += 4) {
|
||||||
|
MBVHRay *ray4[4] = {
|
||||||
|
&rays[active_ray_stacks[task.index][ray_offset + i + 0]],
|
||||||
|
&rays[active_ray_stacks[task.index][ray_offset + i + 1]],
|
||||||
|
&rays[active_ray_stacks[task.index][ray_offset + i + 2]],
|
||||||
|
&rays[active_ray_stacks[task.index][ray_offset + i + 3]]};
|
||||||
|
|
||||||
|
/* load SoA */
|
||||||
|
|
||||||
|
while(triAddr < triAddr2) {
|
||||||
|
mbvh_triangle_intersect(ray4[0], task.object, task.node);
|
||||||
|
mbvh_triangle_intersect(ray4[1], task.object, task.node);
|
||||||
|
mbvh_triangle_intersect(ray4[2], task.object, task.node);
|
||||||
|
mbvh_triangle_intersect(ray4[3], task.object, task.node);
|
||||||
|
triAddr++;
|
||||||
|
|
||||||
|
/* some shadow ray optim could be done by setting t=0 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store AoS */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mono ray leaf intersection */
|
||||||
|
for(; i < task.num; i++) {
|
||||||
|
MBVHRay *ray = &rays[active_ray_stacks[task.index][ray_offset + i]];
|
||||||
|
|
||||||
|
while(triAddr < triAddr2) {
|
||||||
|
mbvh_triangle_intersect(kg, ray, task.object, task.node);
|
||||||
|
triAddr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* instance push */
|
||||||
|
int object = -triAddr-1;
|
||||||
|
int node = triAddr;
|
||||||
|
|
||||||
|
/* push instance pop task */
|
||||||
|
task_stack[num_task].node = MBVH_OBJECT_SENTINEL;
|
||||||
|
task_stack[num_task].index = task.index;
|
||||||
|
task_stack[num_task].num = task.num;
|
||||||
|
task_stack[num_task].object = object;
|
||||||
|
num_task++;
|
||||||
|
|
||||||
|
num_active[task.index] += task.num;
|
||||||
|
|
||||||
|
/* push node task */
|
||||||
|
task_stack[num_task].node = node;
|
||||||
|
task_stack[num_task].index = task.index;
|
||||||
|
task_stack[num_task].num = task.num;
|
||||||
|
task_stack[num_task].object = object;
|
||||||
|
num_task++;
|
||||||
|
|
||||||
|
for(int i = 0; i < task.num; i++) {
|
||||||
|
int rayid = active_ray_stacks[task.index][ray_offset + i];
|
||||||
|
|
||||||
|
/* push on stack for last task */
|
||||||
|
active_ray_stacks[task.index][num_active[task.index]] = rayid;
|
||||||
|
num_active[task.index]++;
|
||||||
|
|
||||||
|
/* transform ray */
|
||||||
|
MBVHRay *ray = &rays[rayid];
|
||||||
|
mbvh_instance_push(kg, object, ray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__device void mbvh_set_ray(MBVHRay *rays, int i, Ray *ray, float tmax)
|
||||||
|
{
|
||||||
|
MBVHRay *mray = &rays[i];
|
||||||
|
|
||||||
|
/* ray parameters in registers */
|
||||||
|
mray->P = ray->P;
|
||||||
|
mray->idir = mbvh_inverse_direction(ray->D);
|
||||||
|
mray->t = tmax;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device bool mbvh_get_intersection(MVBHRay *rays, int i, Intersection *isect, float tmax)
|
||||||
|
{
|
||||||
|
MBVHRay *mray = &rays[i];
|
||||||
|
|
||||||
|
if(mray->t == tmax)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
isect->t = mray->t;
|
||||||
|
isect->u = mray->u;
|
||||||
|
isect->v = mray->v;
|
||||||
|
isect->index = mray->index;
|
||||||
|
isect->object = mray->object;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device bool mbvh_get_shadow(MBVHRay *rays, int i, float tmax)
|
||||||
|
{
|
||||||
|
return (rays[i].t == tmax);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
209
intern/cycles/kernel/kernel_montecarlo.h
Normal file
209
intern/cycles/kernel/kernel_montecarlo.h
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
/*
|
||||||
|
* Parts adapted from Open Shading Language with this license:
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Modifications Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Sony Pictures Imageworks nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __KERNEL_MONTECARLO_CL__
|
||||||
|
#define __KERNEL_MONTECARLO_CL__
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/// Given values x and y on [0,1], convert them in place to values on
|
||||||
|
/// [-1,1] uniformly distributed over a unit sphere. This code is
|
||||||
|
/// derived from Peter Shirley, "Realistic Ray Tracing", p. 103.
|
||||||
|
__device void to_unit_disk(float *x, float *y)
|
||||||
|
{
|
||||||
|
float r, phi;
|
||||||
|
float a = 2.0f * (*x) - 1.0f;
|
||||||
|
float b = 2.0f * (*y) - 1.0f;
|
||||||
|
if(a > -b) {
|
||||||
|
if(a > b) {
|
||||||
|
r = a;
|
||||||
|
phi = M_PI_4_F *(b/a);
|
||||||
|
} else {
|
||||||
|
r = b;
|
||||||
|
phi = M_PI_4_F *(2.0f - a/b);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(a < b) {
|
||||||
|
r = -a;
|
||||||
|
phi = M_PI_4_F *(4.0f + b/a);
|
||||||
|
} else {
|
||||||
|
r = -b;
|
||||||
|
if(b != 0.0f)
|
||||||
|
phi = M_PI_4_F *(6.0f - a/b);
|
||||||
|
else
|
||||||
|
phi = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*x = r * cosf(phi);
|
||||||
|
*y = r * sinf(phi);
|
||||||
|
}
|
||||||
|
|
||||||
|
__device void make_orthonormals_tangent(const float3 N, const float3 T, float3 *a, float3 *b)
|
||||||
|
{
|
||||||
|
*b = cross(N, T);
|
||||||
|
*a = cross(*b, N);
|
||||||
|
}
|
||||||
|
|
||||||
|
__device_inline void sample_cos_hemisphere(const float3 N,
|
||||||
|
float randu, float randv, float3 *omega_in, float *pdf)
|
||||||
|
{
|
||||||
|
// Default closure BSDF implementation: uniformly sample
|
||||||
|
// cosine-weighted hemisphere above the point.
|
||||||
|
to_unit_disk(&randu, &randv);
|
||||||
|
float costheta = sqrtf(max(1.0f - randu * randu - randv * randv, 0.0f));
|
||||||
|
float3 T, B;
|
||||||
|
make_orthonormals(N, &T, &B);
|
||||||
|
*omega_in = randu * T + randv * B + costheta * N;
|
||||||
|
*pdf = costheta *M_1_PI_F;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device_inline void sample_uniform_hemisphere(const float3 N,
|
||||||
|
float randu, float randv,
|
||||||
|
float3 *omega_in, float *pdf)
|
||||||
|
{
|
||||||
|
float z = randu;
|
||||||
|
float r = sqrtf(max(0.f, 1.f - z*z));
|
||||||
|
float phi = 2.f * M_PI_F * randv;
|
||||||
|
float x = r * cosf(phi);
|
||||||
|
float y = r * sinf(phi);
|
||||||
|
|
||||||
|
float3 T, B;
|
||||||
|
make_orthonormals (N, &T, &B);
|
||||||
|
*omega_in = x * T + y * B + z * N;
|
||||||
|
*pdf = 0.5f * M_1_PI_F;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device float3 sample_uniform_sphere(float u1, float u2)
|
||||||
|
{
|
||||||
|
float z = 1.0f - 2.0f*u1;
|
||||||
|
float r = sqrtf(fmaxf(0.0f, 1.0f - z*z));
|
||||||
|
float phi = 2.0f*M_PI_F*u2;
|
||||||
|
float x = r*cosf(phi);
|
||||||
|
float y = r*sinf(phi);
|
||||||
|
|
||||||
|
return make_float3(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
__device float power_heuristic(float a, float b)
|
||||||
|
{
|
||||||
|
return (a*a)/(a*a + b*b);
|
||||||
|
}
|
||||||
|
|
||||||
|
__device float2 concentric_sample_disk(float u1, float u2)
|
||||||
|
{
|
||||||
|
float r, theta;
|
||||||
|
// Map uniform random numbers to $[-1,1]^2$
|
||||||
|
float sx = 2 * u1 - 1;
|
||||||
|
float sy = 2 * u2 - 1;
|
||||||
|
|
||||||
|
// Map square to $(r,\theta)$
|
||||||
|
|
||||||
|
// Handle degeneracy at the origin
|
||||||
|
if(sx == 0.0f && sy == 0.0f) {
|
||||||
|
return make_float2(0.0f, 0.0f);
|
||||||
|
}
|
||||||
|
if(sx >= -sy) {
|
||||||
|
if(sx > sy) {
|
||||||
|
// Handle first region of disk
|
||||||
|
r = sx;
|
||||||
|
if(sy > 0.0f) theta = sy/r;
|
||||||
|
else theta = 8.0f + sy/r;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Handle second region of disk
|
||||||
|
r = sy;
|
||||||
|
theta = 2.0f - sx/r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(sx <= sy) {
|
||||||
|
// Handle third region of disk
|
||||||
|
r = -sx;
|
||||||
|
theta = 4.0f - sy/r;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Handle fourth region of disk
|
||||||
|
r = -sy;
|
||||||
|
theta = 6.0f + sx/r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
theta *= M_PI_4_F;
|
||||||
|
return make_float2(r * cosf(theta), r * sinf(theta));
|
||||||
|
}
|
||||||
|
|
||||||
|
__device float2 regular_polygon_sample(float corners, float rotation, float u, float v)
|
||||||
|
{
|
||||||
|
/* sample corner number and reuse u */
|
||||||
|
float corner = floorf(u*corners);
|
||||||
|
u = u*corners - corner;
|
||||||
|
|
||||||
|
/* uniform sampled triangle weights */
|
||||||
|
u = sqrtf(u);
|
||||||
|
v = v*u;
|
||||||
|
u = 1.0f - u;
|
||||||
|
|
||||||
|
/* point in triangle */
|
||||||
|
float angle = M_PI_F/corners;
|
||||||
|
float2 p = make_float2((u + v)*cosf(angle), (u - v)*sinf(angle));
|
||||||
|
|
||||||
|
/* rotate */
|
||||||
|
rotation += corner*2.0f*angle;
|
||||||
|
|
||||||
|
float cr = cosf(rotation);
|
||||||
|
float sr = sinf(rotation);
|
||||||
|
|
||||||
|
return make_float2(cr*p.x - sr*p.y, sr*p.x + cr*p.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Spherical coordinates <-> Cartesion direction */
|
||||||
|
|
||||||
|
__device float2 direction_to_spherical(float3 dir)
|
||||||
|
{
|
||||||
|
float theta = acosf(dir.z);
|
||||||
|
float phi = atan2f(dir.x, dir.y);
|
||||||
|
|
||||||
|
return make_float2(theta, phi);
|
||||||
|
}
|
||||||
|
|
||||||
|
__device float3 spherical_to_direction(float theta, float phi)
|
||||||
|
{
|
||||||
|
return make_float3(
|
||||||
|
sinf(theta)*cosf(phi),
|
||||||
|
sinf(theta)*sinf(phi),
|
||||||
|
cosf(theta));
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* __KERNEL_MONTECARLO_CL__ */
|
||||||
|
|
68
intern/cycles/kernel/kernel_object.h
Normal file
68
intern/cycles/kernel/kernel_object.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
enum ObjectTransform {
|
||||||
|
OBJECT_TRANSFORM = 0,
|
||||||
|
OBJECT_INVERSE_TRANSFORM = 4,
|
||||||
|
OBJECT_NORMAL_TRANSFORM = 8,
|
||||||
|
OBJECT_PROPERTIES = 12
|
||||||
|
};
|
||||||
|
|
||||||
|
__device_inline Transform object_fetch_transform(KernelGlobals *kg, int object, enum ObjectTransform type)
|
||||||
|
{
|
||||||
|
Transform tfm;
|
||||||
|
|
||||||
|
int offset = object*OBJECT_SIZE + (int)type;
|
||||||
|
|
||||||
|
tfm.x = kernel_tex_fetch(__objects, offset + 0);
|
||||||
|
tfm.y = kernel_tex_fetch(__objects, offset + 1);
|
||||||
|
tfm.z = kernel_tex_fetch(__objects, offset + 2);
|
||||||
|
tfm.w = kernel_tex_fetch(__objects, offset + 3);
|
||||||
|
|
||||||
|
return tfm;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device_inline void object_position_transform(KernelGlobals *kg, int object, float3 *P)
|
||||||
|
{
|
||||||
|
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
|
||||||
|
*P = transform(&tfm, *P);
|
||||||
|
}
|
||||||
|
|
||||||
|
__device_inline void object_normal_transform(KernelGlobals *kg, int object, float3 *N)
|
||||||
|
{
|
||||||
|
Transform tfm = object_fetch_transform(kg, object, OBJECT_NORMAL_TRANSFORM);
|
||||||
|
*N = normalize(transform_direction(&tfm, *N));
|
||||||
|
}
|
||||||
|
|
||||||
|
__device_inline void object_dir_transform(KernelGlobals *kg, int object, float3 *D)
|
||||||
|
{
|
||||||
|
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
|
||||||
|
*D = transform_direction(&tfm, *D);
|
||||||
|
}
|
||||||
|
|
||||||
|
__device_inline float object_surface_area(KernelGlobals *kg, int object)
|
||||||
|
{
|
||||||
|
int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
|
||||||
|
float4 f = kernel_tex_fetch(__objects, offset);
|
||||||
|
return f.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
421
intern/cycles/kernel/kernel_path.h
Normal file
421
intern/cycles/kernel/kernel_path.h
Normal file
@ -0,0 +1,421 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kernel_differential.h"
|
||||||
|
#include "kernel_montecarlo.h"
|
||||||
|
#include "kernel_triangle.h"
|
||||||
|
#include "kernel_object.h"
|
||||||
|
#ifdef __QBVH__
|
||||||
|
#include "kernel_qbvh.h"
|
||||||
|
#else
|
||||||
|
#include "kernel_bvh.h"
|
||||||
|
#endif
|
||||||
|
#include "kernel_camera.h"
|
||||||
|
#include "kernel_shader.h"
|
||||||
|
#include "kernel_light.h"
|
||||||
|
#include "kernel_emission.h"
|
||||||
|
#include "kernel_random.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
#ifdef __MODIFY_TP__
|
||||||
|
__device float3 path_terminate_modified_throughput(KernelGlobals *kg, __global float3 *buffer, int x, int y, int sample)
|
||||||
|
{
|
||||||
|
/* modify throughput to influence path termination probability, to avoid
|
||||||
|
darker regions receiving fewer samples than lighter regions. also RGB
|
||||||
|
are weighted differently. proper validation still remains to be done. */
|
||||||
|
const float3 weights = make_float3(1.0f, 1.33f, 0.66f);
|
||||||
|
const float3 one = make_float3(1.0f, 1.0f, 1.0f);
|
||||||
|
const int minsample = 5;
|
||||||
|
const float minL = 0.1f;
|
||||||
|
|
||||||
|
if(sample >= minsample) {
|
||||||
|
float3 L = buffer[x + y*kernel_data.cam.width];
|
||||||
|
float3 Lmin = make_float3(minL, minL, minL);
|
||||||
|
float correct = (float)(sample+1)/(float)sample;
|
||||||
|
|
||||||
|
L = film_map(L*correct, sample);
|
||||||
|
|
||||||
|
return weights/clamp(L, Lmin, one);
|
||||||
|
}
|
||||||
|
|
||||||
|
return weights;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct PathState {
|
||||||
|
uint flag;
|
||||||
|
int bounce;
|
||||||
|
|
||||||
|
int diffuse_bounce;
|
||||||
|
int glossy_bounce;
|
||||||
|
int transmission_bounce;
|
||||||
|
int transparent_bounce;
|
||||||
|
} PathState;
|
||||||
|
|
||||||
|
__device_inline void path_state_init(PathState *state)
|
||||||
|
{
|
||||||
|
state->flag = PATH_RAY_CAMERA|PATH_RAY_SINGULAR|PATH_RAY_MIS_SKIP;
|
||||||
|
state->bounce = 0;
|
||||||
|
state->diffuse_bounce = 0;
|
||||||
|
state->glossy_bounce = 0;
|
||||||
|
state->transmission_bounce = 0;
|
||||||
|
state->transparent_bounce = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device_inline void path_state_next(KernelGlobals *kg, PathState *state, int label)
|
||||||
|
{
|
||||||
|
/* ray through transparent keeps same flags from previous ray and is
|
||||||
|
not counted as a regular bounce, transparent has separate max */
|
||||||
|
if(label & LABEL_TRANSPARENT) {
|
||||||
|
state->flag |= PATH_RAY_TRANSPARENT;
|
||||||
|
state->transparent_bounce++;
|
||||||
|
|
||||||
|
if(!kernel_data.integrator.transparent_shadows)
|
||||||
|
state->flag |= PATH_RAY_MIS_SKIP;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->bounce++;
|
||||||
|
|
||||||
|
/* reflection/transmission */
|
||||||
|
if(label & LABEL_REFLECT) {
|
||||||
|
state->flag |= PATH_RAY_REFLECT;
|
||||||
|
state->flag &= ~(PATH_RAY_TRANSMIT|PATH_RAY_CAMERA|PATH_RAY_TRANSPARENT);
|
||||||
|
|
||||||
|
if(label & LABEL_DIFFUSE)
|
||||||
|
state->diffuse_bounce++;
|
||||||
|
else
|
||||||
|
state->glossy_bounce++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
kernel_assert(label & LABEL_TRANSMIT);
|
||||||
|
|
||||||
|
state->flag |= PATH_RAY_TRANSMIT;
|
||||||
|
state->flag &= ~(PATH_RAY_REFLECT|PATH_RAY_CAMERA|PATH_RAY_TRANSPARENT);
|
||||||
|
|
||||||
|
state->transmission_bounce++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* diffuse/glossy/singular */
|
||||||
|
if(label & LABEL_DIFFUSE) {
|
||||||
|
state->flag |= PATH_RAY_DIFFUSE;
|
||||||
|
state->flag &= ~(PATH_RAY_GLOSSY|PATH_RAY_SINGULAR|PATH_RAY_MIS_SKIP);
|
||||||
|
}
|
||||||
|
else if(label & LABEL_GLOSSY) {
|
||||||
|
state->flag |= PATH_RAY_GLOSSY;
|
||||||
|
state->flag &= ~(PATH_RAY_DIFFUSE|PATH_RAY_SINGULAR|PATH_RAY_MIS_SKIP);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
kernel_assert(label & LABEL_SINGULAR);
|
||||||
|
|
||||||
|
state->flag |= PATH_RAY_GLOSSY|PATH_RAY_SINGULAR|PATH_RAY_MIS_SKIP;
|
||||||
|
state->flag &= ~PATH_RAY_DIFFUSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__device_inline uint path_state_ray_visibility(PathState *state)
|
||||||
|
{
|
||||||
|
uint flag = state->flag;
|
||||||
|
|
||||||
|
/* for visibility, diffuse/glossy are for reflection only */
|
||||||
|
if(flag & PATH_RAY_TRANSMIT)
|
||||||
|
flag &= ~(PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY);
|
||||||
|
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device_inline float path_state_terminate_probability(KernelGlobals *kg, PathState *state, const float3 throughput)
|
||||||
|
{
|
||||||
|
if(state->flag & PATH_RAY_TRANSPARENT) {
|
||||||
|
/* transparent rays treated separately */
|
||||||
|
if(state->transparent_bounce >= kernel_data.integrator.transparent_max_bounce)
|
||||||
|
return 0.0f;
|
||||||
|
else if(state->transparent_bounce <= kernel_data.integrator.transparent_min_bounce)
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* other rays */
|
||||||
|
if((state->bounce >= kernel_data.integrator.max_bounce) ||
|
||||||
|
(state->diffuse_bounce >= kernel_data.integrator.max_diffuse_bounce) ||
|
||||||
|
(state->glossy_bounce >= kernel_data.integrator.max_glossy_bounce) ||
|
||||||
|
(state->transmission_bounce >= kernel_data.integrator.max_transmission_bounce))
|
||||||
|
return 0.0f;
|
||||||
|
else if(state->bounce <= kernel_data.integrator.min_bounce)
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* probalistic termination */
|
||||||
|
return average(throughput);
|
||||||
|
}
|
||||||
|
|
||||||
|
__device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ray, Intersection *isect, float3 *light_L)
|
||||||
|
{
|
||||||
|
if(ray->t == 0.0f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool result = scene_intersect(kg, ray, PATH_RAY_SHADOW_OPAQUE, isect);
|
||||||
|
|
||||||
|
#ifdef __TRANSPARENT_SHADOWS__
|
||||||
|
if(result && kernel_data.integrator.transparent_shadows) {
|
||||||
|
/* transparent shadows work in such a way to try to minimize overhead
|
||||||
|
in cases where we don't need them. after a regular shadow ray is
|
||||||
|
cast we check if the hit primitive was potentially transparent, and
|
||||||
|
only in that case start marching. this gives on extra ray cast for
|
||||||
|
the cases were we do want transparency.
|
||||||
|
|
||||||
|
also note that for this to work correct, multi close sampling must
|
||||||
|
be used, since we don't pass a random number to shader_eval_surface */
|
||||||
|
if(shader_transparent_shadow(kg, isect)) {
|
||||||
|
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
|
||||||
|
float3 Pend = ray->P + ray->D*ray->t;
|
||||||
|
int bounce = state->transparent_bounce;
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
if(bounce >= kernel_data.integrator.transparent_max_bounce) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(bounce >= kernel_data.integrator.transparent_min_bounce) {
|
||||||
|
/* todo: get random number somewhere for probabilistic terminate */
|
||||||
|
#if 0
|
||||||
|
float probability = average(throughput);
|
||||||
|
float terminate = 0.0f;
|
||||||
|
|
||||||
|
if(terminate >= probability)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
throughput /= probability;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!scene_intersect(kg, ray, PATH_RAY_SHADOW_TRANSPARENT, isect)) {
|
||||||
|
*light_L *= throughput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!shader_transparent_shadow(kg, isect))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
ShaderData sd;
|
||||||
|
shader_setup_from_ray(kg, &sd, isect, ray);
|
||||||
|
shader_eval_surface(kg, &sd, 0.0f, PATH_RAY_SHADOW);
|
||||||
|
|
||||||
|
throughput *= shader_bsdf_transparency(kg, &sd);
|
||||||
|
|
||||||
|
ray->P = ray_offset(sd.P, -sd.Ng);
|
||||||
|
if(ray->t != FLT_MAX)
|
||||||
|
ray->D = normalize_len(Pend - ray->P, &ray->t);
|
||||||
|
|
||||||
|
bounce++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, Ray ray, float3 throughput)
|
||||||
|
{
|
||||||
|
/* initialize */
|
||||||
|
float3 L = make_float3(0.0f, 0.0f, 0.0f);
|
||||||
|
float Ltransparent = 0.0f;
|
||||||
|
|
||||||
|
#ifdef __EMISSION__
|
||||||
|
float ray_pdf = 0.0f;
|
||||||
|
#endif
|
||||||
|
PathState state;
|
||||||
|
int rng_offset = PRNG_BASE_NUM;
|
||||||
|
|
||||||
|
path_state_init(&state);
|
||||||
|
|
||||||
|
/* path iteration */
|
||||||
|
for(;; rng_offset += PRNG_BOUNCE_NUM) {
|
||||||
|
/* intersect scene */
|
||||||
|
Intersection isect;
|
||||||
|
uint visibility = path_state_ray_visibility(&state);
|
||||||
|
|
||||||
|
if(!scene_intersect(kg, &ray, visibility, &isect)) {
|
||||||
|
/* eval background shader if nothing hit */
|
||||||
|
if(kernel_data.background.transparent && (state.flag & PATH_RAY_CAMERA)) {
|
||||||
|
Ltransparent += average(throughput);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
#ifdef __BACKGROUND__
|
||||||
|
ShaderData sd;
|
||||||
|
shader_setup_from_background(kg, &sd, &ray);
|
||||||
|
L += throughput*shader_eval_background(kg, &sd, state.flag);
|
||||||
|
shader_release(kg, &sd);
|
||||||
|
#else
|
||||||
|
L += throughput*make_float3(0.8f, 0.8f, 0.8f);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setup shading */
|
||||||
|
ShaderData sd;
|
||||||
|
shader_setup_from_ray(kg, &sd, &isect, &ray);
|
||||||
|
float rbsdf = path_rng(kg, rng, sample, rng_offset + PRNG_BSDF);
|
||||||
|
shader_eval_surface(kg, &sd, rbsdf, state.flag);
|
||||||
|
|
||||||
|
#ifdef __HOLDOUT__
|
||||||
|
if((sd.flag & SD_HOLDOUT) && (state.flag & PATH_RAY_CAMERA)) {
|
||||||
|
float3 holdout_weight = shader_holdout_eval(kg, &sd);
|
||||||
|
|
||||||
|
if(kernel_data.background.transparent)
|
||||||
|
Ltransparent += average(holdout_weight*throughput);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __EMISSION__
|
||||||
|
/* emission */
|
||||||
|
if(sd.flag & SD_EMISSION)
|
||||||
|
L += throughput*indirect_emission(kg, &sd, isect.t, state.flag, ray_pdf);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* path termination. this is a strange place to put the termination, it's
|
||||||
|
mainly due to the mixed in MIS that we use. gives too many unneeded
|
||||||
|
shader evaluations, only need emission if we are going to terminate */
|
||||||
|
float probability = path_state_terminate_probability(kg, &state, throughput);
|
||||||
|
float terminate = path_rng(kg, rng, sample, rng_offset + PRNG_TERMINATE);
|
||||||
|
|
||||||
|
if(terminate >= probability)
|
||||||
|
break;
|
||||||
|
|
||||||
|
throughput /= probability;
|
||||||
|
|
||||||
|
#ifdef __EMISSION__
|
||||||
|
if(kernel_data.integrator.use_direct_light) {
|
||||||
|
/* sample illumination from lights to find path contribution */
|
||||||
|
if(sd.flag & SD_BSDF_HAS_EVAL) {
|
||||||
|
float light_t = path_rng(kg, rng, sample, rng_offset + PRNG_LIGHT);
|
||||||
|
float light_o = path_rng(kg, rng, sample, rng_offset + PRNG_LIGHT_F);
|
||||||
|
float light_u = path_rng(kg, rng, sample, rng_offset + PRNG_LIGHT_U);
|
||||||
|
float light_v = path_rng(kg, rng, sample, rng_offset + PRNG_LIGHT_V);
|
||||||
|
|
||||||
|
Ray light_ray;
|
||||||
|
float3 light_L;
|
||||||
|
|
||||||
|
#ifdef __MULTI_LIGHT__
|
||||||
|
/* index -1 means randomly sample from distribution */
|
||||||
|
int i = (kernel_data.integrator.num_distribution)? -1: 0;
|
||||||
|
|
||||||
|
for(; i < kernel_data.integrator.num_all_lights; i++) {
|
||||||
|
#else
|
||||||
|
const int i = -1;
|
||||||
|
#endif
|
||||||
|
if(direct_emission(kg, &sd, i, light_t, light_o, light_u, light_v, &light_ray, &light_L)) {
|
||||||
|
/* trace shadow ray */
|
||||||
|
if(!shadow_blocked(kg, &state, &light_ray, &isect, &light_L))
|
||||||
|
L += throughput*light_L;
|
||||||
|
}
|
||||||
|
#ifdef __MULTI_LIGHT__
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* no BSDF? we can stop here */
|
||||||
|
if(!(sd.flag & SD_BSDF))
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* sample BSDF */
|
||||||
|
float bsdf_pdf;
|
||||||
|
float3 bsdf_eval;
|
||||||
|
float3 bsdf_omega_in;
|
||||||
|
differential3 bsdf_domega_in;
|
||||||
|
float bsdf_u = path_rng(kg, rng, sample, rng_offset + PRNG_BSDF_U);
|
||||||
|
float bsdf_v = path_rng(kg, rng, sample, rng_offset + PRNG_BSDF_V);
|
||||||
|
int label;
|
||||||
|
|
||||||
|
label = shader_bsdf_sample(kg, &sd, bsdf_u, bsdf_v, &bsdf_eval,
|
||||||
|
&bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
|
||||||
|
|
||||||
|
shader_release(kg, &sd);
|
||||||
|
|
||||||
|
if(bsdf_pdf == 0.0f || is_zero(bsdf_eval))
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* modify throughput */
|
||||||
|
throughput *= bsdf_eval/bsdf_pdf;
|
||||||
|
|
||||||
|
/* set labels */
|
||||||
|
#ifdef __EMISSION__
|
||||||
|
ray_pdf = bsdf_pdf;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* update path state */
|
||||||
|
path_state_next(kg, &state, label);
|
||||||
|
|
||||||
|
/* setup ray */
|
||||||
|
ray.P = ray_offset(sd.P, (label & LABEL_TRANSMIT)? -sd.Ng: sd.Ng);
|
||||||
|
ray.D = bsdf_omega_in;
|
||||||
|
ray.t = FLT_MAX;
|
||||||
|
#ifdef __RAY_DIFFERENTIALS__
|
||||||
|
ray.dP = sd.dP;
|
||||||
|
ray.dD = bsdf_domega_in;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return make_float4(L.x, L.y, L.z, 1.0f - Ltransparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
__device void kernel_path_trace(KernelGlobals *kg, __global float4 *buffer, __global uint *rng_state, int sample, int x, int y)
|
||||||
|
{
|
||||||
|
/* initialize random numbers */
|
||||||
|
RNG rng;
|
||||||
|
|
||||||
|
float filter_u;
|
||||||
|
float filter_v;
|
||||||
|
|
||||||
|
path_rng_init(kg, rng_state, sample, &rng, x, y, &filter_u, &filter_v);
|
||||||
|
|
||||||
|
/* sample camera ray */
|
||||||
|
Ray ray;
|
||||||
|
|
||||||
|
float lens_u = path_rng(kg, &rng, sample, PRNG_LENS_U);
|
||||||
|
float lens_v = path_rng(kg, &rng, sample, PRNG_LENS_V);
|
||||||
|
|
||||||
|
camera_sample(kg, x, y, filter_u, filter_v, lens_u, lens_v, &ray);
|
||||||
|
|
||||||
|
/* integrate */
|
||||||
|
#ifdef __MODIFY_TP__
|
||||||
|
float3 throughput = path_terminate_modified_throughput(kg, buffer, x, y, sample);
|
||||||
|
float4 L = kernel_path_integrate(kg, &rng, sample, ray, throughput)/throughput;
|
||||||
|
#else
|
||||||
|
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
|
||||||
|
float4 L = kernel_path_integrate(kg, &rng, sample, ray, throughput);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* accumulate result in output buffer */
|
||||||
|
int index = x + y*kernel_data.cam.width;
|
||||||
|
|
||||||
|
if(sample == 0)
|
||||||
|
buffer[index] = L;
|
||||||
|
else
|
||||||
|
buffer[index] += L;
|
||||||
|
|
||||||
|
path_rng_end(kg, rng_state, rng, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user